@krutai/ai-provider 0.2.12 → 0.2.13
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/AI_REFERENCE.md +34 -10
- package/README.md +29 -44
- package/dist/index.d.mts +11 -64
- package/dist/index.d.ts +11 -64
- package/dist/index.js +10 -244
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10 -244
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/AI_REFERENCE.md
CHANGED
|
@@ -19,7 +19,6 @@ AI Flow:
|
|
|
19
19
|
→ POST {serverUrl}/validate (key validation)
|
|
20
20
|
→ POST {serverUrl}/generate (single response)
|
|
21
21
|
→ POST {serverUrl}/stream (SSE streaming)
|
|
22
|
-
→ POST {serverUrl}/chat (multi-turn)
|
|
23
22
|
→ Your deployed LangChain server
|
|
24
23
|
```
|
|
25
24
|
|
|
@@ -43,8 +42,7 @@ packages/ai-provider/
|
|
|
43
42
|
|---|---|---|---|
|
|
44
43
|
| `/validate` | POST | `{ apiKey }` | `{ valid: true/false, message? }` |
|
|
45
44
|
| `/generate` | POST | `{ prompt, model, system?, maxTokens?, temperature? }` | `{ text/content/message: string }` |
|
|
46
|
-
| `/stream` | POST | `{
|
|
47
|
-
| `/chat` | POST | `{ messages, model, maxTokens?, temperature? }` | `{ text/content/message: string }` |
|
|
45
|
+
| `/stream` | POST | `{ messages, model, system?, maxTokens?, temperature? }` | SSE stream `data: <chunk>` |
|
|
48
46
|
|
|
49
47
|
All AI endpoints receive `Authorization: Bearer <apiKey>` and `x-api-key: <apiKey>` headers.
|
|
50
48
|
|
|
@@ -62,8 +60,38 @@ const ai = krutAI({
|
|
|
62
60
|
});
|
|
63
61
|
|
|
64
62
|
await ai.initialize(); // validates key with server
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 1. `chat(prompt: string)` — Simple String Prompts
|
|
66
|
+
Used to get a single, non-streaming text response from a string prompt.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
const text = await ai.chat('Write a poem about TypeScript');
|
|
70
|
+
console.log(text);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 2. `streamChatResponse(messages: ChatMessage[])` — Multi-Turn & Streaming
|
|
74
|
+
Used for multi-turn conversations and streaming responses. It takes an array of `ChatMessage` objects instead of a single string. It returns a raw fetch `Response` containing the `text/event-stream` body.
|
|
75
|
+
|
|
76
|
+
Ideal for proxying streams (e.g., Next.js API routes) down to your backend component or manually reading the `ReadableStream`.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// Example: Proxying in a Next.js route
|
|
80
|
+
export async function POST(req: Request) {
|
|
81
|
+
const { messages } = await req.json();
|
|
82
|
+
|
|
83
|
+
// ai.streamChatResponse accepts an array of messages:
|
|
84
|
+
// [{ role: 'user', content: '...' }, ...]
|
|
85
|
+
return await ai.streamChatResponse(messages);
|
|
86
|
+
}
|
|
65
87
|
|
|
66
|
-
|
|
88
|
+
// Example: Manual Node environment stream reading
|
|
89
|
+
const response = await ai.streamChatResponse([
|
|
90
|
+
{ role: 'system', content: 'You are a helpful assistant.' },
|
|
91
|
+
{ role: 'user', content: 'Tell me a story' }
|
|
92
|
+
]);
|
|
93
|
+
const reader = response.body?.getReader();
|
|
94
|
+
// Use a TextDecoder to parse value chunks...
|
|
67
95
|
```
|
|
68
96
|
|
|
69
97
|
### `KrutAIProvider` class ← FULL CLASS API
|
|
@@ -83,12 +111,8 @@ await ai.initialize();
|
|
|
83
111
|
|
|
84
112
|
**Methods:**
|
|
85
113
|
- `initialize(): Promise<void>` — validates key against server, marks provider ready
|
|
86
|
-
- `
|
|
87
|
-
- `
|
|
88
|
-
- `streamResponse(prompt, opts?)` — `Promise<Response>` — returns the raw fetch Response for proxying
|
|
89
|
-
- `streamChat(messages, opts?)` — `AsyncGenerator<string>` — SSE multi-turn streaming
|
|
90
|
-
- `streamChatResponse(messages, opts?)` — `Promise<Response>` — returns the raw fetch Response for proxying
|
|
91
|
-
- `chat(messages, opts?): Promise<string>` — multi-turn conversation
|
|
114
|
+
- `chat(prompt, opts?): Promise<string>` — single response (non-streaming)
|
|
115
|
+
- `streamChatResponse(messages, opts?)` — `Promise<Response>` — returns the raw fetch Response for proxying (SSE multi-turn streaming)
|
|
92
116
|
- `getModel(): string` — active model name
|
|
93
117
|
- `isInitialized(): boolean`
|
|
94
118
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @krutai/ai-provider
|
|
2
2
|
|
|
3
|
-
AI provider package for KrutAI — fetch-based client
|
|
3
|
+
AI provider package for KrutAI — fetch-based client form our deployed server.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -30,13 +30,13 @@ const ai = krutAI({
|
|
|
30
30
|
await ai.initialize(); // validates key with your server
|
|
31
31
|
|
|
32
32
|
// Single response
|
|
33
|
-
const text = await ai.
|
|
33
|
+
const text = await ai.chat('Write a poem about TypeScript');
|
|
34
34
|
console.log(text);
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
## Usage
|
|
38
38
|
|
|
39
|
-
###
|
|
39
|
+
### Chat (single response)
|
|
40
40
|
|
|
41
41
|
```typescript
|
|
42
42
|
const ai = krutAI({
|
|
@@ -47,7 +47,7 @@ const ai = krutAI({
|
|
|
47
47
|
|
|
48
48
|
await ai.initialize();
|
|
49
49
|
|
|
50
|
-
const text = await ai.
|
|
50
|
+
const text = await ai.chat('Explain async/await in JavaScript', {
|
|
51
51
|
system: 'You are a helpful coding tutor.',
|
|
52
52
|
maxTokens: 500,
|
|
53
53
|
temperature: 0.7,
|
|
@@ -56,21 +56,6 @@ const text = await ai.generate('Explain async/await in JavaScript', {
|
|
|
56
56
|
console.log(text);
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
### Streaming
|
|
60
|
-
|
|
61
|
-
```typescript
|
|
62
|
-
const ai = krutAI({
|
|
63
|
-
apiKey: process.env.KRUTAI_API_KEY!,
|
|
64
|
-
// uses http://localhost:8000 by default
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
await ai.initialize();
|
|
68
|
-
|
|
69
|
-
// stream() is an async generator
|
|
70
|
-
for await (const chunk of ai.stream('Tell me a short story')) {
|
|
71
|
-
process.stdout.write(chunk);
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
59
|
|
|
75
60
|
### Multi-turn Chat
|
|
76
61
|
|
|
@@ -116,29 +101,11 @@ const response = await ai.chat([
|
|
|
116
101
|
});
|
|
117
102
|
```
|
|
118
103
|
|
|
119
|
-
### Streaming
|
|
120
|
-
|
|
121
|
-
```typescript
|
|
122
|
-
const ai = krutAI({
|
|
123
|
-
apiKey: process.env.KRUTAI_API_KEY!,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
await ai.initialize();
|
|
127
|
-
|
|
128
|
-
const stream = ai.streamChat([
|
|
129
|
-
{ role: 'user', content: 'What is the capital of France?' },
|
|
130
|
-
{ role: 'assistant', content: 'Paris.' },
|
|
131
|
-
{ role: 'user', content: 'What is it famous for?' },
|
|
132
|
-
]);
|
|
104
|
+
### Streaming (Proxying SSE Streams)
|
|
133
105
|
|
|
134
|
-
|
|
135
|
-
process.stdout.write(chunk);
|
|
136
|
-
}
|
|
137
|
-
```
|
|
106
|
+
If you are building an API route (e.g., in Next.js) and want to pipe the true Server-Sent Events (SSE) stream down to your backend component, use `streamChatResponse`.
|
|
138
107
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
If you are building an API route (e.g., in Next.js) and want to pipe the true Server-Sent Events (SSE) stream down to your frontend component, use the `Response` variants:
|
|
108
|
+
`streamChatResponse` returns the raw fetch `Response` object containing the `text/event-stream` body from deployed LangChain server.
|
|
142
109
|
|
|
143
110
|
```typescript
|
|
144
111
|
// app/api/chat/route.ts
|
|
@@ -148,11 +115,30 @@ export async function POST(req: Request) {
|
|
|
148
115
|
// Returns the native fetch Response (with text/event-stream headers and body)
|
|
149
116
|
const response = await ai.streamChatResponse(messages);
|
|
150
117
|
|
|
151
|
-
// Proxy it directly to the
|
|
118
|
+
// Proxy it directly to the backend!
|
|
152
119
|
return response;
|
|
153
120
|
}
|
|
154
121
|
```
|
|
155
122
|
|
|
123
|
+
If you need to consume the stream in a Node environment rather than proxying it, you can read from the response body directly:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
const response = await ai.streamChatResponse([
|
|
127
|
+
{ role: 'user', content: 'Tell me a short story' }
|
|
128
|
+
]);
|
|
129
|
+
|
|
130
|
+
const reader = response.body?.getReader();
|
|
131
|
+
const decoder = new TextDecoder();
|
|
132
|
+
|
|
133
|
+
if (reader) {
|
|
134
|
+
while (true) {
|
|
135
|
+
const { done, value } = await reader.read();
|
|
136
|
+
if (done) break;
|
|
137
|
+
process.stdout.write(decoder.decode(value, { stream: true }));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
156
142
|
### Skip validation (useful for tests)
|
|
157
143
|
|
|
158
144
|
```typescript
|
|
@@ -163,7 +149,7 @@ const ai = krutAI({
|
|
|
163
149
|
});
|
|
164
150
|
|
|
165
151
|
// No need to call initialize() when validateOnInit is false
|
|
166
|
-
const text = await ai.
|
|
152
|
+
const text = await ai.chat('Hello!');
|
|
167
153
|
```
|
|
168
154
|
|
|
169
155
|
## Server API Contract
|
|
@@ -174,8 +160,7 @@ Your LangChain server must expose these endpoints:
|
|
|
174
160
|
|---|---|---|---|
|
|
175
161
|
| `/validate` | POST | `x-api-key` header | `{ "apiKey": "..." }` |
|
|
176
162
|
| `/generate` | POST | `Authorization: Bearer <key>` | `{ "prompt": "...", "model": "...", ... }` |
|
|
177
|
-
| `/stream` | POST | `Authorization: Bearer <key>` | `{ "
|
|
178
|
-
| `/chat` | POST | `Authorization: Bearer <key>` | `{ "messages": [...], "model": "...", ... }` |
|
|
163
|
+
| `/stream` | POST | `Authorization: Bearer <key>` | `{ "messages": [...], "model": "...", ... }` |
|
|
179
164
|
|
|
180
165
|
**Validation response:** `{ "valid": true }` or `{ "valid": false, "message": "reason" }`
|
|
181
166
|
|
package/dist/index.d.mts
CHANGED
|
@@ -146,57 +146,6 @@ declare class KrutAIProvider {
|
|
|
146
146
|
private assertInitialized;
|
|
147
147
|
/** Common request headers sent to the server on every AI call. */
|
|
148
148
|
private authHeaders;
|
|
149
|
-
/**
|
|
150
|
-
* Generate a response for a prompt (non-streaming).
|
|
151
|
-
*
|
|
152
|
-
* Calls: POST {serverUrl}/generate
|
|
153
|
-
* Body: { prompt, model, system?, maxTokens?, temperature? }
|
|
154
|
-
* Expected response: { text: string } or { content: string } or { message: string }
|
|
155
|
-
*
|
|
156
|
-
* @param prompt - The user prompt string
|
|
157
|
-
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
158
|
-
* @returns The assistant's response text
|
|
159
|
-
*/
|
|
160
|
-
generate(prompt: string, options?: GenerateOptions): Promise<string>;
|
|
161
|
-
/**
|
|
162
|
-
* Generate a streaming response for a prompt via Server-Sent Events (SSE).
|
|
163
|
-
*
|
|
164
|
-
* Calls: POST {serverUrl}/stream
|
|
165
|
-
* Body: { prompt, model, system?, maxTokens?, temperature? }
|
|
166
|
-
* Expected response: `text/event-stream` with `data: <chunk>` lines.
|
|
167
|
-
*
|
|
168
|
-
* @param prompt - The user prompt string
|
|
169
|
-
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
170
|
-
* @returns An async generator yielding string chunks from the server
|
|
171
|
-
*
|
|
172
|
-
* @example
|
|
173
|
-
* ```typescript
|
|
174
|
-
* const stream = ai.stream('Tell me a story');
|
|
175
|
-
* for await (const chunk of stream) {
|
|
176
|
-
* process.stdout.write(chunk);
|
|
177
|
-
* }
|
|
178
|
-
* ```
|
|
179
|
-
*/
|
|
180
|
-
stream(prompt: string, options?: GenerateOptions): AsyncGenerator<string>;
|
|
181
|
-
/**
|
|
182
|
-
* Similar to stream() but returns the raw fetch Response object.
|
|
183
|
-
* Useful when you want to proxy the Server-Sent Events stream directly to a frontend client
|
|
184
|
-
* (e.g., returning this directly from a Next.js API route).
|
|
185
|
-
*
|
|
186
|
-
* @param prompt - The user prompt string
|
|
187
|
-
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
188
|
-
* @returns A Promise resolving to the native fetch Response
|
|
189
|
-
*/
|
|
190
|
-
streamResponse(prompt: string, options?: GenerateOptions): Promise<Response>;
|
|
191
|
-
/**
|
|
192
|
-
* Multi-turn conversation streaming: pass a full message history.
|
|
193
|
-
* Calls POST /stream with the full { messages } payload.
|
|
194
|
-
*
|
|
195
|
-
* @param messages - Full conversation history
|
|
196
|
-
* @param options - Optional overrides (model, maxTokens, temperature)
|
|
197
|
-
* @returns An async generator yielding string chunks from the server
|
|
198
|
-
*/
|
|
199
|
-
streamChat(messages: ChatMessage[], options?: GenerateOptions): AsyncGenerator<string>;
|
|
200
149
|
/**
|
|
201
150
|
* Similar to streamChat() but returns the raw fetch Response object.
|
|
202
151
|
* Useful for proxying the Server-Sent Events stream directly to a frontend client.
|
|
@@ -207,17 +156,17 @@ declare class KrutAIProvider {
|
|
|
207
156
|
*/
|
|
208
157
|
streamChatResponse(messages: ChatMessage[], options?: GenerateOptions): Promise<Response>;
|
|
209
158
|
/**
|
|
210
|
-
*
|
|
159
|
+
* Generate a response for a prompt (non-streaming).
|
|
211
160
|
*
|
|
212
|
-
* Calls: POST {serverUrl}/
|
|
213
|
-
* Body: {
|
|
161
|
+
* Calls: POST {serverUrl}/generate
|
|
162
|
+
* Body: { prompt, model, system?, maxTokens?, temperature? }
|
|
214
163
|
* Expected response: { text: string } or { content: string } or { message: string }
|
|
215
164
|
*
|
|
216
|
-
* @param
|
|
217
|
-
* @param options - Optional overrides (model, maxTokens, temperature)
|
|
165
|
+
* @param prompt - The user prompt string
|
|
166
|
+
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
218
167
|
* @returns The assistant's response text
|
|
219
168
|
*/
|
|
220
|
-
chat(
|
|
169
|
+
chat(prompt: string, options?: GenerateOptions): Promise<string>;
|
|
221
170
|
}
|
|
222
171
|
|
|
223
172
|
/**
|
|
@@ -237,7 +186,7 @@ declare class KrutAIProvider {
|
|
|
237
186
|
*
|
|
238
187
|
* await ai.initialize(); // validates key with server
|
|
239
188
|
*
|
|
240
|
-
* const text = await ai.
|
|
189
|
+
* const text = await ai.chat('Write a poem about TypeScript');
|
|
241
190
|
* console.log(text);
|
|
242
191
|
* ```
|
|
243
192
|
*
|
|
@@ -249,7 +198,7 @@ declare class KrutAIProvider {
|
|
|
249
198
|
* model: 'gpt-4o',
|
|
250
199
|
* });
|
|
251
200
|
* await ai.initialize();
|
|
252
|
-
* const text = await ai.
|
|
201
|
+
* const text = await ai.chat('Hello!');
|
|
253
202
|
* ```
|
|
254
203
|
*
|
|
255
204
|
* @example Streaming
|
|
@@ -260,10 +209,8 @@ declare class KrutAIProvider {
|
|
|
260
209
|
* });
|
|
261
210
|
* await ai.initialize();
|
|
262
211
|
*
|
|
263
|
-
* const
|
|
264
|
-
*
|
|
265
|
-
* process.stdout.write(chunk);
|
|
266
|
-
* }
|
|
212
|
+
* const response = await ai.streamChatResponse([{ role: 'user', content: 'Tell me a story' }]);
|
|
213
|
+
* // Example assumes you handle the SSE stream from the response body
|
|
267
214
|
* ```
|
|
268
215
|
*
|
|
269
216
|
* @packageDocumentation
|
|
@@ -287,7 +234,7 @@ declare class KrutAIProvider {
|
|
|
287
234
|
* });
|
|
288
235
|
*
|
|
289
236
|
* await ai.initialize();
|
|
290
|
-
* const text = await ai.
|
|
237
|
+
* const text = await ai.chat('Hello!');
|
|
291
238
|
* ```
|
|
292
239
|
*/
|
|
293
240
|
declare function krutAI(config: KrutAIProviderConfig & {
|
package/dist/index.d.ts
CHANGED
|
@@ -146,57 +146,6 @@ declare class KrutAIProvider {
|
|
|
146
146
|
private assertInitialized;
|
|
147
147
|
/** Common request headers sent to the server on every AI call. */
|
|
148
148
|
private authHeaders;
|
|
149
|
-
/**
|
|
150
|
-
* Generate a response for a prompt (non-streaming).
|
|
151
|
-
*
|
|
152
|
-
* Calls: POST {serverUrl}/generate
|
|
153
|
-
* Body: { prompt, model, system?, maxTokens?, temperature? }
|
|
154
|
-
* Expected response: { text: string } or { content: string } or { message: string }
|
|
155
|
-
*
|
|
156
|
-
* @param prompt - The user prompt string
|
|
157
|
-
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
158
|
-
* @returns The assistant's response text
|
|
159
|
-
*/
|
|
160
|
-
generate(prompt: string, options?: GenerateOptions): Promise<string>;
|
|
161
|
-
/**
|
|
162
|
-
* Generate a streaming response for a prompt via Server-Sent Events (SSE).
|
|
163
|
-
*
|
|
164
|
-
* Calls: POST {serverUrl}/stream
|
|
165
|
-
* Body: { prompt, model, system?, maxTokens?, temperature? }
|
|
166
|
-
* Expected response: `text/event-stream` with `data: <chunk>` lines.
|
|
167
|
-
*
|
|
168
|
-
* @param prompt - The user prompt string
|
|
169
|
-
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
170
|
-
* @returns An async generator yielding string chunks from the server
|
|
171
|
-
*
|
|
172
|
-
* @example
|
|
173
|
-
* ```typescript
|
|
174
|
-
* const stream = ai.stream('Tell me a story');
|
|
175
|
-
* for await (const chunk of stream) {
|
|
176
|
-
* process.stdout.write(chunk);
|
|
177
|
-
* }
|
|
178
|
-
* ```
|
|
179
|
-
*/
|
|
180
|
-
stream(prompt: string, options?: GenerateOptions): AsyncGenerator<string>;
|
|
181
|
-
/**
|
|
182
|
-
* Similar to stream() but returns the raw fetch Response object.
|
|
183
|
-
* Useful when you want to proxy the Server-Sent Events stream directly to a frontend client
|
|
184
|
-
* (e.g., returning this directly from a Next.js API route).
|
|
185
|
-
*
|
|
186
|
-
* @param prompt - The user prompt string
|
|
187
|
-
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
188
|
-
* @returns A Promise resolving to the native fetch Response
|
|
189
|
-
*/
|
|
190
|
-
streamResponse(prompt: string, options?: GenerateOptions): Promise<Response>;
|
|
191
|
-
/**
|
|
192
|
-
* Multi-turn conversation streaming: pass a full message history.
|
|
193
|
-
* Calls POST /stream with the full { messages } payload.
|
|
194
|
-
*
|
|
195
|
-
* @param messages - Full conversation history
|
|
196
|
-
* @param options - Optional overrides (model, maxTokens, temperature)
|
|
197
|
-
* @returns An async generator yielding string chunks from the server
|
|
198
|
-
*/
|
|
199
|
-
streamChat(messages: ChatMessage[], options?: GenerateOptions): AsyncGenerator<string>;
|
|
200
149
|
/**
|
|
201
150
|
* Similar to streamChat() but returns the raw fetch Response object.
|
|
202
151
|
* Useful for proxying the Server-Sent Events stream directly to a frontend client.
|
|
@@ -207,17 +156,17 @@ declare class KrutAIProvider {
|
|
|
207
156
|
*/
|
|
208
157
|
streamChatResponse(messages: ChatMessage[], options?: GenerateOptions): Promise<Response>;
|
|
209
158
|
/**
|
|
210
|
-
*
|
|
159
|
+
* Generate a response for a prompt (non-streaming).
|
|
211
160
|
*
|
|
212
|
-
* Calls: POST {serverUrl}/
|
|
213
|
-
* Body: {
|
|
161
|
+
* Calls: POST {serverUrl}/generate
|
|
162
|
+
* Body: { prompt, model, system?, maxTokens?, temperature? }
|
|
214
163
|
* Expected response: { text: string } or { content: string } or { message: string }
|
|
215
164
|
*
|
|
216
|
-
* @param
|
|
217
|
-
* @param options - Optional overrides (model, maxTokens, temperature)
|
|
165
|
+
* @param prompt - The user prompt string
|
|
166
|
+
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
218
167
|
* @returns The assistant's response text
|
|
219
168
|
*/
|
|
220
|
-
chat(
|
|
169
|
+
chat(prompt: string, options?: GenerateOptions): Promise<string>;
|
|
221
170
|
}
|
|
222
171
|
|
|
223
172
|
/**
|
|
@@ -237,7 +186,7 @@ declare class KrutAIProvider {
|
|
|
237
186
|
*
|
|
238
187
|
* await ai.initialize(); // validates key with server
|
|
239
188
|
*
|
|
240
|
-
* const text = await ai.
|
|
189
|
+
* const text = await ai.chat('Write a poem about TypeScript');
|
|
241
190
|
* console.log(text);
|
|
242
191
|
* ```
|
|
243
192
|
*
|
|
@@ -249,7 +198,7 @@ declare class KrutAIProvider {
|
|
|
249
198
|
* model: 'gpt-4o',
|
|
250
199
|
* });
|
|
251
200
|
* await ai.initialize();
|
|
252
|
-
* const text = await ai.
|
|
201
|
+
* const text = await ai.chat('Hello!');
|
|
253
202
|
* ```
|
|
254
203
|
*
|
|
255
204
|
* @example Streaming
|
|
@@ -260,10 +209,8 @@ declare class KrutAIProvider {
|
|
|
260
209
|
* });
|
|
261
210
|
* await ai.initialize();
|
|
262
211
|
*
|
|
263
|
-
* const
|
|
264
|
-
*
|
|
265
|
-
* process.stdout.write(chunk);
|
|
266
|
-
* }
|
|
212
|
+
* const response = await ai.streamChatResponse([{ role: 'user', content: 'Tell me a story' }]);
|
|
213
|
+
* // Example assumes you handle the SSE stream from the response body
|
|
267
214
|
* ```
|
|
268
215
|
*
|
|
269
216
|
* @packageDocumentation
|
|
@@ -287,7 +234,7 @@ declare class KrutAIProvider {
|
|
|
287
234
|
* });
|
|
288
235
|
*
|
|
289
236
|
* await ai.initialize();
|
|
290
|
-
* const text = await ai.
|
|
237
|
+
* const text = await ai.chat('Hello!');
|
|
291
238
|
* ```
|
|
292
239
|
*/
|
|
293
240
|
declare function krutAI(config: KrutAIProviderConfig & {
|
package/dist/index.js
CHANGED
|
@@ -67,241 +67,6 @@ var KrutAIProvider = class {
|
|
|
67
67
|
// ---------------------------------------------------------------------------
|
|
68
68
|
// Public AI Methods
|
|
69
69
|
// ---------------------------------------------------------------------------
|
|
70
|
-
/**
|
|
71
|
-
* Generate a response for a prompt (non-streaming).
|
|
72
|
-
*
|
|
73
|
-
* Calls: POST {serverUrl}/generate
|
|
74
|
-
* Body: { prompt, model, system?, maxTokens?, temperature? }
|
|
75
|
-
* Expected response: { text: string } or { content: string } or { message: string }
|
|
76
|
-
*
|
|
77
|
-
* @param prompt - The user prompt string
|
|
78
|
-
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
79
|
-
* @returns The assistant's response text
|
|
80
|
-
*/
|
|
81
|
-
async generate(prompt, options = {}) {
|
|
82
|
-
this.assertInitialized();
|
|
83
|
-
const model = options.model ?? this.resolvedModel;
|
|
84
|
-
const response = await fetch(`${this.serverUrl}/generate`, {
|
|
85
|
-
method: "POST",
|
|
86
|
-
headers: this.authHeaders(),
|
|
87
|
-
body: JSON.stringify({
|
|
88
|
-
prompt,
|
|
89
|
-
model,
|
|
90
|
-
...options.system !== void 0 ? { system: options.system } : {},
|
|
91
|
-
...options.images !== void 0 ? { images: options.images } : {},
|
|
92
|
-
...options.documents !== void 0 ? { documents: options.documents } : {},
|
|
93
|
-
...options.pdf !== void 0 ? { pdf: options.pdf } : {},
|
|
94
|
-
...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
|
|
95
|
-
...options.temperature !== void 0 ? { temperature: options.temperature } : {}
|
|
96
|
-
})
|
|
97
|
-
});
|
|
98
|
-
if (!response.ok) {
|
|
99
|
-
let errorMessage = `AI server returned HTTP ${response.status} for /generate`;
|
|
100
|
-
try {
|
|
101
|
-
const errorData = await response.json();
|
|
102
|
-
if (errorData?.error) errorMessage = errorData.error;
|
|
103
|
-
else if (errorData?.message) errorMessage = errorData.message;
|
|
104
|
-
} catch {
|
|
105
|
-
}
|
|
106
|
-
throw new Error(errorMessage);
|
|
107
|
-
}
|
|
108
|
-
const data = await response.json();
|
|
109
|
-
return data.text ?? data.content ?? data.message ?? "";
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Generate a streaming response for a prompt via Server-Sent Events (SSE).
|
|
113
|
-
*
|
|
114
|
-
* Calls: POST {serverUrl}/stream
|
|
115
|
-
* Body: { prompt, model, system?, maxTokens?, temperature? }
|
|
116
|
-
* Expected response: `text/event-stream` with `data: <chunk>` lines.
|
|
117
|
-
*
|
|
118
|
-
* @param prompt - The user prompt string
|
|
119
|
-
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
120
|
-
* @returns An async generator yielding string chunks from the server
|
|
121
|
-
*
|
|
122
|
-
* @example
|
|
123
|
-
* ```typescript
|
|
124
|
-
* const stream = ai.stream('Tell me a story');
|
|
125
|
-
* for await (const chunk of stream) {
|
|
126
|
-
* process.stdout.write(chunk);
|
|
127
|
-
* }
|
|
128
|
-
* ```
|
|
129
|
-
*/
|
|
130
|
-
async *stream(prompt, options = {}) {
|
|
131
|
-
this.assertInitialized();
|
|
132
|
-
const model = options.model ?? this.resolvedModel;
|
|
133
|
-
const response = await fetch(`${this.serverUrl}/stream`, {
|
|
134
|
-
method: "POST",
|
|
135
|
-
headers: {
|
|
136
|
-
...this.authHeaders(),
|
|
137
|
-
Accept: "text/event-stream"
|
|
138
|
-
},
|
|
139
|
-
body: JSON.stringify({
|
|
140
|
-
prompt,
|
|
141
|
-
model,
|
|
142
|
-
...options.system !== void 0 ? { system: options.system } : {},
|
|
143
|
-
...options.images !== void 0 ? { images: options.images } : {},
|
|
144
|
-
...options.documents !== void 0 ? { documents: options.documents } : {},
|
|
145
|
-
...options.pdf !== void 0 ? { pdf: options.pdf } : {},
|
|
146
|
-
...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
|
|
147
|
-
...options.temperature !== void 0 ? { temperature: options.temperature } : {}
|
|
148
|
-
})
|
|
149
|
-
});
|
|
150
|
-
if (!response.ok) {
|
|
151
|
-
let errorMessage = `AI server returned HTTP ${response.status} for /stream`;
|
|
152
|
-
try {
|
|
153
|
-
const errorData = await response.json();
|
|
154
|
-
if (errorData?.error) errorMessage = errorData.error;
|
|
155
|
-
else if (errorData?.message) errorMessage = errorData.message;
|
|
156
|
-
} catch {
|
|
157
|
-
}
|
|
158
|
-
throw new Error(errorMessage);
|
|
159
|
-
}
|
|
160
|
-
if (!response.body) {
|
|
161
|
-
throw new Error("AI server returned no response body for /stream");
|
|
162
|
-
}
|
|
163
|
-
const reader = response.body.getReader();
|
|
164
|
-
const decoder = new TextDecoder();
|
|
165
|
-
let buffer = "";
|
|
166
|
-
try {
|
|
167
|
-
while (true) {
|
|
168
|
-
const { done, value } = await reader.read();
|
|
169
|
-
if (done) break;
|
|
170
|
-
buffer += decoder.decode(value, { stream: true });
|
|
171
|
-
const lines = buffer.split("\n");
|
|
172
|
-
buffer = lines.pop() ?? "";
|
|
173
|
-
for (const line of lines) {
|
|
174
|
-
if (line.startsWith("data: ")) {
|
|
175
|
-
const raw = line.slice(6).trim();
|
|
176
|
-
if (raw === "[DONE]") return;
|
|
177
|
-
try {
|
|
178
|
-
const parsed = JSON.parse(raw);
|
|
179
|
-
const chunk = parsed.text ?? parsed.content ?? parsed.delta?.content ?? "";
|
|
180
|
-
if (chunk) yield chunk;
|
|
181
|
-
} catch {
|
|
182
|
-
if (raw) yield raw;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
} finally {
|
|
188
|
-
reader.releaseLock();
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Similar to stream() but returns the raw fetch Response object.
|
|
193
|
-
* Useful when you want to proxy the Server-Sent Events stream directly to a frontend client
|
|
194
|
-
* (e.g., returning this directly from a Next.js API route).
|
|
195
|
-
*
|
|
196
|
-
* @param prompt - The user prompt string
|
|
197
|
-
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
198
|
-
* @returns A Promise resolving to the native fetch Response
|
|
199
|
-
*/
|
|
200
|
-
async streamResponse(prompt, options = {}) {
|
|
201
|
-
this.assertInitialized();
|
|
202
|
-
const model = options.model ?? this.resolvedModel;
|
|
203
|
-
const response = await fetch(`${this.serverUrl}/stream`, {
|
|
204
|
-
method: "POST",
|
|
205
|
-
headers: {
|
|
206
|
-
...this.authHeaders(),
|
|
207
|
-
Accept: "text/event-stream"
|
|
208
|
-
},
|
|
209
|
-
body: JSON.stringify({
|
|
210
|
-
prompt,
|
|
211
|
-
model,
|
|
212
|
-
...options.system !== void 0 ? { system: options.system } : {},
|
|
213
|
-
...options.images !== void 0 ? { images: options.images } : {},
|
|
214
|
-
...options.documents !== void 0 ? { documents: options.documents } : {},
|
|
215
|
-
...options.pdf !== void 0 ? { pdf: options.pdf } : {},
|
|
216
|
-
...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
|
|
217
|
-
...options.temperature !== void 0 ? { temperature: options.temperature } : {}
|
|
218
|
-
})
|
|
219
|
-
});
|
|
220
|
-
if (!response.ok) {
|
|
221
|
-
let errorMessage = `AI server returned HTTP ${response.status} for /stream`;
|
|
222
|
-
try {
|
|
223
|
-
const errorData = await response.json();
|
|
224
|
-
if (errorData?.error) errorMessage = errorData.error;
|
|
225
|
-
else if (errorData?.message) errorMessage = errorData.message;
|
|
226
|
-
} catch {
|
|
227
|
-
}
|
|
228
|
-
throw new Error(errorMessage);
|
|
229
|
-
}
|
|
230
|
-
console.log(response);
|
|
231
|
-
return response;
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Multi-turn conversation streaming: pass a full message history.
|
|
235
|
-
* Calls POST /stream with the full { messages } payload.
|
|
236
|
-
*
|
|
237
|
-
* @param messages - Full conversation history
|
|
238
|
-
* @param options - Optional overrides (model, maxTokens, temperature)
|
|
239
|
-
* @returns An async generator yielding string chunks from the server
|
|
240
|
-
*/
|
|
241
|
-
async *streamChat(messages, options = {}) {
|
|
242
|
-
this.assertInitialized();
|
|
243
|
-
if (!messages.length) {
|
|
244
|
-
throw new Error("Messages array cannot be empty for streamChat");
|
|
245
|
-
}
|
|
246
|
-
const model = options.model ?? this.resolvedModel;
|
|
247
|
-
const response = await fetch(`${this.serverUrl}/stream`, {
|
|
248
|
-
method: "POST",
|
|
249
|
-
headers: {
|
|
250
|
-
...this.authHeaders(),
|
|
251
|
-
Accept: "text/event-stream"
|
|
252
|
-
},
|
|
253
|
-
body: JSON.stringify({
|
|
254
|
-
messages,
|
|
255
|
-
model,
|
|
256
|
-
...options.system !== void 0 ? { system: options.system } : {},
|
|
257
|
-
...options.images !== void 0 ? { images: options.images } : {},
|
|
258
|
-
...options.documents !== void 0 ? { documents: options.documents } : {},
|
|
259
|
-
...options.pdf !== void 0 ? { pdf: options.pdf } : {},
|
|
260
|
-
...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
|
|
261
|
-
...options.temperature !== void 0 ? { temperature: options.temperature } : {}
|
|
262
|
-
})
|
|
263
|
-
});
|
|
264
|
-
if (!response.ok) {
|
|
265
|
-
let errorMessage = `AI server returned HTTP ${response.status} for /stream`;
|
|
266
|
-
try {
|
|
267
|
-
const errorData = await response.json();
|
|
268
|
-
if (errorData?.error) errorMessage = errorData.error;
|
|
269
|
-
else if (errorData?.message) errorMessage = errorData.message;
|
|
270
|
-
} catch {
|
|
271
|
-
}
|
|
272
|
-
throw new Error(errorMessage);
|
|
273
|
-
}
|
|
274
|
-
if (!response.body) {
|
|
275
|
-
throw new Error("AI server returned no response body for /stream");
|
|
276
|
-
}
|
|
277
|
-
const reader = response.body.getReader();
|
|
278
|
-
const decoder = new TextDecoder();
|
|
279
|
-
let buffer = "";
|
|
280
|
-
try {
|
|
281
|
-
while (true) {
|
|
282
|
-
const { done, value } = await reader.read();
|
|
283
|
-
if (done) break;
|
|
284
|
-
buffer += decoder.decode(value, { stream: true });
|
|
285
|
-
const lines = buffer.split("\n");
|
|
286
|
-
buffer = lines.pop() ?? "";
|
|
287
|
-
for (const line of lines) {
|
|
288
|
-
if (line.startsWith("data: ")) {
|
|
289
|
-
const raw = line.slice(6).trim();
|
|
290
|
-
if (raw === "[DONE]") return;
|
|
291
|
-
try {
|
|
292
|
-
const parsed = JSON.parse(raw);
|
|
293
|
-
const chunk = parsed.text ?? parsed.content ?? parsed.delta?.content ?? "";
|
|
294
|
-
if (chunk) yield chunk;
|
|
295
|
-
} catch {
|
|
296
|
-
if (raw) yield raw;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
} finally {
|
|
302
|
-
reader.releaseLock();
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
70
|
/**
|
|
306
71
|
* Similar to streamChat() but returns the raw fetch Response object.
|
|
307
72
|
* Useful for proxying the Server-Sent Events stream directly to a frontend client.
|
|
@@ -346,25 +111,26 @@ var KrutAIProvider = class {
|
|
|
346
111
|
return response;
|
|
347
112
|
}
|
|
348
113
|
/**
|
|
349
|
-
*
|
|
114
|
+
* Generate a response for a prompt (non-streaming).
|
|
350
115
|
*
|
|
351
|
-
* Calls: POST {serverUrl}/
|
|
352
|
-
* Body: {
|
|
116
|
+
* Calls: POST {serverUrl}/generate
|
|
117
|
+
* Body: { prompt, model, system?, maxTokens?, temperature? }
|
|
353
118
|
* Expected response: { text: string } or { content: string } or { message: string }
|
|
354
119
|
*
|
|
355
|
-
* @param
|
|
356
|
-
* @param options - Optional overrides (model, maxTokens, temperature)
|
|
120
|
+
* @param prompt - The user prompt string
|
|
121
|
+
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
357
122
|
* @returns The assistant's response text
|
|
358
123
|
*/
|
|
359
|
-
async chat(
|
|
124
|
+
async chat(prompt, options = {}) {
|
|
360
125
|
this.assertInitialized();
|
|
361
126
|
const model = options.model ?? this.resolvedModel;
|
|
362
|
-
const response = await fetch(`${this.serverUrl}/
|
|
127
|
+
const response = await fetch(`${this.serverUrl}/generate`, {
|
|
363
128
|
method: "POST",
|
|
364
129
|
headers: this.authHeaders(),
|
|
365
130
|
body: JSON.stringify({
|
|
366
|
-
|
|
131
|
+
prompt,
|
|
367
132
|
model,
|
|
133
|
+
...options.system !== void 0 ? { system: options.system } : {},
|
|
368
134
|
...options.images !== void 0 ? { images: options.images } : {},
|
|
369
135
|
...options.documents !== void 0 ? { documents: options.documents } : {},
|
|
370
136
|
...options.pdf !== void 0 ? { pdf: options.pdf } : {},
|
|
@@ -373,7 +139,7 @@ var KrutAIProvider = class {
|
|
|
373
139
|
})
|
|
374
140
|
});
|
|
375
141
|
if (!response.ok) {
|
|
376
|
-
let errorMessage = `AI server returned HTTP ${response.status} for /
|
|
142
|
+
let errorMessage = `AI server returned HTTP ${response.status} for /generate`;
|
|
377
143
|
try {
|
|
378
144
|
const errorData = await response.json();
|
|
379
145
|
if (errorData?.error) errorMessage = errorData.error;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/client.ts","../src/index.ts"],"names":["validateApiKeyFormat","validateApiKey"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Types for @krutai/ai-provider\n */\n\n/**\n * Default model identifier sent to the LangChain server when no model is specified.\n * Your server can use this value to route to its own default model.\n */\nexport const DEFAULT_MODEL = 'default' as const;\n\n/**\n * Default base URL for the LangChain backend server.\n * Used when no serverUrl is provided in the config.\n */\nexport const DEFAULT_SERVER_URL = 'http://localhost:8000' as const;\n\n/**\n * Configuration options for KrutAIProvider\n */\nexport interface KrutAIProviderConfig {\n /**\n * KrutAI API key.\n * Validated against the LangChain server before use.\n * Optional: defaults to process.env.KRUTAI_API_KEY\n */\n apiKey?: string;\n\n /**\n * Base URL of your deployed LangChain backend server.\n * @default \"http://localhost:8000\"\n * @example \"https://ai.krut.ai\"\n */\n serverUrl?: string;\n\n /**\n * The AI model to use (passed to the server).\n * The server decides what to do with this value.\n * @default \"default\"\n */\n model?: string;\n\n /**\n * Whether to validate the API key against the server on initialization.\n * Set to false to skip the validation round-trip (e.g. in tests).\n * @default true\n */\n validateOnInit?: boolean;\n}\n\n/**\n * A part of a multimodal message\n */\nexport interface TextContentPart {\n type: 'text';\n text: string;\n}\n\nexport interface ImageContentPart {\n type: 'image_url';\n image_url: {\n url: string; // Base64 data URI or HTTP(S) URL\n detail?: 'low' | 'high' | 'auto';\n };\n}\n\nexport type ContentPart = TextContentPart | ImageContentPart;\nexport type MessageContent = string | ContentPart[];\n\n/**\n * A single chat message\n */\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system';\n content: MessageContent;\n}\n\n/**\n * Options for a single generate / stream / chat call\n */\nexport interface GenerateOptions {\n /**\n * Override the model for this specific call.\n */\n model?: string;\n\n /**\n * System prompt (prepended as a system message).\n */\n system?: string;\n\n /**\n * Maximum tokens to generate.\n */\n maxTokens?: number;\n\n /**\n * Temperature (0–2).\n */\n temperature?: number;\n\n /**\n * Array of image URLs or base64 data URIs to include with the request.\n */\n images?: string[];\n\n /**\n * Array of document URLs or base64 data URIs (e.g. PDFs) to include with the request.\n */\n documents?: string[];\n\n /**\n * Array of PDF URLs or base64 data URIs to include with the request.\n */\n pdf?: string[];\n}\n","import type { KrutAIProviderConfig, GenerateOptions, ChatMessage } from './types';\nimport { DEFAULT_MODEL, DEFAULT_SERVER_URL } from './types';\nimport {\n validateApiKeyWithService as validateApiKey,\n validateApiKeyFormat,\n ApiKeyValidationError as KrutAIKeyValidationError,\n} from 'krutai';\n\nexport { KrutAIKeyValidationError };\n\n/**\n * KrutAIProvider — fetch-based AI provider for KrutAI\n *\n * Calls your deployed LangChain backend server for all AI operations.\n * The API key is validated against the server before use.\n *\n * @example\n * ```typescript\n * import { KrutAIProvider } from '@krutai/ai-provider';\n *\n * // Using local dev server (http://localhost:8000 by default)\n * const ai = new KrutAIProvider({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * });\n *\n * // Or point to a production server\n * const aiProd = new KrutAIProvider({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://ai.krut.ai',\n * });\n *\n * await ai.initialize(); // validates key against server\n *\n * const text = await ai.generate('Tell me a joke');\n * console.log(text);\n * ```\n */\nexport class KrutAIProvider {\n private readonly apiKey: string;\n private readonly serverUrl: string;\n private readonly resolvedModel: string;\n private readonly config: KrutAIProviderConfig;\n\n private initialized = false;\n\n constructor(config: KrutAIProviderConfig) {\n this.config = config;\n this.apiKey = config.apiKey || process.env.KRUTAI_API_KEY || '';\n this.serverUrl = (config.serverUrl ?? DEFAULT_SERVER_URL).replace(/\\/$/, ''); // strip trailing slash\n this.resolvedModel = config.model ?? DEFAULT_MODEL;\n\n // Basic format check immediately on construction\n validateApiKeyFormat(this.apiKey);\n\n // If validation is disabled, mark as ready immediately\n if (config.validateOnInit === false) {\n this.initialized = true;\n }\n }\n\n /**\n * Initialize the provider.\n * Validates the API key against the LangChain server, then marks provider as ready.\n *\n * @throws {KrutAIKeyValidationError} if the key is rejected or the server is unreachable\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n if (this.config.validateOnInit !== false) {\n await validateApiKey(this.apiKey, this.serverUrl);\n }\n\n this.initialized = true;\n }\n\n /**\n * Returns the currently configured default model.\n */\n getModel(): string {\n return this.resolvedModel;\n }\n\n /**\n * Returns whether the provider has been initialized.\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private assertInitialized(): void {\n if (!this.initialized) {\n throw new Error(\n 'KrutAIProvider not initialized. Call initialize() first or set validateOnInit to false.'\n );\n }\n }\n\n /** Common request headers sent to the server on every AI call. */\n private authHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n 'x-api-key': this.apiKey,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Public AI Methods\n // ---------------------------------------------------------------------------\n\n /**\n * Generate a response for a prompt (non-streaming).\n *\n * Calls: POST {serverUrl}/generate\n * Body: { prompt, model, system?, maxTokens?, temperature? }\n * Expected response: { text: string } or { content: string } or { message: string }\n *\n * @param prompt - The user prompt string\n * @param options - Optional overrides (model, system, maxTokens, temperature)\n * @returns The assistant's response text\n */\n async generate(prompt: string, options: GenerateOptions = {}): Promise<string> {\n this.assertInitialized();\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/generate`, {\n method: 'POST',\n headers: this.authHeaders(),\n body: JSON.stringify({\n prompt,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /generate`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n const data = (await response.json()) as {\n text?: string;\n content?: string;\n message?: string;\n };\n\n return data.text ?? data.content ?? data.message ?? '';\n }\n\n /**\n * Generate a streaming response for a prompt via Server-Sent Events (SSE).\n *\n * Calls: POST {serverUrl}/stream\n * Body: { prompt, model, system?, maxTokens?, temperature? }\n * Expected response: `text/event-stream` with `data: <chunk>` lines.\n *\n * @param prompt - The user prompt string\n * @param options - Optional overrides (model, system, maxTokens, temperature)\n * @returns An async generator yielding string chunks from the server\n *\n * @example\n * ```typescript\n * const stream = ai.stream('Tell me a story');\n * for await (const chunk of stream) {\n * process.stdout.write(chunk);\n * }\n * ```\n */\n async *stream(prompt: string, options: GenerateOptions = {}): AsyncGenerator<string> {\n this.assertInitialized();\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/stream`, {\n method: 'POST',\n headers: {\n ...this.authHeaders(),\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({\n prompt,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /stream`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n if (!response.body) {\n throw new Error('AI server returned no response body for /stream');\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n // Keep the last (potentially incomplete) line in the buffer\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const raw = line.slice(6).trim();\n if (raw === '[DONE]') return;\n try {\n const parsed = JSON.parse(raw) as {\n text?: string;\n content?: string;\n delta?: { content?: string };\n };\n const chunk =\n parsed.text ??\n parsed.content ??\n parsed.delta?.content ??\n '';\n if (chunk) yield chunk;\n } catch {\n // raw string chunk (non-JSON SSE)\n if (raw) yield raw;\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * Similar to stream() but returns the raw fetch Response object.\n * Useful when you want to proxy the Server-Sent Events stream directly to a frontend client\n * (e.g., returning this directly from a Next.js API route).\n *\n * @param prompt - The user prompt string\n * @param options - Optional overrides (model, system, maxTokens, temperature)\n * @returns A Promise resolving to the native fetch Response\n */\n async streamResponse(prompt: string, options: GenerateOptions = {}): Promise<Response> {\n this.assertInitialized();\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/stream`, {\n method: 'POST',\n headers: {\n ...this.authHeaders(),\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({\n prompt,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /stream`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n console.log(response)\n return response;\n }\n\n /**\n * Multi-turn conversation streaming: pass a full message history.\n * Calls POST /stream with the full { messages } payload.\n *\n * @param messages - Full conversation history\n * @param options - Optional overrides (model, maxTokens, temperature)\n * @returns An async generator yielding string chunks from the server\n */\n async *streamChat(messages: ChatMessage[], options: GenerateOptions = {}): AsyncGenerator<string> {\n this.assertInitialized();\n\n if (!messages.length) {\n throw new Error('Messages array cannot be empty for streamChat');\n }\n\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/stream`, {\n method: 'POST',\n headers: {\n ...this.authHeaders(),\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({\n messages,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /stream`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n if (!response.body) {\n throw new Error('AI server returned no response body for /stream');\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const raw = line.slice(6).trim();\n if (raw === '[DONE]') return;\n try {\n const parsed = JSON.parse(raw) as {\n text?: string;\n content?: string;\n delta?: { content?: string };\n };\n const chunk =\n parsed.text ??\n parsed.content ??\n parsed.delta?.content ??\n '';\n if (chunk) yield chunk;\n } catch {\n if (raw) yield raw;\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * Similar to streamChat() but returns the raw fetch Response object.\n * Useful for proxying the Server-Sent Events stream directly to a frontend client.\n *\n * @param messages - Full conversation history\n * @param options - Optional overrides (model, maxTokens, temperature)\n * @returns A Promise resolving to the native fetch Response\n */\n async streamChatResponse(messages: ChatMessage[], options: GenerateOptions = {}): Promise<Response> {\n this.assertInitialized();\n\n if (!messages.length) {\n throw new Error('Messages array cannot be empty for streamChatResponse');\n }\n\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/stream`, {\n method: 'POST',\n headers: {\n ...this.authHeaders(),\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({\n messages,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /stream`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n return response;\n }\n\n /**\n * Multi-turn conversation: pass a full message history.\n *\n * Calls: POST {serverUrl}/chat\n * Body: { messages, model, maxTokens?, temperature? }\n * Expected response: { text: string } or { content: string } or { message: string }\n *\n * @param messages - Full conversation history\n * @param options - Optional overrides (model, maxTokens, temperature)\n * @returns The assistant's response text\n */\n async chat(messages: ChatMessage[], options: GenerateOptions = {}): Promise<string> {\n this.assertInitialized();\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/chat`, {\n method: 'POST',\n headers: this.authHeaders(),\n body: JSON.stringify({\n messages,\n model,\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /chat`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n const data = (await response.json()) as {\n text?: string;\n content?: string;\n message?: string;\n };\n\n return data.text ?? data.content ?? data.message ?? '';\n }\n}\n","/**\n * @krutai/ai-provider — AI Provider package for KrutAI\n *\n * A fetch-based wrapper that calls your deployed LangChain backend server.\n * The user's API key is validated against the server before any AI call is made.\n *\n * @example Basic usage\n * ```typescript\n * import { krutAI } from '@krutai/ai-provider';\n *\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * });\n *\n * await ai.initialize(); // validates key with server\n *\n * const text = await ai.generate('Write a poem about TypeScript');\n * console.log(text);\n * ```\n *\n * @example With custom model\n * ```typescript\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * model: 'gpt-4o',\n * });\n * await ai.initialize();\n * const text = await ai.generate('Hello!');\n * ```\n *\n * @example Streaming\n * ```typescript\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * });\n * await ai.initialize();\n *\n * const stream = ai.stream('Tell me a story');\n * for await (const chunk of stream) {\n * process.stdout.write(chunk);\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { KrutAIProviderConfig } from './types';\nimport { DEFAULT_MODEL } from './types';\nimport { KrutAIProvider } from './client';\n\nexport { KrutAIProvider } from './client';\nexport { KrutAIKeyValidationError } from './client';\nexport {\n validateApiKeyWithService as validateApiKey,\n validateApiKeyFormat,\n} from 'krutai';\nexport type { KrutAIProviderConfig, GenerateOptions, ChatMessage } from './types';\nexport { DEFAULT_MODEL } from './types';\n\n/**\n * krutAI — convenience factory (mirrors `krutAuth` in @krutai/auth).\n *\n * Creates a `KrutAIProvider` instance configured to call your LangChain server.\n *\n * @param config - Provider configuration (`apiKey` and `serverUrl` are required)\n * @returns A `KrutAIProvider` instance — call `.initialize()` before use\n *\n * @example\n * ```typescript\n * import { krutAI } from '@krutai/ai-provider';\n *\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * });\n *\n * await ai.initialize();\n * const text = await ai.generate('Hello!');\n * ```\n */\nexport function krutAI(\n config: KrutAIProviderConfig & { model?: string }\n): KrutAIProvider {\n return new KrutAIProvider({\n model: DEFAULT_MODEL,\n ...config,\n });\n}\n\n// Package metadata\nexport const VERSION = '0.2.0';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/client.ts","../src/index.ts"],"names":["validateApiKeyFormat","validateApiKey"],"mappings":";;;;;AAQO,IAAM,aAAA,GAAgB;AAMtB,IAAM,kBAAA,GAAqB,uBAAA;ACuB3B,IAAM,iBAAN,MAAqB;AAAA,EACP,MAAA;AAAA,EACA,SAAA;AAAA,EACA,aAAA;AAAA,EACA,MAAA;AAAA,EAET,WAAA,GAAc,KAAA;AAAA,EAEtB,YAAY,MAAA,EAA8B;AACtC,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA,CAAO,MAAA,IAAU,OAAA,CAAQ,IAAI,cAAA,IAAkB,EAAA;AAC7D,IAAA,IAAA,CAAK,aAAa,MAAA,CAAO,SAAA,IAAa,kBAAA,EAAoB,OAAA,CAAQ,OAAO,EAAE,CAAA;AAC3E,IAAA,IAAA,CAAK,aAAA,GAAgB,OAAO,KAAA,IAAS,aAAA;AAGrC,IAAAA,2BAAA,CAAqB,KAAK,MAAM,CAAA;AAGhC,IAAA,IAAI,MAAA,CAAO,mBAAmB,KAAA,EAAO;AACjC,MAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAAA,IACvB;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,UAAA,GAA4B;AAC9B,IAAA,IAAI,KAAK,WAAA,EAAa;AAEtB,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,cAAA,KAAmB,KAAA,EAAO;AACtC,MAAA,MAAMC,gCAAA,CAAe,IAAA,CAAK,MAAA,EAAQ,IAAA,CAAK,SAAS,CAAA;AAAA,IACpD;AAEA,IAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAA,GAAmB;AACf,IAAA,OAAO,IAAA,CAAK,aAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,aAAA,GAAyB;AACrB,IAAA,OAAO,IAAA,CAAK,WAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAA,GAA0B;AAC9B,IAAA,IAAI,CAAC,KAAK,WAAA,EAAa;AACnB,MAAA,MAAM,IAAI,KAAA;AAAA,QACN;AAAA,OACJ;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA,EAGQ,WAAA,GAAsC;AAC1C,IAAA,OAAO;AAAA,MACH,cAAA,EAAgB,kBAAA;AAAA,MAChB,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,MACpC,aAAa,IAAA,CAAK;AAAA,KACtB;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,kBAAA,CAAmB,QAAA,EAAyB,OAAA,GAA2B,EAAC,EAAsB;AAChG,IAAA,IAAA,CAAK,iBAAA,EAAkB;AAEvB,IAAA,IAAI,CAAC,SAAS,MAAA,EAAQ;AAClB,MAAA,MAAM,IAAI,MAAM,uDAAuD,CAAA;AAAA,IAC3E;AAEA,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,IAAS,IAAA,CAAK,aAAA;AAEpC,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,SAAS,CAAA,OAAA,CAAA,EAAW;AAAA,MACrD,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,GAAG,KAAK,WAAA,EAAY;AAAA,QACpB,MAAA,EAAQ;AAAA,OACZ;AAAA,MACA,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,QACjB,QAAA;AAAA,QACA,KAAA;AAAA,QACA,GAAI,QAAQ,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAO,GAAI,EAAC;AAAA,QACjE,GAAI,QAAQ,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAO,GAAI,EAAC;AAAA,QACjE,GAAI,QAAQ,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,EAAW,OAAA,CAAQ,SAAA,EAAU,GAAI,EAAC;AAAA,QAC1E,GAAI,QAAQ,GAAA,KAAQ,MAAA,GAAY,EAAE,GAAA,EAAK,OAAA,CAAQ,GAAA,EAAI,GAAI,EAAC;AAAA,QACxD,GAAI,QAAQ,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,EAAW,OAAA,CAAQ,SAAA,EAAU,GAAI,EAAC;AAAA,QAC1E,GAAI,QAAQ,WAAA,KAAgB,MAAA,GAAY,EAAE,WAAA,EAAa,OAAA,CAAQ,WAAA,EAAY,GAAI;AAAC,OACnF;AAAA,KACJ,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AACd,MAAA,IAAI,YAAA,GAAe,CAAA,wBAAA,EAA2B,QAAA,CAAS,MAAM,CAAA,YAAA,CAAA;AAC7D,MAAA,IAAI;AACA,QAAA,MAAM,SAAA,GAAa,MAAM,QAAA,CAAS,IAAA,EAAK;AACvC,QAAA,IAAI,SAAA,EAAW,KAAA,EAAO,YAAA,GAAe,SAAA,CAAU,KAAA;AAAA,aAAA,IACtC,SAAA,EAAW,OAAA,EAAS,YAAA,GAAe,SAAA,CAAU,OAAA;AAAA,MAC1D,CAAA,CAAA,MAAQ;AAAA,MAAE;AACV,MAAA,MAAM,IAAI,MAAM,YAAY,CAAA;AAAA,IAChC;AAEA,IAAA,OAAO,QAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,IAAA,CAAK,MAAA,EAAgB,OAAA,GAA2B,EAAC,EAAoB;AACvE,IAAA,IAAA,CAAK,iBAAA,EAAkB;AACvB,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,IAAS,IAAA,CAAK,aAAA;AAEpC,IAAA,MAAM,WAAW,MAAM,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,SAAS,CAAA,SAAA,CAAA,EAAa;AAAA,MACvD,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,KAAK,WAAA,EAAY;AAAA,MAC1B,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,QACjB,MAAA;AAAA,QACA,KAAA;AAAA,QACA,GAAI,QAAQ,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAO,GAAI,EAAC;AAAA,QACjE,GAAI,QAAQ,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAO,GAAI,EAAC;AAAA,QACjE,GAAI,QAAQ,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,EAAW,OAAA,CAAQ,SAAA,EAAU,GAAI,EAAC;AAAA,QAC1E,GAAI,QAAQ,GAAA,KAAQ,MAAA,GAAY,EAAE,GAAA,EAAK,OAAA,CAAQ,GAAA,EAAI,GAAI,EAAC;AAAA,QACxD,GAAI,QAAQ,SAAA,KAAc,MAAA,GAAY,EAAE,SAAA,EAAW,OAAA,CAAQ,SAAA,EAAU,GAAI,EAAC;AAAA,QAC1E,GAAI,QAAQ,WAAA,KAAgB,MAAA,GAAY,EAAE,WAAA,EAAa,OAAA,CAAQ,WAAA,EAAY,GAAI;AAAC,OACnF;AAAA,KACJ,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AACd,MAAA,IAAI,YAAA,GAAe,CAAA,wBAAA,EAA2B,QAAA,CAAS,MAAM,CAAA,cAAA,CAAA;AAC7D,MAAA,IAAI;AACA,QAAA,MAAM,SAAA,GAAa,MAAM,QAAA,CAAS,IAAA,EAAK;AACvC,QAAA,IAAI,SAAA,EAAW,KAAA,EAAO,YAAA,GAAe,SAAA,CAAU,KAAA;AAAA,aAAA,IACtC,SAAA,EAAW,OAAA,EAAS,YAAA,GAAe,SAAA,CAAU,OAAA;AAAA,MAC1D,CAAA,CAAA,MAAQ;AAAA,MAAE;AACV,MAAA,MAAM,IAAI,MAAM,YAAY,CAAA;AAAA,IAChC;AAEA,IAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAMlC,IAAA,OAAO,IAAA,CAAK,IAAA,IAAQ,IAAA,CAAK,OAAA,IAAW,KAAK,OAAA,IAAW,EAAA;AAAA,EACxD;AACJ;AClIO,SAAS,OACZ,MAAA,EACc;AACd,EAAA,OAAO,IAAI,cAAA,CAAe;AAAA,IACtB,KAAA,EAAO,aAAA;AAAA,IACP,GAAG;AAAA,GACN,CAAA;AACL;AAGO,IAAM,OAAA,GAAU","file":"index.js","sourcesContent":["/**\n * Types for @krutai/ai-provider\n */\n\n/**\n * Default model identifier sent to the LangChain server when no model is specified.\n * Your server can use this value to route to its own default model.\n */\nexport const DEFAULT_MODEL = 'default' as const;\n\n/**\n * Default base URL for the LangChain backend server.\n * Used when no serverUrl is provided in the config.\n */\nexport const DEFAULT_SERVER_URL = 'http://localhost:8000' as const;\n\n/**\n * Configuration options for KrutAIProvider\n */\nexport interface KrutAIProviderConfig {\n /**\n * KrutAI API key.\n * Validated against the LangChain server before use.\n * Optional: defaults to process.env.KRUTAI_API_KEY\n */\n apiKey?: string;\n\n /**\n * Base URL of your deployed LangChain backend server.\n * @default \"http://localhost:8000\"\n * @example \"https://ai.krut.ai\"\n */\n serverUrl?: string;\n\n /**\n * The AI model to use (passed to the server).\n * The server decides what to do with this value.\n * @default \"default\"\n */\n model?: string;\n\n /**\n * Whether to validate the API key against the server on initialization.\n * Set to false to skip the validation round-trip (e.g. in tests).\n * @default true\n */\n validateOnInit?: boolean;\n}\n\n/**\n * A part of a multimodal message\n */\nexport interface TextContentPart {\n type: 'text';\n text: string;\n}\n\nexport interface ImageContentPart {\n type: 'image_url';\n image_url: {\n url: string; // Base64 data URI or HTTP(S) URL\n detail?: 'low' | 'high' | 'auto';\n };\n}\n\nexport type ContentPart = TextContentPart | ImageContentPart;\nexport type MessageContent = string | ContentPart[];\n\n/**\n * A single chat message\n */\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system';\n content: MessageContent;\n}\n\n/**\n * Options for a single generate / stream / chat call\n */\nexport interface GenerateOptions {\n /**\n * Override the model for this specific call.\n */\n model?: string;\n\n /**\n * System prompt (prepended as a system message).\n */\n system?: string;\n\n /**\n * Maximum tokens to generate.\n */\n maxTokens?: number;\n\n /**\n * Temperature (0–2).\n */\n temperature?: number;\n\n /**\n * Array of image URLs or base64 data URIs to include with the request.\n */\n images?: string[];\n\n /**\n * Array of document URLs or base64 data URIs (e.g. PDFs) to include with the request.\n */\n documents?: string[];\n\n /**\n * Array of PDF URLs or base64 data URIs to include with the request.\n */\n pdf?: string[];\n}\n","import type { KrutAIProviderConfig, GenerateOptions, ChatMessage } from './types';\nimport { DEFAULT_MODEL, DEFAULT_SERVER_URL } from './types';\nimport {\n validateApiKeyWithService as validateApiKey,\n validateApiKeyFormat,\n ApiKeyValidationError as KrutAIKeyValidationError,\n} from 'krutai';\n\nexport { KrutAIKeyValidationError };\n\n/**\n * KrutAIProvider — fetch-based AI provider for KrutAI\n *\n * Calls your deployed LangChain backend server for all AI operations.\n * The API key is validated against the server before use.\n *\n * @example\n * ```typescript\n * import { KrutAIProvider } from '@krutai/ai-provider';\n *\n * // Using local dev server (http://localhost:8000 by default)\n * const ai = new KrutAIProvider({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * });\n *\n * // Or point to a production server\n * const aiProd = new KrutAIProvider({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://ai.krut.ai',\n * });\n *\n * await ai.initialize(); // validates key against server\n *\n * const text = await ai.generate('Tell me a joke');\n * console.log(text);\n * ```\n */\nexport class KrutAIProvider {\n private readonly apiKey: string;\n private readonly serverUrl: string;\n private readonly resolvedModel: string;\n private readonly config: KrutAIProviderConfig;\n\n private initialized = false;\n\n constructor(config: KrutAIProviderConfig) {\n this.config = config;\n this.apiKey = config.apiKey || process.env.KRUTAI_API_KEY || '';\n this.serverUrl = (config.serverUrl ?? DEFAULT_SERVER_URL).replace(/\\/$/, ''); // strip trailing slash\n this.resolvedModel = config.model ?? DEFAULT_MODEL;\n\n // Basic format check immediately on construction\n validateApiKeyFormat(this.apiKey);\n\n // If validation is disabled, mark as ready immediately\n if (config.validateOnInit === false) {\n this.initialized = true;\n }\n }\n\n /**\n * Initialize the provider.\n * Validates the API key against the LangChain server, then marks provider as ready.\n *\n * @throws {KrutAIKeyValidationError} if the key is rejected or the server is unreachable\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n if (this.config.validateOnInit !== false) {\n await validateApiKey(this.apiKey, this.serverUrl);\n }\n\n this.initialized = true;\n }\n\n /**\n * Returns the currently configured default model.\n */\n getModel(): string {\n return this.resolvedModel;\n }\n\n /**\n * Returns whether the provider has been initialized.\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private assertInitialized(): void {\n if (!this.initialized) {\n throw new Error(\n 'KrutAIProvider not initialized. Call initialize() first or set validateOnInit to false.'\n );\n }\n }\n\n /** Common request headers sent to the server on every AI call. */\n private authHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n 'x-api-key': this.apiKey,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Public AI Methods\n // ---------------------------------------------------------------------------\n\n /**\n * Similar to streamChat() but returns the raw fetch Response object.\n * Useful for proxying the Server-Sent Events stream directly to a frontend client.\n *\n * @param messages - Full conversation history\n * @param options - Optional overrides (model, maxTokens, temperature)\n * @returns A Promise resolving to the native fetch Response\n */\n async streamChatResponse(messages: ChatMessage[], options: GenerateOptions = {}): Promise<Response> {\n this.assertInitialized();\n\n if (!messages.length) {\n throw new Error('Messages array cannot be empty for streamChatResponse');\n }\n\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/stream`, {\n method: 'POST',\n headers: {\n ...this.authHeaders(),\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({\n messages,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /stream`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n return response;\n }\n\n /**\n * Generate a response for a prompt (non-streaming).\n *\n * Calls: POST {serverUrl}/generate\n * Body: { prompt, model, system?, maxTokens?, temperature? }\n * Expected response: { text: string } or { content: string } or { message: string }\n *\n * @param prompt - The user prompt string\n * @param options - Optional overrides (model, system, maxTokens, temperature)\n * @returns The assistant's response text\n */\n async chat(prompt: string, options: GenerateOptions = {}): Promise<string> {\n this.assertInitialized();\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/generate`, {\n method: 'POST',\n headers: this.authHeaders(),\n body: JSON.stringify({\n prompt,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /generate`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n const data = (await response.json()) as {\n text?: string;\n content?: string;\n message?: string;\n };\n\n return data.text ?? data.content ?? data.message ?? '';\n }\n}\n","/**\n * @krutai/ai-provider — AI Provider package for KrutAI\n *\n * A fetch-based wrapper that calls your deployed LangChain backend server.\n * The user's API key is validated against the server before any AI call is made.\n *\n * @example Basic usage\n * ```typescript\n * import { krutAI } from '@krutai/ai-provider';\n *\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * });\n *\n * await ai.initialize(); // validates key with server\n *\n * const text = await ai.chat('Write a poem about TypeScript');\n * console.log(text);\n * ```\n *\n * @example With custom model\n * ```typescript\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * model: 'gpt-4o',\n * });\n * await ai.initialize();\n * const text = await ai.chat('Hello!');\n * ```\n *\n * @example Streaming\n * ```typescript\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * });\n * await ai.initialize();\n *\n * const response = await ai.streamChatResponse([{ role: 'user', content: 'Tell me a story' }]);\n * // Example assumes you handle the SSE stream from the response body\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { KrutAIProviderConfig } from './types';\nimport { DEFAULT_MODEL } from './types';\nimport { KrutAIProvider } from './client';\n\nexport { KrutAIProvider } from './client';\nexport { KrutAIKeyValidationError } from './client';\nexport {\n validateApiKeyWithService as validateApiKey,\n validateApiKeyFormat,\n} from 'krutai';\nexport type { KrutAIProviderConfig, GenerateOptions, ChatMessage } from './types';\nexport { DEFAULT_MODEL } from './types';\n\n/**\n * krutAI — convenience factory (mirrors `krutAuth` in @krutai/auth).\n *\n * Creates a `KrutAIProvider` instance configured to call your LangChain server.\n *\n * @param config - Provider configuration (`apiKey` and `serverUrl` are required)\n * @returns A `KrutAIProvider` instance — call `.initialize()` before use\n *\n * @example\n * ```typescript\n * import { krutAI } from '@krutai/ai-provider';\n *\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * });\n *\n * await ai.initialize();\n * const text = await ai.chat('Hello!');\n * ```\n */\nexport function krutAI(\n config: KrutAIProviderConfig & { model?: string }\n): KrutAIProvider {\n return new KrutAIProvider({\n model: DEFAULT_MODEL,\n ...config,\n });\n}\n\n// Package metadata\nexport const VERSION = '0.2.0';\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -66,241 +66,6 @@ var KrutAIProvider = class {
|
|
|
66
66
|
// ---------------------------------------------------------------------------
|
|
67
67
|
// Public AI Methods
|
|
68
68
|
// ---------------------------------------------------------------------------
|
|
69
|
-
/**
|
|
70
|
-
* Generate a response for a prompt (non-streaming).
|
|
71
|
-
*
|
|
72
|
-
* Calls: POST {serverUrl}/generate
|
|
73
|
-
* Body: { prompt, model, system?, maxTokens?, temperature? }
|
|
74
|
-
* Expected response: { text: string } or { content: string } or { message: string }
|
|
75
|
-
*
|
|
76
|
-
* @param prompt - The user prompt string
|
|
77
|
-
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
78
|
-
* @returns The assistant's response text
|
|
79
|
-
*/
|
|
80
|
-
async generate(prompt, options = {}) {
|
|
81
|
-
this.assertInitialized();
|
|
82
|
-
const model = options.model ?? this.resolvedModel;
|
|
83
|
-
const response = await fetch(`${this.serverUrl}/generate`, {
|
|
84
|
-
method: "POST",
|
|
85
|
-
headers: this.authHeaders(),
|
|
86
|
-
body: JSON.stringify({
|
|
87
|
-
prompt,
|
|
88
|
-
model,
|
|
89
|
-
...options.system !== void 0 ? { system: options.system } : {},
|
|
90
|
-
...options.images !== void 0 ? { images: options.images } : {},
|
|
91
|
-
...options.documents !== void 0 ? { documents: options.documents } : {},
|
|
92
|
-
...options.pdf !== void 0 ? { pdf: options.pdf } : {},
|
|
93
|
-
...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
|
|
94
|
-
...options.temperature !== void 0 ? { temperature: options.temperature } : {}
|
|
95
|
-
})
|
|
96
|
-
});
|
|
97
|
-
if (!response.ok) {
|
|
98
|
-
let errorMessage = `AI server returned HTTP ${response.status} for /generate`;
|
|
99
|
-
try {
|
|
100
|
-
const errorData = await response.json();
|
|
101
|
-
if (errorData?.error) errorMessage = errorData.error;
|
|
102
|
-
else if (errorData?.message) errorMessage = errorData.message;
|
|
103
|
-
} catch {
|
|
104
|
-
}
|
|
105
|
-
throw new Error(errorMessage);
|
|
106
|
-
}
|
|
107
|
-
const data = await response.json();
|
|
108
|
-
return data.text ?? data.content ?? data.message ?? "";
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Generate a streaming response for a prompt via Server-Sent Events (SSE).
|
|
112
|
-
*
|
|
113
|
-
* Calls: POST {serverUrl}/stream
|
|
114
|
-
* Body: { prompt, model, system?, maxTokens?, temperature? }
|
|
115
|
-
* Expected response: `text/event-stream` with `data: <chunk>` lines.
|
|
116
|
-
*
|
|
117
|
-
* @param prompt - The user prompt string
|
|
118
|
-
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
119
|
-
* @returns An async generator yielding string chunks from the server
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* ```typescript
|
|
123
|
-
* const stream = ai.stream('Tell me a story');
|
|
124
|
-
* for await (const chunk of stream) {
|
|
125
|
-
* process.stdout.write(chunk);
|
|
126
|
-
* }
|
|
127
|
-
* ```
|
|
128
|
-
*/
|
|
129
|
-
async *stream(prompt, options = {}) {
|
|
130
|
-
this.assertInitialized();
|
|
131
|
-
const model = options.model ?? this.resolvedModel;
|
|
132
|
-
const response = await fetch(`${this.serverUrl}/stream`, {
|
|
133
|
-
method: "POST",
|
|
134
|
-
headers: {
|
|
135
|
-
...this.authHeaders(),
|
|
136
|
-
Accept: "text/event-stream"
|
|
137
|
-
},
|
|
138
|
-
body: JSON.stringify({
|
|
139
|
-
prompt,
|
|
140
|
-
model,
|
|
141
|
-
...options.system !== void 0 ? { system: options.system } : {},
|
|
142
|
-
...options.images !== void 0 ? { images: options.images } : {},
|
|
143
|
-
...options.documents !== void 0 ? { documents: options.documents } : {},
|
|
144
|
-
...options.pdf !== void 0 ? { pdf: options.pdf } : {},
|
|
145
|
-
...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
|
|
146
|
-
...options.temperature !== void 0 ? { temperature: options.temperature } : {}
|
|
147
|
-
})
|
|
148
|
-
});
|
|
149
|
-
if (!response.ok) {
|
|
150
|
-
let errorMessage = `AI server returned HTTP ${response.status} for /stream`;
|
|
151
|
-
try {
|
|
152
|
-
const errorData = await response.json();
|
|
153
|
-
if (errorData?.error) errorMessage = errorData.error;
|
|
154
|
-
else if (errorData?.message) errorMessage = errorData.message;
|
|
155
|
-
} catch {
|
|
156
|
-
}
|
|
157
|
-
throw new Error(errorMessage);
|
|
158
|
-
}
|
|
159
|
-
if (!response.body) {
|
|
160
|
-
throw new Error("AI server returned no response body for /stream");
|
|
161
|
-
}
|
|
162
|
-
const reader = response.body.getReader();
|
|
163
|
-
const decoder = new TextDecoder();
|
|
164
|
-
let buffer = "";
|
|
165
|
-
try {
|
|
166
|
-
while (true) {
|
|
167
|
-
const { done, value } = await reader.read();
|
|
168
|
-
if (done) break;
|
|
169
|
-
buffer += decoder.decode(value, { stream: true });
|
|
170
|
-
const lines = buffer.split("\n");
|
|
171
|
-
buffer = lines.pop() ?? "";
|
|
172
|
-
for (const line of lines) {
|
|
173
|
-
if (line.startsWith("data: ")) {
|
|
174
|
-
const raw = line.slice(6).trim();
|
|
175
|
-
if (raw === "[DONE]") return;
|
|
176
|
-
try {
|
|
177
|
-
const parsed = JSON.parse(raw);
|
|
178
|
-
const chunk = parsed.text ?? parsed.content ?? parsed.delta?.content ?? "";
|
|
179
|
-
if (chunk) yield chunk;
|
|
180
|
-
} catch {
|
|
181
|
-
if (raw) yield raw;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
} finally {
|
|
187
|
-
reader.releaseLock();
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Similar to stream() but returns the raw fetch Response object.
|
|
192
|
-
* Useful when you want to proxy the Server-Sent Events stream directly to a frontend client
|
|
193
|
-
* (e.g., returning this directly from a Next.js API route).
|
|
194
|
-
*
|
|
195
|
-
* @param prompt - The user prompt string
|
|
196
|
-
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
197
|
-
* @returns A Promise resolving to the native fetch Response
|
|
198
|
-
*/
|
|
199
|
-
async streamResponse(prompt, options = {}) {
|
|
200
|
-
this.assertInitialized();
|
|
201
|
-
const model = options.model ?? this.resolvedModel;
|
|
202
|
-
const response = await fetch(`${this.serverUrl}/stream`, {
|
|
203
|
-
method: "POST",
|
|
204
|
-
headers: {
|
|
205
|
-
...this.authHeaders(),
|
|
206
|
-
Accept: "text/event-stream"
|
|
207
|
-
},
|
|
208
|
-
body: JSON.stringify({
|
|
209
|
-
prompt,
|
|
210
|
-
model,
|
|
211
|
-
...options.system !== void 0 ? { system: options.system } : {},
|
|
212
|
-
...options.images !== void 0 ? { images: options.images } : {},
|
|
213
|
-
...options.documents !== void 0 ? { documents: options.documents } : {},
|
|
214
|
-
...options.pdf !== void 0 ? { pdf: options.pdf } : {},
|
|
215
|
-
...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
|
|
216
|
-
...options.temperature !== void 0 ? { temperature: options.temperature } : {}
|
|
217
|
-
})
|
|
218
|
-
});
|
|
219
|
-
if (!response.ok) {
|
|
220
|
-
let errorMessage = `AI server returned HTTP ${response.status} for /stream`;
|
|
221
|
-
try {
|
|
222
|
-
const errorData = await response.json();
|
|
223
|
-
if (errorData?.error) errorMessage = errorData.error;
|
|
224
|
-
else if (errorData?.message) errorMessage = errorData.message;
|
|
225
|
-
} catch {
|
|
226
|
-
}
|
|
227
|
-
throw new Error(errorMessage);
|
|
228
|
-
}
|
|
229
|
-
console.log(response);
|
|
230
|
-
return response;
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Multi-turn conversation streaming: pass a full message history.
|
|
234
|
-
* Calls POST /stream with the full { messages } payload.
|
|
235
|
-
*
|
|
236
|
-
* @param messages - Full conversation history
|
|
237
|
-
* @param options - Optional overrides (model, maxTokens, temperature)
|
|
238
|
-
* @returns An async generator yielding string chunks from the server
|
|
239
|
-
*/
|
|
240
|
-
async *streamChat(messages, options = {}) {
|
|
241
|
-
this.assertInitialized();
|
|
242
|
-
if (!messages.length) {
|
|
243
|
-
throw new Error("Messages array cannot be empty for streamChat");
|
|
244
|
-
}
|
|
245
|
-
const model = options.model ?? this.resolvedModel;
|
|
246
|
-
const response = await fetch(`${this.serverUrl}/stream`, {
|
|
247
|
-
method: "POST",
|
|
248
|
-
headers: {
|
|
249
|
-
...this.authHeaders(),
|
|
250
|
-
Accept: "text/event-stream"
|
|
251
|
-
},
|
|
252
|
-
body: JSON.stringify({
|
|
253
|
-
messages,
|
|
254
|
-
model,
|
|
255
|
-
...options.system !== void 0 ? { system: options.system } : {},
|
|
256
|
-
...options.images !== void 0 ? { images: options.images } : {},
|
|
257
|
-
...options.documents !== void 0 ? { documents: options.documents } : {},
|
|
258
|
-
...options.pdf !== void 0 ? { pdf: options.pdf } : {},
|
|
259
|
-
...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
|
|
260
|
-
...options.temperature !== void 0 ? { temperature: options.temperature } : {}
|
|
261
|
-
})
|
|
262
|
-
});
|
|
263
|
-
if (!response.ok) {
|
|
264
|
-
let errorMessage = `AI server returned HTTP ${response.status} for /stream`;
|
|
265
|
-
try {
|
|
266
|
-
const errorData = await response.json();
|
|
267
|
-
if (errorData?.error) errorMessage = errorData.error;
|
|
268
|
-
else if (errorData?.message) errorMessage = errorData.message;
|
|
269
|
-
} catch {
|
|
270
|
-
}
|
|
271
|
-
throw new Error(errorMessage);
|
|
272
|
-
}
|
|
273
|
-
if (!response.body) {
|
|
274
|
-
throw new Error("AI server returned no response body for /stream");
|
|
275
|
-
}
|
|
276
|
-
const reader = response.body.getReader();
|
|
277
|
-
const decoder = new TextDecoder();
|
|
278
|
-
let buffer = "";
|
|
279
|
-
try {
|
|
280
|
-
while (true) {
|
|
281
|
-
const { done, value } = await reader.read();
|
|
282
|
-
if (done) break;
|
|
283
|
-
buffer += decoder.decode(value, { stream: true });
|
|
284
|
-
const lines = buffer.split("\n");
|
|
285
|
-
buffer = lines.pop() ?? "";
|
|
286
|
-
for (const line of lines) {
|
|
287
|
-
if (line.startsWith("data: ")) {
|
|
288
|
-
const raw = line.slice(6).trim();
|
|
289
|
-
if (raw === "[DONE]") return;
|
|
290
|
-
try {
|
|
291
|
-
const parsed = JSON.parse(raw);
|
|
292
|
-
const chunk = parsed.text ?? parsed.content ?? parsed.delta?.content ?? "";
|
|
293
|
-
if (chunk) yield chunk;
|
|
294
|
-
} catch {
|
|
295
|
-
if (raw) yield raw;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
} finally {
|
|
301
|
-
reader.releaseLock();
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
69
|
/**
|
|
305
70
|
* Similar to streamChat() but returns the raw fetch Response object.
|
|
306
71
|
* Useful for proxying the Server-Sent Events stream directly to a frontend client.
|
|
@@ -345,25 +110,26 @@ var KrutAIProvider = class {
|
|
|
345
110
|
return response;
|
|
346
111
|
}
|
|
347
112
|
/**
|
|
348
|
-
*
|
|
113
|
+
* Generate a response for a prompt (non-streaming).
|
|
349
114
|
*
|
|
350
|
-
* Calls: POST {serverUrl}/
|
|
351
|
-
* Body: {
|
|
115
|
+
* Calls: POST {serverUrl}/generate
|
|
116
|
+
* Body: { prompt, model, system?, maxTokens?, temperature? }
|
|
352
117
|
* Expected response: { text: string } or { content: string } or { message: string }
|
|
353
118
|
*
|
|
354
|
-
* @param
|
|
355
|
-
* @param options - Optional overrides (model, maxTokens, temperature)
|
|
119
|
+
* @param prompt - The user prompt string
|
|
120
|
+
* @param options - Optional overrides (model, system, maxTokens, temperature)
|
|
356
121
|
* @returns The assistant's response text
|
|
357
122
|
*/
|
|
358
|
-
async chat(
|
|
123
|
+
async chat(prompt, options = {}) {
|
|
359
124
|
this.assertInitialized();
|
|
360
125
|
const model = options.model ?? this.resolvedModel;
|
|
361
|
-
const response = await fetch(`${this.serverUrl}/
|
|
126
|
+
const response = await fetch(`${this.serverUrl}/generate`, {
|
|
362
127
|
method: "POST",
|
|
363
128
|
headers: this.authHeaders(),
|
|
364
129
|
body: JSON.stringify({
|
|
365
|
-
|
|
130
|
+
prompt,
|
|
366
131
|
model,
|
|
132
|
+
...options.system !== void 0 ? { system: options.system } : {},
|
|
367
133
|
...options.images !== void 0 ? { images: options.images } : {},
|
|
368
134
|
...options.documents !== void 0 ? { documents: options.documents } : {},
|
|
369
135
|
...options.pdf !== void 0 ? { pdf: options.pdf } : {},
|
|
@@ -372,7 +138,7 @@ var KrutAIProvider = class {
|
|
|
372
138
|
})
|
|
373
139
|
});
|
|
374
140
|
if (!response.ok) {
|
|
375
|
-
let errorMessage = `AI server returned HTTP ${response.status} for /
|
|
141
|
+
let errorMessage = `AI server returned HTTP ${response.status} for /generate`;
|
|
376
142
|
try {
|
|
377
143
|
const errorData = await response.json();
|
|
378
144
|
if (errorData?.error) errorMessage = errorData.error;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/client.ts","../src/index.ts"],"names":["validateApiKey"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Types for @krutai/ai-provider\n */\n\n/**\n * Default model identifier sent to the LangChain server when no model is specified.\n * Your server can use this value to route to its own default model.\n */\nexport const DEFAULT_MODEL = 'default' as const;\n\n/**\n * Default base URL for the LangChain backend server.\n * Used when no serverUrl is provided in the config.\n */\nexport const DEFAULT_SERVER_URL = 'http://localhost:8000' as const;\n\n/**\n * Configuration options for KrutAIProvider\n */\nexport interface KrutAIProviderConfig {\n /**\n * KrutAI API key.\n * Validated against the LangChain server before use.\n * Optional: defaults to process.env.KRUTAI_API_KEY\n */\n apiKey?: string;\n\n /**\n * Base URL of your deployed LangChain backend server.\n * @default \"http://localhost:8000\"\n * @example \"https://ai.krut.ai\"\n */\n serverUrl?: string;\n\n /**\n * The AI model to use (passed to the server).\n * The server decides what to do with this value.\n * @default \"default\"\n */\n model?: string;\n\n /**\n * Whether to validate the API key against the server on initialization.\n * Set to false to skip the validation round-trip (e.g. in tests).\n * @default true\n */\n validateOnInit?: boolean;\n}\n\n/**\n * A part of a multimodal message\n */\nexport interface TextContentPart {\n type: 'text';\n text: string;\n}\n\nexport interface ImageContentPart {\n type: 'image_url';\n image_url: {\n url: string; // Base64 data URI or HTTP(S) URL\n detail?: 'low' | 'high' | 'auto';\n };\n}\n\nexport type ContentPart = TextContentPart | ImageContentPart;\nexport type MessageContent = string | ContentPart[];\n\n/**\n * A single chat message\n */\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system';\n content: MessageContent;\n}\n\n/**\n * Options for a single generate / stream / chat call\n */\nexport interface GenerateOptions {\n /**\n * Override the model for this specific call.\n */\n model?: string;\n\n /**\n * System prompt (prepended as a system message).\n */\n system?: string;\n\n /**\n * Maximum tokens to generate.\n */\n maxTokens?: number;\n\n /**\n * Temperature (0–2).\n */\n temperature?: number;\n\n /**\n * Array of image URLs or base64 data URIs to include with the request.\n */\n images?: string[];\n\n /**\n * Array of document URLs or base64 data URIs (e.g. PDFs) to include with the request.\n */\n documents?: string[];\n\n /**\n * Array of PDF URLs or base64 data URIs to include with the request.\n */\n pdf?: string[];\n}\n","import type { KrutAIProviderConfig, GenerateOptions, ChatMessage } from './types';\nimport { DEFAULT_MODEL, DEFAULT_SERVER_URL } from './types';\nimport {\n validateApiKeyWithService as validateApiKey,\n validateApiKeyFormat,\n ApiKeyValidationError as KrutAIKeyValidationError,\n} from 'krutai';\n\nexport { KrutAIKeyValidationError };\n\n/**\n * KrutAIProvider — fetch-based AI provider for KrutAI\n *\n * Calls your deployed LangChain backend server for all AI operations.\n * The API key is validated against the server before use.\n *\n * @example\n * ```typescript\n * import { KrutAIProvider } from '@krutai/ai-provider';\n *\n * // Using local dev server (http://localhost:8000 by default)\n * const ai = new KrutAIProvider({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * });\n *\n * // Or point to a production server\n * const aiProd = new KrutAIProvider({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://ai.krut.ai',\n * });\n *\n * await ai.initialize(); // validates key against server\n *\n * const text = await ai.generate('Tell me a joke');\n * console.log(text);\n * ```\n */\nexport class KrutAIProvider {\n private readonly apiKey: string;\n private readonly serverUrl: string;\n private readonly resolvedModel: string;\n private readonly config: KrutAIProviderConfig;\n\n private initialized = false;\n\n constructor(config: KrutAIProviderConfig) {\n this.config = config;\n this.apiKey = config.apiKey || process.env.KRUTAI_API_KEY || '';\n this.serverUrl = (config.serverUrl ?? DEFAULT_SERVER_URL).replace(/\\/$/, ''); // strip trailing slash\n this.resolvedModel = config.model ?? DEFAULT_MODEL;\n\n // Basic format check immediately on construction\n validateApiKeyFormat(this.apiKey);\n\n // If validation is disabled, mark as ready immediately\n if (config.validateOnInit === false) {\n this.initialized = true;\n }\n }\n\n /**\n * Initialize the provider.\n * Validates the API key against the LangChain server, then marks provider as ready.\n *\n * @throws {KrutAIKeyValidationError} if the key is rejected or the server is unreachable\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n if (this.config.validateOnInit !== false) {\n await validateApiKey(this.apiKey, this.serverUrl);\n }\n\n this.initialized = true;\n }\n\n /**\n * Returns the currently configured default model.\n */\n getModel(): string {\n return this.resolvedModel;\n }\n\n /**\n * Returns whether the provider has been initialized.\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private assertInitialized(): void {\n if (!this.initialized) {\n throw new Error(\n 'KrutAIProvider not initialized. Call initialize() first or set validateOnInit to false.'\n );\n }\n }\n\n /** Common request headers sent to the server on every AI call. */\n private authHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n 'x-api-key': this.apiKey,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Public AI Methods\n // ---------------------------------------------------------------------------\n\n /**\n * Generate a response for a prompt (non-streaming).\n *\n * Calls: POST {serverUrl}/generate\n * Body: { prompt, model, system?, maxTokens?, temperature? }\n * Expected response: { text: string } or { content: string } or { message: string }\n *\n * @param prompt - The user prompt string\n * @param options - Optional overrides (model, system, maxTokens, temperature)\n * @returns The assistant's response text\n */\n async generate(prompt: string, options: GenerateOptions = {}): Promise<string> {\n this.assertInitialized();\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/generate`, {\n method: 'POST',\n headers: this.authHeaders(),\n body: JSON.stringify({\n prompt,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /generate`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n const data = (await response.json()) as {\n text?: string;\n content?: string;\n message?: string;\n };\n\n return data.text ?? data.content ?? data.message ?? '';\n }\n\n /**\n * Generate a streaming response for a prompt via Server-Sent Events (SSE).\n *\n * Calls: POST {serverUrl}/stream\n * Body: { prompt, model, system?, maxTokens?, temperature? }\n * Expected response: `text/event-stream` with `data: <chunk>` lines.\n *\n * @param prompt - The user prompt string\n * @param options - Optional overrides (model, system, maxTokens, temperature)\n * @returns An async generator yielding string chunks from the server\n *\n * @example\n * ```typescript\n * const stream = ai.stream('Tell me a story');\n * for await (const chunk of stream) {\n * process.stdout.write(chunk);\n * }\n * ```\n */\n async *stream(prompt: string, options: GenerateOptions = {}): AsyncGenerator<string> {\n this.assertInitialized();\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/stream`, {\n method: 'POST',\n headers: {\n ...this.authHeaders(),\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({\n prompt,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /stream`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n if (!response.body) {\n throw new Error('AI server returned no response body for /stream');\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n // Keep the last (potentially incomplete) line in the buffer\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const raw = line.slice(6).trim();\n if (raw === '[DONE]') return;\n try {\n const parsed = JSON.parse(raw) as {\n text?: string;\n content?: string;\n delta?: { content?: string };\n };\n const chunk =\n parsed.text ??\n parsed.content ??\n parsed.delta?.content ??\n '';\n if (chunk) yield chunk;\n } catch {\n // raw string chunk (non-JSON SSE)\n if (raw) yield raw;\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * Similar to stream() but returns the raw fetch Response object.\n * Useful when you want to proxy the Server-Sent Events stream directly to a frontend client\n * (e.g., returning this directly from a Next.js API route).\n *\n * @param prompt - The user prompt string\n * @param options - Optional overrides (model, system, maxTokens, temperature)\n * @returns A Promise resolving to the native fetch Response\n */\n async streamResponse(prompt: string, options: GenerateOptions = {}): Promise<Response> {\n this.assertInitialized();\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/stream`, {\n method: 'POST',\n headers: {\n ...this.authHeaders(),\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({\n prompt,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /stream`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n console.log(response)\n return response;\n }\n\n /**\n * Multi-turn conversation streaming: pass a full message history.\n * Calls POST /stream with the full { messages } payload.\n *\n * @param messages - Full conversation history\n * @param options - Optional overrides (model, maxTokens, temperature)\n * @returns An async generator yielding string chunks from the server\n */\n async *streamChat(messages: ChatMessage[], options: GenerateOptions = {}): AsyncGenerator<string> {\n this.assertInitialized();\n\n if (!messages.length) {\n throw new Error('Messages array cannot be empty for streamChat');\n }\n\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/stream`, {\n method: 'POST',\n headers: {\n ...this.authHeaders(),\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({\n messages,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /stream`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n if (!response.body) {\n throw new Error('AI server returned no response body for /stream');\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const raw = line.slice(6).trim();\n if (raw === '[DONE]') return;\n try {\n const parsed = JSON.parse(raw) as {\n text?: string;\n content?: string;\n delta?: { content?: string };\n };\n const chunk =\n parsed.text ??\n parsed.content ??\n parsed.delta?.content ??\n '';\n if (chunk) yield chunk;\n } catch {\n if (raw) yield raw;\n }\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * Similar to streamChat() but returns the raw fetch Response object.\n * Useful for proxying the Server-Sent Events stream directly to a frontend client.\n *\n * @param messages - Full conversation history\n * @param options - Optional overrides (model, maxTokens, temperature)\n * @returns A Promise resolving to the native fetch Response\n */\n async streamChatResponse(messages: ChatMessage[], options: GenerateOptions = {}): Promise<Response> {\n this.assertInitialized();\n\n if (!messages.length) {\n throw new Error('Messages array cannot be empty for streamChatResponse');\n }\n\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/stream`, {\n method: 'POST',\n headers: {\n ...this.authHeaders(),\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({\n messages,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /stream`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n return response;\n }\n\n /**\n * Multi-turn conversation: pass a full message history.\n *\n * Calls: POST {serverUrl}/chat\n * Body: { messages, model, maxTokens?, temperature? }\n * Expected response: { text: string } or { content: string } or { message: string }\n *\n * @param messages - Full conversation history\n * @param options - Optional overrides (model, maxTokens, temperature)\n * @returns The assistant's response text\n */\n async chat(messages: ChatMessage[], options: GenerateOptions = {}): Promise<string> {\n this.assertInitialized();\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/chat`, {\n method: 'POST',\n headers: this.authHeaders(),\n body: JSON.stringify({\n messages,\n model,\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /chat`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n const data = (await response.json()) as {\n text?: string;\n content?: string;\n message?: string;\n };\n\n return data.text ?? data.content ?? data.message ?? '';\n }\n}\n","/**\n * @krutai/ai-provider — AI Provider package for KrutAI\n *\n * A fetch-based wrapper that calls your deployed LangChain backend server.\n * The user's API key is validated against the server before any AI call is made.\n *\n * @example Basic usage\n * ```typescript\n * import { krutAI } from '@krutai/ai-provider';\n *\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * });\n *\n * await ai.initialize(); // validates key with server\n *\n * const text = await ai.generate('Write a poem about TypeScript');\n * console.log(text);\n * ```\n *\n * @example With custom model\n * ```typescript\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * model: 'gpt-4o',\n * });\n * await ai.initialize();\n * const text = await ai.generate('Hello!');\n * ```\n *\n * @example Streaming\n * ```typescript\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * });\n * await ai.initialize();\n *\n * const stream = ai.stream('Tell me a story');\n * for await (const chunk of stream) {\n * process.stdout.write(chunk);\n * }\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { KrutAIProviderConfig } from './types';\nimport { DEFAULT_MODEL } from './types';\nimport { KrutAIProvider } from './client';\n\nexport { KrutAIProvider } from './client';\nexport { KrutAIKeyValidationError } from './client';\nexport {\n validateApiKeyWithService as validateApiKey,\n validateApiKeyFormat,\n} from 'krutai';\nexport type { KrutAIProviderConfig, GenerateOptions, ChatMessage } from './types';\nexport { DEFAULT_MODEL } from './types';\n\n/**\n * krutAI — convenience factory (mirrors `krutAuth` in @krutai/auth).\n *\n * Creates a `KrutAIProvider` instance configured to call your LangChain server.\n *\n * @param config - Provider configuration (`apiKey` and `serverUrl` are required)\n * @returns A `KrutAIProvider` instance — call `.initialize()` before use\n *\n * @example\n * ```typescript\n * import { krutAI } from '@krutai/ai-provider';\n *\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * });\n *\n * await ai.initialize();\n * const text = await ai.generate('Hello!');\n * ```\n */\nexport function krutAI(\n config: KrutAIProviderConfig & { model?: string }\n): KrutAIProvider {\n return new KrutAIProvider({\n model: DEFAULT_MODEL,\n ...config,\n });\n}\n\n// Package metadata\nexport const VERSION = '0.2.0';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/client.ts","../src/index.ts"],"names":["validateApiKey"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Types for @krutai/ai-provider\n */\n\n/**\n * Default model identifier sent to the LangChain server when no model is specified.\n * Your server can use this value to route to its own default model.\n */\nexport const DEFAULT_MODEL = 'default' as const;\n\n/**\n * Default base URL for the LangChain backend server.\n * Used when no serverUrl is provided in the config.\n */\nexport const DEFAULT_SERVER_URL = 'http://localhost:8000' as const;\n\n/**\n * Configuration options for KrutAIProvider\n */\nexport interface KrutAIProviderConfig {\n /**\n * KrutAI API key.\n * Validated against the LangChain server before use.\n * Optional: defaults to process.env.KRUTAI_API_KEY\n */\n apiKey?: string;\n\n /**\n * Base URL of your deployed LangChain backend server.\n * @default \"http://localhost:8000\"\n * @example \"https://ai.krut.ai\"\n */\n serverUrl?: string;\n\n /**\n * The AI model to use (passed to the server).\n * The server decides what to do with this value.\n * @default \"default\"\n */\n model?: string;\n\n /**\n * Whether to validate the API key against the server on initialization.\n * Set to false to skip the validation round-trip (e.g. in tests).\n * @default true\n */\n validateOnInit?: boolean;\n}\n\n/**\n * A part of a multimodal message\n */\nexport interface TextContentPart {\n type: 'text';\n text: string;\n}\n\nexport interface ImageContentPart {\n type: 'image_url';\n image_url: {\n url: string; // Base64 data URI or HTTP(S) URL\n detail?: 'low' | 'high' | 'auto';\n };\n}\n\nexport type ContentPart = TextContentPart | ImageContentPart;\nexport type MessageContent = string | ContentPart[];\n\n/**\n * A single chat message\n */\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system';\n content: MessageContent;\n}\n\n/**\n * Options for a single generate / stream / chat call\n */\nexport interface GenerateOptions {\n /**\n * Override the model for this specific call.\n */\n model?: string;\n\n /**\n * System prompt (prepended as a system message).\n */\n system?: string;\n\n /**\n * Maximum tokens to generate.\n */\n maxTokens?: number;\n\n /**\n * Temperature (0–2).\n */\n temperature?: number;\n\n /**\n * Array of image URLs or base64 data URIs to include with the request.\n */\n images?: string[];\n\n /**\n * Array of document URLs or base64 data URIs (e.g. PDFs) to include with the request.\n */\n documents?: string[];\n\n /**\n * Array of PDF URLs or base64 data URIs to include with the request.\n */\n pdf?: string[];\n}\n","import type { KrutAIProviderConfig, GenerateOptions, ChatMessage } from './types';\nimport { DEFAULT_MODEL, DEFAULT_SERVER_URL } from './types';\nimport {\n validateApiKeyWithService as validateApiKey,\n validateApiKeyFormat,\n ApiKeyValidationError as KrutAIKeyValidationError,\n} from 'krutai';\n\nexport { KrutAIKeyValidationError };\n\n/**\n * KrutAIProvider — fetch-based AI provider for KrutAI\n *\n * Calls your deployed LangChain backend server for all AI operations.\n * The API key is validated against the server before use.\n *\n * @example\n * ```typescript\n * import { KrutAIProvider } from '@krutai/ai-provider';\n *\n * // Using local dev server (http://localhost:8000 by default)\n * const ai = new KrutAIProvider({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * });\n *\n * // Or point to a production server\n * const aiProd = new KrutAIProvider({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://ai.krut.ai',\n * });\n *\n * await ai.initialize(); // validates key against server\n *\n * const text = await ai.generate('Tell me a joke');\n * console.log(text);\n * ```\n */\nexport class KrutAIProvider {\n private readonly apiKey: string;\n private readonly serverUrl: string;\n private readonly resolvedModel: string;\n private readonly config: KrutAIProviderConfig;\n\n private initialized = false;\n\n constructor(config: KrutAIProviderConfig) {\n this.config = config;\n this.apiKey = config.apiKey || process.env.KRUTAI_API_KEY || '';\n this.serverUrl = (config.serverUrl ?? DEFAULT_SERVER_URL).replace(/\\/$/, ''); // strip trailing slash\n this.resolvedModel = config.model ?? DEFAULT_MODEL;\n\n // Basic format check immediately on construction\n validateApiKeyFormat(this.apiKey);\n\n // If validation is disabled, mark as ready immediately\n if (config.validateOnInit === false) {\n this.initialized = true;\n }\n }\n\n /**\n * Initialize the provider.\n * Validates the API key against the LangChain server, then marks provider as ready.\n *\n * @throws {KrutAIKeyValidationError} if the key is rejected or the server is unreachable\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n if (this.config.validateOnInit !== false) {\n await validateApiKey(this.apiKey, this.serverUrl);\n }\n\n this.initialized = true;\n }\n\n /**\n * Returns the currently configured default model.\n */\n getModel(): string {\n return this.resolvedModel;\n }\n\n /**\n * Returns whether the provider has been initialized.\n */\n isInitialized(): boolean {\n return this.initialized;\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private assertInitialized(): void {\n if (!this.initialized) {\n throw new Error(\n 'KrutAIProvider not initialized. Call initialize() first or set validateOnInit to false.'\n );\n }\n }\n\n /** Common request headers sent to the server on every AI call. */\n private authHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n 'x-api-key': this.apiKey,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Public AI Methods\n // ---------------------------------------------------------------------------\n\n /**\n * Similar to streamChat() but returns the raw fetch Response object.\n * Useful for proxying the Server-Sent Events stream directly to a frontend client.\n *\n * @param messages - Full conversation history\n * @param options - Optional overrides (model, maxTokens, temperature)\n * @returns A Promise resolving to the native fetch Response\n */\n async streamChatResponse(messages: ChatMessage[], options: GenerateOptions = {}): Promise<Response> {\n this.assertInitialized();\n\n if (!messages.length) {\n throw new Error('Messages array cannot be empty for streamChatResponse');\n }\n\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/stream`, {\n method: 'POST',\n headers: {\n ...this.authHeaders(),\n Accept: 'text/event-stream',\n },\n body: JSON.stringify({\n messages,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /stream`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n return response;\n }\n\n /**\n * Generate a response for a prompt (non-streaming).\n *\n * Calls: POST {serverUrl}/generate\n * Body: { prompt, model, system?, maxTokens?, temperature? }\n * Expected response: { text: string } or { content: string } or { message: string }\n *\n * @param prompt - The user prompt string\n * @param options - Optional overrides (model, system, maxTokens, temperature)\n * @returns The assistant's response text\n */\n async chat(prompt: string, options: GenerateOptions = {}): Promise<string> {\n this.assertInitialized();\n const model = options.model ?? this.resolvedModel;\n\n const response = await fetch(`${this.serverUrl}/generate`, {\n method: 'POST',\n headers: this.authHeaders(),\n body: JSON.stringify({\n prompt,\n model,\n ...(options.system !== undefined ? { system: options.system } : {}),\n ...(options.images !== undefined ? { images: options.images } : {}),\n ...(options.documents !== undefined ? { documents: options.documents } : {}),\n ...(options.pdf !== undefined ? { pdf: options.pdf } : {}),\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `AI server returned HTTP ${response.status} for /generate`;\n try {\n const errorData = (await response.json()) as { message?: string; error?: string };\n if (errorData?.error) errorMessage = errorData.error;\n else if (errorData?.message) errorMessage = errorData.message;\n } catch { }\n throw new Error(errorMessage);\n }\n\n const data = (await response.json()) as {\n text?: string;\n content?: string;\n message?: string;\n };\n\n return data.text ?? data.content ?? data.message ?? '';\n }\n}\n","/**\n * @krutai/ai-provider — AI Provider package for KrutAI\n *\n * A fetch-based wrapper that calls your deployed LangChain backend server.\n * The user's API key is validated against the server before any AI call is made.\n *\n * @example Basic usage\n * ```typescript\n * import { krutAI } from '@krutai/ai-provider';\n *\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * });\n *\n * await ai.initialize(); // validates key with server\n *\n * const text = await ai.chat('Write a poem about TypeScript');\n * console.log(text);\n * ```\n *\n * @example With custom model\n * ```typescript\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * model: 'gpt-4o',\n * });\n * await ai.initialize();\n * const text = await ai.chat('Hello!');\n * ```\n *\n * @example Streaming\n * ```typescript\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * });\n * await ai.initialize();\n *\n * const response = await ai.streamChatResponse([{ role: 'user', content: 'Tell me a story' }]);\n * // Example assumes you handle the SSE stream from the response body\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { KrutAIProviderConfig } from './types';\nimport { DEFAULT_MODEL } from './types';\nimport { KrutAIProvider } from './client';\n\nexport { KrutAIProvider } from './client';\nexport { KrutAIKeyValidationError } from './client';\nexport {\n validateApiKeyWithService as validateApiKey,\n validateApiKeyFormat,\n} from 'krutai';\nexport type { KrutAIProviderConfig, GenerateOptions, ChatMessage } from './types';\nexport { DEFAULT_MODEL } from './types';\n\n/**\n * krutAI — convenience factory (mirrors `krutAuth` in @krutai/auth).\n *\n * Creates a `KrutAIProvider` instance configured to call your LangChain server.\n *\n * @param config - Provider configuration (`apiKey` and `serverUrl` are required)\n * @returns A `KrutAIProvider` instance — call `.initialize()` before use\n *\n * @example\n * ```typescript\n * import { krutAI } from '@krutai/ai-provider';\n *\n * const ai = krutAI({\n * apiKey: process.env.KRUTAI_API_KEY!,\n * serverUrl: 'https://krut.ai',\n * });\n *\n * await ai.initialize();\n * const text = await ai.chat('Hello!');\n * ```\n */\nexport function krutAI(\n config: KrutAIProviderConfig & { model?: string }\n): KrutAIProvider {\n return new KrutAIProvider({\n model: DEFAULT_MODEL,\n ...config,\n });\n}\n\n// Package metadata\nexport const VERSION = '0.2.0';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@krutai/ai-provider",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
4
4
|
"description": "AI provider package for KrutAI — fetch-based client for your deployed LangChain server with API key validation",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|