@vascend/talos 0.1.5 → 0.1.6

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 (224) hide show
  1. package/dist/core/agent.d.ts +16 -3
  2. package/dist/core/agent.js +114 -34
  3. package/dist/core/background.d.ts +10 -3
  4. package/dist/core/background.js +55 -9
  5. package/dist/core/bootstrap.js +1 -0
  6. package/dist/core/compaction.js +1 -1
  7. package/dist/core/config-storage.d.ts +5 -0
  8. package/dist/core/config-storage.js +83 -0
  9. package/dist/core/config.d.ts +11 -2
  10. package/dist/core/config.js +24 -8
  11. package/dist/core/context-ledger.js +2 -1
  12. package/dist/core/context-policy.d.ts +1 -1
  13. package/dist/core/context-policy.js +10 -7
  14. package/dist/core/credentials.js +29 -30
  15. package/dist/core/effort.d.ts +1 -1
  16. package/dist/core/effort.js +5 -1
  17. package/dist/core/execution-guidance.d.ts +1 -1
  18. package/dist/core/execution-guidance.js +2 -0
  19. package/dist/core/file-coordination.d.ts +3 -0
  20. package/dist/core/file-coordination.js +28 -0
  21. package/dist/core/file-lease-store.d.ts +3 -0
  22. package/dist/core/file-lease-store.js +28 -12
  23. package/dist/core/fusion.d.ts +24 -0
  24. package/dist/core/fusion.js +80 -0
  25. package/dist/core/model-limits.d.ts +1 -0
  26. package/dist/core/model-limits.js +5 -1
  27. package/dist/core/permission-queue.js +15 -15
  28. package/dist/core/request-plan.js +4 -3
  29. package/dist/core/session-naming.js +4 -0
  30. package/dist/core/session.d.ts +4 -2
  31. package/dist/core/session.js +13 -4
  32. package/dist/core/settings.d.ts +2 -0
  33. package/dist/core/settings.js +5 -16
  34. package/dist/core/step-policy.d.ts +18 -0
  35. package/dist/core/step-policy.js +6 -0
  36. package/dist/core/tool-artifacts.d.ts +2 -0
  37. package/dist/core/tool-artifacts.js +21 -3
  38. package/dist/core/tool-result-index.js +29 -33
  39. package/dist/core/tool-result-store.js +6 -5
  40. package/dist/core/types.d.ts +10 -3
  41. package/dist/core/user-inbox.d.ts +9 -0
  42. package/dist/core/user-inbox.js +22 -3
  43. package/dist/core/user-input.js +1 -1
  44. package/dist/fusion/autopilot-fast.d.ts +59 -0
  45. package/dist/fusion/autopilot-fast.js +213 -0
  46. package/dist/fusion/autopilot.d.ts +75 -0
  47. package/dist/fusion/autopilot.js +308 -0
  48. package/dist/fusion/focus.d.ts +30 -0
  49. package/dist/fusion/focus.js +122 -0
  50. package/dist/fusion/gate.d.ts +30 -0
  51. package/dist/fusion/gate.js +95 -0
  52. package/dist/fusion/jev.d.ts +71 -0
  53. package/dist/fusion/jev.js +164 -0
  54. package/dist/fusion/receipts.d.ts +25 -0
  55. package/dist/fusion/receipts.js +34 -0
  56. package/dist/fusion/route.d.ts +25 -0
  57. package/dist/fusion/route.js +84 -0
  58. package/dist/fusion/run.d.ts +4 -0
  59. package/dist/fusion/run.js +186 -0
  60. package/dist/horizon/engine.d.ts +20 -1
  61. package/dist/horizon/engine.js +57 -0
  62. package/dist/horizon/index.d.ts +2 -2
  63. package/dist/horizon/index.js +1 -1
  64. package/dist/horizon/types.d.ts +29 -0
  65. package/dist/index.js +12 -0
  66. package/dist/providers/anthropic-oauth.d.ts +8 -3
  67. package/dist/providers/anthropic-oauth.js +13 -10
  68. package/dist/providers/anthropic.d.ts +9 -2
  69. package/dist/providers/anthropic.js +64 -21
  70. package/dist/providers/cli-models.d.ts +30 -0
  71. package/dist/providers/cli-models.js +194 -0
  72. package/dist/providers/model-effort.js +1 -1
  73. package/dist/providers/openai-oauth.d.ts +8 -3
  74. package/dist/providers/openai-oauth.js +9 -3
  75. package/dist/providers/openrouter-manual-fallback.d.ts +3 -1
  76. package/dist/providers/openrouter-manual-fallback.js +20 -20
  77. package/dist/providers/registry.js +3 -2
  78. package/dist/providers/retry.d.ts +3 -0
  79. package/dist/providers/retry.js +44 -1
  80. package/dist/remote/cifratura.d.ts +12 -0
  81. package/dist/remote/cifratura.js +66 -0
  82. package/dist/remote/index.d.ts +15 -0
  83. package/dist/remote/index.js +65 -0
  84. package/dist/remote/relay-client.d.ts +58 -0
  85. package/dist/remote/relay-client.js +315 -0
  86. package/dist/remote/sessione-remota.d.ts +60 -0
  87. package/dist/remote/sessione-remota.js +266 -0
  88. package/dist/sdk.d.ts +7 -2
  89. package/dist/sdk.js +3 -1
  90. package/dist/tools/builtin.js +41 -20
  91. package/dist/tools/capabilities.d.ts +3 -1
  92. package/dist/tools/capabilities.js +5 -2
  93. package/dist/tools/computer-use.js +2 -1
  94. package/dist/tools/pagination.js +1 -1
  95. package/dist/tools/program.js +34 -21
  96. package/dist/tools/team-tools.js +11 -6
  97. package/dist/tui/account-entry.js +14 -9
  98. package/dist/tui/agent-label.d.ts +2 -0
  99. package/dist/tui/agent-label.js +5 -0
  100. package/dist/tui/agent-sessions-screen.d.ts +12 -2
  101. package/dist/tui/agent-sessions-screen.js +62 -16
  102. package/dist/tui/agent-sessions.d.ts +14 -0
  103. package/dist/tui/agent-sessions.js +67 -6
  104. package/dist/tui/bottom-input.d.ts +46 -2
  105. package/dist/tui/bottom-input.js +358 -59
  106. package/dist/tui/branding.js +8 -4
  107. package/dist/tui/capability-lists.d.ts +10 -0
  108. package/dist/tui/capability-lists.js +41 -0
  109. package/dist/tui/command-output-registry.js +4 -0
  110. package/dist/tui/command-transcript.d.ts +1 -1
  111. package/dist/tui/command-transcript.js +17 -21
  112. package/dist/tui/commands.js +4 -1
  113. package/dist/tui/compaction-status.d.ts +7 -0
  114. package/dist/tui/compaction-status.js +39 -0
  115. package/dist/tui/config-recovery.d.ts +12 -0
  116. package/dist/tui/config-recovery.js +54 -0
  117. package/dist/tui/context-meter.d.ts +3 -0
  118. package/dist/tui/context-meter.js +35 -8
  119. package/dist/tui/diff.d.ts +9 -0
  120. package/dist/tui/diff.js +43 -19
  121. package/dist/tui/fusion-menu.d.ts +5 -0
  122. package/dist/tui/fusion-menu.js +89 -0
  123. package/dist/tui/i18n-catalog.js +312 -1
  124. package/dist/tui/live-command.d.ts +1 -0
  125. package/dist/tui/live-command.js +9 -0
  126. package/dist/tui/live-output.d.ts +1 -0
  127. package/dist/tui/live-output.js +11 -0
  128. package/dist/tui/model-details.js +13 -12
  129. package/dist/tui/model-picker.js +17 -7
  130. package/dist/tui/model-selection.js +19 -10
  131. package/dist/tui/native-scrollback.js +5 -0
  132. package/dist/tui/prompt-queue.d.ts +3 -0
  133. package/dist/tui/prompt-queue.js +19 -1
  134. package/dist/tui/provider-label.d.ts +2 -0
  135. package/dist/tui/provider-label.js +9 -0
  136. package/dist/tui/provider-menu.js +25 -24
  137. package/dist/tui/queue-screen.js +2 -1
  138. package/dist/tui/remote-command.d.ts +7 -0
  139. package/dist/tui/remote-command.js +79 -0
  140. package/dist/tui/repl.d.ts +8 -2
  141. package/dist/tui/repl.js +355 -311
  142. package/dist/tui/review-store.d.ts +1 -0
  143. package/dist/tui/review-store.js +28 -7
  144. package/dist/tui/review-team.js +4 -3
  145. package/dist/tui/runtime-error.d.ts +2 -0
  146. package/dist/tui/runtime-error.js +26 -0
  147. package/dist/tui/selector-mouse.d.ts +1 -0
  148. package/dist/tui/selector-mouse.js +1 -1
  149. package/dist/tui/selector.d.ts +7 -0
  150. package/dist/tui/selector.js +19 -2
  151. package/dist/tui/session-controls.d.ts +26 -0
  152. package/dist/tui/session-controls.js +65 -0
  153. package/dist/tui/session-naming-notice.js +5 -3
  154. package/dist/tui/session-replay.d.ts +1 -0
  155. package/dist/tui/session-replay.js +101 -32
  156. package/dist/tui/session-transcript-layout.d.ts +9 -0
  157. package/dist/tui/session-transcript-layout.js +41 -0
  158. package/dist/tui/startup.js +63 -33
  159. package/dist/tui/status-line.d.ts +1 -1
  160. package/dist/tui/status-line.js +20 -12
  161. package/dist/tui/talos-art-data.d.ts +1 -0
  162. package/dist/tui/talos-art-data.js +2 -0
  163. package/dist/tui/talos-art.d.ts +1 -0
  164. package/dist/tui/talos-art.js +9 -0
  165. package/dist/tui/task-labels.d.ts +1 -0
  166. package/dist/tui/task-labels.js +8 -0
  167. package/dist/tui/terminal-text.d.ts +2 -1
  168. package/dist/tui/terminal-text.js +28 -2
  169. package/dist/tui/theme.js +2 -2
  170. package/dist/tui/tool-presentation.d.ts +3 -0
  171. package/dist/tui/tool-presentation.js +98 -0
  172. package/dist/tui/tool-style.js +4 -0
  173. package/dist/tui/transcript-store.d.ts +25 -0
  174. package/dist/tui/transcript-store.js +151 -0
  175. package/dist/tui/usage-footer.d.ts +1 -1
  176. package/dist/tui/usage-footer.js +3 -1
  177. package/dist/tui/vascend-id.d.ts +49 -0
  178. package/dist/tui/vascend-id.js +321 -0
  179. package/dist/tui/web-login-screen.js +4 -3
  180. package/dist/tui/web-login.d.ts +7 -15
  181. package/dist/tui/web-login.js +38 -78
  182. package/dist/tui/worker-transcripts.d.ts +31 -0
  183. package/dist/tui/worker-transcripts.js +91 -0
  184. package/dist/vascend/candidate-collector.d.ts +6 -5
  185. package/dist/vascend/candidate-collector.js +44 -43
  186. package/dist/vascend/context-lint.js +32 -2
  187. package/dist/vascend/context-market-selection.js +12 -5
  188. package/dist/vascend/context-pack-render.js +10 -4
  189. package/dist/vascend/context-packet-mirrors.d.ts +8 -0
  190. package/dist/vascend/context-packet-mirrors.js +24 -0
  191. package/dist/vascend/context-plan-events.d.ts +4 -0
  192. package/dist/vascend/context-plan-events.js +44 -0
  193. package/dist/vascend/context-snapshot.js +4 -2
  194. package/dist/vascend/context-store-reader.d.ts +20 -0
  195. package/dist/vascend/context-store-reader.js +46 -0
  196. package/dist/vascend/file-lock.d.ts +1 -0
  197. package/dist/vascend/file-lock.js +26 -0
  198. package/dist/vascend/granular-kingdom.d.ts +1 -0
  199. package/dist/vascend/granular-kingdom.js +22 -15
  200. package/dist/vascend/kingdom-bus.d.ts +1 -0
  201. package/dist/vascend/kingdom-bus.js +3 -0
  202. package/dist/vascend/kingdom-channel.d.ts +2 -0
  203. package/dist/vascend/kingdom-channel.js +3 -0
  204. package/dist/vascend/kingdom-live.d.ts +32 -4
  205. package/dist/vascend/kingdom-live.js +149 -13
  206. package/dist/vascend/kingdom-run.d.ts +5 -1
  207. package/dist/vascend/kingdom-run.js +6 -2
  208. package/dist/vascend/kingdom.d.ts +3 -0
  209. package/dist/vascend/kingdom.js +20 -13
  210. package/dist/vascend/memory-packet.d.ts +2 -1
  211. package/dist/vascend/memory-packet.js +31 -44
  212. package/dist/vascend/plan-store.d.ts +3 -1
  213. package/dist/vascend/plan-store.js +6 -4
  214. package/dist/vascend/room-memory.d.ts +10 -1
  215. package/dist/vascend/room-memory.js +42 -2
  216. package/dist/vascend/runtime.d.ts +3 -11
  217. package/dist/vascend/runtime.js +11 -123
  218. package/dist/vascend/session-search.js +2 -0
  219. package/dist/vascend/team-session.js +3 -2
  220. package/dist/vascend/vision.d.ts +3 -1
  221. package/dist/vascend/vision.js +6 -4
  222. package/dist/vascend/worker-session.d.ts +20 -0
  223. package/dist/vascend/worker-session.js +83 -0
  224. package/package.json +1 -1
