@libreapps/react 1.1.1
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.md +21 -0
- package/README.md +347 -0
- package/dist/index.d.mts +255 -0
- package/dist/index.d.ts +255 -0
- package/dist/index.js +548 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +539 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +100 -0
- package/src/components/LibreAppsProvider.test.tsx +346 -0
- package/src/components/LibreAppsProvider.tsx +508 -0
- package/src/hooks/index.ts +39 -0
- package/src/hooks/types.ts +162 -0
- package/src/hooks/useAttachments.ts +0 -0
- package/src/hooks/useAuth.ts +0 -0
- package/src/hooks/useComponent.ts +0 -0
- package/src/hooks/useGenerativeUI.ts +0 -0
- package/src/hooks/useMCP.ts +0 -0
- package/src/hooks/useMessage.ts +105 -0
- package/src/hooks/useModelConfig.ts +0 -0
- package/src/hooks/useStreaming.ts +161 -0
- package/src/hooks/useSuggestions.ts +0 -0
- package/src/hooks/useThread.ts +0 -0
- package/src/hooks/useTool.ts +0 -0
- package/src/index.ts +40 -0
- package/src/types/index.ts +25 -0
- package/src/utils/cn.ts +6 -0
- package/src/utils/id.ts +6 -0
- package/src/utils/stream.ts +33 -0
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React, { createContext, useContext, useCallback, useEffect, useMemo, useState } from 'react'
|
|
4
|
+
import { nanoid } from 'nanoid'
|
|
5
|
+
import { z } from 'zod'
|
|
6
|
+
|
|
7
|
+
// Types
|
|
8
|
+
export interface LibreAppsComponent {
|
|
9
|
+
name: string
|
|
10
|
+
component: React.ComponentType<any>
|
|
11
|
+
description?: string
|
|
12
|
+
parameters?: z.ZodType<any>
|
|
13
|
+
generateUI?: (params: any) => React.ReactElement
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface LibreAppsTool {
|
|
17
|
+
name: string
|
|
18
|
+
description: string
|
|
19
|
+
parameters: z.ZodType<any>
|
|
20
|
+
execute: (params: any) => Promise<any>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface Message {
|
|
24
|
+
id: string
|
|
25
|
+
role: 'user' | 'assistant' | 'system' | 'tool'
|
|
26
|
+
content: string | React.ReactElement
|
|
27
|
+
timestamp: Date
|
|
28
|
+
threadId: string
|
|
29
|
+
toolCalls?: ToolCall[]
|
|
30
|
+
metadata?: Record<string, any>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ToolCall {
|
|
34
|
+
id: string
|
|
35
|
+
name: string
|
|
36
|
+
arguments: any
|
|
37
|
+
result?: any
|
|
38
|
+
status: 'pending' | 'running' | 'completed' | 'failed'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Thread {
|
|
42
|
+
id: string
|
|
43
|
+
messages: Message[]
|
|
44
|
+
createdAt: Date
|
|
45
|
+
updatedAt: Date
|
|
46
|
+
metadata?: Record<string, any>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface LibreAppsContextValue {
|
|
50
|
+
// Configuration
|
|
51
|
+
apiKey?: string
|
|
52
|
+
apiUrl?: string
|
|
53
|
+
model?: string
|
|
54
|
+
|
|
55
|
+
// Components & Tools
|
|
56
|
+
components: Map<string, LibreAppsComponent>
|
|
57
|
+
tools: Map<string, LibreAppsTool>
|
|
58
|
+
|
|
59
|
+
// Thread Management
|
|
60
|
+
threads: Map<string, Thread>
|
|
61
|
+
activeThreadId?: string
|
|
62
|
+
|
|
63
|
+
// Message Operations
|
|
64
|
+
sendMessage: (content: string, threadId?: string) => Promise<Message>
|
|
65
|
+
streamMessage: (content: string, threadId?: string) => AsyncGenerator<Message>
|
|
66
|
+
|
|
67
|
+
// Thread Operations
|
|
68
|
+
createThread: (metadata?: Record<string, any>) => Thread
|
|
69
|
+
switchThread: (threadId: string) => void
|
|
70
|
+
deleteThread: (threadId: string) => void
|
|
71
|
+
|
|
72
|
+
// Component Operations
|
|
73
|
+
registerComponent: (component: LibreAppsComponent) => void
|
|
74
|
+
unregisterComponent: (name: string) => void
|
|
75
|
+
renderComponent: (name: string, props: any) => React.ReactElement | null
|
|
76
|
+
|
|
77
|
+
// Tool Operations
|
|
78
|
+
registerTool: (tool: LibreAppsTool) => void
|
|
79
|
+
unregisterTool: (name: string) => void
|
|
80
|
+
executeTool: (name: string, params: any) => Promise<any>
|
|
81
|
+
|
|
82
|
+
// State Management
|
|
83
|
+
isStreaming: boolean
|
|
84
|
+
responseStage?: 'thinking' | 'generating' | 'tool-calling' | 'completed'
|
|
85
|
+
error?: Error
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const LibreAppsContext = createContext<LibreAppsContextValue | undefined>(undefined)
|
|
89
|
+
|
|
90
|
+
export interface LibreAppsProviderProps {
|
|
91
|
+
children: React.ReactNode
|
|
92
|
+
apiKey?: string
|
|
93
|
+
apiUrl?: string
|
|
94
|
+
model?: string
|
|
95
|
+
components?: LibreAppsComponent[]
|
|
96
|
+
tools?: LibreAppsTool[]
|
|
97
|
+
initialMessages?: Message[]
|
|
98
|
+
onMessage?: (message: Message) => void
|
|
99
|
+
onError?: (error: Error) => void
|
|
100
|
+
enableStreaming?: boolean
|
|
101
|
+
enableMCP?: boolean
|
|
102
|
+
mcpServers?: string[]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function LibreAppsProvider({
|
|
106
|
+
children,
|
|
107
|
+
apiKey,
|
|
108
|
+
apiUrl = 'https://api.libreapps.com/v1',
|
|
109
|
+
model = 'gpt-4-turbo-preview',
|
|
110
|
+
components: initialComponents = [],
|
|
111
|
+
tools: initialTools = [],
|
|
112
|
+
initialMessages = [],
|
|
113
|
+
onMessage,
|
|
114
|
+
onError,
|
|
115
|
+
enableStreaming = true,
|
|
116
|
+
// @ts-expect-error - MCP integration coming soon
|
|
117
|
+
enableMCP = false, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
118
|
+
// @ts-expect-error - MCP server support coming soon
|
|
119
|
+
mcpServers = [] // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
120
|
+
}: LibreAppsProviderProps) {
|
|
121
|
+
// State
|
|
122
|
+
const [components] = useState(() => new Map(initialComponents.map(c => [c.name, c])))
|
|
123
|
+
const [tools] = useState(() => new Map(initialTools.map(t => [t.name, t])))
|
|
124
|
+
const [threads, setThreads] = useState<Map<string, Thread>>(new Map())
|
|
125
|
+
const [activeThreadId, setActiveThreadId] = useState<string>()
|
|
126
|
+
const [isStreaming, setIsStreaming] = useState(false)
|
|
127
|
+
const [responseStage, setResponseStage] = useState<LibreAppsContextValue['responseStage']>()
|
|
128
|
+
const [error, setError] = useState<Error>()
|
|
129
|
+
|
|
130
|
+
// Initialize default thread
|
|
131
|
+
useEffect(() => {
|
|
132
|
+
const defaultThread = createThread({ name: 'default' })
|
|
133
|
+
if (initialMessages.length > 0) {
|
|
134
|
+
defaultThread.messages = initialMessages
|
|
135
|
+
}
|
|
136
|
+
setActiveThreadId(defaultThread.id)
|
|
137
|
+
}, [])
|
|
138
|
+
|
|
139
|
+
// Thread Operations
|
|
140
|
+
const createThread = useCallback((metadata?: Record<string, any>): Thread => {
|
|
141
|
+
const thread: Thread = {
|
|
142
|
+
id: nanoid(),
|
|
143
|
+
messages: [],
|
|
144
|
+
createdAt: new Date(),
|
|
145
|
+
updatedAt: new Date(),
|
|
146
|
+
metadata
|
|
147
|
+
}
|
|
148
|
+
setThreads(prev => new Map(prev).set(thread.id, thread))
|
|
149
|
+
return thread
|
|
150
|
+
}, [])
|
|
151
|
+
|
|
152
|
+
const switchThread = useCallback((threadId: string) => {
|
|
153
|
+
if (threads.has(threadId)) {
|
|
154
|
+
setActiveThreadId(threadId)
|
|
155
|
+
} else {
|
|
156
|
+
throw new Error(`Thread ${threadId} not found`)
|
|
157
|
+
}
|
|
158
|
+
}, [threads])
|
|
159
|
+
|
|
160
|
+
const deleteThread = useCallback((threadId: string) => {
|
|
161
|
+
setThreads(prev => {
|
|
162
|
+
const next = new Map(prev)
|
|
163
|
+
next.delete(threadId)
|
|
164
|
+
return next
|
|
165
|
+
})
|
|
166
|
+
if (activeThreadId === threadId) {
|
|
167
|
+
const remainingThreads = Array.from(threads.keys()).filter(id => id !== threadId)
|
|
168
|
+
setActiveThreadId(remainingThreads[0])
|
|
169
|
+
}
|
|
170
|
+
}, [activeThreadId, threads])
|
|
171
|
+
|
|
172
|
+
// Message Operations
|
|
173
|
+
const sendMessage = useCallback(async (content: string, threadId?: string): Promise<Message> => {
|
|
174
|
+
const targetThreadId = threadId || activeThreadId
|
|
175
|
+
if (!targetThreadId) {
|
|
176
|
+
throw new Error('No active thread')
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const thread = threads.get(targetThreadId)
|
|
180
|
+
if (!thread) {
|
|
181
|
+
throw new Error(`Thread ${targetThreadId} not found`)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Create user message
|
|
185
|
+
const userMessage: Message = {
|
|
186
|
+
id: nanoid(),
|
|
187
|
+
role: 'user',
|
|
188
|
+
content,
|
|
189
|
+
timestamp: new Date(),
|
|
190
|
+
threadId: targetThreadId
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Add to thread
|
|
194
|
+
thread.messages.push(userMessage)
|
|
195
|
+
thread.updatedAt = new Date()
|
|
196
|
+
setThreads(new Map(threads))
|
|
197
|
+
|
|
198
|
+
// Notify callback
|
|
199
|
+
onMessage?.(userMessage)
|
|
200
|
+
|
|
201
|
+
// Send to API
|
|
202
|
+
setIsStreaming(true)
|
|
203
|
+
setResponseStage('thinking')
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
const response = await fetch(`${apiUrl}/chat/completions`, {
|
|
207
|
+
method: 'POST',
|
|
208
|
+
headers: {
|
|
209
|
+
'Content-Type': 'application/json',
|
|
210
|
+
'Authorization': `Bearer ${apiKey}`
|
|
211
|
+
},
|
|
212
|
+
body: JSON.stringify({
|
|
213
|
+
model,
|
|
214
|
+
messages: thread.messages.map(m => ({
|
|
215
|
+
role: m.role,
|
|
216
|
+
content: typeof m.content === 'string' ? m.content : 'Component rendered'
|
|
217
|
+
})),
|
|
218
|
+
tools: Array.from(tools.values()).map(t => ({
|
|
219
|
+
type: 'function',
|
|
220
|
+
function: {
|
|
221
|
+
name: t.name,
|
|
222
|
+
description: t.description,
|
|
223
|
+
parameters: t.parameters
|
|
224
|
+
}
|
|
225
|
+
})),
|
|
226
|
+
stream: enableStreaming
|
|
227
|
+
})
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
if (!response.ok) {
|
|
231
|
+
throw new Error(`API error: ${response.statusText}`)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
setResponseStage('generating')
|
|
235
|
+
|
|
236
|
+
// Handle response
|
|
237
|
+
const data = await response.json()
|
|
238
|
+
const assistantMessage: Message = {
|
|
239
|
+
id: nanoid(),
|
|
240
|
+
role: 'assistant',
|
|
241
|
+
content: data.choices[0].message.content,
|
|
242
|
+
timestamp: new Date(),
|
|
243
|
+
threadId: targetThreadId
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Handle tool calls
|
|
247
|
+
if (data.choices[0].message.tool_calls) {
|
|
248
|
+
setResponseStage('tool-calling')
|
|
249
|
+
assistantMessage.toolCalls = await Promise.all(
|
|
250
|
+
data.choices[0].message.tool_calls.map(async (call: any) => {
|
|
251
|
+
const tool = tools.get(call.function.name)
|
|
252
|
+
if (!tool) {
|
|
253
|
+
return {
|
|
254
|
+
id: call.id,
|
|
255
|
+
name: call.function.name,
|
|
256
|
+
arguments: call.function.arguments,
|
|
257
|
+
status: 'failed',
|
|
258
|
+
result: `Tool ${call.function.name} not found`
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
try {
|
|
263
|
+
const result = await tool.execute(JSON.parse(call.function.arguments))
|
|
264
|
+
return {
|
|
265
|
+
id: call.id,
|
|
266
|
+
name: call.function.name,
|
|
267
|
+
arguments: call.function.arguments,
|
|
268
|
+
status: 'completed',
|
|
269
|
+
result
|
|
270
|
+
}
|
|
271
|
+
} catch (error) {
|
|
272
|
+
return {
|
|
273
|
+
id: call.id,
|
|
274
|
+
name: call.function.name,
|
|
275
|
+
arguments: call.function.arguments,
|
|
276
|
+
status: 'failed',
|
|
277
|
+
result: error instanceof Error ? error.message : 'Unknown error'
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Add assistant message
|
|
285
|
+
thread.messages.push(assistantMessage)
|
|
286
|
+
thread.updatedAt = new Date()
|
|
287
|
+
setThreads(new Map(threads))
|
|
288
|
+
|
|
289
|
+
// Notify callback
|
|
290
|
+
onMessage?.(assistantMessage)
|
|
291
|
+
|
|
292
|
+
setResponseStage('completed')
|
|
293
|
+
return assistantMessage
|
|
294
|
+
} catch (err) {
|
|
295
|
+
const error = err instanceof Error ? err : new Error('Unknown error')
|
|
296
|
+
setError(error)
|
|
297
|
+
onError?.(error)
|
|
298
|
+
throw error
|
|
299
|
+
} finally {
|
|
300
|
+
setIsStreaming(false)
|
|
301
|
+
setResponseStage(undefined)
|
|
302
|
+
}
|
|
303
|
+
}, [apiKey, apiUrl, model, activeThreadId, threads, tools, onMessage, onError, enableStreaming])
|
|
304
|
+
|
|
305
|
+
// Streaming Message Operation
|
|
306
|
+
const streamMessage = useCallback(async function* (
|
|
307
|
+
content: string,
|
|
308
|
+
threadId?: string
|
|
309
|
+
): AsyncGenerator<Message> {
|
|
310
|
+
const targetThreadId = threadId || activeThreadId
|
|
311
|
+
if (!targetThreadId) {
|
|
312
|
+
throw new Error('No active thread')
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const thread = threads.get(targetThreadId)
|
|
316
|
+
if (!thread) {
|
|
317
|
+
throw new Error(`Thread ${targetThreadId} not found`)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Create user message
|
|
321
|
+
const userMessage: Message = {
|
|
322
|
+
id: nanoid(),
|
|
323
|
+
role: 'user',
|
|
324
|
+
content,
|
|
325
|
+
timestamp: new Date(),
|
|
326
|
+
threadId: targetThreadId
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
thread.messages.push(userMessage)
|
|
330
|
+
yield userMessage
|
|
331
|
+
|
|
332
|
+
// Stream from API
|
|
333
|
+
setIsStreaming(true)
|
|
334
|
+
setResponseStage('thinking')
|
|
335
|
+
|
|
336
|
+
try {
|
|
337
|
+
const response = await fetch(`${apiUrl}/chat/completions`, {
|
|
338
|
+
method: 'POST',
|
|
339
|
+
headers: {
|
|
340
|
+
'Content-Type': 'application/json',
|
|
341
|
+
'Authorization': `Bearer ${apiKey}`
|
|
342
|
+
},
|
|
343
|
+
body: JSON.stringify({
|
|
344
|
+
model,
|
|
345
|
+
messages: thread.messages.map(m => ({
|
|
346
|
+
role: m.role,
|
|
347
|
+
content: typeof m.content === 'string' ? m.content : 'Component rendered'
|
|
348
|
+
})),
|
|
349
|
+
stream: true
|
|
350
|
+
})
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
if (!response.ok) {
|
|
354
|
+
throw new Error(`API error: ${response.statusText}`)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
setResponseStage('generating')
|
|
358
|
+
|
|
359
|
+
const reader = response.body?.getReader()
|
|
360
|
+
if (!reader) {
|
|
361
|
+
throw new Error('No response body')
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const decoder = new TextDecoder()
|
|
365
|
+
let assistantMessage: Message = {
|
|
366
|
+
id: nanoid(),
|
|
367
|
+
role: 'assistant',
|
|
368
|
+
content: '',
|
|
369
|
+
timestamp: new Date(),
|
|
370
|
+
threadId: targetThreadId
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
while (true) {
|
|
374
|
+
const { done, value } = await reader.read()
|
|
375
|
+
if (done) break
|
|
376
|
+
|
|
377
|
+
const chunk = decoder.decode(value)
|
|
378
|
+
const lines = chunk.split('\n').filter(line => line.trim() !== '')
|
|
379
|
+
|
|
380
|
+
for (const line of lines) {
|
|
381
|
+
if (line.startsWith('data: ')) {
|
|
382
|
+
const data = line.slice(6)
|
|
383
|
+
if (data === '[DONE]') continue
|
|
384
|
+
|
|
385
|
+
try {
|
|
386
|
+
const parsed = JSON.parse(data)
|
|
387
|
+
if (parsed.choices?.[0]?.delta?.content) {
|
|
388
|
+
assistantMessage.content += parsed.choices[0].delta.content
|
|
389
|
+
yield { ...assistantMessage }
|
|
390
|
+
}
|
|
391
|
+
} catch (e) {
|
|
392
|
+
console.error('Error parsing SSE data:', e)
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
thread.messages.push(assistantMessage)
|
|
399
|
+
thread.updatedAt = new Date()
|
|
400
|
+
setThreads(new Map(threads))
|
|
401
|
+
|
|
402
|
+
setResponseStage('completed')
|
|
403
|
+
} finally {
|
|
404
|
+
setIsStreaming(false)
|
|
405
|
+
setResponseStage(undefined)
|
|
406
|
+
}
|
|
407
|
+
}, [apiKey, apiUrl, model, activeThreadId, threads])
|
|
408
|
+
|
|
409
|
+
// Component Operations
|
|
410
|
+
const registerComponent = useCallback((component: LibreAppsComponent) => {
|
|
411
|
+
components.set(component.name, component)
|
|
412
|
+
}, [components])
|
|
413
|
+
|
|
414
|
+
const unregisterComponent = useCallback((name: string) => {
|
|
415
|
+
components.delete(name)
|
|
416
|
+
}, [components])
|
|
417
|
+
|
|
418
|
+
const renderComponent = useCallback((name: string, props: any): React.ReactElement | null => {
|
|
419
|
+
const component = components.get(name)
|
|
420
|
+
if (!component) return null
|
|
421
|
+
|
|
422
|
+
if (component.generateUI) {
|
|
423
|
+
return component.generateUI(props)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const Component = component.component
|
|
427
|
+
return <Component {...props} />
|
|
428
|
+
}, [components])
|
|
429
|
+
|
|
430
|
+
// Tool Operations
|
|
431
|
+
const registerTool = useCallback((tool: LibreAppsTool) => {
|
|
432
|
+
tools.set(tool.name, tool)
|
|
433
|
+
}, [tools])
|
|
434
|
+
|
|
435
|
+
const unregisterTool = useCallback((name: string) => {
|
|
436
|
+
tools.delete(name)
|
|
437
|
+
}, [tools])
|
|
438
|
+
|
|
439
|
+
const executeTool = useCallback(async (name: string, params: any): Promise<any> => {
|
|
440
|
+
const tool = tools.get(name)
|
|
441
|
+
if (!tool) {
|
|
442
|
+
throw new Error(`Tool ${name} not found`)
|
|
443
|
+
}
|
|
444
|
+
return tool.execute(params)
|
|
445
|
+
}, [tools])
|
|
446
|
+
|
|
447
|
+
// Context value
|
|
448
|
+
const contextValue = useMemo<LibreAppsContextValue>(() => ({
|
|
449
|
+
apiKey,
|
|
450
|
+
apiUrl,
|
|
451
|
+
model,
|
|
452
|
+
components,
|
|
453
|
+
tools,
|
|
454
|
+
threads,
|
|
455
|
+
activeThreadId,
|
|
456
|
+
sendMessage,
|
|
457
|
+
streamMessage,
|
|
458
|
+
createThread,
|
|
459
|
+
switchThread,
|
|
460
|
+
deleteThread,
|
|
461
|
+
registerComponent,
|
|
462
|
+
unregisterComponent,
|
|
463
|
+
renderComponent,
|
|
464
|
+
registerTool,
|
|
465
|
+
unregisterTool,
|
|
466
|
+
executeTool,
|
|
467
|
+
isStreaming,
|
|
468
|
+
responseStage,
|
|
469
|
+
error
|
|
470
|
+
}), [
|
|
471
|
+
apiKey,
|
|
472
|
+
apiUrl,
|
|
473
|
+
model,
|
|
474
|
+
components,
|
|
475
|
+
tools,
|
|
476
|
+
threads,
|
|
477
|
+
activeThreadId,
|
|
478
|
+
sendMessage,
|
|
479
|
+
streamMessage,
|
|
480
|
+
createThread,
|
|
481
|
+
switchThread,
|
|
482
|
+
deleteThread,
|
|
483
|
+
registerComponent,
|
|
484
|
+
unregisterComponent,
|
|
485
|
+
renderComponent,
|
|
486
|
+
registerTool,
|
|
487
|
+
unregisterTool,
|
|
488
|
+
executeTool,
|
|
489
|
+
isStreaming,
|
|
490
|
+
responseStage,
|
|
491
|
+
error
|
|
492
|
+
])
|
|
493
|
+
|
|
494
|
+
return (
|
|
495
|
+
<LibreAppsContext.Provider value={contextValue}>
|
|
496
|
+
{children}
|
|
497
|
+
</LibreAppsContext.Provider>
|
|
498
|
+
)
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Hook to use LibreApps context
|
|
502
|
+
export function useLibreApps() {
|
|
503
|
+
const context = useContext(LibreAppsContext)
|
|
504
|
+
if (!context) {
|
|
505
|
+
throw new Error('useLibreApps must be used within LibreAppsProvider')
|
|
506
|
+
}
|
|
507
|
+
return context
|
|
508
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Core LibreApps hooks for AI interactions
|
|
2
|
+
export { useLibreApps } from '../components/LibreAppsProvider'
|
|
3
|
+
export { useMessage } from './useMessage'
|
|
4
|
+
// export { useThread } from './useThread'
|
|
5
|
+
// export { useComponent } from './useComponent'
|
|
6
|
+
// export { useTool } from './useTool'
|
|
7
|
+
export { useStreaming } from './useStreaming'
|
|
8
|
+
// export { useSuggestions } from './useSuggestions'
|
|
9
|
+
// export { useModelConfig } from './useModelConfig'
|
|
10
|
+
// export { useMCP } from './useMCP'
|
|
11
|
+
// export { useGenerativeUI } from './useGenerativeUI'
|
|
12
|
+
// export { useAuth } from './useAuth'
|
|
13
|
+
// export { useAttachments } from './useAttachments'
|
|
14
|
+
|
|
15
|
+
// Type exports
|
|
16
|
+
export type {
|
|
17
|
+
UseMessageOptions,
|
|
18
|
+
UseMessageReturn,
|
|
19
|
+
// UseThreadOptions,
|
|
20
|
+
// UseThreadReturn,
|
|
21
|
+
// UseComponentOptions,
|
|
22
|
+
// UseComponentReturn,
|
|
23
|
+
// UseToolOptions,
|
|
24
|
+
// UseToolReturn,
|
|
25
|
+
UseStreamingOptions,
|
|
26
|
+
UseStreamingReturn,
|
|
27
|
+
// UseSuggestionsOptions,
|
|
28
|
+
// UseSuggestionsReturn,
|
|
29
|
+
// UseModelConfigOptions,
|
|
30
|
+
// UseModelConfigReturn,
|
|
31
|
+
// UseMCPOptions,
|
|
32
|
+
// UseMCPReturn,
|
|
33
|
+
// UseGenerativeUIOptions,
|
|
34
|
+
// UseGenerativeUIReturn,
|
|
35
|
+
// UseAuthOptions,
|
|
36
|
+
// UseAuthReturn,
|
|
37
|
+
// UseAttachmentsOptions,
|
|
38
|
+
// UseAttachmentsReturn
|
|
39
|
+
} from './types'
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// Hook type definitions
|
|
2
|
+
|
|
3
|
+
export interface UseMessageOptions {
|
|
4
|
+
threadId?: string
|
|
5
|
+
onSuccess?: (message: any) => void
|
|
6
|
+
onError?: (error: Error) => void
|
|
7
|
+
autoRetry?: boolean
|
|
8
|
+
maxRetries?: number
|
|
9
|
+
retryDelay?: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UseMessageReturn {
|
|
13
|
+
sendMessage: (content: string) => Promise<any>
|
|
14
|
+
sendMessageWithAttachments: (content: string, attachments: File[]) => Promise<any>
|
|
15
|
+
isLoading: boolean
|
|
16
|
+
error: Error | null
|
|
17
|
+
lastMessage: any | null
|
|
18
|
+
clearError: () => void
|
|
19
|
+
retry: () => Promise<void>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface UseStreamingOptions {
|
|
23
|
+
threadId?: string
|
|
24
|
+
onChunk?: (chunk: string) => void
|
|
25
|
+
onComplete?: (message: any) => void
|
|
26
|
+
onError?: (error: Error) => void
|
|
27
|
+
bufferSize?: number
|
|
28
|
+
throttleMs?: number
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface UseStreamingReturn {
|
|
32
|
+
streamMessage: (content: string) => Promise<void>
|
|
33
|
+
isStreaming: boolean
|
|
34
|
+
currentMessage: string
|
|
35
|
+
error: Error | null
|
|
36
|
+
stopStreaming: () => void
|
|
37
|
+
clearMessage: () => void
|
|
38
|
+
progress: number
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface UseThreadOptions {
|
|
42
|
+
maxThreads?: number
|
|
43
|
+
autoArchive?: boolean
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface UseThreadReturn {
|
|
47
|
+
threads: Map<string, any>
|
|
48
|
+
activeThread: any | undefined
|
|
49
|
+
createThread: (metadata?: Record<string, any>) => any
|
|
50
|
+
switchThread: (threadId: string) => void
|
|
51
|
+
deleteThread: (threadId: string) => void
|
|
52
|
+
updateThreadMetadata: (threadId: string, metadata: Record<string, any>) => void
|
|
53
|
+
getThreadMessages: (threadId: string) => any[]
|
|
54
|
+
clearThread: (threadId: string) => void
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface UseComponentOptions {
|
|
58
|
+
lazy?: boolean
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface UseComponentReturn {
|
|
62
|
+
registerComponent: (component: any) => void
|
|
63
|
+
unregisterComponent: (name: string) => void
|
|
64
|
+
renderComponent: (name: string, props: any) => React.ReactElement | null
|
|
65
|
+
getComponent: (name: string) => any | undefined
|
|
66
|
+
hasComponent: (name: string) => boolean
|
|
67
|
+
listComponents: () => string[]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface UseToolOptions {
|
|
71
|
+
timeout?: number
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface UseToolReturn {
|
|
75
|
+
executeTool: (name: string, params: any) => Promise<any>
|
|
76
|
+
registerTool: (tool: any) => void
|
|
77
|
+
unregisterTool: (name: string) => void
|
|
78
|
+
isExecuting: boolean
|
|
79
|
+
lastResult: any | null
|
|
80
|
+
error: Error | null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface UseSuggestionsOptions {
|
|
84
|
+
maxSuggestions?: number
|
|
85
|
+
autoRefresh?: boolean
|
|
86
|
+
refreshInterval?: number
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface UseSuggestionsReturn {
|
|
90
|
+
suggestions: any[]
|
|
91
|
+
getSuggestions: (options?: any) => Promise<void>
|
|
92
|
+
acceptSuggestion: (suggestion: any) => void
|
|
93
|
+
dismissSuggestion: (id: string) => void
|
|
94
|
+
isLoading: boolean
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface UseModelConfigOptions {
|
|
98
|
+
defaultModel?: string
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface UseModelConfigReturn {
|
|
102
|
+
currentModel: string
|
|
103
|
+
availableModels: any[]
|
|
104
|
+
switchModel: (modelId: string) => void
|
|
105
|
+
updateParameters: (params: any) => void
|
|
106
|
+
resetToDefaults: () => void
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface UseMCPOptions {
|
|
110
|
+
autoConnect?: boolean
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface UseMCPReturn {
|
|
114
|
+
connectServer: (config: any) => Promise<void>
|
|
115
|
+
disconnectServer: (id: string) => void
|
|
116
|
+
connectedServers: any[]
|
|
117
|
+
executeServerTool: (serverId: string, tool: string, params: any) => Promise<any>
|
|
118
|
+
getServerResources: (serverId: string) => any[]
|
|
119
|
+
isConnected: (serverId: string) => boolean
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface UseGenerativeUIOptions {
|
|
123
|
+
cacheResults?: boolean
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface UseGenerativeUIReturn {
|
|
127
|
+
generateUI: (options: any) => Promise<React.ReactElement>
|
|
128
|
+
isGenerating: boolean
|
|
129
|
+
generatedComponents: React.ReactElement[]
|
|
130
|
+
clearComponents: () => void
|
|
131
|
+
saveComponent: (name: string, component: React.ReactElement) => void
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface UseAuthOptions {
|
|
135
|
+
provider?: string
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface UseAuthReturn {
|
|
139
|
+
user: any | null
|
|
140
|
+
isAuthenticated: boolean
|
|
141
|
+
isLoading: boolean
|
|
142
|
+
signIn: (options?: any) => Promise<void>
|
|
143
|
+
signOut: () => Promise<void>
|
|
144
|
+
getToken: () => Promise<string | null>
|
|
145
|
+
refreshToken: () => Promise<void>
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface UseAttachmentsOptions {
|
|
149
|
+
maxSize?: number
|
|
150
|
+
allowedTypes?: string[]
|
|
151
|
+
autoUpload?: boolean
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface UseAttachmentsReturn {
|
|
155
|
+
attachments: any[]
|
|
156
|
+
addAttachment: (file: File) => Promise<any>
|
|
157
|
+
removeAttachment: (id: string) => void
|
|
158
|
+
clearAttachments: () => void
|
|
159
|
+
uploadAttachment: (attachment: any) => Promise<void>
|
|
160
|
+
isUploading: boolean
|
|
161
|
+
uploadProgress: number
|
|
162
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|