Skip to content

feat: upgrade pi to 1.1.0, gate session reloads and teardown, import the login env - #689

Merged
danyaberezun merged 2 commits into
mainfrom
mcp-stack/1-pi-lifecycle
Oct 11, 2026
Merged

danyaberezun merged 2 commits into
mainfrom
mcp-stack/1-pi-lifecycle

Conversation

@danyaberezun

@danyaberezun danyaberezun commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

ThinkRail embeds pi 1.0.2. MCP support, which the PRs stacked on this one add, runs on pi's built-in MCP
engine and needs pi 1.1.0, which adds:

Two things break on the way:

  • Renamed provider. pi 1.0.3 renamed the Azure provider from azure-openai-responses to azure. A
    chat saved under the old id no longer reopens ("The chat's saved model is unavailable").
  • API changes in tests. pi's BuildSystemPromptOptions gained hiddenTools, and agent_settled
    gained aborted.

Before anything in ThinkRail keeps long-lived resources per chat, such as an MCP server process, four
gaps in how the host drives a session need closing:

  • No session_shutdown on teardown. AgentSession.dispose() never emits session_shutdown, so
    extensions never get to close what they hold when a chat is deleted, its workspace is removed, or the
    host quits.
  • Reloads ran at unsafe moments. reloadSessionResources refused only while streaming. A reload
    could still land:
    • between admitting a prompt and its run starting, while pi still reports idle;
    • during a compaction;
    • while a removed queued message was being requeued.
  • The exclusion set never refreshed. The excluding loader resolved its extension set once at
    construction, so a reload never picked up changed settings or packages.
  • Missing login environment. A host launched from the Dock/Finder repairs PATH from the login
    shell, but imports nothing else from it. A ${VAR} reference that pi resolves then reads empty.

Approach

  • pi 1.1.0. The whole family moves from 1.0.2 to 1.1.0.
    • Renamed provider. A persisted model whose provider pi renamed resolves under the new id
      (RENAMED_PI_PROVIDERS: azure-openai-responses → azure), and the provider-glyph key follows.
    • Test fixtures get hiddenTools and agent_settled.aborted.
  • session_shutdown on every teardown path.
    • When. The cascade emits it before dispose(), started synchronously so handlers are running
      before the synchronous teardown disposes the session.
    • Budget. It is bounded by 3 s (SESSION_SHUTDOWN_BUDGET_MS, also the host-quit budget), so a
      handler that never settles cannot hold teardown.
    • Dispose waits. dispose() runs only after that bounded emission settles, because it invalidates
      the runner the handlers are using.
    • Failed attach. A prepared entry whose workspace became unavailable before registration is now
      abandoned through the same cleanup instead of leaking (abandonPreparedEntry).
  • Reload gate.
    • Quiescent only. A reload runs only when the session is idle: not streaming, no admitted prompt
      still waiting for agent_start, no compaction, no queue requeue holding a reservation.
    • Deferred otherwise. A request that can't run now is deferred, coalesced into one reload, and
      reconsidered at settlement, preflight release and compaction end (requestSessionReload →
      reloaded | deferred).
    • Nothing in between. While a reload runs, nothing is admitted (prompt, steer, follow-up,
      question answer, review fix, compaction), and background-command and subagent completions wait.
  • Excluding loader. pi keeps a reference to the extension path array and reads it on every reload,
    so the host now rebuilds that array in place before each load. Built-in extensions are resolved by
    name and honour -builtin:*, as pi's own discovery does.
  • Login-shell environment. One probe, delimited by a marker (LOGIN_ENV_MARKER), feeds both the
    existing PATH repair and an import of the variables the host doesn't have.
    • Never overridden. Variables already set keep their values.
    • Never imported. PI_* / THINKRAIL_* and shell bookkeeping (PWD, SHLVL, …) never come from
      the shell.
    • Terminal launch. When TERM is set, the import is skipped.
    • E2E fixture. The fake login shell answers the marker probe with the hermetic PATH, so e2e hosts
      still never see the developer's environment.

