SPB Git forge

spb/doc-api

Public
2commits 1branches 0releases
15.7 MBsize
maindefault branch
13 days agolast push
Python 88.3% TypeScript 7.6% Shell 4.1%
2.7 KB

# Custom tools (type: "custom") — free-form text and CFG grammars

Status: DOCUMENTED · LIVE_VERIFIED (2026-09-18, gpt-5.4-nano, regex grammar and default text format; streaming events captured) Sources: https://developers.openai.com/api/docs/guides/function-calling#custom-tools · openapi-master.yaml CustomToolParam, CustomGrammarFormatParam, CustomToolCall, CustomToolCallOutput, CustomToolChatCompletions, ToolChoiceCustom Last verified: 2026-09-18

# Definition

Field Type Req. Notes
type "custom" yes
name string yes
description string no explain the grammar/expected text here
format {type:"text"} (default) | {type:"grammar", syntax:"lark"|"regex", definition:string} no grammar constrains sampling (LLGuidance); terminals/regex use Rust regex syntax
async, defer_loading, allowed_callers no same semantics as functions

Chat Completions shape: {"type":"custom","custom":{"name","description","format":{"type":"grammar","grammar":{"syntax","definition"}}}} (note the extra grammar wrapper); forced choice {"type":"custom","custom":{"name":…}}.

# Items

  • Output custom_tool_call: {"id":"ctc_…","type":"custom_tool_call","status":"completed","call_id":"call_…","name":"answer_yes_no","input":"yes"} (+ optional namespace, caller, async).
  • Input custom_tool_call_output: {"type":"custom_tool_call_output","call_id":"call_…","output":"<string>" | [content parts]}.

# Streaming (live)

response.output_item.added → response.custom_tool_call_input.delta (delta, item_id, output_index, obfuscation) → response.custom_tool_call_input.done (input) → response.output_item.done.

# Grammar guidance (docs)

  • Lark subset: terminals UPPERCASE (lexer, greedy longest-match), rules lowercase; keep "free text between anchors" as one bounded regex terminal; avoid open-ended %ignore; bounded quantifiers ({0,10}) over *.
  • Regex: Rust regex crate syntax, no verbose mode, escape newlines as \n; some features unsupported.
  • Too-complex grammars → API error; iterate on grammar + prompt + description; out-of-distribution symptom = long repetitive but syntactically valid output.

# Live evidence

Probe Model Status Result
regex `^(yes no)$, tool_choice {type:custom,name}` gpt-5.4-nano 200
text format, tool_choice: "required" gpt-5.4-nano 200 custom_tool_call
stream gpt-5.4-nano 200 7 events incl. custom_tool_call_input.delta/done

Examples: examples/openai/tools/custom-tools/ (sh/py/ts). Test: test_custom_tool_regex_grammar.