GoogleCloudPlatform / GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK
adk-2.0 design: oversized AGENT_STATE_CHECKPOINT offload contract
- Dominant language
- Python
- Stars
- 47
- Forks
- 21
- Avg merge
- 2d 13h
- Merged PRs (30d)
- 33
Description
Parent tracker: #190 (v15 contract).
Wave: 3 — Design blocker.
Blocks: large-snapshot handling in #202 (AGENT_STATE_CHECKPOINT).
## Problem
`AGENT_STATE_CHECKPOINT` can carry large `agent_state` dicts. The plugin already has GCS offload for content parts via `HybridContentParser`, but that path is content-part/text-shaped, **not directly reusable** for a structured-dict state snapshot.
## Resolve
Define the explicit offload contract:
- (a) **Where the GCS URI lives**: `attributes.adk.agent_state_uri`?
- (b) **Where the SHA-256 lives**: `attributes.adk.agent_state_sha256`?
- (c) **Whether the inline `content.agent_state` is removed or replaced with a stub** (e.g. `{"_offloaded": true, "uri": ..., "sha256": ...}`).
- (d) **Whether to share parser code with `HybridContentParser` or add a dedicated helper.**
- (e) **Size cap env var**: `BQAA_AGENT_STATE_MAX_BYTES` default value.
## Acceptance
- [ ] All five questions answered in this issue.
- [ ] Decisions reflected in #202 (AGENT_STATE_CHECKPOINT) acceptance.
- [ ] Test: a state snapshot above the cap is offloaded; the inline content shape matches the chosen stub format; the SHA and URI are queryable.
- [ ] Test: a state snapshot below the cap remains inline (no GCS write).
## References
- #190 (v15 risk section; v6 offload sub-issue carve-out).
- `src/google/adk/plugins/bigquery_agent_analytics_plugin.py` (`HybridContentParser`).
---
## Selected approach (v4)
This section captures the decision reached in the #297 v3 review thread.
### Strategy
Dedicated structured-state offloader. Do NOT reuse `HybridContentParser` — that helper is content-part / text-shaped and not directly reusable for a structured `agent_state` dict.
### Canonical contract
- **Env var:** `BQAA_AGENT_STATE_MAX_BYTES` (default **524288** / 512 KB).
- Recommended default keeps inline rows well under BQ Storage Write API's per-row hard limit (10 MiB) and the practical streaming-window soft limit, with envelope headroom.
- **Inline behavior (below threshold):** unchanged from #202. `content.agent_state` holds the dict; no GCS write.
- **Offload behavior (at or above threshold):**
- Serialize the dict to JSON.
- Write to `gs:///agent_state/.json`.
- Replace inline `content.agent_state` with the stub: `{"_offloaded": true, "size_bytes": N, "sha256": ""}`. **URI is NOT in the stub** — single source of truth.
- `attributes.adk.agent_state_uri` = the `gs://` URI.
- `attributes.adk.agent_state_sha256` = hex digest.
- **Helper:** new dedicated `_offload_structured_state(state, ctx) -> (stub, uri, sha256)`. Do not extend `HybridContentParser`.
### Acceptance tests
- **Below threshold:** state snapshot smaller than `BQAA_AGENT_STATE_MAX_BYTES` remains inline. No GCS write. `attributes.adk.agent_state_uri` and `agent_state_sha256` are absent (or null).
- **At/above threshold:** state snapshot exceeding the limit is offloaded:
- GCS object exists at the URI.
- URI is queryable from BQ via `JSON_VALUE(attributes, '$.adk.agent_state_uri')`.
- SHA-256 in attributes matches the GCS object's content hash.
- Inline `content.agent_state` matches the documented stub shape exactly.
- Original payload is recoverable by reading the GCS object.
### References
- #297 v3 — https://github.com/GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK/issues/297#issuecomment-4646954889
Contributor guide
Assessment
This issue has not been assessed yet.