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