supervaizer 0.9.6__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 (50) hide show
  1. supervaizer/__init__.py +88 -0
  2. supervaizer/__version__.py +10 -0
  3. supervaizer/account.py +304 -0
  4. supervaizer/account_service.py +87 -0
  5. supervaizer/admin/routes.py +1254 -0
  6. supervaizer/admin/templates/agent_detail.html +145 -0
  7. supervaizer/admin/templates/agents.html +175 -0
  8. supervaizer/admin/templates/agents_grid.html +80 -0
  9. supervaizer/admin/templates/base.html +233 -0
  10. supervaizer/admin/templates/case_detail.html +230 -0
  11. supervaizer/admin/templates/cases_list.html +182 -0
  12. supervaizer/admin/templates/cases_table.html +134 -0
  13. supervaizer/admin/templates/console.html +389 -0
  14. supervaizer/admin/templates/dashboard.html +153 -0
  15. supervaizer/admin/templates/job_detail.html +192 -0
  16. supervaizer/admin/templates/jobs_list.html +180 -0
  17. supervaizer/admin/templates/jobs_table.html +122 -0
  18. supervaizer/admin/templates/navigation.html +153 -0
  19. supervaizer/admin/templates/recent_activity.html +81 -0
  20. supervaizer/admin/templates/server.html +105 -0
  21. supervaizer/admin/templates/server_status_cards.html +121 -0
  22. supervaizer/agent.py +816 -0
  23. supervaizer/case.py +400 -0
  24. supervaizer/cli.py +135 -0
  25. supervaizer/common.py +283 -0
  26. supervaizer/event.py +181 -0
  27. supervaizer/examples/controller-template.py +195 -0
  28. supervaizer/instructions.py +145 -0
  29. supervaizer/job.py +379 -0
  30. supervaizer/job_service.py +155 -0
  31. supervaizer/lifecycle.py +417 -0
  32. supervaizer/parameter.py +173 -0
  33. supervaizer/protocol/__init__.py +11 -0
  34. supervaizer/protocol/a2a/__init__.py +21 -0
  35. supervaizer/protocol/a2a/model.py +227 -0
  36. supervaizer/protocol/a2a/routes.py +99 -0
  37. supervaizer/protocol/acp/__init__.py +21 -0
  38. supervaizer/protocol/acp/model.py +198 -0
  39. supervaizer/protocol/acp/routes.py +74 -0
  40. supervaizer/py.typed +1 -0
  41. supervaizer/routes.py +667 -0
  42. supervaizer/server.py +554 -0
  43. supervaizer/server_utils.py +54 -0
  44. supervaizer/storage.py +436 -0
  45. supervaizer/telemetry.py +81 -0
  46. supervaizer-0.9.6.dist-info/METADATA +245 -0
  47. supervaizer-0.9.6.dist-info/RECORD +50 -0
  48. supervaizer-0.9.6.dist-info/WHEEL +4 -0
  49. supervaizer-0.9.6.dist-info/entry_points.txt +2 -0
  50. supervaizer-0.9.6.dist-info/licenses/LICENSE.md +346 -0
