repomemory 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +151 -104
- package/dist/commands/analyze.d.ts +2 -0
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +162 -188
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/dashboard.d.ts +5 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +520 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +33 -34
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +2 -1
- package/dist/commands/serve.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +151 -35
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/status.d.ts +4 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +87 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +57 -27
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/wizard.d.ts +4 -0
- package/dist/commands/wizard.d.ts.map +1 -0
- package/dist/commands/wizard.js +184 -0
- package/dist/commands/wizard.js.map +1 -0
- package/dist/index.js +37 -42
- package/dist/index.js.map +1 -1
- package/dist/lib/ai-provider.d.ts +11 -0
- package/dist/lib/ai-provider.d.ts.map +1 -1
- package/dist/lib/ai-provider.js +138 -69
- package/dist/lib/ai-provider.js.map +1 -1
- package/dist/lib/config.d.ts +11 -15
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +33 -21
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/context-store.d.ts +11 -0
- package/dist/lib/context-store.d.ts.map +1 -1
- package/dist/lib/context-store.js +51 -18
- package/dist/lib/context-store.js.map +1 -1
- package/dist/lib/git.d.ts +1 -0
- package/dist/lib/git.d.ts.map +1 -1
- package/dist/lib/git.js +34 -20
- package/dist/lib/git.js.map +1 -1
- package/dist/lib/json-repair.d.ts +24 -0
- package/dist/lib/json-repair.d.ts.map +1 -0
- package/dist/lib/json-repair.js +140 -0
- package/dist/lib/json-repair.js.map +1 -0
- package/dist/lib/repo-scanner.d.ts.map +1 -1
- package/dist/lib/repo-scanner.js +103 -26
- package/dist/lib/repo-scanner.js.map +1 -1
- package/dist/lib/search.d.ts +10 -4
- package/dist/lib/search.d.ts.map +1 -1
- package/dist/lib/search.js +136 -51
- package/dist/lib/search.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +128 -54
- package/dist/mcp/server.js.map +1 -1
- package/package.json +20 -8
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import * as p from "@clack/prompts";
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { initCommand } from "./init.js";
|
|
6
|
+
import { analyzeCommand } from "./analyze.js";
|
|
7
|
+
import { setupCommand } from "./setup.js";
|
|
8
|
+
const PROVIDER_INFO = {
|
|
9
|
+
anthropic: {
|
|
10
|
+
envVar: "ANTHROPIC_API_KEY",
|
|
11
|
+
label: "Anthropic (Claude)",
|
|
12
|
+
hint: "Best quality. Recommended.",
|
|
13
|
+
},
|
|
14
|
+
openai: {
|
|
15
|
+
envVar: "OPENAI_API_KEY",
|
|
16
|
+
label: "OpenAI (GPT-4o)",
|
|
17
|
+
hint: "Fast and reliable.",
|
|
18
|
+
},
|
|
19
|
+
gemini: {
|
|
20
|
+
envVar: "GEMINI_API_KEY",
|
|
21
|
+
label: "Google (Gemini)",
|
|
22
|
+
hint: "Cheapest option.",
|
|
23
|
+
},
|
|
24
|
+
grok: {
|
|
25
|
+
envVar: "GROK_API_KEY",
|
|
26
|
+
label: "xAI (Grok)",
|
|
27
|
+
hint: "OpenAI-compatible.",
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
export async function wizardCommand(options) {
|
|
31
|
+
const repoRoot = options.dir || process.cwd();
|
|
32
|
+
console.clear();
|
|
33
|
+
p.intro(chalk.bgCyan.black(" repomemory ") + chalk.dim(" Your codebase never forgets."));
|
|
34
|
+
// Step 1: Check if already initialized
|
|
35
|
+
const contextExists = existsSync(join(repoRoot, ".context"));
|
|
36
|
+
if (contextExists) {
|
|
37
|
+
const overwrite = await p.confirm({
|
|
38
|
+
message: ".context/ already exists. Re-analyze and refresh?",
|
|
39
|
+
initialValue: false,
|
|
40
|
+
});
|
|
41
|
+
if (p.isCancel(overwrite)) {
|
|
42
|
+
p.cancel("Setup cancelled.");
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
if (!overwrite) {
|
|
46
|
+
p.cancel("Keeping existing context.");
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Step 2: Detect available API keys
|
|
51
|
+
const detectedProviders = [];
|
|
52
|
+
for (const [provider, info] of Object.entries(PROVIDER_INFO)) {
|
|
53
|
+
if (process.env[info.envVar]) {
|
|
54
|
+
detectedProviders.push(provider);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Check alternate env vars
|
|
58
|
+
if (!detectedProviders.includes("gemini") && (process.env.GOOGLE_API_KEY || process.env.GOOGLE_GENERATIVE_AI_API_KEY)) {
|
|
59
|
+
detectedProviders.push("gemini");
|
|
60
|
+
}
|
|
61
|
+
if (!detectedProviders.includes("grok") && process.env.XAI_API_KEY) {
|
|
62
|
+
detectedProviders.push("grok");
|
|
63
|
+
}
|
|
64
|
+
// Step 3: Choose provider
|
|
65
|
+
let selectedProvider;
|
|
66
|
+
if (detectedProviders.length === 1) {
|
|
67
|
+
p.log.success(`Detected API key for ${chalk.bold(PROVIDER_INFO[detectedProviders[0]].label)}`);
|
|
68
|
+
selectedProvider = detectedProviders[0];
|
|
69
|
+
}
|
|
70
|
+
else if (detectedProviders.length > 1) {
|
|
71
|
+
const provider = await p.select({
|
|
72
|
+
message: `Found ${detectedProviders.length} API keys. Which provider?`,
|
|
73
|
+
options: detectedProviders.map((prov) => ({
|
|
74
|
+
value: prov,
|
|
75
|
+
label: PROVIDER_INFO[prov].label,
|
|
76
|
+
hint: PROVIDER_INFO[prov].hint,
|
|
77
|
+
})),
|
|
78
|
+
});
|
|
79
|
+
if (p.isCancel(provider)) {
|
|
80
|
+
p.cancel("Setup cancelled.");
|
|
81
|
+
process.exit(0);
|
|
82
|
+
}
|
|
83
|
+
selectedProvider = provider;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// No API keys found — ask which they want to use
|
|
87
|
+
p.log.warn("No API keys detected in environment.");
|
|
88
|
+
const provider = await p.select({
|
|
89
|
+
message: "Which AI provider will you use?",
|
|
90
|
+
options: Object.entries(PROVIDER_INFO).map(([key, info]) => ({
|
|
91
|
+
value: key,
|
|
92
|
+
label: info.label,
|
|
93
|
+
hint: info.hint,
|
|
94
|
+
})),
|
|
95
|
+
});
|
|
96
|
+
if (p.isCancel(provider)) {
|
|
97
|
+
p.cancel("Setup cancelled.");
|
|
98
|
+
process.exit(0);
|
|
99
|
+
}
|
|
100
|
+
selectedProvider = provider;
|
|
101
|
+
const info = PROVIDER_INFO[selectedProvider];
|
|
102
|
+
p.log.info(`Set your API key:\n ${chalk.cyan(`export ${info.envVar}=your-key-here`)}`);
|
|
103
|
+
const hasKey = await p.confirm({
|
|
104
|
+
message: "Have you set the key? (You can set it now in another terminal)",
|
|
105
|
+
initialValue: false,
|
|
106
|
+
});
|
|
107
|
+
if (p.isCancel(hasKey) || !hasKey) {
|
|
108
|
+
p.log.info("You can run this wizard again after setting your API key.");
|
|
109
|
+
p.log.info(` ${chalk.dim(`export ${info.envVar}=...`)}`);
|
|
110
|
+
p.log.info(` ${chalk.dim("repomemory wizard")}`);
|
|
111
|
+
p.outro("See you soon!");
|
|
112
|
+
process.exit(0);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Step 4: Choose AI tools to integrate
|
|
116
|
+
const tools = await p.multiselect({
|
|
117
|
+
message: "Which AI tools do you use?",
|
|
118
|
+
options: [
|
|
119
|
+
{ value: "claude", label: "Claude Code", hint: "MCP server auto-starts" },
|
|
120
|
+
{ value: "cursor", label: "Cursor", hint: "Adds .cursor/rules/" },
|
|
121
|
+
{ value: "copilot", label: "GitHub Copilot", hint: "Adds copilot-instructions.md" },
|
|
122
|
+
{ value: "windsurf", label: "Windsurf", hint: "Adds .windsurfrules" },
|
|
123
|
+
{ value: "cline", label: "Cline", hint: "Adds .clinerules" },
|
|
124
|
+
{ value: "aider", label: "Aider", hint: "Adds .aider.conf.yml" },
|
|
125
|
+
{ value: "continue", label: "Continue", hint: "Adds .continue/rules/" },
|
|
126
|
+
],
|
|
127
|
+
required: false,
|
|
128
|
+
});
|
|
129
|
+
if (p.isCancel(tools)) {
|
|
130
|
+
p.cancel("Setup cancelled.");
|
|
131
|
+
process.exit(0);
|
|
132
|
+
}
|
|
133
|
+
const selectedTools = tools;
|
|
134
|
+
// Step 5: Run analysis?
|
|
135
|
+
const runAnalysis = await p.confirm({
|
|
136
|
+
message: `Analyze your repo with ${PROVIDER_INFO[selectedProvider].label}? (2-5 min, uses AI)`,
|
|
137
|
+
initialValue: true,
|
|
138
|
+
});
|
|
139
|
+
if (p.isCancel(runAnalysis)) {
|
|
140
|
+
p.cancel("Setup cancelled.");
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
// Step 6: Execute everything
|
|
144
|
+
console.log(); // spacing
|
|
145
|
+
const s = p.spinner();
|
|
146
|
+
// Init
|
|
147
|
+
s.start("Initializing .context/ directory...");
|
|
148
|
+
if (!contextExists) {
|
|
149
|
+
await initCommand({ dir: repoRoot, provider: selectedProvider });
|
|
150
|
+
}
|
|
151
|
+
s.stop("Initialized .context/ directory");
|
|
152
|
+
// Setup tools
|
|
153
|
+
for (const tool of selectedTools) {
|
|
154
|
+
s.start(`Configuring ${tool}...`);
|
|
155
|
+
await setupCommand(tool, { dir: repoRoot });
|
|
156
|
+
s.stop(`Configured ${tool}`);
|
|
157
|
+
}
|
|
158
|
+
// Analyze
|
|
159
|
+
if (runAnalysis) {
|
|
160
|
+
console.log(); // spacing before analyze (it has its own output)
|
|
161
|
+
await analyzeCommand({
|
|
162
|
+
dir: repoRoot,
|
|
163
|
+
provider: selectedProvider,
|
|
164
|
+
verbose: false,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// Done!
|
|
168
|
+
console.log();
|
|
169
|
+
p.note([
|
|
170
|
+
`${chalk.cyan("git add .context/ && git commit -m 'Add repomemory'")}`,
|
|
171
|
+
"",
|
|
172
|
+
"Your team now shares the knowledge.",
|
|
173
|
+
"",
|
|
174
|
+
selectedTools.includes("claude")
|
|
175
|
+
? "Claude Code will auto-discover context via the MCP server."
|
|
176
|
+
: `Run ${chalk.cyan("repomemory setup claude")} to add MCP server integration.`,
|
|
177
|
+
"",
|
|
178
|
+
`Run ${chalk.cyan("repomemory status")} to see your context coverage.`,
|
|
179
|
+
`Run ${chalk.cyan("repomemory analyze --merge")} to update without overwriting edits.`,
|
|
180
|
+
`Run ${chalk.cyan("repomemory dashboard")} to browse context in your browser.`,
|
|
181
|
+
].join("\n"), "Next steps");
|
|
182
|
+
p.outro(chalk.green("Your codebase will never forget again."));
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=wizard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard.js","sourceRoot":"","sources":["../../src/commands/wizard.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -5,11 +5,17 @@ import { analyzeCommand } from "./commands/analyze.js";
|
|
|
5
5
|
import { syncCommand } from "./commands/sync.js";
|
|
6
6
|
import { serveCommand } from "./commands/serve.js";
|
|
7
7
|
import { setupCommand } from "./commands/setup.js";
|
|
8
|
+
import { statusCommand } from "./commands/status.js";
|
|
9
|
+
import { wizardCommand } from "./commands/wizard.js";
|
|
10
|
+
import { dashboardCommand } from "./commands/dashboard.js";
|
|
11
|
+
import { createRequire } from "module";
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
const { version } = require("../package.json");
|
|
8
14
|
const program = new Command();
|
|
9
15
|
program
|
|
10
16
|
.name("repomemory")
|
|
11
|
-
.description("Persistent, structured memory for AI coding agents.
|
|
12
|
-
.version(
|
|
17
|
+
.description("Your codebase never forgets. Persistent, structured memory for AI coding agents.")
|
|
18
|
+
.version(version);
|
|
13
19
|
program
|
|
14
20
|
.command("init")
|
|
15
21
|
.description("Initialize .context/ directory in the current repo")
|
|
@@ -23,6 +29,8 @@ program
|
|
|
23
29
|
.option("-p, --provider <provider>", "AI provider (anthropic, openai, gemini, grok)")
|
|
24
30
|
.option("-m, --model <model>", "Model to use (provider-specific)")
|
|
25
31
|
.option("-v, --verbose", "Show detailed output", false)
|
|
32
|
+
.option("--dry-run", "Show what would be analyzed without calling the AI", false)
|
|
33
|
+
.option("--merge", "Merge with existing context (don't overwrite manual edits)", false)
|
|
26
34
|
.action(analyzeCommand);
|
|
27
35
|
program
|
|
28
36
|
.command("sync")
|
|
@@ -37,48 +45,30 @@ program
|
|
|
37
45
|
.action(serveCommand);
|
|
38
46
|
program
|
|
39
47
|
.command("setup <tool>")
|
|
40
|
-
.description("Configure AI tool integration (claude, cursor, copilot)")
|
|
48
|
+
.description("Configure AI tool integration (claude, cursor, copilot, windsurf, cline, aider, continue)")
|
|
41
49
|
.option("-d, --dir <path>", "Repository root directory", process.cwd())
|
|
42
50
|
.action(setupCommand);
|
|
43
51
|
program
|
|
44
52
|
.command("status")
|
|
45
|
-
.description("Show the current state of .context/")
|
|
53
|
+
.description("Show the current state of .context/ with coverage and freshness")
|
|
46
54
|
.option("-d, --dir <path>", "Repository root directory", process.cwd())
|
|
47
|
-
.action(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const entries = store.listEntries();
|
|
61
|
-
console.log(chalk.bold("\n📊 repomemory status\n"));
|
|
62
|
-
console.log(` ${chalk.cyan("Total files:")} ${stats.totalFiles}`);
|
|
63
|
-
console.log(` ${chalk.cyan("Total size:")} ${(stats.totalSize / 1024).toFixed(1)}KB`);
|
|
64
|
-
console.log();
|
|
65
|
-
for (const [category, count] of Object.entries(stats.categories)) {
|
|
66
|
-
console.log(` ${chalk.bold(category + "/")} (${count} files)`);
|
|
67
|
-
const catEntries = entries.filter((e) => e.category === category);
|
|
68
|
-
for (const entry of catEntries) {
|
|
69
|
-
const sizeKb = (entry.sizeBytes / 1024).toFixed(1);
|
|
70
|
-
console.log(` ${chalk.dim("•")} ${entry.filename} — ${entry.title} (${sizeKb}KB)`);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
console.log();
|
|
74
|
-
console.log(chalk.dim(` Provider: ${config.provider} | Model: ${config.model}`));
|
|
75
|
-
});
|
|
76
|
-
// Global error handler — no stack traces for users
|
|
55
|
+
.action(statusCommand);
|
|
56
|
+
program
|
|
57
|
+
.command("wizard")
|
|
58
|
+
.description("Interactive guided setup — provider, tools, and first analysis in one flow")
|
|
59
|
+
.option("-d, --dir <path>", "Repository root directory", process.cwd())
|
|
60
|
+
.action(wizardCommand);
|
|
61
|
+
program
|
|
62
|
+
.command("dashboard")
|
|
63
|
+
.description("Open a web dashboard to browse and search your context files")
|
|
64
|
+
.option("-d, --dir <path>", "Repository root directory", process.cwd())
|
|
65
|
+
.option("--port <port>", "Port to serve on", "3333")
|
|
66
|
+
.action(dashboardCommand);
|
|
67
|
+
// Global error handlers
|
|
77
68
|
process.on("uncaughtException", (err) => {
|
|
78
69
|
const msg = err.message || String(err);
|
|
79
|
-
// Known error patterns → friendly messages
|
|
80
70
|
if (msg.includes("API key")) {
|
|
81
|
-
console.error(`\n
|
|
71
|
+
console.error(`\n\u2717 ${msg}`);
|
|
82
72
|
console.error("\n Set your API key and try again:");
|
|
83
73
|
console.error(" export ANTHROPIC_API_KEY=sk-ant-...");
|
|
84
74
|
console.error(" export OPENAI_API_KEY=sk-...");
|
|
@@ -86,24 +76,29 @@ process.on("uncaughtException", (err) => {
|
|
|
86
76
|
console.error(" export GROK_API_KEY=...");
|
|
87
77
|
}
|
|
88
78
|
else if (msg.includes("ENOENT")) {
|
|
89
|
-
console.error(`\n
|
|
79
|
+
console.error(`\n\u2717 File or directory not found: ${msg.split("'")[1] || "unknown"}`);
|
|
90
80
|
}
|
|
91
81
|
else if (msg.includes("EACCES")) {
|
|
92
|
-
console.error(`\n
|
|
82
|
+
console.error(`\n\u2717 Permission denied. Try running with appropriate permissions.`);
|
|
93
83
|
}
|
|
94
84
|
else if (msg.includes("fetch failed") || msg.includes("ECONNREFUSED")) {
|
|
95
|
-
console.error(`\n
|
|
85
|
+
console.error(`\n\u2717 Network error. Check your internet connection and try again.`);
|
|
96
86
|
}
|
|
97
87
|
else if (msg.includes("401") || msg.includes("authentication")) {
|
|
98
|
-
console.error(`\n
|
|
88
|
+
console.error(`\n\u2717 Authentication failed. Check your API key is valid.`);
|
|
99
89
|
}
|
|
100
90
|
else if (msg.includes("429") || msg.includes("rate limit")) {
|
|
101
|
-
console.error(`\n
|
|
91
|
+
console.error(`\n\u2717 Rate limited. Wait a moment and try again.`);
|
|
102
92
|
}
|
|
103
93
|
else {
|
|
104
|
-
console.error(`\n
|
|
94
|
+
console.error(`\n\u2717 ${msg}`);
|
|
105
95
|
}
|
|
106
96
|
process.exit(1);
|
|
107
97
|
});
|
|
98
|
+
process.on("unhandledRejection", (reason) => {
|
|
99
|
+
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
100
|
+
console.error(`\n\u2717 ${msg}`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
});
|
|
108
103
|
program.parse();
|
|
109
104
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAE/C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CACV,kFAAkF,CACnF;KACA,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,oDAAoD,CAAC;KACjE,MAAM,CAAC,kBAAkB,EAAE,2BAA2B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;KACtE,MAAM,CACL,2BAA2B,EAC3B,+CAA+C,EAC/C,WAAW,CACZ;KACA,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CACV,iFAAiF,CAClF;KACA,MAAM,CAAC,kBAAkB,EAAE,2BAA2B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;KACtE,MAAM,CACL,2BAA2B,EAC3B,+CAA+C,CAChD;KACA,MAAM,CAAC,qBAAqB,EAAE,kCAAkC,CAAC;KACjE,MAAM,CAAC,eAAe,EAAE,sBAAsB,EAAE,KAAK,CAAC;KACtD,MAAM,CAAC,WAAW,EAAE,oDAAoD,EAAE,KAAK,CAAC;KAChF,MAAM,CAAC,SAAS,EAAE,4DAA4D,EAAE,KAAK,CAAC;KACtF,MAAM,CAAC,cAAc,CAAC,CAAC;AAE1B,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,kDAAkD,CAAC;KAC/D,MAAM,CAAC,kBAAkB,EAAE,2BAA2B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;KACtE,MAAM,CAAC,oBAAoB,EAAE,2CAA2C,CAAC;KACzE,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,+CAA+C,CAAC;KAC5D,MAAM,CAAC,kBAAkB,EAAE,2BAA2B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;KACtE,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,cAAc,CAAC;KACvB,WAAW,CACV,2FAA2F,CAC5F;KACA,MAAM,CAAC,kBAAkB,EAAE,2BAA2B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;KACtE,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,iEAAiE,CAAC;KAC9E,MAAM,CAAC,kBAAkB,EAAE,2BAA2B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;KACtE,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,4EAA4E,CAAC;KACzF,MAAM,CAAC,kBAAkB,EAAE,2BAA2B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;KACtE,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,WAAW,CAAC;KACpB,WAAW,CAAC,8DAA8D,CAAC;KAC3E,MAAM,CAAC,kBAAkB,EAAE,2BAA2B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;KACtE,MAAM,CAAC,eAAe,EAAE,kBAAkB,EAAE,MAAM,CAAC;KACnD,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAE5B,wBAAwB;AACxB,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE;IACtC,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;IAEvC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACrD,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;QACzD,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAClD,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC/C,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC/C,CAAC;SAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,yCAAyC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC;IAC3F,CAAC;SAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,uEAAuE,CAAC,CAAC;IACzF,CAAC;SAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QACxE,OAAO,CAAC,KAAK,CAAC,uEAAuE,CAAC,CAAC;IACzF,CAAC;SAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACjE,OAAO,CAAC,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAChF,CAAC;SAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7D,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACvE,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE;IAC1C,MAAM,GAAG,GAAG,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACtE,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -6,6 +6,8 @@ export interface AIMessage {
|
|
|
6
6
|
export interface AIResponse {
|
|
7
7
|
content: string;
|
|
8
8
|
tokensUsed?: number;
|
|
9
|
+
inputTokens?: number;
|
|
10
|
+
outputTokens?: number;
|
|
9
11
|
}
|
|
10
12
|
export interface AIProvider {
|
|
11
13
|
name: string;
|
|
@@ -14,5 +16,14 @@ export interface AIProvider {
|
|
|
14
16
|
temperature?: number;
|
|
15
17
|
}): Promise<AIResponse>;
|
|
16
18
|
}
|
|
19
|
+
export declare class AIError extends Error {
|
|
20
|
+
readonly provider: string;
|
|
21
|
+
readonly statusCode?: number | undefined;
|
|
22
|
+
readonly isRetryable: boolean;
|
|
23
|
+
constructor(message: string, provider: string, statusCode?: number | undefined, isRetryable?: boolean);
|
|
24
|
+
}
|
|
17
25
|
export declare function createProvider(config: RepoContextConfig): Promise<AIProvider>;
|
|
26
|
+
export declare function validateApiKey(config: RepoContextConfig): Promise<boolean>;
|
|
27
|
+
/** Estimate cost for a given provider/model/token count */
|
|
28
|
+
export declare function estimateCost(provider: string, model: string, inputTokens: number, outputTokens: number): string;
|
|
18
29
|
//# sourceMappingURL=ai-provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-provider.d.ts","sourceRoot":"","sources":["../../src/lib/ai-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"ai-provider.d.ts","sourceRoot":"","sources":["../../src/lib/ai-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC9G;AAED,qBAAa,OAAQ,SAAQ,KAAK;aAGd,QAAQ,EAAE,MAAM;aAChB,UAAU,CAAC,EAAE,MAAM;aACnB,WAAW,EAAE,OAAO;gBAHpC,OAAO,EAAE,MAAM,EACC,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,YAAA,EACnB,WAAW,GAAE,OAAe;CAK/C;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAenF;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAOhF;AAiCD,2DAA2D;AAC3D,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,CAmBR"}
|
package/dist/lib/ai-provider.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
export class AIError extends Error {
|
|
2
|
+
provider;
|
|
3
|
+
statusCode;
|
|
4
|
+
isRetryable;
|
|
5
|
+
constructor(message, provider, statusCode, isRetryable = false) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.provider = provider;
|
|
8
|
+
this.statusCode = statusCode;
|
|
9
|
+
this.isRetryable = isRetryable;
|
|
10
|
+
this.name = "AIError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
1
13
|
export async function createProvider(config) {
|
|
2
14
|
const apiKey = resolveApiKeyForProvider(config);
|
|
3
15
|
switch (config.provider) {
|
|
@@ -13,6 +25,15 @@ export async function createProvider(config) {
|
|
|
13
25
|
throw new Error(`Unknown provider: ${config.provider}. Supported: anthropic, openai, gemini, grok`);
|
|
14
26
|
}
|
|
15
27
|
}
|
|
28
|
+
export async function validateApiKey(config) {
|
|
29
|
+
try {
|
|
30
|
+
resolveApiKeyForProvider(config);
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
16
37
|
function resolveApiKeyForProvider(config) {
|
|
17
38
|
if (config.apiKey)
|
|
18
39
|
return config.apiKey;
|
|
@@ -22,7 +43,6 @@ function resolveApiKeyForProvider(config) {
|
|
|
22
43
|
gemini: "GEMINI_API_KEY",
|
|
23
44
|
grok: "GROK_API_KEY",
|
|
24
45
|
};
|
|
25
|
-
// Also check alternate env var names
|
|
26
46
|
const altEnvMap = {
|
|
27
47
|
gemini: ["GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
|
|
28
48
|
grok: ["XAI_API_KEY"],
|
|
@@ -36,7 +56,28 @@ function resolveApiKeyForProvider(config) {
|
|
|
36
56
|
if (process.env[alt])
|
|
37
57
|
return process.env[alt];
|
|
38
58
|
}
|
|
39
|
-
throw new
|
|
59
|
+
throw new AIError(`No API key found for ${config.provider}. Set ${envVar} environment variable or add apiKey to .repomemory.json`, config.provider);
|
|
60
|
+
}
|
|
61
|
+
/** Estimate cost for a given provider/model/token count */
|
|
62
|
+
export function estimateCost(provider, model, inputTokens, outputTokens) {
|
|
63
|
+
// Approximate pricing per 1M tokens (as of 2025)
|
|
64
|
+
const pricing = {
|
|
65
|
+
"claude-sonnet-4-5-20250929": { input: 3, output: 15 },
|
|
66
|
+
"claude-opus-4-6": { input: 15, output: 75 },
|
|
67
|
+
"gpt-4o": { input: 2.5, output: 10 },
|
|
68
|
+
"o3-mini": { input: 1.1, output: 4.4 },
|
|
69
|
+
"gemini-2.0-flash": { input: 0.1, output: 0.4 },
|
|
70
|
+
"gemini-2.5-pro": { input: 1.25, output: 10 },
|
|
71
|
+
"grok-3": { input: 3, output: 15 },
|
|
72
|
+
"grok-3-mini": { input: 0.3, output: 0.5 },
|
|
73
|
+
};
|
|
74
|
+
const price = pricing[model];
|
|
75
|
+
if (!price)
|
|
76
|
+
return "unknown";
|
|
77
|
+
const cost = (inputTokens / 1_000_000) * price.input + (outputTokens / 1_000_000) * price.output;
|
|
78
|
+
if (cost < 0.01)
|
|
79
|
+
return "<$0.01";
|
|
80
|
+
return `~$${cost.toFixed(2)}`;
|
|
40
81
|
}
|
|
41
82
|
// --- Anthropic (streaming for large outputs) ---
|
|
42
83
|
async function createAnthropicProvider(apiKey, model) {
|
|
@@ -53,32 +94,30 @@ async function createAnthropicProvider(apiKey, model) {
|
|
|
53
94
|
role: m.role,
|
|
54
95
|
content: m.content,
|
|
55
96
|
}));
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
tokensUsed: finalMessage.usage.input_tokens + finalMessage.usage.output_tokens,
|
|
81
|
-
};
|
|
97
|
+
try {
|
|
98
|
+
const stream = client.messages.stream({
|
|
99
|
+
model: model || "claude-sonnet-4-5-20250929",
|
|
100
|
+
max_tokens: maxTokens,
|
|
101
|
+
temperature,
|
|
102
|
+
system: systemMsg?.content || "",
|
|
103
|
+
messages: conversationMsgs,
|
|
104
|
+
});
|
|
105
|
+
const finalMessage = await stream.finalMessage();
|
|
106
|
+
const content = finalMessage.content
|
|
107
|
+
.filter((block) => block.type === "text")
|
|
108
|
+
.map((block) => ("text" in block ? block.text : ""))
|
|
109
|
+
.join("");
|
|
110
|
+
return {
|
|
111
|
+
content,
|
|
112
|
+
tokensUsed: finalMessage.usage.input_tokens + finalMessage.usage.output_tokens,
|
|
113
|
+
inputTokens: finalMessage.usage.input_tokens,
|
|
114
|
+
outputTokens: finalMessage.usage.output_tokens,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
const e = err;
|
|
119
|
+
throw new AIError(e.message, "anthropic", e.status, e.status === 429 || e.status === 529 || e.status === 500);
|
|
120
|
+
}
|
|
82
121
|
},
|
|
83
122
|
};
|
|
84
123
|
}
|
|
@@ -90,19 +129,28 @@ async function createOpenAIProvider(apiKey, model) {
|
|
|
90
129
|
name: "openai",
|
|
91
130
|
async generate(messages, options = {}) {
|
|
92
131
|
const { maxTokens = 16000, temperature = 0.3 } = options;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
132
|
+
try {
|
|
133
|
+
const response = await client.chat.completions.create({
|
|
134
|
+
model: model || "gpt-4o",
|
|
135
|
+
max_completion_tokens: maxTokens,
|
|
136
|
+
temperature,
|
|
137
|
+
messages: messages.map((m) => ({
|
|
138
|
+
role: m.role,
|
|
139
|
+
content: m.content,
|
|
140
|
+
})),
|
|
141
|
+
});
|
|
142
|
+
const usage = response.usage;
|
|
143
|
+
return {
|
|
144
|
+
content: response.choices[0]?.message?.content || "",
|
|
145
|
+
tokensUsed: usage?.total_tokens,
|
|
146
|
+
inputTokens: usage?.prompt_tokens,
|
|
147
|
+
outputTokens: usage?.completion_tokens,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
const e = err;
|
|
152
|
+
throw new AIError(e.message, "openai", e.status, e.status === 429 || e.status === 500);
|
|
153
|
+
}
|
|
106
154
|
},
|
|
107
155
|
};
|
|
108
156
|
}
|
|
@@ -110,27 +158,39 @@ async function createOpenAIProvider(apiKey, model) {
|
|
|
110
158
|
async function createGeminiProvider(apiKey, model) {
|
|
111
159
|
const { GoogleGenerativeAI } = await import("@google/generative-ai");
|
|
112
160
|
const genAI = new GoogleGenerativeAI(apiKey);
|
|
113
|
-
const
|
|
161
|
+
const modelName = model || "gemini-2.0-flash";
|
|
114
162
|
return {
|
|
115
163
|
name: "gemini",
|
|
116
164
|
async generate(messages, options = {}) {
|
|
117
|
-
const { temperature = 0.3 } = options;
|
|
118
|
-
// Combine system + user messages for Gemini
|
|
165
|
+
const { temperature = 0.3, maxTokens = 16000 } = options;
|
|
119
166
|
const systemMsg = messages.find((m) => m.role === "system");
|
|
120
167
|
const userMsgs = messages.filter((m) => m.role !== "system");
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const result = await genModel.generateContent({
|
|
126
|
-
contents: [{ role: "user", parts: [{ text: prompt }] }],
|
|
127
|
-
generationConfig: { temperature },
|
|
168
|
+
// Use systemInstruction properly
|
|
169
|
+
const genModel = genAI.getGenerativeModel({
|
|
170
|
+
model: modelName,
|
|
171
|
+
systemInstruction: systemMsg?.content || undefined,
|
|
128
172
|
});
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
173
|
+
try {
|
|
174
|
+
const result = await genModel.generateContent({
|
|
175
|
+
contents: userMsgs.map((m) => ({
|
|
176
|
+
role: m.role === "assistant" ? "model" : "user",
|
|
177
|
+
parts: [{ text: m.content }],
|
|
178
|
+
})),
|
|
179
|
+
generationConfig: { temperature, maxOutputTokens: maxTokens },
|
|
180
|
+
});
|
|
181
|
+
const response = result.response;
|
|
182
|
+
const usage = response.usageMetadata;
|
|
183
|
+
return {
|
|
184
|
+
content: response.text(),
|
|
185
|
+
tokensUsed: usage?.totalTokenCount,
|
|
186
|
+
inputTokens: usage?.promptTokenCount,
|
|
187
|
+
outputTokens: usage?.candidatesTokenCount,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
const e = err;
|
|
192
|
+
throw new AIError(e.message, "gemini", e.status, true);
|
|
193
|
+
}
|
|
134
194
|
},
|
|
135
195
|
};
|
|
136
196
|
}
|
|
@@ -145,19 +205,28 @@ async function createGrokProvider(apiKey, model) {
|
|
|
145
205
|
name: "grok",
|
|
146
206
|
async generate(messages, options = {}) {
|
|
147
207
|
const { maxTokens = 16000, temperature = 0.3 } = options;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
208
|
+
try {
|
|
209
|
+
const response = await client.chat.completions.create({
|
|
210
|
+
model: model || "grok-3",
|
|
211
|
+
max_tokens: maxTokens,
|
|
212
|
+
temperature,
|
|
213
|
+
messages: messages.map((m) => ({
|
|
214
|
+
role: m.role,
|
|
215
|
+
content: m.content,
|
|
216
|
+
})),
|
|
217
|
+
});
|
|
218
|
+
const usage = response.usage;
|
|
219
|
+
return {
|
|
220
|
+
content: response.choices[0]?.message?.content || "",
|
|
221
|
+
tokensUsed: usage?.total_tokens,
|
|
222
|
+
inputTokens: usage?.prompt_tokens,
|
|
223
|
+
outputTokens: usage?.completion_tokens,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
const e = err;
|
|
228
|
+
throw new AIError(e.message, "grok", e.status, e.status === 429 || e.status === 500);
|
|
229
|
+
}
|
|
161
230
|
},
|
|
162
231
|
};
|
|
163
232
|
}
|