@botbotgo/agent-harness 0.0.320 → 0.0.322

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,9 +1,10 @@
1
+ import { markdownToConsole } from "../projections/presentation.js";
1
2
  import { renderChatRuntimeFailure } from "./chat-workspace.js";
2
3
  export function countRenderedLines(text) {
3
4
  return text.replace(/\n$/, "").split("\n").length;
4
5
  }
5
6
  export function renderChatTextChunk(text, modelInfo) {
6
- return renderChatRuntimeFailure(text, modelInfo);
7
+ return markdownToConsole(renderChatRuntimeFailure(text, modelInfo));
7
8
  }
8
9
  export function renderChatRequestRunning(input) {
9
10
  const parts = [
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.319";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.321";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.319";
1
+ export const AGENT_HARNESS_VERSION = "0.0.321";
@@ -94,7 +94,7 @@ export function markdownToHtml(markdown) {
94
94
  }
95
95
  export function markdownToConsole(markdown) {
96
96
  if (!markdown.includes("\n")) {
97
- return renderInlineConsoleMarkdown(markdown);
97
+ return renderInlineConsoleMarkdown(markdown.trim());
98
98
  }
99
99
  const normalized = markdown.replace(/\r\n/g, "\n");
100
100
  const blocks = normalized.split(/\n\n+/);
@@ -114,11 +114,12 @@ export function markdownToConsole(markdown) {
114
114
  const language = lines[0]?.slice(3).trim();
115
115
  const code = lines.slice(1, -1);
116
116
  const label = language ? ` ${language} ` : " code ";
117
+ const borderWidth = Math.max(label.length, 6);
117
118
  rendered.push([
118
- `\u001b[2m┌${"─".repeat(Math.max(label.length, 6))}\u001b[0m`,
119
+ `\u001b[2m┌${"─".repeat(borderWidth)}\u001b[0m`,
119
120
  `\u001b[2m│\u001b[0m${label}`,
120
121
  ...code.map((line) => ` ${line}`),
121
- "\u001b[2m└──────\u001b[0m",
122
+ `\u001b[2m└${"─".repeat(borderWidth)}\u001b[0m`,
122
123
  ].join("\n"));
123
124
  continue;
124
125
  }
@@ -130,25 +131,30 @@ export function markdownToConsole(markdown) {
130
131
  rendered.push(`\u001b[1m${title}\u001b[0m\n\u001b[2m${underline.repeat(Math.max(3, title.replace(/\u001b\[[0-9;]*m/g, "").length))}\u001b[0m`);
131
132
  continue;
132
133
  }
133
- if (trimmed.split("\n").every((line) => /^[-*]\s+/.test(line))) {
134
+ if (trimmed.split("\n").every((line) => /^\s*[-*]\s+/.test(line))) {
134
135
  rendered.push(trimmed
135
136
  .split("\n")
136
- .map((line) => line.replace(/^[-*]\s+/, "• "))
137
+ .map((line) => {
138
+ const match = line.match(/^(\s*)[-*]\s+(.*)$/);
139
+ const indent = match?.[1] ?? "";
140
+ const content = match?.[2] ?? line;
141
+ return `${indent}• ${content}`;
142
+ })
137
143
  .map((line) => renderInlineConsoleMarkdown(line))
138
144
  .join("\n"));
139
145
  continue;
140
146
  }
141
- if (trimmed.split("\n").every((line) => /^\d+\.\s+/.test(line))) {
147
+ if (trimmed.split("\n").every((line) => /^\s*\d+\.\s+/.test(line))) {
142
148
  rendered.push(trimmed
143
149
  .split("\n")
144
150
  .map((line) => renderInlineConsoleMarkdown(line))
145
151
  .join("\n"));
146
152
  continue;
147
153
  }
148
- if (trimmed.split("\n").every((line) => /^>\s?/.test(line))) {
154
+ if (trimmed.split("\n").every((line) => /^\s*>\s?/.test(line))) {
149
155
  rendered.push(trimmed
150
156
  .split("\n")
151
- .map((line) => line.replace(/^>\s?/, ""))
157
+ .map((line) => line.replace(/^\s*>\s?/, ""))
152
158
  .map((line) => `\u001b[2m│\u001b[0m ${renderInlineConsoleMarkdown(line)}`)
153
159
  .join("\n"));
154
160
  continue;
@@ -0,0 +1 @@
1
+ Do not stop at a plan or ask the user to choose the next obvious diagnostic step when the request is for deep investigation, root-cause analysis, or step-by-step execution and tool evidence already exists in the conversation. Continue the investigation yourself with the next concrete tool call. If the task is non-trivial, call write_todos, then keep executing the next diagnostic steps until you can explain the likely causes, impact, and recommended next actions.
@@ -11,4 +11,4 @@ export declare function resolveExecutionWithoutToolEvidenceTextInstruction(reque
11
11
  export declare function resolveToolCallRecoveryInstruction(error: unknown): string | null;
12
12
  export declare function appendToolRecoveryInstruction(input: unknown, instruction: string): unknown;
13
13
  export declare function wrapResolvedModel<T>(value: T): T;
14
- export { BROWSER_CAPABILITY_DISCLAIMER_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION, STRICT_TOOL_JSON_INSTRUCTION, WORKSPACE_RELATIVE_PATH_INSTRUCTION, WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION, WRITE_TODOS_FULL_ENTRY_INSTRUCTION, WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION } from "../prompts/runtime-prompts.js";
14
+ export { AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION, BROWSER_CAPABILITY_DISCLAIMER_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION, STRICT_TOOL_JSON_INSTRUCTION, WORKSPACE_RELATIVE_PATH_INSTRUCTION, WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION, WRITE_TODOS_FULL_ENTRY_INSTRUCTION, WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION } from "../prompts/runtime-prompts.js";
@@ -1,4 +1,4 @@
1
- import { BROWSER_CAPABILITY_DISCLAIMER_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, STRICT_TOOL_JSON_INSTRUCTION, WORKSPACE_RELATIVE_PATH_INSTRUCTION, WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION, WRITE_TODOS_FULL_ENTRY_INSTRUCTION, WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION, } from "../prompts/runtime-prompts.js";
1
+ import { AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION, BROWSER_CAPABILITY_DISCLAIMER_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, STRICT_TOOL_JSON_INSTRUCTION, WORKSPACE_RELATIVE_PATH_INSTRUCTION, WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION, WRITE_TODOS_FULL_ENTRY_INSTRUCTION, WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION, } from "../prompts/runtime-prompts.js";
2
2
  import { hasToolCalls, readTextContent, wrapNormalizedMessage } from "./output-content.js";
3
3
  function isToolCallParseFailure(error) {
4
4
  if (!(error instanceof Error))
@@ -123,6 +123,71 @@ function extractLastUserMessageText(input) {
123
123
  }
124
124
  return "";
125
125
  }
126
+ function extractAllUserMessageText(input) {
127
+ if (!Array.isArray(input) && !(typeof input === "object" && input && Array.isArray(input.messages))) {
128
+ return "";
129
+ }
130
+ const messages = Array.isArray(input) ? input : input.messages;
131
+ const values = [];
132
+ for (const message of messages) {
133
+ if (typeof message !== "object" || !message)
134
+ continue;
135
+ const typed = message;
136
+ if (typed.role === "user") {
137
+ const text = extractMessageContent(message).trim();
138
+ if (text)
139
+ values.push(text);
140
+ continue;
141
+ }
142
+ const ids = Array.isArray(typed.id) ? typed.id.filter((item) => typeof item === "string") : [];
143
+ const typeName = ids.at(-1);
144
+ const runtimeType = typeof message._getType === "function"
145
+ ? message._getType()
146
+ : typeof message.getType === "function"
147
+ ? message.getType()
148
+ : undefined;
149
+ if (typeName === "HumanMessage" || runtimeType === "human") {
150
+ const text = extractMessageContent(message).trim();
151
+ if (text)
152
+ values.push(text);
153
+ continue;
154
+ }
155
+ if (typeof typed.kwargs === "object" && typed.kwargs && typed.kwargs.role === "user") {
156
+ const text = extractMessageContent(message).trim();
157
+ if (text)
158
+ values.push(text);
159
+ }
160
+ }
161
+ return values.join("\n").trim();
162
+ }
163
+ function hasToolResultEvidence(input) {
164
+ if (!Array.isArray(input) && !(typeof input === "object" && input && Array.isArray(input.messages))) {
165
+ return false;
166
+ }
167
+ const messages = Array.isArray(input) ? input : input.messages;
168
+ for (const message of messages) {
169
+ if (typeof message !== "object" || !message)
170
+ continue;
171
+ const typed = message;
172
+ if (typed.role === "tool") {
173
+ return true;
174
+ }
175
+ const ids = Array.isArray(typed.id) ? typed.id.filter((item) => typeof item === "string") : [];
176
+ const typeName = ids.at(-1);
177
+ const runtimeType = typeof message._getType === "function"
178
+ ? message._getType()
179
+ : typeof message.getType === "function"
180
+ ? message.getType()
181
+ : undefined;
182
+ if (typeName === "ToolMessage" || runtimeType === "tool") {
183
+ return true;
184
+ }
185
+ if (typeof typed.kwargs === "object" && typed.kwargs && typed.kwargs.role === "tool") {
186
+ return true;
187
+ }
188
+ }
189
+ return false;
190
+ }
126
191
  function isToolRequiredExecutionPrompt(text) {
127
192
  if (!text)
128
193
  return false;
@@ -130,6 +195,12 @@ function isToolRequiredExecutionPrompt(text) {
130
195
  /\b(create|write|edit|read|show|display|append|run|execute|wait|sleep|repeat|loop|file|files|command)\b/i.test(text) ||
131
196
  /(创建|写入|读取|显示|追加|执行|运行|等待|重复|文件|命令|步骤)/.test(text));
132
197
  }
198
+ function isAutonomousInvestigationPrompt(text) {
199
+ if (!text)
200
+ return false;
201
+ return (/\b(root cause|rca|deep investigation|investigate deeply|investigate fully|step by step|find all (?:issues|problems|causes)|continue investigating|keep digging|until complete|until you find)\b/i.test(text) ||
202
+ /(根因分析|深度调查|深入调查|一步一步|逐步分析|逐个分析|继续排查|排查到底|找到所有问题|查出所有问题|直到完成|直到找到.*原因)/.test(text));
203
+ }
133
204
  function isBrowserOrUrlTask(text) {
134
205
  if (!text)
135
206
  return false;
@@ -149,6 +220,18 @@ function claimsMissingBrowserCapability(text) {
149
220
  return (/\b(i do not have the capability to access external websites|i do not have access to external websites|i cannot access external websites|i can(?:not|'t) browse|i do not have (?:direct )?(?:web|browser|browsing) access|i do not have .*tool.*(?:website|url|browser)|i cannot summarize .* because .*tool.*failed|please provide (?:the )?text content.*i (?:will|can) summarize)\b/i.test(text) ||
150
221
  /(我没有直接访问外部网站|我无法直接访问外部网站|我无法访问外部网站|我不能访问外部网站|我无法直接访问外部网站内容|我无法访问网页|请提供文本内容.*我将为您进行总结|我没有.*浏览.*工具|我没有.*网页抓取.*工具|我没有.*访问.*网站.*工具|我无法总结该网页内容,因为.*工具执行失败)/.test(text));
151
222
  }
223
+ function asksUserToChooseObviousNextDiagnosticStep(text) {
224
+ if (!text)
225
+ return false;
226
+ return (/\b(which (?:direction|aspect|node|namespace|part)|what would you like me to check|please choose|please tell me (?:which|what|where) .* (?:check|inspect|investigate)|which .* should we start with)\b/i.test(text) ||
227
+ /(请告诉我.*(哪个|哪一个|什么方向)|请选择.*(方向|项目|节点)|您希望我.*(检查|查看).*(哪个|哪一个|方向)|从哪个方向开始)/.test(text));
228
+ }
229
+ function claimsFutureExecutionWithoutToolEvidence(text) {
230
+ if (!text)
231
+ return false;
232
+ return (/\b(i will|i'll|we will|next i(?:'ll| will)|i am going to)\b.*\b(run|execute|inspect|check|investigate|continue|start)\b/i.test(text) ||
233
+ /(我将|我会|接下来我会|现在我将|我将继续).*(执行|检查|查看|调查|排查|开始|继续)/.test(text));
234
+ }
152
235
  export function isRetrySafeInvalidToolSelectionError(value) {
153
236
  const text = readTextContent(value).trim();
154
237
  if (!text)
@@ -156,9 +239,9 @@ export function isRetrySafeInvalidToolSelectionError(value) {
156
239
  return /is not a valid tool, try one of \[/i.test(text);
157
240
  }
158
241
  export function shouldValidateExecutionWithoutToolEvidence(request) {
159
- const userText = extractLastUserMessageText(request);
242
+ const userText = extractAllUserMessageText(request);
160
243
  const browserOrUrlTask = isBrowserOrUrlTask(userText);
161
- return browserOrUrlTask || isToolRequiredExecutionPrompt(userText);
244
+ return browserOrUrlTask || isToolRequiredExecutionPrompt(userText) || isAutonomousInvestigationPrompt(userText);
162
245
  }
163
246
  function extractAssistantTextFromResult(result) {
164
247
  if (typeof result === "object" && result && "messages" in result) {
@@ -192,14 +275,21 @@ export function resolveExecutionWithoutToolEvidenceInstruction(request, result)
192
275
  return resolveExecutionWithoutToolEvidenceTextInstruction(request, assistantText, hasToolCalls(result));
193
276
  }
194
277
  export function resolveExecutionWithoutToolEvidenceTextInstruction(request, assistantText, toolCallEvidence = false) {
195
- const userText = extractLastUserMessageText(request);
278
+ const userText = extractAllUserMessageText(request);
196
279
  const browserOrUrlTask = isBrowserOrUrlTask(userText);
280
+ const autonomousInvestigationTask = isAutonomousInvestigationPrompt(userText);
281
+ const toolResultEvidence = hasToolResultEvidence(request);
197
282
  if (!shouldValidateExecutionWithoutToolEvidence(request)) {
198
283
  return null;
199
284
  }
200
285
  if (!assistantText || toolCallEvidence) {
201
286
  return null;
202
287
  }
288
+ if (autonomousInvestigationTask &&
289
+ toolResultEvidence &&
290
+ (asksUserToChooseObviousNextDiagnosticStep(assistantText) || claimsFutureExecutionWithoutToolEvidence(assistantText))) {
291
+ return AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION;
292
+ }
203
293
  if (browserOrUrlTask && claimsMissingBrowserCapability(assistantText)) {
204
294
  return BROWSER_CAPABILITY_DISCLAIMER_RECOVERY_INSTRUCTION;
205
295
  }
@@ -285,4 +375,4 @@ export function wrapResolvedModel(value) {
285
375
  },
286
376
  });
287
377
  }
288
- export { BROWSER_CAPABILITY_DISCLAIMER_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION, STRICT_TOOL_JSON_INSTRUCTION, WORKSPACE_RELATIVE_PATH_INSTRUCTION, WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION, WRITE_TODOS_FULL_ENTRY_INSTRUCTION, WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION } from "../prompts/runtime-prompts.js";
378
+ export { AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION, BROWSER_CAPABILITY_DISCLAIMER_RECOVERY_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_INSTRUCTION, EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION, INVALID_TOOL_SELECTION_RECOVERY_INSTRUCTION, STRICT_TOOL_JSON_INSTRUCTION, WORKSPACE_RELATIVE_PATH_INSTRUCTION, WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION, WRITE_TODOS_FULL_ENTRY_INSTRUCTION, WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION } from "../prompts/runtime-prompts.js";
@@ -9,6 +9,7 @@ export declare const WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION: string;
9
9
  export declare const WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION: string;
10
10
  export declare const EXECUTION_WITH_TOOL_EVIDENCE_INSTRUCTION: string;
11
11
  export declare const EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION: string;
12
+ export declare const AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION: string;
12
13
  export declare const WORKSPACE_RELATIVE_PATH_INSTRUCTION: string;
13
14
  export declare function renderDurableMemoryContextPrompt(memoryContext: string): string;
14
15
  export declare function renderSlashCommandSkillInstruction(input: {
@@ -12,6 +12,7 @@ export const WRITE_TODOS_NON_EMPTY_INITIAL_LIST_INSTRUCTION = readRuntimePrompt(
12
12
  export const WRITE_TODOS_DESCRIPTIVE_CONTENT_INSTRUCTION = readRuntimePrompt("write-todos-descriptive-content");
13
13
  export const EXECUTION_WITH_TOOL_EVIDENCE_INSTRUCTION = readRuntimePrompt("execution-with-tool-evidence");
14
14
  export const EXECUTION_WITH_TOOL_EVIDENCE_RETRY_INSTRUCTION = readRuntimePrompt("execution-with-tool-evidence-retry");
15
+ export const AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION = readRuntimePrompt("autonomous-investigation-recovery");
15
16
  export const WORKSPACE_RELATIVE_PATH_INSTRUCTION = readRuntimePrompt("workspace-relative-path");
16
17
  export function renderDurableMemoryContextPrompt(memoryContext) {
17
18
  return renderBundledTemplate("prompts/runtime/durable-memory-context.md", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.320",
3
+ "version": "0.0.322",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "license": "MIT",
6
6
  "type": "module",