@satori-sh/cli 0.0.3 → 0.0.5
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/bun.lock +195 -0
- package/dist/index.d.ts +92 -4
- package/dist/index.js +396 -42
- package/package.json +3 -3
- package/tsup.config.js +10 -0
- package/dist/add.d.ts +0 -2
- package/dist/add.d.ts.map +0 -1
- package/dist/add.js +0 -27
- package/dist/add.js.map +0 -1
- package/dist/config.d.ts +0 -3
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -15
- package/dist/config.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/memory.d.ts +0 -12
- package/dist/memory.d.ts.map +0 -1
- package/dist/memory.js +0 -42
- package/dist/memory.js.map +0 -1
- package/dist/search.d.ts +0 -2
- package/dist/search.d.ts.map +0 -1
- package/dist/search.js +0 -27
- package/dist/search.js.map +0 -1
- package/dist/src/add.d.ts +0 -23
- package/dist/src/add.d.ts.map +0 -1
- package/dist/src/add.js +0 -46
- package/dist/src/add.js.map +0 -1
- package/dist/src/config.d.ts +0 -39
- package/dist/src/config.d.ts.map +0 -1
- package/dist/src/config.js +0 -165
- package/dist/src/config.js.map +0 -1
- package/dist/src/index.d.ts +0 -15
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -142
- package/dist/src/index.js.map +0 -1
- package/dist/src/memory.d.ts +0 -52
- package/dist/src/memory.d.ts.map +0 -1
- package/dist/src/memory.js +0 -98
- package/dist/src/memory.js.map +0 -1
- package/dist/src/providers.d.ts +0 -34
- package/dist/src/providers.d.ts.map +0 -1
- package/dist/src/providers.js +0 -107
- package/dist/src/providers.js.map +0 -1
- package/dist/src/search.d.ts +0 -14
- package/dist/src/search.d.ts.map +0 -1
- package/dist/src/search.js +0 -39
- package/dist/src/search.js.map +0 -1
- package/dist/src/types.d.ts +0 -51
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/types.js +0 -2
- package/dist/src/types.js.map +0 -1
- package/dist/tests/index.test.d.ts +0 -2
- package/dist/tests/index.test.d.ts.map +0 -1
- package/dist/tests/index.test.js +0 -257
- package/dist/tests/index.test.js.map +0 -1
- package/dist/types.d.ts +0 -19
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,49 +1,403 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
#!/usr/bin/env node
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
import { readFileSync } from "fs";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
|
|
9
|
+
// src/config.ts
|
|
10
|
+
import { homedir } from "os";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
import { randomUUID } from "crypto";
|
|
13
|
+
async function checkWriteAccess() {
|
|
14
|
+
const { promises: fs } = await import("fs");
|
|
15
|
+
const dir = join(homedir(), ".config", "satori");
|
|
16
|
+
try {
|
|
17
|
+
await fs.mkdir(dir, { recursive: true });
|
|
18
|
+
const tempFile = join(dir, `temp-${randomUUID()}.txt`);
|
|
19
|
+
await fs.writeFile(tempFile, "test");
|
|
20
|
+
await fs.unlink(tempFile);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
throw new Error(`Cannot write to config directory: ${error instanceof Error ? error.message : error}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function saveApiKey(apiKey) {
|
|
26
|
+
const { promises: fs } = await import("fs");
|
|
27
|
+
await checkWriteAccess();
|
|
28
|
+
const configPath = join(homedir(), ".config", "satori", "satori.json");
|
|
29
|
+
try {
|
|
30
|
+
const existing = await loadConfigFile();
|
|
31
|
+
const config = { ...existing, api_key: apiKey };
|
|
32
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new Error(`Failed to save API key: ${error instanceof Error ? error.message : error}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function saveMemoryId(memoryId) {
|
|
38
|
+
const { promises: fs } = await import("fs");
|
|
39
|
+
await checkWriteAccess();
|
|
40
|
+
const configPath = join(homedir(), ".config", "satori", "satori.json");
|
|
41
|
+
try {
|
|
42
|
+
const existing = await loadConfigFile();
|
|
43
|
+
const config = { ...existing, memory_id: memoryId };
|
|
44
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
45
|
+
} catch (error) {
|
|
46
|
+
throw new Error(`Failed to save memory ID: ${error instanceof Error ? error.message : error}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function loadConfigFile() {
|
|
50
|
+
try {
|
|
51
|
+
const configPath = join(homedir(), ".config", "satori", "satori.json");
|
|
52
|
+
const configFile = Bun.file(configPath);
|
|
53
|
+
if (await configFile.exists()) {
|
|
54
|
+
return await configFile.json();
|
|
55
|
+
}
|
|
56
|
+
} catch {
|
|
57
|
+
}
|
|
58
|
+
return {};
|
|
59
|
+
}
|
|
60
|
+
async function getConfig() {
|
|
61
|
+
if (process.platform !== "darwin") {
|
|
62
|
+
throw new Error("We do not currently support Windows yet, email support@satori.sh to request Windows support");
|
|
63
|
+
}
|
|
64
|
+
let apiKey = null;
|
|
65
|
+
let memoryId = void 0;
|
|
66
|
+
try {
|
|
67
|
+
const configPath = join(homedir(), ".config", "satori", "satori.json");
|
|
68
|
+
const configFile = Bun.file(configPath);
|
|
69
|
+
if (await configFile.exists()) {
|
|
70
|
+
const data = await configFile.json();
|
|
71
|
+
if (data && typeof data.api_key === "string") {
|
|
72
|
+
apiKey = data.api_key;
|
|
73
|
+
}
|
|
74
|
+
if (data && typeof data.memory_id === "string") {
|
|
75
|
+
memoryId = data.memory_id;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
}
|
|
80
|
+
if (!apiKey) {
|
|
81
|
+
apiKey = process.env.SATORI_API_KEY || null;
|
|
82
|
+
}
|
|
83
|
+
const baseUrl = process.env.SATORI_BASE_URL || "https://api.satori.sh";
|
|
84
|
+
try {
|
|
85
|
+
new URL(baseUrl);
|
|
86
|
+
} catch {
|
|
87
|
+
throw new Error("Invalid SATORI_BASE_URL format");
|
|
88
|
+
}
|
|
89
|
+
if (!apiKey) {
|
|
9
90
|
try {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
91
|
+
const response = await fetch(`${baseUrl}/orgs`, {
|
|
92
|
+
method: "POST"
|
|
93
|
+
});
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
throw new Error(`HTTP error: ${response.status} ${response.statusText}`);
|
|
96
|
+
}
|
|
97
|
+
const data = await response.json();
|
|
98
|
+
if (data && typeof data.api_key === "string") {
|
|
99
|
+
apiKey = data.api_key;
|
|
100
|
+
await saveApiKey(apiKey);
|
|
101
|
+
} else {
|
|
102
|
+
throw new Error("Invalid response: missing api_key");
|
|
103
|
+
}
|
|
104
|
+
} catch (error) {
|
|
105
|
+
throw new Error(`Failed to generate API key: ${error instanceof Error ? error.message : error}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const provider = process.env.SATORI_PROVIDER || "openai";
|
|
109
|
+
const model = process.env.SATORI_MODEL || "gpt-4o";
|
|
110
|
+
const openaiKey = process.env.OPENAI_API_KEY;
|
|
111
|
+
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
112
|
+
if (!memoryId) {
|
|
113
|
+
memoryId = process.env.SATORI_MEMORY_ID;
|
|
114
|
+
}
|
|
115
|
+
return { apiKey, baseUrl, provider, model, openaiKey, anthropicKey, memoryId };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/search.ts
|
|
119
|
+
async function searchMemories(query) {
|
|
120
|
+
if (!query || !query.trim()) {
|
|
121
|
+
console.error("Query cannot be empty");
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const config = await getConfig();
|
|
126
|
+
const response = await fetch(`${config.baseUrl}/search`, {
|
|
127
|
+
method: "POST",
|
|
128
|
+
headers: {
|
|
129
|
+
"Content-Type": "application/json",
|
|
130
|
+
"Authorization": `Bearer ${config.apiKey}`
|
|
131
|
+
},
|
|
132
|
+
body: JSON.stringify({ query })
|
|
133
|
+
});
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
console.error(`HTTP error: ${response.status} ${response.statusText}`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
await response.json();
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error(`Error searching memories: ${error instanceof Error ? error.message : error}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/add.ts
|
|
145
|
+
async function addMemories(text, options = {}) {
|
|
146
|
+
if (!text || !text.trim()) {
|
|
147
|
+
console.error("Text cannot be empty");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const config = await getConfig();
|
|
152
|
+
const response = await fetch(`${config.baseUrl}/memories`, {
|
|
153
|
+
method: "POST",
|
|
154
|
+
headers: {
|
|
155
|
+
"Content-Type": "application/json",
|
|
156
|
+
"Authorization": `Bearer ${config.apiKey}`
|
|
157
|
+
},
|
|
158
|
+
body: JSON.stringify({ messages: [{ role: "user", content: text }], ...options.memoryId && { memory_id: options.memoryId } })
|
|
25
159
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
160
|
+
if (!response.ok) {
|
|
161
|
+
console.error(`HTTP error: ${response.status} ${response.statusText}`);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
await response.json();
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error(`Error adding memory: ${error instanceof Error ? error.message : error}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// src/memory.ts
|
|
171
|
+
import { generate } from "random-words";
|
|
172
|
+
async function buildMemoryContext(prompt, options = {}) {
|
|
173
|
+
const config = await getConfig();
|
|
174
|
+
let memoryId;
|
|
175
|
+
let generated = false;
|
|
176
|
+
if (options.memoryId) {
|
|
177
|
+
memoryId = options.memoryId;
|
|
178
|
+
} else if (process.env.SATORI_MEMORY_ID) {
|
|
179
|
+
memoryId = process.env.SATORI_MEMORY_ID;
|
|
180
|
+
} else if (config.memoryId) {
|
|
181
|
+
memoryId = config.memoryId;
|
|
182
|
+
} else {
|
|
183
|
+
const words = generate({ exactly: 3 });
|
|
184
|
+
memoryId = words.join("-");
|
|
185
|
+
generated = true;
|
|
186
|
+
}
|
|
187
|
+
const topK = options.topK || 5;
|
|
188
|
+
const url = `${config.baseUrl}/search`;
|
|
189
|
+
const headers = {
|
|
190
|
+
"Content-Type": "application/json",
|
|
191
|
+
"Authorization": `Bearer ${config.apiKey}`
|
|
192
|
+
};
|
|
193
|
+
const body = JSON.stringify({
|
|
194
|
+
query: prompt,
|
|
195
|
+
memory_id: memoryId,
|
|
196
|
+
top_k: topK
|
|
197
|
+
});
|
|
198
|
+
const response = await fetch(url, {
|
|
199
|
+
method: "POST",
|
|
200
|
+
headers,
|
|
201
|
+
body
|
|
202
|
+
});
|
|
203
|
+
if (!response.ok) {
|
|
204
|
+
throw new Error(`HTTP error: ${response.status} ${response.statusText}`);
|
|
205
|
+
}
|
|
206
|
+
const data = await response.json();
|
|
207
|
+
const instruction = generated ? `Memory session id: ${memoryId}.` : void 0;
|
|
208
|
+
if (generated) {
|
|
209
|
+
saveMemoryId(memoryId).catch((err) => {
|
|
210
|
+
console.error("Failed to save memory ID:", err);
|
|
32
211
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
results: data.results,
|
|
215
|
+
memoryId,
|
|
216
|
+
instruction
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function enhanceMessagesWithMemory(messages, memoryContext) {
|
|
220
|
+
const validResults = memoryContext.results.filter((r) => r.memory && r.memory.trim() !== "" && r.memory !== "undefined");
|
|
221
|
+
if (validResults.length === 0) {
|
|
222
|
+
return messages;
|
|
223
|
+
}
|
|
224
|
+
const memoryText = validResults.map((r) => r.memory).join("\n");
|
|
225
|
+
const systemMessage = {
|
|
226
|
+
role: "system",
|
|
227
|
+
content: `Relevant context from memory:
|
|
228
|
+
${memoryText}`
|
|
229
|
+
};
|
|
230
|
+
return [systemMessage, ...messages];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// src/providers.ts
|
|
234
|
+
async function _callOpenAI(messages, options) {
|
|
235
|
+
const config = await getConfig();
|
|
236
|
+
const apiKey = config.openaiKey;
|
|
237
|
+
if (!apiKey) {
|
|
238
|
+
throw new Error("Missing API key for OPENAI_API_KEY");
|
|
239
|
+
}
|
|
240
|
+
const url = "https://api.openai.com/v1/chat/completions";
|
|
241
|
+
const body = {
|
|
242
|
+
model: config.model,
|
|
243
|
+
messages,
|
|
244
|
+
temperature: options.temperature ?? 0.7,
|
|
245
|
+
max_tokens: options.maxTokens ?? 1e3,
|
|
246
|
+
stream: options.stream ?? false
|
|
247
|
+
};
|
|
248
|
+
const headers = {
|
|
249
|
+
"Content-Type": "application/json",
|
|
250
|
+
"Authorization": `Bearer ${apiKey}`
|
|
251
|
+
};
|
|
252
|
+
const response = await fetch(url, {
|
|
253
|
+
method: "POST",
|
|
254
|
+
headers,
|
|
255
|
+
body: JSON.stringify(body)
|
|
256
|
+
});
|
|
257
|
+
if (!response.ok) {
|
|
258
|
+
throw new Error(`OpenAI API error: ${response.status} ${response.statusText}`);
|
|
259
|
+
}
|
|
260
|
+
const data = await response.json();
|
|
261
|
+
return data.choices[0].message.content;
|
|
262
|
+
}
|
|
263
|
+
async function _callAnthropic(messages, options) {
|
|
264
|
+
const config = await getConfig();
|
|
265
|
+
const apiKey = config.anthropicKey;
|
|
266
|
+
if (!apiKey) {
|
|
267
|
+
throw new Error("Missing API key for ANTHROPIC_API_KEY");
|
|
268
|
+
}
|
|
269
|
+
const url = "https://api.anthropic.com/v1/messages";
|
|
270
|
+
const body = {
|
|
271
|
+
model: config.model,
|
|
272
|
+
messages,
|
|
273
|
+
temperature: options.temperature ?? 0.7,
|
|
274
|
+
max_tokens: options.maxTokens ?? 1e3,
|
|
275
|
+
stream: options.stream ?? false
|
|
276
|
+
};
|
|
277
|
+
const headers = {
|
|
278
|
+
"Content-Type": "application/json",
|
|
279
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
280
|
+
"anthropic-version": "2023-06-01"
|
|
281
|
+
};
|
|
282
|
+
const response = await fetch(url, {
|
|
283
|
+
method: "POST",
|
|
284
|
+
headers,
|
|
285
|
+
body: JSON.stringify(body)
|
|
286
|
+
});
|
|
287
|
+
if (!response.ok) {
|
|
288
|
+
throw new Error(`Anthropic API error: ${response.status} ${response.statusText}`);
|
|
289
|
+
}
|
|
290
|
+
const data = await response.json();
|
|
291
|
+
return data.content[0].text;
|
|
292
|
+
}
|
|
293
|
+
async function _callProviderAPI(messages, options, provider) {
|
|
294
|
+
if (provider === "openai") {
|
|
295
|
+
return _callOpenAI(messages, options);
|
|
296
|
+
} else if (provider === "anthropic") {
|
|
297
|
+
return _callAnthropic(messages, options);
|
|
298
|
+
} else {
|
|
299
|
+
throw new Error(`Unsupported provider: ${provider}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// src/index.ts
|
|
304
|
+
async function main() {
|
|
305
|
+
try {
|
|
306
|
+
await getConfig();
|
|
307
|
+
} catch (error) {
|
|
308
|
+
console.error(error instanceof Error ? error.message : "Configuration error");
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
console.log(chalk.cyan(readFileSync("./logo.txt", "utf8")));
|
|
312
|
+
const program = new Command();
|
|
313
|
+
program.name("satori").description("CLI tool for Satori memory server").version("0.0.1");
|
|
314
|
+
program.option("--provider <provider>", "Provider to use (openai or anthropic)", "openai").option("--model <model>", "Model to use", "gpt-4o").option("--memory-id <id>", "Memory ID for scoping");
|
|
315
|
+
const processUserInput = async (input, options, isInteractive = false) => {
|
|
316
|
+
let memoryContext;
|
|
317
|
+
try {
|
|
318
|
+
memoryContext = await buildMemoryContext(input, { memoryId: options.memoryId });
|
|
319
|
+
} catch (memoryError) {
|
|
320
|
+
memoryContext = { results: [], memoryId: options.memoryId, instruction: void 0 };
|
|
321
|
+
}
|
|
322
|
+
const userMessage = { role: "user", content: input };
|
|
323
|
+
const enhancedMessages = enhanceMessagesWithMemory([userMessage], { results: memoryContext.results });
|
|
324
|
+
const response = await _callProviderAPI(enhancedMessages, {
|
|
325
|
+
temperature: 0.7,
|
|
326
|
+
maxTokens: 1e3
|
|
327
|
+
}, options.provider);
|
|
328
|
+
if (isInteractive) {
|
|
329
|
+
console.log(`Assistant: ${response}`);
|
|
330
|
+
} else {
|
|
331
|
+
console.log(response);
|
|
332
|
+
}
|
|
333
|
+
if (memoryContext.instruction) {
|
|
334
|
+
console.log(`
|
|
335
|
+
${memoryContext.instruction}`);
|
|
336
|
+
}
|
|
337
|
+
addMemories(input, { memoryId: memoryContext.memoryId }).catch((err) => {
|
|
338
|
+
console.error("Failed to save memory:", err);
|
|
43
339
|
});
|
|
44
|
-
|
|
340
|
+
return { response, instruction: memoryContext.instruction, memoryId: memoryContext.memoryId };
|
|
341
|
+
};
|
|
342
|
+
program.argument("[prompt]", "initial prompt for chat session (optional)").action(async (initialPrompt, options) => {
|
|
343
|
+
try {
|
|
344
|
+
let memoryId = options.memoryId;
|
|
345
|
+
if (!process.stdin.isTTY) {
|
|
346
|
+
if (initialPrompt) {
|
|
347
|
+
await processUserInput(initialPrompt, options, false);
|
|
348
|
+
}
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (initialPrompt) {
|
|
352
|
+
const result = await processUserInput(initialPrompt, options, true);
|
|
353
|
+
memoryId = result.memoryId;
|
|
354
|
+
}
|
|
355
|
+
const { createInterface } = await import("readline");
|
|
356
|
+
const rl = createInterface({
|
|
357
|
+
input: process.stdin,
|
|
358
|
+
output: process.stdout
|
|
359
|
+
});
|
|
360
|
+
const chatLoop = async () => {
|
|
361
|
+
rl.question(chalk.cyan("> "), async (input) => {
|
|
362
|
+
if (input.toLowerCase() === "exit" || input.toLowerCase() === "quit") {
|
|
363
|
+
console.log("Goodbye!");
|
|
364
|
+
rl.close();
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (!input.trim()) {
|
|
368
|
+
chatLoop();
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
try {
|
|
372
|
+
const result = await processUserInput(input, { ...options, memoryId }, true);
|
|
373
|
+
memoryId = result.memoryId;
|
|
374
|
+
} catch (error) {
|
|
375
|
+
console.error("Chat error:", error instanceof Error ? error.message : error);
|
|
376
|
+
}
|
|
377
|
+
chatLoop();
|
|
378
|
+
});
|
|
379
|
+
};
|
|
380
|
+
console.log('\nEntering interactive mode. Type "exit" or "quit" to end the session.\n');
|
|
381
|
+
chatLoop();
|
|
382
|
+
} catch (error) {
|
|
383
|
+
console.error("Chat error:", error instanceof Error ? error.message : error);
|
|
384
|
+
process.exit(1);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
program.command("add").description("add a new memory").argument("<text>", "text to add as memory").action(async (text) => {
|
|
388
|
+
await addMemories(text);
|
|
389
|
+
});
|
|
390
|
+
program.command("search").description("search memories").argument("<query>", "search query for memories").action(async (query) => {
|
|
391
|
+
await searchMemories(query);
|
|
392
|
+
});
|
|
393
|
+
program.parse();
|
|
45
394
|
}
|
|
46
395
|
if (import.meta.main) {
|
|
47
|
-
|
|
396
|
+
main();
|
|
48
397
|
}
|
|
49
|
-
|
|
398
|
+
export {
|
|
399
|
+
addMemories,
|
|
400
|
+
enhanceMessagesWithMemory,
|
|
401
|
+
main,
|
|
402
|
+
searchMemories
|
|
403
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@satori-sh/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "CLI tool for Satori memory server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"satori": "./dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"build": "
|
|
11
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
12
12
|
"test": "bun test",
|
|
13
13
|
"lint": "tsc --noEmit"
|
|
14
14
|
},
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/bun": "^1.3.3",
|
|
22
22
|
"@types/node": "^24.10.1",
|
|
23
|
+
"tsup": "^8.5.1",
|
|
23
24
|
"typescript": "^5.9.3"
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
|
-
|
package/tsup.config.js
ADDED
package/dist/add.d.ts
DELETED
package/dist/add.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../src/add.ts"],"names":[],"mappings":"AAGA,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B7D"}
|
package/dist/add.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { getConfig } from './config.js';
|
|
2
|
-
export async function addMemories(text) {
|
|
3
|
-
if (!text || !text.trim()) {
|
|
4
|
-
console.error('Text cannot be empty');
|
|
5
|
-
return;
|
|
6
|
-
}
|
|
7
|
-
try {
|
|
8
|
-
const config = getConfig();
|
|
9
|
-
const response = await fetch(`${config.baseUrl}/memories`, {
|
|
10
|
-
method: 'POST',
|
|
11
|
-
headers: {
|
|
12
|
-
'Content-Type': 'application/json',
|
|
13
|
-
'Authorization': `Bearer ${config.apiKey}`
|
|
14
|
-
},
|
|
15
|
-
body: JSON.stringify({ messages: [{ role: "user", content: text }] })
|
|
16
|
-
});
|
|
17
|
-
if (!response.ok) {
|
|
18
|
-
console.error(`HTTP error: ${response.status} ${response.statusText}`);
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
await response.json();
|
|
22
|
-
}
|
|
23
|
-
catch (error) {
|
|
24
|
-
console.error(`Error adding memory: ${error instanceof Error ? error.message : error}`);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=add.js.map
|
package/dist/add.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"add.js","sourceRoot":"","sources":["../src/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxC,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY;IAC5C,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACtC,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,WAAW,EAAE;YACzD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE;aAC3C;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;SACtE,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,eAAe,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YACvE,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,CAAC,IAAI,EAAiB,CAAC;IACvC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,wBAAwB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC"}
|
package/dist/config.d.ts
DELETED
package/dist/config.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,wBAAgB,SAAS,IAAI,MAAM,CAelC"}
|
package/dist/config.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export function getConfig() {
|
|
2
|
-
const apiKey = process.env.SATORI_API_KEY;
|
|
3
|
-
const baseUrl = process.env.SATORI_BASE_URL || 'http://localhost:8000';
|
|
4
|
-
if (!apiKey) {
|
|
5
|
-
throw new Error('Missing SATORI_API_KEY environment variable');
|
|
6
|
-
}
|
|
7
|
-
try {
|
|
8
|
-
new URL(baseUrl);
|
|
9
|
-
}
|
|
10
|
-
catch {
|
|
11
|
-
throw new Error('Invalid SATORI_BASE_URL format');
|
|
12
|
-
}
|
|
13
|
-
return { apiKey, baseUrl };
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS;IACvB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,uBAAuB,CAAC;IAEvE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IAED,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC"}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,wBAAsB,IAAI,kBA0CzB"}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,6BAA6B;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,CAAC,KAAK,UAAU,IAAI;IACxB,IAAI,CAAC;QACH,SAAS,EAAE,CAAC,CAAC,iBAAiB;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,QAAQ,CAAC;SACd,WAAW,CAAC,mCAAmC,CAAC;SAChD,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpB,OAAO;SACJ,QAAQ,CAAC,SAAS,EAAE,2BAA2B,CAAC;SAChD,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,EAAE;QAC9B,MAAM,cAAc,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,kBAAkB,CAAC;SAC/B,QAAQ,CAAC,QAAQ,EAAE,uBAAuB,CAAC;SAC3C,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAC7B,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,sBAAsB,CAAC;SACnC,MAAM,CAAC,uBAAuB,EAAE,uCAAuC,EAAE,QAAQ,CAAC;SAClF,MAAM,CAAC,iBAAiB,EAAE,cAAc,EAAE,QAAQ,CAAC;SACnD,MAAM,CAAC,kBAAkB,EAAE,uBAAuB,CAAC;SACnD,MAAM,CAAC,aAAa,EAAE,mBAAmB,CAAC;SAC1C,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACxB,6BAA6B;QAC7B,OAAO,CAAC,GAAG,CAAC,oCAAoC,EAAE,OAAO,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEL,OAAO,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC;AAED,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACrB,IAAI,EAAE,CAAC;AACT,CAAC"}
|
package/dist/memory.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { SearchResponse } from './types.js';
|
|
2
|
-
interface MemoryOptions {
|
|
3
|
-
memoryId?: string;
|
|
4
|
-
topK?: number;
|
|
5
|
-
}
|
|
6
|
-
export declare function buildMemoryContext(prompt: string, options?: MemoryOptions): Promise<{
|
|
7
|
-
results: SearchResponse['results'];
|
|
8
|
-
memoryId: string;
|
|
9
|
-
instruction?: string;
|
|
10
|
-
}>;
|
|
11
|
-
export {};
|
|
12
|
-
//# sourceMappingURL=memory.d.ts.map
|
package/dist/memory.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5C,UAAU,aAAa;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA2C7K"}
|
package/dist/memory.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { getConfig } from './config.js';
|
|
2
|
-
import { generate } from 'random-words';
|
|
3
|
-
export async function buildMemoryContext(prompt, options = {}) {
|
|
4
|
-
let memoryId;
|
|
5
|
-
let generated = false;
|
|
6
|
-
if (options.memoryId) {
|
|
7
|
-
memoryId = options.memoryId;
|
|
8
|
-
}
|
|
9
|
-
else if (process.env.SATORI_MEMORY_ID) {
|
|
10
|
-
memoryId = process.env.SATORI_MEMORY_ID;
|
|
11
|
-
}
|
|
12
|
-
else {
|
|
13
|
-
const words = generate({ exactly: 3 });
|
|
14
|
-
memoryId = words.join('-');
|
|
15
|
-
generated = true;
|
|
16
|
-
}
|
|
17
|
-
const topK = options.topK || 5;
|
|
18
|
-
const config = getConfig();
|
|
19
|
-
const response = await fetch(`${config.baseUrl}/search`, {
|
|
20
|
-
method: 'POST',
|
|
21
|
-
headers: {
|
|
22
|
-
'Content-Type': 'application/json',
|
|
23
|
-
'Authorization': `Bearer ${config.apiKey}`
|
|
24
|
-
},
|
|
25
|
-
body: JSON.stringify({
|
|
26
|
-
query: prompt,
|
|
27
|
-
memory_id: memoryId,
|
|
28
|
-
top_k: topK
|
|
29
|
-
})
|
|
30
|
-
});
|
|
31
|
-
if (!response.ok) {
|
|
32
|
-
throw new Error(`HTTP error: ${response.status} ${response.statusText}`);
|
|
33
|
-
}
|
|
34
|
-
const data = await response.json();
|
|
35
|
-
const instruction = generated ? `Set SATORI_MEMORY_ID=${memoryId} to reuse this session.` : undefined;
|
|
36
|
-
return {
|
|
37
|
-
results: data.results,
|
|
38
|
-
memoryId,
|
|
39
|
-
instruction
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
//# sourceMappingURL=memory.js.map
|
package/dist/memory.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAOxC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,UAAyB,EAAE;IAClF,IAAI,QAAgB,CAAC;IACrB,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAC9B,CAAC;SAAM,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACxC,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC1C,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAa,CAAC;QACnD,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3B,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;IAE/B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,SAAS,EAAE;QACvD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,eAAe,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE;SAC3C;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,KAAK,EAAE,MAAM;YACb,SAAS,EAAE,QAAQ;YACnB,KAAK,EAAE,IAAI;SACZ,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAoB,CAAC;IAErD,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,wBAAwB,QAAQ,yBAAyB,CAAC,CAAC,CAAC,SAAS,CAAC;IAEtG,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,QAAQ;QACR,WAAW;KACZ,CAAC;AACJ,CAAC"}
|
package/dist/search.d.ts
DELETED
package/dist/search.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAGA,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BjE"}
|
package/dist/search.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { getConfig } from './config.js';
|
|
2
|
-
export async function searchMemories(query) {
|
|
3
|
-
if (!query || !query.trim()) {
|
|
4
|
-
console.error('Query cannot be empty');
|
|
5
|
-
return;
|
|
6
|
-
}
|
|
7
|
-
try {
|
|
8
|
-
const config = getConfig();
|
|
9
|
-
const response = await fetch(`${config.baseUrl}/search`, {
|
|
10
|
-
method: 'POST',
|
|
11
|
-
headers: {
|
|
12
|
-
'Content-Type': 'application/json',
|
|
13
|
-
'Authorization': `Bearer ${config.apiKey}`
|
|
14
|
-
},
|
|
15
|
-
body: JSON.stringify({ query })
|
|
16
|
-
});
|
|
17
|
-
if (!response.ok) {
|
|
18
|
-
console.error(`HTTP error: ${response.status} ${response.statusText}`);
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
await response.json();
|
|
22
|
-
}
|
|
23
|
-
catch (error) {
|
|
24
|
-
console.error(`Error searching memories: ${error instanceof Error ? error.message : error}`);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=search.js.map
|
package/dist/search.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxC,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAa;IAChD,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACvC,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,SAAS,EAAE;YACvD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE;aAC3C;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC;SAChC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,eAAe,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YACvE,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,CAAC,IAAI,EAAoB,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,6BAA6B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/F,CAAC;AACH,CAAC"}
|