@@ -8,6 +8,7 @@ const localAgentUrl = (import.meta as any).env.VITE_AGENT_RUNTIME_URL || '/api';
88
99export interface InvokeAgentRequest {
1010 prompt : string ;
11+ onChunk ?: ( chunk : string ) => void ;
1112}
1213
1314export interface InvokeAgentResponse {
@@ -20,7 +21,7 @@ export const invokeAgent = async (request: InvokeAgentRequest): Promise<InvokeAg
2021 if ( isLocalDev ) {
2122 console . log ( 'Invoking local AgentCore:' , { url : localAgentUrl } ) ;
2223 console . log ( 'Request payload:' , { prompt : request . prompt } ) ;
23-
24+
2425 const response = await fetch ( `${ localAgentUrl } /invocations` , {
2526 method : 'POST' ,
2627 headers : {
@@ -30,15 +31,65 @@ export const invokeAgent = async (request: InvokeAgentRequest): Promise<InvokeAg
3031 prompt : request . prompt
3132 } ) ,
3233 } ) ;
33-
34+
3435 console . log ( 'Local AgentCore response status:' , response . status ) ;
35-
36+
3637 if ( ! response . ok ) {
3738 const errorText = await response . text ( ) ;
3839 console . error ( 'Local AgentCore error response:' , errorText ) ;
3940 throw new Error ( `Local AgentCore invocation failed: ${ response . status } ${ response . statusText } - ${ errorText } ` ) ;
4041 }
4142
43+ // Check if streaming callback is provided
44+ if ( request . onChunk && response . body ) {
45+ const reader = response . body . getReader ( ) ;
46+ const decoder = new TextDecoder ( ) ;
47+ let fullResponse = '' ;
48+ let buffer = '' ;
49+
50+ try {
51+ while ( true ) {
52+ const { done, value } = await reader . read ( ) ;
53+
54+ if ( done ) {
55+ break ;
56+ }
57+
58+ const chunk = decoder . decode ( value , { stream : true } ) ;
59+ buffer += chunk ;
60+
61+ // Process complete SSE messages in the buffer
62+ const lines = buffer . split ( '\n' ) ;
63+ // Keep the last incomplete line in the buffer
64+ buffer = lines . pop ( ) || '' ;
65+
66+ for ( const line of lines ) {
67+ if ( line . startsWith ( 'data: ' ) ) {
68+ const data = line . slice ( 6 ) ; // Remove 'data: ' prefix
69+
70+ // Try to parse as JSON string
71+ try {
72+ const parsed = JSON . parse ( data ) ;
73+ fullResponse += parsed ;
74+ // Call the chunk callback with parsed content
75+ request . onChunk ( parsed ) ;
76+ } catch {
77+ // If not JSON, use the raw data
78+ fullResponse += data ;
79+ request . onChunk ( data ) ;
80+ }
81+ }
82+ }
83+ }
84+
85+ console . log ( 'Streaming completed. Full response:' , fullResponse ) ;
86+ return { response : fullResponse } ;
87+ } finally {
88+ reader . releaseLock ( ) ;
89+ }
90+ }
91+
92+ // Non-streaming mode (backward compatibility)
4293 let data ;
4394 try {
4495 data = await response . json ( ) ;
@@ -49,7 +100,7 @@ export const invokeAgent = async (request: InvokeAgentRequest): Promise<InvokeAg
49100 console . log ( 'Raw response text:' , textResponse ) ;
50101 throw new Error ( `Invalid JSON response from local AgentCore: ${ textResponse } ` ) ;
51102 }
52-
103+
53104 // Handle different response formats from AgentCore
54105 let responseText = '' ;
55106 if ( typeof data === 'string' ) {
@@ -59,9 +110,9 @@ export const invokeAgent = async (request: InvokeAgentRequest): Promise<InvokeAg
59110 } else {
60111 responseText = 'No response from agent' ;
61112 }
62-
113+
63114 console . log ( 'Final response text:' , responseText ) ;
64-
115+
65116 return {
66117 response : responseText
67118 } ;
@@ -82,13 +133,13 @@ export const invokeAgent = async (request: InvokeAgentRequest): Promise<InvokeAg
82133
83134 // URL encode the agent runtime ARN for the API call (as per AWS documentation)
84135 const encodedAgentRuntimeArn = encodeURIComponent ( agentRuntimeArn ) ;
85-
136+
86137 // Use the correct AgentCore endpoint format from AWS documentation
87138 const url = `https://bedrock-agentcore.${ region } .amazonaws.com/runtimes/${ encodedAgentRuntimeArn } /invocations?qualifier=DEFAULT` ;
88-
139+
89140 console . log ( 'Invoking AgentCore directly:' , { url, agentRuntimeArn, region } ) ;
90141 console . log ( 'Request payload:' , { prompt : request . prompt } ) ;
91-
142+
92143 const response = await fetch ( url , {
93144 method : 'POST' ,
94145 headers : {
@@ -101,7 +152,7 @@ export const invokeAgent = async (request: InvokeAgentRequest): Promise<InvokeAg
101152 prompt : request . prompt
102153 } ) ,
103154 } ) ;
104-
155+
105156 console . log ( 'AgentCore response status:' , response . status ) ;
106157 console . log ( 'AgentCore response headers:' , Object . fromEntries ( response . headers . entries ( ) ) ) ;
107158
@@ -111,6 +162,56 @@ export const invokeAgent = async (request: InvokeAgentRequest): Promise<InvokeAg
111162 throw new Error ( `AgentCore invocation failed: ${ response . status } ${ response . statusText } - ${ errorText } ` ) ;
112163 }
113164
165+ // Check if streaming callback is provided
166+ if ( request . onChunk && response . body ) {
167+ const reader = response . body . getReader ( ) ;
168+ const decoder = new TextDecoder ( ) ;
169+ let fullResponse = '' ;
170+ let buffer = '' ;
171+
172+ try {
173+ while ( true ) {
174+ const { done, value } = await reader . read ( ) ;
175+
176+ if ( done ) {
177+ break ;
178+ }
179+
180+ const chunk = decoder . decode ( value , { stream : true } ) ;
181+ buffer += chunk ;
182+
183+ // Process complete SSE messages in the buffer
184+ const lines = buffer . split ( '\n' ) ;
185+ // Keep the last incomplete line in the buffer
186+ buffer = lines . pop ( ) || '' ;
187+
188+ for ( const line of lines ) {
189+ if ( line . startsWith ( 'data: ' ) ) {
190+ const data = line . slice ( 6 ) ; // Remove 'data: ' prefix
191+
192+ // Try to parse as JSON string
193+ try {
194+ const parsed = JSON . parse ( data ) ;
195+ fullResponse += parsed ;
196+ // Call the chunk callback with parsed content
197+ request . onChunk ( parsed ) ;
198+ } catch {
199+ // If not JSON, use the raw data
200+ fullResponse += data ;
201+ request . onChunk ( data ) ;
202+ }
203+ }
204+ }
205+ }
206+
207+ console . log ( 'Streaming completed. Full response:' , fullResponse ) ;
208+ return { response : fullResponse } ;
209+ } finally {
210+ reader . releaseLock ( ) ;
211+ }
212+ }
213+
214+ // Non-streaming mode (backward compatibility)
114215 let data ;
115216 try {
116217 data = await response . json ( ) ;
@@ -121,7 +222,7 @@ export const invokeAgent = async (request: InvokeAgentRequest): Promise<InvokeAg
121222 console . log ( 'Raw response text:' , textResponse ) ;
122223 throw new Error ( `Invalid JSON response from AgentCore: ${ textResponse } ` ) ;
123224 }
124-
225+
125226 // Handle different response formats from AgentCore
126227 let responseText = '' ;
127228 if ( typeof data === 'string' ) {
@@ -131,9 +232,9 @@ export const invokeAgent = async (request: InvokeAgentRequest): Promise<InvokeAg
131232 } else {
132233 responseText = 'No response from agent' ;
133234 }
134-
235+
135236 console . log ( 'Final response text:' , responseText ) ;
136-
237+
137238 return {
138239 response : responseText
139240 } ;
@@ -142,4 +243,4 @@ export const invokeAgent = async (request: InvokeAgentRequest): Promise<InvokeAg
142243 console . error ( 'AgentCore invocation error:' , error ) ;
143244 throw new Error ( `Failed to invoke agent: ${ error . message } ` ) ;
144245 }
145- } ;
246+ } ;
0 commit comments