Server-side tools (OpenAI Responses API)
This guide explains how to call server-side tools using the OpenAI Responses API. It presents an example of a tool that returns the weather in a given location.
Code demo available
This guide includes a code demo to help you get started. See the GitHub repository.
First, define the tool in the OpenAI Responses API tool format:
import OpenAI from 'openai'
const weatherTool: OpenAI.Responses.Tool = {
type: 'function',
name: 'get_weather',
parameters: {
type: 'object',
properties: {
location: {
type: 'string',
description: 'The location to get the weather for',
},
},
required: ['location'],
},
strict: false,
}
Then, when you call the OpenAI API, include the tool in the tools
array.
import {
AiAgentToolkit,
openaiResponsesAdapter,
ChatMessagesFormatter,
} from '@tiptap-pro/extension-ai-agent-server'
import OpenAI from 'openai'
const { chatMessages, schemaAwarenessData } = request
const toolkit = new AiAgentToolkit({
adapter: openaiResponsesAdapter,
schemaAwarenessData,
})
const formatter = new ChatMessagesFormatter({
initialMessages: chatMessages,
adapter: openaiResponsesAdapter,
})
// Initialize the OpenAI client
const openai = new OpenAI()
// Call the OpenAI Responses API
const response = await openai.responses.create({
model: 'gpt-4.1',
input: [
{
role: 'developer',
content: `
<Your system prompt>
${toolkit.getSystemPrompt()}
`,
},
...formatter.format(),
],
// Include the weather tool in the tools array, beside
// the other tools provided by AiAgentToolkit
tools: [...toolkit.format(), weatherTool],
})
First, add the response to the formatter so that it is included in the conversation.
formatter.addAiResponse(response)
Then, check if the response contains a server-side tool call like the weather tool. If so, call the tool and add the result to the formatter. Then, call the OpenAI API again.
Repeat this process until there are no more server-side tool calls in the response.
const isGetWeatherMessage = (
message: OpenAI.Responses.ResponseOutputItem,
): message is OpenAI.Responses.ResponseFunctionToolCall =>
message.type === 'function_call' && message.name === 'get_weather'
let response: OpenAI.Responses.Response | null = null
while (!response || response.output?.some(isGetWeatherMessage)) {
// Call the OpenAI Responses API
response = await openai.responses.create({
model: 'gpt-4.1',
input: [
{
role: 'developer',
content: `${systemPrompt}\n${toolkit.getSystemPrompt()}`,
},
...formatter.format(),
],
// Include the weather tool in the tools array, beside the other tools provided by AiAgentToolkit
tools: [...toolkit.format(), weatherTool],
})
// Convert the response to the format expected by the AI Agent extension
formatter.addAiResponse(response)
// Process weather tool calls
for (const toolCall of response.output) {
if (isGetWeatherMessage(toolCall)) {
const args = locationSchema.parse(JSON.parse(toolCall.arguments))
const weatherResult = await getWeather(args.location)
// Add the tool call result to the formatter
formatter.addChatMessage({
type: 'toolCallResult',
toolName: 'get_weather',
toolCallId: toolCall.call_id,
result: weatherResult,
isError: false,
})
}
}
}
Finally, when there are no more server-side tool calls, use the formatter
to convert the response to the format expected by the AI Agent extension.
const response = formatter.getResolverResponse()
The value returned from formatter.getResolverResponse()
should be the response of your API endpoint and the return value of the resolver function.