@botbotgo/agent-harness 0.0.100 → 0.0.102

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 (40) hide show
  1. package/dist/package-version.d.ts +1 -1
  2. package/dist/package-version.js +1 -1
  3. package/dist/persistence/sqlite-run-context-store.d.ts +22 -0
  4. package/dist/persistence/sqlite-run-context-store.js +64 -0
  5. package/dist/persistence/sqlite-run-queue-store.d.ts +41 -0
  6. package/dist/persistence/sqlite-run-queue-store.js +120 -0
  7. package/dist/persistence/sqlite-store.d.ts +2 -2
  8. package/dist/persistence/sqlite-store.js +31 -117
  9. package/dist/resource/mcp-tool-support.d.ts +21 -0
  10. package/dist/resource/mcp-tool-support.js +173 -0
  11. package/dist/resource/resource-impl.d.ts +1 -18
  12. package/dist/resource/resource-impl.js +79 -240
  13. package/dist/runtime/adapter/invoke-runtime.d.ts +22 -0
  14. package/dist/runtime/adapter/invoke-runtime.js +18 -0
  15. package/dist/runtime/adapter/stream-runtime.d.ts +46 -0
  16. package/dist/runtime/adapter/stream-runtime.js +93 -0
  17. package/dist/runtime/agent-runtime-adapter.d.ts +1 -12
  18. package/dist/runtime/agent-runtime-adapter.js +122 -312
  19. package/dist/runtime/harness/run/recovery.d.ts +42 -0
  20. package/dist/runtime/harness/run/recovery.js +139 -0
  21. package/dist/runtime/harness/run/run-operations.d.ts +50 -0
  22. package/dist/runtime/harness/run/run-operations.js +113 -0
  23. package/dist/runtime/harness/run/run-slot-acquisition.d.ts +64 -0
  24. package/dist/runtime/harness/run/run-slot-acquisition.js +157 -0
  25. package/dist/runtime/harness/run/stream-run.d.ts +53 -0
  26. package/dist/runtime/harness/run/stream-run.js +304 -0
  27. package/dist/runtime/harness.d.ts +2 -17
  28. package/dist/runtime/harness.js +157 -773
  29. package/dist/runtime/support/runtime-factories.js +2 -2
  30. package/dist/workspace/object-loader.d.ts +1 -8
  31. package/dist/workspace/object-loader.js +43 -275
  32. package/dist/workspace/yaml-object-reader.d.ts +15 -0
  33. package/dist/workspace/yaml-object-reader.js +202 -0
  34. package/package.json +1 -1
  35. package/dist/runtime/checkpoint-maintenance.d.ts +0 -1
  36. package/dist/runtime/checkpoint-maintenance.js +0 -1
  37. package/dist/runtime/file-checkpoint-saver.d.ts +0 -1
  38. package/dist/runtime/file-checkpoint-saver.js +0 -1
  39. package/dist/runtime/sqlite-maintained-checkpoint-saver.d.ts +0 -1
  40. package/dist/runtime/sqlite-maintained-checkpoint-saver.js +0 -1
@@ -3,28 +3,25 @@ import { Command, MemorySaver } from "@langchain/langgraph";
3
3
  import { HumanMessage } from "@langchain/core/messages";
4
4
  import { DEFAULT_SUBAGENT_PROMPT, createDeepAgent, createMemoryMiddleware, createPatchToolCallsMiddleware, createSkillsMiddleware, createSummarizationMiddleware, createSubAgentMiddleware, FilesystemBackend, StateBackend, } from "deepagents";
5
5
  import { createAgent, humanInTheLoopMiddleware } from "langchain";
6
- import { extractToolFallbackContext, extractVisibleOutput, isToolCallParseFailure, STRICT_TOOL_JSON_INSTRUCTION, sanitizeVisibleText, wrapResolvedModel, } from "./parsing/output-parsing.js";
6
+ import { extractToolFallbackContext, extractVisibleOutput, isToolCallParseFailure, STRICT_TOOL_JSON_INSTRUCTION, wrapResolvedModel, } from "./parsing/output-parsing.js";
7
7
  import { readStreamDelta, } from "./parsing/stream-event-parsing.js";
8
8
  import { wrapToolForExecution } from "./adapter/tool/tool-hitl.js";
9
9
  import { resolveDeclaredMiddleware } from "./adapter/tool/declared-middleware.js";
10
- import { extractMessageText } from "../utils/message-content.js";
11
10
  import { applyDeepAgentDelegationPromptCompatibility, materializeDeepAgentSkillSourcePaths, } from "./adapter/compat/deepagent-compat.js";
12
11
  import { buildToolNameMapping, } from "./adapter/tool/tool-name-mapping.js";
13
12
  import { createBuiltinMiddlewareTools } from "./adapter/tool/builtin-middleware-tools.js";
14
13
  import { finalizeInvocationResult } from "./adapter/invocation-result.js";
