koishi-plugin-chatluna-long-memory 1.3.1 → 1.3.3
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 +1 -1
- package/lib/index.cjs +202 -106
- package/lib/index.mjs +202 -109
- package/lib/layers/emgas/extractor.d.ts +6 -9
- package/lib/layers/emgas/graph.d.ts +1 -2
- package/lib/layers/emgas/index.d.ts +1 -0
- package/lib/layers/emgas/types.d.ts +10 -1
- package/lib/plugins/tool.d.ts +8 -8
- package/package.json +2 -2
package/README.md
CHANGED
package/lib/index.cjs
CHANGED
|
@@ -2001,6 +2001,153 @@ async function createVectorStoreRetriever(ctx, config, longMemoryId) {
|
|
|
2001
2001
|
}
|
|
2002
2002
|
__name(createVectorStoreRetriever, "createVectorStoreRetriever");
|
|
2003
2003
|
|
|
2004
|
+
// src/layers/emgas/extractor.ts
|
|
2005
|
+
var import_js_yaml2 = __toESM(require("js-yaml"), 1);
|
|
2006
|
+
var import_string3 = require("koishi-plugin-chatluna/utils/string");
|
|
2007
|
+
var GRAPH_ELEMENTS_EXTRACTION_PROMPT = /* @__PURE__ */ __name((text) => `
|
|
2008
|
+
You are an expert in knowledge extraction. Your task is to analyze the following text to identify key concepts and overarching topics.
|
|
2009
|
+
|
|
2010
|
+
Text to analyze:
|
|
2011
|
+
"""
|
|
2012
|
+
${text}
|
|
2013
|
+
"""
|
|
2014
|
+
|
|
2015
|
+
Respond with a single, valid YAML block with two keys: 'concepts' and 'topics'.
|
|
2016
|
+
|
|
2017
|
+
Guidelines:
|
|
2018
|
+
1. **concepts**: A list of the most important keywords, and named entities from the text. Use the base form or most common form.
|
|
2019
|
+
2. **topics**: A list of 1-3 higher-level topics that categorize the concepts. These should be broader categories.
|
|
2020
|
+
3. If no meaningful data can be extracted, return empty lists for both keys.
|
|
2021
|
+
|
|
2022
|
+
Example:
|
|
2023
|
+
Text: "The user is asking about setting up a new React project with Vite. They are having trouble with the HMR (Hot Module Replacement) configuration."
|
|
2024
|
+
|
|
2025
|
+
YAML Output:
|
|
2026
|
+
\`\`\`yaml
|
|
2027
|
+
concepts:
|
|
2028
|
+
- React
|
|
2029
|
+
- Vite
|
|
2030
|
+
- HMR
|
|
2031
|
+
- project setup
|
|
2032
|
+
topics:
|
|
2033
|
+
- Frontend Development
|
|
2034
|
+
- Build Tools
|
|
2035
|
+
\`\`\`
|
|
2036
|
+
|
|
2037
|
+
YAML Output:
|
|
2038
|
+
`, "GRAPH_ELEMENTS_EXTRACTION_PROMPT");
|
|
2039
|
+
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
2040
|
+
"a",
|
|
2041
|
+
"an",
|
|
2042
|
+
"and",
|
|
2043
|
+
"are",
|
|
2044
|
+
"as",
|
|
2045
|
+
"at",
|
|
2046
|
+
"be",
|
|
2047
|
+
"by",
|
|
2048
|
+
"for",
|
|
2049
|
+
"from",
|
|
2050
|
+
"how",
|
|
2051
|
+
"in",
|
|
2052
|
+
"is",
|
|
2053
|
+
"it",
|
|
2054
|
+
"of",
|
|
2055
|
+
"on",
|
|
2056
|
+
"or",
|
|
2057
|
+
"that",
|
|
2058
|
+
"the",
|
|
2059
|
+
"their",
|
|
2060
|
+
"they",
|
|
2061
|
+
"this",
|
|
2062
|
+
"to",
|
|
2063
|
+
"with",
|
|
2064
|
+
"用户",
|
|
2065
|
+
"我们",
|
|
2066
|
+
"你们",
|
|
2067
|
+
"他们",
|
|
2068
|
+
"以及",
|
|
2069
|
+
"但是",
|
|
2070
|
+
"如果",
|
|
2071
|
+
"因为",
|
|
2072
|
+
"所以"
|
|
2073
|
+
]);
|
|
2074
|
+
function format(items) {
|
|
2075
|
+
return items.map((item) => String(item).trim().replace(/\s+/g, " ")).filter(Boolean).map(
|
|
2076
|
+
(item) => /^[\x00-\x7F]+$/.test(item) ? item.toLowerCase() : item
|
|
2077
|
+
);
|
|
2078
|
+
}
|
|
2079
|
+
__name(format, "format");
|
|
2080
|
+
function extractLocal(text) {
|
|
2081
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2082
|
+
const groups = [];
|
|
2083
|
+
for (const item of text.match(
|
|
2084
|
+
/[A-Za-z][A-Za-z0-9+#./-]{1,}|[\u3400-\u9fff]{2,}/g
|
|
2085
|
+
) ?? []) {
|
|
2086
|
+
if (/^[A-Za-z]/.test(item)) {
|
|
2087
|
+
const word = item.toLowerCase();
|
|
2088
|
+
if (STOP_WORDS.has(word)) {
|
|
2089
|
+
continue;
|
|
2090
|
+
}
|
|
2091
|
+
counts.set(word, (counts.get(word) ?? 0) + 1);
|
|
2092
|
+
if (word.length >= 4) {
|
|
2093
|
+
groups.push(word);
|
|
2094
|
+
}
|
|
2095
|
+
continue;
|
|
2096
|
+
}
|
|
2097
|
+
if (item.length >= 2) {
|
|
2098
|
+
groups.push(item.length > 12 ? item.slice(0, 12) : item);
|
|
2099
|
+
}
|
|
2100
|
+
if (item.length <= 8) {
|
|
2101
|
+
counts.set(item, (counts.get(item) ?? 0) + 1);
|
|
2102
|
+
continue;
|
|
2103
|
+
}
|
|
2104
|
+
for (let i = 0; i < item.length - 1; i++) {
|
|
2105
|
+
const word = item.slice(i, i + 2);
|
|
2106
|
+
counts.set(word, (counts.get(word) ?? 0) + 1);
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
const concepts = Array.from(counts.entries()).sort((a, b) => b[1] - a[1] || b[0].length - a[0].length).map(([item]) => item).slice(0, 12);
|
|
2110
|
+
const topics = Array.from(new Set(format(groups))).filter((item) => !STOP_WORDS.has(item)).slice(0, 3);
|
|
2111
|
+
return {
|
|
2112
|
+
concepts,
|
|
2113
|
+
topics: topics.length > 0 ? topics : concepts.slice(0, 3)
|
|
2114
|
+
};
|
|
2115
|
+
}
|
|
2116
|
+
__name(extractLocal, "extractLocal");
|
|
2117
|
+
async function extractGraphElements(modelRef, text) {
|
|
2118
|
+
const model = modelRef?.value;
|
|
2119
|
+
if (model == null) {
|
|
2120
|
+
return extractLocal(text);
|
|
2121
|
+
}
|
|
2122
|
+
try {
|
|
2123
|
+
const prompt = GRAPH_ELEMENTS_EXTRACTION_PROMPT(text);
|
|
2124
|
+
const res = await model.invoke(prompt);
|
|
2125
|
+
const content = (0, import_string3.getMessageContent)(res.content).trim();
|
|
2126
|
+
const yamlMatch = content.match(
|
|
2127
|
+
/```(?:ya?ml)?\s*\r?\n([\s\S]*?)\r?\n```/i
|
|
2128
|
+
);
|
|
2129
|
+
const parsed = import_js_yaml2.default.load(yamlMatch?.[1] ?? content);
|
|
2130
|
+
if (parsed && typeof parsed === "object") {
|
|
2131
|
+
const concepts = format(
|
|
2132
|
+
Array.isArray(parsed.concepts) ? parsed.concepts : []
|
|
2133
|
+
);
|
|
2134
|
+
const topics = format(
|
|
2135
|
+
Array.isArray(parsed.topics) ? parsed.topics : []
|
|
2136
|
+
);
|
|
2137
|
+
if (concepts.length > 0 || topics.length > 0) {
|
|
2138
|
+
return {
|
|
2139
|
+
concepts,
|
|
2140
|
+
topics: topics.length > 0 ? topics : concepts.slice(0, 3)
|
|
2141
|
+
};
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
return extractLocal(text);
|
|
2145
|
+
} catch {
|
|
2146
|
+
return extractLocal(text);
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
__name(extractGraphElements, "extractGraphElements");
|
|
2150
|
+
|
|
2004
2151
|
// src/layers/emgas/graph.ts
|
|
2005
2152
|
var MemoryGraph = class _MemoryGraph {
|
|
2006
2153
|
static {
|
|
@@ -2209,12 +2356,16 @@ var MemoryGraph = class _MemoryGraph {
|
|
|
2209
2356
|
return this.nodes.values();
|
|
2210
2357
|
}
|
|
2211
2358
|
toJSON() {
|
|
2212
|
-
const nodes = Array.from(
|
|
2213
|
-
(
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2359
|
+
const nodes = Array.from(
|
|
2360
|
+
this.nodes.values()
|
|
2361
|
+
).map((node) => ({
|
|
2362
|
+
id: node.id,
|
|
2363
|
+
type: node.type,
|
|
2364
|
+
baseActivation: node.baseActivation,
|
|
2365
|
+
createdAt: node.createdAt.toISOString(),
|
|
2366
|
+
lastAccessed: node.lastAccessed.toISOString(),
|
|
2367
|
+
sourcePassageIds: node.sourcePassageIds ? Array.from(node.sourcePassageIds) : []
|
|
2368
|
+
}));
|
|
2218
2369
|
const edges = [];
|
|
2219
2370
|
const seenEdges = /* @__PURE__ */ new Set();
|
|
2220
2371
|
for (const source of this.edges.values()) {
|
|
@@ -2239,9 +2390,11 @@ var MemoryGraph = class _MemoryGraph {
|
|
|
2239
2390
|
if (!serializedGraph) return graph;
|
|
2240
2391
|
for (const nodeData of serializedGraph.nodes || []) {
|
|
2241
2392
|
graph.nodes.set(nodeData.id, {
|
|
2242
|
-
...nodeData,
|
|
2243
2393
|
createdAt: new Date(nodeData.createdAt),
|
|
2244
2394
|
lastAccessed: new Date(nodeData.lastAccessed),
|
|
2395
|
+
id: nodeData.id,
|
|
2396
|
+
type: nodeData.type,
|
|
2397
|
+
baseActivation: nodeData.baseActivation,
|
|
2245
2398
|
sourcePassageIds: new Set(nodeData.sourcePassageIds || [])
|
|
2246
2399
|
});
|
|
2247
2400
|
}
|
|
@@ -2260,87 +2413,7 @@ var import_crypto6 = require("crypto");
|
|
|
2260
2413
|
var import_fs = require("fs");
|
|
2261
2414
|
var path2 = __toESM(require("path"), 1);
|
|
2262
2415
|
var import_vectorstores2 = require("koishi-plugin-chatluna/llm-core/vectorstores");
|
|
2263
|
-
|
|
2264
|
-
// src/layers/emgas/extractor.ts
|
|
2265
|
-
var import_js_yaml2 = __toESM(require("js-yaml"), 1);
|
|
2266
|
-
var import_string3 = require("koishi-plugin-chatluna/utils/string");
|
|
2267
|
-
var import_error = require("koishi-plugin-chatluna/utils/error");
|
|
2268
|
-
var GRAPH_ELEMENTS_EXTRACTION_PROMPT = /* @__PURE__ */ __name((text) => `
|
|
2269
|
-
You are an expert in knowledge extraction. Your task is to analyze the following text to identify key concepts and overarching topics.
|
|
2270
|
-
|
|
2271
|
-
Text to analyze:
|
|
2272
|
-
"""
|
|
2273
|
-
${text}
|
|
2274
|
-
"""
|
|
2275
|
-
|
|
2276
|
-
Respond with a single, valid YAML block with two keys: 'concepts' and 'topics'.
|
|
2277
|
-
|
|
2278
|
-
Guidelines:
|
|
2279
|
-
1. **concepts**: A list of the most important keywords, and named entities from the text. Use the base form or most common form.
|
|
2280
|
-
2. **topics**: A list of 1-3 higher-level topics that categorize the concepts. These should be broader categories.
|
|
2281
|
-
3. If no meaningful data can be extracted, return empty lists for both keys.
|
|
2282
|
-
|
|
2283
|
-
Example:
|
|
2284
|
-
Text: "The user is asking about setting up a new React project with Vite. They are having trouble with the HMR (Hot Module Replacement) configuration."
|
|
2285
|
-
|
|
2286
|
-
YAML Output:
|
|
2287
|
-
\`\`\`yaml
|
|
2288
|
-
concepts:
|
|
2289
|
-
- React
|
|
2290
|
-
- Vite
|
|
2291
|
-
- HMR
|
|
2292
|
-
- project setup
|
|
2293
|
-
topics:
|
|
2294
|
-
- Frontend Development
|
|
2295
|
-
- Build Tools
|
|
2296
|
-
\`\`\`
|
|
2297
|
-
|
|
2298
|
-
YAML Output:
|
|
2299
|
-
`, "GRAPH_ELEMENTS_EXTRACTION_PROMPT");
|
|
2300
|
-
async function extractGraphElements(modelRef, text) {
|
|
2301
|
-
if (!modelRef.value) {
|
|
2302
|
-
throw new import_error.ChatLunaError(
|
|
2303
|
-
import_error.ChatLunaErrorCode.MODEL_NOT_FOUND,
|
|
2304
|
-
new Error(
|
|
2305
|
-
"LLM-based extractor is disabled. Cannot extract graph elements."
|
|
2306
|
-
)
|
|
2307
|
-
);
|
|
2308
|
-
}
|
|
2309
|
-
const model = modelRef.value;
|
|
2310
|
-
try {
|
|
2311
|
-
const prompt = GRAPH_ELEMENTS_EXTRACTION_PROMPT(text);
|
|
2312
|
-
const res = await model.invoke(prompt);
|
|
2313
|
-
const content = (0, import_string3.getMessageContent)(res.content);
|
|
2314
|
-
const yamlMatch = content.match(
|
|
2315
|
-
/```(?:ya?ml)?\s*\r?\n([\s\S]*?)\r?\n```/i
|
|
2316
|
-
);
|
|
2317
|
-
if (yamlMatch && yamlMatch[1]) {
|
|
2318
|
-
const parsed = import_js_yaml2.default.load(yamlMatch[1]);
|
|
2319
|
-
return {
|
|
2320
|
-
concepts: [].concat(parsed.concepts || []).map((item) => String(item).trim()).filter(Boolean),
|
|
2321
|
-
topics: [].concat(parsed.topics || []).map((item) => String(item).trim()).filter(Boolean)
|
|
2322
|
-
};
|
|
2323
|
-
}
|
|
2324
|
-
throw new import_error.ChatLunaError(
|
|
2325
|
-
import_error.ChatLunaErrorCode.MODEL_RESPONSE_IS_EMPTY,
|
|
2326
|
-
new Error(
|
|
2327
|
-
"LLM did not return a valid YAML for graph element extraction."
|
|
2328
|
-
)
|
|
2329
|
-
);
|
|
2330
|
-
} catch (error) {
|
|
2331
|
-
if (error instanceof import_error.ChatLunaError) {
|
|
2332
|
-
throw error;
|
|
2333
|
-
}
|
|
2334
|
-
throw new import_error.ChatLunaError(
|
|
2335
|
-
import_error.ChatLunaErrorCode.API_REQUEST_FAILED,
|
|
2336
|
-
error
|
|
2337
|
-
);
|
|
2338
|
-
}
|
|
2339
|
-
}
|
|
2340
|
-
__name(extractGraphElements, "extractGraphElements");
|
|
2341
|
-
|
|
2342
|
-
// src/layers/emgas/layer.ts
|
|
2343
|
-
function getGraphFilePath(baseDir, memoryId) {
|
|
2416
|
+
function getGraphFilePath(baseDir, memoryId, dir = "emgas") {
|
|
2344
2417
|
if (!memoryId || typeof memoryId !== "string") {
|
|
2345
2418
|
throw new Error("Invalid memoryId: must be a non-empty string.");
|
|
2346
2419
|
}
|
|
@@ -2350,7 +2423,10 @@ function getGraphFilePath(baseDir, memoryId) {
|
|
|
2350
2423
|
}
|
|
2351
2424
|
return path2.join(
|
|
2352
2425
|
baseDir,
|
|
2353
|
-
"data
|
|
2426
|
+
"data",
|
|
2427
|
+
"chatluna",
|
|
2428
|
+
"long-memory",
|
|
2429
|
+
dir,
|
|
2354
2430
|
`${sanitizedId}.json`
|
|
2355
2431
|
);
|
|
2356
2432
|
}
|
|
@@ -2374,28 +2450,48 @@ var EmgasMemoryLayer = class extends BaseMemoryRetrievalLayer {
|
|
|
2374
2450
|
`Initializing EMGAS layer for memory ID: ${this.info.memoryId}`
|
|
2375
2451
|
);
|
|
2376
2452
|
const baseDir = this.ctx.baseDir || process.cwd();
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
logger2.debug(
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
}
|
|
2453
|
+
let loaded = false;
|
|
2454
|
+
for (const filePath of [
|
|
2455
|
+
getGraphFilePath(baseDir, this.info.memoryId),
|
|
2456
|
+
getGraphFilePath(baseDir, this.info.memoryId, "emgasa")
|
|
2457
|
+
]) {
|
|
2458
|
+
try {
|
|
2459
|
+
const data = await import_fs.promises.readFile(filePath, "utf-8");
|
|
2460
|
+
const serialized = JSON.parse(data);
|
|
2461
|
+
this.memoryGraph = MemoryGraph.fromJSON(serialized);
|
|
2462
|
+
logger2.debug(`EMGAS graph loaded from ${filePath}`);
|
|
2463
|
+
loaded = true;
|
|
2464
|
+
break;
|
|
2465
|
+
} catch (error) {
|
|
2466
|
+
const err = error;
|
|
2467
|
+
if (err && err.code === "ENOENT") {
|
|
2468
|
+
continue;
|
|
2469
|
+
}
|
|
2390
2470
|
logger2.error(
|
|
2391
|
-
`Failed to load EMGAS graph
|
|
2471
|
+
`Failed to load EMGAS graph for ${this.info.memoryId}:`,
|
|
2392
2472
|
error
|
|
2393
2473
|
);
|
|
2474
|
+
break;
|
|
2394
2475
|
}
|
|
2395
2476
|
}
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2477
|
+
if (!loaded) {
|
|
2478
|
+
logger2.debug(
|
|
2479
|
+
`No existing EMGAS graph found for ${this.info.memoryId}. A new one will be created.`
|
|
2480
|
+
);
|
|
2481
|
+
}
|
|
2482
|
+
const modelName = this.config.emgasExtractModel !== "无" ? this.config.emgasExtractModel : this.config.longMemoryExtractModel !== "无" ? this.config.longMemoryExtractModel : this.config.hippoExtractModel !== "无" ? this.config.hippoExtractModel : void 0;
|
|
2483
|
+
this.extractModel = void 0;
|
|
2484
|
+
if (modelName?.includes("/")) {
|
|
2485
|
+
this.extractModel = await this.ctx.chatluna.createChatModel(modelName);
|
|
2486
|
+
} else if (modelName != null) {
|
|
2487
|
+
logger2.warn(
|
|
2488
|
+
`Invalid EMGAS extractor model: ${modelName}. Falling back to local concept extraction.`
|
|
2489
|
+
);
|
|
2490
|
+
} else {
|
|
2491
|
+
logger2.debug(
|
|
2492
|
+
"No EMGAS extractor model configured. Falling back to local concept extraction."
|
|
2493
|
+
);
|
|
2494
|
+
}
|
|
2399
2495
|
this.docstore = new import_vectorstores2.DataBaseDocstore(
|
|
2400
2496
|
this.ctx,
|
|
2401
2497
|
resolveLongMemoryId(this.info)
|
package/lib/index.mjs
CHANGED
|
@@ -1964,6 +1964,153 @@ async function createVectorStoreRetriever(ctx, config, longMemoryId) {
|
|
|
1964
1964
|
}
|
|
1965
1965
|
__name(createVectorStoreRetriever, "createVectorStoreRetriever");
|
|
1966
1966
|
|
|
1967
|
+
// src/layers/emgas/extractor.ts
|
|
1968
|
+
import YAML2 from "js-yaml";
|
|
1969
|
+
import { getMessageContent as getMessageContent3 } from "koishi-plugin-chatluna/utils/string";
|
|
1970
|
+
var GRAPH_ELEMENTS_EXTRACTION_PROMPT = /* @__PURE__ */ __name((text) => `
|
|
1971
|
+
You are an expert in knowledge extraction. Your task is to analyze the following text to identify key concepts and overarching topics.
|
|
1972
|
+
|
|
1973
|
+
Text to analyze:
|
|
1974
|
+
"""
|
|
1975
|
+
${text}
|
|
1976
|
+
"""
|
|
1977
|
+
|
|
1978
|
+
Respond with a single, valid YAML block with two keys: 'concepts' and 'topics'.
|
|
1979
|
+
|
|
1980
|
+
Guidelines:
|
|
1981
|
+
1. **concepts**: A list of the most important keywords, and named entities from the text. Use the base form or most common form.
|
|
1982
|
+
2. **topics**: A list of 1-3 higher-level topics that categorize the concepts. These should be broader categories.
|
|
1983
|
+
3. If no meaningful data can be extracted, return empty lists for both keys.
|
|
1984
|
+
|
|
1985
|
+
Example:
|
|
1986
|
+
Text: "The user is asking about setting up a new React project with Vite. They are having trouble with the HMR (Hot Module Replacement) configuration."
|
|
1987
|
+
|
|
1988
|
+
YAML Output:
|
|
1989
|
+
\`\`\`yaml
|
|
1990
|
+
concepts:
|
|
1991
|
+
- React
|
|
1992
|
+
- Vite
|
|
1993
|
+
- HMR
|
|
1994
|
+
- project setup
|
|
1995
|
+
topics:
|
|
1996
|
+
- Frontend Development
|
|
1997
|
+
- Build Tools
|
|
1998
|
+
\`\`\`
|
|
1999
|
+
|
|
2000
|
+
YAML Output:
|
|
2001
|
+
`, "GRAPH_ELEMENTS_EXTRACTION_PROMPT");
|
|
2002
|
+
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
2003
|
+
"a",
|
|
2004
|
+
"an",
|
|
2005
|
+
"and",
|
|
2006
|
+
"are",
|
|
2007
|
+
"as",
|
|
2008
|
+
"at",
|
|
2009
|
+
"be",
|
|
2010
|
+
"by",
|
|
2011
|
+
"for",
|
|
2012
|
+
"from",
|
|
2013
|
+
"how",
|
|
2014
|
+
"in",
|
|
2015
|
+
"is",
|
|
2016
|
+
"it",
|
|
2017
|
+
"of",
|
|
2018
|
+
"on",
|
|
2019
|
+
"or",
|
|
2020
|
+
"that",
|
|
2021
|
+
"the",
|
|
2022
|
+
"their",
|
|
2023
|
+
"they",
|
|
2024
|
+
"this",
|
|
2025
|
+
"to",
|
|
2026
|
+
"with",
|
|
2027
|
+
"用户",
|
|
2028
|
+
"我们",
|
|
2029
|
+
"你们",
|
|
2030
|
+
"他们",
|
|
2031
|
+
"以及",
|
|
2032
|
+
"但是",
|
|
2033
|
+
"如果",
|
|
2034
|
+
"因为",
|
|
2035
|
+
"所以"
|
|
2036
|
+
]);
|
|
2037
|
+
function format(items) {
|
|
2038
|
+
return items.map((item) => String(item).trim().replace(/\s+/g, " ")).filter(Boolean).map(
|
|
2039
|
+
(item) => /^[\x00-\x7F]+$/.test(item) ? item.toLowerCase() : item
|
|
2040
|
+
);
|
|
2041
|
+
}
|
|
2042
|
+
__name(format, "format");
|
|
2043
|
+
function extractLocal(text) {
|
|
2044
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2045
|
+
const groups = [];
|
|
2046
|
+
for (const item of text.match(
|
|
2047
|
+
/[A-Za-z][A-Za-z0-9+#./-]{1,}|[\u3400-\u9fff]{2,}/g
|
|
2048
|
+
) ?? []) {
|
|
2049
|
+
if (/^[A-Za-z]/.test(item)) {
|
|
2050
|
+
const word = item.toLowerCase();
|
|
2051
|
+
if (STOP_WORDS.has(word)) {
|
|
2052
|
+
continue;
|
|
2053
|
+
}
|
|
2054
|
+
counts.set(word, (counts.get(word) ?? 0) + 1);
|
|
2055
|
+
if (word.length >= 4) {
|
|
2056
|
+
groups.push(word);
|
|
2057
|
+
}
|
|
2058
|
+
continue;
|
|
2059
|
+
}
|
|
2060
|
+
if (item.length >= 2) {
|
|
2061
|
+
groups.push(item.length > 12 ? item.slice(0, 12) : item);
|
|
2062
|
+
}
|
|
2063
|
+
if (item.length <= 8) {
|
|
2064
|
+
counts.set(item, (counts.get(item) ?? 0) + 1);
|
|
2065
|
+
continue;
|
|
2066
|
+
}
|
|
2067
|
+
for (let i = 0; i < item.length - 1; i++) {
|
|
2068
|
+
const word = item.slice(i, i + 2);
|
|
2069
|
+
counts.set(word, (counts.get(word) ?? 0) + 1);
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
const concepts = Array.from(counts.entries()).sort((a, b) => b[1] - a[1] || b[0].length - a[0].length).map(([item]) => item).slice(0, 12);
|
|
2073
|
+
const topics = Array.from(new Set(format(groups))).filter((item) => !STOP_WORDS.has(item)).slice(0, 3);
|
|
2074
|
+
return {
|
|
2075
|
+
concepts,
|
|
2076
|
+
topics: topics.length > 0 ? topics : concepts.slice(0, 3)
|
|
2077
|
+
};
|
|
2078
|
+
}
|
|
2079
|
+
__name(extractLocal, "extractLocal");
|
|
2080
|
+
async function extractGraphElements(modelRef, text) {
|
|
2081
|
+
const model = modelRef?.value;
|
|
2082
|
+
if (model == null) {
|
|
2083
|
+
return extractLocal(text);
|
|
2084
|
+
}
|
|
2085
|
+
try {
|
|
2086
|
+
const prompt = GRAPH_ELEMENTS_EXTRACTION_PROMPT(text);
|
|
2087
|
+
const res = await model.invoke(prompt);
|
|
2088
|
+
const content = getMessageContent3(res.content).trim();
|
|
2089
|
+
const yamlMatch = content.match(
|
|
2090
|
+
/```(?:ya?ml)?\s*\r?\n([\s\S]*?)\r?\n```/i
|
|
2091
|
+
);
|
|
2092
|
+
const parsed = YAML2.load(yamlMatch?.[1] ?? content);
|
|
2093
|
+
if (parsed && typeof parsed === "object") {
|
|
2094
|
+
const concepts = format(
|
|
2095
|
+
Array.isArray(parsed.concepts) ? parsed.concepts : []
|
|
2096
|
+
);
|
|
2097
|
+
const topics = format(
|
|
2098
|
+
Array.isArray(parsed.topics) ? parsed.topics : []
|
|
2099
|
+
);
|
|
2100
|
+
if (concepts.length > 0 || topics.length > 0) {
|
|
2101
|
+
return {
|
|
2102
|
+
concepts,
|
|
2103
|
+
topics: topics.length > 0 ? topics : concepts.slice(0, 3)
|
|
2104
|
+
};
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
return extractLocal(text);
|
|
2108
|
+
} catch {
|
|
2109
|
+
return extractLocal(text);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
__name(extractGraphElements, "extractGraphElements");
|
|
2113
|
+
|
|
1967
2114
|
// src/layers/emgas/graph.ts
|
|
1968
2115
|
var MemoryGraph = class _MemoryGraph {
|
|
1969
2116
|
static {
|
|
@@ -2172,12 +2319,16 @@ var MemoryGraph = class _MemoryGraph {
|
|
|
2172
2319
|
return this.nodes.values();
|
|
2173
2320
|
}
|
|
2174
2321
|
toJSON() {
|
|
2175
|
-
const nodes = Array.from(
|
|
2176
|
-
(
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2322
|
+
const nodes = Array.from(
|
|
2323
|
+
this.nodes.values()
|
|
2324
|
+
).map((node) => ({
|
|
2325
|
+
id: node.id,
|
|
2326
|
+
type: node.type,
|
|
2327
|
+
baseActivation: node.baseActivation,
|
|
2328
|
+
createdAt: node.createdAt.toISOString(),
|
|
2329
|
+
lastAccessed: node.lastAccessed.toISOString(),
|
|
2330
|
+
sourcePassageIds: node.sourcePassageIds ? Array.from(node.sourcePassageIds) : []
|
|
2331
|
+
}));
|
|
2181
2332
|
const edges = [];
|
|
2182
2333
|
const seenEdges = /* @__PURE__ */ new Set();
|
|
2183
2334
|
for (const source of this.edges.values()) {
|
|
@@ -2202,9 +2353,11 @@ var MemoryGraph = class _MemoryGraph {
|
|
|
2202
2353
|
if (!serializedGraph) return graph;
|
|
2203
2354
|
for (const nodeData of serializedGraph.nodes || []) {
|
|
2204
2355
|
graph.nodes.set(nodeData.id, {
|
|
2205
|
-
...nodeData,
|
|
2206
2356
|
createdAt: new Date(nodeData.createdAt),
|
|
2207
2357
|
lastAccessed: new Date(nodeData.lastAccessed),
|
|
2358
|
+
id: nodeData.id,
|
|
2359
|
+
type: nodeData.type,
|
|
2360
|
+
baseActivation: nodeData.baseActivation,
|
|
2208
2361
|
sourcePassageIds: new Set(nodeData.sourcePassageIds || [])
|
|
2209
2362
|
});
|
|
2210
2363
|
}
|
|
@@ -2223,90 +2376,7 @@ import { randomUUID as randomUUID4 } from "crypto";
|
|
|
2223
2376
|
import { promises as fs2 } from "fs";
|
|
2224
2377
|
import * as path2 from "path";
|
|
2225
2378
|
import { DataBaseDocstore } from "koishi-plugin-chatluna/llm-core/vectorstores";
|
|
2226
|
-
|
|
2227
|
-
// src/layers/emgas/extractor.ts
|
|
2228
|
-
import YAML2 from "js-yaml";
|
|
2229
|
-
import { getMessageContent as getMessageContent3 } from "koishi-plugin-chatluna/utils/string";
|
|
2230
|
-
import {
|
|
2231
|
-
ChatLunaError,
|
|
2232
|
-
ChatLunaErrorCode
|
|
2233
|
-
} from "koishi-plugin-chatluna/utils/error";
|
|
2234
|
-
var GRAPH_ELEMENTS_EXTRACTION_PROMPT = /* @__PURE__ */ __name((text) => `
|
|
2235
|
-
You are an expert in knowledge extraction. Your task is to analyze the following text to identify key concepts and overarching topics.
|
|
2236
|
-
|
|
2237
|
-
Text to analyze:
|
|
2238
|
-
"""
|
|
2239
|
-
${text}
|
|
2240
|
-
"""
|
|
2241
|
-
|
|
2242
|
-
Respond with a single, valid YAML block with two keys: 'concepts' and 'topics'.
|
|
2243
|
-
|
|
2244
|
-
Guidelines:
|
|
2245
|
-
1. **concepts**: A list of the most important keywords, and named entities from the text. Use the base form or most common form.
|
|
2246
|
-
2. **topics**: A list of 1-3 higher-level topics that categorize the concepts. These should be broader categories.
|
|
2247
|
-
3. If no meaningful data can be extracted, return empty lists for both keys.
|
|
2248
|
-
|
|
2249
|
-
Example:
|
|
2250
|
-
Text: "The user is asking about setting up a new React project with Vite. They are having trouble with the HMR (Hot Module Replacement) configuration."
|
|
2251
|
-
|
|
2252
|
-
YAML Output:
|
|
2253
|
-
\`\`\`yaml
|
|
2254
|
-
concepts:
|
|
2255
|
-
- React
|
|
2256
|
-
- Vite
|
|
2257
|
-
- HMR
|
|
2258
|
-
- project setup
|
|
2259
|
-
topics:
|
|
2260
|
-
- Frontend Development
|
|
2261
|
-
- Build Tools
|
|
2262
|
-
\`\`\`
|
|
2263
|
-
|
|
2264
|
-
YAML Output:
|
|
2265
|
-
`, "GRAPH_ELEMENTS_EXTRACTION_PROMPT");
|
|
2266
|
-
async function extractGraphElements(modelRef, text) {
|
|
2267
|
-
if (!modelRef.value) {
|
|
2268
|
-
throw new ChatLunaError(
|
|
2269
|
-
ChatLunaErrorCode.MODEL_NOT_FOUND,
|
|
2270
|
-
new Error(
|
|
2271
|
-
"LLM-based extractor is disabled. Cannot extract graph elements."
|
|
2272
|
-
)
|
|
2273
|
-
);
|
|
2274
|
-
}
|
|
2275
|
-
const model = modelRef.value;
|
|
2276
|
-
try {
|
|
2277
|
-
const prompt = GRAPH_ELEMENTS_EXTRACTION_PROMPT(text);
|
|
2278
|
-
const res = await model.invoke(prompt);
|
|
2279
|
-
const content = getMessageContent3(res.content);
|
|
2280
|
-
const yamlMatch = content.match(
|
|
2281
|
-
/```(?:ya?ml)?\s*\r?\n([\s\S]*?)\r?\n```/i
|
|
2282
|
-
);
|
|
2283
|
-
if (yamlMatch && yamlMatch[1]) {
|
|
2284
|
-
const parsed = YAML2.load(yamlMatch[1]);
|
|
2285
|
-
return {
|
|
2286
|
-
concepts: [].concat(parsed.concepts || []).map((item) => String(item).trim()).filter(Boolean),
|
|
2287
|
-
topics: [].concat(parsed.topics || []).map((item) => String(item).trim()).filter(Boolean)
|
|
2288
|
-
};
|
|
2289
|
-
}
|
|
2290
|
-
throw new ChatLunaError(
|
|
2291
|
-
ChatLunaErrorCode.MODEL_RESPONSE_IS_EMPTY,
|
|
2292
|
-
new Error(
|
|
2293
|
-
"LLM did not return a valid YAML for graph element extraction."
|
|
2294
|
-
)
|
|
2295
|
-
);
|
|
2296
|
-
} catch (error) {
|
|
2297
|
-
if (error instanceof ChatLunaError) {
|
|
2298
|
-
throw error;
|
|
2299
|
-
}
|
|
2300
|
-
throw new ChatLunaError(
|
|
2301
|
-
ChatLunaErrorCode.API_REQUEST_FAILED,
|
|
2302
|
-
error
|
|
2303
|
-
);
|
|
2304
|
-
}
|
|
2305
|
-
}
|
|
2306
|
-
__name(extractGraphElements, "extractGraphElements");
|
|
2307
|
-
|
|
2308
|
-
// src/layers/emgas/layer.ts
|
|
2309
|
-
function getGraphFilePath(baseDir, memoryId) {
|
|
2379
|
+
function getGraphFilePath(baseDir, memoryId, dir = "emgas") {
|
|
2310
2380
|
if (!memoryId || typeof memoryId !== "string") {
|
|
2311
2381
|
throw new Error("Invalid memoryId: must be a non-empty string.");
|
|
2312
2382
|
}
|
|
@@ -2316,7 +2386,10 @@ function getGraphFilePath(baseDir, memoryId) {
|
|
|
2316
2386
|
}
|
|
2317
2387
|
return path2.join(
|
|
2318
2388
|
baseDir,
|
|
2319
|
-
"data
|
|
2389
|
+
"data",
|
|
2390
|
+
"chatluna",
|
|
2391
|
+
"long-memory",
|
|
2392
|
+
dir,
|
|
2320
2393
|
`${sanitizedId}.json`
|
|
2321
2394
|
);
|
|
2322
2395
|
}
|
|
@@ -2340,28 +2413,48 @@ var EmgasMemoryLayer = class extends BaseMemoryRetrievalLayer {
|
|
|
2340
2413
|
`Initializing EMGAS layer for memory ID: ${this.info.memoryId}`
|
|
2341
2414
|
);
|
|
2342
2415
|
const baseDir = this.ctx.baseDir || process.cwd();
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
logger2.debug(
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
}
|
|
2416
|
+
let loaded = false;
|
|
2417
|
+
for (const filePath of [
|
|
2418
|
+
getGraphFilePath(baseDir, this.info.memoryId),
|
|
2419
|
+
getGraphFilePath(baseDir, this.info.memoryId, "emgasa")
|
|
2420
|
+
]) {
|
|
2421
|
+
try {
|
|
2422
|
+
const data = await fs2.readFile(filePath, "utf-8");
|
|
2423
|
+
const serialized = JSON.parse(data);
|
|
2424
|
+
this.memoryGraph = MemoryGraph.fromJSON(serialized);
|
|
2425
|
+
logger2.debug(`EMGAS graph loaded from ${filePath}`);
|
|
2426
|
+
loaded = true;
|
|
2427
|
+
break;
|
|
2428
|
+
} catch (error) {
|
|
2429
|
+
const err = error;
|
|
2430
|
+
if (err && err.code === "ENOENT") {
|
|
2431
|
+
continue;
|
|
2432
|
+
}
|
|
2356
2433
|
logger2.error(
|
|
2357
|
-
`Failed to load EMGAS graph
|
|
2434
|
+
`Failed to load EMGAS graph for ${this.info.memoryId}:`,
|
|
2358
2435
|
error
|
|
2359
2436
|
);
|
|
2437
|
+
break;
|
|
2360
2438
|
}
|
|
2361
2439
|
}
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2440
|
+
if (!loaded) {
|
|
2441
|
+
logger2.debug(
|
|
2442
|
+
`No existing EMGAS graph found for ${this.info.memoryId}. A new one will be created.`
|
|
2443
|
+
);
|
|
2444
|
+
}
|
|
2445
|
+
const modelName = this.config.emgasExtractModel !== "无" ? this.config.emgasExtractModel : this.config.longMemoryExtractModel !== "无" ? this.config.longMemoryExtractModel : this.config.hippoExtractModel !== "无" ? this.config.hippoExtractModel : void 0;
|
|
2446
|
+
this.extractModel = void 0;
|
|
2447
|
+
if (modelName?.includes("/")) {
|
|
2448
|
+
this.extractModel = await this.ctx.chatluna.createChatModel(modelName);
|
|
2449
|
+
} else if (modelName != null) {
|
|
2450
|
+
logger2.warn(
|
|
2451
|
+
`Invalid EMGAS extractor model: ${modelName}. Falling back to local concept extraction.`
|
|
2452
|
+
);
|
|
2453
|
+
} else {
|
|
2454
|
+
logger2.debug(
|
|
2455
|
+
"No EMGAS extractor model configured. Falling back to local concept extraction."
|
|
2456
|
+
);
|
|
2457
|
+
}
|
|
2365
2458
|
this.docstore = new DataBaseDocstore(
|
|
2366
2459
|
this.ctx,
|
|
2367
2460
|
resolveLongMemoryId(this.info)
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import { ChatLunaChatModel } from 'koishi-plugin-chatluna/llm-core/platform/model';
|
|
2
1
|
import { ComputedRef } from 'koishi-plugin-chatluna';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
topics: string[];
|
|
6
|
-
}
|
|
2
|
+
import { ChatLunaChatModel } from 'koishi-plugin-chatluna/llm-core/platform/model';
|
|
3
|
+
import { ExtractedGraphElements } from './types';
|
|
7
4
|
/**
|
|
8
|
-
* Extracts key concepts and topics from a text chunk
|
|
9
|
-
*
|
|
10
|
-
* @param
|
|
5
|
+
* Extracts key concepts and topics from a text chunk.
|
|
6
|
+
* It prefers the configured LLM and falls back to local extraction.
|
|
7
|
+
* @param modelRef The configured extractor model.
|
|
11
8
|
* @param text The text to analyze.
|
|
12
9
|
* @returns A promise that resolves to an object containing concepts and topics.
|
|
13
10
|
*/
|
|
14
|
-
export declare function extractGraphElements(modelRef: ComputedRef<ChatLunaChatModel
|
|
11
|
+
export declare function extractGraphElements(modelRef: ComputedRef<ChatLunaChatModel | undefined> | undefined, text: string): Promise<ExtractedGraphElements>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ExtractedGraphElements } from './
|
|
2
|
-
import { MemoryNode, SerializedMemoryGraph, SpreadingActivationOptions } from './types';
|
|
1
|
+
import { ExtractedGraphElements, MemoryNode, SerializedMemoryGraph, SpreadingActivationOptions } from './types';
|
|
3
2
|
/**
|
|
4
3
|
* A class that implements the EMGAS (Episodic Memory Graph with Activation Spreading) framework.
|
|
5
4
|
* It manages a dynamic graph of concepts, handles incremental updates, and performs retrieval
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Core data structures for the EMGAS (Episodic Memory Graph with Activation Spreading) model.
|
|
3
3
|
* Based on the TypeScript blueprint provided in the design document.
|
|
4
4
|
*/
|
|
5
|
+
export interface ExtractedGraphElements {
|
|
6
|
+
concepts: string[];
|
|
7
|
+
topics: string[];
|
|
8
|
+
}
|
|
5
9
|
/**
|
|
6
10
|
* Options for the Spreading Activation retrieval algorithm.
|
|
7
11
|
*/
|
|
@@ -62,6 +66,11 @@ export interface MemoryNode {
|
|
|
62
66
|
*/
|
|
63
67
|
sourcePassageIds?: Set<string>;
|
|
64
68
|
}
|
|
69
|
+
export interface SerializedMemoryNode extends Omit<MemoryNode, 'createdAt' | 'lastAccessed' | 'sourcePassageIds'> {
|
|
70
|
+
createdAt: string;
|
|
71
|
+
lastAccessed: string;
|
|
72
|
+
sourcePassageIds: string[];
|
|
73
|
+
}
|
|
65
74
|
/**
|
|
66
75
|
* Represents a weighted edge in the memory graph, connecting two nodes.
|
|
67
76
|
*/
|
|
@@ -90,7 +99,7 @@ export interface MemoryEdge {
|
|
|
90
99
|
* Represents the entire memory graph, including nodes, edges, and persistence data.
|
|
91
100
|
*/
|
|
92
101
|
export interface SerializedMemoryGraph {
|
|
93
|
-
nodes:
|
|
102
|
+
nodes: SerializedMemoryNode[];
|
|
94
103
|
edges: MemoryEdge[];
|
|
95
104
|
conceptCounts: [string, number][];
|
|
96
105
|
pairCounts: [string, number][];
|
package/lib/plugins/tool.d.ts
CHANGED
|
@@ -35,27 +35,27 @@ export declare class MemoryAddTool extends StructuredTool {
|
|
|
35
35
|
type: z.ZodNativeEnum<typeof MemoryType>;
|
|
36
36
|
importance: z.ZodNumber;
|
|
37
37
|
}, "strip", z.ZodTypeAny, {
|
|
38
|
-
type?: MemoryType;
|
|
39
38
|
content?: string;
|
|
39
|
+
type?: MemoryType;
|
|
40
40
|
importance?: number;
|
|
41
41
|
}, {
|
|
42
|
-
type?: MemoryType;
|
|
43
42
|
content?: string;
|
|
43
|
+
type?: MemoryType;
|
|
44
44
|
importance?: number;
|
|
45
45
|
}>, "many">;
|
|
46
46
|
layer: z.ZodArray<z.ZodUnion<[z.ZodLiteral<"user">, z.ZodLiteral<"preset">, z.ZodLiteral<"guild">, z.ZodLiteral<"global">]>, "many">;
|
|
47
47
|
}, "strip", z.ZodTypeAny, {
|
|
48
48
|
layer?: ("global" | "preset" | "user" | "guild")[];
|
|
49
49
|
memories?: {
|
|
50
|
-
type?: MemoryType;
|
|
51
50
|
content?: string;
|
|
51
|
+
type?: MemoryType;
|
|
52
52
|
importance?: number;
|
|
53
53
|
}[];
|
|
54
54
|
}, {
|
|
55
55
|
layer?: ("global" | "preset" | "user" | "guild")[];
|
|
56
56
|
memories?: {
|
|
57
|
-
type?: MemoryType;
|
|
58
57
|
content?: string;
|
|
58
|
+
type?: MemoryType;
|
|
59
59
|
importance?: number;
|
|
60
60
|
}[];
|
|
61
61
|
}>;
|
|
@@ -94,12 +94,12 @@ export declare class MemoryUpdateTool extends StructuredTool {
|
|
|
94
94
|
type: z.ZodNativeEnum<typeof MemoryType>;
|
|
95
95
|
importance: z.ZodNumber;
|
|
96
96
|
}, "strip", z.ZodTypeAny, {
|
|
97
|
-
type?: MemoryType;
|
|
98
97
|
content?: string;
|
|
98
|
+
type?: MemoryType;
|
|
99
99
|
importance?: number;
|
|
100
100
|
}, {
|
|
101
|
-
type?: MemoryType;
|
|
102
101
|
content?: string;
|
|
102
|
+
type?: MemoryType;
|
|
103
103
|
importance?: number;
|
|
104
104
|
}>, "many">;
|
|
105
105
|
layer: z.ZodArray<z.ZodUnion<[z.ZodLiteral<"user">, z.ZodLiteral<"preset">, z.ZodLiteral<"guild">, z.ZodLiteral<"global">]>, "many">;
|
|
@@ -107,16 +107,16 @@ export declare class MemoryUpdateTool extends StructuredTool {
|
|
|
107
107
|
layer?: ("global" | "preset" | "user" | "guild")[];
|
|
108
108
|
memoryIds?: string[];
|
|
109
109
|
newMemories?: {
|
|
110
|
-
type?: MemoryType;
|
|
111
110
|
content?: string;
|
|
111
|
+
type?: MemoryType;
|
|
112
112
|
importance?: number;
|
|
113
113
|
}[];
|
|
114
114
|
}, {
|
|
115
115
|
layer?: ("global" | "preset" | "user" | "guild")[];
|
|
116
116
|
memoryIds?: string[];
|
|
117
117
|
newMemories?: {
|
|
118
|
-
type?: MemoryType;
|
|
119
118
|
content?: string;
|
|
119
|
+
type?: MemoryType;
|
|
120
120
|
importance?: number;
|
|
121
121
|
}[];
|
|
122
122
|
}>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-chatluna-long-memory",
|
|
3
3
|
"description": "long memory for chatluna",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.3",
|
|
5
5
|
"main": "lib/index.cjs",
|
|
6
6
|
"module": "lib/index.mjs",
|
|
7
7
|
"typings": "lib/index.d.ts",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"koishi": "^4.18.9",
|
|
65
|
-
"koishi-plugin-chatluna": "^1.3.
|
|
65
|
+
"koishi-plugin-chatluna": "^1.3.33"
|
|
66
66
|
},
|
|
67
67
|
"resolutions": {
|
|
68
68
|
"@langchain/core": "^0.3.80",
|