@botbotgo/agent-harness 0.0.326 → 0.0.328

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 (56) hide show
  1. package/dist/cli/chat-stream.js +33 -27
  2. package/dist/cli/main.js +30 -3
  3. package/dist/contracts/runtime-requests.d.ts +1 -2
  4. package/dist/contracts/runtime-scheduling.d.ts +1 -1
  5. package/dist/flow/flow-graph-upstream.js +3 -7
  6. package/dist/package-version.d.ts +1 -1
  7. package/dist/package-version.js +1 -1
  8. package/dist/projections/request-events.js +0 -1
  9. package/dist/resource/isolation.js +51 -10
  10. package/dist/resources/toolkit.mjs +183 -0
  11. package/dist/resources/tools/cancel_request.mjs +1 -1
  12. package/dist/resources/tools/fetch_url.mjs +1 -1
  13. package/dist/resources/tools/http_request.mjs +1 -1
  14. package/dist/resources/tools/inspect_approvals.mjs +1 -1
  15. package/dist/resources/tools/inspect_artifacts.mjs +1 -1
  16. package/dist/resources/tools/inspect_events.mjs +1 -1
  17. package/dist/resources/tools/inspect_requests.mjs +1 -1
  18. package/dist/resources/tools/inspect_sessions.mjs +1 -1
  19. package/dist/resources/tools/list_files.mjs +1 -1
  20. package/dist/resources/tools/read_artifact.mjs +1 -1
  21. package/dist/resources/tools/request_approval.mjs +1 -1
  22. package/dist/resources/tools/run_command.mjs +1 -1
  23. package/dist/resources/tools/schedule_task.mjs +1 -1
  24. package/dist/resources/tools/search_files.mjs +1 -1
  25. package/dist/resources/tools/send_message.mjs +1 -1
  26. package/dist/runtime/adapter/compat/deepagent-compat.d.ts +0 -9
  27. package/dist/runtime/adapter/compat/deepagent-compat.js +0 -22
  28. package/dist/runtime/adapter/flow/stream-runtime.d.ts +4 -0
  29. package/dist/runtime/adapter/flow/stream-runtime.js +239 -8
  30. package/dist/runtime/adapter/local-tool-invocation.js +53 -0
  31. package/dist/runtime/adapter/middleware-assembly.js +174 -29
  32. package/dist/runtime/adapter/runtime-adapter-support.js +1 -2
  33. package/dist/runtime/adapter/stream-event-projection.d.ts +17 -0
  34. package/dist/runtime/adapter/stream-event-projection.js +217 -4
  35. package/dist/runtime/adapter/tool/builtin-middleware-tools.d.ts +0 -3
  36. package/dist/runtime/adapter/tool/builtin-middleware-tools.js +37 -17
  37. package/dist/runtime/adapter/tool/resolved-tool.js +29 -3
  38. package/dist/runtime/agent-runtime-adapter.d.ts +3 -3
  39. package/dist/runtime/agent-runtime-adapter.js +12 -33
  40. package/dist/runtime/agent-runtime-assembly.d.ts +3 -21
  41. package/dist/runtime/agent-runtime-assembly.js +4 -56
  42. package/dist/runtime/harness/run/inspection.js +21 -5
  43. package/dist/runtime/harness/run/run-operations.js +2 -1
  44. package/dist/runtime/harness/run/stream-run.d.ts +3 -1
  45. package/dist/runtime/harness/run/stream-run.js +206 -30
  46. package/dist/runtime/harness.js +3 -0
  47. package/dist/runtime/parsing/output-content.js +11 -4
  48. package/dist/runtime/parsing/output-recovery.d.ts +3 -0
  49. package/dist/runtime/parsing/output-recovery.js +57 -11
  50. package/dist/runtime/parsing/output-tool-args.d.ts +4 -0
  51. package/dist/runtime/parsing/output-tool-args.js +122 -0
  52. package/dist/runtime/parsing/stream-event-parsing.js +37 -3
  53. package/dist/runtime/support/harness-support.d.ts +1 -0
  54. package/dist/runtime/support/harness-support.js +44 -2
  55. package/dist/tools.js +34 -4
  56. package/package.json +8 -8
