supervaizer 0.9.8__py3-none-any.whl → 0.10.1__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 (56) hide show
  1. supervaizer/__init__.py +11 -2
  2. supervaizer/__version__.py +1 -1
  3. supervaizer/account.py +4 -0
  4. supervaizer/account_service.py +7 -1
  5. supervaizer/admin/routes.py +24 -8
  6. supervaizer/admin/templates/agents.html +74 -0
  7. supervaizer/admin/templates/agents_grid.html +5 -3
  8. supervaizer/admin/templates/navigation.html +11 -1
  9. supervaizer/admin/templates/supervaize_instructions.html +212 -0
  10. supervaizer/agent.py +28 -6
  11. supervaizer/case.py +46 -14
  12. supervaizer/cli.py +247 -7
  13. supervaizer/common.py +45 -4
  14. supervaizer/deploy/__init__.py +16 -0
  15. supervaizer/deploy/cli.py +296 -0
  16. supervaizer/deploy/commands/__init__.py +9 -0
  17. supervaizer/deploy/commands/clean.py +294 -0
  18. supervaizer/deploy/commands/down.py +119 -0
  19. supervaizer/deploy/commands/local.py +460 -0
  20. supervaizer/deploy/commands/plan.py +167 -0
  21. supervaizer/deploy/commands/status.py +169 -0
  22. supervaizer/deploy/commands/up.py +281 -0
  23. supervaizer/deploy/docker.py +378 -0
  24. supervaizer/deploy/driver_factory.py +42 -0
  25. supervaizer/deploy/drivers/__init__.py +39 -0
  26. supervaizer/deploy/drivers/aws_app_runner.py +607 -0
  27. supervaizer/deploy/drivers/base.py +196 -0
  28. supervaizer/deploy/drivers/cloud_run.py +570 -0
  29. supervaizer/deploy/drivers/do_app_platform.py +504 -0
  30. supervaizer/deploy/health.py +404 -0
  31. supervaizer/deploy/state.py +210 -0
  32. supervaizer/deploy/templates/Dockerfile.template +44 -0
  33. supervaizer/deploy/templates/debug_env.py +69 -0
  34. supervaizer/deploy/templates/docker-compose.yml.template +37 -0
  35. supervaizer/deploy/templates/dockerignore.template +66 -0
  36. supervaizer/deploy/templates/entrypoint.sh +20 -0
  37. supervaizer/deploy/utils.py +52 -0
  38. supervaizer/examples/controller_template.py +1 -1
  39. supervaizer/job.py +18 -5
  40. supervaizer/job_service.py +6 -5
  41. supervaizer/parameter.py +13 -1
  42. supervaizer/protocol/__init__.py +2 -2
  43. supervaizer/protocol/a2a/routes.py +1 -1
  44. supervaizer/routes.py +141 -17
  45. supervaizer/server.py +5 -11
  46. supervaizer/utils/__init__.py +16 -0
  47. supervaizer/utils/version_check.py +56 -0
  48. {supervaizer-0.9.8.dist-info → supervaizer-0.10.1.dist-info}/METADATA +105 -34
  49. supervaizer-0.10.1.dist-info/RECORD +76 -0
  50. {supervaizer-0.9.8.dist-info → supervaizer-0.10.1.dist-info}/WHEEL +1 -1
  51. supervaizer/protocol/acp/__init__.py +0 -21
  52. supervaizer/protocol/acp/model.py +0 -198
  53. supervaizer/protocol/acp/routes.py +0 -74
  54. supervaizer-0.9.8.dist-info/RECORD +0 -52
  55. {supervaizer-0.9.8.dist-info → supervaizer-0.10.1.dist-info}/entry_points.txt +0 -0
  56. {supervaizer-0.9.8.dist-info → supervaizer-0.10.1.dist-info}/licenses/LICENSE.md +0 -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"
@@ -173,6 +173,7 @@ agent: Agent = Agent(
173
173
  custom={"custom1": custom_method, "custom2": custom_method2},
174
174
  ),
175
175
  parameters_setup=agent_parameters,
176
+ instructions_path="supervaize_instructions.html", # Path where instructions page is served
176
177
  )
177
178
 
178
179
  # For export purposes, use dummy values if environment variables are not set
@@ -186,7 +187,6 @@ account: Account = Account(
186
187
  sv_server: Server = Server(
187
188
  agents=[agent],
188
189
  a2a_endpoints=True, # Enable A2A endpoints
189
- acp_endpoints=True, # Enable ACP endpoints
190
190
  supervisor_account=account, # Account of the supervisor from Supervaize
191
191
  )
192
192
 
supervaizer/job.py CHANGED
@@ -8,7 +8,7 @@ import time
8
8
  import traceback
9
9
  import uuid
10
10
  from datetime import datetime
11
- from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional
11
+ from typing import TYPE_CHECKING, Any, ClassVar, Dict, Optional
12
12
 
13
13
  from supervaizer.__version__ import VERSION
14
14
  from supervaizer.common import SvBaseModel, log, singleton
@@ -242,8 +242,8 @@ class AbstractJob(SvBaseModel):
242
242
  responses: list["JobResponse"] = []
243
243
  finished_at: datetime | None = None
244
244
  created_at: datetime | None = None
245
- agent_parameters: List[dict[str, Any]] | None = None
246
- case_ids: List[str] = [] # Foreign key relationship to cases
245
+ agent_parameters: list[dict[str, Any]] | None = None
246
+ case_ids: list[str] = [] # Foreign key relationship to cases
247
247
 
248
248
 
249
249
  class Job(AbstractJob):
@@ -344,7 +344,7 @@ class Job(AbstractJob):
344
344
  cls,
345
345
  job_context: "JobContext",
346
346
  agent_name: str,
347
- agent_parameters: Optional[List[dict[str, Any]]] = None,
347
+ agent_parameters: Optional[list[dict[str, Any]]] = None,
348
348
  name: Optional[str] = None,
349
349
  ) -> "Job":
350
350
  """Create a new job
@@ -352,7 +352,7 @@ class Job(AbstractJob):
352
352
  Args:
353
353
  job_context (JobContext): The context of the job
354
354
  agent_name (str): The name of the agent
355
- agent_parameters (dict[str, Any] | None): Optional parameters for the job
355
+ agent_parameters (list[dict[str, Any]] | None): Optional parameters for the job
356
356
  name (str | None): Optional name for the job, defaults to mission name if not provided
357
357
 
358
358
  Returns:
@@ -362,6 +362,19 @@ class Job(AbstractJob):
362
362
  # Use provided name or fallback to mission name from context
363
363
  job_name = name or job_context.mission_name
364
364
 
365
+ # Ensure agent_parameters is a list of dicts, not nested incorrectly
366
+ if agent_parameters is not None:
367
+ # If it's a list but the first element is also a list, unwrap it
368
+ if isinstance(agent_parameters, list) and len(agent_parameters) > 0:
369
+ if isinstance(agent_parameters[0], list):
370
+ # Unwrap nested list: [[{...}, {...}]] -> [{...}, {...}]
371
+ agent_parameters = agent_parameters[0]
372
+ # Ensure all elements are dicts
373
+ if not all(isinstance(p, dict) for p in agent_parameters):
374
+ raise ValueError(
375
+ f"agent_parameters must be a list of dictionaries, got: {type(agent_parameters)}"
376
+ )
377
+
365
378
  job = cls(
366
379
  id=job_id,
367
380
  name=job_name,
@@ -7,7 +7,6 @@
7
7
  import json
8
8
  from typing import TYPE_CHECKING, Any, Dict, Optional
9
9
 
10
- from rich import inspect
11
10
 
12
11
  from supervaizer.common import decrypt_value, log
13
12
  from supervaizer.event import JobFinishedEvent
@@ -44,7 +43,7 @@ async def service_job_start(
44
43
  Returns:
45
44
  The created job
46
45
  """
47
- agent_parameters: dict[str, Any] | None = None
46
+ agent_parameters = None
48
47
  # If agent has parameters_setup defined, validate parameters
49
48
  if getattr(agent, "parameters_setup") and encrypted_agent_parameters:
50
49
  agent_parameters_str = decrypt_value(
@@ -54,14 +53,16 @@ async def service_job_start(
54
53
  json.loads(agent_parameters_str) if agent_parameters_str else None
55
54
  )
56
55
 
57
- inspect(agent)
58
- log.debug(f"[Decrypted parameters] : parameters = {agent_parameters}")
56
+ # inspect(agent)
57
+ log.debug(
58
+ f"[service_job_start Decrypted parameters] : parameters = {agent_parameters}"
59
+ )
59
60
 
60
61
  # Create and prepare the job
61
62
  new_saas_job = Job.new(
62
63
  job_context=sv_context,
63
64
  agent_name=agent.name,
64
- agent_parameters=[agent_parameters] if agent_parameters else None,
65
+ agent_parameters=agent_parameters,
65
66
  name=sv_context.job_id,
66
67
  )
67
68
 
supervaizer/parameter.py CHANGED
@@ -63,7 +63,7 @@ class Parameter(ParameterAbstract):
63
63
  """
64
64
  Override the to_dict method to handle the value field.
65
65
  """
66
- data = self.model_dump(mode="json")
66
+ data = super().to_dict
67
67
  if self.is_secret:
68
68
  data["value"] = "********"
69
69
  return data
@@ -187,6 +187,18 @@ class ParametersSetup(SvBaseModel):
187
187
  errors = []
188
188
  invalid_parameters = {}
189
189
 
190
+ # Ensure parameters is a dictionary
191
+ if not isinstance(parameters, dict):
192
+ error_msg = (
193
+ f"Parameters must be a dictionary, got {type(parameters).__name__}"
194
+ )
195
+ errors.append(error_msg)
196
+ return {
197
+ "valid": False,
198
+ "errors": errors,
199
+ "invalid_parameters": {"parameters": error_msg},
200
+ }
201
+
190
202
  # First check for missing required parameters
191
203
  for param_name, param_def in self.definitions.items():
192
204
  if param_def.is_required and param_name not in parameters:
@@ -6,6 +6,6 @@
6
6
 
7
7
  """Protocol implementations for SUPERVAIZER."""
8
8
 
9
- from supervaizer.protocol import a2a, acp
9
+ from supervaizer.protocol import a2a
10
10
 
11
- __all__ = ["a2a", "acp"]
11
+ __all__ = ["a2a"]
@@ -48,7 +48,7 @@ def create_routes(server: "Server") -> APIRouter:
48
48
  @handle_route_errors()
49
49
  async def get_health() -> Dict[str, Any]:
50
50
  """Get health information for the server and all agents."""
51
- log.debug("[A2A] GET /.well-known/health [Health status]")
51
+ # log.debug("[A2A] GET /.well-known/health [Health status]")
52
52
  return create_health_data(server.agents)
53
53
 
54
54
  # Create explicit routes for each agent in the versioned format