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/__init__.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent2Agent (A2A) Protocol Server Implementation
|
|
3
|
+
|
|
4
|
+
This package provides a complete implementation of the A2A protocol specification,
|
|
5
|
+
enabling inter-agent communication and collaboration.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
9
|
+
__author__ = "A2A Project Contributors"
|
|
10
|
+
__license__ = "Apache 2.0"
|
|
11
|
+
|
|
12
|
+
from .server import A2AServer
|
|
13
|
+
from .agent_card import AgentCard
|
|
14
|
+
from .message_broker import MessageBroker
|
|
15
|
+
from .task_manager import TaskManager
|
|
16
|
+
|
|
17
|
+
# Lazy import for opencode bridge to avoid dependency issues
|
|
18
|
+
def get_opencode_bridge():
|
|
19
|
+
"""Get the OpenCode bridge for triggering AI coding agents."""
|
|
20
|
+
from .opencode_bridge import get_bridge
|
|
21
|
+
return get_bridge()
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"A2AServer",
|
|
25
|
+
"AgentCard",
|
|
26
|
+
"MessageBroker",
|
|
27
|
+
"TaskManager",
|
|
28
|
+
"get_opencode_bridge",
|
|
29
|
+
]
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A2A Protocol Compliant Agent Card
|
|
3
|
+
|
|
4
|
+
Implements the official A2A specification AgentCard served at /.well-known/agent-card.json
|
|
5
|
+
for agent discovery and capability advertisement per the A2A protocol v0.3.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
from pydantic import BaseModel, Field
|
|
11
|
+
from fastapi import APIRouter
|
|
12
|
+
from fastapi.responses import JSONResponse
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# A2A Protocol v0.3 Compliant Models
|
|
16
|
+
# Based on specification/json/a2a.json
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AgentProvider(BaseModel):
|
|
20
|
+
"""Represents the service provider of an agent."""
|
|
21
|
+
|
|
22
|
+
organization: str = Field(
|
|
23
|
+
..., description="The name of the agent provider's organization"
|
|
24
|
+
)
|
|
25
|
+
url: str = Field(
|
|
26
|
+
...,
|
|
27
|
+
description="A URL for the agent provider's website or documentation",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AgentExtension(BaseModel):
|
|
32
|
+
"""A declaration of a protocol extension supported by an Agent."""
|
|
33
|
+
|
|
34
|
+
uri: str = Field(
|
|
35
|
+
..., description='The unique URI identifying the extension'
|
|
36
|
+
)
|
|
37
|
+
description: Optional[str] = Field(
|
|
38
|
+
default=None,
|
|
39
|
+
description='A human-readable description of the extension',
|
|
40
|
+
)
|
|
41
|
+
required: Optional[bool] = Field(
|
|
42
|
+
default=False,
|
|
43
|
+
description='If true, the client must comply with the extension',
|
|
44
|
+
)
|
|
45
|
+
params: Optional[Dict[str, Any]] = Field(
|
|
46
|
+
default=None, description='Extension-specific configuration parameters'
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class AgentCapabilities(BaseModel):
|
|
51
|
+
"""Defines optional capabilities supported by an agent."""
|
|
52
|
+
|
|
53
|
+
streaming: Optional[bool] = Field(
|
|
54
|
+
None,
|
|
55
|
+
description='Indicates if the agent supports SSE for streaming responses',
|
|
56
|
+
)
|
|
57
|
+
pushNotifications: Optional[bool] = Field(
|
|
58
|
+
None, description='Indicates if the agent supports push notifications'
|
|
59
|
+
)
|
|
60
|
+
stateTransitionHistory: Optional[bool] = Field(
|
|
61
|
+
None,
|
|
62
|
+
description='Indicates if the agent provides state transition history',
|
|
63
|
+
)
|
|
64
|
+
extensions: Optional[List[AgentExtension]] = Field(
|
|
65
|
+
None, description='Protocol extensions supported by the agent'
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class AgentSkill(BaseModel):
|
|
70
|
+
"""Represents a distinct capability or function that an agent can perform."""
|
|
71
|
+
|
|
72
|
+
id: str = Field(..., description='A unique identifier for the skill')
|
|
73
|
+
name: str = Field(..., description='A human-readable name for the skill')
|
|
74
|
+
description: str = Field(
|
|
75
|
+
..., description='A detailed description of the skill'
|
|
76
|
+
)
|
|
77
|
+
tags: List[str] = Field(
|
|
78
|
+
default_factory=list, description='Keywords describing the skill'
|
|
79
|
+
)
|
|
80
|
+
examples: Optional[List[str]] = Field(
|
|
81
|
+
default=None, description='Example prompts for the skill'
|
|
82
|
+
)
|
|
83
|
+
inputModes: Optional[List[str]] = Field(
|
|
84
|
+
default=None,
|
|
85
|
+
description='Supported input MIME types, overriding defaults',
|
|
86
|
+
)
|
|
87
|
+
outputModes: Optional[List[str]] = Field(
|
|
88
|
+
default=None,
|
|
89
|
+
description='Supported output MIME types, overriding defaults',
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class AgentInterface(BaseModel):
|
|
94
|
+
"""Declares a URL and transport protocol combination for interacting with the agent."""
|
|
95
|
+
|
|
96
|
+
url: str = Field(
|
|
97
|
+
..., description='The URL where this interface is available'
|
|
98
|
+
)
|
|
99
|
+
transport: str = Field(
|
|
100
|
+
..., description='The transport protocol (JSONRPC, HTTP+JSON, GRPC)'
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class HTTPAuthSecurityScheme(BaseModel):
|
|
105
|
+
"""Defines a security scheme using HTTP authentication."""
|
|
106
|
+
|
|
107
|
+
type: str = Field(default='http', description='Security scheme type')
|
|
108
|
+
scheme: str = Field(..., description='HTTP auth scheme (e.g., Bearer)')
|
|
109
|
+
bearerFormat: Optional[str] = Field(
|
|
110
|
+
default=None, description='Format hint for bearer token (e.g., JWT)'
|
|
111
|
+
)
|
|
112
|
+
description: Optional[str] = Field(
|
|
113
|
+
default=None, description='Description of the security scheme'
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class A2AAgentCard(BaseModel):
|
|
118
|
+
"""
|
|
119
|
+
A2A Protocol v0.3 compliant AgentCard.
|
|
120
|
+
|
|
121
|
+
The AgentCard is a self-describing manifest for an agent that provides
|
|
122
|
+
essential metadata including identity, capabilities, skills, supported
|
|
123
|
+
communication methods, and security requirements.
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
name: str = Field(..., description='A human-readable name for the agent')
|
|
127
|
+
description: str = Field(
|
|
128
|
+
..., description="A description of the agent's purpose and capabilities"
|
|
129
|
+
)
|
|
130
|
+
url: str = Field(
|
|
131
|
+
...,
|
|
132
|
+
description='The preferred endpoint URL for interacting with the agent',
|
|
133
|
+
)
|
|
134
|
+
version: str = Field(..., description="The agent's version number")
|
|
135
|
+
protocolVersion: str = Field(
|
|
136
|
+
'0.3', description='The A2A protocol version supported'
|
|
137
|
+
)
|
|
138
|
+
preferredTransport: str = Field(
|
|
139
|
+
'JSONRPC',
|
|
140
|
+
description='The transport protocol for the preferred endpoint',
|
|
141
|
+
)
|
|
142
|
+
additionalInterfaces: Optional[List[AgentInterface]] = Field(
|
|
143
|
+
None, description='Additional supported interfaces'
|
|
144
|
+
)
|
|
145
|
+
capabilities: AgentCapabilities = Field(
|
|
146
|
+
..., description='Capabilities supported by the agent'
|
|
147
|
+
)
|
|
148
|
+
skills: List[AgentSkill] = Field(
|
|
149
|
+
default_factory=list, description='Skills the agent can perform'
|
|
150
|
+
)
|
|
151
|
+
defaultInputModes: List[str] = Field(
|
|
152
|
+
default_factory=list, description='Default supported input MIME types'
|
|
153
|
+
)
|
|
154
|
+
defaultOutputModes: List[str] = Field(
|
|
155
|
+
default_factory=list, description='Default supported output MIME types'
|
|
156
|
+
)
|
|
157
|
+
provider: Optional[AgentProvider] = Field(
|
|
158
|
+
None, description="Information about the agent's provider"
|
|
159
|
+
)
|
|
160
|
+
securitySchemes: Optional[Dict[str, HTTPAuthSecurityScheme]] = Field(
|
|
161
|
+
None, description='Security schemes available for authorization'
|
|
162
|
+
)
|
|
163
|
+
security: Optional[List[Dict[str, List[str]]]] = Field(
|
|
164
|
+
None, description='Security requirements for agent interactions'
|
|
165
|
+
)
|
|
166
|
+
documentationUrl: Optional[str] = Field(
|
|
167
|
+
default=None, description="URL to the agent's documentation"
|
|
168
|
+
)
|
|
169
|
+
iconUrl: Optional[str] = Field(
|
|
170
|
+
default=None, description='URL to an icon for the agent'
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def get_package_version() -> str:
|
|
175
|
+
"""Get the package version from setup.py or fallback."""
|
|
176
|
+
try:
|
|
177
|
+
# Try to import from the installed package
|
|
178
|
+
import importlib.metadata
|
|
179
|
+
|
|
180
|
+
return importlib.metadata.version('codetether')
|
|
181
|
+
except Exception:
|
|
182
|
+
# Fallback to hardcoded version matching setup.py
|
|
183
|
+
return '1.1.0'
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def create_a2a_agent_card(
|
|
187
|
+
base_url: Optional[str] = None,
|
|
188
|
+
) -> A2AAgentCard:
|
|
189
|
+
"""
|
|
190
|
+
Create an A2A protocol v0.3 compliant AgentCard for CodeTether.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
base_url: The base URL where the agent is hosted. If not provided,
|
|
194
|
+
uses A2A_BASE_URL env var or defaults to http://localhost:9000
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
A2AAgentCard: The compliant agent card
|
|
198
|
+
"""
|
|
199
|
+
# Determine base URL
|
|
200
|
+
if base_url is None:
|
|
201
|
+
base_url = os.environ.get('A2A_BASE_URL', 'http://localhost:9000')
|
|
202
|
+
|
|
203
|
+
# Remove trailing slash if present
|
|
204
|
+
base_url = base_url.rstrip('/')
|
|
205
|
+
|
|
206
|
+
return A2AAgentCard(
|
|
207
|
+
name='CodeTether',
|
|
208
|
+
description='Agent-to-Agent coordination and task execution platform. '
|
|
209
|
+
'CodeTether enables multi-agent orchestration, task queue management, '
|
|
210
|
+
'and seamless communication between AI agents using the A2A protocol.',
|
|
211
|
+
url=base_url,
|
|
212
|
+
version=get_package_version(),
|
|
213
|
+
protocolVersion='0.3',
|
|
214
|
+
preferredTransport='JSONRPC',
|
|
215
|
+
additionalInterfaces=[
|
|
216
|
+
AgentInterface(url=base_url, transport='JSONRPC'),
|
|
217
|
+
AgentInterface(url=f'{base_url}/v1/a2a', transport='JSONRPC'),
|
|
218
|
+
AgentInterface(url=f'{base_url}/api', transport='HTTP+JSON'),
|
|
219
|
+
],
|
|
220
|
+
capabilities=AgentCapabilities(
|
|
221
|
+
streaming=True,
|
|
222
|
+
pushNotifications=True,
|
|
223
|
+
stateTransitionHistory=True,
|
|
224
|
+
extensions=[
|
|
225
|
+
AgentExtension(
|
|
226
|
+
uri='https://codetether.io/extensions/mcp',
|
|
227
|
+
description='Model Context Protocol integration for tool synchronization',
|
|
228
|
+
required=False,
|
|
229
|
+
),
|
|
230
|
+
AgentExtension(
|
|
231
|
+
uri='https://codetether.io/extensions/worker-sse',
|
|
232
|
+
description='Server-Sent Events for worker task distribution',
|
|
233
|
+
required=False,
|
|
234
|
+
),
|
|
235
|
+
],
|
|
236
|
+
),
|
|
237
|
+
skills=[
|
|
238
|
+
AgentSkill(
|
|
239
|
+
id='task-management',
|
|
240
|
+
name='Task Management',
|
|
241
|
+
description='Create, query, update, and cancel tasks in the distributed task queue. '
|
|
242
|
+
'Supports task prioritization, worker assignment, and status tracking.',
|
|
243
|
+
tags=['tasks', 'queue', 'orchestration', 'workflow'],
|
|
244
|
+
examples=[
|
|
245
|
+
'Create a new task for code review',
|
|
246
|
+
'Get the status of task abc-123',
|
|
247
|
+
'Cancel all pending tasks',
|
|
248
|
+
'List tasks assigned to worker-1',
|
|
249
|
+
],
|
|
250
|
+
),
|
|
251
|
+
AgentSkill(
|
|
252
|
+
id='agent-messaging',
|
|
253
|
+
name='Agent Messaging',
|
|
254
|
+
description='Send and receive messages between agents. Supports synchronous '
|
|
255
|
+
'and asynchronous messaging with conversation threading.',
|
|
256
|
+
tags=['messaging', 'communication', 'a2a', 'agents'],
|
|
257
|
+
examples=[
|
|
258
|
+
'Send a message to the code-review agent',
|
|
259
|
+
'Get messages from conversation xyz',
|
|
260
|
+
'Broadcast a notification to all agents',
|
|
261
|
+
],
|
|
262
|
+
),
|
|
263
|
+
AgentSkill(
|
|
264
|
+
id='agent-discovery',
|
|
265
|
+
name='Agent Discovery',
|
|
266
|
+
description='Discover and register agents in the network. Query agent '
|
|
267
|
+
'capabilities and maintain an up-to-date registry of available agents.',
|
|
268
|
+
tags=['discovery', 'registry', 'agents', 'network'],
|
|
269
|
+
examples=[
|
|
270
|
+
'List all available agents',
|
|
271
|
+
"Get details for agent 'code-assistant'",
|
|
272
|
+
'Register a new agent with the network',
|
|
273
|
+
],
|
|
274
|
+
),
|
|
275
|
+
AgentSkill(
|
|
276
|
+
id='worker-coordination',
|
|
277
|
+
name='Worker Coordination',
|
|
278
|
+
description='Coordinate worker agents for task execution. Supports SSE-based '
|
|
279
|
+
'push notifications, task claiming, and progress reporting.',
|
|
280
|
+
tags=['workers', 'coordination', 'sse', 'distributed'],
|
|
281
|
+
examples=[
|
|
282
|
+
'Connect as a worker and wait for tasks',
|
|
283
|
+
'Claim the next available task',
|
|
284
|
+
'Report progress on task abc-123',
|
|
285
|
+
],
|
|
286
|
+
),
|
|
287
|
+
AgentSkill(
|
|
288
|
+
id='conversation-history',
|
|
289
|
+
name='Conversation History',
|
|
290
|
+
description='Retrieve and manage conversation history across agent interactions. '
|
|
291
|
+
'Supports filtering by conversation ID, agent, and time range.',
|
|
292
|
+
tags=['history', 'conversations', 'monitoring', 'audit'],
|
|
293
|
+
examples=[
|
|
294
|
+
'Get the last 50 messages',
|
|
295
|
+
'Get conversation history for session xyz',
|
|
296
|
+
"Search messages containing 'error'",
|
|
297
|
+
],
|
|
298
|
+
),
|
|
299
|
+
],
|
|
300
|
+
defaultInputModes=['text/plain', 'application/json'],
|
|
301
|
+
defaultOutputModes=['text/plain', 'application/json'],
|
|
302
|
+
provider=AgentProvider(
|
|
303
|
+
organization='CodeTether',
|
|
304
|
+
url='https://codetether.io',
|
|
305
|
+
),
|
|
306
|
+
securitySchemes={
|
|
307
|
+
'bearer': HTTPAuthSecurityScheme(
|
|
308
|
+
type='http',
|
|
309
|
+
scheme='Bearer',
|
|
310
|
+
bearerFormat='JWT',
|
|
311
|
+
description='JWT Bearer token authentication',
|
|
312
|
+
)
|
|
313
|
+
},
|
|
314
|
+
security=[{'bearer': []}],
|
|
315
|
+
documentationUrl='https://codetether.io/docs',
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
# FastAPI Router for the /.well-known/agent-card.json endpoint
|
|
320
|
+
a2a_agent_card_router = APIRouter(tags=['A2A Discovery'])
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
@a2a_agent_card_router.get(
|
|
324
|
+
'/.well-known/agent-card.json',
|
|
325
|
+
response_class=JSONResponse,
|
|
326
|
+
summary='A2A Agent Card',
|
|
327
|
+
description='Returns the A2A protocol v0.3 compliant agent card for discovery',
|
|
328
|
+
responses={
|
|
329
|
+
200: {
|
|
330
|
+
'description': 'A2A AgentCard for agent discovery',
|
|
331
|
+
'content': {
|
|
332
|
+
'application/json': {
|
|
333
|
+
'example': {
|
|
334
|
+
'name': 'CodeTether',
|
|
335
|
+
'description': 'Agent-to-Agent coordination platform',
|
|
336
|
+
'url': 'https://api.codetether.io',
|
|
337
|
+
'version': '1.1.0',
|
|
338
|
+
'protocolVersion': '0.3',
|
|
339
|
+
'capabilities': {
|
|
340
|
+
'streaming': True,
|
|
341
|
+
'pushNotifications': True,
|
|
342
|
+
'stateTransitionHistory': True,
|
|
343
|
+
},
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
)
|
|
350
|
+
async def get_a2a_agent_card() -> JSONResponse:
|
|
351
|
+
"""
|
|
352
|
+
Serve the A2A protocol compliant agent card.
|
|
353
|
+
|
|
354
|
+
This endpoint follows the A2A specification for agent discovery,
|
|
355
|
+
allowing other agents and clients to discover this agent's
|
|
356
|
+
capabilities, skills, and communication protocols.
|
|
357
|
+
"""
|
|
358
|
+
agent_card = create_a2a_agent_card()
|
|
359
|
+
return JSONResponse(
|
|
360
|
+
content=agent_card.model_dump(exclude_none=True),
|
|
361
|
+
headers={
|
|
362
|
+
'Content-Type': 'application/json',
|
|
363
|
+
'Cache-Control': 'public, max-age=3600',
|
|
364
|
+
},
|
|
365
|
+
)
|