Skip to content

Read execution logs and diagnose errors

The execution log shows which tools ran, what they returned, and whether the run completed. Use it to investigate incorrect answers, slow responses, and errors. This lesson reads the run from lesson 3.

UC AI records two things for each run:

  • uc_ai_agent_executions holds one row per run, with the caller, status, token counts, and run context.
  • uc_ai_agent_messages holds one row for each message item, in order. This includes a row for each tool call and each tool result.

Both tables include the session ID. Lesson 3 printed it after SESSION:. In SQLcl, run variable session_id varchar2(255). Then run execute :session_id := 'PASTE_SESSION_ID_HERE', with your ID in place of the placeholder. The queries below use this bind variable.

If you did not keep the ID, read session_id from the latest execution record for SC_DESK in uc_ai_agent_executions.

Read the messages of the lesson 3 run:

select seq
, role
, tool_name
, substr(coalesce(tool_input, content), 1, 60) as detail
from uc_ai_agent_messages
where session_id = :session_id
order by seq;
SEQ ROLE TOOL_NAME DETAIL
1 user - How much can I still credit on INV-1003, and is the call ins
2 reasoning -
3 tool_call SC_GET_CONTRACT {}
4 tool_call SC_LIST_INVOICES {"max_rows":20}
5 tool_call SC_LIST_CALLS {"max_rows":20}
6 tool_result SC_GET_CONTRACT
7 tool_result SC_LIST_INVOICES
8 tool_result SC_LIST_CALLS
9 assistant - INV-1003 has **€0** left to credit; its full €200 has alread

The recorded trace shows:

  • The model asked for three tools in one round (seq 3 to 5), then read all three results. A round can hold more than one call.
  • The arguments were {} and {"max_rows":20}. There is no contract in them, because no tool declares one. tool_input is what the model sent, and UC AI adds _ctx after that point. The next query reads the run context from the execution row.
  • The answer at seq 9 came after the results at 6 to 8.

Run this query to read the five most recent executions of SC_DESK:

select e.id as execution_id
, e.status
, e.created_by
, e.audience
, e.tool_calls_count
, e.total_input_tokens
, e.total_output_tokens
, e.run_context
, e.error_message
from uc_ai_agent_executions e
where e.agent_id = ( select id from uc_ai_agents where code = 'SC_DESK' )
order by e.started_at desc
fetch first 5 rows only;

Selected columns from the lesson 3 execution:

STATUS CREATED_BY AUDIENCE TOOL_CALLS_COUNT IN OUT RUN_CONTEXT
completed UC_AI db 3 1854 172 {"contract_id":"88"}

run_context records the contract ID supplied by the application.

If the trace contains no tool_call row, inspect the profile configuration, tool tags, and descriptions:

  1. The tag did not reach the profile. Read it back:

    select model_config_json from uc_ai_prompt_profiles
    where code = 'SC_DESK_PROFILE' and version = 1;

    You must see "g_enable_tools": true and your tag in "g_tool_tags". Lesson 3 wrote both.

  2. The tag matches no active tool. A tag with no tool behind it gives the model nothing, and no error:

    select t.code, t.active, g.tag
    from uc_ai_tools t join uc_ai_tool_tags g on g.tool_id = t.id
    where g.tag = 'scdesk';
  3. The description does not say when to use the tool. The description must explain both the returned data and when to request it. For example: “List invoice amounts and existing credits. Use this before you raise a credit note.”

The trace contains a tool_call and a tool_result, but the answer does not use the returned data.

Read tool_output to see what the handler returned:

select seq, tool_name, substr(tool_output, 1, 200) as tool_output
from uc_ai_agent_messages
where session_id = :session_id
and role = 'tool_result'
order by seq;

One possible cause is a handler refusal. The demo handlers return "status":"refused" and a reason when they cannot process a request. The model can report that refusal instead of the requested invoice data.

g_max_tool_calls sets a stopping threshold for the tool loop. To read the actual number of requested calls, run this query:

select count(*) as tool_calls
from uc_ai_agent_messages
where session_id = :session_id
and role = 'tool_call';

On a failed execution record, the token and tool-call counts remain 0. The framework has no result object from which to read the totals. Run this query to inspect failed execution records:

select status, error_message, total_input_tokens, tool_calls_count
from uc_ai_agent_executions
where status = 'failed'
order by started_at desc
fetch first 3 rows only;

So tool_calls_count = 0 on a failed row does not mean “no tool ran”. Count the tool_call rows in uc_ai_agent_messages instead. On a completed row, the column records the tool-call count.

Run the recent-executions query for your lesson 3 run. Inspect these columns:

  • run_context holds {"contract_id":"88"}. A missing contract ID causes the demo handlers to refuse requests.
  • tool_calls_count matches the number of tool_call rows in the trace. The recorded run has 3 in both places. Your model can ask for two or three.
  • Use execution records and messages to diagnose a run.
  • Read tool_output to distinguish a handler refusal from returned invoice data.
  • select seq, role, tool_name, tool_input from uc_ai_agent_messages where session_id = :s order by seq;

Full reference: Conversation message log has every column and the attribution rules for multi-agent patterns.