From b9a51d71fdde3227f1ba1deab99f7282a541a79b Mon Sep 17 00:00:00 2001 From: Joel Teply Date: Fri, 17 Apr 2026 19:47:16 -0500 Subject: [PATCH] Revert "Merge pull request #922 from CambrianTech/feature/phase-1-5-consumer-ordering" This reverts commit 3dfc3a8500f9fa0dfe1cf81a324a1824664eabe1, reversing changes made to a6419b82936ff9b6d0b5acd46fee055324c3dc08. --- src/system/rag/builders/ChatRAGBuilder.ts | 59 ++++++++--------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/src/system/rag/builders/ChatRAGBuilder.ts b/src/system/rag/builders/ChatRAGBuilder.ts index 5e637f6e5..c26e375dd 100644 --- a/src/system/rag/builders/ChatRAGBuilder.ts +++ b/src/system/rag/builders/ChatRAGBuilder.ts @@ -318,37 +318,21 @@ export class ChatRAGBuilder extends RAGBuilder { // 2.4. Inject RAG source context into system prompt — GENERIC LOOP // Each RAGSource provides a systemPromptSection. We inject them all without // knowing source names. Adding a new source requires ZERO changes here. - // - // Phase 1.5 (issue #918): the assembly order is enforced for stable - // byte-prefix prompts so llama-server / DMR can reuse KV cache. Order: - // 1. Identity systemPrompt (INVARIANT — already in finalIdentity) - // 2. Tool definitions (INVARIANT — moved here from end) - // 3. Loop iterates systemPromptSections in tier-sorted order - // (Phase 1's RAGComposer sort guarantees Map iteration order is - // INVARIANT → SEMI_STABLE → VOLATILE → alphabetical within tier) - // 4. Human presence (VOLATILE — moved here from start) - // Volatile content lives only in the suffix; the INVARIANT prefix is - // byte-identical across thousands of turns for the same persona+recipe. const finalIdentity = { ...identity }; - // 2.4.1. Inject INVARIANT tool definitions FIRST (after identity). - // Tool definitions are INVARIANT per the source classification — they - // change only when the tool catalog itself changes, not per request. - // Putting them at the top of the prefix maximizes the byte-stable - // region that DMR can reuse. - const toolDefinitionsPrompt = systemPromptSections.get('tool-definitions'); - let injectedCount = 0; - if (!isSmallContext && toolDefinitionsPrompt) { - finalIdentity.systemPrompt += toolDefinitionsPrompt; - injectedCount++; - this.log(`🔧 ChatRAGBuilder: Injected tool definitions (INVARIANT, byte-stable prefix region)`); + // 2.4.1. Inject human presence awareness (which room each user is viewing) + // This is NOT a RAG source — it's lightweight synchronous state, always injected. + const allPresence = HumanPresenceTracker.allPresence; + if (allPresence.length > 0) { + const lines = allPresence.map(p => { + const viewingThis = p.roomId === contextId; + return `- ${p.displayName} is viewing: ${p.roomName}${viewingThis ? ' (this room — they can see your response in real-time)' : ''}`; + }); + finalIdentity.systemPrompt = finalIdentity.systemPrompt + + `\n\n## HUMAN PRESENCE\n${lines.join('\n')}`; } - // 2.4.2. Inject all OTHER RAG source systemPromptSections in tier order. - // - // The Map iteration order matches the (tier, sourceName) sort that - // RAGComposer applied to result.sections in Phase 1 — Map preserves - // insertion order, and extractFromComposition inserts in that order. + // 2.4.2. Inject all RAG source systemPromptSections generically // // Sources with wrapper instructions — the section content gets wrapped with // additional context instructions. Eventually these wrappers should move INTO @@ -365,9 +349,10 @@ export class ChatRAGBuilder extends RAGBuilder { // Codebase search is critical — if someone asks about code, they need the answer. const ALWAYS_INJECT = new Set(['codebase-search']); - // Tool definitions already injected above; skip in the generic loop. + // Tool definitions are injected separately (native specs vs XML have different paths) const SKIP_GENERIC = new Set(['tool-definitions']); + let injectedCount = 0; for (const [sourceName, section] of systemPromptSections) { if (SKIP_GENERIC.has(sourceName)) continue; if (isSmallContext && !ALWAYS_INJECT.has(sourceName)) continue; @@ -378,18 +363,12 @@ export class ChatRAGBuilder extends RAGBuilder { this.log(`🔧 ChatRAGBuilder: Injected ${sourceName} into system prompt`); } - // 2.4.3. Inject VOLATILE human presence LAST. - // HumanPresenceTracker is not a RAGSource but its content is volatile - // (changes when any user switches rooms). It must live in the suffix, - // never in the byte-stable prefix region. - const allPresence = HumanPresenceTracker.allPresence; - if (allPresence.length > 0) { - const lines = allPresence.map(p => { - const viewingThis = p.roomId === contextId; - return `- ${p.displayName} is viewing: ${p.roomName}${viewingThis ? ' (this room — they can see your response in real-time)' : ''}`; - }); - finalIdentity.systemPrompt = finalIdentity.systemPrompt + - `\n\n## HUMAN PRESENCE\n${lines.join('\n')}`; + // 2.4.3. Inject XML tool definitions for text-based providers (budget-aware via ToolDefinitionsSource) + const toolDefinitionsPrompt = systemPromptSections.get('tool-definitions'); + if (!isSmallContext && toolDefinitionsPrompt) { + finalIdentity.systemPrompt += toolDefinitionsPrompt; + injectedCount++; + this.log(`🔧 ChatRAGBuilder: Injected tool definitions into system prompt (XML format)`); } if (isSmallContext) {