opencode-graphiti 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +176 -0
- package/esm/_dnt.shims.d.ts +6 -0
- package/esm/_dnt.shims.d.ts.map +1 -0
- package/esm/_dnt.shims.js +61 -0
- package/esm/mod.d.ts +2 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +1 -0
- package/esm/package.json +3 -0
- package/esm/src/config.d.ts +3 -0
- package/esm/src/config.d.ts.map +1 -0
- package/esm/src/config.js +43 -0
- package/esm/src/index.d.ts +4 -0
- package/esm/src/index.d.ts.map +1 -0
- package/esm/src/index.js +436 -0
- package/esm/src/services/client.d.ts +37 -0
- package/esm/src/services/client.d.ts.map +1 -0
- package/esm/src/services/client.js +201 -0
- package/esm/src/services/compaction.d.ts +93 -0
- package/esm/src/services/compaction.d.ts.map +1 -0
- package/esm/src/services/compaction.js +144 -0
- package/esm/src/services/context.d.ts +3 -0
- package/esm/src/services/context.d.ts.map +1 -0
- package/esm/src/services/context.js +36 -0
- package/esm/src/services/logger.d.ts +7 -0
- package/esm/src/services/logger.d.ts.map +1 -0
- package/esm/src/services/logger.js +22 -0
- package/esm/src/types/index.d.ts +48 -0
- package/esm/src/types/index.d.ts.map +1 -0
- package/esm/src/types/index.js +1 -0
- package/package.json +34 -0
- package/script/_dnt.shims.d.ts +6 -0
- package/script/_dnt.shims.d.ts.map +1 -0
- package/script/_dnt.shims.js +65 -0
- package/script/mod.d.ts +2 -0
- package/script/mod.d.ts.map +1 -0
- package/script/mod.js +17 -0
- package/script/package.json +3 -0
- package/script/src/config.d.ts +3 -0
- package/script/src/config.d.ts.map +1 -0
- package/script/src/config.js +79 -0
- package/script/src/index.d.ts +4 -0
- package/script/src/index.d.ts.map +1 -0
- package/script/src/index.js +441 -0
- package/script/src/services/client.d.ts +37 -0
- package/script/src/services/client.d.ts.map +1 -0
- package/script/src/services/client.js +238 -0
- package/script/src/services/compaction.d.ts +93 -0
- package/script/src/services/compaction.d.ts.map +1 -0
- package/script/src/services/compaction.js +149 -0
- package/script/src/services/context.d.ts +3 -0
- package/script/src/services/context.d.ts.map +1 -0
- package/script/src/services/context.js +39 -0
- package/script/src/services/logger.d.ts +7 -0
- package/script/src/services/logger.d.ts.map +1 -0
- package/script/src/services/logger.js +61 -0
- package/script/src/types/index.d.ts +48 -0
- package/script/src/types/index.d.ts.map +1 -0
- package/script/src/types/index.js +2 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { GraphitiConfig } from "../types/index.js";
|
|
2
|
+
export interface CompactionDependencies {
|
|
3
|
+
sdkClient: {
|
|
4
|
+
session: {
|
|
5
|
+
summarize: (options: {
|
|
6
|
+
path: {
|
|
7
|
+
id: string;
|
|
8
|
+
};
|
|
9
|
+
body?: {
|
|
10
|
+
providerID: string;
|
|
11
|
+
modelID: string;
|
|
12
|
+
};
|
|
13
|
+
query?: {
|
|
14
|
+
directory?: string;
|
|
15
|
+
};
|
|
16
|
+
}) => Promise<unknown>;
|
|
17
|
+
promptAsync: (options: {
|
|
18
|
+
path: {
|
|
19
|
+
id: string;
|
|
20
|
+
};
|
|
21
|
+
body?: {
|
|
22
|
+
parts: Array<{
|
|
23
|
+
type: "text";
|
|
24
|
+
text: string;
|
|
25
|
+
}>;
|
|
26
|
+
};
|
|
27
|
+
query?: {
|
|
28
|
+
directory?: string;
|
|
29
|
+
};
|
|
30
|
+
}) => Promise<unknown>;
|
|
31
|
+
};
|
|
32
|
+
tui: {
|
|
33
|
+
showToast: (options?: {
|
|
34
|
+
body?: {
|
|
35
|
+
title?: string;
|
|
36
|
+
message: string;
|
|
37
|
+
variant: "info" | "success" | "warning" | "error";
|
|
38
|
+
duration?: number;
|
|
39
|
+
};
|
|
40
|
+
query?: {
|
|
41
|
+
directory?: string;
|
|
42
|
+
};
|
|
43
|
+
}) => Promise<unknown>;
|
|
44
|
+
};
|
|
45
|
+
provider: {
|
|
46
|
+
list: (options?: {
|
|
47
|
+
directory?: string;
|
|
48
|
+
}) => Promise<unknown>;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
directory: string;
|
|
52
|
+
}
|
|
53
|
+
export declare function createPreemptiveCompactionHandler(config: Pick<GraphitiConfig, "compactionThreshold" | "minTokensForCompaction" | "compactionCooldownMs" | "autoResumeAfterCompaction">, deps: CompactionDependencies): {
|
|
54
|
+
checkAndTriggerCompaction(sessionId: string, tokens: {
|
|
55
|
+
input: number;
|
|
56
|
+
output: number;
|
|
57
|
+
reasoning: number;
|
|
58
|
+
cache: {
|
|
59
|
+
read: number;
|
|
60
|
+
write: number;
|
|
61
|
+
};
|
|
62
|
+
}, providerID: string, modelID: string): Promise<void>;
|
|
63
|
+
};
|
|
64
|
+
export declare function handleCompaction(params: {
|
|
65
|
+
client: {
|
|
66
|
+
addEpisode: (args: {
|
|
67
|
+
name: string;
|
|
68
|
+
episodeBody: string;
|
|
69
|
+
groupId?: string;
|
|
70
|
+
source?: "text" | "json" | "message";
|
|
71
|
+
sourceDescription?: string;
|
|
72
|
+
}) => Promise<void>;
|
|
73
|
+
};
|
|
74
|
+
config: GraphitiConfig;
|
|
75
|
+
groupId: string;
|
|
76
|
+
summary: string;
|
|
77
|
+
sessionId: string;
|
|
78
|
+
}): Promise<void>;
|
|
79
|
+
export declare function getCompactionContext(params: {
|
|
80
|
+
client: {
|
|
81
|
+
searchFacts: (args: {
|
|
82
|
+
query: string;
|
|
83
|
+
groupIds?: string[];
|
|
84
|
+
maxFacts?: number;
|
|
85
|
+
}) => Promise<Array<{
|
|
86
|
+
fact: string;
|
|
87
|
+
}>>;
|
|
88
|
+
};
|
|
89
|
+
config: GraphitiConfig;
|
|
90
|
+
groupId: string;
|
|
91
|
+
contextStrings: string[];
|
|
92
|
+
}): Promise<string[]>;
|
|
93
|
+
//# sourceMappingURL=compaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compaction.d.ts","sourceRoot":"","sources":["../../../src/src/services/compaction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { logger } from "./logger.js";
|
|
2
|
+
const DEFAULT_CONTEXT_LIMIT = 200_000;
|
|
3
|
+
const RESUME_DELAY_MS = 500;
|
|
4
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
5
|
+
const buildModelKey = (providerID, modelID) => `${providerID}/${modelID}`;
|
|
6
|
+
const resolveContextLimit = async (providerID, modelID, deps, state) => {
|
|
7
|
+
const modelKey = buildModelKey(providerID, modelID);
|
|
8
|
+
const cached = state.contextLimitCache.get(modelKey);
|
|
9
|
+
if (cached)
|
|
10
|
+
return cached;
|
|
11
|
+
try {
|
|
12
|
+
const providers = await deps.sdkClient.provider.list({
|
|
13
|
+
directory: deps.directory,
|
|
14
|
+
});
|
|
15
|
+
const list = providers.providers ?? [];
|
|
16
|
+
for (const provider of list) {
|
|
17
|
+
const providerInfo = provider;
|
|
18
|
+
if (providerInfo.id !== providerID)
|
|
19
|
+
continue;
|
|
20
|
+
const models = providerInfo.models ?? [];
|
|
21
|
+
for (const model of models) {
|
|
22
|
+
const modelInfo = model;
|
|
23
|
+
if (modelInfo.id !== modelID)
|
|
24
|
+
continue;
|
|
25
|
+
const contextLimit = modelInfo.limit?.context;
|
|
26
|
+
if (typeof contextLimit === "number" && contextLimit > 0) {
|
|
27
|
+
state.contextLimitCache.set(modelKey, contextLimit);
|
|
28
|
+
return contextLimit;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
logger.warn("Failed to fetch provider context limit", err);
|
|
35
|
+
}
|
|
36
|
+
state.contextLimitCache.set(modelKey, DEFAULT_CONTEXT_LIMIT);
|
|
37
|
+
return DEFAULT_CONTEXT_LIMIT;
|
|
38
|
+
};
|
|
39
|
+
export function createPreemptiveCompactionHandler(config, deps) {
|
|
40
|
+
const state = {
|
|
41
|
+
lastCompactionTime: new Map(),
|
|
42
|
+
compactionInProgress: new Set(),
|
|
43
|
+
contextLimitCache: new Map(),
|
|
44
|
+
};
|
|
45
|
+
const checkAndTriggerCompaction = async (sessionId, tokens, providerID, modelID) => {
|
|
46
|
+
const totalTokens = tokens.input + tokens.cache.read + tokens.output +
|
|
47
|
+
tokens.reasoning;
|
|
48
|
+
if (totalTokens < (config.minTokensForCompaction ?? 0))
|
|
49
|
+
return;
|
|
50
|
+
if (state.compactionInProgress.has(sessionId))
|
|
51
|
+
return;
|
|
52
|
+
const lastCompaction = state.lastCompactionTime.get(sessionId) ?? 0;
|
|
53
|
+
if (Date.now() - lastCompaction < (config.compactionCooldownMs ?? 0)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const contextLimit = await resolveContextLimit(providerID, modelID, deps, state);
|
|
57
|
+
const usageRatio = totalTokens / contextLimit;
|
|
58
|
+
if (usageRatio < (config.compactionThreshold ?? 1))
|
|
59
|
+
return;
|
|
60
|
+
state.compactionInProgress.add(sessionId);
|
|
61
|
+
try {
|
|
62
|
+
await deps.sdkClient.tui.showToast({
|
|
63
|
+
body: {
|
|
64
|
+
title: "Graphiti",
|
|
65
|
+
message: "Compacting session to preserve context...",
|
|
66
|
+
variant: "info",
|
|
67
|
+
duration: 3000,
|
|
68
|
+
},
|
|
69
|
+
query: { directory: deps.directory },
|
|
70
|
+
});
|
|
71
|
+
await deps.sdkClient.session.summarize({
|
|
72
|
+
path: { id: sessionId },
|
|
73
|
+
body: { providerID, modelID },
|
|
74
|
+
query: { directory: deps.directory },
|
|
75
|
+
});
|
|
76
|
+
state.lastCompactionTime.set(sessionId, Date.now());
|
|
77
|
+
if (config.autoResumeAfterCompaction) {
|
|
78
|
+
await delay(RESUME_DELAY_MS);
|
|
79
|
+
await deps.sdkClient.session.promptAsync({
|
|
80
|
+
path: { id: sessionId },
|
|
81
|
+
body: { parts: [{ type: "text", text: "Continue" }] },
|
|
82
|
+
query: { directory: deps.directory },
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
logger.info("Preemptive compaction triggered", {
|
|
86
|
+
sessionId,
|
|
87
|
+
providerID,
|
|
88
|
+
modelID,
|
|
89
|
+
usageRatio,
|
|
90
|
+
totalTokens,
|
|
91
|
+
contextLimit,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
logger.error("Preemptive compaction failed", err);
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
state.compactionInProgress.delete(sessionId);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
return { checkAndTriggerCompaction };
|
|
102
|
+
}
|
|
103
|
+
export async function handleCompaction(params) {
|
|
104
|
+
const { client, config, groupId, summary, sessionId } = params;
|
|
105
|
+
if (!config.enableCompactionSave || !summary)
|
|
106
|
+
return;
|
|
107
|
+
try {
|
|
108
|
+
await client.addEpisode({
|
|
109
|
+
name: `Session compaction: ${sessionId}`,
|
|
110
|
+
episodeBody: summary,
|
|
111
|
+
groupId,
|
|
112
|
+
source: "text",
|
|
113
|
+
sourceDescription: "OpenCode session compaction summary",
|
|
114
|
+
});
|
|
115
|
+
logger.info("Saved compaction summary to Graphiti for session", sessionId);
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
logger.error("Failed to save compaction summary:", err);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
export async function getCompactionContext(params) {
|
|
122
|
+
const { client, config, groupId, contextStrings } = params;
|
|
123
|
+
try {
|
|
124
|
+
const queryText = contextStrings.slice(0, 3).join(" ").slice(0, 500);
|
|
125
|
+
if (!queryText.trim())
|
|
126
|
+
return [];
|
|
127
|
+
const facts = await client.searchFacts({
|
|
128
|
+
query: queryText,
|
|
129
|
+
groupIds: [groupId],
|
|
130
|
+
maxFacts: config.maxFacts,
|
|
131
|
+
});
|
|
132
|
+
if (facts.length === 0)
|
|
133
|
+
return [];
|
|
134
|
+
const lines = [
|
|
135
|
+
"## Persistent Knowledge (preserve these facts during compaction):",
|
|
136
|
+
...facts.map((fact) => `- ${fact.fact}`),
|
|
137
|
+
];
|
|
138
|
+
return [lines.join("\n")];
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
logger.error("Failed to get compaction context:", err);
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/src/services/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEpE,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EAAE,EACrB,KAAK,EAAE,YAAY,EAAE,GACpB,MAAM,CA0CR"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function formatMemoryContext(facts, nodes) {
|
|
2
|
+
const sections = [];
|
|
3
|
+
sections.push("# Persistent Memory (from Graphiti Knowledge Graph)");
|
|
4
|
+
sections.push("");
|
|
5
|
+
sections.push("The following information was retrieved from your persistent memory.");
|
|
6
|
+
sections.push("Use this context to inform your responses, but do not mention it unless asked.");
|
|
7
|
+
sections.push("");
|
|
8
|
+
if (facts.length > 0) {
|
|
9
|
+
sections.push("## Known Facts");
|
|
10
|
+
for (const fact of facts) {
|
|
11
|
+
const entities = [];
|
|
12
|
+
if (fact.source_node?.name)
|
|
13
|
+
entities.push(fact.source_node.name);
|
|
14
|
+
if (fact.target_node?.name)
|
|
15
|
+
entities.push(fact.target_node.name);
|
|
16
|
+
const entityStr = entities.length > 0
|
|
17
|
+
? ` [${entities.join(" -> ")}]`
|
|
18
|
+
: "";
|
|
19
|
+
sections.push(`- ${fact.fact}${entityStr}`);
|
|
20
|
+
}
|
|
21
|
+
sections.push("");
|
|
22
|
+
}
|
|
23
|
+
if (nodes.length > 0) {
|
|
24
|
+
sections.push("## Known Entities");
|
|
25
|
+
for (const node of nodes) {
|
|
26
|
+
const labels = node.labels?.length ? ` (${node.labels.join(", ")})` : "";
|
|
27
|
+
const summary = node.summary ? `: ${node.summary}` : "";
|
|
28
|
+
sections.push(`- **${node.name}**${labels}${summary}`);
|
|
29
|
+
}
|
|
30
|
+
sections.push("");
|
|
31
|
+
}
|
|
32
|
+
if (facts.length === 0 && nodes.length === 0) {
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
return sections.join("\n");
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/src/services/logger.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,MAAM;oBACD,OAAO,EAAE;oBAGT,OAAO,EAAE;qBAGR,OAAO,EAAE;qBAGT,OAAO,EAAE;CAG3B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
const console = dntShim.dntGlobalThis.console;
|
|
4
|
+
const PREFIX = "[graphiti]";
|
|
5
|
+
export const logger = {
|
|
6
|
+
info: (...args) => {
|
|
7
|
+
if (process.env.GRAPHITI_DEBUG)
|
|
8
|
+
console.log(PREFIX, ...args);
|
|
9
|
+
},
|
|
10
|
+
warn: (...args) => {
|
|
11
|
+
if (process.env.GRAPHITI_DEBUG)
|
|
12
|
+
console.warn(PREFIX, ...args);
|
|
13
|
+
},
|
|
14
|
+
error: (...args) => {
|
|
15
|
+
if (process.env.GRAPHITI_DEBUG)
|
|
16
|
+
console.error(PREFIX, ...args);
|
|
17
|
+
},
|
|
18
|
+
debug: (...args) => {
|
|
19
|
+
if (process.env.GRAPHITI_DEBUG)
|
|
20
|
+
console.debug(PREFIX, ...args);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface GraphitiConfig {
|
|
2
|
+
endpoint: string;
|
|
3
|
+
groupIdPrefix: string;
|
|
4
|
+
maxFacts: number;
|
|
5
|
+
maxNodes: number;
|
|
6
|
+
maxEpisodes: number;
|
|
7
|
+
injectOnFirstMessage: boolean;
|
|
8
|
+
enableCompactionSave: boolean;
|
|
9
|
+
compactionThreshold?: number;
|
|
10
|
+
minTokensForCompaction?: number;
|
|
11
|
+
compactionCooldownMs?: number;
|
|
12
|
+
autoResumeAfterCompaction?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface GraphitiFact {
|
|
15
|
+
uuid: string;
|
|
16
|
+
fact: string;
|
|
17
|
+
valid_at?: string;
|
|
18
|
+
invalid_at?: string;
|
|
19
|
+
source_node?: {
|
|
20
|
+
name: string;
|
|
21
|
+
uuid: string;
|
|
22
|
+
};
|
|
23
|
+
target_node?: {
|
|
24
|
+
name: string;
|
|
25
|
+
uuid: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export interface GraphitiFactsResponse {
|
|
29
|
+
facts: GraphitiFact[];
|
|
30
|
+
}
|
|
31
|
+
export interface GraphitiNode {
|
|
32
|
+
uuid: string;
|
|
33
|
+
name: string;
|
|
34
|
+
summary?: string;
|
|
35
|
+
labels?: string[];
|
|
36
|
+
}
|
|
37
|
+
export interface GraphitiNodesResponse {
|
|
38
|
+
nodes: GraphitiNode[];
|
|
39
|
+
}
|
|
40
|
+
export interface GraphitiEpisode {
|
|
41
|
+
uuid: string;
|
|
42
|
+
name: string;
|
|
43
|
+
content: string;
|
|
44
|
+
source?: string;
|
|
45
|
+
created_at?: string;
|
|
46
|
+
labels?: string[];
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,oBAAoB,EAAE,OAAO,CAAC;IAE9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-graphiti",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "OpenCode plugin for persistent memory via Graphiti knowledge graph",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "./script/mod.js",
|
|
7
|
+
"module": "./esm/mod.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./esm/mod.js",
|
|
11
|
+
"require": "./script/mod.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {},
|
|
15
|
+
"opencode": {
|
|
16
|
+
"type": "plugin",
|
|
17
|
+
"hooks": [
|
|
18
|
+
"chat.message",
|
|
19
|
+
"event",
|
|
20
|
+
"experimental.session.compacting"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
25
|
+
"@opencode-ai/plugin": "^1.1.53",
|
|
26
|
+
"@opencode-ai/sdk": "^1.1.53",
|
|
27
|
+
"cosmiconfig": "9.0.0",
|
|
28
|
+
"@deno/shim-deno": "~0.18.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^20.9.0"
|
|
32
|
+
},
|
|
33
|
+
"_generatedBy": "dnt@dev"
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dnt.shims.d.ts","sourceRoot":"","sources":["../src/_dnt.shims.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAKvC,eAAO,MAAM,aAAa;;CAA2C,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dntGlobalThis = exports.Deno = void 0;
|
|
4
|
+
const shim_deno_1 = require("@deno/shim-deno");
|
|
5
|
+
var shim_deno_2 = require("@deno/shim-deno");
|
|
6
|
+
Object.defineProperty(exports, "Deno", { enumerable: true, get: function () { return shim_deno_2.Deno; } });
|
|
7
|
+
const dntGlobals = {
|
|
8
|
+
Deno: shim_deno_1.Deno,
|
|
9
|
+
};
|
|
10
|
+
exports.dntGlobalThis = createMergeProxy(globalThis, dntGlobals);
|
|
11
|
+
function createMergeProxy(baseObj, extObj) {
|
|
12
|
+
return new Proxy(baseObj, {
|
|
13
|
+
get(_target, prop, _receiver) {
|
|
14
|
+
if (prop in extObj) {
|
|
15
|
+
return extObj[prop];
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
return baseObj[prop];
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
set(_target, prop, value) {
|
|
22
|
+
if (prop in extObj) {
|
|
23
|
+
delete extObj[prop];
|
|
24
|
+
}
|
|
25
|
+
baseObj[prop] = value;
|
|
26
|
+
return true;
|
|
27
|
+
},
|
|
28
|
+
deleteProperty(_target, prop) {
|
|
29
|
+
let success = false;
|
|
30
|
+
if (prop in extObj) {
|
|
31
|
+
delete extObj[prop];
|
|
32
|
+
success = true;
|
|
33
|
+
}
|
|
34
|
+
if (prop in baseObj) {
|
|
35
|
+
delete baseObj[prop];
|
|
36
|
+
success = true;
|
|
37
|
+
}
|
|
38
|
+
return success;
|
|
39
|
+
},
|
|
40
|
+
ownKeys(_target) {
|
|
41
|
+
const baseKeys = Reflect.ownKeys(baseObj);
|
|
42
|
+
const extKeys = Reflect.ownKeys(extObj);
|
|
43
|
+
const extKeysSet = new Set(extKeys);
|
|
44
|
+
return [...baseKeys.filter((k) => !extKeysSet.has(k)), ...extKeys];
|
|
45
|
+
},
|
|
46
|
+
defineProperty(_target, prop, desc) {
|
|
47
|
+
if (prop in extObj) {
|
|
48
|
+
delete extObj[prop];
|
|
49
|
+
}
|
|
50
|
+
Reflect.defineProperty(baseObj, prop, desc);
|
|
51
|
+
return true;
|
|
52
|
+
},
|
|
53
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
54
|
+
if (prop in extObj) {
|
|
55
|
+
return Reflect.getOwnPropertyDescriptor(extObj, prop);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
return Reflect.getOwnPropertyDescriptor(baseObj, prop);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
has(_target, prop) {
|
|
62
|
+
return prop in extObj || prop in baseObj;
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
package/script/mod.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
package/script/mod.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./src/index.js"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/src/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AA0BvD,wBAAgB,UAAU,IAAI,cAAc,CAe3C"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadConfig = loadConfig;
|
|
37
|
+
const dntShim = __importStar(require("../_dnt.shims.js"));
|
|
38
|
+
const cosmiconfig_1 = require("cosmiconfig");
|
|
39
|
+
const node_fs_1 = require("node:fs");
|
|
40
|
+
const node_os_1 = require("node:os");
|
|
41
|
+
const node_path_1 = require("node:path");
|
|
42
|
+
const DEFAULT_CONFIG = {
|
|
43
|
+
endpoint: "http://localhost:8000/mcp",
|
|
44
|
+
groupIdPrefix: "opencode",
|
|
45
|
+
maxFacts: 10,
|
|
46
|
+
maxNodes: 5,
|
|
47
|
+
maxEpisodes: 5,
|
|
48
|
+
injectOnFirstMessage: true,
|
|
49
|
+
enableCompactionSave: true,
|
|
50
|
+
compactionThreshold: 0.8,
|
|
51
|
+
minTokensForCompaction: 50000,
|
|
52
|
+
compactionCooldownMs: 30000,
|
|
53
|
+
autoResumeAfterCompaction: true,
|
|
54
|
+
};
|
|
55
|
+
function parseJsonc(text) {
|
|
56
|
+
let stripped = text.replace(/(^|\s)\/\/.*$/gm, "$1");
|
|
57
|
+
stripped = stripped.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
58
|
+
return JSON.parse(stripped);
|
|
59
|
+
}
|
|
60
|
+
const createExplorer = (cwd) => {
|
|
61
|
+
return (0, cosmiconfig_1.cosmiconfigSync)("graphiti", { stopDir: cwd });
|
|
62
|
+
};
|
|
63
|
+
function loadConfig() {
|
|
64
|
+
const cwd = dntShim.Deno.cwd();
|
|
65
|
+
const explorer = createExplorer(cwd);
|
|
66
|
+
const result = explorer.search(cwd);
|
|
67
|
+
let config = result?.config;
|
|
68
|
+
if (!config) {
|
|
69
|
+
const configPath = (0, node_path_1.join)((0, node_os_1.homedir)(), ".config", "opencode", "graphiti.jsonc");
|
|
70
|
+
try {
|
|
71
|
+
const raw = (0, node_fs_1.readFileSync)(configPath, "utf-8");
|
|
72
|
+
config = parseJsonc(raw);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
config = null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { ...DEFAULT_CONFIG, ...(config ?? {}) };
|
|
79
|
+
}
|
|
@@ -0,0 +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;AAqB/D,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,EAAE,YAAY,MAAM,KAAG,MAKhE,CAAC;AAeF,eAAO,MAAM,QAAQ,EAAE,MA+ftB,CAAC"}
|