Skip to content

Commit e9c573a

Browse files
committed
fallback for json.loads tool function args
some openai-compatible models (such as openrouter's anthropic models) do not default to an empty json object when there are no arguments, leading to a parsing error. `function.arguments == '{}'`: ```bash % llm --tool llm_version "What is the version?" --td -m openrouter/openai/gpt-4o Tool call: llm_version({}) 0.26 The version of the LLM is 0.26. ``` `function.arguments == ''`: ```bash % llm --tool llm_version "What is the version?" --td -m openrouter/anthropic/claude-sonnet-4 I'll check the version of llm for you.Error: Expecting value: line 1 column 1 (char 0) ```
1 parent 2292d7a commit e9c573a

File tree

1 file changed

+8
-4
lines changed

1 file changed

+8
-4
lines changed

llm/default_plugins/openai_models.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,8 @@ def execute(self, prompt, stream, response, conversation=None, key=None):
690690
usage = chunk.usage.model_dump()
691691
if chunk.choices and chunk.choices[0].delta:
692692
for tool_call in chunk.choices[0].delta.tool_calls or []:
693+
if tool_call.function.arguments is None:
694+
tool_call.function.arguments = ""
693695
index = tool_call.index
694696
if index not in tool_calls:
695697
tool_calls[index] = tool_call
@@ -711,7 +713,7 @@ def execute(self, prompt, stream, response, conversation=None, key=None):
711713
llm.ToolCall(
712714
tool_call_id=value.id,
713715
name=value.function.name,
714-
arguments=json.loads(value.function.arguments),
716+
arguments=json.loads(value.function.arguments or '{}'),
715717
)
716718
)
717719
else:
@@ -728,7 +730,7 @@ def execute(self, prompt, stream, response, conversation=None, key=None):
728730
llm.ToolCall(
729731
tool_call_id=tool_call.id,
730732
name=tool_call.function.name,
731-
arguments=json.loads(tool_call.function.arguments),
733+
arguments=json.loads(tool_call.function.arguments or '{}'),
732734
)
733735
)
734736
if completion.choices[0].message.content is not None:
@@ -774,6 +776,8 @@ async def execute(
774776
usage = chunk.usage.model_dump()
775777
if chunk.choices and chunk.choices[0].delta:
776778
for tool_call in chunk.choices[0].delta.tool_calls or []:
779+
if tool_call.function.arguments is None:
780+
tool_call.function.arguments = ""
777781
index = tool_call.index
778782
if index not in tool_calls:
779783
tool_calls[index] = tool_call
@@ -794,7 +798,7 @@ async def execute(
794798
llm.ToolCall(
795799
tool_call_id=value.id,
796800
name=value.function.name,
797-
arguments=json.loads(value.function.arguments),
801+
arguments=json.loads(value.function.arguments or '{}'),
798802
)
799803
)
800804
response.response_json = remove_dict_none_values(combine_chunks(chunks))
@@ -812,7 +816,7 @@ async def execute(
812816
llm.ToolCall(
813817
tool_call_id=tool_call.id,
814818
name=tool_call.function.name,
815-
arguments=json.loads(tool_call.function.arguments),
819+
arguments=json.loads(tool_call.function.arguments or '{}'),
816820
)
817821
)
818822
if completion.choices[0].message.content is not None:

0 commit comments

Comments
 (0)