Query Details

Custom Agent Protected Content

Query

// Legacy protected-only source, retained for reference; the current pack deploys CustomAgentInlineContent instead.
let Spans=CustomAgentSpans(lookback)
| where Classification !in ('Excluded managed platform', 'Unattributed GenAI') and HasLineage;
let Protected=AppGenAIContent
| where TimeGenerated > ago(lookback)
| extend _ResourceId=tolower(tostring(_ResourceId)), OperationId=tolower(tostring(TraceId)),
    SpanId=tolower(tostring(SpanId)), ContentTime=TimeGenerated
| where isnotempty(_ResourceId) and isnotempty(OperationId) and isnotempty(SpanId)
| summarize arg_max(ContentTime, *) by _ResourceId, OperationId, SpanId
| project _ResourceId, OperationId, SpanId, ContentTime,
    Messages=todynamic(InputMessages), OutputText=tostring(OutputMessages),
    ToolResult=tostring(column_ifexists('ToolCallResult', ''));
Spans
| join kind=inner Protected on _ResourceId, OperationId, SpanId
| extend Messages=iff(gettype(Messages) == 'array' and array_length(Messages) > 0, Messages, dynamic([{}]))
| mv-apply Message=Messages on (
    extend Role=tolower(tostring(Message.role)), Parts=coalesce(Message.parts, Message.content)
    | extend Parts=case(gettype(Parts) == 'string', pack_array(bag_pack('content', tostring(Parts))),
        gettype(Parts) == 'array' and array_length(Parts) > 0, Parts, dynamic([{}]))
    | mv-apply Part=Parts on (
        extend PartText=coalesce(tostring(Part.content), tostring(Part.text),
            iff(gettype(Part) == 'string', tostring(Part), ''))
        | summarize MessageText=strcat_array(make_list(PartText, 100), '\n') by Role
      )
    | summarize UserText=strcat_array(make_list_if(MessageText, Role == 'user', 100), '\n'),
        SystemText=strcat_array(make_list_if(MessageText, Role in ('system', 'developer'), 100), '\n')
  )
| project-away Messages

Explanation

This KQL (Kusto Query Language) query is designed to process and analyze data related to application-generated AI content. Here's a simplified breakdown of what it does:

  1. Define Spans:

    • It starts by filtering data from CustomAgentSpans to exclude certain classifications and only include entries with lineage information.
  2. Define Protected Content:

    • It retrieves data from AppGenAIContent that has been generated within a specified time frame (lookback).
    • It ensures that certain fields (_ResourceId, OperationId, SpanId) are not empty and converts them to lowercase.
    • It summarizes the data to get the most recent entry for each combination of _ResourceId, OperationId, and SpanId.
    • It extracts and processes message content and tool results.
  3. Join and Process Data:

    • It performs an inner join between the Spans and Protected datasets based on _ResourceId, OperationId, and SpanId.
    • It processes the Messages field to ensure it is an array and applies transformations to extract and concatenate message parts.
    • It separates the message content into UserText and SystemText based on the role of the message (e.g., user, system, developer).
  4. Output:

    • The final output excludes the original Messages field and provides a structured view of user and system messages related to AI content interactions.

In essence, this query is used to analyze and summarize interactions with AI content, focusing on the roles of different message parts and organizing them into user and system text for further analysis.