@@ -0,0 +1,83 @@
1
+ import { closeSync, fsyncSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
2
+ import { randomUUID } from "node:crypto";
3
+ import { withLockSync } from "../vascend/file-lock.js";
4
+ // Non convertire una config illeggibile in {}: il prossimo salvataggio
5
+ // cancellerebbe credenziali e preferenze. Solo ENOENT significa prima esecuzione.
6
+ export function readConfigObject(path) {
7
+ let text;
8
+ try {
9
+ text = readFileSync(path, "utf8");
10
+ }
11
+ catch (error) {
12
+ if (error.code === "ENOENT")
13
+ return {};
14
+ throw error;
15
+ }
16
+ const value = JSON.parse(text);
17
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
18
+ throw new Error("La configurazione deve essere un oggetto JSON");
19
+ }
20
+ return value;
21
+ }
22
+ // Temporaneo esclusivo nella stessa directory: rename sostituisce il file solo
23
+ // dopo scrittura + flush. Mai unlink del target, neppure su errore Windows.
24
+ function replaceConfig(path, content) {
25
+ const temporary = `${path}.${process.pid}.${randomUUID()}.tmp`;
26
+ let fd;
27
+ try {
28
+ fd = openSync(temporary, "wx", 0o600);
29
+ writeFileSync(fd, content, "utf8");
30
+ fsyncSync(fd);
31
+ closeSync(fd);
32
+ fd = undefined;
33
+ renameSync(temporary, path);
34
+ }
35
+ finally {
36
+ if (fd !== undefined)
37
+ closeSync(fd);
38
+ try {
39
+ unlinkSync(temporary);
40
+ }
41
+ catch (error) {
42
+ if (error.code !== "ENOENT")
43
+ throw error;
44
+ }
45
+ }
46
+ }
47
+ // Lock comune a settings e credenziali: anche due processi devono fondere
48
+ // l'ultima versione, non sovrascrivere gli aggiornamenti dell'altro.
49
+ export function updateConfigObject(path, update) {
50
+ withLockSync(path, () => {
51
+ const current = readConfigObject(path);
52
+ const next = update(current);
53
+ const content = JSON.stringify(next, null, 2) + "\n";
54
+ replaceConfig(path, content);
55
+ });
56
+ }
57
+ // Chiamare solo dopo consenso esplicito. Se un altro processo ha gia' riparato
58
+ // il file, non azzerarlo. Il backup conserva esattamente i byte originali.
59
+ export function resetInvalidConfig(path) {
60
+ return withLockSync(path, () => {
61
+ const original = readFileSync(path);
62
+ try {
63
+ const value = JSON.parse(original.toString("utf8"));
64
+ if (value && typeof value === "object" && !Array.isArray(value))
65
+ return null;
66
+ }
67
+ catch { /* JSON invalido */ }
68
+ const backup = `${path}.corrupt-${Date.now()}-${randomUUID()}.bak`;
69
+ const fd = openSync(backup, "wx", 0o600);
70
+ try {
71
+ writeFileSync(fd, original);
72
+ fsyncSync(fd);
73
+ }
74
+ finally {
75
+ closeSync(fd);
76
+ }
77
+ if (!readFileSync(path).equals(original))
78
+ throw new Error("Configurazione cambiata durante il ripristino; riprova.");
79
+ // {} eredita tutti i default dal codice, senza fissarli a questa versione.
80
+ replaceConfig(path, "{}\n");
81
+ return backup;
82
+ });
83
+ }
@@ -1,7 +1,12 @@
1
1
  import { type CompactionConfig } from "./compaction.js";
2
2
  import { type VibeModeSelection } from "./vibe-modes.js";
