@botbotgo/agent-harness 0.0.40 → 0.0.42

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.
@@ -12,6 +12,9 @@ import { computeIncrementalOutput, extractAgentStep, extractInterruptPayload, ex
12
12
  import { wrapToolForExecution } from "./tool-hitl.js";
13
13
  import { resolveDeclaredMiddleware } from "./declared-middleware.js";
14
14
  import { extractMessageText, normalizeMessageContent } from "../utils/message-content.js";
15
+ function countConfiguredTools(binding) {
16
+ return binding.langchainAgentParams?.tools.length ?? binding.deepAgentParams?.tools.length ?? 0;
17
+ }
15
18
  const AGENT_INTERRUPT_SENTINEL_PREFIX = "__agent_harness_interrupt__:";
16
19
  const MODEL_SAFE_TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
17
20
  class RuntimeOperationTimeoutError extends Error {
@@ -163,33 +166,11 @@ function asStructuredExecutableTool(resolvedTool, modelFacingName, description)
163
166
  schema: normalizeResolvedToolSchema(resolvedTool),
164
167
  });
165
168
  }
166
- function countConfiguredTools(binding) {
167
- return binding.langchainAgentParams?.tools.length ?? binding.deepAgentParams?.tools.length ?? 0;
168
- }
169
169
  export class AgentRuntimeAdapter {
170
170
  options;
171
171
  constructor(options = {}) {
172
172
  this.options = options;
173
173
  }
174
- canUseSimpleDeepAgentFastPath(binding) {
175
- const params = binding.deepAgentParams;
176
- if (!params) {
177
- return false;
178
- }
179
- if ((params.subagents?.length ?? 0) > 0) {
180
- return false;
181
- }
182
- if ((params.memory?.length ?? 0) > 0) {
183
- return false;
184
- }
185
- if ((params.skills?.length ?? 0) > 0) {
186
- return false;
187
- }
188
- if (params.backend || params.store) {
189
- return false;
190
- }
191
- return true;
192
- }
193
174
  resolveBindingTimeout(binding) {
194
175
  return resolveTimeoutMs(binding.langchainAgentParams?.model.init.timeout ?? binding.deepAgentParams?.model.init.timeout);
195
176
  }
@@ -377,6 +358,13 @@ export class AgentRuntimeAdapter {
377
358
  { role: "user", content: normalizeMessageContent(input) },
378
359
  ];
379
360
  }