@@ -1,3 +1,4 @@
1
+ import { computeIncrementalOutput } from "../runtime/parsing/stream-event-parsing.js";
1
2
  import { countRenderedLines, renderChatRequestRunning, renderChatTextChunk, summarizeChatToolResult } from "./chat-rendering.js";
2
3
  import { buildTerminalRequestSnapshot, buildTodoContinuationSignature, flattenRequestExecutionSteps, renderRequestEventContinuation, renderRequestSnapshotTree, renderRequestTodoContinuation, } from "./request-tree.js";
3
4
  export async function streamChatMessage(input) {
@@ -10,6 +11,7 @@ export async function streamChatMessage(input) {
10
11
  let latestAgentId = input.agentId;
11
12
  let wroteContent = false;
12
13
  let wroteRenderableBlocks = false;
14
+ let renderedAssistantOutput = "";
13
15
  let lastRenderedRequestTreeKey;
14
16
  let lastRenderedRequestTree = "";
15
17
  let lastRenderedRequestTreeLineCount = 0;
@@ -177,28 +179,36 @@ export async function streamChatMessage(input) {
177
179
  suppressRequestTreeRendering = true;
178
180
  clearLiveRequestTree();
179
181
  };
182
+ const writeAssistantOutput = (nextOutput) => {
183
+ const incremental = computeIncrementalOutput(renderedAssistantOutput, nextOutput);
184
+ renderedAssistantOutput = incremental.accumulated;
185
+ if (!incremental.delta) {
186
+ return false;
187
+ }
188
+ if (input.requestEvents) {
189
+ suspendRequestTreeRendering();
190
+ }
191
+ writeChatStdout(renderChatTextChunk(incremental.delta, input.modelInfo));
192
+ wroteContent = true;
193
+ return true;
194
+ };
195
+ const formatAgentProgressLabel = (agentId) => agentId && agentId.trim().length > 0 ? ` agent:${agentId}` : "";
180
196
  const renderContentBlocks = (contentBlocks, agentId) => {
181
197
  latestAgentId = agentId || latestAgentId;
182
- if (!wroteContent) {
183
- const rendered = contentBlocks
184
- .map((block) => {
185
- if (typeof block === "string") {
186
- return block;
187
- }
188
- if (block && typeof block === "object" && "text" in block && typeof block.text === "string") {
189
- return block.text;
190
- }
191
- return "";
192
- })
193
- .filter((block) => block.trim().length > 0)
194
- .join("");
195
- if (rendered) {
196
- if (input.requestEvents) {
197
- suspendRequestTreeRendering();
198
- }
199
- writeChatStdout(renderChatTextChunk(rendered, input.modelInfo));
200
- wroteRenderableBlocks = true;
198
+ const rendered = contentBlocks
199
+ .map((block) => {
200
+ if (typeof block === "string") {
201
+ return block;
202
+ }
203
+ if (block && typeof block === "object" && "text" in block && typeof block.text === "string") {
204
+ return block.text;
201
205
  }
206
+ return "";
207
+ })
208
+ .filter((block) => block.trim().length > 0)
209
+ .join("");
210
+ if (rendered && writeAssistantOutput(rendered)) {
211
+ wroteRenderableBlocks = true;
202
212
  }
203
213
  };
204
214
  const result = await input.client.request({
@@ -253,11 +263,7 @@ export async function streamChatMessage(input) {
253
263
  firstDataAt ??= Date.now();
254
264
  if (delta.type === "output.text.delta") {
255
265
  latestAgentId = delta.agentId || latestAgentId;
256
- if (input.requestEvents) {
257
- suspendRequestTreeRendering();
258
- }
259
- writeChatStdout(renderChatTextChunk(delta.text, input.modelInfo));
260
- wroteContent = true;
266
+ writeAssistantOutput(delta.text);
261
267
  return;
262
268
  }
263
269
  if (delta.type === "output.content-blocks") {
@@ -268,7 +274,7 @@ export async function streamChatMessage(input) {
268
274
  if (delta.type === "tool.result") {
269
275
  latestAgentId = delta.agentId || latestAgentId;
270
276
  if ((input.showToolResults ?? true) && !input.requestEvents) {
271
- writeChatStderr(`\n[${formatPerfClock(Date.now())} +${formatElapsed(Date.now())}] [tool:${delta.toolName}] ${summarizeChatToolResult(delta.output, delta.isError === true)}${delta.isError ? " (error)" : ""}\n`);
277
+ writeChatStderr(`\n[${formatPerfClock(Date.now())} +${formatElapsed(Date.now())}]${formatAgentProgressLabel(delta.agentId)} [tool:${delta.toolName}] ${summarizeChatToolResult(delta.output, delta.isError === true)}${delta.isError ? " (error)" : ""}\n`);
272
278
  }
273
279
  return;
274
280
  }
@@ -277,7 +283,7 @@ export async function streamChatMessage(input) {
277
283
  if (wroteContent || wroteRenderableBlocks) {
278
284
  return;
279
285
  }
280
- const progressLine = `[${formatPerfClock(Date.now())} +${formatElapsed(Date.now())}] ${delta.text}\n`;
286
+ const progressLine = `[${formatPerfClock(Date.now())} +${formatElapsed(Date.now())}]${formatAgentProgressLabel(delta.agentId)} ${delta.text}\n`;
281
287
  if (input.requestEvents && input.liveRequestTree && !suppressRequestTreeRendering && lastRenderedRequestTree) {
282
288
  liveRequestAnnotations.push(progressLine);
283
289
  clearLiveRequestTree();
@@ -317,7 +323,7 @@ export async function streamChatMessage(input) {
317
323
  }
318
324
  }
319
325
  if (!wroteContent && !wroteRenderableBlocks && result.output.trim().length > 0) {
320
- writeChatStdout(renderChatTextChunk(result.output, input.modelInfo));
326
+ writeAssistantOutput(result.output);
321
327
  }
322
328
  if (result.state === "waiting_for_approval") {
323
329
  writeChatStderr(`\nRequest is waiting for approval${result.approvalId ? ` (${result.approvalId})` : ""}.\n`);
package/dist/cli/main.js CHANGED
@@ -24,6 +24,33 @@ import { isTopLevelCliCommand, parseChatOptions, parseInitOptions, parseTopLevel
24
24
  import { resolveCliWorkspaceRoot, validateCliWorkspaceRoot, } from "./workspace.js";
25
25
  export { renderChatBanner, renderChatPromptLine } from "./chat-ui.js";
26
26
  export { probeChatWorkspace, renderChatRuntimeFailure } from "./chat-workspace.js";
27
+ async function stopClientWithTimeout(client, stderr, timeoutMs = 5000) {
28
+ if (!client) {
29
+ return;
30
+ }
31
+ let timeoutHandle;
32
+ try {
33
+ await Promise.race([
34
+ client.stop(),
35
+ new Promise((_, reject) => {
36
+ timeoutHandle = setTimeout(() => {
37
+ reject(new Error(`Timed out after ${timeoutMs}ms while stopping the chat client.`));
38
+ }, timeoutMs);
39
+ }),
40
+ ]);
41
+ }
42
+ catch (error) {
43
+ const message = error instanceof Error ? error.message : String(error);
44
+ if (!/^Timed out after \d+ms while stopping the chat client\.$/.test(message)) {
45
+ stderr(`${message}\n`);
46
+ }
47
+ }
48
+ finally {
49
+ if (timeoutHandle) {
50
+ clearTimeout(timeoutHandle);
51
+ }
52
+ }
53
+ }
27
54
  export { installChatSubprocessExitGuard, isChatServerNoiseLine } from "./process-guards.js";
28
55
  function isObject(value) {
29
56
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -150,7 +177,7 @@ export async function runCli(argv, io = {}, deps = {}) {
150
177
  showToolResults: parsed.requestEvents,
151
178
  showRunningState: false,
152
179
  });
153
- await client.stop();
180
+ await stopClientWithTimeout(client, stderr);
154
181
  restoreWriteListenerGuard?.();
155
182
  restoreEmitterListenerGuard?.();
156
183
  restoreStderrNoiseFilter?.();
@@ -199,7 +226,7 @@ export async function runCli(argv, io = {}, deps = {}) {
199
226
  activeAgentId = interactiveState.activeAgentId;
200
227
  activeSessionId = interactiveState.activeSessionId;
201
228
  latestRequestId = interactiveState.latestRequestId;
202
- await client.stop();
229
+ await stopClientWithTimeout(client, stderr);
203
230
  restoreWriteListenerGuard?.();
204
231
  restoreEmitterListenerGuard?.();
205
232
  restoreStderrNoiseFilter?.();
@@ -214,7 +241,7 @@ export async function runCli(argv, io = {}, deps = {}) {
214
241
  const message = error instanceof Error ? error.message : String(error);
215
242
  stderr(`${message}\n`);
216
243
  if (client) {
217
- await client.stop().catch(() => undefined);
244
+ await stopClientWithTimeout(client, () => undefined);
218
245
  }
219
246
  return 1;
220
247
  }
@@ -49,7 +49,7 @@ export type RequestExecutionStep = {
49
49
  output?: unknown;
50
50
  isError?: boolean;
51
51
  };
52
- export type RequestPlanItemStatus = "pending" | "in_progress" | "completed" | "failed" | "cancelled" | "blocked" | (string & {});
52
+ export type RequestPlanItemStatus = "pending" | "in_progress" | "completed" | "failed" | "cancelled" | (string & {});
53
53
  export type RequestPlanItem = {
54
54
  id?: string;
55
55
  content: string;
@@ -67,7 +67,6 @@ export type RequestPlanSummary = {
67
67
  completed: number;
68
68
  failed: number;
69
69
  cancelled: number;
70
- blocked: number;
71
70
  };
72
71
  export type RequestPlanState = {
73
72
  sessionId: string;
@@ -92,12 +92,12 @@ export type RuntimeAdapterOptions = {
92
92
  storeResolver?: RuntimeStoreResolver;
93
93
  backendResolver?: RuntimeBackendResolver;
94
94
  scheduleManager?: RuntimeScheduleManager;
95
+ bindingResolver?: (agentId: string) => CompiledAgentBinding | undefined;
95
96
  functionToolContextResolver?: (input: {
96
97
  binding?: CompiledAgentBinding;
97
98
  sessionId?: string;
98
99
  requestId?: string;
99
100
  }) => Record<string, unknown> | undefined;
100
- deepAgentUpstreamSubstrateMode?: "full" | "minimal";
101
101
  };
102
102
  export type ToolKindAdapter = {
103
103
  type: string;
@@ -78,13 +78,9 @@ function extractDelegatedAgentId(event) {
78
78
  : asObject(input?.input);
79
79
  const subagentType = typeof input?.subagent_type === "string"
80
80
  ? input.subagent_type
81
- : typeof input?.subagentType === "string"
82
- ? input.subagentType
83
- : typeof nestedInput?.subagent_type === "string"
84
- ? nestedInput.subagent_type
85
- : typeof nestedInput?.subagentType === "string"
86
- ? nestedInput.subagentType
87
- : null;
81
+ : typeof nestedInput?.subagent_type === "string"
82
+ ? nestedInput.subagent_type
83
+ : null;
88
84
  return subagentType && subagentType.trim().length > 0 ? subagentType.trim() : null;
89
85
  }
90
86
  export function convertUpstreamEventsWithAgents(upstreamEvents, initialAgentId) {
@@ -1,2 +1,2 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.325";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.327";
2
2
  export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-22";
@@ -1,2 +1,2 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.325";
1
+ export const AGENT_HARNESS_VERSION = "0.0.327";
2
2
  export const AGENT_HARNESS_RELEASE_DATE = "2026-04-22";
@@ -10,7 +10,6 @@ function createEmptyPlanSummary() {
10
10
  completed: 0,
11
11
  failed: 0,
12
12
  cancelled: 0,
13
- blocked: 0,
14
13
  };
15
14
  }
16
15
  function resolveTodoKey(content, id, index) {
@@ -3,7 +3,7 @@ import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { createHash, randomUUID } from "node:crypto";
5
5
  import { existsSync } from "node:fs";
6
- import { cp, mkdir, readFile, stat, symlink } from "node:fs/promises";
6
+ import { cp, mkdir, readFile, realpath, stat, symlink } from "node:fs/promises";
7
7
  const HARNESS_PACKAGE_NAME = "@botbotgo/agent-harness";
8
8
  const HARNESS_PACKAGE_ROOT = path.resolve(import.meta.dirname, "..", "..");
9
9
  const HARNESS_TOOL_AUTHORING_DEPENDENCIES = [
@@ -32,8 +32,17 @@ function declaredDependencyNames(manifest) {
32
32
  function dependencyLinkPath(isolatedRoot, dependencyName) {
33
33
  return path.join(isolatedRoot, "node_modules", ...dependencyName.split("/"));
34
34
  }
35
- function dependencyPackageRoot(packageJsonPath) {
36
- return path.dirname(packageJsonPath);
35
+ function resourcePackageManifestPath(packageRoot) {
36
+ return path.join(packageRoot, "package.json");
37
+ }
38
+ function hasResourcePackageManifest(packageRoot) {
39
+ return existsSync(resourcePackageManifestPath(packageRoot));
40
+ }
41
+ function hasInstalledNodeModules(packageRoot) {
42
+ return existsSync(path.join(packageRoot, "node_modules"));
43
+ }
44
+ async function dependencyPackageRoot(packageJsonPath) {
45
+ return realpath(path.dirname(packageJsonPath)).catch(() => path.dirname(packageJsonPath));
37
46
  }
38
47
  function declaredDependencySpec(manifest, dependencyName) {
39
48
  return manifest.dependencies?.[dependencyName]
@@ -56,9 +65,9 @@ function resolveDeclaredFileDependency(packageRoot, spec) {
56
65
  if (!existsSync(packageJsonPath)) {
57
66
  return null;
58
67
  }
59
- return dependencyPackageRoot(packageJsonPath);
68
+ return path.dirname(packageJsonPath);
60
69
  }
61
- function resolveDeclaredDependency(packageRoot, manifest, dependencyName) {
70
+ async function resolveDeclaredDependency(packageRoot, manifest, dependencyName) {
62
71
  const localPath = path.join(packageRoot, "node_modules", ...dependencyName.split("/"), "package.json");
63
72
  if (existsSync(localPath)) {
64
73
  return dependencyPackageRoot(localPath);
@@ -66,7 +75,7 @@ function resolveDeclaredDependency(packageRoot, manifest, dependencyName) {
66
75
  const declaredSpec = declaredDependencySpec(manifest, dependencyName);
67
76
  const localFileDependency = declaredSpec ? resolveDeclaredFileDependency(packageRoot, declaredSpec) : null;
68
77
  if (localFileDependency) {
69
- return localFileDependency;
78
+ return realpath(localFileDependency).catch(() => localFileDependency);
70
79
  }
71
80
  try {
72
81
  const requireFromPackage = createRequire(path.join(packageRoot, "package.json"));
@@ -78,7 +87,7 @@ function resolveDeclaredDependency(packageRoot, manifest, dependencyName) {
78
87
  }
79
88
  async function linkDeclaredDependencies(isolatedRoot, packageRoot, manifest) {
80
89
  for (const dependencyName of declaredDependencyNames(manifest)) {
81
- const resolved = resolveDeclaredDependency(packageRoot, manifest, dependencyName);
90
+ const resolved = await resolveDeclaredDependency(packageRoot, manifest, dependencyName);
82
91
  if (!resolved) {
83
92
  continue;
84
93
  }
@@ -95,7 +104,7 @@ async function linkHarnessPackage(isolatedRoot) {
95
104
  await mkdir(path.dirname(targetPath), { recursive: true });
96
105
  await symlink(HARNESS_PACKAGE_ROOT, targetPath, "junction");
97
106
  }
98
- function resolveHarnessOwnedDependency(dependencyName) {
107
+ async function resolveHarnessOwnedDependency(dependencyName) {
99
108
  try {
100
109
  const requireFromHarness = createRequire(path.join(HARNESS_PACKAGE_ROOT, "package.json"));
101
110
  return dependencyPackageRoot(requireFromHarness.resolve(`${dependencyName}/package.json`));
@@ -110,7 +119,7 @@ async function linkHarnessToolAuthoringDependencies(isolatedRoot) {
110
119
  if (existsSync(targetPath)) {
111
120
  continue;
112
121
  }
113
- const resolved = resolveHarnessOwnedDependency(dependencyName);
122
+ const resolved = await resolveHarnessOwnedDependency(dependencyName);
114
123
  if (!resolved) {
115
124
  continue;
116
125
  }
@@ -119,7 +128,7 @@ async function linkHarnessToolAuthoringDependencies(isolatedRoot) {
119
128
  }
120
129
  }
121
130
  async function buildIsolatedResourceRoot(packageRoot) {
122
- const packageJsonPath = path.join(packageRoot, "package.json");
131
+ const packageJsonPath = resourcePackageManifestPath(packageRoot);
123
132
  const manifest = existsSync(packageJsonPath)
124
133
  ? JSON.parse(await readFile(packageJsonPath, "utf8"))
125
134
  : {};
@@ -139,6 +148,35 @@ async function buildIsolatedResourceRoot(packageRoot) {
139
148
  await linkHarnessToolAuthoringDependencies(isolatedRoot);
140
149
  return isolatedRoot;
141
150
  }
151
+ async function readResourcePackageManifest(packageRoot) {
152
+ const packageJsonPath = resourcePackageManifestPath(packageRoot);
153
+ if (!existsSync(packageJsonPath)) {
154
+ return null;
155
+ }
156
+ return JSON.parse(await readFile(packageJsonPath, "utf8"));
157
+ }
158
+ async function validateInstalledResourcePackage(packageRoot) {
159
+ const manifest = await readResourcePackageManifest(packageRoot);
160
+ if (!manifest) {
161
+ return false;
162
+ }
163
+ const dependencyNames = declaredDependencyNames(manifest);
164
+ if (dependencyNames.length === 0) {
165
+ return true;
166
+ }
167
+ const missingDependencies = [];
168
+ for (const dependencyName of dependencyNames) {
169
+ const resolved = await resolveDeclaredDependency(packageRoot, manifest, dependencyName);
170
+ if (!resolved) {
171
+ missingDependencies.push(dependencyName);
172
+ }
173
+ }
174
+ if (missingDependencies.length > 0) {
175
+ const packageLabel = manifest.name ? `${manifest.name} ` : "";
176
+ throw new Error(`Resource package ${packageLabel}at ${packageRoot} is missing installed dependencies: ${missingDependencies.join(", ")}. Run npm install in ${packageRoot}.`);
177
+ }
178
+ return true;
179
+ }
142
180
  async function rebuildIsolatedResourcePackageRoot(packageRoot) {
143
181
  const existingBuild = isolatedResourceRootBuilds.get(packageRoot);
144
182
  if (existingBuild) {
@@ -171,6 +209,9 @@ export async function ensureIsolatedResourcePackageRoot(packageRoot) {
171
209
  return rebuildIsolatedResourcePackageRoot(packageRoot);
172
210
  }
173
211
  export async function resolveIsolatedResourceModulePath(packageRoot, sourcePath) {
212
+ if (hasResourcePackageManifest(packageRoot) && hasInstalledNodeModules(packageRoot) && await validateInstalledResourcePackage(packageRoot)) {
213
+ return sourcePath;
214
+ }
174
215
  const relativeSourcePath = path.relative(packageRoot, sourcePath);
175
216
  let isolatedRoot = await ensureIsolatedResourcePackageRoot(packageRoot);
176
217
  let isolatedSourcePath = path.join(isolatedRoot, relativeSourcePath);
@@ -0,0 +1,183 @@
1
+ export const TOOL_DEFINITION_MARKER = "__agent_harness_tool_definition__";
2
+
3
+ function isZodSchema(value) {
4
+ return typeof value === "object" && value !== null && typeof value.parse === "function";
5
+ }
6
+
7
+ function isParseableSchema(value) {
8
+ return typeof value === "object" && value !== null && typeof value.parse === "function";
9
+ }
10
+
11
+ function getZodLikeTypeName(value) {
12
+ if (typeof value !== "object" || value === null) {
13
+ return undefined;
14
+ }
15
+ if (typeof value.def?.type === "string") {
16
+ return value.def.type;
17
+ }
18
+ if (typeof value._zod?.def?.type === "string") {
19
+ return value._zod.def.type;
20
+ }
21
+ if (typeof value._def?.typeName === "string") {
22
+ return value._def.typeName.replace(/^Zod/, "").toLowerCase();
23
+ }
24
+ return undefined;
25
+ }
26
+
27
+ function getZodLikeObjectShape(value) {
28
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
29
+ return undefined;
30
+ }
31
+ const directShape = typeof value.shape === "function"
32
+ ? value.shape()
33
+ : typeof value._def?.shape === "function"
34
+ ? value._def.shape()
35
+ : value.shape;
36
+ if (typeof directShape === "object" && directShape !== null && !Array.isArray(directShape)) {
37
+ return directShape;
38
+ }
39
+ const zod4Shape = typeof value._zod?.def?.shape === "function" ? value._zod.def.shape() : value._zod?.def?.shape;
40
+ if (typeof zod4Shape === "object" && zod4Shape !== null && !Array.isArray(zod4Shape)) {
41
+ return zod4Shape;
42
+ }
43
+ return undefined;
44
+ }
45
+
46
+ function getZodLikeInnerSchema(value) {
47
+ if (typeof value !== "object" || value === null) {
48
+ return undefined;
49
+ }
50
+ return value.def?.innerType
51
+ ?? value.def?.element
52
+ ?? value.def?.valueType
53
+ ?? value.def?.schema
54
+ ?? value.def?.out
55
+ ?? value.def?.in
56
+ ?? value._zod?.def?.innerType
57
+ ?? value._zod?.def?.element
58
+ ?? value._zod?.def?.valueType
59
+ ?? value._def?.innerType
60
+ ?? value._def?.schema
61
+ ?? value._def?.type
62
+ ?? value._def?.valueType
63
+ ?? value._def?.in
64
+ ?? value._def?.out;
65
+ }
66
+
67
+ function isEffectWrappedOptional(value) {
68
+ const typeName = getZodLikeTypeName(value);
69
+ if (typeName !== "effects" && typeName !== "pipeline" && typeName !== "pipe" && typeName !== "transform") {
70
+ return false;
71
+ }
72
+ const inner = getZodLikeInnerSchema(value);
73
+ const innerTypeName = getZodLikeTypeName(inner);
74
+ return innerTypeName === "optional" || innerTypeName === "default" || innerTypeName === "catch";
75
+ }
76
+
77
+ function buildJsonSchemaFromZodLike(value) {
78
+ const shape = getZodLikeObjectShape(value);
79
+ if (shape) {
80
+ const properties = Object.fromEntries(
81
+ Object.entries(shape).map(([key, entry]) => [key, buildJsonSchemaFromZodLike(getZodLikeInnerSchema(entry) ?? entry) ?? {}]),
82
+ );
83
+ const required = Object.entries(shape)
84
+ .filter(([, entry]) => {
85
+ const typeName = getZodLikeTypeName(entry);
86
+ return typeName !== "optional" && typeName !== "default" && typeName !== "catch" && !isEffectWrappedOptional(entry);
87
+ })
88
+ .map(([key]) => key);
89
+ return {
90
+ type: "object",
91
+ properties,
92
+ ...(required.length > 0 ? { required } : {}),
93
+ };
94
+ }
95
+ const typeName = getZodLikeTypeName(value);
96
+ switch (typeName) {
97
+ case "string":
98
+ return { type: "string" };
99
+ case "number":
100
+ return { type: "number" };
101
+ case "int":
102
+ case "integer":
103
+ return { type: "integer" };
104
+ case "boolean":
105
+ return { type: "boolean" };
106
+ case "unknown":
107
+ case "any":
108
+ return {};
109
+ case "array":
110
+ return {
111
+ type: "array",
112
+ items: buildJsonSchemaFromZodLike(getZodLikeInnerSchema(value)) ?? {},
113
+ };
114
+ case "record":
115
+ return {
116
+ type: "object",
117
+ additionalProperties: buildJsonSchemaFromZodLike(getZodLikeInnerSchema(value)) ?? {},
118
+ };
119
+ case "optional":
120
+ case "nullable":
121
+ case "default":
122
+ case "catch":
123
+ case "effects":
124
+ case "pipeline":
125
+ case "pipe":
126
+ case "transform":
127
+ return buildJsonSchemaFromZodLike(getZodLikeInnerSchema(value)) ?? {};
128
+ default:
129
+ return undefined;
130
+ }
131
+ }
132
+
133
+ export function buildToolJsonSchema(schema) {
134
+ if (!schema) {
135
+ return undefined;
136
+ }
137
+ if (isZodSchema(schema)) {
138
+ return buildJsonSchemaFromZodLike(schema);
139
+ }
140
+ return {
141
+ type: "object",
142
+ properties: Object.fromEntries(Object.entries(schema).map(([key, value]) => [key, buildJsonSchemaFromZodLike(value) ?? {}])),
143
+ required: Object.entries(schema)
144
+ .filter(([, value]) => {
145
+ const typeName = getZodLikeTypeName(value);
146
+ return typeName !== "optional" && typeName !== "default" && typeName !== "catch" && !isEffectWrappedOptional(value);
147
+ })
148
+ .map(([key]) => key),
149
+ };
150
+ }
151
+
152
+ export function normalizeToolSchema(schema) {
153
+ if (isZodSchema(schema)) {
154
+ return schema;
155
+ }
156
+ const rawShape = schema;
157
+ return {
158
+ shape: rawShape,
159
+ parse(input) {
160
+ const source = typeof input === "object" && input !== null && !Array.isArray(input) ? input : {};
161
+ const parsed = {};
162
+ for (const [key, validator] of Object.entries(rawShape)) {
163
+ if (!isParseableSchema(validator)) {
164
+ throw new TypeError(`Tool schema field '${key}' is not parseable.`);
165
+ }
166
+ const hasValue = Object.prototype.hasOwnProperty.call(source, key);
167
+ const value = hasValue ? source[key] : undefined;
168
+ const parsedValue = validator.parse(value);
169
+ if (parsedValue !== undefined) {
170
+ parsed[key] = parsedValue;
171
+ }
172
+ }
173
+ return parsed;
174
+ },
175
+ };
176
+ }
177
+
178
+ export function tool(definition) {
179
+ return {
180
+ ...definition,
181
+ [TOOL_DEFINITION_MARKER]: true,
182
+ };
183
+ }
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, getRuntimeApi, notAvailable, optionalString } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const cancel_request = tool({
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, formatHttpResponse, getBackend, maybePersistLargeToolOutput, optionalString } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const fetch_url = tool({
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, formatHttpResponse, getBackend, maybePersistLargeToolOutput, optionalString, optionalStringRecord } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const http_request = tool({
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, getRuntimeApi, notAvailable, optionalString } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const inspect_approvals = tool({
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, getCurrentRequestIdentity, getRuntimeApi, notAvailable, optionalString } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const inspect_artifacts = tool({
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, getCurrentRequestIdentity, getRuntimeApi, notAvailable, optionalString } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const inspect_events = tool({
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, getRuntimeApi, notAvailable, optionalString } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const inspect_requests = tool({
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, getRuntimeApi, notAvailable, optionalString } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const inspect_sessions = tool({
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, formatListEntries, getBackend, normalizeWorkspacePath, optionalString, tryExecuteShallowDirectoryListing } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const list_files = tool({
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, getCurrentRequestIdentity, getRuntimeApi, notAvailable, optionalString, requiredString } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const read_artifact = tool({
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, getBackend, notAvailable, optionalObject, optionalString } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const request_approval = tool({
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, getBackend, notAvailable, optionalString } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const run_command = tool({
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, getBackend, getRuntimeApi, notAvailable, optionalObject, optionalString } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  function parseScheduleWhen(value) {
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import {
3
3
  defineSchema,
4
4
  formatGrepResult,
@@ -1,4 +1,4 @@
1
- import { tool } from "@botbotgo/agent-harness/tools";
1
+ import { tool } from "../toolkit.mjs";
2
2
  import { defineSchema, getBackend, notAvailable, optionalObject, optionalString } from "./_runtime_tool_helpers.mjs";
3
3
 
4
4
  export const send_message = tool({