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.
Files changed (66) hide show
  1. a2a_server/__init__.py +29 -0
  2. a2a_server/a2a_agent_card.py +365 -0
  3. a2a_server/a2a_errors.py +1133 -0
  4. a2a_server/a2a_executor.py +926 -0
  5. a2a_server/a2a_router.py +1033 -0
  6. a2a_server/a2a_types.py +344 -0
  7. a2a_server/agent_card.py +408 -0
  8. a2a_server/agents_server.py +271 -0
  9. a2a_server/auth_api.py +349 -0
  10. a2a_server/billing_api.py +638 -0
  11. a2a_server/billing_service.py +712 -0
  12. a2a_server/billing_webhooks.py +501 -0
  13. a2a_server/config.py +96 -0
  14. a2a_server/database.py +2165 -0
  15. a2a_server/email_inbound.py +398 -0
  16. a2a_server/email_notifications.py +486 -0
  17. a2a_server/enhanced_agents.py +919 -0
  18. a2a_server/enhanced_server.py +160 -0
  19. a2a_server/hosted_worker.py +1049 -0
  20. a2a_server/integrated_agents_server.py +347 -0
  21. a2a_server/keycloak_auth.py +750 -0
  22. a2a_server/livekit_bridge.py +439 -0
  23. a2a_server/marketing_tools.py +1364 -0
  24. a2a_server/mcp_client.py +196 -0
  25. a2a_server/mcp_http_server.py +2256 -0
  26. a2a_server/mcp_server.py +191 -0
  27. a2a_server/message_broker.py +725 -0
  28. a2a_server/mock_mcp.py +273 -0
  29. a2a_server/models.py +494 -0
  30. a2a_server/monitor_api.py +5904 -0
  31. a2a_server/opencode_bridge.py +1594 -0
  32. a2a_server/redis_task_manager.py +518 -0
  33. a2a_server/server.py +726 -0
  34. a2a_server/task_manager.py +668 -0
  35. a2a_server/task_queue.py +742 -0
  36. a2a_server/tenant_api.py +333 -0
  37. a2a_server/tenant_middleware.py +219 -0
  38. a2a_server/tenant_service.py +760 -0
  39. a2a_server/user_auth.py +721 -0
  40. a2a_server/vault_client.py +576 -0
  41. a2a_server/worker_sse.py +873 -0
  42. agent_worker/__init__.py +8 -0
  43. agent_worker/worker.py +4877 -0
  44. codetether/__init__.py +10 -0
  45. codetether/__main__.py +4 -0
  46. codetether/cli.py +112 -0
  47. codetether/worker_cli.py +57 -0
  48. codetether-1.2.2.dist-info/METADATA +570 -0
  49. codetether-1.2.2.dist-info/RECORD +66 -0
  50. codetether-1.2.2.dist-info/WHEEL +5 -0
  51. codetether-1.2.2.dist-info/entry_points.txt +4 -0
  52. codetether-1.2.2.dist-info/licenses/LICENSE +202 -0
  53. codetether-1.2.2.dist-info/top_level.txt +5 -0
  54. codetether_voice_agent/__init__.py +6 -0
  55. codetether_voice_agent/agent.py +445 -0
  56. codetether_voice_agent/codetether_mcp.py +345 -0
  57. codetether_voice_agent/config.py +16 -0
  58. codetether_voice_agent/functiongemma_caller.py +380 -0
  59. codetether_voice_agent/session_playback.py +247 -0
  60. codetether_voice_agent/tools/__init__.py +21 -0
  61. codetether_voice_agent/tools/definitions.py +135 -0
  62. codetether_voice_agent/tools/handlers.py +380 -0
  63. run_server.py +314 -0
  64. ui/monitor-tailwind.html +1790 -0
  65. ui/monitor.html +1775 -0
  66. ui/monitor.js +2662 -0
