@botbotgo/agent-harness 0.0.32 → 0.0.34

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.31";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.33";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.31";
1
+ export const AGENT_HARNESS_VERSION = "0.0.33";
@@ -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;
@@ -8,7 +8,7 @@ import { ChatOpenAI } from "@langchain/openai";
8
8
  import { createAgent, humanInTheLoopMiddleware, initChatModel } from "langchain";
9
9
  import { z } from "zod";
10
10
  import { extractEmptyAssistantMessageFailure, extractReasoningText, extractToolFallbackContext, extractVisibleOutput, isLikelyToolArgsObject, isToolCallParseFailure, STRICT_TOOL_JSON_INSTRUCTION, sanitizeVisibleText, tryParseJson, wrapResolvedModel, } from "./parsing/output-parsing.js";
11
- 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";
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";
@@ -161,6 +161,25 @@ export class AgentRuntimeAdapter {
161
161
  constructor(options = {}) {
162
162
  this.options = options;
163
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
+ }
164
183
  resolveBindingTimeout(binding) {
165
184
  return resolveTimeoutMs(binding.langchainAgentParams?.model.init.timeout ?? binding.deepAgentParams?.model.init.timeout);
166
185
  }
@@ -468,6 +487,23 @@ export class AgentRuntimeAdapter {
468
487
  if (!params) {
469
488
  throw new Error(`Agent ${binding.agent.id} has no runnable params`);
470
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
+ }
471
507
  const deepAgentConfig = {
472
508
  model: (await this.resolveModel(params.model)),
473
509
  tools: this.resolveTools(params.tools, binding),
@@ -591,7 +627,8 @@ export class AgentRuntimeAdapter {
591
627
  const request = { messages: this.buildAgentMessages(history, input) };
592
628
  if (typeof runnable.streamEvents === "function") {
593
629
  const events = await this.withTimeout(() => runnable.streamEvents(request, { configurable: { thread_id: threadId }, version: "v2" }), invokeTimeoutMs, "agent streamEvents start", "stream");
594
- let terminalOutput = "";
630
+ const allowVisibleStreamDeltas = Boolean(binding.langchainAgentParams);
631
+ let emittedOutput = "";
595
632
  const seenTerminalOutputs = new Set();
596
633
  let lastStep = "";
597
634
  for await (const event of this.iterateWithTimeout(events, streamIdleTimeoutMs, "agent streamEvents")) {
@@ -604,6 +641,26 @@ export class AgentRuntimeAdapter {
604
641
  if (reasoning) {
605
642
  yield { kind: "reasoning", content: reasoning };
606
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
+ }
607
664
  const agentStep = extractAgentStep(event);
608
665
  if (agentStep && agentStep !== lastStep) {
609
666
  lastStep = agentStep;
@@ -622,11 +679,14 @@ export class AgentRuntimeAdapter {
622
679
  if (outputKey) {
623
680
  seenTerminalOutputs.add(outputKey);
624
681
  }
625
- 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
+ }
626
687
  }
627
688
  }
628
- if (terminalOutput) {
629
- yield { kind: "content", content: sanitizeVisibleText(terminalOutput) };
689
+ if (emittedOutput) {
630
690
  return;
631
691
  }
632
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
  }
@@ -3,6 +3,9 @@ import { getSkillInheritancePolicy, resolveToolTargets } from "../extensions.js"
3
3
  import { compileModel, compileTool } from "./resource-compilers.js";
4
4
  import { discoverSkillPaths } from "./support/discovery.js";
5
5
  import { compileAgentMemories, getRuntimeDefaults, resolvePromptValue, resolveRefId } from "./support/workspace-ref-utils.js";
6
+ const WORKSPACE_BOUNDARY_GUIDANCE = "Keep repository and file exploration bounded to the current workspace root unless the user explicitly asks for broader host or filesystem access. " +
7
+ "Do not inspect absolute paths outside the workspace, system directories, or unrelated repos by default. " +
8
+ "Prefer workspace-local tools, relative paths, and the current repository checkout when analyzing code.";
6
9
  function requireSkills(pathEntries, workspaceRoot) {
7
10
  return Array.from(new Set(discoverSkillPaths(pathEntries, workspaceRoot)));
8
11
  }
@@ -79,7 +82,7 @@ function buildSubagent(agent, workspaceRoot, models, tools, parentSkills, parent
79
82
  return {
80
83
  name: resolveAgentRuntimeName(agent),
81
84
  description: agent.description,
82
- systemPrompt: resolvePromptValue(agent.deepAgentConfig?.systemPrompt) ?? "",
85
+ systemPrompt: [resolvePromptValue(agent.deepAgentConfig?.systemPrompt), WORKSPACE_BOUNDARY_GUIDANCE].filter(Boolean).join("\n\n"),
83
86
  tools: requireTools(tools, agent.toolRefs, agent.id),
84
87
  model: agent.modelRef ? requireModel(models, agent.modelRef, agent.id) : parentModel,
85
88
  interruptOn: agent.deepAgentConfig?.interruptOn,
@@ -98,10 +101,7 @@ function resolveSystemPrompt(agent) {
98
101
  return resolveDirectPrompt(agent);
99
102
  }
100
103
  const deepagentPrompt = resolvePromptValue(agent.deepAgentConfig?.systemPrompt);
101
- if (deepagentPrompt) {
102
- return deepagentPrompt;
103
- }
104
- return resolveDirectPrompt(agent);
104
+ return [deepagentPrompt ?? resolveDirectPrompt(agent), WORKSPACE_BOUNDARY_GUIDANCE].filter(Boolean).join("\n\n");
105
105
  }
106
106
  function resolveInterruptOn(agent) {
107
107
  if (agent.executionMode !== "deepagent") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.32",
3
+ "version": "0.0.34",
4
4
  "description": "Agent Harness framework package",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",