Skip to content

fix(pi-plugin): session_id fallback forces manual-save bucket when model passes project explicitly #680

Description

@POLSKA-GRUPA

title: "fix(pi-plugin): session_id fallback forces manual-save bucket when model passes project explicitly"
labels: ["type:bug", "status:needs-review"]

Pre-flight Checks

  • I have searched existing issues and this is not a duplicate
  • I understand this issue needs status:approved before a PR can be opened

Bug Description

In the Pi plugin (plugin/pi/index.ts), the activeSessionId fallback in callMemoryTool() forces the manual-save-{project} bucket whenever the model passes project explicitly, ignoring the real runtime session id available via ctx.sessionManager.getSessionId() (which exposes PI_SESSION_ID).

The Pi adapter correctly registers the runtime session and getSessionId(ctx) returns it, but the fallback ordering discards it as soon as requestedProject is truthy. Since requestedProject is truthy whenever the model passes project (common in multi-project repos), ~100% of observations land in manual-save-{project} instead of the live UUID session — defeating session-scoped context retrieval, timeline, and context tools.

Steps to Reproduce

  1. engram setup pi (installs npm:gentle-engram@0.1.8 or 0.1.10) on a multi-project repo.
  2. Start a Pi session; verify ctx.sessionManager.getSessionId() returns a real UUID (it reads PI_SESSION_ID).
  3. From the session, call mem_save with project: "my-project" (explicit) but no session_id.
  4. Observe the observation is persisted with session_id = "manual-save-my-project" instead of the live UUID.

Expected Behavior

The real runtime session id should take priority over the manual-save bucket. The bucket should only be used when no runtime session exists.

Actual Behavior

// plugin/pi/index.ts (line 550 in 0.1.8, line 562 in 0.1.10)
const requestedProject = typeof params.project === "string" && params.project ? params.project : undefined;
const activeProject = requestedProject || project;
const activeSessionId = String(
  params.session_id ||
  (requestedProject ? `manual-save-${requestedProject}` : sessionId) ||  // ← BUG: forces bucket
  `manual-save-${project}`
);

When requestedProject is truthy (model passed project), the ternary returns manual-save-${requestedProject} — a truthy string — so sessionId (the real UUID) is never reached.

Suggested Fix

Prioritize the real sessionId over the bucket:

const activeSessionId = String(
  params.session_id ||
  sessionId ||                            // ← real runtime session first
  `manual-save-${activeProject}`          // ← bucket only as last resort
);

Rationale: sessionId comes from ctx.sessionManager.getSessionId() which is the authoritative Pi runtime identity (PI_SESSION_ID). The manual-save-{project} bucket should only be used when no runtime session is available. This mirrors the fix direction proposed in #660 for OpenCode, applied to the Pi adapter's client-side fallback.

Impact (real-world)

Discovered while cleaning up a long-running Engram DB at Polska Grupa Konsultingowa (multi-project workspace: pgk_empresa_autonoma, conta-pgk-hiszpania, programador_friki_pgk). Over ~4 months:

  • 5,644 total observations, 3,745 (66%) ended up in manual-save-* buckets despite Pi exposing a valid PI_SESSION_ID on every session.
  • Only 1,778 observations (31%) reached a real UUID session.
  • engram timeline, engram context, and session-scoped search returned degraded results because most observations were bucketed.

After applying the one-line fix locally, new observations correctly bind to the live Pi session.

Operating System

macOS (Apple Silicon)

Engram Version

  • engram binary: 1.20.0
  • gentle-engram npm: 0.1.8 (installed) and 0.1.10 (latest, same bug confirmed)

Agent / Client

Pi (@earendil-works/pi-coding-agent)

Relevant Logs

// Before fix: all observations persisted with session_id = manual-save-{project}
// ctx.sessionManager.getSessionId() = "019fa983-8666-7b6d-99c7-82b0a575bbd1" (ignored)
// persisted session_id           = "manual-save-pgk_empresa_autonoma"

// After fix: observations persisted with session_id = PI_SESSION_ID
// persisted session_id           = "019fa983-8666-7b6d-99c7-82b0a575bbd1"

Additional Context

  • Related: fix(opencode): bind summaries to the runtime session and make fallback worktree-safe #660 (same defect class for OpenCode, server-side active-session fallback). This issue is the Pi adapter client-side equivalent.
  • The bug is present in both gentle-engram@0.1.8 and 0.1.10 (line is identical).
  • The MEMORY_INSTRUCTIONS injected by the plugin do not instruct the model to pass session_id explicitly, so even a well-behaved model relying on the adapter will hit this fallback.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions