Extend decision/glossary pinning to all prompt-building adapters - #582
Open
QuanCheng-QC wants to merge 3 commits into
Open
Extend decision/glossary pinning to all prompt-building adapters#582QuanCheng-QC wants to merge 3 commits into
QuanCheng-QC wants to merge 3 commits into
Conversation
Decision pinning (added for the Claude adapter in c3e63c5) left the other adapters and several configurations without the shared, user-confirmed context, so two agents in the same channel could hold different readings of the same field. Close those gaps: - Hoist the three-state knowledge-entry fetch from ClaudeAdapter into BaseAdapter, generalized to any pinned title with a per-channel id cache. - Add a second pinned entry: a glossary (channel-specific "Glossary for channel <name>", falling back to a workspace-wide "Workspace glossary") that defines shared fields/terms. It is injected data-fenced like the decision log, and folded into the persistent-process fingerprint so a glossary edit respawns Claude CLI sessions with resume to re-pin it. - Wire pinning into the other prompt-building adapters: codex, llm-direct (kimi), amp, copilot, hermes, and opencode prefetch the pinned entries per message and pass them to their system-prompt builders with skills-mode (curl) phrasing. Gemini pins read-only: it has no knowledge tool access, so the write protocol is replaced with a restate-in-reply instruction. - Fix the MCP-mode allowlist: the decision protocol instructs workspace_list/read/write_knowledge by name but none were allowed, so in tool_mode mcp the log silently stopped updating. Plan mode allows the read/list tools only. - Make a disabled knowledge module visible: post a once-per-channel status saying pinning is inactive instead of only logging. Known limitations, deliberately out of scope: openclaw, cursor, and nanoclaw have no per-message system-prompt channel and stay unpinned; adapters that resume CLI-side sessions (amp, copilot, opencode) re-pin only when their CLI session restarts, since only the Claude adapter has the fingerprint-respawn machinery.
Address five review findings on the pinning-coverage commit. The workspace-glossary fallback, once matched, was cached under the channel key; the cached-id fast path then skipped the precedence check forever, so a channel glossary created later stayed invisible until restart. Only highest-precedence matches are cached now — fallback users pay one extra list per message and pick up a new channel glossary on the next turn. The knowledge disable was never handed to the MCP server: the CLI parsed only --disable-files/--disable-browser, so the server registered the knowledge tools regardless, and in execute mode --dangerously-skip-permissions makes allowlist omission a suggestion, not a boundary. The adapter now passes --disable-knowledge and the CLI maps it into the server's disabledModules. Goose builds a real per-turn --system prompt but was left unpinned; it now prefetches and injects both sections read-only (like Gemini, it has no workspace API commands to update entries with). Aider, Cline, and Mini remain unpinned by design — aider is message-file driven, cline deliberately keeps its own system prompt, mini deliberately has no workspace context — and are recorded here as known limitations. A transient knowledge read no longer wipes the last successful pin for prompt-per-turn adapters: _prefetchPinnedContext keeps the previous good result for whichever entry errored, and a thrown fetch keeps the previous context whole. The glossary result now carries its scope, and the prompt makes the workspace-wide fallback read-only for channel agents — a channel-local clarification must not silently rewrite definitions every other channel relies on. Concurrent read-modify-write on the same entry remains last-write-wins, a knowledge-API property shared with the decision log.
The cached-id fast path checked only status, assuming the entry still owns its canonical title. Renaming a channel glossary or decision log (e.g. for archival) therefore kept the old entry pinned indefinitely, masking the workspace fallback or a replacement canonical entry. When GET returns a title that differs from the canonical one, invalidate the cache and re-run list-and-match. A GET response without a title (older backends) is never treated as a rename.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Summary
Decision pinning (#580) gave the Claude adapter a per-channel decision log, but every other adapter — and several Claude configurations — still lacked the shared, user-confirmed context. Two agents in the same channel (e.g. a QA agent and an RD agent on different adapter types) could therefore hold different readings of the same field, with test cases and implementation drifting apart.
This PR makes the pinned knowledge a cross-adapter mechanism and adds a second pinned entry — a glossary — as the single source of truth for field/term definitions.
Changes
ClaudeAdapterintoBaseAdapter, generalized to any pinned title with a per-channel id cache (method names, cache fields, and the three-state contract are unchanged).Glossary for channel <name>, falling back to a workspace-wideWorkspace glossary. Injected data-fenced like the decision log, folded into the persistent-process fingerprint, so a glossary edit respawns Claude CLI sessions with--resumeto re-pin it. The workspace-wide fallback is read-only for channel agents — a channel-local clarification must not silently rewrite definitions other channels rely on.workspace_list/read/write_knowledgeby name but none were allowed — intool_mode: mcpthe log silently stopped updating. Plan mode allows the read/list tools only. The disable is also propagated to the MCP server (--disable-knowledge) so the tools are not even registered — allowlist omission is not a boundary under--dangerously-skip-permissions.Review-driven hardening (rounds 2–3)
channel/workspace) so prompts can phrase the fallback as read-only.Known limitations (accepted)
-swould replace it), mini deliberately has no workspace context. openclaw, cursor, and nanoclaw have no per-message system-prompt channel either.Testing
pinned-context.test.jsandclaude-decision-pinning.test.js), covering: glossary channel→workspace precedence and re-resolution, rename invalidation, fallback non-caching, last-known-good on transient failure, read-only prompts (Gemini/Goose/workspace scope), MCP allowlist +--disable-knowledgepropagation, and the combined-fingerprint respawn paths.npm run lintis non-functional repo-wide (no ESLint config/dependency exists);node --checkpasses on all touched files.