car-runtime 0.46.1 → 0.48.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/index.d.ts +397 -19
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -59,6 +59,14 @@ export interface CoderStartOptions {
|
|
|
59
59
|
* hypothesis, the other buys a retry.
|
|
60
60
|
*/
|
|
61
61
|
transientRetries?: number | undefined | null;
|
|
62
|
+
/**
|
|
63
|
+
* A `coder.discuss` conversation this run was distilled from. Its agreed
|
|
64
|
+
* constraints ride into contract derivation, so a rule stated once in the
|
|
65
|
+
* discussion does not have to be restated in the intent, and the session
|
|
66
|
+
* records the provenance. An unknown id is a clear error — never a silently
|
|
67
|
+
* ungrounded run.
|
|
68
|
+
*/
|
|
69
|
+
discussionId?: string | undefined | null;
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
export class CarRuntime {
|
|
@@ -143,6 +151,28 @@ export class CarRuntime {
|
|
|
143
151
|
/** Register a tool by name. */
|
|
144
152
|
registerTool(name: string): Promise<void>;
|
|
145
153
|
|
|
154
|
+
/**
|
|
155
|
+
* The tools currently registered on this runtime, as a JSON array of full
|
|
156
|
+
* `ToolSchema` objects sorted by name.
|
|
157
|
+
*
|
|
158
|
+
* Counterpart to `registerTool` / `registerToolSchema`, which had none: a
|
|
159
|
+
* caller could add tools but never ask what was actually in effect, so a
|
|
160
|
+
* governed or read-only deployment could not prove "only these tools are
|
|
161
|
+
* callable". Sorted, so two calls with no registration in between are
|
|
162
|
+
* byte-identical and can be diffed.
|
|
163
|
+
*/
|
|
164
|
+
listTools(): Promise<string>;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Remove a tool by name. Resolves to how many were removed — `0` means
|
|
168
|
+
* nothing matched, which is not an error, so cleanup can call this
|
|
169
|
+
* unconditionally.
|
|
170
|
+
*
|
|
171
|
+
* Drops the tool from both the runtime's registry and its schema map, so
|
|
172
|
+
* the model stops seeing it and the validator stops accepting it.
|
|
173
|
+
*/
|
|
174
|
+
unregisterTool(name: string): Promise<number>;
|
|
175
|
+
|
|
146
176
|
/** Register CAR's built-in agent utility tools. */
|
|
147
177
|
registerAgentBasics(): Promise<void>;
|
|
148
178
|
|
|
@@ -391,6 +421,26 @@ export class CarRuntime {
|
|
|
391
421
|
* dispatches the chosen components.
|
|
392
422
|
*/
|
|
393
423
|
planEvolutionLive(requestJson: string): Promise<string>;
|
|
424
|
+
/**
|
|
425
|
+
* `supervision.subscribe` — register this connection as a supervisor of the
|
|
426
|
+
* admission gate: `{ filter?: { tools?, sessions?, min_reversibility? } }`.
|
|
427
|
+
*
|
|
428
|
+
* Intents arrive as `supervision.intent` NOTIFICATIONS on the same socket.
|
|
429
|
+
* A caller that cannot read notifications should poll `supervisionPending`
|
|
430
|
+
* instead — subscribing without consuming them blocks every supervised
|
|
431
|
+
* proposal until it fails closed.
|
|
432
|
+
*/
|
|
433
|
+
supervisionSubscribe(requestJson: string): Promise<string>;
|
|
434
|
+
/**
|
|
435
|
+
* `supervision.unsubscribe` — stop supervising: `{}`. Intents already parked
|
|
436
|
+
* run out their timeout and fail closed rather than being released, so a
|
|
437
|
+
* supervisor cannot turn a pending deny into an allow by disconnecting.
|
|
438
|
+
*/
|
|
439
|
+
supervisionUnsubscribe(requestJson: string): Promise<string>;
|
|
440
|
+
/** `supervision.pending` — every intent currently parked on a verdict: `{}`. */
|
|
441
|
+
supervisionPending(requestJson: string): Promise<string>;
|
|
442
|
+
/** `supervision.decide` — `{ intent_id, decision: { kind: "allow" | "deny" | "escalate", reason? } }`. */
|
|
443
|
+
supervisionDecide(requestJson: string): Promise<string>;
|
|
394
444
|
/** `sync.status` — roster, journal frontier, stable frontier, state hash (B6). */
|
|
395
445
|
syncStatus(requestJson: string): Promise<string>;
|
|
396
446
|
/** `sync.append` — record an op on any surface: `{ surface, payload, scope? }` (B6). */
|
|
@@ -464,6 +514,27 @@ export class CarRuntime {
|
|
|
464
514
|
*/
|
|
465
515
|
enforceSkillDeploymentLive(requestJson: string): Promise<string>;
|
|
466
516
|
|
|
517
|
+
/**
|
|
518
|
+
* Read the standing permission tier granted to this connection's daemon
|
|
519
|
+
* session (`read_only` | `sandbox_edit` | `full_access`) — the tier every
|
|
520
|
+
* {@link submitProposal} on this connection is judged against
|
|
521
|
+
* (Parslee-ai/car#890).
|
|
522
|
+
*/
|
|
523
|
+
permissionGetTier(): Promise<string>;
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Set this connection's standing permission tier and return the tier as the
|
|
527
|
+
* daemon now holds it. `tier` is `read_only` | `sandbox_edit` |
|
|
528
|
+
* `full_access`.
|
|
529
|
+
*
|
|
530
|
+
* Lets a binding client govern its own session — most usefully by tightening
|
|
531
|
+
* it: dropping to `read_only` makes the runtime escalate any write this
|
|
532
|
+
* client proposes to a human instead of running it. Raising the tier is
|
|
533
|
+
* host-gated whenever the daemon runs under a host token, so an agent
|
|
534
|
+
* connection cannot self-elevate.
|
|
535
|
+
*/
|
|
536
|
+
permissionSetTier(tier: string): Promise<string>;
|
|
537
|
+
|
|
467
538
|
/**
|
|
468
539
|
* Ingest a skill through the deployment gate on the daemon (arXiv 2602.12430
|
|
469
540
|
* "Agent Skills" — the loader integration). `requestJson` carries the skill
|
|
@@ -477,6 +548,21 @@ export class CarRuntime {
|
|
|
477
548
|
*/
|
|
478
549
|
ingestSkillGoverned(requestJson: string): Promise<string>;
|
|
479
550
|
|
|
551
|
+
/**
|
|
552
|
+
* Adopt an installed skill pack on the daemon through the skill-trust
|
|
553
|
+
* deployment gate (arXiv 2602.12430 "Agent Skills" — the pack-adoption
|
|
554
|
+
* call-site). `requestJson` carries `pack` (an `ApprovedSkillPack`),
|
|
555
|
+
* `requested_tier?` (default `read_only`), and either `manifest?` — the signed
|
|
556
|
+
* bundle, whose signature trust is derived against the operator's
|
|
557
|
+
* `.car/config.toml` `trusted_skill_signers` keyring — or `provenance?`
|
|
558
|
+
* (caller-assembled), plus optional `scanned?`/`vulnerabilities?`/`source?`.
|
|
559
|
+
* Governance is unconditional: a denied skill never enters the graph. Returns
|
|
560
|
+
* `{ loaded, pending, refused, requested_tier, provenance, trusted_signers }`;
|
|
561
|
+
* a pending deny is resolved via `permission.approve`/`permission.reject` by
|
|
562
|
+
* the returned `fingerprint`, then re-adopted.
|
|
563
|
+
*/
|
|
564
|
+
adoptSkillPack(requestJson: string): Promise<string>;
|
|
565
|
+
|
|
480
566
|
/**
|
|
481
567
|
* Save a learned skill with trigger context. Returns the node
|
|
482
568
|
* index.
|
|
@@ -589,6 +675,13 @@ export class CarRuntime {
|
|
|
589
675
|
* with reasoning suppressed to produce a direct answer, or
|
|
590
676
|
* `"thinking_truncated"` when even that retry was empty (car-releases#60).
|
|
591
677
|
*
|
|
678
|
+
* `auth_fallback_from` is present ONLY when a candidate earlier in the
|
|
679
|
+
* fallback chain was skipped because its credential was **rejected**
|
|
680
|
+
* (not merely absent) and a later model then answered. It names that
|
|
681
|
+
* dead lane, so a caller can tell the user their sign-in lapsed instead
|
|
682
|
+
* of silently serving a different model (Parslee-ai/car#888). Absent on
|
|
683
|
+
* the common path.
|
|
684
|
+
*
|
|
592
685
|
* **Note:** intent is not exposed on the tracked path until the
|
|
593
686
|
* positional argument list is converted to an options object —
|
|
594
687
|
* this method already takes 9 positional parameters and adding
|
|
@@ -774,8 +867,24 @@ export class CarRuntime {
|
|
|
774
867
|
/**
|
|
775
868
|
* Unified registry (local + remote). Returns JSON array of
|
|
776
869
|
* `{ id, name, provider, capabilities, param_count, size_mb,
|
|
777
|
-
* context_length, available, is_local,
|
|
778
|
-
* public_benchmarks, cost }`. `
|
|
870
|
+
* context_length, available, is_local, weights_ready, downloads_weights,
|
|
871
|
+
* max_output_tokens, public_benchmarks, cost }`. `available` means CAR
|
|
872
|
+
* can use the model
|
|
873
|
+
* here — for a local MLX entry with a declared `hf_repo` it is `true`
|
|
874
|
+
* before a byte is fetched, because it lazy-downloads on first use —
|
|
875
|
+
* whereas `weights_ready` means the weights are already on disk (remote
|
|
876
|
+
* models, having none to install, report `true`). Older daemons omit
|
|
877
|
+
* `weights_ready`; it defaults to `false` rather than failing.
|
|
878
|
+
* `downloads_weights` is `true` only for entries whose weights CAR fetches
|
|
879
|
+
* before use (GGUF, MLX, whisper.cpp); when it is `false` — OS-provided
|
|
880
|
+
* models such as `windows/speech-synthesis:os` and
|
|
881
|
+
* `apple/foundation:default`, server-backed local models such as
|
|
882
|
+
* `vllm-mlx/*` and Ollama, and every remote entry — there is nothing to
|
|
883
|
+
* install, so `weights_ready` is meaningless and the CLI renders
|
|
884
|
+
* `INSTALLED` as `-`. Do not substitute `is_local`: those first four are
|
|
885
|
+
* all local and all download nothing. Older daemons omit
|
|
886
|
+
* `downloads_weights`; it defaults to `false` rather than failing.
|
|
887
|
+
* `max_output_tokens` is the registry-declared
|
|
779
888
|
* per-model output ceiling (`null` when the entry omits it; callers
|
|
780
889
|
* then fall back to a fraction of `context_length`).
|
|
781
890
|
* `public_benchmarks` is `[{ name, score, harness?, source_url?,
|
|
@@ -937,9 +1046,93 @@ export class CarRuntime {
|
|
|
937
1046
|
*/
|
|
938
1047
|
coderApproveMerge(sessionId: string, approve: boolean): Promise<string>;
|
|
939
1048
|
|
|
940
|
-
/**
|
|
1049
|
+
/**
|
|
1050
|
+
* Cancel a session: stop the loop, abandon, remove the worktree. Returns
|
|
1051
|
+
* `{state, already_terminal, message}`.
|
|
1052
|
+
*
|
|
1053
|
+
* An already-finished session **succeeds** rather than rejecting: `state`
|
|
1054
|
+
* keeps its pre-existing name and type, `already_terminal` is `true`, and
|
|
1055
|
+
* `message` names what already happened. Callers that cancel unconditionally
|
|
1056
|
+
* on shutdown depend on that — rejecting would turn a quiet exit into a
|
|
1057
|
+
* protocol error whenever the session raced to terminal first.
|
|
1058
|
+
*/
|
|
941
1059
|
coderCancel(sessionId: string): Promise<string>;
|
|
942
1060
|
|
|
1061
|
+
/**
|
|
1062
|
+
* The current session list AND registration for `coder.session_changed` on
|
|
1063
|
+
* this connection, atomically (registered under the same lock the list is
|
|
1064
|
+
* snapshotted under, so nothing slips through the gap). Notifications are
|
|
1065
|
+
* WebSocket-only, same contract as `coder.subscribe`.
|
|
1066
|
+
*
|
|
1067
|
+
* Each row carries the full summary: the pre-existing
|
|
1068
|
+
* `{session_id, state, intent, repo, engine, iterations, updated_at, live,
|
|
1069
|
+
* error}` plus `needs_you` (`"contract" | "question" | "approval" | "auth" |
|
|
1070
|
+
* null`), `needs_you_label` (the daemon-owned wording, so every client says
|
|
1071
|
+
* the same thing), `question_prompt`, `auth_message`, `auth_wait_secs`,
|
|
1072
|
+
* `failure_kind` (`"budget_exhausted" | "auth_required" | "infrastructure" |
|
|
1073
|
+
* "error"` when failed), `worktree` (only when it still exists on disk),
|
|
1074
|
+
* `project`, `result_branch`, `model`, `discussion_id`, and `next_seq` (live
|
|
1075
|
+
* only — the `coder.subscribe` cursor).
|
|
1076
|
+
*
|
|
1077
|
+
* Pass `renew: true` for the lease-renewal form: it re-registers and answers
|
|
1078
|
+
* `{ was_registered }` — `false` means this connection had been shed and
|
|
1079
|
+
* should take a full snapshot — and builds NO summaries, so it is cheap
|
|
1080
|
+
* enough to call on a timer. The default form is unchanged.
|
|
1081
|
+
*/
|
|
1082
|
+
coderWatch(renew?: boolean | undefined | null): Promise<string>;
|
|
1083
|
+
|
|
1084
|
+
/** Stop receiving `coder.session_changed` on this connection. */
|
|
1085
|
+
coderUnwatch(): Promise<string>;
|
|
1086
|
+
|
|
1087
|
+
/**
|
|
1088
|
+
* Redraft a PROPOSED outcome contract from a plain-English request (e.g.
|
|
1089
|
+
* "also verify the Windows path"). Legal only in `contract_proposed`;
|
|
1090
|
+
* nothing executes and the session stays at the gate either way. Unlimited
|
|
1091
|
+
* rounds.
|
|
1092
|
+
*
|
|
1093
|
+
* Returns `{state, revised, contract, baseline, baseline_gates_nothing,
|
|
1094
|
+
* message}`. **Check `revised` before trusting `contract`**: on a redraft
|
|
1095
|
+
* that does not validate, the previous contract comes back byte-identical
|
|
1096
|
+
* with `revised: false` and a `message` explaining why, and the daemon emits
|
|
1097
|
+
* a `contract_revision_rejected` event.
|
|
1098
|
+
*/
|
|
1099
|
+
coderReviseContract(sessionId: string, request: string): Promise<string>;
|
|
1100
|
+
|
|
1101
|
+
/**
|
|
1102
|
+
* Open a repo-grounded, strictly **read-only** discussion — a thinking
|
|
1103
|
+
* surface for working out what a change should be, before a run exists.
|
|
1104
|
+
* Bound at `PermissionTier::ReadOnly` with every write/shell escalation
|
|
1105
|
+
* auto-denied, so it can never touch the repo. Returns
|
|
1106
|
+
* `{discussion_id, repo, repo_summary}`; a non-git path is a clear error.
|
|
1107
|
+
*/
|
|
1108
|
+
coderDiscussStart(repo: string): Promise<string>;
|
|
1109
|
+
|
|
1110
|
+
/**
|
|
1111
|
+
* Send one operator message. Returns `{ok, seq}` where `seq` is the first
|
|
1112
|
+
* event this turn emits; the reply streams as `coder.discuss.event`
|
|
1113
|
+
* (WebSocket-only, same contract as `coder.event`).
|
|
1114
|
+
*/
|
|
1115
|
+
coderDiscussSend(discussionId: string, text: string): Promise<string>;
|
|
1116
|
+
|
|
1117
|
+
/**
|
|
1118
|
+
* Distill the discussion into `{discussion_id, proposed_intent,
|
|
1119
|
+
* constraints}`. **Starts nothing** — no worktree, no branch, no session.
|
|
1120
|
+
* The caller shows `proposed_intent` (never the transcript) for the operator
|
|
1121
|
+
* to edit, then passes it to `coderStart` with `discussion_id` so the agreed
|
|
1122
|
+
* constraints reach contract derivation. Callable repeatedly.
|
|
1123
|
+
*/
|
|
1124
|
+
coderDiscussPromote(discussionId: string): Promise<string>;
|
|
1125
|
+
|
|
1126
|
+
/** Free an in-memory discussion. Discussions do not survive a daemon restart. */
|
|
1127
|
+
coderDiscussClose(discussionId: string): Promise<string>;
|
|
1128
|
+
|
|
1129
|
+
/**
|
|
1130
|
+
* Open discussions: `{discussions: [{discussion_id, repo, created_at,
|
|
1131
|
+
* turns}]}`. Also the capability probe — a daemon predating this surface
|
|
1132
|
+
* answers JSON-RPC `-32601`.
|
|
1133
|
+
*/
|
|
1134
|
+
coderDiscussList(): Promise<string>;
|
|
1135
|
+
|
|
943
1136
|
/**
|
|
944
1137
|
* Managed projects + in-daemon declarative agents (the non-developer path).
|
|
945
1138
|
*
|
|
@@ -1436,10 +1629,25 @@ export class CarRuntime {
|
|
|
1436
1629
|
/**
|
|
1437
1630
|
* Execute a proposal through a CarRuntime with a JS tool callback.
|
|
1438
1631
|
* The callback receives
|
|
1439
|
-
* `{"tool":"name","params":{...},"action_id":"<id>"}`
|
|
1440
|
-
*
|
|
1632
|
+
* `{"tool":"name","params":{...},"action_id":"<id>","request_id":"<id>","timeout_ms":<ms|null>,"session_id":"<id>|null","attempt":<n>}`
|
|
1633
|
+
*
|
|
1634
|
+
* `attempt` is the engine's retry counter, 1-based — which retry you are
|
|
1635
|
+
* serving. (Correlate a specific in-flight call by `request_id` instead.) It
|
|
1636
|
+
* was hardcoded to 1 on the wire and dropped here before car#928.
|
|
1637
|
+
*
|
|
1638
|
+
* `session_id` is the daemon-stamped execution session (car#904) — the
|
|
1639
|
+
* attribution key for which mission a callback belongs to. Null when the
|
|
1640
|
+
* caller has no session. Prefer it over reconstructing attribution from
|
|
1641
|
+
* `action_id`, which is client-authored and not unique across concurrent or
|
|
1642
|
+
* retried attempts.
|
|
1643
|
+
* as a JSON string and must return a JSON string. `action_id` is the
|
|
1441
1644
|
* originating `Action.id` from the proposal — useful for routing
|
|
1442
1645
|
* when the same callback closes over multiple in-flight calls.
|
|
1646
|
+
* `request_id` is the daemon's callback-routing id, which a
|
|
1647
|
+
* `tools.cancel` notification repeats so the host can abort the right
|
|
1648
|
+
* in-flight call. `timeout_ms` is the action's declared budget in
|
|
1649
|
+
* milliseconds when the action declared one (`null` otherwise); the
|
|
1650
|
+
* host's tool runner may use it to bound its own work.
|
|
1443
1651
|
*
|
|
1444
1652
|
* `sessionId`, when provided, scopes per-action policy validation to
|
|
1445
1653
|
* the named session opened via `CarRuntime.openSession()`. Global
|
|
@@ -1657,6 +1865,13 @@ export function registerVoiceEventHandler(
|
|
|
1657
1865
|
* Promise is logged, not surfaced to the host. Process-wide setter,
|
|
1658
1866
|
* symmetric to `registerVoiceEventHandler`; pair with
|
|
1659
1867
|
* `unregisterChatHandler` to clear.
|
|
1868
|
+
*
|
|
1869
|
+
* The handler may call any runtime method and should run the turn inline.
|
|
1870
|
+
* NAPI dispatches through a non-blocking `ThreadsafeFunction` and `chatEvent`
|
|
1871
|
+
* is async, so this side never had the reentrancy hazard that made the same
|
|
1872
|
+
* surface unusable from Python before Parslee-ai/car#905 — noted here because
|
|
1873
|
+
* the two bindings' handlers now carry the same contract for the same reason,
|
|
1874
|
+
* arrived at differently.
|
|
1660
1875
|
*/
|
|
1661
1876
|
export function registerChatHandler(
|
|
1662
1877
|
handlerFn: (paramsJson: string) => void,
|
|
@@ -1675,11 +1890,27 @@ export function unregisterChatHandler(): void;
|
|
|
1675
1890
|
* this handler.
|
|
1676
1891
|
*
|
|
1677
1892
|
* `handlerFn(callJson)` receives
|
|
1678
|
-
* `{"tool":"name","params":{...},"action_id":"<id>"}`
|
|
1679
|
-
*
|
|
1893
|
+
* `{"tool":"name","params":{...},"action_id":"<id>","request_id":"<id>","timeout_ms":<ms|null>,"session_id":"<id>|null","attempt":<n>}`
|
|
1894
|
+
*
|
|
1895
|
+
* `attempt` is the engine's retry counter, 1-based — which retry you are
|
|
1896
|
+
* serving. (Correlate a specific in-flight call by `request_id` instead.) It
|
|
1897
|
+
* was hardcoded to 1 on the wire and dropped here before car#928.
|
|
1898
|
+
*
|
|
1899
|
+
* `session_id` is the daemon-stamped execution session (car#904) — the
|
|
1900
|
+
* attribution key for which mission a callback belongs to. Null when the
|
|
1901
|
+
* caller has no session. Prefer it over reconstructing attribution from
|
|
1902
|
+
* `action_id`, which is client-authored and not unique across concurrent or
|
|
1903
|
+
* retried attempts.
|
|
1904
|
+
* as a JSON string and MUST return a Promise resolving to the tool's
|
|
1680
1905
|
* JSON-encoded result. Throwing rejects the daemon-side action
|
|
1681
1906
|
* with a -32000 JSON-RPC error.
|
|
1682
1907
|
*
|
|
1908
|
+
* `request_id` is the daemon's callback-routing id, repeated by the
|
|
1909
|
+
* `tools.cancel` notification so the host can abort the right
|
|
1910
|
+
* in-flight call. `timeout_ms` is the action's declared budget in
|
|
1911
|
+
* milliseconds when the action declared one (`null` otherwise); the
|
|
1912
|
+
* host's tool runner may use it to bound its own work.
|
|
1913
|
+
*
|
|
1683
1914
|
* `action_id` carries the originating `Action.id` from the
|
|
1684
1915
|
* proposal so process-wide handlers can route concurrent
|
|
1685
1916
|
* callbacks back to the right per-call closure. Empty string when
|
|
@@ -1942,6 +2173,30 @@ export function resumeWorkflow(pausedJson: string, inputJson: string): Promise<s
|
|
|
1942
2173
|
* resumable runs after a restart. */
|
|
1943
2174
|
export function listPausedWorkflows(runsDir: string): string;
|
|
1944
2175
|
|
|
2176
|
+
/** Bind (or clear) the memory namespace for subsequent daemon connections
|
|
2177
|
+
* (car-releases#81). Returns the namespace now in effect, or `null` for the
|
|
2178
|
+
* daemon's shared graph.
|
|
2179
|
+
*
|
|
2180
|
+
* Prefer this over setting `CAR_MEMORY_NAMESPACE` when the namespace is
|
|
2181
|
+
* per-project. An env var cannot carry a per-project value: the host learns
|
|
2182
|
+
* which project it is *after* the process starts, and on **bun** a JS-side
|
|
2183
|
+
* `process.env` write never reaches the C `environ` this library reads — the
|
|
2184
|
+
* write is silently ignored and the session falls back to the shared graph.
|
|
2185
|
+
*
|
|
2186
|
+
* Blank or `null` clears the override, falling back to `CAR_MEMORY_NAMESPACE`
|
|
2187
|
+
* and then the shared graph.
|
|
2188
|
+
*
|
|
2189
|
+
* **Takes effect on the next connection.** The namespace is negotiated during
|
|
2190
|
+
* `session.auth`, so an already-established connection keeps the graph it
|
|
2191
|
+
* bound. Call this before your first CAR call, or disconnect afterwards to
|
|
2192
|
+
* force a rebind — otherwise you keep writing to the previous project's
|
|
2193
|
+
* graph. */
|
|
2194
|
+
export function setMemoryNamespace(namespace?: string | null): string | null;
|
|
2195
|
+
|
|
2196
|
+
/** The memory namespace currently in effect — the explicit override if set,
|
|
2197
|
+
* otherwise `CAR_MEMORY_NAMESPACE`, otherwise `null` (shared graph). */
|
|
2198
|
+
export function getMemoryNamespace(): string | null;
|
|
2199
|
+
|
|
1945
2200
|
/** NLP (F4): identify the dominant language of `text`. Returns
|
|
1946
2201
|
* `{language, backend}` JSON (Apple NaturalLanguage on macOS, pure-Rust
|
|
1947
2202
|
* fallback elsewhere). */
|
|
@@ -2145,10 +2400,25 @@ export function sendA2AMessage(rt: CarRuntime, paramsJson: string): Promise<stri
|
|
|
2145
2400
|
* `{ valid, issues, simulated_state, execution_levels, conflicts,
|
|
2146
2401
|
* evidence }`. `evidence` is the verifier's declared scope (survey
|
|
2147
2402
|
* "Code as Agent Harness" §5.2.2): `{ checks: [{ name, ran, verifies,
|
|
2148
|
-
* cannot_verify, findings }], assumptions, untested_regions,
|
|
2403
|
+
* cannot_verify, findings, tier }], assumptions, untested_regions,
|
|
2149
2404
|
* residual_risks, confidence }` — so a `valid: true` verdict can be read
|
|
2150
2405
|
* with its scope (what was checked, what was not, coverage confidence)
|
|
2151
2406
|
* rather than as a blanket guarantee.
|
|
2407
|
+
*
|
|
2408
|
+
* Each issue is `{ action_id, severity, message, tier }`. `tier` is the
|
|
2409
|
+
* **evidence tier** — `"decision_procedure" | "heuristic" | "sampled"` —
|
|
2410
|
+
* naming which kind of check produced the finding, so you don't have to
|
|
2411
|
+
* pattern-match the message to tell them apart. All of `verify`'s
|
|
2412
|
+
* findings are `decision_procedure` (set membership, the STRIPS-style
|
|
2413
|
+
* forward walk, write-conflict detection) except the
|
|
2414
|
+
* repeated-identical-call rule, which is `heuristic`: the count is
|
|
2415
|
+
* exact, "runaway loop" is a proxy, and a legitimate 3× poll trips it.
|
|
2416
|
+
* The tier is orthogonal to `severity` (how bad, not how derived), and
|
|
2417
|
+
* `decision_procedure` is not a proof or a soundness claim — it means
|
|
2418
|
+
* the check decides the property it reports over the inputs it was
|
|
2419
|
+
* given, which for the state-dependent checks is a forward model built
|
|
2420
|
+
* only from *declared* effects. Each `CheckRecord` carries the same
|
|
2421
|
+
* `tier` as the findings it contributed.
|
|
2152
2422
|
*/
|
|
2153
2423
|
export function verify(
|
|
2154
2424
|
proposalJson: string,
|
|
@@ -2652,8 +2922,13 @@ export function cascadeDecide(
|
|
|
2652
2922
|
*
|
|
2653
2923
|
* `statsJson` is aggregate counters (parsed by serde — keys are snake_case):
|
|
2654
2924
|
* `{ total_facts, structured_facts, total_edges, total_retrievals,
|
|
2655
|
-
* helpful_retrievals, conflicts_resolved,
|
|
2656
|
-
* facts_superseded }` (omitted fields
|
|
2925
|
+
* total_proactive_injections, helpful_retrievals, conflicts_resolved,
|
|
2926
|
+
* outstanding_outdated, facts_created, facts_superseded }` (omitted fields
|
|
2927
|
+
* default to 0). `total_retrievals` counts DELIBERATE recalls only;
|
|
2928
|
+
* harness-initiated proactive injections are reported separately as
|
|
2929
|
+
* `total_proactive_injections` and never feed ranking (car#816).
|
|
2930
|
+
* `helpful_retrievals` is always 0 today — `record_fact_helpful` has no
|
|
2931
|
+
* production caller — so read a 0 there as "not wired", not "nothing helped". Returns the report JSON:
|
|
2657
2932
|
* `{ representation_fidelity, retrieval_precision, update_correctness,
|
|
2658
2933
|
* long_horizon_stability, overall }` (each 0..1), `bottleneck` (one of
|
|
2659
2934
|
* `"representation" | "retrieval" | "update_correctness" |
|
|
@@ -2742,6 +3017,16 @@ export function simulateWithPredictions(
|
|
|
2742
3017
|
* `state_consistency` (changes, snapshots, rollbacks), `safety`
|
|
2743
3018
|
* (permission escalations/denials/approvals), and `replayability` — to
|
|
2744
3019
|
* complement task-success accuracy when comparing harness variants.
|
|
3020
|
+
*
|
|
3021
|
+
* The optional `task_pass_rate` field — and its two companions,
|
|
3022
|
+
* `task_pass_denominator` (how many tasks that rate is over) and
|
|
3023
|
+
* `tasks_unrunnable` (how many the runner could not measure) — are **always
|
|
3024
|
+
* absent** from this result: end-task success is not in the event stream (the
|
|
3025
|
+
* log records what ran, not whether the task was satisfied), and inventing any
|
|
3026
|
+
* of the three here would hand the regression gate a fabricated number. Only a
|
|
3027
|
+
* runner holding the task suite and its grading criteria can supply them —
|
|
3028
|
+
* `car-bench-harness --metrics-out` does. Absent means *not measured*, never
|
|
3029
|
+
* zero.
|
|
2745
3030
|
*/
|
|
2746
3031
|
export function harnessMetrics(eventsJsonl: string): string;
|
|
2747
3032
|
|
|
@@ -2817,9 +3102,30 @@ export function evolutionDiagnose(
|
|
|
2817
3102
|
* `HarnessMutation`; `baselineJson`/`candidateJson` are `HarnessMetrics`
|
|
2818
3103
|
* measured before/after applying it on held-out telemetry. Returns the
|
|
2819
3104
|
* `PromotionDecision` JSON `{ decision: "promote" | "needs_approval" |
|
|
2820
|
-
* "reject", reason }` — a mutation is promoted only if its
|
|
2821
|
-
* without regressing guarded metrics; safety-affecting
|
|
2822
|
-
* `needs_approval` even when they pass.
|
|
3105
|
+
* "reject" | "incomparable", reason }` — a mutation is promoted only if its
|
|
3106
|
+
* target improved without regressing guarded metrics; safety-affecting
|
|
3107
|
+
* mutations route to `needs_approval` even when they pass.
|
|
3108
|
+
*
|
|
3109
|
+
* Reliability is guarded twice, because the two available measures are
|
|
3110
|
+
* different quantities. `task_pass_rate` is end-task success and is checked
|
|
3111
|
+
* first, but only when BOTH documents carry it (absent on either side = not
|
|
3112
|
+
* measured, so the guard does not fire rather than defaulting to 0.0 or 1.0).
|
|
3113
|
+
* `trajectory_efficiency.success_rate` is tool-attempt success and is always
|
|
3114
|
+
* checked. A candidate that cuts tokens by abandoning hard tasks earlier holds
|
|
3115
|
+
* a perfect attempt-level rate while solving fewer tasks — only the first guard
|
|
3116
|
+
* sees that.
|
|
3117
|
+
*
|
|
3118
|
+
* Before either guard, the two pass rates must be over the SAME task set.
|
|
3119
|
+
* `HarnessMetrics` carries two optional companions to `task_pass_rate`:
|
|
3120
|
+
* `task_pass_denominator` (how many tasks the rate is over) and
|
|
3121
|
+
* `tasks_unrunnable` (how many the runner could not measure). When both
|
|
3122
|
+
* documents carry a denominator and they differ, the result is
|
|
3123
|
+
* `incomparable` — no verdict, nothing applied. That is not pedantry: a
|
|
3124
|
+
* harness that loses a capability also loses the ability to *measure* the
|
|
3125
|
+
* tasks needing it, so those tasks leave the denominator and the surviving
|
|
3126
|
+
* rate goes up. Both fields are optional and absent from documents written
|
|
3127
|
+
* before they existed, in which case the check is skipped rather than
|
|
3128
|
+
* failing.
|
|
2823
3129
|
*/
|
|
2824
3130
|
export function evolutionEvaluate(
|
|
2825
3131
|
mutationJson: string,
|
|
@@ -2849,11 +3155,76 @@ export function evolutionApply(
|
|
|
2849
3155
|
// (read_only | sandbox_edit | full_access), gate it against the session's
|
|
2850
3156
|
// granted standing tier, and record human-in-the-loop approvals as durable,
|
|
2851
3157
|
// auditable state (a JSONL ledger keyed by a stable action fingerprint).
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
3158
|
+
//
|
|
3159
|
+
// Two axes, not one. The tier answers "who may authorize this?" and says
|
|
3160
|
+
// nothing about whether the effect can be undone — a `git push`, a production
|
|
3161
|
+
// INSERT, and a charged card are all `full_access` with three different
|
|
3162
|
+
// rollback contracts. Every row below therefore carries a `reversibility`
|
|
3163
|
+
// alongside its `required_tier`.
|
|
3164
|
+
//
|
|
3165
|
+
// The matching Action IR fields (any `proposalJson` this package accepts, and
|
|
3166
|
+
// the full spec in docs/agent-ir-spec.md):
|
|
3167
|
+
//
|
|
3168
|
+
// "reversibility": "reversible" | "compensable" | "irreversible"
|
|
3169
|
+
// Optional. The rollback contract for this action's effects.
|
|
3170
|
+
// `reversible` is undone by restoring the scope it ran in;
|
|
3171
|
+
// `compensable` needs a compensating action run against it;
|
|
3172
|
+
// `irreversible` cannot be undone once it reaches the world.
|
|
3173
|
+
// **Defaults to "irreversible"** when omitted — deliberately, because
|
|
3174
|
+
// the default decides what the runtime believes about an unclassified
|
|
3175
|
+
// action and the two directions fail asymmetrically. Guessing
|
|
3176
|
+
// "reversible" wrongly means silently believing a sent email can be
|
|
3177
|
+
// unsent; guessing "irreversible" wrongly means over-asking for an
|
|
3178
|
+
// approval on something recoverable, which is annoying, visible, and
|
|
3179
|
+
// fixed locally by annotating the action.
|
|
3180
|
+
//
|
|
3181
|
+
// "compensation": { "type": "tool", "tool": string, "parameters"?: object }
|
|
3182
|
+
// | { "type": "action_ref", "action_id": string }
|
|
3183
|
+
// Optional. How to undo the action once it has run — the action-level
|
|
3184
|
+
// analogue of car-workflow's saga CompensationHandler. Meaningful only
|
|
3185
|
+
// with `"reversibility": "compensable"`; omitted from the serialized
|
|
3186
|
+
// form when absent, so older consumers see the payload they saw before.
|
|
3187
|
+
// Declaring one is a *claim*: nothing checks that the named tool is a
|
|
3188
|
+
// true inverse, exactly as nothing checks `expected_effects`.
|
|
3189
|
+
//
|
|
3190
|
+
// Nothing in the runtime enforces on either field yet — they are typed,
|
|
3191
|
+
// classified, and audited. Do not read `"reversible"` as a promise that the
|
|
3192
|
+
// runtime will undo anything for you: rollback restores the state map and
|
|
3193
|
+
// leaves whatever a tool wrote to disk where it is. See
|
|
3194
|
+
// docs/proposals/shepherd-substrate-adoption.md.
|
|
3195
|
+
|
|
3196
|
+
/**
|
|
3197
|
+
* Classify each action in a proposal on both authorization-adjacent axes.
|
|
3198
|
+
* Returns a JSON array of `{ action_id, tool, required_tier, reversibility,
|
|
3199
|
+
* missing_compensation }`. The keys live inside a JSON string, so they stay
|
|
3200
|
+
* snake_case — napi-rs camelCases function and parameter names, not payload
|
|
3201
|
+
* contents.
|
|
3202
|
+
*
|
|
3203
|
+
* - `required_tier` — **who may authorize this**: `"read_only" |
|
|
3204
|
+
* "sandbox_edit" | "full_access"`.
|
|
3205
|
+
* - `reversibility` — **can this be undone**: `"reversible" | "compensable" |
|
|
3206
|
+
* "irreversible"`. Independent of the tier and not derived from it:
|
|
3207
|
+
* `read_secret` is `full_access` and perfectly reversible (a read leaves
|
|
3208
|
+
* nothing to undo), while `send_email` and `deploy_service` are both
|
|
3209
|
+
* `full_access` and differ completely. This is the classifier's answer from
|
|
3210
|
+
* the tool name and flattened parameters — **not** an echo of the action's
|
|
3211
|
+
* declared `reversibility` field, which defaults to `"irreversible"` and so
|
|
3212
|
+
* would tell you only what you sent. It is a keyword heuristic: an
|
|
3213
|
+
* unrecognized tool comes back `"irreversible"`, deliberately.
|
|
3214
|
+
* - `missing_compensation` — the action **declared** `"compensable"` and
|
|
3215
|
+
* supplied no `compensation`, the one incoherent combination the IR cannot
|
|
3216
|
+
* exclude by construction. Keyed off the declared field, so it stays `false`
|
|
3217
|
+
* for proposals that never opted into the axis.
|
|
3218
|
+
*
|
|
3219
|
+
* Severity ascends `"reversible" < "compensable" < "irreversible"`, so the
|
|
3220
|
+
* rollback contract of a whole batch is the worst row — a plan is only as
|
|
3221
|
+
* recoverable as its least recoverable step. (The daemon's `permission.classify`
|
|
3222
|
+
* returns that roll-up precomputed as `declared_rollback_contract`, over the
|
|
3223
|
+
* *declared* fields; this function returns a bare array with nowhere to hang
|
|
3224
|
+
* it, so compute it from the column you care about.)
|
|
3225
|
+
*
|
|
3226
|
+
* Nothing in the runtime gates on the second axis yet — it is typed,
|
|
3227
|
+
* classified, and audited, not enforced.
|
|
2857
3228
|
*/
|
|
2858
3229
|
export function permissionClassify(proposalJson: string): string;
|
|
2859
3230
|
|
|
@@ -2861,10 +3232,17 @@ export function permissionClassify(proposalJson: string): string;
|
|
|
2861
3232
|
* Evaluate each action against a granted standing tier, consulting the
|
|
2862
3233
|
* durable approval ledger JSONL at `ledgerPath` when supplied. Returns a
|
|
2863
3234
|
* JSON array of per-action decisions, each `{ decision, required, granted,
|
|
2864
|
-
* action_id, fingerprint, ... }` where `decision` is `"allow" |
|
|
3235
|
+
* action_id, fingerprint, reversibility, ... }` where `decision` is `"allow" |
|
|
2865
3236
|
* "needs_approval" | "deny"`. A `needs_approval` decision means autonomy is
|
|
2866
3237
|
* suspended pending a human decision; resolve it with
|
|
2867
3238
|
* {@link permissionRecordForFingerprint}.
|
|
3239
|
+
*
|
|
3240
|
+
* `reversibility` is orthogonal to `decision` and rides on **every** row, the
|
|
3241
|
+
* `allow`s included: the gate's verdict says whether the action may run, not
|
|
3242
|
+
* whether it could be taken back afterwards, and a caller that only learns the
|
|
3243
|
+
* rollback contract of the actions it was stopped on is missing exactly the
|
|
3244
|
+
* rows an incident review reads first. Same field, labels, and classifier as
|
|
3245
|
+
* the `PermissionDecision` event the engine writes to its audit log.
|
|
2868
3246
|
*/
|
|
2869
3247
|
export function permissionEvaluate(
|
|
2870
3248
|
proposalJson: string,
|