1. Request a call
tools='[{"type":"function","function":{"name":"get_weather","description":"Get current weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"],"additionalProperties":false}}}]'
first_request=$(jq -nc --argjson tools "$tools" '{
model: "gpt-4o-mini",
messages: [{role:"user", content:"Do I need an umbrella in Shanghai?"}],
tools: $tools
}')
first_response=$(curl -sS https://api.yelu.ai/v1/chat/completions \
-H "Authorization: Bearer $YELU_API_KEY" \
-H "Content-Type: application/json" \
-d "$first_request")
assistant=$(jq -c '.choices[0].message' <<<"$first_response")
call_id=$(jq -r '.tool_calls[0].id' <<<"$assistant")
city=$(jq -r '.tool_calls[0].function.arguments | fromjson | .city' <<<"$assistant")
tool_result=$(jq -nc --arg city "$city" '{city:$city, condition:"rain", temperature_c:24}')
second_request=$(jq -nc \
--argjson tools "$tools" \
--argjson assistant "$assistant" \
--arg call_id "$call_id" \
--arg tool_result "$tool_result" '{
model: "gpt-4o-mini",
messages: [
{role:"user", content:"Do I need an umbrella in Shanghai?"},
$assistant,
{role:"tool", tool_call_id:$call_id, content:$tool_result}
],
tools: $tools
}')
curl -sS https://api.yelu.ai/v1/chat/completions \
-H "Authorization: Bearer $YELU_API_KEY" \
-H "Content-Type: application/json" \
-d "$second_request" | jq -r '.choices[0].message.content'
const messages = [{ role: 'user', content: 'Do I need an umbrella in Shanghai?' }];
const tools = [{ type: 'function', function: {
name: 'get_weather',
description: 'Get current weather for a city',
parameters: {
type: 'object',
properties: { city: { type: 'string' } },
required: ['city'],
additionalProperties: false,
},
} }];
async function complete(body) {
const response = await fetch('https://api.yelu.ai/v1/chat/completions', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.YELU_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ model: 'gpt-4o-mini', ...body }),
});
if (!response.ok) throw new Error(await response.text());
return response.json();
}
const first = await complete({ messages, tools });
const assistant = first.choices[0].message;
const call = assistant.tool_calls[0];
const args = JSON.parse(call.function.arguments);
if (call.function.name !== 'get_weather' || typeof args.city !== 'string') throw new Error('Invalid tool call');
messages.push(assistant, {
role: 'tool',
tool_call_id: call.id,
content: JSON.stringify({ city: args.city, condition: 'rain', temperature_c: 24 }),
});
const final = await complete({ messages, tools });
console.log(final.choices[0].message.content);
import json
import os
import requests
messages = [{"role": "user", "content": "Do I need an umbrella in Shanghai?"}]
tools = [{"type": "function", "function": {
"name": "get_weather",
"description": "Get current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
"additionalProperties": False,
},
}}]
def complete():
response = requests.post(
"https://api.yelu.ai/v1/chat/completions",
headers={"Authorization": f"Bearer {os.environ['YELU_API_KEY']}"},
json={"model": "gpt-4o-mini", "messages": messages, "tools": tools},
timeout=60,
)
response.raise_for_status()
return response.json()
assistant = complete()["choices"][0]["message"]
call = assistant["tool_calls"][0]
arguments = json.loads(call["function"]["arguments"])
if call["function"]["name"] != "get_weather" or not isinstance(arguments.get("city"), str):
raise ValueError("Invalid tool call")
messages.extend([assistant, {
"role": "tool",
"tool_call_id": call["id"],
"content": json.dumps({"city": arguments["city"], "condition": "rain", "temperature_c": 24}),
}])
print(complete()["choices"][0]["message"]["content"])
Never execute a tool solely because the model requested it. Validate the name and arguments, enforce user authorization, and require confirmation for consequential actions.