@townco/agent 0.1.81 → 0.1.83

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.
Files changed (31) hide show
  1. package/dist/acp-server/adapter.js +12 -12
  2. package/dist/acp-server/http.js +1 -1
  3. package/dist/acp-server/session-storage.d.ts +13 -6
  4. package/dist/acp-server/session-storage.js +94 -59
  5. package/dist/runner/agent-runner.d.ts +3 -1
  6. package/dist/runner/hooks/executor.js +1 -1
  7. package/dist/runner/hooks/predefined/compaction-tool.js +31 -8
  8. package/dist/runner/hooks/predefined/tool-response-compactor.js +2 -2
  9. package/dist/runner/langchain/index.d.ts +1 -0
  10. package/dist/runner/langchain/index.js +151 -27
  11. package/dist/runner/langchain/tools/artifacts.d.ts +68 -0
  12. package/dist/runner/langchain/tools/artifacts.js +469 -0
  13. package/dist/runner/langchain/tools/browser.js +15 -3
  14. package/dist/runner/langchain/tools/filesystem.d.ts +8 -4
  15. package/dist/runner/langchain/tools/filesystem.js +118 -82
  16. package/dist/runner/langchain/tools/generate_image.d.ts +19 -0
  17. package/dist/runner/langchain/tools/generate_image.js +54 -14
  18. package/dist/runner/langchain/tools/subagent.js +2 -2
  19. package/dist/runner/langchain/tools/todo.js +3 -0
  20. package/dist/runner/langchain/tools/web_search.js +6 -0
  21. package/dist/runner/session-context.d.ts +40 -0
  22. package/dist/runner/session-context.js +69 -0
  23. package/dist/runner/tools.d.ts +2 -2
  24. package/dist/runner/tools.js +2 -0
  25. package/dist/scaffold/project-scaffold.js +7 -3
  26. package/dist/telemetry/setup.js +1 -1
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/dist/utils/context-size-calculator.d.ts +1 -2
  29. package/dist/utils/context-size-calculator.js +2 -6
  30. package/dist/utils/token-counter.js +2 -2
  31. package/package.json +10 -10
@@ -278,8 +278,10 @@ export class AgentAcpAdapter {
278
278
  return response;
279
279
  }
280
280
  async newSession(params) {
281
- // Generate a unique session ID for this session
282
- const sessionId = Math.random().toString(36).substring(2);
281
+ // Use sessionId from params if provided (HTTP transport injects it),
282
+ // otherwise generate a unique session ID for this session
283
+ const sessionId = params.sessionId ??
284
+ Math.random().toString(36).substring(2);
283
285
  // Extract configOverrides from _meta if provided (Town Hall comparison feature)
284
286
  const configOverrides = params._meta?.configOverrides;
285
287
  const sessionData = {
@@ -602,8 +604,7 @@ export class AgentAcpAdapter {
602
604
  const context_size = calculateContextSize(contextMessages, this.agent.definition.systemPrompt ?? undefined, undefined, // No LLM-reported tokens yet
603
605
  this.currentToolOverheadTokens, // Include tool overhead
604
606
  this.currentMcpOverheadTokens, // Include MCP overhead
605
- getModelContextWindow(this.agent.definition.model), // Model context window for UI
606
- true);
607
+ getModelContextWindow(this.agent.definition.model));
607
608
  const contextSnapshot = createContextSnapshot(session.messages.length - 1, // Exclude the newly added user message (it will be passed separately via prompt)
608
609
  new Date().toISOString(), previousContext, context_size);
609
610
  session.context.push(contextSnapshot);
@@ -620,7 +621,7 @@ export class AgentAcpAdapter {
620
621
  }
621
622
  };
622
623
  // Declare agentResponse and turnTokenUsage outside try block so they're accessible after catch
623
- let agentResponse;
624
+ let _agentResponse;
624
625
  // Track accumulated token usage during the turn
625
626
  const turnTokenUsage = {
626
627
  inputTokens: 0,
@@ -654,8 +655,8 @@ export class AgentAcpAdapter {
654
655
  latestContextEntry: session.context.length > 0 &&
655
656
  session.context[session.context.length - 1]
656
657
  ? {
657
- messageCount: session.context[session.context.length - 1].messages.length,
658
- contextSize: session.context[session.context.length - 1].context_size,
658
+ messageCount: session.context[session.context.length - 1]?.messages.length,
659
+ contextSize: session.context[session.context.length - 1]?.context_size,
659
660
  }
660
661
  : null,
661
662
  });
@@ -663,6 +664,8 @@ export class AgentAcpAdapter {
663
664
  prompt: params.prompt,
664
665
  sessionId: params.sessionId,
665
666
  messageId,
667
+ // Pass agent directory for session-scoped file storage (only if defined)
668
+ ...(this.agentDir ? { agentDir: this.agentDir } : {}),
666
669
  // Pass resolved context messages to agent
667
670
  contextMessages,
668
671
  };
@@ -1155,7 +1158,7 @@ export class AgentAcpAdapter {
1155
1158
  iterResult = await generator.next();
1156
1159
  }
1157
1160
  // Capture the return value (PromptResponse with tokenUsage)
1158
- agentResponse = iterResult.value;
1161
+ _agentResponse = iterResult.value;
1159
1162
  // Flush any remaining pending text
1160
1163
  flushPendingText();
1161
1164
  }
