@botbotgo/agent-harness 0.0.338 → 0.0.341

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 (32) hide show
  1. package/dist/contracts/workspace.d.ts +10 -0
  2. package/dist/package-version.d.ts +2 -2
  3. package/dist/package-version.js +2 -2
  4. package/dist/runtime/adapter/flow/execution-context.js +3 -2
  5. package/dist/runtime/adapter/flow/stream-runtime.d.ts +6 -0
  6. package/dist/runtime/adapter/flow/stream-runtime.js +54 -15
  7. package/dist/runtime/adapter/invocation-result.js +111 -9
  8. package/dist/runtime/adapter/local-tool-invocation.js +21 -1
  9. package/dist/runtime/adapter/middleware/context-hygiene.d.ts +5 -0
  10. package/dist/runtime/adapter/middleware/context-hygiene.js +83 -0
  11. package/dist/runtime/adapter/middleware-assembly.d.ts +11 -0
  12. package/dist/runtime/adapter/middleware-assembly.js +154 -178
  13. package/dist/runtime/adapter/model/invocation-request.js +39 -1
  14. package/dist/runtime/adapter/runtime-adapter-support.js +33 -3
  15. package/dist/runtime/adapter/stream-event-projection.js +6 -5
  16. package/dist/runtime/adapter/tool/builtin-middleware-tools.d.ts +7 -0
  17. package/dist/runtime/adapter/tool/builtin-middleware-tools.js +31 -24
  18. package/dist/runtime/agent-runtime-adapter.d.ts +3 -2
  19. package/dist/runtime/agent-runtime-adapter.js +128 -9
  20. package/dist/runtime/agent-runtime-assembly.d.ts +1 -0
  21. package/dist/runtime/agent-runtime-assembly.js +10 -2
  22. package/dist/runtime/harness/run/inspection.js +4 -5
  23. package/dist/runtime/harness/run/stream-run.js +180 -50
  24. package/dist/runtime/parsing/output-parsing.d.ts +1 -1
  25. package/dist/runtime/parsing/output-parsing.js +1 -1
  26. package/dist/runtime/parsing/output-recovery.d.ts +9 -0
  27. package/dist/runtime/parsing/output-recovery.js +46 -1
  28. package/dist/runtime/support/compiled-binding.d.ts +5 -0
  29. package/dist/runtime/support/compiled-binding.js +12 -0
  30. package/dist/workspace/agent-binding-compiler.js +8 -0
  31. package/dist/workspace/object-loader.js +6 -0
  32. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import type { CompiledAgentBinding, MessageContent, RequestResult, RuntimeAdapterOptions, TranscriptMessage } from "../contracts/types.js";
2
2
  import { type RuntimeStreamChunk } from "./parsing/stream-event-parsing.js";
3
- import { AGENT_INTERRUPT_SENTINEL_PREFIX, buildDeepAgentCreateParams, buildLangChainCreateParams, materializeModelExposedBuiltinMiddlewareTools, resolveLangChainInvocationConfig, resolveRunnableCheckpointer, resolveRunnableInterruptOn } from "./agent-runtime-assembly.js";
3
+ import { AGENT_INTERRUPT_SENTINEL_PREFIX, buildDeepAgentCreateParams, buildLangChainCreateParams, DEFAULT_DEEPAGENT_RECURSION_LIMIT, materializeModelExposedBuiltinMiddlewareTools, resolveLangChainInvocationConfig, resolveRunnableCheckpointer, resolveRunnableInterruptOn } from "./agent-runtime-assembly.js";
4
4
  import { RuntimeOperationTimeoutError } from "./adapter/runtime-shell.js";
5
5
  export { materializeDeepAgentSkillSourcePaths, resolveDeepAgentSkillSourcePaths, relativizeDeepAgentSkillSourcePaths, } from "./adapter/compat/deepagent-compat.js";
6
6
  export { buildAuthOmittingFetch, normalizeOpenAICompatibleInit } from "./adapter/compat/openai-compatible.js";
@@ -45,6 +45,7 @@ export declare class AgentRuntimeAdapter {
45
45
  private createLangChainRunnable;
46
46
  private createRunnable;
47
47
  private createDeepAgentRunnable;
48
+ private createConfigurableDeepAgentRunnable;
48
49
  private buildRunnableCacheKey;
49
50
  create(binding: CompiledAgentBinding, options?: {
50
51
  sessionId?: string;
@@ -66,4 +67,4 @@ export declare class AgentRuntimeAdapter {
66
67
  toolRuntimeContext?: Record<string, unknown>;
67
68
  }): AsyncGenerator<RuntimeStreamChunk | string>;
68
69
  }
69
- export { AgentRuntimeAdapter as RuntimeAdapter, AGENT_INTERRUPT_SENTINEL_PREFIX, AGENT_INTERRUPT_SENTINEL_PREFIX as INTERRUPT_SENTINEL_PREFIX, buildDeepAgentCreateParams, buildLangChainCreateParams, materializeModelExposedBuiltinMiddlewareTools, resolveLangChainInvocationConfig, resolveRunnableCheckpointer, resolveRunnableInterruptOn, RuntimeOperationTimeoutError, };
70
+ export { AgentRuntimeAdapter as RuntimeAdapter, AGENT_INTERRUPT_SENTINEL_PREFIX, AGENT_INTERRUPT_SENTINEL_PREFIX as INTERRUPT_SENTINEL_PREFIX, buildDeepAgentCreateParams, buildLangChainCreateParams, DEFAULT_DEEPAGENT_RECURSION_LIMIT, materializeModelExposedBuiltinMiddlewareTools, resolveLangChainInvocationConfig, resolveRunnableCheckpointer, resolveRunnableInterruptOn, RuntimeOperationTimeoutError, };
@@ -1,25 +1,29 @@
1
1
  import path from "node:path";
2
- import { createDeepAgent, FilesystemBackend, } from "deepagents";
3
- import { createAgent } from "langchain";
2
+ import { GENERAL_PURPOSE_SUBAGENT, createAsyncSubAgentMiddleware, createDeepAgent, createFilesystemMiddleware, createMemoryMiddleware, createPatchToolCallsMiddleware, createSkillsMiddleware, createSummarizationMiddleware, createSubAgentMiddleware, FilesystemBackend, StateBackend, } from "deepagents";
3
+ import { createAgent, humanInTheLoopMiddleware, todoListMiddleware } from "langchain";
4
4
  import { wrapResolvedModel, } from "./parsing/output-parsing.js";
5
- import { AGENT_INTERRUPT_SENTINEL_PREFIX, buildDeepAgentCreateParams, buildLangChainCreateParams, materializeModelExposedBuiltinMiddlewareTools, resolveLangChainInvocationConfig, resolveRunnableCheckpointer, resolveRunnableInterruptOn, shouldAttachDeepAgentBackend, shouldAttachDeepAgentCheckpointer, shouldAttachDeepAgentStore, } from "./agent-runtime-assembly.js";
5
+ import { AGENT_INTERRUPT_SENTINEL_PREFIX, buildDeepAgentCreateParams, buildLangChainCreateParams, DEFAULT_DEEPAGENT_RECURSION_LIMIT, materializeModelExposedBuiltinMiddlewareTools, resolveLangChainInvocationConfig, resolveRunnableCheckpointer, resolveRunnableInterruptOn, shouldAttachDeepAgentBackend, shouldAttachDeepAgentCheckpointer, shouldAttachDeepAgentStore, } from "./agent-runtime-assembly.js";
6
6
  import { resolveDeepAgentSkillSourcePaths, } from "./adapter/compat/deepagent-compat.js";
7
7
  import { buildToolNameMapping, } from "./adapter/tool/tool-name-mapping.js";
8
8
  import { executeRequestInvocation } from "./adapter/flow/invocation-flow.js";
9
9
  import { streamRuntimeExecution } from "./adapter/flow/stream-runtime.js";
10
10
  import { applyToolRecoveryInstruction as applyToolRecoveryInstructionHelper, applyStrictToolJsonInstruction as applyStrictToolJsonInstructionHelper, callRuntimeWithToolParseRecovery as callRuntimeWithToolParseRecoveryHelper, createModelFallbackRunnable as createModelFallbackRunnableHelper, invokeWithProviderRetry as invokeWithProviderRetryHelper, iterateWithTimeout as iterateWithTimeoutHelper, materializeModelStream as materializeModelStreamHelper, RuntimeOperationTimeoutError, withRuntimeTimeout, } from "./adapter/runtime-shell.js";
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";
11
+ import { extractSubagentRequestText, invokeBuiltinTaskTool as invokeBuiltinTaskToolHelper, materializeAutomaticSummarizationMiddleware as materializeAutomaticSummarizationMiddlewareHelper, resolveBuiltinMiddlewareBackend as resolveBuiltinMiddlewareBackendHelper, resolveBuiltinMiddlewareTools as resolveBuiltinMiddlewareToolsHelper, resolveLangChainRuntimeExtensionMiddleware as resolveLangChainRuntimeExtensionMiddlewareHelper, resolveMiddleware as resolveMiddlewareHelper, resolveSubagents as resolveSubagentsHelper, wrapRequestResultAsSubagentResponse, } 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
14
  import { renderDirectWorkspaceListing, shouldDirectlyListWorkspaceFiles } from "./adapter/direct-builtin-utility.js";
15
15
  import { resolveAdapterTools } from "./adapter/tool-resolution.js";
16
16
  import { resolveRuntimeStreamExecutionContext, } from "./adapter/flow/execution-context.js";
17
17
  import { isRetryableProviderError } from "./adapter/resilience.js";
18
+ import { UPSTREAM_REQUEST_CONFIG_KEY, UPSTREAM_SESSION_CONFIG_KEY } from "./adapter/upstream-configurable-keys.js";
18
19
  export { materializeDeepAgentSkillSourcePaths, resolveDeepAgentSkillSourcePaths, relativizeDeepAgentSkillSourcePaths, } from "./adapter/compat/deepagent-compat.js";
19
20
  export { buildAuthOmittingFetch, normalizeOpenAICompatibleInit } from "./adapter/compat/openai-compatible.js";
20
21
  export { buildToolNameMapping, createModelFacingToolNameCandidates, createModelFacingToolNameLookupCandidates, resolveModelFacingToolName, sanitizeToolNameForModel, } from "./adapter/tool/tool-name-mapping.js";
21
22
  export { computeRemainingTimeoutMs, isRetryableProviderError, resolveBindingTimeout, resolveProviderRetryPolicy, resolveStreamIdleTimeout, resolveTimeoutMs, } from "./adapter/resilience.js";
22
- import { getBindingAdapterKind, getBindingDeepAgentSubagents, getBindingExecutionKind, getBindingFilesystemConfig, getBindingPrimaryModel, getBindingSkills, getBindingToolCount, getBindingPrimaryTools, getBindingSystemPrompt, isDeepAgentBinding, isLangChainBinding, } from "./support/compiled-binding.js";
23
+ import { getBindingAdapterKind, getBindingBuiltinToolsConfig, getBindingDeepAgentSubagents, getBindingExecutionParams, getBindingExecutionKind, getBindingFilesystemConfig, getBindingMemorySources, getBindingPrimaryModel, getBindingSkills, getBindingToolCount, getBindingPrimaryTools, getBindingSystemPrompt, isDeepAgentBinding, isLangChainBinding, } from "./support/compiled-binding.js";
24
+ function shouldUseConfigurableDeepAgentAssembly(binding) {
25
+ return getBindingBuiltinToolsConfig(binding) !== undefined;
26
+ }
23
27
  export class AgentRuntimeAdapter {
24
28
  options;
25
29
  modelCache = new Map();
@@ -279,13 +283,64 @@ export class AgentRuntimeAdapter {
279
283
  resolveModel: assembly.resolveModel,
280
284
  resolveTools: assembly.resolveTools,
281
285
  createDeclaredMiddlewareResolverOptions: assembly.createDeclaredMiddlewareResolverOptions,
286
+ resolveBackend: (currentBinding) => {
287
+ const targetBinding = currentBinding ?? binding;
288
+ return targetBinding ? this.options.backendResolver?.(targetBinding) : undefined;
289
+ },
282
290
  });
283
291
  }
