|
|
@@ -8,9 +8,9 @@ import json
|
|
|
from functools import wraps
|
|
|
from typing import Any
|
|
|
|
|
|
+from agent import FailureDetail, FailureDisposition, ToolExecutionError, ToolRegistry
|
|
|
from agent.tools.models import ToolResult
|
|
|
|
|
|
-from agent import FailureDetail, FailureDisposition, ToolExecutionError, ToolRegistry
|
|
|
from script_build_host.domain.errors import ScriptBuildError
|
|
|
|
|
|
from .failures import classify_script_tool_failure
|
|
|
@@ -85,7 +85,7 @@ def register_script_tools(registry: ToolRegistry, gateway: LegacyScriptToolGatew
|
|
|
parent_task_id: str | None = None,
|
|
|
context: dict[str, Any] | None = None,
|
|
|
) -> str | ToolResult:
|
|
|
- """Validate and atomically create Tasks from complete business contracts."""
|
|
|
+ """Resolve Planner-owned semantics and atomically create Tasks."""
|
|
|
|
|
|
contracts = _structured_object_list(contracts, "contracts", max_items=50)
|
|
|
return _json(
|
|
|
@@ -110,6 +110,7 @@ def register_script_tools(registry: ToolRegistry, gateway: LegacyScriptToolGatew
|
|
|
validation_id: str | None = None,
|
|
|
replacement_contract: dict[str, Any] | None = None,
|
|
|
child_contracts: list[dict[str, Any]] | None = None,
|
|
|
+ selected_decision_ids: list[str] | None = None,
|
|
|
context: dict[str, Any] | None = None,
|
|
|
) -> str | ToolResult:
|
|
|
"""Apply one phase-aware Planner decision after contract and boundary checks."""
|
|
|
@@ -137,6 +138,7 @@ def register_script_tools(registry: ToolRegistry, gateway: LegacyScriptToolGatew
|
|
|
validation_id=validation_id,
|
|
|
replacement_contract=replacement_contract,
|
|
|
child_contracts=child_contracts,
|
|
|
+ selected_decision_ids=selected_decision_ids or [],
|
|
|
context=context or {},
|
|
|
)
|
|
|
result_json = _json(result)
|
|
|
@@ -879,15 +881,15 @@ def _plan_script_tasks_schema() -> dict[str, Any]:
|
|
|
"function": {
|
|
|
"name": "plan_script_tasks",
|
|
|
"description": (
|
|
|
- "Create bounded Tasks. Every contracts item must be a complete "
|
|
|
- "script-task-contract/v1 object; do not send preset or display fields."
|
|
|
+ "Create bounded Tasks from business semantics and accepted Decision IDs. "
|
|
|
+ "The Host derives artifact refs, digests, write scope, schema and budget."
|
|
|
),
|
|
|
"parameters": {
|
|
|
"type": "object",
|
|
|
"properties": {
|
|
|
"contracts": {
|
|
|
"type": "array",
|
|
|
- "items": _task_contract_schema(),
|
|
|
+ "items": _planner_task_input_schema(),
|
|
|
"minItems": 1,
|
|
|
"maxItems": 50,
|
|
|
},
|
|
|
@@ -906,8 +908,8 @@ def _decide_script_task_schema() -> dict[str, Any]:
|
|
|
"function": {
|
|
|
"name": "decide_script_task",
|
|
|
"description": (
|
|
|
- "Apply one validated Planner decision. Replacement and child contracts, "
|
|
|
- "when required by the action, must be complete script-task-contract/v1 objects."
|
|
|
+ "Apply one Planner decision. Use selected_decision_ids to close Compose or "
|
|
|
+ "Portfolio; the Host derives every immutable adoption field."
|
|
|
),
|
|
|
"parameters": {
|
|
|
"type": "object",
|
|
|
@@ -929,15 +931,25 @@ def _decide_script_task_schema() -> dict[str, Any]:
|
|
|
"reason": {"type": "string"},
|
|
|
"validation_id": {"type": ["string", "null"], "default": None},
|
|
|
"replacement_contract": {
|
|
|
- "oneOf": [_task_contract_schema(), {"type": "null"}],
|
|
|
+ "oneOf": [
|
|
|
+ _planner_task_input_schema(),
|
|
|
+ _root_replacement_schema(),
|
|
|
+ {"type": "null"},
|
|
|
+ ],
|
|
|
"default": None,
|
|
|
},
|
|
|
"child_contracts": {
|
|
|
"type": "array",
|
|
|
- "items": _task_contract_schema(),
|
|
|
+ "items": _planner_task_input_schema(),
|
|
|
"maxItems": 50,
|
|
|
"default": [],
|
|
|
},
|
|
|
+ "selected_decision_ids": {
|
|
|
+ "type": "array",
|
|
|
+ "items": {"type": "string"},
|
|
|
+ "uniqueItems": True,
|
|
|
+ "default": [],
|
|
|
+ },
|
|
|
},
|
|
|
"required": ["task_id", "action", "reason"],
|
|
|
"additionalProperties": False,
|
|
|
@@ -946,7 +958,7 @@ def _decide_script_task_schema() -> dict[str, Any]:
|
|
|
}
|
|
|
|
|
|
|
|
|
-def _task_contract_schema() -> dict[str, Any]:
|
|
|
+def _planner_task_input_schema() -> dict[str, Any]:
|
|
|
task_kinds = [
|
|
|
"direction",
|
|
|
"pattern-retrieval",
|
|
|
@@ -960,40 +972,9 @@ def _task_contract_schema() -> dict[str, Any]:
|
|
|
"compose",
|
|
|
"candidate-portfolio",
|
|
|
]
|
|
|
- artifact_ref = {
|
|
|
- "type": "object",
|
|
|
- "properties": {
|
|
|
- "uri": {"type": "string"},
|
|
|
- "kind": {"type": "string"},
|
|
|
- "version": {"type": ["string", "null"]},
|
|
|
- "digest": {"type": ["string", "null"]},
|
|
|
- "summary": {"type": ["string", "null"]},
|
|
|
- "metadata": {"type": "object"},
|
|
|
- },
|
|
|
- "required": ["uri", "kind"],
|
|
|
- "additionalProperties": False,
|
|
|
- }
|
|
|
- decision_ref = {
|
|
|
- "type": "object",
|
|
|
- "properties": {
|
|
|
- "decision_id": {"type": "string"},
|
|
|
- "artifact_ref": artifact_ref,
|
|
|
- "scope_ref": {
|
|
|
- "type": "string",
|
|
|
- "description": "A script-build:// control URI from the accepted decision.",
|
|
|
- },
|
|
|
- "expected_task_kind": {"type": "string", "enum": task_kinds},
|
|
|
- },
|
|
|
- "required": ["decision_id", "artifact_ref", "scope_ref", "expected_task_kind"],
|
|
|
- "additionalProperties": False,
|
|
|
- }
|
|
|
return {
|
|
|
"type": "object",
|
|
|
"properties": {
|
|
|
- "schema_version": {
|
|
|
- "type": "string",
|
|
|
- "const": "script-task-contract/v1",
|
|
|
- },
|
|
|
"task_kind": {"type": "string", "enum": task_kinds},
|
|
|
"scope_ref": {
|
|
|
"type": "string",
|
|
|
@@ -1012,34 +993,26 @@ def _task_contract_schema() -> dict[str, Any]:
|
|
|
],
|
|
|
},
|
|
|
"objective": {"type": "string", "maxLength": 2000},
|
|
|
- "input_decision_refs": {"type": "array", "items": decision_ref},
|
|
|
- "base_artifact_ref": {
|
|
|
- "oneOf": [artifact_ref, {"type": "null"}],
|
|
|
+ "input_decision_ids": {
|
|
|
+ "type": "array",
|
|
|
+ "items": {"type": "string"},
|
|
|
+ "uniqueItems": True,
|
|
|
+ "default": [],
|
|
|
},
|
|
|
- "write_scope": {
|
|
|
+ "base_decision_id": {"type": ["string", "null"], "default": None},
|
|
|
+ "comparison_decision_ids": {
|
|
|
"type": "array",
|
|
|
- "items": {
|
|
|
- "type": "string",
|
|
|
- "description": "A bounded script-build:// control URI.",
|
|
|
- },
|
|
|
+ "items": {"type": "string"},
|
|
|
+ "uniqueItems": True,
|
|
|
+ "default": [],
|
|
|
},
|
|
|
- "gap_ref": {"type": ["string", "null"]},
|
|
|
- "output_schema": {
|
|
|
- "type": "string",
|
|
|
- "enum": [
|
|
|
- "script-direction/v1",
|
|
|
- "evidence-record/v1",
|
|
|
- "structure-artifact/v1",
|
|
|
- "paragraph-artifact/v1",
|
|
|
- "paragraph-patch/v1",
|
|
|
- "element-set-artifact/v1",
|
|
|
- "element-set-patch/v1",
|
|
|
- "comparison-artifact/v1",
|
|
|
- "structured-script/v1",
|
|
|
- "candidate-portfolio/v1",
|
|
|
- ],
|
|
|
- "description": "Must match task_kind; use evidence-record/v1 for retrieval.",
|
|
|
+ "supersedes_decision_ids": {
|
|
|
+ "type": "array",
|
|
|
+ "items": {"type": "string"},
|
|
|
+ "uniqueItems": True,
|
|
|
+ "default": [],
|
|
|
},
|
|
|
+ "gap_ref": {"type": ["string", "null"]},
|
|
|
"criteria": {
|
|
|
"type": "array",
|
|
|
"minItems": 1,
|
|
|
@@ -1055,36 +1028,6 @@ def _task_contract_schema() -> dict[str, Any]:
|
|
|
"additionalProperties": False,
|
|
|
},
|
|
|
},
|
|
|
- "budget": {
|
|
|
- "type": "object",
|
|
|
- "properties": {
|
|
|
- "max_attempts": {"type": "integer", "minimum": 1, "maximum": 4},
|
|
|
- "max_tokens": {
|
|
|
- "type": "integer",
|
|
|
- "minimum": 500000,
|
|
|
- "maximum": 1000000,
|
|
|
- },
|
|
|
- "max_seconds": {"type": "integer", "minimum": 1, "maximum": 900},
|
|
|
- "max_external_queries": {
|
|
|
- "type": "integer",
|
|
|
- "minimum": 1,
|
|
|
- "maximum": 40,
|
|
|
- },
|
|
|
- "max_no_improvement": {
|
|
|
- "type": "integer",
|
|
|
- "minimum": 1,
|
|
|
- "maximum": 3,
|
|
|
- },
|
|
|
- },
|
|
|
- "required": [
|
|
|
- "max_attempts",
|
|
|
- "max_tokens",
|
|
|
- "max_seconds",
|
|
|
- "max_external_queries",
|
|
|
- "max_no_improvement",
|
|
|
- ],
|
|
|
- "additionalProperties": False,
|
|
|
- },
|
|
|
"goal_ids": {
|
|
|
"type": "array",
|
|
|
"maxItems": 30,
|
|
|
@@ -1095,41 +1038,33 @@ def _task_contract_schema() -> dict[str, Any]:
|
|
|
"by this Task. Compose and Portfolio include every Goal."
|
|
|
),
|
|
|
},
|
|
|
- "supersedes_decision_ids": {"type": "array", "items": {"type": "string"}},
|
|
|
- "candidate_closure_decision_refs": {"type": "array", "items": decision_ref},
|
|
|
- "adopted_decision_ids": {"type": "array", "items": {"type": "string"}},
|
|
|
- "held_or_rejected_decision_ids": {
|
|
|
- "type": "array",
|
|
|
- "items": {"type": "string"},
|
|
|
- },
|
|
|
- "compose_order": {"type": "array", "items": {"type": "string"}},
|
|
|
- "comparison_decision_refs": {"type": "array", "items": decision_ref},
|
|
|
},
|
|
|
"required": [
|
|
|
- "schema_version",
|
|
|
"task_kind",
|
|
|
"scope_ref",
|
|
|
"intent_class",
|
|
|
"objective",
|
|
|
- "input_decision_refs",
|
|
|
- "base_artifact_ref",
|
|
|
- "write_scope",
|
|
|
- "gap_ref",
|
|
|
- "output_schema",
|
|
|
"criteria",
|
|
|
- "budget",
|
|
|
"goal_ids",
|
|
|
- "supersedes_decision_ids",
|
|
|
- "candidate_closure_decision_refs",
|
|
|
- "adopted_decision_ids",
|
|
|
- "held_or_rejected_decision_ids",
|
|
|
- "compose_order",
|
|
|
- "comparison_decision_refs",
|
|
|
+ "input_decision_ids",
|
|
|
],
|
|
|
"additionalProperties": False,
|
|
|
}
|
|
|
|
|
|
|
|
|
+def _root_replacement_schema() -> dict[str, Any]:
|
|
|
+ return {
|
|
|
+ "type": "object",
|
|
|
+ "properties": {
|
|
|
+ "objective": {"type": "string", "maxLength": 2000},
|
|
|
+ "acceptance_criteria": {"type": "array", "items": {"type": "object"}},
|
|
|
+ "context_refs": {"type": "array", "items": {"type": "string"}},
|
|
|
+ },
|
|
|
+ "required": ["objective", "acceptance_criteria", "context_refs"],
|
|
|
+ "additionalProperties": False,
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
def _save_direction_candidate_schema() -> dict[str, Any]:
|
|
|
constraint = {
|
|
|
"type": "object",
|
|
|
@@ -1170,8 +1105,12 @@ def _save_direction_candidate_schema() -> dict[str, Any]:
|
|
|
"items": {
|
|
|
"type": "object",
|
|
|
"properties": {
|
|
|
- "goal_id": {"type": "string", "minLength": 1},
|
|
|
- "parent_goal_id": {"type": "string", "minLength": 1},
|
|
|
+ "client_key": {"type": "string", "minLength": 1, "maxLength": 128},
|
|
|
+ "parent_client_key": {
|
|
|
+ "type": ["string", "null"],
|
|
|
+ "minLength": 1,
|
|
|
+ "maxLength": 128,
|
|
|
+ },
|
|
|
"statement": {"type": "string", "minLength": 1},
|
|
|
"rationale": {"type": "string", "minLength": 1},
|
|
|
"success_criteria": {
|
|
|
@@ -1182,7 +1121,7 @@ def _save_direction_candidate_schema() -> dict[str, Any]:
|
|
|
},
|
|
|
},
|
|
|
"required": [
|
|
|
- "goal_id",
|
|
|
+ "client_key",
|
|
|
"statement",
|
|
|
"rationale",
|
|
|
"success_criteria",
|
|
|
@@ -1290,8 +1229,18 @@ def _submit_validation_schema() -> dict[str, Any]:
|
|
|
"enum": ["passed", "failed", "inconclusive"],
|
|
|
},
|
|
|
"reason": {"type": "string", "maxLength": 300},
|
|
|
+ "evidence_refs": {
|
|
|
+ "type": "array",
|
|
|
+ "items": artifact_ref,
|
|
|
+ "maxItems": 64,
|
|
|
+ },
|
|
|
},
|
|
|
- "required": ["criterion_id", "verdict", "reason"],
|
|
|
+ "required": [
|
|
|
+ "criterion_id",
|
|
|
+ "verdict",
|
|
|
+ "reason",
|
|
|
+ "evidence_refs",
|
|
|
+ ],
|
|
|
"additionalProperties": False,
|
|
|
},
|
|
|
},
|