fix(oci/cohere): suppress tool calls on stream terminal consolidation chunk

The terminal SSE event re-sends the full assembled response in both
`text` and `chatHistory`. The existing logic already suppresses
`text` to avoid double-emit, but tool calls extracted from the
terminal chunk (via `typed_chunk.toolCalls` or the `chatHistory`
CHATBOT fallback) would still be re-emitted with fresh uuid4 IDs.
If OCI Cohere ever streams tool calls progressively in intermediate
chunks (now possible since CohereStreamChunk has a toolCalls field),
this would cause downstream agentic frameworks to execute each tool
call twice.

Suppress tool calls on the terminal consolidation chunk for the same
reason `text` is suppressed.

Co-authored-by: Yassin Kortam <yassin@berri.ai>
This commit is contained in:
Cursor Agent 2026-05-19 08:45:33 +00:00
parent e4b6c56801
commit b295514489
No known key found for this signature in database

View file

@ -284,12 +284,13 @@ def handle_cohere_stream_chunk(dict_chunk: dict) -> ModelResponseStream:
)
text = "" if is_terminal_consolidation else (typed_chunk.text or "")
cohere_tool_calls = typed_chunk.toolCalls
if cohere_tool_calls is None and is_terminal_consolidation:
for history_msg in typed_chunk.chatHistory or []:
if history_msg.role == "CHATBOT" and history_msg.toolCalls:
cohere_tool_calls = history_msg.toolCalls
break
# Tool calls on the terminal consolidation chunk (whether from
# `typed_chunk.toolCalls` or from `chatHistory`) restate what was already
# streamed in intermediate chunks. Re-emitting them here would mint fresh
# `uuid4` IDs and cause downstream consumers to execute each tool call
# twice. Suppress them on the terminal chunk for the same reason `text`
# is suppressed above.
cohere_tool_calls = None if is_terminal_consolidation else typed_chunk.toolCalls
tool_calls: Optional[List[Dict[str, Any]]] = None
if cohere_tool_calls: