abhishekrn commited on
Commit
fd77b1e
·
1 Parent(s): 979df15

Clean up: Remove docs, scripts, tests directories and simplify pyproject.toml and requirements.txt

Browse files
app.py CHANGED
@@ -18,10 +18,7 @@ demo = gr.ChatInterface(
18
  title="🧠 Topcoder MCP Agent",
19
  theme="soft",
20
  examples=[
21
- "Active AI Challenges",
22
- "get details about user abhishekrn",
23
- "Tell me a joke",
24
- "Show cache stats",
25
  ],
26
  type="messages",
27
  )
 
18
  title="🧠 Topcoder MCP Agent",
19
  theme="soft",
20
  examples=[
21
+ "Active AI Challenges", "Help", "Tell me a joke"
 
 
 
22
  ],
23
  type="messages",
24
  )
docs/conversation_history.md DELETED
@@ -1,182 +0,0 @@
1
- # Conversation History Feature
2
-
3
- ## Overview
4
-
5
- The Topcoder MCP Agent now supports conversation history, allowing the LLM to maintain context across multiple interactions. This enables more coherent and contextual conversations with users.
6
-
7
- ## Features
8
-
9
- ### 1. **Sliding Window History**
10
- - Maintains a configurable number of recent messages (default: 20)
11
- - Automatically removes older messages when the limit is reached
12
- - Preserves conversation context while managing memory usage
13
-
14
- ### 2. **Session Management**
15
- - Each conversation gets a unique session ID
16
- - Sessions persist for 24 hours by default
17
- - Automatic cleanup of expired sessions
18
-
19
- ### 3. **Token Management**
20
- - Rough token estimation (4 characters per token)
21
- - Configurable token limits to prevent context overflow
22
- - Automatic trimming when approaching limits
23
-
24
- ### 4. **Context-Aware Prompts**
25
- - Tool decision prompts include conversation context
26
- - Parameter extraction considers previous interactions
27
- - Response summarization maintains conversation flow
28
-
29
- ## Configuration
30
-
31
- ### Environment Variables
32
-
33
- Add these to your `.env` file:
34
-
35
- ```bash
36
- # Conversation History Settings
37
- CONVERSATION_ENABLE_HISTORY=true
38
- CONVERSATION_MAX_HISTORY_LENGTH=20
39
- CONVERSATION_MAX_TOKENS=4000
40
- ```
41
-
42
- ### Settings Explained
43
-
44
- - `CONVERSATION_ENABLE_HISTORY`: Enable/disable conversation history (default: true)
45
- - `CONVERSATION_MAX_HISTORY_LENGTH`: Maximum number of messages to keep (default: 20)
46
- - `CONVERSATION_MAX_TOKENS`: Approximate token limit for conversation context (default: 4000)
47
-
48
- ## Architecture
49
-
50
- ### Core Components
51
-
52
- 1. **ConversationHistoryService** (`src/domain/services/conversation_history.py`)
53
- - Manages message storage and retrieval
54
- - Implements sliding window logic
55
- - Handles token estimation and limits
56
-
57
- 2. **SessionManager** (`src/domain/services/session_manager.py`)
58
- - Manages conversation sessions
59
- - Handles session creation and cleanup
60
- - Tracks session activity and expiration
61
-
62
- 3. **Updated LLM Provider** (`src/infrastructure/providers/llm_provider.py`)
63
- - New `chat_with_history()` method
64
- - History-aware tool decision making
65
- - Context-aware parameter extraction
66
-
67
- 4. **Enhanced Prompt Service** (`src/application/services/prompt_service.py`)
68
- - Builds prompts with conversation context
69
- - Includes recent message history in tool decisions
70
-
71
- ### Data Flow
72
-
73
- ```
74
- User Input → Session Manager → Conversation History → LLM Provider → Response → History Update
75
- ```
76
-
77
- ## Usage Examples
78
-
79
- ### Basic Conversation Flow
80
-
81
- 1. **First Message**: User asks "Show me active challenges"
82
- - System creates new session
83
- - Stores user message in history
84
- - LLM decides to use `query-tc-challenges` tool
85
- - Response is stored in history
86
-
87
- 2. **Follow-up**: User asks "What about AI challenges specifically?"
88
- - System retrieves conversation history
89
- - LLM considers previous context about challenges
90
- - More specific query to `query-tc-challenges` with AI filter
91
- - Response maintains conversation continuity
92
-
93
- ### Context Preservation
94
-
95
- The system maintains context across interactions:
96
-
97
- ```
98
- User: "Show me active challenges"
99
- Assistant: "Here are the active challenges..."
100
-
101
- User: "What about AI challenges?"
102
- Assistant: "Looking at the active challenges, here are the AI-specific ones..."
103
- ```
104
-
105
- ## Testing
106
-
107
- Run the conversation history tests:
108
-
109
- ```bash
110
- pytest tests/unit/test_conversation_history.py -v
111
- ```
112
-
113
- ## Performance Considerations
114
-
115
- ### Memory Usage
116
- - Each session stores messages in memory
117
- - Sessions are automatically cleaned up after 24 hours
118
- - Token limits prevent excessive memory usage
119
-
120
- ### Response Time
121
- - History retrieval adds minimal overhead
122
- - Token estimation is fast (simple character count)
123
- - Context inclusion improves response quality
124
-
125
- ### Scalability
126
- - Sessions are stored in memory (not persistent)
127
- - For production, consider database storage
128
- - Implement session cleanup for long-running applications
129
-
130
- ## Future Enhancements
131
-
132
- ### Planned Features
133
- 1. **Persistent Storage**: Database-backed session storage
134
- 2. **Advanced Token Counting**: More accurate token estimation
135
- 3. **Context Summarization**: Automatic context compression
136
- 4. **Multi-User Support**: User-specific session management
137
- 5. **Context Analytics**: Track conversation patterns and effectiveness
138
-
139
- ### Configuration Options
140
- 1. **Session Persistence**: Choose between memory and database storage
141
- 2. **Context Compression**: Automatic summarization of old messages
142
- 3. **User Preferences**: Per-user history settings
143
- 4. **Context Filtering**: Selective inclusion of relevant history
144
-
145
- ## Troubleshooting
146
-
147
- ### Common Issues
148
-
149
- 1. **Memory Usage High**
150
- - Reduce `CONVERSATION_MAX_HISTORY_LENGTH`
151
- - Enable session cleanup more frequently
152
- - Monitor active session count
153
-
154
- 2. **Context Not Working**
155
- - Verify `CONVERSATION_ENABLE_HISTORY=true`
156
- - Check session creation in logs
157
- - Ensure history is being passed to LLM calls
158
-
159
- 3. **Slow Responses**
160
- - Reduce `CONVERSATION_MAX_TOKENS`
161
- - Limit history length
162
- - Check token estimation accuracy
163
-
164
- ### Debug Information
165
-
166
- Enable debug logging to see conversation flow:
167
-
168
- ```python
169
- # Add to your application startup
170
- import logging
171
- logging.basicConfig(level=logging.DEBUG)
172
- ```
173
-
174
- ## Migration from v1
175
-
176
- The conversation history feature is backward compatible. Existing applications will continue to work without changes. To enable history:
177
-
178
- 1. Set `CONVERSATION_ENABLE_HISTORY=true`
179
- 2. Configure history limits as needed
180
- 3. Restart the application
181
-
182
- The system will automatically start maintaining conversation context for new interactions.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pyproject.toml CHANGED
@@ -11,165 +11,24 @@ license = {text = "MIT"}
11
  authors = [
12
  {name = "Topcoder Team", email = "support@topcoder.com"}
13
  ]