15
- import { runLocalToolInvocationLoop } from "./adapter/local-tool-invocation.js";
16
- import { createStreamEventProjectionState, projectRuntimeStreamEvent } from "./adapter/stream-event-projection.js";
17
- import { projectTextStreamChunks } from "./adapter/stream-text-consumption.js";
14
+ import { invokeRuntimeWithLocalTools } from "./adapter/invoke-runtime.js";
15
+ import { streamRuntimeExecution } from "./adapter/stream-runtime.js";
18
16
  import { buildDeepAgentRunnableConfig } from "./adapter/deepagent-runnable-config.js";
19
17
  import { buildLangChainRunnableConfig } from "./adapter/langchain-runnable-config.js";
20
18
  import { computeRemainingTimeoutMs, isRetryableProviderError, resolveBindingTimeout, resolveProviderRetryPolicy, resolveStreamIdleTimeout, } from "./adapter/resilience.js";
21
19
  import { createResolvedModel } from "./adapter/model/model-providers.js";
22
- import { buildInvocationRequest, buildSlashCommandSkillInstruction, } from "./adapter/model/invocation-request.js";
20
+ import { buildInvocationRequest, } from "./adapter/model/invocation-request.js";
23
21
  import { compileInterruptOn } from "./adapter/tool/interrupt-policy.js";
24
- import { buildRawModelMessages } from "./adapter/model/message-assembly.js";
25
22
  import { asStructuredExecutableTool, hasCallableToolHandler, normalizeResolvedToolSchema, wrapResolvedToolWithModelFacingName, } from "./adapter/tool/resolved-tool.js";
26
23
  import { instantiateProviderTool } from "./adapter/tool/provider-tool.js";
27
- import { asObject, countConfiguredTools, hasConfiguredMiddlewareKind, hasConfiguredSubagentSupport, isObject, isRecord, sleep, } from "./adapter/runtime-adapter-support.js";
24
+ import { countConfiguredTools, hasConfiguredMiddlewareKind, hasConfiguredSubagentSupport, isObject, isRecord, sleep, } from "./adapter/runtime-adapter-support.js";
28
25
  export { applyDeepAgentDelegationPromptCompatibility, materializeDeepAgentSkillSourcePaths, relativizeDeepAgentSkillSourcePaths, shouldRelaxDeepAgentDelegationPrompt, } from "./adapter/compat/deepagent-compat.js";
29
26
  export { buildAuthOmittingFetch, normalizeOpenAICompatibleInit } from "./adapter/compat/openai-compatible.js";
30
27
  export { buildToolNameMapping, createModelFacingToolNameCandidates, createModelFacingToolNameLookupCandidates, resolveModelFacingToolName, sanitizeToolNameForModel, } from "./adapter/tool/tool-name-mapping.js";
@@ -227,21 +224,9 @@ export class AgentRuntimeAdapter {
227
224
  throw error;
228
225
  }
229
226
  }
