@coreplane/switchboard 1.251.0 → 1.253.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/dist/assets/config/config.example.yaml +28 -2
- package/dist/assets/deploy/cloudflare/preflight.mjs +19 -21
- package/dist/assets/deploy/cloudflare/worker.ts +6 -3
- package/dist/assets/deploy/cloudflare-memory/runMetricsSink.ts +31 -0
- package/dist/assets/deploy/cloudflare-memory/worker.ts +223 -38
- package/dist/assets/deploy/cloudflare-memory/wrangler.template.jsonc +12 -0
- package/dist/assets/deploy/cloudflare-resident/memoryGuard.ts +212 -0
- package/dist/assets/deploy/cloudflare-resident/refresh.ts +1 -1
- package/dist/assets/deploy/cloudflare-resident/worker.ts +317 -56
- package/dist/assets/deploy/cloudflare-sandbox/Dockerfile +4 -2
- package/dist/assets/deploy/cloudflare-sandbox/runtime-supervisor.d.mts +31 -0
- package/dist/assets/deploy/cloudflare-sandbox/runtime-supervisor.mjs +119 -0
- package/dist/assets/deploy/profile.example.json +1 -1
- package/dist/assets/package-lock.json +3 -3
- package/dist/assets/package.json +3 -2
- package/dist/assets/project.json +13 -9
- package/dist/assets/source.json +3 -3
- package/dist/assets/src/agents/registry.ts +5 -5
- package/dist/assets/src/core/authz/policy.ts +8 -0
- package/dist/assets/src/core/budgets.ts +39 -0
- package/dist/assets/src/core/coordinator/contract.ts +93 -1
- package/dist/assets/src/core/coordinator/driver.ts +236 -21
- package/dist/assets/src/core/drain.ts +50 -0
- package/dist/assets/src/core/memory/engine.ts +123 -4
- package/dist/assets/src/core/memory/scorer.ts +12 -4
- package/dist/assets/src/core/memory/types.ts +73 -12
- package/dist/assets/src/core/modelCard.ts +32 -4
- package/dist/assets/src/core/modelPricing.ts +111 -1
- package/dist/assets/src/core/modelProxy/usage.ts +88 -0
- package/dist/assets/src/core/modelRegistry.ts +15 -1
- package/dist/assets/src/core/refusal.ts +4 -7
- package/dist/assets/src/core/reviewVerdict.ts +4 -0
- package/dist/assets/src/core/runEvents.ts +82 -3
- package/dist/assets/src/core/runFriction.ts +8 -2
- package/dist/assets/src/core/runLedger/types.ts +11 -0
- package/dist/assets/src/core/runMetrics.ts +237 -0
- package/dist/assets/src/core/runRecord.ts +46 -0
- package/dist/assets/src/core/runUsage.ts +67 -13
- package/dist/assets/src/core/schedules.ts +3 -0
- package/dist/assets/src/core/ship/contract.ts +34 -14
- package/dist/assets/src/core/ship/coordinator.ts +485 -55
- package/dist/assets/src/core/ship/renewal.ts +10 -5
- package/dist/assets/src/core/trace/attrs.ts +24 -0
- package/dist/assets/src/core/types.ts +5 -5
- package/dist/assets/src/core/verbosity.ts +48 -0
- package/dist/assets/src/deploy/liveGate.ts +40 -13
- package/dist/assets/src/deploy/profile.ts +16 -0
- package/dist/assets/src/deploy/restart.ts +11 -12
- package/dist/assets/src/execution/residentDepCache.ts +50 -1
- package/dist/assets/src/execution/residentDepsStore.ts +40 -2
- package/dist/assets/src/execution/residentRefresh.ts +55 -3
- package/dist/assets/src/execution/residentSteps.ts +4 -0
- package/dist/assets/src/execution/sandboxErrors.ts +8 -0
- package/dist/assets/web/dist/.vite/manifest.json +444 -430
- package/dist/assets/web/dist/assets/{AppShell-DAtHiuI6.js → AppShell-Bmz8nzz3.js} +1 -1
- package/dist/assets/web/dist/assets/{CostsPage-BoKzYa4B.js → CostsPage-CxTKdpzU.js} +1 -1
- package/dist/assets/web/dist/assets/{DeliveryPage-DUXd-Sl-.js → DeliveryPage-C7jaEJip.js} +1 -1
- package/dist/assets/web/dist/assets/HomePage-cWbupQzy.js +3 -0
- package/dist/assets/web/dist/assets/{InputMenu-C6aPpe30.js → InputMenu-C9E7YoII.js} +1 -1
- package/dist/assets/web/dist/assets/{NotFoundPage-DtE-GgTk.js → NotFoundPage-4nlrq7DP.js} +1 -1
- package/dist/assets/web/dist/assets/{PendingTurnRow-DDhMhrI7.js → PendingTurnRow-C-pUgyyX.js} +1 -1
- package/dist/assets/web/dist/assets/PlanePage-BNy4tSgJ.js +1 -0
- package/dist/assets/web/dist/assets/{ResidentDetailPage-BnEoOnGQ.js → ResidentDetailPage-Dbtiq6_J.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-Dxpgf-l-.js → ResidentsIndexPage-CKtz9H1o.js} +1 -1
- package/dist/assets/web/dist/assets/RunFoldRow-sYFtuK2G.js +1 -0
- package/dist/assets/web/dist/assets/RunRoutePage-Clh68nw9.js +9 -0
- package/dist/assets/web/dist/assets/RunsIndexPage-DPDbcOA_.js +1 -0
- package/dist/assets/web/dist/assets/{RunsTabs-YSbUu5py.js → RunsTabs-DotpuCSP.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-B_GgeJrb.js → ScheduledPage-C8FYoZy5.js} +1 -1
- package/dist/assets/web/dist/assets/{SettingSelect-BIzAsLk1.js → SettingSelect-CSiBQCSX.js} +1 -1
- package/dist/assets/web/dist/assets/{SettingsPage-BXX4R113.js → SettingsPage-CkYIhLUl.js} +1 -1
- package/dist/assets/web/dist/assets/{StatusDot-BOaw8le9.js → StatusDot-C0TUgnC1.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-DYZZ4l4V.js → Tooltip-CN5cZdl3.js} +1 -1
- package/dist/assets/web/dist/assets/{UnitRoutePage-BaSW5Odq.js → UnitRoutePage-D_EtAl8r.js} +1 -1
- package/dist/assets/web/dist/assets/{angular-html-BjeQZdCq.js → angular-html-qW40ZL9x.js} +1 -1
- package/dist/assets/web/dist/assets/{angular-ts-ZGdORrL2.js → angular-ts-PUtZU8Cq.js} +1 -1
- package/dist/assets/web/dist/assets/{apl-DhvV_X93.js → apl-D3fC7Qjd.js} +1 -1
- package/dist/assets/web/dist/assets/{astro-DiRSE4Ug.js → astro-Bi3JFHhh.js} +1 -1
- package/dist/assets/web/dist/assets/{blade-D8Fr5Wvq.js → blade-CSpsf9Z9.js} +1 -1
- package/dist/assets/web/dist/assets/budgets-CbIyPAER.js +1 -0
- package/dist/assets/web/dist/assets/{c-BwbC64D4.js → c-DE_b1oWP.js} +1 -1
- package/dist/assets/web/dist/assets/{chapel-DgmqRK97.js → chapel-CWXd9giL.js} +1 -1
- package/dist/assets/web/dist/assets/{cobol-DJod2RNK.js → cobol-CnMOmWNF.js} +1 -1
- package/dist/assets/web/dist/assets/{coffee-D1Y2CgBY.js → coffee-B9WvURu8.js} +1 -1
- package/dist/assets/web/dist/assets/{cpp-CsO97YOM.js → cpp-BZAJXlWI.js} +1 -1
- package/dist/assets/web/dist/assets/{crystal-CJ7m2tOc.js → crystal-Bm48wAlb.js} +1 -1
- package/dist/assets/web/dist/assets/{css-B2M-NKoj.js → css-WtMeC3ab.js} +1 -1
- package/dist/assets/web/dist/assets/{dist-BCVXeBJ9.js → dist-B1Mf2JbM.js} +2 -2
- package/dist/assets/web/dist/assets/{edge-CFVW-m9B.js → edge-BmwNa6Ss.js} +1 -1
- package/dist/assets/web/dist/assets/{elixir-B2mtRgCr.js → elixir-BotfP-Mn.js} +1 -1
- package/dist/assets/web/dist/assets/{elm-2teVAwCi.js → elm-DAFc6laN.js} +1 -1
- package/dist/assets/web/dist/assets/{erb-LAbeNqen.js → erb-QkOON3bB.js} +1 -1
- package/dist/assets/web/dist/assets/{git-rebase-DnhzH_sp.js → git-rebase-BPs-dd73.js} +1 -1
- package/dist/assets/web/dist/assets/{glimmer-js-DPKjXf1-.js → glimmer-js-D8eooepk.js} +1 -1
- package/dist/assets/web/dist/assets/{glimmer-ts-CABXnt5z.js → glimmer-ts-B0bRiDVg.js} +1 -1
- package/dist/assets/web/dist/assets/{glsl-Dz4-3-gJ.js → glsl-Bv6bMe1n.js} +1 -1
- package/dist/assets/web/dist/assets/{graphql-ByWUD1DL.js → graphql-Bh9y-n9o.js} +1 -1
- package/dist/assets/web/dist/assets/{hack-CdmOK2K-.js → hack-DSEbn7Ir.js} +1 -1
- package/dist/assets/web/dist/assets/{haml-DzegMpd2.js → haml-0NW1-z1f.js} +1 -1
- package/dist/assets/web/dist/assets/{handlebars-B5NeiP0e.js → handlebars-BfgCHFbK.js} +1 -1
- package/dist/assets/web/dist/assets/{html-Zg_NHLv9.js → html-CQHc0gQ5.js} +1 -1
- package/dist/assets/web/dist/assets/{html-derivative-DZf9JNzh.js → html-derivative-B0Tm7wLP.js} +1 -1
- package/dist/assets/web/dist/assets/{http-CVFrQZeN.js → http-GAuU3aOF.js} +1 -1
- package/dist/assets/web/dist/assets/{hurl-L5brWAJe.js → hurl-CrDFbF5B.js} +1 -1
- package/dist/assets/web/dist/assets/indexRow-BxKswdlK.js +1 -0
- package/dist/assets/web/dist/assets/{java-hFphyZ4R.js → java-DYv5KhUe.js} +1 -1
- package/dist/assets/web/dist/assets/{javascript-CAJO1WKX.js → javascript-32SiLGg0.js} +1 -1
- package/dist/assets/web/dist/assets/{jinja-N4A4srXI.js → jinja--gJDUGYa.js} +1 -1
- package/dist/assets/web/dist/assets/{jison-D3BZa_iU.js → jison-BlKLGzZH.js} +1 -1
- package/dist/assets/web/dist/assets/{json-DxD1Qh8W.js → json-BICanD1N.js} +1 -1
- package/dist/assets/web/dist/assets/{jsx-CHhag69S.js → jsx-CgW3-uFT.js} +1 -1
- package/dist/assets/web/dist/assets/{julia-CrhkZ6Tt.js → julia-BErRpwwL.js} +1 -1
- package/dist/assets/web/dist/assets/{just-D0LFOuhq.js → just-CordHv0h.js} +1 -1
- package/dist/assets/web/dist/assets/{latex-BHAlwCXK.js → latex-D7LVPLbi.js} +1 -1
- package/dist/assets/web/dist/assets/{liquid-CkaLfCWh.js → liquid-3ehz2i4U.js} +1 -1
- package/dist/assets/web/dist/assets/{lua-B1h4aAzP.js → lua-C9ppSVrm.js} +1 -1
- package/dist/assets/web/dist/assets/main-Cv0q9y56.js +28 -0
- package/dist/assets/web/dist/assets/main-DKFCM-sy.css +1 -0
- package/dist/assets/web/dist/assets/{marko-D6CG4hvX.js → marko-xBZLUBEJ.js} +1 -1
- package/dist/assets/web/dist/assets/{mdc-CVQzimAU.js → mdc-BJxGoVgD.js} +1 -1
- package/dist/assets/web/dist/assets/{nginx-h-9Ir54h.js → nginx-B-sZmpsb.js} +1 -1
- package/dist/assets/web/dist/assets/{nim-DHVI30sp.js → nim--s9wRABK.js} +1 -1
- package/dist/assets/web/dist/assets/{org-AasAXfMF.js → org-DoUvssoI.js} +1 -1
- package/dist/assets/web/dist/assets/{perl-BVi5aTEy.js → perl-B-vGHKOy.js} +1 -1
- package/dist/assets/web/dist/assets/{php-qOkCeUKr.js → php-CerWx_Xb.js} +1 -1
- package/dist/assets/web/dist/assets/{pug-8TnUGvEX.js → pug-CzKrBMb1.js} +1 -1
- package/dist/assets/web/dist/assets/{qml-CpJbhoxn.js → qml-Bs8L8I6k.js} +1 -1
- package/dist/assets/web/dist/assets/{r-JkUNcAJW.js → r-w6uG6mob.js} +1 -1
- package/dist/assets/web/dist/assets/{razor-CtU4ws5a.js → razor-dz2oj2bd.js} +1 -1
- package/dist/assets/web/dist/assets/{regexp-J2zA6ceN.js → regexp-CfQdprnY.js} +1 -1
- package/dist/assets/web/dist/assets/{rst-CMCvf-yZ.js → rst-DAOaX2tb.js} +1 -1
- package/dist/assets/web/dist/assets/{ruby-ChLBY_iR.js → ruby-QcCe4udB.js} +1 -1
- package/dist/assets/web/dist/assets/{sas-cwn4x2VY.js → sas-BrM4lAAc.js} +1 -1
- package/dist/assets/web/dist/assets/{scss-jSrJlzLI.js → scss-DVbJXoUb.js} +1 -1
- package/dist/assets/web/dist/assets/{shellscript-D5nAd0gs.js → shellscript-09fP2hZf.js} +1 -1
- package/dist/assets/web/dist/assets/{shellsession-BZY4-Tdh.js → shellsession-Qgr8xjZF.js} +1 -1
- package/dist/assets/web/dist/assets/{soy-COppPOKr.js → soy-DIYeNTuz.js} +1 -1
- package/dist/assets/web/dist/assets/{sql-Blc_6dOA.js → sql-CzLR9msV.js} +1 -1
- package/dist/assets/web/dist/assets/sseReplay-BYo2EZKy.js +11 -0
- package/dist/assets/web/dist/assets/{stata-DRv3OY-h.js → stata-zCY1ZzH0.js} +1 -1
- package/dist/assets/web/dist/assets/{surrealql-qMv_eeJ6.js → surrealql-CJIjTRV4.js} +1 -1
- package/dist/assets/web/dist/assets/{svelte-d1Edb6Rz.js → svelte-C5OTPFZg.js} +1 -1
- package/dist/assets/web/dist/assets/{templ-CUMSIOXG.js → templ-DYj-UICF.js} +1 -1
- package/dist/assets/web/dist/assets/{tex-BGZQA-Ei.js → tex-xcie-3Gd.js} +1 -1
- package/dist/assets/web/dist/assets/{ts-tags-Z9ulxVsq.js → ts-tags-CoN86VTt.js} +1 -1
- package/dist/assets/web/dist/assets/{tsx-oI4bI3Vf.js → tsx-n3-No_Br.js} +1 -1
- package/dist/assets/web/dist/assets/{twig-D_RXwBIX.js → twig-DPiJ7Vp1.js} +1 -1
- package/dist/assets/web/dist/assets/{typescript-BgqQDYoN.js → typescript-BP6HBaOp.js} +1 -1
- package/dist/assets/web/dist/assets/{typst-5MW-KRDd.js → typst-Do9ZjsVP.js} +1 -1
- package/dist/assets/web/dist/assets/{vue-CZhHHsPm.js → vue-CzAeXNRY.js} +1 -1
- package/dist/assets/web/dist/assets/{vue-html-DlYy2d8v.js → vue-html-D7iYmYjd.js} +1 -1
- package/dist/assets/web/dist/assets/{vue-vine-CJDnx-qn.js → vue-vine-DtrMRsJx.js} +1 -1
- package/dist/assets/web/dist/assets/{xml-BRBDk65Q.js → xml-DGJHo1c0.js} +1 -1
- package/dist/assets/web/dist/assets/{xsl-BlCykPxo.js → xsl-Q00kvNgW.js} +1 -1
- package/dist/assets/web/dist/assets/{yaml-BqW48szf.js → yaml-F-UGKaiO.js} +1 -1
- package/dist/cli.js +5623 -2455
- package/package.json +1 -1
- package/dist/assets/deploy/cloudflare-sandbox/runtime-supervisor.sh +0 -68
- package/dist/assets/web/dist/assets/HomePage-mSiqEEcN.js +0 -2
- package/dist/assets/web/dist/assets/RunFoldRow-CSo4-vld.js +0 -1
- package/dist/assets/web/dist/assets/RunRoutePage-9klVWhSF.js +0 -9
- package/dist/assets/web/dist/assets/RunsIndexPage-BplMIgaw.js +0 -1
- package/dist/assets/web/dist/assets/budgets-BvWYKPsY.js +0 -1
- package/dist/assets/web/dist/assets/indexRow-Bde9OZxG.js +0 -1
- package/dist/assets/web/dist/assets/main-Dkcbtu3u.js +0 -28
- package/dist/assets/web/dist/assets/main-zbP_dTjR.css +0 -1
- package/dist/assets/web/dist/assets/sseReplay-DPwdsaok.js +0 -9
|
@@ -36,9 +36,11 @@ export interface MemoryRecord {
|
|
|
36
36
|
supersedes?: string;
|
|
37
37
|
/** `evicted`: dropped by the per-scope cap (least recently used);
|
|
38
38
|
* `superseded`: replaced by a newer record; `forgotten`: removed by a human
|
|
39
|
-
* via `memory forget
|
|
40
|
-
*
|
|
41
|
-
|
|
39
|
+
* via `memory forget`; `swept`: retired by `memory sweep` because the text
|
|
40
|
+
* carries a status/change-description marker (`rejectionMarkers`). All are
|
|
41
|
+
* soft deletes — the row stays for provenance but is invisible to
|
|
42
|
+
* retrieval, list, and dedup. */
|
|
43
|
+
status: "active" | "superseded" | "forgotten" | "evicted" | "swept";
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
/** What the reflection extractor emits. The store assigns id/timestamps/useCount/
|
|
@@ -52,8 +54,51 @@ export interface MemoryCandidate {
|
|
|
52
54
|
sourceRunId?: string;
|
|
53
55
|
confidence?: number;
|
|
54
56
|
supersedes?: string;
|
|
57
|
+
/** id of a shown record this fact restates: the store bumps that record
|
|
58
|
+
* (`useCount`, `lastUsedAt`, the higher `confidence`) instead of inserting
|
|
59
|
+
* a twin; a target that is missing or not active falls through to the
|
|
60
|
+
* plain dedup-or-insert path. */
|
|
61
|
+
restates?: string;
|
|
55
62
|
}
|
|
56
63
|
|
|
64
|
+
/** What one `write` batch actually did, per candidate action — the seam's
|
|
65
|
+
* receipt (the counters on the `[memory]` outcome line are these plus the
|
|
66
|
+
* parse gate's own). */
|
|
67
|
+
export interface WriteCounts {
|
|
68
|
+
/** Candidates minted as new active records. */
|
|
69
|
+
inserted: number;
|
|
70
|
+
/** Candidates whose normalized text bumped an existing active record. */
|
|
71
|
+
deduped: number;
|
|
72
|
+
/** Candidates that bumped the shown record they restate (no insert). */
|
|
73
|
+
restated: number;
|
|
74
|
+
/** Records flipped to `superseded` by a candidate's pointer. */
|
|
75
|
+
superseded: number;
|
|
76
|
+
/** Records the per-scope cap evicted inside the same batch. */
|
|
77
|
+
evicted: number;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Narrowing filters for `MemoryStore.list` — each narrows, never ranks. */
|
|
81
|
+
export interface MemoryListOptions {
|
|
82
|
+
/** Whole-token text/keyword filter (the human command's `<words>`). */
|
|
83
|
+
query?: string;
|
|
84
|
+
/** Keep only records of this kind (the repository window lists facts). */
|
|
85
|
+
kind?: MemoryRecord["kind"];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** What one sweep did — or, on the durable path, why it could not. The
|
|
89
|
+
* failure is a VALUE, never a throw: the one expected failure is an older
|
|
90
|
+
* Memory Worker generation without the `/sweep` route (a 404), which the
|
|
91
|
+
* command must report as a ⚠️ line, not crash on. */
|
|
92
|
+
export type SweepOutcome =
|
|
93
|
+
| {
|
|
94
|
+
ok: true;
|
|
95
|
+
/** Active facts the gate marked (flipped to `swept`, or merely counted under `dryRun`). */
|
|
96
|
+
swept: number;
|
|
97
|
+
/** The marked record ids — always safe to show (ids carry no record text). */
|
|
98
|
+
ids: string[];
|
|
99
|
+
}
|
|
100
|
+
| { ok: false; error: string };
|
|
101
|
+
|
|
57
102
|
/** A retrieval request: which resource, what to match, how many at most. */
|
|
58
103
|
export interface MemoryQuery {
|
|
59
104
|
scopeKey: string;
|
|
@@ -71,19 +116,29 @@ export interface MemoryStore {
|
|
|
71
116
|
retrieve(q: MemoryQuery, trace?: TraceOptions): Promise<MemoryRecord[]>;
|
|
72
117
|
/** Persist distilled candidates. Dedup (identical normalized text → bump
|
|
73
118
|
* `useCount`) and supersede (`supersedes` id → old record soft-deleted) live
|
|
74
|
-
* inside the store. Driven by the post-run reflection pass (reflection.ts).
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
/**
|
|
119
|
+
* inside the store. Driven by the post-run reflection pass (reflection.ts).
|
|
120
|
+
* Answers what the batch did (`WriteCounts`), so the caller's outcome line
|
|
121
|
+
* reports the store's actions, never a guess. */
|
|
122
|
+
write(scopeKey: string, records: MemoryCandidate[]): Promise<WriteCounts>;
|
|
123
|
+
/** Human view and the repository window's read: a scope's ACTIVE records,
|
|
124
|
+
* newest first, at most `limit`. Unlike `retrieve` this never bumps usage.
|
|
125
|
+
* `opts.query`: when given, only records that a query token hits
|
|
79
126
|
* (whole-token, text or keywords) are listed — the filter narrows, it
|
|
80
|
-
* never ranks or bumps usage.
|
|
81
|
-
|
|
127
|
+
* never ranks or bumps usage. `opts.kind`: when given, only records of
|
|
128
|
+
* that kind (the repository window lists facts, never summaries). */
|
|
129
|
+
list(scopeKey: string, limit: number, opts?: MemoryListOptions): Promise<MemoryRecord[]>;
|
|
82
130
|
/** Human control: soft-delete one ACTIVE record of this scope
|
|
83
131
|
* (`status: "forgotten"`, row kept for provenance). Resolves true when a
|
|
84
132
|
* record was forgotten, false when the id names nothing active in this
|
|
85
133
|
* scope — a foreign-scope id can never be forgotten through another scope. */
|
|
86
134
|
forget(scopeKey: string, id: string): Promise<boolean>;
|
|
135
|
+
/** Human control: retire this scope's ACTIVE facts whose text the write
|
|
136
|
+
* gate would reject today (`rejectionMarkers`, engine.ts) — `status:
|
|
137
|
+
* "swept"`, rows kept for provenance, summaries never touched. Under
|
|
138
|
+
* `dryRun` nothing flips and the marked ids are answered. Idempotent: a
|
|
139
|
+
* second sweep answers 0. Failures come back as `{ok: false}`, never a
|
|
140
|
+
* throw (an older Worker without the route is a reported failure). */
|
|
141
|
+
sweep(scopeKey: string, opts?: { dryRun?: boolean }): Promise<SweepOutcome>;
|
|
87
142
|
}
|
|
88
143
|
|
|
89
144
|
/** The resources memory is scoped to. `org` is the shared resource every
|
|
@@ -98,10 +153,16 @@ export type MemoryScope = "org" | "user" | "repo" | "channel";
|
|
|
98
153
|
export interface MemoryConfig {
|
|
99
154
|
/** Master switch. Default false → `NullMemoryStore` → zero behavior change. */
|
|
100
155
|
enabled?: boolean;
|
|
101
|
-
/** Max records retrieved/injected per request. Default
|
|
156
|
+
/** Max records retrieved/injected per request. Default 32. */
|
|
102
157
|
limit?: number;
|
|
103
|
-
/** Hard token budget for the injected block. Default ~
|
|
158
|
+
/** Hard token budget for the injected block. Default ~3000. */
|
|
104
159
|
maxTokens?: number;
|
|
160
|
+
/** The repository window: a run bound to a repository leads its block with
|
|
161
|
+
* that repository's newest facts — at most this many, read with
|
|
162
|
+
* `list(repoScope, repoWindow, { kind: "fact" })` — ahead of the keyword
|
|
163
|
+
* hits, under the same budget. Default 24; `0` disables the window (the
|
|
164
|
+
* repository scope is retrieved by keyword like the others). */
|
|
165
|
+
repoWindow?: number;
|
|
105
166
|
/** Per-scope cap on ACTIVE records. A write that would leave a scope
|
|
106
167
|
* over the cap evicts the least recently used records (soft delete, status
|
|
107
168
|
* `evicted`) down to it, inside the same write. Default 500. */
|
|
@@ -32,11 +32,23 @@ export type LevelMap = Record<Effort, LevelWord | "refused"> | "unknown";
|
|
|
32
32
|
export type InputSupport = boolean | "unknown";
|
|
33
33
|
export type CacheRule = "automatic" | "markers" | "none" | "unknown";
|
|
34
34
|
|
|
35
|
+
/** One long-context tier of a card's rate (pi's rule, `calculateCost`): when
|
|
36
|
+
* the request's input side (input + cache reads + cache writes) exceeds
|
|
37
|
+
* `inputTokensAbove`, the WHOLE request re-rates at the tier. */
|
|
38
|
+
export interface CardPriceTier {
|
|
39
|
+
inputTokensAbove: number;
|
|
40
|
+
input: number;
|
|
41
|
+
output: number;
|
|
42
|
+
cacheRead: number;
|
|
43
|
+
cacheWrite: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
35
46
|
export interface CardPrice {
|
|
36
47
|
input: number;
|
|
37
48
|
output: number;
|
|
38
49
|
cacheRead: number;
|
|
39
50
|
cacheWrite: number;
|
|
51
|
+
tiers?: readonly CardPriceTier[];
|
|
40
52
|
}
|
|
41
53
|
|
|
42
54
|
export interface ModelCard {
|
|
@@ -123,14 +135,30 @@ function levelMapOf(map: Record<string, string | null> | undefined, reasoning: b
|
|
|
123
135
|
return out;
|
|
124
136
|
}
|
|
125
137
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
138
|
+
type RawPrice = {
|
|
139
|
+
input?: number;
|
|
140
|
+
output?: number;
|
|
141
|
+
cacheRead?: number;
|
|
142
|
+
cacheWrite?: number;
|
|
143
|
+
tiers?: Array<{ inputTokensAbove?: number } & Omit<RawPrice, "tiers">>;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
function priceOf(raw: RawPrice | undefined): CardPrice | undefined {
|
|
129
147
|
if (!raw) return undefined;
|
|
130
148
|
const { input, output, cacheRead, cacheWrite } = raw;
|
|
131
149
|
if (input === undefined || output === undefined || cacheRead === undefined || cacheWrite === undefined)
|
|
132
150
|
return undefined;
|
|
133
|
-
|
|
151
|
+
// A tier missing a field cannot re-rate the whole request; it is dropped,
|
|
152
|
+
// never guessed at the base rate.
|
|
153
|
+
const tiers = (raw.tiers ?? []).filter(
|
|
154
|
+
(t): t is CardPriceTier =>
|
|
155
|
+
t.inputTokensAbove !== undefined &&
|
|
156
|
+
t.input !== undefined &&
|
|
157
|
+
t.output !== undefined &&
|
|
158
|
+
t.cacheRead !== undefined &&
|
|
159
|
+
t.cacheWrite !== undefined,
|
|
160
|
+
);
|
|
161
|
+
return { input, output, cacheRead, cacheWrite, ...(tiers.length > 0 ? { tiers } : {}) };
|
|
134
162
|
}
|
|
135
163
|
|
|
136
164
|
/**
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { parseModelRef } from "./provider.js";
|
|
1
|
+
import { parseModelRef, type TokenUsage } from "./provider.js";
|
|
2
|
+
import type { CardPrice } from "./modelCard.js";
|
|
3
|
+
import type { ReportedCost } from "./modelProxy/usage.js";
|
|
2
4
|
import type { ModelUsage, RunUsage } from "./runUsage.js";
|
|
3
5
|
|
|
4
6
|
// The price of a model's tokens (docs/reference/specs/costs.md): one table
|
|
@@ -148,6 +150,105 @@ export function modelPriceOf(ref: string, prices: ModelPriceTable = NO_PRICES):
|
|
|
148
150
|
return { input: list.input, output: list.output, cacheRead: list.cacheRead, cacheWrite: list.cacheWrite5m };
|
|
149
151
|
}
|
|
150
152
|
|
|
153
|
+
// ---- one turn, priced at the proxy (model-proxy.md item 6) -----------------------
|
|
154
|
+
|
|
155
|
+
/** Which layer priced the turn: the provider's own reported cost, the
|
|
156
|
+
* operator's table (`costs.prices` or a block's `models.<id>.price`), the
|
|
157
|
+
* registry card (the Anthropic family list folds into this layer), or none —
|
|
158
|
+
* an unpriced turn is never $0. */
|
|
159
|
+
export type PriceSource = "provider" | "operator" | "registry" | "none";
|
|
160
|
+
|
|
161
|
+
/** The meter row's dollars: `usd` when a layer priced the turn, `feeUsd` on a
|
|
162
|
+
* BYOK turn (the aggregator's fee — inside `usd` when the vendor's charge was
|
|
163
|
+
* reported beside it, otherwise beside the layer that priced the tokens),
|
|
164
|
+
* and the layer. */
|
|
165
|
+
export interface TurnPrice {
|
|
166
|
+
usd?: number;
|
|
167
|
+
feeUsd?: number;
|
|
168
|
+
priceSource: PriceSource;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** What `priceTurn` reads of the run's model card: the ref the spans name,
|
|
172
|
+
* the card's rate when a layer named one, and which layer did
|
|
173
|
+
* (`ModelCard.provenance.price`). */
|
|
174
|
+
export interface TurnPriceCard {
|
|
175
|
+
ref: string;
|
|
176
|
+
price?: CardPrice;
|
|
177
|
+
pricedBy?: "operator" | "registry" | "wire";
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const turnTokensUsd = (u: TokenUsage, p: { input: number; output: number; cacheRead: number; cacheWrite: number }) =>
|
|
181
|
+
(u.inputTokens * p.input +
|
|
182
|
+
u.outputTokens * p.output +
|
|
183
|
+
(u.cacheReadTokens ?? 0) * p.cacheRead +
|
|
184
|
+
(u.cacheWriteTokens ?? 0) * p.cacheWrite) /
|
|
185
|
+
1_000_000;
|
|
186
|
+
|
|
187
|
+
/** A card rate over one turn's counts, tiers by pi's rule (`calculateCost`):
|
|
188
|
+
* the input side is input + cache reads + cache writes, and the WHOLE request
|
|
189
|
+
* re-rates at the highest tier whose threshold it exceeds. */
|
|
190
|
+
export function cardPriceUsd(usage: TokenUsage, price: CardPrice): number {
|
|
191
|
+
const inputSide = usage.inputTokens + (usage.cacheReadTokens ?? 0) + (usage.cacheWriteTokens ?? 0);
|
|
192
|
+
let rates: { input: number; output: number; cacheRead: number; cacheWrite: number } = price;
|
|
193
|
+
let matched = -1;
|
|
194
|
+
for (const tier of price.tiers ?? []) {
|
|
195
|
+
if (inputSide > tier.inputTokensAbove && tier.inputTokensAbove > matched) {
|
|
196
|
+
rates = tier;
|
|
197
|
+
matched = tier.inputTokensAbove;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return turnTokensUsd(usage, rates);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* One turn's price, by record 0052's precedence: a provider-reported cost is
|
|
205
|
+
* stored as reported (`provider`; on BYOK the fee and the vendor's upstream
|
|
206
|
+
* charge sum into `usd` with `feeUsd` beside), else the operator's layer
|
|
207
|
+
* (`costs.prices` for the exact ref, or the card's operator-named rate), else
|
|
208
|
+
* the registry layer (the card's rate with its tiers, or the Anthropic family
|
|
209
|
+
* list — costs.md item 4b's fallback, folded here), else `none` — a turn no
|
|
210
|
+
* layer prices, and a stream broken before its usage arrived, stays unpriced.
|
|
211
|
+
*/
|
|
212
|
+
export function priceTurn(
|
|
213
|
+
card: TurnPriceCard,
|
|
214
|
+
reported: ReportedCost | undefined,
|
|
215
|
+
usage: TokenUsage | undefined,
|
|
216
|
+
prices: ModelPriceTable = NO_PRICES,
|
|
217
|
+
): TurnPrice {
|
|
218
|
+
if (reported) {
|
|
219
|
+
if (!reported.byok) return { usd: reported.cost, priceSource: "provider" };
|
|
220
|
+
if (reported.upstreamCost !== undefined) {
|
|
221
|
+
return { usd: reported.cost + reported.upstreamCost, priceSource: "provider", feeUsd: reported.cost };
|
|
222
|
+
}
|
|
223
|
+
// A BYOK chunk without the vendor's charge: the fee is not the turn's
|
|
224
|
+
// dollars, so it rides beside whatever layer below prices the tokens —
|
|
225
|
+
// never as an authoritative figure that understates the turn.
|
|
226
|
+
return { ...priceTurn(card, undefined, usage, prices), feeUsd: reported.cost };
|
|
227
|
+
}
|
|
228
|
+
if (!usage) return { priceSource: "none" };
|
|
229
|
+
const operator = prices[card.ref];
|
|
230
|
+
if (operator) return { usd: turnTokensUsd(usage, operator), priceSource: "operator" };
|
|
231
|
+
if (card.price) {
|
|
232
|
+
return {
|
|
233
|
+
usd: cardPriceUsd(usage, card.price),
|
|
234
|
+
priceSource: card.pricedBy === "operator" ? "operator" : "registry",
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
const list = anthropicPriceOf(modelIdOf(card.ref));
|
|
238
|
+
if (list) {
|
|
239
|
+
return {
|
|
240
|
+
usd: turnTokensUsd(usage, {
|
|
241
|
+
input: list.input,
|
|
242
|
+
output: list.output,
|
|
243
|
+
cacheRead: list.cacheRead,
|
|
244
|
+
cacheWrite: list.cacheWrite5m,
|
|
245
|
+
}),
|
|
246
|
+
priceSource: "registry",
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return { priceSource: "none" };
|
|
250
|
+
}
|
|
251
|
+
|
|
151
252
|
/** What a model's counted tokens cost at a price, USD. */
|
|
152
253
|
export function modelUsageUsd(m: ModelUsage, p: ModelPrice): number {
|
|
153
254
|
return (
|
|
@@ -211,6 +312,15 @@ export function llmUsdOfUsage(
|
|
|
211
312
|
let unpricedTokens = 0;
|
|
212
313
|
const byModel: Record<string, PricedModelUsage> = {};
|
|
213
314
|
for (const [ref, m] of Object.entries(usage.byModel)) {
|
|
315
|
+
// A model whose spans priced their own turns (model-proxy item 6) keeps
|
|
316
|
+
// the recorded figure — a provider-reported cost beats any table — and
|
|
317
|
+
// null (a turn without a figure) reads as unpriced, never re-priced here.
|
|
318
|
+
if (m.usd !== undefined) {
|
|
319
|
+
if (m.usd === null) unpricedTokens += m.inputTokens + m.outputTokens + m.cacheReadTokens + m.cacheWriteTokens;
|
|
320
|
+
else usd += m.usd;
|
|
321
|
+
byModel[ref] = { ...m, usd: m.usd };
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
214
324
|
const price = modelPriceOf(ref, prices);
|
|
215
325
|
const priced = price ? modelUsageUsd(m, price) : undefined;
|
|
216
326
|
if (priced === undefined) unpricedTokens += m.inputTokens + m.outputTokens + m.cacheReadTokens + m.cacheWriteTokens;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// A provider's usage object as the proxy's meter reads it
|
|
2
|
+
// (docs/reference/specs/model-proxy.md item 6): the three wire shapes the proxy
|
|
3
|
+
// forwards — Anthropic's `message.usage`, the Chat Completions `usage` and the
|
|
4
|
+
// Responses API's `usage` — each
|
|
5
|
+
// normalized to the one `TokenUsage` every `model.turn` span carries. Undefined
|
|
6
|
+
// unless both core counts are numbers: a malformed or absent usage never fails
|
|
7
|
+
// a completion, it only leaves the turn unmetered. The first two readers were the
|
|
8
|
+
// native adapters' until record 0032's series deleted the adapters; the proxy
|
|
9
|
+
// is their one reader now.
|
|
10
|
+
|
|
11
|
+
import type { TokenUsage } from "../provider.js";
|
|
12
|
+
|
|
13
|
+
/** Anthropic `message.usage` → TokenUsage. */
|
|
14
|
+
export function usageFromAnthropic(u: unknown): TokenUsage | undefined {
|
|
15
|
+
if (typeof u !== "object" || u === null) return undefined;
|
|
16
|
+
const o = u as Record<string, unknown>;
|
|
17
|
+
if (typeof o.input_tokens !== "number" || typeof o.output_tokens !== "number") return undefined;
|
|
18
|
+
const usage: TokenUsage = { inputTokens: o.input_tokens, outputTokens: o.output_tokens };
|
|
19
|
+
if (typeof o.cache_read_input_tokens === "number") usage.cacheReadTokens = o.cache_read_input_tokens;
|
|
20
|
+
if (typeof o.cache_creation_input_tokens === "number") usage.cacheWriteTokens = o.cache_creation_input_tokens;
|
|
21
|
+
return usage;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** OpenAI-style `usage` → TokenUsage. `prompt_tokens_details.cached_tokens` is
|
|
25
|
+
* the cache-read count where the server reports one. */
|
|
26
|
+
export function usageFromOpenAI(u: unknown): TokenUsage | undefined {
|
|
27
|
+
if (typeof u !== "object" || u === null) return undefined;
|
|
28
|
+
const o = u as Record<string, unknown>;
|
|
29
|
+
if (typeof o.prompt_tokens !== "number" || typeof o.completion_tokens !== "number") return undefined;
|
|
30
|
+
const usage: TokenUsage = { inputTokens: o.prompt_tokens, outputTokens: o.completion_tokens };
|
|
31
|
+
const details = o.prompt_tokens_details;
|
|
32
|
+
if (typeof details === "object" && details !== null) {
|
|
33
|
+
const cached = (details as Record<string, unknown>).cached_tokens;
|
|
34
|
+
if (typeof cached === "number") usage.cacheReadTokens = cached;
|
|
35
|
+
}
|
|
36
|
+
return usage;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** A provider-reported cost beside the counters (model-proxy.md item 6): the
|
|
40
|
+
* OpenRouter final chunk's `usage.cost` in USD — on a BYOK turn (`is_byok`)
|
|
41
|
+
* the aggregator's fee alone, with what the vendor billed the operator's own
|
|
42
|
+
* key in `cost_details.upstream_inference_cost`. Read off the same usage
|
|
43
|
+
* object the counters come from; a usage without a finite `cost` reports
|
|
44
|
+
* none (Anthropic's wire never carries one). */
|
|
45
|
+
export interface ReportedCost {
|
|
46
|
+
/** The figure as reported, stored as reported (record 0052). */
|
|
47
|
+
cost: number;
|
|
48
|
+
/** OpenRouter's `is_byok`: the turn billed the operator's own vendor key. */
|
|
49
|
+
byok?: boolean;
|
|
50
|
+
/** `cost_details.upstream_inference_cost`: the vendor's own charge on a BYOK turn. */
|
|
51
|
+
upstreamCost?: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** The cost fields of one wire `usage` object, or undefined when it carries none. */
|
|
55
|
+
export function reportedCostOf(u: unknown): ReportedCost | undefined {
|
|
56
|
+
if (typeof u !== "object" || u === null) return undefined;
|
|
57
|
+
const o = u as Record<string, unknown>;
|
|
58
|
+
if (typeof o.cost !== "number" || !Number.isFinite(o.cost)) return undefined;
|
|
59
|
+
const details = o.cost_details;
|
|
60
|
+
const upstream =
|
|
61
|
+
typeof details === "object" && details !== null
|
|
62
|
+
? (details as Record<string, unknown>).upstream_inference_cost
|
|
63
|
+
: undefined;
|
|
64
|
+
return {
|
|
65
|
+
cost: o.cost,
|
|
66
|
+
...(o.is_byok === true ? { byok: true } : {}),
|
|
67
|
+
...(typeof upstream === "number" && Number.isFinite(upstream) ? { upstreamCost: upstream } : {}),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** The Responses API's `usage` → TokenUsage. `input_tokens_details.cached_tokens`
|
|
72
|
+
* is the cache-read count and `input_tokens_details.cache_write_tokens` the
|
|
73
|
+
* cache-write count where a server reports one (OpenAI itself never does; a
|
|
74
|
+
* gateway on the wire may). `output_tokens_details.reasoning_tokens` rides
|
|
75
|
+
* inside `output_tokens` — the shape is read, never a fifth counter. */
|
|
76
|
+
export function usageFromResponses(u: unknown): TokenUsage | undefined {
|
|
77
|
+
if (typeof u !== "object" || u === null) return undefined;
|
|
78
|
+
const o = u as Record<string, unknown>;
|
|
79
|
+
if (typeof o.input_tokens !== "number" || typeof o.output_tokens !== "number") return undefined;
|
|
80
|
+
const usage: TokenUsage = { inputTokens: o.input_tokens, outputTokens: o.output_tokens };
|
|
81
|
+
const details = o.input_tokens_details;
|
|
82
|
+
if (typeof details === "object" && details !== null) {
|
|
83
|
+
const { cached_tokens, cache_write_tokens } = details as Record<string, unknown>;
|
|
84
|
+
if (typeof cached_tokens === "number") usage.cacheReadTokens = cached_tokens;
|
|
85
|
+
if (typeof cache_write_tokens === "number") usage.cacheWriteTokens = cache_write_tokens;
|
|
86
|
+
}
|
|
87
|
+
return usage;
|
|
88
|
+
}
|
|
@@ -23,7 +23,21 @@ export interface RegistryCard {
|
|
|
23
23
|
* not named (the card's reader applies pi's rule). */
|
|
24
24
|
thinkingLevelMap?: Record<string, string | null>;
|
|
25
25
|
input?: string[];
|
|
26
|
-
cost?: {
|
|
26
|
+
cost?: {
|
|
27
|
+
input?: number;
|
|
28
|
+
output?: number;
|
|
29
|
+
cacheRead?: number;
|
|
30
|
+
cacheWrite?: number;
|
|
31
|
+
/** pi's long-context tiers: the whole request re-rates at the highest tier
|
|
32
|
+
* whose threshold the input side (input + cache reads + cache writes) exceeds. */
|
|
33
|
+
tiers?: Array<{
|
|
34
|
+
inputTokensAbove?: number;
|
|
35
|
+
input?: number;
|
|
36
|
+
output?: number;
|
|
37
|
+
cacheRead?: number;
|
|
38
|
+
cacheWrite?: number;
|
|
39
|
+
}>;
|
|
40
|
+
};
|
|
27
41
|
contextWindow?: number;
|
|
28
42
|
maxTokens?: number;
|
|
29
43
|
compat?: Record<string, unknown>;
|
|
@@ -87,6 +87,7 @@ const CAUSE_OF = {
|
|
|
87
87
|
ship_preflight_head_unknown: "system",
|
|
88
88
|
ship_preflight_closed_resume: "request",
|
|
89
89
|
ship_preflight_no_task: "request",
|
|
90
|
+
ship_preflight_base_missing: "request",
|
|
90
91
|
// the plan hand-off's fifteen sentences (two share `plan_history_unavailable`)
|
|
91
92
|
plan_base_unknown: "request",
|
|
92
93
|
plan_routed_seed: "request",
|
|
@@ -102,13 +103,9 @@ const CAUSE_OF = {
|
|
|
102
103
|
plan_runner_conflict: "system",
|
|
103
104
|
plan_instance_orphaned: "system",
|
|
104
105
|
plan_start_failed: "system",
|
|
105
|
-
// the
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
directive_budget: "request",
|
|
109
|
-
directive_severity: "request",
|
|
110
|
-
directive_renewals: "request",
|
|
111
|
-
directive_verbosity: "request",
|
|
106
|
+
// the resolve parser's thrown errors (A6 of the inventory); the directive
|
|
107
|
+
// parser no longer refuses — a token whose value is outside its vocabulary
|
|
108
|
+
// is text (the interim grammar, src/directives.ts)
|
|
112
109
|
provider_unknown: "request",
|
|
113
110
|
// the model card's refusal (record 0052, model-proxy item 11): a control the
|
|
114
111
|
// resolved card does not take, named before any card or model call
|
|
@@ -108,6 +108,10 @@ export interface Finding {
|
|
|
108
108
|
line?: number;
|
|
109
109
|
/** One line naming the issue; the full explanation lives in the prose. */
|
|
110
110
|
title: string;
|
|
111
|
+
/** Machine provenance: true only on a check finding the ship round's checks
|
|
112
|
+
* step itself appended (ship/coordinator.ts `checkFinding`) — never set from
|
|
113
|
+
* a reviewer's input, whatever id the reviewer chose. */
|
|
114
|
+
check?: true;
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
export interface ReviewVerdict {
|
|
@@ -397,11 +397,19 @@ export type ShipRoundOutcome =
|
|
|
397
397
|
| "approve"
|
|
398
398
|
| "request_changes"
|
|
399
399
|
| "no_verdict"
|
|
400
|
+
/** The round's checks step read a failed check at the reviewed head (record
|
|
401
|
+
* 0055): the failures become check findings and the findings step runs as
|
|
402
|
+
* for any changes-requested round. */
|
|
403
|
+
| "checks_failed"
|
|
400
404
|
| "aborted"
|
|
401
405
|
| "stopped"
|
|
402
406
|
/** The coding round ended at its lease with the unit unfinished and the row
|
|
403
407
|
* showing progress, and the grant renewed: the next segment opens (decision 0046). */
|
|
404
|
-
| "continued"
|
|
408
|
+
| "continued"
|
|
409
|
+
/** The unit idles instead of ending (record 0051): emitted once the wake
|
|
410
|
+
* lands (that plan's fifth unit); in the vocabulary now so rows written
|
|
411
|
+
* then read beside today's — the old kinds stay for rows already written. */
|
|
412
|
+
| "idle";
|
|
405
413
|
|
|
406
414
|
/**
|
|
407
415
|
* One event in a run's stream. `seq` is stamped by `RunRegistry.publish` — a
|
|
@@ -536,6 +544,11 @@ export type RunEvent =
|
|
|
536
544
|
callId?: string;
|
|
537
545
|
spanId?: string;
|
|
538
546
|
logIndex?: number;
|
|
547
|
+
/** The bound the call itself declared, in ms (a bash `timeout`, clamped
|
|
548
|
+
* by nothing here — pi runs an unbounded call until the loop's end).
|
|
549
|
+
* The stall signal (docs/reference/specs/live-view.md item 32) marks a
|
|
550
|
+
* call past it; absent when the call declared none. */
|
|
551
|
+
boundMs?: number;
|
|
539
552
|
seq?: number;
|
|
540
553
|
at?: number;
|
|
541
554
|
}
|
|
@@ -671,8 +684,12 @@ export type RunEvent =
|
|
|
671
684
|
* and — for a repo run — the repo, ref, PR number and PR head as resolved
|
|
672
685
|
* BEFORE the first model turn (`RepoContext`). Published by the dispatcher
|
|
673
686
|
* right after `input`, once per run, so the run page can head its Request
|
|
674
|
-
* block with linked `owner/repo · ref · #PR · sha`.
|
|
675
|
-
*
|
|
687
|
+
* block with linked `owner/repo · ref · #PR · sha`. A HOSTED ship parent
|
|
688
|
+
* (record 0060) carries a second one at the hand-off naming its runner
|
|
689
|
+
* instance (`instanceId`): `run_meta` may repeat on such a run, and every
|
|
690
|
+
* reader of a run's instance id resolves it from the LAST `run_meta`
|
|
691
|
+
* carrying one. Additive: every consumer that only knows the other types
|
|
692
|
+
* keeps working. */
|
|
676
693
|
| {
|
|
677
694
|
type: "run_meta";
|
|
678
695
|
agent: string;
|
|
@@ -865,6 +882,23 @@ export type RunEvent =
|
|
|
865
882
|
* `coordinator_tag` is — so the thread's owner rule can find the instance
|
|
866
883
|
* from the page's ship run. Additive: unknown → ignored. */
|
|
867
884
|
| { type: "ship_handoff"; instanceId: string; seq?: number; at?: number }
|
|
885
|
+
/** A coordinator child interrupted under a deploy roll (docs/reference/specs/run-history.md
|
|
886
|
+
* item 47a): the run closes `interrupted` for a restart from its request —
|
|
887
|
+
* a workspace lost across a bot roll, the resident's container replaced
|
|
888
|
+
* with the relaunch refused — and the record says so as a typed fact
|
|
889
|
+
* beside the `resumed`/`sandbox_restarted` notes, `reason` the refusal or
|
|
890
|
+
* note in one line. Published straight to the registry by the reattach
|
|
891
|
+
* path and the run loop's interruption; the parent's wait settles on its
|
|
892
|
+
* Workflow twin (`child-interrupted-<runId>`) beside `run-finished-<runId>`
|
|
893
|
+
* and confirms by `read-record`. Additive: unknown → ignored. */
|
|
894
|
+
| { type: "child_interrupted"; parentInstanceId: string; reason: string; seq?: number; at?: number }
|
|
895
|
+
/** A coordinator child resumed across a deploy roll (run-history item 47a):
|
|
896
|
+
* the same run re-attached its workspace and carries on under its record,
|
|
897
|
+
* tag and budget. Published straight to the registry by the reattach path;
|
|
898
|
+
* the Workflow twin (`child-resumed-<runId>`) tells the parent's wait to
|
|
899
|
+
* keep waiting rather than walk out the chunk asking. Additive: unknown →
|
|
900
|
+
* ignored. */
|
|
901
|
+
| { type: "child_resumed"; parentInstanceId: string; summary: string; seq?: number; at?: number }
|
|
868
902
|
/** The review post-step's outcome when the verdict landed
|
|
869
903
|
* (docs/reference/specs/agent-review.md item 18): the pull request it was
|
|
870
904
|
* posted to, the head it was pinned to (the carried head after a rebase,
|
|
@@ -905,6 +939,25 @@ export type RunEvent =
|
|
|
905
939
|
seq?: number;
|
|
906
940
|
at?: number;
|
|
907
941
|
}
|
|
942
|
+
/** A hosted ship parent's unit fact (record 0060; docs/reference/specs/agent-ship.md
|
|
943
|
+
* item 17): the runner's routes write it to the parent run through the
|
|
944
|
+
* coordinator's `hostPublish` — `unit-start` publishes state `started` with
|
|
945
|
+
* the unit's thread key and lead, `round` the round's outcome as the unit's
|
|
946
|
+
* state, `unit-end` the ending's kind with its report — carrying the pull
|
|
947
|
+
* request number when the unit's row knows one. The run page draws it as a
|
|
948
|
+
* step whose detail is the report; the friction analyzer counts it as a
|
|
949
|
+
* side fact, never activity. Additive: unknown → ignored. */
|
|
950
|
+
| {
|
|
951
|
+
type: "ship_unit";
|
|
952
|
+
unit: string;
|
|
953
|
+
state: string;
|
|
954
|
+
threadKey?: string;
|
|
955
|
+
lead?: string;
|
|
956
|
+
report?: string;
|
|
957
|
+
pr?: number;
|
|
958
|
+
seq?: number;
|
|
959
|
+
at?: number;
|
|
960
|
+
}
|
|
908
961
|
/** The request router's decision (docs/reference/specs/routing-and-config.md
|
|
909
962
|
* item 21): the preset a plain message was routed to, the one-line reason
|
|
910
963
|
* the router gave (redacted, capped — the same text the card's `routed:`
|
|
@@ -954,6 +1007,32 @@ export type RunEvent =
|
|
|
954
1007
|
seq?: number;
|
|
955
1008
|
at?: number;
|
|
956
1009
|
}
|
|
1010
|
+
/** The operator's decision beside the routed request ([record 0057](../../docs/decisions/0057-the-operator-is-the-one-door-a-model-binds-every-chat-input-and-deterministic-code-authorizes-fences-and-executes.md);
|
|
1011
|
+
* the one-door plan's operator unit; run-history item 60): one per admitted chat
|
|
1012
|
+
* event under `routing.operator: shadow` or `on`, published beside the
|
|
1013
|
+
* `route` event. The decision is binds, a question or a refusal; a bind's
|
|
1014
|
+
* `line` is redacted and cut like the receipt (`ROUTE_RECEIPT_CAP`), never
|
|
1015
|
+
* the message text; `intake` carries the intake gate's verdict when the
|
|
1016
|
+
* gate is present; `latencyMs` and `outputTokens` feed the replay's median
|
|
1017
|
+
* rows. Under `shadow` nothing runs from it. Additive: unknown → ignored. */
|
|
1018
|
+
| {
|
|
1019
|
+
type: "operator";
|
|
1020
|
+
mode: "shadow" | "on";
|
|
1021
|
+
outcome: "binds" | "question" | "refusal";
|
|
1022
|
+
reason: string;
|
|
1023
|
+
binds?: ReadonlyArray<{ line: string; reason: string }>;
|
|
1024
|
+
question?: string;
|
|
1025
|
+
/** A question's proposed line, redacted and cut like the receipt — what
|
|
1026
|
+
* the next turn's "yes" binds (`bindFromAnswer`). */
|
|
1027
|
+
proposal?: string;
|
|
1028
|
+
refusalCause?: string;
|
|
1029
|
+
refusalText?: string;
|
|
1030
|
+
intake?: { verdict: string; reason: string };
|
|
1031
|
+
latencyMs?: number;
|
|
1032
|
+
outputTokens?: number;
|
|
1033
|
+
seq?: number;
|
|
1034
|
+
at?: number;
|
|
1035
|
+
}
|
|
957
1036
|
/** A refusal the door made ([record 0054](../../docs/decisions/0054-a-refusal-the-person-caused-is-one-question-with-a-best-guess.md),
|
|
958
1037
|
* as amended: every refusal is a run record; run-history.md item 2): the
|
|
959
1038
|
* code, its one cause, and the sentence the person read — redacted and
|
|
@@ -413,8 +413,10 @@ export function analyzeRunFriction(events: readonly RunEvent[], opts: FrictionOp
|
|
|
413
413
|
// call that already produced its own tool pair, and artifact beside the
|
|
414
414
|
// attach_file call (or the dispatcher's staging) that moved the file;
|
|
415
415
|
// review_artifact, pr_description, pr_opened, review_posted, the ship_round
|
|
416
|
-
// boundaries
|
|
417
|
-
//
|
|
416
|
+
// boundaries, the hosted parent's ship_unit facts (record 0060 — written by
|
|
417
|
+
// the runner's routes, not the model) and the router's route are published
|
|
418
|
+
// by the dispatcher/pipeline outside the model loop entirely. Counting any
|
|
419
|
+
// of them would distort the story.
|
|
418
420
|
if (
|
|
419
421
|
ev.type === "skill_use" ||
|
|
420
422
|
ev.type === "artifact" ||
|
|
@@ -423,9 +425,13 @@ export function analyzeRunFriction(events: readonly RunEvent[], opts: FrictionOp
|
|
|
423
425
|
ev.type === "pr_opened" ||
|
|
424
426
|
ev.type === "coordinator_tag" ||
|
|
425
427
|
ev.type === "ship_handoff" ||
|
|
428
|
+
ev.type === "child_interrupted" ||
|
|
429
|
+
ev.type === "child_resumed" ||
|
|
426
430
|
ev.type === "review_posted" ||
|
|
427
431
|
ev.type === "ship_round" ||
|
|
432
|
+
ev.type === "ship_unit" ||
|
|
428
433
|
ev.type === "route" ||
|
|
434
|
+
ev.type === "operator" ||
|
|
429
435
|
ev.type === "refusal" ||
|
|
430
436
|
ev.type === "reference" ||
|
|
431
437
|
ev.type === "lease" ||
|
|
@@ -121,6 +121,17 @@ export interface LiveRunMeta {
|
|
|
121
121
|
* the checklist, the pushed branch, the review head, the infra counters). */
|
|
122
122
|
export type RunState = Record<string, unknown>;
|
|
123
123
|
|
|
124
|
+
/** A hosted ship parent's hosting fact on the row's state (record 0060): the
|
|
125
|
+
* runner instance the run hosts and the deadline past which a reclaim closes
|
|
126
|
+
* the row `interrupted` instead of re-hosting it. Set by the ship branch once
|
|
127
|
+
* the instance exists; read by the boot reclaim. */
|
|
128
|
+
export interface HostingState {
|
|
129
|
+
instanceId: string;
|
|
130
|
+
/** Epoch ms: the hand-off time plus the instance's `caps.maxMinutes` plus
|
|
131
|
+
* `HOSTED_DEADLINE_MARGIN_MINUTES`. */
|
|
132
|
+
until: number;
|
|
133
|
+
}
|
|
134
|
+
|
|
124
135
|
export interface LiveRunRow {
|
|
125
136
|
runId: string;
|
|
126
137
|
threadKey: string;
|