@botbotgo/agent-harness 0.0.330 → 0.0.332
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/adapter/flow/stream-runtime.js +8 -1
- package/dist/runtime/adapter/invocation-result.d.ts +7 -0
- package/dist/runtime/adapter/invocation-result.js +95 -1
- package/dist/runtime/adapter/middleware-assembly.js +26 -8
- package/dist/runtime/adapter/stream-event-projection.js +19 -4
- package/dist/runtime/harness/run/stream-run.js +21 -1
- package/dist/runtime/parsing/output-content.js +86 -3
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.331";
|
|
2
2
|
export declare const AGENT_HARNESS_RELEASE_DATE = "2026-04-23";
|
package/dist/package-version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.331";
|
|
2
2
|
export const AGENT_HARNESS_RELEASE_DATE = "2026-04-23";
|
|
@@ -148,7 +148,14 @@ export async function* streamRuntimeExecution(options) {
|
|
|
148
148
|
const shouldDeferStreamContent = () => shouldValidateStreamOutput && !emittedUnsafeStreamSideEffects;
|
|
149
149
|
const flushDeferredStreamContent = async function* () {
|
|
150
150
|
while (deferredStreamContent.length > 0) {
|
|
151
|
-
|
|
151
|
+
const next = deferredStreamContent.shift();
|
|
152
|
+
if (next.kind === "content") {
|
|
153
|
+
if (next.content) {
|
|
154
|
+
yield { kind: "content", content: next.content };
|
|
155
|
+
}
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
yield next;
|
|
152
159
|
}
|
|
153
160
|
};
|
|
154
161
|
try {
|
|
@@ -5,6 +5,13 @@ export type ExecutedToolResult = {
|
|
|
5
5
|
isError?: boolean;
|
|
6
6
|
memoryCandidates?: MemoryCandidate[];
|
|
7
7
|
};
|
|
8
|
+
export declare function resolveDeterministicFinalOutput(params: {
|
|
9
|
+
visibleOutput?: string;
|
|
10
|
+
toolFallback?: string;
|
|
11
|
+
executedToolResults?: ExecutedToolResult[];
|
|
12
|
+
}): string;
|
|
13
|
+
export declare function extractDelegatedFindingsText(executedToolResults: ExecutedToolResult[]): string;
|
|
14
|
+
export declare function extractToolResultFindingsText(executedToolResults: ExecutedToolResult[]): string;
|
|
8
15
|
export declare function finalizeRequestResult(params: {
|
|
9
16
|
bindingAgentId: string;
|
|
10
17
|
sessionId: string;
|
|
@@ -1,6 +1,95 @@
|
|
|
1
1
|
import { containsLikelySkillDocument, extractContentBlocks, extractEmptyAssistantMessageFailure, extractOutputContent, extractToolFallbackContext, extractVisibleOutput, isLikelyToolArgsObject, sanitizeVisibleText, tryParseJson, } from "../parsing/output-parsing.js";
|
|
2
|
+
import { salvageFunctionLikeToolCall } from "../parsing/output-tool-args.js";
|
|
2
3
|
import { buildStateSnapshot } from "./model/message-assembly.js";
|
|
3
4
|
import { asRecord } from "./tool/resolved-tool.js";
|
|
5
|
+
function looksLikeLeakedToolCallText(value) {
|
|
6
|
+
const normalized = sanitizeVisibleText(value).trim();
|
|
7
|
+
if (!normalized) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
if (salvageFunctionLikeToolCall(normalized)) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
const prefixedToolCallMatch = /^(?:\s*(?:Ready|Understood|Okay|Ok|Got it|Sure|All set|What is your request|Please provide a task for me to orchestrate)[.:?!]?\s*)+([A-Za-z_][A-Za-z0-9_]*\([\s\S]*\))\s*$/u.exec(normalized);
|
|
14
|
+
return !!(prefixedToolCallMatch && salvageFunctionLikeToolCall(prefixedToolCallMatch[1]));
|
|
15
|
+
}
|
|
16
|
+
function isPlaceholderTaskCompletion(value) {
|
|
17
|
+
const normalized = sanitizeVisibleText(value).trim();
|
|
18
|
+
return normalized === "Task completed";
|
|
19
|
+
}
|
|
20
|
+
function normalizeToolOutputText(output) {
|
|
21
|
+
const directText = typeof output === "string"
|
|
22
|
+
? sanitizeVisibleText(output).trim()
|
|
23
|
+
: "";
|
|
24
|
+
if (directText && !looksLikeLeakedToolCallText(directText) && !isPlaceholderTaskCompletion(directText)) {
|
|
25
|
+
return directText;
|
|
26
|
+
}
|
|
27
|
+
const visibleOutput = sanitizeVisibleText(extractVisibleOutput(output)).trim();
|
|
28
|
+
if (visibleOutput && !looksLikeLeakedToolCallText(visibleOutput) && !isPlaceholderTaskCompletion(visibleOutput)) {
|
|
29
|
+
return visibleOutput;
|
|
30
|
+
}
|
|
31
|
+
const fallbackContext = sanitizeVisibleText(extractToolFallbackContext(output)).trim();
|
|
32
|
+
if (fallbackContext && !looksLikeLeakedToolCallText(fallbackContext) && !isPlaceholderTaskCompletion(fallbackContext)) {
|
|
33
|
+
return fallbackContext;
|
|
34
|
+
}
|
|
35
|
+
return "";
|
|
36
|
+
}
|
|
37
|
+
function extractLatestSuccessfulTaskResultText(executedToolResults) {
|
|
38
|
+
for (const toolResult of [...executedToolResults].reverse()) {
|
|
39
|
+
if (toolResult.isError === true || toolResult.toolName !== "task") {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const normalized = normalizeToolOutputText(toolResult.output);
|
|
43
|
+
if (normalized) {
|
|
44
|
+
return normalized;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return "";
|
|
48
|
+
}
|
|
49
|
+
function extractLatestSuccessfulNonTodoToolResultText(executedToolResults) {
|
|
50
|
+
for (const toolResult of [...executedToolResults].reverse()) {
|
|
51
|
+
if (toolResult.isError === true) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (toolResult.toolName === "task" || toolResult.toolName === "write_todos" || toolResult.toolName === "read_todos") {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const normalized = normalizeToolOutputText(toolResult.output);
|
|
58
|
+
if (normalized) {
|
|
59
|
+
return normalized;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return "";
|
|
63
|
+
}
|
|
64
|
+
export function resolveDeterministicFinalOutput(params) {
|
|
65
|
+
const visibleOutput = params.visibleOutput ?? "";
|
|
66
|
+
const toolFallback = params.toolFallback ?? "";
|
|
67
|
+
const executedToolResults = params.executedToolResults ?? [];
|
|
68
|
+
const delegatedTaskOutput = extractLatestSuccessfulTaskResultText(executedToolResults);
|
|
69
|
+
if (delegatedTaskOutput) {
|
|
70
|
+
return delegatedTaskOutput;
|
|
71
|
+
}
|
|
72
|
+
const sanitizedVisibleOutput = visibleOutput && !looksLikeLeakedToolCallText(visibleOutput)
|
|
73
|
+
? sanitizeVisibleText(visibleOutput).trim()
|
|
74
|
+
: "";
|
|
75
|
+
if (sanitizedVisibleOutput) {
|
|
76
|
+
return sanitizedVisibleOutput;
|
|
77
|
+
}
|
|
78
|
+
const successfulToolOutput = extractLatestSuccessfulNonTodoToolResultText(executedToolResults);
|
|
79
|
+
if (successfulToolOutput) {
|
|
80
|
+
return successfulToolOutput;
|
|
81
|
+
}
|
|
82
|
+
const sanitizedToolFallback = toolFallback && !looksLikeLeakedToolCallText(toolFallback)
|
|
83
|
+
? sanitizeVisibleText(toolFallback).trim()
|
|
84
|
+
: "";
|
|
85
|
+
return sanitizedToolFallback;
|
|
86
|
+
}
|
|
87
|
+
export function extractDelegatedFindingsText(executedToolResults) {
|
|
88
|
+
return extractLatestSuccessfulTaskResultText(executedToolResults);
|
|
89
|
+
}
|
|
90
|
+
export function extractToolResultFindingsText(executedToolResults) {
|
|
91
|
+
return extractLatestSuccessfulNonTodoToolResultText(executedToolResults);
|
|
92
|
+
}
|
|
4
93
|
export function finalizeRequestResult(params) {
|
|
5
94
|
const { bindingAgentId, sessionId, requestId, result, executedToolResults } = params;
|
|
6
95
|
const interruptContent = Array.isArray(result.__interrupt__) && result.__interrupt__.length > 0 ? JSON.stringify(result.__interrupt__) : undefined;
|
|
@@ -12,7 +101,12 @@ export function finalizeRequestResult(params) {
|
|
|
12
101
|
throw new Error(emptyAssistantMessageFailure);
|
|
13
102
|
}
|
|
14
103
|
const serializedResult = JSON.stringify(result, null, 2);
|
|
15
|
-
const output =
|
|
104
|
+
const output = resolveDeterministicFinalOutput({
|
|
105
|
+
visibleOutput,
|
|
106
|
+
toolFallback,
|
|
107
|
+
executedToolResults,
|
|
108
|
+
})
|
|
109
|
+
|| (containsLikelySkillDocument(result) ? "" : serializedResult);
|
|
16
110
|
const finalMessageText = sanitizeVisibleText(output);
|
|
17
111
|
const outputContent = extractOutputContent(result);
|
|
18
112
|
const contentBlocks = extractContentBlocks(result);
|
|
@@ -12,6 +12,7 @@ import { materializeDeepAgentSkillSourcePaths } from "./compat/deepagent-compat.
|
|
|
12
12
|
import { DEFAULT_SUBAGENT_PROMPT } from "../prompts/runtime-prompts.js";
|
|
13
13
|
import { AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION } from "../prompts/runtime-prompts.js";
|
|
14
14
|
import { createStreamEventProjectionState, projectRuntimeStreamEvent } from "./stream-event-projection.js";
|
|
15
|
+
import { resolveDeterministicFinalOutput } from "./invocation-result.js";
|
|
15
16
|
const EMPTY_TOOL_NAME_MAPPING = {
|
|
16
17
|
originalToModelFacing: new Map(),
|
|
17
18
|
modelFacingToOriginal: new Map(),
|
|
@@ -268,9 +269,10 @@ export async function invokeBuiltinTaskTool(input) {
|
|
|
268
269
|
if (typeof runnable.streamEvents === "function") {
|
|
269
270
|
const runWithStreamInspection = async (recoveryInstruction) => {
|
|
270
271
|
const projectionState = createStreamEventProjectionState();
|
|
272
|
+
const executedToolResults = [];
|
|
271
273
|
const events = await runnable.streamEvents(buildMessages(recoveryInstruction), invokeConfig);
|
|
272
274
|
for await (const event of events) {
|
|
273
|
-
projectRuntimeStreamEvent({
|
|
275
|
+
const projectedChunks = projectRuntimeStreamEvent({
|
|
274
276
|
event,
|
|
275
277
|
allowVisibleStreamDeltas: false,
|
|
276
278
|
includeStateStreamOutput: false,
|
|
@@ -280,15 +282,25 @@ export async function invokeBuiltinTaskTool(input) {
|
|
|
280
282
|
primaryTools: [],
|
|
281
283
|
state: projectionState,
|
|
282
284
|
});
|
|
285
|
+
for (const chunk of projectedChunks) {
|
|
286
|
+
if (chunk.kind !== "tool-result") {
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
executedToolResults.push({
|
|
290
|
+
toolName: chunk.toolName,
|
|
291
|
+
output: chunk.output,
|
|
292
|
+
isError: chunk.isError,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
283
295
|
}
|
|
284
|
-
return projectionState;
|
|
296
|
+
return { projectionState, executedToolResults };
|
|
285
297
|
};
|
|
286
|
-
let projectionState = await runWithStreamInspection();
|
|
298
|
+
let { projectionState, executedToolResults } = await runWithStreamInspection();
|
|
287
299
|
if (requiresDelegatedExecutionRecovery(projectionState)) {
|
|
288
300
|
const recoveryInstruction = projectionState.hasIncompletePlanState && projectionState.emittedToolError
|
|
289
301
|
? `${AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION}\n\n${DELEGATED_FAILURE_PLAN_RECONCILIATION_INSTRUCTION}`
|
|
290
302
|
: AUTONOMOUS_INVESTIGATION_RECOVERY_INSTRUCTION;
|
|
291
|
-
projectionState = await runWithStreamInspection(recoveryInstruction);
|
|
303
|
+
({ projectionState, executedToolResults } = await runWithStreamInspection(recoveryInstruction));
|
|
292
304
|
}
|
|
293
305
|
if (requiresDelegatedExecutionRecovery(projectionState)) {
|
|
294
306
|
throw new Error(formatDelegatedExecutionBlocker(projectionState));
|
|
@@ -297,14 +309,20 @@ export async function invokeBuiltinTaskTool(input) {
|
|
|
297
309
|
throw new Error("Delegated investigation ended without any real tool execution evidence.");
|
|
298
310
|
}
|
|
299
311
|
if (projectionState.emittedToolError) {
|
|
300
|
-
const blockerMessage =
|
|
301
|
-
|
|
312
|
+
const blockerMessage = resolveDeterministicFinalOutput({
|
|
313
|
+
visibleOutput: projectionState.emittedOutput.trim(),
|
|
314
|
+
executedToolResults,
|
|
315
|
+
}) || formatDelegatedExecutionBlocker(projectionState);
|
|
302
316
|
if (hasUnresolvedDelegatedExecution(projectionState) || !projectionState.emittedSuccessfulToolResult) {
|
|
303
317
|
throw new Error(blockerMessage);
|
|
304
318
|
}
|
|
305
319
|
}
|
|
306
|
-
|
|
307
|
-
|
|
320
|
+
const deterministicOutput = resolveDeterministicFinalOutput({
|
|
321
|
+
visibleOutput: projectionState.emittedOutput.trim(),
|
|
322
|
+
executedToolResults,
|
|
323
|
+
});
|
|
324
|
+
if (deterministicOutput) {
|
|
325
|
+
return deterministicOutput;
|
|
308
326
|
}
|
|
309
327
|
if (projectionState.emittedToolResult) {
|
|
310
328
|
throw new Error("Delegated investigation performed tool work but did not return surfaced findings.");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { sanitizeVisibleText } from "../parsing/output-parsing.js";
|
|
2
|
+
import { salvageFunctionLikeToolCall } from "../parsing/output-tool-args.js";
|
|
2
3
|
import { computeIncrementalOutput, extractInterruptPayload, extractReasoningStreamOutput, sanitizeRetainedUpstreamEvent, extractStateStreamOutput, extractTerminalStreamOutput, extractToolResult, extractVisibleStreamOutput, normalizeTerminalOutputKey, } from "../parsing/stream-event-parsing.js";
|
|
3
4
|
import { resolveModelFacingToolName } from "./tool/tool-name-mapping.js";
|
|
4
5
|
export function createStreamEventProjectionState() {
|
|
@@ -24,6 +25,20 @@ export function createStreamEventProjectionState() {
|
|
|
24
25
|
seenTerminalOutputs: new Set(),
|
|
25
26
|
};
|
|
26
27
|
}
|
|
28
|
+
function shouldSuppressVisibleToolCallText(value) {
|
|
29
|
+
const trimmed = value.trim();
|
|
30
|
+
if (!trimmed) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (salvageFunctionLikeToolCall(trimmed)) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
const prefixedToolCallMatch = /^(?:\s*(?:Ready|Understood|Okay|Ok|Got it|Sure|All set)[.:!]?\s*)+([A-Za-z_][A-Za-z0-9_]*\([\s\S]*\))\s*$/u.exec(trimmed);
|
|
37
|
+
if (!prefixedToolCallMatch) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return salvageFunctionLikeToolCall(prefixedToolCallMatch[1]) !== null;
|
|
41
|
+
}
|
|
27
42
|
function readSummaryCounts(summary) {
|
|
28
43
|
if (typeof summary !== "object" || summary === null) {
|
|
29
44
|
return null;
|
|
@@ -218,7 +233,7 @@ export function projectRuntimeStreamEvent(params) {
|
|
|
218
233
|
const allowStreamedVisibleContent = allowVisibleContent && !state.emittedToolResult && !state.emittedToolError;
|
|
219
234
|
if (allowVisibleStreamDeltas && allowStreamedVisibleContent) {
|
|
220
235
|
const visibleStreamOutput = extractVisibleStreamOutput(event);
|
|
221
|
-
if (visibleStreamOutput) {
|
|
236
|
+
if (visibleStreamOutput && !shouldSuppressVisibleToolCallText(visibleStreamOutput)) {
|
|
222
237
|
const nextOutput = computeIncrementalOutput(state.emittedOutput, visibleStreamOutput);
|
|
223
238
|
state.emittedOutput = nextOutput.accumulated;
|
|
224
239
|
if (nextOutput.delta) {
|
|
@@ -228,8 +243,8 @@ export function projectRuntimeStreamEvent(params) {
|
|
|
228
243
|
}
|
|
229
244
|
if (includeStateStreamOutput && allowVisibleContent) {
|
|
230
245
|
const stateStreamOutput = extractStateStreamOutput(event);
|
|
231
|
-
if (stateStreamOutput) {
|
|
232
|
-
const nextOutput = computeIncrementalOutput(state.emittedOutput,
|
|
246
|
+
if (stateStreamOutput && !shouldSuppressVisibleToolCallText(stateStreamOutput)) {
|
|
247
|
+
const nextOutput = computeIncrementalOutput(state.emittedOutput, stateStreamOutput);
|
|
233
248
|
state.emittedOutput = nextOutput.accumulated;
|
|
234
249
|
if (nextOutput.delta) {
|
|
235
250
|
chunks.push({ kind: "content", content: nextOutput.delta });
|
|
@@ -269,7 +284,7 @@ export function projectRuntimeStreamEvent(params) {
|
|
|
269
284
|
state.emittedDelegatedTerminalOutput = true;
|
|
270
285
|
}
|
|
271
286
|
}
|
|
272
|
-
if (output) {
|
|
287
|
+
if (output && !shouldSuppressVisibleToolCallText(output)) {
|
|
273
288
|
const outputKey = normalizeTerminalOutputKey(output);
|
|
274
289
|
if (!outputKey || !state.seenTerminalOutputs.has(outputKey)) {
|
|
275
290
|
if (outputKey) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { resolveDeterministicFinalOutput, } from "../../adapter/invocation-result.js";
|
|
1
2
|
import { AGENT_INTERRUPT_SENTINEL_PREFIX, RuntimeOperationTimeoutError } from "../../agent-runtime-adapter.js";
|
|
2
3
|
import { ExecutionReconciliationError } from "../../adapter/flow/stream-runtime.js";
|
|
3
4
|
import { buildRequestPlanState, summarizeBuiltinWriteTodosArgs } from "../../adapter/runtime-adapter-support.js";
|
|
5
|
+
import { sanitizeVisibleText } from "../../parsing/output-parsing.js";
|
|
4
6
|
import { describeRuntimeError, renderRuntimeFailure, renderToolFailure } from "../../support/harness-support.js";
|
|
5
7
|
import { getBindingPrimaryModel } from "../../support/compiled-binding.js";
|
|
6
8
|
import { createContentBlocksItem, createToolResultKey, } from "../events/streaming.js";
|
|
@@ -466,7 +468,9 @@ export async function* streamHarnessRun(options) {
|
|
|
466
468
|
]).then(([loadedPriorHistory, resolvedReleaseRunSlot]) => [loadedPriorHistory, resolvedReleaseRunSlot]);
|
|
467
469
|
releaseRunSlot = acquiredReleaseRunSlot;
|
|
468
470
|
const toolErrors = [];
|
|
471
|
+
let sawSuccessfulToolResult = false;
|
|
469
472
|
let lastToolResultKey = null;
|
|
473
|
+
const executedToolResults = [];
|
|
470
474
|
const recalledMemories = options.invocation.memoryRecall?.items ?? [];
|
|
471
475
|
for (const item of createRuntimeMemoryRecallSteps(options.sessionId, options.requestId, recalledMemories)) {
|
|
472
476
|
yield item;
|
|
@@ -637,9 +641,17 @@ export async function* streamHarnessRun(options) {
|
|
|
637
641
|
continue;
|
|
638
642
|
}
|
|
639
643
|
lastToolResultKey = toolResultKey;
|
|
644
|
+
executedToolResults.push({
|
|
645
|
+
toolName: normalizedChunk.toolName,
|
|
646
|
+
output: normalizedChunk.output,
|
|
647
|
+
isError: normalizedChunk.isError,
|
|
648
|
+
});
|
|
640
649
|
if (normalizedChunk.isError) {
|
|
641
650
|
toolErrors.push(renderToolFailure(normalizedChunk.toolName, normalizedChunk.output));
|
|
642
651
|
}
|
|
652
|
+
else {
|
|
653
|
+
sawSuccessfulToolResult = true;
|
|
654
|
+
}
|
|
643
655
|
yield {
|
|
644
656
|
type: "tool-result",
|
|
645
657
|
sessionId: options.sessionId,
|
|
@@ -714,10 +726,18 @@ export async function* streamHarnessRun(options) {
|
|
|
714
726
|
content: normalizedChunk.content,
|
|
715
727
|
};
|
|
716
728
|
}
|
|
717
|
-
if (!assistantOutput && toolErrors.length > 0) {
|
|
729
|
+
if (!assistantOutput && toolErrors.length > 0 && !sawSuccessfulToolResult) {
|
|
718
730
|
assistantOutput = toolErrors.join("\n\n");
|
|
719
731
|
emitted = true;
|
|
720
732
|
}
|
|
733
|
+
const resolvedAssistantOutput = resolveDeterministicFinalOutput({
|
|
734
|
+
visibleOutput: assistantOutput,
|
|
735
|
+
executedToolResults,
|
|
736
|
+
});
|
|
737
|
+
if (sanitizeVisibleText(resolvedAssistantOutput) !== sanitizeVisibleText(assistantOutput)) {
|
|
738
|
+
assistantOutput = resolvedAssistantOutput;
|
|
739
|
+
emitted = emitted || assistantOutput.length > 0;
|
|
740
|
+
}
|
|
721
741
|
currentPlanState = await refreshPlanStateFromPersistence(options, currentPlanState);
|
|
722
742
|
if (!assistantOutput) {
|
|
723
743
|
const actual = await options.invokeWithHistory(options.binding, options.input, options.sessionId, options.requestId);
|
|
@@ -1,11 +1,93 @@
|
|
|
1
1
|
import { AIMessage } from "langchain";
|
|
2
2
|
import { salvageFunctionLikeToolCall, salvageToolArgs, isLikelyToolArgsObject, normalizeKnownToolArgs, tryParseJson } from "./output-tool-args.js";
|
|
3
|
+
function consumeLeadingFunctionLikeToolCall(value) {
|
|
4
|
+
const match = /^([A-Za-z_][A-Za-z0-9_]*)\(/.exec(value);
|
|
5
|
+
if (!match) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
let depthParen = 0;
|
|
9
|
+
let depthBracket = 0;
|
|
10
|
+
let depthBrace = 0;
|
|
11
|
+
let inString = false;
|
|
12
|
+
let quoteChar = "";
|
|
13
|
+
let escaping = false;
|
|
14
|
+
for (let index = match[0].length - 1; index < value.length; index += 1) {
|
|
15
|
+
const char = value[index];
|
|
16
|
+
if (inString) {
|
|
17
|
+
if (escaping) {
|
|
18
|
+
escaping = false;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (char === "\\") {
|
|
22
|
+
escaping = true;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (char === quoteChar) {
|
|
26
|
+
inString = false;
|
|
27
|
+
quoteChar = "";
|
|
28
|
+
}
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (char === "\"" || char === "'") {
|
|
32
|
+
inString = true;
|
|
33
|
+
quoteChar = char;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (char === "(") {
|
|
37
|
+
depthParen += 1;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (char === ")") {
|
|
41
|
+
depthParen -= 1;
|
|
42
|
+
if (depthParen === 0 && depthBracket === 0 && depthBrace === 0) {
|
|
43
|
+
const candidate = value.slice(0, index + 1);
|
|
44
|
+
return salvageFunctionLikeToolCall(candidate) ? candidate : null;
|
|
45
|
+
}
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (char === "[")
|
|
49
|
+
depthBracket += 1;
|
|
50
|
+
else if (char === "]")
|
|
51
|
+
depthBracket -= 1;
|
|
52
|
+
else if (char === "{")
|
|
53
|
+
depthBrace += 1;
|
|
54
|
+
else if (char === "}")
|
|
55
|
+
depthBrace -= 1;
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
function stripVisibleFunctionLikeToolCallText(value) {
|
|
60
|
+
let remaining = value.trim();
|
|
61
|
+
let removedLeadingCall = false;
|
|
62
|
+
while (remaining.length > 0) {
|
|
63
|
+
const consumed = consumeLeadingFunctionLikeToolCall(remaining);
|
|
64
|
+
if (!consumed) {
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
removedLeadingCall = true;
|
|
68
|
+
remaining = remaining.slice(consumed.length).trimStart();
|
|
69
|
+
}
|
|
70
|
+
const lineFiltered = remaining
|
|
71
|
+
.split("\n")
|
|
72
|
+
.map((line) => line.trim())
|
|
73
|
+
.filter((line) => !salvageFunctionLikeToolCall(line))
|
|
74
|
+
.join("\n")
|
|
75
|
+
.trim();
|
|
76
|
+
if (lineFiltered.length > 0) {
|
|
77
|
+
const prefixedToolCallMatch = /^(?:\s*(?:Ready|Understood|Okay|Ok|Got it|Sure|All set|Please provide a task for me to orchestrate)[.:!]?\s*)+([A-Za-z_][A-Za-z0-9_]*\([\s\S]*\))\s*$/u.exec(lineFiltered);
|
|
78
|
+
if (prefixedToolCallMatch && salvageFunctionLikeToolCall(prefixedToolCallMatch[1])) {
|
|
79
|
+
return "";
|
|
80
|
+
}
|
|
81
|
+
return lineFiltered;
|
|
82
|
+
}
|
|
83
|
+
return removedLeadingCall ? "" : value.trim();
|
|
84
|
+
}
|
|
3
85
|
export function sanitizeVisibleText(value) {
|
|
4
|
-
return value
|
|
86
|
+
return stripVisibleFunctionLikeToolCallText(value
|
|
5
87
|
.replace(/[A-Za-z0-9_]*Middleware\.after_model/g, "")
|
|
6
88
|
.replace(/todoListMiddleware\.after_model/g, "")
|
|
7
89
|
.replace(/__end__+/g, "")
|
|
8
|
-
.trim();
|
|
90
|
+
.trim());
|
|
9
91
|
}
|
|
10
92
|
function isLikelyMemoryWriteArgsObject(value) {
|
|
11
93
|
if (typeof value !== "object" || !value || Array.isArray(value)) {
|
|
@@ -104,7 +186,7 @@ function extractAssistantTextFromMessages(messages) {
|
|
|
104
186
|
const content = extractMessageContent(message);
|
|
105
187
|
if (content)
|
|
106
188
|
return content;
|
|
107
|
-
|
|
189
|
+
return "";
|
|
108
190
|
}
|
|
109
191
|
const ids = Array.isArray(typed.id) ? typed.id.filter((item) => typeof item === "string") : [];
|
|
110
192
|
const typeName = ids.at(-1);
|
|
@@ -123,6 +205,7 @@ function extractAssistantTextFromMessages(messages) {
|
|
|
123
205
|
const content = extractMessageContent(message);
|
|
124
206
|
if (content)
|
|
125
207
|
return content;
|
|
208
|
+
return "";
|
|
126
209
|
}
|
|
127
210
|
return "";
|
|
128
211
|
}
|