zelari-code 1.5.5 → 1.6.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/app.js +13 -2
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/hooks/historyCompaction.js +124 -0
- package/dist/cli/hooks/historyCompaction.js.map +1 -0
- package/dist/cli/hooks/useChatTurn.js +93 -1
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/main.bundled.js +148 -4
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/slashHandlers/provider.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/main.bundled.js
CHANGED
|
@@ -18592,13 +18592,33 @@ var init_AgentHarness = __esm({
|
|
|
18592
18592
|
this.maxQueuedIterations = config2.maxQueuedIterations ?? 3;
|
|
18593
18593
|
this.maxToolLoopIterations = config2.maxToolLoopIterations ?? 30;
|
|
18594
18594
|
}
|
|
18595
|
+
/**
|
|
18596
|
+
* Snapshot of the live transcript (`this.config.messages`) as mutated
|
|
18597
|
+
* across `run()` iterations — the seed passed at construction plus any
|
|
18598
|
+
* assistant turns (with `toolCalls`) and tool results the loop appended.
|
|
18599
|
+
*
|
|
18600
|
+
* Used by the single-agent chat loop to carry rolling history across
|
|
18601
|
+
* turns: after a run completes, the caller reads the tail of this array
|
|
18602
|
+
* (the assistant/tool messages produced this turn) and feeds it back as
|
|
18603
|
+
* the seed for the next turn, so the model sees its own prior question
|
|
18604
|
+
* when the user answers with a short reply.
|
|
18605
|
+
*
|
|
18606
|
+
* The returned reference is the live array — callers MUST treat it as
|
|
18607
|
+
* read-only (do not mutate). Copy (`[...harness.getMessages()]`) before
|
|
18608
|
+
* retaining across runs.
|
|
18609
|
+
*
|
|
18610
|
+
* @since v1.6.0
|
|
18611
|
+
*/
|
|
18612
|
+
getMessages() {
|
|
18613
|
+
return this.config.messages;
|
|
18614
|
+
}
|
|
18595
18615
|
/**
|
|
18596
18616
|
* Member identity fields (memberId + memberName) to merge into every
|
|
18597
18617
|
* event payload. Returns an empty object when the run is a direct
|
|
18598
18618
|
* user prompt (no member context), so call sites can spread it
|
|
18599
18619
|
* unconditionally.
|
|
18600
18620
|
*
|
|
18601
|
-
* @since
|
|
18621
|
+
* @since v0.5.0
|
|
18602
18622
|
*/
|
|
18603
18623
|
memberFields() {
|
|
18604
18624
|
return {
|
|
@@ -33050,6 +33070,14 @@ init_keyStore();
|
|
|
33050
33070
|
init_toolRegistry();
|
|
33051
33071
|
init_skills2();
|
|
33052
33072
|
|
|
33073
|
+
// packages/core/dist/events/index.js
|
|
33074
|
+
init_events();
|
|
33075
|
+
|
|
33076
|
+
// packages/core/dist/index.js
|
|
33077
|
+
init_harness();
|
|
33078
|
+
init_council();
|
|
33079
|
+
init_skills2();
|
|
33080
|
+
|
|
33053
33081
|
// src/cli/hooks/messageHelpers.ts
|
|
33054
33082
|
function appendSystem(setMessages, content, ts = Date.now()) {
|
|
33055
33083
|
setMessages((prev2) => [
|
|
@@ -33135,6 +33163,61 @@ function finalizeStreamingAssistant(setMessages) {
|
|
|
33135
33163
|
});
|
|
33136
33164
|
}
|
|
33137
33165
|
|
|
33166
|
+
// src/cli/hooks/historyCompaction.ts
|
|
33167
|
+
var COMPACT_MARKER = "[history] Earlier turns were compacted to stay within the context budget.";
|
|
33168
|
+
function resolveMaxMessages(opts) {
|
|
33169
|
+
const raw = process.env.ZELARI_HISTORY_TURNS;
|
|
33170
|
+
const parsed = raw ? Number.parseInt(raw, 10) : 6;
|
|
33171
|
+
const envTurns = Number.isFinite(parsed) && parsed >= 0 ? parsed : 6;
|
|
33172
|
+
const turns = opts?.maxMessages ? Math.ceil(opts.maxMessages / 4) : envTurns;
|
|
33173
|
+
if (turns <= 0) return 0;
|
|
33174
|
+
return turns * 4;
|
|
33175
|
+
}
|
|
33176
|
+
function findValidCutIndex(messages, naiveCut) {
|
|
33177
|
+
let cut = naiveCut;
|
|
33178
|
+
while (cut < messages.length) {
|
|
33179
|
+
const kept = messages.slice(cut);
|
|
33180
|
+
const declared = /* @__PURE__ */ new Set();
|
|
33181
|
+
for (const m of kept) {
|
|
33182
|
+
if (m.role === "assistant" && m.toolCalls) {
|
|
33183
|
+
for (const tc of m.toolCalls) declared.add(tc.id);
|
|
33184
|
+
}
|
|
33185
|
+
}
|
|
33186
|
+
let moved = false;
|
|
33187
|
+
for (let k = 0; k < kept.length; k++) {
|
|
33188
|
+
const m = kept[k];
|
|
33189
|
+
if (m.role === "tool" && m.toolCallId && !declared.has(m.toolCallId)) {
|
|
33190
|
+
for (let j = cut - 1; j >= 0; j--) {
|
|
33191
|
+
const prev2 = messages[j];
|
|
33192
|
+
if (prev2.role === "assistant" && prev2.toolCalls && prev2.toolCalls.some((tc) => tc.id === m.toolCallId)) {
|
|
33193
|
+
cut = j;
|
|
33194
|
+
moved = true;
|
|
33195
|
+
break;
|
|
33196
|
+
}
|
|
33197
|
+
}
|
|
33198
|
+
break;
|
|
33199
|
+
}
|
|
33200
|
+
}
|
|
33201
|
+
if (!moved) break;
|
|
33202
|
+
}
|
|
33203
|
+
return cut;
|
|
33204
|
+
}
|
|
33205
|
+
function compactHistory(messages, opts) {
|
|
33206
|
+
const maxMessages = resolveMaxMessages(opts);
|
|
33207
|
+
if (maxMessages === 0) return [];
|
|
33208
|
+
if (messages.length <= maxMessages * 2) return messages;
|
|
33209
|
+
const naiveCut = messages.length - maxMessages;
|
|
33210
|
+
const cut = findValidCutIndex(messages, naiveCut);
|
|
33211
|
+
const dropped = cut;
|
|
33212
|
+
if (dropped === 0) return messages;
|
|
33213
|
+
const kept = messages.slice(cut);
|
|
33214
|
+
const summary = {
|
|
33215
|
+
role: "system",
|
|
33216
|
+
content: `${COMPACT_MARKER} ${dropped} earlier message(s) dropped.`
|
|
33217
|
+
};
|
|
33218
|
+
return [summary, ...kept];
|
|
33219
|
+
}
|
|
33220
|
+
|
|
33138
33221
|
// src/cli/hooks/chatStats.ts
|
|
33139
33222
|
function computeSessionStatsDelta(realUsage, userText, assistantContent, model, prev2) {
|
|
33140
33223
|
const promptTokens = realUsage ? realUsage.promptTokens : Math.ceil(userText.length / 4);
|
|
@@ -33160,16 +33243,22 @@ function useChatTurn(params) {
|
|
|
33160
33243
|
setSessionActive,
|
|
33161
33244
|
setSessionStats,
|
|
33162
33245
|
setLive,
|
|
33163
|
-
liveRef
|
|
33246
|
+
liveRef,
|
|
33247
|
+
setPicker
|
|
33164
33248
|
} = params;
|
|
33165
33249
|
const harnessRef = useRef4(null);
|
|
33166
33250
|
const [queueCount, setQueueCount] = useState6(0);
|
|
33251
|
+
const historyRef = useRef4([]);
|
|
33167
33252
|
const useLiveModel = !!(setLive && liveRef);
|
|
33168
33253
|
const dispatchPrompt = useCallback2(
|
|
33169
33254
|
async (userText, opts) => {
|
|
33170
33255
|
let envConfig;
|
|
33171
33256
|
let harness;
|
|
33257
|
+
let historySeedLen = 0;
|
|
33258
|
+
let turnSucceeded = false;
|
|
33172
33259
|
try {
|
|
33260
|
+
historyRef.current = compactHistory(historyRef.current);
|
|
33261
|
+
historySeedLen = historyRef.current.length;
|
|
33173
33262
|
envConfig = await providerFromEnv();
|
|
33174
33263
|
if (!envConfig) {
|
|
33175
33264
|
const active = resolveActiveProvider();
|
|
@@ -33328,6 +33417,10 @@ function useChatTurn(params) {
|
|
|
33328
33417
|
provider: "openai-compatible",
|
|
33329
33418
|
messages: [
|
|
33330
33419
|
{ role: "system", content: systemPrompt },
|
|
33420
|
+
// v1.6.0: seed prior turns so the model sees its own last
|
|
33421
|
+
// question when the user answers briefly. historyRef.current
|
|
33422
|
+
// is compacted above (possibly empty if ZELARI_HISTORY_TURNS=0).
|
|
33423
|
+
...historyRef.current,
|
|
33331
33424
|
{ role: "user", content: userText }
|
|
33332
33425
|
],
|
|
33333
33426
|
tools: toolRegistry.toOpenAITools().map((t) => ({
|
|
@@ -33458,10 +33551,53 @@ function useChatTurn(params) {
|
|
|
33458
33551
|
}
|
|
33459
33552
|
}
|
|
33460
33553
|
}
|
|
33554
|
+
turnSucceeded = true;
|
|
33461
33555
|
} finally {
|
|
33462
33556
|
flushStreaming();
|
|
33463
33557
|
if (useLiveModel) finalizeStreaming(setMessages, setLive);
|
|
33464
33558
|
else finalizeStreamingAssistant(setMessages);
|
|
33559
|
+
try {
|
|
33560
|
+
const h = harnessRef.current;
|
|
33561
|
+
if (h && turnSucceeded) {
|
|
33562
|
+
const all = h.getMessages();
|
|
33563
|
+
const seedLen = 1 + historySeedLen + 1;
|
|
33564
|
+
if (all.length > seedLen) {
|
|
33565
|
+
historyRef.current = historyRef.current.concat(
|
|
33566
|
+
all.slice(seedLen)
|
|
33567
|
+
);
|
|
33568
|
+
}
|
|
33569
|
+
}
|
|
33570
|
+
} catch {
|
|
33571
|
+
}
|
|
33572
|
+
if (turnSucceeded && setPicker && assistantContent) {
|
|
33573
|
+
try {
|
|
33574
|
+
const clar = parseClarificationRequest(assistantContent);
|
|
33575
|
+
if (clar && clar.choices && clar.choices.length >= 2) {
|
|
33576
|
+
const cleaned = cleanAgentContent(assistantContent);
|
|
33577
|
+
if (cleaned !== assistantContent) {
|
|
33578
|
+
setMessages((prev2) => {
|
|
33579
|
+
const next = [...prev2];
|
|
33580
|
+
for (let i = next.length - 1; i >= 0; i--) {
|
|
33581
|
+
if (next[i].role === "assistant") {
|
|
33582
|
+
next[i] = { ...next[i], content: cleaned };
|
|
33583
|
+
break;
|
|
33584
|
+
}
|
|
33585
|
+
}
|
|
33586
|
+
return next;
|
|
33587
|
+
});
|
|
33588
|
+
}
|
|
33589
|
+
setPicker({
|
|
33590
|
+
kind: "clarification",
|
|
33591
|
+
title: clar.question,
|
|
33592
|
+
items: clar.choices.map((c) => ({ value: c, label: c })),
|
|
33593
|
+
onAnswer: (value) => {
|
|
33594
|
+
void dispatchPrompt(value);
|
|
33595
|
+
}
|
|
33596
|
+
});
|
|
33597
|
+
}
|
|
33598
|
+
} catch {
|
|
33599
|
+
}
|
|
33600
|
+
}
|
|
33465
33601
|
harnessRef.current = null;
|
|
33466
33602
|
setQueueCount(0);
|
|
33467
33603
|
setBusy(false);
|
|
@@ -36404,7 +36540,11 @@ function App() {
|
|
|
36404
36540
|
setSessionActive: session.setSessionActive,
|
|
36405
36541
|
setSessionStats,
|
|
36406
36542
|
setLive: session.setLive,
|
|
36407
|
-
liveRef: session.liveRef
|
|
36543
|
+
liveRef: session.liveRef,
|
|
36544
|
+
// v1.6.0: lets dispatchPrompt open a SelectList when the agent poses a
|
|
36545
|
+
// ---QUESTION--- clarifying block, so the user picks from the offered
|
|
36546
|
+
// choices instead of typing (and the answer binds via rolling history).
|
|
36547
|
+
setPicker
|
|
36408
36548
|
});
|
|
36409
36549
|
const onNewSession = useCallback5((id) => {
|
|
36410
36550
|
void session.writerRef.current?.close();
|
|
@@ -36445,8 +36585,12 @@ function App() {
|
|
|
36445
36585
|
});
|
|
36446
36586
|
const onPickerSelect = useCallback5((value) => {
|
|
36447
36587
|
if (!picker) return;
|
|
36448
|
-
const cmd = `${picker.commandPrefix} ${value}`;
|
|
36449
36588
|
setPicker(null);
|
|
36589
|
+
if (picker.kind === "clarification") {
|
|
36590
|
+
picker.onAnswer?.(value);
|
|
36591
|
+
return;
|
|
36592
|
+
}
|
|
36593
|
+
const cmd = `${picker.commandPrefix} ${value}`;
|
|
36450
36594
|
void handleSubmit(cmd);
|
|
36451
36595
|
}, [picker, handleSubmit]);
|
|
36452
36596
|
const onPickerCancel = useCallback5(() => setPicker(null), []);
|