/**
 * Core runtime agent types.
 */
import type { Static, TSchema } from '@sinclair/typebox';
import type { EventStream } from '../ai/event-stream.js';
import type { streamSimple } from '../ai/stream.js';
import type { AssistantMessage, AssistantMessageEvent, ImageContent, Message, Model, SimpleStreamOptions, TextContent, Tool, ToolCall, ToolResultMessage, UserMessage } from '../ai/types.js';
import type { ShortcutXLLlmOperation } from '../contracts/model-stream.js';
import type { UserMessageUiMetadata } from '../contracts/user-message-ui-metadata.js';
import type { RuntimeFilesystemApprovalGrant, RuntimePermissionPolicy } from './permission-policy.js';
import type { SessionState } from './session-state.js';
export type { RuntimePermissionPolicy } from './permission-policy.js';
export type ApprovedFilesystemAccessGrant = RuntimeFilesystemApprovalGrant;
export interface ApprovedShellAccessGrant {
    command: string;
}
export interface ToolExecutionApprovalGrants {
    filesystem?: ApprovedFilesystemAccessGrant[];
    shell?: ApprovedShellAccessGrant[];
}
export interface SubagentSpawnGrant {
    /**
     * Approved task spawns become full headless workers.
     *
     * This is intentionally all-or-nothing: once a task launch is allowed, the
     * child receives a full-worker policy derived from its declared tool set
     * rather than a per-capability partial widening.
     */
    fullWorker: true;
    /** One-shot launch-mode override chosen in the task-spawn approval prompt. */
    runInBackground?: boolean;
}
/** Stream function - can return sync or Promise for async config lookup */
export type StreamFn = (...args: Parameters<typeof streamSimple>) => ReturnType<typeof streamSimple> | Promise<ReturnType<typeof streamSimple>>;
/**
 * Configuration for the agent loop.
 */
export interface AgentLoopConfig extends SimpleStreamOptions {
    model: Model<any>;
    /** Host-visible mode of the active agent configuration, e.g. action/ask/plan. */
    agentMode?: string;
    /**
     * Converts AgentMessage[] to LLM-compatible Message[] before each LLM call.
     */
    convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;
    /**
     * Optional transform applied to the context before `convertToLlm`.
     */
    transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;
    /**
     * Resolves an API key dynamically for each LLM call.
     */
    getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
    /**
     * Returns the context object passed as the 5th argument to tool.execute().
     * When absent, tools receive `undefined` as ctx.
     */
    getToolContext?: () => ToolExecutionContext | undefined;
    /**
     * Returns steering messages to inject into the conversation mid-run.
     */
    getSteeringMessages?: () => Promise<AgentMessage[]>;
    /**
     * Returns the current prompt/tool configuration before each LLM call.
     * Runtime mode switches mutate this while a turn is already in flight.
     */
    getActiveConfiguration?: () => {
        agentMode?: string;
        systemPrompt: string;
        tools?: ToolDefinition[];
    };
    /**
     * Returns follow-up messages to process after the agent would otherwise stop.
     */
    getFollowUpMessages?: () => Promise<AgentMessage[]>;
    /**
     * Optional override for requesting a single assistant response.
     * Runtime layers can wrap the default request flow with auth retry or other policies.
     */
    requestAssistantResponse?: (context: AgentContext, config: AgentLoopConfig, signal: AbortSignal | undefined, stream: EventStream<AgentLoopEvent, AgentMessage[]>, streamFn?: StreamFn, onToolCallReady?: (toolCall: ToolCall) => void) => Promise<AssistantMessage>;
    /** Wrap LLM call so UI sees op_start/tick/op_end. Optional in tests. */
    heartbeatWrap?: <T>(promise: Promise<T>, kind: InFlightOpKind, meta?: InFlightMeta) => Promise<T>;
    /**
     * Per-call speed mode. Currently only `'fast'` is meaningful, and only
     * on Shortcut models explicitly enabled for fast handling. Plumbed
     * through `streamFn` as an extension on the options
     * object; the ShortcutXL stream impl reads it and forwards to the
     * proxy as `speed`. Other stream impls (owned AI default) ignore it.
     * Set per-turn from `AgentSubmitOptions.speed`.
     */
    speed?: 'fast' | 'standard';
    /** Host-generated user message identifier forwarded to ShortcutXL's LLM proxy. */
    userMessageId?: string;
    /**
     * Host-owned observability identifiers for the active user turn.
     * These are forwarded only by ShortcutXL's proxy stream implementation.
     */
    initialFileId?: string;
    fileAttachmentIds?: readonly string[];
    interactionMode?: string;
    llmOperation?: ShortcutXLLlmOperation;
}
/**
 * Thinking/reasoning level for models that support it.
 */
export type ThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
/**
 * Module-augmentation hook for custom app messages.
 * See `core/custom-messages.ts` for the built-in augmentation.
 */
