supervaizer 0.9.7__py3-none-any.whl → 0.10.0__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.
- supervaizer/__init__.py +11 -2
- supervaizer/__version__.py +1 -1
- supervaizer/account.py +4 -0
- supervaizer/account_service.py +7 -1
- supervaizer/admin/routes.py +46 -7
- supervaizer/admin/static/js/job-start-form.js +373 -0
- supervaizer/admin/templates/agents.html +74 -0
- supervaizer/admin/templates/agents_grid.html +5 -3
- supervaizer/admin/templates/job_start_test.html +109 -0
- supervaizer/admin/templates/navigation.html +11 -1
- supervaizer/admin/templates/supervaize_instructions.html +212 -0
- supervaizer/agent.py +165 -25
- supervaizer/case.py +46 -14
- supervaizer/cli.py +248 -8
- supervaizer/common.py +45 -4
- supervaizer/deploy/__init__.py +16 -0
- supervaizer/deploy/cli.py +296 -0
- supervaizer/deploy/commands/__init__.py +9 -0
- supervaizer/deploy/commands/clean.py +294 -0
- supervaizer/deploy/commands/down.py +119 -0
- supervaizer/deploy/commands/local.py +460 -0
- supervaizer/deploy/commands/plan.py +167 -0
- supervaizer/deploy/commands/status.py +169 -0
- supervaizer/deploy/commands/up.py +281 -0
- supervaizer/deploy/docker.py +370 -0
- supervaizer/deploy/driver_factory.py +42 -0
- supervaizer/deploy/drivers/__init__.py +39 -0
- supervaizer/deploy/drivers/aws_app_runner.py +607 -0
- supervaizer/deploy/drivers/base.py +196 -0
- supervaizer/deploy/drivers/cloud_run.py +570 -0
- supervaizer/deploy/drivers/do_app_platform.py +504 -0
- supervaizer/deploy/health.py +404 -0
- supervaizer/deploy/state.py +210 -0
- supervaizer/deploy/templates/Dockerfile.template +44 -0
- supervaizer/deploy/templates/debug_env.py +69 -0
- supervaizer/deploy/templates/docker-compose.yml.template +37 -0
- supervaizer/deploy/templates/dockerignore.template +66 -0
- supervaizer/deploy/templates/entrypoint.sh +20 -0
- supervaizer/deploy/utils.py +41 -0
- supervaizer/examples/{controller-template.py → controller_template.py} +5 -4
- supervaizer/job.py +18 -5
- supervaizer/job_service.py +6 -5
- supervaizer/parameter.py +61 -1
- supervaizer/protocol/__init__.py +2 -2
- supervaizer/protocol/a2a/routes.py +1 -1
- supervaizer/routes.py +262 -12
- supervaizer/server.py +5 -11
- supervaizer/utils/__init__.py +16 -0
- supervaizer/utils/version_check.py +56 -0
- {supervaizer-0.9.7.dist-info → supervaizer-0.10.0.dist-info}/METADATA +105 -34
- supervaizer-0.10.0.dist-info/RECORD +76 -0
- {supervaizer-0.9.7.dist-info → supervaizer-0.10.0.dist-info}/WHEEL +1 -1
- supervaizer/protocol/acp/__init__.py +0 -21
- supervaizer/protocol/acp/model.py +0 -198
- supervaizer/protocol/acp/routes.py +0 -74
- supervaizer-0.9.7.dist-info/RECORD +0 -50
- {supervaizer-0.9.7.dist-info → supervaizer-0.10.0.dist-info}/entry_points.txt +0 -0
- {supervaizer-0.9.7.dist-info → supervaizer-0.10.0.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,41 @@
|
|
|
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
|
+
from pathlib import Path
|
|
14
|
+
|
|
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
|
|
@@ -173,19 +173,20 @@ 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
|
|
|
179
|
+
# For export purposes, use dummy values if environment variables are not set
|
|
178
180
|
account: Account = Account(
|
|
179
|
-
workspace_id=os.getenv("SUPERVAIZE_WORKSPACE_ID")
|
|
180
|
-
api_key=os.getenv("SUPERVAIZE_API_KEY")
|
|
181
|
-
api_url=os.getenv("SUPERVAIZE_API_URL")
|
|
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",
|
|
182
184
|
)
|
|
183
185
|
|
|
184
186
|
# Define the supervaizer server capabilities
|
|
185
187
|
sv_server: Server = Server(
|
|
186
188
|
agents=[agent],
|
|
187
189
|
a2a_endpoints=True, # Enable A2A endpoints
|
|
188
|
-
acp_endpoints=True, # Enable ACP endpoints
|
|
189
190
|
supervisor_account=account, # Account of the supervisor from Supervaize
|
|
190
191
|
)
|
|
191
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,
|
|
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:
|
|
246
|
-
case_ids:
|
|
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[
|
|
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,
|
supervaizer/job_service.py
CHANGED
|
@@ -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
|
|
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(
|
|
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=
|
|
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 =
|
|
66
|
+
data = super().to_dict
|
|
67
67
|
if self.is_secret:
|
|
68
68
|
data["value"] = "********"
|
|
69
69
|
return data
|
|
@@ -171,3 +171,63 @@ class ParametersSetup(SvBaseModel):
|
|
|
171
171
|
raise ValueError(message)
|
|
172
172
|
|
|
173
173
|
return self
|
|
174
|
+
|
|
175
|
+
def validate_parameters(self, parameters: Dict[str, Any]) -> Dict[str, Any]:
|
|
176
|
+
"""Validate parameters against their expected types and return validation errors.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
parameters: Dictionary of parameter names and values to validate
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
Dictionary with validation results:
|
|
183
|
+
- "valid": bool - whether all parameters are valid
|
|
184
|
+
- "errors": List[str] - list of validation error messages
|
|
185
|
+
- "invalid_parameters": Dict[str, str] - parameter name to error message mapping
|
|
186
|
+
"""
|
|
187
|
+
errors = []
|
|
188
|
+
invalid_parameters = {}
|
|
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
|
+
|
|
202
|
+
# First check for missing required parameters
|
|
203
|
+
for param_name, param_def in self.definitions.items():
|
|
204
|
+
if param_def.is_required and param_name not in parameters:
|
|
205
|
+
error_msg = f"Required parameter '{param_name}' is missing"
|
|
206
|
+
errors.append(error_msg)
|
|
207
|
+
invalid_parameters[param_name] = error_msg
|
|
208
|
+
|
|
209
|
+
# Then validate the provided parameters
|
|
210
|
+
for param_name, param_value in parameters.items():
|
|
211
|
+
if param_name not in self.definitions:
|
|
212
|
+
error_msg = f"Unknown parameter '{param_name}'"
|
|
213
|
+
errors.append(error_msg)
|
|
214
|
+
invalid_parameters[param_name] = error_msg
|
|
215
|
+
continue
|
|
216
|
+
|
|
217
|
+
param_def = self.definitions[param_name]
|
|
218
|
+
|
|
219
|
+
# Skip validation for None values (optional parameters)
|
|
220
|
+
if param_value is None:
|
|
221
|
+
continue
|
|
222
|
+
|
|
223
|
+
# Since Parameter values are always strings, validate that input parameters are strings
|
|
224
|
+
if not isinstance(param_value, str):
|
|
225
|
+
error_msg = f"Parameter '{param_name}' must be a string, got {type(param_value).__name__}"
|
|
226
|
+
errors.append(error_msg)
|
|
227
|
+
invalid_parameters[param_name] = error_msg
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
"valid": len(errors) == 0,
|
|
231
|
+
"errors": errors,
|
|
232
|
+
"invalid_parameters": invalid_parameters,
|
|
233
|
+
}
|
supervaizer/protocol/__init__.py
CHANGED
|
@@ -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
|