@anvaka/vue-llm 0.1.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 +166 -0
- package/dist/_virtual/_plugin-vue_export-helper.js +9 -0
- package/dist/core/LLMClient.js +248 -0
- package/dist/core/configStore.js +52 -0
- package/dist/core/keyStore.js +58 -0
- package/dist/core/storageAdapter.js +67 -0
- package/dist/index.js +38 -0
- package/dist/providers/AnthropicProvider.js +88 -0
- package/dist/providers/BaseProvider.js +155 -0
- package/dist/providers/CustomProvider.js +53 -0
- package/dist/providers/GeminiProvider.js +163 -0
- package/dist/providers/GrokProvider.js +70 -0
- package/dist/providers/LlamaServerProvider.js +56 -0
- package/dist/providers/OllamaProvider.js +77 -0
- package/dist/providers/OpenAIProvider.js +98 -0
- package/dist/providers/OpenRouterProvider.js +81 -0
- package/dist/providers/factory.js +69 -0
- package/dist/providers/index.js +12 -0
- package/dist/vue/components/LLMConfigModal.vue.js +498 -0
- package/dist/vue/components/ProviderSelector.vue.js +53 -0
- package/dist/vue/components/StoredKeysManager.vue.js +223 -0
- package/dist/vue/index.js +17 -0
- package/dist/vue/plugin.js +26 -0
- package/dist/vue/useLLM.js +137 -0
- package/dist/vue-llm.css +1 -0
- package/package.json +41 -0
- package/src/styles/components.css +15 -0
- package/src/styles/variables.css +70 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { BaseProvider as c } from "./BaseProvider.js";
|
|
2
|
+
class d extends c {
|
|
3
|
+
async detectCapabilities() {
|
|
4
|
+
var e;
|
|
5
|
+
(e = this.config.model) != null && e.includes("claude-3") && this.capabilities.add("vision");
|
|
6
|
+
}
|
|
7
|
+
prepareRequest(e, t) {
|
|
8
|
+
const n = {
|
|
9
|
+
model: t.model || this.config.model || "claude-3-sonnet-20240229",
|
|
10
|
+
max_tokens: t.maxTokens || 1e3,
|
|
11
|
+
temperature: t.temperature || 0.7,
|
|
12
|
+
messages: e.filter((s) => s.role !== "system"),
|
|
13
|
+
stream: t.stream || !1
|
|
14
|
+
}, r = e.find((s) => s.role === "system");
|
|
15
|
+
return r && (n.system = r.content), n;
|
|
16
|
+
}
|
|
17
|
+
processMessages(e, t) {
|
|
18
|
+
return t.images && this.capabilities.has("vision") ? this.addImagesToMessages(e, t.images) : e;
|
|
19
|
+
}
|
|
20
|
+
addImagesToMessages(e, t) {
|
|
21
|
+
const n = e[e.length - 1];
|
|
22
|
+
if (n && n.role === "user") {
|
|
23
|
+
const r = [{ type: "text", text: n.content }];
|
|
24
|
+
t.forEach((s) => {
|
|
25
|
+
r.push({
|
|
26
|
+
type: "image",
|
|
27
|
+
source: { type: "base64", media_type: "image/jpeg", data: typeof s == "string" ? s : s.data }
|
|
28
|
+
});
|
|
29
|
+
}), n.content = r;
|
|
30
|
+
}
|
|
31
|
+
return e;
|
|
32
|
+
}
|
|
33
|
+
processResponse(e) {
|
|
34
|
+
var n, r;
|
|
35
|
+
const t = a(e.stop_reason);
|
|
36
|
+
return { content: ((r = (n = e.content) == null ? void 0 : n[0]) == null ? void 0 : r.text) || "", usage: e.usage || null, finishReason: t };
|
|
37
|
+
}
|
|
38
|
+
parseStreamingLine(e) {
|
|
39
|
+
if (!e.startsWith("data: ")) return null;
|
|
40
|
+
const t = e.slice(6).trim();
|
|
41
|
+
if (t === "[DONE]") return { done: !0 };
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(t);
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
extractStreamingContent(e) {
|
|
49
|
+
var t, n, r, s;
|
|
50
|
+
if (e.done) return { done: !0 };
|
|
51
|
+
if (e.type === "error") {
|
|
52
|
+
const u = ((t = e.error) == null ? void 0 : t.type) || "anthropic_error", o = new Error(((n = e.error) == null ? void 0 : n.message) || "Anthropic streaming error");
|
|
53
|
+
throw o.code = u, e.request_id && (o.requestId = e.request_id), o;
|
|
54
|
+
}
|
|
55
|
+
return e.type === "content_block_delta" ? { content: ((r = e.delta) == null ? void 0 : r.text) || "", thinking: "", done: !1, usage: null, finishReason: null } : e.type === "message_delta" ? { content: "", thinking: "", done: !1, usage: e.usage ? { tokens: e.usage.output_tokens || 0 } : null, finishReason: a((s = e.delta) == null ? void 0 : s.stop_reason) } : e.type === "message_stop" ? { content: "", thinking: "", done: !0, usage: null, finishReason: a(e.stop_reason) } : null;
|
|
56
|
+
}
|
|
57
|
+
getApiPath() {
|
|
58
|
+
return "/v1/messages";
|
|
59
|
+
}
|
|
60
|
+
requiresAuth() {
|
|
61
|
+
return !!this.config.apiKey;
|
|
62
|
+
}
|
|
63
|
+
getAuthHeaderName() {
|
|
64
|
+
return "x-api-key";
|
|
65
|
+
}
|
|
66
|
+
getAuthHeaderValue() {
|
|
67
|
+
return this.config.apiKey;
|
|
68
|
+
}
|
|
69
|
+
buildHeaders() {
|
|
70
|
+
const e = super.buildHeaders();
|
|
71
|
+
return this.requiresAuth() && (e["anthropic-version"] = "2023-06-01", e["anthropic-dangerous-direct-browser-access"] = "true"), e;
|
|
72
|
+
}
|
|
73
|
+
getModelsEndpoint() {
|
|
74
|
+
return `${this.config.baseUrl}/v1/models`;
|
|
75
|
+
}
|
|
76
|
+
parseModelsResponse(e) {
|
|
77
|
+
var t;
|
|
78
|
+
return ((t = e.data) == null ? void 0 : t.map((n) => n.id)) || [];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function a(i) {
|
|
82
|
+
if (!i) return null;
|
|
83
|
+
const e = String(i).toLowerCase();
|
|
84
|
+
return e === "max_tokens" ? "length" : e;
|
|
85
|
+
}
|
|
86
|
+
export {
|
|
87
|
+
d as AnthropicProvider
|
|
88
|
+
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
class R {
|
|
2
|
+
constructor(e) {
|
|
3
|
+
this.config = e, this.capabilities = /* @__PURE__ */ new Set(), this.activeRequests = /* @__PURE__ */ new Map();
|
|
4
|
+
}
|
|
5
|
+
async initialize() {
|
|
6
|
+
await this.detectCapabilities();
|
|
7
|
+
}
|
|
8
|
+
async detectCapabilities() {
|
|
9
|
+
}
|
|
10
|
+
prepareRequest(e, t) {
|
|
11
|
+
throw new Error("prepareRequest must be implemented by subclass");
|
|
12
|
+
}
|
|
13
|
+
processResponse(e) {
|
|
14
|
+
throw new Error("processResponse must be implemented by subclass");
|
|
15
|
+
}
|
|
16
|
+
async streamRequest(e, t, s) {
|
|
17
|
+
const n = this.prepareRequest(e, t), r = new AbortController(), i = t.requestId || this.generateRequestId();
|
|
18
|
+
this.activeRequests.set(i, r);
|
|
19
|
+
try {
|
|
20
|
+
const d = (await this.makeStreamingRequest(n, r.signal)).body.getReader(), p = new TextDecoder();
|
|
21
|
+
let c = "", h = "";
|
|
22
|
+
for (; ; ) {
|
|
23
|
+
const { done: m, value: b } = await d.read();
|
|
24
|
+
if (m) break;
|
|
25
|
+
const g = p.decode(b, { stream: !0 }).split(`
|
|
26
|
+
`).filter((l) => l.trim());
|
|
27
|
+
for (const l of g) {
|
|
28
|
+
const u = this.parseStreamingLine(l);
|
|
29
|
+
if (!u) continue;
|
|
30
|
+
const o = this.extractStreamingContent(u);
|
|
31
|
+
if (o && (o.content && (c += o.content), o.thinking && (h += o.thinking), s({
|
|
32
|
+
content: o.content || "",
|
|
33
|
+
thinking: o.thinking || "",
|
|
34
|
+
fullContent: c,
|
|
35
|
+
fullThinking: h,
|
|
36
|
+
done: o.done || !1,
|
|
37
|
+
usage: o.usage || null,
|
|
38
|
+
finishReason: o.finishReason || null
|
|
39
|
+
}), o.done))
|
|
40
|
+
return c;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return c;
|
|
44
|
+
} catch (a) {
|
|
45
|
+
throw a.name === "AbortError" ? new Error("Request cancelled") : a;
|
|
46
|
+
} finally {
|
|
47
|
+
this.activeRequests.delete(i);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async makeRequest(e, t, s) {
|
|
51
|
+
const n = t ? { signal: t } : new AbortController();
|
|
52
|
+
t || (s = s || this.generateRequestId(), this.activeRequests.set(s, n));
|
|
53
|
+
try {
|
|
54
|
+
const r = this.buildHeaders(), i = await fetch(this.getEndpoint(), {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers: r,
|
|
57
|
+
body: JSON.stringify(e),
|
|
58
|
+
signal: n.signal || t
|
|
59
|
+
});
|
|
60
|
+
if (!i.ok) {
|
|
61
|
+
const a = await i.text();
|
|
62
|
+
throw new Error(`LLM API Error (${i.status}): ${a}`);
|
|
63
|
+
}
|
|
64
|
+
return i.json();
|
|
65
|
+
} catch (r) {
|
|
66
|
+
throw r.name === "AbortError" ? new Error("Request cancelled") : r;
|
|
67
|
+
} finally {
|
|
68
|
+
!t && s && this.activeRequests.delete(s);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async makeStreamingRequest(e, t) {
|
|
72
|
+
const s = this.buildHeaders(), n = await fetch(this.getStreamingEndpoint(), {
|
|
73
|
+
method: "POST",
|
|
74
|
+
headers: s,
|
|
75
|
+
body: JSON.stringify(e),
|
|
76
|
+
signal: t
|
|
77
|
+
});
|
|
78
|
+
if (!n.ok) {
|
|
79
|
+
const r = await n.text();
|
|
80
|
+
throw new Error(`LLM API Error (${n.status}): ${r}`);
|
|
81
|
+
}
|
|
82
|
+
return n;
|
|
83
|
+
}
|
|
84
|
+
buildHeaders() {
|
|
85
|
+
const e = { "Content-Type": "application/json" };
|
|
86
|
+
return this.requiresAuth() && (e[this.getAuthHeaderName()] = this.getAuthHeaderValue()), e;
|
|
87
|
+
}
|
|
88
|
+
getStreamingEndpoint() {
|
|
89
|
+
return `${this.config.baseUrl}${this.getApiPath()}`;
|
|
90
|
+
}
|
|
91
|
+
getEndpoint() {
|
|
92
|
+
return `${this.config.baseUrl}${this.getApiPath()}`;
|
|
93
|
+
}
|
|
94
|
+
parseStreamingLine(e) {
|
|
95
|
+
throw new Error("parseStreamingLine must be implemented by subclass");
|
|
96
|
+
}
|
|
97
|
+
extractStreamingContent(e) {
|
|
98
|
+
throw new Error("extractStreamingContent must be implemented by subclass");
|
|
99
|
+
}
|
|
100
|
+
getApiPath() {
|
|
101
|
+
throw new Error("getApiPath must be implemented by subclass");
|
|
102
|
+
}
|
|
103
|
+
requiresAuth() {
|
|
104
|
+
return !1;
|
|
105
|
+
}
|
|
106
|
+
getAuthHeaderName() {
|
|
107
|
+
return "Authorization";
|
|
108
|
+
}
|
|
109
|
+
getAuthHeaderValue() {
|
|
110
|
+
return `Bearer ${this.config.apiKey}`;
|
|
111
|
+
}
|
|
112
|
+
generateRequestId() {
|
|
113
|
+
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
114
|
+
}
|
|
115
|
+
// Cancel all active requests
|
|
116
|
+
cancelAllRequests() {
|
|
117
|
+
for (const [, e] of this.activeRequests)
|
|
118
|
+
e.abort();
|
|
119
|
+
this.activeRequests.clear();
|
|
120
|
+
}
|
|
121
|
+
// Cancel specific request
|
|
122
|
+
cancelRequest(e) {
|
|
123
|
+
const t = this.activeRequests.get(e);
|
|
124
|
+
t && (t.abort(), this.activeRequests.delete(e));
|
|
125
|
+
}
|
|
126
|
+
// Check if provider has capability
|
|
127
|
+
hasCapability(e) {
|
|
128
|
+
return this.capabilities.has(e);
|
|
129
|
+
}
|
|
130
|
+
// Discover available models (override in subclass if needed)
|
|
131
|
+
async discoverModels(e = 1e4) {
|
|
132
|
+
try {
|
|
133
|
+
const t = this.buildHeaders(), s = new AbortController(), n = setTimeout(() => s.abort(), e), r = await fetch(this.getModelsEndpoint(), {
|
|
134
|
+
method: "GET",
|
|
135
|
+
headers: t,
|
|
136
|
+
signal: s.signal
|
|
137
|
+
});
|
|
138
|
+
if (clearTimeout(n), !r.ok)
|
|
139
|
+
throw new Error(`Failed to fetch models: ${r.status} ${r.statusText}`);
|
|
140
|
+
const i = await r.json();
|
|
141
|
+
return this.parseModelsResponse(i);
|
|
142
|
+
} catch (t) {
|
|
143
|
+
throw t.name === "AbortError" ? new Error("Model discovery timeout - please check your connection") : t;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
getModelsEndpoint() {
|
|
147
|
+
throw new Error("getModelsEndpoint must be implemented by subclass");
|
|
148
|
+
}
|
|
149
|
+
parseModelsResponse(e) {
|
|
150
|
+
throw new Error("parseModelsResponse must be implemented by subclass");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
export {
|
|
154
|
+
R as BaseProvider
|
|
155
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { BaseProvider as u } from "./BaseProvider.js";
|
|
2
|
+
class l extends u {
|
|
3
|
+
async detectCapabilities() {
|
|
4
|
+
}
|
|
5
|
+
prepareRequest(e, t) {
|
|
6
|
+
return {
|
|
7
|
+
model: t.model || this.config.model || "gpt-3.5-turbo",
|
|
8
|
+
messages: e,
|
|
9
|
+
temperature: t.temperature || 0.7,
|
|
10
|
+
max_tokens: t.maxTokens || 1e3,
|
|
11
|
+
stream: t.stream || !1
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
processResponse(e) {
|
|
15
|
+
var t, n, r, s, a;
|
|
16
|
+
return { content: ((r = (n = (t = e.choices) == null ? void 0 : t[0]) == null ? void 0 : n.message) == null ? void 0 : r.content) || "", usage: e.usage || null, finishReason: o((a = (s = e.choices) == null ? void 0 : s[0]) == null ? void 0 : a.finish_reason) };
|
|
17
|
+
}
|
|
18
|
+
parseStreamingLine(e) {
|
|
19
|
+
if (!e.startsWith("data: ")) return null;
|
|
20
|
+
const t = e.slice(6).trim();
|
|
21
|
+
if (t === "[DONE]") return { done: !0 };
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(t);
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
extractStreamingContent(e) {
|
|
29
|
+
var t, n, r, s, a;
|
|
30
|
+
return e.done ? { done: !0 } : { content: ((r = (n = (t = e.choices) == null ? void 0 : t[0]) == null ? void 0 : n.delta) == null ? void 0 : r.content) || "", thinking: "", done: !1, usage: e.usage || null, finishReason: o((a = (s = e.choices) == null ? void 0 : s[0]) == null ? void 0 : a.finish_reason) };
|
|
31
|
+
}
|
|
32
|
+
getApiPath() {
|
|
33
|
+
return "/v1/chat/completions";
|
|
34
|
+
}
|
|
35
|
+
requiresAuth() {
|
|
36
|
+
return !!this.config.apiKey;
|
|
37
|
+
}
|
|
38
|
+
getModelsEndpoint() {
|
|
39
|
+
return `${this.config.baseUrl}/v1/models`;
|
|
40
|
+
}
|
|
41
|
+
parseModelsResponse(e) {
|
|
42
|
+
var t, n;
|
|
43
|
+
return ((n = (t = e.data) == null ? void 0 : t.map((r) => r.id)) == null ? void 0 : n.sort()) || [];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function o(i) {
|
|
47
|
+
if (!i) return null;
|
|
48
|
+
const e = String(i).toLowerCase();
|
|
49
|
+
return e === "max_tokens" ? "length" : e;
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
l as CustomProvider
|
|
53
|
+
};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { BaseProvider as A } from "./BaseProvider.js";
|
|
2
|
+
class _ extends A {
|
|
3
|
+
async detectCapabilities() {
|
|
4
|
+
this.config.model && ((this.config.model.includes("gemini-pro-vision") || this.config.model.includes("gemini-1.5") || this.config.model.includes("gemini-2.0")) && this.capabilities.add("vision"), (this.config.model.includes("gemini-pro") || this.config.model.includes("gemini-1.5") || this.config.model.includes("gemini-2.0")) && this.capabilities.add("tools"), this.config.model.includes("gemini-2.0") && this.capabilities.add("thinking"));
|
|
5
|
+
}
|
|
6
|
+
prepareRequest(e, t) {
|
|
7
|
+
const n = this.processMessages(e, t), s = {
|
|
8
|
+
contents: this.convertToGeminiFormat(n),
|
|
9
|
+
generationConfig: {
|
|
10
|
+
temperature: t.temperature || this.config.temperature || 0.7,
|
|
11
|
+
maxOutputTokens: t.maxTokens || this.config.maxTokens || 1e3,
|
|
12
|
+
topP: 0.8,
|
|
13
|
+
topK: 10
|
|
14
|
+
},
|
|
15
|
+
safetySettings: [
|
|
16
|
+
{ category: "HARM_CATEGORY_HARASSMENT", threshold: "BLOCK_NONE" },
|
|
17
|
+
{ category: "HARM_CATEGORY_HATE_SPEECH", threshold: "BLOCK_NONE" },
|
|
18
|
+
{ category: "HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold: "BLOCK_NONE" },
|
|
19
|
+
{ category: "HARM_CATEGORY_DANGEROUS_CONTENT", threshold: "BLOCK_NONE" }
|
|
20
|
+
]
|
|
21
|
+
}, i = e.find((o) => o.role === "system");
|
|
22
|
+
return i && (s.systemInstruction = { parts: [{ text: i.content }] }), t.tools && this.capabilities.has("tools") && (s.tools = this.convertToolsToGeminiFormat(t.tools)), s;
|
|
23
|
+
}
|
|
24
|
+
convertToGeminiFormat(e) {
|
|
25
|
+
const t = [];
|
|
26
|
+
for (const n of e) {
|
|
27
|
+
if (n.role === "system") continue;
|
|
28
|
+
const s = n.role === "assistant" ? "model" : "user";
|
|
29
|
+
if (Array.isArray(n.content)) {
|
|
30
|
+
const i = n.content.map((o) => {
|
|
31
|
+
var a, l;
|
|
32
|
+
return o.type === "text" ? { text: o.text } : o.type === "image" ? { inlineData: { mimeType: ((a = o.source) == null ? void 0 : a.media_type) || "image/jpeg", data: ((l = o.source) == null ? void 0 : l.data) || o.data } } : o.type === "image_url" ? { inlineData: { mimeType: "image/jpeg", data: o.image_url.url.split(",")[1] } } : { text: String(o) };
|
|
33
|
+
});
|
|
34
|
+
t.push({ role: s, parts: i });
|
|
35
|
+
} else
|
|
36
|
+
t.push({ role: s, parts: [{ text: n.content }] });
|
|
37
|
+
}
|
|
38
|
+
return t;
|
|
39
|
+
}
|
|
40
|
+
processMessages(e, t) {
|
|
41
|
+
return t.images && this.capabilities.has("vision") ? this.addImagesToMessages(e, t.images) : e;
|
|
42
|
+
}
|
|
43
|
+
addImagesToMessages(e, t) {
|
|
44
|
+
const n = e[e.length - 1];
|
|
45
|
+
if (n && n.role === "user") {
|
|
46
|
+
const s = [{ type: "text", text: n.content }];
|
|
47
|
+
t.forEach((i) => s.push({ type: "image", data: typeof i == "string" ? i : i.data, mimeType: "image/jpeg" })), n.content = s;
|
|
48
|
+
}
|
|
49
|
+
return e;
|
|
50
|
+
}
|
|
51
|
+
convertToolsToGeminiFormat(e) {
|
|
52
|
+
return e.map((t) => ({ functionDeclarations: [{ name: t.function.name, description: t.function.description, parameters: t.function.parameters }] }));
|
|
53
|
+
}
|
|
54
|
+
processResponse(e) {
|
|
55
|
+
var n, s;
|
|
56
|
+
const t = { content: "", usage: null, finishReason: null };
|
|
57
|
+
if (e.candidates && e.candidates.length > 0) {
|
|
58
|
+
const i = e.candidates[0];
|
|
59
|
+
if ((n = i.content) != null && n.parts && (t.content = i.content.parts.filter((o) => o.text).map((o) => o.text).join("")), (s = i.content) != null && s.parts) {
|
|
60
|
+
const o = i.content.parts.filter((a) => a.functionCall);
|
|
61
|
+
o.length > 0 && (t.functionCalls = o);
|
|
62
|
+
}
|
|
63
|
+
i.finishReason && (t.finishReason = k(i.finishReason));
|
|
64
|
+
}
|
|
65
|
+
return e.usageMetadata && (t.usage = {
|
|
66
|
+
promptTokens: e.usageMetadata.promptTokenCount,
|
|
67
|
+
completionTokens: e.usageMetadata.candidatesTokenCount,
|
|
68
|
+
totalTokens: e.usageMetadata.totalTokenCount
|
|
69
|
+
}), t;
|
|
70
|
+
}
|
|
71
|
+
async streamRequest(e, t, n) {
|
|
72
|
+
const s = this.prepareRequest(e, t), i = new AbortController(), o = t.requestId || this.generateRequestId();
|
|
73
|
+
this.activeRequests.set(o, i);
|
|
74
|
+
try {
|
|
75
|
+
const l = (await this.makeStreamingRequest(s, i.signal)).body.getReader(), m = new TextDecoder();
|
|
76
|
+
let c = "", R = "", u = "", f = 0, d = 0, h = !1, C = !1;
|
|
77
|
+
for (; ; ) {
|
|
78
|
+
const { done: y, value: M } = await l.read();
|
|
79
|
+
if (y) break;
|
|
80
|
+
u += m.decode(M, { stream: !0 });
|
|
81
|
+
for (let g = d; g < u.length; g++) {
|
|
82
|
+
const p = u[g];
|
|
83
|
+
if (C) {
|
|
84
|
+
C = !1;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (p === "\\" && h) {
|
|
88
|
+
C = !0;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (p === '"') {
|
|
92
|
+
h = !h;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (!h) {
|
|
96
|
+
if (p === "{")
|
|
97
|
+
f === 0 && (d = g), f++;
|
|
98
|
+
else if (p === "}" && (f--, f === 0)) {
|
|
99
|
+
const x = u.slice(d, g + 1);
|
|
100
|
+
try {
|
|
101
|
+
const b = JSON.parse(x), r = this.extractStreamingContent(b);
|
|
102
|
+
if (r && (r.content && (c += r.content), r.thinking && (R += r.thinking), n({ content: r.content || "", thinking: r.thinking || "", fullContent: c, fullThinking: R, done: r.done || !1, usage: r.usage || null, finishReason: r.finishReason || null }), r.done))
|
|
103
|
+
return c;
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
d = g + 1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
f === 0 && d < u.length && (u = u.slice(d), d = 0);
|
|
111
|
+
}
|
|
112
|
+
return c;
|
|
113
|
+
} catch (a) {
|
|
114
|
+
throw a.name === "AbortError" ? new Error("Request cancelled") : a;
|
|
115
|
+
} finally {
|
|
116
|
+
this.activeRequests.delete(o);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
extractStreamingContent(e) {
|
|
120
|
+
var a, l, m;
|
|
121
|
+
if (!((a = e == null ? void 0 : e.candidates) != null && a.length)) return null;
|
|
122
|
+
const t = e.candidates[0];
|
|
123
|
+
let n = "", s = "", i = !1, o = null;
|
|
124
|
+
return (l = t.content) != null && l.parts && (n = t.content.parts.filter((c) => c.text).map((c) => c.text).join("")), t.finishReason && (i = !0, o = k(t.finishReason)), ((m = e.usageMetadata) == null ? void 0 : m.thoughtsTokenCount) > 0 && (s = `[Thinking: ${e.usageMetadata.thoughtsTokenCount} tokens]`), { content: n, thinking: s, done: i, usage: e.usageMetadata ? { promptTokens: e.usageMetadata.promptTokenCount, completionTokens: e.usageMetadata.candidatesTokenCount, totalTokens: e.usageMetadata.totalTokenCount } : null, finishReason: o };
|
|
125
|
+
}
|
|
126
|
+
getApiPath() {
|
|
127
|
+
return `/v1beta/models/${this.config.model || "gemini-pro"}:generateContent`;
|
|
128
|
+
}
|
|
129
|
+
getStreamingEndpoint() {
|
|
130
|
+
const e = this.config.model || "gemini-pro";
|
|
131
|
+
return `${this.config.baseUrl}/v1beta/models/${e}:streamGenerateContent`;
|
|
132
|
+
}
|
|
133
|
+
requiresAuth() {
|
|
134
|
+
return !!this.config.apiKey;
|
|
135
|
+
}
|
|
136
|
+
getAuthHeaderName() {
|
|
137
|
+
return "x-goog-api-key";
|
|
138
|
+
}
|
|
139
|
+
getAuthHeaderValue() {
|
|
140
|
+
return this.config.apiKey;
|
|
141
|
+
}
|
|
142
|
+
buildHeaders() {
|
|
143
|
+
return super.buildHeaders();
|
|
144
|
+
}
|
|
145
|
+
getModelsEndpoint() {
|
|
146
|
+
return `${this.config.baseUrl}/v1beta/models`;
|
|
147
|
+
}
|
|
148
|
+
parseModelsResponse(e) {
|
|
149
|
+
var t;
|
|
150
|
+
return ((t = e.models) == null ? void 0 : t.filter((n) => {
|
|
151
|
+
var i;
|
|
152
|
+
return n.name.toLowerCase().includes("gemini") && ((i = n.supportedGenerationMethods) == null ? void 0 : i.includes("generateContent"));
|
|
153
|
+
}).map((n) => n.name.split("/").pop()).sort()) || [];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function k(T) {
|
|
157
|
+
if (!T) return null;
|
|
158
|
+
const e = String(T).toLowerCase();
|
|
159
|
+
return e.includes("max") && e.includes("token") ? "length" : e;
|
|
160
|
+
}
|
|
161
|
+
export {
|
|
162
|
+
_ as GeminiProvider
|
|
163
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { BaseProvider as c } from "./BaseProvider.js";
|
|
2
|
+
class u extends c {
|
|
3
|
+
async detectCapabilities() {
|
|
4
|
+
if (!this.config.model) return;
|
|
5
|
+
const e = this.config.model.toLowerCase();
|
|
6
|
+
(e.includes("grok-2") || e.includes("vision")) && this.capabilities.add("vision"), this.capabilities.add("tools");
|
|
7
|
+
}
|
|
8
|
+
prepareRequest(e, t) {
|
|
9
|
+
const s = {
|
|
10
|
+
model: t.model || this.config.model || "grok-beta",
|
|
11
|
+
messages: this.processMessages(e, t),
|
|
12
|
+
temperature: t.temperature || 0.7,
|
|
13
|
+
max_tokens: t.maxTokens || 1e3,
|
|
14
|
+
stream: t.stream || !1
|
|
15
|
+
};
|
|
16
|
+
return t.tools && this.capabilities.has("tools") && (s.tools = t.tools), s;
|
|
17
|
+
}
|
|
18
|
+
processMessages(e, t) {
|
|
19
|
+
return t.images && this.capabilities.has("vision") ? this.addImagesToMessages(e, t.images) : e;
|
|
20
|
+
}
|
|
21
|
+
addImagesToMessages(e, t) {
|
|
22
|
+
const s = e[e.length - 1];
|
|
23
|
+
if (s && s.role === "user") {
|
|
24
|
+
const n = [{ type: "text", text: s.content }];
|
|
25
|
+
t.forEach((r) => n.push({ type: "image_url", image_url: { url: typeof r == "string" ? r : r.url } })), s.content = n;
|
|
26
|
+
}
|
|
27
|
+
return e;
|
|
28
|
+
}
|
|
29
|
+
processResponse(e) {
|
|
30
|
+
var t, s, n, r, i;
|
|
31
|
+
return { content: ((n = (s = (t = e.choices) == null ? void 0 : t[0]) == null ? void 0 : s.message) == null ? void 0 : n.content) || "", usage: e.usage || null, finishReason: a((i = (r = e.choices) == null ? void 0 : r[0]) == null ? void 0 : i.finish_reason) };
|
|
32
|
+
}
|
|
33
|
+
parseStreamingLine(e) {
|
|
34
|
+
if (!e.startsWith("data: ")) return null;
|
|
35
|
+
const t = e.slice(6).trim();
|
|
36
|
+
if (t === "[DONE]") return { done: !0 };
|
|
37
|
+
try {
|
|
38
|
+
return JSON.parse(t);
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
extractStreamingContent(e) {
|
|
44
|
+
var s, n, r, i;
|
|
45
|
+
if (e.done) return { done: !0 };
|
|
46
|
+
const t = (n = (s = e.choices) == null ? void 0 : s[0]) == null ? void 0 : n.delta;
|
|
47
|
+
return { content: (t == null ? void 0 : t.content) || "", done: !1, usage: e.usage || null, finishReason: a((i = (r = e.choices) == null ? void 0 : r[0]) == null ? void 0 : i.finish_reason) };
|
|
48
|
+
}
|
|
49
|
+
getApiPath() {
|
|
50
|
+
return "/v1/chat/completions";
|
|
51
|
+
}
|
|
52
|
+
requiresAuth() {
|
|
53
|
+
return !!this.config.apiKey;
|
|
54
|
+
}
|
|
55
|
+
getModelsEndpoint() {
|
|
56
|
+
return `${this.config.baseUrl}/v1/models`;
|
|
57
|
+
}
|
|
58
|
+
parseModelsResponse(e) {
|
|
59
|
+
var t, s, n;
|
|
60
|
+
return ((n = (s = (t = e.data) == null ? void 0 : t.filter((r) => String(r.id).toLowerCase().includes("grok"))) == null ? void 0 : s.map((r) => r.id)) == null ? void 0 : n.sort()) || [];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function a(o) {
|
|
64
|
+
if (!o) return null;
|
|
65
|
+
const e = String(o).toLowerCase();
|
|
66
|
+
return e === "length" || e === "max_tokens" ? "length" : e;
|
|
67
|
+
}
|
|
68
|
+
export {
|
|
69
|
+
u as GrokProvider
|
|
70
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { BaseProvider as l } from "./BaseProvider.js";
|
|
2
|
+
class c extends l {
|
|
3
|
+
async detectCapabilities() {
|
|
4
|
+
}
|
|
5
|
+
prepareRequest(e, t) {
|
|
6
|
+
return {
|
|
7
|
+
model: t.model || this.config.model || "llama2",
|
|
8
|
+
messages: e,
|
|
9
|
+
temperature: t.temperature || 0.7,
|
|
10
|
+
max_tokens: t.maxTokens || 1e3,
|
|
11
|
+
stream: t.stream || !1
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
processResponse(e) {
|
|
15
|
+
var t, r, n, s, a;
|
|
16
|
+
return { content: ((n = (r = (t = e.choices) == null ? void 0 : t[0]) == null ? void 0 : r.message) == null ? void 0 : n.content) || "", usage: e.usage || null, finishReason: o((a = (s = e.choices) == null ? void 0 : s[0]) == null ? void 0 : a.finish_reason) };
|
|
17
|
+
}
|
|
18
|
+
parseStreamingLine(e) {
|
|
19
|
+
if (!e.startsWith("data: ")) return null;
|
|
20
|
+
const t = e.slice(6).trim();
|
|
21
|
+
if (t === "[DONE]") return { done: !0 };
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(t);
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
extractStreamingContent(e) {
|
|
29
|
+
var t, r, n, s, a;
|
|
30
|
+
return e.done ? { done: !0 } : { content: ((n = (r = (t = e.choices) == null ? void 0 : t[0]) == null ? void 0 : r.delta) == null ? void 0 : n.content) || "", thinking: "", done: !1, usage: e.usage || null, finishReason: o((a = (s = e.choices) == null ? void 0 : s[0]) == null ? void 0 : a.finish_reason) };
|
|
31
|
+
}
|
|
32
|
+
getApiPath() {
|
|
33
|
+
return "/v1/chat/completions";
|
|
34
|
+
}
|
|
35
|
+
requiresAuth() {
|
|
36
|
+
return !1;
|
|
37
|
+
}
|
|
38
|
+
getModelsEndpoint() {
|
|
39
|
+
return `${this.config.baseUrl}/v1/models`;
|
|
40
|
+
}
|
|
41
|
+
parseModelsResponse(e) {
|
|
42
|
+
var t;
|
|
43
|
+
return ((t = e.data) == null ? void 0 : t.filter((r) => {
|
|
44
|
+
const n = r.id.toLowerCase();
|
|
45
|
+
return n.includes("mistral") || n.includes("llama") || n.includes("codellama") || n.includes(".gguf") || n.includes(".bin");
|
|
46
|
+
}).map((r) => r.id).sort()) || [];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function o(i) {
|
|
50
|
+
if (!i) return null;
|
|
51
|
+
const e = String(i).toLowerCase();
|
|
52
|
+
return e === "max_tokens" ? "length" : e;
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
c as LlamaServerProvider
|
|
56
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { BaseProvider as r } from "./BaseProvider.js";
|
|
2
|
+
class l extends r {
|
|
3
|
+
async detectCapabilities() {
|
|
4
|
+
if (this.config.model)
|
|
5
|
+
try {
|
|
6
|
+
const t = (await this.fetchModelInfo()).capabilities || [];
|
|
7
|
+
t.includes("thinking") && this.capabilities.add("thinking"), t.includes("vision") && this.capabilities.add("vision"), t.includes("tools") && this.capabilities.add("tools");
|
|
8
|
+
} catch (e) {
|
|
9
|
+
console.warn("Ollama capability detection failed:", e);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
async fetchModelInfo() {
|
|
13
|
+
const e = await fetch(`${this.config.baseUrl}/api/show`, {
|
|
14
|
+
method: "POST",
|
|
15
|
+
headers: { "Content-Type": "application/json" },
|
|
16
|
+
body: JSON.stringify({ name: this.config.model })
|
|
17
|
+
});
|
|
18
|
+
if (!e.ok) throw new Error(`Failed to fetch model info: ${e.status}`);
|
|
19
|
+
return e.json();
|
|
20
|
+
}
|
|
21
|
+
prepareRequest(e, t) {
|
|
22
|
+
const i = t.model || this.config.model;
|
|
23
|
+
if (!i) throw new Error("Model must be specified for Ollama requests");
|
|
24
|
+
const n = {
|
|
25
|
+
model: i,
|
|
26
|
+
messages: this.processMessages(e, t),
|
|
27
|
+
stream: t.stream || !1,
|
|
28
|
+
think: t.enableThinking || !1,
|
|
29
|
+
options: { temperature: t.temperature || 0.7, num_predict: t.maxTokens || 1e3 }
|
|
30
|
+
};
|
|
31
|
+
return t.enableThinking && this.capabilities.has("thinking") && (n.options.enable_thinking = !0), n;
|
|
32
|
+
}
|
|
33
|
+
processMessages(e, t) {
|
|
34
|
+
return t.images && this.capabilities.has("vision") ? this.addImagesToMessages(e, t.images) : e;
|
|
35
|
+
}
|
|
36
|
+
addImagesToMessages(e, t) {
|
|
37
|
+
const i = e[e.length - 1];
|
|
38
|
+
return i && i.role === "user" && (i.images = t.map((n) => typeof n == "string" && n.startsWith("data:") ? n.split(",")[1] : n)), e;
|
|
39
|
+
}
|
|
40
|
+
processResponse(e) {
|
|
41
|
+
var i;
|
|
42
|
+
const t = { content: ((i = e.message) == null ? void 0 : i.content) || "", usage: e.eval_count ? { tokens: e.eval_count } : null, finishReason: a(e.finish_reason) };
|
|
43
|
+
return e.thinking && (t.thinking = e.thinking), t;
|
|
44
|
+
}
|
|
45
|
+
parseStreamingLine(e) {
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(e);
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
extractStreamingContent(e) {
|
|
53
|
+
var t;
|
|
54
|
+
return { content: ((t = e.message) == null ? void 0 : t.content) || "", thinking: e.thinking || "", done: e.done || !1, usage: e.eval_count ? { tokens: e.eval_count } : null, finishReason: a(e.finish_reason) };
|
|
55
|
+
}
|
|
56
|
+
getApiPath() {
|
|
57
|
+
return "/api/chat";
|
|
58
|
+
}
|
|
59
|
+
requiresAuth() {
|
|
60
|
+
return !1;
|
|
61
|
+
}
|
|
62
|
+
getModelsEndpoint() {
|
|
63
|
+
return `${this.config.baseUrl}/api/tags`;
|
|
64
|
+
}
|
|
65
|
+
parseModelsResponse(e) {
|
|
66
|
+
var t;
|
|
67
|
+
return ((t = e.models) == null ? void 0 : t.map((i) => i.name)) || [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function a(s) {
|
|
71
|
+
if (!s) return null;
|
|
72
|
+
const e = String(s).toLowerCase();
|
|
73
|
+
return e === "max_tokens" ? "length" : e;
|
|
74
|
+
}
|
|
75
|
+
export {
|
|
76
|
+
l as OllamaProvider
|
|
77
|
+
};
|