Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
dcef330
fix(dev): stop fabricating route-invocation provider timings
ScriptedAlchemy Sep 5, 2026
a3cce28
fix(dev): pin route invocations to a leased epoch (AB8239)
ScriptedAlchemy Sep 5, 2026
de055e5
fix(dev): rewrite only module specifiers in the route invocation chil…
ScriptedAlchemy Sep 5, 2026
fef0bbe
integrate A4
ScriptedAlchemy Sep 5, 2026
912f1b7
drop LANE-NOTES
ScriptedAlchemy Sep 5, 2026
5efc4b0
integrate A3
ScriptedAlchemy Sep 5, 2026
502e64f
fix merged telemetry/lease test fixtures
ScriptedAlchemy Sep 5, 2026
0d5925b
integrate A1
ScriptedAlchemy Sep 5, 2026
5de5f1c
feat: execute routes from compiled artifacts
ScriptedAlchemy Sep 5, 2026
1b7d78e
integrate A2
ScriptedAlchemy Sep 5, 2026
61c8a32
integrate A2: args check after prepared lease
ScriptedAlchemy Sep 5, 2026
68a938e
integrate A2: trace type through the invocations contract; unit-rende…
ScriptedAlchemy Sep 5, 2026
4dbe4df
integration test: observed provider telemetry from the compiled worker
ScriptedAlchemy Sep 5, 2026
83b28ed
changeset: PR 2a execution parity + provenance
ScriptedAlchemy Sep 5, 2026
0723fc1
Merge origin/main (#635, #640, #636) into wb600-pr2a-exec
ScriptedAlchemy Sep 5, 2026
fdd8932
fix workbench invocation epoch state parity
ScriptedAlchemy Sep 5, 2026
c44ef46
integrate A5
ScriptedAlchemy Sep 5, 2026
fd46e89
drop LANE-NOTES
ScriptedAlchemy Sep 5, 2026
58ec27b
Merge remote-tracking branch 'origin/main' into wb600-pr2a-exec
ScriptedAlchemy Sep 5, 2026
a89aa6c
changeset: name #643
ScriptedAlchemy Sep 5, 2026
2f2ad57
fix(dev): retain state across epoch rebuilds
ScriptedAlchemy Sep 5, 2026
7fcc028
feat(workbench): select invocation surfaces
ScriptedAlchemy Sep 5, 2026
8957f3b
drop LANE-NOTES
ScriptedAlchemy Sep 5, 2026
796096b
drop LANE-NOTES
ScriptedAlchemy Sep 5, 2026
c61cdb9
integrate A6 (surface model) and A9 (dev state root)
ScriptedAlchemy Sep 5, 2026
a12423d
fix stateful test helper call; runtime-environment docs follow the pr…
ScriptedAlchemy Sep 5, 2026
657d7f1
Report route invocation outcome separately from execution status (#64…
ScriptedAlchemy Sep 5, 2026
1a1a46f
drop LANE-NOTES
ScriptedAlchemy Sep 5, 2026
44bfc7d
integrate A7 (outcome vs execution status)
ScriptedAlchemy Sep 5, 2026
db99d4a
project isolated renders by the route's default surface; port exit fi…
ScriptedAlchemy Sep 5, 2026
6c15152
test: cover route invocation acceptance fixtures
ScriptedAlchemy Sep 5, 2026
551130d
fix workbench route review findings
ScriptedAlchemy Sep 5, 2026
564b1e6
drop LANE-NOTES
ScriptedAlchemy Sep 5, 2026
d9aeaf5
drop LANE-NOTES
ScriptedAlchemy Sep 5, 2026
1b451a5
integrate A10 (review fixes) and A8 (six acceptance fixtures); keep t…
ScriptedAlchemy Sep 5, 2026
18739c3
Merge origin/main (#604 manifest v2, #634, #645, #646, #649) into wb6…
ScriptedAlchemy Sep 5, 2026
629738f
Deslop pass for #643 (lane A11)
ScriptedAlchemy Sep 5, 2026
4908c01
drop LANE-NOTES
ScriptedAlchemy Sep 5, 2026
527878b
test: give the compiled-artifact dev-server suites a load-tolerant bu…
ScriptedAlchemy Sep 5, 2026
e1cf6d3
test: keep the parity fixture's handler marker out of the watched sou…
ScriptedAlchemy Sep 6, 2026
d04ff7c
Merge remote-tracking branch 'origin/main' into wb600-pr2a-exec
ScriptedAlchemy Sep 6, 2026
55be005
test(workbench): exact heading locators through expectHeading (#632)
ScriptedAlchemy Sep 6, 2026
79ed2cb
Merge remote-tracking branch 'origin/main' into wb600-pr2a-exec
ScriptedAlchemy Sep 6, 2026
d1a7282
fix: review round 2 — Workbench-only worker input validation, host se…
ScriptedAlchemy Sep 6, 2026
a47f9f8
fix(workbench): loaded invocation host wins over the preflight defaul…
ScriptedAlchemy Sep 6, 2026
7f2dd25
fix(workbench): the preflight default repairs an invalid host selecti…
ScriptedAlchemy Sep 6, 2026
f1eba9c
Merge remote-tracking branch 'origin/main' into wb600-pr2a-exec
ScriptedAlchemy Sep 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/wb600-pr2a-execution-parity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"agent-bundle": patch
---

Run Workbench route invocations (`POST /api/routes/invocations`) through the published compiler epoch by default, so compiler aliases and defines, generated CLI `mapInput` and confirmation, event preflight, operator `.env` layering, and measured provider and render telemetry match the installed artifact and MCP input is validated against the compiled `inputSchema` before the handler runs; `agent-bundle dev` pins `AGENT_BUNDLE_STATE_ROOT` for invocations and dev MCP sessions to `<project>/.agent-bundle/state` so state survives a republish. Requests replace `args`/`event` with a `surface` union (`mcp`, `cli`, `event`, `script`, `unit-render`) resolved from the route kind when omitted and recorded on every envelope, and a completed run reports an `outcome` (`success`, `represented-error`, or `process-exit` with the generated bin's exit code) separately from its execution `status` in the envelope, the `route.invocation` project event, and the Workbench. New diagnostics: `AB8239` (published revision moved while queued), `AB8250`–`AB8252` (compiled artifact, route executable, or preparation unavailable), `AB8253`/`AB8254` (CLI command or projected `cli:` id instead of the canonical `tool:` operation), and `AB8255` (preflight event route submitted without a concrete host). The unit-render loader rewrites only module specifiers from `.js` to `.tsx`, leaving string literals intact. (#643)
2 changes: 2 additions & 0 deletions docs/diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ even when no error diagnostic was reported.
| `AB8219`–`AB8223` | Workbench live MCP probe route (user-initiated, read-only initialize + tools/list): `AB8219` invalid path, `AB8220` invalid request/method, `AB8221` probe target not found, `AB8222` response over the 16 MiB budget, `AB8223` probe unavailable. |
| `AB8233`–`AB8235` | Workbench browser-side strict decoders rejecting a dev-server response: `AB8233` lifecycle replay, `AB8234` host discovery, `AB8235` MCP probe report. |
| `AB8231`–`AB8232`, `AB8236`–`AB8238` | Workbench route invocation service (`/api/routes/invocations`): `AB8231` unknown route or invocation id, `AB8232` no published build / invocation manifest unavailable, `AB8236` render child timed out or crashed, `AB8237` malformed invocation request, and `AB8238` unknown fixture id. (`AB8233`–`AB8235` were already assigned to browser-side decoders.) |
| `AB8239` | Workbench route invocation service (`/api/routes/invocations`): the published manifest digest or source revision moved while the request waited for a concurrency slot (409). Retry against the current revision so the recorded `manifestDigest`/`sourceRevision` cannot describe a different build than the one that ran. |
| `AB8250`–`AB8255` | Workbench production route execution: `AB8250` no published compiler artifact is available, `AB8251` the selected route has no executable in the published artifact, `AB8252` compiled CLI projection or event preflight preparation failed, `AB8253` a selected CLI command does not project onto the canonical operation id, `AB8254` a projected `cli:<command>` id was used instead of its canonical `tool:<server>/<tool>` id plus CLI surface, and `AB8255` an event route with compiled preflight was submitted without a concrete host surface. Rebuild the project for `AB8250`/`AB8251`; fix the reported projection or preflight failure for `AB8252`; use the command or canonical operation named by `AB8253`/`AB8254`; select a generated host wrapper for `AB8255`. |
| `AB8110`–`AB8113` | Workbench standalone MCP Inspector routes (`/api/inspector/status`, `/api/inspector/launch`): `AB8110` invalid path, `AB8111` invalid request shape or query, `AB8112` the Inspector could not be launched (spawn failure, exit before publishing a URL, or the 30 s startup budget elapsed; 502), `AB8113` routes not available (404 when the launcher is not composed, 503 after shutdown). |
| `AB8120`–`AB8123` | Workbench route manifest (`/api/routes/manifest`): `AB8120` invalid path, `AB8121` not available (404/409/503), `AB8122` query string on the request, `AB8123` the browser client could not decode the response (see below). |
| `AB8024`–`AB8025` | Live host MCP proxy: epoch drift behind a host connection and dev-server unavailability (see below). |
Expand Down
32 changes: 21 additions & 11 deletions packages/agent-bundle/src/adapters/hook-contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,8 @@ const eventRouteHookWrapperSource = (
// their session; only projects whose state is workspace-durable have one.
const retiresLineage = standalone && durableLineage && route.event === 'session/end';
const projectBindings = [
...(standalone ? ['createCanonicalEventProps', 'projectEventDocument'] : []),
'createCanonicalEventProps',
...(standalone ? ['projectEventDocument'] : []),
'validateNativeEventEnvelope',
];
return [
Expand Down Expand Up @@ -706,6 +707,11 @@ const eventRouteHookWrapperSource = (
"const endpointId = `${artifactEpoch}:${dirname(dirname(resolve(process.argv[1])))}`;",
'',
'const fail = (message) => { throw new Error(`Agent Bundle event route error: ${message}`); };',
'export const prepareRouteInvocation = (nativeInput, signal) => {',
' const native = validateNativeEventEnvelope(nativeInput, { canonicalEvent, nativeEvent, target });',
' const props = createCanonicalEventProps(canonicalEvent, native, target, nativeEvent, capabilityRevision, signal);',
' return Object.freeze({ gate: "execute", native, props, runtime: runtimeMode });',
'};',
...(standalone
? [
// The wrapper lives in `hooks/`, so its code root is the parent
Expand Down Expand Up @@ -894,6 +900,19 @@ const eventRoutePreflightWrapperSource = (
`const timeoutMs = ${String(entry.hook.timeoutMs ?? 5_000)};`,
`const executor = fileURLToPath(new URL(/* webpackIgnore: true */ ${JSON.stringify(`./${executorFile}`)}, import.meta.url));`,
'const fail = (message) => { throw new Error(`Agent Bundle event route error: ${message}`); };',
'export const prepareRouteInvocation = async (nativeInput, signal, observer) => {',
' const native = validateNativeEventEnvelope(nativeInput, { canonicalEvent, nativeEvent, target });',
' const props = createCanonicalEventProps(canonicalEvent, native, target, nativeEvent, capabilityRevision, signal);',
' const trace = createEventTracer({ execution: eventTraceExecution({ event: canonicalEvent, host: target, nativeEvent }), ...(observer === undefined ? {} : { observer }) });',
' const gate = await executeEventPreflight(preflight, {',
' canonical: props.canonical,',
' host: { name: target, nativeEvent },',
' signal,',
' terminal: { hostSurface: "hook", sharesTarget: false, stderr: { color: "none", kind: "none" }, stdout: { color: "none", kind: "none" } },',
' }, trace);',
' const projected = gate === "execute" ? undefined : projectEventPreflightResult(gate, canonicalEvent, target, nativeEvent, native);',
' return Object.freeze({ gate, native, projected, props, runtime: runtimeMode, trace });',
'};',
'const runExecutor = (input, signal) => new Promise((resolve, reject) => {',
' const child = spawn(process.execPath, [executor], { signal, stdio: ["pipe", "pipe", "pipe"] });',
' const stdout = [];',
Expand Down Expand Up @@ -921,19 +940,10 @@ const eventRoutePreflightWrapperSource = (
' const input = Buffer.concat(chunks);',
' let parsed;',
' try { parsed = JSON.parse(input.toString("utf8")); } catch { fail("stdin must contain exactly one JSON value"); }',
' const native = validateNativeEventEnvelope(parsed, { canonicalEvent, nativeEvent, target });',
' const controller = new AbortController();',
' const signal = AbortSignal.any([controller.signal, AbortSignal.timeout(timeoutMs)]);',
' const props = createCanonicalEventProps(canonicalEvent, native, target, nativeEvent, capabilityRevision, signal);',
' const trace = createEventTracer({ execution: eventTraceExecution({ event: canonicalEvent, host: target, nativeEvent }) });',
' const gate = await executeEventPreflight(preflight, {',
' canonical: props.canonical,',
' host: { name: target, nativeEvent },',
' signal,',
' terminal: { hostSurface: "hook", sharesTarget: false, stderr: { color: "none", kind: "none" }, stdout: { color: "none", kind: "none" } },',
' }, trace);',
' const { gate, native, projected, props, trace } = await prepareRouteInvocation(parsed, signal);',
' if (gate !== "execute") {',
' const projected = projectEventPreflightResult(gate, canonicalEvent, target, nativeEvent, native);',
' if (projected !== undefined) process.stdout.write(JSON.stringify(projected));',
' return;',
' }',
Expand Down
Loading
Loading