@@ -0,0 +1,417 @@
1
+ # Copyright (c) 2024-2025 Alain Prasquier - Supervaize.com. All rights reserved.
2
+ #
3
+ # This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
+ # If a copy of the MPL was not distributed with this file, you can obtain one at
5
+ # https://mozilla.org/MPL/2.0/.
6
+
7
+ import logging
8
+ from datetime import datetime
9
+ from enum import Enum
10
+ from typing import TYPE_CHECKING, Any, Dict, List, Protocol, TypeVar
11
+
12
+ if TYPE_CHECKING:
13
+ pass
14
+
15
+ log = logging.getLogger(__name__)
16
+
17
+
18
+ class EntityStatus(str, Enum):
19
+ """Base status enum for workflow entities."""
20
+
21
+ STOPPED = "stopped"
22
+ IN_PROGRESS = "in_progress"
23
+ CANCELLING = "cancelling"
24
+ AWAITING = "awaiting"
25
+ COMPLETED = "completed"
26
+ FAILED = "failed"
27
+ CANCELLED = "cancelled"
28
+
29
+ @staticmethod
30
+ def status_stopped() -> list["EntityStatus"]:
31
+ return [
32
+ EntityStatus.STOPPED,
33
+ EntityStatus.CANCELLED,
34
+ EntityStatus.FAILED,
35
+ EntityStatus.COMPLETED,
36
+ ]
37
+
38
+ @property
39
+ def is_stopped(self) -> bool:
40
+ return self in EntityStatus.status_stopped()
41
+
42
+ @staticmethod
43
+ def status_running() -> list["EntityStatus"]:
44
+ return [
45
+ EntityStatus.IN_PROGRESS,
46
+ EntityStatus.CANCELLING,
47
+ EntityStatus.AWAITING,
48
+ ]
49
+
50
+ @property
51
+ def is_running(self) -> bool:
52
+ return self in EntityStatus.status_running()
53
+
54
+ @staticmethod
55
+ def status_anomaly() -> list["EntityStatus"]:
56
+ return [
57
+ EntityStatus.CANCELLING,
58
+ EntityStatus.CANCELLED,
59
+ EntityStatus.FAILED,
60
+ ]
61
+
62
+ @property
63
+ def is_anomaly(self) -> bool:
64
+ return self in EntityStatus.status_anomaly()
65
+
66
+ @property
67
+ def label(self) -> str:
68
+ """Get the display label for the enum value."""
69
+ return self.name.replace("_", " ").title()
70
+
71
+
72
+ class EntityEvents(str, Enum):
73
+ """Events that trigger transitions between entity states."""
74
+
75
+ START_WORK = "start_work"
76
+ SUCCESSFULLY_DONE = "successfully_done"
77
+ AWAITING_ON_INPUT = "awaiting_on_input"
78
+ CANCEL_REQUESTED = "cancel_requested"
79
+ ERROR_ENCOUNTERED = "error_encountered"
80
+ TIMEOUT_OR_ERROR = "timeout_or_error"
81
+ INPUT_RECEIVED = "input_received"
82
+ CANCEL_WHILE_WAITING = "cancel_while_waiting"
83
+ CANCEL_CONFIRMED = "cancel_confirmed"
84
+
85
+ @property
86
+ def label(self) -> str:
87
+ """Get the display label for the enum value."""
88
+ return self.name.replace("_", " ").title()
89
+
90
+
91
+ class Lifecycle:
92
+ """
93
+ Defines valid state transitions for workflow entities.
94
+
95
+ From: https://agentcommunicationprotocol.dev/core-concepts/agent-lifecycle
96
+ ```mermaid
97
+ stateDiagram-v2
98
+ [*] --> created
99
+ created --> in_progress : Start work
100
+ in_progress --> completed : Successfully done
101
+ in_progress --> awaiting : Awaiting on input
102
+ in_progress --> cancelling : Cancel requested
103
+ awaiting --> failed : Timeout or error
104
+ in_progress --> failed : Error encountered
105
+ awaiting --> in_progress : Input received
106
+ awaiting --> cancelling : Cancel while waiting
107
+ cancelling --> cancelled : Cancel confirmed
108
+ cancelled --> [*]
109
+ completed --> [*]
110
+ failed --> [*]
111
+ ```
112
+ """
113
+
114
+ # Event to transition mapping
115
+ EVENT_TRANSITIONS = {
116
+ EntityEvents.START_WORK: (EntityStatus.STOPPED, EntityStatus.IN_PROGRESS),
117
+ EntityEvents.SUCCESSFULLY_DONE: (
118
+ EntityStatus.IN_PROGRESS,
119
+ EntityStatus.COMPLETED,
120
+ ),
121
+ EntityEvents.AWAITING_ON_INPUT: (
122
+ EntityStatus.IN_PROGRESS,
123
+ EntityStatus.AWAITING,
124
+ ),
125
+ EntityEvents.CANCEL_REQUESTED: (
126
+ EntityStatus.IN_PROGRESS,
127
+ EntityStatus.CANCELLING,
128
+ ),
129
+ EntityEvents.ERROR_ENCOUNTERED: (EntityStatus.IN_PROGRESS, EntityStatus.FAILED),
130
+ EntityEvents.TIMEOUT_OR_ERROR: (EntityStatus.AWAITING, EntityStatus.FAILED),
131
+ EntityEvents.INPUT_RECEIVED: (EntityStatus.AWAITING, EntityStatus.IN_PROGRESS),
132
+ EntityEvents.CANCEL_WHILE_WAITING: (
133
+ EntityStatus.AWAITING,
134
+ EntityStatus.CANCELLING,
135
+ ),
136
+ EntityEvents.CANCEL_CONFIRMED: (
137
+ EntityStatus.CANCELLING,
138
+ EntityStatus.CANCELLED,
139
+ ),
140
+ }
141
+
142
+ @classmethod
143
+ def get_terminal_states(cls) -> List[EntityStatus]:
144
+ """
145
+ Identify terminal states in the state machine.
146
+
147
+ A terminal state is a state that has no outgoing transitions.
148
+
149
+ Returns:
150
+ list: List of EntityStatus enum values representing terminal states
151
+ """
152
+ # Get all states that appear as 'from_status' in transitions
153
+ states_with_outgoing = set(
154
+ from_status for _, (from_status, _) in cls.EVENT_TRANSITIONS.items()
155
+ )
156
+
157
+ # Terminal states are those that have no outgoing transitions
158
+ terminal_states = [
159
+ status for status in EntityStatus if status not in states_with_outgoing
160
+ ]
161
+
162
+ return terminal_states
163
+
164
+ @classmethod
165
+ def get_start_states(cls) -> List[EntityStatus]:
166
+ """
167
+ Identify start states in the state machine.
168
+
169
+ A start state is a state that can be entered directly at the beginning of
170
+ the workflow. In our case, this is determined by convention and by examining
171
+ which states don't appear as target states in any transition except their own.
172
+
173
+ Returns:
174
+ list: List of EntityStatus enum values representing start states
175
+ """
176
+ # Get all states that appear as 'to_status' in transitions
177
+ target_states = set(
178
+ to_status for _, (_, to_status) in cls.EVENT_TRANSITIONS.items()
179
+ )
180
+
181
+ # Get all states that appear as 'from_status' in transitions
182
+ source_states = set(
183
+ from_status for _, (from_status, _) in cls.EVENT_TRANSITIONS.items()
184
+ )
185
+
186
+ # Find states that are source states but never target states
187
+ # (except for cycles where they might transition to themselves)
188
+ start_candidates = source_states.difference(target_states)
189
+
190
+ # If no clear start states are found based on the above logic,
191
+ # use STOPPED as the conventional start state
192
+ if not start_candidates:
193
+ return [EntityStatus.STOPPED]
194
+
195
+ return list(start_candidates)
196
+
197
+ @classmethod
198
+ def get_valid_transitions(
199
+ cls, current_status: EntityStatus
200
+ ) -> Dict[EntityStatus, EntityEvents]:
201
+ """Get valid transitions from the current status."""
202
+ result = {}
203
+ for event, (from_status, to_status) in cls.EVENT_TRANSITIONS.items():
204
+ if from_status == current_status:
205
+ result[to_status] = event
206
+ return result
207
+
208
+ @classmethod
209
+ def can_transition(cls, from_status: EntityStatus, to_status: EntityStatus) -> bool:
210
+ """Check if transition from current status to target status is valid."""
211
+ for event, (event_from, event_to) in cls.EVENT_TRANSITIONS.items():
212
+ if event_from == from_status and event_to == to_status:
213
+ return True
214
+ return False
215
+
216
+ @classmethod
217
+ def get_transition_reason(
218
+ cls, from_status: EntityStatus, to_status: EntityStatus
219
+ ) -> str:
220
+ """Get the reason/description for a transition."""
221
+ for event, (event_from, event_to) in cls.EVENT_TRANSITIONS.items():
222
+ if event_from == from_status and event_to == to_status:
223
+ return event.value
224
+ return "Invalid transition"
225
+
226
+ @classmethod
227
+ def get_status_from_event(
228
+ cls, current_status: EntityStatus, event: EntityEvents
229
+ ) -> EntityStatus | None:
230
+ """Get the target status for a given event from the current status."""
231
+ if event not in cls.EVENT_TRANSITIONS:
232
+ return None
233
+
234
+ from_status, to_status = cls.EVENT_TRANSITIONS[event]
235
+ if current_status == from_status:
236
+ return to_status
237
+
238
+ return None
239
+
240
+ @classmethod
241
+ def generate_valid_transitions_dict(
242
+ cls,
243
+ ) -> Dict[EntityStatus, Dict[EntityStatus, EntityEvents]]:
244
+ """
245
+ Generate a complete dictionary of all valid transitions in the format:
246
+ {
247
+ StatusA: {StatusB: EventAB, StatusC: EventAC},
248
+ StatusB: {StatusD: EventBD},
249
+ ...
250
+ TerminalStatusX: {},
251
+ }
252
+ """
253
+ # Initialize the result dictionary with all statuses
254
+ result: Dict[EntityStatus, Dict[EntityStatus, EntityEvents]] = {
255
+ status: {} for status in EntityStatus
256
+ }
257
+
258
+ # Populate with transitions from EVENT_TRANSITIONS
259
+ for event, (from_status, to_status) in cls.EVENT_TRANSITIONS.items():
260
+ result[from_status][to_status] = event
261
+
262
+ return result
263
+
264
+ @classmethod
265
+ def generate_mermaid_diagram(cls, steps_list: list[str]) -> str:
266
+ """
267
+ Generate a Mermaid stateDiagram-v2 representation of the state machine.
268
+
269
+ Args:
270
+ steps_list: List of steps to include in the diagram (get it from cls.mermaid_diagram_all_steps())
271
+
272
+ Returns:
273
+ str: Mermaid markdown for the state diagram
274
+ """
275
+ # Start with diagram header
276
+ mermaid = "```mermaid\nstateDiagram-v2\n"
277
+ # Start state
278
+ mermaid += "\n ".join(steps_list)
279
+
280
+ # Close the diagram
281
+ mermaid += "\n```"
282
+
283
+ return mermaid
284
+
285
+ @classmethod
286
+ def mermaid_diagram_all_steps(cls) -> list[str]:
287
+ """Get all steps for the Mermaid diagram."""
288
+ steps = cls.mermaid_start_state()
289
+ steps.extend(cls.mermaid_diagram_steps())
290
+ steps.extend(cls.mermaid_terminal_states())
291
+ return steps
292
+
293
+ @classmethod
294
+ def mermaid_diagram_steps(cls) -> list[str]:
295
+ """
296
+ Generate a list of steps for the Mermaid diagram.
297
+ """
298
+ steps = []
299
+ for event, (from_status, to_status) in cls.EVENT_TRANSITIONS.items():
300
+ # Get the event display name for the transition label
301
+ event_display = str(event.label)
302
+ from_state = from_status.value
303
+ to_state = to_status.value
304
+
305
+ steps.append(f"{from_state} --> {to_state} : {event_display}")
306
+
307
+ return steps
308
+
309
+ @classmethod
310
+ def mermaid_start_state(cls) -> list[str]:
311
+ """Get the start state for the Mermaid diagram."""
312
+ return [f"[*] --> {state.value}" for state in cls.get_start_states()]
313
+
314
+ @classmethod
315
+ def mermaid_terminal_states(cls) -> list[str]:
316
+ """Get the terminal states for the Mermaid diagram."""
317
+ return [f"{state.value} --> [*]" for state in cls.get_terminal_states()]
318
+
319
+
320
+ # Type aliases for backward compatibility
321
+ JobTransitions = Lifecycle
322
+
323
+
324
+ class WorkflowEntity(Protocol):
325
+ """Protocol that defines the interface required for an entity to work with lifecycle transitions."""
326
+
327
+ status: EntityStatus
328
+ finished_at: Any
329
+ id: Any
330
+ name: str
331
+
332
+
333
+ T = TypeVar("T", bound=WorkflowEntity)
334
+
335
+
336
+ class EntityLifecycle:
337
+ """
338
+ Generic lifecycle manager for workflow entities like Job and Case.
339
+ Handles state transitions according to defined business rules.
340
+ """
341
+
342
+ @staticmethod
343
+ def transition(entity: T, to_status: EntityStatus) -> tuple[bool, str]:
344
+ """
345
+ Transition an entity to a new status if the transition is valid.
346
+
347
+ Args:
348
+ entity: The entity object to transition (Job, Case, etc.)
349
+ to_status: The target EntityStatus to transition to
350
+
351
+ Returns:
352
+ tuple[bool, str]: (True, "") if transition was successful,
353
+ (False, "error explanation") otherwise
354
+
355
+ Side effects:
356
+ - Updates the entity status
357
+ - Records the finished time if the entity is in a terminal state
358
+
359
+ Tested in apps.sv_entities.tests.test_lifecycle
360
+ """
361
+ current_status = entity.status
362
+
363
+ # Check if transition is valid
364
+ if not Lifecycle.can_transition(current_status, to_status):
365
+ error_msg = (
366
+ f"Invalid transition: {current_status} → {to_status} "
367
+ f"for {entity.__class__.__name__} {entity.id} ({entity.name})"
368
+ )
369
+ log.warning(error_msg)
370
+ return False, error_msg
371
+
372
+ # Log the transition
373
+ reason = Lifecycle.get_transition_reason(current_status, to_status)
374
+ log.info(
375
+ f"{entity.__class__.__name__} {entity.id} ({entity.name}) "
376
+ f"transitioning: {current_status} → {to_status}. Reason: {reason}"
377
+ )
378
+
379
+ # Update the entity status
380
+ entity.status = to_status
381
+
382
+ # If transitioning to a terminal state, record the finished time
383
+ if to_status in [
384
+ EntityStatus.COMPLETED,
385
+ EntityStatus.CANCELLED,
386
+ EntityStatus.FAILED,
387
+ ]:
388
+ if not entity.finished_at:
389
+ entity.finished_at = datetime.now()
390
+
391
+ return True, ""
392
+
393
+ @staticmethod
394
+ def handle_event(entity: T, event: EntityEvents) -> tuple[bool, str]:
395
+ """
396
+ Handle an event by transitioning the entity to the appropriate status.
397
+
398
+ Args:
399
+ entity: The entity object to transition
400
+ event: The event that occurred
401
+
402
+ Returns:
403
+ tuple[bool, str]: (True, "") if handling was successful,
404
+ (False, "error explanation") otherwise
405
+ """
406
+ current_status = entity.status
407
+ to_status = Lifecycle.get_status_from_event(current_status, event)
408
+
409
+ if not to_status:
410
+ error_msg = (
411
+ f"Invalid event {event} for current status {current_status} "
412
+ f"in {entity.__class__.__name__} {entity.id} ({entity.name})"
413
+ )
414
+ log.warning(error_msg)
415
+ return False, error_msg
416
+
417
+ return EntityLifecycle.transition(entity, to_status)
@@ -0,0 +1,173 @@
1
+ # Copyright (c) 2024-2025 Alain Prasquier - Supervaize.com. All rights reserved.
2
+ #
3
+ # This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
+ # If a copy of the MPL was not distributed with this file, you can obtain one at
5
+ # https://mozilla.org/MPL/2.0/.
6
+
7
+
8
+ from pydantic import Field
9
+ import os
10
+ from typing import Any, Dict, List
11
+
12
+ from supervaizer.common import SvBaseModel, log
13
+
14
+
15
+ class ParameterAbstract(SvBaseModel):
16
+ """
17
+ Base model for agent parameters that defines configuration and metadata.
18
+
19
+ Parameters can be environment variables, secrets, or regular configuration values
20
+ that are used by agents during execution. The Supervaize platform uses this
21
+ model to manage parameter definitions and values.
22
+ """
23
+
24
+ name: str = Field(
25
+ description="The name of the parameter, as used in the agent code"
26
+ )
27
+ description: str | None = Field(
28
+ default=None,
29
+ description="The description of the parameter, used in the Supervaize UI",
30
+ )
31
+ is_environment: bool = Field(
32
+ default=False,
33
+ description="Whether the parameter is set as an environment variable",
34
+ )
35
+ value: str | None = Field(
36
+ default=None,
37
+ description="The value of the parameter - provided by the Supervaize platform",
38
+ )
39
+ is_secret: bool = Field(
40
+ default=False,
41
+ description="Whether the parameter is a secret - hidden from the user in the Supervaize UI",
42
+ )
43
+ is_required: bool = Field(
44
+ default=False,
45
+ description="Whether the parameter is required, used in the Supervaize UI",
46
+ )
47
+
48
+ model_config = {
49
+ "reference_group": "Core",
50
+ "example_dict": {
51
+ "name": "OPEN_API_KEY",
52
+ "description": "OpenAPI Key",
53
+ "is_environment": True,
54
+ "is_secret": True,
55
+ "is_required": True,
56
+ },
57
+ }
58
+
59
+
60
+ class Parameter(ParameterAbstract):
61
+ @property
62
+ def to_dict(self) -> Dict[str, Any]:
63
+ """
64
+ Override the to_dict method to handle the value field.
65
+ """
66
+ data = self.model_dump(mode="json")
67
+ if self.is_secret:
68
+ data["value"] = "********"
69
+ return data
70
+
71
+ @property
72
+ def registration_info(self) -> Dict[str, Any]:
73
+ return {
74
+ "name": self.name,
75
+ "description": self.description,
76
+ "is_environment": self.is_environment,
77
+ "is_secret": self.is_secret,
78
+ "is_required": self.is_required,
79
+ }
80
+
81
+ def set_value(self, value: str) -> None:
82
+ """
83
+ Set the value of a parameter and update the environment variable if needed.
84
+ Note that environment is updated ONLY if set_value is called explicitly.
85
+ Tested in tests/test_parameter.py
86
+ """
87
+ self.value = value
88
+ if self.is_environment:
89
+ os.environ[self.name] = value
90
+
91
+
92
+ class ParametersSetup(SvBaseModel):
93
+ """
94
+ ParametersSetup model for the Supervaize Control API.
95
+
96
+ This represents a collection of parameters that can be used by an agent.
97
+ It contains a dictionary of parameters, where the key is the parameter name
98
+ and the value is the parameter object.
99
+
100
+ Example:
101
+ ```python
102
+ ParametersSetup.from_list([
103
+ Parameter(name="parameter1", value="value1"),
104
+ Parameter(name="parameter2", value="value2", description="desc2"),
105
+ ])
106
+ ```
107
+ """
108
+
109
+ definitions: Dict[str, Parameter] = Field(
110
+ description="A dictionary of Parameters, where the key is the parameter name and the value is the parameter object.",
111
+ )
112
+
113
+ model_config = {
114
+ "reference_group": "Core",
115
+ }
116
+
117
+ @classmethod
118
+ def from_list(
119
+ cls, parameter_list: List[Parameter | Dict[str, Any]] | None
120
+ ) -> "ParametersSetup | None":
121
+ if not parameter_list:
122
+ return None
123
+
124
+ if parameter_list and isinstance(
125
+ parameter_list[0], dict
126
+ ): # TODO: add test for this
127
+ parameter_list_casted = [
128
+ Parameter(**parameter)
129
+ for parameter in parameter_list
130
+ if isinstance(parameter, dict)
131
+ ]
132
+ parameter_list = parameter_list_casted # type: ignore
133
+ return cls(
134
+ definitions={parameter.name: parameter for parameter in parameter_list} # type: ignore
135
+ )
136
+
137
+ def value(self, name: str) -> str | None:
138
+ """
139
+ Get the value of a parameter from the environment.
140
+ """
141
+ parameter = self.definitions.get(name, None)
142
+ return parameter.value if parameter else None
143
+
144
+ @property
145
+ def registration_info(self) -> List[Dict[str, Any]]:
146
+ return [parameter.registration_info for parameter in self.definitions.values()]
147
+
148
+ def update_values_from_server(
149
+ self, server_parameters_setup: List[Dict[str, Any]]
150
+ ) -> "ParametersSetup":
151
+ """Update the values of the parameters from the server.
152
+
153
+ Args:
154
+ server_parameters_setup (List[Dict[str, Any]]): The parameters from the server.
155
+
156
+ Raises:
157
+ ValueError: If the parameter is not found in the definitions.
158
+
159
+ Returns:
160
+ ParametersSetup: The updated parameters.
161
+
162
+ Tested in tests/test_parameter.test_parameters_setup_update_values_from_server
163
+ """
164
+ for parameter in server_parameters_setup:
165
+ if parameter.get("name", None) in self.definitions.keys():
166
+ def_parameter = self.definitions[parameter["name"]]
167
+ def_parameter.set_value(parameter["value"])
168
+ else:
169
+ message = f"Parameter {parameter} not found in definitions"
170
+ log.error(message)
171
+ raise ValueError(message)
172
+
173
+ return self
@@ -0,0 +1,11 @@
1
+ # Copyright (c) 2024-2025 Alain Prasquier - Supervaize.com. All rights reserved.
2
+ #
3
+ # This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
+ # If a copy of the MPL was not distributed with this file, you can obtain one at
5
+ # https://mozilla.org/MPL/2.0/.
6
+
7
+ """Protocol implementations for SUPERVAIZER."""
8
+
9
+ from supervaizer.protocol import a2a, acp
10
+
11
+ __all__ = ["a2a", "acp"]
@@ -0,0 +1,21 @@
1
+ # Copyright (c) 2024-2025 Alain Prasquier - Supervaize.com. All rights reserved.
2
+ #
3
+ # This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
+ # If a copy of the MPL was not distributed with this file, you can obtain one at
5
+ # https://mozilla.org/MPL/2.0/.
6
+
7
+ """A2A protocol implementation for SUPERVAIZER."""
8
+
9
+ from supervaizer.protocol.a2a.model import (
10
+ create_agent_card,
11
+ create_agents_list,
12
+ create_health_data,
13
+ )
14
+ from supervaizer.protocol.a2a.routes import create_routes
15
+
16
+ __all__ = [
17
+ "create_agent_card",
18
+ "create_agents_list",
19
+ "create_health_data",
20
+ "create_routes",
21
+ ]