@botbotgo/agent-harness 0.0.106 → 0.0.108

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.105";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.107";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.105";
1
+ export const AGENT_HARNESS_VERSION = "0.0.107";
@@ -10,21 +10,4 @@ export declare function buildDeepAgentRunnableConfig(params: {
10
10
  resolvedBackend: unknown;
11
11
  resolvedInterruptOn: unknown;
12
12
  resolvedSkills: string[];
13
- }): {
14
- model: never;
15
- tools: never;
16
- systemPrompt: string | undefined;
17
- responseFormat: never;
18
- contextSchema: never;
19
- middleware: never;
20
- subagents: never;
21
- checkpointer: never;
22
- store: never;
23
- backend: never;
24
- interruptOn: never;
25
- name: string;
26
- memory: string[];
27
- skills: string[];
28
- generalPurposeAgent: boolean | undefined;
29
- taskDescription: string | undefined;
30
- };
13
+ }): Record<string, unknown>;
@@ -1,22 +1,29 @@
1
+ import { buildResolvedRunnableConfig } from "./runnable-config.js";
1
2
  export function buildDeepAgentRunnableConfig(params) {
2
3
  const { compatibleParams, resolvedModel, resolvedTools, resolvedMiddleware, resolvedSubagents, resolvedCheckpointer, resolvedStore, resolvedBackend, resolvedInterruptOn, resolvedSkills, } = params;
3
- return {
4
- ...(compatibleParams.passthrough ?? {}),
5
- model: resolvedModel,
6
- tools: resolvedTools,
7
- systemPrompt: compatibleParams.systemPrompt,
8
- responseFormat: compatibleParams.responseFormat,
9
- contextSchema: compatibleParams.contextSchema,
10
- middleware: resolvedMiddleware,
11
- subagents: resolvedSubagents,
12
- checkpointer: resolvedCheckpointer,
13
- store: resolvedStore,
14
- backend: resolvedBackend,
15
- interruptOn: resolvedInterruptOn,
16
- name: compatibleParams.name,
17
- memory: compatibleParams.memory,
18
- skills: resolvedSkills,
19
- generalPurposeAgent: compatibleParams.generalPurposeAgent,
20
- taskDescription: compatibleParams.taskDescription,
21
- };
4
+ return buildResolvedRunnableConfig({
5
+ passthrough: compatibleParams.passthrough ?? {},
6
+ staticConfig: {
7
+ systemPrompt: compatibleParams.systemPrompt,
8
+ responseFormat: compatibleParams.responseFormat,
9
+ contextSchema: compatibleParams.contextSchema,
10
+ name: compatibleParams.name,
11
+ memory: compatibleParams.memory,
12
+ skills: resolvedSkills,
13
+ generalPurposeAgent: compatibleParams.generalPurposeAgent,
14
+ taskDescription: compatibleParams.taskDescription,
15
+ },
16
+ resolved: {
17
+ resolvedModel: resolvedModel,
18
+ resolvedTools: resolvedTools,
19
+ resolvedMiddleware: resolvedMiddleware,
20
+ resolvedCheckpointer: resolvedCheckpointer,
21
+ resolvedStore: resolvedStore,
22
+ },
23
+ extraConfig: {
24
+ subagents: resolvedSubagents,
25
+ backend: resolvedBackend,
26
+ interruptOn: resolvedInterruptOn,
27
+ },
28
+ });
22
29
  }
@@ -0,0 +1,27 @@
1
+ import type { CompiledAgentBinding, CompiledTool } from "../../contracts/types.js";
2
+ import type { ToolNameMapping } from "./tool/tool-name-mapping.js";
3
+ import { getBindingPrimaryModel } from "../support/compiled-binding.js";
4
+ export declare function buildBindingToolExecutionContext(input: {
5
+ binding: CompiledAgentBinding;
6
+ resolveTools: (tools: CompiledTool[], binding?: CompiledAgentBinding) => unknown[];
7
+ getToolNameMapping: (binding: CompiledAgentBinding) => ToolNameMapping;
8
+ context?: Record<string, unknown>;
9
+ }): {
10
+ primaryTools: CompiledTool[];
11
+ resolvedTools: unknown[];
12
+ toolNameMapping: ToolNameMapping;
13
+ executableTools: Map<string, import("./invoke-runtime.js").ExecutableTool>;
14
+ defersToUpstreamHitlExecution: boolean;
15
+ };
16
+ export declare function resolveLangChainStreamContext(input: {
17
+ binding: CompiledAgentBinding;
18
+ resolveModel: (model: NonNullable<ReturnType<typeof getBindingPrimaryModel>>) => Promise<unknown>;
19
+ resolveTools: (tools: CompiledTool[], binding?: CompiledAgentBinding) => unknown[];
20
+ }): Promise<{
21
+ primaryTools: CompiledTool[];
22
+ forceInvokeFallback: boolean;
23
+ canUseDirectModelStream: boolean;
24
+ langChainStreamModel: {
25
+ stream?: (input: unknown) => Promise<AsyncIterable<unknown>>;
26
+ } | undefined;
27
+ }>;
@@ -0,0 +1,45 @@
1
+ import { buildExecutableToolMap } from "./tool-resolution.js";
2
+ import { getBindingLangChainParams, getBindingPrimaryModel, getBindingPrimaryTools, isLangChainBinding } from "../support/compiled-binding.js";
3
+ export function buildBindingToolExecutionContext(input) {
4
+ const primaryTools = getBindingPrimaryTools(input.binding);
5
+ const resolvedTools = input.resolveTools(primaryTools, input.binding);
6
+ const toolNameMapping = input.getToolNameMapping(input.binding);
7
+ const executableTools = buildExecutableToolMap({
8
+ primaryTools,
9
+ resolvedTools,
10
+ toolNameMapping,
11
+ context: input.context,
12
+ });
13
+ return {
14
+ primaryTools,
15
+ resolvedTools,
16
+ toolNameMapping,
17
+ executableTools,
18
+ defersToUpstreamHitlExecution: primaryTools.some((tool) => tool.hitl?.enabled === true),
19
+ };
20
+ }
21
+ export async function resolveLangChainStreamContext(input) {
22
+ const primaryTools = getBindingPrimaryTools(input.binding);
23
+ const primaryModel = getBindingPrimaryModel(input.binding);
24
+ const forceInvokeFallback = isLangChainBinding(input.binding) &&
25
+ primaryTools.length > 0 &&
26
+ primaryModel?.provider === "openai-compatible";
27
+ const langchainParams = isLangChainBinding(input.binding) ? getBindingLangChainParams(input.binding) : undefined;
28
+ const resolvedLangChainModel = langchainParams
29
+ ? (await input.resolveModel(langchainParams.model))
30
+ : undefined;
31
+ const resolvedLangChainTools = langchainParams ? input.resolveTools(langchainParams.tools, input.binding) : [];
32
+ const canUseDirectModelStream = !!resolvedLangChainModel &&
33
+ (resolvedLangChainTools.length === 0 || typeof resolvedLangChainModel.bindTools !== "function");
34
+ const langChainStreamModel = resolvedLangChainModel && canUseDirectModelStream
35
+ ? resolvedLangChainModel
36
+ : resolvedLangChainModel && typeof resolvedLangChainModel.bindTools === "function" && resolvedLangChainTools.length > 0
37
+ ? resolvedLangChainModel.bindTools(resolvedLangChainTools)
38
+ : undefined;
39
+ return {
40
+ primaryTools,
41
+ forceInvokeFallback,
42
+ canUseDirectModelStream,
43
+ langChainStreamModel,
44
+ };
45
+ }
@@ -8,18 +8,4 @@ export declare function buildLangChainRunnableConfig(params: {
8
8
  resolvedStore: unknown;
9
9
  passthroughOverride?: Record<string, unknown>;
10
10
  systemPromptOverride?: string;
11
- }): {
12
- model: never;
13
- tools: never;
14
- systemPrompt: string | undefined;
15
- stateSchema: never;
16
- responseFormat: never;
17
- contextSchema: never;
18
- middleware: never;
19
- checkpointer: never;
20
- store: never;
21
- includeAgentName: "inline" | undefined;
22
- version: "v1" | "v2" | undefined;
23
- name: string | undefined;
24
- description: string;
25
- };
11
+ }): Record<string, unknown>;
@@ -1,19 +1,24 @@
1
+ import { buildResolvedRunnableConfig } from "./runnable-config.js";
1
2
  export function buildLangChainRunnableConfig(params) {
2
3
  const { langchainParams, resolvedModel, resolvedTools, resolvedMiddleware, resolvedCheckpointer, resolvedStore, passthroughOverride, systemPromptOverride, } = params;
3
- return {
4
- ...(passthroughOverride ?? langchainParams.passthrough ?? {}),
5
- model: resolvedModel,
6
- tools: resolvedTools,
7
- systemPrompt: systemPromptOverride ?? langchainParams.systemPrompt,
8
- stateSchema: langchainParams.stateSchema,
9
- responseFormat: langchainParams.responseFormat,
10
- contextSchema: langchainParams.contextSchema,
11
- middleware: resolvedMiddleware,
12
- checkpointer: resolvedCheckpointer,
13
- store: resolvedStore,
14
- includeAgentName: langchainParams.includeAgentName,
15
- version: langchainParams.version,
16
- name: langchainParams.name,
17
- description: langchainParams.description,
18
- };
4
+ return buildResolvedRunnableConfig({
5
+ passthrough: (passthroughOverride ?? langchainParams.passthrough ?? {}),
6
+ staticConfig: {
7
+ systemPrompt: systemPromptOverride ?? langchainParams.systemPrompt,
8
+ stateSchema: langchainParams.stateSchema,
9
+ responseFormat: langchainParams.responseFormat,
10
+ contextSchema: langchainParams.contextSchema,
11
+ includeAgentName: langchainParams.includeAgentName,
12
+ version: langchainParams.version,
13
+ name: langchainParams.name,
14
+ description: langchainParams.description,
15
+ },
16
+ resolved: {
17
+ resolvedModel: resolvedModel,
18
+ resolvedTools: resolvedTools,
19
+ resolvedMiddleware: resolvedMiddleware,
20
+ resolvedCheckpointer: resolvedCheckpointer,
21
+ resolvedStore: resolvedStore,
22
+ },
23
+ });
19
24
  }
