mcard-js 2.1.47 → 2.1.49

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.
Files changed (52) hide show
  1. package/dist/AbstractSqlEngine-DKka6XjT.d.cts +451 -0
  2. package/dist/AbstractSqlEngine-DKka6XjT.d.ts +451 -0
  3. package/dist/CardCollection-TYC67XOH.js +10 -0
  4. package/dist/CardCollection-ZQ3G3Q3A.js +10 -0
  5. package/dist/EventProducer-VFDOM5W2.js +47 -0
  6. package/dist/IndexedDBEngine-5CEFZDOG.js +12 -0
  7. package/dist/IndexedDBEngine-BWXAB46W.js +12 -0
  8. package/dist/LLMRuntime-PH3MOQ2Y.js +17 -0
  9. package/dist/LambdaRuntime-DMEBYJIN.js +19 -0
  10. package/dist/LambdaRuntime-YH74FHIW.js +19 -0
  11. package/dist/Loader-OBPDJNFH.js +12 -0
  12. package/dist/Loader-WZXYG4GE.js +12 -0
  13. package/dist/MCard-RHTWJPHJ.js +8 -0
  14. package/dist/NetworkRuntime-KBQURQ6A.js +1598 -0
  15. package/dist/NetworkRuntime-S4DZCGVN.js +1598 -0
  16. package/dist/OllamaProvider-SPGO5Z5E.js +9 -0
  17. package/dist/chunk-3FFEA2XK.js +149 -0
  18. package/dist/chunk-7AXRV7NS.js +112 -0
  19. package/dist/chunk-AAO4GDBI.js +2360 -0
  20. package/dist/chunk-ASW6AOA7.js +140 -0
  21. package/dist/chunk-BJJZWPIF.js +112 -0
  22. package/dist/chunk-GGQCF7ZK.js +170 -0
  23. package/dist/chunk-HIVVDGE5.js +497 -0
  24. package/dist/chunk-HWBEGVEN.js +364 -0
  25. package/dist/chunk-ISY5LYLF.js +217 -0
  26. package/dist/chunk-KVZYFZJ5.js +427 -0
  27. package/dist/chunk-NGTY4P6A.js +275 -0
  28. package/dist/chunk-OAHWTOEB.js +275 -0
  29. package/dist/chunk-OUW2SUGM.js +368 -0
  30. package/dist/chunk-QKH3N62B.js +2360 -0
  31. package/dist/chunk-QPVEUPMU.js +299 -0
  32. package/dist/chunk-RZENJZGX.js +299 -0
  33. package/dist/chunk-VYDZR4ZD.js +364 -0
  34. package/dist/chunk-XJZOEM5F.js +903 -0
  35. package/dist/chunk-Z7EFXSTO.js +217 -0
  36. package/dist/index.browser.cjs +58 -20
  37. package/dist/index.browser.d.cts +34 -17
  38. package/dist/index.browser.d.ts +34 -17
  39. package/dist/index.browser.js +12 -8
  40. package/dist/index.cjs +644 -167
  41. package/dist/index.d.cts +725 -5
  42. package/dist/index.d.ts +725 -5
  43. package/dist/index.js +536 -95
  44. package/dist/storage/SqliteNodeEngine.cjs +28 -20
  45. package/dist/storage/SqliteNodeEngine.d.cts +1 -1
  46. package/dist/storage/SqliteNodeEngine.d.ts +1 -1
  47. package/dist/storage/SqliteNodeEngine.js +5 -5
  48. package/dist/storage/SqliteWasmEngine.cjs +28 -20
  49. package/dist/storage/SqliteWasmEngine.d.cts +1 -1
  50. package/dist/storage/SqliteWasmEngine.d.ts +1 -1
  51. package/dist/storage/SqliteWasmEngine.js +5 -5
  52. package/package.json +3 -1
