bigquery-agent-analytics 0.2.0__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/PKG-INFO +1 -1
  2. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/pyproject.toml +1 -1
  3. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/trace.py +94 -14
  4. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_sdk_trace.py +255 -0
  5. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/.github/workflows/ci.yml +0 -0
  6. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/.github/workflows/release.yml +0 -0
  7. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/.gitignore +0 -0
  8. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/CODE_OF_CONDUCT.md +0 -0
  9. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/CONTRIBUTING.md +0 -0
  10. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/LICENSE +0 -0
  11. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/README.md +0 -0
  12. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/SDK.md +0 -0
  13. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/SECURITY.md +0 -0
  14. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/autoformat.sh +0 -0
  15. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/dashboard/README.md +0 -0
  16. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/dashboard/agent_analytics_dashboard.ipynb +0 -0
  17. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/dashboard/app.py +0 -0
  18. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/dashboard/requirements.txt +0 -0
  19. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/README.md +0 -0
  20. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/continuous_queries/README.md +0 -0
  21. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/continuous_queries/bigtable_dashboard.sql +0 -0
  22. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/continuous_queries/pubsub_alerting.sql +0 -0
  23. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/continuous_queries/realtime_error_analysis.sql +0 -0
  24. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/continuous_queries/session_scoring.sql +0 -0
  25. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/continuous_queries/setup_reservation.md +0 -0
  26. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/python_udf/README.md +0 -0
  27. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/python_udf/register.sql +0 -0
  28. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/remote_function/README.md +0 -0
  29. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/remote_function/deploy.sh +0 -0
  30. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/remote_function/dispatch.py +0 -0
  31. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/remote_function/main.py +0 -0
  32. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/remote_function/register.sql +0 -0
  33. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/streaming_evaluation/README.md +0 -0
  34. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/streaming_evaluation/main.py +0 -0
  35. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/streaming_evaluation/requirements.txt +0 -0
  36. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/streaming_evaluation/setup.sh +0 -0
  37. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/streaming_evaluation/trigger_query.sql +0 -0
  38. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/deploy/streaming_evaluation/worker.py +0 -0
  39. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/README.md +0 -0
  40. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/context_graph_v2_design.md +0 -0
  41. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/context_graph_v3_design.md +0 -0
  42. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/design.md +0 -0
  43. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/hatteras_evaluation.md +0 -0
  44. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/implementation_plan_remote_function.md +0 -0
  45. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/learning_ontology_and_context_graph.md +0 -0
  46. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/ontology/binding.md +0 -0
  47. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/ontology/cli.md +0 -0
  48. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/ontology/compilation.md +0 -0
  49. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/ontology/ontology.md +0 -0
  50. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/ontology/owl-import.md +0 -0
  51. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/ontology/scaffold.md +0 -0
  52. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/ontology_graph_v4_design.md +0 -0
  53. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/ontology_graph_v5_design.md +0 -0
  54. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/prd_unified_analytics_interface.md +0 -0
  55. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/proposal_bigquery_agent_cli.md +0 -0
  56. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/python_udf_support_design.md +0 -0
  57. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/remote_function_rationale.md +0 -0
  58. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/docs/sdk_usage_tracking.md +0 -0
  59. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/README.md +0 -0
  60. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/ai_classify_side_by_side.sql +0 -0
  61. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/ai_forecast_side_by_side.sql +0 -0
  62. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/ai_ml_integration_demo.ipynb +0 -0
  63. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/ai_similarity_validation.sql +0 -0
  64. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/categorical_dashboard.sql +0 -0
  65. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/categorical_evaluation_demo.ipynb +0 -0
  66. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/ci_eval_pipeline.sh +0 -0
  67. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/cli_agent_tool.py +0 -0
  68. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/context_graph_adcp_demo.ipynb +0 -0
  69. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/continuous_query_alerting.sql +0 -0
  70. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/dashboard_v2.ipynb +0 -0
  71. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/dashboard_v2_bigframes.ipynb +0 -0
  72. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/e2e_demo.py +0 -0
  73. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/e2e_demo_output.txt +0 -0
  74. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/e2e_notebook_demo.ipynb +0 -0
  75. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/event_semantics_views_bigframes_demo.ipynb +0 -0
  76. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/memory_service_demo.ipynb +0 -0
  77. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/migration_v5_demo_notebook.ipynb +0 -0
  78. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/nba_agent_trace_analysis_notebook.ipynb +0 -0
  79. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/ontology_graph_v4_demo.ipynb +0 -0
  80. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/ontology_graph_v5_demo.ipynb +0 -0
  81. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/python_udf_eval_summary.sql +0 -0
  82. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/python_udf_evaluation.sql +0 -0
  83. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/python_udf_event_semantics.sql +0 -0
  84. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/remote_function_dashboard.sql +0 -0
  85. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/examples/ymgo_graph_spec.yaml +0 -0
  86. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/scripts/README.md +0 -0
  87. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/scripts/quality_report.py +0 -0
  88. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/scripts/quality_report.sh +0 -0
  89. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/scripts/sample_report.md +0 -0
  90. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/__init__.py +0 -0
  91. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/_deploy_runtime.py +0 -0
  92. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/_streaming_evaluation.py +0 -0
  93. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/_telemetry.py +0 -0
  94. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/ai_ml_integration.py +0 -0
  95. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/bigframes_evaluator.py +0 -0
  96. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/categorical_evaluator.py +0 -0
  97. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/categorical_views.py +0 -0
  98. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/cli.py +0 -0
  99. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/client.py +0 -0
  100. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/context_graph.py +0 -0
  101. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/eval_suite.py +0 -0
  102. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/eval_validator.py +0 -0
  103. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/evaluators.py +0 -0
  104. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/event_semantics.py +0 -0
  105. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/extracted_models.py +0 -0
  106. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/feedback.py +0 -0
  107. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/formatter.py +0 -0
  108. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/grader_pipeline.py +0 -0
  109. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/insights.py +0 -0
  110. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/memory_service.py +0 -0
  111. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/multi_trial.py +0 -0
  112. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/ontology_graph.py +0 -0
  113. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/ontology_materializer.py +0 -0
  114. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/ontology_models.py +0 -0
  115. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/ontology_orchestrator.py +0 -0
  116. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/ontology_property_graph.py +0 -0
  117. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/ontology_schema_compiler.py +0 -0
  118. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/resolved_spec.py +0 -0
  119. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/runtime_spec.py +0 -0
  120. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/serialization.py +0 -0
  121. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/structured_extraction.py +0 -0
  122. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/trace_evaluator.py +0 -0
  123. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/ttl_importer.py +0 -0
  124. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/udf_kernels.py +0 -0
  125. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/udf_sql_templates.py +0 -0
  126. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_agent_analytics/views.py +0 -0
  127. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_ontology/__init__.py +0 -0
  128. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_ontology/binding_loader.py +0 -0
  129. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_ontology/binding_models.py +0 -0
  130. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_ontology/cli.py +0 -0
  131. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_ontology/docs/user_manual.md +0 -0
  132. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_ontology/graph_ddl_compiler.py +0 -0
  133. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_ontology/graph_ddl_models.py +0 -0
  134. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_ontology/ontology_loader.py +0 -0
  135. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_ontology/ontology_models.py +0 -0
  136. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_ontology/owl_importer.py +0 -0
  137. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/src/bigquery_ontology/scaffold.py +0 -0
  138. {bigquery_agent_analytics-0.2.0/tests/bigquery_ontology → bigquery_agent_analytics-0.2.1/tests}/__init__.py +0 -0
  139. {bigquery_agent_analytics-0.2.0/tests → bigquery_agent_analytics-0.2.1/tests/bigquery_ontology}/__init__.py +0 -0
  140. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/bigquery_ontology/test_binding_loader.py +0 -0
  141. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/bigquery_ontology/test_binding_models.py +0 -0
  142. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/bigquery_ontology/test_cli.py +0 -0
  143. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/bigquery_ontology/test_graph_ddl_compiler.py +0 -0
  144. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/bigquery_ontology/test_ontology_models.py +0 -0
  145. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/bigquery_ontology/test_owl_importer.py +0 -0
  146. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/bigquery_ontology/test_scaffold.py +0 -0
  147. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/bigquery_ontology/test_scaffold_cli.py +0 -0
  148. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/fixtures/lineage_sessions.json +0 -0
  149. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/fixtures/mixed_events.json +0 -0
  150. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/fixtures/test_binding.yaml +0 -0
  151. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/fixtures/test_combined_spec.yaml +0 -0
  152. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/fixtures/test_ontology.yaml +0 -0
  153. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/fixtures/yamo_sample.ttl +0 -0
  154. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_ai_ml_integration.py +0 -0
  155. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_ai_ml_integration_labels.py +0 -0
  156. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_bigframes_evaluator.py +0 -0
  157. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_bridge_hardening.py +0 -0
  158. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_categorical_evaluator.py +0 -0
  159. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_categorical_views.py +0 -0
  160. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_cli.py +0 -0
  161. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_client_labels.py +0 -0
  162. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_context_graph.py +0 -0
  163. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_context_graph_labels.py +0 -0
  164. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_dual_loader.py +0 -0
  165. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_eval_suite.py +0 -0
  166. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_eval_validator.py +0 -0
  167. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_event_semantics.py +0 -0
  168. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_extracted_models.py +0 -0
  169. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_feedback_labels.py +0 -0
  170. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_formatter.py +0 -0
  171. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_grader_pipeline.py +0 -0
  172. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_integration_ontology_binding.py +0 -0
  173. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_memory_service.py +0 -0
  174. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_memory_service_labels.py +0 -0
  175. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_multi_trial.py +0 -0
  176. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_ontology_graph.py +0 -0
  177. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_ontology_labels.py +0 -0
  178. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_ontology_materializer.py +0 -0
  179. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_ontology_models.py +0 -0
  180. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_ontology_orchestrator.py +0 -0
  181. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_ontology_property_graph.py +0 -0
  182. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_ontology_schema_compiler.py +0 -0
  183. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_owl_import_bridge.py +0 -0
  184. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_pr16_fixes.py +0 -0
  185. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_pr17_fixes.py +0 -0
  186. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_pr19_fixes.py +0 -0
  187. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_quality_report_helpers.py +0 -0
  188. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_remote_function.py +0 -0
  189. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_resolved_spec.py +0 -0
  190. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_runtime_factory.py +0 -0
  191. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_runtime_spec.py +0 -0
  192. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_sdk_client.py +0 -0
  193. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_sdk_evaluators.py +0 -0
  194. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_sdk_feedback.py +0 -0
  195. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_sdk_insights.py +0 -0
  196. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_serialization.py +0 -0
  197. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_streaming_evaluation.py +0 -0
  198. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_surface_tags.py +0 -0
  199. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_telemetry.py +0 -0
  200. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_trace_evaluator.py +0 -0
  201. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_trace_filter_factory.py +0 -0
  202. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_udf_kernels.py +0 -0
  203. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_udf_sql_generation.py +0 -0
  204. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_v5_golden.py +0 -0
  205. {bigquery_agent_analytics-0.2.0 → bigquery_agent_analytics-0.2.1}/tests/test_views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bigquery-agent-analytics
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: SDK for analyzing and evaluating agent traces stored in BigQuery.
5
5
  Author: Google LLC
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bigquery-agent-analytics"
7
- version = "0.2.0"
7
+ version = "0.2.1"
8
8
  description = "SDK for analyzing and evaluating agent traces stored in BigQuery."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -42,6 +42,42 @@ from typing import Any, Optional
