Tool Docs in the Prompt
Short, honest schemas. Disabled tools disappear. Leftover examples that call shell after you removed shell are a bug.
The tool list in the prompt is a manual. If it is wrong, the model will still try. This lesson is the manual — names, when to use, when not to, argument types, side effects in plain language. It is not how to implement the functions, not JSON Schema for the runtime, not retrieval. Those belong later. If the manual advertises a function code will not run, you shipped a lie.
Rules for the manual:
- Only tools that are enabled for this run
- Name, when to use, when not to use, argument types
- Side effects in plain language (“emails a human,” “charges a card,” “read-only”)
- “If a tool is not listed, it does not exist. Do not pretend to call it.”
- One line per tool beats a PDF. If you need a PDF, the tool is too big. Split it (or split the agent)
Do not paste 40 pages of OpenAPI. Do not leave shell in a few-shot after you removed shell. Do not mention a tool “as a joke.” Curiosity is how you get a hallucinated tool, then a parser error, then a retry that still wants shell.
The billing agent must not even see the word shell in docs or shots.
Billing must not even see the word shell. Zero means hidden.
Only enabled tools in the manualWhen a tool fails, the observation is still data
Put error=timeout vendor=x in the observation, not a stack. You pay for every token of stack, and the model will imitate it — including file paths and keys. Encode the observation (json.dumps). It cannot grant a new tool. It cannot become the spec.
Docs that say “on error, invent a status” are how you skip get_job. Docs that say “on error, handoff or retry once” match the stop rules.
Generate the manual from the enable list
Do not hand-maintain a second copy of the catalog in a Google doc. docs_for(enabled) is unit-tested: disabled names absent, enabled names present, side-effect verbs present. When you disable a tool in code, the prompt docs and the few-shots must change in the same PR. Leftover docs and shots are how hallucinated tools are born.
Run to execute this in your browser. Nothing is sent to a server.
What printed: three tool lines plus “Tools not listed do not exist.” shell hidden True. Enabled names present. The catalog still contains shell for other agents. Billing never sees it. That is the test: not “the catalog is small,” but “this run’s string lacks disabled names.”
Walkthrough: leftover shell in a shot
Runtime drops shell for billing. The prompt docs still mention it. A few-shot still calls it. The model emits shell on a timeout. Parser errors. Retry still wants shell. The PR that disabled the tool did not grep docs or shots. docs_for(enabled) plus a test that the shot file contains only enabled names would have failed CI.
When get_job times out, the observation is error=timeout vendor=x encoded as JSON, not a stack with paths and keys. Stacks are expensive and imitated.
What goes wrong if you skip this
Hallucinated tools. OpenAPI novels steal the window. Disabled names haunt few-shots. Error stacks leak secrets. The tools track will implement functions; this lesson is the advertisement. Lying advertisements are bugs.
The tool list in the prompt is a manual generated from the enable list. One line per tool: name, types, when to use, when not, side effects in plain language. “If a tool is not listed, it does not exist.” Billing must not see shell in docs or shots. The PR that disables a tool greps both.
Failed tools return short encoded observations, not stacks. You pay for stack tokens and the model imitates paths and keys. Side-effect verbs stay on the line so the model cannot pretend a charge is read-only.
Do not paste forty pages of OpenAPI. If you need a PDF, the tool is too big or the agent is too wide. Split the tool or split the agent.
Common mistakes
| Mistake | Why | Repair |
|---|---|---|
| OpenAPI dump | Completeness | One line each |
| Leftover shots | Forgot grep | Test shot file vs enable list |
| Joke tools | Humor | Hallucinated names |
| Stack traces as obs | Debug | error=timeout encoded |
| Docs without side effects | Short | “emails a human” on the line |
Unit-test the string docs_for(enabled) the way you unit-test a renderer: enabled names present, disabled names absent, side-effect verbs present, the sentence “do not exist” present. Grep the few-shot file in the same test. When a tool fails, assert the observation is short and encoded, not a stack. The advertisement and the runtime enable list must change in one PR.
How agents use this
docs_for(enabled) is unit-tested with the few-shot file. The tools track designs the functions. The prompt only advertises what code will actually run. Side-effect verbs stay in the line. Error observations stay short and encoded. If billing can see the word shell, you failed the test even if the runtime would have refused the call. Curiosity in the manual is how hallucinated tools are born. Hide disabled names. Split fat tools. Keep the advertisement honest. One line per tool is a feature, not a lack of documentation. A PDF is a smell. If the tool needs a PDF, split the tool or split the agent. The prompt is a manual, not an SDK.
Tip:One line per tool beats a PDF. If you need a PDF, the tool is too big. Split it.
Check your understanding