From 7d33aafcab22aeb856192f4d88e3a2c24c8c6dcd Mon Sep 17 00:00:00 2001 From: Fahad Date: Sat, 14 Jun 2025 14:00:13 +0400 Subject: [PATCH] Configurable conversation limit now set to 10 exchanges. This helps when you want to manually continue a thread of thought across different models manually. --- .env.example | 6 ++++++ .gitignore | 3 +++ README.md | 2 +- docker-compose.yml | 1 + tests/test_claude_continuation.py | 12 ++++++------ utils/conversation_memory.py | 12 +++++++++++- 6 files changed, 28 insertions(+), 8 deletions(-) diff --git a/.env.example b/.env.example index fb94221..35d2ccc 100644 --- a/.env.example +++ b/.env.example @@ -92,6 +92,12 @@ DEFAULT_THINKING_MODE_THINKDEEP=high # Defaults to 3 hours if not specified CONVERSATION_TIMEOUT_HOURS=3 +# Optional: Max conversation turns +# Maximum number of turns allowed in an AI-to-AI conversation thread +# Each exchange (Claude asks, Gemini responds) counts as 2 turns +# So 20 turns = 10 exchanges. Defaults to 20 if not specified +MAX_CONVERSATION_TURNS=20 + # Optional: Logging level (DEBUG, INFO, WARNING, ERROR) # DEBUG: Shows detailed operational messages for troubleshooting (default) # INFO: Shows general operational messages diff --git a/.gitignore b/.gitignore index 9675212..bcccb6b 100644 --- a/.gitignore +++ b/.gitignore @@ -166,3 +166,6 @@ test_simulation_files/.claude/ # Temporary test directories test-setup/ + +# Scratch feature documentation files +FEATURE_*.md diff --git a/README.md b/README.md index 8f3fb56..c61e0f3 100644 --- a/README.md +++ b/README.md @@ -470,7 +470,7 @@ This server enables **true AI collaboration** between Claude and multiple AI mod - **Asynchronous workflow**: Conversations don't need to be sequential - Claude can work on tasks between exchanges, then return to Gemini with additional context and progress updates - **Incremental updates**: Share only new information in each exchange while maintaining full conversation history - **Automatic 25K limit bypass**: Each exchange sends only incremental context, allowing unlimited total conversation size -- Up to 5 exchanges per conversation with 3-hour expiry (configurable) +- Up to 10 exchanges per conversation (configurable via `MAX_CONVERSATION_TURNS`) with 3-hour expiry (configurable via `CONVERSATION_TIMEOUT_HOURS`) - Thread-safe with Redis persistence across all tools **Cross-tool & Cross-Model Continuation Example:** diff --git a/docker-compose.yml b/docker-compose.yml index d33242d..4b40b32 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -41,6 +41,7 @@ services: - DEFAULT_MODEL=${DEFAULT_MODEL:-auto} - DEFAULT_THINKING_MODE_THINKDEEP=${DEFAULT_THINKING_MODE_THINKDEEP:-high} - CONVERSATION_TIMEOUT_HOURS=${CONVERSATION_TIMEOUT_HOURS:-3} + - MAX_CONVERSATION_TURNS=${MAX_CONVERSATION_TURNS:-20} # Model usage restrictions - OPENAI_ALLOWED_MODELS=${OPENAI_ALLOWED_MODELS:-} - GOOGLE_ALLOWED_MODELS=${GOOGLE_ALLOWED_MODELS:-} diff --git a/tests/test_claude_continuation.py b/tests/test_claude_continuation.py index 9f666f7..7a699e8 100644 --- a/tests/test_claude_continuation.py +++ b/tests/test_claude_continuation.py @@ -146,8 +146,8 @@ class TestClaudeContinuationOffers: # Should still offer continuation since turns remain assert response_data["status"] == "continuation_available" assert "continuation_offer" in response_data - # 10 max - 2 existing - 1 new = 7 remaining - assert response_data["continuation_offer"]["remaining_turns"] == 7 + # MAX_CONVERSATION_TURNS - 2 existing - 1 new = remaining + assert response_data["continuation_offer"]["remaining_turns"] == MAX_CONVERSATION_TURNS - 3 @patch("utils.conversation_memory.get_redis_client") @patch.dict("os.environ", {"PYTEST_CURRENT_TEST": ""}, clear=False) @@ -267,10 +267,10 @@ I'd be happy to examine the error handling patterns in more detail if that would # Parse response response_data = json.loads(response[0].text) - # Should offer continuation since there are remaining turns (9 remaining: 10 max - 0 current - 1) + # Should offer continuation since there are remaining turns (MAX - 0 current - 1) assert response_data["status"] == "continuation_available" assert response_data.get("continuation_offer") is not None - assert response_data["continuation_offer"]["remaining_turns"] == 9 + assert response_data["continuation_offer"]["remaining_turns"] == MAX_CONVERSATION_TURNS - 1 @patch("utils.conversation_memory.get_redis_client") @patch.dict("os.environ", {"PYTEST_CURRENT_TEST": ""}, clear=False) @@ -465,8 +465,8 @@ class TestContinuationIntegration: # Should still offer continuation if there are remaining turns assert response_data2["status"] == "continuation_available" assert "continuation_offer" in response_data2 - # 10 max - 1 existing - 1 new = 8 remaining - assert response_data2["continuation_offer"]["remaining_turns"] == 8 + # MAX_CONVERSATION_TURNS - 1 existing - 1 new = remaining + assert response_data2["continuation_offer"]["remaining_turns"] == MAX_CONVERSATION_TURNS - 2 if __name__ == "__main__": diff --git a/utils/conversation_memory.py b/utils/conversation_memory.py index cbb95ea..c0f80ce 100644 --- a/utils/conversation_memory.py +++ b/utils/conversation_memory.py @@ -57,7 +57,17 @@ from pydantic import BaseModel logger = logging.getLogger(__name__) # Configuration constants -MAX_CONVERSATION_TURNS = 10 # Maximum turns allowed per conversation thread +# Get max conversation turns from environment, default to 20 turns (10 exchanges) +try: + MAX_CONVERSATION_TURNS = int(os.getenv("MAX_CONVERSATION_TURNS", "20")) + if MAX_CONVERSATION_TURNS <= 0: + logger.warning(f"Invalid MAX_CONVERSATION_TURNS value ({MAX_CONVERSATION_TURNS}), using default of 20 turns") + MAX_CONVERSATION_TURNS = 20 +except ValueError: + logger.warning( + f"Invalid MAX_CONVERSATION_TURNS value ('{os.getenv('MAX_CONVERSATION_TURNS')}'), using default of 20 turns" + ) + MAX_CONVERSATION_TURNS = 20 # Get conversation timeout from environment (in hours), default to 3 hours try: