Tools & Function Calling
Tools extend what an LLM can do during execution. When a template has tools assigned, PromptShuttle automatically manages the tool-calling loop: the LLM decides which tools to call, PromptShuttle executes them, feeds results back, and re-invokes the LLM until it produces a final answer.
How the tool loop works
1. Send prompt + tool definitions to LLM
2. LLM responds with tool_calls (or final text)
3. If tool_calls:
a. Execute all tool calls in parallel
b. Append results to conversation
c. Go to step 1 (re-invoke LLM with results)
4. If final text: return responseThe loop continues until the LLM stops calling tools or the maxToolCalls limit is reached.
Tool types
PromptShuttle supports five tool types, each suited to different use cases:
External
Calls an HTTP endpoint with parameters from the LLM's tool call
Virtual
Enables provider-native capabilities (web search, code interpreter)
Agent
Invokes another flow as a sub-agent, enabling multi-agent orchestration
CritiqueLoop
Runs a producer/critic refinement loop to iteratively improve output
MCP
Calls a tool on an external Model Context Protocol server
External tools
External tools call HTTP endpoints. The LLM decides the arguments; PromptShuttle builds the request and returns the response.
Configuration
name
Tool name (shown to the LLM)
description
What the tool does (helps the LLM decide when to use it)
parameters
Parameter schema (name, type, description, required, enum values)
webUrl
Base HTTP endpoint URL. An absolute https://… names a fixed host; a relative path (/api/v1/search) makes the tool caller-hosted
webUrls
Environment-specific URL overrides ({ "production": "https://...", "staging": "https://..." })
headers
Custom HTTP headers (e.g. API keys)
callbackTokenHeader
Header carrying the caller's per-run token on caller-hosted calls (default X-Tool-Token)
How it works
The LLM returns a tool call with arguments (e.g.
{ "query": "weather in Berlin" })PromptShuttle sends an HTTP GET to the configured URL with arguments as query parameters
The response body (up to 1MB) is returned to the LLM as the tool result
Parameter placeholders in URLs
External tool URLs support [[param]] placeholders that are substituted from the flow's request parameters:
If the flow was called with "parameters": { "region": "eu" }, the URL becomes https://api.example.com/v1/eu/search.
Environment-specific URLs
Use webUrls to point to different endpoints per environment:
Tools your own app serves
If the endpoint lives in the same application that calls PromptShuttle, its address differs on every machine that application runs on — so it does not belong on the tool at all. Give the tool a relative path instead and let each request supply the host:
The origin then comes from the X-Shuttle-Callback-Url header per request. If a request omits it, the tool call fails rather than falling back to a stored URL.
See Caller-Hosted Tools.
Virtual tools (provider-native)
Virtual tools enable capabilities built into the LLM provider, such as web search. They are handled natively by the provider — PromptShuttle passes them through.
Portable tokens
Use search or web_search to request web search. Both tokens map to the serving provider's own search tool, whatever its wire name is. Matching is case-insensitive.
search
web_search_preview
google_search
web_search
web_search
web_search
web_search_preview
google_search
web_search
web_search
social_search
—
—
—
x_search
x_search
—
—
—
x_search
url_context
—
url_context
—
web_search (degrades to search)
A token the serving provider does not offer is skipped, not failed — the model answers without the tool, so a fallback candidate degrades instead of dying. The run then records a vendorToolUnavailable warning (see Run Health) naming the skipped token. Before this warning existed the skip was silent.
Using virtual tools
Virtual tools can be enabled in two ways:
On the template — Create a tool with
type: VirtualandvirtualToolId: "search", then assign it to the templateAt request time — Pass
vendorTools: ["search"]in the flow run request
Citations
Search-grounded responses carry their sources in citations on the response payload (url, title, domain). Sources are unified across providers: OpenAI url_citation annotations, Gemini grounding chunks, xAI inline citations plus its top-level source list.
Combining vendorTools with a responseSchema is safe: PromptShuttle runs the research schema-free, adds one structuring turn when needed, and carries the research turn's citations onto the final structured answer. Measured provider behavior for a single combined call (the passthrough /chat/completions path): OpenAI keeps annotations alongside a JSON-schema response (measured 6/6, two model families, 2026-08-20); Gemini returns grounding chunks only unreliably under a schema (4 of 12 runs came back with zero chunks even though searches ran — both AI Studio and Vertex, gemini-3-flash-preview).
Agent tools
Agent tools invoke another flow as a sub-agent. This is the foundation of multi-agent orchestration in PromptShuttle.
Configuration
agentTemplateId
The ID of the flow to invoke as a sub-agent
maxAgentDepth
Maximum nesting depth for this specific agent (overrides tenant default)
How it works
The LLM calls the agent tool with arguments
PromptShuttle creates a child request linked to the parent
The child flow executes with its own tool-calling loop
The child's text response is returned to the parent LLM as the tool result
Cost is tracked both per-agent (direct) and across the tree (cumulative)
Safety mechanisms
Depth limits — Default max depth is 10. Configurable per tool, per tenant, or per request.
Cycle detection — PromptShuttle tracks the ancestor chain and prevents an agent from calling itself (directly or indirectly).
Cost limits — Per-request cost ceilings apply across the entire agent tree.
Context tools
When a template is running as a sub-agent, PromptShuttle automatically injects context tools:
get_context
Returns execution metadata: depth, agent path, cost used, budget remaining
sub-agents only
get_original_input
Returns the root request's original user messages
sub-agents only
get_state
Read from shared state (lexically scoped — child values shadow parent)
all requests with tools
set_state
Write to shared state (visible to child agents)
all requests with tools
These let agents be context-aware without hardcoding parent/child relationships.
A root request (the one you start) is only given the two state tools. The other two answer questions a root request can already see: get_original_input replays the root's own messages back to the model that is already reading them, and get_context reports a depth of 0 on a path of one. The state tools stay because a root write lands on the root's state, and every descendant reads it — that is the supported way to seed state for a whole agent tree before spawning.
All four remain callable by name at any depth, so a prompt that names one directly keeps working.
CritiqueLoop tools
CritiqueLoop tools implement an iterative refinement pattern: a "producer" flow generates output, then a "critic" flow evaluates it. If the critic rejects the output, the producer tries again with the critic's feedback.
Configuration
producerFlowId
Flow ID of the producer
criticFlowId
Flow ID of the critic
maxLoopIterations
Maximum refinement iterations (default 3)
How it works
The critic always runs with temperature: 0 for consistent evaluation.
Critic response format
The critic flow must return JSON matching this schema:
If approved is false, the feedback string is passed back to the producer for the next iteration.
MCP tools
MCP tools call tools on external Model Context Protocol servers. This lets you integrate with any MCP-compatible tool server.
See MCP Server Integration for setup details.
Managing tools via API
GET
/api/v1/tools
List all tools
GET
/api/v1/tools/{id}
Get a tool by ID
POST
/api/v1/tools
Create a new tool
PUT
/api/v1/tools/{id}
Update a tool
DELETE
/api/v1/tools/{id}
Delete a tool
GET
/api/v1/tools/{id}/usage
List flows that reference this tool
Tool parameter schema
Each tool defines its parameters with a list of properties:
Property types: String, Number. Use isList: true for array parameters. Use enum to constrain values.
Last updated