supervaizer 0.10.5__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 (76) hide show
  1. supervaizer/__init__.py +97 -0
  2. supervaizer/__version__.py +10 -0
  3. supervaizer/account.py +308 -0
  4. supervaizer/account_service.py +93 -0
  5. supervaizer/admin/routes.py +1293 -0
  6. supervaizer/admin/static/js/job-start-form.js +373 -0
  7. supervaizer/admin/templates/agent_detail.html +145 -0
  8. supervaizer/admin/templates/agents.html +249 -0
  9. supervaizer/admin/templates/agents_grid.html +82 -0
  10. supervaizer/admin/templates/base.html +233 -0
  11. supervaizer/admin/templates/case_detail.html +230 -0
  12. supervaizer/admin/templates/cases_list.html +182 -0
  13. supervaizer/admin/templates/cases_table.html +134 -0
  14. supervaizer/admin/templates/console.html +389 -0
  15. supervaizer/admin/templates/dashboard.html +153 -0
  16. supervaizer/admin/templates/job_detail.html +192 -0
  17. supervaizer/admin/templates/job_start_test.html +109 -0
  18. supervaizer/admin/templates/jobs_list.html +180 -0
  19. supervaizer/admin/templates/jobs_table.html +122 -0
  20. supervaizer/admin/templates/navigation.html +163 -0
  21. supervaizer/admin/templates/recent_activity.html +81 -0
  22. supervaizer/admin/templates/server.html +105 -0
  23. supervaizer/admin/templates/server_status_cards.html +121 -0
  24. supervaizer/admin/templates/supervaize_instructions.html +212 -0
  25. supervaizer/agent.py +956 -0
  26. supervaizer/case.py +432 -0
  27. supervaizer/cli.py +395 -0
  28. supervaizer/common.py +324 -0
  29. supervaizer/deploy/__init__.py +16 -0
  30. supervaizer/deploy/cli.py +305 -0
  31. supervaizer/deploy/commands/__init__.py +9 -0
  32. supervaizer/deploy/commands/clean.py +294 -0
  33. supervaizer/deploy/commands/down.py +119 -0
  34. supervaizer/deploy/commands/local.py +460 -0
  35. supervaizer/deploy/commands/plan.py +167 -0
  36. supervaizer/deploy/commands/status.py +169 -0
  37. supervaizer/deploy/commands/up.py +281 -0
  38. supervaizer/deploy/docker.py +377 -0
  39. supervaizer/deploy/driver_factory.py +42 -0
  40. supervaizer/deploy/drivers/__init__.py +39 -0
  41. supervaizer/deploy/drivers/aws_app_runner.py +607 -0
  42. supervaizer/deploy/drivers/base.py +196 -0
  43. supervaizer/deploy/drivers/cloud_run.py +570 -0
  44. supervaizer/deploy/drivers/do_app_platform.py +504 -0
  45. supervaizer/deploy/health.py +404 -0
  46. supervaizer/deploy/state.py +210 -0
  47. supervaizer/deploy/templates/Dockerfile.template +44 -0
  48. supervaizer/deploy/templates/debug_env.py +69 -0
  49. supervaizer/deploy/templates/docker-compose.yml.template +37 -0
  50. supervaizer/deploy/templates/dockerignore.template +66 -0
  51. supervaizer/deploy/templates/entrypoint.sh +20 -0
  52. supervaizer/deploy/utils.py +52 -0
  53. supervaizer/event.py +181 -0
  54. supervaizer/examples/controller_template.py +196 -0
  55. supervaizer/instructions.py +145 -0
  56. supervaizer/job.py +392 -0
  57. supervaizer/job_service.py +156 -0
  58. supervaizer/lifecycle.py +417 -0
  59. supervaizer/parameter.py +233 -0
  60. supervaizer/protocol/__init__.py +11 -0
  61. supervaizer/protocol/a2a/__init__.py +21 -0
  62. supervaizer/protocol/a2a/model.py +227 -0
  63. supervaizer/protocol/a2a/routes.py +99 -0
  64. supervaizer/py.typed +1 -0
  65. supervaizer/routes.py +917 -0
  66. supervaizer/server.py +553 -0
  67. supervaizer/server_utils.py +54 -0
  68. supervaizer/storage.py +462 -0
  69. supervaizer/telemetry.py +81 -0
  70. supervaizer/utils/__init__.py +16 -0
  71. supervaizer/utils/version_check.py +56 -0
  72. supervaizer-0.10.5.dist-info/METADATA +317 -0
  73. supervaizer-0.10.5.dist-info/RECORD +76 -0
  74. supervaizer-0.10.5.dist-info/WHEEL +4 -0
  75. supervaizer-0.10.5.dist-info/entry_points.txt +2 -0
  76. supervaizer-0.10.5.dist-info/licenses/LICENSE.md +346 -0
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright (c) 2024-2025 Alain Prasquier - Supervaize.com. All rights reserved.
3
+ #
4
+ # This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
5
+ # If a copy of the MPL was not distributed with this file, you can obtain one at
6
+ # https://mozilla.org/MPL/2.0/.
7
+
8
+ """Debug script to check environment variables in container."""
9
+
10
+ import os
11
+ import sys
12
+
13
+
14
+ def debug_environment_variables() -> None:
15
+ """Print all environment variables for debugging."""
16
+ print("=== Environment Variables Debug ===")
17
+ print(f"Python version: {sys.version}")
18
+ print(f"Working directory: {os.getcwd()}")
19
+ print()
20
+
21
+ # Check specific Supervaize environment variables
22
+ supervaize_vars = [
23
+ "SUPERVAIZE_API_KEY",
24
+ "SUPERVAIZE_WORKSPACE_ID",
25
+ "SUPERVAIZE_API_URL",
26
+ "SUPERVAIZER_PORT",
27
+ "SUPERVAIZER_PUBLIC_URL",
28
+ "SUPERVAIZER_ENVIRONMENT",
29
+ "SUPERVAIZER_HOST",
30
+ "SUPERVAIZER_API_KEY",
31
+ "SV_RSA_PRIVATE_KEY",
32
+ "SV_LOG_LEVEL",
33
+ ]
34
+
35
+ print("=== Supervaize Environment Variables ===")
36
+ for var_name in supervaize_vars:
37
+ value = os.getenv(var_name)
38
+ if value is None:
39
+ print(f"{var_name}: [NOT SET]")
40
+ elif value == "":
41
+ print(f"{var_name}: [EMPTY STRING]")
42
+ else:
43
+ # Mask sensitive values
44
+ if "KEY" in var_name or "SECRET" in var_name:
45
+ masked_value = (
46
+ value[:4] + "*" * (len(value) - 8) + value[-4:]
47
+ if len(value) > 8
48
+ else "*" * len(value)
49
+ )
50
+ print(f"{var_name}: {masked_value}")
51
+ else:
52
+ print(f"{var_name}: {value}")
53
+
54
+ print()
55
+ print("=== All Environment Variables ===")
56
+ for key, value in sorted(os.environ.items()):
57
+ if "KEY" in key or "SECRET" in key or "PASSWORD" in key:
58
+ masked_value = (
59
+ value[:4] + "*" * (len(value) - 8) + value[-4:]
60
+ if len(value) > 8
61
+ else "*" * len(value)
62
+ )
63
+ print(f"{key}: {masked_value}")
64
+ else:
65
+ print(f"{key}: {value}")
66
+
67
+
68
+ if __name__ == "__main__":
69
+ debug_environment_variables()
@@ -0,0 +1,37 @@
1
+ services:
2
+ {{SERVICE_NAME}}:
3
+ build:
4
+ context: ..
5
+ dockerfile: .deployment/Dockerfile
6
+ args:
7
+ - SUPERVAIZE_API_KEY={{API_KEY}}
8
+ - SUPERVAIZE_WORKSPACE_ID={{WORKSPACE_ID}}
9
+ - SUPERVAIZE_API_URL={{API_URL}}
10
+ - SUPERVAIZER_PORT=8000
11
+ - SUPERVAIZER_PUBLIC_URL={{PUBLIC_URL}}
12
+ ports:
13
+ - "{{PORT}}:8000"
14
+ environment:
15
+ - SUPERVAIZER_ENVIRONMENT={{ENVIRONMENT}}
16
+ - SUPERVAIZER_HOST=0.0.0.0
17
+ - SUPERVAIZER_PORT=8000
18
+ - SV_LOG_LEVEL={{ env.SV_LOG_LEVEL | default('INFO') }}
19
+ - SUPERVAIZER_API_KEY={{API_KEY}}
20
+ - SV_RSA_PRIVATE_KEY={{RSA_KEY}}
21
+ - SUPERVAIZE_API_KEY={{API_KEY}}
22
+ - SUPERVAIZE_WORKSPACE_ID={{WORKSPACE_ID}}
23
+ - SUPERVAIZE_API_URL={{API_URL}}
24
+ - SUPERVAIZER_PUBLIC_URL={{PUBLIC_URL}}
25
+ healthcheck:
26
+ test: ["CMD", "curl", "-f", "http://localhost:8000/.well-known/health"]
27
+ interval: 30s
28
+ timeout: 10s
29
+ retries: 3
30
+ start_period: 40s
31
+ restart: unless-stopped
32
+ networks:
33
+ - supervaizer-network
34
+
35
+ networks:
36
+ supervaizer-network:
37
+ driver: bridge
@@ -0,0 +1,66 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual environments
24
+ .venv/
25
+ venv/
26
+ env/
27
+ ENV/
28
+ env.bak/
29
+ venv.bak/
30
+
31
+ # IDE
32
+ .vscode/
33
+ .idea/
34
+ *.swp
35
+ *.swo
36
+ *~
37
+
38
+ # OS
39
+ .DS_Store
40
+ Thumbs.db
41
+
42
+ # Git
43
+ .git/
44
+ .gitignore
45
+
46
+ # Documentation
47
+ docs/
48
+ *.md
49
+ README*
50
+
51
+ # Tests
52
+ tests/
53
+ test_*
54
+ *_test.py
55
+
56
+ # Deployment artifacts
57
+ .deployment/
58
+ !.deployment/debug_env.py
59
+
60
+ # Logs
61
+ *.log
62
+ logs/
63
+
64
+ # Temporary files
65
+ tmp/
66
+ temp/
@@ -0,0 +1,20 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ # Change to app directory
5
+ cd /app
6
+
7
+ # Remove any stale .venv references that might cause issues
8
+ if [ -d ".venv" ] && [ ! -f ".venv/bin/python3" ]; then
9
+ rm -rf .venv
10
+ fi
11
+
12
+ # Install the project if not already installed
13
+ # This ensures the supervaizer command is available
14
+ if ! command -v supervaizer &> /dev/null; then
15
+ echo "Installing supervaizer..."
16
+ uv sync --frozen --no-dev
17
+ fi
18
+
19
+ # Run supervaizer start
20
+ exec uv run supervaizer start
@@ -0,0 +1,52 @@
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
+ Deployment State Management
9
+
10
+ This module handles deployment state persistence and management.
11
+ """
12
+
13
+ import subprocess
14
+ from pathlib import Path
15
+
16
+ from supervaizer.common import log
17
+
18
+
19
+ def create_deployment_directory(project_root: Path) -> Path:
20
+ """Create deployment directory and add to .gitignore."""
21
+ deployment_dir = project_root / ".deployment"
22
+ deployment_dir.mkdir(exist_ok=True)
23
+
24
+ # Create logs subdirectory
25
+ logs_dir = deployment_dir / "logs"
26
+ logs_dir.mkdir(exist_ok=True)
27
+
28
+ # Add to .gitignore if not already present
29
+ gitignore_path = project_root / ".gitignore"
30
+ gitignore_entry = ".deployment/"
31
+
32
+ if gitignore_path.exists():
33
+ gitignore_content = gitignore_path.read_text()
34
+ if gitignore_entry not in gitignore_content:
35
+ gitignore_path.write_text(gitignore_content + f"\n{gitignore_entry}\n")
36
+ log.info(f"Added {gitignore_entry} to .gitignore")
37
+ else:
38
+ gitignore_path.write_text(f"{gitignore_entry}\n")
39
+ log.info(f"Created .gitignore with {gitignore_entry}")
40
+
41
+ return deployment_dir
42
+
43
+
44
+ def get_git_sha() -> str:
45
+ """Get the current git SHA for tagging."""
46
+ try:
47
+ result = subprocess.run(
48
+ ["git", "rev-parse", "HEAD"], capture_output=True, text=True, check=True
49
+ )
50
+ return result.stdout.strip()[:8] # Use short SHA
51
+ except (subprocess.CalledProcessError, FileNotFoundError):
52
+ return "latest"
supervaizer/event.py ADDED
@@ -0,0 +1,181 @@
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
+ from enum import Enum
8
+ from typing import TYPE_CHECKING, Any, ClassVar, Dict
9
+
10
+ from supervaizer.__version__ import VERSION
11
+ from supervaizer.common import SvBaseModel
12
+ from supervaizer.lifecycle import EntityStatus
13
+
14
+ if TYPE_CHECKING:
15
+ from supervaizer.agent import Agent
16
+ from supervaizer.case import Case, CaseNodeUpdate
17
+ from supervaizer.job import Job
18
+ from supervaizer.server import Server
19
+
20
+
21
+ class EventType(str, Enum):
22
+ AGENT_REGISTER = "agent.register"
23
+ SERVER_REGISTER = "server.register"
24
+ AGENT_WAKEUP = "agent.wakeup"
25
+ AGENT_SEND_ANOMALY = "agent.anomaly"
26
+ INTERMEDIARY = "agent.intermediary"
27
+ JOB_START_CONFIRMATION = "agent.job.start.confirmation"
28
+ JOB_END = "agent.job.end"
29
+ JOB_STATUS = "agent.job.status"
30
+ JOB_RESULT = "agent.job.result"
31
+ JOB_ERROR = "agent.job.error"
32
+ CASE_START = "agent.case.start"
33
+ CASE_END = "agent.case.end"
34
+ CASE_STATUS = "agent.case.status"
35
+ CASE_RESULT = "agent.case.result"
36
+ CASE_UPDATE = "agent.case.update"
37
+
38
+
39
+ class AbstractEvent(SvBaseModel):
40
+ supervaizer_VERSION: ClassVar[str] = VERSION
41
+ source: Dict[str, Any]
42
+ account: Any # Use Any to avoid Pydantic type resolution issues
43
+ type: EventType
44
+ object_type: str
45
+ details: Dict[str, Any]
46
+
47
+
48
+ class Event(AbstractEvent):
49
+ """Base class for all events in the Supervaize Control system.
50
+
51
+ Events represent messages sent from agents to the control system to communicate
52
+ status, anomalies, deliverables and other information.
53
+
54
+ Inherits from AbstractEvent which defines the core event attributes:
55
+ - source: The source/origin of the event (e.g. agent/server URI)
56
+ - type: The EventType enum indicating the event category
57
+ - account: The account that the event belongs to
58
+ - details: A dictionary containing event-specific details
59
+
60
+ Tests in tests/test_event.py
61
+ """
62
+
63
+ def __init__(self, **kwargs: Any) -> None:
64
+ super().__init__(**kwargs)
65
+
66
+ @property
67
+ def payload(self) -> Dict[str, Any]:
68
+ """
69
+ Returns the payload for the event.
70
+ This must be a dictionary that can be serialized to JSON to be sent in the request body.
71
+ """
72
+ return {
73
+ "source": self.source,
74
+ "workspace": f"{self.account.workspace_id}",
75
+ "event_type": f"{self.type.value}",
76
+ "object_type": self.object_type,
77
+ "details": self.details,
78
+ }
79
+
80
+
81
+ class AgentRegisterEvent(Event):
82
+ """Event sent when an agent registers with the control system.
83
+
84
+ Test in tests/test_agent_register_event.py
85
+ """
86
+
87
+ def __init__(
88
+ self,
89
+ agent: "Agent",
90
+ account: Any, # Use Any to avoid type resolution issues
91
+ polling: bool = True,
92
+ ) -> None:
93
+ super().__init__(
94
+ type=EventType.AGENT_REGISTER,
95
+ account=account,
96
+ source={"agent": agent.slug},
97
+ object_type="agent",
98
+ details=agent.registration_info | {"polling": polling},
99
+ )
100
+
101
+
102
+ class ServerRegisterEvent(Event):
103
+ def __init__(
104
+ self,
105
+ account: Any, # Use Any to avoid type resolution issues
106
+ server: "Server",
107
+ ) -> None:
108
+ super().__init__(
109
+ type=EventType.SERVER_REGISTER,
110
+ source={"server": server.uri},
111
+ account=account,
112
+ object_type="server",
113
+ details=server.registration_info,
114
+ )
115
+
116
+
117
+ class JobStartConfirmationEvent(Event):
118
+ def __init__(
119
+ self,
120
+ job: "Job",
121
+ account: Any, # Use Any to avoid type resolution issues
122
+ ) -> None:
123
+ super().__init__(
124
+ type=EventType.JOB_START_CONFIRMATION,
125
+ account=account,
126
+ source={"job": job.id},
127
+ object_type="job",
128
+ details=job.registration_info,
129
+ )
130
+
131
+
132
+ class JobFinishedEvent(Event):
133
+ def __init__(self, job: "Job", account: Any) -> None:
134
+ # Check if job has responses, otherwise use the job's current status
135
+ if job.responses:
136
+ details = job.responses[-1].status
137
+ else:
138
+ details = job.status
139
+
140
+ event_type = (
141
+ EventType.JOB_END
142
+ if details == EntityStatus.COMPLETED
143
+ else EventType.JOB_ERROR
144
+ )
145
+
146
+ super().__init__(
147
+ type=event_type,
148
+ account=account,
149
+ source={"job": job.id},
150
+ object_type="job",
151
+ details=job.registration_info,
152
+ )
153
+
154
+
155
+ class CaseStartEvent(Event):
156
+ def __init__(
157
+ self, case: "Case", account: Any
158
+ ) -> None: # Use Any to avoid type resolution issues
159
+ super().__init__(
160
+ type=EventType.CASE_START,
161
+ account=account,
162
+ source={"job": case.job_id, "case": case.id},
163
+ object_type="case",
164
+ details=case.registration_info,
165
+ )
166
+
167
+
168
+ class CaseUpdateEvent(Event):
169
+ def __init__(
170
+ self,
171
+ case: "Case",
172
+ account: Any,
173
+ update: "CaseNodeUpdate",
174
+ ) -> None:
175
+ super().__init__(
176
+ type=EventType.CASE_UPDATE,
177
+ account=account,
178
+ source={"job": case.job_id, "case": case.id},
179
+ object_type="case",
180
+ details=update.registration_info,
181
+ )
@@ -0,0 +1,196 @@
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
+ # This is an example file.
8
+ # It must be copied / renamed to supervaizer_control.py
9
+ # and edited to configure your agent(s)
10
+
11
+ import os
12
+ import shortuuid
13
+ from rich.console import Console
14
+
15
+ from supervaizer import (
16
+ Agent,
17
+ AgentMethod,
18
+ AgentMethods,
19
+ Parameter,
20
+ ParametersSetup,
21
+ Server,
22
+ )
23
+ from supervaizer.account import Account
24
+
25
+ # Create a console with default style set to yellow
26
+ console = Console(style="yellow")
27
+
28
+ # Public url of your hosted agent (including port if needed)
29
+ # Use loca.lt or ngrok to get a public url during development.
30
+ # This can be setup from environment variables.
31
+ # SUPERVAIZER_HOST and SUPERVAIZER_PORT
32
+ DEV_PUBLIC_URL = "https://myagent-dev.loca.lt"
33
+ # Public url of your hosted agent
34
+ PROD_PUBLIC_URL = "https://myagent.cloud-hosting.net:8001"
35
+
36
+ # Define the parameters and secrets expected by the agent
37
+ agent_parameters: ParametersSetup | None = ParametersSetup.from_list(
38
+ [
39
+ Parameter(
40
+ name="OPEN_API_KEY",
41
+ description="OpenAPI Key",
42
+ is_environment=True,
43
+ is_secret=True,
44
+ ),
45
+ Parameter(
46
+ name="SERPER_API",
47
+ description="Server API key updated",
48
+ is_environment=True,
49
+ is_secret=True,
50
+ ),
51
+ Parameter(
52
+ name="COMPETITOR_SUMMARY_URL",
53
+ description="Competitor Summary URL",
54
+ is_environment=True,
55
+ is_secret=False,
56
+ ),
57
+ ]
58
+ )
59
+
60
+ # Define the method used to start a job
61
+ job_start_method: AgentMethod = AgentMethod(
62
+ name="start", # This is required
63
+ method="example_agent.example_synchronous_job_start", # Path to the main function in dotted notation.
64
+ is_async=False, # Only use sync methods for the moment
65
+ params={"action": "start"}, # If default parameters must be passed to the function.
66
+ fields=[
67
+ {
68
+ "name": "Company to research", # Field name - displayed in the UI
69
+ "type": str, # Python type of the field for pydantic validation - note , ChoiceField and MultipleChoiceField are a list[str]
70
+ "field_type": "CharField", # Field type for persistence.
71
+ "description": "Company to research", # Optional - Description of the field - displayed in the UI
72
+ "default": "Google", # Optional - Default value for the field
73
+ "required": True, # Whether the field is required
74
+ },
75
+ {
76
+ "name": "Max number of results",
77
+ "type": int,
78
+ "field_type": "IntegerField",
79
+ "required": True,
80
+ },
81
+ {
82
+ "name": "Subscribe to updates",
83
+ "type": bool,
84
+ "field_type": "BooleanField",
85
+ "required": False,
86
+ },
87
+ {
88
+ "name": "Type of research",
89
+ "type": str,
90
+ "field_type": "ChoiceField",
91
+ "choices": [["A", "Advanced"], ["R", "Restricted"]],
92
+ "widget": "RadioSelect",
93
+ "required": True,
94
+ },
95
+ {
96
+ "name": "Details of research",
97
+ "type": str,
98
+ "field_type": "CharField",
99
+ "widget": "Textarea",
100
+ "required": False,
101
+ },
102
+ {
103
+ "name": "List of countries",
104
+ "type": list[str],
105
+ "field_type": "MultipleChoiceField",
106
+ "choices": [
107
+ ["PA", "Panama"],
108
+ ["PG", "Papua New Guinea"],
109
+ ["PY", "Paraguay"],
110
+ ["PE", "Peru"],
111
+ ["PH", "Philippines"],
112
+ ["PN", "Pitcairn"],
113
+ ["PL", "Poland"],
114
+ ],
115
+ "required": True,
116
+ },
117
+ {
118
+ "name": "languages",
119
+ "type": list[str],
120
+ "field_type": "MultipleChoiceField",
121
+ "choices": [["en", "English"], ["fr", "French"], ["es", "Spanish"]],
122
+ "required": False,
123
+ },
124
+ ],
125
+ description="Start the collection of new competitor summary",
126
+ )
127
+
128
+ job_stop_method: AgentMethod = AgentMethod(
129
+ name="stop",
130
+ method="control.stop",
131
+ params={"action": "stop"},
132
+ description="Stop the agent",
133
+ )
134
+ job_status_method: AgentMethod = AgentMethod(
135
+ name="status",
136
+ method="hello.mystatus",
137
+ params={"status": "statusvalue"},
138
+ description="Get the status of the agent",
139
+ )
140
+ custom_method: AgentMethod = AgentMethod(
141
+ name="custom",
142
+ method="control.custom",
143
+ params={"action": "custom"},
144
+ description="Custom method",
145
+ )
146
+
147
+ custom_method2: AgentMethod = AgentMethod(
148
+ name="custom2",
149
+ method="control.custom2",
150
+ params={"action": "custom2"},
151
+ description="Custom method",
152
+ )
153
+
154
+
155
+ agent_name = "competitor_summary"
156
+
157
+ # Define the Agent
158
+ agent: Agent = Agent(
159
+ name=agent_name,
160
+ id=shortuuid.uuid(f"{agent_name}"),
161
+ author="John Doe", # Author of the agent
162
+ developer="Developer", # Developer of the controller integration
163
+ maintainer="Ive Maintained", # Maintainer of the integration
164
+ editor="DevAiExperts", # Editor (usually a company)
165
+ version="1.3", # Version string
166
+ description="This is a test agent",
167
+ tags=["testtag", "testtag2"],
168
+ methods=AgentMethods(
169
+ job_start=job_start_method,
170
+ job_stop=job_stop_method,
171
+ job_status=job_status_method,
172
+ chat=None,
173
+ custom={"custom1": custom_method, "custom2": custom_method2},
174
+ ),
175
+ parameters_setup=agent_parameters,
176
+ instructions_path="supervaize_instructions.html", # Path where instructions page is served
177
+ )
178
+
179
+ # For export purposes, use dummy values if environment variables are not set
180
+ account: Account = Account(
181
+ workspace_id=os.getenv("SUPERVAIZE_WORKSPACE_ID") or "dummy_workspace_id",
182
+ api_key=os.getenv("SUPERVAIZE_API_KEY") or "dummy_api_key",
183
+ api_url=os.getenv("SUPERVAIZE_API_URL") or "https://api.supervaize.com",
184
+ )
185
+
186
+ # Define the supervaizer server capabilities
187
+ sv_server: Server = Server(
188
+ agents=[agent],
189
+ a2a_endpoints=True, # Enable A2A endpoints
190
+ supervisor_account=account, # Account of the supervisor from Supervaize
191
+ )
192
+
193
+
194
+ if __name__ == "__main__":
195
+ # Start the supervaize server
196
+ sv_server.launch(log_level="DEBUG")