volute 0.41.1 → 0.42.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.
Files changed (46) hide show
  1. package/dist/{ai-service-XCLE3MQP.js → ai-service-3GBOJGUA.js} +10 -2
  2. package/dist/{chunk-ULNQ6OC4.js → chunk-2YRTSK5K.js} +2 -2
  3. package/dist/{chunk-IJCZAYGT.js → chunk-4ZSUUBG5.js} +97 -2
  4. package/dist/{chunk-F44AEQAW.js → chunk-52NMCDBS.js} +13 -13
  5. package/dist/{chunk-MJIJFCAH.js → chunk-JLX3GC7T.js} +2 -2
  6. package/dist/chunk-KZAL7HEQ.js +141 -0
  7. package/dist/{chunk-EKLRS2SX.js → chunk-RKBYFLOR.js} +1 -1
  8. package/dist/{chunk-GCS64EAD.js → chunk-TKOWXAHG.js} +3 -3
  9. package/dist/{chunk-MYJSKXGH.js → chunk-VSUZE2PD.js} +3 -3
  10. package/dist/{chunk-763WUVJQ.js → chunk-WR7CSHQ4.js} +1 -1
  11. package/dist/cli.js +7 -7
  12. package/dist/{cloud-sync-2XVXEOSU.js → cloud-sync-3OPHFOYQ.js} +7 -7
  13. package/dist/{create-OTM46ZUM.js → create-YNBZWD34.js} +1 -1
  14. package/dist/{daemon-restart-HDVGTYH7.js → daemon-restart-RAKGR56L.js} +2 -2
  15. package/dist/daemon.js +80 -42
  16. package/dist/{delivery-manager-CPADWRV2.js → delivery-manager-5Y35DOX3.js} +7 -7
  17. package/dist/{echo-text-GEDEEY7M.js → echo-text-YP3JVLNA.js} +8 -8
  18. package/dist/{extensions-SU3N4COT.js → extensions-BTNIUS5J.js} +7 -7
  19. package/dist/{message-delivery-HPMELC4Q.js → message-delivery-FPIL26WV.js} +7 -7
  20. package/dist/{mind-APS4URT7.js → mind-VXV6ZYZY.js} +3 -3
  21. package/dist/{mind-manager-74XQZEGX.js → mind-manager-OYOIBGK6.js} +7 -7
  22. package/dist/{mind-service-XGXSMQP6.js → mind-service-PR4PR4XI.js} +7 -7
  23. package/dist/{package-MVFX22K5.js → package-UWH5IM76.js} +1 -1
  24. package/dist/{sandbox-ND53WZVU.js → sandbox-E7RWZDVG.js} +2 -2
  25. package/dist/{scheduler-MEBQF5MW.js → scheduler-KXUY2I7W.js} +7 -7
  26. package/dist/{seed-L4XFZ3VX.js → seed-YQAOIXIY.js} +1 -1
  27. package/dist/{seed-cmd-NSTPYJFC.js → seed-cmd-7KJS4LCA.js} +2 -2
  28. package/dist/{seed-create-ZYCZC46W.js → seed-create-Z7NDRRGP.js} +3 -3
  29. package/dist/{seed-sprout-YXHU73XA.js → seed-sprout-PYDMVVUL.js} +4 -4
  30. package/dist/{setup-FPFWDMXD.js → setup-IYOUPCIK.js} +5 -1
  31. package/dist/{setup-RMR3TKCR.js → setup-VARJ7N6Z.js} +2 -2
  32. package/dist/{skills-AOZF6U2B.js → skills-YBCYVOPQ.js} +2 -2
  33. package/dist/{sleep-manager-OHM3TO62.js → sleep-manager-FJLASHHW.js} +7 -7
  34. package/dist/{spirit-ONLRFATY.js → spirit-NJFAY5CZ.js} +4 -4
  35. package/dist/{sprout-2KJOQZCL.js → sprout-B27C2WGE.js} +1 -1
  36. package/dist/{system-chat-HZUKBIKJ.js → system-chat-P6KVGW4T.js} +7 -7
  37. package/dist/{turn-tracker-TIX4DY2W.js → turn-tracker-W4TASMR7.js} +3 -3
  38. package/dist/{up-7KVNER6V.js → up-POJX6S5Y.js} +2 -2
  39. package/dist/{version-notify-UFFDUPCX.js → version-notify-TCKAX7ZA.js} +7 -7
  40. package/dist/web-assets/assets/{index-DaUp9iE2.js → index-CrFAsfiE.js} +10 -10
  41. package/dist/web-assets/assets/{index-DqHSW9Fr.css → index-D7udpBCx.css} +1 -1
  42. package/dist/web-assets/index.html +2 -2
  43. package/package.json +1 -1
  44. package/templates/codex/src/server.ts +8 -2
  45. package/templates/pi/src/lib/resolve-model.ts +50 -12
  46. package/dist/chunk-MA7MYEOK.js +0 -71
