Build

Make a request

Send a chat completion to SID-1 and read the tool calls it returns.

The SID-1 retrieval pipeline with the request stage highlighted. Four boxes show the flow: a question box feeds into SID-1; SID-1 exchanges repeated tool calls (BM25, ANN, and similar) with a search backend and receives content and metadata back; SID-1 returns ranked results. A dashed box labeled 'Make a request' encloses the question and SID-1 boxes, marking the part this page covers: sending the query to SID-1 and reading the tool calls it returns.

This guide covers how to make a single request to SID-1 and parse the response. SID-1 uses the tool-calling API: all actions are defined as tools and in response to every request, SID-1 will return a list of tool calls that you need to parse. The assistant message's content carries the model's reasoning, not an answer: ignore it, and never show it to end users.

Send the request

SID-1 uses an OpenAI-compatible v1/chat/completions endpoint. You're free to use any package compatible with that API like the official OpenAI package, LangChain ChatOpenAI, or Vercel's AI SDK. SID-1 takes a system prompt that includes a list of tools describing the search queries your backend supports. It then returns a list of these tool invocations.

Here's everything you need to do:

  1. Set the base URL to https://api.sid-1.com/v1 and set a SID_API_KEY. Create a key on the API keys page.
  2. Define a system prompt according to the system prompt specs. Tool parameters and descriptions go into the system prompt.
  3. Pass a tools list to activate tool calling. You must include at least one entry, but SID-1 ignores its contents, so a single placeholder stub is enough. The real tools live in the system prompt. See the tool reference for details.
  4. Place the query, and only the query, in the first user message. Multiple queries should be separated into multiple requests. Extra information or instructions should go in the system prompt.
  5. Use sid-1 as the model name.

This example request sends one question and passes a single placeholder tool to switch on tool-call parsing. The real tools (search, text_search, read, and report_helpful_ids) are described in the system prompt, so SID-1 reads each tool's behavior from there and returns tool calls for your code to run. report_helpful_ids has a special purpose that we'll cover in Loop and exit.

# SYSTEM_PROMPT contains the system prompt from /docs/reference/system-prompt.
curl https://api.sid-1.com/v1/chat/completions \
  -H "Authorization: Bearer $SID_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<JSON
{
  "model": "sid-1",
  "messages": [
    {"role": "system", "content": $(jq -Rs . <<< "$SYSTEM_PROMPT")},
    {"role": "user", "content": "In which cities were the indoor and outdoor 4 minute mile records set?"}
  ],
  "tools": [
    {"type": "function", "function": {"name": "dummy"}}
  ]
}
JSON
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.sid-1.com/v1", api_key=os.environ["SID_API_KEY"])

# SYSTEM_PROMPT contains the system prompt. tools contains a single placeholder stub.
messages = [
    {"role": "system", "content": SYSTEM_PROMPT},
    {"role": "user", "content": "In which cities were the indoor and outdoor 4 minute mile records set?"},
]

response = client.chat.completions.create(model="sid-1", messages=messages, tools=tools)
assistant_msg = response.choices[0].message
import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://api.sid-1.com/v1", apiKey: process.env.SID_API_KEY });

// SYSTEM_PROMPT contains the system prompt. tools contains a single placeholder stub.
const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [
  { role: "system", content: SYSTEM_PROMPT },
  { role: "user", content: "In which cities were the indoor and outdoor 4 minute mile records set?" },
];

const response = await client.chat.completions.create({ model: "sid-1", messages, tools });
const assistantMsg = response.choices[0].message;

tool_choice: required is not supported

The chat completions API for SID-1 currently does not support setting the parameter "tool_choice": "required". Either omit the parameter or set it explicitly to the default, "tool_choice": "auto".

List tool names only

The tools array tells the API which functions SID-1 can call. Put each tool's behavior and arguments in the system prompt, not in tools. SID-1 does not read description or parameters fields from this request.

Read the response

SID-1 returns tool calls in the assistant message's tool_calls array. A turn can (and will) include more than one call, so iterate over the full array and run the calls in parallel (see run tool calls in parallel). Each entry has a tool name and an arguments string of JSON.

{
  "role": "assistant",
  "content": "<think>\nI need the cities for both records, so I'll run a few searches in parallel and a lexical search for the exact phrase.\n</think>\n\n",
  "tool_calls": [
    {
      "id": "chatcmpl-tool-1a2b3c4d",
      "type": "function",
      "function": {
        "name": "search",
        "arguments": "{\"query\": \"indoor 4 minute mile record city\", \"limit\": 5}"
      }
    },
    {
      "id": "chatcmpl-tool-5e6f7a8b",
      "type": "function",
      "function": {
        "name": "search",
        "arguments": "{\"query\": \"outdoor 4 minute mile record city\", \"limit\": 5}"
      }
    },
    {
      "id": "chatcmpl-tool-9c0d1e2f",
      "type": "function",
      "function": {
        "name": "text_search",
        "arguments": "{\"query\": \"four-minute mile world record\", \"limit\": 10}"
      }
    }
  ]
}

Ignore content, read only tool_calls

The assistant message's content holds the model's internal reasoning (returned in redacted_thinking tags), not a user-facing answer. Parse only tool_calls, and never show content to end users. limit is optional (default 5); the model sets it per call and may omit it.

Loop over every entry, extract the name, and parse the arguments JSON string before you dispatch to your handler. We cover the handlers in more depth in the next section. For now, we print each tool call to the console:

import json

for tc in assistant_msg.tool_calls:
    name = tc.function.name
    # arguments is a JSON string, so parse it before passing it to your handler.
    arguments = json.loads(tc.function.arguments)
    print(name, arguments)
for (const tc of assistantMsg.tool_calls ?? []) {
  const name = tc.function.name;
  // arguments is a JSON string, so parse it before passing it to your handler.
  const args = JSON.parse(tc.function.arguments);
  console.log(name, args);
}

When there's no tool call

Treat a response without tool calls as a failed turn. Retry the request (preferred) or end the run instead of passing the message back into the loop. If this happens often, double-check your tool definitions and system prompt.

if not assistant_msg.tool_calls:
    raise RuntimeError("Expected SID-1 to return at least one tool call.")
if (!assistantMsg.tool_calls?.length) {
  throw new Error("Expected SID-1 to return at least one tool call.");
}

Content