opencode-graphiti 0.1.5 → 0.1.7
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 +35 -18
- package/esm/src/config.d.ts.map +1 -1
- package/esm/src/config.js +4 -2
- package/esm/src/handlers/chat.d.ts +2 -1
- package/esm/src/handlers/chat.d.ts.map +1 -1
- package/esm/src/handlers/chat.js +100 -49
- package/esm/src/handlers/compacting.d.ts +1 -0
- package/esm/src/handlers/compacting.d.ts.map +1 -1
- package/esm/src/handlers/compacting.js +2 -1
- package/esm/src/handlers/event.d.ts +2 -2
- package/esm/src/handlers/event.d.ts.map +1 -1
- package/esm/src/handlers/event.js +52 -1
- package/esm/src/handlers/system.d.ts +11 -0
- package/esm/src/handlers/system.d.ts.map +1 -0
- package/esm/src/handlers/system.js +18 -0
- package/esm/src/index.d.ts.map +1 -1
- package/esm/src/index.js +8 -2
- package/esm/src/services/client.d.ts +8 -1
- package/esm/src/services/client.d.ts.map +1 -1
- package/esm/src/services/client.js +23 -0
- package/esm/src/services/compaction.d.ts +10 -0
- package/esm/src/services/compaction.d.ts.map +1 -1
- package/esm/src/services/compaction.js +106 -18
- package/esm/src/services/context-limit.d.ts +2 -8
- package/esm/src/services/context-limit.d.ts.map +1 -1
- package/esm/src/services/context-limit.js +3 -1
- package/esm/src/services/context.d.ts +27 -2
- package/esm/src/services/context.d.ts.map +1 -1
- package/esm/src/services/context.js +107 -13
- package/esm/src/services/logger.d.ts.map +1 -1
- package/esm/src/services/logger.js +1 -2
- package/esm/src/session.d.ts +6 -25
- package/esm/src/session.d.ts.map +1 -1
- package/esm/src/session.js +4 -7
- package/esm/src/types/index.d.ts +8 -2
- package/esm/src/types/index.d.ts.map +1 -1
- package/package.json +2 -3
- package/script/src/config.d.ts.map +1 -1
- package/script/src/config.js +4 -2
- package/script/src/handlers/chat.d.ts +2 -1
- package/script/src/handlers/chat.d.ts.map +1 -1
- package/script/src/handlers/chat.js +99 -48
- package/script/src/handlers/compacting.d.ts +1 -0
- package/script/src/handlers/compacting.d.ts.map +1 -1
- package/script/src/handlers/compacting.js +2 -1
- package/script/src/handlers/event.d.ts +2 -2
- package/script/src/handlers/event.d.ts.map +1 -1
- package/script/src/handlers/event.js +52 -1
- package/script/src/handlers/system.d.ts +11 -0
- package/script/src/handlers/system.d.ts.map +1 -0
- package/script/src/handlers/system.js +21 -0
- package/script/src/index.d.ts.map +1 -1
- package/script/src/index.js +8 -2
- package/script/src/services/client.d.ts +8 -1
- package/script/src/services/client.d.ts.map +1 -1
- package/script/src/services/client.js +23 -0
- package/script/src/services/compaction.d.ts +10 -0
- package/script/src/services/compaction.d.ts.map +1 -1
- package/script/src/services/compaction.js +108 -17
- package/script/src/services/context-limit.d.ts +2 -8
- package/script/src/services/context-limit.d.ts.map +1 -1
- package/script/src/services/context-limit.js +3 -1
- package/script/src/services/context.d.ts +27 -2
- package/script/src/services/context.d.ts.map +1 -1
- package/script/src/services/context.js +118 -14
- package/script/src/services/logger.d.ts.map +1 -1
- package/script/src/services/logger.js +1 -35
- package/script/src/session.d.ts +6 -25
- package/script/src/session.d.ts.map +1 -1
- package/script/src/session.js +4 -7
- package/script/src/types/index.d.ts +8 -2
- package/script/src/types/index.d.ts.map +1 -1
- package/esm/_dnt.shims.d.ts +0 -6
- package/esm/_dnt.shims.d.ts.map +0 -1
- package/esm/_dnt.shims.js +0 -61
- package/script/_dnt.shims.d.ts +0 -6
- package/script/_dnt.shims.d.ts.map +0 -1
- package/script/_dnt.shims.js +0 -65
|
@@ -7,17 +7,8 @@ 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
|
-
const { sessionManager,
|
|
11
|
-
const
|
|
12
|
-
if (part.type !== "text")
|
|
13
|
-
return true;
|
|
14
|
-
if (part.id?.startsWith("graphiti-memory-"))
|
|
15
|
-
return false;
|
|
16
|
-
if (part.id?.startsWith("graphiti-refresh-"))
|
|
17
|
-
return false;
|
|
18
|
-
return true;
|
|
19
|
-
});
|
|
20
|
-
const injectMemoryContext = async (state, messageText, output, prefix, useUserScope, characterBudget, shouldReinject) => {
|
|
10
|
+
const { sessionManager, driftThreshold, factStaleDays, client } = deps;
|
|
11
|
+
const searchAndCacheMemoryContext = async (state, messageText, useUserScope, characterBudget, seedFactUuids) => {
|
|
21
12
|
const userGroupId = state.userGroupId;
|
|
22
13
|
const projectFactsPromise = client.searchFacts({
|
|
23
14
|
query: messageText,
|
|
@@ -50,45 +41,85 @@ function createChatHandler(deps) {
|
|
|
50
41
|
userFactsPromise,
|
|
51
42
|
userNodesPromise,
|
|
52
43
|
]);
|
|
53
|
-
const projectContext = (0, context_js_1.
|
|
54
|
-
|
|
55
|
-
|
|
44
|
+
const projectContext = (0, context_js_1.deduplicateContext)({
|
|
45
|
+
facts: projectFacts,
|
|
46
|
+
nodes: projectNodes,
|
|
47
|
+
});
|
|
48
|
+
const userContext = (0, context_js_1.deduplicateContext)({
|
|
49
|
+
facts: userFacts,
|
|
50
|
+
nodes: userNodes,
|
|
51
|
+
});
|
|
52
|
+
const projectContextString = (0, context_js_1.formatMemoryContext)(projectContext.facts, projectContext.nodes, { factStaleDays });
|
|
53
|
+
const userContextString = (0, context_js_1.formatMemoryContext)(userContext.facts, userContext.nodes, { factStaleDays });
|
|
54
|
+
if (!projectContextString && !userContextString)
|
|
56
55
|
return;
|
|
56
|
+
let snapshotPrimer = "";
|
|
57
|
+
if (useUserScope && characterBudget > 0) {
|
|
58
|
+
try {
|
|
59
|
+
const episodes = await client.getEpisodes({
|
|
60
|
+
groupId: state.groupId,
|
|
61
|
+
lastN: 10,
|
|
62
|
+
});
|
|
63
|
+
const snapshot = episodes
|
|
64
|
+
.filter((episode) => {
|
|
65
|
+
const description = episode.sourceDescription ??
|
|
66
|
+
episode.source_description ?? "";
|
|
67
|
+
return description === "session-snapshot";
|
|
68
|
+
})
|
|
69
|
+
.sort((a, b) => {
|
|
70
|
+
const aTime = a.created_at ? Date.parse(a.created_at) : 0;
|
|
71
|
+
const bTime = b.created_at ? Date.parse(b.created_at) : 0;
|
|
72
|
+
return bTime - aTime;
|
|
73
|
+
})[0];
|
|
74
|
+
if (snapshot?.content) {
|
|
75
|
+
const snapshotBudget = Math.min(characterBudget, 1200);
|
|
76
|
+
snapshotPrimer = [
|
|
77
|
+
"## Session Snapshot",
|
|
78
|
+
"> Most recent session snapshot; use to restore active strategy and open questions.",
|
|
79
|
+
"",
|
|
80
|
+
snapshot.content.slice(0, snapshotBudget),
|
|
81
|
+
].join("\n");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
logger_js_1.logger.error("Failed to load session snapshot", { err });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
57
88
|
const projectBudget = useUserScope
|
|
58
89
|
? Math.floor(characterBudget * 0.7)
|
|
59
90
|
: characterBudget;
|
|
60
91
|
const userBudget = characterBudget - projectBudget;
|
|
61
|
-
const truncatedProject =
|
|
62
|
-
const truncatedUser = useUserScope
|
|
63
|
-
|
|
92
|
+
const truncatedProject = projectContextString.slice(0, projectBudget);
|
|
93
|
+
const truncatedUser = useUserScope
|
|
94
|
+
? userContextString.slice(0, userBudget)
|
|
95
|
+
: "";
|
|
96
|
+
const memoryContext = [snapshotPrimer, truncatedProject, truncatedUser]
|
|
64
97
|
.filter((section) => section.trim().length > 0)
|
|
65
98
|
.join("\n\n")
|
|
66
99
|
.slice(0, characterBudget);
|
|
67
100
|
if (!memoryContext)
|
|
68
101
|
return;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
messageID: output.message.id,
|
|
88
|
-
synthetic: true,
|
|
89
|
-
});
|
|
102
|
+
const allFactUuids = [
|
|
103
|
+
...projectContext.facts.map((fact) => fact.uuid),
|
|
104
|
+
...userContext.facts.map((fact) => fact.uuid),
|
|
105
|
+
];
|
|
106
|
+
const factUuids = seedFactUuids ?? Array.from(new Set(allFactUuids));
|
|
107
|
+
state.cachedMemoryContext = memoryContext;
|
|
108
|
+
logger_js_1.logger.info(`Cached ${projectFacts.length + userFacts.length} facts and ${projectNodes.length + userNodes.length} nodes for system prompt injection`);
|
|
109
|
+
state.lastInjectionFactUuids = factUuids;
|
|
110
|
+
};
|
|
111
|
+
const computeJaccardSimilarity = (left, right) => {
|
|
112
|
+
if (left.length === 0 && right.length === 0)
|
|
113
|
+
return 1;
|
|
114
|
+
const leftSet = new Set(left);
|
|
115
|
+
const rightSet = new Set(right);
|
|
116
|
+
let intersection = 0;
|
|
117
|
+
for (const value of leftSet) {
|
|
118
|
+
if (rightSet.has(value))
|
|
119
|
+
intersection += 1;
|
|
90
120
|
}
|
|
91
|
-
|
|
121
|
+
const union = leftSet.size + rightSet.size - intersection;
|
|
122
|
+
return union === 0 ? 1 : intersection / union;
|
|
92
123
|
};
|
|
93
124
|
return async ({ sessionID }, output) => {
|
|
94
125
|
if (await sessionManager.isSubagentSession(sessionID)) {
|
|
@@ -115,19 +146,39 @@ function createChatHandler(deps) {
|
|
|
115
146
|
messageLength: messageText.length,
|
|
116
147
|
});
|
|
117
148
|
const shouldInjectOnFirst = !state.injectedMemories;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
149
|
+
let shouldReinject = false;
|
|
150
|
+
let currentFactUuids = null;
|
|
151
|
+
if (!shouldInjectOnFirst) {
|
|
152
|
+
try {
|
|
153
|
+
const driftFacts = await client.searchFacts({
|
|
154
|
+
query: messageText,
|
|
155
|
+
groupIds: [state.groupId],
|
|
156
|
+
maxFacts: 20,
|
|
157
|
+
});
|
|
158
|
+
currentFactUuids = driftFacts.map((fact) => fact.uuid);
|
|
159
|
+
const similarity = computeJaccardSimilarity(currentFactUuids, state.lastInjectionFactUuids);
|
|
160
|
+
shouldReinject = similarity < driftThreshold;
|
|
161
|
+
if (!shouldReinject) {
|
|
162
|
+
logger_js_1.logger.debug("Skipping reinjection; similarity above threshold", {
|
|
163
|
+
sessionID,
|
|
164
|
+
similarity,
|
|
165
|
+
});
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
logger_js_1.logger.error("Failed to check topic drift, skipping reinjection", {
|
|
171
|
+
sessionID,
|
|
172
|
+
err,
|
|
173
|
+
});
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
124
177
|
try {
|
|
125
|
-
const prefix = shouldReinject ? "graphiti-refresh-" : "graphiti-memory-";
|
|
126
178
|
const useUserScope = shouldInjectOnFirst;
|
|
127
179
|
const characterBudget = (0, context_limit_js_1.calculateInjectionBudget)(state.contextLimit);
|
|
128
|
-
await
|
|
180
|
+
await searchAndCacheMemoryContext(state, messageText, useUserScope, characterBudget, currentFactUuids);
|
|
129
181
|
state.injectedMemories = true;
|
|
130
|
-
state.lastInjectionMessageCount = state.messageCount;
|
|
131
182
|
}
|
|
132
183
|
catch (err) {
|
|
133
184
|
logger_js_1.logger.error("Failed to inject memories:", err);
|
|
@@ -9,6 +9,7 @@ export interface CompactingHandlerDeps {
|
|
|
9
9
|
sessionManager: SessionManager;
|
|
10
10
|
client: GraphitiClient;
|
|
11
11
|
defaultGroupId: string;
|
|
12
|
+
factStaleDays: number;
|
|
12
13
|
}
|
|
13
14
|
/** Creates the `experimental.session.compacting` hook handler. */
|
|
14
15
|
export declare function createCompactingHandler(deps: CompactingHandlerDeps): ({ sessionID }: CompactingInput, output: CompactingOutput) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,qBAAqB,IAI/D,eAAe,eAAe,EAC9B,QAAQ,gBAAgB,mBA0B3B"}
|
|
@@ -6,7 +6,7 @@ const context_limit_js_1 = require("../services/context-limit.js");
|
|
|
6
6
|
const logger_js_1 = require("../services/logger.js");
|
|
7
7
|
/** Creates the `experimental.session.compacting` hook handler. */
|
|
8
8
|
function createCompactingHandler(deps) {
|
|
9
|
-
const { sessionManager, client, defaultGroupId } = deps;
|
|
9
|
+
const { sessionManager, client, defaultGroupId, factStaleDays } = deps;
|
|
10
10
|
return async ({ sessionID }, output) => {
|
|
11
11
|
const state = sessionManager.getState(sessionID);
|
|
12
12
|
if (!state?.isMain) {
|
|
@@ -23,6 +23,7 @@ function createCompactingHandler(deps) {
|
|
|
23
23
|
user: state.userGroupId,
|
|
24
24
|
},
|
|
25
25
|
contextStrings: output.context,
|
|
26
|
+
factStaleDays,
|
|
26
27
|
});
|
|
27
28
|
if (additionalContext.length > 0) {
|
|
28
29
|
output.context.push(...additionalContext);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Hooks } from "@opencode-ai/plugin";
|
|
2
|
+
import type { OpencodeClient } from "@opencode-ai/sdk";
|
|
2
3
|
import type { GraphitiClient } from "../services/client.js";
|
|
3
|
-
import type { ProviderListClient } from "../services/context-limit.js";
|
|
4
4
|
import type { SessionManager } from "../session.js";
|
|
5
5
|
type EventHook = NonNullable<Hooks["event"]>;
|
|
6
6
|
type EventInput = Parameters<EventHook>[0];
|
|
@@ -9,7 +9,7 @@ export interface EventHandlerDeps {
|
|
|
9
9
|
sessionManager: SessionManager;
|
|
10
10
|
client: GraphitiClient;
|
|
11
11
|
defaultGroupId: string;
|
|
12
|
-
sdkClient:
|
|
12
|
+
sdkClient: OpencodeClient;
|
|
13
13
|
directory: string;
|
|
14
14
|
groupIdPrefix: string;
|
|
15
15
|
}
|
|
@@ -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,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,
|
|
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,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,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,cAAc,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,IAkDzC,WAAW,UAAU,mBAkLpC"}
|
|
@@ -9,6 +9,41 @@ const utils_js_1 = require("../utils.js");
|
|
|
9
9
|
function createEventHandler(deps) {
|
|
10
10
|
const { sessionManager, client, defaultGroupId, sdkClient, directory, groupIdPrefix, } = deps;
|
|
11
11
|
const defaultUserGroupId = (0, utils_js_1.makeUserGroupId)(groupIdPrefix);
|
|
12
|
+
const buildSessionSnapshot = (sessionId, messages) => {
|
|
13
|
+
const recentMessages = messages.slice(-12);
|
|
14
|
+
const recentAssistant = [...recentMessages]
|
|
15
|
+
.reverse()
|
|
16
|
+
.find((message) => message.startsWith("Assistant:"))
|
|
17
|
+
?.replace(/^Assistant:\s*/, "")
|
|
18
|
+
.trim();
|
|
19
|
+
const recentUser = [...recentMessages]
|
|
20
|
+
.reverse()
|
|
21
|
+
.find((message) => message.startsWith("User:"))
|
|
22
|
+
?.replace(/^User:\s*/, "")
|
|
23
|
+
.trim();
|
|
24
|
+
const questionRegex = /[^\n\r?]{3,200}\?/g;
|
|
25
|
+
const questions = recentMessages
|
|
26
|
+
.flatMap((message) => {
|
|
27
|
+
const text = message.replace(/^(User|Assistant):\s*/, "");
|
|
28
|
+
return text.match(questionRegex) ?? [];
|
|
29
|
+
})
|
|
30
|
+
.map((question) => question.trim());
|
|
31
|
+
const uniqueQuestions = Array.from(new Set(questions)).slice(0, 6);
|
|
32
|
+
const lines = [];
|
|
33
|
+
lines.push(`Session ${sessionId} working snapshot`);
|
|
34
|
+
if (recentUser)
|
|
35
|
+
lines.push(`Recent user focus: ${recentUser}`);
|
|
36
|
+
if (recentAssistant) {
|
|
37
|
+
lines.push(`Recent assistant focus: ${recentAssistant}`);
|
|
38
|
+
}
|
|
39
|
+
if (uniqueQuestions.length > 0) {
|
|
40
|
+
lines.push("Open questions:");
|
|
41
|
+
for (const question of uniqueQuestions) {
|
|
42
|
+
lines.push(`- ${question}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return lines.join("\n");
|
|
46
|
+
};
|
|
12
47
|
return async ({ event }) => {
|
|
13
48
|
try {
|
|
14
49
|
if (event.type === "session.created") {
|
|
@@ -27,7 +62,7 @@ function createEventHandler(deps) {
|
|
|
27
62
|
groupId: defaultGroupId,
|
|
28
63
|
userGroupId: defaultUserGroupId,
|
|
29
64
|
injectedMemories: false,
|
|
30
|
-
|
|
65
|
+
lastInjectionFactUuids: [],
|
|
31
66
|
messageCount: 0,
|
|
32
67
|
pendingMessages: [],
|
|
33
68
|
contextLimit: 200_000,
|
|
@@ -74,6 +109,22 @@ function createEventHandler(deps) {
|
|
|
74
109
|
logger_js_1.logger.debug("Ignoring non-main idle session:", sessionId);
|
|
75
110
|
return;
|
|
76
111
|
}
|
|
112
|
+
try {
|
|
113
|
+
const snapshotContent = buildSessionSnapshot(sessionId, state.pendingMessages);
|
|
114
|
+
if (snapshotContent.trim()) {
|
|
115
|
+
await client.addEpisode({
|
|
116
|
+
name: `Snapshot: ${sessionId}`,
|
|
117
|
+
episodeBody: snapshotContent,
|
|
118
|
+
groupId: state.groupId,
|
|
119
|
+
source: "text",
|
|
120
|
+
sourceDescription: "session-snapshot",
|
|
121
|
+
});
|
|
122
|
+
logger_js_1.logger.info("Saved session snapshot", { sessionId });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
logger_js_1.logger.error("Failed to save session snapshot", { sessionId, err });
|
|
127
|
+
}
|
|
77
128
|
await sessionManager.flushPendingMessages(sessionId, "Buffered messages from OpenCode session", 50);
|
|
78
129
|
return;
|
|
79
130
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Hooks } from "@opencode-ai/plugin";
|
|
2
|
+
import type { SessionManager } from "../session.js";
|
|
3
|
+
type SystemTransformHook = NonNullable<Hooks["experimental.chat.system.transform"]>;
|
|
4
|
+
type SystemTransformInput = Parameters<SystemTransformHook>[0];
|
|
5
|
+
type SystemTransformOutput = Parameters<SystemTransformHook>[1];
|
|
6
|
+
export interface SystemHandlerDeps {
|
|
7
|
+
sessionManager: SessionManager;
|
|
8
|
+
}
|
|
9
|
+
export declare function createSystemHandler(deps: SystemHandlerDeps): ({ sessionID }: SystemTransformInput, output: SystemTransformOutput) => Promise<void>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=system.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/system.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,KAAK,mBAAmB,GAAG,WAAW,CACpC,KAAK,CAAC,oCAAoC,CAAC,CAC5C,CAAC;AACF,KAAK,oBAAoB,GAAG,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,KAAK,qBAAqB,GAAG,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,cAAc,CAAC;CAChC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,IAMvD,eAAe,oBAAoB,EACnC,QAAQ,qBAAqB,mBAYhC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSystemHandler = createSystemHandler;
|
|
4
|
+
const logger_js_1 = require("../services/logger.js");
|
|
5
|
+
function createSystemHandler(deps) {
|
|
6
|
+
const { sessionManager } = deps;
|
|
7
|
+
// Assumes chat.message hook completes before system.transform fires for the same turn.
|
|
8
|
+
// deno-lint-ignore require-await
|
|
9
|
+
return async ({ sessionID }, output) => {
|
|
10
|
+
if (!sessionID)
|
|
11
|
+
return;
|
|
12
|
+
const state = sessionManager.getState(sessionID);
|
|
13
|
+
if (!state?.isMain)
|
|
14
|
+
return;
|
|
15
|
+
if (!state.cachedMemoryContext)
|
|
16
|
+
return;
|
|
17
|
+
output.system.push(state.cachedMemoryContext);
|
|
18
|
+
state.cachedMemoryContext = undefined;
|
|
19
|
+
logger_js_1.logger.info("Injected memory context into system prompt");
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAW/D;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAW/D;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,MAuDtB,CAAC"}
|
package/script/src/index.js
CHANGED
|
@@ -5,6 +5,7 @@ const config_js_1 = require("./config.js");
|
|
|
5
5
|
const chat_js_1 = require("./handlers/chat.js");
|
|
6
6
|
const compacting_js_1 = require("./handlers/compacting.js");
|
|
7
7
|
const event_js_1 = require("./handlers/event.js");
|
|
8
|
+
const system_js_1 = require("./handlers/system.js");
|
|
8
9
|
const client_js_1 = require("./services/client.js");
|
|
9
10
|
const logger_js_1 = require("./services/logger.js");
|
|
10
11
|
const session_js_1 = require("./session.js");
|
|
@@ -30,19 +31,24 @@ const graphiti = async (input) => {
|
|
|
30
31
|
sessionManager,
|
|
31
32
|
client,
|
|
32
33
|
defaultGroupId,
|
|
33
|
-
sdkClient
|
|
34
|
+
sdkClient,
|
|
34
35
|
directory: input.directory,
|
|
35
36
|
groupIdPrefix: config.groupIdPrefix,
|
|
36
37
|
}),
|
|
37
38
|
"chat.message": (0, chat_js_1.createChatHandler)({
|
|
38
39
|
sessionManager,
|
|
39
|
-
|
|
40
|
+
driftThreshold: config.driftThreshold,
|
|
41
|
+
factStaleDays: config.factStaleDays,
|
|
40
42
|
client,
|
|
41
43
|
}),
|
|
42
44
|
"experimental.session.compacting": (0, compacting_js_1.createCompactingHandler)({
|
|
43
45
|
sessionManager,
|
|
44
46
|
client,
|
|
45
47
|
defaultGroupId,
|
|
48
|
+
factStaleDays: config.factStaleDays,
|
|
49
|
+
}),
|
|
50
|
+
"experimental.chat.system.transform": (0, system_js_1.createSystemHandler)({
|
|
51
|
+
sessionManager,
|
|
46
52
|
}),
|
|
47
53
|
};
|
|
48
54
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GraphitiFact, GraphitiNode } from "../types/index.js";
|
|
1
|
+
import type { GraphitiEpisode, GraphitiFact, GraphitiNode } from "../types/index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Graphiti MCP client wrapper for connecting, querying,
|
|
4
4
|
* and persisting episodes with basic reconnection handling.
|
|
@@ -57,6 +57,13 @@ export declare class GraphitiClient {
|
|
|
57
57
|
groupIds?: string[];
|
|
58
58
|
maxNodes?: number;
|
|
59
59
|
}): Promise<GraphitiNode[]>;
|
|
60
|
+
/**
|
|
61
|
+
* Retrieve recent episodes for a group.
|
|
62
|
+
*/
|
|
63
|
+
getEpisodes(params: {
|
|
64
|
+
groupId?: string;
|
|
65
|
+
lastN?: number;
|
|
66
|
+
}): Promise<GraphitiEpisode[]>;
|
|
60
67
|
/**
|
|
61
68
|
* Check whether the Graphiti MCP server is reachable.
|
|
62
69
|
*/
|
|
@@ -1 +1 @@
|
|
|
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
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/src/services/client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,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,WAAW,CAAC,MAAM,EAAE;QACxB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAqB9B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;CAQpC"}
|
|
@@ -221,6 +221,29 @@ class GraphitiClient {
|
|
|
221
221
|
return [];
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Retrieve recent episodes for a group.
|
|
226
|
+
*/
|
|
227
|
+
async getEpisodes(params) {
|
|
228
|
+
try {
|
|
229
|
+
const result = await this.callTool("get_episodes", {
|
|
230
|
+
group_id: params.groupId,
|
|
231
|
+
last_n: params.lastN,
|
|
232
|
+
});
|
|
233
|
+
if (Array.isArray(result))
|
|
234
|
+
return result;
|
|
235
|
+
if (result &&
|
|
236
|
+
typeof result === "object" &&
|
|
237
|
+
Array.isArray(result.episodes)) {
|
|
238
|
+
return result.episodes;
|
|
239
|
+
}
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
logger_js_1.logger.error("getEpisodes error:", err);
|
|
244
|
+
return [];
|
|
245
|
+
}
|
|
246
|
+
}
|
|
224
247
|
/**
|
|
225
248
|
* Check whether the Graphiti MCP server is reachable.
|
|
226
249
|
*/
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { GraphitiFact, GraphitiNode } from "../types/index.js";
|
|
2
|
+
export declare const classifyFacts: (facts: GraphitiFact[], now: Date) => {
|
|
3
|
+
decisions: GraphitiFact[];
|
|
4
|
+
active: GraphitiFact[];
|
|
5
|
+
background: GraphitiFact[];
|
|
6
|
+
};
|
|
7
|
+
export declare const takeFactsWithinBudget: (facts: GraphitiFact[], budget: number, formatOptions: {
|
|
8
|
+
factStaleDays: number;
|
|
9
|
+
now: Date;
|
|
10
|
+
}) => GraphitiFact[];
|
|
2
11
|
/**
|
|
3
12
|
* Persist a compaction summary episode when enabled.
|
|
4
13
|
*/
|
|
@@ -38,5 +47,6 @@ export declare function getCompactionContext(params: {
|
|
|
38
47
|
user?: string;
|
|
39
48
|
};
|
|
40
49
|
contextStrings: string[];
|
|
50
|
+
factStaleDays?: number;
|
|
41
51
|
}): Promise<string[]>;
|
|
42
52
|
//# sourceMappingURL=compaction.d.ts.map
|
|
@@ -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;
|
|
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;AA0BpE,eAAO,MAAM,aAAa,GACxB,OAAO,YAAY,EAAE,EACrB,KAAK,IAAI,KACR;IACD,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,UAAU,EAAE,YAAY,EAAE,CAAC;CA4B5B,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,OAAO,YAAY,EAAE,EACrB,QAAQ,MAAM,EACd,eAAe;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,IAAI,CAAA;CAAE,KAClD,YAAY,EAoBd,CAAC;AAEF;;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;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA0KpB"}
|