14
- classifiers = [
15
- "Development Status :: 4 - Beta",
16
- "Intended Audience :: Developers",
17
- "License :: OSI Approved :: MIT License",
18
- "Programming Language :: Python :: 3.9",
19
- "Programming Language :: Python :: 3.10",
20
- "Programming Language :: Python :: 3.11",
21
- "Programming Language :: Python :: 3.12",
22
- "Topic :: Software Development :: Libraries :: Python Modules",
23
- "Topic :: Scientific/Engineering :: Artificial Intelligence",
24
- ]
25
  requires-python = ">=3.9"
26
  dependencies = [
27
- # Core dependencies
28
  "pydantic>=2.5.0",
29
  "dependency-injector>=4.41.0",
30
-
31
- # HTTP and async
32
  "aiohttp>=3.9.0",
33
  "asyncio-mqtt>=0.16.0",
34
-
35
- # Configuration
36
  "python-dotenv>=1.0.0",
37
  "pyyaml>=6.0.0",
38
-
39
- # UI
40
  "gradio>=4.0.0",
41
-
42
- # Data handling
43
  "orjson>=3.9.0",
44
  "jsonschema>=4.20.0",
45
-
46
- # Logging and monitoring
47
  "structlog>=23.2.0",
48
  "prometheus-client>=0.19.0",
49
-
50
- # Testing utilities
51
- "pytest>=7.4.0",
52
- "pytest-asyncio>=0.21.0",
53
- "pytest-cov>=4.1.0",
54
- "httpx>=0.25.0", # For testing HTTP clients
55
-
56
- # Development utilities
57
- "black>=23.0.0",
58
- "isort>=5.12.0",
59
- "mypy>=1.7.0",
60
- "ruff>=0.1.0",
61
- ]
62
-
63
- [project.optional-dependencies]
64
- dev = [
65
- "pre-commit>=3.0.0",
66
- "tox>=4.0.0",
67
- "sphinx>=7.0.0",
68
- "sphinx-rtd-theme>=1.3.0",
69
  ]
