opencode-graphiti 0.1.9 → 0.1.10
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 +7 -1
- package/esm/_dnt.polyfills.d.ts +50 -0
- package/esm/_dnt.polyfills.d.ts.map +1 -0
- package/esm/_dnt.polyfills.js +37 -0
- package/esm/mod.d.ts +1 -0
- package/esm/mod.d.ts.map +1 -1
- package/esm/mod.js +1 -0
- package/esm/src/config.d.ts +7 -1
- package/esm/src/config.d.ts.map +1 -1
- package/esm/src/config.js +17 -5
- package/esm/src/handlers/chat.d.ts.map +1 -1
- package/esm/src/handlers/chat.js +51 -42
- package/esm/src/handlers/event.d.ts +1 -1
- package/esm/src/handlers/event.d.ts.map +1 -1
- package/esm/src/handlers/event.js +42 -46
- package/esm/src/handlers/messages.d.ts.map +1 -1
- package/esm/src/handlers/messages.js +2 -3
- package/esm/src/index.js +2 -2
- package/esm/src/services/client.d.ts +7 -0
- package/esm/src/services/client.d.ts.map +1 -1
- package/esm/src/services/client.js +22 -24
- package/esm/src/services/compaction.d.ts.map +1 -1
- package/esm/src/services/compaction.js +24 -33
- package/esm/src/services/constants.d.ts +7 -0
- package/esm/src/services/constants.d.ts.map +1 -0
- package/esm/src/services/constants.js +6 -0
- package/esm/src/services/context-limit.d.ts +1 -1
- package/esm/src/services/context-limit.d.ts.map +1 -1
- package/esm/src/services/context-limit.js +12 -14
- package/esm/src/services/context.d.ts +27 -7
- package/esm/src/services/context.d.ts.map +1 -1
- package/esm/src/services/context.js +34 -2
- package/esm/src/services/logger.js +2 -4
- package/esm/src/services/sdk-normalize.d.ts +55 -0
- package/esm/src/services/sdk-normalize.d.ts.map +1 -0
- package/esm/src/services/sdk-normalize.js +61 -0
- package/esm/src/session.d.ts +4 -2
- package/esm/src/session.d.ts.map +1 -1
- package/esm/src/session.js +38 -34
- package/esm/src/types/index.d.ts +13 -14
- package/esm/src/types/index.d.ts.map +1 -1
- package/esm/src/utils.d.ts +6 -0
- package/esm/src/utils.d.ts.map +1 -1
- package/esm/src/utils.js +16 -2
- package/package.json +1 -1
- package/script/_dnt.polyfills.d.ts +50 -0
- package/script/_dnt.polyfills.d.ts.map +1 -0
- package/script/_dnt.polyfills.js +38 -0
- package/script/mod.d.ts +1 -0
- package/script/mod.d.ts.map +1 -1
- package/script/mod.js +1 -0
- package/script/src/config.d.ts +7 -1
- package/script/src/config.d.ts.map +1 -1
- package/script/src/config.js +20 -5
- package/script/src/handlers/chat.d.ts.map +1 -1
- package/script/src/handlers/chat.js +49 -40
- package/script/src/handlers/event.d.ts +1 -1
- package/script/src/handlers/event.d.ts.map +1 -1
- package/script/src/handlers/event.js +41 -45
- package/script/src/handlers/messages.d.ts.map +1 -1
- package/script/src/handlers/messages.js +2 -3
- package/script/src/index.js +2 -2
- package/script/src/services/client.d.ts +7 -0
- package/script/src/services/client.d.ts.map +1 -1
- package/script/src/services/client.js +22 -24
- package/script/src/services/compaction.d.ts.map +1 -1
- package/script/src/services/compaction.js +24 -33
- package/script/src/services/constants.d.ts +7 -0
- package/script/src/services/constants.d.ts.map +1 -0
- package/script/src/services/constants.js +9 -0
- package/script/src/services/context-limit.d.ts +1 -1
- package/script/src/services/context-limit.d.ts.map +1 -1
- package/script/src/services/context-limit.js +13 -15
- package/script/src/services/context.d.ts +27 -7
- package/script/src/services/context.d.ts.map +1 -1
- package/script/src/services/context.js +36 -4
- package/script/src/services/logger.js +2 -4
- package/script/src/services/sdk-normalize.d.ts +55 -0
- package/script/src/services/sdk-normalize.d.ts.map +1 -0
- package/script/src/services/sdk-normalize.js +67 -0
- package/script/src/session.d.ts +4 -2
- package/script/src/session.d.ts.map +1 -1
- package/script/src/session.js +38 -34
- package/script/src/types/index.d.ts +13 -14
- package/script/src/types/index.d.ts.map +1 -1
- package/script/src/utils.d.ts +6 -0
- package/script/src/utils.d.ts.map +1 -1
- package/script/src/utils.js +18 -3
|
@@ -2,6 +2,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
|
2
2
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
3
3
|
import manifest from "../../deno.js";
|
|
4
4
|
import { logger } from "./logger.js";
|
|
5
|
+
import { normalizeEpisode } from "./sdk-normalize.js";
|
|
5
6
|
/**
|
|
6
7
|
* Graphiti MCP client wrapper for connecting, querying,
|
|
7
8
|
* and persisting episodes with basic reconnection handling.
|
|
@@ -167,6 +168,22 @@ export class GraphitiClient {
|
|
|
167
168
|
});
|
|
168
169
|
logger.debug("Added episode:", params.name);
|
|
169
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Extract an array from a tool result that may be a bare array or a
|
|
173
|
+
* wrapped-array response object (`{ [key]: T[] }`).
|
|
174
|
+
* Returns the array when found, otherwise `null`.
|
|
175
|
+
* Public for testing.
|
|
176
|
+
*/
|
|
177
|
+
parseWrappedArray(result, wrappedKey) {
|
|
178
|
+
if (Array.isArray(result))
|
|
179
|
+
return result;
|
|
180
|
+
if (result &&
|
|
181
|
+
typeof result === "object" &&
|
|
182
|
+
Array.isArray(result[wrappedKey])) {
|
|
183
|
+
return result[wrappedKey];
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
170
187
|
/**
|
|
171
188
|
* Search Graphiti facts matching the provided query.
|
|
172
189
|
*/
|
|
@@ -177,14 +194,7 @@ export class GraphitiClient {
|
|
|
177
194
|
group_ids: params.groupIds,
|
|
178
195
|
max_facts: params.maxFacts || 10,
|
|
179
196
|
});
|
|
180
|
-
|
|
181
|
-
return result;
|
|
182
|
-
if (result &&
|
|
183
|
-
typeof result === "object" &&
|
|
184
|
-
Array.isArray(result.facts)) {
|
|
185
|
-
return result.facts;
|
|
186
|
-
}
|
|
187
|
-
return [];
|
|
197
|
+
return this.parseWrappedArray(result, "facts") ?? [];
|
|
188
198
|
}
|
|
189
199
|
catch (err) {
|
|
190
200
|
logger.error("searchFacts error:", err);
|
|
@@ -201,14 +211,7 @@ export class GraphitiClient {
|
|
|
201
211
|
group_ids: params.groupIds,
|
|
202
212
|
max_nodes: params.maxNodes || 10,
|
|
203
213
|
});
|
|
204
|
-
|
|
205
|
-
return result;
|
|
206
|
-
if (result &&
|
|
207
|
-
typeof result === "object" &&
|
|
208
|
-
Array.isArray(result.nodes)) {
|
|
209
|
-
return result.nodes;
|
|
210
|
-
}
|
|
211
|
-
return [];
|
|
214
|
+
return this.parseWrappedArray(result, "nodes") ?? [];
|
|
212
215
|
}
|
|
213
216
|
catch (err) {
|
|
214
217
|
logger.error("searchNodes error:", err);
|
|
@@ -224,14 +227,9 @@ export class GraphitiClient {
|
|
|
224
227
|
group_id: params.groupId,
|
|
225
228
|
last_n: params.lastN,
|
|
226
229
|
});
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
typeof result === "object" &&
|
|
231
|
-
Array.isArray(result.episodes)) {
|
|
232
|
-
return result.episodes;
|
|
233
|
-
}
|
|
234
|
-
return [];
|
|
230
|
+
const raw = this.parseWrappedArray(result, "episodes") ??
|
|
231
|
+
[];
|
|
232
|
+
return raw.map(normalizeEpisode);
|
|
235
233
|
}
|
|
236
234
|
catch (err) {
|
|
237
235
|
logger.error("getEpisodes error:", err);
|
|
@@ -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;AAgCpE,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;CAuB5B,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,CA4KpB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { truncateAtLineBoundary } from "../utils.js";
|
|
2
|
+
import { formatFactLines, formatNodeLines, resolveProjectUserContext, } from "./context.js";
|
|
3
|
+
import { DAY_MS, PROJECT_MAX_FACTS } from "./constants.js";
|
|
2
4
|
import { logger } from "./logger.js";
|
|
3
|
-
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
4
5
|
const DECISION_KEYWORDS = [
|
|
5
6
|
"decided",
|
|
6
7
|
"must",
|
|
@@ -17,19 +18,17 @@ const DECISION_KEYWORDS = [
|
|
|
17
18
|
"design",
|
|
18
19
|
"selected",
|
|
19
20
|
];
|
|
21
|
+
// Precompile keyword regex once, outside the fact-classification loop.
|
|
22
|
+
const DECISION_KEYWORD_REGEX = new RegExp(DECISION_KEYWORDS.map((kw) => `\\b${kw}\\b`).join("|"), "i");
|
|
20
23
|
export const classifyFacts = (facts, now) => {
|
|
21
24
|
const decisions = [];
|
|
22
25
|
const active = [];
|
|
23
26
|
const background = [];
|
|
24
27
|
const cutoff = now.getTime() - 7 * DAY_MS;
|
|
25
28
|
for (const fact of facts) {
|
|
26
|
-
const text = fact.fact
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
const regex = new RegExp(`\\b${keyword}\\b`, "i");
|
|
30
|
-
return regex.test(text);
|
|
31
|
-
});
|
|
32
|
-
if (hasDecisionKeyword) {
|
|
29
|
+
const text = fact.fact;
|
|
30
|
+
// Task 7: use precompiled regex instead of building one per keyword per fact.
|
|
31
|
+
if (DECISION_KEYWORD_REGEX.test(text)) {
|
|
33
32
|
decisions.push(fact);
|
|
34
33
|
continue;
|
|
35
34
|
}
|
|
@@ -99,7 +98,7 @@ export async function getCompactionContext(params) {
|
|
|
99
98
|
const projectFactsPromise = client.searchFacts({
|
|
100
99
|
query: queryText,
|
|
101
100
|
groupIds: [groupIds.project],
|
|
102
|
-
maxFacts:
|
|
101
|
+
maxFacts: PROJECT_MAX_FACTS,
|
|
103
102
|
});
|
|
104
103
|
const projectNodesPromise = client.searchNodes({
|
|
105
104
|
query: queryText,
|
|
@@ -121,26 +120,19 @@ export async function getCompactionContext(params) {
|
|
|
121
120
|
maxNodes: 10,
|
|
122
121
|
})
|
|
123
122
|
: Promise.resolve([]);
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
]);
|
|
123
|
+
const { projectContext, userContext, projectFacts, projectNodes, userFacts, userNodes, } = await resolveProjectUserContext({
|
|
124
|
+
projectFacts: projectFactsPromise,
|
|
125
|
+
projectNodes: projectNodesPromise,
|
|
126
|
+
userFacts: userFactsPromise,
|
|
127
|
+
userNodes: userNodesPromise,
|
|
128
|
+
});
|
|
131
129
|
if (projectFacts.length === 0 && projectNodes.length === 0 &&
|
|
132
130
|
userFacts.length === 0 && userNodes.length === 0) {
|
|
133
131
|
return [];
|
|
134
132
|
}
|
|
135
133
|
const formatOptions = { factStaleDays, now };
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
nodes: projectNodes,
|
|
139
|
-
});
|
|
140
|
-
const userContext = deduplicateContext({
|
|
141
|
-
facts: userFacts,
|
|
142
|
-
nodes: userNodes,
|
|
143
|
-
});
|
|
134
|
+
// Task 1: build section line-by-line; truncate at a line boundary to avoid
|
|
135
|
+
// cutting mid-tag or mid-line while still respecting the per-section budget.
|
|
144
136
|
const buildSection = (header, facts, nodes, budget) => {
|
|
145
137
|
const lines = [];
|
|
146
138
|
lines.push(header);
|
|
@@ -172,7 +164,7 @@ export async function getCompactionContext(params) {
|
|
|
172
164
|
lines.push(...formatNodeLines(nodes));
|
|
173
165
|
lines.push("</nodes>");
|
|
174
166
|
}
|
|
175
|
-
return lines.join("\n");
|
|
167
|
+
return truncateAtLineBoundary(lines.join("\n"), budget);
|
|
176
168
|
};
|
|
177
169
|
const headerLines = [
|
|
178
170
|
"<summary>",
|
|
@@ -197,20 +189,19 @@ export async function getCompactionContext(params) {
|
|
|
197
189
|
const userBudget = remainingBudget - projectBudget;
|
|
198
190
|
const projectSection = buildSection('<memory source="project">', projectContext.facts, projectContext.nodes, projectBudget);
|
|
199
191
|
const userSection = buildSection('<memory source="user">', userContext.facts, userContext.nodes, userBudget);
|
|
200
|
-
const truncatedProject = projectSection.slice(0, projectBudget);
|
|
201
|
-
const truncatedUser = userSection.slice(0, userBudget);
|
|
202
192
|
const sections = [header];
|
|
203
|
-
if (
|
|
204
|
-
sections.push(
|
|
193
|
+
if (projectSection.trim()) {
|
|
194
|
+
sections.push(projectSection);
|
|
205
195
|
sections.push("</memory>");
|
|
206
196
|
}
|
|
207
|
-
if (
|
|
208
|
-
sections.push(
|
|
197
|
+
if (userSection.trim()) {
|
|
198
|
+
sections.push(userSection);
|
|
209
199
|
sections.push("</memory>");
|
|
210
200
|
}
|
|
211
201
|
sections.push("</persistent_memory>");
|
|
212
202
|
sections.push("</summary>");
|
|
213
|
-
|
|
203
|
+
// Final overall truncation at a line boundary.
|
|
204
|
+
const content = truncateAtLineBoundary(sections.join("\n"), characterBudget);
|
|
214
205
|
return [content];
|
|
215
206
|
}
|
|
216
207
|
catch (err) {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Milliseconds in one day. */
|
|
2
|
+
export declare const DAY_MS: number;
|
|
3
|
+
/** Default token context limit when the provider does not report one. */
|
|
4
|
+
export declare const DEFAULT_CONTEXT_LIMIT = 200000;
|
|
5
|
+
/** Maximum project-scope facts fetched per search query. */
|
|
6
|
+
export declare const PROJECT_MAX_FACTS = 50;
|
|
7
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/src/services/constants.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,eAAO,MAAM,MAAM,QAAsB,CAAC;AAE1C,yEAAyE;AACzE,eAAO,MAAM,qBAAqB,SAAU,CAAC;AAE7C,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,KAAK,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Milliseconds in one day. */
|
|
2
|
+
export const DAY_MS = 24 * 60 * 60 * 1000;
|
|
3
|
+
/** Default token context limit when the provider does not report one. */
|
|
4
|
+
export const DEFAULT_CONTEXT_LIMIT = 200_000;
|
|
5
|
+
/** Maximum project-scope facts fetched per search query. */
|
|
6
|
+
export const PROJECT_MAX_FACTS = 50;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { OpencodeClient } from "@opencode-ai/sdk";
|
|
2
|
-
export declare function resolveContextLimit(providerID: string, modelID: string, client: OpencodeClient, directory: string): Promise<number>;
|
|
2
|
+
export declare function resolveContextLimit(providerID: string, modelID: string, client: OpencodeClient, directory: string, cache: Map<string, number>): Promise<number>;
|
|
3
3
|
/**
|
|
4
4
|
* Calculate the character budget for memory injection
|
|
5
5
|
* (5% of context limit * 4 chars/token).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-limit.d.ts","sourceRoot":"","sources":["../../../src/src/services/context-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"context-limit.d.ts","sourceRoot":"","sources":["../../../src/src/services/context-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvD,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACzB,OAAO,CAAC,MAAM,CAAC,CA4BjB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAErE"}
|
|
@@ -1,28 +1,26 @@
|
|
|
1
|
+
import { DEFAULT_CONTEXT_LIMIT } from "./constants.js";
|
|
1
2
|
import { logger } from "./logger.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export async function resolveContextLimit(providerID, modelID, client, directory) {
|
|
3
|
+
import { extractSdkProviders } from "./sdk-normalize.js";
|
|
4
|
+
export async function resolveContextLimit(providerID, modelID, client, directory, cache) {
|
|
5
5
|
const modelKey = `${providerID}/${modelID}`;
|
|
6
|
-
const cached =
|
|
6
|
+
const cached = cache.get(modelKey);
|
|
7
7
|
if (cached)
|
|
8
8
|
return cached;
|
|
9
9
|
try {
|
|
10
|
-
const
|
|
10
|
+
const response = await client.provider.list({
|
|
11
11
|
query: { directory },
|
|
12
12
|
});
|
|
13
|
-
const list =
|
|
13
|
+
const list = extractSdkProviders(response);
|
|
14
14
|
for (const provider of list) {
|
|
15
|
-
|
|
16
|
-
if (providerInfo.id !== providerID)
|
|
15
|
+
if (provider.id !== providerID)
|
|
17
16
|
continue;
|
|
18
|
-
const models =
|
|
17
|
+
const models = provider.models ?? [];
|
|
19
18
|
for (const model of models) {
|
|
20
|
-
|
|
21
|
-
if (modelInfo.id !== modelID)
|
|
19
|
+
if (model.id !== modelID)
|
|
22
20
|
continue;
|
|
23
|
-
const contextLimit =
|
|
21
|
+
const contextLimit = model.limit?.context;
|
|
24
22
|
if (typeof contextLimit === "number" && contextLimit > 0) {
|
|
25
|
-
|
|
23
|
+
cache.set(modelKey, contextLimit);
|
|
26
24
|
return contextLimit;
|
|
27
25
|
}
|
|
28
26
|
}
|
|
@@ -31,7 +29,7 @@ export async function resolveContextLimit(providerID, modelID, client, directory
|
|
|
31
29
|
catch (err) {
|
|
32
30
|
logger.warn("Failed to fetch provider context limit", err);
|
|
33
31
|
}
|
|
34
|
-
|
|
32
|
+
cache.set(modelKey, DEFAULT_CONTEXT_LIMIT);
|
|
35
33
|
return DEFAULT_CONTEXT_LIMIT;
|
|
36
34
|
}
|
|
37
35
|
/**
|
|
@@ -16,13 +16,33 @@ export declare const formatNodeLines: (nodes: GraphitiNode[]) => string[];
|
|
|
16
16
|
export declare const deduplicateFactsByUuid: (facts: GraphitiFact[]) => GraphitiFact[];
|
|
17
17
|
export declare const deduplicateNodesByUuid: (nodes: GraphitiNode[]) => GraphitiNode[];
|
|
18
18
|
export declare const removeNodesReferencedByFacts: (facts: GraphitiFact[], nodes: GraphitiNode[]) => GraphitiNode[];
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Await four parallel fact/node promises, deduplicate each side, and return
|
|
21
|
+
* the resolved project and user contexts.
|
|
22
|
+
*
|
|
23
|
+
* Callers construct the promises themselves — this lets chat.ts seed the
|
|
24
|
+
* project-facts promise from an earlier drift-check fetch without issuing a
|
|
25
|
+
* duplicate network request.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveProjectUserContext(promises: {
|
|
28
|
+
projectFacts: Promise<GraphitiFact[]>;
|
|
29
|
+
projectNodes: Promise<GraphitiNode[]>;
|
|
30
|
+
userFacts: Promise<GraphitiFact[]>;
|
|
31
|
+
userNodes: Promise<GraphitiNode[]>;
|
|
32
|
+
}): Promise<{
|
|
33
|
+
projectContext: {
|
|
34
|
+
facts: GraphitiFact[];
|
|
35
|
+
nodes: GraphitiNode[];
|
|
36
|
+
};
|
|
37
|
+
userContext: {
|
|
38
|
+
facts: GraphitiFact[];
|
|
39
|
+
nodes: GraphitiNode[];
|
|
40
|
+
};
|
|
41
|
+
projectFacts: GraphitiFact[];
|
|
42
|
+
projectNodes: GraphitiNode[];
|
|
43
|
+
userFacts: GraphitiFact[];
|
|
44
|
+
userNodes: GraphitiNode[];
|
|
45
|
+
}>;
|
|
26
46
|
/**
|
|
27
47
|
* Format Graphiti facts and nodes into a user-facing context block.
|
|
28
48
|
*/
|
|
@@ -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;
|
|
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;AAGpE,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,KAAG,IAAI,GAAG,IAKjD,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,YAAY,EAAE,KAAK,IAAI,KAAG,OAQ7D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,MAAM,YAAY,EAClB,KAAK,IAAI,EACT,eAAe,MAAM,KACpB,YAUF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,OAAO,YAAY,EAAE,KAAG,YAAY,EAWtE,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,OAAO,YAAY,EAAE,EACrB,UAAU;IACR,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,KACA,YAAY,EAMd,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,MAAM,YAAY,KAAG,MAMnD,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,OAAO,YAAY,EAAE,EACrB,UAAU;IACR,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,KACA,MAAM,EAGR,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,OAAO,YAAY,EAAE,KAAG,MAAM,EAK1D,CAAC;AAEL,eAAO,MAAM,sBAAsB,GACjC,OAAO,YAAY,EAAE,KACpB,YAAY,EASd,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,OAAO,YAAY,EAAE,KACpB,YAAY,EASd,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,OAAO,YAAY,EAAE,EACrB,OAAO,YAAY,EAAE,KACpB,YAAY,EAOd,CAAC;AAeF;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAAC,QAAQ,EAAE;IACxD,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACtC,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACtC,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACnC,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;CACpC,GAAG,OAAO,CAAC;IACV,cAAc,EAAE;QAAE,KAAK,EAAE,YAAY,EAAE,CAAC;QAAC,KAAK,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;IACjE,WAAW,EAAE;QAAE,KAAK,EAAE,YAAY,EAAE,CAAC;QAAC,KAAK,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;IAC9D,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B,CAAC,CAyBD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EAAE,EACrB,KAAK,EAAE,YAAY,EAAE,EACrB,OAAO,CAAC,EAAE;IACR,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,GACA,MAAM,CA6BR;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAW1D"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { DAY_MS } from "./constants.js";
|
|
2
2
|
export const parseDate = (value) => {
|
|
3
3
|
if (!value)
|
|
4
4
|
return null;
|
|
@@ -100,12 +100,44 @@ export const removeNodesReferencedByFacts = (facts, nodes) => {
|
|
|
100
100
|
}
|
|
101
101
|
return nodes.filter((node) => !factNodeUuids.has(node.uuid));
|
|
102
102
|
};
|
|
103
|
-
|
|
103
|
+
const deduplicateContext = (params) => {
|
|
104
104
|
const dedupedFacts = deduplicateFactsByUuid(params.facts);
|
|
105
105
|
const dedupedNodes = deduplicateNodesByUuid(params.nodes);
|
|
106
106
|
const filteredNodes = removeNodesReferencedByFacts(dedupedFacts, dedupedNodes);
|
|
107
107
|
return { facts: dedupedFacts, nodes: filteredNodes };
|
|
108
108
|
};
|
|
109
|
+
/**
|
|
110
|
+
* Await four parallel fact/node promises, deduplicate each side, and return
|
|
111
|
+
* the resolved project and user contexts.
|
|
112
|
+
*
|
|
113
|
+
* Callers construct the promises themselves — this lets chat.ts seed the
|
|
114
|
+
* project-facts promise from an earlier drift-check fetch without issuing a
|
|
115
|
+
* duplicate network request.
|
|
116
|
+
*/
|
|
117
|
+
export async function resolveProjectUserContext(promises) {
|
|
118
|
+
const [projectFacts, projectNodes, userFacts, userNodes] = await Promise.all([
|
|
119
|
+
promises.projectFacts,
|
|
120
|
+
promises.projectNodes,
|
|
121
|
+
promises.userFacts,
|
|
122
|
+
promises.userNodes,
|
|
123
|
+
]);
|
|
124
|
+
const projectContext = deduplicateContext({
|
|
125
|
+
facts: projectFacts,
|
|
126
|
+
nodes: projectNodes,
|
|
127
|
+
});
|
|
128
|
+
const userContext = deduplicateContext({
|
|
129
|
+
facts: userFacts,
|
|
130
|
+
nodes: userNodes,
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
projectContext,
|
|
134
|
+
userContext,
|
|
135
|
+
projectFacts,
|
|
136
|
+
projectNodes,
|
|
137
|
+
userFacts,
|
|
138
|
+
userNodes,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
109
141
|
/**
|
|
110
142
|
* Format Graphiti facts and nodes into a user-facing context block.
|
|
111
143
|
*/
|
|
@@ -7,12 +7,10 @@ export const logger = {
|
|
|
7
7
|
console.log(PREFIX, ...args);
|
|
8
8
|
},
|
|
9
9
|
warn: (...args) => {
|
|
10
|
-
|
|
11
|
-
console.warn(PREFIX, ...args);
|
|
10
|
+
console.warn(PREFIX, ...args);
|
|
12
11
|
},
|
|
13
12
|
error: (...args) => {
|
|
14
|
-
|
|
15
|
-
console.error(PREFIX, ...args);
|
|
13
|
+
console.error(PREFIX, ...args);
|
|
16
14
|
},
|
|
17
15
|
debug: (...args) => {
|
|
18
16
|
if (process.env.GRAPHITI_DEBUG)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Part } from "@opencode-ai/sdk";
|
|
2
|
+
import type { GraphitiEpisode } from "../types/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Narrow type for a single SDK message entry as returned by
|
|
5
|
+
* `session.messages()`.
|
|
6
|
+
*/
|
|
7
|
+
export type SdkMessage = {
|
|
8
|
+
info: {
|
|
9
|
+
role?: string;
|
|
10
|
+
id?: string;
|
|
11
|
+
};
|
|
12
|
+
parts: Part[];
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Normalize an SDK response that may be wrapped in `{ data: … }` or returned
|
|
16
|
+
* directly. Returns the inner value cast to `T`, or `undefined` when the
|
|
17
|
+
* response is absent.
|
|
18
|
+
*
|
|
19
|
+
* This replaces the repeated `"data" in response ? (response as
|
|
20
|
+
* { data?: … }).data : response` pattern found in session.ts and
|
|
21
|
+
* context-limit.ts.
|
|
22
|
+
*/
|
|
23
|
+
export declare function unwrapSdkResponse<T>(response: unknown): T | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Extract the messages array from a raw `session.messages()` response.
|
|
26
|
+
* Returns an empty array when the response is missing or malformed.
|
|
27
|
+
*/
|
|
28
|
+
export declare function extractSdkMessages(response: unknown): SdkMessage[];
|
|
29
|
+
/**
|
|
30
|
+
* Extract the provider list from a raw `provider.list()` response.
|
|
31
|
+
* Returns an empty array when the response is missing or malformed.
|
|
32
|
+
*/
|
|
33
|
+
export type SdkProvider = {
|
|
34
|
+
id?: string;
|
|
35
|
+
models?: SdkModel[];
|
|
36
|
+
};
|
|
37
|
+
export type SdkModel = {
|
|
38
|
+
id?: string;
|
|
39
|
+
limit?: {
|
|
40
|
+
context?: number;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
export declare function extractSdkProviders(response: unknown): SdkProvider[];
|
|
44
|
+
/**
|
|
45
|
+
* Normalize a raw Graphiti episode object so that `sourceDescription` is
|
|
46
|
+
* always the canonical field regardless of whether the payload used
|
|
47
|
+
* camelCase (`sourceDescription`) or snake_case (`source_description`).
|
|
48
|
+
*
|
|
49
|
+
* Call this at the API boundary (e.g. inside `GraphitiClient.getEpisodes`)
|
|
50
|
+
* so all downstream consumers only need to read `episode.sourceDescription`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function normalizeEpisode(raw: GraphitiEpisode & {
|
|
53
|
+
source_description?: string;
|
|
54
|
+
}): GraphitiEpisode;
|
|
55
|
+
//# sourceMappingURL=sdk-normalize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk-normalize.d.ts","sourceRoot":"","sources":["../../../src/src/services/sdk-normalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAA4B,MAAM,kBAAkB,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,KAAK,EAAE,IAAI,EAAE,CAAC;CACf,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,GAAG,CAAC,GAAG,SAAS,CAMrE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,OAAO,GAChB,UAAU,EAAE,CAGd;AAED;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9B,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,OAAO,GAAG,WAAW,EAAE,CAmBpE;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,eAAe,GAAG;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,GACA,eAAe,CAMjB"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize an SDK response that may be wrapped in `{ data: … }` or returned
|
|
3
|
+
* directly. Returns the inner value cast to `T`, or `undefined` when the
|
|
4
|
+
* response is absent.
|
|
5
|
+
*
|
|
6
|
+
* This replaces the repeated `"data" in response ? (response as
|
|
7
|
+
* { data?: … }).data : response` pattern found in session.ts and
|
|
8
|
+
* context-limit.ts.
|
|
9
|
+
*/
|
|
10
|
+
export function unwrapSdkResponse(response) {
|
|
11
|
+
if (response == null)
|
|
12
|
+
return undefined;
|
|
13
|
+
if (typeof response === "object" && "data" in response) {
|
|
14
|
+
return response.data;
|
|
15
|
+
}
|
|
16
|
+
return response;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Extract the messages array from a raw `session.messages()` response.
|
|
20
|
+
* Returns an empty array when the response is missing or malformed.
|
|
21
|
+
*/
|
|
22
|
+
export function extractSdkMessages(response) {
|
|
23
|
+
const payload = unwrapSdkResponse(response);
|
|
24
|
+
return Array.isArray(payload) ? payload : [];
|
|
25
|
+
}
|
|
26
|
+
export function extractSdkProviders(response) {
|
|
27
|
+
// provider.list() may return `{ providers: [...] }` directly (no data wrap).
|
|
28
|
+
if (response != null && typeof response === "object") {
|
|
29
|
+
const obj = response;
|
|
30
|
+
if (Array.isArray(obj["providers"])) {
|
|
31
|
+
return obj["providers"];
|
|
32
|
+
}
|
|
33
|
+
if ("data" in obj) {
|
|
34
|
+
const data = obj["data"];
|
|
35
|
+
if (data != null && typeof data === "object") {
|
|
36
|
+
const dataObj = data;
|
|
37
|
+
if (Array.isArray(dataObj["providers"])) {
|
|
38
|
+
return dataObj["providers"];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (Array.isArray(data))
|
|
42
|
+
return data;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Normalize a raw Graphiti episode object so that `sourceDescription` is
|
|
49
|
+
* always the canonical field regardless of whether the payload used
|
|
50
|
+
* camelCase (`sourceDescription`) or snake_case (`source_description`).
|
|
51
|
+
*
|
|
52
|
+
* Call this at the API boundary (e.g. inside `GraphitiClient.getEpisodes`)
|
|
53
|
+
* so all downstream consumers only need to read `episode.sourceDescription`.
|
|
54
|
+
*/
|
|
55
|
+
export function normalizeEpisode(raw) {
|
|
56
|
+
const { source_description, ...rest } = raw;
|
|
57
|
+
return {
|
|
58
|
+
...rest,
|
|
59
|
+
sourceDescription: rest.sourceDescription ?? source_description,
|
|
60
|
+
};
|
|
61
|
+
}
|
package/esm/src/session.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export type SessionState = {
|
|
|
22
22
|
messageCount: number;
|
|
23
23
|
/** Buffered message strings awaiting flush. */
|
|
24
24
|
pendingMessages: string[];
|
|
25
|
+
/** Last successfully saved idle-session snapshot body. */
|
|
26
|
+
lastSnapshotBody?: string;
|
|
25
27
|
/** Context window limit in tokens. */
|
|
26
28
|
contextLimit: number;
|
|
27
29
|
/** True when this session is the primary (non-subagent) session. */
|
|
@@ -41,6 +43,8 @@ export declare class SessionManager {
|
|
|
41
43
|
private pendingAssistantMessages;
|
|
42
44
|
private bufferedAssistantMessageIds;
|
|
43
45
|
constructor(defaultGroupId: string, defaultUserGroupId: string, sdkClient: OpencodeClient, graphitiClient: GraphitiClient);
|
|
46
|
+
/** Create a default main-session state for the given group IDs. */
|
|
47
|
+
createDefaultState(groupId: string, userGroupId: string): SessionState;
|
|
44
48
|
/** Get the current session state, if present. */
|
|
45
49
|
getState(sessionId: string): SessionState | undefined;
|
|
46
50
|
/** Persist session state for the given session ID. */
|
|
@@ -54,8 +58,6 @@ export declare class SessionManager {
|
|
|
54
58
|
state: SessionState | null;
|
|
55
59
|
resolved: boolean;
|
|
56
60
|
}>;
|
|
57
|
-
/** Determine whether a session is a subagent session. */
|
|
58
|
-
isSubagentSession(sessionId: string): Promise<boolean>;
|
|
59
61
|
/** Buffer partial assistant text for a streaming message. */
|
|
60
62
|
bufferAssistantPart(sessionId: string, messageId: string, text: string): void;
|
|
61
63
|
/** Check if an assistant message has already been finalized. */
|
package/esm/src/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/src/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/src/session.ts"],"names":[],"mappings":"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"}
|