@aexol/spectral 0.9.15 → 0.9.17
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/memory/compaction.d.ts +1 -1
- package/dist/memory/compaction.js +3 -3
- package/dist/memory/config.d.ts +12 -0
- package/dist/memory/config.d.ts.map +1 -1
- package/dist/memory/config.js +27 -0
- package/dist/memory/deterministic-pruner.d.ts +65 -0
- package/dist/memory/deterministic-pruner.d.ts.map +1 -0
- package/dist/memory/deterministic-pruner.js +333 -0
- package/dist/memory/hooks/compaction-hook.d.ts.map +1 -1
- package/dist/memory/hooks/compaction-hook.js +160 -132
- package/dist/memory/hooks/inter-agent-receiver.d.ts +3 -0
- package/dist/memory/hooks/inter-agent-receiver.d.ts.map +1 -0
- package/dist/memory/hooks/inter-agent-receiver.js +183 -0
- package/dist/memory/hooks/observer-trigger.d.ts.map +1 -1
- package/dist/memory/hooks/observer-trigger.js +14 -0
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +6 -0
- package/dist/memory/inter-agent-broker-singleton.d.ts +5 -0
- package/dist/memory/inter-agent-broker-singleton.d.ts.map +1 -0
- package/dist/memory/inter-agent-broker-singleton.js +7 -0
- package/dist/memory/inter-agent-relay.d.ts +7 -0
- package/dist/memory/inter-agent-relay.d.ts.map +1 -0
- package/dist/memory/inter-agent-relay.js +41 -0
- package/dist/memory/project-observations-store.d.ts +7 -0
- package/dist/memory/project-observations-store.d.ts.map +1 -1
- package/dist/memory/prompts.d.ts.map +1 -1
- package/dist/memory/prompts.js +9 -0
- package/dist/memory/tools/receive-agent-observations.d.ts +17 -0
- package/dist/memory/tools/receive-agent-observations.d.ts.map +1 -0
- package/dist/memory/tools/receive-agent-observations.js +68 -0
- package/dist/memory/tools/share-project-observation.d.ts +8 -0
- package/dist/memory/tools/share-project-observation.d.ts.map +1 -0
- package/dist/memory/tools/share-project-observation.js +106 -0
- package/dist/memory/unified-compaction.d.ts +59 -0
- package/dist/memory/unified-compaction.d.ts.map +1 -0
- package/dist/memory/unified-compaction.js +332 -0
- package/dist/relay/dispatcher.d.ts +1 -1
- package/dist/relay/dispatcher.d.ts.map +1 -1
- package/dist/relay/dispatcher.js +13 -0
- package/dist/server/handlers/files-search.d.ts +26 -0
- package/dist/server/handlers/files-search.d.ts.map +1 -0
- package/dist/server/handlers/files-search.js +89 -0
- package/dist/server/inter-agent-broker.d.ts +111 -0
- package/dist/server/inter-agent-broker.d.ts.map +1 -0
- package/dist/server/inter-agent-broker.js +136 -0
- package/dist/server/session-stream.d.ts +1 -0
- package/dist/server/session-stream.d.ts.map +1 -1
- package/dist/server/session-stream.js +43 -0
- package/dist/server/storage.d.ts +28 -0
- package/dist/server/storage.d.ts.map +1 -1
- package/dist/server/storage.js +101 -0
- package/dist/server/wire.d.ts +15 -0
- package/dist/server/wire.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -5,6 +5,8 @@ import { observationsToPromptLines, runObserver } from "../observer.js";
|
|
|
5
5
|
import { serializeSourceAddressedBranchEntries } from "../serialize.js";
|
|
6
6
|
import { estimateEntryTokens, estimateStringTokens } from "../tokens.js";
|
|
7
7
|
import { OBSERVATION_CUSTOM_TYPE, reflectionToPromptLine } from "../types.js";
|
|
8
|
+
import { getProjectObsStore } from "../project-observations-store.js";
|
|
9
|
+
import { relayProjectObservations } from "../inter-agent-relay.js";
|
|
8
10
|
export function registerObserverTrigger(ext, runtime) {
|
|
9
11
|
ext.on("turn_end", (_event, ctx) => {
|
|
10
12
|
process.stderr.write("[obs-mem] turn_end fired\n");
|
|
@@ -146,6 +148,7 @@ export function registerObserverTrigger(ext, runtime) {
|
|
|
146
148
|
records,
|
|
147
149
|
});
|
|
148
150
|
ext.appendEntry(OBSERVATION_CUSTOM_TYPE, data);
|
|
151
|
+
relayObservationRecords(cwd, ctx.sessionManager.getSessionId?.(), records);
|
|
149
152
|
debugLog("observer.appended", { count: records.length, tokenCount: observationTokens, coversFromId, coversUpToId: effectiveCoversUpToId });
|
|
150
153
|
if (hasUI && ui)
|
|
151
154
|
ui.notify(`Observational memory: ${records.length} observation${records.length === 1 ? "" : "s"} recorded (~${observationTokens.toLocaleString()} tokens)`, "info");
|
|
@@ -157,3 +160,14 @@ export function registerObserverTrigger(ext, runtime) {
|
|
|
157
160
|
}));
|
|
158
161
|
});
|
|
159
162
|
}
|
|
163
|
+
function relayObservationRecords(cwd, sessionId, records) {
|
|
164
|
+
if (!sessionId || records.length === 0)
|
|
165
|
+
return;
|
|
166
|
+
const store = getProjectObsStore();
|
|
167
|
+
if (!store)
|
|
168
|
+
return;
|
|
169
|
+
const projectId = store.getProjectByCwd(cwd);
|
|
170
|
+
if (!projectId)
|
|
171
|
+
return;
|
|
172
|
+
relayProjectObservations(cwd, projectId, sessionId, records, "observation");
|
|
173
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/memory/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/memory/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAcjE,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,GAAG,EAAE,YAAY,QAmB5D"}
|
package/dist/memory/index.js
CHANGED
|
@@ -2,10 +2,13 @@ import { registerStatusCommand } from "./commands/status.js";
|
|
|
2
2
|
import { registerViewCommand } from "./commands/view.js";
|
|
3
3
|
import { registerCompactionHook } from "./hooks/compaction-hook.js";
|
|
4
4
|
import { registerCompactionTrigger } from "./hooks/compaction-trigger.js";
|
|
5
|
+
import { registerInterAgentReceiver } from "./hooks/inter-agent-receiver.js";
|
|
5
6
|
import { registerObserverTrigger } from "./hooks/observer-trigger.js";
|
|
6
7
|
import { Runtime } from "./runtime.js";
|
|
7
8
|
import { registerRecallTool } from "./tools/recall-observation.js";
|
|
8
9
|
import { registerReadProjectObservationsTool } from "./tools/read-project-observations.js";
|
|
10
|
+
import { registerReceiveAgentObservationsTool } from "./tools/receive-agent-observations.js";
|
|
11
|
+
import { registerShareProjectObservationTool } from "./tools/share-project-observation.js";
|
|
9
12
|
import { registerWriteProjectObservationTool } from "./tools/write-project-observation.js";
|
|
10
13
|
export default function observationalMemory(ext) {
|
|
11
14
|
const runtime = new Runtime();
|
|
@@ -19,4 +22,7 @@ export default function observationalMemory(ext) {
|
|
|
19
22
|
registerRecallTool(ext);
|
|
20
23
|
registerReadProjectObservationsTool(ext);
|
|
21
24
|
registerWriteProjectObservationTool(ext);
|
|
25
|
+
registerShareProjectObservationTool(ext);
|
|
26
|
+
registerReceiveAgentObservationsTool(ext);
|
|
27
|
+
registerInterAgentReceiver(ext);
|
|
22
28
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { InterAgentBroker, InterAgentMessage } from "../server/inter-agent-broker.js";
|
|
2
|
+
export declare function setInterAgentBroker(broker: InterAgentBroker): void;
|
|
3
|
+
export declare function getInterAgentBroker(): InterAgentBroker | null;
|
|
4
|
+
export type { InterAgentBroker, InterAgentMessage };
|
|
5
|
+
//# sourceMappingURL=inter-agent-broker-singleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inter-agent-broker-singleton.d.ts","sourceRoot":"","sources":["../../src/memory/inter-agent-broker-singleton.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAI3F,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAElE;AAED,wBAAgB,mBAAmB,IAAI,gBAAgB,GAAG,IAAI,CAE7D;AAED,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface RelayObservation {
|
|
2
|
+
id: string;
|
|
3
|
+
content: string;
|
|
4
|
+
relevance: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function relayProjectObservations(cwd: string, projectId: string, sessionId: string, observations: RelayObservation[], originType?: "observation" | "reflection"): void;
|
|
7
|
+
//# sourceMappingURL=inter-agent-relay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inter-agent-relay.d.ts","sourceRoot":"","sources":["../../src/memory/inter-agent-relay.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,gBAAgB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,gBAAgB,EAAE,EAChC,UAAU,GAAE,aAAa,GAAG,YAA2B,GACrD,IAAI,CAiCN"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getInterAgentBroker } from "./inter-agent-broker-singleton.js";
|
|
2
|
+
import { loadConfig } from "./config.js";
|
|
3
|
+
import { debugLog } from "./debug-log.js";
|
|
4
|
+
const RELEVANCE_RANK = {
|
|
5
|
+
low: 0,
|
|
6
|
+
medium: 1,
|
|
7
|
+
high: 2,
|
|
8
|
+
critical: 3,
|
|
9
|
+
};
|
|
10
|
+
export function relayProjectObservations(cwd, projectId, sessionId, observations, originType = "reflection") {
|
|
11
|
+
const broker = getInterAgentBroker();
|
|
12
|
+
if (!broker)
|
|
13
|
+
return;
|
|
14
|
+
const config = loadConfig(cwd).interAgent;
|
|
15
|
+
if (config?.broadcastOnCompact === false) {
|
|
16
|
+
debugLog("inter_agent.broadcast.disabled", { sessionId });
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const minRank = RELEVANCE_RANK[config?.minBroadcastRelevance ?? "high"] ?? 2;
|
|
20
|
+
const ttlSeconds = config?.ttlSeconds;
|
|
21
|
+
for (const obs of observations) {
|
|
22
|
+
if ((RELEVANCE_RANK[obs.relevance] ?? 0) < minRank)
|
|
23
|
+
continue;
|
|
24
|
+
broker.send({
|
|
25
|
+
projectId,
|
|
26
|
+
channel: "memory",
|
|
27
|
+
senderSessionId: sessionId,
|
|
28
|
+
kind: "observation",
|
|
29
|
+
payload: JSON.stringify({
|
|
30
|
+
memoryId: obs.id,
|
|
31
|
+
content: obs.content,
|
|
32
|
+
relevance: obs.relevance,
|
|
33
|
+
sourceSessionId: sessionId,
|
|
34
|
+
originType,
|
|
35
|
+
timestamp: new Date().toISOString(),
|
|
36
|
+
}),
|
|
37
|
+
ttlSeconds,
|
|
38
|
+
});
|
|
39
|
+
debugLog("inter_agent.broadcast.sent", { memoryId: obs.id, sessionId });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -17,6 +17,13 @@ export interface ProjectObservationsStore {
|
|
|
17
17
|
createdAt: number;
|
|
18
18
|
sessionId: string;
|
|
19
19
|
}>;
|
|
20
|
+
getProjectObservationById(projectId: string, observationId: string): {
|
|
21
|
+
id: string;
|
|
22
|
+
content: string;
|
|
23
|
+
relevance: string;
|
|
24
|
+
createdAt: number;
|
|
25
|
+
sessionId: string;
|
|
26
|
+
} | null;
|
|
20
27
|
getProjectByCwd(cwd: string): string | null;
|
|
21
28
|
}
|
|
22
29
|
export declare function setProjectObsStore(store: ProjectObservationsStore): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-observations-store.d.ts","sourceRoot":"","sources":["../../src/memory/project-observations-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,wBAAwB;IACxC,yBAAyB,CACxB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,EACvE,SAAS,EAAE,MAAM,GACf,IAAI,CAAC;IACR,yBAAyB,CACxB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,MAAM,GACZ,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvF,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CAC5C;AAID,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,wBAAwB,GAAG,IAAI,CAExE;AAED,wBAAgB,kBAAkB,IAAI,wBAAwB,GAAG,IAAI,CAEpE"}
|
|
1
|
+
{"version":3,"file":"project-observations-store.d.ts","sourceRoot":"","sources":["../../src/memory/project-observations-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,wBAAwB;IACxC,yBAAyB,CACxB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,EACvE,SAAS,EAAE,MAAM,GACf,IAAI,CAAC;IACR,yBAAyB,CACxB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,MAAM,GACZ,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvF,yBAAyB,CACxB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACnB;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACnG,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CAC5C;AAID,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,wBAAwB,GAAG,IAAI,CAExE;AAED,wBAAgB,kBAAkB,IAAI,wBAAwB,GAAG,IAAI,CAEpE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/memory/prompts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,+QAA+Q,CAAC;AAE1S,eAAO,MAAM,yBAAyB,6oHAmD+F,CAAC;AAEtI,eAAO,MAAM,0BAA0B,67CAkB+F,CAAC;AAEvI,eAAO,MAAM,gBAAgB,8+CAasI,CAAC;AAEpK,eAAO,MAAM,eAAe,knTAoC2G,CAAC;AAExI,eAAO,MAAM,gBAAgB,69UA0DwH,CAAC;AAEtJ,eAAO,MAAM,aAAa,u2cAgFuP,CAAC;
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/memory/prompts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,+QAA+Q,CAAC;AAE1S,eAAO,MAAM,yBAAyB,6oHAmD+F,CAAC;AAEtI,eAAO,MAAM,0BAA0B,67CAkB+F,CAAC;AAEvI,eAAO,MAAM,gBAAgB,8+CAasI,CAAC;AAEpK,eAAO,MAAM,eAAe,knTAoC2G,CAAC;AAExI,eAAO,MAAM,gBAAgB,69UA0DwH,CAAC;AAEtJ,eAAO,MAAM,aAAa,u2cAgFuP,CAAC;AAiBlR,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAIlF;AASD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG/E;AAED,eAAO,MAAM,0BAA0B,07BAOoS,CAAC"}
|
package/dist/memory/prompts.js
CHANGED
|
@@ -261,11 +261,20 @@ What you CANNOT do:
|
|
|
261
261
|
It is valid to end a pass with zero drops if the pool genuinely has nothing more to cut — a follow-up pass will be skipped when a run returns zero drops. On late pressure passes, first re-check old [coverage: reinforced] and [coverage: cited] observations as active-memory redundancies before deciding there are no sound drops. Do not force drops you don't believe in.
|
|
262
262
|
|
|
263
263
|
Remember: pruning is active-memory management, not source deletion. A drop that looks reasonable at "low" still becomes a mistake if the content was a user correction with a mis-labeled relevance and no reflection captures it with equivalent fidelity. Read before you cut.`;
|
|
264
|
+
const REFLECTOR_UNIFIED_PASS = `Pass strategy — combined broad synthesis + atomic facts in a single pass.
|
|
265
|
+
|
|
266
|
+
Phase 1 — Multi-observation synthesis: First crystallize broad durable patterns, repeated preferences, recurring constraints, stable work style, and project-level themes supported by multiple observations. Every reflection in this phase must cite at least 2 distinct supportingObservationIds whose durable meaning is captured by the reflection. If an existing reflection already captures the pattern, repeat the exact same content when adding support ids materially improves active-memory coverage.
|
|
267
|
+
|
|
268
|
+
Phase 2 — Atomic durable facts + safety review: Then capture important durable facts that may be supported by a single authoritative observation: explicit user preferences, hard constraints, corrections, decisions, completed milestones, project facts, release or rollback caveats, important technical context, and other load-bearing facts future agents must not forget. Review high and critical observations against reflections created in phase 1, and catch durable information still missing. Strengthen existing or newly-created reflections by repeating exact reflection content with additional supportingObservationIds for high, critical, and old medium observations whose durable meaning is already captured by that reflection.
|
|
269
|
+
|
|
270
|
+
Do not duplicate earlier reflections; repeat exact existing content only to add missing support or promote no-provenance legacy memory. Create new reflections only when durable meaning is still missing. Do not create low-quality reflections just for coverage, and do not attach observations whose unique exact detail or current task state is not captured with equivalent fidelity.`;
|
|
264
271
|
const REFLECTOR_PASS_STRATEGIES = {
|
|
265
272
|
1: `Pass strategy — multi-observation synthesis. Find broad durable patterns, repeated preferences, recurring constraints, stable work style, and project-level themes supported by multiple observations. Every reflection recorded in this pass must cite at least 2 distinct supportingObservationIds whose durable meaning is captured by the reflection. Do not create one-off event summaries; leave important single-observation facts, safety review, and coverage strengthening for the final reflector pass. If an existing reflection already captures the pattern, repeat the exact same content when adding support ids materially improves active-memory coverage.`,
|
|
266
273
|
2: `Pass strategy — final atomic durable facts, safety review, and coverage strengthening. Capture important durable facts that may be supported by a single authoritative observation: explicit user preferences, hard constraints, corrections, decisions, completed milestones, project facts, release or rollback caveats, important technical context, and other load-bearing facts future agents must not forget. Review high and critical observations against current reflections, including reflections created in pass 1, and catch durable information still missing. Strengthen existing or newly-created reflections by repeating exact reflection content with additional supportingObservationIds for high, critical, and old medium observations whose durable meaning is already captured by that reflection. Do not duplicate earlier reflections; repeat exact existing content only to add missing support or promote no-provenance legacy memory. Create new reflections only when durable meaning is still missing. Do not create low-quality reflections just for coverage, and do not attach observations whose unique exact detail or current task state is not captured with equivalent fidelity.`,
|
|
267
274
|
};
|
|
268
275
|
export function buildReflectorPassGuidance(pass, maxPasses) {
|
|
276
|
+
if (maxPasses === 1)
|
|
277
|
+
return REFLECTOR_UNIFIED_PASS;
|
|
269
278
|
const tier = Math.min(2, Math.max(1, pass));
|
|
270
279
|
return `Pass ${pass} of up to ${maxPasses}. ${REFLECTOR_PASS_STRATEGIES[tier]}`;
|
|
271
280
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Type } from "../../sdk/ai/index.js";
|
|
2
|
+
import { type ExtensionAPI } from "../../sdk/coding-agent/index.js";
|
|
3
|
+
export declare const RECEIVE_AGENT_OBSERVATIONS_TOOL_NAME = "receive_agent_observations";
|
|
4
|
+
export interface AgentObservationPayload {
|
|
5
|
+
memoryId: string;
|
|
6
|
+
content: string;
|
|
7
|
+
relevance: "low" | "medium" | "high" | "critical";
|
|
8
|
+
sourceSessionId: string;
|
|
9
|
+
originType: "observation" | "reflection";
|
|
10
|
+
timestamp: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const receiveAgentObservationsTool: import("../../sdk/coding-agent/index.js").ToolDefinition<Type.TObject<{
|
|
13
|
+
since: Type.TOptional<Type.TNumber>;
|
|
14
|
+
limit: Type.TOptional<Type.TNumber>;
|
|
15
|
+
}>, unknown> & import("../../sdk/coding-agent/index.js").ToolDefinition<any, any>;
|
|
16
|
+
export declare function registerReceiveAgentObservationsTool(ext: ExtensionAPI): void;
|
|
17
|
+
//# sourceMappingURL=receive-agent-observations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receive-agent-observations.d.ts","sourceRoot":"","sources":["../../../src/memory/tools/receive-agent-observations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAIhF,eAAO,MAAM,oCAAoC,+BAA+B,CAAC;AAEjF,MAAM,WAAW,uBAAuB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IAClD,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,aAAa,GAAG,YAAY,CAAC;IACzC,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,4BAA4B;;;iFAmEvC,CAAC;AAEH,wBAAgB,oCAAoC,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAE5E"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Type } from "../../sdk/ai/index.js";
|
|
2
|
+
import { defineTool } from "../../sdk/coding-agent/index.js";
|
|
3
|
+
import { getProjectObsStore } from "../project-observations-store.js";
|
|
4
|
+
import { getInterAgentBroker } from "../inter-agent-broker-singleton.js";
|
|
5
|
+
export const RECEIVE_AGENT_OBSERVATIONS_TOOL_NAME = "receive_agent_observations";
|
|
6
|
+
export const receiveAgentObservationsTool = defineTool({
|
|
7
|
+
name: RECEIVE_AGENT_OBSERVATIONS_TOOL_NAME,
|
|
8
|
+
label: "Receive observations from other agents",
|
|
9
|
+
description: "Poll for observations shared by other active sessions on this project. " +
|
|
10
|
+
"Call this before starting work or when you suspect another agent has shared context.",
|
|
11
|
+
promptSnippet: "Use receive_agent_observations() to pull shared observations from other active sessions.",
|
|
12
|
+
promptGuidelines: [
|
|
13
|
+
"Call at the start of a session or task to pick up context shared by collaborators.",
|
|
14
|
+
"Deduplicate results by memory_id against observations already in your context.",
|
|
15
|
+
],
|
|
16
|
+
parameters: Type.Object({
|
|
17
|
+
since: Type.Optional(Type.Number({ description: "Optional timestamp (ms) to only fetch newer messages." })),
|
|
18
|
+
limit: Type.Optional(Type.Number({ default: 20 })),
|
|
19
|
+
}),
|
|
20
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
21
|
+
const store = getProjectObsStore();
|
|
22
|
+
const broker = getInterAgentBroker();
|
|
23
|
+
if (!store || !broker) {
|
|
24
|
+
return {
|
|
25
|
+
content: [{ type: "text", text: "Receiving is unavailable outside spectral serve." }],
|
|
26
|
+
details: { status: "unavailable", observations: [] },
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const projectId = store.getProjectByCwd(ctx.cwd);
|
|
30
|
+
const sessionId = ctx.sessionManager.getSessionId?.();
|
|
31
|
+
if (!projectId || !sessionId) {
|
|
32
|
+
return {
|
|
33
|
+
content: [{ type: "text", text: "No project/session context." }],
|
|
34
|
+
details: { status: "no_context", observations: [] },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const msgs = broker.poll({
|
|
38
|
+
projectId,
|
|
39
|
+
channel: "memory",
|
|
40
|
+
recipientSessionId: sessionId,
|
|
41
|
+
since: params.since,
|
|
42
|
+
limit: params.limit ?? 20,
|
|
43
|
+
markDelivered: true,
|
|
44
|
+
});
|
|
45
|
+
const observations = msgs
|
|
46
|
+
.filter((m) => m.kind === "observation")
|
|
47
|
+
.map((m) => JSON.parse(m.payload));
|
|
48
|
+
if (observations.length === 0) {
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: "text", text: "No new observations from other agents." }],
|
|
51
|
+
details: { status: "no_new", observations: [] },
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const lines = observations.map((o) => `[${o.relevance}] ${o.content} (from ${o.sourceSessionId}, id: \`${o.memoryId}\`)`);
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: "text",
|
|
59
|
+
text: `New shared observations:\n\n${lines.join("\n")}`,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
details: { status: "ok", observations },
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
export function registerReceiveAgentObservationsTool(ext) {
|
|
67
|
+
ext.registerTool(receiveAgentObservationsTool);
|
|
68
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Type } from "../../sdk/ai/index.js";
|
|
2
|
+
import { type ExtensionAPI } from "../../sdk/coding-agent/index.js";
|
|
3
|
+
export declare const SHARE_PROJECT_OBSERVATION_TOOL_NAME = "share_project_observation";
|
|
4
|
+
export declare const shareProjectObservationTool: import("../../sdk/coding-agent/index.js").ToolDefinition<Type.TObject<{
|
|
5
|
+
memory_id: Type.TString;
|
|
6
|
+
}>, unknown> & import("../../sdk/coding-agent/index.js").ToolDefinition<any, any>;
|
|
7
|
+
export declare function registerShareProjectObservationTool(ext: ExtensionAPI): void;
|
|
8
|
+
//# sourceMappingURL=share-project-observation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share-project-observation.d.ts","sourceRoot":"","sources":["../../../src/memory/tools/share-project-observation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAOhF,eAAO,MAAM,mCAAmC,8BAA8B,CAAC;AA6C/E,eAAO,MAAM,2BAA2B;;iFAqEtC,CAAC;AAEH,wBAAgB,mCAAmC,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAE3E"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Type } from "../../sdk/ai/index.js";
|
|
2
|
+
import { defineTool } from "../../sdk/coding-agent/index.js";
|
|
3
|
+
import { getProjectObsStore } from "../project-observations-store.js";
|
|
4
|
+
import { getInterAgentBroker } from "../inter-agent-broker-singleton.js";
|
|
5
|
+
import { getMemoryState } from "../branch.js";
|
|
6
|
+
import { RELEVANCE_VALUES } from "../types.js";
|
|
7
|
+
export const SHARE_PROJECT_OBSERVATION_TOOL_NAME = "share_project_observation";
|
|
8
|
+
function findObservationInBranch(branch, memoryId) {
|
|
9
|
+
if (!Array.isArray(branch))
|
|
10
|
+
return null;
|
|
11
|
+
const state = getMemoryState(branch);
|
|
12
|
+
for (const obs of state.committedObs) {
|
|
13
|
+
if (obs.id === memoryId) {
|
|
14
|
+
return { id: obs.id, content: obs.content, relevance: obs.relevance, originType: "observation" };
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
for (const obs of state.pendingObs) {
|
|
18
|
+
if (obs.id === memoryId) {
|
|
19
|
+
return { id: obs.id, content: obs.content, relevance: obs.relevance, originType: "observation" };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
for (const reflection of state.reflections) {
|
|
23
|
+
const id = typeof reflection === "string" ? undefined : reflection.id;
|
|
24
|
+
const content = typeof reflection === "string" ? reflection : reflection.content;
|
|
25
|
+
if (id === memoryId) {
|
|
26
|
+
return { id, content, relevance: "high", originType: "reflection" };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function findObservationInStore(store, projectId, memoryId) {
|
|
32
|
+
const obs = store.getProjectObservationById(projectId, memoryId);
|
|
33
|
+
if (!obs)
|
|
34
|
+
return null;
|
|
35
|
+
const relevance = RELEVANCE_VALUES.includes(obs.relevance)
|
|
36
|
+
? obs.relevance
|
|
37
|
+
: "medium";
|
|
38
|
+
return { id: obs.id, content: obs.content, relevance, originType: "observation" };
|
|
39
|
+
}
|
|
40
|
+
export const shareProjectObservationTool = defineTool({
|
|
41
|
+
name: SHARE_PROJECT_OBSERVATION_TOOL_NAME,
|
|
42
|
+
label: "Share observation with other agents",
|
|
43
|
+
description: "Broadcast a project observation or reflection to other active sessions working on this project. " +
|
|
44
|
+
"Use this when you discover a fact another agent should know immediately, " +
|
|
45
|
+
"rather than waiting for them to search project memory.",
|
|
46
|
+
promptSnippet: "Use share_project_observation(memory_id) to push a known observation to other active sessions.",
|
|
47
|
+
promptGuidelines: [
|
|
48
|
+
"Only share observations that are relevant to collaborators on the same project.",
|
|
49
|
+
"Prefer sharing high/critical relevance facts — avoid noise.",
|
|
50
|
+
"The memory_id must be a 12-character lowercase hex id from the current branch or project memory.",
|
|
51
|
+
],
|
|
52
|
+
parameters: Type.Object({
|
|
53
|
+
memory_id: Type.String({
|
|
54
|
+
pattern: "^[a-f0-9]{12}$",
|
|
55
|
+
description: "12-character observation/reflection id.",
|
|
56
|
+
}),
|
|
57
|
+
}),
|
|
58
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
59
|
+
const store = getProjectObsStore();
|
|
60
|
+
const broker = getInterAgentBroker();
|
|
61
|
+
if (!store || !broker) {
|
|
62
|
+
return {
|
|
63
|
+
content: [{ type: "text", text: "Sharing is unavailable outside spectral serve." }],
|
|
64
|
+
details: { status: "unavailable" },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const projectId = store.getProjectByCwd(ctx.cwd);
|
|
68
|
+
const sessionId = ctx.sessionManager.getSessionId?.();
|
|
69
|
+
if (!projectId || !sessionId) {
|
|
70
|
+
return {
|
|
71
|
+
content: [{ type: "text", text: "No project/session context." }],
|
|
72
|
+
details: { status: "no_context" },
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const branch = ctx.sessionManager.getBranch?.();
|
|
76
|
+
const obs = findObservationInBranch(branch, params.memory_id)
|
|
77
|
+
?? findObservationInStore(store, projectId, params.memory_id);
|
|
78
|
+
if (!obs) {
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: "text", text: `Observation \`${params.memory_id}\` not found.` }],
|
|
81
|
+
details: { status: "not_found" },
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
broker.send({
|
|
85
|
+
projectId,
|
|
86
|
+
channel: "memory",
|
|
87
|
+
senderSessionId: sessionId,
|
|
88
|
+
kind: "observation",
|
|
89
|
+
payload: JSON.stringify({
|
|
90
|
+
memoryId: obs.id,
|
|
91
|
+
content: obs.content,
|
|
92
|
+
relevance: obs.relevance,
|
|
93
|
+
sourceSessionId: sessionId,
|
|
94
|
+
originType: obs.originType,
|
|
95
|
+
timestamp: new Date().toISOString(),
|
|
96
|
+
}),
|
|
97
|
+
});
|
|
98
|
+
return {
|
|
99
|
+
content: [{ type: "text", text: `Shared observation \`${obs.id}\` with other project sessions.` }],
|
|
100
|
+
details: { status: "ok", memoryId: obs.id },
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
export function registerShareProjectObservationTool(ext) {
|
|
105
|
+
ext.registerTool(shareProjectObservationTool);
|
|
106
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Compaction — single LLM call replacing both:
|
|
3
|
+
* 1. Core spectral generateSummary() (narrative conversation summary)
|
|
4
|
+
* 2. Sync catch-up observer (observation extraction from gap entries)
|
|
5
|
+
*
|
|
6
|
+
* Uses a text-based delimited output format (compatible with any model
|
|
7
|
+
* without requiring native structured-output support):
|
|
8
|
+
*
|
|
9
|
+
* ===NARRATIVE===
|
|
10
|
+
* ## Goal
|
|
11
|
+
* ...
|
|
12
|
+
*
|
|
13
|
+
* ===OBSERVATIONS===
|
|
14
|
+
* [YYYY-MM-DD HH:MM] [relevance] Content line
|
|
15
|
+
* ...
|
|
16
|
+
*/
|
|
17
|
+
import type { AgentMessage, ThinkingLevel } from "../sdk/agent-core/index.js";
|
|
18
|
+
import type { Model } from "../sdk/ai/index.js";
|
|
19
|
+
import type { ObservationRecord } from "./types.js";
|
|
20
|
+
export interface UnifiedCompactionInput {
|
|
21
|
+
/** Messages to summarize (from core compaction preparation) */
|
|
22
|
+
messagesToSummarize: AgentMessage[];
|
|
23
|
+
/** Serialized gap entries as text with source entry labels */
|
|
24
|
+
gapChunk?: string;
|
|
25
|
+
/** Source entry IDs from gap entries */
|
|
26
|
+
gapSourceEntryIds?: string[];
|
|
27
|
+
/** Model to use */
|
|
28
|
+
model: Model<any>;
|
|
29
|
+
/** API key */
|
|
30
|
+
apiKey: string;
|
|
31
|
+
/** Request headers */
|
|
32
|
+
headers?: Record<string, string>;
|
|
33
|
+
/** Abort signal */
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
/** Previous compaction summary for iterative update */
|
|
36
|
+
previousSummary?: string;
|
|
37
|
+
/** Custom instructions for summarization focus */
|
|
38
|
+
customInstructions?: string;
|
|
39
|
+
/** Thinking level for reasoning models */
|
|
40
|
+
thinkingLevel?: ThinkingLevel;
|
|
41
|
+
/** Reserve tokens for prompt + output */
|
|
42
|
+
reserveTokens: number;
|
|
43
|
+
}
|
|
44
|
+
export interface UnifiedCompactionOutput {
|
|
45
|
+
/** Markdown narrative summary (for CompactionEntry.summary) */
|
|
46
|
+
narrativeSummary: string;
|
|
47
|
+
/** Observations extracted from the conversation */
|
|
48
|
+
observations: ObservationRecord[];
|
|
49
|
+
/** Files read */
|
|
50
|
+
readFiles: string[];
|
|
51
|
+
/** Files modified */
|
|
52
|
+
modifiedFiles: string[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Generate a unified compaction result: narrative summary + observations
|
|
56
|
+
* in a single LLM call. Uses delimited text output for broad model compatibility.
|
|
57
|
+
*/
|
|
58
|
+
export declare function generateUnifiedCompaction(input: UnifiedCompactionInput): Promise<UnifiedCompactionOutput>;
|
|
59
|
+
//# sourceMappingURL=unified-compaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unified-compaction.d.ts","sourceRoot":"","sources":["../../src/memory/unified-compaction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAUhD,OAAO,KAAK,EAAE,iBAAiB,EAAa,MAAM,YAAY,CAAC;AAkO/D,MAAM,WAAW,sBAAsB;IACtC,+DAA+D;IAC/D,mBAAmB,EAAE,YAAY,EAAE,CAAC;IACpC,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,mBAAmB;IACnB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,cAAc;IACd,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,mBAAmB;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kDAAkD;IAClD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0CAA0C;IAC1C,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACvC,+DAA+D;IAC/D,gBAAgB,EAAE,MAAM,CAAC;IACzB,mDAAmD;IACnD,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAClC,iBAAiB;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,qBAAqB;IACrB,aAAa,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC9C,KAAK,EAAE,sBAAsB,GAC3B,OAAO,CAAC,uBAAuB,CAAC,CA0IlC"}
|