70
 
71
- [project.urls]
72
- Homepage = "https://github.com/topcoder/mcp-agent-zephyr"
73
- Repository = "https://github.com/topcoder/mcp-agent-zephyr"
74
- Documentation = "https://topcoder.github.io/mcp-agent-zephyr"
75
- "Bug Tracker" = "https://github.com/topcoder/mcp-agent-zephyr/issues"
76
-
77
  [project.scripts]
78
  topcoder-agent = "src.main:main"
79
 
80
  [tool.setuptools.packages.find]
81
  where = ["."]
82
- include = ["src*"]
83
- exclude = ["tests*"]
84
-
85
- [tool.pytest.ini_options]
86
- testpaths = ["tests"]
87
- python_files = ["test_*.py", "*_test.py"]
88
- python_classes = ["Test*"]
89
- python_functions = ["test_*"]
90
- addopts = [
91
- "--strict-markers",
92
- "--strict-config",
93
- "--cov=src",
94
- "--cov-report=html",
95
- "--cov-report=term-missing",
96
- "--cov-report=xml",
97
- ]
98
- markers = [
99
- "unit: Unit tests",
100
- "integration: Integration tests",
101
- "e2e: End-to-end tests",
102
- "slow: Slow running tests",
103
- ]
104
-
105
- [tool.black]
106
- line-length = 100
107
- target-version = ['py39']
108
- include = '\.pyi?$'
109
- extend-exclude = '''
110
- /(
111
- # directories
112
- \.eggs
113
- | \.git
114
- | \.hg
115
- | \.mypy_cache
116
- | \.tox
117
- | \.venv
118
- | build
119
- | dist
120
- )/
121
- '''
122
-
123
- [tool.isort]
124
- profile = "black"
125
- line_length = 100
126
- multi_line_output = 3
127
- include_trailing_comma = true
128
- force_grid_wrap = 0
129
- use_parentheses = true
130
- ensure_newline_before_comments = true
131
-
132
- [tool.mypy]
133
- python_version = "3.9"
134
- warn_return_any = true
135
- warn_unused_configs = true
136
- disallow_untyped_defs = true
137
- disallow_incomplete_defs = true
138
- check_untyped_defs = true
139
- disallow_untyped_decorators = true
140
- no_implicit_optional = true
141
- warn_redundant_casts = true
142
- warn_unused_ignores = true
143
- warn_no_return = true
144
- warn_unreachable = true
145
- strict_equality = true
146
- show_error_codes = true
147
-
148
- [[tool.mypy.overrides]]
149
- module = [
150
- "gradio.*",
151
- "dependency_injector.*",
152
- ]
153
- ignore_missing_imports = true
154
-
155
- [tool.ruff]
156
- target-version = "py39"
157
- line-length = 100
158
- select = [
159
- "E", # pycodestyle errors
160
- "W", # pycodestyle warnings
161
- "F", # pyflakes
162
- "I", # isort
163
- "C", # flake8-comprehensions
164
- "B", # flake8-bugbear
165
- "UP", # pyupgrade
166
- ]
167
- ignore = [
168
- "E501", # line too long, handled by black
169
- "B008", # do not perform function calls in argument defaults
170
- "C901", # too complex
171
- ]
172
-
173
- [tool.ruff.per-file-ignores]
174
- "__init__.py" = ["F401"]
175
- "tests/*" = ["S101"] # Use of assert in tests
 
11
  authors = [
12
  {name = "Topcoder Team", email = "support@topcoder.com"}
13
  ]
 
 
 
 
 
 
 
 
 
 
 
14
  requires-python = ">=3.9"
15
  dependencies = [
 
16
  "pydantic>=2.5.0",
17
  "dependency-injector>=4.41.0",
 
 
18
  "aiohttp>=3.9.0",
19
  "asyncio-mqtt>=0.16.0",
 
 
20
  "python-dotenv>=1.0.0",
21
  "pyyaml>=6.0.0",
 
 
22
  "gradio>=4.0.0",
 
 
23
  "orjson>=3.9.0",
24
  "jsonschema>=4.20.0",
 
 
25
  "structlog>=23.2.0",
26
  "prometheus-client>=0.19.0",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  ]
28
 
 
 
 
 
 
 
29
  [project.scripts]
30
  topcoder-agent = "src.main:main"
31
 
32
  [tool.setuptools.packages.find]
33
  where = ["."]
34
+ include = ["src*"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -1,19 +1,11 @@
1
- # Core dependencies
2
- gradio>=4.0.0
3
- aiohttp>=3.8.0
 
4
  python-dotenv>=1.0.0
5
- pyyaml>=6.0
6
-
7
- # Data handling
8
- dataclasses; python_version<"3.7"
9
-
10
- # MCP (Model Context Protocol) - if available
11
- # mcp # Uncomment if using official MCP package
12
-
13
- # Development dependencies (optional)
14
- # pytest>=7.0.0
15
- # pytest-asyncio>=0.21.0
16
-
17
- # Note: Built-in Python packages used:
18
- # - json, os, sys, uuid, asyncio, logging, pathlib, datetime, enum, typing
19
- # These are included with Python standard library
 
1
+ pydantic>=2.5.0
2
+ dependency-injector>=4.41.0
3
+ aiohttp>=3.9.0
4
+ asyncio-mqtt>=0.16.0
5
  python-dotenv>=1.0.0
6
+ pyyaml>=6.0.0
7
+ gradio>=4.0.0
8
+ orjson>=3.9.0
9
+ jsonschema>=4.20.0
10
+ structlog>=23.2.0
11
+ prometheus-client>=0.19.0
 
 
 
 
 
 
 
 
 
scripts/generate_compact_specs.py DELETED
@@ -1,56 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Script to generate compact API specifications from MCP catalog.
4
- This condenses large Swagger and tools documents into compact form.
5
- """
6
-
7
- import asyncio
8
- import sys
9
- import os
10
- from pathlib import Path
11
-
12
- # Add src to path and set up environment
13
- project_root = Path(__file__).parent.parent
14
- src_path = project_root / "src"
15
- sys.path.insert(0, str(src_path))
16
- os.chdir(project_root)
17
-
18
- # Now import with absolute imports
19
- from src.mcp.specs_generator import SpecsGenerator
20
-
21
-
22
- async def main():
23
- """Generate compact API specifications."""
24
- print("🔧 Generating compact API specifications...")
25
-
26
- try:
27
- # Initialize specs generator
28
- generator = SpecsGenerator()
29
-
30
- # Generate compact specs
31
- specs = await generator.generate_compact_specs()
32
-
33
- # Save to file
34
- generator.save_compact_specs(specs)
35
-
36
- # Print summary
37
- generator.print_summary(specs)
38
-
39
- print("\n✅ Compact specs generation completed successfully!")
40
- print(f"📁 Output saved to: {generator.output_path}")
41
- print(f"📂 Data folder location: data/compact_api_specs.py")
42
-
43
- # Test the compact utils
44
- print("\n🧪 Testing compact utils...")
45
- from src.mcp.compact_utils import CompactSpecsUtils
46
-
47
- utils = CompactSpecsUtils()
48
- utils.print_compact_summary()
49
-
50
- except Exception as e:
51
- print(f"❌ Error generating compact specs: {e}")
52
- sys.exit(1)
53
-
54
-
55
- if __name__ == "__main__":
56
- asyncio.run(main())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/presentation/gradio_interface.py CHANGED
@@ -173,7 +173,7 @@ def launch_ui():
173
  fn=agent_response,
174
  title="🧠 Topcoder MCP Agent",
175
  theme="soft",
176
- examples=["Active AI Challenges", "get details about user abhishekrn", "Tell me a joke"],
177
  type="messages" # Fix deprecation warning
178
  )
179
  demo.launch()
 
173
  fn=agent_response,
174
  title="🧠 Topcoder MCP Agent",
175
  theme="soft",
176
+ examples=["Active AI Challenges", "Help", "Tell me a joke"],
177
  type="messages" # Fix deprecation warning
178
  )
179
  demo.launch()
tests/unit/test_conversation_history.py DELETED
@@ -1,110 +0,0 @@
1
- import pytest
2
- from datetime import datetime
3
- from src.domain.services.conversation_history import ConversationHistoryService, Message, ConversationSession
4
-
5
- class TestConversationHistory:
6
-
7
- def setup_method(self):
8
- """Set up test fixtures."""
9
- self.history_service = ConversationHistoryService(default_max_history=5, default_max_tokens=1000)
10
- self.session_id = "test_session_123"
11
-
12
- def test_add_message(self):
13
- """Test adding messages to conversation history."""
14
- # Add user message
15
- self.history_service.add_message(self.session_id, "user", "Hello, how are you?")
16
-
17
- # Add assistant message
18
- self.history_service.add_message(self.session_id, "assistant", "I'm doing well, thank you!")
19
-
20
- # Get conversation history
21
- history = self.history_service.get_conversation_history(self.session_id)
22
-
23
- assert len(history) == 2
24
- assert history[0]["role"] == "user"
25
- assert history[0]["content"] == "Hello, how are you?"
26
- assert history[1]["role"] == "assistant"
27
- assert history[1]["content"] == "I'm doing well, thank you!"
28
-
29
- def test_history_limits(self):
30
- """Test that history limits are applied correctly."""
31
- # Add more messages than the limit
32
- for i in range(10):
33
- self.history_service.add_message(self.session_id, "user", f"Message {i}")
34
- self.history_service.add_message(self.session_id, "assistant", f"Response {i}")
35
-
36
- # Should only keep the last 5 messages (due to default_max_history=5)
37
- history = self.history_service.get_conversation_history(self.session_id)
38
- assert len(history) == 5
39
-
40
- # Should be the last 5 messages from the conversation
41
- # With 10 pairs (20 messages total), we should have the last 5 messages
42
- # which would be: Message 8, Response 8, Message 9, Response 9, Message 9 (or similar)
43
- # Let's just verify we have the right number and they're recent
44
- assert len(history) == 5
45
- # The last message should be from the last iteration (9)
46
- assert "9" in history[-1]["content"] or "9" in history[-2]["content"]
47
-
48
- def test_get_recent_messages(self):
49
- """Test getting recent messages."""
50
- # Add several messages
51
- for i in range(5):
52
- self.history_service.add_message(self.session_id, "user", f"Message {i}")
53
- self.history_service.add_message(self.session_id, "assistant", f"Response {i}")
54
-
55
- # Get last 3 messages
56
- recent = self.history_service.get_recent_messages(self.session_id, count=3)
57
- assert len(recent) == 3
58
- # Should be the last 3 messages from the conversation
59
- # With 5 pairs (10 messages total), last 3 would be from the end
60
- assert len(recent) == 3
61
- # The last message should be from the last iteration (4)
62
- assert "4" in recent[-1]["content"] or "4" in recent[-2]["content"]
63
-
64
- def test_clear_history(self):
65
- """Test clearing conversation history."""
66
- # Add some messages
67
- self.history_service.add_message(self.session_id, "user", "Test message")
68
- self.history_service.add_message(self.session_id, "assistant", "Test response")
69
-
70
- # Clear history
71
- self.history_service.clear_history(self.session_id)
72
-
73
- # Verify history is empty
74
- history = self.history_service.get_conversation_history(self.session_id)
75
- assert len(history) == 0
76
-
77
- def test_session_info(self):
78
- """Test getting session information."""
79
- # Add some messages
80
- self.history_service.add_message(self.session_id, "user", "Test message")
81
- self.history_service.add_message(self.session_id, "assistant", "Test response")
82
-
83
- # Get session info
84
- info = self.history_service.get_session_info(self.session_id)
85
-
86
- assert info["session_id"] == self.session_id
87
- assert info["message_count"] == 2
88
- assert info["max_history_length"] == 5
89
- assert info["max_tokens"] == 1000
90
- assert "created_at" in info
91
- assert "last_updated" in info
92
-
93
- def test_token_estimation(self):
94
- """Test token estimation functionality."""
95
- text = "This is a test message with some content."
96
- estimated_tokens = self.history_service._estimate_tokens(text)
97
-
98
- # Should be roughly 1/4 of the character count
99
- expected_tokens = len(text) // 4
100
- assert estimated_tokens == expected_tokens
101
-
102
- def test_total_tokens(self):
103
- """Test total token calculation."""
104
- # Add messages with known content
105
- self.history_service.add_message(self.session_id, "user", "Hello")
106
- self.history_service.add_message(self.session_id, "assistant", "Hi there")
107
-
108
- total_tokens = self.history_service.get_total_tokens(self.session_id)
109
- expected_tokens = (len("Hello") + len("Hi there")) // 4
110
- assert total_tokens == expected_tokens