Prompts
A prompt defines how each request to an LLM is crafted. It specifies system instructions, a model reference, available tools, and behavioral configuration that shapes how the agent responds.
1. Prompt Definition
Each prompt specifies system instructions, a model reference, and optional configuration for tools, input validation, and response behavior.
1.1 Required Properties
A prompt definition MUST include the following properties:
| Property | Type | Description |
|---|---|---|
name | string | Unique identifier for this prompt |
toolDescription | string | Description shown when prompt is exposed as a tool |
prompt | PromptContent | System prompt content (string or structured) |
model | string | Model reference to use for this prompt |
1.2 Optional Properties
A prompt definition MAY include the following properties:
| Property | Type | Default | Description |
|---|---|---|---|
includeChat | boolean | false | Include full chat history |
includePastTools | boolean | false | Include past tool results |
parallelToolCalls | boolean | false | Allow parallel tool execution |
toolChoice | 'auto' | 'none' | 'required' | 'auto' | Tool calling strategy |
requiredSchema | ZodSchema | - | Input validation schema |
tools | (string | ToolConfig | SubpromptConfig | SubagentToolConfig)[] | - | Available tools, sub-prompts, and agent tools (including resumable/non-resumable subagents) |
variables | VariableDefinition[] | - | Variable declarations consumed by this prompt |
env | Record<string, string> | - | Prompt-level default environment variable values |
reasoning | ReasoningConfig | - | Extended thinking config |
recentImageThreshold | number | 10 | Messages to keep images |
hooks | string[] | - | Hook IDs to run for this prompt |
2. Prompt Content
2.1 String Prompts
The simplest form is a plain string containing the system instructions:
prompt: 'You are a helpful assistant. Be concise and accurate.'
System prompts SHOULD NOT contain secrets or sensitive credentials. Implementations SHOULD sanitize prompt content to prevent injection.
2.2 Structured Prompts
For composition and reuse, prompts can be structured arrays of parts:
prompt: [
{ type: 'text', content: 'You are a helpful assistant.\n\n' },
{ type: 'include', prompt: 'common_rules' },
{ type: 'text', content: '\n\nBe concise.' },
]
2.3 Prompt Parts
2.3.1 Text Parts
Text parts contain static content:
| Property | Type | Description |
|---|---|---|
type | 'text' | Discriminator |
content | string | Text content |
2.3.2 Include Parts
Include parts reference other prompts:
| Property | Type | Description |
|---|---|---|
type | 'include' | Discriminator |
prompt | string | Name of prompt to include |
2.4 Include Resolution
When a prompt includes another prompt:
- Implementations MUST recursively resolve all includes
- Implementations MUST detect and reject circular includes
- The included prompt’s content is inserted at the include location
- Only the
promptfield is included (not tools, model, etc.)
3. Tool Configuration
3.1 Simple Tool References
Tools can be referenced by name:
tools: ['search_docs', 'create_ticket', 'send_email']
3.2 Tool Configuration with Environment Values
Tools can be configured with thread variable values using env. This allows prompts to provide default values for tools that need runtime configuration:
tools: [
'search_docs', // Simple reference
{
name: 'file_search', // Tool with env configuration
env: {
VECTOR_STORE_ID: 'vs_abc123',
},
},
]
| Property | Type | Description |
|---|---|---|
name | string | Name of the tool |
env | Record<string, string> | Environment variable values for this tool |
options | Record<string, unknown> | Static tool options |
Prompt-level env values serve as defaults. They can be overridden by higher-precedence sources. See the Tools specification for variable declaration details.
3.3 Sub-Prompt Tool Configuration
When a prompt is used as a tool by another prompt, the caller can configure how results are returned. These options only apply to sub-prompts, not to regular function tools.
Since sub-prompts return their results as tool call responses, all output must be serialized into a single text string. The configuration options control what gets included in that string.
tools: [
'search_docs', // Simple reference (function tool)
{
name: 'summarize_document', // Sub-prompt with configuration
includeTextResponse: true,
includeToolCalls: false,
includeErrors: true,
initUserMessageProperty: 'document',
},
{
name: 'analyze_image', // Sub-prompt with attachment configuration
initUserMessageProperty: 'question',
initAttachmentsProperty: 'image_path',
},
{
name: 'support_handoff', // Agent (ai_human) with initial message
initUserMessageProperty: 'customer_query',
},
]
| Property | Type | Default | Description |
|---|---|---|---|
name | string | Required | Name of the sub-prompt or agent to call |
includeTextResponse | boolean | true | Include the sub-prompt’s text response in the result string |
includeToolCalls | boolean | true | Serialize tool calls made by the sub-prompt (and their results) into the result string |
includeErrors | boolean | true | Serialize any errors from the sub-prompt into the result string |
initUserMessageProperty | string | - | Use this argument property as the initial user message when invoking the sub-prompt or agent |
initAttachmentsProperty | string | - | Use this argument property (file path or array of paths) as attachments in the initial user message |
The initUserMessageProperty is useful when the sub-prompt expects conversational input. For example, if initUserMessageProperty: 'query' is set and the caller passes { query: 'What is X?' }, the sub-prompt receives “What is X?” as its initial user message.
The initAttachmentsProperty allows passing file attachments (images, documents) to the sub-prompt. The property value should be a file path string or an array of paths. For example, if initAttachmentsProperty: 'image' is set and the caller passes { image: '/attachments/photo.jpg' }, the sub-prompt receives the image as an attachment.
💡 Tip: Combine
initUserMessagePropertywithincludeChat: falseon the sub-prompt. The sub-prompt will only receive its own system prompt and the initial user message—allowing it to operate on a smaller, focused context with reduced token usage.
4. Tool Choice Strategy
4.1 Strategy Values
The toolChoice property controls how the LLM calls tools:
| Value | Behavior |
|---|---|
'auto' | Model decides when to call tools (default) |
'none' | Disable tool calling entirely |
'required' | Force the model to call at least one tool |
4.2 Tool Choice Behavior
When toolChoice is 'required':
- The LLM MUST include at least one tool call in its response
- Implementations SHOULD retry if the LLM fails to call a tool
When toolChoice is 'none':
- Tool definitions are not sent to the LLM
- The
toolsarray is ignored for that request
5. Input Validation
5.1 Required Schema
The requiredSchema property defines inputs when the prompt is called as a tool:
requiredSchema: z.object({
query: z.string().describe('Search query'),
limit: z.number().optional().default(10).describe('Max results'),
})
5.2 Schema Usage
When a required schema is provided:
- Implementations MUST validate inputs against the schema
- Implementations MUST generate JSON Schema for LLM tool definitions
- Field descriptions from
.describe()SHOULD be included
User inputs MUST be validated before inclusion in prompts.
💡 Tip: TypeScript implementations can use the
PromptInput<T>helper type to extract the inferred input type from a prompt’s schema:type SearchInput = PromptInput<typeof searchPrompt>.
6. Reasoning Configuration
6.1 Reasoning Properties
For models with extended thinking capabilities:
| Property | Type | Description |
|---|---|---|
effort | 'low' | 'medium' | 'high' | Reasoning effort level |
maxTokens | number | Max tokens for reasoning |
exclude | boolean | Exclude reasoning from response |
include | boolean | Include reasoning in history |
6.2 Effort Levels
| Level | Behavior |
|---|---|
'low' | Minimal reasoning, faster responses |
'medium' | Balanced reasoning and speed |
'high' | Maximum reasoning, slower but thorough |
6.3 Reasoning Visibility
- When
excludeistrue, reasoning is used internally but not returned - When
includeistrue, reasoning is preserved in message history - These can be combined for different use cases
7. Image Context Management
The recentImageThreshold property controls how images are handled in conversation context:
- Images in the most recent N messages are kept as full image content
- Older images are replaced with text descriptions
- Helps manage context window usage in long conversations
8. Hook Scoping
The hooks property declares which hooks run when this prompt is active. Hook IDs reference hooks defined in agents/hooks/ using defineHook().
definePrompt({
name: 'customer_support',
// ...
hooks: ['limit_to_20_messages', 'log_tool_calls', 'redact_credit_cards'],
});
Behavior:
- When
hooksis specified, only those hooks run for this prompt - When
hooksis omitted, the runtime falls back to agent-level hooks - Hook IDs reference the
idproperty fromdefineHook({ hook, id, execute }) - See the Hooks specification for hook definition details
This allows different prompts within the same agent to use different hooks. For example, a classifier prompt might skip message filtering hooks while a support prompt includes them.
9. Validation
9.1 Required Field Validation
Implementations MUST validate that:
nameis a non-empty stringtoolDescriptionis a non-empty stringmodelreferences a defined modelpromptis either a string or valid structured array
9.2 Optional Field Validation
Implementations MUST validate that:
toolChoiceis one of:'auto','none','required'reasoning.effortis one of:'low','medium','high'recentImageThresholdis a positive integer
10. TypeScript Reference
/**
* Text part of a structured prompt.
*/
interface PromptTextPart {
type: 'text';
content: string;
}
/**
* Include part referencing another prompt.
*/
interface PromptIncludePart {
type: 'include';
prompt: string;
}
/**
* Union of prompt part types.
*/
type PromptPart = PromptTextPart | PromptIncludePart;
/**
* Structured prompt array.
*/
type StructuredPrompt = PromptPart[];
/**
* Prompt content (string or structured).
*/
type PromptContent = string | StructuredPrompt;
/**
* Configuration for tools with env values.
*/
interface ToolConfig<T extends string = string> {
name: T;
env?: Record<string, string>;
options?: Record<string, unknown>;
}
/**
* Configuration for sub-prompts or agents used as tools.
* These options control how results are returned and how initial messages are constructed.
*/
interface SubpromptConfig<T extends string = string> {
name: T;
includeTextResponse?: boolean;
includeToolCalls?: boolean;
includeErrors?: boolean;
initUserMessageProperty?: string;
initAttachmentsProperty?: string;
}
/**
* Configuration for invoking a dual_ai agent as a subagent tool.
*/
interface SubagentToolConfig<T extends string = string> {
name: T;
blocking?: boolean;
initUserMessageProperty?: string;
initAttachmentsProperty?: string;
initAgentNameProperty?: string;
immediate?: boolean;
optional?: string;
resumable?: false | {
receives_messages: 'side_a' | 'side_b';
maxInstances?: number;
};
}
/**
* Reasoning configuration.
*/
interface ReasoningConfig {
effort?: 'low' | 'medium' | 'high';
maxTokens?: number;
exclude?: boolean;
include?: boolean;
}
/**
* Prompt definition configuration.
*/
interface PromptDefinition<
N extends string = string,
S extends ToolArgs = ToolArgs,
> {
name: N;
toolDescription: string;
prompt: PromptContent;
model: string;
includeChat?: boolean;
includePastTools?: boolean;
parallelToolCalls?: boolean;
toolChoice?: 'auto' | 'none' | 'required';
requiredSchema?: S;
tools?: (string | ToolConfig | SubpromptConfig | SubagentToolConfig)[];
variables?: Array<{
name: string;
type: 'text' | 'secret';
required: boolean;
description: string;
}>;
env?: Record<string, string>;
reasoning?: ReasoningConfig;
recentImageThreshold?: number;
hooks?: string[];
}
/**
* Helper type for input inference.
*/
type PromptInput<T extends PromptDefinition> =
T['requiredSchema'] extends ToolArgs
? z.infer<T['requiredSchema']>
: never;
/**
* Define a prompt configuration.
*/
function definePrompt<N extends string, S extends ToolArgs = never>(
options: PromptDefinition<N, S>
): PromptDefinition<N, S>;
11. Examples
11.1 Basic Prompt
import { definePrompt } from '@standardagents/spec';
export default definePrompt({
name: 'assistant',
toolDescription: 'General purpose assistant',
model: 'conversational',
prompt: 'You are a helpful assistant. Be concise and accurate.',
});
11.2 Prompt with Tools
import { definePrompt } from '@standardagents/spec';
import { z } from 'zod';
export default definePrompt({
name: 'customer_support',
toolDescription: 'Handle customer support inquiries',
model: 'conversational',
prompt: `You are a customer support agent.
Always be polite and try to resolve issues quickly.
If you cannot help, offer to escalate.`,
tools: ['search_knowledge_base', 'create_ticket'],
includeChat: true,
requiredSchema: z.object({
query: z.string().describe('The customer inquiry'),
}),
});
11.3 Structured Prompt with Includes
import { definePrompt } from '@standardagents/spec';
export default definePrompt({
name: 'sales_agent',
toolDescription: 'Handle sales inquiries',
model: 'conversational',
prompt: [
{ type: 'text', content: 'You are a sales representative.\n\n' },
{ type: 'include', prompt: 'company_info' },
{ type: 'include', prompt: 'product_catalog' },
{ type: 'text', content: '\n\nBe helpful and persuasive.' },
],
tools: ['get_pricing', 'schedule_demo'],
});
11.4 Prompt with Reasoning
import { definePrompt } from '@standardagents/spec';
export default definePrompt({
name: 'code_reviewer',
toolDescription: 'Review code for issues and improvements',
model: 'heavy',
prompt: 'You are an expert code reviewer. Analyze code thoroughly.',
reasoning: {
effort: 'high',
maxTokens: 4096,
exclude: false,
},
});
11.5 Prompt with Hooks
import { definePrompt } from '@standardagents/spec';
export default definePrompt({
name: 'customer_support',
toolDescription: 'Handle customer support inquiries',
model: 'conversational',
prompt: 'You are a customer support agent. Be helpful and concise.',
tools: ['search_knowledge_base', 'create_ticket'],
includeChat: true,
hooks: ['limit_to_20_messages', 'log_tool_calls', 'redact_credit_cards'],
});