@botbotgo/agent-harness 0.0.101 → 0.0.103

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 +3 -166
  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/middleware-assembly.d.ts +75 -0
  16. package/dist/runtime/adapter/middleware-assembly.js +175 -0
  17. package/dist/runtime/adapter/runtime-shell.d.ts +27 -0
  18. package/dist/runtime/adapter/runtime-shell.js +168 -0
  19. package/dist/runtime/adapter/stream-runtime.d.ts +46 -0
  20. package/dist/runtime/adapter/stream-runtime.js +93 -0
  21. package/dist/runtime/adapter/tool-resolution.d.ts +14 -0
  22. package/dist/runtime/adapter/tool-resolution.js +57 -0
  23. package/dist/runtime/agent-runtime-adapter.d.ts +1 -6
  24. package/dist/runtime/agent-runtime-adapter.js +140 -495
  25. package/dist/runtime/harness/run/run-operations.d.ts +50 -0
  26. package/dist/runtime/harness/run/run-operations.js +113 -0
  27. package/dist/runtime/harness/run/run-slot-acquisition.d.ts +64 -0
  28. package/dist/runtime/harness/run/run-slot-acquisition.js +157 -0
  29. package/dist/runtime/harness/run/startup-runtime.d.ts +37 -0
  30. package/dist/runtime/harness/run/startup-runtime.js +68 -0
  31. package/dist/runtime/harness/run/stream-run.d.ts +53 -0
  32. package/dist/runtime/harness/run/stream-run.js +304 -0
  33. package/dist/runtime/harness/run/thread-records.d.ts +21 -0
  34. package/dist/runtime/harness/run/thread-records.js +59 -0
  35. package/dist/runtime/harness.js +121 -639
  36. package/dist/workspace/object-loader.d.ts +1 -8
  37. package/dist/workspace/object-loader.js +3 -197
  38. package/dist/workspace/yaml-object-reader.d.ts +15 -0
  39. package/dist/workspace/yaml-object-reader.js +202 -0
  40. package/package.json +1 -1
@@ -1,34 +1,28 @@
1
1
  import path from "node:path";
2
2
  import { Command, MemorySaver } from "@langchain/langgraph";
3
- import { HumanMessage } from "@langchain/core/messages";
4
- import { DEFAULT_SUBAGENT_PROMPT, createDeepAgent, createMemoryMiddleware, createPatchToolCallsMiddleware, createSkillsMiddleware, createSummarizationMiddleware, createSubAgentMiddleware, FilesystemBackend, StateBackend, } from "deepagents";
5
- import { createAgent, humanInTheLoopMiddleware } from "langchain";
6
- import { extractToolFallbackContext, extractVisibleOutput, isToolCallParseFailure, STRICT_TOOL_JSON_INSTRUCTION, sanitizeVisibleText, wrapResolvedModel, } from "./parsing/output-parsing.js";
7
- import { readStreamDelta, } from "./parsing/stream-event-parsing.js";
8
- import { wrapToolForExecution } from "./adapter/tool/tool-hitl.js";
9
- import { resolveDeclaredMiddleware } from "./adapter/tool/declared-middleware.js";
3
+ import { createDeepAgent, FilesystemBackend, } from "deepagents";
4
+ import { createAgent } from "langchain";
5
+ import { wrapResolvedModel, } from "./parsing/output-parsing.js";
10
6
  import { applyDeepAgentDelegationPromptCompatibility, materializeDeepAgentSkillSourcePaths, } from "./adapter/compat/deepagent-compat.js";
11
7
  import { buildToolNameMapping, } from "./adapter/tool/tool-name-mapping.js";
12
- import { createBuiltinMiddlewareTools } from "./adapter/tool/builtin-middleware-tools.js";
13
8
  import { finalizeInvocationResult } from "./adapter/invocation-result.js";
14
- import { runLocalToolInvocationLoop } from "./adapter/local-tool-invocation.js";
15
- import { createStreamEventProjectionState, projectRuntimeStreamEvent } from "./adapter/stream-event-projection.js";
16
- import { projectTextStreamChunks } from "./adapter/stream-text-consumption.js";
9
+ import { invokeRuntimeWithLocalTools } from "./adapter/invoke-runtime.js";
10
+ import { streamRuntimeExecution } from "./adapter/stream-runtime.js";
17
11
  import { buildDeepAgentRunnableConfig } from "./adapter/deepagent-runnable-config.js";
18
12
  import { buildLangChainRunnableConfig } from "./adapter/langchain-runnable-config.js";