361
+ buildInvocationRequest(history, input, options = {}) {
362
+ return {
363
+ ...(options.state ?? {}),
364
+ ...(options.files ? { files: options.files } : {}),
365
+ messages: this.buildAgentMessages(history, input),
366
+ };
367
+ }
380
368
  buildRawModelMessages(systemPrompt, history, input) {
381
369
  const messages = [];
382
370
  if (systemPrompt) {
@@ -445,6 +433,8 @@ export class AgentRuntimeAdapter {
445
433
  const declarativeMiddleware = await resolveDeclaredMiddleware(binding.langchainAgentParams?.middleware ??
446
434
  binding.deepAgentParams?.middleware, {
447
435
  resolveModel: (model) => this.resolveModel(model),
436
+ resolveCustom: this.options.declaredMiddlewareResolver,
437
+ binding,
448
438
  });
449
439
  const middleware = [
450
440
  ...declarativeMiddleware,
@@ -478,7 +468,7 @@ export class AgentRuntimeAdapter {
478
468
  .replaceAll("{{secondaryAgentId}}", secondaryBinding.agent.id)
479
469
  .replaceAll("{{secondaryDescription}}", secondaryBinding.agent.description);
480
470
  }
481
- async resolveSubagents(subagents) {
471
+ async resolveSubagents(subagents, binding) {
482
472
  return Promise.all(subagents.map(async (subagent) => ({
483
473
  ...subagent,
484
474
  model: subagent.model ? (await this.resolveModel(subagent.model)) : undefined,
@@ -488,6 +478,8 @@ export class AgentRuntimeAdapter {
488
478
  contextSchema: subagent.contextSchema,
489
479
  middleware: (await resolveDeclaredMiddleware(subagent.middleware, {
490
480
  resolveModel: (model) => this.resolveModel(model),
481
+ resolveCustom: this.options.declaredMiddlewareResolver,
482
+ binding,
491
483
  })),
492
484
  })));
493
485
  }
@@ -503,33 +495,22 @@ export class AgentRuntimeAdapter {
503
495
  model: model,
504
496
  tools: tools,
505
497
  systemPrompt: binding.langchainAgentParams.systemPrompt,
498
+ stateSchema: binding.langchainAgentParams.stateSchema,
506
499
  responseFormat: binding.langchainAgentParams.responseFormat,
507
500
  contextSchema: binding.langchainAgentParams.contextSchema,
508
501
  middleware: (await this.resolveMiddleware(binding, interruptOn)),
509
502
  checkpointer: this.resolveCheckpointer(binding),
503
+ store: this.options.storeResolver?.(binding),
504
+ includeAgentName: binding.langchainAgentParams.includeAgentName,
505
+ version: binding.langchainAgentParams.version,
506
+ name: binding.langchainAgentParams.name,
507
+ description: binding.langchainAgentParams.description,
510
508
  });
511
509
  }
512
510
  const params = binding.deepAgentParams;
513
511
  if (!params) {
514
512
  throw new Error(`Agent ${binding.agent.id} has no runnable params`);
515
513
  }
516
- if (this.canUseSimpleDeepAgentFastPath(binding)) {
517
- const interruptOn = this.resolveInterruptOn(binding);
518
- const model = (await this.resolveModel(params.model));
519
- const tools = this.resolveTools(params.tools, binding);
520
- if (tools.length > 0 && typeof model.bindTools !== "function") {
521
- throw new Error(`Agent ${binding.agent.id} configures ${tools.length} tool(s), but resolved model ${params.model.id} does not support tool binding.`);
522
- }
523
- return createAgent({
524
- model: model,
525
- tools: tools,
526
- systemPrompt: params.systemPrompt,
527
- responseFormat: params.responseFormat,
528
- contextSchema: params.contextSchema,
529
- middleware: (await this.resolveMiddleware(binding, interruptOn)),
530
- checkpointer: this.resolveCheckpointer(binding),
531
- });
532
- }
533
514
  const deepAgentConfig = {
534
515
  model: (await this.resolveModel(params.model)),
535
516
  tools: this.resolveTools(params.tools, binding),
@@ -537,7 +518,7 @@ export class AgentRuntimeAdapter {
537
518
  responseFormat: params.responseFormat,
538
519
  contextSchema: params.contextSchema,
539
520
  middleware: (await this.resolveMiddleware(binding)),
540
- subagents: (await this.resolveSubagents(params.subagents)),
521
+ subagents: (await this.resolveSubagents(params.subagents, binding)),
541
522
  checkpointer: this.resolveCheckpointer(binding),
542
523
  store: this.options.storeResolver?.(binding),
543
524
  backend: this.options.backendResolver?.(binding),
@@ -545,6 +526,8 @@ export class AgentRuntimeAdapter {
545
526
  name: params.name,
546
527
  memory: params.memory,
547
528
  skills: params.skills,
529
+ generalPurposeAgent: params.generalPurposeAgent,
530
+ taskDescription: params.taskDescription,
548
531
  };
549
532
  return createDeepAgent(deepAgentConfig);
550
533
  }
@@ -577,14 +560,14 @@ export class AgentRuntimeAdapter {
577
560
  ? secondaryBinding.agent.id
578
561
  : primaryBinding.agent.id;
579
562
  }
580
- async invoke(binding, input, threadId, runId, resumePayload, history = []) {
563
+ async invoke(binding, input, threadId, runId, resumePayload, history = [], options = {}) {
581
564
  const request = resumePayload === undefined
582
- ? { messages: this.buildAgentMessages(history, input) }
565
+ ? this.buildInvocationRequest(history, input, options)
583
566
  : new Command({ resume: resumePayload });
584
567
  let result;
585
568
  try {
586
569
  const runnable = await this.create(binding);
587
- result = (await this.withTimeout(() => runnable.invoke(request, { configurable: { thread_id: threadId } }), this.resolveBindingTimeout(binding), "agent invoke", "invoke"));
570
+ result = (await this.withTimeout(() => runnable.invoke(request, { configurable: { thread_id: threadId }, ...(options.context ? { context: options.context } : {}) }), this.resolveBindingTimeout(binding), "agent invoke", "invoke"));
588
571
  }
589
572
  catch (error) {
590
573
  if (resumePayload !== undefined || !isToolCallParseFailure(error)) {
@@ -592,7 +575,7 @@ export class AgentRuntimeAdapter {
592
575
  }
593
576
  const retriedBinding = this.applyStrictToolJsonInstruction(binding);
594
577
  const runnable = await this.create(retriedBinding);
595
- result = (await this.withTimeout(() => runnable.invoke({ messages: this.buildAgentMessages(history, input) }, { configurable: { thread_id: threadId } }), this.resolveBindingTimeout(retriedBinding), "agent invoke", "invoke"));
578
+ result = (await this.withTimeout(() => runnable.invoke(this.buildInvocationRequest(history, input, options), { configurable: { thread_id: threadId }, ...(options.context ? { context: options.context } : {}) }), this.resolveBindingTimeout(retriedBinding), "agent invoke", "invoke"));
596
579
  }
597
580
  const interruptContent = Array.isArray(result.__interrupt__) && result.__interrupt__.length > 0 ? JSON.stringify(result.__interrupt__) : undefined;
598
581
  const extractedOutput = extractVisibleOutput(result);
@@ -613,7 +596,7 @@ export class AgentRuntimeAdapter {
613
596
  output: sanitizeVisibleText(output),
614
597
  };
615
598
  }
616
- async *stream(binding, input, threadId, history = []) {
599
+ async *stream(binding, input, threadId, history = [], options = {}) {
617
600
  try {
618
601
  const invokeTimeoutMs = this.resolveBindingTimeout(binding);
619
602
  const streamIdleTimeoutMs = this.resolveStreamIdleTimeout(binding);
@@ -651,9 +634,9 @@ export class AgentRuntimeAdapter {
651
634
  }
652
635
  }
653
636
  const runnable = await this.create(binding);
654
- const request = { messages: this.buildAgentMessages(history, input) };
637
+ const request = this.buildInvocationRequest(history, input, options);
655
638
  if (typeof runnable.streamEvents === "function") {
656
- const events = await this.withTimeout(() => runnable.streamEvents(request, { configurable: { thread_id: threadId }, version: "v2" }), computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs), "agent streamEvents start", "stream");
639
+ const events = await this.withTimeout(() => runnable.streamEvents(request, { configurable: { thread_id: threadId }, version: "v2", ...(options.context ? { context: options.context } : {}) }), computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs), "agent streamEvents start", "stream");
657
640
  const allowVisibleStreamDeltas = Boolean(binding.langchainAgentParams);
658
641
  let emittedOutput = "";
659
642
  let emittedToolError = false;
@@ -46,7 +46,7 @@ export function readCheckpointMaintenanceConfig(workspace) {
46
46
  }
47
47
  function resolveSqliteCheckpointPath(binding) {
48
48
  const config = binding.harnessRuntime.checkpointer;
49
- if (!config) {
49
+ if (!config || typeof config === "boolean") {
50
50
  return null;
51
51
  }
52
52
  const kind = typeof config.kind === "string" ? config.kind : "FileCheckpointer";
@@ -1,4 +1,11 @@
1
- import type { CompiledModel } from "../contracts/types.js";
1
+ import type { CompiledAgentBinding, CompiledModel } from "../contracts/types.js";
2
2
  export declare function resolveDeclaredMiddleware(middlewareConfigs: unknown[] | undefined, options: {
3
3
  resolveModel: (model: CompiledModel) => Promise<unknown>;
4
+ resolveCustom?: (input: {
5
+ kind: string;
6
+ config: Record<string, unknown>;
7
+ binding?: CompiledAgentBinding;
8
+ resolveModel: (model: CompiledModel) => Promise<unknown>;
9
+ }) => unknown | unknown[] | null | undefined | Promise<unknown | unknown[] | null | undefined>;
10
+ binding?: CompiledAgentBinding;
4
11
  }): Promise<unknown[]>;
@@ -1,4 +1,4 @@
1
- import { modelCallLimitMiddleware, modelRetryMiddleware, summarizationMiddleware, todoListMiddleware, toolCallLimitMiddleware, toolRetryMiddleware, } from "langchain";
1
+ import { anthropicPromptCachingMiddleware, contextEditingMiddleware, llmToolSelectorMiddleware, modelCallLimitMiddleware, modelFallbackMiddleware, modelRetryMiddleware, openAIModerationMiddleware, summarizationMiddleware, todoListMiddleware, toolCallLimitMiddleware, toolEmulatorMiddleware, toolRetryMiddleware, } from "langchain";
2
2
  function asMiddlewareConfig(value) {
3
3
  return typeof value === "object" && value !== null && !Array.isArray(value) ? { ...value } : null;
4
4
  }
@@ -13,6 +13,18 @@ function omitKind(config) {
13
13
  const { kind: _kind, ...rest } = config;
14
14
  return rest;
15
15
  }
16
+ async function resolveReferencedModel(value, options) {
17
+ if (value && typeof value === "object" && "id" in value) {
18
+ return options.resolveModel(value);
19
+ }
20
+ return value;
21
+ }
22
+ async function resolveReferencedModelList(values, options) {
23
+ if (!Array.isArray(values)) {
24
+ return undefined;
25
+ }
26
+ return Promise.all(values.map((value) => resolveReferencedModel(value, options)));
27
+ }
16
28
  export async function resolveDeclaredMiddleware(middlewareConfigs, options) {
17
29
  const resolved = [];
18
30
  for (const rawConfig of middlewareConfigs ?? []) {
@@ -24,18 +36,29 @@ export async function resolveDeclaredMiddleware(middlewareConfigs, options) {
24
36
  const runtimeConfig = omitKind(config);
25
37
  switch (kind) {
26
38
  case "summarization": {
27
- if (runtimeConfig.model && typeof runtimeConfig.model === "object" && runtimeConfig.model !== null && "id" in runtimeConfig.model) {
28
- runtimeConfig.model = await options.resolveModel(runtimeConfig.model);
29
- }
39
+ runtimeConfig.model = await resolveReferencedModel(runtimeConfig.model, options);
30
40
  if (runtimeConfig.model === undefined) {
31
41
  throw new Error("summarization middleware requires model or modelRef");
32
42
  }
33
43
  resolved.push(summarizationMiddleware(runtimeConfig));
34
44
  break;
35
45
  }
46
+ case "llmToolSelector":
47
+ runtimeConfig.model = await resolveReferencedModel(runtimeConfig.model, options);
48
+ resolved.push(llmToolSelectorMiddleware(runtimeConfig));
49
+ break;
36
50
  case "modelRetry":
37
51
  resolved.push(modelRetryMiddleware(runtimeConfig));
38
52
  break;
53
+ case "modelFallback": {
54
+ const fallbackModels = (await resolveReferencedModelList(runtimeConfig.fallbackModels, options)) ??
55
+ (await resolveReferencedModelList(runtimeConfig.models, options));
56
+ if (!fallbackModels || fallbackModels.length === 0) {
57
+ throw new Error("modelFallback middleware requires fallbackModels or models");
58
+ }
59
+ resolved.push(modelFallbackMiddleware(...fallbackModels));
60
+ break;
61
+ }
39
62
  case "toolRetry":
40
63
  resolved.push(toolRetryMiddleware(runtimeConfig));
41
64
  break;
@@ -48,8 +71,37 @@ export async function resolveDeclaredMiddleware(middlewareConfigs, options) {
48
71
  case "todoList":
49
72
  resolved.push(todoListMiddleware(runtimeConfig));
50
73
  break;
51
- default:
74
+ case "contextEditing":
75
+ resolved.push(contextEditingMiddleware(runtimeConfig));
76
+ break;
77
+ case "toolEmulator":
78
+ resolved.push(toolEmulatorMiddleware(runtimeConfig));
79
+ break;
80
+ case "openAIModeration":
81
+ resolved.push(openAIModerationMiddleware(runtimeConfig));
82
+ break;
83
+ case "anthropicPromptCaching":
84
+ resolved.push(anthropicPromptCachingMiddleware(runtimeConfig));
85
+ break;
86
+ default: {
87
+ const customResolved = options.resolveCustom
88
+ ? await options.resolveCustom({
89
+ kind,
90
+ config: runtimeConfig,
91
+ binding: options.binding,
92
+ resolveModel: options.resolveModel,
93
+ })
94
+ : undefined;
95
+ if (Array.isArray(customResolved)) {
96
+ resolved.push(...customResolved);
97
+ break;
98
+ }
99
+ if (customResolved) {
100
+ resolved.push(customResolved);
101
+ break;
102
+ }
52
103
  throw new Error(`Unsupported declarative middleware kind ${kind}`);
104
+ }
53
105
  }
54
106
  }
55
107
  return resolved;
@@ -20,6 +20,10 @@ export declare class AgentHarnessRuntime {
20
20
  private readonly unregisterThreadMemorySync;
21
21
  private readonly resolvedRuntimeAdapterOptions;
22
22
  private readonly checkpointMaintenance;
23
+ private readonly recoveryConfig;
24
+ private readonly concurrencyConfig;
25
+ private activeRunSlots;
26
+ private readonly pendingRunSlots;
23
27
  private listHostBindings;
24
28
  private defaultRunRoot;
25
29
  private heuristicRoute;
@@ -53,8 +57,11 @@ export declare class AgentHarnessRuntime {
53
57
  private emit;
54
58
  private ensureThreadStarted;
55
59
  private loadPriorHistory;
60
+ private loadRunInput;
56
61
  private appendAssistantMessage;
57
62
  private invokeWithHistory;
63
+ private checkpointRefForState;
64
+ private finalizeContinuedRun;
58
65
  private emitOutputDeltaAndCreateItem;
59
66
  private emitRunCreated;
60
67
  private setRunStateAndEmit;
@@ -64,6 +71,7 @@ export declare class AgentHarnessRuntime {
64
71
  private resolveApprovalRecord;
65
72
  private isDecisionRun;
66
73
  private notifyListener;
74
+ private acquireRunSlot;
67
75
  private dispatchRunListeners;
68
76
  run(options: RunOptions): Promise<RunResult>;
69
77
  streamEvents(options: RunStartOptions): AsyncGenerator<HarnessStreamItem>;
@@ -73,5 +81,6 @@ export declare class AgentHarnessRuntime {
73
81
  }>;
74
82
  close(): Promise<void>;
75
83
  stop(): Promise<void>;
84
+ private recoverStartupRuns;
76
85
  }
77
86
  export { AgentHarnessRuntime as AgentHarness };