import type {
CanonicalMessage,
CanonicalModelError,
CanonicalToolSchema,
} from "../../model/index.js";
export type ContextDiagnostic = {
code: string;
severity: "info" | "warning" | "error" | "fatal";
message: string;
path?: string;
};
* Boundary metadata exposed to the agent loop after `prepareForModel`.
* Lets the loop know which compact boundary (if any) the projection sliced
* messages from.
*/
export type ContextBoundary = {
type: "compact" | "microcompact" | "snip";
retainedMessages: number;
metadata?: Record<string, unknown>;
};
export type ModelContext = {
messages: CanonicalMessage[];
systemPrompt?: string;
systemPromptParts: string[];
tools: CanonicalToolSchema[];
diagnostics: ContextDiagnostic[];
boundaries: ContextBoundary[];
metadata?: Record<string, unknown>;
cacheBreakpoints?: number[];
};
export type ContextPrepareInput = {
sessionId: string;
turnId: string;
cwd: string;
abortSignal?: AbortSignal;
provider: string;
model: string;
permissionMode: string;
additionalWorkingDirectories: string[];
messages: CanonicalMessage[];
tools: CanonicalToolSchema[];
customSystemPrompt?: string;
appendSystemPrompt?: string;
maxMessages?: number;
};
export type ContextToolResultInput = {
sessionId: string;
turnId: string;
toolResultMessage: CanonicalMessage;
messages: CanonicalMessage[];
};
export type ContextToolResultResult = {
messages: CanonicalMessage[];
diagnostics: ContextDiagnostic[];
};
export type ContextRecoveryInput = {
sessionId: string;
turnId: string;
error: CanonicalModelError;
messages: CanonicalMessage[];
hasAttemptedCompact: boolean;
};
export type ContextRecoveryDecision =
| { type: "truncate_head_and_retry"; keepRatio: number; reason: string }
| { type: "strip_images_and_retry"; reason: string }
| { type: "give_up"; reason: string };
* Hand-off after a turn finishes (success, failure, or aborted). When a
* memory provider is wired into context, this is where the runtime forwards
* the conversation snapshot to the provider's capture pipeline. The hook is
* advisory — context implementations without memory simply no-op.
*/
export type ContextCaptureTurnInput = {
sessionId: string;
turnId: string;
messages: CanonicalMessage[];
errored: boolean;
};
* Public ContextRuntime contract consumed by the agent loop. The runtime is
* **not** model-aware — `recoverFromModelError` only returns a decision; the
* loop is responsible for any model calls (CompactionEngine.summarize) needed
* to fulfill the decision.
*/
export interface ContextRuntime {
prepareForModel(input: ContextPrepareInput): Promise<ModelContext>;
applyToolResults(input: ContextToolResultInput): Promise<ContextToolResultResult>;
recoverFromModelError(input: ContextRecoveryInput): Promise<ContextRecoveryDecision>;
* Optional turn-end hook (memory capture). Implementations without a
* memory provider should leave this absent so the agent loop can short-
* circuit. Throwing must not break the turn — implementations swallow.
*/
captureTurn?(input: ContextCaptureTurnInput): Promise<void>;
}