Browse Source

角色:注册动态创作 Worker 与四层候选验证提示词

SamLee 1 day ago
parent
commit
cb515c80e1

+ 102 - 11
script_build_host/src/script_build_host/agents/presets.py

@@ -1,4 +1,4 @@
-"""Exact phase-one preset allowlists."""
+"""Exact Phase1/Phase2 preset allowlists."""
 
 from __future__ import annotations
 
@@ -6,11 +6,17 @@ from agent import AgentPreset, AgentRole
 from agent.core.presets import register_preset
 
 from .prompts import (
+    COMPARISON_WORKER_PROMPT,
+    COMPOSE_WORKER_PROMPT,
     DIRECTION_WORKER_PROMPT,
+    ELEMENT_SET_WORKER_PROMPT,
+    PARAGRAPH_WORKER_PROMPT,
     PLANNER_PROMPT,
+    PORTFOLIO_WORKER_PROMPT,
     RETRIEVAL_VALIDATOR_PROMPT,
     RETRIEVAL_WORKER_PROMPT,
     SCRIPT_CANDIDATE_VALIDATOR_PROMPT,
+    STRUCTURE_WORKER_PROMPT,
 )
 
 _FORBIDDEN = [
@@ -22,23 +28,33 @@ _FORBIDDEN = [
     "edit_file",
     "bash_command",
     "dispatch_tasks",
+    "task_plan",
+    "task_decide",
+    "begin_round",
+    "merge_branch",
+    "multipath",
+    "web_search",
+    "web_fetch",
+    "http_request",
 ]
 
 
-def _worker(tools: list[str], *, direction: bool = False) -> AgentPreset:
+def _worker(tools: list[str], *, prompt: str = RETRIEVAL_WORKER_PROMPT) -> AgentPreset:
     return AgentPreset(
         role=AgentRole.WORKER,
-        allowed_tools=[*tools, "submit_attempt"],
+        allowed_tools=list(dict.fromkeys([*tools, "submit_attempt"])),
         denied_tools=[
             *_FORBIDDEN,
-            "task_plan",
-            "task_decide",
+            "plan_script_tasks",
+            "decide_script_task",
+            "inspect_script_plan",
+            "dispatch_script_tasks",
             "validate_attempt",
             "submit_validation",
         ],
         max_iterations=20,
         skills=[],
-        system_prompt=DIRECTION_WORKER_PROMPT if direction else RETRIEVAL_WORKER_PROMPT,
+        system_prompt=prompt,
     )
 
 
@@ -54,9 +70,10 @@ def register_script_presets() -> None:
         AgentPreset(
             role=AgentRole.PLANNER,
             allowed_tools=[
-                "task_plan",
+                "plan_script_tasks",
+                "decide_script_task",
+                "inspect_script_plan",
                 "dispatch_script_tasks",
-                "task_decide",
                 "validate_attempt",
                 "read_input_snapshot",
             ],
@@ -86,20 +103,94 @@ def register_script_presets() -> None:
         "script_direction_worker",
         _worker(
             ["read_input_snapshot", "read_accepted_artifact", "save_direction_candidate"],
-            direction=True,
+            prompt=DIRECTION_WORKER_PROMPT,
+        ),
+    )
+    paragraph_writes = [
+        "read_attempt_workspace",
+        "create_script_paragraph",
+        "append_paragraph_atoms",
+        "delete_paragraph_atom",
+        "batch_update_script_paragraphs",
+    ]
+    element_writes = [
+        "read_attempt_workspace",
+        "create_script_element",
+        "update_script_element",
+        "batch_link_paragraph_elements",
+        "delete_paragraph_element_links",
+    ]
+    common_candidate_reads = [
+        "read_input_snapshot",
+        "load_frozen_strategy",
+        "read_accepted_input_bundle",
+        "view_frozen_images",
+    ]
+    register_preset(
+        "script_structure_worker",
+        _worker(
+            [*common_candidate_reads, *paragraph_writes],
+            prompt=STRUCTURE_WORKER_PROMPT,
+        ),
+    )
+    register_preset(
+        "script_paragraph_worker",
+        _worker(
+            [*common_candidate_reads, *paragraph_writes],
+            prompt=PARAGRAPH_WORKER_PROMPT,
+        ),
+    )
+    register_preset(
+        "script_element_set_worker",
+        _worker(
+            [*common_candidate_reads, *element_writes],
+            prompt=ELEMENT_SET_WORKER_PROMPT,
+        ),
+    )
+    register_preset(
+        "script_candidate_compare_worker",
+        _worker(
+            ["read_input_snapshot", "read_pinned_candidates", "save_comparison_candidate"],
+            prompt=COMPARISON_WORKER_PROMPT,
+        ),
+    )
+    register_preset(
+        "script_compose_worker",
+        _worker(
+            [
+                "read_input_snapshot",
+                "read_active_frontier",
+                *paragraph_writes,
+                *element_writes,
+                "save_structured_script_candidate",
+            ],
+            prompt=COMPOSE_WORKER_PROMPT,
+        ),
+    )
+    register_preset(
+        "script_candidate_portfolio_worker",
+        _worker(
+            [
+                "read_input_snapshot",
+                "read_pinned_candidates",
+                "save_candidate_portfolio",
+            ],
+            prompt=PORTFOLIO_WORKER_PROMPT,
         ),
     )
     validator_tools = [
         "read_input_snapshot",
+        "view_frozen_images",
         "query_validation_evidence",
         "deterministic_precheck",
         "submit_validation",
     ]
     validator_denied = [
         *_FORBIDDEN,
-        "task_plan",
+        "plan_script_tasks",
         "dispatch_script_tasks",
-        "task_decide",
+        "decide_script_task",
+        "inspect_script_plan",
         "validate_attempt",
         "submit_attempt",
         "save_direction_candidate",

+ 14 - 0
script_build_host/src/script_build_host/agents/prompts/__init__.py

@@ -1,19 +1,33 @@
 """Immutable prompt contracts used by script-build presets."""
 
 from .contracts import (
+    COMPARISON_WORKER_PROMPT,
+    COMPOSE_WORKER_PROMPT,
     DIRECTION_WORKER_PROMPT,
+    ELEMENT_SET_WORKER_PROMPT,
+    PARAGRAPH_WORKER_PROMPT,
     PLANNER_PROMPT,
+    PORTFOLIO_WORKER_PROMPT,
     RETRIEVAL_VALIDATOR_PROMPT,
     RETRIEVAL_WORKER_PROMPT,
     SCRIPT_CANDIDATE_VALIDATOR_PROMPT,
+    STRUCTURE_WORKER_PROMPT,
     phase_one_prompt_manifest,
+    script_build_prompt_manifest,
 )
 
 __all__ = [
+    "COMPARISON_WORKER_PROMPT",
+    "COMPOSE_WORKER_PROMPT",
     "DIRECTION_WORKER_PROMPT",
+    "ELEMENT_SET_WORKER_PROMPT",
+    "PARAGRAPH_WORKER_PROMPT",
     "PLANNER_PROMPT",
+    "PORTFOLIO_WORKER_PROMPT",
     "RETRIEVAL_VALIDATOR_PROMPT",
     "RETRIEVAL_WORKER_PROMPT",
     "SCRIPT_CANDIDATE_VALIDATOR_PROMPT",
+    "STRUCTURE_WORKER_PROMPT",
     "phase_one_prompt_manifest",
+    "script_build_prompt_manifest",
 ]

+ 9 - 4
script_build_host/src/script_build_host/agents/prompts/candidate_validator.md

@@ -1,4 +1,9 @@
-Independently validate the frozen direction candidate. Check schema and digest,
-topic grounding, persona and strategy grounding, accepted evidence closure,
-and whether each direction goal is actionable and testable. Use only protected
-read tools and submit exactly one validation report. Never publish or mutate.
+Independently validate the frozen Direction or Phase2 candidate against every
+criterion. First run deterministic ownership, digest, schema, link, base,
+write-scope and placeholder checks. For local candidates report exact field
+paths, real excerpts and evidence; for Compare check symmetric evidence and
+real differences; for StructuredScript recheck global narrative, repetition,
+pace, conflicts, persona and realized content; for Portfolio check governance
+closure and zero hard or critical unresolved defects. Submit structured
+ScriptDefectV1 items with bounded excerpts. Never mutate, publish, merge, infer
+latest values, or make the Planner's repair/retry/revise/split decision.

+ 8 - 0
script_build_host/src/script_build_host/agents/prompts/comparison_worker.md

@@ -0,0 +1,8 @@
+Compare only the immutable candidates pinned by this Task contract. Evaluate
+each declared criterion symmetrically, identify real differences and possible
+composition conflicts, and freeze one ComparisonArtifactV1. Each criterion
+result must contain a unique criterion_id plus candidate_results covering every
+pinned artifact_ref exactly once with a concrete reason. recommendation must
+be the immutable artifact URI selected by the comparison. Do not rewrite,
+merge, rank by completion time, or fetch a latest candidate. The Planner alone
+decides which result is adopted, replaced, held, or rejected.

+ 7 - 0
script_build_host/src/script_build_host/agents/prompts/compose_worker.md

@@ -0,0 +1,7 @@
+Compose exactly the execution-ready candidate closure frozen in this Task
+contract. Read candidates only through read_active_frontier and apply the
+declared compose_order, never Task creation or completion order. Materialize a
+complete script in this Attempt workspace, close Paragraph/Element/Link
+references, freeze one StructuredScriptArtifactV1, and submit it. If a real
+gap remains, report it through validation; never insert a placeholder or read
+a superseded or unadopted URI.

+ 79 - 9
script_build_host/src/script_build_host/agents/prompts/contracts.py

@@ -1,13 +1,12 @@
-"""Role contracts for the phase-one script-build mission.
+"""Frozen role contracts for the phase-aware script-build mission.
 
 The prompts describe capabilities rather than a fixed workflow.  Identity and
 ownership are enforced by protected tool context, not by prompt text.
 """
 
+from hashlib import sha256
 from pathlib import Path
 
-from script_build_host.infrastructure.canonical_json import canonical_sha256
-
 _ROOT = Path(__file__).resolve().parent
 
 
@@ -20,41 +19,96 @@ RETRIEVAL_WORKER_PROMPT = _read("retrieval_worker.md")
 DIRECTION_WORKER_PROMPT = _read("direction_worker.md")
 RETRIEVAL_VALIDATOR_PROMPT = _read("retrieval_validator.md")
 SCRIPT_CANDIDATE_VALIDATOR_PROMPT = _read("candidate_validator.md")
+STRUCTURE_WORKER_PROMPT = _read("structure_worker.md")
+PARAGRAPH_WORKER_PROMPT = _read("paragraph_worker.md")
+ELEMENT_SET_WORKER_PROMPT = _read("element_set_worker.md")
+COMPARISON_WORKER_PROMPT = _read("comparison_worker.md")
+COMPOSE_WORKER_PROMPT = _read("compose_worker.md")
+PORTFOLIO_WORKER_PROMPT = _read("portfolio_worker.md")
 
 
-def phase_one_prompt_manifest() -> tuple[dict[str, object], ...]:
+def script_build_prompt_manifest() -> tuple[dict[str, object], ...]:
+    """Return every Prompt a new Phase1+Phase2 InputSnapshot must freeze."""
+
     values = {
-        "script_planner": ("planner", "script_planner.md", PLANNER_PROMPT),
-        "script_direction_worker": ("worker", "direction_worker.md", DIRECTION_WORKER_PROMPT),
+        "script_planner": ("planner", "script_planner.md", PLANNER_PROMPT, 2),
+        "script_direction_worker": (
+            "worker",
+            "direction_worker.md",
+            DIRECTION_WORKER_PROMPT,
+            1,
+        ),
         "script_pattern_retrieval_worker": (
             "worker",
             "retrieval_worker.md",
             RETRIEVAL_WORKER_PROMPT,
+            1,
         ),
         "script_decode_retrieval_worker": (
             "worker",
             "retrieval_worker.md",
             RETRIEVAL_WORKER_PROMPT,
+            1,
         ),
         "script_external_retrieval_worker": (
             "worker",
             "retrieval_worker.md",
             RETRIEVAL_WORKER_PROMPT,
+            1,
         ),
         "script_knowledge_retrieval_worker": (
             "worker",
             "retrieval_worker.md",
             RETRIEVAL_WORKER_PROMPT,
+            1,
         ),
         "script_retrieval_validator": (
             "validator",
             "retrieval_validator.md",
             RETRIEVAL_VALIDATOR_PROMPT,
+            1,
         ),
         "script_candidate_validator": (
             "validator",
             "candidate_validator.md",
             SCRIPT_CANDIDATE_VALIDATOR_PROMPT,
+            2,
+        ),
+        "script_structure_worker": (
+            "worker",
+            "structure_worker.md",
+            STRUCTURE_WORKER_PROMPT,
+            1,
+        ),
+        "script_paragraph_worker": (
+            "worker",
+            "paragraph_worker.md",
+            PARAGRAPH_WORKER_PROMPT,
+            1,
+        ),
+        "script_element_set_worker": (
+            "worker",
+            "element_set_worker.md",
+            ELEMENT_SET_WORKER_PROMPT,
+            1,
+        ),
+        "script_candidate_compare_worker": (
+            "worker",
+            "comparison_worker.md",
+            COMPARISON_WORKER_PROMPT,
+            1,
+        ),
+        "script_compose_worker": (
+            "worker",
+            "compose_worker.md",
+            COMPOSE_WORKER_PROMPT,
+            1,
+        ),
+        "script_candidate_portfolio_worker": (
+            "worker",
+            "portfolio_worker.md",
+            PORTFOLIO_WORKER_PROMPT,
+            1,
         ),
     }
     return tuple(
@@ -64,9 +118,25 @@ def phase_one_prompt_manifest() -> tuple[dict[str, object], ...]:
             "role": role,
             "source": "file",
             "source_id": filename,
-            "version": 1,
+            "version": version,
             "content": content,
-            "content_sha256": canonical_sha256(content).wire,
+            "content_sha256": f"sha256:{sha256(content.encode('utf-8')).hexdigest()}",
         }
-        for preset, (role, filename, content) in values.items()
+        for preset, (role, filename, content, version) in values.items()
     )
+
+
+def phase_one_prompt_manifest() -> tuple[dict[str, object], ...]:
+    """Compatibility view used by older callers and Phase1 fixture tests."""
+
+    phase_one = {
+        "script_planner",
+        "script_direction_worker",
+        "script_pattern_retrieval_worker",
+        "script_decode_retrieval_worker",
+        "script_external_retrieval_worker",
+        "script_knowledge_retrieval_worker",
+        "script_retrieval_validator",
+        "script_candidate_validator",
+    }
+    return tuple(item for item in script_build_prompt_manifest() if item["preset"] in phase_one)

+ 5 - 0
script_build_host/src/script_build_host/agents/prompts/element_set_worker.md

@@ -0,0 +1,5 @@
+Produce one independently testable ElementSet increment for the exact frozen
+scope. Elements may be explored before Paragraphs, but every adopted Element
+must eventually map to an adopted Paragraph or scope; leave unplaced items for
+Planner disposition. Use only accepted inputs and this Attempt workspace.
+Freeze one Artifact and submit it without reading or mutating another branch.

+ 5 - 0
script_build_host/src/script_build_host/agents/prompts/paragraph_worker.md

@@ -0,0 +1,5 @@
+Produce one independently testable Paragraph increment for the exact frozen
+scope in this Task contract. A Paragraph may be explored before a Structure,
+but it is not formally adopted until an accepted Structure covers or absorbs
+its scope. Use only accepted inputs and the current Attempt workspace. Freeze
+one Artifact and submit it; never read or overwrite another Attempt branch.

+ 6 - 0
script_build_host/src/script_build_host/agents/prompts/portfolio_worker.md

@@ -0,0 +1,6 @@
+Close governance over the immutable StructuredScript and Comparison inputs
+pinned by this execution-ready Task contract. Select exactly one adopted
+StructuredScript and explicitly classify every candidate and Decision as
+adopted, superseded, held, or rejected. Freeze one CandidatePortfolioArtifactV1.
+Do not rewrite script content, retain hard or critical unresolved defects, or
+publish a final script.

+ 17 - 8
script_build_host/src/script_build_host/agents/prompts/script_planner.md

@@ -1,8 +1,17 @@
-You are the sole planner for one script-build mission. Inspect the task ledger,
-identify the next missing capability, and create or revise tasks dynamically.
-Retrieval tasks that a direction attempt consumes must be direct children of
-the direction task. Dispatch only through dispatch_script_tasks. Read every
-independent validation report before accepting, repairing, retrying, revising,
-splitting, or blocking a task. Never create a fixed Round, Branch, multipath,
-or precomputed workflow. Phase one ends after an accepted direction: block the
-Root with reason PHASE_ONE_CAPABILITY_BOUNDARY; never claim final script success.
+You are the sole planner for one script-build mission. Inspect only the bounded
+plan view, then create complete ScriptTaskContractV1 values for independently
+testable creative increments. A Task is a frozen input plus a precise scope and
+acceptance criteria; it is not a business module or a fixed workflow step.
+Element-first, Paragraph-first, local Structure-first, later Retrieval, A/B
+comparison and replacement are all valid when their immutable input closure is
+explicit. Formal adoption order is declared only by an execution-ready Compose
+or Portfolio contract, never by Task creation or completion time.
+
+Use plan_script_tasks, decide_script_task and inspect_script_plan instead of
+generic task_plan or task_decide. Dispatch only through dispatch_script_tasks.
+Read every independent validation before accepting, repairing, retrying,
+revising, splitting, replacing, comparing, or blocking. Never mutate a
+completed Task or historical ACCEPT; create a new Task with explicit
+supersedes_decision_ids. Never create Round, branch-zero, multipath, final
+publication, or claim success. Phase boundaries are supplied by the Host's
+signed system policy and enforced by decide_script_task, not by this prompt.

+ 5 - 0
script_build_host/src/script_build_host/agents/prompts/structure_worker.md

@@ -0,0 +1,5 @@
+Produce one independently testable Structure increment for the exact frozen
+scope in this Task contract. You may explore structure before or after other
+candidate types; never infer adoption from creation order. Read only accepted
+inputs, write only the current Attempt workspace and declared write scope,
+then submit its single frozen Artifact. Do not invent a latest candidate.

+ 75 - 7
script_build_host/src/script_build_host/agents/validation.py

@@ -23,7 +23,9 @@ from agent.orchestration.validation_policy import (
     ValidationContext,
 )
 
-from script_build_host.domain.artifacts import ArtifactKind
+from script_build_host.domain.artifacts import ArtifactKind, BusinessArtifact
+from script_build_host.domain.candidate_validation import placeholder_paths
+from script_build_host.domain.defects import ScriptDefectV1, validate_defect_set
 from script_build_host.domain.ports import (
     MissionBindingRepository,
     ScriptBusinessArtifactRepository,
@@ -38,6 +40,25 @@ RETRIEVAL_KINDS = frozenset(
         "knowledge-retrieval",
     }
 )
+PHASE_TWO_KINDS = frozenset(
+    {
+        "structure",
+        "paragraph",
+        "element-set",
+        "compare",
+        "compose",
+        "candidate-portfolio",
+    }
+)
+_ARTIFACT_KIND_BY_TASK_KIND = {
+    "direction": ArtifactKind.DIRECTION,
+    "structure": ArtifactKind.STRUCTURE,
+    "paragraph": ArtifactKind.PARAGRAPH,
+    "element-set": ArtifactKind.ELEMENT_SET,
+    "compare": ArtifactKind.COMPARISON,
+    "compose": ArtifactKind.STRUCTURED_SCRIPT,
+    "candidate-portfolio": ArtifactKind.CANDIDATE_PORTFOLIO,
+}
 _DIGEST = re.compile(r"^sha256:[0-9a-f]{64}$")
 
 
@@ -59,10 +80,10 @@ class ScriptBuildValidationPolicy:
         kind = task_kind(context.task.current_spec.context_refs)
         if kind in RETRIEVAL_KINDS:
             preset = "script_retrieval_validator"
-        elif kind == "direction":
+        elif kind == "direction" or kind in PHASE_TWO_KINDS:
             preset = "script_candidate_validator"
         else:
-            raise ValueError(f"Unsupported phase-one task kind: {kind!r}")
+            raise ValueError(f"Unsupported script-build task kind: {kind!r}")
         return ValidationPlan(
             mode=ValidationMode.AGENT,
             validator_preset=preset,
@@ -106,19 +127,24 @@ def precheck_snapshot(context: ValidationContext) -> list[DeterministicRuleResul
             and context.snapshot.evidence_refs[0].kind == ArtifactKind.EVIDENCE.value
         )
         expected = "one evidence reference"
-    elif kind == "direction":
+    elif kind in _ARTIFACT_KIND_BY_TASK_KIND:
+        expected_kind = _ARTIFACT_KIND_BY_TASK_KIND[kind]
         shape_ok = (
             len(context.snapshot.artifact_refs) == 1
             and not context.snapshot.evidence_refs
-            and context.snapshot.artifact_refs[0].kind == ArtifactKind.DIRECTION.value
+            and context.snapshot.artifact_refs[0].kind == expected_kind.value
         )
-        expected = "one direction artifact reference"
+        expected = f"one {expected_kind.value} artifact reference"
     else:
         shape_ok = False
         expected = "a supported phase-one task kind"
     results.append(
         DeterministicRuleResult(
-            rule_id="phase-one-artifact-shape",
+            rule_id=(
+                "phase-two-artifact-shape"
+                if kind in PHASE_TWO_KINDS
+                else "phase-one-artifact-shape"
+            ),
             verdict=ValidationVerdict.PASSED if shape_ok else ValidationVerdict.FAILED,
             reason=(
                 f"Attempt contains {expected}" if shape_ok else f"Attempt must contain {expected}"
@@ -128,6 +154,44 @@ def precheck_snapshot(context: ValidationContext) -> list[DeterministicRuleResul
     return results
 
 
+def validation_layer(kind: str) -> str:
+    """Return the semantic layer without granting the Validator decision rights."""
+
+    if kind == "compare":
+        return "compare"
+    if kind == "compose":
+        return "global"
+    if kind == "candidate-portfolio":
+        return "governance"
+    if kind in PHASE_TWO_KINDS:
+        return "local"
+    if kind in RETRIEVAL_KINDS or kind == "direction":
+        return "phase-one"
+    raise ValueError(f"unsupported script-build task kind: {kind!r}")
+
+
+def precheck_business_artifact(artifact: BusinessArtifact) -> tuple[str, ...]:
+    """Detect unrealized candidate prose after domain schema checks have succeeded."""
+    return placeholder_paths(artifact)
+
+
+def validate_phase_two_defects(
+    values: Sequence[Mapping[str, Any]],
+    *,
+    criterion_ids: set[str],
+    allowed_evidence_refs: set[str],
+    passed: bool,
+) -> tuple[ScriptDefectV1, ...]:
+    defects = tuple(ScriptDefectV1.from_payload(item) for item in values)
+    validate_defect_set(
+        defects,
+        criterion_ids=criterion_ids,
+        allowed_evidence_refs=allowed_evidence_refs,
+        passed=passed,
+    )
+    return defects
+
+
 class ScriptBuildDeterministicValidator:
     """Optional deterministic validator for explicitly selected rule plans."""
 
@@ -248,12 +312,16 @@ class ScriptBuildEvidenceProvider:
 
 
 __all__ = [
+    "PHASE_TWO_KINDS",
     "RETRIEVAL_KINDS",
     "TASK_KIND_PREFIX",
     "ScriptBuildArtifactEvidenceReader",
     "ScriptBuildDeterministicValidator",
     "ScriptBuildEvidenceProvider",
     "ScriptBuildValidationPolicy",
+    "precheck_business_artifact",
     "precheck_snapshot",
     "task_kind",
+    "validate_phase_two_defects",
+    "validation_layer",
 ]