@curaious/uno-converse 0.1.7

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 ADDED
@@ -0,0 +1,282 @@
1
+ # @curaious/uno-converse
2
+
3
+ React hooks and utilities for building conversation UIs with [Uno Agent Server](https://github.com/curaious/uno).
4
+
5
+ ## Features
6
+
7
+ - 🎣 **React Hook** - `useConversation` hook for complete conversation state management
8
+ - 🌊 **Streaming Support** - Built-in SSE streaming with real-time message updates
9
+ - 📦 **Type Safe** - Full TypeScript support with comprehensive type definitions
10
+ - 🔌 **Flexible API Client** - Bring your own API client or use the built-in one
11
+ - 🎯 **Zero Dependencies** - Only React as a peer dependency
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ # npm
17
+ npm install @curaious/uno-converse
18
+
19
+ # yarn
20
+ yarn add @curaious/uno-converse
21
+
22
+ # pnpm
23
+ pnpm add @curaious/uno-converse
24
+ ```
25
+
26
+ ### GitHub Packages Registry
27
+
28
+ This package is published to GitHub Packages. You'll need to configure npm to use the GitHub registry for `@curaious` scoped packages:
29
+
30
+ ```bash
31
+ # Create or edit ~/.npmrc
32
+ echo "@curaious:registry=https://npm.pkg.github.com" >> ~/.npmrc
33
+ ```
34
+
35
+ You may also need to authenticate with a GitHub personal access token:
36
+
37
+ ```bash
38
+ echo "//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN" >> ~/.npmrc
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ```tsx
44
+ import { useConversation, createApiClient, MessageType, ContentType } from '@curaious/uno-converse';
45
+
46
+ // Create an API client
47
+ const client = createApiClient({
48
+ baseUrl: 'https://your-uno-server.com/api/agent-server',
49
+ headers: {
50
+ 'Authorization': 'Bearer your-api-key',
51
+ },
52
+ });
53
+
54
+ function ChatApp() {
55
+ const {
56
+ allMessages,
57
+ isStreaming,
58
+ sendMessage,
59
+ startNewChat,
60
+ conversations,
61
+ selectConversation,
62
+ } = useConversation({
63
+ namespace: 'my-app',
64
+ client,
65
+ });
66
+
67
+ const handleSend = async (text: string) => {
68
+ await sendMessage(
69
+ [{
70
+ type: MessageType.Message,
71
+ id: Date.now().toString(),
72
+ content: [{ type: ContentType.InputText, text }],
73
+ }],
74
+ {
75
+ baseUrl: client.baseUrl,
76
+ namespace: 'my-app',
77
+ agentName: 'my-agent',
78
+ }
79
+ );
80
+ };
81
+
82
+ return (
83
+ <div>
84
+ <button onClick={startNewChat}>New Chat</button>
85
+
86
+ <div className="messages">
87
+ {allMessages.map((msg) => (
88
+ <Message key={msg.message_id} message={msg} />
89
+ ))}
90
+ {isStreaming && <LoadingIndicator />}
91
+ </div>
92
+
93
+ <ChatInput onSend={handleSend} disabled={isStreaming} />
94
+ </div>
95
+ );
96
+ }
97
+ ```
98
+
99
+ ## API Reference
100
+
101
+ ### `useConversation(options)`
102
+
103
+ The main hook for managing conversation state.
104
+
105
+ #### Options
106
+
107
+ | Option | Type | Default | Description |
108
+ |--------|------|---------|-------------|
109
+ | `namespace` | `string` | required | Namespace for organizing conversations |
110
+ | `client` | `UnoApiClient` | required | API client for communicating with Uno server |
111
+ | `autoLoad` | `boolean` | `true` | Auto-load conversations on mount |
112
+
113
+ #### Return Value
114
+
115
+ ```typescript
116
+ interface UseConversationReturn {
117
+ // State
118
+ conversations: Conversation[];
119
+ conversationsLoading: boolean;
120
+ threads: Thread[];
121
+ threadsLoading: boolean;
122
+ currentThread: Thread | null;
123
+ messages: ConversationMessage[];
124
+ streamingMessage: ConversationMessage | null;
125
+ messagesLoading: boolean;
126
+ isStreaming: boolean;
127
+ currentConversationId: string | null;
128
+ currentThreadId: string | null;
129
+ allMessages: ConversationMessage[];
130
+
131
+ // Actions
132
+ loadConversations: () => Promise<void>;
133
+ selectConversation: (conversationId: string) => void;
134
+ loadThreads: (conversationId: string) => Promise<void>;
135
+ selectThread: (threadId: string) => void;
136
+ sendMessage: (messages: MessageUnion[], config: ConverseConfig) => Promise<void>;
137
+ startNewChat: () => void;
138
+ }
139
+ ```
140
+
141
+ ### `createApiClient(options)`
142
+
143
+ Creates a default API client using fetch.
144
+
145
+ ```typescript
146
+ const client = createApiClient({
147
+ baseUrl: 'https://your-server.com/api/agent-server',
148
+ headers: { 'Authorization': 'Bearer token' },
149
+ projectId: 'optional-project-id',
150
+ });
151
+ ```
152
+
153
+ ### Custom API Client
154
+
155
+ You can implement your own API client:
156
+
157
+ ```typescript
158
+ import type { UnoApiClient } from '@curaious/uno-converse';
159
+
160
+ const customClient: UnoApiClient = {
161
+ baseUrl: 'https://your-server.com',
162
+ headers: { 'Authorization': 'Bearer token' },
163
+
164
+ async getConversations(namespace) {
165
+ // Your implementation
166
+ },
167
+
168
+ async getThreads(conversationId, namespace) {
169
+ // Your implementation
170
+ },
171
+
172
+ async getMessages(threadId, namespace) {
173
+ // Your implementation
174
+ },
175
+
176
+ async getMessage(messageId, namespace) {
177
+ // Your implementation
178
+ },
179
+ };
180
+ ```
181
+
182
+ ### Streaming Utilities
183
+
184
+ For advanced use cases, you can use the streaming utilities directly:
185
+
186
+ ```typescript
187
+ import { streamSSE, ChunkProcessor } from '@curaious/uno-converse';
188
+
189
+ // Stream SSE events
190
+ await streamSSE(
191
+ 'https://your-server.com/converse',
192
+ { method: 'POST', body: JSON.stringify(payload) },
193
+ {
194
+ onChunk: (data) => console.log('Chunk:', data),
195
+ onComplete: () => console.log('Done'),
196
+ onError: (err) => console.error('Error:', err),
197
+ }
198
+ );
199
+
200
+ // Process chunks into conversation messages
201
+ const processor = new ChunkProcessor(
202
+ 'conversation-id',
203
+ 'thread-id',
204
+ (conversation) => updateUI(conversation)
205
+ );
206
+
207
+ processor.processChunk(jsonString);
208
+ ```
209
+
210
+ ## Message Types
211
+
212
+ The library exports comprehensive types for all message formats:
213
+
214
+ ```typescript
215
+ import {
216
+ MessageType,
217
+ ContentType,
218
+ Role,
219
+ type MessageUnion,
220
+ type InputMessage,
221
+ type FunctionCallMessage,
222
+ type ReasoningMessage,
223
+ } from '@curaious/uno-converse';
224
+
225
+ // Create a user message
226
+ const userMessage: InputMessage = {
227
+ type: MessageType.Message,
228
+ role: Role.User,
229
+ content: [
230
+ { type: ContentType.InputText, text: 'Hello!' },
231
+ ],
232
+ };
233
+ ```
234
+
235
+ ## Tool Call Approvals
236
+
237
+ Handle human-in-the-loop scenarios with function call approvals:
238
+
239
+ ```typescript
240
+ const { sendMessage } = useConversation({ ... });
241
+
242
+ // Approve or reject pending tool calls
243
+ const handleApproval = async (approvedIds: string[], rejectedIds: string[]) => {
244
+ await sendMessage(
245
+ [{
246
+ type: MessageType.FunctionCallApprovalResponse,
247
+ id: Date.now().toString(),
248
+ approved_call_ids: approvedIds,
249
+ rejected_call_ids: rejectedIds,
250
+ }],
251
+ converseConfig
252
+ );
253
+ };
254
+ ```
255
+
256
+ ## Type Guards
257
+
258
+ The library exports type guard functions for runtime type checking:
259
+
260
+ ```typescript
261
+ import {
262
+ isEasyMessage,
263
+ isInputMessage,
264
+ isFunctionCallMessage,
265
+ isReasoningMessage,
266
+ } from '@curaious/uno-converse';
267
+
268
+ allMessages.forEach((msg) => {
269
+ msg.messages.forEach((m) => {
270
+ if (isFunctionCallMessage(m)) {
271
+ console.log('Function call:', m.name, m.arguments);
272
+ } else if (isReasoningMessage(m)) {
273
+ console.log('Reasoning:', m.summary);
274
+ }
275
+ });
276
+ });
277
+ ```
278
+
279
+ ## License
280
+
281
+ MIT
282
+