car-runtime 0.52.1 → 0.54.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 +47 -0
- package/agent-loop.d.ts +30 -0
- package/agent-loop.js +578 -0
- package/agent-loop.mjs +4 -0
- package/daemon-wrappers.js +6155 -0
- package/docs/ASSISTANT.md +1 -0
- package/docs/CLI.md +449 -19
- package/docs/agent-ir-spec.md +74 -7
- package/index.d.ts +1334 -38
- package/index.js +45 -0
- package/install.js +16 -0
- package/package.json +21 -2
package/docs/agent-ir-spec.md
CHANGED
|
@@ -168,6 +168,24 @@ Snake-case enum. What happens when this action's tool returns an error or a prec
|
|
|
168
168
|
| `"retry"` | retry up to `max_retries` times before aborting |
|
|
169
169
|
| `"skip"` | mark this action skipped and continue with the rest |
|
|
170
170
|
|
|
171
|
+
### Tool failure classification
|
|
172
|
+
|
|
173
|
+
A tool executor may return a typed `ToolFailure` with classification
|
|
174
|
+
`"ordinary"` or `"terminal"`. This is evidence produced by the tool during
|
|
175
|
+
execution, not a fourth `FailureBehavior`:
|
|
176
|
+
|
|
177
|
+
- `"ordinary"` follows the action's declared failure behavior. Existing string
|
|
178
|
+
errors convert to this classification, so legacy errors keep their current
|
|
179
|
+
retry, skip, or abort behavior.
|
|
180
|
+
- `"terminal"` stops retrying immediately and aborts and rolls back the
|
|
181
|
+
proposal regardless of its declared failure behavior. The failed
|
|
182
|
+
`ActionResult` carries `"terminal": true`; the field is absent for all other
|
|
183
|
+
results and defaults to false when deserializing older results.
|
|
184
|
+
|
|
185
|
+
Terminality is strictly opt-in. CAR never infers it from words such as
|
|
186
|
+
"terminal" or "fatal" in an error message. This engine-level contract does not
|
|
187
|
+
halt a daemon session; session halting is a separate daemon-owned layer.
|
|
188
|
+
|
|
171
189
|
### Action lifecycle (informational)
|
|
172
190
|
|
|
173
191
|
The runtime tags each action with an `ActionStatus` as it moves through validation and execution:
|
|
@@ -181,6 +199,35 @@ Proposed → Validated → Executing → Succeeded
|
|
|
181
199
|
|
|
182
200
|
`ActionStatus` is observable through the event log, not part of the input contract.
|
|
183
201
|
|
|
202
|
+
#### Execution outcome event data
|
|
203
|
+
|
|
204
|
+
Every per-action `ActionFailed` event carries:
|
|
205
|
+
|
|
206
|
+
- `params_digest`: lowercase SHA-256 of the RFC 8785/JCS-canonicalized action
|
|
207
|
+
`parameters` object. The event never copies raw parameters; consumers join
|
|
208
|
+
through `proposal_id` + `action_id` to the authoritative `ProposalReceived`
|
|
209
|
+
record and can use the digest to detect a mismatch.
|
|
210
|
+
- `expected_effects`: the action's declared expected-effects object, unchanged.
|
|
211
|
+
- `error_class`: one of `timeout`, `rejected_by_policy`, `tool_error`,
|
|
212
|
+
`validation`, or `unknown`.
|
|
213
|
+
|
|
214
|
+
`ActionSucceeded` carries `params_digest` and `expected_effects` too, making the
|
|
215
|
+
success/failure join symmetric without adding an error classification to a
|
|
216
|
+
successful call.
|
|
217
|
+
|
|
218
|
+
The normalized error mapping is intentionally low-cardinality:
|
|
219
|
+
|
|
220
|
+
| `error_class` | Mapping |
|
|
221
|
+
|---|---|
|
|
222
|
+
| `timeout` | the engine's action deadline expired, or the daemon-to-host tool callback reported its own timeout |
|
|
223
|
+
| `rejected_by_policy` | a dispatch-time tool guard returned the stable `denied by policy:` or `rejected by policy:` prefix |
|
|
224
|
+
| `validation` | post-dispatch output or callback-state JCS/I-JSON, state-key-set, or serialization validation failed |
|
|
225
|
+
| `tool_error` | any other error returned while dispatching a tool action |
|
|
226
|
+
| `unknown` | a post-dispatch failure on an action with no tool |
|
|
227
|
+
|
|
228
|
+
Normal action/schema/policy admission failures happen before execution and are
|
|
229
|
+
`ActionRejected`, not `ActionFailed`, so this mapping does not reclassify them.
|
|
230
|
+
|
|
184
231
|
---
|
|
185
232
|
|
|
186
233
|
## Precondition
|
|
@@ -220,6 +267,7 @@ Registered when a tool is added to the runtime. Carries everything the runtime n
|
|
|
220
267
|
```jsonc
|
|
221
268
|
{
|
|
222
269
|
"name": "deploy",
|
|
270
|
+
"source": "user_defined",
|
|
223
271
|
"description": "Deploys an artifact to a target environment.",
|
|
224
272
|
"parameters": {
|
|
225
273
|
"type": "object",
|
|
@@ -238,6 +286,7 @@ Registered when a tool is added to the runtime. Carries everything the runtime n
|
|
|
238
286
|
| Field | Type | Required | Default | Notes |
|
|
239
287
|
|-------|------|----------|---------|-------|
|
|
240
288
|
| `name` | string | **yes** | — | unique within a runtime |
|
|
289
|
+
| `source` | `builtin \| user_defined \| subprocess \| mcp` | no | `user_defined` | stable origin category assigned by the runtime; MCP server detail remains registry-private |
|
|
241
290
|
| `description` | string | no | `""` | human-readable; included in tool catalog |
|
|
242
291
|
| `parameters` | JSON Schema | no | `{}` | validated by the runtime before dispatch |
|
|
243
292
|
| `returns` | JSON Schema | no | none | validated against tool return value when set |
|
|
@@ -302,12 +351,10 @@ Returned by `proposal.submit` (WebSocket), `executeProposal` (NAPI), `execute_pr
|
|
|
302
351
|
{
|
|
303
352
|
"action_id": "a1",
|
|
304
353
|
"status": "succeeded",
|
|
354
|
+
"rolled_back": true,
|
|
305
355
|
"output": { "deployed": true },
|
|
306
|
-
"error":
|
|
307
|
-
"state_changes": {
|
|
308
|
-
"deployed": { "op": "set", "value": true },
|
|
309
|
-
"obsolete_key": { "op": "delete" }
|
|
310
|
-
},
|
|
356
|
+
"error": "proposal aborted; state effects were rolled back; external effects may remain and were not undone",
|
|
357
|
+
"state_changes": {},
|
|
311
358
|
"duration_ms": 1230.0,
|
|
312
359
|
"timestamp": "2026-05-02T12:00:01Z"
|
|
313
360
|
}
|
|
@@ -318,6 +365,19 @@ Returned by `proposal.submit` (WebSocket), `executeProposal` (NAPI), `execute_pr
|
|
|
318
365
|
|
|
319
366
|
`status` is one of: `"proposed"`, `"validated"`, `"rejected"`, `"executing"`, `"succeeded"`, `"failed"`, `"skipped"`.
|
|
320
367
|
|
|
368
|
+
A failed action includes `"terminal": true` only when its tool returned
|
|
369
|
+
`ToolFailureClassification::Terminal`. The field is omitted otherwise. A
|
|
370
|
+
terminal result means the engine stopped retries and aborted this proposal; it
|
|
371
|
+
does not by itself describe daemon session state.
|
|
372
|
+
|
|
373
|
+
`rolled_back` is an independent commit marker. A successful action in an
|
|
374
|
+
aborted proposal remains `status: "succeeded"` because it executed, while
|
|
375
|
+
`rolled_back: true` reports that the enclosing state transaction was restored.
|
|
376
|
+
Its `state_changes` are empty and `error` may carry the warning that external
|
|
377
|
+
effects can remain. Consumers must use `rolled_back`, never compare that warning
|
|
378
|
+
text. The field defaults to `false` when absent and false values are omitted from
|
|
379
|
+
the serialized response for compatibility with older readers.
|
|
380
|
+
|
|
321
381
|
Each `state_changes` value is a tagged `StateMutation`: `{"op":"set","value":…}`
|
|
322
382
|
sets the key (including explicitly setting it to JSON `null`), while
|
|
323
383
|
`{"op":"delete"}` removes it. Rust consumers can encode and decode that stable
|
|
@@ -562,15 +622,21 @@ allow = ["staging", "preview"] # any other target — or none at all — is de
|
|
|
562
622
|
| `allow` | no | permitted values; defaults to empty, which denies every call |
|
|
563
623
|
|
|
564
624
|
#### `deny_tool_param_matching`
|
|
565
|
-
The content counterpart to `deny_tool_param`, for
|
|
625
|
+
The content counterpart to `deny_tool_param`, for conditions no fixed substring expresses — credential shapes, account numbers, an address family, or an open-ended trusted prefix. `matches` is a regex over the string-coerced parameter value. The match is **unanchored**, so the pattern fires anywhere in the value; anchor it with `^`/`$` when that matters.
|
|
566
626
|
|
|
567
|
-
The pattern is compiled once when the rule set is applied, not per action. A pattern that fails to compile **denies every call to that tool** rather than disappearing, matching the loader's loud-error posture.
|
|
627
|
+
By default a regex match denies and an absent parameter does not. Set `negate = true` for the "unless" form: a mismatch denies, and an absent parameter also denies because nothing proves the required pattern. The pattern is compiled once when the rule set is applied, not per action. A pattern that fails to compile **denies every call to that tool** rather than disappearing, matching the loader's loud-error posture.
|
|
568
628
|
|
|
569
629
|
```toml
|
|
570
630
|
[[deny_tool_param_matching]]
|
|
571
631
|
tool = "http_request"
|
|
572
632
|
param = "body"
|
|
573
633
|
matches = "sk-[A-Za-z0-9]{20,}" # never let an API-key-shaped string leave in a body
|
|
634
|
+
|
|
635
|
+
[[deny_tool_param_matching]]
|
|
636
|
+
tool = "docker.rm"
|
|
637
|
+
param = "name"
|
|
638
|
+
matches = "^parslee-"
|
|
639
|
+
negate = true # deny unless the name has the trusted prefix
|
|
574
640
|
```
|
|
575
641
|
|
|
576
642
|
| Param | Required | Notes |
|
|
@@ -578,6 +644,7 @@ matches = "sk-[A-Za-z0-9]{20,}" # never let an API-key-shaped string leave in
|
|
|
578
644
|
| `tool` | yes | tool name the rule applies to |
|
|
579
645
|
| `param` | yes | parameter key inspected on the action |
|
|
580
646
|
| `matches` | yes | regex source; unanchored; an uncompilable pattern denies the tool outright |
|
|
647
|
+
| `negate` | no | defaults to `false`; when `true`, deny mismatch or absence instead of match |
|
|
581
648
|
|
|
582
649
|
#### `rate_limit_tool`
|
|
583
650
|
A sliding-window cap on how often `tool` may be called. The call is denied when admitting it would make it the `max_calls + 1`-th call to `tool` within the trailing `interval_secs`. `max_calls = 0` denies every call. This bounds how much of a side effect an agent can produce in a stretch of wall-clock time, independently of whether any single call is legitimate.
|