@roj-ai/debug 0.0.2
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/dist/components/debug/DebugContext.d.ts +10 -0
- package/dist/components/debug/DebugNavigation.d.ts +29 -0
- package/dist/components/debug/DebugShell.d.ts +18 -0
- package/dist/components/debug/LLMCallDetail.d.ts +7 -0
- package/dist/components/debug/TimelineDetailInspector.d.ts +6 -0
- package/dist/components/debug/communication/CommunicationDiagram.d.ts +9 -0
- package/dist/components/debug/communication/DiagramHeader.d.ts +7 -0
- package/dist/components/debug/communication/ParticipantLane.d.ts +7 -0
- package/dist/components/debug/communication/TimeAxis.d.ts +9 -0
- package/dist/components/debug/communication/elements/IdleGap.d.ts +9 -0
- package/dist/components/debug/communication/elements/LLMBlock.d.ts +9 -0
- package/dist/components/debug/communication/elements/MessageArrow.d.ts +10 -0
- package/dist/components/debug/communication/elements/ToolBlock.d.ts +9 -0
- package/dist/components/debug/communication/hooks/useDiagramData.d.ts +12 -0
- package/dist/components/debug/communication/hooks/useTimeCompression.d.ts +7 -0
- package/dist/components/debug/communication/hooks/useZoomPan.d.ts +11 -0
- package/dist/components/debug/communication/popovers/ElementPopover.d.ts +8 -0
- package/dist/components/debug/communication/types.d.ts +136 -0
- package/dist/components/debug/index.d.ts +11 -0
- package/dist/components/debug/pages/AgentDetailPage.d.ts +3 -0
- package/dist/components/debug/pages/AgentsPage.d.ts +1 -0
- package/dist/components/debug/pages/CommunicationPage.d.ts +1 -0
- package/dist/components/debug/pages/DashboardPage.d.ts +1 -0
- package/dist/components/debug/pages/EventsPage.d.ts +1 -0
- package/dist/components/debug/pages/FilesPage.d.ts +1 -0
- package/dist/components/debug/pages/LLMCallPage.d.ts +1 -0
- package/dist/components/debug/pages/LLMCallsPage.d.ts +1 -0
- package/dist/components/debug/pages/LogsPage.d.ts +1 -0
- package/dist/components/debug/pages/MailboxPage.d.ts +1 -0
- package/dist/components/debug/pages/ServicesPage.d.ts +1 -0
- package/dist/components/debug/pages/TimelinePage.d.ts +1 -0
- package/dist/components/debug/pages/UserChatPage.d.ts +1 -0
- package/dist/components/debug/pages/index.d.ts +13 -0
- package/dist/index.d.ts +9 -0
- package/dist/lib/domain-utils.d.ts +7 -0
- package/dist/providers/EventPollingProvider.d.ts +27 -0
- package/dist/stores/event-store.d.ts +93 -0
- package/dist/utils/format.d.ts +1 -0
- package/package.json +43 -0
- package/src/components/debug/DebugContext.tsx +18 -0
- package/src/components/debug/DebugNavigation.tsx +55 -0
- package/src/components/debug/DebugShell.tsx +321 -0
- package/src/components/debug/LLMCallDetail.tsx +740 -0
- package/src/components/debug/TimelineDetailInspector.tsx +204 -0
- package/src/components/debug/communication/CommunicationDiagram.tsx +260 -0
- package/src/components/debug/communication/DiagramHeader.tsx +113 -0
- package/src/components/debug/communication/ParticipantLane.tsx +60 -0
- package/src/components/debug/communication/TimeAxis.tsx +106 -0
- package/src/components/debug/communication/elements/IdleGap.tsx +90 -0
- package/src/components/debug/communication/elements/LLMBlock.tsx +107 -0
- package/src/components/debug/communication/elements/MessageArrow.tsx +119 -0
- package/src/components/debug/communication/elements/ToolBlock.tsx +99 -0
- package/src/components/debug/communication/hooks/useDiagramData.ts +294 -0
- package/src/components/debug/communication/hooks/useTimeCompression.ts +140 -0
- package/src/components/debug/communication/hooks/useZoomPan.ts +87 -0
- package/src/components/debug/communication/popovers/ElementPopover.tsx +158 -0
- package/src/components/debug/communication/types.ts +180 -0
- package/src/components/debug/index.ts +37 -0
- package/src/components/debug/pages/AgentDetailPage.tsx +1295 -0
- package/src/components/debug/pages/AgentsPage.tsx +297 -0
- package/src/components/debug/pages/CommunicationPage.tsx +89 -0
- package/src/components/debug/pages/DashboardPage.tsx +1504 -0
- package/src/components/debug/pages/EventsPage.tsx +276 -0
- package/src/components/debug/pages/FilesPage.tsx +366 -0
- package/src/components/debug/pages/LLMCallPage.tsx +32 -0
- package/src/components/debug/pages/LLMCallsPage.tsx +473 -0
- package/src/components/debug/pages/LogsPage.tsx +199 -0
- package/src/components/debug/pages/MailboxPage.tsx +232 -0
- package/src/components/debug/pages/ServicesPage.tsx +193 -0
- package/src/components/debug/pages/TimelinePage.tsx +569 -0
- package/src/components/debug/pages/UserChatPage.tsx +250 -0
- package/src/components/debug/pages/index.ts +13 -0
- package/src/index.ts +55 -0
- package/src/lib/domain-utils.ts +12 -0
- package/src/providers/EventPollingProvider.tsx +60 -0
- package/src/stores/event-store.ts +497 -0
- package/src/utils/format.ts +8 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import type { DebugChatMessage } from '@roj-ai/shared'
|
|
2
|
+
import { useState } from 'react'
|
|
3
|
+
import { DebugLink } from '../DebugNavigation'
|
|
4
|
+
import { useChatDebug, useEventStore } from '../../../stores/event-store'
|
|
5
|
+
|
|
6
|
+
export function UserChatPage() {
|
|
7
|
+
|
|
8
|
+
// Get chat debug messages from event store
|
|
9
|
+
const messages = useChatDebug()
|
|
10
|
+
const isLoading = useEventStore((s) => s.isLoading)
|
|
11
|
+
const error = useEventStore((s) => s.error)
|
|
12
|
+
|
|
13
|
+
const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set())
|
|
14
|
+
|
|
15
|
+
const toggleExpanded = (id: string) => {
|
|
16
|
+
setExpandedIds((prev) => {
|
|
17
|
+
const next = new Set(prev)
|
|
18
|
+
if (next.has(id)) {
|
|
19
|
+
next.delete(id)
|
|
20
|
+
} else {
|
|
21
|
+
next.add(id)
|
|
22
|
+
}
|
|
23
|
+
return next
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Calculate stats
|
|
28
|
+
const total = messages.length
|
|
29
|
+
const userCount = messages.filter((m) => m.type === 'user_message').length
|
|
30
|
+
const agentCount = messages.filter((m) => m.type === 'agent_message').length
|
|
31
|
+
const askUserCount = messages.filter((m) => m.type === 'ask_user').length
|
|
32
|
+
const answeredCount = messages.filter((m) => m.type === 'ask_user' && m.answered).length
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div className="space-y-4">
|
|
36
|
+
{/* Summary */}
|
|
37
|
+
<div className="flex items-center gap-6 text-sm">
|
|
38
|
+
<span className="text-slate-600">
|
|
39
|
+
<span className="font-medium text-slate-900">{total}</span> messages
|
|
40
|
+
</span>
|
|
41
|
+
<span className="text-slate-600">
|
|
42
|
+
<span className="font-medium text-blue-600">{userCount}</span> user
|
|
43
|
+
</span>
|
|
44
|
+
<span className="text-slate-600">
|
|
45
|
+
<span className="font-medium text-green-600">{agentCount}</span> agent
|
|
46
|
+
</span>
|
|
47
|
+
{askUserCount > 0 && (
|
|
48
|
+
<span className="text-slate-600">
|
|
49
|
+
<span className="font-medium text-purple-600">{askUserCount}</span> questions
|
|
50
|
+
{answeredCount > 0 && <span className="text-slate-500">({answeredCount} answered)</span>}
|
|
51
|
+
</span>
|
|
52
|
+
)}
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
{/* Error */}
|
|
56
|
+
{error && <div className="text-red-500 text-sm">{error}</div>}
|
|
57
|
+
|
|
58
|
+
{/* Loading */}
|
|
59
|
+
{isLoading && messages.length === 0 && <div className="text-slate-500 text-sm">Loading chat messages...</div>}
|
|
60
|
+
|
|
61
|
+
{/* Table */}
|
|
62
|
+
{messages.length > 0 && (
|
|
63
|
+
<div className="bg-white rounded-md border border-slate-200 overflow-hidden">
|
|
64
|
+
<div className="overflow-x-auto">
|
|
65
|
+
<table className="w-full text-sm">
|
|
66
|
+
<thead className="bg-slate-50 border-b border-slate-200">
|
|
67
|
+
<tr>
|
|
68
|
+
<th className="px-3 py-2 text-left font-medium text-slate-600 w-20">Type</th>
|
|
69
|
+
<th className="px-3 py-2 text-left font-medium text-slate-600">Content</th>
|
|
70
|
+
<th className="px-3 py-2 text-left font-medium text-slate-600 w-24">Agent</th>
|
|
71
|
+
<th className="px-3 py-2 text-left font-medium text-slate-600 w-32">Links</th>
|
|
72
|
+
<th className="px-3 py-2 text-left font-medium text-slate-600 w-20">Time</th>
|
|
73
|
+
<th className="px-3 py-2 text-left font-medium text-slate-600 w-16">Event</th>
|
|
74
|
+
</tr>
|
|
75
|
+
</thead>
|
|
76
|
+
<tbody className="divide-y divide-slate-200">
|
|
77
|
+
{messages.map((msg) => (
|
|
78
|
+
<MessageRow
|
|
79
|
+
key={msg.messageId}
|
|
80
|
+
message={msg}
|
|
81
|
+
isExpanded={expandedIds.has(msg.messageId)}
|
|
82
|
+
onToggleExpand={() => toggleExpanded(msg.messageId)}
|
|
83
|
+
/>
|
|
84
|
+
))}
|
|
85
|
+
</tbody>
|
|
86
|
+
</table>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
)}
|
|
90
|
+
|
|
91
|
+
{/* Empty state */}
|
|
92
|
+
{!isLoading && messages.length === 0 && <div className="text-slate-500 text-sm">No chat messages found</div>}
|
|
93
|
+
</div>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function MessageRow({
|
|
98
|
+
message,
|
|
99
|
+
isExpanded,
|
|
100
|
+
onToggleExpand,
|
|
101
|
+
}: {
|
|
102
|
+
message: DebugChatMessage
|
|
103
|
+
isExpanded: boolean
|
|
104
|
+
onToggleExpand: () => void
|
|
105
|
+
}) {
|
|
106
|
+
const isLongMessage = message.content.length > 100
|
|
107
|
+
const displayContent = isExpanded
|
|
108
|
+
? message.content
|
|
109
|
+
: message.content.slice(0, 100) + (isLongMessage ? '...' : '')
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<tr className="hover:bg-slate-50">
|
|
113
|
+
{/* Type */}
|
|
114
|
+
<td className="px-3 py-2">
|
|
115
|
+
<TypeBadge type={message.type} answered={message.answered} />
|
|
116
|
+
</td>
|
|
117
|
+
|
|
118
|
+
{/* Content */}
|
|
119
|
+
<td className="px-3 py-2">
|
|
120
|
+
<div
|
|
121
|
+
className={`text-slate-700 ${isLongMessage ? 'cursor-pointer' : ''}`}
|
|
122
|
+
onClick={isLongMessage ? onToggleExpand : undefined}
|
|
123
|
+
>
|
|
124
|
+
<span className="whitespace-pre-wrap break-words">{displayContent}</span>
|
|
125
|
+
{isLongMessage && (
|
|
126
|
+
<button
|
|
127
|
+
onClick={(e) => {
|
|
128
|
+
e.stopPropagation()
|
|
129
|
+
onToggleExpand()
|
|
130
|
+
}}
|
|
131
|
+
className="ml-2 text-violet-600 hover:text-violet-800 text-xs"
|
|
132
|
+
>
|
|
133
|
+
{isExpanded ? 'less' : 'more'}
|
|
134
|
+
</button>
|
|
135
|
+
)}
|
|
136
|
+
</div>
|
|
137
|
+
{/* Show answer for ask_user messages */}
|
|
138
|
+
{message.type === 'ask_user' && message.answered && (
|
|
139
|
+
<div className="mt-1 text-xs text-slate-500">
|
|
140
|
+
Answer: <span className="font-mono">{JSON.stringify(message.answer)}</span>
|
|
141
|
+
</div>
|
|
142
|
+
)}
|
|
143
|
+
{/* Show input type for ask_user messages */}
|
|
144
|
+
{message.type === 'ask_user' && message.inputType && (
|
|
145
|
+
<div className="mt-1 text-xs text-slate-400">
|
|
146
|
+
Input: {message.inputType.type}
|
|
147
|
+
</div>
|
|
148
|
+
)}
|
|
149
|
+
</td>
|
|
150
|
+
|
|
151
|
+
{/* Agent */}
|
|
152
|
+
<td className="px-3 py-2">
|
|
153
|
+
{message.agentId && message.agentName && (
|
|
154
|
+
<AgentBadge
|
|
155
|
+
agentId={message.agentId}
|
|
156
|
+
agentName={message.agentName}
|
|
157
|
+
/>
|
|
158
|
+
)}
|
|
159
|
+
</td>
|
|
160
|
+
|
|
161
|
+
{/* Links */}
|
|
162
|
+
<td className="px-3 py-2">
|
|
163
|
+
<div className="flex flex-wrap gap-1">
|
|
164
|
+
{message.llmCallId && (
|
|
165
|
+
<DebugLink
|
|
166
|
+
to={`llm-calls/${message.llmCallId}`}
|
|
167
|
+
className="inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-yellow-100 text-yellow-700 hover:bg-yellow-200"
|
|
168
|
+
>
|
|
169
|
+
LLM
|
|
170
|
+
</DebugLink>
|
|
171
|
+
)}
|
|
172
|
+
{message.toolCallId && (
|
|
173
|
+
<span
|
|
174
|
+
className="inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-slate-100 text-slate-600"
|
|
175
|
+
title={`Tool Call: ${message.toolCallId}`}
|
|
176
|
+
>
|
|
177
|
+
Tool
|
|
178
|
+
</span>
|
|
179
|
+
)}
|
|
180
|
+
{message.mailboxMessageId && (
|
|
181
|
+
<DebugLink
|
|
182
|
+
to="mailbox"
|
|
183
|
+
className="inline-flex items-center px-1.5 py-0.5 rounded text-xs bg-indigo-100 text-indigo-700 hover:bg-indigo-200"
|
|
184
|
+
>
|
|
185
|
+
Mailbox
|
|
186
|
+
</DebugLink>
|
|
187
|
+
)}
|
|
188
|
+
</div>
|
|
189
|
+
</td>
|
|
190
|
+
|
|
191
|
+
{/* Time */}
|
|
192
|
+
<td className="px-3 py-2 font-mono text-xs text-slate-500 whitespace-nowrap">
|
|
193
|
+
{new Date(message.timestamp).toLocaleTimeString()}
|
|
194
|
+
</td>
|
|
195
|
+
|
|
196
|
+
{/* Event Index */}
|
|
197
|
+
<td className="px-3 py-2 font-mono text-xs text-slate-400">
|
|
198
|
+
#{message.eventIndex}
|
|
199
|
+
</td>
|
|
200
|
+
</tr>
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function TypeBadge({ type, answered }: { type: DebugChatMessage['type']; answered?: boolean }) {
|
|
205
|
+
switch (type) {
|
|
206
|
+
case 'user_message':
|
|
207
|
+
return (
|
|
208
|
+
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-700">
|
|
209
|
+
User
|
|
210
|
+
</span>
|
|
211
|
+
)
|
|
212
|
+
case 'agent_message':
|
|
213
|
+
return (
|
|
214
|
+
<span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-700">
|
|
215
|
+
Agent
|
|
216
|
+
</span>
|
|
217
|
+
)
|
|
218
|
+
case 'ask_user':
|
|
219
|
+
return (
|
|
220
|
+
<span
|
|
221
|
+
className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${
|
|
222
|
+
answered
|
|
223
|
+
? 'bg-purple-100 text-purple-700'
|
|
224
|
+
: 'bg-purple-200 text-purple-800 animate-pulse'
|
|
225
|
+
}`}
|
|
226
|
+
>
|
|
227
|
+
Question{answered ? '' : ' (pending)'}
|
|
228
|
+
</span>
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function AgentBadge({
|
|
234
|
+
agentId,
|
|
235
|
+
agentName,
|
|
236
|
+
}: {
|
|
237
|
+
agentId: string
|
|
238
|
+
agentName: string
|
|
239
|
+
}) {
|
|
240
|
+
return (
|
|
241
|
+
<DebugLink
|
|
242
|
+
to={`agents/${agentId}`}
|
|
243
|
+
className="inline-flex items-center gap-1 px-2 py-0.5 rounded text-xs font-medium bg-slate-100 text-slate-700 hover:bg-slate-200"
|
|
244
|
+
>
|
|
245
|
+
<span className="truncate max-w-20" title={agentName}>
|
|
246
|
+
{agentName}
|
|
247
|
+
</span>
|
|
248
|
+
</DebugLink>
|
|
249
|
+
)
|
|
250
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { AgentDetailPage } from './AgentDetailPage'
|
|
2
|
+
export { DashboardPage } from './DashboardPage'
|
|
3
|
+
export { AgentsPage } from './AgentsPage'
|
|
4
|
+
export { CommunicationPage } from './CommunicationPage'
|
|
5
|
+
export { EventsPage } from './EventsPage'
|
|
6
|
+
export { LLMCallPage } from './LLMCallPage'
|
|
7
|
+
export { LLMCallsPage } from './LLMCallsPage'
|
|
8
|
+
export { MailboxPage } from './MailboxPage'
|
|
9
|
+
export { TimelinePage } from './TimelinePage'
|
|
10
|
+
export { UserChatPage } from './UserChatPage'
|
|
11
|
+
export { FilesPage } from './FilesPage'
|
|
12
|
+
export { LogsPage } from './LogsPage'
|
|
13
|
+
export { ServicesPage } from './ServicesPage'
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @roj-ai/debug
|
|
3
|
+
*
|
|
4
|
+
* React debug UI for session event inspection — extracted from @roj-ai/client.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Event store
|
|
8
|
+
export {
|
|
9
|
+
selectAgentTree,
|
|
10
|
+
selectGlobalMailbox,
|
|
11
|
+
selectMetrics,
|
|
12
|
+
selectTimeline,
|
|
13
|
+
useAgentDetail,
|
|
14
|
+
useAgentTree,
|
|
15
|
+
useChatDebug,
|
|
16
|
+
useEvents,
|
|
17
|
+
useEventStore,
|
|
18
|
+
useGlobalMailbox,
|
|
19
|
+
useMetrics,
|
|
20
|
+
useSessionInfo,
|
|
21
|
+
useTimeline,
|
|
22
|
+
} from './stores/event-store'
|
|
23
|
+
|
|
24
|
+
// Event polling provider
|
|
25
|
+
export { EventPollingProvider, useEventPolling } from './providers/EventPollingProvider'
|
|
26
|
+
|
|
27
|
+
// Debug components (context, navigation, shell, pages, diagrams)
|
|
28
|
+
export {
|
|
29
|
+
AgentDetailPage,
|
|
30
|
+
AgentsPage,
|
|
31
|
+
BackIcon,
|
|
32
|
+
CommunicationDiagram,
|
|
33
|
+
CommunicationPage,
|
|
34
|
+
DashboardPage,
|
|
35
|
+
DebugContext,
|
|
36
|
+
DebugLink,
|
|
37
|
+
DebugShell,
|
|
38
|
+
EventsPage,
|
|
39
|
+
FilesPage,
|
|
40
|
+
getNavItemClassName,
|
|
41
|
+
LLMCallDetail,
|
|
42
|
+
LLMCallPage,
|
|
43
|
+
LLMCallsPage,
|
|
44
|
+
LogsPage,
|
|
45
|
+
MailboxPage,
|
|
46
|
+
navItems,
|
|
47
|
+
ServicesPage,
|
|
48
|
+
TimelinePage,
|
|
49
|
+
useDebugContext,
|
|
50
|
+
useDebugNavigate,
|
|
51
|
+
useDebugParams,
|
|
52
|
+
useDebugSessionId,
|
|
53
|
+
UserChatPage,
|
|
54
|
+
} from './components/debug'
|
|
55
|
+
export type { DebugContextValue, NavItem } from './components/debug'
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import { useEventStore } from '../stores/event-store'
|
|
3
|
+
|
|
4
|
+
interface EventPollingProviderProps {
|
|
5
|
+
sessionId: string
|
|
6
|
+
children: React.ReactNode
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Provider component that manages event polling for a session.
|
|
11
|
+
*
|
|
12
|
+
* When mounted, it loads the session's events and starts polling for new events.
|
|
13
|
+
* When unmounted (e.g., navigating away), it stops polling and resets the store.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* ```tsx
|
|
17
|
+
* <EventPollingProvider sessionId={sessionId}>
|
|
18
|
+
* <DebugViews />
|
|
19
|
+
* </EventPollingProvider>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function EventPollingProvider({ sessionId, children }: EventPollingProviderProps) {
|
|
23
|
+
const loadSession = useEventStore((s) => s.loadSession)
|
|
24
|
+
const reset = useEventStore((s) => s.reset)
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
loadSession(sessionId)
|
|
28
|
+
|
|
29
|
+
// Cleanup on unmount or sessionId change
|
|
30
|
+
return () => {
|
|
31
|
+
reset()
|
|
32
|
+
}
|
|
33
|
+
}, [sessionId, loadSession, reset])
|
|
34
|
+
|
|
35
|
+
return <>{children}</>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Hook to initialize event polling for a session.
|
|
40
|
+
* Use this instead of EventPollingProvider if you want more control.
|
|
41
|
+
*/
|
|
42
|
+
export function useEventPolling(sessionId: string | undefined) {
|
|
43
|
+
const loadSession = useEventStore((s) => s.loadSession)
|
|
44
|
+
const reset = useEventStore((s) => s.reset)
|
|
45
|
+
const isLoading = useEventStore((s) => s.isLoading)
|
|
46
|
+
const error = useEventStore((s) => s.error)
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (!sessionId) return
|
|
50
|
+
|
|
51
|
+
loadSession(sessionId)
|
|
52
|
+
|
|
53
|
+
// Cleanup on unmount or sessionId change
|
|
54
|
+
return () => {
|
|
55
|
+
reset()
|
|
56
|
+
}
|
|
57
|
+
}, [sessionId, loadSession, reset])
|
|
58
|
+
|
|
59
|
+
return { isLoading, error }
|
|
60
|
+
}
|