import { z } from 'zod';
import { E as ErrorCode } from './errors-C-so0M4t.js';

/** JSON-serializable value used for tool arguments and results */
type JSONValue = string | number | boolean | null | JSONValue[] | {
    [key: string]: JSONValue;
};

/** What the LLM sees — name, description, schema. Passed to all backends. */
interface ToolDeclaration<TParams = unknown> {
    name: string;
    description: string;
    parameters: z.ZodType<TParams>;
    needsApproval?: boolean;
    metadata?: {
        category?: string;
        icon?: string;
        tags?: string[];
    };
}
/** Full tool with execute function. Required for API-based backends.
 *  CLI backends extract declaration; execute map held internally.
 *  The optional second parameter receives request-scoped context
 *  when invoked through ChatRuntime (session ID, user data, custom metadata). */
interface ToolDefinition<TParams = unknown> extends ToolDeclaration<TParams> {
    execute: (params: TParams, context?: ToolContext) => Promise<unknown> | unknown;
}
/** Request-scoped context passed to tool execute functions via ChatRuntime.
 *  Contains session identity and user-defined metadata from the current session. */
interface ToolContext {
    /** Active chat session ID */
    sessionId: string;
    /** Custom metadata from the session (e.g. user ID, tenant, permissions) */
    custom?: Record<string, unknown>;
}
/** A tool call made by the LLM during execution */
interface ToolCall {
    id: string;
    name: string;
    args: JSONValue;
}
/** Result of executing a tool call */
interface ToolResult {
    toolCallId: string;
    name: string;
    result: JSONValue;
    isError?: boolean;
}

/** Message content — plain string or array of text/image parts */
type MessageContent = string | Array<ContentPart>;
/** Individual content part within a multi-part message */
type ContentPart = {
    type: "text";
    text: string;
} | {
    type: "image";
    data: string;
    mimeType: string;
};
/** Conversation message — discriminated union on `role` */
type Message = {
    role: "user";
    content: MessageContent;
} | {
    role: "assistant";
    content: MessageContent;
    toolCalls?: ToolCall[];
} | {
    role: "tool";
    content?: string;
    toolResults: ToolResult[];
} | {
    role: "system";
    content: string;
};

/** Scope for "remember this decision" */
type PermissionScope = "once" | "session" | "project" | "always";
/** What the permission callback receives */
interface PermissionRequest {
    toolName: string;
    toolArgs: Record<string, unknown>;
    /** Unique identifier for this specific tool call */
    toolCallId?: string;
    /** SDK-suggested scope (from Claude CLI's suggestions) */
    suggestedScope?: PermissionScope;
    /** Original SDK permission request (for pass-through) */
    rawSDKRequest?: unknown;
}
/** What the permission callback returns */
interface PermissionDecision {
    allowed: boolean;
    /** How long to remember this decision */
    scope?: PermissionScope;
    /** Modified tool arguments (tool args may be altered by user) */
    modifiedInput?: Record<string, unknown>;
    /** Denial reason (if denied) */
    reason?: string;
}
/** Permission callback signature */
type PermissionCallback = (request: PermissionRequest, signal: AbortSignal) => Promise<PermissionDecision>;
/** Request for user input — separate from permissions */
interface UserInputRequest {
    question: string;
    choices?: string[];
    /** Whether to allow freeform text input (default: true) */
    allowFreeform?: boolean;
}
/** Response from user to an input request */
interface UserInputResponse {
    answer: string;
    /** true if user typed a custom answer instead of selecting a choice */
    wasFreeform: boolean;
    /** Index of selected choice (if choice was selected) */
    selectedChoiceIndex?: number;
}
/** Hooks for supervisor/UI to intercept agent actions */
interface SupervisorHooks {
    onPermission?: PermissionCallback;
    onAskUser?: (request: UserInputRequest, signal: AbortSignal) => Promise<UserInputResponse>;
}

/** Model metadata returned by listModels() */
interface ModelInfo {
    id: string;
    name?: string;
    provider?: string;
    /** Model tier for UI categorization and cost hints */
    tier?: "fast" | "standard" | "premium";
    /** Context window size in tokens */
    contextWindow?: number;
    /** Model capabilities (e.g. "vision", "tools", "structured") */
    capabilities?: string[];
}
/** LLM model parameters */
interface ModelParams {
    temperature?: number;
    maxTokens?: number;
    topP?: number;
    stopSequences?: string[];
}
/** Result of backend validation check */
interface ValidationResult {
    valid: boolean;
    errors: string[];
}

