chore: my-deepagent-seed (BudgetTracker PoC + v0.1.0 seed assets)
Pre-flight assets prepared on the main machine before the new-machine rewrite of my-deepagent in Python. - poc/: BudgetTracker + CostMiddleware + MockChatModel PoC. Validates wrap_model_call pattern, SQLite WAL + ON CONFLICT upsert, per-scope cap accounting. 5/5 pytest PASS in isolated uv venv. - schemas/: 10 personas (Anthropic Sonnet/Opus/Haiku + DeepSeek mix), 3 workflows (spec-and-review, bug-fix-with-reproduction, code-investigation), 4 artifact JSON Schemas (dev/spec@1, dev/phase-plan@1, dev/review-finding-batch@1, common/final-report@1). - schemas/validate.py: pydantic + Draft202012 cross-validation. 18/18 assets verified. - README.md: new-machine bootstrap instructions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
178
my-deepagent-seed/schemas/validate.py
Normal file
178
my-deepagent-seed/schemas/validate.py
Normal file
@@ -0,0 +1,178 @@
|
||||
"""Validate all seed assets. Run from schemas/ directory."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any, Literal
|
||||
|
||||
import jsonschema
|
||||
import yaml
|
||||
from pydantic import BaseModel, Field, ValidationError
|
||||
|
||||
|
||||
class FilesystemPermissionSpec(BaseModel):
|
||||
operations: list[Literal["read", "write", "edit", "ls"]]
|
||||
paths: list[str]
|
||||
mode: Literal["allow", "deny"] = "allow"
|
||||
|
||||
|
||||
class PersonaSubagent(BaseModel):
|
||||
name: str
|
||||
description: str
|
||||
system_prompt: str
|
||||
allowed_tools: list[str] = []
|
||||
model: str | None = None
|
||||
permissions: list[FilesystemPermissionSpec] = []
|
||||
interrupt_on: dict[str, Any] = {}
|
||||
|
||||
|
||||
class Persona(BaseModel):
|
||||
name: str
|
||||
version: int = Field(ge=1)
|
||||
description: str | None = None
|
||||
backend: Literal["openrouter", "anthropic", "openai", "google", "fake"]
|
||||
model: str
|
||||
provider_origin: str
|
||||
capabilities: list[str]
|
||||
max_risk_level: Literal["low", "medium", "high"]
|
||||
allowed_roles: list[str] | None = None
|
||||
system_prompt: str
|
||||
allowed_tools: list[str] | None = None
|
||||
subagents: list[PersonaSubagent] = []
|
||||
permissions: list[FilesystemPermissionSpec] = []
|
||||
interrupt_on: dict[str, Any] | None = None
|
||||
model_params: dict[str, Any] = {}
|
||||
deepagents_backend: Literal[
|
||||
"state", "local_shell", "filesystem", "composite", "langsmith"
|
||||
] = "local_shell"
|
||||
fallback_model: str | None = None
|
||||
max_cost_per_call_usd: float | None = None
|
||||
|
||||
|
||||
class ExpectedArtifact(BaseModel):
|
||||
path: str
|
||||
schema_: str = Field(alias="schema")
|
||||
|
||||
model_config = {"populate_by_name": True}
|
||||
|
||||
|
||||
class WorkflowPhase(BaseModel):
|
||||
key: str
|
||||
title: str
|
||||
risk: Literal["low", "medium", "high"]
|
||||
role: str
|
||||
expected_artifact: ExpectedArtifact | None = None
|
||||
gates: list[str] = []
|
||||
timeout_seconds: int | None = None
|
||||
instructions: str
|
||||
max_budget_usd: float | None = None
|
||||
|
||||
|
||||
class WorkflowRole(BaseModel):
|
||||
id: str
|
||||
required_capabilities: list[str]
|
||||
preferred_backends: list[str] = []
|
||||
fallback_personas: list[str] = []
|
||||
|
||||
|
||||
class WorkflowTemplate(BaseModel):
|
||||
name: str
|
||||
version: int = Field(ge=1)
|
||||
description: str | None = None
|
||||
roles: list[WorkflowRole]
|
||||
phases: list[WorkflowPhase]
|
||||
default_gates: list[str] = []
|
||||
max_total_budget_usd: float | None = None
|
||||
|
||||
|
||||
ROOT = Path(__file__).parent
|
||||
CAPABILITIES = {
|
||||
"spec_write",
|
||||
"phase_planning",
|
||||
"task_dag_planning",
|
||||
"code_edit",
|
||||
"test_first_development",
|
||||
"code_review",
|
||||
"evidence_check",
|
||||
"command_execute",
|
||||
"backtest_run",
|
||||
"metric_extract",
|
||||
"failure_mining",
|
||||
"objective_eval",
|
||||
"final_report_compose",
|
||||
}
|
||||
|
||||
errors: list[str] = []
|
||||
|
||||
|
||||
def validate_personas() -> int:
|
||||
count = 0
|
||||
for f in sorted((ROOT / "personas").glob("*.yaml")):
|
||||
try:
|
||||
data = yaml.safe_load(f.read_text())
|
||||
p = Persona.model_validate(data)
|
||||
unknown_caps = set(p.capabilities) - CAPABILITIES
|
||||
if unknown_caps:
|
||||
raise ValueError(f"unknown capabilities: {unknown_caps}")
|
||||
print(f" ok personas/{f.name}")
|
||||
count += 1
|
||||
except (ValidationError, ValueError, yaml.YAMLError) as e:
|
||||
errors.append(f"personas/{f.name}: {e}")
|
||||
print(f" FAIL personas/{f.name}: {e}")
|
||||
return count
|
||||
|
||||
|
||||
def validate_workflows() -> int:
|
||||
count = 0
|
||||
for f in sorted((ROOT / "workflows").glob("*.yaml")):
|
||||
try:
|
||||
data = yaml.safe_load(f.read_text())
|
||||
w = WorkflowTemplate.model_validate(data)
|
||||
role_ids = {r.id for r in w.roles}
|
||||
for ph in w.phases:
|
||||
if ph.role not in role_ids:
|
||||
raise ValueError(
|
||||
f"phase '{ph.key}' references unknown role '{ph.role}'"
|
||||
)
|
||||
print(f" ok workflows/{f.name}")
|
||||
count += 1
|
||||
except (ValidationError, ValueError, yaml.YAMLError) as e:
|
||||
errors.append(f"workflows/{f.name}: {e}")
|
||||
print(f" FAIL workflows/{f.name}: {e}")
|
||||
return count
|
||||
|
||||
|
||||
def validate_artifact_schemas() -> int:
|
||||
count = 0
|
||||
for f in sorted((ROOT / "artifacts").rglob("*.json")):
|
||||
try:
|
||||
schema = json.loads(f.read_text())
|
||||
jsonschema.Draft202012Validator.check_schema(schema)
|
||||
if "$id" not in schema:
|
||||
raise ValueError("missing $id")
|
||||
print(f" ok artifacts/{f.relative_to(ROOT / 'artifacts')}")
|
||||
count += 1
|
||||
except (
|
||||
jsonschema.exceptions.SchemaError,
|
||||
ValueError,
|
||||
json.JSONDecodeError,
|
||||
) as e:
|
||||
errors.append(f"artifacts/{f.relative_to(ROOT / 'artifacts')}: {e}")
|
||||
print(f" FAIL artifacts/{f.relative_to(ROOT / 'artifacts')}: {e}")
|
||||
return count
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Personas:")
|
||||
p_count = validate_personas()
|
||||
print("\nWorkflows:")
|
||||
w_count = validate_workflows()
|
||||
print("\nArtifact schemas:")
|
||||
a_count = validate_artifact_schemas()
|
||||
print(f"\nTotal: personas={p_count}, workflows={w_count}, artifacts={a_count}")
|
||||
if errors:
|
||||
print(f"\nERRORS: {len(errors)}")
|
||||
for e in errors:
|
||||
print(f" - {e}")
|
||||
sys.exit(1)
|
||||
print("\nAll seeds validated.")
|
||||
Reference in New Issue
Block a user