opencode-graphiti 0.1.0 → 0.1.2

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 (72) hide show
  1. package/README.md +44 -27
  2. package/esm/src/config.d.ts +3 -0
  3. package/esm/src/config.d.ts.map +1 -1
  4. package/esm/src/config.js +21 -35
  5. package/esm/src/handlers/chat.d.ts +21 -0
  6. package/esm/src/handlers/chat.d.ts.map +1 -0
  7. package/esm/src/handlers/chat.js +127 -0
  8. package/esm/src/handlers/compacting.d.ts +15 -0
  9. package/esm/src/handlers/compacting.d.ts.map +1 -0
  10. package/esm/src/handlers/compacting.js +29 -0
  11. package/esm/src/handlers/event.d.ts +18 -0
  12. package/esm/src/handlers/event.d.ts.map +1 -0
  13. package/esm/src/handlers/event.js +132 -0
  14. package/esm/src/index.d.ts +3 -1
  15. package/esm/src/index.d.ts.map +1 -1
  16. package/esm/src/index.js +28 -419
  17. package/esm/src/services/client.d.ts +33 -5
  18. package/esm/src/services/client.d.ts.map +1 -1
  19. package/esm/src/services/client.js +42 -20
  20. package/esm/src/services/compaction.d.ts +18 -69
  21. package/esm/src/services/compaction.d.ts.map +1 -1
  22. package/esm/src/services/compaction.js +86 -112
  23. package/esm/src/services/context-limit.d.ts +14 -0
  24. package/esm/src/services/context-limit.d.ts.map +1 -0
  25. package/esm/src/services/context-limit.js +41 -0
  26. package/esm/src/services/context.d.ts +5 -0
  27. package/esm/src/services/context.d.ts.map +1 -1
  28. package/esm/src/services/context.js +19 -16
  29. package/esm/src/session.d.ts +90 -0
  30. package/esm/src/session.d.ts.map +1 -0
  31. package/esm/src/session.js +304 -0
  32. package/esm/src/types/index.d.ts +28 -9
  33. package/esm/src/types/index.d.ts.map +1 -1
  34. package/esm/src/utils.d.ts +21 -0
  35. package/esm/src/utils.d.ts.map +1 -0
  36. package/esm/src/utils.js +34 -0
  37. package/package.json +3 -2
  38. package/script/src/config.d.ts +3 -0
  39. package/script/src/config.d.ts.map +1 -1
  40. package/script/src/config.js +21 -35
  41. package/script/src/handlers/chat.d.ts +21 -0
  42. package/script/src/handlers/chat.d.ts.map +1 -0
  43. package/script/src/handlers/chat.js +130 -0
  44. package/script/src/handlers/compacting.d.ts +15 -0
  45. package/script/src/handlers/compacting.d.ts.map +1 -0
  46. package/script/src/handlers/compacting.js +32 -0
  47. package/script/src/handlers/event.d.ts +18 -0
  48. package/script/src/handlers/event.d.ts.map +1 -0
  49. package/script/src/handlers/event.js +135 -0
  50. package/script/src/index.d.ts +3 -1
  51. package/script/src/index.d.ts.map +1 -1
  52. package/script/src/index.js +30 -422
  53. package/script/src/services/client.d.ts +33 -5
  54. package/script/src/services/client.d.ts.map +1 -1
  55. package/script/src/services/client.js +42 -53
  56. package/script/src/services/compaction.d.ts +18 -69
  57. package/script/src/services/compaction.d.ts.map +1 -1
  58. package/script/src/services/compaction.js +86 -113
  59. package/script/src/services/context-limit.d.ts +14 -0
  60. package/script/src/services/context-limit.d.ts.map +1 -0
  61. package/script/src/services/context-limit.js +45 -0
  62. package/script/src/services/context.d.ts +5 -0
  63. package/script/src/services/context.d.ts.map +1 -1
  64. package/script/src/services/context.js +22 -16
  65. package/script/src/session.d.ts +90 -0
  66. package/script/src/session.d.ts.map +1 -0
  67. package/script/src/session.js +308 -0
  68. package/script/src/types/index.d.ts +28 -9
  69. package/script/src/types/index.d.ts.map +1 -1
  70. package/script/src/utils.d.ts +21 -0
  71. package/script/src/utils.d.ts.map +1 -0
  72. package/script/src/utils.js +44 -0
