@townco/agent 0.1.53 → 0.1.54
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/acp-server/adapter.d.ts +16 -0
- package/dist/acp-server/adapter.js +230 -16
- package/dist/acp-server/cli.d.ts +1 -3
- package/dist/acp-server/http.js +39 -1
- package/dist/acp-server/session-storage.d.ts +16 -1
- package/dist/acp-server/session-storage.js +23 -0
- package/dist/bin.js +0 -0
- package/dist/definition/index.d.ts +2 -2
- package/dist/definition/index.js +1 -0
- package/dist/runner/agent-runner.d.ts +7 -2
- package/dist/runner/index.d.ts +1 -3
- package/dist/runner/langchain/index.js +178 -38
- package/dist/runner/langchain/tools/generate_image.d.ts +28 -0
- package/dist/runner/langchain/tools/generate_image.js +135 -0
- package/dist/runner/langchain/tools/subagent.d.ts +6 -1
- package/dist/runner/langchain/tools/subagent.js +12 -2
- package/dist/runner/tools.d.ts +19 -2
- package/dist/runner/tools.js +9 -0
- package/dist/telemetry/index.js +7 -1
- package/dist/templates/index.d.ts +3 -0
- package/dist/templates/index.js +26 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -6
- package/templates/index.ts +36 -5
- package/dist/definition/mcp.d.ts +0 -0
- package/dist/definition/mcp.js +0 -0
- package/dist/definition/tools/todo.d.ts +0 -49
- package/dist/definition/tools/todo.js +0 -80
- package/dist/definition/tools/web_search.d.ts +0 -4
- package/dist/definition/tools/web_search.js +0 -26
- package/dist/dev-agent/index.d.ts +0 -2
- package/dist/dev-agent/index.js +0 -18
- package/dist/example.d.ts +0 -2
- package/dist/example.js +0 -19
- package/dist/scaffold/link-local.d.ts +0 -1
- package/dist/scaffold/link-local.js +0 -54
- package/dist/utils/__tests__/tool-overhead-calculator.test.d.ts +0 -1
- package/dist/utils/__tests__/tool-overhead-calculator.test.js +0 -153
- package/dist/utils/logger.d.ts +0 -39
- package/dist/utils/logger.js +0 -175
|
@@ -27,6 +27,20 @@ export declare class AgentAcpAdapter implements acp.Agent {
|
|
|
27
27
|
private currentToolOverheadTokens;
|
|
28
28
|
private currentMcpOverheadTokens;
|
|
29
29
|
constructor(agent: AgentRunner, connection: acp.AgentSideConnection, agentDir?: string, agentName?: string);
|
|
30
|
+
/**
|
|
31
|
+
* Extract tool metadata from the agent definition for exposing to clients.
|
|
32
|
+
* This provides basic info about available tools without loading them fully.
|
|
33
|
+
*/
|
|
34
|
+
private getToolsMetadata;
|
|
35
|
+
/**
|
|
36
|
+
* Extract MCP metadata from the agent definition for exposing to clients.
|
|
37
|
+
*/
|
|
38
|
+
private getMcpsMetadata;
|
|
39
|
+
/**
|
|
40
|
+
* Extract subagent metadata from the Task tool if present.
|
|
41
|
+
* This provides info about subagents configured via makeSubagentsTool.
|
|
42
|
+
*/
|
|
43
|
+
private getSubagentsMetadata;
|
|
30
44
|
/**
|
|
31
45
|
* Helper to save session to disk
|
|
32
46
|
* Call this after any modification to session.messages or session.context
|
|
@@ -38,10 +52,12 @@ export declare class AgentAcpAdapter implements acp.Agent {
|
|
|
38
52
|
authenticate(_params: acp.AuthenticateRequest): Promise<acp.AuthenticateResponse | undefined>;
|
|
39
53
|
setSessionMode(_params: acp.SetSessionModeRequest): Promise<acp.SetSessionModeResponse>;
|
|
40
54
|
prompt(params: acp.PromptRequest): Promise<acp.PromptResponse>;
|
|
55
|
+
private _promptImpl;
|
|
41
56
|
/**
|
|
42
57
|
* Execute hooks if configured for this agent
|
|
43
58
|
* Returns new context entries that should be appended to session.context
|
|
44
59
|
*/
|
|
45
60
|
private executeHooksIfConfigured;
|
|
61
|
+
private _executeHooksImpl;
|
|
46
62
|
cancel(params: acp.CancelNotification): Promise<void>;
|
|
47
63
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as acp from "@agentclientprotocol/sdk";
|
|
2
|
+
import { context, trace } from "@opentelemetry/api";
|
|
2
3
|
import { createLogger } from "@townco/core";
|
|
3
4
|
import { HookExecutor, loadHookCallback } from "../runner/hooks";
|
|
5
|
+
import { telemetry } from "../telemetry/index.js";
|
|
4
6
|
import { calculateContextSize, } from "../utils/context-size-calculator.js";
|
|
5
7
|
import { countToolResultTokens } from "../utils/token-counter.js";
|
|
6
8
|
import { SessionStorage, } from "./session-storage.js";
|
|
@@ -132,6 +134,82 @@ export class AgentAcpAdapter {
|
|
|
132
134
|
sessionStoragePath: this.storage ? `${agentDir}/.sessions` : null,
|
|
133
135
|
});
|
|
134
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Extract tool metadata from the agent definition for exposing to clients.
|
|
139
|
+
* This provides basic info about available tools without loading them fully.
|
|
140
|
+
*/
|
|
141
|
+
getToolsMetadata() {
|
|
142
|
+
const tools = this.agent.definition.tools ?? [];
|
|
143
|
+
return tools.map((tool) => {
|
|
144
|
+
if (typeof tool === "string") {
|
|
145
|
+
// Built-in tool - return basic info
|
|
146
|
+
return { name: tool, description: `Built-in tool: ${tool}` };
|
|
147
|
+
}
|
|
148
|
+
else if (tool.type === "direct") {
|
|
149
|
+
return {
|
|
150
|
+
name: tool.name,
|
|
151
|
+
description: tool.description,
|
|
152
|
+
...(tool.prettyName ? { prettyName: tool.prettyName } : {}),
|
|
153
|
+
...(tool.icon ? { icon: tool.icon } : {}),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
else if (tool.type === "filesystem") {
|
|
157
|
+
return {
|
|
158
|
+
name: "filesystem",
|
|
159
|
+
description: "File system access tools",
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
else if (tool.type === "custom") {
|
|
163
|
+
// Custom tools from module paths - extract name from path
|
|
164
|
+
const pathParts = tool.modulePath.split("/");
|
|
165
|
+
const fileName = pathParts[pathParts.length - 1] ?? "custom";
|
|
166
|
+
const name = fileName.replace(/\.(ts|js)$/, "");
|
|
167
|
+
return {
|
|
168
|
+
name,
|
|
169
|
+
description: `Custom tool from ${tool.modulePath}`,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
return { name: "unknown", description: "Unknown tool type" };
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Extract MCP metadata from the agent definition for exposing to clients.
|
|
177
|
+
*/
|
|
178
|
+
getMcpsMetadata() {
|
|
179
|
+
const mcps = this.agent.definition.mcps ?? [];
|
|
180
|
+
return mcps.map((mcp) => {
|
|
181
|
+
if (typeof mcp === "string") {
|
|
182
|
+
return {
|
|
183
|
+
name: mcp,
|
|
184
|
+
transport: "http", // String configs are resolved to HTTP proxy
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
name: mcp.name,
|
|
189
|
+
transport: mcp.transport,
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Extract subagent metadata from the Task tool if present.
|
|
195
|
+
* This provides info about subagents configured via makeSubagentsTool.
|
|
196
|
+
*/
|
|
197
|
+
getSubagentsMetadata() {
|
|
198
|
+
const tools = this.agent.definition.tools ?? [];
|
|
199
|
+
for (const tool of tools) {
|
|
200
|
+
// Look for direct tools with subagentConfigs (Task tools created by makeSubagentsTool)
|
|
201
|
+
if (typeof tool === "object" &&
|
|
202
|
+
tool.type === "direct" &&
|
|
203
|
+
"subagentConfigs" in tool &&
|
|
204
|
+
Array.isArray(tool.subagentConfigs)) {
|
|
205
|
+
return tool.subagentConfigs.map((config) => ({
|
|
206
|
+
name: config.agentName,
|
|
207
|
+
description: config.description,
|
|
208
|
+
}));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
135
213
|
/**
|
|
136
214
|
* Helper to save session to disk
|
|
137
215
|
* Call this after any modification to session.messages or session.context
|
|
@@ -168,19 +246,23 @@ export class AgentAcpAdapter {
|
|
|
168
246
|
...(this.agentDisplayName ? { title: this.agentDisplayName } : {}),
|
|
169
247
|
};
|
|
170
248
|
}
|
|
171
|
-
// Pass
|
|
172
|
-
// since Implementation doesn't support these fields
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
249
|
+
// Pass extended agent info via _meta extension point
|
|
250
|
+
// since ACP Implementation type doesn't support these fields directly
|
|
251
|
+
const toolsMetadata = this.getToolsMetadata();
|
|
252
|
+
const mcpsMetadata = this.getMcpsMetadata();
|
|
253
|
+
const subagentsMetadata = this.getSubagentsMetadata();
|
|
254
|
+
response._meta = {
|
|
255
|
+
...response._meta,
|
|
256
|
+
...(this.agentDescription
|
|
257
|
+
? { agentDescription: this.agentDescription }
|
|
258
|
+
: {}),
|
|
259
|
+
...(this.agentSuggestedPrompts
|
|
260
|
+
? { suggestedPrompts: this.agentSuggestedPrompts }
|
|
261
|
+
: {}),
|
|
262
|
+
...(toolsMetadata.length > 0 ? { tools: toolsMetadata } : {}),
|
|
263
|
+
...(mcpsMetadata.length > 0 ? { mcps: mcpsMetadata } : {}),
|
|
264
|
+
...(subagentsMetadata.length > 0 ? { subagents: subagentsMetadata } : {}),
|
|
265
|
+
};
|
|
184
266
|
return response;
|
|
185
267
|
}
|
|
186
268
|
async newSession(params) {
|
|
@@ -236,6 +318,14 @@ export class AgentAcpAdapter {
|
|
|
236
318
|
}
|
|
237
319
|
else if (block.type === "tool_call") {
|
|
238
320
|
// Replay tool call directly in final state (skip pending → completed transitions)
|
|
321
|
+
const replayMeta = {
|
|
322
|
+
isReplay: true,
|
|
323
|
+
...(block.prettyName ? { prettyName: block.prettyName } : {}),
|
|
324
|
+
...(block.icon ? { icon: block.icon } : {}),
|
|
325
|
+
...(block.subline ? { subline: block.subline } : {}),
|
|
326
|
+
...(block.batchId ? { batchId: block.batchId } : {}),
|
|
327
|
+
...block._meta,
|
|
328
|
+
};
|
|
239
329
|
this.connection.sessionUpdate({
|
|
240
330
|
sessionId: params.sessionId,
|
|
241
331
|
update: {
|
|
@@ -245,6 +335,7 @@ export class AgentAcpAdapter {
|
|
|
245
335
|
kind: block.kind,
|
|
246
336
|
status: block.status, // Use final status directly
|
|
247
337
|
rawInput: block.rawInput,
|
|
338
|
+
_meta: replayMeta,
|
|
248
339
|
},
|
|
249
340
|
});
|
|
250
341
|
// If there's output, emit tool_output event for the UI to display
|
|
@@ -326,6 +417,22 @@ export class AgentAcpAdapter {
|
|
|
326
417
|
return {};
|
|
327
418
|
}
|
|
328
419
|
async prompt(params) {
|
|
420
|
+
const promptSpan = telemetry.startSpan("adapter.prompt", {
|
|
421
|
+
"session.id": params.sessionId,
|
|
422
|
+
});
|
|
423
|
+
const spanContext = promptSpan
|
|
424
|
+
? trace.setSpan(context.active(), promptSpan)
|
|
425
|
+
: context.active();
|
|
426
|
+
return context.with(spanContext, async () => {
|
|
427
|
+
try {
|
|
428
|
+
return await this._promptImpl(params);
|
|
429
|
+
}
|
|
430
|
+
finally {
|
|
431
|
+
telemetry.endSpan(promptSpan);
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
async _promptImpl(params) {
|
|
329
436
|
let session = this.sessions.get(params.sessionId);
|
|
330
437
|
// If session not found (e.g., after server restart), create a new one
|
|
331
438
|
if (!session) {
|
|
@@ -345,7 +452,29 @@ export class AgentAcpAdapter {
|
|
|
345
452
|
this.currentMcpOverheadTokens = 0;
|
|
346
453
|
// Generate a unique messageId for this assistant response
|
|
347
454
|
const messageId = Math.random().toString(36).substring(2);
|
|
348
|
-
//
|
|
455
|
+
// Convert prompt content blocks to session storage format
|
|
456
|
+
const userContentBlocks = params.prompt.map((block) => {
|
|
457
|
+
if (block.type === "text") {
|
|
458
|
+
return { type: "text", text: block.text };
|
|
459
|
+
}
|
|
460
|
+
else if (block.type === "image") {
|
|
461
|
+
// Preserve image block with all its data
|
|
462
|
+
const imgBlock = block;
|
|
463
|
+
const imageBlock = { type: "image" };
|
|
464
|
+
if (imgBlock.source)
|
|
465
|
+
imageBlock.source = imgBlock.source;
|
|
466
|
+
if (imgBlock.url)
|
|
467
|
+
imageBlock.url = imgBlock.url;
|
|
468
|
+
if (imgBlock.data)
|
|
469
|
+
imageBlock.data = imgBlock.data;
|
|
470
|
+
if (imgBlock.mimeType)
|
|
471
|
+
imageBlock.mimeType = imgBlock.mimeType;
|
|
472
|
+
return imageBlock;
|
|
473
|
+
}
|
|
474
|
+
// Fallback for unknown types - convert to text
|
|
475
|
+
return { type: "text", text: JSON.stringify(block) };
|
|
476
|
+
});
|
|
477
|
+
// Extract text for logging
|
|
349
478
|
const userMessageText = params.prompt
|
|
350
479
|
.filter((p) => p.type === "text")
|
|
351
480
|
.map((p) => p.text)
|
|
@@ -359,7 +488,7 @@ export class AgentAcpAdapter {
|
|
|
359
488
|
if (!this.noSession) {
|
|
360
489
|
const userMessage = {
|
|
361
490
|
role: "user",
|
|
362
|
-
content:
|
|
491
|
+
content: userContentBlocks,
|
|
363
492
|
timestamp: new Date().toISOString(),
|
|
364
493
|
};
|
|
365
494
|
session.messages.push(userMessage);
|
|
@@ -537,10 +666,50 @@ export class AgentAcpAdapter {
|
|
|
537
666
|
if ("sessionUpdate" in msg && msg.sessionUpdate === "tool_call") {
|
|
538
667
|
flushPendingText();
|
|
539
668
|
const toolCallMsg = msg;
|
|
669
|
+
// Extract prettyName, icon, and batchId from _meta
|
|
670
|
+
const prettyName = toolCallMsg._meta &&
|
|
671
|
+
typeof toolCallMsg._meta === "object" &&
|
|
672
|
+
"prettyName" in toolCallMsg._meta
|
|
673
|
+
? String(toolCallMsg._meta.prettyName)
|
|
674
|
+
: undefined;
|
|
675
|
+
const icon = toolCallMsg._meta &&
|
|
676
|
+
typeof toolCallMsg._meta === "object" &&
|
|
677
|
+
"icon" in toolCallMsg._meta
|
|
678
|
+
? String(toolCallMsg._meta.icon)
|
|
679
|
+
: undefined;
|
|
680
|
+
const batchId = toolCallMsg._meta &&
|
|
681
|
+
typeof toolCallMsg._meta === "object" &&
|
|
682
|
+
"batchId" in toolCallMsg._meta
|
|
683
|
+
? String(toolCallMsg._meta.batchId)
|
|
684
|
+
: undefined;
|
|
685
|
+
// Extract subline from _meta, or compute it for todo_write from rawInput
|
|
686
|
+
let subline = toolCallMsg._meta &&
|
|
687
|
+
typeof toolCallMsg._meta === "object" &&
|
|
688
|
+
"subline" in toolCallMsg._meta
|
|
689
|
+
? String(toolCallMsg._meta.subline)
|
|
690
|
+
: undefined;
|
|
691
|
+
// For todo_write, compute subline from in_progress item's activeForm
|
|
692
|
+
if (!subline &&
|
|
693
|
+
toolCallMsg.title === "todo_write" &&
|
|
694
|
+
toolCallMsg.rawInput &&
|
|
695
|
+
"todos" in toolCallMsg.rawInput &&
|
|
696
|
+
Array.isArray(toolCallMsg.rawInput.todos)) {
|
|
697
|
+
const inProgressItem = toolCallMsg.rawInput.todos.find((todo) => todo.status === "in_progress");
|
|
698
|
+
if (inProgressItem &&
|
|
699
|
+
typeof inProgressItem === "object" &&
|
|
700
|
+
"activeForm" in inProgressItem &&
|
|
701
|
+
typeof inProgressItem.activeForm === "string") {
|
|
702
|
+
subline = inProgressItem.activeForm;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
540
705
|
const toolCall = {
|
|
541
706
|
type: "tool_call",
|
|
542
707
|
id: toolCallMsg.toolCallId || `tool_${Date.now()}`,
|
|
708
|
+
...(batchId ? { batchId } : {}),
|
|
543
709
|
title: toolCallMsg.title || "Tool",
|
|
710
|
+
...(prettyName ? { prettyName } : {}),
|
|
711
|
+
...(icon ? { icon } : {}),
|
|
712
|
+
...(subline ? { subline } : {}),
|
|
544
713
|
kind: toolCallMsg.kind || "other",
|
|
545
714
|
status: toolCallMsg.status || "pending",
|
|
546
715
|
startedAt: Date.now(),
|
|
@@ -714,8 +883,35 @@ export class AgentAcpAdapter {
|
|
|
714
883
|
}
|
|
715
884
|
// The agent may emit extended types (like tool_output) that aren't in ACP SDK yet
|
|
716
885
|
// The http transport will handle routing these appropriately
|
|
717
|
-
//
|
|
886
|
+
// Enhance todo_write tool_call with subline showing in-progress item
|
|
718
887
|
let enhancedMsg = msg;
|
|
888
|
+
if ("sessionUpdate" in msg &&
|
|
889
|
+
msg.sessionUpdate === "tool_call" &&
|
|
890
|
+
"title" in msg &&
|
|
891
|
+
msg.title === "todo_write" &&
|
|
892
|
+
"rawInput" in msg &&
|
|
893
|
+
msg.rawInput &&
|
|
894
|
+
typeof msg.rawInput === "object" &&
|
|
895
|
+
"todos" in msg.rawInput &&
|
|
896
|
+
Array.isArray(msg.rawInput.todos)) {
|
|
897
|
+
// Find the in_progress item and extract its activeForm
|
|
898
|
+
const inProgressItem = msg.rawInput.todos.find((todo) => todo.status === "in_progress");
|
|
899
|
+
if (inProgressItem &&
|
|
900
|
+
typeof inProgressItem === "object" &&
|
|
901
|
+
"activeForm" in inProgressItem &&
|
|
902
|
+
typeof inProgressItem.activeForm === "string") {
|
|
903
|
+
enhancedMsg = {
|
|
904
|
+
...msg,
|
|
905
|
+
_meta: {
|
|
906
|
+
...(typeof msg._meta === "object" && msg._meta !== null
|
|
907
|
+
? msg._meta
|
|
908
|
+
: {}),
|
|
909
|
+
subline: inProgressItem.activeForm,
|
|
910
|
+
},
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
// Add context input tokens to messages with token usage metadata
|
|
719
915
|
if (!this.noSession &&
|
|
720
916
|
"_meta" in msg &&
|
|
721
917
|
msg._meta &&
|
|
@@ -824,6 +1020,24 @@ export class AgentAcpAdapter {
|
|
|
824
1020
|
if (this.noSession || !hooks || hooks.length === 0) {
|
|
825
1021
|
return [];
|
|
826
1022
|
}
|
|
1023
|
+
const hookSpan = telemetry.startSpan("adapter.executeHooks", {
|
|
1024
|
+
"hooks.executionPoint": executionPoint,
|
|
1025
|
+
"hooks.count": hooks.length,
|
|
1026
|
+
"session.id": sessionId,
|
|
1027
|
+
});
|
|
1028
|
+
const spanContext = hookSpan
|
|
1029
|
+
? trace.setSpan(context.active(), hookSpan)
|
|
1030
|
+
: context.active();
|
|
1031
|
+
return context.with(spanContext, async () => {
|
|
1032
|
+
try {
|
|
1033
|
+
return await this._executeHooksImpl(session, sessionId, executionPoint, hooks);
|
|
1034
|
+
}
|
|
1035
|
+
finally {
|
|
1036
|
+
telemetry.endSpan(hookSpan);
|
|
1037
|
+
}
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
async _executeHooksImpl(session, sessionId, executionPoint, hooks) {
|
|
827
1041
|
logger.info(`Executing hooks at ${executionPoint}`, {
|
|
828
1042
|
hooksLength: hooks.length,
|
|
829
1043
|
contextEntries: session.context.length,
|
package/dist/acp-server/cli.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
1
|
import type { AgentDefinition } from "../definition";
|
|
2
2
|
import { type AgentRunner } from "../runner";
|
|
3
|
-
export declare function makeStdioTransport(
|
|
4
|
-
agent: AgentRunner | AgentDefinition,
|
|
5
|
-
): void;
|
|
3
|
+
export declare function makeStdioTransport(agent: AgentRunner | AgentDefinition): void;
|
package/dist/acp-server/http.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { join } from "node:path";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
3
|
import { gzipSync } from "node:zlib";
|
|
4
4
|
import * as acp from "@agentclientprotocol/sdk";
|
|
5
5
|
import { PGlite } from "@electric-sql/pglite";
|
|
@@ -264,6 +264,44 @@ export function makeHttpTransport(agent, agentDir, agentName) {
|
|
|
264
264
|
allowMethods: ["GET", "POST", "OPTIONS"],
|
|
265
265
|
}));
|
|
266
266
|
app.get("/health", (c) => c.json({ ok: true }));
|
|
267
|
+
// Serve static files from agent directory (for generated images, etc.)
|
|
268
|
+
if (agentDir) {
|
|
269
|
+
app.get("/static/*", async (c) => {
|
|
270
|
+
const path = c.req.path.replace(/^\/static\//, "");
|
|
271
|
+
const filePath = join(agentDir, path);
|
|
272
|
+
// Security check: ensure the file is within the agent directory
|
|
273
|
+
const normalizedPath = resolve(filePath);
|
|
274
|
+
const normalizedAgentDir = resolve(agentDir);
|
|
275
|
+
if (!normalizedPath.startsWith(normalizedAgentDir)) {
|
|
276
|
+
logger.warn("Attempted to access file outside agent directory", {
|
|
277
|
+
path,
|
|
278
|
+
filePath,
|
|
279
|
+
agentDir,
|
|
280
|
+
});
|
|
281
|
+
return c.json({ error: "Invalid path" }, 403);
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
const file = Bun.file(filePath);
|
|
285
|
+
const exists = await file.exists();
|
|
286
|
+
if (!exists) {
|
|
287
|
+
logger.warn("Static file not found", { path, filePath });
|
|
288
|
+
return c.json({ error: "File not found" }, 404);
|
|
289
|
+
}
|
|
290
|
+
const buffer = await file.arrayBuffer();
|
|
291
|
+
const contentType = file.type || "application/octet-stream";
|
|
292
|
+
return new Response(buffer, {
|
|
293
|
+
headers: {
|
|
294
|
+
"Content-Type": contentType,
|
|
295
|
+
"Cache-Control": "public, max-age=31536000",
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
logger.error("Error serving static file", { error, path, filePath });
|
|
301
|
+
return c.json({ error: "Internal server error" }, 500);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
}
|
|
267
305
|
app.get("/events", (c) => {
|
|
268
306
|
const sessionId = c.req.header("X-Session-ID");
|
|
269
307
|
if (!sessionId) {
|
|
@@ -5,10 +5,25 @@ export interface TextBlock {
|
|
|
5
5
|
type: "text";
|
|
6
6
|
text: string;
|
|
7
7
|
}
|
|
8
|
+
export interface ImageBlock {
|
|
9
|
+
type: "image";
|
|
10
|
+
source?: {
|
|
11
|
+
type: "base64";
|
|
12
|
+
media_type: "image/jpeg" | "image/png" | "image/gif" | "image/webp";
|
|
13
|
+
data: string;
|
|
14
|
+
} | undefined;
|
|
15
|
+
url?: string | undefined;
|
|
16
|
+
data?: string | undefined;
|
|
17
|
+
mimeType?: string | undefined;
|
|
18
|
+
}
|
|
8
19
|
export interface ToolCallBlock {
|
|
9
20
|
type: "tool_call";
|
|
10
21
|
id: string;
|
|
22
|
+
batchId?: string | undefined;
|
|
11
23
|
title: string;
|
|
24
|
+
prettyName?: string | undefined;
|
|
25
|
+
icon?: string | undefined;
|
|
26
|
+
subline?: string | undefined;
|
|
12
27
|
kind: "read" | "edit" | "delete" | "move" | "search" | "execute" | "think" | "fetch" | "switch_mode" | "other";
|
|
13
28
|
status: "pending" | "in_progress" | "completed" | "failed";
|
|
14
29
|
rawInput?: Record<string, unknown> | undefined;
|
|
@@ -23,7 +38,7 @@ export interface ToolCallBlock {
|
|
|
23
38
|
finalTokens?: number;
|
|
24
39
|
};
|
|
25
40
|
}
|
|
26
|
-
export type ContentBlock = TextBlock | ToolCallBlock;
|
|
41
|
+
export type ContentBlock = TextBlock | ImageBlock | ToolCallBlock;
|
|
27
42
|
/**
|
|
28
43
|
* Session message format stored in files
|
|
29
44
|
*/
|
|
@@ -8,10 +8,32 @@ const textBlockSchema = z.object({
|
|
|
8
8
|
type: z.literal("text"),
|
|
9
9
|
text: z.string(),
|
|
10
10
|
});
|
|
11
|
+
const imageBlockSchema = z.object({
|
|
12
|
+
type: z.literal("image"),
|
|
13
|
+
source: z
|
|
14
|
+
.object({
|
|
15
|
+
type: z.literal("base64"),
|
|
16
|
+
media_type: z.enum([
|
|
17
|
+
"image/jpeg",
|
|
18
|
+
"image/png",
|
|
19
|
+
"image/gif",
|
|
20
|
+
"image/webp",
|
|
21
|
+
]),
|
|
22
|
+
data: z.string(),
|
|
23
|
+
})
|
|
24
|
+
.optional(),
|
|
25
|
+
url: z.string().optional(),
|
|
26
|
+
data: z.string().optional(),
|
|
27
|
+
mimeType: z.string().optional(),
|
|
28
|
+
});
|
|
11
29
|
const toolCallBlockSchema = z.object({
|
|
12
30
|
type: z.literal("tool_call"),
|
|
13
31
|
id: z.string(),
|
|
32
|
+
batchId: z.string().optional(),
|
|
14
33
|
title: z.string(),
|
|
34
|
+
prettyName: z.string().optional(),
|
|
35
|
+
icon: z.string().optional(),
|
|
36
|
+
subline: z.string().optional(),
|
|
15
37
|
kind: z.enum([
|
|
16
38
|
"read",
|
|
17
39
|
"edit",
|
|
@@ -33,6 +55,7 @@ const toolCallBlockSchema = z.object({
|
|
|
33
55
|
});
|
|
34
56
|
const contentBlockSchema = z.discriminatedUnion("type", [
|
|
35
57
|
textBlockSchema,
|
|
58
|
+
imageBlockSchema,
|
|
36
59
|
toolCallBlockSchema,
|
|
37
60
|
]);
|
|
38
61
|
const sessionMessageSchema = z.object({
|
package/dist/bin.js
CHANGED
|
File without changes
|
|
@@ -11,7 +11,7 @@ export declare const McpConfigSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
11
11
|
transport: z.ZodLiteral<"http">;
|
|
12
12
|
url: z.ZodString;
|
|
13
13
|
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
14
|
-
}, z.core.$strip
|
|
14
|
+
}, z.core.$strip>, z.ZodString]>;
|
|
15
15
|
/** Hook configuration schema. */
|
|
16
16
|
export declare const HookConfigSchema: z.ZodObject<{
|
|
17
17
|
type: z.ZodEnum<{
|
|
@@ -59,7 +59,7 @@ export declare const AgentDefinitionSchema: z.ZodObject<{
|
|
|
59
59
|
transport: z.ZodLiteral<"http">;
|
|
60
60
|
url: z.ZodString;
|
|
61
61
|
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
62
|
-
}, z.core.$strip
|
|
62
|
+
}, z.core.$strip>, z.ZodString]>>>;
|
|
63
63
|
harnessImplementation: z.ZodOptional<z.ZodLiteral<"langchain">>;
|
|
64
64
|
hooks: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
65
65
|
type: z.ZodEnum<{
|
package/dist/definition/index.js
CHANGED
|
@@ -23,6 +23,7 @@ const McpStreamableHttpConfigSchema = McpBaseConfigSchema.extend({
|
|
|
23
23
|
export const McpConfigSchema = z.union([
|
|
24
24
|
McpStdioConfigSchema,
|
|
25
25
|
McpStreamableHttpConfigSchema,
|
|
26
|
+
z.string(),
|
|
26
27
|
]);
|
|
27
28
|
/** Custom tool configuration schema. */
|
|
28
29
|
const CustomToolSchema = z.object({
|
|
@@ -8,7 +8,7 @@ export declare const zAgentRunnerParams: z.ZodObject<{
|
|
|
8
8
|
suggestedPrompts: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
9
9
|
systemPrompt: z.ZodNullable<z.ZodString>;
|
|
10
10
|
model: z.ZodString;
|
|
11
|
-
tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodLiteral<"todo_write">, z.ZodLiteral<"get_weather">, z.ZodLiteral<"web_search">, z.ZodLiteral<"filesystem">]>, z.ZodObject<{
|
|
11
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodLiteral<"todo_write">, z.ZodLiteral<"get_weather">, z.ZodLiteral<"web_search">, z.ZodLiteral<"filesystem">, z.ZodLiteral<"generate_image">]>, z.ZodObject<{
|
|
12
12
|
type: z.ZodLiteral<"custom">;
|
|
13
13
|
modulePath: z.ZodString;
|
|
14
14
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -22,6 +22,11 @@ export declare const zAgentRunnerParams: z.ZodObject<{
|
|
|
22
22
|
schema: z.ZodAny;
|
|
23
23
|
prettyName: z.ZodOptional<z.ZodString>;
|
|
24
24
|
icon: z.ZodOptional<z.ZodString>;
|
|
25
|
+
subagentConfigs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
26
|
+
agentName: z.ZodString;
|
|
27
|
+
description: z.ZodString;
|
|
28
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
29
|
+
}, z.core.$strip>>>;
|
|
25
30
|
}, z.core.$strip>]>>>;
|
|
26
31
|
mcps: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
27
32
|
name: z.ZodString;
|
|
@@ -33,7 +38,7 @@ export declare const zAgentRunnerParams: z.ZodObject<{
|
|
|
33
38
|
transport: z.ZodLiteral<"http">;
|
|
34
39
|
url: z.ZodString;
|
|
35
40
|
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
36
|
-
}, z.core.$strip
|
|
41
|
+
}, z.core.$strip>, z.ZodString]>>>;
|
|
37
42
|
hooks: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
38
43
|
type: z.ZodEnum<{
|
|
39
44
|
context_size: "context_size";
|
package/dist/runner/index.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import type { AgentDefinition } from "../definition";
|
|
2
2
|
import { type AgentRunner } from "./agent-runner";
|
|
3
3
|
export type { AgentRunner };
|
|
4
|
-
export declare const makeRunnerFromDefinition: (
|
|
5
|
-
definition: AgentDefinition,
|
|
6
|
-
) => AgentRunner;
|
|
4
|
+
export declare const makeRunnerFromDefinition: (definition: AgentDefinition) => AgentRunner;
|