@vascend/talos 0.1.4 → 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/LICENSE +22 -0
- package/README.md +37 -12
- package/dist/core/agent.d.ts +16 -3
- package/dist/core/agent.js +170 -70
- 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.d.ts +3 -0
- package/dist/core/session-naming.js +47 -0
- package/dist/core/session-usage.js +4 -1
- package/dist/core/session.d.ts +5 -2
- package/dist/core/session.js +22 -7
- 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/storage-health.d.ts +24 -0
- package/dist/core/storage-health.js +72 -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 +26 -2
- 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 +35 -0
- package/dist/tui/agent-sessions-screen.js +178 -0
- package/dist/tui/agent-sessions.d.ts +53 -0
- package/dist/tui/agent-sessions.js +236 -0
- package/dist/tui/bottom-input.d.ts +57 -2
- package/dist/tui/bottom-input.js +449 -54
- 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 +6 -2
- 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 +351 -2
- 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/logo.js +3 -0
- package/dist/tui/model-details.js +13 -12
- package/dist/tui/model-picker.d.ts +2 -0
- package/dist/tui/model-picker.js +59 -0
- package/dist/tui/model-selection.js +19 -10
- package/dist/tui/native-scrollback.d.ts +2 -1
- package/dist/tui/native-scrollback.js +31 -6
- package/dist/tui/prompt-queue-store.d.ts +1 -0
- package/dist/tui/prompt-queue-store.js +4 -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/queued-questions.js +2 -4
- package/dist/tui/quick-help.d.ts +1 -1
- package/dist/tui/quick-help.js +3 -0
- package/dist/tui/remote-command.d.ts +7 -0
- package/dist/tui/remote-command.js +79 -0
- package/dist/tui/repl.d.ts +11 -2
- package/dist/tui/repl.js +457 -327
- package/dist/tui/review-store.d.ts +8 -1
- package/dist/tui/review-store.js +64 -11
- 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/scrollback-archive.d.ts +16 -0
- package/dist/tui/scrollback-archive.js +90 -0
- package/dist/tui/selector-mouse.d.ts +1 -0
- package/dist/tui/selector-mouse.js +1 -1
- package/dist/tui/selector.d.ts +11 -0
- package/dist/tui/selector.js +28 -4
- package/dist/tui/session-controls.d.ts +26 -0
- package/dist/tui/session-controls.js +65 -0
- package/dist/tui/session-naming-notice.d.ts +14 -0
- package/dist/tui/session-naming-notice.js +59 -0
- package/dist/tui/session-picker.d.ts +2 -0
- package/dist/tui/session-picker.js +32 -0
- 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/storage-warning.d.ts +2 -0
- package/dist/tui/storage-warning.js +35 -0
- 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-feedback-loop.js +2 -0
- 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.d.ts +1 -0
- package/dist/vascend/context-snapshot.js +8 -5
- package/dist/vascend/context-store-reader.d.ts +20 -0
- package/dist/vascend/context-store-reader.js +46 -0
- package/dist/vascend/context-window-compiler.d.ts +1 -0
- package/dist/vascend/context-window-compiler.js +1 -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 +52 -17
- 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 +22 -11
- package/dist/vascend/memory-packet.d.ts +2 -1
- package/dist/vascend/memory-packet.js +31 -44
- package/dist/vascend/memory-store.d.ts +1 -0
- package/dist/vascend/memory-store.js +12 -4
- package/dist/vascend/plan-store.d.ts +3 -1
- package/dist/vascend/plan-store.js +6 -4
- package/dist/vascend/room-memory.d.ts +13 -2
- package/dist/vascend/room-memory.js +48 -6
- 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 +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AgentEvent, Message, ToolCallPart } from "../core/types.js";
|
|
2
|
+
import { AgentSessions } from "./agent-sessions.js";
|
|
2
3
|
export type ReviewState = "running" | "ok" | "error" | "stopped" | "info";
|
|
3
4
|
export type ReviewKind = "tool" | "file" | "team" | "notice";
|
|
4
5
|
export interface ReviewChange {
|
|
@@ -27,9 +28,14 @@ export declare function reviewTitle(name: string): string;
|
|
|
27
28
|
export declare function callTarget(call: ToolCallPart): string;
|
|
28
29
|
export declare class ReviewStore {
|
|
29
30
|
private readonly capacity;
|
|
31
|
+
private readonly maxChars;
|
|
32
|
+
readonly sessions: AgentSessions;
|
|
30
33
|
private items;
|
|
34
|
+
private sizes;
|
|
35
|
+
private retainedChars;
|
|
31
36
|
private callIndex;
|
|
32
37
|
private actorText;
|
|
38
|
+
private rawActors;
|
|
33
39
|
private sequence;
|
|
34
40
|
private run;
|
|
35
41
|
private _revision;
|
|
@@ -37,7 +43,7 @@ export declare class ReviewStore {
|
|
|
37
43
|
private _running;
|
|
38
44
|
private _label;
|
|
39
45
|
private _goal;
|
|
40
|
-
constructor(capacity?: number);
|
|
46
|
+
constructor(capacity?: number, maxChars?: number);
|
|
41
47
|
get revision(): number;
|
|
42
48
|
get evicted(): number;
|
|
43
49
|
get running(): boolean;
|
|
@@ -57,4 +63,5 @@ export declare class ReviewStore {
|
|
|
57
63
|
private callId;
|
|
58
64
|
private notice;
|
|
59
65
|
private put;
|
|
66
|
+
private remove;
|
|
60
67
|
}
|
package/dist/tui/review-store.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { oneLine } from "./terminal-text.js";
|
|
2
|
+
import { AgentSessions } from "./agent-sessions.js";
|
|
3
|
+
import { agentLabel } from "./agent-label.js";
|
|
4
|
+
import { tr } from "./i18n.js";
|
|
5
|
+
import { runtimeError } from "./runtime-error.js";
|
|
2
6
|
const LABELS = {
|
|
3
7
|
read_file: "Lettura", list_dir: "Cartella", grep: "Ricerca", glob: "Ricerca file",
|
|
4
8
|
write_file: "Scrittura", edit_file: "Modifica", bash: "Comando", bash_bg: "Comando in background",
|
|
@@ -8,7 +12,17 @@ const LABELS = {
|
|
|
8
12
|
vascend_addrooms: "Nuove attività", vascend_status: "Lista attività",
|
|
9
13
|
kingdom_send: "Messaggio al team", kingdom_inbox: "Messaggi del team", kingdom_wait: "Attesa collaboratori",
|
|
10
14
|
};
|
|
11
|
-
export function reviewTitle(name) {
|
|
15
|
+
export function reviewTitle(name) {
|
|
16
|
+
return name === "bash_output" ? tr("Processo in background", "Background process") : LABELS[name] ?? name;
|
|
17
|
+
}
|
|
18
|
+
function textSize(value, seen = new Set()) {
|
|
19
|
+
if (typeof value === "string")
|
|
20
|
+
return value.length;
|
|
21
|
+
if (!value || typeof value !== "object" || seen.has(value))
|
|
22
|
+
return 0;
|
|
23
|
+
seen.add(value);
|
|
24
|
+
return Object.values(value).reduce((size, child) => size + textSize(child, seen), 0);
|
|
25
|
+
}
|
|
12
26
|
export function callTarget(call) {
|
|
13
27
|
const i = call.input;
|
|
14
28
|
return oneLine(String(i["path"] ?? i["command"] ?? i["pattern"] ?? i["query"] ??
|
|
@@ -18,9 +32,14 @@ export function callTarget(call) {
|
|
|
18
32
|
// della chat viene compattato. Nessuna lettura del filesystem dal renderer.
|
|
19
33
|
export class ReviewStore {
|
|
20
34
|
capacity;
|
|
35
|
+
maxChars;
|
|
36
|
+
sessions = new AgentSessions();
|
|
21
37
|
items = new Map();
|
|
38
|
+
sizes = new Map();
|
|
39
|
+
retainedChars = 0;
|
|
22
40
|
callIndex = new Map();
|
|
23
41
|
actorText = new Map();
|
|
42
|
+
rawActors = new Set();
|
|
24
43
|
sequence = 0;
|
|
25
44
|
run = 0;
|
|
26
45
|
_revision = 0;
|
|
@@ -28,17 +47,29 @@ export class ReviewStore {
|
|
|
28
47
|
_running = false;
|
|
29
48
|
_label = "Pronto";
|
|
30
49
|
_goal = "";
|
|
31
|
-
constructor(capacity = 2000) {
|
|
50
|
+
constructor(capacity = 2000, maxChars = 8_000_000) {
|
|
32
51
|
this.capacity = capacity;
|
|
52
|
+
this.maxChars = maxChars;
|
|
33
53
|
}
|
|
34
54
|
get revision() { return this._revision; }
|
|
35
55
|
get evicted() { return this._evicted; }
|
|
36
56
|
get running() { return this._running || [...this.items.values()].some(e => e.state === "running"); }
|
|
37
|
-
get label() {
|
|
57
|
+
get label() {
|
|
58
|
+
if (!this._running && this.running)
|
|
59
|
+
return tr("Collaboratori in esecuzione", "Workers running");
|
|
60
|
+
switch (this._label) {
|
|
61
|
+
case "Pronto": return tr("Pronto", "Ready");
|
|
62
|
+
case "Avvio": return tr("Avvio", "Starting");
|
|
63
|
+
case "Interrotto": return tr("Interrotto", "Interrupted");
|
|
64
|
+
case "In attesa del prossimo messaggio": return tr("In attesa del prossimo messaggio", "Waiting for the next message");
|
|
65
|
+
default: return this._label;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
38
68
|
get goal() { return this._goal; }
|
|
39
69
|
entries() { return [...this.items.values()]; }
|
|
40
70
|
get(id) { return this.items.get(id); }
|
|
41
71
|
begin(goal) {
|
|
72
|
+
this.sessions.begin(goal);
|
|
42
73
|
this.run += 1;
|
|
43
74
|
this._running = true;
|
|
44
75
|
this._label = "Avvio";
|
|
@@ -46,6 +77,7 @@ export class ReviewStore {
|
|
|
46
77
|
this._revision += 1;
|
|
47
78
|
}
|
|
48
79
|
finish(interrupted = false) {
|
|
80
|
+
this.sessions.finish();
|
|
49
81
|
for (const entry of this.items.values()) {
|
|
50
82
|
if (entry.state === "running" && entry.actor === "Talos")
|
|
51
83
|
this.put({ ...entry, state: "stopped", endedAt: Date.now() });
|
|
@@ -55,9 +87,13 @@ export class ReviewStore {
|
|
|
55
87
|
this._revision += 1;
|
|
56
88
|
}
|
|
57
89
|
reset(history = []) {
|
|
90
|
+
this.sessions.reset();
|
|
58
91
|
this.items.clear();
|
|
92
|
+
this.sizes.clear();
|
|
93
|
+
this.retainedChars = 0;
|
|
59
94
|
this.callIndex.clear();
|
|
60
95
|
this.actorText.clear();
|
|
96
|
+
this.rawActors.clear();
|
|
61
97
|
this.sequence = 0;
|
|
62
98
|
this.run = 0;
|
|
63
99
|
this._evicted = 0;
|
|
@@ -87,6 +123,11 @@ export class ReviewStore {
|
|
|
87
123
|
this.put({ ...entry, change });
|
|
88
124
|
}
|
|
89
125
|
record(event, at = Date.now(), actor = "Talos") {
|
|
126
|
+
// Host summaries must not overwrite full raw tool output or duplicate messages.
|
|
127
|
+
if (event.type === "kingdom" && (event.phase === "tool" || event.phase === "say" || event.phase === "inbox")
|
|
128
|
+
&& this.rawActors.has(event.slug))
|
|
129
|
+
return;
|
|
130
|
+
this.sessions.record(event, at, actor);
|
|
90
131
|
switch (event.type) {
|
|
91
132
|
case "status":
|
|
92
133
|
this._label = oneLine(event.label);
|
|
@@ -132,7 +173,7 @@ export class ReviewStore {
|
|
|
132
173
|
break;
|
|
133
174
|
}
|
|
134
175
|
case "error":
|
|
135
|
-
this.notice("Errore", event.message, "error", at, actor);
|
|
176
|
+
this.notice(tr("Errore", "Error"), runtimeError(event.message), "error", at, actor);
|
|
136
177
|
break;
|
|
137
178
|
case "compacted":
|
|
138
179
|
this.notice("Contesto riassunto", `Stima locale: ${event.tokensBefore} → ${event.tokensAfter} token.\n${event.anchors?.join("\n") ?? ""}`, "info", at);
|
|
@@ -149,6 +190,9 @@ export class ReviewStore {
|
|
|
149
190
|
}
|
|
150
191
|
}
|
|
151
192
|
recordActor(actor, event) {
|
|
193
|
+
this.rawActors.add(actor);
|
|
194
|
+
if (event.type === "status" || event.type === "text")
|
|
195
|
+
this.sessions.record(event, Date.now(), actor);
|
|
152
196
|
if (event.type === "status") {
|
|
153
197
|
this.put({ id: `status:${this.run}:${actor}`, kind: "notice", actor, title: "Stato",
|
|
154
198
|
target: oneLine(event.label), output: event.label, state: "info", startedAt: Date.now() });
|
|
@@ -166,17 +210,16 @@ export class ReviewStore {
|
|
|
166
210
|
if (text?.trim())
|
|
167
211
|
this.notice("Aggiornamento", text, "info", Date.now(), actor);
|
|
168
212
|
this.actorText.delete(actor);
|
|
169
|
-
this.
|
|
213
|
+
this.remove(`stream:${this.run}:${actor}`);
|
|
170
214
|
}
|
|
171
215
|
if (event.type === "turn_start" || event.type === "done" || event.type === "error") {
|
|
172
216
|
this.record({ type: "kingdom", phase: "vassal", slug: actor,
|
|
173
217
|
state: event.type === "turn_start" ? "active" : event.type === "done" ? "done" : "error",
|
|
174
|
-
...(event.type === "error" ? { label: event.message } : {}) });
|
|
218
|
+
...(event.type === "error" ? { label: runtimeError(event.message) } : {}) });
|
|
175
219
|
}
|
|
176
220
|
if (event.type === "done" || event.type === "error")
|
|
177
221
|
this.finishActor(actor);
|
|
178
|
-
|
|
179
|
-
this.record(event, Date.now(), actor);
|
|
222
|
+
this.record(event, Date.now(), actor);
|
|
180
223
|
}
|
|
181
224
|
recordKingdom(e, at) {
|
|
182
225
|
if (e.phase === "start") {
|
|
@@ -227,7 +270,7 @@ export class ReviewStore {
|
|
|
227
270
|
}
|
|
228
271
|
else if (e.phase === "say" || e.phase === "note" || e.phase === "notice" || e.phase === "message" || e.phase === "inbox") {
|
|
229
272
|
const actor = "slug" in e ? e.slug : "from" in e ? e.from : "Talos";
|
|
230
|
-
this.notice(e.phase === "message" ? `${actor} → ${e.to}` : e.phase === "inbox" ? `Messaggio ${e.state === "read" ? "letto" : "in coda"}` : "Aggiornamento", e.text, "info", at, actor);
|
|
273
|
+
this.notice(e.phase === "message" ? `${agentLabel(actor)} → ${agentLabel(e.to)}` : e.phase === "inbox" ? `Messaggio ${e.state === "read" ? "letto" : "in coda"}` : "Aggiornamento", e.text, "info", at, actor);
|
|
231
274
|
}
|
|
232
275
|
else if (e.phase === "task") {
|
|
233
276
|
const id = `task:${this.run}:${e.slug}:${e.workstreamId}:${e.taskRef}`;
|
|
@@ -254,17 +297,27 @@ export class ReviewStore {
|
|
|
254
297
|
this.put({ id: `notice:${++this.sequence}`, kind: "notice", title, target: oneLine(output).slice(0, 200), actor, state, output, startedAt: at });
|
|
255
298
|
}
|
|
256
299
|
put(entry) {
|
|
300
|
+
const size = textSize(entry);
|
|
301
|
+
this.retainedChars += size - (this.sizes.get(entry.id) ?? 0);
|
|
302
|
+
this.sizes.set(entry.id, size);
|
|
257
303
|
this.items.set(entry.id, entry);
|
|
258
|
-
|
|
304
|
+
while (this.items.size > this.capacity || this.retainedChars > this.maxChars) {
|
|
259
305
|
const oldest = [...this.items.values()].find(e => e.state !== "running");
|
|
260
306
|
if (oldest) {
|
|
261
|
-
this.
|
|
307
|
+
this.remove(oldest.id);
|
|
262
308
|
for (const [key, id] of this.callIndex)
|
|
263
309
|
if (id === oldest.id)
|
|
264
310
|
this.callIndex.delete(key);
|
|
265
311
|
this._evicted += 1;
|
|
266
312
|
}
|
|
313
|
+
else
|
|
314
|
+
break;
|
|
267
315
|
}
|
|
268
316
|
this._revision += 1;
|
|
269
317
|
}
|
|
318
|
+
remove(id) {
|
|
319
|
+
this.retainedChars -= this.sizes.get(id) ?? 0;
|
|
320
|
+
this.sizes.delete(id);
|
|
321
|
+
this.items.delete(id);
|
|
322
|
+
}
|
|
270
323
|
}
|
package/dist/tui/review-team.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { agentLabel } from "./agent-label.js";
|
|
1
2
|
// Proiezione del registro: una riga stabile per agente, non una per evento.
|
|
2
3
|
export function teamEntries(store) {
|
|
3
4
|
const groups = new Map();
|
|
@@ -19,9 +20,9 @@ export function teamEntries(store) {
|
|
|
19
20
|
const waiting = state === "running" && status && /attes|conferm|permess|domand/i.test(status.target)
|
|
20
21
|
&& (status.startedAt ?? 0) >= (latest.endedAt ?? latest.startedAt ?? 0);
|
|
21
22
|
const activity = (waiting ? status.target : "") || current || (state !== "running" ? lifecycle?.output : "") || `${latest.title}: ${latest.target}`;
|
|
22
|
-
return { id: `agent:${actor}`, actor, kind: "team", title: actor,
|
|
23
|
-
state, target: `${actor} · ${state === "running" ? "in corso" : state === "ok" ? "concluso" : state === "error" ? "errore" : state === "stopped" ? "interrotto" : lifecycle?.output?.startsWith("In coda") ? "in coda" : "stato non disponibile"} · ${activity}`,
|
|
24
|
-
output: `Incarico: ${goal}\nRuolo: ${lifecycle?.role ?? "non disponibile"}\nRisponde a: ${lifecycle?.parent ?? "
|
|
23
|
+
return { id: `agent:${actor}`, actor, kind: "team", title: agentLabel(actor),
|
|
24
|
+
state, target: `${agentLabel(actor)} · ${state === "running" ? "in corso" : state === "ok" ? "concluso" : state === "error" ? "errore" : state === "stopped" ? "interrotto" : lifecycle?.output?.startsWith("In coda") ? "in coda" : "stato non disponibile"} · ${activity}`,
|
|
25
|
+
output: `Incarico: ${goal}\nRuolo: ${lifecycle?.role ?? "non disponibile"}\nRisponde a: ${agentLabel(lifecycle?.parent ?? "main")}\nAttività: ${activity}\n${active.length} tool attivi · ${files.size} file · ${problems.length} problemi\nEventi disponibili: ${entries.length}`,
|
|
25
26
|
startedAt: lifecycle?.startedAt, endedAt: lifecycle?.endedAt };
|
|
26
27
|
});
|
|
27
28
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { tr } from "./i18n.js";
|
|
2
|
+
export function isUserInterruption(message) {
|
|
3
|
+
return /^(?:interrotto|interrupted|richiesta interrotta|request interrupted|the operation was aborted\.?|this operation was aborted\.?)$/i.test(message.trim());
|
|
4
|
+
}
|
|
5
|
+
// Localize Talos-owned runtime diagnostics at the display boundary, including
|
|
6
|
+
// events from existing sessions. Unknown provider errors retain their details.
|
|
7
|
+
export function runtimeError(message) {
|
|
8
|
+
switch (message) {
|
|
9
|
+
case "interrotto": return tr("interrotto", "Interrupted");
|
|
10
|
+
case "Il contesto supera la finestra del modello anche dopo la compattazione. La sessione resta recuperabile.": return tr("Il contesto supera la finestra del modello anche dopo la compattazione. La sessione resta recuperabile.", "The context exceeds the model window even after compaction. The session can still be recovered.");
|
|
11
|
+
case "Il provider ha interrotto il turno senza fornire dettagli.": return tr("Il provider ha interrotto il turno senza fornire dettagli.", "The provider interrupted the turn without providing details.");
|
|
12
|
+
case "Il provider ha terminato con tool_use senza fornire una tool call valida. Il task non e' stato completato; riprova mantenendo questa sessione.": return tr("Il provider ha terminato con tool_use senza fornire una tool call valida. Il task non e' stato completato; riprova mantenendo questa sessione.", "The provider ended with tool_use without a valid tool call. The task was not completed; retry in this session.");
|
|
13
|
+
case "Il provider ha chiuso il turno senza una risposta finale. Il task non e' stato dichiarato completato; riprova mantenendo questa sessione.": return tr("Il provider ha chiuso il turno senza una risposta finale. Il task non e' stato dichiarato completato; riprova mantenendo questa sessione.", "The provider ended the turn without a final response. The task was not marked complete; retry in this session.");
|
|
14
|
+
case "La delega richiesta non e' stata autorizzata; il task non viene dichiarato completato.": return tr("La delega richiesta non e' stata autorizzata; il task non viene dichiarato completato.", "The requested delegation was not authorized; the task is not marked complete.");
|
|
15
|
+
}
|
|
16
|
+
const turns = /^pausa al tetto di (\d+) turni per questo giro \(TALOS_MAX_TURNS per alzarlo\); la validazione del piano riprende le attivita rimaste$/.exec(message);
|
|
17
|
+
if (turns)
|
|
18
|
+
return tr("Pausa al limite di {count} turni per questo giro (TALOS_MAX_TURNS per alzarlo); la validazione del piano riprende le attività rimaste.", "Paused at the limit of {count} turns for this run (increase TALOS_MAX_TURNS to raise it); plan validation resumes the remaining tasks.", { count: turns[1] });
|
|
19
|
+
const output = /^Risposta incompleta: raggiunto il limite di output dopo (\d+) continuazion[ei]\. Il task non e' stato marcato completato; riprendi dalla stessa sessione\.$/.exec(message);
|
|
20
|
+
if (output)
|
|
21
|
+
return tr("Risposta incompleta: limite di output raggiunto. Continuazioni eseguite: {count}. Il task non è stato marcato completato; riprendi dalla stessa sessione.", "Incomplete response: output limit reached. Continuations used: {count}. The task was not marked complete; resume in the same session.", { count: output[1] });
|
|
22
|
+
const tasks = /^Task incompleto: restano (.+)\. Il turno e' stato fermato senza dichiarare un falso completamento; riprendilo nella stessa sessione\.$/.exec(message);
|
|
23
|
+
if (tasks)
|
|
24
|
+
return tr("Task incompleto: restano {tasks}. Il turno è stato fermato senza dichiarare un falso completamento; riprendilo nella stessa sessione.", "Incomplete task: {tasks} remain. The turn stopped without claiming completion; resume in the same session.", { tasks: tasks[1] });
|
|
25
|
+
return message;
|
|
26
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ScrollbackLine } from "./native-scrollback.js";
|
|
2
|
+
export declare class ScrollbackArchive implements Iterable<ScrollbackLine> {
|
|
3
|
+
private readonly maxChars;
|
|
4
|
+
private rows;
|
|
5
|
+
private chars;
|
|
6
|
+
private directory?;
|
|
7
|
+
private fd?;
|
|
8
|
+
private bytes;
|
|
9
|
+
constructor(maxChars?: number);
|
|
10
|
+
get retainedChars(): number;
|
|
11
|
+
push(line: ScrollbackLine): void;
|
|
12
|
+
private write;
|
|
13
|
+
private spill;
|
|
14
|
+
[Symbol.iterator](): Iterator<ScrollbackLine>;
|
|
15
|
+
clear(): void;
|
|
16
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { closeSync, mkdtempSync, openSync, readSync, rmdirSync, unlinkSync, writeSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { StringDecoder } from "node:string_decoder";
|
|
5
|
+
// This extra copy is used for resize, not model context. Spill old rows to
|
|
6
|
+
// disk instead of retaining another complete transcript in the JavaScript heap.
|
|
7
|
+
export class ScrollbackArchive {
|
|
8
|
+
maxChars;
|
|
9
|
+
rows = [];
|
|
10
|
+
chars = 0;
|
|
11
|
+
directory;
|
|
12
|
+
fd;
|
|
13
|
+
bytes = 0;
|
|
14
|
+
constructor(maxChars = 1_000_000) {
|
|
15
|
+
this.maxChars = maxChars;
|
|
16
|
+
}
|
|
17
|
+
get retainedChars() { return this.chars; }
|
|
18
|
+
push(line) {
|
|
19
|
+
if (this.rows.length >= 5000 || this.chars + line.text.length > this.maxChars)
|
|
20
|
+
this.spill();
|
|
21
|
+
if (line.text.length > this.maxChars)
|
|
22
|
+
this.write(line);
|
|
23
|
+
else {
|
|
24
|
+
this.rows.push(line);
|
|
25
|
+
this.chars += line.text.length;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
write(line) {
|
|
29
|
+
if (this.fd === undefined) {
|
|
30
|
+
this.directory = mkdtempSync(join(tmpdir(), "talos-scrollback-"));
|
|
31
|
+
this.fd = openSync(join(this.directory, "rows.jsonl"), "w+", 0o600);
|
|
32
|
+
}
|
|
33
|
+
const data = Buffer.from(JSON.stringify(line) + "\n");
|
|
34
|
+
let offset = 0;
|
|
35
|
+
while (offset < data.length) {
|
|
36
|
+
const written = writeSync(this.fd, data, offset, data.length - offset, this.bytes);
|
|
37
|
+
if (!written)
|
|
38
|
+
throw new Error("Unable to write terminal scrollback");
|
|
39
|
+
offset += written;
|
|
40
|
+
this.bytes += written;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
spill() {
|
|
44
|
+
for (const row of this.rows)
|
|
45
|
+
this.write(row);
|
|
46
|
+
this.rows = [];
|
|
47
|
+
this.chars = 0;
|
|
48
|
+
}
|
|
49
|
+
*[Symbol.iterator]() {
|
|
50
|
+
if (this.fd !== undefined) {
|
|
51
|
+
const buffer = Buffer.allocUnsafe(64 * 1024);
|
|
52
|
+
const decoder = new StringDecoder("utf8");
|
|
53
|
+
let position = 0;
|
|
54
|
+
let pending = "";
|
|
55
|
+
while (position < this.bytes) {
|
|
56
|
+
const size = readSync(this.fd, buffer, 0, Math.min(buffer.length, this.bytes - position), position);
|
|
57
|
+
if (!size)
|
|
58
|
+
throw new Error("Unable to read terminal scrollback");
|
|
59
|
+
position += size;
|
|
60
|
+
pending += decoder.write(buffer.subarray(0, size));
|
|
61
|
+
let start = 0;
|
|
62
|
+
let end;
|
|
63
|
+
while ((end = pending.indexOf("\n", start)) >= 0) {
|
|
64
|
+
yield JSON.parse(pending.slice(start, end));
|
|
65
|
+
start = end + 1;
|
|
66
|
+
}
|
|
67
|
+
pending = pending.slice(start);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
yield* this.rows;
|
|
71
|
+
}
|
|
72
|
+
clear() {
|
|
73
|
+
this.rows = [];
|
|
74
|
+
this.chars = 0;
|
|
75
|
+
this.bytes = 0;
|
|
76
|
+
if (this.fd !== undefined) {
|
|
77
|
+
closeSync(this.fd);
|
|
78
|
+
this.fd = undefined;
|
|
79
|
+
}
|
|
80
|
+
if (this.directory) {
|
|
81
|
+
const directory = this.directory;
|
|
82
|
+
this.directory = undefined;
|
|
83
|
+
try {
|
|
84
|
+
unlinkSync(join(directory, "rows.jsonl"));
|
|
85
|
+
rmdirSync(directory);
|
|
86
|
+
}
|
|
87
|
+
catch { /* A scanner may hold the disposable cache open on Windows. */ }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -57,7 +57,7 @@ export class SelectorMouseInput {
|
|
|
57
57
|
}
|
|
58
58
|
export function selectorMouseIndex(o) {
|
|
59
59
|
const top = o.rows - Math.min(o.renderedRows, o.rows - 1) + 1;
|
|
60
|
-
const row = o.y - top - 1;
|
|
60
|
+
const row = o.y - top - (o.headerRows ?? 1);
|
|
61
61
|
if (o.x < 1 || o.x > o.columns + 1 || row < 0 || row >= Math.min(o.count, o.pageSize))
|
|
62
62
|
return null;
|
|
63
63
|
const start = Math.max(0, Math.min(o.index - Math.floor(o.pageSize / 2), o.count - o.pageSize));
|
package/dist/tui/selector.d.ts
CHANGED
|
@@ -6,6 +6,12 @@ export interface SelectOption<T> {
|
|
|
6
6
|
readonly group?: string;
|
|
7
7
|
readonly hint?: string;
|
|
8
8
|
readonly value: T;
|
|
9
|
+
readonly age?: string;
|
|
10
|
+
readonly modelInfo?: {
|
|
11
|
+
readonly context?: number;
|
|
12
|
+
readonly reasoning?: boolean;
|
|
13
|
+
readonly cost: Readonly<Record<string, number>>;
|
|
14
|
+
};
|
|
9
15
|
}
|
|
10
16
|
interface SelectorControl {
|
|
11
17
|
pause(): void;
|
|
@@ -14,16 +20,20 @@ interface SelectorControl {
|
|
|
14
20
|
setOverlay(lines: string[] | null): void;
|
|
15
21
|
}
|
|
16
22
|
interface SelectorOptions<T> {
|
|
23
|
+
readonly signal?: AbortSignal;
|
|
17
24
|
readonly title: string;
|
|
18
25
|
readonly hint?: string;
|
|
19
26
|
readonly options: readonly SelectOption<T>[];
|
|
20
27
|
readonly current?: T;
|
|
21
28
|
readonly currentKey?: string;
|
|
29
|
+
readonly onCycleMode?: () => SelectOption<T> | undefined;
|
|
22
30
|
readonly theme: TuiTheme;
|
|
23
31
|
readonly wide?: boolean;
|
|
24
32
|
readonly question?: boolean;
|
|
25
33
|
readonly selectedDetailsOnly?: boolean;
|
|
26
34
|
readonly mouse?: boolean;
|
|
35
|
+
readonly sessionList?: boolean;
|
|
36
|
+
readonly modelList?: boolean;
|
|
27
37
|
}
|
|
28
38
|
export interface SelectorRenderOptions<T> extends SelectorOptions<T> {
|
|
29
39
|
readonly index: number;
|
|
@@ -33,6 +43,7 @@ export interface SelectorRenderOptions<T> extends SelectorOptions<T> {
|
|
|
33
43
|
readonly totalCount?: number;
|
|
34
44
|
readonly details?: boolean;
|
|
35
45
|
readonly detailOffset?: number;
|
|
46
|
+
readonly rows?: number;
|
|
36
47
|
}
|
|
37
48
|
export declare function pickerPageSize(rows: number, fullHeight?: boolean): number;
|
|
38
49
|
export declare function filterOptions<T extends {
|
package/dist/tui/selector.js
CHANGED
|
@@ -6,6 +6,8 @@ import { tr } from "./i18n.js";
|
|
|
6
6
|
import { SelectorMouseInput, selectorMouseIndex } from "./selector-mouse.js";
|
|
7
7
|
import { fitLine, oneLine, padLine, plainText, terminalWidth, wrapText } from "./terminal-text.js";
|
|
8
8
|
import { renderQuestionChoices } from "./question.js";
|
|
9
|
+
import { renderSessionPicker } from "./session-picker.js";
|
|
10
|
+
import { renderModelPicker } from "./model-picker.js";
|
|
9
11
|
export function pickerPageSize(rows, fullHeight = false) {
|
|
10
12
|
const available = Math.max(1, Math.floor(rows) - 6);
|
|
11
13
|
return Math.min(available, fullHeight ? 26 : 7);
|
|
@@ -42,6 +44,10 @@ function detailLines(opts, option, width) {
|
|
|
42
44
|
];
|
|
43
45
|
}
|
|
44
46
|
export function renderSelector(opts) {
|
|
47
|
+
if (opts.modelList && !opts.details)
|
|
48
|
+
return renderModelPicker(opts);
|
|
49
|
+
if (opts.sessionList && !opts.details)
|
|
50
|
+
return renderSessionPicker(opts);
|
|
45
51
|
const t = opts.theme;
|
|
46
52
|
const width = selectorWidth(opts.columns, opts.wide);
|
|
47
53
|
const page = Math.max(1, opts.pageSize);
|
|
@@ -109,6 +115,8 @@ export function renderSelector(opts) {
|
|
|
109
115
|
return lines;
|
|
110
116
|
}
|
|
111
117
|
export async function selectOption(opts) {
|
|
118
|
+
if (opts.signal?.aborted)
|
|
119
|
+
return null;
|
|
112
120
|
if (!stdin.isTTY || !stdout.isTTY || typeof stdin.setRawMode !== "function") {
|
|
113
121
|
opts.ctl.write(opts.theme.bold(`\n ${opts.title}\n`));
|
|
114
122
|
if (opts.hint)
|
|
@@ -132,7 +140,8 @@ export async function selectOption(opts) {
|
|
|
132
140
|
let renderedRows = 0;
|
|
133
141
|
const wasRaw = stdin.isRaw;
|
|
134
142
|
const wasPaused = stdin.isPaused();
|
|
135
|
-
const pageSize = () =>
|
|
143
|
+
const pageSize = () => opts.modelList ? Math.max(1, (stdout.rows || 24) - 13)
|
|
144
|
+
: opts.sessionList ? Math.max(1, (stdout.rows || 24) - 8) : pickerPageSize(stdout.rows || 24, opts.fullHeight);
|
|
136
145
|
const detailMax = () => Math.max(0, detailLines(opts, filtered[index], selectorWidth(opts.terminalColumns(), opts.wide) - 2).length - pageSize());
|
|
137
146
|
const applyFilter = () => {
|
|
138
147
|
const previous = filtered[index];
|
|
@@ -152,7 +161,7 @@ export async function selectOption(opts) {
|
|
|
152
161
|
detailOffset = Math.min(detailOffset, detailMax());
|
|
153
162
|
const lines = renderSelector({ ...opts, options: filtered, index,
|
|
154
163
|
pageSize: pageSize(), columns: opts.terminalColumns(), query: opts.filterable ? query : undefined,
|
|
155
|
-
totalCount: opts.options.length, details, detailOffset,
|
|
164
|
+
totalCount: opts.options.length, details, detailOffset, rows: stdout.rows || 24,
|
|
156
165
|
});
|
|
157
166
|
renderedRows = lines.length;
|
|
158
167
|
opts.ctl.setOverlay(lines);
|
|
@@ -165,6 +174,7 @@ export async function selectOption(opts) {
|
|
|
165
174
|
if (settled)
|
|
166
175
|
return;
|
|
167
176
|
settled = true;
|
|
177
|
+
opts.signal?.removeEventListener("abort", abort);
|
|
168
178
|
stdin.off("data", onData);
|
|
169
179
|
decoder.dispose();
|
|
170
180
|
keys.off("keypress", onKeypress);
|
|
@@ -190,7 +200,8 @@ export async function selectOption(opts) {
|
|
|
190
200
|
if (event.button !== 0 || details || opts.question)
|
|
191
201
|
return;
|
|
192
202
|
const hit = selectorMouseIndex({ y: event.y, x: event.x, rows: stdout.rows || 24,
|
|
193
|
-
columns: selectorWidth(opts.terminalColumns(), opts.wide), renderedRows,
|
|
203
|
+
columns: opts.modelList ? Math.max(1, opts.terminalColumns() - 2) : selectorWidth(opts.terminalColumns(), opts.wide), renderedRows,
|
|
204
|
+
headerRows: opts.modelList ? 4 : 1,
|
|
194
205
|
count: filtered.length, index, pageSize: pageSize() });
|
|
195
206
|
if (hit === null)
|
|
196
207
|
return;
|
|
@@ -205,6 +216,14 @@ export async function selectOption(opts) {
|
|
|
205
216
|
const utf8 = new StringDecoder("utf8");
|
|
206
217
|
const onData = (data) => decoder.push(typeof data === "string" ? data : utf8.write(data));
|
|
207
218
|
const onKeypress = (chunk, key) => {
|
|
219
|
+
if (key.shift && key.name === "tab" && opts.onCycleMode) {
|
|
220
|
+
const selected = opts.onCycleMode();
|
|
221
|
+
if (selected)
|
|
222
|
+
cleanup(selected);
|
|
223
|
+
else
|
|
224
|
+
draw();
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
208
227
|
if (key.name === "return") {
|
|
209
228
|
cleanup(filtered[index] ?? null);
|
|
210
229
|
return;
|
|
@@ -288,12 +307,17 @@ export async function selectOption(opts) {
|
|
|
288
307
|
else if (key.name === "q")
|
|
289
308
|
cleanup(null);
|
|
290
309
|
};
|
|
310
|
+
const abort = () => cleanup(null);
|
|
291
311
|
opts.ctl.pause();
|
|
292
312
|
stdin.setRawMode(true);
|
|
293
313
|
stdin.resume();
|
|
294
314
|
stdin.on("data", onData);
|
|
295
315
|
keys.on("keypress", onKeypress);
|
|
296
316
|
stdout.on("resize", draw);
|
|
297
|
-
|
|
317
|
+
opts.signal?.addEventListener("abort", abort, { once: true });
|
|
318
|
+
if (opts.signal?.aborted)
|
|
319
|
+
abort();
|
|
320
|
+
else
|
|
321
|
+
draw();
|
|
298
322
|
});
|
|
299
323
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { UserInbox } from "../core/user-inbox.js";
|
|
2
|
+
import type { ContentPart } from "../core/types.js";
|
|
3
|
+
import type { AgentSession } from "./agent-sessions.js";
|
|
4
|
+
import type { TuiTheme } from "./branding.js";
|
|
5
|
+
import { buildUsageFooter } from "./usage-footer.js";
|
|
6
|
+
export declare function workerFooter(session: AgentSession, width: number, theme: TuiTheme, usage?: Parameters<typeof buildUsageFooter>[2], providerId?: (model: string) => string): readonly string[];
|
|
7
|
+
export declare function deleteWorker(session: AgentSession): {
|
|
8
|
+
ok: boolean;
|
|
9
|
+
error?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function stopWorker(session: AgentSession): {
|
|
12
|
+
ok: boolean;
|
|
13
|
+
error?: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function bindWorkerInbox(session: AgentSession, inbox: UserInbox): {
|
|
16
|
+
ok: boolean;
|
|
17
|
+
error?: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function wakeWorker(session: AgentSession): {
|
|
20
|
+
ok: boolean;
|
|
21
|
+
error?: string;
|
|
22
|
+
};
|
|
23
|
+
export declare function sendWorker(session: AgentSession, text: string, parts: readonly ContentPart[], immediate: boolean): {
|
|
24
|
+
ok: boolean;
|
|
25
|
+
error?: string;
|
|
26
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { kingdomLive } from "../vascend/kingdom-live.js";
|
|
2
|
+
import { compactContextTokens } from "./context-bar.js";
|
|
3
|
+
import { buildUsageFooter } from "./usage-footer.js";
|
|
4
|
+
import { tr } from "./i18n.js";
|
|
5
|
+
import { fitLine } from "./terminal-text.js";
|
|
6
|
+
import { ContextMeter } from "./context-meter.js";
|
|
7
|
+
const meters = new WeakMap();
|
|
8
|
+
export function workerFooter(session, width, theme, usage = { limits: new Map(), incomplete: false, missing: 0, unsaved: false }, providerId = model => model.split("/")[0] ?? "") {
|
|
9
|
+
const source = kingdomLive.contextSource(session.kingdomId ?? "", session.actor);
|
|
10
|
+
let reading;
|
|
11
|
+
if (source) {
|
|
12
|
+
let entry = meters.get(source.session);
|
|
13
|
+
if (!entry) {
|
|
14
|
+
entry = { meter: new ContextMeter() };
|
|
15
|
+
meters.set(source.session, entry);
|
|
16
|
+
}
|
|
17
|
+
const input = { ...source, env: source.env ?? process.env };
|
|
18
|
+
if (session.context && entry.observed !== session.context) {
|
|
19
|
+
entry.meter.observe(input, session.context);
|
|
20
|
+
entry.observed = session.context;
|
|
21
|
+
}
|
|
22
|
+
reading = entry.meter.read(input);
|
|
23
|
+
}
|
|
24
|
+
const ctx = reading ?? session.context;
|
|
25
|
+
const model = source?.config.model ?? session.context?.model ?? session.actor;
|
|
26
|
+
const footer = buildUsageFooter({ model, cwd: source?.config.cwd ?? "", width,
|
|
27
|
+
effort: source?.config.effort, fast: source?.config.fast,
|
|
28
|
+
contextTokens: ctx?.tokens, contextWindow: ctx?.window, contextArchive: reading?.archived,
|
|
29
|
+
}, theme, usage, providerId(model), { order: [] });
|
|
30
|
+
return [...footer,
|
|
31
|
+
fitLine(theme.muted(` ${tr("Consumo cumulativo", "Cumulative usage")}: ${session.usageMissing ? "≥" : ""}${session.usageKnown
|
|
32
|
+
? compactContextTokens(session.inputTokens + session.outputTokens) : "—"} token`), width - 1)];
|
|
33
|
+
}
|
|
34
|
+
// Release works for both active and idle workers; persisted history is kept.
|
|
35
|
+
export function deleteWorker(session) {
|
|
36
|
+
if (session.id === "main")
|
|
37
|
+
return { ok: false, error: tr("La sessione principale non si elimina", "Cannot delete the main session") };
|
|
38
|
+
if (session.kingdomId)
|
|
39
|
+
kingdomLive.release(session.kingdomId, session.actor);
|
|
40
|
+
return { ok: true };
|
|
41
|
+
}
|
|
42
|
+
export function stopWorker(session) {
|
|
43
|
+
if (!session.kingdomId)
|
|
44
|
+
return { ok: false, error: tr("Collaboratore non attivo", "Worker inactive") };
|
|
45
|
+
return kingdomLive.stop(session.kingdomId, session.actor);
|
|
46
|
+
}
|
|
47
|
+
export function bindWorkerInbox(session, inbox) {
|
|
48
|
+
return kingdomLive.bindInbox(session.kingdomId ?? "", session.actor, inbox);
|
|
49
|
+
}
|
|
50
|
+
export function wakeWorker(session) {
|
|
51
|
+
return kingdomLive.wake(session.kingdomId ?? "", session.actor);
|
|
52
|
+
}
|
|
53
|
+
// Session-scoped commands cannot silently fall through to the main session.
|
|
54
|
+
// Global display/preferences commands are still handled by the host explicitly.
|
|
55
|
+
export function sendWorker(session, text, parts, immediate) {
|
|
56
|
+
if (!session.kingdomId)
|
|
57
|
+
return { ok: false, error: tr("Collaboratore non attivo", "Worker inactive") };
|
|
58
|
+
const compact = /^\/compact(?:\s+([\s\S]*))?\s*$/.exec(text.trim());
|
|
59
|
+
if (compact)
|
|
60
|
+
return kingdomLive.compact(session.kingdomId, session.actor, compact[1]);
|
|
61
|
+
if (text.trimStart().startsWith("/"))
|
|
62
|
+
return { ok: false,
|
|
63
|
+
error: tr("Comando non disponibile per questa sessione", "Command unavailable for this session") };
|
|
64
|
+
return kingdomLive.deliver(session.kingdomId, session.actor, text, undefined, parts, immediate);
|
|
65
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare class SessionNamingNotice {
|
|
2
|
+
private readonly refresh;
|
|
3
|
+
private title;
|
|
4
|
+
private startedAt;
|
|
5
|
+
private pending;
|
|
6
|
+
private timer?;
|
|
7
|
+
constructor(refresh: () => void);
|
|
8
|
+
show(title: string): void;
|
|
9
|
+
start(): void;
|
|
10
|
+
finish(title: string): void;
|
|
11
|
+
lines(now?: number): readonly string[];
|
|
12
|
+
line(now?: number): string;
|
|
13
|
+
clear(): void;
|
|
14
|
+
}
|