@@ -1,66 +1,7 @@
1
- import type { GraphitiConfig } from "../types/index.js";
2
- export interface CompactionDependencies {
3
- sdkClient: {
4
- session: {
5
- summarize: (options: {
6
- path: {
7
- id: string;
8
- };
9
- body?: {
10
- providerID: string;
11
- modelID: string;
12
- };
13
- query?: {
14
- directory?: string;
15
- };
16
- }) => Promise<unknown>;
17
- promptAsync: (options: {
18
- path: {
19
- id: string;
20
- };
21
- body?: {
22
- parts: Array<{
23
- type: "text";
24
- text: string;
25
- }>;
26
- };
27
- query?: {
28
- directory?: string;
29
- };
30
- }) => Promise<unknown>;
31
- };
32
- tui: {
33
- showToast: (options?: {
34
- body?: {
35
- title?: string;
36
- message: string;
37
- variant: "info" | "success" | "warning" | "error";
38
- duration?: number;
39
- };
40
- query?: {
41
- directory?: string;
42
- };
43
- }) => Promise<unknown>;
44
- };
45
- provider: {
46
- list: (options?: {
47
- directory?: string;
48
- }) => Promise<unknown>;
49
- };
50
- };
51
- directory: string;
52
- }
53
- export declare function createPreemptiveCompactionHandler(config: Pick<GraphitiConfig, "compactionThreshold" | "minTokensForCompaction" | "compactionCooldownMs" | "autoResumeAfterCompaction">, deps: CompactionDependencies): {
54
- checkAndTriggerCompaction(sessionId: string, tokens: {
55
- input: number;
56
- output: number;
57
- reasoning: number;
58
- cache: {
59
- read: number;
60
- write: number;
61
- };
62
- }, providerID: string, modelID: string): Promise<void>;
63
- };
1
+ import type { GraphitiFact, GraphitiNode } from "../types/index.js";
2
+ /**
3
+ * Persist a compaction summary episode when enabled.
4
+ */
64
5
  export declare function handleCompaction(params: {
65
6
  client: {
66
7
  addEpisode: (args: {
@@ -71,23 +12,31 @@ export declare function handleCompaction(params: {
71
12
  sourceDescription?: string;
72
13
  }) => Promise<void>;
73
14
  };
74
- config: GraphitiConfig;
75
15
  groupId: string;
76
16
  summary: string;
77
17
  sessionId: string;
78
18
  }): Promise<void>;
19
+ /**
20
+ * Retrieve persistent fact context to include during compaction.
21
+ */
79
22
  export declare function getCompactionContext(params: {
80
23
  client: {
81
24
  searchFacts: (args: {
82
25
  query: string;
83
26
  groupIds?: string[];
84
27
  maxFacts?: number;
85
- }) => Promise<Array<{
86
- fact: string;
87
- }>>;
28
+ }) => Promise<GraphitiFact[]>;
29
+ searchNodes: (args: {
30
+ query: string;
31
+ groupIds?: string[];
32
+ maxNodes?: number;
33
+ }) => Promise<GraphitiNode[]>;
34
+ };
35
+ characterBudget: number;
36
+ groupIds: {
37
+ project: string;
38
+ user?: string;
88
39
  };
89
- config: GraphitiConfig;
90
- groupId: string;
91
40
  contextStrings: string[];
92
41
  }): Promise<string[]>;