42
42
  logger = logging.getLogger("bigquery_agent_analytics." + __name__)
43
43
 
44
44
 
45
+ _ANSI_RED = "\x1b[31m"
46
+ _ANSI_YELLOW = "\x1b[33m"
47
+ _ANSI_RESET = "\x1b[0m"
48
+
49
+
50
+ def _colorize(text: str, ansi_code: str, enabled: bool) -> str:
51
+ """Wraps text in an ANSI color code when enabled, else returns unchanged."""
52
+ if not enabled:
53
+ return text
54
+ return f"{ansi_code}{text}{_ANSI_RESET}"
55
+
56
+
57
+ _TEXT_WRAPPER_PREFIX = "text: "
58
+
59
+
60
+ def _unwrap_text_field(value: str) -> str:
61
+ """Strip a leading ``text: '...'`` wrapper if present.
62
+
63
+ Some ADK plugin versions serialize an LLM response with a literal
64
+ ``text: '...'`` Python-repr-style prefix in ``content.response``.
65
+ Strip it so ``Span.summary`` and ``Trace.render`` surface a clean
66
+ human-readable string.
67
+ """
68
+ if not value.startswith(_TEXT_WRAPPER_PREFIX):
69
+ return value
70
+ inner = value[len(_TEXT_WRAPPER_PREFIX) :]
71
+ if not inner or inner[0] not in ("'", '"'):
72
+ return inner
73
+ quote = inner[0]
74
+ # Match trailing quote only if the string is not truncated.
75
+ if len(inner) >= 2 and inner.endswith(quote):
76
+ return inner[1:-1]
77
+ # Truncated — drop the opening quote and leave the rest.
78
+ return inner[1:]
79
+
80
+
45
81
  class EventType(Enum):
