car-runtime 0.47.0 → 0.49.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 +320 -19
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -151,6 +151,28 @@ export class CarRuntime {
|
|
|
151
151
|
/** Register a tool by name. */
|
|
152
152
|
registerTool(name: string): Promise<void>;
|
|
153
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
|
+
|
|
154
176
|
/** Register CAR's built-in agent utility tools. */
|
|
155
177
|
registerAgentBasics(): Promise<void>;
|
|
156
178
|
|
|
@@ -399,6 +421,26 @@ export class CarRuntime {
|
|
|
399
421
|
* dispatches the chosen components.
|
|
400
422
|
*/
|
|
401
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>;
|
|
402
444
|
/** `sync.status` — roster, journal frontier, stable frontier, state hash (B6). */
|
|
403
445
|
syncStatus(requestJson: string): Promise<string>;
|
|
404
446
|
/** `sync.append` — record an op on any surface: `{ surface, payload, scope? }` (B6). */
|
|
@@ -432,15 +474,97 @@ export class CarRuntime {
|
|
|
432
474
|
* Run one evolution cycle over the daemon's **live** signals — the
|
|
433
475
|
* self-evolution governor's real executor (arXiv 2507.21046). `requestJson`
|
|
434
476
|
* is `{ policy?, dry_run?, harness_baseline_metrics?,
|
|
435
|
-
* harness_candidate_metrics? }`; the daemon plans over all five live
|
|
477
|
+
* harness_candidate_metrics?, harness_measure?, context_measure? }`; the daemon plans over all five live
|
|
436
478
|
* components (Memory/Skills/Context from the engine, Harness from the event
|
|
437
479
|
* log, Tools from connector health) and dispatches each `EvolveNow`
|
|
438
480
|
* component: Memory → consolidate (sized by decide_maintenance), Skills →
|
|
439
481
|
* evolve_skills over event-log failure traces, Harness → the HITL-gated
|
|
440
482
|
* harness_evolution loop (pending approvals resolve via
|
|
441
|
-
* `permission.approve`/`reject` by fingerprint)
|
|
442
|
-
* `
|
|
443
|
-
* `
|
|
483
|
+
* `permission.approve`/`reject` by fingerprint), Context → the
|
|
484
|
+
* `context_evolution` loop, which resolves each mutation either through the
|
|
485
|
+
* opt-in pre-activation grader (`context_measure`) or, for whatever that did
|
|
486
|
+
* not decide, the diagnose→approve→apply→measure→revert human path. Returns
|
|
487
|
+
* the cycle record JSON
|
|
488
|
+
* `{ plan, steps, evolved, out_of_scope, pending_approvals?, measurement? }`,
|
|
489
|
+
* where each step is `{ component, ran, applied, out_of_scope, outcome }`.
|
|
490
|
+
*
|
|
491
|
+
* **Context.** Diagnoses off the engine's own live conversation-layer
|
|
492
|
+
* saturation and lowers `MemgineConfig.conversation_keep_recent` (halved,
|
|
493
|
+
* floored at 2) so compaction summarizes more of the older turns. Every
|
|
494
|
+
* mutation is HITL-gated on the same shared durable `ApprovalLedger` as
|
|
495
|
+
* harness ones, under its own fingerprint namespace
|
|
496
|
+
* `context:<component>:<patch-digest>`, resolved by the same
|
|
497
|
+
* `permission.approve`/`reject`. There **is** a pre-activation regression
|
|
498
|
+
* gate, opt-in via `context_measure` (see below) — this doc comment used to
|
|
499
|
+
* say there was none, because the bench replayed a runtime with no memgine
|
|
500
|
+
* attached and never offered a `recall` tool; bench tasks may now declare a
|
|
501
|
+
* `memory:` fixture and are then replayed with a real memgine and the shipped
|
|
502
|
+
* `recall` tool, so the assembled context moves with the knob. A graded
|
|
503
|
+
* mutation promotes (`applied` with `governance: "promoted"`) or is rejected
|
|
504
|
+
* (`rejected_by_gate`) with no operator in the loop. On the human-approved
|
|
505
|
+
* path — and whenever no grade ran — the daemon measures the MARGIN after the
|
|
506
|
+
* apply: compact under the unchanged value for a baseline
|
|
507
|
+
* (`conversation_tokens_baseline`), apply, compact again, and revert unless
|
|
508
|
+
* the tokens fell below that baseline (`rolled_back`, not counted as
|
|
509
|
+
* applied; `rollback_failed` with `rollback_error` if even the revert did
|
|
510
|
+
* not take). Comparing against the baseline rather than the uncompacted
|
|
511
|
+
* layer is what stops the change being credited with savings compaction
|
|
512
|
+
* would have produced anyway. So context is **not** unattended out of the
|
|
513
|
+
* box; it becomes unattended for a given change only once that fingerprint
|
|
514
|
+
* has been approved — and since the ledger is daemon-wide and the
|
|
515
|
+
* fingerprint names the change, that approval covers the same change on
|
|
516
|
+
* every engine this daemon evolves. On the unattended cadence a falsified
|
|
517
|
+
* mutation then backs off exponentially per fingerprint (`in_backoff`)
|
|
518
|
+
* instead of being re-applied and re-reverted every tick. The step's
|
|
519
|
+
* `outcome` is a JSON string `{ mechanism: "context_evolution", mutations,
|
|
520
|
+
* applied, pending, details }`, each detail carrying `mutation`,
|
|
521
|
+
* `component`, `fingerprint`, `rationale` and one of `pending_approval` |
|
|
522
|
+
* `applied` | `rolled_back` | `rollback_failed` | `apply_failed` |
|
|
523
|
+
* `would_apply` | `in_backoff` | `rejected_by_operator` |
|
|
524
|
+
* `approved_no_patch` | `rejected_by_gate` | `measurement_failed` |
|
|
525
|
+
* `config_moved_during_measurement` (a graded promotion whose measured base
|
|
526
|
+
* was moved by something else while the replays ran — nothing applied, both
|
|
527
|
+
* values reported, no backoff). When `context_measure` was requested the
|
|
528
|
+
* summary also carries `context_measured: { status: "measured" |
|
|
529
|
+
* "skipped_dry_run", grade_attempts, model, split, split_seed }`.
|
|
530
|
+
*
|
|
531
|
+
* **Tools** is recorded as `out_of_scope` — a decision, not a failure.
|
|
532
|
+
* Connector remediation means re-running a connector's OAuth or credential
|
|
533
|
+
* exchange, an access change this loop holds no authority to perform;
|
|
534
|
+
* reconnect/re-auth stay operator actions via `connectors.*`. Such a step is
|
|
535
|
+
* `ran: true, applied: false, out_of_scope: true` with the reason in
|
|
536
|
+
* `outcome`, and the component appears in the top-level `out_of_scope`
|
|
537
|
+
* array (always present, empty when none). `ran: false` therefore means one
|
|
538
|
+
* thing only: the mechanism was invoked and errored.
|
|
539
|
+
*
|
|
540
|
+
* `harness_measure` `{ model, split?, held_in_fraction?, split_seed?,
|
|
541
|
+
* max_turns?, tasks_dir? }` opts into **in-daemon measurement**: the daemon
|
|
542
|
+
* replays the held-out split itself (once for the baseline under the live
|
|
543
|
+
* `HarnessConfig`, once per measurable mutation under that config plus the
|
|
544
|
+
* mutation's patch) and feeds the regression gate, so a cycle can promote or
|
|
545
|
+
* reject unattended. It is mutually exclusive with the two supplied-metrics
|
|
546
|
+
* params (sending both errors, naming both); `dry_run` measures nothing and
|
|
547
|
+
* reports `measurement.status = "skipped_dry_run"`; a build with no
|
|
548
|
+
* in-process evaluator installed errors rather than degrading to HITL;
|
|
549
|
+
* safety-affecting and patchless mutations are never measured; a failed
|
|
550
|
+
* replay reports `measurement_failed` and fabricates no metrics.
|
|
551
|
+
*
|
|
552
|
+
* `context_measure` takes the SAME request shape and opts into the **Context
|
|
553
|
+
* pillar's** pre-activation grader: two replays over the same split, one
|
|
554
|
+
* under the engine's live `MemgineConfig` and one under it plus the
|
|
555
|
+
* mutation's patch, graded on TASK outcomes by the same gate. The two params
|
|
556
|
+
* are not mutually exclusive with each other (different pillars, two
|
|
557
|
+
* independent measurements). `dry_run` performs no replay; a build with no
|
|
558
|
+
* evaluator installed errors; a patchless mutation is never measured; the
|
|
559
|
+
* unattended cadence never requests a grade at all, so an idle timer cannot
|
|
560
|
+
* start spending benchmark replays.
|
|
561
|
+
* `measurement` is TOP-LEVEL on the response (not only inside the harness
|
|
562
|
+
* step) and present whenever `harness_measure` was requested, in every
|
|
563
|
+
* shape it can end in — `measured` / `skipped_dry_run` /
|
|
564
|
+
* `measurement_failed` with the error. A replay is a paid side effect and
|
|
565
|
+
* the plan may legitimately never dispatch Harness, so a side effect
|
|
566
|
+
* reported only from that step is one a caller can be billed for and never
|
|
567
|
+
* see.
|
|
444
568
|
*/
|
|
445
569
|
runEvolutionCycleLive(requestJson: string): Promise<string>;
|
|
446
570
|
|
|
@@ -472,6 +596,27 @@ export class CarRuntime {
|
|
|
472
596
|
*/
|
|
473
597
|
enforceSkillDeploymentLive(requestJson: string): Promise<string>;
|
|
474
598
|
|
|
599
|
+
/**
|
|
600
|
+
* Read the standing permission tier granted to this connection's daemon
|
|
601
|
+
* session (`read_only` | `sandbox_edit` | `full_access`) — the tier every
|
|
602
|
+
* {@link submitProposal} on this connection is judged against
|
|
603
|
+
* (Parslee-ai/car#890).
|
|
604
|
+
*/
|
|
605
|
+
permissionGetTier(): Promise<string>;
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Set this connection's standing permission tier and return the tier as the
|
|
609
|
+
* daemon now holds it. `tier` is `read_only` | `sandbox_edit` |
|
|
610
|
+
* `full_access`.
|
|
611
|
+
*
|
|
612
|
+
* Lets a binding client govern its own session — most usefully by tightening
|
|
613
|
+
* it: dropping to `read_only` makes the runtime escalate any write this
|
|
614
|
+
* client proposes to a human instead of running it. Raising the tier is
|
|
615
|
+
* host-gated whenever the daemon runs under a host token, so an agent
|
|
616
|
+
* connection cannot self-elevate.
|
|
617
|
+
*/
|
|
618
|
+
permissionSetTier(tier: string): Promise<string>;
|
|
619
|
+
|
|
475
620
|
/**
|
|
476
621
|
* Ingest a skill through the deployment gate on the daemon (arXiv 2602.12430
|
|
477
622
|
* "Agent Skills" — the loader integration). `requestJson` carries the skill
|
|
@@ -485,6 +630,21 @@ export class CarRuntime {
|
|
|
485
630
|
*/
|
|
486
631
|
ingestSkillGoverned(requestJson: string): Promise<string>;
|
|
487
632
|
|
|
633
|
+
/**
|
|
634
|
+
* Adopt an installed skill pack on the daemon through the skill-trust
|
|
635
|
+
* deployment gate (arXiv 2602.12430 "Agent Skills" — the pack-adoption
|
|
636
|
+
* call-site). `requestJson` carries `pack` (an `ApprovedSkillPack`),
|
|
637
|
+
* `requested_tier?` (default `read_only`), and either `manifest?` — the signed
|
|
638
|
+
* bundle, whose signature trust is derived against the operator's
|
|
639
|
+
* `.car/config.toml` `trusted_skill_signers` keyring — or `provenance?`
|
|
640
|
+
* (caller-assembled), plus optional `scanned?`/`vulnerabilities?`/`source?`.
|
|
641
|
+
* Governance is unconditional: a denied skill never enters the graph. Returns
|
|
642
|
+
* `{ loaded, pending, refused, requested_tier, provenance, trusted_signers }`;
|
|
643
|
+
* a pending deny is resolved via `permission.approve`/`permission.reject` by
|
|
644
|
+
* the returned `fingerprint`, then re-adopted.
|
|
645
|
+
*/
|
|
646
|
+
adoptSkillPack(requestJson: string): Promise<string>;
|
|
647
|
+
|
|
488
648
|
/**
|
|
489
649
|
* Save a learned skill with trigger context. Returns the node
|
|
490
650
|
* index.
|
|
@@ -597,6 +757,13 @@ export class CarRuntime {
|
|
|
597
757
|
* with reasoning suppressed to produce a direct answer, or
|
|
598
758
|
* `"thinking_truncated"` when even that retry was empty (car-releases#60).
|
|
599
759
|
*
|
|
760
|
+
* `auth_fallback_from` is present ONLY when a candidate earlier in the
|
|
761
|
+
* fallback chain was skipped because its credential was **rejected**
|
|
762
|
+
* (not merely absent) and a later model then answered. It names that
|
|
763
|
+
* dead lane, so a caller can tell the user their sign-in lapsed instead
|
|
764
|
+
* of silently serving a different model (Parslee-ai/car#888). Absent on
|
|
765
|
+
* the common path.
|
|
766
|
+
*
|
|
600
767
|
* **Note:** intent is not exposed on the tracked path until the
|
|
601
768
|
* positional argument list is converted to an options object —
|
|
602
769
|
* this method already takes 9 positional parameters and adding
|
|
@@ -782,8 +949,24 @@ export class CarRuntime {
|
|
|
782
949
|
/**
|
|
783
950
|
* Unified registry (local + remote). Returns JSON array of
|
|
784
951
|
* `{ id, name, provider, capabilities, param_count, size_mb,
|
|
785
|
-
* context_length, available, is_local,
|
|
786
|
-
* public_benchmarks, cost }`. `
|
|
952
|
+
* context_length, available, is_local, weights_ready, downloads_weights,
|
|
953
|
+
* max_output_tokens, public_benchmarks, cost }`. `available` means CAR
|
|
954
|
+
* can use the model
|
|
955
|
+
* here — for a local MLX entry with a declared `hf_repo` it is `true`
|
|
956
|
+
* before a byte is fetched, because it lazy-downloads on first use —
|
|
957
|
+
* whereas `weights_ready` means the weights are already on disk (remote
|
|
958
|
+
* models, having none to install, report `true`). Older daemons omit
|
|
959
|
+
* `weights_ready`; it defaults to `false` rather than failing.
|
|
960
|
+
* `downloads_weights` is `true` only for entries whose weights CAR fetches
|
|
961
|
+
* before use (GGUF, MLX, whisper.cpp); when it is `false` — OS-provided
|
|
962
|
+
* models such as `windows/speech-synthesis:os` and
|
|
963
|
+
* `apple/foundation:default`, server-backed local models such as
|
|
964
|
+
* `vllm-mlx/*` and Ollama, and every remote entry — there is nothing to
|
|
965
|
+
* install, so `weights_ready` is meaningless and the CLI renders
|
|
966
|
+
* `INSTALLED` as `-`. Do not substitute `is_local`: those first four are
|
|
967
|
+
* all local and all download nothing. Older daemons omit
|
|
968
|
+
* `downloads_weights`; it defaults to `false` rather than failing.
|
|
969
|
+
* `max_output_tokens` is the registry-declared
|
|
787
970
|
* per-model output ceiling (`null` when the entry omits it; callers
|
|
788
971
|
* then fall back to a fraction of `context_length`).
|
|
789
972
|
* `public_benchmarks` is `[{ name, score, harness?, source_url?,
|
|
@@ -968,10 +1151,10 @@ export class CarRuntime {
|
|
|
968
1151
|
* error}` plus `needs_you` (`"contract" | "question" | "approval" | "auth" |
|
|
969
1152
|
* null`), `needs_you_label` (the daemon-owned wording, so every client says
|
|
970
1153
|
* the same thing), `question_prompt`, `auth_message`, `auth_wait_secs`,
|
|
971
|
-
* `failure_kind` (`"budget_exhausted" | "auth_required" | "
|
|
972
|
-
* failed), `worktree` (only when it still exists on disk),
|
|
973
|
-
* `result_branch`, `model`, `discussion_id`, and `next_seq` (live
|
|
974
|
-
* the `coder.subscribe` cursor).
|
|
1154
|
+
* `failure_kind` (`"budget_exhausted" | "auth_required" | "infrastructure" |
|
|
1155
|
+
* "error"` when failed), `worktree` (only when it still exists on disk),
|
|
1156
|
+
* `project`, `result_branch`, `model`, `discussion_id`, and `next_seq` (live
|
|
1157
|
+
* only — the `coder.subscribe` cursor).
|
|
975
1158
|
*
|
|
976
1159
|
* Pass `renew: true` for the lease-renewal form: it re-registers and answers
|
|
977
1160
|
* `{ was_registered }` — `false` means this connection had been shed and
|
|
@@ -1457,11 +1640,60 @@ export class CarRuntime {
|
|
|
1457
1640
|
mailAccounts(): string;
|
|
1458
1641
|
|
|
1459
1642
|
/**
|
|
1460
|
-
* Returns JSON inbox snapshot
|
|
1461
|
-
*
|
|
1643
|
+
* Returns JSON inbox snapshot
|
|
1644
|
+
* `{ available, backend, reason?, summaries: InboxSummary[] }` — per-account
|
|
1645
|
+
* unread/total counts, not message rows. Use `mailMessages` for rows.
|
|
1646
|
+
* `accountIdsCsv` is an optional comma-separated filter; omit to query all
|
|
1647
|
+
* known accounts.
|
|
1462
1648
|
*/
|
|
1463
1649
|
mailInbox(accountIdsCsv?: string | null): string;
|
|
1464
1650
|
|
|
1651
|
+
/**
|
|
1652
|
+
* Enumerate every mailbox (folder) of the given accounts, nested ones
|
|
1653
|
+
* included on BOTH backends. Returns
|
|
1654
|
+
* `{ available, backend, reason?, mailboxes: Mailbox[] }` where `Mailbox`
|
|
1655
|
+
* is `{ account_id, name, full_name, unread, total }`.
|
|
1656
|
+
*
|
|
1657
|
+
* `full_name` is the selector to pass back as `MessageQuery.mailbox` — the
|
|
1658
|
+
* slash-joined path on macOS, the folder id on Microsoft Graph. Graph's
|
|
1659
|
+
* `/me/mailFolders` is root-only, so nested folders come from a bounded
|
|
1660
|
+
* `childFolders` walk (depth 8, at most 64 requests); a tree deeper or
|
|
1661
|
+
* wider than that is truncated.
|
|
1662
|
+
*
|
|
1663
|
+
* An `accountIdsCsv` that matches no account returns `available: false`
|
|
1664
|
+
* with a reason, not an empty list.
|
|
1665
|
+
*/
|
|
1666
|
+
mailMailboxes(accountIdsCsv?: string | null): string;
|
|
1667
|
+
|
|
1668
|
+
/**
|
|
1669
|
+
* Read message rows, newest first. `queryJson` is a `MessageQuery`:
|
|
1670
|
+
* `{account_ids?: string[], mailbox?: string | null, limit?: number,
|
|
1671
|
+
* since?: string, include_body?: boolean}`. Every field defaults, and
|
|
1672
|
+
* `mailbox: null` means INBOX — so `"{}"` reproduces the pre-existing
|
|
1673
|
+
* INBOX-only read.
|
|
1674
|
+
*
|
|
1675
|
+
* "Newest first" is GLOBAL, not per account: rows from every matched
|
|
1676
|
+
* account are merged into one date-ordered list before `limit` applies, so
|
|
1677
|
+
* `limit: 1` across two accounts returns the newer message rather than
|
|
1678
|
+
* whichever account the backend listed first.
|
|
1679
|
+
*
|
|
1680
|
+
* Returns `{ available, backend, reason?, messages: MessageSummary[] }`;
|
|
1681
|
+
* each row carries a stable opaque `id` accepted by `mailMessageBody`, and
|
|
1682
|
+
* a `mailbox` holding the mailbox as the backend RESOLVED it (a query for
|
|
1683
|
+
* `"travel"` comes back stamped `"Travel/2026"`), so rows match
|
|
1684
|
+
* `mailMailboxes` output. An unresolvable mailbox or an unmatched
|
|
1685
|
+
* `account_ids` returns `available: false` with a reason, never an empty
|
|
1686
|
+
* list.
|
|
1687
|
+
*/
|
|
1688
|
+
mailMessages(queryJson: string): string;
|
|
1689
|
+
|
|
1690
|
+
/**
|
|
1691
|
+
* Fetch one message body by the `id` from a `mailMessages` row. Returns
|
|
1692
|
+
* `{ available, backend, reason?, id, content_type, body, truncated }`;
|
|
1693
|
+
* bodies are cut at 100,000 characters with `truncated: true`.
|
|
1694
|
+
*/
|
|
1695
|
+
mailMessageBody(messageId: string): string;
|
|
1696
|
+
|
|
1465
1697
|
/**
|
|
1466
1698
|
* Send mail. `sendRequestJson` is `{to, subject, body, ...}` per the
|
|
1467
1699
|
* provider contract. Returns JSON `{ok, message_id?}`.
|
|
@@ -1528,10 +1760,25 @@ export class CarRuntime {
|
|
|
1528
1760
|
/**
|
|
1529
1761
|
* Execute a proposal through a CarRuntime with a JS tool callback.
|
|
1530
1762
|
* The callback receives
|
|
1531
|
-
* `{"tool":"name","params":{...},"action_id":"<id>"}`
|
|
1532
|
-
*
|
|
1763
|
+
* `{"tool":"name","params":{...},"action_id":"<id>","request_id":"<id>","timeout_ms":<ms|null>,"session_id":"<id>|null","attempt":<n>}`
|
|
1764
|
+
*
|
|
1765
|
+
* `attempt` is the engine's retry counter, 1-based — which retry you are
|
|
1766
|
+
* serving. (Correlate a specific in-flight call by `request_id` instead.) It
|
|
1767
|
+
* was hardcoded to 1 on the wire and dropped here before car#928.
|
|
1768
|
+
*
|
|
1769
|
+
* `session_id` is the daemon-stamped execution session (car#904) — the
|
|
1770
|
+
* attribution key for which mission a callback belongs to. Null when the
|
|
1771
|
+
* caller has no session. Prefer it over reconstructing attribution from
|
|
1772
|
+
* `action_id`, which is client-authored and not unique across concurrent or
|
|
1773
|
+
* retried attempts.
|
|
1774
|
+
* as a JSON string and must return a JSON string. `action_id` is the
|
|
1533
1775
|
* originating `Action.id` from the proposal — useful for routing
|
|
1534
1776
|
* when the same callback closes over multiple in-flight calls.
|
|
1777
|
+
* `request_id` is the daemon's callback-routing id, which a
|
|
1778
|
+
* `tools.cancel` notification repeats so the host can abort the right
|
|
1779
|
+
* in-flight call. `timeout_ms` is the action's declared budget in
|
|
1780
|
+
* milliseconds when the action declared one (`null` otherwise); the
|
|
1781
|
+
* host's tool runner may use it to bound its own work.
|
|
1535
1782
|
*
|
|
1536
1783
|
* `sessionId`, when provided, scopes per-action policy validation to
|
|
1537
1784
|
* the named session opened via `CarRuntime.openSession()`. Global
|
|
@@ -1749,6 +1996,13 @@ export function registerVoiceEventHandler(
|
|
|
1749
1996
|
* Promise is logged, not surfaced to the host. Process-wide setter,
|
|
1750
1997
|
* symmetric to `registerVoiceEventHandler`; pair with
|
|
1751
1998
|
* `unregisterChatHandler` to clear.
|
|
1999
|
+
*
|
|
2000
|
+
* The handler may call any runtime method and should run the turn inline.
|
|
2001
|
+
* NAPI dispatches through a non-blocking `ThreadsafeFunction` and `chatEvent`
|
|
2002
|
+
* is async, so this side never had the reentrancy hazard that made the same
|
|
2003
|
+
* surface unusable from Python before Parslee-ai/car#905 — noted here because
|
|
2004
|
+
* the two bindings' handlers now carry the same contract for the same reason,
|
|
2005
|
+
* arrived at differently.
|
|
1752
2006
|
*/
|
|
1753
2007
|
export function registerChatHandler(
|
|
1754
2008
|
handlerFn: (paramsJson: string) => void,
|
|
@@ -1767,11 +2021,27 @@ export function unregisterChatHandler(): void;
|
|
|
1767
2021
|
* this handler.
|
|
1768
2022
|
*
|
|
1769
2023
|
* `handlerFn(callJson)` receives
|
|
1770
|
-
* `{"tool":"name","params":{...},"action_id":"<id>"}`
|
|
1771
|
-
*
|
|
2024
|
+
* `{"tool":"name","params":{...},"action_id":"<id>","request_id":"<id>","timeout_ms":<ms|null>,"session_id":"<id>|null","attempt":<n>}`
|
|
2025
|
+
*
|
|
2026
|
+
* `attempt` is the engine's retry counter, 1-based — which retry you are
|
|
2027
|
+
* serving. (Correlate a specific in-flight call by `request_id` instead.) It
|
|
2028
|
+
* was hardcoded to 1 on the wire and dropped here before car#928.
|
|
2029
|
+
*
|
|
2030
|
+
* `session_id` is the daemon-stamped execution session (car#904) — the
|
|
2031
|
+
* attribution key for which mission a callback belongs to. Null when the
|
|
2032
|
+
* caller has no session. Prefer it over reconstructing attribution from
|
|
2033
|
+
* `action_id`, which is client-authored and not unique across concurrent or
|
|
2034
|
+
* retried attempts.
|
|
2035
|
+
* as a JSON string and MUST return a Promise resolving to the tool's
|
|
1772
2036
|
* JSON-encoded result. Throwing rejects the daemon-side action
|
|
1773
2037
|
* with a -32000 JSON-RPC error.
|
|
1774
2038
|
*
|
|
2039
|
+
* `request_id` is the daemon's callback-routing id, repeated by the
|
|
2040
|
+
* `tools.cancel` notification so the host can abort the right
|
|
2041
|
+
* in-flight call. `timeout_ms` is the action's declared budget in
|
|
2042
|
+
* milliseconds when the action declared one (`null` otherwise); the
|
|
2043
|
+
* host's tool runner may use it to bound its own work.
|
|
2044
|
+
*
|
|
1775
2045
|
* `action_id` carries the originating `Action.id` from the
|
|
1776
2046
|
* proposal so process-wide handlers can route concurrent
|
|
1777
2047
|
* callbacks back to the right per-call closure. Empty string when
|
|
@@ -2878,6 +3148,16 @@ export function simulateWithPredictions(
|
|
|
2878
3148
|
* `state_consistency` (changes, snapshots, rollbacks), `safety`
|
|
2879
3149
|
* (permission escalations/denials/approvals), and `replayability` — to
|
|
2880
3150
|
* complement task-success accuracy when comparing harness variants.
|
|
3151
|
+
*
|
|
3152
|
+
* The optional `task_pass_rate` field — and its two companions,
|
|
3153
|
+
* `task_pass_denominator` (how many tasks that rate is over) and
|
|
3154
|
+
* `tasks_unrunnable` (how many the runner could not measure) — are **always
|
|
3155
|
+
* absent** from this result: end-task success is not in the event stream (the
|
|
3156
|
+
* log records what ran, not whether the task was satisfied), and inventing any
|
|
3157
|
+
* of the three here would hand the regression gate a fabricated number. Only a
|
|
3158
|
+
* runner holding the task suite and its grading criteria can supply them —
|
|
3159
|
+
* `car-bench-harness --metrics-out` does. Absent means *not measured*, never
|
|
3160
|
+
* zero.
|
|
2881
3161
|
*/
|
|
2882
3162
|
export function harnessMetrics(eventsJsonl: string): string;
|
|
2883
3163
|
|
|
@@ -2953,9 +3233,30 @@ export function evolutionDiagnose(
|
|
|
2953
3233
|
* `HarnessMutation`; `baselineJson`/`candidateJson` are `HarnessMetrics`
|
|
2954
3234
|
* measured before/after applying it on held-out telemetry. Returns the
|
|
2955
3235
|
* `PromotionDecision` JSON `{ decision: "promote" | "needs_approval" |
|
|
2956
|
-
* "reject", reason }` — a mutation is promoted only if its
|
|
2957
|
-
* without regressing guarded metrics; safety-affecting
|
|
2958
|
-
* `needs_approval` even when they pass.
|
|
3236
|
+
* "reject" | "incomparable", reason }` — a mutation is promoted only if its
|
|
3237
|
+
* target improved without regressing guarded metrics; safety-affecting
|
|
3238
|
+
* mutations route to `needs_approval` even when they pass.
|
|
3239
|
+
*
|
|
3240
|
+
* Reliability is guarded twice, because the two available measures are
|
|
3241
|
+
* different quantities. `task_pass_rate` is end-task success and is checked
|
|
3242
|
+
* first, but only when BOTH documents carry it (absent on either side = not
|
|
3243
|
+
* measured, so the guard does not fire rather than defaulting to 0.0 or 1.0).
|
|
3244
|
+
* `trajectory_efficiency.success_rate` is tool-attempt success and is always
|
|
3245
|
+
* checked. A candidate that cuts tokens by abandoning hard tasks earlier holds
|
|
3246
|
+
* a perfect attempt-level rate while solving fewer tasks — only the first guard
|
|
3247
|
+
* sees that.
|
|
3248
|
+
*
|
|
3249
|
+
* Before either guard, the two pass rates must be over the SAME task set.
|
|
3250
|
+
* `HarnessMetrics` carries two optional companions to `task_pass_rate`:
|
|
3251
|
+
* `task_pass_denominator` (how many tasks the rate is over) and
|
|
3252
|
+
* `tasks_unrunnable` (how many the runner could not measure). When both
|
|
3253
|
+
* documents carry a denominator and they differ, the result is
|
|
3254
|
+
* `incomparable` — no verdict, nothing applied. That is not pedantry: a
|
|
3255
|
+
* harness that loses a capability also loses the ability to *measure* the
|
|
3256
|
+
* tasks needing it, so those tasks leave the denominator and the surviving
|
|
3257
|
+
* rate goes up. Both fields are optional and absent from documents written
|
|
3258
|
+
* before they existed, in which case the check is skipped rather than
|
|
3259
|
+
* failing.
|
|
2959
3260
|
*/
|
|
2960
3261
|
export function evolutionEvaluate(
|
|
2961
3262
|
mutationJson: string,
|