Skip to content

feat(pi-ext-run-log): @agentic-kit/pi-ext-run-log — mirror pi session entries into the run log - #1724

Merged
pyramation merged 2 commits into
mainfrom
feat/pi-ext-run-log
Aug 14, 2026
Merged

feat(pi-ext-run-log): @agentic-kit/pi-ext-run-log — mirror pi session entries into the run log#1724
pyramation merged 2 commits into
mainfrom
feat/pi-ext-run-log

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Summary

Package 2 of the agentic-kit series (issue #1657): the write side of the run log for a pi session. @agentic-kit/run-log (#1723) defines the record + store contract; this package is the pi extension that fills it. Same code in both placements — local Desktop session and a long-running cloud job — only runId and the store differ, which is what makes a run observable from anywhere without a second transcript format.

Stacked on feat/agentic-run-log, so until #1723 merges this diff also shows agentic/run-log.

Why draining, not an event

pi owns its session (an append-only entry tree, persisted as JSONL) and exposes no "entry appended" event. So SessionMirror drains: after each event that could have appended, it takes the entries past its read index and appends them verbatim.

// after every mirrored event
mirror.bind(ctx.sessionManager);
await mirror.drain();      // header once, then entries[consumed..]

Index-based reading is sound precisely because the session is append-only — entries are never rewritten or removed, only branched from.

The load-bearing invariants (each has a test):

  • advance-after-appendconsumed/headerMirrored move only once store.append resolves, so a failed drain is retried whole and leaves no hole.
  • serialized drains — every drain chains off this.tail, so concurrent events cannot interleave batches and break run-log ordering.
  • session identity, not object identity — the read position is keyed to the session header's id, so a switch/fork/new-session re-mirrors from the start and the store's idempotency (pi entry ids) discards the carried-over entries. The same property makes resume free: a restarted host re-appends its history and writes nothing new.
  • verbatim — entry types this package has never heard of round-trip unchanged (expect(record.entry).toEqual(exotic)).

Failure policy

A store failure is rethrown into pi's event dispatch by default — a run log that silently stops recording is worse than a loud one, so losing entries is never the default. onError lets a host trade that for survival.

SessionMirror deliberately knows nothing about pi's extension API (it takes { getHeader, getEntries }), so mirroring is tested against a fake session and the extension test drives the registered handlers with a fake ExtensionAPI — no agent process in the unit tests.

Verification

  • pnpm test in the package: 15 tests, 2 suites green (header-once/ordering, verbatim, unbound no-op, concurrent drains, retry-after-failure, session switch, idempotent resume, malformed entry, version passthrough, event registration, onError, flush)
  • pnpm build (makage, CJS+ESM) and pnpm lint clean
  • pnpm install --frozen-lockfile passes with the hand-added importer (no lockfile churn)
  • added to the agentic batch in .github/workflows/run-tests.yaml

Link to Devin session: https://app.devin.ai/sessions/450ce6d6659c47759c184ae6ec19a2a8
Requested by: @pyramation

A pi extension that drains pi's append-only session into an
@agentic-kit/run-log store — verbatim, in order, same code locally and in
the cloud (only runId and the store differ).

Draining is index-based because the session is append-only; the read
position is keyed to the session header id so a switch/fork re-mirrors and
the store's idempotency absorbs the duplicates. A drain advances only after
a successful append, and store failures are rethrown into pi's dispatch by
default rather than silently dropping entries.
@pyramation pyramation self-assigned this Aug 14, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant