ai.matey.react.core 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/cjs/index.js +18 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/types.js +10 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/use-chat.js +418 -0
- package/dist/cjs/use-chat.js.map +1 -0
- package/dist/cjs/use-completion.js +193 -0
- package/dist/cjs/use-completion.js.map +1 -0
- package/dist/cjs/use-object.js +250 -0
- package/dist/cjs/use-object.js.map +1 -0
- package/dist/esm/index.js +12 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/types.js +9 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/use-chat.js +415 -0
- package/dist/esm/use-chat.js.map +1 -0
- package/dist/esm/use-completion.js +190 -0
- package/dist/esm/use-completion.js.map +1 -0
- package/dist/esm/use-object.js +247 -0
- package/dist/esm/use-object.js.map +1 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/types.d.ts +295 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/use-chat.d.ts +73 -0
- package/dist/types/use-chat.d.ts.map +1 -0
- package/dist/types/use-completion.d.ts +37 -0
- package/dist/types/use-completion.d.ts.map +1 -0
- package/dist/types/use-object.d.ts +47 -0
- package/dist/types/use-object.d.ts.map +1 -0
- package/package.json +78 -0
- package/readme.md +232 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useChat Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for building chat interfaces with streaming support.
|
|
5
|
+
* Supports both HTTP API mode and direct backend mode.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { useState, useCallback, useRef, useId, useEffect } from 'react';
|
|
10
|
+
import { createChat } from 'ai.matey.wrapper';
|
|
11
|
+
/**
|
|
12
|
+
* Generate a unique ID.
|
|
13
|
+
*/
|
|
14
|
+
function generateUniqueId() {
|
|
15
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Convert React Message to IR message format.
|
|
19
|
+
*/
|
|
20
|
+
function messageToIR(message) {
|
|
21
|
+
return {
|
|
22
|
+
role: message.role,
|
|
23
|
+
content: message.content,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* useChat - React hook for chat interfaces.
|
|
28
|
+
*
|
|
29
|
+
* Provides state management, streaming, and utilities for building
|
|
30
|
+
* chat applications with AI backends.
|
|
31
|
+
*
|
|
32
|
+
* Supports two modes:
|
|
33
|
+
* 1. HTTP Mode (default): Uses `api` endpoint with fetch
|
|
34
|
+
* 2. Direct Mode: Uses `direct.backend` for direct backend access
|
|
35
|
+
*
|
|
36
|
+
* @example HTTP Mode
|
|
37
|
+
* ```tsx
|
|
38
|
+
* import { useChat } from 'ai.matey.react.core';
|
|
39
|
+
*
|
|
40
|
+
* function ChatComponent() {
|
|
41
|
+
* const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
|
|
42
|
+
* api: '/api/chat',
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* return (
|
|
46
|
+
* <div>
|
|
47
|
+
* {messages.map((m) => (
|
|
48
|
+
* <div key={m.id}>{m.role}: {m.content}</div>
|
|
49
|
+
* ))}
|
|
50
|
+
* <form onSubmit={handleSubmit}>
|
|
51
|
+
* <input value={input} onChange={handleInputChange} />
|
|
52
|
+
* <button type="submit" disabled={isLoading}>Send</button>
|
|
53
|
+
* </form>
|
|
54
|
+
* </div>
|
|
55
|
+
* );
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @example Direct Mode
|
|
60
|
+
* ```tsx
|
|
61
|
+
* import { useChat } from 'ai.matey.react.core';
|
|
62
|
+
* import { AnthropicBackend } from 'ai.matey.backend/anthropic';
|
|
63
|
+
*
|
|
64
|
+
* const backend = new AnthropicBackend({ apiKey: process.env.ANTHROPIC_API_KEY });
|
|
65
|
+
*
|
|
66
|
+
* function ChatComponent() {
|
|
67
|
+
* const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
|
|
68
|
+
* direct: {
|
|
69
|
+
* backend,
|
|
70
|
+
* systemPrompt: 'You are a helpful assistant.',
|
|
71
|
+
* },
|
|
72
|
+
* });
|
|
73
|
+
*
|
|
74
|
+
* return (
|
|
75
|
+
* <div>
|
|
76
|
+
* {messages.map((m) => (
|
|
77
|
+
* <div key={m.id}>{m.role}: {m.content}</div>
|
|
78
|
+
* ))}
|
|
79
|
+
* <form onSubmit={handleSubmit}>
|
|
80
|
+
* <input value={input} onChange={handleInputChange} />
|
|
81
|
+
* <button type="submit" disabled={isLoading}>Send</button>
|
|
82
|
+
* </form>
|
|
83
|
+
* </div>
|
|
84
|
+
* );
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export function useChat(options = {}) {
|
|
89
|
+
const { initialMessages = [], initialInput = '', id,
|
|
90
|
+
// HTTP mode options
|
|
91
|
+
api = '/api/chat', headers = {}, body = {}, streamProtocol = 'data', onResponse,
|
|
92
|
+
// Direct mode options
|
|
93
|
+
direct,
|
|
94
|
+
// Common options
|
|
95
|
+
generateId = generateUniqueId, onFinish, onError, keepLastMessageOnError = true, maxToolRoundtrips = 0, sendExtraMessageFields = false, } = options;
|
|
96
|
+
// Determine mode
|
|
97
|
+
const isDirectMode = !!direct;
|
|
98
|
+
// Generate a stable ID for this chat instance
|
|
99
|
+
const hookId = useId();
|
|
100
|
+
const chatId = id ?? hookId;
|
|
101
|
+
// State
|
|
102
|
+
const [messages, setMessages] = useState(initialMessages);
|
|
103
|
+
const [input, setInput] = useState(initialInput);
|
|
104
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
105
|
+
const [error, setError] = useState(undefined);
|
|
106
|
+
const [data, _setData] = useState(undefined);
|
|
107
|
+
// Refs
|
|
108
|
+
const abortControllerRef = useRef(null);
|
|
109
|
+
const chatRef = useRef(null);
|
|
110
|
+
// Create Chat instance for direct mode
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (isDirectMode && direct) {
|
|
113
|
+
chatRef.current = createChat({
|
|
114
|
+
backend: direct.backend,
|
|
115
|
+
systemPrompt: direct.systemPrompt,
|
|
116
|
+
defaultParameters: direct.defaultParameters,
|
|
117
|
+
tools: direct.tools,
|
|
118
|
+
onToolCall: direct.onToolCall,
|
|
119
|
+
autoExecuteTools: direct.autoExecuteTools,
|
|
120
|
+
maxToolRounds: direct.maxToolRounds ?? maxToolRoundtrips,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return () => {
|
|
124
|
+
chatRef.current = null;
|
|
125
|
+
};
|
|
126
|
+
}, [isDirectMode, direct, maxToolRoundtrips]);
|
|
127
|
+
/**
|
|
128
|
+
* Handle input change from form elements.
|
|
129
|
+
*/
|
|
130
|
+
const handleInputChange = useCallback((e) => {
|
|
131
|
+
setInput(e.target.value);
|
|
132
|
+
}, []);
|
|
133
|
+
/**
|
|
134
|
+
* Stop current streaming request.
|
|
135
|
+
*/
|
|
136
|
+
const stop = useCallback(() => {
|
|
137
|
+
if (abortControllerRef.current) {
|
|
138
|
+
abortControllerRef.current.abort();
|
|
139
|
+
abortControllerRef.current = null;
|
|
140
|
+
}
|
|
141
|
+
}, []);
|
|
142
|
+
/**
|
|
143
|
+
* Send request in direct mode using wrapper-ir Chat.
|
|
144
|
+
*/
|
|
145
|
+
const sendDirectRequest = useCallback(async (messagesToSend, _requestOptions) => {
|
|
146
|
+
const chat = chatRef.current;
|
|
147
|
+
if (!chat) {
|
|
148
|
+
throw new Error('Chat instance not initialized');
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
setIsLoading(true);
|
|
152
|
+
setError(undefined);
|
|
153
|
+
// Create abort controller
|
|
154
|
+
abortControllerRef.current = new AbortController();
|
|
155
|
+
const { signal } = abortControllerRef.current;
|
|
156
|
+
// Clear chat and restore messages
|
|
157
|
+
chat.clear();
|
|
158
|
+
for (const msg of messagesToSend.slice(0, -1)) {
|
|
159
|
+
chat.addMessage(messageToIR(msg));
|
|
160
|
+
}
|
|
161
|
+
// Get the last user message content
|
|
162
|
+
const lastMessage = messagesToSend[messagesToSend.length - 1];
|
|
163
|
+
if (!lastMessage || lastMessage.role !== 'user') {
|
|
164
|
+
throw new Error('Last message must be a user message');
|
|
165
|
+
}
|
|
166
|
+
// Add placeholder assistant message
|
|
167
|
+
const assistantId = generateId();
|
|
168
|
+
const assistantMessage = {
|
|
169
|
+
id: assistantId,
|
|
170
|
+
role: 'assistant',
|
|
171
|
+
content: '',
|
|
172
|
+
createdAt: new Date(),
|
|
173
|
+
};
|
|
174
|
+
setMessages((prev) => [...prev, assistantMessage]);
|
|
175
|
+
// Stream the response
|
|
176
|
+
const response = await chat.stream(lastMessage.content, {
|
|
177
|
+
signal,
|
|
178
|
+
onChunk: ({ accumulated }) => {
|
|
179
|
+
setMessages((prev) => prev.map((msg) => (msg.id === assistantId ? { ...msg, content: accumulated } : msg)));
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
// Finalize message
|
|
183
|
+
const finalMessage = {
|
|
184
|
+
id: assistantId,
|
|
185
|
+
role: 'assistant',
|
|
186
|
+
content: response.content,
|
|
187
|
+
createdAt: new Date(),
|
|
188
|
+
};
|
|
189
|
+
setMessages((prev) => prev.map((msg) => (msg.id === assistantId ? finalMessage : msg)));
|
|
190
|
+
onFinish?.(finalMessage);
|
|
191
|
+
return response.content;
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
198
|
+
setError(error);
|
|
199
|
+
onError?.(error);
|
|
200
|
+
if (!keepLastMessageOnError) {
|
|
201
|
+
setMessages((prev) => prev.slice(0, -1));
|
|
202
|
+
}
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
setIsLoading(false);
|
|
207
|
+
abortControllerRef.current = null;
|
|
208
|
+
}
|
|
209
|
+
}, [generateId, onFinish, onError, keepLastMessageOnError]);
|
|
210
|
+
/**
|
|
211
|
+
* Send request in HTTP mode using fetch.
|
|
212
|
+
*/
|
|
213
|
+
const sendHttpRequest = useCallback(async (messagesToSend, requestOptions) => {
|
|
214
|
+
try {
|
|
215
|
+
setIsLoading(true);
|
|
216
|
+
setError(undefined);
|
|
217
|
+
// Create abort controller
|
|
218
|
+
abortControllerRef.current = new AbortController();
|
|
219
|
+
const { signal } = abortControllerRef.current;
|
|
220
|
+
// Prepare request body
|
|
221
|
+
const requestBody = {
|
|
222
|
+
messages: sendExtraMessageFields
|
|
223
|
+
? messagesToSend
|
|
224
|
+
: messagesToSend.map(({ role, content }) => ({ role, content })),
|
|
225
|
+
id: chatId,
|
|
226
|
+
...body,
|
|
227
|
+
...requestOptions?.body,
|
|
228
|
+
};
|
|
229
|
+
// Make request
|
|
230
|
+
const response = await fetch(api, {
|
|
231
|
+
method: 'POST',
|
|
232
|
+
headers: {
|
|
233
|
+
'Content-Type': 'application/json',
|
|
234
|
+
...headers,
|
|
235
|
+
...requestOptions?.headers,
|
|
236
|
+
},
|
|
237
|
+
body: JSON.stringify(requestBody),
|
|
238
|
+
signal,
|
|
239
|
+
});
|
|
240
|
+
// Call onResponse callback
|
|
241
|
+
onResponse?.(response);
|
|
242
|
+
if (!response.ok) {
|
|
243
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
244
|
+
}
|
|
245
|
+
if (!response.body) {
|
|
246
|
+
throw new Error('Response body is null');
|
|
247
|
+
}
|
|
248
|
+
// Handle streaming response
|
|
249
|
+
const reader = response.body.getReader();
|
|
250
|
+
const decoder = new TextDecoder();
|
|
251
|
+
let assistantContent = '';
|
|
252
|
+
const assistantId = generateId();
|
|
253
|
+
// Add placeholder message
|
|
254
|
+
const assistantMessage = {
|
|
255
|
+
id: assistantId,
|
|
256
|
+
role: 'assistant',
|
|
257
|
+
content: '',
|
|
258
|
+
createdAt: new Date(),
|
|
259
|
+
};
|
|
260
|
+
setMessages((prev) => [...prev, assistantMessage]);
|
|
261
|
+
// Read stream
|
|
262
|
+
while (true) {
|
|
263
|
+
const { done, value } = await reader.read();
|
|
264
|
+
if (done) {
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
268
|
+
if (streamProtocol === 'data') {
|
|
269
|
+
// Parse SSE data format
|
|
270
|
+
const lines = chunk.split('\n');
|
|
271
|
+
for (const line of lines) {
|
|
272
|
+
if (line.startsWith('data: ')) {
|
|
273
|
+
const data = line.slice(6);
|
|
274
|
+
if (data === '[DONE]') {
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
try {
|
|
278
|
+
const parsed = JSON.parse(data);
|
|
279
|
+
if (parsed.content) {
|
|
280
|
+
assistantContent += parsed.content;
|
|
281
|
+
}
|
|
282
|
+
else if (parsed.choices?.[0]?.delta?.content) {
|
|
283
|
+
assistantContent += parsed.choices[0].delta.content;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
// Ignore parse errors for incomplete JSON
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
// Raw text protocol
|
|
294
|
+
assistantContent += chunk;
|
|
295
|
+
}
|
|
296
|
+
// Update message content
|
|
297
|
+
setMessages((prev) => prev.map((msg) => msg.id === assistantId ? { ...msg, content: assistantContent } : msg));
|
|
298
|
+
}
|
|
299
|
+
// Finalize message
|
|
300
|
+
const finalMessage = {
|
|
301
|
+
id: assistantId,
|
|
302
|
+
role: 'assistant',
|
|
303
|
+
content: assistantContent,
|
|
304
|
+
createdAt: new Date(),
|
|
305
|
+
};
|
|
306
|
+
setMessages((prev) => prev.map((msg) => (msg.id === assistantId ? finalMessage : msg)));
|
|
307
|
+
onFinish?.(finalMessage);
|
|
308
|
+
return assistantContent;
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
312
|
+
// Request was aborted, not an error
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
316
|
+
setError(error);
|
|
317
|
+
onError?.(error);
|
|
318
|
+
if (!keepLastMessageOnError) {
|
|
319
|
+
// Remove the last user message on error
|
|
320
|
+
setMessages((prev) => prev.slice(0, -1));
|
|
321
|
+
}
|
|
322
|
+
return undefined;
|
|
323
|
+
}
|
|
324
|
+
finally {
|
|
325
|
+
setIsLoading(false);
|
|
326
|
+
abortControllerRef.current = null;
|
|
327
|
+
}
|
|
328
|
+
}, [
|
|
329
|
+
api,
|
|
330
|
+
body,
|
|
331
|
+
chatId,
|
|
332
|
+
generateId,
|
|
333
|
+
headers,
|
|
334
|
+
keepLastMessageOnError,
|
|
335
|
+
onError,
|
|
336
|
+
onFinish,
|
|
337
|
+
onResponse,
|
|
338
|
+
sendExtraMessageFields,
|
|
339
|
+
streamProtocol,
|
|
340
|
+
]);
|
|
341
|
+
/**
|
|
342
|
+
* Send request using the appropriate mode.
|
|
343
|
+
*/
|
|
344
|
+
const sendRequest = useCallback(async (messagesToSend, requestOptions) => {
|
|
345
|
+
return isDirectMode
|
|
346
|
+
? sendDirectRequest(messagesToSend, requestOptions)
|
|
347
|
+
: sendHttpRequest(messagesToSend, requestOptions);
|
|
348
|
+
}, [isDirectMode, sendDirectRequest, sendHttpRequest]);
|
|
349
|
+
/**
|
|
350
|
+
* Append a message and send.
|
|
351
|
+
*/
|
|
352
|
+
const append = useCallback(async (message, options) => {
|
|
353
|
+
const newMessage = typeof message === 'string'
|
|
354
|
+
? {
|
|
355
|
+
id: generateId(),
|
|
356
|
+
role: 'user',
|
|
357
|
+
content: message,
|
|
358
|
+
createdAt: new Date(),
|
|
359
|
+
}
|
|
360
|
+
: message;
|
|
361
|
+
const newMessages = [...messages, newMessage];
|
|
362
|
+
setMessages(newMessages);
|
|
363
|
+
return sendRequest(newMessages, options);
|
|
364
|
+
}, [generateId, messages, sendRequest]);
|
|
365
|
+
/**
|
|
366
|
+
* Handle form submission.
|
|
367
|
+
*/
|
|
368
|
+
const handleSubmit = useCallback((e, options) => {
|
|
369
|
+
e?.preventDefault();
|
|
370
|
+
if (!input.trim()) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
const userMessage = {
|
|
374
|
+
id: generateId(),
|
|
375
|
+
role: 'user',
|
|
376
|
+
content: input,
|
|
377
|
+
createdAt: new Date(),
|
|
378
|
+
};
|
|
379
|
+
const newMessages = [...messages, userMessage];
|
|
380
|
+
setMessages(newMessages);
|
|
381
|
+
setInput('');
|
|
382
|
+
sendRequest(newMessages, options);
|
|
383
|
+
}, [generateId, input, messages, sendRequest]);
|
|
384
|
+
/**
|
|
385
|
+
* Reload the last assistant message.
|
|
386
|
+
*/
|
|
387
|
+
const reload = useCallback(async (options) => {
|
|
388
|
+
if (messages.length === 0) {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
// Find messages up to the last user message
|
|
392
|
+
const lastUserIndex = messages.findLastIndex((m) => m.role === 'user');
|
|
393
|
+
if (lastUserIndex === -1) {
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
const messagesToReload = messages.slice(0, lastUserIndex + 1);
|
|
397
|
+
setMessages(messagesToReload);
|
|
398
|
+
return sendRequest(messagesToReload, options);
|
|
399
|
+
}, [messages, sendRequest]);
|
|
400
|
+
return {
|
|
401
|
+
messages,
|
|
402
|
+
input,
|
|
403
|
+
setInput,
|
|
404
|
+
handleInputChange,
|
|
405
|
+
handleSubmit,
|
|
406
|
+
append,
|
|
407
|
+
reload,
|
|
408
|
+
stop,
|
|
409
|
+
setMessages,
|
|
410
|
+
isLoading,
|
|
411
|
+
error,
|
|
412
|
+
data,
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
//# sourceMappingURL=use-chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-chat.js","sourceRoot":"","sources":["../../src/use-chat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useCompletion Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for text completion interfaces with streaming support.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { useState, useCallback, useRef, useId } from 'react';
|
|
9
|
+
/**
|
|
10
|
+
* useCompletion - React hook for text completion.
|
|
11
|
+
*
|
|
12
|
+
* Provides state management and streaming for single-turn
|
|
13
|
+
* text completion tasks.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* import { useCompletion } from 'ai.matey.react.core';
|
|
18
|
+
*
|
|
19
|
+
* function CompletionComponent() {
|
|
20
|
+
* const { completion, input, handleInputChange, handleSubmit, isLoading } = useCompletion({
|
|
21
|
+
* api: '/api/completion',
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* return (
|
|
25
|
+
* <div>
|
|
26
|
+
* <p>{completion}</p>
|
|
27
|
+
* <form onSubmit={handleSubmit}>
|
|
28
|
+
* <input value={input} onChange={handleInputChange} placeholder="Enter a prompt..." />
|
|
29
|
+
* <button type="submit" disabled={isLoading}>Complete</button>
|
|
30
|
+
* </form>
|
|
31
|
+
* </div>
|
|
32
|
+
* );
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function useCompletion(options = {}) {
|
|
37
|
+
const { initialInput = '', initialCompletion = '', id, api = '/api/completion', headers = {}, body = {}, onFinish, onError, onResponse, streamProtocol = 'data', } = options;
|
|
38
|
+
// Generate a stable ID for this completion instance
|
|
39
|
+
const hookId = useId();
|
|
40
|
+
const completionId = id ?? hookId;
|
|
41
|
+
// State
|
|
42
|
+
const [completion, setCompletion] = useState(initialCompletion);
|
|
43
|
+
const [input, setInput] = useState(initialInput);
|
|
44
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
45
|
+
const [error, setError] = useState(undefined);
|
|
46
|
+
const [data, _setData] = useState(undefined);
|
|
47
|
+
// Refs for abort control
|
|
48
|
+
const abortControllerRef = useRef(null);
|
|
49
|
+
/**
|
|
50
|
+
* Handle input change from form elements.
|
|
51
|
+
*/
|
|
52
|
+
const handleInputChange = useCallback((e) => {
|
|
53
|
+
setInput(e.target.value);
|
|
54
|
+
}, []);
|
|
55
|
+
/**
|
|
56
|
+
* Stop current streaming request.
|
|
57
|
+
*/
|
|
58
|
+
const stop = useCallback(() => {
|
|
59
|
+
if (abortControllerRef.current) {
|
|
60
|
+
abortControllerRef.current.abort();
|
|
61
|
+
abortControllerRef.current = null;
|
|
62
|
+
}
|
|
63
|
+
}, []);
|
|
64
|
+
/**
|
|
65
|
+
* Send a completion request and handle streaming response.
|
|
66
|
+
*/
|
|
67
|
+
const complete = useCallback(async (prompt, requestOptions) => {
|
|
68
|
+
try {
|
|
69
|
+
setIsLoading(true);
|
|
70
|
+
setError(undefined);
|
|
71
|
+
setCompletion('');
|
|
72
|
+
// Create abort controller
|
|
73
|
+
abortControllerRef.current = new AbortController();
|
|
74
|
+
const { signal } = abortControllerRef.current;
|
|
75
|
+
// Prepare request body
|
|
76
|
+
const requestBody = {
|
|
77
|
+
prompt,
|
|
78
|
+
id: completionId,
|
|
79
|
+
...body,
|
|
80
|
+
...requestOptions?.body,
|
|
81
|
+
};
|
|
82
|
+
// Make request
|
|
83
|
+
const response = await fetch(api, {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
headers: {
|
|
86
|
+
'Content-Type': 'application/json',
|
|
87
|
+
...headers,
|
|
88
|
+
...requestOptions?.headers,
|
|
89
|
+
},
|
|
90
|
+
body: JSON.stringify(requestBody),
|
|
91
|
+
signal,
|
|
92
|
+
});
|
|
93
|
+
// Call onResponse callback
|
|
94
|
+
onResponse?.(response);
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
97
|
+
}
|
|
98
|
+
if (!response.body) {
|
|
99
|
+
throw new Error('Response body is null');
|
|
100
|
+
}
|
|
101
|
+
// Handle streaming response
|
|
102
|
+
const reader = response.body.getReader();
|
|
103
|
+
const decoder = new TextDecoder();
|
|
104
|
+
let completionText = '';
|
|
105
|
+
// Read stream
|
|
106
|
+
while (true) {
|
|
107
|
+
const { done, value } = await reader.read();
|
|
108
|
+
if (done) {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
112
|
+
if (streamProtocol === 'data') {
|
|
113
|
+
// Parse SSE data format
|
|
114
|
+
const lines = chunk.split('\n');
|
|
115
|
+
for (const line of lines) {
|
|
116
|
+
if (line.startsWith('data: ')) {
|
|
117
|
+
const data = line.slice(6);
|
|
118
|
+
if (data === '[DONE]') {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const parsed = JSON.parse(data);
|
|
123
|
+
if (parsed.text) {
|
|
124
|
+
completionText += parsed.text;
|
|
125
|
+
}
|
|
126
|
+
else if (parsed.choices?.[0]?.text) {
|
|
127
|
+
completionText += parsed.choices[0].text;
|
|
128
|
+
}
|
|
129
|
+
else if (parsed.choices?.[0]?.delta?.content) {
|
|
130
|
+
completionText += parsed.choices[0].delta.content;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// Ignore parse errors for incomplete JSON
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// Raw text protocol
|
|
141
|
+
completionText += chunk;
|
|
142
|
+
}
|
|
143
|
+
// Update completion
|
|
144
|
+
setCompletion(completionText);
|
|
145
|
+
}
|
|
146
|
+
onFinish?.(prompt, completionText);
|
|
147
|
+
return completionText;
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
151
|
+
// Request was aborted, not an error
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
155
|
+
setError(error);
|
|
156
|
+
onError?.(error);
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
setIsLoading(false);
|
|
161
|
+
abortControllerRef.current = null;
|
|
162
|
+
}
|
|
163
|
+
}, [api, body, completionId, headers, onError, onFinish, onResponse, streamProtocol]);
|
|
164
|
+
/**
|
|
165
|
+
* Handle form submission.
|
|
166
|
+
*/
|
|
167
|
+
const handleSubmit = useCallback((e) => {
|
|
168
|
+
e?.preventDefault();
|
|
169
|
+
if (!input.trim()) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const prompt = input;
|
|
173
|
+
setInput('');
|
|
174
|
+
complete(prompt);
|
|
175
|
+
}, [complete, input]);
|
|
176
|
+
return {
|
|
177
|
+
completion,
|
|
178
|
+
input,
|
|
179
|
+
setInput,
|
|
180
|
+
handleInputChange,
|
|
181
|
+
handleSubmit,
|
|
182
|
+
complete,
|
|
183
|
+
stop,
|
|
184
|
+
setCompletion,
|
|
185
|
+
isLoading,
|
|
186
|
+
error,
|
|
187
|
+
data,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=use-completion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-completion.js","sourceRoot":"","sources":["../../src/use-completion.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAO7D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,aAAa,CAAC,UAAgC,EAAE;IAC9D,MAAM,EACJ,YAAY,GAAG,EAAE,EACjB,iBAAiB,GAAG,EAAE,EACtB,EAAE,EACF,GAAG,GAAG,iBAAiB,EACvB,OAAO,GAAG,EAAE,EACZ,IAAI,GAAG,EAAE,EACT,QAAQ,EACR,OAAO,EACP,UAAU,EACV,cAAc,GAAG,MAAM,GACxB,GAAG,OAAO,CAAC;IAEZ,oDAAoD;IACpD,MAAM,MAAM,GAAG,KAAK,EAAE,CAAC;IACvB,MAAM,YAAY,GAAG,EAAE,IAAI,MAAM,CAAC;IAElC,QAAQ;IACR,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAS,iBAAiB,CAAC,CAAC;IACxE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAS,YAAY,CAAC,CAAC;IACzD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAU,KAAK,CAAC,CAAC;IAC3D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAoB,SAAS,CAAC,CAAC;IACjE,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAwB,SAAS,CAAC,CAAC;IAEpE,yBAAyB;IACzB,MAAM,kBAAkB,GAAG,MAAM,CAAyB,IAAI,CAAC,CAAC;IAEhE;;OAEG;IACH,MAAM,iBAAiB,GAAG,WAAW,CACnC,CAAC,CAA4D,EAAE,EAAE;QAC/D,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC,EACD,EAAE,CACH,CAAC;IAEF;;OAEG;IACH,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE;QAC5B,IAAI,kBAAkB,CAAC,OAAO,EAAE,CAAC;YAC/B,kBAAkB,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACnC,kBAAkB,CAAC,OAAO,GAAG,IAAI,CAAC;QACpC,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP;;OAEG;IACH,MAAM,QAAQ,GAAG,WAAW,CAC1B,KAAK,EACH,MAAc,EACd,cAAyC,EACL,EAAE;QACtC,IAAI,CAAC;YACH,YAAY,CAAC,IAAI,CAAC,CAAC;YACnB,QAAQ,CAAC,SAAS,CAAC,CAAC;YACpB,aAAa,CAAC,EAAE,CAAC,CAAC;YAElB,0BAA0B;YAC1B,kBAAkB,CAAC,OAAO,GAAG,IAAI,eAAe,EAAE,CAAC;YACnD,MAAM,EAAE,MAAM,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC;YAE9C,uBAAuB;YACvB,MAAM,WAAW,GAAG;gBAClB,MAAM;gBACN,EAAE,EAAE,YAAY;gBAChB,GAAG,IAAI;gBACP,GAAG,cAAc,EAAE,IAAI;aACxB,CAAC;YAEF,eAAe;YACf,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,GAAG,OAAO;oBACV,GAAG,cAAc,EAAE,OAAO;iBAC3B;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;gBACjC,MAAM;aACP,CAAC,CAAC;YAEH,2BAA2B;YAC3B,UAAU,EAAE,CAAC,QAAQ,CAAC,CAAC;YAEvB,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YAC5D,CAAC;YAED,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;YAC3C,CAAC;YAED,4BAA4B;YAC5B,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;YAClC,IAAI,cAAc,GAAG,EAAE,CAAC;YAExB,cAAc;YACd,OAAO,IAAI,EAAE,CAAC;gBACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAE5C,IAAI,IAAI,EAAE,CAAC;oBACT,MAAM;gBACR,CAAC;gBAED,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;gBAEtD,IAAI,cAAc,KAAK,MAAM,EAAE,CAAC;oBAC9B,wBAAwB;oBACxB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;wBACzB,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;4BAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;4BAC3B,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gCACtB,MAAM;4BACR,CAAC;4BACD,IAAI,CAAC;gCACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gCAChC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;oCAChB,cAAc,IAAI,MAAM,CAAC,IAAI,CAAC;gCAChC,CAAC;qCAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;oCACrC,cAAc,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gCAC3C,CAAC;qCAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;oCAC/C,cAAc,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;gCACpD,CAAC;4BACH,CAAC;4BAAC,MAAM,CAAC;gCACP,0CAA0C;4BAC5C,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,oBAAoB;oBACpB,cAAc,IAAI,KAAK,CAAC;gBAC1B,CAAC;gBAED,oBAAoB;gBACpB,aAAa,CAAC,cAAc,CAAC,CAAC;YAChC,CAAC;YAED,QAAQ,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;YAEnC,OAAO,cAAc,CAAC;QACxB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBACtD,oCAAoC;gBACpC,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAClE,QAAQ,CAAC,KAAK,CAAC,CAAC;YAChB,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;YAEjB,OAAO,SAAS,CAAC;QACnB,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,kBAAkB,CAAC,OAAO,GAAG,IAAI,CAAC;QACpC,CAAC;IACH,CAAC,EACD,CAAC,GAAG,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,CAAC,CAClF,CAAC;IAEF;;OAEG;IACH,MAAM,YAAY,GAAG,WAAW,CAC9B,CAAC,CAAoC,EAAE,EAAE;QACvC,CAAC,EAAE,cAAc,EAAE,CAAC;QAEpB,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAClB,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC;QACrB,QAAQ,CAAC,EAAE,CAAC,CAAC;QACb,QAAQ,CAAC,MAAM,CAAC,CAAC;IACnB,CAAC,EACD,CAAC,QAAQ,EAAE,KAAK,CAAC,CAClB,CAAC;IAEF,OAAO;QACL,UAAU;QACV,KAAK;QACL,QAAQ;QACR,iBAAiB;QACjB,YAAY;QACZ,QAAQ;QACR,IAAI;QACJ,aAAa;QACb,SAAS;QACT,KAAK;QACL,IAAI;KACL,CAAC;AACJ,CAAC"}
|