Implementation:Openai Openai node Completions RunTools
| Knowledge Sources | |
|---|---|
| Domains | Function_Calling, Agentic_Patterns |
| Last Updated | 2026-02-15 00:00 GMT |
Overview
Concrete tool for running automatic tool execution loops with Chat Completions provided by the openai-node SDK.
Description
The Completions.runTools() method creates a ChatCompletionRunner (non-streaming) or ChatCompletionStreamingRunner (streaming) that manages the tool call loop automatically. It delegates to AbstractChatCompletionRunner._runTools() which implements the core loop: call the API, check for tool calls, parse arguments, execute callbacks, append results, and repeat.
The runner is an EventStream that emits typed events: message, chatCompletion, functionToolCall, functionToolCallResult. Consumers can listen to events or await finalChatCompletion().
Usage
Call client.chat.completions.runTools() with tool definitions that include implementation callbacks (via zodFunction or manual RunnableFunction objects). The runner handles the entire loop.
Code Reference
Source Location
- Repository: openai-node
- File: src/resources/chat/completions/completions.ts (runTools method), src/lib/AbstractChatCompletionRunner.ts (loop implementation)
- Lines: completions.ts:L167-193 (runTools), AbstractChatCompletionRunner.ts:L254-382 (_runTools loop)
Signature
class Completions extends APIResource {
// Non-streaming overload
runTools<
Params extends ChatCompletionToolRunnerParams<any>,
ParsedT = ExtractParsedContentFromParams<Params>,
>(body: Params, options?: RunnerOptions): ChatCompletionRunner<ParsedT>;
// Streaming overload
runTools<
Params extends ChatCompletionStreamingToolRunnerParams<any>,
ParsedT = ExtractParsedContentFromParams<Params>,
>(body: Params, options?: RunnerOptions): ChatCompletionStreamingRunner<ParsedT>;
}
interface RunnerOptions {
maxChatCompletions?: number; // Default: 10
}
Import
import OpenAI from 'openai';
// Access via: client.chat.completions.runTools(...)
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| body.messages | Array<ChatCompletionMessageParam> | Yes | Conversation messages |
| body.model | string | Yes | Model ID |
| body.tools | AutoParseableTool[] | Yes | Tools with implementation callbacks |
| body.stream | boolean | No | Enable streaming mode |
| options.maxChatCompletions | number | No (default 10) | Maximum API calls before stopping |
Outputs
| Name | Type | Description |
|---|---|---|
| runner | ChatCompletionStreamingRunner | Event stream with tool execution lifecycle |
| runner.finalChatCompletion() | Promise<ParsedChatCompletion> | Final model response after all tool calls resolved |
| runner.messages | ChatCompletionMessageParam[] | Complete conversation history including tool calls and results |
Usage Examples
Automatic Tool Execution
import { z } from 'zod';
import OpenAI from 'openai';
import { zodFunction } from 'openai/helpers/zod';
const client = new OpenAI();
const getWeather = zodFunction({
name: 'get_weather',
description: 'Get weather for a city',
parameters: z.object({ city: z.string() }),
function: async ({ city }) => ({ temp: 22, condition: 'sunny' }),
});
const lookupRestaurant = zodFunction({
name: 'lookup_restaurant',
description: 'Find restaurants in a city',
parameters: z.object({ city: z.string(), cuisine: z.string() }),
function: async ({ city, cuisine }) => ({ name: 'Le Bistro', rating: 4.5 }),
});
const runner = client.chat.completions.runTools({
model: 'gpt-4o',
messages: [
{ role: 'user', content: 'What is the weather in Paris, and recommend a French restaurant there?' },
],
tools: [getWeather, lookupRestaurant],
});
// Listen to events
runner.on('functionToolCallResult', (result) => {
console.log('Tool result:', result);
});
const completion = await runner.finalChatCompletion();
console.log(completion.choices[0].message.content);
Streaming with Tools
const runner = client.chat.completions.runTools({
model: 'gpt-4o',
stream: true,
messages: [{ role: 'user', content: 'What is the weather in Tokyo?' }],
tools: [getWeather],
});
runner.on('content.delta', ({ delta }) => {
process.stdout.write(delta);
});
await runner.finalChatCompletion();