46
82
  """Standard event types logged by the analytics plugin."""
47
83
 
@@ -232,13 +268,32 @@ class Span:
232
268
  if not self.is_error:
233
269
  return None
234
270
  parts = [self.event_type]
235
- tool = self.content.get("tool")
236
- if tool:
237
- parts.append(f"tool={tool}")
271
+ if self.tool_name:
272
+ parts.append(f"tool={self.tool_name}")
238
273
  if self.error_message:
239
274
  parts.append(self.error_message[:200])
240
275
  return " | ".join(parts)
241
276
 
277
+ @property
278
+ def tool_name(self) -> Optional[str]:
279
+ """Returns the tool name for tool-related events.
280
+
281
+ Populated only for ``TOOL_STARTING``, ``TOOL_COMPLETED``,
282
+ ``TOOL_ERROR``, and ``HITL_*`` event types where the plugin
283
+ writes the tool name into ``content.tool``. Returns ``None``
284
+ for any other event type, even if ``content`` happens to
285
+ carry a ``"tool"`` key — callers rely on this attribute
286
+ meaning "this span invoked a tool."
287
+ """
288
+ if self.event_type not in (
289
+ "TOOL_STARTING",
290
+ "TOOL_COMPLETED",
291
+ "TOOL_ERROR",
292
+ ) and not self.event_type.startswith("HITL_"):
293
+ return None
294
+ tool = self.content.get("tool")
295
+ return tool if tool else None
296
+
242
297
  @property
