@adia-ai/llm 0.5.21 → 0.6.1

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/adapters/index.js CHANGED
@@ -33,33 +33,33 @@
33
33
  * { type: 'done', text: 'full response', usage: { input, output }, stopReason }
34
34
  * { type: 'error', error: Error }
35
35
  */
36
-
37
36
  import { anthropic } from './anthropic.js';
38
37
  import { openai } from './openai.js';
39
38
  import { gemini } from './gemini.js';
40
-
41
39
  // ── Provider registry ──
42
-
43
40
  const providers = { anthropic, openai, gemini };
44
-
45
41
  /** Detect provider from model name. */
46
42
  function detectProvider(model) {
47
- if (!model) return null;
48
- const m = model.toLowerCase();
49
- if (m.includes('claude') || m.startsWith('anthropic/')) return 'anthropic';
50
- if (m.includes('gpt') || m.includes('o1') || m.includes('o3') || m.includes('o4') || m.startsWith('openai/')) return 'openai';
51
- if (m.includes('gemini') || m.startsWith('google/')) return 'gemini';
52
- return null;
43
+ if (!model)
44
+ return null;
45
+ const m = model.toLowerCase();
46
+ if (m.includes('claude') || m.startsWith('anthropic/'))
47
+ return 'anthropic';
48
+ if (m.includes('gpt') || m.includes('o1') || m.includes('o3') || m.includes('o4') || m.startsWith('openai/'))
49
+ return 'openai';
50
+ if (m.includes('gemini') || m.startsWith('google/'))
51
+ return 'gemini';
52
+ return null;
53
53
  }
54
-
55
54
  function resolveAdapter(opts) {
56
- const name = opts.provider || detectProvider(opts.model);
57
- if (!name) throw new Error(`Cannot detect provider for model "${opts.model}". Set provider explicitly.`);
58
- const adapter = providers[name];
59
- if (!adapter) throw new Error(`Unknown provider "${name}". Available: ${Object.keys(providers).join(', ')}`);
60
- return adapter;
55
+ const name = (opts.provider || detectProvider(opts.model));
56
+ if (!name)
57
+ throw new Error(`Cannot detect provider for model "${opts.model}". Set provider explicitly.`);
58
+ const adapter = providers[name];
59
+ if (!adapter)
60
+ throw new Error(`Unknown provider "${name}". Available: ${Object.keys(providers).join(', ')}`);
61
+ return adapter;
61
62
  }
62
-
63
63
  // ── Proxy mode ──
64
64
  //
65
65
  // Two proxy flavors are supported:
