zelari-code 2.19.0 → 2.20.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/cli/budget/retrievalPolicy.js +82 -0
- package/dist/cli/budget/retrievalPolicy.js.map +1 -0
- package/dist/cli/hooks/permissionPicker.js +9 -1
- package/dist/cli/hooks/permissionPicker.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +10 -2
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/main.bundled.js +1009 -871
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/provider/capabilities.js +3 -0
- package/dist/cli/provider/capabilities.js.map +1 -1
- package/dist/cli/provider/openai-compatible.js +27 -1
- package/dist/cli/provider/openai-compatible.js.map +1 -1
- package/dist/cli/runHeadless.js +7 -2
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/safety/resourceClaims.js +33 -2
- package/dist/cli/safety/resourceClaims.js.map +1 -1
- package/dist/cli/safety/toolPermissions.js +11 -4
- package/dist/cli/safety/toolPermissions.js.map +1 -1
- package/dist/cli/toolRegistry.js +16 -2
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/skillTool.js +20 -6
- package/dist/cli/tools/skillTool.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -29977,8 +29977,9 @@ var init_service = __esm({
|
|
|
29977
29977
|
const text = (raw.query ?? raw.text ?? "").slice(0, 64e3);
|
|
29978
29978
|
const limit = Math.max(1, Math.min(raw.limit ?? 8, 100));
|
|
29979
29979
|
this.emit({ type: "memory_recall_start" });
|
|
29980
|
+
const { weights, ...recallQuery } = raw;
|
|
29980
29981
|
const candidates = await this.backend.search({
|
|
29981
|
-
...
|
|
29982
|
+
...recallQuery,
|
|
29982
29983
|
text,
|
|
29983
29984
|
projectId: this.projectId,
|
|
29984
29985
|
statuses: raw.statuses ?? (raw.includeHistorical ? void 0 : ["active"]),
|
|
@@ -30025,7 +30026,7 @@ var init_service = __esm({
|
|
|
30025
30026
|
}
|
|
30026
30027
|
}
|
|
30027
30028
|
}
|
|
30028
|
-
const ranked = diverse(rankMemoryCandidates([...byId.values()], text), limit);
|
|
30029
|
+
const ranked = diverse(rankMemoryCandidates([...byId.values()], text, weights ? { weights } : {}), limit);
|
|
30029
30030
|
this.emit({
|
|
30030
30031
|
type: "memory_recall_end",
|
|
30031
30032
|
durationMs: Date.now() - started,
|
|
@@ -40721,25 +40722,883 @@ var init_skillsMd = __esm({
|
|
|
40721
40722
|
}
|
|
40722
40723
|
});
|
|
40723
40724
|
|
|
40725
|
+
// src/cli/budget/historySummary.ts
|
|
40726
|
+
function extractiveHistorySummary(dropped, opts) {
|
|
40727
|
+
const maxChars = opts?.maxChars ?? MAX_SUMMARY_CHARS;
|
|
40728
|
+
if (dropped.length === 0) return "No prior turns.";
|
|
40729
|
+
const userGoals = [];
|
|
40730
|
+
const assistantNotes = [];
|
|
40731
|
+
const userConstraints = [];
|
|
40732
|
+
const unresolved = [];
|
|
40733
|
+
const verification = [];
|
|
40734
|
+
const decisions = [];
|
|
40735
|
+
const tools = /* @__PURE__ */ new Map();
|
|
40736
|
+
const files = /* @__PURE__ */ new Set();
|
|
40737
|
+
let toolResults = 0;
|
|
40738
|
+
for (const m of dropped) {
|
|
40739
|
+
if (m.role === "user" && m.content.trim()) {
|
|
40740
|
+
const goal = oneLine(m.content, 220);
|
|
40741
|
+
userGoals.push(goal);
|
|
40742
|
+
if (/\b(must|never|required|only|do not|constraint|vincolo|deve|senza)\b/i.test(goal)) userConstraints.push(goal);
|
|
40743
|
+
} else if (m.role === "assistant") {
|
|
40744
|
+
if (m.content.trim()) {
|
|
40745
|
+
const note = oneLine(m.content, 220);
|
|
40746
|
+
assistantNotes.push(note);
|
|
40747
|
+
if (/\b(fail|failed|error|unresolved|remaining|todo|blocked|gap|errore|fallit|irrisolt|manca)\b/i.test(note)) unresolved.push(note);
|
|
40748
|
+
if (/\b(test|typecheck|build|verify|verification|passed|failed|green|red)\b/i.test(note)) verification.push(note);
|
|
40749
|
+
if (/\b(decid|decision|chosen|choose|scelt|adopt|implement)\b/i.test(note)) decisions.push(note);
|
|
40750
|
+
}
|
|
40751
|
+
if (m.toolCalls) {
|
|
40752
|
+
for (const tc of m.toolCalls) {
|
|
40753
|
+
tools.set(tc.name, (tools.get(tc.name) ?? 0) + 1);
|
|
40754
|
+
collectPaths3(tc.args, files);
|
|
40755
|
+
}
|
|
40756
|
+
}
|
|
40757
|
+
} else if (m.role === "tool") {
|
|
40758
|
+
toolResults += 1;
|
|
40759
|
+
collectPathsFromText(m.content, files);
|
|
40760
|
+
if (/\b(fail|failed|error|exception|blocked|errore|fallit)\b/i.test(m.content)) unresolved.push(oneLine(m.content, 220));
|
|
40761
|
+
if (/\b(test|typecheck|build|verify|passed|failed|success)\b/i.test(m.content)) verification.push(oneLine(m.content, 220));
|
|
40762
|
+
}
|
|
40763
|
+
}
|
|
40764
|
+
const parts = [
|
|
40765
|
+
"[history-summary] Earlier turns were compacted to stay within the context budget.",
|
|
40766
|
+
`Dropped ${dropped.length} message(s) (${userGoals.length} user, ${assistantNotes.length} assistant notes, ${toolResults} tool results).`
|
|
40767
|
+
];
|
|
40768
|
+
if (userGoals.length) {
|
|
40769
|
+
parts.push("## User goals / requests");
|
|
40770
|
+
for (const g of userGoals.slice(-6)) parts.push(`- ${g}`);
|
|
40771
|
+
}
|
|
40772
|
+
if (userConstraints.length) {
|
|
40773
|
+
parts.push("## User constraints (preserve exactly)");
|
|
40774
|
+
for (const item of [...new Set(userConstraints)].slice(-8)) parts.push(`- ${item}`);
|
|
40775
|
+
}
|
|
40776
|
+
if (unresolved.length) {
|
|
40777
|
+
parts.push("## Unresolved failures / pending repair");
|
|
40778
|
+
for (const item of [...new Set(unresolved)].slice(-8)) parts.push(`- ${item}`);
|
|
40779
|
+
}
|
|
40780
|
+
if (verification.length) {
|
|
40781
|
+
parts.push("## Latest verification state");
|
|
40782
|
+
for (const item of [...new Set(verification)].slice(-6)) parts.push(`- ${item}`);
|
|
40783
|
+
}
|
|
40784
|
+
if (decisions.length) {
|
|
40785
|
+
parts.push("## Recent active decisions");
|
|
40786
|
+
for (const item of [...new Set(decisions)].slice(-6)) parts.push(`- ${item}`);
|
|
40787
|
+
}
|
|
40788
|
+
if (assistantNotes.length) {
|
|
40789
|
+
parts.push("## Assistant conclusions (truncated)");
|
|
40790
|
+
for (const a of assistantNotes.slice(-5)) parts.push(`- ${a}`);
|
|
40791
|
+
}
|
|
40792
|
+
if (tools.size) {
|
|
40793
|
+
const ranked = [...tools.entries()].sort((a, b) => b[1] - a[1]).slice(0, 12).map(([n, c]) => `${n}\xD7${c}`);
|
|
40794
|
+
parts.push(`## Tools used: ${ranked.join(", ")}`);
|
|
40795
|
+
}
|
|
40796
|
+
if (files.size) {
|
|
40797
|
+
const list = [...files].slice(0, 24);
|
|
40798
|
+
parts.push(`## Paths mentioned: ${list.join(", ")}`);
|
|
40799
|
+
}
|
|
40800
|
+
parts.push(
|
|
40801
|
+
"Continue from the recent messages below; do not re-ask goals already answered above unless the user changes them."
|
|
40802
|
+
);
|
|
40803
|
+
let out = parts.join("\n");
|
|
40804
|
+
if (out.length > maxChars) {
|
|
40805
|
+
out = `${out.slice(0, maxChars - 1)}\u2026`;
|
|
40806
|
+
}
|
|
40807
|
+
return out;
|
|
40808
|
+
}
|
|
40809
|
+
function oneLine(s, max) {
|
|
40810
|
+
const t = s.replace(/\s+/g, " ").trim();
|
|
40811
|
+
if (t.length <= max) return t;
|
|
40812
|
+
return `${t.slice(0, max - 1)}\u2026`;
|
|
40813
|
+
}
|
|
40814
|
+
function collectPaths3(args, out) {
|
|
40815
|
+
if (!args || typeof args !== "object") return;
|
|
40816
|
+
const obj = args;
|
|
40817
|
+
for (const key of ["path", "file", "filepath", "filePath", "target", "cwd"]) {
|
|
40818
|
+
const v = obj[key];
|
|
40819
|
+
if (typeof v === "string" && v.length > 1 && v.length < 260) {
|
|
40820
|
+
out.add(v.replace(/\\/g, "/"));
|
|
40821
|
+
}
|
|
40822
|
+
}
|
|
40823
|
+
if (typeof obj.file_path === "string") out.add(String(obj.file_path));
|
|
40824
|
+
}
|
|
40825
|
+
function collectPathsFromText(text, out) {
|
|
40826
|
+
const re = /(?:^|[\s"'`])((?:[\w.-]+\/)+[\w.-]+\.\w{1,8})/g;
|
|
40827
|
+
let m;
|
|
40828
|
+
let n = 0;
|
|
40829
|
+
while ((m = re.exec(text)) !== null && n < 8) {
|
|
40830
|
+
out.add(m[1]);
|
|
40831
|
+
n += 1;
|
|
40832
|
+
}
|
|
40833
|
+
}
|
|
40834
|
+
var MAX_SUMMARY_CHARS;
|
|
40835
|
+
var init_historySummary = __esm({
|
|
40836
|
+
"src/cli/budget/historySummary.ts"() {
|
|
40837
|
+
"use strict";
|
|
40838
|
+
MAX_SUMMARY_CHARS = 3500;
|
|
40839
|
+
}
|
|
40840
|
+
});
|
|
40841
|
+
|
|
40842
|
+
// src/cli/budget/llmCompact.ts
|
|
40843
|
+
function isLlmCompactEnabled() {
|
|
40844
|
+
const v = process.env.ZELARI_LLM_COMPACT?.trim().toLowerCase();
|
|
40845
|
+
if (v === "0" || v === "false" || v === "off" || v === "no") return false;
|
|
40846
|
+
return true;
|
|
40847
|
+
}
|
|
40848
|
+
function compactModelOverride() {
|
|
40849
|
+
const v = process.env.ZELARI_COMPACT_MODEL?.trim();
|
|
40850
|
+
return v ? v : void 0;
|
|
40851
|
+
}
|
|
40852
|
+
async function llmSummarizeHistoryReplay(input) {
|
|
40853
|
+
const override = input.overrideModel ?? compactModelOverride();
|
|
40854
|
+
const model = override ?? input.model;
|
|
40855
|
+
const cacheReuseExpected = !override;
|
|
40856
|
+
if (!isLlmCompactEnabled()) return { summary: null, model, cacheReuseExpected };
|
|
40857
|
+
if (input.droppedMessages.length === 0) {
|
|
40858
|
+
return { summary: null, model, cacheReuseExpected };
|
|
40859
|
+
}
|
|
40860
|
+
const messages = [
|
|
40861
|
+
...input.systemMessages,
|
|
40862
|
+
...input.droppedMessages,
|
|
40863
|
+
{
|
|
40864
|
+
role: "user",
|
|
40865
|
+
content: COMPACTION_INSTRUCTION
|
|
40866
|
+
}
|
|
40867
|
+
];
|
|
40868
|
+
const controller = new AbortController();
|
|
40869
|
+
const timeout = setTimeout(() => controller.abort(), REPLAY_TIMEOUT_MS);
|
|
40870
|
+
const onOuterAbort = () => controller.abort();
|
|
40871
|
+
input.signal?.addEventListener("abort", onOuterAbort, { once: true });
|
|
40872
|
+
try {
|
|
40873
|
+
let text = "";
|
|
40874
|
+
let emittedToolCall = false;
|
|
40875
|
+
for await (const delta of input.providerStream({
|
|
40876
|
+
provider: input.provider,
|
|
40877
|
+
model,
|
|
40878
|
+
messages,
|
|
40879
|
+
// Tools stay advertised: dropping them would change the prefix token
|
|
40880
|
+
// sequence and destroy cache reuse (explicit DSH decision). They are
|
|
40881
|
+
// sorted canonically (same discipline as the live routed request and
|
|
40882
|
+
// the snapshot fingerprints) so the replay prefix is byte-identical.
|
|
40883
|
+
tools: [...input.tools].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0),
|
|
40884
|
+
signal: controller.signal,
|
|
40885
|
+
generation: {
|
|
40886
|
+
purpose: "compaction",
|
|
40887
|
+
temperature: 0.1,
|
|
40888
|
+
maxTokens: 900
|
|
40889
|
+
}
|
|
40890
|
+
})) {
|
|
40891
|
+
if (delta.kind === "text") text += delta.delta;
|
|
40892
|
+
if (delta.kind === "tool_call") emittedToolCall = true;
|
|
40893
|
+
}
|
|
40894
|
+
if (emittedToolCall) return { summary: null, model, cacheReuseExpected };
|
|
40895
|
+
if (!text.trim()) return { summary: null, model, cacheReuseExpected };
|
|
40896
|
+
return { summary: text.trim(), model, cacheReuseExpected };
|
|
40897
|
+
} catch {
|
|
40898
|
+
return { summary: null, model, cacheReuseExpected };
|
|
40899
|
+
} finally {
|
|
40900
|
+
clearTimeout(timeout);
|
|
40901
|
+
input.signal?.removeEventListener("abort", onOuterAbort);
|
|
40902
|
+
}
|
|
40903
|
+
}
|
|
40904
|
+
var COMPACTION_INSTRUCTION, REPLAY_TIMEOUT_MS;
|
|
40905
|
+
var init_llmCompact = __esm({
|
|
40906
|
+
"src/cli/budget/llmCompact.ts"() {
|
|
40907
|
+
"use strict";
|
|
40908
|
+
COMPACTION_INSTRUCTION = `
|
|
40909
|
+
You are now acting as a compaction engine for this coding-agent session.
|
|
40910
|
+
|
|
40911
|
+
Condense the conversation ABOVE into a compact checkpoint sufficient to continue the task.
|
|
40912
|
+
|
|
40913
|
+
Preserve:
|
|
40914
|
+
- user's goal and evolving intent
|
|
40915
|
+
- decisions already made
|
|
40916
|
+
- exact file paths and identifiers
|
|
40917
|
+
- code changes already completed
|
|
40918
|
+
- commands/errors that still matter
|
|
40919
|
+
- constraints
|
|
40920
|
+
- unfinished work
|
|
40921
|
+
- the single most likely next action
|
|
40922
|
+
|
|
40923
|
+
Do not call tools.
|
|
40924
|
+
Do not mention this summarization request.
|
|
40925
|
+
Output only the checkpoint.
|
|
40926
|
+
Be concise.
|
|
40927
|
+
`.trim();
|
|
40928
|
+
REPLAY_TIMEOUT_MS = 6e4;
|
|
40929
|
+
}
|
|
40930
|
+
});
|
|
40931
|
+
|
|
40932
|
+
// src/cli/hooks/historyCompaction.ts
|
|
40933
|
+
function compactedRangeFromDropped(dropped) {
|
|
40934
|
+
if (dropped.length === 0) return void 0;
|
|
40935
|
+
const seqs = [];
|
|
40936
|
+
const sources = [];
|
|
40937
|
+
for (const m of dropped) {
|
|
40938
|
+
const hasCompactRange = typeof m.compactedFromSeq === "number" && Number.isInteger(m.compactedFromSeq) && m.compactedFromSeq > 0 && typeof m.compactedToSeq === "number" && Number.isInteger(m.compactedToSeq) && m.compactedToSeq >= m.compactedFromSeq;
|
|
40939
|
+
if (hasCompactRange) {
|
|
40940
|
+
seqs.push(m.compactedFromSeq, m.compactedToSeq);
|
|
40941
|
+
sources.push(...m.sourceEventSeqs ?? []);
|
|
40942
|
+
if (typeof m.seq === "number" && Number.isInteger(m.seq) && m.seq > 0) {
|
|
40943
|
+
seqs.push(m.seq);
|
|
40944
|
+
sources.push(m.seq);
|
|
40945
|
+
}
|
|
40946
|
+
continue;
|
|
40947
|
+
}
|
|
40948
|
+
if (typeof m.seq !== "number" || !Number.isInteger(m.seq) || m.seq < 1) return void 0;
|
|
40949
|
+
seqs.push(m.seq);
|
|
40950
|
+
sources.push(m.seq);
|
|
40951
|
+
}
|
|
40952
|
+
return {
|
|
40953
|
+
fromSeq: Math.min(...seqs),
|
|
40954
|
+
toSeq: Math.max(...seqs),
|
|
40955
|
+
sourceEventSeqs: [...new Set(sources)]
|
|
40956
|
+
};
|
|
40957
|
+
}
|
|
40958
|
+
function withDroppedRange(result, dropped, strategy) {
|
|
40959
|
+
const range = compactedRangeFromDropped(dropped);
|
|
40960
|
+
if (!range) return { ...result, strategy };
|
|
40961
|
+
return { ...result, ...range, strategy };
|
|
40962
|
+
}
|
|
40963
|
+
function resolveMaxMessages(opts) {
|
|
40964
|
+
const envTurns = envNumber(process.env.ZELARI_HISTORY_TURNS, { default: 6, min: 0 });
|
|
40965
|
+
let turns = opts?.maxMessages ? Math.ceil(opts.maxMessages / 4) : envTurns;
|
|
40966
|
+
if (opts?.durableStatePresent && !opts?.maxMessages && process.env.ZELARI_HISTORY_TURNS === void 0) {
|
|
40967
|
+
turns = Math.min(turns, 3);
|
|
40968
|
+
}
|
|
40969
|
+
if (turns <= 0) return 0;
|
|
40970
|
+
if (opts?.force && opts?.maxMessages) return Math.max(1, opts.maxMessages);
|
|
40971
|
+
return turns * 4;
|
|
40972
|
+
}
|
|
40973
|
+
function findValidCutIndex(messages, naiveCut) {
|
|
40974
|
+
let cut = naiveCut;
|
|
40975
|
+
while (cut < messages.length) {
|
|
40976
|
+
const kept = messages.slice(cut);
|
|
40977
|
+
const declared = /* @__PURE__ */ new Set();
|
|
40978
|
+
for (const m of kept) {
|
|
40979
|
+
if (m.role === "assistant" && m.toolCalls) {
|
|
40980
|
+
for (const tc of m.toolCalls) declared.add(tc.id);
|
|
40981
|
+
}
|
|
40982
|
+
}
|
|
40983
|
+
let moved = false;
|
|
40984
|
+
for (let k = 0; k < kept.length; k++) {
|
|
40985
|
+
const m = kept[k];
|
|
40986
|
+
if (m.role === "tool" && m.toolCallId && !declared.has(m.toolCallId)) {
|
|
40987
|
+
for (let j = cut - 1; j >= 0; j--) {
|
|
40988
|
+
const prev2 = messages[j];
|
|
40989
|
+
if (prev2.role === "assistant" && prev2.toolCalls && prev2.toolCalls.some((tc) => tc.id === m.toolCallId)) {
|
|
40990
|
+
cut = j;
|
|
40991
|
+
moved = true;
|
|
40992
|
+
break;
|
|
40993
|
+
}
|
|
40994
|
+
}
|
|
40995
|
+
break;
|
|
40996
|
+
}
|
|
40997
|
+
}
|
|
40998
|
+
if (!moved) break;
|
|
40999
|
+
}
|
|
41000
|
+
return cut;
|
|
41001
|
+
}
|
|
41002
|
+
function resolvePruneLimits(opts) {
|
|
41003
|
+
const maxChars = opts?.maxChars ?? envNumber(process.env.ZELARI_TOOL_RESULT_MAX_CHARS, { default: 8e3, min: 256 });
|
|
41004
|
+
const rawTail = opts?.tailChars ?? envNumber(process.env.ZELARI_TOOL_RESULT_TAIL_CHARS, { default: 1e3, min: 0 });
|
|
41005
|
+
const tailChars = Math.min(rawTail, maxChars);
|
|
41006
|
+
return { maxChars, tailChars };
|
|
41007
|
+
}
|
|
41008
|
+
function pruneToolResultsDetailed(messages, opts) {
|
|
41009
|
+
const { maxChars, tailChars } = resolvePruneLimits(opts);
|
|
41010
|
+
const headChars = maxChars - tailChars;
|
|
41011
|
+
const stats = { pruned: 0, charsOmitted: 0 };
|
|
41012
|
+
let changed = false;
|
|
41013
|
+
const out = messages.map((m) => {
|
|
41014
|
+
if (m.role !== "tool") return m;
|
|
41015
|
+
const body = m.content ?? "";
|
|
41016
|
+
if (body.length <= maxChars) return m;
|
|
41017
|
+
const head = headChars > 0 ? body.slice(0, headChars) : "";
|
|
41018
|
+
const tail2 = tailChars > 0 ? body.slice(-tailChars) : "";
|
|
41019
|
+
const omitted = body.length - head.length - tail2.length;
|
|
41020
|
+
changed = true;
|
|
41021
|
+
stats.pruned += 1;
|
|
41022
|
+
stats.charsOmitted += omitted;
|
|
41023
|
+
return {
|
|
41024
|
+
...m,
|
|
41025
|
+
content: [head, "\u2026[pruned " + omitted + " chars]\u2026", tail2].join(String.fromCharCode(10))
|
|
41026
|
+
};
|
|
41027
|
+
});
|
|
41028
|
+
return {
|
|
41029
|
+
messages: changed ? out : messages,
|
|
41030
|
+
stats
|
|
41031
|
+
};
|
|
41032
|
+
}
|
|
41033
|
+
function compactHistory(messages, opts) {
|
|
41034
|
+
return compactHistoryDetailed(messages, opts).messages;
|
|
41035
|
+
}
|
|
41036
|
+
function buildCheckpointMessage(summaryText, range) {
|
|
41037
|
+
return {
|
|
41038
|
+
role: "user",
|
|
41039
|
+
content: CHECKPOINT_WRAPPER_PREFIX + "\n\n<compacted-summary>\n" + summaryText + "\n</compacted-summary>",
|
|
41040
|
+
...range ? {
|
|
41041
|
+
compactedFromSeq: range.fromSeq,
|
|
41042
|
+
compactedToSeq: range.toSeq,
|
|
41043
|
+
sourceEventSeqs: [...range.sourceEventSeqs]
|
|
41044
|
+
} : {}
|
|
41045
|
+
};
|
|
41046
|
+
}
|
|
41047
|
+
function compactHistoryDetailed(messages, opts) {
|
|
41048
|
+
const maxMessages = resolveMaxMessages(opts);
|
|
41049
|
+
if (maxMessages === 0) {
|
|
41050
|
+
return withDroppedRange(
|
|
41051
|
+
{ messages: [], compacted: true, messagesRemoved: messages.length, summary: "" },
|
|
41052
|
+
messages,
|
|
41053
|
+
"extractive"
|
|
41054
|
+
);
|
|
41055
|
+
}
|
|
41056
|
+
if (messages.length <= maxMessages * 2 && !opts?.force) {
|
|
41057
|
+
return {
|
|
41058
|
+
messages,
|
|
41059
|
+
compacted: false,
|
|
41060
|
+
messagesRemoved: 0,
|
|
41061
|
+
summary: ""
|
|
41062
|
+
};
|
|
41063
|
+
}
|
|
41064
|
+
const naiveCut = Math.max(0, messages.length - maxMessages);
|
|
41065
|
+
const cut = findValidCutIndex(messages, naiveCut);
|
|
41066
|
+
if (cut === 0) {
|
|
41067
|
+
return {
|
|
41068
|
+
messages,
|
|
41069
|
+
compacted: false,
|
|
41070
|
+
messagesRemoved: 0,
|
|
41071
|
+
summary: ""
|
|
41072
|
+
};
|
|
41073
|
+
}
|
|
41074
|
+
const droppedMsgs = messages.slice(0, cut);
|
|
41075
|
+
const droppedRange = compactedRangeFromDropped(droppedMsgs);
|
|
41076
|
+
const pruned = pruneToolResultsDetailed(messages.slice(cut));
|
|
41077
|
+
const kept = pruned.messages;
|
|
41078
|
+
const summaryText = extractiveHistorySummary(droppedMsgs);
|
|
41079
|
+
const summary = buildCheckpointMessage(
|
|
41080
|
+
summaryText || `${COMPACT_MARKER} ${cut} earlier message(s) dropped.`,
|
|
41081
|
+
droppedRange
|
|
41082
|
+
);
|
|
41083
|
+
return withDroppedRange(
|
|
41084
|
+
{
|
|
41085
|
+
messages: [summary, ...kept],
|
|
41086
|
+
compacted: true,
|
|
41087
|
+
messagesRemoved: cut,
|
|
41088
|
+
summary: summary.content,
|
|
41089
|
+
prunedToolResults: pruned.stats.pruned
|
|
41090
|
+
},
|
|
41091
|
+
droppedMsgs,
|
|
41092
|
+
"extractive"
|
|
41093
|
+
);
|
|
41094
|
+
}
|
|
41095
|
+
async function compactHistoryAsync(messages, opts) {
|
|
41096
|
+
const base2 = compactHistoryDetailed(messages, opts);
|
|
41097
|
+
if (!base2.compacted || base2.messagesRemoved === 0) return base2;
|
|
41098
|
+
const cut = base2.messagesRemoved;
|
|
41099
|
+
const droppedMsgs = messages.slice(0, cut);
|
|
41100
|
+
const extractive = extractiveHistorySummary(droppedMsgs);
|
|
41101
|
+
let summaryText = extractive;
|
|
41102
|
+
let cacheReuseExpected;
|
|
41103
|
+
let replayExactPrefix;
|
|
41104
|
+
const canReplay = !!(opts?.providerStream && opts?.requestSnapshot);
|
|
41105
|
+
if (canReplay) {
|
|
41106
|
+
try {
|
|
41107
|
+
const replay = await llmSummarizeHistoryReplay({
|
|
41108
|
+
providerStream: opts.providerStream,
|
|
41109
|
+
provider: opts.requestSnapshot.provider,
|
|
41110
|
+
model: opts.requestSnapshot.model,
|
|
41111
|
+
systemMessages: opts.requestSnapshot.systemMessages,
|
|
41112
|
+
tools: opts.requestSnapshot.tools,
|
|
41113
|
+
droppedMessages: droppedMsgs,
|
|
41114
|
+
signal: opts?.signal
|
|
41115
|
+
});
|
|
41116
|
+
cacheReuseExpected = replay.cacheReuseExpected;
|
|
41117
|
+
if (replay.summary && replay.summary.trim().length > 40) {
|
|
41118
|
+
const sourceTokens = roughTokens(droppedMsgs);
|
|
41119
|
+
const summaryTok = Math.ceil(replay.summary.length / 4);
|
|
41120
|
+
if (summaryTok < sourceTokens) {
|
|
41121
|
+
summaryText = replay.summary.trim();
|
|
41122
|
+
}
|
|
41123
|
+
}
|
|
41124
|
+
} catch {
|
|
41125
|
+
}
|
|
41126
|
+
}
|
|
41127
|
+
const pruned = pruneToolResultsDetailed(messages.slice(cut));
|
|
41128
|
+
const kept = pruned.messages;
|
|
41129
|
+
const summary = buildCheckpointMessage(summaryText, compactedRangeFromDropped(droppedMsgs));
|
|
41130
|
+
const usedLlm = summaryText !== extractive && summaryText.trim().length > 40;
|
|
41131
|
+
return withDroppedRange(
|
|
41132
|
+
{
|
|
41133
|
+
messages: [summary, ...kept],
|
|
41134
|
+
compacted: true,
|
|
41135
|
+
messagesRemoved: cut,
|
|
41136
|
+
summary: summaryText,
|
|
41137
|
+
prunedToolResults: pruned.stats.pruned,
|
|
41138
|
+
cacheReuseExpected,
|
|
41139
|
+
replayExactPrefix
|
|
41140
|
+
},
|
|
41141
|
+
droppedMsgs,
|
|
41142
|
+
usedLlm ? "llm" : "extractive"
|
|
41143
|
+
);
|
|
41144
|
+
}
|
|
41145
|
+
function roughTokens(msgs) {
|
|
41146
|
+
let n = 0;
|
|
41147
|
+
for (const m of msgs) {
|
|
41148
|
+
n += Math.ceil((m.content ?? "").length / 4);
|
|
41149
|
+
if (m.toolCalls) {
|
|
41150
|
+
for (const tc of m.toolCalls) {
|
|
41151
|
+
n += Math.ceil(JSON.stringify(tc.args ?? {}).length / 4);
|
|
41152
|
+
}
|
|
41153
|
+
}
|
|
41154
|
+
}
|
|
41155
|
+
return Math.max(1, n);
|
|
41156
|
+
}
|
|
41157
|
+
var COMPACT_MARKER, CHECKPOINT_WRAPPER_PREFIX;
|
|
41158
|
+
var init_historyCompaction = __esm({
|
|
41159
|
+
"src/cli/hooks/historyCompaction.ts"() {
|
|
41160
|
+
"use strict";
|
|
41161
|
+
init_historySummary();
|
|
41162
|
+
init_llmCompact();
|
|
41163
|
+
init_envNumber();
|
|
41164
|
+
COMPACT_MARKER = "[history] Earlier turns were compacted to stay within the context budget.";
|
|
41165
|
+
CHECKPOINT_WRAPPER_PREFIX = "This is an automatically generated checkpoint of earlier conversation. Treat it as established context and continue directly.";
|
|
41166
|
+
}
|
|
41167
|
+
});
|
|
41168
|
+
|
|
41169
|
+
// src/cli/provider/capabilities.ts
|
|
41170
|
+
function frozenProfile(input) {
|
|
41171
|
+
if (input.reasoning.levels) Object.freeze(input.reasoning.levels);
|
|
41172
|
+
Object.freeze(input.reasoning);
|
|
41173
|
+
Object.freeze(input.promptCache);
|
|
41174
|
+
Object.freeze(input.toolCalling);
|
|
41175
|
+
Object.freeze(input.buildRecovery);
|
|
41176
|
+
Object.freeze(input.sampling);
|
|
41177
|
+
Object.freeze(input.compaction);
|
|
41178
|
+
return Object.freeze(input);
|
|
41179
|
+
}
|
|
41180
|
+
function resolveHarnessProfile(model, providerId) {
|
|
41181
|
+
const provider = providerId?.trim().toLowerCase();
|
|
41182
|
+
if (provider === "deepseek") return "deepseek-v4";
|
|
41183
|
+
if (provider === "grok") return "grok";
|
|
41184
|
+
if (provider === "minimax") return "minimax";
|
|
41185
|
+
if (provider === "glm") return "glm";
|
|
41186
|
+
if (model && DEEPSEEK_RE.test(model)) return "deepseek-v4";
|
|
41187
|
+
if (model && GROK_RE.test(model)) return "grok";
|
|
41188
|
+
if (model && MINIMAX_RE.test(model)) return "minimax";
|
|
41189
|
+
if (model && GLM_RE.test(model)) return "glm";
|
|
41190
|
+
return "default";
|
|
41191
|
+
}
|
|
41192
|
+
function capabilitiesFor(model, providerId) {
|
|
41193
|
+
switch (resolveHarnessProfile(model, providerId)) {
|
|
41194
|
+
case "deepseek-v4":
|
|
41195
|
+
return DEEPSEEK_V4_CAPS;
|
|
41196
|
+
case "grok":
|
|
41197
|
+
return GROK_CAPS;
|
|
41198
|
+
case "minimax":
|
|
41199
|
+
return model && MINIMAX_M3_RE.test(model) ? MINIMAX_M3_CAPS : MINIMAX_M2_CAPS;
|
|
41200
|
+
case "glm":
|
|
41201
|
+
return GLM_CAPS;
|
|
41202
|
+
default:
|
|
41203
|
+
return DEFAULT_CAPS;
|
|
41204
|
+
}
|
|
41205
|
+
}
|
|
41206
|
+
var SHARED_COMPACTION, DEFAULT_CAPS, DEEPSEEK_V4_CAPS, GROK_CAPS, MINIMAX_M3_CAPS, MINIMAX_M2_CAPS, GLM_CAPS, DEEPSEEK_RE, GROK_RE, MINIMAX_RE, MINIMAX_M3_RE, GLM_RE;
|
|
41207
|
+
var init_capabilities = __esm({
|
|
41208
|
+
"src/cli/provider/capabilities.ts"() {
|
|
41209
|
+
"use strict";
|
|
41210
|
+
SHARED_COMPACTION = { warnAt: 0.7, compactAt: 0.85, hardAt: 0.95 };
|
|
41211
|
+
DEFAULT_CAPS = frozenProfile({
|
|
41212
|
+
contextWindow: 4e5,
|
|
41213
|
+
reasoning: { supported: true, levels: ["low", "medium", "high"], replayReasoning: true },
|
|
41214
|
+
promptCache: { supported: true, pricedCacheRead: false },
|
|
41215
|
+
toolCalling: { parallel: true },
|
|
41216
|
+
buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
|
|
41217
|
+
sampling: { temperature: 0.7 },
|
|
41218
|
+
compaction: { ...SHARED_COMPACTION },
|
|
41219
|
+
profile: "default"
|
|
41220
|
+
});
|
|
41221
|
+
DEEPSEEK_V4_CAPS = frozenProfile({
|
|
41222
|
+
contextWindow: 1e6,
|
|
41223
|
+
reasoning: { supported: true, levels: ["high", "max"], replayReasoning: true },
|
|
41224
|
+
promptCache: { supported: true, pricedCacheRead: true },
|
|
41225
|
+
toolCalling: { parallel: true },
|
|
41226
|
+
buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
|
|
41227
|
+
sampling: { temperature: 0.7 },
|
|
41228
|
+
compaction: { ...SHARED_COMPACTION },
|
|
41229
|
+
profile: "deepseek-v4"
|
|
41230
|
+
});
|
|
41231
|
+
GROK_CAPS = frozenProfile({
|
|
41232
|
+
contextWindow: 5e5,
|
|
41233
|
+
// grok-4.x truncation fix: explicit conversation ceiling (see interface
|
|
41234
|
+
// doc). Override at runtime via ZELARI_MAX_OUTPUT_TOKENS.
|
|
41235
|
+
maxOutputTokens: 32768,
|
|
41236
|
+
reasoning: {
|
|
41237
|
+
supported: true,
|
|
41238
|
+
levels: ["low", "medium", "high", "xhigh"],
|
|
41239
|
+
replayReasoning: false
|
|
41240
|
+
},
|
|
41241
|
+
promptCache: {
|
|
41242
|
+
supported: true,
|
|
41243
|
+
pricedCacheRead: true,
|
|
41244
|
+
conversationAffinityHeader: "x-grok-conv-id"
|
|
41245
|
+
},
|
|
41246
|
+
toolCalling: { parallel: true },
|
|
41247
|
+
buildRecovery: { forceToolChoice: true, maxForcedTurns: 1 },
|
|
41248
|
+
sampling: { temperature: 0.7 },
|
|
41249
|
+
compaction: { ...SHARED_COMPACTION },
|
|
41250
|
+
profile: "grok"
|
|
41251
|
+
});
|
|
41252
|
+
MINIMAX_M3_CAPS = frozenProfile({
|
|
41253
|
+
contextWindow: 1e6,
|
|
41254
|
+
reasoning: { supported: true, replayReasoning: true },
|
|
41255
|
+
promptCache: { supported: false, pricedCacheRead: false },
|
|
41256
|
+
toolCalling: { parallel: true },
|
|
41257
|
+
buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
|
|
41258
|
+
sampling: { temperature: 0.7 },
|
|
41259
|
+
compaction: { ...SHARED_COMPACTION },
|
|
41260
|
+
profile: "minimax"
|
|
41261
|
+
});
|
|
41262
|
+
MINIMAX_M2_CAPS = frozenProfile({
|
|
41263
|
+
contextWindow: 204800,
|
|
41264
|
+
reasoning: { supported: true, replayReasoning: true },
|
|
41265
|
+
promptCache: { supported: false, pricedCacheRead: false },
|
|
41266
|
+
toolCalling: { parallel: true },
|
|
41267
|
+
buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
|
|
41268
|
+
sampling: { temperature: 0.7 },
|
|
41269
|
+
compaction: { ...SHARED_COMPACTION },
|
|
41270
|
+
profile: "minimax"
|
|
41271
|
+
});
|
|
41272
|
+
GLM_CAPS = frozenProfile({
|
|
41273
|
+
contextWindow: 2e5,
|
|
41274
|
+
reasoning: { supported: true, replayReasoning: true },
|
|
41275
|
+
promptCache: { supported: true, pricedCacheRead: false },
|
|
41276
|
+
toolCalling: { parallel: true },
|
|
41277
|
+
buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
|
|
41278
|
+
sampling: { temperature: 0.7 },
|
|
41279
|
+
compaction: { ...SHARED_COMPACTION },
|
|
41280
|
+
profile: "glm"
|
|
41281
|
+
});
|
|
41282
|
+
DEEPSEEK_RE = /^deepseek-(?:v4(?:\.|-|$)|chat$|reasoner$)/i;
|
|
41283
|
+
GROK_RE = /^grok(?:\.|-|$)/i;
|
|
41284
|
+
MINIMAX_RE = /^minimax(?:\.|-|$)/i;
|
|
41285
|
+
MINIMAX_M3_RE = /^minimax-m3(?:\.|-|$)/i;
|
|
41286
|
+
GLM_RE = /^glm(?:\.|-|$)/i;
|
|
41287
|
+
}
|
|
41288
|
+
});
|
|
41289
|
+
|
|
41290
|
+
// src/cli/budget/tokenBudget.ts
|
|
41291
|
+
function mergeCompactRange(into, r) {
|
|
41292
|
+
if (r.fromSeq !== void 0 && r.toSeq !== void 0) {
|
|
41293
|
+
into.fromSeq = into.fromSeq === void 0 ? r.fromSeq : Math.min(into.fromSeq, r.fromSeq);
|
|
41294
|
+
into.toSeq = into.toSeq === void 0 ? r.toSeq : Math.max(into.toSeq, r.toSeq);
|
|
41295
|
+
if (r.sourceEventSeqs) into.sourceSeqs.push(...r.sourceEventSeqs);
|
|
41296
|
+
}
|
|
41297
|
+
if (r.strategy === "llm") into.strategy = "llm";
|
|
41298
|
+
else if (r.strategy && !into.strategy) into.strategy = r.strategy;
|
|
41299
|
+
}
|
|
41300
|
+
function estimateTokens2(text) {
|
|
41301
|
+
if (!text) return 0;
|
|
41302
|
+
return Math.max(1, Math.ceil(text.length / 4));
|
|
41303
|
+
}
|
|
41304
|
+
function estimateHistoryTokens(messages) {
|
|
41305
|
+
let n = 0;
|
|
41306
|
+
for (const m of messages) {
|
|
41307
|
+
n += estimateTokens2(m.content);
|
|
41308
|
+
if (m.toolCalls) {
|
|
41309
|
+
for (const tc of m.toolCalls) {
|
|
41310
|
+
n += estimateTokens2(tc.name) + estimateTokens2(JSON.stringify(tc.args ?? {}));
|
|
41311
|
+
}
|
|
41312
|
+
}
|
|
41313
|
+
}
|
|
41314
|
+
return n;
|
|
41315
|
+
}
|
|
41316
|
+
function defaultContextLimitForModel(model, provider) {
|
|
41317
|
+
return capabilitiesFor(model, provider).contextWindow;
|
|
41318
|
+
}
|
|
41319
|
+
function resolveContextLimit(model, provider) {
|
|
41320
|
+
return envNumber(process.env.ZELARI_CONTEXT_LIMIT, {
|
|
41321
|
+
default: defaultContextLimitForModel(model, provider),
|
|
41322
|
+
min: 4e3,
|
|
41323
|
+
max: 2e6
|
|
41324
|
+
});
|
|
41325
|
+
}
|
|
41326
|
+
function phaseKnobs(phase2) {
|
|
41327
|
+
return {
|
|
41328
|
+
historyTurns: phase2 === "plan" ? envNumber(process.env.ZELARI_HISTORY_TURNS, { default: 8, min: 0 }) : envNumber(process.env.ZELARI_HISTORY_TURNS, { default: 6, min: 0 }),
|
|
41329
|
+
maxToolLoopIterations: phase2 === "plan" ? envNumber(process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS, { default: 60, min: 1 }) : envNumber(process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS, {
|
|
41330
|
+
default: 120,
|
|
41331
|
+
min: 1
|
|
41332
|
+
})
|
|
41333
|
+
};
|
|
41334
|
+
}
|
|
41335
|
+
async function applyBudgetPolicyAsync(history2, phase2, opts) {
|
|
41336
|
+
const contextLimit = resolveContextLimit(opts?.model, opts?.provider);
|
|
41337
|
+
const compact3 = capabilitiesFor(opts?.model, opts?.provider).compaction;
|
|
41338
|
+
const sessionExtra = opts?.sessionTokens ?? 0;
|
|
41339
|
+
const warnings = [];
|
|
41340
|
+
let { historyTurns, maxToolLoopIterations } = phaseKnobs(phase2);
|
|
41341
|
+
const envelope = opts?.requestSnapshot ?? null;
|
|
41342
|
+
const surface = envelope?.snapshot ?? opts?.requestSurface ?? null;
|
|
41343
|
+
const replayBase = surface ? {
|
|
41344
|
+
provider: surface.provider,
|
|
41345
|
+
model: surface.model,
|
|
41346
|
+
systemMessages: surface.systemMessages,
|
|
41347
|
+
tools: surface.tools
|
|
41348
|
+
} : opts?.providerStream ? { provider: "local", model: opts?.model ?? "unknown", systemMessages: [], tools: [] } : null;
|
|
41349
|
+
const headerTokens = surface ? estimateSystemTokensLite(surface.systemMessages) + estimateToolSchemaTokensLite(surface.tools) : 0;
|
|
41350
|
+
const convTokensOf = (h) => estimateConversationTokensLite(h);
|
|
41351
|
+
let hist = history2;
|
|
41352
|
+
let estimated = surface ? headerTokens + convTokensOf(hist) + RESERVED_OUTPUT_TOKENS : estimateHistoryTokens(hist) + sessionExtra;
|
|
41353
|
+
let occupancy = Math.min(1, estimated / contextLimit);
|
|
41354
|
+
let compactSummary = "";
|
|
41355
|
+
let messagesRemoved = 0;
|
|
41356
|
+
let cacheReuseExpected;
|
|
41357
|
+
let prunedTotal = 0;
|
|
41358
|
+
const compactRange = { sourceSeqs: [] };
|
|
41359
|
+
if (occupancy >= compact3.warnAt && occupancy < compact3.compactAt) {
|
|
41360
|
+
warnings.push(
|
|
41361
|
+
`[budget] context ~${Math.round(occupancy * 100)}% full (${estimated}/${contextLimit} tok full-request est.) \u2014 consider /compact or shorter replies.`
|
|
41362
|
+
);
|
|
41363
|
+
}
|
|
41364
|
+
if (occupancy >= 0.8) {
|
|
41365
|
+
const pruned = pruneToolResultsDetailed(hist);
|
|
41366
|
+
if (pruned.stats.pruned > 0) {
|
|
41367
|
+
hist = pruned.messages;
|
|
41368
|
+
prunedTotal += pruned.stats.pruned;
|
|
41369
|
+
estimated = surface ? headerTokens + convTokensOf(hist) + RESERVED_OUTPUT_TOKENS : estimateHistoryTokens(hist) + sessionExtra;
|
|
41370
|
+
occupancy = Math.min(1, estimated / contextLimit);
|
|
41371
|
+
warnings.push(
|
|
41372
|
+
`[budget] pruned ${pruned.stats.pruned} oversized tool result(s) \u2192 ${Math.round(occupancy * 100)}% (${estimated} tok).`
|
|
41373
|
+
);
|
|
41374
|
+
}
|
|
41375
|
+
}
|
|
41376
|
+
const fold = (r, label, forcedTurns) => {
|
|
41377
|
+
hist = applySessionSurface(r.messages);
|
|
41378
|
+
if (r.compacted) {
|
|
41379
|
+
messagesRemoved += r.messagesRemoved;
|
|
41380
|
+
if (r.summary) compactSummary = r.summary;
|
|
41381
|
+
mergeCompactRange(compactRange, r);
|
|
41382
|
+
if (r.cacheReuseExpected !== void 0) {
|
|
41383
|
+
cacheReuseExpected = r.cacheReuseExpected;
|
|
41384
|
+
}
|
|
41385
|
+
}
|
|
41386
|
+
estimated = surface ? headerTokens + convTokensOf(hist) + RESERVED_OUTPUT_TOKENS : estimateHistoryTokens(hist) + sessionExtra;
|
|
41387
|
+
occupancy = Math.min(1, estimated / contextLimit);
|
|
41388
|
+
warnings.push(
|
|
41389
|
+
`[budget] ${label} \u2014 kept ~${forcedTurns} turns (${estimated} tok est.` + (r.messagesRemoved ? `, removed ${r.messagesRemoved} msgs` : "") + (r.cacheReuseExpected === false ? ", cache reuse NOT expected (model override)" : "") + ")."
|
|
41390
|
+
);
|
|
41391
|
+
};
|
|
41392
|
+
if (occupancy >= compact3.compactAt) {
|
|
41393
|
+
const forcedTurns = Math.max(1, Math.floor(historyTurns / 2));
|
|
41394
|
+
historyTurns = forcedTurns;
|
|
41395
|
+
maxToolLoopIterations = Math.min(
|
|
41396
|
+
maxToolLoopIterations,
|
|
41397
|
+
phase2 === "plan" ? 24 : 40
|
|
41398
|
+
);
|
|
41399
|
+
let r = await compactHistoryAsync(hist, {
|
|
41400
|
+
maxMessages: Math.max(2, forcedTurns * 4),
|
|
41401
|
+
force: true,
|
|
41402
|
+
signal: opts?.signal,
|
|
41403
|
+
...replayBase ? { requestSnapshot: replayBase, providerStream: opts?.providerStream } : {}
|
|
41404
|
+
});
|
|
41405
|
+
if (!r.compacted) {
|
|
41406
|
+
r = await compactHistoryAsync(hist, {
|
|
41407
|
+
maxMessages: 2,
|
|
41408
|
+
force: true,
|
|
41409
|
+
signal: opts?.signal,
|
|
41410
|
+
...replayBase ? { requestSnapshot: replayBase, providerStream: opts?.providerStream } : {}
|
|
41411
|
+
});
|
|
41412
|
+
}
|
|
41413
|
+
const label = r.cacheReuseExpected === false ? "llm-compact (model override)" : "auto-compact";
|
|
41414
|
+
fold(r, label, forcedTurns);
|
|
41415
|
+
}
|
|
41416
|
+
if (occupancy >= compact3.hardAt) {
|
|
41417
|
+
const hard = await compactHistoryAsync(hist, {
|
|
41418
|
+
maxMessages: 2,
|
|
41419
|
+
force: true,
|
|
41420
|
+
signal: opts?.signal
|
|
41421
|
+
});
|
|
41422
|
+
fold(hard, hard.summary.includes("\xB7 llm") ? "llm-compact" : "HARD trim", 2);
|
|
41423
|
+
historyTurns = 2;
|
|
41424
|
+
maxToolLoopIterations = Math.min(maxToolLoopIterations, 16);
|
|
41425
|
+
warnings.push(
|
|
41426
|
+
"[budget] HARD context pressure (\u226595%) \u2014 prefer /clear or a new session if quality drops."
|
|
41427
|
+
);
|
|
41428
|
+
}
|
|
41429
|
+
const cacheMetricsLine = envelope ? [
|
|
41430
|
+
"compaction meter:",
|
|
41431
|
+
`provider/model: ${envelope.snapshot.provider}/${envelope.snapshot.model}`,
|
|
41432
|
+
`headerFingerprint: ${envelope.snapshot.headerFingerprint.slice(0, 12)}`,
|
|
41433
|
+
`occupancy: ${Math.round(occupancy * 100)}% (${estimated}/${contextLimit})`,
|
|
41434
|
+
...envelope.usage?.cachedPromptTokens !== void 0 ? [`cachedPromptTokens: ${envelope.usage.cachedPromptTokens}`] : [],
|
|
41435
|
+
...cacheReuseExpected !== void 0 ? [`cacheReuseExpected: ${cacheReuseExpected}`] : []
|
|
41436
|
+
].join(" | ") : void 0;
|
|
41437
|
+
return {
|
|
41438
|
+
history: hist,
|
|
41439
|
+
warnings,
|
|
41440
|
+
maxToolLoopIterations,
|
|
41441
|
+
historyTurns,
|
|
41442
|
+
estimatedHistoryTokens: surface ? convTokensOf(hist) : estimated,
|
|
41443
|
+
contextLimit,
|
|
41444
|
+
occupancy,
|
|
41445
|
+
compactSummary: compactSummary || void 0,
|
|
41446
|
+
messagesRemoved: messagesRemoved || void 0,
|
|
41447
|
+
...compactRange.fromSeq !== void 0 && compactRange.toSeq !== void 0 ? {
|
|
41448
|
+
compactedFromSeq: compactRange.fromSeq,
|
|
41449
|
+
compactedToSeq: compactRange.toSeq,
|
|
41450
|
+
compactSourceSeqs: compactRange.sourceSeqs,
|
|
41451
|
+
compactStrategy: compactRange.strategy
|
|
41452
|
+
} : {},
|
|
41453
|
+
...surface ? { contextPressureTokens: estimated } : {},
|
|
41454
|
+
...cacheReuseExpected !== void 0 ? { cacheReuseExpected } : {},
|
|
41455
|
+
...cacheMetricsLine ? { cacheMetricsLine } : {}
|
|
41456
|
+
};
|
|
41457
|
+
}
|
|
41458
|
+
function estimateSystemTokensLite(systemMessages) {
|
|
41459
|
+
let n = 0;
|
|
41460
|
+
for (const m of systemMessages) n += 4 + Math.ceil((m.content ?? "").length / 4);
|
|
41461
|
+
return n;
|
|
41462
|
+
}
|
|
41463
|
+
function estimateToolSchemaTokensLite(tools) {
|
|
41464
|
+
let n = 0;
|
|
41465
|
+
for (const t of tools) {
|
|
41466
|
+
n += Math.ceil((t.name ?? "").length / 4);
|
|
41467
|
+
n += Math.ceil((t.description ?? "").length / 4);
|
|
41468
|
+
n += Math.ceil(JSON.stringify(t.parameters ?? {}).length / 4);
|
|
41469
|
+
}
|
|
41470
|
+
return n + tools.length * 4;
|
|
41471
|
+
}
|
|
41472
|
+
function estimateConversationTokensLite(messages) {
|
|
41473
|
+
let n = 0;
|
|
41474
|
+
for (const m of messages) {
|
|
41475
|
+
n += 4 + Math.ceil((m.content ?? "").length / 4);
|
|
41476
|
+
if (m.toolCalls) {
|
|
41477
|
+
for (const tc of m.toolCalls) {
|
|
41478
|
+
n += Math.ceil(tc.name.length / 4) + Math.ceil(tc.id.length / 4);
|
|
41479
|
+
n += Math.ceil(JSON.stringify(tc.args ?? {}).length / 4);
|
|
41480
|
+
}
|
|
41481
|
+
}
|
|
41482
|
+
if (m.reasoningContent) n += Math.ceil(m.reasoningContent.length / 4);
|
|
41483
|
+
if (m.toolCallId) n += Math.ceil(m.toolCallId.length / 4);
|
|
41484
|
+
}
|
|
41485
|
+
return n;
|
|
41486
|
+
}
|
|
41487
|
+
var RESERVED_OUTPUT_TOKENS;
|
|
41488
|
+
var init_tokenBudget = __esm({
|
|
41489
|
+
"src/cli/budget/tokenBudget.ts"() {
|
|
41490
|
+
"use strict";
|
|
41491
|
+
init_envNumber();
|
|
41492
|
+
init_historyCompaction();
|
|
41493
|
+
init_observationStore();
|
|
41494
|
+
init_capabilities();
|
|
41495
|
+
RESERVED_OUTPUT_TOKENS = 8192;
|
|
41496
|
+
}
|
|
41497
|
+
});
|
|
41498
|
+
|
|
41499
|
+
// src/cli/budget/retrievalPolicy.ts
|
|
41500
|
+
var retrievalPolicy_exports = {};
|
|
41501
|
+
__export(retrievalPolicy_exports, {
|
|
41502
|
+
BASELINE_RETRIEVAL_POLICY: () => BASELINE_RETRIEVAL_POLICY,
|
|
41503
|
+
RETRIEVAL_PRESSURE_THRESHOLDS: () => RETRIEVAL_PRESSURE_THRESHOLDS,
|
|
41504
|
+
estimateHistoryOccupancy: () => estimateHistoryOccupancy,
|
|
41505
|
+
filterSkillCatalogByBand: () => filterSkillCatalogByBand,
|
|
41506
|
+
resolveRetrievalPolicy: () => resolveRetrievalPolicy,
|
|
41507
|
+
retrievalBand: () => retrievalBand
|
|
41508
|
+
});
|
|
41509
|
+
function retrievalBand(occupancy) {
|
|
41510
|
+
const occ = Number.isFinite(occupancy) ? Math.max(0, Math.min(1, occupancy)) : 0;
|
|
41511
|
+
if (occ >= RETRIEVAL_PRESSURE_THRESHOLDS.high) return "high";
|
|
41512
|
+
if (occ >= RETRIEVAL_PRESSURE_THRESHOLDS.medium) return "medium";
|
|
41513
|
+
return "low";
|
|
41514
|
+
}
|
|
41515
|
+
function resolveRetrievalPolicy(occupancy) {
|
|
41516
|
+
const band = retrievalBand(occupancy);
|
|
41517
|
+
const packing = PRESSURE_PACKING[band];
|
|
41518
|
+
const weights = PRESSURE_WEIGHTS[band];
|
|
41519
|
+
return {
|
|
41520
|
+
band,
|
|
41521
|
+
...packing,
|
|
41522
|
+
...weights ? { weights } : {}
|
|
41523
|
+
};
|
|
41524
|
+
}
|
|
41525
|
+
function estimateHistoryOccupancy(history2, opts) {
|
|
41526
|
+
const limit = resolveContextLimit(opts?.model, opts?.provider);
|
|
41527
|
+
return Math.min(1, estimateHistoryTokens(history2) / limit);
|
|
41528
|
+
}
|
|
41529
|
+
function filterSkillCatalogByBand(skills, band) {
|
|
41530
|
+
if (band !== "high") return [...skills];
|
|
41531
|
+
return skills.filter((s) => s.estimatedCost !== "high");
|
|
41532
|
+
}
|
|
41533
|
+
var RETRIEVAL_PRESSURE_THRESHOLDS, BASELINE_RETRIEVAL_POLICY, PRESSURE_WEIGHTS, PRESSURE_PACKING;
|
|
41534
|
+
var init_retrievalPolicy = __esm({
|
|
41535
|
+
"src/cli/budget/retrievalPolicy.ts"() {
|
|
41536
|
+
"use strict";
|
|
41537
|
+
init_tokenBudget();
|
|
41538
|
+
RETRIEVAL_PRESSURE_THRESHOLDS = { medium: 0.5, high: 0.8 };
|
|
41539
|
+
BASELINE_RETRIEVAL_POLICY = {
|
|
41540
|
+
band: "low",
|
|
41541
|
+
maxChars: 2e3,
|
|
41542
|
+
maxMemories: 8
|
|
41543
|
+
};
|
|
41544
|
+
PRESSURE_WEIGHTS = {
|
|
41545
|
+
low: void 0,
|
|
41546
|
+
medium: {
|
|
41547
|
+
semanticRelevance: 0.35,
|
|
41548
|
+
lexicalRelevance: 0.2,
|
|
41549
|
+
importance: 0.15,
|
|
41550
|
+
confidence: 0.1,
|
|
41551
|
+
recency: 0.05,
|
|
41552
|
+
graphProximity: 0.1,
|
|
41553
|
+
verificationBonus: 0.05
|
|
41554
|
+
},
|
|
41555
|
+
high: {
|
|
41556
|
+
semanticRelevance: 0.4,
|
|
41557
|
+
lexicalRelevance: 0.25,
|
|
41558
|
+
importance: 0.15,
|
|
41559
|
+
confidence: 0.1,
|
|
41560
|
+
recency: 0,
|
|
41561
|
+
graphProximity: 0.05,
|
|
41562
|
+
verificationBonus: 0.05
|
|
41563
|
+
}
|
|
41564
|
+
};
|
|
41565
|
+
PRESSURE_PACKING = {
|
|
41566
|
+
low: { maxChars: 2e3, maxMemories: 8 },
|
|
41567
|
+
medium: { maxChars: 1200, maxMemories: 6 },
|
|
41568
|
+
high: { maxChars: 600, maxMemories: 4 }
|
|
41569
|
+
};
|
|
41570
|
+
}
|
|
41571
|
+
});
|
|
41572
|
+
|
|
40724
41573
|
// src/cli/tools/skillTool.ts
|
|
40725
|
-
function formatAvailableSkillsCatalog(cwd = process.cwd()) {
|
|
41574
|
+
function formatAvailableSkillsCatalog(cwd = process.cwd(), opts) {
|
|
40726
41575
|
try {
|
|
40727
41576
|
loadSkillMdSkills(cwd);
|
|
40728
41577
|
} catch {
|
|
40729
41578
|
}
|
|
40730
|
-
const
|
|
40731
|
-
|
|
41579
|
+
const band = opts?.pressureBand;
|
|
41580
|
+
const all = listCodingSkills();
|
|
41581
|
+
if (all.length === 0) {
|
|
40732
41582
|
return "No skills registered.";
|
|
40733
41583
|
}
|
|
40734
|
-
const
|
|
41584
|
+
const gated = band ? filterSkillCatalogByBand(all, band) : all;
|
|
41585
|
+
const hidden = all.length - gated.length;
|
|
41586
|
+
const lines = gated.slice(0, 80).map((s) => {
|
|
40735
41587
|
const desc = (s.description || s.id).replace(/\s+/g, " ").trim().slice(0, 160);
|
|
40736
41588
|
return `- ${s.id}: ${desc}`;
|
|
40737
41589
|
});
|
|
41590
|
+
if (hidden > 0) {
|
|
41591
|
+
lines.push(
|
|
41592
|
+
`(plus ${hidden} high-cost skill(s) hidden under context pressure \u2014 still loadable by name if truly needed)`
|
|
41593
|
+
);
|
|
41594
|
+
}
|
|
40738
41595
|
return lines.join("\n");
|
|
40739
41596
|
}
|
|
40740
41597
|
function createSkillTool(opts) {
|
|
40741
41598
|
const cwd = opts?.cwd ?? process.cwd();
|
|
40742
|
-
const catalog = formatAvailableSkillsCatalog(cwd
|
|
41599
|
+
const catalog = formatAvailableSkillsCatalog(cwd, {
|
|
41600
|
+
pressureBand: opts?.pressureBand
|
|
41601
|
+
});
|
|
40743
41602
|
return {
|
|
40744
41603
|
name: "skill",
|
|
40745
41604
|
description: "Load the full instructions for a named coding skill into this turn. Call when a skill matches the current task. Available skills:\n" + catalog,
|
|
@@ -40781,6 +41640,7 @@ var init_skillTool = __esm({
|
|
|
40781
41640
|
init_skills2();
|
|
40782
41641
|
init_toolTypes();
|
|
40783
41642
|
init_skillsMd();
|
|
41643
|
+
init_retrievalPolicy();
|
|
40784
41644
|
SkillArgsSchema = external_exports.object({
|
|
40785
41645
|
name: external_exports.string().min(1).describe("Skill id/name to load (from the available skills list).")
|
|
40786
41646
|
});
|
|
@@ -43862,124 +44722,6 @@ var init_semantic2 = __esm({
|
|
|
43862
44722
|
}
|
|
43863
44723
|
});
|
|
43864
44724
|
|
|
43865
|
-
// src/cli/provider/capabilities.ts
|
|
43866
|
-
function frozenProfile(input) {
|
|
43867
|
-
if (input.reasoning.levels) Object.freeze(input.reasoning.levels);
|
|
43868
|
-
Object.freeze(input.reasoning);
|
|
43869
|
-
Object.freeze(input.promptCache);
|
|
43870
|
-
Object.freeze(input.toolCalling);
|
|
43871
|
-
Object.freeze(input.buildRecovery);
|
|
43872
|
-
Object.freeze(input.sampling);
|
|
43873
|
-
Object.freeze(input.compaction);
|
|
43874
|
-
return Object.freeze(input);
|
|
43875
|
-
}
|
|
43876
|
-
function resolveHarnessProfile(model, providerId) {
|
|
43877
|
-
const provider = providerId?.trim().toLowerCase();
|
|
43878
|
-
if (provider === "deepseek") return "deepseek-v4";
|
|
43879
|
-
if (provider === "grok") return "grok";
|
|
43880
|
-
if (provider === "minimax") return "minimax";
|
|
43881
|
-
if (provider === "glm") return "glm";
|
|
43882
|
-
if (model && DEEPSEEK_RE.test(model)) return "deepseek-v4";
|
|
43883
|
-
if (model && GROK_RE.test(model)) return "grok";
|
|
43884
|
-
if (model && MINIMAX_RE.test(model)) return "minimax";
|
|
43885
|
-
if (model && GLM_RE.test(model)) return "glm";
|
|
43886
|
-
return "default";
|
|
43887
|
-
}
|
|
43888
|
-
function capabilitiesFor(model, providerId) {
|
|
43889
|
-
switch (resolveHarnessProfile(model, providerId)) {
|
|
43890
|
-
case "deepseek-v4":
|
|
43891
|
-
return DEEPSEEK_V4_CAPS;
|
|
43892
|
-
case "grok":
|
|
43893
|
-
return GROK_CAPS;
|
|
43894
|
-
case "minimax":
|
|
43895
|
-
return model && MINIMAX_M3_RE.test(model) ? MINIMAX_M3_CAPS : MINIMAX_M2_CAPS;
|
|
43896
|
-
case "glm":
|
|
43897
|
-
return GLM_CAPS;
|
|
43898
|
-
default:
|
|
43899
|
-
return DEFAULT_CAPS;
|
|
43900
|
-
}
|
|
43901
|
-
}
|
|
43902
|
-
var SHARED_COMPACTION, DEFAULT_CAPS, DEEPSEEK_V4_CAPS, GROK_CAPS, MINIMAX_M3_CAPS, MINIMAX_M2_CAPS, GLM_CAPS, DEEPSEEK_RE, GROK_RE, MINIMAX_RE, MINIMAX_M3_RE, GLM_RE;
|
|
43903
|
-
var init_capabilities = __esm({
|
|
43904
|
-
"src/cli/provider/capabilities.ts"() {
|
|
43905
|
-
"use strict";
|
|
43906
|
-
SHARED_COMPACTION = { warnAt: 0.7, compactAt: 0.85, hardAt: 0.95 };
|
|
43907
|
-
DEFAULT_CAPS = frozenProfile({
|
|
43908
|
-
contextWindow: 4e5,
|
|
43909
|
-
reasoning: { supported: true, levels: ["low", "medium", "high"], replayReasoning: true },
|
|
43910
|
-
promptCache: { supported: true, pricedCacheRead: false },
|
|
43911
|
-
toolCalling: { parallel: true },
|
|
43912
|
-
buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
|
|
43913
|
-
sampling: { temperature: 0.7 },
|
|
43914
|
-
compaction: { ...SHARED_COMPACTION },
|
|
43915
|
-
profile: "default"
|
|
43916
|
-
});
|
|
43917
|
-
DEEPSEEK_V4_CAPS = frozenProfile({
|
|
43918
|
-
contextWindow: 1e6,
|
|
43919
|
-
reasoning: { supported: true, levels: ["high", "max"], replayReasoning: true },
|
|
43920
|
-
promptCache: { supported: true, pricedCacheRead: true },
|
|
43921
|
-
toolCalling: { parallel: true },
|
|
43922
|
-
buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
|
|
43923
|
-
sampling: { temperature: 0.7 },
|
|
43924
|
-
compaction: { ...SHARED_COMPACTION },
|
|
43925
|
-
profile: "deepseek-v4"
|
|
43926
|
-
});
|
|
43927
|
-
GROK_CAPS = frozenProfile({
|
|
43928
|
-
contextWindow: 5e5,
|
|
43929
|
-
reasoning: {
|
|
43930
|
-
supported: true,
|
|
43931
|
-
levels: ["low", "medium", "high", "xhigh"],
|
|
43932
|
-
replayReasoning: false
|
|
43933
|
-
},
|
|
43934
|
-
promptCache: {
|
|
43935
|
-
supported: true,
|
|
43936
|
-
pricedCacheRead: true,
|
|
43937
|
-
conversationAffinityHeader: "x-grok-conv-id"
|
|
43938
|
-
},
|
|
43939
|
-
toolCalling: { parallel: true },
|
|
43940
|
-
buildRecovery: { forceToolChoice: true, maxForcedTurns: 1 },
|
|
43941
|
-
sampling: { temperature: 0.7 },
|
|
43942
|
-
compaction: { ...SHARED_COMPACTION },
|
|
43943
|
-
profile: "grok"
|
|
43944
|
-
});
|
|
43945
|
-
MINIMAX_M3_CAPS = frozenProfile({
|
|
43946
|
-
contextWindow: 1e6,
|
|
43947
|
-
reasoning: { supported: true, replayReasoning: true },
|
|
43948
|
-
promptCache: { supported: false, pricedCacheRead: false },
|
|
43949
|
-
toolCalling: { parallel: true },
|
|
43950
|
-
buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
|
|
43951
|
-
sampling: { temperature: 0.7 },
|
|
43952
|
-
compaction: { ...SHARED_COMPACTION },
|
|
43953
|
-
profile: "minimax"
|
|
43954
|
-
});
|
|
43955
|
-
MINIMAX_M2_CAPS = frozenProfile({
|
|
43956
|
-
contextWindow: 204800,
|
|
43957
|
-
reasoning: { supported: true, replayReasoning: true },
|
|
43958
|
-
promptCache: { supported: false, pricedCacheRead: false },
|
|
43959
|
-
toolCalling: { parallel: true },
|
|
43960
|
-
buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
|
|
43961
|
-
sampling: { temperature: 0.7 },
|
|
43962
|
-
compaction: { ...SHARED_COMPACTION },
|
|
43963
|
-
profile: "minimax"
|
|
43964
|
-
});
|
|
43965
|
-
GLM_CAPS = frozenProfile({
|
|
43966
|
-
contextWindow: 2e5,
|
|
43967
|
-
reasoning: { supported: true, replayReasoning: true },
|
|
43968
|
-
promptCache: { supported: true, pricedCacheRead: false },
|
|
43969
|
-
toolCalling: { parallel: true },
|
|
43970
|
-
buildRecovery: { forceToolChoice: false, maxForcedTurns: 0 },
|
|
43971
|
-
sampling: { temperature: 0.7 },
|
|
43972
|
-
compaction: { ...SHARED_COMPACTION },
|
|
43973
|
-
profile: "glm"
|
|
43974
|
-
});
|
|
43975
|
-
DEEPSEEK_RE = /^deepseek-(?:v4(?:\.|-|$)|chat$|reasoner$)/i;
|
|
43976
|
-
GROK_RE = /^grok(?:\.|-|$)/i;
|
|
43977
|
-
MINIMAX_RE = /^minimax(?:\.|-|$)/i;
|
|
43978
|
-
MINIMAX_M3_RE = /^minimax-m3(?:\.|-|$)/i;
|
|
43979
|
-
GLM_RE = /^glm(?:\.|-|$)/i;
|
|
43980
|
-
}
|
|
43981
|
-
});
|
|
43982
|
-
|
|
43983
44725
|
// src/cli/provider/openai-compatible.ts
|
|
43984
44726
|
var openai_compatible_exports = {};
|
|
43985
44727
|
__export(openai_compatible_exports, {
|
|
@@ -44163,6 +44905,12 @@ ${notes}
|
|
|
44163
44905
|
}
|
|
44164
44906
|
return { role: m.role, content: m.content };
|
|
44165
44907
|
}
|
|
44908
|
+
function positiveEnvInt(name) {
|
|
44909
|
+
const raw = process.env[name];
|
|
44910
|
+
if (!raw) return void 0;
|
|
44911
|
+
const n = Number.parseInt(raw, 10);
|
|
44912
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
44913
|
+
}
|
|
44166
44914
|
function openaiCompatibleProvider(config2) {
|
|
44167
44915
|
return async function* (params) {
|
|
44168
44916
|
const capabilities = capabilitiesFor(params.model, config2.providerId);
|
|
@@ -44195,6 +44943,8 @@ function openaiCompatibleProvider(config2) {
|
|
|
44195
44943
|
};
|
|
44196
44944
|
if (typeof generation?.maxTokens === "number" && generation.maxTokens > 0) {
|
|
44197
44945
|
body.max_tokens = generation.maxTokens;
|
|
44946
|
+
} else if (typeof capabilities.maxOutputTokens === "number" && capabilities.maxOutputTokens > 0) {
|
|
44947
|
+
body.max_tokens = positiveEnvInt("ZELARI_MAX_OUTPUT_TOKENS") ?? capabilities.maxOutputTokens;
|
|
44198
44948
|
}
|
|
44199
44949
|
const thinkingSpec = config2.thinking ?? "auto";
|
|
44200
44950
|
if (config2.providerId === "deepseek" && thinkingSpec === "auto") {
|
|
@@ -46386,8 +47136,8 @@ function defaultPermissionPolicy(overrides) {
|
|
|
46386
47136
|
return {
|
|
46387
47137
|
read: parseAction(process.env.ZELARI_PERMISSION_READ, "allow"),
|
|
46388
47138
|
write: parseAction(process.env.ZELARI_PERMISSION_WRITE, "allow"),
|
|
46389
|
-
execute: parseAction(process.env.ZELARI_PERMISSION_EXECUTE, "
|
|
46390
|
-
network: parseAction(process.env.ZELARI_PERMISSION_NETWORK, "
|
|
47139
|
+
execute: parseAction(process.env.ZELARI_PERMISSION_EXECUTE, "ask"),
|
|
47140
|
+
network: parseAction(process.env.ZELARI_PERMISSION_NETWORK, "ask"),
|
|
46391
47141
|
ui: "allow",
|
|
46392
47142
|
auto: isAutoPermissions(),
|
|
46393
47143
|
...overrides
|
|
@@ -47353,7 +48103,7 @@ function matchResourceClaimLayered(layers, precedence, claim, root) {
|
|
|
47353
48103
|
function resolveClaimsVerdict(layers, precedence, toolName, args, root) {
|
|
47354
48104
|
const claims = resourceClaimsFor(toolName, args);
|
|
47355
48105
|
const matchedRules = [];
|
|
47356
|
-
if (!layers || claims.length === 0) return { matchedRules };
|
|
48106
|
+
if (!layers || claims.length === 0) return { claims, matchedRules };
|
|
47357
48107
|
const effects = [];
|
|
47358
48108
|
for (const claim of claims) {
|
|
47359
48109
|
const hit = matchResourceClaimLayered(layers, precedence, claim, root);
|
|
@@ -47362,7 +48112,26 @@ function resolveClaimsVerdict(layers, precedence, toolName, args, root) {
|
|
|
47362
48112
|
matchedRules.push(hit);
|
|
47363
48113
|
}
|
|
47364
48114
|
}
|
|
47365
|
-
return effects.length > 0 ? { effect: intersectEffects(...effects), matchedRules } : { matchedRules };
|
|
48115
|
+
return effects.length > 0 ? { effect: intersectEffects(...effects), claims, matchedRules } : { claims, matchedRules };
|
|
48116
|
+
}
|
|
48117
|
+
function describeResourceClaim(claim) {
|
|
48118
|
+
const cap3 = (s) => s.length > 160 ? `${s.slice(0, 157)}\u2026` : s;
|
|
48119
|
+
switch (claim.kind) {
|
|
48120
|
+
case "path":
|
|
48121
|
+
return cap3(`path ${claim.operation}: ${claim.path}`);
|
|
48122
|
+
case "process":
|
|
48123
|
+
return cap3(`process: ${[claim.executable, ...claim.argv ?? []].join(" ")}`);
|
|
48124
|
+
case "network":
|
|
48125
|
+
return cap3(`network: ${claim.host}${claim.port !== void 0 ? `:${claim.port}` : ""}`);
|
|
48126
|
+
case "mcp":
|
|
48127
|
+
return cap3(`mcp: ${claim.server}/${claim.tool}`);
|
|
48128
|
+
case "ssh":
|
|
48129
|
+
return cap3(`ssh: ${claim.target}${claim.command ? ` (${claim.command})` : ""}`);
|
|
48130
|
+
case "ui":
|
|
48131
|
+
return cap3(`ui: ${claim.action}`);
|
|
48132
|
+
case "agent":
|
|
48133
|
+
return cap3(`agent: ${claim.role}`);
|
|
48134
|
+
}
|
|
47366
48135
|
}
|
|
47367
48136
|
var MAX_RAW_SHELL_STRIP_DEPTH, RAW_SHELL_WRAPPERS, RAW_SHELL_INTERPRETERS;
|
|
47368
48137
|
var init_resourceClaims = __esm({
|
|
@@ -47819,7 +48588,7 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
47819
48588
|
registry4.register(withPerm(askUserTool));
|
|
47820
48589
|
}
|
|
47821
48590
|
const enableSkill = options.enableSkill !== false && options.readOnly !== true && !gauntletParent && profile !== "explore" && profile !== "verify";
|
|
47822
|
-
const skillTool = enableSkill ? withPerm(createSkillTool({ cwd: root })) : null;
|
|
48591
|
+
const skillTool = enableSkill ? withPerm(createSkillTool({ cwd: root, pressureBand: options.pressureBand })) : null;
|
|
47823
48592
|
if (skillTool) {
|
|
47824
48593
|
registry4.register(skillTool);
|
|
47825
48594
|
}
|
|
@@ -48113,11 +48882,17 @@ function wrapWithPermissions(original, policy, onAsk, agentLayers, precedence =
|
|
|
48113
48882
|
);
|
|
48114
48883
|
}
|
|
48115
48884
|
try {
|
|
48885
|
+
const expanded = claims?.claims ?? resourceClaimsFor(original.name, input ?? {});
|
|
48116
48886
|
const ok = await onAsk({
|
|
48117
48887
|
toolName: original.name,
|
|
48118
48888
|
reason: decision.reason,
|
|
48119
48889
|
categories: decision.categories,
|
|
48120
|
-
args: input
|
|
48890
|
+
args: input,
|
|
48891
|
+
policyNote: rulePrefix || void 0,
|
|
48892
|
+
claims: expanded.slice(0, 6).map((c) => ({
|
|
48893
|
+
kind: c.kind,
|
|
48894
|
+
summary: describeResourceClaim(c)
|
|
48895
|
+
}))
|
|
48121
48896
|
});
|
|
48122
48897
|
if (!ok) {
|
|
48123
48898
|
return typedErr(
|
|
@@ -50400,547 +51175,103 @@ var init_fileStateStore = __esm({
|
|
|
50400
51175
|
return [];
|
|
50401
51176
|
}
|
|
50402
51177
|
async materializeContext() {
|
|
50403
|
-
return "";
|
|
50404
|
-
}
|
|
50405
|
-
async close() {
|
|
50406
|
-
}
|
|
50407
|
-
};
|
|
50408
|
-
}
|
|
50409
|
-
});
|
|
50410
|
-
|
|
50411
|
-
// src/cli/hooks/messageHelpers.ts
|
|
50412
|
-
function appendSystem(setMessages, content, ts = Date.now()) {
|
|
50413
|
-
setMessages((prev2) => [
|
|
50414
|
-
...prev2,
|
|
50415
|
-
{ id: crypto.randomUUID(), role: "system", content, ts }
|
|
50416
|
-
]);
|
|
50417
|
-
}
|
|
50418
|
-
function appendUser(setMessages, content, ts = Date.now()) {
|
|
50419
|
-
setMessages((prev2) => [
|
|
50420
|
-
...prev2,
|
|
50421
|
-
{ id: crypto.randomUUID(), role: "user", content, ts }
|
|
50422
|
-
]);
|
|
50423
|
-
}
|
|
50424
|
-
function appendOrExtendStreamingAssistant(setMessages, fullContent, ts, memberContext) {
|
|
50425
|
-
setMessages((prev2) => {
|
|
50426
|
-
const last = prev2[prev2.length - 1];
|
|
50427
|
-
if (last && last.role === "assistant" && last.id.startsWith("streaming-")) {
|
|
50428
|
-
return [...prev2.slice(0, -1), { ...last, content: fullContent }];
|
|
50429
|
-
}
|
|
50430
|
-
return [
|
|
50431
|
-
...prev2,
|
|
50432
|
-
{
|
|
50433
|
-
id: `streaming-${crypto.randomUUID()}`,
|
|
50434
|
-
role: "assistant",
|
|
50435
|
-
content: fullContent,
|
|
50436
|
-
ts,
|
|
50437
|
-
...memberContext?.memberId ? { memberId: memberContext.memberId } : {},
|
|
50438
|
-
...memberContext?.memberName ? { memberName: memberContext.memberName } : {}
|
|
50439
|
-
}
|
|
50440
|
-
];
|
|
50441
|
-
});
|
|
50442
|
-
}
|
|
50443
|
-
function appendToolStart(setMessages, toolName, toolCallId, args, ts) {
|
|
50444
|
-
const argsPreview = formatToolSummary(toolName, args);
|
|
50445
|
-
setMessages((prev2) => [
|
|
50446
|
-
...prev2,
|
|
50447
|
-
{
|
|
50448
|
-
id: crypto.randomUUID(),
|
|
50449
|
-
role: "tool",
|
|
50450
|
-
content: argsPreview,
|
|
50451
|
-
ts,
|
|
50452
|
-
toolName,
|
|
50453
|
-
toolCallId,
|
|
50454
|
-
toolOk: void 0,
|
|
50455
|
-
toolDurationMs: void 0
|
|
50456
|
-
}
|
|
50457
|
-
]);
|
|
50458
|
-
}
|
|
50459
|
-
function updateToolMessageEnd(setMessages, toolCallId, isError, durationMs, result) {
|
|
50460
|
-
setMessages((prev2) => {
|
|
50461
|
-
for (let i = prev2.length - 1; i >= 0; i--) {
|
|
50462
|
-
const m = prev2[i];
|
|
50463
|
-
if (m && m.role === "tool" && m.toolCallId === toolCallId && m.toolDurationMs === void 0) {
|
|
50464
|
-
const updated = [...prev2];
|
|
50465
|
-
updated[i] = {
|
|
50466
|
-
...m,
|
|
50467
|
-
toolOk: !isError,
|
|
50468
|
-
toolDurationMs: durationMs,
|
|
50469
|
-
...result !== void 0 ? {
|
|
50470
|
-
toolResult: toolResultForStorage(
|
|
50471
|
-
m.toolName ?? "",
|
|
50472
|
-
result,
|
|
50473
|
-
isError
|
|
50474
|
-
)
|
|
50475
|
-
} : {}
|
|
50476
|
-
};
|
|
50477
|
-
return updated;
|
|
50478
|
-
}
|
|
50479
|
-
}
|
|
50480
|
-
return prev2;
|
|
50481
|
-
});
|
|
50482
|
-
}
|
|
50483
|
-
function finalizeStreamingAssistant(setMessages) {
|
|
50484
|
-
setMessages((prev2) => {
|
|
50485
|
-
const last = prev2[prev2.length - 1];
|
|
50486
|
-
if (last && last.role === "assistant" && last.id.startsWith("streaming-")) {
|
|
50487
|
-
return [
|
|
50488
|
-
...prev2.slice(0, -1),
|
|
50489
|
-
{ ...last, id: last.id.slice("streaming-".length) }
|
|
50490
|
-
];
|
|
50491
|
-
}
|
|
50492
|
-
return prev2;
|
|
50493
|
-
});
|
|
50494
|
-
}
|
|
50495
|
-
var init_messageHelpers = __esm({
|
|
50496
|
-
"src/cli/hooks/messageHelpers.ts"() {
|
|
50497
|
-
"use strict";
|
|
50498
|
-
init_toolFormat();
|
|
50499
|
-
init_toolFormat();
|
|
50500
|
-
}
|
|
50501
|
-
});
|
|
50502
|
-
|
|
50503
|
-
// src/cli/budget/historySummary.ts
|
|
50504
|
-
function extractiveHistorySummary(dropped, opts) {
|
|
50505
|
-
const maxChars = opts?.maxChars ?? MAX_SUMMARY_CHARS;
|
|
50506
|
-
if (dropped.length === 0) return "No prior turns.";
|
|
50507
|
-
const userGoals = [];
|
|
50508
|
-
const assistantNotes = [];
|
|
50509
|
-
const userConstraints = [];
|
|
50510
|
-
const unresolved = [];
|
|
50511
|
-
const verification = [];
|
|
50512
|
-
const decisions = [];
|
|
50513
|
-
const tools = /* @__PURE__ */ new Map();
|
|
50514
|
-
const files = /* @__PURE__ */ new Set();
|
|
50515
|
-
let toolResults = 0;
|
|
50516
|
-
for (const m of dropped) {
|
|
50517
|
-
if (m.role === "user" && m.content.trim()) {
|
|
50518
|
-
const goal = oneLine(m.content, 220);
|
|
50519
|
-
userGoals.push(goal);
|
|
50520
|
-
if (/\b(must|never|required|only|do not|constraint|vincolo|deve|senza)\b/i.test(goal)) userConstraints.push(goal);
|
|
50521
|
-
} else if (m.role === "assistant") {
|
|
50522
|
-
if (m.content.trim()) {
|
|
50523
|
-
const note = oneLine(m.content, 220);
|
|
50524
|
-
assistantNotes.push(note);
|
|
50525
|
-
if (/\b(fail|failed|error|unresolved|remaining|todo|blocked|gap|errore|fallit|irrisolt|manca)\b/i.test(note)) unresolved.push(note);
|
|
50526
|
-
if (/\b(test|typecheck|build|verify|verification|passed|failed|green|red)\b/i.test(note)) verification.push(note);
|
|
50527
|
-
if (/\b(decid|decision|chosen|choose|scelt|adopt|implement)\b/i.test(note)) decisions.push(note);
|
|
50528
|
-
}
|
|
50529
|
-
if (m.toolCalls) {
|
|
50530
|
-
for (const tc of m.toolCalls) {
|
|
50531
|
-
tools.set(tc.name, (tools.get(tc.name) ?? 0) + 1);
|
|
50532
|
-
collectPaths3(tc.args, files);
|
|
50533
|
-
}
|
|
50534
|
-
}
|
|
50535
|
-
} else if (m.role === "tool") {
|
|
50536
|
-
toolResults += 1;
|
|
50537
|
-
collectPathsFromText(m.content, files);
|
|
50538
|
-
if (/\b(fail|failed|error|exception|blocked|errore|fallit)\b/i.test(m.content)) unresolved.push(oneLine(m.content, 220));
|
|
50539
|
-
if (/\b(test|typecheck|build|verify|passed|failed|success)\b/i.test(m.content)) verification.push(oneLine(m.content, 220));
|
|
50540
|
-
}
|
|
50541
|
-
}
|
|
50542
|
-
const parts = [
|
|
50543
|
-
"[history-summary] Earlier turns were compacted to stay within the context budget.",
|
|
50544
|
-
`Dropped ${dropped.length} message(s) (${userGoals.length} user, ${assistantNotes.length} assistant notes, ${toolResults} tool results).`
|
|
50545
|
-
];
|
|
50546
|
-
if (userGoals.length) {
|
|
50547
|
-
parts.push("## User goals / requests");
|
|
50548
|
-
for (const g of userGoals.slice(-6)) parts.push(`- ${g}`);
|
|
50549
|
-
}
|
|
50550
|
-
if (userConstraints.length) {
|
|
50551
|
-
parts.push("## User constraints (preserve exactly)");
|
|
50552
|
-
for (const item of [...new Set(userConstraints)].slice(-8)) parts.push(`- ${item}`);
|
|
50553
|
-
}
|
|
50554
|
-
if (unresolved.length) {
|
|
50555
|
-
parts.push("## Unresolved failures / pending repair");
|
|
50556
|
-
for (const item of [...new Set(unresolved)].slice(-8)) parts.push(`- ${item}`);
|
|
50557
|
-
}
|
|
50558
|
-
if (verification.length) {
|
|
50559
|
-
parts.push("## Latest verification state");
|
|
50560
|
-
for (const item of [...new Set(verification)].slice(-6)) parts.push(`- ${item}`);
|
|
50561
|
-
}
|
|
50562
|
-
if (decisions.length) {
|
|
50563
|
-
parts.push("## Recent active decisions");
|
|
50564
|
-
for (const item of [...new Set(decisions)].slice(-6)) parts.push(`- ${item}`);
|
|
50565
|
-
}
|
|
50566
|
-
if (assistantNotes.length) {
|
|
50567
|
-
parts.push("## Assistant conclusions (truncated)");
|
|
50568
|
-
for (const a of assistantNotes.slice(-5)) parts.push(`- ${a}`);
|
|
50569
|
-
}
|
|
50570
|
-
if (tools.size) {
|
|
50571
|
-
const ranked = [...tools.entries()].sort((a, b) => b[1] - a[1]).slice(0, 12).map(([n, c]) => `${n}\xD7${c}`);
|
|
50572
|
-
parts.push(`## Tools used: ${ranked.join(", ")}`);
|
|
50573
|
-
}
|
|
50574
|
-
if (files.size) {
|
|
50575
|
-
const list = [...files].slice(0, 24);
|
|
50576
|
-
parts.push(`## Paths mentioned: ${list.join(", ")}`);
|
|
50577
|
-
}
|
|
50578
|
-
parts.push(
|
|
50579
|
-
"Continue from the recent messages below; do not re-ask goals already answered above unless the user changes them."
|
|
50580
|
-
);
|
|
50581
|
-
let out = parts.join("\n");
|
|
50582
|
-
if (out.length > maxChars) {
|
|
50583
|
-
out = `${out.slice(0, maxChars - 1)}\u2026`;
|
|
50584
|
-
}
|
|
50585
|
-
return out;
|
|
50586
|
-
}
|
|
50587
|
-
function oneLine(s, max) {
|
|
50588
|
-
const t = s.replace(/\s+/g, " ").trim();
|
|
50589
|
-
if (t.length <= max) return t;
|
|
50590
|
-
return `${t.slice(0, max - 1)}\u2026`;
|
|
50591
|
-
}
|
|
50592
|
-
function collectPaths3(args, out) {
|
|
50593
|
-
if (!args || typeof args !== "object") return;
|
|
50594
|
-
const obj = args;
|
|
50595
|
-
for (const key of ["path", "file", "filepath", "filePath", "target", "cwd"]) {
|
|
50596
|
-
const v = obj[key];
|
|
50597
|
-
if (typeof v === "string" && v.length > 1 && v.length < 260) {
|
|
50598
|
-
out.add(v.replace(/\\/g, "/"));
|
|
50599
|
-
}
|
|
50600
|
-
}
|
|
50601
|
-
if (typeof obj.file_path === "string") out.add(String(obj.file_path));
|
|
50602
|
-
}
|
|
50603
|
-
function collectPathsFromText(text, out) {
|
|
50604
|
-
const re = /(?:^|[\s"'`])((?:[\w.-]+\/)+[\w.-]+\.\w{1,8})/g;
|
|
50605
|
-
let m;
|
|
50606
|
-
let n = 0;
|
|
50607
|
-
while ((m = re.exec(text)) !== null && n < 8) {
|
|
50608
|
-
out.add(m[1]);
|
|
50609
|
-
n += 1;
|
|
50610
|
-
}
|
|
50611
|
-
}
|
|
50612
|
-
var MAX_SUMMARY_CHARS;
|
|
50613
|
-
var init_historySummary = __esm({
|
|
50614
|
-
"src/cli/budget/historySummary.ts"() {
|
|
50615
|
-
"use strict";
|
|
50616
|
-
MAX_SUMMARY_CHARS = 3500;
|
|
50617
|
-
}
|
|
50618
|
-
});
|
|
50619
|
-
|
|
50620
|
-
// src/cli/budget/llmCompact.ts
|
|
50621
|
-
function isLlmCompactEnabled() {
|
|
50622
|
-
const v = process.env.ZELARI_LLM_COMPACT?.trim().toLowerCase();
|
|
50623
|
-
if (v === "0" || v === "false" || v === "off" || v === "no") return false;
|
|
50624
|
-
return true;
|
|
50625
|
-
}
|
|
50626
|
-
function compactModelOverride() {
|
|
50627
|
-
const v = process.env.ZELARI_COMPACT_MODEL?.trim();
|
|
50628
|
-
return v ? v : void 0;
|
|
50629
|
-
}
|
|
50630
|
-
async function llmSummarizeHistoryReplay(input) {
|
|
50631
|
-
const override = input.overrideModel ?? compactModelOverride();
|
|
50632
|
-
const model = override ?? input.model;
|
|
50633
|
-
const cacheReuseExpected = !override;
|
|
50634
|
-
if (!isLlmCompactEnabled()) return { summary: null, model, cacheReuseExpected };
|
|
50635
|
-
if (input.droppedMessages.length === 0) {
|
|
50636
|
-
return { summary: null, model, cacheReuseExpected };
|
|
50637
|
-
}
|
|
50638
|
-
const messages = [
|
|
50639
|
-
...input.systemMessages,
|
|
50640
|
-
...input.droppedMessages,
|
|
50641
|
-
{
|
|
50642
|
-
role: "user",
|
|
50643
|
-
content: COMPACTION_INSTRUCTION
|
|
50644
|
-
}
|
|
50645
|
-
];
|
|
50646
|
-
const controller = new AbortController();
|
|
50647
|
-
const timeout = setTimeout(() => controller.abort(), REPLAY_TIMEOUT_MS);
|
|
50648
|
-
const onOuterAbort = () => controller.abort();
|
|
50649
|
-
input.signal?.addEventListener("abort", onOuterAbort, { once: true });
|
|
50650
|
-
try {
|
|
50651
|
-
let text = "";
|
|
50652
|
-
let emittedToolCall = false;
|
|
50653
|
-
for await (const delta of input.providerStream({
|
|
50654
|
-
provider: input.provider,
|
|
50655
|
-
model,
|
|
50656
|
-
messages,
|
|
50657
|
-
// Tools stay advertised: dropping them would change the prefix token
|
|
50658
|
-
// sequence and destroy cache reuse (explicit DSH decision). They are
|
|
50659
|
-
// sorted canonically (same discipline as the live routed request and
|
|
50660
|
-
// the snapshot fingerprints) so the replay prefix is byte-identical.
|
|
50661
|
-
tools: [...input.tools].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0),
|
|
50662
|
-
signal: controller.signal,
|
|
50663
|
-
generation: {
|
|
50664
|
-
purpose: "compaction",
|
|
50665
|
-
temperature: 0.1,
|
|
50666
|
-
maxTokens: 900
|
|
50667
|
-
}
|
|
50668
|
-
})) {
|
|
50669
|
-
if (delta.kind === "text") text += delta.delta;
|
|
50670
|
-
if (delta.kind === "tool_call") emittedToolCall = true;
|
|
50671
|
-
}
|
|
50672
|
-
if (emittedToolCall) return { summary: null, model, cacheReuseExpected };
|
|
50673
|
-
if (!text.trim()) return { summary: null, model, cacheReuseExpected };
|
|
50674
|
-
return { summary: text.trim(), model, cacheReuseExpected };
|
|
50675
|
-
} catch {
|
|
50676
|
-
return { summary: null, model, cacheReuseExpected };
|
|
50677
|
-
} finally {
|
|
50678
|
-
clearTimeout(timeout);
|
|
50679
|
-
input.signal?.removeEventListener("abort", onOuterAbort);
|
|
50680
|
-
}
|
|
50681
|
-
}
|
|
50682
|
-
var COMPACTION_INSTRUCTION, REPLAY_TIMEOUT_MS;
|
|
50683
|
-
var init_llmCompact = __esm({
|
|
50684
|
-
"src/cli/budget/llmCompact.ts"() {
|
|
50685
|
-
"use strict";
|
|
50686
|
-
COMPACTION_INSTRUCTION = `
|
|
50687
|
-
You are now acting as a compaction engine for this coding-agent session.
|
|
50688
|
-
|
|
50689
|
-
Condense the conversation ABOVE into a compact checkpoint sufficient to continue the task.
|
|
50690
|
-
|
|
50691
|
-
Preserve:
|
|
50692
|
-
- user's goal and evolving intent
|
|
50693
|
-
- decisions already made
|
|
50694
|
-
- exact file paths and identifiers
|
|
50695
|
-
- code changes already completed
|
|
50696
|
-
- commands/errors that still matter
|
|
50697
|
-
- constraints
|
|
50698
|
-
- unfinished work
|
|
50699
|
-
- the single most likely next action
|
|
50700
|
-
|
|
50701
|
-
Do not call tools.
|
|
50702
|
-
Do not mention this summarization request.
|
|
50703
|
-
Output only the checkpoint.
|
|
50704
|
-
Be concise.
|
|
50705
|
-
`.trim();
|
|
50706
|
-
REPLAY_TIMEOUT_MS = 6e4;
|
|
51178
|
+
return "";
|
|
51179
|
+
}
|
|
51180
|
+
async close() {
|
|
51181
|
+
}
|
|
51182
|
+
};
|
|
50707
51183
|
}
|
|
50708
51184
|
});
|
|
50709
51185
|
|
|
50710
|
-
// src/cli/hooks/
|
|
50711
|
-
function
|
|
50712
|
-
|
|
50713
|
-
|
|
50714
|
-
|
|
50715
|
-
|
|
50716
|
-
const hasCompactRange = typeof m.compactedFromSeq === "number" && Number.isInteger(m.compactedFromSeq) && m.compactedFromSeq > 0 && typeof m.compactedToSeq === "number" && Number.isInteger(m.compactedToSeq) && m.compactedToSeq >= m.compactedFromSeq;
|
|
50717
|
-
if (hasCompactRange) {
|
|
50718
|
-
seqs.push(m.compactedFromSeq, m.compactedToSeq);
|
|
50719
|
-
sources.push(...m.sourceEventSeqs ?? []);
|
|
50720
|
-
if (typeof m.seq === "number" && Number.isInteger(m.seq) && m.seq > 0) {
|
|
50721
|
-
seqs.push(m.seq);
|
|
50722
|
-
sources.push(m.seq);
|
|
50723
|
-
}
|
|
50724
|
-
continue;
|
|
50725
|
-
}
|
|
50726
|
-
if (typeof m.seq !== "number" || !Number.isInteger(m.seq) || m.seq < 1) return void 0;
|
|
50727
|
-
seqs.push(m.seq);
|
|
50728
|
-
sources.push(m.seq);
|
|
50729
|
-
}
|
|
50730
|
-
return {
|
|
50731
|
-
fromSeq: Math.min(...seqs),
|
|
50732
|
-
toSeq: Math.max(...seqs),
|
|
50733
|
-
sourceEventSeqs: [...new Set(sources)]
|
|
50734
|
-
};
|
|
50735
|
-
}
|
|
50736
|
-
function withDroppedRange(result, dropped, strategy) {
|
|
50737
|
-
const range = compactedRangeFromDropped(dropped);
|
|
50738
|
-
if (!range) return { ...result, strategy };
|
|
50739
|
-
return { ...result, ...range, strategy };
|
|
51186
|
+
// src/cli/hooks/messageHelpers.ts
|
|
51187
|
+
function appendSystem(setMessages, content, ts = Date.now()) {
|
|
51188
|
+
setMessages((prev2) => [
|
|
51189
|
+
...prev2,
|
|
51190
|
+
{ id: crypto.randomUUID(), role: "system", content, ts }
|
|
51191
|
+
]);
|
|
50740
51192
|
}
|
|
50741
|
-
function
|
|
50742
|
-
|
|
50743
|
-
|
|
50744
|
-
|
|
50745
|
-
|
|
50746
|
-
}
|
|
50747
|
-
if (turns <= 0) return 0;
|
|
50748
|
-
if (opts?.force && opts?.maxMessages) return Math.max(1, opts.maxMessages);
|
|
50749
|
-
return turns * 4;
|
|
51193
|
+
function appendUser(setMessages, content, ts = Date.now()) {
|
|
51194
|
+
setMessages((prev2) => [
|
|
51195
|
+
...prev2,
|
|
51196
|
+
{ id: crypto.randomUUID(), role: "user", content, ts }
|
|
51197
|
+
]);
|
|
50750
51198
|
}
|
|
50751
|
-
function
|
|
50752
|
-
|
|
50753
|
-
|
|
50754
|
-
|
|
50755
|
-
|
|
50756
|
-
for (const m of kept) {
|
|
50757
|
-
if (m.role === "assistant" && m.toolCalls) {
|
|
50758
|
-
for (const tc of m.toolCalls) declared.add(tc.id);
|
|
50759
|
-
}
|
|
51199
|
+
function appendOrExtendStreamingAssistant(setMessages, fullContent, ts, memberContext) {
|
|
51200
|
+
setMessages((prev2) => {
|
|
51201
|
+
const last = prev2[prev2.length - 1];
|
|
51202
|
+
if (last && last.role === "assistant" && last.id.startsWith("streaming-")) {
|
|
51203
|
+
return [...prev2.slice(0, -1), { ...last, content: fullContent }];
|
|
50760
51204
|
}
|
|
50761
|
-
|
|
50762
|
-
|
|
50763
|
-
|
|
50764
|
-
|
|
50765
|
-
|
|
50766
|
-
|
|
50767
|
-
|
|
50768
|
-
|
|
50769
|
-
|
|
50770
|
-
break;
|
|
50771
|
-
}
|
|
50772
|
-
}
|
|
50773
|
-
break;
|
|
51205
|
+
return [
|
|
51206
|
+
...prev2,
|
|
51207
|
+
{
|
|
51208
|
+
id: `streaming-${crypto.randomUUID()}`,
|
|
51209
|
+
role: "assistant",
|
|
51210
|
+
content: fullContent,
|
|
51211
|
+
ts,
|
|
51212
|
+
...memberContext?.memberId ? { memberId: memberContext.memberId } : {},
|
|
51213
|
+
...memberContext?.memberName ? { memberName: memberContext.memberName } : {}
|
|
50774
51214
|
}
|
|
50775
|
-
|
|
50776
|
-
if (!moved) break;
|
|
50777
|
-
}
|
|
50778
|
-
return cut;
|
|
50779
|
-
}
|
|
50780
|
-
function resolvePruneLimits(opts) {
|
|
50781
|
-
const maxChars = opts?.maxChars ?? envNumber(process.env.ZELARI_TOOL_RESULT_MAX_CHARS, { default: 8e3, min: 256 });
|
|
50782
|
-
const rawTail = opts?.tailChars ?? envNumber(process.env.ZELARI_TOOL_RESULT_TAIL_CHARS, { default: 1e3, min: 0 });
|
|
50783
|
-
const tailChars = Math.min(rawTail, maxChars);
|
|
50784
|
-
return { maxChars, tailChars };
|
|
50785
|
-
}
|
|
50786
|
-
function pruneToolResultsDetailed(messages, opts) {
|
|
50787
|
-
const { maxChars, tailChars } = resolvePruneLimits(opts);
|
|
50788
|
-
const headChars = maxChars - tailChars;
|
|
50789
|
-
const stats = { pruned: 0, charsOmitted: 0 };
|
|
50790
|
-
let changed = false;
|
|
50791
|
-
const out = messages.map((m) => {
|
|
50792
|
-
if (m.role !== "tool") return m;
|
|
50793
|
-
const body = m.content ?? "";
|
|
50794
|
-
if (body.length <= maxChars) return m;
|
|
50795
|
-
const head = headChars > 0 ? body.slice(0, headChars) : "";
|
|
50796
|
-
const tail2 = tailChars > 0 ? body.slice(-tailChars) : "";
|
|
50797
|
-
const omitted = body.length - head.length - tail2.length;
|
|
50798
|
-
changed = true;
|
|
50799
|
-
stats.pruned += 1;
|
|
50800
|
-
stats.charsOmitted += omitted;
|
|
50801
|
-
return {
|
|
50802
|
-
...m,
|
|
50803
|
-
content: [head, "\u2026[pruned " + omitted + " chars]\u2026", tail2].join(String.fromCharCode(10))
|
|
50804
|
-
};
|
|
51215
|
+
];
|
|
50805
51216
|
});
|
|
50806
|
-
return {
|
|
50807
|
-
messages: changed ? out : messages,
|
|
50808
|
-
stats
|
|
50809
|
-
};
|
|
50810
|
-
}
|
|
50811
|
-
function compactHistory(messages, opts) {
|
|
50812
|
-
return compactHistoryDetailed(messages, opts).messages;
|
|
50813
|
-
}
|
|
50814
|
-
function buildCheckpointMessage(summaryText, range) {
|
|
50815
|
-
return {
|
|
50816
|
-
role: "user",
|
|
50817
|
-
content: CHECKPOINT_WRAPPER_PREFIX + "\n\n<compacted-summary>\n" + summaryText + "\n</compacted-summary>",
|
|
50818
|
-
...range ? {
|
|
50819
|
-
compactedFromSeq: range.fromSeq,
|
|
50820
|
-
compactedToSeq: range.toSeq,
|
|
50821
|
-
sourceEventSeqs: [...range.sourceEventSeqs]
|
|
50822
|
-
} : {}
|
|
50823
|
-
};
|
|
50824
51217
|
}
|
|
50825
|
-
function
|
|
50826
|
-
const
|
|
50827
|
-
|
|
50828
|
-
|
|
50829
|
-
{ messages: [], compacted: true, messagesRemoved: messages.length, summary: "" },
|
|
50830
|
-
messages,
|
|
50831
|
-
"extractive"
|
|
50832
|
-
);
|
|
50833
|
-
}
|
|
50834
|
-
if (messages.length <= maxMessages * 2 && !opts?.force) {
|
|
50835
|
-
return {
|
|
50836
|
-
messages,
|
|
50837
|
-
compacted: false,
|
|
50838
|
-
messagesRemoved: 0,
|
|
50839
|
-
summary: ""
|
|
50840
|
-
};
|
|
50841
|
-
}
|
|
50842
|
-
const naiveCut = Math.max(0, messages.length - maxMessages);
|
|
50843
|
-
const cut = findValidCutIndex(messages, naiveCut);
|
|
50844
|
-
if (cut === 0) {
|
|
50845
|
-
return {
|
|
50846
|
-
messages,
|
|
50847
|
-
compacted: false,
|
|
50848
|
-
messagesRemoved: 0,
|
|
50849
|
-
summary: ""
|
|
50850
|
-
};
|
|
50851
|
-
}
|
|
50852
|
-
const droppedMsgs = messages.slice(0, cut);
|
|
50853
|
-
const droppedRange = compactedRangeFromDropped(droppedMsgs);
|
|
50854
|
-
const pruned = pruneToolResultsDetailed(messages.slice(cut));
|
|
50855
|
-
const kept = pruned.messages;
|
|
50856
|
-
const summaryText = extractiveHistorySummary(droppedMsgs);
|
|
50857
|
-
const summary = buildCheckpointMessage(
|
|
50858
|
-
summaryText || `${COMPACT_MARKER} ${cut} earlier message(s) dropped.`,
|
|
50859
|
-
droppedRange
|
|
50860
|
-
);
|
|
50861
|
-
return withDroppedRange(
|
|
51218
|
+
function appendToolStart(setMessages, toolName, toolCallId, args, ts) {
|
|
51219
|
+
const argsPreview = formatToolSummary(toolName, args);
|
|
51220
|
+
setMessages((prev2) => [
|
|
51221
|
+
...prev2,
|
|
50862
51222
|
{
|
|
50863
|
-
|
|
50864
|
-
|
|
50865
|
-
|
|
50866
|
-
|
|
50867
|
-
|
|
50868
|
-
|
|
50869
|
-
|
|
50870
|
-
|
|
50871
|
-
|
|
51223
|
+
id: crypto.randomUUID(),
|
|
51224
|
+
role: "tool",
|
|
51225
|
+
content: argsPreview,
|
|
51226
|
+
ts,
|
|
51227
|
+
toolName,
|
|
51228
|
+
toolCallId,
|
|
51229
|
+
toolOk: void 0,
|
|
51230
|
+
toolDurationMs: void 0
|
|
51231
|
+
}
|
|
51232
|
+
]);
|
|
50872
51233
|
}
|
|
50873
|
-
|
|
50874
|
-
|
|
50875
|
-
|
|
50876
|
-
|
|
50877
|
-
|
|
50878
|
-
|
|
50879
|
-
|
|
50880
|
-
|
|
50881
|
-
|
|
50882
|
-
|
|
50883
|
-
|
|
50884
|
-
|
|
50885
|
-
|
|
50886
|
-
|
|
50887
|
-
|
|
50888
|
-
|
|
50889
|
-
|
|
50890
|
-
|
|
50891
|
-
|
|
50892
|
-
signal: opts?.signal
|
|
50893
|
-
});
|
|
50894
|
-
cacheReuseExpected = replay.cacheReuseExpected;
|
|
50895
|
-
if (replay.summary && replay.summary.trim().length > 40) {
|
|
50896
|
-
const sourceTokens = roughTokens(droppedMsgs);
|
|
50897
|
-
const summaryTok = Math.ceil(replay.summary.length / 4);
|
|
50898
|
-
if (summaryTok < sourceTokens) {
|
|
50899
|
-
summaryText = replay.summary.trim();
|
|
50900
|
-
}
|
|
51234
|
+
function updateToolMessageEnd(setMessages, toolCallId, isError, durationMs, result) {
|
|
51235
|
+
setMessages((prev2) => {
|
|
51236
|
+
for (let i = prev2.length - 1; i >= 0; i--) {
|
|
51237
|
+
const m = prev2[i];
|
|
51238
|
+
if (m && m.role === "tool" && m.toolCallId === toolCallId && m.toolDurationMs === void 0) {
|
|
51239
|
+
const updated = [...prev2];
|
|
51240
|
+
updated[i] = {
|
|
51241
|
+
...m,
|
|
51242
|
+
toolOk: !isError,
|
|
51243
|
+
toolDurationMs: durationMs,
|
|
51244
|
+
...result !== void 0 ? {
|
|
51245
|
+
toolResult: toolResultForStorage(
|
|
51246
|
+
m.toolName ?? "",
|
|
51247
|
+
result,
|
|
51248
|
+
isError
|
|
51249
|
+
)
|
|
51250
|
+
} : {}
|
|
51251
|
+
};
|
|
51252
|
+
return updated;
|
|
50901
51253
|
}
|
|
50902
|
-
} catch {
|
|
50903
51254
|
}
|
|
50904
|
-
|
|
50905
|
-
|
|
50906
|
-
const kept = pruned.messages;
|
|
50907
|
-
const summary = buildCheckpointMessage(summaryText, compactedRangeFromDropped(droppedMsgs));
|
|
50908
|
-
const usedLlm = summaryText !== extractive && summaryText.trim().length > 40;
|
|
50909
|
-
return withDroppedRange(
|
|
50910
|
-
{
|
|
50911
|
-
messages: [summary, ...kept],
|
|
50912
|
-
compacted: true,
|
|
50913
|
-
messagesRemoved: cut,
|
|
50914
|
-
summary: summaryText,
|
|
50915
|
-
prunedToolResults: pruned.stats.pruned,
|
|
50916
|
-
cacheReuseExpected,
|
|
50917
|
-
replayExactPrefix
|
|
50918
|
-
},
|
|
50919
|
-
droppedMsgs,
|
|
50920
|
-
usedLlm ? "llm" : "extractive"
|
|
50921
|
-
);
|
|
51255
|
+
return prev2;
|
|
51256
|
+
});
|
|
50922
51257
|
}
|
|
50923
|
-
function
|
|
50924
|
-
|
|
50925
|
-
|
|
50926
|
-
|
|
50927
|
-
|
|
50928
|
-
|
|
50929
|
-
|
|
50930
|
-
|
|
51258
|
+
function finalizeStreamingAssistant(setMessages) {
|
|
51259
|
+
setMessages((prev2) => {
|
|
51260
|
+
const last = prev2[prev2.length - 1];
|
|
51261
|
+
if (last && last.role === "assistant" && last.id.startsWith("streaming-")) {
|
|
51262
|
+
return [
|
|
51263
|
+
...prev2.slice(0, -1),
|
|
51264
|
+
{ ...last, id: last.id.slice("streaming-".length) }
|
|
51265
|
+
];
|
|
50931
51266
|
}
|
|
50932
|
-
|
|
50933
|
-
|
|
51267
|
+
return prev2;
|
|
51268
|
+
});
|
|
50934
51269
|
}
|
|
50935
|
-
var
|
|
50936
|
-
|
|
50937
|
-
"src/cli/hooks/historyCompaction.ts"() {
|
|
51270
|
+
var init_messageHelpers = __esm({
|
|
51271
|
+
"src/cli/hooks/messageHelpers.ts"() {
|
|
50938
51272
|
"use strict";
|
|
50939
|
-
|
|
50940
|
-
|
|
50941
|
-
init_envNumber();
|
|
50942
|
-
COMPACT_MARKER = "[history] Earlier turns were compacted to stay within the context budget.";
|
|
50943
|
-
CHECKPOINT_WRAPPER_PREFIX = "This is an automatically generated checkpoint of earlier conversation. Treat it as established context and continue directly.";
|
|
51273
|
+
init_toolFormat();
|
|
51274
|
+
init_toolFormat();
|
|
50944
51275
|
}
|
|
50945
51276
|
});
|
|
50946
51277
|
|
|
@@ -51253,215 +51584,6 @@ var init_phase = __esm({
|
|
|
51253
51584
|
}
|
|
51254
51585
|
});
|
|
51255
51586
|
|
|
51256
|
-
// src/cli/budget/tokenBudget.ts
|
|
51257
|
-
function mergeCompactRange(into, r) {
|
|
51258
|
-
if (r.fromSeq !== void 0 && r.toSeq !== void 0) {
|
|
51259
|
-
into.fromSeq = into.fromSeq === void 0 ? r.fromSeq : Math.min(into.fromSeq, r.fromSeq);
|
|
51260
|
-
into.toSeq = into.toSeq === void 0 ? r.toSeq : Math.max(into.toSeq, r.toSeq);
|
|
51261
|
-
if (r.sourceEventSeqs) into.sourceSeqs.push(...r.sourceEventSeqs);
|
|
51262
|
-
}
|
|
51263
|
-
if (r.strategy === "llm") into.strategy = "llm";
|
|
51264
|
-
else if (r.strategy && !into.strategy) into.strategy = r.strategy;
|
|
51265
|
-
}
|
|
51266
|
-
function estimateTokens2(text) {
|
|
51267
|
-
if (!text) return 0;
|
|
51268
|
-
return Math.max(1, Math.ceil(text.length / 4));
|
|
51269
|
-
}
|
|
51270
|
-
function estimateHistoryTokens(messages) {
|
|
51271
|
-
let n = 0;
|
|
51272
|
-
for (const m of messages) {
|
|
51273
|
-
n += estimateTokens2(m.content);
|
|
51274
|
-
if (m.toolCalls) {
|
|
51275
|
-
for (const tc of m.toolCalls) {
|
|
51276
|
-
n += estimateTokens2(tc.name) + estimateTokens2(JSON.stringify(tc.args ?? {}));
|
|
51277
|
-
}
|
|
51278
|
-
}
|
|
51279
|
-
}
|
|
51280
|
-
return n;
|
|
51281
|
-
}
|
|
51282
|
-
function defaultContextLimitForModel(model, provider) {
|
|
51283
|
-
return capabilitiesFor(model, provider).contextWindow;
|
|
51284
|
-
}
|
|
51285
|
-
function resolveContextLimit(model, provider) {
|
|
51286
|
-
return envNumber(process.env.ZELARI_CONTEXT_LIMIT, {
|
|
51287
|
-
default: defaultContextLimitForModel(model, provider),
|
|
51288
|
-
min: 4e3,
|
|
51289
|
-
max: 2e6
|
|
51290
|
-
});
|
|
51291
|
-
}
|
|
51292
|
-
function phaseKnobs(phase2) {
|
|
51293
|
-
return {
|
|
51294
|
-
historyTurns: phase2 === "plan" ? envNumber(process.env.ZELARI_HISTORY_TURNS, { default: 8, min: 0 }) : envNumber(process.env.ZELARI_HISTORY_TURNS, { default: 6, min: 0 }),
|
|
51295
|
-
maxToolLoopIterations: phase2 === "plan" ? envNumber(process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS, { default: 60, min: 1 }) : envNumber(process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS, {
|
|
51296
|
-
default: 120,
|
|
51297
|
-
min: 1
|
|
51298
|
-
})
|
|
51299
|
-
};
|
|
51300
|
-
}
|
|
51301
|
-
async function applyBudgetPolicyAsync(history2, phase2, opts) {
|
|
51302
|
-
const contextLimit = resolveContextLimit(opts?.model, opts?.provider);
|
|
51303
|
-
const compact3 = capabilitiesFor(opts?.model, opts?.provider).compaction;
|
|
51304
|
-
const sessionExtra = opts?.sessionTokens ?? 0;
|
|
51305
|
-
const warnings = [];
|
|
51306
|
-
let { historyTurns, maxToolLoopIterations } = phaseKnobs(phase2);
|
|
51307
|
-
const envelope = opts?.requestSnapshot ?? null;
|
|
51308
|
-
const surface = envelope?.snapshot ?? opts?.requestSurface ?? null;
|
|
51309
|
-
const replayBase = surface ? {
|
|
51310
|
-
provider: surface.provider,
|
|
51311
|
-
model: surface.model,
|
|
51312
|
-
systemMessages: surface.systemMessages,
|
|
51313
|
-
tools: surface.tools
|
|
51314
|
-
} : opts?.providerStream ? { provider: "local", model: opts?.model ?? "unknown", systemMessages: [], tools: [] } : null;
|
|
51315
|
-
const headerTokens = surface ? estimateSystemTokensLite(surface.systemMessages) + estimateToolSchemaTokensLite(surface.tools) : 0;
|
|
51316
|
-
const convTokensOf = (h) => estimateConversationTokensLite(h);
|
|
51317
|
-
let hist = history2;
|
|
51318
|
-
let estimated = surface ? headerTokens + convTokensOf(hist) + RESERVED_OUTPUT_TOKENS : estimateHistoryTokens(hist) + sessionExtra;
|
|
51319
|
-
let occupancy = Math.min(1, estimated / contextLimit);
|
|
51320
|
-
let compactSummary = "";
|
|
51321
|
-
let messagesRemoved = 0;
|
|
51322
|
-
let cacheReuseExpected;
|
|
51323
|
-
let prunedTotal = 0;
|
|
51324
|
-
const compactRange = { sourceSeqs: [] };
|
|
51325
|
-
if (occupancy >= compact3.warnAt && occupancy < compact3.compactAt) {
|
|
51326
|
-
warnings.push(
|
|
51327
|
-
`[budget] context ~${Math.round(occupancy * 100)}% full (${estimated}/${contextLimit} tok full-request est.) \u2014 consider /compact or shorter replies.`
|
|
51328
|
-
);
|
|
51329
|
-
}
|
|
51330
|
-
if (occupancy >= 0.8) {
|
|
51331
|
-
const pruned = pruneToolResultsDetailed(hist);
|
|
51332
|
-
if (pruned.stats.pruned > 0) {
|
|
51333
|
-
hist = pruned.messages;
|
|
51334
|
-
prunedTotal += pruned.stats.pruned;
|
|
51335
|
-
estimated = surface ? headerTokens + convTokensOf(hist) + RESERVED_OUTPUT_TOKENS : estimateHistoryTokens(hist) + sessionExtra;
|
|
51336
|
-
occupancy = Math.min(1, estimated / contextLimit);
|
|
51337
|
-
warnings.push(
|
|
51338
|
-
`[budget] pruned ${pruned.stats.pruned} oversized tool result(s) \u2192 ${Math.round(occupancy * 100)}% (${estimated} tok).`
|
|
51339
|
-
);
|
|
51340
|
-
}
|
|
51341
|
-
}
|
|
51342
|
-
const fold = (r, label, forcedTurns) => {
|
|
51343
|
-
hist = applySessionSurface(r.messages);
|
|
51344
|
-
if (r.compacted) {
|
|
51345
|
-
messagesRemoved += r.messagesRemoved;
|
|
51346
|
-
if (r.summary) compactSummary = r.summary;
|
|
51347
|
-
mergeCompactRange(compactRange, r);
|
|
51348
|
-
if (r.cacheReuseExpected !== void 0) {
|
|
51349
|
-
cacheReuseExpected = r.cacheReuseExpected;
|
|
51350
|
-
}
|
|
51351
|
-
}
|
|
51352
|
-
estimated = surface ? headerTokens + convTokensOf(hist) + RESERVED_OUTPUT_TOKENS : estimateHistoryTokens(hist) + sessionExtra;
|
|
51353
|
-
occupancy = Math.min(1, estimated / contextLimit);
|
|
51354
|
-
warnings.push(
|
|
51355
|
-
`[budget] ${label} \u2014 kept ~${forcedTurns} turns (${estimated} tok est.` + (r.messagesRemoved ? `, removed ${r.messagesRemoved} msgs` : "") + (r.cacheReuseExpected === false ? ", cache reuse NOT expected (model override)" : "") + ")."
|
|
51356
|
-
);
|
|
51357
|
-
};
|
|
51358
|
-
if (occupancy >= compact3.compactAt) {
|
|
51359
|
-
const forcedTurns = Math.max(1, Math.floor(historyTurns / 2));
|
|
51360
|
-
historyTurns = forcedTurns;
|
|
51361
|
-
maxToolLoopIterations = Math.min(
|
|
51362
|
-
maxToolLoopIterations,
|
|
51363
|
-
phase2 === "plan" ? 24 : 40
|
|
51364
|
-
);
|
|
51365
|
-
let r = await compactHistoryAsync(hist, {
|
|
51366
|
-
maxMessages: Math.max(2, forcedTurns * 4),
|
|
51367
|
-
force: true,
|
|
51368
|
-
signal: opts?.signal,
|
|
51369
|
-
...replayBase ? { requestSnapshot: replayBase, providerStream: opts?.providerStream } : {}
|
|
51370
|
-
});
|
|
51371
|
-
if (!r.compacted) {
|
|
51372
|
-
r = await compactHistoryAsync(hist, {
|
|
51373
|
-
maxMessages: 2,
|
|
51374
|
-
force: true,
|
|
51375
|
-
signal: opts?.signal,
|
|
51376
|
-
...replayBase ? { requestSnapshot: replayBase, providerStream: opts?.providerStream } : {}
|
|
51377
|
-
});
|
|
51378
|
-
}
|
|
51379
|
-
const label = r.cacheReuseExpected === false ? "llm-compact (model override)" : "auto-compact";
|
|
51380
|
-
fold(r, label, forcedTurns);
|
|
51381
|
-
}
|
|
51382
|
-
if (occupancy >= compact3.hardAt) {
|
|
51383
|
-
const hard = await compactHistoryAsync(hist, {
|
|
51384
|
-
maxMessages: 2,
|
|
51385
|
-
force: true,
|
|
51386
|
-
signal: opts?.signal
|
|
51387
|
-
});
|
|
51388
|
-
fold(hard, hard.summary.includes("\xB7 llm") ? "llm-compact" : "HARD trim", 2);
|
|
51389
|
-
historyTurns = 2;
|
|
51390
|
-
maxToolLoopIterations = Math.min(maxToolLoopIterations, 16);
|
|
51391
|
-
warnings.push(
|
|
51392
|
-
"[budget] HARD context pressure (\u226595%) \u2014 prefer /clear or a new session if quality drops."
|
|
51393
|
-
);
|
|
51394
|
-
}
|
|
51395
|
-
const cacheMetricsLine = envelope ? [
|
|
51396
|
-
"compaction meter:",
|
|
51397
|
-
`provider/model: ${envelope.snapshot.provider}/${envelope.snapshot.model}`,
|
|
51398
|
-
`headerFingerprint: ${envelope.snapshot.headerFingerprint.slice(0, 12)}`,
|
|
51399
|
-
`occupancy: ${Math.round(occupancy * 100)}% (${estimated}/${contextLimit})`,
|
|
51400
|
-
...envelope.usage?.cachedPromptTokens !== void 0 ? [`cachedPromptTokens: ${envelope.usage.cachedPromptTokens}`] : [],
|
|
51401
|
-
...cacheReuseExpected !== void 0 ? [`cacheReuseExpected: ${cacheReuseExpected}`] : []
|
|
51402
|
-
].join(" | ") : void 0;
|
|
51403
|
-
return {
|
|
51404
|
-
history: hist,
|
|
51405
|
-
warnings,
|
|
51406
|
-
maxToolLoopIterations,
|
|
51407
|
-
historyTurns,
|
|
51408
|
-
estimatedHistoryTokens: surface ? convTokensOf(hist) : estimated,
|
|
51409
|
-
contextLimit,
|
|
51410
|
-
occupancy,
|
|
51411
|
-
compactSummary: compactSummary || void 0,
|
|
51412
|
-
messagesRemoved: messagesRemoved || void 0,
|
|
51413
|
-
...compactRange.fromSeq !== void 0 && compactRange.toSeq !== void 0 ? {
|
|
51414
|
-
compactedFromSeq: compactRange.fromSeq,
|
|
51415
|
-
compactedToSeq: compactRange.toSeq,
|
|
51416
|
-
compactSourceSeqs: compactRange.sourceSeqs,
|
|
51417
|
-
compactStrategy: compactRange.strategy
|
|
51418
|
-
} : {},
|
|
51419
|
-
...surface ? { contextPressureTokens: estimated } : {},
|
|
51420
|
-
...cacheReuseExpected !== void 0 ? { cacheReuseExpected } : {},
|
|
51421
|
-
...cacheMetricsLine ? { cacheMetricsLine } : {}
|
|
51422
|
-
};
|
|
51423
|
-
}
|
|
51424
|
-
function estimateSystemTokensLite(systemMessages) {
|
|
51425
|
-
let n = 0;
|
|
51426
|
-
for (const m of systemMessages) n += 4 + Math.ceil((m.content ?? "").length / 4);
|
|
51427
|
-
return n;
|
|
51428
|
-
}
|
|
51429
|
-
function estimateToolSchemaTokensLite(tools) {
|
|
51430
|
-
let n = 0;
|
|
51431
|
-
for (const t of tools) {
|
|
51432
|
-
n += Math.ceil((t.name ?? "").length / 4);
|
|
51433
|
-
n += Math.ceil((t.description ?? "").length / 4);
|
|
51434
|
-
n += Math.ceil(JSON.stringify(t.parameters ?? {}).length / 4);
|
|
51435
|
-
}
|
|
51436
|
-
return n + tools.length * 4;
|
|
51437
|
-
}
|
|
51438
|
-
function estimateConversationTokensLite(messages) {
|
|
51439
|
-
let n = 0;
|
|
51440
|
-
for (const m of messages) {
|
|
51441
|
-
n += 4 + Math.ceil((m.content ?? "").length / 4);
|
|
51442
|
-
if (m.toolCalls) {
|
|
51443
|
-
for (const tc of m.toolCalls) {
|
|
51444
|
-
n += Math.ceil(tc.name.length / 4) + Math.ceil(tc.id.length / 4);
|
|
51445
|
-
n += Math.ceil(JSON.stringify(tc.args ?? {}).length / 4);
|
|
51446
|
-
}
|
|
51447
|
-
}
|
|
51448
|
-
if (m.reasoningContent) n += Math.ceil(m.reasoningContent.length / 4);
|
|
51449
|
-
if (m.toolCallId) n += Math.ceil(m.toolCallId.length / 4);
|
|
51450
|
-
}
|
|
51451
|
-
return n;
|
|
51452
|
-
}
|
|
51453
|
-
var RESERVED_OUTPUT_TOKENS;
|
|
51454
|
-
var init_tokenBudget = __esm({
|
|
51455
|
-
"src/cli/budget/tokenBudget.ts"() {
|
|
51456
|
-
"use strict";
|
|
51457
|
-
init_envNumber();
|
|
51458
|
-
init_historyCompaction();
|
|
51459
|
-
init_observationStore();
|
|
51460
|
-
init_capabilities();
|
|
51461
|
-
RESERVED_OUTPUT_TOKENS = 8192;
|
|
51462
|
-
}
|
|
51463
|
-
});
|
|
51464
|
-
|
|
51465
51587
|
// src/cli/budget/requestMeter.ts
|
|
51466
51588
|
function estimateTokensLocal(text) {
|
|
51467
51589
|
if (!text) return 0;
|
|
@@ -66217,11 +66339,14 @@ async function runHeadlessCouncil(opts, provider, model, providerStream, extras)
|
|
|
66217
66339
|
const { composeProjectContext: composeProjectContext2 } = await Promise.resolve().then(() => (init_composeContext(), composeContext_exports));
|
|
66218
66340
|
const { loadDurableContext: loadDurableContext2 } = await Promise.resolve().then(() => (init_loadDurableContext(), loadDurableContext_exports));
|
|
66219
66341
|
const durableState = await loadDurableContext2(cwd);
|
|
66342
|
+
const { resolveRetrievalPolicy: resolveRetrievalPolicy2 } = await Promise.resolve().then(() => (init_retrievalPolicy(), retrievalPolicy_exports));
|
|
66343
|
+
const retrieval = resolveRetrievalPolicy2(councilContext.budget.occupancy);
|
|
66220
66344
|
const memoryContext = nativeMemory ? (await nativeMemory.buildContext({
|
|
66221
66345
|
text: effectiveTask,
|
|
66222
66346
|
useGraph: true,
|
|
66223
|
-
maxChars:
|
|
66224
|
-
maxMemories:
|
|
66347
|
+
maxChars: retrieval.maxChars,
|
|
66348
|
+
maxMemories: retrieval.maxMemories,
|
|
66349
|
+
...retrieval.weights ? { weights: retrieval.weights } : {}
|
|
66225
66350
|
})).text : "";
|
|
66226
66351
|
const composed = composeProjectContext2({
|
|
66227
66352
|
mode: "council",
|
|
@@ -73439,21 +73564,27 @@ function createPermissionAskHandler(opts) {
|
|
|
73439
73564
|
const catLabel = cats.length === 1 ? cats[0] : cats.join("+") || "action";
|
|
73440
73565
|
const title = `Allow tool "${req.toolName}"?`;
|
|
73441
73566
|
const detail = req.reason + (cats.length ? ` [${cats.join(", ")}]` : "");
|
|
73567
|
+
const claimLines = (req.claims ?? []).map((c) => `\xB7 ${c.summary}`);
|
|
73568
|
+
const note = req.policyNote ? `
|
|
73569
|
+
${req.policyNote}` : "";
|
|
73570
|
+
const claimsBlock = claimLines.length ? `
|
|
73571
|
+
Claims:
|
|
73572
|
+
${claimLines.join("\n")}` : "";
|
|
73442
73573
|
appendSystem2?.(
|
|
73443
73574
|
`[permission] ${title}
|
|
73444
|
-
${detail}
|
|
73575
|
+
${detail}${note}${claimsBlock}
|
|
73445
73576
|
\u2192 Allow once \xB7 Always (tool) \xB7 Always (${catLabel}) \xB7 Deny`,
|
|
73446
73577
|
Date.now()
|
|
73447
73578
|
);
|
|
73448
73579
|
let settled = false;
|
|
73449
73580
|
const askTimeoutMs = askUserTimeoutMs();
|
|
73450
73581
|
let cancelAskTimeout = () => void 0;
|
|
73451
|
-
const finish2 = (ok,
|
|
73582
|
+
const finish2 = (ok, note2) => {
|
|
73452
73583
|
if (settled) return;
|
|
73453
73584
|
settled = true;
|
|
73454
73585
|
cancelAskTimeout();
|
|
73455
73586
|
setPicker2(null);
|
|
73456
|
-
if (
|
|
73587
|
+
if (note2) appendSystem2?.(note2, Date.now());
|
|
73457
73588
|
resolve9(ok);
|
|
73458
73589
|
};
|
|
73459
73590
|
cancelAskTimeout = armPickerTimeout(
|
|
@@ -74587,6 +74718,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
74587
74718
|
let councilMemory;
|
|
74588
74719
|
let councilMemoryAutoWrite = false;
|
|
74589
74720
|
let nativeMemoryContext = "";
|
|
74721
|
+
let councilRetrievalBand = "low";
|
|
74590
74722
|
try {
|
|
74591
74723
|
const memoryFactory = await Promise.resolve().then(() => (init_serviceFactory(), serviceFactory_exports));
|
|
74592
74724
|
if (memoryFactory.isMemoryV2Enabled()) {
|
|
@@ -74601,11 +74733,17 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
74601
74733
|
});
|
|
74602
74734
|
councilMemoryAutoWrite = memoryFactory.isMemoryAutoWriteEnabled();
|
|
74603
74735
|
if (!overrides.ragContext) {
|
|
74736
|
+
const { resolveRetrievalPolicy: resolveRetrievalPolicy2 } = await Promise.resolve().then(() => (init_retrievalPolicy(), retrievalPolicy_exports));
|
|
74737
|
+
const retrieval = resolveRetrievalPolicy2(
|
|
74738
|
+
councilContext.budget.occupancy
|
|
74739
|
+
);
|
|
74740
|
+
councilRetrievalBand = retrieval.band;
|
|
74604
74741
|
nativeMemoryContext = (await councilMemory.buildContext({
|
|
74605
74742
|
text: effectiveText,
|
|
74606
74743
|
useGraph: true,
|
|
74607
|
-
maxChars:
|
|
74608
|
-
maxMemories:
|
|
74744
|
+
maxChars: retrieval.maxChars,
|
|
74745
|
+
maxMemories: retrieval.maxMemories,
|
|
74746
|
+
...retrieval.weights ? { weights: retrieval.weights } : {}
|
|
74609
74747
|
})).text;
|
|
74610
74748
|
}
|
|
74611
74749
|
}
|