car-runtime 0.50.0 → 0.52.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 +9 -2
- package/docs/ASSISTANT.md +491 -0
- package/docs/CLI.md +3051 -0
- package/docs/GUIDE.md +266 -0
- package/docs/MCP.md +382 -0
- package/docs/SPEC.md +169 -0
- package/docs/agent-ir-spec.md +677 -0
- package/docs/websocket-protocol.md +10 -0
- package/index.d.ts +84 -0
- package/package.json +5 -3
package/docs/SPEC.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# CAR specification
|
|
2
|
+
|
|
3
|
+
The data shapes and semantics CAR guarantees across every binding (Python, Node,
|
|
4
|
+
Swift/Kotlin, the `car` CLI, and the `car-server` JSON-RPC protocol). These are
|
|
5
|
+
the contracts you code against; they're stable within a minor version (CAR is
|
|
6
|
+
pre-1.0 — see *Versioning*).
|
|
7
|
+
|
|
8
|
+
## The model: propose → verify → execute
|
|
9
|
+
|
|
10
|
+
CAR treats a plan as first-class data. A **proposal** is a DAG of **actions**;
|
|
11
|
+
the runtime validates it, optionally verifies properties over it, enforces
|
|
12
|
+
policies, and then executes — dispatching each tool through *your* callback while
|
|
13
|
+
owning ordering, state, retries, and the audit trail.
|
|
14
|
+
|
|
15
|
+
## Action / proposal shape
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"actions": [
|
|
20
|
+
{
|
|
21
|
+
"id": "a1",
|
|
22
|
+
"type": "tool_call",
|
|
23
|
+
"tool": "read_file",
|
|
24
|
+
"parameters": { "path": "/tmp/foo.txt" },
|
|
25
|
+
"dependencies": []
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "a2",
|
|
29
|
+
"type": "tool_call",
|
|
30
|
+
"tool": "summarize",
|
|
31
|
+
"parameters": { "text_ref": "$a1.output" },
|
|
32
|
+
"dependencies": ["a1"]
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- `id` — unique within the proposal; referenced by `dependencies` and by
|
|
39
|
+
`$<id>.output` interpolation.
|
|
40
|
+
- `type` — one of `tool_call`, `state_write`, `state_read`, `assertion`.
|
|
41
|
+
- `dependencies` — ids that must complete first. Actions with satisfied
|
|
42
|
+
dependencies run concurrently; the runtime owns the DAG scheduling.
|
|
43
|
+
|
|
44
|
+
The full IR (effect sets, read/write sets, cost metadata, invocation modes) is
|
|
45
|
+
documented in the source repo's `docs/agent-ir-spec.md`; the shape above is the
|
|
46
|
+
minimum every binding accepts.
|
|
47
|
+
|
|
48
|
+
## Tool callback contract
|
|
49
|
+
|
|
50
|
+
You register a tool name and provide a dispatch callback; CAR never owns tool
|
|
51
|
+
implementations.
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
def tool_fn(call_json: str) -> str:
|
|
55
|
+
call = json.loads(call_json)
|
|
56
|
+
if call["tool"] == "read_file":
|
|
57
|
+
return json.dumps({"content": open(call["params"]["path"]).read()})
|
|
58
|
+
return json.dumps({"error": f"unknown tool: {call['tool']}"})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- Input: ONE JSON string describing the whole call — `{"tool", "params",
|
|
62
|
+
"action_id", "request_id", "timeout_ms", "session_id", "attempt"}`. Not the
|
|
63
|
+
name and params as two arguments.
|
|
64
|
+
- Output: a JSON string. An error is just a `{"error": "..."}` payload — the
|
|
65
|
+
runtime handles retries / replans if configured.
|
|
66
|
+
- In Node the callback is async and returns a `Promise<string>`; in
|
|
67
|
+
`car-server` it's a bidirectional JSON-RPC callback.
|
|
68
|
+
|
|
69
|
+
## Policies
|
|
70
|
+
|
|
71
|
+
Policies are enforced in **Rust, before any tool fires** — they can't be skipped
|
|
72
|
+
by the model or the tool code. Register them by kind:
|
|
73
|
+
|
|
74
|
+
| Kind | Effect |
|
|
75
|
+
|------|--------|
|
|
76
|
+
| `deny_tool` | Block a tool entirely. |
|
|
77
|
+
| `deny_tool_param` | Block a tool when a parameter matches a pattern (e.g. `shell` where `command` contains `rm -rf`). |
|
|
78
|
+
| `require_state` | Require a state key/precondition before an action runs. |
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
rt.register_policy("no_rm", "deny_tool_param",
|
|
82
|
+
target="shell", key="command", pattern="rm -rf")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Beyond static policies, CAR classifies each action into a **risk tier**
|
|
86
|
+
(`read_only` / `sandbox_edit` / `full_access`) and gates it against a granted
|
|
87
|
+
standing tier with human-in-the-loop approval; per-agent postures
|
|
88
|
+
(always-allow / require-approval / deny) refine this per agent. Approvals are
|
|
89
|
+
recorded to a durable ledger.
|
|
90
|
+
|
|
91
|
+
## Static verification
|
|
92
|
+
|
|
93
|
+
Before executing, you can check properties over a proposal — these are pure,
|
|
94
|
+
side-effect-free, and run in milliseconds. They are static analysis, not
|
|
95
|
+
solver-backed proof. The forward walk models only the effects an action
|
|
96
|
+
*declares* in `expected_effects`, so a declared effect is assumed to land and an
|
|
97
|
+
undeclared one is invisible:
|
|
98
|
+
|
|
99
|
+
- **`verify`** — structural + semantic validity: dependencies resolve,
|
|
100
|
+
preconditions are establishable against the supplied state, tools exist, and
|
|
101
|
+
tool-call parameters match the registered schema. Returns `{ valid, issues }`.
|
|
102
|
+
Write conflicts are reported as *warnings* — they do not make a proposal
|
|
103
|
+
invalid. Policy is enforced separately by `car-policy`, not here.
|
|
104
|
+
- **`simulate`** — forward-simulate the state transitions the plan would produce,
|
|
105
|
+
without running any tool.
|
|
106
|
+
- **`equivalent`** — spot-check that two proposals produce the same effects over
|
|
107
|
+
a set of test states (two trivial defaults unless you supply your own). Not a
|
|
108
|
+
proof of equivalence.
|
|
109
|
+
- **`optimize`** — prune phantom `state_dependencies` so independent actions can
|
|
110
|
+
run in the same DAG level. It does not reorder or remove actions.
|
|
111
|
+
|
|
112
|
+
"Deterministic" means: given the same proposal, policies, and tool outputs, the
|
|
113
|
+
runtime's ordering, validation, and state transitions are reproducible — the
|
|
114
|
+
non-determinism is confined to your tool implementations and the model.
|
|
115
|
+
|
|
116
|
+
## Multi-agent shapes
|
|
117
|
+
|
|
118
|
+
Five coordination patterns are exposed as standalone functions:
|
|
119
|
+
`run_pipeline`, `run_swarm` (`parallel` / `sequential` / `debate`),
|
|
120
|
+
`run_supervisor`, `run_map_reduce`, `run_vote`. Each takes your agent callback.
|
|
121
|
+
|
|
122
|
+
**AgentSpec** (what you pass in):
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
{
|
|
126
|
+
"name": "reviewer",
|
|
127
|
+
"system_prompt": "You review code for the 3 biggest risks.",
|
|
128
|
+
"tools": ["grep", "read_file"],
|
|
129
|
+
"max_turns": 5,
|
|
130
|
+
"metadata": { "model": "claude-opus-4-8", "temperature": 0.3 }
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**AgentOutput** (what your `agent_fn(spec_json, task)` MUST return, as a JSON
|
|
135
|
+
string — the shape is strict; missing fields fail deserialization):
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
{
|
|
139
|
+
"name": "reviewer",
|
|
140
|
+
"answer": "...final answer text...",
|
|
141
|
+
"turns": 1,
|
|
142
|
+
"tool_calls": 0, # integer count, NOT an array
|
|
143
|
+
"duration_ms": 100.0,
|
|
144
|
+
"error": None # or a string if the agent failed
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The runtime doesn't care how you produce `answer` (Anthropic, OpenAI, local
|
|
149
|
+
Qwen3 via `infer_tracked`, a deterministic tool chain — anything).
|
|
150
|
+
|
|
151
|
+
## Skills / learning loop
|
|
152
|
+
|
|
153
|
+
`TraceEvent` records (`action_succeeded` / `action_failed` with `tool`, `data`,
|
|
154
|
+
`reward`) feed `distill_skills` → `ingest_distilled_skills`; per-skill outcomes
|
|
155
|
+
(`report_outcome`) drive `domains_needing_evolution`, `evolve_skills`, and
|
|
156
|
+
`repair_skill`. A skill auto-degrades when `fail_count > success_count + 2`. Full
|
|
157
|
+
worked example: [GUIDE.md](./GUIDE.md) and `examples/python/multi_agent.py`.
|
|
158
|
+
|
|
159
|
+
## Conformance
|
|
160
|
+
|
|
161
|
+
Execution semantics are portable: the **RuntimeBench** suite (`car-conformance`)
|
|
162
|
+
verifies every runtime capability against this spec, so an implementation either
|
|
163
|
+
passes the conformance tests or it isn't CAR-compatible.
|
|
164
|
+
|
|
165
|
+
## Versioning
|
|
166
|
+
|
|
167
|
+
CAR is pre-1.0. Breaking changes between minor versions are possible — **pin to
|
|
168
|
+
exact versions** until the API stabilizes. Each release lists breaking changes in
|
|
169
|
+
its GitHub release notes and in `CHANGELOG.md`.
|