/**
 * CacheDecision subflow — provider-agnostic translation from
 * `activeInjections + DSL directives` → `CacheMarker[]`.
 *
 * This is the core "policy → markers" Lego layer. It runs every
 * iteration (after slot subflows produce their output, before the
 * CacheGate decider). Pure transform: no IO, no LLM calls, no
 * provider knowledge.
 *
 * Algorithm:
 *   1. Build a `CachePolicyContext` from agent state
 *   2. For each injection in `activeInjections`, evaluate its
 *      `metadata.cache` directive against the context → cacheable boolean
 *   3. For each slot (system / tools / messages):
 *      a. Walk the slot's contributions in order
 *      b. Find the LAST index that's contiguous-from-start cacheable
 *      c. Emit one CacheMarker at that boundary if any cacheable
 *   4. The moving breakpoint: when EVERYTHING the policies govern before
 *      the conversation is cacheable — every tools entry, every system
 *      entry, every delivered message — mark the conversation's LAST
 *      message, so the next call (which repeats the conversation and
 *      appends to it) reads the whole prefix back. See
 *      `conversationTailMarker`.
 *
 * Nothing is marked when the tool schemas change on every call
 * (`toolsVaryPerCall`, the findings offer): tools render first on a
 * breakpoint wire, so every breakpoint would pay the write premium on bytes
 * the next call does not send.
 *
 * Each marker is provider-agnostic. Provider strategy translates
 * to wire format in Phase 6+.
 *
 * Special case — base system prompt: the agent's
 * `agent.getSystemPromptCachePolicy()` value is folded in at index 0
 * of the system slot. Always-on injections (Steering / Fact /
 * always-active rules) follow.
 */
import type { TypedScope } from 'footprintjs';
import type { CacheMarker, CachePolicy, CachePolicyContext } from './types.js';
import type { LLMMessage } from '../provider-contract/types.js';
import type { Injection } from '../injection-engine/types.js';
/**
 * Subflow scope state. Set via inputMapper from the agent's parent
 * scope; produces `cacheMarkers` consumed by the BuildLLMRequest stage.
 */
export interface CacheDecisionState {
    readonly activeInjections: readonly Injection[];
    readonly iteration: number;
    readonly maxIterations: number;
    readonly userMessage: string;
    readonly lastToolName?: string;
    /**
     * Cumulative input tokens spent across all LLM calls in THIS
     * `agent.run()` invocation only. Resets at the start of each turn
     * (each `agent.run()` call). Predicates can use this for budget-
     * aware cache invalidation (e.g., "flush cache after 50K tokens").
     */
    readonly cumulativeInputTokens: number;
    /**
     * Base system prompt's cache policy (from
     * `agent.getSystemPromptCachePolicy()`). Folded in at index 0 of
     * the system slot's cache evaluation, ahead of any always-on
     * injections.
     */
    readonly systemPromptCachePolicy: CachePolicy;
    /** Global kill switch. When `true`, subflow emits zero markers. */
    readonly cachingDisabled: boolean;
    /**
     * The window as the request will carry it (7.21) — post-window-strategy,
     * post-delivery. Only the `messages` marker needs it, and it needs it for
     * one reason: that marker's `boundaryIndex` is read by providers as an
     * index INTO THIS ARRAY, so it has to be computed here from the array
     * itself. Optional so the standalone/unit uses of `computeCacheMarkers`
     * that predate delivery keep working; absent means no messages marker —
     * neither a delivered-message one nor the conversation tail.
     */
    readonly history?: readonly LLMMessage[];
    /**
     * `true` when the tool schemas are re-decorated on every call — the
     * findings offer (`.findings()`) binds the served result ids into every
     * tool's `_findings` schema, newest first, so the list changes whenever a
     * result is served. Tools render FIRST on a breakpoint wire (Anthropic:
     * tools → system → messages), so no prefix through them repeats from one
     * tool-calling iteration to the next, and every breakpoint would pay the
     * cache-write premium on bytes the next call does not send — measured on
     * the inputs bench (`bench/cache`), 97% of request bytes marked and 5% of
     * the repeat calls' bytes read back. The
     * decision places none. Absent ≡ `false`. The agent charts pass it at BUILD
     * time (`cacheDecisionStage`), never through scope.
     */
    readonly toolsVaryPerCall?: boolean;
    cacheMarkers: readonly CacheMarker[];
}
/**
 * Evaluate a `CachePolicy` against the current context.
 * Returns `true` if the policy says THIS iteration's content is cacheable.
 */
export declare function evaluateCachePolicy(policy: CachePolicy, ctx: CachePolicyContext): boolean;
/**
 * Identify which slots an injection contributes to. An injection can
 * target multiple slots simultaneously (Skills target both system +
 * tools); we visit each contributing slot independently.
 */
export declare function injectionTargetSlots(injection: Injection): ReadonlyArray<'system' | 'tools' | 'messages'>;
/**
 * Pure transform: state → markers. Exported so tests can exercise
 * the algorithm directly without the FlowChartExecutor ceremony of
 * mounting the subflow as a child of a parent chart.
 *
 * The subflow body (`decide` below) is a thin wrapper that pulls
 * state from scope and delegates here.
 */
export declare function computeCacheMarkers(state: Omit<CacheDecisionState, 'cacheMarkers'>): readonly CacheMarker[];
/** What a chart knows about its own wire when it builds the decision stage. */
export interface CacheDecisionStageOptions {
    /**
     * The chart re-decorates every tool schema per call (the findings door) —
     * see {@link CacheDecisionState.toolsVaryPerCall}. A BUILD-time fact, so it
     * is closed over here rather than read from scope: an unarmed agent's
     * decision stage reads exactly the keys it always did.
     */
    readonly toolsVaryPerCall?: boolean;
}
/**
 * The decision stage, built for one chart. Thin scope-binding wrapper around
 * `computeCacheMarkers`, so it can serve as the ROOT stage of the `sf-cache`
 * subflow (a chart cannot start with a nested subflow) — no logic
 * duplication.
 */
export declare function cacheDecisionStage(options?: CacheDecisionStageOptions): (scope: TypedScope<CacheDecisionState>) => void;
/** The decision stage for a chart whose tool schemas are stable per call. */
export declare const decideCacheMarkers: (scope: TypedScope<CacheDecisionState>) => void;
//# sourceMappingURL=CacheDecisionSubflow.d.ts.map