19
- import { computeRemainingTimeoutMs, isRetryableProviderError, resolveBindingTimeout, resolveProviderRetryPolicy, resolveStreamIdleTimeout, } from "./adapter/resilience.js";
13
+ import { applyStrictToolJsonInstruction as applyStrictToolJsonInstructionHelper, callRuntimeWithToolParseRecovery as callRuntimeWithToolParseRecoveryHelper, createModelFallbackRunnable as createModelFallbackRunnableHelper, invokeWithProviderRetry as invokeWithProviderRetryHelper, iterateWithTimeout as iterateWithTimeoutHelper, materializeModelStream as materializeModelStreamHelper, RuntimeOperationTimeoutError, withRuntimeTimeout, } from "./adapter/runtime-shell.js";
14
+ import { invokeBuiltinTaskTool as invokeBuiltinTaskToolHelper, resolveAutomaticSummarizationMiddleware as resolveAutomaticSummarizationMiddlewareHelper, resolveBuiltinMiddlewareBackend as resolveBuiltinMiddlewareBackendHelper, resolveBuiltinMiddlewareTools as resolveBuiltinMiddlewareToolsHelper, resolveLangChainAutomaticMiddleware as resolveLangChainAutomaticMiddlewareHelper, resolveMiddleware as resolveMiddlewareHelper, resolveSubagents as resolveSubagentsHelper, } from "./adapter/middleware-assembly.js";
15
+ import { computeRemainingTimeoutMs, resolveBindingTimeout, resolveStreamIdleTimeout, } from "./adapter/resilience.js";
20
16
  import { createResolvedModel } from "./adapter/model/model-providers.js";
21
17
  import { buildInvocationRequest, } from "./adapter/model/invocation-request.js";
22
18
  import { compileInterruptOn } from "./adapter/tool/interrupt-policy.js";
23
- import { buildRawModelMessages } from "./adapter/model/message-assembly.js";
24
- import { asStructuredExecutableTool, hasCallableToolHandler, normalizeResolvedToolSchema, wrapResolvedToolWithModelFacingName, } from "./adapter/tool/resolved-tool.js";
25
- import { instantiateProviderTool } from "./adapter/tool/provider-tool.js";
26
- import { countConfiguredTools, hasConfiguredMiddlewareKind, hasConfiguredSubagentSupport, isObject, isRecord, sleep, } from "./adapter/runtime-adapter-support.js";
19
+ import { countConfiguredTools, } from "./adapter/runtime-adapter-support.js";
20
+ import { buildExecutableToolMap, resolveAdapterTools } from "./adapter/tool-resolution.js";
27
21
  export { applyDeepAgentDelegationPromptCompatibility, materializeDeepAgentSkillSourcePaths, relativizeDeepAgentSkillSourcePaths, shouldRelaxDeepAgentDelegationPrompt, } from "./adapter/compat/deepagent-compat.js";
28
22
  export { buildAuthOmittingFetch, normalizeOpenAICompatibleInit } from "./adapter/compat/openai-compatible.js";
29
23
  export { buildToolNameMapping, createModelFacingToolNameCandidates, createModelFacingToolNameLookupCandidates, resolveModelFacingToolName, sanitizeToolNameForModel, } from "./adapter/tool/tool-name-mapping.js";
30
24
  export { computeRemainingTimeoutMs, isRetryableProviderError, resolveBindingTimeout, resolveProviderRetryPolicy, resolveStreamIdleTimeout, resolveTimeoutMs, } from "./adapter/resilience.js";
31
- import { getBindingAdapterKind, getBindingDeepAgentParams, getBindingInterruptCompatibilityRules, getBindingLangChainParams, getBindingMiddlewareConfigs, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSystemPrompt, isDeepAgentBinding, isLangChainBinding, } from "./support/compiled-binding.js";
25
+ import { getBindingAdapterKind, getBindingDeepAgentParams, getBindingInterruptCompatibilityRules, getBindingLangChainParams, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSystemPrompt, isDeepAgentBinding, isLangChainBinding, } from "./support/compiled-binding.js";
32
26
  const AGENT_INTERRUPT_SENTINEL_PREFIX = "__agent_harness_interrupt__:";
