chore: save current work
This commit is contained in:
@@ -1,83 +1,98 @@
|
||||
"""Real provider structured-output conformance gate for protocol v3."""
|
||||
"""Cached, role-scoped structured-output conformance checks."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from hashlib import sha256
|
||||
import json
|
||||
from typing import Any
|
||||
from typing import Any, Literal
|
||||
|
||||
from app.cad_agent.application.llm_contracts import (
|
||||
EmptyCommand,
|
||||
GeometryConclusion,
|
||||
RollbackCheckpoint,
|
||||
candidate_review_schema,
|
||||
final_review_schema,
|
||||
geometry_conclusion_schema,
|
||||
next_action_schema,
|
||||
operation_contract_request_schema,
|
||||
requirements_draft_schema,
|
||||
requirements_patch_schema,
|
||||
requirements_review_schema,
|
||||
rollback_checkpoint_schema,
|
||||
topology_request_schema,
|
||||
ImageObservation,
|
||||
RequirementsAuthorOutput,
|
||||
StatelessCandidateReview,
|
||||
StatelessGeometryConclusion,
|
||||
StatelessRollbackCheckpoint,
|
||||
StatelessTopologyRequest,
|
||||
requirements_spec_schema,
|
||||
stateless_final_review_schema,
|
||||
stateless_next_action_schema,
|
||||
)
|
||||
from app.cad_agent.domain.operation_contract import fragment_schema
|
||||
from app.cad_agent.domain.verifier_registry import default_registry
|
||||
from app.cad_agent.ports import CadRuntime, ModelGateway
|
||||
|
||||
|
||||
_CONFORMANCE_WORKING_HEAD = "cad_conformance:root:v1"
|
||||
_CONFORMANCE_REQUIREMENT_IDS = ["req_001"]
|
||||
_CONFORMANCE_CLAIM_IDS = ["claim_001"]
|
||||
_CONFORMANCE_DRAFT_IDS = ["draft_001"]
|
||||
_CONFORMANCE_SOURCE_IDS = ["src_001"]
|
||||
CapabilityRole = Literal["author", "reviewer"]
|
||||
|
||||
|
||||
def conformance_tools(runtime: CadRuntime) -> list[dict[str, Any]]:
|
||||
"""Return the complete v3 structured-output surface.
|
||||
|
||||
A provider is usable only when it can return valid arguments for every
|
||||
fixed schema and every currently registered runtime operation. This list
|
||||
intentionally derives the operation portion from the runtime registry so
|
||||
a newly exposed operation cannot bypass the capability gate.
|
||||
"""
|
||||
registry = default_registry()
|
||||
def conformance_tools(runtime: CadRuntime, *, role: CapabilityRole) -> list[dict[str, Any]]:
|
||||
if role == "reviewer":
|
||||
return [
|
||||
_tool("observe_images", ImageObservation.model_json_schema()),
|
||||
_tool("review_candidate", StatelessCandidateReview.model_json_schema()),
|
||||
_tool("review_final", stateless_final_review_schema(1)),
|
||||
]
|
||||
atomic_ids = list(runtime.supported_atomic_ids())
|
||||
tools = [
|
||||
_tool("submit_requirements_draft_batch", requirements_draft_schema(registry.expected_one_of_schema(), _CONFORMANCE_SOURCE_IDS)),
|
||||
_tool("patch_requirements_draft", requirements_patch_schema(registry.expected_one_of_schema(), _CONFORMANCE_SOURCE_IDS, _CONFORMANCE_DRAFT_IDS)),
|
||||
_tool("finalize_requirements_draft", EmptyCommand.model_json_schema()),
|
||||
_tool("review_requirements", requirements_review_schema(_CONFORMANCE_SOURCE_IDS, _CONFORMANCE_DRAFT_IDS)),
|
||||
_tool("propose_next_action", next_action_schema(_CONFORMANCE_WORKING_HEAD, _CONFORMANCE_REQUIREMENT_IDS, atomic_ids)),
|
||||
_tool("inspect_topology", topology_request_schema(_CONFORMANCE_WORKING_HEAD)),
|
||||
_tool("get_cdsl_operation_contract", operation_contract_request_schema(_CONFORMANCE_WORKING_HEAD, atomic_ids[0])),
|
||||
_tool("review_candidate", candidate_review_schema("candidate_conformance", _CONFORMANCE_WORKING_HEAD, _CONFORMANCE_CLAIM_IDS)),
|
||||
_tool("complete_task", EmptyCommand.model_json_schema()),
|
||||
_tool("review_final", final_review_schema(_CONFORMANCE_WORKING_HEAD, _CONFORMANCE_CLAIM_IDS)),
|
||||
_tool("record_geometry_conclusion", geometry_conclusion_schema(_CONFORMANCE_WORKING_HEAD, ["evidence_current_state"])),
|
||||
_tool("rollback_checkpoint", rollback_checkpoint_schema(_CONFORMANCE_WORKING_HEAD, ["checkpoint_root"])),
|
||||
]
|
||||
if not atomic_ids:
|
||||
raise RuntimeError("Runtime has no operations for conformance")
|
||||
tools = [
|
||||
_tool("submit_requirements_spec", requirements_spec_schema(default_registry().expected_one_of_schema())),
|
||||
_tool("propose_next_action", stateless_next_action_schema(atomic_ids)),
|
||||
_tool("inspect_topology", StatelessTopologyRequest.model_json_schema()),
|
||||
_tool("record_geometry_conclusion", StatelessGeometryConclusion.model_json_schema()),
|
||||
_tool("rollback_checkpoint", StatelessRollbackCheckpoint.model_json_schema()),
|
||||
_tool("complete_task", EmptyCommand.model_json_schema()),
|
||||
]
|
||||
for atomic_id in atomic_ids:
|
||||
contract = runtime.operation_contract(atomic_id)
|
||||
tools.append(_tool(f"conformance_{atomic_id}", fragment_schema(contract, selector_tokens=["sel_conformance"], reference_tokens=["ref_conformance"])))
|
||||
tools.append(_tool(
|
||||
f"conformance_{atomic_id}",
|
||||
fragment_schema(contract, selector_tokens=["sel_conformance"], reference_tokens=["ref_conformance"]),
|
||||
))
|
||||
return tools
|
||||
|
||||
|
||||
def conformance_hash(tools: list[dict[str, Any]]) -> str:
|
||||
return sha256(json.dumps(tools, ensure_ascii=True, sort_keys=True, separators=(",", ":")).encode("utf-8")).hexdigest()
|
||||
def conformance_hash(tools: list[dict[str, Any]], *, role: CapabilityRole) -> str:
|
||||
payload = {"protocol": "cad.v3.spec.v1", "role": role, "tools": tools}
|
||||
return sha256(json.dumps(payload, ensure_ascii=True, sort_keys=True, separators=(",", ":")).encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
async def verify_model_capability(repository: Any, runtime: CadRuntime, models: ModelGateway, *, provider_id: str, model_id: str, force: bool = False) -> dict[str, Any]:
|
||||
tools = conformance_tools(runtime)
|
||||
schema_hash = conformance_hash(tools)
|
||||
def cached_model_capability(
|
||||
repository: Any,
|
||||
runtime: CadRuntime,
|
||||
*,
|
||||
provider_id: str,
|
||||
model_id: str,
|
||||
role: CapabilityRole,
|
||||
) -> dict[str, Any] | None:
|
||||
tools = conformance_tools(runtime, role=role)
|
||||
schema_hash = conformance_hash(tools, role=role)
|
||||
cached = repository.model_capability(provider_id, model_id, schema_hash)
|
||||
if cached is not None and cached["supported"] and not force:
|
||||
return {"cached": True, "schema_hash": schema_hash, **cached["report"]}
|
||||
if cached is None:
|
||||
return None
|
||||
return {"cached": True, "schema_hash": schema_hash, "role": role, **cached["report"]}
|
||||
|
||||
|
||||
async def verify_model_capability(
|
||||
repository: Any,
|
||||
runtime: CadRuntime,
|
||||
models: ModelGateway,
|
||||
*,
|
||||
provider_id: str,
|
||||
model_id: str,
|
||||
role: CapabilityRole,
|
||||
force: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
tools = conformance_tools(runtime, role=role)
|
||||
schema_hash = conformance_hash(tools, role=role)
|
||||
cached = repository.model_capability(provider_id, model_id, schema_hash)
|
||||
if cached is not None and not force:
|
||||
return {"cached": True, "schema_hash": schema_hash, "role": role, **cached["report"]}
|
||||
report = await models.conformance(provider_id=provider_id, model_id=model_id, tools=tools)
|
||||
report = {"schema_hash": schema_hash, "tool_count": len(tools), **report}
|
||||
repository.record_model_capability(provider_id, model_id, schema_hash, report)
|
||||
report = {"schema_hash": schema_hash, "role": role, "tool_count": len(tools), **report}
|
||||
if not report.get("probe_unavailable"):
|
||||
repository.record_model_capability(provider_id, model_id, schema_hash, report)
|
||||
return report
|
||||
|
||||
|
||||
@@ -86,7 +101,7 @@ def _tool(name: str, parameters: dict[str, Any]) -> dict[str, Any]:
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": name,
|
||||
"description": "Structured output conformance probe. Return one schema-valid call with every required root and nested property.",
|
||||
"description": "Structured output conformance probe. Return one schema-valid call.",
|
||||
"parameters": parameters,
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user