@aexol/spectral 0.9.260 → 0.9.263
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/agent/index.d.ts +26 -0
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +240 -14
- package/dist/generated/zeus/const.d.ts.map +1 -1
- package/dist/generated/zeus/const.js +9 -4
- package/dist/generated/zeus/index.d.ts +68 -43
- package/dist/generated/zeus/index.d.ts.map +1 -1
- package/dist/memory/tool-output-compressor.d.ts +31 -1
- package/dist/memory/tool-output-compressor.d.ts.map +1 -1
- package/dist/memory/tool-output-compressor.js +64 -22
- package/dist/sdk/coding-agent/core/agent-session.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/agent-session.js +28 -6
- package/dist/sdk/coding-agent/core/session-manager.d.ts +6 -2
- package/dist/sdk/coding-agent/core/session-manager.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/session-manager.js +6 -2
- package/dist/server/agent-bridge.d.ts.map +1 -1
- package/dist/server/agent-bridge.js +7 -1
- package/dist/server/session-stream.d.ts +23 -0
- package/dist/server/session-stream.d.ts.map +1 -1
- package/dist/server/session-stream.js +83 -15
- package/package.json +1 -1
package/dist/agent/index.d.ts
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
* `compact_context`, and `subagent` remain excluded
|
|
32
32
|
*/
|
|
33
33
|
import type { AgentEvent, AgentTool } from "../sdk/agent-core/index.js";
|
|
34
|
+
import type { AgentMessage } from "../sdk/agent-core/index.js";
|
|
34
35
|
import { type ExtensionAPI, type ExtensionContext } from "../sdk/coding-agent/index.js";
|
|
35
36
|
import { type AgentConfig } from "./agents.js";
|
|
36
37
|
import type { ServerEvent } from "../server/wire.ts";
|
|
@@ -91,6 +92,31 @@ export declare function resolveSubagentMaxAttempts(explicit: number | undefined,
|
|
|
91
92
|
enabled?: boolean;
|
|
92
93
|
maxRetries?: number;
|
|
93
94
|
} | undefined): number;
|
|
95
|
+
/**
|
|
96
|
+
* Deterministic compact-and-retry for a subagent context overflow.
|
|
97
|
+
*
|
|
98
|
+
* Builds a compacted message state from the child transcript: a deterministic
|
|
99
|
+
* DCP-lite summary of the older history plus a kept recent tail. The latest
|
|
100
|
+
* user message (the task prompt) is pinned so it survives verbatim. Returns the
|
|
101
|
+
* new message state, or `undefined` when there is nothing meaningful to
|
|
102
|
+
* compact (e.g. the transcript is just the task prompt) or the cut cannot be
|
|
103
|
+
* computed.
|
|
104
|
+
*
|
|
105
|
+
* No LLM calls — this is pure `prepareCompaction` + `compactDcpLite` over a
|
|
106
|
+
* synthetic session-entry list, so it is safe to run inline in the retry loop.
|
|
107
|
+
*/
|
|
108
|
+
export declare function compactMessagesForOverflow(messages: AgentMessage[], contextWindow: number): AgentMessage[] | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* Deterministic single-message size guard.
|
|
111
|
+
*
|
|
112
|
+
* If a SINGLE message's estimated tokens exceed ~50% of the model context
|
|
113
|
+
* window, its text content is truncated to a safe cap and a marker note is
|
|
114
|
+
* appended. This keeps the provider request sub-window even when one oversized
|
|
115
|
+
* message (e.g. a giant file read) would otherwise push the request over the
|
|
116
|
+
* limit and yield a silent 400. Purely local — no LLM calls. Returns the
|
|
117
|
+
* original array unchanged when no message needs truncation.
|
|
118
|
+
*/
|
|
119
|
+
export declare function guardOversizedMessages(messages: AgentMessage[], contextWindow: number): AgentMessage[];
|
|
94
120
|
export default function subagentExtension(ext: ExtensionAPI, opts?: {
|
|
95
121
|
disabledAgents?: string[];
|
|
96
122
|
emitSubagentEvent?: (event: ServerEvent) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAEX,UAAU,EAEV,SAAS,EAET,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAEX,UAAU,EAEV,SAAS,EAET,MAAM,4BAA4B,CAAC;AAOpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAwB/D,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAKrB,MAAM,8BAA8B,CAAC;AAItC,OAAO,EACN,KAAK,WAAW,EAQhB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,uCAAuC,CAAC;AAS/C,OAAO,KAAK,EAAE,sBAAsB,EAAgB,MAAM,6CAA6C,CAAC;AA+HxG;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACxC,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC,GACpF,MAAM,CAeR;AAyND;;;GAGG;AACH,wBAAgB,oCAAoC,CACnD,cAAc,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,GAChD,IAAI,CAAC,sBAAsB,EAAE,WAAW,GAAG,cAAc,CAAC,CAe5D;AAgCD,wBAAgB,oBAAoB,CACnC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,YAAY,EACjB,GAAG,EAAE,gBAAgB,EACrB,SAAS,CAAC,EAAE,MAAM,GAChB,SAAS,EAAE,CAkDb;AAyBD;;;;;;;;;;GAUG;AACH;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACxC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,6EAA6E;IAC7E,GAAG,EAAE,cAAc,CAAC;CACpB;AAED,8EAA8E;AAC9E,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,wBAAwB,CAAC;AAqF1E,2FAA2F;AAC3F,wBAAgB,+BAA+B,CAC9C,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GACtD,IAAI,CAEN;AAmBD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GAC9D,MAAM,CAiBR;AAsBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,YAAY,EAAE,EACxB,aAAa,EAAE,MAAM,GACnB,YAAY,EAAE,GAAG,SAAS,CAyE5B;AASD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACrC,QAAQ,EAAE,YAAY,EAAE,EACxB,aAAa,EAAE,MAAM,GACnB,YAAY,EAAE,CAchB;AA8tBD,MAAM,CAAC,OAAO,UAAU,iBAAiB,CACxC,GAAG,EAAE,YAAY,EACjB,IAAI,CAAC,EAAE;IACN,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,wBAAwB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CAC3D,GACC,IAAI,CAwbN"}
|
package/dist/agent/index.js
CHANGED
|
@@ -32,6 +32,9 @@
|
|
|
32
32
|
*/
|
|
33
33
|
import { agentLoop, agentLoopContinue, } from "../sdk/agent-core/index.js";
|
|
34
34
|
import { buildIsolatedRequestTimePrunedMessagesResult, COMPACT_CONTEXT_TOOL_NAME, } from "../memory/tools/compact-context.js";
|
|
35
|
+
import { compactDcpLite, prepareCompaction, DEFAULT_COMPACTION_SETTINGS, } from "../sdk/coding-agent/core/compaction/index.js";
|
|
36
|
+
import { estimateTokens } from "../sdk/coding-agent/core/compaction/tokens.js";
|
|
37
|
+
import { createCompactionSummaryMessage, convertToLlm, } from "../sdk/coding-agent/core/messages.js";
|
|
35
38
|
import { isRateLimitError, isTransientApiError, isContextOverflow, isPaymentRequiredError, streamSimple, } from "../sdk/ai/index.js";
|
|
36
39
|
import { RETRY_DEFAULT_BASE_DELAY_MS, RETRY_DEFAULT_MAX_RETRIES, RETRY_MAX_BACKOFF_DELAY_MS, } from "../sdk/coding-agent/index.js";
|
|
37
40
|
import { mutateSystemPrompt } from "../sdk/coding-agent/core/system-prompt-mutator.js";
|
|
@@ -136,6 +139,25 @@ function compactProgressMessage(value) {
|
|
|
136
139
|
return value === undefined ? undefined : "Tool progress updated";
|
|
137
140
|
}
|
|
138
141
|
const PRIMARY_AGENT_BLOCK_RE = /(?:^|\n)(?:# Primary Agent: [^\n]*\n(?:\n[^\n]*)*?)(?:\n\n---\n\n|$)/;
|
|
142
|
+
/**
|
|
143
|
+
* Strip `compact_context` tool-description lines from a base system prompt.
|
|
144
|
+
*
|
|
145
|
+
* Subagents exclude the `compact_context` tool (see SUBAGENT_EXCLUDED_TOOL_NAMES),
|
|
146
|
+
* so its promptSnippet (an "Available tools" bullet) and its promptGuidelines
|
|
147
|
+
* ("Guidelines" bullets) must not leak into the subagent's prompt — they would
|
|
148
|
+
* describe a tool the subagent cannot call. Both are `- ` bullets that mention
|
|
149
|
+
* the tool name, so a line-based filter is a clean deterministic anchor. Only
|
|
150
|
+
* the subagent base prompt is touched; the main-session prompt is unaffected.
|
|
151
|
+
*/
|
|
152
|
+
function stripCompactContextFromPrompt(prompt) {
|
|
153
|
+
if (!prompt.includes(COMPACT_CONTEXT_TOOL_NAME))
|
|
154
|
+
return prompt;
|
|
155
|
+
return prompt
|
|
156
|
+
.split("\n")
|
|
157
|
+
.filter((line) => !(line.trimStart().startsWith("- ") &&
|
|
158
|
+
line.includes(COMPACT_CONTEXT_TOOL_NAME)))
|
|
159
|
+
.join("\n");
|
|
160
|
+
}
|
|
139
161
|
/**
|
|
140
162
|
* Build the system prompt for a subagent session.
|
|
141
163
|
*
|
|
@@ -151,10 +173,13 @@ export function buildSubagentSystemPrompt(baseSystemPrompt, agent) {
|
|
|
151
173
|
agentMetadataBlock(agent);
|
|
152
174
|
if (!baseSystemPrompt)
|
|
153
175
|
return subagentBlock;
|
|
154
|
-
|
|
155
|
-
|
|
176
|
+
// Drop the excluded compact_context tool's description lines before any
|
|
177
|
+
// further shaping, so the subagent never sees a tool it cannot call.
|
|
178
|
+
const base = stripCompactContextFromPrompt(baseSystemPrompt);
|
|
179
|
+
const stripped = base.replace(PRIMARY_AGENT_BLOCK_RE, "");
|
|
180
|
+
if (stripped === base) {
|
|
156
181
|
// No existing primary block: inject the subagent block below the base.
|
|
157
|
-
return `${
|
|
182
|
+
return `${base}\n\n---\n\n${subagentBlock}`;
|
|
158
183
|
}
|
|
159
184
|
const remainder = stripped.replace(/^\n+|\n+$/g, "");
|
|
160
185
|
return remainder ? `${remainder}\n\n---\n\n${subagentBlock}` : subagentBlock;
|
|
@@ -477,6 +502,147 @@ export function resolveSubagentMaxAttempts(explicit, settings) {
|
|
|
477
502
|
return 1 + retries;
|
|
478
503
|
}
|
|
479
504
|
// ---------------------------------------------------------------------------
|
|
505
|
+
// Overflow recovery — deterministic DCP-lite compact-and-retry
|
|
506
|
+
// ---------------------------------------------------------------------------
|
|
507
|
+
/**
|
|
508
|
+
* Max compact-and-retry attempts on a context overflow. This budget is
|
|
509
|
+
* SEPARATE from the transient-error retry budget (`maxSegments`): an overflow
|
|
510
|
+
* is not a transient provider failure, so recovering it must not consume the
|
|
511
|
+
* transient retries (and vice versa).
|
|
512
|
+
*/
|
|
513
|
+
const MAX_OVERFLOW_COMPACT_RETRIES = 2;
|
|
514
|
+
/**
|
|
515
|
+
* Recent-tail keep budget for an overflow compaction: `max(12_000, 10% of the
|
|
516
|
+
* model context window)` tokens, mirroring the main session's auto
|
|
517
|
+
* older-history keep-recent floor.
|
|
518
|
+
*/
|
|
519
|
+
const OVERFLOW_KEEP_RECENT_TOKENS_FLOOR = 12_000;
|
|
520
|
+
const OVERFLOW_KEEP_RECENT_WINDOW_RATIO = 0.1;
|
|
521
|
+
/**
|
|
522
|
+
* Deterministic compact-and-retry for a subagent context overflow.
|
|
523
|
+
*
|
|
524
|
+
* Builds a compacted message state from the child transcript: a deterministic
|
|
525
|
+
* DCP-lite summary of the older history plus a kept recent tail. The latest
|
|
526
|
+
* user message (the task prompt) is pinned so it survives verbatim. Returns the
|
|
527
|
+
* new message state, or `undefined` when there is nothing meaningful to
|
|
528
|
+
* compact (e.g. the transcript is just the task prompt) or the cut cannot be
|
|
529
|
+
* computed.
|
|
530
|
+
*
|
|
531
|
+
* No LLM calls — this is pure `prepareCompaction` + `compactDcpLite` over a
|
|
532
|
+
* synthetic session-entry list, so it is safe to run inline in the retry loop.
|
|
533
|
+
*/
|
|
534
|
+
export function compactMessagesForOverflow(messages, contextWindow) {
|
|
535
|
+
// Drop trailing failed assistant message(s) so the compaction summarizes
|
|
536
|
+
// real history, not the overflow error turn the child just produced.
|
|
537
|
+
const working = [...messages];
|
|
538
|
+
while (working.length > 0 &&
|
|
539
|
+
working[working.length - 1].role === "assistant") {
|
|
540
|
+
working.pop();
|
|
541
|
+
}
|
|
542
|
+
// Need at least a summarizable prefix plus a kept tail to be useful.
|
|
543
|
+
if (working.length < 2)
|
|
544
|
+
return undefined;
|
|
545
|
+
const entries = working.map((message, index) => ({
|
|
546
|
+
type: "message",
|
|
547
|
+
id: `subagent-compact-${index}`,
|
|
548
|
+
parentId: index > 0 ? `subagent-compact-${index - 1}` : null,
|
|
549
|
+
timestamp: new Date(index).toISOString(),
|
|
550
|
+
message,
|
|
551
|
+
}));
|
|
552
|
+
const keepRecentTokens = Math.max(OVERFLOW_KEEP_RECENT_TOKENS_FLOOR, Math.floor((contextWindow ?? 0) * OVERFLOW_KEEP_RECENT_WINDOW_RATIO));
|
|
553
|
+
const settings = {
|
|
554
|
+
...DEFAULT_COMPACTION_SETTINGS,
|
|
555
|
+
keepRecentTokens,
|
|
556
|
+
};
|
|
557
|
+
// No `pinLatestUserMessage`: in a subagent the task prompt is the FIRST (and
|
|
558
|
+
// usually only) user message, so pinning it would pull the cut to the start
|
|
559
|
+
// and summarize nothing. The task prompt is preserved verbatim below instead.
|
|
560
|
+
const preparation = prepareCompaction(entries, settings, {
|
|
561
|
+
phaseBoundary: false,
|
|
562
|
+
});
|
|
563
|
+
if (!preparation)
|
|
564
|
+
return undefined;
|
|
565
|
+
// Nothing to summarize (the whole transcript is the recent tail) → the
|
|
566
|
+
// compaction would not shrink the request, so there is nothing to recover.
|
|
567
|
+
// A split-turn cut summarizes via `turnPrefixMessages` instead of
|
|
568
|
+
// `messagesToSummarize`, so both must be empty to be a true no-op.
|
|
569
|
+
if (preparation.messagesToSummarize.length === 0 &&
|
|
570
|
+
preparation.turnPrefixMessages.length === 0) {
|
|
571
|
+
return undefined;
|
|
572
|
+
}
|
|
573
|
+
const compactResult = compactDcpLite(preparation);
|
|
574
|
+
const firstKeptIndex = entries.findIndex((entry) => entry.id === compactResult.firstKeptEntryId);
|
|
575
|
+
const keptTail = working.slice(firstKeptIndex >= 0 ? firstKeptIndex : 0);
|
|
576
|
+
if (keptTail.length === 0)
|
|
577
|
+
return undefined;
|
|
578
|
+
const summaryMessage = createCompactionSummaryMessage(compactResult.summary, compactResult.tokensBefore, new Date().toISOString());
|
|
579
|
+
// Preserve the task prompt (first user message) verbatim if the cut
|
|
580
|
+
// summarized it away — the DCP-lite summary only keeps a bounded excerpt,
|
|
581
|
+
// and the goal must survive compaction intact.
|
|
582
|
+
const firstUserIndex = working.findIndex((m) => m.role === "user");
|
|
583
|
+
const taskPrompt = firstUserIndex >= 0 && firstKeptIndex > firstUserIndex
|
|
584
|
+
? working[firstUserIndex]
|
|
585
|
+
: undefined;
|
|
586
|
+
return taskPrompt
|
|
587
|
+
? [taskPrompt, summaryMessage, ...keptTail]
|
|
588
|
+
: [summaryMessage, ...keptTail];
|
|
589
|
+
}
|
|
590
|
+
/** Fraction of the window a single message may occupy before the guard cuts it. */
|
|
591
|
+
const MAX_SINGLE_MESSAGE_WINDOW_RATIO = 0.5;
|
|
592
|
+
/** Target size (fraction of the window) a truncated message is cut to. */
|
|
593
|
+
const TRUNCATED_MESSAGE_TARGET_WINDOW_RATIO = 0.4;
|
|
594
|
+
/** Rough chars-per-token heuristic for turning a token budget into a char cap. */
|
|
595
|
+
const CHARS_PER_TOKEN = 4;
|
|
596
|
+
/**
|
|
597
|
+
* Deterministic single-message size guard.
|
|
598
|
+
*
|
|
599
|
+
* If a SINGLE message's estimated tokens exceed ~50% of the model context
|
|
600
|
+
* window, its text content is truncated to a safe cap and a marker note is
|
|
601
|
+
* appended. This keeps the provider request sub-window even when one oversized
|
|
602
|
+
* message (e.g. a giant file read) would otherwise push the request over the
|
|
603
|
+
* limit and yield a silent 400. Purely local — no LLM calls. Returns the
|
|
604
|
+
* original array unchanged when no message needs truncation.
|
|
605
|
+
*/
|
|
606
|
+
export function guardOversizedMessages(messages, contextWindow) {
|
|
607
|
+
if (!Number.isFinite(contextWindow) || contextWindow <= 0)
|
|
608
|
+
return messages;
|
|
609
|
+
const thresholdTokens = contextWindow * MAX_SINGLE_MESSAGE_WINDOW_RATIO;
|
|
610
|
+
const targetChars = Math.floor(contextWindow * TRUNCATED_MESSAGE_TARGET_WINDOW_RATIO * CHARS_PER_TOKEN);
|
|
611
|
+
let changed = false;
|
|
612
|
+
const guarded = messages.map((message) => {
|
|
613
|
+
if (estimateTokens(message) <= thresholdTokens)
|
|
614
|
+
return message;
|
|
615
|
+
changed = true;
|
|
616
|
+
return truncateMessageToSafeCap(message, targetChars);
|
|
617
|
+
});
|
|
618
|
+
return changed ? guarded : messages;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Truncate a message's text content to `targetChars`, appending a marker note.
|
|
622
|
+
* Non-text parts (images, tool calls) are preserved. Returns the message
|
|
623
|
+
* unchanged when its text is already within the cap.
|
|
624
|
+
*/
|
|
625
|
+
function truncateMessageToSafeCap(message, targetChars) {
|
|
626
|
+
const rawContent = message.content;
|
|
627
|
+
const parts = Array.isArray(rawContent)
|
|
628
|
+
? rawContent
|
|
629
|
+
: typeof rawContent === "string"
|
|
630
|
+
? [{ type: "text", text: rawContent }]
|
|
631
|
+
: [];
|
|
632
|
+
const textParts = parts.filter((part) => part.type === "text" && typeof part.text === "string");
|
|
633
|
+
const totalText = textParts.map((part) => part.text).join("\n");
|
|
634
|
+
if (totalText.length <= targetChars)
|
|
635
|
+
return message;
|
|
636
|
+
const omitted = totalText.length - targetChars;
|
|
637
|
+
const truncatedText = totalText.slice(0, targetChars) +
|
|
638
|
+
`\n[spectral: truncated ${omitted} chars to fit context window]`;
|
|
639
|
+
const nonTextParts = parts.filter((part) => part.type !== "text");
|
|
640
|
+
return {
|
|
641
|
+
...message,
|
|
642
|
+
content: [{ type: "text", text: truncatedText }, ...nonTextParts],
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
// ---------------------------------------------------------------------------
|
|
480
646
|
// Core — run a single subagent in-process via agentLoop
|
|
481
647
|
// ---------------------------------------------------------------------------
|
|
482
648
|
async function runSingleAgent(defaultCwd, agents, activePrimary, agentName, task, cwd, step, signal, onUpdate, makeDetails, parentToolCallId, onInternalEvent, ext, ctx, maxRetries) {
|
|
@@ -662,23 +828,39 @@ async function runSingleAgent(defaultCwd, agents, activePrimary, agentName, task
|
|
|
662
828
|
model,
|
|
663
829
|
apiKey: auth.apiKey,
|
|
664
830
|
headers: auth.headers,
|
|
665
|
-
|
|
831
|
+
// Full converter so a compact-and-retry's `compactionSummary` message
|
|
832
|
+
// is sent to the LLM (the old role filter would have silently dropped
|
|
833
|
+
// it, defeating the compaction). Standard user/assistant/toolResult
|
|
834
|
+
// messages pass through unchanged.
|
|
835
|
+
convertToLlm: (msgs) => convertToLlm(msgs),
|
|
666
836
|
toolExecution: "parallel",
|
|
667
837
|
transformContext: async (messages) => {
|
|
668
838
|
// Pure request-time DCP adapter: policy-derived, invocation-local, and
|
|
669
839
|
// never connected to the parent Runtime or SessionManager.
|
|
840
|
+
let transformed = messages;
|
|
670
841
|
try {
|
|
671
842
|
const pruned = buildIsolatedRequestTimePrunedMessagesResult(messages, undefined, undefined, isolatedPruneFrozen, model.contextWindow);
|
|
672
843
|
isolatedPruneFrozen = pruned.frozen;
|
|
673
|
-
|
|
844
|
+
transformed = pruned.messages;
|
|
845
|
+
}
|
|
846
|
+
catch {
|
|
847
|
+
transformed = messages;
|
|
848
|
+
}
|
|
849
|
+
// Deterministic single-message guard: if one message is ~50%+ of
|
|
850
|
+
// the window, truncate it so the provider gets a sub-window request
|
|
851
|
+
// instead of a silent 400. Request-time only (no mutation, no LLM).
|
|
852
|
+
try {
|
|
853
|
+
transformed = guardOversizedMessages(transformed, model.contextWindow);
|
|
674
854
|
}
|
|
675
855
|
catch {
|
|
676
|
-
|
|
856
|
+
// Leave the (already pruned) messages as-is on an unexpected
|
|
857
|
+
// guard failure — never block the request on the guard.
|
|
677
858
|
}
|
|
859
|
+
return transformed;
|
|
678
860
|
},
|
|
679
861
|
afterToolCall: async ({ toolCall, args, result, isError }) => {
|
|
680
862
|
try {
|
|
681
|
-
const content = compressSubagentToolResult(toolCall.name, args, result, ctx);
|
|
863
|
+
const content = compressSubagentToolResult(toolCall.name, args, result, ctx, isError);
|
|
682
864
|
return content ? { content, details: result.details, isError, terminate: result.terminate } : undefined;
|
|
683
865
|
}
|
|
684
866
|
catch {
|
|
@@ -702,6 +884,10 @@ async function runSingleAgent(defaultCwd, agents, activePrimary, agentName, task
|
|
|
702
884
|
const collectedMessages = [];
|
|
703
885
|
let hadError = false;
|
|
704
886
|
let segments = 0;
|
|
887
|
+
// Compact-and-retry budget for context overflow. Separate from the
|
|
888
|
+
// transient-error retry budget (`maxSegments`) so recovering an overflow
|
|
889
|
+
// does not consume transient retries (and vice versa).
|
|
890
|
+
let overflowCompactions = 0;
|
|
705
891
|
// Per-LLM-round timing stamps (TPS contract), mirroring the bridge's
|
|
706
892
|
// main-session `pending` stamps: message_start opens the round, the
|
|
707
893
|
// first text/thinking delta ends the TTFT window, message_end closes it.
|
|
@@ -854,8 +1040,6 @@ async function runSingleAgent(defaultCwd, agents, activePrimary, agentName, task
|
|
|
854
1040
|
// Stream result error — already handled by message events
|
|
855
1041
|
}
|
|
856
1042
|
// ── Run-level retry decision (mirrors AgentSession._prepareRetry) ──
|
|
857
|
-
if (segments >= maxSegments)
|
|
858
|
-
break;
|
|
859
1043
|
if (currentResult.stopReason !== "error")
|
|
860
1044
|
break;
|
|
861
1045
|
// Abort after a completed segment (parent stop or budget timeout):
|
|
@@ -867,13 +1051,55 @@ async function runSingleAgent(defaultCwd, agents, activePrimary, agentName, task
|
|
|
867
1051
|
// Explicit for parity with AgentSession._isRetryableError.
|
|
868
1052
|
if (isPaymentRequiredError(errorMessage))
|
|
869
1053
|
break;
|
|
870
|
-
// Context overflow is
|
|
871
|
-
//
|
|
872
|
-
//
|
|
873
|
-
//
|
|
1054
|
+
// Context overflow is NOT transient — it is recovered with a
|
|
1055
|
+
// deterministic DCP-lite compact-and-retry on a SEPARATE budget
|
|
1056
|
+
// (`overflowCompactions`), so it does not consume the transient
|
|
1057
|
+
// retry budget (`maxSegments`). Checked before the transient
|
|
1058
|
+
// classifiers because overflow messages can contain bare
|
|
1059
|
+
// status-code-like numerals (e.g. "501234 tokens > 500000 maximum").
|
|
874
1060
|
if (isContextOverflow(buildOverflowProbe(errorMessage), model.contextWindow)) {
|
|
875
|
-
|
|
1061
|
+
if (overflowCompactions >= MAX_OVERFLOW_COMPACT_RETRIES) {
|
|
1062
|
+
// Second overflow after compaction: recovery is exhausted.
|
|
1063
|
+
currentResult.stopReason = "error";
|
|
1064
|
+
const message = "Context overflow recovery failed after compact-and-retry attempts. Try reducing context or switching to a larger-context model.";
|
|
1065
|
+
currentResult.errorMessage = message;
|
|
1066
|
+
currentResult.stderr = message;
|
|
1067
|
+
break;
|
|
1068
|
+
}
|
|
1069
|
+
let compacted;
|
|
1070
|
+
try {
|
|
1071
|
+
compacted = compactMessagesForOverflow(collectedMessages, model.contextWindow);
|
|
1072
|
+
}
|
|
1073
|
+
catch (err) {
|
|
1074
|
+
console.error(`[subagent] overflow compaction failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1075
|
+
compacted = undefined;
|
|
1076
|
+
}
|
|
1077
|
+
if (!compacted) {
|
|
1078
|
+
// Nothing compactable (e.g. only the task prompt) or the cut
|
|
1079
|
+
// could not be computed: hard-fail with a clear message.
|
|
1080
|
+
currentResult.stopReason = "error";
|
|
1081
|
+
const message = "Context overflow: no compactable history to summarize. Try reducing context or switching to a larger-context model.";
|
|
1082
|
+
currentResult.errorMessage = message;
|
|
1083
|
+
currentResult.stderr = message;
|
|
1084
|
+
break;
|
|
1085
|
+
}
|
|
1086
|
+
// Apply the compacted state and resume on the next iteration via
|
|
1087
|
+
// agentLoopContinue (the last kept message is a toolResult/user).
|
|
1088
|
+
collectedMessages.length = 0;
|
|
1089
|
+
for (const msg of compacted)
|
|
1090
|
+
collectedMessages.push(msg);
|
|
1091
|
+
currentResult.messages = [...collectedMessages];
|
|
1092
|
+
// Reset the frozen request-time prune so the new (smaller)
|
|
1093
|
+
// prefix re-freezes and stays byte-stable within the resumed run.
|
|
1094
|
+
isolatedPruneFrozen = null;
|
|
1095
|
+
overflowCompactions += 1;
|
|
1096
|
+
continue;
|
|
876
1097
|
}
|
|
1098
|
+
// Transient provider error: bounded by the maxSegments retry budget.
|
|
1099
|
+
// Compact-and-retry segments are excluded so overflow recovery does
|
|
1100
|
+
// not consume the transient budget.
|
|
1101
|
+
if (segments - overflowCompactions >= maxSegments)
|
|
1102
|
+
break;
|
|
877
1103
|
if (!isRateLimitError(errorMessage) && !isTransientApiError(errorMessage)) {
|
|
878
1104
|
break;
|
|
879
1105
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../../src/generated/zeus/const.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAC,GAAG,CA47B5C,CAAA;AAED,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAC,GAAG,
|
|
1
|
+
{"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../../src/generated/zeus/const.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAC,GAAG,CA47B5C,CAAA;AAED,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAC,GAAG,CAg5C1C,CAAA;AAED,eAAO,MAAM,GAAG;;;;CAIf,CAAA"}
|
|
@@ -91,8 +91,8 @@ export const AllTypesProps = {
|
|
|
91
91
|
UpdateLeadInput: {
|
|
92
92
|
leadType: "LeadType"
|
|
93
93
|
},
|
|
94
|
-
IngestCloudDocumentInput: {},
|
|
95
94
|
UpdateCloudDocumentInput: {},
|
|
95
|
+
RequestCloudDocumentUploadInput: {},
|
|
96
96
|
InferenceStatus: "enum",
|
|
97
97
|
RegisterInput: {},
|
|
98
98
|
LoginInput: {},
|
|
@@ -319,8 +319,8 @@ export const AllTypesProps = {
|
|
|
319
319
|
input: "GenerateAexolFromTextInput"
|
|
320
320
|
},
|
|
321
321
|
cancelFromTask: {},
|
|
322
|
-
|
|
323
|
-
input: "
|
|
322
|
+
requestCloudDocumentUpload: {
|
|
323
|
+
input: "RequestCloudDocumentUploadInput"
|
|
324
324
|
},
|
|
325
325
|
updateCloudDocument: {
|
|
326
326
|
input: "UpdateCloudDocumentInput"
|
|
@@ -967,6 +967,11 @@ export const ReturnTypes = {
|
|
|
967
967
|
score: "Float",
|
|
968
968
|
content: "String"
|
|
969
969
|
},
|
|
970
|
+
CloudDocumentUpload: {
|
|
971
|
+
id: "ID",
|
|
972
|
+
putUrl: "String",
|
|
973
|
+
expiresAt: "DateTime"
|
|
974
|
+
},
|
|
970
975
|
TokenUsage: {
|
|
971
976
|
inputTokens: "Long",
|
|
972
977
|
outputTokens: "Long",
|
|
@@ -1199,7 +1204,7 @@ export const ReturnTypes = {
|
|
|
1199
1204
|
deleteProjectFile: "Boolean",
|
|
1200
1205
|
generateAexolFromText: "FromTask",
|
|
1201
1206
|
cancelFromTask: "Boolean",
|
|
1202
|
-
|
|
1207
|
+
requestCloudDocumentUpload: "CloudDocumentUpload",
|
|
1203
1208
|
updateCloudDocument: "CloudDocument",
|
|
1204
1209
|
deleteCloudDocument: "Boolean",
|
|
1205
1210
|
cleanupOrphanCloudChunks: "Int",
|
|
@@ -940,15 +940,6 @@ export type ValueTypes = {
|
|
|
940
940
|
__typename?: boolean | `@${string}`;
|
|
941
941
|
['...on CloudSearchResult']?: Omit<ValueTypes["CloudSearchResult"], "...on CloudSearchResult">;
|
|
942
942
|
}>;
|
|
943
|
-
["IngestCloudDocumentInput"]: {
|
|
944
|
-
teamId: ValueTypes["ID"] | Variable<any, string>;
|
|
945
|
-
projectId: ValueTypes["ID"] | Variable<any, string>;
|
|
946
|
-
name: string | Variable<any, string>;
|
|
947
|
-
contentType: string | Variable<any, string>;
|
|
948
|
-
content: string | Variable<any, string>;
|
|
949
|
-
metadata?: string | undefined | null | Variable<any, string>;
|
|
950
|
-
tags?: string | undefined | null | Variable<any, string>;
|
|
951
|
-
};
|
|
952
943
|
["UpdateCloudDocumentInput"]: {
|
|
953
944
|
name?: string | undefined | null | Variable<any, string>;
|
|
954
945
|
contentType?: string | undefined | null | Variable<any, string>;
|
|
@@ -956,6 +947,22 @@ export type ValueTypes = {
|
|
|
956
947
|
metadata?: string | undefined | null | Variable<any, string>;
|
|
957
948
|
tags?: string | undefined | null | Variable<any, string>;
|
|
958
949
|
};
|
|
950
|
+
["RequestCloudDocumentUploadInput"]: {
|
|
951
|
+
teamId: ValueTypes["ID"] | Variable<any, string>;
|
|
952
|
+
projectId: ValueTypes["ID"] | Variable<any, string>;
|
|
953
|
+
name: string | Variable<any, string>;
|
|
954
|
+
contentType: string | Variable<any, string>;
|
|
955
|
+
contentLength?: number | undefined | null | Variable<any, string>;
|
|
956
|
+
metadata?: string | undefined | null | Variable<any, string>;
|
|
957
|
+
tags?: string | undefined | null | Variable<any, string>;
|
|
958
|
+
};
|
|
959
|
+
["CloudDocumentUpload"]: AliasType<{
|
|
960
|
+
id?: boolean | `@${string}`;
|
|
961
|
+
putUrl?: boolean | `@${string}`;
|
|
962
|
+
expiresAt?: boolean | `@${string}`;
|
|
963
|
+
__typename?: boolean | `@${string}`;
|
|
964
|
+
['...on CloudDocumentUpload']?: Omit<ValueTypes["CloudDocumentUpload"], "...on CloudDocumentUpload">;
|
|
965
|
+
}>;
|
|
959
966
|
["InferenceStatus"]: InferenceStatus;
|
|
960
967
|
["TokenUsage"]: AliasType<{
|
|
961
968
|
inputTokens?: boolean | `@${string}`;
|
|
@@ -1627,9 +1634,9 @@ export type ValueTypes = {
|
|
|
1627
1634
|
cancelFromTask?: [{
|
|
1628
1635
|
taskId: ValueTypes["ID"] | Variable<any, string>;
|
|
1629
1636
|
}, boolean | `@${string}`];
|
|
1630
|
-
|
|
1631
|
-
input: ValueTypes["
|
|
1632
|
-
}, ValueTypes["
|
|
1637
|
+
requestCloudDocumentUpload?: [{
|
|
1638
|
+
input: ValueTypes["RequestCloudDocumentUploadInput"] | Variable<any, string>;
|
|
1639
|
+
}, ValueTypes["CloudDocumentUpload"]];
|
|
1633
1640
|
updateCloudDocument?: [{
|
|
1634
1641
|
id: ValueTypes["ID"] | Variable<any, string>;
|
|
1635
1642
|
teamId: ValueTypes["ID"] | Variable<any, string>;
|
|
@@ -3767,15 +3774,6 @@ export type ResolverInputTypes = {
|
|
|
3767
3774
|
content?: boolean | `@${string}`;
|
|
3768
3775
|
__typename?: boolean | `@${string}`;
|
|
3769
3776
|
}>;
|
|
3770
|
-
["IngestCloudDocumentInput"]: {
|
|
3771
|
-
teamId: ResolverInputTypes["ID"];
|
|
3772
|
-
projectId: ResolverInputTypes["ID"];
|
|
3773
|
-
name: string;
|
|
3774
|
-
contentType: string;
|
|
3775
|
-
content: string;
|
|
3776
|
-
metadata?: string | undefined | null;
|
|
3777
|
-
tags?: string | undefined | null;
|
|
3778
|
-
};
|
|
3779
3777
|
["UpdateCloudDocumentInput"]: {
|
|
3780
3778
|
name?: string | undefined | null;
|
|
3781
3779
|
contentType?: string | undefined | null;
|
|
@@ -3783,6 +3781,21 @@ export type ResolverInputTypes = {
|
|
|
3783
3781
|
metadata?: string | undefined | null;
|
|
3784
3782
|
tags?: string | undefined | null;
|
|
3785
3783
|
};
|
|
3784
|
+
["RequestCloudDocumentUploadInput"]: {
|
|
3785
|
+
teamId: ResolverInputTypes["ID"];
|
|
3786
|
+
projectId: ResolverInputTypes["ID"];
|
|
3787
|
+
name: string;
|
|
3788
|
+
contentType: string;
|
|
3789
|
+
contentLength?: number | undefined | null;
|
|
3790
|
+
metadata?: string | undefined | null;
|
|
3791
|
+
tags?: string | undefined | null;
|
|
3792
|
+
};
|
|
3793
|
+
["CloudDocumentUpload"]: AliasType<{
|
|
3794
|
+
id?: boolean | `@${string}`;
|
|
3795
|
+
putUrl?: boolean | `@${string}`;
|
|
3796
|
+
expiresAt?: boolean | `@${string}`;
|
|
3797
|
+
__typename?: boolean | `@${string}`;
|
|
3798
|
+
}>;
|
|
3786
3799
|
["InferenceStatus"]: InferenceStatus;
|
|
3787
3800
|
["TokenUsage"]: AliasType<{
|
|
3788
3801
|
inputTokens?: boolean | `@${string}`;
|
|
@@ -4441,9 +4454,9 @@ export type ResolverInputTypes = {
|
|
|
4441
4454
|
cancelFromTask?: [{
|
|
4442
4455
|
taskId: ResolverInputTypes["ID"];
|
|
4443
4456
|
}, boolean | `@${string}`];
|
|
4444
|
-
|
|
4445
|
-
input: ResolverInputTypes["
|
|
4446
|
-
}, ResolverInputTypes["
|
|
4457
|
+
requestCloudDocumentUpload?: [{
|
|
4458
|
+
input: ResolverInputTypes["RequestCloudDocumentUploadInput"];
|
|
4459
|
+
}, ResolverInputTypes["CloudDocumentUpload"]];
|
|
4447
4460
|
updateCloudDocument?: [{
|
|
4448
4461
|
id: ResolverInputTypes["ID"];
|
|
4449
4462
|
teamId: ResolverInputTypes["ID"];
|
|
@@ -6476,21 +6489,26 @@ export type ModelTypes = {
|
|
|
6476
6489
|
score: number;
|
|
6477
6490
|
content: string;
|
|
6478
6491
|
};
|
|
6479
|
-
["
|
|
6492
|
+
["UpdateCloudDocumentInput"]: {
|
|
6493
|
+
name?: string | undefined | null;
|
|
6494
|
+
contentType?: string | undefined | null;
|
|
6495
|
+
content?: string | undefined | null;
|
|
6496
|
+
metadata?: string | undefined | null;
|
|
6497
|
+
tags?: string | undefined | null;
|
|
6498
|
+
};
|
|
6499
|
+
["RequestCloudDocumentUploadInput"]: {
|
|
6480
6500
|
teamId: ModelTypes["ID"];
|
|
6481
6501
|
projectId: ModelTypes["ID"];
|
|
6482
6502
|
name: string;
|
|
6483
6503
|
contentType: string;
|
|
6484
|
-
|
|
6504
|
+
contentLength?: number | undefined | null;
|
|
6485
6505
|
metadata?: string | undefined | null;
|
|
6486
6506
|
tags?: string | undefined | null;
|
|
6487
6507
|
};
|
|
6488
|
-
["
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
metadata?: string | undefined | null;
|
|
6493
|
-
tags?: string | undefined | null;
|
|
6508
|
+
["CloudDocumentUpload"]: {
|
|
6509
|
+
id: ModelTypes["ID"];
|
|
6510
|
+
putUrl: string;
|
|
6511
|
+
expiresAt?: ModelTypes["DateTime"] | undefined | null;
|
|
6494
6512
|
};
|
|
6495
6513
|
["InferenceStatus"]: InferenceStatus;
|
|
6496
6514
|
["TokenUsage"]: {
|
|
@@ -6787,7 +6805,7 @@ export type ModelTypes = {
|
|
|
6787
6805
|
deleteProjectFile: boolean;
|
|
6788
6806
|
generateAexolFromText: ModelTypes["FromTask"];
|
|
6789
6807
|
cancelFromTask: boolean;
|
|
6790
|
-
|
|
6808
|
+
requestCloudDocumentUpload: ModelTypes["CloudDocumentUpload"];
|
|
6791
6809
|
updateCloudDocument: ModelTypes["CloudDocument"];
|
|
6792
6810
|
deleteCloudDocument: boolean;
|
|
6793
6811
|
cleanupOrphanCloudChunks: number;
|
|
@@ -8548,21 +8566,28 @@ export type GraphQLTypes = {
|
|
|
8548
8566
|
content: string;
|
|
8549
8567
|
['...on CloudSearchResult']: Omit<GraphQLTypes["CloudSearchResult"], "...on CloudSearchResult">;
|
|
8550
8568
|
};
|
|
8551
|
-
["
|
|
8569
|
+
["UpdateCloudDocumentInput"]: {
|
|
8570
|
+
name?: string | undefined | null;
|
|
8571
|
+
contentType?: string | undefined | null;
|
|
8572
|
+
content?: string | undefined | null;
|
|
8573
|
+
metadata?: string | undefined | null;
|
|
8574
|
+
tags?: string | undefined | null;
|
|
8575
|
+
};
|
|
8576
|
+
["RequestCloudDocumentUploadInput"]: {
|
|
8552
8577
|
teamId: GraphQLTypes["ID"];
|
|
8553
8578
|
projectId: GraphQLTypes["ID"];
|
|
8554
8579
|
name: string;
|
|
8555
8580
|
contentType: string;
|
|
8556
|
-
|
|
8581
|
+
contentLength?: number | undefined | null;
|
|
8557
8582
|
metadata?: string | undefined | null;
|
|
8558
8583
|
tags?: string | undefined | null;
|
|
8559
8584
|
};
|
|
8560
|
-
["
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
8585
|
+
["CloudDocumentUpload"]: {
|
|
8586
|
+
__typename: "CloudDocumentUpload";
|
|
8587
|
+
id: GraphQLTypes["ID"];
|
|
8588
|
+
putUrl: string;
|
|
8589
|
+
expiresAt?: GraphQLTypes["DateTime"] | undefined | null;
|
|
8590
|
+
['...on CloudDocumentUpload']: Omit<GraphQLTypes["CloudDocumentUpload"], "...on CloudDocumentUpload">;
|
|
8566
8591
|
};
|
|
8567
8592
|
["InferenceStatus"]: InferenceStatus;
|
|
8568
8593
|
["TokenUsage"]: {
|
|
@@ -8886,7 +8911,7 @@ export type GraphQLTypes = {
|
|
|
8886
8911
|
deleteProjectFile: boolean;
|
|
8887
8912
|
generateAexolFromText: GraphQLTypes["FromTask"];
|
|
8888
8913
|
cancelFromTask: boolean;
|
|
8889
|
-
|
|
8914
|
+
requestCloudDocumentUpload: GraphQLTypes["CloudDocumentUpload"];
|
|
8890
8915
|
updateCloudDocument: GraphQLTypes["CloudDocument"];
|
|
8891
8916
|
deleteCloudDocument: boolean;
|
|
8892
8917
|
cleanupOrphanCloudChunks: number;
|
|
@@ -10307,8 +10332,8 @@ type ZEUS_VARIABLES = {
|
|
|
10307
10332
|
["UpdateLeadStatusInput"]: ValueTypes["UpdateLeadStatusInput"];
|
|
10308
10333
|
["CreateLeadInput"]: ValueTypes["CreateLeadInput"];
|
|
10309
10334
|
["UpdateLeadInput"]: ValueTypes["UpdateLeadInput"];
|
|
10310
|
-
["IngestCloudDocumentInput"]: ValueTypes["IngestCloudDocumentInput"];
|
|
10311
10335
|
["UpdateCloudDocumentInput"]: ValueTypes["UpdateCloudDocumentInput"];
|
|
10336
|
+
["RequestCloudDocumentUploadInput"]: ValueTypes["RequestCloudDocumentUploadInput"];
|
|
10312
10337
|
["InferenceStatus"]: ValueTypes["InferenceStatus"];
|
|
10313
10338
|
["RegisterInput"]: ValueTypes["RegisterInput"];
|
|
10314
10339
|
["LoginInput"]: ValueTypes["LoginInput"];
|