fix(proxy): bridge session resolution + make Pi a first-class client - #1260
Draft
nicwn wants to merge 2 commits into
Draft
fix(proxy): bridge session resolution + make Pi a first-class client#1260nicwn wants to merge 2 commits into
nicwn wants to merge 2 commits into
Conversation
…idge session resolution Two bugs broke the memory-bridge and skill-bridge read path for any agent source other than codebuddy/claude-code (pi, dsh, codex, workbuddy, opencode). The agent could not search its own L1/L0 memory or load skills via the bridge — it silently received 40101 'session not initialized'. Bug 1 — BindingRepo never activated in default 3-container install: The default install (start-all.sh) generates config with redis.enabled=false and no storage: section. The eager activation block in server.ts only called tryActivateStorage and tryActivateRedis, both of which silently no-op when their config flags are false. ensureBindingRepoPersistent (the fs fallback) was only called inside buildPipelineBundle, which runs lazily on the first main request — AFTER completeRegistration's store.set() already skipped the L2b binding write because bindingRepo was still null. Fix: call ensureBindingRepoPersistent(config) in the server.ts eager block, right after tryActivateStorage/tryActivateRedis. It is idempotent (no-ops if a BindingRepo was already set by storage/redis). Bug 2 — bridge L1 lookup used a hardcoded agent-source prefix list: loadSessionIdsL1 tried [bare, 'codebuddy:', 'claude-code:'] — missing every other agentSource (pi, dsh, codex, workbuddy, opencode). The L1 state was in the Map under 'pi:sessionId' but the bridge never looked there. Fix: add SessionStore.keysWithSuffix(sessionId) and use it in both bridges to enumerate all L1 keys ending with ':sessionId'. This works for any current or future agentSource without maintaining a list. Tests: 6 new tests covering bare match, multi-agent-source, no-match, substring-vs-suffix, and pi/dsh integration scenarios.
nicwn
marked this pull request as draft
September 4, 2026 10:06
…set-import adapter, and bundled pi-plugin source
Pi already had proxy-side support (agent adapter, injection profile,
session-init picker) but was missing the user-facing onboarding surface
that every other agent has. This commit makes Pi a first-class client:
agents/pi/README.md:
Connection guide following the house style of agents/claude-code/README.md.
Documents the Pi extension approach (env vars + extension install,
not a config file), the interactive TUI picker, preset identity,
dynamic model catalog, injection profile, and troubleshooting.
agents/pi/asset-import.md:
How to import local Pi skill/session history into team memory.
Pi sessions live at ~/.pi/agent/sessions/<workspace-slug>/*.jsonl.
agents/setup-proxy.sh:
- Add 'pi' to the AGENTS array, menu, config paths, help text
- Add write_pi() function: env-var-guided setup (no config file to
write — Pi uses a Pi extension + env vars), with optional
'pi install' and a model-switch reminder
- Add Pi scan block: detect existing @tencentdb-agent-memory/pi-tdai-client
package in ~/.pi/agent/settings.json
agents/asset-import.ts:
- Add make_piAdapter() to the ADAPTERS registry: scans
~/.pi/agent/skills/ and <cwd>/.pi/skills/ for SKILL.md files,
and ~/.pi/agent/sessions/<workspace>/*.jsonl for conversation history
- Add '.pi' to CWD_MARKER_DIRS for auto-detection
- Add 'session' to parseJsonlLines skip list (Pi's JSONL header type)
agents/README.md:
- Add Pi to the agent comparison table and asset-import table
- Update count from 7 to 8 agents
MemoryCore/pi-plugin/:
Bundle the full Pi extension source (interactive picker, dynamic model
discovery, form parser, TUI picker) with the upstream package name
(@tencentdb-agent-memory/pi-tdai-client). The upstream repo had a
minimal stub; this brings it to feature parity with the fork's version.
30 tests across 4 test files (index, discovery, form, picker).
Collaborator
|
Thank you so much for your attention and contribution! We will arrange an internal review for this PR shortly, and all feedback will be shared right here in the discussion. |
Movtrength
reviewed
Sep 5, 2026
Movtrength
left a comment
There was a problem hiding this comment.
Review (local verification)
Verified on top of current feat/server_team (merge is clean; PR was 3 commits behind: #1195 / #1222 / #1052).
What looks good
- Bug 1 fix — eager
ensureBindingRepoPersistent(config)inserver.tsis the right place; idempotent and matches the lazy path inbuildPipelineBundle. - Bug 2 fix —
SessionStore.keysWithSuffix+ bridgeloadSessionIdsL1correctly drops the hardcodedcodebuddy/claude-codeprefix list. This is the durable fix vs forever extending the candidate list. - Pi first-class surface — docs /
setup-proxy.sh/ asset-import / pi-plugin tests are coherent with the earlier Pi adapter work. - Tests — pi-plugin: 30/30 pass. Original bridge unit tests: 6/6 pass after install.
Nits / follow-ups before un-draft
- Please merge/rebase onto latest
feat/server_team— no conflicts; needed for #1195 (piinAGENT_PREFIX_RE). - Bridge “integration” tests don’t call the bridge — they only exercise
keysWithSuffix, andsession_id: ""would make realtoIdFieldsreturnnull. I have a local patch that drivescreateMemoryBridgeHandlerwith a mocked fetcher (pi/dsh hit → 200 upstream, miss → 40101). Happy to push it if you add write access / cherry-pick, or I can paste a follow-up PR once there’s a fork to target. - Ambiguous multi-prefix — if both
pi:abcanddsh:abcexist, first Map hit wins. Probably fine for real traffic (one agent source per conversation), but worth a one-line comment. - Scope — bridge fix + Pi onboarding are independently reviewable; splitting would speed merge of the bugfix if Pi docs need more bikeshedding.
Ready?
Approach LGTM for the bridge bugs. After syncing with feat/server_team (+ ideally the real handler-level tests), this can leave draft.
3 tasks
|
Pushed a companion with write access on my fork: #1265 Includes your two commits + merge of current |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The memory-bridge and skill-bridge read path is broken for any agent source other than
codebuddyandclaude-code. When an agent (pi, dsh, codex, workbuddy, opencode) tries to search its L1/L0 memory or load skills via the bridge, it receives40101 "session not initialized"— even though the session was successfully initialized and the agent has persona/skills injected.This affects every default-install user (the 3-container
start-all.shdeploy with no Redis and nostorage:section), not just custom deployments.Root Causes
Bug 1: BindingRepo never activated in default install
The default install generates
redis: enabled: falseand nostorage:section. The eager activation block inserver.tsonly callstryActivateStorageandtryActivateRedis— both silently no-op when their config flags are false.ensureBindingRepoPersistent(the fs fallback) is only called insidebuildPipelineBundle, which runs lazily on the first main request — aftercompleteRegistration→store.set()already skipped the L2b binding write becausethis.bindingRepowas stillnull.Result: the L2b binding (designed as the bridge's L2 backstop, keyed by
(spaceId, sessionId)) is never written. The bridge L2 lookup always misses.Bug 2: Bridge L1 lookup uses a hardcoded agent-source prefix list
loadSessionIdsL1in bothmemory-bridge.tsandskill-bridge.tstries these candidate keys:The
pi:prefix (anddsh:,codex:,workbuddy:,opencode:) is missing. The L1 state IS in thestatesMap underpi:sessionId, but the bridge never looks there.Fixes
Fix 1: Eagerly activate BindingRepo at startup
Add
ensureBindingRepoPersistent(config)to theserver.tseager block, right aftertryActivateStorage/tryActivateRedis. It is idempotent (no-ops if a BindingRepo was already set by storage/redis).This ensures the BindingRepo is ready before any request can trigger
completeRegistration, so the L2b binding write actually happens.Fix 2: Enumerate L1 keys by suffix instead of hardcoded prefixes
Add
SessionStore.keysWithSuffix(sessionId)— returns all L1 keys matching:${sessionId}(or the bare sessionId). Both bridges use it inloadSessionIdsL1:This works for any current or future agentSource without maintaining a hardcoded list.
Impact
SessionStore.statesMap.Testing
6 new tests in
src/__tests__/bridge-session-resolution.test.ts:keysWithSuffix: bare match, multi-agent-source, no-match, substring-vs-suffixAll 14 tests pass (8 existing + 6 new).
Files Changed
src/server.tsensureBindingRepoPersistent(config)to eager activationsrc/session/store.tskeysWithSuffix(sessionId)methodsrc/memory/memory-bridge.tskeysWithSuffixinloadSessionIdsL1src/skill/skill-bridge.tskeysWithSuffixinloadSessionIdsL1src/__tests__/bridge-session-resolution.test.ts