@schmitech/chatbot-api 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -290
- package/api.d.ts +25 -0
- package/dist/api.cjs +2 -2
- package/dist/api.cjs.map +1 -1
- package/dist/api.mjs +128 -84
- package/dist/api.mjs.d.ts +1 -9
- package/dist/api.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,76 +1,45 @@
|
|
|
1
|
-
# Chatbot API Client
|
|
1
|
+
# 🤖 Chatbot API Client
|
|
2
2
|
|
|
3
|
-
A JavaScript/TypeScript client
|
|
3
|
+
A JavaScript/TypeScript client for seamless interaction with the Chatbot server, now supporting API key authentication.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## 📥 Installation
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
### 📍 Local Development (npm link)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
npm run build
|
|
14
|
-
npm link
|
|
15
|
-
```
|
|
11
|
+
Use during local development:
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
3. Now you can import and use the library in your project:
|
|
23
|
-
```javascript
|
|
24
|
-
import { streamChat } from 'chatbot-api';
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### Option 2: Installing from a local directory
|
|
28
|
-
|
|
29
|
-
You can also install the package directly from the local directory:
|
|
30
|
-
|
|
31
|
-
1. In this library directory, run:
|
|
32
|
-
```bash
|
|
33
|
-
npm run build
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
2. In your project directory, run:
|
|
37
|
-
```bash
|
|
38
|
-
npm install /path/to/qa-chatbot-server/api
|
|
39
|
-
```
|
|
13
|
+
```bash
|
|
14
|
+
npm run build
|
|
15
|
+
npm link
|
|
40
16
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
```
|
|
17
|
+
# In your project directory
|
|
18
|
+
npm link @schmitech/chatbot-api
|
|
19
|
+
```
|
|
45
20
|
|
|
46
|
-
###
|
|
21
|
+
### 📂 Local Directory Install
|
|
47
22
|
|
|
48
|
-
|
|
23
|
+
Direct local installation:
|
|
49
24
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
3. Update the package name in package.json to ensure it's unique
|
|
56
|
-
4. Publish the package:
|
|
57
|
-
```bash
|
|
58
|
-
npm publish
|
|
59
|
-
```
|
|
25
|
+
```bash
|
|
26
|
+
npm run build
|
|
27
|
+
npm install /path/to/qa-chatbot-server/api
|
|
28
|
+
```
|
|
60
29
|
|
|
61
|
-
###
|
|
30
|
+
### 🌐 CDN Integration
|
|
62
31
|
|
|
63
|
-
|
|
32
|
+
Integrate directly into websites via CDN:
|
|
64
33
|
|
|
65
34
|
```html
|
|
66
|
-
<!-- For ESM (modern browsers) -->
|
|
67
35
|
<script type="module">
|
|
68
|
-
import { configureApi, streamChat } from 'https://cdn.jsdelivr.net/npm/@schmitech/chatbot-api
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
36
|
+
import { configureApi, streamChat } from 'https://cdn.jsdelivr.net/npm/@schmitech/chatbot-api/dist/api.mjs';
|
|
37
|
+
|
|
38
|
+
configureApi({
|
|
39
|
+
apiUrl: 'https://your-api-server.com',
|
|
40
|
+
apiKey: 'your-api-key'
|
|
41
|
+
});
|
|
42
|
+
|
|
74
43
|
async function handleChat() {
|
|
75
44
|
for await (const response of streamChat('Hello', false)) {
|
|
76
45
|
console.log(response.text);
|
|
@@ -79,315 +48,158 @@ You can include the library directly in your website using jsDelivr CDN:
|
|
|
79
48
|
</script>
|
|
80
49
|
```
|
|
81
50
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
```html
|
|
85
|
-
<script type="module">
|
|
86
|
-
import { configureApi, streamChat } from 'https://cdn.jsdelivr.net/npm/@schmitech/chatbot-api/dist/api.mjs';
|
|
87
|
-
// ...
|
|
88
|
-
</script>
|
|
89
|
-
```
|
|
51
|
+
---
|
|
90
52
|
|
|
91
|
-
## Usage
|
|
53
|
+
## ⚙️ Usage
|
|
92
54
|
|
|
93
|
-
### Configuration (Required)
|
|
55
|
+
### 🚨 Configuration (Required)
|
|
94
56
|
|
|
95
|
-
|
|
57
|
+
You must configure the API client before usage:
|
|
96
58
|
|
|
97
59
|
```javascript
|
|
98
|
-
import { configureApi, streamChat } from 'chatbot-api';
|
|
60
|
+
import { configureApi, streamChat } from '@schmitech/chatbot-api';
|
|
99
61
|
|
|
100
|
-
|
|
101
|
-
|
|
62
|
+
configureApi({
|
|
63
|
+
apiUrl: 'https://your-api-server.com',
|
|
64
|
+
apiKey: 'your-api-key'
|
|
65
|
+
});
|
|
102
66
|
```
|
|
103
67
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
### Basic Usage
|
|
68
|
+
### 📖 Basic Example
|
|
107
69
|
|
|
108
70
|
```javascript
|
|
109
|
-
import { configureApi, streamChat } from 'chatbot-api';
|
|
110
|
-
|
|
111
71
|
async function chat() {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// Stream chat responses
|
|
116
|
-
for await (const response of streamChat('Hello, how can I help you?', false)) {
|
|
117
|
-
// Access the text response
|
|
72
|
+
configureApi({ apiUrl: 'https://your-api-server.com', apiKey: 'your-api-key' });
|
|
73
|
+
|
|
74
|
+
for await (const response of streamChat('Hello, how can I help?', false)) {
|
|
118
75
|
console.log(response.text);
|
|
119
|
-
|
|
120
|
-
// Check if this is the final response
|
|
121
|
-
if (response.done) {
|
|
122
|
-
console.log('Chat complete!');
|
|
123
|
-
}
|
|
76
|
+
if (response.done) console.log('Chat complete!');
|
|
124
77
|
}
|
|
125
78
|
}
|
|
126
79
|
|
|
127
80
|
chat();
|
|
128
81
|
```
|
|
129
82
|
|
|
130
|
-
###
|
|
83
|
+
### 🎙️ Voice-enabled Example
|
|
131
84
|
|
|
132
85
|
```javascript
|
|
133
|
-
import { configureApi, streamChat } from 'chatbot-api';
|
|
134
|
-
|
|
135
86
|
async function chatWithVoice() {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
// Stream chat responses with voice enabled (second parameter true)
|
|
87
|
+
configureApi({ apiUrl: 'https://your-api-server.com', apiKey: 'your-api-key' });
|
|
88
|
+
|
|
140
89
|
for await (const response of streamChat('Tell me a joke', true)) {
|
|
141
|
-
|
|
142
|
-
if (response.text) {
|
|
143
|
-
console.log(response.text);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Handle audio content when available
|
|
147
|
-
if (response.type === 'audio' && response.content) {
|
|
148
|
-
// Process audio content (base64 encoded)
|
|
90
|
+
if (response.type === 'audio') {
|
|
149
91
|
console.log('Received audio content');
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (response.done) {
|
|
154
|
-
console.log('Chat complete!');
|
|
92
|
+
} else {
|
|
93
|
+
console.log(response.text);
|
|
155
94
|
}
|
|
95
|
+
if (response.done) console.log('Chat complete!');
|
|
156
96
|
}
|
|
157
97
|
}
|
|
158
98
|
|
|
159
99
|
chatWithVoice();
|
|
160
100
|
```
|
|
161
101
|
|
|
162
|
-
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## ⚛️ React Integration
|
|
105
|
+
|
|
106
|
+
Configure once globally:
|
|
163
107
|
|
|
164
108
|
```jsx
|
|
165
|
-
import React, { useState
|
|
166
|
-
import { configureApi, streamChat } from 'chatbot-api';
|
|
109
|
+
import React, { useState } from 'react';
|
|
110
|
+
import { configureApi, streamChat } from '@schmitech/chatbot-api';
|
|
167
111
|
|
|
168
|
-
|
|
169
|
-
|
|
112
|
+
configureApi({
|
|
113
|
+
apiUrl: 'https://your-api-server.com',
|
|
114
|
+
apiKey: 'your-api-key'
|
|
115
|
+
});
|
|
170
116
|
|
|
171
117
|
function ChatComponent() {
|
|
172
118
|
const [messages, setMessages] = useState([]);
|
|
173
119
|
const [input, setInput] = useState('');
|
|
174
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
175
120
|
|
|
176
121
|
const handleSubmit = async (e) => {
|
|
177
122
|
e.preventDefault();
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
let fullResponse = '';
|
|
186
|
-
|
|
187
|
-
try {
|
|
188
|
-
for await (const response of streamChat(userMessage, false)) {
|
|
189
|
-
if (response.text) {
|
|
190
|
-
fullResponse += response.text;
|
|
191
|
-
// Update the UI with each chunk of text as it arrives
|
|
192
|
-
setMessages(prev => [
|
|
193
|
-
...prev.slice(0, -1),
|
|
194
|
-
{ text: userMessage, isUser: true },
|
|
195
|
-
{ text: fullResponse, isUser: false, isComplete: response.done }
|
|
196
|
-
]);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (response.done) {
|
|
200
|
-
setIsLoading(false);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
} catch (error) {
|
|
204
|
-
console.error('Chat error:', error);
|
|
205
|
-
setMessages(prev => [...prev, {
|
|
206
|
-
text: `Error: ${error.message}`,
|
|
207
|
-
isUser: false,
|
|
208
|
-
isError: true
|
|
209
|
-
}]);
|
|
210
|
-
setIsLoading(false);
|
|
123
|
+
setMessages(prev => [...prev, { text: input, isUser: true }]);
|
|
124
|
+
|
|
125
|
+
let responseText = '';
|
|
126
|
+
for await (const response of streamChat(input, false)) {
|
|
127
|
+
responseText += response.text;
|
|
128
|
+
setMessages(prev => [...prev, { text: responseText, isUser: false }]);
|
|
129
|
+
if (response.done) break;
|
|
211
130
|
}
|
|
131
|
+
setInput('');
|
|
212
132
|
};
|
|
213
133
|
|
|
214
134
|
return (
|
|
215
|
-
<
|
|
216
|
-
<
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
{msg.text}
|
|
220
|
-
</div>
|
|
221
|
-
))}
|
|
222
|
-
{isLoading && <div className="loading">...</div>}
|
|
223
|
-
</div>
|
|
224
|
-
|
|
225
|
-
<form onSubmit={handleSubmit}>
|
|
226
|
-
<input
|
|
227
|
-
value={input}
|
|
228
|
-
onChange={(e) => setInput(e.target.value)}
|
|
229
|
-
placeholder="Type your message..."
|
|
230
|
-
disabled={isLoading}
|
|
231
|
-
/>
|
|
232
|
-
<button type="submit" disabled={isLoading}>Send</button>
|
|
233
|
-
</form>
|
|
234
|
-
</div>
|
|
135
|
+
<form onSubmit={handleSubmit}>
|
|
136
|
+
<input value={input} onChange={(e) => setInput(e.target.value)} />
|
|
137
|
+
<button type="submit">Send</button>
|
|
138
|
+
</form>
|
|
235
139
|
);
|
|
236
140
|
}
|
|
237
141
|
|
|
238
142
|
export default ChatComponent;
|
|
239
143
|
```
|
|
240
144
|
|
|
241
|
-
|
|
145
|
+
---
|
|
242
146
|
|
|
243
|
-
|
|
147
|
+
## 📱 Mobile Usage
|
|
244
148
|
|
|
245
|
-
|
|
149
|
+
### 📲 React Native
|
|
246
150
|
|
|
247
151
|
```javascript
|
|
248
|
-
|
|
152
|
+
configureApi({ apiUrl: 'https://your-api-server.com', apiKey: 'your-api-key' });
|
|
249
153
|
|
|
250
|
-
// Configure API
|
|
251
|
-
configureApi('https://your-api-server.com');
|
|
252
|
-
|
|
253
|
-
// Usage in React Native component
|
|
254
154
|
async function handleChat(message) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
// Update UI with response.text
|
|
258
|
-
}
|
|
259
|
-
} catch (error) {
|
|
260
|
-
console.error('Chat error:', error);
|
|
155
|
+
for await (const response of streamChat(message, false)) {
|
|
156
|
+
// Handle response
|
|
261
157
|
}
|
|
262
158
|
}
|
|
263
159
|
```
|
|
264
160
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
For pure native iOS, you'll need to create a Swift wrapper:
|
|
268
|
-
|
|
269
|
-
```swift
|
|
270
|
-
// ChatService.swift
|
|
271
|
-
import Foundation
|
|
272
|
-
|
|
273
|
-
class ChatService {
|
|
274
|
-
private let apiUrl: String
|
|
275
|
-
|
|
276
|
-
init(apiUrl: String) {
|
|
277
|
-
self.apiUrl = apiUrl
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
func sendMessage(_ message: String, voiceEnabled: Bool,
|
|
281
|
-
onResponse: @escaping (String, Bool) -> Void,
|
|
282
|
-
onError: @escaping (Error) -> Void) {
|
|
283
|
-
|
|
284
|
-
guard let url = URL(string: "\(apiUrl)/chat") else {
|
|
285
|
-
onError(NSError(domain: "Invalid URL", code: 0))
|
|
286
|
-
return
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
var request = URLRequest(url: url)
|
|
290
|
-
request.httpMethod = "POST"
|
|
291
|
-
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
292
|
-
|
|
293
|
-
let body: [String: Any] = ["message": message, "voiceEnabled": voiceEnabled]
|
|
294
|
-
request.httpBody = try? JSONSerialization.data(withJSONObject: body)
|
|
295
|
-
|
|
296
|
-
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
|
297
|
-
// Handle streaming responses
|
|
298
|
-
// ...
|
|
299
|
-
}
|
|
300
|
-
task.resume()
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### Native Android (Kotlin)
|
|
306
|
-
|
|
307
|
-
For pure native Android, you'd implement:
|
|
308
|
-
|
|
309
|
-
```kotlin
|
|
310
|
-
// ChatService.kt
|
|
311
|
-
class ChatService(private val apiUrl: String) {
|
|
312
|
-
fun sendMessage(
|
|
313
|
-
message: String,
|
|
314
|
-
voiceEnabled: Boolean,
|
|
315
|
-
onResponse: (text: String, isDone: Boolean) -> Unit,
|
|
316
|
-
onError: (error: Throwable) -> Unit
|
|
317
|
-
) {
|
|
318
|
-
val client = OkHttpClient()
|
|
319
|
-
|
|
320
|
-
val requestBody = JSONObject().apply {
|
|
321
|
-
put("message", message)
|
|
322
|
-
put("voiceEnabled", voiceEnabled)
|
|
323
|
-
}.toString().toRequestBody("application/json".toMediaType())
|
|
324
|
-
|
|
325
|
-
val request = Request.Builder()
|
|
326
|
-
.url("$apiUrl/chat")
|
|
327
|
-
.post(requestBody)
|
|
328
|
-
.build()
|
|
329
|
-
|
|
330
|
-
// Set up streaming response handling
|
|
331
|
-
// ...
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
### Alternative Approaches
|
|
337
|
-
|
|
338
|
-
1. **Flutter**: Create Dart implementation using http package
|
|
339
|
-
2. **WebView**: Embed a web component in your app that uses the JS client
|
|
340
|
-
3. **Capacitor/Cordova**: Create a hybrid app, use the npm package directly
|
|
341
|
-
|
|
342
|
-
## API Reference
|
|
343
|
-
|
|
344
|
-
### configureApi(apiUrl)
|
|
345
|
-
|
|
346
|
-
Configures the API client with your server URL.
|
|
161
|
+
---
|
|
347
162
|
|
|
348
|
-
|
|
349
|
-
- **Returns**: void
|
|
163
|
+
## 📚 API Reference
|
|
350
164
|
|
|
351
|
-
###
|
|
165
|
+
### `configureApi(config)`
|
|
352
166
|
|
|
353
|
-
|
|
167
|
+
| Parameter | Description | Required |
|
|
168
|
+
|-----------|-------------|----------|
|
|
169
|
+
| `apiUrl` | Chatbot API URL | ✅ Yes |
|
|
170
|
+
| `apiKey` | API key for authentication | ✅ Yes |
|
|
354
171
|
|
|
355
|
-
|
|
356
|
-
- **voiceEnabled** (boolean): Whether to enable voice responses
|
|
357
|
-
- **Returns**: AsyncGenerator that yields StreamResponse objects
|
|
172
|
+
### `streamChat(message, voiceEnabled)`
|
|
358
173
|
|
|
359
|
-
|
|
174
|
+
Streams responses from the server:
|
|
175
|
+
- `message`: Message string
|
|
176
|
+
- `voiceEnabled`: Boolean, enables audio response
|
|
360
177
|
|
|
178
|
+
Returns an async generator yielding:
|
|
361
179
|
```typescript
|
|
362
180
|
interface StreamResponse {
|
|
363
|
-
text?: string;
|
|
364
|
-
content?: string;
|
|
365
|
-
done?: boolean;
|
|
366
|
-
type?: string;
|
|
181
|
+
text?: string;
|
|
182
|
+
content?: string;
|
|
183
|
+
done?: boolean;
|
|
184
|
+
type?: string;
|
|
367
185
|
}
|
|
368
186
|
```
|
|
369
187
|
|
|
370
|
-
|
|
188
|
+
---
|
|
371
189
|
|
|
372
|
-
|
|
190
|
+
## 🛠️ Development
|
|
373
191
|
|
|
374
|
-
|
|
375
|
-
npm run build
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
### Running Tests
|
|
192
|
+
### 🧪 Testing
|
|
379
193
|
|
|
380
194
|
```bash
|
|
381
|
-
|
|
195
|
+
npm run build
|
|
382
196
|
npm test
|
|
383
|
-
|
|
384
|
-
# Run tests in watch mode
|
|
385
197
|
npm run test:watch
|
|
386
|
-
|
|
387
|
-
# Test a specific query
|
|
388
|
-
npm run test-query "how much is the fee?" "http://your-api-server.com"
|
|
198
|
+
npm run test-query "your query" "http://your-api-server.com" "your-api-key"
|
|
389
199
|
```
|
|
390
200
|
|
|
391
|
-
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 📃 License
|
|
392
204
|
|
|
393
|
-
MIT
|
|
205
|
+
MIT License - See [LICENSE](LICENSE).
|
package/api.d.ts
CHANGED
|
@@ -5,5 +5,30 @@ export interface StreamResponse {
|
|
|
5
5
|
export interface ChatResponse {
|
|
6
6
|
response: string;
|
|
7
7
|
}
|
|
8
|
+
interface MCPResponse {
|
|
9
|
+
jsonrpc: "2.0";
|
|
10
|
+
id: string;
|
|
11
|
+
result?: {
|
|
12
|
+
type?: "start" | "chunk" | "complete";
|
|
13
|
+
chunk?: {
|
|
14
|
+
content: string;
|
|
15
|
+
};
|
|
16
|
+
output?: {
|
|
17
|
+
messages: Array<{
|
|
18
|
+
role: string;
|
|
19
|
+
content: string;
|
|
20
|
+
}>;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
error?: {
|
|
24
|
+
code: number;
|
|
25
|
+
message: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
8
28
|
export declare const configureApi: (apiUrl: string, apiKey: string) => void;
|
|
9
29
|
export declare function streamChat(message: string, stream?: boolean): AsyncGenerator<StreamResponse>;
|
|
30
|
+
export declare function sendToolsRequest(tools: Array<{
|
|
31
|
+
name: string;
|
|
32
|
+
parameters: Record<string, any>;
|
|
33
|
+
}>): Promise<MCPResponse>;
|
|
34
|
+
export {};
|
package/dist/api.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let
|
|
2
|
-
`);a=
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let y=null,m=null;const j=(t,e)=>{if(!t||typeof t!="string")throw new Error("API URL must be a valid string");if(!e||typeof e!="string")throw new Error("API key must be a valid string");y=t,m=e},v=()=>{if(!y)throw new Error("API URL not configured. Please call configureApi() with your server URL before using any API functions.");return y},C=()=>{if(!m)throw new Error("API key not configured. Please call configureApi() with your API key before using any API functions.");return m},R=(t,e={})=>{t.startsWith("https:");const r=Date.now().toString(36)+Math.random().toString(36).substring(2);return{...e,headers:{...e.headers,Connection:"keep-alive","X-Request-ID":r,"X-API-Key":C()}}},M=(t,e=!0)=>({jsonrpc:"2.0",method:"tools/call",params:{name:"chat",arguments:{messages:[{role:"user",content:t}],stream:e}},id:Date.now().toString(36)+Math.random().toString(36).substring(2)}),q=t=>({jsonrpc:"2.0",method:"tools/call",params:{name:"tools",arguments:{tools:t}},id:Date.now().toString(36)+Math.random().toString(36).substring(2)});async function*D(t,e=!0){var r,n,u,A,P,k,E,b,S;try{const c=v(),i=await fetch(`${c}/v1/chat`,R(c,{method:"POST",headers:{"Content-Type":"application/json",Accept:e?"text/event-stream":"application/json"},body:JSON.stringify(M(t,e))}));if(!i.ok){const o=await i.text();throw console.error(`API request failed: ${i.status} ${o}`),new Error(`Network response was not ok: ${i.status} ${o}`)}if(!e){const o=await i.json();if(o.error)throw new Error(`MCP Error: ${o.error.message}`);(A=(u=(n=(r=o.result)==null?void 0:r.output)==null?void 0:n.messages)==null?void 0:u[0])!=null&&A.content&&(yield{text:o.result.output.messages[0].content,done:!0});return}const I=(P=i.body)==null?void 0:P.getReader();if(!I)throw new Error("No reader available");const $=new TextDecoder;let a="",g="";for(;;){const{done:o,value:l}=await I.read();if(o)break;const f=$.decode(l,{stream:!0});a+=f;const N=a.split(`
|
|
2
|
+
`);a=N.pop()||"";for(const h of N)if(h.trim()&&h.startsWith("data: "))try{const d=h.slice(6).trim();if(d==="[DONE]"){yield{text:"",done:!0};break}const s=JSON.parse(d);if(s.result){let p="";if(s.result.type==="start")continue;if(s.result.type==="chunk"&&s.result.chunk?p=s.result.chunk.content:s.result.type==="complete"&&((E=(k=s.result.output)==null?void 0:k.messages)!=null&&E[0])&&(p=s.result.output.messages[0].content),p){const w=O(p,g);w?(g+=w,yield{text:w,done:s.result.type==="complete"}):s.result.type==="complete"&&(yield{text:"",done:!0})}}}catch(d){console.warn("Error parsing JSON chunk:",h,"Error:",d)}}if(a&&a.startsWith("data: "))try{const o=a.slice(6).trim();if(o!=="[DONE]"){const l=JSON.parse(o);if((S=(b=l.result)==null?void 0:b.chunk)!=null&&S.content){const f=O(l.result.chunk.content,g);f&&(yield{text:f,done:l.result.type==="complete"})}}}catch(o){console.warn("Error parsing final JSON buffer:",a,"Error:",o)}}catch(c){console.error("Chat API error:",c.message),yield{text:`Error connecting to chat server: ${c.message}`,done:!0}}}function O(t,e){if(!e)return t;if(e.endsWith(t))return"";if(t.length>e.length){if(t.startsWith(e))return t.slice(e.length);let r=0;const n=Math.min(e.length,t.length);for(;r<n&&e[r]===t[r];)r++;if(r>e.length/2)return t.slice(r)}return t}async function J(t){const e=v(),r=await fetch(`${e}/v1/chat`,R(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(q(t))}));if(!r.ok){const u=await r.text();throw new Error(`Network response was not ok: ${r.status} ${u}`)}const n=await r.json();if(n.error)throw new Error(`MCP Error: ${n.error.message}`);return n}exports.configureApi=j;exports.sendToolsRequest=J;exports.streamChat=D;
|
|
3
3
|
//# sourceMappingURL=api.cjs.map
|
package/dist/api.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.cjs","sources":["../api.ts"],"sourcesContent":["// For Node.js environments, we can use http.Agent for connection pooling\nlet httpAgent: any = null;\nlet httpsAgent: any = null;\n\n// Define the StreamResponse interface\nexport interface StreamResponse {\n text: string;\n done: boolean;\n}\n\nexport interface ChatResponse {\n response: string;\n}\n\n// Store the configured API URL and key\nlet configuredApiUrl: string | null = null;\nlet configuredApiKey: string | null = null;\n\n// Configure the API with a custom URL and API key\nexport const configureApi = (apiUrl: string, apiKey: string): void => {\n if (!apiUrl || typeof apiUrl !== 'string') {\n throw new Error('API URL must be a valid string');\n }\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('API key must be a valid string');\n }\n configuredApiUrl = apiUrl;\n configuredApiKey = apiKey;\n}\n\n// Get the configured API URL or throw an error if not configured\nconst getApiUrl = (): string => {\n if (!configuredApiUrl) {\n throw new Error('API URL not configured. Please call configureApi() with your server URL before using any API functions.');\n }\n return configuredApiUrl;\n};\n\n// Get the configured API key or throw an error if not configured\nconst getApiKey = (): string => {\n if (!configuredApiKey) {\n throw new Error('API key not configured. Please call configureApi() with your API key before using any API functions.');\n }\n return configuredApiKey;\n};\n\n// Helper to get fetch options with connection pooling if available\nconst getFetchOptions = (apiUrl: string, options: RequestInit = {}): RequestInit | any => {\n const isHttps = apiUrl.startsWith('https:');\n \n // Only use agents in Node.js environment\n if (typeof window === 'undefined') {\n if (isHttps && httpsAgent) {\n // Using 'any' type to bypass TypeScript limitations with Node.js http.Agent\n return { ...options, agent: httpsAgent } as any;\n } else if (httpAgent) {\n return { ...options, agent: httpAgent } as any;\n }\n }\n \n // Browser environment\n const requestId = Date.now().toString(36) + Math.random().toString(36).substring(2);\n \n // Use keep-alive header in browser environments\n return {\n ...options,\n headers: {\n ...options.headers,\n 'Connection': 'keep-alive',\n 'X-Request-ID': requestId, // Add unique ID to track requests\n 'X-API-Key': getApiKey() // Add API key to headers\n }\n };\n};\n\nexport async function* streamChat(\n message: string,\n stream: boolean = true\n): AsyncGenerator<StreamResponse> {\n try {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/chat`, getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': stream ? 'text/event-stream' : 'application/json'\n },\n body: JSON.stringify({ message, stream }),\n }));\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error(`API request failed: ${response.status} ${errorText}`);\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n if (!stream) {\n // Handle non-streaming response\n const data = await response.json() as ChatResponse;\n yield {\n text: data.response,\n done: true\n };\n return;\n }\n \n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader available');\n\n const decoder = new TextDecoder();\n let buffer = '';\n let currentFullText = ''; // Track full response to detect duplicates\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n buffer += chunk;\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.trim() && line.startsWith('data: ')) {\n try {\n // Properly extract the JSON part by trimming whitespace after 'data:'\n const jsonText = line.slice(6).trim();\n const data = JSON.parse(jsonText);\n \n if (data.text) {\n // Check if this is a duplicate or overlapping chunk\n const newText = extractNewText(data.text, currentFullText);\n \n // Only yield if we have new text\n if (newText) {\n currentFullText += newText;\n yield {\n text: newText,\n done: data.done || false\n };\n } else if (data.done) {\n // Always send done signal even if no new text\n yield {\n text: '',\n done: true\n };\n }\n } else {\n // Pass through as-is if no text property\n yield {\n text: data.text || '',\n done: data.done || false\n };\n }\n } catch (error) {\n console.warn('Error parsing JSON chunk:', line, 'Error:', error);\n }\n }\n }\n }\n\n if (buffer && buffer.startsWith('data: ')) {\n try {\n // Properly extract the JSON part by trimming whitespace after 'data:'\n const jsonText = buffer.slice(6).trim();\n const data = JSON.parse(jsonText);\n \n if (data.text) {\n // Check for duplicates in final chunk\n const newText = extractNewText(data.text, currentFullText);\n if (newText || data.done) {\n yield {\n text: newText || '',\n done: data.done || false\n };\n }\n } else {\n yield {\n text: data.text || '',\n done: data.done || false\n };\n }\n } catch (error) {\n console.warn('Error parsing final JSON buffer:', buffer, 'Error:', error);\n }\n }\n } catch (error: any) {\n console.error('Chat API error:', error.message);\n yield { \n text: `Error connecting to chat server: ${error.message}`, \n done: true \n };\n }\n}\n\n// Helper function to extract only new text from incoming chunks\nfunction extractNewText(incomingText: string, currentText: string): string {\n // If we have no current text, all text is new\n if (!currentText) return incomingText;\n \n // Handle exact duplicates\n if (currentText.endsWith(incomingText)) return '';\n\n // If incoming text is larger, check if it's an expanded version\n if (incomingText.length > currentText.length) {\n // If incoming text contains all of current text at the beginning,\n // only return the new part\n if (incomingText.startsWith(currentText)) {\n return incomingText.slice(currentText.length);\n }\n \n // Sometimes the FastAPI server might send growing chunks like \"Hel\" -> \"Hello\" -> \"Hello wo\" -> \"Hello world\"\n // Find the longest common prefix\n let i = 0;\n const minLength = Math.min(currentText.length, incomingText.length);\n while (i < minLength && currentText[i] === incomingText[i]) {\n i++;\n }\n \n // If there's significant overlap, extract only the new part\n if (i > currentText.length / 2) {\n return incomingText.slice(i);\n }\n }\n \n // Default: return the full text (this handles non-overlapping chunks)\n return incomingText;\n}"],"names":["configuredApiUrl","configuredApiKey","configureApi","apiUrl","apiKey","getApiUrl","getApiKey","getFetchOptions","options","requestId","streamChat","message","stream","API_URL","response","errorText","reader","_a","decoder","buffer","currentFullText","done","value","chunk","lines","line","jsonText","data","newText","extractNewText","error","incomingText","currentText","i","minLength"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api.cjs","sources":["../api.ts"],"sourcesContent":["// For Node.js environments, we can use http.Agent for connection pooling\nlet httpAgent: any = null;\nlet httpsAgent: any = null;\n\n// Define the StreamResponse interface\nexport interface StreamResponse {\n text: string;\n done: boolean;\n}\n\nexport interface ChatResponse {\n response: string;\n}\n\n// MCP Protocol interfaces\ninterface MCPRequest {\n jsonrpc: \"2.0\";\n method: string;\n params: {\n name: string;\n arguments: {\n messages?: Array<{\n role: string;\n content: string;\n }>;\n stream?: boolean;\n tools?: Array<{\n name: string;\n parameters: Record<string, any>;\n }>;\n };\n };\n id: string;\n}\n\ninterface MCPResponse {\n jsonrpc: \"2.0\";\n id: string;\n result?: {\n type?: \"start\" | \"chunk\" | \"complete\";\n chunk?: {\n content: string;\n };\n output?: {\n messages: Array<{\n role: string;\n content: string;\n }>;\n };\n };\n error?: {\n code: number;\n message: string;\n };\n}\n\n// Store the configured API URL and key\nlet configuredApiUrl: string | null = null;\nlet configuredApiKey: string | null = null;\n\n// Configure the API with a custom URL and API key\nexport const configureApi = (apiUrl: string, apiKey: string): void => {\n if (!apiUrl || typeof apiUrl !== 'string') {\n throw new Error('API URL must be a valid string');\n }\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('API key must be a valid string');\n }\n configuredApiUrl = apiUrl;\n configuredApiKey = apiKey;\n}\n\n// Get the configured API URL or throw an error if not configured\nconst getApiUrl = (): string => {\n if (!configuredApiUrl) {\n throw new Error('API URL not configured. Please call configureApi() with your server URL before using any API functions.');\n }\n return configuredApiUrl;\n};\n\n// Get the configured API key or throw an error if not configured\nconst getApiKey = (): string => {\n if (!configuredApiKey) {\n throw new Error('API key not configured. Please call configureApi() with your API key before using any API functions.');\n }\n return configuredApiKey;\n};\n\n// Helper to get fetch options with connection pooling if available\nconst getFetchOptions = (apiUrl: string, options: RequestInit = {}): RequestInit | any => {\n const isHttps = apiUrl.startsWith('https:');\n \n // Only use agents in Node.js environment\n if (typeof window === 'undefined') {\n if (isHttps && httpsAgent) {\n return { ...options, agent: httpsAgent } as any;\n } else if (httpAgent) {\n return { ...options, agent: httpAgent } as any;\n }\n }\n \n // Browser environment\n const requestId = Date.now().toString(36) + Math.random().toString(36).substring(2);\n \n // Use keep-alive header in browser environments\n return {\n ...options,\n headers: {\n ...options.headers,\n 'Connection': 'keep-alive',\n 'X-Request-ID': requestId,\n 'X-API-Key': getApiKey()\n }\n };\n};\n\n// Create MCP request\nconst createMCPRequest = (message: string, stream: boolean = true): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"chat\",\n arguments: {\n messages: [\n { role: \"user\", content: message }\n ],\n stream\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\n// Create MCP tools request\nconst createMCPToolsRequest = (tools: Array<{ name: string; parameters: Record<string, any> }>): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"tools\",\n arguments: {\n tools\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\nexport async function* streamChat(\n message: string,\n stream: boolean = true\n): AsyncGenerator<StreamResponse> {\n try {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/v1/chat`, getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': stream ? 'text/event-stream' : 'application/json'\n },\n body: JSON.stringify(createMCPRequest(message, stream)),\n }));\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error(`API request failed: ${response.status} ${errorText}`);\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n if (!stream) {\n // Handle non-streaming response\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n if (data.result?.output?.messages?.[0]?.content) {\n yield {\n text: data.result.output.messages[0].content,\n done: true\n };\n }\n return;\n }\n \n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader available');\n\n const decoder = new TextDecoder();\n let buffer = '';\n let currentFullText = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n buffer += chunk;\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.trim() && line.startsWith('data: ')) {\n try {\n const jsonText = line.slice(6).trim();\n if (jsonText === '[DONE]') {\n yield { text: '', done: true };\n break;\n }\n\n const data = JSON.parse(jsonText) as MCPResponse;\n \n if (data.result) {\n let content = '';\n \n // Handle different response types\n if (data.result.type === 'start') {\n continue;\n } else if (data.result.type === 'chunk' && data.result.chunk) {\n content = data.result.chunk.content;\n } else if (data.result.type === 'complete' && data.result.output?.messages?.[0]) {\n content = data.result.output.messages[0].content;\n }\n\n if (content) {\n const newText = extractNewText(content, currentFullText);\n if (newText) {\n currentFullText += newText;\n yield {\n text: newText,\n done: data.result.type === 'complete'\n };\n } else if (data.result.type === 'complete') {\n yield { text: '', done: true };\n }\n }\n }\n } catch (error) {\n console.warn('Error parsing JSON chunk:', line, 'Error:', error);\n }\n }\n }\n }\n\n // Handle any remaining buffer\n if (buffer && buffer.startsWith('data: ')) {\n try {\n const jsonText = buffer.slice(6).trim();\n if (jsonText !== '[DONE]') {\n const data = JSON.parse(jsonText) as MCPResponse;\n if (data.result?.chunk?.content) {\n const newText = extractNewText(data.result.chunk.content, currentFullText);\n if (newText) {\n yield {\n text: newText,\n done: data.result.type === 'complete'\n };\n }\n }\n }\n } catch (error) {\n console.warn('Error parsing final JSON buffer:', buffer, 'Error:', error);\n }\n }\n } catch (error: any) {\n console.error('Chat API error:', error.message);\n yield { \n text: `Error connecting to chat server: ${error.message}`, \n done: true \n };\n }\n}\n\n// Helper function to extract only new text from incoming chunks\nfunction extractNewText(incomingText: string, currentText: string): string {\n if (!currentText) return incomingText;\n if (currentText.endsWith(incomingText)) return '';\n \n if (incomingText.length > currentText.length) {\n if (incomingText.startsWith(currentText)) {\n return incomingText.slice(currentText.length);\n }\n \n let i = 0;\n const minLength = Math.min(currentText.length, incomingText.length);\n while (i < minLength && currentText[i] === incomingText[i]) {\n i++;\n }\n \n if (i > currentText.length / 2) {\n return incomingText.slice(i);\n }\n }\n \n return incomingText;\n}\n\n// New function to send tools request\nexport async function sendToolsRequest(tools: Array<{ name: string; parameters: Record<string, any> }>): Promise<MCPResponse> {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/v1/chat`, getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(createMCPToolsRequest(tools)),\n }));\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n\n return data;\n}"],"names":["configuredApiUrl","configuredApiKey","configureApi","apiUrl","apiKey","getApiUrl","getApiKey","getFetchOptions","options","requestId","createMCPRequest","message","stream","createMCPToolsRequest","tools","streamChat","API_URL","response","errorText","data","_d","_c","_b","_a","reader","_e","decoder","buffer","currentFullText","done","value","chunk","lines","line","jsonText","content","_g","_f","newText","extractNewText","error","_i","_h","incomingText","currentText","i","minLength","sendToolsRequest"],"mappings":"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"}
|
package/dist/api.mjs
CHANGED
|
@@ -1,130 +1,174 @@
|
|
|
1
|
-
let
|
|
2
|
-
const
|
|
3
|
-
if (!t || typeof t != "string")
|
|
4
|
-
throw new Error("API URL must be a valid string");
|
|
1
|
+
let y = null, m = null;
|
|
2
|
+
const D = (e, t) => {
|
|
5
3
|
if (!e || typeof e != "string")
|
|
4
|
+
throw new Error("API URL must be a valid string");
|
|
5
|
+
if (!t || typeof t != "string")
|
|
6
6
|
throw new Error("API key must be a valid string");
|
|
7
|
-
|
|
8
|
-
},
|
|
9
|
-
if (!
|
|
7
|
+
y = e, m = t;
|
|
8
|
+
}, $ = () => {
|
|
9
|
+
if (!y)
|
|
10
10
|
throw new Error("API URL not configured. Please call configureApi() with your server URL before using any API functions.");
|
|
11
|
-
return
|
|
12
|
-
},
|
|
13
|
-
if (!
|
|
11
|
+
return y;
|
|
12
|
+
}, j = () => {
|
|
13
|
+
if (!m)
|
|
14
14
|
throw new Error("API key not configured. Please call configureApi() with your API key before using any API functions.");
|
|
15
|
-
return
|
|
16
|
-
},
|
|
17
|
-
|
|
15
|
+
return m;
|
|
16
|
+
}, v = (e, t = {}) => {
|
|
17
|
+
e.startsWith("https:");
|
|
18
18
|
const r = Date.now().toString(36) + Math.random().toString(36).substring(2);
|
|
19
19
|
return {
|
|
20
|
-
...
|
|
20
|
+
...t,
|
|
21
21
|
headers: {
|
|
22
|
-
...
|
|
22
|
+
...t.headers,
|
|
23
23
|
Connection: "keep-alive",
|
|
24
24
|
"X-Request-ID": r,
|
|
25
|
-
|
|
26
|
-
"X-API-Key": b()
|
|
27
|
-
// Add API key to headers
|
|
25
|
+
"X-API-Key": j()
|
|
28
26
|
}
|
|
29
27
|
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
}, C = (e, t = !0) => ({
|
|
29
|
+
jsonrpc: "2.0",
|
|
30
|
+
method: "tools/call",
|
|
31
|
+
params: {
|
|
32
|
+
name: "chat",
|
|
33
|
+
arguments: {
|
|
34
|
+
messages: [
|
|
35
|
+
{ role: "user", content: e }
|
|
36
|
+
],
|
|
37
|
+
stream: t
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
id: Date.now().toString(36) + Math.random().toString(36).substring(2)
|
|
41
|
+
}), M = (e) => ({
|
|
42
|
+
jsonrpc: "2.0",
|
|
43
|
+
method: "tools/call",
|
|
44
|
+
params: {
|
|
45
|
+
name: "tools",
|
|
46
|
+
arguments: {
|
|
47
|
+
tools: e
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
id: Date.now().toString(36) + Math.random().toString(36).substring(2)
|
|
51
|
+
});
|
|
52
|
+
async function* q(e, t = !0) {
|
|
53
|
+
var r, s, u, A, P, k, E, b, I;
|
|
33
54
|
try {
|
|
34
|
-
const
|
|
55
|
+
const c = $(), i = await fetch(`${c}/v1/chat`, v(c, {
|
|
35
56
|
method: "POST",
|
|
36
57
|
headers: {
|
|
37
58
|
"Content-Type": "application/json",
|
|
38
|
-
Accept:
|
|
59
|
+
Accept: t ? "text/event-stream" : "application/json"
|
|
39
60
|
},
|
|
40
|
-
body: JSON.stringify(
|
|
61
|
+
body: JSON.stringify(C(e, t))
|
|
41
62
|
}));
|
|
42
63
|
if (!i.ok) {
|
|
43
64
|
const o = await i.text();
|
|
44
65
|
throw console.error(`API request failed: ${i.status} ${o}`), new Error(`Network response was not ok: ${i.status} ${o}`);
|
|
45
66
|
}
|
|
46
|
-
if (!
|
|
47
|
-
|
|
48
|
-
|
|
67
|
+
if (!t) {
|
|
68
|
+
const o = await i.json();
|
|
69
|
+
if (o.error)
|
|
70
|
+
throw new Error(`MCP Error: ${o.error.message}`);
|
|
71
|
+
(A = (u = (s = (r = o.result) == null ? void 0 : r.output) == null ? void 0 : s.messages) == null ? void 0 : u[0]) != null && A.content && (yield {
|
|
72
|
+
text: o.result.output.messages[0].content,
|
|
49
73
|
done: !0
|
|
50
|
-
};
|
|
74
|
+
});
|
|
51
75
|
return;
|
|
52
76
|
}
|
|
53
|
-
const
|
|
54
|
-
if (!
|
|
55
|
-
const
|
|
56
|
-
let a = "",
|
|
77
|
+
const S = (P = i.body) == null ? void 0 : P.getReader();
|
|
78
|
+
if (!S) throw new Error("No reader available");
|
|
79
|
+
const R = new TextDecoder();
|
|
80
|
+
let a = "", w = "";
|
|
57
81
|
for (; ; ) {
|
|
58
|
-
const { done: o, value:
|
|
82
|
+
const { done: o, value: l } = await S.read();
|
|
59
83
|
if (o) break;
|
|
60
|
-
const
|
|
61
|
-
a +=
|
|
62
|
-
const
|
|
84
|
+
const f = R.decode(l, { stream: !0 });
|
|
85
|
+
a += f;
|
|
86
|
+
const N = a.split(`
|
|
63
87
|
`);
|
|
64
|
-
a =
|
|
65
|
-
for (const
|
|
66
|
-
if (
|
|
88
|
+
a = N.pop() || "";
|
|
89
|
+
for (const h of N)
|
|
90
|
+
if (h.trim() && h.startsWith("data: "))
|
|
67
91
|
try {
|
|
68
|
-
const
|
|
69
|
-
if (
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
92
|
+
const d = h.slice(6).trim();
|
|
93
|
+
if (d === "[DONE]") {
|
|
94
|
+
yield { text: "", done: !0 };
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
const n = JSON.parse(d);
|
|
98
|
+
if (n.result) {
|
|
99
|
+
let p = "";
|
|
100
|
+
if (n.result.type === "start")
|
|
101
|
+
continue;
|
|
102
|
+
if (n.result.type === "chunk" && n.result.chunk ? p = n.result.chunk.content : n.result.type === "complete" && ((E = (k = n.result.output) == null ? void 0 : k.messages) != null && E[0]) && (p = n.result.output.messages[0].content), p) {
|
|
103
|
+
const g = O(p, w);
|
|
104
|
+
g ? (w += g, yield {
|
|
105
|
+
text: g,
|
|
106
|
+
done: n.result.type === "complete"
|
|
107
|
+
}) : n.result.type === "complete" && (yield { text: "", done: !0 });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch (d) {
|
|
111
|
+
console.warn("Error parsing JSON chunk:", h, "Error:", d);
|
|
85
112
|
}
|
|
86
113
|
}
|
|
87
114
|
if (a && a.startsWith("data: "))
|
|
88
115
|
try {
|
|
89
|
-
const o = a.slice(6).trim()
|
|
90
|
-
if (
|
|
91
|
-
const
|
|
92
|
-
(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
};
|
|
116
|
+
const o = a.slice(6).trim();
|
|
117
|
+
if (o !== "[DONE]") {
|
|
118
|
+
const l = JSON.parse(o);
|
|
119
|
+
if ((I = (b = l.result) == null ? void 0 : b.chunk) != null && I.content) {
|
|
120
|
+
const f = O(l.result.chunk.content, w);
|
|
121
|
+
f && (yield {
|
|
122
|
+
text: f,
|
|
123
|
+
done: l.result.type === "complete"
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
101
127
|
} catch (o) {
|
|
102
128
|
console.warn("Error parsing final JSON buffer:", a, "Error:", o);
|
|
103
129
|
}
|
|
104
|
-
} catch (
|
|
105
|
-
console.error("Chat API error:",
|
|
106
|
-
text: `Error connecting to chat server: ${
|
|
130
|
+
} catch (c) {
|
|
131
|
+
console.error("Chat API error:", c.message), yield {
|
|
132
|
+
text: `Error connecting to chat server: ${c.message}`,
|
|
107
133
|
done: !0
|
|
108
134
|
};
|
|
109
135
|
}
|
|
110
136
|
}
|
|
111
|
-
function
|
|
112
|
-
if (!
|
|
113
|
-
if (
|
|
114
|
-
if (
|
|
115
|
-
if (
|
|
116
|
-
return
|
|
137
|
+
function O(e, t) {
|
|
138
|
+
if (!t) return e;
|
|
139
|
+
if (t.endsWith(e)) return "";
|
|
140
|
+
if (e.length > t.length) {
|
|
141
|
+
if (e.startsWith(t))
|
|
142
|
+
return e.slice(t.length);
|
|
117
143
|
let r = 0;
|
|
118
|
-
const s = Math.min(
|
|
119
|
-
for (; r < s &&
|
|
144
|
+
const s = Math.min(t.length, e.length);
|
|
145
|
+
for (; r < s && t[r] === e[r]; )
|
|
120
146
|
r++;
|
|
121
|
-
if (r >
|
|
122
|
-
return
|
|
147
|
+
if (r > t.length / 2)
|
|
148
|
+
return e.slice(r);
|
|
149
|
+
}
|
|
150
|
+
return e;
|
|
151
|
+
}
|
|
152
|
+
async function J(e) {
|
|
153
|
+
const t = $(), r = await fetch(`${t}/v1/chat`, v(t, {
|
|
154
|
+
method: "POST",
|
|
155
|
+
headers: {
|
|
156
|
+
"Content-Type": "application/json"
|
|
157
|
+
},
|
|
158
|
+
body: JSON.stringify(M(e))
|
|
159
|
+
}));
|
|
160
|
+
if (!r.ok) {
|
|
161
|
+
const u = await r.text();
|
|
162
|
+
throw new Error(`Network response was not ok: ${r.status} ${u}`);
|
|
123
163
|
}
|
|
124
|
-
|
|
164
|
+
const s = await r.json();
|
|
165
|
+
if (s.error)
|
|
166
|
+
throw new Error(`MCP Error: ${s.error.message}`);
|
|
167
|
+
return s;
|
|
125
168
|
}
|
|
126
169
|
export {
|
|
127
|
-
|
|
128
|
-
|
|
170
|
+
D as configureApi,
|
|
171
|
+
J as sendToolsRequest,
|
|
172
|
+
q as streamChat
|
|
129
173
|
};
|
|
130
174
|
//# sourceMappingURL=api.mjs.map
|
package/dist/api.mjs.d.ts
CHANGED
|
@@ -1,9 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
text?: string;
|
|
3
|
-
content?: string;
|
|
4
|
-
done?: boolean;
|
|
5
|
-
type?: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function configureApi(apiUrl: string, apiKey?: string): void;
|
|
9
|
-
export function streamChat(message: string, voiceEnabled: boolean): AsyncGenerator<StreamResponse>;
|
|
1
|
+
export * from "../api.d.ts";
|
package/dist/api.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.mjs","sources":["../api.ts"],"sourcesContent":["// For Node.js environments, we can use http.Agent for connection pooling\nlet httpAgent: any = null;\nlet httpsAgent: any = null;\n\n// Define the StreamResponse interface\nexport interface StreamResponse {\n text: string;\n done: boolean;\n}\n\nexport interface ChatResponse {\n response: string;\n}\n\n// Store the configured API URL and key\nlet configuredApiUrl: string | null = null;\nlet configuredApiKey: string | null = null;\n\n// Configure the API with a custom URL and API key\nexport const configureApi = (apiUrl: string, apiKey: string): void => {\n if (!apiUrl || typeof apiUrl !== 'string') {\n throw new Error('API URL must be a valid string');\n }\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('API key must be a valid string');\n }\n configuredApiUrl = apiUrl;\n configuredApiKey = apiKey;\n}\n\n// Get the configured API URL or throw an error if not configured\nconst getApiUrl = (): string => {\n if (!configuredApiUrl) {\n throw new Error('API URL not configured. Please call configureApi() with your server URL before using any API functions.');\n }\n return configuredApiUrl;\n};\n\n// Get the configured API key or throw an error if not configured\nconst getApiKey = (): string => {\n if (!configuredApiKey) {\n throw new Error('API key not configured. Please call configureApi() with your API key before using any API functions.');\n }\n return configuredApiKey;\n};\n\n// Helper to get fetch options with connection pooling if available\nconst getFetchOptions = (apiUrl: string, options: RequestInit = {}): RequestInit | any => {\n const isHttps = apiUrl.startsWith('https:');\n \n // Only use agents in Node.js environment\n if (typeof window === 'undefined') {\n if (isHttps && httpsAgent) {\n // Using 'any' type to bypass TypeScript limitations with Node.js http.Agent\n return { ...options, agent: httpsAgent } as any;\n } else if (httpAgent) {\n return { ...options, agent: httpAgent } as any;\n }\n }\n \n // Browser environment\n const requestId = Date.now().toString(36) + Math.random().toString(36).substring(2);\n \n // Use keep-alive header in browser environments\n return {\n ...options,\n headers: {\n ...options.headers,\n 'Connection': 'keep-alive',\n 'X-Request-ID': requestId, // Add unique ID to track requests\n 'X-API-Key': getApiKey() // Add API key to headers\n }\n };\n};\n\nexport async function* streamChat(\n message: string,\n stream: boolean = true\n): AsyncGenerator<StreamResponse> {\n try {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/chat`, getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': stream ? 'text/event-stream' : 'application/json'\n },\n body: JSON.stringify({ message, stream }),\n }));\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error(`API request failed: ${response.status} ${errorText}`);\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n if (!stream) {\n // Handle non-streaming response\n const data = await response.json() as ChatResponse;\n yield {\n text: data.response,\n done: true\n };\n return;\n }\n \n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader available');\n\n const decoder = new TextDecoder();\n let buffer = '';\n let currentFullText = ''; // Track full response to detect duplicates\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n buffer += chunk;\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.trim() && line.startsWith('data: ')) {\n try {\n // Properly extract the JSON part by trimming whitespace after 'data:'\n const jsonText = line.slice(6).trim();\n const data = JSON.parse(jsonText);\n \n if (data.text) {\n // Check if this is a duplicate or overlapping chunk\n const newText = extractNewText(data.text, currentFullText);\n \n // Only yield if we have new text\n if (newText) {\n currentFullText += newText;\n yield {\n text: newText,\n done: data.done || false\n };\n } else if (data.done) {\n // Always send done signal even if no new text\n yield {\n text: '',\n done: true\n };\n }\n } else {\n // Pass through as-is if no text property\n yield {\n text: data.text || '',\n done: data.done || false\n };\n }\n } catch (error) {\n console.warn('Error parsing JSON chunk:', line, 'Error:', error);\n }\n }\n }\n }\n\n if (buffer && buffer.startsWith('data: ')) {\n try {\n // Properly extract the JSON part by trimming whitespace after 'data:'\n const jsonText = buffer.slice(6).trim();\n const data = JSON.parse(jsonText);\n \n if (data.text) {\n // Check for duplicates in final chunk\n const newText = extractNewText(data.text, currentFullText);\n if (newText || data.done) {\n yield {\n text: newText || '',\n done: data.done || false\n };\n }\n } else {\n yield {\n text: data.text || '',\n done: data.done || false\n };\n }\n } catch (error) {\n console.warn('Error parsing final JSON buffer:', buffer, 'Error:', error);\n }\n }\n } catch (error: any) {\n console.error('Chat API error:', error.message);\n yield { \n text: `Error connecting to chat server: ${error.message}`, \n done: true \n };\n }\n}\n\n// Helper function to extract only new text from incoming chunks\nfunction extractNewText(incomingText: string, currentText: string): string {\n // If we have no current text, all text is new\n if (!currentText) return incomingText;\n \n // Handle exact duplicates\n if (currentText.endsWith(incomingText)) return '';\n\n // If incoming text is larger, check if it's an expanded version\n if (incomingText.length > currentText.length) {\n // If incoming text contains all of current text at the beginning,\n // only return the new part\n if (incomingText.startsWith(currentText)) {\n return incomingText.slice(currentText.length);\n }\n \n // Sometimes the FastAPI server might send growing chunks like \"Hel\" -> \"Hello\" -> \"Hello wo\" -> \"Hello world\"\n // Find the longest common prefix\n let i = 0;\n const minLength = Math.min(currentText.length, incomingText.length);\n while (i < minLength && currentText[i] === incomingText[i]) {\n i++;\n }\n \n // If there's significant overlap, extract only the new part\n if (i > currentText.length / 2) {\n return incomingText.slice(i);\n }\n }\n \n // Default: return the full text (this handles non-overlapping chunks)\n return incomingText;\n}"],"names":["configuredApiUrl","configuredApiKey","configureApi","apiUrl","apiKey","getApiUrl","getApiKey","getFetchOptions","options","requestId","streamChat","message","stream","_a","API_URL","response","errorText","reader","decoder","buffer","currentFullText","done","value","chunk","lines","line","jsonText","data","newText","extractNewText","error","incomingText","currentText","i","minLength"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api.mjs","sources":["../api.ts"],"sourcesContent":["// For Node.js environments, we can use http.Agent for connection pooling\nlet httpAgent: any = null;\nlet httpsAgent: any = null;\n\n// Define the StreamResponse interface\nexport interface StreamResponse {\n text: string;\n done: boolean;\n}\n\nexport interface ChatResponse {\n response: string;\n}\n\n// MCP Protocol interfaces\ninterface MCPRequest {\n jsonrpc: \"2.0\";\n method: string;\n params: {\n name: string;\n arguments: {\n messages?: Array<{\n role: string;\n content: string;\n }>;\n stream?: boolean;\n tools?: Array<{\n name: string;\n parameters: Record<string, any>;\n }>;\n };\n };\n id: string;\n}\n\ninterface MCPResponse {\n jsonrpc: \"2.0\";\n id: string;\n result?: {\n type?: \"start\" | \"chunk\" | \"complete\";\n chunk?: {\n content: string;\n };\n output?: {\n messages: Array<{\n role: string;\n content: string;\n }>;\n };\n };\n error?: {\n code: number;\n message: string;\n };\n}\n\n// Store the configured API URL and key\nlet configuredApiUrl: string | null = null;\nlet configuredApiKey: string | null = null;\n\n// Configure the API with a custom URL and API key\nexport const configureApi = (apiUrl: string, apiKey: string): void => {\n if (!apiUrl || typeof apiUrl !== 'string') {\n throw new Error('API URL must be a valid string');\n }\n if (!apiKey || typeof apiKey !== 'string') {\n throw new Error('API key must be a valid string');\n }\n configuredApiUrl = apiUrl;\n configuredApiKey = apiKey;\n}\n\n// Get the configured API URL or throw an error if not configured\nconst getApiUrl = (): string => {\n if (!configuredApiUrl) {\n throw new Error('API URL not configured. Please call configureApi() with your server URL before using any API functions.');\n }\n return configuredApiUrl;\n};\n\n// Get the configured API key or throw an error if not configured\nconst getApiKey = (): string => {\n if (!configuredApiKey) {\n throw new Error('API key not configured. Please call configureApi() with your API key before using any API functions.');\n }\n return configuredApiKey;\n};\n\n// Helper to get fetch options with connection pooling if available\nconst getFetchOptions = (apiUrl: string, options: RequestInit = {}): RequestInit | any => {\n const isHttps = apiUrl.startsWith('https:');\n \n // Only use agents in Node.js environment\n if (typeof window === 'undefined') {\n if (isHttps && httpsAgent) {\n return { ...options, agent: httpsAgent } as any;\n } else if (httpAgent) {\n return { ...options, agent: httpAgent } as any;\n }\n }\n \n // Browser environment\n const requestId = Date.now().toString(36) + Math.random().toString(36).substring(2);\n \n // Use keep-alive header in browser environments\n return {\n ...options,\n headers: {\n ...options.headers,\n 'Connection': 'keep-alive',\n 'X-Request-ID': requestId,\n 'X-API-Key': getApiKey()\n }\n };\n};\n\n// Create MCP request\nconst createMCPRequest = (message: string, stream: boolean = true): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"chat\",\n arguments: {\n messages: [\n { role: \"user\", content: message }\n ],\n stream\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\n// Create MCP tools request\nconst createMCPToolsRequest = (tools: Array<{ name: string; parameters: Record<string, any> }>): MCPRequest => {\n return {\n jsonrpc: \"2.0\",\n method: \"tools/call\",\n params: {\n name: \"tools\",\n arguments: {\n tools\n }\n },\n id: Date.now().toString(36) + Math.random().toString(36).substring(2)\n };\n};\n\nexport async function* streamChat(\n message: string,\n stream: boolean = true\n): AsyncGenerator<StreamResponse> {\n try {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/v1/chat`, getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': stream ? 'text/event-stream' : 'application/json'\n },\n body: JSON.stringify(createMCPRequest(message, stream)),\n }));\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error(`API request failed: ${response.status} ${errorText}`);\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n if (!stream) {\n // Handle non-streaming response\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n if (data.result?.output?.messages?.[0]?.content) {\n yield {\n text: data.result.output.messages[0].content,\n done: true\n };\n }\n return;\n }\n \n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader available');\n\n const decoder = new TextDecoder();\n let buffer = '';\n let currentFullText = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n const chunk = decoder.decode(value, { stream: true });\n buffer += chunk;\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.trim() && line.startsWith('data: ')) {\n try {\n const jsonText = line.slice(6).trim();\n if (jsonText === '[DONE]') {\n yield { text: '', done: true };\n break;\n }\n\n const data = JSON.parse(jsonText) as MCPResponse;\n \n if (data.result) {\n let content = '';\n \n // Handle different response types\n if (data.result.type === 'start') {\n continue;\n } else if (data.result.type === 'chunk' && data.result.chunk) {\n content = data.result.chunk.content;\n } else if (data.result.type === 'complete' && data.result.output?.messages?.[0]) {\n content = data.result.output.messages[0].content;\n }\n\n if (content) {\n const newText = extractNewText(content, currentFullText);\n if (newText) {\n currentFullText += newText;\n yield {\n text: newText,\n done: data.result.type === 'complete'\n };\n } else if (data.result.type === 'complete') {\n yield { text: '', done: true };\n }\n }\n }\n } catch (error) {\n console.warn('Error parsing JSON chunk:', line, 'Error:', error);\n }\n }\n }\n }\n\n // Handle any remaining buffer\n if (buffer && buffer.startsWith('data: ')) {\n try {\n const jsonText = buffer.slice(6).trim();\n if (jsonText !== '[DONE]') {\n const data = JSON.parse(jsonText) as MCPResponse;\n if (data.result?.chunk?.content) {\n const newText = extractNewText(data.result.chunk.content, currentFullText);\n if (newText) {\n yield {\n text: newText,\n done: data.result.type === 'complete'\n };\n }\n }\n }\n } catch (error) {\n console.warn('Error parsing final JSON buffer:', buffer, 'Error:', error);\n }\n }\n } catch (error: any) {\n console.error('Chat API error:', error.message);\n yield { \n text: `Error connecting to chat server: ${error.message}`, \n done: true \n };\n }\n}\n\n// Helper function to extract only new text from incoming chunks\nfunction extractNewText(incomingText: string, currentText: string): string {\n if (!currentText) return incomingText;\n if (currentText.endsWith(incomingText)) return '';\n \n if (incomingText.length > currentText.length) {\n if (incomingText.startsWith(currentText)) {\n return incomingText.slice(currentText.length);\n }\n \n let i = 0;\n const minLength = Math.min(currentText.length, incomingText.length);\n while (i < minLength && currentText[i] === incomingText[i]) {\n i++;\n }\n \n if (i > currentText.length / 2) {\n return incomingText.slice(i);\n }\n }\n \n return incomingText;\n}\n\n// New function to send tools request\nexport async function sendToolsRequest(tools: Array<{ name: string; parameters: Record<string, any> }>): Promise<MCPResponse> {\n const API_URL = getApiUrl();\n \n const response = await fetch(`${API_URL}/v1/chat`, getFetchOptions(API_URL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(createMCPToolsRequest(tools)),\n }));\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Network response was not ok: ${response.status} ${errorText}`);\n }\n\n const data = await response.json() as MCPResponse;\n if (data.error) {\n throw new Error(`MCP Error: ${data.error.message}`);\n }\n\n return data;\n}"],"names":["configuredApiUrl","configuredApiKey","configureApi","apiUrl","apiKey","getApiUrl","getApiKey","getFetchOptions","options","requestId","createMCPRequest","message","stream","createMCPToolsRequest","tools","streamChat","_a","_b","_c","_d","_e","_f","_g","_h","_i","API_URL","response","errorText","data","reader","decoder","buffer","currentFullText","done","value","chunk","lines","line","jsonText","content","newText","extractNewText","error","incomingText","currentText","i","minLength","sendToolsRequest"],"mappings":"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"}
|