@iowarp/clio-coder 0.3.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/CHANGELOG.md +407 -0
- package/CODE_OF_CONDUCT.md +21 -0
- package/CONTRIBUTING.md +224 -0
- package/LICENSE +202 -0
- package/NOTICE +9 -0
- package/README.md +798 -0
- package/SECURITY.md +72 -0
- package/assets/clio-coder-logo-128.webp +0 -0
- package/damage-control-rules.yaml +419 -0
- package/dist/acp-UMLFVA3F.js +92 -0
- package/dist/agents-Q4MYPMUW.js +91 -0
- package/dist/auth-O6HYIJ6J.js +521 -0
- package/dist/chunk-262G75JS.js +35 -0
- package/dist/chunk-26BZQOAD.js +1281 -0
- package/dist/chunk-2J63S4SF.js +508 -0
- package/dist/chunk-3DANZDGR.js +717 -0
- package/dist/chunk-4UQA7NCT.js +29 -0
- package/dist/chunk-527KG6XR.js +497 -0
- package/dist/chunk-5LDRNKX2.js +1063 -0
- package/dist/chunk-5N2FG33Q.js +25 -0
- package/dist/chunk-67MTHP2E.js +135 -0
- package/dist/chunk-6CWDTGUC.js +20 -0
- package/dist/chunk-7BHLZB3A.js +2115 -0
- package/dist/chunk-7RBKDI66.js +348 -0
- package/dist/chunk-AMFR5YA3.js +541 -0
- package/dist/chunk-BBUH4VAA.js +1224 -0
- package/dist/chunk-BYEU76JP.js +899 -0
- package/dist/chunk-CLJ5HLUD.js +458 -0
- package/dist/chunk-D5YD55AR.js +116 -0
- package/dist/chunk-DXQNI4PC.js +61 -0
- package/dist/chunk-E3NYWENM.js +1004 -0
- package/dist/chunk-GNGDQYDU.js +34688 -0
- package/dist/chunk-GOTUR54M.js +9 -0
- package/dist/chunk-HBU5MTAM.js +41 -0
- package/dist/chunk-HMYNFFY4.js +28 -0
- package/dist/chunk-JPOWPFCU.js +1010 -0
- package/dist/chunk-JWHCJDCI.js +1215 -0
- package/dist/chunk-KBR4MZZR.js +41 -0
- package/dist/chunk-KKKPTZLM.js +93 -0
- package/dist/chunk-ME6DNWIU.js +66 -0
- package/dist/chunk-NI4DEJMC.js +88 -0
- package/dist/chunk-O4EJEDHO.js +659 -0
- package/dist/chunk-PIDUD6M2.js +31 -0
- package/dist/chunk-PS4PFJQP.js +29459 -0
- package/dist/chunk-QV47YRF4.js +48 -0
- package/dist/chunk-RQDWMVRB.js +279 -0
- package/dist/chunk-TFSSEXL6.js +136 -0
- package/dist/chunk-TKHQ4DGZ.js +8290 -0
- package/dist/chunk-TPOCL34A.js +2876 -0
- package/dist/chunk-UGYAX5YI.js +565 -0
- package/dist/chunk-UHTSULZS.js +461 -0
- package/dist/chunk-UU3R62TT.js +128 -0
- package/dist/chunk-UWIJNAOB.js +3906 -0
- package/dist/chunk-VOO7NYPP.js +914 -0
- package/dist/chunk-VPAWTYLY.js +117 -0
- package/dist/chunk-WD6AJM35.js +1216 -0
- package/dist/chunk-X3BR7HWV.js +115 -0
- package/dist/chunk-X3NE4WVW.js +120 -0
- package/dist/chunk-XNISANGE.js +1395 -0
- package/dist/chunk-XV4ZJ6ZM.js +3177 -0
- package/dist/cli/index.js +236 -0
- package/dist/clio-KIQ5SNDS.js +53 -0
- package/dist/components-JVHMUBEB.js +653 -0
- package/dist/config-ZFCDBMDC.js +372 -0
- package/dist/configure-G4E3A2PG.js +27 -0
- package/dist/context-CDXTP2MP.js +293 -0
- package/dist/context-E3KIFVXI.js +185 -0
- package/dist/context-clear-3F4PLXOS.js +102 -0
- package/dist/context-index-Q7YSYTR3.js +106 -0
- package/dist/docs-YIETIWZI.js +280 -0
- package/dist/doctor-M5HJJZOL.js +61 -0
- package/dist/domains/agents/builtins/architect.md +33 -0
- package/dist/domains/agents/builtins/coder.md +31 -0
- package/dist/domains/agents/builtins/context-bootstrap.md +38 -0
- package/dist/domains/agents/builtins/debugger.md +30 -0
- package/dist/domains/agents/builtins/documenter.md +31 -0
- package/dist/domains/agents/builtins/git-master.md +30 -0
- package/dist/domains/agents/builtins/provenance.md +30 -0
- package/dist/domains/agents/builtins/researcher.md +71 -0
- package/dist/domains/agents/builtins/scout.md +42 -0
- package/dist/domains/agents/builtins/tester.md +31 -0
- package/dist/domains/agents/builtins/verifier.md +30 -0
- package/dist/domains/agents/builtins/wiki-writer.md +41 -0
- package/dist/eval-B3KZZESM.js +2674 -0
- package/dist/evidence-V67CHM35.js +233 -0
- package/dist/evolve-YDZSUQYA.js +518 -0
- package/dist/extensions-SRG7XCAH.js +207 -0
- package/dist/fleet-CA2CRTVG.js +760 -0
- package/dist/fleet-preflight-CLIAX7YR.js +21 -0
- package/dist/init-2OZDJE2D.js +227 -0
- package/dist/memory-3PIQQAKX.js +207 -0
- package/dist/models-DY35XI7Y.js +237 -0
- package/dist/paths-5OMXW7Z4.js +57 -0
- package/dist/preload-KZVHET2B.js +11 -0
- package/dist/reset-PIFYNOS3.js +216 -0
- package/dist/run-3VSPP24F.js +735 -0
- package/dist/share-D36RQCXM.js +241 -0
- package/dist/skills-F2MRLELY.js +445 -0
- package/dist/skills-eval-E2ZTW4PL.js +932 -0
- package/dist/targets-DZMEZAH4.js +977 -0
- package/dist/trace-7NYCUI2J.js +250 -0
- package/dist/uninstall-AD3JWHBB.js +322 -0
- package/dist/upgrade-WYYBKGDY.js +301 -0
- package/dist/usage-ULIDAGFF.js +755 -0
- package/dist/version-ROZ6CZKH.js +16 -0
- package/dist/wiki-generate-PKFIX6OB.js +377 -0
- package/dist/worker/entry.js +1739 -0
- package/docs/README.md +93 -0
- package/docs/acp.md +120 -0
- package/docs/alcf-provider.md +72 -0
- package/docs/architecture.md +172 -0
- package/docs/artifact-versions.md +54 -0
- package/docs/built-in-agents.md +265 -0
- package/docs/capacity-and-scheduling.md +97 -0
- package/docs/commands-and-modes.md +554 -0
- package/docs/config-knobs-audit.md +115 -0
- package/docs/configuration-and-targets.md +812 -0
- package/docs/context-engine.md +236 -0
- package/docs/dispatch-architecture-rationale.md +126 -0
- package/docs/documentation-coverage.md +46 -0
- package/docs/documentation-guide.md +166 -0
- package/docs/environment-variables.md +105 -0
- package/docs/eval-runner.md +205 -0
- package/docs/evals-internal.md +298 -0
- package/docs/evidence-and-memory.md +243 -0
- package/docs/evolution.md +143 -0
- package/docs/exit-codes-and-output.md +74 -0
- package/docs/extensions-and-sharing.md +306 -0
- package/docs/fleet-demo-runbook.md +179 -0
- package/docs/fleet-dispatch.md +591 -0
- package/docs/glossary.md +75 -0
- package/docs/html/agents_blueprint.html +936 -0
- package/docs/html/alcf_blueprint.html +324 -0
- package/docs/html/architecture_blueprint.html +850 -0
- package/docs/html/commands_blueprint.html +794 -0
- package/docs/html/config_knobs_audit_blueprint.html +178 -0
- package/docs/html/configuration_blueprint.html +1080 -0
- package/docs/html/context_blueprint.html +603 -0
- package/docs/html/documentation_blueprint.html +832 -0
- package/docs/html/environment_blueprint.html +404 -0
- package/docs/html/eval_blueprint.html +743 -0
- package/docs/html/evals_internal_blueprint.html +190 -0
- package/docs/html/evolution_blueprint.html +674 -0
- package/docs/html/extensions_blueprint.html +2065 -0
- package/docs/html/fleet_dispatch_blueprint.html +286 -0
- package/docs/html/index.html +919 -0
- package/docs/html/lifecycle_blueprint.html +723 -0
- package/docs/html/memory_blueprint.html +699 -0
- package/docs/html/middleware_blueprint.html +664 -0
- package/docs/html/models_blueprint.html +2366 -0
- package/docs/html/observability_blueprint.html +683 -0
- package/docs/html/provider_adapter_blueprint.html +245 -0
- package/docs/html/safety_blueprint.html +1386 -0
- package/docs/html/shared.css +571 -0
- package/docs/html/shared.js +143 -0
- package/docs/html/skills_blueprint.html +671 -0
- package/docs/html/soak_blueprint.html +182 -0
- package/docs/html/tool_usage_blueprint.html +350 -0
- package/docs/html/tools_blueprint.html +2249 -0
- package/docs/html/trace_blueprint.html +235 -0
- package/docs/html/tui_design_blueprint.html +314 -0
- package/docs/html/validation_blueprint.html +961 -0
- package/docs/html/worker_dispatch_blueprint.html +231 -0
- package/docs/installation-and-lifecycle.md +308 -0
- package/docs/middleware-and-components.md +148 -0
- package/docs/model-catalog.md +189 -0
- package/docs/observability.md +233 -0
- package/docs/proactive-memory.md +452 -0
- package/docs/prompt-envelope-and-tools.md +142 -0
- package/docs/provider-adapter-cookbook.md +148 -0
- package/docs/release-cut-checklist.md +138 -0
- package/docs/safety-model.md +357 -0
- package/docs/scientific-validation.md +105 -0
- package/docs/session-lifecycle.md +156 -0
- package/docs/skills-marketplace.md +46 -0
- package/docs/tool-usage.md +527 -0
- package/docs/trace-store.md +132 -0
- package/docs/troubleshooting.md +33 -0
- package/docs/tui-design.md +239 -0
- package/docs/worker-dispatch-mechanics.md +242 -0
- package/package.json +132 -0
- package/skills/README.md +408 -0
- package/skills/git/commit-crafting/SKILL.md +79 -0
- package/skills/git/commit-crafting/evals.md +92 -0
- package/skills/git/create-pr/SKILL.md +116 -0
- package/skills/git/create-pr/evals.md +114 -0
- package/skills/git/investigate-issue/SKILL.md +139 -0
- package/skills/git/investigate-issue/evals.md +94 -0
- package/skills/git/resolve-merge-conflicts/SKILL.md +96 -0
- package/skills/git/resolve-merge-conflicts/evals.md +58 -0
- package/skills/git/review-changes/SKILL.md +103 -0
- package/skills/git/review-changes/evals.md +85 -0
- package/skills/git/worktree-create/SKILL.md +92 -0
- package/skills/git/worktree-create/evals.md +97 -0
- package/skills/git/worktree-create/references/worktree-setup.md +66 -0
- package/skills/git/worktree-merge/SKILL.md +95 -0
- package/skills/git/worktree-merge/evals.md +114 -0
- package/skills/skill-marketplace.json +261 -0
- package/skills/workflow/cut-it/SKILL.md +86 -0
- package/skills/workflow/cut-it/evals.md +42 -0
- package/src/domains/agents/builtins/architect.md +33 -0
- package/src/domains/agents/builtins/coder.md +31 -0
- package/src/domains/agents/builtins/context-bootstrap.md +38 -0
- package/src/domains/agents/builtins/debugger.md +30 -0
- package/src/domains/agents/builtins/documenter.md +31 -0
- package/src/domains/agents/builtins/git-master.md +30 -0
- package/src/domains/agents/builtins/provenance.md +30 -0
- package/src/domains/agents/builtins/researcher.md +71 -0
- package/src/domains/agents/builtins/scout.md +42 -0
- package/src/domains/agents/builtins/tester.md +31 -0
- package/src/domains/agents/builtins/verifier.md +30 -0
- package/src/domains/agents/builtins/wiki-writer.md +41 -0
- package/src/domains/agents/fleets/build-review.md +34 -0
- package/src/domains/agents/fleets/build-test.md +35 -0
- package/src/domains/agents/fleets/sdlc.md +86 -0
- package/src/domains/prompts/fragments/identity/clio-worker.md +11 -0
- package/src/domains/prompts/fragments/identity/clio.md +26 -0
- package/src/domains/prompts/fragments/operating/contract.md +64 -0
- package/src/domains/prompts/fragments/safety/auto-edit.md +14 -0
- package/src/domains/prompts/fragments/safety/full-auto.md +14 -0
- package/src/domains/prompts/fragments/safety/read-only.md +13 -0
- package/src/domains/prompts/fragments/safety/suggest.md +13 -0
- package/src/domains/prompts/fragments/wiki/page.md +75 -0
- package/src/domains/prompts/fragments/wiki/plan.md +48 -0
- package/src/domains/providers/models/cloud-models/alcf.yaml +40 -0
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +993 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# Worker Dispatch Mechanics
|
|
2
|
+
|
|
3
|
+
> [!TIP]
|
|
4
|
+
> **Interactive Spec Available:** An interactive NDJSON protocol timeline stream and heartbeat watchdog simulator is located at [docs/html/worker_dispatch_blueprint.html](html/worker_dispatch_blueprint.html) (Version: 0.3.0).
|
|
5
|
+
|
|
6
|
+
This document describes the design and lifecycle of Clio Coder dispatched workers, focusing on the spawning sequence, execution isolation, the standard input/output NDJSON communication loop, and permission escalation routing.
|
|
7
|
+
|
|
8
|
+
Source of truth:
|
|
9
|
+
- Subprocess entry: [src/worker/entry.ts](../src/worker/entry.ts)
|
|
10
|
+
- Input demultiplexing: [src/worker/stdin-demux.ts](../src/worker/stdin-demux.ts)
|
|
11
|
+
- Heartbeat loop: [src/worker/heartbeat.ts](../src/worker/heartbeat.ts)
|
|
12
|
+
- Spec contracts and exit codes: [src/worker/spec-contract.ts](../src/worker/spec-contract.ts)
|
|
13
|
+
- Dispatch orchestrator: [src/domains/dispatch/index.ts](../src/domains/dispatch/index.ts)
|
|
14
|
+
- Engine worker runtime: [src/engine/worker-runtime.ts](../src/engine/worker-runtime.ts)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. Spawning Sequence & Environment Isolation
|
|
19
|
+
|
|
20
|
+
When the orchestrator dispatches a task to a fleet agent (such as via the `dispatch` tool or `clio-coder eval` execution), it spins up a child process running the compiled worker entry.
|
|
21
|
+
|
|
22
|
+
1. **Child Process Creation:**
|
|
23
|
+
The parent process spawns a Node.js subprocess pointing to `dist/worker/entry.js`.
|
|
24
|
+
2. **Environment Scrubbing:**
|
|
25
|
+
To ensure clean execution, the child process runs with a sanitized environment. The orchestrator scrubs user-interactive flags (e.g., `CLIO_CODER_INTERACTIVE` is removed from `process.env`) to prevent child workers from attempting to mount TUI elements or intercept standard input signals.
|
|
26
|
+
3. **Spec Injection & Attestation Handshake:**
|
|
27
|
+
The orchestrator serializes a `WorkerSpec` JSON document and writes it as the very first line of `stdin` to the child worker. Before reaching a model, every worker announces its attestation on the structured stderr control lane (`@clio-control/1 ` prefix): protocol version (`WORKER_PROTOCOL_VERSION = 1`), spec version, process ID, process group ID (or null), host, settings fingerprint, worker-computed spec digest (`specDigest`), runtime ID, target ID, endpoint identity hash (`endpointIdentityHash`), wire model ID, effective tool signature, and bounded node resource facts (labels, CPU count, total memory, free memory, GPU count, VRAM, and resident models). The orchestrator compares each field against the approved plan and terminates a drifting peer instead of running it. Bulk NDJSON on `stdout` is accepted only once that attestation verifies.
|
|
28
|
+
|
|
29
|
+
```mermaid
|
|
30
|
+
sequenceDiagram
|
|
31
|
+
participant Orchestrator
|
|
32
|
+
participant WorkerSubprocess as Worker (entry.ts)
|
|
33
|
+
participant Engine as Engine (worker-runtime.ts)
|
|
34
|
+
|
|
35
|
+
Orchestrator->>WorkerSubprocess: Spawn (node entry.js)
|
|
36
|
+
Orchestrator->>WorkerSubprocess: Send WorkerSpec (NDJSON on stdin)
|
|
37
|
+
WorkerSubprocess->>Orchestrator: announce control frame (stderr @clio-control/1)
|
|
38
|
+
Note over WorkerSubprocess: Starts heartbeat on stderr control lane
|
|
39
|
+
WorkerSubprocess->>Engine: startWorkerRun(input)
|
|
40
|
+
loop Execution Loop
|
|
41
|
+
Engine->>WorkerSubprocess: Emit event
|
|
42
|
+
WorkerSubprocess->>Orchestrator: NDJSON event (stdout bulk lane)
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 2. Standard Input/Output NDJSON Protocol
|
|
49
|
+
|
|
50
|
+
Dispatched workers are non-interactive. Coordination between the orchestrator and the worker occurs across two dedicated communication lanes plus standard input:
|
|
51
|
+
|
|
52
|
+
### 2.1 Worker Output Lanes
|
|
53
|
+
|
|
54
|
+
Clio divides worker output into two isolated streams to protect control signals from bulk data starvation:
|
|
55
|
+
|
|
56
|
+
1. **Bulk Lane (`stdout`)**:
|
|
57
|
+
Streams turn execution events as single-line NDJSON objects, capped by `WORKER_BULK_FRAME_MAX_BYTES` (4 MiB). To prevent quadratic payload explosion during streaming, `projectWorkerEventForStdout` (`src/worker/event-projection.ts`) slims `message_update` events by stripping cumulative message snapshots before emission. Major event kinds on stdout include:
|
|
58
|
+
* **Logs / Stream chunks:** Output segments generated by the model during a turn.
|
|
59
|
+
* **Tool Invocation:** Requests to run specific tools.
|
|
60
|
+
* **Permission Escalation:** Emitted when a tool requires approval under the `escalate` posture.
|
|
61
|
+
* **Completion / Failure:** Marks the final state of the run, providing execution receipts.
|
|
62
|
+
|
|
63
|
+
2. **Control Lane (`stderr`)**:
|
|
64
|
+
Emits out-of-band control frames prefixed by `@clio-control/1 `, capped at `WORKER_CONTROL_FRAME_MAX_BYTES` (16 KiB). Because control frames travel over `stderr`, they bypass backpressured bulk stdout streams and reach orchestrator watchdogs immediately. Control frame kinds include:
|
|
65
|
+
* **Announce:** `{"kind": "announce", "attestation": ...}` sent immediately upon startup.
|
|
66
|
+
* **Heartbeat:** `{"kind": "heartbeat", "at": 1720186123000}` emitted every 1000 milliseconds.
|
|
67
|
+
* **Steer / Cancel Acknowledgments:** Confirming reception of stdin control directives.
|
|
68
|
+
|
|
69
|
+
### 2.2 Worker Input (`stdin`)
|
|
70
|
+
The worker entry mounts a custom stdin demultiplexer (`createWorkerStdinDemux`) that parses lines arriving after the initial `WorkerSpec`. It processes two types of JSON messages:
|
|
71
|
+
1. **Steering Commands:**
|
|
72
|
+
`{"type": "steer", "text": "guidance message", "sequence": 1}`
|
|
73
|
+
Instructs a live-input HTTP or SDK worker to alter course. Its runtime emits
|
|
74
|
+
the receipt-bearing `clio_steer_received` event only after accepting the
|
|
75
|
+
message for the next turn boundary. Single-shot subprocess runtimes install
|
|
76
|
+
no steering handler, drop unexpected guidance without claiming receipt, and
|
|
77
|
+
are not offered steering by the dispatch contract or TUI.
|
|
78
|
+
2. **Permission Decisions:**
|
|
79
|
+
`{"type": "permission_decision", "requestId": "req-xxx", "decision": "approve"|"deny"}`
|
|
80
|
+
Resolves a parked tool call that was escalated to the operator.
|
|
81
|
+
|
|
82
|
+
Any stdin chunk that is not a valid JSON structure matching these schemas is logged as a dropped line and does not crash the worker.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 3. Heartbeats and the Watchdog
|
|
87
|
+
|
|
88
|
+
Even when a model is processing a long thinking phase or generating a heavy output, the worker must prove it is alive to prevent the parent orchestrator's watchdog from reclaiming it.
|
|
89
|
+
|
|
90
|
+
* **Emission:** The heartbeat loop (`startWorkerHeartbeat` in `src/worker/heartbeat.ts`) writes a heartbeat control frame (`{"kind": "heartbeat", "at": ...}`) to the `stderr` control lane every 1000 milliseconds.
|
|
91
|
+
* **Stream Isolation:** Because heartbeats ride the control lane rather than `stdout`, a large bulk output or queued tool result cannot starve or delay the watchdog check.
|
|
92
|
+
* **Non-Blocking Timer:** The heartbeat timer interval is explicitly `.unref()`'d, ensuring the Node.js runtime is not kept alive past the natural lifetime of the worker run.
|
|
93
|
+
* **Termination:** Once `startWorkerRun` resolves, the timer is cleared before returning the worker's exit code.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 4. Permission Escalation and Parking
|
|
98
|
+
|
|
99
|
+
When a tool requires explicit confirmation (for example executing a mutating file change or running a bash command at `suggest` autonomy), the worker evaluates `onPermission`:
|
|
100
|
+
|
|
101
|
+
```mermaid
|
|
102
|
+
stateDiagram-v2
|
|
103
|
+
[*] --> CheckPermission
|
|
104
|
+
CheckPermission --> DenyPosture : onPermission = "deny"
|
|
105
|
+
CheckPermission --> FailPosture : onPermission = "fail"
|
|
106
|
+
CheckPermission --> EscalatePosture : onPermission = "escalate"
|
|
107
|
+
|
|
108
|
+
DenyPosture --> ToolDenied : Return structured denial to model
|
|
109
|
+
FailPosture --> AbortRun : Exit process with code 3 (WORKER_EXIT_PERMISSION_REQUIRED)
|
|
110
|
+
|
|
111
|
+
state EscalatePosture {
|
|
112
|
+
[*] --> ParkCall
|
|
113
|
+
ParkCall --> EmitEscalatedEvent : stdout <- clio_permission_escalated
|
|
114
|
+
EmitEscalatedEvent --> WaitForInput
|
|
115
|
+
WaitForInput --> ResolveApprove : stdin -> permission_decision (approve)
|
|
116
|
+
WaitForInput --> ResolveDeny : stdin -> permission_decision (deny)
|
|
117
|
+
WaitForInput --> TimeoutFallback : timeoutMs reached
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
ResolveApprove --> RunTool : Execute tool
|
|
121
|
+
ResolveDeny --> ToolDenied : Return structured denial to model
|
|
122
|
+
TimeoutFallback --> ApplyFallback : Apply fallback posture (deny | fail)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
1. **Deny:** Immediately returns a structured denial to the model, allowing the run to continue without making the call.
|
|
126
|
+
2. **Fail:** Terminate the run immediately, exiting the worker subprocess with exit code `3` (`WORKER_EXIT_PERMISSION_REQUIRED`).
|
|
127
|
+
3. **Escalate (Parking Loop):**
|
|
128
|
+
- The worker parks the tool execution thread.
|
|
129
|
+
- It generates a unique `requestId` and emits a `clio_permission_escalated` event to `stdout`.
|
|
130
|
+
- The parent process intercepts this event, displays the approval prompt in the interactive TUI, and waits for the operator.
|
|
131
|
+
- If the operator selects approve or deny, the parent writes `{"type":"permission_decision", "requestId":"...", "decision":"..."}` to the worker's `stdin`.
|
|
132
|
+
- The demuxer resolves the parked promise, resuming tool execution.
|
|
133
|
+
- **Timeout Safety:** If no decision arrives within `escalation.timeoutMs` (default `120000` ms), the worker resumes and applies the `escalation.fallback` posture (default `deny`). If running headlessly (no operator attached) or on runtimes that cannot support park loops, the posture collapses to the fallback immediately.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 5. Assignment-aware retry and failover
|
|
138
|
+
|
|
139
|
+
A worker process produces one immutable **attempt**. Dispatch groups attempts
|
|
140
|
+
under a logical **assignment** whose id is the first attempt's
|
|
141
|
+
`lineage.rootRunId`. Attached and batch `finalPromise` handles resolve to the
|
|
142
|
+
terminal attempt receipt, not to an earlier failure that happened to trigger a
|
|
143
|
+
retry. Receipt bytes and integrity versions remain unchanged; assignment state
|
|
144
|
+
is maintained separately in `assignments.json` with the attempt ids, terminal
|
|
145
|
+
run id, and status.
|
|
146
|
+
|
|
147
|
+
Detached `monitor collect` resolves the assignment's terminal run and returns
|
|
148
|
+
its complete `attemptRunIds` history. `status`, `wait`, `steer`, permission
|
|
149
|
+
resolution, and cancellation also accept the assignment id and address the
|
|
150
|
+
current attempt. Cancellation prevents queued or future attempts. Pipelines
|
|
151
|
+
therefore receive terminal fallback output as their next-stage input.
|
|
152
|
+
|
|
153
|
+
The assignment also owns the event stream. `dispatch()` returns a single
|
|
154
|
+
stream carrying every attempt's frames in order, separated by a synthetic
|
|
155
|
+
`attempt_start` frame (`attempt`, `runId`, `previousRunId`, `reason`). The
|
|
156
|
+
stream ends when the assignment settles, not when one attempt's worker exits,
|
|
157
|
+
so a consumer that drains it has seen exactly the run the terminal receipt
|
|
158
|
+
describes. A canceled assignment ends its stream immediately.
|
|
159
|
+
|
|
160
|
+
Retry timing is governed by `workers.maxRetries` and exponential backoff alone.
|
|
161
|
+
Target cooldowns gate *new* dispatches to a known-bad target and are not
|
|
162
|
+
applied to retries of an in-flight assignment, whose retry budget already
|
|
163
|
+
bounds it. A retry refused at admission settles the assignment failed and
|
|
164
|
+
records the denial reason in the assignment's `outcomeDetail`.
|
|
165
|
+
|
|
166
|
+
Retry also requires evidence that reusing the same checkout is safe. Each
|
|
167
|
+
receipt seals `safety.toolTelemetry`: coverage is `complete`, `partial`, or
|
|
168
|
+
`unavailable`, with ingestion errors and unmatched tool starts preserved.
|
|
169
|
+
Dispatch suppresses automatic retry after an executed state-changing call,
|
|
170
|
+
after an unfinished state-changing call, or when an opaque mutation-capable
|
|
171
|
+
runtime cannot prove that the failed attempt left the workspace unchanged.
|
|
172
|
+
Claude CLI runs technically constrained to read-only tools retain retries;
|
|
173
|
+
mutation-capable subprocess and ACP runs fail closed until isolated retry
|
|
174
|
+
workspaces exist.
|
|
175
|
+
|
|
176
|
+
Failover modes are:
|
|
177
|
+
|
|
178
|
+
- `none`: exact pins remain fail-closed; retries can only repeat the same tuple.
|
|
179
|
+
- `approved`: candidates must be exact members of the operator-approved
|
|
180
|
+
agent/target/model/node envelope.
|
|
181
|
+
- `automatic`: typed failures may replace only implicated route parts. Node
|
|
182
|
+
channel failure excludes the node; target rate limiting excludes the target.
|
|
183
|
+
|
|
184
|
+
Operator cancellation, policy rejection, permission refusal, and deterministic
|
|
185
|
+
task failures do not retry. The first three are neutral to target/node
|
|
186
|
+
infrastructure breakers.
|
|
187
|
+
|
|
188
|
+
### 5.1 Failure Taxonomy & Route Exclusion
|
|
189
|
+
|
|
190
|
+
The coordinator classifies failures into 13 explicit categories (`src/domains/dispatch/failure-classification.ts`) to determine which route parts (`agent`, `target`, `model`, `node`, `runtime`) are excluded during an assignment retry:
|
|
191
|
+
|
|
192
|
+
| Failure Class | Trigger Pattern / Exit Code | Excluded Route Part | Retryable? |
|
|
193
|
+
| --- | --- | --- | --- |
|
|
194
|
+
| `operator-cancel` | User abort, `canceled` outcome | None (Neutral) | No |
|
|
195
|
+
| `policy` | Policy denial, `denied_by_policy` | None (Neutral) | No |
|
|
196
|
+
| `permission` | `WORKER_EXIT_PERMISSION_REQUIRED` (code 3) | None (Neutral) | No |
|
|
197
|
+
| `deterministic-task` | `isDeterministicOutcomeCode()` (e.g. `result_contract_exhausted`) | None | No |
|
|
198
|
+
| `model-quality` | Quality gate failure | `agent, model` | Yes |
|
|
199
|
+
| `node-channel` | Stall killed, `spawn_failed`, SSH exit code 255 | `node` | Yes |
|
|
200
|
+
| `node-resource` | VRAM/GPU OOM error pattern | `node` | Yes |
|
|
201
|
+
| `target-auth` | HTTP 401/403, invalid API key | `target` | Yes |
|
|
202
|
+
| `target-rate-limit` | HTTP 429, rate limit error pattern | `target` | Yes (Delayed) |
|
|
203
|
+
| `target-transient` | Timeout, HTTP 502/503/504 | `target` | Yes |
|
|
204
|
+
| `capacity` | Queue full / overload pattern | `node` | Yes |
|
|
205
|
+
| `worker-runtime` | `failed` outcome after more-specific classifiers do not match | `runtime` | Yes |
|
|
206
|
+
| `internal` | No more-specific termination evidence; coordinator fallback | None | Yes |
|
|
207
|
+
|
|
208
|
+
### 5.2 Canonical Receipt Integrity Serialization
|
|
209
|
+
|
|
210
|
+
Receipts carry exactly one integrity version (`RUN_RECEIPT_INTEGRITY_VERSION = 15`); any other version is invalid. It computes a cryptographic SHA-256 digest over a strictly sorted, canonical JSON representation (`serializeCanonical` in `src/domains/dispatch/receipt-integrity.ts`).
|
|
211
|
+
|
|
212
|
+
- **Object Key Sorting**: Keys are sorted lexicographically before serialization (`Object.keys(obj).sort()`).
|
|
213
|
+
- **Strict Primitive Handling**: `undefined` object properties are omitted; non-finite numbers (`NaN`, `Infinity`) or `bigint` throw an explicit serialization error.
|
|
214
|
+
- **Coverage**: Includes every current receipt field and reconstructible ledger field, including route intent/decision/quality, execution role, worker identity, result-contract conformance, node/reroute/gate/plan provenance, briefing, steering, and `outcomeCode`.
|
|
215
|
+
|
|
216
|
+
### 5.3 Acceptance Coverage
|
|
217
|
+
|
|
218
|
+
The assignment contract's acceptance scenarios map to deterministic contract
|
|
219
|
+
tests as follows:
|
|
220
|
+
|
|
221
|
+
| # | Scenario | Contract test |
|
|
222
|
+
| --- | --- | --- |
|
|
223
|
+
| 1 | Remote stall, approved local fallback, attached success | `dispatch-envelope.test.ts`: "falls back from remote to local only within an approved envelope" |
|
|
224
|
+
| 2 | Detached collection returns successful terminal fallback | `dispatch-assignment-detached.test.ts`: "collects the terminal retry…" |
|
|
225
|
+
| 3 | Pipeline consumes terminal fallback output | `dispatch-assignment-detached.test.ts`: "threads the successful retry output…" |
|
|
226
|
+
| 4 | Failed attempt remains visible and integrity-verifiable | `dispatch-assignment.test.ts`: "resolves attached dispatch…" (also covered by detached collection) |
|
|
227
|
+
| 5 | Cancellation starts no retry | `dispatch-assignment.test.ts`: "canceling the root attempt starts no retry" |
|
|
228
|
+
| 6 | Cancellation does not cool the target | `dispatch-failure-class.test.ts`: "keeps cancellation and permission neutral…" |
|
|
229
|
+
| 7 | Permission/policy rejection is retry- and breaker-neutral | `dispatch-failure-class.test.ts`: classification/decision table and neutral-target test |
|
|
230
|
+
| 8 | Node-channel failure changes node but retains model | `dispatch-failure-class.test.ts`: "moves only the node…" |
|
|
231
|
+
| 9 | Rate limit retains agent/model and delays or changes target | `dispatch-failure-class.test.ts`: "changes target after rate limiting…" |
|
|
232
|
+
| 10 | Exhaustion returns one failure with all attempt receipts | `dispatch-assignment.test.ts`: "settles exhausted retries…" |
|
|
233
|
+
| 11 | Exact manual pin never falls back | `dispatch-envelope.test.ts`: "keeps a manual exact pin fail-closed…" |
|
|
234
|
+
| 12 | Approved envelope never spawns outside its candidate list | `dispatch-envelope.test.ts`: "settles failed instead of spawning an unlisted candidate" |
|
|
235
|
+
|
|
236
|
+
## 6. Worker Exit Codes
|
|
237
|
+
|
|
238
|
+
The child process exits with specific status codes to signal run outcomes to the orchestrator:
|
|
239
|
+
* **`0`**: The worker process completed without a runtime error; dispatch still requires a nonempty receipt-sealed final answer before classifying the run as successful.
|
|
240
|
+
* **`2`**: Worker runtime initialization failed (e.g., target runtime not registered, or `WorkerSpec` invalid/mismatched).
|
|
241
|
+
* **`3` (`WORKER_EXIT_PERMISSION_REQUIRED`)**: The run aborted because a tool required permission and `onPermission` was set to `fail` (or timed out to a `fail` fallback).
|
|
242
|
+
* **Other (e.g., `1` or uncaught exceptions)**: Represents an unhandled crash or internal error within the runner.
|
package/package.json
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@iowarp/clio-coder",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Coding agent for HPC and scientific-software developers, part of IOWarp's CLIO ecosystem of agentic science.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"agentic-ai",
|
|
8
|
+
"agentic-coding",
|
|
9
|
+
"agentic-science",
|
|
10
|
+
"coding",
|
|
11
|
+
"repository",
|
|
12
|
+
"terminal",
|
|
13
|
+
"developer-tools",
|
|
14
|
+
"llm",
|
|
15
|
+
"agents",
|
|
16
|
+
"model-targets",
|
|
17
|
+
"multi-agent",
|
|
18
|
+
"coding-agents",
|
|
19
|
+
"software-engineering",
|
|
20
|
+
"research-software",
|
|
21
|
+
"scientific-computing",
|
|
22
|
+
"hpc",
|
|
23
|
+
"clio",
|
|
24
|
+
"iowarp"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"license": "Apache-2.0",
|
|
28
|
+
"author": "Anthony Kougkas <a.kougkas@gmail.com> (https://github.com/akougkas)",
|
|
29
|
+
"contributors": [
|
|
30
|
+
"IOWarp <https://iowarp.ai>",
|
|
31
|
+
"Gnosis Research Center <https://grc.iit.edu/>"
|
|
32
|
+
],
|
|
33
|
+
"homepage": "https://iowarp.ai",
|
|
34
|
+
"bugs": "https://github.com/iowarp/clio-coder/issues",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/iowarp/clio-coder.git"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=22.19.0"
|
|
41
|
+
},
|
|
42
|
+
"bin": {
|
|
43
|
+
"clio-coder": "dist/cli/index.js"
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"dist",
|
|
47
|
+
"!dist/**/*.map",
|
|
48
|
+
"assets/clio-coder-logo-128.webp",
|
|
49
|
+
"src/domains/agents/builtins/**",
|
|
50
|
+
"src/domains/agents/fleets/**",
|
|
51
|
+
"skills/workflow/cut-it/**",
|
|
52
|
+
"skills/git/**",
|
|
53
|
+
"skills/skill-marketplace.json",
|
|
54
|
+
"src/domains/providers/models/**",
|
|
55
|
+
"src/domains/prompts/fragments/**",
|
|
56
|
+
"docs/*.md",
|
|
57
|
+
"docs/html/**",
|
|
58
|
+
"README.md",
|
|
59
|
+
"CHANGELOG.md",
|
|
60
|
+
"CONTRIBUTING.md",
|
|
61
|
+
"SECURITY.md",
|
|
62
|
+
"CODE_OF_CONDUCT.md",
|
|
63
|
+
"NOTICE",
|
|
64
|
+
"LICENSE",
|
|
65
|
+
"damage-control-rules.yaml"
|
|
66
|
+
],
|
|
67
|
+
"publishConfig": {
|
|
68
|
+
"access": "public"
|
|
69
|
+
},
|
|
70
|
+
"scripts": {
|
|
71
|
+
"build": "tsup",
|
|
72
|
+
"dev": "tsup --watch",
|
|
73
|
+
"clean": "rm -rf dist",
|
|
74
|
+
"typecheck": "tsc -p tsconfig.tests.json",
|
|
75
|
+
"format": "biome format --write .",
|
|
76
|
+
"lint": "biome check .",
|
|
77
|
+
"check:boundaries": "node --import tsx --import ./tests/harness/tmp-root.ts --test 'tests/boundaries/**/*.test.ts'",
|
|
78
|
+
"test:file": "node --import tsx --import ./tests/harness/tmp-root.ts --test",
|
|
79
|
+
"test:smoke": "node --import tsx --import ./tests/harness/tmp-root.ts --test 'tests/smoke/**/*.test.ts'",
|
|
80
|
+
"test:contracts": "node --import tsx --import ./tests/harness/tmp-root.ts --test 'tests/contracts/**/*.test.ts'",
|
|
81
|
+
"test": "node --import tsx --import ./tests/harness/tmp-root.ts --test 'tests/contracts/**/*.test.ts' 'tests/smoke/**/*.test.ts' 'tests/boundaries/**/*.test.ts'",
|
|
82
|
+
"test:coverage": "node --import tsx --import ./tests/harness/tmp-root.ts --test --experimental-test-coverage --test-coverage-include='src/**/*.ts' --test-coverage-exclude='src/**/*.d.ts' 'tests/contracts/**/*.test.ts' 'tests/smoke/**/*.test.ts' 'tests/boundaries/**/*.test.ts'",
|
|
83
|
+
"test:repeat": "node tests/harness/repeat-tests.mjs",
|
|
84
|
+
"test:trace-viewer": "npm --prefix apps/trace-viewer test",
|
|
85
|
+
"trace:ui": "node apps/trace-viewer/server.mjs",
|
|
86
|
+
"ci": "npm run typecheck && npm run lint && npm run skills:check && npm run build && npm run test && npm run test:trace-viewer",
|
|
87
|
+
"ci:release": "npm run ci && node scripts/check-release.mjs",
|
|
88
|
+
"test:live": "node scripts/live-smoke.mjs",
|
|
89
|
+
"test:live-eval": "node scripts/live-eval-recon.mjs",
|
|
90
|
+
"test:live-eval:fleet-dispatch": "node scripts/live-eval-fleet-dispatch.mjs",
|
|
91
|
+
"test:live-verify:dispatch-routing": "node scripts/live-verify-dispatch-routing.mjs",
|
|
92
|
+
"bench:swe": "python3 benchmarks/community/swe-bench-lite/swebench_clio.py",
|
|
93
|
+
"bench:scicode": "python3 benchmarks/community/scicode/scicode_clio.py",
|
|
94
|
+
"bench:tb": "python3 benchmarks/community/clio_fleet.py",
|
|
95
|
+
"install:local": "bash scripts/install-local.sh",
|
|
96
|
+
"prepublishOnly": "npm run ci:release",
|
|
97
|
+
"skills:pin": "node --import tsx scripts/pin-skills.ts",
|
|
98
|
+
"skills:check": "node --import tsx scripts/pin-skills.ts --check",
|
|
99
|
+
"test:lifecycle": "node --import tsx scripts/lifecycle-matrix.mjs"
|
|
100
|
+
},
|
|
101
|
+
"dependencies": {
|
|
102
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.186",
|
|
103
|
+
"@earendil-works/pi-agent-core": "0.83.0",
|
|
104
|
+
"@earendil-works/pi-ai": "0.83.0",
|
|
105
|
+
"@earendil-works/pi-tui": "0.83.0",
|
|
106
|
+
"@lmstudio/sdk": "1.5.0",
|
|
107
|
+
"@silvia-odwyer/photon-node": "^0.3.4",
|
|
108
|
+
"@vscode/tree-sitter-wasm": "^0.3.1",
|
|
109
|
+
"chalk": "5.6.2",
|
|
110
|
+
"diff": "9.0.0",
|
|
111
|
+
"ollama": "0.6.3",
|
|
112
|
+
"tree-sitter-wasms": "^0.1.13",
|
|
113
|
+
"typebox": "1.3.0",
|
|
114
|
+
"undici": "8.5.0",
|
|
115
|
+
"uuid": "14.0.1",
|
|
116
|
+
"yaml": "2.9.0"
|
|
117
|
+
},
|
|
118
|
+
"overrides": {
|
|
119
|
+
"@anthropic-ai/sdk": "0.105.0",
|
|
120
|
+
"ip-address": "10.2.0",
|
|
121
|
+
"esbuild": "0.28.1"
|
|
122
|
+
},
|
|
123
|
+
"devDependencies": {
|
|
124
|
+
"@biomejs/biome": "2.5.1",
|
|
125
|
+
"@types/node": "24.12.2",
|
|
126
|
+
"esbuild": "0.28.1",
|
|
127
|
+
"node-pty": "1.1.0",
|
|
128
|
+
"tsup": "8.5.1",
|
|
129
|
+
"tsx": "4.22.4",
|
|
130
|
+
"typescript": "6.0.3"
|
|
131
|
+
}
|
|
132
|
+
}
|