Changes

  • pi family: package.json catalog and bun.lock at pi 1.1.0, plus the pi-thinkrail-workflow
    and pi-dag test fixtures.
  • packages/server/src/agent/agentSessionManager.ts:
    • the reload gate (requestSessionReload, preflight reservations, held reservations for queue
      requeues, admission at every run entry);
    • the bounded session_shutdown emission and deferred dispose;
    • abandonPreparedEntry;
    • RENAMED_PI_PROVIDERS.
  • packages/server/src/agent/extensions.ts: the excluding loader re-resolves on every reload
    (builtinExtensionNames, relabelDiscoveredExtensions; extraFactories are InlineExtensions).
  • packages/shared/src/shellEnv.ts: parseLoginShellEnv, loginShellImports,
    LOGIN_ENV_MARKER, and resolveShellEnv({ probe }). It builds on fix(shared): always adopt the login-shell PATH at host start #686's always-probe PATH repair.
  • New tests:
    • reloadGate.test.ts: immediate reload when idle; deferral while streaming and while a slash
      command is in preflight; a queued-message removal racing a pending reload; no admission during a
      reload.
    • sessionShutdown.test.ts: handlers are awaited; a hanging handler is bounded.
    • In piRuntime.test.ts: the re-resolve on every reload, including -builtin:*.
    • In runtimeGenerations.test.ts: the renamed-provider reattach.
    • shellEnv.test.ts: import rules, marker parsing, the TERM skip.
  • E2E: e2e/fixtures/executables.ts and e2e/SPEC.md (the marker-aware fake login shell).
  • Specs: packages/server/src/agent/SPEC.md (session lifecycle, reload gate, loader, renamed
    providers) and packages/shared/SPEC.md.

Notes for reviewers:

Screenshots

Not applicable: no visible frontend change. The only web change is the generated provider-glyph key for
pi's renamed Azure provider; the glyph is the same.

Related issues

No tracked issue. This is part of the MCP support stack (milestone 1); review and merge in order:

  1. feat: upgrade pi to 1.1.0, gate session reloads and teardown, import the login env #689 feat: upgrade pi to 1.1.0, gate session reloads and teardown, import the login env ← this PR
  2. feat: pass each project's trust to pi and name what trusting it loads #690 feat: pass each project's trust to pi and name what trusting it loads
  3. feat(server): run the MCP servers from mcp.json in chats on pi's built-in engine #691 feat(server): run the MCP servers from mcp.json in chats on pi's built-in engine
  4. feat(server): serve MCP server management, status and sign-in to clients #692 feat(server): serve MCP server management, status and sign-in to clients
  5. feat(web): track MCP status and list each chat's MCP servers in its resources #693 feat(web): track MCP status and list each chat's MCP servers in its resources
  6. feat: manage MCP servers in Settings #694 feat: manage MCP servers in Settings
  7. feat(web): render MCP tool calls, resources and tool_search as cards #695 feat(web): render MCP tool calls, resources and tool_search as cards

Base: main.

Testing

On this PR's tree:

  • bunx turbo run typecheck --filter='!@thinkrail/desktop' → 19/19
  • bun test packages/server packages/pi-delegation packages/pi-subagents packages/pi-background-commands packages/pi-todos packages/pi-dag packages/pi-thinkrail-workflow packages/contracts packages/shared packages/artifact-tests → 1900 pass, 10 skip, 0 fail
  • bun test packages/server/src/agent/reloadGate.test.ts packages/server/src/agent/sessionShutdown.test.ts packages/server/src/agent/runtimeGenerations.test.ts packages/server/src/agent/piRuntime.test.ts packages/shared, run twice → 103/103 both times
  • cd apps/web && bun test → 1574 pass
  • bun test ./scripts/ → 91 pass; bunx turbo run test --continue for every other package (desktop excluded) → 17/17 tasks
  • bun run lint → clean, no warnings; check:deps, check:boundaries, check:seams, check:spec-surface → OK
  • bun run e2e → all 8 shards passed (490 tests)
  • bun run build:binary && bun run smoke:binary → smoke OK

