GoogleCloudPlatform / GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK

adk-2.0 consumer: long_running_tool_durations view (full key, pause_kind='tool', orphan rows)

Open
#215 7 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
47
Forks
21
Avg merge
2d 13h
Merged PRs (30d)
33

Description

Parent tracker: #190 (v18 contract).
Wave: 5 — Consumer views.
Blocked by: #195 (`attributes.adk.app_name` identity stamping — the full-key join reads it directly), #199 (producer TOOL_PAUSED/TOOL_COMPLETED), #210 (cross-event deployment plumbing).

## Contract

### Healthy pairs

Pair `TOOL_PAUSED` → `TOOL_COMPLETED` on the **full key**:
`(JSON_VALUE(attributes, '$.adk.app_name'), user_id, session_id, JSON_VALUE(attributes, '$.adk.function_call_id'))`

**Filter to `attributes.adk.pause_kind = 'tool'` on both rows** so HITL synthetic waits never enter tool-duration analytics.

**Exclude orphan-tagged completions from the healthy-pair stream.** A `TOOL_COMPLETED` with `attributes.adk.pause_orphan = true` was tagged orphan at write time because the matching `TOOL_PAUSED` was not visible. By the time of a later query the paused row can be visible, so without an explicit filter the same completion can appear as both a healthy duration AND an orphan row. The healthy-pair completed stream must therefore filter:

```sql
COALESCE(SAFE_CAST(JSON_VALUE(attributes, '$.adk.pause_orphan') AS BOOL), FALSE) = FALSE
```

Emit `MIN(pause_ts) → MAX(complete_ts)` elapsed time. **Do not rely on `invoke_node` span duration** — paused tools can cross invocation boundaries.

### Orphan completions

`TOOL_COMPLETED` with `attributes.adk.pause_orphan = true` AND `attributes.adk.pause_kind = 'tool'` (HITL orphans excluded — see also defense in fixture #218) appear with:
- `status = 'orphan_completion'`
- `pause_ts = NULL`
- `complete_ts = `

### Dedupe — separate streams

Dedupe must run **separately per event stream** so a duplicate `TOOL_PAUSED` does not collide with a real `TOOL_COMPLETED` under the same full key. A single `ROW_NUMBER() OVER (PARTITION BY ORDER BY timestamp)` across both event types would order the earliest row first — usually the `TOOL_PAUSED` — and could drop the matching `TOOL_COMPLETED`, making healthy pairs vanish.

Concrete shape:

```sql
WITH paused_dedup AS (
SELECT *, ROW_NUMBER() OVER (
PARTITION BY
JSON_VALUE(attributes, '$.adk.app_name'), user_id, session_id,
JSON_VALUE(attributes, '$.adk.function_call_id')
ORDER BY timestamp
) AS rn
FROM ``
WHERE event_type = 'TOOL_PAUSED'
AND JSON_VALUE(attributes, '$.adk.pause_kind') = 'tool'
),
completed_dedup AS (
SELECT *, ROW_NUMBER() OVER (
PARTITION BY
JSON_VALUE(attributes, '$.adk.app_name'), user_id, session_id,
JSON_VALUE(attributes, '$.adk.function_call_id')
ORDER BY timestamp
) AS rn
FROM ``
WHERE event_type = 'TOOL_COMPLETED'
AND JSON_VALUE(attributes, '$.adk.pause_kind') = 'tool'
AND COALESCE(SAFE_CAST(JSON_VALUE(attributes, '$.adk.pause_orphan') AS BOOL), FALSE) = FALSE
)
-- then JOIN paused_dedup rn=1 with completed_dedup rn=1; UNION orphan completions
-- (TOOL_COMPLETED with pause_orphan = true AND pause_kind = 'tool', deduped separately).
```

Equivalent: include `event_type` in the partition. Either form is acceptable — the constraint is that a duplicate paused row cannot displace the matching completion row.

## Acceptance

- [ ] Healthy pair: `pause_kind = 'tool'` only; full-key join; **healthy-pair completed stream excludes `pause_orphan = true`**.
- [ ] Orphan: included when `pause_orphan = true AND pause_kind = 'tool'`; HITL orphans excluded.
- [ ] **HITL-orphan exclusion test** (consumes the synthetic fixture row from #218): a synthetic `TOOL_COMPLETED` with `pause_kind = 'hitl_confirmation'` and `pause_orphan = true` is asserted **absent** from this view.
- [ ] **Orphan double-count test**: a fixture with a visible `TOOL_PAUSED` and a `TOOL_COMPLETED` (`pause_orphan = true`) for the same full key produces exactly **one** `status = 'orphan_completion'` row and **no** healthy duplicate.
- [ ] Cross-invocation pause/resume produces correct end-to-end wall-clock duration.
- [ ] Dedupe runs separately per event stream (or with `event_type` included in the partition).
- [ ] **Dedupe robustness test**: a fixture with duplicate `TOOL_PAUSED` rows **and** duplicate `TOOL_COMPLETED` rows for the same full key returns exactly one healthy duration row.

## References

- #190 (v18 consumer view 4; v13-v15 orphan + HITL contracts; v17 orphan double-count exclusion).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.