@botbotgo/agent-harness 0.0.102 → 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.
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/adapter/middleware-assembly.d.ts +75 -0
- package/dist/runtime/adapter/middleware-assembly.js +175 -0
- package/dist/runtime/adapter/runtime-shell.d.ts +27 -0
- package/dist/runtime/adapter/runtime-shell.js +168 -0
- package/dist/runtime/adapter/tool-resolution.d.ts +14 -0
- package/dist/runtime/adapter/tool-resolution.js +57 -0
- package/dist/runtime/agent-runtime-adapter.d.ts +1 -6
- package/dist/runtime/agent-runtime-adapter.js +76 -356
- package/dist/runtime/harness/run/startup-runtime.d.ts +37 -0
- package/dist/runtime/harness/run/startup-runtime.js +68 -0
- package/dist/runtime/harness/run/thread-records.d.ts +21 -0
- package/dist/runtime/harness/run/thread-records.js +59 -0
- package/dist/runtime/harness.js +42 -111
- package/package.json +1 -1
|
@@ -1,32 +1,28 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { Command, MemorySaver } from "@langchain/langgraph";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { extractToolFallbackContext, extractVisibleOutput, isToolCallParseFailure, STRICT_TOOL_JSON_INSTRUCTION, 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
9
|
import { invokeRuntimeWithLocalTools } from "./adapter/invoke-runtime.js";
|
|
15
10
|
import { streamRuntimeExecution } from "./adapter/stream-runtime.js";
|
|
16
11
|
import { buildDeepAgentRunnableConfig } from "./adapter/deepagent-runnable-config.js";
|
|
17
12
|
import { buildLangChainRunnableConfig } from "./adapter/langchain-runnable-config.js";
|
|
18
|
-
import {
|
|
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";
|
|
19
16
|
import { createResolvedModel } from "./adapter/model/model-providers.js";
|
|
20
17
|
import { buildInvocationRequest, } from "./adapter/model/invocation-request.js";
|
|
21
18
|
import { compileInterruptOn } from "./adapter/tool/interrupt-policy.js";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
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";
|
|
25
21
|
export { applyDeepAgentDelegationPromptCompatibility, materializeDeepAgentSkillSourcePaths, relativizeDeepAgentSkillSourcePaths, shouldRelaxDeepAgentDelegationPrompt, } from "./adapter/compat/deepagent-compat.js";
|
|
26
22
|
export { buildAuthOmittingFetch, normalizeOpenAICompatibleInit } from "./adapter/compat/openai-compatible.js";
|
|
27
23
|
export { buildToolNameMapping, createModelFacingToolNameCandidates, createModelFacingToolNameLookupCandidates, resolveModelFacingToolName, sanitizeToolNameForModel, } from "./adapter/tool/tool-name-mapping.js";
|
|
28
24
|
export { computeRemainingTimeoutMs, isRetryableProviderError, resolveBindingTimeout, resolveProviderRetryPolicy, resolveStreamIdleTimeout, resolveTimeoutMs, } from "./adapter/resilience.js";
|
|
29
|
-
import { getBindingAdapterKind, getBindingDeepAgentParams, getBindingInterruptCompatibilityRules, getBindingLangChainParams,
|
|
25
|
+
import { getBindingAdapterKind, getBindingDeepAgentParams, getBindingInterruptCompatibilityRules, getBindingLangChainParams, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSystemPrompt, isDeepAgentBinding, isLangChainBinding, } from "./support/compiled-binding.js";
|
|
30
26
|
const AGENT_INTERRUPT_SENTINEL_PREFIX = "__agent_harness_interrupt__:";
|
|
31
27
|
const UPSTREAM_BUILTIN_MIDDLEWARE_TOOL_NAMES = Object.freeze([
|
|
32
28
|
"write_todos",
|
|
@@ -39,18 +35,6 @@ const UPSTREAM_BUILTIN_MIDDLEWARE_TOOL_NAMES = Object.freeze([
|
|
|
39
35
|
"execute",
|
|
40
36
|
"task",
|
|
41
37
|
]);
|
|
42
|
-
class RuntimeOperationTimeoutError extends Error {
|
|
43
|
-
operation;
|
|
44
|
-
timeoutMs;
|
|
45
|
-
stage;
|
|
46
|
-
constructor(operation, timeoutMs, stage = operation.includes("stream") ? "stream" : "invoke") {
|
|
47
|
-
super(`${operation} timed out after ${timeoutMs}ms`);
|
|
48
|
-
this.operation = operation;
|
|
49
|
-
this.timeoutMs = timeoutMs;
|
|
50
|
-
this.stage = stage;
|
|
51
|
-
this.name = "RuntimeOperationTimeoutError";
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
38
|
export class AgentRuntimeAdapter {
|
|
55
39
|
options;
|
|
56
40
|
modelCache = new Map();
|
|
@@ -67,144 +51,22 @@ export class AgentRuntimeAdapter {
|
|
|
67
51
|
});
|
|
68
52
|
}
|
|
69
53
|
async invokeWithProviderRetry(binding, operation) {
|
|
70
|
-
|
|
71
|
-
let lastError;
|
|
72
|
-
for (let attempt = 1; attempt <= retryPolicy.maxAttempts; attempt += 1) {
|
|
73
|
-
try {
|
|
74
|
-
return await operation();
|
|
75
|
-
}
|
|
76
|
-
catch (error) {
|
|
77
|
-
lastError = error;
|
|
78
|
-
if (attempt >= retryPolicy.maxAttempts || !isRetryableProviderError(binding, error)) {
|
|
79
|
-
throw error;
|
|
80
|
-
}
|
|
81
|
-
if (retryPolicy.backoffMs > 0) {
|
|
82
|
-
await sleep(retryPolicy.backoffMs);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
54
|
+
return invokeWithProviderRetryHelper(binding, operation);
|
|
87
55
|
}
|
|
88
56
|
async withTimeout(producer, timeoutMs, operation, stage = operation.includes("stream") ? "stream" : "invoke") {
|
|
89
|
-
|
|
90
|
-
return Promise.resolve(producer());
|
|
91
|
-
}
|
|
92
|
-
return new Promise((resolve, reject) => {
|
|
93
|
-
const timer = setTimeout(() => reject(new RuntimeOperationTimeoutError(operation, timeoutMs, stage)), timeoutMs);
|
|
94
|
-
Promise.resolve(producer()).then((value) => {
|
|
95
|
-
clearTimeout(timer);
|
|
96
|
-
resolve(value);
|
|
97
|
-
}, (error) => {
|
|
98
|
-
clearTimeout(timer);
|
|
99
|
-
reject(error);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
57
|
+
return withRuntimeTimeout(producer, timeoutMs, operation, stage);
|
|
102
58
|
}
|
|
103
59
|
async *iterateWithTimeout(iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs) {
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
for (;;) {
|
|
107
|
-
const effectiveTimeoutMs = computeRemainingTimeoutMs(deadlineAt, timeoutMs);
|
|
108
|
-
if (effectiveTimeoutMs !== undefined && effectiveTimeoutMs <= 0) {
|
|
109
|
-
throw new RuntimeOperationTimeoutError(operation, deadlineTimeoutMs ?? timeoutMs ?? 0, "invoke");
|
|
110
|
-
}
|
|
111
|
-
let next;
|
|
112
|
-
try {
|
|
113
|
-
next = await this.withTimeout(() => iterator.next(), effectiveTimeoutMs, operation, "stream");
|
|
114
|
-
}
|
|
115
|
-
catch (error) {
|
|
116
|
-
if (error instanceof RuntimeOperationTimeoutError &&
|
|
117
|
-
deadlineAt &&
|
|
118
|
-
deadlineTimeoutMs &&
|
|
119
|
-
effectiveTimeoutMs !== timeoutMs) {
|
|
120
|
-
throw new RuntimeOperationTimeoutError(operation, deadlineTimeoutMs, "invoke");
|
|
121
|
-
}
|
|
122
|
-
throw error;
|
|
123
|
-
}
|
|
124
|
-
if (next.done) {
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
yield next.value;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
finally {
|
|
131
|
-
if (typeof iterator.return === "function") {
|
|
132
|
-
const returnResult = iterator.return();
|
|
133
|
-
if (returnResult && typeof returnResult.then === "function") {
|
|
134
|
-
void returnResult.catch(() => undefined);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
60
|
+
yield* iterateWithTimeoutHelper(iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs);
|
|
138
61
|
}
|
|
139
62
|
async materializeModelStream(streamFactory, input, config) {
|
|
140
|
-
|
|
141
|
-
let content = "";
|
|
142
|
-
for await (const chunk of stream) {
|
|
143
|
-
const delta = readStreamDelta(chunk) || extractVisibleOutput(chunk);
|
|
144
|
-
if (delta) {
|
|
145
|
-
content += delta;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return { content };
|
|
63
|
+
return materializeModelStreamHelper(streamFactory, input, config);
|
|
149
64
|
}
|
|
150
65
|
createModelFallbackRunnable(model) {
|
|
151
|
-
return
|
|
152
|
-
invoke: async (input, config) => {
|
|
153
|
-
const request = typeof input === "object" && input !== null && "messages" in input
|
|
154
|
-
? input.messages
|
|
155
|
-
: input;
|
|
156
|
-
if (typeof model.invoke === "function") {
|
|
157
|
-
return model.invoke(request, config);
|
|
158
|
-
}
|
|
159
|
-
if (typeof model.stream === "function") {
|
|
160
|
-
return this.materializeModelStream(model.stream.bind(model), request, config);
|
|
161
|
-
}
|
|
162
|
-
throw new Error("Resolved model must define invoke or stream.");
|
|
163
|
-
},
|
|
164
|
-
stream: async (input, config) => {
|
|
165
|
-
if (typeof model.stream === "function") {
|
|
166
|
-
const request = typeof input === "object" && input !== null && "messages" in input
|
|
167
|
-
? input.messages
|
|
168
|
-
: input;
|
|
169
|
-
return model.stream(request, config);
|
|
170
|
-
}
|
|
171
|
-
if (typeof model.invoke === "function") {
|
|
172
|
-
const request = typeof input === "object" && input !== null && "messages" in input
|
|
173
|
-
? input.messages
|
|
174
|
-
: input;
|
|
175
|
-
const result = await model.invoke(request, config);
|
|
176
|
-
const text = extractVisibleOutput(result);
|
|
177
|
-
async function* singleChunk() {
|
|
178
|
-
yield { content: text };
|
|
179
|
-
}
|
|
180
|
-
return singleChunk();
|
|
181
|
-
}
|
|
182
|
-
throw new Error("Resolved model must define invoke or stream.");
|
|
183
|
-
},
|
|
184
|
-
};
|
|
66
|
+
return createModelFallbackRunnableHelper(model);
|
|
185
67
|
}
|
|
186
68
|
applyStrictToolJsonInstruction(binding) {
|
|
187
|
-
|
|
188
|
-
const params = getBindingLangChainParams(binding);
|
|
189
|
-
return {
|
|
190
|
-
...binding,
|
|
191
|
-
langchainAgentParams: {
|
|
192
|
-
...params,
|
|
193
|
-
systemPrompt: [params.systemPrompt, STRICT_TOOL_JSON_INSTRUCTION].filter(Boolean).join("\n\n"),
|
|
194
|
-
},
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
if (isDeepAgentBinding(binding)) {
|
|
198
|
-
const params = getBindingDeepAgentParams(binding);
|
|
199
|
-
return {
|
|
200
|
-
...binding,
|
|
201
|
-
deepAgentParams: {
|
|
202
|
-
...params,
|
|
203
|
-
systemPrompt: [params.systemPrompt, STRICT_TOOL_JSON_INSTRUCTION].filter(Boolean).join("\n\n"),
|
|
204
|
-
},
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
return binding;
|
|
69
|
+
return applyStrictToolJsonInstructionHelper(binding);
|
|
208
70
|
}
|
|
209
71
|
async resolveModel(model) {
|
|
210
72
|
const cacheKey = this.getModelCacheKey(model);
|
|
@@ -225,20 +87,10 @@ export class AgentRuntimeAdapter {
|
|
|
225
87
|
}
|
|
226
88
|
}
|
|
227
89
|
resolveTools(tools, binding) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (resolvedTool === undefined) {
|
|
233
|
-
return [];
|
|
234
|
-
}
|
|
235
|
-
const wrappedTool = wrapToolForExecution(resolvedTool, compiledTool, binding);
|
|
236
|
-
const modelFacingName = toolNameMapping.originalToModelFacing.get(compiledTool.name) ?? compiledTool.name;
|
|
237
|
-
const structuredTool = asStructuredExecutableTool(wrappedTool, modelFacingName, compiledTool.description);
|
|
238
|
-
if (structuredTool !== wrappedTool) {
|
|
239
|
-
return structuredTool;
|
|
240
|
-
}
|
|
241
|
-
return modelFacingName === compiledTool.name ? wrappedTool : wrapResolvedToolWithModelFacingName(wrappedTool, modelFacingName);
|
|
90
|
+
return resolveAdapterTools({
|
|
91
|
+
tools,
|
|
92
|
+
binding,
|
|
93
|
+
resolveToolValues: this.options.toolResolver,
|
|
242
94
|
});
|
|
243
95
|
}
|
|
244
96
|
resolveFilesystemBackend(binding) {
|
|
@@ -259,24 +111,12 @@ export class AgentRuntimeAdapter {
|
|
|
259
111
|
});
|
|
260
112
|
}
|
|
261
113
|
resolveBuiltinMiddlewareBackend(binding, options = {}) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
store: this.options.storeResolver?.(binding),
|
|
269
|
-
};
|
|
270
|
-
const configuredBackend = isDeepAgentBinding(binding)
|
|
271
|
-
? this.options.backendResolver?.(binding)
|
|
272
|
-
: this.resolveFilesystemBackend(binding);
|
|
273
|
-
if (typeof configuredBackend === "function") {
|
|
274
|
-
return configuredBackend(runtimeLike);
|
|
275
|
-
}
|
|
276
|
-
if (configuredBackend) {
|
|
277
|
-
return configuredBackend;
|
|
278
|
-
}
|
|
279
|
-
return new StateBackend(runtimeLike);
|
|
114
|
+
return resolveBuiltinMiddlewareBackendHelper({
|
|
115
|
+
binding,
|
|
116
|
+
runtimeAdapterOptions: this.options,
|
|
117
|
+
resolveFilesystemBackend: (currentBinding) => this.resolveFilesystemBackend(currentBinding),
|
|
118
|
+
options,
|
|
119
|
+
});
|
|
280
120
|
}
|
|
281
121
|
createDeclaredMiddlewareResolverOptions(binding) {
|
|
282
122
|
return {
|
|
@@ -294,149 +134,57 @@ export class AgentRuntimeAdapter {
|
|
|
294
134
|
};
|
|
295
135
|
}
|
|
296
136
|
async invokeBuiltinTaskTool(binding, input, options = {}) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
const description = typeof typedInput.description === "string" ? typedInput.description : "";
|
|
306
|
-
const subagentType = typeof typedInput.subagent_type === "string" ? typedInput.subagent_type : "";
|
|
307
|
-
const builtinBackend = this.resolveBuiltinMiddlewareBackend(binding, options);
|
|
308
|
-
const resolvedSubagents = await this.resolveSubagents(params.subagents, binding);
|
|
309
|
-
const selectedSubagent = resolvedSubagents.find((subagent) => subagent.name === subagentType);
|
|
310
|
-
if (!selectedSubagent) {
|
|
311
|
-
const allowed = [
|
|
312
|
-
...resolvedSubagents.map((subagent) => subagent.name),
|
|
313
|
-
...(params.generalPurposeAgent ? ["general-purpose"] : []),
|
|
314
|
-
];
|
|
315
|
-
throw new Error(`Error: invoked agent of type ${subagentType}, the only allowed types are ${allowed.map((name) => `\`${name}\``).join(", ")}`);
|
|
316
|
-
}
|
|
317
|
-
const summarizationModel = selectedSubagent.model
|
|
318
|
-
? await this.resolveModel(selectedSubagent.model)
|
|
319
|
-
: await this.resolveModel(params.model);
|
|
320
|
-
const middleware = [
|
|
321
|
-
...(selectedSubagent.skills?.length
|
|
322
|
-
? [createSkillsMiddleware({ backend: builtinBackend, sources: selectedSubagent.skills })]
|
|
323
|
-
: []),
|
|
324
|
-
...(selectedSubagent.memory?.length
|
|
325
|
-
? [createMemoryMiddleware({ backend: builtinBackend, sources: selectedSubagent.memory })]
|
|
326
|
-
: []),
|
|
327
|
-
...(selectedSubagent.middleware ??
|
|
328
|
-
[
|
|
329
|
-
createPatchToolCallsMiddleware(),
|
|
330
|
-
createSummarizationMiddleware({
|
|
331
|
-
model: summarizationModel,
|
|
332
|
-
backend: builtinBackend,
|
|
333
|
-
}),
|
|
334
|
-
]),
|
|
335
|
-
...(selectedSubagent.interruptOn
|
|
336
|
-
? [humanInTheLoopMiddleware({
|
|
337
|
-
interruptOn: compileInterruptOn(selectedSubagent.tools ?? [], selectedSubagent.interruptOn),
|
|
338
|
-
})]
|
|
339
|
-
: []),
|
|
340
|
-
];
|
|
341
|
-
const runnable = createAgent({
|
|
342
|
-
model: (selectedSubagent.model ?? (await this.resolveModel(params.model))),
|
|
343
|
-
tools: (selectedSubagent.tools ?? this.resolveTools(params.tools, binding)),
|
|
344
|
-
systemPrompt: selectedSubagent.systemPrompt ?? DEFAULT_SUBAGENT_PROMPT,
|
|
345
|
-
middleware: middleware,
|
|
346
|
-
responseFormat: selectedSubagent.responseFormat,
|
|
347
|
-
contextSchema: selectedSubagent.contextSchema,
|
|
348
|
-
name: selectedSubagent.name,
|
|
349
|
-
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),
|
|
350
145
|
});
|
|
351
|
-
const result = await runnable.invoke({ messages: [new HumanMessage({ content: description })] }, { configurable: { thread_id: `${binding.agent.id}:builtin-task` }, ...(options.context ? { context: options.context } : {}) });
|
|
352
|
-
const visibleOutput = extractVisibleOutput(result);
|
|
353
|
-
const fallbackOutput = extractToolFallbackContext(result);
|
|
354
|
-
return visibleOutput || fallbackOutput || JSON.stringify(result);
|
|
355
146
|
}
|
|
356
147
|
async resolveBuiltinMiddlewareTools(binding, options = {}) {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
: 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),
|
|
363
153
|
});
|
|
364
154
|
}
|
|
365
155
|
async resolveAutomaticSummarizationMiddleware(binding) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
if (!primaryModel) {
|
|
371
|
-
return [];
|
|
372
|
-
}
|
|
373
|
-
return resolveDeclaredMiddleware([{ kind: "summarization", model: primaryModel }], this.createDeclaredMiddlewareResolverOptions(binding));
|
|
156
|
+
return resolveAutomaticSummarizationMiddlewareHelper({
|
|
157
|
+
binding,
|
|
158
|
+
createDeclaredMiddlewareResolverOptions: (currentBinding) => this.createDeclaredMiddlewareResolverOptions(currentBinding),
|
|
159
|
+
});
|
|
374
160
|
}
|
|
375
161
|
async resolveLangChainAutomaticMiddleware(binding) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
if ((compatibleParams.skills?.length ?? 0) > 0) {
|
|
385
|
-
automaticMiddleware.push(createSkillsMiddleware({
|
|
386
|
-
backend: this.resolveFilesystemBackend(binding),
|
|
387
|
-
sources: compatibleParams.skills,
|
|
388
|
-
}));
|
|
389
|
-
}
|
|
390
|
-
if ((compatibleParams.memory?.length ?? 0) > 0) {
|
|
391
|
-
automaticMiddleware.push(createMemoryMiddleware({
|
|
392
|
-
backend: this.resolveFilesystemBackend(binding),
|
|
393
|
-
sources: compatibleParams.memory,
|
|
394
|
-
}));
|
|
395
|
-
}
|
|
396
|
-
if (hasConfiguredSubagentSupport(binding)) {
|
|
397
|
-
automaticMiddleware.push(createSubAgentMiddleware({
|
|
398
|
-
defaultModel: (await this.resolveModel(compatibleParams.model)),
|
|
399
|
-
defaultTools: this.resolveTools(compatibleParams.tools, binding),
|
|
400
|
-
defaultInterruptOn: getBindingInterruptCompatibilityRules(binding),
|
|
401
|
-
subagents: (await this.resolveSubagents(compatibleParams.subagents ?? [], binding)),
|
|
402
|
-
generalPurposeAgent: compatibleParams.generalPurposeAgent,
|
|
403
|
-
taskDescription: compatibleParams.taskDescription ?? null,
|
|
404
|
-
}));
|
|
405
|
-
}
|
|
406
|
-
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
|
+
});
|
|
407
170
|
}
|
|
408
171
|
async resolveMiddleware(binding, interruptOn) {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
:
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
...(this.options.middlewareResolver ? this.options.middlewareResolver(binding) : []),
|
|
417
|
-
];
|
|
418
|
-
if (interruptOn && Object.keys(interruptOn).length > 0) {
|
|
419
|
-
middleware.push(humanInTheLoopMiddleware({ interruptOn }));
|
|
420
|
-
}
|
|
421
|
-
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
|
+
});
|
|
422
179
|
}
|
|
423
180
|
async resolveSubagents(subagents, binding) {
|
|
424
|
-
return
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
runRoot: binding?.harnessRuntime.runRoot,
|
|
432
|
-
ownerId: `${binding?.agent.id ?? "agent"}-${subagent.name}`,
|
|
433
|
-
skillPaths: subagent.skills,
|
|
434
|
-
}),
|
|
435
|
-
interruptOn: compileInterruptOn(subagent.tools ?? [], subagent.interruptOn),
|
|
436
|
-
responseFormat: subagent.responseFormat,
|
|
437
|
-
contextSchema: subagent.contextSchema,
|
|
438
|
-
middleware: (await resolveDeclaredMiddleware(subagent.middleware, this.createDeclaredMiddlewareResolverOptions(binding))),
|
|
439
|
-
})));
|
|
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
|
+
});
|
|
440
188
|
}
|
|
441
189
|
async createLangChainRunnable(binding, options = {}) {
|
|
442
190
|
const params = getBindingLangChainParams(binding);
|
|
@@ -517,50 +265,22 @@ export class AgentRuntimeAdapter {
|
|
|
517
265
|
});
|
|
518
266
|
};
|
|
519
267
|
const callRuntimeWithToolParseRecovery = async (activeRequest) => {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
}
|
|
527
|
-
return callRuntime(this.applyStrictToolJsonInstruction(binding), activeRequest);
|
|
528
|
-
}
|
|
268
|
+
return callRuntimeWithToolParseRecoveryHelper({
|
|
269
|
+
binding,
|
|
270
|
+
request: activeRequest,
|
|
271
|
+
resumePayload,
|
|
272
|
+
callRuntime,
|
|
273
|
+
});
|
|
529
274
|
};
|
|
530
275
|
const primaryTools = getBindingPrimaryTools(binding);
|
|
531
276
|
const resolvedTools = this.resolveTools(primaryTools, binding);
|
|
532
277
|
const toolNameMapping = buildToolNameMapping(primaryTools);
|
|
533
|
-
const executableTools =
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
}
|
|
540
|
-
const handler = async (toolInput) => {
|
|
541
|
-
const callable = typeof resolvedTool.invoke === "function"
|
|
542
|
-
? resolvedTool.invoke
|
|
543
|
-
: typeof resolvedTool.call === "function"
|
|
544
|
-
? resolvedTool.call
|
|
545
|
-
: resolvedTool.func;
|
|
546
|
-
if (!callable) {
|
|
547
|
-
throw new Error(`Tool ${compiledTool.name} has no callable handler.`);
|
|
548
|
-
}
|
|
549
|
-
return Promise.resolve(callable.call(resolvedTool, toolInput, options.context ? { context: options.context } : undefined));
|
|
550
|
-
};
|
|
551
|
-
const modelFacingName = toolNameMapping.originalToModelFacing.get(compiledTool.name) ?? compiledTool.name;
|
|
552
|
-
const normalizedSchema = normalizeResolvedToolSchema(resolvedTool);
|
|
553
|
-
executableTools.set(modelFacingName, {
|
|
554
|
-
name: compiledTool.name,
|
|
555
|
-
schema: normalizedSchema,
|
|
556
|
-
invoke: handler,
|
|
557
|
-
});
|
|
558
|
-
executableTools.set(compiledTool.name, {
|
|
559
|
-
name: compiledTool.name,
|
|
560
|
-
schema: normalizedSchema,
|
|
561
|
-
invoke: handler,
|
|
562
|
-
});
|
|
563
|
-
}
|
|
278
|
+
const executableTools = buildExecutableToolMap({
|
|
279
|
+
primaryTools,
|
|
280
|
+
resolvedTools,
|
|
281
|
+
toolNameMapping,
|
|
282
|
+
context: options.context,
|
|
283
|
+
});
|
|
564
284
|
const builtinExecutableTools = await this.resolveBuiltinMiddlewareTools(binding, options);
|
|
565
285
|
const localOrUpstreamInvocation = await invokeRuntimeWithLocalTools({
|
|
566
286
|
binding,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { RunResult, ThreadSummary } from "../../../contracts/types.js";
|
|
2
|
+
import type { RuntimePersistence } from "../../../persistence/types.js";
|
|
3
|
+
import type { ConcurrencyConfig, RecoveryConfig } from "../../../workspace/support/workspace-ref-utils.js";
|
|
4
|
+
import { recoverQueuedStartupRun } from "./recovery.js";
|
|
5
|
+
type Startable = {
|
|
6
|
+
start(): Promise<void>;
|
|
7
|
+
};
|
|
8
|
+
type StartupRecoveryContext = Parameters<typeof recoverQueuedStartupRun>[0];
|
|
9
|
+
export declare function initializeHarnessRuntime(input: {
|
|
10
|
+
persistence: RuntimePersistence;
|
|
11
|
+
checkpointMaintenance: Startable | null;
|
|
12
|
+
runtimeRecordMaintenance: Startable | null;
|
|
13
|
+
healthMonitor: Startable | null;
|
|
14
|
+
recoverStartupRuns: () => Promise<void>;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
export declare function recoverStartupRuns(input: {
|
|
17
|
+
recoveryConfig: RecoveryConfig;
|
|
18
|
+
persistence: RuntimePersistence;
|
|
19
|
+
createStartupRecoveryContext: () => StartupRecoveryContext;
|
|
20
|
+
reclaimExpiredClaimedRuns: (nowIso?: string) => Promise<void>;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
export declare function reclaimExpiredClaimedRuns(input: {
|
|
23
|
+
persistence: RuntimePersistence;
|
|
24
|
+
setRunStateAndEmit: (threadId: string, runId: string, sequence: number, state: RunResult["state"], options: {
|
|
25
|
+
previousState: string | null;
|
|
26
|
+
checkpointRef?: string | null;
|
|
27
|
+
error?: string;
|
|
28
|
+
}) => Promise<unknown>;
|
|
29
|
+
emit: (threadId: string, runId: string, sequence: number, eventType: string, payload: Record<string, unknown>) => Promise<unknown>;
|
|
30
|
+
concurrencyConfig: ConcurrencyConfig;
|
|
31
|
+
getActiveRunSlots: () => number;
|
|
32
|
+
}, nowIso?: string): Promise<void>;
|
|
33
|
+
export declare function isStaleRunningRun(input: {
|
|
34
|
+
persistence: RuntimePersistence;
|
|
35
|
+
concurrencyConfig: ConcurrencyConfig;
|
|
36
|
+
}, thread: ThreadSummary, nowMs?: number): Promise<boolean>;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { recoverQueuedStartupRun, recoverResumingStartupRun, recoverRunningStartupRun, } from "./recovery.js";
|
|
2
|
+
export async function initializeHarnessRuntime(input) {
|
|
3
|
+
await input.persistence.initialize();
|
|
4
|
+
await input.checkpointMaintenance?.start();
|
|
5
|
+
await input.runtimeRecordMaintenance?.start();
|
|
6
|
+
await input.healthMonitor?.start();
|
|
7
|
+
await input.recoverStartupRuns();
|
|
8
|
+
}
|
|
9
|
+
export async function recoverStartupRuns(input) {
|
|
10
|
+
if (!input.recoveryConfig.enabled) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
await input.reclaimExpiredClaimedRuns();
|
|
14
|
+
const threads = await input.persistence.listSessions();
|
|
15
|
+
const recoveryContext = input.createStartupRecoveryContext();
|
|
16
|
+
for (const thread of threads) {
|
|
17
|
+
const handled = await recoverQueuedStartupRun(recoveryContext, thread) ||
|
|
18
|
+
await recoverRunningStartupRun(recoveryContext, thread) ||
|
|
19
|
+
await recoverResumingStartupRun(recoveryContext, thread);
|
|
20
|
+
if (handled) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export async function reclaimExpiredClaimedRuns(input, nowIso = new Date().toISOString()) {
|
|
26
|
+
const expiredClaims = await input.persistence.listExpiredClaimedRuns(nowIso);
|
|
27
|
+
for (const claim of expiredClaims) {
|
|
28
|
+
const thread = await input.persistence.getSession(claim.threadId);
|
|
29
|
+
if (!thread) {
|
|
30
|
+
await input.persistence.releaseRunClaim(claim.runId);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const lifecycle = await input.persistence.getRunLifecycle(claim.threadId, claim.runId);
|
|
34
|
+
if (lifecycle.state === "claimed") {
|
|
35
|
+
await input.persistence.enqueueRun({
|
|
36
|
+
threadId: claim.threadId,
|
|
37
|
+
runId: claim.runId,
|
|
38
|
+
priority: claim.priority,
|
|
39
|
+
queueKey: claim.queueKey,
|
|
40
|
+
availableAt: nowIso,
|
|
41
|
+
});
|
|
42
|
+
await input.setRunStateAndEmit(claim.threadId, claim.runId, 99, "queued", {
|
|
43
|
+
previousState: "claimed",
|
|
44
|
+
});
|
|
45
|
+
await input.emit(claim.threadId, claim.runId, 100, "run.queued", {
|
|
46
|
+
queuePosition: 0,
|
|
47
|
+
activeRunCount: input.getActiveRunSlots(),
|
|
48
|
+
maxConcurrentRuns: input.concurrencyConfig.maxConcurrentRuns,
|
|
49
|
+
recoveredOnStartup: true,
|
|
50
|
+
reclaimReason: "expired-lease",
|
|
51
|
+
});
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
await input.persistence.releaseRunClaim(claim.runId);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export async function isStaleRunningRun(input, thread, nowMs = Date.now()) {
|
|
58
|
+
const control = await input.persistence.getRunControl(thread.latestRunId);
|
|
59
|
+
const heartbeatAt = control?.heartbeatAt;
|
|
60
|
+
if (!heartbeatAt) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
const heartbeatAtMs = Date.parse(heartbeatAt);
|
|
64
|
+
if (!Number.isFinite(heartbeatAtMs)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
return nowMs - heartbeatAtMs >= input.concurrencyConfig.heartbeatTimeoutMs;
|
|
68
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ApprovalRecord, ThreadRecord, ThreadSummary } from "../../../contracts/types.js";
|
|
2
|
+
import type { RuntimePersistence } from "../../../persistence/types.js";
|
|
3
|
+
export declare function getThreadRecord(input: {
|
|
4
|
+
persistence: RuntimePersistence;
|
|
5
|
+
getSession: (threadId: string) => Promise<ThreadSummary | null>;
|
|
6
|
+
}, threadId: string): Promise<ThreadRecord | null>;
|
|
7
|
+
export declare function listPublicApprovals(input: {
|
|
8
|
+
persistence: RuntimePersistence;
|
|
9
|
+
}, filter?: {
|
|
10
|
+
status?: ApprovalRecord["status"];
|
|
11
|
+
threadId?: string;
|
|
12
|
+
runId?: string;
|
|
13
|
+
}): Promise<ApprovalRecord[]>;
|
|
14
|
+
export declare function getPublicApproval(input: {
|
|
15
|
+
persistence: RuntimePersistence;
|
|
16
|
+
}, approvalId: string): Promise<ApprovalRecord | null>;
|
|
17
|
+
export declare function deleteThreadRecord(input: {
|
|
18
|
+
getThread: (threadId: string) => Promise<ThreadRecord | null>;
|
|
19
|
+
deleteThread: (threadId: string) => Promise<boolean>;
|
|
20
|
+
deleteThreadCheckpoints: (threadId: string) => Promise<void>;
|
|
21
|
+
}, threadId: string): Promise<boolean>;
|