33
27
  const UPSTREAM_BUILTIN_MIDDLEWARE_TOOL_NAMES = Object.freeze([
34
28
  "write_todos",
@@ -41,18 +35,6 @@ const UPSTREAM_BUILTIN_MIDDLEWARE_TOOL_NAMES = Object.freeze([
41
35
  "execute",
42
36
  "task",
43
37
  ]);
44
- class RuntimeOperationTimeoutError extends Error {
45
- operation;
46
- timeoutMs;
47
- stage;
48
- constructor(operation, timeoutMs, stage = operation.includes("stream") ? "stream" : "invoke") {
49
- super(`${operation} timed out after ${timeoutMs}ms`);
50
- this.operation = operation;
51
- this.timeoutMs = timeoutMs;
52
- this.stage = stage;
53
- this.name = "RuntimeOperationTimeoutError";
54
- }
55
- }
56
38
  export class AgentRuntimeAdapter {
57
39
  options;
58
40
  modelCache = new Map();
@@ -69,144 +51,22 @@ export class AgentRuntimeAdapter {
69
51
  });
70
52
  }
71
53
  async invokeWithProviderRetry(binding, operation) {
72
- const retryPolicy = resolveProviderRetryPolicy(binding);
73
- let lastError;
74
- for (let attempt = 1; attempt <= retryPolicy.maxAttempts; attempt += 1) {
75
- try {
76
- return await operation();
77
- }
78
- catch (error) {
79
- lastError = error;
80
- if (attempt >= retryPolicy.maxAttempts || !isRetryableProviderError(binding, error)) {
81
- throw error;
82
- }
83
- if (retryPolicy.backoffMs > 0) {
84
- await sleep(retryPolicy.backoffMs);
85
- }
86
- }
87
- }
88
- throw lastError instanceof Error ? lastError : new Error(String(lastError));
54
+ return invokeWithProviderRetryHelper(binding, operation);
89
55
  }
90
56
  async withTimeout(producer, timeoutMs, operation, stage = operation.includes("stream") ? "stream" : "invoke") {
91
- if (!timeoutMs) {
92
- return Promise.resolve(producer());
93
- }
94
- return new Promise((resolve, reject) => {
95
- const timer = setTimeout(() => reject(new RuntimeOperationTimeoutError(operation, timeoutMs, stage)), timeoutMs);
96
- Promise.resolve(producer()).then((value) => {
97
- clearTimeout(timer);
98
- resolve(value);
99
- }, (error) => {
100
- clearTimeout(timer);
101
- reject(error);
102
- });
103
- });
57
+ return withRuntimeTimeout(producer, timeoutMs, operation, stage);
104
58
  }
105
59
  async *iterateWithTimeout(iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs) {
106
- const iterator = iterable[Symbol.asyncIterator]();
107
- try {
108
- for (;;) {
109
- const effectiveTimeoutMs = computeRemainingTimeoutMs(deadlineAt, timeoutMs);
110
- if (effectiveTimeoutMs !== undefined && effectiveTimeoutMs <= 0) {
111
- throw new RuntimeOperationTimeoutError(operation, deadlineTimeoutMs ?? timeoutMs ?? 0, "invoke");
112
- }
113
- let next;
114
- try {
115
- next = await this.withTimeout(() => iterator.next(), effectiveTimeoutMs, operation, "stream");
116
- }
117
- catch (error) {
118
- if (error instanceof RuntimeOperationTimeoutError &&
119
- deadlineAt &&
120
- deadlineTimeoutMs &&
121
- effectiveTimeoutMs !== timeoutMs) {
122
- throw new RuntimeOperationTimeoutError(operation, deadlineTimeoutMs, "invoke");
123
- }
124
- throw error;
125
- }
126
- if (next.done) {
127
- return;
128
- }
129
- yield next.value;
130
- }
131
- }
132
- finally {
133
- if (typeof iterator.return === "function") {
134
- const returnResult = iterator.return();
135
- if (returnResult && typeof returnResult.then === "function") {
136
- void returnResult.catch(() => undefined);
137
- }
138
- }
139
- }
60
+ yield* iterateWithTimeoutHelper(iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs);
140
61
  }
141
62
  async materializeModelStream(streamFactory, input, config) {
142
- const stream = await streamFactory(input, config);
143
- let content = "";
144
- for await (const chunk of stream) {
145
- const delta = readStreamDelta(chunk) || extractVisibleOutput(chunk);
146
- if (delta) {
147
- content += delta;
148
- }
149
- }
150
- return { content };
63
+ return materializeModelStreamHelper(streamFactory, input, config);
151
64
  }
152
65
  createModelFallbackRunnable(model) {
153
- return {
154
- invoke: async (input, config) => {
155
- const request = typeof input === "object" && input !== null && "messages" in input
156
- ? input.messages
157
- : input;
158
- if (typeof model.invoke === "function") {
159
- return model.invoke(request, config);
160
- }
161
- if (typeof model.stream === "function") {
162
- return this.materializeModelStream(model.stream.bind(model), request, config);
163
- }
164
- throw new Error("Resolved model must define invoke or stream.");
165
- },
166
- stream: async (input, config) => {
167
- if (typeof model.stream === "function") {
168
- const request = typeof input === "object" && input !== null && "messages" in input
169
- ? input.messages
170
- : input;
171
- return model.stream(request, config);
172
- }
173
- if (typeof model.invoke === "function") {
174
- const request = typeof input === "object" && input !== null && "messages" in input
175
- ? input.messages
176
- : input;
177
- const result = await model.invoke(request, config);
178
- const text = extractVisibleOutput(result);
179
- async function* singleChunk() {
180
- yield { content: text };
181
- }
182
- return singleChunk();
183
- }
184
- throw new Error("Resolved model must define invoke or stream.");
185
- },
186
- };
66
+ return createModelFallbackRunnableHelper(model);
187
67
  }
188
68
  applyStrictToolJsonInstruction(binding) {
189
- if (isLangChainBinding(binding)) {
190
- const params = getBindingLangChainParams(binding);
191
- return {
192
- ...binding,
193
- langchainAgentParams: {
194
- ...params,
195
- systemPrompt: [params.systemPrompt, STRICT_TOOL_JSON_INSTRUCTION].filter(Boolean).join("\n\n"),
196
- },
197
- };
198
- }
199
- if (isDeepAgentBinding(binding)) {
200
- const params = getBindingDeepAgentParams(binding);
201
- return {
202
- ...binding,
203
- deepAgentParams: {
204
- ...params,
205
- systemPrompt: [params.systemPrompt, STRICT_TOOL_JSON_INSTRUCTION].filter(Boolean).join("\n\n"),
206
- },
207
- };
208
- }
209
- return binding;
69
+ return applyStrictToolJsonInstructionHelper(binding);
210
70
  }
211
71
  async resolveModel(model) {
212
72
  const cacheKey = this.getModelCacheKey(model);
@@ -227,20 +87,10 @@ export class AgentRuntimeAdapter {
227
87
  }
228
88
  }
229
89
  resolveTools(tools, binding) {
230
- const resolved = this.options.toolResolver ? this.options.toolResolver(tools.map((tool) => tool.id), binding) : [];
231
- const toolNameMapping = buildToolNameMapping(tools);
232
- return tools.flatMap((compiledTool, index) => {
233
- const resolvedTool = resolved[index] ?? (compiledTool.type === "provider" ? instantiateProviderTool(compiledTool) : undefined);
234
- if (resolvedTool === undefined) {
235
- return [];
236
- }
237
- const wrappedTool = wrapToolForExecution(resolvedTool, compiledTool, binding);
238
- const modelFacingName = toolNameMapping.originalToModelFacing.get(compiledTool.name) ?? compiledTool.name;
239
- const structuredTool = asStructuredExecutableTool(wrappedTool, modelFacingName, compiledTool.description);
240
- if (structuredTool !== wrappedTool) {
241
- return structuredTool;
242
- }
243
- return modelFacingName === compiledTool.name ? wrappedTool : wrapResolvedToolWithModelFacingName(wrappedTool, modelFacingName);
90
+ return resolveAdapterTools({
91
+ tools,
92
+ binding,
93
+ resolveToolValues: this.options.toolResolver,
244
94
  });
245
95
  }
246
96
  resolveFilesystemBackend(binding) {
@@ -261,24 +111,12 @@ export class AgentRuntimeAdapter {
261
111
  });
262
112
  }
263
113
  resolveBuiltinMiddlewareBackend(binding, options = {}) {
264
- const runtimeState = {
265
- ...(options.state ?? {}),
266
- ...(isRecord(options.files) ? { files: options.files } : {}),
267
- };
268
- const runtimeLike = {
269
- state: runtimeState,
270
- store: this.options.storeResolver?.(binding),
271
- };
272
- const configuredBackend = isDeepAgentBinding(binding)
273
- ? this.options.backendResolver?.(binding)
274
- : this.resolveFilesystemBackend(binding);
275
- if (typeof configuredBackend === "function") {
276
- return configuredBackend(runtimeLike);
277
- }
278
- if (configuredBackend) {
279
- return configuredBackend;
280
- }
281
- return new StateBackend(runtimeLike);
114
+ return resolveBuiltinMiddlewareBackendHelper({
115
+ binding,
116
+ runtimeAdapterOptions: this.options,
117
+ resolveFilesystemBackend: (currentBinding) => this.resolveFilesystemBackend(currentBinding),
118
+ options,
119
+ });
282
120
  }
283
121
  createDeclaredMiddlewareResolverOptions(binding) {
284
122
  return {
@@ -296,149 +134,57 @@ export class AgentRuntimeAdapter {
296
134
  };
297
135
  }
298
136
  async invokeBuiltinTaskTool(binding, input, options = {}) {
299
- if (!isDeepAgentBinding(binding)) {
300
- throw new Error("The built-in task tool is only available for deepagent bindings.");
301
- }
302
- const params = getBindingDeepAgentParams(binding);
303
- if (!params) {
304
- throw new Error(`Agent ${binding.agent.id} has no deepagent params`);
305
- }
306
- const typedInput = isObject(input) ? input : {};
307
- const description = typeof typedInput.description === "string" ? typedInput.description : "";
308
- const subagentType = typeof typedInput.subagent_type === "string" ? typedInput.subagent_type : "";
309
- const builtinBackend = this.resolveBuiltinMiddlewareBackend(binding, options);
310
- const resolvedSubagents = await this.resolveSubagents(params.subagents, binding);
311
- const selectedSubagent = resolvedSubagents.find((subagent) => subagent.name === subagentType);
312
- if (!selectedSubagent) {
313
- const allowed = [
314
- ...resolvedSubagents.map((subagent) => subagent.name),
315
- ...(params.generalPurposeAgent ? ["general-purpose"] : []),
316
- ];
317
- throw new Error(`Error: invoked agent of type ${subagentType}, the only allowed types are ${allowed.map((name) => `\`${name}\``).join(", ")}`);
318
- }
319
- const summarizationModel = selectedSubagent.model
320
- ? await this.resolveModel(selectedSubagent.model)
321
- : await this.resolveModel(params.model);
322
- const middleware = [
323
- ...(selectedSubagent.skills?.length
324
- ? [createSkillsMiddleware({ backend: builtinBackend, sources: selectedSubagent.skills })]
325
- : []),
326
- ...(selectedSubagent.memory?.length
327
- ? [createMemoryMiddleware({ backend: builtinBackend, sources: selectedSubagent.memory })]
328
- : []),
329
- ...(selectedSubagent.middleware ??
330
- [
331
- createPatchToolCallsMiddleware(),
332
- createSummarizationMiddleware({
333
- model: summarizationModel,
334
- backend: builtinBackend,
335
- }),
336
- ]),
337
- ...(selectedSubagent.interruptOn
338
- ? [humanInTheLoopMiddleware({
339
- interruptOn: compileInterruptOn(selectedSubagent.tools ?? [], selectedSubagent.interruptOn),
340
- })]
341
- : []),
342
- ];
343
- const runnable = createAgent({
344
- model: (selectedSubagent.model ?? (await this.resolveModel(params.model))),
345
- tools: (selectedSubagent.tools ?? this.resolveTools(params.tools, binding)),
346
- systemPrompt: selectedSubagent.systemPrompt ?? DEFAULT_SUBAGENT_PROMPT,
347
- middleware: middleware,
348
- responseFormat: selectedSubagent.responseFormat,
349
- contextSchema: selectedSubagent.contextSchema,
350
- name: selectedSubagent.name,
351
- description: selectedSubagent.description,
137
+ return invokeBuiltinTaskToolHelper({
138
+ binding,
139
+ toolInput: input,
140
+ options,
141
+ resolveBuiltinMiddlewareBackend: (currentBinding, currentOptions) => this.resolveBuiltinMiddlewareBackend(currentBinding, currentOptions),
142
+ resolveSubagents: (subagents, currentBinding) => this.resolveSubagents(subagents, currentBinding),
143
+ resolveModel: (model) => this.resolveModel(model),
144
+ resolveTools: (tools, currentBinding) => this.resolveTools(tools, currentBinding),
352
145
  });
353
- const result = await runnable.invoke({ messages: [new HumanMessage({ content: description })] }, { configurable: { thread_id: `${binding.agent.id}:builtin-task` }, ...(options.context ? { context: options.context } : {}) });
354
- const visibleOutput = extractVisibleOutput(result);
355
- const fallbackOutput = extractToolFallbackContext(result);
356
- return visibleOutput || fallbackOutput || JSON.stringify(result);
357
146
  }
358
147
  async resolveBuiltinMiddlewareTools(binding, options = {}) {
359
- const backend = this.resolveBuiltinMiddlewareBackend(binding, options);
360
- return createBuiltinMiddlewareTools(backend, {
361
- includeTaskTool: isDeepAgentBinding(binding),
362
- invokeTaskTool: isDeepAgentBinding(binding)
363
- ? async (input) => this.invokeBuiltinTaskTool(binding, input, options)
364
- : undefined,
148
+ return resolveBuiltinMiddlewareToolsHelper({
149
+ binding,
150
+ options,
151
+ resolveBuiltinMiddlewareBackend: (currentBinding, currentOptions) => this.resolveBuiltinMiddlewareBackend(currentBinding, currentOptions),
152
+ invokeBuiltinTaskTool: (currentBinding, toolInput, currentOptions) => this.invokeBuiltinTaskTool(currentBinding, toolInput, currentOptions),
365
153
  });
366
154
  }
367
155
  async resolveAutomaticSummarizationMiddleware(binding) {
368
- if (hasConfiguredMiddlewareKind(binding, "summarization")) {
369
- return [];
370
- }
371
- const primaryModel = getBindingPrimaryModel(binding);
372
- if (!primaryModel) {
373
- return [];
374
- }
375
- return resolveDeclaredMiddleware([{ kind: "summarization", model: primaryModel }], this.createDeclaredMiddlewareResolverOptions(binding));
156
+ return resolveAutomaticSummarizationMiddlewareHelper({
157
+ binding,
158
+ createDeclaredMiddlewareResolverOptions: (currentBinding) => this.createDeclaredMiddlewareResolverOptions(currentBinding),
159
+ });
376
160
  }
377
161
  async resolveLangChainAutomaticMiddleware(binding) {
378
- const params = getBindingLangChainParams(binding);
379
- if (!params) {
380
- return [];
381
- }
382
- const compatibleParams = applyDeepAgentDelegationPromptCompatibility(params.model, params);
383
- const automaticMiddleware = [];
384
- automaticMiddleware.push(createPatchToolCallsMiddleware());
385
- automaticMiddleware.push(...(await this.resolveAutomaticSummarizationMiddleware(binding)));
386
- if ((compatibleParams.skills?.length ?? 0) > 0) {
387
- automaticMiddleware.push(createSkillsMiddleware({
388
- backend: this.resolveFilesystemBackend(binding),
389
- sources: compatibleParams.skills,
390
- }));
391
- }
392
- if ((compatibleParams.memory?.length ?? 0) > 0) {
393
- automaticMiddleware.push(createMemoryMiddleware({
394
- backend: this.resolveFilesystemBackend(binding),
395
- sources: compatibleParams.memory,
396
- }));
397
- }
398
- if (hasConfiguredSubagentSupport(binding)) {
399
- automaticMiddleware.push(createSubAgentMiddleware({
400
- defaultModel: (await this.resolveModel(compatibleParams.model)),
401
- defaultTools: this.resolveTools(compatibleParams.tools, binding),
402
- defaultInterruptOn: getBindingInterruptCompatibilityRules(binding),
403
- subagents: (await this.resolveSubagents(compatibleParams.subagents ?? [], binding)),
404
- generalPurposeAgent: compatibleParams.generalPurposeAgent,
405
- taskDescription: compatibleParams.taskDescription ?? null,
406
- }));
407
- }
408
- return automaticMiddleware;
162
+ return resolveLangChainAutomaticMiddlewareHelper({
163
+ binding,
164
+ resolveAutomaticSummarizationMiddleware: (currentBinding) => this.resolveAutomaticSummarizationMiddleware(currentBinding),
165
+ resolveFilesystemBackend: (currentBinding) => this.resolveFilesystemBackend(currentBinding),
166
+ resolveModel: (model) => this.resolveModel(model),
167
+ resolveTools: (tools, currentBinding) => this.resolveTools(tools, currentBinding),
168
+ resolveSubagents: (subagents, currentBinding) => this.resolveSubagents(subagents, currentBinding),
169
+ });
409
170
  }
410
171
  async resolveMiddleware(binding, interruptOn) {
411
- const declarativeMiddleware = await resolveDeclaredMiddleware(getBindingMiddlewareConfigs(binding), this.createDeclaredMiddlewareResolverOptions(binding));
412
- const automaticMiddleware = isLangChainBinding(binding)
413
- ? await this.resolveLangChainAutomaticMiddleware(binding)
414
- : [];
415
- const middleware = [
416
- ...declarativeMiddleware,
417
- ...automaticMiddleware,
418
- ...(this.options.middlewareResolver ? this.options.middlewareResolver(binding) : []),
419
- ];
420
- if (interruptOn && Object.keys(interruptOn).length > 0) {
421
- middleware.push(humanInTheLoopMiddleware({ interruptOn }));
422
- }
423
- return middleware;
172
+ return resolveMiddlewareHelper({
173
+ binding,
174
+ interruptOn,
175
+ runtimeAdapterOptions: this.options,
176
+ createDeclaredMiddlewareResolverOptions: (currentBinding) => this.createDeclaredMiddlewareResolverOptions(currentBinding),
177
+ resolveLangChainAutomaticMiddleware: (currentBinding) => this.resolveLangChainAutomaticMiddleware(currentBinding),
178
+ });
424
179
  }
425
180
  async resolveSubagents(subagents, binding) {
426
- return Promise.all(subagents.map(async (subagent) => ({
427
- ...subagent,
428
- ...(subagent.passthrough ?? {}),
429
- model: subagent.model ? (await this.resolveModel(subagent.model)) : undefined,
430
- tools: subagent.tools ? this.resolveTools(subagent.tools) : undefined,
431
- skills: await materializeDeepAgentSkillSourcePaths({
432
- workspaceRoot: binding?.harnessRuntime.workspaceRoot,
433
- runRoot: binding?.harnessRuntime.runRoot,
434
- ownerId: `${binding?.agent.id ?? "agent"}-${subagent.name}`,
435
- skillPaths: subagent.skills,
436
- }),
437
- interruptOn: compileInterruptOn(subagent.tools ?? [], subagent.interruptOn),
438
- responseFormat: subagent.responseFormat,
439
- contextSchema: subagent.contextSchema,
440
- middleware: (await resolveDeclaredMiddleware(subagent.middleware, this.createDeclaredMiddlewareResolverOptions(binding))),
441
- })));
181
+ return resolveSubagentsHelper({
182
+ subagents,
183
+ binding,
184
+ resolveModel: (model) => this.resolveModel(model),
185
+ resolveTools: (tools, currentBinding) => this.resolveTools(tools, currentBinding),
186
+ createDeclaredMiddlewareResolverOptions: (currentBinding) => this.createDeclaredMiddlewareResolverOptions(currentBinding),
187
+ });
442
188
  }
443
189
  async createLangChainRunnable(binding, options = {}) {
444
190
  const params = getBindingLangChainParams(binding);
@@ -512,7 +258,6 @@ export class AgentRuntimeAdapter {
512
258
  const request = resumePayload === undefined
513
259
  ? buildInvocationRequest(binding, history, input, options)
514
260
  : new Command({ resume: resumePayload });
515
- let result;
516
261
  const callRuntime = async (activeBinding, activeRequest) => {
517
262
  return this.invokeWithProviderRetry(activeBinding, async () => {
518
263
  const runnable = await this.create(activeBinding);
@@ -520,74 +265,36 @@ export class AgentRuntimeAdapter {
520
265
  });
521
266
  };
522
267
  const callRuntimeWithToolParseRecovery = async (activeRequest) => {
523
- try {
524
- return await callRuntime(binding, activeRequest);
525
- }
526
- catch (error) {
527
- if (resumePayload !== undefined || !isToolCallParseFailure(error)) {
528
- throw error;
529
- }
530
- return callRuntime(this.applyStrictToolJsonInstruction(binding), activeRequest);
531
- }
268
+ return callRuntimeWithToolParseRecoveryHelper({
269
+ binding,
270
+ request: activeRequest,
271
+ resumePayload,
272
+ callRuntime,
273
+ });
532
274
  };
533
- const executedToolResults = [];
534
- if (resumePayload !== undefined) {
535
- result = await callRuntimeWithToolParseRecovery(request);
536
- }
537
- else {
538
- const primaryTools = getBindingPrimaryTools(binding);
539
- const defersToUpstreamHitlExecution = primaryTools.some((tool) => tool.hitl?.enabled === true);
540
- if (defersToUpstreamHitlExecution) {
541
- result = await callRuntimeWithToolParseRecovery(request);
542
- }
543
- else {
544
- const resolvedTools = this.resolveTools(primaryTools, binding);
545
- const toolNameMapping = buildToolNameMapping(primaryTools);
546
- const executableTools = new Map();
547
- const builtinExecutableTools = await this.resolveBuiltinMiddlewareTools(binding, options);
548
- for (let index = 0; index < primaryTools.length; index += 1) {
549
- const compiledTool = primaryTools[index];
550
- const resolvedTool = resolvedTools[index];
551
- if (!compiledTool || !resolvedTool || !hasCallableToolHandler(resolvedTool)) {
552
- continue;
553
- }
554
- const handler = async (toolInput) => {
555
- const callable = typeof resolvedTool.invoke === "function"
556
- ? resolvedTool.invoke
557
- : typeof resolvedTool.call === "function"
558
- ? resolvedTool.call
559
- : resolvedTool.func;
560
- if (!callable) {
561
- throw new Error(`Tool ${compiledTool.name} has no callable handler.`);
562
- }
563
- return Promise.resolve(callable.call(resolvedTool, toolInput, options.context ? { context: options.context } : undefined));
564
- };
565
- const modelFacingName = toolNameMapping.originalToModelFacing.get(compiledTool.name) ?? compiledTool.name;
566
- const normalizedSchema = normalizeResolvedToolSchema(resolvedTool);
567
- executableTools.set(modelFacingName, {
568
- name: compiledTool.name,
569
- schema: normalizedSchema,
570
- invoke: handler,
571
- });
572
- executableTools.set(compiledTool.name, {
573
- name: compiledTool.name,
574
- schema: normalizedSchema,
575
- invoke: handler,
576
- });
577
- }
578
- const localInvocation = await runLocalToolInvocationLoop({
579
- binding,
580
- request,
581
- primaryTools,
582
- toolNameMapping,
583
- executableTools: executableTools,
584
- builtinExecutableTools: builtinExecutableTools,
585
- callRuntimeWithToolParseRecovery,
586
- });
587
- result = localInvocation.result;
588
- executedToolResults.push(...localInvocation.executedToolResults);
589
- }
590
- }
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,
282
+ context: options.context,
283
+ });
284
+ const builtinExecutableTools = await this.resolveBuiltinMiddlewareTools(binding, options);
285
+ const localOrUpstreamInvocation = await invokeRuntimeWithLocalTools({
286
+ binding,
287
+ request,
288
+ resumePayload,
289
+ primaryTools,
290
+ defersToUpstreamHitlExecution: primaryTools.some((tool) => tool.hitl?.enabled === true),
291
+ toolNameMapping,
292
+ executableTools,
293
+ builtinExecutableTools: builtinExecutableTools,
294
+ callRuntimeWithToolParseRecovery,
295
+ });
296
+ const result = localOrUpstreamInvocation.result;
297
+ const executedToolResults = [...localOrUpstreamInvocation.executedToolResults];
591
298
  if (!result) {
592
299
  throw new Error("Agent invocation returned no result");
593
300
  }
@@ -600,113 +307,51 @@ export class AgentRuntimeAdapter {
600
307
  });
601
308
  }
602
309
  async *stream(binding, input, threadId, history = [], options = {}) {
603
- try {
604
- const invokeTimeoutMs = resolveBindingTimeout(binding);
605
- const streamIdleTimeoutMs = resolveStreamIdleTimeout(binding);
606
- const streamDeadlineAt = invokeTimeoutMs ? Date.now() + invokeTimeoutMs : undefined;
607
- const primaryTools = getBindingPrimaryTools(binding);
608
- const toolNameMapping = buildToolNameMapping(primaryTools);
609
- const primaryModel = getBindingPrimaryModel(binding);
610
- const forceInvokeFallback = isLangChainBinding(binding) &&
611
- primaryTools.length > 0 &&
612
- primaryModel?.provider === "openai-compatible";
613
- if (isLangChainBinding(binding)) {
614
- const langchainParams = getBindingLangChainParams(binding);
615
- const resolvedModel = (await this.resolveModel(langchainParams.model));
616
- const tools = this.resolveTools(langchainParams.tools, binding);
617
- const canUseDirectModelStream = tools.length === 0 || typeof resolvedModel.bindTools !== "function";
618
- const model = canUseDirectModelStream
619
- ? resolvedModel
620
- : typeof resolvedModel.bindTools === "function" && tools.length > 0
621
- ? resolvedModel.bindTools(tools)
622
- : resolvedModel;
623
- // For tool-using langchain agents, a raw model.stream pass cannot execute the
624
- // agent loop and only adds an extra model round-trip before the runnable path.
625
- if (canUseDirectModelStream && typeof model.stream === "function") {
626
- const stream = await this.withTimeout(() => model.stream(buildRawModelMessages(binding, getBindingSystemPrompt(binding), history, input)), computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs), "model stream start", "stream");
627
- let emitted = false;
628
- const projected = projectTextStreamChunks(this.iterateWithTimeout(stream, streamIdleTimeoutMs, "model stream", streamDeadlineAt, invokeTimeoutMs));
629
- let nextChunk = await projected.next();
630
- while (!nextChunk.done) {
631
- if (nextChunk.value.kind === "content") {
632
- emitted = true;
633
- }
634
- yield nextChunk.value;
635
- nextChunk = await projected.next();
636
- }
637
- if (nextChunk.value.emittedContent || emitted) {
638
- return;
639
- }
640
- }
641
- }
642
- const runnable = await this.create(binding);
643
- const request = buildInvocationRequest(binding, history, input, options);
644
- if (!forceInvokeFallback && typeof runnable.streamEvents === "function") {
645
- 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");
646
- const projectionState = createStreamEventProjectionState();
647
- for await (const event of this.iterateWithTimeout(events, streamIdleTimeoutMs, "agent streamEvents", streamDeadlineAt, invokeTimeoutMs)) {
648
- const projectedChunks = projectRuntimeStreamEvent({
649
- event,
650
- allowVisibleStreamDeltas: isLangChainBinding(binding),
651
- includeStateStreamOutput: isDeepAgentBinding(binding),
652
- toolNameMapping,
653
- primaryTools,
654
- state: projectionState,
655
- });
656
- for (const chunk of projectedChunks) {
657
- yield chunk;
658
- }
659
- }
660
- if (projectionState.emittedOutput || projectionState.emittedToolResult || projectionState.emittedToolError) {
661
- return;
662
- }
663
- }
664
- if (!forceInvokeFallback && isLangChainBinding(binding) && typeof runnable.stream === "function") {
665
- const stream = await this.withTimeout(() => runnable.stream(request, { configurable: { thread_id: threadId, run_id: options.runId } }), computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs), "agent stream start", "stream");
666
- let emitted = false;
667
- const projected = projectTextStreamChunks(this.iterateWithTimeout(stream, streamIdleTimeoutMs, "agent stream", streamDeadlineAt, invokeTimeoutMs));
668
- let nextChunk = await projected.next();
669
- while (!nextChunk.done) {
670
- if (nextChunk.value.kind === "content") {
671
- emitted = true;
672
- }
673
- yield nextChunk.value;
674
- nextChunk = await projected.next();
675
- }
676
- if (nextChunk.value.emittedContent || emitted) {
677
- return;
678
- }
679
- }
680
- const result = await this.invoke(binding, input, threadId, options.runId ?? threadId, undefined, history, options);
681
- const executedToolResults = Array.isArray(result.metadata?.executedToolResults)
682
- ? result.metadata.executedToolResults
683
- : [];
684
- for (const toolResult of executedToolResults) {
685
- yield {
686
- kind: "tool-result",
687
- toolName: toolResult.toolName,
688
- output: toolResult.output,
689
- isError: toolResult.isError,
690
- };
691
- }
692
- if (result.output) {
693
- yield { kind: "content", content: sanitizeVisibleText(result.output) };
694
- }
695
- }
696
- catch (error) {
697
- if (countConfiguredTools(binding) > 0 &&
698
- error instanceof Error &&
699
- error.message.includes("does not support tool binding")) {
700
- throw error;
701
- }
702
- if (!isToolCallParseFailure(error)) {
703
- throw error;
704
- }
705
- const retried = await this.invoke(this.applyStrictToolJsonInstruction(binding), input, threadId, options.runId ?? threadId, undefined, history, options);
706
- if (retried.output) {
707
- yield { kind: "content", content: sanitizeVisibleText(retried.output) };
708
- }
709
- }
310
+ const invokeTimeoutMs = resolveBindingTimeout(binding);
311
+ const streamIdleTimeoutMs = resolveStreamIdleTimeout(binding);
312
+ 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;
331
+ yield* streamRuntimeExecution({
332
+ binding,
333
+ input,
334
+ threadId,
335
+ history,
336
+ runtimeOptions: options,
337
+ primaryTools,
338
+ toolNameMapping,
339
+ forceInvokeFallback,
340
+ canUseDirectModelStream,
341
+ langChainStreamModel,
342
+ createRunnable: () => this.create(binding),
343
+ withTimeout: (producer, timeoutMs, operation, stage) => this.withTimeout(producer, timeoutMs, operation, stage),
344
+ iterateWithTimeout: (iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs) => this.iterateWithTimeout(iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs),
345
+ invokeTimeoutMs: computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs),
346
+ streamIdleTimeoutMs,
347
+ streamDeadlineAt,
348
+ invoke: (activeBinding, activeInput, activeThreadId, runId, resumePayload, activeHistory, invokeOptions) => this.invoke(activeBinding, activeInput, activeThreadId, runId, resumePayload, activeHistory, invokeOptions),
349
+ applyStrictToolJsonInstruction: (activeBinding) => this.applyStrictToolJsonInstruction(activeBinding),
350
+ getSystemPrompt: (activeBinding) => getBindingSystemPrompt(activeBinding),
351
+ isLangChainBinding,
352
+ isDeepAgentBinding,
353
+ countConfiguredTools,
354
+ });
710
355
  }
711
356
  }
712
357
  export { AgentRuntimeAdapter as RuntimeAdapter, AGENT_INTERRUPT_SENTINEL_PREFIX, AGENT_INTERRUPT_SENTINEL_PREFIX as INTERRUPT_SENTINEL_PREFIX, RuntimeOperationTimeoutError, };