93
42
  //# sourceMappingURL=compaction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../../src/src/services/compaction.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../../src/src/services/compaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAIpE;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,MAAM,EAAE;QACN,UAAU,EAAE,CAAC,IAAI,EAAE;YACjB,IAAI,EAAE,MAAM,CAAC;YACb,WAAW,EAAE,MAAM,CAAC;YACpB,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;YACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;SAC5B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACrB,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,MAAM,EAAE;QACN,WAAW,EAAE,CAAC,IAAI,EAAE;YAClB,KAAK,EAAE,MAAM,CAAC;YACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;YACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;SACnB,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;QAC9B,WAAW,EAAE,CAAC,IAAI,EAAE;YAClB,KAAK,EAAE,MAAM,CAAC;YACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;YACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;SACnB,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;KAC/B,CAAC;IACF,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE;QACR,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA8GpB"}
@@ -1,108 +1,11 @@
1
+ import { formatFactLines, formatNodeLines } from "./context.js";
1
2
  import { logger } from "./logger.js";
2
- const DEFAULT_CONTEXT_LIMIT = 200_000;
3
- const RESUME_DELAY_MS = 500;
4
- const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
5
- const buildModelKey = (providerID, modelID) => `${providerID}/${modelID}`;
6
- const resolveContextLimit = async (providerID, modelID, deps, state) => {
7
- const modelKey = buildModelKey(providerID, modelID);
8
- const cached = state.contextLimitCache.get(modelKey);
9
- if (cached)
10
- return cached;
11
- try {
12
- const providers = await deps.sdkClient.provider.list({
13
- directory: deps.directory,
14
- });
15
- const list = providers.providers ?? [];
16
- for (const provider of list) {
17
- const providerInfo = provider;
18
- if (providerInfo.id !== providerID)
19
- continue;
20
- const models = providerInfo.models ?? [];
21
- for (const model of models) {
22
- const modelInfo = model;
23
- if (modelInfo.id !== modelID)
24
- continue;
25
- const contextLimit = modelInfo.limit?.context;
26
- if (typeof contextLimit === "number" && contextLimit > 0) {
27
- state.contextLimitCache.set(modelKey, contextLimit);
28
- return contextLimit;
29
- }
30
- }
31
- }
32
- }
33
- catch (err) {
34
- logger.warn("Failed to fetch provider context limit", err);
35
- }
36
- state.contextLimitCache.set(modelKey, DEFAULT_CONTEXT_LIMIT);
37
- return DEFAULT_CONTEXT_LIMIT;
38
- };
39
- export function createPreemptiveCompactionHandler(config, deps) {
40
- const state = {
41
- lastCompactionTime: new Map(),
42
- compactionInProgress: new Set(),
43
- contextLimitCache: new Map(),
44
- };
45
- const checkAndTriggerCompaction = async (sessionId, tokens, providerID, modelID) => {
46
- const totalTokens = tokens.input + tokens.cache.read + tokens.output +
47
- tokens.reasoning;
48
- if (totalTokens < (config.minTokensForCompaction ?? 0))
49
- return;
50
- if (state.compactionInProgress.has(sessionId))
51
- return;
52
- const lastCompaction = state.lastCompactionTime.get(sessionId) ?? 0;
53
- if (Date.now() - lastCompaction < (config.compactionCooldownMs ?? 0)) {
54
- return;
55
- }
56
- const contextLimit = await resolveContextLimit(providerID, modelID, deps, state);
57
- const usageRatio = totalTokens / contextLimit;
58
- if (usageRatio < (config.compactionThreshold ?? 1))
59
- return;
60
- state.compactionInProgress.add(sessionId);
61
- try {
62
- await deps.sdkClient.tui.showToast({
63
- body: {
64
- title: "Graphiti",
65
- message: "Compacting session to preserve context...",
66
- variant: "info",
67
- duration: 3000,
68
- },
69
- query: { directory: deps.directory },
70
- });
71
- await deps.sdkClient.session.summarize({
72
- path: { id: sessionId },
73
- body: { providerID, modelID },
74
- query: { directory: deps.directory },
75
- });
76
- state.lastCompactionTime.set(sessionId, Date.now());
77
- if (config.autoResumeAfterCompaction) {
78
- await delay(RESUME_DELAY_MS);
79
- await deps.sdkClient.session.promptAsync({
80
- path: { id: sessionId },
81
- body: { parts: [{ type: "text", text: "Continue" }] },
82
- query: { directory: deps.directory },
83
- });
84
- }
85
- logger.info("Preemptive compaction triggered", {
86
- sessionId,
87
- providerID,
88
- modelID,
89
- usageRatio,
90
- totalTokens,
91
- contextLimit,
92
- });
93
- }
94
- catch (err) {
95
- logger.error("Preemptive compaction failed", err);
96
- }
97
- finally {
98
- state.compactionInProgress.delete(sessionId);
99
- }
100
- };
101
- return { checkAndTriggerCompaction };
102
- }
3
+ /**
4
+ * Persist a compaction summary episode when enabled.
5
+ */
103
6
  export async function handleCompaction(params) {
104
- const { client, config, groupId, summary, sessionId } = params;
105
- if (!config.enableCompactionSave || !summary)
7
+ const { client, groupId, summary, sessionId } = params;
8
+ if (!summary)
106
9
  return;
107
10
  try {
108
11
  await client.addEpisode({
@@ -118,24 +21,95 @@ export async function handleCompaction(params) {
118
21
  logger.error("Failed to save compaction summary:", err);
119
22
  }
120
23
  }
24
+ /**
25
+ * Retrieve persistent fact context to include during compaction.
26
+ */
121
27
  export async function getCompactionContext(params) {
122
- const { client, config, groupId, contextStrings } = params;
28
+ const { client, characterBudget, groupIds, contextStrings } = params;
123
29
  try {
124
30
  const queryText = contextStrings.slice(0, 3).join(" ").slice(0, 500);
125
31
  if (!queryText.trim())
126
32
  return [];
127
- const facts = await client.searchFacts({
33
+ const projectFactsPromise = client.searchFacts({
128
34
  query: queryText,
129
- groupIds: [groupId],
130
- maxFacts: config.maxFacts,
35
+ groupIds: [groupIds.project],
36
+ maxFacts: 50,
131
37
  });
132
- if (facts.length === 0)
38
+ const projectNodesPromise = client.searchNodes({
39
+ query: queryText,
40
+ groupIds: [groupIds.project],
41
+ maxNodes: 30,
42
+ });
43
+ const userGroupId = groupIds.user;
44
+ const userFactsPromise = userGroupId
45
+ ? client.searchFacts({
46
+ query: queryText,
47
+ groupIds: [userGroupId],
48
+ maxFacts: 20,
49
+ })
50
+ : Promise.resolve([]);
51
+ const userNodesPromise = userGroupId
52
+ ? client.searchNodes({
53
+ query: queryText,
54
+ groupIds: [userGroupId],
55
+ maxNodes: 10,
56
+ })
57
+ : Promise.resolve([]);
58
+ const [projectFacts, projectNodes, userFacts, userNodes] = await Promise
59
+ .all([
60
+ projectFactsPromise,
61
+ projectNodesPromise,
62
+ userFactsPromise,
63
+ userNodesPromise,
64
+ ]);
65
+ if (projectFacts.length === 0 && projectNodes.length === 0 &&
66
+ userFacts.length === 0 && userNodes.length === 0) {
133
67
  return [];
134
- const lines = [
135
- "## Persistent Knowledge (preserve these facts during compaction):",
136
- ...facts.map((fact) => `- ${fact.fact}`),
68
+ }
69
+ const buildSection = (header, facts, nodes) => {
70
+ const lines = [];
71
+ lines.push(header);
72
+ if (facts.length > 0) {
73
+ lines.push("### Facts");
74
+ lines.push(...formatFactLines(facts));
75
+ }
76
+ if (nodes.length > 0) {
77
+ lines.push("### Nodes");
78
+ lines.push(...formatNodeLines(nodes));
79
+ }
80
+ return lines.join("\n");
81
+ };
82
+ const projectSection = buildSection("## Persistent Knowledge (Project)", projectFacts, projectNodes);
83
+ const userSection = buildSection("## Persistent Knowledge (User)", userFacts, userNodes);
84
+ const headerLines = [
85
+ "## Current Goal",
86
+ "- ",
87
+ "",
88
+ "## Work Completed",
89
+ "- ",
90
+ "",
91
+ "## Remaining Tasks",
92
+ "- ",
93
+ "",
94
+ "## Constraints & Decisions",
95
+ "- ",
96
+ "",
97
+ "## Persistent Knowledge",
137
98
  ];
138
- return [lines.join("\n")];
99
+ const header = headerLines.join("\n");
100
+ const base = `${header}\n`;
101
+ const remainingBudget = Math.max(characterBudget - base.length, 0);
102
+ const projectBudget = Math.floor(remainingBudget * 0.7);
103
+ const userBudget = remainingBudget - projectBudget;
104
+ const truncatedProject = projectSection.slice(0, projectBudget);
105
+ const truncatedUser = userSection.slice(0, userBudget);
106
+ const sections = [header];
107
+ if (truncatedProject.trim())
108
+ sections.push(truncatedProject);
109
+ if (truncatedUser.trim())
110
+ sections.push(truncatedUser);
111
+ const content = sections.join("\n").slice(0, characterBudget);
112
+ return [content];
139
113
  }
140
114
  catch (err) {
141
115
  logger.error("Failed to get compaction context:", err);
@@ -0,0 +1,14 @@
1
+ export interface ProviderListClient {
2
+ provider: {
3
+ list: (options?: {
4
+ directory?: string;
5
+ }) => Promise<unknown>;
6
+ };
7
+ }
8
+ export declare function resolveContextLimit(providerID: string, modelID: string, client: ProviderListClient, directory: string): Promise<number>;
9
+ /**
10
+ * Calculate the character budget for memory injection
11
+ * (5% of context limit * 4 chars/token).
12
+ */
13
+ export declare function calculateInjectionBudget(contextLimit: number): number;
14
+ //# sourceMappingURL=context-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-limit.d.ts","sourceRoot":"","sources":["../../../src/src/services/context-limit.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE;QACR,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE;YAAE,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KAC9D,CAAC;CACH;AAID,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,kBAAkB,EAC1B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CA+BjB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAErE"}
@@ -0,0 +1,41 @@
1
+ import { logger } from "./logger.js";
2
+ const DEFAULT_CONTEXT_LIMIT = 200_000;
3
+ const contextLimitCache = new Map();
4
+ export async function resolveContextLimit(providerID, modelID, client, directory) {
5
+ const modelKey = `${providerID}/${modelID}`;
6
+ const cached = contextLimitCache.get(modelKey);
7
+ if (cached)
8
+ return cached;
9
+ try {
10
+ const providers = await client.provider.list({ directory });
11
+ const list = providers.providers ?? [];
12
+ for (const provider of list) {
13
+ const providerInfo = provider;
14
+ if (providerInfo.id !== providerID)
15
+ continue;
16
+ const models = providerInfo.models ?? [];
17
+ for (const model of models) {
18
+ const modelInfo = model;
19
+ if (modelInfo.id !== modelID)
20
+ continue;
21
+ const contextLimit = modelInfo.limit?.context;
22
+ if (typeof contextLimit === "number" && contextLimit > 0) {
23
+ contextLimitCache.set(modelKey, contextLimit);
24
+ return contextLimit;
25
+ }
26
+ }
27
+ }
28
+ }
29
+ catch (err) {
30
+ logger.warn("Failed to fetch provider context limit", err);
31
+ }
32
+ contextLimitCache.set(modelKey, DEFAULT_CONTEXT_LIMIT);
33
+ return DEFAULT_CONTEXT_LIMIT;
34
+ }
35
+ /**
36
+ * Calculate the character budget for memory injection
37
+ * (5% of context limit * 4 chars/token).
38
+ */
39
+ export function calculateInjectionBudget(contextLimit) {
40
+ return Math.floor(contextLimit * 0.05 * 4);
41
+ }
@@ -1,3 +1,8 @@
1
1
  import type { GraphitiFact, GraphitiNode } from "../types/index.js";
2
+ export declare const formatFactLines: (facts: GraphitiFact[]) => string[];
3
+ export declare const formatNodeLines: (nodes: GraphitiNode[]) => string[];
4
+ /**
5
+ * Format Graphiti facts and nodes into a user-facing context block.
6
+ */
2
7
  export declare function formatMemoryContext(facts: GraphitiFact[], nodes: GraphitiNode[]): string;
3
8
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/src/services/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEpE,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EAAE,EACrB,KAAK,EAAE,YAAY,EAAE,GACpB,MAAM,CA0CR"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/src/services/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEpE,eAAO,MAAM,eAAe,GAAI,OAAO,YAAY,EAAE,KAAG,MAAM,EAO1D,CAAC;AAEL,eAAO,MAAM,eAAe,GAAI,OAAO,YAAY,EAAE,KAAG,MAAM,EAK1D,CAAC;AAEL;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EAAE,EACrB,KAAK,EAAE,YAAY,EAAE,GACpB,MAAM,CA8BR"}
@@ -1,3 +1,20 @@
1
+ export const formatFactLines = (facts) => facts.map((fact) => {
2
+ const entities = [];
3
+ if (fact.source_node?.name)
4
+ entities.push(fact.source_node.name);
5
+ if (fact.target_node?.name)
6
+ entities.push(fact.target_node.name);
7
+ const entityStr = entities.length > 0 ? ` [${entities.join(" -> ")}]` : "";
8
+ return `- ${fact.fact}${entityStr}`;
9
+ });
10
+ export const formatNodeLines = (nodes) => nodes.map((node) => {
11
+ const labels = node.labels?.length ? ` (${node.labels.join(", ")})` : "";
12
+ const summary = node.summary ? `: ${node.summary}` : "";
13
+ return `- **${node.name}**${labels}${summary}`;
14
+ });
15
+ /**
16
+ * Format Graphiti facts and nodes into a user-facing context block.
17
+ */
1
18
  export function formatMemoryContext(facts, nodes) {
2
19
  const sections = [];
3
20
  sections.push("# Persistent Memory (from Graphiti Knowledge Graph)");
@@ -7,26 +24,12 @@ export function formatMemoryContext(facts, nodes) {
7
24
  sections.push("");
8
25
  if (facts.length > 0) {
9
26
  sections.push("## Known Facts");
10
- for (const fact of facts) {
11
- const entities = [];
12
- if (fact.source_node?.name)
13
- entities.push(fact.source_node.name);
14
- if (fact.target_node?.name)
15
- entities.push(fact.target_node.name);
16
- const entityStr = entities.length > 0
17
- ? ` [${entities.join(" -> ")}]`
18
- : "";
19
- sections.push(`- ${fact.fact}${entityStr}`);
20
- }
27
+ sections.push(...formatFactLines(facts));
21
28
  sections.push("");
22
29
  }
23
30
  if (nodes.length > 0) {
24
31
  sections.push("## Known Entities");
25
- for (const node of nodes) {
26
- const labels = node.labels?.length ? ` (${node.labels.join(", ")})` : "";
27
- const summary = node.summary ? `: ${node.summary}` : "";
28
- sections.push(`- **${node.name}**${labels}${summary}`);
29
- }
32
+ sections.push(...formatNodeLines(nodes));
30
33
  sections.push("");
31
34
  }
32
35
  if (facts.length === 0 && nodes.length === 0) {
@@ -0,0 +1,90 @@
1
+ import type { GraphitiClient } from "./services/client.js";
2
+ /**
3
+ * Per-session state tracked by the plugin.
4
+ */
5
+ export type SessionState = {
6
+ /** Graphiti group ID for this session. */
7
+ groupId: string;
8
+ /** Graphiti group ID for user-scoped memories. */
9
+ userGroupId: string;
10
+ /** Whether memories have been injected into this session yet. */
11
+ injectedMemories: boolean;
12
+ /** Message count at last memory injection. */
13
+ lastInjectionMessageCount: number;
14
+ /** Count of messages observed in this session. */
15
+ messageCount: number;
16
+ /** Buffered message strings awaiting flush. */
17
+ pendingMessages: string[];
18
+ /** Context window limit in tokens. */
19
+ contextLimit: number;
20
+ /** True when this session is the primary (non-subagent) session. */
21
+ isMain: boolean;
22
+ };
23
+ /**
24
+ * Minimal SDK client interface needed for session operations.
25
+ */
26
+ export interface SdkSessionClient {
27
+ session: {
28
+ /** Retrieve session metadata by ID. */
29
+ get: (args: {
30
+ path: {
31
+ id: string;
32
+ };
33
+ }) => Promise<unknown>;
34
+ /** List recent messages for a session. */
35
+ messages: (args: {
36
+ sessionID: string;
37
+ limit?: number;
38
+ }) => Promise<unknown>;
39
+ };
40
+ }
41
+ /**
42
+ * Manages session lifecycle, parent ID resolution, message buffering,
43
+ * and flushing of pending messages to Graphiti.
44
+ */
45
+ /**
46
+ * Tracks per-session state, parent resolution, message buffering,
47
+ * and flushing pending messages to Graphiti.
48
+ */
49
+ export declare class SessionManager {
50
+ private readonly defaultGroupId;
51
+ private readonly defaultUserGroupId;
52
+ private readonly sdkClient;
53
+ private readonly graphitiClient;
54
+ private sessions;
55
+ private parentIdCache;
56
+ private pendingAssistantMessages;
57
+ private bufferedAssistantMessageIds;
58
+ constructor(defaultGroupId: string, defaultUserGroupId: string, sdkClient: SdkSessionClient, graphitiClient: GraphitiClient);
59
+ /** Get the current session state, if present. */
60
+ getState(sessionId: string): SessionState | undefined;
61
+ /** Persist session state for the given session ID. */
62
+ setState(sessionId: string, state: SessionState): void;
63
+ /** Cache a resolved parent ID for a session. */
64
+ setParentId(sessionId: string, parentId: string | null): void;
65
+ /** Resolve and cache the parent ID for a session. */
66
+ resolveParentId(sessionId: string): Promise<string | null | undefined>;
67
+ /** Resolve the session state, initializing if needed. */
68
+ resolveSessionState(sessionId: string): Promise<{
69
+ state: SessionState | null;
70
+ resolved: boolean;
71
+ }>;
72
+ /** Determine whether a session is a subagent session. */
73
+ isSubagentSession(sessionId: string): Promise<boolean>;
74
+ /** Buffer partial assistant text for a streaming message. */
75
+ bufferAssistantPart(sessionId: string, messageId: string, text: string): void;
76
+ /** Check if an assistant message has already been finalized. */
77
+ isAssistantBuffered(sessionId: string, messageId: string): boolean;
78
+ /**
79
+ * Finalize a buffered assistant message and append it to pending messages.
80
+ */
81
+ finalizeAssistantMessage(state: SessionState, sessionId: string, messageId: string, source: string): void;
82
+ /** Flush pending buffered messages to Graphiti when size thresholds permit. */
83
+ flushPendingMessages(sessionId: string, sourceDescription: string, minBytes: number): Promise<void>;
84
+ /** Remove a pending assistant message by key. */
85
+ deletePendingAssistant(sessionId: string, messageId: string): void;
86
+ /** Clear cached data for a session. */
87
+ deleteSession(sessionId: string): void;
88
+ private fetchLatestAssistantMessage;
89
+ }
90
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/src/session.ts"],"names":[],"mappings":"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"}