algochat-ai 1.0.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/LICENSE +21 -0
- package/README.md +698 -0
- package/examples/advanced.js +71 -0
- package/examples/basic.js +35 -0
- package/examples/multimodal.js +36 -0
- package/examples/streaming.js +26 -0
- package/examples/whatsapp-baileys.js +190 -0
- package/package.json +41 -0
- package/src/client.js +380 -0
- package/src/index.d.ts +144 -0
- package/src/index.js +254 -0
- package/src/models.js +87 -0
package/src/client.js
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AlgoChatClient — core HTTP client for algochat.app
|
|
5
|
+
*
|
|
6
|
+
* Handles:
|
|
7
|
+
* 1. GET /api/csrf → csrf_token cookie
|
|
8
|
+
* 2. POST /api/session → zola_sid (anonymous userId)
|
|
9
|
+
* 3. POST /api/create-chat → chatId
|
|
10
|
+
* 4. POST /api/files → (optional) image upload
|
|
11
|
+
* 5. POST /api/chat → SSE stream ← the actual AI response
|
|
12
|
+
*
|
|
13
|
+
* Sessions are cached for 25 minutes and refreshed automatically on 401/403.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const axios = require('axios');
|
|
17
|
+
const FormData = require('form-data');
|
|
18
|
+
const { v4: uuidv4 } = require('uuid');
|
|
19
|
+
|
|
20
|
+
const ALGOCHAT_BASE = 'https://algochat.app';
|
|
21
|
+
const SESSION_TTL_MS = 25 * 60 * 1000; // 25 minutes
|
|
22
|
+
|
|
23
|
+
const UA =
|
|
24
|
+
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36';
|
|
25
|
+
|
|
26
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
function parseCookies(setCookieHeaders = []) {
|
|
29
|
+
const cookies = {};
|
|
30
|
+
for (const cookie of setCookieHeaders) {
|
|
31
|
+
const [nameValue] = cookie.split(';');
|
|
32
|
+
const idx = nameValue.indexOf('=');
|
|
33
|
+
if (idx === -1) continue;
|
|
34
|
+
cookies[nameValue.slice(0, idx).trim()] = nameValue.slice(idx + 1).trim();
|
|
35
|
+
}
|
|
36
|
+
return cookies;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function buildCookieHeader(cookies) {
|
|
40
|
+
return Object.entries(cookies)
|
|
41
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
42
|
+
.join('; ');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function randomId(length = 16) {
|
|
46
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
47
|
+
return Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join('');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function buildDefaultSystemPrompt() {
|
|
51
|
+
const date = new Date().toLocaleDateString('en-US', {
|
|
52
|
+
month: 'short',
|
|
53
|
+
day: 'numeric',
|
|
54
|
+
year: 'numeric',
|
|
55
|
+
});
|
|
56
|
+
return `Date: ${date}\n\nYou are a helpful AI assistant. Respond clearly and concisely. Use markdown formatting when appropriate.`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ─── Session management ───────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
class AlgoChatClient {
|
|
62
|
+
constructor(options = {}) {
|
|
63
|
+
this._sessionCache = null;
|
|
64
|
+
this._sessionFetchedAt = 0;
|
|
65
|
+
this._debug = options.debug === true;
|
|
66
|
+
this._timeout = options.timeout || 90000;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
_log(...args) {
|
|
70
|
+
if (this._debug) console.log('[AlgoChat]', ...args);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
_warn(...args) {
|
|
74
|
+
if (this._debug) console.warn('[AlgoChat]', ...args);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async _fetchSession() {
|
|
78
|
+
this._log('Initializing session...');
|
|
79
|
+
const cookies = {};
|
|
80
|
+
|
|
81
|
+
// Step 1: CSRF token
|
|
82
|
+
const csrfRes = await axios.get(`${ALGOCHAT_BASE}/api/csrf`, {
|
|
83
|
+
headers: { 'User-Agent': UA, Accept: 'application/json, */*', Referer: ALGOCHAT_BASE },
|
|
84
|
+
});
|
|
85
|
+
Object.assign(cookies, parseCookies(csrfRes.headers['set-cookie']));
|
|
86
|
+
this._log('Got csrf_token:', !!cookies['csrf_token']);
|
|
87
|
+
|
|
88
|
+
// Step 2: Anonymous session (zola_sid)
|
|
89
|
+
const sessionRes = await axios.post(
|
|
90
|
+
`${ALGOCHAT_BASE}/api/session`,
|
|
91
|
+
{},
|
|
92
|
+
{
|
|
93
|
+
headers: {
|
|
94
|
+
'Content-Type': 'application/json',
|
|
95
|
+
'User-Agent': UA,
|
|
96
|
+
Cookie: buildCookieHeader(cookies),
|
|
97
|
+
Origin: ALGOCHAT_BASE,
|
|
98
|
+
Referer: ALGOCHAT_BASE,
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
Object.assign(cookies, parseCookies(sessionRes.headers['set-cookie']));
|
|
103
|
+
this._log('Got zola_sid:', cookies['zola_sid'] ? 'yes' : 'no');
|
|
104
|
+
|
|
105
|
+
return cookies;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async _getSession() {
|
|
109
|
+
const now = Date.now();
|
|
110
|
+
if (!this._sessionCache || now - this._sessionFetchedAt > SESSION_TTL_MS) {
|
|
111
|
+
this._sessionCache = await this._fetchSession();
|
|
112
|
+
this._sessionFetchedAt = now;
|
|
113
|
+
}
|
|
114
|
+
return this._sessionCache;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
_invalidateSession() {
|
|
118
|
+
this._sessionCache = null;
|
|
119
|
+
this._sessionFetchedAt = 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async _createChat(cookies, model) {
|
|
123
|
+
const res = await axios.post(
|
|
124
|
+
`${ALGOCHAT_BASE}/api/create-chat`,
|
|
125
|
+
{ title: 'New Chat', model: model || 'gemini-3-flash-preview' },
|
|
126
|
+
{
|
|
127
|
+
headers: {
|
|
128
|
+
'Content-Type': 'application/json',
|
|
129
|
+
'User-Agent': UA,
|
|
130
|
+
Cookie: buildCookieHeader(cookies),
|
|
131
|
+
Origin: ALGOCHAT_BASE,
|
|
132
|
+
Referer: ALGOCHAT_BASE,
|
|
133
|
+
},
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
const chatId = res.data?.chat?.id || res.data?.id;
|
|
137
|
+
if (!chatId) throw new Error('create-chat did not return a chatId');
|
|
138
|
+
this._log('Created chatId:', chatId);
|
|
139
|
+
return chatId;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Upload an image to AlgoChat /api/files.
|
|
144
|
+
* @param {string} imageSource - base64 data URI or https URL
|
|
145
|
+
* @param {object} cookies - session cookies
|
|
146
|
+
* @param {string} [filename]
|
|
147
|
+
* @returns {Promise<{url: string, filename: string, mediaType: string}>}
|
|
148
|
+
*/
|
|
149
|
+
async uploadImage(imageSource, cookies, filename = 'image.jpg') {
|
|
150
|
+
let imageBuffer;
|
|
151
|
+
let mediaType = 'image/jpeg';
|
|
152
|
+
|
|
153
|
+
if (imageSource.startsWith('data:')) {
|
|
154
|
+
const match = imageSource.match(/^data:([^;]+);base64,(.+)$/);
|
|
155
|
+
if (!match) throw new Error('Invalid base64 data URI format');
|
|
156
|
+
mediaType = match[1];
|
|
157
|
+
imageBuffer = Buffer.from(match[2], 'base64');
|
|
158
|
+
const ext = mediaType.split('/')[1]?.replace('jpeg', 'jpg') || 'jpg';
|
|
159
|
+
if (!filename || filename === 'image.jpg') filename = `image.${ext}`;
|
|
160
|
+
} else if (imageSource.startsWith('http://') || imageSource.startsWith('https://')) {
|
|
161
|
+
const imgRes = await axios.get(imageSource, { responseType: 'arraybuffer', timeout: 30000 });
|
|
162
|
+
imageBuffer = Buffer.from(imgRes.data);
|
|
163
|
+
mediaType = imgRes.headers['content-type']?.split(';')[0] || 'image/jpeg';
|
|
164
|
+
const urlFilename = imageSource.split('/').pop()?.split('?')[0];
|
|
165
|
+
if (urlFilename && urlFilename.includes('.')) filename = urlFilename;
|
|
166
|
+
} else {
|
|
167
|
+
throw new Error('Image source must be a base64 data URI or an https URL');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const form = new FormData();
|
|
171
|
+
form.append('file', imageBuffer, { filename, contentType: mediaType });
|
|
172
|
+
|
|
173
|
+
this._log(`Uploading image: ${filename} (${mediaType}, ${imageBuffer.length} bytes)`);
|
|
174
|
+
|
|
175
|
+
const res = await axios.post(`${ALGOCHAT_BASE}/api/files`, form, {
|
|
176
|
+
headers: {
|
|
177
|
+
...form.getHeaders(),
|
|
178
|
+
'User-Agent': UA,
|
|
179
|
+
Cookie: buildCookieHeader(cookies),
|
|
180
|
+
Origin: ALGOCHAT_BASE,
|
|
181
|
+
Referer: ALGOCHAT_BASE,
|
|
182
|
+
},
|
|
183
|
+
timeout: 60000,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const fileId = res.data?.id || res.data?.fileId || res.data?.file?.id;
|
|
187
|
+
if (!fileId) throw new Error(`Image upload failed – unexpected response: ${JSON.stringify(res.data)}`);
|
|
188
|
+
|
|
189
|
+
const fileUrl = `/api/files/${fileId}`;
|
|
190
|
+
this._log(`Image uploaded → ${fileUrl}`);
|
|
191
|
+
return { url: fileUrl, filename, mediaType };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async _contentToParts(content, cookies) {
|
|
195
|
+
if (typeof content === 'string') return [{ type: 'text', text: content }];
|
|
196
|
+
if (!Array.isArray(content)) return [{ type: 'text', text: String(content) }];
|
|
197
|
+
|
|
198
|
+
const parts = [];
|
|
199
|
+
for (const item of content) {
|
|
200
|
+
if (item.type === 'text') {
|
|
201
|
+
parts.push({ type: 'text', text: item.text || '' });
|
|
202
|
+
} else if (item.type === 'image_url') {
|
|
203
|
+
const imageUrl = item.image_url?.url || item.image_url;
|
|
204
|
+
if (!imageUrl) continue;
|
|
205
|
+
|
|
206
|
+
// Strategy 1: Try /api/files upload
|
|
207
|
+
try {
|
|
208
|
+
const uploaded = await this.uploadImage(imageUrl, cookies);
|
|
209
|
+
parts.push({ type: 'file', url: uploaded.url, filename: uploaded.filename, mediaType: uploaded.mediaType });
|
|
210
|
+
continue;
|
|
211
|
+
} catch (uploadErr) {
|
|
212
|
+
const status = uploadErr.response?.status;
|
|
213
|
+
const isAuthErr = status === 401 || status === 403;
|
|
214
|
+
if (!isAuthErr) {
|
|
215
|
+
this._warn('Image upload failed:', uploadErr.message);
|
|
216
|
+
parts.push({ type: 'text', text: '[Image could not be processed]' });
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
this._warn('/api/files upload denied. Using direct URL fallback.');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Strategy 2: Pass URL/base64 directly
|
|
223
|
+
if (imageUrl.startsWith('data:')) {
|
|
224
|
+
const match = imageUrl.match(/^data:([^;]+);base64,(.+)$/);
|
|
225
|
+
if (match) {
|
|
226
|
+
parts.push({
|
|
227
|
+
type: 'file',
|
|
228
|
+
url: imageUrl,
|
|
229
|
+
mediaType: match[1],
|
|
230
|
+
filename: `image.${match[1].split('/')[1]?.replace('jpeg', 'jpg') || 'jpg'}`,
|
|
231
|
+
});
|
|
232
|
+
} else {
|
|
233
|
+
parts.push({ type: 'text', text: '[Invalid base64 image]' });
|
|
234
|
+
}
|
|
235
|
+
} else {
|
|
236
|
+
const urlFilename = imageUrl.split('/').pop()?.split('?')[0] || 'image.jpg';
|
|
237
|
+
const guessedMediaType = urlFilename.endsWith('.png') ? 'image/png'
|
|
238
|
+
: urlFilename.endsWith('.webp') ? 'image/webp'
|
|
239
|
+
: urlFilename.endsWith('.gif') ? 'image/gif'
|
|
240
|
+
: 'image/jpeg';
|
|
241
|
+
parts.push({ type: 'file', url: imageUrl, filename: urlFilename, mediaType: guessedMediaType });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return parts.length > 0 ? parts : [{ type: 'text', text: '' }];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async _convertMessages(messages, cookies) {
|
|
249
|
+
const results = [];
|
|
250
|
+
for (const msg of messages) {
|
|
251
|
+
const parts = await this._contentToParts(msg.content, cookies);
|
|
252
|
+
results.push({
|
|
253
|
+
id: randomId(8),
|
|
254
|
+
role: msg.role === 'assistant' ? 'assistant' : 'user',
|
|
255
|
+
parts,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return results;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Create a chat and return the raw SSE stream.
|
|
263
|
+
*
|
|
264
|
+
* @param {object} params
|
|
265
|
+
* @param {string} [params.model]
|
|
266
|
+
* @param {Array} params.messages - Array of {role, content} objects
|
|
267
|
+
* @param {string} [params.systemPrompt]
|
|
268
|
+
* @returns {Promise<{stream: import('stream').Readable, chatId: string}>}
|
|
269
|
+
*/
|
|
270
|
+
async createChatStream({ model, messages, systemPrompt }) {
|
|
271
|
+
const resolvedModel = model || 'gemini-3-flash-preview';
|
|
272
|
+
let session = await this._getSession();
|
|
273
|
+
|
|
274
|
+
let chatId;
|
|
275
|
+
try {
|
|
276
|
+
chatId = await this._createChat(session, resolvedModel);
|
|
277
|
+
} catch (err) {
|
|
278
|
+
if (err.response?.status === 401 || err.response?.status === 403) {
|
|
279
|
+
this._invalidateSession();
|
|
280
|
+
session = await this._getSession();
|
|
281
|
+
chatId = await this._createChat(session, resolvedModel);
|
|
282
|
+
} else {
|
|
283
|
+
throw err;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const convertedMessages = await this._convertMessages(messages, session);
|
|
288
|
+
|
|
289
|
+
const requestBody = {
|
|
290
|
+
chatId,
|
|
291
|
+
userId: session['zola_sid'],
|
|
292
|
+
model: resolvedModel,
|
|
293
|
+
isAuthenticated: false,
|
|
294
|
+
systemPrompt: systemPrompt || buildDefaultSystemPrompt(),
|
|
295
|
+
enableSearch: false,
|
|
296
|
+
id: randomId(16),
|
|
297
|
+
messages: convertedMessages,
|
|
298
|
+
trigger: 'submit-message',
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const headers = {
|
|
302
|
+
'Content-Type': 'application/json',
|
|
303
|
+
'User-Agent': UA,
|
|
304
|
+
Cookie: buildCookieHeader(session),
|
|
305
|
+
Origin: ALGOCHAT_BASE,
|
|
306
|
+
Referer: `${ALGOCHAT_BASE}/c/${chatId}`,
|
|
307
|
+
'x-vercel-ai-ui-message-stream': 'v1',
|
|
308
|
+
Accept: 'text/event-stream',
|
|
309
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
310
|
+
'Cache-Control': 'no-cache',
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
this._log(`POST /api/chat | model=${resolvedModel} | chatId=${chatId}`);
|
|
314
|
+
|
|
315
|
+
let response;
|
|
316
|
+
try {
|
|
317
|
+
response = await axios.post(`${ALGOCHAT_BASE}/api/chat`, requestBody, {
|
|
318
|
+
headers,
|
|
319
|
+
responseType: 'stream',
|
|
320
|
+
timeout: this._timeout,
|
|
321
|
+
});
|
|
322
|
+
} catch (err) {
|
|
323
|
+
const status = err.response?.status;
|
|
324
|
+
if (status === 401 || status === 403) {
|
|
325
|
+
this._invalidateSession();
|
|
326
|
+
session = await this._getSession();
|
|
327
|
+
chatId = await this._createChat(session, resolvedModel);
|
|
328
|
+
requestBody.chatId = chatId;
|
|
329
|
+
requestBody.userId = session['zola_sid'];
|
|
330
|
+
headers.Cookie = buildCookieHeader(session);
|
|
331
|
+
headers.Referer = `${ALGOCHAT_BASE}/c/${chatId}`;
|
|
332
|
+
response = await axios.post(`${ALGOCHAT_BASE}/api/chat`, requestBody, {
|
|
333
|
+
headers,
|
|
334
|
+
responseType: 'stream',
|
|
335
|
+
timeout: this._timeout,
|
|
336
|
+
});
|
|
337
|
+
} else {
|
|
338
|
+
throw err;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return { stream: response.data, chatId };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Collect the full SSE stream into a plain text string.
|
|
347
|
+
* @param {import('stream').Readable} stream
|
|
348
|
+
* @returns {Promise<string>}
|
|
349
|
+
*/
|
|
350
|
+
async streamToText(stream) {
|
|
351
|
+
return new Promise((resolve, reject) => {
|
|
352
|
+
let fullText = '';
|
|
353
|
+
let buffer = '';
|
|
354
|
+
|
|
355
|
+
stream.on('data', (chunk) => {
|
|
356
|
+
buffer += chunk.toString();
|
|
357
|
+
const lines = buffer.split('\n');
|
|
358
|
+
buffer = lines.pop();
|
|
359
|
+
|
|
360
|
+
for (const line of lines) {
|
|
361
|
+
const trimmed = line.trim();
|
|
362
|
+
if (!trimmed.startsWith('data:')) continue;
|
|
363
|
+
const jsonStr = trimmed.slice(5).trim();
|
|
364
|
+
if (!jsonStr || jsonStr === '[DONE]') continue;
|
|
365
|
+
try {
|
|
366
|
+
const parsed = JSON.parse(jsonStr);
|
|
367
|
+
if (parsed.type === 'text-delta' && parsed.delta) fullText += parsed.delta;
|
|
368
|
+
} catch {
|
|
369
|
+
// skip malformed chunks
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
stream.on('end', () => resolve(fullText));
|
|
375
|
+
stream.on('error', reject);
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
module.exports = AlgoChatClient;
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Type definitions for algochat-ai
|
|
2
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
|
|
4
|
+
export interface ChatOptions {
|
|
5
|
+
/** AlgoChat model ID or OpenAI alias. Default: 'gemini-3-flash-preview' */
|
|
6
|
+
model?: string;
|
|
7
|
+
/** Override the system prompt. */
|
|
8
|
+
systemPrompt?: string;
|
|
9
|
+
/** Enable verbose debug logging. Default: false */
|
|
10
|
+
debug?: boolean;
|
|
11
|
+
/** Request timeout in milliseconds. Default: 90000 */
|
|
12
|
+
timeout?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface Message {
|
|
16
|
+
role: 'user' | 'assistant' | 'system';
|
|
17
|
+
content: string | ContentPart[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ContentPart {
|
|
21
|
+
type: 'text' | 'image_url';
|
|
22
|
+
text?: string;
|
|
23
|
+
image_url?: { url: string };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ChatCompletion {
|
|
27
|
+
id: string;
|
|
28
|
+
object: 'chat.completion';
|
|
29
|
+
created: number;
|
|
30
|
+
model: string;
|
|
31
|
+
choices: Array<{
|
|
32
|
+
index: number;
|
|
33
|
+
message: { role: string; content: string };
|
|
34
|
+
finish_reason: string;
|
|
35
|
+
logprobs: null;
|
|
36
|
+
}>;
|
|
37
|
+
usage: {
|
|
38
|
+
prompt_tokens: number;
|
|
39
|
+
completion_tokens: number;
|
|
40
|
+
total_tokens: number;
|
|
41
|
+
};
|
|
42
|
+
system_fingerprint: null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ModelInfo {
|
|
46
|
+
id: string;
|
|
47
|
+
object: 'model';
|
|
48
|
+
created: number;
|
|
49
|
+
owned_by: string;
|
|
50
|
+
permission: any[];
|
|
51
|
+
root: string;
|
|
52
|
+
parent: null;
|
|
53
|
+
requiresAuth: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface UploadedFile {
|
|
57
|
+
url: string;
|
|
58
|
+
filename: string;
|
|
59
|
+
mediaType: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface AlgoChatClientOptions {
|
|
63
|
+
/** Enable verbose debug logging. Default: false */
|
|
64
|
+
debug?: boolean;
|
|
65
|
+
/** Request timeout in milliseconds. Default: 90000 */
|
|
66
|
+
timeout?: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface CreateChatStreamParams {
|
|
70
|
+
model?: string;
|
|
71
|
+
messages: Message[];
|
|
72
|
+
systemPrompt?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface CreateChatStreamResult {
|
|
76
|
+
stream: NodeJS.ReadableStream;
|
|
77
|
+
chatId: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export declare class AlgoChatClient {
|
|
81
|
+
constructor(options?: AlgoChatClientOptions);
|
|
82
|
+
|
|
83
|
+
createChatStream(params: CreateChatStreamParams): Promise<CreateChatStreamResult>;
|
|
84
|
+
streamToText(stream: NodeJS.ReadableStream): Promise<string>;
|
|
85
|
+
uploadImage(imageSource: string, cookies: Record<string, string>, filename?: string): Promise<UploadedFile>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Send a message and get the full AI response as a string.
|
|
90
|
+
*
|
|
91
|
+
* @param input - A string message or an OpenAI-style messages array
|
|
92
|
+
* @param options - Optional configuration
|
|
93
|
+
*/
|
|
94
|
+
export declare function chat(input: string | Message[], options?: ChatOptions): Promise<string>;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Stream the AI response chunk by chunk.
|
|
98
|
+
* Calls onChunk(delta) for every piece of text received.
|
|
99
|
+
* Returns the full accumulated response when the stream ends.
|
|
100
|
+
*
|
|
101
|
+
* @param input - A string message or an OpenAI-style messages array
|
|
102
|
+
* @param onChunk - Callback invoked with each text delta
|
|
103
|
+
* @param options - Optional configuration
|
|
104
|
+
*/
|
|
105
|
+
export declare function chatStream(
|
|
106
|
+
input: string | Message[],
|
|
107
|
+
onChunk: (chunk: string) => void,
|
|
108
|
+
options?: ChatOptions
|
|
109
|
+
): Promise<string>;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Send a message together with an image (multimodal).
|
|
113
|
+
*
|
|
114
|
+
* @param text - The text question about the image
|
|
115
|
+
* @param imageUrl - An https:// URL or a base64 data URI (data:image/...)
|
|
116
|
+
* @param options - Optional configuration
|
|
117
|
+
*/
|
|
118
|
+
export declare function chatWithImage(text: string, imageUrl: string, options?: ChatOptions): Promise<string>;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get a full OpenAI-compatible chat completion object (non-streaming).
|
|
122
|
+
*
|
|
123
|
+
* @param messages - OpenAI-style messages array
|
|
124
|
+
* @param options - Optional configuration
|
|
125
|
+
*/
|
|
126
|
+
export declare function createCompletion(messages: Message[], options?: ChatOptions): Promise<ChatCompletion>;
|
|
127
|
+
|
|
128
|
+
/** Resolve a model name (OpenAI alias or native) to an AlgoChat model ID. */
|
|
129
|
+
export declare function resolveModel(requestedModel: string): string;
|
|
130
|
+
|
|
131
|
+
/** Return all supported models in OpenAI /v1/models format. */
|
|
132
|
+
export declare function getModelList(): ModelInfo[];
|
|
133
|
+
|
|
134
|
+
/** All supported AlgoChat models with metadata. */
|
|
135
|
+
export declare const ALGOCHAT_MODELS: Record<string, {
|
|
136
|
+
id: string;
|
|
137
|
+
displayName: string;
|
|
138
|
+
contextWindow: number;
|
|
139
|
+
maxOutputTokens: number;
|
|
140
|
+
requiresAuth: boolean;
|
|
141
|
+
}>;
|
|
142
|
+
|
|
143
|
+
/** Default model ID used when none is specified. */
|
|
144
|
+
export declare const DEFAULT_MODEL: string;
|