Skip to main content

Command Palette

Search for a command to run...

APEX AI Agent Logging with Request & Response Handlers

Updated
11 min read
APEX AI Agent Logging with Request & Response Handlers
J
Hi, thanks for stopping by! I am focused on designing and building innovative solutions using AI, the Oracle Database, Oracle APEX, and Oracle REST Data Services (ORDS). I hope you enjoy my blog.

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.

🗾
Shared Components > Generative AI > AI Attributes
APEX 26.1 AI Agent Request and Response Handler Setup
💡
As noted above, you can do much more with Request and Response handlers, but I will focus on logging for this post.

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_prompt with 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.

  1. p_param.invocation Shows which turn of the agent loop is running. In the log, invocation 1 is the initial user request; invocation 2 is after the tool call result is available.

  2. p_param.agent.static_id Identifies the specific APEX AI Agent: dispatchiq-service-agent.

  3. p_param.component.* Shows what APEX component invoked the agent. Here it is NATIVE_OPEN_AI_ASSISTANT on an APEX_APPLICATION_PAGE_DA_ACTS component.

  4. p_result.request.service_id Identifies the configured AI service/provider used for the request: 6845344927070344.

  5. p_result.request.system_prompt Contains the operational instruction sent to the model.

  6. p_result.request.messages.count Shows how much conversation context is being sent. It is 1 initially, then 3 after the assistant tool call and the tool result are added.

  7. p_result.request.messages(n).chat_role Shows the role sequence sent to the model. The second request includes user, assistant, and tool.

  8. p_result.request.messages(n).tool_calls Captures tool-call history. On invocation 2, the assistant message includes a search_open_cases tool call with id and arguments.

  9. p_result.request.messages(n).tool.content Contains the tool result returned into the model context.

  10. p_result.request.tools Lists 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, and update_service_visit.

  11. p_result.request.tools(n).parameters_json_schema This 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.

  12. p_result.payload Carries runtime metadata outside the core model request. This log includes values such as chatId, plugin state, notifications, approved tools, toolExecutionOrder, server tool names, exposeServerTools, and exposeTokenUsage. After the tool executes, it also carries notification data like Searched Open Cases and 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_exit when 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, invocation 1 is the model response that requests a tool call; invocation 2 is the response after the tool result has been sent back to the model.

  • p_param.request
    This is the normalized t_chat_request passed into the response handler. Per the APEX docs, it includes service_id, system_prompt, messages, tools, temperature, and response_json_schema.

  • p_param.request.messages
    This is the chat history sent to the model. APEX defines each entry as a t_chat_message, with chat_role, message, tool_calls, tool, and attachments.

  • p_param.request.messages(n).chat_role
    Shows the role sequence. Oracle defines role constants for assistant, system, tool, and user. In the example, the second response-handler call includes user, assistant, and tool.

  • 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 having id, name, args, and args_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 by C_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, and update_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 contains 1 tool call; in the second, it contains 0.

  • p_param.pending_tool_calls(n).args_json
    Contains parsed JSON arguments for a pending tool call. In the example, search_open_cases was called with MAX_ROWS: 100 and the other filters set to null.

  • p_result.response.type
    Shows the high-level response type. Oracle defines complete, error, and tool_calls. In the example, the first response is tool_calls; the second is complete.

  • p_result.response.error and p_result.response.refusal
    These identify failure/refusal states. Oracle defines recoverable response error values such as content_filter, generic, invalid_response, invalid_tool_call, max_length, and refusal. In this log, these fields are empty.

  • p_result.response.message
    Contains the normalized assistant response as a t_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, and p_result.response.total_tokens
    Captures token usage from the AI provider response. In the example, the total tokens were 2,854 for the tool-call response and 12,177 for 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 is NULL, 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.

This code is not intended to be a drop-in APEX Agent Handler logging solution. The sample code logs everything so you can see what APEX passes through the handlers. That is useful for learning and debugging, but it is not what I would deploy unchanged in production. Prompts, system prompts, tool results, model responses, and payload metadata may contain sensitive business data or personal information. In a real application, log selectively, redact sensitive values, restrict access to the logging tables, and define a retention policy.

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,854 total tokens; after the tool result was injected, the second response used 12,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.