opencode-graphiti 0.1.3 → 0.1.5

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/README.md CHANGED
@@ -101,7 +101,7 @@ Create a config file at `~/.config/opencode/graphiti.jsonc`:
101
101
  // Graphiti MCP server endpoint
102
102
  "endpoint": "http://localhost:8000/mcp",
103
103
 
104
- // Prefix for project group IDs (e.g. "opencode_my-project")
104
+ // Prefix for project group IDs (e.g. "opencode-my-project")
105
105
  "groupIdPrefix": "opencode",
106
106
 
107
107
  // Number of user messages between memory re-injections (0 = disabled)
@@ -118,8 +118,12 @@ values.
118
118
 
119
119
  On the first user message in a session, the plugin searches Graphiti for facts
120
120
  and entities relevant to the message content. Results are split into project and
121
- user scopes (70% / 30% budget split), formatted, and prepended to the
122
- conversation as a synthetic context block.
121
+ user scopes (70% / 30% budget split), formatted in XML-style `<memory>` blocks
122
+ with explicit de-emphasis instructions, and injected into the conversation.
123
+
124
+ Memory is injected via `output.message.system` (system-level instruction) when
125
+ available, which prevents memory from influencing session titles. If the system
126
+ field is unavailable, the plugin falls back to prepending synthetic parts.
123
127
 
124
128
  The injection budget is calculated dynamically: 5% of the model's context limit
125
129
  (resolved from the provider list) multiplied by 4 characters per token.
