codetether 1.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- a2a_server/__init__.py +29 -0
- a2a_server/a2a_agent_card.py +365 -0
- a2a_server/a2a_errors.py +1133 -0
- a2a_server/a2a_executor.py +926 -0
- a2a_server/a2a_router.py +1033 -0
- a2a_server/a2a_types.py +344 -0
- a2a_server/agent_card.py +408 -0
- a2a_server/agents_server.py +271 -0
- a2a_server/auth_api.py +349 -0
- a2a_server/billing_api.py +638 -0
- a2a_server/billing_service.py +712 -0
- a2a_server/billing_webhooks.py +501 -0
- a2a_server/config.py +96 -0
- a2a_server/database.py +2165 -0
- a2a_server/email_inbound.py +398 -0
- a2a_server/email_notifications.py +486 -0
- a2a_server/enhanced_agents.py +919 -0
- a2a_server/enhanced_server.py +160 -0
- a2a_server/hosted_worker.py +1049 -0
- a2a_server/integrated_agents_server.py +347 -0
- a2a_server/keycloak_auth.py +750 -0
- a2a_server/livekit_bridge.py +439 -0
- a2a_server/marketing_tools.py +1364 -0
- a2a_server/mcp_client.py +196 -0
- a2a_server/mcp_http_server.py +2256 -0
- a2a_server/mcp_server.py +191 -0
- a2a_server/message_broker.py +725 -0
- a2a_server/mock_mcp.py +273 -0
- a2a_server/models.py +494 -0
- a2a_server/monitor_api.py +5904 -0
- a2a_server/opencode_bridge.py +1594 -0
- a2a_server/redis_task_manager.py +518 -0
- a2a_server/server.py +726 -0
- a2a_server/task_manager.py +668 -0
- a2a_server/task_queue.py +742 -0
- a2a_server/tenant_api.py +333 -0
- a2a_server/tenant_middleware.py +219 -0
- a2a_server/tenant_service.py +760 -0
- a2a_server/user_auth.py +721 -0
- a2a_server/vault_client.py +576 -0
- a2a_server/worker_sse.py +873 -0
- agent_worker/__init__.py +8 -0
- agent_worker/worker.py +4877 -0
- codetether/__init__.py +10 -0
- codetether/__main__.py +4 -0
- codetether/cli.py +112 -0
- codetether/worker_cli.py +57 -0
- codetether-1.2.2.dist-info/METADATA +570 -0
- codetether-1.2.2.dist-info/RECORD +66 -0
- codetether-1.2.2.dist-info/WHEEL +5 -0
- codetether-1.2.2.dist-info/entry_points.txt +4 -0
- codetether-1.2.2.dist-info/licenses/LICENSE +202 -0
- codetether-1.2.2.dist-info/top_level.txt +5 -0
- codetether_voice_agent/__init__.py +6 -0
- codetether_voice_agent/agent.py +445 -0
- codetether_voice_agent/codetether_mcp.py +345 -0
- codetether_voice_agent/config.py +16 -0
- codetether_voice_agent/functiongemma_caller.py +380 -0
- codetether_voice_agent/session_playback.py +247 -0
- codetether_voice_agent/tools/__init__.py +21 -0
- codetether_voice_agent/tools/definitions.py +135 -0
- codetether_voice_agent/tools/handlers.py +380 -0
- run_server.py +314 -0
- ui/monitor-tailwind.html +1790 -0
- ui/monitor.html +1775 -0
- ui/monitor.js +2662 -0
a2a_server/mock_mcp.py
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mock MCP implementation for demonstration purposes.
|
|
3
|
+
This simulates MCP tool integration without requiring complex MCP infrastructure.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import asyncio
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
import math
|
|
10
|
+
from typing import Any, Dict, List, Optional, Union
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MockMCPTool:
|
|
17
|
+
"""Base class for mock MCP tools."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, name: str, description: str):
|
|
20
|
+
self.name = name
|
|
21
|
+
self.description = description
|
|
22
|
+
|
|
23
|
+
async def call(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
24
|
+
"""Call the tool with given arguments."""
|
|
25
|
+
raise NotImplementedError
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class CalculatorTool(MockMCPTool):
|
|
29
|
+
"""Mock calculator tool."""
|
|
30
|
+
|
|
31
|
+
def __init__(self):
|
|
32
|
+
super().__init__("calculator", "Performs mathematical calculations")
|
|
33
|
+
|
|
34
|
+
async def call(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
35
|
+
"""Perform calculation."""
|
|
36
|
+
try:
|
|
37
|
+
operation = arguments.get("operation")
|
|
38
|
+
a = float(arguments.get("a", 0))
|
|
39
|
+
b = arguments.get("b")
|
|
40
|
+
|
|
41
|
+
if b is not None:
|
|
42
|
+
b = float(b)
|
|
43
|
+
|
|
44
|
+
if operation == "add":
|
|
45
|
+
if b is None:
|
|
46
|
+
return {"error": "Addition requires two numbers"}
|
|
47
|
+
result = a + b
|
|
48
|
+
elif operation == "subtract":
|
|
49
|
+
if b is None:
|
|
50
|
+
return {"error": "Subtraction requires two numbers"}
|
|
51
|
+
result = a - b
|
|
52
|
+
elif operation == "multiply":
|
|
53
|
+
if b is None:
|
|
54
|
+
return {"error": "Multiplication requires two numbers"}
|
|
55
|
+
result = a * b
|
|
56
|
+
elif operation == "divide":
|
|
57
|
+
if b is None:
|
|
58
|
+
return {"error": "Division requires two numbers"}
|
|
59
|
+
if b == 0:
|
|
60
|
+
return {"error": "Cannot divide by zero"}
|
|
61
|
+
result = a / b
|
|
62
|
+
elif operation == "square":
|
|
63
|
+
result = a ** 2
|
|
64
|
+
elif operation == "sqrt":
|
|
65
|
+
if a < 0:
|
|
66
|
+
return {"error": "Cannot take square root of negative number"}
|
|
67
|
+
result = math.sqrt(a)
|
|
68
|
+
else:
|
|
69
|
+
return {"error": f"Unknown operation: {operation}"}
|
|
70
|
+
|
|
71
|
+
return {"result": result, "operation": operation, "inputs": {"a": a, "b": b}}
|
|
72
|
+
|
|
73
|
+
except Exception as e:
|
|
74
|
+
return {"error": f"Calculation error: {str(e)}"}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class WeatherTool(MockMCPTool):
|
|
78
|
+
"""Mock weather tool."""
|
|
79
|
+
|
|
80
|
+
def __init__(self):
|
|
81
|
+
super().__init__("weather_info", "Provides weather information")
|
|
82
|
+
|
|
83
|
+
async def call(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
84
|
+
"""Get weather information."""
|
|
85
|
+
location = arguments.get("location", "unknown location")
|
|
86
|
+
|
|
87
|
+
# Mock weather data
|
|
88
|
+
return {
|
|
89
|
+
"location": location,
|
|
90
|
+
"temperature": "22°C",
|
|
91
|
+
"condition": "Partly cloudy",
|
|
92
|
+
"humidity": "65%",
|
|
93
|
+
"wind": "10 km/h SW",
|
|
94
|
+
"timestamp": datetime.now().isoformat()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class TextAnalyzerTool(MockMCPTool):
|
|
99
|
+
"""Mock text analyzer tool."""
|
|
100
|
+
|
|
101
|
+
def __init__(self):
|
|
102
|
+
super().__init__("text_analyzer", "Analyzes text and provides statistics")
|
|
103
|
+
|
|
104
|
+
async def call(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
105
|
+
"""Analyze text."""
|
|
106
|
+
text = arguments.get("text", "")
|
|
107
|
+
|
|
108
|
+
words = text.split()
|
|
109
|
+
sentences = text.split('.')
|
|
110
|
+
chars = len(text)
|
|
111
|
+
chars_no_spaces = len(text.replace(' ', ''))
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
"text": text,
|
|
115
|
+
"word_count": len(words),
|
|
116
|
+
"sentence_count": len([s for s in sentences if s.strip()]),
|
|
117
|
+
"character_count": chars,
|
|
118
|
+
"character_count_no_spaces": chars_no_spaces,
|
|
119
|
+
"average_word_length": sum(len(word) for word in words) / len(words) if words else 0,
|
|
120
|
+
"timestamp": datetime.now().isoformat()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class MemoryTool(MockMCPTool):
|
|
125
|
+
"""Mock memory/storage tool."""
|
|
126
|
+
|
|
127
|
+
def __init__(self):
|
|
128
|
+
super().__init__("memory_store", "Simple key-value memory store")
|
|
129
|
+
self._memory = {}
|
|
130
|
+
|
|
131
|
+
async def call(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
132
|
+
"""Perform memory operation."""
|
|
133
|
+
try:
|
|
134
|
+
action = arguments.get("action")
|
|
135
|
+
key = arguments.get("key")
|
|
136
|
+
value = arguments.get("value")
|
|
137
|
+
|
|
138
|
+
if action == "store":
|
|
139
|
+
if key is None or value is None:
|
|
140
|
+
return {"error": "Store action requires both key and value"}
|
|
141
|
+
self._memory[key] = value
|
|
142
|
+
return {"action": "store", "key": key, "value": value, "success": True}
|
|
143
|
+
|
|
144
|
+
elif action == "retrieve":
|
|
145
|
+
if key is None:
|
|
146
|
+
return {"error": "Retrieve action requires a key"}
|
|
147
|
+
value = self._memory.get(key)
|
|
148
|
+
if value is None:
|
|
149
|
+
return {"action": "retrieve", "key": key, "found": False}
|
|
150
|
+
return {"action": "retrieve", "key": key, "value": value, "found": True}
|
|
151
|
+
|
|
152
|
+
elif action == "list":
|
|
153
|
+
keys = list(self._memory.keys())
|
|
154
|
+
return {"action": "list", "keys": keys, "count": len(keys)}
|
|
155
|
+
|
|
156
|
+
elif action == "delete":
|
|
157
|
+
if key is None:
|
|
158
|
+
return {"error": "Delete action requires a key"}
|
|
159
|
+
if key in self._memory:
|
|
160
|
+
del self._memory[key]
|
|
161
|
+
return {"action": "delete", "key": key, "success": True}
|
|
162
|
+
return {"action": "delete", "key": key, "success": False, "error": "Key not found"}
|
|
163
|
+
|
|
164
|
+
else:
|
|
165
|
+
return {"error": f"Unknown action: {action}"}
|
|
166
|
+
|
|
167
|
+
except Exception as e:
|
|
168
|
+
return {"error": f"Memory operation error: {str(e)}"}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class MockMCPClient:
|
|
172
|
+
"""Mock MCP client that simulates MCP tool interactions."""
|
|
173
|
+
|
|
174
|
+
def __init__(self):
|
|
175
|
+
self.tools = {
|
|
176
|
+
"calculator": CalculatorTool(),
|
|
177
|
+
"weather_info": WeatherTool(),
|
|
178
|
+
"text_analyzer": TextAnalyzerTool(),
|
|
179
|
+
"memory_store": MemoryTool()
|
|
180
|
+
}
|
|
181
|
+
self.connected = False
|
|
182
|
+
|
|
183
|
+
async def connect(self) -> bool:
|
|
184
|
+
"""Simulate connecting to MCP server."""
|
|
185
|
+
await asyncio.sleep(0.1) # Simulate connection delay
|
|
186
|
+
self.connected = True
|
|
187
|
+
logger.info(f"Mock MCP client connected with {len(self.tools)} tools")
|
|
188
|
+
return True
|
|
189
|
+
|
|
190
|
+
async def disconnect(self):
|
|
191
|
+
"""Simulate disconnecting from MCP server."""
|
|
192
|
+
self.connected = False
|
|
193
|
+
logger.info("Mock MCP client disconnected")
|
|
194
|
+
|
|
195
|
+
async def get_available_tools(self) -> List[Dict[str, Any]]:
|
|
196
|
+
"""Get list of available tools."""
|
|
197
|
+
return [
|
|
198
|
+
{"name": name, "description": tool.description}
|
|
199
|
+
for name, tool in self.tools.items()
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
async def call_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
|
|
203
|
+
"""Call a tool with the given arguments."""
|
|
204
|
+
if not self.connected:
|
|
205
|
+
return {"error": "Not connected to MCP server"}
|
|
206
|
+
|
|
207
|
+
tool = self.tools.get(tool_name)
|
|
208
|
+
if not tool:
|
|
209
|
+
return {"error": f"Tool '{tool_name}' not found"}
|
|
210
|
+
|
|
211
|
+
try:
|
|
212
|
+
result = await tool.call(arguments)
|
|
213
|
+
return {
|
|
214
|
+
"success": True,
|
|
215
|
+
"tool": tool_name,
|
|
216
|
+
"arguments": arguments,
|
|
217
|
+
"result": result
|
|
218
|
+
}
|
|
219
|
+
except Exception as e:
|
|
220
|
+
logger.error(f"Error calling tool {tool_name}: {e}")
|
|
221
|
+
return {
|
|
222
|
+
"error": f"Tool call failed: {str(e)}",
|
|
223
|
+
"tool": tool_name,
|
|
224
|
+
"arguments": arguments
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async def calculator(self, operation: str, a: float, b: Optional[float] = None) -> Dict[str, Any]:
|
|
228
|
+
"""Convenience method for calculator tool."""
|
|
229
|
+
args = {"operation": operation, "a": a}
|
|
230
|
+
if b is not None:
|
|
231
|
+
args["b"] = b
|
|
232
|
+
return await self.call_tool("calculator", args)
|
|
233
|
+
|
|
234
|
+
async def get_weather(self, location: str) -> Dict[str, Any]:
|
|
235
|
+
"""Convenience method for weather tool."""
|
|
236
|
+
return await self.call_tool("weather_info", {"location": location})
|
|
237
|
+
|
|
238
|
+
async def analyze_text(self, text: str) -> Dict[str, Any]:
|
|
239
|
+
"""Convenience method for text analyzer tool."""
|
|
240
|
+
return await self.call_tool("text_analyzer", {"text": text})
|
|
241
|
+
|
|
242
|
+
async def memory_operation(self, action: str, key: Optional[str] = None, value: Optional[str] = None) -> Dict[str, Any]:
|
|
243
|
+
"""Convenience method for memory store tool."""
|
|
244
|
+
args = {"action": action}
|
|
245
|
+
if key is not None:
|
|
246
|
+
args["key"] = key
|
|
247
|
+
if value is not None:
|
|
248
|
+
args["value"] = value
|
|
249
|
+
return await self.call_tool("memory_store", args)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
# Global mock MCP client instance
|
|
253
|
+
_mock_mcp_client: Optional[MockMCPClient] = None
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
async def get_mock_mcp_client() -> MockMCPClient:
|
|
257
|
+
"""Get or create the global mock MCP client instance."""
|
|
258
|
+
global _mock_mcp_client
|
|
259
|
+
|
|
260
|
+
if _mock_mcp_client is None:
|
|
261
|
+
_mock_mcp_client = MockMCPClient()
|
|
262
|
+
await _mock_mcp_client.connect()
|
|
263
|
+
|
|
264
|
+
return _mock_mcp_client
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
async def cleanup_mock_mcp_client():
|
|
268
|
+
"""Clean up the global mock MCP client instance."""
|
|
269
|
+
global _mock_mcp_client
|
|
270
|
+
|
|
271
|
+
if _mock_mcp_client:
|
|
272
|
+
await _mock_mcp_client.disconnect()
|
|
273
|
+
_mock_mcp_client = None
|