Skip to content

Replace custom ContextStore with A2A-native task history #116

@jezekra1

Description

@jezekra1

Is your feature request related to a problem? Please describe.
Conversation history is currently stored in two places: once inside A2A Tasks (task.history / task.artifacts) and again in a custom ContextStore abstraction backed by the adk-server /contexts/{id}/history API. This duplication adds complexity and diverges from the A2A protocol's native support for conversation data.

The A2A SDK now provides first-class support for task listing with contextId filtering, pagination, and owner scoping — covering all current ContextStore use cases.

Describe the solution you'd like

Use A2A Tasks as the single source of truth for conversation history. This is a breaking change — no migration path, done in one step.

Current vs Proposed

Layer Current Proposed
adk-py RunContext Calls _store.store(msg) to push to ContextStore Remove store() / load_history() — history lives in TaskUpdater's task updates (already happening)
adk-py ContextStore MemoryContextStore, PlatformContextStore Remove entirely
adk-server /contexts API Full CRUD + history endpoints Keep context metadata (title, timestamps) but drop history endpoints
UI data fetching GET /contexts/{id}/historyconvertHistoryToUIMessages() Call A2A proxy ListTasks with contextId filter → flatten task.history into UI messages
UI messages provider useListContextHistory hook New useListTasks hook against A2A endpoint

Files to remove in adk-py

  • kagenti_adk/server/store/context_store.py (abstract interface)
  • kagenti_adk/server/store/memory_context_store.py
  • kagenti_adk/server/store/platform_context_store.py
  • store() / load_history() / delete_history_from_id() on RunContext

adk-server /contexts endpoints

  • Keep: context CRUD (create, list, get, update, delete) for sidebar and metadata
  • Remove: POST /contexts/{id}/history, GET /contexts/{id}/history, DELETE /contexts/{id}/history

How agent-side history access works after the change

If an agent function needs prior conversation context, it reads from task_store.list(context_id=...) or task_store.get(task_id) directly — no separate store abstraction needed.

Conversation title generation

Currently handled by ContextService.add_history_item() which detects the first user message and generates a title. Two options:

  1. Agent-side: The agent (or a background task triggered by the agent) generates a title after the first interaction and stores it in task metadata.
  2. Server-side: The A2A proxy layer detects the first task in a context and triggers title generation as a background job, storing the result in context metadata.

Conversation metadata (title, timestamps, etc.)

The /contexts table currently stores metadata like title, created_at, last_active_at. Options:

  1. Keep lightweight /contexts table — only for metadata, no history. Simplest migration path.
  2. A2A extension — store conversation-level metadata (title, etc.) on the tasks themselves via A2A task metadata fields. The first task in a context carries the conversation metadata. Eliminates the need for a separate contexts table entirely.

Option 2 is the cleaner long-term approach but requires convention around which task holds conversation metadata.

Listing conversations for the sidebar

Currently GET /contexts lists all conversations. With A2A-only approach, we'd need a distinct query on context_id from the tasks table. Keeping the lightweight /contexts endpoint is simpler and avoids an expensive distinct query.

Describe alternatives you've considered
Keep the current dual-store approach and sync them, but this adds maintenance burden and fights against A2A's direction of providing first-class task/history management.

Additional context
The A2A ListTasks method supports all needed filtering:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "ListTasks",
  "params": {
    "contextId": "context-uuid",
    "status": "TASK_STATE_WORKING",
    "pageSize": 50,
    "pageToken": "cursor-token"
  }
}

Related: #91

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions