Spaces:
Sleeping
Sleeping
Commit ·
fd77b1e
1
Parent(s): 979df15
Clean up: Remove docs, scripts, tests directories and simplify pyproject.toml and requirements.txt
Browse files- app.py +1 -4
- docs/conversation_history.md +0 -182
- pyproject.toml +1 -142
- requirements.txt +10 -18
- scripts/generate_compact_specs.py +0 -56
- src/presentation/gradio_interface.py +1 -1
- tests/unit/test_conversation_history.py +0 -110
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 |
-
|
| 2 |
-
|
| 3 |
-
aiohttp>=3.
|
|
|
|
| 4 |
python-dotenv>=1.0.0
|
| 5 |
-
pyyaml>=6.0
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 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", "
|
| 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|