export interface CustomAgentMessages {
}
/**
 * SXL-side extension of owned AI's `UserMessage`. Carries optional metadata
 * (`contextResetBoundary`, `uiMetadata`) that is meaningful to the SXL runtime
 * and UI but must not ride to LLM providers. The projection in
 * `core/agent-snapshot-builder.ts:convertAgentMessagesToLlm` strips the field
 * before returning a clean owned AI `UserMessage`.
 *
 * `contextResetBoundary` is `true` (or absent) only — never `false`, never
 * any other truthy value. Enforced by `assertSessionInvariants` in §11.
 *
 * See `shortcutXL/docs/migration/archive/section_25_human_turn_enrichments/spec.md`
 * § Persistence + Simplifying assumptions #7a.
 */
export interface UserAgentMessage extends UserMessage {
    /** Optional host-provided stable UI id. When present, persistence uses it as the session-entry id. */
    id?: string;
    contextResetBoundary?: true;
    uiMetadata?: UserMessageUiMetadata;
}
/**
 * AgentMessage: Union of LLM messages + custom messages.
 *
 * The user variant is `UserAgentMessage` (extends `UserMessage`) so the SXL
 * runtime can attach SXL-only fields without polluting owned AI's types.
 */
export type AgentMessage = Exclude<Message, UserMessage> | UserAgentMessage | CustomAgentMessages[keyof CustomAgentMessages];
/** Kind of long-running op the heartbeat emitter wraps. */
export declare const InFlightOpKind: {
    readonly Compaction: "compaction";
    readonly HostTool: "host_tool";
    readonly Llm: "llm";
    readonly Subagent: "subagent";
    readonly Tool: "tool";
};
export type InFlightOpKind = (typeof InFlightOpKind)[keyof typeof InFlightOpKind];
/** Optional metadata carried alongside an in-flight op. */
export interface InFlightMeta {
    label?: string;
    toolName?: string;
    toolCallId?: string;
}
/** One outstanding heartbeat-wrapped op. Stacked entries allowed. */
export interface InFlightOp extends InFlightMeta {
    opId: string;
    kind: InFlightOpKind;
    startedAt: number;
    elapsedMs: number;
}
/** Failure category exposed to UI; mirrors backend error codes. */
export type AgentErrorKind = 'context_too_long' | 'llm_unavailable' | 'internal';
/**
 * AgentController state containing all configuration and conversation data.
 */
export interface AgentState {
    systemPrompt: string;
    model: Model<any>;
    thinkingLevel: ThinkingLevel;
    tools: ToolDefinition[];
    messages: AgentMessage[];
    isStreaming: boolean;
    streamMessage: AgentMessage | null;
    pendingToolCalls: Set<string>;
    error?: string;
    /** Categorical reason for `error`, when one is known. */
    errorKind?: AgentErrorKind;
    /**
     * Operations the heartbeat emitter has open. Pushed on `op_start`, mutated
     * on `heartbeat_tick`, removed on `op_end`. Snapshot mirrors this.
     */
    inFlight: InFlightOp[];
}
export interface AgentToolResult<T> {
    content: (TextContent | ImageContent)[];
    details: T;
    isError?: boolean;
}
export type AgentToolUpdateCallback<T = any> = (partialResult: AgentToolResult<T>) => void;
/**
 * Opaque context passed as the 5th argument to tool.execute().
 *
 * At runtime this may be an app-owned extension context, but we can't
 * reference that type here without creating a circular dependency. Tools that
 * need the full shape should import `ExtensionContext` from app/extensions
 * and cast.
 */
export interface ToolExecutionContext {
    sessionState?: SessionState;
    permissionPolicy?: RuntimePermissionPolicy;
    approvalGrants?: ToolExecutionApprovalGrants;
    /**
     * One-shot approval context for a single task-tool spawn.
     *
     * Unlike filesystem/shell approvalGrants, this does not authorize repeated
     * child launches. It only marks the current task invocation as approved to
     * launch a full-worker child session.
     */
    subagentSpawnGrant?: SubagentSpawnGrant;
    /** Wrap long-running awaitables so UI sees op_start/tick/op_end. Optional in tests. */
    heartbeatWrap?: <T>(promise: Promise<T>, kind: InFlightOpKind, meta?: InFlightMeta) => Promise<T>;
}
export type InFlightOpTerminalStatus = 'completed' | 'cancelled' | 'failed';
/** Event names emitted by owned AI's assistant-message stream. */
export declare const AssistantMessageEventType: {
    readonly Done: "done";
    readonly Error: "error";
    readonly Start: "start";
    readonly TextDelta: "text_delta";
    readonly TextEnd: "text_end";
    readonly TextStart: "text_start";
    readonly ThinkingDelta: "thinking_delta";
    readonly ThinkingEnd: "thinking_end";
    readonly ThinkingRedacted: "thinking_redacted";
    readonly ThinkingStart: "thinking_start";
    readonly ToolCallDelta: "toolcall_delta";
    readonly ToolCallEnd: "toolcall_end";
    readonly ToolCallStart: "toolcall_start";
};
export type AssistantMessageEventType = (typeof AssistantMessageEventType)[keyof typeof AssistantMessageEventType];
/**
 * Canonical headless tool interface used everywhere: agent loop, extensions, session.
 */
