Skip to content

Pi sessions: extensions can carry files kept beside Pi's session files - #262

Open
vitalNohj wants to merge 3 commits into
TannerMidd:release/0.28.0from
vitalNohj:feat/pi-session-companions
Open

vitalNohj wants to merge 3 commits into
TannerMidd:release/0.28.0from
vitalNohj:feat/pi-session-companions

Conversation

@vitalNohj

Copy link
Copy Markdown
Contributor

Built on #261. Review that one first; this PR adds two commits on top.

What

Some Pi extensions keep a file of their own next to a Pi session file, for example <session>.jsonl.notes.md or a state file for that session. When a person continues the session in Pocket, those files need to come along with the conversion. Today the copy gets the conversation and the extension's file is left behind. Only the extension knows what its file means and how to use it in the copy.

This adds one experimental extension point, host.registerPiSessionCompanion. An extension names a suffix. Pocket then:

  1. finds <session>.jsonl<suffix> beside the session file and lists it in the preview ("Includes: …");
  2. after writing the copy, calls the extension with the file's path and the copy's context, each message tagged with the Pi entry it came from;
  3. shows what the extension returns, or the error it throws, in the "Continued from Pi" notice.

Pocket never reads, copies or changes the file. It only knows the extension's suffix and label.

const stop = host.registerPiSessionCompanion({
    suffix: ".notes.md",
    label: "Notes",
    continued: async ({ conversationId, piFile, companion, entries }) => {
        // entries: [{ id, from?, message }] for the copy's context,
        // `from` = the Pi entry id the message came from
        return "Brought Pi's notes along."; // shown to the person
    },
});
web.onDispose(stop);

Why core (C16)

  • C5: finding a file beside the session, timing the call after the copy, and showing the result are the same for every extension. Only the core can do them at the right moment, after the copy is written but before the person sees it.
  • C7: the mechanism is in core, and what a file means is in the extension. Pocket knows nothing about any specific file format.
  • C15: the extension point comes with a user: a tested example, docs/examples/pi-notes.ts.
  • C17: the core change and the example are separate commits.

How

  • Validation. PiSessions.registerCompanion checks the suffix with /^\.[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/, so a suffix can't contain / or .. and can't reach outside the session's folder. It returns a function that removes the registration.
  • The preview checks which suffixes have a file (stat, regular files only) and returns their labels as companions.
  • Mapping messages back to Pi. writePiSession now returns which written entry came from which Pi entry. After the commit, continuePiSession builds the copy's context view and calls each companion in turn. Each call has a 60 s limit.
  • Failures don't block the copy. A throw or timeout becomes ": " in the notes, and is also written to the server log. The copy is already written by then.
  • Response. continuePiSession returns { id, notes? }, and the sheet adds the notes to its "Continued from Pi" notice.
  • Types and docs. Host.registerPiSessionCompanion, PiSessionCompanion and PiSessionContinued are in types/pocket.d.ts with @since 0.28.0 @experimental. They have a reference entry, a row in the API versions table, a guide (docs/extensions/pi-session-companions.md), and a sentence in docs/features.md.

Example (separate commit)

docs/examples/pi-notes.ts brings <session>.jsonl.notes.md along. It copies the notes into its own folder and shows them in that session's system prompt, quoted with host.text.defang. It checks that host.registerPiSessionCompanion exists, so it still loads on an older Pocket.

Tests

  • test/pi-sessions.test.ts, an extension's file beside Pi's session comes along, uses three companions: one that works, one that throws, and one whose file is missing. It checks that:
    • an invalid suffix is rejected;
    • the preview lists only the two with files;
    • the notes have the working one's text and the throwing one's error;
    • the companion with no file is never called;
    • the entries' messages equal the copy's real context;
    • every from is a real Pi entry id;
    • the file is unchanged;
    • the labels are gone after removing the registration.
  • test/docs-examples.test.ts has a new test for the Pi notes example, end to end, and adds the example to the drop-in list.
  • The related suites (pi-sessions, docs-examples, model-providers, extension*, docs, public-links) pass, 105 tests. node test/types-file.ts and node docs-site/check-reference.mjs pass, and so does ESLint.

Use cases

  • Notes or memory an extension keeps per session (the example).
  • State an extension keeps per session that refers to Pi's entry ids. entries gives each copied message with the Pi entry it came from, so the extension can translate its ids to the copy's.

@vitalNohj
vitalNohj force-pushed the feat/pi-session-companions branch from dc9ed14 to 18e504c Compare November 3, 2026 12:46
@vitalNohj

Copy link
Copy Markdown
Contributor Author

Rebased onto release/0.28.0 at 0.28.0-beta.6 (0457d2f3). No conflicts.

Tests on beta.6: tsc, node test/types-file.ts, node docs-site/check-reference.mjs, and ESLint pass. 113 tests across pi-sessions, docs-examples, model-providers, docs, public-links, and extension* pass.

Real-world check. I used a separate Pi Pocket instance built from this branch, with an extension that registers a companion. It ran on a real 42 MB, 5,644-message Pi session that has a companion file beside it.

  • The preview listed the companion ("Includes: …").
  • Continue took 8.5 s, and the notice showed the extension's returned text.
  • The extension got the copy's context with each message's Pi entry ID. It used them to translate its own state.
  • In the new session, the agent could use that state.

@vitalNohj
vitalNohj marked this pull request as ready for review November 3, 2026 12:46
…ession-companions

# Conflicts:
#	src/server/pi-sessions.ts

This branch has not been deployed

No deployments
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