Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ jobs:
# run: pytest --cov=trpc_agent_sdk --cov-report=xml --cov-report=term tests/
run: pytest --cov=trpc_agent_sdk --cov-report=xml --cov-report=term --cov-fail-under=80 tests/

- name: Run InMemory-only replay smoke test (not full matrix)
env:
TRPC_REPLAY_BACKENDS: in_memory
# The full cross-backend replay matrix runs in the coverage step above.
run: pytest -q tests/sessions/test_replay_consistency.py tests/sessions/test_replay_real_agent.py

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
env:
Expand Down
2 changes: 1 addition & 1 deletion requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Test framework
pytest
pytest-mock
pytest-asyncio
pytest-asyncio>=0.24.0
pyparsing>=2.4.2
pytest-cov
unittest-xml-reporting
Expand Down
3 changes: 3 additions & 0 deletions tests/sessions/DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Session / Memory / Summary Replay Harness 设计说明

同一组轨迹驱动 InMemory、SQLite 和可选 Redis,快照覆盖事件、state、memory、summary。归一化只处理自动 ID、相对时间、Unicode 空白和无序容器;Summary 文本可规范化,但 session 归属、版本和覆盖关系必须一致。差异按后端对和字段路径精确匹配。SQLite 重开验证持久化;`TRPC_REPLAY_BACKENDS=in_memory` 为轻量模式。两份 JSON 均为测试生成产物,可删除后重跑再生,不是手写契约。
34 changes: 34 additions & 0 deletions tests/sessions/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#
# 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 the Apache License Version 2.0.
#
"""Collection policy for the replay acceptance tests."""

import os

import pytest

BACKEND_MODE_ENVIRONMENT_VARIABLE = "TRPC_REPLAY_BACKENDS"
IN_MEMORY_BACKEND_MODE = "in_memory"
IN_MEMORY_TEST_NAME = "test_in_memory_only_lightweight_mode"
IN_MEMORY_REAL_AGENT_SAFE_TEST_NAME = "test_subtle_realistic_drift_is_detected"
REPLAY_TEST_FILES = frozenset({
"test_replay_consistency.py",
"test_replay_real_agent.py",
})
IN_MEMORY_SKIP_REASON = "disabled by TRPC_REPLAY_BACKENDS=in_memory"


def pytest_collection_modifyitems(items):
"""Keep only the lightweight replay when InMemory-only mode is selected."""
if os.getenv(BACKEND_MODE_ENVIRONMENT_VARIABLE) != IN_MEMORY_BACKEND_MODE:
return
skip = pytest.mark.skip(reason=IN_MEMORY_SKIP_REASON)
for item in items:
if (item.path.name == "test_replay_consistency.py" and item.name != IN_MEMORY_TEST_NAME) or (
item.path.name == "test_replay_real_agent.py"
and item.name != IN_MEMORY_REAL_AGENT_SAFE_TEST_NAME):
item.add_marker(skip)
56 changes: 56 additions & 0 deletions tests/sessions/real_agent_replay_validation_report.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"case_id": "real_agent_tool_memory",
"clean_comparison": {
"diffs": [],
"unexpected_diff_count": 0
},
"injected_anomalies": {
"memory_single_character_drift": {
"detected": true,
"diffs": [
{
"allowed": false,
"backend_pair": [
"in_memory",
"sqlite"
],
"case_id": "real_agent_tool_memory",
"category": "memory",
"event_index": null,
"field_path": "/memory/Chinese/memories/0/content/parts/0/text",
"left": "Here are the preferences for **replay-user**:\n\n- **Preferred Language:** Chinese\n- **Notification Channel:** email",
"reason": null,
"right": "Here are the preferences for **replay-user**:\n\n- **Preferred Language:** Chinese\n- **Notification Channel:** emaiX",
"session_id": "replay-session",
"summary_id": null
}
],
"unexpected_diff_count": 1
},
"tool_response_single_character_drift": {
"detected": true,
"diffs": [
{
"allowed": false,
"backend_pair": [
"in_memory",
"sqlite"
],
"case_id": "real_agent_tool_memory",
"category": "events",
"event_index": 2,
"field_path": "/events/2/content/parts/0/function_response/response/preferred_language",
"left": "Chinese",
"reason": null,
"right": "ChinesX",
"session_id": "replay-session",
"summary_id": null
}
],
"unexpected_diff_count": 1
}
},
"model": "deepseek-v4-flash",
"schema_version": 1,
"tool_round_trip": true
}
Loading
Loading