export declare const ToolLifecycleSource: {
    readonly AgentLoop: "agent_loop";
    readonly HostTool: "host_tool";
};
export type ToolLifecycleSource = (typeof ToolLifecycleSource)[keyof typeof ToolLifecycleSource];
export interface ToolDefinition<TParameters extends TSchema = TSchema, TDetails = any> extends Tool<TParameters> {
    label: string;
    execute: (toolCallId: string, params: Static<TParameters>, signal: AbortSignal | undefined, onUpdate: AgentToolUpdateCallback<TDetails> | undefined, ctx: ToolExecutionContext | undefined) => Promise<AgentToolResult<TDetails>>;
    /** Optional guideline bullets appended to the default system prompt Guidelines section. */
    promptGuidelines?: string[];
    /** When true, the tool is safe to execute concurrently during model streaming. */
    isReadOnly?: boolean;
    /**
     * Which runtime protocol owns lifecycle telemetry for this tool.
     * Defaults to `agent_loop`; host-mediated tools set `host_tool` so their
     * HostToolRequest/ResultApplied events are the single lifecycle source.
     */
    lifecycleSource?: ToolLifecycleSource;
    /** Safe scalar result fields for observability. Must not include user content or raw args. */
    getResultObservabilityFields?: (details: unknown) => Record<string, unknown> | undefined;
}
export interface AgentContext {
    systemPrompt: string;
    messages: AgentMessage[];
    tools?: ToolDefinition[];
}
export declare const AgentLoopEventType: {
    readonly AgentEnd: "agent_end";
    readonly AgentStart: "agent_start";
    readonly HeartbeatTick: "heartbeat_tick";
    readonly MessageEnd: "message_end";
    readonly MessageStart: "message_start";
    readonly MessageUpdate: "message_update";
    readonly OpEnd: "op_end";
    readonly OpStart: "op_start";
    readonly ToolExecutionEnd: "tool_execution_end";
    readonly ToolExecutionStart: "tool_execution_start";
    readonly ToolExecutionUpdate: "tool_execution_update";
    readonly TurnEnd: "turn_end";
    readonly TurnStart: "turn_start";
};
export type AgentLoopEventType = (typeof AgentLoopEventType)[keyof typeof AgentLoopEventType];
/**
 * Events emitted by the AgentController for UI updates.
 */
export type AgentLoopEvent = {
    type: typeof AgentLoopEventType.AgentStart;
} | {
    type: typeof AgentLoopEventType.AgentEnd;
    messages: AgentMessage[];
} | {
    type: typeof AgentLoopEventType.TurnStart;
} | {
    type: typeof AgentLoopEventType.TurnEnd;
    message: AgentMessage;
    toolResults: ToolResultMessage[];
} | {
    type: typeof AgentLoopEventType.MessageStart;
    message: AgentMessage;
} | {
    type: typeof AgentLoopEventType.MessageUpdate;
    message: AgentMessage;
    assistantMessageEvent: AssistantMessageEvent;
} | {
    type: typeof AgentLoopEventType.MessageEnd;
    message: AgentMessage;
} | {
    type: typeof AgentLoopEventType.ToolExecutionStart;
    toolCallId: string;
    toolName: string;
    args: Record<string, unknown>;
    startedAt: number;
} | {
    type: typeof AgentLoopEventType.ToolExecutionUpdate;
    toolCallId: string;
    toolName: string;
    args: Record<string, unknown>;
    partialResult: unknown;
} | {
    type: typeof AgentLoopEventType.ToolExecutionEnd;
    toolCallId: string;
    toolName: string;
    result: any;
    isError: boolean;
    startedAt: number;
    endedAt: number;
} | {
    type: typeof AgentLoopEventType.OpStart;
    opId: string;
    kind: InFlightOpKind;
    meta: InFlightMeta;
    startedAt: number;
} | {
    type: typeof AgentLoopEventType.HeartbeatTick;
    opId: string;
    kind: InFlightOpKind;
    meta: InFlightMeta;
    startedAt: number;
    elapsedMs: number;
} | {
    type: typeof AgentLoopEventType.OpEnd;
    opId: string;
    kind: InFlightOpKind;
    meta: InFlightMeta;
    startedAt: number;
    endedAt: number;
    status: InFlightOpTerminalStatus;
    errorMessage?: string;
};
//# sourceMappingURL=core-types.d.ts.map