mirror of https://github.com/aliasrobotics/cai.git
fix(chatcompletions): repair truncated tool-call args before emission
A streaming tool call cut off after the opening brace would leave
state.function_calls[i].arguments = "{". CAI persisted that into
conversation history verbatim, and on the next turn the upstream
litellm proxy strict-parsed it as JSON and rejected the whole
request with HTTP 400 ("unexpected end of data: line 1 column 2"),
wedging the session.
- openai_chatcompletions.py: at end-of-stream, validate every
accumulated function_call.arguments string. If empty or not
valid JSON, normalize to "{}" before emitting events.
- message_builder.py: same guard when replaying assistant tool_calls
out of memory, so a poisoned history loaded from disk also recovers.
This commit is contained in:
parent
23739d0631
commit
967762950c
|
|
@ -424,6 +424,14 @@ class Converter:
|
|||
arguments = "{}"
|
||||
elif isinstance(arguments, dict):
|
||||
arguments = json.dumps(arguments)
|
||||
else:
|
||||
# Truncated/streamed-then-cut function call args (e.g. "{")
|
||||
# are not valid JSON and the upstream proxy rejects the whole
|
||||
# request with HTTP 400, wedging the conversation.
|
||||
try:
|
||||
json.loads(arguments)
|
||||
except (TypeError, ValueError):
|
||||
arguments = "{}"
|
||||
tool_calls_param.append(
|
||||
ChatCompletionMessageToolCallParam(
|
||||
id=tc.get("id", "")[:40],
|
||||
|
|
|
|||
|
|
@ -2676,6 +2676,19 @@ class OpenAIChatCompletionsModel(Model):
|
|||
type="response.content_part.done",
|
||||
)
|
||||
|
||||
# Repair partially-streamed function calls before emission so a
|
||||
# truncated args string like "{" cannot poison conversation history
|
||||
# and trigger HTTP 400 on the next request.
|
||||
for _fc in state.function_calls.values():
|
||||
_args = _fc.arguments or ""
|
||||
if not _args.strip():
|
||||
_fc.arguments = "{}"
|
||||
else:
|
||||
try:
|
||||
json.loads(_args)
|
||||
except (TypeError, ValueError):
|
||||
_fc.arguments = "{}"
|
||||
|
||||
# Actually send events for the function calls
|
||||
for function_call in state.function_calls.values():
|
||||
# First, a ResponseOutputItemAdded for the function call
|
||||
|
|
|
|||
Loading…
Reference in New Issue