memo-grafter 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/.env.example +3 -0
  2. package/LICENSE +21 -0
  3. package/README.md +182 -0
  4. package/USER_GUIDE.md +702 -0
  5. package/dist/MemoGrafter.d.ts +29 -0
  6. package/dist/MemoGrafter.d.ts.map +1 -0
  7. package/dist/MemoGrafter.js +106 -0
  8. package/dist/MemoGrafter.js.map +1 -0
  9. package/dist/MemoGrafterAgent.d.ts +18 -0
  10. package/dist/MemoGrafterAgent.d.ts.map +1 -0
  11. package/dist/MemoGrafterAgent.js +55 -0
  12. package/dist/MemoGrafterAgent.js.map +1 -0
  13. package/dist/adapters/OpenAIAdapter.d.ts +14 -0
  14. package/dist/adapters/OpenAIAdapter.d.ts.map +1 -0
  15. package/dist/adapters/OpenAIAdapter.js +37 -0
  16. package/dist/adapters/OpenAIAdapter.js.map +1 -0
  17. package/dist/adapters/types.d.ts +2 -0
  18. package/dist/adapters/types.d.ts.map +1 -0
  19. package/dist/adapters/types.js +2 -0
  20. package/dist/adapters/types.js.map +1 -0
  21. package/dist/fleet/ConductorAgent.d.ts +15 -0
  22. package/dist/fleet/ConductorAgent.d.ts.map +1 -0
  23. package/dist/fleet/ConductorAgent.js +41 -0
  24. package/dist/fleet/ConductorAgent.js.map +1 -0
  25. package/dist/fleet/FleetStore.d.ts +12 -0
  26. package/dist/fleet/FleetStore.d.ts.map +1 -0
  27. package/dist/fleet/FleetStore.js +30 -0
  28. package/dist/fleet/FleetStore.js.map +1 -0
  29. package/dist/fleet/MemoGrafterFleet.d.ts +20 -0
  30. package/dist/fleet/MemoGrafterFleet.d.ts.map +1 -0
  31. package/dist/fleet/MemoGrafterFleet.js +49 -0
  32. package/dist/fleet/MemoGrafterFleet.js.map +1 -0
  33. package/dist/fleet/WorkerAgent.d.ts +30 -0
  34. package/dist/fleet/WorkerAgent.d.ts.map +1 -0
  35. package/dist/fleet/WorkerAgent.js +95 -0
  36. package/dist/fleet/WorkerAgent.js.map +1 -0
  37. package/dist/fleet/types.d.ts +38 -0
  38. package/dist/fleet/types.d.ts.map +1 -0
  39. package/dist/fleet/types.js +2 -0
  40. package/dist/fleet/types.js.map +1 -0
  41. package/dist/index.d.ts +9 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +7 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/pipeline/GrafterPipeline.d.ts +16 -0
  46. package/dist/pipeline/GrafterPipeline.d.ts.map +1 -0
  47. package/dist/pipeline/GrafterPipeline.js +58 -0
  48. package/dist/pipeline/GrafterPipeline.js.map +1 -0
  49. package/dist/pipeline/IngestPipeline.d.ts +19 -0
  50. package/dist/pipeline/IngestPipeline.d.ts.map +1 -0
  51. package/dist/pipeline/IngestPipeline.js +44 -0
  52. package/dist/pipeline/IngestPipeline.js.map +1 -0
  53. package/dist/pipeline/SegmentProcessor.d.ts +19 -0
  54. package/dist/pipeline/SegmentProcessor.d.ts.map +1 -0
  55. package/dist/pipeline/SegmentProcessor.js +92 -0
  56. package/dist/pipeline/SegmentProcessor.js.map +1 -0
  57. package/dist/pipeline/TopicDriftDetector.d.ts +22 -0
  58. package/dist/pipeline/TopicDriftDetector.d.ts.map +1 -0
  59. package/dist/pipeline/TopicDriftDetector.js +96 -0
  60. package/dist/pipeline/TopicDriftDetector.js.map +1 -0
  61. package/dist/queue/IngestQueue.d.ts +16 -0
  62. package/dist/queue/IngestQueue.d.ts.map +1 -0
  63. package/dist/queue/IngestQueue.js +103 -0
  64. package/dist/queue/IngestQueue.js.map +1 -0
  65. package/dist/store/GraphStore.d.ts +71 -0
  66. package/dist/store/GraphStore.d.ts.map +1 -0
  67. package/dist/store/GraphStore.js +577 -0
  68. package/dist/store/GraphStore.js.map +1 -0
  69. package/dist/types.d.ts +84 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/dist/types.js +2 -0
  72. package/dist/types.js.map +1 -0
  73. package/dist/utils/drift/cosineSimilarity.d.ts +2 -0
  74. package/dist/utils/drift/cosineSimilarity.d.ts.map +1 -0
  75. package/dist/utils/drift/cosineSimilarity.js +12 -0
  76. package/dist/utils/drift/cosineSimilarity.js.map +1 -0
  77. package/dist/utils/drift/vectorAvg.d.ts +2 -0
  78. package/dist/utils/drift/vectorAvg.d.ts.map +1 -0
  79. package/dist/utils/drift/vectorAvg.js +11 -0
  80. package/dist/utils/drift/vectorAvg.js.map +1 -0
  81. package/dist/utils/normalizeText.d.ts +2 -0
  82. package/dist/utils/normalizeText.d.ts.map +1 -0
  83. package/dist/utils/normalizeText.js +14 -0
  84. package/dist/utils/normalizeText.js.map +1 -0
  85. package/dist/utils/vectorLiteral.d.ts +3 -0
  86. package/dist/utils/vectorLiteral.d.ts.map +1 -0
  87. package/dist/utils/vectorLiteral.js +18 -0
  88. package/dist/utils/vectorLiteral.js.map +1 -0
  89. package/package.json +55 -0
