Query Agent Catalog Traces with SQL++

  • Capella AI Services
  • how-to
You can also use SQL++ through the Query Service or Capella Analytics to query your Agent Catalog activity logs.

Using queries might return more details on traces that you cannot see through the Agent Tracer UI.

Prerequisites

Procedure

To query traces from the Agent Catalog:

  • Query Service

  • Capella Analytics

  1. In the Capella UI, on the Operational page, click the name of the cluster where you uploaded your Agent Catalog activity.

  2. Go to Data Tools  Query.

  3. Do 1 of the following, or write your own query for your log data:

  1. In the Capella UI, on the Analytics page, click the name of the cluster where you created the link to your Agent Catalog operational cluster.

  2. Do 1 of the following, or write your own query for your log data:

Query the Sessions View

The following example queries use a generated data view called Sessions to return data on specific sessions in your agent activity. This can include agent handoff information, for help with debugging multi-agent systems.

  • Query Service

  • Capella Analytics

Copy and paste the following query into the Query Service’s Query Workbench, replacing the placeholders with the bucket and scope for your Agent Catalog activity logs:

FROM
        `[BUCKET_NAME]`.`[SCOPE_NAME]`.Sessions() s
    SELECT
        s.sid,
        s.cid,
        s.root,
        s.start_t,
        s.content,
        s.ann
    LIMIT 10;

If you want to specifically filter for agent handoff messages in the Sessions view, add a WHERE clause to your query for kind = "edge":

FROM
        `[BUCKET_NAME]`.`[SCOPE_NAME]`.Sessions() s
    SELECT
        s.sid,
        s.cid,
        s.root,
        s.start_t,
        s.content,
        s.ann
    WHERE kind = "edge"
    LIMIT 10;

Copy and paste the following query into the Capella Analytics workbench. Replace the placeholders with the database, scope, and collection link name from your Analytics cluster remote link to your Agent Catalog activity logs. This query creates the Sessions data view:

CREATE OR REPLACE ANALYTICS VIEW `[DATABASE_NAME]`.`[SCOPE_NAME]`.Sessions AS
    FROM
        `[DATABASE_NAME]`.`[SCOPE_NAME]`.`[COLLECTION_NAME]` AS l
    LETTING
        sid = l.span.session,
        cid = {
            "identifier": l.catalog_version.identifier,
            "timestamp": l.catalog_version.timestamp
        },
        root = l.span.name[0]
    GROUP BY
        sid,
        cid,
        root
        GROUP AS g
    LETTING
        content = (
            FROM
                g AS gi
            SELECT
                gi.l.content     AS event,
                gi.l.timestamp   AS timestamp,
                gi.l.span.name   AS name,
                gi.l.annotations AS annotations,
                ROW_NUMBER()
                    OVER (
                        ORDER BY
                            STR_TO_MILLIS(gi.l.timestamp) ASC
                    ) AS seq_num
            ORDER BY
                seq_num
        ),
        annotations = (
            FROM
                g AS gi
            WHERE
                gi.l.annotations IS NOT UNKNOWN
            SELECT DISTINCT
                gi.l.span.name,
                gi.l.annotations
        )
    SELECT
        sid                  AS sid,
        cid                  AS cid,
        root                 AS root,
        content              AS content,
        content[0].timestamp AS start_t,
        annotations          AS ann
    ORDER BY
        STR_TO_MILLIS(start_t) ASC;

Then, run the following query to return 10 Sessions records:

FROM
      `[DATABASE_NAME]`.`[SCOPE_NAME]`.Sessions s
    SELECT
        s.sid,
        s.cid,
        s.root,
        s.start_t,
        s.content,
        s.ann
    LIMIT 10;

If you want to specifically filter for agent handoff messages in the Sessions view, add a WHERE clause to your query for kind = "edge":

FROM
      `[DATABASE_NAME]`.`[SCOPE_NAME]`.Sessions s
    SELECT
        s.sid,
        s.cid,
        s.root,
        s.start_t,
        s.content,
        s.ann
    WHERE kind = "edge"
    LIMIT 10;

The records in the Sessions view contain the following information:

Key Description

sid

The session ID value.

Set a session string on a span to customize this value, or accept the default generated UUIDs. For more information, see the Agent Catalog documentation on Log.Span.

cid

The specific catalog version.

root

The name of the root span, as configured in Add a Root Span to Your Agentic App.

start_t

The start time of the session.

content

The events that occurred during the session, such as user messages, LLM responses, or internal agent thinking.

ann

Any custom tags added to the messages or the span.

Query the Exchanges View

The following example queries use a generated data view called Exchanges to return data on specific exchanges, or the events between a user’s input and the agent’s response.

  • Query Service

  • Capella Analytics

Copy and paste the following query into the Query Service’s Query Workbench, replacing agent-catalog and agent-activity with the bucket and scope for your Agent Catalog activity logs:

FROM
        `[BUCKET_NAME]`.`[SCOPE_NAME]`.Exchanges() e
    SELECT
        e.sid,
        e.root,
        e.input,
        e.output,
        e.content
    ORDER BY
        e.output.timestamp DESC
    LIMIT 1;

