@junghanacs/entwurf 0.52.0 → 0.53.1
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 +1 -1
- package/BASELINE.md +116 -397
- package/CHANGELOG.md +131 -2
- package/CONTRIBUTING.md +4 -4
- package/DELIVERY.md +2 -2
- package/ENTWURF-CLI.json +1 -1
- package/README.md +7 -4
- package/VERIFY.md +332 -142
- package/demo/demo-baseline.sh +1 -1
- package/demo/demo.sh +1 -1
- package/docs/acp-backend-rail.md +248 -34
- package/docs/setup-clean-host.md +50 -65
- 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 +90 -14
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +4 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/context.js +15 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/model-ids.js +9 -12
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +41 -56
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +33 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +34 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +3 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +2 -1
- package/package.json +4 -4
- package/pi/settings.reference.json +0 -1
- package/pi-extensions/acp-provider.ts +12 -6
- package/pi-extensions/lib/acp/acp-client.ts +6 -7
- package/pi-extensions/lib/acp/backend-adapter.ts +139 -15
- package/pi-extensions/lib/acp/backend.ts +261 -32
- package/pi-extensions/lib/acp/config.ts +4 -9
- package/pi-extensions/lib/acp/context.ts +17 -0
- package/pi-extensions/lib/acp/event-mapper.ts +236 -17
- package/pi-extensions/lib/acp/model-ids.js +9 -12
- package/pi-extensions/lib/acp/models.ts +46 -57
- package/pi-extensions/lib/acp/tool-surface.ts +34 -6
- package/pi-extensions/lib/fresh-call-composition.ts +37 -3
- package/pi-extensions/lib/herdr-fresh-call.ts +3 -1
- package/pi-extensions/lib/mux-fresh-call.ts +3 -1
- package/run.sh +25 -86
- package/scripts/check-acp-carrier-augment.ts +3 -21
- package/scripts/check-acp-prompt-lifecycle.ts +24 -3
- package/scripts/check-acp-provider-surface.ts +17 -26
- package/scripts/check-acp-session-reuse.ts +23 -4
- package/scripts/check-acp-stop-reason.ts +22 -3
- package/scripts/check-acp-stream-hooks.ts +24 -3
- package/scripts/check-acp-usage-accounting.ts +53 -24
- package/scripts/check-copilot-receive-arm.ts +19 -2
- package/scripts/check-fresh-call-dispatch.ts +9 -3
- package/scripts/check-gate-qualification.ts +5 -5
- package/scripts/check-herdr-fresh-call.ts +1 -0
- package/scripts/check-install-surface.ts +6 -0
- package/scripts/check-probe-ordering.ts +34 -24
- package/scripts/check-release-gate-outcomes.ts +9 -23
- package/scripts/lib/probe-cli-target.ts +3 -2
- package/scripts/mutants/acp-augment.json +0 -26
- package/scripts/mutants/acp-cortex.json +10 -183
- package/scripts/mutants/acp-foreground-only.json +11 -0
- package/scripts/mutants/acp-launch-namespace.json +3 -1
- package/scripts/mutants/acp-prompt-lifecycle.json +2 -2
- package/scripts/mutants/acp-set-model-readback.json +488 -0
- package/scripts/mutants/mux-fresh-call.json +12 -1
- package/scripts/mutants/pi-floor.json +2 -2
- package/scripts/mutants/release-gate.json +3 -3
- package/scripts/raw-acp-compaction-measure/probe.ts +8 -2
- package/scripts/smoke-acp-cortex-live.ts +4 -408
- package/scripts/smoke-acp-ordering-probe-live.ts +7 -1
- package/scripts/smoke-acp-session-reuse-live.ts +11 -2
- package/scripts/smoke-herdr-raw-install-live.sh +4 -4
- package/scripts/check-acp-cortex.ts +0 -710
package/docs/setup-clean-host.md
CHANGED
|
@@ -23,11 +23,11 @@ evidence split, and its three states must not collapse into "macOS is supported"
|
|
|
23
23
|
|
|
24
24
|
## Requirements
|
|
25
25
|
|
|
26
|
-
The
|
|
26
|
+
The current published Entwurf 0.52.0 uses the exact Pi 1.5.2 SDK set and host Pi `>=1.5.2 <1.6`. The marked 0.51.0 / SDK 1.5.0 examples below are historical and remain bound to their own published manifest. Source validation, publication and a running host's loaded bytes are separate evidence; the earlier addon-less validation tarball installed on one operating host is not the published artifact (see the [#158 boundary](#sdk-152-candidate-boundary-158)).
|
|
27
27
|
|
|
28
28
|
The validation TGZ installed in #155's operating window before the D1 display repair is an earlier, separate artifact, not the published one; see the [SDK 1.5 boundary](#sdk-15-development-boundary-155) below.
|
|
29
29
|
|
|
30
|
-
The
|
|
30
|
+
The older package, `0.50.0`, ships the Pi 1.4.0 SDK set and requires a Pi 1.4.x host; the setup guide inside that tarball is its contract.
|
|
31
31
|
|
|
32
32
|
| Component | Requirement | Needed for |
|
|
33
33
|
|---|---|---|
|
|
@@ -35,14 +35,13 @@ The previous package, `0.50.0`, ships the Pi 1.4.0 SDK set and requires a Pi 1.4
|
|
|
35
35
|
| npm/pnpm | npm is bundled with Node; pnpm is required for source setup | package or source installation |
|
|
36
36
|
| Python 3 | required by `setup`/`install` (project-path normalization + settings writers); `--help`/`check-bridge` stay Python-free | pi/Claude/agy/Copilot/Codex wiring writers |
|
|
37
37
|
| entwurf | global/project-local `@junghanacs/entwurf`, or a source checkout | operator command and garden capability |
|
|
38
|
-
| pi | optional-by-presence —
|
|
39
|
-
| Native durable (`pi-durable`) | supplied by the Entwurf package (#130): Entwurf's owned app carrier plus its exact pi SDK set (1.5.
|
|
38
|
+
| pi | optional-by-presence — current 0.52.0: `>=1.5.2 <1.6`; historical 0.51.0: <!-- entwurf:published @junghanacs/entwurf@0.51.0 pi 1.5.0 -->`>=1.5.0 <1.6`<!-- /entwurf:published -->. Absent is an explicit setup SKIP, below-floor is a named FAIL | ACP provider, control sockets |
|
|
39
|
+
| Native durable (`pi-durable`) | supplied by the Entwurf package (#130): Entwurf's owned app carrier plus its exact pi SDK set (1.5.2 in published 0.52.0; 1.5.0 in historical 0.51.0) as production dependencies — setup PASS when they verify, a named FAIL otherwise (never SKIP) | the `entwurf pi-durable` contact; native birth/LIVE on this supply surface is a separate release proof (§2b) |
|
|
40
40
|
| Claude Code | optional, **`>=2.1.306`** — the exec-form hook floor | Claude ACP auth/runtime and mailbox-backed native citizen |
|
|
41
41
|
| GitHub Copilot CLI | optional-by-presence, operator-installed and authenticated — absent is an explicit setup SKIP; detected composes all four units (birth/MCP/receiver/footer) | self-fetch citizen and visible fresh |
|
|
42
42
|
| OMP (`omp`) | optional-by-presence, operator-installed — absent is an explicit setup SKIP; detected composes all four units (birth/MCP/`tools.xdev` setting/receiver) | self-fetch citizen and visible fresh (accepted on one host — see §4b) |
|
|
43
43
|
| Antigravity `agy` | optional, operator-installed and authenticated | legacy citizen; native push paused (#152) |
|
|
44
44
|
| OpenAI Codex CLI | optional-by-presence, operator-installed and authenticated; detected composes all four operator-owned units (birth/MCP/status-line/terminal-title) and stays non-green until the operator trusts the birth declaration once in a visible Codex; visible fresh also requires the operator-owned app-server, started with `entwurf codex-app-server` in a tmux session of the operator's choosing (#95 D1 retired the fixed `codex` home) | native-push and visible fresh, supported in 0.21.0 |
|
|
45
|
-
| Cortex Code | optional, operator-installed and authenticated | Cortex ACP backend |
|
|
46
45
|
|
|
47
46
|
Claude Code >=2.1.306 is required for the managed exec-hook lifecycle and same-id resume. The package
|
|
48
47
|
never supplies or proxies backend credentials.
|
|
@@ -85,8 +84,8 @@ node --version
|
|
|
85
84
|
npm --version
|
|
86
85
|
```
|
|
87
86
|
|
|
88
|
-
The two npm forms below install the **published** package, `0.
|
|
89
|
-
set)
|
|
87
|
+
The two npm forms below install the **published** package, `0.52.0` (Pi 1.5.x, the Pi 1.5.2 SDK
|
|
88
|
+
set). The [product entry](../README.md#install)'s unpinned `npm install -g @junghanacs/entwurf`
|
|
90
89
|
takes whichever version npm's `latest` dist-tag names; pin `@<version>` as below when you mean the
|
|
91
90
|
exact artifact the [Requirements](#requirements) table describes.
|
|
92
91
|
|
|
@@ -94,7 +93,7 @@ Global install is simplest when native harnesses should find stable bins from ev
|
|
|
94
93
|
working directory:
|
|
95
94
|
|
|
96
95
|
```bash
|
|
97
|
-
npm install -g @junghanacs/entwurf@0.
|
|
96
|
+
npm install -g @junghanacs/entwurf@0.52.0
|
|
98
97
|
entwurf --help
|
|
99
98
|
entwurf setup /path/to/your-project
|
|
100
99
|
entwurf check-bridge
|
|
@@ -105,7 +104,7 @@ A project-local installation is also supported:
|
|
|
105
104
|
```bash
|
|
106
105
|
mkdir -p ~/entwurf-smoke && cd ~/entwurf-smoke
|
|
107
106
|
npm init -y
|
|
108
|
-
npm install --save-dev @junghanacs/entwurf@0.
|
|
107
|
+
npm install --save-dev @junghanacs/entwurf@0.52.0
|
|
109
108
|
npx entwurf setup .
|
|
110
109
|
npx entwurf check-bridge
|
|
111
110
|
```
|
|
@@ -115,10 +114,10 @@ project-local install, or `./run.sh <command>` from a source checkout. Keep that
|
|
|
115
114
|
same scope when upgrading and checking; native process restarts are separate (§7).
|
|
116
115
|
|
|
117
116
|
`check-bridge` is auth-free. It proves the installed prebuilt MCP server boots and
|
|
118
|
-
lists the nine garden tools (0.
|
|
117
|
+
lists the nine garden tools (0.52.0); it does not prove a backend model turn, native hook or retirement permission.
|
|
119
118
|
|
|
120
119
|
Neither npm form installs a harness runtime. `pi`, Claude Code, Copilot CLI, Codex CLI, agy,
|
|
121
|
-
|
|
120
|
+
and their authentication remain operator-owned optional prerequisites for the
|
|
122
121
|
integrations that use them; all may be absent on an Entwurf-only host. A source checkout's
|
|
123
122
|
pinned Pi development packages are for building and testing this repo, not a transitive product installation promise.
|
|
124
123
|
|
|
@@ -226,12 +225,11 @@ physical-Darwin receipt. `entwurf install` may write `.pi/settings.json`
|
|
|
226
225
|
on Darwin; that is wiring, not a rail receipt. If `pi` is on PATH,
|
|
227
226
|
`setup` names the pi row FAIL with the §1 Darwin wording.
|
|
228
227
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
The previous 0.50.0 uses the Pi 1.4.x host named in its own setup guide:
|
|
228
|
+
For published Entwurf 0.52.0, install its exact host Pi floor and wire the project as shown below.
|
|
229
|
+
The previous 0.51.0 uses the Pi 1.5.0 floor named in its own setup guide:
|
|
232
230
|
|
|
233
231
|
```bash
|
|
234
|
-
npm install -g @earendil-works/pi-coding-agent@1.5.
|
|
232
|
+
npm install -g @earendil-works/pi-coding-agent@1.5.2
|
|
235
233
|
pi --version
|
|
236
234
|
|
|
237
235
|
cd ~/entwurf-smoke
|
|
@@ -239,13 +237,12 @@ entwurf install .
|
|
|
239
237
|
pi -e "$(npm root -g)/@junghanacs/entwurf" --list-models entwurf
|
|
240
238
|
```
|
|
241
239
|
|
|
242
|
-
The supported host Pi range for published Entwurf 0.
|
|
240
|
+
The supported host Pi range for published Entwurf 0.52.0 is `>=1.5.2 <1.6`.
|
|
243
241
|
A detected host outside that range is refused for Pi wiring; Entwurf does not upgrade it.
|
|
244
242
|
Align the host explicitly, for example with the exact npm command above, before wiring Pi. A host using only the external MCP bridge can skip pi until it needs a
|
|
245
243
|
control socket; no delivery rail launches a pi process.
|
|
246
|
-
<!-- /entwurf:published -->
|
|
247
244
|
|
|
248
|
-
|
|
245
|
+
Published 0.52.0 requires host Pi `>=1.5.2 <1.6`; `setup` reports a detected older host as FAIL. Prepare host Pi 1.5.2 before wiring, and use the checkout path rather than the global npm package when running a checkout directly. Range eligibility does not replace installation, validation or operating approval. Ordinary Pi 1.5.2 defaults its global `cacheWarming` setting to `idle`, which may send additional provider requests; pi-durable does not map that setting. See the [#158 durable boundary](./durable-native-support.md#sdk-152-candidate-boundary-158).
|
|
249
246
|
|
|
250
247
|
For daily garden-native pi sessions:
|
|
251
248
|
|
|
@@ -264,7 +261,7 @@ A plain `pi` can load the package without becoming a citizen.
|
|
|
264
261
|
In that session ask for `entwurf_self`, then `entwurf_peers`. Pick an existing
|
|
265
262
|
live garden id and ask for `entwurf_v2` with `intent: "fire-and-forget"` and your
|
|
266
263
|
message. These are harness tools, not shell subcommands; pi exposes them through
|
|
267
|
-
Pi's built-in MCP as `mcp__entwurf_bridge__<verb>`. The
|
|
264
|
+
Pi's built-in MCP as `mcp__entwurf_bridge__<verb>`. The bridge has nine tools;
|
|
268
265
|
pi hides `entwurf_inbox_read` and `entwurf_register_native`, leaving seven active.
|
|
269
266
|
The added `entwurf_retire_call` is only for one target/action explicitly requested by the
|
|
270
267
|
human operator, never autonomous cleanup. Where a host provides or is configured with an approval
|
|
@@ -349,12 +346,12 @@ by `entwurf pi` or by registering ordinary Pi's adapter.
|
|
|
349
346
|
|
|
350
347
|
What the Entwurf package supplies:
|
|
351
348
|
|
|
352
|
-
1. **The pi SDK set** — published 0.
|
|
353
|
-
pi-durable, chord, pi-mcp, pi-codemode, pi-telemetry, pi-schema}` at exactly `1.5.
|
|
354
|
-
`proper-lockfile`, as
|
|
355
|
-
|
|
356
|
-
[SDK pin](../pi/pi-durable/overlay/upstream-pin.json) and [package manifest](../package.json)
|
|
357
|
-
|
|
349
|
+
1. **The pi SDK set** — published 0.52.0 supplies `@earendil-works/{pi-coding-agent, pi-ai, pi-tui, pi-agent-core,
|
|
350
|
+
pi-durable, chord, pi-mcp, pi-codemode, pi-telemetry, pi-schema}` at exactly `1.5.2`, plus
|
|
351
|
+
`proper-lockfile`, as production dependencies. Model data rides `pi-ai@1.5.2`, not a catalog copy.
|
|
352
|
+
Historical 0.51.0 used <!-- entwurf:published @junghanacs/entwurf@0.51.0 pi 1.5.0 -->`@earendil-works/pi-ai@1.5.0`<!-- /entwurf:published -->.
|
|
353
|
+
The [SDK pin](../pi/pi-durable/overlay/upstream-pin.json) and [package manifest](../package.json)
|
|
354
|
+
describe the checkout you hold, not immutable published bytes.
|
|
358
355
|
2. **The native app/TUI carrier** — upstream does not publish the experimental durable
|
|
359
356
|
app (`pi-coding-agent` excludes `dist/experimental`; `pi-durable` on npm is the
|
|
360
357
|
library). Entwurf owns the six app files as canonical source (`pi/pi-durable/src`,
|
|
@@ -364,7 +361,7 @@ What the Entwurf package supplies:
|
|
|
364
361
|
(`pi/pi-durable/carrier-resolver.mjs`), which maps them to the published package's
|
|
365
362
|
own `dist/` as installed — never through a source checkout.
|
|
366
363
|
|
|
367
|
-
The upstream library guide for the published 0.51.0 pairing is [v1.5.0](https://github.com/earendil-works/pi/blob/v1.5.0/packages/durable/README.md); for the
|
|
364
|
+
The upstream library guide for the published 0.51.0 pairing is [v1.5.0](https://github.com/earendil-works/pi/blob/v1.5.0/packages/durable/README.md); for the published 0.52.0 SDK APIs use [v1.5.2](https://github.com/earendil-works/pi/blob/v1.5.2/packages/durable/README.md).
|
|
368
365
|
The [experimental app guide](https://github.com/earendil-works/pi/blob/v1.1.0/packages/coding-agent/src/experimental/durable/README.md)
|
|
369
366
|
(last published at v1.1.0) records the app's origin: Entwurf's maintained app source, not a newer upstream app, is the current composition authority. Both guides describe what the carrier is. Running the bare upstream app does not attach Entwurf's
|
|
370
367
|
garden contact. Entwurf does not rebuild the controller/model/auth/storage system or
|
|
@@ -379,7 +376,7 @@ carrier file, the license, the resolver and its relocation grammar are present
|
|
|
379
376
|
(`pi-durable-carrier-drift`); every declared SDK package resolves from the carrier
|
|
380
377
|
(`pi-durable-sdk-absent`); and every reachable physical edge — from the carrier to each package,
|
|
381
378
|
and from every package copy it reaches, at any depth, to its own `@earendil-works` dependencies —
|
|
382
|
-
lands on a package of the declared name at exactly the pinned version (`pi-durable-sdk-mismatch`). The members' declarations are exact in the published 1.5.0 set and, measured on the registry tarballs (#158), in the 1.5.2
|
|
379
|
+
lands on a package of the declared name at exactly the pinned version (`pi-durable-sdk-mismatch`). The members' declarations are exact in the published 1.5.0 set and, measured on the registry tarballs (#158), in the 1.5.2 set; even so, the physical package each import binds must be checked. Sharing
|
|
383
380
|
one copy with an aligned host install of the same version is an ordinary layout. A mixed
|
|
384
381
|
tree (for example an override that binds pi-durable's `pi-ai` to an older published version) still
|
|
385
382
|
*imports* — which is why the edge check exists — and is refused by name.
|
|
@@ -461,7 +458,7 @@ tree (for example an override that binds pi-durable's `pi-ai` to an older publis
|
|
|
461
458
|
manifest field; it is a known constraint of supplying both from one package, accepted for 0.32,
|
|
462
459
|
not a claim that every load path is harmless.
|
|
463
460
|
|
|
464
|
-
The ordinary Pi CLI on PATH is a separate subject (§2;
|
|
461
|
+
The ordinary Pi CLI on PATH is a separate subject (§2; historical 0.51.0 range <!-- entwurf:published @junghanacs/entwurf@0.51.0 pi 1.5.0 -->`>=1.5.0 <1.6`<!-- /entwurf:published -->, current 0.52.0 range `>=1.5.2 <1.6`): a host Pi is
|
|
465
462
|
not needed to run pi-durable, and a host inside the range need not be the same copy as the
|
|
466
463
|
carrier's. The native harnesses own credentials, model settings and their respective session stores — ordinary Pi JSONL and pi-durable SQLite; keep them
|
|
467
464
|
in place rather than copying credentials or migrating ordinary Pi transcripts. Native
|
|
@@ -474,7 +471,7 @@ proof ([#130](https://github.com/junghan0611/entwurf/issues/130)).
|
|
|
474
471
|
|
|
475
472
|
### SDK 1.5 development boundary (#155)
|
|
476
473
|
|
|
477
|
-
The
|
|
474
|
+
The historical 0.51.0 instructions describe the SDK 1.5.0 set that #155 shipped; the #155 SDK
|
|
478
475
|
1.5 development candidates that preceded it were distinct subjects. Synthetic migration and
|
|
479
476
|
downgrade-refusal fixtures on `0408a66` did not authorize an operating first write. A separately
|
|
480
477
|
approved 1.5 operating window and Native LIVE were later measured as described below; neither made
|
|
@@ -483,7 +480,7 @@ the validation TGZ the published artifact. Installing an older package is not a
|
|
|
483
480
|
|
|
484
481
|
### SDK 1.5.2 candidate boundary (#158)
|
|
485
482
|
|
|
486
|
-
The 0.52.0
|
|
483
|
+
The published 0.52.0 package (#158) pins the Pi SDK at exactly 1.5.2 (ten members) and declares host Pi `>=1.5.2 <1.6`. Publication does not install it on an operating host; an operating move requires its own installation and same-identity return receipts. The #155 receipts above prove their own subject only; none is inherited by 1.5.2.
|
|
487
484
|
|
|
488
485
|
What #158 measured so far and what it did not is recorded in [the durable-native boundary](./durable-native-support.md#sdk-152-candidate-boundary-158) and in the #158 thread: registry tarball integrity and member edges, an isolated six-member scheduler comparison and a native SQLite cross-version read/append check. The pre-version checkpoint's frozen FULL belongs to its own recorded worktree. The earlier validation candidate has its own floor and installation receipts; later source edits and the final carrier-bearing artifact require their own acceptance. Operating-scale and interrupted sessions are not certified by the bounded fixtures. An operating move follows the default radius below, each step with its own receipt.
|
|
489
486
|
|
|
@@ -998,7 +995,7 @@ real initial Pi outside `codex`, then omitted-placement Codex and outbound Pi in
|
|
|
998
995
|
callbacks and addressed delivery both ways. `DELIVERY.md` owns that 57-assertion receipt, its four
|
|
999
996
|
coordinates, and its digest as history. The caller-seat re-run is **accepted** — 2026-09-16, 56
|
|
1000
997
|
assertions for the seat topology and 65 for the caller-DIRECTORY axis, both exit 0 — and it, not the
|
|
1001
|
-
fixed home, is the current contract (`DELIVERY.md`,
|
|
998
|
+
fixed home, is the current contract (`DELIVERY.md`, BASELINE.md's release-host table (Codex caller-seat rows), `VERIFY.md` release
|
|
1002
999
|
acceptance).
|
|
1003
1000
|
|
|
1004
1001
|
`entwurf_fresh_call` accepts backend `codex` — supported in 0.21.0 — and requires an explicit model. Its
|
|
@@ -1078,7 +1075,7 @@ LIVE=1 AGY_CONVERSATION_ID=<id> entwurf smoke-agy-native-push-live
|
|
|
1078
1075
|
|
|
1079
1076
|
ACP turns are CERTIFIED on Linux; on macOS they are NOT CERTIFIED —
|
|
1080
1077
|
pending physical host. Mux (visible fresh / resume) is the same state.
|
|
1081
|
-
A CI runner has no Claude
|
|
1078
|
+
A CI runner has no Claude login.
|
|
1082
1079
|
|
|
1083
1080
|
Claude uses the operator's existing local Claude authentication:
|
|
1084
1081
|
|
|
@@ -1086,16 +1083,10 @@ Claude uses the operator's existing local Claude authentication:
|
|
|
1086
1083
|
LIVE=1 entwurf smoke-acp-provider-live
|
|
1087
1084
|
```
|
|
1088
1085
|
|
|
1089
|
-
Cortex
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> \
|
|
1094
|
-
entwurf smoke-acp-cortex-live
|
|
1095
|
-
```
|
|
1096
|
-
|
|
1097
|
-
The aggregate release gate is Claude-backed and does not run Cortex automatically.
|
|
1098
|
-
Its silence is not a Cortex PASS.
|
|
1086
|
+
Cortex ACP is disabled. Existing Cortex configuration and credentials are not modified.
|
|
1087
|
+
Entwurf fresh/resume exact admission refuses retired Cortex ids; the ACP adapter also
|
|
1088
|
+
refuses a Cortex id that reaches it, without a Claude fallback. Pi's own direct `--model`
|
|
1089
|
+
fuzzy selection precedes that adapter; its result for a typed retired id is unmeasured here.
|
|
1099
1090
|
|
|
1100
1091
|
### Backend prerequisites and resolver
|
|
1101
1092
|
|
|
@@ -1107,12 +1098,10 @@ operator-installed Claude runtime. Resolution order:
|
|
|
1107
1098
|
2. `require.resolve(...)` against the bundled `@agentclientprotocol/claude-agent-acp`.
|
|
1108
1099
|
3. `PATH:claude-agent-acp` fallback if package resolution fails.
|
|
1109
1100
|
|
|
1110
|
-
The curated Claude ids are `claude-opus-5-5`, `claude-sonnet-5-5`,
|
|
1111
|
-
`claude-fable-5-1
|
|
1112
|
-
`
|
|
1113
|
-
|
|
1114
|
-
an authenticated connection; the env override wins. Codex and Antigravity are
|
|
1115
|
-
native-push citizens (§4c/§5), not ACP backends.
|
|
1101
|
+
The curated Claude ids are `claude-opus-5-5`, `claude-sonnet-5-5`,
|
|
1102
|
+
`claude-fable-5-1`, and `claude-fable-5-2`. Cortex ACP is disabled; a legacy
|
|
1103
|
+
`entwurfProvider.cortexConnection` does not select a backend or block Claude.
|
|
1104
|
+
Codex and Antigravity are native-push citizens (§4c/§5), not ACP backends.
|
|
1116
1105
|
|
|
1117
1106
|
### Settings reference and backend-specific keys
|
|
1118
1107
|
|
|
@@ -1147,15 +1136,11 @@ retired bundled `session-bridge` entry. It is not a general MCP catalog.
|
|
|
1147
1136
|
user augment. Large Claude `_meta.systemPrompt` carriers can route OAuth sessions
|
|
1148
1137
|
to metered “extra usage” billing.
|
|
1149
1138
|
|
|
1150
|
-
`entwurfProvider` is one block, not a promise that every key shapes both backends.
|
|
1151
1139
|
`tools`, `permissionAllow`, `disallowedTools`, `settingSources`, `skillPlugins`
|
|
1152
|
-
and `appendSystemPrompt` are Claude's declaration surface
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
transports. `compaction` is a **top-level pi key**, not a backend knob. Unknown
|
|
1157
|
-
and retired keys are ignored; a wrong-backend key can fail silently, so check
|
|
1158
|
-
which backend consumes it before diagnosing bridge failure.
|
|
1140
|
+
and `appendSystemPrompt` are Claude's declaration surface. `mcpServers` carries
|
|
1141
|
+
explicit servers. `compaction` is a **top-level pi key**, not a backend knob.
|
|
1142
|
+
The retired `cortexConnection` key is not consumed by Claude and does not enable
|
|
1143
|
+
Cortex ACP; unknown and retired keys are ignored.
|
|
1159
1144
|
|
|
1160
1145
|
### Backend operation and containment
|
|
1161
1146
|
|
|
@@ -1170,12 +1155,8 @@ Read/Bash/Edit/Write; `Skill` is added for non-empty `skillPlugins`.
|
|
|
1170
1155
|
The launch env sets `CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1`: vendor-managed
|
|
1171
1156
|
background work is off, not arbitrary processes a command detaches itself.
|
|
1172
1157
|
|
|
1173
|
-
Cortex uses its native tools, session-private HOME / `SNOWFLAKE_HOME`, and private
|
|
1174
|
-
`cortex/mcp.json` projection because it ignores wire `mcpServers`. Only the bridge
|
|
1175
|
-
receives the real operator HOME needed for the garden store; `CORTEX_HOME` is
|
|
1176
|
-
refused, including an empty value, because it bypasses containment.
|
|
1177
1158
|
[ACP backend rail — Shipped adapters](./acp-backend-rail.md#shipped-adapters)
|
|
1178
|
-
owns the exact overlay/carrier
|
|
1159
|
+
owns the exact Claude overlay/carrier mechanics and audit limits.
|
|
1179
1160
|
|
|
1180
1161
|
Entwurf owns no memory layer or memory DB, and no backend is another's memory
|
|
1181
1162
|
authority. Operator semantic-memory / Denote tools remain host-native skills,
|
|
@@ -1210,7 +1191,7 @@ Non-empty `skillPlugins` auto-adds `Skill` to `tools` and `Skill(*)` to
|
|
|
1210
1191
|
path or missing `.claude-plugin/plugin.json` before starting the session; the
|
|
1211
1192
|
SDK, not the bridge, validates plugin.json contents and SKILL.md bodies.
|
|
1212
1193
|
Start a fresh Claude session and ask it to list callable skills. The operator
|
|
1213
|
-
judgement is
|
|
1194
|
+
judgement is asking the session which skills it can call; it is not a named row in [VERIFY](../VERIFY.md).
|
|
1214
1195
|
This is Claude-only; Codex uses native `~/.codex/skills/` passthrough.
|
|
1215
1196
|
[agent-config](https://github.com/junghan0611/agent-config) is a real multi-harness
|
|
1216
1197
|
consumer, not a requirement for this setup.
|
|
@@ -1236,8 +1217,7 @@ Bridge identity, pi context, `~/AGENTS.md`, cwd AGENTS and date/cwd ride a one-s
|
|
|
1236
1217
|
first-user prepend (`pi-context-augment.ts`), not the system carrier. It removes
|
|
1237
1218
|
duplicate cwd AGENTS already in `<project-context ...>`. Its descriptions do not
|
|
1238
1219
|
grant tools: the actual callable schema is truth (`read` / `Read` / `exec_command`,
|
|
1239
|
-
MCP only when schema-visible).
|
|
1240
|
-
has no system-prompt carrier; Claude uses `_meta.systemPrompt`.
|
|
1220
|
+
MCP only when schema-visible). Claude uses `_meta.systemPrompt` for its engraving.
|
|
1241
1221
|
|
|
1242
1222
|
### Session reuse and compaction
|
|
1243
1223
|
|
|
@@ -1253,7 +1233,12 @@ owns the reuse policy and distinguishes live mapping from semantic recall.
|
|
|
1253
1233
|
**Entwurf does not implement compaction.** A backend's native compaction preserves
|
|
1254
1234
|
the pi session/mapping; configure its policy through that backend's own interface,
|
|
1255
1235
|
not a pi-side JSONL summary. The bridge exposes no backend-specific compaction
|
|
1256
|
-
knobs.
|
|
1236
|
+
knobs. One fixed exception on the Claude ACP rail: its adapter's idle `/compact` (an autonomous
|
|
1237
|
+
turn on an idle session) is turned off inline (`settings.idleCompaction: false`), because pi would
|
|
1238
|
+
not see that turn; in-prompt auto-compaction stays the backend's, and a managed settings tier would
|
|
1239
|
+
still win over the inline value ([rail §Capability posture](./acp-backend-rail.md#capability-posture)).
|
|
1240
|
+
Pi's own summaries on a Claude ACP model (`/compact`, the threshold, overflow recovery, `/tree`) are not that backend compaction: each runs as a one-shot tool-less turn on a new child, and the session's retained child is closed after a compaction ([rail §11-10](./acp-backend-rail.md)).
|
|
1241
|
+
The ACP footer uses `usage_update.used / size` (backend prompt/tools/cache/
|
|
1257
1242
|
session included) with `[entwurf:usage]` diagnostics. Near limit choose a visible
|
|
1258
1243
|
action: clear, open a new session with a different model, or let the backend
|
|
1259
1244
|
compact natively.
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// This module owns the `AcpConnectionLike` seam so the backend and the live
|
|
17
17
|
// smokes both drive ONE adapter — the SDK method-name mapping lives here only,
|
|
18
18
|
// and the backend's orchestration + the gate fakes stay untouched.
|
|
19
|
-
import { AGENT_METHODS, CLIENT_METHODS, client
|
|
19
|
+
import { AGENT_METHODS, CLIENT_METHODS, client } from "@agentclientprotocol/sdk";
|
|
20
20
|
/**
|
|
21
21
|
* Production factory — wrap the SDK 1.1 fluent `client()` into the
|
|
22
22
|
* `AcpConnectionLike` seam the backend (and the live smokes) drive.
|
|
@@ -23,7 +23,7 @@ import { fileURLToPath } from "node:url";
|
|
|
23
23
|
import { RequestError } from "@agentclientprotocol/sdk";
|
|
24
24
|
import { enrichMcpServersWithEnvelope } from "./config.js";
|
|
25
25
|
import { loadEngraving } from "./engraving.js";
|
|
26
|
-
import { CORTEX_MODEL_PREFIX, curatedClaudeModels, curatedCortexModels,
|
|
26
|
+
import { CLAUDE_ACP_EFFORT_VALUES, CORTEX_MODEL_PREFIX, curatedClaudeModels, curatedCortexModels, LEGACY_CORTEX_MODEL_IDS, SUPPORTED_ANTHROPIC_MODEL_IDS, } from "./models.js";
|
|
27
27
|
import { claudeLaunchEnvDefaults, ensureClaudeConfigOverlay, ensureCortexDualHomeOverlay } from "./overlay.js";
|
|
28
28
|
import { buildClaudeSessionMeta } from "./tool-surface.js";
|
|
29
29
|
// POSIX-safe single-quote wrapper for shell arg interpolation. Byte-for-byte
|
|
@@ -114,7 +114,7 @@ export const CLAUDE_FOREGROUND_ONLY_ENV = { CLAUDE_CODE_DISABLE_BACKGROUND_TASKS
|
|
|
114
114
|
* The set-model answer is read back before the prompt (#128). claude-agent-acp resolves the
|
|
115
115
|
* requested id onto one of the rows it offers and answers with that row's `value` as the model
|
|
116
116
|
* option's `currentValue` (0.85.1 `dist/acp-agent.js:5459-5499`). `[측정 2026-10-12]` 0.85.1, no
|
|
117
|
-
* prompt: `claude-fable-5-1` answers its own row, while `claude-sonnet-5-5` and `claude-opus-5-5`
|
|
117
|
+
* prompt: `claude-fable-5-1` answers its own row (and, at 0.106.0 #142, so does `claude-fable-5-2`), while `claude-sonnet-5-5` and `claude-opus-5-5`
|
|
118
118
|
* answer the alias rows `sonnet` and `opus`, named `Sonnet 5.5` and `Opus 5.5`. The id an alias row
|
|
119
119
|
* resolves to (`ModelInfo.resolvedModel`) is not on the ACP wire, so an alias answer is accepted
|
|
120
120
|
* only as the exact measured row, value AND name, declared here for the requested id. No other
|
|
@@ -148,6 +148,46 @@ export function confirmClaudeSetModelAnswer(response, nativeModelId) {
|
|
|
148
148
|
`name the requested model. Refusing before the prompt so a different model cannot answer under this id; ` +
|
|
149
149
|
`the installed driver and the curated id disagree, and repeating the turn cannot change that.`);
|
|
150
150
|
}
|
|
151
|
+
const CLAUDE_EFFORT_VALUE_SET = new Set(CLAUDE_ACP_EFFORT_VALUES);
|
|
152
|
+
/** The named refusal for a thinking level ACP Claude cannot carry (#142). The text is fixed and
|
|
153
|
+
* must read as NON-transient to pi's retry and overflow classifiers: replaying the turn cannot
|
|
154
|
+
* change the level that was asked for. */
|
|
155
|
+
export const ACP_THINKING_LEVEL_UNSUPPORTED = "acp-thinking-level-unsupported";
|
|
156
|
+
/**
|
|
157
|
+
* Map pi's requested level to the claude-agent-acp effort value, or refuse by name (#142).
|
|
158
|
+
* The value is the registered row's `thinkingLevelMap` entry for that level — the documented pi
|
|
159
|
+
* meaning of the map — and must be one of the measured effort values. `undefined` (pi off, or no
|
|
160
|
+
* level) is refused rather than left at the vendor `default`: that would let the turn run at a
|
|
161
|
+
* depth nobody chose while the operator believes a level was applied.
|
|
162
|
+
*/
|
|
163
|
+
export function resolveClaudeEffort(modelId, reasoning, thinkingLevelMap) {
|
|
164
|
+
const value = reasoning === undefined ? undefined : thinkingLevelMap?.[reasoning];
|
|
165
|
+
if (typeof value === "string" && CLAUDE_EFFORT_VALUE_SET.has(value))
|
|
166
|
+
return value;
|
|
167
|
+
const asked = reasoning === undefined
|
|
168
|
+
? "no thinking level (pi sends none for `off`, and none when no level is set; the two are indistinguishable here)"
|
|
169
|
+
: `thinking level ${JSON.stringify(reasoning)}`;
|
|
170
|
+
throw new Error(`entwurf: ${ACP_THINKING_LEVEL_UNSUPPORTED} — ${modelId} over Claude ACP carries effort ` +
|
|
171
|
+
`${CLAUDE_ACP_EFFORT_VALUES.join("/")} only, and was asked for ${asked}. Choose one of those levels; ` +
|
|
172
|
+
`the turn was not sent, and repeating it at the same level cannot change that.`);
|
|
173
|
+
}
|
|
174
|
+
function claudeEffortRefusal(modelId, value, what, cause) {
|
|
175
|
+
const error = new Error(`entwurf: claude-agent-acp ${what} for effort ${JSON.stringify(value)} on ${modelId}. Refusing before the prompt ` +
|
|
176
|
+
`so the turn cannot run at an effort nobody chose; repeating the turn cannot change the driver's answer.`);
|
|
177
|
+
if (cause !== undefined)
|
|
178
|
+
error.cause = cause;
|
|
179
|
+
return error;
|
|
180
|
+
}
|
|
181
|
+
/** Refuse unless the set-effort answer reads back the requested value. */
|
|
182
|
+
export function confirmClaudeEffortAnswer(response, modelId, value) {
|
|
183
|
+
const configOptions = response?.configOptions;
|
|
184
|
+
const effort = Array.isArray(configOptions)
|
|
185
|
+
? configOptions.find((option) => option?.id === "effort")
|
|
186
|
+
: undefined;
|
|
187
|
+
if (effort?.currentValue === value)
|
|
188
|
+
return;
|
|
189
|
+
throw claudeEffortRefusal(modelId, value, effort == null ? "answered with no effort option" : `answered effort ${jsonText(effort.currentValue)}`);
|
|
190
|
+
}
|
|
151
191
|
export const claudeAdapter = {
|
|
152
192
|
backend: "claude",
|
|
153
193
|
// Claude owns its UNPREFIXED curated ids only (rail “Adapter contract”). The native id
|
|
@@ -206,6 +246,23 @@ export const claudeAdapter = {
|
|
|
206
246
|
});
|
|
207
247
|
confirmClaudeSetModelAnswer(answer, nativeModelId);
|
|
208
248
|
},
|
|
249
|
+
resolveThinking({ modelId, reasoning, thinkingLevelMap }) {
|
|
250
|
+
return resolveClaudeEffort(modelId, reasoning, thinkingLevelMap);
|
|
251
|
+
},
|
|
252
|
+
async enforceThinking({ connection, acpSessionId, modelId, value }) {
|
|
253
|
+
const setConfig = connection.setSessionConfigOption;
|
|
254
|
+
if (typeof setConfig !== "function") {
|
|
255
|
+
throw new Error(`setSessionConfigOption unsupported — cannot set effort for ${modelId}`);
|
|
256
|
+
}
|
|
257
|
+
let answer;
|
|
258
|
+
try {
|
|
259
|
+
answer = await setConfig.call(connection, { sessionId: acpSessionId, configId: "effort", value });
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
throw claudeEffortRefusal(modelId, value, "refused the set", err);
|
|
263
|
+
}
|
|
264
|
+
confirmClaudeEffortAnswer(answer, modelId, value);
|
|
265
|
+
},
|
|
209
266
|
configSignatureFields(_adapterSettings) {
|
|
210
267
|
// Claude folds no extra backend-specific fields beyond backend + nativeModelId
|
|
211
268
|
// (which backend.ts adds). A future backend reads its own stable id off
|
|
@@ -226,21 +283,15 @@ export const claudeAdapter = {
|
|
|
226
283
|
// ---------------------------------------------------------------------------
|
|
227
284
|
// Registry — modelId → adapter
|
|
228
285
|
// ---------------------------------------------------------------------------
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
// ---------------------------------------------------------------------------
|
|
234
|
-
// cortex adapter — Snowflake Cortex Code, the first non-claude backend on the
|
|
235
|
-
// rail (docs/acp-backend-rail.md, “Shipped adapters”). It adds ZERO to the common layer:
|
|
236
|
-
// everything cortex-specific lives here + models.ts + overlay.ts + the gates.
|
|
237
|
-
// ---------------------------------------------------------------------------
|
|
238
|
-
const SUPPORTED_CORTEX_IDS = new Set(SUPPORTED_CORTEX_MODEL_IDS);
|
|
286
|
+
// The former Cortex implementation is retained privately for historical source
|
|
287
|
+
// continuity only. The exported adapter below denies every side-effecting entry,
|
|
288
|
+
// and the production registry does not contain this implementation.
|
|
289
|
+
const SUPPORTED_CORTEX_IDS = new Set(LEGACY_CORTEX_MODEL_IDS);
|
|
239
290
|
/** The env var an operator sets to pin a Snowflake connection per-shell without
|
|
240
291
|
* editing settings.json. Wins over `entwurfProvider.cortexConnection`. The
|
|
241
292
|
* ENTWURF_ACP_* convention (PR #40's legacy PI_SHELL_ACP* cortex-connection var renamed). */
|
|
242
293
|
export const CORTEX_CONNECTION_ENV = "ENTWURF_ACP_CORTEX_CONNECTION";
|
|
243
|
-
|
|
294
|
+
const retiredCortexAdapter = {
|
|
244
295
|
backend: "cortex",
|
|
245
296
|
// Cortex owns the reserved `cortex-` prefix (rail “Adapter contract”). routeModel strips it to the
|
|
246
297
|
// native id: `cortex-auto` → "auto", `cortex-claude-sonnet-5` → "claude-sonnet-5".
|
|
@@ -373,7 +424,29 @@ export const cortexAdapter = {
|
|
|
373
424
|
// server rejects a prompt with, so every cortex failure keeps the verbatim-first
|
|
374
425
|
// errorMessage. Borrowing claude's `incomplete_tool_call` reader would be a guess.
|
|
375
426
|
};
|
|
376
|
-
const
|
|
427
|
+
const cortexDisabled = () => {
|
|
428
|
+
throw new Error("entwurf: cortex-acp-disabled: Cortex ACP is not supported");
|
|
429
|
+
};
|
|
430
|
+
/** Retained exported shape refuses the retired adapter before a launch or overlay can be made. */
|
|
431
|
+
export const cortexAdapter = {
|
|
432
|
+
...retiredCortexAdapter,
|
|
433
|
+
routeModel: () => undefined,
|
|
434
|
+
curatedModels: () => [],
|
|
435
|
+
resolveAdapterSettings: cortexDisabled,
|
|
436
|
+
resolveLaunch: cortexDisabled,
|
|
437
|
+
launchEnvDefaults: cortexDisabled,
|
|
438
|
+
ensureOverlay: cortexDisabled,
|
|
439
|
+
loadCarrier: cortexDisabled,
|
|
440
|
+
buildSessionMeta: cortexDisabled,
|
|
441
|
+
enforceModel: cortexDisabled,
|
|
442
|
+
configSignatureFields: cortexDisabled,
|
|
443
|
+
};
|
|
444
|
+
const ADAPTERS = [claudeAdapter];
|
|
445
|
+
/** A declared backend is only a guard, never a replacement routing authority. */
|
|
446
|
+
export function assertSupportedDeclaredBackend(backend) {
|
|
447
|
+
if (backend?.toLowerCase() === "cortex")
|
|
448
|
+
cortexDisabled();
|
|
449
|
+
}
|
|
377
450
|
/**
|
|
378
451
|
* Resolve the backend adapter that owns `modelId`.
|
|
379
452
|
*
|
|
@@ -385,6 +458,9 @@ const ADAPTERS = [claudeAdapter, cortexAdapter];
|
|
|
385
458
|
* so callers get `{ adapter, nativeModelId }` and never re-parse the id string.
|
|
386
459
|
*/
|
|
387
460
|
export function resolveAcpBackendAdapter(modelId) {
|
|
461
|
+
if (modelId.toLowerCase().startsWith(CORTEX_MODEL_PREFIX)) {
|
|
462
|
+
throw new Error(`entwurf: cortex-acp-disabled: ${JSON.stringify(modelId)} is not supported`);
|
|
463
|
+
}
|
|
388
464
|
const matches = [];
|
|
389
465
|
for (const adapter of ADAPTERS) {
|
|
390
466
|
const routed = adapter.routeModel(modelId);
|
|
@@ -16,15 +16,10 @@
|
|
|
16
16
|
//
|
|
17
17
|
// The COMMON keys parsed here are Claude-SHAPED by origin (tools / permissionAllow /
|
|
18
18
|
// disallowedTools / settingSources / skillPlugins are claude-agent-acp's surface).
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// the backend-invariant exclude-tools preflight and folds every one of them into
|
|
24
|
-
// `bridgeConfigSignature` (so changing one still invalidates a reused cortex
|
|
25
|
-
// session). Backend-OWNED settings never land here: they ride the opaque
|
|
26
|
-
// `adapterSettings` seam (rail “Adapter contract”), which is what keeps a backend-named key like
|
|
27
|
-
// `cortexConnection` off this common shape.
|
|
19
|
+
// The common path reads `tools` for the backend-invariant exclude-tools preflight
|
|
20
|
+
// and folds these keys into `bridgeConfigSignature`. Backend-owned settings ride
|
|
21
|
+
// the opaque `adapterSettings` seam. A dormant `cortexConnection` does not select
|
|
22
|
+
// or enable Cortex ACP, which is disabled.
|
|
28
23
|
//
|
|
29
24
|
// PURITY / SIGNATURE contract (NEXT oracle C / 핀1 / GPT `…2f9325` boost):
|
|
30
25
|
// - `normalizeMcpServers` is pure: a SORTED, validated server list + a sha256
|
|
@@ -57,6 +57,17 @@ function textFromAssistantContent(content) {
|
|
|
57
57
|
.map((c) => c.text)
|
|
58
58
|
.join(""));
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* The harness fact pi already holds about an assistant turn that was cut
|
|
62
|
+
* (`stopReason: "aborted"` — an operator abort, or a vendor `cancelled` mapped to it; the line
|
|
63
|
+
* names no cause), stated so a NEW session's transcript does not read a
|
|
64
|
+
* cancelled turn as a clean refusal (#142: a fresh session concluded a command had
|
|
65
|
+
* not run when its first effect was on disk). It adds no claim about what did or
|
|
66
|
+
* did not happen — only that the turn was cut and that a cut is not a rollback.
|
|
67
|
+
* Only the full transcript carries it: a reused session already holds its own
|
|
68
|
+
* record of the interruption and receives just the latest user delta.
|
|
69
|
+
*/
|
|
70
|
+
export const ABORTED_TURN_STATUS = "[turn status: aborted — actions this turn had started may already have taken effect; cancellation is not rollback]";
|
|
60
71
|
/** Render one pi message as a transcript line, or undefined to skip it. */
|
|
61
72
|
function renderMessage(message) {
|
|
62
73
|
switch (message.role) {
|
|
@@ -66,6 +77,10 @@ function renderMessage(message) {
|
|
|
66
77
|
}
|
|
67
78
|
case "assistant": {
|
|
68
79
|
const text = textFromAssistantContent(message.content).trim();
|
|
80
|
+
if (message.stopReason === "aborted") {
|
|
81
|
+
// Kept even when the cut turn left no text: the cut itself is the fact.
|
|
82
|
+
return text ? `Assistant: ${text}\n${ABORTED_TURN_STATUS}` : `Assistant: ${ABORTED_TURN_STATUS}`;
|
|
83
|
+
}
|
|
69
84
|
return text ? `Assistant: ${text}` : undefined;
|
|
70
85
|
}
|
|
71
86
|
case "toolResult": {
|
|
@@ -12,12 +12,9 @@
|
|
|
12
12
|
// would need a `.ts` specifier the root config cannot allow.
|
|
13
13
|
//
|
|
14
14
|
// WHY THE LAUNCH SEAMS ASK AT ALL. Pi's `--model` resolver falls back to a
|
|
15
|
-
// case-insensitive substring match among
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
// silently open on the Snowflake Cortex rail instead of the Claude subscription.
|
|
19
|
-
// An exact match against this list is the only admission; nothing is aliased,
|
|
20
|
-
// substituted or rewritten.
|
|
15
|
+
// case-insensitive substring match among provider rows. The old multi-backend
|
|
16
|
+
// surface could silently match a retired Claude id to a Cortex row. Cortex is
|
|
17
|
+
// now disabled; exact membership remains the admission, with no substitution.
|
|
21
18
|
/** The single ACP provider id under which every curated row is registered. */
|
|
22
19
|
export const PROVIDER_ID = "entwurf";
|
|
23
20
|
// The curated Claude ids. Adding one here is a commitment to verify it across
|
|
@@ -26,20 +23,21 @@ export const SUPPORTED_ANTHROPIC_MODEL_IDS = /** @type {const} */ ([
|
|
|
26
23
|
"claude-sonnet-5-5",
|
|
27
24
|
"claude-opus-5-5",
|
|
28
25
|
"claude-fable-5-1",
|
|
26
|
+
"claude-fable-5-2",
|
|
29
27
|
]);
|
|
30
28
|
/** The anchor model whose absence is a hard registry regression, not a soft skip. */
|
|
31
29
|
export const CURATED_ANCHOR_MODEL_ID = "claude-opus-5-5";
|
|
32
|
-
//
|
|
33
|
-
//
|
|
30
|
+
// These former IDs are retained only as historical refusal inputs. The prefix
|
|
31
|
+
// is reserved so a disabled Cortex request never falls through to Claude.
|
|
34
32
|
export const CORTEX_MODEL_PREFIX = "cortex-";
|
|
35
|
-
export const
|
|
33
|
+
export const LEGACY_CORTEX_MODEL_IDS = /** @type {const} */ ([
|
|
36
34
|
"cortex-auto",
|
|
37
35
|
"cortex-claude-opus-5",
|
|
38
36
|
"cortex-claude-sonnet-5",
|
|
39
37
|
"cortex-openai-gpt-5.4",
|
|
40
38
|
]);
|
|
41
39
|
/** @type {ReadonlySet<string>} */
|
|
42
|
-
const CURATED_ACP_MODEL_IDS = new Set(
|
|
40
|
+
const CURATED_ACP_MODEL_IDS = new Set(SUPPORTED_ANTHROPIC_MODEL_IDS);
|
|
43
41
|
/**
|
|
44
42
|
* Exact membership only — no trim, no case folding, no prefix.
|
|
45
43
|
* @param {string} model
|
|
@@ -51,8 +49,7 @@ export function isCuratedAcpModelId(model) {
|
|
|
51
49
|
/** The named refusal both launch seams answer with. */
|
|
52
50
|
export const ACP_MODEL_NOT_CURATED = /** @type {const} */ ("acp-model-not-curated");
|
|
53
51
|
export const ACP_MODEL_NOT_CURATED_HINT = `an ${PROVIDER_ID} model must be one exact curated ACP id (${[...CURATED_ACP_MODEL_IDS].join(", ")}); ` +
|
|
54
|
-
"Pi
|
|
55
|
-
"so nothing was opened, and nothing is aliased or rewritten";
|
|
52
|
+
"Cortex ACP is disabled; Pi may otherwise pick another row by substring, so nothing was opened and nothing is aliased or rewritten";
|
|
56
53
|
/** Carries `reason` so callers match a FIELD, never the wording. */
|
|
57
54
|
export class AcpModelNotCuratedError extends Error {
|
|
58
55
|
/** @param {string} model */
|