docs(TASK-044): review polish — visible-output wording, web-search wire pin note, truncation debug line, thinking-exclusion pin test
This commit is contained in:
3 files changed
+25
-1
No files matched your search
+4
-1
@@ -12,12 +12,15 @@ migrate them to the sibling `patch.responses` key / the model patch's `responses
|
|||||||
(env override: `COYOTE_PATCH_<client>_RESPONSES`).
|
(env override: `COYOTE_PATCH_<client>_RESPONSES`).
|
||||||
- Sessions saved after this change may contain the new `reasoning` thinking blocks (encrypted
|
- Sessions saved after this change may contain the new `reasoning` thinking blocks (encrypted
|
||||||
reasoning items from the Responses API); older coyote binaries cannot load those sessions.
|
reasoning items from the Responses API); older coyote binaries cannot load those sessions.
|
||||||
|
- OpenAI native web search (the bundled `web_search_coyote` tool) uses the chat-only
|
||||||
|
`gpt-4o-*search-preview` mechanism, which the responses wire does not serve: until the tool is
|
||||||
|
updated, pin `wire_api: chat` on the openai client when relying on it.
|
||||||
|
|
||||||
### Feat
|
### Feat
|
||||||
|
|
||||||
- support `wire_api: responses | chat` on the openai and openai-compatible clients, with wire-aware request patching on both patch layers
|
- support `wire_api: responses | chat` on the openai and openai-compatible clients, with wire-aware request patching on both patch layers
|
||||||
- report token usage (including cached input tokens) on the openai responses path
|
- report token usage (including cached input tokens) on the openai responses path
|
||||||
- streaming responses that end with `response.incomplete` now surface the truncation reason (e.g. `max_output_tokens`) when no output was delivered — matching the non-streaming behavior — and record token usage for truncated turns instead of ending silently
|
- streaming responses that end with `response.incomplete` now surface the truncation reason (e.g. `max_output_tokens`) when no visible output (text or tool calls) was delivered — matching the non-streaming behavior — and record token usage for truncated turns instead of ending silently
|
||||||
- the responses wire always sends `include: ["reasoning.encrypted_content"]` and `"strict": false` tool definitions; strict third-party `/v1/responses` servers may reject these as unknown params when opted in via `wire_api: responses` (workaround: a `responses`-keyed client patch, e.g. `include: null` for Groq)
|
- the responses wire always sends `include: ["reasoning.encrypted_content"]` and `"strict": false` tool definitions; strict third-party `/v1/responses` servers may reject these as unknown params when opted in via `wire_api: responses` (workaround: a `responses`-keyed client patch, e.g. `include: null` for Groq)
|
||||||
|
|
||||||
## v0.10.3 (2026-09-15)
|
## v0.10.3 (2026-09-15)
|
||||||
|
|||||||
@@ -954,6 +954,10 @@ fn openai_responses_handle_event(data: &Value, handler: &mut SseHandler) -> Resu
|
|||||||
// partial text or tool calls are returned rather than discarded
|
// partial text or tool calls are returned rather than discarded
|
||||||
// by a hard error; only an empty truncated response bails.
|
// by a hard error; only an empty truncated response bails.
|
||||||
if handler.has_received_visible_output() {
|
if handler.has_received_visible_output() {
|
||||||
|
debug!(
|
||||||
|
"response truncated ({}); keeping partial output",
|
||||||
|
data["response"]["incomplete_details"]["reason"]
|
||||||
|
);
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
match data["response"]["incomplete_details"]["reason"].as_str() {
|
match data["response"]["incomplete_details"]["reason"].as_str() {
|
||||||
|
|||||||
@@ -552,6 +552,23 @@ mod tests {
|
|||||||
assert!(handler.has_received_content());
|
assert!(handler.has_received_content());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pins the deliberate exclusion: thinking blocks count as received
|
||||||
|
/// content but not as visible output, so a thinking-only stream is
|
||||||
|
/// still an empty response to the caller.
|
||||||
|
#[test]
|
||||||
|
fn thinking_blocks_do_not_count_as_visible_output() {
|
||||||
|
let (mut handler, _rx) = new_handler();
|
||||||
|
handler.thinking_block(ThinkingBlock::Thinking {
|
||||||
|
thinking: "hmm".to_string(),
|
||||||
|
signature: "sig".to_string(),
|
||||||
|
});
|
||||||
|
assert!(handler.has_received_content());
|
||||||
|
assert!(!handler.has_received_visible_output());
|
||||||
|
|
||||||
|
handler.text("hello").unwrap();
|
||||||
|
assert!(handler.has_received_visible_output());
|
||||||
|
}
|
||||||
|
|
||||||
/// Claude splits usage across events: `message_start` carries the input
|
/// Claude splits usage across events: `message_start` carries the input
|
||||||
/// and cache counts with a provisional output count, `message_delta`
|
/// and cache counts with a provisional output count, `message_delta`
|
||||||
/// carries only the final output count. Later non-None fields must win.
|
/// carries only the final output count. Later non-None fields must win.
|
||||||
|
|||||||
Reference in new issue
Block a user