230
- buildToolNameMapping(tools) {
231
- return buildToolNameMapping(tools);
232
- }
233
- buildSlashCommandSkillInstruction(binding, input) {
234
- return buildSlashCommandSkillInstruction(binding, input);
235
- }
236
- buildInvocationRequest(binding, history, input, options = {}) {
237
- return buildInvocationRequest(binding, history, input, options);
238
- }
239
- buildRawModelMessages(binding, systemPrompt, history, input) {
240
- return buildRawModelMessages(binding, systemPrompt, history, input);
241
- }
242
227
  resolveTools(tools, binding) {
243
228
  const resolved = this.options.toolResolver ? this.options.toolResolver(tools.map((tool) => tool.id), binding) : [];
244
- const toolNameMapping = this.buildToolNameMapping(tools);
229
+ const toolNameMapping = buildToolNameMapping(tools);
245
230
  return tools.flatMap((compiledTool, index) => {
246
231
  const resolvedTool = resolved[index] ?? (compiledTool.type === "provider" ? instantiateProviderTool(compiledTool) : undefined);
247
232
  if (resolvedTool === undefined) {
@@ -256,12 +241,6 @@ export class AgentRuntimeAdapter {
256
241
  return modelFacingName === compiledTool.name ? wrappedTool : wrapResolvedToolWithModelFacingName(wrappedTool, modelFacingName);
257
242
  });
258
243
  }
259
- compileInterruptOn(tools, compatibilityRules) {
260
- return compileInterruptOn(tools, compatibilityRules);
261
- }
262
- resolveInterruptOn(binding) {
263
- return this.compileInterruptOn(getBindingPrimaryTools(binding), getBindingInterruptCompatibilityRules(binding));
264
- }
265
244
  resolveFilesystemBackend(binding) {
266
245
  const filesystemConfig = getBindingLangChainParams(binding)?.filesystem;
267
246
  const configuredRootDir = typeof filesystemConfig?.rootDir === "string" && filesystemConfig.rootDir.trim().length > 0
@@ -299,6 +278,21 @@ export class AgentRuntimeAdapter {
299
278
  }
300
279
  return new StateBackend(runtimeLike);
301
280
  }
281
+ createDeclaredMiddlewareResolverOptions(binding) {
282
+ return {
283
+ resolveModel: (model) => this.resolveModel(model),
284
+ resolveBackend: (resolvedBinding) => {
285
+ const targetBinding = resolvedBinding ?? binding;
286
+ return targetBinding ? this.options.backendResolver?.(targetBinding) : undefined;
287
+ },
288
+ resolveFilesystemBackend: (resolvedBinding) => {
289
+ const targetBinding = resolvedBinding ?? binding;
290
+ return targetBinding ? this.resolveFilesystemBackend(targetBinding) : undefined;
291
+ },
292
+ resolveCustom: this.options.declaredMiddlewareResolver,
293
+ binding,
294
+ };
295
+ }
302
296
  async invokeBuiltinTaskTool(binding, input, options = {}) {
303
297
  if (!isDeepAgentBinding(binding)) {
304
298
  throw new Error("The built-in task tool is only available for deepagent bindings.");
@@ -340,7 +334,7 @@ export class AgentRuntimeAdapter {
340
334
  ]),
341
335
  ...(selectedSubagent.interruptOn
342
336
  ? [humanInTheLoopMiddleware({
343
- interruptOn: this.compileInterruptOn(selectedSubagent.tools ?? [], selectedSubagent.interruptOn),
337
+ interruptOn: compileInterruptOn(selectedSubagent.tools ?? [], selectedSubagent.interruptOn),
344
338
  })]
345
339
  : []),
346
340
  ];
@@ -376,13 +370,7 @@ export class AgentRuntimeAdapter {
376
370
  if (!primaryModel) {
377
371
  return [];
378
372
  }
379
- return resolveDeclaredMiddleware([{ kind: "summarization", model: primaryModel }], {
380
- resolveModel: (model) => this.resolveModel(model),
381
- resolveBackend: (resolvedBinding) => this.options.backendResolver?.(resolvedBinding ?? binding),
382
- resolveFilesystemBackend: (resolvedBinding) => this.resolveFilesystemBackend(resolvedBinding ?? binding),
383
- resolveCustom: this.options.declaredMiddlewareResolver,
384
- binding,
385
- });
373
+ return resolveDeclaredMiddleware([{ kind: "summarization", model: primaryModel }], this.createDeclaredMiddlewareResolverOptions(binding));
386
374
  }
387
375
  async resolveLangChainAutomaticMiddleware(binding) {
388
376
  const params = getBindingLangChainParams(binding);
@@ -417,23 +405,11 @@ export class AgentRuntimeAdapter {
417
405
  }
418
406
  return automaticMiddleware;
419
407
  }
420
- async resolveDeepAgentAutomaticMiddleware(binding) {
421
- if (!isDeepAgentBinding(binding)) {
422
- return [];
423
- }
424
- return [];
425
- }
426
408
  async resolveMiddleware(binding, interruptOn) {
427
- const declarativeMiddleware = await resolveDeclaredMiddleware(getBindingMiddlewareConfigs(binding), {
428
- resolveModel: (model) => this.resolveModel(model),
429
- resolveBackend: (resolvedBinding) => this.options.backendResolver?.(resolvedBinding ?? binding),
430
- resolveFilesystemBackend: (resolvedBinding) => this.resolveFilesystemBackend(resolvedBinding ?? binding),
431
- resolveCustom: this.options.declaredMiddlewareResolver,
432
- binding,
433
- });
409
+ const declarativeMiddleware = await resolveDeclaredMiddleware(getBindingMiddlewareConfigs(binding), this.createDeclaredMiddlewareResolverOptions(binding));
434
410
  const automaticMiddleware = isLangChainBinding(binding)
435
411
  ? await this.resolveLangChainAutomaticMiddleware(binding)
436
- : await this.resolveDeepAgentAutomaticMiddleware(binding);
412
+ : [];
437
413
  const middleware = [
438
414
  ...declarativeMiddleware,
439
415
  ...automaticMiddleware,
@@ -444,9 +420,6 @@ export class AgentRuntimeAdapter {
444
420
  }
445
421
  return middleware;
446
422
  }
447
- resolveCheckpointer(binding) {
448
- return this.options.checkpointerResolver ? this.options.checkpointerResolver(binding) : new MemorySaver();
449
- }
450
423
  async resolveSubagents(subagents, binding) {
451
424
  return Promise.all(subagents.map(async (subagent) => ({
452
425
  ...subagent,
@@ -459,27 +432,15 @@ export class AgentRuntimeAdapter {
459
432
  ownerId: `${binding?.agent.id ?? "agent"}-${subagent.name}`,
460
433
  skillPaths: subagent.skills,
461
434
  }),
462
- interruptOn: this.compileInterruptOn(subagent.tools ?? [], subagent.interruptOn),
435
+ interruptOn: compileInterruptOn(subagent.tools ?? [], subagent.interruptOn),
463
436
  responseFormat: subagent.responseFormat,
464
437
  contextSchema: subagent.contextSchema,
465
- middleware: (await resolveDeclaredMiddleware(subagent.middleware, {
466
- resolveModel: (model) => this.resolveModel(model),
467
- resolveBackend: (resolvedBinding) => {
468
- const targetBinding = resolvedBinding ?? binding;
469
- return targetBinding ? this.options.backendResolver?.(targetBinding) : undefined;
470
- },
471
- resolveFilesystemBackend: (resolvedBinding) => {
472
- const targetBinding = resolvedBinding ?? binding;
473
- return targetBinding ? this.resolveFilesystemBackend(targetBinding) : undefined;
474
- },
475
- resolveCustom: this.options.declaredMiddlewareResolver,
476
- binding,
477
- })),
438
+ middleware: (await resolveDeclaredMiddleware(subagent.middleware, this.createDeclaredMiddlewareResolverOptions(binding))),
478
439
  })));
479
440
  }
480
441
  async createLangChainRunnable(binding, options = {}) {
481
442
  const params = getBindingLangChainParams(binding);
482
- const interruptOn = this.resolveInterruptOn(binding);
443
+ const interruptOn = compileInterruptOn(getBindingPrimaryTools(binding), getBindingInterruptCompatibilityRules(binding));
483
444
  const model = (await this.resolveModel(params.model));
484
445
  const tools = this.resolveTools(params.tools, binding);
485
446
  if (tools.length > 0 && typeof model.bindTools !== "function") {
@@ -490,90 +451,12 @@ export class AgentRuntimeAdapter {
490
451
  resolvedModel: model,
491
452
  resolvedTools: tools,
492
453
  resolvedMiddleware: await this.resolveMiddleware(binding, interruptOn),
493
- resolvedCheckpointer: this.resolveCheckpointer(binding),
454
+ resolvedCheckpointer: this.options.checkpointerResolver ? this.options.checkpointerResolver(binding) : new MemorySaver(),
494
455
  resolvedStore: this.options.storeResolver?.(binding),
495
456
  passthroughOverride: options.passthroughOverride,
496
457
  systemPromptOverride: options.systemPromptOverride,
497
458
  }));
498
459
  }
499
- extractInvocationRequestText(request) {
500
- if (!isRecord(request) || !Array.isArray(request.messages)) {
501
- return "";
502
- }
503
- for (let index = request.messages.length - 1; index >= 0; index -= 1) {
504
- const message = request.messages[index];
505
- if (!isRecord(message)) {
506
- continue;
507
- }
508
- const role = typeof message.role === "string" ? message.role : undefined;
509
- if (role !== "user") {
510
- continue;
511
- }
512
- return extractMessageText(message.content);
513
- }
514
- return "";
515
- }
516
- prependSystemMessage(request, content) {
517
- if (!content.trim() || !isRecord(request) || !Array.isArray(request.messages)) {
518
- return request;
519
- }
520
- return {
521
- ...request,
522
- messages: [{ role: "system", content }, ...request.messages],
523
- };
524
- }
525
- replaceLastUserMessage(request, content) {
526
- if (!content.trim() || !isRecord(request) || !Array.isArray(request.messages)) {
527
- return request;
528
- }
529
- const messages = [...request.messages];
530
- for (let index = messages.length - 1; index >= 0; index -= 1) {
531
- const message = messages[index];
532
- if (!isRecord(message) || message.role !== "user") {
533
- continue;
534
- }
535
- messages[index] = {
536
- ...message,
537
- content,
538
- };
539
- return {
540
- ...request,
541
- messages,
542
- };
543
- }
544
- return {
545
- ...request,
546
- messages: [...messages, { role: "user", content }],
547
- };
548
- }
549
- extractExecutedToolResults(result) {
550
- const metadata = asObject(result?.metadata);
551
- if (Array.isArray(metadata?.executedToolResults)) {
552
- return metadata.executedToolResults;
553
- }
554
- const messages = Array.isArray(result?.messages) ? result.messages : [];
555
- return messages.flatMap((message) => {
556
- const typed = asObject(message);
557
- const kwargs = asObject(typed?.kwargs);
558
- const typeId = Array.isArray(typed?.id) ? typed.id.at(-1) : undefined;
559
- const runtimeType = typeof typed?.type === "string" ? typed.type : undefined;
560
- if (typeId !== "ToolMessage" && runtimeType !== "tool") {
561
- return [];
562
- }
563
- const toolName = typeof typed?.name === "string"
564
- ? typed.name
565
- : typeof kwargs?.name === "string"
566
- ? kwargs.name
567
- : "tool";
568
- const output = typed?.content ??
569
- kwargs?.content ??
570
- "";
571
- return [{
572
- toolName,
573
- output,
574
- }];
575
- });
576
- }
577
460
  async createRunnable(binding) {
578
461
  if (getBindingAdapterKind(binding) === "langgraph") {
579
462
  throw new Error(`Agent ${binding.agent.id} uses removed backend langgraph; use langchain-v1 or deepagent`);
@@ -595,10 +478,10 @@ export class AgentRuntimeAdapter {
595
478
  resolvedTools: this.resolveTools(compatibleParams.tools, binding),
596
479
  resolvedMiddleware: await this.resolveMiddleware(binding),
597
480
  resolvedSubagents: await this.resolveSubagents(compatibleParams.subagents, binding),
598
- resolvedCheckpointer: this.resolveCheckpointer(binding),
481
+ resolvedCheckpointer: this.options.checkpointerResolver ? this.options.checkpointerResolver(binding) : new MemorySaver(),
599
482
  resolvedStore: this.options.storeResolver?.(binding),
600
483
  resolvedBackend: this.options.backendResolver?.(binding),
601
- resolvedInterruptOn: this.resolveInterruptOn(binding),
484
+ resolvedInterruptOn: compileInterruptOn(getBindingPrimaryTools(binding), getBindingInterruptCompatibilityRules(binding)),
602
485
  resolvedSkills: (await materializeDeepAgentSkillSourcePaths({
603
486
  workspaceRoot: binding.harnessRuntime.workspaceRoot,
604
487
  runRoot: binding.harnessRuntime.runRoot,
@@ -625,9 +508,8 @@ export class AgentRuntimeAdapter {
625
508
  }
626
509
  async invoke(binding, input, threadId, runId, resumePayload, history = [], options = {}) {
627
510
  const request = resumePayload === undefined
628
- ? this.buildInvocationRequest(binding, history, input, options)
511
+ ? buildInvocationRequest(binding, history, input, options)
629
512
  : new Command({ resume: resumePayload });
630
- let result;
631
513
  const callRuntime = async (activeBinding, activeRequest) => {
632
514
  return this.invokeWithProviderRetry(activeBinding, async () => {
633
515
  const runnable = await this.create(activeBinding);
@@ -645,64 +527,54 @@ export class AgentRuntimeAdapter {
645
527
  return callRuntime(this.applyStrictToolJsonInstruction(binding), activeRequest);
646
528
  }
647
529
  };
648
- const executedToolResults = [];
649
- if (resumePayload !== undefined) {
650
- result = await callRuntimeWithToolParseRecovery(request);
651
- }
652
- else {
653
- const primaryTools = getBindingPrimaryTools(binding);
654
- const defersToUpstreamHitlExecution = primaryTools.some((tool) => tool.hitl?.enabled === true);
655
- if (defersToUpstreamHitlExecution) {
656
- result = await callRuntimeWithToolParseRecovery(request);
530
+ const primaryTools = getBindingPrimaryTools(binding);
531
+ const resolvedTools = this.resolveTools(primaryTools, binding);
532
+ const toolNameMapping = buildToolNameMapping(primaryTools);
533
+ const executableTools = new Map();
534
+ for (let index = 0; index < primaryTools.length; index += 1) {
535
+ const compiledTool = primaryTools[index];
536
+ const resolvedTool = resolvedTools[index];
537
+ if (!compiledTool || !resolvedTool || !hasCallableToolHandler(resolvedTool)) {
538
+ continue;
657
539
  }
658
- else {
659
- const resolvedTools = this.resolveTools(primaryTools, binding);
660
- const toolNameMapping = this.buildToolNameMapping(primaryTools);
661
- const executableTools = new Map();
662
- const builtinExecutableTools = await this.resolveBuiltinMiddlewareTools(binding, options);
663
- for (let index = 0; index < primaryTools.length; index += 1) {
664
- const compiledTool = primaryTools[index];
665
- const resolvedTool = resolvedTools[index];
666
- if (!compiledTool || !resolvedTool || !hasCallableToolHandler(resolvedTool)) {
667
- continue;
668
- }
669
- const handler = async (toolInput) => {
670
- const callable = typeof resolvedTool.invoke === "function"
671
- ? resolvedTool.invoke
672
- : typeof resolvedTool.call === "function"
673
- ? resolvedTool.call
674
- : resolvedTool.func;
675
- if (!callable) {
676
- throw new Error(`Tool ${compiledTool.name} has no callable handler.`);
677
- }
678
- return Promise.resolve(callable.call(resolvedTool, toolInput, options.context ? { context: options.context } : undefined));
679
- };
680
- const modelFacingName = toolNameMapping.originalToModelFacing.get(compiledTool.name) ?? compiledTool.name;
681
- const normalizedSchema = normalizeResolvedToolSchema(resolvedTool);
682
- executableTools.set(modelFacingName, {
683
- name: compiledTool.name,
684
- schema: normalizedSchema,
685
- invoke: handler,
686
- });
687
- executableTools.set(compiledTool.name, {
688
- name: compiledTool.name,
689
- schema: normalizedSchema,
690
- invoke: handler,
691
- });
540
+ const handler = async (toolInput) => {
541
+ const callable = typeof resolvedTool.invoke === "function"
542
+ ? resolvedTool.invoke
543
+ : typeof resolvedTool.call === "function"
544
+ ? resolvedTool.call
545
+ : resolvedTool.func;
546
+ if (!callable) {
547
+ throw new Error(`Tool ${compiledTool.name} has no callable handler.`);
692
548
  }
693
- const localInvocation = await runLocalToolInvocationLoop({
694
- binding,
695
- request,
696
- primaryTools,
697
- toolNameMapping,
698
- executableTools: executableTools,
699
- builtinExecutableTools: builtinExecutableTools,
700
- callRuntimeWithToolParseRecovery,
701
- });
702
- result = localInvocation.result;
703
- executedToolResults.push(...localInvocation.executedToolResults);
704
- }
549
+ return Promise.resolve(callable.call(resolvedTool, toolInput, options.context ? { context: options.context } : undefined));
550
+ };
551
+ const modelFacingName = toolNameMapping.originalToModelFacing.get(compiledTool.name) ?? compiledTool.name;
552
+ const normalizedSchema = normalizeResolvedToolSchema(resolvedTool);
553
+ executableTools.set(modelFacingName, {
554
+ name: compiledTool.name,
555
+ schema: normalizedSchema,
556
+ invoke: handler,
557
+ });
558
+ executableTools.set(compiledTool.name, {
559
+ name: compiledTool.name,
560
+ schema: normalizedSchema,
561
+ invoke: handler,
562
+ });
705
563
  }
564
+ const builtinExecutableTools = await this.resolveBuiltinMiddlewareTools(binding, options);
565
+ const localOrUpstreamInvocation = await invokeRuntimeWithLocalTools({
566
+ binding,
567
+ request,
568
+ resumePayload,
569
+ primaryTools,
570
+ defersToUpstreamHitlExecution: primaryTools.some((tool) => tool.hitl?.enabled === true),
571
+ toolNameMapping,
572
+ executableTools,
573
+ builtinExecutableTools: builtinExecutableTools,
574
+ callRuntimeWithToolParseRecovery,
575
+ });
576
+ const result = localOrUpstreamInvocation.result;
577
+ const executedToolResults = [...localOrUpstreamInvocation.executedToolResults];
706
578
  if (!result) {
707
579
  throw new Error("Agent invocation returned no result");
708
580
  }
@@ -715,113 +587,51 @@ export class AgentRuntimeAdapter {
715
587
  });
716
588
  }
717
589
  async *stream(binding, input, threadId, history = [], options = {}) {
718
- try {
719
- const invokeTimeoutMs = resolveBindingTimeout(binding);
720
- const streamIdleTimeoutMs = resolveStreamIdleTimeout(binding);
721
- const streamDeadlineAt = invokeTimeoutMs ? Date.now() + invokeTimeoutMs : undefined;
722
- const primaryTools = getBindingPrimaryTools(binding);
723
- const toolNameMapping = this.buildToolNameMapping(primaryTools);
724
- const primaryModel = getBindingPrimaryModel(binding);
725
- const forceInvokeFallback = isLangChainBinding(binding) &&
726
- primaryTools.length > 0 &&
727
- primaryModel?.provider === "openai-compatible";
728
- if (isLangChainBinding(binding)) {
729
- const langchainParams = getBindingLangChainParams(binding);
730
- const resolvedModel = (await this.resolveModel(langchainParams.model));
731
- const tools = this.resolveTools(langchainParams.tools, binding);
732
- const canUseDirectModelStream = tools.length === 0 || typeof resolvedModel.bindTools !== "function";
733
- const model = canUseDirectModelStream
734
- ? resolvedModel
735
- : typeof resolvedModel.bindTools === "function" && tools.length > 0
736
- ? resolvedModel.bindTools(tools)
737
- : resolvedModel;
738
- // For tool-using langchain agents, a raw model.stream pass cannot execute the
739
- // agent loop and only adds an extra model round-trip before the runnable path.
740
- if (canUseDirectModelStream && typeof model.stream === "function") {
741
- const stream = await this.withTimeout(() => model.stream(this.buildRawModelMessages(binding, getBindingSystemPrompt(binding), history, input)), computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs), "model stream start", "stream");
742
- let emitted = false;
743
- const projected = projectTextStreamChunks(this.iterateWithTimeout(stream, streamIdleTimeoutMs, "model stream", streamDeadlineAt, invokeTimeoutMs));
744
- let nextChunk = await projected.next();
745
- while (!nextChunk.done) {
746
- if (nextChunk.value.kind === "content") {
747
- emitted = true;
748
- }
749
- yield nextChunk.value;
750
- nextChunk = await projected.next();
751
- }
752
- if (nextChunk.value.emittedContent || emitted) {
753
- return;
754
- }
755
- }
756
- }
757
- const runnable = await this.create(binding);
758
- const request = this.buildInvocationRequest(binding, history, input, options);
759
- if (!forceInvokeFallback && typeof runnable.streamEvents === "function") {
760
- const events = await this.withTimeout(() => runnable.streamEvents(request, { configurable: { thread_id: threadId, run_id: options.runId }, version: "v2", ...(options.context ? { context: options.context } : {}) }), computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs), "agent streamEvents start", "stream");
761
- const projectionState = createStreamEventProjectionState();
762
- for await (const event of this.iterateWithTimeout(events, streamIdleTimeoutMs, "agent streamEvents", streamDeadlineAt, invokeTimeoutMs)) {
763
- const projectedChunks = projectRuntimeStreamEvent({
764
- event,
765
- allowVisibleStreamDeltas: isLangChainBinding(binding),
766
- includeStateStreamOutput: isDeepAgentBinding(binding),
767
- toolNameMapping,
768
- primaryTools,
769
- state: projectionState,
770
- });
771
- for (const chunk of projectedChunks) {
772
- yield chunk;
773
- }
774
- }
775
- if (projectionState.emittedOutput || projectionState.emittedToolResult || projectionState.emittedToolError) {
776
- return;
777
- }
778
- }
779
- if (!forceInvokeFallback && isLangChainBinding(binding) && typeof runnable.stream === "function") {
780
- const stream = await this.withTimeout(() => runnable.stream(request, { configurable: { thread_id: threadId, run_id: options.runId } }), computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs), "agent stream start", "stream");
781
- let emitted = false;
782
- const projected = projectTextStreamChunks(this.iterateWithTimeout(stream, streamIdleTimeoutMs, "agent stream", streamDeadlineAt, invokeTimeoutMs));
783
- let nextChunk = await projected.next();
784
- while (!nextChunk.done) {
785
- if (nextChunk.value.kind === "content") {
786
- emitted = true;
787
- }
788
- yield nextChunk.value;
789
- nextChunk = await projected.next();
790
- }
791
- if (nextChunk.value.emittedContent || emitted) {
792
- return;
793
- }
794
- }
795
- const result = await this.invoke(binding, input, threadId, options.runId ?? threadId, undefined, history, options);
796
- const executedToolResults = Array.isArray(result.metadata?.executedToolResults)
797
- ? result.metadata.executedToolResults
798
- : [];
799
- for (const toolResult of executedToolResults) {
800
- yield {
801
- kind: "tool-result",
802
- toolName: toolResult.toolName,
803
- output: toolResult.output,
804
- isError: toolResult.isError,
805
- };
806
- }
807
- if (result.output) {
808
- yield { kind: "content", content: sanitizeVisibleText(result.output) };
809
- }
810
- }
811
- catch (error) {
812
- if (countConfiguredTools(binding) > 0 &&
813
- error instanceof Error &&
814
- error.message.includes("does not support tool binding")) {
815
- throw error;
816
- }
817
- if (!isToolCallParseFailure(error)) {
818
- throw error;
819
- }
820
- const retried = await this.invoke(this.applyStrictToolJsonInstruction(binding), input, threadId, options.runId ?? threadId, undefined, history, options);
821
- if (retried.output) {
822
- yield { kind: "content", content: sanitizeVisibleText(retried.output) };
823
- }
824
- }
590
+ const invokeTimeoutMs = resolveBindingTimeout(binding);
591
+ const streamIdleTimeoutMs = resolveStreamIdleTimeout(binding);
592
+ const streamDeadlineAt = invokeTimeoutMs ? Date.now() + invokeTimeoutMs : undefined;
593
+ const primaryTools = getBindingPrimaryTools(binding);
594
+ const toolNameMapping = buildToolNameMapping(primaryTools);
595
+ const primaryModel = getBindingPrimaryModel(binding);
596
+ const forceInvokeFallback = isLangChainBinding(binding) &&
597
+ primaryTools.length > 0 &&
598
+ primaryModel?.provider === "openai-compatible";
599
+ const langchainParams = isLangChainBinding(binding) ? getBindingLangChainParams(binding) : undefined;
600
+ const resolvedLangChainModel = langchainParams
601
+ ? (await this.resolveModel(langchainParams.model))
602
+ : undefined;
603
+ const resolvedLangChainTools = langchainParams ? this.resolveTools(langchainParams.tools, binding) : [];
604
+ const canUseDirectModelStream = !!resolvedLangChainModel &&
605
+ (resolvedLangChainTools.length === 0 || typeof resolvedLangChainModel.bindTools !== "function");
606
+ const langChainStreamModel = resolvedLangChainModel && canUseDirectModelStream
607
+ ? resolvedLangChainModel
608
+ : resolvedLangChainModel && typeof resolvedLangChainModel.bindTools === "function" && resolvedLangChainTools.length > 0
609
+ ? resolvedLangChainModel.bindTools(resolvedLangChainTools)
610
+ : undefined;
611
+ yield* streamRuntimeExecution({
612
+ binding,
613
+ input,
614
+ threadId,
615
+ history,
616
+ runtimeOptions: options,
617
+ primaryTools,
618
+ toolNameMapping,
619
+ forceInvokeFallback,
620
+ canUseDirectModelStream,
621
+ langChainStreamModel,
622
+ createRunnable: () => this.create(binding),
623
+ withTimeout: (producer, timeoutMs, operation, stage) => this.withTimeout(producer, timeoutMs, operation, stage),
624
+ iterateWithTimeout: (iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs) => this.iterateWithTimeout(iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs),
625
+ invokeTimeoutMs: computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs),
626
+ streamIdleTimeoutMs,
627
+ streamDeadlineAt,
628
+ invoke: (activeBinding, activeInput, activeThreadId, runId, resumePayload, activeHistory, invokeOptions) => this.invoke(activeBinding, activeInput, activeThreadId, runId, resumePayload, activeHistory, invokeOptions),
629
+ applyStrictToolJsonInstruction: (activeBinding) => this.applyStrictToolJsonInstruction(activeBinding),
630
+ getSystemPrompt: (activeBinding) => getBindingSystemPrompt(activeBinding),
631
+ isLangChainBinding,
632
+ isDeepAgentBinding,
633
+ countConfiguredTools,
634
+ });
825
635
  }
826
636
  }
827
637
  export { AgentRuntimeAdapter as RuntimeAdapter, AGENT_INTERRUPT_SENTINEL_PREFIX, AGENT_INTERRUPT_SENTINEL_PREFIX as INTERRUPT_SENTINEL_PREFIX, RuntimeOperationTimeoutError, };
@@ -0,0 +1,42 @@
1
+ import type { MessageContent, RunResult, ThreadSummary, WorkspaceBundle } from "../../../contracts/types.js";
2
+ import type { RuntimePersistence } from "../../../persistence/types.js";
3
+ import type { AgentRuntimeAdapter } from "../../agent-runtime-adapter.js";
4
+ import type { ConcurrencyConfig, RecoveryConfig } from "../../../workspace/support/workspace-ref-utils.js";
5
+ type RecoveryBinding = WorkspaceBundle["bindings"] extends Map<any, infer T> ? T : never;
6
+ type StartupRecoveryContext = {
7
+ persistence: RuntimePersistence;
8
+ workspace: WorkspaceBundle;
9
+ runtimeAdapter: AgentRuntimeAdapter;
10
+ recoveryConfig: RecoveryConfig;
11
+ concurrencyConfig: ConcurrencyConfig;
12
+ getBinding: (agentId: string) => RecoveryBinding | undefined;
13
+ acquireRunSlot: (threadId?: string, runId?: string, activeState?: RunResult["state"], priority?: number) => Promise<() => Promise<void>>;
14
+ executeQueuedRun: (binding: RecoveryBinding, input: MessageContent, threadId: string, runId: string, agentId: string, options?: {
15
+ context?: Record<string, unknown>;
16
+ state?: Record<string, unknown>;
17
+ files?: Record<string, unknown>;
18
+ previousState?: RunResult["state"];
19
+ stateSequence?: number;
20
+ approvalSequence?: number;
21
+ }) => Promise<RunResult>;
22
+ setRunStateAndEmit: (threadId: string, runId: string, sequence: number, state: RunResult["state"], options: {
23
+ previousState: string | null;
24
+ checkpointRef?: string | null;
25
+ error?: string;
26
+ }) => Promise<unknown>;
27
+ emit: (threadId: string, runId: string, sequence: number, eventType: string, payload: Record<string, unknown>) => Promise<unknown>;
28
+ loadRunInput: (threadId: string, runId: string) => Promise<MessageContent>;
29
+ finalizeContinuedRun: (binding: RecoveryBinding, threadId: string, runId: string, input: MessageContent, actual: RunResult, options: {
30
+ previousState: RunResult["state"] | null;
31
+ stateSequence: number;
32
+ approvalSequence?: number;
33
+ }) => Promise<RunResult>;
34
+ supportsRunningReplay: (binding: RecoveryBinding) => boolean;
35
+ isStaleRunningRun: (thread: ThreadSummary, nowMs?: number) => Promise<boolean>;
36
+ recordLlmSuccess: (startedAt: number) => void;
37
+ recordLlmFailure: (startedAt: number) => void;
38
+ };
39
+ export declare function recoverQueuedStartupRun(context: StartupRecoveryContext, thread: ThreadSummary): Promise<boolean>;
40
+ export declare function recoverRunningStartupRun(context: StartupRecoveryContext, thread: ThreadSummary): Promise<boolean>;
41
+ export declare function recoverResumingStartupRun(context: StartupRecoveryContext, thread: ThreadSummary): Promise<boolean>;
42
+ export {};