@@ -0,0 +1,344 @@
1
+ """
2
+ A2A Protocol State Types and Mappings
3
+
4
+ This module provides alignment between our internal task states and the
5
+ official A2A protocol task states as defined in the specification.
6
+
7
+ A2A Spec States:
8
+ - submitted: Task created and acknowledged
9
+ - working: Actively processing
10
+ - completed: Finished successfully (TERMINAL)
11
+ - failed: Done but failed (TERMINAL)
12
+ - cancelled: Cancelled before completion (TERMINAL)
13
+ - input-required: Awaiting additional input
14
+ - rejected: Agent declined the task (TERMINAL)
15
+ - auth-required: Needs out-of-band authentication
16
+
17
+ Our Internal States (TaskStatus):
18
+ - SUBMITTED: Initial state after creation
19
+ - PENDING: Legacy alias for submitted (deprecated)
20
+ - WORKING: Actively processing
21
+ - INPUT_REQUIRED: Awaiting user input
22
+ - COMPLETED: Finished successfully (TERMINAL)
23
+ - FAILED: Failed (TERMINAL)
24
+ - CANCELLED: Cancelled (TERMINAL)
25
+ - REJECTED: Agent declined (TERMINAL)
26
+ - AUTH_REQUIRED: Needs authentication
27
+ """
28
+
29
+ from enum import Enum
30
+ from typing import Set
31
+
32
+
33
+ class A2ATaskState(str, Enum):
34
+ """
35
+ Official A2A protocol task states.
36
+
37
+ These are the states defined in the A2A specification that should be
38
+ used when communicating with external A2A clients and servers.
39
+ """
40
+
41
+ SUBMITTED = 'submitted'
42
+ WORKING = 'working'
43
+ COMPLETED = 'completed'
44
+ FAILED = 'failed'
45
+ CANCELLED = 'cancelled'
46
+ INPUT_REQUIRED = 'input-required'
47
+ REJECTED = 'rejected'
48
+ AUTH_REQUIRED = 'auth-required'
49
+
50
+
51
+ # Terminal states - once a task reaches these, it cannot transition further
52
+ A2A_TERMINAL_STATES: Set[A2ATaskState] = {
53
+ A2ATaskState.COMPLETED,
54
+ A2ATaskState.FAILED,
55
+ A2ATaskState.CANCELLED,
56
+ A2ATaskState.REJECTED,
57
+ }
58
+
59
+ # Non-terminal states - task can still transition
60
+ A2A_ACTIVE_STATES: Set[A2ATaskState] = {
61
+ A2ATaskState.SUBMITTED,
62
+ A2ATaskState.WORKING,
63
+ A2ATaskState.INPUT_REQUIRED,
64
+ A2ATaskState.AUTH_REQUIRED,
65
+ }
66
+
67
+
68
+ def is_a2a_terminal_state(state: A2ATaskState) -> bool:
69
+ """
70
+ Check if an A2A state is terminal.
71
+
72
+ Terminal states indicate the task has reached a final state and
73
+ cannot transition to any other state.
74
+
75
+ Args:
76
+ state: The A2A task state to check
77
+
78
+ Returns:
79
+ True if the state is terminal, False otherwise
80
+ """
81
+ return state in A2A_TERMINAL_STATES
82
+
83
+
84
+ def is_a2a_active_state(state: A2ATaskState) -> bool:
85
+ """
86
+ Check if an A2A state is active (non-terminal).
87
+
88
+ Active states indicate the task is still in progress and can
89
+ transition to other states.
90
+
91
+ Args:
92
+ state: The A2A task state to check
93
+
94
+ Returns:
95
+ True if the state is active, False otherwise
96
+ """
97
+ return state in A2A_ACTIVE_STATES
98
+
99
+
100
+ # Import here to avoid circular imports - we need the actual TaskStatus
101
+ # This will be populated after models.py is updated
102
+ def _get_task_status():
103
+ """Lazy import of TaskStatus to avoid circular imports."""
104
+ from a2a_server.models import TaskStatus
105
+
106
+ return TaskStatus
107
+
108
+
109
+ # Mapping from internal TaskStatus to A2A protocol states
110
+ _INTERNAL_TO_A2A_MAP = {
111
+ 'submitted': A2ATaskState.SUBMITTED,
112
+ 'pending': A2ATaskState.SUBMITTED, # Legacy mapping
113
+ 'working': A2ATaskState.WORKING,
114
+ 'input-required': A2ATaskState.INPUT_REQUIRED,
115
+ 'completed': A2ATaskState.COMPLETED,
116
+ 'failed': A2ATaskState.FAILED,
117
+ 'cancelled': A2ATaskState.CANCELLED,
118
+ 'rejected': A2ATaskState.REJECTED,
119
+ 'auth-required': A2ATaskState.AUTH_REQUIRED,
120
+ }
121
+
122
+ # Mapping from A2A protocol states to internal TaskStatus values
123
+ _A2A_TO_INTERNAL_MAP = {
124
+ A2ATaskState.SUBMITTED: 'submitted',
125
+ A2ATaskState.WORKING: 'working',
126
+ A2ATaskState.INPUT_REQUIRED: 'input-required',
127
+ A2ATaskState.COMPLETED: 'completed',
128
+ A2ATaskState.FAILED: 'failed',
129
+ A2ATaskState.CANCELLED: 'cancelled',
130
+ A2ATaskState.REJECTED: 'rejected',
131
+ A2ATaskState.AUTH_REQUIRED: 'auth-required',
132
+ }
133
+
134
+
135
+ def internal_to_a2a_state(internal_state) -> A2ATaskState:
136
+ """
137
+ Convert an internal TaskStatus to the corresponding A2A protocol state.
138
+
139
+ Args:
140
+ internal_state: TaskStatus enum value or string representation
141
+
142
+ Returns:
143
+ The corresponding A2ATaskState
144
+
145
+ Raises:
146
+ ValueError: If the internal state has no A2A mapping
147
+
148
+ Examples:
149
+ >>> internal_to_a2a_state(TaskStatus.PENDING)
150
+ <A2ATaskState.SUBMITTED: 'submitted'>
151
+
152
+ >>> internal_to_a2a_state(TaskStatus.WORKING)
153
+ <A2ATaskState.WORKING: 'working'>
154
+
155
+ >>> internal_to_a2a_state('completed')
156
+ <A2ATaskState.COMPLETED: 'completed'>
157
+ """
158
+ # Handle both enum and string values
159
+ if hasattr(internal_state, 'value'):
160
+ state_value = internal_state.value
161
+ else:
162
+ state_value = str(internal_state).lower()
163
+
164
+ if state_value not in _INTERNAL_TO_A2A_MAP:
165
+ raise ValueError(
166
+ f"Unknown internal state '{state_value}'. "
167
+ f'Valid states: {list(_INTERNAL_TO_A2A_MAP.keys())}'
168
+ )
169
+
170
+ return _INTERNAL_TO_A2A_MAP[state_value]
171
+
172
+
173
+ def a2a_to_internal_state(a2a_state: A2ATaskState):
174
+ """
175
+ Convert an A2A protocol state to the corresponding internal TaskStatus.
176
+
177
+ Args:
178
+ a2a_state: A2ATaskState enum value or string representation
179
+
180
+ Returns:
181
+ The corresponding TaskStatus enum value
182
+
183
+ Raises:
184
+ ValueError: If the A2A state has no internal mapping
185
+
186
+ Examples:
187
+ >>> a2a_to_internal_state(A2ATaskState.SUBMITTED)
188
+ <TaskStatus.SUBMITTED: 'submitted'>
189
+
190
+ >>> a2a_to_internal_state('working')
191
+ <TaskStatus.WORKING: 'working'>
192
+ """
193
+ TaskStatus = _get_task_status()
194
+
195
+ # Handle both enum and string values
196
+ if isinstance(a2a_state, str):
197
+ try:
198
+ a2a_state = A2ATaskState(a2a_state)
199
+ except ValueError:
200
+ raise ValueError(
201
+ f"Unknown A2A state '{a2a_state}'. "
202
+ f'Valid states: {[s.value for s in A2ATaskState]}'
203
+ )
204
+
205
+ if a2a_state not in _A2A_TO_INTERNAL_MAP:
206
+ raise ValueError(
207
+ f"Unknown A2A state '{a2a_state}'. "
208
+ f'Valid states: {list(_A2A_TO_INTERNAL_MAP.keys())}'
209
+ )
210
+
211
+ internal_value = _A2A_TO_INTERNAL_MAP[a2a_state]
212
+ return TaskStatus(internal_value)
213
+
214
+
215
+ def is_internal_terminal_state(internal_state) -> bool:
216
+ """
217
+ Check if an internal TaskStatus is terminal.
218
+
219
+ Args:
220
+ internal_state: TaskStatus enum value or string representation
221
+
222
+ Returns:
223
+ True if the state is terminal, False otherwise
224
+
225
+ Examples:
226
+ >>> is_internal_terminal_state(TaskStatus.COMPLETED)
227
+ True
228
+
229
+ >>> is_internal_terminal_state(TaskStatus.WORKING)
230
+ False
231
+ """
232
+ try:
233
+ a2a_state = internal_to_a2a_state(internal_state)
234
+ return is_a2a_terminal_state(a2a_state)
235
+ except ValueError:
236
+ return False
237
+
238
+
239
+ def is_internal_active_state(internal_state) -> bool:
240
+ """
241
+ Check if an internal TaskStatus is active (non-terminal).
242
+
243
+ Args:
244
+ internal_state: TaskStatus enum value or string representation
245
+
246
+ Returns:
247
+ True if the state is active, False otherwise
248
+ """
249
+ try:
250
+ a2a_state = internal_to_a2a_state(internal_state)
251
+ return is_a2a_active_state(a2a_state)
252
+ except ValueError:
253
+ return False
254
+
255
+
256
+ # Valid state transitions as defined by A2A protocol
257
+ # Key is the current state, value is set of valid next states
258
+ VALID_STATE_TRANSITIONS = {
259
+ A2ATaskState.SUBMITTED: {
260
+ A2ATaskState.WORKING,
261
+ A2ATaskState.COMPLETED,
262
+ A2ATaskState.FAILED,
263
+ A2ATaskState.CANCELLED,
264
+ A2ATaskState.REJECTED,
265
+ A2ATaskState.INPUT_REQUIRED,
266
+ A2ATaskState.AUTH_REQUIRED,
267
+ },
268
+ A2ATaskState.WORKING: {
269
+ A2ATaskState.COMPLETED,
270
+ A2ATaskState.FAILED,
271
+ A2ATaskState.CANCELLED,
272
+ A2ATaskState.INPUT_REQUIRED,
273
+ A2ATaskState.AUTH_REQUIRED,
274
+ },
275
+ A2ATaskState.INPUT_REQUIRED: {
276
+ A2ATaskState.WORKING,
277
+ A2ATaskState.COMPLETED,
278
+ A2ATaskState.FAILED,
279
+ A2ATaskState.CANCELLED,
280
+ },
281
+ A2ATaskState.AUTH_REQUIRED: {
282
+ A2ATaskState.WORKING,
283
+ A2ATaskState.COMPLETED,
284
+ A2ATaskState.FAILED,
285
+ A2ATaskState.CANCELLED,
286
+ },
287
+ # Terminal states cannot transition
288
+ A2ATaskState.COMPLETED: set(),
289
+ A2ATaskState.FAILED: set(),
290
+ A2ATaskState.CANCELLED: set(),
291
+ A2ATaskState.REJECTED: set(),
292
+ }
293
+
294
+
295
+ def is_valid_transition(
296
+ from_state: A2ATaskState, to_state: A2ATaskState
297
+ ) -> bool:
298
+ """
299
+ Check if a state transition is valid according to A2A protocol.
300
+
301
+ Args:
302
+ from_state: Current state
303
+ to_state: Target state
304
+
305
+ Returns:
306
+ True if the transition is valid, False otherwise
307
+
308
+ Examples:
309
+ >>> is_valid_transition(A2ATaskState.SUBMITTED, A2ATaskState.WORKING)
310
+ True
311
+
312
+ >>> is_valid_transition(A2ATaskState.COMPLETED, A2ATaskState.WORKING)
313
+ False
314
+ """
315
+ if from_state not in VALID_STATE_TRANSITIONS:
316
+ return False
317
+ return to_state in VALID_STATE_TRANSITIONS[from_state]
318
+
319
+
320
+ def get_valid_next_states(current_state: A2ATaskState) -> Set[A2ATaskState]:
321
+ """
322
+ Get the set of valid states that can be transitioned to from the current state.
323
+
324
+ Args:
325
+ current_state: The current A2A task state
326
+
327
+ Returns:
328
+ Set of valid next states (empty set for terminal states)
329
+
330
+ Examples:
331
+ >>> get_valid_next_states(A2ATaskState.WORKING)
332
+ {<A2ATaskState.COMPLETED>, <A2ATaskState.FAILED>, ...}
333
+
334
+ >>> get_valid_next_states(A2ATaskState.COMPLETED)
335
+ set()
336
+ """
337
+ return VALID_STATE_TRANSITIONS.get(current_state, set())
338
+
339
+
340
+ # Convenience constants for commonly used state sets
341
+ TERMINAL_STATES = A2A_TERMINAL_STATES
342
+ ACTIVE_STATES = A2A_ACTIVE_STATES
343
+ WAITING_STATES = {A2ATaskState.INPUT_REQUIRED, A2ATaskState.AUTH_REQUIRED}
344
+ PROCESSING_STATES = {A2ATaskState.SUBMITTED, A2ATaskState.WORKING}