import type { TextBlock } from '../types/blocks.js'; import type { TokenSavingTier } from '../types/config.js'; import type { MemoryStore } from '../types/memory.js'; import type { ModeStore } from '../types/mode.js'; import type { SkillLoader } from '../types/skill.js'; import type { BuildContext, ModelCapabilities, SystemPromptBuilder, SystemPromptRegions } from '../types/system-prompt.js'; import type { SystemPromptContributor } from '../types/system-prompt-contributor.js'; import { type InstructionBundle, type InstructionBundlePaths } from './instruction-bundle.js'; export declare const LAYER_1_IDENTITY: string; /** * The section of the system prompt a given TextBlock originated from. Used by * `getContextBreakdown()` to attribute real token counts per category in the * `/context` display. */ export type SystemBlockSource = 'identity' | 'tool-usage' | 'environment' | 'skills' | 'mode' | 'plan' | 'leader-after-task' | 'contributor' | 'ledger' | 'nextsteps'; /** * Side-table mapping each system-prompt TextBlock to the section it came from. * Kept as a WeakMap rather than a field on TextBlock so the label never reaches * the wire: the provider adapters spread blocks verbatim (Anthropic non-ttl * `: b`, OpenAI `stripCacheControl` rest-spread), so any extra field would leak. * Block identities survive `flattenSystemPromptRegions` into `ctx.systemPrompt`, * so a later read of `ctx.systemPrompt` resolves the same entries. */ export declare const SYSTEM_BLOCK_SOURCE: WeakMap; /** Canonical shell the `bash` tool targets — drives the Environment Shell line * and the syntax-guidance sub-block. */ type EffectiveShell = 'pwsh' | 'powershell' | 'cmd' | 'posix'; /** * Derive the shell the `bash` tool will use from `os.platform()` + the pinned * `WRONGSTACK_SHELL` value (set at boot by `ensureSessionShell` in * @wrongstack/tools). On POSIX this is always `'posix'` and the caller shows the * raw `$SHELL`. On Windows with no pinned value (boot didn't run — tests / * embeddings) we report `'cmd'`, matching `bash.ts`'s default for * non-PowerShell-looking commands. */ export declare function effectiveShell(platform: NodeJS.Platform, wrongstackShell: string | undefined): EffectiveShell; /** * Shell-specific syntax guidance for the Environment block. Returns `''` for * POSIX (the model writes bash natively, so no nudge is needed). `detail: * 'short'` is the light-tier one-liner; `'full'` is the complete cheat-sheet. * The `&&`/`||` note branches on the PowerShell edition (only pwsh 7 supports * them). */ export declare function shellGuidanceBlock(shell: EffectiveShell, detail: 'full' | 'short'): string; export interface DefaultSystemPromptBuilderOptions { memoryStore?: MemoryStore | undefined; /** * Inject a static "# Relevant Memory" section into the built prompt from * `memoryStore`. Default: true. Set to false when a dedicated per-turn memory * retriever (the SAGE turn middleware) is the single injection * channel — this avoids double-injecting the same memories and keeps all * memory context flowing through one system. */ injectMemory?: boolean | undefined; skillLoader?: SkillLoader | undefined; /** * How skill bodies reach the prompt. `'eager'` (default) injects every * discovered skill body; `'progressive'` injects only a name+trigger manifest * and relies on the agent calling the `skill` tool to load a body on demand * (the agentskills.io progressive-disclosure model). */ skillMode?: 'eager' | 'progressive' | undefined; /** * In eager mode, cap the total chars of injected skill bodies (highest-priority * skills first); the rest become a load-on-demand manifest. Bounds prompt * cost when many skills are discovered. Default ~24k chars. */ skillEagerMaxChars?: number | undefined; modeStore?: ModeStore | undefined; /** Pre-resolved active mode id — shown in environment block. */ modeId?: string | undefined; /** Pre-resolved mode prompt — avoids redundant modeStore.getActiveMode() call. */ modePrompt?: string | undefined; /** Model capabilities — object snapshot or lazy getter for live model switches. */ modelCapabilities?: ModelCapabilities | (() => ModelCapabilities | undefined) | undefined; todayIso?: string | undefined; /** * Path to the session's plan JSON, or a getter that returns it. When * set, the builder reads the file on every `build()` call and injects * an "Active plan" block listing open items, so the LLM is anchored to * the strategic roadmap every turn — not just at resume. The block is * tagged `ephemeral` so a plan edit on turn N doesn't invalidate the * provider's prefix cache for earlier turns. * * The function form lets callers bind the builder before the session * id is known (e.g. DI containers that resolve the builder lazily) — * the getter is called at build-time, after the session has been * created. */ planPath?: string | (() => string | undefined); /** * System prompt contributors — called on every `build()` to inject * additional TextBlocks. Use `ExtensionRegistry.listSystemPromptContributors()` * or pass a plain array. Contributors are called in order; a throwing * contributor is caught and logged without aborting the build. */ contributors?: readonly SystemPromptContributor[] | undefined; /** * Token-saving mode tier. Controls how aggressively the system prompt is * compacted: skill bodies are omitted/trimmed, tool hints are shortened, * and optional guidance sections (delegation, mailbox, context management) * use minimal versions to reduce per-request tokens. * * - 'off' — Full guidance (no reduction) * - 'minimal' — TIER1 tools, stripped guidance * - 'light' — TIER1 + memory tools, minimal patterns * - 'medium' — TIER1 + TIER2 tools, some guidance * - 'aggressive' — Maximum reduction before tools become unusable * * Boolean values are accepted for backward compatibility: * - `true` → 'medium' * - `false` → 'off' */ tokenSavingMode?: TokenSavingTier | boolean | undefined; /** * File-backed instruction layers. Builtins are loaded first, then global * overrides, then project overrides, then explicit files. This lets durable * system instructions live outside TypeScript while keeping the builder API * stable for embedded runtimes. */ instructionPaths?: InstructionBundlePaths | undefined; /** * Last-mile in-memory overrides, applied after instructionPaths. Useful for * tests, embedders, and plugin-provided prompt experiments. */ instructionBundle?: InstructionBundle | undefined; } export declare class DefaultSystemPromptBuilder implements SystemPromptBuilder { private readonly opts; /** * Cached environment block, keyed by projectRoot. A single builder * instance is normally reused across turns of the same agent run, but * tests and library consumers may reuse it across runs with different * roots; keying the cache prevents leaking the first call's project * state into a later call against an unrelated project. */ private envCacheByRoot; private skillCache?; /** Cached full skill bodies (after frontmatter), built once per session. */ private skillBodyCache?; /** Tools from last build — used for memory relevance scoring. */ private _lastBuildTools?; /** Cached rendered online agents string, keyed by content fingerprint. */ private _lastOnlineAgents?; /** Cached full buildToolUsage output — keyed by tools array ref + agents fingerprint + tier. */ private _toolsUsageCache?; private _instructionBundle?; constructor(opts?: DefaultSystemPromptBuilderOptions); /** * Normalizes `tokenSavingMode` to a boolean for backward-compatible boolean checks. * - `undefined` / `false` / `'off'` → false * - `true` / any tier string other than `'off'` → true * * Note: invalid tier strings (e.g. "MINIMAL") are coerced to 'off' * by `normalizeTokenSavingTier` via the `tier` getter, so isCompact * correctly returns false for them — preventing isCompact/tier * disagreement on bad input. */ private get isCompact(); /** Exposes the effective (concrete) `TokenSavingTier` for tier-aware guidance * decisions. Invalid strings coerce to 'off'; the `'auto'` sentinel expands * from the model's context window (cache-safe — the window is stable per * session, so the resolved tier and therefore the prompt prefix stay stable). * See packages/core/src/types/config.ts. */ private get tier(); /** * Returns the max tool description length for the current tier. * Per the design doc: off=80, minimal=40, light=50, medium=60, aggressive=70. */ private toolDescLimit; build(ctx: BuildContext): Promise; buildRegions(ctx: BuildContext): Promise; private instructions; private instructionSection; /** * Cached plan content keyed by (planPath, mtimeMs). The plan is read * once per system-prompt build; most turns don't change the plan, so * this avoids a blocking fs.readFile + JSON.parse on every iteration. * Cleared when the file's mtime changes (the `/plan` tool mutated it). */ private _planCache?; /** * Reads the session-scoped plan sidecar (when configured) and produces * a short "Active plan" block listing open items so the model is * anchored to the strategic roadmap every turn. Reads on every `build()` * so a plan edit (via `/plan` or the `plan` tool) reflects on the next * turn without restarting the session. */ private buildActivePlan; private _formatPlan; private buildToolUsage; private renderToolSelectionBoundary; /** * Cheap content fingerprint of the online agents array. The mailbox * rebuilds the array as a fresh object on every status check, so caching * by reference always misses — this lets the renderOnlineAgents and * buildToolUsage caches detect rendered identity/status/task/tool changes * instead. * * O(n) over every field rendered in the peer snapshot. This matters because * status/task/tool changes should invalidate the prompt just like joins and * leaves do. Uses FNV-1a over character codes; a collision would only leave a * stale cosmetic snapshot in the prompt. */ private agentsFingerprint; /** * Render the online agents list, cached by content fingerprint. The agents * list changes at join/leave pace (seconds to minutes), not every prompt * build turn (hundreds of ms). The fingerprint detects membership changes * without holding the array reference — the mailbox rebuilds the array as * a fresh object on every status check, so reference equality always misses. * * Tier behaviour: * - 'off' / 'medium' / 'aggressive' → full list with names, sessions, sources * - 'minimal' / 'light' → count only (no list) */ private renderOnlineAgents; private buildEnvironment; private modelCapabilities; private buildMemoryAndSkills; /** * Build the progressive-disclosure manifest: list each skill's name + trigger * only and instruct the agent to call the `skill` tool to load a body. No * bodies are injected — the agent pulls them on demand (agentskills.io tier 2). */ private buildProgressiveSkillManifest; /** Build full skill bodies (token-saving OFF), bounded by an overall budget. */ private buildFullSkillBodies; /** * Build compact skill bodies for token-saving mode. * Uses `readSaveBody` from the skill loader which tries `SKILL.save.md` * first, then falls back to auto-compaction. */ private buildCompactSkillBodies; private buildMode; private dirExists; private gitStatus; private detectLanguages; } export {}; //# sourceMappingURL=system-prompt-builder.d.ts.map