@genui/a3-create 0.1.36 → 0.1.37
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/package.json
CHANGED
|
@@ -24,26 +24,14 @@ interface ExamplePageLayoutProps {
|
|
|
24
24
|
initialState?: Record<string, unknown>
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export function ExamplePageLayout({
|
|
28
|
-
title,
|
|
29
|
-
description,
|
|
30
|
-
sessionId,
|
|
31
|
-
initialMessages,
|
|
32
|
-
variant,
|
|
33
|
-
agents,
|
|
34
|
-
initialActiveAgentId,
|
|
35
|
-
initialState,
|
|
36
|
-
}: ExamplePageLayoutProps) {
|
|
27
|
+
export function ExamplePageLayout({ title, description, sessionId, initialMessages, variant, agents, initialActiveAgentId, initialState }: ExamplePageLayoutProps) {
|
|
37
28
|
const [activeAgentId, setActiveAgentId] = useState<string | null>(initialActiveAgentId ?? null)
|
|
38
29
|
const [state, setState] = useState<Record<string, unknown>>(initialState ?? {})
|
|
39
30
|
|
|
40
|
-
const handleSessionUpdate = useCallback(
|
|
41
|
-
(update
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
},
|
|
45
|
-
[],
|
|
46
|
-
)
|
|
31
|
+
const handleSessionUpdate = useCallback((update: { activeAgentId: string | null; state: Record<string, unknown> }) => {
|
|
32
|
+
setActiveAgentId(update.activeAgentId)
|
|
33
|
+
setState(update.state)
|
|
34
|
+
}, [])
|
|
47
35
|
|
|
48
36
|
const handleRestart = useCallback(async () => {
|
|
49
37
|
const fresh = await restartSession(sessionId)
|
|
@@ -55,17 +43,7 @@ export function ExamplePageLayout({
|
|
|
55
43
|
}, [sessionId])
|
|
56
44
|
|
|
57
45
|
return (
|
|
58
|
-
<Box
|
|
59
|
-
sx={{
|
|
60
|
-
display: 'flex',
|
|
61
|
-
flexDirection: 'column',
|
|
62
|
-
height: '100%',
|
|
63
|
-
px: { xs: 2, sm: 3, md: 5, lg: 8 },
|
|
64
|
-
maxWidth: 1600,
|
|
65
|
-
width: '100%',
|
|
66
|
-
mx: 'auto',
|
|
67
|
-
}}
|
|
68
|
-
>
|
|
46
|
+
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%', px: { xs: 2, sm: 3, md: 5, lg: 8 }, maxWidth: 1600, width: '100%', mx: 'auto' }}>
|
|
69
47
|
<Typography variant="h5" fontWeight="bold" sx={{ pt: 3 }}>
|
|
70
48
|
{title}
|
|
71
49
|
</Typography>
|
|
@@ -83,30 +61,9 @@ export function ExamplePageLayout({
|
|
|
83
61
|
}}
|
|
84
62
|
>
|
|
85
63
|
<Box sx={{ minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
|
|
86
|
-
{variant === 'blocking' &&
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
initialMessages={initialMessages}
|
|
90
|
-
onSessionUpdate={handleSessionUpdate}
|
|
91
|
-
onRestart={handleRestart}
|
|
92
|
-
/>
|
|
93
|
-
)}
|
|
94
|
-
{variant === 'stream' && (
|
|
95
|
-
<StreamChat
|
|
96
|
-
sessionId={sessionId}
|
|
97
|
-
initialMessages={initialMessages}
|
|
98
|
-
onSessionUpdate={handleSessionUpdate}
|
|
99
|
-
onRestart={handleRestart}
|
|
100
|
-
/>
|
|
101
|
-
)}
|
|
102
|
-
{variant === 'agui' && (
|
|
103
|
-
<AguiChat
|
|
104
|
-
sessionId={sessionId}
|
|
105
|
-
initialMessages={initialMessages}
|
|
106
|
-
onSessionUpdate={handleSessionUpdate}
|
|
107
|
-
onRestart={handleRestart}
|
|
108
|
-
/>
|
|
109
|
-
)}
|
|
64
|
+
{variant === 'blocking' && <Chat sessionId={sessionId} initialMessages={initialMessages} onSessionUpdate={handleSessionUpdate} onRestart={handleRestart} />}
|
|
65
|
+
{variant === 'stream' && <StreamChat sessionId={sessionId} initialMessages={initialMessages} onSessionUpdate={handleSessionUpdate} onRestart={handleRestart} />}
|
|
66
|
+
{variant === 'agui' && <AguiChat sessionId={sessionId} initialMessages={initialMessages} onSessionUpdate={handleSessionUpdate} onRestart={handleRestart} />}
|
|
110
67
|
</Box>
|
|
111
68
|
<Box sx={{ minHeight: 0, display: 'flex', flexDirection: 'column', gap: 3, overflow: 'auto' }}>
|
|
112
69
|
<AgentGraph agents={agents} activeAgentId={activeAgentId} />
|
|
@@ -36,127 +36,120 @@ export function StreamChat({ sessionId, initialMessages, onSessionUpdate, onRest
|
|
|
36
36
|
const assistantIdRef = useRef<string>('')
|
|
37
37
|
const { isRestarting, handleRestart } = useRestart({ onRestart, setMessages, onSessionUpdate })
|
|
38
38
|
|
|
39
|
-
const handleSubmit = useCallback(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
const handleSubmit = useCallback(async (text: string) => {
|
|
40
|
+
const userMsg: Message = {
|
|
41
|
+
messageId: crypto.randomUUID(),
|
|
42
|
+
text,
|
|
43
|
+
metadata: { source: MessageSender.USER },
|
|
44
|
+
}
|
|
45
|
+
setMessages((prev) => [...prev, userMsg])
|
|
46
|
+
setIsLoading(true)
|
|
47
|
+
|
|
48
|
+
// Create a placeholder assistant message for streaming into
|
|
49
|
+
let assistantId = crypto.randomUUID()
|
|
50
|
+
assistantIdRef.current = assistantId
|
|
51
|
+
|
|
52
|
+
const streamingMsg: Message = {
|
|
53
|
+
messageId: assistantId,
|
|
54
|
+
text: '',
|
|
55
|
+
metadata: { source: MessageSender.ASSISTANT },
|
|
56
|
+
isStreaming: true,
|
|
57
|
+
}
|
|
58
|
+
setMessages((prev) => [...prev, streamingMsg])
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const response = await fetch('/api/stream', {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
headers: { 'Content-Type': 'application/json' },
|
|
64
|
+
body: JSON.stringify({ message: text, sessionId }),
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
throw new Error(`HTTP error: ${response.status}`)
|
|
45
69
|
}
|
|
46
|
-
setMessages((prev) => [...prev, userMsg])
|
|
47
|
-
setIsLoading(true)
|
|
48
|
-
|
|
49
|
-
// Create a placeholder assistant message for streaming into
|
|
50
|
-
let assistantId = crypto.randomUUID()
|
|
51
|
-
assistantIdRef.current = assistantId
|
|
52
|
-
|
|
53
|
-
const streamingMsg: Message = {
|
|
54
|
-
messageId: assistantId,
|
|
55
|
-
text: '',
|
|
56
|
-
metadata: { source: MessageSender.ASSISTANT },
|
|
57
|
-
isStreaming: true,
|
|
58
|
-
}
|
|
59
|
-
setMessages((prev) => [...prev, streamingMsg])
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
method: 'POST',
|
|
64
|
-
headers: { 'Content-Type': 'application/json' },
|
|
65
|
-
body: JSON.stringify({ message: text, sessionId }),
|
|
66
|
-
})
|
|
71
|
+
const reader = response.body?.getReader()
|
|
72
|
+
if (!reader) throw new Error('No response body')
|
|
67
73
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
const decoder = new TextDecoder()
|
|
75
|
+
let buffer = ''
|
|
76
|
+
|
|
77
|
+
while (true) {
|
|
78
|
+
const { done, value } = await reader.read()
|
|
79
|
+
if (done) break
|
|
80
|
+
|
|
81
|
+
buffer += decoder.decode(value, { stream: true })
|
|
82
|
+
|
|
83
|
+
// Process complete SSE lines
|
|
84
|
+
const lines = buffer.split('\n')
|
|
85
|
+
buffer = lines.pop() ?? ''
|
|
71
86
|
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
buffer = lines.pop() ?? ''
|
|
87
|
-
|
|
88
|
-
for (const line of lines) {
|
|
89
|
-
if (!line.startsWith('data: ')) continue
|
|
90
|
-
const data = line.slice(6)
|
|
91
|
-
if (data === '[DONE]') continue
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
const event = JSON.parse(data) as StreamEvent
|
|
95
|
-
|
|
96
|
-
if (event.type === EventType.TEXT_MESSAGE_CONTENT && event.delta) {
|
|
97
|
-
setIsTransitioning(false)
|
|
98
|
-
setMessages((prev) =>
|
|
99
|
-
prev.map((m) => (m.messageId === assistantId ? { ...m, text: m.text + event.delta } : m)),
|
|
100
|
-
)
|
|
101
|
-
} else if (event.type === EventType.CUSTOM && event.name === 'AgentTransition') {
|
|
102
|
-
const transitionEvent = event as StreamEvent & {
|
|
103
|
-
value?: { toAgentId?: string; state?: Record<string, unknown> }
|
|
104
|
-
}
|
|
105
|
-
onSessionUpdate?.({
|
|
106
|
-
activeAgentId: transitionEvent.value?.toAgentId ?? null,
|
|
107
|
-
state: transitionEvent.value?.state ?? {},
|
|
108
|
-
})
|
|
109
|
-
const prevAssistantId = assistantId
|
|
110
|
-
assistantId = crypto.randomUUID()
|
|
111
|
-
assistantIdRef.current = assistantId
|
|
112
|
-
setIsTransitioning(true)
|
|
113
|
-
setMessages((prev) => {
|
|
114
|
-
const updated = prev.map((m) => (m.messageId === prevAssistantId ? { ...m, isStreaming: false } : m))
|
|
115
|
-
return [
|
|
116
|
-
...updated,
|
|
117
|
-
{
|
|
118
|
-
messageId: assistantId,
|
|
119
|
-
text: '',
|
|
120
|
-
metadata: { source: MessageSender.ASSISTANT },
|
|
121
|
-
isStreaming: true,
|
|
122
|
-
},
|
|
123
|
-
]
|
|
124
|
-
})
|
|
125
|
-
} else if (event.type === EventType.RUN_FINISHED) {
|
|
126
|
-
setIsTransitioning(false)
|
|
127
|
-
const result = event.result
|
|
128
|
-
onSessionUpdate?.({
|
|
129
|
-
activeAgentId: (result?.activeAgentId as string) ?? null,
|
|
130
|
-
state: (result?.state as Record<string, unknown>) ?? {},
|
|
131
|
-
})
|
|
132
|
-
setMessages((prev) => prev.map((m) => (m.messageId === assistantId ? { ...m, isStreaming: false } : m)))
|
|
133
|
-
} else if (event.type === EventType.RUN_ERROR) {
|
|
134
|
-
setIsTransitioning(false)
|
|
135
|
-
setMessages((prev) =>
|
|
136
|
-
prev.map((m) =>
|
|
137
|
-
m.messageId === assistantId ? { ...m, text: m.text || CHAT_ERROR_SHORT, isStreaming: false } : m,
|
|
138
|
-
),
|
|
139
|
-
)
|
|
87
|
+
for (const line of lines) {
|
|
88
|
+
if (!line.startsWith('data: ')) continue
|
|
89
|
+
const data = line.slice(6)
|
|
90
|
+
if (data === '[DONE]') continue
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const event = JSON.parse(data) as StreamEvent
|
|
94
|
+
|
|
95
|
+
if (event.type === EventType.TEXT_MESSAGE_CONTENT && event.delta) {
|
|
96
|
+
setIsTransitioning(false)
|
|
97
|
+
setMessages((prev) => prev.map((m) => (m.messageId === assistantId ? { ...m, text: m.text + event.delta } : m)))
|
|
98
|
+
} else if (event.type === EventType.CUSTOM && event.name === 'AgentTransition') {
|
|
99
|
+
const transitionEvent = event as StreamEvent & {
|
|
100
|
+
value?: { toAgentId?: string; state?: Record<string, unknown> }
|
|
140
101
|
}
|
|
141
|
-
|
|
142
|
-
|
|
102
|
+
onSessionUpdate?.({
|
|
103
|
+
activeAgentId: transitionEvent.value?.toAgentId ?? null,
|
|
104
|
+
state: transitionEvent.value?.state ?? {},
|
|
105
|
+
})
|
|
106
|
+
const prevAssistantId = assistantId
|
|
107
|
+
assistantId = crypto.randomUUID()
|
|
108
|
+
assistantIdRef.current = assistantId
|
|
109
|
+
setIsTransitioning(true)
|
|
110
|
+
setMessages((prev) => {
|
|
111
|
+
const updated = prev.map((m) => (m.messageId === prevAssistantId ? { ...m, isStreaming: false } : m))
|
|
112
|
+
return [...updated, { messageId: assistantId, text: '', metadata: { source: MessageSender.ASSISTANT }, isStreaming: true }]
|
|
113
|
+
})
|
|
114
|
+
} else if (event.type === EventType.RUN_FINISHED) {
|
|
115
|
+
setIsTransitioning(false)
|
|
116
|
+
const result = event.result
|
|
117
|
+
onSessionUpdate?.({
|
|
118
|
+
activeAgentId: (result?.activeAgentId as string) ?? null,
|
|
119
|
+
state: (result?.state as Record<string, unknown>) ?? {},
|
|
120
|
+
})
|
|
121
|
+
setMessages((prev) => prev.map((m) => (m.messageId === assistantId ? { ...m, isStreaming: false } : m)))
|
|
122
|
+
} else if (event.type === EventType.RUN_ERROR) {
|
|
123
|
+
setIsTransitioning(false)
|
|
124
|
+
setMessages((prev) =>
|
|
125
|
+
prev.map((m) =>
|
|
126
|
+
m.messageId === assistantId
|
|
127
|
+
? { ...m, text: m.text || CHAT_ERROR_SHORT, isStreaming: false }
|
|
128
|
+
: m,
|
|
129
|
+
),
|
|
130
|
+
)
|
|
143
131
|
}
|
|
132
|
+
} catch {
|
|
133
|
+
// Skip malformed JSON lines
|
|
144
134
|
}
|
|
145
135
|
}
|
|
146
|
-
|
|
147
|
-
// Ensure streaming flag is cleared
|
|
148
|
-
setMessages((prev) => prev.map((m) => (m.messageId === assistantId ? { ...m, isStreaming: false } : m)))
|
|
149
|
-
} catch (error) {
|
|
150
|
-
console.error('Chat stream error:', error)
|
|
151
|
-
setMessages((prev) =>
|
|
152
|
-
prev.map((m) => (m.messageId === assistantId ? { ...m, text: m.text || CHAT_ERROR, isStreaming: false } : m)),
|
|
153
|
-
)
|
|
154
|
-
} finally {
|
|
155
|
-
setIsLoading(false)
|
|
156
136
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
137
|
+
|
|
138
|
+
// Ensure streaming flag is cleared
|
|
139
|
+
setMessages((prev) => prev.map((m) => (m.messageId === assistantId ? { ...m, isStreaming: false } : m)))
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error('Chat stream error:', error)
|
|
142
|
+
setMessages((prev) =>
|
|
143
|
+
prev.map((m) =>
|
|
144
|
+
m.messageId === assistantId
|
|
145
|
+
? { ...m, text: m.text || CHAT_ERROR, isStreaming: false }
|
|
146
|
+
: m,
|
|
147
|
+
),
|
|
148
|
+
)
|
|
149
|
+
} finally {
|
|
150
|
+
setIsLoading(false)
|
|
151
|
+
}
|
|
152
|
+
}, [onSessionUpdate, sessionId])
|
|
160
153
|
|
|
161
154
|
return (
|
|
162
155
|
<ChatContainer elevation={0}>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @genui/a3
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@genui/a3)
|
|
3
|
+
[](https://www.npmjs.com/package/@genui/a3)
|
|
4
4
|
[](https://github.com/generalui/a3/blob/main/LICENSE)
|
|
5
5
|
|
|
6
6
|
**Predictable, governable multi-agent orchestration for TypeScript.**
|
package/template/package.json
CHANGED
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
"@ag-ui/encoder": "0.0.45",
|
|
12
12
|
"@emotion/react": "11.14.0",
|
|
13
13
|
"@emotion/styled": "11.14.1",
|
|
14
|
-
"@genui/a3": "
|
|
15
|
-
"@genui/a3-anthropic": "
|
|
16
|
-
"@genui/a3-bedrock": "
|
|
17
|
-
"@genui/a3-openai": "
|
|
14
|
+
"@genui/a3": "^0.1.36",
|
|
15
|
+
"@genui/a3-anthropic": "^0.1.36",
|
|
16
|
+
"@genui/a3-bedrock": "^0.1.36",
|
|
17
|
+
"@genui/a3-openai": "^0.1.36",
|
|
18
18
|
"@mui/icons-material": "7.3.7",
|
|
19
19
|
"@mui/material": "7.3.7",
|
|
20
20
|
"next": "16.1.7",
|
package/template/next-env.d.ts
DELETED