@@ -73,7 +73,7 @@ function resolveAdapter(opts) {
73
73
  // — dumb URL rewriter that forwards the request body + headers
74
74
  // verbatim to the upstream API. The client must send the real
75
75
  // upstream body shape AND the real auth header (x-api-key for
76
- // Anthropic, Authorization: Bearer for OpenAI/Gemini).
76
+ // Anthropic, Authorization: Bearer *** OpenAI/Gemini).
77
77
  //
78
78
  // We distinguish by URL shape: anything matching `/api/llm/<provider>/`
79
79
  // is treated as a passthrough proxy and routed through buildRequest()
@@ -82,119 +82,107 @@ function resolveAdapter(opts) {
82
82
  // Each adapter still parses the upstream's streamed body via its own
83
83
  // parseStream — passthrough proxies pipe SSE bytes verbatim, smart
84
84
  // proxies must do the same.
85
-
86
85
  const PASSTHROUGH_PROXY_RE = /\/api\/llm\/[a-z]+(\/|$)/;
87
-
88
86
  function isPassthroughProxy(url) {
89
- return typeof url === 'string' && PASSTHROUGH_PROXY_RE.test(url);
87
+ return typeof url === 'string' && PASSTHROUGH_PROXY_RE.test(url);
90
88
  }
91
-
92
89
  function proxyRequest(opts, stream) {
93
- const provider = opts.provider || detectProvider(opts.model);
94
- const body = {
95
- provider,
96
- model: opts.model,
97
- messages: opts.messages,
98
- stream,
99
- };
100
- if (opts.system != null) body.system = opts.system;
101
- if (opts.maxTokens != null) body.maxTokens = opts.maxTokens;
102
- if (opts.temperature != null) body.temperature = opts.temperature;
103
- if (opts.thinking != null) body.thinking = opts.thinking;
104
- return {
105
- url: opts.proxyUrl,
106
- headers: { 'content-type': 'application/json' },
107
- body,
108
- };
90
+ const provider = opts.provider || detectProvider(opts.model);
91
+ const body = {
92
+ provider,
93
+ model: opts.model,
94
+ messages: opts.messages,
95
+ stream,
96
+ };
97
+ if (opts.system != null)
98
+ body['system'] = opts.system;
99
+ if (opts.maxTokens != null)
100
+ body['maxTokens'] = opts.maxTokens;
101
+ if (opts.temperature != null)
102
+ body['temperature'] = opts.temperature;
103
+ if (opts.thinking != null)
104
+ body['thinking'] = opts.thinking;
105
+ return {
106
+ url: opts.proxyUrl,
107
+ headers: { 'content-type': 'application/json' },
108
+ body,
109
+ };
109
110
  }
110
-
111
111
  /**
112
112
  * Build a passthrough-proxy request: real upstream body + real auth
113
113
  * header, but URL pointed at the proxy. The proxy forwards verbatim.
114
114
  */
115
115
  function passthroughRequest(opts, stream) {
116
- const adapter = resolveAdapter(opts);
117
- const built = adapter.buildRequest({ ...opts, stream });
118
- return { ...built, url: opts.proxyUrl };
116
+ const adapter = resolveAdapter(opts);
117
+ const built = adapter.buildRequest({ ...opts, stream });
118
+ return { ...built, url: opts.proxyUrl };
119
119
  }
120
-
121
120
  // ── Standalone functions ──
122
-
123
121
  /**
124
122
  * Non-streaming chat completion.
125
- * @returns {Promise<{text: string, usage: {input: number, output: number}, stopReason: string}>}
126
123
  */
127
124
  export async function chat(opts) {
128
- const adapter = resolveAdapter(opts);
129
- const { url, headers, body } = opts.proxyUrl
130
- ? (isPassthroughProxy(opts.proxyUrl) ? passthroughRequest(opts, false) : proxyRequest(opts, false))
131
- : adapter.buildRequest({ ...opts, stream: false });
132
-
133
- const res = await fetch(url, {
134
- method: 'POST',
135
- headers,
136
- body: JSON.stringify(body),
137
- signal: opts.signal,
138
- });
139
-
140
- if (!res.ok) {
141
- const err = await res.json().catch(() => ({}));
142
- throw new Error(err?.error?.message || `${adapter.name} API error ${res.status}`);
143
- }
144
-
145
- return adapter.parseResponse(await res.json());
125
+ const adapter = resolveAdapter(opts);
126
+ const { url, headers, body } = opts.proxyUrl
127
+ ? (isPassthroughProxy(opts.proxyUrl) ? passthroughRequest(opts, false) : proxyRequest(opts, false))
128
+ : adapter.buildRequest({ ...opts, stream: false });
129
+ const res = await fetch(url, {
130
+ method: 'POST',
131
+ headers,
132
+ body: JSON.stringify(body),
133
+ signal: (opts.signal ?? null),
134
+ });
135
+ if (!res.ok) {
136
+ const err = await res.json().catch(() => ({}));
137
+ throw new Error(err?.error?.message || `${adapter.name} API error ${res.status}`);
138
+ }
139
+ return adapter.parseResponse(await res.json());
146
140
  }
147
-
148
141
  /**
149
142
  * Streaming chat — yields chunks as they arrive.
150
- * @returns {AsyncGenerator<{type: string, text?: string, snapshot?: string, usage?: object, error?: Error}>}
151
143
  */
152
144
  export async function* streamChat(opts) {
153
- const adapter = resolveAdapter(opts);
154
- const { url, headers, body } = opts.proxyUrl
155
- ? (isPassthroughProxy(opts.proxyUrl) ? passthroughRequest(opts, true) : proxyRequest(opts, true))
156
- : adapter.buildRequest({ ...opts, stream: true });
157
-
158
- let res;
159
- try {
160
- res = await fetch(url, {
161
- method: 'POST',
162
- headers,
163
- body: JSON.stringify(body),
164
- signal: opts.signal,
165
- });
166
- } catch (err) {
167
- yield { type: 'error', error: err };
168
- return;
169
- }
170
-
171
- if (!res.ok) {
172
- const err = await res.json().catch(() => ({}));
173
- yield { type: 'error', error: new Error(err?.error?.message || `${adapter.name} API error ${res.status}`) };
174
- return;
175
- }
176
-
177
- yield* adapter.parseStream(res);
145
+ const adapter = resolveAdapter(opts);
146
+ const { url, headers, body } = opts.proxyUrl
147
+ ? (isPassthroughProxy(opts.proxyUrl) ? passthroughRequest(opts, true) : proxyRequest(opts, true))
148
+ : adapter.buildRequest({ ...opts, stream: true });
149
+ let res;
150
+ try {
151
+ res = await fetch(url, {
152
+ method: 'POST',
153
+ headers,
154
+ body: JSON.stringify(body),
155
+ signal: (opts.signal ?? null),
156
+ });
157
+ }
158
+ catch (err) {
159
+ yield { type: 'error', error: err };
160
+ return;
161
+ }
162
+ if (!res.ok) {
163
+ const err = await res.json().catch(() => ({}));
164
+ yield { type: 'error', error: new Error(err?.error?.message || `${adapter.name} API error ${res.status}`) };
165
+ return;
166
+ }
167
+ yield* adapter.parseStream(res);
178
168
  }
179
-
180
169
  // ── Client factory ──
181
-
182
170
  /**
183
171
  * Create a reusable client instance with defaults baked in.
184
172
  *
185
- * @param {object} defaults
186
- * @param {string} defaults.provider — 'anthropic' | 'openai' | 'gemini'
187
- * @param {string} defaults.apiKey
188
- * @param {string} [defaults.model] — default model
189
- * @param {string} [defaults.proxyUrl] — proxy URL (for CORS)
190
- * @param {string} [defaults.system] — default system prompt
173
+ * @param defaults
174
+ * @param defaults.provider — 'anthropic' | 'openai' | 'gemini'
175
+ * @param defaults.apiKey
176
+ * @param defaults.model — default model
177
+ * @param defaults.proxyUrl — proxy URL (for CORS)
178
+ * @param defaults.system — default system prompt
191
179
  */
192
180
  export function createClient(defaults = {}) {
193
- return {
194
- chat: (opts) => chat({ ...defaults, ...opts }),
195
- stream: (opts) => streamChat({ ...defaults, ...opts }),
196
- };
181
+ return {
182
+ chat: (opts) => chat({ ...defaults, ...opts }),
183
+ stream: (opts) => streamChat({ ...defaults, ...opts }),
184
+ };
197
185
  }
198
-
199
186
  // Re-export adapters for direct use
200
187
  export { anthropic, openai, gemini };
188
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/adapters/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * OpenAI Chat Completions API adapter.
3
+ * Endpoint: https://api.openai.com/v1/chat/completions
4
+ * Also compatible with: Groq, Together, Mistral, any OpenAI-compatible API.
5
+ */
6
+ import type { AdapterRequest, AdapterResponse, StreamChunk, BuildRequestOpts } from './anthropic.js';
7
+ interface OpenAIUsage {
8
+ prompt_tokens?: number;
9
+ completion_tokens?: number;
10
+ }
11
+ interface OpenAIChoice {
12
+ message?: {
13
+ content?: string;
14
+ };
15
+ delta?: {
16
+ content?: string;
17
+ reasoning_content?: string;
18
+ };
19
+ finish_reason?: string;
20
+ }
21
+ interface OpenAIResponseBody {
22
+ choices?: OpenAIChoice[];
23
+ usage?: OpenAIUsage;
24
+ }
25
+ export declare const openai: {
26
+ name: "openai";
27
+ buildRequest(opts: BuildRequestOpts): AdapterRequest;
28
+ parseResponse(data: OpenAIResponseBody): AdapterResponse;
29
+ parseStream(response: Response): AsyncGenerator<StreamChunk>;
30
+ };
31
+ export {};
32
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../src/adapters/openai.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAgB,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAMnH,UAAU,WAAW;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,kBAAkB;IAC1B,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAID,eAAO,MAAM,MAAM;;uBAGE,gBAAgB,GAAG,cAAc;wBA0BhC,kBAAkB,GAAG,eAAe;0BAU3B,QAAQ,GAAG,cAAc,CAAC,WAAW,CAAC;CAmCpE,CAAC"}
@@ -3,82 +3,83 @@
3
3
  * Endpoint: https://api.openai.com/v1/chat/completions
4
4
  * Also compatible with: Groq, Together, Mistral, any OpenAI-compatible API.
5
5
  */
6
-
7
6
  import { readSSE } from './sse.js';
8
-
9
7
  const API_URL = 'https://api.openai.com/v1/chat/completions';
10
-
8
+ // ── Adapter ────────────────────────────────────────────────────────────────
11
9
  export const openai = {
12
- name: 'openai',
13
-
14
- buildRequest(opts) {
15
- const messages = [];
16
- if (opts.system) messages.push({ role: 'system', content: opts.system });
17
- for (const msg of opts.messages) {
18
- messages.push({ role: msg.role, content: msg.content });
19
- }
20
-
21
- const body = {
22
- model: opts.model,
23
- messages,
24
- stream: !!opts.stream,
25
- };
26
- if (opts.maxTokens) body.max_tokens = opts.maxTokens;
27
- if (opts.temperature != null) body.temperature = opts.temperature;
28
- if (opts.stream) body.stream_options = { include_usage: true };
29
-
30
- return {
31
- url: API_URL,
32
- headers: {
33
- 'content-type': 'application/json',
34
- 'authorization': `Bearer ${opts.apiKey}`,
35
- },
36
- body,
37
- };
38
- },
39
-
40
- parseResponse(data) {
41
- const choice = data.choices?.[0];
42
- const text = choice?.message?.content ?? '';
43
- return {
44
- text,
45
- usage: { input: data.usage?.prompt_tokens ?? 0, output: data.usage?.completion_tokens ?? 0 },
46
- stopReason: choice?.finish_reason === 'stop' ? 'end' : (choice?.finish_reason ?? 'end'),
47
- };
48
- },
49
-
50
- async *parseStream(response) {
51
- let snapshot = '';
52
- let usage = { input: 0, output: 0 };
53
- let stopReason = 'end';
54
-
55
- for await (const event of readSSE(response.body)) {
56
- if (event.done) break;
57
- let data;
58
- try { data = JSON.parse(event.data); } catch { continue; }
59
-
60
- if (data.usage) {
61
- usage.input = data.usage.prompt_tokens ?? 0;
62
- usage.output = data.usage.completion_tokens ?? 0;
63
- }
64
-
65
- const choice = data.choices?.[0];
66
- if (!choice) continue;
67
-
68
- if (choice.finish_reason) {
69
- stopReason = choice.finish_reason === 'stop' ? 'end' : choice.finish_reason;
70
- }
71
-
72
- const delta = choice.delta;
73
- if (delta?.content) {
74
- snapshot += delta.content;
75
- yield { type: 'text', text: delta.content, snapshot };
76
- }
77
- if (delta?.reasoning_content) {
78
- yield { type: 'thinking', text: delta.reasoning_content };
79
- }
80
- }
81
-
82
- yield { type: 'done', text: snapshot, usage, stopReason };
83
- },
10
+ name: 'openai',
11
+ buildRequest(opts) {
12
+ const messages = [];
13
+ if (opts.system)
14
+ messages.push({ role: 'system', content: opts.system });
15
+ for (const msg of opts.messages) {
16
+ messages.push({ role: msg.role, content: msg.content });
17
+ }
18
+ const body = {
19
+ model: opts.model,
20
+ messages,
21
+ stream: !!opts.stream,
22
+ };
23
+ if (opts.maxTokens)
24
+ body['max_tokens'] = opts.maxTokens;
25
+ if (opts.temperature != null)
26
+ body['temperature'] = opts.temperature;
27
+ if (opts.stream)
28
+ body['stream_options'] = { include_usage: true };
29
+ return {
30
+ url: API_URL,
31
+ headers: {
32
+ 'content-type': 'application/json',
33
+ 'authorization': `Bearer ${opts.apiKey}`,
34
+ },
35
+ body,
36
+ };
37
+ },
38
+ parseResponse(data) {
39
+ const choice = data.choices?.[0];
40
+ const text = choice?.message?.content ?? '';
41
+ return {
42
+ text,
43
+ usage: { input: data.usage?.prompt_tokens ?? 0, output: data.usage?.completion_tokens ?? 0 },
44
+ stopReason: choice?.finish_reason === 'stop' ? 'end' : (choice?.finish_reason ?? 'end'),
45
+ };
46
+ },
47
+ async *parseStream(response) {
48
+ if (!response.body)
49
+ throw new Error('Response body is null');
50
+ let snapshot = '';
51
+ let usage = { input: 0, output: 0 };
52
+ let stopReason = 'end';
53
+ for await (const event of readSSE(response.body)) {
54
+ if (event.done)
55
+ break;
56
+ let data;
57
+ try {
58
+ data = JSON.parse(event.data);
59
+ }
60
+ catch {
61
+ continue;
62
+ }
63
+ if (data.usage) {
64
+ usage.input = data.usage.prompt_tokens ?? 0;
65
+ usage.output = data.usage.completion_tokens ?? 0;
66
+ }
67
+ const choice = data.choices?.[0];
68
+ if (!choice)
69
+ continue;
70
+ if (choice.finish_reason) {
71
+ stopReason = choice.finish_reason === 'stop' ? 'end' : choice.finish_reason;
72
+ }
73
+ const delta = choice.delta;
74
+ if (delta?.content) {
75
+ snapshot += delta.content;
76
+ yield { type: 'text', text: delta.content, snapshot };
77
+ }
78
+ if (delta?.reasoning_content) {
79
+ yield { type: 'thinking', text: delta.reasoning_content };
80
+ }
81
+ }
82
+ yield { type: 'done', text: snapshot, usage, stopReason };
83
+ },
84
84
  };
85
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../src/adapters/openai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * SSE Parser — shared by Anthropic, OpenAI, and Gemini adapters.
3
+ * Handles partial line buffering, double-newline splitting, and [DONE] detection.
4
+ */
5
+ export interface SSEEvent {
6
+ event: string | undefined;
7
+ data: string;
8
+ done: boolean;
9
+ }
10
+ export declare function readSSE(body: ReadableStream<Uint8Array>): AsyncGenerator<SSEEvent>;
11
+ //# sourceMappingURL=sse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/adapters/sse.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wBAAuB,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,cAAc,CAAC,QAAQ,CAAC,CAoBzF"}
package/adapters/sse.js CHANGED
@@ -2,49 +2,56 @@
2
2
  * SSE Parser — shared by Anthropic, OpenAI, and Gemini adapters.
3
3
  * Handles partial line buffering, double-newline splitting, and [DONE] detection.
4
4
  */
5
-
6
5
  export async function* readSSE(body) {
7
- const reader = body.getReader();
8
- const decoder = new TextDecoder();
9
- let buffer = '';
10
- try {
11
- while (true) {
12
- const { done, value } = await reader.read();
13
- if (done) break;
14
- buffer += decoder.decode(value, { stream: true });
15
- const { events, remainder } = parse(buffer);
16
- buffer = remainder;
17
- for (const event of events) yield event;
6
+ const reader = body.getReader();
7
+ const decoder = new TextDecoder();
8
+ let buffer = '';
9
+ try {
10
+ while (true) {
11
+ const { done, value } = await reader.read();
12
+ if (done)
13
+ break;
14
+ buffer += decoder.decode(value, { stream: true });
15
+ const { events, remainder } = parse(buffer);
16
+ buffer = remainder;
17
+ for (const event of events)
18
+ yield event;
19
+ }
20
+ if (buffer.trim()) {
21
+ const { events } = parse(buffer + '\n\n');
22
+ for (const event of events)
23
+ yield event;
24
+ }
18
25
  }
19
- if (buffer.trim()) {
20
- const { events } = parse(buffer + '\n\n');
21
- for (const event of events) yield event;
26
+ finally {
27
+ reader.releaseLock();
22
28
  }
23
- } finally {
24
- reader.releaseLock();
25
- }
26
29
  }
27
-
28
30
  function parse(text) {
29
- const events = [];
30
- const parts = text.split(/\n\n|\r\n\r\n/);
31
- const remainder = parts.pop() ?? '';
32
- for (const part of parts) {
33
- const trimmed = part.trim();
34
- if (!trimmed) continue;
35
- let eventType;
36
- const dataLines = [];
37
- for (const line of trimmed.split(/\r?\n/)) {
38
- if (line.startsWith(':')) continue;
39
- if (line.startsWith('event:')) eventType = line.slice(6).trim();
40
- else if (line.startsWith('data:')) {
41
- const v = line.slice(5);
42
- dataLines.push(v.startsWith(' ') ? v.slice(1) : v);
43
- }
31
+ const events = [];
32
+ const parts = text.split(/\n\n|\r\n\r\n/);
33
+ const remainder = parts.pop() ?? '';
34
+ for (const part of parts) {
35
+ const trimmed = part.trim();
36
+ if (!trimmed)
37
+ continue;
38
+ let eventType;
39
+ const dataLines = [];
40
+ for (const line of trimmed.split(/\r?\n/)) {
41
+ if (line.startsWith(':'))
42
+ continue;
43
+ if (line.startsWith('event:'))
44
+ eventType = line.slice(6).trim();
45
+ else if (line.startsWith('data:')) {
46
+ const v = line.slice(5);
47
+ dataLines.push(v.startsWith(' ') ? v.slice(1) : v);
48
+ }
49
+ }
50
+ if (!dataLines.length)
51
+ continue;
52
+ const data = dataLines.join('\n');
53
+ events.push({ event: eventType, data, done: data === '[DONE]' });
44
54
  }
45
- if (!dataLines.length) continue;
46
- const data = dataLines.join('\n');
47
- events.push({ event: eventType, data, done: data === '[DONE]' });
48
- }
49
- return { events, remainder };
55
+ return { events, remainder };
50
56
  }
57
+ //# sourceMappingURL=sse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.js","sourceRoot":"","sources":["../src/adapters/sse.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,OAAO,CAAC,IAAgC;IAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAChB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAClD,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;YAC5C,MAAM,GAAG,SAAS,CAAC;YACnB,KAAK,MAAM,KAAK,IAAI,MAAM;gBAAE,MAAM,KAAK,CAAC;QAC1C,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YAClB,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;YAC1C,KAAK,MAAM,KAAK,IAAI,MAAM;gBAAE,MAAM,KAAK,CAAC;QAC1C,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,IAAY;IACzB,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;IACpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,IAAI,SAA6B,CAAC;QAClC,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1C,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YACnC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;gBAAE,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBAC3D,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACxB,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,MAAM;YAAE,SAAS;QAChC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC/B,CAAC"}
package/index.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @adia-ai/llm — provider-agnostic LLM client for AdiaUI.
3
+ *
4
+ * Re-exports the public API surface:
5
+ * - chat, streamChat, createClient — standalone functions + factory
6
+ * - MODELS, DEFAULT_MODEL — model catalog
7
+ * - StubLLMAdapter — deterministic test stub
8
+ * - createAdapter — AdiaUI pipeline bridge
9
+ */
10
+ export { chat, streamChat, createClient } from './adapters/index.js';
11
+ export { MODELS, DEFAULT_MODEL } from './models.js';
12
+ export { StubLLMAdapter } from './llm-stub.js';
13
+ export { createAdapter } from './llm-bridge.js';
14
+ //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}