@gcunharodrigues/wrxn 0.17.0 → 0.18.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gcunharodrigues/wrxn",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "WRXN Kernel — installable AI operating system. Two profiles (project | workspace), pull-based updates, managed/seeded/state file classes.",
5
5
  "bin": {
6
6
  "wrxn": "bin/wrxn.cjs"
@@ -24,19 +24,28 @@ const path = require('path');
24
24
  const https = require('https');
25
25
  const { spawnSync } = require('child_process');
26
26
 
27
- // ── default tiering (PRD) ──────────────────────────────────────────────────────
28
- // handoff + dream default to gemini/gemini-3.1-flash-lite, falling back to claude/claude-sonnet-4-6.
29
- // The seeded memory.config.json is this object serialized; an operator edits it and `wrxn update`
30
- // preserves it (seeded class). Claude stays the fallback so a keyless fresh install still writes a
31
- // baton via the operator's CLI auth (no GEMINI_API_KEY gemini gated claude carries it).
27
+ // ── default tiering (PRD + #59) ────────────────────────────────────────────────
28
+ // handoff stays FAST gemini-3.1-flash-lite with thinkingBudget:0 (reasoning OFF), because handoff is on the
29
+ // 180s session-start hold path. dream REASONS gemini-3.5-flash with thinkingBudget:-1 (dynamic, the model
30
+ // decides) + maxOutputTokens:8192 (sized for reasoning + the ~4.3k-char dream JSON so it can't truncate),
31
+ // because dream runs off the critical path where quality matters. Both fall back to claude/claude-sonnet-4-6.
32
+ // The seeded memory.config.json is DEFAULTS serialized; an operator edits it and `wrxn update` preserves it
33
+ // (seeded class), so EXISTING installs keep their config and only FRESH installs get these defaults (no
34
+ // migration). Claude stays the fallback so a keyless fresh install still writes a baton via the operator's CLI
35
+ // auth (no GEMINI_API_KEY → gemini gated → claude carries it). thinkingBudget: 0 off / -1 dynamic / N>0 bounded.
36
+ // DEFAULT_TASK is the conservative per-task default for any task NOT named in DEFAULTS.tasks (reasoning off,
37
+ // preserving #30's safe default); handoff + dream pin their own tiering below.
32
38
  const DEFAULT_TASK = {
33
- primary: { engine: 'gemini', model: 'gemini-3.1-flash-lite' },
39
+ primary: { engine: 'gemini', model: 'gemini-3.1-flash-lite', thinkingBudget: 0 },
34
40
  fallback: { engine: 'claude', model: 'claude-sonnet-4-6' },
35
41
  };
36
42
  const DEFAULTS = {
37
43
  tasks: {
38
44
  handoff: clone(DEFAULT_TASK),
39
- dream: clone(DEFAULT_TASK),
45
+ dream: {
46
+ primary: { engine: 'gemini', model: 'gemini-3.5-flash', thinkingBudget: -1, maxOutputTokens: 8192 },
47
+ fallback: { engine: 'claude', model: 'claude-sonnet-4-6' },
48
+ },
40
49
  },
41
50
  };
42
51
 
@@ -272,15 +281,17 @@ function buildClaudeSpec({ model, prompt, blob }) {
272
281
  * `x-goog-api-key` header, the task prompt as `system_instruction` and the blob as user content
273
282
  * (mirrors the proven aimem-handoff-synth call). PURE.
274
283
  *
275
- * `thinking` controls the `generationConfig.thinkingConfig` directive (#30): when true (default) the spec
276
- * carries `{ thinkingBudget: 0 }`, which DISABLES model-side thinking on thinking-default models (a verified
277
- * HTTP-200 no-op on non-thinking models) so reasoning tokens never consume the output budget and the answer
278
- * is never split into a dropped `thought` part. Pass `false` to OMIT the directive — the AC3 retry path for
279
- * forced-thinking models (gemma-class) that reject thinkingConfig with an HTTP 400.
284
+ * `thinkingBudget` is the PER-ENGINE reasoning directive (#59, generalizing #30): a NUMBER sets
285
+ * `generationConfig.thinkingConfig = { thinkingBudget }` `0` disables model-side thinking (a verified
286
+ * HTTP-200 no-op on non-thinking models), `-1` lets the model decide (dynamic), `N>0` bounds it to N thinking
287
+ * tokens. An ABSENT budget defaults to `0` (preserves #30's safe default). An explicit `null` OMITS
288
+ * thinkingConfig entirely — the AC3 retry path for forced-thinking models (gemma-class) that reject the
289
+ * directive with an HTTP 400. `maxOutputTokens` is the per-engine output cap (default GEMINI_MAX_OUTPUT_TOKENS).
280
290
  */
281
- function buildGeminiSpec({ model, prompt, blob, apiKey, thinking = true }) {
282
- const generationConfig = { temperature: 0.2, maxOutputTokens: GEMINI_MAX_OUTPUT_TOKENS };
283
- if (thinking) generationConfig.thinkingConfig = { thinkingBudget: 0 };
291
+ function buildGeminiSpec({ model, prompt, blob, apiKey, thinkingBudget = 0, maxOutputTokens = GEMINI_MAX_OUTPUT_TOKENS }) {
292
+ const generationConfig = { temperature: 0.2, maxOutputTokens };
293
+ // a NUMBER (incl. 0 and -1) sets the directive; an explicit `null` OMITS it (the AC3 retry-without path).
294
+ if (thinkingBudget !== null) generationConfig.thinkingConfig = { thinkingBudget };
284
295
  return {
285
296
  engine: 'gemini',
286
297
  method: 'POST',
@@ -450,11 +461,12 @@ async function runEngine(engine, { prompt, blob, apiKey, invoke, sleep = default
450
461
  callOnce = () => invoke(spec);
451
462
  } else if (engine.engine === 'gemini') {
452
463
  if (!apiKey) return { text: null, attempts: 0 }; // missing key fails this engine (→ fallback / null), no request, no retry.
464
+ const { thinkingBudget, maxOutputTokens } = engine; // per-engine reasoning config (#59); absent → buildGeminiSpec defaults (0 / 4096).
453
465
  callOnce = async () => {
454
- const r = await invoke(buildGeminiSpec({ model: engine.model, prompt, blob, apiKey, thinking: true }));
466
+ const r = await invoke(buildGeminiSpec({ model: engine.model, prompt, blob, apiKey, thinkingBudget, maxOutputTokens }));
455
467
  if (r && r.thinkingUnsupported) {
456
- // this model rejects the thinkingConfig directive (forced-thinking / gemma-class) — retry once without it.
457
- return invoke(buildGeminiSpec({ model: engine.model, prompt, blob, apiKey, thinking: false }));
468
+ // this model rejects the thinkingConfig directive (forced-thinking / gemma-class) — retry once without it (same cap).
469
+ return invoke(buildGeminiSpec({ model: engine.model, prompt, blob, apiKey, thinkingBudget: null, maxOutputTokens }));
458
470
  }
459
471
  return r;
460
472
  };
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "tasks": {
3
3
  "handoff": {
4
- "primary": { "engine": "gemini", "model": "gemini-3.1-flash-lite" },
4
+ "primary": { "engine": "gemini", "model": "gemini-3.1-flash-lite", "thinkingBudget": 0 },
5
5
  "fallback": { "engine": "claude", "model": "claude-sonnet-4-6" }
6
6
  },
7
7
  "dream": {
8
- "primary": { "engine": "gemini", "model": "gemini-3.1-flash-lite" },
8
+ "primary": { "engine": "gemini", "model": "gemini-3.5-flash", "thinkingBudget": -1, "maxOutputTokens": 8192 },
9
9
  "fallback": { "engine": "claude", "model": "claude-sonnet-4-6" }
10
10
  }
11
11
  }