284
- async resolveDeepAgentSubagents(subagents, binding) {
292
+ async resolveDeepAgentSubagents(subagents, binding, options = {}) {
285
293
  const syncSubagents = subagents.filter((subagent) => !("graphId" in subagent));
286
294
  const asyncSubagents = subagents.filter((subagent) => "graphId" in subagent);
287
295
  const resolvedSyncSubagents = await this.resolveSubagents(syncSubagents, binding);
288
- return [...resolvedSyncSubagents, ...asyncSubagents];
296
+ const wrappedSyncSubagents = await Promise.all(resolvedSyncSubagents.map(async (resolvedSubagent, index) => {
297
+ const compiledSubagent = syncSubagents[index];
298
+ const targetAgentId = compiledSubagent?.agentId;
299
+ const targetBinding = targetAgentId ? this.options.bindingResolver?.(targetAgentId) : undefined;
300
+ if (!targetBinding) {
301
+ return resolvedSubagent;
302
+ }
303
+ const wrapper = {
304
+ name: resolvedSubagent.name,
305
+ description: resolvedSubagent.description,
306
+ systemPrompt: resolvedSubagent.systemPrompt,
307
+ runnable: {
308
+ invoke: async (state, config) => {
309
+ const requestText = extractSubagentRequestText(state);
310
+ const configurable = typeof config?.configurable === "object" && config.configurable
311
+ ? config.configurable
312
+ : {};
313
+ const sessionId = typeof configurable[UPSTREAM_SESSION_CONFIG_KEY] === "string"
314
+ ? configurable[UPSTREAM_SESSION_CONFIG_KEY]
315
+ : options.sessionId ?? `${binding?.agent.id ?? "agent"}:${resolvedSubagent.name}`;
316
+ const requestId = typeof configurable[UPSTREAM_REQUEST_CONFIG_KEY] === "string"
317
+ ? configurable[UPSTREAM_REQUEST_CONFIG_KEY]
318
+ : sessionId;
319
+ const childSessionId = `${sessionId}:delegated:${resolvedSubagent.name}`;
320
+ const childRequestId = `${requestId}:delegated:${resolvedSubagent.name}:${Date.now().toString(36)}`;
321
+ try {
322
+ const result = await this.invoke(targetBinding, requestText, childSessionId, childRequestId, undefined, [], {
323
+ ...(typeof config?.context === "object" && config.context ? { context: config.context } : {}),
324
+ });
325
+ return wrapRequestResultAsSubagentResponse({
326
+ output: result.output,
327
+ structuredResponse: result.structuredResponse,
328
+ });
329
+ }
330
+ catch (error) {
331
+ const message = error instanceof Error && error.message.trim().length > 0
332
+ ? error.message.trim()
333
+ : "delegated execution failed";
334
+ return wrapRequestResultAsSubagentResponse({
335
+ output: `Blocked: ${message}`,
336
+ });
337
+ }
338
+ },
339
+ },
340
+ };
341
+ return wrapper;
342
+ }));
343
+ return [...wrappedSyncSubagents, ...asyncSubagents];
289
344
  }
290
345
  async createLangChainRunnable(binding, options = {}) {
291
346
  const executionKind = getBindingExecutionKind(binding);
@@ -352,7 +407,7 @@ export class AgentRuntimeAdapter {
352
407
  explicitToolNames: primaryTools.map((tool) => tool.name),
353
408
  });
354
409
  const resolvedMiddleware = await this.resolveMiddleware(binding);
355
- const resolvedSubagents = await this.resolveDeepAgentSubagents(getBindingDeepAgentSubagents(binding), binding);
410
+ const resolvedSubagents = await this.resolveDeepAgentSubagents(getBindingDeepAgentSubagents(binding), binding, { sessionId: options.sessionId ?? options.legacySessionId });
356
411
  const resolvedInterruptOn = resolveRunnableInterruptOn(binding);
357
412
  const resolvedCheckpointer = shouldAttachDeepAgentCheckpointer(binding, resolvedInterruptOn)
358
413
  ? resolveRunnableCheckpointer(this.options, binding)
@@ -377,8 +432,66 @@ export class AgentRuntimeAdapter {
377
432
  resolvedInterruptOn,
378
433
  resolvedSkills,
379
434
  });
435
+ if (shouldUseConfigurableDeepAgentAssembly(binding)) {
436
+ return this.createConfigurableDeepAgentRunnable(binding, {
437
+ resolvedModel,
438
+ resolvedTools: [...resolvedTools, ...builtinMiddlewareTools],
439
+ resolvedMiddleware,
440
+ resolvedSubagents,
441
+ resolvedInterruptOn,
442
+ resolvedBackend,
443
+ resolvedSkills,
444
+ });
445
+ }
380
446
  return createDeepAgent(deepAgentConfig);
381
447
  }
