explainthisrepo 0.9.2 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/init.js +10 -1
- package/dist/providers/anthropic.d.ts +17 -0
- package/dist/providers/anthropic.js +68 -0
- package/dist/providers/ollama.js +25 -16
- package/dist/providers/registry.js +2 -0
- package/package.json +1 -1
package/dist/init.js
CHANGED
|
@@ -5,7 +5,8 @@ import { writeConfig } from "./config.js";
|
|
|
5
5
|
const PROVIDERS = {
|
|
6
6
|
"1": "gemini",
|
|
7
7
|
"2": "openai",
|
|
8
|
-
"3": "ollama"
|
|
8
|
+
"3": "ollama",
|
|
9
|
+
"4": "anthropic",
|
|
9
10
|
};
|
|
10
11
|
export async function runInit() {
|
|
11
12
|
const err = process.stderr;
|
|
@@ -42,6 +43,7 @@ async function promptProvider() {
|
|
|
42
43
|
err.write(" 1) Gemini\n");
|
|
43
44
|
err.write(" 2) OpenAI\n");
|
|
44
45
|
err.write(" 3) Ollama (local)\n");
|
|
46
|
+
err.write(" 4) Anthropic\n");
|
|
45
47
|
const choice = (await prompt("> ")).trim();
|
|
46
48
|
const provider = PROVIDERS[choice];
|
|
47
49
|
if (!provider) {
|
|
@@ -76,6 +78,13 @@ async function promptProviderConfig(provider) {
|
|
|
76
78
|
host
|
|
77
79
|
};
|
|
78
80
|
}
|
|
81
|
+
if (provider === "anthropic") {
|
|
82
|
+
const key = (await promptHidden("Anthropic API key: ")).trim();
|
|
83
|
+
if (!key) {
|
|
84
|
+
throw new Error("API key cannot be empty");
|
|
85
|
+
}
|
|
86
|
+
return { api_key: key };
|
|
87
|
+
}
|
|
79
88
|
throw new Error(`Unsupported provider: ${provider}`);
|
|
80
89
|
}
|
|
81
90
|
function prompt(label) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { LLMProvider } from "./base.js";
|
|
2
|
+
type AnthropicConfig = {
|
|
3
|
+
api_key?: string;
|
|
4
|
+
model?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare class AnthropicProvider implements LLMProvider {
|
|
7
|
+
name: string;
|
|
8
|
+
private apiKey;
|
|
9
|
+
private model;
|
|
10
|
+
private client;
|
|
11
|
+
constructor(config?: AnthropicConfig);
|
|
12
|
+
validateConfig(): void;
|
|
13
|
+
private getClient;
|
|
14
|
+
generate(prompt: string): Promise<string>;
|
|
15
|
+
doctor(): Promise<string[]>;
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { LLMProviderError } from "./base.js";
|
|
2
|
+
const DEFAULT_MODEL = "claude-3-5-sonnet-20241022";
|
|
3
|
+
export class AnthropicProvider {
|
|
4
|
+
name = "anthropic";
|
|
5
|
+
apiKey;
|
|
6
|
+
model;
|
|
7
|
+
client = null;
|
|
8
|
+
constructor(config = {}) {
|
|
9
|
+
this.apiKey = config.api_key ?? "";
|
|
10
|
+
this.model = config.model ?? DEFAULT_MODEL;
|
|
11
|
+
this.validateConfig();
|
|
12
|
+
}
|
|
13
|
+
validateConfig() {
|
|
14
|
+
if (!this.apiKey || !this.apiKey.trim()) {
|
|
15
|
+
throw new LLMProviderError("Anthropic provider requires an API key.\n" +
|
|
16
|
+
"Run `explainthisrepo init` or set providers.anthropic.api_key.");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
getClient() {
|
|
20
|
+
if (this.client) {
|
|
21
|
+
return this.client;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const { default: Anthropic } = require("@anthropic-ai/sdk");
|
|
25
|
+
this.client = new Anthropic({ apiKey: this.apiKey });
|
|
26
|
+
return this.client;
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
throw new LLMProviderError("Anthropic support is not installed.\n" +
|
|
30
|
+
"Install it with:\n" +
|
|
31
|
+
' npm install @anthropic-ai/sdk');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async generate(prompt) {
|
|
35
|
+
const client = this.getClient();
|
|
36
|
+
let response;
|
|
37
|
+
try {
|
|
38
|
+
response = await client.messages.create({
|
|
39
|
+
model: this.model,
|
|
40
|
+
max_tokens: 1024,
|
|
41
|
+
messages: [
|
|
42
|
+
{ role: "user", content: prompt }
|
|
43
|
+
]
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
const message = err?.message ? String(err.message) : String(err);
|
|
48
|
+
throw new LLMProviderError(`Anthropic request failed: ${message}`);
|
|
49
|
+
}
|
|
50
|
+
let text = null;
|
|
51
|
+
try {
|
|
52
|
+
text = response?.content?.[0]?.text ?? null;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
text = null;
|
|
56
|
+
}
|
|
57
|
+
if (!text || !text.trim()) {
|
|
58
|
+
throw new LLMProviderError("Anthropic returned no text");
|
|
59
|
+
}
|
|
60
|
+
return text.trim();
|
|
61
|
+
}
|
|
62
|
+
async doctor() {
|
|
63
|
+
return [
|
|
64
|
+
`ANTHROPIC_API_KEY set: ${Boolean(this.apiKey)}`,
|
|
65
|
+
`model: ${this.model}`,
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
}
|
package/dist/providers/ollama.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { LLMProviderError } from "./base.js";
|
|
2
|
-
const DEFAULT_MODEL = "llama3";
|
|
3
2
|
const DEFAULT_HOST = "http://localhost:11434";
|
|
4
3
|
export class OllamaProvider {
|
|
5
4
|
name = "ollama";
|
|
6
5
|
model;
|
|
7
6
|
host;
|
|
8
7
|
constructor(config = {}) {
|
|
9
|
-
this.model = config.model
|
|
8
|
+
this.model = config.model;
|
|
10
9
|
this.host = (config.host ?? DEFAULT_HOST).replace(/\/$/, "");
|
|
11
10
|
this.validateConfig();
|
|
12
11
|
}
|
|
13
12
|
validateConfig() {
|
|
13
|
+
if (!this.model || !String(this.model).trim()) {
|
|
14
|
+
throw new LLMProviderError("Ollama provider requires a model.\n" +
|
|
15
|
+
"Set providers.ollama.model (e.g. llama3, gemma3:4b, glm-5:cloud).");
|
|
16
|
+
}
|
|
14
17
|
if (!this.host.startsWith("http")) {
|
|
15
18
|
throw new LLMProviderError("Ollama host must be a valid URL (e.g. http://localhost:11434)");
|
|
16
19
|
}
|
|
@@ -28,8 +31,8 @@ export class OllamaProvider {
|
|
|
28
31
|
results.push(`Ollama server responded with ${res.status}`);
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
|
-
catch {
|
|
32
|
-
results.push(
|
|
34
|
+
catch (err) {
|
|
35
|
+
results.push(`Ollama server not reachable: ${String(err?.message ?? err)}`);
|
|
33
36
|
}
|
|
34
37
|
results.push(`model: ${this.model}`);
|
|
35
38
|
results.push(`host: ${this.host}`);
|
|
@@ -42,32 +45,38 @@ export class OllamaProvider {
|
|
|
42
45
|
prompt,
|
|
43
46
|
stream: false
|
|
44
47
|
};
|
|
48
|
+
let res;
|
|
45
49
|
try {
|
|
46
|
-
|
|
50
|
+
res = await fetch(url, {
|
|
47
51
|
method: "POST",
|
|
48
52
|
headers: {
|
|
49
53
|
"Content-Type": "application/json"
|
|
50
54
|
},
|
|
51
55
|
body: JSON.stringify(payload)
|
|
52
56
|
});
|
|
53
|
-
if (!res.ok) {
|
|
54
|
-
throw new LLMProviderError(`Ollama server responded with ${res.status}`);
|
|
55
|
-
}
|
|
56
|
-
const data = await res.json();
|
|
57
|
-
const text = data?.response ?? "";
|
|
58
|
-
if (!text.trim()) {
|
|
59
|
-
throw new LLMProviderError("Ollama returned no text");
|
|
60
|
-
}
|
|
61
|
-
return text.trim();
|
|
62
57
|
}
|
|
63
58
|
catch (err) {
|
|
64
|
-
const message = err?.message ? String(err.message) : String(err);
|
|
65
59
|
throw new LLMProviderError([
|
|
66
60
|
"Failed to connect to Ollama.",
|
|
67
61
|
"Ensure Ollama is running locally.",
|
|
68
62
|
"Start it with: ollama serve",
|
|
69
|
-
`Error: ${message}`
|
|
63
|
+
`Error: ${String(err?.message ?? err)}`
|
|
70
64
|
].join("\n"));
|
|
71
65
|
}
|
|
66
|
+
if (!res.ok) {
|
|
67
|
+
throw new LLMProviderError(`Ollama HTTP error: ${res.status}`);
|
|
68
|
+
}
|
|
69
|
+
let data;
|
|
70
|
+
try {
|
|
71
|
+
data = await res.json();
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
throw new LLMProviderError("Invalid response from Ollama");
|
|
75
|
+
}
|
|
76
|
+
const text = data?.response;
|
|
77
|
+
if (!text || !String(text).trim()) {
|
|
78
|
+
throw new LLMProviderError("Ollama returned no text");
|
|
79
|
+
}
|
|
80
|
+
return String(text).trim();
|
|
72
81
|
}
|
|
73
82
|
}
|
|
@@ -3,10 +3,12 @@ import { LLMProviderError } from "./base.js";
|
|
|
3
3
|
import { GeminiProvider } from "./gemini.js";
|
|
4
4
|
import { OpenAIProvider } from "./openai.js";
|
|
5
5
|
import { OllamaProvider } from "./ollama.js";
|
|
6
|
+
import { AnthropicProvider } from "./anthropic.js";
|
|
6
7
|
const PROVIDER_REGISTRY = {
|
|
7
8
|
gemini: GeminiProvider,
|
|
8
9
|
openai: OpenAIProvider,
|
|
9
10
|
ollama: OllamaProvider,
|
|
11
|
+
anthropic: AnthropicProvider,
|
|
10
12
|
};
|
|
11
13
|
export function listProviders() {
|
|
12
14
|
return Object.keys(PROVIDER_REGISTRY);
|