@@ -1215,13 +1218,10 @@ export class AgentAcpAdapter {
1215
1218
  }
1216
1219
  }
1217
1220
  // Calculate context size with LLM-reported tokens from this turn
1218
- // Exclude tool results - they're only sent during the turn they were received,
1219
- // not in subsequent turns (only messages are sent)
1220
1221
  const context_size = calculateContextSize(contextMessages, this.agent.definition.systemPrompt ?? undefined, turnTokenUsage.inputTokens, // Final LLM-reported tokens from this turn
1221
1222
  this.currentToolOverheadTokens, // Include tool overhead
1222
1223
  this.currentMcpOverheadTokens, // Include MCP overhead
1223
- getModelContextWindow(this.agent.definition.model), // Model context window for UI
1224
- true);
1224
+ getModelContextWindow(this.agent.definition.model));
1225
1225
  const contextSnapshot = createContextSnapshot(session.messages.length, new Date().toISOString(), previousContext, context_size);
1226
1226
  session.context.push(contextSnapshot);
1227
1227
  await this.saveSessionToDisk(params.sessionId, session);
@@ -241,7 +241,7 @@ export function makeHttpTransport(agent, agentDir, agentName) {
241
241
  }
242
242
  // Regular session update - send via PubSub
243
243
  const channel = safeChannelName("notifications", msgSessionId);