@@ -8,8 +8,8 @@
8
8
  <link rel="preconnect" href="https://fonts.googleapis.com" />
9
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
10
  <link href="https://fonts.googleapis.com/css2?family=Averia+Serif+Libre:wght@300;400;700&family=Fira+Code:wght@300;400;500;600&family=Averia+Sans+Libre:ital,wght@0,300;0,400;0,500;0,600;1,400&display=swap" rel="stylesheet" />
11
- <script type="module" crossorigin src="/assets/index-DaUp9iE2.js"></script>
12
- <link rel="stylesheet" crossorigin href="/assets/index-DqHSW9Fr.css">
11
+ <script type="module" crossorigin src="/assets/index-CrFAsfiE.js"></script>
12
+ <link rel="stylesheet" crossorigin href="/assets/index-D7udpBCx.css">
13
13
  </head>
14
14
  <body>
15
15
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "volute",
3
- "version": "0.41.1",
3
+ "version": "0.42.0",
4
4
  "description": "CLI for creating and managing self-modifying AI minds powered by the Claude Agent SDK",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -15,7 +15,13 @@ import { createVoluteServer } from "./lib/volute-server.js";
15
15
  const { port } = parseArgs();
16
16
  const config = loadConfig();
17
17
  if (config.logLevel) setLevel(config.logLevel);
18
- if (config.model) log("server", `using model: ${config.model}`);
18
+ // The Codex SDK wants a bare model slug, but config.model may carry a pi-style
19
+ // "provider:model" prefix (e.g. "openai-codex:gpt-5.5") when the spirit's model
20
+ // is provider-qualified. Strip the prefix so the SDK gets just the model.
21
+ const model = config.model?.includes(":")
22
+ ? config.model.slice(config.model.indexOf(":") + 1)
23
+ : config.model;
24
+ if (config.model) log("server", `using model: ${model}`);
19
25
  if (config.reasoningEffort) log("server", `reasoning effort: ${config.reasoningEffort}`);
20
26
 
21
27
  const systemPrompt = loadSystemPrompt();
@@ -28,7 +34,7 @@ const mind = createMind({
28
34
  systemPrompt,
29
35
  cwd,
30
36
  mindDir,
31
- model: config.model,
37
+ model,
32
38
  reasoningEffort: config.reasoningEffort,
33
39
  maxContextTokens: config.compaction?.maxContextTokens,
34
40
  });
@@ -1,21 +1,59 @@
1
1
  import { getBuiltinModel, getBuiltinModels } from "@earendil-works/pi-ai/providers/all";
2
2
 
