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.
@@ -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
- ...raw,
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 skills = listCodingSkills();
40731
- if (skills.length === 0) {
41579
+ const band = opts?.pressureBand;
41580
+ const all = listCodingSkills();
41581
+ if (all.length === 0) {
40732
41582
  return "No skills registered.";
40733
41583
  }
40734
- const lines = skills.slice(0, 80).map((s) => {
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, "allow"),
46390
- network: parseAction(process.env.ZELARI_PERMISSION_NETWORK, "allow"),
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/historyCompaction.ts
50711
- function compactedRangeFromDropped(dropped) {
50712
- if (dropped.length === 0) return void 0;
50713
- const seqs = [];
50714
- const sources = [];
50715
- for (const m of dropped) {
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 resolveMaxMessages(opts) {
50742
- const envTurns = envNumber(process.env.ZELARI_HISTORY_TURNS, { default: 6, min: 0 });
50743
- let turns = opts?.maxMessages ? Math.ceil(opts.maxMessages / 4) : envTurns;
50744
- if (opts?.durableStatePresent && !opts?.maxMessages && process.env.ZELARI_HISTORY_TURNS === void 0) {
50745
- turns = Math.min(turns, 3);
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 findValidCutIndex(messages, naiveCut) {
50752
- let cut = naiveCut;
50753
- while (cut < messages.length) {
50754
- const kept = messages.slice(cut);
50755
- const declared = /* @__PURE__ */ new Set();
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
- let moved = false;
50762
- for (let k = 0; k < kept.length; k++) {
50763
- const m = kept[k];
50764
- if (m.role === "tool" && m.toolCallId && !declared.has(m.toolCallId)) {
50765
- for (let j = cut - 1; j >= 0; j--) {
50766
- const prev2 = messages[j];
50767
- if (prev2.role === "assistant" && prev2.toolCalls && prev2.toolCalls.some((tc) => tc.id === m.toolCallId)) {
50768
- cut = j;
50769
- moved = true;
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 compactHistoryDetailed(messages, opts) {
50826
- const maxMessages = resolveMaxMessages(opts);
50827
- if (maxMessages === 0) {
50828
- return withDroppedRange(
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
- messages: [summary, ...kept],
50864
- compacted: true,
50865
- messagesRemoved: cut,
50866
- summary: summary.content,
50867
- prunedToolResults: pruned.stats.pruned
50868
- },
50869
- droppedMsgs,
50870
- "extractive"
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
- async function compactHistoryAsync(messages, opts) {
50874
- const base2 = compactHistoryDetailed(messages, opts);
50875
- if (!base2.compacted || base2.messagesRemoved === 0) return base2;
50876
- const cut = base2.messagesRemoved;
50877
- const droppedMsgs = messages.slice(0, cut);
50878
- const extractive = extractiveHistorySummary(droppedMsgs);
50879
- let summaryText = extractive;
50880
- let cacheReuseExpected;
50881
- let replayExactPrefix;
50882
- const canReplay = !!(opts?.providerStream && opts?.requestSnapshot);
50883
- if (canReplay) {
50884
- try {
50885
- const replay = await llmSummarizeHistoryReplay({
50886
- providerStream: opts.providerStream,
50887
- provider: opts.requestSnapshot.provider,
50888
- model: opts.requestSnapshot.model,
50889
- systemMessages: opts.requestSnapshot.systemMessages,
50890
- tools: opts.requestSnapshot.tools,
50891
- droppedMessages: droppedMsgs,
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
- const pruned = pruneToolResultsDetailed(messages.slice(cut));
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 roughTokens(msgs) {
50924
- let n = 0;
50925
- for (const m of msgs) {
50926
- n += Math.ceil((m.content ?? "").length / 4);
50927
- if (m.toolCalls) {
50928
- for (const tc of m.toolCalls) {
50929
- n += Math.ceil(JSON.stringify(tc.args ?? {}).length / 4);
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
- return Math.max(1, n);
51267
+ return prev2;
51268
+ });
50934
51269
  }
50935
- var COMPACT_MARKER, CHECKPOINT_WRAPPER_PREFIX;
50936
- var init_historyCompaction = __esm({
50937
- "src/cli/hooks/historyCompaction.ts"() {
51270
+ var init_messageHelpers = __esm({
51271
+ "src/cli/hooks/messageHelpers.ts"() {
50938
51272
  "use strict";
50939
- init_historySummary();
50940
- init_llmCompact();
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: 2e3,
66224
- maxMemories: 8
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, note) => {
73582
+ const finish2 = (ok, note2) => {
73452
73583
  if (settled) return;
73453
73584
  settled = true;
73454
73585
  cancelAskTimeout();
73455
73586
  setPicker2(null);
73456
- if (note) appendSystem2?.(note, Date.now());
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: 2e3,
74608
- maxMemories: 8
74744
+ maxChars: retrieval.maxChars,
74745
+ maxMemories: retrieval.maxMemories,
74746
+ ...retrieval.weights ? { weights: retrieval.weights } : {}
74609
74747
  })).text;
74610
74748
  }
74611
74749
  }