@botbotgo/agent-harness 0.0.315 → 0.0.317
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/projections/request-events.js +54 -3
- package/dist/projections/upstream-events.js +6 -1
- package/dist/runtime/adapter/stream-event-projection.js +2 -2
- package/dist/runtime/harness/events/streaming.js +4 -1
- package/dist/runtime/parsing/stream-event-parsing.d.ts +2 -0
- package/dist/runtime/parsing/stream-event-parsing.js +146 -1
- 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.316";
|
package/dist/package-version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.316";
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
const MAX_SNAPSHOT_OUTPUT_CHARS = 4_096;
|
|
2
|
+
const MAX_DATA_EVENT_INLINE_CHARS = 12_000;
|
|
3
|
+
const DATA_EVENT_PREVIEW_CHARS = 2_000;
|
|
4
|
+
const TRUNCATION_SENTINEL = "\n...[truncated]";
|
|
1
5
|
function createEmptyPlanSummary() {
|
|
2
6
|
return {
|
|
3
7
|
total: 0,
|
|
@@ -58,6 +62,53 @@ function buildPlanItems(snapshot, planItems) {
|
|
|
58
62
|
function buildStepEventKey(input) {
|
|
59
63
|
return `${input.kind}:${input.id}`;
|
|
60
64
|
}
|
|
65
|
+
function truncateText(value, maxChars) {
|
|
66
|
+
if (value.length <= maxChars) {
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
const sliceLength = Math.max(0, maxChars - TRUNCATION_SENTINEL.length);
|
|
70
|
+
return `${value.slice(0, sliceLength)}${TRUNCATION_SENTINEL}`;
|
|
71
|
+
}
|
|
72
|
+
function appendSnapshotOutput(current, delta) {
|
|
73
|
+
if (!delta || current.length >= MAX_SNAPSHOT_OUTPUT_CHARS || current.endsWith(TRUNCATION_SENTINEL)) {
|
|
74
|
+
return current;
|
|
75
|
+
}
|
|
76
|
+
const remaining = MAX_SNAPSHOT_OUTPUT_CHARS - current.length;
|
|
77
|
+
if (delta.length <= remaining) {
|
|
78
|
+
return current + delta;
|
|
79
|
+
}
|
|
80
|
+
return `${current}${truncateText(delta, remaining)}`;
|
|
81
|
+
}
|
|
82
|
+
function summarizeLargeDataEventOutput(output) {
|
|
83
|
+
if (typeof output === "string") {
|
|
84
|
+
if (output.length <= MAX_DATA_EVENT_INLINE_CHARS) {
|
|
85
|
+
return output;
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
truncated: true,
|
|
89
|
+
originalSizeChars: output.length,
|
|
90
|
+
preview: truncateText(output, DATA_EVENT_PREVIEW_CHARS),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (typeof output === "number" || typeof output === "boolean" || output === null || output === undefined) {
|
|
94
|
+
return output;
|
|
95
|
+
}
|
|
96
|
+
let serialized;
|
|
97
|
+
try {
|
|
98
|
+
serialized = JSON.stringify(output, null, 2);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
serialized = String(output);
|
|
102
|
+
}
|
|
103
|
+
if (serialized.length <= MAX_DATA_EVENT_INLINE_CHARS) {
|
|
104
|
+
return output;
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
truncated: true,
|
|
108
|
+
originalSizeChars: serialized.length,
|
|
109
|
+
preview: truncateText(serialized, DATA_EVENT_PREVIEW_CHARS),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
61
112
|
function applyPlanState(snapshot, planState) {
|
|
62
113
|
if (!shouldReplacePlanItems(snapshot.plan.items, planState.items)) {
|
|
63
114
|
return {
|
|
@@ -263,7 +314,7 @@ export function applyRequestStreamItemToSnapshot(snapshot, item) {
|
|
|
263
314
|
requestId: item.requestId,
|
|
264
315
|
updatedAt: now,
|
|
265
316
|
agentId: item.agentId,
|
|
266
|
-
output: snapshot.output
|
|
317
|
+
output: appendSnapshotOutput(snapshot.output, item.content),
|
|
267
318
|
};
|
|
268
319
|
case "commentary":
|
|
269
320
|
return {
|
|
@@ -327,7 +378,7 @@ export function applyRequestStreamItemToSnapshot(snapshot, item) {
|
|
|
327
378
|
updatedAt: now,
|
|
328
379
|
state: item.result.state,
|
|
329
380
|
agentId: item.result.agentId ?? snapshot.agentId,
|
|
330
|
-
output: item.result.output
|
|
381
|
+
output: item.result.output ? truncateText(item.result.output, MAX_SNAPSHOT_OUTPUT_CHARS) : snapshot.output,
|
|
331
382
|
...(item.result.contentBlocks ? { contentBlocks: item.result.contentBlocks } : {}),
|
|
332
383
|
...(item.result.structuredResponse !== undefined ? { structuredResponse: item.result.structuredResponse } : {}),
|
|
333
384
|
...(item.result.interruptContent !== undefined ? { interruptContent: item.result.interruptContent } : {}),
|
|
@@ -376,7 +427,7 @@ export function toRequestDataEvent(item) {
|
|
|
376
427
|
requestId: item.requestId,
|
|
377
428
|
agentId: item.agentId,
|
|
378
429
|
toolName: item.toolName,
|
|
379
|
-
output: item.output,
|
|
430
|
+
output: summarizeLargeDataEventOutput(item.output),
|
|
380
431
|
...(item.isError !== undefined ? { isError: item.isError } : {}),
|
|
381
432
|
};
|
|
382
433
|
case "upstream-event":
|
|
@@ -74,7 +74,12 @@ function buildStepLabel(category, status, name) {
|
|
|
74
74
|
return status === "started" ? `Running ${displayName}` : `Completed ${displayName}`;
|
|
75
75
|
}
|
|
76
76
|
function createProjectionKey(parts) {
|
|
77
|
-
return JSON.stringify(parts)
|
|
77
|
+
return JSON.stringify(parts, (_key, value) => {
|
|
78
|
+
if (typeof value === "string" && value.length > 512) {
|
|
79
|
+
return `${value.slice(0, 497)}...[${value.length} chars]`;
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
});
|
|
78
83
|
}
|
|
79
84
|
export function createUpstreamTimelineReducer() {
|
|
80
85
|
const emittedStepKeys = new Set();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sanitizeVisibleText } from "../parsing/output-parsing.js";
|
|
2
|
-
import { computeIncrementalOutput, extractInterruptPayload, extractReasoningStreamOutput, extractStateStreamOutput, extractTerminalStreamOutput, extractToolResult, extractVisibleStreamOutput, normalizeTerminalOutputKey, } from "../parsing/stream-event-parsing.js";
|
|
2
|
+
import { computeIncrementalOutput, extractInterruptPayload, extractReasoningStreamOutput, sanitizeRetainedUpstreamEvent, extractStateStreamOutput, extractTerminalStreamOutput, extractToolResult, extractVisibleStreamOutput, normalizeTerminalOutputKey, } from "../parsing/stream-event-parsing.js";
|
|
3
3
|
import { resolveModelFacingToolName } from "./tool/tool-name-mapping.js";
|
|
4
4
|
export function createStreamEventProjectionState() {
|
|
5
5
|
return {
|
|
@@ -13,7 +13,7 @@ export function projectRuntimeStreamEvent(params) {
|
|
|
13
13
|
const { event, allowVisibleStreamDeltas, includeStateStreamOutput, toolNameMapping, primaryTools, state, } = params;
|
|
14
14
|
const chunks = [{
|
|
15
15
|
kind: "upstream-event",
|
|
16
|
-
event,
|
|
16
|
+
event: sanitizeRetainedUpstreamEvent(event),
|
|
17
17
|
}];
|
|
18
18
|
const interruptPayload = extractInterruptPayload(event);
|
|
19
19
|
if (interruptPayload) {
|
|
@@ -29,7 +29,10 @@ export function createToolResultKey(toolName, output, isError) {
|
|
|
29
29
|
catch {
|
|
30
30
|
serializedOutput = String(output);
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
const preview = serializedOutput.length > 512
|
|
33
|
+
? `${serializedOutput.slice(0, 497)}...[${serializedOutput.length} chars]`
|
|
34
|
+
: serializedOutput;
|
|
35
|
+
return JSON.stringify([toolName, preview, isError === true]);
|
|
33
36
|
}
|
|
34
37
|
export async function dispatchRequestListeners(stream, listeners, options) {
|
|
35
38
|
const notifyIfPresent = async (listener, value) => {
|
|
@@ -23,6 +23,8 @@ export type RuntimeStreamChunk = {
|
|
|
23
23
|
kind: "profile";
|
|
24
24
|
step: RequestExecutionStep;
|
|
25
25
|
};
|
|
26
|
+
export declare function sanitizeStreamPayload(value: unknown): unknown;
|
|
27
|
+
export declare function sanitizeRetainedUpstreamEvent(event: unknown): unknown;
|
|
26
28
|
export declare function extractTerminalStreamOutput(event: unknown): string;
|
|
27
29
|
export declare function extractReasoningStreamOutput(event: unknown): string;
|
|
28
30
|
export declare function extractVisibleStreamOutput(event: unknown): string;
|
|
@@ -1,5 +1,150 @@
|
|
|
1
1
|
import { isLowSignalTodoContent } from "../adapter/runtime-adapter-support.js";
|
|
2
2
|
import { extractReasoningText, extractVisibleOutput, hasToolCalls, readTextContent } from "./output-parsing.js";
|
|
3
|
+
const MAX_STREAM_INLINE_TEXT_CHARS = 12_000;
|
|
4
|
+
const STREAM_PREVIEW_TEXT_CHARS = 2_000;
|
|
5
|
+
const MAX_STREAM_OBJECT_KEYS = 64;
|
|
6
|
+
const MAX_STREAM_ARRAY_ITEMS = 64;
|
|
7
|
+
const MAX_STREAM_SANITIZE_DEPTH = 6;
|
|
8
|
+
const LARGE_CONTEXT_KEYS = new Set([
|
|
9
|
+
"input",
|
|
10
|
+
"inputs",
|
|
11
|
+
"messages",
|
|
12
|
+
"history",
|
|
13
|
+
"context",
|
|
14
|
+
"attachments",
|
|
15
|
+
"files",
|
|
16
|
+
"conversation",
|
|
17
|
+
"transcript",
|
|
18
|
+
]);
|
|
19
|
+
function truncatePreview(value, maxChars) {
|
|
20
|
+
if (value.length <= maxChars) {
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
return `${value.slice(0, Math.max(0, maxChars - 15))}\n...[truncated]`;
|
|
24
|
+
}
|
|
25
|
+
function summarizeLargeText(value) {
|
|
26
|
+
if (value.length <= MAX_STREAM_INLINE_TEXT_CHARS) {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
truncated: true,
|
|
31
|
+
originalSizeChars: value.length,
|
|
32
|
+
preview: truncatePreview(value, STREAM_PREVIEW_TEXT_CHARS),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function sanitizeStreamPayloadValue(value, depth) {
|
|
36
|
+
if (typeof value === "string") {
|
|
37
|
+
return summarizeLargeText(value);
|
|
38
|
+
}
|
|
39
|
+
if (value === null
|
|
40
|
+
|| value === undefined
|
|
41
|
+
|| typeof value === "number"
|
|
42
|
+
|| typeof value === "boolean") {
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
if (depth >= MAX_STREAM_SANITIZE_DEPTH) {
|
|
46
|
+
let serialized = "";
|
|
47
|
+
try {
|
|
48
|
+
serialized = JSON.stringify(value);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
serialized = String(value);
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
truncated: true,
|
|
55
|
+
reason: "max-depth",
|
|
56
|
+
originalSizeChars: serialized.length,
|
|
57
|
+
preview: truncatePreview(serialized, STREAM_PREVIEW_TEXT_CHARS),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (Array.isArray(value)) {
|
|
61
|
+
const limited = value
|
|
62
|
+
.slice(0, MAX_STREAM_ARRAY_ITEMS)
|
|
63
|
+
.map((entry) => sanitizeStreamPayloadValue(entry, depth + 1));
|
|
64
|
+
return value.length > MAX_STREAM_ARRAY_ITEMS
|
|
65
|
+
? {
|
|
66
|
+
items: limited,
|
|
67
|
+
truncated: true,
|
|
68
|
+
originalLength: value.length,
|
|
69
|
+
}
|
|
70
|
+
: limited;
|
|
71
|
+
}
|
|
72
|
+
if (typeof value === "object") {
|
|
73
|
+
const entries = Object.entries(value);
|
|
74
|
+
const limitedEntries = entries.slice(0, MAX_STREAM_OBJECT_KEYS);
|
|
75
|
+
const sanitized = Object.fromEntries(limitedEntries.map(([key, entry]) => [key, sanitizeStreamPayloadValue(entry, depth + 1)]));
|
|
76
|
+
if (entries.length > MAX_STREAM_OBJECT_KEYS) {
|
|
77
|
+
sanitized.__truncatedKeys = {
|
|
78
|
+
truncated: true,
|
|
79
|
+
originalKeyCount: entries.length,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return sanitized;
|
|
83
|
+
}
|
|
84
|
+
return String(value);
|
|
85
|
+
}
|
|
86
|
+
export function sanitizeStreamPayload(value) {
|
|
87
|
+
return sanitizeStreamPayloadValue(value, 0);
|
|
88
|
+
}
|
|
89
|
+
function summarizeOpaquePayload(value) {
|
|
90
|
+
if (value === null || value === undefined) {
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
if (typeof value === "string") {
|
|
94
|
+
return {
|
|
95
|
+
truncated: true,
|
|
96
|
+
reason: "omitted-large-context",
|
|
97
|
+
originalSizeChars: value.length,
|
|
98
|
+
preview: truncatePreview(value, STREAM_PREVIEW_TEXT_CHARS),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
let serialized = "";
|
|
102
|
+
try {
|
|
103
|
+
serialized = JSON.stringify(value);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
serialized = String(value);
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
truncated: true,
|
|
110
|
+
reason: "omitted-large-context",
|
|
111
|
+
originalSizeChars: serialized.length,
|
|
112
|
+
preview: truncatePreview(serialized, STREAM_PREVIEW_TEXT_CHARS),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function sanitizeRetainedEventDataField(key, value) {
|
|
116
|
+
if (LARGE_CONTEXT_KEYS.has(key)) {
|
|
117
|
+
if (key === "input" && typeof value === "object" && value && !Array.isArray(value)) {
|
|
118
|
+
const typed = value;
|
|
119
|
+
const taskSubagentType = typeof typed.subagent_type === "string"
|
|
120
|
+
? typed.subagent_type
|
|
121
|
+
: typeof typed.subagentType === "string"
|
|
122
|
+
? typed.subagentType
|
|
123
|
+
: undefined;
|
|
124
|
+
if (taskSubagentType) {
|
|
125
|
+
return { subagent_type: taskSubagentType };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return summarizeOpaquePayload(value);
|
|
129
|
+
}
|
|
130
|
+
return sanitizeStreamPayload(value);
|
|
131
|
+
}
|
|
132
|
+
export function sanitizeRetainedUpstreamEvent(event) {
|
|
133
|
+
if (typeof event !== "object" || !event || Array.isArray(event)) {
|
|
134
|
+
return sanitizeStreamPayload(event);
|
|
135
|
+
}
|
|
136
|
+
const typed = event;
|
|
137
|
+
const retained = {};
|
|
138
|
+
for (const [key, value] of Object.entries(typed)) {
|
|
139
|
+
if (key === "data" && typeof value === "object" && value && !Array.isArray(value)) {
|
|
140
|
+
const data = value;
|
|
141
|
+
retained.data = Object.fromEntries(Object.entries(data).map(([dataKey, dataValue]) => [dataKey, sanitizeRetainedEventDataField(dataKey, dataValue)]));
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
retained[key] = sanitizeStreamPayload(value);
|
|
145
|
+
}
|
|
146
|
+
return retained;
|
|
147
|
+
}
|
|
3
148
|
function parseMaybeJson(value) {
|
|
4
149
|
const trimmed = value.trim();
|
|
5
150
|
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
|
|
@@ -146,7 +291,7 @@ export function extractToolResult(event) {
|
|
|
146
291
|
}
|
|
147
292
|
return {
|
|
148
293
|
toolName,
|
|
149
|
-
output: normalizedOutput,
|
|
294
|
+
output: sanitizeStreamPayload(normalizedOutput),
|
|
150
295
|
isError: isToolError || isErrorLikeToolOutput(normalizedOutput),
|
|
151
296
|
};
|
|
152
297
|
}
|