3
+ /** Length of the shared leading prefix of two strings. */
4
+ function sharedPrefixLength(a: string, b: string): number {
5
+ let i = 0;
6
+ while (i < a.length && i < b.length && a[i] === b[i]) i++;
7
+ return i;
8
+ }
9
+
10
+ /**
11
+ * Build a usable model for a custom id not in the built-in catalog by cloning a
12
+ * sibling built-in model of the same provider (inherits api/baseUrl/compat/caps)
13
+ * and overriding id/name. Picks the sibling sharing the longest id prefix (same
14
+ * family), breaking ties toward the largest context window. Returns undefined
15
+ * when the provider has no built-in models at all.
16
+ *
17
+ * NOTE: mirrors pickSibling/buildCustomModel in the daemon's
18
+ * packages/daemon/src/lib/ai-service.ts (kept as a copy since the template can't
19
+ * import daemon code); keep the two in sync.
20
+ */
21
+ function buildCustomModel(provider: string, id: string) {
22
+ const siblings = getBuiltinModels(provider as any);
23
+ if (siblings.length === 0) return undefined;
24
+ let best = siblings[0];
25
+ let bestPrefix = -1;
26
+ for (const s of siblings) {
27
+ const prefix = sharedPrefixLength(s.id, id);
28
+ if (prefix > bestPrefix || (prefix === bestPrefix && s.contextWindow > best.contextWindow)) {
29
+ bestPrefix = prefix;
30
+ best = s;
31
+ }
32
+ }
33
+ return { ...best, id, name: id, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 } };
34
+ }
35
+
3
36
  export function resolveModel(modelStr: string) {
4
37
  const [provider, ...rest] = modelStr.split(":");
5
38
  const modelId = rest.join(":");
6
39
 
7
- // Try exact match first, then prefix match against available models
8
- let model = getBuiltinModel(provider as any, modelId as any);
9
- if (!model) {
10
- const available = getBuiltinModels(provider as any);
11
- const found = available.find((m) => m.id.startsWith(modelId));
12
- if (found) model = found;
13
- }
14
- if (!model) {
15
- const available = getBuiltinModels(provider as any);
16
- throw new Error(
17
- `Model not found: ${modelStr}\nAvailable ${provider} models: ${available.map((m) => m.id).join(", ")}`,
40
+ // Exact catalog match wins.
41
+ const exact = getBuiltinModel(provider as any, modelId as any);
42
+ if (exact) return exact;
43
+
44
+ // Not in the catalog: treat the id as authoritative and clone a sibling of the
45
+ // same provider. The daemon only ever writes exact ids here (built-in or an
46
+ // admin-registered custom id), so we deliberately do NOT prefix-match — doing so
47
+ // could silently resolve a selected custom id (e.g. "gpt-5") to a different
48
+ // catalog model that starts with it (e.g. "gpt-5-codex"). Mirrors the daemon's
49
+ // exact→custom ordering in ai-service.ts findModel().
50
+ const custom = buildCustomModel(provider, modelId);
51
+ if (custom) {
52
+ console.warn(
53
+ `[resolve-model] "${modelStr}" is not in the built-in catalog; cloning provider defaults from a sibling model. If this id is a typo it will fail at request time.`,
18
54
  );
55
+ return custom;
19
56
  }
20
- return model;
57
+
58
+ throw new Error(`Model not found: ${modelStr}\nUnknown provider: ${provider}`);
21
59
  }
@@ -1,71 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- voluteSystemDir
4
- } from "./chunk-IUZ3EV2D.js";
5
-
6
- // packages/daemon/src/lib/config/setup.ts
7
- import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
8
- import { resolve } from "path";
9
- function configPath() {
10
- return resolve(voluteSystemDir(), "config.json");
11
- }
12
- var _cachedConfig = null;
13
- var CONFIG_CACHE_TTL = 2e3;
14
- function _resetConfigCache() {
15
- _cachedConfig = null;
16
- }
17
- function readGlobalConfig() {
18
- if (_cachedConfig && Date.now() - _cachedConfig.ts < CONFIG_CACHE_TTL) {
19
- return { ..._cachedConfig.config };
20
- }
21
- const path = configPath();
22
- if (!existsSync(path)) {
23
- _cachedConfig = null;
24
- return {};
25
- }
26
- try {
27
- const config = JSON.parse(readFileSync(path, "utf-8"));
28
- _cachedConfig = { config, ts: Date.now() };
29
- return config;
30
- } catch (err) {
31
- console.error(`Failed to parse ${path}: ${err instanceof Error ? err.message : err}`);
32
- return {};
33
- }
34
- }
35
- function writeGlobalConfig(config) {
36
- const path = configPath();
37
- mkdirSync(voluteSystemDir(), { recursive: true });
38
- writeFileSync(path, `${JSON.stringify(config, null, 2)}
39
- `, { mode: 384 });
40
- chmodSync(path, 384);
41
- _cachedConfig = { config, ts: Date.now() };
42
- }
43
- function isSetupComplete() {
44
- const config = readGlobalConfig();
45
- return config.setupCompleted === true;
46
- }
47
- function isImagegenEnabled() {
48
- const config = readGlobalConfig();
49
- const ig = config.imagegen;
50
- if (!ig) return false;
51
- if (ig.enabled === true) return true;
52
- if (ig.providers && Object.keys(ig.providers).length > 0) return true;
53
- return false;
54
- }
55
- function migrateSetupCompleted() {
56
- const config = readGlobalConfig();
57
- if (config.setup != null && config.setupCompleted == null) {
58
- config.setupCompleted = true;
59
- writeGlobalConfig(config);
60
- }
61
- }
62
-
63
- export {
64
- configPath,
65
- _resetConfigCache,
66
- readGlobalConfig,
67
- writeGlobalConfig,
68
- isSetupComplete,
69
- isImagegenEnabled,
70
- migrateSetupCompleted
71
- };