Copy and paste the following query into the Capella Analytics workbench. Replace the placeholders with the database, scope, and collection link name from your Analytics cluster remote link to your Agent Catalog activity logs. This query creates the Exchanges data view:

CREATE OR REPLACE ANALYTICS VIEW `[BUCKET_NAME]`.`[SCOPE_NAME]`.Exchanges AS
    WITH
        RowOrderedLogs AS (
            FROM
                `[BUCKET_NAME]`.`[SCOPE_NAME]`.`[LOG_COLLECTION_NAME]` AS l
            SELECT
                l.content.kind AS kind,
                l.span.session AS sid,
                l.*,
                ROW_NUMBER()
                    OVER (
                        PARTITION BY
                            sid
                        ORDER BY
                            STR_TO_MILLIS(l.timestamp) ASC
                    ) AS rn
        ),
        UserToAssistantRows AS (
            FROM
                RowOrderedLogs rol
            GROUP BY
                rol.sid
                GROUP AS g
            LETTING
                input_rows = (
                    FROM
                        g AS gi
                    WHERE
                        gi.rol.kind = "user"
                    SELECT VALUE
                        gi.rol.rn
                    ORDER BY
                        gi.rol.rn ASC
                ),
                output_rows = (
                    FROM
                        g AS gi
                    WHERE
                        gi.rol.kind = "assistant"
                    SELECT VALUE
                        gi.rol.rn
                    ORDER BY
                        gi.rol.rn ASC
                ),
                -- We are looking for the row numbers corresponding to user -- assistant pairs here.
                input_output_pairs = (
                    FROM
                       input_rows AS iro,
                       output_rows AS oro
                    WHERE
                        iro < oro
                    GROUP BY
                        iro
                        GROUP AS gi
                    -- We are interested in the closest assistant message to the user message.
                    LETTING
                        ordered_output = (
                            FROM
                                gi AS gii
                            SELECT VALUE
                                gii.oro
                            ORDER BY
                                gii.oro ASC
                        )
                    SELECT
                        iro               AS input_row,
                        ordered_output[0] AS output_row
                )
            SELECT
                rol.sid            AS sid,
                input_output_pairs AS pairs
        ),
        UserToAssistantUnnested AS (
            FROM
                UserToAssistantRows AS u2a,
                u2a.pairs AS p
            SELECT
                u2a.sid      AS sid,
                p.input_row  AS inp_rn,
                p.output_row AS out_rn
        )
    FROM
        UserToAssistantUnnested AS u2au,
        RowOrderedLogs AS rol
    WHERE
        rol.sid = u2au.sid AND
        rol.rn >= u2au.inp_rn AND
        rol.rn <= u2au.out_rn
    GROUP BY
        rol.sid          AS sid,
        rol.span.name[0] AS root,
        u2au.inp_rn      AS inp_rn,
        u2au.out_rn      AS out_rn
        GROUP AS g
    LETTING
        content = (
            FROM
                g AS gi
            SELECT VALUE
                OBJECT_REMOVE(gi.rol, "rn")
            ORDER BY
                gi.rol.timestamp ASC
        ),
        input_content = (
            FROM
                g AS gi
            WHERE
                gi.rol.rn = inp_rn
            SELECT VALUE
                OBJECT_REMOVE(gi.rol, "rn")
            LIMIT 1
        )[0],
        output_content = (
            FROM
                g AS gi
            WHERE
                gi.rol.rn = out_rn
            SELECT VALUE
                OBJECT_REMOVE(gi.rol, "rn")
            LIMIT 1
        )[0]
    SELECT
        sid            AS sid,
        root           AS root,
        input_content  AS `input`,
        output_content AS `out`,
        content        AS content;

Then, run the following query to return the most recent exchange record:

FROM 
      `[DATABASE_NAME]`.`[SCOPE_NAME]`.Exchanges e
    SELECT 
        e.sid,
        e.root,
        e.input,
        e.out,
        e.content
    ORDER BY e.out.timestamp DESC
    LIMIT 1;

The records in the Exchanges view contain the following information:

Key Description

sid

The session ID value.

Set a session string on a span to customize this value, or accept the default generated UUIDs. For more information, see the Agent Catalog documentation on Log.Span.

root

The name of the root span, as configured in Add a Root Span to Your Agentic App.

input

The user’s input to the agent app.

output (out in the Capella Analytics view)

The assistant’s response to the user’s input.

content

All intermediate content logs between the input and output events, including messages sent to the LLM, tools executed, and so on.

Query the ToolInvocations View

The following example queries use a generated data view called ToolInvocations to return data on tool calls and tool results.

  • Query Service

  • Capella Analytics

Copy and paste the following query into the Query Service’s Query Workbench, replacing agent-catalog and agent-activity with the bucket and scope for your Agent Catalog activity logs:

FROM
        `[BUCKET_NAME]`.`[SCOPE_NAME]`.ToolInvocations() ti
    SELECT
        ti.sid,
        ti.root,
        ti.tool_call,
        ti.tool_result
    ORDER BY
        ti.tool_result.timestamp DESC
    LIMIT 1;

