@botbotgo/agent-harness 0.0.313 → 0.0.315

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.
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.312";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.314";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.312";
1
+ export const AGENT_HARNESS_VERSION = "0.0.314";
@@ -1 +1,5 @@
1
1
  export declare function summarizeAssistantText(text: string): string;
2
+ export declare function shouldDirectlyListWorkspaceFiles(input: string | Array<{
3
+ type?: unknown;
4
+ text?: unknown;
5
+ }>): boolean;
@@ -1,3 +1,15 @@
1
+ const DIRECT_LISTING_PATTERNS = [
2
+ /^ls$/iu,
3
+ /^list files$/iu,
4
+ /^list the files$/iu,
5
+ /^list files in (?:the )?(?:current )?directory$/iu,
6
+ /^show files$/iu,
7
+ /^show me the files$/iu,
8
+ /^show the files$/iu,
9
+ /^列出文件$/u,
10
+ /^列出当前目录(?:下)?文件$/u,
11
+ /^查看文件列表$/u,
12
+ ];
1
13
  const GENERIC_ASSISTANT_SUMMARY_MAX_CHARS = 180;
2
14
  const GENERIC_ASSISTANT_SUMMARY_MAX_LINES = 6;
3
15
  function parseListingEntry(line) {
@@ -88,3 +100,26 @@ export function summarizeAssistantText(text) {
88
100
  }
89
101
  return summarizeGenericAssistantResponse(normalized);
90
102
  }
103
+ function extractPlainTextInput(input) {
104
+ if (typeof input === "string") {
105
+ const normalized = input.trim();
106
+ return normalized.length > 0 ? normalized : undefined;
107
+ }
108
+ if (!Array.isArray(input)) {
109
+ return undefined;
110
+ }
111
+ const text = input
112
+ .filter((part) => part?.type === "text" && typeof part.text === "string")
113
+ .map((part) => part.text.trim())
114
+ .filter((part) => part.length > 0)
115
+ .join("\n")
116
+ .trim();
117
+ return text.length > 0 ? text : undefined;
118
+ }
119
+ export function shouldDirectlyListWorkspaceFiles(input) {
120
+ const normalized = extractPlainTextInput(input);
121
+ if (!normalized) {
122
+ return false;
123
+ }
124
+ return DIRECT_LISTING_PATTERNS.some((pattern) => pattern.test(normalized));
125
+ }
@@ -22,6 +22,7 @@ export declare function executeRequestInvocation(options: {
22
22
  state?: Record<string, unknown>;
23
23
  files?: Record<string, unknown>;
24
24
  memoryContext?: string;
25
+ toolRuntimeContext?: Record<string, unknown>;
25
26
  }) => Promise<Map<string, ExecutableTool>>;
26
27
  callRuntimeWithToolParseRecovery: (request: unknown) => Promise<Record<string, unknown>>;
27
28
  }): Promise<RequestResult>;
@@ -34,6 +34,7 @@ export async function executeRequestInvocation(options) {
34
34
  executableTools,
35
35
  builtinExecutableTools: builtinExecutableTools,
36
36
  callRuntimeWithToolParseRecovery: options.callRuntimeWithToolParseRecovery,
37
+ toolRuntimeContext: invokeOptions.toolRuntimeContext,
37
38
  });
38
39
  const result = localOrUpstreamInvocation.result;
39
40
  const executedToolResults = [...localOrUpstreamInvocation.executedToolResults];
@@ -16,6 +16,7 @@ export declare function invokeRuntimeWithLocalTools(options: {
16
16
  executableTools: Map<string, ExecutableTool>;
17
17
  builtinExecutableTools: Map<string, ExecutableTool>;
18
18
  callRuntimeWithToolParseRecovery: (request: unknown) => Promise<Record<string, unknown>>;
19
+ toolRuntimeContext?: Record<string, unknown>;
19
20
  }): Promise<{
20
21
  result: Record<string, unknown>;
21
22
  executedToolResults: ExecutedToolResult[];
@@ -14,5 +14,6 @@ export async function invokeRuntimeWithLocalTools(options) {
14
14
  executableTools: options.executableTools,
15
15
  builtinExecutableTools: options.builtinExecutableTools,
16
16
  callRuntimeWithToolParseRecovery: options.callRuntimeWithToolParseRecovery,
17
+ toolRuntimeContext: options.toolRuntimeContext,
17
18
  });