@@ -0,0 +1,38 @@
1
+ import type { AbsorbFromAgentOptions, InjectionResult, MemoGrafterConfig, Message, TopicNode } from "../types.js";
2
+ export interface FleetGraph {
3
+ id: string;
4
+ name?: string;
5
+ agents: FleetAgentInfo[];
6
+ }
7
+ export interface FleetAgentInfo {
8
+ id: string;
9
+ sessionId: string;
10
+ color: string;
11
+ }
12
+ export interface MemoGrafterFleetOptions {
13
+ id?: string;
14
+ name?: string;
15
+ }
16
+ export interface WorkerAgentConfig {
17
+ color: string;
18
+ sessionId?: string;
19
+ id?: string;
20
+ }
21
+ export interface ConductorGraftOptions {
22
+ topicIds?: string[];
23
+ prompt?: string;
24
+ minSimilarity?: number;
25
+ limit?: number;
26
+ }
27
+ export type FleetAbsorbOptions = AbsorbFromAgentOptions;
28
+ export interface FleetWorker {
29
+ getAgentId(): string;
30
+ getSessionId(): string;
31
+ getColor(): string;
32
+ invoke(userMessage: string): Promise<string>;
33
+ getHistory(): Message[];
34
+ getActiveNodes(): Promise<TopicNode[]>;
35
+ graft(topicIds?: string[]): Promise<InjectionResult>;
36
+ }
37
+ export type { MemoGrafterConfig };
38
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/fleet/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,eAAe,EAAE,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAElH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,kBAAkB,GAAG,sBAAsB,CAAC;AAExD,MAAM,WAAW,WAAW;IAC1B,UAAU,IAAI,MAAM,CAAC;IACrB,YAAY,IAAI,MAAM,CAAC;IACvB,QAAQ,IAAI,MAAM,CAAC;IACnB,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,UAAU,IAAI,OAAO,EAAE,CAAC;IACxB,cAAc,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACvC,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CACtD;AAED,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/fleet/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ export { MemoGrafterAgent } from "./MemoGrafterAgent.js";
2
+ export { MemoGrafter } from "./MemoGrafter.js";
3
+ export { ConductorAgent } from "./fleet/ConductorAgent.js";
4
+ export { MemoGrafterFleet } from "./fleet/MemoGrafterFleet.js";
5
+ export { WorkerAgent } from "./fleet/WorkerAgent.js";
6
+ export { OpenAIEmbedAdapter, OpenAILLMAdapter } from "./adapters/OpenAIAdapter.js";
7
+ export type { AbsorbFromAgentOptions, DriftMode, EmbedAdapter, InjectionResult, LLMAdapter, MemoGrafterConfig, MemoGrafterDriftConfig, MemoGrafterGraphConfig, MemoGrafterInjectConfig, MemoGrafterQueueConfig, Message, TopicEdge, TopicNode, TopicSegment, } from "./types.js";
8
+ export type { ConductorGraftOptions, FleetAbsorbOptions, FleetAgentInfo, FleetGraph, FleetWorker, MemoGrafterFleetOptions, WorkerAgentConfig, } from "./fleet/types.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACnF,YAAY,EACV,sBAAsB,EACtB,SAAS,EACT,YAAY,EACZ,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,OAAO,EACP,SAAS,EACT,SAAS,EACT,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,WAAW,EACX,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { MemoGrafterAgent } from "./MemoGrafterAgent.js";
2
+ export { MemoGrafter } from "./MemoGrafter.js";
3
+ export { ConductorAgent } from "./fleet/ConductorAgent.js";
4
+ export { MemoGrafterFleet } from "./fleet/MemoGrafterFleet.js";
5
+ export { WorkerAgent } from "./fleet/WorkerAgent.js";
6
+ export { OpenAIEmbedAdapter, OpenAILLMAdapter } from "./adapters/OpenAIAdapter.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { GraphStore } from "../store/GraphStore.js";
2
+ import type { InjectionResult } from "../types.js";
3
+ export declare class GrafterPipeline {
4
+ private store;
5
+ private config;
6
+ constructor(store: GraphStore, config: {
7
+ hopDepth: number;
8
+ bufferSize: number;
9
+ tokenBudget: number;
10
+ });
11
+ run(sessionId: string, topicIds: string[]): Promise<InjectionResult>;
12
+ private assemblePrompt;
13
+ private formatNode;
14
+ private countTokens;
15
+ }
16
+ //# sourceMappingURL=GrafterPipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrafterPipeline.d.ts","sourceRoot":"","sources":["../../src/pipeline/GrafterPipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAsB,MAAM,aAAa,CAAC;AAEvE,qBAAa,eAAe;IAExB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;gBADN,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;KACrB;IAGG,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC;YA4B5D,cAAc;IAqB5B,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,WAAW;CAGpB"}
@@ -0,0 +1,58 @@
1
+ export class GrafterPipeline {
2
+ store;
3
+ config;
4
+ constructor(store, config) {
5
+ this.store = store;
6
+ this.config = config;
7
+ }
8
+ async run(sessionId, topicIds) {
9
+ if (topicIds.length === 0) {
10
+ return { systemPrompt: "", nodes: [], tokenCount: 0 };
11
+ }
12
+ const neighbourhood = await this.store.getNeighbours(topicIds, this.config.hopDepth, sessionId);
13
+ const nodes = neighbourhood.sort((a, b) => a.messageRange[0] - b.messageRange[0]
14
+ || a.messageRange[1] - b.messageRange[1]
15
+ || a.topicOrder - b.topicOrder);
16
+ const fittedNodes = [...nodes];
17
+ let systemPrompt = await this.assemblePrompt(sessionId, fittedNodes);
18
+ let tokenCount = this.countTokens(systemPrompt);
19
+ while (tokenCount > this.config.tokenBudget && fittedNodes.length > 0) {
20
+ fittedNodes.pop();
21
+ systemPrompt = await this.assemblePrompt(sessionId, fittedNodes);
22
+ tokenCount = this.countTokens(systemPrompt);
23
+ }
24
+ return {
25
+ systemPrompt,
26
+ nodes: fittedNodes,
27
+ tokenCount,
28
+ };
29
+ }
30
+ async assemblePrompt(sessionId, nodes) {
31
+ if (nodes.length === 0)
32
+ return "";
33
+ const blocks = [];
34
+ for (const node of nodes) {
35
+ const start = Math.max(0, node.messageRange[0] - this.config.bufferSize);
36
+ const end = node.messageRange[1] + this.config.bufferSize;
37
+ const messages = await this.store.getBufferMessages(sessionId, start, end);
38
+ blocks.push(this.formatNode(node, messages));
39
+ }
40
+ return [
41
+ "MemoGrafter retrieved memory context:",
42
+ "Use these memories as prior conversation context when answering the user.",
43
+ "If the user asks what you remember, answer from these memories instead of saying you have no record.",
44
+ "",
45
+ blocks.join("\n---\n"),
46
+ ].join("\n");
47
+ }
48
+ formatNode(node, messages) {
49
+ const context = messages
50
+ .map((message) => `${message.role}: ${message.content}`)
51
+ .join("\n");
52
+ return `[Topic: ${node.label}]\nSummary: ${node.summary}\nContext:\n${context}`;
53
+ }
54
+ countTokens(prompt) {
55
+ return Math.ceil(prompt.length / 4);
56
+ }
57
+ }
58
+ //# sourceMappingURL=GrafterPipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrafterPipeline.js","sourceRoot":"","sources":["../../src/pipeline/GrafterPipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { GraphStore } from "../store/GraphStore.js";
2
+ import type { EmbedAdapter, LLMAdapter, Message, TopicNode } from "../types.js";
3
+ export declare class IngestPipeline {
4
+ private readonly store;
5
+ private readonly embedder;
6
+ private readonly config;
7
+ private readonly driftDetector;
8
+ private readonly segmentProcessor;
9
+ constructor(store: GraphStore, llm: LLMAdapter, embedder: EmbedAdapter, config: {
10
+ windowSize: number;
11
+ threshold: number;
12
+ topK: number;
13
+ mode: "window" | "intent";
14
+ minSegmentMessages: number;
15
+ });
16
+ run(messages: Message[], sessionId: string): Promise<TopicNode[]>;
17
+ private embedMessage;
18
+ }
19
+ //# sourceMappingURL=IngestPipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IngestPipeline.d.ts","sourceRoot":"","sources":["../../src/pipeline/IngestPipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAKhF,qBAAa,cAAc;IAKvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAEtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPzB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;gBAGjC,KAAK,EAAE,UAAU,EAClC,GAAG,EAAE,UAAU,EACE,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;QAC1B,kBAAkB,EAAE,MAAM,CAAC;KAC5B;IAcG,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;YAmBzD,YAAY;CAI3B"}
@@ -0,0 +1,44 @@
1
+ import { normalizeText } from "../utils/normalizeText.js";
2
+ import { SegmentProcessor } from "./SegmentProcessor.js";
3
+ import { TopicDriftDetector } from "./TopicDriftDetector.js";
4
+ export class IngestPipeline {
5
+ store;
6
+ embedder;
7
+ config;
8
+ driftDetector;
9
+ segmentProcessor;
10
+ constructor(store, llm, embedder, config) {
11
+ this.store = store;
12
+ this.embedder = embedder;
13
+ this.config = config;
14
+ this.driftDetector = new TopicDriftDetector({
15
+ windowSize: config.windowSize,
16
+ threshold: config.threshold,
17
+ mode: config.mode,
18
+ minSegmentMessages: config.minSegmentMessages,
19
+ });
20
+ this.segmentProcessor = new SegmentProcessor(store, llm, embedder, {
21
+ topK: config.topK,
22
+ semanticThreshold: 0.6,
23
+ });
24
+ }
25
+ async run(messages, sessionId) {
26
+ if (messages.length === 0)
27
+ return [];
28
+ await this.store.saveMessages(sessionId, messages);
29
+ await this.store.clearSession(sessionId);
30
+ const embeddings = await Promise.all(messages.map((message) => this.embedMessage(message)));
31
+ const segments = this.driftDetector.detectSegments(messages, embeddings);
32
+ const nodes = [];
33
+ for (const segment of segments) {
34
+ nodes.push(await this.segmentProcessor.process(segment, messages, sessionId));
35
+ }
36
+ await this.store.rebuildEdgesForSession(sessionId, this.config.topK);
37
+ return nodes;
38
+ }
39
+ async embedMessage(message) {
40
+ const content = normalizeText(message.content) ?? message.content;
41
+ return this.embedder.embed(content);
42
+ }
43
+ }
44
+ //# sourceMappingURL=IngestPipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IngestPipeline.js","sourceRoot":"","sources":["../../src/pipeline/IngestPipeline.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,MAAM,OAAO,cAAc;IAKN;IAEA;IACA;IAPF,aAAa,CAAqB;IAClC,gBAAgB,CAAmB;IAEpD,YACmB,KAAiB,EAClC,GAAe,EACE,QAAsB,EACtB,MAMhB;QATgB,UAAK,GAAL,KAAK,CAAY;QAEjB,aAAQ,GAAR,QAAQ,CAAc;QACtB,WAAM,GAAN,MAAM,CAMtB;QAED,IAAI,CAAC,aAAa,GAAG,IAAI,kBAAkB,CAAC;YAC1C,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;SAC9C,CAAC,CAAC;QACH,IAAI,CAAC,gBAAgB,GAAG,IAAI,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE;YACjE,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,iBAAiB,EAAE,GAAG;SACvB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,QAAmB,EAAE,SAAiB;QAC9C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAErC,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACnD,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAEzC,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC5F,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QACzE,MAAM,KAAK,GAAgB,EAAE,CAAC;QAE9B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;QAChF,CAAC;QAED,MAAM,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAErE,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,OAAgB;QACzC,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC;QAClE,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ import type { GraphStore } from "../store/GraphStore.js";
2
+ import type { EmbedAdapter, LLMAdapter, Message, TopicNode } from "../types.js";
3
+ import type { DriftSegment } from "./TopicDriftDetector.js";
4
+ export declare class SegmentProcessor {
5
+ private readonly store;
6
+ private readonly llm;
7
+ private readonly embedder;
8
+ private readonly config;
9
+ constructor(store: GraphStore, llm: LLMAdapter, embedder: EmbedAdapter, config: {
10
+ topK: number;
11
+ semanticThreshold: number;
12
+ });
13
+ process(segment: DriftSegment, messages: Message[], sessionId: string): Promise<TopicNode>;
14
+ private createSegment;
15
+ private nodeRunner;
16
+ private nodeProcessor;
17
+ private parseExtraction;
18
+ }
19
+ //# sourceMappingURL=SegmentProcessor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SegmentProcessor.d.ts","sourceRoot":"","sources":["../../src/pipeline/SegmentProcessor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAgB,MAAM,aAAa,CAAC;AAE9F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAHN,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,UAAU,EACf,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,iBAAiB,EAAE,MAAM,CAAC;KAC3B;IAGG,OAAO,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;YAKlF,aAAa;YAYb,UAAU;YAMV,aAAa;IA8C3B,OAAO,CAAC,eAAe;CAiBxB"}
@@ -0,0 +1,92 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { normalizeText } from "../utils/normalizeText.js";
3
+ export class SegmentProcessor {
4
+ store;
5
+ llm;
6
+ embedder;
7
+ config;
8
+ constructor(store, llm, embedder, config) {
9
+ this.store = store;
10
+ this.llm = llm;
11
+ this.embedder = embedder;
12
+ this.config = config;
13
+ }
14
+ async process(segment, messages, sessionId) {
15
+ const savedSegment = await this.createSegment(segment, sessionId);
16
+ return this.nodeRunner(savedSegment, messages);
17
+ }
18
+ async createSegment(segment, sessionId) {
19
+ return this.store.saveSegment({
20
+ id: randomUUID(),
21
+ sessionId,
22
+ startIndex: segment.start,
23
+ endIndex: segment.end,
24
+ topicOrder: segment.topicOrder,
25
+ driftScore: segment.driftScore,
26
+ createdAt: new Date(),
27
+ });
28
+ }
29
+ async nodeRunner(segment, messages) {
30
+ const node = await this.nodeProcessor(messages, segment);
31
+ await this.store.saveNode(node);
32
+ return node;
33
+ }
34
+ async nodeProcessor(messages, segment) {
35
+ const segmentMessages = messages.slice(segment.startIndex, segment.endIndex + 1);
36
+ const messageContent = segmentMessages
37
+ .map((message, index) => `Message ${index + 1}:\n[${message.role}] ${normalizeText(message.content) ?? message.content}`)
38
+ .join("\n\n");
39
+ const extractionPrompt = [
40
+ "Analyze this conversation segment and extract structured memory for a future chatbot.",
41
+ "",
42
+ "Identify:",
43
+ "- The core topic being discussed",
44
+ "- What the user wanted to know, do, or accomplish",
45
+ "- What the assistant provided, decided, or concluded",
46
+ "- Any unresolved questions or open threads",
47
+ "",
48
+ "Respond only in this exact format with no extra text:",
49
+ "LABEL: <3-6 word topic label>",
50
+ "USER_INTENT: <two-three sentences describing what the user was trying to achieve or understand>",
51
+ "OUTCOME: <one-two sentences describing what was concluded, decided, or provided>",
52
+ "OPEN: <one sentence describing any unresolved question or follow-up, or None if fully resolved>",
53
+ "",
54
+ "Conversation segment:",
55
+ messageContent,
56
+ ].join("\n");
57
+ const raw = await this.llm.complete([{ role: "user", content: extractionPrompt }]);
58
+ const extracted = this.parseExtraction(raw);
59
+ const embedding = await this.embedder.embed(extracted.summary);
60
+ return {
61
+ id: randomUUID(),
62
+ sessionId: segment.sessionId,
63
+ segmentId: segment.id,
64
+ label: extracted.label,
65
+ summary: extracted.summary,
66
+ embedding,
67
+ messageRange: [segment.startIndex, segment.endIndex],
68
+ topicOrder: segment.topicOrder,
69
+ driftScore: segment.driftScore,
70
+ agentColor: null,
71
+ fleetId: null,
72
+ agentId: null,
73
+ createdAt: new Date(),
74
+ };
75
+ }
76
+ parseExtraction(raw) {
77
+ const label = raw.match(/^LABEL:\s*(.+)$/im)?.[1]?.trim() ?? "Unknown";
78
+ const userIntent = raw.match(/^USER_INTENT:\s*(.+)$/im)?.[1]?.trim() ?? "";
79
+ const outcome = raw.match(/^OUTCOME:\s*(.+)$/im)?.[1]?.trim() ?? "";
80
+ const open = raw.match(/^OPEN:\s*(.+)$/im)?.[1]?.trim() ?? "";
81
+ const parts = [
82
+ userIntent && `User wanted: ${userIntent}`,
83
+ outcome && `Outcome: ${outcome}`,
84
+ open && open.toLowerCase() !== "none" && `Still open: ${open}`,
85
+ ].filter(Boolean);
86
+ return {
87
+ label,
88
+ summary: parts.join(" "),
89
+ };
90
+ }
91
+ }
92
+ //# sourceMappingURL=SegmentProcessor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SegmentProcessor.js","sourceRoot":"","sources":["../../src/pipeline/SegmentProcessor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { DriftMode, Message } from "../types.js";
2
+ export interface DriftSegment {
3
+ start: number;
4
+ end: number;
5
+ topicOrder: number;
6
+ driftScore: number;
7
+ }
8
+ export declare class TopicDriftDetector {
9
+ private readonly config;
10
+ constructor(config: {
11
+ windowSize: number;
12
+ threshold: number;
13
+ mode: DriftMode;
14
+ minSegmentMessages: number;
15
+ });
16
+ detect(messages: Message[], embeddings: number[][]): number[];
17
+ detectSegments(messages: Message[], embeddings: number[][]): DriftSegment[];
18
+ private detectBoundaries;
19
+ private detectIntentBoundaries;
20
+ private detectWindowBoundaries;
21
+ }
22
+ //# sourceMappingURL=TopicDriftDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TopicDriftDetector.d.ts","sourceRoot":"","sources":["../../src/pipeline/TopicDriftDetector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAItD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAOD,qBAAa,kBAAkB;IAE3B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,SAAS,CAAC;QAChB,kBAAkB,EAAE,MAAM,CAAC;KAC5B;IAGH,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE;IAI7D,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,GAAG,YAAY,EAAE;IA8B3E,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,sBAAsB;IA+B9B,OAAO,CAAC,sBAAsB;CA8B/B"}
@@ -0,0 +1,96 @@
1
+ import { cosineSimilarity } from "../utils/drift/cosineSimilarity.js";
2
+ import { avg } from "../utils/drift/vectorAvg.js";
3
+ export class TopicDriftDetector {
4
+ config;
5
+ constructor(config) {
6
+ this.config = config;
7
+ }
8
+ detect(messages, embeddings) {
9
+ return this.detectBoundaries(messages, embeddings).map((boundary) => boundary.index);
10
+ }
11
+ detectSegments(messages, embeddings) {
12
+ if (messages.length === 0)
13
+ return [];
14
+ const boundaries = this.detectBoundaries(messages, embeddings);
15
+ const segments = [];
16
+ let start = 0;
17
+ for (const [index, boundary] of boundaries.entries()) {
18
+ const end = boundary.index - 1;
19
+ if (end >= start) {
20
+ segments.push({
21
+ start,
22
+ end,
23
+ topicOrder: index + 1,
24
+ driftScore: boundary.score,
25
+ });
26
+ }
27
+ start = boundary.index;
28
+ }
29
+ segments.push({
30
+ start,
31
+ end: messages.length - 1,
32
+ topicOrder: segments.length + 1,
33
+ driftScore: 0,
34
+ });
35
+ return segments;
36
+ }
37
+ detectBoundaries(messages, embeddings) {
38
+ if (this.config.mode === "intent") {
39
+ return this.detectIntentBoundaries(messages, embeddings);
40
+ }
41
+ return this.detectWindowBoundaries(messages, embeddings);
42
+ }
43
+ detectIntentBoundaries(messages, embeddings) {
44
+ const boundaries = [];
45
+ let segmentStart = 0;
46
+ let topicEmbeddings = [];
47
+ for (let index = 0; index < messages.length; index += 1) {
48
+ const message = messages[index];
49
+ const embedding = embeddings[index];
50
+ if (!message || !embedding || message.role !== "user")
51
+ continue;
52
+ if (topicEmbeddings.length === 0) {
53
+ topicEmbeddings = [embedding];
54
+ continue;
55
+ }
56
+ const driftScore = 1 - cosineSimilarity(avg(topicEmbeddings), embedding);
57
+ const segmentLength = index - segmentStart;
58
+ if (driftScore > this.config.threshold && segmentLength >= this.config.minSegmentMessages) {
59
+ boundaries.push({ index, score: driftScore });
60
+ segmentStart = index;
61
+ topicEmbeddings = [embedding];
62
+ continue;
63
+ }
64
+ topicEmbeddings.push(embedding);
65
+ }
66
+ return boundaries;
67
+ }
68
+ detectWindowBoundaries(messages, embeddings) {
69
+ const boundaries = [];
70
+ const halfWindowSize = Math.floor(this.config.windowSize / 2);
71
+ if (halfWindowSize < 1)
72
+ return boundaries;
73
+ let segmentStart = 0;
74
+ let window = [];
75
+ for (let index = 0; index < messages.length; index += 1) {
76
+ const embedding = embeddings[index];
77
+ if (!embedding)
78
+ continue;
79
+ window = [...window, { index, embedding }].slice(-this.config.windowSize);
80
+ if (window.length < this.config.windowSize)
81
+ continue;
82
+ const previous = window.slice(0, halfWindowSize).map((item) => item.embedding);
83
+ const current = window.slice(-halfWindowSize).map((item) => item.embedding);
84
+ const driftScore = 1 - cosineSimilarity(avg(previous), avg(current));
85
+ const boundaryIndex = window.at(-halfWindowSize)?.index ?? index;
86
+ const segmentLength = boundaryIndex - segmentStart;
87
+ if (driftScore > this.config.threshold && segmentLength >= this.config.minSegmentMessages) {
88
+ boundaries.push({ index: boundaryIndex, score: driftScore });
89
+ segmentStart = boundaryIndex;
90
+ window = window.filter((item) => item.index >= boundaryIndex);
91
+ }
92
+ }
93
+ return boundaries;
94
+ }
95
+ }
96
+ //# sourceMappingURL=TopicDriftDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TopicDriftDetector.js","sourceRoot":"","sources":["../../src/pipeline/TopicDriftDetector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { IngestPipeline } from "../pipeline/IngestPipeline.js";
2
+ import type { MemoGrafterQueueConfig, Message } from "../types.js";
3
+ export declare class IngestQueue {
4
+ private readonly pipeline;
5
+ private readonly connection;
6
+ private readonly queue;
7
+ private worker;
8
+ private readonly defaultJobOptions;
9
+ private readonly queueName;
10
+ constructor(pipeline: IngestPipeline, config: MemoGrafterQueueConfig);
11
+ enqueue(messages: Message[], sessionId: string): Promise<void>;
12
+ close(): Promise<void>;
13
+ private ensureWorker;
14
+ private withTimeout;
15
+ }
16
+ //# sourceMappingURL=IngestQueue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IngestQueue.d.ts","sourceRoot":"","sources":["../../src/queue/IngestQueue.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAOnE,qBAAa,WAAW;IAQpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAP3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;IAC7C,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAc;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAGhB,QAAQ,EAAE,cAAc,EACzC,MAAM,EAAE,sBAAsB;IAgC1B,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB9D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB5B,OAAO,CAAC,YAAY;YAwBN,WAAW;CAY1B"}
@@ -0,0 +1,103 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { Queue, Worker } from "bullmq";
3
+ import { Redis } from "ioredis";
4
+ export class IngestQueue {
5
+ pipeline;
6
+ connection;
7
+ queue;
8
+ worker = null;
9
+ defaultJobOptions;
10
+ queueName;
11
+ constructor(pipeline, config) {
12
+ this.pipeline = pipeline;
13
+ this.queueName = config.queueName ?? `mg-ingest-${randomUUID()}`;
14
+ this.connection = new Redis(config.redisUrl, {
15
+ enableOfflineQueue: false,
16
+ maxRetriesPerRequest: null,
17
+ retryStrategy: () => null,
18
+ });
19
+ this.connection.on("error", (error) => {
20
+ console.warn("MemoGrafter ingest queue Redis warning:", error.message);
21
+ });
22
+ this.defaultJobOptions = {
23
+ attempts: 3,
24
+ backoff: {
25
+ type: "exponential",
26
+ delay: 1000,
27
+ },
28
+ removeOnComplete: config.removeOnComplete ?? true,
29
+ removeOnFail: config.removeOnFail ?? true,
30
+ };
31
+ this.queue = new Queue(this.queueName, {
32
+ connection: this.connection,
33
+ defaultJobOptions: this.defaultJobOptions,
34
+ });
35
+ this.queue.on("error", (error) => {
36
+ console.warn("MemoGrafter ingest queue warning:", error.message);
37
+ });
38
+ }
39
+ async enqueue(messages, sessionId) {
40
+ try {
41
+ await this.withTimeout(this.queue.add("ingest", {
42
+ messages: [...messages],
43
+ sessionId,
44
+ }, this.defaultJobOptions), 1000, "MemoGrafter ingest queue enqueue timed out.");
45
+ this.ensureWorker();
46
+ }
47
+ catch (error) {
48
+ console.warn("MemoGrafter ingest queue enqueue failed:", error);
49
+ }
50
+ }
51
+ async close() {
52
+ if (this.worker) {
53
+ await this.withTimeout(this.worker.close(false), 10000, "MemoGrafter ingest queue worker close timed out.").catch((error) => {
54
+ console.warn("MemoGrafter ingest queue worker close warning:", error);
55
+ });
56
+ }
57
+ await this.withTimeout(this.queue.close(), 1000, "MemoGrafter ingest queue close timed out.").catch((error) => {
58
+ console.warn("MemoGrafter ingest queue close warning:", error);
59
+ });
60
+ if (this.worker) {
61
+ await Promise.resolve(this.worker.disconnect()).catch((error) => {
62
+ console.warn("MemoGrafter ingest queue worker disconnect warning:", error);
63
+ });
64
+ }
65
+ await Promise.resolve(this.queue.disconnect()).catch((error) => {
66
+ console.warn("MemoGrafter ingest queue disconnect warning:", error);
67
+ });
68
+ this.connection.disconnect();
69
+ }
70
+ ensureWorker() {
71
+ if (this.worker)
72
+ return;
73
+ this.worker = new Worker(this.queueName, async (job) => {
74
+ try {
75
+ await this.pipeline.run(job.data.messages, job.data.sessionId);
76
+ }
77
+ catch (error) {
78
+ console.warn("MemoGrafter background ingest failed:", error);
79
+ throw error;
80
+ }
81
+ }, { connection: this.connection });
82
+ this.worker.on("failed", (_job, error) => {
83
+ console.warn("MemoGrafter ingest queue worker warning:", error.message);
84
+ });
85
+ this.worker.on("error", (error) => {
86
+ console.warn("MemoGrafter ingest queue worker warning:", error.message);
87
+ });
88
+ }
89
+ async withTimeout(promise, milliseconds, message) {
90
+ let timeout;
91
+ const timeoutPromise = new Promise((_, reject) => {
92
+ timeout = setTimeout(() => reject(new Error(message)), milliseconds);
93
+ });
94
+ try {
95
+ return await Promise.race([promise, timeoutPromise]);
96
+ }
97
+ finally {
98
+ if (timeout)
99
+ clearTimeout(timeout);
100
+ }
101
+ }
102
+ }
103
+ //# sourceMappingURL=IngestQueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IngestQueue.js","sourceRoot":"","sources":["../../src/queue/IngestQueue.ts"],"names":[],"mappings":"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"}