@botbotgo/agent-harness 0.0.31 → 0.0.33
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/agent-runtime-adapter.d.ts +1 -0
- package/dist/runtime/agent-runtime-adapter.js +102 -5
- package/dist/runtime/parsing/stream-event-parsing.d.ts +6 -0
- package/dist/runtime/parsing/stream-event-parsing.js +53 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.32";
|
package/dist/package-version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.32";
|
|
@@ -15,6 +15,7 @@ declare class RuntimeOperationTimeoutError extends Error {
|
|
|
15
15
|
export declare class AgentRuntimeAdapter {
|
|
16
16
|
private readonly options;
|
|
17
17
|
constructor(options?: RuntimeAdapterOptions);
|
|
18
|
+
private canUseSimpleDeepAgentFastPath;
|
|
18
19
|
private resolveBindingTimeout;
|
|
19
20
|
private resolveStreamIdleTimeout;
|
|
20
21
|
private withTimeout;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { Command, MemorySaver } from "@langchain/langgraph";
|
|
2
|
+
import { tool as createLangChainTool } from "@langchain/core/tools";
|
|
2
3
|
import { createDeepAgent } from "deepagents";
|
|
3
4
|
import { ChatAnthropic } from "@langchain/anthropic";
|
|
4
5
|
import { ChatGoogle } from "@langchain/google";
|
|
5
6
|
import { ChatOllama } from "@langchain/ollama";
|
|
6
7
|
import { ChatOpenAI } from "@langchain/openai";
|
|
7
8
|
import { createAgent, humanInTheLoopMiddleware, initChatModel } from "langchain";
|
|
9
|
+
import { z } from "zod";
|
|
8
10
|
import { extractEmptyAssistantMessageFailure, extractReasoningText, extractToolFallbackContext, extractVisibleOutput, isLikelyToolArgsObject, isToolCallParseFailure, STRICT_TOOL_JSON_INSTRUCTION, sanitizeVisibleText, tryParseJson, wrapResolvedModel, } from "./parsing/output-parsing.js";
|
|
9
|
-
import { extractAgentStep, extractInterruptPayload, extractReasoningStreamOutput, extractTerminalStreamOutput, extractToolResult, normalizeTerminalOutputKey, readStreamDelta, } from "./parsing/stream-event-parsing.js";
|
|
11
|
+
import { computeIncrementalOutput, extractAgentStep, extractInterruptPayload, extractReasoningStreamOutput, extractStateStreamOutput, extractVisibleStreamOutput, extractTerminalStreamOutput, extractToolResult, normalizeTerminalOutputKey, readStreamDelta, } from "./parsing/stream-event-parsing.js";
|
|
10
12
|
import { wrapToolForExecution } from "./tool-hitl.js";
|
|
11
13
|
import { resolveDeclaredMiddleware } from "./declared-middleware.js";
|
|
12
14
|
import { extractMessageText, normalizeMessageContent } from "../utils/message-content.js";
|
|
@@ -120,6 +122,37 @@ function wrapResolvedToolWithModelFacingName(resolvedTool, modelFacingName) {
|
|
|
120
122
|
},
|
|
121
123
|
});
|
|
122
124
|
}
|
|
125
|
+
function hasCallableToolHandler(value) {
|
|
126
|
+
if (typeof value !== "object" || value === null) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
const typed = value;
|
|
130
|
+
return typeof typed.invoke === "function" || typeof typed.call === "function" || typeof typed.func === "function";
|
|
131
|
+
}
|
|
132
|
+
function normalizeResolvedToolSchema(resolvedTool) {
|
|
133
|
+
const schema = resolvedTool.schema;
|
|
134
|
+
if (schema && typeof schema.parse === "function" && "_def" in schema) {
|
|
135
|
+
return resolvedTool.schema;
|
|
136
|
+
}
|
|
137
|
+
if (schema && (schema.type === "object" || typeof schema.properties === "object")) {
|
|
138
|
+
return schema;
|
|
139
|
+
}
|
|
140
|
+
return z.object({}).passthrough();
|
|
141
|
+
}
|
|
142
|
+
function asStructuredExecutableTool(resolvedTool, modelFacingName, description) {
|
|
143
|
+
if (!hasCallableToolHandler(resolvedTool)) {
|
|
144
|
+
return resolvedTool;
|
|
145
|
+
}
|
|
146
|
+
const handler = resolvedTool.invoke ?? resolvedTool.call ?? resolvedTool.func;
|
|
147
|
+
if (typeof handler !== "function") {
|
|
148
|
+
return resolvedTool;
|
|
149
|
+
}
|
|
150
|
+
return createLangChainTool(async (input, config) => handler(input, config), {
|
|
151
|
+
name: modelFacingName,
|
|
152
|
+
description,
|
|
153
|
+
schema: normalizeResolvedToolSchema(resolvedTool),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
123
156
|
function countConfiguredTools(binding) {
|
|
124
157
|
return binding.langchainAgentParams?.tools.length ?? binding.deepAgentParams?.tools.length ?? 0;
|
|
125
158
|
}
|
|
@@ -128,6 +161,25 @@ export class AgentRuntimeAdapter {
|
|
|
128
161
|
constructor(options = {}) {
|
|
129
162
|
this.options = options;
|
|
130
163
|
}
|
|
164
|
+
canUseSimpleDeepAgentFastPath(binding) {
|
|
165
|
+
const params = binding.deepAgentParams;
|
|
166
|
+
if (!params) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
if ((params.subagents?.length ?? 0) > 0) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
if ((params.memory?.length ?? 0) > 0) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
if ((params.skills?.length ?? 0) > 0) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
if (params.backend || params.store) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
131
183
|
resolveBindingTimeout(binding) {
|
|
132
184
|
return resolveTimeoutMs(binding.langchainAgentParams?.model.init.timeout ?? binding.deepAgentParams?.model.init.timeout);
|
|
133
185
|
}
|
|
@@ -317,6 +369,10 @@ export class AgentRuntimeAdapter {
|
|
|
317
369
|
}
|
|
318
370
|
const wrappedTool = wrapToolForExecution(resolvedTool, compiledTool);
|
|
319
371
|
const modelFacingName = toolNameMapping.originalToModelFacing.get(compiledTool.name) ?? compiledTool.name;
|
|
372
|
+
const structuredTool = asStructuredExecutableTool(wrappedTool, modelFacingName, compiledTool.description);
|
|
373
|
+
if (structuredTool !== wrappedTool) {
|
|
374
|
+
return structuredTool;
|
|
375
|
+
}
|
|
320
376
|
return modelFacingName === compiledTool.name ? wrappedTool : wrapResolvedToolWithModelFacingName(wrappedTool, modelFacingName);
|
|
321
377
|
});
|
|
322
378
|
}
|
|
@@ -431,6 +487,23 @@ export class AgentRuntimeAdapter {
|
|
|
431
487
|
if (!params) {
|
|
432
488
|
throw new Error(`Agent ${binding.agent.id} has no runnable params`);
|
|
433
489
|
}
|
|
490
|
+
if (this.canUseSimpleDeepAgentFastPath(binding)) {
|
|
491
|
+
const interruptOn = this.resolveInterruptOn(binding);
|
|
492
|
+
const model = (await this.resolveModel(params.model));
|
|
493
|
+
const tools = this.resolveTools(params.tools, binding);
|
|
494
|
+
if (tools.length > 0 && typeof model.bindTools !== "function") {
|
|
495
|
+
throw new Error(`Agent ${binding.agent.id} configures ${tools.length} tool(s), but resolved model ${params.model.id} does not support tool binding.`);
|
|
496
|
+
}
|
|
497
|
+
return createAgent({
|
|
498
|
+
model: model,
|
|
499
|
+
tools: tools,
|
|
500
|
+
systemPrompt: params.systemPrompt,
|
|
501
|
+
responseFormat: params.responseFormat,
|
|
502
|
+
contextSchema: params.contextSchema,
|
|
503
|
+
middleware: (await this.resolveMiddleware(binding, interruptOn)),
|
|
504
|
+
checkpointer: this.resolveCheckpointer(binding),
|
|
505
|
+
});
|
|
506
|
+
}
|
|
434
507
|
const deepAgentConfig = {
|
|
435
508
|
model: (await this.resolveModel(params.model)),
|
|
436
509
|
tools: this.resolveTools(params.tools, binding),
|
|
@@ -554,7 +627,8 @@ export class AgentRuntimeAdapter {
|
|
|
554
627
|
const request = { messages: this.buildAgentMessages(history, input) };
|
|
555
628
|
if (typeof runnable.streamEvents === "function") {
|
|
556
629
|
const events = await this.withTimeout(() => runnable.streamEvents(request, { configurable: { thread_id: threadId }, version: "v2" }), invokeTimeoutMs, "agent streamEvents start", "stream");
|
|
557
|
-
|
|
630
|
+
const allowVisibleStreamDeltas = Boolean(binding.langchainAgentParams);
|
|
631
|
+
let emittedOutput = "";
|
|
558
632
|
const seenTerminalOutputs = new Set();
|
|
559
633
|
let lastStep = "";
|
|
560
634
|
for await (const event of this.iterateWithTimeout(events, streamIdleTimeoutMs, "agent streamEvents")) {
|
|
@@ -567,6 +641,26 @@ export class AgentRuntimeAdapter {
|
|
|
567
641
|
if (reasoning) {
|
|
568
642
|
yield { kind: "reasoning", content: reasoning };
|
|
569
643
|
}
|
|
644
|
+
if (allowVisibleStreamDeltas) {
|
|
645
|
+
const visibleStreamOutput = extractVisibleStreamOutput(event);
|
|
646
|
+
if (visibleStreamOutput) {
|
|
647
|
+
const nextOutput = computeIncrementalOutput(emittedOutput, visibleStreamOutput);
|
|
648
|
+
emittedOutput = nextOutput.accumulated;
|
|
649
|
+
if (nextOutput.delta) {
|
|
650
|
+
yield { kind: "content", content: nextOutput.delta };
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
if (binding.deepAgentParams) {
|
|
655
|
+
const stateStreamOutput = extractStateStreamOutput(event);
|
|
656
|
+
if (stateStreamOutput) {
|
|
657
|
+
const nextOutput = computeIncrementalOutput(emittedOutput, sanitizeVisibleText(stateStreamOutput));
|
|
658
|
+
emittedOutput = nextOutput.accumulated;
|
|
659
|
+
if (nextOutput.delta) {
|
|
660
|
+
yield { kind: "content", content: nextOutput.delta };
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
570
664
|
const agentStep = extractAgentStep(event);
|
|
571
665
|
if (agentStep && agentStep !== lastStep) {
|
|
572
666
|
lastStep = agentStep;
|
|
@@ -585,11 +679,14 @@ export class AgentRuntimeAdapter {
|
|
|
585
679
|
if (outputKey) {
|
|
586
680
|
seenTerminalOutputs.add(outputKey);
|
|
587
681
|
}
|
|
588
|
-
|
|
682
|
+
const nextOutput = computeIncrementalOutput(emittedOutput, sanitizeVisibleText(output));
|
|
683
|
+
emittedOutput = nextOutput.accumulated;
|
|
684
|
+
if (nextOutput.delta) {
|
|
685
|
+
yield { kind: "content", content: nextOutput.delta };
|
|
686
|
+
}
|
|
589
687
|
}
|
|
590
688
|
}
|
|
591
|
-
if (
|
|
592
|
-
yield { kind: "content", content: sanitizeVisibleText(terminalOutput) };
|
|
689
|
+
if (emittedOutput) {
|
|
593
690
|
return;
|
|
594
691
|
}
|
|
595
692
|
}
|
|
@@ -17,6 +17,8 @@ export type RuntimeStreamChunk = {
|
|
|
17
17
|
};
|
|
18
18
|
export declare function extractTerminalStreamOutput(event: unknown): string;
|
|
19
19
|
export declare function extractReasoningStreamOutput(event: unknown): string;
|
|
20
|
+
export declare function extractVisibleStreamOutput(event: unknown): string;
|
|
21
|
+
export declare function extractStateStreamOutput(event: unknown): string;
|
|
20
22
|
export declare function extractAgentStep(event: unknown): string | null;
|
|
21
23
|
export declare function extractToolResult(event: unknown): {
|
|
22
24
|
toolName: string;
|
|
@@ -24,4 +26,8 @@ export declare function extractToolResult(event: unknown): {
|
|
|
24
26
|
} | null;
|
|
25
27
|
export declare function extractInterruptPayload(event: unknown): string | null;
|
|
26
28
|
export declare function normalizeTerminalOutputKey(value: string): string;
|
|
29
|
+
export declare function computeIncrementalOutput(accumulated: string, next: string): {
|
|
30
|
+
accumulated: string;
|
|
31
|
+
delta: string;
|
|
32
|
+
};
|
|
27
33
|
export declare function readStreamDelta(chunk: unknown): string;
|
|
@@ -73,6 +73,29 @@ export function extractReasoningStreamOutput(event) {
|
|
|
73
73
|
const typed = event;
|
|
74
74
|
return typed.event === "on_chat_model_stream" ? extractReasoningText(typed.data?.chunk) : "";
|
|
75
75
|
}
|
|
76
|
+
export function extractVisibleStreamOutput(event) {
|
|
77
|
+
if (typeof event !== "object" || !event)
|
|
78
|
+
return "";
|
|
79
|
+
const typed = event;
|
|
80
|
+
return typed.event === "on_chat_model_stream" ? readTextContent(typed.data?.chunk) : "";
|
|
81
|
+
}
|
|
82
|
+
export function extractStateStreamOutput(event) {
|
|
83
|
+
if (typeof event !== "object" || !event)
|
|
84
|
+
return "";
|
|
85
|
+
const typed = event;
|
|
86
|
+
if (typed.event !== "on_chain_stream") {
|
|
87
|
+
return "";
|
|
88
|
+
}
|
|
89
|
+
const chunk = typed.data?.chunk;
|
|
90
|
+
if (typeof chunk !== "object" || !chunk) {
|
|
91
|
+
return "";
|
|
92
|
+
}
|
|
93
|
+
const record = chunk;
|
|
94
|
+
if (!("messages" in record) && !("output" in record)) {
|
|
95
|
+
return "";
|
|
96
|
+
}
|
|
97
|
+
return extractVisibleOutput(chunk);
|
|
98
|
+
}
|
|
76
99
|
export function extractAgentStep(event) {
|
|
77
100
|
if (typeof event !== "object" || !event)
|
|
78
101
|
return null;
|
|
@@ -156,6 +179,36 @@ export function extractInterruptPayload(event) {
|
|
|
156
179
|
export function normalizeTerminalOutputKey(value) {
|
|
157
180
|
return value.trim();
|
|
158
181
|
}
|
|
182
|
+
export function computeIncrementalOutput(accumulated, next) {
|
|
183
|
+
if (!next) {
|
|
184
|
+
return { accumulated, delta: "" };
|
|
185
|
+
}
|
|
186
|
+
if (!accumulated) {
|
|
187
|
+
return { accumulated: next, delta: next };
|
|
188
|
+
}
|
|
189
|
+
if (next === accumulated || accumulated.endsWith(next)) {
|
|
190
|
+
return { accumulated, delta: "" };
|
|
191
|
+
}
|
|
192
|
+
if (next.startsWith(accumulated)) {
|
|
193
|
+
return {
|
|
194
|
+
accumulated: next,
|
|
195
|
+
delta: next.slice(accumulated.length),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
const overlapLength = Math.min(accumulated.length, next.length);
|
|
199
|
+
for (let size = overlapLength; size > 0; size -= 1) {
|
|
200
|
+
if (accumulated.slice(-size) === next.slice(0, size)) {
|
|
201
|
+
return {
|
|
202
|
+
accumulated: accumulated + next.slice(size),
|
|
203
|
+
delta: next.slice(size),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
accumulated: accumulated + next,
|
|
209
|
+
delta: next,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
159
212
|
export function readStreamDelta(chunk) {
|
|
160
213
|
return readTextContent(chunk);
|
|
161
214
|
}
|