18
19
  }
@@ -14,10 +14,11 @@ type LocalToolInvocationParams = {
14
14
  executableTools: Map<string, ExecutableTool>;
15
15
  builtinExecutableTools: Map<string, ExecutableTool>;
16
16
  callRuntimeWithToolParseRecovery: (request: unknown) => Promise<Record<string, unknown>>;
17
+ toolRuntimeContext?: Record<string, unknown>;
17
18
  };
18
19
  type LocalToolInvocationResult = {
19
20
  result: Record<string, unknown>;
20
21
  executedToolResults: ExecutedToolResult[];
21
22
  };
22
- export declare function runLocalToolInvocationLoop({ binding, request, primaryTools, toolNameMapping, executableTools, builtinExecutableTools, callRuntimeWithToolParseRecovery, }: LocalToolInvocationParams): Promise<LocalToolInvocationResult>;
23
+ export declare function runLocalToolInvocationLoop({ binding, request, primaryTools, toolNameMapping, executableTools, builtinExecutableTools, callRuntimeWithToolParseRecovery, toolRuntimeContext, }: LocalToolInvocationParams): Promise<LocalToolInvocationResult>;
23
24
  export {};
@@ -3,6 +3,7 @@ import { createModelFacingToolNameLookupCandidates, resolveModelFacingToolName }
3
3
  import { canReplayToolCallsLocally } from "./tool/tool-replay.js";
4
4
  import { extractToolCallsFromResult, normalizeToolArgsForSchema, stringifyToolOutput } from "./tool/tool-arguments.js";
5
5
  import { extractMemoryCandidatesFromToolOutput } from "../harness/system/runtime-memory-candidates.js";
6
+ import { maybePersistLargeToolOutput } from "./tool/tool-output-artifacts.js";
6
7
  const TOOL_FOLLOW_UP_INSTRUCTION = "One or more tool results are already available in this conversation. Answer the user's current request directly from the existing context and tool results. Do not ask the user to repeat inputs that are already present above.";
7
8
  function extractLatestUserInput(request) {
8
9
  const typedRequest = request;
@@ -19,7 +20,7 @@ function extractLatestUserInput(request) {
19
20
  }
20
21
  return undefined;
21
22
  }
