@standardagents/agentbuilder-template 0.0.1-dev.fffff

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1733 @@
1
+ // src/docs/root.ts
2
+ var ROOT_CLAUDE_MD = `# Standard Agents
3
+
4
+ This project uses Standard Agents - a framework for building AI agents on Cloudflare Workers.
5
+
6
+ ## Architecture Overview
7
+
8
+ Standard Agents uses a **composition model** where four core components work together:
9
+
10
+ \`\`\`
11
+ Model \u2192 Prompt \u2192 Agent \u2192 Thread
12
+ \u2502 \u2502 \u2502 \u2502
13
+ \u2502 \u2502 \u2502 \u2514\u2500 Conversation instance (Durable Object)
14
+ \u2502 \u2502 \u2514\u2500 Orchestrates conversation flow
15
+ \u2502 \u2514\u2500 System instructions + tools
16
+ \u2514\u2500 LLM provider configuration
17
+ \`\`\`
18
+
19
+ **Models** define which LLM to use (provider, model ID, pricing, fallbacks).
20
+ **Prompts** define what the LLM should do (system instructions, available tools).
21
+ **Agents** orchestrate conversations (which prompt, stop conditions, turn limits).
22
+ **Threads** are individual conversation instances with persistent storage.
23
+
24
+ ## How Components Compose
25
+
26
+ ### Basic Flow
27
+ 1. User creates a thread with an agent
28
+ 2. Agent uses its configured prompt
29
+ 3. Prompt specifies the model and tools
30
+ 4. LLM responds, potentially calling tools
31
+ 5. Tools execute and return results
32
+ 6. Loop continues until stop condition
33
+
34
+ ### Sub-Prompts (Prompts as Tools)
35
+ Prompts can call other prompts as tools. This enables:
36
+ - **Specialized reasoning**: A main prompt delegates to expert sub-prompts
37
+ - **Structured outputs**: Sub-prompt validates and formats data
38
+ - **Context isolation**: Sub-prompt gets fresh context without full history
39
+
40
+ \`\`\`typescript
41
+ // Main prompt can call 'data_extractor' as a tool
42
+ definePrompt({
43
+ name: 'main_assistant',
44
+ tools: ['data_extractor'], // Another prompt exposed as tool
45
+ // ...
46
+ });
47
+ \`\`\`
48
+
49
+ ### Agent Handoffs (Agents as Tools)
50
+ Agents can delegate to other agents entirely:
51
+ - **Specialization**: Route to domain-specific agents
52
+ - **Escalation**: Hand off to more capable agents
53
+ - **Workflows**: Chain agents for multi-step processes
54
+
55
+ \`\`\`typescript
56
+ defineAgent({
57
+ name: 'triage_agent',
58
+ exposeAsTool: true,
59
+ toolDescription: 'Hand off to triage for initial assessment',
60
+ // ...
61
+ });
62
+ \`\`\`
63
+
64
+ ## File Structure
65
+
66
+ \`\`\`
67
+ agents/
68
+ \u251C\u2500\u2500 CLAUDE.md # This file
69
+ \u251C\u2500\u2500 Thread.ts # Durable Object for conversation threads
70
+ \u251C\u2500\u2500 AgentBuilder.ts # Durable Object for metadata
71
+ \u251C\u2500\u2500 agents/ # Agent definitions (defineAgent)
72
+ \u2502 \u2514\u2500\u2500 CLAUDE.md
73
+ \u251C\u2500\u2500 prompts/ # Prompt definitions (definePrompt)
74
+ \u2502 \u2514\u2500\u2500 CLAUDE.md
75
+ \u251C\u2500\u2500 models/ # Model configurations (defineModel)
76
+ \u2502 \u2514\u2500\u2500 CLAUDE.md
77
+ \u251C\u2500\u2500 tools/ # Custom tools (defineTool)
78
+ \u2502 \u2514\u2500\u2500 CLAUDE.md
79
+ \u251C\u2500\u2500 hooks/ # Lifecycle hooks (defineHook)
80
+ \u2502 \u2514\u2500\u2500 CLAUDE.md
81
+ \u2514\u2500\u2500 api/ # Thread API endpoints (defineThreadEndpoint)
82
+ \u2514\u2500\u2500 CLAUDE.md
83
+ \`\`\`
84
+
85
+ Files are **auto-discovered** at runtime. No manual registration needed.
86
+
87
+ ## ThreadState
88
+
89
+ \`ThreadState\` is the state object available in tools and hooks:
90
+
91
+ \`\`\`typescript
92
+ interface ThreadState {
93
+ // Identity (readonly)
94
+ threadId: string; // Thread identifier
95
+ agentId: string; // Agent identifier
96
+ userId: string | null; // User identifier (if set)
97
+ createdAt: number; // Creation timestamp
98
+ children: SubagentRegistryEntry[]; // Resumable child registry
99
+ terminated: number | null; // Soft-termination timestamp
100
+
101
+ // Methods
102
+ getMessages(options?): Promise<MessagesResult>; // Get conversation history
103
+ injectMessage(input): Promise<Message>; // Add message to thread
104
+ queueMessage(input): Promise<void>; // Queue message for next step
105
+ loadModel(name): Promise<ModelConfig>; // Load model definition
106
+ loadPrompt(name): Promise<PromptConfig>; // Load prompt definition
107
+ loadAgent(name): Promise<AgentConfig>; // Load agent definition
108
+ env(propertyName): Promise<string>; // Resolve env value for this thread
109
+ setEnv(propertyName, value): Promise<void>; // Set thread env + propagate to active descendants
110
+ getValue<T = unknown>(key: string): Promise<T | null>; // Read durable per-thread JSON value
111
+ setValue(key: string, value: unknown): Promise<void>; // Write durable value; null/undefined deletes
112
+ notifyParent(content): Promise<void>; // Explicitly queue a silent message to the parent
113
+ setStatus(status): Promise<void>; // Update this child in the parent registry
114
+ getChildThread(referenceId): Promise<ThreadState | null>; // Resolve child thread
115
+ getParentThread(): Promise<ThreadState | null>; // Resolve parent thread
116
+ terminate(): Promise<void>; // Soft-terminate thread
117
+ runCode(source, options?): CodeExecution; // Run JS/TS in a fresh Dynamic Worker sandbox
118
+ }
119
+ \`\`\`
120
+
121
+ \`runCode\` has no implicit access to thread state, filesystem, network, timers, or host globals. Bridge only the exact capabilities needed through \`imports\` or \`globals\`; use \`modules\` for local relative ES modules; use \`execute\` to select the export and args to run. \`modules\` keys are graph-root relative paths; entry-source imports resolve from \`filename\` when supplied, including \`../\` parent paths that stay inside the supplied graph. TypeScript input is accepted by default and erased before evaluation. In thread endpoints, \`runCode\` is forwarded into the thread Durable Object; pass plain transferable options there and keep function-backed bridges in tools or in-thread execution contexts.
122
+
123
+ ## Subagents
124
+
125
+ \`dual_ai\` agents can be used as subagents from prompt tool configs:
126
+
127
+ - Each subagent runs in its own thread (\`DurableThread\`)
128
+ - Parent/child linkage is tracked in thread metadata
129
+ - Resumable children are visible in \`state.children\`
130
+ - Parent threads create/message resumable children via built-ins (\`subagent_create\`, \`subagent_message\`)
131
+ - Child completion results are queued back to the parent when \`parentCommunication\` is \`implicit\`
132
+ - Explicit relationships can stay idle until code calls \`state.notifyParent()\` or \`state.setStatus()\`
133
+
134
+ Access in tools:
135
+ \`\`\`typescript
136
+ export default defineTool('...', schema, async (state, args) => {
137
+ const threadId = state.threadId;
138
+ const { messages } = await state.getMessages();
139
+ const count = (await state.getValue<number>('invocation_count')) ?? 0;
140
+ await state.setValue('invocation_count', count + 1);
141
+ // ...
142
+ });
143
+ \`\`\`
144
+
145
+ Access in hooks:
146
+ \`\`\`typescript
147
+ export default defineHook({
148
+ hook: 'before_create_message',
149
+ id: 'my_hook',
150
+ execute: async (state, message) => {
151
+ console.log(\`Thread: \${state.threadId}, Agent: \${state.agentId}\`);
152
+ return message;
153
+ }
154
+ });
155
+ \`\`\`
156
+
157
+ ## Quick Reference
158
+
159
+ | Function | Purpose | Directory |
160
+ |----------|---------|-----------|
161
+ | \`defineModel()\` | Configure LLM provider | \`agents/models/\` |
162
+ | \`definePrompt()\` | System instructions + tools | \`agents/prompts/\` |
163
+ | \`defineAgent()\` | Conversation orchestration | \`agents/agents/\` |
164
+ | \`defineTool()\` | Custom tool functions | \`agents/tools/\` |
165
+ | \`defineHook()\` | Lifecycle interception | \`agents/hooks/\` |
166
+ | \`defineThreadEndpoint()\` | Custom API routes | \`agents/api/\` |
167
+
168
+ ## Runtime Utilities
169
+
170
+ Import from \`@standardagents/builder\`:
171
+
172
+ \`\`\`typescript
173
+ import {
174
+ queueTool, // Queue another tool for execution
175
+ injectMessage, // Add message without triggering execution
176
+ getMessages, // Retrieve message history
177
+ emitThreadEvent, // Send custom WebSocket events
178
+ } from '@standardagents/builder';
179
+ \`\`\`
180
+
181
+ ## Documentation
182
+
183
+ Full documentation: https://docs.standardagentbuilder.com
184
+
185
+ - [Architecture Overview](https://docs.standardagentbuilder.com/introduction/architecture)
186
+ - [Models](https://docs.standardagentbuilder.com/core-concepts/models)
187
+ - [Prompts](https://docs.standardagentbuilder.com/core-concepts/prompts)
188
+ - [Agents](https://docs.standardagentbuilder.com/core-concepts/agents)
189
+ - [Tools](https://docs.standardagentbuilder.com/core-concepts/tools)
190
+ - [Hooks](https://docs.standardagentbuilder.com/core-concepts/hooks)
191
+ - [ThreadState](https://docs.standardagentbuilder.com/core-concepts/threadstate)
192
+ - [Thread API](https://docs.standardagentbuilder.com/core-concepts/api)
193
+ `;
194
+
195
+ // src/docs/models.ts
196
+ var MODELS_CLAUDE_MD = `# Model Definitions
197
+
198
+ Models define which LLM provider and model to use for prompts.
199
+
200
+ ## Properties
201
+
202
+ | Property | Type | Required | Description |
203
+ |----------|------|----------|-------------|
204
+ | \`name\` | \`string\` | Yes | Unique identifier for this model configuration |
205
+ | \`provider\` | \`'openai' \\| 'anthropic' \\| 'openrouter' \\| 'google' \\| 'cerebras' \\| 'groq' \\| 'xai'\` | Yes | LLM provider |
206
+ | \`model\` | \`string\` | Yes | Model ID sent to provider API |
207
+ | \`fallbacks\` | \`string[]\` | No | Fallback model names to try if primary fails |
208
+ | \`inputPrice\` | \`number\` | No | Cost per 1M input tokens (USD) |
209
+ | \`outputPrice\` | \`number\` | No | Cost per 1M output tokens (USD) |
210
+ | \`cachedPrice\` | \`number\` | No | Cost per 1M cached input tokens |
211
+ | \`includedProviders\` | \`string[]\` | No | Provider prefixes for OpenRouter routing |
212
+ | \`providerTools\` | \`string[]\` | No | Provider-built-in tool names to make available for prompts using this model |
213
+
214
+ ## Example
215
+
216
+ \`\`\`typescript
217
+ import { defineModel } from '@standardagents/builder';
218
+
219
+ export default defineModel({
220
+ name: 'default',
221
+ provider: 'openrouter',
222
+ model: 'google/gemini-3-flash-preview',
223
+ fallbacks: ['fast', 'cheap-heavy'],
224
+ });
225
+ \`\`\`
226
+
227
+ ## Provider Tools
228
+
229
+ Providers can expose built-in tools such as search, file search, code execution,
230
+ or provider-specific tools through their \`getTools()\` implementation. Enable the
231
+ provider tool names on the model with \`providerTools\`; prompts can then include
232
+ those tools like normal tool names. Provider tools execute on the upstream
233
+ provider, not in AgentBuilder, and successful calls are logged as provider tool
234
+ entries.
235
+
236
+ OpenRouter exposes \`web_search\`, \`web_fetch\`, \`datetime\`, and \`image_generation\`
237
+ as provider-executed server tools. Configure optional OpenRouter parameters with
238
+ \`providerOptions.serverTools\` on the model.
239
+
240
+ ## Recommended Models (OpenRouter)
241
+
242
+ | Use Case | Model ID | Description |
243
+ |----------|----------|-------------|
244
+ | Fast/Cheap | \`z-ai/glm-4.5-air\` | Quick responses, low cost |
245
+ | Mid-tier | \`google/gemini-3-flash-preview\` | Good balance of speed and quality |
246
+ | Cheap Heavy | \`z-ai/glm-4.7\` | More capable, still affordable |
247
+ | Heavy | \`google/gemini-3-pro-preview\` | Most capable, for complex tasks |
248
+
249
+ **\u26A0\uFE0F Google Models**: When using Google models (\`google/gemini-*\`), you must enable \`reasoning\` in your prompt configuration or tool calls will fail. See the prompts CLAUDE.md for details.
250
+
251
+ ## Provider API Keys
252
+
253
+ Set these environment variables in \`.dev.vars\` (local) or Cloudflare secrets (production):
254
+
255
+ | Provider | Environment Variable |
256
+ |----------|---------------------|
257
+ | Cerebras | \`CEREBRAS_API_KEY\` |
258
+ | Groq | \`GROQ_API_KEY\` |
259
+ | OpenAI | \`OPENAI_API_KEY\` |
260
+ | Anthropic | \`ANTHROPIC_API_KEY\` |
261
+ | OpenRouter | \`OPENROUTER_API_KEY\` |
262
+ | Google | \`GOOGLE_API_KEY\` |
263
+ | xAI | \`XAI_API_KEY\` |
264
+
265
+ If \`STANDARD_AGENTS_API_KEY\` is present and a provider-specific key is not set,
266
+ first-party Standard Agents providers route through the hosted Standard Agents
267
+ router. Setting a provider-specific key always uses that provider directly.
268
+
269
+ ## Fallback Strategy
270
+
271
+ When a model fails, fallbacks are tried in order:
272
+ 1. Primary model (2 attempts)
273
+ 2. First fallback (2 attempts)
274
+ 3. Second fallback (2 attempts)
275
+ 4. ...and so on
276
+
277
+ Retries occur on: network errors, rate limits (429), server errors (5xx), auth errors (401).
278
+
279
+ ## OpenRouter Configuration
280
+
281
+ For OpenRouter, use the full model path:
282
+
283
+ \`\`\`typescript
284
+ export default defineModel({
285
+ name: 'heavy',
286
+ provider: 'openrouter',
287
+ model: 'google/gemini-3-pro-preview',
288
+ includedProviders: ['google'], // Prefer Google's servers
289
+ });
290
+ \`\`\`
291
+
292
+ ## Best Practices
293
+
294
+ - **Name by use case**, not model ID (e.g., \`fast\`, \`default\`, \`heavy\`)
295
+ - **Configure fallbacks** for production reliability
296
+ - **Set pricing** for cost tracking in logs when your provider or runtime does not supply it automatically
297
+ - **Cerebras note:** documented Cerebras models have built-in fallback pricing for request logs, but custom/private Cerebras models should still set \`inputPrice\` and \`outputPrice\`
298
+ - **Use environment variables** for API keys, never hardcode
299
+
300
+ ## Documentation
301
+
302
+ Full reference: https://docs.standardagentbuilder.com/api-reference/define/model
303
+ `;
304
+
305
+ // src/docs/prompts.ts
306
+ var PROMPTS_CLAUDE_MD = `# Prompt Definitions
307
+
308
+ Prompts define system instructions, model selection, and available tools for LLM interactions.
309
+
310
+ ## Properties
311
+
312
+ | Property | Type | Required | Description |
313
+ |----------|------|----------|-------------|
314
+ | \`name\` | \`string\` | Yes | Unique identifier for this prompt |
315
+ | \`toolDescription\` | \`string\` | Yes | Description shown when used as a tool |
316
+ | \`prompt\` | \`string \\| StructuredPrompt\` | Yes | System instructions |
317
+ | \`model\` | \`string\` | Yes | Model name to use (references \`agents/models/\`) |
318
+ | \`tools\` | \`(string \\| ToolConfig \\| SubagentToolConfig)[]\` | No | Available tools (include ai_human agent names for handoffs and dual_ai subagent configs) |
319
+ | \`includeChat\` | \`boolean\` | No | Include full conversation history |
320
+ | \`includePastTools\` | \`boolean\` | No | Include previous tool results |
321
+ | \`parallelToolCalls\` | \`boolean\` | No | Allow multiple concurrent tool calls |
322
+ | \`toolChoice\` | \`'auto' \\| 'none' \\| 'required'\` | No | Tool calling strategy |
323
+ | \`requiredSchema\` | \`z.ZodObject\` | No | Input validation when called as tool |
324
+ | \`variables\` | \`VariableDefinition[]\` | No | Variable declarations (\`name\`, \`type\`, \`required\`, \`scoped\`, \`description\`) |
325
+ | \`env\` | \`Record<string, string>\` | No | Prompt-level default values for variables |
326
+ | \`hooks\` | \`string[]\` | No | Hook IDs to run for this prompt (overrides agent hooks) |
327
+ | \`reasoning\` | \`ReasoningConfig\` | No | Extended thinking configuration |
328
+
329
+ ## Basic Example
330
+
331
+ \`\`\`typescript
332
+ import { definePrompt } from '@standardagents/builder';
333
+
334
+ export default definePrompt({
335
+ name: 'customer_support',
336
+ toolDescription: 'Handle customer support inquiries',
337
+ model: 'default',
338
+ prompt: \`You are a helpful customer support agent.
339
+ Always be polite and professional.
340
+ If you cannot help, escalate to a human.\`,
341
+ tools: ['search_knowledge_base', 'create_ticket'],
342
+ includeChat: true,
343
+ });
344
+ \`\`\`
345
+
346
+ ## Structured Prompts
347
+
348
+ Include other prompts for reusable instruction blocks:
349
+
350
+ \`\`\`typescript
351
+ export default definePrompt({
352
+ name: 'main_assistant',
353
+ toolDescription: 'Primary assistant',
354
+ model: 'default',
355
+ prompt: [
356
+ { type: 'text', content: 'You are a helpful assistant.\\n\\n' },
357
+ { type: 'include', prompt: 'common_rules' }, // Includes another prompt
358
+ { type: 'env', property: 'ASSISTANT_TONE' }, // Inject variable value
359
+ { type: 'text', content: '\\n\\nBe concise.' },
360
+ ],
361
+ });
362
+ \`\`\`
363
+
364
+ \`type: 'env'\` inserts a resolved thread variable value. Use this only for non-secret values that are safe to expose to the LLM.
365
+
366
+ The sandboxed coding prompt declares \`HTTP_HOST\` as a text variable. Its URL helper uses that value as the origin for files exposed from the thread \`public/\` directory and endpoints exposed from the thread \`api/\` directory. Public URLs should usually omit extensions; extensionless public paths resolve \`.html\`, then \`.js\`, then \`.ts\`, then matching \`index\` files in the same order. Browser pages should reference only public files, \`api/\` endpoints, or absolute external URLs, using relative asset URLs like \`./app\` and \`./api/todos\`; private \`src/\` files are not served directly. Public \`.ts\` files are transformed to browser JavaScript and are not server endpoints. Server-side endpoints live under the thread filesystem \`api/\` directory, and the \`api/\` directory name stays in the public URL: \`api/todo.ts\` is \`/api/threads/{threadId}/api/todo\`, while \`api/todo.ts\` is not \`/api/threads/{threadId}/todo\` or \`/api/threads/{threadId}/todos\`. Endpoint files default-export a function that accepts \`Request\` and returns \`Response\` or \`Promise<Response>\`. Endpoint code can import \`fetch\`, \`fs\`, and \`storage\`, and can import private helpers with relative paths such as \`../src/todo.ts\`. When the coding agent creates a site, page, or endpoint, it should call \`get_public_url\` with the created file path and use the returned URL.
367
+
368
+ Sandboxed code and \`api/\` endpoints can persist small JSON-serializable runtime data through \`import { storage } from "storage"\`. Use \`storage.get\`, \`storage.set\`, \`storage.delete\`, and \`storage.has\` with stable logical keys. Do not expose, mention, or depend on internal storage key prefixes.
369
+
370
+ The sandboxed coding prompt includes \`delete_file\` for removing files or empty directories from the thread filesystem. Use it to clean up obsolete implementation files, stale public assets, and abandoned endpoint routes after the replacement is working.
371
+
372
+ ## Tool Configuration
373
+
374
+ Tools can be simple names or detailed configs:
375
+
376
+ \`\`\`typescript
377
+ tools: [
378
+ 'simple_tool', // Just the tool name
379
+ {
380
+ name: 'complex_tool',
381
+ includeTextResponse: true, // Include sub-prompt text in result
382
+ includeToolCalls: false, // Exclude sub-prompt tool calls
383
+ includeErrors: true, // Include error details
384
+ initUserMessageProperty: 'query', // Use this arg as initial message
385
+ },
386
+ ],
387
+ \`\`\`
388
+
389
+ Provider-built-in tools use the same \`tools\` list once the selected model enables
390
+ them with \`providerTools\`. AgentBuilder passes them to the provider and records
391
+ provider-reported calls in request logs; it does not execute those tools locally.
392
+ Generated prompt files may store these selections as \`provider:<toolName>\` to
393
+ distinguish provider tools from local tools with the same name.
394
+
395
+ ### Subagent Tool Configuration
396
+
397
+ Use \`SubagentToolConfig\` when the tool is a \`dual_ai\` agent:
398
+
399
+ \`\`\`typescript
400
+ tools: [
401
+ // Blocking, non-resumable (default)
402
+ { name: 'data_processor_agent' },
403
+
404
+ // Non-blocking, resumable with a single instance
405
+ {
406
+ name: 'browser_agent',
407
+ blocking: false,
408
+ immediate: {
409
+ nameEnv: 'BROWSER_AGENT_NAME',
410
+ descriptionEnv: 'BROWSER_AGENT_DESCRIPTION',
411
+ scopedEnv: ['BROWSER_AGENT_API_KEY'],
412
+ },
413
+ optional: 'ENABLE_BROWSER_AGENT',
414
+ initAgentNameProperty: 'name',
415
+ resumable: {
416
+ receives_messages: 'side_a',
417
+ maxInstances: 1,
418
+ parentCommunication: 'explicit',
419
+ },
420
+ },
421
+ ]
422
+ \`\`\`
423
+
424
+ When prompt-configured resumable dual_ai subagents exist, the runtime auto-injects:
425
+ - \`subagent_create\` for spawning new child instances
426
+ - \`subagent_message\` for messaging active resumable instances
427
+
428
+ \`subagent_create\` requires a non-empty \`name\` for human-friendly child thread labels.
429
+ AgentBuilder stores that argument as a \`name:<value>\` thread tag.
430
+
431
+ Set \`immediate: true\` to run a tool automatically when the prompt activates.
432
+ Use \`immediate: { nameEnv, descriptionEnv, scopedEnv }\` when you want safe per-instance bootstrap hints while keeping copied scoped env runtime-only.
433
+ Set \`optional: 'ENV_NAME'\` to enable a subagent branch only when env resolves to \`true\`, \`1\`, or \`yes\`.
434
+ Set \`resumable.parentCommunication: 'explicit'\` when the child should stay quiet until its own tools or hooks call \`state.notifyParent()\` or \`state.setStatus()\`.
435
+ If required scoped vars are missing, the runtime returns \`error_code: "subagent_env_required"\` with a temporary \`GET/POST /api/threads/:threadId/variables/:requestId\` endpoint in \`error_data.endpoint\`.
436
+
437
+ ## Input Validation
438
+
439
+ Validate inputs when prompt is called as a tool:
440
+
441
+ \`\`\`typescript
442
+ import { z } from 'zod';
443
+
444
+ export default definePrompt({
445
+ name: 'data_extractor',
446
+ toolDescription: 'Extract structured data from text',
447
+ model: 'default',
448
+ prompt: 'Extract the requested data from the input.',
449
+ requiredSchema: z.object({
450
+ text: z.string().describe('Text to extract from'),
451
+ fields: z.array(z.string()).describe('Fields to extract'),
452
+ }),
453
+ });
454
+ \`\`\`
455
+
456
+ ## Extended Thinking (Reasoning)
457
+
458
+ Enable for complex reasoning tasks:
459
+
460
+ \`\`\`typescript
461
+ export default definePrompt({
462
+ name: 'code_reviewer',
463
+ toolDescription: 'Review code for issues',
464
+ model: 'heavy',
465
+ prompt: 'Review the code thoroughly...',
466
+ reasoning: {
467
+ effort: 'high', // 'low' | 'medium' | 'high'
468
+ maxTokens: 16000, // Max thinking tokens
469
+ exclude: true, // Don't include thinking in response
470
+ },
471
+ });
472
+ \`\`\`
473
+
474
+ **\u26A0\uFE0F Google Models Require Reasoning**: When using Google models (\`google/gemini-*\`) via OpenRouter, you **must** include \`reasoning\` configuration or tool calls will fail. At minimum:
475
+
476
+ \`\`\`typescript
477
+ reasoning: {
478
+ effort: 'low', // Can be 'low', 'medium', or 'high'
479
+ },
480
+ \`\`\`
481
+
482
+ ## Hooks
483
+
484
+ Attach lifecycle hooks to a prompt:
485
+
486
+ \`\`\`typescript
487
+ export default definePrompt({
488
+ name: 'customer_support',
489
+ toolDescription: 'Handle customer support',
490
+ model: 'default',
491
+ prompt: 'You are a support agent...',
492
+ hooks: ['limit_to_20', 'redact_pii'], // Hook IDs from agents/hooks/
493
+ });
494
+ \`\`\`
495
+
496
+ Prompt hooks take precedence over agent hooks. See \`agents/hooks/CLAUDE.md\` for details.
497
+
498
+ ## Best Practices
499
+
500
+ - **Write clear instructions** - Structure with headers and bullet points
501
+ - **Describe tools thoroughly** - LLMs decide based on descriptions
502
+ - **Validate inputs with Zod** - Catch errors early
503
+ - **Use \`includeChat\`** for conversational context
504
+ - **Name by purpose**, not model (e.g., \`support_agent\` not \`gpt4_prompt\`)
505
+
506
+ ## Documentation
507
+
508
+ Full reference: https://docs.standardagentbuilder.com/api-reference/define/prompt
509
+ `;
510
+
511
+ // src/docs/agents.ts
512
+ var AGENTS_CLAUDE_MD = `# Agent Definitions
513
+
514
+ Agents orchestrate conversations by defining prompts, stop conditions, and turn limits.
515
+
516
+ ## Agent Properties
517
+
518
+ | Property | Type | Required | Description |
519
+ |----------|------|----------|-------------|
520
+ | \`name\` | \`string\` | Yes | Unique identifier for this agent |
521
+ | \`type\` | \`'ai_human' \\| 'dual_ai'\` | No | Conversation type (default: \`ai_human\`) |
522
+ | \`sideA\` | \`SideConfig\` | Yes | Configuration for side A (AI in ai_human) |
523
+ | \`sideB\` | \`SideConfig\` | No | Configuration for side B (required for dual_ai) |
524
+ | \`maxSessionTurns\` | \`number\` | No | Max total turns across both sides |
525
+ | \`exposeAsTool\` | \`boolean\` | No | Allow other prompts to hand off to this agent |
526
+ | \`toolDescription\` | \`string\` | No | Description when used as tool (required if exposeAsTool) |
527
+ | \`env\` | \`Record<string, string>\` | No | Agent-level default variable values |
528
+ | \`hooks\` | \`string[]\` | No | Hook IDs to run for this agent (fallback if prompt has no hooks) |
529
+ | \`tags\` | \`string[]\` | No | Tags for categorization and filtering |
530
+
531
+ ## Side Configuration
532
+
533
+ | Property | Type | Required | Description |
534
+ |----------|------|----------|-------------|
535
+ | \`label\` | \`string\` | No | Display name for this side |
536
+ | \`prompt\` | \`string\` | Yes | Prompt name to use (references \`agents/prompts/\`) |
537
+ | \`stopOnResponse\` | \`boolean\` | No | Stop turn when LLM returns text (default: true) |
538
+ | \`stopTool\` | \`string\` | No | Tool that stops this side's turn |
539
+ | \`stopToolResponseProperty\` | \`string\` | No | Property to extract from stop tool result |
540
+ | \`maxSteps\` | \`number\` | No | Maximum step budget for this side |
541
+ | \`sessionStop\` | \`string \\| SessionToolBinding\` | No | Terminal success lifecycle binding |
542
+ | \`sessionFail\` | \`string \\| SessionToolBinding\` | No | Terminal failure lifecycle binding |
543
+ | \`sessionStatus\` | \`string \\| SessionToolBinding\` | No | Non-terminal status lifecycle binding |
544
+ | \`manualStopCondition\` | \`boolean\` | No | Enable custom stop handling via hooks |
545
+
546
+ ## Basic Example (AI-Human)
547
+
548
+ \`\`\`typescript
549
+ import { defineAgent } from '@standardagents/builder';
550
+
551
+ export default defineAgent({
552
+ name: 'support_agent',
553
+ type: 'ai_human',
554
+ sideA: {
555
+ label: 'Support',
556
+ prompt: 'customer_support',
557
+ stopOnResponse: true,
558
+ sessionStop: 'close_ticket',
559
+ maxSteps: 50,
560
+ },
561
+ tags: ['support', 'tier-1'],
562
+ });
563
+ \`\`\`
564
+
565
+ ## Dual-AI Example
566
+
567
+ Two AI agents conversing (e.g., debate, iterative refinement):
568
+
569
+ \`\`\`typescript
570
+ export default defineAgent({
571
+ name: 'code_review_debate',
572
+ type: 'dual_ai',
573
+ maxSessionTurns: 20,
574
+ sideA: {
575
+ label: 'Reviewer',
576
+ prompt: 'code_reviewer',
577
+ stopOnResponse: true,
578
+ },
579
+ sideB: {
580
+ label: 'Developer',
581
+ prompt: 'code_defender',
582
+ stopOnResponse: true,
583
+ },
584
+ });
585
+ \`\`\`
586
+
587
+ ## Dual-AI Subagent Pattern
588
+
589
+ When a \`dual_ai\` agent is used as a subagent tool, a common split is:
590
+ - **sideA**: performs work (tools, data gathering, execution)
591
+ - **sideB**: reflection, verification, and quality checks
592
+
593
+ \`\`\`typescript
594
+ export default defineAgent({
595
+ name: 'research_subagent',
596
+ type: 'dual_ai',
597
+ exposeAsTool: true,
598
+ toolDescription: 'Researches and validates findings autonomously',
599
+ maxSessionTurns: 16,
600
+ sideA: {
601
+ label: 'Worker',
602
+ prompt: 'research_worker',
603
+ sessionStatus: 'set_subagent_status',
604
+ sessionFail: 'fail_research_subagent',
605
+ sessionStop: 'finish_subagent',
606
+ },
607
+ sideB: {
608
+ label: 'Reviewer',
609
+ prompt: 'research_reviewer',
610
+ stopOnResponse: true,
611
+ },
612
+ });
613
+ \`\`\`
614
+
615
+ ## Agent Handoffs
616
+
617
+ Expose an agent for handoffs from other prompts:
618
+
619
+ \`\`\`typescript
620
+ export default defineAgent({
621
+ name: 'escalation_agent',
622
+ type: 'ai_human',
623
+ exposeAsTool: true,
624
+ toolDescription: 'Escalate to senior support for complex issues',
625
+ sideA: {
626
+ prompt: 'senior_support',
627
+ },
628
+ });
629
+ \`\`\`
630
+
631
+ Other prompts can then include the agent name in their \`tools\` array to enable handoffs.
632
+
633
+ ## Stop Conditions (Priority Order)
634
+
635
+ 1. **sessionFail** - Ends entire conversation with a terminal failure
636
+ 2. **sessionStop** - Ends entire conversation successfully
637
+ 3. **stopTool** - Ends current side's turn
638
+ 4. **maxSteps** - Ends side execution when the safety budget is reached
639
+ 5. **stopOnResponse** - Ends turn when LLM returns text
640
+ 6. **maxSessionTurns** - Ends conversation (hard limit: 250)
641
+
642
+ ## Hooks
643
+
644
+ Attach lifecycle hooks at the agent level:
645
+
646
+ \`\`\`typescript
647
+ export default defineAgent({
648
+ name: 'support_agent',
649
+ type: 'ai_human',
650
+ hooks: ['log_all_messages', 'sanitize_results'],
651
+ sideA: {
652
+ prompt: 'customer_support',
653
+ },
654
+ });
655
+ \`\`\`
656
+
657
+ Agent hooks run as a fallback when the active prompt has no hooks defined. Prompt hooks always take precedence. See \`agents/hooks/CLAUDE.md\` for details.
658
+
659
+ ## Naming Convention
660
+
661
+ Agent names **must** end with the \`_agent\` suffix (e.g., \`support_agent\`, \`research_agent\`).
662
+ This convention is enforced by the builder UI and makes agents easily identifiable in logs and code.
663
+
664
+ ## Best Practices
665
+
666
+ - **Use descriptive names** (\`customer_support_agent\` not \`agent1\`)
667
+ - **Always use the _agent suffix** - names like \`support_agent\`, \`research_agent\`
668
+ - **Always set maxSteps or maxSessionTurns** as safety limits
669
+ - **Match stop conditions to use case** - chat apps use stopOnResponse, workflows use stopTool
670
+ - **Use labels** for clarity in logs and UI
671
+ - **Organize with tags** for filtering
672
+
673
+ ## Documentation
674
+
675
+ Full reference: https://docs.standardagentbuilder.com/api-reference/define/agent
676
+ `;
677
+
678
+ // src/docs/tools.ts
679
+ var TOOLS_CLAUDE_MD = `# Custom Tools
680
+
681
+ Tools extend agent capabilities beyond text generation. They allow LLMs to fetch data, perform calculations, execute side effects, and chain to other prompts or agents.
682
+
683
+ ## Function Signature
684
+
685
+ \`\`\`typescript
686
+ defineTool({
687
+ description: string, // What the tool does (shown to LLM)
688
+ args?: z.ZodObject, // Input validation schema (optional)
689
+ execute: (state, args) => ToolResult, // Implementation
690
+ variables?: VariableDefinition[], // Declared variables (optional)
691
+ })
692
+ \`\`\`
693
+
694
+ ## Basic Example
695
+
696
+ \`\`\`typescript
697
+ import { defineTool } from '@standardagents/builder';
698
+ import { z } from 'zod';
699
+
700
+ export default defineTool({
701
+ description: 'Search the knowledge base for articles matching a query',
702
+ args: z.object({
703
+ query: z.string().describe('Search query'),
704
+ limit: z.number().optional().default(10).describe('Max results'),
705
+ }),
706
+ execute: async (state, args) => {
707
+ const results = await searchKB(args.query, args.limit);
708
+ return {
709
+ status: 'success',
710
+ result: JSON.stringify(results),
711
+ };
712
+ },
713
+ });
714
+ \`\`\`
715
+
716
+ ## Argument Schemas
717
+
718
+ Tool args must be a top-level \`z.object(...)\`. Prefer explicit, bounded schemas made from strings, numbers, booleans, nulls, literals, enums, arrays, objects, optionals, nullables, and defaults. Avoid provider-visible recursive or open-ended schemas such as \`z.unknown()\`, \`z.any()\`, and \`z.object({}).catchall(...)\`; strict tool providers can reject the generated JSON Schema. If a tool needs arbitrary JSON input, accept it as a JSON string and parse it inside \`execute\`.
719
+
720
+ ## ToolResult Interface
721
+
722
+ | Property | Type | Description |
723
+ |----------|------|-------------|
724
+ | \`status\` | \`'success' \\| 'error'\` | Whether the tool succeeded |
725
+ | \`result\` | \`string\` | Tool output (required for success) |
726
+ | \`error\` | \`string\` | Error message (for error status) |
727
+ | \`error_code\` | \`string\` | Machine-readable error code |
728
+ | \`error_data\` | \`Record<string, unknown>\` | Structured error payload |
729
+ | \`attachments\` | \`ToolAttachment[]\` | Files to attach (images, etc.) |
730
+
731
+ ## ThreadState Access
732
+
733
+ The \`state\` parameter provides access to:
734
+
735
+ \`\`\`typescript
736
+ execute: async (state, args) => {
737
+ // Thread information
738
+ const threadId = state.thread.id;
739
+ const thread = state.thread.instance;
740
+
741
+ // Configuration
742
+ const agentName = state.agent.name;
743
+ const modelName = state.model.name;
744
+
745
+ // Message history
746
+ const messages = state.messages;
747
+
748
+ // Thread variable resolution
749
+ const apiKey = await state.env('GOOGLE_API_KEY');
750
+ await state.setEnv('LAST_TOOL_RUN_AT', new Date().toISOString());
751
+
752
+ // Durable per-thread JSON values
753
+ const runCount = (await state.getValue<number>('run_count')) ?? 0;
754
+ await state.setValue('run_count', runCount + 1);
755
+
756
+ // Sandboxed JS/TS execution with explicit bridge capabilities
757
+ const run = state.runCode('export async function main(path) { return await read(path) }', {
758
+ execute: { fn: 'main', args: ['/notes.txt'] },
759
+ globals: {
760
+ read: async (path: string) => {
761
+ const data = await state.readFile(path);
762
+ return data ? new TextDecoder().decode(data) : null;
763
+ },
764
+ },
765
+ });
766
+ const codeResult = await run;
767
+
768
+ // Parent state (for sub-prompts)
769
+ const root = state.rootState;
770
+ }
771
+ \`\`\`
772
+
773
+ Use \`state.runCode()\` instead of \`eval\` or \`new Function\` for model- or user-authored JavaScript/TypeScript. The sandbox starts with no ambient host capabilities; provide imports/globals explicitly, use \`modules\` for local relative ES modules, use \`execute\` to select an export and pass args, use \`report\` for streamed observations, and call \`run.terminate(reason)\` from your own timeout budget when needed. \`modules\` keys are graph-root relative paths; entry-source imports resolve from \`options.filename\` when supplied. Relative module imports may use \`./\` and \`../\` as long as they resolve within the supplied module graph. In thread endpoints, \`runCode\` is forwarded into the thread Durable Object; pass plain transferable option values there, and do function-backed bridges from tools or in-thread execution contexts.
774
+
775
+ ## Tool Without Arguments
776
+
777
+ \`\`\`typescript
778
+ export default defineTool({
779
+ description: 'Get current server time',
780
+ execute: async (state) => {
781
+ return {
782
+ status: 'success',
783
+ result: new Date().toISOString(),
784
+ };
785
+ },
786
+ });
787
+ \`\`\`
788
+
789
+ ## Error Handling
790
+
791
+ Return errors gracefully instead of throwing:
792
+
793
+ \`\`\`typescript
794
+ export default defineTool({
795
+ description: 'Fetch user data',
796
+ args: z.object({ userId: z.string() }),
797
+ execute: async (state, args) => {
798
+ try {
799
+ const user = await fetchUser(args.userId);
800
+ return { status: 'success', result: JSON.stringify(user) };
801
+ } catch (error) {
802
+ return {
803
+ status: 'error',
804
+ error: \`Failed to fetch user: \${error.message}\`,
805
+ };
806
+ }
807
+ },
808
+ });
809
+ \`\`\`
810
+
811
+ ## Queueing Additional Tools
812
+
813
+ Queue another tool to run after the current one:
814
+
815
+ \`\`\`typescript
816
+ import { queueTool } from '@standardagents/builder';
817
+
818
+ export default defineTool({
819
+ description: 'Create order and send confirmation',
820
+ args: z.object({ items: z.array(z.string()) }),
821
+ execute: async (state, args) => {
822
+ const order = await createOrder(args.items);
823
+
824
+ // Queue email tool to run next
825
+ queueTool(state, 'send_confirmation_email', {
826
+ orderId: order.id,
827
+ email: state.thread.metadata.userEmail,
828
+ });
829
+
830
+ return { status: 'success', result: JSON.stringify(order) };
831
+ },
832
+ });
833
+ \`\`\`
834
+
835
+ ## Injecting Messages
836
+
837
+ Add messages without triggering re-execution:
838
+
839
+ \`\`\`typescript
840
+ import { injectMessage } from '@standardagents/builder';
841
+
842
+ export default defineTool({
843
+ description: 'Log audit event',
844
+ args: z.object({ event: z.string() }),
845
+ execute: async (state, args) => {
846
+ await injectMessage(state, {
847
+ role: 'system',
848
+ content: \`[AUDIT] \${args.event}\`,
849
+ });
850
+ return { status: 'success', result: 'Logged' };
851
+ },
852
+ });
853
+ \`\`\`
854
+
855
+ ## Variables and Env
856
+
857
+ Tools can declare variable requirements with \`variables\`, including \`required\` and \`description\` metadata:
858
+
859
+ \`\`\`typescript
860
+ export default defineTool({
861
+ description: 'Search uploaded documents',
862
+ args: z.object({ query: z.string() }),
863
+ execute: async (state, args) => {
864
+ const vectorStoreId = await state.env('VECTOR_STORE_ID');
865
+ const results = await searchVectorStore(vectorStoreId, args.query);
866
+ return { status: 'success', result: JSON.stringify(results) };
867
+ },
868
+ variables: [
869
+ {
870
+ name: 'VECTOR_STORE_ID',
871
+ type: 'text',
872
+ required: true,
873
+ scoped: false,
874
+ description: 'OpenAI Vector Store ID',
875
+ },
876
+ ],
877
+ });
878
+ \`\`\`
879
+
880
+ Use \`scoped: true\` for per-instance values that should not inherit from parent thread env (for example per-account OAuth tokens on subagents).
881
+
882
+ ## Returning Attachments
883
+
884
+ Tools can return file attachments (e.g., generated images):
885
+
886
+ \`\`\`typescript
887
+ export default defineTool({
888
+ description: 'Generate a chart from data',
889
+ args: z.object({ data: z.array(z.number()) }),
890
+ execute: async (state, args) => {
891
+ const chartImage = await generateChart(args.data);
892
+ return {
893
+ status: 'success',
894
+ result: 'Chart generated successfully',
895
+ attachments: [{
896
+ name: 'chart.png',
897
+ mimeType: 'image/png',
898
+ data: chartImage.base64,
899
+ width: 800,
900
+ height: 600,
901
+ }],
902
+ };
903
+ },
904
+ });
905
+ \`\`\`
906
+
907
+ ## Best Practices
908
+
909
+ - **Write clear descriptions** - LLMs decide tool usage based on descriptions
910
+ - **Describe all parameters** with \`.describe()\` in Zod schemas
911
+ - **Handle errors gracefully** - return error status, don't throw
912
+ - **Use snake_case** for file names (\`search_knowledge_base.ts\`)
913
+ - **Keep tools focused** - one task per tool
914
+ - **Use \`state.rootState\`** when queueing from sub-prompts
915
+
916
+ ## Supported Zod Types
917
+
918
+ - Primitives: \`string\`, \`number\`, \`boolean\`, \`null\`
919
+ - Enums: \`z.enum(['a', 'b', 'c'])\`
920
+ - Arrays: \`z.array(z.string())\`
921
+ - Objects: \`z.object({ ... })\`
922
+ - Optional: \`z.string().optional()\`
923
+ - Default: \`z.number().default(10)\`
924
+ - Nullable: \`z.string().nullable()\`
925
+
926
+ ## Documentation
927
+
928
+ Full reference: https://docs.standardagentbuilder.com/api-reference/define/tool
929
+ `;
930
+
931
+ // src/docs/hooks.ts
932
+ var HOOKS_CLAUDE_MD = `# Lifecycle Hooks
933
+
934
+ Hooks intercept and modify agent execution at specific lifecycle points.
935
+
936
+ ## Available Hooks
937
+
938
+ | Hook | Signature | Purpose |
939
+ |------|-----------|---------|
940
+ | \`after_thread_created\` | \`(state: ThreadState) => void\` | Initialize a newly created thread before execution |
941
+ | \`after_subagent_created\` | \`(state: ThreadState, childState: ThreadState) => void\` | Run parent-side logic after a child thread is created |
942
+ | \`after_system_message\` | \`(state: ThreadState, systemMessage: string) => string \\| null \\| undefined\` | Modify the rendered system message for a request |
943
+ | \`filter_messages\` | \`(state: ThreadState, messages: Message[]) => Message[]\` | Filter raw messages before LLM context |
944
+ | \`prefilter_llm_history\` | \`(state: ThreadState, messages: LLMMessage[]) => LLMMessage[]\` | Modify chat completion messages before LLM |
945
+ | \`before_create_message\` | \`(state: ThreadState, message: Message) => Message\` | Modify message before database insert |
946
+ | \`after_create_message\` | \`(state: ThreadState, message: Message) => void\` | Run logic after message created |
947
+ | \`before_update_message\` | \`(state: ThreadState, id: string, updates: Record) => Record\` | Modify updates before message update |
948
+ | \`after_update_message\` | \`(state: ThreadState, message: Message) => void\` | Run logic after message updated |
949
+ | \`before_store_tool_result\` | \`(state: ThreadState, toolCall: HookToolCall, result: HookToolResult) => HookToolResult\` | Modify tool result before storage |
950
+ | \`after_tool_call_success\` | \`(state: ThreadState, toolCall: HookToolCall, result: HookToolResult) => HookToolResult \\| null\` | Process successful tool execution |
951
+ | \`after_tool_call_failure\` | \`(state: ThreadState, toolCall: HookToolCall, result: HookToolResult) => HookToolResult \\| null\` | Process failed tool execution |
952
+
953
+ All hooks receive \`ThreadState\` as their first parameter, providing access to thread identity, message history, resource loading, durable per-thread values via \`getValue\` / \`setValue\`, and sandboxed JS/TS execution via \`runCode\`.
954
+
955
+ ## Creating a Hook
956
+
957
+ Each hook file exports a default \`defineHook\` call with three properties:
958
+
959
+ \`\`\`typescript
960
+ import { defineHook } from '@standardagents/builder';
961
+
962
+ export default defineHook({
963
+ hook: 'filter_messages', // Hook type
964
+ id: 'limit_recent_messages', // Unique ID (snake_case)
965
+ execute: async (state, messages) => {
966
+ return messages.slice(-20);
967
+ }
968
+ });
969
+ \`\`\`
970
+
971
+ ## Hook Scoping
972
+
973
+ Hooks are scoped to **prompts** or **agents** via their ID:
974
+
975
+ \`\`\`typescript
976
+ // In a prompt definition
977
+ definePrompt({
978
+ name: 'customer_support',
979
+ hooks: ['limit_recent_messages', 'redact_pii'],
980
+ // ...
981
+ });
982
+
983
+ // In an agent definition
984
+ defineAgent({
985
+ name: 'support_agent',
986
+ hooks: ['log_all_messages'],
987
+ // ...
988
+ });
989
+ \`\`\`
990
+
991
+ - **Prompt hooks** take precedence over agent hooks
992
+ - If a prompt defines hooks, only those run (agent hooks are skipped)
993
+ - If no prompt hooks are defined, agent hooks run as fallback
994
+ - Hooks are filtered by type at runtime
995
+
996
+ ## File Naming
997
+
998
+ Hook files can use **any name** \u2014 the hook type and ID are defined inside the file:
999
+
1000
+ \`\`\`
1001
+ agents/hooks/
1002
+ \u251C\u2500\u2500 my_filter.ts # Could contain any hook type
1003
+ \u251C\u2500\u2500 redact_sensitive_data.ts
1004
+ \u251C\u2500\u2500 log_tool_usage.ts
1005
+ \u2514\u2500\u2500 add_metadata.ts
1006
+ \`\`\`
1007
+
1008
+ ## Examples
1009
+
1010
+ ### Filter Messages (Limit Context)
1011
+
1012
+ \`\`\`typescript
1013
+ import { defineHook } from '@standardagents/builder';
1014
+
1015
+ export default defineHook({
1016
+ hook: 'filter_messages',
1017
+ id: 'limit_to_20',
1018
+ execute: async (state, messages) => {
1019
+ return messages.slice(-20);
1020
+ }
1021
+ });
1022
+ \`\`\`
1023
+
1024
+ ### Prefilter LLM History (Redact Content)
1025
+
1026
+ \`\`\`typescript
1027
+ import { defineHook } from '@standardagents/builder';
1028
+
1029
+ export default defineHook({
1030
+ hook: 'prefilter_llm_history',
1031
+ id: 'redact_pii',
1032
+ execute: async (state, messages) => {
1033
+ return messages.map(msg => ({
1034
+ ...msg,
1035
+ content: typeof msg.content === 'string'
1036
+ ? msg.content.replace(/\\b\\d{4}-\\d{4}-\\d{4}-\\d{4}\\b/g, '[REDACTED]')
1037
+ : msg.content,
1038
+ }));
1039
+ }
1040
+ });
1041
+ \`\`\`
1042
+
1043
+ ### Before Create Message (Add Metadata)
1044
+
1045
+ \`\`\`typescript
1046
+ import { defineHook } from '@standardagents/builder';
1047
+
1048
+ export default defineHook({
1049
+ hook: 'before_create_message',
1050
+ id: 'add_version_metadata',
1051
+ execute: async (state, message) => {
1052
+ if (message.role === 'user' && message.content) {
1053
+ return { ...message, content: \`[v1.0] \${message.content}\` };
1054
+ }
1055
+ return message;
1056
+ }
1057
+ });
1058
+ \`\`\`
1059
+
1060
+ ### Before Store Tool Result (Sanitize)
1061
+
1062
+ \`\`\`typescript
1063
+ import { defineHook } from '@standardagents/builder';
1064
+
1065
+ export default defineHook({
1066
+ hook: 'before_store_tool_result',
1067
+ id: 'sanitize_results',
1068
+ execute: async (state, toolCall, toolResult) => {
1069
+ // toolCall: { id, type: 'function', function: { name, arguments } }
1070
+ // toolResult: { status, result?, error?, stack?, attachments? }
1071
+ if (toolResult.result) {
1072
+ return { ...toolResult, result: toolResult.result.replace(/secret/gi, '[REDACTED]') };
1073
+ }
1074
+ return toolResult;
1075
+ }
1076
+ });
1077
+ \`\`\`
1078
+
1079
+ ### After Tool Call Success (Logging)
1080
+
1081
+ \`\`\`typescript
1082
+ import { defineHook } from '@standardagents/builder';
1083
+
1084
+ export default defineHook({
1085
+ hook: 'after_tool_call_success',
1086
+ id: 'log_tool_success',
1087
+ execute: async (state, toolCall, result) => {
1088
+ console.log(\`Tool \${toolCall.function.name} succeeded\`);
1089
+ return null; // Return null to use original result
1090
+ }
1091
+ });
1092
+ \`\`\`
1093
+
1094
+ ### After Tool Call Failure (Recovery)
1095
+
1096
+ \`\`\`typescript
1097
+ import { defineHook } from '@standardagents/builder';
1098
+
1099
+ export default defineHook({
1100
+ hook: 'after_tool_call_failure',
1101
+ id: 'weather_fallback',
1102
+ execute: async (state, toolCall, result) => {
1103
+ if (toolCall.function.name === 'fetch_weather') {
1104
+ return {
1105
+ status: 'success',
1106
+ result: JSON.stringify({ temp: 'unavailable', fallback: true }),
1107
+ };
1108
+ }
1109
+ return null; // Use original error for other tools
1110
+ }
1111
+ });
1112
+ \`\`\`
1113
+
1114
+ ## Hook Categories
1115
+
1116
+ **Transformation hooks** (return modified data):
1117
+ - \`after_system_message\` (return replacement string, or null/undefined for no change)
1118
+ - \`filter_messages\`
1119
+ - \`prefilter_llm_history\`
1120
+ - \`before_create_message\`
1121
+ - \`before_update_message\`
1122
+ - \`before_store_tool_result\`
1123
+ - \`after_tool_call_success\` (return modified result or null)
1124
+ - \`after_tool_call_failure\` (return modified result or null)
1125
+
1126
+ **Event hooks** (side effects only):
1127
+ - \`after_thread_created\`
1128
+ - \`after_subagent_created\`
1129
+ - \`after_create_message\`
1130
+ - \`after_update_message\`
1131
+
1132
+ ## Best Practices
1133
+
1134
+ - **Keep hooks fast** - target <100ms execution
1135
+ - **Wrap in try-catch** - hooks continue on error (original data preserved)
1136
+ - **Use unique IDs** - hook IDs must be snake_case and unique across the project
1137
+ - **Scope appropriately** - assign hooks to prompts or agents that need them
1138
+ - **Document purpose** with clear comments
1139
+ - **Use for cross-cutting concerns** - logging, redaction, enrichment
1140
+
1141
+ ## Documentation
1142
+
1143
+ Full reference: https://docs.standardagentbuilder.com/api-reference/define/hook
1144
+ `;
1145
+
1146
+ // src/docs/api.ts
1147
+ var API_CLAUDE_MD = `# Thread-Specific API Endpoints
1148
+
1149
+ Define custom API endpoints that operate on specific threads with access to the thread's ThreadState.
1150
+
1151
+ ## File-Based Routing
1152
+
1153
+ | File Pattern | HTTP Method | Route |
1154
+ |--------------|-------------|-------|
1155
+ | \`name.ts\` | GET | \`/api/threads/:threadId/name\` |
1156
+ | \`name.get.ts\` | GET | \`/api/threads/:threadId/name\` |
1157
+ | \`name.post.ts\` | POST | \`/api/threads/:threadId/name\` |
1158
+ | \`name.put.ts\` | PUT | \`/api/threads/:threadId/name\` |
1159
+ | \`name.delete.ts\` | DELETE | \`/api/threads/:threadId/name\` |
1160
+ | \`index.ts\` | GET | \`/api/threads/:threadId\` |
1161
+ | \`nested/route.ts\` | GET | \`/api/threads/:threadId/nested/route\` |
1162
+ | \`items/[id].ts\` | GET | \`/api/threads/:threadId/items/:id\` |
1163
+ | \`files/[*].ts\` | GET | \`/api/threads/:threadId/files/*\` |
1164
+
1165
+ Files without a method suffix default to GET. Method suffixes are case-insensitive and support \`.get.ts\`, \`.post.ts\`, \`.put.ts\`, \`.patch.ts\`, and \`.delete.ts\`.
1166
+
1167
+ Dynamic segments use \`[name]\` and are passed to the handler as \`params.name\`. Catch-all segments use \`[*]\` and are passed as \`params['*']\`; the catch-all value may contain \`/\` for nested paths. Static routes match before dynamic routes, and dynamic routes match before catch-all routes.
1168
+
1169
+ ## Basic Example
1170
+
1171
+ \`\`\`typescript
1172
+ // agents/api/status.get.ts -> GET /api/threads/:threadId/status
1173
+ import { defineThreadEndpoint } from '@standardagents/spec';
1174
+
1175
+ export default defineThreadEndpoint(async (req, state, params) => {
1176
+ const { messages, total } = await state.getMessages();
1177
+ return Response.json({
1178
+ threadId: state.threadId,
1179
+ messageCount: total,
1180
+ status: 'active',
1181
+ params,
1182
+ });
1183
+ });
1184
+ \`\`\`
1185
+
1186
+ ## Handler Parameters
1187
+
1188
+ | Parameter | Type | Description |
1189
+ |-----------|------|-------------|
1190
+ | \`req\` | \`Request\` | The incoming HTTP request |
1191
+ | \`state\` | \`ThreadState\` | Thread state with messages, identity, file system, \`runCode\`, etc. |
1192
+ | \`params\` | \`Record<string, string>\` | Route parameters captured from \`[name]\` and \`[*]\` path segments |
1193
+
1194
+ Note: \`state.execution\` is always \`null\` in endpoints since the thread is at rest. \`state.runCode()\` is available from endpoints and is forwarded into the thread runtime; pass plain transferable option values there, and do function-backed sandbox bridges from tools or in-thread execution contexts.
1195
+
1196
+ ## ThreadState Methods
1197
+
1198
+ Access thread data through the state object:
1199
+
1200
+ \`\`\`typescript
1201
+ import { defineThreadEndpoint } from '@standardagents/spec';
1202
+
1203
+ export default defineThreadEndpoint(async (req, state) => {
1204
+ // Thread identity
1205
+ console.log('Thread ID:', state.threadId);
1206
+ console.log('Agent ID:', state.agentId);
1207
+ console.log('User ID:', state.userId);
1208
+
1209
+ // Message operations
1210
+ const { messages, total, hasMore } = await state.getMessages({
1211
+ limit: 100,
1212
+ offset: 0,
1213
+ order: 'desc',
1214
+ });
1215
+
1216
+ // Thread env (thread scope + active descendants)
1217
+ const approvalGate = await state.env('TOPDOWN_APPROVAL_GATE');
1218
+ await state.setEnv('TOPDOWN_APPROVAL_GATE', approvalGate || 'open');
1219
+
1220
+ // Durable per-thread JSON values
1221
+ const exports = (await state.getValue<number>('export_count')) ?? 0;
1222
+ await state.setValue('export_count', exports + 1);
1223
+
1224
+ // File system operations
1225
+ const files = await state.findFiles('**/*.json');
1226
+ const data = await state.readFile('/data/config.json');
1227
+
1228
+ // Resource loading
1229
+ const agent = await state.loadAgent('my-agent');
1230
+ const prompt = await state.loadPrompt('my-prompt');
1231
+
1232
+ return Response.json({ messages, total });
1233
+ });
1234
+ \`\`\`
1235
+
1236
+ ## POST with Request Body
1237
+
1238
+ \`\`\`typescript
1239
+ // agents/api/export.post.ts -> POST /api/threads/:threadId/export
1240
+ import { defineThreadEndpoint } from '@standardagents/spec';
1241
+
1242
+ export default defineThreadEndpoint(async (req, state) => {
1243
+ const body = await req.json();
1244
+ const { format = 'json' } = body;
1245
+
1246
+ const { messages } = await state.getMessages();
1247
+
1248
+ if (format === 'csv') {
1249
+ const csv = messages.map(m => \`\${m.role},\${m.content}\`).join('\\n');
1250
+ return new Response(csv, {
1251
+ headers: { 'Content-Type': 'text/csv' },
1252
+ });
1253
+ }
1254
+
1255
+ return Response.json(messages);
1256
+ });
1257
+ \`\`\`
1258
+
1259
+ ## Nested Routes
1260
+
1261
+ Create directories for nested routes:
1262
+
1263
+ \`\`\`
1264
+ agents/api/
1265
+ \u251C\u2500\u2500 status.get.ts -> GET /api/threads/:threadId/status
1266
+ \u251C\u2500\u2500 export.post.ts -> POST /api/threads/:threadId/export
1267
+ \u2514\u2500\u2500 messages/
1268
+ \u251C\u2500\u2500 count.ts -> GET /api/threads/:threadId/messages/count
1269
+ \u251C\u2500\u2500 [id].ts -> GET /api/threads/:threadId/messages/:id
1270
+ \u2514\u2500\u2500 [*].ts -> GET /api/threads/:threadId/messages/*
1271
+ \`\`\`
1272
+
1273
+ ## Error Handling
1274
+
1275
+ \`\`\`typescript
1276
+ import { defineThreadEndpoint } from '@standardagents/spec';
1277
+
1278
+ export default defineThreadEndpoint(async (req, state) => {
1279
+ try {
1280
+ const data = await riskyOperation();
1281
+ return Response.json(data);
1282
+ } catch (error) {
1283
+ return Response.json({ error: error.message }, { status: 500 });
1284
+ }
1285
+ });
1286
+ \`\`\`
1287
+
1288
+ ## File System Operations
1289
+
1290
+ \`\`\`typescript
1291
+ import { defineThreadEndpoint } from '@standardagents/spec';
1292
+
1293
+ export default defineThreadEndpoint(async (req, state) => {
1294
+ // Read files
1295
+ const content = await state.readFile('/data/file.txt');
1296
+
1297
+ // Write files
1298
+ await state.writeFile('/output/result.json', JSON.stringify(data), 'application/json');
1299
+
1300
+ // List directory
1301
+ const { entries } = await state.readdirFile('/data');
1302
+
1303
+ // Search files
1304
+ const matches = await state.grepFiles('pattern');
1305
+ const paths = await state.findFiles('**/*.ts');
1306
+
1307
+ return Response.json({ success: true });
1308
+ });
1309
+ \`\`\`
1310
+
1311
+ ## Best Practices
1312
+
1313
+ - **Keep handlers fast** - endpoints are in the request path
1314
+ - **Paginate large queries** - use limit/offset for messages
1315
+ - **Validate input data** - check request body before processing
1316
+ - **Use descriptive file names** - \`export.post.ts\` not \`ep1.ts\`
1317
+ - **Return proper status codes** - 200, 400, 404, 500
1318
+ - **Import from spec** - use \`@standardagents/spec\` for \`defineThreadEndpoint\`
1319
+
1320
+ ## Documentation
1321
+
1322
+ Full reference: https://docs.standardagentbuilder.com/core-concepts/api
1323
+ `;
1324
+
1325
+ // src/index.ts
1326
+ var FIRST_PARTY_PROVIDER_PACKAGES = [
1327
+ "@standardagents/cloudflare",
1328
+ "@standardagents/cerebras",
1329
+ "@standardagents/google",
1330
+ "@standardagents/groq",
1331
+ "@standardagents/openai",
1332
+ "@standardagents/openrouter",
1333
+ "@standardagents/xai"
1334
+ ];
1335
+ var DEFAULT_TEMPLATE_VERSIONS = {
1336
+ standardAgents: "latest",
1337
+ sip: "latest",
1338
+ vite: "latest",
1339
+ typescript: "latest",
1340
+ cloudflareVitePlugin: "latest",
1341
+ wrangler: "latest",
1342
+ zod: "latest"
1343
+ };
1344
+ var AGENTBUILDER_TEMPLATE_VERSION = "0.15.0";
1345
+ var DEFAULT_COMPATIBILITY_DATE = "2025-08-13";
1346
+ function ensureTrailingNewline(value) {
1347
+ return value.endsWith("\n") ? value : `${value}
1348
+ `;
1349
+ }
1350
+ function mergeVersions(versions) {
1351
+ return {
1352
+ ...DEFAULT_TEMPLATE_VERSIONS,
1353
+ ...versions
1354
+ };
1355
+ }
1356
+ function packageNameFromProjectName(projectName) {
1357
+ const normalized = projectName.toLowerCase().replace(/^@[^/]+\//, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1358
+ return normalized || "agentbuilder-project";
1359
+ }
1360
+ function file(path, content, message) {
1361
+ return {
1362
+ path,
1363
+ content: ensureTrailingNewline(content),
1364
+ message
1365
+ };
1366
+ }
1367
+ function renderPackageJson(options) {
1368
+ const versions = mergeVersions(options.versions);
1369
+ const standardAgentsVersion = versions.standardAgents;
1370
+ const dependencies = {
1371
+ "@standardagents/builder": standardAgentsVersion,
1372
+ "@standardagents/spec": standardAgentsVersion,
1373
+ "@standardagents/sip": versions.sip,
1374
+ zod: versions.zod ?? "latest"
1375
+ };
1376
+ for (const providerPackage of FIRST_PARTY_PROVIDER_PACKAGES) {
1377
+ dependencies[providerPackage] = standardAgentsVersion;
1378
+ }
1379
+ return `${JSON.stringify({
1380
+ name: packageNameFromProjectName(options.projectName),
1381
+ version: "0.0.0",
1382
+ private: true,
1383
+ type: "module",
1384
+ scripts: {
1385
+ dev: "vite --host 0.0.0.0 --port 5173",
1386
+ build: "vite build",
1387
+ typecheck: "tsc --noEmit",
1388
+ "wrangler:types": "wrangler types"
1389
+ },
1390
+ dependencies,
1391
+ devDependencies: {
1392
+ "@cloudflare/vite-plugin": versions.cloudflareVitePlugin,
1393
+ typescript: versions.typescript,
1394
+ vite: versions.vite,
1395
+ wrangler: versions.wrangler
1396
+ }
1397
+ }, null, 2)}
1398
+ `;
1399
+ }
1400
+ function renderWranglerJson(options) {
1401
+ const compatibilityDate = options.compatibilityDate ?? DEFAULT_COMPATIBILITY_DATE;
1402
+ const workerName = packageNameFromProjectName(options.projectName);
1403
+ return `{
1404
+ "$schema": "node_modules/wrangler/config-schema.json",
1405
+ "name": "${workerName}",
1406
+ "main": "worker/index.ts",
1407
+ "compatibility_date": "${compatibilityDate}",
1408
+ "compatibility_flags": ["nodejs_compat", "enable_ctx_exports"],
1409
+ "observability": {
1410
+ "enabled": true
1411
+ },
1412
+ "worker_loaders": [
1413
+ {
1414
+ "binding": "AGENT_BUILDER_CODE_LOADER"
1415
+ }
1416
+ ],
1417
+ "vars": {
1418
+ "AGENT_BUILDER_CODE_COMPATIBILITY_DATE": "${compatibilityDate}"
1419
+ },
1420
+ "assets": {
1421
+ "directory": "dist/client",
1422
+ "not_found_handling": "single-page-application",
1423
+ "binding": "ASSETS",
1424
+ "run_worker_first": ["/**"]
1425
+ },
1426
+ "durable_objects": {
1427
+ "bindings": [
1428
+ {
1429
+ "name": "AGENT_BUILDER_THREAD",
1430
+ "class_name": "DurableThread"
1431
+ },
1432
+ {
1433
+ "name": "AGENT_BUILDER",
1434
+ "class_name": "DurableAgentBuilder"
1435
+ }
1436
+ ]
1437
+ },
1438
+ "migrations": [
1439
+ {
1440
+ "tag": "v1",
1441
+ "new_sqlite_classes": ["DurableThread"]
1442
+ },
1443
+ {
1444
+ "tag": "v2",
1445
+ "new_sqlite_classes": ["DurableAgentBuilder"]
1446
+ }
1447
+ ]
1448
+ }
1449
+ `;
1450
+ }
1451
+ function renderViteConfig() {
1452
+ return `import { defineConfig } from "vite"
1453
+ import { cloudflare } from "@cloudflare/vite-plugin"
1454
+ import { agentbuilder } from "@standardagents/builder"
1455
+
1456
+ export default defineConfig({
1457
+ plugins: [agentbuilder({ mountPoint: "/" }), cloudflare()],
1458
+ })
1459
+ `;
1460
+ }
1461
+ function renderTsConfig() {
1462
+ return `{
1463
+ "compilerOptions": {
1464
+ "target": "ES2022",
1465
+ "useDefineForClassFields": true,
1466
+ "module": "ESNext",
1467
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
1468
+ "skipLibCheck": true,
1469
+ "moduleResolution": "Bundler",
1470
+ "allowImportingTsExtensions": true,
1471
+ "resolveJsonModule": true,
1472
+ "isolatedModules": true,
1473
+ "noEmit": true,
1474
+ "strict": true
1475
+ },
1476
+ "include": ["worker", "agents"]
1477
+ }
1478
+ `;
1479
+ }
1480
+ function renderWorkerIndex() {
1481
+ return `import { router, CodeExecutionBridge } from "virtual:@standardagents/builder"
1482
+ import DurableThread from "../agents/Thread"
1483
+ import DurableAgentBuilder from "../agents/AgentBuilder"
1484
+
1485
+ export default {
1486
+ async fetch(request, env) {
1487
+ const res = await router(request, env)
1488
+ return res ?? new Response(null, { status: 404 })
1489
+ },
1490
+ } satisfies ExportedHandler<Env>
1491
+
1492
+ export { DurableThread, DurableAgentBuilder, CodeExecutionBridge }
1493
+ `;
1494
+ }
1495
+ function renderDurableThread() {
1496
+ return `import { DurableThread } from "virtual:@standardagents/builder"
1497
+
1498
+ export default class Thread extends DurableThread {}
1499
+ `;
1500
+ }
1501
+ function renderDurableAgentBuilder() {
1502
+ return `import { DurableAgentBuilder } from "virtual:@standardagents/builder"
1503
+
1504
+ export default class AgentBuilder extends DurableAgentBuilder {}
1505
+ `;
1506
+ }
1507
+ function renderGitignore() {
1508
+ return `node_modules
1509
+ dist
1510
+ .wrangler
1511
+ .env
1512
+ .dev.vars
1513
+ `;
1514
+ }
1515
+ function renderDevVarsExample() {
1516
+ return `# Standard Agents local development environment
1517
+ # Copy to .dev.vars for local-only Worker secrets.
1518
+
1519
+ # Local data encryption key. Generate with: openssl rand -hex 32
1520
+ ENCRYPTION_KEY=
1521
+
1522
+ # Optional local admin password for development access.
1523
+ SUPER_ADMIN_PASSWORD=password
1524
+
1525
+ # Platform connection. The CLI writes real values to .dev.vars for platform-created projects.
1526
+ STANDARD_AGENTS_API_KEY=
1527
+ PLATFORM_ENDPOINT=
1528
+ STANDARD_AGENTS_API_URL=
1529
+
1530
+ # BYOK provider keys. When set, these keys override Standard Agents hosted routing for that provider.
1531
+ CLOUDFLARE_API_TOKEN=
1532
+ CLOUDFLARE_ACCOUNT_ID=
1533
+ CEREBRAS_API_KEY=
1534
+ GOOGLE_API_KEY=
1535
+ GROQ_API_KEY=
1536
+ OPENAI_API_KEY=
1537
+ OPENROUTER_API_KEY=
1538
+ XAI_API_KEY=
1539
+ `;
1540
+ }
1541
+ function renderDeployHelper() {
1542
+ return `import fs from "node:fs";
1543
+ import path from "node:path";
1544
+
1545
+ function findBundleInDir(dir) {
1546
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
1547
+ const files = entries
1548
+ .filter((entry) => entry.isFile() && /\\.(m?js)$/.test(entry.name))
1549
+ .sort((a, b) => {
1550
+ const aIsIndex = a.name === "index.js" || a.name === "index.mjs" ? 0 : 1;
1551
+ const bIsIndex = b.name === "index.js" || b.name === "index.mjs" ? 0 : 1;
1552
+ if (aIsIndex !== bIsIndex) return aIsIndex - bIsIndex;
1553
+ return fs.statSync(path.join(dir, b.name)).size - fs.statSync(path.join(dir, a.name)).size;
1554
+ });
1555
+
1556
+ for (const file of files) {
1557
+ const filePath = path.join(dir, file.name);
1558
+ const content = fs.readFileSync(filePath, "utf8");
1559
+ if (content.includes("export default") || content.includes("export {")) {
1560
+ return { path: filePath, content };
1561
+ }
1562
+ }
1563
+
1564
+ for (const entry of entries) {
1565
+ if (!entry.isDirectory() || entry.name === "client" || entry.name === "node_modules") continue;
1566
+ const nested = findBundleInDir(path.join(dir, entry.name));
1567
+ if (nested) return nested;
1568
+ }
1569
+ return null;
1570
+ }
1571
+
1572
+ function findWorkerBundle() {
1573
+ for (const dir of [".wrangler/tmp", "dist"]) {
1574
+ if (!fs.existsSync(dir)) continue;
1575
+ const bundle = findBundleInDir(dir);
1576
+ if (bundle) return bundle;
1577
+ }
1578
+ throw new Error("Could not find a Worker bundle in .wrangler/tmp or dist");
1579
+ }
1580
+
1581
+ const deployUrl = process.env.STANDARD_AGENTS_DEPLOY_URL;
1582
+ const deployToken = process.env.STANDARD_AGENTS_DEPLOY_TOKEN;
1583
+ const buildId = process.env.STANDARD_AGENTS_BUILD_ID;
1584
+ if (!deployUrl || !deployToken || !buildId) {
1585
+ throw new Error("Missing Standard Agents deployment environment");
1586
+ }
1587
+
1588
+ const bundle = findWorkerBundle();
1589
+ const response = await fetch(deployUrl, {
1590
+ method: "POST",
1591
+ headers: {
1592
+ "Authorization": \`Bearer \${deployToken}\`,
1593
+ "Content-Type": "application/json",
1594
+ },
1595
+ body: JSON.stringify({
1596
+ build_id: buildId,
1597
+ script_content: bundle.content,
1598
+ compatibility_date: process.env.STANDARD_AGENTS_COMPATIBILITY_DATE || undefined,
1599
+ }),
1600
+ });
1601
+
1602
+ if (!response.ok) {
1603
+ const text = await response.text();
1604
+ throw new Error(\`Standard Agents deploy failed (\${response.status}): \${text}\`);
1605
+ }
1606
+
1607
+ console.log(\`Deployed Standard Agents Worker from \${bundle.path}\`);
1608
+ `;
1609
+ }
1610
+ function renderDeployWorkflow() {
1611
+ return `name: Standard Agents Deploy
1612
+
1613
+ on:
1614
+ repository_dispatch:
1615
+ types: [standardagents-deploy]
1616
+
1617
+ permissions:
1618
+ contents: read
1619
+
1620
+ jobs:
1621
+ deploy:
1622
+ runs-on: ubuntu-latest
1623
+ env:
1624
+ STANDARD_AGENTS_BUILD_ID: \${{ github.event.client_payload.build_id }}
1625
+ STANDARD_AGENTS_DEPLOY_URL: \${{ github.event.client_payload.deploy_url }}
1626
+ STANDARD_AGENTS_DEPLOY_TOKEN: \${{ github.event.client_payload.deploy_token }}
1627
+ STANDARD_AGENTS_COMPATIBILITY_DATE: \${{ github.event.client_payload.compatibility_date }}
1628
+ STANDARD_AGENTS_API_URL: \${{ github.event.client_payload.api_url }}
1629
+ steps:
1630
+ - uses: actions/checkout@v4
1631
+ with:
1632
+ ref: \${{ github.event.client_payload.commit_sha }}
1633
+ - uses: actions/setup-node@v4
1634
+ with:
1635
+ node-version: 22
1636
+ - name: Enable package managers
1637
+ run: corepack enable
1638
+ - name: Install dependencies
1639
+ shell: bash
1640
+ run: |
1641
+ if [ -f pnpm-lock.yaml ]; then
1642
+ pnpm install --frozen-lockfile || pnpm install
1643
+ elif [ -f yarn.lock ]; then
1644
+ yarn install --immutable || yarn install
1645
+ elif [ -f bun.lockb ] || [ -f bun.lock ]; then
1646
+ bun install --frozen-lockfile || bun install
1647
+ elif [ -f package-lock.json ]; then
1648
+ npm ci || npm install
1649
+ else
1650
+ npm install
1651
+ fi
1652
+ - name: Build
1653
+ shell: bash
1654
+ run: |
1655
+ if [ -f pnpm-lock.yaml ]; then
1656
+ pnpm run build
1657
+ elif [ -f yarn.lock ]; then
1658
+ yarn build
1659
+ elif [ -f bun.lockb ] || [ -f bun.lock ]; then
1660
+ bun run build
1661
+ else
1662
+ npm run build
1663
+ fi
1664
+ - name: Upload Worker
1665
+ run: node .github/standardagents-deploy.mjs
1666
+ `;
1667
+ }
1668
+ function renderTemplateMetadata(options) {
1669
+ return `${JSON.stringify({
1670
+ generator: "@standardagents/agentbuilder-template",
1671
+ template_version: options.templateVersion ?? AGENTBUILDER_TEMPLATE_VERSION,
1672
+ project_name: options.projectName
1673
+ }, null, 2)}
1674
+ `;
1675
+ }
1676
+ function renderAgentBuilderProject(options) {
1677
+ const files = [
1678
+ file("package.json", renderPackageJson(options), "Add AgentBuilder package manifest"),
1679
+ file("tsconfig.json", renderTsConfig(), "Add TypeScript config"),
1680
+ file("vite.config.ts", renderViteConfig(), "Add Vite config"),
1681
+ file("wrangler.jsonc", renderWranglerJson(options), "Add Wrangler config"),
1682
+ file("worker/index.ts", renderWorkerIndex(), "Add Worker entrypoint"),
1683
+ file("agents/Thread.ts", renderDurableThread(), "Add DurableThread"),
1684
+ file("agents/AgentBuilder.ts", renderDurableAgentBuilder(), "Add DurableAgentBuilder"),
1685
+ file("agents/agents/CLAUDE.md", AGENTS_CLAUDE_MD, "Add agent docs"),
1686
+ file("agents/prompts/CLAUDE.md", PROMPTS_CLAUDE_MD, "Add prompt docs"),
1687
+ file("agents/models/CLAUDE.md", MODELS_CLAUDE_MD, "Add model docs"),
1688
+ file("agents/tools/CLAUDE.md", TOOLS_CLAUDE_MD, "Add tool docs"),
1689
+ file("agents/hooks/CLAUDE.md", HOOKS_CLAUDE_MD, "Add hook docs"),
1690
+ file("agents/api/CLAUDE.md", API_CLAUDE_MD, "Add API docs"),
1691
+ file("CLAUDE.md", ROOT_CLAUDE_MD, "Add AgentBuilder project docs"),
1692
+ file(".dev.vars.example", renderDevVarsExample(), "Add local env example"),
1693
+ file(".gitignore", renderGitignore(), "Add gitignore")
1694
+ ];
1695
+ if (options.includeTemplateMetadata) {
1696
+ files.push(file(".standardagents/template.json", renderTemplateMetadata(options), "Add Standard Agents template metadata"));
1697
+ }
1698
+ if (options.includeDeployAutomation) {
1699
+ files.push(
1700
+ file(".github/standardagents-deploy.mjs", renderDeployHelper(), "Add Standard Agents deploy helper"),
1701
+ file(".github/workflows/standardagents-deploy.yml", renderDeployWorkflow(), "Add Standard Agents deploy workflow")
1702
+ );
1703
+ }
1704
+ return files;
1705
+ }
1706
+ export {
1707
+ AGENTBUILDER_TEMPLATE_VERSION,
1708
+ AGENTS_CLAUDE_MD,
1709
+ API_CLAUDE_MD,
1710
+ DEFAULT_COMPATIBILITY_DATE,
1711
+ DEFAULT_TEMPLATE_VERSIONS,
1712
+ FIRST_PARTY_PROVIDER_PACKAGES,
1713
+ HOOKS_CLAUDE_MD,
1714
+ MODELS_CLAUDE_MD,
1715
+ PROMPTS_CLAUDE_MD,
1716
+ ROOT_CLAUDE_MD,
1717
+ TOOLS_CLAUDE_MD,
1718
+ packageNameFromProjectName,
1719
+ renderAgentBuilderProject,
1720
+ renderDeployHelper,
1721
+ renderDeployWorkflow,
1722
+ renderDevVarsExample,
1723
+ renderDurableAgentBuilder,
1724
+ renderDurableThread,
1725
+ renderGitignore,
1726
+ renderPackageJson,
1727
+ renderTemplateMetadata,
1728
+ renderTsConfig,
1729
+ renderViteConfig,
1730
+ renderWorkerIndex,
1731
+ renderWranglerJson
1732
+ };
1733
+ //# sourceMappingURL=index.js.map