Repository navigation
feat: add the execution-observer foundation - #12
Conversation
Greptile SummaryThis PR introduces the execution-observer foundation: a typed lifecycle event stream (
Confidence Score: 5/5Safe to merge — the observer is fully opt-in, every event is emitted under error isolation, and all existing execution paths are unaffected when no plugin registers an observer. The new lifecycle stream is additive and behaviour-neutral: the no-op default means zero runtime change for current hosts. Both the inline and pausable paths correctly pair every Started event with a Finished counterpart — including on the interrupt/failure path via tapCause. The only finding is a test assertion that works today but relies on an implicit assumption about Effect's synchronous scheduler ordering. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant C as Caller
participant E as Engine (startPausableExecution)
participant O as ExecutionObserver(s)
participant F as Daemon Fiber
C->>E: "executeWithPause(code, {trigger})"
E->>O: "ExecutionStarted {executionId, owner, trigger}"
E->>F: forkDetach(codeExecutor.execute)
E->>E: awaitCompletionOrPause (race Fiber.join vs Queue.take)
alt No elicitation (completes directly)
F->>O: "ToolCallStarted {executionId, toolCallId, path}"
F->>O: "ToolCallFinished {executionId, toolCallId, status}"
F->>O: "ExecutionFinished {executionId, status: completed}"
F-->>E: Fiber.join resolves
E-->>C: "{status: completed}"
else Elicitation required (pause path)
F->>O: "InteractionStarted {executionId, interactionId}"
F->>E: Queue.offer(paused)
E-->>C: "{status: paused, execution}"
Note over F: Fiber blocked on Deferred.await
C->>E: resume(pauseId, response)
E->>F: Deferred.succeed(response)
F->>O: "InteractionResolved {status: accepted/declined/cancelled}"
Note over F,O: tapCause also emits InteractionResolved on interrupt/failure
F->>O: "ExecutionFinished {executionId, status}"
F-->>E: Fiber.join resolves
E-->>C: "{status: completed}"
end
Reviews (3): Last reviewed commit: "fix(execution): parallelize observer fan..." | Re-trigger Greptile |
… hook The pull-model execution lifecycle stream the engine emits: six tagged events (ExecutionStarted/Finished, ToolCallStarted/Finished, InteractionStarted/ Resolved), the ExecutionObserver interface, and composeExecutionObservers which fans each event to every plugin's runtime.executionObserver with per-observer error suppression. Events carry owner: OwnerBinding (tenant + subject) since the v2 restructure removed ScopeId. Adds the optional PluginSpec.runtime hook.
…n span createExecutionEngine takes an optional observer and emits the six ExecutionEvents around a run: ExecutionStarted (with trigger), tool calls bracketed via an invoker wrapper, elicitations via InteractionStarted/Resolved on both the inline and pause/resume paths, and ExecutionFinished on the forked fiber. The observer defaults to no-op, so hosts that register none are unaffected. Each run mints its own ExecutionId, distinct from the per-pause resume handle. execute/executeWithPause gain a trigger option, and the mcp.execute span is annotated with the run id + trigger so traces correlate to a run. Exposes Executor.owner so events can attribute work without re-threading identity.
The shared (user, org) -> { executor, engine } factory composes every
registered plugin's runtime.executionObserver and passes it to the engine.
Cloud, self-host, host-cloudflare and the MCP Durable Objects all build through
this factory, so one seam wires the observer for every HTTP and DO path. No
plugin observing = no-op.
Local's fixed-execution seam and in-process MCP handler build the engine directly rather than through makeExecutionStack, so compose the observer at both. Other hosts inherit it from the shared factory.
08a80c1 to
11d40f4
Compare
…events on interrupt Addresses Greptile review on #12: - composeExecutionObservers fans events to observers with concurrency: unbounded, so a slow sink (DB-backed history) no longer serializes behind another (metrics push). Per-observer error isolation is unchanged. - The pausable elicitation path now emits InteractionResolved on the failure/interrupt branch too (via tapCause), so a fiber killed while blocked on the response Deferred still pairs its InteractionStarted — matching the inline path.
Adds **`@executor-js/plugin-execution-history`** — an opt-in execution-history sink built on the observer foundation. - Records every run (plus its tool calls and interactions) into three owner-scoped `pluginStorage` collections via a buffered-batch writer — **no new tables, no migrations**; works on D1/libSQL/sqlite/postgres. - `./api`: a scoped read API (`list`/`get`/`listToolCalls`) over HttpApi (`executionHistoryHttpPlugin`). - `./client`: a Runs page at `/plugins/executionHistory/` (table, status filter, pagination, 4-tab detail drawer) — mounts via the existing plugins catch-all with zero router changes. The base `.` entry never loads the API or React layers. Fully opt-in (not registered in any default config). Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, unit + handler tests green. Runs-page live render still to verify. <!-- stack:links:start --> ### [Stack](https://github.com/kitlangton/stack) 1. #12 2. **#13** 👈 current 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-metrics`** — an opt-in metrics sink built on the observer foundation. - Base plugin drives Effect Metric counters + an execution-duration histogram from the event stream. - `./api`: an auth-gated `GET /execution-metrics/metrics` Prometheus scrape (`executionMetricsHttpPlugin`). - `./cloudflare`: a Workers Analytics Engine sink (`writeDataPoint`) — per-isolate Effect metrics being meaningless on a Worker fleet. Wired opt-in on host-cloudflare, gated on the `ANALYTICS` binding. Base `.` entry free of `@executor-js/api` and `@cloudflare/workers-types`. Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and metrics-render tests green (an adversarial-verify pass caught + fixed a Prometheus histogram-bucket bug). <!-- stack:links:start --> ### [Stack](https://github.com/kitlangton/stack) 1. #12 2. #13 3. **#14** 👈 current <!-- stack:links:end -->
Adds the **execution-observer foundation** — the seam the history and metrics plugins build on. - New `ExecutionObserver` contract in the SDK: six tagged lifecycle events (`ExecutionStarted`/`Finished`, `ToolCallStarted`/`Finished`, `InteractionStarted`/`Resolved`) + `composeExecutionObservers`, with a `plugin.runtime.executionObserver` hook. - The execution engine emits the events (re-derived onto the current Queue-based pause model), exposes `Executor.owner`, and tags the run span with the execution id + trigger. - `makeExecutionStack` composes plugin observers — one seam covers every HTTP host and the MCP Durable Objects; local's fixed-execution + in-process MCP are wired directly. **Behaviour-neutral / opt-in:** with no plugin observing, every path is a no-op. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and observer unit tests all green. Live app verification still to come. <!-- stack:links:start --> 1. **#12** 👈 current 2. #13 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-history`** — an opt-in execution-history sink built on the observer foundation. - Records every run (plus its tool calls and interactions) into three owner-scoped `pluginStorage` collections via a buffered-batch writer — **no new tables, no migrations**; works on D1/libSQL/sqlite/postgres. - `./api`: a scoped read API (`list`/`get`/`listToolCalls`) over HttpApi (`executionHistoryHttpPlugin`). - `./client`: a Runs page at `/plugins/executionHistory/` (table, status filter, pagination, 4-tab detail drawer) — mounts via the existing plugins catch-all with zero router changes. The base `.` entry never loads the API or React layers. Fully opt-in (not registered in any default config). Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, unit + handler tests green. Runs-page live render still to verify. <!-- stack:links:start --> ### [Stack](https://github.com/kitlangton/stack) 1. #12 2. **#13** 👈 current 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-metrics`** — an opt-in metrics sink built on the observer foundation. - Base plugin drives Effect Metric counters + an execution-duration histogram from the event stream. - `./api`: an auth-gated `GET /execution-metrics/metrics` Prometheus scrape (`executionMetricsHttpPlugin`). - `./cloudflare`: a Workers Analytics Engine sink (`writeDataPoint`) — per-isolate Effect metrics being meaningless on a Worker fleet. Wired opt-in on host-cloudflare, gated on the `ANALYTICS` binding. Base `.` entry free of `@executor-js/api` and `@cloudflare/workers-types`. Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and metrics-render tests green (an adversarial-verify pass caught + fixed a Prometheus histogram-bucket bug). <!-- stack:links:start --> 1. #12 2. #13 3. **#14** 👈 current <!-- stack:links:end -->
Adds the **execution-observer foundation** — the seam the history and metrics plugins build on. - New `ExecutionObserver` contract in the SDK: six tagged lifecycle events (`ExecutionStarted`/`Finished`, `ToolCallStarted`/`Finished`, `InteractionStarted`/`Resolved`) + `composeExecutionObservers`, with a `plugin.runtime.executionObserver` hook. - The execution engine emits the events (re-derived onto the current Queue-based pause model), exposes `Executor.owner`, and tags the run span with the execution id + trigger. - `makeExecutionStack` composes plugin observers — one seam covers every HTTP host and the MCP Durable Objects; local's fixed-execution + in-process MCP are wired directly. **Behaviour-neutral / opt-in:** with no plugin observing, every path is a no-op. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and observer unit tests all green. Live app verification still to come. <!-- stack:links:start --> 1. **#12** 👈 current 2. #13 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-history`** — an opt-in execution-history sink built on the observer foundation. - Records every run (plus its tool calls and interactions) into three owner-scoped `pluginStorage` collections via a buffered-batch writer — **no new tables, no migrations**; works on D1/libSQL/sqlite/postgres. - `./api`: a scoped read API (`list`/`get`/`listToolCalls`) over HttpApi (`executionHistoryHttpPlugin`). - `./client`: a Runs page at `/plugins/executionHistory/` (table, status filter, pagination, 4-tab detail drawer) — mounts via the existing plugins catch-all with zero router changes. The base `.` entry never loads the API or React layers. Fully opt-in (not registered in any default config). Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, unit + handler tests green. Runs-page live render still to verify. <!-- stack:links:start --> ### [Stack](https://github.com/kitlangton/stack) 1. #12 2. **#13** 👈 current 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-metrics`** — an opt-in metrics sink built on the observer foundation. - Base plugin drives Effect Metric counters + an execution-duration histogram from the event stream. - `./api`: an auth-gated `GET /execution-metrics/metrics` Prometheus scrape (`executionMetricsHttpPlugin`). - `./cloudflare`: a Workers Analytics Engine sink (`writeDataPoint`) — per-isolate Effect metrics being meaningless on a Worker fleet. Wired opt-in on host-cloudflare, gated on the `ANALYTICS` binding. Base `.` entry free of `@executor-js/api` and `@cloudflare/workers-types`. Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and metrics-render tests green (an adversarial-verify pass caught + fixed a Prometheus histogram-bucket bug). <!-- stack:links:start --> 1. #12 2. #13 3. **#14** 👈 current <!-- stack:links:end -->
Adds the **execution-observer foundation** — the seam the history and metrics plugins build on. - New `ExecutionObserver` contract in the SDK: six tagged lifecycle events (`ExecutionStarted`/`Finished`, `ToolCallStarted`/`Finished`, `InteractionStarted`/`Resolved`) + `composeExecutionObservers`, with a `plugin.runtime.executionObserver` hook. - The execution engine emits the events (re-derived onto the current Queue-based pause model), exposes `Executor.owner`, and tags the run span with the execution id + trigger. - `makeExecutionStack` composes plugin observers — one seam covers every HTTP host and the MCP Durable Objects; local's fixed-execution + in-process MCP are wired directly. **Behaviour-neutral / opt-in:** with no plugin observing, every path is a no-op. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and observer unit tests all green. Live app verification still to come. <!-- stack:links:start --> 1. **#12** 👈 current 2. #13 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-history`** — an opt-in execution-history sink built on the observer foundation. - Records every run (plus its tool calls and interactions) into three owner-scoped `pluginStorage` collections via a buffered-batch writer — **no new tables, no migrations**; works on D1/libSQL/sqlite/postgres. - `./api`: a scoped read API (`list`/`get`/`listToolCalls`) over HttpApi (`executionHistoryHttpPlugin`). - `./client`: a Runs page at `/plugins/executionHistory/` (table, status filter, pagination, 4-tab detail drawer) — mounts via the existing plugins catch-all with zero router changes. The base `.` entry never loads the API or React layers. Fully opt-in (not registered in any default config). Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, unit + handler tests green. Runs-page live render still to verify. <!-- stack:links:start --> ### [Stack](https://github.com/kitlangton/stack) 1. #12 2. **#13** 👈 current 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-metrics`** — an opt-in metrics sink built on the observer foundation. - Base plugin drives Effect Metric counters + an execution-duration histogram from the event stream. - `./api`: an auth-gated `GET /execution-metrics/metrics` Prometheus scrape (`executionMetricsHttpPlugin`). - `./cloudflare`: a Workers Analytics Engine sink (`writeDataPoint`) — per-isolate Effect metrics being meaningless on a Worker fleet. Wired opt-in on host-cloudflare, gated on the `ANALYTICS` binding. Base `.` entry free of `@executor-js/api` and `@cloudflare/workers-types`. Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and metrics-render tests green (an adversarial-verify pass caught + fixed a Prometheus histogram-bucket bug). <!-- stack:links:start --> 1. #12 2. #13 3. **#14** 👈 current <!-- stack:links:end -->
Adds the **execution-observer foundation** — the seam the history and metrics plugins build on. - New `ExecutionObserver` contract in the SDK: six tagged lifecycle events (`ExecutionStarted`/`Finished`, `ToolCallStarted`/`Finished`, `InteractionStarted`/`Resolved`) + `composeExecutionObservers`, with a `plugin.runtime.executionObserver` hook. - The execution engine emits the events (re-derived onto the current Queue-based pause model), exposes `Executor.owner`, and tags the run span with the execution id + trigger. - `makeExecutionStack` composes plugin observers — one seam covers every HTTP host and the MCP Durable Objects; local's fixed-execution + in-process MCP are wired directly. **Behaviour-neutral / opt-in:** with no plugin observing, every path is a no-op. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and observer unit tests all green. Live app verification still to come. <!-- stack:links:start --> 1. **#12** 👈 current 2. #13 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-history`** — an opt-in execution-history sink built on the observer foundation. - Records every run (plus its tool calls and interactions) into three owner-scoped `pluginStorage` collections via a buffered-batch writer — **no new tables, no migrations**; works on D1/libSQL/sqlite/postgres. - `./api`: a scoped read API (`list`/`get`/`listToolCalls`) over HttpApi (`executionHistoryHttpPlugin`). - `./client`: a Runs page at `/plugins/executionHistory/` (table, status filter, pagination, 4-tab detail drawer) — mounts via the existing plugins catch-all with zero router changes. The base `.` entry never loads the API or React layers. Fully opt-in (not registered in any default config). Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, unit + handler tests green. Runs-page live render still to verify. <!-- stack:links:start --> 1. #12 2. **#13** 👈 current 3. #14 <!-- stack:links:end -->
Adds the **execution-observer foundation** — the seam the history and metrics plugins build on. - New `ExecutionObserver` contract in the SDK: six tagged lifecycle events (`ExecutionStarted`/`Finished`, `ToolCallStarted`/`Finished`, `InteractionStarted`/`Resolved`) + `composeExecutionObservers`, with a `plugin.runtime.executionObserver` hook. - The execution engine emits the events (re-derived onto the current Queue-based pause model), exposes `Executor.owner`, and tags the run span with the execution id + trigger. - `makeExecutionStack` composes plugin observers — one seam covers every HTTP host and the MCP Durable Objects; local's fixed-execution + in-process MCP are wired directly. **Behaviour-neutral / opt-in:** with no plugin observing, every path is a no-op. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and observer unit tests all green. Live app verification still to come. <!-- stack:links:start --> 1. **#12** 👈 current 2. #13 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-history`** — an opt-in execution-history sink built on the observer foundation. - Records every run (plus its tool calls and interactions) into three owner-scoped `pluginStorage` collections via a buffered-batch writer — **no new tables, no migrations**; works on D1/libSQL/sqlite/postgres. - `./api`: a scoped read API (`list`/`get`/`listToolCalls`) over HttpApi (`executionHistoryHttpPlugin`). - `./client`: a Runs page at `/plugins/executionHistory/` (table, status filter, pagination, 4-tab detail drawer) — mounts via the existing plugins catch-all with zero router changes. The base `.` entry never loads the API or React layers. Fully opt-in (not registered in any default config). Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, unit + handler tests green. Runs-page live render still to verify. <!-- stack:links:start --> 1. #12 2. **#13** 👈 current 3. #14 <!-- stack:links:end -->
Adds the **execution-observer foundation** — the seam the history and metrics plugins build on. - New `ExecutionObserver` contract in the SDK: six tagged lifecycle events (`ExecutionStarted`/`Finished`, `ToolCallStarted`/`Finished`, `InteractionStarted`/`Resolved`) + `composeExecutionObservers`, with a `plugin.runtime.executionObserver` hook. - The execution engine emits the events (re-derived onto the current Queue-based pause model), exposes `Executor.owner`, and tags the run span with the execution id + trigger. - `makeExecutionStack` composes plugin observers — one seam covers every HTTP host and the MCP Durable Objects; local's fixed-execution + in-process MCP are wired directly. **Behaviour-neutral / opt-in:** with no plugin observing, every path is a no-op. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and observer unit tests all green. Live app verification still to come. <!-- stack:links:start --> 1. **#12** 👈 current 2. #13 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-history`** — an opt-in execution-history sink built on the observer foundation. - Records every run (plus its tool calls and interactions) into three owner-scoped `pluginStorage` collections via a buffered-batch writer — **no new tables, no migrations**; works on D1/libSQL/sqlite/postgres. - `./api`: a scoped read API (`list`/`get`/`listToolCalls`) over HttpApi (`executionHistoryHttpPlugin`). - `./client`: a Runs page at `/plugins/executionHistory/` (table, status filter, pagination, 4-tab detail drawer) — mounts via the existing plugins catch-all with zero router changes. The base `.` entry never loads the API or React layers. Fully opt-in (not registered in any default config). Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, unit + handler tests green. Runs-page live render still to verify. <!-- stack:links:start --> 1. #12 2. **#13** 👈 current 3. #14 <!-- stack:links:end -->
Adds the **execution-observer foundation** — the seam the history and metrics plugins build on. - New `ExecutionObserver` contract in the SDK: six tagged lifecycle events (`ExecutionStarted`/`Finished`, `ToolCallStarted`/`Finished`, `InteractionStarted`/`Resolved`) + `composeExecutionObservers`, with a `plugin.runtime.executionObserver` hook. - The execution engine emits the events (re-derived onto the current Queue-based pause model), exposes `Executor.owner`, and tags the run span with the execution id + trigger. - `makeExecutionStack` composes plugin observers — one seam covers every HTTP host and the MCP Durable Objects; local's fixed-execution + in-process MCP are wired directly. **Behaviour-neutral / opt-in:** with no plugin observing, every path is a no-op. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and observer unit tests all green. Live app verification still to come. <!-- stack:links:start --> 1. **#12** 👈 current 2. #13 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-history`** — an opt-in execution-history sink built on the observer foundation. - Records every run (plus its tool calls and interactions) into three owner-scoped `pluginStorage` collections via a buffered-batch writer — **no new tables, no migrations**; works on D1/libSQL/sqlite/postgres. - `./api`: a scoped read API (`list`/`get`/`listToolCalls`) over HttpApi (`executionHistoryHttpPlugin`). - `./client`: a Runs page at `/plugins/executionHistory/` (table, status filter, pagination, 4-tab detail drawer) — mounts via the existing plugins catch-all with zero router changes. The base `.` entry never loads the API or React layers. Fully opt-in (not registered in any default config). Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, unit + handler tests green. Runs-page live render still to verify. <!-- stack:links:start --> 1. #12 2. **#13** 👈 current 3. #14 <!-- stack:links:end -->
Adds the **execution-observer foundation** — the seam the history and metrics plugins build on. - New `ExecutionObserver` contract in the SDK: six tagged lifecycle events (`ExecutionStarted`/`Finished`, `ToolCallStarted`/`Finished`, `InteractionStarted`/`Resolved`) + `composeExecutionObservers`, with a `plugin.runtime.executionObserver` hook. - The execution engine emits the events (re-derived onto the current Queue-based pause model), exposes `Executor.owner`, and tags the run span with the execution id + trigger. - `makeExecutionStack` composes plugin observers — one seam covers every HTTP host and the MCP Durable Objects; local's fixed-execution + in-process MCP are wired directly. **Behaviour-neutral / opt-in:** with no plugin observing, every path is a no-op. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and observer unit tests all green. Live app verification still to come. <!-- stack:links:start --> 1. **#12** 👈 current 2. #13 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-history`** — an opt-in execution-history sink built on the observer foundation. - Records every run (plus its tool calls and interactions) into three owner-scoped `pluginStorage` collections via a buffered-batch writer — **no new tables, no migrations**; works on D1/libSQL/sqlite/postgres. - `./api`: a scoped read API (`list`/`get`/`listToolCalls`) over HttpApi (`executionHistoryHttpPlugin`). - `./client`: a Runs page at `/plugins/executionHistory/` (table, status filter, pagination, 4-tab detail drawer) — mounts via the existing plugins catch-all with zero router changes. The base `.` entry never loads the API or React layers. Fully opt-in (not registered in any default config). Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, unit + handler tests green. Runs-page live render still to verify. <!-- stack:links:start --> 1. #12 2. **#13** 👈 current 3. #14 <!-- stack:links:end -->
Adds the **execution-observer foundation** — the seam the history and metrics plugins build on. - New `ExecutionObserver` contract in the SDK: six tagged lifecycle events (`ExecutionStarted`/`Finished`, `ToolCallStarted`/`Finished`, `InteractionStarted`/`Resolved`) + `composeExecutionObservers`, with a `plugin.runtime.executionObserver` hook. - The execution engine emits the events (re-derived onto the current Queue-based pause model), exposes `Executor.owner`, and tags the run span with the execution id + trigger. - `makeExecutionStack` composes plugin observers — one seam covers every HTTP host and the MCP Durable Objects; local's fixed-execution + in-process MCP are wired directly. **Behaviour-neutral / opt-in:** with no plugin observing, every path is a no-op. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and observer unit tests all green. Live app verification still to come. <!-- stack:links:start --> 1. **#12** 👈 current 2. #13 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-history`** — an opt-in execution-history sink built on the observer foundation. - Records every run (plus its tool calls and interactions) into three owner-scoped `pluginStorage` collections via a buffered-batch writer — **no new tables, no migrations**; works on D1/libSQL/sqlite/postgres. - `./api`: a scoped read API (`list`/`get`/`listToolCalls`) over HttpApi (`executionHistoryHttpPlugin`). - `./client`: a Runs page at `/plugins/executionHistory/` (table, status filter, pagination, 4-tab detail drawer) — mounts via the existing plugins catch-all with zero router changes. The base `.` entry never loads the API or React layers. Fully opt-in (not registered in any default config). Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, unit + handler tests green. Runs-page live render still to verify. <!-- stack:links:start --> 1. #12 2. **#13** 👈 current 3. #14 <!-- stack:links:end -->
Adds the **execution-observer foundation** — the seam the history and metrics plugins build on. - New `ExecutionObserver` contract in the SDK: six tagged lifecycle events (`ExecutionStarted`/`Finished`, `ToolCallStarted`/`Finished`, `InteractionStarted`/`Resolved`) + `composeExecutionObservers`, with a `plugin.runtime.executionObserver` hook. - The execution engine emits the events (re-derived onto the current Queue-based pause model), exposes `Executor.owner`, and tags the run span with the execution id + trigger. - `makeExecutionStack` composes plugin observers — one seam covers every HTTP host and the MCP Durable Objects; local's fixed-execution + in-process MCP are wired directly. **Behaviour-neutral / opt-in:** with no plugin observing, every path is a no-op. Gates: `format:check`, `lint`, full-monorepo `typecheck`, and observer unit tests all green. Live app verification still to come. <!-- stack:links:start --> 1. **#12** 👈 current 2. #13 3. #14 <!-- stack:links:end -->
Adds **`@executor-js/plugin-execution-history`** — an opt-in execution-history sink built on the observer foundation. - Records every run (plus its tool calls and interactions) into three owner-scoped `pluginStorage` collections via a buffered-batch writer — **no new tables, no migrations**; works on D1/libSQL/sqlite/postgres. - `./api`: a scoped read API (`list`/`get`/`listToolCalls`) over HttpApi (`executionHistoryHttpPlugin`). - `./client`: a Runs page at `/plugins/executionHistory/` (table, status filter, pagination, 4-tab detail drawer) — mounts via the existing plugins catch-all with zero router changes. The base `.` entry never loads the API or React layers. Fully opt-in (not registered in any default config). Stacked on the execution-observer foundation. Gates: `format:check`, `lint`, full-monorepo `typecheck`, unit + handler tests green. Runs-page live render still to verify. <!-- stack:links:start --> 1. #12 2. **#13** 👈 current 3. #14 <!-- stack:links:end -->
Adds the execution-observer foundation — the seam the history and metrics plugins build on.
ExecutionObservercontract in the SDK: six tagged lifecycle events (ExecutionStarted/Finished,ToolCallStarted/Finished,InteractionStarted/Resolved) +composeExecutionObservers, with aplugin.runtime.executionObserverhook.Executor.owner, and tags the run span with the execution id + trigger.makeExecutionStackcomposes plugin observers — one seam covers every HTTP host and the MCP Durable Objects; local's fixed-execution + in-process MCP are wired directly.Behaviour-neutral / opt-in: with no plugin observing, every path is a no-op.
Gates:
format:check,lint, full-monorepotypecheck, and observer unit tests all green. Live app verification still to come.Stack