243
298
  def label(self) -> str:
244
299
  """Returns a human-readable label for this span."""
@@ -311,6 +366,7 @@ class Span:
311
366
  text = self.content.get("text") or ""
312
367
  if not text:
313
368
  text = self.content.get("raw") or ""
369
+ text = _unwrap_text_field(text) if isinstance(text, str) else text
314
370
  if not text and self.content_parts:
315
371
  for p in self.content_parts:
316
372
  if p.text:
@@ -631,7 +687,7 @@ class Trace:
631
687
 
632
688
  return roots
633
689
 
634
- def render(self, format: str = "tree") -> str:
690
+ def render(self, format: str = "tree", color: bool = False) -> str:
635
691
  """Renders the trace as a hierarchical DAG view.
636
692
 
637
693
  This generates a tree representation of the agent's
@@ -642,6 +698,12 @@ class Trace:
642
698
 
643
699
  Args:
644
700
  format: Render format. Currently supports "tree".
701
+ color: When ``True``, wrap error markers and warning
702
+ markers in ANSI color codes (red and yellow
703
+ respectively). Default ``False`` emits plain text
704
+ suitable for any output target. Enable this in TTY
705
+ contexts (terminal sessions) for faster visual
706
+ scanning of failures in large traces.
645
707
 
646
708
  Returns:
647
709
  A string containing the rendered trace. Also printed
@@ -661,10 +723,10 @@ class Trace:
661
723
  if not roots:
662
724
  # Flat rendering when no span IDs exist
663
725
  for span in self.spans:
664
- self._render_flat_span(span, lines)
726
+ self._render_flat_span(span, lines, color=color)
665
727
  else:
666
728
  for root in roots:
667
- self._render_span(root, lines, prefix="", is_last=True)
729
+ self._render_span(root, lines, prefix="", is_last=True, color=color)
668
730
 
669
731
  output = "\n".join(lines)
670
732
  print(output)
@@ -676,16 +738,17 @@ class Trace:
676
738
  lines: list[str],
677
739
  prefix: str,
678
740
  is_last: bool,
741
+ color: bool = False,
679
742
  ) -> None:
680
743
  """Recursively renders a span and its children as a tree."""
681
744
  connector = "\u2514\u2500 " if is_last else "\u251c\u2500 "
682
745
 
683
746
  if span.is_error:
684
- status_icon = "\u2717"
747
+ status_icon = _colorize("\u2717", _ANSI_RED, color)
685
748
  elif span.subtree_has_error:
686
749
  # Propagate error visibility: mark parents whose subtree
687
750
  # contains an error so the failure is visible at every level.
688
- status_icon = "\u26a0"
751
+ status_icon = _colorize("\u26a0", _ANSI_YELLOW, color)
689
752
  else:
690
753
  status_icon = "\u2713"
691
754
 
@@ -719,11 +782,20 @@ class Trace:
719
782
  lines,
720
783
  child_prefix,
721
784
  is_last=(i == len(span.children) - 1),
785
+ color=color,
722
786
  )
723
787
 
724
- def _render_flat_span(self, span: Span, lines: list[str]) -> None:
788
+ def _render_flat_span(
789
+ self,
790
+ span: Span,
791
+ lines: list[str],
792
+ color: bool = False,
793
+ ) -> None:
725
794
  """Renders a single span without tree structure."""
726
- status_icon = "\u2717" if span.is_error else "\u2713"
795
+ if span.is_error:
796
+ status_icon = _colorize("\u2717", _ANSI_RED, color)
797
+ else:
798
+ status_icon = "\u2713"
727
799
  latency = ""
728
800
  if span.latency_ms is not None:
729
801
  latency = f" ({span.latency_ms:.0f}ms)"
@@ -776,9 +848,13 @@ class Trace:
776
848
  if isinstance(c, dict):
777
849
  result = c.get("response")
778
850
  if result:
779
- return result
851
+ return (
852
+ _unwrap_text_field(result)
853
+ if isinstance(result, str)
854
+ else result
855
+ )
780
856
  elif c:
781
- return str(c)
857
+ return _unwrap_text_field(str(c))
782
858
 
783
859
  for span in reversed(self.spans):
784
860
  if span.event_type == "AGENT_COMPLETED":
@@ -786,9 +862,13 @@ class Trace:
786
862
  if isinstance(c, dict):
787
863
  result = c.get("response") or c.get("text_summary")
788
864
  if result:
789
- return result
865
+ return (
866
+ _unwrap_text_field(result)
867
+ if isinstance(result, str)
868
+ else result
869
+ )
790
870
  elif c:
791
- return str(c)
871
+ return _unwrap_text_field(str(c))
792
872
  return None
793
873
 
794
874
  @property
@@ -120,6 +120,73 @@ class TestSpan:
120
120
  )
121
121
  assert "ERROR" in span.label
122
122
 
123
+ def test_tool_name_for_tool_event(self):
124
+ span = Span(
125
+ event_type="TOOL_STARTING",
126
+ agent="agent",
127
+ timestamp=datetime.now(timezone.utc),
128
+ content={"tool": "search_contacts"},
129
+ )
130
+ assert span.tool_name == "search_contacts"
131
+
132
+ def test_tool_name_for_hitl_event(self):
133
+ span = Span(
134
+ event_type="HITL_APPROVAL_REQUESTED",
135
+ agent="agent",
136
+ timestamp=datetime.now(timezone.utc),
137
+ content={"tool": "book_meeting"},
138
+ )
139
+ assert span.tool_name == "book_meeting"
140
+
141
+ def test_tool_name_none_for_non_tool_event(self):
142
+ span = Span(
143
+ event_type="USER_MESSAGE_RECEIVED",
144
+ agent=None,
145
+ timestamp=datetime.now(timezone.utc),
146
+ content={"text_summary": "Hello"},
147
+ )
148
+ assert span.tool_name is None
149
+
150
+ def test_tool_name_none_when_missing(self):
151
+ span = Span(
152
+ event_type="TOOL_STARTING",
153
+ agent="agent",
154
+ timestamp=datetime.now(timezone.utc),
155
+ content={},
156
+ )
157
+ assert span.tool_name is None
158
+
159
+ def test_tool_name_none_when_empty(self):
160
+ span = Span(
161
+ event_type="TOOL_STARTING",
162
+ agent="agent",
163
+ timestamp=datetime.now(timezone.utc),
164
+ content={"tool": ""},
165
+ )
166
+ assert span.tool_name is None
167
+
168
+ def test_tool_name_does_not_leak_for_non_tool_event_with_tool_key(self):
169
+ """Non-tool events carrying an incidental content['tool'] key must
170
+ NOT surface it as tool_name. The attribute means "this span invoked
171
+ a tool" — arbitrary payloads that happen to use the same key name
172
+ should return None."""
173
+ span = Span(
174
+ event_type="AGENT_THOUGHT",
175
+ agent="agent",
176
+ timestamp=datetime.now(timezone.utc),
177
+ content={"tool": "looks_like_a_tool_but_isnt", "note": "reasoning"},
178
+ )
179
+ assert span.tool_name is None
180
+
181
+ def test_tool_name_does_not_leak_for_llm_response_with_tool_key(self):
182
+ span = Span(
183
+ event_type="LLM_RESPONSE",
184
+ agent="agent",
185
+ timestamp=datetime.now(timezone.utc),
186
+ content={"response": "I'll use a tool", "tool": "mentioned_in_text"},
187
+ )
188
+ assert span.tool_name is None
189
+
123
190
  def test_summary_with_text(self):
124
191
  span = Span(
125
192
  event_type="USER_MESSAGE_RECEIVED",
@@ -227,6 +294,57 @@ class TestSpan:
227
294
  )
228
295
  assert span.summary == "You are a helpful assistant"
229
296
 
297
+ def test_summary_unwraps_text_single_quoted(self):
298
+ """`text: 'hello'` wrapper should be stripped from response."""
299
+ span = Span(
300
+ event_type="LLM_RESPONSE",
301
+ agent="agent",
302
+ timestamp=datetime.now(timezone.utc),
303
+ content={"response": "text: 'hello world'"},
304
+ )
305
+ assert span.summary == "hello world"
306
+
307
+ def test_summary_unwraps_text_double_quoted(self):
308
+ """`text: \"hello\"` wrapper should be stripped too."""
309
+ span = Span(
310
+ event_type="LLM_RESPONSE",
311
+ agent="agent",
312
+ timestamp=datetime.now(timezone.utc),
313
+ content={"response": 'text: "hello world"'},
314
+ )
315
+ assert span.summary == "hello world"
316
+
317
+ def test_summary_unwraps_truncated_text_field(self):
318
+ """Truncated `text: 'abc...` (no closing quote) strips opening quote only."""
319
+ span = Span(
320
+ event_type="LLM_RESPONSE",
321
+ agent="agent",
322
+ timestamp=datetime.now(timezone.utc),
323
+ content={"response": "text: 'I found three Priyas"},
324
+ )
325
+ assert span.summary == "I found three Priyas"
326
+
327
+ def test_summary_leaves_plain_text_alone(self):
328
+ """A response without the wrapper must be returned unchanged."""
329
+ span = Span(
330
+ event_type="LLM_RESPONSE",
331
+ agent="agent",
332
+ timestamp=datetime.now(timezone.utc),
333
+ content={"response": "Booking confirmed for Priya Patel."},
334
+ )
335
+ assert span.summary == "Booking confirmed for Priya Patel."
336
+
337
+ def test_summary_leaves_non_wrapper_text_prefix_alone(self):
338
+ """`text:` without a following space-quoted value is not our wrapper."""
339
+ span = Span(
340
+ event_type="LLM_RESPONSE",
341
+ agent="agent",
342
+ timestamp=datetime.now(timezone.utc),
343
+ content={"response": "text:the-tool-id-is-x"},
344
+ )
345
+ # No leading `text: ` (with space), so the unwrapper leaves it alone.
346
+ assert span.summary == "text:the-tool-id-is-x"
347
+
230
348
 
231
349
  class TestTrace:
232
350
  """Tests for Trace class."""
@@ -300,6 +418,116 @@ class TestTrace:
300
418
  assert "USER_MESSAGE_RECEIVED" in output
301
419
  assert "TOOL_STARTING" in output
302
420
 
421
+ def test_render_color_default_off(self):
422
+ """Default render() must not emit ANSI escape codes."""
423
+ ts = datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
424
+ spans = [
425
+ Span(
426
+ event_type="TOOL_ERROR",
427
+ agent="agent",
428
+ timestamp=ts,
429
+ content={"tool": "search"},
430
+ error_message="boom",
431
+ status="ERROR",
432
+ span_id="s1",
433
+ ),
434
+ ]
435
+ trace = Trace(trace_id="t1", session_id="sess-1", spans=spans)
436
+ output = trace.render()
437
+ assert "\x1b[" not in output
438
+
439
+ def test_render_color_true_wraps_error_icon(self):
440
+ """With color=True, error spans get red ANSI wrap on the cross icon."""
441
+ ts = datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
442
+ spans = [
443
+ Span(
444
+ event_type="TOOL_ERROR",
445
+ agent="agent",
446
+ timestamp=ts,
447
+ content={"tool": "search"},
448
+ error_message="boom",
449
+ status="ERROR",
450
+ span_id="s1",
451
+ ),
452
+ ]
453
+ trace = Trace(trace_id="t1", session_id="sess-1", spans=spans)
454
+ output = trace.render(color=True)
455
+ assert "\x1b[31m\u2717\x1b[0m" in output
456
+
457
+ def test_render_color_true_wraps_subtree_warning(self):
458
+ """Parent of an error child gets yellow warning icon wrap."""
459
+ ts = datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
460
+ spans = [
461
+ Span(
462
+ event_type="AGENT_STARTING",
463
+ agent="agent",
464
+ timestamp=ts,
465
+ span_id="s1",
466
+ ),
467
+ Span(
468
+ event_type="TOOL_ERROR",
469
+ agent="agent",
470
+ timestamp=ts,
471
+ content={"tool": "search"},
472
+ error_message="boom",
473
+ status="ERROR",
474
+ span_id="s2",
475
+ parent_span_id="s1",
476
+ ),
477
+ ]
478
+ trace = Trace(trace_id="t1", session_id="sess-1", spans=spans)
479
+ output = trace.render(color=True)
480
+ assert "\x1b[33m\u26a0\x1b[0m" in output
481
+ assert "\x1b[31m\u2717\x1b[0m" in output
482
+
483
+ def test_render_color_true_no_wrap_on_success(self):
484
+ """Successful spans stay plain even with color=True."""
485
+ ts = datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
486
+ spans = [
487
+ Span(
488
+ event_type="TOOL_COMPLETED",
489
+ agent="agent",
490
+ timestamp=ts,
491
+ content={"tool": "search", "result": "ok"},
492
+ status="OK",
493
+ span_id="s1",
494
+ ),
495
+ ]
496
+ trace = Trace(trace_id="t1", session_id="sess-1", spans=spans)
497
+ output = trace.render(color=True)
498
+ assert "\x1b[" not in output
499
+
500
+ def test_render_handles_unicode_tool_names(self):
501
+ """Non-ASCII tool names must not crash render() and must preserve
502
+ the tree-connector structure on each line. Display-width alignment
503
+ in monospace fonts is a known limitation (tracked separately) —
504
+ this test pins the minimum: no exceptions, connectors emitted."""
505
+ ts = datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
506
+ spans = [
507
+ Span(
508
+ event_type="TOOL_STARTING",
509
+ agent="agent",
510
+ timestamp=ts,
511
+ content={"tool": "搜索联系人"},
512
+ span_id="s1",
513
+ ),
514
+ Span(
515
+ event_type="TOOL_COMPLETED",
516
+ agent="agent",
517
+ timestamp=ts,
518
+ content={"tool": "🔍_fuzzy_search", "result": "ok"},
519
+ span_id="s2",
520
+ parent_span_id="s1",
521
+ latency_ms=50,
522
+ ),
523
+ ]
524
+ trace = Trace(trace_id="t1", session_id="sess-1", spans=spans)
525
+ output = trace.render()
526
+ assert "搜索联系人" in output
527
+ assert "🔍_fuzzy_search" in output
528
+ # tree connectors present on every non-header line
529
+ assert "\u2514\u2500" in output or "\u251c\u2500" in output
530
+
303
531
  def test_render_flat_no_span_ids(self):
304
532
  ts = datetime.now(timezone.utc)
305
533
  spans = [
@@ -363,6 +591,33 @@ class TestTrace:
363
591
  trace = Trace(trace_id="t", session_id="s", spans=spans)
364
592
  assert trace.final_response == "LLM said this"
365
593
 
594
+ def test_final_response_unwraps_text_prefix_from_llm_response(self):
595
+ """text: '...' wrapper must be stripped at the trace-level accessor too."""
596
+ ts = datetime.now(timezone.utc)
597
+ spans = [
598
+ Span(
599
+ event_type="LLM_RESPONSE",
600
+ agent="agent",
601
+ timestamp=ts,
602
+ content={"response": "text: 'I found three people named Priya.'"},
603
+ ),
604
+ ]
605
+ trace = Trace(trace_id="t", session_id="s", spans=spans)
606
+ assert trace.final_response == "I found three people named Priya."
607
+
608
+ def test_final_response_unwraps_text_prefix_from_agent_completed(self):
609
+ ts = datetime.now(timezone.utc)
610
+ spans = [
611
+ Span(
612
+ event_type="AGENT_COMPLETED",
613
+ agent="agent",
614
+ timestamp=ts,
615
+ content={"response": 'text: "Booking confirmed."'},
616
+ ),
617
+ ]
618
+ trace = Trace(trace_id="t", session_id="s", spans=spans)
619
+ assert trace.final_response == "Booking confirmed."
620
+
366
621
  def test_final_response_null_agent_completed(self):
367
622
  """Handles null AGENT_COMPLETED content (ADK plugin behavior)."""
368
623
  ts = datetime.now(timezone.utc)