This document captures the current /v1/responses streaming compatibility contract at the proxy boundary.
In the spirit of “重新审视那份研究文档,将其与我们当前的代码库对齐,并融入到我们的 docs 文件夹下”, this note replaces the earlier investigation log with a current-state contract description tied to the code that actually ships.
GitHub Copilot's upstream /responses stream is close to the OpenAI Responses surface, but not identical enough to expose raw passthrough safely.
The most important known gap is stream identity stability:
- upstream can emit unstable
response.idvalues across lifecycle events - upstream can emit unstable
item_idvalues across child events for the same logicaloutput_index - some clients assume a stable item identity and will break when that assumption is violated
The proxy therefore applies a small compatibility shim on the native /v1/responses passthrough path.
At the proxy boundary, response.id is stabilized to the first observed value. Later lifecycle events such as:
response.completedresponse.incompleteresponse.failed
are rewritten back to that stable ID when upstream drifts.
Implementation:
At the proxy boundary, every event that carries both:
output_indexitem_id
is normalized structurally rather than by an event-name whitelist.
That means the proxy now rewrites observed and future child events consistently as long as they reference a known output_index.
This includes events such as:
response.output_text.deltaresponse.output_text.doneresponse.function_call_arguments.deltaresponse.function_call_arguments.doneresponse.reasoning_summary_text.deltaresponse.reasoning_summary_text.doneresponse.reasoning_summary_part.addedresponse.reasoning_summary_part.doneresponse.content_part.addedresponse.content_part.done- unknown future events that still carry
output_indexanditem_id
Stable output-item identity is tracked by output_index.
The current rules are:
response.output_item.addedseeds the stable item ID when first seenresponse.output_item.doneseeds it only if no stable ID exists yetresponse.output_item.donedoes not overwrite a previously established stable ID- if upstream drifts on
response.output_item.done.item.id, the proxy rewrites it back to the stable ID
This keeps late upstream drift from corrupting the tracker state used by child events.
The local Responses stream type model now includes the currently observed part events that matter for compatibility:
response.reasoning_summary_part.addedresponse.reasoning_summary_part.doneresponse.content_part.addedresponse.content_part.done
Implementation:
The contract above is covered by focused route-level tests rather than only unit tests on helper functions.
Relevant suites:
Current checks include:
- per-
output_indexchild-event normalization response.reasoning_summary_part.*response.content_part.*- unknown future event normalization by shape
response.output_item.doneseeding without overwrite- stable
response.idon lifecycle events - malformed JSON passthrough
This compatibility layer does not try to make Copilot byte-for-byte identical to OpenAI.
It only aims to preserve the wire-level invariants that real OpenAI Responses clients depend on:
- valid SSE framing
- stable logical item identity
- coherent lifecycle IDs
- tolerance for future event additions
This is also intentionally separate from the broader upstream support gaps documented in:
Those notes cover resource-surface issues such as previous_response_id, retrieve, delete, and input_tokens, which are different from the streaming identity problem described here.
This document originated from a debugging investigation triggered by a third-party client crash caused by unstable reasoning event IDs. That earlier incident report was useful for local debugging, but the durable value for the repository is the current compatibility contract described above.