diff --git a/.changeset/quick-adk-tokens.md b/.changeset/quick-adk-tokens.md new file mode 100644 index 000000000..1f7e23957 --- /dev/null +++ b/.changeset/quick-adk-tokens.md @@ -0,0 +1,5 @@ +--- +"braintrust": patch +--- + +fix(google-adk): Fix token count in google adk diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-auto-hook.span-tree.json b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-auto-hook.span-tree.json index 1e1d4eed4..26004f81a 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-auto-hook.span-tree.json +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-auto-hook.span-tree.json @@ -252,6 +252,68 @@ "operation": "sequential-run", "testRunId": "" } + }, + { + "name": "adk-usage-run-operation", + "children": [ + { + "name": "Google ADK Runner", + "type": "task", + "children": [ + { + "name": "Agent: usage_agent", + "type": "task", + "children": [], + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", + "provider": "google-adk" + }, + "metrics": { + "duration": 0 + } + } + ], + "input": { + "messages": [ + { + "content": "Return the usage fixture.", + "role": "user" + } + ] + }, + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.session_id": "test-session-usage", + "google_adk.user_id": "test-user", + "provider": "google-adk" + }, + "metrics": { + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 + } + } + ], + "metadata": { + "operation": "usage-run", + "testRunId": "" + } } ], "metadata": { diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-auto-hook.span-tree.txt b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-auto-hook.span-tree.txt index 0177fca3e..3e2668fd0 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-auto-hook.span-tree.txt +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-auto-hook.span-tree.txt @@ -141,71 +141,120 @@ span_tree: │ "prompt_tokens": 37, │ "tokens": 53 │ } - └── adk-sequential-run-operation + ├── adk-sequential-run-operation + │ metadata: { + │ "operation": "sequential-run", + │ "testRunId": "" + │ } + │ └── Google ADK Runner [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Hello.", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.session_id": "test-session-sequential", + │ "google_adk.user_id": "test-user", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ └── Agent: sequential_workflow [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "sequential_workflow", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ ├── Agent: greeter [task] + │ │ output: { + │ │ "author": "greeter", + │ │ "content": "Hello.", + │ │ "role": "model" + │ │ } + │ │ metadata: { + │ │ "google_adk.agent_name": "greeter", + │ │ "model": "gemini-2.5-flash-lite", + │ │ "provider": "google-adk" + │ │ } + │ │ metrics: { + │ │ "duration": 0 + │ │ } + │ └── Agent: farewell [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "farewell", + │ "model": "gemini-2.5-flash-lite", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + └── adk-usage-run-operation metadata: { - "operation": "sequential-run", + "operation": "usage-run", "testRunId": "" } └── Google ADK Runner [task] input: { "messages": [ { - "content": "Hello.", + "content": "Return the usage fixture.", "role": "user" } ] } output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.session_id": "test-session-sequential", + "google_adk.session_id": "test-session-usage", "google_adk.user_id": "test-user", "provider": "google-adk" } metrics: { - "duration": 0 + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 } - └── Agent: sequential_workflow [task] + └── Agent: usage_agent [task] output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.agent_name": "sequential_workflow", + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", "provider": "google-adk" } metrics: { "duration": 0 } - ├── Agent: greeter [task] - │ output: { - │ "author": "greeter", - │ "content": "Hello.", - │ "role": "model" - │ } - │ metadata: { - │ "google_adk.agent_name": "greeter", - │ "model": "gemini-2.5-flash-lite", - │ "provider": "google-adk" - │ } - │ metrics: { - │ "duration": 0 - │ } - └── Agent: farewell [task] - output: { - "author": "farewell", - "content": "Goodbye.", - "role": "model" - } - metadata: { - "google_adk.agent_name": "farewell", - "model": "gemini-2.5-flash-lite", - "provider": "google-adk" - } - metrics: { - "duration": 0 - } diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-auto-hook.span-tree.json b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-auto-hook.span-tree.json index 1e1d4eed4..26004f81a 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-auto-hook.span-tree.json +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-auto-hook.span-tree.json @@ -252,6 +252,68 @@ "operation": "sequential-run", "testRunId": "" } + }, + { + "name": "adk-usage-run-operation", + "children": [ + { + "name": "Google ADK Runner", + "type": "task", + "children": [ + { + "name": "Agent: usage_agent", + "type": "task", + "children": [], + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", + "provider": "google-adk" + }, + "metrics": { + "duration": 0 + } + } + ], + "input": { + "messages": [ + { + "content": "Return the usage fixture.", + "role": "user" + } + ] + }, + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.session_id": "test-session-usage", + "google_adk.user_id": "test-user", + "provider": "google-adk" + }, + "metrics": { + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 + } + } + ], + "metadata": { + "operation": "usage-run", + "testRunId": "" + } } ], "metadata": { diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-auto-hook.span-tree.txt b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-auto-hook.span-tree.txt index 0177fca3e..3e2668fd0 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-auto-hook.span-tree.txt +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-auto-hook.span-tree.txt @@ -141,71 +141,120 @@ span_tree: │ "prompt_tokens": 37, │ "tokens": 53 │ } - └── adk-sequential-run-operation + ├── adk-sequential-run-operation + │ metadata: { + │ "operation": "sequential-run", + │ "testRunId": "" + │ } + │ └── Google ADK Runner [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Hello.", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.session_id": "test-session-sequential", + │ "google_adk.user_id": "test-user", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ └── Agent: sequential_workflow [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "sequential_workflow", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ ├── Agent: greeter [task] + │ │ output: { + │ │ "author": "greeter", + │ │ "content": "Hello.", + │ │ "role": "model" + │ │ } + │ │ metadata: { + │ │ "google_adk.agent_name": "greeter", + │ │ "model": "gemini-2.5-flash-lite", + │ │ "provider": "google-adk" + │ │ } + │ │ metrics: { + │ │ "duration": 0 + │ │ } + │ └── Agent: farewell [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "farewell", + │ "model": "gemini-2.5-flash-lite", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + └── adk-usage-run-operation metadata: { - "operation": "sequential-run", + "operation": "usage-run", "testRunId": "" } └── Google ADK Runner [task] input: { "messages": [ { - "content": "Hello.", + "content": "Return the usage fixture.", "role": "user" } ] } output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.session_id": "test-session-sequential", + "google_adk.session_id": "test-session-usage", "google_adk.user_id": "test-user", "provider": "google-adk" } metrics: { - "duration": 0 + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 } - └── Agent: sequential_workflow [task] + └── Agent: usage_agent [task] output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.agent_name": "sequential_workflow", + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", "provider": "google-adk" } metrics: { "duration": 0 } - ├── Agent: greeter [task] - │ output: { - │ "author": "greeter", - │ "content": "Hello.", - │ "role": "model" - │ } - │ metadata: { - │ "google_adk.agent_name": "greeter", - │ "model": "gemini-2.5-flash-lite", - │ "provider": "google-adk" - │ } - │ metrics: { - │ "duration": 0 - │ } - └── Agent: farewell [task] - output: { - "author": "farewell", - "content": "Goodbye.", - "role": "model" - } - metadata: { - "google_adk.agent_name": "farewell", - "model": "gemini-2.5-flash-lite", - "provider": "google-adk" - } - metrics: { - "duration": 0 - } diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-wrapped.span-tree.json b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-wrapped.span-tree.json index 82b9c464e..1cb9c85c3 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-wrapped.span-tree.json +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-wrapped.span-tree.json @@ -172,6 +172,68 @@ "operation": "sequential-run", "testRunId": "" } + }, + { + "name": "adk-usage-run-operation", + "children": [ + { + "name": "Google ADK Runner", + "type": "task", + "children": [ + { + "name": "Agent: usage_agent", + "type": "task", + "children": [], + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", + "provider": "google-adk" + }, + "metrics": { + "duration": 0 + } + } + ], + "input": { + "messages": [ + { + "content": "Return the usage fixture.", + "role": "user" + } + ] + }, + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.session_id": "test-session-usage", + "google_adk.user_id": "test-user", + "provider": "google-adk" + }, + "metrics": { + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 + } + } + ], + "metadata": { + "operation": "usage-run", + "testRunId": "" + } } ], "metadata": { diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-wrapped.span-tree.txt b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-wrapped.span-tree.txt index 66f2073bf..dcb770203 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-wrapped.span-tree.txt +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-latest-wrapped.span-tree.txt @@ -65,71 +65,120 @@ span_tree: │ metrics: { │ "duration": 0 │ } - └── adk-sequential-run-operation + ├── adk-sequential-run-operation + │ metadata: { + │ "operation": "sequential-run", + │ "testRunId": "" + │ } + │ └── Google ADK Runner [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Hello.", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.session_id": "test-session-sequential", + │ "google_adk.user_id": "test-user", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ └── Agent: sequential_workflow [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "sequential_workflow", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ ├── Agent: greeter [task] + │ │ output: { + │ │ "author": "greeter", + │ │ "content": "Hello.", + │ │ "role": "model" + │ │ } + │ │ metadata: { + │ │ "google_adk.agent_name": "greeter", + │ │ "model": "gemini-2.5-flash-lite", + │ │ "provider": "google-adk" + │ │ } + │ │ metrics: { + │ │ "duration": 0 + │ │ } + │ └── Agent: farewell [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "farewell", + │ "model": "gemini-2.5-flash-lite", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + └── adk-usage-run-operation metadata: { - "operation": "sequential-run", + "operation": "usage-run", "testRunId": "" } └── Google ADK Runner [task] input: { "messages": [ { - "content": "Hello.", + "content": "Return the usage fixture.", "role": "user" } ] } output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.session_id": "test-session-sequential", + "google_adk.session_id": "test-session-usage", "google_adk.user_id": "test-user", "provider": "google-adk" } metrics: { - "duration": 0 + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 } - └── Agent: sequential_workflow [task] + └── Agent: usage_agent [task] output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.agent_name": "sequential_workflow", + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", "provider": "google-adk" } metrics: { "duration": 0 } - ├── Agent: greeter [task] - │ output: { - │ "author": "greeter", - │ "content": "Hello.", - │ "role": "model" - │ } - │ metadata: { - │ "google_adk.agent_name": "greeter", - │ "model": "gemini-2.5-flash-lite", - │ "provider": "google-adk" - │ } - │ metrics: { - │ "duration": 0 - │ } - └── Agent: farewell [task] - output: { - "author": "farewell", - "content": "Goodbye.", - "role": "model" - } - metadata: { - "google_adk.agent_name": "farewell", - "model": "gemini-2.5-flash-lite", - "provider": "google-adk" - } - metrics: { - "duration": 0 - } diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-wrapped.span-tree.json b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-wrapped.span-tree.json index 82b9c464e..1cb9c85c3 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-wrapped.span-tree.json +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-wrapped.span-tree.json @@ -172,6 +172,68 @@ "operation": "sequential-run", "testRunId": "" } + }, + { + "name": "adk-usage-run-operation", + "children": [ + { + "name": "Google ADK Runner", + "type": "task", + "children": [ + { + "name": "Agent: usage_agent", + "type": "task", + "children": [], + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", + "provider": "google-adk" + }, + "metrics": { + "duration": 0 + } + } + ], + "input": { + "messages": [ + { + "content": "Return the usage fixture.", + "role": "user" + } + ] + }, + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.session_id": "test-session-usage", + "google_adk.user_id": "test-user", + "provider": "google-adk" + }, + "metrics": { + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 + } + } + ], + "metadata": { + "operation": "usage-run", + "testRunId": "" + } } ], "metadata": { diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-wrapped.span-tree.txt b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-wrapped.span-tree.txt index 66f2073bf..dcb770203 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-wrapped.span-tree.txt +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v0-wrapped.span-tree.txt @@ -65,71 +65,120 @@ span_tree: │ metrics: { │ "duration": 0 │ } - └── adk-sequential-run-operation + ├── adk-sequential-run-operation + │ metadata: { + │ "operation": "sequential-run", + │ "testRunId": "" + │ } + │ └── Google ADK Runner [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Hello.", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.session_id": "test-session-sequential", + │ "google_adk.user_id": "test-user", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ └── Agent: sequential_workflow [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "sequential_workflow", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ ├── Agent: greeter [task] + │ │ output: { + │ │ "author": "greeter", + │ │ "content": "Hello.", + │ │ "role": "model" + │ │ } + │ │ metadata: { + │ │ "google_adk.agent_name": "greeter", + │ │ "model": "gemini-2.5-flash-lite", + │ │ "provider": "google-adk" + │ │ } + │ │ metrics: { + │ │ "duration": 0 + │ │ } + │ └── Agent: farewell [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "farewell", + │ "model": "gemini-2.5-flash-lite", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + └── adk-usage-run-operation metadata: { - "operation": "sequential-run", + "operation": "usage-run", "testRunId": "" } └── Google ADK Runner [task] input: { "messages": [ { - "content": "Hello.", + "content": "Return the usage fixture.", "role": "user" } ] } output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.session_id": "test-session-sequential", + "google_adk.session_id": "test-session-usage", "google_adk.user_id": "test-user", "provider": "google-adk" } metrics: { - "duration": 0 + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 } - └── Agent: sequential_workflow [task] + └── Agent: usage_agent [task] output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.agent_name": "sequential_workflow", + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", "provider": "google-adk" } metrics: { "duration": 0 } - ├── Agent: greeter [task] - │ output: { - │ "author": "greeter", - │ "content": "Hello.", - │ "role": "model" - │ } - │ metadata: { - │ "google_adk.agent_name": "greeter", - │ "model": "gemini-2.5-flash-lite", - │ "provider": "google-adk" - │ } - │ metrics: { - │ "duration": 0 - │ } - └── Agent: farewell [task] - output: { - "author": "farewell", - "content": "Goodbye.", - "role": "model" - } - metadata: { - "google_adk.agent_name": "farewell", - "model": "gemini-2.5-flash-lite", - "provider": "google-adk" - } - metrics: { - "duration": 0 - } diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-auto-hook.span-tree.json b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-auto-hook.span-tree.json index 1e1d4eed4..26004f81a 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-auto-hook.span-tree.json +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-auto-hook.span-tree.json @@ -252,6 +252,68 @@ "operation": "sequential-run", "testRunId": "" } + }, + { + "name": "adk-usage-run-operation", + "children": [ + { + "name": "Google ADK Runner", + "type": "task", + "children": [ + { + "name": "Agent: usage_agent", + "type": "task", + "children": [], + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", + "provider": "google-adk" + }, + "metrics": { + "duration": 0 + } + } + ], + "input": { + "messages": [ + { + "content": "Return the usage fixture.", + "role": "user" + } + ] + }, + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.session_id": "test-session-usage", + "google_adk.user_id": "test-user", + "provider": "google-adk" + }, + "metrics": { + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 + } + } + ], + "metadata": { + "operation": "usage-run", + "testRunId": "" + } } ], "metadata": { diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-auto-hook.span-tree.txt b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-auto-hook.span-tree.txt index 0177fca3e..3e2668fd0 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-auto-hook.span-tree.txt +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-auto-hook.span-tree.txt @@ -141,71 +141,120 @@ span_tree: │ "prompt_tokens": 37, │ "tokens": 53 │ } - └── adk-sequential-run-operation + ├── adk-sequential-run-operation + │ metadata: { + │ "operation": "sequential-run", + │ "testRunId": "" + │ } + │ └── Google ADK Runner [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Hello.", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.session_id": "test-session-sequential", + │ "google_adk.user_id": "test-user", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ └── Agent: sequential_workflow [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "sequential_workflow", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ ├── Agent: greeter [task] + │ │ output: { + │ │ "author": "greeter", + │ │ "content": "Hello.", + │ │ "role": "model" + │ │ } + │ │ metadata: { + │ │ "google_adk.agent_name": "greeter", + │ │ "model": "gemini-2.5-flash-lite", + │ │ "provider": "google-adk" + │ │ } + │ │ metrics: { + │ │ "duration": 0 + │ │ } + │ └── Agent: farewell [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "farewell", + │ "model": "gemini-2.5-flash-lite", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + └── adk-usage-run-operation metadata: { - "operation": "sequential-run", + "operation": "usage-run", "testRunId": "" } └── Google ADK Runner [task] input: { "messages": [ { - "content": "Hello.", + "content": "Return the usage fixture.", "role": "user" } ] } output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.session_id": "test-session-sequential", + "google_adk.session_id": "test-session-usage", "google_adk.user_id": "test-user", "provider": "google-adk" } metrics: { - "duration": 0 + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 } - └── Agent: sequential_workflow [task] + └── Agent: usage_agent [task] output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.agent_name": "sequential_workflow", + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", "provider": "google-adk" } metrics: { "duration": 0 } - ├── Agent: greeter [task] - │ output: { - │ "author": "greeter", - │ "content": "Hello.", - │ "role": "model" - │ } - │ metadata: { - │ "google_adk.agent_name": "greeter", - │ "model": "gemini-2.5-flash-lite", - │ "provider": "google-adk" - │ } - │ metrics: { - │ "duration": 0 - │ } - └── Agent: farewell [task] - output: { - "author": "farewell", - "content": "Goodbye.", - "role": "model" - } - metadata: { - "google_adk.agent_name": "farewell", - "model": "gemini-2.5-flash-lite", - "provider": "google-adk" - } - metrics: { - "duration": 0 - } diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-auto-hook.span-tree.json b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-auto-hook.span-tree.json index 1e1d4eed4..26004f81a 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-auto-hook.span-tree.json +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-auto-hook.span-tree.json @@ -252,6 +252,68 @@ "operation": "sequential-run", "testRunId": "" } + }, + { + "name": "adk-usage-run-operation", + "children": [ + { + "name": "Google ADK Runner", + "type": "task", + "children": [ + { + "name": "Agent: usage_agent", + "type": "task", + "children": [], + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", + "provider": "google-adk" + }, + "metrics": { + "duration": 0 + } + } + ], + "input": { + "messages": [ + { + "content": "Return the usage fixture.", + "role": "user" + } + ] + }, + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.session_id": "test-session-usage", + "google_adk.user_id": "test-user", + "provider": "google-adk" + }, + "metrics": { + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 + } + } + ], + "metadata": { + "operation": "usage-run", + "testRunId": "" + } } ], "metadata": { diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-auto-hook.span-tree.txt b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-auto-hook.span-tree.txt index 0177fca3e..3e2668fd0 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-auto-hook.span-tree.txt +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-auto-hook.span-tree.txt @@ -141,71 +141,120 @@ span_tree: │ "prompt_tokens": 37, │ "tokens": 53 │ } - └── adk-sequential-run-operation + ├── adk-sequential-run-operation + │ metadata: { + │ "operation": "sequential-run", + │ "testRunId": "" + │ } + │ └── Google ADK Runner [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Hello.", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.session_id": "test-session-sequential", + │ "google_adk.user_id": "test-user", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ └── Agent: sequential_workflow [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "sequential_workflow", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ ├── Agent: greeter [task] + │ │ output: { + │ │ "author": "greeter", + │ │ "content": "Hello.", + │ │ "role": "model" + │ │ } + │ │ metadata: { + │ │ "google_adk.agent_name": "greeter", + │ │ "model": "gemini-2.5-flash-lite", + │ │ "provider": "google-adk" + │ │ } + │ │ metrics: { + │ │ "duration": 0 + │ │ } + │ └── Agent: farewell [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "farewell", + │ "model": "gemini-2.5-flash-lite", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + └── adk-usage-run-operation metadata: { - "operation": "sequential-run", + "operation": "usage-run", "testRunId": "" } └── Google ADK Runner [task] input: { "messages": [ { - "content": "Hello.", + "content": "Return the usage fixture.", "role": "user" } ] } output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.session_id": "test-session-sequential", + "google_adk.session_id": "test-session-usage", "google_adk.user_id": "test-user", "provider": "google-adk" } metrics: { - "duration": 0 + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 } - └── Agent: sequential_workflow [task] + └── Agent: usage_agent [task] output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.agent_name": "sequential_workflow", + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", "provider": "google-adk" } metrics: { "duration": 0 } - ├── Agent: greeter [task] - │ output: { - │ "author": "greeter", - │ "content": "Hello.", - │ "role": "model" - │ } - │ metadata: { - │ "google_adk.agent_name": "greeter", - │ "model": "gemini-2.5-flash-lite", - │ "provider": "google-adk" - │ } - │ metrics: { - │ "duration": 0 - │ } - └── Agent: farewell [task] - output: { - "author": "farewell", - "content": "Goodbye.", - "role": "model" - } - metadata: { - "google_adk.agent_name": "farewell", - "model": "gemini-2.5-flash-lite", - "provider": "google-adk" - } - metrics: { - "duration": 0 - } diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-wrapped.span-tree.json b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-wrapped.span-tree.json index 82b9c464e..1cb9c85c3 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-wrapped.span-tree.json +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-wrapped.span-tree.json @@ -172,6 +172,68 @@ "operation": "sequential-run", "testRunId": "" } + }, + { + "name": "adk-usage-run-operation", + "children": [ + { + "name": "Google ADK Runner", + "type": "task", + "children": [ + { + "name": "Agent: usage_agent", + "type": "task", + "children": [], + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", + "provider": "google-adk" + }, + "metrics": { + "duration": 0 + } + } + ], + "input": { + "messages": [ + { + "content": "Return the usage fixture.", + "role": "user" + } + ] + }, + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.session_id": "test-session-usage", + "google_adk.user_id": "test-user", + "provider": "google-adk" + }, + "metrics": { + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 + } + } + ], + "metadata": { + "operation": "usage-run", + "testRunId": "" + } } ], "metadata": { diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-wrapped.span-tree.txt b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-wrapped.span-tree.txt index 66f2073bf..dcb770203 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-wrapped.span-tree.txt +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-latest-wrapped.span-tree.txt @@ -65,71 +65,120 @@ span_tree: │ metrics: { │ "duration": 0 │ } - └── adk-sequential-run-operation + ├── adk-sequential-run-operation + │ metadata: { + │ "operation": "sequential-run", + │ "testRunId": "" + │ } + │ └── Google ADK Runner [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Hello.", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.session_id": "test-session-sequential", + │ "google_adk.user_id": "test-user", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ └── Agent: sequential_workflow [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "sequential_workflow", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ ├── Agent: greeter [task] + │ │ output: { + │ │ "author": "greeter", + │ │ "content": "Hello.", + │ │ "role": "model" + │ │ } + │ │ metadata: { + │ │ "google_adk.agent_name": "greeter", + │ │ "model": "gemini-2.5-flash-lite", + │ │ "provider": "google-adk" + │ │ } + │ │ metrics: { + │ │ "duration": 0 + │ │ } + │ └── Agent: farewell [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "farewell", + │ "model": "gemini-2.5-flash-lite", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + └── adk-usage-run-operation metadata: { - "operation": "sequential-run", + "operation": "usage-run", "testRunId": "" } └── Google ADK Runner [task] input: { "messages": [ { - "content": "Hello.", + "content": "Return the usage fixture.", "role": "user" } ] } output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.session_id": "test-session-sequential", + "google_adk.session_id": "test-session-usage", "google_adk.user_id": "test-user", "provider": "google-adk" } metrics: { - "duration": 0 + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 } - └── Agent: sequential_workflow [task] + └── Agent: usage_agent [task] output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.agent_name": "sequential_workflow", + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", "provider": "google-adk" } metrics: { "duration": 0 } - ├── Agent: greeter [task] - │ output: { - │ "author": "greeter", - │ "content": "Hello.", - │ "role": "model" - │ } - │ metadata: { - │ "google_adk.agent_name": "greeter", - │ "model": "gemini-2.5-flash-lite", - │ "provider": "google-adk" - │ } - │ metrics: { - │ "duration": 0 - │ } - └── Agent: farewell [task] - output: { - "author": "farewell", - "content": "Goodbye.", - "role": "model" - } - metadata: { - "google_adk.agent_name": "farewell", - "model": "gemini-2.5-flash-lite", - "provider": "google-adk" - } - metrics: { - "duration": 0 - } diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-wrapped.span-tree.json b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-wrapped.span-tree.json index 82b9c464e..1cb9c85c3 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-wrapped.span-tree.json +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-wrapped.span-tree.json @@ -172,6 +172,68 @@ "operation": "sequential-run", "testRunId": "" } + }, + { + "name": "adk-usage-run-operation", + "children": [ + { + "name": "Google ADK Runner", + "type": "task", + "children": [ + { + "name": "Agent: usage_agent", + "type": "task", + "children": [], + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", + "provider": "google-adk" + }, + "metrics": { + "duration": 0 + } + } + ], + "input": { + "messages": [ + { + "content": "Return the usage fixture.", + "role": "user" + } + ] + }, + "output": { + "author": "usage_agent", + "content": "Usage response.", + "role": "model" + }, + "metadata": { + "google_adk.session_id": "test-session-usage", + "google_adk.user_id": "test-user", + "provider": "google-adk" + }, + "metrics": { + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 + } + } + ], + "metadata": { + "operation": "usage-run", + "testRunId": "" + } } ], "metadata": { diff --git a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-wrapped.span-tree.txt b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-wrapped.span-tree.txt index 66f2073bf..dcb770203 100644 --- a/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-wrapped.span-tree.txt +++ b/e2e/scenarios/google-adk-instrumentation/__snapshots__/google-adk-v1-wrapped.span-tree.txt @@ -65,71 +65,120 @@ span_tree: │ metrics: { │ "duration": 0 │ } - └── adk-sequential-run-operation + ├── adk-sequential-run-operation + │ metadata: { + │ "operation": "sequential-run", + │ "testRunId": "" + │ } + │ └── Google ADK Runner [task] + │ input: { + │ "messages": [ + │ { + │ "content": "Hello.", + │ "role": "user" + │ } + │ ] + │ } + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.session_id": "test-session-sequential", + │ "google_adk.user_id": "test-user", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ └── Agent: sequential_workflow [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "sequential_workflow", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + │ ├── Agent: greeter [task] + │ │ output: { + │ │ "author": "greeter", + │ │ "content": "Hello.", + │ │ "role": "model" + │ │ } + │ │ metadata: { + │ │ "google_adk.agent_name": "greeter", + │ │ "model": "gemini-2.5-flash-lite", + │ │ "provider": "google-adk" + │ │ } + │ │ metrics: { + │ │ "duration": 0 + │ │ } + │ └── Agent: farewell [task] + │ output: { + │ "author": "farewell", + │ "content": "Goodbye.", + │ "role": "model" + │ } + │ metadata: { + │ "google_adk.agent_name": "farewell", + │ "model": "gemini-2.5-flash-lite", + │ "provider": "google-adk" + │ } + │ metrics: { + │ "duration": 0 + │ } + └── adk-usage-run-operation metadata: { - "operation": "sequential-run", + "operation": "usage-run", "testRunId": "" } └── Google ADK Runner [task] input: { "messages": [ { - "content": "Hello.", + "content": "Return the usage fixture.", "role": "user" } ] } output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.session_id": "test-session-sequential", + "google_adk.session_id": "test-session-usage", "google_adk.user_id": "test-user", "provider": "google-adk" } metrics: { - "duration": 0 + "completion_audio_tokens": 2, + "completion_image_tokens": 3, + "completion_reasoning_tokens": 5, + "completion_tokens": 8, + "duration": 0, + "prompt_audio_tokens": 1, + "prompt_cached_tokens": 4, + "prompt_tokens": 12, + "tokens": 20 } - └── Agent: sequential_workflow [task] + └── Agent: usage_agent [task] output: { - "author": "farewell", - "content": "Goodbye.", + "author": "usage_agent", + "content": "Usage response.", "role": "model" } metadata: { - "google_adk.agent_name": "sequential_workflow", + "google_adk.agent_name": "usage_agent", + "model": "gemini-2.5-flash-lite", "provider": "google-adk" } metrics: { "duration": 0 } - ├── Agent: greeter [task] - │ output: { - │ "author": "greeter", - │ "content": "Hello.", - │ "role": "model" - │ } - │ metadata: { - │ "google_adk.agent_name": "greeter", - │ "model": "gemini-2.5-flash-lite", - │ "provider": "google-adk" - │ } - │ metrics: { - │ "duration": 0 - │ } - └── Agent: farewell [task] - output: { - "author": "farewell", - "content": "Goodbye.", - "role": "model" - } - metadata: { - "google_adk.agent_name": "farewell", - "model": "gemini-2.5-flash-lite", - "provider": "google-adk" - } - metrics: { - "duration": 0 - } diff --git a/e2e/scenarios/google-adk-instrumentation/assertions.ts b/e2e/scenarios/google-adk-instrumentation/assertions.ts index c8b4c22c8..c2e484b3e 100644 --- a/e2e/scenarios/google-adk-instrumentation/assertions.ts +++ b/e2e/scenarios/google-adk-instrumentation/assertions.ts @@ -13,7 +13,11 @@ import { } from "../../helpers/span-tree"; import { findLatestSpan } from "../../helpers/trace-selectors"; -import { ROOT_NAME, SCENARIO_NAME } from "./scenario.impl.mjs"; +import { + EXPECTED_GOOGLE_ADK_USAGE_METRICS, + ROOT_NAME, + SCENARIO_NAME, +} from "./scenario.impl.mjs"; type RunGoogleADKScenario = (harness: { runNodeScenarioDir: (options: { @@ -328,6 +332,21 @@ export function defineGoogleADKInstrumentationAssertions(options: { expect(llmSpan?.metrics).toBeDefined(); }); + test("records normalized ADK usage metrics", testConfig, () => { + const usageRunnerSpan = events.find( + (event) => + event.span.name === "Google ADK Runner" && + (event.row.metadata as Record | undefined)?.[ + "google_adk.session_id" + ] === "test-session-usage", + ); + + expect(usageRunnerSpan).toBeDefined(); + expect(usageRunnerSpan?.metrics).toMatchObject( + EXPECTED_GOOGLE_ADK_USAGE_METRICS, + ); + }); + test("matches the shared span tree snapshot", testConfig, async () => { await matchSpanTreeSnapshot(events, spanSnapshotPath); }); diff --git a/e2e/scenarios/google-adk-instrumentation/scenario.impl.mjs b/e2e/scenarios/google-adk-instrumentation/scenario.impl.mjs index b547faad3..bfd4f0361 100644 --- a/e2e/scenarios/google-adk-instrumentation/scenario.impl.mjs +++ b/e2e/scenarios/google-adk-instrumentation/scenario.impl.mjs @@ -8,6 +8,16 @@ import { const GOOGLE_MODEL = "gemini-2.5-flash-lite"; const ROOT_NAME = "google-adk-instrumentation-root"; const SCENARIO_NAME = "google-adk-instrumentation"; +const EXPECTED_GOOGLE_ADK_USAGE_METRICS = { + completion_audio_tokens: 2, + completion_image_tokens: 3, + completion_reasoning_tokens: 5, + completion_tokens: 8, + prompt_audio_tokens: 1, + prompt_cached_tokens: 4, + prompt_tokens: 12, + tokens: 20, +}; async function runGoogleADKInstrumentationScenario(adk, options = {}) { const decoratedADK = options.decorateSDK ? options.decorateSDK(adk) : adk; @@ -75,6 +85,42 @@ async function runGoogleADKInstrumentationScenario(adk, options = {}) { userId, }); + const usageAgent = new LlmAgent({ + name: "usage_agent", + model: agentModel, + instruction: "Return the deterministic usage response.", + beforeModelCallback: () => ({ + content: { + role: "model", + parts: [{ text: "Usage response." }], + }, + usageMetadata: { + cachedContentTokenCount: 4, + candidatesTokenCount: 3, + candidatesTokensDetails: [ + { modality: "AUDIO", tokenCount: 2 }, + { modality: "IMAGE", tokenCount: 3 }, + ], + promptTokenCount: 10, + promptTokensDetails: [{ modality: "AUDIO", tokenCount: 1 }], + thoughtsTokenCount: 5, + toolUsePromptTokenCount: 2, + totalTokenCount: 20, + }, + }), + }); + const usageRunner = new InMemoryRunner({ + agent: usageAgent, + appName: "e2e-test-usage-app", + }); + const usageSessionId = "test-session-usage"; + + await usageRunner.sessionService.createSession({ + appName: usageRunner.appName, + sessionId: usageSessionId, + userId, + }); + const greeter = new LlmAgent({ name: "greeter", model: agentModel, @@ -146,6 +192,19 @@ async function runGoogleADKInstrumentationScenario(adk, options = {}) { } }, ); + + await runOperation("adk-usage-run-operation", "usage-run", async () => { + await collectAsync( + usageRunner.runAsync({ + userId, + sessionId: usageSessionId, + newMessage: { + role: "user", + parts: [{ text: "Return the usage fixture." }], + }, + }), + ); + }); }, metadata: { scenario: SCENARIO_NAME, @@ -165,4 +224,9 @@ export async function runAutoGoogleADKInstrumentation(adk) { await runGoogleADKInstrumentationScenario(adk); } -export { GOOGLE_MODEL, ROOT_NAME, SCENARIO_NAME }; +export { + EXPECTED_GOOGLE_ADK_USAGE_METRICS, + GOOGLE_MODEL, + ROOT_NAME, + SCENARIO_NAME, +}; diff --git a/js/src/instrumentation/plugins/google-adk-plugin.test.ts b/js/src/instrumentation/plugins/google-adk-plugin.test.ts index cca8c650e..073af75f4 100644 --- a/js/src/instrumentation/plugins/google-adk-plugin.test.ts +++ b/js/src/instrumentation/plugins/google-adk-plugin.test.ts @@ -32,6 +32,7 @@ vi.mock("../../logger", () => ({ _internalGetGlobalState: (...args: any[]) => (mockInternalGetGlobalState as any)(...args), BRAINTRUST_CURRENT_SPAN_STORE: MOCK_CURRENT_SPAN_STORE_SYMBOL, + withCurrent: (_span: any, callback: () => unknown) => callback(), Attachment: class MockAttachment { reference: any; constructor(params: any) { @@ -259,6 +260,189 @@ describe("GoogleADKPlugin", () => { expect(mockStartSpan).toHaveBeenCalledTimes(1); }); + + it.each([ + { + name: "candidate-only usage", + usageMetadata: [{ candidatesTokenCount: 5 }], + expectedMetrics: { completion_tokens: 5 }, + absentMetrics: [ + "prompt_tokens", + "completion_reasoning_tokens", + "tokens", + ], + }, + { + name: "thought-only usage", + usageMetadata: [{ thoughtsTokenCount: 7 }], + expectedMetrics: { + completion_tokens: 7, + completion_reasoning_tokens: 7, + }, + absentMetrics: ["prompt_tokens", "tokens"], + }, + { + name: "tool-use-only usage", + usageMetadata: [{ toolUsePromptTokenCount: 11 }], + expectedMetrics: { prompt_tokens: 11 }, + absentMetrics: [ + "completion_tokens", + "completion_reasoning_tokens", + "tokens", + ], + }, + { + name: "combined usage across events", + usageMetadata: [ + { + promptTokenCount: 10, + toolUsePromptTokenCount: 2, + candidatesTokenCount: 2, + thoughtsTokenCount: 1, + cachedContentTokenCount: 4, + totalTokenCount: 15, + }, + { + promptTokenCount: 5, + toolUsePromptTokenCount: 1, + candidatesTokenCount: 3, + thoughtsTokenCount: 2, + cachedContentTokenCount: 0, + totalTokenCount: 11, + }, + ], + expectedMetrics: { + prompt_tokens: 18, + completion_tokens: 8, + completion_reasoning_tokens: 3, + prompt_cached_tokens: 4, + tokens: 26, + }, + absentMetrics: [], + }, + { + name: "modality-detail usage across events", + usageMetadata: [ + { + promptTokensDetails: [ + { modality: "AUDIO", tokenCount: 2 }, + { modality: "TEXT", tokenCount: 10 }, + ], + candidatesTokensDetails: [ + { modality: "AUDIO", tokenCount: 3 }, + { modality: "IMAGE", tokenCount: 4 }, + { modality: "TEXT", tokenCount: 5 }, + ], + }, + { + promptTokensDetails: [{ modality: "AUDIO", tokenCount: 0 }], + candidatesTokensDetails: [ + { modality: "AUDIO", tokenCount: 2 }, + { modality: "IMAGE", tokenCount: 1 }, + ], + }, + ], + expectedMetrics: { + prompt_audio_tokens: 2, + completion_audio_tokens: 5, + completion_image_tokens: 5, + }, + absentMetrics: ["prompt_tokens", "completion_tokens", "tokens"], + }, + { + name: "missing usage", + usageMetadata: [{}], + expectedMetrics: {}, + absentMetrics: [ + "completion_audio_tokens", + "completion_image_tokens", + "completion_reasoning_tokens", + "completion_tokens", + "prompt_audio_tokens", + "prompt_cached_tokens", + "prompt_tokens", + "tokens", + ], + }, + ])( + "normalizes $name", + async ({ usageMetadata, expectedMetrics, absentMetrics }) => { + plugin.enable(); + + const handlers = subscribeSpy.mock.calls[0][0]; + const event: any = { + arguments: [{ userId: "user-123", sessionId: "session-456" }], + }; + + handlers.start(event); + const span = mockStartSpan.mock.results.at(-1)?.value as { + log: ReturnType; + }; + event.result = (async function* () { + for (const usage of usageMetadata) { + yield { usageMetadata: usage }; + } + })(); + handlers.end(event); + + for await (const _event of event.result) { + // Consume the runner stream so the span is finalized. + } + + const metrics = span.log.mock.calls.at(-1)?.[0].metrics; + expect(metrics).toMatchObject(expectedMetrics); + for (const metric of absentMetrics) { + expect(metrics).not.toHaveProperty(metric); + } + }, + ); + + it("preserves explicitly reported zero usage", async () => { + plugin.enable(); + + const handlers = subscribeSpy.mock.calls[0][0]; + const event: any = { + arguments: [{ userId: "user-123", sessionId: "session-456" }], + }; + + handlers.start(event); + const span = mockStartSpan.mock.results.at(-1)?.value as { + log: ReturnType; + }; + event.result = (async function* () { + yield { + usageMetadata: { + cachedContentTokenCount: 0, + candidatesTokenCount: 0, + candidatesTokensDetails: [ + { modality: "AUDIO", tokenCount: 0 }, + { modality: "IMAGE", tokenCount: 0 }, + ], + promptTokenCount: 0, + promptTokensDetails: [{ modality: "AUDIO", tokenCount: 0 }], + thoughtsTokenCount: 0, + toolUsePromptTokenCount: 0, + totalTokenCount: 0, + }, + }; + })(); + handlers.end(event); + + for await (const _event of event.result) { + // Consume the runner stream so the span is finalized. + } + + expect(span.log.mock.calls.at(-1)?.[0].metrics).toMatchObject({ + completion_audio_tokens: 0, + completion_image_tokens: 0, + completion_reasoning_tokens: 0, + completion_tokens: 0, + prompt_audio_tokens: 0, + prompt_cached_tokens: 0, + prompt_tokens: 0, + tokens: 0, + }); + }); }); describe("agent.runAsync channel", () => { diff --git a/js/src/instrumentation/plugins/google-adk-plugin.ts b/js/src/instrumentation/plugins/google-adk-plugin.ts index fb2383142..623264016 100644 --- a/js/src/instrumentation/plugins/google-adk-plugin.ts +++ b/js/src/instrumentation/plugins/google-adk-plugin.ts @@ -947,6 +947,26 @@ function aggregateUsageFromEvents( aggregated.thoughtsTokenCount = (aggregated.thoughtsTokenCount ?? 0) + usage.thoughtsTokenCount; } + if (usage.toolUsePromptTokenCount !== undefined) { + aggregated.toolUsePromptTokenCount = + (aggregated.toolUsePromptTokenCount ?? 0) + + usage.toolUsePromptTokenCount; + } + + for (const detailsField of [ + "promptTokensDetails", + "cacheTokensDetails", + "candidatesTokensDetails", + "toolUsePromptTokensDetails", + ] as const) { + const details = usage[detailsField]; + if (details !== undefined) { + aggregated[detailsField] = [ + ...(aggregated[detailsField] ?? []), + ...details, + ]; + } + } } return hasUsage ? aggregated : undefined; @@ -956,11 +976,19 @@ function populateUsageMetrics( metrics: Record, usage: GoogleADKUsageMetadata, ): void { - if (usage.promptTokenCount !== undefined) { - metrics.prompt_tokens = usage.promptTokenCount; + if ( + usage.promptTokenCount !== undefined || + usage.toolUsePromptTokenCount !== undefined + ) { + metrics.prompt_tokens = + (usage.promptTokenCount ?? 0) + (usage.toolUsePromptTokenCount ?? 0); } - if (usage.candidatesTokenCount !== undefined) { - metrics.completion_tokens = usage.candidatesTokenCount; + if ( + usage.candidatesTokenCount !== undefined || + usage.thoughtsTokenCount !== undefined + ) { + metrics.completion_tokens = + (usage.candidatesTokenCount ?? 0) + (usage.thoughtsTokenCount ?? 0); } if (usage.totalTokenCount !== undefined) { metrics.tokens = usage.totalTokenCount; @@ -971,6 +999,22 @@ function populateUsageMetrics( if (usage.thoughtsTokenCount !== undefined) { metrics.completion_reasoning_tokens = usage.thoughtsTokenCount; } + for (const detail of usage.promptTokensDetails ?? []) { + if (detail.modality === "AUDIO" && detail.tokenCount !== undefined) { + metrics.prompt_audio_tokens = + (metrics.prompt_audio_tokens ?? 0) + detail.tokenCount; + } + } + for (const detail of usage.candidatesTokensDetails ?? []) { + if (detail.modality === "AUDIO" && detail.tokenCount !== undefined) { + metrics.completion_audio_tokens = + (metrics.completion_audio_tokens ?? 0) + detail.tokenCount; + } + if (detail.modality === "IMAGE" && detail.tokenCount !== undefined) { + metrics.completion_image_tokens = + (metrics.completion_image_tokens ?? 0) + detail.tokenCount; + } + } } function cleanMetrics(metrics: Record): Record { diff --git a/js/src/vendor-sdk-types/google-adk.ts b/js/src/vendor-sdk-types/google-adk.ts index 20b82e874..d140a8b41 100644 --- a/js/src/vendor-sdk-types/google-adk.ts +++ b/js/src/vendor-sdk-types/google-adk.ts @@ -141,4 +141,14 @@ export interface GoogleADKUsageMetadata { totalTokenCount?: number; cachedContentTokenCount?: number; thoughtsTokenCount?: number; + toolUsePromptTokenCount?: number; + promptTokensDetails?: GoogleADKModalityTokenCount[]; + cacheTokensDetails?: GoogleADKModalityTokenCount[]; + candidatesTokensDetails?: GoogleADKModalityTokenCount[]; + toolUsePromptTokensDetails?: GoogleADKModalityTokenCount[]; +} + +export interface GoogleADKModalityTokenCount { + modality?: string; + tokenCount?: number; }