@@ -0,0 +1,275 @@
1
+ import {
2
+ createPage
3
+ } from "./chunk-3EIBJPNF.js";
4
+ import {
5
+ init_Handle,
6
+ validateHandle
7
+ } from "./chunk-ADV52544.js";
8
+ import {
9
+ DEFAULT_PAGE_SIZE,
10
+ INDEXEDDB_DEFAULT_DB_NAME,
11
+ INDEXEDDB_DEFAULT_DB_VERSION
12
+ } from "./chunk-J3IDWMDN.js";
13
+ import {
14
+ MCard
15
+ } from "./chunk-GGQCF7ZK.js";
16
+
17
+ // src/storage/engines/IndexedDBEngine.ts
18
+ import { openDB } from "idb";
19
+ init_Handle();
20
+ var IndexedDBEngine = class {
21
+ db = null;
22
+ dbName;
23
+ constructor(dbName = INDEXEDDB_DEFAULT_DB_NAME) {
24
+ this.dbName = dbName;
25
+ }
26
+ /**
27
+ * Initialize the database connection
28
+ */
29
+ async init() {
30
+ this.db = await openDB(this.dbName, INDEXEDDB_DEFAULT_DB_VERSION, {
31
+ upgrade(db) {
32
+ if (!db.objectStoreNames.contains("cards")) {
33
+ db.createObjectStore("cards", { keyPath: "hash" });
34
+ }
35
+ if (!db.objectStoreNames.contains("handles")) {
36
+ const handleStore = db.createObjectStore("handles", { keyPath: "handle" });
37
+ handleStore.createIndex("by-hash", "currentHash");
38
+ }
39
+ if (!db.objectStoreNames.contains("handleHistory")) {
40
+ const historyStore = db.createObjectStore("handleHistory", {
41
+ keyPath: "id",
42
+ autoIncrement: true
43
+ });
44
+ historyStore.createIndex("by-handle", "handle");
45
+ }
46
+ }
47
+ });
48
+ }
49
+ ensureDb() {
50
+ if (!this.db) {
51
+ throw new Error("Database not initialized. Call init() first.");
52
+ }
53
+ return this.db;
54
+ }
55
+ // =========== Card Operations ===========
56
+ async add(card) {
57
+ const db = this.ensureDb();
58
+ await db.put("cards", {
59
+ hash: card.hash,
60
+ content: card.content,
61
+ g_time: card.g_time
62
+ });
63
+ return card.hash;
64
+ }
65
+ async get(hash) {
66
+ const db = this.ensureDb();
67
+ const record = await db.get("cards", hash);
68
+ if (!record) return null;
69
+ return MCard.fromData(record.content, record.hash, record.g_time);
70
+ }
71
+ async delete(hash) {
72
+ const db = this.ensureDb();
73
+ await db.delete("cards", hash);
74
+ }
75
+ async getPage(pageNumber, pageSize = DEFAULT_PAGE_SIZE) {
76
+ const db = this.ensureDb();
77
+ const totalItems = await db.count("cards");
78
+ const allCards = await db.getAll("cards");
79
+ const start = (pageNumber - 1) * pageSize;
80
+ const pageRecords = allCards.slice(start, start + pageSize);
81
+ const items = pageRecords.map((r) => MCard.fromData(r.content, r.hash, r.g_time));
82
+ return createPage(items, totalItems, pageNumber, pageSize);
83
+ }
84
+ async count() {
85
+ const db = this.ensureDb();
86
+ return db.count("cards");
87
+ }
88
+ async searchByHash(hashPrefix) {
89
+ const db = this.ensureDb();
90
+ const start = hashPrefix;
91
+ const end = hashPrefix + "\uFFFF";
92
+ const range = IDBKeyRange.bound(start, end);
93
+ const records = await db.getAll("cards", range);
94
+ return records.map((r) => MCard.fromData(r.content, r.hash, r.g_time));
95
+ }
96
+ async search(query, pageNumber, pageSize = DEFAULT_PAGE_SIZE) {
97
+ const db = this.ensureDb();
98
+ const records = await db.getAll("cards");
99
+ const decoder = new TextDecoder();
100
+ const filtered = records.filter((r) => {
101
+ try {
102
+ const text = decoder.decode(r.content);
103
+ return text.includes(query);
104
+ } catch {
105
+ return false;
106
+ }
107
+ });
108
+ const totalItems = filtered.length;
109
+ const start = (pageNumber - 1) * pageSize;
110
+ const pageItems = filtered.slice(start, start + pageSize).map((r) => MCard.fromData(r.content, r.hash, r.g_time));
111
+ return createPage(pageItems, totalItems, pageNumber, pageSize);
112
+ }
113
+ async getAll() {
114
+ const db = this.ensureDb();
115
+ const records = await db.getAll("cards");
116
+ return records.map((r) => MCard.fromData(r.content, r.hash, r.g_time));
117
+ }
118
+ async clear() {
119
+ const db = this.ensureDb();
120
+ await db.clear("cards");
121
+ await db.clear("handles");
122
+ await db.clear("handleHistory");
123
+ }
124
+ // =========== Handle Operations ===========
125
+ async registerHandle(handle, hash) {
126
+ const db = this.ensureDb();
127
+ const normalized = validateHandle(handle);
128
+ const existing = await db.get("handles", normalized);
129
+ if (existing) {
130
+ throw new Error(`Handle '${handle}' already exists.`);
131
+ }
132
+ const now = (/* @__PURE__ */ new Date()).toISOString();
133
+ await db.put("handles", {
134
+ handle: normalized,
135
+ currentHash: hash,
136
+ createdAt: now,
137
+ updatedAt: now
138
+ });
139
+ }
140
+ async resolveHandle(handle) {
141
+ const db = this.ensureDb();
142
+ const normalized = validateHandle(handle);
143
+ const record = await db.get("handles", normalized);
144
+ return record?.currentHash ?? null;
145
+ }
146
+ async getByHandle(handle) {
147
+ const hash = await this.resolveHandle(handle);
148
+ if (!hash) return null;
149
+ return this.get(hash);
150
+ }
151
+ async updateHandle(handle, newHash) {
152
+ const db = this.ensureDb();
153
+ const normalized = validateHandle(handle);
154
+ const existing = await db.get("handles", normalized);
155
+ if (!existing) {
156
+ throw new Error(`Handle '${handle}' not found.`);
157
+ }
158
+ const previousHash = existing.currentHash;
159
+ const now = (/* @__PURE__ */ new Date()).toISOString();
160
+ await db.add("handleHistory", {
161
+ handle: normalized,
162
+ previousHash,
163
+ changedAt: now
164
+ });
165
+ await db.put("handles", {
166
+ ...existing,
167
+ currentHash: newHash,
168
+ updatedAt: now
169
+ });
170
+ return previousHash;
171
+ }
172
+ async getHandleHistory(handle) {
173
+ const db = this.ensureDb();
174
+ const normalized = validateHandle(handle);
175
+ const records = await db.getAllFromIndex("handleHistory", "by-handle", normalized);
176
+ return records.map((r) => ({ previousHash: r.previousHash, changedAt: r.changedAt })).reverse();
177
+ }
178
+ async pruneHandleHistory(handle, options = {}) {
179
+ const db = this.ensureDb();
180
+ const normalized = validateHandle(handle);
181
+ const records = await db.getAllFromIndex("handleHistory", "by-handle", normalized);
182
+ let toDelete;
183
+ if (options.deleteAll) {
184
+ toDelete = records;
185
+ } else if (options.olderThan) {
186
+ toDelete = records.filter((r) => r.changedAt < options.olderThan);
187
+ } else {
188
+ return 0;
189
+ }
190
+ const tx = db.transaction("handleHistory", "readwrite");
191
+ for (const record of toDelete) {
192
+ await tx.store.delete(record.id);
193
+ }
194
+ await tx.done;
195
+ return toDelete.length;
196
+ }
197
+ // =========== Handle Management Operations ===========
198
+ async getAllHandles() {
199
+ const db = this.ensureDb();
200
+ const records = await db.getAll("handles");
201
+ return records.map((r) => ({ handle: r.handle, hash: r.currentHash }));
202
+ }
203
+ async removeHandle(handle) {
204
+ const db = this.ensureDb();
205
+ const normalized = validateHandle(handle);
206
+ const keysToTry = normalized !== handle.trim() ? [normalized, handle.trim()] : [normalized];
207
+ const tx = db.transaction(["handles", "handleHistory"], "readwrite");
208
+ const handleStore = tx.objectStore("handles");
209
+ const historyStore = tx.objectStore("handleHistory");
210
+ for (const key of keysToTry) {
211
+ await handleStore.delete(key);
212
+ }
213
+ const historyIndex = historyStore.index("by-handle");
214
+ for (const key of keysToTry) {
215
+ let cursor = await historyIndex.openCursor(key);
216
+ while (cursor) {
217
+ await cursor.delete();
218
+ cursor = await cursor.continue();
219
+ }
220
+ }
221
+ await tx.done;
222
+ }
223
+ async renameHandle(oldHandle, newHandle) {
224
+ const db = this.ensureDb();
225
+ const normalizedOld = validateHandle(oldHandle);
226
+ const normalizedNew = validateHandle(newHandle);
227
+ if (normalizedOld === normalizedNew) return;
228
+ const oldEntry = await db.get("handles", normalizedOld);
229
+ if (!oldEntry) throw new Error(`Handle '${oldHandle}' not found.`);
230
+ const newEntry = await db.get("handles", normalizedNew);
231
+ if (newEntry) throw new Error(`Handle '${newHandle}' already exists.`);
232
+ const tx = db.transaction(["handles", "handleHistory"], "readwrite");
233
+ const handleStore = tx.objectStore("handles");
234
+ const historyStore = tx.objectStore("handleHistory");
235
+ const now = (/* @__PURE__ */ new Date()).toISOString();
236
+ await handleStore.put({
237
+ ...oldEntry,
238
+ handle: normalizedNew,
239
+ updatedAt: now
240
+ });
241
+ await handleStore.delete(normalizedOld);
242
+ const historyIndex = historyStore.index("by-handle");
243
+ let cursor = await historyIndex.openCursor(normalizedOld);
244
+ while (cursor) {
245
+ const record = cursor.value;
246
+ record.handle = normalizedNew;
247
+ await cursor.update(record);
248
+ cursor = await cursor.continue();
249
+ }
250
+ await tx.done;
251
+ }
252
+ async deleteHistoryEntry(handle, previousHash) {
253
+ const db = this.ensureDb();
254
+ const normalized = validateHandle(handle);
255
+ const records = await db.getAllFromIndex("handleHistory", "by-handle", normalized);
256
+ const entries = records.sort((a, b) => a.id - b.id);
257
+ const targetIdx = entries.findIndex((e) => e.previousHash === previousHash);
258
+ if (targetIdx === -1) return;
259
+ const target = entries[targetIdx];
260
+ const successor = entries[targetIdx + 1];
261
+ const tx = db.transaction("handleHistory", "readwrite");
262
+ const store = tx.objectStore("handleHistory");
263
+ if (successor && targetIdx > 0) {
264
+ const predecessor = entries[targetIdx - 1];
265
+ successor.previousHash = predecessor.previousHash;
266
+ await store.put(successor);
267
+ }
268
+ await store.delete(target.id);
269
+ await tx.done;
270
+ }
271
+ };
272
+
273
+ export {
274
+ IndexedDBEngine
275
+ };
@@ -0,0 +1,368 @@
1
+ import {
2
+ Either
3
+ } from "./chunk-2KADE3SE.js";
4
+ import {
5
+ LLM_DEFAULT_RETRY_COUNT,
6
+ LLM_DEFAULT_RETRY_DELAY_SECS,
7
+ LLM_DEFAULT_TIMEOUT_SECS
8
+ } from "./chunk-3FFEA2XK.js";
9
+
10
+ // src/ptr/llm/providers/LLMProvider.ts
11
+ var BaseLLMProvider = class {
12
+ async get_status() {
13
+ const available = await this.validate_connection();
14
+ let models = [];
15
+ if (available) {
16
+ const result = await this.list_models();
17
+ if (result.isRight) {
18
+ models = result.right;
19
+ } else {
20
+ models = result.left;
21
+ }
22
+ } else {
23
+ models = "Not connected";
24
+ }
25
+ return {
26
+ provider: this.provider_name,
27
+ available,
28
+ models: Array.isArray(models) ? models : [],
29
+ error: typeof models === "string" ? models : null
30
+ };
31
+ }
32
+ };
33
+
34
+ // src/ptr/llm/Config.ts
35
+ var DEFAULT_PROVIDER = "ollama";
36
+ var LLM_PROVIDERS = {
37
+ "ollama": {
38
+ base_url: "http://localhost:11434",
39
+ api_path: "/api/generate",
40
+ chat_path: "/api/chat",
41
+ models_path: "/api/tags",
42
+ default_model: "gemma3:latest",
43
+ available_models: ["gemma3:latest", "llama3:latest", "qwen3:latest"]
44
+ },
45
+ "webllm": {
46
+ base_url: "",
47
+ // running in-browser
48
+ api_path: "",
49
+ chat_path: "",
50
+ models_path: null,
51
+ default_model: "Llama-3-8B-Instruct-q4f32_1-MLC",
52
+ available_models: ["Llama-3-8B-Instruct-q4f32_1-MLC", "Hermes-2-Pro-Llama-3-8B-q4f16_1-MLC", "Phi-3-Mini-4k-Instruct-q4f16_1-MLC"]
53
+ },
54
+ "mlc-llm": {
55
+ base_url: "http://localhost:8000",
56
+ api_path: "/v1/completions",
57
+ chat_path: "/v1/chat/completions",
58
+ models_path: "/v1/models",
59
+ default_model: "Llama-3-8B-Instruct-q4f16_1-MLC",
60
+ available_models: []
61
+ },
62
+ "lmstudio": {
63
+ base_url: "http://localhost:1234",
64
+ api_path: "/v1/completions",
65
+ chat_path: "/v1/chat/completions",
66
+ models_path: "/v1/models",
67
+ default_model: "local-model",
68
+ available_models: []
69
+ },
70
+ "openai": {
71
+ base_url: "https://api.openai.com",
72
+ api_path: "/v1/completions",
73
+ chat_path: "/v1/chat/completions",
74
+ models_path: "/v1/models",
75
+ default_model: "gpt-4",
76
+ available_models: ["gpt-4", "gpt-4-turbo", "gpt-3.5-turbo"]
77
+ },
78
+ "anthropic": {
79
+ base_url: "https://api.anthropic.com",
80
+ api_path: "/v1/messages",
81
+ chat_path: "/v1/messages",
82
+ models_path: null,
83
+ default_model: "claude-3-sonnet-20240229",
84
+ available_models: ["claude-3-opus", "claude-3-sonnet", "claude-3-haiku"]
85
+ }
86
+ };
87
+ var DEFAULT_LLM_CONFIG = {
88
+ temperature: 0.7,
89
+ max_tokens: 2048,
90
+ top_p: 1,
91
+ top_k: 40,
92
+ timeout: LLM_DEFAULT_TIMEOUT_SECS,
93
+ stream: false,
94
+ response_format: "text",
95
+ retry_count: LLM_DEFAULT_RETRY_COUNT,
96
+ retry_delay: LLM_DEFAULT_RETRY_DELAY_SECS
97
+ };
98
+ var RESPONSE_FORMATS = ["text", "json", "structured", "markdown"];
99
+ var LLMConfig = class _LLMConfig {
100
+ provider;
101
+ model;
102
+ endpoint_url;
103
+ api_key;
104
+ system_prompt;
105
+ assistant_instruction;
106
+ temperature;
107
+ max_tokens;
108
+ top_p;
109
+ top_k;
110
+ frequency_penalty;
111
+ presence_penalty;
112
+ stop_sequences;
113
+ response_format;
114
+ json_schema;
115
+ timeout;
116
+ retry_count;
117
+ retry_delay;
118
+ stream;
119
+ constructor(data = {}) {
120
+ this.provider = data.provider || DEFAULT_PROVIDER;
121
+ this.model = data.model || null;
122
+ this.endpoint_url = data.endpoint_url || null;
123
+ this.api_key = data.api_key || null;
124
+ this.system_prompt = data.system_prompt || "";
125
+ this.assistant_instruction = data.assistant_instruction || "";
126
+ this.temperature = data.temperature ?? DEFAULT_LLM_CONFIG.temperature;
127
+ this.max_tokens = data.max_tokens ?? DEFAULT_LLM_CONFIG.max_tokens;
128
+ this.top_p = data.top_p ?? DEFAULT_LLM_CONFIG.top_p;
129
+ this.top_k = data.top_k ?? DEFAULT_LLM_CONFIG.top_k;
130
+ this.frequency_penalty = data.frequency_penalty || 0;
131
+ this.presence_penalty = data.presence_penalty || 0;
132
+ this.stop_sequences = data.stop_sequences || [];
133
+ this.response_format = data.response_format || DEFAULT_LLM_CONFIG.response_format;
134
+ this.json_schema = data.json_schema || null;
135
+ this.timeout = data.timeout ?? DEFAULT_LLM_CONFIG.timeout;
136
+ this.retry_count = data.retry_count ?? DEFAULT_LLM_CONFIG.retry_count;
137
+ this.retry_delay = data.retry_delay ?? DEFAULT_LLM_CONFIG.retry_delay;
138
+ this.stream = data.stream ?? DEFAULT_LLM_CONFIG.stream;
139
+ this.validate();
140
+ }
141
+ validate() {
142
+ if (!LLM_PROVIDERS[this.provider]) {
143
+ throw new Error(`Unknown provider: ${this.provider}. Available: ${Object.keys(LLM_PROVIDERS).join(", ")}`);
144
+ }
145
+ if (!RESPONSE_FORMATS.includes(this.response_format)) {
146
+ throw new Error(`Unknown response format: ${this.response_format}. Available: ${RESPONSE_FORMATS.join(", ")}`);
147
+ }
148
+ }
149
+ get effective_model() {
150
+ return this.model || LLM_PROVIDERS[this.provider].default_model;
151
+ }
152
+ get effective_base_url() {
153
+ if (this.endpoint_url) {
154
+ return this.endpoint_url.replace(/\/$/, "");
155
+ }
156
+ return LLM_PROVIDERS[this.provider].base_url;
157
+ }
158
+ to_provider_params() {
159
+ const params = {
160
+ model: this.effective_model,
161
+ temperature: this.temperature
162
+ };
163
+ if (this.provider === "ollama") {
164
+ params.options = {
165
+ num_predict: this.max_tokens,
166
+ top_p: this.top_p,
167
+ top_k: this.top_k,
168
+ temperature: this.temperature
169
+ };
170
+ if (this.stop_sequences.length > 0) {
171
+ params.options.stop = this.stop_sequences;
172
+ }
173
+ } else {
174
+ params.max_tokens = this.max_tokens;
175
+ params.top_p = this.top_p;
176
+ if (this.stop_sequences.length > 0) {
177
+ params.stop = this.stop_sequences;
178
+ }
179
+ if (this.frequency_penalty) params.frequency_penalty = this.frequency_penalty;
180
+ if (this.presence_penalty) params.presence_penalty = this.presence_penalty;
181
+ }
182
+ return params;
183
+ }
184
+ static from_concrete(concrete, context = {}) {
185
+ const configData = { ...concrete.llm_config || {} };
186
+ ["provider", "model", "system_prompt", "temperature", "max_tokens"].forEach((key) => {
187
+ if (key in concrete) {
188
+ configData[key] = concrete[key];
189
+ }
190
+ });
191
+ const contextKeys = [
192
+ "provider",
193
+ "model",
194
+ "endpoint_url",
195
+ "api_key",
196
+ "system_prompt",
197
+ "assistant_instruction",
198
+ "temperature",
199
+ "max_tokens",
200
+ "top_p",
201
+ "top_k",
202
+ "response_format",
203
+ "timeout"
204
+ ];
205
+ contextKeys.forEach((key) => {
206
+ if (key in context) {
207
+ configData[key] = context[key];
208
+ }
209
+ });
210
+ return new _LLMConfig(configData);
211
+ }
212
+ };
213
+
214
+ // src/ptr/llm/providers/OllamaProvider.ts
215
+ import * as http from "http";
216
+ import * as https from "https";
217
+ var OllamaProvider = class extends BaseLLMProvider {
218
+ provider_name = "ollama";
219
+ base_url;
220
+ timeout;
221
+ config;
222
+ constructor(base_url = null, timeout = LLM_DEFAULT_TIMEOUT_SECS) {
223
+ super();
224
+ this.config = LLM_PROVIDERS["ollama"];
225
+ this.base_url = (base_url || this.config.base_url).replace(/\/$/, "");
226
+ this.timeout = timeout * 1e3;
227
+ }
228
+ async _make_request(endpoint, data = null, method = "POST") {
229
+ const urlStr = `${this.base_url}${endpoint}`;
230
+ const url = new URL(urlStr);
231
+ const isHttps = url.protocol === "https:";
232
+ const client = isHttps ? https : http;
233
+ const options = {
234
+ method,
235
+ headers: {
236
+ "Content-Type": "application/json"
237
+ },
238
+ timeout: this.timeout
239
+ };
240
+ return new Promise((resolve) => {
241
+ let payload;
242
+ if (data) {
243
+ payload = JSON.stringify(data);
244
+ options.headers["Content-Length"] = Buffer.byteLength(payload);
245
+ }
246
+ const req = client.request(url, options, (res) => {
247
+ let body = "";
248
+ res.on("data", (chunk) => {
249
+ body += chunk;
250
+ });
251
+ res.on("end", () => {
252
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
253
+ try {
254
+ if (body.includes("\n") && !body.trim().startsWith("{")) {
255
+ resolve(Either.right(JSON.parse(body)));
256
+ } else {
257
+ resolve(Either.right(JSON.parse(body)));
258
+ }
259
+ } catch (e) {
260
+ const lines = body.trim().split("\n").filter((l) => l);
261
+ if (lines.length > 0) {
262
+ try {
263
+ resolve(Either.right(JSON.parse(lines[lines.length - 1])));
264
+ } catch (parseErr) {
265
+ resolve(Either.left(`Ollama response parse error: ${parseErr}`));
266
+ }
267
+ } else {
268
+ resolve(Either.left(`Ollama response parse error: ${e}`));
269
+ }
270
+ }
271
+ } else {
272
+ resolve(Either.left(`Ollama HTTP error ${res.statusCode}: ${body}`));
273
+ }
274
+ });
275
+ });
276
+ req.on("error", (e) => {
277
+ resolve(Either.left(`Ollama connection error: ${e.message}`));
278
+ });
279
+ req.on("timeout", () => {
280
+ req.destroy();
281
+ resolve(Either.left(`Ollama request timed out after ${this.timeout}ms`));
282
+ });
283
+ if (payload) {
284
+ req.write(payload);
285
+ }
286
+ req.end();
287
+ });
288
+ }
289
+ async complete(prompt, params, images) {
290
+ const data = {
291
+ model: typeof params.model === "string" ? params.model : this.config.default_model,
292
+ prompt,
293
+ stream: false
294
+ };
295
+ if (images && images.length > 0) {
296
+ data.images = images;
297
+ }
298
+ if (params.options) {
299
+ data.options = params.options;
300
+ }
301
+ const result = await this._make_request(this.config.api_path, data);
302
+ if (result.isLeft) {
303
+ return Either.left(result.left);
304
+ }
305
+ const response = result.right;
306
+ if (response.response !== void 0) {
307
+ return Either.right(response.response);
308
+ } else if (response.error) {
309
+ return Either.left(`Ollama error: ${response.error}`);
310
+ } else {
311
+ return Either.left(`Unexpected Ollama response format: ${JSON.stringify(response)}`);
312
+ }
313
+ }
314
+ async chat(messages, params) {
315
+ const data = {
316
+ model: typeof params.model === "string" ? params.model : this.config.default_model,
317
+ messages,
318
+ stream: false
319
+ };
320
+ if (params.options) {
321
+ data.options = params.options;
322
+ }
323
+ const result = await this._make_request(this.config.chat_path, data);
324
+ if (result.isLeft) {
325
+ return Either.left(result.left);
326
+ }
327
+ const response = result.right;
328
+ if (response.message) {
329
+ return Either.right({
330
+ content: response.message.content || "",
331
+ role: response.message.role || "assistant",
332
+ model: response.model || data.model,
333
+ done: response.done ?? true,
334
+ total_duration: response.total_duration,
335
+ eval_count: response.eval_count
336
+ });
337
+ } else if (response.error) {
338
+ return Either.left(`Ollama error: ${response.error}`);
339
+ } else {
340
+ return Either.left(`Unexpected Ollama chat response format: ${JSON.stringify(response)}`);
341
+ }
342
+ }
343
+ async validate_connection() {
344
+ const result = await this._make_request(this.config.models_path, null, "GET");
345
+ return result.isRight;
346
+ }
347
+ async list_models() {
348
+ const result = await this._make_request(this.config.models_path, null, "GET");
349
+ if (result.isLeft) {
350
+ return Either.left(result.left);
351
+ }
352
+ const response = result.right;
353
+ if (response.models) {
354
+ const models = response.models.map((m) => m.name || m.model || "unknown");
355
+ return Either.right(models);
356
+ } else {
357
+ return Either.left(`Unexpected models response: ${JSON.stringify(response)}`);
358
+ }
359
+ }
360
+ };
361
+
362
+ export {
363
+ DEFAULT_PROVIDER,
364
+ LLM_PROVIDERS,
365
+ LLMConfig,
366
+ BaseLLMProvider,
367
+ OllamaProvider
368
+ };