ai.matey.react.hooks 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 +20 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/use-assistant.js +180 -0
- package/dist/cjs/use-assistant.js.map +1 -0
- package/dist/cjs/use-stream.js +173 -0
- package/dist/cjs/use-stream.js.map +1 -0
- package/dist/cjs/use-token-count.js +135 -0
- package/dist/cjs/use-token-count.js.map +1 -0
- package/dist/esm/index.js +12 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/use-assistant.js +177 -0
- package/dist/esm/use-assistant.js.map +1 -0
- package/dist/esm/use-stream.js +170 -0
- package/dist/esm/use-stream.js.map +1 -0
- package/dist/esm/use-token-count.js +130 -0
- package/dist/esm/use-token-count.js.map +1 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/use-assistant.d.ts +123 -0
- package/dist/types/use-assistant.d.ts.map +1 -0
- package/dist/types/use-stream.d.ts +75 -0
- package/dist/types/use-stream.d.ts.map +1 -0
- package/dist/types/use-token-count.d.ts +68 -0
- package/dist/types/use-token-count.d.ts.map +1 -0
- package/package.json +77 -0
- package/readme.md +143 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useAssistant Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for OpenAI Assistants API compatible interfaces.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { useState, useCallback, useRef } from 'react';
|
|
9
|
+
/**
|
|
10
|
+
* useAssistant - React hook for OpenAI Assistants API.
|
|
11
|
+
*
|
|
12
|
+
* Provides state management for conversations with OpenAI Assistants,
|
|
13
|
+
* including thread management and run status tracking.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* import { useAssistant } from 'ai.matey.react.hooks';
|
|
18
|
+
*
|
|
19
|
+
* function AssistantChat() {
|
|
20
|
+
* const { messages, input, handleInputChange, handleSubmit, status } = useAssistant({
|
|
21
|
+
* api: '/api/assistant',
|
|
22
|
+
* assistantId: 'asst_xxx',
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* return (
|
|
26
|
+
* <div>
|
|
27
|
+
* {messages.map((m) => (
|
|
28
|
+
* <div key={m.id}>{m.role}: {m.content}</div>
|
|
29
|
+
* ))}
|
|
30
|
+
* <form onSubmit={handleSubmit}>
|
|
31
|
+
* <input value={input} onChange={handleInputChange} />
|
|
32
|
+
* <button type="submit" disabled={status === 'in_progress'}>Send</button>
|
|
33
|
+
* </form>
|
|
34
|
+
* </div>
|
|
35
|
+
* );
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export function useAssistant(options = {}) {
|
|
40
|
+
const { api = '/api/assistant', assistantId, threadId: initialThreadId, headers = {}, body = {}, onStatus, onError, } = options;
|
|
41
|
+
// State
|
|
42
|
+
const [messages, setMessages] = useState([]);
|
|
43
|
+
const [input, setInput] = useState('');
|
|
44
|
+
const [threadId, setThreadId] = useState(initialThreadId);
|
|
45
|
+
const [status, setStatus] = useState('awaiting_message');
|
|
46
|
+
const [error, setError] = useState(undefined);
|
|
47
|
+
// Refs for abort control
|
|
48
|
+
const abortControllerRef = useRef(null);
|
|
49
|
+
/**
|
|
50
|
+
* Update status and call callback.
|
|
51
|
+
*/
|
|
52
|
+
const updateStatus = useCallback((newStatus) => {
|
|
53
|
+
setStatus(newStatus);
|
|
54
|
+
onStatus?.(newStatus);
|
|
55
|
+
}, [onStatus]);
|
|
56
|
+
/**
|
|
57
|
+
* Handle input change from form elements.
|
|
58
|
+
*/
|
|
59
|
+
const handleInputChange = useCallback((e) => {
|
|
60
|
+
setInput(e.target.value);
|
|
61
|
+
}, []);
|
|
62
|
+
/**
|
|
63
|
+
* Stop current run.
|
|
64
|
+
*/
|
|
65
|
+
const stop = useCallback(() => {
|
|
66
|
+
if (abortControllerRef.current) {
|
|
67
|
+
abortControllerRef.current.abort();
|
|
68
|
+
abortControllerRef.current = null;
|
|
69
|
+
updateStatus('cancelled');
|
|
70
|
+
}
|
|
71
|
+
}, [updateStatus]);
|
|
72
|
+
/**
|
|
73
|
+
* Generate unique ID.
|
|
74
|
+
*/
|
|
75
|
+
const generateId = useCallback(() => {
|
|
76
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
77
|
+
}, []);
|
|
78
|
+
/**
|
|
79
|
+
* Send a message to the assistant.
|
|
80
|
+
*/
|
|
81
|
+
const append = useCallback(async (message) => {
|
|
82
|
+
try {
|
|
83
|
+
setError(undefined);
|
|
84
|
+
updateStatus('in_progress');
|
|
85
|
+
// Create abort controller
|
|
86
|
+
abortControllerRef.current = new AbortController();
|
|
87
|
+
const { signal } = abortControllerRef.current;
|
|
88
|
+
// Create user message
|
|
89
|
+
const userMessage = typeof message === 'string'
|
|
90
|
+
? {
|
|
91
|
+
id: generateId(),
|
|
92
|
+
role: 'user',
|
|
93
|
+
content: message,
|
|
94
|
+
createdAt: new Date(),
|
|
95
|
+
}
|
|
96
|
+
: { ...message, id: message.id ?? generateId() };
|
|
97
|
+
setMessages((prev) => [...prev, userMessage]);
|
|
98
|
+
// Prepare request body
|
|
99
|
+
const requestBody = {
|
|
100
|
+
message: typeof message === 'string' ? message : message.content,
|
|
101
|
+
assistantId,
|
|
102
|
+
threadId,
|
|
103
|
+
...body,
|
|
104
|
+
};
|
|
105
|
+
// Make request
|
|
106
|
+
const response = await fetch(api, {
|
|
107
|
+
method: 'POST',
|
|
108
|
+
headers: {
|
|
109
|
+
'Content-Type': 'application/json',
|
|
110
|
+
...headers,
|
|
111
|
+
},
|
|
112
|
+
body: JSON.stringify(requestBody),
|
|
113
|
+
signal,
|
|
114
|
+
});
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
117
|
+
}
|
|
118
|
+
const data = await response.json();
|
|
119
|
+
// Update thread ID if new
|
|
120
|
+
if (data.threadId && !threadId) {
|
|
121
|
+
setThreadId(data.threadId);
|
|
122
|
+
}
|
|
123
|
+
// Add assistant message
|
|
124
|
+
if (data.message) {
|
|
125
|
+
const assistantMessage = {
|
|
126
|
+
id: data.message.id ?? generateId(),
|
|
127
|
+
role: 'assistant',
|
|
128
|
+
content: data.message.content ?? '',
|
|
129
|
+
createdAt: new Date(),
|
|
130
|
+
threadId: data.threadId,
|
|
131
|
+
runId: data.runId,
|
|
132
|
+
annotations: data.message.annotations,
|
|
133
|
+
};
|
|
134
|
+
setMessages((prev) => [...prev, assistantMessage]);
|
|
135
|
+
}
|
|
136
|
+
updateStatus('completed');
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
143
|
+
setError(error);
|
|
144
|
+
onError?.(error);
|
|
145
|
+
updateStatus('failed');
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
abortControllerRef.current = null;
|
|
149
|
+
}
|
|
150
|
+
}, [api, assistantId, body, generateId, headers, onError, threadId, updateStatus]);
|
|
151
|
+
/**
|
|
152
|
+
* Handle form submission.
|
|
153
|
+
*/
|
|
154
|
+
const handleSubmit = useCallback((e) => {
|
|
155
|
+
e?.preventDefault();
|
|
156
|
+
if (!input.trim() || status === 'in_progress') {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const message = input;
|
|
160
|
+
setInput('');
|
|
161
|
+
append(message);
|
|
162
|
+
}, [append, input, status]);
|
|
163
|
+
return {
|
|
164
|
+
messages,
|
|
165
|
+
input,
|
|
166
|
+
setInput,
|
|
167
|
+
handleInputChange,
|
|
168
|
+
handleSubmit,
|
|
169
|
+
append,
|
|
170
|
+
threadId,
|
|
171
|
+
status,
|
|
172
|
+
stop,
|
|
173
|
+
setMessages,
|
|
174
|
+
error,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=use-assistant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-assistant.js","sourceRoot":"","sources":["../../src/use-assistant.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useStream Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for generic text streaming with state management.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { useState, useCallback, useRef } from 'react';
|
|
9
|
+
/**
|
|
10
|
+
* useStream - React hook for generic text streaming.
|
|
11
|
+
*
|
|
12
|
+
* Provides state management for streaming text from various sources
|
|
13
|
+
* including fetch responses, ReadableStreams, and async iterables.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* import { useStream } from 'ai.matey.react.hooks';
|
|
18
|
+
*
|
|
19
|
+
* function StreamingComponent() {
|
|
20
|
+
* const { text, isStreaming, startStream, stop } = useStream({
|
|
21
|
+
* onComplete: (fullText) => console.log('Completed:', fullText),
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* const handleClick = async () => {
|
|
25
|
+
* const response = await fetch('/api/stream');
|
|
26
|
+
* await startStream(response);
|
|
27
|
+
* };
|
|
28
|
+
*
|
|
29
|
+
* return (
|
|
30
|
+
* <div>
|
|
31
|
+
* <button onClick={handleClick} disabled={isStreaming}>Start</button>
|
|
32
|
+
* <button onClick={stop} disabled={!isStreaming}>Stop</button>
|
|
33
|
+
* <pre>{text}</pre>
|
|
34
|
+
* </div>
|
|
35
|
+
* );
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export function useStream(options = {}) {
|
|
40
|
+
const { onChunk, onComplete, onError, initialText = '' } = options;
|
|
41
|
+
// State
|
|
42
|
+
const [text, setText] = useState(initialText);
|
|
43
|
+
const [isStreaming, setIsStreaming] = useState(false);
|
|
44
|
+
const [error, setError] = useState(undefined);
|
|
45
|
+
// Refs
|
|
46
|
+
const abortControllerRef = useRef(null);
|
|
47
|
+
const textRef = useRef(initialText);
|
|
48
|
+
/**
|
|
49
|
+
* Stop streaming.
|
|
50
|
+
*/
|
|
51
|
+
const stop = useCallback(() => {
|
|
52
|
+
if (abortControllerRef.current) {
|
|
53
|
+
abortControllerRef.current.abort();
|
|
54
|
+
abortControllerRef.current = null;
|
|
55
|
+
}
|
|
56
|
+
setIsStreaming(false);
|
|
57
|
+
}, []);
|
|
58
|
+
/**
|
|
59
|
+
* Reset state.
|
|
60
|
+
*/
|
|
61
|
+
const reset = useCallback(() => {
|
|
62
|
+
stop();
|
|
63
|
+
setText(initialText);
|
|
64
|
+
textRef.current = initialText;
|
|
65
|
+
setError(undefined);
|
|
66
|
+
}, [initialText, stop]);
|
|
67
|
+
/**
|
|
68
|
+
* Start streaming from a fetch Response.
|
|
69
|
+
*/
|
|
70
|
+
const startStream = useCallback(async (response) => {
|
|
71
|
+
if (!response.body) {
|
|
72
|
+
throw new Error('Response body is null');
|
|
73
|
+
}
|
|
74
|
+
return startReadableStream(response.body);
|
|
75
|
+
}, []);
|
|
76
|
+
/**
|
|
77
|
+
* Start streaming from a ReadableStream.
|
|
78
|
+
*/
|
|
79
|
+
const startReadableStream = useCallback(async (stream) => {
|
|
80
|
+
try {
|
|
81
|
+
setIsStreaming(true);
|
|
82
|
+
setError(undefined);
|
|
83
|
+
setText('');
|
|
84
|
+
textRef.current = '';
|
|
85
|
+
// Create abort controller
|
|
86
|
+
abortControllerRef.current = new AbortController();
|
|
87
|
+
const reader = stream.getReader();
|
|
88
|
+
const decoder = new TextDecoder();
|
|
89
|
+
while (true) {
|
|
90
|
+
// Check if aborted
|
|
91
|
+
if (abortControllerRef.current?.signal.aborted) {
|
|
92
|
+
reader.cancel();
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
const { done, value } = await reader.read();
|
|
96
|
+
if (done) {
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
100
|
+
textRef.current += chunk;
|
|
101
|
+
setText(textRef.current);
|
|
102
|
+
onChunk?.(chunk);
|
|
103
|
+
}
|
|
104
|
+
onComplete?.(textRef.current);
|
|
105
|
+
return textRef.current;
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
109
|
+
return textRef.current;
|
|
110
|
+
}
|
|
111
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
112
|
+
setError(error);
|
|
113
|
+
onError?.(error);
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
setIsStreaming(false);
|
|
118
|
+
abortControllerRef.current = null;
|
|
119
|
+
}
|
|
120
|
+
}, [onChunk, onComplete, onError]);
|
|
121
|
+
/**
|
|
122
|
+
* Start streaming from an async iterable.
|
|
123
|
+
*/
|
|
124
|
+
const startAsyncIterable = useCallback(async (iterable) => {
|
|
125
|
+
try {
|
|
126
|
+
setIsStreaming(true);
|
|
127
|
+
setError(undefined);
|
|
128
|
+
setText('');
|
|
129
|
+
textRef.current = '';
|
|
130
|
+
// Create abort controller
|
|
131
|
+
abortControllerRef.current = new AbortController();
|
|
132
|
+
for await (const chunk of iterable) {
|
|
133
|
+
// Check if aborted
|
|
134
|
+
if (abortControllerRef.current?.signal.aborted) {
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
textRef.current += chunk;
|
|
138
|
+
setText(textRef.current);
|
|
139
|
+
onChunk?.(chunk);
|
|
140
|
+
}
|
|
141
|
+
onComplete?.(textRef.current);
|
|
142
|
+
return textRef.current;
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
146
|
+
return textRef.current;
|
|
147
|
+
}
|
|
148
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
149
|
+
setError(error);
|
|
150
|
+
onError?.(error);
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
setIsStreaming(false);
|
|
155
|
+
abortControllerRef.current = null;
|
|
156
|
+
}
|
|
157
|
+
}, [onChunk, onComplete, onError]);
|
|
158
|
+
return {
|
|
159
|
+
text,
|
|
160
|
+
isStreaming,
|
|
161
|
+
error,
|
|
162
|
+
startStream,
|
|
163
|
+
startReadableStream,
|
|
164
|
+
startAsyncIterable,
|
|
165
|
+
stop,
|
|
166
|
+
reset,
|
|
167
|
+
setText,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=use-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-stream.js","sourceRoot":"","sources":["../../src/use-stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useTokenCount Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for estimating token counts.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { useState, useEffect, useMemo, useCallback } from 'react';
|
|
9
|
+
/**
|
|
10
|
+
* Default tokenizer using rough estimation.
|
|
11
|
+
*
|
|
12
|
+
* Uses ~4 characters per token as a rough estimate,
|
|
13
|
+
* which is approximately accurate for GPT models with English text.
|
|
14
|
+
*/
|
|
15
|
+
function defaultTokenizer(text) {
|
|
16
|
+
if (!text)
|
|
17
|
+
return 0;
|
|
18
|
+
// More sophisticated estimation:
|
|
19
|
+
// - Count words (average ~1.3 tokens per word)
|
|
20
|
+
// - Count special characters/punctuation (often separate tokens)
|
|
21
|
+
// - Account for whitespace
|
|
22
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
23
|
+
const wordTokens = words.length * 1.3;
|
|
24
|
+
// Count punctuation and special characters
|
|
25
|
+
const punctuation = (text.match(/[.,!?;:'"()\[\]{}<>@#$%^&*+=|\\/-]/g) || []).length;
|
|
26
|
+
// Count numbers as separate tokens
|
|
27
|
+
const numbers = (text.match(/\d+/g) || []).length;
|
|
28
|
+
return Math.ceil(wordTokens + punctuation * 0.5 + numbers);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* useTokenCount - React hook for estimating token counts.
|
|
32
|
+
*
|
|
33
|
+
* Provides real-time token estimation for text input,
|
|
34
|
+
* useful for staying within model context limits.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```tsx
|
|
38
|
+
* import { useTokenCount } from 'ai.matey.react.hooks';
|
|
39
|
+
*
|
|
40
|
+
* function TokenCounter() {
|
|
41
|
+
* const [text, setText] = useState('');
|
|
42
|
+
* const { tokenCount, characterCount, wordCount } = useTokenCount({ text });
|
|
43
|
+
*
|
|
44
|
+
* return (
|
|
45
|
+
* <div>
|
|
46
|
+
* <textarea value={text} onChange={(e) => setText(e.target.value)} />
|
|
47
|
+
* <p>Tokens: ~{tokenCount} | Words: {wordCount} | Characters: {characterCount}</p>
|
|
48
|
+
* </div>
|
|
49
|
+
* );
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function useTokenCount(options = {}) {
|
|
54
|
+
const { text = '', model: _model, // Reserved for future model-specific tokenizers
|
|
55
|
+
tokenizer = defaultTokenizer, debounceMs = 100, } = options;
|
|
56
|
+
const [tokenCount, setTokenCount] = useState(0);
|
|
57
|
+
const [isEstimating, setIsEstimating] = useState(false);
|
|
58
|
+
// Character count (memoized)
|
|
59
|
+
const characterCount = useMemo(() => text.length, [text]);
|
|
60
|
+
// Word count (memoized)
|
|
61
|
+
const wordCount = useMemo(() => {
|
|
62
|
+
if (!text.trim())
|
|
63
|
+
return 0;
|
|
64
|
+
return text.split(/\s+/).filter(Boolean).length;
|
|
65
|
+
}, [text]);
|
|
66
|
+
// Count tokens function
|
|
67
|
+
const countTokens = useCallback((inputText) => {
|
|
68
|
+
return tokenizer(inputText);
|
|
69
|
+
}, [tokenizer]);
|
|
70
|
+
// Debounced token counting effect
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if (!text) {
|
|
73
|
+
setTokenCount(0);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
setIsEstimating(true);
|
|
77
|
+
const timeoutId = setTimeout(() => {
|
|
78
|
+
const count = countTokens(text);
|
|
79
|
+
setTokenCount(count);
|
|
80
|
+
setIsEstimating(false);
|
|
81
|
+
}, debounceMs);
|
|
82
|
+
return () => {
|
|
83
|
+
clearTimeout(timeoutId);
|
|
84
|
+
};
|
|
85
|
+
}, [text, countTokens, debounceMs]);
|
|
86
|
+
return {
|
|
87
|
+
tokenCount,
|
|
88
|
+
characterCount,
|
|
89
|
+
wordCount,
|
|
90
|
+
isEstimating,
|
|
91
|
+
countTokens,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Model-specific token limits.
|
|
96
|
+
*/
|
|
97
|
+
export const MODEL_TOKEN_LIMITS = {
|
|
98
|
+
'gpt-4': 8192,
|
|
99
|
+
'gpt-4-32k': 32768,
|
|
100
|
+
'gpt-4-turbo': 128000,
|
|
101
|
+
'gpt-4o': 128000,
|
|
102
|
+
'gpt-3.5-turbo': 16385,
|
|
103
|
+
'claude-3-opus': 200000,
|
|
104
|
+
'claude-3-sonnet': 200000,
|
|
105
|
+
'claude-3-haiku': 200000,
|
|
106
|
+
'gemini-pro': 30720,
|
|
107
|
+
'gemini-1.5-pro': 1000000,
|
|
108
|
+
'command-r': 128000,
|
|
109
|
+
'command-r-plus': 128000,
|
|
110
|
+
'mixtral-8x7b': 32768,
|
|
111
|
+
'llama-3-70b': 8192,
|
|
112
|
+
'llama-3.1-405b': 128000,
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Get token limit for a model.
|
|
116
|
+
*/
|
|
117
|
+
export function getModelTokenLimit(model) {
|
|
118
|
+
// Try exact match
|
|
119
|
+
if (MODEL_TOKEN_LIMITS[model]) {
|
|
120
|
+
return MODEL_TOKEN_LIMITS[model];
|
|
121
|
+
}
|
|
122
|
+
// Try prefix match
|
|
123
|
+
for (const [key, value] of Object.entries(MODEL_TOKEN_LIMITS)) {
|
|
124
|
+
if (model.startsWith(key) || model.includes(key)) {
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=use-token-count.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-token-count.js","sourceRoot":"","sources":["../../src/use-token-count.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Matey React Hooks
|
|
3
|
+
*
|
|
4
|
+
* Additional specialized React hooks for AI applications.
|
|
5
|
+
*
|
|
6
|
+
* @packageDocumentation
|
|
7
|
+
*/
|
|
8
|
+
export { useAssistant } from './use-assistant.js';
|
|
9
|
+
export { useTokenCount, getModelTokenLimit, MODEL_TOKEN_LIMITS } from './use-token-count.js';
|
|
10
|
+
export { useStream } from './use-stream.js';
|
|
11
|
+
export type { AssistantMessage, Annotation, AssistantStatus, UseAssistantOptions, UseAssistantReturn, } from './use-assistant.js';
|
|
12
|
+
export type { UseTokenCountOptions, UseTokenCountReturn } from './use-token-count.js';
|
|
13
|
+
export type { UseStreamOptions, UseStreamReturn } from './use-stream.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,YAAY,EACV,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEtF,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useAssistant Hook
|
|
3
|
+
*
|
|
4
|
+
* React hook for OpenAI Assistants API compatible interfaces.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import type { Message } from 'ai.matey.react.core';
|
|
9
|
+
/**
|
|
10
|
+
* Assistant message with additional metadata.
|
|
11
|
+
*/
|
|
12
|
+
export interface AssistantMessage extends Message {
|
|
13
|
+
/** Thread ID */
|
|
14
|
+
threadId?: string;
|
|
15
|
+
/** Run ID */
|
|
16
|
+
runId?: string;
|
|
17
|
+
/** File annotations */
|
|
18
|
+
annotations?: Annotation[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* File annotation.
|
|
22
|
+
*/
|
|
23
|
+
export interface Annotation {
|
|
24
|
+
/** Annotation type */
|
|
25
|
+
type: 'file_citation' | 'file_path';
|
|
26
|
+
/** Text content */
|
|
27
|
+
text: string;
|
|
28
|
+
/** File citation details */
|
|
29
|
+
file_citation?: {
|
|
30
|
+
file_id: string;
|
|
31
|
+
quote?: string;
|
|
32
|
+
};
|
|
33
|
+
/** File path details */
|
|
34
|
+
file_path?: {
|
|
35
|
+
file_id: string;
|
|
36
|
+
};
|
|
37
|
+
/** Start index */
|
|
38
|
+
start_index: number;
|
|
39
|
+
/** End index */
|
|
40
|
+
end_index: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Assistant run status.
|
|
44
|
+
*/
|
|
45
|
+
export type AssistantStatus = 'awaiting_message' | 'in_progress' | 'requires_action' | 'cancelling' | 'cancelled' | 'failed' | 'completed' | 'expired';
|
|
46
|
+
/**
|
|
47
|
+
* Assistant hook options.
|
|
48
|
+
*/
|
|
49
|
+
export interface UseAssistantOptions {
|
|
50
|
+
/** API endpoint */
|
|
51
|
+
api?: string;
|
|
52
|
+
/** Assistant ID */
|
|
53
|
+
assistantId?: string;
|
|
54
|
+
/** Thread ID for continuing a conversation */
|
|
55
|
+
threadId?: string;
|
|
56
|
+
/** Request headers */
|
|
57
|
+
headers?: Record<string, string>;
|
|
58
|
+
/** Request body extras */
|
|
59
|
+
body?: Record<string, unknown>;
|
|
60
|
+
/** Called when status changes */
|
|
61
|
+
onStatus?: (status: AssistantStatus) => void;
|
|
62
|
+
/** Called on error */
|
|
63
|
+
onError?: (error: Error) => void;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Assistant hook return value.
|
|
67
|
+
*/
|
|
68
|
+
export interface UseAssistantReturn {
|
|
69
|
+
/** Chat messages */
|
|
70
|
+
messages: AssistantMessage[];
|
|
71
|
+
/** Current input value */
|
|
72
|
+
input: string;
|
|
73
|
+
/** Set input value */
|
|
74
|
+
setInput: (input: string) => void;
|
|
75
|
+
/** Handle input change */
|
|
76
|
+
handleInputChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
77
|
+
/** Handle form submit */
|
|
78
|
+
handleSubmit: (e?: React.FormEvent<HTMLFormElement>) => void;
|
|
79
|
+
/** Submit message programmatically */
|
|
80
|
+
append: (message: string | Message) => Promise<void>;
|
|
81
|
+
/** Thread ID */
|
|
82
|
+
threadId: string | undefined;
|
|
83
|
+
/** Current status */
|
|
84
|
+
status: AssistantStatus;
|
|
85
|
+
/** Stop the current run */
|
|
86
|
+
stop: () => void;
|
|
87
|
+
/** Set messages */
|
|
88
|
+
setMessages: (messages: AssistantMessage[]) => void;
|
|
89
|
+
/** Error if any */
|
|
90
|
+
error: Error | undefined;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* useAssistant - React hook for OpenAI Assistants API.
|
|
94
|
+
*
|
|
95
|
+
* Provides state management for conversations with OpenAI Assistants,
|
|
96
|
+
* including thread management and run status tracking.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```tsx
|
|
100
|
+
* import { useAssistant } from 'ai.matey.react.hooks';
|
|
101
|
+
*
|
|
102
|
+
* function AssistantChat() {
|
|
103
|
+
* const { messages, input, handleInputChange, handleSubmit, status } = useAssistant({
|
|
104
|
+
* api: '/api/assistant',
|
|
105
|
+
* assistantId: 'asst_xxx',
|
|
106
|
+
* });
|
|
107
|
+
*
|
|
108
|
+
* return (
|
|
109
|
+
* <div>
|
|
110
|
+
* {messages.map((m) => (
|
|
111
|
+
* <div key={m.id}>{m.role}: {m.content}</div>
|
|
112
|
+
* ))}
|
|
113
|
+
* <form onSubmit={handleSubmit}>
|
|
114
|
+
* <input value={input} onChange={handleInputChange} />
|
|
115
|
+
* <button type="submit" disabled={status === 'in_progress'}>Send</button>
|
|
116
|
+
* </form>
|
|
117
|
+
* </div>
|
|
118
|
+
* );
|
|
119
|
+
* }
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export declare function useAssistant(options?: UseAssistantOptions): UseAssistantReturn;
|
|
123
|
+
//# sourceMappingURL=use-assistant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-assistant.d.ts","sourceRoot":"","sources":["../../src/use-assistant.ts"],"names":[],"mappings":"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"}
|