@junghanacs/entwurf 0.16.1 → 0.17.2
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/AGENTS.md +4 -2
- package/CHANGELOG.md +333 -0
- package/VERIFY.md +8 -1
- package/docs/acp-backend-rail.md +25 -14
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/acp-client.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +15 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-mailbox.js +9 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-runner.js +14 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send.js +5 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +18 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +23 -7
- package/package.json +4 -4
- package/pi/meta-bridge/entwurf-meta-receive/hooks/hooks.json +3 -1
- package/pi/meta-bridge/entwurf-meta-receive/scripts/doorbell.sh +13 -8
- package/pi-extensions/lib/acp/acp-client.ts +57 -4
- package/pi-extensions/lib/acp/backend-adapter.ts +59 -0
- package/pi-extensions/lib/acp/backend.ts +453 -11
- package/pi-extensions/lib/acp/event-mapper.ts +43 -6
- package/pi-extensions/lib/entwurf-v2-mailbox.ts +9 -2
- package/pi-extensions/lib/entwurf-v2-runner.ts +23 -6
- package/pi-extensions/lib/entwurf-v2-send.ts +26 -3
- package/pi-extensions/lib/entwurf-v2-surface.ts +18 -3
- package/pi-extensions/lib/meta-session.ts +32 -7
- package/run.sh +21 -0
- package/scripts/check-acp-stop-reason.ts +8 -2
- package/scripts/check-acp-usage-accounting.ts +1074 -0
- package/scripts/check-entwurf-v2-mailbox.ts +33 -0
- package/scripts/check-entwurf-v2-runner.ts +18 -0
- package/scripts/check-entwurf-v2-send.ts +13 -1
- package/scripts/check-entwurf-v2-surface.ts +75 -3
- package/scripts/check-gate-qualification.ts +1 -0
- package/scripts/check-hook-launch-topology.ts +70 -1
- package/scripts/check-mailbox-receipt-state.ts +6 -0
- package/scripts/check-meta-doctor-oracle.sh +73 -0
- package/scripts/check-meta-mailbox-state-write.ts +9 -2
- package/scripts/check-meta-manifest-schema.py +19 -1
- package/scripts/check-meta-session.ts +10 -2
- package/scripts/lib/pi-record-discovery.ts +47 -0
- package/scripts/meta-bridge-doctor.sh +18 -3
- package/scripts/meta-bridge-state.py +23 -5
- package/scripts/meta-bridge-statusline.sh +65 -2
- package/scripts/mutants/acp-stream-hooks.json +4 -2
- package/scripts/mutants/acp-usage-accounting.json +181 -0
- package/scripts/raw-async-delivery/README.md +280 -9
- package/scripts/raw-async-delivery/cc-mailbox-rewake.sh +6 -2
- package/scripts/raw-async-delivery/lab-statusline.sh +63 -0
- package/scripts/raw-async-delivery/mailbox-watch.py +230 -0
- package/scripts/raw-async-delivery/plugin-entwurf-receive/hooks/hooks.json +3 -1
- package/scripts/raw-async-delivery/plugin-entwurf-receive/scripts/watch-filechanged.sh +13 -4
- package/scripts/raw-async-delivery/probe-delivery-transparency.sh +387 -0
- package/scripts/smoke-acp-bundled-mcp-live.ts +2 -2
- package/scripts/smoke-acp-cortex-live.ts +2 -2
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-acp-socket-citizen-live.ts +2 -2
- package/scripts/smoke-acp-v2-send-live.ts +2 -2
- package/scripts/smoke-entwurf-v2-matrix-live.ts +60 -10
- package/scripts/smoke-meta-async-drift.sh +31 -8
- package/scripts/smoke-meta-install-state.sh +170 -11
- package/scripts/smoke-meta-keyset-guard.sh +4 -1
- package/scripts/smoke-mux-lifecycle-live.ts +46 -2
|
@@ -61,12 +61,17 @@ export interface DispatchExecutorDeps {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/** The per-transport success outcome, discriminated by transport so the surface renders
|
|
64
|
-
* each without guessing. `control-socket` carries the optional N3 `rejectReason
|
|
64
|
+
* each without guessing. `control-socket` carries the optional N3 `rejectReason` and,
|
|
65
|
+
* when a dead-socket re-resolve fell back to the mailbox, that leg's #98 R `messagePath`;
|
|
65
66
|
* `meta-mailbox` is always `success:true` (enqueue has no in-band refuse — a failure is
|
|
66
|
-
* a throw, handled as `execution-failed`)
|
|
67
|
+
* a throw, handled as `execution-failed`) and carries the #98 R send receipt: the path of
|
|
68
|
+
* the `.msg` the enqueue actually wrote. OPTIONAL because a fake/legacy `sendMailbox` dep
|
|
69
|
+
* may omit it — a missing receipt must degrade the rendered line, never fail the delivery,
|
|
70
|
+
* and it is the ONLY enqueue-side datum carried (never a read timestamp; see
|
|
71
|
+
* `RpcSendResult`). */
|
|
67
72
|
export type ExecutedOutcome =
|
|
68
|
-
| { transport: "control-socket"; outcome: SendFinalOutcome; rejectReason?: string }
|
|
69
|
-
| { transport: "meta-mailbox"; success: true }
|
|
73
|
+
| { transport: "control-socket"; outcome: SendFinalOutcome; rejectReason?: string; messagePath?: string }
|
|
74
|
+
| { transport: "meta-mailbox"; success: true; messagePath?: string }
|
|
70
75
|
// native-push carries `retried` so the surface can note the 1-shot re-probe retry fired.
|
|
71
76
|
| { transport: "native-push"; success: true; retried: boolean };
|
|
72
77
|
|
|
@@ -118,7 +123,12 @@ export async function executeDispatch(
|
|
|
118
123
|
kind: "executed",
|
|
119
124
|
receipt,
|
|
120
125
|
transport,
|
|
121
|
-
outcome: {
|
|
126
|
+
outcome: {
|
|
127
|
+
transport: "control-socket",
|
|
128
|
+
outcome: r.outcome,
|
|
129
|
+
rejectReason: r.rejectReason,
|
|
130
|
+
messagePath: r.messagePath,
|
|
131
|
+
},
|
|
122
132
|
};
|
|
123
133
|
} catch (err) {
|
|
124
134
|
// N1: a delivered/refused send whose release then threw — lock dirty, do NOT retry.
|
|
@@ -150,7 +160,14 @@ export async function executeDispatch(
|
|
|
150
160
|
"entwurf-v2-runner: meta-mailbox send returned success:false (contract violation; a mailbox has no in-band reject).",
|
|
151
161
|
);
|
|
152
162
|
}
|
|
153
|
-
return {
|
|
163
|
+
return {
|
|
164
|
+
kind: "executed",
|
|
165
|
+
receipt,
|
|
166
|
+
transport,
|
|
167
|
+
// #98 R: carry the enqueue receipt verbatim. `undefined` stays `undefined` —
|
|
168
|
+
// the runner never substitutes a guessed path for a missing one.
|
|
169
|
+
outcome: { transport: "meta-mailbox", success: true, messagePath: r.messagePath },
|
|
170
|
+
};
|
|
154
171
|
} catch (err) {
|
|
155
172
|
return { kind: "execution-failed", receipt, transport, error: errorMessage(err), retrySafe: false };
|
|
156
173
|
}
|
|
@@ -52,10 +52,20 @@ export type MetaMailboxPlan = Extract<ExecutionPlan, { transport: "meta-mailbox"
|
|
|
52
52
|
export type SendFinalOutcome = "sent" | "fallback-sent" | "rejected" | "failed";
|
|
53
53
|
|
|
54
54
|
/** What a single RPC / mailbox enqueue reports. `success:false` is an in-band reject
|
|
55
|
-
* (the receiver answered and refused) — distinct from a thrown connect error.
|
|
55
|
+
* (the receiver answered and refused) — distinct from a thrown connect error.
|
|
56
|
+
*
|
|
57
|
+
* `messagePath` is the SEND-side receipt (#98 R) and is OPTIONAL because only the
|
|
58
|
+
* mailbox rail has one: an enqueue writes a file, so there is a per-message artifact
|
|
59
|
+
* to name. A control-socket RPC hands the body to a live receiver and produces no
|
|
60
|
+
* file, so it leaves this undefined rather than inventing one. It carries the ENQUEUED
|
|
61
|
+
* path and NOTHING about reading: `lastReadAt` at enqueue time is the PREVIOUS
|
|
62
|
+
* message's read stamp, so surfacing it here would read as "my message was read" —
|
|
63
|
+
* the exact misreading #98 opened on. The per-message read receipt is the `.read`
|
|
64
|
+
* suffix on this very file, never a state.json slot. */
|
|
56
65
|
export interface RpcSendResult {
|
|
57
66
|
success: boolean;
|
|
58
67
|
error?: string;
|
|
68
|
+
messagePath?: string;
|
|
59
69
|
}
|
|
60
70
|
|
|
61
71
|
/** The same-lock one-shot re-resolve result (5c-2b implements the resolver; 5c-2a
|
|
@@ -98,6 +108,14 @@ export interface ControlSocketSendResult {
|
|
|
98
108
|
* 5d runner carries this verbatim so the surface can tell "in-band refusal" from
|
|
99
109
|
* "no live route" — the N3 carry-over the hand boundary used to drop. */
|
|
100
110
|
rejectReason?: string;
|
|
111
|
+
/** #98 R, fallback leg: the `.msg` a dead-socket re-resolve enqueued. Present ONLY
|
|
112
|
+
* when the fallback actually routed to the mailbox and the enqueue succeeded — a
|
|
113
|
+
* control-socket retry hands the body to a live receiver and writes no file, so it
|
|
114
|
+
* leaves this undefined rather than inventing one. Same rule as `RpcSendResult`: the
|
|
115
|
+
* ENQUEUED path and nothing about reading. Without it a `fallback-sent` is the one
|
|
116
|
+
* mailbox delivery whose sender gets no per-message identifier — the same letter the
|
|
117
|
+
* primary mailbox rail names. */
|
|
118
|
+
messagePath?: string;
|
|
101
119
|
}
|
|
102
120
|
|
|
103
121
|
// A drive step's verdict: the terminal outcome, plus the original error to RETHROW on
|
|
@@ -107,6 +125,8 @@ interface SendDrive {
|
|
|
107
125
|
outcome: SendFinalOutcome;
|
|
108
126
|
error?: unknown;
|
|
109
127
|
rejectReason?: string;
|
|
128
|
+
/** #98 R receipt from the mailbox fallback leg (see `ControlSocketSendResult`). */
|
|
129
|
+
messagePath?: string;
|
|
110
130
|
}
|
|
111
131
|
|
|
112
132
|
/**
|
|
@@ -139,7 +159,7 @@ export async function executeControlSocketSend(
|
|
|
139
159
|
drive = { outcome: "failed", error: err };
|
|
140
160
|
}
|
|
141
161
|
finalizeRelease(policy, deps, held, drive);
|
|
142
|
-
return { outcome: drive.outcome, rejectReason: drive.rejectReason };
|
|
162
|
+
return { outcome: drive.outcome, rejectReason: drive.rejectReason, messagePath: drive.messagePath };
|
|
143
163
|
}
|
|
144
164
|
|
|
145
165
|
/** Drive the 1차 send and route a connect failure through the F3 split. */
|
|
@@ -208,7 +228,10 @@ async function driveDeadFallback(
|
|
|
208
228
|
// hand never reaches for the mailbox on its own; only the resolver routes here.
|
|
209
229
|
try {
|
|
210
230
|
const r = await deps.sendViaMailbox(rePlan, lock);
|
|
211
|
-
|
|
231
|
+
// #98 R: this leg writes a `.msg` exactly like the primary mailbox rail, so it
|
|
232
|
+
// owes the sender the same per-message receipt. Carried only on success — a
|
|
233
|
+
// `rejected` enqueue wrote no file to name.
|
|
234
|
+
return r.success ? { outcome: "fallback-sent", messagePath: r.messagePath } : { outcome: "rejected" };
|
|
212
235
|
} catch (err) {
|
|
213
236
|
return { outcome: "failed", error: err };
|
|
214
237
|
}
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* surface never needs to name the `EntwurfV2RunResult` union (it only sees `{text,isError}`).
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
import { basename } from "node:path";
|
|
22
23
|
import type { SenderEnvelope } from "./entwurf-control-rpc.ts";
|
|
23
24
|
import type { DispatchInput, EntwurfV2Mode } from "./entwurf-v2-decider.ts";
|
|
24
25
|
import { makeProductionEntwurfV2Deps, type ProductionEntwurfV2Opts } from "./entwurf-v2-production.ts";
|
|
@@ -144,8 +145,13 @@ export function renderEntwurfV2Result(result: EntwurfV2RunResult): EntwurfV2Surf
|
|
|
144
145
|
if (o.transport === "control-socket") {
|
|
145
146
|
const delivered = o.outcome === "sent" || o.outcome === "fallback-sent";
|
|
146
147
|
const reason = o.rejectReason ? ` (reason: ${o.rejectReason})` : "";
|
|
148
|
+
// #98 R, fallback leg: a dead socket that re-resolved to the mailbox wrote a
|
|
149
|
+
// `.msg` — name it, exactly as the primary mailbox rail does. Absent on a
|
|
150
|
+
// socket-to-socket retry (no file) and on every non-mailbox outcome, so the
|
|
151
|
+
// line degrades to the bare outcome rather than printing "undefined".
|
|
152
|
+
const enqueued = o.messagePath ? ` (enqueued ${basename(o.messagePath)})` : "";
|
|
147
153
|
return {
|
|
148
|
-
text: `entwurf_v2 control-socket → ${o.outcome}${reason}`,
|
|
154
|
+
text: `entwurf_v2 control-socket → ${o.outcome}${reason}${enqueued}`,
|
|
149
155
|
isError: !delivered,
|
|
150
156
|
};
|
|
151
157
|
}
|
|
@@ -156,8 +162,17 @@ export function renderEntwurfV2Result(result: EntwurfV2RunResult): EntwurfV2Surf
|
|
|
156
162
|
isError: false,
|
|
157
163
|
};
|
|
158
164
|
}
|
|
159
|
-
// meta-mailbox
|
|
160
|
-
|
|
165
|
+
// meta-mailbox. #98 R: name the FILE that was enqueued, so the sender's transcript
|
|
166
|
+
// carries a per-message identifier instead of a bare literal. Only the basename —
|
|
167
|
+
// the directory is `<meta-mailbox>/<target garden id>/`, which the caller already
|
|
168
|
+
// typed. Deliberately NOT a read stamp: at enqueue time `lastReadAt` belongs to the
|
|
169
|
+
// PREVIOUS message, so printing it would claim a read that has not happened.
|
|
170
|
+
// A dep that omits the receipt falls back to the old literal rather than printing
|
|
171
|
+
// "undefined" — the delivery still happened.
|
|
172
|
+
return {
|
|
173
|
+
text: `entwurf_v2 meta-mailbox → enqueued${o.messagePath ? ` (${basename(o.messagePath)})` : ""}`,
|
|
174
|
+
isError: false,
|
|
175
|
+
};
|
|
161
176
|
}
|
|
162
177
|
case "execution-failed": {
|
|
163
178
|
if (result.releaseFailed && result.finalizedOutcome) {
|
|
@@ -2532,9 +2532,17 @@ export interface ReadMetaInboxResult {
|
|
|
2532
2532
|
* Drain a garden citizen's mailbox: read every unread message (a fresh `.msg`
|
|
2533
2533
|
* read before its doorbell, or a doorbell-rung `.msg.delivered`), archive each to
|
|
2534
2534
|
* `*.read` so a re-read never double-returns, and — only if at least one message
|
|
2535
|
-
* was read — stamp `lastReadAt
|
|
2536
|
-
*
|
|
2537
|
-
*
|
|
2535
|
+
* was read — stamp `lastReadAt`. `lastDeliveredAt` stays untouched (see the
|
|
2536
|
+
* stamp-site note below). An empty inbox mutates nothing: reading nothing is not
|
|
2537
|
+
* a receipt.
|
|
2538
|
+
*
|
|
2539
|
+
* WHERE THE PER-MESSAGE TRUTH LIVES (#98 5a, corrected 2026-09-03). The FILE SUFFIX
|
|
2540
|
+
* is the per-message receipt: `.msg` = enqueued, `.msg.delivered` = the doorbell
|
|
2541
|
+
* rang for it, `.msg.delivered.read` = this function handed it to the reader.
|
|
2542
|
+
* `state.json` is NOT that — its three slots are GARDEN-WIDE and overwritten, so
|
|
2543
|
+
* `lastReadAt` says "this citizen last read something at T", never "message X was
|
|
2544
|
+
* read". A sender that quotes `lastReadAt` back as the fate of the letter it just
|
|
2545
|
+
* queued is quoting the PREVIOUS letter's read. That misreading is what opened #98.
|
|
2538
2546
|
*/
|
|
2539
2547
|
export function readMetaInbox(opts: ReadMetaInboxOptions): ReadMetaInboxResult {
|
|
2540
2548
|
const now = opts.now ?? new Date();
|
|
@@ -2560,10 +2568,18 @@ export function readMetaInbox(opts: ReadMetaInboxOptions): ReadMetaInboxResult {
|
|
|
2560
2568
|
return { gardenId: citizen.gardenId, messages, readAt: null, recordPath: recordFile };
|
|
2561
2569
|
}
|
|
2562
2570
|
|
|
2563
|
-
// 3D-4 the cut: the read receipt lives SOLELY in the mailbox state store
|
|
2564
|
-
// Stamp lastReadAt — the one
|
|
2565
|
-
// reached the reader). lastDeliveredAt is
|
|
2566
|
-
//
|
|
2571
|
+
// 3D-4 the cut: the garden-wide read receipt lives SOLELY in the mailbox state store
|
|
2572
|
+
// now. Stamp lastReadAt — the one slot this layer stamps honestly (it KNOWS a body
|
|
2573
|
+
// reached the reader at this instant). lastDeliveredAt is left alone, and #98 5a
|
|
2574
|
+
// corrects WHY: the old comment said "the doorbell owns it", but the shipped
|
|
2575
|
+
// doorbell.sh (54 lines) writes NOTHING to state.json — measured, zero state writes.
|
|
2576
|
+
// So `lastDeliveredAt` is a RESERVED SLOT nobody stamps, permanently null on all
|
|
2577
|
+
// ~180 on-disk states, while 900+ files carry a `.delivered` suffix. Stamping it
|
|
2578
|
+
// here would still be wrong (it would report read-time as delivery-time), so it
|
|
2579
|
+
// stays null — but do not read "the doorbell will fill it in" into that. The
|
|
2580
|
+
// per-message delivery fact is the `.delivered` SUFFIX. The field is left in place
|
|
2581
|
+
// deliberately: removing it is a migration (the parser rejects unknown keys AND a
|
|
2582
|
+
// bumped schemaVersion, and every stamp re-parses first), tracked as #98 5b.
|
|
2567
2583
|
// The state stamp returns the updated state, whose lastReadAt IS the D7 read-receipt.
|
|
2568
2584
|
// Inside the messages.length>0 branch by construction — an empty inbox already
|
|
2569
2585
|
// early-returned (no .read archive, state untouched), so "read nothing" is no
|
|
@@ -2603,6 +2619,15 @@ export const MAILBOX_RECEIPT_SCHEMA_VERSION = 1 as const;
|
|
|
2603
2619
|
* The per-citizen mailbox receipt state. Holds exactly the three delivery
|
|
2604
2620
|
* timestamps that move out of `record.delivery` (wakeMode/deliveryLevel are
|
|
2605
2621
|
* capability, deliberately absent). Body is SSOT; the on-disk path is derived.
|
|
2622
|
+
*
|
|
2623
|
+
* SCOPE (#98 5a): these are GARDEN-WIDE "last activity" slots, single-valued and
|
|
2624
|
+
* overwritten — NOT per-message receipts. Per message, the receipt is the file
|
|
2625
|
+
* suffix in the same directory (`.msg` → `.msg.delivered` → `.msg.delivered.read`).
|
|
2626
|
+
* `lastEnqueuedAt`/`lastReadAt` are stamped by `enqueueMetaMessage`/`readMetaInbox`.
|
|
2627
|
+
* `lastDeliveredAt` is stamped by NOBODY: the doorbell does not write state.json, so
|
|
2628
|
+
* it is a reserved slot that is null everywhere. Kept rather than removed because the
|
|
2629
|
+
* parser is doubly strict (exact schemaVersion + no unknown keys) and every stamp
|
|
2630
|
+
* re-parses, so dropping it is a migration over the existing on-disk v1 files (#98 5b).
|
|
2606
2631
|
*/
|
|
2607
2632
|
export interface MailboxReceiptState {
|
|
2608
2633
|
schemaVersion: typeof MAILBOX_RECEIPT_SCHEMA_VERSION;
|
package/run.sh
CHANGED
|
@@ -2700,6 +2700,24 @@ check_acp_event_mapper() {
|
|
|
2700
2700
|
run_ts scripts/check-acp-event-mapper.ts
|
|
2701
2701
|
}
|
|
2702
2702
|
|
|
2703
|
+
check_acp_usage_accounting() {
|
|
2704
|
+
# Deterministic gate for the ACP USAGE ACCOUNTING contract (#93). A long-lived
|
|
2705
|
+
# Claude ACP session's dashboard read 10-18x high on three live ledgers,
|
|
2706
|
+
# because the per-turn token partition was dropped at the type boundary while
|
|
2707
|
+
# the backend's RUNNING SESSION TOTAL was assigned to a per-turn cost field pi
|
|
2708
|
+
# then summed. Drives streamAcpTurn against a fake ACP child + connection whose
|
|
2709
|
+
# turns are scripted (usage_update notification + PromptResponse.usage) for
|
|
2710
|
+
# five cells: the four-way token partition reaches the pi message; per-turn
|
|
2711
|
+
# costs are adjacent diffs of the running total and sum back to it across a
|
|
2712
|
+
# reused session; a turn with no cost notification attributes $0 and HOLDS the
|
|
2713
|
+
# baseline; a decreasing total rebaselines, attributes $0 and tells the
|
|
2714
|
+
# operator; totalTokens stays CONTEXT OCCUPANCY (asserted through pi's own
|
|
2715
|
+
# calculateContextTokens) and carries forward; and cortex — no measured
|
|
2716
|
+
# extractor — keeps its pre-#93 output untouched.
|
|
2717
|
+
section "ACP usage accounting (turn partition + adjacent-diff cost)"
|
|
2718
|
+
run_ts scripts/check-acp-usage-accounting.ts
|
|
2719
|
+
}
|
|
2720
|
+
|
|
2703
2721
|
check_acp_stop_reason() {
|
|
2704
2722
|
# Deterministic gate for the ACP stop-reason contract. Drives every member of
|
|
2705
2723
|
# the closed ACP terminal set (end_turn / max_tokens / max_turn_requests /
|
|
@@ -6520,6 +6538,9 @@ case "$cmd" in
|
|
|
6520
6538
|
check-acp-event-mapper)
|
|
6521
6539
|
check_acp_event_mapper
|
|
6522
6540
|
;;
|
|
6541
|
+
check-acp-usage-accounting)
|
|
6542
|
+
check_acp_usage_accounting
|
|
6543
|
+
;;
|
|
6523
6544
|
check-acp-stop-reason)
|
|
6524
6545
|
check_acp_stop_reason
|
|
6525
6546
|
;;
|
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
//
|
|
3
3
|
// WHAT THIS EXISTS TO STOP. `mapPromptStopReason` used to be a bare
|
|
4
4
|
// `switch` returning a StopReason with `default: return "stop"`. The ACP terminal
|
|
5
|
-
// set is closed — `@agentclientprotocol/sdk` 1.
|
|
6
|
-
// `end_turn | max_tokens | max_turn_requests | refusal | cancelled
|
|
5
|
+
// set is closed — `@agentclientprotocol/sdk` 1.4.0 `dist/schema/types.gen.d.ts:3001`
|
|
6
|
+
// declares `end_turn | max_tokens | max_turn_requests | refusal | cancelled`, with
|
|
7
|
+
// no `| string` arm. Re-measured at the 1.3.0 → 1.4.0 bump rather than inherited,
|
|
8
|
+
// because 1.4.0 also ships a SECOND, OPEN union at `dist/v2/schema/types.gen.d.ts:3607`
|
|
9
|
+
// (`… | "cancelled" | string`). That one is reachable only through the
|
|
10
|
+
// `./experimental/v2` export; entwurf imports the BARE specifier, which the package
|
|
11
|
+
// `exports` map sends to `./dist/acp.js` — the closed v1 surface. The claim holds
|
|
12
|
+
// only while that import stays bare, so a move to the v2 export retires it — so that
|
|
7
13
|
// default silently collapsed THREE distinct non-success outcomes into a clean
|
|
8
14
|
// successful turn:
|
|
9
15
|
//
|