zelari-code 1.27.0 → 1.27.2

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.
@@ -35269,10 +35269,17 @@ var init_missionSlice = __esm({
35269
35269
  var planner_exports = {};
35270
35270
  __export(planner_exports, {
35271
35271
  KRAKEN_PLANNER_SYSTEM_PROMPT: () => KRAKEN_PLANNER_SYSTEM_PROMPT,
35272
+ PlannerTransportError: () => PlannerTransportError,
35272
35273
  buildGraphFromPlan: () => buildGraphFromPlan,
35273
35274
  extractJsonObject: () => extractJsonObject,
35274
35275
  planTaskGraph: () => planTaskGraph
35275
35276
  });
35277
+ function resolvePlannerTimeoutMs(env = process.env) {
35278
+ const raw = env.ZELARI_KRAKEN_PLANNER_TIMEOUT_MS;
35279
+ if (raw === void 0 || raw === "") return DEFAULT_LLM_TIMEOUT_MS;
35280
+ const n = Number.parseInt(raw, 10);
35281
+ return Number.isFinite(n) && n >= 0 ? n : DEFAULT_LLM_TIMEOUT_MS;
35282
+ }
35276
35283
  function resolvePlannerMaxTokens(env = process.env) {
35277
35284
  const raw = env.ZELARI_KRAKEN_PLANNER_MAX_TOKENS;
35278
35285
  if (raw === void 0 || raw === "") return DEFAULT_LLM_MAX_TOKENS;
@@ -35321,6 +35328,23 @@ function extractBalancedJsonObject2(s) {
35321
35328
  }
35322
35329
  return null;
35323
35330
  }
35331
+ function escapeJsonControlChar(c) {
35332
+ if (c >= " ") return c;
35333
+ switch (c) {
35334
+ case "\n":
35335
+ return "\\n";
35336
+ case "\r":
35337
+ return "\\r";
35338
+ case " ":
35339
+ return "\\t";
35340
+ case "\b":
35341
+ return "\\b";
35342
+ case "\f":
35343
+ return "\\f";
35344
+ default:
35345
+ return `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`;
35346
+ }
35347
+ }
35324
35348
  function repairLooseJson(s) {
35325
35349
  let out = "";
35326
35350
  let i = 0;
@@ -35332,15 +35356,16 @@ function repairLooseJson(s) {
35332
35356
  i += 1;
35333
35357
  while (i < n) {
35334
35358
  const c = s[i];
35335
- out += c;
35336
35359
  i += 1;
35337
35360
  if (c === "\\") {
35361
+ out += c;
35338
35362
  if (i < n) {
35339
35363
  out += s[i];
35340
35364
  i += 1;
35341
35365
  }
35342
35366
  continue;
35343
35367
  }
35368
+ out += escapeJsonControlChar(c);
35344
35369
  if (c === '"') break;
35345
35370
  }
35346
35371
  continue;
@@ -35359,7 +35384,7 @@ function repairLooseJson(s) {
35359
35384
  i += 1;
35360
35385
  break;
35361
35386
  }
35362
- value += c;
35387
+ value += escapeJsonControlChar(c);
35363
35388
  i += 1;
35364
35389
  }
35365
35390
  out += `"${value.replace(/"/g, '\\"')}"`;
@@ -35431,7 +35456,7 @@ async function resolveLlm(opts) {
35431
35456
  if (!baseUrl) {
35432
35457
  throw new Error(`No base URL for provider '${active}'. Set a custom endpoint in Settings.`);
35433
35458
  }
35434
- const model = opts.model?.trim() || getModelForProvider(active) || process.env.ZELARI_MODEL || "";
35459
+ const model = opts.model?.trim() || process.env.ZELARI_KRAKEN_PLANNER_MODEL?.trim() || getModelForProvider(active) || process.env.ZELARI_MODEL || "";
35435
35460
  if (!model) {
35436
35461
  throw new Error(`No model selected for provider '${active}'`);
35437
35462
  }
@@ -35441,31 +35466,50 @@ async function createDefaultLlmClient(opts) {
35441
35466
  const llm = await resolveLlm(opts);
35442
35467
  return {
35443
35468
  async complete({ system, user }) {
35469
+ const timeoutMs = resolvePlannerTimeoutMs();
35444
35470
  const controller = new AbortController();
35445
- const t = setTimeout(() => controller.abort(), LLM_TIMEOUT_MS);
35471
+ let timedOut = false;
35472
+ const t = timeoutMs > 0 ? setTimeout(() => {
35473
+ timedOut = true;
35474
+ controller.abort();
35475
+ }, timeoutMs) : void 0;
35446
35476
  try {
35447
35477
  const url2 = `${llm.baseUrl.replace(/\/$/, "")}/chat/completions`;
35448
- const res = await fetch(url2, {
35449
- method: "POST",
35450
- signal: controller.signal,
35451
- headers: {
35452
- "content-type": "application/json",
35453
- authorization: `Bearer ${llm.apiKey}`
35454
- },
35455
- body: JSON.stringify({
35456
- model: llm.model,
35457
- temperature: 0.2,
35458
- max_tokens: resolvePlannerMaxTokens(),
35459
- stream: false,
35460
- messages: [
35461
- { role: "system", content: system },
35462
- { role: "user", content: user }
35463
- ]
35464
- })
35465
- });
35478
+ let res;
35479
+ try {
35480
+ res = await fetch(url2, {
35481
+ method: "POST",
35482
+ signal: controller.signal,
35483
+ headers: {
35484
+ "content-type": "application/json",
35485
+ authorization: `Bearer ${llm.apiKey}`
35486
+ },
35487
+ body: JSON.stringify({
35488
+ model: llm.model,
35489
+ temperature: 0.2,
35490
+ max_tokens: resolvePlannerMaxTokens(),
35491
+ stream: false,
35492
+ messages: [
35493
+ { role: "system", content: system },
35494
+ { role: "user", content: user }
35495
+ ]
35496
+ })
35497
+ });
35498
+ } catch (err) {
35499
+ if (timedOut) {
35500
+ throw new PlannerTransportError(
35501
+ `Planner request timed out after ${Math.round(timeoutMs / 1e3)}s (no response). Raise ZELARI_KRAKEN_PLANNER_TIMEOUT_MS, or set ZELARI_KRAKEN_PLANNER_MODEL to a faster non-reasoning model.`
35502
+ );
35503
+ }
35504
+ throw new PlannerTransportError(
35505
+ `Planner request failed: ${err instanceof Error ? err.message : String(err)}`
35506
+ );
35507
+ }
35466
35508
  if (!res.ok) {
35467
35509
  const errBody = await res.text().catch(() => "");
35468
- throw new Error(`LLM HTTP ${res.status}${errBody ? `: ${errBody.slice(0, 200)}` : ""}`);
35510
+ throw new PlannerTransportError(
35511
+ `LLM HTTP ${res.status}${errBody ? `: ${errBody.slice(0, 200)}` : ""}`
35512
+ );
35469
35513
  }
35470
35514
  const json2 = await res.json();
35471
35515
  const choice = json2.choices?.[0];
@@ -35478,7 +35522,7 @@ async function createDefaultLlmClient(opts) {
35478
35522
  `Empty model response${reason ? ` (finish_reason=${reason})` : ""}` + (reason === "length" ? " \u2014 the model likely ran out of tokens before producing JSON; raise ZELARI_KRAKEN_PLANNER_MAX_TOKENS or simplify the prompt." : "")
35479
35523
  );
35480
35524
  } finally {
35481
- clearTimeout(t);
35525
+ if (t !== void 0) clearTimeout(t);
35482
35526
  }
35483
35527
  }
35484
35528
  };
@@ -35568,6 +35612,7 @@ async function planTaskGraph(opts) {
35568
35612
  }
35569
35613
  return graph;
35570
35614
  } catch (err) {
35615
+ if (err instanceof PlannerTransportError) throw err;
35571
35616
  lastError = err instanceof Error ? err.message : String(err);
35572
35617
  userMessage = `${userBase}
35573
35618
 
@@ -35578,7 +35623,7 @@ Your previous response was invalid (${lastError}). Return ONLY corrected JSON ma
35578
35623
  `kraken planner: failed to produce a valid task graph after ${MAX_PLAN_ATTEMPTS} attempts \u2014 ${lastError}`
35579
35624
  );
35580
35625
  }
35581
- var LLM_TIMEOUT_MS, MAX_PLAN_ATTEMPTS, DEFAULT_LLM_MAX_TOKENS, DEFAULT_MAX_RETRIES, KRAKEN_PLANNER_SYSTEM_PROMPT, PlannedNodeSchema, PlannedGraphSchema;
35626
+ var MAX_PLAN_ATTEMPTS, DEFAULT_LLM_TIMEOUT_MS, PlannerTransportError, DEFAULT_LLM_MAX_TOKENS, DEFAULT_MAX_RETRIES, KRAKEN_PLANNER_SYSTEM_PROMPT, PlannedNodeSchema, PlannedGraphSchema;
35582
35627
  var init_planner = __esm({
35583
35628
  "src/cli/kraken/planner.ts"() {
35584
35629
  "use strict";
@@ -35587,8 +35632,14 @@ var init_planner = __esm({
35587
35632
  init_providerConfig();
35588
35633
  init_keyStore();
35589
35634
  init_openai_compatible();
35590
- LLM_TIMEOUT_MS = 9e4;
35591
35635
  MAX_PLAN_ATTEMPTS = 2;
35636
+ DEFAULT_LLM_TIMEOUT_MS = 3e5;
35637
+ PlannerTransportError = class extends Error {
35638
+ constructor(message) {
35639
+ super(message);
35640
+ this.name = "PlannerTransportError";
35641
+ }
35642
+ };
35592
35643
  DEFAULT_LLM_MAX_TOKENS = 8192;
35593
35644
  DEFAULT_MAX_RETRIES = {
35594
35645
  explore: 0,
@@ -35645,6 +35696,7 @@ __export(executor_exports, {
35645
35696
  DEFAULT_FIX_BUDGET: () => DEFAULT_FIX_BUDGET,
35646
35697
  DEFAULT_MAX_PARALLEL: () => DEFAULT_MAX_PARALLEL,
35647
35698
  DEFAULT_NODE_TIMEOUT_MS: () => DEFAULT_NODE_TIMEOUT_MS,
35699
+ DEFAULT_WRITER_NODE_TIMEOUT_MS: () => DEFAULT_WRITER_NODE_TIMEOUT_MS,
35648
35700
  KrakenGraphExecutor: () => KrakenGraphExecutor,
35649
35701
  isKrakenGraphEnabled: () => isKrakenGraphEnabled,
35650
35702
  isWorldModelGateEnabled: () => isWorldModelGateEnabled,
@@ -35666,11 +35718,21 @@ function resolveFixBudget(env = process.env) {
35666
35718
  const n = Number.parseInt(raw, 10);
35667
35719
  return Number.isFinite(n) && n >= 0 ? n : DEFAULT_FIX_BUDGET;
35668
35720
  }
35669
- function resolveNodeTimeoutMs(env = process.env) {
35721
+ function resolveNodeTimeoutMs(env = process.env, agent) {
35670
35722
  const raw = env.ZELARI_KRAKEN_NODE_TIMEOUT_MS;
35671
- if (raw === void 0 || raw === "") return DEFAULT_NODE_TIMEOUT_MS;
35672
- const n = Number.parseInt(raw, 10);
35673
- return Number.isFinite(n) && n >= 0 ? n : DEFAULT_NODE_TIMEOUT_MS;
35723
+ if (raw !== void 0 && raw !== "") {
35724
+ const n = Number.parseInt(raw, 10);
35725
+ if (Number.isFinite(n) && n >= 0) return n;
35726
+ }
35727
+ if (agent === "general") {
35728
+ const rawWriter = env.ZELARI_KRAKEN_WRITER_NODE_TIMEOUT_MS;
35729
+ if (rawWriter !== void 0 && rawWriter !== "") {
35730
+ const n = Number.parseInt(rawWriter, 10);
35731
+ if (Number.isFinite(n) && n >= 0) return n;
35732
+ }
35733
+ return DEFAULT_WRITER_NODE_TIMEOUT_MS;
35734
+ }
35735
+ return DEFAULT_NODE_TIMEOUT_MS;
35674
35736
  }
35675
35737
  function isKrakenGraphEnabled(env = process.env) {
35676
35738
  return env.ZELARI_KRAKEN_GRAPH !== "0";
@@ -35686,7 +35748,7 @@ function defaultChecksExists(cwd) {
35686
35748
  return false;
35687
35749
  }
35688
35750
  }
35689
- var DEFAULT_MAX_PARALLEL, DEFAULT_FIX_BUDGET, DEFAULT_NODE_TIMEOUT_MS, KrakenGraphExecutor;
35751
+ var DEFAULT_MAX_PARALLEL, DEFAULT_FIX_BUDGET, DEFAULT_NODE_TIMEOUT_MS, DEFAULT_WRITER_NODE_TIMEOUT_MS, KrakenGraphExecutor;
35690
35752
  var init_executor = __esm({
35691
35753
  "src/cli/kraken/executor.ts"() {
35692
35754
  "use strict";
@@ -35699,11 +35761,13 @@ var init_executor = __esm({
35699
35761
  DEFAULT_MAX_PARALLEL = 12;
35700
35762
  DEFAULT_FIX_BUDGET = 3;
35701
35763
  DEFAULT_NODE_TIMEOUT_MS = 3e5;
35764
+ DEFAULT_WRITER_NODE_TIMEOUT_MS = 9e5;
35702
35765
  KrakenGraphExecutor = class {
35703
35766
  deps;
35704
35767
  parentCwd;
35705
35768
  sessionId;
35706
35769
  maxParallel;
35770
+ /** Explicit all-kinds override; when undefined the budget is per-kind. */
35707
35771
  nodeTimeoutMs;
35708
35772
  fixBudgetRemaining;
35709
35773
  worldModelGateOverride;
@@ -35717,7 +35781,7 @@ var init_executor = __esm({
35717
35781
  this.parentCwd = opts.parentCwd;
35718
35782
  this.sessionId = opts.sessionId;
35719
35783
  this.maxParallel = opts.maxParallel ?? resolveMaxParallel();
35720
- this.nodeTimeoutMs = opts.nodeTimeoutMs ?? resolveNodeTimeoutMs();
35784
+ this.nodeTimeoutMs = opts.nodeTimeoutMs;
35721
35785
  this.fixBudgetRemaining = opts.fixBudget ?? resolveFixBudget();
35722
35786
  this.worldModelGateOverride = opts.worldModelGate;
35723
35787
  this.runTentacleFn = opts.runTentacleFn ?? runTentacle;
@@ -35818,7 +35882,8 @@ var init_executor = __esm({
35818
35882
  return res;
35819
35883
  }
35820
35884
  /**
35821
- * Bound a tentacle run to `nodeTimeoutMs` wall-clock. On timeout, resolves
35885
+ * Bound a tentacle run to its wall-clock budget (explicit `nodeTimeoutMs`
35886
+ * option, else per-kind — writers get more than readers). On timeout, resolves
35822
35887
  * to a synthetic `TentacleFailure` so the normal retry/fix/cascade-skip
35823
35888
  * path handles it — this only bounds how long the EXECUTOR waits, it does
35824
35889
  * not (cannot) forcibly cancel the underlying sub-agent run; the point is
@@ -35826,8 +35891,8 @@ var init_executor = __esm({
35826
35891
  * can exit instead of hanging forever on one stuck node.
35827
35892
  */
35828
35893
  withNodeTimeout(promise2, agent) {
35829
- if (this.nodeTimeoutMs <= 0) return promise2;
35830
- const ms = this.nodeTimeoutMs;
35894
+ const ms = this.nodeTimeoutMs ?? resolveNodeTimeoutMs(process.env, agent);
35895
+ if (ms <= 0) return promise2;
35831
35896
  let timer;
35832
35897
  const timeout = new Promise((resolve3) => {
35833
35898
  timer = setTimeout(() => {
@@ -48698,7 +48763,7 @@ init_keyStore();
48698
48763
  init_openai_compatible();
48699
48764
  var MAX_PAGE_CHARS = 24e3;
48700
48765
  var FETCH_TIMEOUT_MS2 = 25e3;
48701
- var LLM_TIMEOUT_MS2 = 9e4;
48766
+ var LLM_TIMEOUT_MS = 9e4;
48702
48767
  var SYSTEM = `You convert web page content into a Zelari Code coding skill (SKILL.md style).
48703
48768
 
48704
48769
  Return ONLY a single JSON object (no markdown fences) with keys:
@@ -48841,7 +48906,7 @@ async function generateSkillFromUrl(opts) {
48841
48906
  model: opts.model
48842
48907
  });
48843
48908
  const controller = new AbortController();
48844
- const t = setTimeout(() => controller.abort(), LLM_TIMEOUT_MS2);
48909
+ const t = setTimeout(() => controller.abort(), LLM_TIMEOUT_MS);
48845
48910
  try {
48846
48911
  const url2 = `${llm.baseUrl.replace(/\/$/, "")}/chat/completions`;
48847
48912
  const res = await fetch(url2, {