/** Usage data from LLM execution — tokens consumed plus optional metadata */
interface UsageData {
    promptTokens: number;
    completionTokens: number;
    model?: string;
    backend?: string;
}
/** Events emitted during streaming agent execution */
type AgentEvent = {
    type: "text_delta";
    text: string;
} | {
    type: "thinking_delta";
    text: string;
} | {
    type: "tool_call_start";
    toolCallId: string;
    toolName: string;
    args: JSONValue;
} | {
    type: "tool_call_end";
    toolCallId: string;
    toolName: string;
    result: JSONValue;
} | {
    type: "permission_request";
    request: PermissionRequest;
} | {
    type: "permission_response";
    toolName: string;
    decision: PermissionDecision;
} | {
    type: "ask_user";
    request: UserInputRequest;
} | {
    type: "ask_user_response";
    answer: string;
} | {
    type: "thinking_start";
} | {
    type: "thinking_end";
} | {
    type: "usage_update";
    promptTokens: number;
    completionTokens: number;
    model?: string;
    backend?: string;
} | {
    type: "session_info";
    sessionId: string;
    transcriptPath?: string;
    backend: string;
} | {
    type: "heartbeat";
} | {
    type: "error";
    error: string;
    recoverable: boolean;
    code?: ErrorCode;
} | {
    type: "done";
    finalOutput: string | null;
    structuredOutput?: unknown;
    streamed?: boolean;
};

/** Pluggable store for persisting permission (scope) decisions across runs. */
interface IPermissionStore {
    /** Check if tool is already approved */
    isApproved(toolName: string): Promise<boolean>;
    /** Store an approval decision */
    approve(toolName: string, scope: PermissionScope): Promise<void>;
    /** Revoke approval for a tool */
    revoke(toolName: string): Promise<void>;
    /** Clear all approvals */
    clear(): Promise<void>;
    /** Dispose resources */
    dispose(): Promise<void>;
}

/** Per-call overrides passed to run(), stream(), runStructured().
 *  Allows overriding the model, tools, signal, and other parameters
 *  on a per-request basis without modifying the agent configuration. */
interface CallOptions {
    /** Override the default model for this call */
    model?: string;
    /** Override/extend tools for this call */
    tools?: ToolDefinition[];
    /** Per-call abort signal */
    signal?: AbortSignal;
    /** Override system message for this call */
    systemMessage?: string;
    /** Provider-specific options passed through to the underlying SDK */
    providerOptions?: Record<string, unknown>;
    /** Per-call timeout in milliseconds */
    timeout?: number;
    /** Per-call token limit */
    maxTokens?: number;
    /** Retry configuration for this call */
    retry?: RetryConfig;
}
/** Configuration for automatic retries on transient errors */
interface RetryConfig {
    /** Maximum number of retries (default: 0 — no retry) */
    maxRetries?: number;
    /** Initial delay in ms before first retry (default: 1000) */
    initialDelayMs?: number;
    /** Backoff multiplier (default: 2) */
    backoffMultiplier?: number;
    /** Which error codes to retry (default: all recoverable codes) */
    retryableErrors?: ErrorCode[];
}
/** Configuration for typed structured output from LLM */
interface StructuredOutputConfig<T = unknown> {
    schema: z.ZodType<T>;
    name?: string;
    description?: string;
}
/** Options passed to agent.run() / agent.stream().
 *  Extends CallOptions with run-specific fields (context, activityTimeoutMs).
 *  model is REQUIRED — every agent call must specify the model explicitly. */
interface RunOptions extends CallOptions {
    /** Model to use for this call (required — no implicit defaults) */
    model: string;
    /** Arbitrary context passed to the agent run */
    context?: Record<string, unknown>;
    /** Inactivity timeout for streaming (ms). When set, the stream aborts if no
     *  event (including heartbeats/progress) arrives within this period. Resets on
     *  every received event. Default: no timeout. Only affects stream()/streamWithContext(). */
    activityTimeoutMs?: number;
}
/** Timeout configuration for agent operations */
interface TimeoutConfig {
    /** Max time for entire agent run (ms) */
    total?: number;
    /** Max time for a single tool execution (ms) */
    perTool?: number;
    /** Max time for a single LLM request (ms) */
    perLLMRequest?: number;
}
/** Error handling strategy configuration */
interface ErrorHandlingConfig {
    /** What to do when a tool throws */
    onToolError?: "fail" | "continue" | "ask-llm";
    /** Retry config for transient LLM failures */
    retryLLM?: {
        maxAttempts: number;
        backoffMs: number;
    };
    /** Global error callback for monitoring */
    onError?: (error: Error, context: {
        phase: "tool" | "llm" | "permission" | "ask-user";
    }) => void;
}
/** Identity-only agent configuration — defines the agent's behavior, NOT per-call defaults.
 *  For creating an agent with model/tools defaults, use FullAgentConfig. */
