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.
@@ -0,0 +1,75 @@
1
+ /**
2
+ * useStream Hook
3
+ *
4
+ * React hook for generic text streaming with state management.
5
+ *
6
+ * @module
7
+ */
8
+ /**
9
+ * Stream hook options.
10
+ */
11
+ export interface UseStreamOptions {
12
+ /** Called for each chunk */
13
+ onChunk?: (chunk: string) => void;
14
+ /** Called when stream completes */
15
+ onComplete?: (fullText: string) => void;
16
+ /** Called on error */
17
+ onError?: (error: Error) => void;
18
+ /** Initial text value */
19
+ initialText?: string;
20
+ }
21
+ /**
22
+ * Stream hook return value.
23
+ */
24
+ export interface UseStreamReturn {
25
+ /** Current streamed text */
26
+ text: string;
27
+ /** Whether streaming is active */
28
+ isStreaming: boolean;
29
+ /** Error if any */
30
+ error: Error | undefined;
31
+ /** Start streaming from a response */
32
+ startStream: (response: Response) => Promise<string>;
33
+ /** Start streaming from a ReadableStream */
34
+ startReadableStream: (stream: ReadableStream<Uint8Array>) => Promise<string>;
35
+ /** Start streaming from an async iterable */
36
+ startAsyncIterable: (iterable: AsyncIterable<string>) => Promise<string>;
37
+ /** Stop streaming */
38
+ stop: () => void;
39
+ /** Reset state */
40
+ reset: () => void;
41
+ /** Manually set text */
42
+ setText: (text: string) => void;
43
+ }
44
+ /**
45
+ * useStream - React hook for generic text streaming.
46
+ *
47
+ * Provides state management for streaming text from various sources
48
+ * including fetch responses, ReadableStreams, and async iterables.
49
+ *
50
+ * @example
51
+ * ```tsx
52
+ * import { useStream } from 'ai.matey.react.hooks';
53
+ *
54
+ * function StreamingComponent() {
55
+ * const { text, isStreaming, startStream, stop } = useStream({
56
+ * onComplete: (fullText) => console.log('Completed:', fullText),
57
+ * });
58
+ *
59
+ * const handleClick = async () => {
60
+ * const response = await fetch('/api/stream');
61
+ * await startStream(response);
62
+ * };
63
+ *
64
+ * return (
65
+ * <div>
66
+ * <button onClick={handleClick} disabled={isStreaming}>Start</button>
67
+ * <button onClick={stop} disabled={!isStreaming}>Stop</button>
68
+ * <pre>{text}</pre>
69
+ * </div>
70
+ * );
71
+ * }
72
+ * ```
73
+ */
74
+ export declare function useStream(options?: UseStreamOptions): UseStreamReturn;
75
+ //# sourceMappingURL=use-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-stream.d.ts","sourceRoot":"","sources":["../../src/use-stream.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4BAA4B;IAC5B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,mCAAmC;IACnC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,sBAAsB;IACtB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,WAAW,EAAE,OAAO,CAAC;IACrB,mBAAmB;IACnB,KAAK,EAAE,KAAK,GAAG,SAAS,CAAC;IACzB,sCAAsC;IACtC,WAAW,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,4CAA4C;IAC5C,mBAAmB,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7E,6CAA6C;IAC7C,kBAAkB,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACzE,qBAAqB;IACrB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,kBAAkB;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,wBAAwB;IACxB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,eAAe,CA0JzE"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * useTokenCount Hook
3
+ *
4
+ * React hook for estimating token counts.
5
+ *
6
+ * @module
7
+ */
8
+ /**
9
+ * Token count options.
10
+ */
11
+ export interface UseTokenCountOptions {
12
+ /** Text to count tokens for */
13
+ text?: string;
14
+ /** Model to use for estimation */
15
+ model?: string;
16
+ /** Custom tokenizer function */
17
+ tokenizer?: (text: string) => number;
18
+ /** Debounce delay in ms */
19
+ debounceMs?: number;
20
+ }
21
+ /**
22
+ * Token count return value.
23
+ */
24
+ export interface UseTokenCountReturn {
25
+ /** Estimated token count */
26
+ tokenCount: number;
27
+ /** Characters count */
28
+ characterCount: number;
29
+ /** Word count */
30
+ wordCount: number;
31
+ /** Whether estimation is in progress */
32
+ isEstimating: boolean;
33
+ /** Count tokens for text */
34
+ countTokens: (text: string) => number;
35
+ }
36
+ /**
37
+ * useTokenCount - React hook for estimating token counts.
38
+ *
39
+ * Provides real-time token estimation for text input,
40
+ * useful for staying within model context limits.
41
+ *
42
+ * @example
43
+ * ```tsx
44
+ * import { useTokenCount } from 'ai.matey.react.hooks';
45
+ *
46
+ * function TokenCounter() {
47
+ * const [text, setText] = useState('');
48
+ * const { tokenCount, characterCount, wordCount } = useTokenCount({ text });
49
+ *
50
+ * return (
51
+ * <div>
52
+ * <textarea value={text} onChange={(e) => setText(e.target.value)} />
53
+ * <p>Tokens: ~{tokenCount} | Words: {wordCount} | Characters: {characterCount}</p>
54
+ * </div>
55
+ * );
56
+ * }
57
+ * ```
58
+ */
59
+ export declare function useTokenCount(options?: UseTokenCountOptions): UseTokenCountReturn;
60
+ /**
61
+ * Model-specific token limits.
62
+ */
63
+ export declare const MODEL_TOKEN_LIMITS: Record<string, number>;
64
+ /**
65
+ * Get token limit for a model.
66
+ */
67
+ export declare function getModelTokenLimit(model: string): number | undefined;
68
+ //# sourceMappingURL=use-token-count.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-token-count.d.ts","sourceRoot":"","sources":["../../src/use-token-count.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,4BAA4B;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,YAAY,EAAE,OAAO,CAAC;IACtB,4BAA4B;IAC5B,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC;AA4BD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,mBAAmB,CAuDrF;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAgBrD,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAcpE"}
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "ai.matey.react.hooks",
3
+ "version": "0.2.0",
4
+ "description": "Additional React hooks for AI Matey - useAssistant, useStream, useTokenCount",
5
+ "type": "module",
6
+ "main": "./dist/cjs/index.js",
7
+ "module": "./dist/esm/index.js",
8
+ "types": "./dist/types/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/types/index.d.ts",
13
+ "default": "./dist/esm/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/types/index.d.ts",
17
+ "default": "./dist/cjs/index.js"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "readme.md",
24
+ "CHANGELOG.md",
25
+ "LICENSE"
26
+ ],
27
+ "scripts": {
28
+ "build": "npm run build:esm && npm run build:cjs && npm run build:types",
29
+ "build:esm": "tsc -p tsconfig.esm.json",
30
+ "build:cjs": "tsc -p tsconfig.cjs.json",
31
+ "build:types": "tsc -p tsconfig.types.json",
32
+ "clean": "rm -rf dist",
33
+ "typecheck": "tsc --noEmit",
34
+ "test": "vitest run"
35
+ },
36
+ "dependencies": {
37
+ "ai.matey.types": "*",
38
+ "ai.matey.react.core": "*"
39
+ },
40
+ "peerDependencies": {
41
+ "react": ">=18.0.0"
42
+ },
43
+ "peerDependenciesMeta": {
44
+ "react": {
45
+ "optional": false
46
+ }
47
+ },
48
+ "devDependencies": {
49
+ "@types/react": "^18.2.0",
50
+ "react": "^18.2.0",
51
+ "typescript": "^5.9.3",
52
+ "vitest": "^3.2.4"
53
+ },
54
+ "keywords": [
55
+ "ai",
56
+ "llm",
57
+ "react",
58
+ "hooks",
59
+ "useAssistant",
60
+ "useStream",
61
+ "ai-matey"
62
+ ],
63
+ "author": "AI Matey",
64
+ "license": "MIT",
65
+ "homepage": "https://github.com/johnhenry/ai.matey#readme",
66
+ "bugs": {
67
+ "url": "https://github.com/johnhenry/ai.matey/issues"
68
+ },
69
+ "repository": {
70
+ "type": "git",
71
+ "url": "git+https://github.com/johnhenry/ai.matey.git",
72
+ "directory": "packages/react-hooks"
73
+ },
74
+ "engines": {
75
+ "node": ">=18.0.0"
76
+ }
77
+ }
package/readme.md ADDED
@@ -0,0 +1,143 @@
1
+ # ai.matey.react.hooks
2
+
3
+ Additional specialized React hooks for AI applications.
4
+
5
+ Part of the [ai.matey](https://github.com/johnhenry/ai.matey) monorepo.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install ai.matey.react.hooks
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```tsx
16
+ import { useAssistant } from 'ai.matey.react.hooks';
17
+
18
+ function AssistantChat() {
19
+ const { messages, input, handleInputChange, handleSubmit, status } = useAssistant({
20
+ api: '/api/assistant',
21
+ assistantId: 'asst_xxx',
22
+ });
23
+
24
+ return (
25
+ <div>
26
+ {messages.map((m) => (
27
+ <div key={m.id}>
28
+ <strong>{m.role}:</strong> {m.content}
29
+ </div>
30
+ ))}
31
+ <form onSubmit={handleSubmit}>
32
+ <input value={input} onChange={handleInputChange} />
33
+ <button type="submit" disabled={status === 'in_progress'}>
34
+ Send
35
+ </button>
36
+ </form>
37
+ <p>Status: {status}</p>
38
+ </div>
39
+ );
40
+ }
41
+ ```
42
+
43
+ ## Exports
44
+
45
+ ### Hooks
46
+
47
+ - `useAssistant` - OpenAI Assistants API integration with thread management
48
+ - `useTokenCount` - Token counting and context window tracking
49
+ - `useStream` - Low-level stream consumption hook
50
+
51
+ ### Types
52
+
53
+ - `AssistantMessage`, `Annotation`, `AssistantStatus` - Assistant types
54
+ - `UseAssistantOptions`, `UseAssistantReturn` - useAssistant types
55
+ - `UseTokenCountOptions`, `UseTokenCountReturn` - useTokenCount types
56
+ - `UseStreamOptions`, `UseStreamReturn` - useStream types
57
+
58
+ ## API Reference
59
+
60
+ ### useAssistant
61
+
62
+ React hook for OpenAI Assistants API with thread and run management.
63
+
64
+ ```tsx
65
+ const {
66
+ messages, // AssistantMessage[] - Chat history with annotations
67
+ input, // string - Current input
68
+ setInput, // (value: string) => void
69
+ handleInputChange, // (e: ChangeEvent) => void
70
+ handleSubmit, // (e?: FormEvent) => void
71
+ append, // (message: string | Message) => Promise<void>
72
+ threadId, // string | undefined - Current thread ID
73
+ status, // AssistantStatus - Run status
74
+ stop, // () => void - Cancel current run
75
+ setMessages, // (messages: AssistantMessage[]) => void
76
+ error, // Error | undefined
77
+ } = useAssistant({
78
+ api: '/api/assistant', // API endpoint
79
+ assistantId: 'asst_xxx', // OpenAI Assistant ID
80
+ threadId: 'thread_xxx', // Existing thread to continue
81
+ headers: {}, // Request headers
82
+ body: {}, // Extra request body
83
+ onStatus: (status) => {}, // Called on status change
84
+ onError: (error) => {}, // Called on error
85
+ });
86
+ ```
87
+
88
+ **AssistantStatus values:**
89
+ - `awaiting_message` - Ready for input
90
+ - `in_progress` - Processing request
91
+ - `requires_action` - Tool call pending
92
+ - `completed` - Run finished
93
+ - `failed` - Run failed
94
+ - `cancelled` - Run cancelled
95
+ - `expired` - Run expired
96
+
97
+ ### useTokenCount
98
+
99
+ Track token usage and context window limits.
100
+
101
+ ```tsx
102
+ const {
103
+ tokenCount, // number - Current token count
104
+ maxTokens, // number - Model's max context
105
+ remainingTokens, // number - Tokens remaining
106
+ isNearLimit, // boolean - Within 10% of limit
107
+ isOverLimit, // boolean - Exceeded limit
108
+ updateText, // (text: string) => void - Update counted text
109
+ } = useTokenCount({
110
+ model: 'gpt-4', // Model name for limits
111
+ text: '', // Initial text to count
112
+ warningThreshold: 0.9, // Threshold for isNearLimit
113
+ });
114
+ ```
115
+
116
+ **Supported models:**
117
+ - `gpt-4`, `gpt-4-turbo`: 128,000 tokens
118
+ - `gpt-3.5-turbo`: 16,385 tokens
119
+ - `claude-3-opus`, `claude-3-sonnet`: 200,000 tokens
120
+ - And more...
121
+
122
+ ### useStream
123
+
124
+ Low-level hook for consuming async iterables/streams.
125
+
126
+ ```tsx
127
+ const {
128
+ data, // T[] - Accumulated data
129
+ isStreaming, // boolean
130
+ error, // Error | undefined
131
+ start, // (stream: AsyncIterable<T>) => void
132
+ stop, // () => void
133
+ reset, // () => void
134
+ } = useStream<ChunkType>({
135
+ onChunk: (chunk) => {}, // Called for each chunk
136
+ onComplete: (data) => {}, // Called when done
137
+ onError: (error) => {}, // Called on error
138
+ });
139
+ ```
140
+
141
+ ## License
142
+
143
+ MIT - see [LICENSE](./LICENSE) for details.