Focused live specs (real Central, bun run e2e:full <files>): queue, skills-reload, chat-resources, reopen-chat, subagents and agent → 9 passed. The complete bun run e2e:full suite was not run.

The complete bun run e2e:full suite ran on the top of the stack (#695), which contains this change: no-agent 8/8 shards; agent 53 passed, 2 failed — error-turn.live.spec.ts:35 and visualize.live.spec.ts:62, which fail on origin/main too.

Desktop: @thinkrail/desktop's typecheck could not run as configured on this machine. Its electrobun prepare step waits on a shared cache lock that another process holds. Run without prepare, cd apps/desktop && tsc --noEmit reports the same 18 electrobun-declaration errors (TS7016/TS7006/TS7031) as on origin/main and none from this change. Its bun test passes (123 pass, 1 skip, as on origin/main). This change touches no desktop file.

Checklist

  • Fast gates pass: bun run lint, bun run typecheck, bun run test
  • E2E suite passes for app-affecting changes (bun run e2e, or bun run e2e:full when touching agent behavior)
  • Before/after screenshots are included for frontend changes, or marked not applicable
  • Relevant SPEC.md / top-level specs updated to reflect any boundary, contract, or behavior change
  • I have read the Contributing guide and agree to the Code of Conduct

@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

🌐 Website preview

Preview retired when this pull request closed.

@danyaberezun
danyaberezun added this pull request to stack #696 October 9, 2026 07:52
@danyaberezun
danyaberezun marked this pull request as ready for review October 9, 2026 08:00

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes — please address the blocking inline finding.

Comment thread packages/server/src/agent/agentSessionManager.ts

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

…the login env

- pi 1.0.2 → 1.1.0; chats saved under pi's renamed Azure provider
  (azure-openai-responses → azure) reopen under the new id.
- Session teardown emits session_shutdown, bounded by a 3 s budget, and
  disposes the pi session only after the emission settles.
- Resource reloads run only when the session is quiescent; otherwise they
  are deferred, coalesced and reconsidered at settlement, preflight release
  and compaction end. Nothing is admitted while a reload runs.
- The excluding loader re-resolves its extension set on every reload,
  built-ins by name honouring -builtin:*.
- A GUI-launched host imports the login shell's environment alongside the
  PATH repair, never overriding what it has and never PI_* / THINKRAIL_*.
…es on every teardown path

disposeAllSessions, abandonPreparedEntry and the failed-creation cleanup
disposed the pi session right after starting the shutdown emission, which
invalidates the extension context the handlers were still using.
@danyaberezun
danyaberezun force-pushed the mcp-stack/1-pi-lifecycle branch from a1f48c6 to 476e40a Compare October 9, 2026 12:12
@danyaberezun

Copy link
Copy Markdown
Collaborator Author

Rebased the whole stack onto main @ 830de94 (#663 landed with protocol v78). The stack's protocol pins moved up: PROJECT_TRUST_PROTOCOL_VERSION 78 → 79 (#690) and MCP_PROTOCOL_VERSION 79 → 80 (#692), PROTOCOL_VERSION is 80 at the top. Verified on the stack top: lint, deps/boundaries/seams/spec-surface, typecheck, unit tests (web 1704, server-side 1787) and the complete bun run e2e (8/8 shards).

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved — ready to merge.

@danyaberezun
danyaberezun added this pull request to the merge queue Oct 11, 2026
Merged via the queue into main with commit ea08fbd Oct 11, 2026
19 checks passed
@danyaberezun
danyaberezun deleted the mcp-stack/1-pi-lifecycle branch October 11, 2026 07:13
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.

2 participants