244
- const { payload, isCompressed, originalSize, compressedSize } = compressIfNeeded(rawMsg);
244
+ const { payload, compressedSize } = compressIfNeeded(rawMsg);
245
245
  if (compressedSize <= 7500) {
246
246
  const escapedPayload = payload.replace(/'/g, "''");
247
247
  try {
@@ -147,7 +147,8 @@ export interface StoredSession {
147
147
  }
148
148
  /**
149
149
  * File-based session storage
150
- * Stores sessions in agents/<agent-name>/.sessions/<session_id>.json
150
+ * Stores sessions in agents/<agent-name>/.sessions/<session_id>/session.json
151
+ * (Legacy: agents/<agent-name>/.sessions/<session_id>.json)
151
152
  */
152
153
  export declare class SessionStorage {
153
154
  private sessionsDir;
@@ -159,13 +160,18 @@ export declare class SessionStorage {
159
160
  */
160
161
  constructor(agentDir: string, agentName: string);
161
162
  /**
162
- * Ensure the .sessions directory exists
163
+ * Ensure the session directory exists
163
164
  */
164
- private ensureSessionsDir;
165
+ private ensureSessionDir;
165
166
  /**
166
167
  * Get the file path for a session
167
168
  */
168
169
  private getSessionPath;
170
+ /**
171
+ * Get the legacy file path for a session (for backwards compatibility)
172
+ * Legacy format: .sessions/<session_id>.json (flat file, not directory)
173
+ */
174
+ private getLegacySessionPath;
169
175
  /**
170
176
  * Save a session to disk
171
177
  * Uses atomic write (write to temp file, then rename)
@@ -177,18 +183,19 @@ export declare class SessionStorage {
177
183
  loadSession(sessionId: string): Promise<StoredSession | null>;
178
184
  /**
179
185
  * Synchronous session loading (for internal use)
186
+ * Checks new location first, falls back to legacy location
180
187
  */
181
188
  private loadSessionSync;
182
189
  /**
183
- * Check if a session exists
190
+ * Check if a session exists (checks both new and legacy locations)
184
191
  */
185
192
  sessionExists(sessionId: string): boolean;
186
193
  /**
187
- * Delete a session
194
+ * Delete a session (deletes entire session directory or legacy file)
188
195
  */
189
196
  deleteSession(sessionId: string): Promise<boolean>;
190
197
  /**
191
- * List all session IDs
198
+ * List all session IDs (checks both new and legacy locations)
192
199
  */
193
200
  listSessions(): Promise<string[]>;
194
201
  /**
@@ -131,7 +131,8 @@ const storedSessionSchema = z.object({
131
131
  });
132
132
  /**
133
133
  * File-based session storage
134
- * Stores sessions in agents/<agent-name>/.sessions/<session_id>.json
134
+ * Stores sessions in agents/<agent-name>/.sessions/<session_id>/session.json
135
+ * (Legacy: agents/<agent-name>/.sessions/<session_id>.json)
135
136
  */
136
137
  export class SessionStorage {
137
138
  sessionsDir;
@@ -146,17 +147,25 @@ export class SessionStorage {
146
147
  this.agentName = agentName;
147
148
  }
148
149
  /**
149
- * Ensure the .sessions directory exists
150
+ * Ensure the session directory exists
150
151
  */
151
- ensureSessionsDir() {
152
- if (!existsSync(this.sessionsDir)) {
153
- mkdirSync(this.sessionsDir, { recursive: true });
152
+ ensureSessionDir(sessionId) {
153
+ const sessionDir = join(this.sessionsDir, sessionId);
154
+ if (!existsSync(sessionDir)) {
155
+ mkdirSync(sessionDir, { recursive: true });
154
156
  }
155
157
  }
156
158
  /**
157
159
  * Get the file path for a session
158
160
  */
159
161
  getSessionPath(sessionId) {
162
+ return join(this.sessionsDir, sessionId, "session.json");
163
+ }
164
+ /**
165
+ * Get the legacy file path for a session (for backwards compatibility)
166
+ * Legacy format: .sessions/<session_id>.json (flat file, not directory)
167
+ */
168
+ getLegacySessionPath(sessionId) {
160
169
  return join(this.sessionsDir, `${sessionId}.json`);
161
170
  }
162
171
  /**
@@ -164,7 +173,7 @@ export class SessionStorage {
164
173
  * Uses atomic write (write to temp file, then rename)
165
174
  */
166
175
  async saveSession(sessionId, messages, context) {
167
- this.ensureSessionsDir();
176
+ this.ensureSessionDir(sessionId);
168
177
  const sessionPath = this.getSessionPath(sessionId);
169
178
  const tempPath = `${sessionPath}.tmp`;
170
179
  const now = new Date().toISOString();
@@ -207,14 +216,24 @@ export class SessionStorage {
207
216
  }
208
217
  /**
209
218
  * Synchronous session loading (for internal use)
219
+ * Checks new location first, falls back to legacy location
210
220
  */
211
221
  loadSessionSync(sessionId) {
212
222
  const sessionPath = this.getSessionPath(sessionId);
223
+ const legacyPath = this.getLegacySessionPath(sessionId);
224
+ // Check new location first
225
+ let actualPath = sessionPath;
213
226
  if (!existsSync(sessionPath)) {
214
- return null;
227
+ // Fall back to legacy location
228
+ if (existsSync(legacyPath)) {
229
+ actualPath = legacyPath;
230
+ }
231
+ else {
232
+ return null;
233
+ }
215
234
  }
216
235
  try {
217
- const content = readFileSync(sessionPath, "utf-8");
236
+ const content = readFileSync(actualPath, "utf-8");
218
237
  const parsed = JSON.parse(content);
219
238
  // Validate with zod
220
239
  const validated = storedSessionSchema.parse(parsed);
@@ -225,39 +244,64 @@ export class SessionStorage {
225
244
  }
226
245
  }
227
246
  /**
228
- * Check if a session exists
247
+ * Check if a session exists (checks both new and legacy locations)
229
248
  */
230
249
  sessionExists(sessionId) {
231
- return existsSync(this.getSessionPath(sessionId));
250
+ return (existsSync(this.getSessionPath(sessionId)) ||
251
+ existsSync(this.getLegacySessionPath(sessionId)));
232
252
  }
233
253
  /**
234
- * Delete a session
254
+ * Delete a session (deletes entire session directory or legacy file)
235
255
  */
236
256
  async deleteSession(sessionId) {
237
- const sessionPath = this.getSessionPath(sessionId);
238
- if (!existsSync(sessionPath)) {
239
- return false;
240
- }
257
+ const sessionDir = join(this.sessionsDir, sessionId);
258
+ const legacyPath = this.getLegacySessionPath(sessionId);
259
+ let deleted = false;
241
260
  try {
242
- unlinkSync(sessionPath);
243
- return true;
261
+ // Delete session directory (.sessions/<sessionId>/)
262
+ if (existsSync(sessionDir)) {
263
+ // Recursively delete the session directory
264
+ const { rmSync } = await import("node:fs");
265
+ rmSync(sessionDir, { recursive: true, force: true });
266
+ deleted = true;
267
+ }
268
+ // Also delete legacy location if it exists (.sessions/<sessionId>.json)
269
+ if (existsSync(legacyPath)) {
270
+ unlinkSync(legacyPath);
271
+ deleted = true;
272
+ }
273
+ return deleted;
244
274
  }
245
275
  catch (error) {
246
276
  throw new Error(`Failed to delete session ${sessionId}: ${error instanceof Error ? error.message : String(error)}`);
247
277
  }
248
278
  }
249
279
  /**
250
- * List all session IDs
280
+ * List all session IDs (checks both new and legacy locations)
251
281
  */
252
282
  async listSessions() {
253
- if (!existsSync(this.sessionsDir)) {
254
- return [];
255
- }
283
+ const sessionIds = new Set();
256
284
  try {
257
- const files = readdirSync(this.sessionsDir);
258
- return files
259
- .filter((file) => file.endsWith(".json") && !file.endsWith(".tmp"))
260
- .map((file) => file.replace(".json", ""));
285
+ // Check .sessions/ directory
286
+ if (existsSync(this.sessionsDir)) {
287
+ const entries = readdirSync(this.sessionsDir, { withFileTypes: true });
288
+ for (const entry of entries) {
289
+ if (entry.isDirectory()) {
290
+ // New format: .sessions/<sessionId>/session.json
291
+ const sessionJsonPath = join(this.sessionsDir, entry.name, "session.json");
292
+ if (existsSync(sessionJsonPath)) {
293
+ sessionIds.add(entry.name);
294
+ }
295
+ }
296
+ else if (entry.isFile() &&
297
+ entry.name.endsWith(".json") &&
298
+ !entry.name.endsWith(".tmp")) {
299
+ // Legacy format: .sessions/<sessionId>.json
300
+ sessionIds.add(entry.name.replace(".json", ""));
301
+ }
302
+ }
303
+ }
304
+ return Array.from(sessionIds);
261
305
  }
262
306
  catch (error) {
263
307
  throw new Error(`Failed to list sessions: ${error instanceof Error ? error.message : String(error)}`);
@@ -271,43 +315,34 @@ export class SessionStorage {
271
315
  * Returns sessions sorted by updatedAt (most recent first)
272
316
  */
273
317
  async listSessionsWithMetadata() {
274
- if (!existsSync(this.sessionsDir)) {
275
- return [];
276
- }
277
- try {
278
- const files = readdirSync(this.sessionsDir);
279
- const sessionFiles = files.filter((file) => file.endsWith(".json") && !file.endsWith(".tmp"));
280
- const sessions = [];
281
- for (const file of sessionFiles) {
282
- const sessionId = file.replace(".json", "");
283
- try {
284
- const session = this.loadSessionSync(sessionId);
285
- if (session) {
286
- // Find the first user message for preview
287
- const firstUserMsg = session.messages.find((m) => m.role === "user");
288
- const firstUserText = firstUserMsg?.content.find((c) => c.type === "text");
289
- const entry = {
290
- sessionId: session.sessionId,
291
- createdAt: session.metadata.createdAt,
292
- updatedAt: session.metadata.updatedAt,
293
- messageCount: session.messages.length,
294
- };
295
- if (firstUserText && "text" in firstUserText) {
296
- entry.firstUserMessage = firstUserText.text.slice(0, 100);
297
- }
298
- sessions.push(entry);
318
+ // Get all session IDs from both locations
319
+ const sessionIds = await this.listSessions();
320
+ const sessions = [];
321
+ for (const sessionId of sessionIds) {
322
+ try {
323
+ const session = this.loadSessionSync(sessionId);
324
+ if (session) {
325
+ // Find the first user message for preview
326
+ const firstUserMsg = session.messages.find((m) => m.role === "user");
327
+ const firstUserText = firstUserMsg?.content.find((c) => c.type === "text");
328
+ const entry = {
329
+ sessionId: session.sessionId,
330
+ createdAt: session.metadata.createdAt,
331
+ updatedAt: session.metadata.updatedAt,
332
+ messageCount: session.messages.length,
333
+ };
334
+ if (firstUserText && "text" in firstUserText) {
335
+ entry.firstUserMessage = firstUserText.text.slice(0, 100);
299
336
  }
300
- }
301
- catch {
302
- // Skip invalid sessions
337
+ sessions.push(entry);
303
338
  }
304
339
  }
305
- // Sort by updatedAt, most recent first
306
- sessions.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
307
- return sessions;
308
- }
309
- catch (error) {
310
- throw new Error(`Failed to list sessions: ${error instanceof Error ? error.message : String(error)}`);
340
+ catch {
341
+ // Skip invalid sessions
342
+ }
311
343
  }
344
+ // Sort by updatedAt, most recent first
345
+ sessions.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
346
+ return sessions;
312
347
  }
313
348
  }
@@ -9,7 +9,7 @@ export declare const zAgentRunnerParams: z.ZodObject<{
9
9
  suggestedPrompts: z.ZodOptional<z.ZodArray<z.ZodString>>;
10
10
  systemPrompt: z.ZodNullable<z.ZodString>;
11
11
  model: z.ZodString;
12
- 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<"town_web_search">, z.ZodLiteral<"filesystem">, z.ZodLiteral<"generate_image">, z.ZodLiteral<"browser">]>, z.ZodObject<{
12
+ tools: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodLiteral<"artifacts">, z.ZodLiteral<"todo_write">, z.ZodLiteral<"get_weather">, z.ZodLiteral<"web_search">, z.ZodLiteral<"town_web_search">, z.ZodLiteral<"filesystem">, z.ZodLiteral<"generate_image">, z.ZodLiteral<"town_generate_image">, z.ZodLiteral<"browser">]>, z.ZodObject<{
13
13
  type: z.ZodLiteral<"custom">;
14
14
  modulePath: z.ZodString;
15
15
  }, z.core.$strip>, z.ZodObject<{
@@ -74,6 +74,8 @@ export interface ConfigOverrides {
74
74
  }
75
75
  export type InvokeRequest = Omit<PromptRequest, "_meta"> & {
76
76
  messageId: string;
77
+ /** Agent directory path for session-scoped file storage */
78
+ agentDir?: string;
77
79
  sessionMeta?: Record<string, unknown>;
78
80
  contextMessages?: SessionMessage[];
79
81
  configOverrides?: ConfigOverrides;
@@ -186,7 +186,7 @@ export class HookExecutor {
186
186
  };
187
187
  const result = await callback(hookContext);
188
188
  // Extract modified output and warnings from metadata
189
- if (result.metadata && result.metadata.modifiedOutput) {
189
+ if (result.metadata?.modifiedOutput) {
190
190
  // Hook took action - emit completed notification
191
191
  const response = { notifications };
192
192
  response.modifiedOutput = result.metadata.modifiedOutput;
@@ -11,7 +11,7 @@ export const compactionTool = async (ctx) => {
11
11
  logger.info("Compaction tool triggered", {
12
12
  currentTokens: ctx.currentTokens,
13
13
  maxTokens: ctx.maxTokens,
14
- percentage: ctx.percentage.toFixed(2) + "%",
14
+ percentage: `${ctx.percentage.toFixed(2)}%`,
15
15
  contextEntries: ctx.session.context.length,
16
16
  totalMessages: ctx.session.messages.length,
17
17
  model: ctx.model,
@@ -24,14 +24,36 @@ export const compactionTool = async (ctx) => {
24
24
  });
25
25
  // Build the conversation history to compact
26
26
  const messagesToCompact = ctx.session.messages;
27
- // Convert session messages to text for context
27
+ // Convert session messages to text for context, including tool calls and results
28
28
  const conversationText = messagesToCompact
29
29
  .map((msg) => {
30
- const textContent = msg.content
31
- .filter((block) => block.type === "text")
32
- .map((block) => block.text)
33
- .join("\n");
34
- return `${msg.role.toUpperCase()}:\n${textContent}`;
30
+ const parts = [];
31
+ for (const block of msg.content) {
32
+ if (block.type === "text") {
33
+ parts.push(block.text);
34
+ }
35
+ else if (block.type === "tool_call") {
36
+ // Include tool call info
37
+ parts.push(`[Tool: ${block.title}]`);
38
+ if (block.rawInput) {
39
+ parts.push(`Input: ${JSON.stringify(block.rawInput, null, 2)}`);
40
+ }
41
+ if (block.rawOutput) {
42
+ // Summarize large outputs to avoid overwhelming the compaction LLM
43
+ const outputStr = JSON.stringify(block.rawOutput);
44
+ if (outputStr.length > 2000) {
45
+ parts.push(`Output: [Large output - ${outputStr.length} chars]`);
46
+ }
47
+ else {
48
+ parts.push(`Output: ${outputStr}`);
49
+ }
50
+ }
51
+ if (block.error) {
52
+ parts.push(`Error: ${block.error}`);
53
+ }
54
+ }
55
+ }
56
+ return `${msg.role.toUpperCase()}:\n${parts.join("\n")}`;
35
57
  })
36
58
  .join("\n\n---\n\n");
37
59
  // Create system prompt for compaction
@@ -85,7 +107,8 @@ Please provide your summary based on the conversation above, following this stru
85
107
  .join("\n")
86
108
  : "Failed to extract summary";
87
109
  // Extract token usage from LLM response
88
- const responseUsage = response.usage_metadata;
110
+ const responseUsage = response
111
+ .usage_metadata;
89
112
  const summaryTokens = responseUsage?.output_tokens ?? 0;
90
113
  const inputTokensUsed = responseUsage?.input_tokens ?? ctx.currentTokens;
91
114
  logger.info("Generated compaction summary", {
@@ -89,7 +89,7 @@ export const toolResponseCompactor = async (ctx) => {
89
89
  // Try more aggressive truncation (70% of target as emergency measure)
90
90
  const emergencySize = Math.floor(targetSize * 0.7);
91
91
  const emergencyTruncated = truncateToolResponse(rawOutput, emergencySize);
92
- let emergencyTokens = countToolResultTokens(emergencyTruncated);
92
+ const emergencyTokens = countToolResultTokens(emergencyTruncated);
93
93
  // Final safety check - if emergency truncation STILL exceeded target, use ultra-conservative fallback
94
94
  if (emergencyTokens > targetSize) {
95
95
  logger.error("Emergency truncation STILL exceeded target - using ultra-conservative fallback", {
@@ -151,7 +151,7 @@ export const toolResponseCompactor = async (ctx) => {
151
151
  .map((msg) => {
152
152
  const text = msg.content
153
153
  .filter((b) => b.type === "text")
154
- .map((b) => b.text)
154
+ .map((b) => (b.type === "text" ? b.text : ""))
155
155
  .join("\n");
156
156
  return `${msg.role}: ${text}`;
157
157
  })
@@ -13,5 +13,6 @@ export declare class LangchainAgent implements AgentRunner {
13
13
  constructor(params: CreateAgentRunnerParams);
14
14
  invoke(req: InvokeRequest): AsyncGenerator<ExtendedSessionUpdate, PromptResponse, undefined>;
15
15
  private invokeInternal;
16
+ private invokeWithContext;
16
17
  }
17
18
  export { makeSubagentsTool } from "./tools/subagent.js";