memorylake-openclaw 1.1.2 → 1.1.4
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/dist/index.js +1794 -0
- package/dist/index.js.map +1 -0
- package/package.json +18 -1
- package/.github/workflows/release.yml +0 -23
- package/CHANGELOG.md +0 -55
- package/docs/openclaw.mdx +0 -110
- package/index.ts +0 -65
- package/lib/cli/register-cli.ts +0 -134
- package/lib/config.ts +0 -105
- package/lib/core-bridge.ts +0 -155
- package/lib/helpers/parse-content-disposition.ts +0 -21
- package/lib/helpers/rewrite-query.ts +0 -122
- package/lib/helpers/upload-record.ts +0 -47
- package/lib/hooks/auto-capture.ts +0 -97
- package/lib/hooks/auto-recall.ts +0 -89
- package/lib/hooks/auto-upload.ts +0 -72
- package/lib/plugin-context.ts +0 -77
- package/lib/prompt/register-prompt.ts +0 -66
- package/lib/provider.ts +0 -227
- package/lib/tools/document-tools.ts +0 -100
- package/lib/tools/memory-tools.ts +0 -298
- package/lib/tools/search-tools.ts +0 -288
- package/lib/types.ts +0 -273
- package/lib/utils/builders.ts +0 -127
- package/lib/utils/config-parser.ts +0 -14
- package/lib/utils/normalizers.ts +0 -76
- package/test/json5_config_smoke.test.mjs +0 -104
- package/test/path_reg.test.mjs +0 -197
package/lib/types.ts
DELETED
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
export const DEFAULT_USER_ID = "default";
|
|
2
|
-
|
|
3
|
-
export type MemoryLakeConfig = {
|
|
4
|
-
host: string;
|
|
5
|
-
apiKey: string;
|
|
6
|
-
projectId: string;
|
|
7
|
-
userId: string;
|
|
8
|
-
autoCapture: boolean;
|
|
9
|
-
autoRecall: boolean;
|
|
10
|
-
autoUpload: boolean;
|
|
11
|
-
searchThreshold: number;
|
|
12
|
-
topK: number;
|
|
13
|
-
rerank: boolean;
|
|
14
|
-
webSearchIncludeDomains?: string[];
|
|
15
|
-
webSearchExcludeDomains?: string[];
|
|
16
|
-
webSearchCountry?: string;
|
|
17
|
-
webSearchTimezone?: string;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
// V2 API option types
|
|
21
|
-
export interface AddOptions {
|
|
22
|
-
user_id: string;
|
|
23
|
-
chat_session_id?: string;
|
|
24
|
-
metadata?: Record<string, unknown>;
|
|
25
|
-
infer?: boolean;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface SearchOptions {
|
|
29
|
-
user_id: string;
|
|
30
|
-
top_k?: number;
|
|
31
|
-
threshold?: number;
|
|
32
|
-
rerank?: boolean;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface ListOptions {
|
|
36
|
-
user_id?: string;
|
|
37
|
-
page?: number;
|
|
38
|
-
size?: number;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface MemoryItem {
|
|
42
|
-
id: string;
|
|
43
|
-
content: string;
|
|
44
|
-
user_id?: string;
|
|
45
|
-
created_at?: string;
|
|
46
|
-
updated_at?: string;
|
|
47
|
-
has_unresolved_conflict?: boolean;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface ConflictMemorySnapshot {
|
|
51
|
-
memory_id: string;
|
|
52
|
-
memory_history_id?: string;
|
|
53
|
-
memory_text: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface ConflictFileChunk {
|
|
57
|
-
chunk: { type?: string; text: string; range?: string };
|
|
58
|
-
document_id?: string;
|
|
59
|
-
document_name?: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface ConflictResolve {
|
|
63
|
-
id: string;
|
|
64
|
-
strategy: string;
|
|
65
|
-
keep_memory_id?: string;
|
|
66
|
-
forgotten_memory_ids?: string[];
|
|
67
|
-
resolved_by?: string;
|
|
68
|
-
created_at?: string;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export interface ConflictItem {
|
|
72
|
-
id: string;
|
|
73
|
-
name: string;
|
|
74
|
-
description: string;
|
|
75
|
-
category: "m2m" | "m2d";
|
|
76
|
-
conflict_type: "logical" | "knowledge";
|
|
77
|
-
memory_ids: string[];
|
|
78
|
-
memory_snapshots: ConflictMemorySnapshot[];
|
|
79
|
-
file_chunks: ConflictFileChunk[];
|
|
80
|
-
resolved: boolean;
|
|
81
|
-
resolve?: ConflictResolve;
|
|
82
|
-
stale?: boolean;
|
|
83
|
-
event_id?: string;
|
|
84
|
-
created_at?: string;
|
|
85
|
-
updated_at?: string;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export interface ConflictListResponse {
|
|
89
|
-
items: ConflictItem[];
|
|
90
|
-
page: number;
|
|
91
|
-
total: number;
|
|
92
|
-
page_size: number;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export interface AddResultItem {
|
|
96
|
-
event_id: string;
|
|
97
|
-
status: string;
|
|
98
|
-
message: string;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export interface AddResult {
|
|
102
|
-
results: AddResultItem[];
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export interface DocumentSearchResult {
|
|
106
|
-
type: "table" | "paragraph" | "figure";
|
|
107
|
-
document_id?: string;
|
|
108
|
-
document_name?: string;
|
|
109
|
-
source_document?: { file_name?: string };
|
|
110
|
-
highlight?: {
|
|
111
|
-
chunks?: Array<{ text?: string; range?: string }>;
|
|
112
|
-
inner_tables?: Array<{
|
|
113
|
-
id?: string;
|
|
114
|
-
columns?: Array<{ name?: string; data_type?: string }>;
|
|
115
|
-
num_rows?: number;
|
|
116
|
-
}>;
|
|
117
|
-
figure?: {
|
|
118
|
-
text?: string;
|
|
119
|
-
caption?: string;
|
|
120
|
-
summary_text?: string;
|
|
121
|
-
};
|
|
122
|
-
};
|
|
123
|
-
title?: string;
|
|
124
|
-
footnote?: string;
|
|
125
|
-
sheet_name?: string;
|
|
126
|
-
semantic_sheet_name?: string;
|
|
127
|
-
figure_id?: number;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export interface DocumentSearchResponse {
|
|
131
|
-
count: number;
|
|
132
|
-
results: DocumentSearchResult[];
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Allowed values for web search domain (aligned with zootopia unified_search Domain).
|
|
137
|
-
* Declared as enum in schema; at runtime accept string and fall back to "auto" if invalid.
|
|
138
|
-
*/
|
|
139
|
-
export const WebSearchDomainValues = [
|
|
140
|
-
"web",
|
|
141
|
-
"academic",
|
|
142
|
-
"news",
|
|
143
|
-
"people",
|
|
144
|
-
"company",
|
|
145
|
-
"financial",
|
|
146
|
-
"markets",
|
|
147
|
-
"code",
|
|
148
|
-
"legal",
|
|
149
|
-
"government",
|
|
150
|
-
"poi",
|
|
151
|
-
"auto",
|
|
152
|
-
] as const;
|
|
153
|
-
export type WebSearchDomain = (typeof WebSearchDomainValues)[number];
|
|
154
|
-
|
|
155
|
-
export const WEB_SEARCH_DOMAIN_SET = new Set<string>(WebSearchDomainValues);
|
|
156
|
-
|
|
157
|
-
export interface WebSearchUserLocation {
|
|
158
|
-
country?: string;
|
|
159
|
-
timezone?: string;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export interface WebSearchOptions {
|
|
163
|
-
/** Declared as enum in schema; at runtime accept string, normalized with fallback to "auto". */
|
|
164
|
-
domain?: WebSearchDomain | string;
|
|
165
|
-
max_results?: number;
|
|
166
|
-
start_date?: string;
|
|
167
|
-
end_date?: string;
|
|
168
|
-
include_domains?: string[];
|
|
169
|
-
exclude_domains?: string[];
|
|
170
|
-
user_location?: WebSearchUserLocation;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export interface WebSearchResult {
|
|
174
|
-
url?: string;
|
|
175
|
-
title?: string;
|
|
176
|
-
summary?: string;
|
|
177
|
-
content?: string;
|
|
178
|
-
source?: string;
|
|
179
|
-
published_date?: string;
|
|
180
|
-
author?: string;
|
|
181
|
-
score?: number;
|
|
182
|
-
highlights?: string[];
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export interface WebSearchResponse {
|
|
186
|
-
results: WebSearchResult[];
|
|
187
|
-
total_results: number;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Allowed values for open data search category (aligned with opendata endpoint).
|
|
192
|
-
* Maps to proprietary data sources per category.
|
|
193
|
-
*/
|
|
194
|
-
export const OpenDataCategoryValues = [
|
|
195
|
-
"research/academic",
|
|
196
|
-
"clinical/trials",
|
|
197
|
-
"drug/database",
|
|
198
|
-
"financial/markets",
|
|
199
|
-
"company/fundamentals",
|
|
200
|
-
"economic/data",
|
|
201
|
-
"patents/ip",
|
|
202
|
-
] as const;
|
|
203
|
-
export type OpenDataCategory = (typeof OpenDataCategoryValues)[number];
|
|
204
|
-
|
|
205
|
-
export const OPEN_DATA_CATEGORY_SET = new Set<string>(OpenDataCategoryValues);
|
|
206
|
-
|
|
207
|
-
export interface OpenDataIndustry {
|
|
208
|
-
id: string;
|
|
209
|
-
name: string;
|
|
210
|
-
description?: string;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export interface ProjectInfo {
|
|
214
|
-
id: string;
|
|
215
|
-
name: string;
|
|
216
|
-
description?: string;
|
|
217
|
-
industries: OpenDataIndustry[];
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export interface OpenDataSearchOptions {
|
|
221
|
-
dataset?: OpenDataCategory | string;
|
|
222
|
-
max_results?: number;
|
|
223
|
-
start_date?: string;
|
|
224
|
-
end_date?: string;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export interface OpenDataSearchResult {
|
|
228
|
-
title?: string;
|
|
229
|
-
url?: string;
|
|
230
|
-
summary?: string;
|
|
231
|
-
content?: string;
|
|
232
|
-
source?: string;
|
|
233
|
-
category?: string;
|
|
234
|
-
published_date?: string;
|
|
235
|
-
author?: string;
|
|
236
|
-
score?: number;
|
|
237
|
-
metadata?: Record<string, unknown>;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
export interface OpenDataSearchResponse {
|
|
241
|
-
results: OpenDataSearchResult[];
|
|
242
|
-
total_results: number;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// ============================================================================
|
|
246
|
-
// Unified Provider Interface
|
|
247
|
-
// ============================================================================
|
|
248
|
-
|
|
249
|
-
export interface MemoryLakeProvider {
|
|
250
|
-
add(
|
|
251
|
-
messages: Array<{ role: string; content: string }>,
|
|
252
|
-
options: AddOptions,
|
|
253
|
-
): Promise<AddResult>;
|
|
254
|
-
search(query: string, options: SearchOptions): Promise<MemoryItem[]>;
|
|
255
|
-
get(memoryId: string): Promise<MemoryItem>;
|
|
256
|
-
getAll(options: ListOptions): Promise<MemoryItem[]>;
|
|
257
|
-
delete(memoryId: string): Promise<void>;
|
|
258
|
-
searchDocuments(query: string, topN: number): Promise<DocumentSearchResponse>;
|
|
259
|
-
getDocumentDownloadUrl(documentId: string): Promise<string>;
|
|
260
|
-
searchWeb(query: string, options: WebSearchOptions): Promise<WebSearchResponse>;
|
|
261
|
-
searchOpenData(query: string, options: OpenDataSearchOptions): Promise<OpenDataSearchResponse>;
|
|
262
|
-
getProject(): Promise<ProjectInfo>;
|
|
263
|
-
listConflicts(memoryIds: string[], userId: string): Promise<ConflictItem[]>;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/** Shared type for the upload / uploadAuto function signature */
|
|
267
|
-
export type UploadFn = (opts: {
|
|
268
|
-
host: string;
|
|
269
|
-
apiKey: string;
|
|
270
|
-
projectId: string;
|
|
271
|
-
filePath: string;
|
|
272
|
-
fileName: string;
|
|
273
|
-
}) => Promise<unknown>;
|
package/lib/utils/builders.ts
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
import type { MemoryLakeConfig, AddOptions, SearchOptions, DocumentSearchResult, WebSearchResult, ConflictItem, OpenDataSearchResult } from "../types";
|
|
3
|
-
|
|
4
|
-
const require = createRequire(import.meta.url);
|
|
5
|
-
const { version: PLUGIN_VERSION } = require("../../package.json") as { version: string };
|
|
6
|
-
|
|
7
|
-
// ============================================================================
|
|
8
|
-
// Context Builders
|
|
9
|
-
// ============================================================================
|
|
10
|
-
|
|
11
|
-
export function buildDocumentContext(
|
|
12
|
-
results: DocumentSearchResult[],
|
|
13
|
-
maxChunkLength = 10000,
|
|
14
|
-
): string {
|
|
15
|
-
const parts: string[] = [];
|
|
16
|
-
|
|
17
|
-
for (const result of results) {
|
|
18
|
-
const source = result.document_name ?? result.source_document?.file_name ?? "unknown";
|
|
19
|
-
const docId = result.document_id ?? "unknown";
|
|
20
|
-
const highlight = result.highlight;
|
|
21
|
-
|
|
22
|
-
if (result.type === "table") {
|
|
23
|
-
const title = result.title || "Untitled Table";
|
|
24
|
-
const sheetLabel = result.semantic_sheet_name || result.sheet_name;
|
|
25
|
-
const sheetPart = sheetLabel ? `, sheet: ${sheetLabel}` : "";
|
|
26
|
-
parts.push(`### Table: ${title} (from ${source}${sheetPart}, doc_id: ${docId})`);
|
|
27
|
-
if (result.footnote) parts.push(`Note: ${result.footnote}`);
|
|
28
|
-
|
|
29
|
-
for (const innerTable of highlight?.inner_tables ?? []) {
|
|
30
|
-
const colDesc = (innerTable.columns ?? [])
|
|
31
|
-
.map((c) => `${c.name}(${c.data_type})`)
|
|
32
|
-
.join(", ");
|
|
33
|
-
if (colDesc) parts.push(`Columns: ${colDesc}`);
|
|
34
|
-
if (innerTable.num_rows != null) parts.push(`Rows: ${innerTable.num_rows}`);
|
|
35
|
-
}
|
|
36
|
-
for (const chunk of highlight?.chunks ?? []) {
|
|
37
|
-
if (chunk.text) parts.push(chunk.text.slice(0, maxChunkLength));
|
|
38
|
-
}
|
|
39
|
-
} else if (result.type === "paragraph") {
|
|
40
|
-
parts.push(`### Paragraph (from ${source}, doc_id: ${docId}):`);
|
|
41
|
-
for (const chunk of highlight?.chunks ?? []) {
|
|
42
|
-
if (chunk.text) parts.push(chunk.text.slice(0, maxChunkLength));
|
|
43
|
-
}
|
|
44
|
-
} else if (result.type === "figure") {
|
|
45
|
-
const figure = highlight?.figure;
|
|
46
|
-
if (figure) {
|
|
47
|
-
parts.push(`### Figure (from ${source}, doc_id: ${docId}):`);
|
|
48
|
-
if (figure.caption) parts.push(`Caption: ${figure.caption}`);
|
|
49
|
-
const text = figure.text || figure.summary_text || "";
|
|
50
|
-
if (text) parts.push(text);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return parts.join("\n\n");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export function buildWebSearchContext(results: WebSearchResult[]): string {
|
|
59
|
-
return results
|
|
60
|
-
.map((result, index) => {
|
|
61
|
-
const parts = [`${index + 1}. ${result.title ?? result.url ?? "Untitled result"}`];
|
|
62
|
-
if (result.url) parts.push(`URL: ${result.url}`);
|
|
63
|
-
if (result.summary) parts.push(`Summary: ${result.summary}`);
|
|
64
|
-
if (result.source) parts.push(`Source: ${result.source}`);
|
|
65
|
-
if (result.published_date) parts.push(`Published: ${result.published_date}`);
|
|
66
|
-
return parts.join("\n");
|
|
67
|
-
})
|
|
68
|
-
.join("\n\n");
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function buildConflictContext(conflicts: ConflictItem[], maxChunkLength = 200): string {
|
|
72
|
-
return conflicts
|
|
73
|
-
.map((c) => {
|
|
74
|
-
const parts: string[] = [
|
|
75
|
-
`- [${c.conflict_type}] ${c.description}`,
|
|
76
|
-
];
|
|
77
|
-
for (const snap of c.memory_snapshots ?? []) {
|
|
78
|
-
parts.push(` Memory(${snap.memory_id}): ${snap.memory_text.slice(0, maxChunkLength)}`);
|
|
79
|
-
}
|
|
80
|
-
for (const fc of c.file_chunks ?? []) {
|
|
81
|
-
const docLabel = fc.document_name ?? fc.document_id ?? "unknown";
|
|
82
|
-
parts.push(` Document(${docLabel}): ${fc.chunk.text.slice(0, maxChunkLength)}`);
|
|
83
|
-
}
|
|
84
|
-
return parts.join("\n");
|
|
85
|
-
})
|
|
86
|
-
.join("\n");
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function buildOpenDataContext(results: OpenDataSearchResult[]): string {
|
|
90
|
-
const filtered = results.map((r) => {
|
|
91
|
-
const item: Record<string, unknown> = {};
|
|
92
|
-
if (r.title != null) item.title = r.title;
|
|
93
|
-
if (r.url != null) item.url = r.url;
|
|
94
|
-
if (r.content != null) item.content = r.content;
|
|
95
|
-
if (r.published_date != null) item.published_date = r.published_date;
|
|
96
|
-
if (r.category != null) item.category = r.category;
|
|
97
|
-
return item;
|
|
98
|
-
});
|
|
99
|
-
return JSON.stringify(filtered, null, 2);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// ============================================================================
|
|
103
|
-
// Option Builders
|
|
104
|
-
// ============================================================================
|
|
105
|
-
|
|
106
|
-
export function buildAddOptions(effectiveCfg: MemoryLakeConfig, userIdOverride?: string, sessionId?: string): AddOptions {
|
|
107
|
-
const opts: AddOptions = {
|
|
108
|
-
user_id: userIdOverride || effectiveCfg.userId,
|
|
109
|
-
infer: true,
|
|
110
|
-
metadata: { source: "OPENCLAW", plugin_version: PLUGIN_VERSION },
|
|
111
|
-
};
|
|
112
|
-
if (sessionId) opts.chat_session_id = sessionId;
|
|
113
|
-
return opts;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function buildSearchOptions(
|
|
117
|
-
effectiveCfg: MemoryLakeConfig,
|
|
118
|
-
userIdOverride?: string,
|
|
119
|
-
limit?: number,
|
|
120
|
-
): SearchOptions {
|
|
121
|
-
return {
|
|
122
|
-
user_id: userIdOverride || effectiveCfg.userId,
|
|
123
|
-
top_k: limit ?? effectiveCfg.topK,
|
|
124
|
-
threshold: effectiveCfg.searchThreshold,
|
|
125
|
-
rerank: effectiveCfg.rerank,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import JSON5 from "json5";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Read and parse a JSON5-compatible config file.
|
|
6
|
-
*/
|
|
7
|
-
export function readJson5ConfigFile(filePath: string): unknown {
|
|
8
|
-
const source = fs.readFileSync(filePath, "utf-8");
|
|
9
|
-
try {
|
|
10
|
-
return JSON5.parse(source);
|
|
11
|
-
} catch (err) {
|
|
12
|
-
throw new Error(`Failed to parse JSON5 config file "${filePath}": ${String(err)}`);
|
|
13
|
-
}
|
|
14
|
-
}
|
package/lib/utils/normalizers.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import type { MemoryItem, AddResult, WebSearchResponse, OpenDataSearchResult, OpenDataSearchResponse, WebSearchDomain, OpenDataCategory } from "../types";
|
|
2
|
-
import { WEB_SEARCH_DOMAIN_SET, OPEN_DATA_CATEGORY_SET } from "../types";
|
|
3
|
-
|
|
4
|
-
/** Normalize domain: accept string at runtime; if not a valid enum value, return "auto". */
|
|
5
|
-
export function normalizeWebSearchDomain(value: unknown): WebSearchDomain {
|
|
6
|
-
if (value == null) return "auto";
|
|
7
|
-
const s = typeof value === "string" ? value.toLowerCase().trim() : "";
|
|
8
|
-
return (WEB_SEARCH_DOMAIN_SET.has(s) ? s : "auto") as WebSearchDomain;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** Normalize category: accept string at runtime; return undefined if not a valid enum value. */
|
|
12
|
-
export function normalizeOpenDataCategory(value: unknown): OpenDataCategory | undefined {
|
|
13
|
-
if (value == null) return undefined;
|
|
14
|
-
const s = typeof value === "string" ? value.toLowerCase().trim() : "";
|
|
15
|
-
return OPEN_DATA_CATEGORY_SET.has(s) ? (s as OpenDataCategory) : undefined;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function normalizeMemoryItem(raw: any): MemoryItem {
|
|
19
|
-
return {
|
|
20
|
-
id: raw.id ?? "",
|
|
21
|
-
content: raw.content ?? "",
|
|
22
|
-
user_id: raw.user_id,
|
|
23
|
-
created_at: raw.created_at,
|
|
24
|
-
updated_at: raw.updated_at,
|
|
25
|
-
has_unresolved_conflict: raw.has_unresolved_conflict ?? false,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function normalizeSearchResults(raw: any): MemoryItem[] {
|
|
30
|
-
if (raw?.results && Array.isArray(raw.results))
|
|
31
|
-
return raw.results.map(normalizeMemoryItem);
|
|
32
|
-
if (Array.isArray(raw)) return raw.map(normalizeMemoryItem);
|
|
33
|
-
return [];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function normalizeAddResult(raw: any): AddResult {
|
|
37
|
-
const items = raw?.results ?? (Array.isArray(raw) ? raw : []);
|
|
38
|
-
return {
|
|
39
|
-
results: items.map((r: any) => ({
|
|
40
|
-
event_id: r.event_id ?? "",
|
|
41
|
-
status: r.status ?? "",
|
|
42
|
-
message: r.message ?? "",
|
|
43
|
-
})),
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function normalizeWebSearchResponse(raw: any): WebSearchResponse {
|
|
48
|
-
return {
|
|
49
|
-
results: Array.isArray(raw?.results) ? raw.results : [],
|
|
50
|
-
total_results: typeof raw?.total_results === "number" ? raw.total_results : 0,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function normalizeOpenDataResult(raw: any): OpenDataSearchResult {
|
|
55
|
-
return {
|
|
56
|
-
title: typeof raw?.title === "string" ? raw.title : undefined,
|
|
57
|
-
url: typeof raw?.url === "string" ? raw.url : undefined,
|
|
58
|
-
summary: typeof raw?.summary === "string" ? raw.summary : undefined,
|
|
59
|
-
content: typeof raw?.content === "string" ? raw.content : undefined,
|
|
60
|
-
source: typeof raw?.source === "string" ? raw.source : undefined,
|
|
61
|
-
category: typeof raw?.category === "string" ? raw.category : undefined,
|
|
62
|
-
published_date: typeof raw?.published_date === "string" ? raw.published_date : undefined,
|
|
63
|
-
author: typeof raw?.author === "string" ? raw.author : undefined,
|
|
64
|
-
score: typeof raw?.score === "number" ? raw.score : undefined,
|
|
65
|
-
metadata: raw?.metadata && typeof raw.metadata === "object" && !Array.isArray(raw.metadata)
|
|
66
|
-
? raw.metadata as Record<string, unknown>
|
|
67
|
-
: undefined,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function normalizeOpenDataSearchResponse(raw: any): OpenDataSearchResponse {
|
|
72
|
-
return {
|
|
73
|
-
results: Array.isArray(raw?.results) ? raw.results.map(normalizeOpenDataResult) : [],
|
|
74
|
-
total_results: typeof raw?.total_results === "number" ? raw.total_results : 0,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { describe, it } from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { mkdtempSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
import { join, resolve } from "node:path";
|
|
6
|
-
import { spawnSync } from "node:child_process";
|
|
7
|
-
|
|
8
|
-
const repoRoot = resolve(process.cwd());
|
|
9
|
-
const getConfigScript = join(repoRoot, "skills/common/get-config.mjs");
|
|
10
|
-
const pluginContextSource = join(repoRoot, "lib/plugin-context.ts");
|
|
11
|
-
const registerCliSource = join(repoRoot, "lib/cli/register-cli.ts");
|
|
12
|
-
|
|
13
|
-
function runGetConfig(homeDir, agentId = "a1") {
|
|
14
|
-
return spawnSync("node", [getConfigScript, "--agent", agentId], {
|
|
15
|
-
env: { ...process.env, HOME: homeDir },
|
|
16
|
-
encoding: "utf8",
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
describe("json5 config smoke", () => {
|
|
21
|
-
it("accepts JSON5 openclaw.json in get-config.mjs", () => {
|
|
22
|
-
const root = mkdtempSync(join(tmpdir(), "ml-json5-ok-"));
|
|
23
|
-
const home = root;
|
|
24
|
-
const workspace = join(root, "workspace");
|
|
25
|
-
mkdirSync(join(home, ".openclaw"), { recursive: true });
|
|
26
|
-
mkdirSync(join(workspace, ".memorylake"), { recursive: true });
|
|
27
|
-
|
|
28
|
-
writeFileSync(
|
|
29
|
-
join(home, ".openclaw", "openclaw.json"),
|
|
30
|
-
`{
|
|
31
|
-
// allow comments
|
|
32
|
-
plugins: {
|
|
33
|
-
entries: {
|
|
34
|
-
"memorylake-openclaw": {
|
|
35
|
-
config: {
|
|
36
|
-
apiKey: "k",
|
|
37
|
-
projectId: "p",
|
|
38
|
-
host: "https://app.memorylake.ai",
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
agents: {
|
|
44
|
-
list: [{ id: "a1", workspace: "${workspace.replaceAll("\\", "\\\\")}" }],
|
|
45
|
-
},
|
|
46
|
-
}
|
|
47
|
-
`,
|
|
48
|
-
);
|
|
49
|
-
writeFileSync(join(workspace, ".memorylake", "config.json"), JSON.stringify({ topK: 5 }));
|
|
50
|
-
|
|
51
|
-
const result = runGetConfig(home);
|
|
52
|
-
assert.equal(result.status, 0, result.stderr);
|
|
53
|
-
const parsed = JSON.parse(result.stdout);
|
|
54
|
-
assert.equal(parsed.projectId, "p");
|
|
55
|
-
assert.equal(parsed.workspace, workspace);
|
|
56
|
-
assert.equal(parsed.topK, 5);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it("returns clear non-zero error for malformed JSON5 global config", () => {
|
|
60
|
-
const root = mkdtempSync(join(tmpdir(), "ml-json5-bad-global-"));
|
|
61
|
-
const home = root;
|
|
62
|
-
mkdirSync(join(home, ".openclaw"), { recursive: true });
|
|
63
|
-
writeFileSync(join(home, ".openclaw", "openclaw.json"), "{ invalid json5 }");
|
|
64
|
-
|
|
65
|
-
const result = runGetConfig(home);
|
|
66
|
-
assert.notEqual(result.status, 0);
|
|
67
|
-
assert.match(result.stderr, /failed to parse JSON5 config file/);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it("keeps workspace override as strict JSON", () => {
|
|
71
|
-
const root = mkdtempSync(join(tmpdir(), "ml-json5-bad-local-"));
|
|
72
|
-
const home = root;
|
|
73
|
-
const workspace = join(root, "workspace");
|
|
74
|
-
mkdirSync(join(home, ".openclaw"), { recursive: true });
|
|
75
|
-
mkdirSync(join(workspace, ".memorylake"), { recursive: true });
|
|
76
|
-
|
|
77
|
-
writeFileSync(
|
|
78
|
-
join(home, ".openclaw", "openclaw.json"),
|
|
79
|
-
JSON.stringify({
|
|
80
|
-
plugins: {
|
|
81
|
-
entries: {
|
|
82
|
-
"memorylake-openclaw": {
|
|
83
|
-
config: { apiKey: "k", projectId: "p", host: "https://app.memorylake.ai" },
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
agents: { list: [{ id: "a1", workspace }] },
|
|
88
|
-
}),
|
|
89
|
-
);
|
|
90
|
-
writeFileSync(join(workspace, ".memorylake", "config.json"), "{ trailing: 1, }");
|
|
91
|
-
|
|
92
|
-
const result = runGetConfig(home);
|
|
93
|
-
assert.notEqual(result.status, 0);
|
|
94
|
-
assert.match(result.stderr, /failed to parse workspace config/);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it("ensures plugin and CLI global config paths use shared JSON5 parser", () => {
|
|
98
|
-
const pluginContext = readFileSync(pluginContextSource, "utf8");
|
|
99
|
-
const registerCli = readFileSync(registerCliSource, "utf8");
|
|
100
|
-
|
|
101
|
-
assert.match(pluginContext, /readJson5ConfigFile\(GLOBAL_CONFIG_PATH\)/);
|
|
102
|
-
assert.match(registerCli, /readJson5ConfigFile\(openclawPath\)/);
|
|
103
|
-
});
|
|
104
|
-
});
|