interface AgentConfig {
    systemPrompt: string;
    supervisor?: SupervisorHooks;
    maxTurns?: number;
    timeout?: TimeoutConfig;
    errorHandling?: ErrorHandlingConfig;
    /** Pluggable store for persisting permission scope decisions across runs */
    permissionStore?: IPermissionStore;
    /** How to apply systemPrompt: "append" adds to backend default, "replace" overrides it.
     *  Default: "append". Currently used by the Copilot backend. */
    systemMessageMode?: "append" | "replace";
    /**
     * Filter for backend built-in tools (e.g. `["web_search", "web_fetch"]` for Copilot).
     * When set, only listed built-in tools are available. Backend-specific.
     *
     * **Security note**: This is a trust boundary — it controls which backend-native tools
     * the AI agent can invoke. By default, backends expose ALL their built-in tools.
     * Set this to restrict access (e.g. prevent file system access in a web-facing agent).
     */
    availableTools?: string[];
    /** Callback invoked with usage data after run completion or during streaming.
     *  Fire-and-forget: errors are logged but not propagated. */
    onUsage?: (usage: UsageData) => void;
    /** Interval in milliseconds for emitting heartbeat events during streaming.
     *  When set, heartbeat events are emitted to keep the stream alive during
     *  long tool executions. Default: off (no heartbeats). */
    heartbeatInterval?: number;
    /** Session reuse mode for CLI backends (Copilot, Claude).
     *  "per-call" (default): creates a fresh CLI session for each run/stream call.
     *  "persistent": reuses the same CLI session across calls, preserving conversation
     *  history natively in the CLI backend. Session is destroyed on agent dispose(). */
    sessionMode?: "per-call" | "persistent";
}
/** Per-call defaults that can be provided at agent creation time.
 *  Each field can also be overridden on individual calls via RunOptions. */
interface CallDefaults {
    /** Default model (overridable per-call via RunOptions.model) */
    model?: string;
    /** Default model parameters */
    modelParams?: ModelParams;
    /** Default tools (overridable per-call via RunOptions.tools) */
    tools?: ToolDefinition[];
    /** Provider-specific options passed through to the underlying SDK.
     *  For Vercel AI: passed as providerOptions to generateText/streamText.
     *  Example: { google: { thinkingConfig: { thinkingBudget: 1024 } } } */
    providerOptions?: Record<string, Record<string, unknown>>;
}
/** Full agent configuration: identity + per-call defaults.
 *  This is what createAgent() accepts. Backward-compatible with the old AgentConfig shape. */
type FullAgentConfig = AgentConfig & CallDefaults;
/** Result of an agent run, generic over structured output type T */
interface AgentResult<T = void> {
    output: string | null;
    structuredOutput: T extends void ? undefined : T;
    toolCalls: Array<{
        toolName: string;
        args: JSONValue;
        result: JSONValue;
        approved: boolean;
    }>;
    messages: Message[];
    usage?: UsageData;
}
/** Agent lifecycle state */
type AgentState = "idle" | "running" | "streaming" | "disposed";
/** Core agent interface — run prompts, stream events, manage lifecycle */
interface IAgent {
    /** The CLI session ID when using persistent session mode. Undefined in per-call mode
     *  or before the first call. Can be stored externally for session resume. */
    readonly sessionId: string | undefined;
    /** Run a single prompt and return the result. Wraps prompt in a user message. */
    run(prompt: MessageContent, options: RunOptions): Promise<AgentResult>;
    /** Run with full conversation history. Messages are passed directly to the backend. */
    runWithContext(messages: Message[], options: RunOptions): Promise<AgentResult>;
    /** Run with structured output validated against a Zod schema. */
    runStructured<T>(prompt: MessageContent, schema: StructuredOutputConfig<T>, options: RunOptions): Promise<AgentResult<T>>;
    /** Stream events for a single prompt. Wraps prompt in a user message. */
    stream(prompt: MessageContent, options: RunOptions): AsyncIterable<AgentEvent>;
    /** Stream events with full conversation history. Messages are passed directly to the backend. */
    streamWithContext(messages: Message[], options: RunOptions): AsyncIterable<AgentEvent>;
    /** Abort the current operation. No-op if not running. */
    abort(): void;
    /** Gracefully interrupt the current operation. Resolves when the backend acknowledges. */
    interrupt(): Promise<void>;
    /** Get current agent lifecycle state. */
    getState(): AgentState;
    /** Get frozen agent configuration. */
    getConfig(): Readonly<FullAgentConfig>;
    /** Release resources. After dispose(), agent must not be used. */
    dispose(): void;
}
/** Backend service interface — creates agents, lists models, validates config */
interface IAgentService {
    readonly name: string;
    createAgent(config: FullAgentConfig): IAgent;
    listModels(): Promise<ModelInfo[]>;
    validate(): Promise<ValidationResult>;
    dispose(): Promise<void>;
}

export type { AgentEvent as A, FullAgentConfig as F, IAgentService as I, ModelInfo as M, RunOptions as R, ToolDefinition as T, UsageData as U, ValidationResult as V, MessageContent as a, AgentResult as b, IAgent as c, Message as d, ToolResult as e };
