Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,19 @@ This format follows [Keep a Changelog](https://keepachangelog.com/) and adheres
WAF checklist row are gone.

### Fixed
- **Observe distinguishes request and dependency telemetry reliably.** KQL now
retains the source table while unioning Application Insights records, so
Overview and Agents prefer request-level `invoke_agent` records correctly
instead of returning zero totals, and Runs omits uncorrelated internal spans.
- **Observe now attributes Foundry agents and presents usable telemetry tables.**
Hosted and prompt agents are classified from their emitted provider metadata,
project attribution recognizes the Foundry project dimension, and Runs returns
one correlated execution instead of separate rows for each internal operation.
Overview counts only agent invocations, token usage is split into sortable
columns, and internal connector diagnostics and the redundant Telemetry
coverage tab no longer appear in the user-facing dashboard.
KQL tracks each unioned telemetry table explicitly so Overview and Agents can
prefer request records without returning empty totals. Overview counts only
agent invocations, token usage is split into sortable columns, and internal
connector diagnostics and the redundant Telemetry coverage tab no longer
appear in the user-facing dashboard.
- **Foundry project links now open the configured project instead of the tenant
landing page.** In project-observability-only mode there is no cloud evaluation
report from which to recover a portal URL, so Cockpit previously fell back to
Expand Down
12 changes: 7 additions & 5 deletions src/agentops/agent/observe/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
DEFAULT_REQUEST_DEADLINE_SECONDS = 10
DEFAULT_LOOKBACK_HOURS = 24

_TELEMETRY_TABLES = "union AppDependencies, AppRequests"
_TELEMETRY_TABLES = "union withsource=TelemetryTable AppDependencies, AppRequests"
_APPGENAI_TABLE = "AppGenAIContent"
_PROJECT_RESOURCE_ID = (
'tostring(coalesce(Properties["gen_ai.project.id"], '
Expand Down Expand Up @@ -268,9 +268,9 @@ def build_overview_query(
_time_window_clause(filters),
*_dimension_filters(filters, scope_source),
*_agent_extend_clauses(),
'| extend is_request_invocation = Type == "AppRequests" and '
'| extend is_request_invocation = TelemetryTable == "AppRequests" and '
'operation_name == "invoke_agent", '
'is_dependency_invocation = Type == "AppDependencies" and '
'is_dependency_invocation = TelemetryTable == "AppDependencies" and '
'operation_name == "invoke_agent"',
"| summarize request_invocations = countif(is_request_invocation), "
"dependency_invocations = countif(is_dependency_invocation), "
Expand Down Expand Up @@ -301,9 +301,9 @@ def build_agents_query(
_time_window_clause(filters),
*_dimension_filters(filters, scope_source),
*_agent_extend_clauses(),
'| extend is_request_invocation = Type == "AppRequests" and '
'| extend is_request_invocation = TelemetryTable == "AppRequests" and '
'operation_name == "invoke_agent", '
'is_dependency_invocation = Type == "AppDependencies" and '
'is_dependency_invocation = TelemetryTable == "AppDependencies" and '
'operation_name == "invoke_agent"',
"| summarize request_invocations = countif(is_request_invocation), "
"dependency_invocations = countif(is_dependency_invocation), "
Expand Down Expand Up @@ -496,6 +496,8 @@ def build_runs_query(
"reported_credits, decimal(null))",
'| extend conversation_id = tostring(Properties["gen_ai.conversation.id"])',
'| extend foundry_thread_id = tostring(Properties["gen_ai.thread.id"])',
"| where isnotempty(conversation_id) or isnotempty(foundry_thread_id) "
'or operation_name == "invoke_agent"',
"| extend run_key = iff(isnotempty(conversation_id), conversation_id, "
"iff(isnotempty(foundry_thread_id), foundry_thread_id, tostring(OperationId)))",
"| extend run_key_kind = iff(isnotempty(conversation_id) or isnotempty(foundry_thread_id), "
Expand Down
12 changes: 10 additions & 2 deletions tests/unit/test_observe_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,9 @@ def test_models_query_projects_unmapped_usage_attributes_in_one_bounded_query()
assert "make_bag(pack(token_class_name, token_class_value))" in query
assert "extra_token_classes" in query
assert "join kind=leftouter" in query
assert query.count("union AppDependencies, AppRequests") == 1
assert (
query.count("union withsource=TelemetryTable AppDependencies, AppRequests") == 1
)
assert query.count("by project_resource_id, model, deployment") >= 2
assert "| sort by requests desc" in query
assert f"| take {MAX_ROWS_PER_QUERY}" in query
Expand Down Expand Up @@ -688,7 +690,9 @@ def test_tool_filter_kql_metacharacters_remain_inside_the_string_literal() -> No
def test_tools_query_uses_tool_metadata_without_reading_tool_content() -> None:
query = build_tools_query(_filters(tool_name="lookup'o''ticket"))

assert query.startswith("let base = union AppDependencies, AppRequests")
assert query.startswith(
"let base = union withsource=TelemetryTable AppDependencies, AppRequests"
)
assert 'Properties["gen_ai.tool.name"]' in query
assert 'Properties["gen_ai.operation.name"]' in query
assert "| where isnotempty(tool_name)" in query
Expand All @@ -713,6 +717,10 @@ def test_runs_query_prefers_conversation_then_foundry_thread_before_trace() -> N
< query.index("tostring(OperationId)")
)
assert '"conversation", "trace"' in query
assert (
"| where isnotempty(conversation_id) or isnotempty(foundry_thread_id) "
'or operation_name == "invoke_agent"'
) in query
assert "run\\'o\\'\\'key" in query
assert "| sort by last_activity_at desc" in query
assert "turns = dcount(OperationId)" in query
Expand Down
Loading