#!/usr/bin/env python3 """Function calling: force a strict function, send the result back, stream the arguments. STATUS: LIVE_VERIFIED 2026-09-18 (gpt-5.4-nano; forced tool_choice -> function_call -> function_call_output -> message; streaming emits response.function_call_arguments.delta/done). Run: .venv/bin/python examples/openai/tools/function-calling/function_calling.py """ import json, sys from pathlib import Path ROOT = Path(__file__).resolve().parents[4]; sys.path.insert(0, str(ROOT)) from scripts.live import load_env, log_request; load_env() from openai import OpenAI client = OpenAI(); MODEL = "gpt-5.4-nano" WEATHER = {"type": "function", "name": "get_weather", "description": "Current weather for a city.", "strict": True, "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"], "additionalProperties": False}} r1 = client.responses.create(model=MODEL, input="Weather in Paris?", tools=[WEATHER], max_output_tokens=64, tool_choice={"type": "function", "name": "get_weather"}, reasoning={"effort": "low"}) log_request("openai", "POST", "/v1/responses", 200, 0.0001, "function_calling.py forced call") call = next(i for i in r1.output if i.type == "function_call") print("function_call:", call.name, call.arguments, call.call_id) r2 = client.responses.create(model=MODEL, previous_response_id=r1.id, tools=[WEATHER], max_output_tokens=32, reasoning={"effort": "low"}, input=[{"type": "function_call_output", "call_id": call.call_id, "output": json.dumps({"temp_c": 18, "sky": "clear"})}]) log_request("openai", "POST", "/v1/responses", 200, 0.0001, "function_calling.py round trip") print("final:", r2.output_text) with client.responses.stream(model=MODEL, input="Weather in Rome?", tools=[WEATHER], tool_choice="required", max_output_tokens=64, reasoning={"effort": "low"}) as s: seen = [] for ev in s: seen.append(ev.type) log_request("openai", "POST", "/v1/responses", 200, 0.0001, "function_calling.py stream") print("stream events:", sorted(set(seen)))