Copy and paste the following query into the Capella Analytics workbench. Replace the placeholders with the database, scope, and collection link name from your Analytics cluster remote link to your Agent Catalog activity logs. This query creates the ToolInvocations data view:

CREATE OR REPLACE ANALYTICS VIEW `[BUCKET_NAME]`.`[SCOPE_NAME]`.ToolInvocations AS
    FROM
        (
            WITH
                RowOrderedToolLogs AS (
                    FROM
                        `[BUCKET_NAME]`.`[SCOPE_NAME]`.`[LOG_COLLECTION_NAME]` AS l
                    WHERE
                        l.content.kind = "tool-call" OR
                        l.content.kind = "tool-result"
                    SELECT
                        l.content.kind AS kind,
                        l.span.session AS sid,
                        l.*,
                        ROW_NUMBER()
                            OVER (
                                PARTITION BY
                                    sid
                                ORDER BY
                                    STR_TO_MILLIS(l.timestamp) ASC
                            ) AS rn
                ),
                CallToResultRows AS (
                    FROM
                        RowOrderedToolLogs rol
                    GROUP BY
                        rol.sid
                        GROUP AS g
                    LETTING
                        input_rows = (
                            FROM
                                g AS gi
                            WHERE
                                gi.rol.kind = "tool-call"
                            SELECT VALUE
                                gi.rol.rn
                            ORDER BY
                                gi.rol.rn ASC
                        ),
                        output_rows = (
                            FROM
                                g AS gi
                            WHERE
                                gi.rol.kind = "tool-result"
                            SELECT VALUE
                                gi.rol.rn
                            ORDER BY
                                gi.rol.rn ASC
                        ),
                        input_output_pairs = (
                            FROM
                               input_rows AS iro,
                               output_rows AS oro
                            WHERE
                                iro < oro
                            GROUP BY
                                iro
                                GROUP AS gi
                            LETTING
                                ordered_output = (
                                    FROM
                                        gi AS gii
                                    SELECT VALUE
                                        gii.oro
                                    ORDER BY
                                        gii.oro ASC
                                )
                            SELECT
                                iro               AS input_row,
                                ordered_output[0] AS output_row
                        )
                    SELECT
                        rol.sid            AS sid,
                        input_output_pairs AS pairs
                ),
                CallToResultRowsUnnested AS (
                    FROM
                        CallToResultRows AS c2r,
                        c2r.pairs AS p
                    SELECT
                        c2r.sid      AS sid,
                        p.input_row  AS inp_rn,
                        p.output_row AS out_rn
                ),
                ToolCalls AS (
                    FROM
                        `[BUCKET_NAME]`.`[SCOPE_NAME]`.`[LOG_COLLECTION_NAME]` AS l
                    WHERE
                        l.content.kind = "tool-call"
                    SELECT VALUE
                        l
                ),
                ToolResults AS (
                    FROM
                        `[BUCKET_NAME]`.`[SCOPE_NAME]`.`[LOG_COLLECTION_NAME]` AS l
                    WHERE
                        l.content.kind = "tool-result"
                    SELECT VALUE
                        l
                )
            FROM
                CallToResultRowsUnnested AS c2ru,
                RowOrderedToolLogs AS rol1,
                RowOrderedToolLogs AS rol2
            LETTING
                tool_call = OBJECT_REMOVE(rol1, "rn"),
                tool_result = OBJECT_REMOVE(rol2, "rn")
            WHERE
                rol1.rn = c2ru.inp_rn AND
                rol2.rn = c2ru.out_rn
            SELECT
                c2ru.sid       AS sid,
                c2ru.span.name AS root,
                tool_call      AS tool_call,
                tool_result    AS tool_result
            UNION ALL
            FROM
                ToolCalls AS tc,
                ToolResults AS tr
            WHERE
                tc.content.tool_call_id = tr.content.tool_call_id
            SELECT
                tc.span.session AS sid,
                tc.span.name    AS root,
                tc              AS tool_call,
                tr              AS tool_result
        ) AS ti
    GROUP BY
        tc.identifier
        GROUP AS g
    SELECT VALUE
        g[0].ti;

Then, run the following query to return the most recent tool invocation record:

FROM
        `[BUCKET_NAME]`.`[SCOPE_NAME]`.ToolInvocations ti
    SELECT
        ti.sid,
        ti.root,
        ti.tool_call,
        ti.tool_result
    ORDER BY
        ti.tool_result.timestamp DESC
    LIMIT 1;

The records in the ToolInvocations view contain the following information:

Key Description

sid

The session ID value.

Set a session string on a span to customize this value, or accept the default generated UUIDs. For more information, see the Agent Catalog documentation on Log.Span.

root

The name of the root span, as configured in Add a Root Span to Your Agentic App.

tool_call

The tool call from your agent application.

tool_result

The results returned by the tool call.

Next Steps

To view traces in the Agent Tracer UI, see View Traces in Agent Tracer.

To view details about specific tools and prompts published to Agent Catalog from your project, see Use the Agent Catalog Tools and Prompts Hub.