@hasna/brains 0.0.5 → 0.0.7
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 +190 -0
- package/dist/cli/index.js +1328 -916
- package/dist/db/index.d.ts.map +1 -1
- package/dist/index.js +4315 -132
- package/dist/lib/config.d.ts +11 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/gatherers/index.d.ts +1 -0
- package/dist/lib/gatherers/index.d.ts.map +1 -1
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/package-metadata.d.ts +2 -0
- package/dist/lib/package-metadata.d.ts.map +1 -0
- package/dist/lib/providers/openai.d.ts +2 -0
- package/dist/lib/providers/openai.d.ts.map +1 -1
- package/dist/lib/providers/thinker-labs.d.ts +1 -0
- package/dist/lib/providers/thinker-labs.d.ts.map +1 -1
- package/dist/lib/retry.d.ts +7 -0
- package/dist/lib/retry.d.ts.map +1 -0
- package/dist/lib/schemas.d.ts +87 -0
- package/dist/lib/schemas.d.ts.map +1 -0
- package/dist/mcp/index.d.ts +74 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +4879 -441
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +4309 -9
- package/drizzle/0000_foamy_daimon_hellstrom.sql +36 -0
- package/drizzle/meta/0000_snapshot.json +259 -0
- package/drizzle/meta/_journal.json +13 -0
- package/package.json +6 -2
package/dist/cli/index.js
CHANGED
|
@@ -26,6 +26,7 @@ var __export = (target, all) => {
|
|
|
26
26
|
set: (newValue) => all[name] = () => newValue
|
|
27
27
|
});
|
|
28
28
|
};
|
|
29
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
29
30
|
var __require = import.meta.require;
|
|
30
31
|
|
|
31
32
|
// node_modules/commander/lib/error.js
|
|
@@ -2062,6 +2063,352 @@ var require_commander = __commonJS((exports) => {
|
|
|
2062
2063
|
exports.InvalidOptionArgumentError = InvalidArgumentError;
|
|
2063
2064
|
});
|
|
2064
2065
|
|
|
2066
|
+
// src/lib/gatherers/todos.ts
|
|
2067
|
+
var exports_todos = {};
|
|
2068
|
+
__export(exports_todos, {
|
|
2069
|
+
gatherFromTodos: () => gatherFromTodos
|
|
2070
|
+
});
|
|
2071
|
+
import { Database as Database3 } from "bun:sqlite";
|
|
2072
|
+
import { homedir as homedir3 } from "os";
|
|
2073
|
+
import { join as join3 } from "path";
|
|
2074
|
+
function taskToCreateExample(task) {
|
|
2075
|
+
const userMsg = `Create a task: ${task.title}${task.description ? `
|
|
2076
|
+
|
|
2077
|
+
Description: ${task.description}` : ""}`;
|
|
2078
|
+
const taskDetails = {
|
|
2079
|
+
id: task.short_id ?? task.id,
|
|
2080
|
+
title: task.title,
|
|
2081
|
+
description: task.description ?? "",
|
|
2082
|
+
status: task.status,
|
|
2083
|
+
priority: task.priority,
|
|
2084
|
+
tags: JSON.parse(task.tags ?? "[]"),
|
|
2085
|
+
created_at: task.created_at
|
|
2086
|
+
};
|
|
2087
|
+
return {
|
|
2088
|
+
messages: [
|
|
2089
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
2090
|
+
{ role: "user", content: userMsg },
|
|
2091
|
+
{ role: "assistant", content: `Created task: ${JSON.stringify(taskDetails, null, 2)}` }
|
|
2092
|
+
]
|
|
2093
|
+
};
|
|
2094
|
+
}
|
|
2095
|
+
function taskToStatusUpdateExample(task) {
|
|
2096
|
+
if (!task.completed_at && task.status === "pending")
|
|
2097
|
+
return null;
|
|
2098
|
+
const id = task.short_id ?? task.id;
|
|
2099
|
+
return {
|
|
2100
|
+
messages: [
|
|
2101
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
2102
|
+
{ role: "user", content: `Mark task ${id} as ${task.status}` },
|
|
2103
|
+
{ role: "assistant", content: `Task ${id} has been updated to status: ${task.status}. ${task.completed_at ? `Completed at: ${task.completed_at}` : ""}`.trim() }
|
|
2104
|
+
]
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
function taskToSearchExample(tasks, query) {
|
|
2108
|
+
const matched = tasks.filter((t) => t.title.toLowerCase().includes(query.toLowerCase())).slice(0, 5);
|
|
2109
|
+
return {
|
|
2110
|
+
messages: [
|
|
2111
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
2112
|
+
{ role: "user", content: `Search tasks for: "${query}"` },
|
|
2113
|
+
{
|
|
2114
|
+
role: "assistant",
|
|
2115
|
+
content: matched.length > 0 ? `Found ${matched.length} task(s):
|
|
2116
|
+
${matched.map((t) => `- [${t.short_id ?? t.id}] ${t.title} (${t.status})`).join(`
|
|
2117
|
+
`)}` : `No tasks found matching "${query}".`
|
|
2118
|
+
}
|
|
2119
|
+
]
|
|
2120
|
+
};
|
|
2121
|
+
}
|
|
2122
|
+
async function gatherFromTodos(options = {}) {
|
|
2123
|
+
const dbPath = join3(homedir3(), ".todos", "todos.db");
|
|
2124
|
+
const db = new Database3(dbPath, { readonly: true, create: false });
|
|
2125
|
+
try {
|
|
2126
|
+
let query = "SELECT * FROM tasks WHERE 1=1";
|
|
2127
|
+
const params = [];
|
|
2128
|
+
if (options.since) {
|
|
2129
|
+
query += " AND created_at >= ?";
|
|
2130
|
+
params.push(options.since.toISOString());
|
|
2131
|
+
}
|
|
2132
|
+
query += " ORDER BY created_at DESC";
|
|
2133
|
+
if (options.limit) {
|
|
2134
|
+
query += " LIMIT ?";
|
|
2135
|
+
params.push(options.limit * 2);
|
|
2136
|
+
}
|
|
2137
|
+
const tasks = db.query(query).all(...params);
|
|
2138
|
+
const examples = [];
|
|
2139
|
+
for (const task of tasks) {
|
|
2140
|
+
examples.push(taskToCreateExample(task));
|
|
2141
|
+
const statusEx = taskToStatusUpdateExample(task);
|
|
2142
|
+
if (statusEx)
|
|
2143
|
+
examples.push(statusEx);
|
|
2144
|
+
}
|
|
2145
|
+
const searchTerms = ["urgent", "fix", "implement", "create", "update", "review"];
|
|
2146
|
+
for (const term of searchTerms) {
|
|
2147
|
+
examples.push(taskToSearchExample(tasks, term));
|
|
2148
|
+
}
|
|
2149
|
+
const finalExamples = options.limit ? examples.slice(0, options.limit) : examples;
|
|
2150
|
+
return {
|
|
2151
|
+
source: "todos",
|
|
2152
|
+
examples: finalExamples,
|
|
2153
|
+
count: finalExamples.length
|
|
2154
|
+
};
|
|
2155
|
+
} finally {
|
|
2156
|
+
db.close();
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
var SYSTEM_PROMPT = "You are a task management assistant that helps users create, update, search, and manage tasks and projects.";
|
|
2160
|
+
var init_todos = () => {};
|
|
2161
|
+
|
|
2162
|
+
// src/lib/gatherers/mementos.ts
|
|
2163
|
+
var exports_mementos = {};
|
|
2164
|
+
__export(exports_mementos, {
|
|
2165
|
+
gatherFromMementos: () => gatherFromMementos
|
|
2166
|
+
});
|
|
2167
|
+
import { Database as Database4 } from "bun:sqlite";
|
|
2168
|
+
import { homedir as homedir4 } from "os";
|
|
2169
|
+
import { join as join4 } from "path";
|
|
2170
|
+
function memoryToRecallExample(memory) {
|
|
2171
|
+
return {
|
|
2172
|
+
messages: [
|
|
2173
|
+
{ role: "system", content: SYSTEM_PROMPT2 },
|
|
2174
|
+
{ role: "user", content: `What do you remember about "${memory.key}"?` },
|
|
2175
|
+
{
|
|
2176
|
+
role: "assistant",
|
|
2177
|
+
content: memory.summary ? `${memory.value}
|
|
2178
|
+
|
|
2179
|
+
Summary: ${memory.summary}` : memory.value
|
|
2180
|
+
}
|
|
2181
|
+
]
|
|
2182
|
+
};
|
|
2183
|
+
}
|
|
2184
|
+
function memoryToSaveExample(memory) {
|
|
2185
|
+
const tags = JSON.parse(memory.tags ?? "[]");
|
|
2186
|
+
return {
|
|
2187
|
+
messages: [
|
|
2188
|
+
{ role: "system", content: SYSTEM_PROMPT2 },
|
|
2189
|
+
{
|
|
2190
|
+
role: "user",
|
|
2191
|
+
content: `Remember this for me: ${memory.key} = ${memory.value}${tags.length ? ` (tags: ${tags.join(", ")})` : ""}`
|
|
2192
|
+
},
|
|
2193
|
+
{
|
|
2194
|
+
role: "assistant",
|
|
2195
|
+
content: `Saved to memory: "${memory.key}" with ${memory.category} category, importance ${memory.importance}/10, scope: ${memory.scope}.`
|
|
2196
|
+
}
|
|
2197
|
+
]
|
|
2198
|
+
};
|
|
2199
|
+
}
|
|
2200
|
+
function memoryToSearchExample(memories, category) {
|
|
2201
|
+
const matched = memories.filter((m) => m.category === category && m.status === "active").slice(0, 5);
|
|
2202
|
+
return {
|
|
2203
|
+
messages: [
|
|
2204
|
+
{ role: "system", content: SYSTEM_PROMPT2 },
|
|
2205
|
+
{ role: "user", content: `What ${category} memories do you have?` },
|
|
2206
|
+
{
|
|
2207
|
+
role: "assistant",
|
|
2208
|
+
content: matched.length > 0 ? `Here are my ${category} memories:
|
|
2209
|
+
${matched.map((m) => `- ${m.key}: ${m.value.slice(0, 120)}${m.value.length > 120 ? "..." : ""}`).join(`
|
|
2210
|
+
`)}` : `I don't have any ${category} memories stored yet.`
|
|
2211
|
+
}
|
|
2212
|
+
]
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
async function gatherFromMementos(options = {}) {
|
|
2216
|
+
const dbPath = join4(homedir4(), ".mementos", "mementos.db");
|
|
2217
|
+
const db = new Database4(dbPath, { readonly: true, create: false });
|
|
2218
|
+
try {
|
|
2219
|
+
let query = "SELECT * FROM memories WHERE status = 'active'";
|
|
2220
|
+
const params = [];
|
|
2221
|
+
if (options.since) {
|
|
2222
|
+
query += " AND created_at >= ?";
|
|
2223
|
+
params.push(options.since.toISOString());
|
|
2224
|
+
}
|
|
2225
|
+
query += " ORDER BY importance DESC, created_at DESC";
|
|
2226
|
+
if (options.limit) {
|
|
2227
|
+
query += " LIMIT ?";
|
|
2228
|
+
params.push(options.limit * 3);
|
|
2229
|
+
}
|
|
2230
|
+
const memories = db.query(query).all(...params);
|
|
2231
|
+
const examples = [];
|
|
2232
|
+
for (const memory of memories) {
|
|
2233
|
+
examples.push(memoryToRecallExample(memory));
|
|
2234
|
+
examples.push(memoryToSaveExample(memory));
|
|
2235
|
+
}
|
|
2236
|
+
const categories = [...new Set(memories.map((m) => m.category))];
|
|
2237
|
+
for (const category of categories) {
|
|
2238
|
+
examples.push(memoryToSearchExample(memories, category));
|
|
2239
|
+
}
|
|
2240
|
+
const finalExamples = options.limit ? examples.slice(0, options.limit) : examples;
|
|
2241
|
+
return {
|
|
2242
|
+
source: "mementos",
|
|
2243
|
+
examples: finalExamples,
|
|
2244
|
+
count: finalExamples.length
|
|
2245
|
+
};
|
|
2246
|
+
} finally {
|
|
2247
|
+
db.close();
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
var SYSTEM_PROMPT2 = "You are an AI assistant with persistent memory. You can remember and recall information across sessions to provide better, more personalized assistance.";
|
|
2251
|
+
var init_mementos = () => {};
|
|
2252
|
+
|
|
2253
|
+
// src/lib/gatherers/conversations.ts
|
|
2254
|
+
var exports_conversations = {};
|
|
2255
|
+
__export(exports_conversations, {
|
|
2256
|
+
gatherFromConversations: () => gatherFromConversations
|
|
2257
|
+
});
|
|
2258
|
+
import { Database as Database5 } from "bun:sqlite";
|
|
2259
|
+
import { homedir as homedir5 } from "os";
|
|
2260
|
+
import { join as join5 } from "path";
|
|
2261
|
+
function windowToExample(window2) {
|
|
2262
|
+
if (window2.length < 2)
|
|
2263
|
+
return null;
|
|
2264
|
+
const messages = [
|
|
2265
|
+
{ role: "system", content: SYSTEM_PROMPT3 }
|
|
2266
|
+
];
|
|
2267
|
+
for (let i = 0;i < window2.length - 1; i++) {
|
|
2268
|
+
const msg = window2[i];
|
|
2269
|
+
if (!msg)
|
|
2270
|
+
continue;
|
|
2271
|
+
const role = i % 2 === 0 ? "user" : "assistant";
|
|
2272
|
+
messages.push({
|
|
2273
|
+
role,
|
|
2274
|
+
content: `[${msg.from_agent} \u2192 ${msg.to_agent ?? msg.space ?? "all"}]: ${msg.content}`
|
|
2275
|
+
});
|
|
2276
|
+
}
|
|
2277
|
+
const last = window2[window2.length - 1];
|
|
2278
|
+
if (!last)
|
|
2279
|
+
return null;
|
|
2280
|
+
messages.push({
|
|
2281
|
+
role: "assistant",
|
|
2282
|
+
content: `[${last.from_agent} \u2192 ${last.to_agent ?? last.space ?? "all"}]: ${last.content}`
|
|
2283
|
+
});
|
|
2284
|
+
return { messages };
|
|
2285
|
+
}
|
|
2286
|
+
async function gatherFromConversations(options = {}) {
|
|
2287
|
+
const dbPath = join5(homedir5(), ".conversations", "messages.db");
|
|
2288
|
+
const db = new Database5(dbPath, { readonly: true, create: false });
|
|
2289
|
+
try {
|
|
2290
|
+
let query = "SELECT * FROM messages WHERE 1=1";
|
|
2291
|
+
const params = [];
|
|
2292
|
+
if (options.since) {
|
|
2293
|
+
query += " AND created_at >= ?";
|
|
2294
|
+
params.push(options.since.toISOString());
|
|
2295
|
+
}
|
|
2296
|
+
query += " ORDER BY session_id, created_at ASC";
|
|
2297
|
+
const allMessages = db.query(query).all(...params);
|
|
2298
|
+
const sessions = new Map;
|
|
2299
|
+
for (const msg of allMessages) {
|
|
2300
|
+
const msgs = sessions.get(msg.session_id) ?? [];
|
|
2301
|
+
msgs.push(msg);
|
|
2302
|
+
sessions.set(msg.session_id, msgs);
|
|
2303
|
+
}
|
|
2304
|
+
const examples = [];
|
|
2305
|
+
const windowSize = 4;
|
|
2306
|
+
for (const [, sessionMsgs] of sessions) {
|
|
2307
|
+
if (sessionMsgs.length < 2)
|
|
2308
|
+
continue;
|
|
2309
|
+
for (let start = 0;start <= sessionMsgs.length - 2; start++) {
|
|
2310
|
+
const end = Math.min(start + windowSize, sessionMsgs.length);
|
|
2311
|
+
const window2 = sessionMsgs.slice(start, end);
|
|
2312
|
+
const example = windowToExample(window2);
|
|
2313
|
+
if (example)
|
|
2314
|
+
examples.push(example);
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
const finalExamples = options.limit ? examples.slice(0, options.limit) : examples;
|
|
2318
|
+
return {
|
|
2319
|
+
source: "conversations",
|
|
2320
|
+
examples: finalExamples,
|
|
2321
|
+
count: finalExamples.length
|
|
2322
|
+
};
|
|
2323
|
+
} finally {
|
|
2324
|
+
db.close();
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
var SYSTEM_PROMPT3 = "You are a helpful AI assistant participating in multi-agent conversations. You communicate clearly and collaboratively with other agents and users.";
|
|
2328
|
+
var init_conversations = () => {};
|
|
2329
|
+
|
|
2330
|
+
// src/lib/gatherers/sessions.ts
|
|
2331
|
+
var exports_sessions2 = {};
|
|
2332
|
+
__export(exports_sessions2, {
|
|
2333
|
+
gatherFromSessions: () => gatherFromSessions
|
|
2334
|
+
});
|
|
2335
|
+
import { readdir, readFile, stat } from "fs/promises";
|
|
2336
|
+
import { existsSync as existsSync2 } from "fs";
|
|
2337
|
+
import { join as join6 } from "path";
|
|
2338
|
+
import { homedir as homedir6 } from "os";
|
|
2339
|
+
function extractText(content) {
|
|
2340
|
+
if (typeof content === "string")
|
|
2341
|
+
return content;
|
|
2342
|
+
return content.filter((c) => c.type === "text" && c.text).map((c) => c.text).join(`
|
|
2343
|
+
`).trim();
|
|
2344
|
+
}
|
|
2345
|
+
async function gatherFromSessions(options = {}) {
|
|
2346
|
+
const { limit: limit2 = 1000 } = options;
|
|
2347
|
+
const examples = [];
|
|
2348
|
+
const claudeDir = join6(homedir6(), ".claude", "projects");
|
|
2349
|
+
if (!existsSync2(claudeDir)) {
|
|
2350
|
+
return { source: "sessions", examples: [], count: 0 };
|
|
2351
|
+
}
|
|
2352
|
+
const projectDirs = await readdir(claudeDir).catch(() => []);
|
|
2353
|
+
for (const projectDir of projectDirs) {
|
|
2354
|
+
if (examples.length >= limit2)
|
|
2355
|
+
break;
|
|
2356
|
+
const projectPath = join6(claudeDir, projectDir);
|
|
2357
|
+
const files = await readdir(projectPath).catch(() => []);
|
|
2358
|
+
for (const file of files) {
|
|
2359
|
+
if (examples.length >= limit2)
|
|
2360
|
+
break;
|
|
2361
|
+
if (!file.endsWith(".jsonl"))
|
|
2362
|
+
continue;
|
|
2363
|
+
const filePath = join6(projectPath, file);
|
|
2364
|
+
if (options.since) {
|
|
2365
|
+
const fileStat = await stat(filePath).catch(() => null);
|
|
2366
|
+
if (fileStat && fileStat.mtime < options.since)
|
|
2367
|
+
continue;
|
|
2368
|
+
}
|
|
2369
|
+
const content = await readFile(filePath, "utf-8").catch(() => "");
|
|
2370
|
+
if (!content.trim())
|
|
2371
|
+
continue;
|
|
2372
|
+
const lines = content.trim().split(`
|
|
2373
|
+
`);
|
|
2374
|
+
const turns = [];
|
|
2375
|
+
for (const line of lines) {
|
|
2376
|
+
try {
|
|
2377
|
+
const entry = JSON.parse(line);
|
|
2378
|
+
if ((entry.type === "user" || entry.type === "human") && entry.message?.content) {
|
|
2379
|
+
const text2 = extractText(entry.message.content);
|
|
2380
|
+
if (text2.trim())
|
|
2381
|
+
turns.push({ role: "user", content: text2.trim() });
|
|
2382
|
+
} else if (entry.type === "assistant" && entry.message?.content) {
|
|
2383
|
+
const text2 = extractText(entry.message.content);
|
|
2384
|
+
if (text2.trim())
|
|
2385
|
+
turns.push({ role: "assistant", content: text2.trim() });
|
|
2386
|
+
}
|
|
2387
|
+
} catch {}
|
|
2388
|
+
}
|
|
2389
|
+
const windowSize = 6;
|
|
2390
|
+
for (let start = 0;start < turns.length - 1 && examples.length < limit2; start++) {
|
|
2391
|
+
const window2 = turns.slice(start, start + windowSize);
|
|
2392
|
+
if (!window2[0] || window2[0].role !== "user")
|
|
2393
|
+
continue;
|
|
2394
|
+
const lastAssistantIdx = window2.map((t) => t.role).lastIndexOf("assistant");
|
|
2395
|
+
if (lastAssistantIdx < 1)
|
|
2396
|
+
continue;
|
|
2397
|
+
const usedTurns = window2.slice(0, lastAssistantIdx + 1);
|
|
2398
|
+
examples.push({
|
|
2399
|
+
messages: [
|
|
2400
|
+
{ role: "system", content: SYSTEM_PROMPT4 },
|
|
2401
|
+
...usedTurns
|
|
2402
|
+
]
|
|
2403
|
+
});
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
return { source: "sessions", examples, count: examples.length };
|
|
2408
|
+
}
|
|
2409
|
+
var SYSTEM_PROMPT4 = "You are Claude Code, an AI assistant built by Anthropic that helps developers with coding, architecture, debugging, and software engineering tasks.";
|
|
2410
|
+
var init_sessions = () => {};
|
|
2411
|
+
|
|
2065
2412
|
// node_modules/commander/esm.mjs
|
|
2066
2413
|
var import__ = __toESM(require_commander(), 1);
|
|
2067
2414
|
var {
|
|
@@ -3436,9 +3783,9 @@ function mapRelationalRow(tablesConfig, tableConfig, row, buildQueryResultSelect
|
|
|
3436
3783
|
|
|
3437
3784
|
// src/cli/index.ts
|
|
3438
3785
|
import { randomUUID } from "crypto";
|
|
3439
|
-
import { readFileSync as
|
|
3440
|
-
import { join as
|
|
3441
|
-
import { homedir as
|
|
3786
|
+
import { readFileSync as readFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
3787
|
+
import { join as join7 } from "path";
|
|
3788
|
+
import { homedir as homedir7 } from "os";
|
|
3442
3789
|
|
|
3443
3790
|
// node_modules/drizzle-orm/bun-sqlite/driver.js
|
|
3444
3791
|
import { Database } from "bun:sqlite";
|
|
@@ -5721,10 +6068,48 @@ function drizzle(...params) {
|
|
|
5721
6068
|
drizzle2.mock = mock;
|
|
5722
6069
|
})(drizzle || (drizzle = {}));
|
|
5723
6070
|
|
|
6071
|
+
// node_modules/drizzle-orm/migrator.js
|
|
6072
|
+
import crypto from "crypto";
|
|
6073
|
+
import fs from "fs";
|
|
6074
|
+
function readMigrationFiles(config) {
|
|
6075
|
+
const migrationFolderTo = config.migrationsFolder;
|
|
6076
|
+
const migrationQueries = [];
|
|
6077
|
+
const journalPath = `${migrationFolderTo}/meta/_journal.json`;
|
|
6078
|
+
if (!fs.existsSync(journalPath)) {
|
|
6079
|
+
throw new Error(`Can't find meta/_journal.json file`);
|
|
6080
|
+
}
|
|
6081
|
+
const journalAsString = fs.readFileSync(`${migrationFolderTo}/meta/_journal.json`).toString();
|
|
6082
|
+
const journal = JSON.parse(journalAsString);
|
|
6083
|
+
for (const journalEntry of journal.entries) {
|
|
6084
|
+
const migrationPath = `${migrationFolderTo}/${journalEntry.tag}.sql`;
|
|
6085
|
+
try {
|
|
6086
|
+
const query = fs.readFileSync(`${migrationFolderTo}/${journalEntry.tag}.sql`).toString();
|
|
6087
|
+
const result = query.split("--> statement-breakpoint").map((it) => {
|
|
6088
|
+
return it;
|
|
6089
|
+
});
|
|
6090
|
+
migrationQueries.push({
|
|
6091
|
+
sql: result,
|
|
6092
|
+
bps: journalEntry.breakpoints,
|
|
6093
|
+
folderMillis: journalEntry.when,
|
|
6094
|
+
hash: crypto.createHash("sha256").update(query).digest("hex")
|
|
6095
|
+
});
|
|
6096
|
+
} catch {
|
|
6097
|
+
throw new Error(`No file ${migrationPath} found in ${migrationFolderTo} folder`);
|
|
6098
|
+
}
|
|
6099
|
+
}
|
|
6100
|
+
return migrationQueries;
|
|
6101
|
+
}
|
|
6102
|
+
|
|
6103
|
+
// node_modules/drizzle-orm/bun-sqlite/migrator.js
|
|
6104
|
+
function migrate(db, config) {
|
|
6105
|
+
const migrations = readMigrationFiles(config);
|
|
6106
|
+
db.dialect.migrate(migrations, db.session, config);
|
|
6107
|
+
}
|
|
6108
|
+
|
|
5724
6109
|
// src/db/index.ts
|
|
5725
6110
|
import { Database as Database2 } from "bun:sqlite";
|
|
5726
6111
|
import { mkdirSync } from "fs";
|
|
5727
|
-
import { dirname, join } from "path";
|
|
6112
|
+
import { dirname, join, resolve } from "path";
|
|
5728
6113
|
import { homedir } from "os";
|
|
5729
6114
|
|
|
5730
6115
|
// src/db/schema.ts
|
|
@@ -5776,52 +6161,55 @@ var DEFAULT_DB_PATH = join(homedir(), ".brains", "brains.db");
|
|
|
5776
6161
|
function ensureDir(filePath) {
|
|
5777
6162
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
5778
6163
|
}
|
|
5779
|
-
function createTables(sqlite) {
|
|
5780
|
-
sqlite.exec(`
|
|
5781
|
-
CREATE TABLE IF NOT EXISTS fine_tuned_models (
|
|
5782
|
-
id TEXT PRIMARY KEY,
|
|
5783
|
-
base_model TEXT NOT NULL,
|
|
5784
|
-
name TEXT NOT NULL,
|
|
5785
|
-
provider TEXT NOT NULL,
|
|
5786
|
-
status TEXT NOT NULL DEFAULT 'pending',
|
|
5787
|
-
fine_tune_job_id TEXT,
|
|
5788
|
-
display_name TEXT,
|
|
5789
|
-
description TEXT,
|
|
5790
|
-
collection TEXT,
|
|
5791
|
-
tags TEXT,
|
|
5792
|
-
created_at INTEGER NOT NULL,
|
|
5793
|
-
updated_at INTEGER NOT NULL
|
|
5794
|
-
);
|
|
5795
|
-
|
|
5796
|
-
CREATE TABLE IF NOT EXISTS training_jobs (
|
|
5797
|
-
id TEXT PRIMARY KEY,
|
|
5798
|
-
model_id TEXT NOT NULL REFERENCES fine_tuned_models(id),
|
|
5799
|
-
provider TEXT NOT NULL,
|
|
5800
|
-
status TEXT NOT NULL,
|
|
5801
|
-
started_at INTEGER NOT NULL,
|
|
5802
|
-
finished_at INTEGER,
|
|
5803
|
-
metrics TEXT,
|
|
5804
|
-
error TEXT
|
|
5805
|
-
);
|
|
5806
|
-
|
|
5807
|
-
CREATE TABLE IF NOT EXISTS training_datasets (
|
|
5808
|
-
id TEXT PRIMARY KEY,
|
|
5809
|
-
source TEXT NOT NULL,
|
|
5810
|
-
file_path TEXT NOT NULL,
|
|
5811
|
-
example_count INTEGER NOT NULL,
|
|
5812
|
-
created_at INTEGER NOT NULL,
|
|
5813
|
-
used_in_job_id TEXT REFERENCES training_jobs(id)
|
|
5814
|
-
);
|
|
5815
|
-
`);
|
|
5816
|
-
}
|
|
5817
6164
|
function getDb(dbPath) {
|
|
5818
6165
|
const resolvedPath = dbPath ?? DEFAULT_DB_PATH;
|
|
5819
6166
|
ensureDir(resolvedPath);
|
|
5820
6167
|
const sqlite = new Database2(resolvedPath);
|
|
5821
6168
|
sqlite.run("PRAGMA journal_mode = WAL");
|
|
5822
6169
|
sqlite.run("PRAGMA foreign_keys = ON");
|
|
5823
|
-
|
|
5824
|
-
|
|
6170
|
+
const db = drizzle(sqlite, { schema: exports_schema });
|
|
6171
|
+
try {
|
|
6172
|
+
const migrationsFolder = resolve(import.meta.dir, "../../drizzle");
|
|
6173
|
+
migrate(db, { migrationsFolder });
|
|
6174
|
+
} catch {
|
|
6175
|
+
sqlite.exec(`
|
|
6176
|
+
CREATE TABLE IF NOT EXISTS fine_tuned_models (
|
|
6177
|
+
id TEXT PRIMARY KEY,
|
|
6178
|
+
base_model TEXT NOT NULL,
|
|
6179
|
+
name TEXT NOT NULL,
|
|
6180
|
+
provider TEXT NOT NULL,
|
|
6181
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
6182
|
+
fine_tune_job_id TEXT,
|
|
6183
|
+
display_name TEXT,
|
|
6184
|
+
description TEXT,
|
|
6185
|
+
collection TEXT,
|
|
6186
|
+
tags TEXT,
|
|
6187
|
+
created_at INTEGER NOT NULL,
|
|
6188
|
+
updated_at INTEGER NOT NULL
|
|
6189
|
+
);
|
|
6190
|
+
|
|
6191
|
+
CREATE TABLE IF NOT EXISTS training_jobs (
|
|
6192
|
+
id TEXT PRIMARY KEY,
|
|
6193
|
+
model_id TEXT NOT NULL REFERENCES fine_tuned_models(id),
|
|
6194
|
+
provider TEXT NOT NULL,
|
|
6195
|
+
status TEXT NOT NULL,
|
|
6196
|
+
started_at INTEGER NOT NULL,
|
|
6197
|
+
finished_at INTEGER,
|
|
6198
|
+
metrics TEXT,
|
|
6199
|
+
error TEXT
|
|
6200
|
+
);
|
|
6201
|
+
|
|
6202
|
+
CREATE TABLE IF NOT EXISTS training_datasets (
|
|
6203
|
+
id TEXT PRIMARY KEY,
|
|
6204
|
+
source TEXT NOT NULL,
|
|
6205
|
+
file_path TEXT NOT NULL,
|
|
6206
|
+
example_count INTEGER NOT NULL,
|
|
6207
|
+
created_at INTEGER NOT NULL,
|
|
6208
|
+
used_in_job_id TEXT REFERENCES training_jobs(id)
|
|
6209
|
+
);
|
|
6210
|
+
`);
|
|
6211
|
+
}
|
|
6212
|
+
return db;
|
|
5825
6213
|
}
|
|
5826
6214
|
|
|
5827
6215
|
// node_modules/openai/internal/qs/formats.mjs
|
|
@@ -6912,8 +7300,8 @@ function _addRequestID(value, response) {
|
|
|
6912
7300
|
|
|
6913
7301
|
class APIPromise extends Promise {
|
|
6914
7302
|
constructor(responsePromise, parseResponse = defaultParseResponse) {
|
|
6915
|
-
super((
|
|
6916
|
-
|
|
7303
|
+
super((resolve2) => {
|
|
7304
|
+
resolve2(null);
|
|
6917
7305
|
});
|
|
6918
7306
|
this.responsePromise = responsePromise;
|
|
6919
7307
|
this.parseResponse = parseResponse;
|
|
@@ -7424,7 +7812,7 @@ var startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;
|
|
|
7424
7812
|
var isAbsoluteURL = (url) => {
|
|
7425
7813
|
return startsWithSchemeRegexp.test(url);
|
|
7426
7814
|
};
|
|
7427
|
-
var sleep = (ms) => new Promise((
|
|
7815
|
+
var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
7428
7816
|
var validatePositiveInteger = (name, n) => {
|
|
7429
7817
|
if (typeof n !== "number" || !Number.isInteger(n)) {
|
|
7430
7818
|
throw new OpenAIError(`${name} must be an integer`);
|
|
@@ -7789,12 +8177,12 @@ class EventStream {
|
|
|
7789
8177
|
_EventStream_errored.set(this, false);
|
|
7790
8178
|
_EventStream_aborted.set(this, false);
|
|
7791
8179
|
_EventStream_catchingPromiseCreated.set(this, false);
|
|
7792
|
-
__classPrivateFieldSet3(this, _EventStream_connectedPromise, new Promise((
|
|
7793
|
-
__classPrivateFieldSet3(this, _EventStream_resolveConnectedPromise,
|
|
8180
|
+
__classPrivateFieldSet3(this, _EventStream_connectedPromise, new Promise((resolve2, reject) => {
|
|
8181
|
+
__classPrivateFieldSet3(this, _EventStream_resolveConnectedPromise, resolve2, "f");
|
|
7794
8182
|
__classPrivateFieldSet3(this, _EventStream_rejectConnectedPromise, reject, "f");
|
|
7795
8183
|
}), "f");
|
|
7796
|
-
__classPrivateFieldSet3(this, _EventStream_endPromise, new Promise((
|
|
7797
|
-
__classPrivateFieldSet3(this, _EventStream_resolveEndPromise,
|
|
8184
|
+
__classPrivateFieldSet3(this, _EventStream_endPromise, new Promise((resolve2, reject) => {
|
|
8185
|
+
__classPrivateFieldSet3(this, _EventStream_resolveEndPromise, resolve2, "f");
|
|
7798
8186
|
__classPrivateFieldSet3(this, _EventStream_rejectEndPromise, reject, "f");
|
|
7799
8187
|
}), "f");
|
|
7800
8188
|
__classPrivateFieldGet3(this, _EventStream_connectedPromise, "f").catch(() => {});
|
|
@@ -7846,11 +8234,11 @@ class EventStream {
|
|
|
7846
8234
|
return this;
|
|
7847
8235
|
}
|
|
7848
8236
|
emitted(event) {
|
|
7849
|
-
return new Promise((
|
|
8237
|
+
return new Promise((resolve2, reject) => {
|
|
7850
8238
|
__classPrivateFieldSet3(this, _EventStream_catchingPromiseCreated, true, "f");
|
|
7851
8239
|
if (event !== "error")
|
|
7852
8240
|
this.once("error", reject);
|
|
7853
|
-
this.once(event,
|
|
8241
|
+
this.once(event, resolve2);
|
|
7854
8242
|
});
|
|
7855
8243
|
}
|
|
7856
8244
|
async done() {
|
|
@@ -8008,7 +8396,7 @@ class AssistantStream extends EventStream {
|
|
|
8008
8396
|
if (done) {
|
|
8009
8397
|
return { value: undefined, done: true };
|
|
8010
8398
|
}
|
|
8011
|
-
return new Promise((
|
|
8399
|
+
return new Promise((resolve2, reject) => readQueue.push({ resolve: resolve2, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: undefined, done: true });
|
|
8012
8400
|
}
|
|
8013
8401
|
const chunk = pushQueue.shift();
|
|
8014
8402
|
return { value: chunk, done: false };
|
|
@@ -9288,11 +9676,11 @@ class ChatCompletionStream extends AbstractChatCompletionRunner {
|
|
|
9288
9676
|
}
|
|
9289
9677
|
return this._addChatCompletion(__classPrivateFieldGet6(this, _ChatCompletionStream_instances, "m", _ChatCompletionStream_endRequest).call(this));
|
|
9290
9678
|
}
|
|
9291
|
-
[(_ChatCompletionStream_params = new WeakMap, _ChatCompletionStream_choiceEventStates = new WeakMap, _ChatCompletionStream_currentChatCompletionSnapshot = new WeakMap, _ChatCompletionStream_instances = new WeakSet, _ChatCompletionStream_beginRequest = function
|
|
9679
|
+
[(_ChatCompletionStream_params = new WeakMap, _ChatCompletionStream_choiceEventStates = new WeakMap, _ChatCompletionStream_currentChatCompletionSnapshot = new WeakMap, _ChatCompletionStream_instances = new WeakSet, _ChatCompletionStream_beginRequest = function _ChatCompletionStream_beginRequest() {
|
|
9292
9680
|
if (this.ended)
|
|
9293
9681
|
return;
|
|
9294
9682
|
__classPrivateFieldSet5(this, _ChatCompletionStream_currentChatCompletionSnapshot, undefined, "f");
|
|
9295
|
-
}, _ChatCompletionStream_getChoiceEventState = function
|
|
9683
|
+
}, _ChatCompletionStream_getChoiceEventState = function _ChatCompletionStream_getChoiceEventState(choice) {
|
|
9296
9684
|
let state = __classPrivateFieldGet6(this, _ChatCompletionStream_choiceEventStates, "f")[choice.index];
|
|
9297
9685
|
if (state) {
|
|
9298
9686
|
return state;
|
|
@@ -9307,7 +9695,7 @@ class ChatCompletionStream extends AbstractChatCompletionRunner {
|
|
|
9307
9695
|
};
|
|
9308
9696
|
__classPrivateFieldGet6(this, _ChatCompletionStream_choiceEventStates, "f")[choice.index] = state;
|
|
9309
9697
|
return state;
|
|
9310
|
-
}, _ChatCompletionStream_addChunk = function
|
|
9698
|
+
}, _ChatCompletionStream_addChunk = function _ChatCompletionStream_addChunk(chunk) {
|
|
9311
9699
|
if (this.ended)
|
|
9312
9700
|
return;
|
|
9313
9701
|
const completion = __classPrivateFieldGet6(this, _ChatCompletionStream_instances, "m", _ChatCompletionStream_accumulateChatCompletion).call(this, chunk);
|
|
@@ -9374,7 +9762,7 @@ class ChatCompletionStream extends AbstractChatCompletionRunner {
|
|
|
9374
9762
|
}
|
|
9375
9763
|
}
|
|
9376
9764
|
}
|
|
9377
|
-
}, _ChatCompletionStream_emitToolCallDoneEvent = function
|
|
9765
|
+
}, _ChatCompletionStream_emitToolCallDoneEvent = function _ChatCompletionStream_emitToolCallDoneEvent(choiceSnapshot, toolCallIndex) {
|
|
9378
9766
|
const state = __classPrivateFieldGet6(this, _ChatCompletionStream_instances, "m", _ChatCompletionStream_getChoiceEventState).call(this, choiceSnapshot);
|
|
9379
9767
|
if (state.done_tool_calls.has(toolCallIndex)) {
|
|
9380
9768
|
return;
|
|
@@ -9397,7 +9785,7 @@ class ChatCompletionStream extends AbstractChatCompletionRunner {
|
|
|
9397
9785
|
} else {
|
|
9398
9786
|
assertNever2(toolCallSnapshot.type);
|
|
9399
9787
|
}
|
|
9400
|
-
}, _ChatCompletionStream_emitContentDoneEvents = function
|
|
9788
|
+
}, _ChatCompletionStream_emitContentDoneEvents = function _ChatCompletionStream_emitContentDoneEvents(choiceSnapshot) {
|
|
9401
9789
|
const state = __classPrivateFieldGet6(this, _ChatCompletionStream_instances, "m", _ChatCompletionStream_getChoiceEventState).call(this, choiceSnapshot);
|
|
9402
9790
|
if (choiceSnapshot.message.content && !state.content_done) {
|
|
9403
9791
|
state.content_done = true;
|
|
@@ -9419,7 +9807,7 @@ class ChatCompletionStream extends AbstractChatCompletionRunner {
|
|
|
9419
9807
|
state.logprobs_refusal_done = true;
|
|
9420
9808
|
this._emit("logprobs.refusal.done", { refusal: choiceSnapshot.logprobs.refusal });
|
|
9421
9809
|
}
|
|
9422
|
-
}, _ChatCompletionStream_endRequest = function
|
|
9810
|
+
}, _ChatCompletionStream_endRequest = function _ChatCompletionStream_endRequest() {
|
|
9423
9811
|
if (this.ended) {
|
|
9424
9812
|
throw new OpenAIError(`stream has ended, this shouldn't happen`);
|
|
9425
9813
|
}
|
|
@@ -9430,13 +9818,13 @@ class ChatCompletionStream extends AbstractChatCompletionRunner {
|
|
|
9430
9818
|
__classPrivateFieldSet5(this, _ChatCompletionStream_currentChatCompletionSnapshot, undefined, "f");
|
|
9431
9819
|
__classPrivateFieldSet5(this, _ChatCompletionStream_choiceEventStates, [], "f");
|
|
9432
9820
|
return finalizeChatCompletion(snapshot, __classPrivateFieldGet6(this, _ChatCompletionStream_params, "f"));
|
|
9433
|
-
}, _ChatCompletionStream_getAutoParseableResponseFormat = function
|
|
9821
|
+
}, _ChatCompletionStream_getAutoParseableResponseFormat = function _ChatCompletionStream_getAutoParseableResponseFormat() {
|
|
9434
9822
|
const responseFormat = __classPrivateFieldGet6(this, _ChatCompletionStream_params, "f")?.response_format;
|
|
9435
9823
|
if (isAutoParsableResponseFormat(responseFormat)) {
|
|
9436
9824
|
return responseFormat;
|
|
9437
9825
|
}
|
|
9438
9826
|
return null;
|
|
9439
|
-
}, _ChatCompletionStream_accumulateChatCompletion = function
|
|
9827
|
+
}, _ChatCompletionStream_accumulateChatCompletion = function _ChatCompletionStream_accumulateChatCompletion(chunk) {
|
|
9440
9828
|
var _a, _b, _c, _d;
|
|
9441
9829
|
let snapshot = __classPrivateFieldGet6(this, _ChatCompletionStream_currentChatCompletionSnapshot, "f");
|
|
9442
9830
|
const { choices, ...rest } = chunk;
|
|
@@ -9573,7 +9961,7 @@ class ChatCompletionStream extends AbstractChatCompletionRunner {
|
|
|
9573
9961
|
if (done) {
|
|
9574
9962
|
return { value: undefined, done: true };
|
|
9575
9963
|
}
|
|
9576
|
-
return new Promise((
|
|
9964
|
+
return new Promise((resolve2, reject) => readQueue.push({ resolve: resolve2, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: undefined, done: true });
|
|
9577
9965
|
}
|
|
9578
9966
|
const chunk = pushQueue.shift();
|
|
9579
9967
|
return { value: chunk, done: false };
|
|
@@ -10662,11 +11050,11 @@ class ResponseStream extends EventStream {
|
|
|
10662
11050
|
}
|
|
10663
11051
|
return __classPrivateFieldGet7(this, _ResponseStream_instances, "m", _ResponseStream_endRequest).call(this);
|
|
10664
11052
|
}
|
|
10665
|
-
[(_ResponseStream_params = new WeakMap, _ResponseStream_currentResponseSnapshot = new WeakMap, _ResponseStream_finalResponse = new WeakMap, _ResponseStream_instances = new WeakSet, _ResponseStream_beginRequest = function
|
|
11053
|
+
[(_ResponseStream_params = new WeakMap, _ResponseStream_currentResponseSnapshot = new WeakMap, _ResponseStream_finalResponse = new WeakMap, _ResponseStream_instances = new WeakSet, _ResponseStream_beginRequest = function _ResponseStream_beginRequest() {
|
|
10666
11054
|
if (this.ended)
|
|
10667
11055
|
return;
|
|
10668
11056
|
__classPrivateFieldSet6(this, _ResponseStream_currentResponseSnapshot, undefined, "f");
|
|
10669
|
-
}, _ResponseStream_addEvent = function
|
|
11057
|
+
}, _ResponseStream_addEvent = function _ResponseStream_addEvent(event, starting_after) {
|
|
10670
11058
|
if (this.ended)
|
|
10671
11059
|
return;
|
|
10672
11060
|
const maybeEmit = (name, event2) => {
|
|
@@ -10714,7 +11102,7 @@ class ResponseStream extends EventStream {
|
|
|
10714
11102
|
maybeEmit(event.type, event);
|
|
10715
11103
|
break;
|
|
10716
11104
|
}
|
|
10717
|
-
}, _ResponseStream_endRequest = function
|
|
11105
|
+
}, _ResponseStream_endRequest = function _ResponseStream_endRequest() {
|
|
10718
11106
|
if (this.ended) {
|
|
10719
11107
|
throw new OpenAIError(`stream has ended, this shouldn't happen`);
|
|
10720
11108
|
}
|
|
@@ -10726,7 +11114,7 @@ class ResponseStream extends EventStream {
|
|
|
10726
11114
|
const parsedResponse = finalizeResponse(snapshot, __classPrivateFieldGet7(this, _ResponseStream_params, "f"));
|
|
10727
11115
|
__classPrivateFieldSet6(this, _ResponseStream_finalResponse, parsedResponse, "f");
|
|
10728
11116
|
return parsedResponse;
|
|
10729
|
-
}, _ResponseStream_accumulateResponse = function
|
|
11117
|
+
}, _ResponseStream_accumulateResponse = function _ResponseStream_accumulateResponse(event) {
|
|
10730
11118
|
let snapshot = __classPrivateFieldGet7(this, _ResponseStream_currentResponseSnapshot, "f");
|
|
10731
11119
|
if (!snapshot) {
|
|
10732
11120
|
if (event.type !== "response.created") {
|
|
@@ -10822,7 +11210,7 @@ class ResponseStream extends EventStream {
|
|
|
10822
11210
|
if (done) {
|
|
10823
11211
|
return { value: undefined, done: true };
|
|
10824
11212
|
}
|
|
10825
|
-
return new Promise((
|
|
11213
|
+
return new Promise((resolve2, reject) => readQueue.push({ resolve: resolve2, reject })).then((event2) => event2 ? { value: event2, done: false } : { value: undefined, done: true });
|
|
10826
11214
|
}
|
|
10827
11215
|
const event = pushQueue.shift();
|
|
10828
11216
|
return { value: event, done: false };
|
|
@@ -11004,863 +11392,612 @@ class Files3 extends APIResource {
|
|
|
11004
11392
|
case "failed":
|
|
11005
11393
|
case "completed":
|
|
11006
11394
|
return file;
|
|
11007
|
-
}
|
|
11008
|
-
}
|
|
11009
|
-
}
|
|
11010
|
-
async upload(vectorStoreId, file, options) {
|
|
11011
|
-
const fileInfo = await this._client.files.create({ file, purpose: "assistants" }, options);
|
|
11012
|
-
return this.create(vectorStoreId, { file_id: fileInfo.id }, options);
|
|
11013
|
-
}
|
|
11014
|
-
async uploadAndPoll(vectorStoreId, file, options) {
|
|
11015
|
-
const fileInfo = await this.upload(vectorStoreId, file, options);
|
|
11016
|
-
return await this.poll(vectorStoreId, fileInfo.id, options);
|
|
11017
|
-
}
|
|
11018
|
-
content(vectorStoreId, fileId, options) {
|
|
11019
|
-
return this._client.getAPIList(`/vector_stores/${vectorStoreId}/files/${fileId}/content`, FileContentResponsesPage, { ...options, headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers } });
|
|
11020
|
-
}
|
|
11021
|
-
}
|
|
11022
|
-
|
|
11023
|
-
class VectorStoreFilesPage extends CursorPage {
|
|
11024
|
-
}
|
|
11025
|
-
|
|
11026
|
-
class FileContentResponsesPage extends Page {
|
|
11027
|
-
}
|
|
11028
|
-
Files3.VectorStoreFilesPage = VectorStoreFilesPage;
|
|
11029
|
-
Files3.FileContentResponsesPage = FileContentResponsesPage;
|
|
11030
|
-
|
|
11031
|
-
// node_modules/openai/resources/vector-stores/file-batches.mjs
|
|
11032
|
-
class FileBatches extends APIResource {
|
|
11033
|
-
create(vectorStoreId, body, options) {
|
|
11034
|
-
return this._client.post(`/vector_stores/${vectorStoreId}/file_batches`, {
|
|
11035
|
-
body,
|
|
11036
|
-
...options,
|
|
11037
|
-
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11038
|
-
});
|
|
11039
|
-
}
|
|
11040
|
-
retrieve(vectorStoreId, batchId, options) {
|
|
11041
|
-
return this._client.get(`/vector_stores/${vectorStoreId}/file_batches/${batchId}`, {
|
|
11042
|
-
...options,
|
|
11043
|
-
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11044
|
-
});
|
|
11045
|
-
}
|
|
11046
|
-
cancel(vectorStoreId, batchId, options) {
|
|
11047
|
-
return this._client.post(`/vector_stores/${vectorStoreId}/file_batches/${batchId}/cancel`, {
|
|
11048
|
-
...options,
|
|
11049
|
-
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11050
|
-
});
|
|
11051
|
-
}
|
|
11052
|
-
async createAndPoll(vectorStoreId, body, options) {
|
|
11053
|
-
const batch = await this.create(vectorStoreId, body);
|
|
11054
|
-
return await this.poll(vectorStoreId, batch.id, options);
|
|
11055
|
-
}
|
|
11056
|
-
listFiles(vectorStoreId, batchId, query = {}, options) {
|
|
11057
|
-
if (isRequestOptions(query)) {
|
|
11058
|
-
return this.listFiles(vectorStoreId, batchId, {}, query);
|
|
11059
|
-
}
|
|
11060
|
-
return this._client.getAPIList(`/vector_stores/${vectorStoreId}/file_batches/${batchId}/files`, VectorStoreFilesPage, { query, ...options, headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers } });
|
|
11061
|
-
}
|
|
11062
|
-
async poll(vectorStoreId, batchId, options) {
|
|
11063
|
-
const headers = { ...options?.headers, "X-Stainless-Poll-Helper": "true" };
|
|
11064
|
-
if (options?.pollIntervalMs) {
|
|
11065
|
-
headers["X-Stainless-Custom-Poll-Interval"] = options.pollIntervalMs.toString();
|
|
11066
|
-
}
|
|
11067
|
-
while (true) {
|
|
11068
|
-
const { data: batch, response } = await this.retrieve(vectorStoreId, batchId, {
|
|
11069
|
-
...options,
|
|
11070
|
-
headers
|
|
11071
|
-
}).withResponse();
|
|
11072
|
-
switch (batch.status) {
|
|
11073
|
-
case "in_progress":
|
|
11074
|
-
let sleepInterval = 5000;
|
|
11075
|
-
if (options?.pollIntervalMs) {
|
|
11076
|
-
sleepInterval = options.pollIntervalMs;
|
|
11077
|
-
} else {
|
|
11078
|
-
const headerInterval = response.headers.get("openai-poll-after-ms");
|
|
11079
|
-
if (headerInterval) {
|
|
11080
|
-
const headerIntervalMs = parseInt(headerInterval);
|
|
11081
|
-
if (!isNaN(headerIntervalMs)) {
|
|
11082
|
-
sleepInterval = headerIntervalMs;
|
|
11083
|
-
}
|
|
11084
|
-
}
|
|
11085
|
-
}
|
|
11086
|
-
await sleep(sleepInterval);
|
|
11087
|
-
break;
|
|
11088
|
-
case "failed":
|
|
11089
|
-
case "cancelled":
|
|
11090
|
-
case "completed":
|
|
11091
|
-
return batch;
|
|
11092
|
-
}
|
|
11093
|
-
}
|
|
11094
|
-
}
|
|
11095
|
-
async uploadAndPoll(vectorStoreId, { files, fileIds = [] }, options) {
|
|
11096
|
-
if (files == null || files.length == 0) {
|
|
11097
|
-
throw new Error(`No \`files\` provided to process. If you've already uploaded files you should use \`.createAndPoll()\` instead`);
|
|
11098
|
-
}
|
|
11099
|
-
const configuredConcurrency = options?.maxConcurrency ?? 5;
|
|
11100
|
-
const concurrencyLimit = Math.min(configuredConcurrency, files.length);
|
|
11101
|
-
const client = this._client;
|
|
11102
|
-
const fileIterator = files.values();
|
|
11103
|
-
const allFileIds = [...fileIds];
|
|
11104
|
-
async function processFiles(iterator) {
|
|
11105
|
-
for (let item of iterator) {
|
|
11106
|
-
const fileObj = await client.files.create({ file: item, purpose: "assistants" }, options);
|
|
11107
|
-
allFileIds.push(fileObj.id);
|
|
11108
|
-
}
|
|
11109
|
-
}
|
|
11110
|
-
const workers = Array(concurrencyLimit).fill(fileIterator).map(processFiles);
|
|
11111
|
-
await allSettledWithThrow(workers);
|
|
11112
|
-
return await this.createAndPoll(vectorStoreId, {
|
|
11113
|
-
file_ids: allFileIds
|
|
11114
|
-
});
|
|
11115
|
-
}
|
|
11116
|
-
}
|
|
11117
|
-
|
|
11118
|
-
// node_modules/openai/resources/vector-stores/vector-stores.mjs
|
|
11119
|
-
class VectorStores extends APIResource {
|
|
11120
|
-
constructor() {
|
|
11121
|
-
super(...arguments);
|
|
11122
|
-
this.files = new Files3(this._client);
|
|
11123
|
-
this.fileBatches = new FileBatches(this._client);
|
|
11124
|
-
}
|
|
11125
|
-
create(body, options) {
|
|
11126
|
-
return this._client.post("/vector_stores", {
|
|
11127
|
-
body,
|
|
11128
|
-
...options,
|
|
11129
|
-
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11130
|
-
});
|
|
11131
|
-
}
|
|
11132
|
-
retrieve(vectorStoreId, options) {
|
|
11133
|
-
return this._client.get(`/vector_stores/${vectorStoreId}`, {
|
|
11134
|
-
...options,
|
|
11135
|
-
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11136
|
-
});
|
|
11137
|
-
}
|
|
11138
|
-
update(vectorStoreId, body, options) {
|
|
11139
|
-
return this._client.post(`/vector_stores/${vectorStoreId}`, {
|
|
11140
|
-
body,
|
|
11141
|
-
...options,
|
|
11142
|
-
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11143
|
-
});
|
|
11144
|
-
}
|
|
11145
|
-
list(query = {}, options) {
|
|
11146
|
-
if (isRequestOptions(query)) {
|
|
11147
|
-
return this.list({}, query);
|
|
11148
|
-
}
|
|
11149
|
-
return this._client.getAPIList("/vector_stores", VectorStoresPage, {
|
|
11150
|
-
query,
|
|
11151
|
-
...options,
|
|
11152
|
-
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11153
|
-
});
|
|
11154
|
-
}
|
|
11155
|
-
del(vectorStoreId, options) {
|
|
11156
|
-
return this._client.delete(`/vector_stores/${vectorStoreId}`, {
|
|
11157
|
-
...options,
|
|
11158
|
-
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11159
|
-
});
|
|
11160
|
-
}
|
|
11161
|
-
search(vectorStoreId, body, options) {
|
|
11162
|
-
return this._client.getAPIList(`/vector_stores/${vectorStoreId}/search`, VectorStoreSearchResponsesPage, {
|
|
11163
|
-
body,
|
|
11164
|
-
method: "post",
|
|
11165
|
-
...options,
|
|
11166
|
-
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11167
|
-
});
|
|
11168
|
-
}
|
|
11169
|
-
}
|
|
11170
|
-
|
|
11171
|
-
class VectorStoresPage extends CursorPage {
|
|
11172
|
-
}
|
|
11173
|
-
|
|
11174
|
-
class VectorStoreSearchResponsesPage extends Page {
|
|
11175
|
-
}
|
|
11176
|
-
VectorStores.VectorStoresPage = VectorStoresPage;
|
|
11177
|
-
VectorStores.VectorStoreSearchResponsesPage = VectorStoreSearchResponsesPage;
|
|
11178
|
-
VectorStores.Files = Files3;
|
|
11179
|
-
VectorStores.VectorStoreFilesPage = VectorStoreFilesPage;
|
|
11180
|
-
VectorStores.FileContentResponsesPage = FileContentResponsesPage;
|
|
11181
|
-
VectorStores.FileBatches = FileBatches;
|
|
11182
|
-
// node_modules/openai/index.mjs
|
|
11183
|
-
var _a;
|
|
11184
|
-
|
|
11185
|
-
class OpenAI extends APIClient {
|
|
11186
|
-
constructor({ baseURL = readEnv("OPENAI_BASE_URL"), apiKey = readEnv("OPENAI_API_KEY"), organization = readEnv("OPENAI_ORG_ID") ?? null, project = readEnv("OPENAI_PROJECT_ID") ?? null, ...opts } = {}) {
|
|
11187
|
-
if (apiKey === undefined) {
|
|
11188
|
-
throw new OpenAIError("The OPENAI_API_KEY environment variable is missing or empty; either provide it, or instantiate the OpenAI client with an apiKey option, like new OpenAI({ apiKey: 'My API Key' }).");
|
|
11189
|
-
}
|
|
11190
|
-
const options = {
|
|
11191
|
-
apiKey,
|
|
11192
|
-
organization,
|
|
11193
|
-
project,
|
|
11194
|
-
...opts,
|
|
11195
|
-
baseURL: baseURL || `https://api.openai.com/v1`
|
|
11196
|
-
};
|
|
11197
|
-
if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {
|
|
11198
|
-
throw new OpenAIError(`It looks like you're running in a browser-like environment.
|
|
11199
|
-
|
|
11200
|
-
This is disabled by default, as it risks exposing your secret API credentials to attackers.
|
|
11201
|
-
If you understand the risks and have appropriate mitigations in place,
|
|
11202
|
-
you can set the \`dangerouslyAllowBrowser\` option to \`true\`, e.g.,
|
|
11203
|
-
|
|
11204
|
-
new OpenAI({ apiKey, dangerouslyAllowBrowser: true });
|
|
11205
|
-
|
|
11206
|
-
https://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety
|
|
11207
|
-
`);
|
|
11208
|
-
}
|
|
11209
|
-
super({
|
|
11210
|
-
baseURL: options.baseURL,
|
|
11211
|
-
timeout: options.timeout ?? 600000,
|
|
11212
|
-
httpAgent: options.httpAgent,
|
|
11213
|
-
maxRetries: options.maxRetries,
|
|
11214
|
-
fetch: options.fetch
|
|
11215
|
-
});
|
|
11216
|
-
this.completions = new Completions3(this);
|
|
11217
|
-
this.chat = new Chat(this);
|
|
11218
|
-
this.embeddings = new Embeddings(this);
|
|
11219
|
-
this.files = new Files2(this);
|
|
11220
|
-
this.images = new Images(this);
|
|
11221
|
-
this.audio = new Audio(this);
|
|
11222
|
-
this.moderations = new Moderations(this);
|
|
11223
|
-
this.models = new Models(this);
|
|
11224
|
-
this.fineTuning = new FineTuning(this);
|
|
11225
|
-
this.graders = new Graders2(this);
|
|
11226
|
-
this.vectorStores = new VectorStores(this);
|
|
11227
|
-
this.beta = new Beta(this);
|
|
11228
|
-
this.batches = new Batches(this);
|
|
11229
|
-
this.uploads = new Uploads(this);
|
|
11230
|
-
this.responses = new Responses(this);
|
|
11231
|
-
this.evals = new Evals(this);
|
|
11232
|
-
this.containers = new Containers(this);
|
|
11233
|
-
this._options = options;
|
|
11234
|
-
this.apiKey = apiKey;
|
|
11235
|
-
this.organization = organization;
|
|
11236
|
-
this.project = project;
|
|
11237
|
-
}
|
|
11238
|
-
defaultQuery() {
|
|
11239
|
-
return this._options.defaultQuery;
|
|
11395
|
+
}
|
|
11396
|
+
}
|
|
11240
11397
|
}
|
|
11241
|
-
|
|
11242
|
-
|
|
11243
|
-
|
|
11244
|
-
"OpenAI-Organization": this.organization,
|
|
11245
|
-
"OpenAI-Project": this.project,
|
|
11246
|
-
...this._options.defaultHeaders
|
|
11247
|
-
};
|
|
11398
|
+
async upload(vectorStoreId, file, options) {
|
|
11399
|
+
const fileInfo = await this._client.files.create({ file, purpose: "assistants" }, options);
|
|
11400
|
+
return this.create(vectorStoreId, { file_id: fileInfo.id }, options);
|
|
11248
11401
|
}
|
|
11249
|
-
|
|
11250
|
-
|
|
11402
|
+
async uploadAndPoll(vectorStoreId, file, options) {
|
|
11403
|
+
const fileInfo = await this.upload(vectorStoreId, file, options);
|
|
11404
|
+
return await this.poll(vectorStoreId, fileInfo.id, options);
|
|
11251
11405
|
}
|
|
11252
|
-
|
|
11253
|
-
return
|
|
11406
|
+
content(vectorStoreId, fileId, options) {
|
|
11407
|
+
return this._client.getAPIList(`/vector_stores/${vectorStoreId}/files/${fileId}/content`, FileContentResponsesPage, { ...options, headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers } });
|
|
11254
11408
|
}
|
|
11255
11409
|
}
|
|
11256
|
-
_a = OpenAI;
|
|
11257
|
-
OpenAI.OpenAI = _a;
|
|
11258
|
-
OpenAI.DEFAULT_TIMEOUT = 600000;
|
|
11259
|
-
OpenAI.OpenAIError = OpenAIError;
|
|
11260
|
-
OpenAI.APIError = APIError;
|
|
11261
|
-
OpenAI.APIConnectionError = APIConnectionError;
|
|
11262
|
-
OpenAI.APIConnectionTimeoutError = APIConnectionTimeoutError;
|
|
11263
|
-
OpenAI.APIUserAbortError = APIUserAbortError;
|
|
11264
|
-
OpenAI.NotFoundError = NotFoundError;
|
|
11265
|
-
OpenAI.ConflictError = ConflictError;
|
|
11266
|
-
OpenAI.RateLimitError = RateLimitError;
|
|
11267
|
-
OpenAI.BadRequestError = BadRequestError;
|
|
11268
|
-
OpenAI.AuthenticationError = AuthenticationError;
|
|
11269
|
-
OpenAI.InternalServerError = InternalServerError;
|
|
11270
|
-
OpenAI.PermissionDeniedError = PermissionDeniedError;
|
|
11271
|
-
OpenAI.UnprocessableEntityError = UnprocessableEntityError;
|
|
11272
|
-
OpenAI.toFile = toFile;
|
|
11273
|
-
OpenAI.fileFromPath = fileFromPath;
|
|
11274
|
-
OpenAI.Completions = Completions3;
|
|
11275
|
-
OpenAI.Chat = Chat;
|
|
11276
|
-
OpenAI.ChatCompletionsPage = ChatCompletionsPage;
|
|
11277
|
-
OpenAI.Embeddings = Embeddings;
|
|
11278
|
-
OpenAI.Files = Files2;
|
|
11279
|
-
OpenAI.FileObjectsPage = FileObjectsPage;
|
|
11280
|
-
OpenAI.Images = Images;
|
|
11281
|
-
OpenAI.Audio = Audio;
|
|
11282
|
-
OpenAI.Moderations = Moderations;
|
|
11283
|
-
OpenAI.Models = Models;
|
|
11284
|
-
OpenAI.ModelsPage = ModelsPage;
|
|
11285
|
-
OpenAI.FineTuning = FineTuning;
|
|
11286
|
-
OpenAI.Graders = Graders2;
|
|
11287
|
-
OpenAI.VectorStores = VectorStores;
|
|
11288
|
-
OpenAI.VectorStoresPage = VectorStoresPage;
|
|
11289
|
-
OpenAI.VectorStoreSearchResponsesPage = VectorStoreSearchResponsesPage;
|
|
11290
|
-
OpenAI.Beta = Beta;
|
|
11291
|
-
OpenAI.Batches = Batches;
|
|
11292
|
-
OpenAI.BatchesPage = BatchesPage;
|
|
11293
|
-
OpenAI.Uploads = Uploads;
|
|
11294
|
-
OpenAI.Responses = Responses;
|
|
11295
|
-
OpenAI.Evals = Evals;
|
|
11296
|
-
OpenAI.EvalListResponsesPage = EvalListResponsesPage;
|
|
11297
|
-
OpenAI.Containers = Containers;
|
|
11298
|
-
OpenAI.ContainerListResponsesPage = ContainerListResponsesPage;
|
|
11299
|
-
var _deployments_endpoints = new Set([
|
|
11300
|
-
"/completions",
|
|
11301
|
-
"/chat/completions",
|
|
11302
|
-
"/embeddings",
|
|
11303
|
-
"/audio/transcriptions",
|
|
11304
|
-
"/audio/translations",
|
|
11305
|
-
"/audio/speech",
|
|
11306
|
-
"/images/generations",
|
|
11307
|
-
"/images/edits"
|
|
11308
|
-
]);
|
|
11309
|
-
var openai_default = OpenAI;
|
|
11310
11410
|
|
|
11311
|
-
|
|
11312
|
-
import { readFileSync } from "fs";
|
|
11313
|
-
function getClient() {
|
|
11314
|
-
const apiKey = process.env.OPENAI_API_KEY;
|
|
11315
|
-
if (!apiKey) {
|
|
11316
|
-
throw new Error("OPENAI_API_KEY environment variable is required");
|
|
11317
|
-
}
|
|
11318
|
-
return new openai_default({ apiKey });
|
|
11319
|
-
}
|
|
11320
|
-
async function uploadTrainingFile(filePath) {
|
|
11321
|
-
const client = getClient();
|
|
11322
|
-
const fileContent = readFileSync(filePath);
|
|
11323
|
-
const blob2 = new Blob([fileContent], { type: "application/jsonl" });
|
|
11324
|
-
const file = new File([blob2], filePath.split("/").pop() ?? "training.jsonl", { type: "application/jsonl" });
|
|
11325
|
-
const response = await client.files.create({
|
|
11326
|
-
file,
|
|
11327
|
-
purpose: "fine-tune"
|
|
11328
|
-
});
|
|
11329
|
-
return { fileId: response.id };
|
|
11330
|
-
}
|
|
11331
|
-
async function createFineTuneJob(fileId, baseModel, suffix) {
|
|
11332
|
-
const client = getClient();
|
|
11333
|
-
const params = {
|
|
11334
|
-
training_file: fileId,
|
|
11335
|
-
model: baseModel
|
|
11336
|
-
};
|
|
11337
|
-
if (suffix) {
|
|
11338
|
-
params.suffix = suffix;
|
|
11339
|
-
}
|
|
11340
|
-
const response = await client.fineTuning.jobs.create(params);
|
|
11341
|
-
return { jobId: response.id, status: response.status };
|
|
11342
|
-
}
|
|
11343
|
-
async function getFineTuneStatus(jobId) {
|
|
11344
|
-
const client = getClient();
|
|
11345
|
-
const response = await client.fineTuning.jobs.retrieve(jobId);
|
|
11346
|
-
return {
|
|
11347
|
-
jobId: response.id,
|
|
11348
|
-
status: response.status,
|
|
11349
|
-
fineTunedModel: response.fine_tuned_model ?? undefined,
|
|
11350
|
-
error: response.error?.message ?? undefined
|
|
11351
|
-
};
|
|
11352
|
-
}
|
|
11353
|
-
async function listFineTunedModels() {
|
|
11354
|
-
const client = getClient();
|
|
11355
|
-
const jobs = await client.fineTuning.jobs.list();
|
|
11356
|
-
return jobs.data.map((job) => ({
|
|
11357
|
-
id: job.id,
|
|
11358
|
-
model: job.fine_tuned_model ?? job.model,
|
|
11359
|
-
status: job.status,
|
|
11360
|
-
created: job.created_at
|
|
11361
|
-
}));
|
|
11411
|
+
class VectorStoreFilesPage extends CursorPage {
|
|
11362
11412
|
}
|
|
11363
11413
|
|
|
11364
|
-
|
|
11365
|
-
var DEFAULT_BASE_URL = "https://api.thinkerlabs.ai/v1";
|
|
11366
|
-
function getConfig() {
|
|
11367
|
-
const apiKey = process.env.THINKER_LABS_API_KEY;
|
|
11368
|
-
const baseUrl = process.env.THINKER_LABS_BASE_URL ?? DEFAULT_BASE_URL;
|
|
11369
|
-
if (!apiKey)
|
|
11370
|
-
throw new Error("THINKER_LABS_API_KEY environment variable is required");
|
|
11371
|
-
return { apiKey, baseUrl };
|
|
11372
|
-
}
|
|
11373
|
-
async function request(method, path, body, file) {
|
|
11374
|
-
const { apiKey, baseUrl } = getConfig();
|
|
11375
|
-
const headers = { Authorization: `Bearer ${apiKey}` };
|
|
11376
|
-
let fetchBody;
|
|
11377
|
-
if (file) {
|
|
11378
|
-
const form = new FormData;
|
|
11379
|
-
form.append("file", new Blob([file.data], { type: "text/plain" }), file.name);
|
|
11380
|
-
if (body) {
|
|
11381
|
-
for (const [k, v] of Object.entries(body)) {
|
|
11382
|
-
form.append(k, v);
|
|
11383
|
-
}
|
|
11384
|
-
}
|
|
11385
|
-
fetchBody = form;
|
|
11386
|
-
} else if (body) {
|
|
11387
|
-
headers["Content-Type"] = "application/json";
|
|
11388
|
-
fetchBody = JSON.stringify(body);
|
|
11389
|
-
}
|
|
11390
|
-
const res = await fetch(`${baseUrl}${path}`, { method, headers, body: fetchBody });
|
|
11391
|
-
if (!res.ok) {
|
|
11392
|
-
const text2 = await res.text();
|
|
11393
|
-
throw new Error(`Thinker Labs API error ${res.status}: ${text2}`);
|
|
11394
|
-
}
|
|
11395
|
-
if (res.status === 204)
|
|
11396
|
-
return;
|
|
11397
|
-
return res.json();
|
|
11398
|
-
}
|
|
11399
|
-
async function uploadTrainingData(filePath) {
|
|
11400
|
-
const fileContent = await Bun.file(filePath).text();
|
|
11401
|
-
const fileName = filePath.split("/").pop() ?? "training.jsonl";
|
|
11402
|
-
const result = await request("POST", "/datasets/upload", undefined, { name: fileName, data: fileContent });
|
|
11403
|
-
return { datasetId: result.id };
|
|
11404
|
-
}
|
|
11405
|
-
async function startFineTune(datasetId, baseModel, name) {
|
|
11406
|
-
const result = await request("POST", "/fine-tunes", {
|
|
11407
|
-
dataset_id: datasetId,
|
|
11408
|
-
base_model: baseModel,
|
|
11409
|
-
...name ? { name } : {}
|
|
11410
|
-
});
|
|
11411
|
-
return { jobId: result.id, status: result.status };
|
|
11412
|
-
}
|
|
11413
|
-
async function getStatus(jobId) {
|
|
11414
|
-
const result = await request("GET", `/fine-tunes/${jobId}`);
|
|
11415
|
-
return {
|
|
11416
|
-
jobId: result.id,
|
|
11417
|
-
status: result.status,
|
|
11418
|
-
modelId: result.model_id,
|
|
11419
|
-
error: result.error
|
|
11420
|
-
};
|
|
11421
|
-
}
|
|
11422
|
-
async function listModels() {
|
|
11423
|
-
const result = await request("GET", "/fine-tunes");
|
|
11424
|
-
return (result.data ?? []).map((m) => ({
|
|
11425
|
-
id: m.id,
|
|
11426
|
-
name: m.name,
|
|
11427
|
-
status: m.status,
|
|
11428
|
-
baseModel: m.base_model,
|
|
11429
|
-
createdAt: m.created_at
|
|
11430
|
-
}));
|
|
11414
|
+
class FileContentResponsesPage extends Page {
|
|
11431
11415
|
}
|
|
11432
|
-
|
|
11433
|
-
|
|
11416
|
+
Files3.VectorStoreFilesPage = VectorStoreFilesPage;
|
|
11417
|
+
Files3.FileContentResponsesPage = FileContentResponsesPage;
|
|
11418
|
+
|
|
11419
|
+
// node_modules/openai/resources/vector-stores/file-batches.mjs
|
|
11420
|
+
class FileBatches extends APIResource {
|
|
11421
|
+
create(vectorStoreId, body, options) {
|
|
11422
|
+
return this._client.post(`/vector_stores/${vectorStoreId}/file_batches`, {
|
|
11423
|
+
body,
|
|
11424
|
+
...options,
|
|
11425
|
+
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11426
|
+
});
|
|
11427
|
+
}
|
|
11428
|
+
retrieve(vectorStoreId, batchId, options) {
|
|
11429
|
+
return this._client.get(`/vector_stores/${vectorStoreId}/file_batches/${batchId}`, {
|
|
11430
|
+
...options,
|
|
11431
|
+
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11432
|
+
});
|
|
11433
|
+
}
|
|
11434
|
+
cancel(vectorStoreId, batchId, options) {
|
|
11435
|
+
return this._client.post(`/vector_stores/${vectorStoreId}/file_batches/${batchId}/cancel`, {
|
|
11436
|
+
...options,
|
|
11437
|
+
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11438
|
+
});
|
|
11439
|
+
}
|
|
11440
|
+
async createAndPoll(vectorStoreId, body, options) {
|
|
11441
|
+
const batch = await this.create(vectorStoreId, body);
|
|
11442
|
+
return await this.poll(vectorStoreId, batch.id, options);
|
|
11443
|
+
}
|
|
11444
|
+
listFiles(vectorStoreId, batchId, query = {}, options) {
|
|
11445
|
+
if (isRequestOptions(query)) {
|
|
11446
|
+
return this.listFiles(vectorStoreId, batchId, {}, query);
|
|
11447
|
+
}
|
|
11448
|
+
return this._client.getAPIList(`/vector_stores/${vectorStoreId}/file_batches/${batchId}/files`, VectorStoreFilesPage, { query, ...options, headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers } });
|
|
11449
|
+
}
|
|
11450
|
+
async poll(vectorStoreId, batchId, options) {
|
|
11451
|
+
const headers = { ...options?.headers, "X-Stainless-Poll-Helper": "true" };
|
|
11452
|
+
if (options?.pollIntervalMs) {
|
|
11453
|
+
headers["X-Stainless-Custom-Poll-Interval"] = options.pollIntervalMs.toString();
|
|
11454
|
+
}
|
|
11455
|
+
while (true) {
|
|
11456
|
+
const { data: batch, response } = await this.retrieve(vectorStoreId, batchId, {
|
|
11457
|
+
...options,
|
|
11458
|
+
headers
|
|
11459
|
+
}).withResponse();
|
|
11460
|
+
switch (batch.status) {
|
|
11461
|
+
case "in_progress":
|
|
11462
|
+
let sleepInterval = 5000;
|
|
11463
|
+
if (options?.pollIntervalMs) {
|
|
11464
|
+
sleepInterval = options.pollIntervalMs;
|
|
11465
|
+
} else {
|
|
11466
|
+
const headerInterval = response.headers.get("openai-poll-after-ms");
|
|
11467
|
+
if (headerInterval) {
|
|
11468
|
+
const headerIntervalMs = parseInt(headerInterval);
|
|
11469
|
+
if (!isNaN(headerIntervalMs)) {
|
|
11470
|
+
sleepInterval = headerIntervalMs;
|
|
11471
|
+
}
|
|
11472
|
+
}
|
|
11473
|
+
}
|
|
11474
|
+
await sleep(sleepInterval);
|
|
11475
|
+
break;
|
|
11476
|
+
case "failed":
|
|
11477
|
+
case "cancelled":
|
|
11478
|
+
case "completed":
|
|
11479
|
+
return batch;
|
|
11480
|
+
}
|
|
11481
|
+
}
|
|
11482
|
+
}
|
|
11483
|
+
async uploadAndPoll(vectorStoreId, { files, fileIds = [] }, options) {
|
|
11484
|
+
if (files == null || files.length == 0) {
|
|
11485
|
+
throw new Error(`No \`files\` provided to process. If you've already uploaded files you should use \`.createAndPoll()\` instead`);
|
|
11486
|
+
}
|
|
11487
|
+
const configuredConcurrency = options?.maxConcurrency ?? 5;
|
|
11488
|
+
const concurrencyLimit = Math.min(configuredConcurrency, files.length);
|
|
11489
|
+
const client = this._client;
|
|
11490
|
+
const fileIterator = files.values();
|
|
11491
|
+
const allFileIds = [...fileIds];
|
|
11492
|
+
async function processFiles(iterator) {
|
|
11493
|
+
for (let item of iterator) {
|
|
11494
|
+
const fileObj = await client.files.create({ file: item, purpose: "assistants" }, options);
|
|
11495
|
+
allFileIds.push(fileObj.id);
|
|
11496
|
+
}
|
|
11497
|
+
}
|
|
11498
|
+
const workers = Array(concurrencyLimit).fill(fileIterator).map(processFiles);
|
|
11499
|
+
await allSettledWithThrow(workers);
|
|
11500
|
+
return await this.createAndPoll(vectorStoreId, {
|
|
11501
|
+
file_ids: allFileIds
|
|
11502
|
+
});
|
|
11503
|
+
}
|
|
11434
11504
|
}
|
|
11435
11505
|
|
|
11436
|
-
|
|
11437
|
-
|
|
11438
|
-
|
|
11439
|
-
|
|
11440
|
-
|
|
11441
|
-
|
|
11442
|
-
async uploadTrainingFile(filePath) {
|
|
11443
|
-
const { datasetId } = await uploadTrainingData(filePath);
|
|
11444
|
-
return { fileId: datasetId };
|
|
11506
|
+
// node_modules/openai/resources/vector-stores/vector-stores.mjs
|
|
11507
|
+
class VectorStores extends APIResource {
|
|
11508
|
+
constructor() {
|
|
11509
|
+
super(...arguments);
|
|
11510
|
+
this.files = new Files3(this._client);
|
|
11511
|
+
this.fileBatches = new FileBatches(this._client);
|
|
11445
11512
|
}
|
|
11446
|
-
|
|
11447
|
-
return
|
|
11513
|
+
create(body, options) {
|
|
11514
|
+
return this._client.post("/vector_stores", {
|
|
11515
|
+
body,
|
|
11516
|
+
...options,
|
|
11517
|
+
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11518
|
+
});
|
|
11448
11519
|
}
|
|
11449
|
-
|
|
11450
|
-
|
|
11451
|
-
|
|
11520
|
+
retrieve(vectorStoreId, options) {
|
|
11521
|
+
return this._client.get(`/vector_stores/${vectorStoreId}`, {
|
|
11522
|
+
...options,
|
|
11523
|
+
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11524
|
+
});
|
|
11452
11525
|
}
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11526
|
+
update(vectorStoreId, body, options) {
|
|
11527
|
+
return this._client.post(`/vector_stores/${vectorStoreId}`, {
|
|
11528
|
+
body,
|
|
11529
|
+
...options,
|
|
11530
|
+
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11531
|
+
});
|
|
11456
11532
|
}
|
|
11457
|
-
|
|
11458
|
-
|
|
11533
|
+
list(query = {}, options) {
|
|
11534
|
+
if (isRequestOptions(query)) {
|
|
11535
|
+
return this.list({}, query);
|
|
11536
|
+
}
|
|
11537
|
+
return this._client.getAPIList("/vector_stores", VectorStoresPage, {
|
|
11538
|
+
query,
|
|
11539
|
+
...options,
|
|
11540
|
+
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11541
|
+
});
|
|
11459
11542
|
}
|
|
11460
|
-
|
|
11461
|
-
|
|
11462
|
-
|
|
11463
|
-
|
|
11464
|
-
|
|
11465
|
-
if (rows.length === 0) {
|
|
11466
|
-
console.log(chalk.dim(" (no records)"));
|
|
11467
|
-
return;
|
|
11543
|
+
del(vectorStoreId, options) {
|
|
11544
|
+
return this._client.delete(`/vector_stores/${vectorStoreId}`, {
|
|
11545
|
+
...options,
|
|
11546
|
+
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11547
|
+
});
|
|
11468
11548
|
}
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
console.log("\u2502" + headerLine + "\u2502");
|
|
11477
|
-
console.log("\u251C" + midBorder + "\u2524");
|
|
11478
|
-
for (const row of rows) {
|
|
11479
|
-
const rowLine = row.map((cell, i) => ` ${(cell ?? "").padEnd(colWidths[i] ?? 0)} `).join("\u2502");
|
|
11480
|
-
console.log("\u2502" + rowLine + "\u2502");
|
|
11549
|
+
search(vectorStoreId, body, options) {
|
|
11550
|
+
return this._client.getAPIList(`/vector_stores/${vectorStoreId}/search`, VectorStoreSearchResponsesPage, {
|
|
11551
|
+
body,
|
|
11552
|
+
method: "post",
|
|
11553
|
+
...options,
|
|
11554
|
+
headers: { "OpenAI-Beta": "assistants=v2", ...options?.headers }
|
|
11555
|
+
});
|
|
11481
11556
|
}
|
|
11482
|
-
console.log("\u2514" + bottomBorder + "\u2518");
|
|
11483
|
-
}
|
|
11484
|
-
var STATUS_COLORS = {
|
|
11485
|
-
succeeded: chalk.green,
|
|
11486
|
-
running: chalk.cyan,
|
|
11487
|
-
pending: chalk.yellow,
|
|
11488
|
-
failed: chalk.red,
|
|
11489
|
-
cancelled: chalk.dim,
|
|
11490
|
-
queued: chalk.yellow,
|
|
11491
|
-
validating_files: chalk.blue
|
|
11492
|
-
};
|
|
11493
|
-
function printStatus(status) {
|
|
11494
|
-
const colorFn = STATUS_COLORS[status] ?? chalk.white;
|
|
11495
|
-
return colorFn(`\u25CF ${status}`);
|
|
11496
|
-
}
|
|
11497
|
-
function printJson(obj) {
|
|
11498
|
-
console.log(JSON.stringify(obj, null, 2));
|
|
11499
|
-
}
|
|
11500
|
-
function printError(message) {
|
|
11501
|
-
console.error(chalk.red("\u2717 Error: ") + message);
|
|
11502
|
-
}
|
|
11503
|
-
function printSuccess(message) {
|
|
11504
|
-
console.log(chalk.green("\u2713 ") + message);
|
|
11505
|
-
}
|
|
11506
|
-
function printInfo(message) {
|
|
11507
|
-
console.log(chalk.dim(" " + message));
|
|
11508
11557
|
}
|
|
11509
11558
|
|
|
11510
|
-
|
|
11511
|
-
import { Database as Database3 } from "bun:sqlite";
|
|
11512
|
-
import { homedir as homedir2 } from "os";
|
|
11513
|
-
import { join as join2 } from "path";
|
|
11514
|
-
var SYSTEM_PROMPT = "You are a task management assistant that helps users create, update, search, and manage tasks and projects.";
|
|
11515
|
-
function taskToCreateExample(task) {
|
|
11516
|
-
const userMsg = `Create a task: ${task.title}${task.description ? `
|
|
11517
|
-
|
|
11518
|
-
Description: ${task.description}` : ""}`;
|
|
11519
|
-
const taskDetails = {
|
|
11520
|
-
id: task.short_id ?? task.id,
|
|
11521
|
-
title: task.title,
|
|
11522
|
-
description: task.description ?? "",
|
|
11523
|
-
status: task.status,
|
|
11524
|
-
priority: task.priority,
|
|
11525
|
-
tags: JSON.parse(task.tags ?? "[]"),
|
|
11526
|
-
created_at: task.created_at
|
|
11527
|
-
};
|
|
11528
|
-
return {
|
|
11529
|
-
messages: [
|
|
11530
|
-
{ role: "system", content: SYSTEM_PROMPT },
|
|
11531
|
-
{ role: "user", content: userMsg },
|
|
11532
|
-
{ role: "assistant", content: `Created task: ${JSON.stringify(taskDetails, null, 2)}` }
|
|
11533
|
-
]
|
|
11534
|
-
};
|
|
11535
|
-
}
|
|
11536
|
-
function taskToStatusUpdateExample(task) {
|
|
11537
|
-
if (!task.completed_at && task.status === "pending")
|
|
11538
|
-
return null;
|
|
11539
|
-
const id = task.short_id ?? task.id;
|
|
11540
|
-
return {
|
|
11541
|
-
messages: [
|
|
11542
|
-
{ role: "system", content: SYSTEM_PROMPT },
|
|
11543
|
-
{ role: "user", content: `Mark task ${id} as ${task.status}` },
|
|
11544
|
-
{ role: "assistant", content: `Task ${id} has been updated to status: ${task.status}. ${task.completed_at ? `Completed at: ${task.completed_at}` : ""}`.trim() }
|
|
11545
|
-
]
|
|
11546
|
-
};
|
|
11559
|
+
class VectorStoresPage extends CursorPage {
|
|
11547
11560
|
}
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
return {
|
|
11551
|
-
messages: [
|
|
11552
|
-
{ role: "system", content: SYSTEM_PROMPT },
|
|
11553
|
-
{ role: "user", content: `Search tasks for: "${query}"` },
|
|
11554
|
-
{
|
|
11555
|
-
role: "assistant",
|
|
11556
|
-
content: matched.length > 0 ? `Found ${matched.length} task(s):
|
|
11557
|
-
${matched.map((t) => `- [${t.short_id ?? t.id}] ${t.title} (${t.status})`).join(`
|
|
11558
|
-
`)}` : `No tasks found matching "${query}".`
|
|
11559
|
-
}
|
|
11560
|
-
]
|
|
11561
|
-
};
|
|
11561
|
+
|
|
11562
|
+
class VectorStoreSearchResponsesPage extends Page {
|
|
11562
11563
|
}
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
if (
|
|
11575
|
-
|
|
11576
|
-
params.push(options.limit * 2);
|
|
11577
|
-
}
|
|
11578
|
-
const tasks = db.query(query).all(...params);
|
|
11579
|
-
const examples = [];
|
|
11580
|
-
for (const task of tasks) {
|
|
11581
|
-
examples.push(taskToCreateExample(task));
|
|
11582
|
-
const statusEx = taskToStatusUpdateExample(task);
|
|
11583
|
-
if (statusEx)
|
|
11584
|
-
examples.push(statusEx);
|
|
11564
|
+
VectorStores.VectorStoresPage = VectorStoresPage;
|
|
11565
|
+
VectorStores.VectorStoreSearchResponsesPage = VectorStoreSearchResponsesPage;
|
|
11566
|
+
VectorStores.Files = Files3;
|
|
11567
|
+
VectorStores.VectorStoreFilesPage = VectorStoreFilesPage;
|
|
11568
|
+
VectorStores.FileContentResponsesPage = FileContentResponsesPage;
|
|
11569
|
+
VectorStores.FileBatches = FileBatches;
|
|
11570
|
+
// node_modules/openai/index.mjs
|
|
11571
|
+
var _a;
|
|
11572
|
+
|
|
11573
|
+
class OpenAI extends APIClient {
|
|
11574
|
+
constructor({ baseURL = readEnv("OPENAI_BASE_URL"), apiKey = readEnv("OPENAI_API_KEY"), organization = readEnv("OPENAI_ORG_ID") ?? null, project = readEnv("OPENAI_PROJECT_ID") ?? null, ...opts } = {}) {
|
|
11575
|
+
if (apiKey === undefined) {
|
|
11576
|
+
throw new OpenAIError("The OPENAI_API_KEY environment variable is missing or empty; either provide it, or instantiate the OpenAI client with an apiKey option, like new OpenAI({ apiKey: 'My API Key' }).");
|
|
11585
11577
|
}
|
|
11586
|
-
const
|
|
11587
|
-
|
|
11588
|
-
|
|
11578
|
+
const options = {
|
|
11579
|
+
apiKey,
|
|
11580
|
+
organization,
|
|
11581
|
+
project,
|
|
11582
|
+
...opts,
|
|
11583
|
+
baseURL: baseURL || `https://api.openai.com/v1`
|
|
11584
|
+
};
|
|
11585
|
+
if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {
|
|
11586
|
+
throw new OpenAIError(`It looks like you're running in a browser-like environment.
|
|
11587
|
+
|
|
11588
|
+
This is disabled by default, as it risks exposing your secret API credentials to attackers.
|
|
11589
|
+
If you understand the risks and have appropriate mitigations in place,
|
|
11590
|
+
you can set the \`dangerouslyAllowBrowser\` option to \`true\`, e.g.,
|
|
11591
|
+
|
|
11592
|
+
new OpenAI({ apiKey, dangerouslyAllowBrowser: true });
|
|
11593
|
+
|
|
11594
|
+
https://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety
|
|
11595
|
+
`);
|
|
11589
11596
|
}
|
|
11590
|
-
|
|
11597
|
+
super({
|
|
11598
|
+
baseURL: options.baseURL,
|
|
11599
|
+
timeout: options.timeout ?? 600000,
|
|
11600
|
+
httpAgent: options.httpAgent,
|
|
11601
|
+
maxRetries: options.maxRetries,
|
|
11602
|
+
fetch: options.fetch
|
|
11603
|
+
});
|
|
11604
|
+
this.completions = new Completions3(this);
|
|
11605
|
+
this.chat = new Chat(this);
|
|
11606
|
+
this.embeddings = new Embeddings(this);
|
|
11607
|
+
this.files = new Files2(this);
|
|
11608
|
+
this.images = new Images(this);
|
|
11609
|
+
this.audio = new Audio(this);
|
|
11610
|
+
this.moderations = new Moderations(this);
|
|
11611
|
+
this.models = new Models(this);
|
|
11612
|
+
this.fineTuning = new FineTuning(this);
|
|
11613
|
+
this.graders = new Graders2(this);
|
|
11614
|
+
this.vectorStores = new VectorStores(this);
|
|
11615
|
+
this.beta = new Beta(this);
|
|
11616
|
+
this.batches = new Batches(this);
|
|
11617
|
+
this.uploads = new Uploads(this);
|
|
11618
|
+
this.responses = new Responses(this);
|
|
11619
|
+
this.evals = new Evals(this);
|
|
11620
|
+
this.containers = new Containers(this);
|
|
11621
|
+
this._options = options;
|
|
11622
|
+
this.apiKey = apiKey;
|
|
11623
|
+
this.organization = organization;
|
|
11624
|
+
this.project = project;
|
|
11625
|
+
}
|
|
11626
|
+
defaultQuery() {
|
|
11627
|
+
return this._options.defaultQuery;
|
|
11628
|
+
}
|
|
11629
|
+
defaultHeaders(opts) {
|
|
11591
11630
|
return {
|
|
11592
|
-
|
|
11593
|
-
|
|
11594
|
-
|
|
11631
|
+
...super.defaultHeaders(opts),
|
|
11632
|
+
"OpenAI-Organization": this.organization,
|
|
11633
|
+
"OpenAI-Project": this.project,
|
|
11634
|
+
...this._options.defaultHeaders
|
|
11595
11635
|
};
|
|
11596
|
-
}
|
|
11597
|
-
|
|
11636
|
+
}
|
|
11637
|
+
authHeaders(opts) {
|
|
11638
|
+
return { Authorization: `Bearer ${this.apiKey}` };
|
|
11639
|
+
}
|
|
11640
|
+
stringifyQuery(query) {
|
|
11641
|
+
return stringify(query, { arrayFormat: "brackets" });
|
|
11598
11642
|
}
|
|
11599
11643
|
}
|
|
11644
|
+
_a = OpenAI;
|
|
11645
|
+
OpenAI.OpenAI = _a;
|
|
11646
|
+
OpenAI.DEFAULT_TIMEOUT = 600000;
|
|
11647
|
+
OpenAI.OpenAIError = OpenAIError;
|
|
11648
|
+
OpenAI.APIError = APIError;
|
|
11649
|
+
OpenAI.APIConnectionError = APIConnectionError;
|
|
11650
|
+
OpenAI.APIConnectionTimeoutError = APIConnectionTimeoutError;
|
|
11651
|
+
OpenAI.APIUserAbortError = APIUserAbortError;
|
|
11652
|
+
OpenAI.NotFoundError = NotFoundError;
|
|
11653
|
+
OpenAI.ConflictError = ConflictError;
|
|
11654
|
+
OpenAI.RateLimitError = RateLimitError;
|
|
11655
|
+
OpenAI.BadRequestError = BadRequestError;
|
|
11656
|
+
OpenAI.AuthenticationError = AuthenticationError;
|
|
11657
|
+
OpenAI.InternalServerError = InternalServerError;
|
|
11658
|
+
OpenAI.PermissionDeniedError = PermissionDeniedError;
|
|
11659
|
+
OpenAI.UnprocessableEntityError = UnprocessableEntityError;
|
|
11660
|
+
OpenAI.toFile = toFile;
|
|
11661
|
+
OpenAI.fileFromPath = fileFromPath;
|
|
11662
|
+
OpenAI.Completions = Completions3;
|
|
11663
|
+
OpenAI.Chat = Chat;
|
|
11664
|
+
OpenAI.ChatCompletionsPage = ChatCompletionsPage;
|
|
11665
|
+
OpenAI.Embeddings = Embeddings;
|
|
11666
|
+
OpenAI.Files = Files2;
|
|
11667
|
+
OpenAI.FileObjectsPage = FileObjectsPage;
|
|
11668
|
+
OpenAI.Images = Images;
|
|
11669
|
+
OpenAI.Audio = Audio;
|
|
11670
|
+
OpenAI.Moderations = Moderations;
|
|
11671
|
+
OpenAI.Models = Models;
|
|
11672
|
+
OpenAI.ModelsPage = ModelsPage;
|
|
11673
|
+
OpenAI.FineTuning = FineTuning;
|
|
11674
|
+
OpenAI.Graders = Graders2;
|
|
11675
|
+
OpenAI.VectorStores = VectorStores;
|
|
11676
|
+
OpenAI.VectorStoresPage = VectorStoresPage;
|
|
11677
|
+
OpenAI.VectorStoreSearchResponsesPage = VectorStoreSearchResponsesPage;
|
|
11678
|
+
OpenAI.Beta = Beta;
|
|
11679
|
+
OpenAI.Batches = Batches;
|
|
11680
|
+
OpenAI.BatchesPage = BatchesPage;
|
|
11681
|
+
OpenAI.Uploads = Uploads;
|
|
11682
|
+
OpenAI.Responses = Responses;
|
|
11683
|
+
OpenAI.Evals = Evals;
|
|
11684
|
+
OpenAI.EvalListResponsesPage = EvalListResponsesPage;
|
|
11685
|
+
OpenAI.Containers = Containers;
|
|
11686
|
+
OpenAI.ContainerListResponsesPage = ContainerListResponsesPage;
|
|
11687
|
+
var _deployments_endpoints = new Set([
|
|
11688
|
+
"/completions",
|
|
11689
|
+
"/chat/completions",
|
|
11690
|
+
"/embeddings",
|
|
11691
|
+
"/audio/transcriptions",
|
|
11692
|
+
"/audio/translations",
|
|
11693
|
+
"/audio/speech",
|
|
11694
|
+
"/images/generations",
|
|
11695
|
+
"/images/edits"
|
|
11696
|
+
]);
|
|
11697
|
+
var openai_default = OpenAI;
|
|
11600
11698
|
|
|
11601
|
-
// src/lib/
|
|
11602
|
-
import {
|
|
11603
|
-
import { homedir as homedir3 } from "os";
|
|
11604
|
-
import { join as join3 } from "path";
|
|
11605
|
-
var SYSTEM_PROMPT2 = "You are an AI assistant with persistent memory. You can remember and recall information across sessions to provide better, more personalized assistance.";
|
|
11606
|
-
function memoryToRecallExample(memory) {
|
|
11607
|
-
return {
|
|
11608
|
-
messages: [
|
|
11609
|
-
{ role: "system", content: SYSTEM_PROMPT2 },
|
|
11610
|
-
{ role: "user", content: `What do you remember about "${memory.key}"?` },
|
|
11611
|
-
{
|
|
11612
|
-
role: "assistant",
|
|
11613
|
-
content: memory.summary ? `${memory.value}
|
|
11699
|
+
// src/lib/providers/openai.ts
|
|
11700
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
11614
11701
|
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11702
|
+
// src/lib/config.ts
|
|
11703
|
+
import { readFileSync, writeFileSync, mkdirSync as mkdirSync2, existsSync } from "fs";
|
|
11704
|
+
import { join as join2, dirname as dirname2 } from "path";
|
|
11705
|
+
import { homedir as homedir2 } from "os";
|
|
11706
|
+
var CONFIG_KEYS = ["OPENAI_API_KEY", "THINKER_LABS_API_KEY", "THINKER_LABS_BASE_URL"];
|
|
11707
|
+
var CONFIG_PATH = join2(homedir2(), ".brains", "config.json");
|
|
11708
|
+
function readConfigFile() {
|
|
11709
|
+
if (!existsSync(CONFIG_PATH))
|
|
11710
|
+
return {};
|
|
11711
|
+
try {
|
|
11712
|
+
return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
11713
|
+
} catch {
|
|
11714
|
+
return {};
|
|
11715
|
+
}
|
|
11619
11716
|
}
|
|
11620
|
-
function
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
|
|
11625
|
-
|
|
11626
|
-
|
|
11627
|
-
|
|
11628
|
-
|
|
11629
|
-
|
|
11630
|
-
|
|
11631
|
-
|
|
11632
|
-
|
|
11633
|
-
|
|
11634
|
-
|
|
11717
|
+
function writeConfigFile(data) {
|
|
11718
|
+
mkdirSync2(dirname2(CONFIG_PATH), { recursive: true });
|
|
11719
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(data, null, 2) + `
|
|
11720
|
+
`, "utf-8");
|
|
11721
|
+
}
|
|
11722
|
+
function getConfigValue(key) {
|
|
11723
|
+
if (process.env[key])
|
|
11724
|
+
return process.env[key];
|
|
11725
|
+
return readConfigFile()[key];
|
|
11726
|
+
}
|
|
11727
|
+
function setConfigValue(key, value) {
|
|
11728
|
+
const data = readConfigFile();
|
|
11729
|
+
data[key] = value;
|
|
11730
|
+
writeConfigFile(data);
|
|
11731
|
+
}
|
|
11732
|
+
function listConfig() {
|
|
11733
|
+
const file = readConfigFile();
|
|
11734
|
+
return CONFIG_KEYS.map((key) => {
|
|
11735
|
+
if (process.env[key])
|
|
11736
|
+
return { key, value: process.env[key], source: "env" };
|
|
11737
|
+
if (file[key])
|
|
11738
|
+
return { key, value: file[key], source: "file" };
|
|
11739
|
+
return { key, value: "", source: "unset" };
|
|
11740
|
+
});
|
|
11635
11741
|
}
|
|
11636
|
-
function
|
|
11637
|
-
const
|
|
11638
|
-
|
|
11639
|
-
|
|
11640
|
-
{ role: "system", content: SYSTEM_PROMPT2 },
|
|
11641
|
-
{ role: "user", content: `What ${category} memories do you have?` },
|
|
11642
|
-
{
|
|
11643
|
-
role: "assistant",
|
|
11644
|
-
content: matched.length > 0 ? `Here are my ${category} memories:
|
|
11645
|
-
${matched.map((m) => `- ${m.key}: ${m.value.slice(0, 120)}${m.value.length > 120 ? "..." : ""}`).join(`
|
|
11646
|
-
`)}` : `I don't have any ${category} memories stored yet.`
|
|
11647
|
-
}
|
|
11648
|
-
]
|
|
11649
|
-
};
|
|
11742
|
+
function deleteConfigValue(key) {
|
|
11743
|
+
const data = readConfigFile();
|
|
11744
|
+
delete data[key];
|
|
11745
|
+
writeConfigFile(data);
|
|
11650
11746
|
}
|
|
11651
|
-
|
|
11652
|
-
|
|
11653
|
-
|
|
11654
|
-
|
|
11655
|
-
|
|
11656
|
-
|
|
11657
|
-
|
|
11658
|
-
query += " AND created_at >= ?";
|
|
11659
|
-
params.push(options.since.toISOString());
|
|
11747
|
+
|
|
11748
|
+
// src/lib/retry.ts
|
|
11749
|
+
var RETRYABLE_STATUS_CODES = new Set([429, 500, 502, 503, 504]);
|
|
11750
|
+
function isRetryableError(err) {
|
|
11751
|
+
if (err instanceof Error) {
|
|
11752
|
+
if (err.message.includes("fetch failed") || err.message.includes("ECONNRESET") || err.message.includes("ETIMEDOUT")) {
|
|
11753
|
+
return true;
|
|
11660
11754
|
}
|
|
11661
|
-
|
|
11662
|
-
if (
|
|
11663
|
-
|
|
11664
|
-
|
|
11755
|
+
const match = err.message.match(/^(\d{3})\s/);
|
|
11756
|
+
if (match) {
|
|
11757
|
+
const status = parseInt(match[1], 10);
|
|
11758
|
+
return RETRYABLE_STATUS_CODES.has(status);
|
|
11665
11759
|
}
|
|
11666
|
-
const
|
|
11667
|
-
|
|
11668
|
-
|
|
11669
|
-
|
|
11670
|
-
examples.push(memoryToSaveExample(memory));
|
|
11760
|
+
const tlMatch = err.message.match(/API error (\d{3})/);
|
|
11761
|
+
if (tlMatch) {
|
|
11762
|
+
const status = parseInt(tlMatch[1], 10);
|
|
11763
|
+
return RETRYABLE_STATUS_CODES.has(status);
|
|
11671
11764
|
}
|
|
11672
|
-
|
|
11673
|
-
|
|
11674
|
-
|
|
11765
|
+
}
|
|
11766
|
+
return false;
|
|
11767
|
+
}
|
|
11768
|
+
async function withRetry(fn, options = {}) {
|
|
11769
|
+
const { maxAttempts = 3, baseDelayMs = 1000, onRetry } = options;
|
|
11770
|
+
let lastError = new Error("Unknown error");
|
|
11771
|
+
for (let attempt = 1;attempt <= maxAttempts; attempt++) {
|
|
11772
|
+
try {
|
|
11773
|
+
return await fn();
|
|
11774
|
+
} catch (err) {
|
|
11775
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
11776
|
+
if (attempt === maxAttempts || !isRetryableError(lastError)) {
|
|
11777
|
+
throw lastError;
|
|
11778
|
+
}
|
|
11779
|
+
const delayMs = baseDelayMs * Math.pow(2, attempt - 1);
|
|
11780
|
+
onRetry?.(attempt, delayMs, lastError);
|
|
11781
|
+
await new Promise((resolve2) => setTimeout(resolve2, delayMs));
|
|
11675
11782
|
}
|
|
11676
|
-
const finalExamples = options.limit ? examples.slice(0, options.limit) : examples;
|
|
11677
|
-
return {
|
|
11678
|
-
source: "mementos",
|
|
11679
|
-
examples: finalExamples,
|
|
11680
|
-
count: finalExamples.length
|
|
11681
|
-
};
|
|
11682
|
-
} finally {
|
|
11683
|
-
db.close();
|
|
11684
11783
|
}
|
|
11784
|
+
throw lastError;
|
|
11685
11785
|
}
|
|
11686
11786
|
|
|
11687
|
-
// src/lib/
|
|
11688
|
-
|
|
11689
|
-
|
|
11690
|
-
|
|
11691
|
-
|
|
11692
|
-
function windowToExample(window2) {
|
|
11693
|
-
if (window2.length < 2)
|
|
11694
|
-
return null;
|
|
11695
|
-
const messages = [
|
|
11696
|
-
{ role: "system", content: SYSTEM_PROMPT3 }
|
|
11697
|
-
];
|
|
11698
|
-
for (let i = 0;i < window2.length - 1; i++) {
|
|
11699
|
-
const msg = window2[i];
|
|
11700
|
-
if (!msg)
|
|
11701
|
-
continue;
|
|
11702
|
-
const role = i % 2 === 0 ? "user" : "assistant";
|
|
11703
|
-
messages.push({
|
|
11704
|
-
role,
|
|
11705
|
-
content: `[${msg.from_agent} \u2192 ${msg.to_agent ?? msg.space ?? "all"}]: ${msg.content}`
|
|
11706
|
-
});
|
|
11787
|
+
// src/lib/providers/openai.ts
|
|
11788
|
+
function getClient() {
|
|
11789
|
+
const apiKey = getConfigValue("OPENAI_API_KEY");
|
|
11790
|
+
if (!apiKey) {
|
|
11791
|
+
throw new Error("OPENAI_API_KEY is not set. Run: brains config set OPENAI_API_KEY <key>");
|
|
11707
11792
|
}
|
|
11708
|
-
|
|
11709
|
-
|
|
11710
|
-
|
|
11711
|
-
|
|
11712
|
-
|
|
11713
|
-
|
|
11793
|
+
return new openai_default({ apiKey });
|
|
11794
|
+
}
|
|
11795
|
+
async function uploadTrainingFile(filePath) {
|
|
11796
|
+
return withRetry(async () => {
|
|
11797
|
+
const client = getClient();
|
|
11798
|
+
const fileContent = readFileSync2(filePath);
|
|
11799
|
+
const blob2 = new Blob([fileContent], { type: "application/jsonl" });
|
|
11800
|
+
const file = new File([blob2], filePath.split("/").pop() ?? "training.jsonl", { type: "application/jsonl" });
|
|
11801
|
+
const response = await client.files.create({ file, purpose: "fine-tune" });
|
|
11802
|
+
return { fileId: response.id };
|
|
11714
11803
|
});
|
|
11715
|
-
return { messages };
|
|
11716
11804
|
}
|
|
11717
|
-
async function
|
|
11718
|
-
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
|
|
11722
|
-
|
|
11723
|
-
|
|
11724
|
-
|
|
11725
|
-
|
|
11726
|
-
|
|
11727
|
-
|
|
11728
|
-
|
|
11729
|
-
const
|
|
11730
|
-
|
|
11731
|
-
const msgs = sessions.get(msg.session_id) ?? [];
|
|
11732
|
-
msgs.push(msg);
|
|
11733
|
-
sessions.set(msg.session_id, msgs);
|
|
11734
|
-
}
|
|
11735
|
-
const examples = [];
|
|
11736
|
-
const windowSize = 4;
|
|
11737
|
-
for (const [, sessionMsgs] of sessions) {
|
|
11738
|
-
if (sessionMsgs.length < 2)
|
|
11739
|
-
continue;
|
|
11740
|
-
for (let start = 0;start <= sessionMsgs.length - 2; start++) {
|
|
11741
|
-
const end = Math.min(start + windowSize, sessionMsgs.length);
|
|
11742
|
-
const window2 = sessionMsgs.slice(start, end);
|
|
11743
|
-
const example = windowToExample(window2);
|
|
11744
|
-
if (example)
|
|
11745
|
-
examples.push(example);
|
|
11746
|
-
}
|
|
11747
|
-
}
|
|
11748
|
-
const finalExamples = options.limit ? examples.slice(0, options.limit) : examples;
|
|
11805
|
+
async function createFineTuneJob(fileId, baseModel, suffix) {
|
|
11806
|
+
return withRetry(async () => {
|
|
11807
|
+
const client = getClient();
|
|
11808
|
+
const params = { training_file: fileId, model: baseModel };
|
|
11809
|
+
if (suffix)
|
|
11810
|
+
params.suffix = suffix;
|
|
11811
|
+
const response = await client.fineTuning.jobs.create(params);
|
|
11812
|
+
return { jobId: response.id, status: response.status };
|
|
11813
|
+
});
|
|
11814
|
+
}
|
|
11815
|
+
async function getFineTuneStatus(jobId) {
|
|
11816
|
+
return withRetry(async () => {
|
|
11817
|
+
const client = getClient();
|
|
11818
|
+
const response = await client.fineTuning.jobs.retrieve(jobId);
|
|
11749
11819
|
return {
|
|
11750
|
-
|
|
11751
|
-
|
|
11752
|
-
|
|
11820
|
+
jobId: response.id,
|
|
11821
|
+
status: response.status,
|
|
11822
|
+
fineTunedModel: response.fine_tuned_model ?? undefined,
|
|
11823
|
+
baseModel: response.model ?? undefined,
|
|
11824
|
+
error: response.error?.message ?? undefined
|
|
11753
11825
|
};
|
|
11754
|
-
}
|
|
11755
|
-
|
|
11826
|
+
});
|
|
11827
|
+
}
|
|
11828
|
+
async function listFineTunedModels() {
|
|
11829
|
+
return withRetry(async () => {
|
|
11830
|
+
const client = getClient();
|
|
11831
|
+
const jobs = await client.fineTuning.jobs.list();
|
|
11832
|
+
return jobs.data.map((job) => ({
|
|
11833
|
+
id: job.id,
|
|
11834
|
+
model: job.fine_tuned_model ?? job.model,
|
|
11835
|
+
status: job.status,
|
|
11836
|
+
created: job.created_at
|
|
11837
|
+
}));
|
|
11838
|
+
});
|
|
11839
|
+
}
|
|
11840
|
+
|
|
11841
|
+
// src/lib/providers/thinker-labs.ts
|
|
11842
|
+
var DEFAULT_BASE_URL = "https://api.thinkerlabs.ai/v1";
|
|
11843
|
+
function getConfig() {
|
|
11844
|
+
const apiKey = getConfigValue("THINKER_LABS_API_KEY");
|
|
11845
|
+
const baseUrl = getConfigValue("THINKER_LABS_BASE_URL") ?? DEFAULT_BASE_URL;
|
|
11846
|
+
if (!apiKey)
|
|
11847
|
+
throw new Error("THINKER_LABS_API_KEY is not set. Run: brains config set THINKER_LABS_API_KEY <key>");
|
|
11848
|
+
return { apiKey, baseUrl };
|
|
11849
|
+
}
|
|
11850
|
+
async function request(method, path, body, file) {
|
|
11851
|
+
return withRetry(async () => {
|
|
11852
|
+
const { apiKey, baseUrl } = getConfig();
|
|
11853
|
+
const headers = { Authorization: `Bearer ${apiKey}` };
|
|
11854
|
+
let fetchBody;
|
|
11855
|
+
if (file) {
|
|
11856
|
+
const form = new FormData;
|
|
11857
|
+
form.append("file", new Blob([file.data], { type: "text/plain" }), file.name);
|
|
11858
|
+
if (body) {
|
|
11859
|
+
for (const [k, v] of Object.entries(body)) {
|
|
11860
|
+
form.append(k, v);
|
|
11861
|
+
}
|
|
11862
|
+
}
|
|
11863
|
+
fetchBody = form;
|
|
11864
|
+
} else if (body) {
|
|
11865
|
+
headers["Content-Type"] = "application/json";
|
|
11866
|
+
fetchBody = JSON.stringify(body);
|
|
11867
|
+
}
|
|
11868
|
+
const res = await fetch(`${baseUrl}${path}`, { method, headers, body: fetchBody });
|
|
11869
|
+
if (!res.ok) {
|
|
11870
|
+
const text2 = await res.text();
|
|
11871
|
+
throw new Error(`Thinker Labs API error ${res.status}: ${text2}`);
|
|
11872
|
+
}
|
|
11873
|
+
if (res.status === 204)
|
|
11874
|
+
return;
|
|
11875
|
+
return res.json();
|
|
11876
|
+
});
|
|
11877
|
+
}
|
|
11878
|
+
async function uploadTrainingData(filePath) {
|
|
11879
|
+
const fileContent = await Bun.file(filePath).text();
|
|
11880
|
+
const fileName = filePath.split("/").pop() ?? "training.jsonl";
|
|
11881
|
+
const result = await request("POST", "/datasets/upload", undefined, { name: fileName, data: fileContent });
|
|
11882
|
+
return { datasetId: result.id };
|
|
11883
|
+
}
|
|
11884
|
+
async function startFineTune(datasetId, baseModel, name) {
|
|
11885
|
+
const result = await request("POST", "/fine-tunes", {
|
|
11886
|
+
dataset_id: datasetId,
|
|
11887
|
+
base_model: baseModel,
|
|
11888
|
+
...name ? { name } : {}
|
|
11889
|
+
});
|
|
11890
|
+
return { jobId: result.id, status: result.status };
|
|
11891
|
+
}
|
|
11892
|
+
async function getStatus(jobId) {
|
|
11893
|
+
const result = await request("GET", `/fine-tunes/${jobId}`);
|
|
11894
|
+
return {
|
|
11895
|
+
jobId: result.id,
|
|
11896
|
+
status: result.status,
|
|
11897
|
+
modelId: result.model_id,
|
|
11898
|
+
error: result.error
|
|
11899
|
+
};
|
|
11900
|
+
}
|
|
11901
|
+
async function listModels() {
|
|
11902
|
+
const result = await request("GET", "/fine-tunes");
|
|
11903
|
+
return (result.data ?? []).map((m) => ({
|
|
11904
|
+
id: m.id,
|
|
11905
|
+
name: m.name,
|
|
11906
|
+
status: m.status,
|
|
11907
|
+
baseModel: m.base_model,
|
|
11908
|
+
createdAt: m.created_at
|
|
11909
|
+
}));
|
|
11910
|
+
}
|
|
11911
|
+
async function cancelJob(jobId) {
|
|
11912
|
+
await request("DELETE", `/fine-tunes/${jobId}`);
|
|
11913
|
+
}
|
|
11914
|
+
|
|
11915
|
+
class ThinkerLabsProvider {
|
|
11916
|
+
uploadTrainingData = uploadTrainingData;
|
|
11917
|
+
startFineTune = startFineTune;
|
|
11918
|
+
getStatus = getStatus;
|
|
11919
|
+
listModels = listModels;
|
|
11920
|
+
cancelJob = cancelJob;
|
|
11921
|
+
async uploadTrainingFile(filePath) {
|
|
11922
|
+
const { datasetId } = await uploadTrainingData(filePath);
|
|
11923
|
+
return { fileId: datasetId };
|
|
11924
|
+
}
|
|
11925
|
+
async createFineTuneJob(fileId, baseModel, suffix) {
|
|
11926
|
+
return startFineTune(fileId, baseModel, suffix);
|
|
11927
|
+
}
|
|
11928
|
+
async getFineTuneStatus(jobId) {
|
|
11929
|
+
const result = await getStatus(jobId);
|
|
11930
|
+
return { jobId: result.jobId, status: result.status, fineTunedModel: result.modelId, error: result.error };
|
|
11931
|
+
}
|
|
11932
|
+
async listFineTunedModels() {
|
|
11933
|
+
const models = await listModels();
|
|
11934
|
+
return models.map((m) => ({ id: m.id, model: m.baseModel, status: m.status, created: m.createdAt }));
|
|
11935
|
+
}
|
|
11936
|
+
async cancelFineTuneJob(jobId) {
|
|
11937
|
+
return cancelJob(jobId);
|
|
11756
11938
|
}
|
|
11757
11939
|
}
|
|
11758
11940
|
|
|
11759
|
-
// src/
|
|
11760
|
-
import
|
|
11761
|
-
|
|
11762
|
-
|
|
11763
|
-
|
|
11764
|
-
|
|
11765
|
-
function extractText(content) {
|
|
11766
|
-
if (typeof content === "string")
|
|
11767
|
-
return content;
|
|
11768
|
-
return content.filter((c) => c.type === "text" && c.text).map((c) => c.text).join(`
|
|
11769
|
-
`).trim();
|
|
11770
|
-
}
|
|
11771
|
-
async function gatherFromSessions(options = {}) {
|
|
11772
|
-
const { limit: limit2 = 1000 } = options;
|
|
11773
|
-
const examples = [];
|
|
11774
|
-
const claudeDir = join5(homedir5(), ".claude", "projects");
|
|
11775
|
-
if (!existsSync(claudeDir)) {
|
|
11776
|
-
return { source: "sessions", examples: [], count: 0 };
|
|
11941
|
+
// src/cli/ui.ts
|
|
11942
|
+
import chalk from "chalk";
|
|
11943
|
+
function printTable(headers, rows) {
|
|
11944
|
+
if (rows.length === 0) {
|
|
11945
|
+
console.log(chalk.dim(" (no records)"));
|
|
11946
|
+
return;
|
|
11777
11947
|
}
|
|
11778
|
-
const
|
|
11779
|
-
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
|
|
11785
|
-
|
|
11786
|
-
|
|
11787
|
-
|
|
11788
|
-
|
|
11789
|
-
|
|
11790
|
-
if (options.since) {
|
|
11791
|
-
const fileStat = await stat(filePath).catch(() => null);
|
|
11792
|
-
if (fileStat && fileStat.mtime < options.since)
|
|
11793
|
-
continue;
|
|
11794
|
-
}
|
|
11795
|
-
const content = await readFile(filePath, "utf-8").catch(() => "");
|
|
11796
|
-
if (!content.trim())
|
|
11797
|
-
continue;
|
|
11798
|
-
const lines = content.trim().split(`
|
|
11799
|
-
`);
|
|
11800
|
-
const turns = [];
|
|
11801
|
-
for (const line of lines) {
|
|
11802
|
-
try {
|
|
11803
|
-
const entry = JSON.parse(line);
|
|
11804
|
-
if ((entry.type === "user" || entry.type === "human") && entry.message?.content) {
|
|
11805
|
-
const text2 = extractText(entry.message.content);
|
|
11806
|
-
if (text2.trim())
|
|
11807
|
-
turns.push({ role: "user", content: text2.trim() });
|
|
11808
|
-
} else if (entry.type === "assistant" && entry.message?.content) {
|
|
11809
|
-
const text2 = extractText(entry.message.content);
|
|
11810
|
-
if (text2.trim())
|
|
11811
|
-
turns.push({ role: "assistant", content: text2.trim() });
|
|
11812
|
-
}
|
|
11813
|
-
} catch {}
|
|
11814
|
-
}
|
|
11815
|
-
const windowSize = 6;
|
|
11816
|
-
for (let start = 0;start < turns.length - 1 && examples.length < limit2; start++) {
|
|
11817
|
-
const window2 = turns.slice(start, start + windowSize);
|
|
11818
|
-
if (!window2[0] || window2[0].role !== "user")
|
|
11819
|
-
continue;
|
|
11820
|
-
const lastAssistantIdx = window2.map((t) => t.role).lastIndexOf("assistant");
|
|
11821
|
-
if (lastAssistantIdx < 1)
|
|
11822
|
-
continue;
|
|
11823
|
-
const usedTurns = window2.slice(0, lastAssistantIdx + 1);
|
|
11824
|
-
examples.push({
|
|
11825
|
-
messages: [
|
|
11826
|
-
{ role: "system", content: SYSTEM_PROMPT4 },
|
|
11827
|
-
...usedTurns
|
|
11828
|
-
]
|
|
11829
|
-
});
|
|
11830
|
-
}
|
|
11831
|
-
}
|
|
11948
|
+
const colWidths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? "").length)));
|
|
11949
|
+
const separator = colWidths.map((w) => "\u2500".repeat(w + 2)).join("\u253C");
|
|
11950
|
+
const headerLine = headers.map((h, i) => ` ${chalk.bold(h.padEnd(colWidths[i] ?? 0))} `).join("\u2502");
|
|
11951
|
+
const topBorder = colWidths.map((w) => "\u2500".repeat(w + 2)).join("\u252C");
|
|
11952
|
+
const midBorder = separator;
|
|
11953
|
+
const bottomBorder = colWidths.map((w) => "\u2500".repeat(w + 2)).join("\u2534");
|
|
11954
|
+
console.log("\u250C" + topBorder + "\u2510");
|
|
11955
|
+
console.log("\u2502" + headerLine + "\u2502");
|
|
11956
|
+
console.log("\u251C" + midBorder + "\u2524");
|
|
11957
|
+
for (const row of rows) {
|
|
11958
|
+
const rowLine = row.map((cell, i) => ` ${(cell ?? "").padEnd(colWidths[i] ?? 0)} `).join("\u2502");
|
|
11959
|
+
console.log("\u2502" + rowLine + "\u2502");
|
|
11832
11960
|
}
|
|
11833
|
-
|
|
11961
|
+
console.log("\u2514" + bottomBorder + "\u2518");
|
|
11834
11962
|
}
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11963
|
+
var STATUS_COLORS = {
|
|
11964
|
+
succeeded: chalk.green,
|
|
11965
|
+
running: chalk.cyan,
|
|
11966
|
+
pending: chalk.yellow,
|
|
11967
|
+
failed: chalk.red,
|
|
11968
|
+
cancelled: chalk.dim,
|
|
11969
|
+
queued: chalk.yellow,
|
|
11970
|
+
validating_files: chalk.blue
|
|
11971
|
+
};
|
|
11972
|
+
function printStatus(status) {
|
|
11973
|
+
const colorFn = STATUS_COLORS[status] ?? chalk.white;
|
|
11974
|
+
return colorFn(`\u25CF ${status}`);
|
|
11975
|
+
}
|
|
11976
|
+
function printJson(obj) {
|
|
11977
|
+
console.log(JSON.stringify(obj, null, 2));
|
|
11978
|
+
}
|
|
11979
|
+
function printError(message) {
|
|
11980
|
+
console.error(chalk.red("\u2717 Error: ") + message);
|
|
11981
|
+
}
|
|
11982
|
+
function printSuccess(message) {
|
|
11983
|
+
console.log(chalk.green("\u2713 ") + message);
|
|
11984
|
+
}
|
|
11985
|
+
function printInfo(message) {
|
|
11986
|
+
console.log(chalk.dim(" " + message));
|
|
11854
11987
|
}
|
|
11855
11988
|
|
|
11856
11989
|
// src/cli/index.ts
|
|
11857
11990
|
var program2 = new Command;
|
|
11858
11991
|
program2.name("brains").description("Fine-tuned model tracker and trainer").version("0.0.1");
|
|
11859
11992
|
var modelsCmd = program2.command("models").description("Manage tracked fine-tuned models");
|
|
11860
|
-
modelsCmd.command("list").description("List all tracked fine-tuned models").action(async () => {
|
|
11993
|
+
modelsCmd.command("list").description("List all tracked fine-tuned models").option("--json", "Output as JSON").action(async (opts) => {
|
|
11861
11994
|
try {
|
|
11862
11995
|
const db = getDb();
|
|
11863
11996
|
const models = await db.select().from(fineTunedModels);
|
|
11997
|
+
if (opts.json) {
|
|
11998
|
+
printJson(models);
|
|
11999
|
+
return;
|
|
12000
|
+
}
|
|
11864
12001
|
if (models.length === 0) {
|
|
11865
12002
|
printInfo("No models tracked yet. Use 'brains finetune start' to train one.");
|
|
11866
12003
|
return;
|
|
@@ -11878,14 +12015,22 @@ modelsCmd.command("list").description("List all tracked fine-tuned models").acti
|
|
|
11878
12015
|
process.exit(1);
|
|
11879
12016
|
}
|
|
11880
12017
|
});
|
|
11881
|
-
modelsCmd.command("show <id>").description("Show details of a specific model").action(async (id) => {
|
|
12018
|
+
modelsCmd.command("show <id>").description("Show details of a specific model").option("--json", "Output as JSON").action(async (id, opts) => {
|
|
11882
12019
|
try {
|
|
11883
12020
|
const db = getDb();
|
|
11884
12021
|
const [model] = await db.select().from(fineTunedModels).where(eq(fineTunedModels.id, id));
|
|
11885
12022
|
if (!model) {
|
|
11886
|
-
|
|
12023
|
+
if (opts.json) {
|
|
12024
|
+
printJson({ error: `Model not found: ${id}` });
|
|
12025
|
+
} else {
|
|
12026
|
+
printError(`Model not found: ${id}`);
|
|
12027
|
+
}
|
|
11887
12028
|
process.exit(1);
|
|
11888
12029
|
}
|
|
12030
|
+
if (opts.json) {
|
|
12031
|
+
printJson(model);
|
|
12032
|
+
return;
|
|
12033
|
+
}
|
|
11889
12034
|
console.log();
|
|
11890
12035
|
const tagsList = model.tags ? JSON.parse(model.tags).join(", ") : "(none)";
|
|
11891
12036
|
console.log(` ID: ${model.id}`);
|
|
@@ -11972,29 +12117,89 @@ modelsCmd.command("collection <id> <collectionName>").description("Set the colle
|
|
|
11972
12117
|
process.exit(1);
|
|
11973
12118
|
}
|
|
11974
12119
|
});
|
|
12120
|
+
modelsCmd.command("import <job-id>").description("Import an externally created fine-tuned model into local tracking").option("--provider <provider>", "Provider (openai|thinker-labs)", "openai").option("--name <name>", "Display name for the model").action(async (jobId, opts) => {
|
|
12121
|
+
try {
|
|
12122
|
+
let result;
|
|
12123
|
+
if (opts.provider === "openai") {
|
|
12124
|
+
result = await getFineTuneStatus(jobId);
|
|
12125
|
+
} else {
|
|
12126
|
+
const tl = new ThinkerLabsProvider;
|
|
12127
|
+
result = await tl.getFineTuneStatus(jobId);
|
|
12128
|
+
}
|
|
12129
|
+
const db = getDb();
|
|
12130
|
+
const [existing] = await db.select().from(fineTunedModels).where(eq(fineTunedModels.fineTuneJobId, jobId));
|
|
12131
|
+
if (existing) {
|
|
12132
|
+
printInfo(`Model already tracked as: ${existing.id}`);
|
|
12133
|
+
return;
|
|
12134
|
+
}
|
|
12135
|
+
const modelId = randomUUID();
|
|
12136
|
+
const now = Date.now();
|
|
12137
|
+
const name = opts.name ?? result.fineTunedModel ?? `imported-${jobId}`;
|
|
12138
|
+
await db.insert(fineTunedModels).values({
|
|
12139
|
+
id: modelId,
|
|
12140
|
+
name,
|
|
12141
|
+
provider: opts.provider,
|
|
12142
|
+
baseModel: result.baseModel ?? "unknown",
|
|
12143
|
+
status: result.status,
|
|
12144
|
+
fineTuneJobId: jobId,
|
|
12145
|
+
createdAt: now,
|
|
12146
|
+
updatedAt: now
|
|
12147
|
+
});
|
|
12148
|
+
await db.insert(trainingJobs).values({
|
|
12149
|
+
id: randomUUID(),
|
|
12150
|
+
modelId,
|
|
12151
|
+
provider: opts.provider,
|
|
12152
|
+
status: result.status,
|
|
12153
|
+
startedAt: now
|
|
12154
|
+
});
|
|
12155
|
+
printSuccess(`Model imported successfully.`);
|
|
12156
|
+
console.log();
|
|
12157
|
+
console.log(` Local ID: ${modelId}`);
|
|
12158
|
+
console.log(` Job ID: ${jobId}`);
|
|
12159
|
+
console.log(` Name: ${name}`);
|
|
12160
|
+
console.log(` Status: ${printStatus(result.status)}`);
|
|
12161
|
+
if (result.fineTunedModel)
|
|
12162
|
+
console.log(` Model: ${result.fineTunedModel}`);
|
|
12163
|
+
console.log();
|
|
12164
|
+
} catch (err) {
|
|
12165
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
12166
|
+
process.exit(1);
|
|
12167
|
+
}
|
|
12168
|
+
});
|
|
11975
12169
|
var finetuneCmd = program2.command("finetune").description("Manage fine-tuning jobs");
|
|
11976
|
-
finetuneCmd.command("start").description("Start a fine-tuning job").requiredOption("--provider <provider>", "Provider to use (openai|thinker-labs)").requiredOption("--base-model <model>", "Base model to fine-tune (e.g. gpt-4o-mini-2024-07-18)").
|
|
12170
|
+
finetuneCmd.command("start").description("Start a fine-tuning job").requiredOption("--provider <provider>", "Provider to use (openai|thinker-labs)").requiredOption("--base-model <model>", "Base model to fine-tune (e.g. gpt-4o-mini-2024-07-18)").option("--dataset <path>", "Path to the JSONL training dataset (auto-detects latest if omitted)").requiredOption("--name <name>", "Human-readable name for this fine-tuned model").action(async (opts) => {
|
|
11977
12171
|
try {
|
|
11978
12172
|
if (opts.provider !== "openai" && opts.provider !== "thinker-labs") {
|
|
11979
12173
|
printError(`Unknown provider: ${opts.provider}. Use 'openai' or 'thinker-labs'.`);
|
|
11980
12174
|
process.exit(1);
|
|
11981
12175
|
}
|
|
11982
|
-
|
|
11983
|
-
|
|
12176
|
+
let datasetPath = opts.dataset;
|
|
12177
|
+
if (!datasetPath) {
|
|
12178
|
+
const db2 = getDb();
|
|
12179
|
+
const [latest] = await db2.select().from(trainingDatasets).orderBy(desc(trainingDatasets.createdAt)).limit(1);
|
|
12180
|
+
if (!latest?.filePath) {
|
|
12181
|
+
printError("No datasets found. Run 'brains data gather' first.");
|
|
12182
|
+
process.exit(1);
|
|
12183
|
+
}
|
|
12184
|
+
datasetPath = latest.filePath;
|
|
12185
|
+
printInfo(`Using latest dataset: ${datasetPath} (${latest.exampleCount} examples)`);
|
|
12186
|
+
}
|
|
12187
|
+
if (!existsSync3(datasetPath)) {
|
|
12188
|
+
printError(`Dataset file not found: ${datasetPath}`);
|
|
11984
12189
|
process.exit(1);
|
|
11985
12190
|
}
|
|
11986
|
-
printInfo(`Uploading training file: ${
|
|
12191
|
+
printInfo(`Uploading training file: ${datasetPath} \u2026`);
|
|
11987
12192
|
let fileId;
|
|
11988
12193
|
let jobId;
|
|
11989
12194
|
let jobStatus;
|
|
11990
12195
|
if (opts.provider === "openai") {
|
|
11991
|
-
({ fileId } = await uploadTrainingFile(
|
|
12196
|
+
({ fileId } = await uploadTrainingFile(datasetPath));
|
|
11992
12197
|
printSuccess(`File uploaded. fileId = ${fileId}`);
|
|
11993
12198
|
printInfo(`Creating fine-tune job on OpenAI \u2026`);
|
|
11994
12199
|
({ jobId, status: jobStatus } = await createFineTuneJob(fileId, opts.baseModel, opts.name));
|
|
11995
12200
|
} else {
|
|
11996
12201
|
const tl = new ThinkerLabsProvider;
|
|
11997
|
-
({ fileId } = await tl.uploadTrainingFile(
|
|
12202
|
+
({ fileId } = await tl.uploadTrainingFile(datasetPath));
|
|
11998
12203
|
printSuccess(`File uploaded. fileId = ${fileId}`);
|
|
11999
12204
|
printInfo(`Creating fine-tune job on Thinker Labs \u2026`);
|
|
12000
12205
|
({ jobId, status: jobStatus } = await tl.createFineTuneJob(fileId, opts.baseModel, opts.name));
|
|
@@ -12032,7 +12237,7 @@ finetuneCmd.command("start").description("Start a fine-tuning job").requiredOpti
|
|
|
12032
12237
|
process.exit(1);
|
|
12033
12238
|
}
|
|
12034
12239
|
});
|
|
12035
|
-
finetuneCmd.command("status <job-id>").description("Get the status of a fine-tuning job").option("--provider <provider>", "Provider (openai|thinker-labs)", "openai").action(async (jobId, opts) => {
|
|
12240
|
+
finetuneCmd.command("status <job-id>").description("Get the status of a fine-tuning job").option("--provider <provider>", "Provider (openai|thinker-labs)", "openai").option("--json", "Output as JSON").action(async (jobId, opts) => {
|
|
12036
12241
|
try {
|
|
12037
12242
|
let result;
|
|
12038
12243
|
if (opts.provider === "openai") {
|
|
@@ -12041,16 +12246,20 @@ finetuneCmd.command("status <job-id>").description("Get the status of a fine-tun
|
|
|
12041
12246
|
const tl = new ThinkerLabsProvider;
|
|
12042
12247
|
result = await tl.getFineTuneStatus(jobId);
|
|
12043
12248
|
}
|
|
12044
|
-
|
|
12045
|
-
|
|
12046
|
-
|
|
12047
|
-
|
|
12048
|
-
console.log(`
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
|
|
12249
|
+
if (opts.json) {
|
|
12250
|
+
printJson(result);
|
|
12251
|
+
} else {
|
|
12252
|
+
console.log();
|
|
12253
|
+
console.log(` Job ID: ${result.jobId}`);
|
|
12254
|
+
console.log(` Status: ${printStatus(result.status)}`);
|
|
12255
|
+
if (result.fineTunedModel) {
|
|
12256
|
+
console.log(` Fine-tuned model: ${result.fineTunedModel}`);
|
|
12257
|
+
}
|
|
12258
|
+
if (result.error) {
|
|
12259
|
+
console.log(` Error: ${result.error}`);
|
|
12260
|
+
}
|
|
12261
|
+
console.log();
|
|
12052
12262
|
}
|
|
12053
|
-
console.log();
|
|
12054
12263
|
const db = getDb();
|
|
12055
12264
|
const [model] = await db.select().from(fineTunedModels).where(eq(fineTunedModels.fineTuneJobId, jobId));
|
|
12056
12265
|
if (model) {
|
|
@@ -12062,7 +12271,64 @@ finetuneCmd.command("status <job-id>").description("Get the status of a fine-tun
|
|
|
12062
12271
|
process.exit(1);
|
|
12063
12272
|
}
|
|
12064
12273
|
});
|
|
12065
|
-
finetuneCmd.command("
|
|
12274
|
+
finetuneCmd.command("watch <job-id>").description("Poll a fine-tuning job until it completes or fails").option("--provider <provider>", "Provider (openai|thinker-labs)", "openai").option("--interval <seconds>", "Poll interval in seconds", "30").action(async (jobId, opts) => {
|
|
12275
|
+
const intervalMs = Math.max(5, parseInt(opts.interval, 10) || 30) * 1000;
|
|
12276
|
+
const terminalStates = new Set(["succeeded", "failed", "cancelled"]);
|
|
12277
|
+
printInfo(`Watching job ${jobId} (polling every ${intervalMs / 1000}s) \u2026`);
|
|
12278
|
+
console.log();
|
|
12279
|
+
const poll = async () => {
|
|
12280
|
+
try {
|
|
12281
|
+
let result;
|
|
12282
|
+
if (opts.provider === "openai") {
|
|
12283
|
+
result = await getFineTuneStatus(jobId);
|
|
12284
|
+
} else {
|
|
12285
|
+
const tl = new ThinkerLabsProvider;
|
|
12286
|
+
result = await tl.getFineTuneStatus(jobId);
|
|
12287
|
+
}
|
|
12288
|
+
const ts = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
12289
|
+
process.stdout.write(` [${ts}] ${printStatus(result.status)}`);
|
|
12290
|
+
if (result.fineTunedModel)
|
|
12291
|
+
process.stdout.write(` model: ${result.fineTunedModel}`);
|
|
12292
|
+
process.stdout.write(`
|
|
12293
|
+
`);
|
|
12294
|
+
const db = getDb();
|
|
12295
|
+
const [model] = await db.select().from(fineTunedModels).where(eq(fineTunedModels.fineTuneJobId, jobId));
|
|
12296
|
+
if (model) {
|
|
12297
|
+
await db.update(fineTunedModels).set({ status: result.status, updatedAt: Date.now() }).where(eq(fineTunedModels.fineTuneJobId, jobId));
|
|
12298
|
+
}
|
|
12299
|
+
if (terminalStates.has(result.status)) {
|
|
12300
|
+
console.log();
|
|
12301
|
+
if (result.status === "succeeded") {
|
|
12302
|
+
printSuccess(`Job completed successfully.`);
|
|
12303
|
+
if (result.fineTunedModel)
|
|
12304
|
+
printSuccess(`Fine-tuned model: ${result.fineTunedModel}`);
|
|
12305
|
+
} else if (result.status === "failed") {
|
|
12306
|
+
printError(`Job failed.${result.error ? " Error: " + result.error : ""}`);
|
|
12307
|
+
} else {
|
|
12308
|
+
printInfo(`Job ${result.status}.`);
|
|
12309
|
+
}
|
|
12310
|
+
return true;
|
|
12311
|
+
}
|
|
12312
|
+
return false;
|
|
12313
|
+
} catch (err) {
|
|
12314
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
12315
|
+
return false;
|
|
12316
|
+
}
|
|
12317
|
+
};
|
|
12318
|
+
const done = await poll();
|
|
12319
|
+
if (!done) {
|
|
12320
|
+
await new Promise((resolve2) => {
|
|
12321
|
+
const timer = setInterval(async () => {
|
|
12322
|
+
const finished = await poll();
|
|
12323
|
+
if (finished) {
|
|
12324
|
+
clearInterval(timer);
|
|
12325
|
+
resolve2();
|
|
12326
|
+
}
|
|
12327
|
+
}, intervalMs);
|
|
12328
|
+
});
|
|
12329
|
+
}
|
|
12330
|
+
});
|
|
12331
|
+
finetuneCmd.command("list").description("List all fine-tuning jobs").option("--provider <provider>", "Provider to query (openai|thinker-labs)", "openai").option("--json", "Output as JSON").action(async (opts) => {
|
|
12066
12332
|
try {
|
|
12067
12333
|
let jobs;
|
|
12068
12334
|
if (opts.provider === "openai") {
|
|
@@ -12071,6 +12337,10 @@ finetuneCmd.command("list").description("List all fine-tuning jobs").option("--p
|
|
|
12071
12337
|
const tl = new ThinkerLabsProvider;
|
|
12072
12338
|
jobs = await tl.listFineTunedModels();
|
|
12073
12339
|
}
|
|
12340
|
+
if (opts.json) {
|
|
12341
|
+
printJson(jobs);
|
|
12342
|
+
return;
|
|
12343
|
+
}
|
|
12074
12344
|
if (jobs.length === 0) {
|
|
12075
12345
|
printInfo("No fine-tuning jobs found.");
|
|
12076
12346
|
return;
|
|
@@ -12086,7 +12356,7 @@ finetuneCmd.command("list").description("List all fine-tuning jobs").option("--p
|
|
|
12086
12356
|
process.exit(1);
|
|
12087
12357
|
}
|
|
12088
12358
|
});
|
|
12089
|
-
var DEFAULT_DATASETS_DIR =
|
|
12359
|
+
var DEFAULT_DATASETS_DIR = join7(homedir7(), ".brains", "datasets");
|
|
12090
12360
|
var dataCmd = program2.command("data").description("Manage training datasets");
|
|
12091
12361
|
dataCmd.command("gather").description("Gather training data from agent memory sources").option("--source <source>", "Data source: todos|mementos|conversations|sessions|all", "all").option("--output <dir>", "Output directory", DEFAULT_DATASETS_DIR).option("--limit <n>", "Maximum number of examples to gather", "500").action(async (opts) => {
|
|
12092
12362
|
const validSources = ["todos", "mementos", "conversations", "sessions", "all"];
|
|
@@ -12100,44 +12370,59 @@ dataCmd.command("gather").description("Gather training data from agent memory so
|
|
|
12100
12370
|
process.exit(1);
|
|
12101
12371
|
}
|
|
12102
12372
|
try {
|
|
12103
|
-
|
|
12373
|
+
mkdirSync3(opts.output, { recursive: true });
|
|
12104
12374
|
const sources = opts.source === "all" ? ["todos", "mementos", "conversations", "sessions"] : [opts.source];
|
|
12105
12375
|
const now = Date.now();
|
|
12106
12376
|
const db = getDb();
|
|
12107
|
-
const
|
|
12377
|
+
const gathererMap = {
|
|
12378
|
+
todos: (o) => Promise.resolve().then(() => (init_todos(), exports_todos)).then((m) => m.gatherFromTodos(o)),
|
|
12379
|
+
mementos: (o) => Promise.resolve().then(() => (init_mementos(), exports_mementos)).then((m) => m.gatherFromMementos(o)),
|
|
12380
|
+
conversations: (o) => Promise.resolve().then(() => (init_conversations(), exports_conversations)).then((m) => m.gatherFromConversations(o)),
|
|
12381
|
+
sessions: (o) => Promise.resolve().then(() => (init_sessions(), exports_sessions2)).then((m) => m.gatherFromSessions(o))
|
|
12382
|
+
};
|
|
12108
12383
|
let totalExamples = 0;
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
printInfo(`
|
|
12112
|
-
|
|
12113
|
-
|
|
12114
|
-
|
|
12115
|
-
|
|
12116
|
-
|
|
12117
|
-
|
|
12118
|
-
|
|
12119
|
-
|
|
12384
|
+
let successfulSources = 0;
|
|
12385
|
+
for (const source of sources) {
|
|
12386
|
+
printInfo(`Gathering from ${source} \u2026`);
|
|
12387
|
+
try {
|
|
12388
|
+
const gatherer = gathererMap[source];
|
|
12389
|
+
if (!gatherer) {
|
|
12390
|
+
printError(` Unknown source: ${source}`);
|
|
12391
|
+
continue;
|
|
12392
|
+
}
|
|
12393
|
+
const { examples, count } = await gatherer({ limit: limit2 });
|
|
12394
|
+
if (count === 0) {
|
|
12395
|
+
printInfo(` No examples found in ${source}.`);
|
|
12396
|
+
continue;
|
|
12397
|
+
}
|
|
12398
|
+
const fileName = `${source}-${now}.jsonl`;
|
|
12399
|
+
const filePath = join7(opts.output, fileName);
|
|
12400
|
+
writeFileSync2(filePath, examples.map((e) => JSON.stringify(e)).join(`
|
|
12120
12401
|
`) + `
|
|
12121
12402
|
`, "utf8");
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12403
|
+
await db.insert(trainingDatasets).values({
|
|
12404
|
+
id: randomUUID(),
|
|
12405
|
+
source,
|
|
12406
|
+
filePath,
|
|
12407
|
+
exampleCount: count,
|
|
12408
|
+
createdAt: now
|
|
12409
|
+
});
|
|
12410
|
+
printSuccess(` \u2713 ${count} examples \u2192 ${filePath}`);
|
|
12411
|
+
totalExamples += count;
|
|
12412
|
+
successfulSources++;
|
|
12413
|
+
} catch (sourceErr) {
|
|
12414
|
+
printError(` \u2717 ${source}: ${sourceErr instanceof Error ? sourceErr.message : String(sourceErr)}`);
|
|
12415
|
+
}
|
|
12131
12416
|
}
|
|
12132
12417
|
console.log();
|
|
12133
|
-
printSuccess(`Total examples
|
|
12418
|
+
printSuccess(`Total: ${totalExamples} examples from ${successfulSources} source(s)`);
|
|
12134
12419
|
} catch (err) {
|
|
12135
12420
|
printError(err instanceof Error ? err.message : String(err));
|
|
12136
12421
|
process.exit(1);
|
|
12137
12422
|
}
|
|
12138
12423
|
});
|
|
12139
12424
|
dataCmd.command("preview <file>").description("Preview a JSONL training file").option("-n, --count <n>", "Number of examples to show", "5").action((file, opts) => {
|
|
12140
|
-
if (!
|
|
12425
|
+
if (!existsSync3(file)) {
|
|
12141
12426
|
printError(`File not found: ${file}`);
|
|
12142
12427
|
process.exit(1);
|
|
12143
12428
|
}
|
|
@@ -12147,7 +12432,7 @@ dataCmd.command("preview <file>").description("Preview a JSONL training file").o
|
|
|
12147
12432
|
process.exit(1);
|
|
12148
12433
|
}
|
|
12149
12434
|
try {
|
|
12150
|
-
const content =
|
|
12435
|
+
const content = readFileSync3(file, "utf8");
|
|
12151
12436
|
const lines = content.trim().split(`
|
|
12152
12437
|
`).filter(Boolean);
|
|
12153
12438
|
const total = lines.length;
|
|
@@ -12172,10 +12457,63 @@ dataCmd.command("preview <file>").description("Preview a JSONL training file").o
|
|
|
12172
12457
|
process.exit(1);
|
|
12173
12458
|
}
|
|
12174
12459
|
});
|
|
12175
|
-
dataCmd.command("
|
|
12460
|
+
dataCmd.command("merge <files...>").description("Merge multiple JSONL datasets into one").option("--output <path>", "Output file path", join7(DEFAULT_DATASETS_DIR, `merged-${Date.now()}.jsonl`)).option("--no-dedupe", "Skip deduplication").action(async (files, opts) => {
|
|
12461
|
+
try {
|
|
12462
|
+
for (const f of files) {
|
|
12463
|
+
if (!existsSync3(f)) {
|
|
12464
|
+
printError(`File not found: ${f}`);
|
|
12465
|
+
process.exit(1);
|
|
12466
|
+
}
|
|
12467
|
+
}
|
|
12468
|
+
mkdirSync3(join7(opts.output, "..").replace(/\/\.\.$/, "") || DEFAULT_DATASETS_DIR, { recursive: true });
|
|
12469
|
+
const allExamples = [];
|
|
12470
|
+
for (const f of files) {
|
|
12471
|
+
const lines = readFileSync3(f, "utf8").split(`
|
|
12472
|
+
`).map((l) => l.trim()).filter(Boolean);
|
|
12473
|
+
allExamples.push(...lines);
|
|
12474
|
+
printInfo(` Read ${lines.length} examples from ${f}`);
|
|
12475
|
+
}
|
|
12476
|
+
let finalLines = allExamples;
|
|
12477
|
+
let dupeCount = 0;
|
|
12478
|
+
if (opts.dedupe) {
|
|
12479
|
+
const seen = new Set;
|
|
12480
|
+
finalLines = allExamples.filter((line) => {
|
|
12481
|
+
if (seen.has(line)) {
|
|
12482
|
+
dupeCount++;
|
|
12483
|
+
return false;
|
|
12484
|
+
}
|
|
12485
|
+
seen.add(line);
|
|
12486
|
+
return true;
|
|
12487
|
+
});
|
|
12488
|
+
}
|
|
12489
|
+
writeFileSync2(opts.output, finalLines.join(`
|
|
12490
|
+
`) + `
|
|
12491
|
+
`, "utf8");
|
|
12492
|
+
const db = getDb();
|
|
12493
|
+
await db.insert(trainingDatasets).values({
|
|
12494
|
+
id: randomUUID(),
|
|
12495
|
+
source: "mixed",
|
|
12496
|
+
filePath: opts.output,
|
|
12497
|
+
exampleCount: finalLines.length,
|
|
12498
|
+
createdAt: Date.now()
|
|
12499
|
+
});
|
|
12500
|
+
console.log();
|
|
12501
|
+
printSuccess(`Merged ${files.length} files \u2014 ${finalLines.length} examples \u2192 ${opts.output}`);
|
|
12502
|
+
if (opts.dedupe && dupeCount > 0)
|
|
12503
|
+
printInfo(` Removed ${dupeCount} duplicate(s)`);
|
|
12504
|
+
} catch (err) {
|
|
12505
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
12506
|
+
process.exit(1);
|
|
12507
|
+
}
|
|
12508
|
+
});
|
|
12509
|
+
dataCmd.command("list").description("List all gathered datasets").option("--json", "Output as JSON").action(async (opts) => {
|
|
12176
12510
|
try {
|
|
12177
12511
|
const db = getDb();
|
|
12178
12512
|
const datasets = await db.select().from(trainingDatasets);
|
|
12513
|
+
if (opts.json) {
|
|
12514
|
+
printJson(datasets);
|
|
12515
|
+
return;
|
|
12516
|
+
}
|
|
12179
12517
|
if (datasets.length === 0) {
|
|
12180
12518
|
printInfo("No datasets found. Use 'brains data gather' to create one.");
|
|
12181
12519
|
return;
|
|
@@ -12193,10 +12531,10 @@ dataCmd.command("list").description("List all gathered datasets").action(async (
|
|
|
12193
12531
|
}
|
|
12194
12532
|
});
|
|
12195
12533
|
var collectionsCmd = program2.command("collections").description("Manage model collections");
|
|
12196
|
-
collectionsCmd.action(async () => {
|
|
12197
|
-
await listCollections();
|
|
12534
|
+
collectionsCmd.option("--json", "Output as JSON").action(async (opts) => {
|
|
12535
|
+
await listCollections(opts.json);
|
|
12198
12536
|
});
|
|
12199
|
-
async function listCollections() {
|
|
12537
|
+
async function listCollections(json = false) {
|
|
12200
12538
|
try {
|
|
12201
12539
|
const db = getDb();
|
|
12202
12540
|
const rows = await db.select({
|
|
@@ -12204,6 +12542,10 @@ async function listCollections() {
|
|
|
12204
12542
|
count: sql`count(*)`.as("count"),
|
|
12205
12543
|
names: sql`group_concat(coalesce(${fineTunedModels.displayName}, ${fineTunedModels.name}), ', ')`.as("names")
|
|
12206
12544
|
}).from(fineTunedModels).groupBy(fineTunedModels.collection);
|
|
12545
|
+
if (json) {
|
|
12546
|
+
printJson(rows);
|
|
12547
|
+
return;
|
|
12548
|
+
}
|
|
12207
12549
|
if (rows.length === 0) {
|
|
12208
12550
|
printInfo("No collections found. Set a collection with 'brains models set-collection'.");
|
|
12209
12551
|
return;
|
|
@@ -12218,8 +12560,8 @@ async function listCollections() {
|
|
|
12218
12560
|
process.exit(1);
|
|
12219
12561
|
}
|
|
12220
12562
|
}
|
|
12221
|
-
collectionsCmd.command("list").description("List all collections with model counts").action(async () => {
|
|
12222
|
-
await listCollections();
|
|
12563
|
+
collectionsCmd.command("list").description("List all collections with model counts").option("--json", "Output as JSON").action(async (opts) => {
|
|
12564
|
+
await listCollections(opts.json);
|
|
12223
12565
|
});
|
|
12224
12566
|
collectionsCmd.command("show <name>").description("List all models in a collection").action(async (name) => {
|
|
12225
12567
|
try {
|
|
@@ -12247,4 +12589,74 @@ collectionsCmd.command("rename <oldName> <newName>").description("Rename a colle
|
|
|
12247
12589
|
process.exit(1);
|
|
12248
12590
|
}
|
|
12249
12591
|
});
|
|
12592
|
+
program2.command("remove <id>").alias("rm").alias("uninstall").description("Remove a fine-tuned model or training job by ID").option("--type <type>", "Type: model | job (default: auto-detect)").action(async (id, opts) => {
|
|
12593
|
+
const db = getDb();
|
|
12594
|
+
try {
|
|
12595
|
+
const type = opts.type?.toLowerCase();
|
|
12596
|
+
if (type === "job" || !type && !type) {
|
|
12597
|
+
const job = db.select().from(trainingJobs).where(eq(trainingJobs.id, id)).get();
|
|
12598
|
+
if (job || type === "job") {
|
|
12599
|
+
if (!job) {
|
|
12600
|
+
printError(`Job not found: ${id}`);
|
|
12601
|
+
process.exit(1);
|
|
12602
|
+
}
|
|
12603
|
+
db.delete(trainingJobs).where(eq(trainingJobs.id, id)).run();
|
|
12604
|
+
printSuccess(`Training job ${id} removed`);
|
|
12605
|
+
return;
|
|
12606
|
+
}
|
|
12607
|
+
}
|
|
12608
|
+
if (type === "model" || !type) {
|
|
12609
|
+
const model = db.select().from(fineTunedModels).where(eq(fineTunedModels.id, id)).get();
|
|
12610
|
+
if (model) {
|
|
12611
|
+
db.delete(fineTunedModels).where(eq(fineTunedModels.id, id)).run();
|
|
12612
|
+
printSuccess(`Model ${id} removed`);
|
|
12613
|
+
return;
|
|
12614
|
+
}
|
|
12615
|
+
}
|
|
12616
|
+
printError(`Not found: ${id}. Use --type model|job`);
|
|
12617
|
+
process.exit(1);
|
|
12618
|
+
} catch (err) {
|
|
12619
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
12620
|
+
process.exit(1);
|
|
12621
|
+
}
|
|
12622
|
+
});
|
|
12623
|
+
var configCmd = program2.command("config").description("Manage API keys and settings");
|
|
12624
|
+
configCmd.command("list").description("Show all config keys and their sources").action(() => {
|
|
12625
|
+
const entries = listConfig();
|
|
12626
|
+
console.log();
|
|
12627
|
+
for (const { key, value, source } of entries) {
|
|
12628
|
+
const display = source === "unset" ? "(unset)" : value.length > 8 ? value.slice(0, 4) + "****" + value.slice(-4) : "****";
|
|
12629
|
+
const src = source === "env" ? " [env]" : source === "file" ? " [file]" : "";
|
|
12630
|
+
console.log(` ${key.padEnd(28)} ${display}${src}`);
|
|
12631
|
+
}
|
|
12632
|
+
console.log();
|
|
12633
|
+
});
|
|
12634
|
+
configCmd.command("get <key>").description("Get a config value").action((key) => {
|
|
12635
|
+
if (!CONFIG_KEYS.includes(key)) {
|
|
12636
|
+
printError(`Unknown key: ${key}. Valid keys: ${CONFIG_KEYS.join(", ")}`);
|
|
12637
|
+
process.exit(1);
|
|
12638
|
+
}
|
|
12639
|
+
const value = getConfigValue(key);
|
|
12640
|
+
if (!value) {
|
|
12641
|
+
printInfo(`${key} is not set.`);
|
|
12642
|
+
} else {
|
|
12643
|
+
console.log(value);
|
|
12644
|
+
}
|
|
12645
|
+
});
|
|
12646
|
+
configCmd.command("set <key> <value>").description("Set a config value (stored in ~/.brains/config.json)").action((key, value) => {
|
|
12647
|
+
if (!CONFIG_KEYS.includes(key)) {
|
|
12648
|
+
printError(`Unknown key: ${key}. Valid keys: ${CONFIG_KEYS.join(", ")}`);
|
|
12649
|
+
process.exit(1);
|
|
12650
|
+
}
|
|
12651
|
+
setConfigValue(key, value);
|
|
12652
|
+
printSuccess(`${key} saved to ~/.brains/config.json`);
|
|
12653
|
+
});
|
|
12654
|
+
configCmd.command("unset <key>").description("Remove a config value from the config file").action((key) => {
|
|
12655
|
+
if (!CONFIG_KEYS.includes(key)) {
|
|
12656
|
+
printError(`Unknown key: ${key}. Valid keys: ${CONFIG_KEYS.join(", ")}`);
|
|
12657
|
+
process.exit(1);
|
|
12658
|
+
}
|
|
12659
|
+
deleteConfigValue(key);
|
|
12660
|
+
printSuccess(`${key} removed from config.`);
|
|
12661
|
+
});
|
|
12250
12662
|
program2.parse();
|