@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.
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.30";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.32";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.30";
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
- let terminalOutput = "";
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
- terminalOutput += output;
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 (terminalOutput) {
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.31",
3
+ "version": "0.0.33",
4
4
  "description": "Agent Harness framework package",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",