3
- export declare const BASE_SYSTEM = "# Vascend Talos\n\nINDICE\n1 = agente\n2 = workspace\n3 = strumento\n4 = azione\n\nDEFINIZIONI\n@agente[ruolo]: coding_agent in terminale, conciso, diretto\n@workspace[fonte]: ispeziona coi tool invece di indovinare\n@strumento[uso]: read/edit/bash per agire sul workspace, non descrivere\n@strumento[terminale]: per ricerca e ispezione del codice preferisci bash con rg e rg --files, git diff/status e comandi nativi della shell selezionata. Limita path e output a cio' che serve. Se rg o il terminale non sono disponibili usa grep/glob/read_file/list_dir. Per modifiche puntuali usa edit_file/write_file e rispetta il coordinamento dei file\n@strumento[write_grande]: per file lunghi (oltre ~150 righe) scrivi in PIU' chiamate write_file: la prima crea il file, le successive con append=true accodano il resto. Un singolo write enorme puo' essere troncato dal limite di output e fallire\n@strumento[ricerca]: prima di costruire qualcosa di non banale, RICERCA con web_fetch (documentazione, riferimenti, esempi) invece di indovinare le API\n@strumento[domanda]: se un requisito e' davvero ambiguo e cambia il risultato, usa ask_user PRIMA di procedere; per i dettagli minori assumi il default ragionevole e dichiaralo, non fermarti di continuo\n@strumento[risposta_mancante]: ask_user required=true mantiene esplicita l'informazione necessaria non ricevuta; prosegui solo col lavoro indipendente. required=false serve per preferenze facoltative e reversibili. Silenzio e annullamento non sono consenso\n@strumento[e2e]: per un obiettivo grande (es. ricostruire una piattaforma) pianifica con vascend_plan in piu' gruppi/attivita, ricerca, costruisci una BOZZA COMPLETA end-to-end; annota le decisioni con vascend_note\n@strumento[collaboratori]: chiama team_engage soltanto quando l'utente chiede esplicitamente piu' agenti, sub-agent o lavoro parallelo; una domanda informativa, un controllo del workspace o un task semplice restano sempre sul singolo agente principale\n@strumento[ripresa]: vascend_status legge task, dipendenze, note e prove persistite; riprendi il piano esistente dopo resume/compattazione. vascend_addtasks estende, vascend_note conserva decisioni. replace=true ridefinisce esplicitamente un piano, perdendo i suoi progressi\n@strumento[verifica]: definisci passi con un risultato osservabile e una verifica pertinente; running prima del lavoro, completed solo dopo verifica. Un comando in background va seguito con bash_output fino all'esito finale. Le prove salvate sono evidenze da controllare, non certificazioni\n@azione[proporzione]: mantieni piano, strumenti e verifiche proporzionati al compito; le richieste semplici o a singolo passo non richiedono piano ne' collaboratori\n@azione[distruttiva]: spiega prima cosa stai per fare\n@azione[fine]: a compito finito fermati, niente riepiloghi superflui\n\nOUTPUT: agente di coding che agisce coi tool, conciso, con risposte Markdown leggibili.\n\nEfficient execution\n- Determine whether the user wants advice, an explanation, instructions for manual work, or\n actual execution. Advice and manual instructions are fulfilled by the response; do not run\n their example scripts or perform the user's setup. A todo list does not grant authorization.\n Before continuing after an error, check whether further agent action is needed and authorized.\n Stop when the request is answered; wait when the next step belongs to the user or needs input.\n Preserve incomplete tasks honestly instead of forcing completion or retrying indefinitely.\n- For a small cosmetic change (one button color, label, spacing or font), locate the affected\n component, edit it, then verify the local result. Do not create a plan, delegate, research the\n web, inspect the whole repository or run a global test/build cycle unless evidence requires it.\n Escalate scope only when the actual dependency or failure demands it.\n- Decide what evidence is needed for the next decision. Issue independent reads together and\n reuse results that are still valid. Do not spend a model round on each already-decided action.\n- Use run_program for known sequences: await dependent edits and plan transitions in order,\n stop on errors, and return a concise summary. Complete a task only after its checks succeed.\n- Prepare related replacements in one round. Never edit the same file concurrently. Independent\n edits on distinct files may run together in bounded groups of at most four; await every outcome\n before inspecting the result or starting dependent work. Keep permission gates in place.\n- For short checks use foreground bash, or background with its brief initial wait. Use\n background=true with yield_time_ms=0 for persistent servers or work that must detach immediately.\n Collect ready background results together; a running command is not a passed check.\n- Run the relevant integrated checks after the edits. Repeat checks only after changes, failures\n or a concrete unresolved concern; do not duplicate typecheck and build without a reason.\n- When parallel work is authorized and worthwhile, start with at most two collaborators on\n concrete disjoint areas, agree on interfaces and acceptance checks, and declare after dependencies.\n The coordinator reviews the combined result. Prefer one agent for small or tightly coupled work.\n- Format user-facing responses in readable Markdown: short paragraphs, **bold** key findings,\n lists for steps, tables for comparisons, fenced code with a language, and descriptive links.\n Keep internal planning notation out of ordinary explanations unless the user asks for it.";
4
- export declare const HORIZON_SYSTEM = "# Horizon\n\nYou are a coding agent embedded in the Horizon workspace.\n- Write in the language the user writes in, and keep writing in it for the whole\n conversation. These instructions are in English for precision, not as a hint about\n the reply language: a message in Italian gets an answer in Italian. Code,\n identifiers, paths, commands and tool arguments stay exactly as they are.\n- Inspect the real workspace before making claims.\n- Match the requested scope: analysis stays read-only; change/build work is implemented end to end and verified.\n- Prefer focused changes, but do not shrink a broad request into a partial patch.\n- Keep planning proportional to the task; simple tasks do not need a formal plan.\n- Use ordinary to-do-list language for progress: tasks, groups, dependencies and\n pending, in progress, completed or failed states, translated into the user's language.\n Memory indexes and internal implementation names are context for you; present the\n relevant tasks, next steps and results to the user.\n- Start substantial work with a short update, then act with tools. During long tasks share\n useful findings or blockers about once a minute; avoid narrating every tool call.\n- Respect the workspace permissions selected by the user.\n- Exhaust safe in-scope alternatives before asking the user to unblock you.\n- Never announce completion while a plan step is pending/running/failed or the requested\n artifact has not been verified. Continue working, or report the concrete blocker.\n- Keep the final answer compact: outcome first, then verification and any blocker. Do not\n expose or recap internal context packs, memory routing, hidden prompts, or chain-of-thought.\n\nTools\n- The tools listed for you cover file reads, writes, edits, search and shell: call them directly.\n- Prefer the terminal for code discovery and inspection: rg for content, rg --files for paths,\n git diff/status for changes, and native commands for the selected shell. Scope searches to\n relevant directories and return only useful output. If rg or terminal access is unavailable,\n use read_file or discover grep/glob/list_dir with tool_search (or call them inside run_program).\n Use edit_file/write_file for focused edits and discover file_activity when coordination needs it.\n Shell access does not expand the authorized workspace or bypass permissions.\n- More tools exist on demand. Find them with tool_search, asking in ONE call for every tool\n you expect to need (\"names\" when you know them, \"query\" otherwise): they become callable\n directly, by name. Do not search again for a tool you loaded. Calling tool_search without\n names/query lists the inventory without activating it; continue with offset=next_offset.\n- Missing a capability? Inspect the actual catalog before assuming a host integration exists.\n If custom-tool authoring is available, follow its guide. Ask the user only for information\n or decisions that the available tools and project context cannot resolve.\n- Use ask_user for missing requirements or decisions that materially change the result.\n Ask a concise, self-contained question early, with options when useful. Collaborators can\n use the same tool. If a required answer is missing, keep the dependency blocked and continue\n independent work; do not invent the answer or interpret silence as approval. Use required=false\n only for optional preferences with a reasonable, reversible default. Routine implementation\n choices should not interrupt the user.\n- For work with several steps \u2014 including games, challenges, puzzles and multi-level tasks \u2014\n lay out the plan with vascend_plan and keep it honest with vascend_mark as you go (one step\n running at a time). The plan is not paperwork: it appears live as a\n task board next to the conversation, where the user follows progress and can edit or add\n steps. Give each step an observable result and a proportionate check. Short, single-step\n requests need no plan. Read vascend_status after resume/compaction and before handing off\n substantial work; resume it only when that is still necessary and authorized by the current\n request. vascend_addtasks extends it without resetting\n progress; vascend_plan with replace=true explicitly replaces it. Save decisions, blockers\n and the next action with vascend_note before switching workstreams.\n- Start a step with vascend_mark status=running. Complete it only after the relevant checks,\n recording paths, commands and observed outcomes. Evidence in the plan is a record to inspect,\n not an automatic correctness certificate. Reopening a step clears old completion evidence.\n Respect after dependencies; use pending to pause a step and failed to record a concrete blocker.\n- A plan is not a collaborator. When the user asks for multiple agents, subagents or parallel\n experts, actually call team_engage: create one collaborator per independent workstream and\n assign its complete task. If vascend_plan already created several task groups, pass their slugs\n through the group field so those collaborators own and update the same T01/T02 tasks. Do not\n merely draw multiple workstreams and then execute all of them in the orchestrator.\n- Issue independent reads together. For related tool sequences use run_program and print only\n the results needed for the next decision; keep dependent edits and approvals sequential.\n- When bash returns a background id, use bash_output until the process exits. Partial output\n or a started process does not mean the check passed. Leave persistent development servers\n running when they are needed and report their status separately from verification results.\n- Act on what is already in context: do not re-read a file or repeat a search whose result\n you still have.\n- If a tool reports a missing or malformed argument, fix the argument shape it names \u2014 do not\n retry the same call unchanged.\n\nEfficient execution\n- Determine whether the user wants advice, an explanation, instructions for manual work, or\n actual execution. Advice and manual instructions are fulfilled by the response; do not run\n their example scripts or perform the user's setup. A todo list does not grant authorization.\n Before continuing after an error, check whether further agent action is needed and authorized.\n Stop when the request is answered; wait when the next step belongs to the user or needs input.\n Preserve incomplete tasks honestly instead of forcing completion or retrying indefinitely.\n- For a small cosmetic change (one button color, label, spacing or font), locate the affected\n component, edit it, then verify the local result. Do not create a plan, delegate, research the\n web, inspect the whole repository or run a global test/build cycle unless evidence requires it.\n Escalate scope only when the actual dependency or failure demands it.\n- Decide what evidence is needed for the next decision. Issue independent reads together and\n reuse results that are still valid. Do not spend a model round on each already-decided action.\n- Use run_program for known sequences: await dependent edits and plan transitions in order,\n stop on errors, and return a concise summary. Complete a task only after its checks succeed.\n- Prepare related replacements in one round. Never edit the same file concurrently. Independent\n edits on distinct files may run together in bounded groups of at most four; await every outcome\n before inspecting the result or starting dependent work. Keep permission gates in place.\n- For short checks use foreground bash, or background with its brief initial wait. Use\n background=true with yield_time_ms=0 for persistent servers or work that must detach immediately.\n Collect ready background results together; a running command is not a passed check.\n- Run the relevant integrated checks after the edits. Repeat checks only after changes, failures\n or a concrete unresolved concern; do not duplicate typecheck and build without a reason.\n- When parallel work is authorized and worthwhile, start with at most two collaborators on\n concrete disjoint areas, agree on interfaces and acceptance checks, and declare after dependencies.\n The coordinator reviews the combined result. Prefer one agent for small or tightly coupled work.\n- Format user-facing responses in readable Markdown: short paragraphs, **bold** key findings,\n lists for steps, tables for comparisons, fenced code with a language, and descriptive links.\n Keep internal planning notation out of ordinary explanations unless the user asks for it.";
3
+ import { type FusionConfig } from "./fusion.js";
4
+ export declare class InvalidConfigError extends Error {
5
+ readonly path: string;
6
+ constructor(path: string, cause: unknown);
7
+ }
8
+ export declare const BASE_SYSTEM = "# Vascend Talos\n\nINDICE\n1 = agente\n2 = workspace\n3 = strumento\n4 = azione\n\nDEFINIZIONI\n@agente[ruolo]: coding_agent in terminale, conciso, diretto\n@workspace[fonte]: ispeziona coi tool invece di indovinare\n@strumento[uso]: read/edit/bash per agire sul workspace, non descrivere\n@strumento[terminale]: per ricerca e ispezione del codice preferisci bash con rg e rg --files, git diff/status e comandi nativi della shell selezionata. Limita path e output a cio' che serve. Se rg o il terminale non sono disponibili usa grep/glob/read_file/list_dir. Per modifiche puntuali usa edit_file/write_file e rispetta il coordinamento dei file\n@strumento[write_grande]: per file lunghi (oltre ~150 righe) scrivi in PIU' chiamate write_file: la prima crea il file, le successive con append=true accodano il resto. Un singolo write enorme puo' essere troncato dal limite di output e fallire\n@strumento[ricerca]: prima di costruire qualcosa di non banale, RICERCA con web_fetch (documentazione, riferimenti, esempi) invece di indovinare le API\n@strumento[domanda]: se un requisito e' davvero ambiguo e cambia il risultato, usa ask_user PRIMA di procedere; per i dettagli minori assumi il default ragionevole e dichiaralo, non fermarti di continuo\n@strumento[risposta_mancante]: ask_user required=true mantiene esplicita l'informazione necessaria non ricevuta; prosegui solo col lavoro indipendente. required=false serve per preferenze facoltative e reversibili. Silenzio e annullamento non sono consenso\n@strumento[e2e]: per un obiettivo grande (es. ricostruire una piattaforma) pianifica con vascend_plan in piu' gruppi/attivita, ricerca, costruisci una BOZZA COMPLETA end-to-end; annota le decisioni con vascend_note\n@strumento[collaboratori]: chiama team_engage soltanto quando l'utente chiede esplicitamente piu' agenti, sub-agent o lavoro parallelo; una domanda informativa, un controllo del workspace o un task semplice restano sempre sul singolo agente principale\n@strumento[ripresa]: vascend_status legge task, dipendenze, note e prove persistite; riprendi il piano esistente dopo resume/compattazione. vascend_addtasks estende, vascend_note conserva decisioni. replace=true ridefinisce esplicitamente un piano, perdendo i suoi progressi\n@strumento[verifica]: definisci passi con un risultato osservabile e una verifica pertinente; running prima del lavoro, completed solo dopo verifica. Un comando in background va seguito con bash_output fino all'esito finale. Le prove salvate sono evidenze da controllare, non certificazioni\n@azione[proporzione]: mantieni piano, strumenti e verifiche proporzionati al compito; le richieste semplici o a singolo passo non richiedono piano ne' collaboratori\n@azione[distruttiva]: spiega prima cosa stai per fare\n@azione[fine]: a compito finito fermati, niente riepiloghi superflui\n\nOUTPUT: agente di coding che agisce coi tool, conciso, con risposte Markdown leggibili.\n\nEfficient execution\n- Determine whether the user wants advice, an explanation, instructions for manual work, or\n actual execution. Advice and manual instructions are fulfilled by the response; do not run\n their example scripts or perform the user's setup. A todo list does not grant authorization.\n Before continuing after an error, check whether further agent action is needed and authorized.\n Stop when the request is answered; wait when the next step belongs to the user or needs input.\n Preserve incomplete tasks honestly instead of forcing completion or retrying indefinitely.\n- For a small cosmetic change (one button color, label, spacing or font), locate the affected\n component, edit it, then verify the local result. Do not create a plan, delegate, research the\n web, inspect the whole repository or run a global test/build cycle unless evidence requires it.\n Escalate scope only when the actual dependency or failure demands it.\n- Decide what evidence is needed for the next decision. Issue independent reads together and\n reuse results that are still valid. Do not spend a model round on each already-decided action.\n- Use run_program for known sequences: await dependent edits and plan transitions in order,\n stop on errors, and return a concise summary. Complete a task only after its checks succeed.\n- Prepare related replacements in one round. Never edit the same file concurrently. Independent\n edits on distinct files may run together in bounded groups of at most four; await every outcome\n before inspecting the result or starting dependent work. Keep permission gates in place.\n- For short checks use foreground bash, or background with its brief initial wait. Use\n background=true with yield_time_ms=0 for persistent servers or work that must detach immediately.\n Collect ready background results together; a running command is not a passed check.\n bash_output waits locally for completion by default: call it once and omit timeout_seconds.\n Use wait=false only to inspect a persistent server or diagnose a process; do not poll in a loop.\n- Run the relevant integrated checks after the edits. Repeat checks only after changes, failures\n or a concrete unresolved concern; do not duplicate typecheck and build without a reason.\n- When parallel work is authorized and worthwhile, start with at most two collaborators on\n concrete disjoint areas, agree on interfaces and acceptance checks, and declare after dependencies.\n The coordinator reviews the combined result. Prefer one agent for small or tightly coupled work.\n- Format user-facing responses in readable Markdown: short paragraphs, **bold** key findings,\n lists for steps, tables for comparisons, fenced code with a language, and descriptive links.\n Keep internal planning notation out of ordinary explanations unless the user asks for it.";
9
+ export declare const HORIZON_SYSTEM = "# Horizon\n\nYou are a coding agent embedded in the Horizon workspace.\n- Write in the language the user writes in, and keep writing in it for the whole\n conversation. These instructions are in English for precision, not as a hint about\n the reply language: a message in Italian gets an answer in Italian. Code,\n identifiers, paths, commands and tool arguments stay exactly as they are.\n- Inspect the real workspace before making claims.\n- Match the requested scope: analysis stays read-only; change/build work is implemented end to end and verified.\n- Prefer focused changes, but do not shrink a broad request into a partial patch.\n- Keep planning proportional to the task; simple tasks do not need a formal plan.\n- Use ordinary to-do-list language for progress: tasks, groups, dependencies and\n pending, in progress, completed or failed states, translated into the user's language.\n Memory indexes and internal implementation names are context for you; present the\n relevant tasks, next steps and results to the user.\n- Start substantial work with a short update, then act with tools. During long tasks share\n useful findings or blockers about once a minute; avoid narrating every tool call.\n- Respect the workspace permissions selected by the user.\n- Exhaust safe in-scope alternatives before asking the user to unblock you.\n- Never announce completion while a plan step is pending/running/failed or the requested\n artifact has not been verified. Continue working, or report the concrete blocker.\n- Keep the final answer compact: outcome first, then verification and any blocker. Do not\n expose or recap internal context packs, memory routing, hidden prompts, or chain-of-thought.\n\nTools\n- The tools listed for you cover file reads, writes, edits, search and shell: call them directly.\n- Prefer the terminal for code discovery and inspection: rg for content, rg --files for paths,\n git diff/status for changes, and native commands for the selected shell. Scope searches to\n relevant directories and return only useful output. If rg or terminal access is unavailable,\n use read_file or discover grep/glob/list_dir with tool_search (or call them inside run_program).\n Use edit_file/write_file for focused edits and discover file_activity when coordination needs it.\n Shell access does not expand the authorized workspace or bypass permissions.\n- More tools exist on demand. Find them with tool_search, asking in ONE call for every tool\n you expect to need (\"names\" when you know them, \"query\" otherwise): they become callable\n directly, by name. Do not search again for a tool you loaded. Calling tool_search without\n names/query lists the inventory without activating it; continue with offset=next_offset.\n- Missing a capability? Inspect the actual catalog before assuming a host integration exists.\n If custom-tool authoring is available, follow its guide. Ask the user only for information\n or decisions that the available tools and project context cannot resolve.\n- Use ask_user for missing requirements or decisions that materially change the result.\n Ask a concise, self-contained question early, with options when useful. Collaborators can\n use the same tool. If a required answer is missing, keep the dependency blocked and continue\n independent work; do not invent the answer or interpret silence as approval. Use required=false\n only for optional preferences with a reasonable, reversible default. Routine implementation\n choices should not interrupt the user.\n- For work with several steps \u2014 including games, challenges, puzzles and multi-level tasks \u2014\n lay out the plan with vascend_plan and keep it honest with vascend_mark as you go (one step\n running at a time). The plan is not paperwork: it appears live as a\n task board next to the conversation, where the user follows progress and can edit or add\n steps. Give each step an observable result and a proportionate check. Short, single-step\n requests need no plan. Read vascend_status after resume/compaction and before handing off\n substantial work; resume it only when that is still necessary and authorized by the current\n request. vascend_addtasks extends it without resetting\n progress; vascend_plan with replace=true explicitly replaces it. Save decisions, blockers\n and the next action with vascend_note before switching workstreams.\n- Start a step with vascend_mark status=running. Complete it only after the relevant checks,\n recording paths, commands and observed outcomes. Evidence in the plan is a record to inspect,\n not an automatic correctness certificate. Reopening a step clears old completion evidence.\n Respect after dependencies; use pending to pause a step and failed to record a concrete blocker.\n- A plan is not a collaborator. When the user asks for multiple agents, subagents or parallel\n experts, actually call team_engage: create one collaborator per independent workstream and\n assign its complete task. If vascend_plan already created several task groups, pass their slugs\n through the group field so those collaborators own and update the same T01/T02 tasks. Do not\n merely draw multiple workstreams and then execute all of them in the orchestrator.\n- Issue independent reads together. For related tool sequences use run_program and print only\n the results needed for the next decision; keep dependent edits and approvals sequential.\n- When bash returns a background id, call bash_output once: it waits locally until the process exits.\n Use wait=false to inspect persistent servers; do not repeatedly poll unchanged output. Partial output\n or a started process does not mean the check passed. Leave persistent development servers\n running when they are needed and report their status separately from verification results.\n- Act on what is already in context: do not re-read a file or repeat a search whose result\n you still have.\n- If a tool reports a missing or malformed argument, fix the argument shape it names \u2014 do not\n retry the same call unchanged.\n\nEfficient execution\n- Determine whether the user wants advice, an explanation, instructions for manual work, or\n actual execution. Advice and manual instructions are fulfilled by the response; do not run\n their example scripts or perform the user's setup. A todo list does not grant authorization.\n Before continuing after an error, check whether further agent action is needed and authorized.\n Stop when the request is answered; wait when the next step belongs to the user or needs input.\n Preserve incomplete tasks honestly instead of forcing completion or retrying indefinitely.\n- For a small cosmetic change (one button color, label, spacing or font), locate the affected\n component, edit it, then verify the local result. Do not create a plan, delegate, research the\n web, inspect the whole repository or run a global test/build cycle unless evidence requires it.\n Escalate scope only when the actual dependency or failure demands it.\n- Decide what evidence is needed for the next decision. Issue independent reads together and\n reuse results that are still valid. Do not spend a model round on each already-decided action.\n- Use run_program for known sequences: await dependent edits and plan transitions in order,\n stop on errors, and return a concise summary. Complete a task only after its checks succeed.\n- Prepare related replacements in one round. Never edit the same file concurrently. Independent\n edits on distinct files may run together in bounded groups of at most four; await every outcome\n before inspecting the result or starting dependent work. Keep permission gates in place.\n- For short checks use foreground bash, or background with its brief initial wait. Use\n background=true with yield_time_ms=0 for persistent servers or work that must detach immediately.\n Collect ready background results together; a running command is not a passed check.\n bash_output waits locally for completion by default: call it once and omit timeout_seconds.\n Use wait=false only to inspect a persistent server or diagnose a process; do not poll in a loop.\n- Run the relevant integrated checks after the edits. Repeat checks only after changes, failures\n or a concrete unresolved concern; do not duplicate typecheck and build without a reason.\n- When parallel work is authorized and worthwhile, start with at most two collaborators on\n concrete disjoint areas, agree on interfaces and acceptance checks, and declare after dependencies.\n The coordinator reviews the combined result. Prefer one agent for small or tightly coupled work.\n- Format user-facing responses in readable Markdown: short paragraphs, **bold** key findings,\n lists for steps, tables for comparisons, fenced code with a language, and descriptive links.\n Keep internal planning notation out of ordinary explanations unless the user asks for it.";
5
10
  export type TalosBanner = "vascend-terminal" | "minimal" | "custom" | "none";