448
+ createConfigurableDeepAgentRunnable(binding, input) {
449
+ const builtinTools = getBindingBuiltinToolsConfig(binding) ?? {};
450
+ const backend = (input.resolvedBackend ?? new StateBackend({}));
451
+ const inlineSubagents = input.resolvedSubagents.filter((subagent) => !("graphId" in subagent));
452
+ const asyncSubagents = input.resolvedSubagents.filter((subagent) => "graphId" in subagent);
453
+ const subagents = inlineSubagents.some((subagent) => subagent.name === GENERAL_PURPOSE_SUBAGENT.name)
454
+ ? inlineSubagents
455
+ : [{
456
+ ...GENERAL_PURPOSE_SUBAGENT,
457
+ model: input.resolvedModel,
458
+ tools: input.resolvedTools,
459
+ skills: input.resolvedSkills,
460
+ }, ...inlineSubagents];
461
+ const middleware = [
462
+ ...(builtinTools.todos === false ? [] : [todoListMiddleware()]),
463
+ ...(input.resolvedSkills.length > 0 ? [createSkillsMiddleware({ backend, sources: input.resolvedSkills })] : []),
464
+ ...(builtinTools.filesystem === false ? [] : [createFilesystemMiddleware({ backend })]),
465
+ createSubAgentMiddleware({
466
+ defaultModel: input.resolvedModel,
467
+ defaultTools: input.resolvedTools,
468
+ defaultInterruptOn: input.resolvedInterruptOn,
469
+ subagents: subagents,
470
+ generalPurposeAgent: false,
471
+ }),
472
+ createSummarizationMiddleware({
473
+ model: input.resolvedModel,
474
+ backend,
475
+ }),
476
+ createPatchToolCallsMiddleware(),
477
+ ...(asyncSubagents.length > 0 ? [createAsyncSubAgentMiddleware({ asyncSubAgents: asyncSubagents })] : []),
478
+ ...input.resolvedMiddleware,
479
+ ...(getBindingMemorySources(binding).length > 0 ? [createMemoryMiddleware({ backend, sources: getBindingMemorySources(binding) })] : []),
480
+ ...(input.resolvedInterruptOn ? [humanInTheLoopMiddleware({ interruptOn: input.resolvedInterruptOn })] : []),
481
+ ];
482
+ const executionParams = getBindingExecutionParams(binding);
483
+ const responseFormat = getBindingExecutionKind(binding) === "deepagent"
484
+ ? (executionParams && "responseFormat" in executionParams ? executionParams.responseFormat : undefined)
485
+ : undefined;
486
+ return createAgent({
487
+ model: input.resolvedModel,
488
+ systemPrompt: getBindingSystemPrompt(binding),
489
+ tools: input.resolvedTools,
490
+ middleware: middleware,
491
+ name: binding.agent.id,
492
+ ...(responseFormat !== undefined ? { responseFormat: responseFormat } : {}),
493
+ });
494
+ }
382
495
  buildRunnableCacheKey(binding, sessionId) {
383
496
  const filesystemConfig = getBindingFilesystemConfig(binding);
384
497
  const sessionStorage = typeof filesystemConfig?.sessionStorage === "object" && filesystemConfig.sessionStorage
@@ -522,6 +635,12 @@ export class AgentRuntimeAdapter {
522
635
  canUseDirectModelStream,
523
636
  langChainStreamModel,
524
637
  createRunnable: () => this.create(binding, { sessionId }),
638
+ resolveInvocationConfig: (activeBinding, configOptions) => resolveLangChainInvocationConfig(activeBinding, {
639
+ sessionId: configOptions.sessionId,
640
+ requestId: configOptions.requestId,
641
+ ...(configOptions.context ? { context: configOptions.context } : {}),
642
+ ...(configOptions.toolRuntimeContext ? { toolRuntimeContext: configOptions.toolRuntimeContext } : {}),
643
+ }),
525
644
  withTimeout: (producer, timeoutMs, operation, stage) => this.withTimeout(producer, timeoutMs, operation, stage),
526
645
  iterateWithTimeout: (iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs) => this.iterateWithTimeout(iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs),
527
646
  invokeTimeoutMs,
@@ -541,4 +660,4 @@ export class AgentRuntimeAdapter {
541
660
  });
542
661
  }
543
662
  }
