@standardagents/cli 0.11.0-next.ab7e1ea → 0.11.0-next.c3b4490
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/chat/src/App.tsx +1 -1
- package/chat/src/components/MessageList.tsx +94 -40
- package/dist/index.js +171 -115
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/chat/src/App.tsx
CHANGED
|
@@ -110,7 +110,7 @@ function AuthenticatedApp() {
|
|
|
110
110
|
</button>
|
|
111
111
|
|
|
112
112
|
{currentThreadId ? (
|
|
113
|
-
<ThreadProvider key={currentThreadId} threadId={currentThreadId} live>
|
|
113
|
+
<ThreadProvider key={currentThreadId} threadId={currentThreadId} live useWorkblocks>
|
|
114
114
|
<Chat
|
|
115
115
|
thread={threads.find(t => t.id === currentThreadId)}
|
|
116
116
|
onUpdateTitle={(title) => updateThreadTitle(currentThreadId, title)}
|
|
@@ -228,62 +228,114 @@ function WorkItemStatus({ status }: { status: 'pending' | 'success' | 'error' |
|
|
|
228
228
|
return <SpinnerIcon className="w-3.5 h-3.5 text-[var(--text-secondary)]" />
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
// Chevron icon for collapse/expand
|
|
232
|
+
function ChevronIcon({ className, expanded }: { className?: string; expanded: boolean }) {
|
|
233
|
+
return (
|
|
234
|
+
<svg
|
|
235
|
+
className={`${className} transition-transform duration-200 ${expanded ? 'rotate-90' : ''}`}
|
|
236
|
+
viewBox="0 0 24 24"
|
|
237
|
+
fill="none"
|
|
238
|
+
stroke="currentColor"
|
|
239
|
+
strokeWidth={2}
|
|
240
|
+
strokeLinecap="round"
|
|
241
|
+
strokeLinejoin="round"
|
|
242
|
+
>
|
|
243
|
+
<path d="M9 18l6-6-6-6" />
|
|
244
|
+
</svg>
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
|
|
231
248
|
// Workblock component
|
|
232
|
-
function Workblock({ workblock }: { workblock: WorkMessage }) {
|
|
249
|
+
function Workblock({ workblock, isLast, threadLoading }: { workblock: WorkMessage; isLast?: boolean; threadLoading?: boolean }) {
|
|
250
|
+
const [isExpanded, setIsExpanded] = useState(false)
|
|
233
251
|
const { text } = parseMessageContent(workblock.content)
|
|
234
252
|
const isPending = workblock.status === 'pending'
|
|
235
253
|
|
|
236
254
|
// Group work items by tool_call_id to pair calls with results
|
|
237
255
|
const toolCalls = workblock.workItems.filter(item => item.type === 'tool_call')
|
|
256
|
+
const toolResults = workblock.workItems.filter(item => item.type === 'tool_result')
|
|
238
257
|
|
|
239
|
-
// Count completed vs total
|
|
258
|
+
// Count completed vs total and check for errors
|
|
240
259
|
const completedCount = toolCalls.filter(item => item.status === 'success' || item.status === 'error').length
|
|
260
|
+
const errorCount = toolCalls.filter(item => item.status === 'error').length
|
|
241
261
|
const totalCount = toolCalls.length
|
|
262
|
+
const hasErrors = errorCount > 0
|
|
263
|
+
|
|
264
|
+
// Get most recent info for the badge (last tool result or last tool call name)
|
|
265
|
+
const lastResult = toolResults[toolResults.length - 1]
|
|
266
|
+
const lastToolCall = toolCalls[toolCalls.length - 1]
|
|
267
|
+
const badgeText = lastResult?.content
|
|
268
|
+
? (lastResult.content.length > 40 ? lastResult.content.slice(0, 40) + '...' : lastResult.content)
|
|
269
|
+
: lastToolCall?.name
|
|
270
|
+
? formatToolName(lastToolCall.name)
|
|
271
|
+
: null
|
|
272
|
+
|
|
273
|
+
// Determine status label and color
|
|
274
|
+
const statusLabel = isPending ? 'Working' : hasErrors ? 'Completed with errors' : 'Completed'
|
|
275
|
+
const statusColor = isPending ? 'text-violet-500' : hasErrors ? 'text-amber-500' : 'text-emerald-500'
|
|
276
|
+
|
|
277
|
+
// Show loader if this is the last workblock and thread is still loading
|
|
278
|
+
const showLoader = isLast && threadLoading && !isPending
|
|
242
279
|
|
|
243
280
|
return (
|
|
244
|
-
<div className="animate-fade-in
|
|
245
|
-
{/*
|
|
281
|
+
<div className="animate-fade-in">
|
|
282
|
+
{/* Workblock panel */}
|
|
246
283
|
<div className={`bg-[var(--bg-tertiary)] border border-[var(--border-primary)] rounded-xl overflow-hidden max-w-[85%] ${isPending ? 'workblock-shimmer' : ''}`}>
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
284
|
+
{/* Header - clickable to toggle */}
|
|
285
|
+
<button
|
|
286
|
+
onClick={() => setIsExpanded(!isExpanded)}
|
|
287
|
+
className="w-full px-3 py-2 bg-[var(--bg-hover)] flex items-center gap-2 hover:bg-[var(--bg-tertiary)] transition-colors text-left"
|
|
288
|
+
>
|
|
289
|
+
<ChevronIcon className="w-3.5 h-3.5 text-[var(--text-tertiary)]" expanded={isExpanded} />
|
|
290
|
+
<span className={`text-xs font-medium uppercase tracking-wide ${statusColor}`}>
|
|
291
|
+
{statusLabel}
|
|
292
|
+
</span>
|
|
293
|
+
{(isPending || showLoader) && (
|
|
294
|
+
<SpinnerIcon className="w-3 h-3 text-violet-500" />
|
|
295
|
+
)}
|
|
296
|
+
{/* Badge with most recent info when collapsed */}
|
|
297
|
+
{!isExpanded && badgeText && (
|
|
298
|
+
<span className="ml-auto text-xs text-[var(--text-tertiary)] bg-[var(--bg-secondary)] px-2 py-0.5 rounded truncate max-w-[200px]">
|
|
299
|
+
{badgeText}
|
|
251
300
|
</span>
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
)
|
|
255
|
-
</div>
|
|
256
|
-
{totalCount > 1 && (
|
|
257
|
-
<span className="text-xs text-[var(--text-tertiary)]">
|
|
301
|
+
)}
|
|
302
|
+
{isExpanded && totalCount > 1 && (
|
|
303
|
+
<span className="ml-auto text-xs text-[var(--text-tertiary)]">
|
|
258
304
|
{completedCount}/{totalCount}
|
|
259
305
|
</span>
|
|
260
306
|
)}
|
|
261
|
-
</
|
|
307
|
+
</button>
|
|
308
|
+
|
|
309
|
+
{/* Collapsible content */}
|
|
310
|
+
{isExpanded && (
|
|
311
|
+
<>
|
|
312
|
+
{/* Text content (thinking/reasoning) inside the workblock */}
|
|
313
|
+
{text && text.trim() && (
|
|
314
|
+
<div className="px-3 py-2.5 border-t border-[var(--border-primary)] bg-[var(--bg-secondary)]">
|
|
315
|
+
<p className="text-sm text-[var(--text-secondary)] italic whitespace-pre-wrap break-words">
|
|
316
|
+
{text.trim()}
|
|
317
|
+
</p>
|
|
318
|
+
</div>
|
|
319
|
+
)}
|
|
262
320
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
321
|
+
{/* Tool calls list */}
|
|
322
|
+
<div className="divide-y divide-[var(--border-primary)] border-t border-[var(--border-primary)]">
|
|
323
|
+
{toolCalls.map((item, index) => (
|
|
324
|
+
<div
|
|
325
|
+
key={item.id}
|
|
326
|
+
className="px-3 py-2.5 flex items-center gap-3 animate-slide-in"
|
|
327
|
+
style={{ animationDelay: `${index * 50}ms` }}
|
|
328
|
+
>
|
|
329
|
+
<WorkItemStatus status={item.status} />
|
|
330
|
+
<span className="text-sm text-[var(--text-primary)]">
|
|
331
|
+
{formatToolName(item.name)}
|
|
332
|
+
</span>
|
|
333
|
+
</div>
|
|
334
|
+
))}
|
|
274
335
|
</div>
|
|
275
|
-
|
|
276
|
-
|
|
336
|
+
</>
|
|
337
|
+
)}
|
|
277
338
|
</div>
|
|
278
|
-
|
|
279
|
-
{/* Text content if present */}
|
|
280
|
-
{text && (
|
|
281
|
-
<div className="max-w-[85%]">
|
|
282
|
-
<div className="whitespace-pre-wrap break-words text-[15px] leading-relaxed text-[var(--text-primary)]">
|
|
283
|
-
{text}
|
|
284
|
-
</div>
|
|
285
|
-
</div>
|
|
286
|
-
)}
|
|
287
339
|
</div>
|
|
288
340
|
)
|
|
289
341
|
}
|
|
@@ -717,7 +769,7 @@ function ThinkingIndicator() {
|
|
|
717
769
|
}
|
|
718
770
|
|
|
719
771
|
export function MessageList() {
|
|
720
|
-
const { messages, loading, threadId } = useThread()
|
|
772
|
+
const { workblocks: messages, loading, threadId } = useThread()
|
|
721
773
|
const bottomRef = useRef<HTMLDivElement>(null)
|
|
722
774
|
|
|
723
775
|
const scrollToBottom = useCallback(() => {
|
|
@@ -771,10 +823,12 @@ export function MessageList() {
|
|
|
771
823
|
|
|
772
824
|
return (
|
|
773
825
|
<div className="py-6 px-4 space-y-6">
|
|
774
|
-
{messages.map((msg) => {
|
|
826
|
+
{messages.map((msg, index) => {
|
|
827
|
+
const isLast = index === messages.length - 1
|
|
828
|
+
|
|
775
829
|
// Handle workblocks
|
|
776
830
|
if (isWorkMessage(msg)) {
|
|
777
|
-
return <Workblock key={msg.id} workblock={msg} />
|
|
831
|
+
return <Workblock key={msg.id} workblock={msg} isLast={isLast} threadLoading={loading} />
|
|
778
832
|
}
|
|
779
833
|
|
|
780
834
|
// Skip system and tool messages (tool messages are shown in workblocks)
|
package/dist/index.js
CHANGED
|
@@ -116,30 +116,32 @@ agents/
|
|
|
116
116
|
|
|
117
117
|
Files are **auto-discovered** at runtime. No manual registration needed.
|
|
118
118
|
|
|
119
|
-
##
|
|
119
|
+
## ThreadState
|
|
120
120
|
|
|
121
|
-
\`
|
|
121
|
+
\`ThreadState\` is the state object available in tools and hooks:
|
|
122
122
|
|
|
123
123
|
\`\`\`typescript
|
|
124
|
-
interface
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
124
|
+
interface ThreadState {
|
|
125
|
+
// Identity (readonly)
|
|
126
|
+
threadId: string; // Thread identifier
|
|
127
|
+
agentId: string; // Agent identifier
|
|
128
|
+
userId: string | null; // User identifier (if set)
|
|
129
|
+
createdAt: number; // Creation timestamp
|
|
130
|
+
|
|
131
|
+
// Methods
|
|
132
|
+
getMessages(options?): Promise<MessagesResult>; // Get conversation history
|
|
133
|
+
injectMessage(input): Promise<Message>; // Add message to thread
|
|
134
|
+
loadModel(name): Promise<ModelConfig>; // Load model definition
|
|
135
|
+
loadPrompt(name): Promise<PromptConfig>; // Load prompt definition
|
|
136
|
+
loadAgent(name): Promise<AgentConfig>; // Load agent definition
|
|
135
137
|
}
|
|
136
138
|
\`\`\`
|
|
137
139
|
|
|
138
140
|
Access in tools:
|
|
139
141
|
\`\`\`typescript
|
|
140
142
|
export default defineTool('...', schema, async (flow, args) => {
|
|
141
|
-
const threadId = flow.
|
|
142
|
-
const messages = flow.
|
|
143
|
+
const threadId = flow.threadId;
|
|
144
|
+
const { messages } = await flow.getMessages();
|
|
143
145
|
// ...
|
|
144
146
|
});
|
|
145
147
|
\`\`\`
|
|
@@ -283,15 +285,12 @@ Prompts define system instructions, model selection, and available tools for LLM
|
|
|
283
285
|
| \`toolDescription\` | \`string\` | Yes | Description shown when used as a tool |
|
|
284
286
|
| \`prompt\` | \`string \\| StructuredPrompt\` | Yes | System instructions |
|
|
285
287
|
| \`model\` | \`string\` | Yes | Model name to use (references \`agents/models/\`) |
|
|
286
|
-
| \`tools\` | \`(string \\| ToolConfig)[]\` | No | Available tools for
|
|
287
|
-
| \`handoffAgents\` | \`string[]\` | No | Agents this prompt can hand off to |
|
|
288
|
+
| \`tools\` | \`(string \\| ToolConfig)[]\` | No | Available tools (include ai_human agent names for handoffs) |
|
|
288
289
|
| \`includeChat\` | \`boolean\` | No | Include full conversation history |
|
|
289
290
|
| \`includePastTools\` | \`boolean\` | No | Include previous tool results |
|
|
290
291
|
| \`parallelToolCalls\` | \`boolean\` | No | Allow multiple concurrent tool calls |
|
|
291
292
|
| \`toolChoice\` | \`'auto' \\| 'none' \\| 'required'\` | No | Tool calling strategy |
|
|
292
293
|
| \`requiredSchema\` | \`z.ZodObject\` | No | Input validation when called as tool |
|
|
293
|
-
| \`beforeTool\` | \`string\` | No | Tool to run before LLM request |
|
|
294
|
-
| \`afterTool\` | \`string\` | No | Tool to run after LLM response |
|
|
295
294
|
| \`reasoning\` | \`ReasoningConfig\` | No | Extended thinking configuration |
|
|
296
295
|
|
|
297
296
|
## Basic Example
|
|
@@ -491,7 +490,7 @@ export default defineAgent({
|
|
|
491
490
|
});
|
|
492
491
|
\`\`\`
|
|
493
492
|
|
|
494
|
-
Other prompts can then include
|
|
493
|
+
Other prompts can then include the agent name in their \`tools\` array to enable handoffs.
|
|
495
494
|
|
|
496
495
|
## Stop Conditions (Priority Order)
|
|
497
496
|
|
|
@@ -528,12 +527,12 @@ Tools extend agent capabilities beyond text generation. They allow LLMs to fetch
|
|
|
528
527
|
## Function Signature
|
|
529
528
|
|
|
530
529
|
\`\`\`typescript
|
|
531
|
-
defineTool(
|
|
530
|
+
defineTool({
|
|
532
531
|
description: string, // What the tool does (shown to LLM)
|
|
533
|
-
args
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
)
|
|
532
|
+
args?: z.ZodObject, // Input validation schema (optional)
|
|
533
|
+
execute: (state, args) => ToolResult, // Implementation
|
|
534
|
+
tenvs?: z.ZodObject, // Thread environment variables (optional)
|
|
535
|
+
})
|
|
537
536
|
\`\`\`
|
|
538
537
|
|
|
539
538
|
## Basic Example
|
|
@@ -542,20 +541,20 @@ defineTool(
|
|
|
542
541
|
import { defineTool } from '@standardagents/builder';
|
|
543
542
|
import { z } from 'zod';
|
|
544
543
|
|
|
545
|
-
export default defineTool(
|
|
546
|
-
'Search the knowledge base for articles matching a query',
|
|
547
|
-
z.object({
|
|
544
|
+
export default defineTool({
|
|
545
|
+
description: 'Search the knowledge base for articles matching a query',
|
|
546
|
+
args: z.object({
|
|
548
547
|
query: z.string().describe('Search query'),
|
|
549
548
|
limit: z.number().optional().default(10).describe('Max results'),
|
|
550
549
|
}),
|
|
551
|
-
async (
|
|
550
|
+
execute: async (state, args) => {
|
|
552
551
|
const results = await searchKB(args.query, args.limit);
|
|
553
552
|
return {
|
|
554
553
|
status: 'success',
|
|
555
554
|
result: JSON.stringify(results),
|
|
556
555
|
};
|
|
557
|
-
}
|
|
558
|
-
);
|
|
556
|
+
},
|
|
557
|
+
});
|
|
559
558
|
\`\`\`
|
|
560
559
|
|
|
561
560
|
## ToolResult Interface
|
|
@@ -565,44 +564,45 @@ export default defineTool(
|
|
|
565
564
|
| \`status\` | \`'success' \\| 'error'\` | Whether the tool succeeded |
|
|
566
565
|
| \`result\` | \`string\` | Tool output (required for success) |
|
|
567
566
|
| \`error\` | \`string\` | Error message (for error status) |
|
|
567
|
+
| \`attachments\` | \`ToolAttachment[]\` | Files to attach (images, etc.) |
|
|
568
568
|
|
|
569
|
-
##
|
|
569
|
+
## ThreadState Access
|
|
570
570
|
|
|
571
|
-
The \`
|
|
571
|
+
The \`state\` parameter provides access to:
|
|
572
572
|
|
|
573
573
|
\`\`\`typescript
|
|
574
|
-
async (
|
|
574
|
+
execute: async (state, args) => {
|
|
575
575
|
// Thread information
|
|
576
|
-
const threadId =
|
|
577
|
-
const thread =
|
|
576
|
+
const threadId = state.thread.id;
|
|
577
|
+
const thread = state.thread.instance;
|
|
578
578
|
|
|
579
579
|
// Configuration
|
|
580
|
-
const agentName =
|
|
581
|
-
const modelName =
|
|
580
|
+
const agentName = state.agent.name;
|
|
581
|
+
const modelName = state.model.name;
|
|
582
582
|
|
|
583
583
|
// Message history
|
|
584
|
-
const messages =
|
|
584
|
+
const messages = state.messages;
|
|
585
585
|
|
|
586
586
|
// Environment bindings
|
|
587
|
-
const env =
|
|
587
|
+
const env = state.env;
|
|
588
588
|
|
|
589
589
|
// Parent state (for sub-prompts)
|
|
590
|
-
const root =
|
|
590
|
+
const root = state.rootState;
|
|
591
591
|
}
|
|
592
592
|
\`\`\`
|
|
593
593
|
|
|
594
594
|
## Tool Without Arguments
|
|
595
595
|
|
|
596
596
|
\`\`\`typescript
|
|
597
|
-
export default defineTool(
|
|
598
|
-
'Get current server time',
|
|
599
|
-
async (
|
|
597
|
+
export default defineTool({
|
|
598
|
+
description: 'Get current server time',
|
|
599
|
+
execute: async (state) => {
|
|
600
600
|
return {
|
|
601
601
|
status: 'success',
|
|
602
602
|
result: new Date().toISOString(),
|
|
603
603
|
};
|
|
604
|
-
}
|
|
605
|
-
);
|
|
604
|
+
},
|
|
605
|
+
});
|
|
606
606
|
\`\`\`
|
|
607
607
|
|
|
608
608
|
## Error Handling
|
|
@@ -610,10 +610,10 @@ export default defineTool(
|
|
|
610
610
|
Return errors gracefully instead of throwing:
|
|
611
611
|
|
|
612
612
|
\`\`\`typescript
|
|
613
|
-
export default defineTool(
|
|
614
|
-
'Fetch user data',
|
|
615
|
-
z.object({ userId: z.string() }),
|
|
616
|
-
async (
|
|
613
|
+
export default defineTool({
|
|
614
|
+
description: 'Fetch user data',
|
|
615
|
+
args: z.object({ userId: z.string() }),
|
|
616
|
+
execute: async (state, args) => {
|
|
617
617
|
try {
|
|
618
618
|
const user = await fetchUser(args.userId);
|
|
619
619
|
return { status: 'success', result: JSON.stringify(user) };
|
|
@@ -623,8 +623,8 @@ export default defineTool(
|
|
|
623
623
|
error: \`Failed to fetch user: \${error.message}\`,
|
|
624
624
|
};
|
|
625
625
|
}
|
|
626
|
-
}
|
|
627
|
-
);
|
|
626
|
+
},
|
|
627
|
+
});
|
|
628
628
|
\`\`\`
|
|
629
629
|
|
|
630
630
|
## Queueing Additional Tools
|
|
@@ -634,21 +634,21 @@ Queue another tool to run after the current one:
|
|
|
634
634
|
\`\`\`typescript
|
|
635
635
|
import { queueTool } from '@standardagents/builder';
|
|
636
636
|
|
|
637
|
-
export default defineTool(
|
|
638
|
-
'Create order and send confirmation',
|
|
639
|
-
z.object({ items: z.array(z.string()) }),
|
|
640
|
-
async (
|
|
637
|
+
export default defineTool({
|
|
638
|
+
description: 'Create order and send confirmation',
|
|
639
|
+
args: z.object({ items: z.array(z.string()) }),
|
|
640
|
+
execute: async (state, args) => {
|
|
641
641
|
const order = await createOrder(args.items);
|
|
642
642
|
|
|
643
643
|
// Queue email tool to run next
|
|
644
|
-
queueTool(
|
|
644
|
+
queueTool(state, 'send_confirmation_email', {
|
|
645
645
|
orderId: order.id,
|
|
646
|
-
email:
|
|
646
|
+
email: state.thread.metadata.userEmail,
|
|
647
647
|
});
|
|
648
648
|
|
|
649
649
|
return { status: 'success', result: JSON.stringify(order) };
|
|
650
|
-
}
|
|
651
|
-
);
|
|
650
|
+
},
|
|
651
|
+
});
|
|
652
652
|
\`\`\`
|
|
653
653
|
|
|
654
654
|
## Injecting Messages
|
|
@@ -658,17 +658,61 @@ Add messages without triggering re-execution:
|
|
|
658
658
|
\`\`\`typescript
|
|
659
659
|
import { injectMessage } from '@standardagents/builder';
|
|
660
660
|
|
|
661
|
-
export default defineTool(
|
|
662
|
-
'Log audit event',
|
|
663
|
-
z.object({ event: z.string() }),
|
|
664
|
-
async (
|
|
665
|
-
await injectMessage(
|
|
661
|
+
export default defineTool({
|
|
662
|
+
description: 'Log audit event',
|
|
663
|
+
args: z.object({ event: z.string() }),
|
|
664
|
+
execute: async (state, args) => {
|
|
665
|
+
await injectMessage(state, {
|
|
666
666
|
role: 'system',
|
|
667
667
|
content: \`[AUDIT] \${args.event}\`,
|
|
668
668
|
});
|
|
669
669
|
return { status: 'success', result: 'Logged' };
|
|
670
|
-
}
|
|
671
|
-
);
|
|
670
|
+
},
|
|
671
|
+
});
|
|
672
|
+
\`\`\`
|
|
673
|
+
|
|
674
|
+
## Thread Environment Variables (tenvs)
|
|
675
|
+
|
|
676
|
+
Tools can declare required thread environment variables:
|
|
677
|
+
|
|
678
|
+
\`\`\`typescript
|
|
679
|
+
export default defineTool({
|
|
680
|
+
description: 'Search uploaded documents',
|
|
681
|
+
args: z.object({ query: z.string() }),
|
|
682
|
+
execute: async (state, args) => {
|
|
683
|
+
const vectorStoreId = state.tenvs.vectorStoreId;
|
|
684
|
+
const results = await searchVectorStore(vectorStoreId, args.query);
|
|
685
|
+
return { status: 'success', result: JSON.stringify(results) };
|
|
686
|
+
},
|
|
687
|
+
tenvs: z.object({
|
|
688
|
+
vectorStoreId: z.string().describe('OpenAI Vector Store ID'),
|
|
689
|
+
}),
|
|
690
|
+
});
|
|
691
|
+
\`\`\`
|
|
692
|
+
|
|
693
|
+
## Returning Attachments
|
|
694
|
+
|
|
695
|
+
Tools can return file attachments (e.g., generated images):
|
|
696
|
+
|
|
697
|
+
\`\`\`typescript
|
|
698
|
+
export default defineTool({
|
|
699
|
+
description: 'Generate a chart from data',
|
|
700
|
+
args: z.object({ data: z.array(z.number()) }),
|
|
701
|
+
execute: async (state, args) => {
|
|
702
|
+
const chartImage = await generateChart(args.data);
|
|
703
|
+
return {
|
|
704
|
+
status: 'success',
|
|
705
|
+
result: 'Chart generated successfully',
|
|
706
|
+
attachments: [{
|
|
707
|
+
name: 'chart.png',
|
|
708
|
+
mimeType: 'image/png',
|
|
709
|
+
data: chartImage.base64,
|
|
710
|
+
width: 800,
|
|
711
|
+
height: 600,
|
|
712
|
+
}],
|
|
713
|
+
};
|
|
714
|
+
},
|
|
715
|
+
});
|
|
672
716
|
\`\`\`
|
|
673
717
|
|
|
674
718
|
## Best Practices
|
|
@@ -678,7 +722,7 @@ export default defineTool(
|
|
|
678
722
|
- **Handle errors gracefully** - return error status, don't throw
|
|
679
723
|
- **Use snake_case** for file names (\`search_knowledge_base.ts\`)
|
|
680
724
|
- **Keep tools focused** - one task per tool
|
|
681
|
-
- **Use \`
|
|
725
|
+
- **Use \`state.rootState\`** when queueing from sub-prompts
|
|
682
726
|
|
|
683
727
|
## Supported Zod Types
|
|
684
728
|
|
|
@@ -982,17 +1026,19 @@ Full reference: https://docs.standardagentbuilder.com/core-concepts/api
|
|
|
982
1026
|
`;
|
|
983
1027
|
|
|
984
1028
|
// src/commands/scaffold.ts
|
|
985
|
-
var WRANGLER_TEMPLATE = (name) =>
|
|
1029
|
+
var WRANGLER_TEMPLATE = (name) => {
|
|
1030
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1031
|
+
return `{
|
|
986
1032
|
"$schema": "node_modules/wrangler/config-schema.json",
|
|
987
1033
|
"name": "${name}",
|
|
988
1034
|
"main": "worker/index.ts",
|
|
989
|
-
"compatibility_date": "
|
|
1035
|
+
"compatibility_date": "${today}",
|
|
990
1036
|
"compatibility_flags": ["nodejs_compat"],
|
|
991
1037
|
"observability": {
|
|
992
1038
|
"enabled": true
|
|
993
1039
|
},
|
|
994
1040
|
"assets": {
|
|
995
|
-
"directory": "dist",
|
|
1041
|
+
"directory": "dist/client",
|
|
996
1042
|
"not_found_handling": "single-page-application",
|
|
997
1043
|
"binding": "ASSETS",
|
|
998
1044
|
"run_worker_first": ["/**"]
|
|
@@ -1021,6 +1067,7 @@ var WRANGLER_TEMPLATE = (name) => `{
|
|
|
1021
1067
|
]
|
|
1022
1068
|
}
|
|
1023
1069
|
`;
|
|
1070
|
+
};
|
|
1024
1071
|
var THREAD_TS = `import { DurableThread } from 'virtual:@standardagents/builder'
|
|
1025
1072
|
|
|
1026
1073
|
export default class Thread extends DurableThread {}
|
|
@@ -1085,14 +1132,6 @@ async function modifyViteConfig(configPath, force) {
|
|
|
1085
1132
|
logger.info("Vite config already includes Standard Agents plugins");
|
|
1086
1133
|
return true;
|
|
1087
1134
|
}
|
|
1088
|
-
if (!hasCloudflare || force) {
|
|
1089
|
-
addVitePlugin(mod, {
|
|
1090
|
-
from: "@cloudflare/vite-plugin",
|
|
1091
|
-
imported: "cloudflare",
|
|
1092
|
-
constructor: "cloudflare"
|
|
1093
|
-
});
|
|
1094
|
-
logger.success("Added cloudflare plugin to vite.config");
|
|
1095
|
-
}
|
|
1096
1135
|
if (!hasAgentBuilder || force) {
|
|
1097
1136
|
addVitePlugin(mod, {
|
|
1098
1137
|
from: "@standardagents/builder",
|
|
@@ -1102,6 +1141,14 @@ async function modifyViteConfig(configPath, force) {
|
|
|
1102
1141
|
});
|
|
1103
1142
|
logger.success("Added agentbuilder plugin to vite.config");
|
|
1104
1143
|
}
|
|
1144
|
+
if (!hasCloudflare || force) {
|
|
1145
|
+
addVitePlugin(mod, {
|
|
1146
|
+
from: "@cloudflare/vite-plugin",
|
|
1147
|
+
imported: "cloudflare",
|
|
1148
|
+
constructor: "cloudflare"
|
|
1149
|
+
});
|
|
1150
|
+
logger.success("Added cloudflare plugin to vite.config");
|
|
1151
|
+
}
|
|
1105
1152
|
await writeFile(mod, configPath);
|
|
1106
1153
|
return true;
|
|
1107
1154
|
} catch (error) {
|
|
@@ -1109,10 +1156,10 @@ async function modifyViteConfig(configPath, force) {
|
|
|
1109
1156
|
logger.log("");
|
|
1110
1157
|
logger.log("Please manually add the following to your vite.config.ts:");
|
|
1111
1158
|
logger.log("");
|
|
1112
|
-
logger.log(` import { cloudflare } from '@cloudflare/vite-plugin'`);
|
|
1113
1159
|
logger.log(` import { agentbuilder } from '@standardagents/builder'`);
|
|
1160
|
+
logger.log(` import { cloudflare } from '@cloudflare/vite-plugin'`);
|
|
1114
1161
|
logger.log("");
|
|
1115
|
-
logger.log(` plugins: [
|
|
1162
|
+
logger.log(` plugins: [agentbuilder({ mountPoint: '/' }), cloudflare()]`);
|
|
1116
1163
|
logger.log("");
|
|
1117
1164
|
return false;
|
|
1118
1165
|
}
|
|
@@ -1161,7 +1208,7 @@ function createOrUpdateWranglerConfig(cwd, projectName, force) {
|
|
|
1161
1208
|
}
|
|
1162
1209
|
if (!config.assets) {
|
|
1163
1210
|
const edits = modify(result, ["assets"], {
|
|
1164
|
-
directory: "dist",
|
|
1211
|
+
directory: "dist/client",
|
|
1165
1212
|
not_found_handling: "single-page-application",
|
|
1166
1213
|
binding: "ASSETS",
|
|
1167
1214
|
run_worker_first: ["/**"]
|
|
@@ -1520,19 +1567,14 @@ function detectPackageManager() {
|
|
|
1520
1567
|
if (fs3.existsSync("package-lock.json")) return "npm";
|
|
1521
1568
|
return "npm";
|
|
1522
1569
|
}
|
|
1523
|
-
function
|
|
1570
|
+
function getCliVersion() {
|
|
1524
1571
|
try {
|
|
1525
1572
|
const __dirname2 = path3.dirname(fileURLToPath(import.meta.url));
|
|
1526
1573
|
const pkgPath = path3.resolve(__dirname2, "../../package.json");
|
|
1527
1574
|
const pkg2 = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
1528
|
-
|
|
1529
|
-
const prereleaseMatch = version.match(/-([a-z]+)\./i);
|
|
1530
|
-
if (prereleaseMatch) {
|
|
1531
|
-
return `@${prereleaseMatch[1]}`;
|
|
1532
|
-
}
|
|
1533
|
-
return `@^${version}`;
|
|
1575
|
+
return pkg2.version;
|
|
1534
1576
|
} catch {
|
|
1535
|
-
return "";
|
|
1577
|
+
return "latest";
|
|
1536
1578
|
}
|
|
1537
1579
|
}
|
|
1538
1580
|
async function selectPackageManager(detected) {
|
|
@@ -1670,31 +1712,7 @@ export default defineConfig({
|
|
|
1670
1712
|
}
|
|
1671
1713
|
}
|
|
1672
1714
|
logger.log("");
|
|
1673
|
-
logger.info("Step 2:
|
|
1674
|
-
logger.log("");
|
|
1675
|
-
try {
|
|
1676
|
-
const installCmd = pm === "npm" ? "install" : "add";
|
|
1677
|
-
const devFlag = pm === "npm" ? "--save-dev" : "-D";
|
|
1678
|
-
const builderVersion = getBuilderPackageVersion();
|
|
1679
|
-
await runCommand(pm, [
|
|
1680
|
-
installCmd,
|
|
1681
|
-
devFlag,
|
|
1682
|
-
"@cloudflare/vite-plugin",
|
|
1683
|
-
`@standardagents/builder${builderVersion}`,
|
|
1684
|
-
"wrangler",
|
|
1685
|
-
"zod"
|
|
1686
|
-
], projectPath);
|
|
1687
|
-
} catch (error) {
|
|
1688
|
-
logger.error("Failed to install dependencies");
|
|
1689
|
-
process.exit(1);
|
|
1690
|
-
}
|
|
1691
|
-
logger.log("");
|
|
1692
|
-
logger.info("Step 3: Configuring Standard Agents...");
|
|
1693
|
-
logger.log("");
|
|
1694
|
-
process.chdir(projectPath);
|
|
1695
|
-
await scaffold({ force: true });
|
|
1696
|
-
logger.log("");
|
|
1697
|
-
logger.info("Step 4: Configuring environment variables...");
|
|
1715
|
+
logger.info("Step 2: Configuring environment variables...");
|
|
1698
1716
|
logger.log("");
|
|
1699
1717
|
const encryptionKey = crypto.randomBytes(32).toString("hex");
|
|
1700
1718
|
let openrouterKey = "";
|
|
@@ -1729,6 +1747,44 @@ export default defineConfig({
|
|
|
1729
1747
|
if (!adminPassword) {
|
|
1730
1748
|
adminPassword = "admin";
|
|
1731
1749
|
}
|
|
1750
|
+
logger.log("");
|
|
1751
|
+
logger.info("Step 3: Installing Standard Agents dependencies...");
|
|
1752
|
+
logger.log("");
|
|
1753
|
+
try {
|
|
1754
|
+
const installCmd = pm === "npm" ? "install" : "add";
|
|
1755
|
+
const devFlag = pm === "npm" ? "--save-dev" : "-D";
|
|
1756
|
+
const cliVersion = getCliVersion();
|
|
1757
|
+
await runCommand(pm, [
|
|
1758
|
+
installCmd,
|
|
1759
|
+
devFlag,
|
|
1760
|
+
"@cloudflare/vite-plugin",
|
|
1761
|
+
"wrangler"
|
|
1762
|
+
], projectPath);
|
|
1763
|
+
const deps = [
|
|
1764
|
+
`@standardagents/builder@${cliVersion}`,
|
|
1765
|
+
`@standardagents/spec@${cliVersion}`,
|
|
1766
|
+
`@standardagents/sip@${cliVersion}`,
|
|
1767
|
+
"zod"
|
|
1768
|
+
];
|
|
1769
|
+
if (openaiKey) {
|
|
1770
|
+
deps.push(`@standardagents/openai@${cliVersion}`);
|
|
1771
|
+
}
|
|
1772
|
+
if (openrouterKey) {
|
|
1773
|
+
deps.push(`@standardagents/openrouter@${cliVersion}`);
|
|
1774
|
+
}
|
|
1775
|
+
await runCommand(pm, [installCmd, ...deps], projectPath);
|
|
1776
|
+
} catch (error) {
|
|
1777
|
+
logger.error("Failed to install dependencies");
|
|
1778
|
+
process.exit(1);
|
|
1779
|
+
}
|
|
1780
|
+
logger.log("");
|
|
1781
|
+
logger.info("Step 4: Configuring Standard Agents...");
|
|
1782
|
+
logger.log("");
|
|
1783
|
+
process.chdir(projectPath);
|
|
1784
|
+
await scaffold({ force: true });
|
|
1785
|
+
logger.log("");
|
|
1786
|
+
logger.info("Writing environment configuration...");
|
|
1787
|
+
logger.log("");
|
|
1732
1788
|
const devVarsLines = [
|
|
1733
1789
|
"# Standard Agents Environment Variables",
|
|
1734
1790
|
"# This file contains secrets for local development only",
|