22
- export async function runLocalToolInvocationLoop({ binding, request, primaryTools, toolNameMapping, executableTools, builtinExecutableTools, callRuntimeWithToolParseRecovery, }) {
23
+ export async function runLocalToolInvocationLoop({ binding, request, primaryTools, toolNameMapping, executableTools, builtinExecutableTools, callRuntimeWithToolParseRecovery, toolRuntimeContext, }) {
23
24
  const executedToolResults = [];
24
25
  let activeRequest = request;
25
26
  let currentMessages = Array.isArray(activeRequest.messages) ? [...activeRequest.messages] : [];
@@ -74,17 +75,24 @@ export async function runLocalToolInvocationLoop({ binding, request, primaryTool
74
75
  const normalizedArgs = normalizeToolArgsForSchema(toolCall.args, activeExecutable.schema, toolCall.rawArgsInput, {
75
76
  latestUserInput,
76
77
  });
77
- const toolResult = await activeExecutable.invoke(normalizedArgs);
78
+ const toolResult = toolRuntimeContext
79
+ ? await activeExecutable.invoke(normalizedArgs, { toolRuntimeContext })
80
+ : await activeExecutable.invoke(normalizedArgs);
78
81
  const memoryCandidates = compiledTool ? extractMemoryCandidatesFromToolOutput(compiledTool, toolResult) : [];
79
- executedToolResults.push({
82
+ const safeToolResult = await maybePersistLargeToolOutput({
80
83
  toolName: activeExecutable.name,
81
84
  output: toolResult,
85
+ toolRuntimeContext: toolRuntimeContext,
86
+ });
87
+ executedToolResults.push({
88
+ toolName: activeExecutable.name,
89
+ output: safeToolResult,
82
90
  ...(memoryCandidates.length > 0 ? { memoryCandidates } : {}),
83
91
  });
84
92
  nextMessages.push(new ToolMessage({
85
93
  name: activeExecutable.name,
86
94
  tool_call_id: toolCall.id ?? `tool-${iteration + 1}-${toolIndex + 1}`,
87
- content: stringifyToolOutput(toolResult),
95
+ content: stringifyToolOutput(safeToolResult),
88
96
  }));
89
97
  }
90
98
  currentMessages = nextMessages;
@@ -73,16 +73,19 @@ export declare function resolveBuiltinMiddlewareTools(input: {
73
73
  context?: Record<string, unknown>;
74
74
  state?: Record<string, unknown>;
75
75
  files?: Record<string, unknown>;
76
+ toolRuntimeContext?: Record<string, unknown>;
76
77
  };
77
78
  resolveBuiltinMiddlewareBackend: (binding: CompiledAgentBinding, options?: {
78
79
  context?: Record<string, unknown>;
79
80
  state?: Record<string, unknown>;
80
81
  files?: Record<string, unknown>;
82
+ toolRuntimeContext?: Record<string, unknown>;
81
83
  }) => unknown;
82
84
  invokeBuiltinTaskTool: (binding: CompiledAgentBinding, toolInput: unknown, options?: {
83
85
  context?: Record<string, unknown>;
84
86
  state?: Record<string, unknown>;
85
87
  files?: Record<string, unknown>;
88
+ toolRuntimeContext?: Record<string, unknown>;
86
89
  }) => Promise<unknown>;
87
90
  }): Promise<Map<string, ExecutableTool>>;
88
91
  export declare function materializeAutomaticSummarizationMiddleware(input: {
@@ -182,6 +182,7 @@ export async function resolveBuiltinMiddlewareTools(input) {
182
182
  return createBuiltinMiddlewareTools(backend, {
183
183
  includeTaskTool: isDeepAgentBinding(input.binding),
184
184
  workspaceRoot: input.binding.harnessRuntime.workspaceRoot,
185
+ toolRuntimeContext: input.options?.toolRuntimeContext,
185
186
  invokeTaskTool: isDeepAgentBinding(input.binding)
186
187
  ? async (toolInput) => input.invokeBuiltinTaskTool(input.binding, toolInput, input.options)
187
188
  : undefined,
@@ -250,4 +250,5 @@ export declare function createBuiltinMiddlewareTools(backend: BuiltinMiddlewareB
250
250
  includeTaskTool: boolean;
251
251
  invokeTaskTool?: (input: unknown) => Promise<unknown>;
252
252
  workspaceRoot?: string;
253
+ toolRuntimeContext?: Record<string, unknown>;
253
254
  }): Promise<Map<string, BuiltinExecutableTool>>;
@@ -3,6 +3,7 @@ import { z } from "zod";
3
3
  import { isSandboxBackend } from "deepagents";
4
4
  import { isRecord } from "../../../utils/object.js";
5
5
  import { formatBuiltinTodoSnapshot, isLowSignalTodoContent, summarizeBuiltinWriteTodosArgs, truncateLines } from "../runtime-adapter-support.js";
6
+ import { maybePersistLargeToolOutput, resolveToolRuntimeContext } from "./tool-output-artifacts.js";
6
7
  export const BUILTIN_MIDDLEWARE_TOOL_DESCRIPTORS = [
7
8
  { name: "write_todos", description: "Create and update the runtime todo board for multi-step work." },
8
9
  { name: "read_todos", description: "Read the current runtime todo board." },
@@ -159,6 +160,11 @@ export async function createBuiltinMiddlewareTools(backend, options) {
159
160
  blocked: 0,
160
161
  },
161
162
  };
163
+ const finalizeOutput = async (toolName, output, toolConfig) => maybePersistLargeToolOutput({
164
+ toolName,
165
+ output,
166
+ toolRuntimeContext: resolveToolRuntimeContext(toolConfig, options.toolRuntimeContext),
167
+ });
162
168
  tools.set("write_todos", {
163
169
  name: "write_todos",
164
170
  description: "Create and update the runtime todo board for multi-step work.",
@@ -200,11 +206,11 @@ export async function createBuiltinMiddlewareTools(backend, options) {
200
206
  name: "ls",
201
207
  description: "List files in a directory.",
202
208
  schema: z.object({ path: z.string().optional().default("/") }).passthrough(),
203
- invoke: async (input) => {
209
+ invoke: async (input, toolConfig) => {
204
210
  const targetPath = normalizeWorkspacePathOrThrow(pathScopedBackend, isRecord(input) && typeof input.path === "string" ? input.path : "/");
205
211
  const shallowListing = await tryExecuteShallowDirectoryListing(pathScopedBackend, targetPath);
206
212
  if (typeof shallowListing === "string") {
207
- return shallowListing.length > 0 ? shallowListing : `No files found in ${targetPath}`;
213
+ return finalizeOutput("ls", shallowListing.length > 0 ? shallowListing : `No files found in ${targetPath}`, toolConfig);
208
214
  }
209
215
  const legacyInfos = (await Promise.resolve(backend.lsInfo?.(targetPath))) ?? [];
210
216
  const infos = legacyInfos.length > 0
@@ -217,14 +223,14 @@ export async function createBuiltinMiddlewareTools(backend, options) {
217
223
  if (infos.length === 0) {
218
224
  return `No files found in ${targetPath}`;
219
225
  }
220
- return truncateLines(infos.map((info) => info.is_dir ? `${info.path} (directory)` : `${info.path}${info.size ? ` (${info.size} bytes)` : ""}`));
226
+ return finalizeOutput("ls", truncateLines(infos.map((info) => info.is_dir ? `${info.path} (directory)` : `${info.path}${info.size ? ` (${info.size} bytes)` : ""}`)), toolConfig);
221
227
  },
222
228
  });
223
229
  tools.set("list_files", {
224
230
  name: "list_files",
225
231
  description: "List files in a directory.",
226
232
  schema: z.object({ path: z.string().optional().default("/") }).passthrough(),
227
- invoke: async (input) => tools.get("ls").invoke(input),
233
+ invoke: async (input, toolConfig) => tools.get("ls").invoke(input, toolConfig),
228
234
  });
229
235
  tools.set("read_file", {
230
236
  name: "read_file",
@@ -352,7 +358,7 @@ export async function createBuiltinMiddlewareTools(backend, options) {
352
358
  name: "execute",
353
359
  description: "Run a shell command in the workspace sandbox.",
354
360
  schema: z.object({ command: z.string() }).passthrough(),
355
- invoke: async (input) => {
361
+ invoke: async (input, toolConfig) => {
356
362
  if (!isSandboxBackend(backend) || typeof backend.execute !== "function") {
357
363
  return "Error: Execution not available. This agent's backend does not support command execution (SandboxBackendProtocol).";
358
364
  }
@@ -365,29 +371,29 @@ export async function createBuiltinMiddlewareTools(backend, options) {
365
371
  if (result.truncated) {
366
372
  parts.push("\n[Output was truncated due to size limits]");
367
373
  }
368
- return parts.join("");
374
+ return finalizeOutput("execute", parts.join(""), toolConfig);
369
375
  },
370
376
  });
371
377
  tools.set("run_command", {
372
378
  name: "run_command",
373
379
  description: "Run a shell command in the workspace sandbox.",
374
380
  schema: z.object({ command: z.string() }).passthrough(),
375
- invoke: async (input) => tools.get("execute").invoke(input),
381
+ invoke: async (input, toolConfig) => tools.get("execute").invoke(input, toolConfig),
376
382
  });
377
383
  tools.set("fetch_url", {
378
384
  name: "fetch_url",
379
385
  description: "Fetch a URL and return the response body.",
380
386
  schema: z.object({ url: z.string() }).passthrough(),
381
- invoke: async (input) => {
387
+ invoke: async (input, toolConfig) => {
382
388
  if (typeof backend.fetchUrl !== "function") {
383
389
  return notAvailable("fetch_url", "URL fetching");
384
390
  }
385
391
  const typed = isRecord(input) ? input : {};
386
392
  const result = await Promise.resolve(backend.fetchUrl(typeof typed.url === "string" ? typed.url : ""));
387
393
  if (typeof result === "string") {
388
- return result;
394
+ return finalizeOutput("fetch_url", result, toolConfig);
389
395
  }
390
- return formatHttpResponse(result);
396
+ return finalizeOutput("fetch_url", formatHttpResponse(result), toolConfig);
391
397
  },
392
398
  });
393
399
  tools.set("http_request", {
@@ -399,7 +405,7 @@ export async function createBuiltinMiddlewareTools(backend, options) {
399
405
  headers: z.record(z.string(), z.string()).optional(),
400
406
  body: z.string().optional(),
401
407
  }).passthrough(),
402
- invoke: async (input) => {
408
+ invoke: async (input, toolConfig) => {
403
409
  if (typeof backend.httpRequest !== "function") {
404
410
  return notAvailable("http_request", "structured HTTP requests");
405
411
  }
@@ -413,9 +419,9 @@ export async function createBuiltinMiddlewareTools(backend, options) {
413
419
  body: typeof typed.body === "string" ? typed.body : undefined,
414
420
  }));
415
421
  if (typeof result === "string") {
416
- return result;
422
+ return finalizeOutput("http_request", result, toolConfig);
417
423
  }
418
- return formatHttpResponse(result);
424
+ return finalizeOutput("http_request", formatHttpResponse(result), toolConfig);
419
425
  },
420
426
  });
421
427
  tools.set("send_message", {
@@ -0,0 +1,35 @@
1
+ type ArtifactCreateInput = {
2
+ sessionId: string;
3
+ requestId: string;
4
+ kind: string;
5
+ path: string;
6
+ content: unknown;
7
+ artifactId?: string;
8
+ createdAt?: string;
9
+ };
10
+ type ArtifactCreateResult = {
11
+ artifactId: string;
12
+ kind: string;
13
+ path: string;
14
+ createdAt: string;
15
+ };
16
+ type ToolRuntimeContext = {
17
+ runtime?: {
18
+ current?: {
19
+ sessionId?: string;
20
+ requestId?: string;
21
+ };
22
+ artifacts?: {
23
+ create?: (input: ArtifactCreateInput) => Promise<ArtifactCreateResult> | ArtifactCreateResult;
24
+ };
25
+ };
26
+ };
27
+ export declare function resolveToolRuntimeContext(toolConfig?: Record<string, unknown>, fallback?: Record<string, unknown>): ToolRuntimeContext | undefined;
28
+ export declare function maybePersistLargeToolOutput(input: {
29
+ toolName: string;
30
+ output: unknown;
31
+ toolRuntimeContext?: Record<string, unknown>;
32
+ maxInlineChars?: number;
33
+ previewChars?: number;
34
+ }): Promise<unknown>;
35
+ export {};
@@ -0,0 +1,88 @@
1
+ function asRecord(value) {
2
+ return typeof value === "object" && value !== null && !Array.isArray(value)
3
+ ? value
4
+ : undefined;
5
+ }
6
+ function toSerializedToolOutput(output) {
7
+ if (typeof output === "string") {
8
+ return output;
9
+ }
10
+ try {
11
+ return JSON.stringify(output, null, 2);
12
+ }
13
+ catch {
14
+ return String(output);
15
+ }
16
+ }
17
+ function truncatePreview(text, maxChars) {
18
+ if (text.length <= maxChars) {
19
+ return text;
20
+ }
21
+ return `${text.slice(0, Math.max(0, maxChars - 15))}\n...[truncated]`;
22
+ }
23
+ function sanitizeArtifactToolName(toolName) {
24
+ return toolName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "tool";
25
+ }
26
+ export function resolveToolRuntimeContext(toolConfig, fallback) {
27
+ const dynamic = asRecord(toolConfig?.toolRuntimeContext);
28
+ const configurable = asRecord(toolConfig?.configurable);
29
+ const fallbackRuntime = asRecord(asRecord(fallback)?.runtime);
30
+ const fallbackCurrent = asRecord(fallbackRuntime?.current);
31
+ const resolved = (dynamic ?? fallback);
32
+ const runtime = asRecord(resolved?.runtime);
33
+ if (!runtime) {
34
+ return resolved;
35
+ }
36
+ return {
37
+ ...resolved,
38
+ runtime: {
39
+ ...runtime,
40
+ current: {
41
+ ...fallbackCurrent,
42
+ ...asRecord(runtime.current),
43
+ ...(typeof configurable?.thread_id === "string" ? { sessionId: configurable.thread_id } : {}),
44
+ ...(typeof configurable?.request_id === "string" ? { requestId: configurable.request_id } : {}),
45
+ },
46
+ },
47
+ };
48
+ }
49
+ export async function maybePersistLargeToolOutput(input) {
50
+ const maxInlineChars = input.maxInlineChars ?? 12_000;
51
+ const previewChars = input.previewChars ?? 2_000;
52
+ const serialized = toSerializedToolOutput(input.output);
53
+ if (serialized.length <= maxInlineChars) {
54
+ return input.output;
55
+ }
56
+ const runtimeContext = input.toolRuntimeContext;
57
+ const runtime = runtimeContext?.runtime;
58
+ const sessionId = runtime?.current?.sessionId;
59
+ const requestId = runtime?.current?.requestId;
60
+ const createArtifact = runtime?.artifacts?.create;
61
+ const createdAt = new Date().toISOString();
62
+ const safeToolName = sanitizeArtifactToolName(input.toolName);
63
+ let artifact;
64
+ if (typeof createArtifact === "function" && typeof sessionId === "string" && typeof requestId === "string") {
65
+ artifact = await Promise.resolve(createArtifact({
66
+ sessionId,
67
+ requestId,
68
+ kind: "tool-output",
69
+ path: `artifacts/tool-output-${safeToolName}-${Date.now()}.json`,
70
+ createdAt,
71
+ content: {
72
+ toolName: input.toolName,
73
+ createdAt,
74
+ output: input.output,
75
+ },
76
+ }));
77
+ }
78
+ return {
79
+ truncated: true,
80
+ toolName: input.toolName,
81
+ message: artifact
82
+ ? "Full tool output was stored as a request artifact because it exceeded the inline size limit."
83
+ : "Tool output exceeded the inline size limit and was truncated for runtime stability.",
84
+ originalSizeChars: serialized.length,
85
+ preview: truncatePreview(serialized, previewChars),
86
+ ...(artifact ? { artifact } : {}),
87
+ };
88
+ }
@@ -32,6 +32,7 @@ export declare class AgentRuntimeAdapter {
32
32
  private resolveFilesystemRootDir;
33
33
  private resolveBuiltinMiddlewareBackend;
34
34
  private buildFunctionToolRuntimeContext;
35
+ private tryHandleDirectWorkspaceListing;
35
36
  private createDeclaredMiddlewareResolverOptions;
36
37
  private createAssemblyResolvers;
37
38
  private invokeBuiltinTaskTool;
@@ -11,6 +11,7 @@ import { applyToolRecoveryInstruction as applyToolRecoveryInstructionHelper, app
11
11
  import { invokeBuiltinTaskTool as invokeBuiltinTaskToolHelper, materializeAutomaticSummarizationMiddleware as materializeAutomaticSummarizationMiddlewareHelper, resolveBuiltinMiddlewareBackend as resolveBuiltinMiddlewareBackendHelper, resolveBuiltinMiddlewareTools as resolveBuiltinMiddlewareToolsHelper, resolveLangChainRuntimeExtensionMiddleware as resolveLangChainRuntimeExtensionMiddlewareHelper, resolveMiddleware as resolveMiddlewareHelper, resolveSubagents as resolveSubagentsHelper, } from "./adapter/middleware-assembly.js";
12
12
  import { resolveBindingTimeout, resolveStreamIdleTimeout, } from "./adapter/resilience.js";
13
13
  import { createResolvedModel } from "./adapter/model/model-providers.js";
14
+ import { shouldDirectlyListWorkspaceFiles } from "./adapter/direct-builtin-utility.js";
14
15
  import { resolveAdapterTools } from "./adapter/tool-resolution.js";
15
16
  import { resolveRuntimeStreamExecutionContext, } from "./adapter/flow/execution-context.js";
16
17
  import { isRetryableProviderError } from "./adapter/resilience.js";
@@ -173,6 +174,30 @@ export class AgentRuntimeAdapter {
173
174
  },
174
175
  };
175
176
  }
177
+ async tryHandleDirectWorkspaceListing(binding, input, options = {}) {
178
+ if (!shouldDirectlyListWorkspaceFiles(input)) {
179
+ return undefined;
180
+ }
181
+ const builtinTools = await this.resolveBuiltinMiddlewareTools(binding, {
182
+ context: options.context,
183
+ state: options.state,
184
+ files: options.files,
185
+ sessionId: options.sessionId,
186
+ requestId: options.requestId,
187
+ });
188
+ const listTool = builtinTools.get("list_files") ?? builtinTools.get("ls");
189
+ if (!listTool) {
190
+ return undefined;
191
+ }
192
+ const output = await listTool.invoke({ path: "." });
193
+ if (typeof output !== "string" || output.trim().length === 0) {
194
+ return undefined;
195
+ }
196
+ return {
197
+ toolName: listTool.name,
198
+ output,
199
+ };
200
+ }
176
201
  createDeclaredMiddlewareResolverOptions(binding, options = {}) {
177
202
  return {
178
203
  resolveModel: (model) => this.resolveModel(model),
@@ -277,7 +302,12 @@ export class AgentRuntimeAdapter {
277
302
  const resolvedModel = await this.resolveModel(primaryModel);
278
303
  const resolvedTools = this.resolveTools(primaryTools, binding);
279
304
  const builtinMiddlewareTools = materializeModelExposedBuiltinMiddlewareTools({
280
- builtinTools: await this.resolveBuiltinMiddlewareTools(binding, { sessionId: options.sessionId ?? options.legacySessionId }),
305
+ builtinTools: await this.resolveBuiltinMiddlewareTools(binding, {
306
+ sessionId: options.sessionId ?? options.legacySessionId,
307
+ toolRuntimeContext: this.buildFunctionToolRuntimeContext(binding, {
308
+ sessionId: options.sessionId ?? options.legacySessionId,
309
+ }),
310
+ }),
281
311
  explicitToolNames: primaryTools.map((tool) => tool.name),
282
312
  });
283
313
  const resolvedMiddleware = await this.resolveMiddleware(binding, interruptOn, { sessionId: options.sessionId ?? options.legacySessionId });
@@ -305,9 +335,9 @@ export class AgentRuntimeAdapter {
305
335
  if (isLangChainBinding(binding)) {
306
336
  return this.createLangChainRunnable(binding, { sessionId: options.sessionId ?? options.legacySessionId });
307
337
  }
308
- return this.createDeepAgentRunnable(binding);
338
+ return this.createDeepAgentRunnable(binding, { sessionId: options.sessionId ?? options.legacySessionId });
309
339
  }
310
- async createDeepAgentRunnable(binding) {
340
+ async createDeepAgentRunnable(binding, options = {}) {
311
341
  const executionKind = getBindingExecutionKind(binding);
312
342
  const primaryModel = getBindingPrimaryModel(binding);
313
343
  const primaryTools = getBindingPrimaryTools(binding);
@@ -317,7 +347,12 @@ export class AgentRuntimeAdapter {
317
347
  const resolvedModel = await this.resolveModel(primaryModel);
318
348
  const resolvedTools = this.resolveTools(primaryTools, binding);
319
349
  const builtinMiddlewareTools = materializeModelExposedBuiltinMiddlewareTools({
320
- builtinTools: await this.resolveBuiltinMiddlewareTools(binding),
350
+ builtinTools: await this.resolveBuiltinMiddlewareTools(binding, {
351
+ sessionId: options.sessionId ?? options.legacySessionId,
352
+ toolRuntimeContext: this.buildFunctionToolRuntimeContext(binding, {
353
+ sessionId: options.sessionId ?? options.legacySessionId,
354
+ }),
355
+ }),
321
356
  explicitToolNames: primaryTools.map((tool) => tool.name),
322
357
  });
323
358
  const resolvedMiddleware = await this.resolveMiddleware(binding);
@@ -398,6 +433,30 @@ export class AgentRuntimeAdapter {
398
433
  }
399
434
  }
400
435
  async invoke(binding, input, sessionId, requestId, resumePayload, history = [], options = {}) {
436
+ const directListing = await this.tryHandleDirectWorkspaceListing(binding, input, {
437
+ ...options,
438
+ sessionId,
439
+ requestId,
440
+ });
441
+ if (directListing) {
442
+ return {
443
+ sessionId,
444
+ requestId,
445
+ agentId: binding.agent.id,
446
+ state: "completed",
447
+ output: directListing.output,
448
+ finalMessageText: directListing.output,
449
+ metadata: {
450
+ executedToolResults: [{
451
+ toolName: directListing.toolName,
452
+ output: directListing.output,
453
+ }],
454
+ upstreamResult: {
455
+ directUtility: directListing.toolName,
456
+ },
457
+ },
458
+ };
459
+ }
401
460
  const callRuntime = async (activeBinding, activeRequest) => {
402
461
  return this.invokeWithProviderRetry(activeBinding, async () => {
403
462
  const runnable = await this.create(activeBinding, { sessionId });
@@ -444,6 +503,23 @@ export class AgentRuntimeAdapter {
444
503
  }));
445
504
  }
446
505
  async *stream(binding, input, sessionId, history = [], options = {}) {
506
+ const directListing = await this.tryHandleDirectWorkspaceListing(binding, input, {
507
+ ...options,
508
+ sessionId,
509
+ requestId: options.requestId,
510
+ });
511
+ if (directListing) {
512
+ yield {
513
+ kind: "tool-result",
514
+ toolName: directListing.toolName,
515
+ output: directListing.output,
516
+ };
517
+ yield {
518
+ kind: "content",
519
+ content: directListing.output,
520
+ };
521
+ return;
522
+ }
447
523
  const invokeTimeoutMs = resolveBindingTimeout(binding);
448
524
  const streamIdleTimeoutMs = resolveStreamIdleTimeout(binding);
449
525
  const streamDeadlineAt = invokeTimeoutMs ? Date.now() + invokeTimeoutMs : undefined;
@@ -174,6 +174,7 @@ export class AgentHarnessRuntime {
174
174
  artifacts: {
175
175
  list: (sessionId, requestId) => this.listRequestArtifacts(sessionId, requestId),
176
176
  read: (sessionId, requestId, artifactPath) => this.readRequestArtifact(sessionId, requestId, artifactPath),
177
+ create: (artifact) => this.recordArtifact(artifact),
177
178
  },
178
179
  schedules: {
179
180
  manage: (options) => this.manageSchedule(options),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.313",
3
+ "version": "0.0.315",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",