544
- export { AgentRuntimeAdapter as RuntimeAdapter, AGENT_INTERRUPT_SENTINEL_PREFIX, AGENT_INTERRUPT_SENTINEL_PREFIX as INTERRUPT_SENTINEL_PREFIX, buildDeepAgentCreateParams, buildLangChainCreateParams, materializeModelExposedBuiltinMiddlewareTools, resolveLangChainInvocationConfig, resolveRunnableCheckpointer, resolveRunnableInterruptOn, RuntimeOperationTimeoutError, };
663
+ export { AgentRuntimeAdapter as RuntimeAdapter, AGENT_INTERRUPT_SENTINEL_PREFIX, AGENT_INTERRUPT_SENTINEL_PREFIX as INTERRUPT_SENTINEL_PREFIX, buildDeepAgentCreateParams, buildLangChainCreateParams, DEFAULT_DEEPAGENT_RECURSION_LIMIT, materializeModelExposedBuiltinMiddlewareTools, resolveLangChainInvocationConfig, resolveRunnableCheckpointer, resolveRunnableInterruptOn, RuntimeOperationTimeoutError, };
@@ -2,6 +2,7 @@ import type { CompiledAgentBinding, CompiledAsyncSubAgent, RuntimeAdapterOptions
2
2
  import type { ExecutableTool } from "./adapter/flow/invoke-runtime.js";
3
3
  import type { UpstreamSubagentConfig } from "./adapter/middleware-assembly.js";
4
4
  export declare const AGENT_INTERRUPT_SENTINEL_PREFIX = "__agent_harness_interrupt__:";
5
+ export declare const DEFAULT_DEEPAGENT_RECURSION_LIMIT = 100;
5
6
  export declare function materializeModelExposedBuiltinMiddlewareTools(input: {
6
7
  builtinTools: Map<string, ExecutableTool>;
7
8
  explicitToolNames?: string[];
@@ -4,6 +4,7 @@ import { asStructuredExecutableTool } from "./adapter/tool/resolved-tool.js";
4
4
  import { compileInterruptOn } from "./adapter/tool/interrupt-policy.js";
5
5
  import { getBindingBackendConfig, getBindingExecutionKind, getBindingExecutionParams, getBindingInterruptCompatibilityRules, getBindingMemorySources, getBindingMiddlewareConfigs, getBindingPrimaryTools, getBindingSkills, getBindingStoreConfig, } from "./support/compiled-binding.js";
6
6
  export const AGENT_INTERRUPT_SENTINEL_PREFIX = "__agent_harness_interrupt__:";
7
+ export const DEFAULT_DEEPAGENT_RECURSION_LIMIT = 100;
7
8
  const BUILTIN_MIDDLEWARE_ALIAS_TOOL_NAMES = new Set([
8
9
  "list_files",
9
10
  "search_files",
@@ -88,8 +89,12 @@ export function buildLangChainCreateParams(input) {
88
89
  };
89
90
  }
90
91
  export function resolveLangChainInvocationConfig(binding, options) {
91
- const langchainPassthrough = typeof binding.harnessRuntime.langchain?.passthrough === "object" && binding.harnessRuntime.langchain?.passthrough
92
- ? binding.harnessRuntime.langchain.passthrough
92
+ const executionKind = getBindingExecutionKind(binding) ?? binding.agent.executionMode;
93
+ const runtimePassthrough = executionKind === "deepagent"
94
+ ? binding.harnessRuntime.deepagent?.passthrough
95
+ : binding.harnessRuntime.langchain?.passthrough;
96
+ const langchainPassthrough = typeof runtimePassthrough === "object" && runtimePassthrough
97
+ ? runtimePassthrough
93
98
  : undefined;
94
99
  const config = {
95
100
  configurable: {
@@ -100,6 +105,9 @@ export function resolveLangChainInvocationConfig(binding, options) {
100
105
  if (typeof langchainPassthrough?.recursionLimit === "number") {
101
106
  config.recursionLimit = langchainPassthrough.recursionLimit;
102
107
  }
108
+ else if (executionKind === "deepagent") {
109
+ config.recursionLimit = DEFAULT_DEEPAGENT_RECURSION_LIMIT;
110
+ }
103
111
  if (options.context) {
104
112
  config.context = options.context;
105
113
  }
@@ -1,9 +1,9 @@
1
1
  import { readSkillMetadata } from "../../skills/skill-metadata.js";
2
2
  import { createUpstreamTimelineReducer } from "../../../projections/upstream-events.js";
3
3
  import { formatAgentName } from "../../../utils/agent-display.js";
4
- import { getBindingMemorySources, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSkills, getBindingSubagents, isDeepAgentBinding, } from "../../support/compiled-binding.js";
4
+ import { getBindingBuiltinToolsConfig, getBindingMemorySources, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSkills, getBindingSubagents, isDeepAgentBinding, } from "../../support/compiled-binding.js";
5
5
  import { buildRuntimeGovernanceBundles } from "./governance.js";
6
- import { BUILTIN_MIDDLEWARE_TOOL_DESCRIPTORS } from "../../adapter/tool/builtin-middleware-tools.js";
6
+ import { filterBuiltinMiddlewareToolDescriptors } from "../../adapter/tool/builtin-middleware-tools.js";
7
7
  import { buildSurfaceId, resolveSurfaceAction, resolveSurfaceDisplayName, } from "./surface-semantics.js";
8
8
  function asObject(value) {
9
9
  return typeof value === "object" && value !== null ? value : null;
@@ -109,9 +109,8 @@ export function buildRequestRuntimeSnapshot(binding, options) {
109
109
  const tools = isDeepAgentBinding(binding)
110
110
  ? [
111
111
  ...declaredTools,
112
- ...BUILTIN_MIDDLEWARE_TOOL_DESCRIPTORS
113
- .filter((descriptor) => !declaredTools.some((tool) => tool.name === descriptor.name))
114
- .map((descriptor) => ({ ...descriptor })),
112
+ ...filterBuiltinMiddlewareToolDescriptors(getBindingBuiltinToolsConfig(binding))
113
+ .filter((descriptor) => !declaredTools.some((tool) => tool.name === descriptor.name)),
115
114
  ]
116
115
  : declaredTools;
117
116
  return {
@@ -43,7 +43,7 @@ function readTerminalStructuredStatus(value) {
43
43
  return readTerminalStructuredStatus(JSON.parse(value));
44
44
  }
45
45
  catch {
46
- return null;
46
+ return /^\s*Status:\s*completed\b/im.test(value) ? "completed" : null;
47
47
  }
48
48
  }
49
49
  if (typeof value !== "object" || value === null) {
@@ -54,9 +54,20 @@ function readTerminalStructuredStatus(value) {
54
54
  return typed.status;
55
55
  }
56
56
  return (readTerminalStructuredStatus(typed.structuredResponse)
57
+ ?? readTerminalStructuredStatus(typed.content)
57
58
  ?? readTerminalStructuredStatus(typed.output)
58
59
  ?? readTerminalStructuredStatus(typed.data));
59
60
  }
61
+ function isSubstantiveTerminalAssistantOutput(value) {
62
+ const normalized = sanitizeVisibleText(value).trim();
63
+ if (normalized.length < 80) {
64
+ return false;
65
+ }
66
+ if (/\b(?:delegated|waiting|wait for|initiated)\b/i.test(normalized) && !/\b(?:finding|summary|root cause|evidence|completed|result|issue)\b/i.test(normalized)) {
67
+ return false;
68
+ }
69
+ return true;
70
+ }
60
71
  function reconcilePlanStateToTerminalStatus(planState, status, updatedAt) {
61
72
  const items = planState.items.map((item) => ({
62
73
  ...item,
@@ -134,6 +145,57 @@ function buildPlanStateSignature(planState) {
134
145
  summary: planState.summary,
135
146
  });
136
147
  }
148
+ function recomputePlanSummary(items) {
149
+ return {
150
+ total: items.length,
151
+ pending: items.filter((item) => item.status === "pending").length,
152
+ inProgress: items.filter((item) => item.status === "in_progress").length,
153
+ completed: items.filter((item) => item.status === "completed").length,
154
+ failed: items.filter((item) => item.status === "failed").length,
155
+ cancelled: items.filter((item) => item.status === "cancelled").length,
156
+ };
157
+ }
158
+ function normalizePlanItemKey(item) {
159
+ return typeof item.id === "string" && item.id.trim().length > 0
160
+ ? `id:${item.id.trim()}`
161
+ : `content:${item.content.trim().toLowerCase()}`;
162
+ }
163
+ function mergePartialPlanState(currentPlanState, incomingPlanState) {
164
+ if (!currentPlanState || incomingPlanState.items.length >= currentPlanState.items.length) {
165
+ return incomingPlanState;
166
+ }
167
+ const currentByKey = new Map(currentPlanState.items.map((item, index) => [normalizePlanItemKey(item), { item, index }]));
168
+ const incomingByKey = new Map();
169
+ for (const incomingItem of incomingPlanState.items) {
170
+ const key = normalizePlanItemKey(incomingItem);
171
+ if (!currentByKey.has(key)) {
172
+ const currentStructuredIds = countStructuredTodoIds(currentPlanState.items);
173
+ const incomingStructuredIds = countStructuredTodoIds(incomingPlanState.items);
174
+ if (currentStructuredIds > 0 && incomingStructuredIds === 0) {
175
+ return currentPlanState;
176
+ }
177
+ const mergedItems = currentPlanState.items.map((item, index) => {
178
+ const incomingByIndex = incomingPlanState.items[index];
179
+ return incomingByIndex ? { ...item, status: incomingByIndex.status } : item;
180
+ });
181
+ return {
182
+ ...incomingPlanState,
183
+ items: mergedItems,
184
+ summary: recomputePlanSummary(mergedItems),
185
+ };
186
+ }
187
+ incomingByKey.set(key, incomingItem);
188
+ }
189
+ const mergedItems = currentPlanState.items.map((item) => {
190
+ const incomingItem = incomingByKey.get(normalizePlanItemKey(item));
191
+ return incomingItem ? { ...item, ...incomingItem } : item;
192
+ });
193
+ return {
194
+ ...incomingPlanState,
195
+ items: mergedItems,
196
+ summary: recomputePlanSummary(mergedItems),
197
+ };
198
+ }
137
199
  function countStructuredTodoIds(items) {
138
200
  return items.filter((item) => typeof item.id === "string" && item.id.length > 0).length;
139
201
  }
@@ -283,16 +345,23 @@ function summarizePlanState(planState) {
283
345
  if (planState.summary.total <= 0) {
284
346
  return null;
285
347
  }
286
- const counts = [
287
- planState.summary.inProgress > 0 ? `${planState.summary.inProgress} in progress` : "",
288
- planState.summary.pending > 0 ? `${planState.summary.pending} pending` : "",
289
- planState.summary.completed > 0 ? `${planState.summary.completed} completed` : "",
290
- planState.summary.failed > 0 ? `${planState.summary.failed} failed` : "",
291
- ].filter((value) => value.length > 0);
292
- if (counts.length === 0) {
293
- counts.push(`${planState.summary.total} total`);
294
- }
295
- return `Plan updated: ${counts.join(", ")}.`;
348
+ const statusMarker = (status) => {
349
+ switch (status) {
350
+ case "completed":
351
+ return "[x]";
352
+ case "in_progress":
353
+ return "[~]";
354
+ case "failed":
355
+ return "[!]";
356
+ case "cancelled":
357
+ return "[-]";
358
+ default:
359
+ return "[ ]";
360
+ }
361
+ };
362
+ const items = planState.items.slice(0, 6).map((item) => `${statusMarker(item.status)} ${item.content}`);
363
+ const suffix = planState.items.length > items.length ? ` | +${planState.items.length - items.length} more` : "";
364
+ return `TODO: ${items.join(" | ")}${suffix}`;
296
365
  }
297
366
  function createSurfaceCommentary(surfaceItem) {
298
367
  const name = normalizeCommentaryText(surfaceItem.name);
@@ -446,6 +515,10 @@ export async function* streamHarnessRun(options) {
446
515
  let delegationChain = [options.selectedAgentId];
447
516
  let upstreamEventOrdinal = 0;
448
517
  let syntheticFallback;
518
+ const toolErrors = [];
519
+ let sawSuccessfulToolResult = false;
520
+ let lastToolResultKey = null;
521
+ const executedToolResults = [];
449
522
  const emittedCommentary = new Set();
450
523
  const emitCommentary = function* (content) {
451
524
  const normalized = normalizeCommentaryText(content);
@@ -467,10 +540,6 @@ export async function* streamHarnessRun(options) {
467
540
  options.releaseRequestSlotPromise,
468
541
  ]).then(([loadedPriorHistory, resolvedReleaseRunSlot]) => [loadedPriorHistory, resolvedReleaseRunSlot]);
469
542
  releaseRunSlot = acquiredReleaseRunSlot;
470
- const toolErrors = [];
471
- let sawSuccessfulToolResult = false;
472
- let lastToolResultKey = null;
473
- const executedToolResults = [];
474
543
  const recalledMemories = options.invocation.memoryRecall?.items ?? [];
475
544
  for (const item of createRuntimeMemoryRecallSteps(options.sessionId, options.requestId, recalledMemories)) {
476
545
  yield item;
@@ -502,32 +571,16 @@ export async function* streamHarnessRun(options) {
502
571
  updatedAt: new Date().toISOString(),
503
572
  });
504
573
  if (upstreamPlanState) {
505
- const signature = buildPlanStateSignature(upstreamPlanState);
506
- if (signature !== lastPlanStateSignature && shouldEmitPlanState(currentPlanState, upstreamPlanState)) {
507
- planStateVersion = upstreamPlanState.version;
508
- lastPlanStateSignature = signature;
509
- currentPlanState = upstreamPlanState;
510
- for (const item of await emitPlanStateUpdate(options, currentAgentId, upstreamPlanState)) {
511
- yield item;
512
- }
513
- const commentary = summarizePlanState(upstreamPlanState);
514
- if (commentary) {
515
- yield* emitCommentary(commentary);
516
- }
517
- }
518
- }
519
- const terminalStructuredStatus = readTerminalStructuredStatus(normalizedChunk.event);
520
- if (terminalStructuredStatus && currentPlanState && planStateHasActiveItems(currentPlanState)) {
521
- const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, terminalStructuredStatus, new Date().toISOString());
522
- const signature = buildPlanStateSignature(reconciledPlanState);
523
- if (signature !== lastPlanStateSignature) {
524
- planStateVersion = reconciledPlanState.version;
574
+ const mergedPlanState = mergePartialPlanState(currentPlanState, upstreamPlanState);
575
+ const signature = buildPlanStateSignature(mergedPlanState);
576
+ if (signature !== lastPlanStateSignature && shouldEmitPlanState(currentPlanState, mergedPlanState)) {
577
+ planStateVersion = mergedPlanState.version;
525
578
  lastPlanStateSignature = signature;
526
- currentPlanState = reconciledPlanState;
527
- for (const item of await emitPlanStateUpdate(options, currentAgentId, reconciledPlanState)) {
579
+ currentPlanState = mergedPlanState;
580
+ for (const item of await emitPlanStateUpdate(options, currentAgentId, mergedPlanState)) {
528
581
  yield item;
529
582
  }
530
- const commentary = summarizePlanState(reconciledPlanState);
583
+ const commentary = summarizePlanState(mergedPlanState);
531
584
  if (commentary) {
532
585
  yield* emitCommentary(commentary);
533
586
  }
@@ -677,20 +730,23 @@ export async function* streamHarnessRun(options) {
677
730
  updatedAt: new Date().toISOString(),
678
731
  });
679
732
  if (planState) {
680
- const signature = buildPlanStateSignature(planState);
681
- if (signature !== lastPlanStateSignature && shouldEmitPlanState(currentPlanState, planState)) {
733
+ const mergedPlanState = mergePartialPlanState(currentPlanState, planState);
734
+ const signature = buildPlanStateSignature(mergedPlanState);
735
+ if (signature !== lastPlanStateSignature && shouldEmitPlanState(currentPlanState, mergedPlanState)) {
682
736
  lastPlanStateSignature = signature;
683
- currentPlanState = planState;
684
- for (const item of await emitPlanStateUpdate(options, currentAgentId, planState)) {
737
+ currentPlanState = mergedPlanState;
738
+ for (const item of await emitPlanStateUpdate(options, currentAgentId, mergedPlanState)) {
685
739
  yield item;
686
740
  }
687
- const commentary = summarizePlanState(planState);
741
+ const commentary = summarizePlanState(mergedPlanState);
688
742
  if (commentary) {
689
743
  yield* emitCommentary(commentary);
690
744
  }
691
745
  }
692
746
  }
693
- const terminalStructuredStatus = readTerminalStructuredStatus(normalizedChunk.output);
747
+ const terminalStructuredStatus = normalizedChunk.toolName === "task"
748
+ ? readTerminalStructuredStatus(normalizedChunk.output)
749
+ : null;
694
750
  if (terminalStructuredStatus && currentPlanState && planStateHasActiveItems(currentPlanState)) {
695
751
  const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, terminalStructuredStatus, new Date().toISOString());
696
752
  const signature = buildPlanStateSignature(reconciledPlanState);
@@ -757,15 +813,16 @@ export async function* streamHarnessRun(options) {
757
813
  updatedAt: new Date().toISOString(),
758
814
  });
759
815
  if (finalPlanState) {
760
- const signature = buildPlanStateSignature(finalPlanState);
761
- if (signature !== lastPlanStateSignature && shouldEmitPlanState(currentPlanState, finalPlanState)) {
762
- planStateVersion = finalPlanState.version;
816
+ const mergedPlanState = mergePartialPlanState(currentPlanState, finalPlanState);
817
+ const signature = buildPlanStateSignature(mergedPlanState);
818
+ if (signature !== lastPlanStateSignature && shouldEmitPlanState(currentPlanState, mergedPlanState)) {
819
+ planStateVersion = mergedPlanState.version;
763
820
  lastPlanStateSignature = signature;
764
- currentPlanState = finalPlanState;
765
- for (const item of await emitPlanStateUpdate(options, currentAgentId, finalPlanState)) {
821
+ currentPlanState = mergedPlanState;
822
+ for (const item of await emitPlanStateUpdate(options, currentAgentId, mergedPlanState)) {
766
823
  yield item;
767
824
  }
768
- const commentary = summarizePlanState(finalPlanState);
825
+ const commentary = summarizePlanState(mergedPlanState);
769
826
  if (commentary) {
770
827
  yield* emitCommentary(commentary);
771
828
  }
@@ -791,6 +848,22 @@ export async function* streamHarnessRun(options) {
791
848
  }
792
849
  }
793
850
  currentPlanState = await refreshPlanStateFromPersistence(options, currentPlanState);
851
+ if (isSubstantiveTerminalAssistantOutput(assistantOutput) && planStateHasActiveItems(currentPlanState)) {
852
+ const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, "completed", new Date().toISOString());
853
+ const signature = buildPlanStateSignature(reconciledPlanState);
854
+ if (signature !== lastPlanStateSignature) {
855
+ planStateVersion = reconciledPlanState.version;
856
+ lastPlanStateSignature = signature;
857
+ currentPlanState = reconciledPlanState;
858
+ for (const item of await emitPlanStateUpdate(options, currentAgentId, reconciledPlanState)) {
859
+ yield item;
860
+ }
861
+ const commentary = summarizePlanState(reconciledPlanState);
862
+ if (commentary) {
863
+ yield* emitCommentary(commentary);
864
+ }
865
+ }
866
+ }
794
867
  if (assistantOutputCameFromInvokeFallback
795
868
  && nonUpstreamStreamActivityObserved
796
869
  && planStateHasActiveItems(currentPlanState)) {
@@ -833,6 +906,63 @@ export async function* streamHarnessRun(options) {
833
906
  };
834
907
  }
835
908
  catch (error) {
909
+ const deterministicToolEvidenceOutput = resolveDeterministicFinalOutput({
910
+ visibleOutput: assistantOutput,
911
+ executedToolResults,
912
+ });
913
+ if (!assistantOutput && sawSuccessfulToolResult && deterministicToolEvidenceOutput) {
914
+ const terminalStructuredStatus = readTerminalStructuredStatus(deterministicToolEvidenceOutput);
915
+ if (terminalStructuredStatus && currentPlanState && planStateHasActiveItems(currentPlanState)) {
916
+ const reconciledPlanState = reconcilePlanStateToTerminalStatus(currentPlanState, terminalStructuredStatus, new Date().toISOString());
917
+ const signature = buildPlanStateSignature(reconciledPlanState);
918
+ if (signature !== lastPlanStateSignature) {
919
+ planStateVersion = reconciledPlanState.version;
920
+ lastPlanStateSignature = signature;
921
+ currentPlanState = reconciledPlanState;
922
+ for (const item of await emitPlanStateUpdate(options, currentAgentId, reconciledPlanState)) {
923
+ yield item;
924
+ }
925
+ const commentary = summarizePlanState(reconciledPlanState);
926
+ if (commentary) {
927
+ yield* emitCommentary(commentary);
928
+ }
929
+ }
930
+ }
931
+ await options.appendAssistantMessage(options.sessionId, options.requestId, deterministicToolEvidenceOutput);
932
+ yield {
933
+ type: "event",
934
+ event: await options.emit(options.sessionId, options.requestId, 3, "output.delta", { content: deterministicToolEvidenceOutput }),
935
+ };
936
+ yield {
937
+ type: "content",
938
+ sessionId: options.sessionId,
939
+ requestId: options.requestId,
940
+ agentId: currentAgentId,
941
+ content: deterministicToolEvidenceOutput,
942
+ };
943
+ const completedEvent = await options.setRequestStateAndEmit(options.sessionId, options.requestId, 6, "completed", {
944
+ previousState: "running",
945
+ });
946
+ yield {
947
+ type: "event",
948
+ event: completedEvent,
949
+ };
950
+ yield {
951
+ type: "result",
952
+ result: {
953
+ sessionId: options.sessionId,
954
+ requestId: options.requestId,
955
+ agentId: currentAgentId,
956
+ state: "completed",
957
+ output: deterministicToolEvidenceOutput,
958
+ finalMessageText: deterministicToolEvidenceOutput,
959
+ metadata: {
960
+ executedToolResults,
961
+ },
962
+ },
963
+ };
964
+ return;
965
+ }
836
966
  const shouldRetryAfterStreamingCompatibilityError = !assistantOutput &&
837
967
  isOpenAICompatibleStreamingCompatibilityError(options.binding, error);
838
968
  if ((emitted || streamActivityObserved)
@@ -1,4 +1,4 @@
1
- export { appendToolRecoveryInstruction, isRepairableWriteTodosContentFailure, isRepairableWriteTodosEmptyFailure, isRepairableWriteTodosPlaceholderFailure, isRetrySafeInvalidToolSelectionError, isToolCallRecoveryFailure, isToolCallValidationFailure, isWorkspacePathScopeFailure, resolveExecutionWithoutToolEvidenceInstruction, resolveExecutionWithoutToolEvidenceTextInstruction, resolveToolCallRecoveryInstruction, shouldValidateExecutionWithoutToolEvidence, wrapResolvedModel, } from "./output-recovery.js";
1
+ export { appendToolRecoveryInstruction, isRepairableWriteTodosContentFailure, isRepairableWriteTodosEmptyFailure, isRepairableWriteTodosPlaceholderFailure, isRetrySafeInvalidToolSelectionError, resolveMissingPlanRecoveryInstruction, isToolCallRecoveryFailure, isToolCallValidationFailure, isWorkspacePathScopeFailure, resolveExecutionWithoutToolEvidenceInstruction, resolveExecutionWithoutToolEvidenceTextInstruction, resolveToolCallRecoveryInstruction, shouldValidateExecutionWithoutToolEvidence, wrapResolvedModel, } from "./output-recovery.js";
2
2
  export { BROWSER_CAPABILITY_DISCLAIMER_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION, STRICT_TOOL_JSON_INSTRUCTION, WORKSPACE_RELATIVE_PATH_INSTRUCTION, WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION, WRITE_TODOS_FULL_ENTRY_INSTRUCTION, WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION, } from "../prompts/runtime-prompts.js";
3
3
  export { containsLikelySkillDocument, extractContentBlocks, extractEmptyAssistantMessageFailure, extractOutputContent, extractReasoningText, extractToolFallbackContext, extractVisibleOutput, hasToolCalls, readTextContent, sanitizeVisibleText, } from "./output-content.js";
4
4
  export { isLikelyToolArgsObject, salvageToolArgs, tryParseJson, } from "./output-tool-args.js";
@@ -1,4 +1,4 @@
1
- export { appendToolRecoveryInstruction, isRepairableWriteTodosContentFailure, isRepairableWriteTodosEmptyFailure, isRepairableWriteTodosPlaceholderFailure, isRetrySafeInvalidToolSelectionError, isToolCallRecoveryFailure, isToolCallValidationFailure, isWorkspacePathScopeFailure, resolveExecutionWithoutToolEvidenceInstruction, resolveExecutionWithoutToolEvidenceTextInstruction, resolveToolCallRecoveryInstruction, shouldValidateExecutionWithoutToolEvidence, wrapResolvedModel, } from "./output-recovery.js";
1
+ export { appendToolRecoveryInstruction, isRepairableWriteTodosContentFailure, isRepairableWriteTodosEmptyFailure, isRepairableWriteTodosPlaceholderFailure, isRetrySafeInvalidToolSelectionError, resolveMissingPlanRecoveryInstruction, isToolCallRecoveryFailure, isToolCallValidationFailure, isWorkspacePathScopeFailure, resolveExecutionWithoutToolEvidenceInstruction, resolveExecutionWithoutToolEvidenceTextInstruction, resolveToolCallRecoveryInstruction, shouldValidateExecutionWithoutToolEvidence, wrapResolvedModel, } from "./output-recovery.js";
2
2
  export { BROWSER_CAPABILITY_DISCLAIMER_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION, STRICT_TOOL_JSON_INSTRUCTION, WORKSPACE_RELATIVE_PATH_INSTRUCTION, WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION, WRITE_TODOS_FULL_ENTRY_INSTRUCTION, WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION, } from "../prompts/runtime-prompts.js";
3
3
  export { containsLikelySkillDocument, extractContentBlocks, extractEmptyAssistantMessageFailure, extractOutputContent, extractReasoningText, extractToolFallbackContext, extractVisibleOutput, hasToolCalls, readTextContent, sanitizeVisibleText, } from "./output-content.js";
4
4
  export { isLikelyToolArgsObject, salvageToolArgs, tryParseJson, } from "./output-tool-args.js";