@animalabs/agent-framework 0.24.1 → 0.26.0
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/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +21 -8
- package/dist/src/agent.js.map +1 -1
- package/dist/src/framework.d.ts +18 -1
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +87 -37
- package/dist/src/framework.js.map +1 -1
- package/dist/src/mcpl/references.d.ts +4 -1
- package/dist/src/mcpl/references.d.ts.map +1 -1
- package/dist/src/mcpl/references.js +5 -2
- package/dist/src/mcpl/references.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +74 -20
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/types.d.ts +6 -2
- package/dist/src/modules/workspace/types.d.ts.map +1 -1
- package/dist/src/modules/workspace/types.js.map +1 -1
- package/dist/src/text-as-stored.d.ts +31 -0
- package/dist/src/text-as-stored.d.ts.map +1 -0
- package/dist/src/text-as-stored.js +70 -0
- package/dist/src/text-as-stored.js.map +1 -0
- package/dist/src/tool-image-ledger.d.ts +26 -3
- package/dist/src/tool-image-ledger.d.ts.map +1 -1
- package/dist/src/tool-image-ledger.js +31 -4
- package/dist/src/tool-image-ledger.js.map +1 -1
- package/dist/src/tool-presentation.d.ts.map +1 -1
- package/dist/src/tool-presentation.js +9 -1
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/tool-result-history.d.ts +15 -5
- package/dist/src/tool-result-history.d.ts.map +1 -1
- package/dist/src/tool-result-history.js +33 -9
- package/dist/src/tool-result-history.js.map +1 -1
- package/dist/src/types/events.d.ts +8 -2
- package/dist/src/types/events.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/agent.ts +21 -8
- package/src/framework.ts +92 -36
- package/src/mcpl/references.ts +5 -2
- package/src/modules/workspace/index.ts +74 -20
- package/src/modules/workspace/types.ts +6 -2
- package/src/text-as-stored.ts +73 -0
- package/src/tool-image-ledger.ts +31 -4
- package/src/tool-presentation.ts +8 -1
- package/src/tool-result-history.ts +33 -8
- package/src/types/events.ts +8 -2
|
@@ -9,12 +9,14 @@
|
|
|
9
9
|
* `maxChars` slice and re-introduces, one turn deferred, exactly the silent
|
|
10
10
|
* hallucination this feature exists to kill.
|
|
11
11
|
*
|
|
12
|
-
* For MCP-shaped content arrays, this helper keeps text blocks verbatim
|
|
12
|
+
* For MCP-shaped content arrays, this helper keeps text blocks verbatim,
|
|
13
|
+
* apart from a lone UTF-16 surrogate, which becomes U+FFFD (#695), and
|
|
13
14
|
* replaces image blocks with a short `[image: mimeType, ~NKB]` placeholder.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* sits in the data, so its uri
|
|
17
|
-
* claims a uri or a disposition
|
|
15
|
+
* A string is already text and is kept as it is. For anything else it falls
|
|
16
|
+
* back to JSON, written by RFC-005's rules at every depth (historyJson): a
|
|
17
|
+
* reference is shown as its stub wherever it sits in the data, so its uri
|
|
18
|
+
* never reaches history, and inline data that claims a uri or a disposition
|
|
19
|
+
* is withheld.
|
|
18
20
|
*/
|
|
19
21
|
import { INLINE_WITHHELD_TEXT, isInlineContradiction, referenceStubOrNull } from './mcpl/references.js';
|
|
20
22
|
import { NON_STRING_TEXT_PLACEHOLDER } from './mcpl/visible-content.js';
|
|
@@ -39,9 +41,19 @@ import { formatToolImagePlaceholder, toolResultCutAt } from './tool-image-ledger
|
|
|
39
41
|
export const DEFAULT_TOOL_RESULT_INLINE_MAX_CHARS = 24000;
|
|
40
42
|
export function toolResultDataToHistoryString(data, maxChars, options) {
|
|
41
43
|
const fromArray = tryHistoryStringFromContentArray(data, options);
|
|
44
|
+
// A string is the text the tool means to say, kept as it is: JSON would
|
|
45
|
+
// quote it and escape every newline, so a multi-line result would reach
|
|
46
|
+
// the model, a script and its spill file as one escaped line. Kept well
|
|
47
|
+
// formed: a lone UTF-16 surrogate, which JSON escaped, isn't text, a
|
|
48
|
+
// provider can refuse a request that carries one, and UTF-8 can't store
|
|
49
|
+
// it in a spill file, so it reads as U+FFFD.
|
|
42
50
|
// JSON leaves out undefined, a function and a symbol: a result with no data
|
|
43
51
|
// is stored as no text, as an empty content array is.
|
|
44
|
-
|
|
52
|
+
// RFC-005 shows only objects otherwise (shownInHistory), so a string has
|
|
53
|
+
// nothing for historyJson to stub or withhold.
|
|
54
|
+
const str = fromArray
|
|
55
|
+
?? (typeof data === 'string' ? data.toWellFormed() : historyJson(data))
|
|
56
|
+
?? '';
|
|
45
57
|
return maxChars ? truncateForHistory(str, maxChars) : str;
|
|
46
58
|
}
|
|
47
59
|
/**
|
|
@@ -52,13 +64,23 @@ export function toolResultDataToHistoryString(data, maxChars, options) {
|
|
|
52
64
|
*
|
|
53
65
|
* Each field is read once: the direct Agent API passes its caller's own
|
|
54
66
|
* result here, unchecked, and a getter needn't answer the same way twice.
|
|
67
|
+
*
|
|
68
|
+
* Each text a tool result's copies carry is made well formed where it's
|
|
69
|
+
* taken from the result: a lone UTF-16 surrogate becomes U+FFFD, as the
|
|
70
|
+
* context store makes it when it writes, so the copy sent to membrane and the
|
|
71
|
+
* copy stored carry the same text (#695). Other data goes through JSON,
|
|
72
|
+
* which escapes a lone half. toWellFormed() keeps the length,
|
|
73
|
+
* so the cut, the spans and the slots are computed from the well-formed text
|
|
74
|
+
* as before; a cut at a lone high half no longer steps back over it.
|
|
55
75
|
*/
|
|
56
76
|
export function nonErrorResultText(result, maxChars, options) {
|
|
57
77
|
const data = result.data;
|
|
58
78
|
if (data === undefined || data === null) {
|
|
59
79
|
const error = result.error;
|
|
60
|
-
if (typeof error === 'string' && error)
|
|
61
|
-
|
|
80
|
+
if (typeof error === 'string' && error) {
|
|
81
|
+
const text = error.toWellFormed();
|
|
82
|
+
return maxChars ? truncateForHistory(text, maxChars) : text;
|
|
83
|
+
}
|
|
62
84
|
}
|
|
63
85
|
return toolResultDataToHistoryString(data, maxChars, options);
|
|
64
86
|
}
|
|
@@ -92,7 +114,9 @@ function tryHistoryStringFromContentArray(data, options) {
|
|
|
92
114
|
if (b.type === 'text') {
|
|
93
115
|
// A text that isn't a string shows as the converters' placeholder,
|
|
94
116
|
// rather than sending the whole array to the JSON fallback.
|
|
95
|
-
|
|
117
|
+
// Read once: a direct Agent API result is unchecked.
|
|
118
|
+
const text = b.text;
|
|
119
|
+
parts.push({ kind: 'text', text: typeof text === 'string' ? text.toWellFormed() : NON_STRING_TEXT_PLACEHOLDER });
|
|
96
120
|
}
|
|
97
121
|
else if (isInlineContradiction(b)) {
|
|
98
122
|
// RFC-005 vector 2: checked before the data branch so inline data
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-result-history.js","sourceRoot":"","sources":["../../src/tool-result-history.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"tool-result-history.js","sourceRoot":"","sources":["../../src/tool-result-history.ts"],"names":[],"mappings":"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"}
|
|
@@ -158,7 +158,13 @@ export interface ModuleEvent {
|
|
|
158
158
|
export interface ToolResult {
|
|
159
159
|
/** Whether the tool succeeded */
|
|
160
160
|
success: boolean;
|
|
161
|
-
/**
|
|
161
|
+
/**
|
|
162
|
+
* Result data (if success). The model reads a string as that text, an MCP
|
|
163
|
+
* content array whose every block the framework knows as those blocks, and
|
|
164
|
+
* anything else as JSON, where RFC-005 shows a reference as its stub and
|
|
165
|
+
* withholds inline data that claims a uri or a disposition. With no data,
|
|
166
|
+
* it reads the result's error text, if any.
|
|
167
|
+
*/
|
|
162
168
|
data?: unknown;
|
|
163
169
|
/** Error message (if failure) */
|
|
164
170
|
error?: string;
|
|
@@ -241,7 +247,7 @@ export interface ToolCall {
|
|
|
241
247
|
/**
|
|
242
248
|
* How long this call's result may be and still reach its caller whole,
|
|
243
249
|
* measured as the framework stores it: an error's text, or a success's data
|
|
244
|
-
* as JSON (a content array as its text). For a model's call it is the
|
|
250
|
+
* as JSON (a string or a content array as its text). For a model's call it is the
|
|
245
251
|
* agent's inline cap, past which the framework spills the result to a
|
|
246
252
|
* workspace file and sends a preview. A result that long is stored whole
|
|
247
253
|
* unless its round's results together pass the readers' per-message bound,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/types/events.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/types/events.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@animalabs/agent-framework",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Multi-agent framework with pluggable modules, persistent state, and concurrent tool execution",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"license": "MIT",
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@animalabs/chronicle": "^0.4.0",
|
|
52
|
-
"@animalabs/context-manager": "^0.
|
|
53
|
-
"@animalabs/membrane": "^0.
|
|
52
|
+
"@animalabs/context-manager": "^0.20.0",
|
|
53
|
+
"@animalabs/membrane": "^0.7.1",
|
|
54
54
|
"@modelcontextprotocol/client": "^2.3.1",
|
|
55
55
|
"chokidar": "^4.0.3",
|
|
56
56
|
"discord.js": "^14.25.1",
|
package/src/agent.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { createHash } from 'node:crypto';
|
|
|
4
4
|
import type { CacheWireReceipt, KvUnifiedRequestHooks } from './kv-unified-wire.js';
|
|
5
5
|
import { ToolResultGuard } from './tool-result-guard.js';
|
|
6
6
|
import { withoutTokenEstimates } from './thinking-token-stamp.js';
|
|
7
|
+
import { injectionsAsStored } from './text-as-stored.js';
|
|
7
8
|
import { assertBooleanSetting, holdsSettings } from './config-checks.js';
|
|
8
9
|
import {
|
|
9
10
|
CONTINUE_ROW,
|
|
@@ -1157,6 +1158,8 @@ export class Agent {
|
|
|
1157
1158
|
if (this._state.status === 'inferring') {
|
|
1158
1159
|
throw new Error(`Agent ${this.name} is already inferring`);
|
|
1159
1160
|
}
|
|
1161
|
+
// Unstored, so they leave for the request here (text-as-stored.ts).
|
|
1162
|
+
injections = injectionsAsStored(injections);
|
|
1160
1163
|
|
|
1161
1164
|
if (this._state.status === 'waiting_for_tools') {
|
|
1162
1165
|
throw new Error(`Agent ${this.name} is waiting for tool results`);
|
|
@@ -1332,6 +1335,9 @@ export class Agent {
|
|
|
1332
1335
|
compressionTools: ToolDefinition[] = availableTools,
|
|
1333
1336
|
options: ActivationRequestOptions = {},
|
|
1334
1337
|
): Promise<{ request: NormalizedRequest; continuePrompt?: RequestOnlyPrompt }> {
|
|
1338
|
+
// Unstored, so they leave for the request here (text-as-stored.ts), the
|
|
1339
|
+
// layout hash below included.
|
|
1340
|
+
injections = injectionsAsStored(injections);
|
|
1335
1341
|
// Compression may revisit hidden tools in recorded history. Keep its full
|
|
1336
1342
|
// definition set separate from the resident's advertised tools: the
|
|
1337
1343
|
// autobiographical strategy must declare the same tools on its
|
|
@@ -1921,14 +1927,21 @@ export class Agent {
|
|
|
1921
1927
|
// via buildStoredToolResultContent, with workspace spill). No workspace
|
|
1922
1928
|
// is reachable from here, so the house default cap applies as plain
|
|
1923
1929
|
// truncation — bounded beats unbounded, for errors too.
|
|
1924
|
-
const content = results.map((r) =>
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1930
|
+
const content = results.map((r) => {
|
|
1931
|
+
// This API's results are unchecked (nonErrorResultText), so each field
|
|
1932
|
+
// is read once, and only an error that is a string is made well formed;
|
|
1933
|
+
// any other error value is passed on as it was before.
|
|
1934
|
+
const isError = r.result.isError;
|
|
1935
|
+
const error: unknown = isError ? r.result.error ?? 'Unknown error' : undefined;
|
|
1936
|
+
return {
|
|
1937
|
+
type: 'tool_result' as const,
|
|
1938
|
+
toolUseId: r.id,
|
|
1939
|
+
content: isError
|
|
1940
|
+
? truncateForHistory(typeof error === 'string' ? error.toWellFormed() : error as string, DEFAULT_TOOL_RESULT_INLINE_MAX_CHARS)
|
|
1941
|
+
: nonErrorResultText(r.result, DEFAULT_TOOL_RESULT_INLINE_MAX_CHARS),
|
|
1942
|
+
isError,
|
|
1943
|
+
};
|
|
1944
|
+
});
|
|
1932
1945
|
|
|
1933
1946
|
return [{
|
|
1934
1947
|
participant: 'user',
|
package/src/framework.ts
CHANGED
|
@@ -157,6 +157,7 @@ import { bounded, renderList, renderReturn, VALUE_CHARS } from './code-execution
|
|
|
157
157
|
import { splitProseRuns, withoutRoundsProse } from './prose-segments.js';
|
|
158
158
|
import { cumulativeDelta } from './usage-accounting.js';
|
|
159
159
|
import { stampThinkingTokenEstimates } from './thinking-token-stamp.js';
|
|
160
|
+
import { contentAsStored, nameAsStored } from './text-as-stored.js';
|
|
160
161
|
|
|
161
162
|
/** An MCPL tool call refused because its server isn't in the registry: one
|
|
162
163
|
* closed for good, one removed, or one whose connect failed without
|
|
@@ -929,7 +930,8 @@ function describeDeferredWrite(msg: { id: string; participant: string; content:
|
|
|
929
930
|
function isInjectableMidTurn(msg: { participant: string; content: ContentBlock[] }, agentName: string): boolean {
|
|
930
931
|
// Exact, as membrane's role test is: only a participant equal to the
|
|
931
932
|
// request's assistantParticipant (Agent's name) renders as the assistant.
|
|
932
|
-
|
|
933
|
+
// It's the name as sent, which the boundary takes as the store keeps it.
|
|
934
|
+
return nameAsStored(msg.participant) !== agentName
|
|
933
935
|
&& !msg.content.some((b) => b.type === 'tool_use' || b.type === 'tool_result');
|
|
934
936
|
}
|
|
935
937
|
|
|
@@ -1252,6 +1254,12 @@ function isTurnContinuation(reason: string): boolean {
|
|
|
1252
1254
|
return reason === 'context_budget_restart' || reason === 'tool_results_ready'
|
|
1253
1255
|
|| reason === 'tool_result_guard_retry';
|
|
1254
1256
|
}
|
|
1257
|
+
|
|
1258
|
+
/** Wake sources the framework generates for itself (bounce wakes,
|
|
1259
|
+
* continuations, retries, unsticks, admission requeues). A wake from any
|
|
1260
|
+
* other source — a channel message, a heartbeat or other server event, a
|
|
1261
|
+
* gate flush, a timer, an operator nudge — is a cause of its own. */
|
|
1262
|
+
const FRAMEWORK_WAKE_SOURCES = new Set(['framework', 'scheduler']);
|
|
1255
1263
|
const CONVERSATION_ROUTER_STATE_ID = 'framework/conversation-router';
|
|
1256
1264
|
const INFERENCE_LOG_ID = 'framework/inference-log';
|
|
1257
1265
|
const PROCESS_LOG_ID = 'framework/process-log';
|
|
@@ -12145,11 +12153,14 @@ export class AgentFramework {
|
|
|
12145
12153
|
// 0.5.x, and from 0.6.0 declares it can't carry them, so none are
|
|
12146
12154
|
// collected for it. Each goes as its participant and content
|
|
12147
12155
|
// alone: a stored row's metadata is the host's record, not input
|
|
12148
|
-
// for membrane.
|
|
12156
|
+
// for membrane. Each goes with its name and text as the store
|
|
12157
|
+
// keeps them, whether it's a heard message, rendered or not, or a
|
|
12158
|
+
// notice the boundary made: this is where they leave for the
|
|
12159
|
+
// request.
|
|
12149
12160
|
currentState.stream.provideToolResults(
|
|
12150
12161
|
agent.toolResultGuard.submissionResults(membraneResults),
|
|
12151
12162
|
midTurnInjections.length > 0
|
|
12152
|
-
? { injectedMessages: midTurnInjections.map(({ participant, content }) => ({ participant, content })) }
|
|
12163
|
+
? { injectedMessages: midTurnInjections.map(({ participant, content }) => ({ participant: nameAsStored(participant), content: contentAsStored(content) })) }
|
|
12153
12164
|
: undefined,
|
|
12154
12165
|
);
|
|
12155
12166
|
// RFC-006 §3.3: consumption is determined at assembly, and this
|
|
@@ -14458,6 +14469,16 @@ export class AgentFramework {
|
|
|
14458
14469
|
// requests[0] in that mixed batch bypassed the turn lock because a
|
|
14459
14470
|
// restart existed, then treated the continuation as a fresh turn.
|
|
14460
14471
|
const trigger = budgetRestart ?? requests[0];
|
|
14472
|
+
// The bounce-wake cap (bounceProse) stops a bounce → wake → bounce loop
|
|
14473
|
+
// that nothing else feeds. A turn with a cause of its own is not that
|
|
14474
|
+
// loop, so the count starts again. Otherwise only a delivered prose
|
|
14475
|
+
// envelope reset it, and a resident that recovers from bounces with a
|
|
14476
|
+
// send tool kept the count for good: every later bounce, a reply to a
|
|
14477
|
+
// fresh message included, appended its notice without a wake.
|
|
14478
|
+
// (Optional chaining: prototype-built harnesses leave the map unset.)
|
|
14479
|
+
if (requests.some((r) => !FRAMEWORK_WAKE_SOURCES.has(r.source))) {
|
|
14480
|
+
this.proseBounceStreaks?.delete(agentName);
|
|
14481
|
+
}
|
|
14461
14482
|
// Route this turn's auto-published speech to the channel that triggered
|
|
14462
14483
|
// it (item-3 redux). A batched wake may carry several triggering channels
|
|
14463
14484
|
// (messages arrived in >1 channel while the agent was busy/idle):
|
|
@@ -16634,7 +16655,9 @@ export class AgentFramework {
|
|
|
16634
16655
|
}
|
|
16635
16656
|
}
|
|
16636
16657
|
|
|
16637
|
-
/** Cap on consecutive bounce-triggered wakes (notices still append after).
|
|
16658
|
+
/** Cap on consecutive bounce-triggered wakes (notices still append after).
|
|
16659
|
+
* The count resets on a delivered prose envelope, and when a turn starts
|
|
16660
|
+
* with a cause of its own (processInferenceRequests). */
|
|
16638
16661
|
private static readonly PROSE_BOUNCE_WAKE_CAP = 2;
|
|
16639
16662
|
|
|
16640
16663
|
/**
|
|
@@ -20593,7 +20616,7 @@ export class AgentFramework {
|
|
|
20593
20616
|
for (const tc of toolResults) {
|
|
20594
20617
|
const { text, shown, stored } = alone.get(tc.id)!;
|
|
20595
20618
|
spilled.set(tc.id, byShare
|
|
20596
|
-
? await this.spillOrTruncate(text, share!.cap, `${dateLabel}-${tc.id}`, shown, share!.bound, stored.written)
|
|
20619
|
+
? await this.spillOrTruncate(text, share!.cap, `${dateLabel}-${tc.id}`, shown, share!.bound, stored.written, { readCap: maxChars! })
|
|
20597
20620
|
: stored);
|
|
20598
20621
|
}
|
|
20599
20622
|
const blocks: ContentBlock[] = toolResults.map(tc => ({
|
|
@@ -20631,7 +20654,7 @@ export class AgentFramework {
|
|
|
20631
20654
|
tc: CompletedToolCall,
|
|
20632
20655
|
maxChars: number | undefined,
|
|
20633
20656
|
): { text: string; shown: ShownRanges | null } {
|
|
20634
|
-
if (tc.result.isError) return { text: tc.result.error ?? 'Unknown error', shown: null };
|
|
20657
|
+
if (tc.result.isError) return { text: (tc.result.error ?? 'Unknown error').toWellFormed(), shown: null };
|
|
20635
20658
|
const ledger = this.toolImageLedgerFor(agentName);
|
|
20636
20659
|
let blocks = null as HistoryBlockSpan[] | null;
|
|
20637
20660
|
const text = nonErrorResultText(tc.result, undefined, {
|
|
@@ -20809,6 +20832,11 @@ export class AgentFramework {
|
|
|
20809
20832
|
/** The spill file an earlier cut of this text wrote: reused, not written
|
|
20810
20833
|
* again. Undefined when none was cut. */
|
|
20811
20834
|
written?: SpillWrite,
|
|
20835
|
+
/** Set where `cap` and `bound` are this text's share of one turn's
|
|
20836
|
+
* bound (buildStoredToolResultContent): `readCap` is the inline cap,
|
|
20837
|
+
* which a later read of the file comes back under alone in its own turn
|
|
20838
|
+
* and its paging advice is sized to. */
|
|
20839
|
+
share?: { readCap: number },
|
|
20812
20840
|
): Promise<{ text: string; filePath: string | null; written?: SpillWrite }> {
|
|
20813
20841
|
if (!cap || content.length <= cap) return { text: content, filePath: null };
|
|
20814
20842
|
// The stored text is the only place save_recent_image discovers tool
|
|
@@ -20818,45 +20846,67 @@ export class AgentFramework {
|
|
|
20818
20846
|
// newest slots past the cut that the live copy showed are re-appended
|
|
20819
20847
|
// after the notice. Otherwise the live copy is this text, and nothing
|
|
20820
20848
|
// past the cut is kept (#403). The stored copy, notice and kept slots
|
|
20821
|
-
// included, fits `bound`, the most a reader's strategy keeps of it,
|
|
20822
|
-
// no reader's cut takes the
|
|
20823
|
-
// spill notices name the head
|
|
20824
|
-
|
|
20849
|
+
// included, fits `bound`, the most a reader's strategy keeps of it,
|
|
20850
|
+
// where `bound` leaves the notice its room, so no reader's cut takes the
|
|
20851
|
+
// notice (cutStoredToolResultToFit), and the spill notices name the head
|
|
20852
|
+
// they kept. Under a share too small for that, a cut keeps no head and
|
|
20853
|
+
// stores its notice alone, and a text no longer than that notice is
|
|
20854
|
+
// stored whole, with no file written: each result at its least.
|
|
20855
|
+
const readCap = share?.readCap ?? cap;
|
|
20856
|
+
const cut = cutStoredToolResultToFit(content, cap, shown, bound,
|
|
20857
|
+
share ? this.spillNoticeLength(label, content, shown, bound, readCap) : undefined);
|
|
20858
|
+
if (cut.head === content) return { text: content, filePath: null };
|
|
20825
20859
|
const { head } = cut;
|
|
20826
20860
|
const kept = formatKeptImageSlots(cut);
|
|
20827
20861
|
|
|
20828
20862
|
if (written === undefined) written = await this.writeToolResultFile(label, content);
|
|
20863
|
+
const notice = this.spillNotice(head.length, content, shown, bound, readCap, written);
|
|
20864
|
+
// The notice was measured as a written file's reads. A write that failed
|
|
20865
|
+
// keeps nothing, and its notice, naming the failure, can be longer: under
|
|
20866
|
+
// a share, a cut that keeps no head and would store no less than the
|
|
20867
|
+
// text is stored as the text itself, where the text holds no image slot.
|
|
20868
|
+
// One that does is stored as it was measured, cut, since save_recent_image
|
|
20869
|
+
// counted it so before the write.
|
|
20870
|
+
if (share && head.length === 0 && notice.length >= content.length && parseImagePlaceholders(content).length === 0) {
|
|
20871
|
+
return { text: content, filePath: null, written };
|
|
20872
|
+
}
|
|
20873
|
+
return { text: head + notice + kept, filePath: written && written.error === undefined ? written.path : null, written };
|
|
20874
|
+
}
|
|
20875
|
+
|
|
20876
|
+
/**
|
|
20877
|
+
* The notice a cut copy carries after its head (spillOrTruncate): the file
|
|
20878
|
+
* holding the whole result and how to read it back, or why there is none.
|
|
20879
|
+
*/
|
|
20880
|
+
private spillNotice(headLength: number, content: string, shown: ShownRanges | null, bound: number | undefined,
|
|
20881
|
+
readCap: number, written: SpillWrite): string {
|
|
20829
20882
|
if (written && written.error === undefined) {
|
|
20830
|
-
const
|
|
20831
|
-
return {
|
|
20832
|
-
|
|
20833
|
-
+ `\n\n[truncated — showing ${head.length} of ${content.length} chars; full content: workspace file ${path}`
|
|
20834
|
-
+ `. ${this.spillPageAdvice(path, cap, bound === undefined || cutStoredToolResultToFit(content, bound, shown, bound).head.length > head.length)}]`
|
|
20835
|
-
+ kept,
|
|
20836
|
-
filePath: path,
|
|
20837
|
-
written,
|
|
20838
|
-
};
|
|
20883
|
+
const canRaise = bound === undefined || cutStoredToolResultToFit(content, bound, shown, bound).head.length > headLength;
|
|
20884
|
+
return `\n\n[truncated — showing ${headLength} of ${content.length} chars; full content: workspace file ${written.path}`
|
|
20885
|
+
+ `. ${this.spillPageAdvice(written.path, readCap, canRaise)}]`;
|
|
20839
20886
|
}
|
|
20840
20887
|
if (written) {
|
|
20841
20888
|
// A workspace was there and the write FAILED — say that, loudly and
|
|
20842
20889
|
// distinctly. Telling the agent "no writable workspace" would teach
|
|
20843
20890
|
// them their residence lacks a capability it actually has.
|
|
20844
|
-
return {
|
|
20845
|
-
|
|
20846
|
-
+ `\n\n[truncated — showing ${head.length} of ${content.length} chars; spill to workspace file ${written.path} FAILED`
|
|
20847
|
-
+ ` (${written.error}); content over the cap was not retained]`
|
|
20848
|
-
+ kept,
|
|
20849
|
-
filePath: null,
|
|
20850
|
-
written,
|
|
20851
|
-
};
|
|
20891
|
+
return `\n\n[truncated — showing ${headLength} of ${content.length} chars; spill to workspace file ${written.path} FAILED`
|
|
20892
|
+
+ ` (${written.error}); content over the cap was not retained]`;
|
|
20852
20893
|
}
|
|
20853
|
-
return
|
|
20854
|
-
|
|
20855
|
-
|
|
20856
|
-
|
|
20857
|
-
|
|
20858
|
-
|
|
20859
|
-
|
|
20894
|
+
return '\n\n[truncated — original was ' + content.length + ' chars; no writable workspace mount without an include, full content not retained]';
|
|
20895
|
+
}
|
|
20896
|
+
|
|
20897
|
+
/**
|
|
20898
|
+
* The length of the notice a cut of `content` that keeps no head would
|
|
20899
|
+
* carry, before any file is written, as it reads once its file is
|
|
20900
|
+
* (toolResultFilePlace, where any earlier cut of the text wrote it too), so
|
|
20901
|
+
* the cut and save_recent_image's count of the result before it measure
|
|
20902
|
+
* alike. For keeping whole, under a share, a text no longer than its notice
|
|
20903
|
+
* (cutStoredToolResultToFit). A write that fails carries a notice naming
|
|
20904
|
+
* the failure instead (spillOrTruncate).
|
|
20905
|
+
*/
|
|
20906
|
+
private spillNoticeLength(label: string, content: string, shown: ShownRanges | null, bound: number | undefined,
|
|
20907
|
+
readCap: number): number {
|
|
20908
|
+
const place = this.toolResultFilePlace(label);
|
|
20909
|
+
return this.spillNotice(0, content, shown, bound, readCap, place ? { path: place.path } : null).length;
|
|
20860
20910
|
}
|
|
20861
20911
|
|
|
20862
20912
|
/**
|
|
@@ -21185,7 +21235,8 @@ export class AgentFramework {
|
|
|
21185
21235
|
if (b.type === 'text') {
|
|
21186
21236
|
// A text that isn't a string shows as the converters' placeholder,
|
|
21187
21237
|
// rather than sending the whole array to the JSON fallback.
|
|
21188
|
-
|
|
21238
|
+
// Well formed, as the stored copy's text is (nonErrorResultText).
|
|
21239
|
+
let text = typeof b.text === 'string' ? b.text.toWellFormed() : NON_STRING_TEXT_PLACEHOLDER;
|
|
21189
21240
|
if (maxChars && text.length > maxChars) {
|
|
21190
21241
|
text = text.slice(0, toolResultCutAt(text, maxChars))
|
|
21191
21242
|
+ '\n\n[truncated — original was ' + text.length + ' chars'
|
|
@@ -28349,11 +28400,16 @@ export class AgentFramework {
|
|
|
28349
28400
|
// the round's calls, finished or not.
|
|
28350
28401
|
const { cap, bound } = this.resolveToolResultInlineCap(agent);
|
|
28351
28402
|
const share = toolResultShare(cap, bound, state.pending.size + state.completed.length);
|
|
28403
|
+
const dateLabel = new Date().toISOString().slice(0, 10);
|
|
28352
28404
|
for (let i = state.completed.length - 1; i >= 0 && collecting(); i--) {
|
|
28353
28405
|
const tc = state.completed[i]!;
|
|
28354
28406
|
const { text, shown } = this.storedToolResultText(agentName, tc, cap);
|
|
28355
28407
|
const alone = storedImageSlots(text, cap, shown, bound);
|
|
28356
|
-
|
|
28408
|
+
// By its share, with the notice the commit's cut would carry, so a
|
|
28409
|
+
// result no longer than its notice counts as kept whole, as the
|
|
28410
|
+
// commit stores it.
|
|
28411
|
+
const byShare = storedImageSlots(text, share.cap, shown, share.bound,
|
|
28412
|
+
this.spillNoticeLength(`${dateLabel}-${tc.id}`, text, shown, share.bound, cap));
|
|
28357
28413
|
if (alone.length !== byShare.length || alone.some((slot, j) => slot.text !== byShare[j]!.text)) {
|
|
28358
28414
|
this.toolRoundsByShare.add(state.completed);
|
|
28359
28415
|
}
|
package/src/mcpl/references.ts
CHANGED
|
@@ -434,7 +434,10 @@ export function unfetchableReason(record: ReferenceRecord, nowMs = Date.now()):
|
|
|
434
434
|
/**
|
|
435
435
|
* RFC-005 treatment for one MCPL wire block, for the model-visible text
|
|
436
436
|
* lanes. Returns a replacement string, or null when the block should keep
|
|
437
|
-
* its existing (inline/text) handling.
|
|
437
|
+
* its existing (inline/text) handling. A reference's stub carries text taken
|
|
438
|
+
* from the block's own fields, so it's made well formed (a lone UTF-16
|
|
439
|
+
* surrogate becomes U+FFFD), as the context store would make it: a tool
|
|
440
|
+
* result's copies then carry the same text (#695).
|
|
438
441
|
*/
|
|
439
442
|
export function referenceStubOrNull(block: unknown, provenance?: string, serverId?: string): string | null {
|
|
440
443
|
const c = classifyBlock(block);
|
|
@@ -442,7 +445,7 @@ export function referenceStubOrNull(block: unknown, provenance?: string, serverI
|
|
|
442
445
|
case 'text': return null;
|
|
443
446
|
case 'inline':
|
|
444
447
|
return c.contradiction ? INLINE_WITHHELD_TEXT : null;
|
|
445
|
-
case 'reference': return buildReferenceStub(c.testimony, provenance, serverId);
|
|
448
|
+
case 'reference': return buildReferenceStub(c.testimony, provenance, serverId).toWellFormed();
|
|
446
449
|
case 'invalid': return c.shown;
|
|
447
450
|
}
|
|
448
451
|
}
|