@townco/agent 0.1.118 → 0.1.120
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/http.js +2 -28
- package/dist/runner/e2b-sandbox-manager.d.ts +3 -0
- package/dist/runner/e2b-sandbox-manager.js +48 -19
- package/dist/runner/langchain/tools/artifacts.d.ts +68 -0
- package/dist/runner/langchain/tools/artifacts.js +474 -0
- package/dist/runner/langchain/tools/conversation_search.d.ts +22 -0
- package/dist/runner/langchain/tools/conversation_search.js +137 -0
- package/dist/runner/langchain/tools/e2b.d.ts +3 -3
- package/dist/runner/langchain/tools/e2b.js +37 -21
- package/dist/runner/langchain/tools/generate_image.d.ts +47 -0
- package/dist/runner/langchain/tools/generate_image.js +175 -0
- package/dist/runner/langchain/tools/port-utils.d.ts +8 -0
- package/dist/runner/langchain/tools/port-utils.js +35 -0
- package/dist/runner/langchain/tools/subagent-connections.d.ts +6 -0
- package/dist/runner/langchain/tools/subagent.js +114 -3
- package/dist/templates/index.d.ts +5 -1
- package/dist/templates/index.js +6 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/templates/index.ts +12 -1
package/dist/acp-server/http.js
CHANGED
|
@@ -259,19 +259,7 @@ export function createAcpHttpApp(agent, agentDir, agentName) {
|
|
|
259
259
|
const stream = sseStreams.get(msgSessionId);
|
|
260
260
|
if (stream) {
|
|
261
261
|
try {
|
|
262
|
-
//
|
|
263
|
-
const isSourcesMsg = rawMsg &&
|
|
264
|
-
typeof rawMsg === "object" &&
|
|
265
|
-
"params" in rawMsg &&
|
|
266
|
-
rawMsg.params?.update?.sessionUpdate === "sources";
|
|
267
|
-
if (isSourcesMsg) {
|
|
268
|
-
const sourcesCount = rawMsg.params?.update?.sources?.length;
|
|
269
|
-
logger.info("🔶 SENDING LARGE SOURCES VIA DIRECT SSE", {
|
|
270
|
-
sessionId: msgSessionId,
|
|
271
|
-
sourcesCount,
|
|
272
|
-
compressedSize,
|
|
273
|
-
});
|
|
274
|
-
}
|
|
262
|
+
// Send large messages directly via SSE
|
|
275
263
|
await stream.writeSSE({
|
|
276
264
|
event: "message",
|
|
277
265
|
data: JSON.stringify(rawMsg),
|
|
@@ -811,21 +799,7 @@ export function createAcpHttpApp(agent, agentDir, agentName) {
|
|
|
811
799
|
return;
|
|
812
800
|
}
|
|
813
801
|
}
|
|
814
|
-
|
|
815
|
-
const isSourcesMsg = json &&
|
|
816
|
-
typeof json === "object" &&
|
|
817
|
-
"params" in json &&
|
|
818
|
-
json.params?.update?.sessionUpdate === "sources";
|
|
819
|
-
if (isSourcesMsg) {
|
|
820
|
-
logger.info("🔶 SENDING SOURCES VIA SSE", {
|
|
821
|
-
sessionId,
|
|
822
|
-
channel,
|
|
823
|
-
sourcesCount: json.params?.update?.sources?.length,
|
|
824
|
-
});
|
|
825
|
-
}
|
|
826
|
-
else {
|
|
827
|
-
logger.trace("Sending SSE message", { sessionId, channel });
|
|
828
|
-
}
|
|
802
|
+
logger.trace("Sending SSE message", { sessionId, channel });
|
|
829
803
|
await stream.writeSSE({
|
|
830
804
|
event: "message",
|
|
831
805
|
data: JSON.stringify(json),
|
|
@@ -3,6 +3,9 @@ import type { Sandbox } from "@e2b/code-interpreter";
|
|
|
3
3
|
* Get or create an E2B sandbox for the current session.
|
|
4
4
|
* Sandboxes are session-scoped and reused across tool calls.
|
|
5
5
|
* Attempts to reconnect to persisted sandboxes when resuming sessions.
|
|
6
|
+
*
|
|
7
|
+
* Uses promise caching to prevent race conditions when multiple tools
|
|
8
|
+
* are called in parallel - all concurrent calls will share the same sandbox.
|
|
6
9
|
*/
|
|
7
10
|
export declare function getSessionSandbox(apiKey: string): Promise<Sandbox>;
|
|
8
11
|
/**
|
|
@@ -8,6 +8,8 @@ const sessionSandboxes = new Map();
|
|
|
8
8
|
const sandboxActivity = new Map();
|
|
9
9
|
// Map sessionId -> cleanup timeout handle
|
|
10
10
|
const cleanupTimeouts = new Map();
|
|
11
|
+
// Map sessionId -> Promise<Sandbox> for in-flight creations (prevents race condition)
|
|
12
|
+
const sandboxCreationPromises = new Map();
|
|
11
13
|
// Sandbox timeout in milliseconds (default: 15 minutes)
|
|
12
14
|
const SANDBOX_TIMEOUT_MS = 15 * 60 * 1000;
|
|
13
15
|
/**
|
|
@@ -58,24 +60,10 @@ function getSessionStorage() {
|
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* Attempts to reconnect to persisted sandboxes when resuming sessions.
|
|
63
|
+
* Internal function to create or reconnect to a sandbox for a session.
|
|
64
|
+
* This should only be called from getSessionSandbox() with proper promise tracking.
|
|
64
65
|
*/
|
|
65
|
-
|
|
66
|
-
if (!hasSessionContext()) {
|
|
67
|
-
throw new Error("E2B tools require session context");
|
|
68
|
-
}
|
|
69
|
-
const { sessionId } = getSessionContext();
|
|
70
|
-
// Check for existing in-memory sandbox
|
|
71
|
-
let sandbox = sessionSandboxes.get(sessionId);
|
|
72
|
-
if (sandbox) {
|
|
73
|
-
// Update activity timestamp and reschedule cleanup
|
|
74
|
-
sandboxActivity.set(sessionId, Date.now());
|
|
75
|
-
rescheduleCleanup(sessionId);
|
|
76
|
-
logger.debug("Reusing existing sandbox", { sessionId });
|
|
77
|
-
return sandbox;
|
|
78
|
-
}
|
|
66
|
+
async function createSandboxForSession(sessionId, apiKey) {
|
|
79
67
|
// Try to reconnect to persisted sandbox
|
|
80
68
|
const storage = getSessionStorage();
|
|
81
69
|
const persistedSandboxId = storage?.getSandboxId(sessionId);
|
|
@@ -86,7 +74,9 @@ export async function getSessionSandbox(apiKey) {
|
|
|
86
74
|
});
|
|
87
75
|
try {
|
|
88
76
|
const { Sandbox: SandboxClass } = await import("@e2b/code-interpreter");
|
|
89
|
-
sandbox = await SandboxClass.connect(persistedSandboxId, {
|
|
77
|
+
const sandbox = await SandboxClass.connect(persistedSandboxId, {
|
|
78
|
+
apiKey,
|
|
79
|
+
});
|
|
90
80
|
logger.info("Successfully reconnected to sandbox", {
|
|
91
81
|
sessionId,
|
|
92
82
|
sandboxId: persistedSandboxId,
|
|
@@ -131,7 +121,7 @@ export async function getSessionSandbox(apiKey) {
|
|
|
131
121
|
config.template = templateId;
|
|
132
122
|
logger.info("Using custom E2B template", { templateId });
|
|
133
123
|
}
|
|
134
|
-
sandbox = await SandboxClass.create(config);
|
|
124
|
+
const sandbox = await SandboxClass.create(config);
|
|
135
125
|
logger.info("Created new sandbox", {
|
|
136
126
|
sessionId,
|
|
137
127
|
sandboxId: sandbox.sandboxId,
|
|
@@ -167,6 +157,45 @@ logging.basicConfig(
|
|
|
167
157
|
scheduleCleanup(sessionId);
|
|
168
158
|
return sandbox;
|
|
169
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Get or create an E2B sandbox for the current session.
|
|
162
|
+
* Sandboxes are session-scoped and reused across tool calls.
|
|
163
|
+
* Attempts to reconnect to persisted sandboxes when resuming sessions.
|
|
164
|
+
*
|
|
165
|
+
* Uses promise caching to prevent race conditions when multiple tools
|
|
166
|
+
* are called in parallel - all concurrent calls will share the same sandbox.
|
|
167
|
+
*/
|
|
168
|
+
export async function getSessionSandbox(apiKey) {
|
|
169
|
+
if (!hasSessionContext()) {
|
|
170
|
+
throw new Error("E2B tools require session context");
|
|
171
|
+
}
|
|
172
|
+
const { sessionId } = getSessionContext();
|
|
173
|
+
// Check for existing in-memory sandbox
|
|
174
|
+
const existingSandbox = sessionSandboxes.get(sessionId);
|
|
175
|
+
if (existingSandbox) {
|
|
176
|
+
// Update activity timestamp and reschedule cleanup
|
|
177
|
+
sandboxActivity.set(sessionId, Date.now());
|
|
178
|
+
rescheduleCleanup(sessionId);
|
|
179
|
+
logger.debug("Reusing existing sandbox", { sessionId });
|
|
180
|
+
return existingSandbox;
|
|
181
|
+
}
|
|
182
|
+
// Check for in-flight creation (prevents race condition when tools run in parallel)
|
|
183
|
+
const existingPromise = sandboxCreationPromises.get(sessionId);
|
|
184
|
+
if (existingPromise) {
|
|
185
|
+
logger.debug("Waiting for in-flight sandbox creation", { sessionId });
|
|
186
|
+
return existingPromise;
|
|
187
|
+
}
|
|
188
|
+
// Create new sandbox with promise tracking
|
|
189
|
+
const creationPromise = createSandboxForSession(sessionId, apiKey);
|
|
190
|
+
sandboxCreationPromises.set(sessionId, creationPromise);
|
|
191
|
+
try {
|
|
192
|
+
const sandbox = await creationPromise;
|
|
193
|
+
return sandbox;
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
sandboxCreationPromises.delete(sessionId);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
170
199
|
/**
|
|
171
200
|
* Explicitly destroy a session's sandbox (called on session end).
|
|
172
201
|
* Also clears the persisted sandboxId from storage.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supabase Storage-backed artifacts tool for agent backend
|
|
3
|
+
*
|
|
4
|
+
* Provides file storage capabilities using Supabase Storage with the following operations:
|
|
5
|
+
* - artifacts_cp: Copy files to/from Supabase Storage
|
|
6
|
+
* - artifacts_del: Delete files from Supabase Storage
|
|
7
|
+
* - artifacts_ls: List files in Supabase Storage
|
|
8
|
+
* - artifacts_url: Generate signed URLs
|
|
9
|
+
*
|
|
10
|
+
* Storage keys are scoped by: <deploying_user>/<agent_name>/<session_id>/<file_path>
|
|
11
|
+
*/
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
/**
|
|
14
|
+
* Factory function to create the artifacts tools
|
|
15
|
+
* Returns an array of all four artifact management tools
|
|
16
|
+
*/
|
|
17
|
+
export declare function makeArtifactsTools(): (import("langchain").DynamicStructuredTool<z.ZodObject<{
|
|
18
|
+
session_id: z.ZodOptional<z.ZodString>;
|
|
19
|
+
source: z.ZodString;
|
|
20
|
+
destination: z.ZodString;
|
|
21
|
+
direction: z.ZodEnum<{
|
|
22
|
+
download: "download";
|
|
23
|
+
upload: "upload";
|
|
24
|
+
}>;
|
|
25
|
+
}, z.core.$strip>, {
|
|
26
|
+
session_id: string;
|
|
27
|
+
source: string;
|
|
28
|
+
destination: string;
|
|
29
|
+
direction: "download" | "upload";
|
|
30
|
+
}, {
|
|
31
|
+
session_id?: string | undefined;
|
|
32
|
+
source: string;
|
|
33
|
+
destination: string;
|
|
34
|
+
direction: "download" | "upload";
|
|
35
|
+
}, string> | import("langchain").DynamicStructuredTool<z.ZodObject<{
|
|
36
|
+
session_id: z.ZodOptional<z.ZodString>;
|
|
37
|
+
path: z.ZodString;
|
|
38
|
+
}, z.core.$strip>, {
|
|
39
|
+
session_id: string;
|
|
40
|
+
path: string;
|
|
41
|
+
}, {
|
|
42
|
+
session_id?: string | undefined;
|
|
43
|
+
path: string;
|
|
44
|
+
}, string> | import("langchain").DynamicStructuredTool<z.ZodObject<{
|
|
45
|
+
session_id: z.ZodOptional<z.ZodString>;
|
|
46
|
+
path: z.ZodOptional<z.ZodString>;
|
|
47
|
+
recursive: z.ZodOptional<z.ZodBoolean>;
|
|
48
|
+
}, z.core.$strip>, {
|
|
49
|
+
session_id: string;
|
|
50
|
+
path?: string;
|
|
51
|
+
recursive?: boolean;
|
|
52
|
+
}, {
|
|
53
|
+
session_id?: string | undefined;
|
|
54
|
+
path?: string | undefined;
|
|
55
|
+
recursive?: boolean | undefined;
|
|
56
|
+
}, string> | import("langchain").DynamicStructuredTool<z.ZodObject<{
|
|
57
|
+
session_id: z.ZodOptional<z.ZodString>;
|
|
58
|
+
path: z.ZodString;
|
|
59
|
+
expires_in: z.ZodOptional<z.ZodNumber>;
|
|
60
|
+
}, z.core.$strip>, {
|
|
61
|
+
session_id: string;
|
|
62
|
+
path: string;
|
|
63
|
+
expires_in?: number;
|
|
64
|
+
}, {
|
|
65
|
+
session_id?: string | undefined;
|
|
66
|
+
path: string;
|
|
67
|
+
expires_in?: number | undefined;
|
|
68
|
+
}, string>)[];
|