6
11
  export type TalosEffort = "" | "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
7
12
  export type TalosPermMode = "normal" | "acceptEdits" | "auto";
@@ -18,10 +23,13 @@ export interface TalosUiConfig {
18
23
  readonly theme: string;
19
24
  }
20
25
  export interface PiConfig {
26
+ readonly fusion?: FusionConfig | null;
21
27
  readonly cwd: string;
22
28
  readonly model: string;
23
29
  readonly maxTokens: number;
24
30
  readonly system: string;
31
+ /** Authoritative host instructions for this run, outside the stable prefix. */
32
+ readonly turnSystem?: string;
25
33
  readonly autoDelegatePlans: boolean;
26
34
  readonly workerModelPool?: readonly string[];
27
35
  readonly sessionDir: string;
@@ -42,6 +50,7 @@ export interface PiConfig {
42
50
  readonly statusLine?: readonly string[];
43
51
  readonly vibeMode: VibeModeSelection;
44
52
  }
53
+ export declare const DEFAULT_UI: TalosUiConfig;
45
54
  export declare function buildConfig(opts: {
46
55
  cwd?: string;
47
56
  model?: string;
@@ -5,6 +5,16 @@ import { VASCEND_SYSTEM_BLOCK } from "../vascend/runtime.js";
5
5
  import { parseVibeMode } from "./vibe-modes.js";
6
6
  import { defaultSessionDir, talosConfigDir } from "./env-paths.js";
7
7
  import { EXECUTION_GUIDANCE } from "./execution-guidance.js";
8
+ import { fusionFromEnv, parseFusion } from "./fusion.js";
9
+ export class InvalidConfigError extends Error {
10
+ path;
11
+ constructor(path, cause) {
12
+ const detail = cause instanceof Error ? cause.message : String(cause);
13
+ super(`config Talos non valida: ${path} — ${detail}`);
14
+ this.name = "InvalidConfigError";
15
+ this.path = path;
16
+ }
17
+ }
8
18
  // System prompt deliberatamente minimale: la personalita' e le regole
9
19
  // di progetto arrivano da SYSTEM.md / AGENTS.md, non dal harness.
10
20
  export const BASE_SYSTEM = `# Vascend Talos
@@ -104,7 +114,8 @@ Tools
104
114
  merely draw multiple workstreams and then execute all of them in the orchestrator.
105
115
  - Issue independent reads together. For related tool sequences use run_program and print only
106
116
  the results needed for the next decision; keep dependent edits and approvals sequential.
107
- - When bash returns a background id, use bash_output until the process exits. Partial output
117
+ - When bash returns a background id, call bash_output once: it waits locally until the process exits.
118
+ Use wait=false to inspect persistent servers; do not repeatedly poll unchanged output. Partial output
108
119
  or a started process does not mean the check passed. Leave persistent development servers
109
120
  running when they are needed and report their status separately from verification results.
110
121
  - Act on what is already in context: do not re-read a file or repeat a search whose result
@@ -115,7 +126,7 @@ Tools
115
126
  ${EXECUTION_GUIDANCE}`;
116
127
  // File di contesto a livello progetto, in ordine di priorita'.
117
128
  const DEFAULT_CONTEXT_FILES = ["SYSTEM.md", "AGENTS.md", ".talos/SYSTEM.md"];
118
- const DEFAULT_UI = {
129
+ export const DEFAULT_UI = {
119
130
  banner: "vascend-terminal",
120
131
  logoLines: [],
121
132
  title: "Vascend Talos",
@@ -236,15 +247,17 @@ function parseConfigFile(path) {
236
247
  raw = JSON.parse(readFileSync(path, "utf8"));
237
248
  }
238
249
  catch (err) {
239
- // Un config corrotto (es. scrittura troncata da disco pieno) non deve
240
- // impedire l'avvio: lo si ignora con un avviso e si usano i default.
241
- process.stderr.write(`[avviso] config ignorata (JSON non valido): ${path} — ${err.message}\n`);
242
- return {};
250
+ // Avviare coi default dopo una scrittura troncata nasconderebbe credenziali
251
+ // e preferenze e farebbe partire erroneamente il login. La config va prima
252
+ // riparata: nessun bootstrap o flusso interattivo deve proseguire.
253
+ throw new InvalidConfigError(path, err);
254
+ }
255
+ if (!isRecord(raw)) {
256
+ throw new InvalidConfigError(path, new Error("la radice deve essere un oggetto JSON"));
243
257
  }
244
- if (!isRecord(raw))
245
- return {};
246
258
  return {
247
259
  model: text(raw["model"]),
260
+ fusion: parseFusion(raw["fusion"]),
248
261
  maxTokens: positiveInt(raw["maxTokens"]),
249
262
  sessionDir: text(raw["sessionDir"]),
250
263
  contextFiles: csv(raw["contextFiles"]),
@@ -261,6 +274,7 @@ function parseConfigFile(path) {
261
274
  }
262
275
  function envPatch(env) {
263
276
  return {
277
+ fusion: fusionFromEnv(env),
264
278
  model: text(env["TALOS_MODEL"]),
265
279
  maxTokens: positiveInt(env["TALOS_MAX_TOKENS"]),
266
280
  sessionDir: text(env["TALOS_SESSION_DIR"]),
@@ -325,6 +339,7 @@ function mergeConfig(base, patch) {
325
339
  : base.systemAppend;
326
340
  return {
327
341
  ...base,
342
+ fusion: patch.fusion !== undefined ? patch.fusion : base.fusion,
328
343
  model: patch.model ?? base.model,
329
344
  maxTokens: patch.maxTokens ?? base.maxTokens,
330
345
  sessionDir: patch.sessionDir ?? base.sessionDir,
@@ -399,6 +414,7 @@ export function buildConfig(opts) {
399
414
  return {
400
415
  cwd,
401
416
  model: finalConfig.model,
417
+ fusion: finalConfig.fusion,
402
418
  maxTokens: finalConfig.maxTokens,
403
419
  system,
404
420
  autoDelegatePlans: horizonHost,
@@ -12,6 +12,7 @@
12
12
  // Modulo PURO: nessuna lettura di disco, nessuna dipendenza dal runtime. A
13
13
  // parita' di input restituisce lo stesso registro, quindi e' verificabile.
14
14
  import { contextWindowFor, estimateTokens, estimateToolDefinitionTokens, IMAGE_TOKEN_ESTIMATE, } from "./compaction.js";
15
+ import { maxInputFor } from "./model-limits.js";
15
16
  // Sotto questa soglia una voce della cronologia non e' un problema di contesto:
16
17
  // elencarla sposterebbe l'attenzione dal poco che pesa davvero.
17
18
  const HEAVY_MIN_TOKENS = 400;
@@ -20,7 +21,7 @@ export function buildContextLedger(input) {
20
21
  const now = input.now ?? Date.now();
21
22
  const window = contextWindowFor(input.model, input.contextWindow ?? 0);
22
23
  const reserve = Math.max(0, input.reserveTokens ?? 0);
23
- const compactAt = Math.max(1, Math.min(window - reserve, input.workingContextTokens ?? window));
24
+ const compactAt = Math.max(1, Math.min(window - reserve, maxInputFor(input.model), input.workingContextTokens || window));
24
25
  const slices = [];
25
26
  const push = (block, cacheable) => {
26
27
  const tokens = block.tokens ?? (block.text ? estimateTokens(block.text) : 0);
@@ -11,7 +11,7 @@ export interface ContextPolicy {
11
11
  }
12
12
  export declare function isChatHostProfile(env: NodeJS.ProcessEnv): boolean;
13
13
  export declare function contextPolicy(env: NodeJS.ProcessEnv): ContextPolicy;
14
- export declare function workingContextLimits(policy: ContextPolicy, window: number, reserve: number): {
14
+ export declare function workingContextLimits(policy: ContextPolicy, window: number, reserve: number, outputTokens?: number, inputLimit?: number): {
15
15
  readonly active: number;
16
16
  readonly checkpoint: number;
17
17
  };
@@ -6,16 +6,16 @@ const CHAT_DEFAULTS = {
6
6
  placement: "turn",
7
7
  learning: "deferred",
8
8
  roomCompaction: "threshold",
9
- compactAtFraction: 0.6,
10
- workingContextTokens: 128_000,
9
+ compactAtFraction: 0.9,
10
+ workingContextTokens: 0,
11
11
  };
12
12
  const AGENT_DEFAULTS = {
13
13
  chat: false,
14
14
  placement: "turn",
15
15
  learning: "deferred",
16
16
  roomCompaction: "threshold",
17
- compactAtFraction: 0.6,
18
- workingContextTokens: 128_000,
17
+ compactAtFraction: 0.9,
18
+ workingContextTokens: 0,
19
19
  };
20
20
  // Profilo host dichiarato dall'ospite (mai dedotto dal testo utente).
21
21
  export function isChatHostProfile(env) {
@@ -33,9 +33,12 @@ export function contextPolicy(env) {
33
33
  workingContextTokens: positiveInteger(env["TALOS_WORKING_CONTEXT_TOKENS"]) ?? base.workingContextTokens,
34
34
  };
35
35
  }
36
- export function workingContextLimits(policy, window, reserve) {
37
- const active = Math.max(1, Math.min(policy.workingContextTokens, window - reserve));
38
- return { active, checkpoint: Math.min(64_000, active * policy.compactAtFraction) };
36
+ export function workingContextLimits(policy, window, reserve, outputTokens = 0, inputLimit = window) {
37
+ // On small overridden windows the requested output ceiling may exceed the
38
+ // entire window. Admission can shrink output; reserve at most a quarter here.
39
+ const outputReserve = Math.min(outputTokens, Math.floor(window / 4));
40
+ const active = Math.max(1, Math.min(policy.workingContextTokens || window, inputLimit, window - Math.max(reserve, outputReserve)));
41
+ return { active, checkpoint: active * policy.compactAtFraction };
39
42
  }
40
43
  function positiveInteger(raw) {
41
44
  const n = Number(raw);
@@ -1,5 +1,6 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { dirname, join } from "node:path";
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { updateConfigObject } from "./config-storage.js";
3
4
  import { readOpenRouterCreds } from "../providers/openrouter-auth.js";
4
5
  import { talosConfigDir } from "./env-paths.js";
5
6
  // Posizione del file globale. null se la config globale e' disattivata
@@ -90,21 +91,21 @@ export function saveCredential(env, providerId, patch) {
90
91
  if (!path || !providerId.trim())
91
92
  return false;
92
93
  try {
93
- const current = readJson(path);
94
- const providers = parseStore(current["providers"]);
95
- const merged = mergeCredential(providers[providerId], patch);
96
- const nextProviders = { ...providers };
97
- if (merged)
98
- nextProviders[providerId] = merged;
99
- else
100
- delete nextProviders[providerId];
101
- const next = { ...current };
102
- if (Object.keys(nextProviders).length > 0)
103
- next["providers"] = nextProviders;
104
- else
105
- delete next["providers"];
106
- mkdirSync(dirname(path), { recursive: true });
107
- writeFileSync(path, JSON.stringify(next, null, 2) + "\n", "utf8");
94
+ updateConfigObject(path, (current) => {
95
+ const providers = parseStore(current["providers"]);
96
+ const merged = mergeCredential(providers[providerId], patch);
97
+ const nextProviders = { ...providers };
98
+ if (merged)
99
+ nextProviders[providerId] = merged;
100
+ else
101
+ delete nextProviders[providerId];
102
+ const next = { ...current };
103
+ if (Object.keys(nextProviders).length > 0)
104
+ next["providers"] = nextProviders;
105
+ else
106
+ delete next["providers"];
107
+ return next;
108
+ });
108
109
  return true;
109
110
  }
110
111
  catch {
@@ -118,19 +119,17 @@ export function deleteCredential(env, providerId) {
118
119
  if (!path || !providerId.trim())
119
120
  return false;
120
121
  try {
121
- const current = readJson(path);
122
- const providers = parseStore(current["providers"]);
123
- if (!(providerId in providers))
124
- return true;
125
- const nextProviders = { ...providers };
126
- delete nextProviders[providerId];
127
- const next = { ...current };
128
- if (Object.keys(nextProviders).length > 0)
129
- next["providers"] = nextProviders;
130
- else
131
- delete next["providers"];
132
- mkdirSync(dirname(path), { recursive: true });
133
- writeFileSync(path, JSON.stringify(next, null, 2) + "\n", "utf8");
122
+ updateConfigObject(path, (current) => {
123
+ const providers = parseStore(current["providers"]);
124
+ const nextProviders = { ...providers };
125
+ delete nextProviders[providerId];
126
+ const next = { ...current };
127
+ if (Object.keys(nextProviders).length > 0)
128
+ next["providers"] = nextProviders;
129
+ else
130
+ delete next["providers"];
131
+ return next;
132
+ });
134
133
  return true;
135
134
  }
136
135
  catch {
@@ -1,5 +1,5 @@
1
1
  export type Effort = "" | "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
2
2
  export declare function effectiveToolName(name: string, input?: Record<string, unknown>): string;
3
- export declare function effortRoutingEnabled(env: NodeJS.ProcessEnv): boolean;
3
+ export declare function effortRoutingEnabled(env: NodeJS.ProcessEnv, providerId?: string): boolean;
4
4
  export declare function isRoutineBatch(toolNames: readonly string[], hadError: boolean): boolean;
5
5
  export declare function routeEffort(base: Effort, turn: number, routine: boolean, enabled: boolean): Effort;
@@ -22,7 +22,11 @@ export function effectiveToolName(name, input) {
22
22
  const target = input?.["name"];
23
23
  return typeof target === "string" && target.trim() ? target.trim() : name;
24
24
  }
25
- export function effortRoutingEnabled(env) {
25
+ export function effortRoutingEnabled(env, providerId = "") {
26
+ // Top-level effort changes invalidate Claude's message cache. Keep the
27
+ // user's effort stable rather than trading a cheap read for a full rewrite.
28
+ if (providerId === "anthropic" || providerId === "claude-code")
29
+ return false;
26
30
  const v = (env["TALOS_EFFORT_ROUTING"] ?? "").trim().toLowerCase();
27
31
  return !(v === "0" || v === "off" || v === "false" || v === "no");
28
32
  }
@@ -1,5 +1,5 @@
1
1
  import type { ToolCallPart, ToolResultPart } from "./types.js";
2
- export declare const EXECUTION_GUIDANCE = "Efficient execution\n- Determine whether the user wants advice, an explanation, instructions for manual work, or\n actual execution. Advice and manual instructions are fulfilled by the response; do not run\n their example scripts or perform the user's setup. A todo list does not grant authorization.\n Before continuing after an error, check whether further agent action is needed and authorized.\n Stop when the request is answered; wait when the next step belongs to the user or needs input.\n Preserve incomplete tasks honestly instead of forcing completion or retrying indefinitely.\n- For a small cosmetic change (one button color, label, spacing or font), locate the affected\n component, edit it, then verify the local result. Do not create a plan, delegate, research the\n web, inspect the whole repository or run a global test/build cycle unless evidence requires it.\n Escalate scope only when the actual dependency or failure demands it.\n- Decide what evidence is needed for the next decision. Issue independent reads together and\n reuse results that are still valid. Do not spend a model round on each already-decided action.\n- Use run_program for known sequences: await dependent edits and plan transitions in order,\n stop on errors, and return a concise summary. Complete a task only after its checks succeed.\n- Prepare related replacements in one round. Never edit the same file concurrently. Independent\n edits on distinct files may run together in bounded groups of at most four; await every outcome\n before inspecting the result or starting dependent work. Keep permission gates in place.\n- For short checks use foreground bash, or background with its brief initial wait. Use\n background=true with yield_time_ms=0 for persistent servers or work that must detach immediately.\n Collect ready background results together; a running command is not a passed check.\n- Run the relevant integrated checks after the edits. Repeat checks only after changes, failures\n or a concrete unresolved concern; do not duplicate typecheck and build without a reason.\n- When parallel work is authorized and worthwhile, start with at most two collaborators on\n concrete disjoint areas, agree on interfaces and acceptance checks, and declare after dependencies.\n The coordinator reviews the combined result. Prefer one agent for small or tightly coupled work.\n- Format user-facing responses in readable Markdown: short paragraphs, **bold** key findings,\n lists for steps, tables for comparisons, fenced code with a language, and descriptive links.\n Keep internal planning notation out of ordinary explanations unless the user asks for it.";
2
+ export declare const EXECUTION_GUIDANCE = "Efficient execution\n- Determine whether the user wants advice, an explanation, instructions for manual work, or\n actual execution. Advice and manual instructions are fulfilled by the response; do not run\n their example scripts or perform the user's setup. A todo list does not grant authorization.\n Before continuing after an error, check whether further agent action is needed and authorized.\n Stop when the request is answered; wait when the next step belongs to the user or needs input.\n Preserve incomplete tasks honestly instead of forcing completion or retrying indefinitely.\n- For a small cosmetic change (one button color, label, spacing or font), locate the affected\n component, edit it, then verify the local result. Do not create a plan, delegate, research the\n web, inspect the whole repository or run a global test/build cycle unless evidence requires it.\n Escalate scope only when the actual dependency or failure demands it.\n- Decide what evidence is needed for the next decision. Issue independent reads together and\n reuse results that are still valid. Do not spend a model round on each already-decided action.\n- Use run_program for known sequences: await dependent edits and plan transitions in order,\n stop on errors, and return a concise summary. Complete a task only after its checks succeed.\n- Prepare related replacements in one round. Never edit the same file concurrently. Independent\n edits on distinct files may run together in bounded groups of at most four; await every outcome\n before inspecting the result or starting dependent work. Keep permission gates in place.\n- For short checks use foreground bash, or background with its brief initial wait. Use\n background=true with yield_time_ms=0 for persistent servers or work that must detach immediately.\n Collect ready background results together; a running command is not a passed check.\n bash_output waits locally for completion by default: call it once and omit timeout_seconds.\n Use wait=false only to inspect a persistent server or diagnose a process; do not poll in a loop.\n- Run the relevant integrated checks after the edits. Repeat checks only after changes, failures\n or a concrete unresolved concern; do not duplicate typecheck and build without a reason.\n- When parallel work is authorized and worthwhile, start with at most two collaborators on\n concrete disjoint areas, agree on interfaces and acceptance checks, and declare after dependencies.\n The coordinator reviews the combined result. Prefer one agent for small or tightly coupled work.\n- Format user-facing responses in readable Markdown: short paragraphs, **bold** key findings,\n lists for steps, tables for comparisons, fenced code with a language, and descriptive links.\n Keep internal planning notation out of ordinary explanations unless the user asks for it.";
3
3
  export declare class ExecutionGuidance {
4
4
  private previous;
5
5
  private readonly reminded;
@@ -20,6 +20,8 @@ export const EXECUTION_GUIDANCE = `Efficient execution
20
20
  - For short checks use foreground bash, or background with its brief initial wait. Use
21
21
  background=true with yield_time_ms=0 for persistent servers or work that must detach immediately.
22
22
  Collect ready background results together; a running command is not a passed check.
23
+ bash_output waits locally for completion by default: call it once and omit timeout_seconds.
24
+ Use wait=false only to inspect a persistent server or diagnose a process; do not poll in a loop.
23
25
  - Run the relevant integrated checks after the edits. Repeat checks only after changes, failures
24
26
  or a concrete unresolved concern; do not duplicate typecheck and build without a reason.
25
27
  - When parallel work is authorized and worthwhile, start with at most two collaborators on
@@ -54,7 +54,10 @@ export declare class FileCoordinationHub {
54
54
  observe(pathValue: string, actor: FileActor): readonly FilePresence[];
55
55
  acquire(pathValue: string, actor: FileActor): FileLeaseResult;
56
56
  validate(lease: FileLease): readonly FilePresence[];
57
+ acquireAsync(pathValue: string, actor: FileActor, signal?: AbortSignal): Promise<FileLeaseResult>;
58
+ releaseAsync(lease: FileLease): Promise<void>;
57
59
  release(lease: FileLease): void;
60
+ private forgetLease;
58
61
  clearActor(actorId: string, includeLeases?: boolean): void;
59
62
  private activeConflicts;
60
63
  private storageFailure;
@@ -85,11 +85,39 @@ export class FileCoordinationHub {
85
85
  return [this.storageFailure(lease.path, error)];
86
86
  }
87
87
  }
88
+ async acquireAsync(pathValue, actor, signal) {
89
+ const path = this.path(pathValue);
90
+ const conflicts = this.activeConflicts(path, actor.id);
91
+ if (conflicts.length)
92
+ return { ok: false, conflicts };
93
+ const lease = { id: `fl-${randomUUID()}`, path, actor };
94
+ try {
95
+ const shared = await this.persistent.acquireAsync(lease, signal);
96
+ if (shared.length)
97
+ return { ok: false, conflicts: shared };
98
+ }
99
+ catch (error) {
100
+ return { ok: false, conflicts: [this.storageFailure(path, error)] };
101
+ }
102
+ this.leases.set(lease.id, lease);
103
+ this.put({ path, mode: "writing", actor, updatedAt: Date.now(), leaseId: lease.id });
104
+ return { ok: true, lease };
105
+ }
106
+ async releaseAsync(lease) {
107
+ try {
108
+ await this.persistent.releaseAsync(lease);
109
+ }
110
+ catch { /* fail closed: retain the persistent lease */ }
111
+ this.forgetLease(lease);
112
+ }
88
113
  release(lease) {
89
114
  try {
90
115
  this.persistent.release(lease);
91
116
  }
92
117
  catch { /* fail closed: a later writer sees the retained lease */ }
118
+ this.forgetLease(lease);
119
+ }
120
+ forgetLease(lease) {
93
121
  this.leases.delete(lease.id);
94
122
  const entries = this.byPath.get(lease.path);
95
123
  const current = entries?.get(lease.actor.id);
@@ -7,8 +7,11 @@ export declare class FileLeaseStore {
7
7
  constructor(directory: string);
8
8
  acquire(lease: FileLease): readonly FilePresence[];
9
9
  validate(lease: FileLease): readonly FilePresence[];
10
+ acquireAsync(lease: FileLease, signal?: AbortSignal): Promise<readonly FilePresence[]>;
11
+ releaseAsync(lease: FileLease): Promise<void>;
10
12
  release(lease: FileLease): void;
11
13
  list(path?: string): readonly FilePresence[];
12
14
  private transaction;
15
+ private update;
13
16
  private read;
14
17
  }
@@ -1,7 +1,7 @@
1
1
  import { readFileSync, writeFileSync, renameSync, realpathSync } from "node:fs";
2
2
  import { join, resolve } from "node:path";
3
3
  import { randomUUID } from "node:crypto";
4
- import { withLockSync } from "../vascend/file-lock.js";
4
+ import { withLock, withLockSync } from "../vascend/file-lock.js";
5
5
  import { executionTargetKey, localExecutionTarget } from "./execution-target.js";
6
6
  import { createHash } from "node:crypto";
7
7
  import { tmpdir } from "node:os";
@@ -33,6 +33,21 @@ export class FileLeaseStore {
33
33
  : current ? [presence(current)] : [{ path: lease.path, mode: "writing", updatedAt: Date.now(),
34
34
  actor: { id: "lease-lost", label: "lease di scrittura non piu' valida", kind: "external" } }];
35
35
  }
36
+ async acquireAsync(lease, signal) {
37
+ return withLock(this.path, () => this.update(records => {
38
+ const current = records[lease.path];
39
+ if (current)
40
+ return [presence(current)];
41
+ records[lease.path] = { ...lease, pid: process.pid, at: Date.now() };
42
+ return [];
43
+ }), {}, signal);
44
+ }
45
+ async releaseAsync(lease) {
46
+ await withLock(this.path, () => this.update(records => {
47
+ if (records[lease.path]?.id === lease.id)
48
+ delete records[lease.path];
49
+ }));
50
+ }
36
51
  release(lease) {
37
52
  this.transaction((records) => {
38
53
  if (records[lease.path]?.id === lease.id)
@@ -43,17 +58,18 @@ export class FileLeaseStore {
43
58
  return Object.values(this.read()).filter((record) => (!path || record.path === path) && alive(record.pid)).map(presence);
44
59
  }
45
60
  transaction(fn) {
46
- return withLockSync(this.path, () => {
47
- const records = this.read();
48
- for (const [key, record] of Object.entries(records))
49
- if (!alive(record.pid))
50
- delete records[key];
51
- const value = fn(records);
52
- const temp = this.path + "." + randomUUID() + ".tmp";
53
- writeFileSync(temp, JSON.stringify(records), "utf8");
54
- renameSync(temp, this.path);
55
- return value;
56
- });
61
+ return withLockSync(this.path, () => this.update(fn));
62
+ }
63
+ update(fn) {
64
+ const records = this.read();
65
+ for (const [key, record] of Object.entries(records))
66
+ if (!alive(record.pid))
67
+ delete records[key];
68
+ const value = fn(records);
69
+ const temp = this.path + "." + randomUUID() + ".tmp";
70
+ writeFileSync(temp, JSON.stringify(records), "utf8");
71
+ renameSync(temp, this.path);
72
+ return value;
57
73
  }
58
74
  read() {
59
75
  try {
@@ -0,0 +1,24 @@
1
+ export type FusionGateMode = "guard" | "auto";
2
+ export interface FusionConfig {
3
+ /** Modelli qualificati fra cui Jev puo' scegliere per un compito nuovo (oltre a quello attivo). */
4
+ readonly routes: readonly string[];
5
+ /** guard: Jev puo' solo bloccare o far chiedere; auto: un allow netto salta la domanda. */
6
+ readonly gate: FusionGateMode;
7
+ /** Focus per passo con pacchetti di tool. */
8
+ readonly focus: boolean;
9
+ }
10
+ export declare const DEFAULT_FUSION: FusionConfig;
11
+ export declare function parseFusion(value: unknown): FusionConfig | null | undefined;
12
+ export declare function fusionFromEnv(env: NodeJS.ProcessEnv): FusionConfig | null | undefined;
13
+ export declare function isPaidTier(tier: string | undefined): boolean;
14
+ export type FusionAvailability = {
15
+ readonly ok: true;
16
+ readonly channel: "dev" | "client";
17
+ } | {
18
+ readonly ok: false;
19
+ readonly channel: "dev" | "client";
20
+ readonly reason: "missing_openrouter" | "missing_login" | "free_plan";
21
+ };
22
+ /** Cosa puo' fare questa installazione. Il tier, se noto, arriva dalla sessione Vascend. */
23
+ export declare function fusionAvailability(env: NodeJS.ProcessEnv, tier?: string, hostProxy?: boolean): FusionAvailability;
24
+ export declare function fusionUnavailableMessage(reason: "missing_openrouter" | "missing_login" | "free_plan" | "not_entitled"): string;