okstra 0.186.7 → 0.187.0
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.
- package/README.md +1 -1
- package/dist/cli-registry.d.mts +88 -1
- package/dist/cli-registry.mjs +68 -111
- package/dist/cli-registry.mjs.map +1 -1
- package/dist/commands/execute/render-bundle.mjs +0 -1
- package/dist/commands/execute/render-bundle.mjs.map +1 -1
- package/dist/commands/execute/run.mjs +8 -3
- package/dist/commands/execute/run.mjs.map +1 -1
- package/dist/commands/lifecycle/check-project.mjs +1 -14
- package/dist/commands/lifecycle/check-project.mjs.map +1 -1
- package/dist/commands/lifecycle/config.mjs +38 -40
- package/dist/commands/lifecycle/config.mjs.map +1 -1
- package/dist/commands/lifecycle/doctor.d.mts +22 -7
- package/dist/commands/lifecycle/doctor.mjs +77 -49
- package/dist/commands/lifecycle/doctor.mjs.map +1 -1
- package/dist/commands/lifecycle/install.d.mts +12 -10
- package/dist/commands/lifecycle/install.mjs +104 -39
- package/dist/commands/lifecycle/install.mjs.map +1 -1
- package/dist/commands/lifecycle/paths.mjs +8 -3
- package/dist/commands/lifecycle/paths.mjs.map +1 -1
- package/dist/commands/lifecycle/preflight.mjs +2 -1
- package/dist/commands/lifecycle/preflight.mjs.map +1 -1
- package/dist/commands/lifecycle/setup.mjs +22 -36
- package/dist/commands/lifecycle/setup.mjs.map +1 -1
- package/dist/commands/lifecycle/uninstall.d.mts +4 -2
- package/dist/commands/lifecycle/uninstall.mjs +59 -15
- package/dist/commands/lifecycle/uninstall.mjs.map +1 -1
- package/dist/commands/memory/memory.mjs +7 -1
- package/dist/commands/memory/memory.mjs.map +1 -1
- package/dist/lib/helper-scripts.d.mts +1 -1
- package/dist/lib/helper-scripts.mjs +10 -18
- package/dist/lib/helper-scripts.mjs.map +1 -1
- package/dist/lib/host-config.d.mts +72 -0
- package/dist/lib/host-config.mjs +404 -0
- package/dist/lib/host-config.mjs.map +1 -0
- package/dist/lib/host-registry-client.d.mts +2 -2
- package/dist/lib/host-registry-client.mjs +0 -3
- package/dist/lib/host-registry-client.mjs.map +1 -1
- package/dist/lib/install-assets.d.mts +1 -0
- package/dist/lib/install-assets.mjs +4 -0
- package/dist/lib/install-assets.mjs.map +1 -1
- package/dist/lib/proc.d.mts +2 -0
- package/dist/lib/proc.mjs +12 -0
- package/dist/lib/proc.mjs.map +1 -1
- package/dist/lib/python-command.d.mts +2 -0
- package/dist/lib/python-command.mjs +52 -0
- package/dist/lib/python-command.mjs.map +1 -0
- package/dist/lib/python-helper.d.mts +2 -5
- package/dist/lib/python-helper.mjs +3 -52
- package/dist/lib/python-helper.mjs.map +1 -1
- package/dist/lib/runtime-payload.d.mts +23 -0
- package/dist/lib/runtime-payload.mjs +57 -0
- package/dist/lib/runtime-payload.mjs.map +1 -0
- package/dist/lib/types.d.mts +24 -13
- package/docs/architecture/storage-model.md +21 -5
- package/docs/architecture.md +37 -36
- package/docs/cli.md +55 -76
- package/docs/coding-rules.md +295 -0
- package/docs/container.md +10 -36
- package/docs/contributor-change-matrix.md +1 -1
- package/docs/for-ai/skills/okstra-code-review.md +0 -1
- package/docs/for-ai/skills/okstra-container-build.md +8 -41
- package/docs/for-ai/skills/okstra-inspect.md +4 -4
- package/docs/for-ai/skills/okstra-manager.md +2 -2
- package/docs/for-ai/skills/okstra-rollup.md +0 -1
- package/docs/for-ai/skills/okstra-run.md +3 -3
- package/docs/for-ai/skills/okstra-user-response.md +0 -1
- package/docs/performance-improvement-plan-v2.md +1 -1
- package/docs/project-structure-overview.md +62 -62
- package/docs/task-process/README.md +3 -3
- package/docs/task-process/common-flow.md +1 -1
- package/docs/task-process/error-analysis.md +3 -3
- package/docs/task-process/implementation-planning.md +3 -1
- package/docs/task-process/release-handoff.md +1 -1
- package/package.json +3 -2
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +6 -11
- package/runtime/agents/workers/report-writer-worker.md +1 -1
- package/runtime/bin/lib/okstra/cli.sh +4 -0
- package/runtime/bin/lib/okstra/globals.sh +2 -0
- package/runtime/bin/lib/okstra/interactive.sh +26 -173
- package/runtime/bin/lib/okstra/project-resolver.sh +23 -61
- package/runtime/bin/lib/okstra/usage.sh +3 -3
- package/runtime/bin/okstra-compact-reminder.sh +1 -5
- package/runtime/bin/okstra-error-log.py +19 -2
- package/runtime/bin/okstra-import-check.py +26 -0
- package/runtime/bin/okstra-inject-report-index.py +5 -4
- package/runtime/bin/okstra-provider-exec.py +22 -17
- package/runtime/bin/okstra-render-final-report.py +16 -6
- package/runtime/bin/okstra-render-report-views.py +25 -18
- package/runtime/bin/okstra-report-translate.py +30 -18
- package/runtime/bin/okstra-spawn-followups.py +4 -0
- package/runtime/bin/okstra-token-usage.py +3 -0
- package/runtime/bin/okstra.sh +4 -2
- package/runtime/bin/okstra_bootstrap.py +58 -0
- package/runtime/prompts/coding-preflight/overview.md +1 -1
- package/runtime/prompts/duties/planning-worker.md +1 -1
- package/runtime/prompts/launch.template.md +35 -9
- package/runtime/prompts/lead/convergence.md +96 -87
- package/runtime/prompts/lead/okstra-lead-contract.md +63 -12
- package/runtime/prompts/lead/plan-body-verification.md +65 -46
- package/runtime/prompts/lead/report-writer.md +34 -4
- package/runtime/prompts/lead/team-contract.md +4 -1
- package/runtime/prompts/profiles/_clarification-recommendation.md +2 -1
- package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
- package/runtime/prompts/profiles/_common-contract.md +3 -3
- package/runtime/prompts/profiles/_coverage-critic.md +1 -1
- package/runtime/prompts/profiles/_implementation-deliverable.md +2 -2
- package/runtime/prompts/profiles/_implementation-executor.md +3 -1
- package/runtime/prompts/profiles/_implementation-verifier.md +16 -2
- package/runtime/prompts/profiles/error-analysis.md +4 -3
- package/runtime/prompts/profiles/final-verification.md +2 -2
- package/runtime/prompts/profiles/implementation-planning.md +22 -17
- package/runtime/prompts/profiles/implementation.md +3 -2
- package/runtime/prompts/profiles/requirements-discovery.md +2 -1
- package/runtime/prompts/wizard/prompts.ko.json +29 -8
- package/runtime/python/okstra_ctl/__init__.py +6 -27
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +4 -5
- package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +21 -2
- package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +3 -12
- package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +40 -22
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +14 -21
- package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +37 -20
- package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +86 -14
- package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +12 -12
- package/runtime/python/okstra_ctl/adapters/runtime/cmux.py +4 -7
- package/runtime/python/okstra_ctl/agent/__init__.py +1 -0
- package/runtime/python/okstra_ctl/{agent_activity.py → agent/activity.py} +12 -1
- package/runtime/python/okstra_ctl/{agent_invocation.py → agent/invocation.py} +34 -5
- package/runtime/python/okstra_ctl/agent/prompt_cli/__init__.py +19 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/__main__.py +11 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +215 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/dynamic_verifier.py +155 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/emit.py +66 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/inputs.py +138 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +408 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/results.py +197 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +107 -0
- package/runtime/python/okstra_ctl/analysis_packet.py +47 -4
- package/runtime/python/okstra_ctl/approval_decisions.py +260 -8
- package/runtime/python/okstra_ctl/assignment_resolver.py +0 -12
- package/runtime/python/okstra_ctl/attempt_evidence.py +12 -24
- package/runtime/python/okstra_ctl/blocking_checks.py +251 -0
- package/runtime/python/okstra_ctl/brief_frontmatter.py +0 -7
- package/runtime/python/okstra_ctl/clarification_items/__init__.py +102 -0
- package/runtime/python/okstra_ctl/clarification_items/carry.py +224 -0
- package/runtime/python/okstra_ctl/clarification_items/dispositions.py +135 -0
- package/runtime/python/okstra_ctl/clarification_items/parsing.py +253 -0
- package/runtime/python/okstra_ctl/clarification_items/rows.py +115 -0
- package/runtime/python/okstra_ctl/clarification_items/scan.py +215 -0
- package/runtime/python/okstra_ctl/clarification_items/sidecars.py +211 -0
- package/runtime/python/okstra_ctl/cmux.py +38 -31
- package/runtime/python/okstra_ctl/code_review_target.py +163 -1
- package/runtime/python/okstra_ctl/conformance.py +23 -0
- package/runtime/python/okstra_ctl/container.py +38 -421
- package/runtime/python/okstra_ctl/context_cost.py +16 -2
- package/runtime/python/okstra_ctl/contract_graph_cli.py +7 -0
- package/runtime/python/okstra_ctl/convergence.py +101 -15
- package/runtime/python/okstra_ctl/convergence_critic_prompt.py +345 -0
- package/runtime/python/okstra_ctl/convergence_engine.py +382 -70
- package/runtime/python/okstra_ctl/convergence_store.py +5 -29
- package/runtime/python/okstra_ctl/design_prep.py +108 -12
- package/runtime/python/okstra_ctl/design_snapshot.py +11 -1
- package/runtime/python/okstra_ctl/design_surfaces.py +29 -2
- package/runtime/python/okstra_ctl/dispatch_core.py +102 -25
- package/runtime/python/okstra_ctl/dispatch_state.py +268 -39
- package/runtime/python/okstra_ctl/doctor_cli.py +48 -0
- package/runtime/python/okstra_ctl/domain/worker_exec.py +10 -5
- package/runtime/python/okstra_ctl/domain/worker_presentation.py +21 -1
- package/runtime/python/okstra_ctl/domain/worker_stream.py +52 -21
- package/runtime/python/okstra_ctl/domain/write_policy.py +219 -0
- package/runtime/python/okstra_ctl/entrypoints/hosts.py +9 -2
- package/runtime/python/okstra_ctl/error_log_core.py +1 -1
- package/runtime/python/okstra_ctl/error_report.py +14 -0
- package/runtime/python/okstra_ctl/error_zip.py +18 -2
- package/runtime/python/okstra_ctl/execution_identity.py +100 -7
- package/runtime/python/okstra_ctl/execution_manifest.py +67 -20
- package/runtime/python/okstra_ctl/execution_mutation_audit.py +90 -8
- package/runtime/python/okstra_ctl/final_report_paths.py +17 -0
- package/runtime/python/okstra_ctl/final_report_schema.py +90 -16
- package/runtime/python/okstra_ctl/git_reconcile.py +22 -2
- package/runtime/python/okstra_ctl/handoff.py +24 -1
- package/runtime/python/okstra_ctl/ids.py +6 -16
- package/runtime/python/okstra_ctl/implementation_direction.py +142 -33
- package/runtime/python/okstra_ctl/implementation_options.py +25 -11
- package/runtime/python/okstra_ctl/implementation_outcome.py +5 -2
- package/runtime/python/okstra_ctl/improvement_lenses.py +0 -14
- package/runtime/python/okstra_ctl/incremental_carry.py +69 -8
- package/runtime/python/okstra_ctl/incremental_scope.py +173 -12
- package/runtime/python/okstra_ctl/index.py +2 -2
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +48 -8
- package/runtime/python/okstra_ctl/interactive_cli.py +223 -0
- package/runtime/python/okstra_ctl/json_boundary.py +10 -0
- package/runtime/python/okstra_ctl/listing.py +0 -91
- package/runtime/python/okstra_ctl/locks.py +5 -19
- package/runtime/python/okstra_ctl/log_report.py +14 -0
- package/runtime/python/okstra_ctl/manager_cli.py +22 -3
- package/runtime/python/okstra_ctl/manager_launch.py +4 -8
- package/runtime/python/okstra_ctl/material.py +2 -2
- package/runtime/python/okstra_ctl/migrate.py +23 -1
- package/runtime/python/okstra_ctl/model_cli.py +19 -5
- package/runtime/python/okstra_ctl/model_discovery.py +46 -47
- package/runtime/python/okstra_ctl/model_io/__init__.py +1 -0
- package/runtime/python/okstra_ctl/model_io/lines.py +163 -0
- package/runtime/python/okstra_ctl/model_io/references.py +370 -0
- package/runtime/python/okstra_ctl/model_io/renderers.py +498 -0
- package/runtime/python/okstra_ctl/model_io_cli.py +30 -945
- package/runtime/python/okstra_ctl/model_pool.py +10 -6
- package/runtime/python/okstra_ctl/models.py +8 -8
- package/runtime/python/okstra_ctl/mutation_recovery.py +5 -63
- package/runtime/python/okstra_ctl/next_phase.py +121 -69
- package/runtime/python/okstra_ctl/pane_reclaim.py +23 -0
- package/runtime/python/okstra_ctl/pane_title.py +11 -8
- package/runtime/python/okstra_ctl/path_hints.py +36 -11
- package/runtime/python/okstra_ctl/paths.py +76 -8
- package/runtime/python/okstra_ctl/plan_items.py +132 -16
- package/runtime/python/okstra_ctl/plan_items_cli.py +486 -36
- package/runtime/python/okstra_ctl/plan_run_root.py +1 -1
- package/runtime/python/okstra_ctl/plan_validate_cli.py +51 -0
- package/runtime/python/okstra_ctl/plan_verify_cli.py +80 -0
- package/runtime/python/okstra_ctl/prepare_error.py +20 -0
- package/runtime/python/okstra_ctl/prior_planning.py +157 -0
- package/runtime/python/okstra_ctl/profile_show.py +18 -1
- package/runtime/python/okstra_ctl/project_setup_cli.py +140 -0
- package/runtime/python/okstra_ctl/recap.py +22 -1
- package/runtime/python/okstra_ctl/reconcile.py +84 -0
- package/runtime/python/okstra_ctl/registry/host_registry.py +18 -1
- package/runtime/python/okstra_ctl/render.py +98 -32
- package/runtime/python/okstra_ctl/render_final_report.py +3 -7
- package/runtime/python/okstra_ctl/report_assembly.py +297 -7
- package/runtime/python/okstra_ctl/report_contract.py +30 -7
- package/runtime/python/okstra_ctl/report_finalize.py +206 -15
- package/runtime/python/okstra_ctl/report_html/common.py +2 -2
- package/runtime/python/okstra_ctl/report_html/render.py +8 -12
- package/runtime/python/okstra_ctl/report_language.py +8 -4
- package/runtime/python/okstra_ctl/report_narrative.py +90 -3
- package/runtime/python/okstra_ctl/report_projections.py +8 -2
- package/runtime/python/okstra_ctl/report_synthesis_packet.py +258 -1
- package/runtime/python/okstra_ctl/report_translation.py +2 -35
- package/runtime/python/okstra_ctl/report_views.py +4 -22
- package/runtime/python/okstra_ctl/resolve_task_key.py +13 -0
- package/runtime/python/okstra_ctl/rollup.py +13 -0
- package/runtime/python/okstra_ctl/run.py +639 -138
- package/runtime/python/okstra_ctl/run_audit.py +13 -0
- package/runtime/python/okstra_ctl/run_index_row.py +0 -12
- package/runtime/python/okstra_ctl/seeding.py +21 -11
- package/runtime/python/okstra_ctl/sequence.py +1 -1
- package/runtime/python/okstra_ctl/session.py +64 -14
- package/runtime/python/okstra_ctl/set_work_status.py +18 -0
- package/runtime/python/okstra_ctl/stage_integrate.py +15 -1
- package/runtime/python/okstra_ctl/stage_ledger.py +1 -1
- package/runtime/python/okstra_ctl/stage_map.py +57 -11
- package/runtime/python/okstra_ctl/stage_map_cli.py +83 -0
- package/runtime/python/okstra_ctl/stage_map_view.py +65 -0
- package/runtime/python/okstra_ctl/stage_targets.py +3 -12
- package/runtime/python/okstra_ctl/task_list_cli.py +138 -0
- package/runtime/python/okstra_ctl/task_show_cli.py +66 -0
- package/runtime/python/okstra_ctl/task_target.py +4 -16
- package/runtime/python/okstra_ctl/team.py +49 -2
- package/runtime/python/okstra_ctl/time_report.py +17 -2
- package/runtime/python/okstra_ctl/usage_report.py +11 -0
- package/runtime/python/okstra_ctl/user_response.py +55 -218
- package/runtime/python/okstra_ctl/user_response_values.py +242 -0
- package/runtime/python/okstra_ctl/validation_contract.py +3 -0
- package/runtime/python/okstra_ctl/verification_target.py +68 -0
- package/runtime/python/okstra_ctl/wizard.py +457 -92
- package/runtime/python/okstra_ctl/worker_artifacts.py +75 -16
- package/runtime/python/okstra_ctl/worker_audit_check.py +22 -0
- package/runtime/python/okstra_ctl/worker_dispatch.py +21 -0
- package/runtime/python/okstra_ctl/worker_liveness.py +33 -0
- package/runtime/python/okstra_ctl/worker_prompt_body.py +15 -2
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +98 -7
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +24 -2
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +18 -3
- package/runtime/python/okstra_ctl/worker_request.py +2 -1
- package/runtime/python/okstra_ctl/worker_runner.py +16 -9
- package/runtime/python/okstra_ctl/worker_state.py +16 -1
- package/runtime/python/okstra_ctl/workflow.py +18 -1
- package/runtime/python/okstra_ctl/worktree/__init__.py +92 -0
- package/runtime/python/okstra_ctl/worktree/cleanliness.py +89 -0
- package/runtime/python/okstra_ctl/worktree/decisions.py +127 -0
- package/runtime/python/okstra_ctl/worktree/git_ops.py +165 -0
- package/runtime/python/okstra_ctl/worktree/linking.py +249 -0
- package/runtime/python/okstra_ctl/worktree/naming.py +91 -0
- package/runtime/python/okstra_ctl/worktree/provision.py +385 -0
- package/runtime/python/okstra_ctl/worktree/sync_config.py +181 -0
- package/runtime/python/okstra_ctl/worktree_cli.py +75 -0
- package/runtime/python/okstra_ctl/worktree_lookup_cli.py +39 -0
- package/runtime/python/okstra_ctl/worktree_registry.py +7 -0
- package/runtime/python/okstra_ctl/worktree_status_cli.py +53 -0
- package/runtime/python/okstra_ctl/write_policy.py +90 -213
- package/runtime/python/okstra_project/__init__.py +0 -4
- package/runtime/python/okstra_project/dirs.py +2 -2
- package/runtime/python/okstra_project/phase_pointer.py +84 -0
- package/runtime/python/okstra_project/slug.py +24 -0
- package/runtime/python/okstra_project/state.py +22 -230
- package/runtime/python/okstra_token_usage/claude.py +9 -1
- package/runtime/python/okstra_token_usage/cli.py +3 -1
- package/runtime/python/okstra_token_usage/collect.py +71 -10
- package/runtime/python/okstra_token_usage/cursor.py +2 -0
- package/runtime/python/okstra_token_usage/grok.py +1 -5
- package/runtime/python/okstra_token_usage/paths.py +26 -0
- package/runtime/python/okstra_token_usage/pricing.py +19 -7
- package/runtime/schemas/convergence-critic-results-v1.0.schema.json +5 -0
- package/runtime/schemas/execution-manifest-v2.schema.json +10 -10
- package/runtime/schemas/final-report-v2.0.schema.json +9 -26
- package/runtime/schemas/final-report-v3.0.schema.json +173 -41
- package/runtime/schemas/report-narrative-v3.0.schema.json +3 -2
- package/runtime/skills/okstra-brief-gen/SKILL.md +35 -2
- package/runtime/skills/okstra-container-build/SKILL.md +16 -47
- package/runtime/skills/okstra-inspect/facets/history.md +1 -1
- package/runtime/skills/okstra-inspect/facets/status.md +7 -6
- package/runtime/skills/okstra-pr-gen/SKILL.md +1 -1
- package/runtime/skills/okstra-run/SKILL.md +7 -5
- package/runtime/templates/report-writer-prompt-preamble.md +1 -1
- package/runtime/templates/reports/brief.template.md +6 -2
- package/runtime/templates/reports/error-analysis-input.template.md +2 -0
- package/runtime/templates/reports/final-verification-input.template.md +2 -0
- package/runtime/templates/reports/implementation-input.template.md +7 -1
- package/runtime/templates/reports/implementation-planning-input.template.md +4 -0
- package/runtime/templates/reports/quick-input.template.md +2 -0
- package/runtime/templates/reports/release-handoff-input.template.md +6 -1
- package/runtime/templates/reports/report.js +20 -3
- package/runtime/templates/reports/schedule.template.md +2 -0
- package/runtime/templates/reports/settings.template.json +0 -10
- package/runtime/templates/reports/task-brief.template.md +3 -0
- package/runtime/templates/reports/user-response.template.md +7 -3
- package/runtime/validators/checks/fixtures-01.py +57 -0
- package/runtime/validators/checks/fixtures-02.py +565 -0
- package/runtime/validators/checks/runners-01.py +108 -0
- package/runtime/validators/checks/validate-assets-01.py +60 -0
- package/runtime/validators/checks/validate-prompt-metadata-01.py +261 -0
- package/runtime/validators/checks/validate-tasks-01.py +46 -0
- package/runtime/validators/checks/validate-tasks-02.py +85 -0
- package/runtime/validators/checks/validate-tasks-03.py +61 -0
- package/runtime/validators/checks/validate-tasks-04.py +118 -0
- package/runtime/validators/forbidden_actions.py +73 -3
- package/runtime/validators/lib/common.sh +5 -0
- package/runtime/validators/lib/fixtures.sh +7 -591
- package/runtime/validators/lib/paths.sh +13 -0
- package/runtime/validators/lib/runners.sh +6 -104
- package/runtime/validators/lib/summary.sh +1 -1
- package/runtime/validators/lib/validate-assets.sh +6 -56
- package/runtime/validators/lib/validate-prompt-metadata.sh +6 -257
- package/runtime/validators/lib/validate-tasks.sh +9 -294
- package/runtime/validators/validate-implementation-plan-stages.py +4 -4
- package/runtime/validators/validate-run.py +1369 -2654
- package/runtime/validators/validate-workflow.sh +56 -16
- package/runtime/validators/validate_improvement_report.py +2 -1
- package/runtime/validators/validate_session_conformance.py +295 -49
- package/dist/commands/execute/agent-prompt.d.mts +0 -1
- package/dist/commands/execute/agent-prompt.mjs +0 -24
- package/dist/commands/execute/agent-prompt.mjs.map +0 -1
- package/dist/commands/execute/codex-dispatch.d.mts +0 -3
- package/dist/commands/execute/codex-dispatch.mjs +0 -6
- package/dist/commands/execute/codex-dispatch.mjs.map +0 -1
- package/dist/commands/execute/codex-run.d.mts +0 -3
- package/dist/commands/execute/codex-run.mjs +0 -62
- package/dist/commands/execute/codex-run.mjs.map +0 -1
- package/dist/commands/execute/convergence.d.mts +0 -1
- package/dist/commands/execute/convergence.mjs +0 -38
- package/dist/commands/execute/convergence.mjs.map +0 -1
- package/dist/commands/execute/error-log.d.mts +0 -1
- package/dist/commands/execute/error-log.mjs +0 -18
- package/dist/commands/execute/error-log.mjs.map +0 -1
- package/dist/commands/execute/git-reconcile.d.mts +0 -1
- package/dist/commands/execute/git-reconcile.mjs +0 -30
- package/dist/commands/execute/git-reconcile.mjs.map +0 -1
- package/dist/commands/execute/handoff.d.mts +0 -1
- package/dist/commands/execute/handoff.mjs +0 -31
- package/dist/commands/execute/handoff.mjs.map +0 -1
- package/dist/commands/execute/incremental-carry.d.mts +0 -1
- package/dist/commands/execute/incremental-carry.mjs +0 -20
- package/dist/commands/execute/incremental-carry.mjs.map +0 -1
- package/dist/commands/execute/incremental-scope.d.mts +0 -1
- package/dist/commands/execute/incremental-scope.mjs +0 -29
- package/dist/commands/execute/incremental-scope.mjs.map +0 -1
- package/dist/commands/execute/integrate-stages.d.mts +0 -1
- package/dist/commands/execute/integrate-stages.mjs +0 -24
- package/dist/commands/execute/integrate-stages.mjs.map +0 -1
- package/dist/commands/execute/pane-title.d.mts +0 -1
- package/dist/commands/execute/pane-title.mjs +0 -20
- package/dist/commands/execute/pane-title.mjs.map +0 -1
- package/dist/commands/execute/plan-items.d.mts +0 -1
- package/dist/commands/execute/plan-items.mjs +0 -9
- package/dist/commands/execute/plan-items.mjs.map +0 -1
- package/dist/commands/execute/plan-validate.d.mts +0 -1
- package/dist/commands/execute/plan-validate.mjs +0 -68
- package/dist/commands/execute/plan-validate.mjs.map +0 -1
- package/dist/commands/execute/plan-verify.d.mts +0 -1
- package/dist/commands/execute/plan-verify.mjs +0 -43
- package/dist/commands/execute/plan-verify.mjs.map +0 -1
- package/dist/commands/execute/spawn-followups.d.mts +0 -1
- package/dist/commands/execute/spawn-followups.mjs +0 -22
- package/dist/commands/execute/spawn-followups.mjs.map +0 -1
- package/dist/commands/execute/team.d.mts +0 -3
- package/dist/commands/execute/team.mjs +0 -66
- package/dist/commands/execute/team.mjs.map +0 -1
- package/dist/commands/execute/token-usage.d.mts +0 -1
- package/dist/commands/execute/token-usage.mjs +0 -19
- package/dist/commands/execute/token-usage.mjs.map +0 -1
- package/dist/commands/execute/worker-audit-check.d.mts +0 -1
- package/dist/commands/execute/worker-audit-check.mjs +0 -34
- package/dist/commands/execute/worker-audit-check.mjs.map +0 -1
- package/dist/commands/execute/worker-dispatch.d.mts +0 -7
- package/dist/commands/execute/worker-dispatch.mjs +0 -64
- package/dist/commands/execute/worker-dispatch.mjs.map +0 -1
- package/dist/commands/execute/worker-state.d.mts +0 -1
- package/dist/commands/execute/worker-state.mjs +0 -28
- package/dist/commands/execute/worker-state.mjs.map +0 -1
- package/dist/commands/execute/worktree-lookup.d.mts +0 -1
- package/dist/commands/execute/worktree-lookup.mjs +0 -92
- package/dist/commands/execute/worktree-lookup.mjs.map +0 -1
- package/dist/commands/execute/worktree-status.d.mts +0 -1
- package/dist/commands/execute/worktree-status.mjs +0 -121
- package/dist/commands/execute/worktree-status.mjs.map +0 -1
- package/dist/commands/inspect/code-review.d.mts +0 -1
- package/dist/commands/inspect/code-review.mjs +0 -32
- package/dist/commands/inspect/code-review.mjs.map +0 -1
- package/dist/commands/inspect/container.d.mts +0 -1
- package/dist/commands/inspect/container.mjs +0 -25
- package/dist/commands/inspect/container.mjs.map +0 -1
- package/dist/commands/inspect/context-cost.d.mts +0 -1
- package/dist/commands/inspect/context-cost.mjs +0 -25
- package/dist/commands/inspect/context-cost.mjs.map +0 -1
- package/dist/commands/inspect/design-prep.d.mts +0 -1
- package/dist/commands/inspect/design-prep.mjs +0 -22
- package/dist/commands/inspect/design-prep.mjs.map +0 -1
- package/dist/commands/inspect/error-report.d.mts +0 -1
- package/dist/commands/inspect/error-report.mjs +0 -25
- package/dist/commands/inspect/error-report.mjs.map +0 -1
- package/dist/commands/inspect/error-zip.d.mts +0 -1
- package/dist/commands/inspect/error-zip.mjs +0 -24
- package/dist/commands/inspect/error-zip.mjs.map +0 -1
- package/dist/commands/inspect/log-report.d.mts +0 -1
- package/dist/commands/inspect/log-report.mjs +0 -26
- package/dist/commands/inspect/log-report.mjs.map +0 -1
- package/dist/commands/inspect/model-io.d.mts +0 -1
- package/dist/commands/inspect/model-io.mjs +0 -25
- package/dist/commands/inspect/model-io.mjs.map +0 -1
- package/dist/commands/inspect/profile-show.d.mts +0 -1
- package/dist/commands/inspect/profile-show.mjs +0 -28
- package/dist/commands/inspect/profile-show.mjs.map +0 -1
- package/dist/commands/inspect/recap.d.mts +0 -1
- package/dist/commands/inspect/recap.mjs +0 -30
- package/dist/commands/inspect/recap.mjs.map +0 -1
- package/dist/commands/inspect/resolve-task-key.d.mts +0 -1
- package/dist/commands/inspect/resolve-task-key.mjs +0 -24
- package/dist/commands/inspect/resolve-task-key.mjs.map +0 -1
- package/dist/commands/inspect/rollup.d.mts +0 -1
- package/dist/commands/inspect/rollup.mjs +0 -25
- package/dist/commands/inspect/rollup.mjs.map +0 -1
- package/dist/commands/inspect/run-audit.d.mts +0 -1
- package/dist/commands/inspect/run-audit.mjs +0 -25
- package/dist/commands/inspect/run-audit.mjs.map +0 -1
- package/dist/commands/inspect/set-work-status.d.mts +0 -1
- package/dist/commands/inspect/set-work-status.mjs +0 -29
- package/dist/commands/inspect/set-work-status.mjs.map +0 -1
- package/dist/commands/inspect/stage-map.d.mts +0 -1
- package/dist/commands/inspect/stage-map.mjs +0 -131
- package/dist/commands/inspect/stage-map.mjs.map +0 -1
- package/dist/commands/inspect/task-list.d.mts +0 -1
- package/dist/commands/inspect/task-list.mjs +0 -149
- package/dist/commands/inspect/task-list.mjs.map +0 -1
- package/dist/commands/inspect/task-show.d.mts +0 -1
- package/dist/commands/inspect/task-show.mjs +0 -108
- package/dist/commands/inspect/task-show.mjs.map +0 -1
- package/dist/commands/inspect/time-report.d.mts +0 -1
- package/dist/commands/inspect/time-report.mjs +0 -24
- package/dist/commands/inspect/time-report.mjs.map +0 -1
- package/dist/commands/inspect/usage-report.d.mts +0 -1
- package/dist/commands/inspect/usage-report.mjs +0 -23
- package/dist/commands/inspect/usage-report.mjs.map +0 -1
- package/dist/commands/inspect/user-response.d.mts +0 -1
- package/dist/commands/inspect/user-response.mjs +0 -35
- package/dist/commands/inspect/user-response.mjs.map +0 -1
- package/dist/commands/inspect/worker-liveness.d.mts +0 -1
- package/dist/commands/inspect/worker-liveness.mjs +0 -45
- package/dist/commands/inspect/worker-liveness.mjs.map +0 -1
- package/dist/commands/lifecycle/contract-check.d.mts +0 -1
- package/dist/commands/lifecycle/contract-check.mjs +0 -18
- package/dist/commands/lifecycle/contract-check.mjs.map +0 -1
- package/dist/commands/lifecycle/migrate.d.mts +0 -1
- package/dist/commands/lifecycle/migrate.mjs +0 -30
- package/dist/commands/lifecycle/migrate.mjs.map +0 -1
- package/dist/commands/lifecycle/model.d.mts +0 -1
- package/dist/commands/lifecycle/model.mjs +0 -22
- package/dist/commands/lifecycle/model.mjs.map +0 -1
- package/dist/commands/manager.d.mts +0 -3
- package/dist/commands/manager.mjs +0 -50
- package/dist/commands/manager.mjs.map +0 -1
- package/dist/commands/report/agent-activity.d.mts +0 -1
- package/dist/commands/report/agent-activity.mjs +0 -20
- package/dist/commands/report/agent-activity.mjs.map +0 -1
- package/dist/commands/report/approval-decision.d.mts +0 -1
- package/dist/commands/report/approval-decision.mjs +0 -21
- package/dist/commands/report/approval-decision.mjs.map +0 -1
- package/dist/commands/report/design-snapshot.d.mts +0 -1
- package/dist/commands/report/design-snapshot.mjs +0 -19
- package/dist/commands/report/design-snapshot.mjs.map +0 -1
- package/dist/commands/report/finalize.d.mts +0 -4
- package/dist/commands/report/finalize.mjs +0 -64
- package/dist/commands/report/finalize.mjs.map +0 -1
- package/dist/commands/report/inject-report-index.d.mts +0 -1
- package/dist/commands/report/inject-report-index.mjs +0 -21
- package/dist/commands/report/inject-report-index.mjs.map +0 -1
- package/dist/commands/report/render-final-report.d.mts +0 -1
- package/dist/commands/report/render-final-report.mjs +0 -23
- package/dist/commands/report/render-final-report.mjs.map +0 -1
- package/dist/commands/report/render-views.d.mts +0 -1
- package/dist/commands/report/render-views.mjs +0 -27
- package/dist/commands/report/render-views.mjs.map +0 -1
- package/dist/commands/report/translate.d.mts +0 -1
- package/dist/commands/report/translate.mjs +0 -33
- package/dist/commands/report/translate.mjs.map +0 -1
- package/runtime/bin/lib/okstra/tmux-pane.sh +0 -40
- package/runtime/bin/lib/okstra-ctl/cmd-batch.sh +0 -59
- package/runtime/bin/lib/okstra-ctl/cmd-list.sh +0 -35
- package/runtime/bin/lib/okstra-ctl/cmd-open.sh +0 -36
- package/runtime/bin/lib/okstra-ctl/cmd-projects.sh +0 -26
- package/runtime/bin/lib/okstra-ctl/cmd-reconcile.sh +0 -29
- package/runtime/bin/lib/okstra-ctl/cmd-reindex.sh +0 -38
- package/runtime/bin/lib/okstra-ctl/cmd-rerun.sh +0 -345
- package/runtime/bin/lib/okstra-ctl/cmd-show.sh +0 -27
- package/runtime/bin/lib/okstra-ctl/cmd-tail.sh +0 -92
- package/runtime/bin/lib/okstra-ctl/main.sh +0 -41
- package/runtime/bin/lib/okstra-ctl/prepare.sh +0 -31
- package/runtime/bin/lib/okstra-ctl/usage.sh +0 -23
- package/runtime/bin/okstra-central.sh +0 -152
- package/runtime/bin/okstra-incremental-carry.py +0 -10
- package/runtime/bin/okstra-incremental-scope.py +0 -10
- package/runtime/bin/okstra-team-reconcile.sh +0 -36
- package/runtime/python/okstra_ctl/agent_prompt_cli.py +0 -1156
- package/runtime/python/okstra_ctl/batch.py +0 -60
- package/runtime/python/okstra_ctl/clarification_items.py +0 -1050
- package/runtime/python/okstra_ctl/container_registry.py +0 -72
- package/runtime/python/okstra_ctl/improvement_assignment.py +0 -61
- package/runtime/python/okstra_ctl/resolver.py +0 -54
- package/runtime/python/okstra_ctl/team_reconcile.py +0 -275
- package/runtime/python/okstra_ctl/tmux.py +0 -134
- package/runtime/python/okstra_ctl/worktree.py +0 -1099
|
@@ -1,1156 +0,0 @@
|
|
|
1
|
-
"""Materialize and verify one auditable LLM invocation specification."""
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
import argparse
|
|
5
|
-
from dataclasses import replace
|
|
6
|
-
from datetime import datetime, timezone
|
|
7
|
-
import hashlib
|
|
8
|
-
import json
|
|
9
|
-
import os
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
from pathlib import PurePosixPath
|
|
12
|
-
import shutil
|
|
13
|
-
import sys
|
|
14
|
-
import tempfile
|
|
15
|
-
from typing import Any, Mapping, get_args
|
|
16
|
-
|
|
17
|
-
from .agent_invocation import (
|
|
18
|
-
AgentInstruction,
|
|
19
|
-
AgentInstructionSource,
|
|
20
|
-
AgentAudience,
|
|
21
|
-
AgentInvocationError,
|
|
22
|
-
AgentInvocationRequest,
|
|
23
|
-
AgentModelAssignment,
|
|
24
|
-
PreparedAgentInvocation,
|
|
25
|
-
agent_model_assignment_from_payload,
|
|
26
|
-
compose_agent_prompt,
|
|
27
|
-
compose_unbound_run_prompt,
|
|
28
|
-
digest_duty_catalog,
|
|
29
|
-
invocation_execution_identity_from_manifest,
|
|
30
|
-
materialize_standalone_result,
|
|
31
|
-
prepare_agent_invocation,
|
|
32
|
-
publish_standalone_completion,
|
|
33
|
-
verify_standalone_completion,
|
|
34
|
-
verify_agent_invocation,
|
|
35
|
-
v2_role_assignment_authority_errors,
|
|
36
|
-
)
|
|
37
|
-
from .fixed_text import line
|
|
38
|
-
from .json_boundary import JsonBoundaryError, load_owned_object
|
|
39
|
-
from .convergence_store import (
|
|
40
|
-
DYNAMIC_VERIFIER_SOURCE_ROLES,
|
|
41
|
-
reserve_dynamic_verifier,
|
|
42
|
-
)
|
|
43
|
-
from .assignment_environment import load_assignment_context
|
|
44
|
-
from .assignment_resolver import AssignmentContext, resolve_dispatch_assignment
|
|
45
|
-
from .path_hints import hydrate_active_run_context
|
|
46
|
-
from .worker_prompt_headers import WorkerPromptHeaderError, worker_prompt_headers
|
|
47
|
-
from .worker_artifact_paths import audit_sidecar_rel
|
|
48
|
-
from .wrapper_status import (
|
|
49
|
-
log_path_for_prompt,
|
|
50
|
-
prompt_derived_paths,
|
|
51
|
-
status_path_for_prompt,
|
|
52
|
-
)
|
|
53
|
-
from .report_inputs import report_narrative_path, uses_report_contract_v3
|
|
54
|
-
from .worker_prompt_policy import (
|
|
55
|
-
CRITIC_DUTY_BY_ASSIGNMENT_SEGMENT,
|
|
56
|
-
resolve_prompt_plan_for_manifest,
|
|
57
|
-
)
|
|
58
|
-
from .dispatch_state import (
|
|
59
|
-
BACKEND_CLI_WRAPPER,
|
|
60
|
-
BACKEND_CMUX_PANE,
|
|
61
|
-
DispatchError,
|
|
62
|
-
detect_terminal_backend,
|
|
63
|
-
link_agent_dispatch_result,
|
|
64
|
-
record_verified_agent_dispatch,
|
|
65
|
-
reject_agent_dispatch_result,
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
_AUDIENCES = frozenset(get_args(AgentAudience))
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
class AgentPromptCliError(RuntimeError):
|
|
73
|
-
"""Raised when CLI input cannot become a valid invocation request."""
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def _parser() -> argparse.ArgumentParser:
|
|
77
|
-
parser = argparse.ArgumentParser(prog="okstra agent-prompt")
|
|
78
|
-
commands = parser.add_subparsers(dest="command", required=True)
|
|
79
|
-
_add_materialize_parser(commands)
|
|
80
|
-
_add_completion_parsers(commands)
|
|
81
|
-
_add_dispatch_parsers(commands)
|
|
82
|
-
return parser
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def _add_materialize_parser(commands: argparse._SubParsersAction) -> None:
|
|
86
|
-
materialize = commands.add_parser("materialize")
|
|
87
|
-
_common_paths(materialize)
|
|
88
|
-
materialize.add_argument("--invocation-id", required=True)
|
|
89
|
-
materialize.add_argument("--audience", required=True)
|
|
90
|
-
materialize.add_argument("--instruction", required=True)
|
|
91
|
-
materialize.add_argument("--prompt", required=True)
|
|
92
|
-
materialize.add_argument("--run-manifest")
|
|
93
|
-
materialize.add_argument("--worker-id")
|
|
94
|
-
materialize.add_argument("--dispatch-kind")
|
|
95
|
-
materialize.add_argument("--assignment-ref")
|
|
96
|
-
materialize.add_argument("--source-role-execution-ref")
|
|
97
|
-
materialize.add_argument("--result")
|
|
98
|
-
materialize.add_argument("--audit-source")
|
|
99
|
-
materialize.add_argument("--host-runtime")
|
|
100
|
-
materialize.add_argument(
|
|
101
|
-
"--terminal-backend",
|
|
102
|
-
choices=(BACKEND_CLI_WRAPPER, BACKEND_CMUX_PANE),
|
|
103
|
-
)
|
|
104
|
-
materialize.add_argument("--provider")
|
|
105
|
-
materialize.add_argument("--model-role")
|
|
106
|
-
materialize.add_argument("--model", default="")
|
|
107
|
-
materialize.add_argument("--purpose")
|
|
108
|
-
materialize.add_argument(
|
|
109
|
-
"--replace-undispatched",
|
|
110
|
-
action="store_true",
|
|
111
|
-
help="rewrite a prompt this invocation id already wrote, allowed only "
|
|
112
|
-
"while no dispatch has referenced it — the exit for a prompt that "
|
|
113
|
-
"failed a pre-dispatch gate and never ran. Not available for v2 "
|
|
114
|
-
"reverify prompts (--assignment-ref reverify/…): their reservation "
|
|
115
|
-
"records the prompt's input digest in the run manifest and "
|
|
116
|
-
"reservations are append-only, so a rewrite needs a fresh "
|
|
117
|
-
"invocation id and prompt path",
|
|
118
|
-
)
|
|
119
|
-
materialize.add_argument("--json", action="store_true")
|
|
120
|
-
|
|
121
|
-
verify = commands.add_parser("verify")
|
|
122
|
-
_common_paths(verify)
|
|
123
|
-
verify.add_argument("--run-manifest")
|
|
124
|
-
verify.add_argument("--metadata", required=True)
|
|
125
|
-
verify.add_argument("--json", action="store_true")
|
|
126
|
-
verify.add_argument("--text", action="store_true")
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def _add_completion_parsers(commands: argparse._SubParsersAction) -> None:
|
|
130
|
-
materialize_result = commands.add_parser("materialize-result")
|
|
131
|
-
_standalone_completion_args(materialize_result)
|
|
132
|
-
materialize_result.add_argument("--returned-body-file", required=True)
|
|
133
|
-
|
|
134
|
-
complete = commands.add_parser("complete")
|
|
135
|
-
_standalone_completion_args(complete)
|
|
136
|
-
|
|
137
|
-
verify_completion = commands.add_parser("verify-completion")
|
|
138
|
-
_common_paths(verify_completion)
|
|
139
|
-
verify_completion.add_argument("--purpose", required=True)
|
|
140
|
-
verify_completion.add_argument("--completion", required=True)
|
|
141
|
-
verify_completion.add_argument("--json", action="store_true")
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def _add_dispatch_parsers(commands: argparse._SubParsersAction) -> None:
|
|
145
|
-
record_dispatch = commands.add_parser("record-dispatch")
|
|
146
|
-
_common_paths(record_dispatch)
|
|
147
|
-
record_dispatch.add_argument("--run-manifest", required=True)
|
|
148
|
-
record_dispatch.add_argument("--metadata", required=True)
|
|
149
|
-
record_dispatch.add_argument(
|
|
150
|
-
"--enforcement-mode",
|
|
151
|
-
required=True,
|
|
152
|
-
choices=("core-pre-dispatch", "host-native-spec-link-gate"),
|
|
153
|
-
)
|
|
154
|
-
record_dispatch.add_argument("--json", action="store_true")
|
|
155
|
-
|
|
156
|
-
reject_result = commands.add_parser(
|
|
157
|
-
"reject-result",
|
|
158
|
-
help="mark a linked result rejected so a corrective re-dispatch can "
|
|
159
|
-
"claim its path",
|
|
160
|
-
)
|
|
161
|
-
_common_paths(reject_result)
|
|
162
|
-
reject_result.add_argument("--run-manifest", required=True)
|
|
163
|
-
reject_result.add_argument("--dispatch-id", required=True)
|
|
164
|
-
reject_result.add_argument("--superseded-by", required=True)
|
|
165
|
-
reject_result.add_argument("--reason", required=True)
|
|
166
|
-
reject_result.add_argument("--json", action="store_true")
|
|
167
|
-
|
|
168
|
-
link_result = commands.add_parser("link-result")
|
|
169
|
-
_common_paths(link_result)
|
|
170
|
-
link_result.add_argument("--run-manifest", required=True)
|
|
171
|
-
link_result.add_argument("--dispatch-id", required=True)
|
|
172
|
-
link_result.add_argument("--result", required=True)
|
|
173
|
-
link_result.add_argument("--json", action="store_true")
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
def _common_paths(parser: argparse.ArgumentParser) -> None:
|
|
177
|
-
parser.add_argument("--project-root", required=True)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
def _standalone_completion_args(parser: argparse.ArgumentParser) -> None:
|
|
181
|
-
_common_paths(parser)
|
|
182
|
-
parser.add_argument("--purpose", required=True)
|
|
183
|
-
parser.add_argument("--metadata", required=True)
|
|
184
|
-
parser.add_argument("--json", action="store_true")
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def main(argv: list[str] | None = None) -> int:
|
|
188
|
-
try:
|
|
189
|
-
args = _parser().parse_args(argv)
|
|
190
|
-
if args.command == "materialize":
|
|
191
|
-
prepared = _materialize(args)
|
|
192
|
-
_emit(_prepared_payload(prepared, args.audience), args.json)
|
|
193
|
-
return 0
|
|
194
|
-
if args.command == "verify":
|
|
195
|
-
_verify(args)
|
|
196
|
-
_emit(
|
|
197
|
-
{"ok": True, "metadataPath": str(Path(args.metadata).resolve())},
|
|
198
|
-
args.json,
|
|
199
|
-
args.text,
|
|
200
|
-
)
|
|
201
|
-
return 0
|
|
202
|
-
if args.command == "materialize-result":
|
|
203
|
-
_materialize_result(args)
|
|
204
|
-
return 0
|
|
205
|
-
if args.command == "complete":
|
|
206
|
-
_complete(args)
|
|
207
|
-
return 0
|
|
208
|
-
if args.command == "verify-completion":
|
|
209
|
-
_verify_completion(args)
|
|
210
|
-
return 0
|
|
211
|
-
if args.command == "record-dispatch":
|
|
212
|
-
_record_dispatch(args)
|
|
213
|
-
return 0
|
|
214
|
-
if args.command == "reject-result":
|
|
215
|
-
_reject_result(args)
|
|
216
|
-
return 0
|
|
217
|
-
_link_result(args)
|
|
218
|
-
return 0
|
|
219
|
-
except (
|
|
220
|
-
AgentPromptCliError,
|
|
221
|
-
AgentInvocationError,
|
|
222
|
-
DispatchError,
|
|
223
|
-
WorkerPromptHeaderError,
|
|
224
|
-
OSError,
|
|
225
|
-
ValueError,
|
|
226
|
-
) as exc:
|
|
227
|
-
print(f"error: {exc}", file=sys.stderr)
|
|
228
|
-
return 2
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
def _materialize(args: argparse.Namespace) -> PreparedAgentInvocation:
|
|
232
|
-
project_root = _project_root(args.project_root)
|
|
233
|
-
if args.run_manifest:
|
|
234
|
-
return _materialize_run(args, project_root)
|
|
235
|
-
return _materialize_standalone(args, project_root)
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
def _record_dispatch(args: argparse.Namespace) -> None:
|
|
239
|
-
project_root = _project_root(args.project_root)
|
|
240
|
-
record = record_verified_agent_dispatch(
|
|
241
|
-
project_root=project_root,
|
|
242
|
-
run_manifest_path=_project_input(
|
|
243
|
-
project_root, args.run_manifest, "run manifest"
|
|
244
|
-
),
|
|
245
|
-
metadata_path=_project_input(
|
|
246
|
-
project_root, args.metadata, "agent invocation metadata"
|
|
247
|
-
),
|
|
248
|
-
enforcement_mode=args.enforcement_mode,
|
|
249
|
-
)
|
|
250
|
-
_emit(record, args.json)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
def _reject_result(args: argparse.Namespace) -> None:
|
|
254
|
-
project_root = _project_root(args.project_root)
|
|
255
|
-
row = reject_agent_dispatch_result(
|
|
256
|
-
project_root=project_root,
|
|
257
|
-
run_manifest_path=_project_input(
|
|
258
|
-
project_root, args.run_manifest, "run manifest"
|
|
259
|
-
),
|
|
260
|
-
dispatch_id=args.dispatch_id,
|
|
261
|
-
superseded_by=args.superseded_by,
|
|
262
|
-
reason=args.reason,
|
|
263
|
-
)
|
|
264
|
-
_emit(row, args.json)
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
def _link_result(args: argparse.Namespace) -> None:
|
|
268
|
-
project_root = _project_root(args.project_root)
|
|
269
|
-
link = link_agent_dispatch_result(
|
|
270
|
-
project_root=project_root,
|
|
271
|
-
run_manifest_path=_project_input(
|
|
272
|
-
project_root, args.run_manifest, "run manifest"
|
|
273
|
-
),
|
|
274
|
-
dispatch_id=args.dispatch_id,
|
|
275
|
-
result_path=_project_input(project_root, args.result, "agent result"),
|
|
276
|
-
)
|
|
277
|
-
_emit(link, args.json)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
def _materialize_run(
|
|
281
|
-
args: argparse.Namespace,
|
|
282
|
-
project_root: Path,
|
|
283
|
-
) -> PreparedAgentInvocation:
|
|
284
|
-
required = {
|
|
285
|
-
"worker-id": args.worker_id,
|
|
286
|
-
"dispatch-kind": args.dispatch_kind,
|
|
287
|
-
"assignment-ref": args.assignment_ref,
|
|
288
|
-
"result": args.result,
|
|
289
|
-
}
|
|
290
|
-
missing = [name for name, value in required.items() if not value]
|
|
291
|
-
if missing:
|
|
292
|
-
raise AgentPromptCliError(
|
|
293
|
-
f"run materialization requires: {', '.join('--' + name for name in missing)}"
|
|
294
|
-
)
|
|
295
|
-
forbidden = {
|
|
296
|
-
"host-runtime": args.host_runtime,
|
|
297
|
-
"provider": args.provider,
|
|
298
|
-
"model-role": args.model_role,
|
|
299
|
-
"model": args.model,
|
|
300
|
-
"purpose": args.purpose,
|
|
301
|
-
}
|
|
302
|
-
present = [name for name, value in forbidden.items() if value]
|
|
303
|
-
if present:
|
|
304
|
-
raise AgentPromptCliError(
|
|
305
|
-
f"run materialization forbids: {', '.join('--' + name for name in present)}"
|
|
306
|
-
)
|
|
307
|
-
manifest_path = _project_input(project_root, args.run_manifest, "run manifest")
|
|
308
|
-
manifest = _read_json_object(manifest_path, "run manifest")
|
|
309
|
-
contract = _mapping(manifest.get("agentContract"), "run agent contract")
|
|
310
|
-
authorized = _mapping(contract.get("authorizedPaths"), "authorized paths")
|
|
311
|
-
|
|
312
|
-
instruction_path = _authorized_path(
|
|
313
|
-
project_root,
|
|
314
|
-
args.instruction,
|
|
315
|
-
authorized.get("instructionRoots"),
|
|
316
|
-
"instruction",
|
|
317
|
-
must_exist=True,
|
|
318
|
-
)
|
|
319
|
-
prompt_path = _authorized_path(
|
|
320
|
-
project_root,
|
|
321
|
-
args.prompt,
|
|
322
|
-
authorized.get("promptRoots"),
|
|
323
|
-
"prompt",
|
|
324
|
-
must_exist=False,
|
|
325
|
-
)
|
|
326
|
-
result_path = _authorized_path(
|
|
327
|
-
project_root,
|
|
328
|
-
args.result,
|
|
329
|
-
authorized.get("resultRoots"),
|
|
330
|
-
"result",
|
|
331
|
-
must_exist=False,
|
|
332
|
-
)
|
|
333
|
-
if args.audience == "report-writer" and not args.audit_source:
|
|
334
|
-
# The report writer is the one audience whose result path is not its own
|
|
335
|
-
# worker result: it writes the report body, while the audit sidecar is
|
|
336
|
-
# derived from its `.md`. With both collapsed into one value the prompt
|
|
337
|
-
# loses its `**Worker Result Path:**` anchor and the writer puts the
|
|
338
|
-
# report where the audit file belongs — silently, because every header
|
|
339
|
-
# is still present and well-formed. The roster path derives both from
|
|
340
|
-
# the manifest; a dynamic call has to name them.
|
|
341
|
-
#
|
|
342
|
-
# Which artifact `--result` names depends on the report contract, and
|
|
343
|
-
# `dispatch_state.dispatch_result_path` is what decides it. Naming only
|
|
344
|
-
# the v2 answer here sent v3 runs to the data.json, so the narrative
|
|
345
|
-
# `report-finalize` assembles from was never written and the phase
|
|
346
|
-
# failed later, at a place that does not point back here.
|
|
347
|
-
if uses_report_contract_v3(manifest):
|
|
348
|
-
expected = report_narrative_path(project_root, manifest)
|
|
349
|
-
raise AgentPromptCliError(
|
|
350
|
-
"report-writer materialization requires --audit-source: under "
|
|
351
|
-
f"report contract 3.0 --result is the narrative ({expected}), "
|
|
352
|
-
"which `report-finalize` assembles the report data.json from, "
|
|
353
|
-
"and --audit-source the worker-result .md the audit sidecar is "
|
|
354
|
-
"derived from"
|
|
355
|
-
)
|
|
356
|
-
raise AgentPromptCliError(
|
|
357
|
-
"report-writer materialization requires --audit-source: under "
|
|
358
|
-
"report contract 2.0 --result is the report data.json, and "
|
|
359
|
-
"--audit-source the worker-result .md the audit sidecar is "
|
|
360
|
-
"derived from"
|
|
361
|
-
)
|
|
362
|
-
audit_source_path = (
|
|
363
|
-
_authorized_path(
|
|
364
|
-
project_root,
|
|
365
|
-
args.audit_source,
|
|
366
|
-
authorized.get("resultRoots"),
|
|
367
|
-
"audit source",
|
|
368
|
-
must_exist=False,
|
|
369
|
-
)
|
|
370
|
-
if args.audit_source
|
|
371
|
-
else result_path
|
|
372
|
-
)
|
|
373
|
-
_validate_run_identity(
|
|
374
|
-
manifest,
|
|
375
|
-
worker_id=args.worker_id,
|
|
376
|
-
dispatch_kind=args.dispatch_kind,
|
|
377
|
-
assignment_ref=args.assignment_ref,
|
|
378
|
-
audience=args.audience,
|
|
379
|
-
)
|
|
380
|
-
assignments = _mapping(
|
|
381
|
-
manifest.get("invocationAssignments"),
|
|
382
|
-
"run invocation assignments",
|
|
383
|
-
)
|
|
384
|
-
if args.assignment_ref not in assignments:
|
|
385
|
-
raise AgentPromptCliError(
|
|
386
|
-
f"assignment reference is missing from run manifest: {args.assignment_ref}"
|
|
387
|
-
)
|
|
388
|
-
assignment_payload = assignments[args.assignment_ref]
|
|
389
|
-
assignment = agent_model_assignment_from_payload(assignment_payload)
|
|
390
|
-
dynamic_source = _dynamic_verifier_source(args, manifest)
|
|
391
|
-
identity = (
|
|
392
|
-
None
|
|
393
|
-
if dynamic_source is not None
|
|
394
|
-
else invocation_execution_identity_from_manifest(
|
|
395
|
-
manifest,
|
|
396
|
-
assignment=assignment,
|
|
397
|
-
assignment_ref=args.assignment_ref,
|
|
398
|
-
duty_id=args.audience,
|
|
399
|
-
)
|
|
400
|
-
)
|
|
401
|
-
duty_root = _project_manifest_path(
|
|
402
|
-
project_root,
|
|
403
|
-
contract.get("dutyRootPath"),
|
|
404
|
-
"duty root",
|
|
405
|
-
must_exist=True,
|
|
406
|
-
)
|
|
407
|
-
if contract.get("catalogDigest") != digest_duty_catalog(duty_root):
|
|
408
|
-
raise AgentPromptCliError("run duty snapshot catalog digest does not match")
|
|
409
|
-
active_context_path = _project_manifest_path(
|
|
410
|
-
project_root,
|
|
411
|
-
manifest.get("activeRunContextPath"),
|
|
412
|
-
"active run context",
|
|
413
|
-
must_exist=True,
|
|
414
|
-
)
|
|
415
|
-
active_context = hydrate_active_run_context(
|
|
416
|
-
_read_json_object(active_context_path, "active run context")
|
|
417
|
-
)
|
|
418
|
-
prompt_rel = _relative(project_root, prompt_path)
|
|
419
|
-
result_rel = _relative(project_root, result_path)
|
|
420
|
-
audit_rel = _relative(project_root, audit_source_path)
|
|
421
|
-
anchor_lines = tuple(worker_prompt_headers(
|
|
422
|
-
project_root=project_root,
|
|
423
|
-
prompt_rel=prompt_rel,
|
|
424
|
-
result_rel=result_rel,
|
|
425
|
-
audit_source_rel=audit_rel,
|
|
426
|
-
worker_id=args.worker_id,
|
|
427
|
-
dispatch_kind=args.dispatch_kind,
|
|
428
|
-
manifest=manifest,
|
|
429
|
-
active_context=active_context,
|
|
430
|
-
))
|
|
431
|
-
request = AgentInvocationRequest(
|
|
432
|
-
invocation_id=args.invocation_id,
|
|
433
|
-
worker_id=args.worker_id if identity is None else None,
|
|
434
|
-
audience=args.audience,
|
|
435
|
-
assignment_ref=args.assignment_ref,
|
|
436
|
-
purpose=None,
|
|
437
|
-
assignment=assignment,
|
|
438
|
-
instruction=AgentInstruction(
|
|
439
|
-
anchor_lines=anchor_lines,
|
|
440
|
-
body=instruction_path.read_text(encoding="utf-8"),
|
|
441
|
-
source_paths=(AgentInstructionSource(
|
|
442
|
-
kind="project",
|
|
443
|
-
path=_relative(project_root, instruction_path),
|
|
444
|
-
),),
|
|
445
|
-
),
|
|
446
|
-
project_root=project_root,
|
|
447
|
-
run_manifest_path=manifest_path,
|
|
448
|
-
duty_root=duty_root,
|
|
449
|
-
prompt_path=prompt_path,
|
|
450
|
-
metadata_path=prompt_path.with_name(prompt_path.name + ".meta.json"),
|
|
451
|
-
dispatch_kind=args.dispatch_kind,
|
|
452
|
-
participant_ref=identity.participant_ref if identity is not None else None,
|
|
453
|
-
role_execution_ref=(
|
|
454
|
-
identity.role_execution_ref if identity is not None else None
|
|
455
|
-
),
|
|
456
|
-
duty_id=identity.duty_id if identity is not None else None,
|
|
457
|
-
invocation_ref=args.invocation_id if identity is not None else None,
|
|
458
|
-
attempt=1,
|
|
459
|
-
replace_undispatched=args.replace_undispatched,
|
|
460
|
-
)
|
|
461
|
-
if dynamic_source is not None:
|
|
462
|
-
request = _reserve_dynamic_verifier_request(
|
|
463
|
-
request,
|
|
464
|
-
args=args,
|
|
465
|
-
manifest=manifest,
|
|
466
|
-
manifest_path=manifest_path,
|
|
467
|
-
active_context=active_context,
|
|
468
|
-
source_role_execution_ref=dynamic_source,
|
|
469
|
-
artifact_paths=_dynamic_verifier_artifact_paths(
|
|
470
|
-
project_root,
|
|
471
|
-
prompt_path,
|
|
472
|
-
result_path,
|
|
473
|
-
audit_source_path,
|
|
474
|
-
audit_rel,
|
|
475
|
-
active_context,
|
|
476
|
-
args.worker_id,
|
|
477
|
-
),
|
|
478
|
-
)
|
|
479
|
-
return prepare_agent_invocation(request)
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
def _run_worktree(
|
|
483
|
-
manifest: Mapping[str, Any], active_context: Mapping[str, Any]
|
|
484
|
-
) -> Path | None:
|
|
485
|
-
"""이 런의 워커 루트. 디스패치가 job 에 싣는 값과 같은 seam 에서 읽는다."""
|
|
486
|
-
from .dispatch_state import worktree_path
|
|
487
|
-
|
|
488
|
-
value = worktree_path(manifest, active_context)
|
|
489
|
-
return Path(value) if value else None
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
def _reserve_dynamic_verifier_request(
|
|
493
|
-
request: AgentInvocationRequest,
|
|
494
|
-
*,
|
|
495
|
-
args: argparse.Namespace,
|
|
496
|
-
manifest: Mapping[str, Any],
|
|
497
|
-
manifest_path: Path,
|
|
498
|
-
active_context: Mapping[str, Any],
|
|
499
|
-
source_role_execution_ref: str,
|
|
500
|
-
artifact_paths: tuple[Path, ...],
|
|
501
|
-
) -> AgentInvocationRequest:
|
|
502
|
-
_validate_dynamic_source_assignment(
|
|
503
|
-
manifest,
|
|
504
|
-
source_role_execution_ref,
|
|
505
|
-
request.assignment,
|
|
506
|
-
)
|
|
507
|
-
prompt_bytes = compose_unbound_run_prompt(request)
|
|
508
|
-
verifier, invocation = reserve_dynamic_verifier(
|
|
509
|
-
manifest_path,
|
|
510
|
-
source_role_execution_ref=source_role_execution_ref,
|
|
511
|
-
duty_id=args.audience,
|
|
512
|
-
round_number=_reverify_round(args.dispatch_kind),
|
|
513
|
-
task_key=_required_manifest_string(manifest, "taskKey"),
|
|
514
|
-
input_digest="sha256:" + hashlib.sha256(prompt_bytes).hexdigest(),
|
|
515
|
-
invocation_ref=args.invocation_id,
|
|
516
|
-
artifact_paths=artifact_paths,
|
|
517
|
-
worktree=_run_worktree(manifest, active_context),
|
|
518
|
-
)
|
|
519
|
-
bound = replace(
|
|
520
|
-
request,
|
|
521
|
-
worker_id=None,
|
|
522
|
-
participant_ref=verifier.participant_ref,
|
|
523
|
-
role_execution_ref=verifier.role_execution_ref,
|
|
524
|
-
duty_id=args.audience,
|
|
525
|
-
invocation_ref=invocation.invocation_ref,
|
|
526
|
-
)
|
|
527
|
-
if compose_agent_prompt(bound).encode("utf-8") != prompt_bytes:
|
|
528
|
-
raise AgentPromptCliError(
|
|
529
|
-
"dynamic verifier identity changed immutable prompt bytes"
|
|
530
|
-
)
|
|
531
|
-
return bound
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
def _dynamic_verifier_artifact_paths(
|
|
535
|
-
project_root: Path,
|
|
536
|
-
prompt_path: Path,
|
|
537
|
-
result_path: Path,
|
|
538
|
-
audit_source_path: Path,
|
|
539
|
-
audit_rel: str,
|
|
540
|
-
active_context: Mapping[str, Any],
|
|
541
|
-
worker_id: str,
|
|
542
|
-
) -> tuple[Path, ...]:
|
|
543
|
-
paths = {
|
|
544
|
-
result_path,
|
|
545
|
-
audit_source_path,
|
|
546
|
-
project_root / audit_sidecar_rel(audit_rel),
|
|
547
|
-
*prompt_derived_paths(prompt_path),
|
|
548
|
-
}
|
|
549
|
-
error_logs = active_context.get("errorLogs")
|
|
550
|
-
sidecars = error_logs.get("sidecarsByWorkerId") if isinstance(error_logs, Mapping) else None
|
|
551
|
-
value = sidecars.get(worker_id) if isinstance(sidecars, Mapping) else None
|
|
552
|
-
if isinstance(value, str) and value:
|
|
553
|
-
path = Path(value)
|
|
554
|
-
paths.add(path if path.is_absolute() else project_root / path)
|
|
555
|
-
return tuple(sorted(paths, key=str))
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
def _dynamic_verifier_source(
|
|
559
|
-
args: argparse.Namespace,
|
|
560
|
-
manifest: Mapping[str, Any],
|
|
561
|
-
) -> str | None:
|
|
562
|
-
is_v2 = (
|
|
563
|
-
manifest.get("schemaVersion") == "2.0"
|
|
564
|
-
and manifest.get("executionIdentityVersion") == 2
|
|
565
|
-
)
|
|
566
|
-
is_reverify = (
|
|
567
|
-
args.assignment_ref.startswith("reverify/")
|
|
568
|
-
and args.audience == "reverification-worker"
|
|
569
|
-
)
|
|
570
|
-
source = args.source_role_execution_ref
|
|
571
|
-
if is_v2 and is_reverify:
|
|
572
|
-
if args.replace_undispatched:
|
|
573
|
-
raise AgentPromptCliError(
|
|
574
|
-
"v2 dynamic verifier prompts are append-only: this "
|
|
575
|
-
"invocation's reservation already recorded this prompt's input "
|
|
576
|
-
"digest in the run manifest, and a reservation cannot be "
|
|
577
|
-
"rewritten. Use a fresh invocation ID and prompt path."
|
|
578
|
-
)
|
|
579
|
-
if not source:
|
|
580
|
-
raise AgentPromptCliError(
|
|
581
|
-
"v2 reverify materialization requires "
|
|
582
|
-
"--source-role-execution-ref"
|
|
583
|
-
)
|
|
584
|
-
return source
|
|
585
|
-
if source:
|
|
586
|
-
raise AgentPromptCliError(
|
|
587
|
-
"--source-role-execution-ref is allowed only for v2 reverify"
|
|
588
|
-
)
|
|
589
|
-
return None
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
def _reverify_round(dispatch_kind: str) -> int:
|
|
593
|
-
prefix = "reverify-r"
|
|
594
|
-
value = dispatch_kind.removeprefix(prefix)
|
|
595
|
-
if not dispatch_kind.startswith(prefix) or not value.isdigit() or int(value) < 1:
|
|
596
|
-
raise AgentPromptCliError(
|
|
597
|
-
"dynamic verifier dispatch kind must be reverify-r<N>"
|
|
598
|
-
)
|
|
599
|
-
return int(value)
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
def _validate_dynamic_source_assignment(
|
|
603
|
-
manifest: Mapping[str, Any],
|
|
604
|
-
source_role_execution_ref: str,
|
|
605
|
-
assignment: AgentModelAssignment,
|
|
606
|
-
) -> None:
|
|
607
|
-
rows = manifest.get("roleExecutions")
|
|
608
|
-
source = next(
|
|
609
|
-
(
|
|
610
|
-
row
|
|
611
|
-
for row in rows
|
|
612
|
-
if isinstance(row, Mapping)
|
|
613
|
-
and row.get("roleExecutionRef") == source_role_execution_ref
|
|
614
|
-
),
|
|
615
|
-
None,
|
|
616
|
-
) if isinstance(rows, list) else None
|
|
617
|
-
if source is None:
|
|
618
|
-
raise AgentPromptCliError(
|
|
619
|
-
f"source role execution is unknown: {source_role_execution_ref}"
|
|
620
|
-
)
|
|
621
|
-
if source.get("role") not in DYNAMIC_VERIFIER_SOURCE_ROLES:
|
|
622
|
-
raise AgentPromptCliError(
|
|
623
|
-
"dynamic verifier source role is not eligible for re-verification"
|
|
624
|
-
)
|
|
625
|
-
errors = v2_role_assignment_authority_errors(
|
|
626
|
-
manifest,
|
|
627
|
-
role_execution_ref=source_role_execution_ref,
|
|
628
|
-
participant_ref=str(source.get("participantRef") or ""),
|
|
629
|
-
assignment=assignment,
|
|
630
|
-
)
|
|
631
|
-
if errors:
|
|
632
|
-
raise AgentPromptCliError(
|
|
633
|
-
"dynamic verifier source does not match the selected assignment: "
|
|
634
|
-
+ "; ".join(errors)
|
|
635
|
-
)
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
def _required_manifest_string(
|
|
639
|
-
manifest: Mapping[str, Any],
|
|
640
|
-
key: str,
|
|
641
|
-
) -> str:
|
|
642
|
-
value = manifest.get(key)
|
|
643
|
-
if not isinstance(value, str) or not value.strip():
|
|
644
|
-
raise AgentPromptCliError(f"run manifest has no {key}")
|
|
645
|
-
return value
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
def _validate_run_identity(
|
|
649
|
-
manifest: Mapping[str, Any],
|
|
650
|
-
*,
|
|
651
|
-
worker_id: str,
|
|
652
|
-
dispatch_kind: str,
|
|
653
|
-
assignment_ref: str,
|
|
654
|
-
audience: str,
|
|
655
|
-
) -> None:
|
|
656
|
-
expected: str
|
|
657
|
-
if assignment_ref == "lead":
|
|
658
|
-
expected = "lead"
|
|
659
|
-
if worker_id != "lead":
|
|
660
|
-
raise AgentPromptCliError("lead assignment requires worker ID 'lead'")
|
|
661
|
-
elif assignment_ref == "translator":
|
|
662
|
-
expected = "translator"
|
|
663
|
-
if worker_id != "translator":
|
|
664
|
-
raise AgentPromptCliError("translator assignment requires worker ID 'translator'")
|
|
665
|
-
elif assignment_ref.startswith("critic/"):
|
|
666
|
-
scope = assignment_ref.split("/", 1)[1]
|
|
667
|
-
expected = CRITIC_DUTY_BY_ASSIGNMENT_SEGMENT.get(scope, "")
|
|
668
|
-
if not expected or dispatch_kind != "critic":
|
|
669
|
-
raise AgentPromptCliError("critic assignment identity is invalid")
|
|
670
|
-
# provider 대조는 여기 두지 않는다. critic 의 `worker_id` 는 배정 참조의
|
|
671
|
-
# 마지막 마디(`scope` / `acceptance`)이고 provider 이름이 아니다
|
|
672
|
-
# (`render.py` 의 로스터 행이 `assignment_ref.rsplit("/", 1)[-1]` 로 만든다).
|
|
673
|
-
# 종전에 있던 `provider != worker_id` 검사는 두 어휘를 비교해서 늘 참이 되는
|
|
674
|
-
# 형태였고, 설정을 run manifest 에서 찾다 못 찾아 조용히 건너뛰었기에
|
|
675
|
-
# 드러나지 않았다. 정본에서 읽게 고치면 모든 critic 디스패치가 거부된다.
|
|
676
|
-
else:
|
|
677
|
-
try:
|
|
678
|
-
expected = resolve_prompt_plan_for_manifest(
|
|
679
|
-
manifest=manifest,
|
|
680
|
-
worker_id=worker_id,
|
|
681
|
-
dispatch_kind=dispatch_kind,
|
|
682
|
-
).duty_audience
|
|
683
|
-
except ValueError as exc:
|
|
684
|
-
raise AgentPromptCliError(str(exc)) from exc
|
|
685
|
-
if audience != expected and _manifest_issued_role_execution(
|
|
686
|
-
manifest, audience=audience, assignment_ref=assignment_ref
|
|
687
|
-
):
|
|
688
|
-
# The prompt plan names a worker's role by worker id, so on an
|
|
689
|
-
# implementation run the executor's provider resolves to the
|
|
690
|
-
# executor role no matter which role execution is being targeted.
|
|
691
|
-
# But the manifest issues one role execution per role, and a
|
|
692
|
-
# provider serving as both executor and verifier gets two — a
|
|
693
|
-
# normal roster, since the verifier contract accepts reusing the
|
|
694
|
-
# executor's model behind its own session. Refusing the second
|
|
695
|
-
# audience made a role execution okstra had itself issued
|
|
696
|
-
# undispatchable, which costs the run an independent verifier.
|
|
697
|
-
expected = audience
|
|
698
|
-
if audience != expected:
|
|
699
|
-
raise AgentPromptCliError(
|
|
700
|
-
f"audience {audience!r} does not match required audience {expected!r}"
|
|
701
|
-
)
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
def _manifest_issued_role_execution(
|
|
705
|
-
manifest: Mapping[str, Any],
|
|
706
|
-
*,
|
|
707
|
-
audience: str,
|
|
708
|
-
assignment_ref: str,
|
|
709
|
-
) -> bool:
|
|
710
|
-
"""Whether this run issued a role execution for that audience's role.
|
|
711
|
-
|
|
712
|
-
Keyed on the manifest's own rows, not on what the prompt plan infers from
|
|
713
|
-
a worker id: the question is whether okstra created the execution being
|
|
714
|
-
targeted, and only the manifest answers that.
|
|
715
|
-
"""
|
|
716
|
-
from .domain.role import RoleCatalogError, role_for_duty
|
|
717
|
-
|
|
718
|
-
try:
|
|
719
|
-
role = role_for_duty(audience)
|
|
720
|
-
except RoleCatalogError:
|
|
721
|
-
return False
|
|
722
|
-
assignments = manifest.get("invocationAssignments")
|
|
723
|
-
assignment = (
|
|
724
|
-
assignments.get(assignment_ref) if isinstance(assignments, Mapping) else None
|
|
725
|
-
)
|
|
726
|
-
provider = (
|
|
727
|
-
assignment.get("provider") if isinstance(assignment, Mapping) else None
|
|
728
|
-
)
|
|
729
|
-
if not provider:
|
|
730
|
-
return False
|
|
731
|
-
executions = manifest.get("roleExecutions")
|
|
732
|
-
return any(
|
|
733
|
-
isinstance(row, Mapping)
|
|
734
|
-
and row.get("role") == role
|
|
735
|
-
and row.get("provider") == provider
|
|
736
|
-
for row in (executions if isinstance(executions, list) else [])
|
|
737
|
-
)
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
def _materialize_standalone(
|
|
741
|
-
args: argparse.Namespace,
|
|
742
|
-
project_root: Path,
|
|
743
|
-
) -> PreparedAgentInvocation:
|
|
744
|
-
required = {
|
|
745
|
-
"host-runtime": args.host_runtime,
|
|
746
|
-
"provider": args.provider,
|
|
747
|
-
"model-role": args.model_role,
|
|
748
|
-
"purpose": args.purpose,
|
|
749
|
-
}
|
|
750
|
-
missing = [name for name, value in required.items() if not value]
|
|
751
|
-
if missing:
|
|
752
|
-
raise AgentPromptCliError(
|
|
753
|
-
"standalone materialization requires: "
|
|
754
|
-
+ ", ".join("--" + name for name in missing)
|
|
755
|
-
)
|
|
756
|
-
forbidden = {
|
|
757
|
-
"worker-id": args.worker_id,
|
|
758
|
-
"dispatch-kind": args.dispatch_kind,
|
|
759
|
-
"assignment-ref": args.assignment_ref,
|
|
760
|
-
"result": args.result,
|
|
761
|
-
"audit-source": args.audit_source,
|
|
762
|
-
"source-role-execution-ref": args.source_role_execution_ref,
|
|
763
|
-
}
|
|
764
|
-
present = [name for name, value in forbidden.items() if value]
|
|
765
|
-
if present:
|
|
766
|
-
raise AgentPromptCliError(
|
|
767
|
-
"standalone materialization forbids: "
|
|
768
|
-
+ ", ".join("--" + name for name in present)
|
|
769
|
-
)
|
|
770
|
-
if not _is_slug(args.purpose) or not _is_slug(args.invocation_id):
|
|
771
|
-
raise AgentPromptCliError("standalone purpose and invocation ID must be slugs")
|
|
772
|
-
if args.audience not in _AUDIENCES:
|
|
773
|
-
raise AgentPromptCliError(f"unknown duty audience: {args.audience}")
|
|
774
|
-
root = project_root / ".okstra" / "agent-invocations" / args.purpose
|
|
775
|
-
if not root.is_dir():
|
|
776
|
-
raise AgentPromptCliError(f"standalone invocation root not found: {root}")
|
|
777
|
-
resolved_root = root.resolve(strict=True)
|
|
778
|
-
if not _is_relative_to(resolved_root, project_root):
|
|
779
|
-
raise AgentPromptCliError("standalone invocation root escapes project root")
|
|
780
|
-
root = resolved_root
|
|
781
|
-
expected_instruction = root / f"{args.invocation_id}.instructions.md"
|
|
782
|
-
expected_prompt = root / f"{args.invocation_id}.prompt.md"
|
|
783
|
-
instruction_path = _exact_path(args.instruction, expected_instruction, True, "instruction")
|
|
784
|
-
prompt_path = _exact_path(args.prompt, expected_prompt, False, "prompt")
|
|
785
|
-
assignment_context = load_assignment_context(
|
|
786
|
-
host_runtime=args.host_runtime,
|
|
787
|
-
terminal_backend=args.terminal_backend or detect_terminal_backend(),
|
|
788
|
-
execution_provider_ids=(args.provider,),
|
|
789
|
-
include_native_provider=False,
|
|
790
|
-
)
|
|
791
|
-
assignment = _standalone_assignment(
|
|
792
|
-
context=assignment_context,
|
|
793
|
-
provider=args.provider,
|
|
794
|
-
model_role=args.model_role,
|
|
795
|
-
model=args.model,
|
|
796
|
-
)
|
|
797
|
-
duty_root = root / f"{args.invocation_id}.duty-contracts"
|
|
798
|
-
_snapshot_standalone_duties(duty_root)
|
|
799
|
-
return prepare_agent_invocation(AgentInvocationRequest(
|
|
800
|
-
invocation_id=args.invocation_id,
|
|
801
|
-
worker_id=None,
|
|
802
|
-
audience=args.audience,
|
|
803
|
-
assignment_ref=None,
|
|
804
|
-
purpose=args.purpose,
|
|
805
|
-
assignment=assignment,
|
|
806
|
-
instruction=AgentInstruction(
|
|
807
|
-
anchor_lines=(),
|
|
808
|
-
body=instruction_path.read_text(encoding="utf-8"),
|
|
809
|
-
source_paths=(AgentInstructionSource(
|
|
810
|
-
kind="project",
|
|
811
|
-
path=_relative(project_root, instruction_path),
|
|
812
|
-
),),
|
|
813
|
-
),
|
|
814
|
-
project_root=project_root,
|
|
815
|
-
run_manifest_path=None,
|
|
816
|
-
duty_root=duty_root,
|
|
817
|
-
prompt_path=prompt_path,
|
|
818
|
-
metadata_path=prompt_path.with_name(prompt_path.name + ".meta.json"),
|
|
819
|
-
dispatch_kind="standalone",
|
|
820
|
-
participant_ref=None,
|
|
821
|
-
role_execution_ref=None,
|
|
822
|
-
duty_id=None,
|
|
823
|
-
invocation_ref=None,
|
|
824
|
-
attempt=1,
|
|
825
|
-
))
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
def _standalone_assignment(
|
|
829
|
-
*,
|
|
830
|
-
context: AssignmentContext,
|
|
831
|
-
provider: str,
|
|
832
|
-
model_role: str,
|
|
833
|
-
model: str,
|
|
834
|
-
) -> AgentModelAssignment:
|
|
835
|
-
host_runtime = context.environment.host_descriptor.id
|
|
836
|
-
resolved = resolve_dispatch_assignment(
|
|
837
|
-
context=context,
|
|
838
|
-
host_runtime=host_runtime,
|
|
839
|
-
role=model_role,
|
|
840
|
-
duty_id=model_role,
|
|
841
|
-
provider=provider,
|
|
842
|
-
model=model,
|
|
843
|
-
)
|
|
844
|
-
binding = resolved.binding
|
|
845
|
-
if binding is None:
|
|
846
|
-
raise AgentPromptCliError("standalone assignment requires a model binding")
|
|
847
|
-
return AgentModelAssignment(
|
|
848
|
-
provider=resolved.provider_id,
|
|
849
|
-
model=resolved.display_name,
|
|
850
|
-
model_execution_value=binding.resolved_execution_value,
|
|
851
|
-
runner=binding.runner,
|
|
852
|
-
host_runtime=host_runtime,
|
|
853
|
-
host_model_value=binding.host_model_value,
|
|
854
|
-
)
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
def _snapshot_standalone_duties(destination: Path) -> None:
|
|
858
|
-
source = Path(__file__).resolve().parents[2] / "prompts" / "duties"
|
|
859
|
-
if not source.is_dir():
|
|
860
|
-
raise AgentPromptCliError(f"duty contract source not found: {source}")
|
|
861
|
-
if destination.exists():
|
|
862
|
-
if not destination.is_dir() or digest_duty_catalog(destination) != digest_duty_catalog(source):
|
|
863
|
-
raise AgentPromptCliError("standalone duty snapshot conflicts with existing files")
|
|
864
|
-
return
|
|
865
|
-
temporary = Path(tempfile.mkdtemp(prefix=f".{destination.name}.", dir=destination.parent))
|
|
866
|
-
try:
|
|
867
|
-
shutil.copytree(source, temporary, dirs_exist_ok=True)
|
|
868
|
-
try:
|
|
869
|
-
os.rename(temporary, destination)
|
|
870
|
-
except FileExistsError:
|
|
871
|
-
if digest_duty_catalog(destination) != digest_duty_catalog(source):
|
|
872
|
-
raise AgentPromptCliError("standalone duty snapshot publication conflict")
|
|
873
|
-
finally:
|
|
874
|
-
if temporary.exists():
|
|
875
|
-
shutil.rmtree(temporary)
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
def _verify(args: argparse.Namespace) -> None:
|
|
879
|
-
project_root = _project_root(args.project_root)
|
|
880
|
-
metadata_path = _project_input(project_root, args.metadata, "metadata")
|
|
881
|
-
metadata = _read_json_object(metadata_path, "metadata")
|
|
882
|
-
contract_source = _mapping(metadata.get("contractSource"), "contract source")
|
|
883
|
-
mode = contract_source.get("mode")
|
|
884
|
-
expected_manifest: Path | None = None
|
|
885
|
-
expected_assignment: AgentModelAssignment | None = None
|
|
886
|
-
if mode == "run":
|
|
887
|
-
if not args.run_manifest:
|
|
888
|
-
raise AgentPromptCliError("run invocation verification requires --run-manifest")
|
|
889
|
-
expected_manifest = _project_input(project_root, args.run_manifest, "run manifest")
|
|
890
|
-
manifest = _read_json_object(expected_manifest, "run manifest")
|
|
891
|
-
assignments = _mapping(manifest.get("invocationAssignments"), "run assignments")
|
|
892
|
-
reference = metadata.get("assignmentRef")
|
|
893
|
-
if not isinstance(reference, str) or reference not in assignments:
|
|
894
|
-
raise AgentPromptCliError("assignment reference is missing from run manifest")
|
|
895
|
-
expected_assignment = agent_model_assignment_from_payload(assignments[reference])
|
|
896
|
-
elif mode == "standalone":
|
|
897
|
-
if args.run_manifest:
|
|
898
|
-
raise AgentPromptCliError("standalone invocation verification forbids --run-manifest")
|
|
899
|
-
else:
|
|
900
|
-
raise AgentPromptCliError("contract source mode is invalid")
|
|
901
|
-
errors = verify_agent_invocation(
|
|
902
|
-
metadata_path,
|
|
903
|
-
project_root=project_root,
|
|
904
|
-
expected_run_manifest_path=expected_manifest,
|
|
905
|
-
expected_assignment=expected_assignment,
|
|
906
|
-
)
|
|
907
|
-
if errors:
|
|
908
|
-
raise AgentPromptCliError("; ".join(errors))
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
def _materialize_result(args: argparse.Namespace) -> None:
|
|
912
|
-
project_root = _project_root(args.project_root)
|
|
913
|
-
metadata_path = _project_input(project_root, args.metadata, "metadata")
|
|
914
|
-
root = project_root / ".okstra" / "agent-invocations" / args.purpose
|
|
915
|
-
temporary_root = root / ".tmp"
|
|
916
|
-
returned_body_path = _project_input(
|
|
917
|
-
project_root,
|
|
918
|
-
args.returned_body_file,
|
|
919
|
-
"returned body",
|
|
920
|
-
)
|
|
921
|
-
if not temporary_root.is_dir() or not _is_relative_to(
|
|
922
|
-
returned_body_path,
|
|
923
|
-
temporary_root.resolve(strict=True),
|
|
924
|
-
):
|
|
925
|
-
raise AgentPromptCliError(
|
|
926
|
-
"returned body file must be inside the standalone purpose .tmp directory"
|
|
927
|
-
)
|
|
928
|
-
result = materialize_standalone_result(
|
|
929
|
-
project_root=project_root,
|
|
930
|
-
purpose=args.purpose,
|
|
931
|
-
metadata_path=metadata_path,
|
|
932
|
-
returned_body=returned_body_path.read_bytes(),
|
|
933
|
-
)
|
|
934
|
-
_emit({
|
|
935
|
-
"ok": True,
|
|
936
|
-
"purpose": result.purpose,
|
|
937
|
-
"invocationId": result.invocation_id,
|
|
938
|
-
"metadataPath": str(result.prompt_metadata_path),
|
|
939
|
-
"resultPath": str(result.result_path),
|
|
940
|
-
"resultEnvelopeDigest": result.result_envelope_digest,
|
|
941
|
-
}, args.json)
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
def _complete(args: argparse.Namespace) -> None:
|
|
945
|
-
project_root = _project_root(args.project_root)
|
|
946
|
-
metadata_path = _project_input(project_root, args.metadata, "metadata")
|
|
947
|
-
completion = publish_standalone_completion(
|
|
948
|
-
project_root=project_root,
|
|
949
|
-
purpose=args.purpose,
|
|
950
|
-
metadata_path=metadata_path,
|
|
951
|
-
completed_at=datetime.now(timezone.utc),
|
|
952
|
-
)
|
|
953
|
-
_emit({
|
|
954
|
-
"ok": True,
|
|
955
|
-
"purpose": args.purpose,
|
|
956
|
-
"metadataPath": str(metadata_path),
|
|
957
|
-
"completionPath": str(completion),
|
|
958
|
-
}, args.json)
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
def _verify_completion(args: argparse.Namespace) -> None:
|
|
962
|
-
project_root = _project_root(args.project_root)
|
|
963
|
-
completion_path = _project_input(
|
|
964
|
-
project_root,
|
|
965
|
-
args.completion,
|
|
966
|
-
"completion",
|
|
967
|
-
)
|
|
968
|
-
verified = verify_standalone_completion(
|
|
969
|
-
completion_path,
|
|
970
|
-
project_root=project_root,
|
|
971
|
-
expected_purpose=args.purpose,
|
|
972
|
-
)
|
|
973
|
-
_emit({
|
|
974
|
-
"ok": True,
|
|
975
|
-
"purpose": verified.purpose,
|
|
976
|
-
"invocationId": verified.invocation_id,
|
|
977
|
-
"metadataPath": str(verified.prompt_metadata_path),
|
|
978
|
-
"resultPath": str(verified.result_path),
|
|
979
|
-
"completionPath": str(verified.completion_path),
|
|
980
|
-
"resultEnvelopeDigest": verified.result_envelope_digest,
|
|
981
|
-
"returnedBody": verified.returned_body,
|
|
982
|
-
}, args.json)
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
def _authorized_path(
|
|
986
|
-
project_root: Path,
|
|
987
|
-
raw_path: str,
|
|
988
|
-
raw_roots: object,
|
|
989
|
-
label: str,
|
|
990
|
-
*,
|
|
991
|
-
must_exist: bool,
|
|
992
|
-
) -> Path:
|
|
993
|
-
if not isinstance(raw_roots, list) or not raw_roots:
|
|
994
|
-
raise AgentPromptCliError(f"run manifest has no authorized {label} roots")
|
|
995
|
-
path = _candidate(project_root, raw_path, must_exist=must_exist, label=label)
|
|
996
|
-
roots = [
|
|
997
|
-
_project_manifest_path(project_root, value, f"{label} root", must_exist=True)
|
|
998
|
-
for value in raw_roots
|
|
999
|
-
]
|
|
1000
|
-
if not any(_is_relative_to(path, root) for root in roots):
|
|
1001
|
-
raise AgentPromptCliError(f"{label} path is outside authorized roots: {path}")
|
|
1002
|
-
return path
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
def _candidate(project_root: Path, raw: str, *, must_exist: bool, label: str) -> Path:
|
|
1006
|
-
candidate = Path(raw)
|
|
1007
|
-
if not candidate.is_absolute():
|
|
1008
|
-
candidate = project_root / candidate
|
|
1009
|
-
try:
|
|
1010
|
-
if must_exist or candidate.exists() or candidate.is_symlink():
|
|
1011
|
-
return candidate.resolve(strict=True)
|
|
1012
|
-
return candidate.parent.resolve(strict=True) / candidate.name
|
|
1013
|
-
except OSError as exc:
|
|
1014
|
-
raise AgentPromptCliError(f"{label} path is invalid: {candidate}") from exc
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
def _project_input(project_root: Path, raw: str, label: str) -> Path:
|
|
1018
|
-
path = _candidate(project_root, raw, must_exist=True, label=label)
|
|
1019
|
-
if not _is_relative_to(path, project_root):
|
|
1020
|
-
raise AgentPromptCliError(f"{label} path escapes project root: {path}")
|
|
1021
|
-
return path
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
def _project_manifest_path(
|
|
1025
|
-
project_root: Path,
|
|
1026
|
-
value: object,
|
|
1027
|
-
label: str,
|
|
1028
|
-
*,
|
|
1029
|
-
must_exist: bool,
|
|
1030
|
-
) -> Path:
|
|
1031
|
-
if not isinstance(value, str) or not value:
|
|
1032
|
-
raise AgentPromptCliError(f"{label} path is invalid")
|
|
1033
|
-
pure = PurePosixPath(value)
|
|
1034
|
-
if pure.is_absolute() or any(part in {"", ".", ".."} for part in pure.parts):
|
|
1035
|
-
raise AgentPromptCliError(f"{label} path is invalid")
|
|
1036
|
-
path = _candidate(project_root, value, must_exist=must_exist, label=label)
|
|
1037
|
-
if not _is_relative_to(path, project_root):
|
|
1038
|
-
raise AgentPromptCliError(f"{label} path escapes project root: {path}")
|
|
1039
|
-
return path
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
def _exact_path(raw: str, expected: Path, must_exist: bool, label: str) -> Path:
|
|
1043
|
-
actual = (
|
|
1044
|
-
Path(raw).resolve(strict=True)
|
|
1045
|
-
if must_exist
|
|
1046
|
-
else Path(raw).parent.resolve(strict=True) / Path(raw).name
|
|
1047
|
-
)
|
|
1048
|
-
expected_actual = (
|
|
1049
|
-
expected.resolve(strict=True)
|
|
1050
|
-
if must_exist
|
|
1051
|
-
else expected.parent.resolve(strict=True) / expected.name
|
|
1052
|
-
)
|
|
1053
|
-
if actual != expected_actual:
|
|
1054
|
-
raise AgentPromptCliError(f"{label} does not use canonical standalone path")
|
|
1055
|
-
return actual
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
def _project_root(value: str) -> Path:
|
|
1059
|
-
try:
|
|
1060
|
-
return Path(value).resolve(strict=True)
|
|
1061
|
-
except OSError as exc:
|
|
1062
|
-
raise AgentPromptCliError(f"project root not found: {value}") from exc
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
def _relative(project_root: Path, path: Path) -> str:
|
|
1066
|
-
try:
|
|
1067
|
-
return path.relative_to(project_root).as_posix()
|
|
1068
|
-
except ValueError as exc:
|
|
1069
|
-
raise AgentPromptCliError(f"path escapes project root: {path}") from exc
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
def _read_json_object(path: Path, label: str) -> dict[str, Any]:
|
|
1073
|
-
try:
|
|
1074
|
-
value = load_owned_object(path, artifact="agent prompt metadata")
|
|
1075
|
-
except JsonBoundaryError as exc:
|
|
1076
|
-
raise AgentPromptCliError(f"{label} is invalid: {path}") from exc
|
|
1077
|
-
if not isinstance(value, dict):
|
|
1078
|
-
raise AgentPromptCliError(f"{label} must be a JSON object: {path}")
|
|
1079
|
-
return value
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
def _mapping(value: object, label: str) -> Mapping[str, Any]:
|
|
1083
|
-
if not isinstance(value, Mapping):
|
|
1084
|
-
raise AgentPromptCliError(f"{label} is missing or invalid")
|
|
1085
|
-
return value
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
def _is_relative_to(path: Path, root: Path) -> bool:
|
|
1089
|
-
try:
|
|
1090
|
-
path.relative_to(root)
|
|
1091
|
-
except ValueError:
|
|
1092
|
-
return False
|
|
1093
|
-
return True
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
def _is_slug(value: str) -> bool:
|
|
1097
|
-
if not value or value.startswith("-") or value.endswith("-"):
|
|
1098
|
-
return False
|
|
1099
|
-
return all(part.isalnum() and part.lower() == part for part in value.split("-"))
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
def _prepared_payload(
|
|
1103
|
-
prepared: PreparedAgentInvocation,
|
|
1104
|
-
audience: str,
|
|
1105
|
-
) -> dict[str, object]:
|
|
1106
|
-
assignment = prepared.assignment
|
|
1107
|
-
return {
|
|
1108
|
-
"ok": True,
|
|
1109
|
-
"invocationId": prepared.invocation_id,
|
|
1110
|
-
"workerId": prepared.worker_id,
|
|
1111
|
-
"assignmentRef": prepared.assignment_ref,
|
|
1112
|
-
"audience": audience,
|
|
1113
|
-
"promptPath": str(prepared.prompt_path),
|
|
1114
|
-
"metadataPath": str(prepared.metadata_path),
|
|
1115
|
-
"modelAssignment": {
|
|
1116
|
-
"provider": assignment.provider,
|
|
1117
|
-
"model": assignment.model,
|
|
1118
|
-
"modelExecutionValue": assignment.model_execution_value,
|
|
1119
|
-
"runner": assignment.runner,
|
|
1120
|
-
"hostRuntime": assignment.host_runtime,
|
|
1121
|
-
"hostModelValue": assignment.host_model_value,
|
|
1122
|
-
},
|
|
1123
|
-
"digests": {
|
|
1124
|
-
"catalogDigest": prepared.catalog_digest,
|
|
1125
|
-
"assignmentDigest": prepared.assignment_digest,
|
|
1126
|
-
"dutyDigest": prepared.duty_digest,
|
|
1127
|
-
"instructionDigest": prepared.instruction_digest,
|
|
1128
|
-
"promptDigest": prepared.prompt_digest,
|
|
1129
|
-
},
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
def _emit(
|
|
1134
|
-
payload: Mapping[str, object], as_json: bool, as_text: bool = False
|
|
1135
|
-
) -> None:
|
|
1136
|
-
if as_json:
|
|
1137
|
-
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
1138
|
-
elif as_text:
|
|
1139
|
-
print(render_agent_prompt_text(payload), end="")
|
|
1140
|
-
else:
|
|
1141
|
-
print(payload.get("promptPath") or payload.get("metadataPath") or "ok")
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
def render_agent_prompt_text(payload: Mapping[str, object]) -> str:
|
|
1145
|
-
"""agent prompt 검증 결과의 승인된 경로만 투영한다."""
|
|
1146
|
-
rows = ["Okstra agent prompt\n"]
|
|
1147
|
-
rows.append(line("Status", "ready" if payload.get("ok", True) else "error"))
|
|
1148
|
-
for label, key in (("Prompt path", "promptPath"), ("Metadata path", "metadataPath"),
|
|
1149
|
-
("Assignment ID", "assignmentId"), ("Worker role", "workerRole")):
|
|
1150
|
-
if key in payload:
|
|
1151
|
-
rows.append(line(label, payload.get(key)))
|
|
1152
|
-
return "".join(rows)
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
if __name__ == "__main__":
|
|
1156
|
-
raise SystemExit(main())
|