@@ -8,6 +8,28 @@ import { hasConfiguredMiddlewareKind, hasConfiguredSubagentSupport, isObject, is
8
8
  import { resolveDeclaredMiddleware } from "./tool/declared-middleware.js";
9
9
  import { getBindingDeepAgentParams, getBindingInterruptCompatibilityRules, getBindingLangChainParams, getBindingMiddlewareConfigs, getBindingPrimaryModel, isDeepAgentBinding, isLangChainBinding, } from "../support/compiled-binding.js";
10
10
  import { applyDeepAgentDelegationPromptCompatibility, materializeDeepAgentSkillSourcePaths } from "./compat/deepagent-compat.js";
11
+ function buildLangChainContextMiddleware(params) {
12
+ const middleware = [];
13
+ const hasSkills = (params.compatibleParams.skills?.length ?? 0) > 0;
14
+ const hasMemory = (params.compatibleParams.memory?.length ?? 0) > 0;
15
+ if (!hasSkills && !hasMemory) {
16
+ return middleware;
17
+ }
18
+ const backend = params.resolveFilesystemBackend(params.binding);
19
+ if (hasSkills) {
20
+ middleware.push(createSkillsMiddleware({
21
+ backend,
22
+ sources: params.compatibleParams.skills,
23
+ }));
24
+ }
25
+ if (hasMemory) {
26
+ middleware.push(createMemoryMiddleware({
27
+ backend,
28
+ sources: params.compatibleParams.memory,
29
+ }));
30
+ }
31
+ return middleware;
32
+ }
11
33
  export function resolveBuiltinMiddlewareBackend(input) {
12
34
  const runtimeState = {
13
35
  ...(input.options?.state ?? {}),
@@ -134,18 +156,11 @@ export async function resolveLangChainAutomaticMiddleware(input) {
134
156
  const automaticMiddleware = [];
135
157
  automaticMiddleware.push(createPatchToolCallsMiddleware());
136
158
  automaticMiddleware.push(...(await input.resolveAutomaticSummarizationMiddleware(input.binding)));
137
- if ((compatibleParams.skills?.length ?? 0) > 0) {
138
- automaticMiddleware.push(createSkillsMiddleware({
139
- backend: input.resolveFilesystemBackend(input.binding),
140
- sources: compatibleParams.skills,
141
- }));
142
- }
143
- if ((compatibleParams.memory?.length ?? 0) > 0) {
144
- automaticMiddleware.push(createMemoryMiddleware({
145
- backend: input.resolveFilesystemBackend(input.binding),
146
- sources: compatibleParams.memory,
147
- }));
148
- }
159
+ automaticMiddleware.push(...buildLangChainContextMiddleware({
160
+ binding: input.binding,
161
+ compatibleParams,
162
+ resolveFilesystemBackend: input.resolveFilesystemBackend,
163
+ }));
149
164
  if (hasConfiguredSubagentSupport(input.binding)) {
150
165
  automaticMiddleware.push(createSubAgentMiddleware({
151
166
  defaultModel: (await input.resolveModel(compatibleParams.model)),
@@ -0,0 +1,13 @@
1
+ export type ResolvedRunnableDependencies = {
2
+ resolvedModel: unknown;
3
+ resolvedTools: unknown[];
4
+ resolvedMiddleware: unknown[];
5
+ resolvedCheckpointer: unknown;
6
+ resolvedStore: unknown;
7
+ };
8
+ export declare function buildResolvedRunnableConfig(params: {
9
+ passthrough?: Record<string, unknown>;
10
+ staticConfig?: Record<string, unknown>;
11
+ resolved: ResolvedRunnableDependencies;
12
+ extraConfig?: Record<string, unknown>;
13
+ }): Record<string, unknown>;
@@ -0,0 +1,13 @@
1
+ export function buildResolvedRunnableConfig(params) {
2
+ const { passthrough, staticConfig, resolved, extraConfig } = params;
3
+ return {
4
+ ...(passthrough ?? {}),
5
+ ...(staticConfig ?? {}),
6
+ model: resolved.resolvedModel,
7
+ tools: resolved.resolvedTools,
8
+ middleware: resolved.resolvedMiddleware,
9
+ checkpointer: resolved.resolvedCheckpointer,
10
+ store: resolved.resolvedStore,
11
+ ...(extraConfig ?? {}),
12
+ };
13
+ }
@@ -1,6 +1,6 @@
1
- import { getBindingLangChainParams, getBindingMiddlewareConfigs, getBindingPrimaryTools } from "../support/compiled-binding.js";
1
+ import { getBindingExecutionView } from "../support/compiled-binding.js";
2
2
  export function countConfiguredTools(binding) {
3
- return getBindingPrimaryTools(binding).length;
3
+ return getBindingExecutionView(binding).primaryTools.length;
4
4
  }
5
5
  export function asObject(value) {
6
6
  return typeof value === "object" && value ? value : undefined;
@@ -9,14 +9,14 @@ export function sleep(ms) {
9
9
  return new Promise((resolve) => setTimeout(resolve, ms));
10
10
  }
11
11
  export function hasConfiguredSubagentSupport(binding) {
12
- const params = getBindingLangChainParams(binding);
12
+ const params = getBindingExecutionView(binding).langchainParams;
13
13
  if (!params) {
14
14
  return false;
15
15
  }
16
16
  return (params.subagents?.length ?? 0) > 0 || params.generalPurposeAgent === true || Boolean(params.taskDescription?.trim());
17
17
  }
18
18
  export function hasConfiguredMiddlewareKind(binding, kind) {
19
- return getBindingMiddlewareConfigs(binding)?.some((entry) => entry.kind === kind) ?? false;
19
+ return getBindingExecutionView(binding).middlewareConfigs?.some((entry) => entry.kind === kind) ?? false;
20
20
  }
21
21
  export function isRecord(value) {
22
22
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -15,6 +15,7 @@ export declare class AgentRuntimeAdapter {
15
15
  private readonly options;
16
16
  private readonly modelCache;
17
17
  private readonly runnableCache;
18
+ private readonly toolNameMappingCache;
18
19
  constructor(options?: RuntimeAdapterOptions);
19
20
  private getModelCacheKey;
20
21
  private invokeWithProviderRetry;
@@ -25,6 +26,7 @@ export declare class AgentRuntimeAdapter {
25
26
  private applyStrictToolJsonInstruction;
26
27
  private resolveModel;
27
28
  private resolveTools;
29
+ private getToolNameMapping;
28
30
  private resolveFilesystemBackend;
29
31
  private resolveBuiltinMiddlewareBackend;
30
32
  private createDeclaredMiddlewareResolverOptions;
@@ -17,12 +17,13 @@ import { createResolvedModel } from "./adapter/model/model-providers.js";
17
17
  import { buildInvocationRequest, } from "./adapter/model/invocation-request.js";
18
18
  import { compileInterruptOn } from "./adapter/tool/interrupt-policy.js";
19
19
  import { countConfiguredTools, } from "./adapter/runtime-adapter-support.js";
20
- import { buildExecutableToolMap, resolveAdapterTools } from "./adapter/tool-resolution.js";
20
+ import { resolveAdapterTools } from "./adapter/tool-resolution.js";
21
+ import { buildBindingToolExecutionContext, resolveLangChainStreamContext } from "./adapter/execution-context.js";
21
22
  export { applyDeepAgentDelegationPromptCompatibility, materializeDeepAgentSkillSourcePaths, relativizeDeepAgentSkillSourcePaths, shouldRelaxDeepAgentDelegationPrompt, } from "./adapter/compat/deepagent-compat.js";
22
23
  export { buildAuthOmittingFetch, normalizeOpenAICompatibleInit } from "./adapter/compat/openai-compatible.js";
23
24
  export { buildToolNameMapping, createModelFacingToolNameCandidates, createModelFacingToolNameLookupCandidates, resolveModelFacingToolName, sanitizeToolNameForModel, } from "./adapter/tool/tool-name-mapping.js";
24
25
  export { computeRemainingTimeoutMs, isRetryableProviderError, resolveBindingTimeout, resolveProviderRetryPolicy, resolveStreamIdleTimeout, resolveTimeoutMs, } from "./adapter/resilience.js";
25
- import { getBindingAdapterKind, getBindingDeepAgentParams, getBindingInterruptCompatibilityRules, getBindingLangChainParams, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSystemPrompt, isDeepAgentBinding, isLangChainBinding, } from "./support/compiled-binding.js";
26
+ import { getBindingAdapterKind, getBindingDeepAgentParams, getBindingInterruptCompatibilityRules, getBindingLangChainParams, getBindingPrimaryTools, getBindingSystemPrompt, isDeepAgentBinding, isLangChainBinding, } from "./support/compiled-binding.js";
26
27
  const AGENT_INTERRUPT_SENTINEL_PREFIX = "__agent_harness_interrupt__:";
27
28
  const UPSTREAM_BUILTIN_MIDDLEWARE_TOOL_NAMES = Object.freeze([
28
29
  "write_todos",
@@ -35,10 +36,17 @@ const UPSTREAM_BUILTIN_MIDDLEWARE_TOOL_NAMES = Object.freeze([
35
36
  "execute",
36
37
  "task",
37
38
  ]);
39
+ function resolveBindingCheckpointer(options, binding) {
40
+ return options.checkpointerResolver ? options.checkpointerResolver(binding) : new MemorySaver();
41
+ }
42
+ function resolveBindingInterruptOn(binding) {
43
+ return compileInterruptOn(getBindingPrimaryTools(binding), getBindingInterruptCompatibilityRules(binding));
44
+ }
38
45
  export class AgentRuntimeAdapter {
39
46
  options;
40
47
  modelCache = new Map();
41
48
  runnableCache = new WeakMap();
49
+ toolNameMappingCache = new WeakMap();
42
50
  constructor(options = {}) {
43
51
  this.options = options;
44
52
  }
@@ -93,6 +101,15 @@ export class AgentRuntimeAdapter {
93
101
  resolveToolValues: this.options.toolResolver,
94
102
  });
95
103
  }
104
+ getToolNameMapping(binding) {
105
+ const cached = this.toolNameMappingCache.get(binding);
106
+ if (cached) {
107
+ return cached;
108
+ }
109
+ const resolved = buildToolNameMapping(getBindingPrimaryTools(binding));
110
+ this.toolNameMappingCache.set(binding, resolved);
111
+ return resolved;
112
+ }
96
113
  resolveFilesystemBackend(binding) {
97
114
  const filesystemConfig = getBindingLangChainParams(binding)?.filesystem;
98
115
  const configuredRootDir = typeof filesystemConfig?.rootDir === "string" && filesystemConfig.rootDir.trim().length > 0
@@ -188,7 +205,7 @@ export class AgentRuntimeAdapter {
188
205
  }
189
206
  async createLangChainRunnable(binding, options = {}) {
190
207
  const params = getBindingLangChainParams(binding);
191
- const interruptOn = compileInterruptOn(getBindingPrimaryTools(binding), getBindingInterruptCompatibilityRules(binding));
208
+ const interruptOn = resolveBindingInterruptOn(binding);
192
209
  const model = (await this.resolveModel(params.model));
193
210
  const tools = this.resolveTools(params.tools, binding);
194
211
  if (tools.length > 0 && typeof model.bindTools !== "function") {
@@ -199,7 +216,7 @@ export class AgentRuntimeAdapter {
199
216
  resolvedModel: model,
200
217
  resolvedTools: tools,
201
218
  resolvedMiddleware: await this.resolveMiddleware(binding, interruptOn),
202
- resolvedCheckpointer: this.options.checkpointerResolver ? this.options.checkpointerResolver(binding) : new MemorySaver(),
219
+ resolvedCheckpointer: resolveBindingCheckpointer(this.options, binding),
203
220
  resolvedStore: this.options.storeResolver?.(binding),
204
221
  passthroughOverride: options.passthroughOverride,
205
222
  systemPromptOverride: options.systemPromptOverride,
@@ -226,10 +243,10 @@ export class AgentRuntimeAdapter {
226
243
  resolvedTools: this.resolveTools(compatibleParams.tools, binding),
227
244
  resolvedMiddleware: await this.resolveMiddleware(binding),
228
245
  resolvedSubagents: await this.resolveSubagents(compatibleParams.subagents, binding),
229
- resolvedCheckpointer: this.options.checkpointerResolver ? this.options.checkpointerResolver(binding) : new MemorySaver(),
246
+ resolvedCheckpointer: resolveBindingCheckpointer(this.options, binding),
230
247
  resolvedStore: this.options.storeResolver?.(binding),
231
248
  resolvedBackend: this.options.backendResolver?.(binding),
232
- resolvedInterruptOn: compileInterruptOn(getBindingPrimaryTools(binding), getBindingInterruptCompatibilityRules(binding)),
249
+ resolvedInterruptOn: resolveBindingInterruptOn(binding),
233
250
  resolvedSkills: (await materializeDeepAgentSkillSourcePaths({
234
251
  workspaceRoot: binding.harnessRuntime.workspaceRoot,
235
252
  runRoot: binding.harnessRuntime.runRoot,
@@ -272,13 +289,10 @@ export class AgentRuntimeAdapter {
272
289
  callRuntime,
273
290
  });
274
291
  };
275
- const primaryTools = getBindingPrimaryTools(binding);
276
- const resolvedTools = this.resolveTools(primaryTools, binding);
277
- const toolNameMapping = buildToolNameMapping(primaryTools);
278
- const executableTools = buildExecutableToolMap({
279
- primaryTools,
280
- resolvedTools,
281
- toolNameMapping,
292
+ const { primaryTools, toolNameMapping, executableTools, defersToUpstreamHitlExecution, } = buildBindingToolExecutionContext({
293
+ binding,
294
+ resolveTools: (tools, currentBinding) => this.resolveTools(tools, currentBinding),
295
+ getToolNameMapping: (currentBinding) => this.getToolNameMapping(currentBinding),
282
296
  context: options.context,
283
297
  });
284
298
  const builtinExecutableTools = await this.resolveBuiltinMiddlewareTools(binding, options);
@@ -287,7 +301,7 @@ export class AgentRuntimeAdapter {
287
301
  request,
288
302
  resumePayload,
289
303
  primaryTools,
290
- defersToUpstreamHitlExecution: primaryTools.some((tool) => tool.hitl?.enabled === true),
304
+ defersToUpstreamHitlExecution,
291
305
  toolNameMapping,
292
306
  executableTools,
293
307
  builtinExecutableTools: builtinExecutableTools,
@@ -310,24 +324,16 @@ export class AgentRuntimeAdapter {
310
324
  const invokeTimeoutMs = resolveBindingTimeout(binding);
311
325
  const streamIdleTimeoutMs = resolveStreamIdleTimeout(binding);
312
326
  const streamDeadlineAt = invokeTimeoutMs ? Date.now() + invokeTimeoutMs : undefined;
313
- const primaryTools = getBindingPrimaryTools(binding);
314
- const toolNameMapping = buildToolNameMapping(primaryTools);
315
- const primaryModel = getBindingPrimaryModel(binding);
316
- const forceInvokeFallback = isLangChainBinding(binding) &&
317
- primaryTools.length > 0 &&
318
- primaryModel?.provider === "openai-compatible";
319
- const langchainParams = isLangChainBinding(binding) ? getBindingLangChainParams(binding) : undefined;
320
- const resolvedLangChainModel = langchainParams
321
- ? (await this.resolveModel(langchainParams.model))
322
- : undefined;
323
- const resolvedLangChainTools = langchainParams ? this.resolveTools(langchainParams.tools, binding) : [];
324
- const canUseDirectModelStream = !!resolvedLangChainModel &&
325
- (resolvedLangChainTools.length === 0 || typeof resolvedLangChainModel.bindTools !== "function");
326
- const langChainStreamModel = resolvedLangChainModel && canUseDirectModelStream
327
- ? resolvedLangChainModel
328
- : resolvedLangChainModel && typeof resolvedLangChainModel.bindTools === "function" && resolvedLangChainTools.length > 0
329
- ? resolvedLangChainModel.bindTools(resolvedLangChainTools)
330
- : undefined;
327
+ const { primaryTools, toolNameMapping } = buildBindingToolExecutionContext({
328
+ binding,
329
+ resolveTools: (tools, currentBinding) => this.resolveTools(tools, currentBinding),
330
+ getToolNameMapping: (currentBinding) => this.getToolNameMapping(currentBinding),
331
+ });
332
+ const { forceInvokeFallback, canUseDirectModelStream, langChainStreamModel, } = await resolveLangChainStreamContext({
333
+ binding,
334
+ resolveModel: (model) => this.resolveModel(model),
335
+ resolveTools: (tools, currentBinding) => this.resolveTools(tools, currentBinding),
336
+ });
331
337
  yield* streamRuntimeExecution({
332
338
  binding,
333
339
  input,
@@ -0,0 +1,13 @@
1
+ import type { HarnessEvent } from "../../contracts/types.js";
2
+ import type { RuntimePersistence } from "../../persistence/types.js";
3
+ export declare function createBackgroundEventRuntime(input: {
4
+ persistence: RuntimePersistence;
5
+ publishEvent: (event: HarnessEvent) => void;
6
+ trackBackgroundTask: (task: Promise<void>) => void;
7
+ backgroundEventTypes: ReadonlySet<HarnessEvent["eventType"]>;
8
+ }): {
9
+ persistence: RuntimePersistence;
10
+ publishEvent: (event: HarnessEvent) => void;
11
+ trackBackgroundTask: (task: Promise<void>) => void;
12
+ backgroundEventTypes: ReadonlySet<import("../../contracts/runtime.js").HarnessEventType>;
13
+ };
@@ -0,0 +1,8 @@
1
+ export function createBackgroundEventRuntime(input) {
2
+ return {
3
+ persistence: input.persistence,
4
+ publishEvent: input.publishEvent,
5
+ trackBackgroundTask: input.trackBackgroundTask,
6
+ backgroundEventTypes: input.backgroundEventTypes,
7
+ };
8
+ }
@@ -0,0 +1,14 @@
1
+ import type { CompiledTool, RuntimeAdapterOptions, WorkspaceBundle } from "../../contracts/types.js";
2
+ type Binding = WorkspaceBundle["bindings"] extends Map<any, infer T> ? T : never;
3
+ export declare function getWorkspaceBinding(workspace: WorkspaceBundle, agentId: string): Binding | undefined;
4
+ export declare function getRequiredWorkspaceBinding(workspace: WorkspaceBundle, agentId: string): Binding;
5
+ export declare function resolveWorkspaceAgentTools(input: {
6
+ workspace: WorkspaceBundle;
7
+ agentId: string;
8
+ toolResolver?: RuntimeAdapterOptions["toolResolver"];
9
+ }): Array<{
10
+ compiledTool: CompiledTool;
11
+ resolvedTool: unknown;
12
+ }>;
13
+ export declare function bindingSupportsRunningReplay(binding: Binding): boolean;
14
+ export {};
@@ -0,0 +1,23 @@
1
+ import { getBindingPrimaryTools } from "../support/compiled-binding.js";
2
+ export function getWorkspaceBinding(workspace, agentId) {
3
+ return workspace.bindings.get(agentId);
4
+ }
5
+ export function getRequiredWorkspaceBinding(workspace, agentId) {
6
+ const binding = getWorkspaceBinding(workspace, agentId);
7
+ if (!binding) {
8
+ throw new Error(`Unknown agent ${agentId}`);
9
+ }
10
+ return binding;
11
+ }
12
+ export function resolveWorkspaceAgentTools(input) {
13
+ const binding = getRequiredWorkspaceBinding(input.workspace, input.agentId);
14
+ const compiledTools = getBindingPrimaryTools(binding);
15
+ const resolvedTools = input.toolResolver ? input.toolResolver(compiledTools.map((tool) => tool.id), binding) : [];
16
+ return compiledTools.map((compiledTool, index) => ({
17
+ compiledTool,
18
+ resolvedTool: resolvedTools[index],
19
+ }));
20
+ }
21
+ export function bindingSupportsRunningReplay(binding) {
22
+ return getBindingPrimaryTools(binding).every((tool) => tool.retryable === true);
23
+ }
@@ -2,7 +2,7 @@ import { createCheckpointerForConfig, createStoreForConfig } from "../../support
2
2
  import { resolveCompiledEmbeddingModel, resolveCompiledEmbeddingModelRef } from "../../support/embedding-models.js";
3
3
  import { resolveCompiledVectorStore, resolveCompiledVectorStoreRef } from "../../support/vector-stores.js";
4
4
  export function resolveStoreFromConfig(stores, storeConfig, runRoot) {
5
- const cacheKey = storeConfig ? JSON.stringify(storeConfig) : undefined;
5
+ const cacheKey = storeConfig ? `${runRoot}:${JSON.stringify(storeConfig)}` : undefined;
6
6
  if (!storeConfig || !cacheKey) {
7
7
  return undefined;
8
8
  }
@@ -14,6 +14,9 @@ export declare class AgentHarnessRuntime {
14
14
  private readonly stores;
15
15
  private readonly embeddingModels;
16
16
  private readonly vectorStores;
17
+ private readonly hostBindings;
18
+ private readonly defaultHostBinding?;
19
+ private readonly defaultRunRootValue;
17
20
  private readonly defaultStore;
18
21
  private readonly runtimeMemoryStore;
19
22
  private readonly routingRules;
@@ -30,7 +33,7 @@ export declare class AgentHarnessRuntime {
30
33
  private pendingRunInsertionOrder;
31
34
  private readonly pendingRunSlots;
32
35
  private runtimeEventSequence;
33
- private listHostBindings;
36
+ private readonly backgroundEventRuntime;
34
37
  private defaultRunRoot;
35
38
  private getDefaultHostAgentId;
36
39
  private resolveSelectedAgentId;
@@ -41,8 +44,6 @@ export declare class AgentHarnessRuntime {
41
44
  initialize(): Promise<void>;
42
45
  subscribe(listener: (event: HarnessEvent) => void): () => void;
43
46
  getHealth(): Promise<RuntimeHealthSnapshot>;
44
- private resolveAgentTools;
45
- private supportsRunningReplay;
46
47
  listThreads(filter?: {
47
48
  agentId?: string;
48
49
  }): Promise<ThreadSummary[]>;
@@ -89,7 +90,6 @@ export declare class AgentHarnessRuntime {
89
90
  private isDecisionRun;
90
91
  private notifyListener;
91
92
  private prepareRunStart;
92
- private createStartupRecoveryContext;
93
93
  private acquireRunSlot;
94
94
  private dropPendingRunSlot;
95
95
  private dispatchRunListeners;
@@ -4,6 +4,7 @@ import { createPersistentId } from "../utils/id.js";
4
4
  import { AgentRuntimeAdapter } from "./agent-runtime-adapter.js";
5
5
  import { createResourceBackendResolver, createResourceToolResolver } from "../resource/resource.js";
6
6
  import { EventBus } from "./harness/events/event-bus.js";
7
+ import { createBackgroundEventRuntime } from "./harness/background-runtime.js";
7
8
  import { PolicyEngine } from "./harness/system/policy-engine.js";
8
9
  import { getConcurrencyConfig, getRecoveryConfig, getRoutingDefaultAgentId, getRoutingRules, matchRoutingRule, } from "../workspace/support/workspace-ref-utils.js";
9
10
  import { createHarnessEvent, inferRoutingBindings, renderRuntimeFailure, } from "./support/harness-support.js";
@@ -22,7 +23,8 @@ import { dropPendingRunSlot, enqueuePendingRunSlot } from "./harness/run/run-que
22
23
  import { getDefaultHostAgentId, resolveSelectedAgentId } from "./harness/run/routing.js";
23
24
  import { resolveCheckpointer, resolveEmbeddingModel, resolveStore, resolveStoreFromConfig, resolveVectorStore, } from "./harness/run/resources.js";
24
25
  import { createToolMcpServerFromTools, serveToolsOverStdioFromHarness } from "../mcp.js";
25
- import { getBindingAdapterKind, getBindingPrimaryTools, getBindingStoreConfig } from "./support/compiled-binding.js";
26
+ import { getBindingAdapterKind, getBindingStoreConfig } from "./support/compiled-binding.js";
27
+ import { getRequiredWorkspaceBinding, getWorkspaceBinding, resolveWorkspaceAgentTools, } from "./harness/bindings.js";
26
28
  import { describeWorkspaceInventory, listAgentSkills as listWorkspaceAgentSkills, } from "./harness/system/inventory.js";
27
29
  import { createDefaultHealthSnapshot, isInventoryEnabled, isThreadMemorySyncEnabled, } from "./harness/runtime-defaults.js";
28
30
  import { initializeHarnessRuntime, isStaleRunningRun as isHarnessStaleRunningRun, } from "./harness/run/startup-runtime.js";
@@ -46,6 +48,9 @@ export class AgentHarnessRuntime {
46
48
  stores = new Map();
47
49
  embeddingModels = new Map();
48
50
  vectorStores = new Map();
51
+ hostBindings;
52
+ defaultHostBinding;
53
+ defaultRunRootValue;
49
54
  defaultStore;
50
55
  runtimeMemoryStore;
51
56
  routingRules;
@@ -62,12 +67,9 @@ export class AgentHarnessRuntime {
62
67
  pendingRunInsertionOrder = 0;
63
68
  pendingRunSlots = [];
64
69
  runtimeEventSequence = 0;
65
- listHostBindings() {
66
- return inferRoutingBindings(this.workspace).hostBindings;
67
- }
70
+ backgroundEventRuntime;
68
71
  defaultRunRoot() {
69
- return (this.listHostBindings()[0]?.harnessRuntime.runRoot ??
70
- `${this.workspace.workspaceRoot}/run-data`);
72
+ return this.defaultRunRootValue;
71
73
  }
72
74
  getDefaultHostAgentId() {
73
75
  return getDefaultHostAgentId(this.workspace, this.routingDefaultAgentId);
@@ -85,13 +87,16 @@ export class AgentHarnessRuntime {
85
87
  constructor(workspace, runtimeAdapterOptions = {}) {
86
88
  this.workspace = workspace;
87
89
  this.runtimeAdapterOptions = runtimeAdapterOptions;
90
+ this.hostBindings = inferRoutingBindings(this.workspace).hostBindings;
91
+ this.defaultHostBinding = this.hostBindings[0];
92
+ this.defaultRunRootValue = this.defaultHostBinding?.harnessRuntime.runRoot ?? `${this.workspace.workspaceRoot}/run-data`;
88
93
  const runRoot = this.defaultRunRoot();
89
94
  this.persistence = new SqlitePersistence(runRoot);
90
- const defaultStoreConfig = this.listHostBindings()[0]?.harnessRuntime.store;
95
+ const defaultStoreConfig = this.defaultHostBinding?.harnessRuntime.store;
91
96
  this.defaultStore = resolveStoreFromConfig(this.stores, defaultStoreConfig, runRoot) ?? new FileBackedStore(`${runRoot}/store.json`);
92
- const runtimeMemoryStoreConfig = typeof this.listHostBindings()[0]?.harnessRuntime.runtimeMemory?.store === "object" &&
93
- this.listHostBindings()[0]?.harnessRuntime.runtimeMemory?.store
94
- ? this.listHostBindings()[0]?.harnessRuntime.runtimeMemory?.store
97
+ const runtimeMemoryStoreConfig = typeof this.defaultHostBinding?.harnessRuntime.runtimeMemory?.store === "object" &&
98
+ this.defaultHostBinding?.harnessRuntime.runtimeMemory?.store
99
+ ? this.defaultHostBinding.harnessRuntime.runtimeMemory.store
95
100
  : undefined;
96
101
  this.runtimeMemoryStore = resolveStoreFromConfig(this.stores, runtimeMemoryStoreConfig, runRoot) ?? this.defaultStore;
97
102
  this.resolvedRuntimeAdapterOptions = {
@@ -110,6 +115,12 @@ export class AgentHarnessRuntime {
110
115
  ((binding) => createResourceBackendResolver(workspace)(binding)),
111
116
  };
112
117
  this.runtimeAdapter = new AgentRuntimeAdapter(this.resolvedRuntimeAdapterOptions);
118
+ this.backgroundEventRuntime = createBackgroundEventRuntime({
119
+ persistence: this.persistence,
120
+ publishEvent: (event) => this.eventBus.publish(event),
121
+ trackBackgroundTask: (task) => this.trackBackgroundTask(task),
122
+ backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
123
+ });
113
124
  this.routingRules = getRoutingRules(workspace.refs);
114
125
  this.routingDefaultAgentId = getRoutingDefaultAgentId(workspace.refs);
115
126
  if (isThreadMemorySyncEnabled(workspace)) {
@@ -159,23 +170,6 @@ export class AgentHarnessRuntime {
159
170
  }
160
171
  return createDefaultHealthSnapshot(this.activeRunSlots, this.pendingRunSlots.length);
161
172
  }
162
- resolveAgentTools(agentId) {
163
- const binding = this.workspace.bindings.get(agentId);
164
- if (!binding) {
165
- throw new Error(`Unknown agent ${agentId}`);
166
- }
167
- const compiledTools = getBindingPrimaryTools(binding);
168
- const resolver = this.resolvedRuntimeAdapterOptions.toolResolver;
169
- const resolvedTools = resolver ? resolver(compiledTools.map((tool) => tool.id), binding) : [];
170
- return compiledTools.map((compiledTool, index) => ({
171
- compiledTool,
172
- resolvedTool: resolvedTools[index],
173
- }));
174
- }
175
- supportsRunningReplay(binding) {
176
- const tools = getBindingPrimaryTools(binding);
177
- return tools.every((tool) => tool.retryable === true);
178
- }
179
173
  async listThreads(filter) {
180
174
  return this.persistence.listSessions(filter);
181
175
  }
@@ -242,7 +236,11 @@ export class AgentHarnessRuntime {
242
236
  }, threadId);
243
237
  }
244
238
  async createToolMcpServer(options) {
245
- const tools = this.resolveAgentTools(options.agentId).map(({ compiledTool, resolvedTool }) => ({
239
+ const tools = resolveWorkspaceAgentTools({
240
+ workspace: this.workspace,
241
+ agentId: options.agentId,
242
+ toolResolver: this.resolvedRuntimeAdapterOptions.toolResolver,
243
+ }).map(({ compiledTool, resolvedTool }) => ({
246
244
  compiledTool,
247
245
  resolvedTool,
248
246
  sourceTool: this.workspace.tools.get(compiledTool.id),
@@ -250,7 +248,11 @@ export class AgentHarnessRuntime {
250
248
  return createToolMcpServerFromTools(tools, options);
251
249
  }
252
250
  async serveToolsOverStdio(options) {
253
- const tools = this.resolveAgentTools(options.agentId).map(({ compiledTool, resolvedTool }) => ({
251
+ const tools = resolveWorkspaceAgentTools({
252
+ workspace: this.workspace,
253
+ agentId: options.agentId,
254
+ toolResolver: this.resolvedRuntimeAdapterOptions.toolResolver,
255
+ }).map(({ compiledTool, resolvedTool }) => ({
254
256
  compiledTool,
255
257
  resolvedTool,
256
258
  sourceTool: this.workspace.tools.get(compiledTool.id),
@@ -261,13 +263,13 @@ export class AgentHarnessRuntime {
261
263
  const rawInput = extractMessageText(input);
262
264
  const configuredRule = this.routingRules.find((rule) => matchRoutingRule(rawInput, rule, options));
263
265
  if (configuredRule) {
264
- const configuredBinding = this.workspace.bindings.get(configuredRule.agentId);
266
+ const configuredBinding = getWorkspaceBinding(this.workspace, configuredRule.agentId);
265
267
  if (configuredBinding) {
266
268
  return configuredBinding.agent.id;
267
269
  }
268
270
  }
269
271
  const defaultBinding = this.routingDefaultAgentId
270
- ? this.workspace.bindings.get(this.routingDefaultAgentId)
272
+ ? getWorkspaceBinding(this.workspace, this.routingDefaultAgentId)
271
273
  : undefined;
272
274
  if (defaultBinding) {
273
275
  return defaultBinding.agent.id;
@@ -430,10 +432,7 @@ export class AgentHarnessRuntime {
430
432
  }
431
433
  catch (error) {
432
434
  await emitSyntheticFallbackEvent({
433
- persistence: this.persistence,
434
- publishEvent: (event) => this.eventBus.publish(event),
435
- trackBackgroundTask: (task) => this.trackBackgroundTask(task),
436
- backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
435
+ ...this.backgroundEventRuntime,
437
436
  }, threadId, runId, agentId, error, 103);
438
437
  await this.setRunStateAndEmit(threadId, runId, 104, "failed", {
439
438
  previousState: previousState === "queued" ? "running" : previousState,
@@ -461,18 +460,12 @@ export class AgentHarnessRuntime {
461
460
  }
462
461
  async setRunStateAndEmit(threadId, runId, sequence, state, options) {
463
462
  return setRunStateAndEmitEvent({
464
- persistence: this.persistence,
465
- publishEvent: (event) => this.eventBus.publish(event),
466
- trackBackgroundTask: (task) => this.trackBackgroundTask(task),
467
- backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
463
+ ...this.backgroundEventRuntime,
468
464
  }, threadId, runId, sequence, state, options);
469
465
  }
470
466
  async requestApprovalAndEmit(threadId, runId, input, interruptContent, checkpointRef, sequence) {
471
467
  return requestApprovalAndEmitEvent({
472
- persistence: this.persistence,
473
- publishEvent: (event) => this.eventBus.publish(event),
474
- trackBackgroundTask: (task) => this.trackBackgroundTask(task),
475
- backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
468
+ ...this.backgroundEventRuntime,
476
469
  }, threadId, runId, input, interruptContent, checkpointRef, sequence);
477
470
  }
478
471
  isDecisionRun(options) {
@@ -486,10 +479,7 @@ export class AgentHarnessRuntime {
486
479
  }
487
480
  async prepareRunStart(options, invocation, runCreatedPayload) {
488
481
  const selectedAgentId = await this.resolveSelectedAgentId(options.input, options.agentId, options.threadId);
489
- const binding = this.workspace.bindings.get(selectedAgentId);
490
- if (!binding) {
491
- throw new Error(`Unknown agent ${selectedAgentId}`);
492
- }
482
+ const binding = getRequiredWorkspaceBinding(this.workspace, selectedAgentId);
493
483
  const policyDecision = this.policyEngine.evaluate(binding);
494
484
  if (!policyDecision.allowed) {
495
485
  throw new Error(`Policy evaluation blocked agent ${selectedAgentId}: ${policyDecision.reasons.join(", ")}`);
@@ -505,34 +495,11 @@ export class AgentHarnessRuntime {
505
495
  runId,
506
496
  isNewThread,
507
497
  runCreatedEventPromise: emitRunCreatedEvent({
508
- persistence: this.persistence,
509
- publishEvent: (event) => this.eventBus.publish(event),
510
- trackBackgroundTask: (task) => this.trackBackgroundTask(task),
511
- backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
498
+ ...this.backgroundEventRuntime,
512
499
  }, threadId, runId, runCreatedPayload(binding, selectedAgentId)),
513
500
  releaseRunSlotPromise: this.acquireRunSlot(threadId, runId, "running", priority),
514
501
  };
515
502
  }
516
- createStartupRecoveryContext() {
517
- return {
518
- persistence: this.persistence,
519
- workspace: this.workspace,
520
- runtimeAdapter: this.runtimeAdapter,
521
- recoveryConfig: this.recoveryConfig,
522
- concurrencyConfig: this.concurrencyConfig,
523
- getBinding: (agentId) => this.workspace.bindings.get(agentId),
524
- acquireRunSlot: (threadId, runId, activeState = "running", priority = 0) => this.acquireRunSlot(threadId, runId, activeState, priority),
525
- executeQueuedRun: (binding, input, threadId, runId, agentId, options = {}) => this.executeQueuedRun(binding, input, threadId, runId, agentId, options),
526
- setRunStateAndEmit: (threadId, runId, sequence, state, options) => this.setRunStateAndEmit(threadId, runId, sequence, state, options),
527
- emit: (threadId, runId, sequence, eventType, payload) => this.emit(threadId, runId, sequence, eventType, payload),
528
- loadRunInput: (threadId, runId) => this.loadRunInput(threadId, runId),
529
- finalizeContinuedRun: (binding, threadId, runId, input, actual, options) => this.finalizeContinuedRun(binding, threadId, runId, input, actual, options),
530
- supportsRunningReplay: (binding) => this.supportsRunningReplay(binding),
531
- isStaleRunningRun: (thread, nowMs = Date.now()) => this.isStaleRunningRun(thread, nowMs),
532
- recordLlmSuccess: (startedAt) => this.recordLlmSuccess(startedAt),
533
- recordLlmFailure: (startedAt) => this.recordLlmFailure(startedAt),
534
- };
535
- }
536
503
  async acquireRunSlot(threadId, runId, activeState = "running", priority = 0) {
537
504
  return acquireHarnessRunSlot({
538
505
  persistence: this.persistence,
@@ -604,7 +571,7 @@ export class AgentHarnessRuntime {
604
571
  async *streamEvents(options) {
605
572
  const invocation = normalizeInvocationEnvelope(options);
606
573
  const selectedAgentId = await this.resolveSelectedAgentId(options.input, options.agentId, options.threadId);
607
- const binding = this.workspace.bindings.get(selectedAgentId);
574
+ const binding = getWorkspaceBinding(this.workspace, selectedAgentId);
608
575
  if (!binding) {
609
576
  const result = await this.run(options);
610
577
  for (const line of result.output.split("\n")) {
@@ -644,10 +611,7 @@ export class AgentHarnessRuntime {
644
611
  appendAssistantMessage: (currentThreadId, currentRunId, content) => appendLifecycleAssistantMessage(this.persistence, currentThreadId, currentRunId, content),
645
612
  clearRunRequest: (currentThreadId, currentRunId) => this.persistence.clearRunRequest(currentThreadId, currentRunId),
646
613
  emitSyntheticFallback: (currentThreadId, currentRunId, currentSelectedAgentId, error) => emitSyntheticFallbackEvent({
647
- persistence: this.persistence,
648
- publishEvent: (event) => this.eventBus.publish(event),
649
- trackBackgroundTask: (task) => this.trackBackgroundTask(task),
650
- backgroundEventTypes: AgentHarnessRuntime.BACKGROUND_EVENT_TYPES,
614
+ ...this.backgroundEventRuntime,
651
615
  }, currentThreadId, currentRunId, currentSelectedAgentId, error),
652
616
  });
653
617
  }
@@ -656,7 +620,7 @@ export class AgentHarnessRuntime {
656
620
  getApprovalById: (approvalId) => this.persistence.getApproval(approvalId),
657
621
  getSession: (threadId) => this.getSession(threadId),
658
622
  resolveApprovalRecord: (resumeOptions, thread) => resolveHarnessApprovalRecord(this.persistence, resumeOptions, thread),
659
- getBinding: (agentId) => this.workspace.bindings.get(agentId),
623
+ getBinding: (agentId) => getWorkspaceBinding(this.workspace, agentId),
660
624
  buildResumePayload: (binding, approval, resumeOptions) => buildHarnessResumePayload(binding, approval, resumeOptions),
661
625
  getRunCancellation: (runId) => this.getRunCancellation(runId),
662
626
  finalizeCancelledRun: (threadId, runId, previousState, reason) => this.finalizeCancelledRun(threadId, runId, previousState, reason),
@@ -1,4 +1,18 @@
1
1
  import type { CompiledAgentBinding, CompiledModel, CompiledTool, DeepAgentParams, LangChainAgentParams, RuntimeModelSlot } from "../../contracts/types.js";
2
+ export type BindingExecutionView = {
3
+ adapterKind: string;
4
+ adapterConfig: Record<string, unknown>;
5
+ langchainParams?: LangChainAgentParams;
6
+ deepAgentParams?: DeepAgentParams;
7
+ executionParams?: LangChainAgentParams | DeepAgentParams;
8
+ primaryTools: CompiledTool[];
9
+ primaryModel?: CompiledModel;
10
+ systemPrompt?: string;
11
+ middlewareConfigs?: Array<Record<string, unknown>>;
12
+ interruptCompatibilityRules?: Record<string, boolean | object>;
13
+ storeConfig?: Record<string, unknown>;
14
+ };
15
+ export declare function getBindingExecutionView(binding: CompiledAgentBinding): BindingExecutionView;
2
16
  export declare function getBindingAdapterKind(binding: CompiledAgentBinding): string;
3
17
  export declare function getBindingAdapterConfig(binding: CompiledAgentBinding): Record<string, unknown>;
4
18
  export declare function getBindingLangChainParams(binding: CompiledAgentBinding): LangChainAgentParams | undefined;
@@ -3,25 +3,53 @@ function asRecord(value) {
3
3
  ? value
4
4
  : undefined;
5
5
  }
6
+ const bindingExecutionViewCache = new WeakMap();
7
+ function deriveBindingExecutionView(binding) {
8
+ const cached = bindingExecutionViewCache.get(binding);
9
+ if (cached) {
10
+ return cached;
11
+ }
12
+ const adapterKind = binding.adapter?.kind ?? binding.agent.executionMode;
13
+ const adapterConfig = binding.adapter?.config ?? {};
14
+ const adapterParams = asRecord(adapterConfig.params);
15
+ const langchainParams = adapterKind === "langchain-v1" && adapterParams
16
+ ? adapterParams
17
+ : binding.langchainAgentParams;
18
+ const deepAgentParams = adapterKind === "deepagent" && adapterParams
19
+ ? adapterParams
20
+ : binding.deepAgentParams;
21
+ const primaryTools = langchainParams?.tools ?? deepAgentParams?.tools ?? [];
22
+ const view = {
23
+ adapterKind,
24
+ adapterConfig,
25
+ langchainParams,
26
+ deepAgentParams,
27
+ executionParams: langchainParams ?? deepAgentParams,
28
+ primaryTools,
29
+ primaryModel: langchainParams?.model ?? deepAgentParams?.model,
30
+ systemPrompt: langchainParams?.systemPrompt ?? deepAgentParams?.systemPrompt,
31
+ middlewareConfigs: langchainParams?.middleware ?? deepAgentParams?.middleware,
32
+ interruptCompatibilityRules: deepAgentParams?.interruptOn ??
33
+ binding.agent.langchainAgentConfig?.interruptOn,
34
+ storeConfig: deepAgentParams?.store ?? binding.harnessRuntime?.store,
35
+ };
36
+ bindingExecutionViewCache.set(binding, view);
37
+ return view;
38
+ }
39
+ export function getBindingExecutionView(binding) {
40
+ return deriveBindingExecutionView(binding);
41
+ }
6
42
  export function getBindingAdapterKind(binding) {
7
- return binding.adapter?.kind ?? binding.agent.executionMode;
43
+ return getBindingExecutionView(binding).adapterKind;
8
44
  }
9
45
  export function getBindingAdapterConfig(binding) {
10
- return binding.adapter?.config ?? {};
46
+ return getBindingExecutionView(binding).adapterConfig;
11
47
  }
12
48
  export function getBindingLangChainParams(binding) {
13
- const adapterParams = getBindingAdapterConfig(binding).params;
14
- if (getBindingAdapterKind(binding) === "langchain-v1" && typeof adapterParams === "object" && adapterParams && !Array.isArray(adapterParams)) {
15
- return adapterParams;
16
- }
17
- return binding.langchainAgentParams;
49
+ return getBindingExecutionView(binding).langchainParams;
18
50
  }
19
51
  export function getBindingDeepAgentParams(binding) {
20
- const adapterParams = asRecord(getBindingAdapterConfig(binding).params);
21
- if (getBindingAdapterKind(binding) === "deepagent" && adapterParams) {
22
- return adapterParams;
23
- }
24
- return binding.deepAgentParams;
52
+ return getBindingExecutionView(binding).deepAgentParams;
25
53
  }
26
54
  export function isLangChainBinding(binding) {
27
55
  return getBindingAdapterKind(binding) === "langchain-v1" || Boolean(binding.langchainAgentParams);
@@ -30,30 +58,29 @@ export function isDeepAgentBinding(binding) {
30
58
  return getBindingAdapterKind(binding) === "deepagent" || Boolean(binding.deepAgentParams);
31
59
  }
32
60
  export function getBindingPrimaryTools(binding) {
33
- return binding.langchainAgentParams?.tools ?? binding.deepAgentParams?.tools ?? [];
61
+ return getBindingExecutionView(binding).primaryTools;
34
62
  }
35
63
  export function getBindingPrimaryModel(binding) {
36
- return binding.langchainAgentParams?.model ?? binding.deepAgentParams?.model;
64
+ return getBindingExecutionView(binding).primaryModel;
37
65
  }
38
66
  export function getBindingRuntimeModel(binding, slot) {
39
67
  return binding.harnessRuntime.models?.[slot];
40
68
  }
41
69
  export function getBindingSystemPrompt(binding) {
42
- return binding.langchainAgentParams?.systemPrompt ?? binding.deepAgentParams?.systemPrompt;
70
+ return getBindingExecutionView(binding).systemPrompt;
43
71
  }
44
72
  export function getBindingMiddlewareConfigs(binding) {
45
- return binding.langchainAgentParams?.middleware ?? binding.deepAgentParams?.middleware;
73
+ return getBindingExecutionView(binding).middlewareConfigs;
46
74
  }
47
75
  export function getBindingInterruptCompatibilityRules(binding) {
48
- return binding.deepAgentParams?.interruptOn ??
49
- binding.agent.langchainAgentConfig?.interruptOn;
76
+ return getBindingExecutionView(binding).interruptCompatibilityRules;
50
77
  }
51
78
  export function getBindingModelInit(binding) {
52
79
  return getBindingPrimaryModel(binding)?.init;
53
80
  }
54
81
  export function getBindingStoreConfig(binding) {
55
- return binding.deepAgentParams?.store ?? binding.harnessRuntime.store;
82
+ return getBindingExecutionView(binding).storeConfig;
56
83
  }
57
84
  export function bindingHasSubagents(binding) {
58
- return (binding.deepAgentParams?.subagents.length ?? 0) > 0;
85
+ return (getBindingDeepAgentParams(binding)?.subagents.length ?? 0) > 0;
59
86
  }
@@ -90,21 +90,20 @@ export function requireTools(tools, refs, ownerId) {
90
90
  }
91
91
  function buildSubagent(agent, workspaceRoot, models, tools, parentSkills, parentModel, parentMemory) {
92
92
  const ownMemory = compileAgentMemories(workspaceRoot, agent.memorySources);
93
+ const execution = compileExecutionCore(agent, models, tools);
93
94
  return {
94
95
  name: resolveAgentRuntimeName(agent),
95
96
  description: agent.description,
96
- systemPrompt: [resolvePromptValue(agent.deepAgentConfig?.systemPrompt), WORKSPACE_BOUNDARY_GUIDANCE].filter(Boolean).join("\n\n"),
97
- tools: requireTools(tools, agent.toolRefs, agent.id),
98
- model: agent.modelRef ? requireModel(models, agent.modelRef, agent.id) : parentModel,
99
- interruptOn: agent.deepAgentConfig?.interruptOn,
97
+ systemPrompt: execution.systemPrompt ?? WORKSPACE_BOUNDARY_GUIDANCE,
98
+ tools: execution.tools,
99
+ model: agent.modelRef ? execution.model : parentModel,
100
+ interruptOn: resolveInterruptOn(agent),
100
101
  skills: compileAgentSkills(workspaceRoot, agent, parentSkills),
101
102
  memory: ownMemory.length > 0 ? ownMemory : parentMemory,
102
- responseFormat: agent.deepAgentConfig?.responseFormat,
103
- contextSchema: agent.deepAgentConfig?.contextSchema,
104
- middleware: compileMiddlewareConfigs(agent.deepAgentConfig?.middleware, models, agent.id),
105
- passthrough: typeof agent.deepAgentConfig?.passthrough === "object" && agent.deepAgentConfig.passthrough
106
- ? { ...agent.deepAgentConfig.passthrough }
107
- : undefined,
103
+ responseFormat: execution.responseFormat,
104
+ contextSchema: execution.contextSchema,
105
+ middleware: execution.middleware,
106
+ passthrough: execution.passthrough,
108
107
  };
109
108
  }
110
109
  function resolveDirectPrompt(agent) {
@@ -124,6 +123,45 @@ function resolveInterruptOn(agent) {
124
123
  return (agent.deepAgentConfig?.interruptOn ??
125
124
  agent.langchainAgentConfig?.interruptOn);
126
125
  }
126
+ function resolveResponseFormat(agent) {
127
+ return agent.deepAgentConfig?.responseFormat ?? agent.langchainAgentConfig?.responseFormat;
128
+ }
129
+ function resolveContextSchema(agent) {
130
+ return agent.deepAgentConfig?.contextSchema ?? agent.langchainAgentConfig?.contextSchema;
131
+ }
132
+ function resolveCompiledMiddleware(agent, models) {
133
+ const middleware = agent.deepAgentConfig?.middleware ??
134
+ agent.langchainAgentConfig?.middleware;
135
+ return compileMiddlewareConfigs(middleware, models, agent.id);
136
+ }
137
+ function resolvePassthrough(agent) {
138
+ const passthrough = typeof agent.deepAgentConfig?.passthrough === "object" && agent.deepAgentConfig.passthrough
139
+ ? agent.deepAgentConfig.passthrough
140
+ : typeof agent.langchainAgentConfig?.passthrough === "object" && agent.langchainAgentConfig.passthrough
141
+ ? agent.langchainAgentConfig.passthrough
142
+ : undefined;
143
+ return passthrough ? { ...passthrough } : undefined;
144
+ }
145
+ function compileSubagents(agent, agents, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel, compiledAgentMemory) {
146
+ return agent.subagentRefs.map((ref) => {
147
+ const subagent = agents.get(resolveRefId(ref));
148
+ if (!subagent) {
149
+ throw new Error(`Missing subagent ${ref} for agent ${agent.id}`);
150
+ }
151
+ return buildSubagent(subagent, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel, compiledAgentMemory);
152
+ });
153
+ }
154
+ function compileExecutionCore(agent, models, tools) {
155
+ return {
156
+ model: requireModel(models, agent.modelRef, agent.id),
157
+ tools: requireTools(tools, agent.toolRefs, agent.id),
158
+ systemPrompt: resolveSystemPrompt(agent),
159
+ responseFormat: resolveResponseFormat(agent),
160
+ contextSchema: resolveContextSchema(agent),
161
+ middleware: resolveCompiledMiddleware(agent, models),
162
+ passthrough: resolvePassthrough(agent),
163
+ };
164
+ }
127
165
  function resolveBackendConfig(agent, refs) {
128
166
  if (agent.executionMode !== "deepagent") {
129
167
  return undefined;
@@ -286,7 +324,11 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
286
324
  const resilience = getResilienceConfig(refs);
287
325
  const compiledAgentSkills = compileAgentSkills(workspaceRoot, agent);
288
326
  const compiledAgentMemory = compileAgentMemories(workspaceRoot, agent.memorySources);
289
- const compiledAgentModel = requireModel(models, agent.modelRef || (internalSubagent ? "model/default" : ""), agent.id);
327
+ const execution = compileExecutionCore({
328
+ ...agent,
329
+ modelRef: agent.modelRef || (internalSubagent ? "model/default" : ""),
330
+ }, models, tools);
331
+ const compiledAgentModel = execution.model;
290
332
  const backend = resolveBackendConfig(agent, refs);
291
333
  const store = resolveStoreConfig(agent, refs);
292
334
  const checkpointer = resolveCheckpointerConfig(agent, refs);
@@ -323,28 +365,19 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
323
365
  },
324
366
  };
325
367
  if (agent.executionMode !== "deepagent") {
326
- const basePassthrough = typeof agent.langchainAgentConfig?.passthrough === "object" && agent.langchainAgentConfig.passthrough
327
- ? { ...agent.langchainAgentConfig.passthrough }
328
- : undefined;
329
368
  const langchainAgentParams = {
330
- model: compiledAgentModel,
331
- tools: requireTools(tools, agent.toolRefs, agent.id),
332
- systemPrompt: resolveSystemPrompt(agent),
369
+ model: execution.model,
370
+ tools: execution.tools,
371
+ systemPrompt: execution.systemPrompt,
333
372
  stateSchema: agent.langchainAgentConfig?.stateSchema,
334
- responseFormat: agent.langchainAgentConfig?.responseFormat,
335
- contextSchema: agent.langchainAgentConfig?.contextSchema,
373
+ responseFormat: execution.responseFormat,
374
+ contextSchema: execution.contextSchema,
336
375
  filesystem: typeof agent.langchainAgentConfig?.filesystem === "object" && agent.langchainAgentConfig.filesystem
337
376
  ? { ...agent.langchainAgentConfig.filesystem }
338
377
  : undefined,
339
- middleware: compileMiddlewareConfigs(agent.langchainAgentConfig?.middleware, models, agent.id),
340
- passthrough: basePassthrough,
341
- subagents: agent.subagentRefs.map((ref) => {
342
- const subagent = agents.get(resolveRefId(ref));
343
- if (!subagent) {
344
- throw new Error(`Missing subagent ${ref} for agent ${agent.id}`);
345
- }
346
- return buildSubagent(subagent, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel, compiledAgentMemory);
347
- }),
378
+ middleware: execution.middleware,
379
+ passthrough: execution.passthrough,
380
+ subagents: compileSubagents(agent, agents, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel, compiledAgentMemory),
348
381
  memory: compiledAgentMemory,
349
382
  skills: compiledAgentSkills,
350
383
  generalPurposeAgent: typeof agent.langchainAgentConfig?.generalPurposeAgent === "boolean" ? agent.langchainAgentConfig.generalPurposeAgent : undefined,
@@ -370,23 +403,15 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
370
403
  };
371
404
  }
372
405
  const deepAgentParams = {
373
- model: compiledAgentModel,
374
- tools: requireTools(tools, agent.toolRefs, agent.id),
375
- systemPrompt: resolveSystemPrompt(agent),
376
- responseFormat: agent.deepAgentConfig?.responseFormat,
377
- contextSchema: agent.deepAgentConfig?.contextSchema,
378
- middleware: compileMiddlewareConfigs(agent.deepAgentConfig?.middleware, models, agent.id),
379
- passthrough: typeof agent.deepAgentConfig?.passthrough === "object" && agent.deepAgentConfig.passthrough
380
- ? { ...agent.deepAgentConfig.passthrough }
381
- : undefined,
406
+ model: execution.model,
407
+ tools: execution.tools,
408
+ systemPrompt: execution.systemPrompt,
409
+ responseFormat: execution.responseFormat,
410
+ contextSchema: execution.contextSchema,
411
+ middleware: execution.middleware,
412
+ passthrough: execution.passthrough,
382
413
  description: agent.description,
383
- subagents: agent.subagentRefs.map((ref) => {
384
- const subagent = agents.get(resolveRefId(ref));
385
- if (!subagent) {
386
- throw new Error(`Missing subagent ${ref} for agent ${agent.id}`);
387
- }
388
- return buildSubagent(subagent, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel, compiledAgentMemory);
389
- }),
414
+ subagents: compileSubagents(agent, agents, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel, compiledAgentMemory),
390
415
  interruptOn: resolveInterruptOn(agent),
391
416
  ...(backend ? { backend: backend.config } : {}),
392
417
  ...(store ? { store: store.config } : {}),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.106",
3
+ "version": "0.0.108",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",