@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.
- package/dist/core/agent.d.ts +16 -3
- package/dist/core/agent.js +114 -34
- package/dist/core/background.d.ts +10 -3
- package/dist/core/background.js +55 -9
- package/dist/core/bootstrap.js +1 -0
- package/dist/core/compaction.js +1 -1
- package/dist/core/config-storage.d.ts +5 -0
- package/dist/core/config-storage.js +83 -0
- package/dist/core/config.d.ts +11 -2
- package/dist/core/config.js +24 -8
- package/dist/core/context-ledger.js +2 -1
- package/dist/core/context-policy.d.ts +1 -1
- package/dist/core/context-policy.js +10 -7
- package/dist/core/credentials.js +29 -30
- package/dist/core/effort.d.ts +1 -1
- package/dist/core/effort.js +5 -1
- package/dist/core/execution-guidance.d.ts +1 -1
- package/dist/core/execution-guidance.js +2 -0
- package/dist/core/file-coordination.d.ts +3 -0
- package/dist/core/file-coordination.js +28 -0
- package/dist/core/file-lease-store.d.ts +3 -0
- package/dist/core/file-lease-store.js +28 -12
- package/dist/core/fusion.d.ts +24 -0
- package/dist/core/fusion.js +80 -0
- package/dist/core/model-limits.d.ts +1 -0
- package/dist/core/model-limits.js +5 -1
- package/dist/core/permission-queue.js +15 -15
- package/dist/core/request-plan.js +4 -3
- package/dist/core/session-naming.js +4 -0
- package/dist/core/session.d.ts +4 -2
- package/dist/core/session.js +13 -4
- package/dist/core/settings.d.ts +2 -0
- package/dist/core/settings.js +5 -16
- package/dist/core/step-policy.d.ts +18 -0
- package/dist/core/step-policy.js +6 -0
- package/dist/core/tool-artifacts.d.ts +2 -0
- package/dist/core/tool-artifacts.js +21 -3
- package/dist/core/tool-result-index.js +29 -33
- package/dist/core/tool-result-store.js +6 -5
- package/dist/core/types.d.ts +10 -3
- package/dist/core/user-inbox.d.ts +9 -0
- package/dist/core/user-inbox.js +22 -3
- package/dist/core/user-input.js +1 -1
- package/dist/fusion/autopilot-fast.d.ts +59 -0
- package/dist/fusion/autopilot-fast.js +213 -0
- package/dist/fusion/autopilot.d.ts +75 -0
- package/dist/fusion/autopilot.js +308 -0
- package/dist/fusion/focus.d.ts +30 -0
- package/dist/fusion/focus.js +122 -0
- package/dist/fusion/gate.d.ts +30 -0
- package/dist/fusion/gate.js +95 -0
- package/dist/fusion/jev.d.ts +71 -0
- package/dist/fusion/jev.js +164 -0
- package/dist/fusion/receipts.d.ts +25 -0
- package/dist/fusion/receipts.js +34 -0
- package/dist/fusion/route.d.ts +25 -0
- package/dist/fusion/route.js +84 -0
- package/dist/fusion/run.d.ts +4 -0
- package/dist/fusion/run.js +186 -0
- package/dist/horizon/engine.d.ts +20 -1
- package/dist/horizon/engine.js +57 -0
- package/dist/horizon/index.d.ts +2 -2
- package/dist/horizon/index.js +1 -1
- package/dist/horizon/types.d.ts +29 -0
- package/dist/index.js +12 -0
- package/dist/providers/anthropic-oauth.d.ts +8 -3
- package/dist/providers/anthropic-oauth.js +13 -10
- package/dist/providers/anthropic.d.ts +9 -2
- package/dist/providers/anthropic.js +64 -21
- package/dist/providers/cli-models.d.ts +30 -0
- package/dist/providers/cli-models.js +194 -0
- package/dist/providers/model-effort.js +1 -1
- package/dist/providers/openai-oauth.d.ts +8 -3
- package/dist/providers/openai-oauth.js +9 -3
- package/dist/providers/openrouter-manual-fallback.d.ts +3 -1
- package/dist/providers/openrouter-manual-fallback.js +20 -20
- package/dist/providers/registry.js +3 -2
- package/dist/providers/retry.d.ts +3 -0
- package/dist/providers/retry.js +44 -1
- package/dist/remote/cifratura.d.ts +12 -0
- package/dist/remote/cifratura.js +66 -0
- package/dist/remote/index.d.ts +15 -0
- package/dist/remote/index.js +65 -0
- package/dist/remote/relay-client.d.ts +58 -0
- package/dist/remote/relay-client.js +315 -0
- package/dist/remote/sessione-remota.d.ts +60 -0
- package/dist/remote/sessione-remota.js +266 -0
- package/dist/sdk.d.ts +7 -2
- package/dist/sdk.js +3 -1
- package/dist/tools/builtin.js +41 -20
- package/dist/tools/capabilities.d.ts +3 -1
- package/dist/tools/capabilities.js +5 -2
- package/dist/tools/computer-use.js +2 -1
- package/dist/tools/pagination.js +1 -1
- package/dist/tools/program.js +34 -21
- package/dist/tools/team-tools.js +11 -6
- package/dist/tui/account-entry.js +14 -9
- package/dist/tui/agent-label.d.ts +2 -0
- package/dist/tui/agent-label.js +5 -0
- package/dist/tui/agent-sessions-screen.d.ts +12 -2
- package/dist/tui/agent-sessions-screen.js +62 -16
- package/dist/tui/agent-sessions.d.ts +14 -0
- package/dist/tui/agent-sessions.js +67 -6
- package/dist/tui/bottom-input.d.ts +46 -2
- package/dist/tui/bottom-input.js +358 -59
- package/dist/tui/branding.js +8 -4
- package/dist/tui/capability-lists.d.ts +10 -0
- package/dist/tui/capability-lists.js +41 -0
- package/dist/tui/command-output-registry.js +4 -0
- package/dist/tui/command-transcript.d.ts +1 -1
- package/dist/tui/command-transcript.js +17 -21
- package/dist/tui/commands.js +4 -1
- package/dist/tui/compaction-status.d.ts +7 -0
- package/dist/tui/compaction-status.js +39 -0
- package/dist/tui/config-recovery.d.ts +12 -0
- package/dist/tui/config-recovery.js +54 -0
- package/dist/tui/context-meter.d.ts +3 -0
- package/dist/tui/context-meter.js +35 -8
- package/dist/tui/diff.d.ts +9 -0
- package/dist/tui/diff.js +43 -19
- package/dist/tui/fusion-menu.d.ts +5 -0
- package/dist/tui/fusion-menu.js +89 -0
- package/dist/tui/i18n-catalog.js +312 -1
- package/dist/tui/live-command.d.ts +1 -0
- package/dist/tui/live-command.js +9 -0
- package/dist/tui/live-output.d.ts +1 -0
- package/dist/tui/live-output.js +11 -0
- package/dist/tui/model-details.js +13 -12
- package/dist/tui/model-picker.js +17 -7
- package/dist/tui/model-selection.js +19 -10
- package/dist/tui/native-scrollback.js +5 -0
- package/dist/tui/prompt-queue.d.ts +3 -0
- package/dist/tui/prompt-queue.js +19 -1
- package/dist/tui/provider-label.d.ts +2 -0
- package/dist/tui/provider-label.js +9 -0
- package/dist/tui/provider-menu.js +25 -24
- package/dist/tui/queue-screen.js +2 -1
- package/dist/tui/remote-command.d.ts +7 -0
- package/dist/tui/remote-command.js +79 -0
- package/dist/tui/repl.d.ts +8 -2
- package/dist/tui/repl.js +355 -311
- package/dist/tui/review-store.d.ts +1 -0
- package/dist/tui/review-store.js +28 -7
- package/dist/tui/review-team.js +4 -3
- package/dist/tui/runtime-error.d.ts +2 -0
- package/dist/tui/runtime-error.js +26 -0
- package/dist/tui/selector-mouse.d.ts +1 -0
- package/dist/tui/selector-mouse.js +1 -1
- package/dist/tui/selector.d.ts +7 -0
- package/dist/tui/selector.js +19 -2
- package/dist/tui/session-controls.d.ts +26 -0
- package/dist/tui/session-controls.js +65 -0
- package/dist/tui/session-naming-notice.js +5 -3
- package/dist/tui/session-replay.d.ts +1 -0
- package/dist/tui/session-replay.js +101 -32
- package/dist/tui/session-transcript-layout.d.ts +9 -0
- package/dist/tui/session-transcript-layout.js +41 -0
- package/dist/tui/startup.js +63 -33
- package/dist/tui/status-line.d.ts +1 -1
- package/dist/tui/status-line.js +20 -12
- package/dist/tui/talos-art-data.d.ts +1 -0
- package/dist/tui/talos-art-data.js +2 -0
- package/dist/tui/talos-art.d.ts +1 -0
- package/dist/tui/talos-art.js +9 -0
- package/dist/tui/task-labels.d.ts +1 -0
- package/dist/tui/task-labels.js +8 -0
- package/dist/tui/terminal-text.d.ts +2 -1
- package/dist/tui/terminal-text.js +28 -2
- package/dist/tui/theme.js +2 -2
- package/dist/tui/tool-presentation.d.ts +3 -0
- package/dist/tui/tool-presentation.js +98 -0
- package/dist/tui/tool-style.js +4 -0
- package/dist/tui/transcript-store.d.ts +25 -0
- package/dist/tui/transcript-store.js +151 -0
- package/dist/tui/usage-footer.d.ts +1 -1
- package/dist/tui/usage-footer.js +3 -1
- package/dist/tui/vascend-id.d.ts +49 -0
- package/dist/tui/vascend-id.js +321 -0
- package/dist/tui/web-login-screen.js +4 -3
- package/dist/tui/web-login.d.ts +7 -15
- package/dist/tui/web-login.js +38 -78
- package/dist/tui/worker-transcripts.d.ts +31 -0
- package/dist/tui/worker-transcripts.js +91 -0
- package/dist/vascend/candidate-collector.d.ts +6 -5
- package/dist/vascend/candidate-collector.js +44 -43
- package/dist/vascend/context-lint.js +32 -2
- package/dist/vascend/context-market-selection.js +12 -5
- package/dist/vascend/context-pack-render.js +10 -4
- package/dist/vascend/context-packet-mirrors.d.ts +8 -0
- package/dist/vascend/context-packet-mirrors.js +24 -0
- package/dist/vascend/context-plan-events.d.ts +4 -0
- package/dist/vascend/context-plan-events.js +44 -0
- package/dist/vascend/context-snapshot.js +4 -2
- package/dist/vascend/context-store-reader.d.ts +20 -0
- package/dist/vascend/context-store-reader.js +46 -0
- package/dist/vascend/file-lock.d.ts +1 -0
- package/dist/vascend/file-lock.js +26 -0
- package/dist/vascend/granular-kingdom.d.ts +1 -0
- package/dist/vascend/granular-kingdom.js +22 -15
- package/dist/vascend/kingdom-bus.d.ts +1 -0
- package/dist/vascend/kingdom-bus.js +3 -0
- package/dist/vascend/kingdom-channel.d.ts +2 -0
- package/dist/vascend/kingdom-channel.js +3 -0
- package/dist/vascend/kingdom-live.d.ts +32 -4
- package/dist/vascend/kingdom-live.js +149 -13
- package/dist/vascend/kingdom-run.d.ts +5 -1
- package/dist/vascend/kingdom-run.js +6 -2
- package/dist/vascend/kingdom.d.ts +3 -0
- package/dist/vascend/kingdom.js +20 -13
- package/dist/vascend/memory-packet.d.ts +2 -1
- package/dist/vascend/memory-packet.js +31 -44
- package/dist/vascend/plan-store.d.ts +3 -1
- package/dist/vascend/plan-store.js +6 -4
- package/dist/vascend/room-memory.d.ts +10 -1
- package/dist/vascend/room-memory.js +42 -2
- package/dist/vascend/runtime.d.ts +3 -11
- package/dist/vascend/runtime.js +11 -123
- package/dist/vascend/session-search.js +2 -0
- package/dist/vascend/team-session.js +3 -2
- package/dist/vascend/vision.d.ts +3 -1
- package/dist/vascend/vision.js +6 -4
- package/dist/vascend/worker-session.d.ts +20 -0
- package/dist/vascend/worker-session.js +83 -0
- package/package.json +1 -1
package/dist/core/agent.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EventSink, Message, Provider, ToolContext, ContentPart, ToolCallPart, SpawnAgentSpec } from "./types.js";
|
|
1
|
+
import type { AgentEvent, EventSink, Message, Provider, ToolContext, ContentPart, ToolCallPart, SpawnAgentSpec } from "./types.js";
|
|
2
2
|
import type { ToolRegistry } from "../tools/registry.js";
|
|
3
3
|
import type { Session } from "./session.js";
|
|
4
4
|
import type { PiConfig } from "./config.js";
|
|
@@ -7,13 +7,26 @@ import { type UserInbox } from "./user-inbox.js";
|
|
|
7
7
|
import { type ContextFabricResult } from "../vascend/context-fabric.js";
|
|
8
8
|
import { type FileCoordinationContext } from "./file-coordination.js";
|
|
9
9
|
import type { ExecutionTarget } from "./execution-target.js";
|
|
10
|
+
import type { StepPolicy } from "./step-policy.js";
|
|
10
11
|
import { type WorkspaceSession } from "./workspace-sessions.js";
|
|
11
12
|
export interface AgentDeps {
|
|
13
|
+
readonly fusionHarness?: import("./bootstrap.js").Harness;
|
|
14
|
+
/** Politica per passo (Fusion): guida effimera e tool ammessi nel passo. */
|
|
15
|
+
readonly stepPolicy?: StepPolicy;
|
|
16
|
+
/** Trasporto Jev dell'host per il canale client (sessione Vascend dell'host). */
|
|
17
|
+
readonly jevProxy?: import("../fusion/jev.js").JevProxy;
|
|
18
|
+
/** Full worker events for hosts with per-agent transcripts. */
|
|
19
|
+
readonly onWorkerEvent?: (actor: string, event: AgentEvent) => void;
|
|
12
20
|
readonly provider: Provider;
|
|
13
21
|
readonly tools: ToolRegistry;
|
|
14
22
|
readonly session: Session;
|
|
15
23
|
readonly config: PiConfig;
|
|
16
24
|
readonly env?: NodeJS.ProcessEnv;
|
|
25
|
+
/** Correlazione di un follow-up gia' prelevato dall'inbox dall'host. */
|
|
26
|
+
readonly inputMessage?: {
|
|
27
|
+
readonly id: string;
|
|
28
|
+
readonly immediate?: boolean;
|
|
29
|
+
};
|
|
17
30
|
/** Allowlist filesystem aggiuntiva, isolata al singolo runTurn. */
|
|
18
31
|
readonly fsRoots?: readonly string[];
|
|
19
32
|
readonly executionTarget?: ExecutionTarget;
|
|
@@ -25,8 +38,8 @@ export interface AgentDeps {
|
|
|
25
38
|
* Viene marcata come non attendibile e non entra mai nella sessione.
|
|
26
39
|
*/
|
|
27
40
|
readonly ephemeralContext?: string;
|
|
28
|
-
readonly confirm: (action: string, detail: string) => Promise<boolean>;
|
|
29
|
-
readonly ask?: (question: string, options?: readonly string[]) => Promise<string | null>;
|
|
41
|
+
readonly confirm: (action: string, detail: string, signal?: AbortSignal) => Promise<boolean>;
|
|
42
|
+
readonly ask?: (question: string, options?: readonly string[], signal?: AbortSignal) => Promise<string | null>;
|
|
30
43
|
readonly spawnKingdom?: (castles: readonly SpawnAgentSpec[], opts?: {
|
|
31
44
|
baseBranch?: string;
|
|
32
45
|
detach?: boolean;
|
package/dist/core/agent.js
CHANGED
|
@@ -3,10 +3,11 @@ import { trackSessionUsage } from "./session-usage.js";
|
|
|
3
3
|
import { nameSession } from "./session-naming.js";
|
|
4
4
|
import { quotaResetAt } from "../providers/quota-limits.js";
|
|
5
5
|
import { RequestBudget } from "./request-plan.js";
|
|
6
|
-
import {
|
|
6
|
+
import { maxInputFor, resolveMaxTokens } from "./model-limits.js";
|
|
7
|
+
import { projectToolResult, visibleOutputPages, boundHistoricalToolResults } from "./tool-artifacts.js";
|
|
7
8
|
import { contextWindowFor, estimateMessagesTokens, estimateTokens, estimateToolDefinitionTokens, IMAGE_TOKEN_ESTIMATE, planCompaction, planCompactionMove, protectedExcerpts, repairInstructions, summarizeMessages, verifySummary, withProtectedExcerpts, } from "./compaction.js";
|
|
8
9
|
import { RoomMemory, formatRoomRecord } from "../vascend/room-memory.js";
|
|
9
|
-
import {} from "./context-ledger.js";
|
|
10
|
+
import { buildContextLedger } from "./context-ledger.js";
|
|
10
11
|
import { applyMediaEviction, applyToolResultDemotion, mediaBudgetPolicy, planMediaEviction, planToolResultDemotion, slimMessageForSession, toolIndexPolicy, EMPTY_PLAN, } from "./tool-result-index.js";
|
|
11
12
|
import { createToolExecutor } from "./tool-executor.js";
|
|
12
13
|
import { ToolOutputStore } from "./tool-result-store.js";
|
|
@@ -26,6 +27,7 @@ import { DecisionStore, promoteDecisions, decisionToRoomRecord } from "../vascen
|
|
|
26
27
|
import { ContractStore, promoteContractChanges, contractToRoomRecord } from "../vascend/contract-memory.js";
|
|
27
28
|
import { VascendPlanStore } from "../vascend/plan-store.js";
|
|
28
29
|
import { pendingMembers, teamForSession, waitForTeamChange } from "../vascend/team-session.js";
|
|
30
|
+
import { resolveKingdomBus } from "../vascend/kingdom-channel.js";
|
|
29
31
|
import { getKingdomScribe } from "../vascend/kingdom-scribe.js";
|
|
30
32
|
import { toolCompressOptions } from "./tool-compress.js";
|
|
31
33
|
import { routeEffort, isRoutineBatch, effectiveToolName, effortRoutingEnabled } from "./effort.js";
|
|
@@ -39,14 +41,6 @@ import { RunTiming } from "./run-timing.js";
|
|
|
39
41
|
import { queuedConfirmation } from "./permission-queue.js";
|
|
40
42
|
import { workspaceMessageText, workspacePeersContext } from "./workspace-sessions.js";
|
|
41
43
|
const CONTEXT_READ_TOOLS = new Set(["read_file", "glob", "grep", "list_dir", "recall", "output_page", "vascend_status", "ram_status", "file_activity", "workspace_sessions", "tool_search", "tool_list", "tool_describe", "bash_output"]);
|
|
42
|
-
// Tetto di sicurezza ai turni di un singolo giro (anti-loop). Alto di default
|
|
43
|
-
// (i goal Danilov multi-castello richiedono molti turni) e configurabile via
|
|
44
|
-
// TALOS_MAX_TURNS. Al raggiungimento NON e' un errore fatale: il giro termina e
|
|
45
|
-
// la validazione del regno sveglia l'agente sulle stanze ancora al buio.
|
|
46
|
-
function maxTurns(env) {
|
|
47
|
-
const n = Number(env["TALOS_MAX_TURNS"]);
|
|
48
|
-
return Number.isFinite(n) && n > 0 ? n : 200;
|
|
49
|
-
}
|
|
50
44
|
// Quante volte auto-continuare un output troncato (stop=max_tokens) prima di
|
|
51
45
|
// arrendersi e chiedere di spezzare il compito. Configurabile via
|
|
52
46
|
// TALOS_MAX_AUTOCONTINUE. 0 = disabilita l'auto-continuazione.
|
|
@@ -153,9 +147,13 @@ function coerceParam(raw) {
|
|
|
153
147
|
return raw.replace(/^\n/, "").replace(/\n$/, "");
|
|
154
148
|
}
|
|
155
149
|
// Esegue un giro completo: dato l'input utente, alterna chiamate al modello
|
|
156
|
-
// ed esecuzione di tool finche' il modello non si ferma
|
|
157
|
-
//
|
|
150
|
+
// ed esecuzione di tool finche' il modello non si ferma, si verifica un errore
|
|
151
|
+
// o l'utente interrompe via signal. Nessun tetto al numero di turni.
|
|
158
152
|
export async function runTurn(deps, userInput, sink, signal) {
|
|
153
|
+
if (deps.config.fusion && !deps.kingdom) {
|
|
154
|
+
const { runFusionTurn } = await import("../fusion/run.js");
|
|
155
|
+
return runFusionTurn(deps, userInput, sink, signal, runTurn);
|
|
156
|
+
}
|
|
159
157
|
// Un collaboratore costruito copiando AgentDeps non assume l'identita'
|
|
160
158
|
// della sessione principale: il team ha gia' il proprio canale dedicato.
|
|
161
159
|
const channel = deps.workspaceSession?.owns(deps.config.cwd, deps.session.id, deps.executionTarget)
|
|
@@ -166,13 +164,23 @@ export async function runTurn(deps, userInput, sink, signal) {
|
|
|
166
164
|
const timing = new RunTiming(deps.config.sessionDir, deps.session.id, deps.env ?? process.env);
|
|
167
165
|
const releaseStorage = protectSessionStorage(deps.config.sessionDir, [deps.session.id, deps.config.roomStoreId, deps.config.planStoreId].filter((value) => Boolean(value)), deps.env ?? process.env, deps.config.cwd);
|
|
168
166
|
let failed = false;
|
|
167
|
+
const namingController = new AbortController();
|
|
168
|
+
const abortNaming = () => namingController.abort();
|
|
169
|
+
signal.addEventListener("abort", abortNaming, { once: true });
|
|
170
|
+
if (signal.aborted)
|
|
171
|
+
abortNaming();
|
|
169
172
|
const naming = (deps.env ?? process.env)["TALOS_AUTO_TITLE"] === "1" && !deps.kingdom
|
|
170
|
-
? nameSession(deps, text, sink, signal) : Promise.resolve();
|
|
173
|
+
? nameSession(deps, text, sink, namingController.signal) : Promise.resolve();
|
|
171
174
|
try {
|
|
172
175
|
await runAgentLoop({ ...deps, workspaceSession: channel,
|
|
173
176
|
provider: trackSessionUsage(timing.provider(deps.provider), deps.config.sessionDir, deps.session.id, sink),
|
|
174
177
|
confirm: (action, detail) => timing.wait("permission", () => queuedConfirmation(deps.confirm, action, detail, signal)),
|
|
175
|
-
}, userInput, event => {
|
|
178
|
+
}, userInput, event => {
|
|
179
|
+
if (event.type === "status" && event.label.startsWith("Limite sessione di 5 ore raggiunto"))
|
|
180
|
+
abortNaming();
|
|
181
|
+
timing.event(event);
|
|
182
|
+
sink(event);
|
|
183
|
+
}, signal);
|
|
176
184
|
}
|
|
177
185
|
catch (error) {
|
|
178
186
|
failed = true;
|
|
@@ -180,6 +188,7 @@ export async function runTurn(deps, userInput, sink, signal) {
|
|
|
180
188
|
}
|
|
181
189
|
finally {
|
|
182
190
|
await naming;
|
|
191
|
+
signal.removeEventListener("abort", abortNaming);
|
|
183
192
|
timing.finish(signal.aborted, failed);
|
|
184
193
|
channel?.update({ state: "idle" });
|
|
185
194
|
releaseStorage();
|
|
@@ -337,6 +346,10 @@ userInput, sink, signal) {
|
|
|
337
346
|
systemBlocks.splice(stableBlockCount);
|
|
338
347
|
turnBlocks.length = 0;
|
|
339
348
|
turnBlockRecords.length = 0;
|
|
349
|
+
if (config.turnSystem) {
|
|
350
|
+
turnBlocks.push(config.turnSystem);
|
|
351
|
+
turnBlockRecords.push({ key: "host-instructions", label: "Istruzioni operative dell'host", text: config.turnSystem, cacheable: false });
|
|
352
|
+
}
|
|
340
353
|
if (persistenceReminder)
|
|
341
354
|
addTurnBlock(persistenceReminder, { key: "nudge", label: "Promemoria di persistenza" });
|
|
342
355
|
// Il contesto dell'host non e' parte del system prompt ne' della cronologia:
|
|
@@ -359,10 +372,19 @@ userInput, sink, signal) {
|
|
|
359
372
|
userText: latestUserText,
|
|
360
373
|
inheritProjectFrame: sharedProjectMemory && sessionWasEmpty,
|
|
361
374
|
});
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
375
|
+
const inheritedFrame = fabric.frame.receipt?.inherited === true;
|
|
376
|
+
// Su una sessione vuota il frame appena creato deriva interamente dal
|
|
377
|
+
// messaggio corrente: reinviarlo come Fabric ripeterebbe lo stesso prompt
|
|
378
|
+
// in missione, contratto e revisioni. Il frame viene comunque persistito
|
|
379
|
+
// e sara' disponibile dal follow-up successivo.
|
|
380
|
+
const fabricBlock = horizonHost
|
|
381
|
+
? renderHorizonFabricBlock(fabric)
|
|
382
|
+
: sessionWasEmpty && !inheritedFrame ? "" : fabric.systemBlock;
|
|
383
|
+
if (fabricBlock)
|
|
384
|
+
addTurnBlock(fabricBlock, {
|
|
385
|
+
key: "fabric",
|
|
386
|
+
label: "Frame di progetto (Context Fabric)",
|
|
387
|
+
});
|
|
366
388
|
}
|
|
367
389
|
catch {
|
|
368
390
|
// Context Fabric e' un acceleratore, non un single point of failure: uno
|
|
@@ -469,12 +491,12 @@ userInput, sink, signal) {
|
|
|
469
491
|
// dal turno) e fonde la config migliore nella baseline del progetto. Effetto
|
|
470
492
|
// collaterale utile: lascia lo snapshot degli store caldo per il turno dopo.
|
|
471
493
|
let memoryPacket = "";
|
|
472
|
-
if (!contextBlock || horizonHost) {
|
|
494
|
+
if (!contextBlock || horizonHost || sessionWasEmpty) {
|
|
473
495
|
memoryPacket = compileInput.snapshot.packet(12_000);
|
|
474
496
|
}
|
|
475
497
|
if (!contextBlock)
|
|
476
498
|
contextBlock = memoryPacket;
|
|
477
|
-
if (
|
|
499
|
+
if (!shouldIncludeHorizonContextPack({
|
|
478
500
|
sessionWasEmpty,
|
|
479
501
|
inheritedFrame: fabric?.frame.receipt?.inherited === true,
|
|
480
502
|
hasCompiledEvidence: Boolean(compiledContext?.report.cleaned.length),
|
|
@@ -519,6 +541,9 @@ userInput, sink, signal) {
|
|
|
519
541
|
// Il blocco NON viene persistito nella sessione: la cronologia su disco resta
|
|
520
542
|
// pulita e il prefisso inviato al modello resta byte-identico fra i turni.
|
|
521
543
|
const turnMessage = session.append({ role: "user", content: userParts }).message;
|
|
544
|
+
if (deps.inputMessage)
|
|
545
|
+
sink({ type: "user_message", id: deps.inputMessage.id, text: userText,
|
|
546
|
+
at: Date.now(), ...(deps.inputMessage.immediate ? { immediate: true } : {}) });
|
|
522
547
|
await host?.emit("agent_start", { input: userText });
|
|
523
548
|
// Prende in carico i messaggi arrivati durante il turno: li appende come
|
|
524
549
|
// messaggi utente veri (quindi entrano nel contesto del giro successivo) e
|
|
@@ -526,6 +551,7 @@ userInput, sink, signal) {
|
|
|
526
551
|
// l'interfaccia mostra come "letto". Ritorna true se ne ha consumato almeno
|
|
527
552
|
// uno, cosi' il chiamante sa che c'e' lavoro nuovo da servire.
|
|
528
553
|
const receivedPeerMessages = new Set();
|
|
554
|
+
const notifiedTeamMessages = new Set();
|
|
529
555
|
const consumeInbox = () => {
|
|
530
556
|
const arrivals = deps.inbox?.drain() ?? [];
|
|
531
557
|
if (arrivals.length) {
|
|
@@ -560,7 +586,6 @@ userInput, sink, signal) {
|
|
|
560
586
|
}
|
|
561
587
|
return arrivals.length > 0 || peerArrivals > 0;
|
|
562
588
|
};
|
|
563
|
-
const turnCap = maxTurns(env);
|
|
564
589
|
const requestBudget = new RequestBudget();
|
|
565
590
|
const toolCompress = toolCompressOptions(env);
|
|
566
591
|
// Archivio dei tool result: gli output voluminosi vengono indicizzati appena
|
|
@@ -584,7 +609,7 @@ userInput, sink, signal) {
|
|
|
584
609
|
// Effort routing: i turni di routine (digestione di letture) abbassano il
|
|
585
610
|
// reasoning; il primo turno e quelli con scrittura/errore tengono l'effort pieno.
|
|
586
611
|
const baseEffort = (config.effort ?? "");
|
|
587
|
-
const effortRouting = effortRoutingEnabled(env);
|
|
612
|
+
const effortRouting = effortRoutingEnabled(env, provider.id);
|
|
588
613
|
let routineBatch = false;
|
|
589
614
|
// Auto-continuazione su output troncato: se il modello si ferma per
|
|
590
615
|
// max_tokens (risposta tagliata al tetto), invece di chiudere la stanza con
|
|
@@ -595,6 +620,7 @@ userInput, sink, signal) {
|
|
|
595
620
|
const completionRepairCap = maxCompletionRepairs(env);
|
|
596
621
|
let emptyResponseRepairs = 0;
|
|
597
622
|
let transientGuardContext = "";
|
|
623
|
+
let stepDirective = null;
|
|
598
624
|
let planCompletionRepairs = 0;
|
|
599
625
|
let planTouchedThisRun = false;
|
|
600
626
|
let delegationObserved = false;
|
|
@@ -626,7 +652,28 @@ userInput, sink, signal) {
|
|
|
626
652
|
...openContractSymbols(deps),
|
|
627
653
|
].filter(Boolean)),
|
|
628
654
|
].slice(0, MAX_COMPACTION_ANCHORS);
|
|
629
|
-
for (let turn = 0
|
|
655
|
+
for (let turn = 0;; turn += 1) {
|
|
656
|
+
if (signal.aborted) {
|
|
657
|
+
await archiveCurrentRoom();
|
|
658
|
+
sink({ type: "error", message: "interrotto" });
|
|
659
|
+
await host?.emit("agent_end", {});
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
// I comandi manuali mutano la cronologia solo dopo un batch completo di
|
|
663
|
+
// tool, mai durante provider/tool concorrenti. Non diventano prompt finti.
|
|
664
|
+
const compactions = deps.inbox?.drainCompactions?.() ?? [];
|
|
665
|
+
for (const request of compactions) {
|
|
666
|
+
try {
|
|
667
|
+
const compacted = await compactNow(deps, signal, sink, request.instructions, compactionAnchors());
|
|
668
|
+
contextDirty ||= compacted;
|
|
669
|
+
sink({ type: "status", category: "context", label: compacted
|
|
670
|
+
? "Contesto compattato; proseguo nella stessa sessione."
|
|
671
|
+
: "Nessuna compattazione necessaria; contesto conservato." });
|
|
672
|
+
}
|
|
673
|
+
catch (err) {
|
|
674
|
+
sink({ type: "status", category: "context", label: `Compattazione non riuscita: ${err.message}; contesto conservato.` });
|
|
675
|
+
}
|
|
676
|
+
}
|
|
630
677
|
if (signal.aborted) {
|
|
631
678
|
await archiveCurrentRoom();
|
|
632
679
|
sink({ type: "error", message: "interrotto" });
|
|
@@ -658,7 +705,7 @@ userInput, sink, signal) {
|
|
|
658
705
|
// persisted, including nested execute calls and updates from collaborators.
|
|
659
706
|
if (completed.length && config.compaction.enabled && config.compaction.perRoom
|
|
660
707
|
&& policy.roomCompaction !== "never") {
|
|
661
|
-
const limits = workingContextLimits(policy, contextWindowFor(config.model, config.contextWindow), config.compaction.reserveTokens);
|
|
708
|
+
const limits = workingContextLimits(policy, contextWindowFor(config.model, config.contextWindow), config.compaction.reserveTokens, resolveMaxTokens(config.maxTokens, config.model), maxInputFor(config.model));
|
|
662
709
|
const activeTokens = contextTokens(deps, runtimeSystem) + estimateTokens(turnContext)
|
|
663
710
|
- planDemotion(session.history()).freedTokens
|
|
664
711
|
- planMediaEviction({ messages: session.history(), policy: mediaBudget }).images * IMAGE_TOKEN_ESTIMATE;
|
|
@@ -691,6 +738,7 @@ userInput, sink, signal) {
|
|
|
691
738
|
// successivo la sessione espone soltanto il riferimento testuale. Senza
|
|
692
739
|
// questa proiezione ogni nuova richiesta reinviava lo stesso base64 (e gli
|
|
693
740
|
// SVG storici potevano far fallire Anthropic per dimensioni nominali >8k).
|
|
741
|
+
messages = boundHistoricalToolResults(messages, outputStore, toolCompress);
|
|
694
742
|
messages = projectHistoricalPromptImages(messages, turnMessage);
|
|
695
743
|
// Budget delle immagini: le schermate vecchie lasciano la finestra. Prima
|
|
696
744
|
// della retrocessione del testo, perche' e' la voce piu' pesante di tutte
|
|
@@ -761,7 +809,10 @@ userInput, sink, signal) {
|
|
|
761
809
|
: {}),
|
|
762
810
|
};
|
|
763
811
|
let streamedText = "";
|
|
764
|
-
|
|
812
|
+
stepDirective = deps.stepPolicy
|
|
813
|
+
? await deps.stepPolicy.beforeStep({ step: turn, tools: tools.names(), signal }).catch(() => null) : null;
|
|
814
|
+
const requestTurnContext = [turnContext, scopeGuidance, transientGuardContext, peerContext, stepDirective?.guidance]
|
|
815
|
+
.filter(Boolean).join("\n\n");
|
|
765
816
|
// I guard interni valgono per una sola richiesta provider e non devono
|
|
766
817
|
// entrare nella cronologia come messaggi utente.
|
|
767
818
|
transientGuardContext = "";
|
|
@@ -784,6 +835,7 @@ userInput, sink, signal) {
|
|
|
784
835
|
onActivity: (label) => sink({ type: "status", label }),
|
|
785
836
|
onReasoning: (delta) => sink({ type: "reasoning", delta }),
|
|
786
837
|
}, ledgerInput);
|
|
838
|
+
sessionContextFrames.set(session, { ...ledgerInput, messages: undefined, now: undefined });
|
|
787
839
|
sink({ type: "context_window", ledger: requestPlan.ledger });
|
|
788
840
|
if (!requestPlan.fits) {
|
|
789
841
|
sink({ type: "error", message: "Il contesto supera la finestra del modello anche dopo la compattazione. La sessione resta recuperabile." });
|
|
@@ -909,12 +961,21 @@ userInput, sink, signal) {
|
|
|
909
961
|
// Ultimo controllo della casella prima di chiudere: se l'utente ha scritto
|
|
910
962
|
// mentre il modello stava componendo la risposta, il turno prosegue invece
|
|
911
963
|
// di terminare e costringerlo a un giro nuovo.
|
|
912
|
-
if (consumeInbox())
|
|
964
|
+
if (consumeInbox() || deps.inbox?.pendingCompactions)
|
|
913
965
|
continue;
|
|
914
966
|
const activeTeam = delegationObserved ? teamForSession(session.id) : null;
|
|
915
967
|
if (activeTeam && !activeTeam.done) {
|
|
916
968
|
sink({ type: "status", label: `team al lavoro: ${pendingMembers(activeTeam).join(", ")}; attendo avanzamento` });
|
|
917
|
-
|
|
969
|
+
const teamBus = resolveKingdomBus(process.env, config.sessionDir);
|
|
970
|
+
await waitForTeamChange(activeTeam, signal, () => {
|
|
971
|
+
if (deps.inbox?.pending || deps.inbox?.pendingCompactions)
|
|
972
|
+
return true;
|
|
973
|
+
const unread = teamBus.peekInbox(activeTeam.id, deps.kingdom?.self || "orchestratore")
|
|
974
|
+
.filter(message => !notifiedTeamMessages.has(`${activeTeam.id}:${message.seq}`));
|
|
975
|
+
for (const message of unread)
|
|
976
|
+
notifiedTeamMessages.add(`${activeTeam.id}:${message.seq}`);
|
|
977
|
+
return unread.length > 0;
|
|
978
|
+
});
|
|
918
979
|
transientGuardContext = "[TALOS_TEAM_GUARD]\nIl team avviato deve ancora essere raccolto e verificato. "
|
|
919
980
|
+ "Leggi team_report e team_inbox, rispondi ai blocchi e verifica i risultati prima della consegna. "
|
|
920
981
|
+ "Non dichiarare concluso il lavoro solo perche' l'ingaggio e' partito.";
|
|
@@ -1050,6 +1111,10 @@ userInput, sink, signal) {
|
|
|
1050
1111
|
// a indice di stanze, cosi' resta sempre compatto. Il dettaglio si
|
|
1051
1112
|
// recupera col tool recall.
|
|
1052
1113
|
await archiveCurrentRoom();
|
|
1114
|
+
// L'archiviazione puo' attendere I/O: non perdere un invio o comando
|
|
1115
|
+
// arrivato dopo il primo controllo della finale e prima del done.
|
|
1116
|
+
if (consumeInbox() || deps.inbox?.pendingCompactions)
|
|
1117
|
+
continue;
|
|
1053
1118
|
sink({ type: "done" });
|
|
1054
1119
|
await host?.emit("agent_end", {});
|
|
1055
1120
|
return;
|
|
@@ -1057,6 +1122,7 @@ userInput, sink, signal) {
|
|
|
1057
1122
|
// Esegue i tool richiesti e raccoglie i risultati in un turno "tool".
|
|
1058
1123
|
const ctx = {
|
|
1059
1124
|
cwd: config.cwd,
|
|
1125
|
+
waitInterrupted: () => Boolean(deps.inbox?.pending || deps.inbox?.pendingCompactions),
|
|
1060
1126
|
...(deps.workspaceSession ? { workspaceSession: deps.workspaceSession } : {}),
|
|
1061
1127
|
...(deps.executionTarget ? { executionTarget: deps.executionTarget } : {}),
|
|
1062
1128
|
...(deps.fsRoots !== undefined ? { fsRoots: deps.fsRoots } : {}),
|
|
@@ -1085,6 +1151,9 @@ userInput, sink, signal) {
|
|
|
1085
1151
|
const executeCall = createToolExecutor(ctx, {
|
|
1086
1152
|
onCall: (call, parentId) => sink({ type: "tool_call", call, ...(parentId ? { parentId } : {}) }),
|
|
1087
1153
|
before: async (call) => {
|
|
1154
|
+
if (stepDirective?.admit && !stepDirective.admit(call.name)) {
|
|
1155
|
+
return { block: true, reason: stepDirective.rejection ?? "tool non ammesso in questo passo" };
|
|
1156
|
+
}
|
|
1088
1157
|
let blocked;
|
|
1089
1158
|
for (const output of await host?.emit("tool_call", { toolName: call.name, input: { ...call.input } }) ?? []) {
|
|
1090
1159
|
if (output.block)
|
|
@@ -1135,6 +1204,9 @@ userInput, sink, signal) {
|
|
|
1135
1204
|
results.push(part);
|
|
1136
1205
|
sink({ type: "tool_result", result: part });
|
|
1137
1206
|
}
|
|
1207
|
+
deps.stepPolicy?.afterStep?.({ step: turn, final: false,
|
|
1208
|
+
tools: toolCalls.map(call => effectiveToolName(call.name, call.input)),
|
|
1209
|
+
errors: results.filter(result => result.isError).length });
|
|
1138
1210
|
if (toolCalls.some((call, index) => PLAN_COMPLETION_TOOLS.has(effectiveToolName(call.name, call.input))
|
|
1139
1211
|
&& results[index]?.isError !== true)) {
|
|
1140
1212
|
planTouchedThisRun = true;
|
|
@@ -1204,9 +1276,6 @@ Il piano ha ${collaborators.length} filoni `
|
|
|
1204
1276
|
transientGuardContext = [transientGuardContext, hint].filter(Boolean).join("\n\n");
|
|
1205
1277
|
}
|
|
1206
1278
|
}
|
|
1207
|
-
await host?.emit("agent_end", {});
|
|
1208
|
-
await archiveCurrentRoom();
|
|
1209
|
-
sink({ type: "error", message: `pausa al tetto di ${turnCap} turni per questo giro (TALOS_MAX_TURNS per alzarlo); la validazione del piano riprende le attivita rimaste` });
|
|
1210
1279
|
}
|
|
1211
1280
|
// Archivia la stanza appena illuminata: costruisce il record Danilov dei nodi
|
|
1212
1281
|
// di questo turno e lo persiste nella memoria delle stanze. L'archiviazione e'
|
|
@@ -1278,7 +1347,7 @@ async function archiveRoom(deps, roomStartHead, sink, policy, signal, anchors) {
|
|
|
1278
1347
|
const firstKeptId = head;
|
|
1279
1348
|
if (policy.roomCompaction === "threshold") {
|
|
1280
1349
|
const window = contextWindowFor(config.model, config.contextWindow);
|
|
1281
|
-
const limits = workingContextLimits(policy, window, config.compaction.reserveTokens);
|
|
1350
|
+
const limits = workingContextLimits(policy, window, config.compaction.reserveTokens, resolveMaxTokens(config.maxTokens, config.model), maxInputFor(config.model));
|
|
1282
1351
|
if (projectedContextTokens(deps) <= limits.checkpoint)
|
|
1283
1352
|
return;
|
|
1284
1353
|
await compactNow(deps, signal, sink, undefined, anchors);
|
|
@@ -1630,6 +1699,9 @@ function projectCompactionMessages(deps, messages) {
|
|
|
1630
1699
|
// Compattazione gia' avviata e non ancora conclusa, per sessione. Single-flight:
|
|
1631
1700
|
// due turni ravvicinati non devono riassumere due volte la stessa cronologia.
|
|
1632
1701
|
const pendingCompaction = new WeakMap();
|
|
1702
|
+
// Ultima composizione runtime: una compattazione idle non deve misurare solo
|
|
1703
|
+
// la cronologia o usare l'usage cumulativo del provider come finestra attiva.
|
|
1704
|
+
const sessionContextFrames = new WeakMap();
|
|
1633
1705
|
// Compatta se la soglia e' superata. No-op se disabilitata o non necessario.
|
|
1634
1706
|
//
|
|
1635
1707
|
// La compattazione e' il nodo piu' costoso del giro: una chiamata al modello
|
|
@@ -1650,7 +1722,7 @@ savedTokens = 0,
|
|
|
1650
1722
|
system = deps.config.system) {
|
|
1651
1723
|
const { compaction } = deps.config;
|
|
1652
1724
|
const inFlight = pendingCompaction.get(deps.session);
|
|
1653
|
-
const limits = workingContextLimits(contextPolicy(deps.env ?? process.env), contextWindowFor(deps.config.model, deps.config.contextWindow), compaction.reserveTokens);
|
|
1725
|
+
const limits = workingContextLimits(contextPolicy(deps.env ?? process.env), contextWindowFor(deps.config.model, deps.config.contextWindow), compaction.reserveTokens, resolveMaxTokens(deps.config.maxTokens, deps.config.model), maxInputFor(deps.config.model));
|
|
1654
1726
|
const move = planCompactionMove({
|
|
1655
1727
|
enabled: compaction.enabled,
|
|
1656
1728
|
// Il pack compilato e il contesto IDE sono effimeri e quindi non vivono
|
|
@@ -1705,8 +1777,8 @@ export async function compactNow(deps, signal, sink, instructions, anchors = [])
|
|
|
1705
1777
|
async function performCompaction(deps, signal, sink, instructions, anchors = []) {
|
|
1706
1778
|
const { session, config } = deps;
|
|
1707
1779
|
const provider = trackSessionUsage(deps.provider, config.sessionDir, session.id, sink);
|
|
1708
|
-
const fullChain = session.nodeChain();
|
|
1709
1780
|
const previousCompaction = session.lastCompaction;
|
|
1781
|
+
const fullChain = session.nodeChain(previousCompaction?.firstKeptId);
|
|
1710
1782
|
const liveStart = previousCompaction
|
|
1711
1783
|
? fullChain.findIndex((node) => node.id === previousCompaction.firstKeptId)
|
|
1712
1784
|
: 0;
|
|
@@ -1780,7 +1852,7 @@ async function performCompaction(deps, signal, sink, instructions, anchors = [])
|
|
|
1780
1852
|
// A speculative summary may finish after new messages arrive. Keep that tail
|
|
1781
1853
|
// intact, but reject a result for a branch that is no longer current.
|
|
1782
1854
|
if (signal.aborted || session.lastCompaction !== previousCompaction
|
|
1783
|
-
|| !session.nodeChain().some(node => node.id === snapshotHead))
|
|
1855
|
+
|| !session.nodeChain(snapshotHead ?? undefined).some(node => node.id === snapshotHead))
|
|
1784
1856
|
return false;
|
|
1785
1857
|
const checkpoint = compactionCheckpoint(checkpointTasks(config, session.id, deps.kingdom?.self), messages, plan.cutIndex);
|
|
1786
1858
|
if (checkpoint)
|
|
@@ -1788,6 +1860,14 @@ async function performCompaction(deps, signal, sink, instructions, anchors = [])
|
|
|
1788
1860
|
session.compact(summary, firstKept.id, tokensBefore);
|
|
1789
1861
|
const tokensAfter = projectedContextTokens(deps);
|
|
1790
1862
|
sink({ type: "compacted", tokensBefore, tokensAfter, reason: "summary", ...(anchors.length ? { anchors: [...anchors] } : {}) });
|
|
1863
|
+
const frame = sessionContextFrames.get(session);
|
|
1864
|
+
sink({ type: "context_window", ledger: buildContextLedger({
|
|
1865
|
+
model: config.model, contextWindow: config.contextWindow, reserveTokens: config.compaction.reserveTokens,
|
|
1866
|
+
workingContextTokens: contextPolicy(deps.env ?? process.env).workingContextTokens,
|
|
1867
|
+
system: config.system, ...frame, tools: deps.tools.defs(),
|
|
1868
|
+
messages: projectCompactionMessages(deps, session.history()), demoted: null,
|
|
1869
|
+
compaction: { ts: session.lastCompaction.ts, tokensBefore, summary },
|
|
1870
|
+
}) });
|
|
1791
1871
|
return true;
|
|
1792
1872
|
}
|
|
1793
1873
|
finally {
|
|
@@ -13,14 +13,16 @@ export interface BgTask {
|
|
|
13
13
|
}
|
|
14
14
|
interface Foreground {
|
|
15
15
|
readonly taskId: string;
|
|
16
|
+
readonly sessionId?: string;
|
|
16
17
|
background(): void;
|
|
17
18
|
}
|
|
18
19
|
export declare class BackgroundManager {
|
|
19
20
|
private readonly tasks;
|
|
20
21
|
private readonly children;
|
|
21
22
|
private readonly order;
|
|
23
|
+
private readonly completedOrder;
|
|
22
24
|
private seq;
|
|
23
|
-
private
|
|
25
|
+
private readonly foregrounds;
|
|
24
26
|
private readonly changeCbs;
|
|
25
27
|
private readonly finishCbs;
|
|
26
28
|
createTask(command: string): BgTask;
|
|
@@ -29,11 +31,16 @@ export declare class BackgroundManager {
|
|
|
29
31
|
finishTask(id: string, status: BgStatus, exitCode?: number): void;
|
|
30
32
|
setForeground(fg: Foreground): void;
|
|
31
33
|
clearForeground(id?: string): void;
|
|
32
|
-
|
|
34
|
+
private foreground;
|
|
35
|
+
hasForeground(sessionId?: string): boolean;
|
|
33
36
|
markDetached(id: string): void;
|
|
34
|
-
requestBackground(): BgTask | null;
|
|
37
|
+
requestBackground(sessionId?: string): BgTask | null;
|
|
35
38
|
kill(id: string): boolean;
|
|
36
39
|
get(id: string): BgTask | undefined;
|
|
40
|
+
waitForTask(id: string, signal: AbortSignal, options?: {
|
|
41
|
+
readonly timeoutMs?: number;
|
|
42
|
+
readonly interrupted?: () => boolean;
|
|
43
|
+
}): Promise<void>;
|
|
37
44
|
list(): readonly BgTask[];
|
|
38
45
|
running(): readonly BgTask[];
|
|
39
46
|
onChange(cb: () => void): () => void;
|
package/dist/core/background.js
CHANGED
|
@@ -25,8 +25,9 @@ export class BackgroundManager {
|
|
|
25
25
|
tasks = new Map();
|
|
26
26
|
children = new Map();
|
|
27
27
|
order = [];
|
|
28
|
+
completedOrder = [];
|
|
28
29
|
seq = 0;
|
|
29
|
-
|
|
30
|
+
foregrounds = new Map();
|
|
30
31
|
changeCbs = new Set();
|
|
31
32
|
finishCbs = new Set();
|
|
32
33
|
createTask(command) {
|
|
@@ -56,6 +57,7 @@ export class BackgroundManager {
|
|
|
56
57
|
t.endedAt = Date.now();
|
|
57
58
|
if (exitCode !== undefined)
|
|
58
59
|
t.exitCode = exitCode;
|
|
60
|
+
this.completedOrder.push(id);
|
|
59
61
|
this.children.delete(id);
|
|
60
62
|
this.emitChange();
|
|
61
63
|
for (const cb of this.finishCbs)
|
|
@@ -63,10 +65,17 @@ export class BackgroundManager {
|
|
|
63
65
|
this.pruneHistory(id);
|
|
64
66
|
}
|
|
65
67
|
// Registra il comando in primo piano (chiamato dal tool bash all'avvio).
|
|
66
|
-
setForeground(fg) { this.fg
|
|
67
|
-
clearForeground(id) {
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
setForeground(fg) { this.foregrounds.set(fg.taskId, fg); }
|
|
69
|
+
clearForeground(id) {
|
|
70
|
+
if (id)
|
|
71
|
+
this.foregrounds.delete(id);
|
|
72
|
+
else
|
|
73
|
+
this.foregrounds.clear();
|
|
74
|
+
}
|
|
75
|
+
foreground(sessionId) {
|
|
76
|
+
return [...this.foregrounds.values()].findLast(fg => sessionId === undefined || fg.sessionId === sessionId);
|
|
77
|
+
}
|
|
78
|
+
hasForeground(sessionId) { return !!this.foreground(sessionId); }
|
|
70
79
|
markDetached(id) {
|
|
71
80
|
const task = this.tasks.get(id);
|
|
72
81
|
if (task && !task.detached) {
|
|
@@ -76,11 +85,11 @@ export class BackgroundManager {
|
|
|
76
85
|
}
|
|
77
86
|
// Ctrl+B: stacca il comando in primo piano. Ritorna il task o null se non c'e'
|
|
78
87
|
// niente in primo piano.
|
|
79
|
-
requestBackground() {
|
|
80
|
-
const fg = this.
|
|
88
|
+
requestBackground(sessionId) {
|
|
89
|
+
const fg = this.foreground(sessionId);
|
|
81
90
|
if (!fg)
|
|
82
91
|
return null;
|
|
83
|
-
this.fg
|
|
92
|
+
this.foregrounds.delete(fg.taskId);
|
|
84
93
|
const t = this.tasks.get(fg.taskId);
|
|
85
94
|
if (t)
|
|
86
95
|
t.detached = true;
|
|
@@ -97,6 +106,41 @@ export class BackgroundManager {
|
|
|
97
106
|
return true;
|
|
98
107
|
}
|
|
99
108
|
get(id) { return this.tasks.get(id); }
|
|
109
|
+
// Wait in the host, without asking the model to poll unchanged output.
|
|
110
|
+
// Keep the task reference alive even if completed history is pruned.
|
|
111
|
+
async waitForTask(id, signal, options = {}) {
|
|
112
|
+
signal.throwIfAborted();
|
|
113
|
+
const task = this.tasks.get(id);
|
|
114
|
+
if (!task || task.status !== "running" || options.interrupted?.())
|
|
115
|
+
return;
|
|
116
|
+
await new Promise((resolve, reject) => {
|
|
117
|
+
let timeout;
|
|
118
|
+
let interruptCheck;
|
|
119
|
+
const cleanup = () => {
|
|
120
|
+
unsubscribe();
|
|
121
|
+
signal.removeEventListener("abort", abort);
|
|
122
|
+
clearTimeout(timeout);
|
|
123
|
+
clearInterval(interruptCheck);
|
|
124
|
+
};
|
|
125
|
+
const finish = () => { cleanup(); resolve(); };
|
|
126
|
+
const abort = () => { cleanup(); reject(signal.reason); };
|
|
127
|
+
const unsubscribe = this.onFinish(completed => { if (completed.id === id)
|
|
128
|
+
finish(); });
|
|
129
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
130
|
+
if (options.timeoutMs !== undefined)
|
|
131
|
+
timeout = setTimeout(finish, options.timeoutMs);
|
|
132
|
+
// Only check local user input; elapsed time/output never wakes the model.
|
|
133
|
+
if (options.interrupted)
|
|
134
|
+
interruptCheck = setInterval(() => {
|
|
135
|
+
if (options.interrupted?.())
|
|
136
|
+
finish();
|
|
137
|
+
}, 100);
|
|
138
|
+
if (signal.aborted)
|
|
139
|
+
abort();
|
|
140
|
+
else if (task.status !== "running")
|
|
141
|
+
finish();
|
|
142
|
+
});
|
|
143
|
+
}
|
|
100
144
|
list() {
|
|
101
145
|
// Ogni comando shell nasce come candidato al Ctrl+B, ma diventa davvero
|
|
102
146
|
// un'attivita' in background soltanto quando l'utente lo stacca. Esporre
|
|
@@ -111,7 +155,7 @@ export class BackgroundManager {
|
|
|
111
155
|
emitChange() { for (const cb of this.changeCbs)
|
|
112
156
|
cb(); }
|
|
113
157
|
pruneHistory(latestId) {
|
|
114
|
-
const completedDetached = this.
|
|
158
|
+
const completedDetached = this.completedOrder.filter((id) => {
|
|
115
159
|
const task = this.tasks.get(id);
|
|
116
160
|
return Boolean(task?.detached && task.status !== "running");
|
|
117
161
|
});
|
|
@@ -134,6 +178,8 @@ export class BackgroundManager {
|
|
|
134
178
|
}
|
|
135
179
|
const retainedOrder = this.order.filter((id) => keep.has(id));
|
|
136
180
|
this.order.splice(0, this.order.length, ...retainedOrder);
|
|
181
|
+
const retainedCompleted = this.completedOrder.filter(id => keep.has(id));
|
|
182
|
+
this.completedOrder.splice(0, this.completedOrder.length, ...retainedCompleted);
|
|
137
183
|
}
|
|
138
184
|
}
|
|
139
185
|
// Istanza condivisa di processo.
|
package/dist/core/bootstrap.js
CHANGED
package/dist/core/compaction.js
CHANGED
|
@@ -69,7 +69,7 @@ export function contextWindowFor(model, override = 0) {
|
|
|
69
69
|
const m = model.toLowerCase();
|
|
70
70
|
if (m.includes("1m"))
|
|
71
71
|
return 1_000_000;
|
|
72
|
-
if (m.includes("gpt-5.6") || m.includes("gpt-6
|
|
72
|
+
if (m.includes("gpt-5.6") || m.includes("gpt-6"))
|
|
73
73
|
return 1_050_000;
|
|
74
74
|
if (/claude-(?:fable|opus|sonnet)-5(?:\b|[-.])/.test(m))
|
|
75
75
|
return 1_000_000;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type ConfigObject = Record<string, unknown>;
|
|
2
|
+
export declare function readConfigObject(path: string): ConfigObject;
|
|
3
|
+
export declare function updateConfigObject(path: string, update: (current: ConfigObject) => ConfigObject): void;
|
|
4
|
+
export declare function resetInvalidConfig(path: string): string | null;
|
|
5
|
+
export {};
|