assistants/tools/function-calling.md +0 −1084 deleted
File Deleted View Diff
1# Assistants Function Calling
2
3> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.
4
5After achieving feature parity in the Responses API, we've deprecated the Assistants API. It will shut down on August 26, 2026. Follow the [migration guide](https://developers.openai.com/platform/assistants/migration) to update your integration. [Learn more](https://platform.openai.com/docs/guides/migrate-to-responses).
6
7## Overview
8
9Similar to the Chat Completions API, the Assistants API supports function calling. Function calling allows you to describe functions to the Assistants API and have it intelligently return the functions that need to be called along with their arguments.
10
11## Quickstart
12
13In this example, we'll create a weather assistant and define two functions,
14`get_current_temperature` and `get_rain_probability`, as tools that the Assistant can call.
15Depending on the user query, the model will invoke parallel function calling if using our
16latest models released on or after Nov 6, 2023.
17In our example that uses parallel function calling, we will ask the Assistant what the weather in
18San Francisco is like today and the chances of rain. We also show how to output the Assistant's response with streaming.
19
20With the launch of Structured Outputs, you can now use the parameter `strict:
21 true` when using function calling with the Assistants API. For more
22 information, refer to the [Function calling
23 guide](https://developers.openai.com/api/docs/guides/function-calling#strict-mode). Please note that
24 Structured Outputs are not supported in the Assistants API when using vision.
25
26### Step 1: Define functions
27
28When creating your assistant, you will first define the functions under the `tools` param of the assistant.
29
30```javascript
31const assistant = await client.beta.assistants.create({
32 model: "gpt-4o",
33 instructions:
34 "You are a weather bot. Use the provided functions to answer questions.",
35 tools: [
36 {
37 type: "function",
38 function: {
39 name: "getCurrentTemperature",
40 description: "Get the current temperature for a specific location",
41 parameters: {
42 type: "object",
43 properties: {
44 location: {
45 type: "string",
46 description: "The city and state, e.g., San Francisco, CA",
47 },
48 unit: {
49 type: "string",
50 enum: ["Celsius", "Fahrenheit"],
51 description:
52 "The temperature unit to use. Infer this from the user's location.",
53 },
54 },
55 required: ["location", "unit"],
56 },
57 },
58 },
59 {
60 type: "function",
61 function: {
62 name: "getRainProbability",
63 description: "Get the probability of rain for a specific location",
64 parameters: {
65 type: "object",
66 properties: {
67 location: {
68 type: "string",
69 description: "The city and state, e.g., San Francisco, CA",
70 },
71 },
72 required: ["location"],
73 },
74 },
75 },
76 ],
77});
78```
79
80```python
81from openai import OpenAI
82
83client = OpenAI()
84
85assistant = client.beta.assistants.create(
86 instructions="You are a weather bot. Use the provided functions to answer questions.",
87 model="gpt-4o",
88 tools=[
89 {
90 "type": "function",
91 "function": {
92 "name": "get_current_temperature",
93 "description": "Get the current temperature for a specific location",
94 "parameters": {
95 "type": "object",
96 "properties": {
97 "location": {
98 "type": "string",
99 "description": "The city and state, e.g., San Francisco, CA",
100 },
101 "unit": {
102 "type": "string",
103 "enum": ["Celsius", "Fahrenheit"],
104 "description": "The temperature unit to use. Infer this from the user's location.",
105 },
106 },
107 "required": ["location", "unit"],
108 },
109 },
110 },
111 {
112 "type": "function",
113 "function": {
114 "name": "get_rain_probability",
115 "description": "Get the probability of rain for a specific location",
116 "parameters": {
117 "type": "object",
118 "properties": {
119 "location": {
120 "type": "string",
121 "description": "The city and state, e.g., San Francisco, CA",
122 }
123 },
124 "required": ["location"],
125 },
126 },
127 },
128 ],
129)
130```
131
132```go
133assistant, err := client.Beta.Assistants.New(context.Background(), openai.BetaAssistantNewParams{
134 Model: shared.ChatModelGPT4o,
135 Instructions: openai.String("You are a weather bot. Use the provided functions to answer questions."),
136 Tools: weatherTools(false),
137})
138if err != nil {
139 panic(err)
140}
141
142func weatherTools(strict bool) []openai.AssistantToolUnionParam {
143 return []openai.AssistantToolUnionParam{
144 openai.AssistantToolParamOfFunction(shared.FunctionDefinitionParam{
145 Name: "get_current_temperature",
146 Description: openai.String("Get the current temperature for a specific location"),
147 Parameters: map[string]any{
148 "type": "object",
149 "properties": map[string]any{
150 "location": map[string]any{"type": "string", "description": "The city and state, e.g., San Francisco, CA"},
151 "unit": map[string]any{"type": "string", "enum": []string{"Celsius", "Fahrenheit"}, "description": "The temperature unit to use. Infer this from the user's location."},
152 },
153 "required": []string{"location", "unit"},
154 },
155 Strict: openai.Bool(strict),
156 }),
157 openai.AssistantToolParamOfFunction(shared.FunctionDefinitionParam{
158 Name: "get_rain_probability",
159 Description: openai.String("Get the probability of rain for a specific location"),
160 Parameters: map[string]any{
161 "type": "object",
162 "properties": map[string]any{
163 "location": map[string]any{"type": "string", "description": "The city and state, e.g., San Francisco, CA"},
164 },
165 "required": []string{"location"},
166 },
167 Strict: openai.Bool(strict),
168 }),
169 }
170}
171```
172
173```java
174import com.openai.client.OpenAIClient;
175import com.openai.client.okhttp.OpenAIOkHttpClient;
176import com.openai.core.JsonValue;
177import com.openai.models.FunctionDefinition;
178import com.openai.models.FunctionParameters;
179import com.openai.models.beta.assistants.AssistantCreateParams;
180import java.util.List;
181import java.util.Map;
182
183var assistant =
184 client
185 .beta()
186 .assistants()
187 .create(
188 AssistantCreateParams.builder()
189 .model("gpt-4o")
190 .instructions(
191 "You are a weather bot. Use the provided functions to answer questions.")
192 .addFunctionTool(
193 FunctionDefinition.builder()
194 .name("get_current_temperature")
195 .description("Get the current temperature for a specific location")
196 .parameters(
197 FunctionParameters.builder()
198 .putAdditionalProperty("type", JsonValue.from("object"))
199 .putAdditionalProperty(
200 "properties",
201 JsonValue.from(
202 Map.of(
203 "location",
204 Map.of(
205 "type", "string",
206 "description",
207 "The city and state, e.g., San Francisco, CA"),
208 "unit",
209 Map.of(
210 "type",
211 "string",
212 "enum",
213 List.of("Celsius", "Fahrenheit"),
214 "description",
215 "The temperature unit to use. Infer this from the user's location."))))
216 .putAdditionalProperty(
217 "required", JsonValue.from(List.of("location", "unit")))
218 .build())
219 .build())
220 .addFunctionTool(
221 FunctionDefinition.builder()
222 .name("get_rain_probability")
223 .description("Get the probability of rain for a specific location")
224 .parameters(
225 FunctionParameters.builder()
226 .putAdditionalProperty("type", JsonValue.from("object"))
227 .putAdditionalProperty(
228 "properties",
229 JsonValue.from(
230 Map.of(
231 "location",
232 Map.of(
233 "type", "string",
234 "description",
235 "The city and state, e.g., San Francisco, CA"))))
236 .putAdditionalProperty(
237 "required", JsonValue.from(List.of("location")))
238 .build())
239 .build())
240 .build());
241
242System.out.println(assistant.id());
243```
244
245```ruby
246require "openai"
247
248client = OpenAI::Client.new
249assistant = client.beta.assistants.create(
250 model: "gpt-4o",
251 instructions: "Use the provided functions to answer weather questions.",
252 tools: [
253 {
254 type: :function,
255 function: {
256 name: "get_current_temperature",
257 description: "Get the current temperature for a location",
258 parameters: {
259 type: :object,
260 properties: {
261 location: {type: :string},
262 unit: {type: :string, enum: ["Celsius", "Fahrenheit"]}
263 },
264 required: ["location", "unit"]
265 }
266 }
267 },
268 {
269 type: :function,
270 function: {
271 name: "get_rain_probability",
272 description: "Get the probability of rain for a location",
273 parameters: {
274 type: :object,
275 properties: {location: {type: :string}},
276 required: ["location"]
277 }
278 }
279 }
280 ]
281)
282puts(assistant.id)
283```
284
285
286### Step 2: Create a Thread and add Messages
287
288Create a Thread when a user starts a conversation and add Messages to the Thread as the user asks questions.
289
290```javascript
291const thread = await client.beta.threads.create();
292const message = client.beta.threads.messages.create(thread.id, {
293 role: "user",
294 content:
295 "What's the weather in San Francisco today and the likelihood it'll rain?",
296});
297```
298
299```python
300thread = client.beta.threads.create()
301message = client.beta.threads.messages.create(
302 thread_id=thread.id,
303 role="user",
304 content="What's the weather in San Francisco today and the likelihood it'll rain?",
305)
306```
307
308```go
309thread, err := client.Beta.Threads.New(context.Background(), openai.BetaThreadNewParams{})
310if err != nil {
311 panic(err)
312}
313_, err = client.Beta.Threads.Messages.New(context.Background(), thread.ID, openai.BetaThreadMessageNewParams{
314 Role: "user",
315 Content: openai.BetaThreadMessageNewParamsContentUnion{
316 OfString: openai.String("What's the weather in San Francisco today and the likelihood it'll rain?"),
317 },
318})
319if err != nil {
320 panic(err)
321}
322```
323
324```java
325import com.openai.client.OpenAIClient;
326import com.openai.client.okhttp.OpenAIOkHttpClient;
327import com.openai.models.beta.threads.ThreadCreateParams;
328import com.openai.models.beta.threads.messages.MessageCreateParams;
329
330var thread = client.beta().threads().create(ThreadCreateParams.builder().build());
331var message =
332 client
333 .beta()
334 .threads()
335 .messages()
336 .create(
337 thread.id(),
338 MessageCreateParams.builder()
339 .role(MessageCreateParams.Role.USER)
340 .content("What's the weather in San Francisco today, and will it rain?")
341 .build());
342
343System.out.println(message.id());
344```
345
346```ruby
347require "openai"
348
349client = OpenAI::Client.new
350thread = client.beta.threads.create
351message = client.beta.threads.messages.create(
352 thread.id,
353 role: :user,
354 content: "What's the weather in San Francisco today, and will it rain?"
355)
356puts(message.id)
357```
358
359
360### Step 3: Initiate a Run
361
362When you initiate a Run on a Thread containing a user Message that triggers one or more functions,
363the Run will enter a `pending` status. After it processes, the run will enter a `requires_action` state which you can
364verify by checking the Run’s `status`. This indicates that you need to run tools and submit their outputs to the
365Assistant to continue Run execution. In our case, we will see two `tool_calls`, which indicates that the
366user query resulted in parallel function calling.
367
368Note that a runs expire ten minutes after creation. Be sure to submit your
369 tool outputs before the 10 min mark.
370
371You will see two `tool_calls` within `required_action`, which indicates the user query triggered parallel function calling.
372
373```json
374{
375 "id": "run_qJL1kI9xxWlfE0z1yfL0fGg9",
376 ...
377 "status": "requires_action",
378 "required_action": {
379 "submit_tool_outputs": {
380 "tool_calls": [
381 {
382 "id": "call_FthC9qRpsL5kBpwwyw6c7j4k",
383 "function": {
384 "arguments": "{"location": "San Francisco, CA"}",
385 "name": "get_rain_probability"
386 },
387 "type": "function"
388 },
389 {
390 "id": "call_RpEDoB8O0FTL9JoKTuCVFOyR",
391 "function": {
392 "arguments": "{"location": "San Francisco, CA", "unit": "Fahrenheit"}",
393 "name": "get_current_temperature"
394 },
395 "type": "function"
396 }
397 ]
398 },
399 ...
400 "type": "submit_tool_outputs"
401 }
402}
403```
404
405<figcaption>Run object truncated here for readability</figcaption>
406
407
408
409How you initiate a Run and submit `tool_calls` will differ depending on whether you are using streaming or not,
410although in both cases all `tool_calls` need to be submitted at the same time.
411You can then complete the Run by submitting the tool outputs from the functions you called.
412Pass each `tool_call_id` referenced in the `required_action` object to match outputs to each function call.
413
414
415
416With streaming
417
418
419
420For the streaming case, we create an EventHandler class to handle events in the response stream and submit all tool outputs at once with the “submit tool outputs stream” helper in the Python and Node SDKs.
421
422```javascript
423class EventHandler extends EventEmitter {
424 constructor(client) {
425 super();
426 this.client = client;
427 }
428
429 async onEvent(event) {
430 try {
431 console.log(event);
432 // Retrieve events that are denoted with 'requires_action'
433 // since these will have our tool_calls
434 if (event.event === "thread.run.requires_action") {
435 await this.handleRequiresAction(
436 event.data,
437 event.data.id,
438 event.data.thread_id
439 );
440 }
441 } catch (error) {
442 console.error("Error handling event:", error);
443 }
444 }
445
446 async handleRequiresAction(data, runId, threadId) {
447 const toolOutputs = data.required_action.submit_tool_outputs.tool_calls.map(
448 (toolCall) => {
449 if (toolCall.function.name === "getCurrentTemperature") {
450 return { tool_call_id: toolCall.id, output: "57" };
451 } else if (toolCall.function.name === "getRainProbability") {
452 return { tool_call_id: toolCall.id, output: "0.06" };
453 }
454 throw new Error(`Unknown tool: ${toolCall.function.name}`);
455 }
456 );
457 // Submit all the tool outputs at the same time
458 await this.submitToolOutputs(toolOutputs, runId, threadId);
459 }
460
461 async submitToolOutputs(toolOutputs, runId, threadId) {
462 try {
463 // Use the submitToolOutputsStream helper
464 const stream = this.client.beta.threads.runs.submitToolOutputsStream(
465 runId,
466 { thread_id: threadId, tool_outputs: toolOutputs }
467 );
468 for await (const event of stream) {
469 this.emit("event", event);
470 }
471 } catch (error) {
472 console.error("Error submitting tool outputs:", error);
473 }
474 }
475}
476
477const eventHandler = new EventHandler(client);
478eventHandler.on("event", eventHandler.onEvent.bind(eventHandler));
479
480const stream = await client.beta.threads.runs.stream(threadId, {
481 assistant_id: assistantId,
482});
483
484for await (const event of stream) {
485 eventHandler.emit("event", event);
486}
487```
488
489```python
490from typing_extensions import override
491from openai import AssistantEventHandler
492
493class EventHandler(AssistantEventHandler):
494 @override
495 def on_event(self, event):
496 # Retrieve events that are denoted with 'requires_action'
497 # since these will have our tool_calls
498 if event.event == "thread.run.requires_action":
499 run_id = event.data.id # Retrieve the run ID from the event data
500 self.handle_requires_action(event.data, run_id)
501
502 def handle_requires_action(self, data, run_id):
503 tool_outputs = []
504
505 for tool in data.required_action.submit_tool_outputs.tool_calls:
506 if tool.function.name == "get_current_temperature":
507 tool_outputs.append({"tool_call_id": tool.id, "output": "57"})
508 elif tool.function.name == "get_rain_probability":
509 tool_outputs.append({"tool_call_id": tool.id, "output": "0.06"})
510
511 # Submit all tool_outputs at the same time
512 self.submit_tool_outputs(tool_outputs, run_id)
513
514 def submit_tool_outputs(self, tool_outputs, run_id):
515 # Use the submit_tool_outputs_stream helper
516 with client.beta.threads.runs.submit_tool_outputs_stream(
517 thread_id=self.current_run.thread_id,
518 run_id=self.current_run.id,
519 tool_outputs=tool_outputs,
520 event_handler=EventHandler(),
521 ) as stream:
522 for text in stream.text_deltas:
523 print(text, end="", flush=True)
524 print()
525
526with client.beta.threads.runs.stream(
527 thread_id=thread.id,
528 assistant_id=assistant.id,
529 event_handler=EventHandler(),
530) as stream:
531 stream.until_done()
532```
533
534
535
536
537
538
539
540Without streaming
541
542
543
544Runs are asynchronous, which means you'll want to monitor their `status` by polling the Run object until a
545[terminal status](https://developers.openai.com/api/docs/assistants/deep-dive#runs-and-run-steps) is reached. For convenience, where available, the 'create and poll' SDK helpers assist both in
546creating the run and then polling for its completion. The Go tab shows the equivalent workflow with manual polling. Once the Run completes, you can list the
547Messages added to the Thread by the Assistant. Finally, you would retrieve all the `tool_outputs` from
548`required_action` and submit them at the same time to the 'submit tool outputs and poll' helper.
549
550```javascript
551async function handleRequiresAction(run) {
552 // Check if there are tools that require outputs
553 if (
554 run.required_action &&
555 run.required_action.submit_tool_outputs &&
556 run.required_action.submit_tool_outputs.tool_calls
557 ) {
558 // Loop through each tool in the required action section
559 const toolOutputs = run.required_action.submit_tool_outputs.tool_calls.map(
560 (tool) => {
561 if (tool.function.name === "getCurrentTemperature") {
562 return { tool_call_id: tool.id, output: "57" };
563 } else if (tool.function.name === "getRainProbability") {
564 return { tool_call_id: tool.id, output: "0.06" };
565 }
566 throw new Error(`Unknown tool: ${tool.function.name}`);
567 }
568 );
569
570 // Submit all tool outputs at once after collecting them in a list
571 if (toolOutputs.length > 0) {
572 run = await client.beta.threads.runs.submitToolOutputsAndPoll(run.id, {
573 thread_id: thread.id,
574 tool_outputs: toolOutputs,
575 });
576 console.log("Tool outputs submitted successfully.");
577 } else {
578 console.log("No tool outputs to submit.");
579 }
580
581 // Check status after submitting tool outputs
582 return handleRunStatus(run);
583 }
584}
585
586async function handleRunStatus(run) {
587 // Check if the run is completed
588 if (run.status === "completed") {
589 let messages = await client.beta.threads.messages.list(thread.id);
590 console.log(messages.data);
591 return messages.data;
592 } else if (run.status === "requires_action") {
593 console.log(run.status);
594 return await handleRequiresAction(run);
595 } else {
596 console.error("Run did not complete:", run);
597 }
598}
599
600// Create and poll run
601let run = await client.beta.threads.runs.createAndPoll(thread.id, {
602 assistant_id: assistant.id,
603});
604
605handleRunStatus(run);
606```
607
608```python
609run = client.beta.threads.runs.create_and_poll(
610 thread_id=thread.id,
611 assistant_id=assistant.id,
612)
613
614if run.status == "completed":
615 messages = client.beta.threads.messages.list(thread_id=thread.id)
616 print(messages)
617
618# Define the list to store tool outputs
619tool_outputs = []
620
621# Loop through each tool in the required action section
622if run.required_action:
623 for tool in run.required_action.submit_tool_outputs.tool_calls:
624 if tool.function.name == "get_current_temperature":
625 tool_outputs.append({"tool_call_id": tool.id, "output": "57"})
626 elif tool.function.name == "get_rain_probability":
627 tool_outputs.append({"tool_call_id": tool.id, "output": "0.06"})
628
629# Submit all tool outputs at once after collecting them in a list
630if tool_outputs:
631 try:
632 run = client.beta.threads.runs.submit_tool_outputs_and_poll(
633 thread_id=thread.id,
634 run_id=run.id,
635 tool_outputs=tool_outputs,
636 )
637 print("Tool outputs submitted successfully.")
638 except Exception as e:
639 print("Failed to submit tool outputs:", e)
640else:
641 print("No tool outputs to submit.")
642
643if run.status == "completed":
644 messages = client.beta.threads.messages.list(thread_id=thread.id)
645 print(messages)
646else:
647 print(run.status)
648```
649
650```go
651run, err := client.Beta.Threads.Runs.New(context.Background(), thread.ID, openai.BetaThreadRunNewParams{
652 AssistantID: assistant.ID,
653})
654if err != nil {
655 panic(err)
656}
657run = pollRun(client, thread.ID, run)
658if run.Status == openai.RunStatusRequiresAction {
659 outputs := make([]openai.BetaThreadRunSubmitToolOutputsParamsToolOutput, 0)
660 for _, toolCall := range run.RequiredAction.SubmitToolOutputs.ToolCalls {
661 switch toolCall.Function.Name {
662 case "get_current_temperature":
663 outputs = append(outputs, openai.BetaThreadRunSubmitToolOutputsParamsToolOutput{
664 ToolCallID: openai.String(toolCall.ID), Output: openai.String("57"),
665 })
666 case "get_rain_probability":
667 outputs = append(outputs, openai.BetaThreadRunSubmitToolOutputsParamsToolOutput{
668 ToolCallID: openai.String(toolCall.ID), Output: openai.String("0.06"),
669 })
670 }
671 }
672 if len(outputs) > 0 {
673 run, err = client.Beta.Threads.Runs.SubmitToolOutputs(
674 context.Background(), thread.ID, run.ID,
675 openai.BetaThreadRunSubmitToolOutputsParams{ToolOutputs: outputs},
676 )
677 if err != nil {
678 panic(err)
679 }
680 run = pollRun(client, thread.ID, run)
681 }
682}
683if run.Status == openai.RunStatusCompleted {
684 messages, err := client.Beta.Threads.Messages.List(context.Background(), thread.ID, openai.BetaThreadMessageListParams{})
685 if err != nil {
686 panic(err)
687 }
688 fmt.Println(messages.Data)
689} else {
690 fmt.Println(run.Status)
691}
692
693func pollRun(client openai.Client, threadID string, run *openai.Run) *openai.Run {
694 for run.Status == openai.RunStatusQueued || run.Status == openai.RunStatusInProgress {
695 time.Sleep(time.Second)
696 next, err := client.Beta.Threads.Runs.Get(context.Background(), threadID, run.ID)
697 if err != nil {
698 panic(err)
699 }
700 run = next
701 }
702 return run
703}
704```
705
706```java
707import com.openai.client.OpenAIClient;
708import com.openai.client.okhttp.OpenAIOkHttpClient;
709import com.openai.models.beta.threads.runs.Run;
710import com.openai.models.beta.threads.runs.RunCreateParams;
711import com.openai.models.beta.threads.runs.RunRetrieveParams;
712import com.openai.models.beta.threads.runs.RunStatus;
713import com.openai.models.beta.threads.runs.RunSubmitToolOutputsParams;
714import java.util.ArrayList;
715
716String threadId = System.getenv("OPENAI_EXAMPLE_THREAD_ID");
717Run run =
718 client
719 .beta()
720 .threads()
721 .runs()
722 .create(
723 threadId,
724 RunCreateParams.builder()
725 .assistantId(System.getenv("OPENAI_EXAMPLE_ASSISTANT_ID"))
726 .build());
727run = poll(client, threadId, run);
728
729if (run.status().equals(RunStatus.REQUIRES_ACTION)) {
730 var action =
731 run.requiredAction()
732 .orElseThrow(() -> new IllegalStateException("Run has no required action"));
733 var outputs = new ArrayList<RunSubmitToolOutputsParams.ToolOutput>();
734 for (var call : action.submitToolOutputs().toolCalls()) {
735 String output =
736 switch (call.function().name()) {
737 case "get_current_temperature" -> "57";
738 case "get_rain_probability" -> "0.06";
739 default -> null;
740 };
741 if (output != null) {
742 outputs.add(
743 RunSubmitToolOutputsParams.ToolOutput.builder()
744 .toolCallId(call.id())
745 .output(output)
746 .build());
747 }
748 }
749 if (outputs.isEmpty()) throw new IllegalStateException("No supported tool calls requested");
750 run =
751 client
752 .beta()
753 .threads()
754 .runs()
755 .submitToolOutputs(
756 run.id(),
757 RunSubmitToolOutputsParams.builder()
758 .threadId(threadId)
759 .toolOutputs(outputs)
760 .build());
761 run = poll(client, threadId, run);
762}
763
764if (!run.status().equals(RunStatus.COMPLETED)) {
765 throw new IllegalStateException("Run ended with status: " + run.status());
766}
767client.beta().threads().messages().list(threadId).items().stream()
768 .flatMap(message -> message.content().stream())
769 .flatMap(content -> content.text().stream())
770 .forEach(content -> System.out.println(content.text().value()));
771```
772
773```ruby
774require "openai"
775
776client = OpenAI::Client.new
777thread_id = ENV.fetch("OPENAI_THREAD_ID")
778assistant_id = ENV.fetch("OPENAI_ASSISTANT_ID")
779
780poll_run = lambda do |run|
781 while [
782 OpenAI::Beta::Threads::RunStatus::QUEUED,
783 OpenAI::Beta::Threads::RunStatus::IN_PROGRESS
784 ].include?(run.status)
785 sleep(2)
786 run = client.beta.threads.runs.retrieve(run.id, thread_id: thread_id)
787 end
788 run
789end
790
791run = client.beta.threads.runs.create(thread_id, assistant_id: assistant_id)
792run = poll_run.call(run)
793
794if run.status == OpenAI::Beta::Threads::RunStatus::REQUIRES_ACTION
795 required_action = run.required_action or raise "Run has no required action"
796 tool_outputs = required_action.submit_tool_outputs.tool_calls.filter_map do |tool_call|
797 output = case tool_call.function.name
798 when "get_current_temperature" then "57"
799 when "get_rain_probability" then "0.06"
800 end
801 {tool_call_id: tool_call.id, output: output} if output
802 end
803 raise "No supported tool calls were requested" if tool_outputs.empty?
804
805 run = client.beta.threads.runs.submit_tool_outputs(
806 run.id,
807 thread_id: thread_id,
808 tool_outputs: tool_outputs
809 )
810 run = poll_run.call(run)
811end
812
813if run.status == OpenAI::Beta::Threads::RunStatus::COMPLETED
814 messages = client.beta.threads.messages.list(thread_id)
815 messages.auto_paging_each { |message| puts(message.content) }
816else
817 warn("Run ended with status: #{run.status}")
818end
819```
820
821
822
823### Using Structured Outputs
824
825When you enable [Structured Outputs](https://developers.openai.com/api/docs/guides/structured-outputs) by supplying `strict: true`, the OpenAI API will pre-process your supplied schema on your first request, and then use this artifact to constrain the model to your schema.
826
827```javascript
828const assistant = await client.beta.assistants.create({
829 model: "gpt-4o-2024-08-06",
830 instructions:
831 "You are a weather bot. Use the provided functions to answer questions.",
832 tools: [
833 {
834 type: "function",
835 function: {
836 name: "getCurrentTemperature",
837 description: "Get the current temperature for a specific location",
838 parameters: {
839 type: "object",
840 properties: {
841 location: {
842 type: "string",
843 description: "The city and state, e.g., San Francisco, CA",
844 },
845 unit: {
846 type: "string",
847 enum: ["Celsius", "Fahrenheit"],
848 description:
849 "The temperature unit to use. Infer this from the user's location.",
850 },
851 },
852 required: ["location", "unit"],
853 // highlight-start
854 additionalProperties: false,
855 // highlight-end
856 },
857 // highlight-start
858 strict: true,
859 // highlight-end
860 },
861 },
862 {
863 type: "function",
864 function: {
865 name: "getRainProbability",
866 description: "Get the probability of rain for a specific location",
867 parameters: {
868 type: "object",
869 properties: {
870 location: {
871 type: "string",
872 description: "The city and state, e.g., San Francisco, CA",
873 },
874 },
875 required: ["location"],
876 // highlight-start
877 additionalProperties: false,
878 // highlight-end
879 },
880 // highlight-start
881 strict: true,
882 // highlight-end
883 },
884 },
885 ],
886});
887```
888
889```python
890from openai import OpenAI
891
892client = OpenAI()
893
894assistant = client.beta.assistants.create(
895 instructions="You are a weather bot. Use the provided functions to answer questions.",
896 model="gpt-4o-2024-08-06",
897 tools=[
898 {
899 "type": "function",
900 "function": {
901 "name": "get_current_temperature",
902 "description": "Get the current temperature for a specific location",
903 "parameters": {
904 "type": "object",
905 "properties": {
906 "location": {
907 "type": "string",
908 "description": "The city and state, e.g., San Francisco, CA",
909 },
910 "unit": {
911 "type": "string",
912 "enum": ["Celsius", "Fahrenheit"],
913 "description": "The temperature unit to use. Infer this from the user's location.",
914 },
915 },
916 "required": ["location", "unit"],
917 # highlight-start
918 "additionalProperties": False,
919 # highlight-end
920 },
921 # highlight-start
922 "strict": True,
923 # highlight-end
924 },
925 },
926 {
927 "type": "function",
928 "function": {
929 "name": "get_rain_probability",
930 "description": "Get the probability of rain for a specific location",
931 "parameters": {
932 "type": "object",
933 "properties": {
934 "location": {
935 "type": "string",
936 "description": "The city and state, e.g., San Francisco, CA",
937 }
938 },
939 "required": ["location"],
940 # highlight-start
941 "additionalProperties": False,
942 # highlight-end
943 },
944 # highlight-start
945 "strict": True,
946 # highlight-end
947 },
948 },
949 ],
950)
951```
952
953```go
954assistant, err := client.Beta.Assistants.New(context.Background(), openai.BetaAssistantNewParams{
955 Model: shared.ChatModelGPT4o2024_08_06,
956 Instructions: openai.String("You are a weather bot. Use the provided functions to answer questions."),
957 Tools: weatherTools(),
958})
959if err != nil {
960 panic(err)
961}
962
963func weatherTools() []openai.AssistantToolUnionParam {
964 return []openai.AssistantToolUnionParam{
965 openai.AssistantToolParamOfFunction(shared.FunctionDefinitionParam{
966 Name: "get_current_temperature",
967 Description: openai.String("Get the current temperature for a specific location"),
968 Parameters: map[string]any{
969 "type": "object",
970 "properties": map[string]any{
971 "location": map[string]any{"type": "string", "description": "The city and state, e.g., San Francisco, CA"},
972 "unit": map[string]any{"type": "string", "enum": []string{"Celsius", "Fahrenheit"}, "description": "The temperature unit to use. Infer this from the user's location."},
973 },
974 "required": []string{"location", "unit"},
975 "additionalProperties": false,
976 },
977 Strict: openai.Bool(true),
978 }),
979 openai.AssistantToolParamOfFunction(shared.FunctionDefinitionParam{
980 Name: "get_rain_probability",
981 Description: openai.String("Get the probability of rain for a specific location"),
982 Parameters: map[string]any{
983 "type": "object",
984 "properties": map[string]any{
985 "location": map[string]any{"type": "string", "description": "The city and state, e.g., San Francisco, CA"},
986 },
987 "required": []string{"location"},
988 "additionalProperties": false,
989 },
990 Strict: openai.Bool(true),
991 }),
992 }
993}
994```
995
996```java
997import com.openai.client.OpenAIClient;
998import com.openai.client.okhttp.OpenAIOkHttpClient;
999import com.openai.core.JsonValue;
1000import com.openai.models.FunctionDefinition;
1001import com.openai.models.FunctionParameters;
1002import com.openai.models.beta.assistants.AssistantCreateParams;
1003import java.util.List;
1004import java.util.Map;
1005
1006var assistant =
1007 client
1008 .beta()
1009 .assistants()
1010 .create(
1011 AssistantCreateParams.builder()
1012 .model("gpt-4o-2024-08-06")
1013 .instructions(
1014 "You are a weather bot. Use the provided functions to answer questions.")
1015 .addFunctionTool(
1016 FunctionDefinition.builder()
1017 .name("get_current_temperature")
1018 .description("Get the current temperature for a specific location")
1019 .strict(true)
1020 .parameters(
1021 FunctionParameters.builder()
1022 .putAdditionalProperty("type", JsonValue.from("object"))
1023 .putAdditionalProperty(
1024 "properties",
1025 JsonValue.from(
1026 Map.of(
1027 "location",
1028 Map.of(
1029 "type", "string",
1030 "description",
1031 "The city and state, e.g., San Francisco, CA"),
1032 "unit",
1033 Map.of(
1034 "type",
1035 "string",
1036 "enum",
1037 List.of("Celsius", "Fahrenheit"),
1038 "description",
1039 "The temperature unit to use. Infer this from the user's location."))))
1040 .putAdditionalProperty(
1041 "required", JsonValue.from(List.of("location", "unit")))
1042 .putAdditionalProperty(
1043 "additionalProperties", JsonValue.from(false))
1044 .build())
1045 .build())
1046 .addFunctionTool(
1047 FunctionDefinition.builder()
1048 .name("get_rain_probability")
1049 .description("Get the probability of rain for a specific location")
1050 .strict(true)
1051 .parameters(
1052 FunctionParameters.builder()
1053 .putAdditionalProperty("type", JsonValue.from("object"))
1054 .putAdditionalProperty(
1055 "properties",
1056 JsonValue.from(
1057 Map.of(
1058 "location",
1059 Map.of(
1060 "type", "string",
1061 "description",
1062 "The city and state, e.g., San Francisco, CA"))))
1063 .putAdditionalProperty(
1064 "required", JsonValue.from(List.of("location")))
1065 .putAdditionalProperty(
1066 "additionalProperties", JsonValue.from(false))
1067 .build())
1068 .build())
1069 .build());
1070
1071System.out.println(assistant.id());
1072```
1073
1074```ruby
1075require "openai"
1076
1077client = OpenAI::Client.new
1078assistant = client.beta.assistants.create(
1079 model: "gpt-4o",
1080 name: "Weather assistant",
1081 tools: [{type: :function, function: {name: "get_weather", description: "Get weather", parameters: {type: :object, properties: {city: {type: :string}}, required: ["city"], additionalProperties: false}, strict: true}}]
1082)
1083puts(assistant.id)
1084```