@@ -167,21 +171,10 @@ Each project gets a unique `group_id` derived from its directory name (e.g.
167
171
  underscores (colons are not allowed). This ensures memories from different
168
172
  projects stay isolated.
169
173
 
170
- ## Development
171
-
172
- ```bash
173
- # Format
174
- deno fmt
175
-
176
- # Lint
177
- deno lint
174
+ ## Contributing
178
175
 
179
- # Type check
180
- deno check src/index.ts
181
-
182
- # Build
183
- deno task build
184
- ```
176
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and release
177
+ process.
185
178
 
186
179
  ## License
187
180
 
package/esm/deno.d.ts ADDED
@@ -0,0 +1,47 @@
1
+ declare namespace _default {
2
+ export let name: string;
3
+ export let description: string;
4
+ export let version: string;
5
+ export let license: string;
6
+ export namespace tasks {
7
+ let build: string;
8
+ namespace deploy {
9
+ let command: string;
10
+ let dependencies: string[];
11
+ }
12
+ let dev: string;
13
+ let check: string;
14
+ let lint: string;
15
+ let fmt: string;
16
+ }
17
+ export namespace lint_1 {
18
+ let exclude: string[];
19
+ namespace rules {
20
+ let exclude_1: string[];
21
+ export { exclude_1 as exclude };
22
+ }
23
+ }
24
+ export { lint_1 as lint };
25
+ export namespace fmt_1 {
26
+ let exclude_2: string[];
27
+ export { exclude_2 as exclude };
28
+ }
29
+ export { fmt_1 as fmt };
30
+ export namespace compilerOptions {
31
+ let strict: boolean;
32
+ let lib: string[];
33
+ }
34
+ export let nodeModulesDir: string;
35
+ export let imports: {
36
+ "@modelcontextprotocol/sdk": string;
37
+ "@opencode-ai/plugin": string;
38
+ "@opencode-ai/sdk": string;
39
+ cosmiconfig: string;
40
+ zod: string;
41
+ };
42
+ export let exports: {
43
+ ".": string;
44
+ };
45
+ }
46
+ export default _default;
47
+ //# sourceMappingURL=deno.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deno.d.ts","sourceRoot":"","sources":["../src/deno.js"],"names":[],"mappings":""}
package/esm/deno.js ADDED
@@ -0,0 +1,41 @@
1
+ export default {
2
+ "name": "opencode-graphiti",
3
+ "description": "OpenCode plugin for persistent memory via Graphiti knowledge graph",
4
+ "version": "0.0.0-development",
5
+ "license": "MIT",
6
+ "tasks": {
7
+ "build": "deno run -A dnt.ts",
8
+ "deploy": {
9
+ "command": "cd dist/ && npm publish",
10
+ "dependencies": ["build"]
11
+ },
12
+ "dev": "deno run --allow-all src/index.ts",
13
+ "check": "deno check src/index.ts",
14
+ "lint": "deno lint",
15
+ "fmt": "deno fmt"
16
+ },
17
+ "lint": {
18
+ "exclude": ["dist/"],
19
+ "rules": {
20
+ "exclude": ["no-import-prefix"]
21
+ }
22
+ },
23
+ "fmt": {
24
+ "exclude": ["dist/"]
25
+ },
26
+ "compilerOptions": {
27
+ "strict": true,
28
+ "lib": ["deno.ns", "dom", "esnext"]
29
+ },
30
+ "nodeModulesDir": "auto",
31
+ "imports": {
32
+ "@modelcontextprotocol/sdk": "npm:@modelcontextprotocol/sdk@^1.25.2",
33
+ "@opencode-ai/plugin": "npm:@opencode-ai/plugin@^1.1.53",
34
+ "@opencode-ai/sdk": "npm:@opencode-ai/sdk@^1.1.53",
35
+ "cosmiconfig": "npm:cosmiconfig@9.0.0",
36
+ "zod": "npm:zod@4.3.6"
37
+ },
38
+ "exports": {
39
+ ".": "./mod.ts"
40
+ }
41
+ };
@@ -1,6 +1,9 @@
1
- import type { Part } from "@opencode-ai/sdk";
1
+ import type { Hooks } from "@opencode-ai/plugin";
2
2
  import type { GraphitiClient } from "../services/client.js";
3
3
  import type { SessionManager } from "../session.js";
4
+ type ChatMessageHook = NonNullable<Hooks["chat.message"]>;
5
+ type ChatMessageInput = Parameters<ChatMessageHook>[0];
6
+ type ChatMessageOutput = Parameters<ChatMessageHook>[1];
4
7
  /** Dependencies for the chat message handler. */
5
8
  export interface ChatHandlerDeps {
6
9
  sessionManager: SessionManager;
@@ -8,14 +11,6 @@ export interface ChatHandlerDeps {
8
11
  client: GraphitiClient;
9
12
  }
10
13
  /** Creates the `chat.message` hook handler. */
11
- export declare function createChatHandler(deps: ChatHandlerDeps): ({ sessionID }: {
12
- sessionID: string;
13
- }, output: {
14
- allow_buffering?: boolean;
15
- parts: Part[];
16
- message: {
17
- sessionID: string;
18
- id: string;
19
- };
20
- }) => Promise<void>;
14
+ export declare function createChatHandler(deps: ChatHandlerDeps): ({ sessionID }: ChatMessageInput, output: ChatMessageOutput) => Promise<void>;
15
+ export {};
21
16
  //# sourceMappingURL=chat.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/chat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,IA6FnD,eAAe;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EACpC,QAAQ;IACN,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C,mBA4DJ"}
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/chat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,KAAK,eAAe,GAAG,WAAW,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;AAC1D,KAAK,gBAAgB,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,KAAK,iBAAiB,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;AAExD,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,IAyGvC,eAAe,gBAAgB,EAAE,QAAQ,iBAAiB,mBAuDzE"}
@@ -1,24 +1,20 @@
1
- import { formatMemoryContext } from "../services/context.js";
2
1
  import { calculateInjectionBudget } from "../services/context-limit.js";
2
+ import { formatMemoryContext } from "../services/context.js";
3
3
  import { logger } from "../services/logger.js";
4
4
  import { extractTextFromParts } from "../utils.js";
5
5
  /** Creates the `chat.message` hook handler. */
6
6
  export function createChatHandler(deps) {
7
7
  const { sessionManager, injectionInterval, client } = deps;
8
8
  const removeSyntheticMemoryParts = (parts) => parts.filter((part) => {
9
- const synthetic = part.synthetic;
10
- const id = typeof part.id === "string"
11
- ? String(part.id)
12
- : "";
13
- if (!synthetic)
9
+ if (part.type !== "text")
14
10
  return true;
15
- if (id.startsWith("graphiti-memory-"))
11
+ if (part.id?.startsWith("graphiti-memory-"))
16
12
  return false;
17
- if (id.startsWith("graphiti-refresh-"))
13
+ if (part.id?.startsWith("graphiti-refresh-"))
18
14
  return false;
19
15
  return true;
20
16
  });
21
- const injectMemoryContext = async (state, messageText, output, prefix, useUserScope, characterBudget) => {
17
+ const injectMemoryContext = async (state, messageText, output, prefix, useUserScope, characterBudget, shouldReinject) => {
22
18
  const userGroupId = state.userGroupId;
23
19
  const projectFactsPromise = client.searchFacts({
24
20
  query: messageText,
@@ -67,14 +63,28 @@ export function createChatHandler(deps) {
67
63
  .slice(0, characterBudget);
68
64
  if (!memoryContext)
69
65
  return;
70
- output.parts.unshift({
71
- type: "text",
72
- text: memoryContext,
73
- id: `${prefix}${Date.now()}`,
74
- sessionID: output.message.sessionID,
75
- messageID: output.message.id,
76
- synthetic: true,
77
- });
66
+ if ("system" in output.message) {
67
+ try {
68
+ output.message.system = memoryContext;
69
+ return;
70
+ }
71
+ catch (_err) {
72
+ // Fall through to synthetic injection.
73
+ }
74
+ }
75
+ if (shouldReinject) {
76
+ output.parts = removeSyntheticMemoryParts(output.parts);
77
+ }
78
+ {
79
+ output.parts.unshift({
80
+ type: "text",
81
+ text: memoryContext,
82
+ id: `${prefix}${Date.now()}`,
83
+ sessionID: output.message.sessionID,
84
+ messageID: output.message.id,
85
+ synthetic: true,
86
+ });
87
+ }
78
88
  logger.info(`Injected ${projectFacts.length + userFacts.length} facts and ${projectNodes.length + userNodes.length} nodes`);
79
89
  };
80
90
  return async ({ sessionID }, output) => {
@@ -84,7 +94,6 @@ export function createChatHandler(deps) {
84
94
  }
85
95
  const { state, resolved } = await sessionManager.resolveSessionState(sessionID);
86
96
  if (!resolved) {
87
- output.allow_buffering = true;
88
97
  logger.debug("Unable to resolve session for message:", { sessionID });
89
98
  return;
90
99
  }
@@ -109,14 +118,11 @@ export function createChatHandler(deps) {
109
118
  injectionInterval;
110
119
  if (!shouldInjectOnFirst && !shouldReinject)
111
120
  return;
112
- if (shouldReinject) {
113
- output.parts = removeSyntheticMemoryParts(output.parts);
114
- }
115
121
  try {
116
122
  const prefix = shouldReinject ? "graphiti-refresh-" : "graphiti-memory-";
117
123
  const useUserScope = shouldInjectOnFirst;
118
124
  const characterBudget = calculateInjectionBudget(state.contextLimit);
119
- await injectMemoryContext(state, messageText, output, prefix, useUserScope, characterBudget);
125
+ await injectMemoryContext(state, messageText, output, prefix, useUserScope, characterBudget, shouldReinject);
120
126
  state.injectedMemories = true;
121
127
  state.lastInjectionMessageCount = state.messageCount;
122
128
  }
@@ -1,5 +1,9 @@
1
+ import type { Hooks } from "@opencode-ai/plugin";
1
2
  import type { GraphitiClient } from "../services/client.js";
2
3
  import type { SessionManager } from "../session.js";
4
+ type CompactingHook = NonNullable<Hooks["experimental.session.compacting"]>;
5
+ type CompactingInput = Parameters<CompactingHook>[0];
6
+ type CompactingOutput = Parameters<CompactingHook>[1];
3
7
  /** Dependencies for the compacting handler. */
4
8
  export interface CompactingHandlerDeps {
5
9
  sessionManager: SessionManager;
@@ -7,9 +11,6 @@ export interface CompactingHandlerDeps {
7
11
  defaultGroupId: string;
8
12
  }
9
13
  /** Creates the `experimental.session.compacting` hook handler. */
10
- export declare function createCompactingHandler(deps: CompactingHandlerDeps): ({ sessionID }: {
11
- sessionID: string;
12
- }, output: {
13
- context: string[];
14
- }) => Promise<void>;
14
+ export declare function createCompactingHandler(deps: CompactingHandlerDeps): ({ sessionID }: CompactingInput, output: CompactingOutput) => Promise<void>;
15
+ export {};
15
16
  //# sourceMappingURL=compacting.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compacting.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/compacting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,+CAA+C;AAC/C,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,qBAAqB,IAI/D,eAAe;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EACpC,QAAQ;IAAE,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,mBAyBhC"}
1
+ {"version":3,"file":"compacting.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/compacting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,KAAK,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC,CAAC;AAC5E,KAAK,eAAe,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,KAAK,gBAAgB,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAEtD,+CAA+C;AAC/C,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,qBAAqB,IAI/D,eAAe,eAAe,EAC9B,QAAQ,gBAAgB,mBAyB3B"}
@@ -1,7 +1,9 @@
1
- import type { Event } from "@opencode-ai/sdk";
1
+ import type { Hooks } from "@opencode-ai/plugin";
2
2
  import type { GraphitiClient } from "../services/client.js";
3
3
  import type { ProviderListClient } from "../services/context-limit.js";
4
4
  import type { SessionManager } from "../session.js";
5
+ type EventHook = NonNullable<Hooks["event"]>;
6
+ type EventInput = Parameters<EventHook>[0];
5
7
  /** Dependencies for the event handler. */
6
8
  export interface EventHandlerDeps {
7
9
  sessionManager: SessionManager;
@@ -12,7 +14,6 @@ export interface EventHandlerDeps {
12
14
  groupIdPrefix: string;
13
15
  }
14
16
  /** Creates the `event` hook handler. */
15
- export declare function createEventHandler(deps: EventHandlerDeps): ({ event }: {
16
- event: Event;
17
- }) => Promise<void>;
17
+ export declare function createEventHandler(deps: EventHandlerDeps): ({ event }: EventInput) => Promise<void>;
18
+ export {};
18
19
  //# sourceMappingURL=event.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,IAWzC,WAAW;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,mBA+J1C"}
1
+ {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,KAAK,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7C,KAAK,UAAU,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE3C,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,IAWzC,WAAW,UAAU,mBA+JpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/src/services/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EAEZ,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAG3B;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAS;IAEzB;;OAEG;gBACS,QAAQ,EAAE,MAAM;IAM5B,oDAAoD;IACpD,OAAO,CAAC,wBAAwB;IAOhC;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAgBjC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAOnB,QAAQ;IAkCtB,OAAO,CAAC,gBAAgB;YASV,SAAS;IAavB;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;IAyBzC;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;QACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,GAAG,OAAO,CAAC,IAAI,CAAC;IAWjB;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAsB3B;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAsB3B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;CAQpC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/src/services/client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,YAAY,EAEZ,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAG3B;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAS;IAEzB;;OAEG;gBACS,QAAQ,EAAE,MAAM;IAS5B,oDAAoD;IACpD,OAAO,CAAC,wBAAwB;IAUhC;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAgBjC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAOnB,QAAQ;IAkCtB,OAAO,CAAC,gBAAgB;YASV,SAAS;IAavB;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;IAyBzC;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;QACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,GAAG,OAAO,CAAC,IAAI,CAAC;IAWjB;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAsB3B;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAsB3B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;CAQpC"}
@@ -1,5 +1,6 @@
1
1
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
2
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
3
+ import manifest from "../../deno.js";
3
4
  import { logger } from "./logger.js";
4
5
  /**
5
6
  * Graphiti MCP client wrapper for connecting, querying,
@@ -35,12 +36,18 @@ export class GraphitiClient {
35
36
  value: void 0
36
37
  });
37
38
  this.endpoint = endpoint;
38
- this.client = new Client({ name: "opencode-graphiti", version: "0.1.0" });
39
+ this.client = new Client({
40
+ name: manifest.name,
41
+ version: manifest.version,
42
+ });
39
43
  this.transport = new StreamableHTTPClientTransport(new URL(endpoint));
40
44
  }
41
45
  /** Create a fresh MCP Client and Transport pair. */
42
46
  createClientAndTransport() {
43
- this.client = new Client({ name: "opencode-graphiti", version: "0.1.0" });
47
+ this.client = new Client({
48
+ name: manifest.name,
49
+ version: manifest.version,
50
+ });
44
51
  this.transport = new StreamableHTTPClientTransport(new URL(this.endpoint));
45
52
  }
46
53
  /**
@@ -1 +1 @@
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
+ {"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,CAgIpB"}
@@ -69,32 +69,40 @@ export async function getCompactionContext(params) {
69
69
  const buildSection = (header, facts, nodes) => {
70
70
  const lines = [];
71
71
  lines.push(header);
72
+ lines.push("<instruction>Background context only; do not reference in titles, summaries, or opening responses unless directly relevant.</instruction>");
72
73
  if (facts.length > 0) {
73
- lines.push("### Facts");
74
+ lines.push("<facts>");
74
75
  lines.push(...formatFactLines(facts));
76
+ lines.push("</facts>");
75
77
  }
76
78
  if (nodes.length > 0) {
77
- lines.push("### Nodes");
79
+ lines.push("<nodes>");
78
80
  lines.push(...formatNodeLines(nodes));
81
+ lines.push("</nodes>");
79
82
  }
80
83
  return lines.join("\n");
81
84
  };
82
- const projectSection = buildSection("## Persistent Knowledge (Project)", projectFacts, projectNodes);
83
- const userSection = buildSection("## Persistent Knowledge (User)", userFacts, userNodes);
85
+ const projectSection = buildSection('<memory source="project">', projectFacts, projectNodes);
86
+ const userSection = buildSection('<memory source="user">', userFacts, userNodes);
84
87
  const headerLines = [
85
- "## Current Goal",
88
+ "<summary>",
89
+ "<current_goal>",
86
90
  "- ",
91
+ "</current_goal>",
87
92
  "",
88
- "## Work Completed",
93
+ "<work_completed>",
89
94
  "- ",
95
+ "</work_completed>",
90
96
  "",
91
- "## Remaining Tasks",
97
+ "<remaining_tasks>",
92
98
  "- ",
99
+ "</remaining_tasks>",
93
100
  "",
94
- "## Constraints & Decisions",
101
+ "<constraints_decisions>",
95
102
  "- ",
103
+ "</constraints_decisions>",
96
104
  "",
97
- "## Persistent Knowledge",
105
+ "<persistent_memory>",
98
106
  ];
99
107
  const header = headerLines.join("\n");
100
108
  const base = `${header}\n`;
@@ -104,10 +112,16 @@ export async function getCompactionContext(params) {
104
112
  const truncatedProject = projectSection.slice(0, projectBudget);
105
113
  const truncatedUser = userSection.slice(0, userBudget);
106
114
  const sections = [header];
107
- if (truncatedProject.trim())
115
+ if (truncatedProject.trim()) {
108
116
  sections.push(truncatedProject);
109
- if (truncatedUser.trim())
117
+ sections.push("</memory>");
118
+ }
119
+ if (truncatedUser.trim()) {
110
120
  sections.push(truncatedUser);
121
+ sections.push("</memory>");
122
+ }
123
+ sections.push("</persistent_memory>");
124
+ sections.push("</summary>");
111
125
  const content = sections.join("\n").slice(0, characterBudget);
112
126
  return [content];
113
127
  }
@@ -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,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
+ {"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,CA0BR"}
@@ -5,35 +5,33 @@ export const formatFactLines = (facts) => facts.map((fact) => {
5
5
  if (fact.target_node?.name)
6
6
  entities.push(fact.target_node.name);
7
7
  const entityStr = entities.length > 0 ? ` [${entities.join(" -> ")}]` : "";
8
- return `- ${fact.fact}${entityStr}`;
8
+ return `<fact>${fact.fact}${entityStr}</fact>`;
9
9
  });
10
10
  export const formatNodeLines = (nodes) => nodes.map((node) => {
11
11
  const labels = node.labels?.length ? ` (${node.labels.join(", ")})` : "";
12
12
  const summary = node.summary ? `: ${node.summary}` : "";
13
- return `- **${node.name}**${labels}${summary}`;
13
+ return `<node>${node.name}${labels}${summary}</node>`;
14
14
  });
15
15
  /**
16
16
  * Format Graphiti facts and nodes into a user-facing context block.
17
17
  */
18
18
  export function formatMemoryContext(facts, nodes) {
19
+ if (facts.length === 0 && nodes.length === 0) {
20
+ return "";
21
+ }
19
22
  const sections = [];
20
- sections.push("# Persistent Memory (from Graphiti Knowledge Graph)");
21
- sections.push("");
22
- sections.push("The following information was retrieved from your persistent memory.");
23
- sections.push("Use this context to inform your responses, but do not mention it unless asked.");
24
- sections.push("");
23
+ sections.push("<memory>");
24
+ sections.push("<instruction>Background context only; do not reference in titles, summaries, or opening responses unless directly relevant.</instruction>");
25
25
  if (facts.length > 0) {
26
- sections.push("## Known Facts");
26
+ sections.push("<facts>");
27
27
  sections.push(...formatFactLines(facts));
28
- sections.push("");
28
+ sections.push("</facts>");
29
29
  }
30
30
  if (nodes.length > 0) {
31
- sections.push("## Known Entities");
31
+ sections.push("<nodes>");
32
32
  sections.push(...formatNodeLines(nodes));
33
- sections.push("");
34
- }
35
- if (facts.length === 0 && nodes.length === 0) {
36
- return "";
33
+ sections.push("</nodes>");
37
34
  }
35
+ sections.push("</memory>");
38
36
  return sections.join("\n");
39
37
  }
package/package.json CHANGED
@@ -1,10 +1,30 @@
1
1
  {
2
2
  "name": "opencode-graphiti",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "OpenCode plugin for persistent memory via Graphiti knowledge graph",
5
+ "keywords": [
6
+ "opencode",
7
+ "graphiti",
8
+ "knowledge-graph",
9
+ "persistent-memory",
10
+ "plugin",
11
+ "mcp",
12
+ "ai",
13
+ "context"
14
+ ],
15
+ "author": "Vicary A. <vicary.archangel@member.mensa.org>",
16
+ "homepage": "https://github.com/vicary/opencode-graphiti#readme",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/vicary/opencode-graphiti.git"
20
+ },
5
21
  "license": "MIT",
22
+ "bugs": {
23
+ "url": "https://github.com/vicary/opencode-graphiti/issues"
24
+ },
6
25
  "main": "./esm/mod.js",
7
26
  "module": "./esm/mod.js",
27
+ "types": "./esm/mod.d.ts",
8
28
  "exports": {
9
29
  ".": {
10
30
  "import": "./esm/mod.js",
@@ -12,6 +32,9 @@
12
32
  }
13
33
  },
14
34
  "scripts": {},
35
+ "engines": {
36
+ "node": ">=20"
37
+ },
15
38
  "opencode": {
16
39
  "type": "plugin",
17
40
  "hooks": [
@@ -0,0 +1,47 @@
1
+ declare namespace _default {
2
+ export let name: string;
3
+ export let description: string;
4
+ export let version: string;
5
+ export let license: string;
6
+ export namespace tasks {
7
+ let build: string;
8
+ namespace deploy {
9
+ let command: string;
10
+ let dependencies: string[];
11
+ }
12
+ let dev: string;
13
+ let check: string;
14
+ let lint: string;
15
+ let fmt: string;
16
+ }
17
+ export namespace lint_1 {
18
+ let exclude: string[];
19
+ namespace rules {
20
+ let exclude_1: string[];
21
+ export { exclude_1 as exclude };
22
+ }
23
+ }
24
+ export { lint_1 as lint };
25
+ export namespace fmt_1 {
26
+ let exclude_2: string[];
27
+ export { exclude_2 as exclude };
28
+ }
29
+ export { fmt_1 as fmt };
30
+ export namespace compilerOptions {
31
+ let strict: boolean;
32
+ let lib: string[];
33
+ }
34
+ export let nodeModulesDir: string;
35
+ export let imports: {
36
+ "@modelcontextprotocol/sdk": string;
37
+ "@opencode-ai/plugin": string;
38
+ "@opencode-ai/sdk": string;
39
+ cosmiconfig: string;
40
+ zod: string;
41
+ };
42
+ export let exports: {
43
+ ".": string;
44
+ };
45
+ }
46
+ export default _default;
47
+ //# sourceMappingURL=deno.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deno.d.ts","sourceRoot":"","sources":["../src/deno.js"],"names":[],"mappings":""}
package/script/deno.js ADDED
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = {
4
+ "name": "opencode-graphiti",
5
+ "description": "OpenCode plugin for persistent memory via Graphiti knowledge graph",
6
+ "version": "0.0.0-development",
7
+ "license": "MIT",
8
+ "tasks": {
9
+ "build": "deno run -A dnt.ts",
10
+ "deploy": {
11
+ "command": "cd dist/ && npm publish",
12
+ "dependencies": ["build"]
13
+ },
14
+ "dev": "deno run --allow-all src/index.ts",
15
+ "check": "deno check src/index.ts",
16
+ "lint": "deno lint",
17
+ "fmt": "deno fmt"
18
+ },
19
+ "lint": {
20
+ "exclude": ["dist/"],
21
+ "rules": {
22
+ "exclude": ["no-import-prefix"]
23
+ }
24
+ },
25
+ "fmt": {
26
+ "exclude": ["dist/"]
27
+ },
28
+ "compilerOptions": {
29
+ "strict": true,
30
+ "lib": ["deno.ns", "dom", "esnext"]
31
+ },
32
+ "nodeModulesDir": "auto",
33
+ "imports": {
34
+ "@modelcontextprotocol/sdk": "npm:@modelcontextprotocol/sdk@^1.25.2",
35
+ "@opencode-ai/plugin": "npm:@opencode-ai/plugin@^1.1.53",
36
+ "@opencode-ai/sdk": "npm:@opencode-ai/sdk@^1.1.53",
37
+ "cosmiconfig": "npm:cosmiconfig@9.0.0",
38
+ "zod": "npm:zod@4.3.6"
39
+ },
40
+ "exports": {
41
+ ".": "./mod.ts"
42
+ }
43
+ };
@@ -1,6 +1,9 @@
1
- import type { Part } from "@opencode-ai/sdk";
1
+ import type { Hooks } from "@opencode-ai/plugin";
2
2
  import type { GraphitiClient } from "../services/client.js";
3
3
  import type { SessionManager } from "../session.js";
4
+ type ChatMessageHook = NonNullable<Hooks["chat.message"]>;
5
+ type ChatMessageInput = Parameters<ChatMessageHook>[0];
6
+ type ChatMessageOutput = Parameters<ChatMessageHook>[1];
4
7
  /** Dependencies for the chat message handler. */
5
8
  export interface ChatHandlerDeps {
6
9
  sessionManager: SessionManager;
@@ -8,14 +11,6 @@ export interface ChatHandlerDeps {
8
11
  client: GraphitiClient;
9
12
  }
10
13
  /** Creates the `chat.message` hook handler. */
11
- export declare function createChatHandler(deps: ChatHandlerDeps): ({ sessionID }: {
12
- sessionID: string;
13
- }, output: {
14
- allow_buffering?: boolean;
15
- parts: Part[];
16
- message: {
17
- sessionID: string;
18
- id: string;
19
- };
20
- }) => Promise<void>;
14
+ export declare function createChatHandler(deps: ChatHandlerDeps): ({ sessionID }: ChatMessageInput, output: ChatMessageOutput) => Promise<void>;
15
+ export {};
21
16
  //# sourceMappingURL=chat.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/chat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,IA6FnD,eAAe;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EACpC,QAAQ;IACN,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C,mBA4DJ"}
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/chat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,KAAK,eAAe,GAAG,WAAW,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;AAC1D,KAAK,gBAAgB,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,KAAK,iBAAiB,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;AAExD,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,IAyGvC,eAAe,gBAAgB,EAAE,QAAQ,iBAAiB,mBAuDzE"}
@@ -1,27 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createChatHandler = createChatHandler;
4
- const context_js_1 = require("../services/context.js");
5
4
  const context_limit_js_1 = require("../services/context-limit.js");
5
+ const context_js_1 = require("../services/context.js");
6
6
  const logger_js_1 = require("../services/logger.js");
7
7
  const utils_js_1 = require("../utils.js");
8
8
  /** Creates the `chat.message` hook handler. */
9
9
  function createChatHandler(deps) {
10
10
  const { sessionManager, injectionInterval, client } = deps;
11
11
  const removeSyntheticMemoryParts = (parts) => parts.filter((part) => {
12
- const synthetic = part.synthetic;
13
- const id = typeof part.id === "string"
14
- ? String(part.id)
15
- : "";
16
- if (!synthetic)
12
+ if (part.type !== "text")
17
13
  return true;
18
- if (id.startsWith("graphiti-memory-"))
14
+ if (part.id?.startsWith("graphiti-memory-"))
19
15
  return false;
20
- if (id.startsWith("graphiti-refresh-"))
16
+ if (part.id?.startsWith("graphiti-refresh-"))
21
17
  return false;
22
18
  return true;
23
19
  });
24
- const injectMemoryContext = async (state, messageText, output, prefix, useUserScope, characterBudget) => {
20
+ const injectMemoryContext = async (state, messageText, output, prefix, useUserScope, characterBudget, shouldReinject) => {
25
21
  const userGroupId = state.userGroupId;
26
22
  const projectFactsPromise = client.searchFacts({
27
23
  query: messageText,
@@ -70,14 +66,28 @@ function createChatHandler(deps) {
70
66
  .slice(0, characterBudget);
71
67
  if (!memoryContext)
72
68
  return;
73
- output.parts.unshift({
74
- type: "text",
75
- text: memoryContext,
76
- id: `${prefix}${Date.now()}`,
77
- sessionID: output.message.sessionID,
78
- messageID: output.message.id,
79
- synthetic: true,
80
- });
69
+ if ("system" in output.message) {
70
+ try {
71
+ output.message.system = memoryContext;
72
+ return;
73
+ }
74
+ catch (_err) {
75
+ // Fall through to synthetic injection.
76
+ }
77
+ }
78
+ if (shouldReinject) {
79
+ output.parts = removeSyntheticMemoryParts(output.parts);
80
+ }
81
+ {
82
+ output.parts.unshift({
83
+ type: "text",
84
+ text: memoryContext,
85
+ id: `${prefix}${Date.now()}`,
86
+ sessionID: output.message.sessionID,
87
+ messageID: output.message.id,
88
+ synthetic: true,
89
+ });
90
+ }
81
91
  logger_js_1.logger.info(`Injected ${projectFacts.length + userFacts.length} facts and ${projectNodes.length + userNodes.length} nodes`);
82
92
  };
83
93
  return async ({ sessionID }, output) => {
@@ -87,7 +97,6 @@ function createChatHandler(deps) {
87
97
  }
88
98
  const { state, resolved } = await sessionManager.resolveSessionState(sessionID);
89
99
  if (!resolved) {
90
- output.allow_buffering = true;
91
100
  logger_js_1.logger.debug("Unable to resolve session for message:", { sessionID });
92
101
  return;
93
102
  }
@@ -112,14 +121,11 @@ function createChatHandler(deps) {
112
121
  injectionInterval;
113
122
  if (!shouldInjectOnFirst && !shouldReinject)
114
123
  return;
115
- if (shouldReinject) {
116
- output.parts = removeSyntheticMemoryParts(output.parts);
117
- }
118
124
  try {
119
125
  const prefix = shouldReinject ? "graphiti-refresh-" : "graphiti-memory-";
120
126
  const useUserScope = shouldInjectOnFirst;
121
127
  const characterBudget = (0, context_limit_js_1.calculateInjectionBudget)(state.contextLimit);
122
- await injectMemoryContext(state, messageText, output, prefix, useUserScope, characterBudget);
128
+ await injectMemoryContext(state, messageText, output, prefix, useUserScope, characterBudget, shouldReinject);
123
129
  state.injectedMemories = true;
124
130
  state.lastInjectionMessageCount = state.messageCount;
125
131
  }
@@ -1,5 +1,9 @@
1
+ import type { Hooks } from "@opencode-ai/plugin";
1
2
  import type { GraphitiClient } from "../services/client.js";
2
3
  import type { SessionManager } from "../session.js";
4
+ type CompactingHook = NonNullable<Hooks["experimental.session.compacting"]>;
5
+ type CompactingInput = Parameters<CompactingHook>[0];
6
+ type CompactingOutput = Parameters<CompactingHook>[1];
3
7
  /** Dependencies for the compacting handler. */
4
8
  export interface CompactingHandlerDeps {
5
9
  sessionManager: SessionManager;
@@ -7,9 +11,6 @@ export interface CompactingHandlerDeps {
7
11
  defaultGroupId: string;
8
12
  }
9
13
  /** Creates the `experimental.session.compacting` hook handler. */
10
- export declare function createCompactingHandler(deps: CompactingHandlerDeps): ({ sessionID }: {
11
- sessionID: string;
12
- }, output: {
13
- context: string[];
14
- }) => Promise<void>;
14
+ export declare function createCompactingHandler(deps: CompactingHandlerDeps): ({ sessionID }: CompactingInput, output: CompactingOutput) => Promise<void>;
15
+ export {};
15
16
  //# sourceMappingURL=compacting.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compacting.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/compacting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,+CAA+C;AAC/C,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,qBAAqB,IAI/D,eAAe;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,EACpC,QAAQ;IAAE,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,mBAyBhC"}
1
+ {"version":3,"file":"compacting.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/compacting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,KAAK,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC,CAAC;AAC5E,KAAK,eAAe,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,KAAK,gBAAgB,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;AAEtD,+CAA+C;AAC/C,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,qBAAqB,IAI/D,eAAe,eAAe,EAC9B,QAAQ,gBAAgB,mBAyB3B"}
@@ -1,7 +1,9 @@
1
- import type { Event } from "@opencode-ai/sdk";
1
+ import type { Hooks } from "@opencode-ai/plugin";
2
2
  import type { GraphitiClient } from "../services/client.js";
3
3
  import type { ProviderListClient } from "../services/context-limit.js";
4
4
  import type { SessionManager } from "../session.js";
5
+ type EventHook = NonNullable<Hooks["event"]>;
6
+ type EventInput = Parameters<EventHook>[0];
5
7
  /** Dependencies for the event handler. */
6
8
  export interface EventHandlerDeps {
7
9
  sessionManager: SessionManager;
@@ -12,7 +14,6 @@ export interface EventHandlerDeps {
12
14
  groupIdPrefix: string;
13
15
  }
14
16
  /** Creates the `event` hook handler. */
15
- export declare function createEventHandler(deps: EventHandlerDeps): ({ event }: {
16
- event: Event;
17
- }) => Promise<void>;
17
+ export declare function createEventHandler(deps: EventHandlerDeps): ({ event }: EventInput) => Promise<void>;
18
+ export {};
18
19
  //# sourceMappingURL=event.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,IAWzC,WAAW;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,mBA+J1C"}
1
+ {"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,KAAK,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7C,KAAK,UAAU,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE3C,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,cAAc,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,kBAAkB,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,IAWzC,WAAW,UAAU,mBA+JpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/src/services/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EAEZ,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAG3B;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAS;IAEzB;;OAEG;gBACS,QAAQ,EAAE,MAAM;IAM5B,oDAAoD;IACpD,OAAO,CAAC,wBAAwB;IAOhC;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAgBjC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAOnB,QAAQ;IAkCtB,OAAO,CAAC,gBAAgB;YASV,SAAS;IAavB;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;IAyBzC;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;QACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,GAAG,OAAO,CAAC,IAAI,CAAC;IAWjB;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAsB3B;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAsB3B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;CAQpC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/src/services/client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,YAAY,EAEZ,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAG3B;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAS;IAEzB;;OAEG;gBACS,QAAQ,EAAE,MAAM;IAS5B,oDAAoD;IACpD,OAAO,CAAC,wBAAwB;IAUhC;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAgBjC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAOnB,QAAQ;IAkCtB,OAAO,CAAC,gBAAgB;YASV,SAAS;IAavB;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;IAyBzC;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;QACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,GAAG,OAAO,CAAC,IAAI,CAAC;IAWjB;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAsB3B;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAsB3B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;CAQpC"}
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.GraphitiClient = void 0;
4
7
  const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
5
8
  const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
9
+ const deno_js_1 = __importDefault(require("../../deno.js"));
6
10
  const logger_js_1 = require("./logger.js");
7
11
  /**
8
12
  * Graphiti MCP client wrapper for connecting, querying,
@@ -38,12 +42,18 @@ class GraphitiClient {
38
42
  value: void 0
39
43
  });
40
44
  this.endpoint = endpoint;
41
- this.client = new index_js_1.Client({ name: "opencode-graphiti", version: "0.1.0" });
45
+ this.client = new index_js_1.Client({
46
+ name: deno_js_1.default.name,
47
+ version: deno_js_1.default.version,
48
+ });
42
49
  this.transport = new streamableHttp_js_1.StreamableHTTPClientTransport(new URL(endpoint));
43
50
  }
44
51
  /** Create a fresh MCP Client and Transport pair. */
45
52
  createClientAndTransport() {
46
- this.client = new index_js_1.Client({ name: "opencode-graphiti", version: "0.1.0" });
53
+ this.client = new index_js_1.Client({
54
+ name: deno_js_1.default.name,
55
+ version: deno_js_1.default.version,
56
+ });
47
57
  this.transport = new streamableHttp_js_1.StreamableHTTPClientTransport(new URL(this.endpoint));
48
58
  }
49
59
  /**
@@ -1 +1 @@
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
+ {"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,CAgIpB"}
@@ -73,32 +73,40 @@ async function getCompactionContext(params) {
73
73
  const buildSection = (header, facts, nodes) => {
74
74
  const lines = [];
75
75
  lines.push(header);
76
+ lines.push("<instruction>Background context only; do not reference in titles, summaries, or opening responses unless directly relevant.</instruction>");
76
77
  if (facts.length > 0) {
77
- lines.push("### Facts");
78
+ lines.push("<facts>");
78
79
  lines.push(...(0, context_js_1.formatFactLines)(facts));
80
+ lines.push("</facts>");
79
81
  }
80
82
  if (nodes.length > 0) {
81
- lines.push("### Nodes");
83
+ lines.push("<nodes>");
82
84
  lines.push(...(0, context_js_1.formatNodeLines)(nodes));
85
+ lines.push("</nodes>");
83
86
  }
84
87
  return lines.join("\n");
85
88
  };
86
- const projectSection = buildSection("## Persistent Knowledge (Project)", projectFacts, projectNodes);
87
- const userSection = buildSection("## Persistent Knowledge (User)", userFacts, userNodes);
89
+ const projectSection = buildSection('<memory source="project">', projectFacts, projectNodes);
90
+ const userSection = buildSection('<memory source="user">', userFacts, userNodes);
88
91
  const headerLines = [
89
- "## Current Goal",
92
+ "<summary>",
93
+ "<current_goal>",
90
94
  "- ",
95
+ "</current_goal>",
91
96
  "",
92
- "## Work Completed",
97
+ "<work_completed>",
93
98
  "- ",
99
+ "</work_completed>",
94
100
  "",
95
- "## Remaining Tasks",
101
+ "<remaining_tasks>",
96
102
  "- ",
103
+ "</remaining_tasks>",
97
104
  "",
98
- "## Constraints & Decisions",
105
+ "<constraints_decisions>",
99
106
  "- ",
107
+ "</constraints_decisions>",
100
108
  "",
101
- "## Persistent Knowledge",
109
+ "<persistent_memory>",
102
110
  ];
103
111
  const header = headerLines.join("\n");
104
112
  const base = `${header}\n`;
@@ -108,10 +116,16 @@ async function getCompactionContext(params) {
108
116
  const truncatedProject = projectSection.slice(0, projectBudget);
109
117
  const truncatedUser = userSection.slice(0, userBudget);
110
118
  const sections = [header];
111
- if (truncatedProject.trim())
119
+ if (truncatedProject.trim()) {
112
120
  sections.push(truncatedProject);
113
- if (truncatedUser.trim())
121
+ sections.push("</memory>");
122
+ }
123
+ if (truncatedUser.trim()) {
114
124
  sections.push(truncatedUser);
125
+ sections.push("</memory>");
126
+ }
127
+ sections.push("</persistent_memory>");
128
+ sections.push("</summary>");
115
129
  const content = sections.join("\n").slice(0, characterBudget);
116
130
  return [content];
117
131
  }
@@ -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,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
+ {"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,CA0BR"}
@@ -9,37 +9,35 @@ const formatFactLines = (facts) => facts.map((fact) => {
9
9
  if (fact.target_node?.name)
10
10
  entities.push(fact.target_node.name);
11
11
  const entityStr = entities.length > 0 ? ` [${entities.join(" -> ")}]` : "";
12
- return `- ${fact.fact}${entityStr}`;
12
+ return `<fact>${fact.fact}${entityStr}</fact>`;
13
13
  });
14
14
  exports.formatFactLines = formatFactLines;
15
15
  const formatNodeLines = (nodes) => nodes.map((node) => {
16
16
  const labels = node.labels?.length ? ` (${node.labels.join(", ")})` : "";
17
17
  const summary = node.summary ? `: ${node.summary}` : "";
18
- return `- **${node.name}**${labels}${summary}`;
18
+ return `<node>${node.name}${labels}${summary}</node>`;
19
19
  });
20
20
  exports.formatNodeLines = formatNodeLines;
21
21
  /**
22
22
  * Format Graphiti facts and nodes into a user-facing context block.
23
23
  */
24
24
  function formatMemoryContext(facts, nodes) {
25
+ if (facts.length === 0 && nodes.length === 0) {
26
+ return "";
27
+ }
25
28
  const sections = [];
26
- sections.push("# Persistent Memory (from Graphiti Knowledge Graph)");
27
- sections.push("");
28
- sections.push("The following information was retrieved from your persistent memory.");
29
- sections.push("Use this context to inform your responses, but do not mention it unless asked.");
30
- sections.push("");
29
+ sections.push("<memory>");
30
+ sections.push("<instruction>Background context only; do not reference in titles, summaries, or opening responses unless directly relevant.</instruction>");
31
31
  if (facts.length > 0) {
32
- sections.push("## Known Facts");
32
+ sections.push("<facts>");
33
33
  sections.push(...(0, exports.formatFactLines)(facts));
34
- sections.push("");
34
+ sections.push("</facts>");
35
35
  }
36
36
  if (nodes.length > 0) {
37
- sections.push("## Known Entities");
37
+ sections.push("<nodes>");
38
38
  sections.push(...(0, exports.formatNodeLines)(nodes));
39
- sections.push("");
40
- }
41
- if (facts.length === 0 && nodes.length === 0) {
42
- return "";
39
+ sections.push("</nodes>");
43
40
  }
41
+ sections.push("</memory>");
44
42
  return sections.join("\n");
45
43
  }