@@ -120,8 +120,6 @@ def __init__(
120120 self .handlers : Dict [str , Callable ] = {}
121121 self ._ping_handler : Optional [Callable ] = None
122122 self ._websocket_handler : Optional [Callable ] = None
123- self ._prompt_key : Optional [str ] = None
124- self ._response_key : Optional [str ] = None
125123 self ._active_tasks : Dict [int , Dict [str , Any ]] = {}
126124 self ._task_counter_lock : threading .Lock = threading .Lock ()
127125 self ._forced_ping_status : Optional [PingStatus ] = None
@@ -146,44 +144,18 @@ def __init__(
146144 self .logger .addHandler (handler )
147145 self .logger .setLevel (logging .DEBUG if self .debug else logging .INFO )
148146
149- def entrypoint (
150- self , func : Callable = None , * , prompt_key : Optional [str ] = None , response_key : Optional [str ] = None
151- ) -> Callable :
147+ def entrypoint (self , func : Callable ) -> Callable :
152148 """Decorator to register a function as the main entrypoint.
153149
154150 Args:
155151 func: The function to register as entrypoint
156- prompt_key: Optional key to extract user prompt from the payload dict.
157- If not specified, tries common keys in order (prompt, input, query,
158- message, question, user_input) then falls back to JSON serialization.
159- response_key: Optional key to extract agent response from the result dict.
160- If not specified, the full result is used.
161152
162153 Returns:
163154 The decorated function with added serve method
164-
165- Examples:
166- @app.entrypoint
167- def handler(payload):
168- ...
169-
170- @app.entrypoint(prompt_key="user_input")
171- def handler(payload):
172- ...
173155 """
174-
175- def decorator (f : Callable ) -> Callable :
176- self .handlers ["main" ] = f
177- self ._prompt_key = prompt_key
178- self ._response_key = response_key
179- f .run = lambda port = 8080 , host = None : self .run (port , host )
180- return f
181-
182- if func is not None :
183- # Called as @app.entrypoint without arguments
184- return decorator (func )
185- # Called as @app.entrypoint(...) with arguments
186- return decorator
156+ self .handlers ["main" ] = func
157+ func .run = lambda port = 8080 , host = None : self .run (port , host )
158+ return func
187159
188160 def ping (self , func : Callable ) -> Callable :
189161 """Decorator to register a custom ping status handler.
@@ -412,78 +384,6 @@ def _takes_context(self, handler: Callable) -> bool:
412384 except Exception :
413385 return False
414386
415- def _emit_invocation_otel_attributes (self , payload : Any , result : Any ) -> None :
416- """Emit OTEL span attributes with the invocation input and output.
417-
418- These attributes provide a canonical, framework-agnostic source of the
419- user's prompt and the agent's response for AgentCore Evaluation. They
420- enable evaluation of agents that use custom state schemas (e.g. workflow
421- agents with TypedDict states) where the default MessagesState-based
422- extraction in the evaluation mapper would fail.
423-
424- The attributes are set on the current active span (typically the root
425- POST /invocations span created by ADOT auto-instrumentation).
426-
427- When prompt_key or response_key is configured via @app.entrypoint(),
428- those specific keys are used to extract from dict payloads/results.
429- Otherwise, a heuristic tries common keys in priority order.
430- """
431- try :
432- from opentelemetry import trace as otel_trace
433-
434- span = otel_trace .get_current_span ()
435- if not span or not span .is_recording ():
436- return
437-
438- # Extract user prompt from payload
439- user_prompt = None
440- if isinstance (payload , dict ):
441- if self ._prompt_key is not None :
442- value = payload .get (self ._prompt_key )
443- if isinstance (value , str ):
444- user_prompt = value
445- else :
446- for key in ("prompt" , "input" , "query" , "message" , "question" , "user_input" ):
447- if key in payload and isinstance (payload [key ], str ):
448- user_prompt = payload [key ]
449- break
450- if user_prompt is None :
451- user_prompt = json .dumps (payload , ensure_ascii = False , default = str )
452- elif isinstance (payload , str ):
453- user_prompt = payload
454- else :
455- user_prompt = str (payload )
456-
457- # Extract agent response from result
458- agent_response = None
459- if isinstance (result , str ):
460- agent_response = result
461- elif isinstance (result , Response ):
462- pass # Skip for streaming/custom responses — cannot capture full output
463- elif isinstance (result , dict ) and self ._response_key is not None :
464- value = result .get (self ._response_key )
465- if isinstance (value , str ):
466- agent_response = value
467- elif value is not None :
468- try :
469- agent_response = json .dumps (value , ensure_ascii = False , default = str )
470- except Exception :
471- agent_response = str (value )
472- elif result is not None :
473- try :
474- agent_response = json .dumps (result , ensure_ascii = False , default = str )
475- except Exception :
476- agent_response = str (result )
477-
478- if user_prompt :
479- span .set_attribute ("agentcore.invocation.user_prompt" , user_prompt [:16384 ])
480- if agent_response :
481- span .set_attribute ("agentcore.invocation.agent_response" , agent_response [:16384 ])
482- except ImportError :
483- pass # OpenTelemetry not installed — silently skip
484- except Exception :
485- self .logger .debug ("Failed to emit invocation OTEL attributes" , exc_info = True )
486-
487387 async def _handle_invocation (self , request ):
488388 request_context = self ._build_request_context (request )
489389
@@ -511,8 +411,6 @@ async def _handle_invocation(self, request):
511411 self .logger .debug ("Invoking handler: %s" , handler_name )
512412 result = await self ._invoke_handler (handler , request_context , takes_context , payload )
513413
514- self ._emit_invocation_otel_attributes (payload , result )
515-
516414 duration = time .time () - start_time
517415 if inspect .isgenerator (result ):
518416 self .logger .info ("Returning streaming response (generator) (%.3fs)" , duration )
0 commit comments