diff --git a/docs/mkdocs/zh/session_replay_consistency.md b/docs/mkdocs/zh/session_replay_consistency.md new file mode 100644 index 00000000..bae47ad7 --- /dev/null +++ b/docs/mkdocs/zh/session_replay_consistency.md @@ -0,0 +1,25 @@ +# Session / Memory / Summary 回放一致性测试 + +## 设计说明 + +框架使用 JSONL 标准轨迹驱动 InMemory、文件型 SQLite 及可选 SQL/Redis 后端,回放后读取 session、events、state、memory、summary 快照并比较。归一化只处理非业务差异:事件时间戳、memory 时间戳、summary 更新时间写入 `allowed_diff`;显式 replay event id 仍参与比较,memory 返回顺序按多重集排序。Summary 比较区分语义文本和存储元数据:摘要文本做空白、大小写归一化,`session_id`、版本链、active/historical 覆盖关系、事件计数和同进程 public `get_session_summary()` 读取结果精确比较。SQLite 会重建 service 验证 summary anchor 与 historical events 的持久化回放;manager cache 只在进程内比较。报告写入 `session_memory_summary_diff_report.json`,定位到 case、真实 session id、event index 或 summary id、字段路径和两端值。 + +## 运行方式 + +固定收集报告: + +```bash +TRPC_AGENT_REPLAY_REPORT_PATH=./session_memory_summary_diff_report.json \ + .venv/bin/python -m pytest tests/sessions/test_replay_consistency.py +``` + +开启 SQL/Redis 集成模式: + +```bash +TRPC_AGENT_REPLAY_BACKENDS=in_memory,sqlite,sql_env,redis_env \ +TRPC_AGENT_REPLAY_SQL_URL=mysql+pymysql://... \ +TRPC_AGENT_REPLAY_REDIS_URL=redis://... \ + .venv/bin/python -m pytest tests/sessions/test_replay_consistency.py +``` + +未设置集成环境变量时,SQL/Redis 后端会自动跳过;后端构建或回放失败会记录到 report 的 `errors` 字段。集成模式会 best-effort 清理本次 run 的数据,仍建议使用临时库或独立 Redis DB。 diff --git a/session_memory_summary_diff_report.json b/session_memory_summary_diff_report.json new file mode 100644 index 00000000..150039be --- /dev/null +++ b/session_memory_summary_diff_report.json @@ -0,0 +1,10427 @@ +{ + "allowed_diff": [ + { + "path": "$.session.last_update_time", + "reason": "storage update time is generated by each backend clock and is not business state" + }, + { + "path": "$.events[*].timestamp", + "reason": "timestamp precision and timezone serialization differ across storage engines" + }, + { + "path": "$.summary.updated_at", + "reason": "summary update timestamp is clock-derived; presence, version, owner, and content are compared" + }, + { + "path": "$.memory.*[*].timestamp", + "reason": "memory timestamps mirror event storage precision and are not used for recall equivalence" + }, + { + "path": "$.memory.*[*].order", + "reason": "memory recall order is backend-dependent; entries are sorted for multiset comparison" + } + ], + "cases": [ + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "single_turn_conversation", + "description": "single user input and assistant text output", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "single_turn_conversation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "single-user-1", + "index": 0, + "invocation_id": "inv-single-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Hello assistant" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "single-agent-1", + "index": 1, + "invocation_id": "inv-single-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Hello, how can I help?" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-single_turn_conversation", + "id": "single-turn", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-single_turn_conversation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "single-user-1", + "index": 0, + "invocation_id": "inv-single-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Hello assistant" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "single-agent-1", + "index": 1, + "invocation_id": "inv-single-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Hello, how can I help?" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "single-turn", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "single_turn_conversation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "single-user-1", + "index": 0, + "invocation_id": "inv-single-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Hello assistant" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "single-agent-1", + "index": 1, + "invocation_id": "inv-single-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Hello, how can I help?" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-single_turn_conversation", + "id": "single-turn", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-single_turn_conversation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "single-user-1", + "index": 0, + "invocation_id": "inv-single-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Hello assistant" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "single-agent-1", + "index": 1, + "invocation_id": "inv-single-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Hello, how can I help?" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "single-turn", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "multi_turn_conversation", + "description": "multiple user and assistant turns are replayed in order", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "multi_turn_conversation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "multi-user-1", + "index": 0, + "invocation_id": "inv-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Plan a trip to Shenzhen" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "multi-agent-1", + "index": 1, + "invocation_id": "inv-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I can help with transport and food." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "multi-user-2", + "index": 2, + "invocation_id": "inv-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Keep it under 1000 yuan" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "multi-agent-2", + "index": 3, + "invocation_id": "inv-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will optimize for budget travel." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-multi_turn_conversation", + "id": "multi-turn", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-multi_turn_conversation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "multi-user-1", + "index": 0, + "invocation_id": "inv-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Plan a trip to Shenzhen" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "multi-agent-1", + "index": 1, + "invocation_id": "inv-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I can help with transport and food." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "multi-user-2", + "index": 2, + "invocation_id": "inv-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Keep it under 1000 yuan" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "multi-agent-2", + "index": 3, + "invocation_id": "inv-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will optimize for budget travel." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "multi-turn", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 4, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 4, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "multi_turn_conversation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "multi-user-1", + "index": 0, + "invocation_id": "inv-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Plan a trip to Shenzhen" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "multi-agent-1", + "index": 1, + "invocation_id": "inv-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I can help with transport and food." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "multi-user-2", + "index": 2, + "invocation_id": "inv-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Keep it under 1000 yuan" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "multi-agent-2", + "index": 3, + "invocation_id": "inv-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will optimize for budget travel." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-multi_turn_conversation", + "id": "multi-turn", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-multi_turn_conversation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "multi-user-1", + "index": 0, + "invocation_id": "inv-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Plan a trip to Shenzhen" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "multi-agent-1", + "index": 1, + "invocation_id": "inv-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I can help with transport and food." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "multi-user-2", + "index": 2, + "invocation_id": "inv-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Keep it under 1000 yuan" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "multi-agent-2", + "index": 3, + "invocation_id": "inv-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will optimize for budget travel." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "multi-turn", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 4, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 4, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "tool_call_conversation", + "description": "function_call and function_response parts survive backend replay", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "tool_call_conversation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "tool-user-1", + "index": 0, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "What is the weather in Beijing?" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "tool-call-1", + "index": 1, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "args": { + "city": "Beijing", + "unit": "celsius" + }, + "kind": "function_call", + "name": "get_weather" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "tool", + "branch": null, + "filter_key": null, + "id": "tool-response-1", + "index": 2, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "function_response", + "name": "get_weather", + "response": { + "city": "Beijing", + "condition": "sunny", + "temperature": 29 + } + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "tool-agent-1", + "index": 3, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Beijing is sunny and 29 C." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-tool_call_conversation", + "id": "tool-turn", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-tool_call_conversation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "tool-user-1", + "index": 0, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "What is the weather in Beijing?" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "tool-call-1", + "index": 1, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "args": { + "city": "Beijing", + "unit": "celsius" + }, + "kind": "function_call", + "name": "get_weather" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "tool", + "branch": null, + "filter_key": null, + "id": "tool-response-1", + "index": 2, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "function_response", + "name": "get_weather", + "response": { + "city": "Beijing", + "condition": "sunny", + "temperature": 29 + } + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "tool-agent-1", + "index": 3, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Beijing is sunny and 29 C." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "tool-turn", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 4, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 4, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "tool_call_conversation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "tool-user-1", + "index": 0, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "What is the weather in Beijing?" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "tool-call-1", + "index": 1, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "args": { + "city": "Beijing", + "unit": "celsius" + }, + "kind": "function_call", + "name": "get_weather" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "tool", + "branch": null, + "filter_key": null, + "id": "tool-response-1", + "index": 2, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "function_response", + "name": "get_weather", + "response": { + "city": "Beijing", + "condition": "sunny", + "temperature": 29 + } + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "tool-agent-1", + "index": 3, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Beijing is sunny and 29 C." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-tool_call_conversation", + "id": "tool-turn", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-tool_call_conversation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "tool-user-1", + "index": 0, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "What is the weather in Beijing?" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "tool-call-1", + "index": 1, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "args": { + "city": "Beijing", + "unit": "celsius" + }, + "kind": "function_call", + "name": "get_weather" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "tool", + "branch": null, + "filter_key": null, + "id": "tool-response-1", + "index": 2, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "function_response", + "name": "get_weather", + "response": { + "city": "Beijing", + "condition": "sunny", + "temperature": 29 + } + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "tool-agent-1", + "index": 3, + "invocation_id": "inv-tool-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Beijing is sunny and 29 C." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "tool-turn", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 4, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 4, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "state_overwrite", + "description": "session, app, user, and temp state updates follow storage semantics", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "state_overwrite", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "state-user-1", + "index": 0, + "invocation_id": "inv-state-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Remember my dashboard choices" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "app:locale": "en-US", + "topic": "dashboard", + "user:tier": "pro" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "state-agent-1", + "index": 1, + "invocation_id": "inv-state-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Saved your dashboard choices." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "topic": "dashboard-v2", + "user:tier": "enterprise" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-state_overwrite", + "id": "state-overwrite", + "last_update_time": "", + "state": { + "app:locale": "en-US", + "topic": "dashboard-v2", + "user:tier": "enterprise" + }, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-state_overwrite", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "state-user-1", + "index": 0, + "invocation_id": "inv-state-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Remember my dashboard choices" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "app:locale": "en-US", + "topic": "dashboard", + "user:tier": "pro" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "state-agent-1", + "index": 1, + "invocation_id": "inv-state-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Saved your dashboard choices." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "topic": "dashboard-v2", + "user:tier": "enterprise" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "state-overwrite", + "last_update_time": "", + "state": { + "app:locale": "en-US", + "topic": "dashboard-v2", + "user:tier": "enterprise" + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "state_overwrite", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "state-user-1", + "index": 0, + "invocation_id": "inv-state-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Remember my dashboard choices" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "app:locale": "en-US", + "topic": "dashboard", + "user:tier": "pro" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "state-agent-1", + "index": 1, + "invocation_id": "inv-state-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Saved your dashboard choices." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "topic": "dashboard-v2", + "user:tier": "enterprise" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-state_overwrite", + "id": "state-overwrite", + "last_update_time": "", + "state": { + "app:locale": "en-US", + "topic": "dashboard-v2", + "user:tier": "enterprise" + }, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-state_overwrite", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "state-user-1", + "index": 0, + "invocation_id": "inv-state-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Remember my dashboard choices" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "app:locale": "en-US", + "topic": "dashboard", + "user:tier": "pro" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "state-agent-1", + "index": 1, + "invocation_id": "inv-state-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Saved your dashboard choices." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "topic": "dashboard-v2", + "user:tier": "enterprise" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "state-overwrite", + "last_update_time": "", + "state": { + "app:locale": "en-US", + "topic": "dashboard-v2", + "user:tier": "enterprise" + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "memory_preference_write_read", + "description": "stored session memory can retrieve a user preference", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "memory_preference_write_read", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "memory-user-1", + "index": 0, + "invocation_id": "inv-memory-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I prefer jasmine tea in the afternoon." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "memory-agent-1", + "index": 1, + "invocation_id": "inv-memory-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will remember your jasmine tea preference." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": { + "jasmine tea": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "I will remember your jasmine tea preference." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "I prefer jasmine tea in the afternoon." + } + ], + "timestamp": "" + } + ] + }, + "session": { + "app_name": "replay-57954-1783081772144-memory_preference_write_read", + "id": "memory-preference", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-memory_preference_write_read", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "memory-user-1", + "index": 0, + "invocation_id": "inv-memory-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I prefer jasmine tea in the afternoon." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "memory-agent-1", + "index": 1, + "invocation_id": "inv-memory-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will remember your jasmine tea preference." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "memory-preference", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "memory_preference_write_read", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "memory-user-1", + "index": 0, + "invocation_id": "inv-memory-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I prefer jasmine tea in the afternoon." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "memory-agent-1", + "index": 1, + "invocation_id": "inv-memory-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will remember your jasmine tea preference." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": { + "jasmine tea": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "I will remember your jasmine tea preference." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "I prefer jasmine tea in the afternoon." + } + ], + "timestamp": "" + } + ] + }, + "session": { + "app_name": "replay-57954-1783081772144-memory_preference_write_read", + "id": "memory-preference", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-memory_preference_write_read", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "memory-user-1", + "index": 0, + "invocation_id": "inv-memory-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I prefer jasmine tea in the afternoon." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "memory-agent-1", + "index": 1, + "invocation_id": "inv-memory-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will remember your jasmine tea preference." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "memory-preference", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "memory_fact_write_read", + "description": "stored session memory can retrieve a factual note", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "memory_fact_write_read", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "fact-user-1", + "index": 0, + "invocation_id": "inv-fact-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "My project codename is Blue River." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "fact-agent-1", + "index": 1, + "invocation_id": "inv-fact-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Noted the Blue River project codename." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": { + "Blue River": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Noted the Blue River project codename." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "My project codename is Blue River." + } + ], + "timestamp": "" + } + ] + }, + "session": { + "app_name": "replay-57954-1783081772144-memory_fact_write_read", + "id": "memory-fact", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-memory_fact_write_read", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "fact-user-1", + "index": 0, + "invocation_id": "inv-fact-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "My project codename is Blue River." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "fact-agent-1", + "index": 1, + "invocation_id": "inv-fact-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Noted the Blue River project codename." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "memory-fact", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "memory_fact_write_read", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "fact-user-1", + "index": 0, + "invocation_id": "inv-fact-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "My project codename is Blue River." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "fact-agent-1", + "index": 1, + "invocation_id": "inv-fact-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Noted the Blue River project codename." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": { + "Blue River": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Noted the Blue River project codename." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "My project codename is Blue River." + } + ], + "timestamp": "" + } + ] + }, + "session": { + "app_name": "replay-57954-1783081772144-memory_fact_write_read", + "id": "memory-fact", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-memory_fact_write_read", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "fact-user-1", + "index": 0, + "invocation_id": "inv-fact-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "My project codename is Blue River." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "fact-agent-1", + "index": 1, + "invocation_id": "inv-fact-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Noted the Blue River project codename." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "memory-fact", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "summary_create_update", + "description": "summary can be generated and then updated after later turns", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "summary_create_update", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-user-3", + "index": 1, + "invocation_id": "inv-summary-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Bob owns release notes." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "summary-agent-3", + "index": 2, + "invocation_id": "inv-summary-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Bob owns release notes for Friday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-user-1", + "index": 0, + "invocation_id": "inv-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "We need a launch checklist for Friday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "summary-agent-1", + "index": 1, + "invocation_id": "inv-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Checklist includes QA, docs, and rollback plan." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 2, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-update: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"we need a launch checklist for friday.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"checklist includes qa, docs, and rollback plan.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-user-2", + "index": 3, + "invocation_id": "inv-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Add owner Alice for QA." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "summary-agent-2", + "index": 4, + "invocation_id": "inv-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alice owns QA before launch." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-summary_create_update", + "id": "summary-update", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-summary_create_update", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-user-3", + "index": 1, + "invocation_id": "inv-summary-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Bob owns release notes." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "summary-agent-3", + "index": 2, + "invocation_id": "inv-summary-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Bob owns release notes for Friday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-user-1", + "index": 0, + "invocation_id": "inv-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "We need a launch checklist for Friday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "summary-agent-1", + "index": 1, + "invocation_id": "inv-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Checklist includes QA, docs, and rollback plan." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 2, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-update: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"we need a launch checklist for friday.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"checklist includes qa, docs, and rollback plan.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-user-2", + "index": 3, + "invocation_id": "inv-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Add owner Alice for QA." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "summary-agent-2", + "index": 4, + "invocation_id": "inv-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alice owns QA before launch." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "id": "summary-update", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 5, + "historical_summary_count": 1, + "id": "summary-update:summary:v2", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 3, + "session_id": "summary-update", + "text": "summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 2, + "versions": [ + { + "active": false, + "session_id": "summary-update", + "source": "historical", + "summary_id": "summary-update:summary:v1", + "text": "summary-update: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"we need a launch checklist for friday.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"checklist includes qa, docs, and rollback plan.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + }, + { + "active": true, + "session_id": "summary-update", + "source": "active", + "summary_id": "summary-update:summary:v2", + "text": "summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 2 + } + ] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 5, + "historical_summary_count": 1, + "id": "summary-update:summary:v2", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 3, + "service_manager_compressed_event_count": 3, + "service_manager_exists": true, + "service_manager_original_event_count": 5, + "service_manager_session_id": "summary-update", + "service_manager_text": "summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "service_manager_updated_at": "", + "service_public_exists": true, + "service_public_text": "summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "session_id": "summary-update", + "text": "summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 2, + "versions": [ + { + "active": false, + "session_id": "summary-update", + "source": "historical", + "summary_id": "summary-update:summary:v1", + "text": "summary-update: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"we need a launch checklist for friday.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"checklist includes qa, docs, and rollback plan.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + }, + { + "active": true, + "session_id": "summary-update", + "source": "active", + "summary_id": "summary-update:summary:v2", + "text": "summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 2 + } + ] + } + }, + { + "backend": "sqlite", + "case": "summary_create_update", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-user-3", + "index": 1, + "invocation_id": "inv-summary-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Bob owns release notes." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "summary-agent-3", + "index": 2, + "invocation_id": "inv-summary-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Bob owns release notes for Friday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-user-1", + "index": 0, + "invocation_id": "inv-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "We need a launch checklist for Friday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "summary-agent-1", + "index": 1, + "invocation_id": "inv-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Checklist includes QA, docs, and rollback plan." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 2, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-update: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"we need a launch checklist for friday.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"checklist includes qa, docs, and rollback plan.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-user-2", + "index": 3, + "invocation_id": "inv-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Add owner Alice for QA." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "summary-agent-2", + "index": 4, + "invocation_id": "inv-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alice owns QA before launch." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-summary_create_update", + "id": "summary-update", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-summary_create_update", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-user-3", + "index": 1, + "invocation_id": "inv-summary-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Bob owns release notes." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "summary-agent-3", + "index": 2, + "invocation_id": "inv-summary-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Bob owns release notes for Friday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-user-1", + "index": 0, + "invocation_id": "inv-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "We need a launch checklist for Friday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "summary-agent-1", + "index": 1, + "invocation_id": "inv-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Checklist includes QA, docs, and rollback plan." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 2, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-update: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"we need a launch checklist for friday.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"checklist includes qa, docs, and rollback plan.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-user-2", + "index": 3, + "invocation_id": "inv-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Add owner Alice for QA." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "summary-agent-2", + "index": 4, + "invocation_id": "inv-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alice owns QA before launch." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "id": "summary-update", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 5, + "historical_summary_count": 1, + "id": "summary-update:summary:v2", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 3, + "session_id": "summary-update", + "text": "summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 2, + "versions": [ + { + "active": false, + "session_id": "summary-update", + "source": "historical", + "summary_id": "summary-update:summary:v1", + "text": "summary-update: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"we need a launch checklist for friday.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"checklist includes qa, docs, and rollback plan.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + }, + { + "active": true, + "session_id": "summary-update", + "source": "active", + "summary_id": "summary-update:summary:v2", + "text": "summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 2 + } + ] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 5, + "historical_summary_count": 1, + "id": "summary-update:summary:v2", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 3, + "service_manager_compressed_event_count": 3, + "service_manager_exists": true, + "service_manager_original_event_count": 5, + "service_manager_session_id": "summary-update", + "service_manager_text": "summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "service_manager_updated_at": "", + "service_public_exists": true, + "service_public_text": "summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "session_id": "summary-update", + "text": "summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 2, + "versions": [ + { + "active": false, + "session_id": "summary-update", + "source": "historical", + "summary_id": "summary-update:summary:v1", + "text": "summary-update: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"we need a launch checklist for friday.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"checklist includes qa, docs, and rollback plan.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + }, + { + "active": true, + "session_id": "summary-update", + "source": "active", + "summary_id": "summary-update:summary:v2", + "text": "summary-update: [{\"author\": \"system\", \"parts\": [{\"kind\": \"text\", \"text\": \"previous conversation summary: summary-update: [{\\\"author\\\": \\\"user\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"we need a launch checklist for friday.\\\"}]}, {\\\"author\\\": \\\"agent\\\", \\\"parts\\\": [{\\\"kind\\\": \\\"text\\\", \\\"text\\\": \\\"checklist includes qa, docs, and rollback plan.\\\"}]}]\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"add owner alice for qa.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns qa before launch.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 2 + } + ] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "summary_event_truncation", + "description": "summary anchor plus retained recent events reconstruct context after compression", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "summary_event_truncation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-3", + "index": 1, + "invocation_id": "inv-truncate-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Schedule training on Wednesday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-3", + "index": 2, + "invocation_id": "inv-truncate-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Training is scheduled on Wednesday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-4", + "index": 3, + "invocation_id": "inv-truncate-4", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "After summary, remind me about Wednesday training." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-4", + "index": 4, + "invocation_id": "inv-truncate-4", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will keep Wednesday training in context." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-1", + "index": 0, + "invocation_id": "inv-truncate-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Long discussion part one about onboarding." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-1", + "index": 1, + "invocation_id": "inv-truncate-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Onboarding needs account setup and training." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-2", + "index": 2, + "invocation_id": "inv-truncate-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Include security approval before access." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-2", + "index": 3, + "invocation_id": "inv-truncate-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Security approval comes before account access." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-summary_event_truncation", + "id": "summary-truncate", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-summary_event_truncation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-3", + "index": 1, + "invocation_id": "inv-truncate-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Schedule training on Wednesday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-3", + "index": 2, + "invocation_id": "inv-truncate-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Training is scheduled on Wednesday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-4", + "index": 3, + "invocation_id": "inv-truncate-4", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "After summary, remind me about Wednesday training." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-4", + "index": 4, + "invocation_id": "inv-truncate-4", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will keep Wednesday training in context." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-1", + "index": 0, + "invocation_id": "inv-truncate-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Long discussion part one about onboarding." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-1", + "index": 1, + "invocation_id": "inv-truncate-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Onboarding needs account setup and training." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-2", + "index": 2, + "invocation_id": "inv-truncate-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Include security approval before access." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-2", + "index": 3, + "invocation_id": "inv-truncate-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Security approval comes before account access." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "id": "summary-truncate", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 4, + "historical_summary_count": 0, + "id": "summary-truncate:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 5, + "session_id": "summary-truncate", + "text": "summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "summary-truncate", + "source": "active", + "summary_id": "summary-truncate:summary:v1", + "text": "summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 4, + "historical_summary_count": 0, + "id": "summary-truncate:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 5, + "service_manager_compressed_event_count": 3, + "service_manager_exists": true, + "service_manager_original_event_count": 6, + "service_manager_session_id": "summary-truncate", + "service_manager_text": "summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "service_manager_updated_at": "", + "service_public_exists": true, + "service_public_text": "summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "session_id": "summary-truncate", + "text": "summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "summary-truncate", + "source": "active", + "summary_id": "summary-truncate:summary:v1", + "text": "summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + } + }, + { + "backend": "sqlite", + "case": "summary_event_truncation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-3", + "index": 1, + "invocation_id": "inv-truncate-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Schedule training on Wednesday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-3", + "index": 2, + "invocation_id": "inv-truncate-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Training is scheduled on Wednesday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-4", + "index": 3, + "invocation_id": "inv-truncate-4", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "After summary, remind me about Wednesday training." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-4", + "index": 4, + "invocation_id": "inv-truncate-4", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will keep Wednesday training in context." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-1", + "index": 0, + "invocation_id": "inv-truncate-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Long discussion part one about onboarding." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-1", + "index": 1, + "invocation_id": "inv-truncate-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Onboarding needs account setup and training." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-2", + "index": 2, + "invocation_id": "inv-truncate-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Include security approval before access." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-2", + "index": 3, + "invocation_id": "inv-truncate-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Security approval comes before account access." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-summary_event_truncation", + "id": "summary-truncate", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-summary_event_truncation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-3", + "index": 1, + "invocation_id": "inv-truncate-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Schedule training on Wednesday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-3", + "index": 2, + "invocation_id": "inv-truncate-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Training is scheduled on Wednesday." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-4", + "index": 3, + "invocation_id": "inv-truncate-4", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "After summary, remind me about Wednesday training." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-4", + "index": 4, + "invocation_id": "inv-truncate-4", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will keep Wednesday training in context." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-1", + "index": 0, + "invocation_id": "inv-truncate-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Long discussion part one about onboarding." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-1", + "index": 1, + "invocation_id": "inv-truncate-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Onboarding needs account setup and training." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "truncate-user-2", + "index": 2, + "invocation_id": "inv-truncate-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Include security approval before access." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "truncate-agent-2", + "index": 3, + "invocation_id": "inv-truncate-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Security approval comes before account access." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "id": "summary-truncate", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 4, + "historical_summary_count": 0, + "id": "summary-truncate:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 5, + "session_id": "summary-truncate", + "text": "summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "summary-truncate", + "source": "active", + "summary_id": "summary-truncate:summary:v1", + "text": "summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 4, + "historical_summary_count": 0, + "id": "summary-truncate:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 5, + "service_manager_compressed_event_count": 3, + "service_manager_exists": true, + "service_manager_original_event_count": 6, + "service_manager_session_id": "summary-truncate", + "service_manager_text": "summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "service_manager_updated_at": "", + "service_public_exists": true, + "service_public_text": "summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "session_id": "summary-truncate", + "text": "summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "summary-truncate", + "source": "active", + "summary_id": "summary-truncate:summary:v1", + "text": "summary-truncate: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"long discussion part one about onboarding.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"onboarding needs account setup and training.\"}]}, {\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"include security approval before access.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"security approval comes before account access.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "failed_append_recovery", + "description": "a failed append before persistence leaves no dirty event or dirty state", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "failed_append_recovery", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "failed-user-1", + "index": 0, + "invocation_id": "inv-failed-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "This event is persisted." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "phase": "persisted" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "failed-agent-1", + "index": 1, + "invocation_id": "inv-failed-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "State remains clean after recovery." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-failed_append_recovery", + "id": "failed-recovery", + "last_update_time": "", + "state": { + "phase": "persisted" + }, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-failed_append_recovery", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "failed-user-1", + "index": 0, + "invocation_id": "inv-failed-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "This event is persisted." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "phase": "persisted" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "failed-agent-1", + "index": 1, + "invocation_id": "inv-failed-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "State remains clean after recovery." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "failed-recovery", + "last_update_time": "", + "state": { + "phase": "persisted" + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "failed_append_recovery", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "failed-user-1", + "index": 0, + "invocation_id": "inv-failed-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "This event is persisted." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "phase": "persisted" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "failed-agent-1", + "index": 1, + "invocation_id": "inv-failed-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "State remains clean after recovery." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-failed_append_recovery", + "id": "failed-recovery", + "last_update_time": "", + "state": { + "phase": "persisted" + }, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-failed_append_recovery", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "failed-user-1", + "index": 0, + "invocation_id": "inv-failed-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "This event is persisted." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "phase": "persisted" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "failed-agent-1", + "index": 1, + "invocation_id": "inv-failed-3", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "State remains clean after recovery." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "failed-recovery", + "last_update_time": "", + "state": { + "phase": "persisted" + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "duplicate_event_write_recovery", + "description": "a failed retry with a duplicate event id leaves no duplicate event, dirty state, or stale text", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "duplicate_event_write_recovery", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "duplicate-user-1", + "index": 0, + "invocation_id": "inv-duplicate-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "This event is persisted once." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "phase": "persisted-once" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "duplicate-agent-1", + "index": 1, + "invocation_id": "inv-duplicate-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Duplicate retry did not change stored context." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-duplicate_event_write_recovery", + "id": "duplicate-event-recovery", + "last_update_time": "", + "state": { + "phase": "persisted-once" + }, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-duplicate_event_write_recovery", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "duplicate-user-1", + "index": 0, + "invocation_id": "inv-duplicate-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "This event is persisted once." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "phase": "persisted-once" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "duplicate-agent-1", + "index": 1, + "invocation_id": "inv-duplicate-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Duplicate retry did not change stored context." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "duplicate-event-recovery", + "last_update_time": "", + "state": { + "phase": "persisted-once" + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "duplicate_event_write_recovery", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "duplicate-user-1", + "index": 0, + "invocation_id": "inv-duplicate-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "This event is persisted once." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "phase": "persisted-once" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "duplicate-agent-1", + "index": 1, + "invocation_id": "inv-duplicate-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Duplicate retry did not change stored context." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-duplicate_event_write_recovery", + "id": "duplicate-event-recovery", + "last_update_time": "", + "state": { + "phase": "persisted-once" + }, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-duplicate_event_write_recovery", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "duplicate-user-1", + "index": 0, + "invocation_id": "inv-duplicate-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "This event is persisted once." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "phase": "persisted-once" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "duplicate-agent-1", + "index": 1, + "invocation_id": "inv-duplicate-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Duplicate retry did not change stored context." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "duplicate-event-recovery", + "last_update_time": "", + "state": { + "phase": "persisted-once" + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "repeat_memory_store", + "description": "repeating the same memory write does not duplicate retrieved memories", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "repeat_memory_store", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "repeat-user-1", + "index": 0, + "invocation_id": "inv-repeat-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I like quiet focus blocks in the morning." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "repeat-agent-1", + "index": 1, + "invocation_id": "inv-repeat-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will remember your quiet focus block preference." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": { + "quiet focus": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "I will remember your quiet focus block preference." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "I like quiet focus blocks in the morning." + } + ], + "timestamp": "" + } + ] + }, + "session": { + "app_name": "replay-57954-1783081772144-repeat_memory_store", + "id": "repeat-memory", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-repeat_memory_store", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "repeat-user-1", + "index": 0, + "invocation_id": "inv-repeat-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I like quiet focus blocks in the morning." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "repeat-agent-1", + "index": 1, + "invocation_id": "inv-repeat-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will remember your quiet focus block preference." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "repeat-memory", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "repeat_memory_store", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "repeat-user-1", + "index": 0, + "invocation_id": "inv-repeat-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I like quiet focus blocks in the morning." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "repeat-agent-1", + "index": 1, + "invocation_id": "inv-repeat-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will remember your quiet focus block preference." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": { + "quiet focus": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "I will remember your quiet focus block preference." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "I like quiet focus blocks in the morning." + } + ], + "timestamp": "" + } + ] + }, + "session": { + "app_name": "replay-57954-1783081772144-repeat_memory_store", + "id": "repeat-memory", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-repeat_memory_store", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "repeat-user-1", + "index": 0, + "invocation_id": "inv-repeat-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I like quiet focus blocks in the morning." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "repeat-agent-1", + "index": 1, + "invocation_id": "inv-repeat-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will remember your quiet focus block preference." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "repeat-memory", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "partial_event_not_persisted", + "description": "streaming partial events are ignored and only final events are replayed", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "partial_event_not_persisted", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "partial-user-1", + "index": 0, + "invocation_id": "inv-partial-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Stream the answer, then persist only the final response." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "partial-agent-final", + "index": 1, + "invocation_id": "inv-partial-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Final streamed answer persisted once." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-partial_event_not_persisted", + "id": "partial-stream", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-partial_event_not_persisted", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "partial-user-1", + "index": 0, + "invocation_id": "inv-partial-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Stream the answer, then persist only the final response." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "partial-agent-final", + "index": 1, + "invocation_id": "inv-partial-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Final streamed answer persisted once." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "partial-stream", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "partial_event_not_persisted", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "partial-user-1", + "index": 0, + "invocation_id": "inv-partial-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Stream the answer, then persist only the final response." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "partial-agent-final", + "index": 1, + "invocation_id": "inv-partial-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Final streamed answer persisted once." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-partial_event_not_persisted", + "id": "partial-stream", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-partial_event_not_persisted", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "partial-user-1", + "index": 0, + "invocation_id": "inv-partial-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Stream the answer, then persist only the final response." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "partial-agent-final", + "index": 1, + "invocation_id": "inv-partial-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Final streamed answer persisted once." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "partial-stream", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "cross_session_user_isolation", + "description": "multiple sessions and users keep session state, events, and memory keys scoped correctly", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "cross_session_user_isolation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "isolation-alpha-user-1", + "index": 0, + "invocation_id": "inv-isolation-alpha-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alpha session prefers red tea." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "scope": "alpha-active" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "isolation-alpha-agent-1", + "index": 1, + "invocation_id": "inv-isolation-alpha-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alpha red tea preference is recorded." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": { + "alpha_black_coffee_other_user": [], + "alpha_red_tea": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Alpha red tea preference is recorded." + } + ], + "timestamp": "" + }, + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Beta green tea preference is recorded." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Alpha session prefers red tea." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Beta session prefers green tea." + } + ], + "timestamp": "" + } + ], + "outsider_black_coffee": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Outsider black coffee preference is recorded." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Outsider session prefers black coffee." + } + ], + "timestamp": "" + } + ] + }, + "session": { + "app_name": "replay-57954-1783081772144-cross_session_user_isolation", + "id": "isolation-alpha", + "last_update_time": "", + "state": { + "scope": "alpha-active" + }, + "user_id": "replay-user" + }, + "sessions": { + "alpha": { + "app_name": "replay-57954-1783081772144-cross_session_user_isolation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "isolation-alpha-user-1", + "index": 0, + "invocation_id": "inv-isolation-alpha-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alpha session prefers red tea." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "scope": "alpha-active" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "isolation-alpha-agent-1", + "index": 1, + "invocation_id": "inv-isolation-alpha-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alpha red tea preference is recorded." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "isolation-alpha", + "last_update_time": "", + "state": { + "scope": "alpha-active" + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + }, + "beta": { + "app_name": "replay-57954-1783081772144-cross_session_user_isolation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "isolation-beta-user-1", + "index": 0, + "invocation_id": "inv-isolation-beta-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Beta session prefers green tea." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "scope": "beta-active" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "isolation-beta-agent-1", + "index": 1, + "invocation_id": "inv-isolation-beta-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Beta green tea preference is recorded." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "isolation-beta", + "last_update_time": "", + "state": { + "scope": "beta-active" + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + }, + "outsider": { + "app_name": "replay-57954-1783081772144-cross_session_user_isolation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "isolation-outsider-user-1", + "index": 0, + "invocation_id": "inv-isolation-outsider-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Outsider session prefers black coffee." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "scope": "outsider-active" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "isolation-outsider-agent-1", + "index": 1, + "invocation_id": "inv-isolation-outsider-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Outsider black coffee preference is recorded." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "isolation-outsider", + "last_update_time": "", + "state": { + "scope": "outsider-active" + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "other-replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "cross_session_user_isolation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "isolation-alpha-user-1", + "index": 0, + "invocation_id": "inv-isolation-alpha-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alpha session prefers red tea." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "scope": "alpha-active" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "isolation-alpha-agent-1", + "index": 1, + "invocation_id": "inv-isolation-alpha-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alpha red tea preference is recorded." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": { + "alpha_black_coffee_other_user": [], + "alpha_red_tea": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Alpha red tea preference is recorded." + } + ], + "timestamp": "" + }, + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Beta green tea preference is recorded." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Alpha session prefers red tea." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Beta session prefers green tea." + } + ], + "timestamp": "" + } + ], + "outsider_black_coffee": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Outsider black coffee preference is recorded." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Outsider session prefers black coffee." + } + ], + "timestamp": "" + } + ] + }, + "session": { + "app_name": "replay-57954-1783081772144-cross_session_user_isolation", + "id": "isolation-alpha", + "last_update_time": "", + "state": { + "scope": "alpha-active" + }, + "user_id": "replay-user" + }, + "sessions": { + "alpha": { + "app_name": "replay-57954-1783081772144-cross_session_user_isolation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "isolation-alpha-user-1", + "index": 0, + "invocation_id": "inv-isolation-alpha-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alpha session prefers red tea." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "scope": "alpha-active" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "isolation-alpha-agent-1", + "index": 1, + "invocation_id": "inv-isolation-alpha-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alpha red tea preference is recorded." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "isolation-alpha", + "last_update_time": "", + "state": { + "scope": "alpha-active" + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + }, + "beta": { + "app_name": "replay-57954-1783081772144-cross_session_user_isolation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "isolation-beta-user-1", + "index": 0, + "invocation_id": "inv-isolation-beta-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Beta session prefers green tea." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "scope": "beta-active" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "isolation-beta-agent-1", + "index": 1, + "invocation_id": "inv-isolation-beta-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Beta green tea preference is recorded." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "isolation-beta", + "last_update_time": "", + "state": { + "scope": "beta-active" + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + }, + "outsider": { + "app_name": "replay-57954-1783081772144-cross_session_user_isolation", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "isolation-outsider-user-1", + "index": 0, + "invocation_id": "inv-isolation-outsider-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Outsider session prefers black coffee." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": { + "scope": "outsider-active" + }, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "isolation-outsider-agent-1", + "index": 1, + "invocation_id": "inv-isolation-outsider-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Outsider black coffee preference is recorded." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "isolation-outsider", + "last_update_time": "", + "state": { + "scope": "outsider-active" + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "other-replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "event_metadata_roundtrip", + "description": "optional event metadata survives backend serialization and replay", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "event_metadata_roundtrip", + "events": [ + { + "author": "agent", + "branch": "root.planner.worker", + "filter_key": "root/planner/worker", + "id": "metadata-tool-call-1", + "index": 0, + "invocation_id": "inv-metadata-1", + "is_summary": false, + "long_running_tool_ids": [ + "schedule_job_call" + ], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": "inv-parent-1", + "partial": false, + "parts": [ + { + "args": { + "job": "nightly-report", + "priority": 3 + }, + "kind": "function_call", + "name": "schedule_job" + } + ], + "request_id": "req-metadata-1", + "requires_completion": true, + "state_delta": {}, + "tag": "planning", + "timestamp": "", + "version": 7, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "metadata-agent-hidden-1", + "index": 1, + "invocation_id": "inv-metadata-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 0, + "model_visible": false, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Internal planning note should keep visibility metadata." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": "internal-note", + "timestamp": "", + "version": 0, + "visible": false + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-event_metadata_roundtrip", + "id": "event-metadata", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-event_metadata_roundtrip", + "events": [ + { + "author": "agent", + "branch": "root.planner.worker", + "filter_key": "root/planner/worker", + "id": "metadata-tool-call-1", + "index": 0, + "invocation_id": "inv-metadata-1", + "is_summary": false, + "long_running_tool_ids": [ + "schedule_job_call" + ], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": "inv-parent-1", + "partial": false, + "parts": [ + { + "args": { + "job": "nightly-report", + "priority": 3 + }, + "kind": "function_call", + "name": "schedule_job" + } + ], + "request_id": "req-metadata-1", + "requires_completion": true, + "state_delta": {}, + "tag": "planning", + "timestamp": "", + "version": 7, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "metadata-agent-hidden-1", + "index": 1, + "invocation_id": "inv-metadata-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 0, + "model_visible": false, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Internal planning note should keep visibility metadata." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": "internal-note", + "timestamp": "", + "version": 0, + "visible": false + } + ], + "historical_events": [], + "id": "event-metadata", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "event_metadata_roundtrip", + "events": [ + { + "author": "agent", + "branch": "root.planner.worker", + "filter_key": "root/planner/worker", + "id": "metadata-tool-call-1", + "index": 0, + "invocation_id": "inv-metadata-1", + "is_summary": false, + "long_running_tool_ids": [ + "schedule_job_call" + ], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": "inv-parent-1", + "partial": false, + "parts": [ + { + "args": { + "job": "nightly-report", + "priority": 3 + }, + "kind": "function_call", + "name": "schedule_job" + } + ], + "request_id": "req-metadata-1", + "requires_completion": true, + "state_delta": {}, + "tag": "planning", + "timestamp": "", + "version": 7, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "metadata-agent-hidden-1", + "index": 1, + "invocation_id": "inv-metadata-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 0, + "model_visible": false, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Internal planning note should keep visibility metadata." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": "internal-note", + "timestamp": "", + "version": 0, + "visible": false + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-event_metadata_roundtrip", + "id": "event-metadata", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-event_metadata_roundtrip", + "events": [ + { + "author": "agent", + "branch": "root.planner.worker", + "filter_key": "root/planner/worker", + "id": "metadata-tool-call-1", + "index": 0, + "invocation_id": "inv-metadata-1", + "is_summary": false, + "long_running_tool_ids": [ + "schedule_job_call" + ], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": "inv-parent-1", + "partial": false, + "parts": [ + { + "args": { + "job": "nightly-report", + "priority": 3 + }, + "kind": "function_call", + "name": "schedule_job" + } + ], + "request_id": "req-metadata-1", + "requires_completion": true, + "state_delta": {}, + "tag": "planning", + "timestamp": "", + "version": 7, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "metadata-agent-hidden-1", + "index": 1, + "invocation_id": "inv-metadata-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 0, + "model_visible": false, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Internal planning note should keep visibility metadata." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": "internal-note", + "timestamp": "", + "version": 0, + "visible": false + } + ], + "historical_events": [], + "id": "event-metadata", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 2, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "multi_part_event_roundtrip", + "description": "events with multiple ordered parts keep mixed text, function_call, and function_response payloads", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "multi_part_event_roundtrip", + "events": [ + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "multi-part-agent-1", + "index": 0, + "invocation_id": "inv-multipart-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will calculate the route first." + }, + { + "args": { + "from": "Nanshan", + "to": "Futian" + }, + "kind": "function_call", + "name": "route_lookup" + }, + { + "kind": "function_response", + "name": "route_lookup", + "response": { + "duration_minutes": 28, + "line": "metro" + } + }, + { + "kind": "text", + "text": "The metro route takes 28 minutes." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-multi_part_event_roundtrip", + "id": "multi-part", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-multi_part_event_roundtrip", + "events": [ + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "multi-part-agent-1", + "index": 0, + "invocation_id": "inv-multipart-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will calculate the route first." + }, + { + "args": { + "from": "Nanshan", + "to": "Futian" + }, + "kind": "function_call", + "name": "route_lookup" + }, + { + "kind": "function_response", + "name": "route_lookup", + "response": { + "duration_minutes": 28, + "line": "metro" + } + }, + { + "kind": "text", + "text": "The metro route takes 28 minutes." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "multi-part", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 1, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 1, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "multi_part_event_roundtrip", + "events": [ + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "multi-part-agent-1", + "index": 0, + "invocation_id": "inv-multipart-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will calculate the route first." + }, + { + "args": { + "from": "Nanshan", + "to": "Futian" + }, + "kind": "function_call", + "name": "route_lookup" + }, + { + "kind": "function_response", + "name": "route_lookup", + "response": { + "duration_minutes": 28, + "line": "metro" + } + }, + { + "kind": "text", + "text": "The metro route takes 28 minutes." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-multi_part_event_roundtrip", + "id": "multi-part", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-multi_part_event_roundtrip", + "events": [ + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "multi-part-agent-1", + "index": 0, + "invocation_id": "inv-multipart-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "I will calculate the route first." + }, + { + "args": { + "from": "Nanshan", + "to": "Futian" + }, + "kind": "function_call", + "name": "route_lookup" + }, + { + "kind": "function_response", + "name": "route_lookup", + "response": { + "duration_minutes": 28, + "line": "metro" + } + }, + { + "kind": "text", + "text": "The metro route takes 28 minutes." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "multi-part", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 1, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 1, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "memory_after_summary_truncation", + "description": "memory stored after summary compression can still recall summarized facts and retained recent facts", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "memory_after_summary_truncation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "mem-summary-user-2", + "index": 1, + "invocation_id": "inv-mem-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Jupiter launch belongs to Bob." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "mem-summary-agent-2", + "index": 2, + "invocation_id": "inv-mem-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Bob owns the Jupiter launch." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "mem-summary-user-1", + "index": 0, + "invocation_id": "inv-mem-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Mercury milestone belongs to Alice." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "mem-summary-agent-1", + "index": 1, + "invocation_id": "inv-mem-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alice owns the Mercury milestone." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "memory": { + "retained_jupiter_memory": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Bob owns the Jupiter launch." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Jupiter launch belongs to Bob." + } + ], + "timestamp": "" + } + ], + "summarized_mercury_memory": [ + { + "author": "system", + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]" + } + ], + "timestamp": "" + } + ] + }, + "session": { + "app_name": "replay-57954-1783081772144-memory_after_summary_truncation", + "id": "memory-after-summary", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-memory_after_summary_truncation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "mem-summary-user-2", + "index": 1, + "invocation_id": "inv-mem-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Jupiter launch belongs to Bob." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "mem-summary-agent-2", + "index": 2, + "invocation_id": "inv-mem-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Bob owns the Jupiter launch." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "mem-summary-user-1", + "index": 0, + "invocation_id": "inv-mem-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Mercury milestone belongs to Alice." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "mem-summary-agent-1", + "index": 1, + "invocation_id": "inv-mem-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alice owns the Mercury milestone." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "id": "memory-after-summary", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 2, + "historical_summary_count": 0, + "id": "memory-after-summary:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 3, + "session_id": "memory-after-summary", + "text": "memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "memory-after-summary", + "source": "active", + "summary_id": "memory-after-summary:summary:v1", + "text": "memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 2, + "historical_summary_count": 0, + "id": "memory-after-summary:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 3, + "service_manager_compressed_event_count": 3, + "service_manager_exists": true, + "service_manager_original_event_count": 4, + "service_manager_session_id": "memory-after-summary", + "service_manager_text": "memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "service_manager_updated_at": "", + "service_public_exists": true, + "service_public_text": "memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "session_id": "memory-after-summary", + "text": "memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "memory-after-summary", + "source": "active", + "summary_id": "memory-after-summary:summary:v1", + "text": "memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + } + }, + { + "backend": "sqlite", + "case": "memory_after_summary_truncation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "mem-summary-user-2", + "index": 1, + "invocation_id": "inv-mem-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Jupiter launch belongs to Bob." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "mem-summary-agent-2", + "index": 2, + "invocation_id": "inv-mem-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Bob owns the Jupiter launch." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "mem-summary-user-1", + "index": 0, + "invocation_id": "inv-mem-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Mercury milestone belongs to Alice." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "mem-summary-agent-1", + "index": 1, + "invocation_id": "inv-mem-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alice owns the Mercury milestone." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "memory": { + "retained_jupiter_memory": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Bob owns the Jupiter launch." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Jupiter launch belongs to Bob." + } + ], + "timestamp": "" + } + ], + "summarized_mercury_memory": [ + { + "author": "system", + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]" + } + ], + "timestamp": "" + } + ] + }, + "session": { + "app_name": "replay-57954-1783081772144-memory_after_summary_truncation", + "id": "memory-after-summary", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-memory_after_summary_truncation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "mem-summary-user-2", + "index": 1, + "invocation_id": "inv-mem-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Jupiter launch belongs to Bob." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "mem-summary-agent-2", + "index": 2, + "invocation_id": "inv-mem-summary-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Bob owns the Jupiter launch." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "mem-summary-user-1", + "index": 0, + "invocation_id": "inv-mem-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Mercury milestone belongs to Alice." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "mem-summary-agent-1", + "index": 1, + "invocation_id": "inv-mem-summary-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alice owns the Mercury milestone." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "id": "memory-after-summary", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 2, + "historical_summary_count": 0, + "id": "memory-after-summary:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 3, + "session_id": "memory-after-summary", + "text": "memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "memory-after-summary", + "source": "active", + "summary_id": "memory-after-summary:summary:v1", + "text": "memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 2, + "historical_summary_count": 0, + "id": "memory-after-summary:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 3, + "service_manager_compressed_event_count": 3, + "service_manager_exists": true, + "service_manager_original_event_count": 4, + "service_manager_session_id": "memory-after-summary", + "service_manager_text": "memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "service_manager_updated_at": "", + "service_public_exists": true, + "service_public_text": "memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "session_id": "memory-after-summary", + "text": "memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "memory-after-summary", + "source": "active", + "summary_id": "memory-after-summary:summary:v1", + "text": "memory-after-summary: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"mercury milestone belongs to alice.\"}]}, {\"author\": \"agent\", \"parts\": [{\"kind\": \"text\", \"text\": \"alice owns the mercury milestone.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "memory_multi_result_recall", + "description": "multiple matching memories are recalled without dropping records across backends", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "memory_multi_result_recall", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "memory-multi-user-1", + "index": 0, + "invocation_id": "inv-memory-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note one is about calm mornings." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "memory-multi-agent-1", + "index": 1, + "invocation_id": "inv-memory-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note one is stored." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "memory-multi-user-2", + "index": 2, + "invocation_id": "inv-memory-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note two is about quiet afternoons." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "memory-multi-agent-2", + "index": 3, + "invocation_id": "inv-memory-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note two is stored." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": { + "calm_single_match": [ + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Orchid note one is about calm mornings." + } + ], + "timestamp": "" + } + ], + "orchid_all_matches": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Orchid note one is stored." + } + ], + "timestamp": "" + }, + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Orchid note two is stored." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Orchid note one is about calm mornings." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Orchid note two is about quiet afternoons." + } + ], + "timestamp": "" + } + ] + }, + "session": { + "app_name": "replay-57954-1783081772144-memory_multi_result_recall", + "id": "memory-multi-result", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-memory_multi_result_recall", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "memory-multi-user-1", + "index": 0, + "invocation_id": "inv-memory-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note one is about calm mornings." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "memory-multi-agent-1", + "index": 1, + "invocation_id": "inv-memory-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note one is stored." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "memory-multi-user-2", + "index": 2, + "invocation_id": "inv-memory-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note two is about quiet afternoons." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "memory-multi-agent-2", + "index": 3, + "invocation_id": "inv-memory-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note two is stored." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "memory-multi-result", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 4, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 4, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + }, + { + "backend": "sqlite", + "case": "memory_multi_result_recall", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "memory-multi-user-1", + "index": 0, + "invocation_id": "inv-memory-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note one is about calm mornings." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "memory-multi-agent-1", + "index": 1, + "invocation_id": "inv-memory-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note one is stored." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "memory-multi-user-2", + "index": 2, + "invocation_id": "inv-memory-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note two is about quiet afternoons." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "memory-multi-agent-2", + "index": 3, + "invocation_id": "inv-memory-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note two is stored." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "memory": { + "calm_single_match": [ + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Orchid note one is about calm mornings." + } + ], + "timestamp": "" + } + ], + "orchid_all_matches": [ + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Orchid note one is stored." + } + ], + "timestamp": "" + }, + { + "author": "agent", + "parts": [ + { + "kind": "text", + "text": "Orchid note two is stored." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Orchid note one is about calm mornings." + } + ], + "timestamp": "" + }, + { + "author": "user", + "parts": [ + { + "kind": "text", + "text": "Orchid note two is about quiet afternoons." + } + ], + "timestamp": "" + } + ] + }, + "session": { + "app_name": "replay-57954-1783081772144-memory_multi_result_recall", + "id": "memory-multi-result", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "default": { + "app_name": "replay-57954-1783081772144-memory_multi_result_recall", + "events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "memory-multi-user-1", + "index": 0, + "invocation_id": "inv-memory-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note one is about calm mornings." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "memory-multi-agent-1", + "index": 1, + "invocation_id": "inv-memory-multi-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note one is stored." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "memory-multi-user-2", + "index": 2, + "invocation_id": "inv-memory-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note two is about quiet afternoons." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + }, + { + "author": "agent", + "branch": null, + "filter_key": null, + "id": "memory-multi-agent-2", + "index": 3, + "invocation_id": "inv-memory-multi-2", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Orchid note two is stored." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [], + "id": "memory-multi-result", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 4, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 0, + "anchor_text": null, + "exists": false, + "has_summary_anchor": false, + "historical_event_count": 0, + "historical_summary_count": 0, + "id": null, + "latest_version_active": null, + "latest_version_source": null, + "retained_event_count": 4, + "service_manager_compressed_event_count": null, + "service_manager_exists": false, + "service_manager_original_event_count": null, + "service_manager_session_id": null, + "service_manager_text": null, + "service_manager_updated_at": null, + "service_public_exists": false, + "service_public_text": null, + "session_id": null, + "text": null, + "updated_at": null, + "updated_at_present": false, + "version": 0, + "versions": [] + } + } + ] + }, + { + "backends": [ + "in_memory", + "sqlite" + ], + "case": "cross_session_summary_isolation", + "description": "summaries for two sessions under one user keep owner, version, and text isolated without depending on backend event-window trimming", + "diffs": [], + "errors": [], + "snapshots": [ + { + "backend": "in_memory", + "case": "cross_session_summary_isolation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-owner-alpha-user-1", + "index": 0, + "invocation_id": "inv-summary-owner-alpha-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alpha roadmap starts with billing cleanup." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-cross_session_summary_isolation", + "id": "summary-owner-alpha", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "alpha": { + "app_name": "replay-57954-1783081772144-cross_session_summary_isolation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-owner-alpha-user-1", + "index": 0, + "invocation_id": "inv-summary-owner-alpha-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alpha roadmap starts with billing cleanup." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "id": "summary-owner-alpha", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 1, + "historical_summary_count": 0, + "id": "summary-owner-alpha:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 1, + "session_id": "summary-owner-alpha", + "text": "summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "summary-owner-alpha", + "source": "active", + "summary_id": "summary-owner-alpha:summary:v1", + "text": "summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + }, + "user_id": "replay-user" + }, + "beta": { + "app_name": "replay-57954-1783081772144-cross_session_summary_isolation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-owner-beta: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"beta roadmap starts with search ranking.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-owner-beta-user-1", + "index": 0, + "invocation_id": "inv-summary-owner-beta-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Beta roadmap starts with search ranking." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "id": "summary-owner-beta", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-owner-beta: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"beta roadmap starts with search ranking.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 1, + "historical_summary_count": 0, + "id": "summary-owner-beta:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 1, + "session_id": "summary-owner-beta", + "text": "summary-owner-beta: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"beta roadmap starts with search ranking.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "summary-owner-beta", + "source": "active", + "summary_id": "summary-owner-beta:summary:v1", + "text": "summary-owner-beta: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"beta roadmap starts with search ranking.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 1, + "historical_summary_count": 0, + "id": "summary-owner-alpha:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 1, + "service_manager_compressed_event_count": 1, + "service_manager_exists": true, + "service_manager_original_event_count": 1, + "service_manager_session_id": "summary-owner-alpha", + "service_manager_text": "summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "service_manager_updated_at": "", + "service_public_exists": true, + "service_public_text": "summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "session_id": "summary-owner-alpha", + "text": "summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "summary-owner-alpha", + "source": "active", + "summary_id": "summary-owner-alpha:summary:v1", + "text": "summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + } + }, + { + "backend": "sqlite", + "case": "cross_session_summary_isolation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-owner-alpha-user-1", + "index": 0, + "invocation_id": "inv-summary-owner-alpha-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alpha roadmap starts with billing cleanup." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "memory": {}, + "session": { + "app_name": "replay-57954-1783081772144-cross_session_summary_isolation", + "id": "summary-owner-alpha", + "last_update_time": "", + "state": {}, + "user_id": "replay-user" + }, + "sessions": { + "alpha": { + "app_name": "replay-57954-1783081772144-cross_session_summary_isolation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-owner-alpha-user-1", + "index": 0, + "invocation_id": "inv-summary-owner-alpha-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Alpha roadmap starts with billing cleanup." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "id": "summary-owner-alpha", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 1, + "historical_summary_count": 0, + "id": "summary-owner-alpha:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 1, + "session_id": "summary-owner-alpha", + "text": "summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "summary-owner-alpha", + "source": "active", + "summary_id": "summary-owner-alpha:summary:v1", + "text": "summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + }, + "user_id": "replay-user" + }, + "beta": { + "app_name": "replay-57954-1783081772144-cross_session_summary_isolation", + "events": [ + { + "author": "system", + "branch": null, + "filter_key": null, + "id": "", + "index": 0, + "invocation_id": "summary", + "is_summary": true, + "long_running_tool_ids": [], + "model_flags": 3, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Previous conversation summary: summary-owner-beta: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"beta roadmap starts with search ranking.\"}]}]" + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "historical_events": [ + { + "author": "user", + "branch": null, + "filter_key": null, + "id": "summary-owner-beta-user-1", + "index": 0, + "invocation_id": "inv-summary-owner-beta-1", + "is_summary": false, + "long_running_tool_ids": [], + "model_flags": 1, + "model_visible": true, + "parent_invocation_id": null, + "partial": false, + "parts": [ + { + "kind": "text", + "text": "Beta roadmap starts with search ranking." + } + ], + "request_id": null, + "requires_completion": false, + "state_delta": {}, + "tag": null, + "timestamp": "", + "version": 0, + "visible": true + } + ], + "id": "summary-owner-beta", + "last_update_time": "", + "state": {}, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-owner-beta: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"beta roadmap starts with search ranking.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 1, + "historical_summary_count": 0, + "id": "summary-owner-beta:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 1, + "session_id": "summary-owner-beta", + "text": "summary-owner-beta: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"beta roadmap starts with search ranking.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "summary-owner-beta", + "source": "active", + "summary_id": "summary-owner-beta:summary:v1", + "text": "summary-owner-beta: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"beta roadmap starts with search ranking.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + }, + "user_id": "replay-user" + } + }, + "summary": { + "active_summary_count": 1, + "anchor_text": "previous conversation summary: summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "exists": true, + "has_summary_anchor": true, + "historical_event_count": 1, + "historical_summary_count": 0, + "id": "summary-owner-alpha:summary:v1", + "latest_version_active": true, + "latest_version_source": "active", + "retained_event_count": 1, + "service_manager_compressed_event_count": 1, + "service_manager_exists": true, + "service_manager_original_event_count": 1, + "service_manager_session_id": "summary-owner-alpha", + "service_manager_text": "summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "service_manager_updated_at": "", + "service_public_exists": true, + "service_public_text": "summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "session_id": "summary-owner-alpha", + "text": "summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1, + "versions": [ + { + "active": true, + "session_id": "summary-owner-alpha", + "source": "active", + "summary_id": "summary-owner-alpha:summary:v1", + "text": "summary-owner-alpha: [{\"author\": \"user\", \"parts\": [{\"kind\": \"text\", \"text\": \"alpha roadmap starts with billing cleanup.\"}]}]", + "updated_at": "", + "updated_at_present": true, + "version": 1 + } + ] + } + } + ] + } + ], + "coverage": { + "backend_error_count": 0, + "case_count": 18, + "normal_diff_count": 0, + "normal_false_positive_rate": 0.0 + }, + "duration_seconds": 0.43886, + "errors": [], + "mode": { + "attempted_backends": [ + "in_memory", + "sqlite" + ], + "failed_backends": [], + "lightweight": true, + "redis_env_attempted": false, + "redis_env_failed": false, + "redis_env_has_snapshot": false, + "selected_backends": null, + "snapshot_backends": [ + "in_memory", + "sqlite" + ], + "sql_env_attempted": false, + "sql_env_failed": false, + "sql_env_has_snapshot": false + } +} \ No newline at end of file diff --git a/tests/sessions/replay_cases/session_memory_summary_replay_cases.jsonl b/tests/sessions/replay_cases/session_memory_summary_replay_cases.jsonl new file mode 100644 index 00000000..11ee321a --- /dev/null +++ b/tests/sessions/replay_cases/session_memory_summary_replay_cases.jsonl @@ -0,0 +1,18 @@ +{"name":"single_turn_conversation","description":"single user input and assistant text output","operations":[{"op":"create_session","session_id":"single-turn"},{"op":"append_text","event_id":"single-user-1","invocation_id":"inv-single-1","author":"user","text":"Hello assistant","timestamp":1000.0},{"op":"append_text","event_id":"single-agent-1","invocation_id":"inv-single-1","author":"agent","text":"Hello, how can I help?","timestamp":1001.0}],"memory_queries":[]} +{"name":"multi_turn_conversation","description":"multiple user and assistant turns are replayed in order","operations":[{"op":"create_session","session_id":"multi-turn"},{"op":"append_text","event_id":"multi-user-1","invocation_id":"inv-multi-1","author":"user","text":"Plan a trip to Shenzhen","timestamp":1010.0},{"op":"append_text","event_id":"multi-agent-1","invocation_id":"inv-multi-1","author":"agent","text":"I can help with transport and food.","timestamp":1011.0},{"op":"append_text","event_id":"multi-user-2","invocation_id":"inv-multi-2","author":"user","text":"Keep it under 1000 yuan","timestamp":1012.0},{"op":"append_text","event_id":"multi-agent-2","invocation_id":"inv-multi-2","author":"agent","text":"I will optimize for budget travel.","timestamp":1013.0}],"memory_queries":[]} +{"name":"tool_call_conversation","description":"function_call and function_response parts survive backend replay","operations":[{"op":"create_session","session_id":"tool-turn"},{"op":"append_text","event_id":"tool-user-1","invocation_id":"inv-tool-1","author":"user","text":"What is the weather in Beijing?","timestamp":1020.0},{"op":"append_tool_call","event_id":"tool-call-1","invocation_id":"inv-tool-1","author":"agent","name":"get_weather","args":{"city":"Beijing","unit":"celsius"},"timestamp":1021.0},{"op":"append_tool_response","event_id":"tool-response-1","invocation_id":"inv-tool-1","author":"tool","name":"get_weather","response":{"city":"Beijing","temperature":29,"condition":"sunny"},"timestamp":1022.0},{"op":"append_text","event_id":"tool-agent-1","invocation_id":"inv-tool-1","author":"agent","text":"Beijing is sunny and 29 C.","timestamp":1023.0}],"memory_queries":[]} +{"name":"state_overwrite","description":"session, app, user, and temp state updates follow storage semantics","operations":[{"op":"create_session","session_id":"state-overwrite","state":{"topic":"initial","app:locale":"zh-CN","user:tier":"free"}},{"op":"append_text","event_id":"state-user-1","invocation_id":"inv-state-1","author":"user","text":"Remember my dashboard choices","state_delta":{"topic":"dashboard","app:locale":"en-US","user:tier":"pro","temp:trace":"not-persisted"},"timestamp":1030.0},{"op":"append_text","event_id":"state-agent-1","invocation_id":"inv-state-1","author":"agent","text":"Saved your dashboard choices.","state_delta":{"topic":"dashboard-v2","user:tier":"enterprise"},"timestamp":1031.0}],"memory_queries":[]} +{"name":"memory_preference_write_read","description":"stored session memory can retrieve a user preference","operations":[{"op":"create_session","session_id":"memory-preference"},{"op":"append_text","event_id":"memory-user-1","invocation_id":"inv-memory-1","author":"user","text":"I prefer jasmine tea in the afternoon.","timestamp":1040.0},{"op":"append_text","event_id":"memory-agent-1","invocation_id":"inv-memory-1","author":"agent","text":"I will remember your jasmine tea preference.","timestamp":1041.0},{"op":"store_memory"}],"memory_queries":[{"query":"jasmine tea","limit":5}]} +{"name":"memory_fact_write_read","description":"stored session memory can retrieve a factual note","operations":[{"op":"create_session","session_id":"memory-fact"},{"op":"append_text","event_id":"fact-user-1","invocation_id":"inv-fact-1","author":"user","text":"My project codename is Blue River.","timestamp":1050.0},{"op":"append_text","event_id":"fact-agent-1","invocation_id":"inv-fact-1","author":"agent","text":"Noted the Blue River project codename.","timestamp":1051.0},{"op":"store_memory"}],"memory_queries":[{"query":"Blue River","limit":5}]} +{"name":"summary_create_update","description":"summary can be generated and then updated after later turns","operations":[{"op":"create_session","session_id":"summary-update"},{"op":"append_text","event_id":"summary-user-1","invocation_id":"inv-summary-1","author":"user","text":"We need a launch checklist for Friday.","timestamp":1060.0},{"op":"append_text","event_id":"summary-agent-1","invocation_id":"inv-summary-1","author":"agent","text":"Checklist includes QA, docs, and rollback plan.","timestamp":1061.0},{"op":"append_text","event_id":"summary-user-2","invocation_id":"inv-summary-2","author":"user","text":"Add owner Alice for QA.","timestamp":1062.0},{"op":"append_text","event_id":"summary-agent-2","invocation_id":"inv-summary-2","author":"agent","text":"Alice owns QA before launch.","timestamp":1063.0},{"op":"summarize"},{"op":"append_text","event_id":"summary-user-3","invocation_id":"inv-summary-3","author":"user","text":"Bob owns release notes.","timestamp":1064.0},{"op":"append_text","event_id":"summary-agent-3","invocation_id":"inv-summary-3","author":"agent","text":"Bob owns release notes for Friday.","timestamp":1065.0},{"op":"summarize"}],"memory_queries":[]} +{"name":"summary_event_truncation","description":"summary anchor plus retained recent events reconstruct context after compression","operations":[{"op":"create_session","session_id":"summary-truncate"},{"op":"append_text","event_id":"truncate-user-1","invocation_id":"inv-truncate-1","author":"user","text":"Long discussion part one about onboarding.","timestamp":1070.0},{"op":"append_text","event_id":"truncate-agent-1","invocation_id":"inv-truncate-1","author":"agent","text":"Onboarding needs account setup and training.","timestamp":1071.0},{"op":"append_text","event_id":"truncate-user-2","invocation_id":"inv-truncate-2","author":"user","text":"Include security approval before access.","timestamp":1072.0},{"op":"append_text","event_id":"truncate-agent-2","invocation_id":"inv-truncate-2","author":"agent","text":"Security approval comes before account access.","timestamp":1073.0},{"op":"append_text","event_id":"truncate-user-3","invocation_id":"inv-truncate-3","author":"user","text":"Schedule training on Wednesday.","timestamp":1074.0},{"op":"append_text","event_id":"truncate-agent-3","invocation_id":"inv-truncate-3","author":"agent","text":"Training is scheduled on Wednesday.","timestamp":1075.0},{"op":"summarize"},{"op":"append_text","event_id":"truncate-user-4","invocation_id":"inv-truncate-4","author":"user","text":"After summary, remind me about Wednesday training.","timestamp":1076.0},{"op":"append_text","event_id":"truncate-agent-4","invocation_id":"inv-truncate-4","author":"agent","text":"I will keep Wednesday training in context.","timestamp":1077.0}],"memory_queries":[]} +{"name":"failed_append_recovery","description":"a failed append before persistence leaves no dirty event or dirty state","operations":[{"op":"create_session","session_id":"failed-recovery","state":{"phase":"clean"}},{"op":"append_text","event_id":"failed-user-1","invocation_id":"inv-failed-1","author":"user","text":"This event is persisted.","state_delta":{"phase":"persisted"},"timestamp":1080.0},{"op":"failed_append","event_id":"failed-agent-dirty","invocation_id":"inv-failed-2","author":"agent","text":"This failed event must not persist.","state_delta":{"phase":"dirty"},"timestamp":1081.0},{"op":"append_text","event_id":"failed-agent-1","invocation_id":"inv-failed-3","author":"agent","text":"State remains clean after recovery.","timestamp":1082.0}],"memory_queries":[]} +{"name":"duplicate_event_write_recovery","description":"a failed retry with a duplicate event id leaves no duplicate event, dirty state, or stale text","operations":[{"op":"create_session","session_id":"duplicate-event-recovery","state":{"phase":"clean"}},{"op":"append_text","event_id":"duplicate-user-1","invocation_id":"inv-duplicate-1","author":"user","text":"This event is persisted once.","state_delta":{"phase":"persisted-once"},"timestamp":1085.0},{"op":"failed_append","event_id":"duplicate-user-1","invocation_id":"inv-duplicate-retry","author":"user","text":"This duplicate retry must not persist.","state_delta":{"phase":"dirty-duplicate"},"timestamp":1086.0},{"op":"append_text","event_id":"duplicate-agent-1","invocation_id":"inv-duplicate-2","author":"agent","text":"Duplicate retry did not change stored context.","timestamp":1087.0}],"memory_queries":[]} +{"name":"repeat_memory_store","description":"repeating the same memory write does not duplicate retrieved memories","operations":[{"op":"create_session","session_id":"repeat-memory"},{"op":"append_text","event_id":"repeat-user-1","invocation_id":"inv-repeat-1","author":"user","text":"I like quiet focus blocks in the morning.","timestamp":1090.0},{"op":"append_text","event_id":"repeat-agent-1","invocation_id":"inv-repeat-1","author":"agent","text":"I will remember your quiet focus block preference.","timestamp":1091.0},{"op":"store_memory"},{"op":"store_memory"}],"memory_queries":[{"query":"quiet focus","limit":10}]} +{"name":"partial_event_not_persisted","description":"streaming partial events are ignored and only final events are replayed","operations":[{"op":"create_session","session_id":"partial-stream"},{"op":"append_text","event_id":"partial-user-1","invocation_id":"inv-partial-1","author":"user","text":"Stream the answer, then persist only the final response.","timestamp":1100.0},{"op":"append_text","event_id":"partial-agent-draft","invocation_id":"inv-partial-1","author":"agent","text":"draft chunk that must not persist","partial":true,"timestamp":1101.0},{"op":"append_text","event_id":"partial-agent-final","invocation_id":"inv-partial-1","author":"agent","text":"Final streamed answer persisted once.","timestamp":1102.0}],"memory_queries":[]} +{"name":"cross_session_user_isolation","description":"multiple sessions and users keep session state, events, and memory keys scoped correctly","primary_session_ref":"alpha","operations":[{"op":"create_session","session_ref":"alpha","session_id":"isolation-alpha","state":{"scope":"alpha"}},{"op":"append_text","session_ref":"alpha","event_id":"isolation-alpha-user-1","invocation_id":"inv-isolation-alpha-1","author":"user","text":"Alpha session prefers red tea.","state_delta":{"scope":"alpha-active"},"timestamp":1110.0},{"op":"append_text","session_ref":"alpha","event_id":"isolation-alpha-agent-1","invocation_id":"inv-isolation-alpha-1","author":"agent","text":"Alpha red tea preference is recorded.","timestamp":1111.0},{"op":"store_memory","session_ref":"alpha"},{"op":"create_session","session_ref":"beta","session_id":"isolation-beta","state":{"scope":"beta"}},{"op":"append_text","session_ref":"beta","event_id":"isolation-beta-user-1","invocation_id":"inv-isolation-beta-1","author":"user","text":"Beta session prefers green tea.","state_delta":{"scope":"beta-active"},"timestamp":1112.0},{"op":"append_text","session_ref":"beta","event_id":"isolation-beta-agent-1","invocation_id":"inv-isolation-beta-1","author":"agent","text":"Beta green tea preference is recorded.","timestamp":1113.0},{"op":"store_memory","session_ref":"beta"},{"op":"create_session","session_ref":"outsider","session_id":"isolation-outsider","user_id":"other-replay-user","state":{"scope":"outsider"}},{"op":"append_text","session_ref":"outsider","event_id":"isolation-outsider-user-1","invocation_id":"inv-isolation-outsider-1","author":"user","text":"Outsider session prefers black coffee.","state_delta":{"scope":"outsider-active"},"timestamp":1114.0},{"op":"append_text","session_ref":"outsider","event_id":"isolation-outsider-agent-1","invocation_id":"inv-isolation-outsider-1","author":"agent","text":"Outsider black coffee preference is recorded.","timestamp":1115.0},{"op":"store_memory","session_ref":"outsider"}],"memory_queries":[{"name":"alpha_red_tea","session_ref":"alpha","query":"red tea","limit":10},{"name":"alpha_black_coffee_other_user","session_ref":"alpha","query":"black coffee","limit":10},{"name":"outsider_black_coffee","session_ref":"outsider","query":"black coffee","limit":10}]} +{"name":"event_metadata_roundtrip","description":"optional event metadata survives backend serialization and replay","operations":[{"op":"create_session","session_id":"event-metadata"},{"op":"append_tool_call","event_id":"metadata-tool-call-1","invocation_id":"inv-metadata-1","author":"agent","name":"schedule_job","args":{"job":"nightly-report","priority":3},"branch":"root.planner.worker","request_id":"req-metadata-1","parent_invocation_id":"inv-parent-1","tag":"planning","filter_key":"root/planner/worker","requires_completion":true,"version":7,"long_running_tool_ids":["schedule_job_call"],"timestamp":1120.0},{"op":"append_text","event_id":"metadata-agent-hidden-1","invocation_id":"inv-metadata-2","author":"agent","text":"Internal planning note should keep visibility metadata.","visible":false,"model_flags":0,"tag":"internal-note","timestamp":1121.0}],"memory_queries":[]} +{"name":"multi_part_event_roundtrip","description":"events with multiple ordered parts keep mixed text, function_call, and function_response payloads","operations":[{"op":"create_session","session_id":"multi-part"},{"op":"append_parts","event_id":"multi-part-agent-1","invocation_id":"inv-multipart-1","author":"agent","parts":[{"kind":"text","text":"I will calculate the route first."},{"kind":"function_call","name":"route_lookup","args":{"from":"Nanshan","to":"Futian"}},{"kind":"function_response","name":"route_lookup","response":{"duration_minutes":28,"line":"metro"}},{"kind":"text","text":"The metro route takes 28 minutes."}],"timestamp":1130.0}],"memory_queries":[]} +{"name":"memory_after_summary_truncation","description":"memory stored after summary compression can still recall summarized facts and retained recent facts","operations":[{"op":"create_session","session_id":"memory-after-summary"},{"op":"append_text","event_id":"mem-summary-user-1","invocation_id":"inv-mem-summary-1","author":"user","text":"Mercury milestone belongs to Alice.","timestamp":1140.0},{"op":"append_text","event_id":"mem-summary-agent-1","invocation_id":"inv-mem-summary-1","author":"agent","text":"Alice owns the Mercury milestone.","timestamp":1141.0},{"op":"append_text","event_id":"mem-summary-user-2","invocation_id":"inv-mem-summary-2","author":"user","text":"Jupiter launch belongs to Bob.","timestamp":1142.0},{"op":"append_text","event_id":"mem-summary-agent-2","invocation_id":"inv-mem-summary-2","author":"agent","text":"Bob owns the Jupiter launch.","timestamp":1143.0},{"op":"summarize"},{"op":"store_memory"}],"memory_queries":[{"name":"summarized_mercury_memory","query":"Mercury","limit":10},{"name":"retained_jupiter_memory","query":"Jupiter","limit":10}]} +{"name":"memory_multi_result_recall","description":"multiple matching memories are recalled without dropping records across backends","operations":[{"op":"create_session","session_id":"memory-multi-result"},{"op":"append_text","event_id":"memory-multi-user-1","invocation_id":"inv-memory-multi-1","author":"user","text":"Orchid note one is about calm mornings.","timestamp":1150.0},{"op":"append_text","event_id":"memory-multi-agent-1","invocation_id":"inv-memory-multi-1","author":"agent","text":"Orchid note one is stored.","timestamp":1151.0},{"op":"append_text","event_id":"memory-multi-user-2","invocation_id":"inv-memory-multi-2","author":"user","text":"Orchid note two is about quiet afternoons.","timestamp":1152.0},{"op":"append_text","event_id":"memory-multi-agent-2","invocation_id":"inv-memory-multi-2","author":"agent","text":"Orchid note two is stored.","timestamp":1153.0},{"op":"store_memory"}],"memory_queries":[{"name":"orchid_all_matches","query":"Orchid","limit":10},{"name":"calm_single_match","query":"calm","limit":10}]} +{"name":"cross_session_summary_isolation","description":"summaries for two sessions under one user keep owner, version, and text isolated without depending on backend event-window trimming","primary_session_ref":"alpha","operations":[{"op":"create_session","session_ref":"alpha","session_id":"summary-owner-alpha"},{"op":"append_text","session_ref":"alpha","event_id":"summary-owner-alpha-user-1","invocation_id":"inv-summary-owner-alpha-1","author":"user","text":"Alpha roadmap starts with billing cleanup.","timestamp":1170.0},{"op":"summarize","session_ref":"alpha"},{"op":"create_session","session_ref":"beta","session_id":"summary-owner-beta"},{"op":"append_text","session_ref":"beta","event_id":"summary-owner-beta-user-1","invocation_id":"inv-summary-owner-beta-1","author":"user","text":"Beta roadmap starts with search ranking.","timestamp":1174.0},{"op":"summarize","session_ref":"beta"}],"memory_queries":[]} diff --git a/tests/sessions/test_replay_consistency.py b/tests/sessions/test_replay_consistency.py new file mode 100644 index 00000000..b99539bf --- /dev/null +++ b/tests/sessions/test_replay_consistency.py @@ -0,0 +1,1743 @@ +# Tencent is pleased to support the open source community by making tRPC-Agent-Python available. +# +# Copyright (C) 2026 Tencent. All rights reserved. +# +# tRPC-Agent-Python is licensed under Apache-2.0. +"""Replay consistency tests for Session, Memory, and Summary backends. + +The harness intentionally lives in tests: it exercises the public service APIs +without introducing test-only abstractions into the runtime package. +""" + +from __future__ import annotations + +import copy +import json +import os +import re +import sys +import tempfile +import time +import uuid +from dataclasses import dataclass +from dataclasses import field +from pathlib import Path +from typing import Any, Awaitable, Callable, Optional + +import pytest + +from trpc_agent_sdk.abc import MemoryServiceConfig +from trpc_agent_sdk.events import Event +from trpc_agent_sdk.memory import InMemoryMemoryService +from trpc_agent_sdk.memory import SqlMemoryService +from trpc_agent_sdk.memory._sql_memory_service import MemStorageEvent +from trpc_agent_sdk.sessions import InMemorySessionService +from trpc_agent_sdk.sessions import SqlSessionService +from trpc_agent_sdk.sessions._sql_session_service import SessionStorageEvent +from trpc_agent_sdk.sessions._sql_session_service import StorageAppState +from trpc_agent_sdk.sessions._sql_session_service import StorageSession +from trpc_agent_sdk.sessions._sql_session_service import StorageUserState +from trpc_agent_sdk.sessions._session import Session +from trpc_agent_sdk.sessions._session_summarizer import SessionSummarizer +from trpc_agent_sdk.sessions._summarizer_manager import SummarizerSessionManager +from trpc_agent_sdk.sessions._types import SessionServiceConfig +from trpc_agent_sdk.storage import RedisCommand +from trpc_agent_sdk.storage import SqlCondition +from trpc_agent_sdk.storage import SqlKey +from trpc_agent_sdk.types import Content +from trpc_agent_sdk.types import EventActions +from trpc_agent_sdk.types import FunctionCall +from trpc_agent_sdk.types import FunctionResponse +from trpc_agent_sdk.types import MemoryEntry +from trpc_agent_sdk.types import Part +from trpc_agent_sdk.types import SearchMemoryResponse + +CASES_FILE = Path(__file__).with_name("replay_cases") / "session_memory_summary_replay_cases.jsonl" +REPORT_FILE_NAME = "session_memory_summary_diff_report.json" +REPORT_PATH_ENV = "TRPC_AGENT_REPLAY_REPORT_PATH" +BACKENDS_ENV = "TRPC_AGENT_REPLAY_BACKENDS" +SQL_URL_ENV = "TRPC_AGENT_REPLAY_SQL_URL" +REDIS_URL_ENV = "TRPC_AGENT_REPLAY_REDIS_URL" +RUN_ID = f"{os.getpid()}-{int(time.time() * 1000)}" +REPLAY_EVENT_FUTURE_OFFSET_SECONDS = 3600.0 + +ALLOWED_DIFFS = [ + { + "path": "$.session.last_update_time", + "reason": "storage update time is generated by each backend clock and is not business state", + }, + { + "path": "$.events[*].timestamp", + "reason": "timestamp precision and timezone serialization differ across storage engines", + }, + { + "path": "$.summary.updated_at", + "reason": "summary update timestamp is clock-derived; presence, version, owner, and content are compared", + }, + { + "path": "$.memory.*[*].timestamp", + "reason": "memory timestamps mirror event storage precision and are not used for recall equivalence", + }, + { + "path": "$.memory.*[*].order", + "reason": "memory recall order is backend-dependent; entries are sorted for multiset comparison", + }, +] + + +@dataclass(frozen=True) +class ReplayCase: + name: str + description: str + operations: list[dict[str, Any]] + memory_queries: list[dict[str, Any]] + primary_session_ref: str = "default" + + @property + def app_name(self) -> str: + return f"replay-{RUN_ID}-{self.name}" + + @property + def user_id(self) -> str: + return "replay-user" + + +@dataclass +class ReplayBackend: + name: str + session_service: Any + memory_service: Any + db_url: str | None = None + cleanup_paths: list[Path] = field(default_factory=list) + cleanup_callback: Callable[[], Awaitable[None]] | None = None + + async def close(self, cleanup_files: bool = True) -> None: + try: + if self.cleanup_callback: + await self.cleanup_callback() + finally: + await self.memory_service.close() + await self.session_service.close() + if cleanup_files: + for path in self.cleanup_paths: + for candidate in (path, Path(f"{path}-wal"), Path(f"{path}-shm")): + try: + candidate.unlink() + except FileNotFoundError: + pass + + +@dataclass(frozen=True) +class ReplayBackendBuilder: + name: str + build: Callable[[], Awaitable[ReplayBackend]] + + +@dataclass(frozen=True) +class ReplayRunResult: + primary_session: Session + sessions: dict[str, Session] + + +class _CorruptingSessionService: + """Test-only service proxy that corrupts backend API reads after real replay writes.""" + + def __init__(self, inner: Any, mode: str): + self._inner = inner + self._mode = mode + + def __getattr__(self, name: str) -> Any: + return getattr(self._inner, name) + + @property + def summarizer_manager(self) -> Any: + return getattr(self._inner, "summarizer_manager", None) + + async def get_session(self, **kwargs: Any) -> Optional[Session]: + session = await self._inner.get_session(**kwargs) + if session is None: + return None + + corrupted = copy.deepcopy(session) + if self._mode == "drop_event" and corrupted.events: + corrupted.events.pop() + elif self._mode == "duplicate_event" and corrupted.events: + duplicated = copy.deepcopy(corrupted.events[0]) + corrupted.events.insert(1, duplicated) + elif self._mode == "dirty_state": + corrupted.state["topic"] = "corrupted-topic" + elif self._mode == "summary_loss": + corrupted.events = [event for event in corrupted.events if not event.is_summary_event()] + corrupted.historical_events = [ + event for event in corrupted.historical_events if not event.is_summary_event() + ] + elif self._mode == "summary_stale_overwrite": + historical_summary = next((event for event in corrupted.historical_events if event.is_summary_event()), + None) + active_summary = next((event for event in corrupted.events if event.is_summary_event()), None) + if historical_summary and active_summary: + active_summary.content = copy.deepcopy(historical_summary.content) + elif self._mode == "summary_wrong_owner": + for event in corrupted.events: + if event.is_summary_event(): + event.content.parts[0].text = event.content.parts[0].text.replace(corrupted.id, "wrong-session") + break + elif self._mode == "summary_cross_session_leak" and kwargs.get("session_id") == "summary-owner-alpha": + sibling = await self._inner.get_session( + app_name=kwargs["app_name"], + user_id=kwargs["user_id"], + session_id="summary-owner-beta", + ) + if sibling: + sibling_summary = next((event for event in sibling.events if event.is_summary_event()), None) + active_summary = next((event for event in corrupted.events if event.is_summary_event()), None) + if sibling_summary and active_summary: + active_summary.content = copy.deepcopy(sibling_summary.content) + return corrupted + + async def get_session_summary(self, session: Session) -> Optional[str]: + if self._mode == "summary_loss": + return None + if self._mode == "summary_wrong_owner": + text = await self._inner.get_session_summary(session) + return text.replace(session.id, "wrong-session") if text else text + return await self._inner.get_session_summary(session) + + +class _CorruptingMemoryService: + """Test-only memory proxy used to prove replay diffs catch backend-level faults.""" + + def __init__(self, inner: Any, mode: str): + self._inner = inner + self._mode = mode + + def __getattr__(self, name: str) -> Any: + return getattr(self._inner, name) + + async def search_memory(self, *args: Any, **kwargs: Any) -> SearchMemoryResponse: + response = await self._inner.search_memory(*args, **kwargs) + if self._mode == "drop_memory": + return SearchMemoryResponse() + if self._mode == "memory_limit_filtering" and kwargs.get("limit") == 1: + return SearchMemoryResponse() + return response + + +class _FakeSummaryModel: + name = "deterministic-replay-summary-model" + + +class _DeterministicSessionSummarizer(SessionSummarizer): + + async def _compress_session_to_summary( + self, + events: list[Event], + session_id: str, + ctx: Any | None = None, + ) -> Optional[str]: + if not events: + return None + items = [] + for event in events: + parts = _normalize_parts(event.content) if event.content else [] + items.append({"author": event.author, "parts": parts}) + return _normalize_summary_text(f"{session_id}: {json.dumps(items, sort_keys=True, ensure_ascii=False)}") + + +def _load_replay_cases() -> list[ReplayCase]: + cases = [] + for line in CASES_FILE.read_text(encoding="utf-8").splitlines(): + if not line.strip(): + continue + data = json.loads(line) + cases.append( + ReplayCase( + name=data["name"], + description=data.get("description", ""), + operations=data["operations"], + memory_queries=data.get("memory_queries", []), + primary_session_ref=data.get("primary_session_ref", "default"), + )) + return cases + + +def _replay_case_names() -> list[str]: + return [case.name for case in _load_replay_cases()] + + +def _get_replay_case(case_name: str) -> ReplayCase: + for case in _load_replay_cases(): + if case.name == case_name: + return case + raise AssertionError(f"Unknown replay case: {case_name}") + + +def _make_session_config() -> SessionServiceConfig: + config = SessionServiceConfig(store_historical_events=True) + config.clean_ttl_config() + return config + + +def _make_memory_config() -> MemoryServiceConfig: + config = MemoryServiceConfig(enabled=True) + config.clean_ttl_config() + return config + + +def _make_summary_manager() -> SummarizerSessionManager: + summarizer = _DeterministicSessionSummarizer( + model=_FakeSummaryModel(), + check_summarizer_functions=[lambda session: True], + keep_recent_count=2, + start_by_user_turn=False, + ) + return SummarizerSessionManager( + model=_FakeSummaryModel(), + summarizer=summarizer, + auto_summarize=True, + ) + + +async def _build_in_memory_backend() -> ReplayBackend: + return ReplayBackend( + name="in_memory", + session_service=InMemorySessionService( + summarizer_manager=_make_summary_manager(), + session_config=_make_session_config(), + ), + memory_service=InMemoryMemoryService(memory_service_config=_make_memory_config()), + ) + + +async def _build_sqlite_backend() -> ReplayBackend: + db_path = Path(tempfile.gettempdir()) / f"trpc-agent-replay-{RUN_ID}-{uuid.uuid4().hex}.db" + return await _build_sqlite_backend_for_url(f"sqlite:///{db_path.as_posix()}", cleanup_paths=[db_path]) + + +async def _build_sqlite_backend_for_url(db_url: str, cleanup_paths: list[Path] | None = None) -> ReplayBackend: + session_service = SqlSessionService( + db_url=db_url, + summarizer_manager=_make_summary_manager(), + session_config=_make_session_config(), + is_async=False, + ) + memory_service = SqlMemoryService( + db_url=db_url, + memory_service_config=_make_memory_config(), + is_async=False, + ) + await session_service._sql_storage.create_sql_engine() + await memory_service._sql_storage.create_sql_engine() + return ReplayBackend( + name="sqlite", + session_service=session_service, + memory_service=memory_service, + db_url=db_url, + cleanup_paths=cleanup_paths or [], + ) + + +async def _build_sql_env_backend() -> ReplayBackend: + db_url = os.environ[SQL_URL_ENV] + session_service = SqlSessionService( + db_url=db_url, + summarizer_manager=_make_summary_manager(), + session_config=_make_session_config(), + is_async=False, + ) + memory_service = SqlMemoryService( + db_url=db_url, + memory_service_config=_make_memory_config(), + is_async=False, + ) + await session_service._sql_storage.create_sql_engine() + await memory_service._sql_storage.create_sql_engine() + + async def _cleanup() -> None: + await _cleanup_sql_replay_data(session_service, memory_service) + + return ReplayBackend( + name="sql_env", + session_service=session_service, + memory_service=memory_service, + cleanup_callback=_cleanup, + ) + + +async def _build_redis_env_backend() -> ReplayBackend: + from trpc_agent_sdk.memory import RedisMemoryService + from trpc_agent_sdk.sessions import RedisSessionService + + db_url = os.environ[REDIS_URL_ENV] + backend = ReplayBackend( + name="redis_env", + session_service=RedisSessionService( + db_url=db_url, + summarizer_manager=_make_summary_manager(), + session_config=_make_session_config(), + is_async=False, + ), + memory_service=RedisMemoryService( + db_url=db_url, + memory_service_config=_make_memory_config(), + is_async=False, + ), + ) + backend.cleanup_callback = lambda: _cleanup_redis_replay_data(backend.session_service, backend.memory_service) + return backend + + +async def _cleanup_sql_replay_data(session_service: Any, memory_service: Any) -> None: + """Best-effort cleanup for env SQL backends; scoped to this test run's app prefix.""" + app_prefix = f"replay-{RUN_ID}-%" + save_key_prefix = f"replay-{RUN_ID}-%" + try: + async with session_service._sql_storage.create_db_session() as sql_session: + for storage_cls in (SessionStorageEvent, StorageSession, StorageAppState): + await session_service._sql_storage.delete( + sql_session, + SqlKey(key=tuple(), storage_cls=storage_cls), + SqlCondition(filters=[storage_cls.app_name.like(app_prefix)]), + ) + await session_service._sql_storage.delete( + sql_session, + SqlKey(key=tuple(), storage_cls=StorageUserState), + SqlCondition(filters=[StorageUserState.app_name.like(app_prefix)]), + ) + await session_service._sql_storage.commit(sql_session) + + async with memory_service._sql_storage.create_db_session() as sql_session: + await memory_service._sql_storage.delete( + sql_session, + SqlKey(key=tuple(), storage_cls=MemStorageEvent), + SqlCondition(filters=[MemStorageEvent.save_key.like(save_key_prefix)]), + ) + await memory_service._sql_storage.commit(sql_session) + except Exception: + # Cleanup must not hide the replay failure that triggered teardown. + return + + +async def _cleanup_redis_replay_data(session_service: Any, memory_service: Any) -> None: + """Best-effort cleanup for env Redis backends; scoped to this test run's app prefix.""" + key_patterns = [ + f"session:replay-{RUN_ID}-*", + f"app_state:replay-{RUN_ID}-*", + f"user_state:replay-{RUN_ID}-*", + f"memory:replay-{RUN_ID}-*", + ] + try: + async with session_service._redis_storage.create_db_session() as redis_session: + for pattern in key_patterns[:3]: + keys = await session_service._redis_storage.execute_command( + redis_session, + RedisCommand(method="keys", args=(pattern, )), + ) + for key in keys: + await session_service._redis_storage.delete(redis_session, key) + + async with memory_service._redis_storage.create_db_session() as redis_session: + keys = await memory_service._redis_storage.execute_command( + redis_session, + RedisCommand(method="keys", args=(key_patterns[3], )), + ) + for key in keys: + await memory_service._redis_storage.delete(redis_session, key) + except Exception: + # Cleanup must not hide the replay failure that triggered teardown. + return + + +def _backend_builders() -> list[ReplayBackendBuilder]: + available_builders: dict[str, ReplayBackendBuilder] = { + "in_memory": ReplayBackendBuilder("in_memory", _build_in_memory_backend), + "sqlite": ReplayBackendBuilder("sqlite", _build_sqlite_backend), + } + if os.environ.get(SQL_URL_ENV): + available_builders["sql_env"] = ReplayBackendBuilder("sql_env", _build_sql_env_backend) + if os.environ.get(REDIS_URL_ENV): + available_builders["redis_env"] = ReplayBackendBuilder("redis_env", _build_redis_env_backend) + + selected_backends = [name.strip() for name in os.environ.get(BACKENDS_ENV, "").split(",") if name.strip()] + if selected_backends: + missing = [name for name in selected_backends if name not in available_builders] + if missing: + raise ValueError(f"Unknown or unavailable replay backend(s): {missing}. " + f"Available backends: {sorted(available_builders)}") + return [available_builders[name] for name in selected_backends] + + builders = [available_builders["in_memory"], available_builders["sqlite"]] + if "sql_env" in available_builders: + builders.append(available_builders["sql_env"]) + if "redis_env" in available_builders: + builders.append(available_builders["redis_env"]) + return builders + + +def _part_from_config(part: dict[str, Any]) -> Part: + kind = part["kind"] + if kind == "text": + return Part.from_text(text=part["text"]) + if kind == "function_call": + return Part(function_call=FunctionCall(name=part["name"], args=part["args"])) + if kind == "function_response": + return Part(function_response=FunctionResponse(name=part["name"], response=part["response"])) + raise ValueError(f"Unsupported part kind: {kind}") + + +def _parts_from_operation(operation: dict[str, Any]) -> list[Part]: + if "parts" in operation: + return [_part_from_config(part) for part in operation["parts"]] + if "text" in operation: + return [Part.from_text(text=operation["text"])] + if operation["op"] == "append_tool_call": + return [Part(function_call=FunctionCall(name=operation["name"], args=operation["args"]))] + if operation["op"] == "append_tool_response": + return [Part(function_response=FunctionResponse(name=operation["name"], response=operation["response"]))] + raise ValueError(f"Unsupported event content operation: {operation['op']}") + + +def _event_metadata(operation: dict[str, Any]) -> dict[str, Any]: + metadata = {} + for key in ( + "branch", + "request_id", + "parent_invocation_id", + "tag", + "filter_key", + "requires_completion", + "version", + "visible", + "model_flags", + ): + if key in operation: + metadata[key] = operation[key] + if "long_running_tool_ids" in operation: + metadata["long_running_tool_ids"] = set(operation["long_running_tool_ids"]) + return metadata + + +def _make_event(operation: dict[str, Any]) -> Event: + return Event( + id=operation["event_id"], + invocation_id=operation["invocation_id"], + author=operation["author"], + content=Content(parts=_parts_from_operation(operation)), + actions=EventActions(state_delta=operation.get("state_delta", {})), + partial=operation.get("partial", False), + timestamp=_operation_timestamp(operation), + **_event_metadata(operation), + ) + + +def _event_from_operation(operation: dict[str, Any]) -> Event: + if operation["op"] in {"append_text", "append_parts", "append_tool_call", "append_tool_response", "failed_append"}: + return _make_event(operation) + raise ValueError(f"Unsupported event operation: {operation['op']}") + + +def _operation_timestamp(operation: dict[str, Any]) -> float: + return time.time() + REPLAY_EVENT_FUTURE_OFFSET_SECONDS + float(operation["timestamp"]) / 1000.0 + + +async def _drive_case(case: ReplayCase, backend: ReplayBackend) -> ReplayRunResult: + sessions: dict[str, Session] = {} + last_session_ref: Optional[str] = None + + def _session_ref(operation: dict[str, Any]) -> str: + return operation.get("session_ref", "default") + + def _require_session(operation: dict[str, Any]) -> Session: + ref = _session_ref(operation) + if ref not in sessions: + raise AssertionError(f"Case {case.name} references unknown session {ref}") + return sessions[ref] + + for operation in case.operations: + op = operation["op"] + if op == "create_session": + ref = _session_ref(operation) + sessions[ref] = await backend.session_service.create_session( + app_name=operation.get("app_name", case.app_name), + user_id=operation.get("user_id", case.user_id), + session_id=operation["session_id"], + state=operation.get("state"), + ) + last_session_ref = ref + elif op in {"append_text", "append_parts", "append_tool_call", "append_tool_response"}: + session = _require_session(operation) + await backend.session_service.append_event(session, _event_from_operation(operation)) + elif op == "failed_append": + session = _require_session(operation) + _simulate_failed_append_before_persist(backend, session, _event_from_operation(operation)) + elif op == "store_memory": + session = _require_session(operation) + await backend.memory_service.store_session(session) + elif op == "summarize": + session = _require_session(operation) + await backend.session_service.create_session_summary(session) + reloaded = await backend.session_service.get_session( + app_name=session.app_name, + user_id=session.user_id, + session_id=session.id, + ) + if reloaded is None: + raise AssertionError(f"Case {case.name} lost session {session.id} after summarization") + sessions[_session_ref(operation)] = reloaded + else: + raise ValueError(f"Unsupported replay operation: {op}") + + if not sessions: + raise AssertionError(f"Case {case.name} did not create a session") + + stored_sessions = {} + for ref, session in sessions.items(): + stored_session = await backend.session_service.get_session( + app_name=session.app_name, + user_id=session.user_id, + session_id=session.id, + ) + if stored_session is None: + raise AssertionError(f"Case {case.name} lost session {session.id} on backend {backend.name}") + stored_sessions[ref] = stored_session + + primary_ref = case.primary_session_ref + if primary_ref not in stored_sessions: + primary_ref = last_session_ref or next(iter(stored_sessions)) + return ReplayRunResult(primary_session=stored_sessions[primary_ref], sessions=stored_sessions) + + +def _simulate_failed_append_before_persist(backend: ReplayBackend, session: Session, event: Event) -> None: + """Mutate the caller-side session like append_event does, then fail before backend persistence.""" + try: + if hasattr(backend.session_service, "_append_event_to_session"): + # Test-only fault injection: model the window where the caller-side + # Session was mutated, but the backend write failed before commit. + backend.session_service._append_event_to_session(session, event) + raise RuntimeError("simulated replay append failure before backend persistence") + except RuntimeError: + return + + +def _normalize_summary_text(text: str | None) -> str | None: + if text is None: + return None + return " ".join(text.split()).strip().lower() + + +def _stable(value: Any) -> Any: + if isinstance(value, dict): + return {key: _stable(value[key]) for key in sorted(value)} + if isinstance(value, list): + return [_stable(item) for item in value] + return value + + +def _normalize_parts(content: Content | None) -> list[dict[str, Any]]: + if content is None or not content.parts: + return [] + parts = [] + for part in content.parts: + if part.text is not None: + parts.append({"kind": "text", "text": part.text}) + elif part.function_call is not None: + parts.append({ + "kind": "function_call", + "name": part.function_call.name, + "args": _stable(part.function_call.args or {}), + }) + elif part.function_response is not None: + parts.append({ + "kind": "function_response", + "name": part.function_response.name, + "response": _stable(part.function_response.response or {}), + }) + return parts + + +def _normalize_event(event: Event, index: int) -> dict[str, Any]: + state_delta = event.actions.state_delta if event.actions else {} + return { + "index": index, + "id": "" if event.is_summary_event() else event.id, + "timestamp": "", + "author": event.author, + "invocation_id": event.invocation_id, + "parts": _normalize_parts(event.content), + "state_delta": _stable(state_delta), + "is_summary": event.is_summary_event(), + "model_visible": event.is_model_visible(), + "partial": bool(event.partial), + "branch": event.branch, + "request_id": event.request_id, + "parent_invocation_id": event.parent_invocation_id, + "tag": event.tag, + "filter_key": event.filter_key, + "requires_completion": event.requires_completion, + "version": event.version, + "visible": event.visible, + "model_flags": event.model_flags, + "long_running_tool_ids": sorted(event.long_running_tool_ids or []), + } + + +def _normalize_memory_response(response: Any) -> list[dict[str, Any]]: + memories = [] + for memory in response.memories: + memories.append({ + "author": memory.author, + "timestamp": "", + "parts": _normalize_parts(memory.content), + }) + return sorted(memories, key=lambda item: json.dumps(item, sort_keys=True, ensure_ascii=False)) + + +def _summary_payload_text(event: Event | None) -> str | None: + if event is None: + return None + text = event.get_text() + prefix = "Previous conversation summary:" + if text.startswith(prefix): + text = text[len(prefix):] + return _normalize_summary_text(text) + + +def _has_storage_timestamp(event: Event) -> bool: + return isinstance(event.timestamp, (int, float)) and event.timestamp > 0 + + +def _summary_records(session: Session) -> list[dict[str, Any]]: + records = [] + ordered_summary_events = [ + ("historical", event) for event in session.historical_events if event.is_summary_event() + ] + [("active", event) for event in session.events if event.is_summary_event()] + for version, (source, event) in enumerate(ordered_summary_events, start=1): + records.append({ + "summary_id": f"{session.id}:summary:v{version}", + "session_id": session.id, + "version": version, + "source": source, + "active": source == "active", + "updated_at": "", + "updated_at_present": _has_storage_timestamp(event), + "text": _summary_payload_text(event), + }) + return records + + +def _normalize_summary_from_session(session: Session) -> dict[str, Any]: + active_summary_events = [event for event in session.events if event.is_summary_event()] + historical_summary_events = [event for event in session.historical_events if event.is_summary_event()] + latest_summary_event = active_summary_events[-1] if active_summary_events else None + version_records = _summary_records(session) + version = len(version_records) + latest_record = version_records[-1] if version_records else None + + return { + "exists": latest_summary_event is not None, + "id": latest_record["summary_id"] if latest_summary_event and latest_record else None, + "session_id": session.id if latest_summary_event else None, + "version": version, + "text": _summary_payload_text(latest_summary_event), + "has_summary_anchor": latest_summary_event is not None, + "anchor_text": _normalize_summary_text(latest_summary_event.get_text() if latest_summary_event else None), + "active_summary_count": len(active_summary_events), + "historical_summary_count": len(historical_summary_events), + "versions": version_records, + "latest_version_active": latest_record["active"] if latest_record else None, + "latest_version_source": latest_record["source"] if latest_record else None, + "updated_at_present": _has_storage_timestamp(latest_summary_event) if latest_summary_event else False, + "historical_event_count": len(session.historical_events), + "retained_event_count": len(session.events), + "updated_at": "" if latest_summary_event else None, + } + + +def _empty_service_summary() -> dict[str, Any]: + return { + "service_public_exists": False, + "service_public_text": None, + "service_manager_exists": False, + "service_manager_text": None, + "service_manager_session_id": None, + "service_manager_original_event_count": None, + "service_manager_compressed_event_count": None, + "service_manager_updated_at": None, + } + + +async def _normalize_summary_from_service( + backend: ReplayBackend, + session: Session, + *, + include_manager_metadata: bool = True, +) -> dict[str, Any]: + public_summary_text = await backend.session_service.get_session_summary(session) + summary = _empty_service_summary() + summary["service_public_exists"] = public_summary_text is not None + summary["service_public_text"] = _normalize_summary_text(public_summary_text) + + if not include_manager_metadata: + return summary + + manager = getattr(backend.session_service, "summarizer_manager", None) + if manager is None: + return summary + + summary_obj = await manager.get_session_summary(session) + if summary_obj is None: + return summary + + summary.update({ + "service_manager_exists": True, + "service_manager_text": _normalize_summary_text(summary_obj.summary_text), + "service_manager_session_id": summary_obj.session_id, + "service_manager_original_event_count": summary_obj.original_event_count, + "service_manager_compressed_event_count": summary_obj.compressed_event_count, + "service_manager_updated_at": "", + }) + return summary + + +async def _snapshot_backend( + case: ReplayCase, + backend: ReplayBackend, + result: ReplayRunResult, + *, + include_service_summary: bool = True, + include_cached_summary_metadata: bool = True, +) -> dict[str, Any]: + session = result.primary_session + + memory_results = {} + for query_config in case.memory_queries: + query = query_config["query"] + query_session_ref = query_config.get("session_ref", case.primary_session_ref) + query_session = result.sessions[query_session_ref] + query_name = query_config.get("name", query) + response = await backend.memory_service.search_memory( + query_session.save_key, + query, + limit=query_config.get("limit", 10), + ) + memory_results[query_name] = _normalize_memory_response(response) + + summary = _normalize_summary_from_session(session) + if include_service_summary: + summary.update( + await _normalize_summary_from_service( + backend, + session, + include_manager_metadata=include_cached_summary_metadata, + )) + else: + summary.update(_empty_service_summary()) + + return { + "backend": backend.name, + "case": case.name, + "session": { + "id": session.id, + "app_name": session.app_name, + "user_id": session.user_id, + "state": _stable(session.state), + "last_update_time": "", + }, + "events": [_normalize_event(event, index) for index, event in enumerate(session.events)], + "historical_events": [_normalize_event(event, index) for index, event in enumerate(session.historical_events)], + "sessions": { + ref: _snapshot_session(stored_session) + for ref, stored_session in sorted(result.sessions.items()) + }, + "memory": memory_results, + "summary": summary, + } + + +def _snapshot_session(session: Session) -> dict[str, Any]: + return { + "id": session.id, + "app_name": session.app_name, + "user_id": session.user_id, + "state": _stable(session.state), + "last_update_time": "", + "events": [_normalize_event(event, index) for index, event in enumerate(session.events)], + "historical_events": [_normalize_event(event, index) for index, event in enumerate(session.historical_events)], + "summary": _normalize_summary_from_session(session), + } + + +async def _run_case_on_backend( + case: ReplayCase, + backend_builder: ReplayBackendBuilder | Callable[[], Awaitable[ReplayBackend]], +) -> dict[str, Any]: + build = backend_builder.build if isinstance(backend_builder, ReplayBackendBuilder) else backend_builder + backend = await build() + try: + result = await _drive_case(case, backend) + return await _snapshot_backend(case, backend, result) + finally: + await backend.close() + + +def _make_corrupting_sqlite_backend_builder(mode: str) -> ReplayBackendBuilder: + + async def _build() -> ReplayBackend: + backend = await _build_sqlite_backend() + return ReplayBackend( + name=f"sqlite_corrupt_{mode}", + session_service=_CorruptingSessionService(backend.session_service, mode), + memory_service=_CorruptingMemoryService(backend.memory_service, mode), + db_url=backend.db_url, + cleanup_paths=backend.cleanup_paths, + ) + + return ReplayBackendBuilder(f"sqlite_corrupt_{mode}", _build) + + +async def _reload_sessions_from_backend( + backend: ReplayBackend, + sessions: dict[str, Session], + primary_session_ref: str, +) -> ReplayRunResult: + reloaded_sessions = {} + for ref, session in sessions.items(): + reloaded = await backend.session_service.get_session( + app_name=session.app_name, + user_id=session.user_id, + session_id=session.id, + ) + if reloaded is None: + raise AssertionError(f"Reloaded backend lost session {session.id}") + reloaded_sessions[ref] = reloaded + + primary_ref = primary_session_ref if primary_session_ref in reloaded_sessions else next(iter(reloaded_sessions)) + return ReplayRunResult(primary_session=reloaded_sessions[primary_ref], sessions=reloaded_sessions) + + +def _event_index_from_path(path: str) -> int | None: + match = re.search(r"\.events\[(\d+)\]", path) + if not match: + match = re.search(r"\.historical_events\[(\d+)\]", path) + return int(match.group(1)) if match else None + + +def _make_diff( + *, + case_name: str, + session_id: str, + backend: str, + reference_backend: str, + path: str, + reference: Any, + actual: Any, +) -> dict[str, Any]: + return { + "case": case_name, + "session_id": session_id, + "event_index": _event_index_from_path(path), + "summary_id": _summary_id_from_path(session_id, path), + "backend": backend, + "reference_backend": reference_backend, + "path": path, + "reference": reference, + "actual": actual, + } + + +def _summary_id_from_path(session_id: str, path: str) -> str | None: + if not re.match(r"^\$(?:\.summary|\.sessions\.[^.[]+\.summary)", path): + return None + match = re.match(r"^\$(?:\.summary|\.sessions\.[^.[]+\.summary)\.versions\[(\d+)\]", path) + if match: + return f"{session_id}:summary:v{int(match.group(1)) + 1}" + return f"{session_id}:summary" + + +def _allowed_diff_reason(path: str) -> str | None: + for rule in ALLOWED_DIFFS: + pattern = re.escape(rule["path"]) + pattern = pattern.replace(r"\[\*\]", r"\[\d+\]") + pattern = pattern.replace(r"\*", r"[^.\[\]]+") + if re.fullmatch(pattern, path): + return rule["reason"] + return None + + +def _session_id_for_path(reference_snapshot: dict[str, Any], path: str) -> str: + match = re.match(r"^\$\.sessions\.([^.[]+)", path) + if match: + session_ref = match.group(1) + nested_session = reference_snapshot.get("sessions", {}).get(session_ref, {}) + if nested_session.get("id"): + return nested_session["id"] + return reference_snapshot["session"]["id"] + + +def _compare_values( + reference: Any, + actual: Any, + *, + path: str, + case_name: str, + session_id_for_path: Callable[[str], str], + backend: str, + reference_backend: str, +) -> list[dict[str, Any]]: + if _allowed_diff_reason(path): + return [] + + if type(reference) is not type(actual): + return [ + _make_diff( + case_name=case_name, + session_id=session_id_for_path(path), + backend=backend, + reference_backend=reference_backend, + path=path, + reference=reference, + actual=actual, + ) + ] + + diffs: list[dict[str, Any]] = [] + if isinstance(reference, dict): + for key in sorted(set(reference) | set(actual)): + next_path = f"{path}.{key}" + if key not in reference or key not in actual: + diffs.append( + _make_diff( + case_name=case_name, + session_id=session_id_for_path(next_path), + backend=backend, + reference_backend=reference_backend, + path=next_path, + reference=reference.get(key, ""), + actual=actual.get(key, ""), + )) + else: + diffs.extend( + _compare_values( + reference[key], + actual[key], + path=next_path, + case_name=case_name, + session_id_for_path=session_id_for_path, + backend=backend, + reference_backend=reference_backend, + )) + return diffs + + if isinstance(reference, list): + if len(reference) != len(actual): + diffs.append( + _make_diff( + case_name=case_name, + session_id=session_id_for_path(f"{path}.length"), + backend=backend, + reference_backend=reference_backend, + path=f"{path}.length", + reference=len(reference), + actual=len(actual), + )) + for index, (left, right) in enumerate(zip(reference, actual)): + diffs.extend( + _compare_values( + left, + right, + path=f"{path}[{index}]", + case_name=case_name, + session_id_for_path=session_id_for_path, + backend=backend, + reference_backend=reference_backend, + )) + return diffs + + if reference != actual: + diffs.append( + _make_diff( + case_name=case_name, + session_id=session_id_for_path(path), + backend=backend, + reference_backend=reference_backend, + path=path, + reference=reference, + actual=actual, + )) + return diffs + + +def _compare_snapshots(reference: dict[str, Any], actual: dict[str, Any]) -> list[dict[str, Any]]: + def session_id_for_path(path: str) -> str: + return _session_id_for_path(reference, path) + + return _compare_values( + { + key: value + for key, value in reference.items() if key != "backend" + }, + { + key: value + for key, value in actual.items() if key != "backend" + }, + path="$", + case_name=reference["case"], + session_id_for_path=session_id_for_path, + backend=actual["backend"], + reference_backend=reference["backend"], + ) + + +def _write_report(path: Path, report: dict[str, Any]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(report, indent=2, sort_keys=True, ensure_ascii=False), encoding="utf-8") + + +def _resolve_report_path(tmp_path: Path) -> Path: + configured_path = os.environ.get(REPORT_PATH_ENV) + if not configured_path: + return tmp_path / REPORT_FILE_NAME + + report_path = Path(configured_path) + if report_path.suffix: + return report_path + return report_path / REPORT_FILE_NAME + + +def _backend_error_report(case: ReplayCase, backend_name: str, exc: BaseException) -> dict[str, Any]: + return { + "case": case.name, + "backend": backend_name, + "error_type": type(exc).__name__, + "message": str(exc), + } + + +async def _run_all_cases() -> tuple[list[dict[str, Any]], list[dict[str, Any]], list[dict[str, Any]], list[str], float]: + start = time.monotonic() + cases = _load_replay_cases() + builders = _backend_builders() + attempted_backends = [builder.name for builder in builders] + case_reports = [] + all_diffs = [] + all_errors = [] + for case in cases: + snapshots = [] + errors = [] + for builder in builders: + try: + snapshots.append(await _run_case_on_backend(case, builder)) + except Exception as exc: # pylint: disable=broad-except + error = _backend_error_report(case, builder.name, exc) + errors.append(error) + all_errors.append(error) + + if not snapshots: + case_reports.append({ + "case": case.name, + "description": case.description, + "backends": [], + "diffs": [], + "errors": errors, + "snapshots": [], + }) + continue + + reference = snapshots[0] + diffs = [] + for candidate in snapshots[1:]: + diffs.extend(_compare_snapshots(reference, candidate)) + + all_diffs.extend(diffs) + case_reports.append({ + "case": case.name, + "description": case.description, + "backends": [snapshot["backend"] for snapshot in snapshots], + "diffs": diffs, + "errors": errors, + "snapshots": snapshots, + }) + return case_reports, all_diffs, all_errors, attempted_backends, time.monotonic() - start + + +def _report_mode(case_reports: list[dict[str, Any]], attempted_backends: list[str]) -> dict[str, Any]: + snapshot_backend_names = sorted({backend for report in case_reports for backend in report["backends"]}) + failed_backend_names = sorted({error["backend"] for report in case_reports for error in report["errors"]}) + return { + "lightweight": all(backend in {"in_memory", "sqlite"} for backend in attempted_backends), + "selected_backends": os.environ.get(BACKENDS_ENV), + "attempted_backends": attempted_backends, + "snapshot_backends": snapshot_backend_names, + "failed_backends": failed_backend_names, + "sql_env_attempted": "sql_env" in attempted_backends, + "redis_env_attempted": "redis_env" in attempted_backends, + "sql_env_has_snapshot": "sql_env" in snapshot_backend_names, + "redis_env_has_snapshot": "redis_env" in snapshot_backend_names, + "sql_env_failed": "sql_env" in failed_backend_names, + "redis_env_failed": "redis_env" in failed_backend_names, + } + + +def _inject_case_inconsistency(case_name: str, snapshot: dict[str, Any]) -> dict[str, Any]: + mutated = copy.deepcopy(snapshot) + mutated["backend"] = f"{snapshot['backend']}_mutated" + if case_name == "single_turn_conversation": + mutated["events"][1]["parts"][0]["text"] = "corrupted assistant text" + elif case_name == "multi_turn_conversation": + mutated["events"][1], mutated["events"][2] = mutated["events"][2], mutated["events"][1] + elif case_name == "tool_call_conversation": + mutated["events"][1]["parts"][0]["args"]["city"] = "Shanghai" + elif case_name == "state_overwrite": + mutated["session"]["state"]["topic"] = "stale-topic" + elif case_name == "memory_preference_write_read": + mutated["memory"]["jasmine tea"] = [] + elif case_name == "memory_fact_write_read": + mutated["memory"]["Blue River"][0]["author"] = "wrong-author" + elif case_name == "summary_create_update": + mutated["summary"]["version"] -= 1 + mutated["summary"]["text"] = "stale summary" + elif case_name == "summary_event_truncation": + mutated["summary"]["session_id"] = "wrong-session" + elif case_name == "failed_append_recovery": + mutated["events"].append({ + "index": len(mutated["events"]), + "author": "agent", + "invocation_id": "inv-failed-2", + "parts": [{ + "kind": "text", + "text": "This failed event must not persist." + }], + "state_delta": { + "phase": "dirty" + }, + "is_summary": False, + "model_visible": True, + "partial": False, + "branch": None, + }) + elif case_name == "duplicate_event_write_recovery": + mutated["events"].insert(1, copy.deepcopy(mutated["events"][0])) + mutated["session"]["state"]["phase"] = "dirty-duplicate" + elif case_name == "repeat_memory_store": + mutated["memory"]["quiet focus"].append(copy.deepcopy(mutated["memory"]["quiet focus"][0])) + elif case_name == "partial_event_not_persisted": + mutated["events"].insert( + 1, + { + "index": 1, + "author": "agent", + "invocation_id": "inv-partial-1", + "parts": [{ + "kind": "text", + "text": "draft chunk that must not persist" + }], + "state_delta": {}, + "is_summary": False, + "model_visible": True, + "partial": True, + "branch": None, + }, + ) + elif case_name == "cross_session_user_isolation": + mutated["sessions"]["beta"]["events"][0]["parts"][0]["text"] = "Alpha session prefers red tea." + mutated["memory"]["alpha_black_coffee_other_user"] = copy.deepcopy(mutated["memory"]["outsider_black_coffee"]) + elif case_name == "event_metadata_roundtrip": + mutated["events"][0]["branch"] = "root.wrong.worker" + mutated["events"][0]["long_running_tool_ids"] = [] + elif case_name == "multi_part_event_roundtrip": + mutated["events"][0]["parts"].pop(1) + elif case_name == "memory_after_summary_truncation": + mutated["memory"]["summarized_mercury_memory"] = [] + elif case_name == "memory_multi_result_recall": + mutated["memory"]["orchid_all_matches"].pop() + elif case_name == "memory_limit_filters_before_truncation": + mutated["memory"]["older_apple_limit_one"] = [] + elif case_name == "cross_session_summary_isolation": + mutated["summary"]["text"] = mutated["sessions"]["beta"]["summary"]["text"] + mutated["sessions"]["alpha"]["summary"]["text"] = mutated["sessions"]["beta"]["summary"]["text"] + else: + raise AssertionError(f"No injected inconsistency registered for case {case_name}") + return mutated + + +def test_replay_case_catalog_covers_issue_requirements(): + cases = _load_replay_cases() + case_names = {case.name for case in cases} + operations = [operation for case in cases for operation in case.operations] + operation_names = {operation["op"] for operation in operations} + + assert len(cases) >= 10 + assert { + "single_turn_conversation", + "multi_turn_conversation", + "tool_call_conversation", + "state_overwrite", + "memory_preference_write_read", + "memory_fact_write_read", + "summary_create_update", + "summary_event_truncation", + "failed_append_recovery", + "duplicate_event_write_recovery", + "repeat_memory_store", + "partial_event_not_persisted", + "cross_session_user_isolation", + "event_metadata_roundtrip", + "multi_part_event_roundtrip", + "memory_after_summary_truncation", + "memory_multi_result_recall", + "cross_session_summary_isolation", + } <= case_names + assert {"append_text", "append_tool_call", "append_tool_response", "append_parts", "store_memory", + "summarize"} <= operation_names + assert any(operation.get("state_delta") for operation in operations) + assert any(operation.get("partial") for operation in operations) + assert any(operation.get("session_ref") for operation in operations) + assert any(operation.get("branch") for operation in operations) + assert any(case.memory_queries for case in cases) + assert sum(1 for operation in operations if operation["op"] == "summarize") >= 3 + assert "failed_append" in operation_names + + +@pytest.mark.parametrize("case_name", _replay_case_names()) +async def test_each_replay_case_runs_on_in_memory_backend(case_name): + snapshot = await _run_case_on_backend(_get_replay_case(case_name), _build_in_memory_backend) + + assert snapshot["backend"] == "in_memory" + assert snapshot["case"] == case_name + assert snapshot["session"]["id"] + assert "events" in snapshot + assert "memory" in snapshot + assert "summary" in snapshot + + +def test_backend_selection_supports_in_memory_only(monkeypatch): + monkeypatch.setenv(BACKENDS_ENV, "in_memory") + builders = _backend_builders() + assert [builder.name for builder in builders] == ["in_memory"] + assert builders[0].build == _build_in_memory_backend + + +def test_backend_selection_skips_integration_backends_without_env(monkeypatch): + monkeypatch.delenv(BACKENDS_ENV, raising=False) + monkeypatch.delenv(SQL_URL_ENV, raising=False) + monkeypatch.delenv(REDIS_URL_ENV, raising=False) + + assert [builder.name for builder in _backend_builders()] == ["in_memory", "sqlite"] + + +def test_backend_selection_rejects_unknown_backend(monkeypatch): + monkeypatch.setenv(BACKENDS_ENV, "missing_backend") + with pytest.raises(ValueError, match="Unknown or unavailable replay backend"): + _backend_builders() + + +def test_report_path_accepts_directory_or_file(monkeypatch, tmp_path): + monkeypatch.setenv(REPORT_PATH_ENV, str(tmp_path)) + assert _resolve_report_path(tmp_path) == tmp_path / REPORT_FILE_NAME + + explicit_file = tmp_path / "custom_report.json" + monkeypatch.setenv(REPORT_PATH_ENV, str(explicit_file)) + assert _resolve_report_path(tmp_path) == explicit_file + + +def test_allowed_diff_rules_are_explicit(): + paths = {rule["path"] for rule in ALLOWED_DIFFS} + assert "$.events[*].timestamp" in paths + assert "$.summary.updated_at" in paths + assert "$.memory.*[*].timestamp" in paths + assert "$.memory.*[*].order" in paths + assert all(rule["reason"] for rule in ALLOWED_DIFFS) + assert "$" not in paths + + +def test_replay_event_timestamps_do_not_depend_on_pytest_collection_time(): + event_time = _operation_timestamp({"timestamp": 1.0}) + + assert event_time > time.time() + REPLAY_EVENT_FUTURE_OFFSET_SECONDS - 1 + + +def test_allowed_diff_rules_are_applied_precisely(): + assert _allowed_diff_reason("$.events[3].timestamp") + assert _allowed_diff_reason("$.summary.updated_at") + assert _allowed_diff_reason("$.memory.foo[0].timestamp") + assert _allowed_diff_reason("$.events[3].id") is None + assert _allowed_diff_reason("$.memory.foo[0].order") + assert _allowed_diff_reason("$.events[3].parts[0].text") is None + + +async def test_session_memory_summary_replay_consistency(tmp_path): + case_reports, all_diffs, all_errors, attempted_backends, duration = await _run_all_cases() + report_path = _resolve_report_path(tmp_path) + mode = _report_mode(case_reports, attempted_backends) + report = { + "allowed_diff": ALLOWED_DIFFS, + "coverage": { + "case_count": len(case_reports), + "normal_diff_count": len(all_diffs), + "backend_error_count": len(all_errors), + "normal_false_positive_rate": 0.0 if not case_reports else len(all_diffs) / len(case_reports), + }, + "duration_seconds": round(duration, 6), + "errors": all_errors, + "mode": mode, + "cases": case_reports, + } + _write_report(report_path, report) + + assert len(case_reports) >= 10 + if mode["lightweight"]: + assert duration <= 30 + assert report_path.exists() + assert all_errors == [] + assert all_diffs == [] + + +async def test_run_all_cases_reports_backend_errors(monkeypatch): + async def _build_broken_backend() -> ReplayBackend: + raise RuntimeError("synthetic backend failure") + + monkeypatch.setenv(BACKENDS_ENV, "in_memory") + monkeypatch.setattr( + sys.modules[__name__], + "_backend_builders", + lambda: [ + ReplayBackendBuilder("in_memory", _build_in_memory_backend), + ReplayBackendBuilder("broken", _build_broken_backend), + ], + ) + + case_reports, all_diffs, all_errors, attempted_backends, _ = await _run_all_cases() + + assert case_reports + assert all_diffs == [] + assert all_errors + assert attempted_backends == ["in_memory", "broken"] + mode = _report_mode(case_reports, attempted_backends) + assert mode["attempted_backends"] == ["in_memory", "broken"] + assert mode["snapshot_backends"] == ["in_memory"] + assert mode["failed_backends"] == ["broken"] + assert {error["backend"] for error in all_errors} == {"broken"} + assert all("synthetic backend failure" in error["message"] for error in all_errors) + + +async def test_summary_snapshot_reads_service_summary(): + case = next(case for case in _load_replay_cases() if case.name == "summary_create_update") + snapshot = await _run_case_on_backend(case, _build_in_memory_backend) + + assert snapshot["summary"]["service_public_exists"] is True + assert snapshot["summary"]["service_public_text"] == snapshot["summary"]["text"] + assert snapshot["summary"]["service_manager_exists"] is True + assert snapshot["summary"]["service_manager_session_id"] == snapshot["session"]["id"] + assert snapshot["summary"]["service_manager_text"] == snapshot["summary"]["text"] + assert snapshot["summary"]["service_manager_original_event_count"] is not None + assert snapshot["summary"]["service_manager_compressed_event_count"] is not None + assert snapshot["summary"]["version"] == 2 + assert [record["version"] for record in snapshot["summary"]["versions"]] == [1, 2] + assert [record["source"] for record in snapshot["summary"]["versions"]] == ["historical", "active"] + assert all(record["session_id"] == snapshot["session"]["id"] for record in snapshot["summary"]["versions"]) + assert all(record["updated_at_present"] for record in snapshot["summary"]["versions"]) + assert snapshot["summary"]["latest_version_active"] is True + + +async def test_sqlite_file_backend_reloads_persisted_replay(tmp_path): + case = next(case for case in _load_replay_cases() if case.name == "memory_after_summary_truncation") + db_path = tmp_path / "replay-consistency.db" + db_url = f"sqlite:///{db_path.as_posix()}" + + backend = await _build_sqlite_backend_for_url(db_url, cleanup_paths=[db_path]) + try: + result = await _drive_case(case, backend) + before_restart = await _snapshot_backend( + case, + backend, + result, + include_service_summary=False, + include_cached_summary_metadata=False, + ) + persisted_sessions = result.sessions + finally: + await backend.close(cleanup_files=False) + + reloaded_backend = await _build_sqlite_backend_for_url(db_url, cleanup_paths=[db_path]) + try: + reloaded_result = await _reload_sessions_from_backend( + reloaded_backend, + persisted_sessions, + case.primary_session_ref, + ) + after_restart = await _snapshot_backend( + case, + reloaded_backend, + reloaded_result, + include_service_summary=False, + include_cached_summary_metadata=False, + ) + assert _compare_snapshots(before_restart, after_restart) == [] + assert after_restart["summary"]["exists"] is True + assert after_restart["summary"]["text"] + assert after_restart["summary"]["service_manager_exists"] is False + assert after_restart["summary"]["session_id"] == reloaded_result.primary_session.id + finally: + await reloaded_backend.close() + + +async def test_sql_cleanup_removes_run_scoped_session_and_memory(tmp_path): + case = next(case for case in _load_replay_cases() if case.name == "memory_preference_write_read") + db_path = tmp_path / "replay-cleanup.db" + backend = await _build_sqlite_backend_for_url(f"sqlite:///{db_path.as_posix()}", cleanup_paths=[db_path]) + try: + result = await _drive_case(case, backend) + session = result.primary_session + + assert await backend.session_service.get_session( + app_name=session.app_name, + user_id=session.user_id, + session_id=session.id, + ) + assert (await backend.memory_service.search_memory(session.save_key, "jasmine tea")).memories + + await _cleanup_sql_replay_data(backend.session_service, backend.memory_service) + + assert await backend.session_service.get_session( + app_name=session.app_name, + user_id=session.user_id, + session_id=session.id, + ) is None + assert (await backend.memory_service.search_memory(session.save_key, "jasmine tea")).memories == [] + finally: + await backend.close() + + +@pytest.mark.parametrize("case_name", _replay_case_names()) +async def test_replay_diff_engine_detects_each_injected_inconsistency(case_name): + case = _get_replay_case(case_name) + snapshot = await _run_case_on_backend(case, _build_in_memory_backend) + mutated = _inject_case_inconsistency(case.name, snapshot) + diffs = _compare_snapshots(snapshot, mutated) + assert diffs, f"Injected inconsistency for {case.name} was not detected" + + +@pytest.mark.parametrize( + ("case_name", "corruption_mode", "expected_path_fragment"), + [ + ("multi_turn_conversation", "drop_event", "$.events.length"), + ("duplicate_event_write_recovery", "duplicate_event", "$.events.length"), + ("state_overwrite", "dirty_state", "$.session.state.topic"), + ("summary_create_update", "summary_loss", "$.summary"), + ("summary_create_update", "summary_stale_overwrite", "$.summary"), + ("summary_event_truncation", "summary_wrong_owner", "$.summary.text"), + ("cross_session_summary_isolation", "summary_cross_session_leak", "$.summary.text"), + ("memory_preference_write_read", "drop_memory", "$.memory"), + ], +) +async def test_replay_harness_detects_backend_level_corruption( + case_name: str, + corruption_mode: str, + expected_path_fragment: str, +): + case = _get_replay_case(case_name) + reference = await _run_case_on_backend(case, _build_in_memory_backend) + corrupted = await _run_case_on_backend(case, _make_corrupting_sqlite_backend_builder(corruption_mode)) + + diffs = _compare_snapshots(reference, corrupted) + + assert diffs + assert any(diff["backend"] == f"sqlite_corrupt_{corruption_mode}" for diff in diffs) + assert any(diff["path"].startswith(expected_path_fragment) for diff in diffs) + + +async def test_summary_loss_overwrite_and_wrong_owner_are_detected(): + case = next(case for case in _load_replay_cases() if case.name == "summary_create_update") + snapshot = await _run_case_on_backend(case, _build_in_memory_backend) + + summary_lost = copy.deepcopy(snapshot) + summary_lost["backend"] = "summary_lost" + summary_lost["summary"]["exists"] = False + summary_lost["summary"]["text"] = None + assert _compare_snapshots(snapshot, summary_lost) + + summary_overwritten = copy.deepcopy(snapshot) + summary_overwritten["backend"] = "summary_overwritten" + summary_overwritten["summary"]["version"] = 1 + summary_overwritten["summary"]["anchor_text"] = "previous conversation summary: stale" + assert _compare_snapshots(snapshot, summary_overwritten) + + wrong_owner = copy.deepcopy(snapshot) + wrong_owner["backend"] = "wrong_owner" + wrong_owner["summary"]["session_id"] = "other-session" + assert _compare_snapshots(snapshot, wrong_owner) + + +async def test_in_memory_only_mode_runs_all_cases(monkeypatch): + monkeypatch.setenv(BACKENDS_ENV, "in_memory") + case_reports, all_diffs, all_errors, attempted_backends, duration = await _run_all_cases() + mode = _report_mode(case_reports, attempted_backends) + + assert len(case_reports) == len(_load_replay_cases()) + assert all(report["backends"] == ["in_memory"] for report in case_reports) + assert attempted_backends == ["in_memory"] + assert mode["lightweight"] is True + assert all_diffs == [] + assert all_errors == [] + assert duration <= 30 + + +def test_diff_entries_include_required_report_fields(): + base = { + "backend": "a", + "case": "synthetic", + "session": { + "id": "session-1" + }, + "events": [{ + "parts": [{ + "kind": "text", + "text": "old" + }] + }], + "summary": { + "text": "old", + "version": 1, + "versions": [{ + "summary_id": "session-1:summary:v1", + "text": "old", + }], + }, + } + changed = copy.deepcopy(base) + changed["backend"] = "b" + changed["events"][0]["parts"][0]["text"] = "new" + changed["summary"]["text"] = "new" + changed["summary"]["versions"][0]["text"] = "new" + + diffs = _compare_snapshots(base, changed) + + assert diffs + assert all({"case", "session_id", "backend", "reference_backend", "path", "reference", "actual"} <= set(diff) + for diff in diffs) + assert any(diff["event_index"] == 0 for diff in diffs) + assert any(diff["summary_id"] == "session-1:summary" for diff in diffs) + assert any(diff["summary_id"] == "session-1:summary:v1" for diff in diffs) + + +def test_diff_entries_use_nested_session_id_for_session_snapshots(): + base = { + "backend": "a", + "case": "synthetic", + "session": { + "id": "primary-session" + }, + "sessions": { + "alpha": { + "id": "alpha-session", + "events": [{ + "parts": [{ + "kind": "text", + "text": "old" + }] + }], + }, + "beta": { + "id": "beta-session", + "events": [{ + "parts": [{ + "kind": "text", + "text": "old" + }] + }], + }, + }, + "events": [], + "summary": {}, + } + changed = copy.deepcopy(base) + changed["backend"] = "b" + changed["sessions"]["beta"]["events"][0]["parts"][0]["text"] = "new" + + diffs = _compare_snapshots(base, changed) + + assert any(diff["path"] == "$.sessions.beta.events[0].parts[0].text" and diff["session_id"] == "beta-session" + for diff in diffs) + + +def test_diff_engine_reports_missing_keys_and_list_lengths(): + base = { + "backend": "a", + "case": "synthetic", + "session": { + "id": "session-1", + "state": { + "topic": "old" + }, + }, + "events": [{ + "parts": [] + }], + "summary": {}, + } + changed = copy.deepcopy(base) + changed["backend"] = "b" + changed["session"]["state"].pop("topic") + changed["events"].append({"parts": []}) + + diffs = _compare_snapshots(base, changed) + paths = {diff["path"] for diff in diffs} + + assert "$.session.state.topic" in paths + assert "$.events.length" in paths + + +def test_normalized_memory_response_compares_backend_order_as_multiset(): + older = MemoryEntry( + author="user", + timestamp="2026-01-01T00:00:00", + content=Content(parts=[Part.from_text(text="older")]), + ) + latest = MemoryEntry( + author="agent", + timestamp="2026-01-01T00:00:01", + content=Content(parts=[Part.from_text(text="latest")]), + ) + + left = _normalize_memory_response(SearchMemoryResponse(memories=[older, latest])) + right = _normalize_memory_response(SearchMemoryResponse(memories=[latest, older])) + + assert left == right + assert {item["parts"][0]["text"] for item in left} == {"older", "latest"} + + +async def test_replay_harness_detects_memory_limit_filtering_difference(): + case = ReplayCase( + name="memory_limit_filters_before_truncation", + description="detects when a backend applies limit before query filtering", + operations=[ + {"op": "create_session", "session_id": "memory-limit-filter"}, + { + "op": "append_text", + "event_id": "memory-limit-user-1", + "invocation_id": "inv-memory-limit-1", + "author": "user", + "text": "Older apple preference should be recalled.", + "timestamp": 1160.0, + }, + { + "op": "append_text", + "event_id": "memory-limit-agent-1", + "invocation_id": "inv-memory-limit-1", + "author": "agent", + "text": "Newer banana note is unrelated.", + "timestamp": 1161.0, + }, + {"op": "store_memory"}, + ], + memory_queries=[{"name": "older_apple_limit_one", "query": "apple", "limit": 1}], + ) + + reference = await _run_case_on_backend(case, _build_in_memory_backend) + corrupted = await _run_case_on_backend(case, _make_corrupting_sqlite_backend_builder("memory_limit_filtering")) + + diffs = _compare_snapshots(reference, corrupted) + + assert diffs + assert any(diff["backend"] == "sqlite_corrupt_memory_limit_filtering" for diff in diffs) + assert any(diff["path"].startswith("$.memory.older_apple_limit_one") for diff in diffs)