@@ -6,9 +6,42 @@ import { StreamingAgent } from '@astack-tech/components/agents';
66import { Deepseek } from '@astack-tech/integrations/model-provider' ;
77import type { ModelProvider } from '@astack-tech/components' ;
88
9+ // Enhanced logging function with immediate flush
10+ const log = ( ...args : unknown [ ] ) => {
11+ const timestamp = new Date ( ) . toISOString ( ) ;
12+ console . log ( `[${ timestamp } ]` , ...args ) ;
13+ // Force flush to stdout for CloudWatch
14+ if ( process . stdout . write ) {
15+ process . stdout . write ( '' ) ;
16+ }
17+ } ;
18+
19+ const logError = ( ...args : unknown [ ] ) => {
20+ const timestamp = new Date ( ) . toISOString ( ) ;
21+ console . error ( `[${ timestamp } ] ERROR:` , ...args ) ;
22+ if ( process . stderr . write ) {
23+ process . stderr . write ( '' ) ;
24+ }
25+ } ;
26+
927// Initialize Hono app
1028const app = new Hono ( ) ;
1129
30+ // Global request logger middleware
31+ app . use ( '*' , async ( c , next ) => {
32+ const method = c . req . method ;
33+ const path = c . req . path ;
34+ const startTime = Date . now ( ) ;
35+
36+ log ( `➡️ ${ method } ${ path } ` ) ;
37+ log ( `📋 Headers:` , JSON . stringify ( c . req . header ( ) , null , 2 ) ) ;
38+
39+ await next ( ) ;
40+
41+ const duration = Date . now ( ) - startTime ;
42+ log ( `⬅️ ${ method } ${ path } - Status: ${ c . res . status } - Duration: ${ duration } ms` ) ;
43+ } ) ;
44+
1245// Create Deepseek model instance
1346const createModel = ( ) : ModelProvider => {
1447 const apiKey = process . env . DEEPSEEK_API_KEY ;
@@ -56,26 +89,60 @@ app.get('/health', (c: Context) => {
5689 } ) ;
5790} ) ;
5891
92+ // Ping endpoint for AgentCore health checks
93+ app . get ( '/ping' , ( c : Context ) => {
94+ return c . json ( { status : 'healthy' } ) ;
95+ } ) ;
96+
5997// AWS Bedrock AgentCore invocations endpoint (port 8080 required)
6098app . post ( '/invocations' , async ( c : Context ) => {
6199 try {
62- const request : BedrockRequest = await c . req . json ( ) ;
100+ log ( '🔍 Parsing request body...' ) ;
101+ const rawBody = await c . req . text ( ) ;
102+ log ( '📦 Raw request body:' , rawBody ) ;
103+
104+ let request : BedrockRequest ;
105+ try {
106+ request = JSON . parse ( rawBody ) ;
107+ log ( '✅ Request parsed successfully:' , JSON . stringify ( request , null , 2 ) ) ;
108+ } catch ( parseError ) {
109+ logError ( '❌ JSON parse error:' , parseError ) ;
110+ return c . json (
111+ {
112+ error : 'Invalid JSON in request body' ,
113+ details : parseError instanceof Error ? parseError . message : 'Unknown parse error' ,
114+ receivedBody : rawBody . substring ( 0 , 500 ) , // First 500 chars for debugging
115+ } ,
116+ 400
117+ ) ;
118+ }
63119
64120 // Extract messages from request
65121 const messages = request . messages || [
66122 { role : 'user' as const , content : request . inputText || '' } ,
67123 ] ;
68124
125+ log ( '💬 Processing messages:' , JSON . stringify ( messages , null , 2 ) ) ;
126+
69127 const agent = getAgent ( ) ;
128+ log ( '🤖 Agent instance ready' ) ;
70129
71130 // Stream response using SSE format
131+ log ( '🌊 Starting SSE stream...' ) ;
72132 return streamSSE ( c , async ( stream : SSEStreamingApi ) => {
73133 try {
134+ log ( '📡 Beginning agent execution...' ) ;
135+ let chunkCount = 0 ;
136+
74137 for await ( const chunk of agent . runStream ( { messages } ) ) {
138+ chunkCount ++ ;
139+ log ( `📨 Chunk ${ chunkCount } :` , chunk . type ) ;
140+
75141 // Transform AStack chunks to SSE events
76142 switch ( chunk . type ) {
77143 case 'assistant_message' :
78144 if ( chunk . content ) {
145+ log ( `💬 Assistant message: "${ chunk . content . substring ( 0 , 100 ) } ..."` ) ;
79146 await stream . writeSSE ( {
80147 event : 'message' ,
81148 data : JSON . stringify ( {
@@ -87,6 +154,7 @@ app.post('/invocations', async (c: Context) => {
87154 break ;
88155
89156 case 'completed' :
157+ log ( '✅ Stream completed:' , chunk . finalMessage ?. substring ( 0 , 100 ) ) ;
90158 await stream . writeSSE ( {
91159 event : 'done' ,
92160 data : JSON . stringify ( {
@@ -97,6 +165,7 @@ app.post('/invocations', async (c: Context) => {
97165 break ;
98166
99167 case 'error' :
168+ logError ( '❌ Stream error:' , chunk . error ) ;
100169 await stream . writeSSE ( {
101170 event : 'error' ,
102171 data : JSON . stringify ( {
@@ -106,19 +175,25 @@ app.post('/invocations', async (c: Context) => {
106175 break ;
107176 }
108177 }
178+
179+ log ( `✨ Stream finished successfully with ${ chunkCount } chunks` ) ;
109180 } catch ( error ) {
181+ logError ( '❌ Stream processing error:' , error ) ;
110182 await stream . writeSSE ( {
111183 event : 'error' ,
112184 data : JSON . stringify ( {
113185 error : error instanceof Error ? error . message : 'Stream error' ,
186+ stack : error instanceof Error ? error . stack : undefined ,
114187 } ) ,
115188 } ) ;
116189 }
117190 } ) ;
118191 } catch ( error ) {
192+ logError ( '❌ Request handling error:' , error ) ;
119193 return c . json (
120194 {
121195 error : error instanceof Error ? error . message : 'Invalid request' ,
196+ stack : error instanceof Error ? error . stack : undefined ,
122197 } ,
123198 400
124199 ) ;
@@ -136,9 +211,14 @@ serve(
136211 hostname : HOST ,
137212 } ,
138213 ( ) => {
139- console . log ( `🚀 AStack Bedrock Agent Runtime started` ) ;
140- console . log ( `📡 Listening on ${ HOST } :${ PORT } ` ) ;
141- console . log ( `🔗 Health: http://localhost:${ PORT } /health` ) ;
142- console . log ( `🤖 Invocations: http://localhost:${ PORT } /invocations` ) ;
214+ log ( '🚀 AStack Bedrock Agent Runtime started' ) ;
215+ log ( `📡 Listening on ${ HOST } :${ PORT } ` ) ;
216+ log ( `🔗 Health: http://localhost:${ PORT } /health` ) ;
217+ log ( `🤖 Invocations: http://localhost:${ PORT } /invocations` ) ;
218+ log ( '🔧 Environment:' , {
219+ NODE_ENV : process . env . NODE_ENV ,
220+ HAS_DEEPSEEK_KEY : ! ! process . env . DEEPSEEK_API_KEY ,
221+ } ) ;
222+ log ( '✨ Ready to handle requests' ) ;
143223 }
144224) ;
0 commit comments