zelari-code 1.13.0 → 1.14.3
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/LICENSE +18 -33
- package/README.md +54 -26
- package/dist/cli/app.js +3 -3
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/headless.js +29 -2
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/hooks/conversationContext.js +94 -17
- package/dist/cli/hooks/conversationContext.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +17 -6
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/main.bundled.js +391 -109
- package/dist/cli/main.bundled.js.map +3 -3
- package/dist/cli/modelPricing.js +3 -1
- package/dist/cli/modelPricing.js.map +1 -1
- package/dist/cli/provider/openai-compatible.js +88 -11
- package/dist/cli/provider/openai-compatible.js.map +1 -1
- package/dist/cli/providerConfig.js +3 -2
- package/dist/cli/providerConfig.js.map +1 -1
- package/dist/cli/runHeadless.js +245 -102
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/slashHandlers/provider.js +1 -1
- package/dist/cli/slashHandlers/provider.js.map +1 -1
- package/package.json +5 -5
package/dist/cli/main.bundled.js
CHANGED
|
@@ -741,10 +741,11 @@ var init_providerConfig = __esm({
|
|
|
741
741
|
DEFAULTS = {
|
|
742
742
|
activeProviderId: "openai-compatible",
|
|
743
743
|
modelByProvider: {
|
|
744
|
-
|
|
744
|
+
// grok-4.5: flagship; reasoning_effort defaults to "high" on the xAI API
|
|
745
|
+
"openai-compatible": "grok-4.5",
|
|
745
746
|
"minimax": "MiniMax-M2.5",
|
|
746
747
|
"glm": "glm-4.6",
|
|
747
|
-
"grok": "grok-4",
|
|
748
|
+
"grok": "grok-4.5",
|
|
748
749
|
"deepseek": "deepseek-v4-pro",
|
|
749
750
|
"custom": ""
|
|
750
751
|
},
|
|
@@ -18345,7 +18346,9 @@ Earlier members' outputs are shared context. Build on them; do not re-derive or
|
|
|
18345
18346
|
|
|
18346
18347
|
- Be concise and structured. Prefer short markdown sections and bullets over walls of text.
|
|
18347
18348
|
- Be proactive but not reckless: if a single missing fact would change the design, ask one focused question; otherwise make a documented assumption and proceed.
|
|
18348
|
-
- Prefer action over description when the user wants code, fixes, or repo changes \u2014 use tools.
|
|
18349
|
+
- Prefer action over description when the user wants code, fixes, or repo changes \u2014 use tools (write_file/edit_file/bash), not prose-only plans.
|
|
18350
|
+
- When the user confirms a plan ("procedi", "s\xEC", "implementa"), the prior plan is work TO DO on disk. Reading alone is incomplete.
|
|
18351
|
+
- Never claim work is "already implemented" without verifying the real files (and writing if gaps remain).
|
|
18349
18352
|
- Think step by step internally; surface conclusions and a brief rationale, not a full chain of thought.`
|
|
18350
18353
|
};
|
|
18351
18354
|
BEHAVIOR_COUNCIL = {
|
|
@@ -18416,11 +18419,12 @@ Earlier members' outputs are shared context. Build on them; do not re-derive or
|
|
|
18416
18419
|
content: `# Coding Practices
|
|
18417
18420
|
|
|
18418
18421
|
- **Read before edit**: open relevant files (and nearby callers/tests) before changing code.
|
|
18422
|
+
- **Then write**: if the task is to implement, follow reads with write_file/edit_file in the same turn. Do not end after exploration.
|
|
18419
18423
|
- **Minimal diffs**: change only what the task requires; match existing style and patterns.
|
|
18420
18424
|
- **Don't invent**: no fake APIs, deps, or config keys \u2014 discover from the tree or package manifests.
|
|
18421
18425
|
- **Verify**: after non-trivial edits, run the project's tests/typecheck/build when available; fix failures you introduced.
|
|
18422
18426
|
- **Use project scripts**: prefer package.json / Makefile / existing tooling over ad-hoc commands.
|
|
18423
|
-
- **Finish**:
|
|
18427
|
+
- **Finish**: list the paths you wrote/edited and how to verify. If you wrote nothing, say so honestly \u2014 do not invent a done report.`
|
|
18424
18428
|
};
|
|
18425
18429
|
CLARIFICATION_PROTOCOL_MODULE = {
|
|
18426
18430
|
type: "custom",
|
|
@@ -19832,7 +19836,7 @@ ${cached2}`
|
|
|
19832
19836
|
const key = hashToolCall(tt.name, tt.args);
|
|
19833
19837
|
return !turnToolCalls.some((n) => hashToolCall(n.name, n.args) === key);
|
|
19834
19838
|
});
|
|
19835
|
-
if ((/---TOOLS---/.test(turnText) || /
|
|
19839
|
+
if ((/---TOOLS---/.test(turnText) || /<\/?minimax:tool_call\b/i.test(turnText) || /invoke\s+name\s*=/i.test(turnText) || /\]\s*<\s*\]\s*minimax\s*\[/i.test(turnText)) && textTools.length === 0) {
|
|
19836
19840
|
const parseErr = createBrainEvent("error", this.sessionId, {
|
|
19837
19841
|
severity: "recoverable",
|
|
19838
19842
|
message: "Found text-format tool block but parse failed; tool calls were not executed. Prefer native tool_call, or ---TOOLS--- with ONE valid JSON array.",
|
|
@@ -19899,6 +19903,9 @@ ${cached2}`
|
|
|
19899
19903
|
finishRef.value = "tool_calls";
|
|
19900
19904
|
}
|
|
19901
19905
|
}
|
|
19906
|
+
if (turnToolResults.length > 0) {
|
|
19907
|
+
finishRef.value = "tool_calls";
|
|
19908
|
+
}
|
|
19902
19909
|
if (finishRef.value === "tool_calls" && turnToolCalls.length === 0 && turnToolResults.length === 0) {
|
|
19903
19910
|
const truncErr = createBrainEvent("error", this.sessionId, {
|
|
19904
19911
|
severity: "recoverable",
|
|
@@ -20364,6 +20371,38 @@ function openaiCompatibleProvider(config2) {
|
|
|
20364
20371
|
const decoder = new TextDecoder();
|
|
20365
20372
|
let buffer = "";
|
|
20366
20373
|
const toolCallAccumulator = /* @__PURE__ */ new Map();
|
|
20374
|
+
let emittedToolCall = false;
|
|
20375
|
+
let reasoningDetailsBuf = "";
|
|
20376
|
+
const tryParseArgs = (raw) => {
|
|
20377
|
+
const t = raw.trim();
|
|
20378
|
+
if (t.length === 0) return {};
|
|
20379
|
+
try {
|
|
20380
|
+
const parsed = JSON.parse(t);
|
|
20381
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
20382
|
+
return parsed;
|
|
20383
|
+
}
|
|
20384
|
+
return null;
|
|
20385
|
+
} catch {
|
|
20386
|
+
return null;
|
|
20387
|
+
}
|
|
20388
|
+
};
|
|
20389
|
+
const flushToolAccumulator = function* () {
|
|
20390
|
+
const entries = [...toolCallAccumulator.entries()].sort((a, b) => a[0] - b[0]);
|
|
20391
|
+
for (const [idx, existing] of entries) {
|
|
20392
|
+
if (!existing.name) continue;
|
|
20393
|
+
const args = tryParseArgs(existing.argsJson);
|
|
20394
|
+
if (args === null) continue;
|
|
20395
|
+
toolCallAccumulator.delete(idx);
|
|
20396
|
+
emittedToolCall = true;
|
|
20397
|
+
yield {
|
|
20398
|
+
kind: "tool_call",
|
|
20399
|
+
toolCallId: existing.id || `tc-${idx}`,
|
|
20400
|
+
toolName: existing.name,
|
|
20401
|
+
args
|
|
20402
|
+
};
|
|
20403
|
+
}
|
|
20404
|
+
toolCallAccumulator.clear();
|
|
20405
|
+
};
|
|
20367
20406
|
try {
|
|
20368
20407
|
while (true) {
|
|
20369
20408
|
const { value, done } = await reader.read();
|
|
@@ -20376,7 +20415,11 @@ function openaiCompatibleProvider(config2) {
|
|
|
20376
20415
|
if (!trimmed.startsWith("data:")) continue;
|
|
20377
20416
|
const data = trimmed.slice(5).trim();
|
|
20378
20417
|
if (data === "[DONE]") {
|
|
20379
|
-
yield
|
|
20418
|
+
yield* flushToolAccumulator();
|
|
20419
|
+
yield {
|
|
20420
|
+
kind: "finish",
|
|
20421
|
+
reason: emittedToolCall ? "tool_calls" : "stop"
|
|
20422
|
+
};
|
|
20380
20423
|
return;
|
|
20381
20424
|
}
|
|
20382
20425
|
try {
|
|
@@ -20405,6 +20448,22 @@ function openaiCompatibleProvider(config2) {
|
|
|
20405
20448
|
if (typeof reasoning === "string" && reasoning.length > 0) {
|
|
20406
20449
|
yield { kind: "thinking", delta: reasoning };
|
|
20407
20450
|
}
|
|
20451
|
+
const details = delta?.reasoning_details;
|
|
20452
|
+
if (Array.isArray(details)) {
|
|
20453
|
+
for (const d of details) {
|
|
20454
|
+
if (!d || typeof d !== "object") continue;
|
|
20455
|
+
const t = d.text;
|
|
20456
|
+
if (typeof t !== "string" || t.length === 0) continue;
|
|
20457
|
+
if (t.startsWith(reasoningDetailsBuf)) {
|
|
20458
|
+
const piece = t.slice(reasoningDetailsBuf.length);
|
|
20459
|
+
reasoningDetailsBuf = t;
|
|
20460
|
+
if (piece.length > 0) yield { kind: "thinking", delta: piece };
|
|
20461
|
+
} else {
|
|
20462
|
+
reasoningDetailsBuf += t;
|
|
20463
|
+
yield { kind: "thinking", delta: t };
|
|
20464
|
+
}
|
|
20465
|
+
}
|
|
20466
|
+
}
|
|
20408
20467
|
if (Array.isArray(delta?.tool_calls)) {
|
|
20409
20468
|
for (const tc of delta.tool_calls) {
|
|
20410
20469
|
const idx = tc.index ?? 0;
|
|
@@ -20418,27 +20477,34 @@ function openaiCompatibleProvider(config2) {
|
|
|
20418
20477
|
if (tc.function?.arguments) existing.argsJson += tc.function.arguments;
|
|
20419
20478
|
toolCallAccumulator.set(idx, existing);
|
|
20420
20479
|
if (existing.argsJson.trim().endsWith("}")) {
|
|
20421
|
-
|
|
20422
|
-
|
|
20480
|
+
const parsedArgs = tryParseArgs(existing.argsJson);
|
|
20481
|
+
if (parsedArgs !== null && existing.name) {
|
|
20423
20482
|
toolCallAccumulator.delete(idx);
|
|
20483
|
+
emittedToolCall = true;
|
|
20424
20484
|
yield {
|
|
20425
20485
|
kind: "tool_call",
|
|
20426
20486
|
toolCallId: existing.id || `tc-${idx}`,
|
|
20427
20487
|
toolName: existing.name,
|
|
20428
20488
|
args: parsedArgs
|
|
20429
20489
|
};
|
|
20430
|
-
} catch {
|
|
20431
20490
|
}
|
|
20432
20491
|
}
|
|
20433
20492
|
}
|
|
20434
20493
|
}
|
|
20435
20494
|
if (choice?.finish_reason) {
|
|
20436
|
-
yield
|
|
20495
|
+
yield* flushToolAccumulator();
|
|
20496
|
+
const reason = choice.finish_reason === "stop" && emittedToolCall ? "tool_calls" : choice.finish_reason;
|
|
20497
|
+
yield { kind: "finish", reason };
|
|
20437
20498
|
}
|
|
20438
20499
|
} catch {
|
|
20439
20500
|
}
|
|
20440
20501
|
}
|
|
20441
20502
|
}
|
|
20503
|
+
yield* flushToolAccumulator();
|
|
20504
|
+
yield {
|
|
20505
|
+
kind: "finish",
|
|
20506
|
+
reason: emittedToolCall ? "tool_calls" : "stop"
|
|
20507
|
+
};
|
|
20442
20508
|
} finally {
|
|
20443
20509
|
reader.releaseLock();
|
|
20444
20510
|
}
|
|
@@ -24757,7 +24823,12 @@ function parseThinking(text) {
|
|
|
24757
24823
|
}
|
|
24758
24824
|
function cleanAgentContent(text, opts = {}) {
|
|
24759
24825
|
const stripQuestion = opts.stripQuestion !== false;
|
|
24760
|
-
|
|
24826
|
+
const stripThink = opts.stripThink !== false;
|
|
24827
|
+
let out = text;
|
|
24828
|
+
if (stripThink) {
|
|
24829
|
+
out = out.replace(/<think(?:ing)?>[\s\S]*?<\/think(?:ing)?>/gi, "").replace(/<think(?:ing)?>[\s\S]*$/gi, "").replace(/<\/think(?:ing)?>/gi, "");
|
|
24830
|
+
}
|
|
24831
|
+
out = out.replace(/<minimax:tool_call>[\s\S]*?<\/minimax:tool_call>/g, "");
|
|
24761
24832
|
if (stripQuestion) {
|
|
24762
24833
|
out = out.replace(/---QUESTION---[\s\S]*?---END---/g, "");
|
|
24763
24834
|
}
|
|
@@ -26988,14 +27059,18 @@ var conversationContext_exports = {};
|
|
|
26988
27059
|
__export(conversationContext_exports, {
|
|
26989
27060
|
_resetConversationContextForTests: () => _resetConversationContextForTests,
|
|
26990
27061
|
appendMessages: () => appendMessages,
|
|
27062
|
+
buildAgentUserWithHistory: () => buildAgentUserWithHistory,
|
|
27063
|
+
buildContinueUserMessage: () => buildContinueUserMessage,
|
|
26991
27064
|
buildCouncilTaskWithHistory: () => buildCouncilTaskWithHistory,
|
|
26992
27065
|
clearHistory: () => clearHistory,
|
|
26993
27066
|
compactInPlace: () => compactInPlace,
|
|
27067
|
+
expectsDiskImplementation: () => expectsDiskImplementation,
|
|
26994
27068
|
formatHistoryForCouncil: () => formatHistoryForCouncil,
|
|
26995
27069
|
formatHistoryMessages: () => formatHistoryMessages,
|
|
26996
27070
|
getHistory: () => getHistory,
|
|
26997
27071
|
getLastClarification: () => getLastClarification,
|
|
26998
27072
|
hydrateHistory: () => hydrateHistory,
|
|
27073
|
+
isShortContinueReply: () => isShortContinueReply,
|
|
26999
27074
|
maybeAnchorShortAnswer: () => maybeAnchorShortAnswer,
|
|
27000
27075
|
serializeHistory: () => serializeHistory,
|
|
27001
27076
|
setHistory: () => setHistory,
|
|
@@ -27078,22 +27153,67 @@ ${body.slice(body.length - maxTotalChars)}`;
|
|
|
27078
27153
|
}
|
|
27079
27154
|
return body;
|
|
27080
27155
|
}
|
|
27081
|
-
function
|
|
27082
|
-
const messages = prior ?? [];
|
|
27156
|
+
function isShortContinueReply(task) {
|
|
27083
27157
|
const trimmed = task.trim();
|
|
27084
|
-
|
|
27085
|
-
if (
|
|
27086
|
-
|
|
27087
|
-
|
|
27088
|
-
|
|
27158
|
+
if (!trimmed) return false;
|
|
27159
|
+
if (SHORT_CONTINUE.test(trimmed)) return true;
|
|
27160
|
+
if (trimmed.length <= 80 && !trimmed.includes("\n") && SHORT_CONTINUE_LOOSE.test(trimmed)) {
|
|
27161
|
+
return true;
|
|
27162
|
+
}
|
|
27163
|
+
return false;
|
|
27164
|
+
}
|
|
27165
|
+
function buildContinueUserMessage(task, prior, opts) {
|
|
27166
|
+
if (!isShortContinueReply(task) || prior.length === 0) return null;
|
|
27167
|
+
const lastAsst = [...prior].reverse().find((m) => m.role === "assistant" && (m.content ?? "").trim());
|
|
27168
|
+
if (!lastAsst) return null;
|
|
27169
|
+
const max = opts?.maxPriorChars ?? 8e3;
|
|
27170
|
+
const trimmed = task.trim();
|
|
27171
|
+
return `The user says "${trimmed}" \u2014 this is a CONTINUATION of an existing multi-turn session (the Desktop phase may have switched plan\u2194build; mode may have changed). This is NOT a new conversation and you DO have prior context below.
|
|
27089
27172
|
|
|
27090
|
-
##
|
|
27091
|
-
|
|
27173
|
+
## CRITICAL \u2014 plan text \u2260 done on disk
|
|
27174
|
+
The prior assistant output is a PLAN / SPEC / PROPOSAL (or analysis). It is NOT proof that project files already contain those changes.
|
|
27175
|
+
The user CONFIRMED the plan and wants you to IMPLEMENT it ON DISK NOW.
|
|
27176
|
+
- You MUST use write_file and/or edit_file (and bash when needed) to apply every planned change.
|
|
27177
|
+
- Reading files alone is incomplete. Do not stop after read_file/list_files/grep.
|
|
27178
|
+
- Do NOT claim "already implemented" / "tutto fatto" unless you verified the changes exist on disk in THIS turn (read after your own successful writes).
|
|
27179
|
+
- Do NOT restart from zero or re-ask for the overall goal.
|
|
27180
|
+
|
|
27181
|
+
## Prior assistant output (plan to implement \u2014 authoritative)
|
|
27182
|
+
${truncate(lastAsst.content, max)}
|
|
27092
27183
|
|
|
27093
27184
|
## Instruction
|
|
27094
|
-
|
|
27185
|
+
Implement the plan on disk now with mutating tools, then briefly list the files you wrote/edited.`;
|
|
27186
|
+
}
|
|
27187
|
+
function expectsDiskImplementation(task, phase2, prior) {
|
|
27188
|
+
if ((phase2 ?? "build") === "plan") return false;
|
|
27189
|
+
const trimmed = task.trim();
|
|
27190
|
+
if (!trimmed) return false;
|
|
27191
|
+
if (isShortContinueReply(trimmed)) return true;
|
|
27192
|
+
if (/\b(implement|implementa|scrivi|scriviamo|applica|modifica|fix|write|edit|crea|aggiungi|aggiorna|apply|patch)\b/i.test(
|
|
27193
|
+
trimmed
|
|
27194
|
+
)) {
|
|
27195
|
+
return true;
|
|
27196
|
+
}
|
|
27197
|
+
if (prior && prior.length > 0 && isShortContinueReply(trimmed)) {
|
|
27198
|
+
const lastAsst = [...prior].reverse().find((m) => m.role === "assistant" && (m.content ?? "").trim());
|
|
27199
|
+
if (lastAsst && /\b(se confermi|passo alla|scriv|implement|on disk|write_file|modifiche proposte|riepilogo delle modifiche)\b/i.test(
|
|
27200
|
+
lastAsst.content
|
|
27201
|
+
)) {
|
|
27202
|
+
return true;
|
|
27095
27203
|
}
|
|
27096
27204
|
}
|
|
27205
|
+
return false;
|
|
27206
|
+
}
|
|
27207
|
+
function buildCouncilTaskWithHistory(task, prior) {
|
|
27208
|
+
const messages = prior ?? [];
|
|
27209
|
+
const trimmed = task.trim();
|
|
27210
|
+
let userPart = maybeAnchorShortAnswer(task) ?? task;
|
|
27211
|
+
const continued = buildContinueUserMessage(trimmed, messages, {
|
|
27212
|
+
maxPriorChars: 4500
|
|
27213
|
+
});
|
|
27214
|
+
if (continued) {
|
|
27215
|
+
userPart = continued;
|
|
27216
|
+
}
|
|
27097
27217
|
const block = formatHistoryMessages(messages, 6, 12e3);
|
|
27098
27218
|
if (!block) return userPart;
|
|
27099
27219
|
if (userPart.includes("Prior assistant output")) {
|
|
@@ -27104,6 +27224,12 @@ Proceed with the next concrete steps implied by that context (implementation whe
|
|
|
27104
27224
|
## Current user request
|
|
27105
27225
|
${userPart}`;
|
|
27106
27226
|
}
|
|
27227
|
+
function buildAgentUserWithHistory(task, prior) {
|
|
27228
|
+
const messages = prior ?? [];
|
|
27229
|
+
const anchored = maybeAnchorShortAnswer(task);
|
|
27230
|
+
if (anchored) return anchored;
|
|
27231
|
+
return buildContinueUserMessage(task, messages, { maxPriorChars: 8e3 }) ?? task;
|
|
27232
|
+
}
|
|
27107
27233
|
function truncate(s, max) {
|
|
27108
27234
|
const t = s.replace(/\s+/g, " ").trim();
|
|
27109
27235
|
if (t.length <= max) return t;
|
|
@@ -27113,14 +27239,15 @@ function _resetConversationContextForTests() {
|
|
|
27113
27239
|
history = [];
|
|
27114
27240
|
lastClarification = null;
|
|
27115
27241
|
}
|
|
27116
|
-
var history, lastClarification, SHORT_CONTINUE;
|
|
27242
|
+
var history, lastClarification, SHORT_CONTINUE, SHORT_CONTINUE_LOOSE;
|
|
27117
27243
|
var init_conversationContext = __esm({
|
|
27118
27244
|
"src/cli/hooks/conversationContext.ts"() {
|
|
27119
27245
|
"use strict";
|
|
27120
27246
|
init_historyCompaction();
|
|
27121
27247
|
history = [];
|
|
27122
27248
|
lastClarification = null;
|
|
27123
|
-
SHORT_CONTINUE = /^(procedi|continua|continue|go\s*ahead|go|ok|okay|sì|si|yes|vai|avanti|next|proceed)$/i;
|
|
27249
|
+
SHORT_CONTINUE = /^(procedi|continua|continue|go\s*ahead|go|ok|okay|sì|si|yes|vai|avanti|next|proceed|conferma|confermo|applica|fai|scrivi|esegui|implementa|vai pure|fai pure|ok procedi|sì procedi|si procedi)$/i;
|
|
27250
|
+
SHORT_CONTINUE_LOOSE = /\b(procedi|continua|continue|conferma|confermo|applica|implementa|scriv[ia]|esegui|vai pure|fai pure|go ahead|proceed)\b/i;
|
|
27124
27251
|
}
|
|
27125
27252
|
});
|
|
27126
27253
|
|
|
@@ -31869,7 +31996,9 @@ import { Box as Box5, Text as Text6 } from "ink";
|
|
|
31869
31996
|
|
|
31870
31997
|
// src/cli/modelPricing.ts
|
|
31871
31998
|
var PRICES_PER_MILLION = {
|
|
31872
|
-
// xAI Grok
|
|
31999
|
+
// xAI Grok (list prices; grok-4.5 default reasoning_effort is "high")
|
|
32000
|
+
"grok-4.5": { input: 2, output: 6, cachedInput: 0.5 },
|
|
32001
|
+
"grok-4.3": { input: 1.25, output: 2.5, cachedInput: 0.2 },
|
|
31873
32002
|
"grok-4": { input: 3, output: 15 },
|
|
31874
32003
|
"grok-4-fast": { input: 0.2, output: 0.5 },
|
|
31875
32004
|
"grok-3": { input: 3, output: 15 },
|
|
@@ -35293,11 +35422,16 @@ function useChatTurn(params) {
|
|
|
35293
35422
|
"- write_file / edit_file / bash / apply_diff are unavailable.",
|
|
35294
35423
|
"- Produce a clear plan, ask clarifying questions (---QUESTION---), use workspace plan tools when relevant.",
|
|
35295
35424
|
"- When the plan is ready, tell the user to run /build to implement."
|
|
35296
|
-
].join("\n") : workPhase === "build"
|
|
35425
|
+
].join("\n") : workPhase === "build" ? [
|
|
35297
35426
|
"",
|
|
35298
35427
|
"# Work Phase: BUILD",
|
|
35299
|
-
"Implement
|
|
35300
|
-
|
|
35428
|
+
"Implement on disk. Prefer acting over describing.",
|
|
35429
|
+
"- Prior plan/synthesis text is a SPEC to apply \u2014 not proof files already changed.",
|
|
35430
|
+
"- You MUST use write_file/edit_file for every file you change before claiming done.",
|
|
35431
|
+
"- After read_file: if the planned change is missing, WRITE it \u2014 do not stop at analysis.",
|
|
35432
|
+
"- Never claim already-implemented based only on reading a plan or skimming code.",
|
|
35433
|
+
planSummary ? "- An approved plan exists in the workspace \u2014 implement it and update task statuses as you go." : ""
|
|
35434
|
+
].filter(Boolean).join("\n") : "";
|
|
35301
35435
|
const shellContextBlock = [
|
|
35302
35436
|
"# Platform & Shell",
|
|
35303
35437
|
`platform: ${process.platform}`,
|
|
@@ -35538,7 +35672,8 @@ function useChatTurn(params) {
|
|
|
35538
35672
|
(m) => m.role === "assistant" && m.content ? {
|
|
35539
35673
|
...m,
|
|
35540
35674
|
content: cleanAgentContent(m.content, {
|
|
35541
|
-
stripQuestion: false
|
|
35675
|
+
stripQuestion: false,
|
|
35676
|
+
stripThink: false
|
|
35542
35677
|
})
|
|
35543
35678
|
} : m
|
|
35544
35679
|
)
|
|
@@ -37789,7 +37924,7 @@ async function handleLoginOAuthGrok(ctx) {
|
|
|
37789
37924
|
});
|
|
37790
37925
|
setActiveProviderId("grok");
|
|
37791
37926
|
if (!getModelForProvider("grok")) {
|
|
37792
|
-
setModelForProvider("grok", ctx.providerDefaults["grok"] ?? "grok-4");
|
|
37927
|
+
setModelForProvider("grok", ctx.providerDefaults["grok"] ?? "grok-4.5");
|
|
37793
37928
|
}
|
|
37794
37929
|
const expiresHint = resultOAuth.expiresAt ? `, expires ${new Date(resultOAuth.expiresAt).toISOString()}` : "";
|
|
37795
37930
|
const refreshHint = resultOAuth.refreshToken ? ", refresh token saved" : "";
|
|
@@ -38611,10 +38746,10 @@ function useTerminalSize(options = {}) {
|
|
|
38611
38746
|
}
|
|
38612
38747
|
|
|
38613
38748
|
// src/cli/app.tsx
|
|
38614
|
-
var MODEL = process.env.OPENAI_MODEL ?? "grok-4";
|
|
38749
|
+
var MODEL = process.env.OPENAI_MODEL ?? "grok-4.5";
|
|
38615
38750
|
var providerDefaults = {
|
|
38616
|
-
"openai-compatible": "grok-4",
|
|
38617
|
-
"grok": "grok-4",
|
|
38751
|
+
"openai-compatible": "grok-4.5",
|
|
38752
|
+
"grok": "grok-4.5",
|
|
38618
38753
|
"minimax": "MiniMax-chat-latest",
|
|
38619
38754
|
"glm": "glm-4.5",
|
|
38620
38755
|
"deepseek": "deepseek-v4-pro"
|
|
@@ -39471,7 +39606,21 @@ function parseHeadlessFlags(argv) {
|
|
|
39471
39606
|
const parsedHist = JSON.parse(raw);
|
|
39472
39607
|
if (Array.isArray(parsedHist)) {
|
|
39473
39608
|
history2 = parsedHist.filter(
|
|
39474
|
-
(m) => m && typeof m === "object" && typeof m.role === "string"
|
|
39609
|
+
(m) => !!m && typeof m === "object" && typeof m.role === "string"
|
|
39610
|
+
).map((m) => {
|
|
39611
|
+
const role = String(m.role);
|
|
39612
|
+
const raw2 = m.content;
|
|
39613
|
+
const content = typeof raw2 === "string" ? raw2 : raw2 == null ? "" : typeof raw2 === "object" ? JSON.stringify(raw2) : String(raw2);
|
|
39614
|
+
const msg = {
|
|
39615
|
+
role,
|
|
39616
|
+
content
|
|
39617
|
+
};
|
|
39618
|
+
if (typeof m.toolCallId === "string") {
|
|
39619
|
+
msg.toolCallId = m.toolCallId;
|
|
39620
|
+
}
|
|
39621
|
+
return msg;
|
|
39622
|
+
}).filter(
|
|
39623
|
+
(m) => m.role === "user" || m.role === "assistant" || m.role === "tool" || m.role === "system"
|
|
39475
39624
|
);
|
|
39476
39625
|
}
|
|
39477
39626
|
} catch {
|
|
@@ -39535,6 +39684,7 @@ function emitEvent(event) {
|
|
|
39535
39684
|
// src/cli/runHeadless.ts
|
|
39536
39685
|
init_harness();
|
|
39537
39686
|
init_conversationContext();
|
|
39687
|
+
init_council();
|
|
39538
39688
|
init_toolRegistry();
|
|
39539
39689
|
init_skills2();
|
|
39540
39690
|
init_envNumber();
|
|
@@ -39708,7 +39858,19 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
39708
39858
|
"The shell is NON-INTERACTIVE (stdin closed): pass non-interactive flags (--yes, --force, --template).",
|
|
39709
39859
|
"",
|
|
39710
39860
|
`# Work phase: ${opts.phase ?? "build"}`,
|
|
39711
|
-
(opts.phase ?? "build") === "plan" ?
|
|
39861
|
+
(opts.phase ?? "build") === "plan" ? [
|
|
39862
|
+
"PLAN phase: explore and design only.",
|
|
39863
|
+
"Do not write project source files (write_file/edit_file/bash blocked).",
|
|
39864
|
+
"Plan artifacts under .zelari are allowed.",
|
|
39865
|
+
"When the plan is ready, tell the user to switch to BUILD to implement on disk."
|
|
39866
|
+
].join(" ") : [
|
|
39867
|
+
"BUILD phase \u2014 IMPLEMENT ON DISK (mandatory when the user wants code/file changes).",
|
|
39868
|
+
"Prior chat may contain a plan or synthesis: that text is a SPEC to apply, NOT proof that files already changed.",
|
|
39869
|
+
"You MUST call write_file and/or edit_file for every file you change before saying you are done.",
|
|
39870
|
+
"After read_file: if the planned change is missing, WRITE it \u2014 do not stop at analysis.",
|
|
39871
|
+
'Never claim "already implemented" / "tutto fatto" based only on reading a plan or skimming code.',
|
|
39872
|
+
"Only claim done after successful mutating tool calls in THIS turn (or after proving the exact planned diff already exists on disk via read_file of the real files)."
|
|
39873
|
+
].join(" ")
|
|
39712
39874
|
].join("\n")
|
|
39713
39875
|
};
|
|
39714
39876
|
const { loadProjectInstructions: loadProjectInstructions2 } = await Promise.resolve().then(() => (init_projectInstructions(), projectInstructions_exports));
|
|
@@ -39753,95 +39915,202 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
39753
39915
|
languageDirectiveContent
|
|
39754
39916
|
].join("\n");
|
|
39755
39917
|
}
|
|
39756
|
-
const historySeed = (opts.history ?? []).map(
|
|
39757
|
-
(m) => m.role === "assistant" && m.content ? {
|
|
39758
|
-
|
|
39759
|
-
|
|
39760
|
-
|
|
39761
|
-
|
|
39762
|
-
|
|
39763
|
-
|
|
39764
|
-
|
|
39765
|
-
|
|
39766
|
-
|
|
39767
|
-
|
|
39768
|
-
|
|
39769
|
-
|
|
39770
|
-
|
|
39771
|
-
|
|
39772
|
-
|
|
39773
|
-
|
|
39774
|
-
|
|
39775
|
-
|
|
39776
|
-
|
|
39777
|
-
|
|
39778
|
-
|
|
39779
|
-
|
|
39780
|
-
|
|
39781
|
-
|
|
39782
|
-
|
|
39783
|
-
|
|
39784
|
-
|
|
39785
|
-
|
|
39786
|
-
|
|
39787
|
-
|
|
39788
|
-
|
|
39789
|
-
|
|
39790
|
-
|
|
39791
|
-
|
|
39792
|
-
|
|
39793
|
-
|
|
39794
|
-
|
|
39795
|
-
} else {
|
|
39796
|
-
if (cleanDelta.length > 0) textBuffer.push(cleanDelta);
|
|
39918
|
+
const historySeed = (opts.history ?? []).filter((m) => m.role === "user" || m.role === "assistant").map(
|
|
39919
|
+
(m) => m.role === "assistant" && m.content ? {
|
|
39920
|
+
role: "assistant",
|
|
39921
|
+
content: cleanAgentContent(m.content, {
|
|
39922
|
+
stripQuestion: false,
|
|
39923
|
+
stripThink: false
|
|
39924
|
+
})
|
|
39925
|
+
} : { role: m.role, content: m.content ?? "" }
|
|
39926
|
+
).filter((m) => (m.content ?? "").trim().length > 0);
|
|
39927
|
+
const effectiveTask = buildAgentUserWithHistory(opts.task, historySeed);
|
|
39928
|
+
const maxToolLoop = (() => {
|
|
39929
|
+
const n = envNumber(process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS, {
|
|
39930
|
+
default: 30,
|
|
39931
|
+
min: 1
|
|
39932
|
+
});
|
|
39933
|
+
return n;
|
|
39934
|
+
})();
|
|
39935
|
+
async function runSinglePass(messages, passSessionId) {
|
|
39936
|
+
const harness = new AgentHarness({
|
|
39937
|
+
model,
|
|
39938
|
+
provider,
|
|
39939
|
+
sessionId: passSessionId,
|
|
39940
|
+
messages,
|
|
39941
|
+
tools,
|
|
39942
|
+
toolRegistry,
|
|
39943
|
+
providerStream,
|
|
39944
|
+
maxToolLoopIterations: maxToolLoop
|
|
39945
|
+
});
|
|
39946
|
+
let finalReason = "completed";
|
|
39947
|
+
let exitCode = 0;
|
|
39948
|
+
const textBuffer = [];
|
|
39949
|
+
let successfulWrites = 0;
|
|
39950
|
+
let emittedWrites = 0;
|
|
39951
|
+
const pendingToolNames = /* @__PURE__ */ new Map();
|
|
39952
|
+
const scrub = createStreamScrubber();
|
|
39953
|
+
try {
|
|
39954
|
+
for await (const event of harness.run()) {
|
|
39955
|
+
if (event.type === "message_start") {
|
|
39956
|
+
scrub.reset();
|
|
39797
39957
|
}
|
|
39798
|
-
|
|
39799
|
-
|
|
39800
|
-
|
|
39958
|
+
if (event.type === "tool_execution_start") {
|
|
39959
|
+
const name = event.toolName ?? "";
|
|
39960
|
+
const id = event.toolCallId ?? "";
|
|
39961
|
+
if (id && name) pendingToolNames.set(id, name);
|
|
39962
|
+
if (name === "write_file" || name === "edit_file" || name === "apply_diff") {
|
|
39963
|
+
emittedWrites += 1;
|
|
39964
|
+
}
|
|
39965
|
+
}
|
|
39966
|
+
if (event.type === "tool_execution_end") {
|
|
39967
|
+
const id = event.toolCallId ?? "";
|
|
39968
|
+
const name = pendingToolNames.get(id) ?? "";
|
|
39969
|
+
pendingToolNames.delete(id);
|
|
39970
|
+
const isError = !!event.isError;
|
|
39971
|
+
const result = String(event.result ?? "");
|
|
39972
|
+
if ((name === "write_file" || name === "edit_file" || name === "apply_diff") && !isError) {
|
|
39973
|
+
const zeroEdit = name === "edit_file" && /occurrencesReplaced["']?\s*[:=]\s*0\b|0 occurrence|no changes/i.test(
|
|
39974
|
+
result
|
|
39975
|
+
);
|
|
39976
|
+
if (!zeroEdit) successfulWrites += 1;
|
|
39977
|
+
}
|
|
39801
39978
|
}
|
|
39802
|
-
if (event.type === "
|
|
39803
|
-
const
|
|
39804
|
-
if (
|
|
39805
|
-
if (
|
|
39806
|
-
|
|
39979
|
+
if (event.type === "message_delta" && typeof event.delta === "string") {
|
|
39980
|
+
const cleanDelta = scrub.push(event.delta);
|
|
39981
|
+
if (opts.output === "json") {
|
|
39982
|
+
if (cleanDelta.length > 0) {
|
|
39983
|
+
emitEvent({ ...event, delta: cleanDelta });
|
|
39984
|
+
}
|
|
39985
|
+
} else if (opts.output === "plain") {
|
|
39986
|
+
if (cleanDelta.length > 0) process.stdout.write(cleanDelta);
|
|
39987
|
+
} else {
|
|
39988
|
+
if (cleanDelta.length > 0) textBuffer.push(cleanDelta);
|
|
39807
39989
|
}
|
|
39808
|
-
|
|
39809
|
-
if (
|
|
39810
|
-
|
|
39811
|
-
|
|
39812
|
-
|
|
39990
|
+
} else {
|
|
39991
|
+
if (opts.output === "json") {
|
|
39992
|
+
emitEvent(event);
|
|
39993
|
+
}
|
|
39994
|
+
if (event.type === "agent_end") {
|
|
39995
|
+
const tail = scrub.flush();
|
|
39996
|
+
if (tail.length > 0) {
|
|
39997
|
+
if (opts.output === "plain") process.stdout.write(tail);
|
|
39998
|
+
else textBuffer.push(tail);
|
|
39999
|
+
}
|
|
40000
|
+
finalReason = event.reason;
|
|
40001
|
+
if (event.reason === "error") exitCode = 3;
|
|
40002
|
+
} else if (event.type === "error") {
|
|
40003
|
+
if (event.severity === "fatal") {
|
|
40004
|
+
exitCode = 2;
|
|
40005
|
+
}
|
|
39813
40006
|
}
|
|
39814
40007
|
}
|
|
39815
40008
|
}
|
|
40009
|
+
} catch (err) {
|
|
40010
|
+
process.stderr.write(
|
|
40011
|
+
`[zelari-code --headless] runtime error: ${err instanceof Error ? err.message : String(err)}
|
|
40012
|
+
`
|
|
40013
|
+
);
|
|
40014
|
+
return {
|
|
40015
|
+
finalReason: "error",
|
|
40016
|
+
exitCode: 2,
|
|
40017
|
+
textBuffer,
|
|
40018
|
+
successfulWrites,
|
|
40019
|
+
emittedWrites,
|
|
40020
|
+
messages: harness.getMessages()
|
|
40021
|
+
};
|
|
39816
40022
|
}
|
|
39817
|
-
|
|
39818
|
-
|
|
39819
|
-
|
|
40023
|
+
return {
|
|
40024
|
+
finalReason,
|
|
40025
|
+
exitCode,
|
|
40026
|
+
textBuffer,
|
|
40027
|
+
successfulWrites,
|
|
40028
|
+
emittedWrites,
|
|
40029
|
+
messages: harness.getMessages()
|
|
40030
|
+
};
|
|
40031
|
+
}
|
|
40032
|
+
const initialMessages = [
|
|
40033
|
+
{ role: "system", content: systemPrompt },
|
|
40034
|
+
...historySeed,
|
|
40035
|
+
{ role: "user", content: effectiveTask }
|
|
40036
|
+
];
|
|
40037
|
+
let pass = await runSinglePass(initialMessages, sessionId);
|
|
40038
|
+
const wantWrites = expectsDiskImplementation(
|
|
40039
|
+
opts.task,
|
|
40040
|
+
opts.phase,
|
|
40041
|
+
historySeed
|
|
40042
|
+
);
|
|
40043
|
+
if (wantWrites && pass.successfulWrites === 0 && pass.finalReason === "completed" && pass.exitCode === 0) {
|
|
40044
|
+
const retryPrompt = buildImplementationWriteRetryPrompt(opts.task);
|
|
40045
|
+
if (opts.output === "json") {
|
|
40046
|
+
emitEvent({
|
|
40047
|
+
type: "log",
|
|
40048
|
+
message: "[headless] BUILD: no successful write_file/edit_file \u2014 forcing implementation retry"
|
|
40049
|
+
});
|
|
40050
|
+
} else {
|
|
40051
|
+
process.stderr.write(
|
|
40052
|
+
`[zelari-code --headless] BUILD: no successful writes \u2014 forcing implementation retry
|
|
39820
40053
|
`
|
|
39821
|
-
|
|
39822
|
-
|
|
40054
|
+
);
|
|
40055
|
+
}
|
|
40056
|
+
const retryMessages = [
|
|
40057
|
+
...pass.messages.filter((m) => m.role !== "system")
|
|
40058
|
+
];
|
|
40059
|
+
const withSystem = [
|
|
40060
|
+
{ role: "system", content: systemPrompt },
|
|
40061
|
+
...retryMessages,
|
|
40062
|
+
{ role: "user", content: retryPrompt }
|
|
40063
|
+
];
|
|
40064
|
+
const retry = await runSinglePass(withSystem, `${sessionId}-write-retry`);
|
|
40065
|
+
pass = {
|
|
40066
|
+
...retry,
|
|
40067
|
+
textBuffer: [...pass.textBuffer, ...retry.textBuffer],
|
|
40068
|
+
successfulWrites: pass.successfulWrites + retry.successfulWrites,
|
|
40069
|
+
emittedWrites: pass.emittedWrites + retry.emittedWrites
|
|
40070
|
+
};
|
|
39823
40071
|
}
|
|
39824
|
-
if (opts.output === "plain" && textBuffer.length > 0) {
|
|
39825
|
-
process.stdout.write(textBuffer.join(""));
|
|
40072
|
+
if (opts.output === "plain" && pass.textBuffer.length > 0) {
|
|
40073
|
+
process.stdout.write(pass.textBuffer.join(""));
|
|
39826
40074
|
}
|
|
39827
40075
|
process.stdout.write("");
|
|
39828
|
-
if (finalReason !== "error" && opts.output === "json") {
|
|
40076
|
+
if (pass.finalReason !== "error" && opts.output === "json") {
|
|
39829
40077
|
try {
|
|
39830
|
-
const all =
|
|
39831
|
-
|
|
39832
|
-
|
|
39833
|
-
const
|
|
39834
|
-
|
|
39835
|
-
|
|
39836
|
-
|
|
39837
|
-
|
|
40078
|
+
const all = pass.messages;
|
|
40079
|
+
let lastAsst = "";
|
|
40080
|
+
for (let i = all.length - 1; i >= 0; i--) {
|
|
40081
|
+
const m = all[i];
|
|
40082
|
+
if (m?.role === "assistant" && (m.content ?? "").trim()) {
|
|
40083
|
+
lastAsst = cleanAgentContent(m.content, {
|
|
40084
|
+
stripQuestion: false,
|
|
40085
|
+
stripThink: false
|
|
40086
|
+
});
|
|
40087
|
+
break;
|
|
39838
40088
|
}
|
|
39839
40089
|
}
|
|
40090
|
+
if (!lastAsst.trim() && pass.textBuffer.length > 0) {
|
|
40091
|
+
lastAsst = pass.textBuffer.join("").trim();
|
|
40092
|
+
}
|
|
40093
|
+
if (wantWrites && pass.successfulWrites === 0) {
|
|
40094
|
+
lastAsst = (lastAsst ? `${lastAsst}
|
|
40095
|
+
|
|
40096
|
+
` : "") + "[zelari] WARNING: BUILD turn ended with zero successful file writes. The planned changes may still need to be applied on disk.";
|
|
40097
|
+
emitEvent({
|
|
40098
|
+
type: "log",
|
|
40099
|
+
message: "[headless] BUILD warning: still zero successful writes after retry"
|
|
40100
|
+
});
|
|
40101
|
+
}
|
|
40102
|
+
const snapshot = [
|
|
40103
|
+
{ role: "user", content: opts.task },
|
|
40104
|
+
...lastAsst ? [{ role: "assistant", content: lastAsst }] : []
|
|
40105
|
+
];
|
|
40106
|
+
if (snapshot.length > 0) {
|
|
40107
|
+
emitEvent({ type: "history_snapshot", messages: snapshot });
|
|
40108
|
+
}
|
|
39840
40109
|
} catch {
|
|
39841
40110
|
}
|
|
39842
40111
|
}
|
|
39843
|
-
if (finalReason === "error") return 3;
|
|
39844
|
-
return exitCode;
|
|
40112
|
+
if (pass.finalReason === "error") return 3;
|
|
40113
|
+
return pass.exitCode;
|
|
39845
40114
|
}
|
|
39846
40115
|
async function buildCouncilToolRegistry(planMode, opts) {
|
|
39847
40116
|
const { registry: toolRegistry } = createBuiltinToolRegistry({ planMode });
|
|
@@ -39870,7 +40139,13 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
39870
40139
|
const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
|
|
39871
40140
|
const feedbackStore = new FeedbackStore2();
|
|
39872
40141
|
const historySeed = (opts.history ?? []).map(
|
|
39873
|
-
(m) => m.role === "assistant" && m.content ? {
|
|
40142
|
+
(m) => m.role === "assistant" && m.content ? {
|
|
40143
|
+
...m,
|
|
40144
|
+
content: cleanAgentContent(m.content, {
|
|
40145
|
+
stripQuestion: false,
|
|
40146
|
+
stripThink: false
|
|
40147
|
+
})
|
|
40148
|
+
} : m
|
|
39874
40149
|
);
|
|
39875
40150
|
const effectiveTask = buildCouncilTaskWithHistory(opts.task, historySeed);
|
|
39876
40151
|
let exitCode = 0;
|
|
@@ -39969,7 +40244,13 @@ async function runHeadlessZelari(opts, provider, model, providerStream) {
|
|
|
39969
40244
|
}
|
|
39970
40245
|
};
|
|
39971
40246
|
const historySeed = (opts.history ?? []).map(
|
|
39972
|
-
(m) => m.role === "assistant" && m.content ? {
|
|
40247
|
+
(m) => m.role === "assistant" && m.content ? {
|
|
40248
|
+
...m,
|
|
40249
|
+
content: cleanAgentContent(m.content, {
|
|
40250
|
+
stripQuestion: false,
|
|
40251
|
+
stripThink: false
|
|
40252
|
+
})
|
|
40253
|
+
} : m
|
|
39973
40254
|
);
|
|
39974
40255
|
const missionTask = buildCouncilTaskWithHistory(opts.task, historySeed);
|
|
39975
40256
|
emit(`[zelari] mission brief
|
|
@@ -40061,7 +40342,8 @@ ${ragContext}` : slicePrompt;
|
|
|
40061
40342
|
}
|
|
40062
40343
|
if (synthesisText.trim()) {
|
|
40063
40344
|
lastMissionAssistant = cleanAgentContent(synthesisText, {
|
|
40064
|
-
stripQuestion: false
|
|
40345
|
+
stripQuestion: false,
|
|
40346
|
+
stripThink: false
|
|
40065
40347
|
});
|
|
40066
40348
|
}
|
|
40067
40349
|
return {
|