APEX AI Agent Logging with Request & Response Handlers

Introduction
Logging is one of the first things you need when building serious AI Agents. Without it, debugging quickly becomes guesswork. You can see the final answer, but not always why the model chose a tool, what arguments it passed, what data came back, or how much context was sent into the next model call.
APEX AI Agent Request and Response handlers provide useful inspection points inside the agent loop. In this post, I will show how I used those handlers to log the request and response, tool calls and results, token usage, and related runtime metadata for an APEX AI Agent interaction.
I am focusing only on logging here. The same handlers can also be used to modify requests and responses, but that deserves its own post.
Why Logging is Important
Logging AI Agent activity allows you to:
Troubleshoot agent behavior by seeing the actual request, response, tool calls, tool results, and loop invocation where something changed.
Audit what the model saw and returned, including user prompts, system prompts, tool schemas, final answers, refusals, and errors.
Validate tool usage by inspecting requested tool names, arguments, execution results, and whether business rules were followed.
Monitor cost and performance using token counts, response size, large tool-result payloads, and repeated agent-loop turns.
Build repeatable evals and regression tests from real interactions, including prompts, tool definitions, tool calls, tool results, and final responses.
Setup
For APEX AI Agent calls, Request and Response handlers provide a clean place to add logging. These are hooks provided by the APEX team to allow you to call your own code before and after each AI service request in the agent loop, including turns where the model requests tool execution or receives tool results.
Handler API Signatures
APEX requires that you provide procedures with specific signatures. Here are the signatures for the two procedures in the configuration above.
PROCEDURE agent_request_handler
(p_param in apex_ai.t_chat_request_handler_param,
p_result in out nocopy apex_ai.t_chat_request_handler_result);
PROCEDURE agent_response_handler
(p_param in apex_ai.t_chat_response_handler_param,
p_result in out nocopy apex_ai.t_chat_response_handler_result);
The APEX documentation has details of the record types here, although at the time of writing this post, apex_ai.t_chat_request_handler_param and apex_ai.t_chat_request_handler_result were not in the docs (link to forum post).
Logging the Request
When APEX makes a call to an AI service, it first makes a call to the procedure you set up in the 'Request Handler Procedure' above. In my example, this is the procedure agent_request_handler.
Use this handler when you need to shape what gets sent to the AI model. Typical uses include:
Identify the turn number within the agent loop.
Check the user prompt for prompt injection or inappropriate content.
Supplement the
system_promptwith APEX application context.Add, remove, or modify available tools before the model sees them.
Make other controlled changes to the outgoing request.
In the context of logging and AI Agents, this handler allows us to capture the following. The list below contains 12 of the more interesting fields (out of about 40). I have annotated each output with values from an example AI Agent call.
p_param.invocationShows which turn of the agent loop is running. In the log, invocation1is the initial user request; invocation2is after the tool call result is available.p_param.agent.static_idIdentifies the specific APEX AI Agent:dispatchiq-service-agent.p_param.component.*Shows what APEX component invoked the agent. Here it isNATIVE_OPEN_AI_ASSISTANTon anAPEX_APPLICATION_PAGE_DA_ACTScomponent.p_result.request.service_idIdentifies the configured AI service/provider used for the request:6845344927070344.p_result.request.system_promptContains the operational instruction sent to the model.p_result.request.messages.countShows how much conversation context is being sent. It is1initially, then3after the assistant tool call and the tool result are added.p_result.request.messages(n).chat_roleShows the role sequence sent to the model. The second request includesuser,assistant, andtool.p_result.request.messages(n).tool_callsCaptures tool-call history. On invocation2, the assistant message includes asearch_open_casestool call with id and arguments.p_result.request.messages(n).tool.contentContains the tool result returned into the model context.p_result.request.toolsLists the tools exposed to the model:create_service_case,create_service_visit,customer_case_summary,lookup_asset_health,recommend_technician,search_open_cases,update_service_case, andupdate_service_visit.p_result.request.tools(n).parameters_json_schemaThis is the exact JSON schema supplied to the model for each tool’s arguments. It matters because it controls what argument names, types, required fields, and enum-style constraints the model is expected to follow. In the log, these schemas are populated for all 8 tools on the latter request.p_result.payloadCarries runtime metadata outside the core model request. This log includes values such aschatId, plugin state, notifications, approved tools,toolExecutionOrder, server tool names,exposeServerTools, andexposeTokenUsage. After the tool executes, it also carries notification data likeSearched Open Casesand prior token usage.
Logging the Response
When an APEX AI Agent receives a response from an AI service, it makes a call to the procedure you set up in the Response Handler Procedure. In my example, this is the procedure agent_response_handler.
Use this handler when you need to inspect, validate, or modify the output from the AI model. In APEX terms, the response handler receives a read-only t_chat_response_handler_param record and returns changes through a read-write t_chat_response_handler_result record. Oracle defines the response-handler input as containing invocation, the normalized request, and pending_tool_calls; the result contains response, messages, and early_exit.
Typical uses:
Determine whether the AI service returned a final answer, an error, or requested tool execution.
Inspect pending tool calls before they are executed.
Validate tool-call arguments for authorization, safety, required values, or business-rule violations.
Detect invalid tool calls, invalid JSON responses, refusals, content filtering, or max-length failures.
Add or replace messages returned from the response handler.
Set
early_exitwhen you want to stop the normal agent loop.Capture token usage and response metadata.
Modify, suppress, or replace the assistant’s final response.
Add notifications, approvals, audit data, or custom payload values after the model responds.
Any other post-processing of the AI response.
In the context of logging and AI Agents, this handler allows us to capture the following. The list below contains 15 of the more interesting fields, out of a total of about 65 logged structural attributes. I have again annotated each output with values from an example AI Agent call.
p_param.invocation
Shows which turn of the agent loop is running. In the log, invocation1is the model response that requests a tool call; invocation2is the response after the tool result has been sent back to the model.p_param.request
This is the normalizedt_chat_requestpassed into the response handler. Per the APEX docs, it includesservice_id,system_prompt,messages,tools,temperature, andresponse_json_schema.p_param.request.messages
This is the chat history sent to the model. APEX defines each entry as at_chat_message, withchat_role,message,tool_calls,tool, andattachments.p_param.request.messages(n).chat_role
Shows the role sequence. Oracle defines role constants forassistant,system,tool, anduser. In the example, the second response-handler call includesuser,assistant, andtool.p_param.request.messages(n).tool_calls
Captures tool calls emitted by the AI service and included in chat history. APEX defines a tool call as havingid,name,args, andargs_json.p_param.request.messages(n).tool.content
Contains tool-response content added back into the chat history. Oracle describes this as the tool response entry used byC_ROLE_TOOL.p_param.request.tools
Lists the tool definitions available to the model. In the example:create_service_case,create_service_visit,customer_case_summary,lookup_asset_health,recommend_technician,search_open_cases,update_service_case, andupdate_service_visit.p_param.pending_tool_calls
Contains tool calls requested by the AI service that are pending execution. In the first response-handler call, this contains1tool call; in the second, it contains0.p_param.pending_tool_calls(n).args_json
Contains parsed JSON arguments for a pending tool call. In the example,search_open_caseswas called withMAX_ROWS: 100and the other filters set tonull.p_result.response.type
Shows the high-level response type. Oracle definescomplete,error, andtool_calls. In the example, the first response istool_calls; the second iscomplete.p_result.response.errorandp_result.response.refusal
These identify failure/refusal states. Oracle defines recoverable response error values such ascontent_filter,generic,invalid_response,invalid_tool_call,max_length, andrefusal. In this log, these fields are empty.p_result.response.message
Contains the normalized assistant response as at_chat_message. In the final call, this contains the assistant’s answer beginning “Here are the open cases returned…”p_result.response.input_tokens,p_result.response.output_tokens, andp_result.response.total_tokens
Captures token usage from the AI provider response. In the example, the total tokens were2,854for the tool-call response and12,177for the final response after the tool result was included.p_result.messages
A read-write collection of chat messages returned by the handler. This can be used when you need to add or alter messages as part of response handling.p_result.early_exit
A Boolean result field that can stop the normal response flow. In the example log, it isNULL, meaning the handler did not force an early exit.
Sample Code
I created a gist that includes a package body containing the two handler procedures agent_request_handler and agent_response_handler. These procedures (with the help of some helper functions) output every single record and attribute passed into the handlers by the APEX AI Agent. Everything is output using apex_debug.info, so you need to enable debug before invoking your agent to see the results. This is a great way to see what is going on during an APEX Agent Loop.
You can see an Excel file with a sample agent interaction and the results from these debug messages here.
Interesting Observations
Two things stood out to me while writing this post:
SQL Query-style tool results are returned as CSV text inside
tool.content. I guess I was expecting this to be JSON because JSON preserves structure and JSON can include metadata about the response (e.g., rows returned, total available rows, page number, etc.).The tool result dominated the economics of the interaction. The first response used
2,854total tokens; after the tool result was injected, the second response used12,177. The “expensive” part of an agent workflow is not the user prompt or system prompt, but the shape and size of your database result set.
Conclusion
APEX Agent Request and Response handlers provide a useful inspection point within the APEX AI Agent loop. Even if you do not change the request or response, logging these records makes it much easier to understand what the agent was asked to do, which tools it selected, what arguments it passed, what came back from those tools, and how the final answer was produced.
The biggest practical lesson from this exercise is that tool design is also cost design. If a tool returns too much data, that data becomes model context on the next turn. Logging makes that visible.
Once you have this level of visibility, debugging AI Agent behavior becomes a lot less subjective. You can inspect the actual prompts, tool definitions, tool calls, tool results, token usage, errors, and final responses, then make targeted changes to your prompts, tools, schemas, and data returned to the model.
In a future post, I will look at how these same handlers can be used not just for logging, but also to modify requests and responses as part of the agent workflow.




