The loop
Moss stores nothing between calls. Each round sends the whole conversation, and you repeat it until the reply has no tool calls.1
Send your tools
Put function tools in
tools. On Responses a function tool is flat: name, description and parameters sit next to type.2
Run each call
The reply’s
output holds one function_call item per call, with a call_id, the tool’s name and its arguments. arguments is a JSON string, such as {"id": "A1"}. Parse it and run the tool in your code.3
Send the results back
Call again with the conversation so far. In order, send the earlier input, the The reply is the answer, or more calls. Repeat until
output items, and one function_call_output per call with the same call_id. Send instructions again too.output has no function_call items.tools on every request. Moss keeps no state, so the model sees only the tools in the request it is answering.
Send output items back unchanged. A function_call item can carry fields beyond OpenAI’s, such as Gemini’s extra_content and its thought signature. The model needs them on the next turn.
Write the loop with an SDK
Each loop runs until the reply has no calls.lookup_order stands for your own code, and it returns text.
ResponseFunctionToolCall and goes back as its raw JSON, with every field the model sent. In JavaScript, the loop streams each round and reads the items from stream.finalResponse(). Without stream: true, create returns the response directly.
Call tools on Chat Completions
Chat Completions takes OpenAI’s Chat shape, where a tool nestsname and parameters under function. A reply without stream has the calls in choices[0].message.tool_calls, with finish_reason tool_calls.
Send the assistant message back unchanged, then one tool message per call, and call again:
tools every time, and keep every field of tool_calls, such as Gemini’s extra_content. A tools value that is not a list of objects returns 400.
Choose how the model calls tools
tool_choice sets whether the model must call a tool. On Responses it takes these values:
On Chat Completions,
tool_choice takes OpenAI’s Chat values. A named function there is {"type": "function", "function": {"name": "lookup_order"}}.
On the Moss key, anthropic/claude-sonnet-5.5, anthropic/claude-opus-5.5 and anthropic/claude-fable-5.1 take only auto and none. A tool_choice of required or a named tool returns 400 unsupported_parameter.
parallel_tool_calls is true by default, so the model can call more than one tool at once. Set it to false to allow one call at a time.
Structured output
To get JSON that matches a schema, settext.format to type json_schema on Responses. Type json_object asks for any JSON object, and type text is plain text. Anthropic models on the Moss key refuse json_object with 400 unsupported_parameter; send json_schema instead.
output_text is then the JSON object as a string. On Chat Completions, send the schema in response_format instead, in OpenAI’s shape: {"type": "json_schema", "json_schema": {"name": "shipping_answer", "schema": ...}}.
Stream tool calls
On a Responses stream, each call starts withresponse.output_item.added. Its arguments arrive in pieces in response.function_call_arguments.delta events, then whole in response.function_call_arguments.done. response.output_item.done carries the finished function_call item.
On a Chat Completions stream, each call arrives in pieces in delta.tool_calls, with index, id, function.name and function.arguments. Join the pieces by index. A chunk with finish_reason tool_calls ends the round.
Streaming lists every event and chunk.