Repository navigation
feat(harness-pi): pass the harness session to extension factories - #23100
Conversation
An `extensionFactories` entry received only Pi's `ExtensionAPI`, so an extension could not reach the sandbox the session runs against or the instructions the caller set for the turn. A Task-style tool that runs a child Pi session against the parent's sandbox with the parent's instructions had no way to get either. Each factory now gets a second argument, `PiHarnessExtensionSession`: the restricted sandbox session (the same view the builtin tools use), the session work directory, and an `instructions()` getter. Instructions arrive per turn and the factory runs before the first turn, so a getter over the session's current instructions is the only shape that stays correct. A second argument keeps every existing `(pi) => void` factory assignable; the session wraps each factory in a one-line adapter before handing the list to Pi's resource loader.
Feature reviewOutcome: changes-required Implements featureStatus: partially-implements The implementation correctly passes a restricted sandbox session, sessionWorkDir, and live instructions() getter to factories, but the required user-facing documentation is incomplete. Concerns:
Side effectsRisk: low Caller factories are wrapped once per harness session before being passed to Pi; existing extension lifecycle and resource-reload behavior remains unchanged. Concerns: none. PerformanceRisk: low The change adds one small adapter closure per configured factory and an O(1) instructions getter, with no material per-turn resource cost. Concerns: none. Backwards compatibilityRisk: low Existing one-argument ExtensionFactory values remain structurally assignable, are exercised by runtime and type tests, and retain their previous invocation behavior. Concerns: none. Breaking changesRisk: none The public setting is broadened to session-aware factories without removing exports, narrowing accepted inputs, changing defaults, or altering persisted formats; existing factories still compile and run. Concerns: none. ArchitectureRisk: low The public session abstraction remains owned by @ai-sdk/harness-pi and reuses the existing getRestrictedSandboxSession boundary; no cross-package src imports or dependency-direction violations were introduced. Concerns: none. Change scopeStatus: minimal All seven changed files directly implement, export, test, document, or release-note the extension-session API; no unrelated code or generated artifacts are included. Concerns: none. SecurityRisk: low Factories receive toolSafeSandboxSession rather than the network sandbox handle, preventing access to sandbox lifecycle and network-policy operations; documentation continues to identify inline extensions as trusted host code. Concerns: none. TestingStatus: appropriate Tests verify the restricted sandbox and work directory, observe different instructions across two turns, and type-check both plain Pi factories and session-aware factories. Concerns: none. VerificationInspected the full origin/main...HEAD diff and surrounding session lifecycle code. pnpm --filter @ai-sdk/harness-pi test:node passed 270 tests, package type-check and build passed, pnpm type-check:full passed, pnpm check reported no formatting or lint errors, git diff --check passed, and changeset status recognized the patch release. |
Review found the provider docs page still described one-argument extension factories, and the README example claimed to use all three session fields while using two. The provider page now lists `sandboxSession`, `sessionWorkDir` and `instructions()` with an example, and both examples run a command in the session's sandbox so each field appears. The example type-checks against `createPi`. `extensionSession` moves above the comment about MCP servers, which it had been inserted beneath.
Feature reviewOutcome: approved Implements featureStatus: fully-implements Each configured factory is adapted to receive a PiHarnessExtensionSession containing getRestrictedSandboxSession(input.sandboxSession), sessionWorkDir, and a live instructions() closure updated before each turn. The new types are publicly exported, and both provider documentation and the package README document all three fields. Concerns: none. Side effectsRisk: low The change adds one adapter closure per caller-supplied factory while preserving the existing extension runtime, resource-reload behavior, MCP factory handling, and factory ordering. Concerns: none. PerformanceRisk: low Runtime overhead is limited to one small closure per extension factory and an O(1) instructions getter; no additional sandbox operations or per-event allocations are introduced. Concerns: none. Backwards compatibilityRisk: low Existing one-argument Pi ExtensionFactory values remain assignable to PiHarnessExtensionFactory and continue to run unchanged, as verified by the type test and existing runtime factory test. Concerns: none. Breaking changesRisk: none No exports, settings, defaults, errors, persisted formats, or accepted factory inputs are removed or narrowed. The callback contract is extended with a second argument while ordinary one-argument JavaScript and TypeScript callbacks remain valid. Concerns: none. ArchitectureRisk: low The session-aware abstraction is owned and exported by @ai-sdk/harness-pi, reuses the established @ai-sdk/harness getRestrictedSandboxSession boundary, and introduces no cross-package src imports or dependency-direction violations. Concerns: none. Change scopeStatus: minimal All eight changed files directly provide the implementation, public exports and types, runtime and type tests, user-facing documentation, or the required patch changeset. Concerns: none. SecurityRisk: low Factories receive the restricted sandbox surface used by harness tooling rather than the network sandbox's lifecycle and policy-management capabilities; documentation also continues to identify inline extensions as trusted host code. Concerns: none. TestingStatus: appropriate Tests cover the session object, work directory, restricted sandbox result, changing instructions across two turns, single factory initialization, and compatibility with plain Pi factories. README and provider-doc examples demonstrate all three session fields. Concerns: none. VerificationInspected the complete origin/main...HEAD diff, surrounding Pi session lifecycle and resource-reload code, public exports, sandbox restriction helper, and Pi's upstream ExtensionFactory definition. pnpm --filter @ai-sdk/harness-pi test:node passed 301 tests; package type-check and build passed; pnpm type-check:full and pnpm check passed; git diff --check passed; and changeset status recognized @ai-sdk/harness-pi for a patch release. |
|
🚀 Published in:
|
Background
An
extensionFactoriesentry received only Pi'sExtensionAPI, so an extension could not reach the sandbox the session runs against or the instructions the caller set for the turn. A Task-style tool that runs a child Pi session against the parent's sandbox with the parent's instructions had no way to get either. #23103 also builds on this: it removes the host copy of the workspace, which leavessession.sandboxSessionas the only way an extension can read project files.Summary
PiHarnessExtensionSession: the restrictedsandboxSession(the same view the builtin tools use), thesessionWorkDir, and aninstructions()getter.(pi) => voidfactories stay assignable and keep working unchanged.End-to-End Verification
Run against the real Pi runtime through
HarnessAgent, with a local just-bash sandbox and Claude Haiku 4.5 over the AI Gateway. The same scenario was run onmainas the control.mainthe factory receives nothing. On this branch it receives the session work directory, a sandbox session, andinstructions()returns the turn's instructions including the token.Checklist
pnpm changesetin the project root)Related Issues
Split out of #22289.