@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
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { sanitizeText } from "../core/text-sanitize.js";
|
|
2
|
-
import { listMemoryScopes
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { listMemoryScopes } from "./memory-store.js";
|
|
3
|
+
import { ContextStoreReader } from "./context-store-reader.js";
|
|
4
|
+
import { packetEventsWithoutMirrors } from "./context-packet-mirrors.js";
|
|
5
|
+
import { visionCompleteness } from "./vision.js";
|
|
6
6
|
import { listContextMemoryScopes } from "./context-fabric.js";
|
|
7
|
-
export function buildMemoryPacket(input) {
|
|
7
|
+
export function buildMemoryPacket(input, reader = new ContextStoreReader(input.sessionDir)) {
|
|
8
8
|
const maxChars = input.maxChars && input.maxChars > 0 ? input.maxChars : 12_000;
|
|
9
9
|
const recentLimit = input.recentLimit && input.recentLimit > 0 ? input.recentLimit : 10;
|
|
10
10
|
const projectScopeLimit = input.projectScopeLimit && input.projectScopeLimit > 0 ? input.projectScopeLimit : 6;
|
|
11
|
-
const rooms =
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
11
|
+
const rooms = selectFrontierRooms(reader.rooms(input.scopeId));
|
|
12
|
+
const localPlan = reader.plan(input.scopeId);
|
|
13
|
+
const castles = (!input.planScopeId || input.planScopeId === input.scopeId
|
|
14
|
+
? localPlan : reader.plan(input.planScopeId)) ?? [];
|
|
15
|
+
const visions = reader.visions(input.scopeId);
|
|
15
16
|
const allowedScopes = !input.projectScopes && input.projectKey
|
|
16
17
|
? new Set(listContextMemoryScopes(input.sessionDir, input.projectKey))
|
|
17
18
|
: null;
|
|
@@ -19,10 +20,18 @@ export function buildMemoryPacket(input) {
|
|
|
19
20
|
excludeScope: input.scopeId,
|
|
20
21
|
limit: allowedScopes ? 10_000 : projectScopeLimit,
|
|
21
22
|
}).filter((scope) => !allowedScopes || allowedScopes.has(scope)).slice(0, projectScopeLimit);
|
|
22
|
-
const projectRooms =
|
|
23
|
-
const projectCastles =
|
|
24
|
-
const projectVisions =
|
|
25
|
-
const
|
|
23
|
+
const projectRooms = projectScopes.flatMap(scopeId => reader.rooms(scopeId).slice(-2).map(value => ({ scopeId, value }))).slice(0, 8);
|
|
24
|
+
const projectCastles = projectScopes.flatMap(scopeId => (reader.plan(scopeId) ?? []).slice(0, 2).map(value => ({ scopeId, value }))).slice(0, 8);
|
|
25
|
+
const projectVisions = projectScopes.flatMap(scopeId => reader.visions(scopeId).slice(0, 2).map(value => ({ scopeId, value }))).slice(0, 5);
|
|
26
|
+
const localEvents = reader.events(input.scopeId);
|
|
27
|
+
const scopedEvents = projectScopes.flatMap(scopeId => reader.events(scopeId).map(value => ({ scopeId, value })));
|
|
28
|
+
const allEvents = [...localEvents.map(value => ({ scopeId: input.scopeId, value })), ...scopedEvents];
|
|
29
|
+
const displayedRooms = [...rooms.map(value => ({ scopeId: input.scopeId, value })), ...projectRooms];
|
|
30
|
+
const filtered = packetEventsWithoutMirrors(allEvents, displayedRooms);
|
|
31
|
+
const events = recentEvents(filtered.filter(e => e.scopeId === input.scopeId).map(e => e.value), recentLimit)
|
|
32
|
+
.map(value => ({ scopeId: input.scopeId, value }));
|
|
33
|
+
const projectEvents = filtered.filter(e => e.scopeId !== input.scopeId && !isSuperseded(e.value))
|
|
34
|
+
.sort((a, b) => b.value.createdAt - a.value.createdAt || b.value.id.localeCompare(a.value.id)).slice(0, recentLimit);
|
|
26
35
|
const hasProject = Boolean(projectRooms.length || projectCastles.length || projectVisions.length || projectEvents.length);
|
|
27
36
|
if (!rooms.length && !castles.length && !visions.length && !events.length && !hasProject)
|
|
28
37
|
return "";
|
|
@@ -52,9 +61,7 @@ export function buildMemoryPacket(input) {
|
|
|
52
61
|
];
|
|
53
62
|
return clampMemoryPacket(lines.filter(Boolean).join("\n"), maxChars);
|
|
54
63
|
}
|
|
55
|
-
function
|
|
56
|
-
if (!rooms.length)
|
|
57
|
-
return ["@frontiera[vuota]: nessuna attivita indicizzata"];
|
|
64
|
+
function selectFrontierRooms(rooms) {
|
|
58
65
|
// La frontiera e' ordinata vecchio->recente. Conserva un indice per livello
|
|
59
66
|
// ma dedica la maggior parte degli slot allo stato piu' recente: slice(0,10)
|
|
60
67
|
// nascondeva proprio le ultime stanze nei run lunghi.
|
|
@@ -63,8 +70,12 @@ function frontierRows(rooms) {
|
|
|
63
70
|
if (!byLevel.has(room.level))
|
|
64
71
|
byLevel.set(room.level, room);
|
|
65
72
|
const picked = [...byLevel.values(), ...rooms.slice(-8)];
|
|
66
|
-
|
|
67
|
-
|
|
73
|
+
return [...new Map(picked.map((room) => [room.room, room])).values()].slice(-10);
|
|
74
|
+
}
|
|
75
|
+
function frontierRows(rooms) {
|
|
76
|
+
if (!rooms.length)
|
|
77
|
+
return ["@frontiera[vuota]: nessuna attivita indicizzata"];
|
|
78
|
+
return rooms.map((r) => `@frontiera[${r.room}]: level=${r.level}, title="${q(r.title)}", termini=${r.terms.slice(0, 6).join(",")}${r.attachments?.length ? `, allegati=${r.attachments.length}, recupero=recall rooms=["${r.room}"] attachments=true` : ''}`);
|
|
68
79
|
}
|
|
69
80
|
function planRows(castles) {
|
|
70
81
|
if (!castles.length)
|
|
@@ -75,7 +86,7 @@ function planRows(castles) {
|
|
|
75
86
|
.sort((a, b) => Number(a.status === "completed") - Number(b.status === "completed") || a.bit - b.bit)
|
|
76
87
|
.slice(0, 8)
|
|
77
88
|
.map((t) => `@task[${castle.slug}/${t.id}]: status=${t.status}, title="${q(t.title)}"`);
|
|
78
|
-
return [`@plan[${castle.slug}]: title="${q(castle.title)}", target=${castle.maskTarget}, attivita=${castle.tasks.length}`, ...tasks];
|
|
89
|
+
return [`@plan[${castle.slug}]: title="${q(castle.title)}", target=${castle.maskTarget}, attivita=${castle.tasks.length}${castle.after?.trim() ? `, after="${q(castle.after)}"` : ""}`, ...tasks];
|
|
79
90
|
}).slice(0, 32);
|
|
80
91
|
}
|
|
81
92
|
function visionRows(visions) {
|
|
@@ -93,7 +104,7 @@ function projectRows(rooms, castles, visions) {
|
|
|
93
104
|
"[WORKING_SET_PROGETTO]",
|
|
94
105
|
...rooms.map((r) => `@project_frontiera[${r.scopeId}/${r.value.room}]: level=${r.value.level}, title="${q(r.value.title)}"`),
|
|
95
106
|
...castles.flatMap((c) => [
|
|
96
|
-
`@project_plan[${c.scopeId}/${c.value.slug}]: title="${q(c.value.title)}", target=${c.value.maskTarget}, attivita=${c.value.tasks.length}`,
|
|
107
|
+
`@project_plan[${c.scopeId}/${c.value.slug}]: title="${q(c.value.title)}", target=${c.value.maskTarget}, attivita=${c.value.tasks.length}${c.value.after?.trim() ? `, after="${q(c.value.after)}"` : ""}`,
|
|
97
108
|
...c.value.tasks.slice(0, 4).map((t) => `@project_task[${c.scopeId}/${c.value.slug}/${t.id}]: status=${t.status}, title="${q(t.title)}"`),
|
|
98
109
|
]),
|
|
99
110
|
...visions.map((v) => `@project_vision[${v.scopeId}/${v.value.taskId}]: goal="${q(v.value.goal)}"`),
|
|
@@ -116,30 +127,6 @@ function isSuperseded(event) {
|
|
|
116
127
|
const status = typeof event.payload?.["status"] === "string" ? event.payload["status"] : "active";
|
|
117
128
|
return status === "superseded" || status === "archived" || typeof event.payload?.["supersededBy"] === "string";
|
|
118
129
|
}
|
|
119
|
-
function loadProjectFrontiers(sessionDir, scopes, limit) {
|
|
120
|
-
return scopes.flatMap((scopeId) => safe(() => RoomMemory.open(sessionDir, scopeId).frontier().slice(-2).map((value) => ({ scopeId, value })), [])).slice(0, limit);
|
|
121
|
-
}
|
|
122
|
-
function loadProjectCastles(sessionDir, scopes, limit) {
|
|
123
|
-
return scopes.flatMap((scopeId) => safe(() => VascendPlanStore.open(sessionDir, scopeId).castles().slice(0, 2).map((value) => ({ scopeId, value })), [])).slice(0, limit);
|
|
124
|
-
}
|
|
125
|
-
function loadProjectVisions(sessionDir, scopes, limit) {
|
|
126
|
-
return scopes.flatMap((scopeId) => safe(() => VascendVisionStore.open(sessionDir, scopeId).all().slice(0, 2).map((value) => ({ scopeId, value })), [])).slice(0, limit);
|
|
127
|
-
}
|
|
128
|
-
function loadProjectEvents(sessionDir, scopes, limit) {
|
|
129
|
-
const events = scopes.flatMap((scopeId) => safe(() => MemoryStore.open(sessionDir, scopeId).all().map((value) => ({ scopeId, value })), []));
|
|
130
|
-
return events
|
|
131
|
-
.filter((e) => !isSuperseded(e.value))
|
|
132
|
-
.sort((a, b) => b.value.createdAt - a.value.createdAt || b.value.id.localeCompare(a.value.id))
|
|
133
|
-
.slice(0, limit);
|
|
134
|
-
}
|
|
135
|
-
function safe(fn, fallback) {
|
|
136
|
-
try {
|
|
137
|
-
return fn();
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
return fallback;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
130
|
function q(value, max = 120) {
|
|
144
131
|
const oneLine = sanitizeText(value).replace(/\s+/g, " ").trim().replace(/"/g, "'");
|
|
145
132
|
return oneLine.length > max ? oneLine.slice(0, max - 1).trimEnd() + "..." : oneLine;
|
|
@@ -37,8 +37,10 @@ export interface KingdomPlan {
|
|
|
37
37
|
}
|
|
38
38
|
export declare class VascendPlanStore {
|
|
39
39
|
private readonly file;
|
|
40
|
-
private readonly
|
|
40
|
+
private readonly openMemory;
|
|
41
41
|
private kingdom;
|
|
42
|
+
private memoryStore?;
|
|
43
|
+
private get memory();
|
|
42
44
|
private constructor();
|
|
43
45
|
static open(sessionDir: string, sessionId: string, options?: {
|
|
44
46
|
strict?: boolean;
|
|
@@ -63,14 +63,16 @@ function buildCastle(slug, title, taskTitles, after) {
|
|
|
63
63
|
}
|
|
64
64
|
export class VascendPlanStore {
|
|
65
65
|
file;
|
|
66
|
-
|
|
66
|
+
openMemory;
|
|
67
67
|
kingdom = { castles: [] };
|
|
68
|
-
|
|
68
|
+
memoryStore;
|
|
69
|
+
get memory() { return this.memoryStore ??= this.openMemory(); }
|
|
70
|
+
constructor(file, openMemory) {
|
|
69
71
|
this.file = file;
|
|
70
|
-
this.
|
|
72
|
+
this.openMemory = openMemory;
|
|
71
73
|
}
|
|
72
74
|
static open(sessionDir, sessionId, options = {}) {
|
|
73
|
-
const store = new VascendPlanStore(join(sessionDir, `${sessionId}.castle.json`), MemoryStore.open(sessionDir, sessionId));
|
|
75
|
+
const store = new VascendPlanStore(join(sessionDir, `${sessionId}.castle.json`), () => MemoryStore.open(sessionDir, sessionId));
|
|
74
76
|
if (existsSync(store.file)) {
|
|
75
77
|
try {
|
|
76
78
|
const raw = JSON.parse(readFileSync(store.file, "utf8"));
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import type { Message } from "../core/types.js";
|
|
1
|
+
import type { Message, ImagePart } from "../core/types.js";
|
|
2
2
|
import { RoomGraph, type RoomEdge, type RoomNeighbor } from "./room-graph.js";
|
|
3
|
+
export interface RoomAttachment {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly mime: string;
|
|
6
|
+
readonly source?: string;
|
|
7
|
+
readonly bytes: number;
|
|
8
|
+
}
|
|
3
9
|
export interface RoomRecord {
|
|
10
|
+
readonly attachments?: readonly RoomAttachment[];
|
|
4
11
|
readonly room: string;
|
|
5
12
|
readonly level: number;
|
|
6
13
|
readonly title: string;
|
|
@@ -35,6 +42,8 @@ export declare class RoomMemory {
|
|
|
35
42
|
private tokensFor;
|
|
36
43
|
private indexedDocs;
|
|
37
44
|
static open(sessionDir: string, sessionId: string, fanout?: number): RoomMemory;
|
|
45
|
+
private persistMedia;
|
|
46
|
+
attachmentMedia(rooms: readonly string[]): readonly ImagePart[];
|
|
38
47
|
count(): number;
|
|
39
48
|
all(): readonly RoomRecord[];
|
|
40
49
|
frontier(): readonly RoomRecord[];
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
3
4
|
import { sanitizeText } from "../core/text-sanitize.js";
|
|
4
5
|
import { MemoryStore } from "./memory-store.js";
|
|
5
6
|
import { STOP, tokenize, buildSynonyms, expandQuery, bm25Score, } from "./lexical-search.js";
|
|
6
7
|
import { withLockSync } from "./file-lock.js";
|
|
7
8
|
import { RoomGraph, clusterByAffinity, clusterLabel, roomEdges, topTerms, } from "./room-graph.js";
|
|
9
|
+
const pendingMedia = new WeakMap();
|
|
10
|
+
const validImage = (image) => /^image\/(png|jpeg|webp|gif)$/.test(image.mime)
|
|
11
|
+
&& image.data.length > 0 && image.data.length <= 28_000_000 && /^[A-Za-z0-9+/=\s]+$/.test(image.data);
|
|
12
|
+
const attachmentId = (image) => createHash('sha256').update(image.mime).update(image.data).digest('hex');
|
|
8
13
|
// Peso di un vicino a 2 hop rispetto al seme che lo ha portato. Allineato al
|
|
9
14
|
// peso del link tipizzato in context-retriever.ts: stessa semantica, stesso
|
|
10
15
|
// numero, cosi' recall e compilazione del contesto non si contraddicono.
|
|
@@ -78,6 +83,31 @@ export class RoomMemory {
|
|
|
78
83
|
}
|
|
79
84
|
return mem;
|
|
80
85
|
}
|
|
86
|
+
persistMedia(record) {
|
|
87
|
+
const media = pendingMedia.get(record) || [];
|
|
88
|
+
if (!media.length)
|
|
89
|
+
return;
|
|
90
|
+
const dir = this.file + '.attachments';
|
|
91
|
+
mkdirSync(dir, { recursive: true });
|
|
92
|
+
for (const image of media)
|
|
93
|
+
writeFileSync(join(dir, attachmentId(image) + '.json'), JSON.stringify(image), { encoding: 'utf8', mode: 0o600 });
|
|
94
|
+
pendingMedia.delete(record);
|
|
95
|
+
}
|
|
96
|
+
attachmentMedia(rooms) {
|
|
97
|
+
const allowed = this.expandRooms(rooms).flatMap(record => record.attachments || []);
|
|
98
|
+
const out = [];
|
|
99
|
+
for (const ref of allowed.slice(0, 8)) {
|
|
100
|
+
if (!/^[a-f0-9]{64}$/.test(ref.id))
|
|
101
|
+
continue;
|
|
102
|
+
try {
|
|
103
|
+
const image = JSON.parse(readFileSync(join(this.file + '.attachments', ref.id + '.json'), 'utf8'));
|
|
104
|
+
if (validImage(image) && attachmentId(image) === ref.id)
|
|
105
|
+
out.push(image);
|
|
106
|
+
}
|
|
107
|
+
catch { /* Allegato assente: non inventare dati visivi. */ }
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
81
111
|
count() {
|
|
82
112
|
return this.records.length;
|
|
83
113
|
}
|
|
@@ -102,6 +132,7 @@ export class RoomMemory {
|
|
|
102
132
|
// Aggiunge una stanza (livello 0): fast path append, protetto da lock
|
|
103
133
|
// file-system cosi' due processi concorrenti non interlacciano le righe.
|
|
104
134
|
append(record) {
|
|
135
|
+
this.persistMedia(record);
|
|
105
136
|
this.records.push(record);
|
|
106
137
|
mkdirSync(dirname(this.file), { recursive: true });
|
|
107
138
|
withLockSync(this.file, () => {
|
|
@@ -151,6 +182,7 @@ export class RoomMemory {
|
|
|
151
182
|
this.reloadFromDisk();
|
|
152
183
|
const id = this.nextRoomId(ns);
|
|
153
184
|
const rec = build(id);
|
|
185
|
+
this.persistMedia(rec);
|
|
154
186
|
this.records.push(rec);
|
|
155
187
|
appendFileSync(this.file, JSON.stringify(rec) + "\n", "utf8");
|
|
156
188
|
return rec;
|
|
@@ -329,7 +361,7 @@ export class RoomMemory {
|
|
|
329
361
|
const rows = front
|
|
330
362
|
.map((r, i) => {
|
|
331
363
|
const marker = i === last ? " <- TURNO PIU' RECENTE" : "";
|
|
332
|
-
return `${i + 1}. @${levelLabel(r.level)}[${r.room}]: "${escapeValue(r.title)}" · termini=${r.terms.slice(0, 8).join(",")}${marker}`;
|
|
364
|
+
return `${i + 1}. @${levelLabel(r.level)}[${r.room}]: "${escapeValue(r.title)}" · termini=${r.terms.slice(0, 8).join(",")}${r.attachments?.length ? ` · allegati=${r.attachments.length}; recall rooms=["${r.room}"] attachments=true` : ''}${marker}`;
|
|
333
365
|
})
|
|
334
366
|
.join("\n");
|
|
335
367
|
return `ATTIVITA_ARCHIVIATE (ordine cronologico: prima le piu' vecchie, ultima la piu' recente)
|
|
@@ -371,6 +403,8 @@ function roomEvent(type, record, children = []) {
|
|
|
371
403
|
}
|
|
372
404
|
// Record Danilov compatto di una STANZA (livello 0) dai messaggi del turno.
|
|
373
405
|
export function formatRoomRecord(room, messages, createdAt) {
|
|
406
|
+
const media = messages.filter(message => message.role === 'user').flatMap(message => message.content.filter((part) => part.type === 'image')).filter(validImage).slice(0, 8);
|
|
407
|
+
const attachments = media.map(image => ({ id: attachmentId(image), mime: image.mime, bytes: Math.floor(image.data.length * 0.75), ...(image.source ? { source: image.source } : {}) }));
|
|
374
408
|
const title = roomTitle(messages);
|
|
375
409
|
const tools = collectToolCalls(messages);
|
|
376
410
|
const files = collectFiles(messages);
|
|
@@ -382,6 +416,7 @@ export function formatRoomRecord(room, messages, createdAt) {
|
|
|
382
416
|
]).slice(0, 12);
|
|
383
417
|
const def = [
|
|
384
418
|
`@goal[${room}]: "${escapeValue(title)}"`,
|
|
419
|
+
...attachments.map(att => `@attachment[${att.id}]: ${att.mime}, source=${escapeValue(att.source || 'immagine')}; recall rooms=["${room}"] attachments=true`),
|
|
385
420
|
...tools.slice(0, 12).map((t, i) => `@tool[${room}.${i + 1}]: ${t.name}(${escapeValue(t.arg)}) -> ${escapeValue(t.result)}`),
|
|
386
421
|
...files.slice(0, 12).map((f, i) => `@file[${room}.${i + 1}]: ${escapeValue(f)}`),
|
|
387
422
|
].join("\n");
|
|
@@ -401,7 +436,10 @@ RELAZIONI
|
|
|
401
436
|
${rel}
|
|
402
437
|
|
|
403
438
|
OUTPUT: ${escapeValue(output) || "(nessun output testuale)"}`);
|
|
404
|
-
|
|
439
|
+
const record = { room, level: 0, title, terms, body, children: [], parent: null, createdAt, edges, ...(attachments.length ? { attachments } : {}) };
|
|
440
|
+
if (media.length)
|
|
441
|
+
pendingMedia.set(record, media);
|
|
442
|
+
return record;
|
|
405
443
|
}
|
|
406
444
|
// Record di ROLLUP (castello/regno/...): indice sui figli che ha chiuso.
|
|
407
445
|
export function formatRollupRecord(id, level, children, createdAt) {
|
|
@@ -439,6 +477,7 @@ OUTPUT: riepilogo delle attivita; apri i dettagli col tool recall.`);
|
|
|
439
477
|
terms,
|
|
440
478
|
body,
|
|
441
479
|
children: children.map((c) => c.room),
|
|
480
|
+
attachments: children.flatMap(c => c.attachments || []),
|
|
442
481
|
parent: null,
|
|
443
482
|
// Il padre eredita il timestamp del figlio piu' recente: con i gruppi per
|
|
444
483
|
// affinita' l'istante del rollup non direbbe nulla, mentre cosi' la
|
|
@@ -488,6 +527,7 @@ function normalize(raw) {
|
|
|
488
527
|
parent: raw.parent ?? null,
|
|
489
528
|
createdAt: typeof raw.createdAt === "number" ? raw.createdAt : 0,
|
|
490
529
|
...(Array.isArray(raw.edges) ? { edges: raw.edges.filter(isRoomEdge) } : {}),
|
|
530
|
+
...(Array.isArray(raw.attachments) ? { attachments: raw.attachments.filter(att => att && /^[a-f0-9]{64}$/.test(att.id)) } : {}),
|
|
491
531
|
};
|
|
492
532
|
}
|
|
493
533
|
// Aggiorna solo le etichette generate dei vecchi riepiloghi. Gli ID,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type VisionLike } from "./long-term-context.js";
|
|
1
|
+
import type { VisionLike } from "./long-term-context.js";
|
|
3
2
|
export type VascendMode = "off" | "sticky";
|
|
4
3
|
export type VascendPromptMode = "one-shot" | "sticky";
|
|
5
4
|
export type VascendTaskStatus = "pending" | "running" | "completed" | "failed";
|
|
@@ -48,10 +47,6 @@ export type VascendCommandResult = {
|
|
|
48
47
|
readonly message: string;
|
|
49
48
|
readonly input: string;
|
|
50
49
|
};
|
|
51
|
-
export interface VascendCheckpoint {
|
|
52
|
-
readonly path: string;
|
|
53
|
-
readonly text: string;
|
|
54
|
-
}
|
|
55
50
|
export declare const VASCEND_SYSTEM_BLOCK = "# Lista delle attivita\nComunica in italiano naturale, con spiegazioni chiare e Markdown leggibile.\nDescrivi il lavoro con una to-do list: attivita, gruppi, dipendenze e stati\nda fare, in corso, completata o fallita. I riepiloghi della memoria sono solo\ncontesto interno: all'utente mostra le attivita e i risultati pertinenti.\nPer lavori con piu passi usa vascend_plan: un piano contiene gruppi di attivita,\nogni gruppo contiene attivita con stato, dipendenze e prove di verifica.\nAggiorna gli stati con vascend_mark; completa solo dopo le verifiche.\nUsa vascend_note per decisioni e blocchi e recall per recuperare il passato.\nPer lavori indipendenti valuta collaboratori tramite gli strumenti del team.\nPer domande o richieste semplici non creare un piano inutile.";
|
|
56
51
|
export interface VascendVerdict {
|
|
57
52
|
readonly ok: boolean;
|
|
@@ -66,19 +61,16 @@ export declare function createVascendState(): VascendState;
|
|
|
66
61
|
export declare function createVascendGoal(state: VascendState, goal: string): VascendState;
|
|
67
62
|
export declare function setVascendMode(state: VascendState, mode: VascendMode): VascendState;
|
|
68
63
|
export declare function setVascendVision(state: VascendState, vision: VisionLike | null): VascendState;
|
|
69
|
-
export declare function wrapVascendPrompt(
|
|
70
|
-
export declare function formatVascendCompact(state: VascendState, messages?: readonly Message[]): string;
|
|
64
|
+
export declare function wrapVascendPrompt(_state: VascendState, userText: string, _mode: VascendPromptMode): string;
|
|
71
65
|
export declare class VascendRuntime {
|
|
72
|
-
private readonly cwd;
|
|
73
66
|
private stateValue;
|
|
74
67
|
private customPlan;
|
|
75
|
-
constructor(
|
|
68
|
+
constructor(_cwd: string, initialMode?: VascendMode);
|
|
76
69
|
state(): VascendState;
|
|
77
70
|
hasCustomPlan(): boolean;
|
|
78
71
|
loadPlan(sessionDir: string, sessionId: string): boolean;
|
|
79
72
|
resetPlan(sessionDir: string, sessionId: string): void;
|
|
80
73
|
handleCommand(args: string): VascendCommandResult;
|
|
81
74
|
prepareUserInput(userText: string): PreparedVascendInput;
|
|
82
|
-
compact(messages: readonly Message[]): VascendCheckpoint;
|
|
83
75
|
private wrap;
|
|
84
76
|
}
|
package/dist/vascend/runtime.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
1
|
import { sanitizeText } from "../core/text-sanitize.js";
|
|
4
2
|
import { VascendPlanStore } from "./plan-store.js";
|
|
5
|
-
import { injectLongTermContext } from "./long-term-context.js";
|
|
6
3
|
export const VASCEND_SYSTEM_BLOCK = `# Lista delle attivita
|
|
7
4
|
Comunica in italiano naturale, con spiegazioni chiare e Markdown leggibile.
|
|
8
5
|
Descrivi il lavoro con una to-do list: attivita, gruppi, dipendenze e stati
|
|
@@ -14,6 +11,7 @@ Aggiorna gli stati con vascend_mark; completa solo dopo le verifiche.
|
|
|
14
11
|
Usa vascend_note per decisioni e blocchi e recall per recuperare il passato.
|
|
15
12
|
Per lavori indipendenti valuta collaboratori tramite gli strumenti del team.
|
|
16
13
|
Per domande o richieste semplici non creare un piano inutile.`;
|
|
14
|
+
const MAX_GOAL_CHARS = 240;
|
|
17
15
|
export function validateKingdom(state) {
|
|
18
16
|
const castles = state.kingdom.castles;
|
|
19
17
|
const multi = castles.length > 1;
|
|
@@ -55,7 +53,9 @@ export function createVascendState() {
|
|
|
55
53
|
return { mode: "off", goal: null, kingdom: { castles: [] } };
|
|
56
54
|
}
|
|
57
55
|
export function createVascendGoal(state, goal) {
|
|
58
|
-
|
|
56
|
+
// Il goal e' una chiave breve per UI, routing e memoria. Resta nello stato
|
|
57
|
+
// strutturato e non viene copiato dentro al messaggio utente.
|
|
58
|
+
const title = oneLine(goal).slice(0, MAX_GOAL_CHARS) || "obiettivo";
|
|
59
59
|
// NIENTE castello automatico: il castello (con le sue stanze) si crea solo su
|
|
60
60
|
// richiesta (comando /castle) o quando l'agente pianifica con vascend_plan.
|
|
61
61
|
// Cosi' il riquadro non compare quando non serve (es. un saluto).
|
|
@@ -69,90 +69,19 @@ export function setVascendMode(state, mode) {
|
|
|
69
69
|
export function setVascendVision(state, vision) {
|
|
70
70
|
return { ...state, vision };
|
|
71
71
|
}
|
|
72
|
-
export function wrapVascendPrompt(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
: "";
|
|
78
|
-
const immediatePrompt = `[VASCEND_GOAL]
|
|
79
|
-
GOAL: ${state.goal}
|
|
80
|
-
MODE: ${mode}
|
|
81
|
-
${checkpointBlock}
|
|
82
|
-
Piano di lavoro:
|
|
83
|
-
- Comunica in modo naturale e leggibile, senza imporre notazioni speciali.
|
|
84
|
-
- Per lavori con piu passi crea o riprendi il piano con vascend_plan e vascend_status.
|
|
85
|
-
- Organizza il piano in gruppi e attivita; aggiorna gli stati con vascend_mark.
|
|
86
|
-
- Completa le attivita solo dopo verifiche concrete; registra decisioni e blocchi.
|
|
87
|
-
- Per lavori indipendenti valuta collaboratori; per domande semplici non serve un piano.
|
|
88
|
-
|
|
89
|
-
INPUT_UTENTE
|
|
90
|
-
${userText}`;
|
|
91
|
-
// Antepone il CONTESTO A LUNGO TERMINE (Vision finale) come piano SEPARATO
|
|
92
|
-
// dal goal immediato. Il goal corrente viene passato come "immediato" cosi'
|
|
93
|
-
// che il blocco espliciti la distinzione momentaneo/visione. Se non c'e'
|
|
94
|
-
// Vision con contenuto, injectLongTermContext ritorna il prompt invariato.
|
|
95
|
-
const currentCastle = state.kingdom.castles[0];
|
|
96
|
-
const currentRoom = currentCastle?.tasks.find((t) => t.status === "running");
|
|
97
|
-
return injectLongTermContext(immediatePrompt, {
|
|
98
|
-
vision: state.vision ?? null,
|
|
99
|
-
immediate: {
|
|
100
|
-
...(state.goal ? { goal: state.goal } : {}),
|
|
101
|
-
...(currentCastle ? { castle: currentCastle.title } : {}),
|
|
102
|
-
...(currentRoom ? { room: currentRoom.title } : {}),
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
export function formatVascendCompact(state, messages = []) {
|
|
107
|
-
const castle = state.kingdom.castles[0];
|
|
108
|
-
const multi = state.kingdom.castles.length > 1;
|
|
109
|
-
const tasks = state.kingdom.castles.flatMap(group => group.tasks.map(task => ({ ...task,
|
|
110
|
-
id: multi ? `${group.slug}/${task.id}` : task.id,
|
|
111
|
-
})));
|
|
112
|
-
const groups = state.kingdom.castles.map(group => `@gruppo[${group.slug}]: titolo="${escapeValue(group.title)}", dipendenza=${group.after ?? "none"}`).join("\n");
|
|
113
|
-
const taskRows = tasks.length
|
|
114
|
-
? tasks.map((task) => compactTaskRow(task)).join("\n")
|
|
115
|
-
: "@aperto[goal]: nessun_gruppo_attivo, blocco=none";
|
|
116
|
-
const recent = messagePreviews(messages)
|
|
117
|
-
.map((text, index) => `@stato[recent_${index + 1}]: ${text}`)
|
|
118
|
-
.join("\n");
|
|
119
|
-
const relations = tasks.length
|
|
120
|
-
? tasks.map((task, index) => `@R${index + 1}: @stato[goal] -> @${task.status === "completed" ? "fatto" : "aperto"}[${task.id}], task`).join("\n")
|
|
121
|
-
: "@R1: @stato[goal] -> @aperto[goal], crea_gruppo";
|
|
122
|
-
// The synthetic summary is usually older than the last four messages.
|
|
123
|
-
// Keep it in the cold-start checkpoint, not just 140-character previews.
|
|
124
|
-
const summary = messages.flatMap(message => message.content
|
|
125
|
-
.filter(part => part.type === "text" && part.text.startsWith("[Riepilogo del contesto precedente]"))
|
|
126
|
-
.map(part => part.type === "text" ? part.text : "")).at(-1);
|
|
127
|
-
return `INDICE
|
|
128
|
-
1 = goal
|
|
129
|
-
2 = gruppo
|
|
130
|
-
3 = task
|
|
131
|
-
4 = file
|
|
132
|
-
5 = contesto
|
|
133
|
-
|
|
134
|
-
DEFINIZIONI
|
|
135
|
-
@stato[goal]: valore="${escapeValue(state.goal ?? "nessun_goal")}", mode=${state.mode}
|
|
136
|
-
@stato[gruppo]: slug=${castle?.slug ?? "none"}, mask=${castle?.maskTarget ?? "0x0000"}
|
|
137
|
-
${groups}
|
|
138
|
-
${taskRows}
|
|
139
|
-
@file[checkpoint]: path=.vascend-compact.md, ruolo=checkpoint, stato=aggiornato${recent ? `\n${recent}` : ""}
|
|
140
|
-
|
|
141
|
-
RELAZIONI
|
|
142
|
-
${relations}
|
|
143
|
-
@R99: @file[checkpoint] -> @stato[goal], ripresa
|
|
144
|
-
|
|
145
|
-
OUTPUT: stato compatto della sessione, pronto a riprendere a freddo.${summary ? `\n\nCONTESTO DI RIPRESA\n${summary}` : ""}`;
|
|
72
|
+
export function wrapVascendPrompt(_state, userText, _mode) {
|
|
73
|
+
// La richiesta dell'utente deve comparire una sola volta nel payload. Goal,
|
|
74
|
+
// piano, Vision e ricevute vengono gia' composti dal Context Fabric e dagli
|
|
75
|
+
// store JSON nel canale di contesto del turno.
|
|
76
|
+
return userText;
|
|
146
77
|
}
|
|
147
78
|
export class VascendRuntime {
|
|
148
|
-
cwd;
|
|
149
79
|
stateValue;
|
|
150
80
|
customPlan = false;
|
|
151
81
|
// initialMode permette di rendere il metodo Vascend NATIVO (sticky) di
|
|
152
82
|
// default nella TUI, senza dover digitare /vascend on. Default "off" per
|
|
153
83
|
// mantenere puro il runtime fuori dalla TUI (test, print, SDK).
|
|
154
|
-
constructor(
|
|
155
|
-
this.cwd = cwd;
|
|
84
|
+
constructor(_cwd, initialMode = "off") {
|
|
156
85
|
this.stateValue = setVascendMode(createVascendState(), initialMode);
|
|
157
86
|
}
|
|
158
87
|
state() {
|
|
@@ -233,54 +162,13 @@ export class VascendRuntime {
|
|
|
233
162
|
this.stateValue = createVascendGoal(this.stateValue, userText);
|
|
234
163
|
return { active: true, input: this.wrap(userText, "sticky") };
|
|
235
164
|
}
|
|
236
|
-
compact(messages) {
|
|
237
|
-
const text = formatVascendCompact(this.stateValue, messages);
|
|
238
|
-
const path = checkpointPath(this.cwd);
|
|
239
|
-
writeFileSync(path, text + "\n", "utf8");
|
|
240
|
-
return { path, text };
|
|
241
|
-
}
|
|
242
165
|
wrap(userText, mode) {
|
|
243
|
-
return wrapVascendPrompt(this.stateValue, userText, mode
|
|
166
|
+
return wrapVascendPrompt(this.stateValue, userText, mode);
|
|
244
167
|
}
|
|
245
168
|
}
|
|
246
|
-
function compactTaskRow(task) {
|
|
247
|
-
const kind = task.status === "completed" ? "fatto" : "aperto";
|
|
248
|
-
const block = task.status === "failed" ? ", blocco=failed" : "";
|
|
249
|
-
const evidence = task.evidence?.length
|
|
250
|
-
? `, prove="${escapeValue(task.evidence.slice(-3).join(" | "))}"`
|
|
251
|
-
: "";
|
|
252
|
-
return `@${kind}[${task.id}]: titolo="${escapeValue(task.title)}", bit=${task.bit}, mask=${task.mask}, esito=${task.status}${block}${evidence}`;
|
|
253
|
-
}
|
|
254
|
-
function messagePreviews(messages) {
|
|
255
|
-
return messages.slice(-4).flatMap((message) => {
|
|
256
|
-
const text = message.content
|
|
257
|
-
.map((part) => {
|
|
258
|
-
if (part.type === "text")
|
|
259
|
-
return part.text;
|
|
260
|
-
if (part.type === "tool_call")
|
|
261
|
-
return `${part.name} ${JSON.stringify(part.input)}`;
|
|
262
|
-
if (part.type === "image")
|
|
263
|
-
return `[immagine ${part.mime}]`;
|
|
264
|
-
return part.output;
|
|
265
|
-
})
|
|
266
|
-
.join(" ");
|
|
267
|
-
const compact = oneLine(text).slice(0, 140);
|
|
268
|
-
return compact ? [`role=${message.role}, text="${escapeValue(compact)}"`] : [];
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
function checkpointPath(cwd) {
|
|
272
|
-
return join(cwd, ".vascend-compact.md");
|
|
273
|
-
}
|
|
274
|
-
function readCheckpoint(cwd) {
|
|
275
|
-
const path = checkpointPath(cwd);
|
|
276
|
-
return existsSync(path) ? readFileSync(path, "utf8") : undefined;
|
|
277
|
-
}
|
|
278
169
|
function oneLine(value) {
|
|
279
170
|
return sanitizeText(value).replace(/\s+/g, " ").trim();
|
|
280
171
|
}
|
|
281
|
-
function escapeValue(value) {
|
|
282
|
-
return oneLine(value).replace(/"/g, "'");
|
|
283
|
-
}
|
|
284
172
|
function hexMask(value) {
|
|
285
173
|
return `0x${value.toString(16).padStart(4, "0")}`;
|
|
286
174
|
}
|
|
@@ -80,6 +80,8 @@ function lineText(line) {
|
|
|
80
80
|
const BOILERPLATE = /^\s*(?:\[COLLABORATORE|\[VASSALLO|\[VASCEND_GOAL\]|INDICE\s+\d\s*=|<!--\s*vascend:|@regno|@stato\[)/i;
|
|
81
81
|
const OBJECTIVE_MARKER = /(?:OBIETTIVO_ATTIVITA|OBIETTIVO_CASTELLO|OBIETTIVO|GOAL)\s*[:=]\s*(.{4,})/i;
|
|
82
82
|
export function pickObjective(userTexts) {
|
|
83
|
+
// Compatibilita di sola lettura con sessioni storiche che contenevano il
|
|
84
|
+
// vecchio wrapper/checkpoint. Non carica file e non aggiunge dati al prompt.
|
|
83
85
|
const cut = (text) => text.split(/\s(?:MODE|CHECKPOINT_PRECEDENTE|CHECKPOINT|INDICE|OUTPUT)\s*[:=]/)[0].trim().slice(0, 200);
|
|
84
86
|
const plain = userTexts.find((text) => !BOILERPLATE.test(text));
|
|
85
87
|
if (plain)
|
|
@@ -119,8 +119,9 @@ function checkpoint(team) {
|
|
|
119
119
|
export async function waitForTeamChange(team, signal, interrupted) {
|
|
120
120
|
const signature = (current) => JSON.stringify(current.members.map((member) => [member.slug, member.status]));
|
|
121
121
|
const before = signature(team);
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
// Poll local state only. A wall-clock deadline used to wake the provider
|
|
123
|
+
// repeatedly even when no worker or message had changed.
|
|
124
|
+
while (!signal.aborted && !interrupted()) {
|
|
124
125
|
const current = teamById(team.sessionId, team.id);
|
|
125
126
|
if (!current || current.done || signature(current) !== before)
|
|
126
127
|
return;
|
package/dist/vascend/vision.d.ts
CHANGED
|
@@ -60,8 +60,10 @@ export declare function visionFromJSON(json: string, opts?: {
|
|
|
60
60
|
}): Vision | null;
|
|
61
61
|
export declare class VascendVisionStore {
|
|
62
62
|
private readonly file;
|
|
63
|
-
private readonly
|
|
63
|
+
private readonly openMemory;
|
|
64
64
|
private visions;
|
|
65
|
+
private memoryStore?;
|
|
66
|
+
private get memory();
|
|
65
67
|
private constructor();
|
|
66
68
|
static open(sessionDir: string, sessionId: string): VascendVisionStore;
|
|
67
69
|
has(taskId: string): boolean;
|
package/dist/vascend/vision.js
CHANGED
|
@@ -202,14 +202,16 @@ export function visionFromJSON(json, opts) {
|
|
|
202
202
|
// VascendPlanStore: API immutabile verso l'esterno, persistenza su mutazione.
|
|
203
203
|
export class VascendVisionStore {
|
|
204
204
|
file;
|
|
205
|
-
|
|
205
|
+
openMemory;
|
|
206
206
|
visions = {};
|
|
207
|
-
|
|
207
|
+
memoryStore;
|
|
208
|
+
get memory() { return this.memoryStore ??= this.openMemory(); }
|
|
209
|
+
constructor(file, openMemory) {
|
|
208
210
|
this.file = file;
|
|
209
|
-
this.
|
|
211
|
+
this.openMemory = openMemory;
|
|
210
212
|
}
|
|
211
213
|
static open(sessionDir, sessionId) {
|
|
212
|
-
const store = new VascendVisionStore(join(sessionDir, `${sessionId}.vision.json`), MemoryStore.open(sessionDir, sessionId));
|
|
214
|
+
const store = new VascendVisionStore(join(sessionDir, `${sessionId}.vision.json`), () => MemoryStore.open(sessionDir, sessionId));
|
|
213
215
|
if (existsSync(store.file)) {
|
|
214
216
|
try {
|
|
215
217
|
const raw = JSON.parse(readFileSync(store.file, "utf8"));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type AgentDeps } from "../core/agent.js";
|
|
2
|
+
import type { AgentEvent } from "../core/types.js";
|
|
3
|
+
import { createWorkerInbox } from "./kingdom-live.js";
|
|
4
|
+
/** Un incarico finisce, la conversazione puo' restare disponibile per l'host. */
|
|
5
|
+
export declare function createWorkerSession(opts: {
|
|
6
|
+
kingdomId: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
sessionId: string;
|
|
9
|
+
goal: string;
|
|
10
|
+
parentSignal: AbortSignal;
|
|
11
|
+
controller: AbortController;
|
|
12
|
+
retain: boolean | "queued";
|
|
13
|
+
onController?: (controller: AbortController) => void;
|
|
14
|
+
binding: ReturnType<typeof createWorkerInbox>;
|
|
15
|
+
deps: AgentDeps;
|
|
16
|
+
sink: (event: AgentEvent) => void;
|
|
17
|
+
}): {
|
|
18
|
+
readonly signal: AbortSignal;
|
|
19
|
+
finish: () => void;
|
|
20
|
+
};
|