import { aP as ToolCall, c as Attachment, R as Diagnostic, ao as Provider, a9 as ModelConfig, aB as Session, aK as SessionSummary, ag as Project, aF as SessionMode, aH as SessionPhase, M as Message, J as Criterion, L as CriterionStatus, ax as QueuedMessage, F as ContextState, O as DangerLevel$1, az as ServerMessage, aM as StatsIdentity, aS as ToolResult, D as Config } from '../protocol-CdVNdXi8.js';
import { Server } from 'node:http';

interface LLMMessage {
    role: 'system' | 'user' | 'assistant' | 'tool';
    content: string;
    thinkingContent?: string;
    toolCalls?: ToolCall[];
    toolCallId?: string;
    name?: string;
    attachments?: Attachment[];
}
interface LLMToolDefinition {
    type: 'function';
    function: {
        name: string;
        description: string;
        parameters: Record<string, unknown>;
    };
}
interface LLMCompletionRequest {
    messages: LLMMessage[];
    tools?: LLMToolDefinition[];
    toolChoice?: 'auto' | 'none' | 'required' | {
        type: 'function';
        function: {
            name: string;
        };
    };
    temperature?: number;
    maxTokens?: number;
    stream?: boolean;
    signal?: AbortSignal;
    disableThinking?: boolean;
    modelSettings?: {
        temperature?: number;
        topP?: number;
        topK?: number;
        maxTokens?: number;
        supportsVision?: boolean;
    };
    disableXmlProtection?: boolean;
    onVisionFallbackStart?: (attachmentId: string, filename?: string) => void;
    onVisionFallbackDone?: (attachmentId: string, description: string) => void;
}
interface LLMCompletionResponse {
    id: string;
    content: string;
    toolCalls?: ToolCall[];
    thinkingContent?: string;
    reasoning_content?: string;
    finishReason: 'stop' | 'tool_calls' | 'length' | 'content_filter';
    usage: {
        promptTokens: number;
        completionTokens: number;
        totalTokens: number;
    };
}
type LLMStreamEvent = {
    type: 'text_delta';
    content: string;
} | {
    type: 'thinking_delta';
    content: string;
} | {
    type: 'tool_call_delta';
    index: number;
    id?: string;
    name?: string;
    arguments?: string;
} | {
    type: 'done';
    response: LLMCompletionResponse;
} | {
    type: 'error';
    error: string;
} | {
    type: 'xml_tool_abort';
};
interface LLMClient {
    complete(request: LLMCompletionRequest): Promise<LLMCompletionResponse>;
    stream(request: LLMCompletionRequest): AsyncIterable<LLMStreamEvent>;
}

/**
 * Model-specific configuration profiles.
 * Different models have different optimal settings and capabilities.
 */
interface ModelProfile {
    /** Display name for the model */
    name: string;
    /** Sampling parameters */
    temperature: number;
    topP: number;
    topK?: number;
    /** Whether the model outputs reasoning/thinking content */
    supportsReasoning: boolean;
    /** Whether reasoning should be treated as regular content (for broken configs) */
    reasoningAsContent: boolean;
    /** Max tokens to generate if not specified */
    defaultMaxTokens: number;
    /** Whether the model supports vision/images */
    supportsVision: boolean;
}

/**
 * LLM Backend detection and capabilities.
 * Supports vLLM, SGLang, Ollama, and llama.cpp inference engines.
 */
type Backend = 'vllm' | 'sglang' | 'ollama' | 'llamacpp' | 'opencode-go' | 'unknown';

interface LLMClientWithModel extends LLMClient {
    getModel(): string;
    setModel(model: string): void;
    getProfile(): ModelProfile;
    getBackend(): Backend;
    setBackend(backend: Backend): void;
}

interface LspManagerInterface {
    /**
     * Notify the LSP that a file has changed and get diagnostics
     * Returns diagnostics for the file (may be empty if no issues)
     */
    notifyFileChange(path: string, content: string): Promise<Diagnostic[]>;
    /**
     * Get current diagnostics for a file without triggering a change
     */
    getDiagnostics(path: string): Diagnostic[];
    /**
     * Check if LSP is available for a given file
     */
    isAvailableFor(path: string): boolean;
    /**
     * Shutdown all LSP servers
     */
    shutdown(): Promise<void>;
}

interface ProviderManager {
    getProviders(): Provider[];
    getActiveProvider(): Provider | undefined;
    getActiveProviderId(): string | undefined;
    getCurrentModel(): string | undefined;
    getCurrentModelContext(): number;
    getLLMClient(): LLMClientWithModel;
    activateProvider(providerId: string, options?: {
        model?: string;
    }): Promise<{
        success: boolean;
        error?: string;
    }>;
    addProvider(provider: Omit<Provider, 'id' | 'createdAt'>): Provider;
    removeProvider(providerId: string): boolean;
    setProviders(providers: Provider[], defaultModelSelection?: string): void;
    getProviderStatus(providerId: string): 'connected' | 'disconnected' | 'unknown';
    getProviderModels(providerId: string): Promise<ModelConfig[]>;
    setDefaultModelSelection(providerId: string, model: string): Promise<{
        success: boolean;
        error?: string;
    }>;
    updateModelContext(providerId: string, modelId: string, contextWindow: number): Promise<{
        success: boolean;
        error?: string;
    }>;
    updateModelSettings(providerId: string, modelId: string, settings: {
        contextWindow?: number;
        temperature?: number | null;
        topP?: number | null;
        topK?: number | null;
        maxTokens?: number | null;
        supportsVision?: boolean;
    }): Promise<{
        success: boolean;
        error?: string;
        model?: ModelConfig;
    }>;
    refreshProviderModels(providerId: string): Promise<{
        success: boolean;
        error?: string;
    }>;
    getModelSettings(modelId: string): {
        temperature?: number;
        topP?: number;
        topK?: number;
        maxTokens?: number;
    } | undefined;
}

/**
 * Session Database Operations
 *
 * Manages session metadata in SQLite. Session content (messages, criteria, todos)
 * is stored in the events table and derived via EventStore folding.
 */

type DangerLevel = 'normal' | 'dangerous';

type Unsubscribe = () => void;

/**
 * Manages multiple LSP servers for a session.
 * Lazy-starts servers on first file access for each language.
 */
declare class LspManager implements LspManagerInterface {
    private workdir;
    private sessionId;
    private servers;
    private unavailableServers;
    private serverPromises;
    constructor(workdir: string, sessionId: string);
    private getOrCreateServer;
    private startServer;
    private getServerForFile;
    /**
     * Notify LSP that a file has changed and get diagnostics.
     * This is the main entry point for tools like write_file and edit_file.
     */
    notifyFileChange(path: string, content: string): Promise<Diagnostic[]>;
    /**
     * Get current diagnostics for a file without triggering a change.
     */
    getDiagnostics(path: string): Diagnostic[];
    /**
     * Check if LSP is available for a given file type.
     * Returns true if we have or can start a server for this file type.
     */
    isAvailableFor(path: string): boolean;
    /**
     * Shutdown all LSP servers.
     */
    shutdown(): Promise<void>;
    /**
     * Get status of all servers.
     */
    getStatus(): {
        language: string;
        state: string;
    }[];
}

type SessionEvent = {
    type: 'session_created';
    session: Session;
} | {
    type: 'session_updated';
    session: Session;
} | {
    type: 'session_deleted';
    sessionId: string;
} | {
    type: 'mode_changed';
    sessionId: string;
    from: SessionMode;
    to: SessionMode;
} | {
    type: 'phase_changed';
    sessionId: string;
    phase: SessionPhase;
} | {
    type: 'running_changed';
    sessionId: string;
    isRunning: boolean;
} | {
    type: 'criteria_updated';
    sessionId: string;
    criteria: Criterion[];
} | {
    type: 'message_added';
    sessionId: string;
    message: Message;
} | {
    type: 'queue_added';
    sessionId: string;
    queueId: string;
    mode: 'asap' | 'completion';
    content: string;
} | {
    type: 'queue_drained';
    sessionId: string;
    queueId: string;
} | {
    type: 'queue_cancelled';
    sessionId: string;
    queueId: string;
};
declare class SessionManager {
    private events;
    private activeSessionId;
    private providerManager;
    private cachedPromptStore;
    private dynamicContextChangedStore;
    constructor(providerManager: ProviderManager);
    getCurrentModelSettings(): {
        temperature?: number;
        topP?: number;
        topK?: number;
        maxTokens?: number;
        supportsVision?: boolean;
    } | undefined;
    getCurrentModelContext(): number;
    /**
     * Create a new session. Emits session.initialized event.
     * Note: maxTokens is no longer stored in the session - it comes from the current model config
     */
    createSession(projectId: string, title?: string, providerId?: string | null, providerModel?: string | null): Session;
    /**
     * Get a session by ID. Returns null if not found.
     * Session state is derived from EventStore.
     */
    getSession(id: string): Session | null;
    /**
     * Get a session by ID. Throws if not found.
     */
    requireSession(id: string): Session;
    /**
     * List all sessions (summary only).
     */
    listSessions(): SessionSummary[];
    /**
     * List sessions for a project with pagination.
     */
    listSessionsByProject(projectId: string, limit?: number, offset?: number): {
        sessions: SessionSummary[];
        hasMore: boolean;
    };
    /**
     * Delete a session and all its events.
     */
    deleteSession(id: string): void;
    /**
     * Get a project by ID.
     */
    getProject(projectId: string): Project | null;
    /**
     * Delete all sessions for a project.
     */
    deleteAllSessions(projectId: string, workdir: string): void;
    /**
     * Change session mode. Emits mode.changed event.
     */
    setMode(sessionId: string, toMode: SessionMode): Session;
    /**
     * Change session phase. Emits phase.changed event.
     */
    setPhase(sessionId: string, phase: SessionPhase): Session;
    /**
     * Set danger level. Does NOT emit event - danger level is not part of session state.
     * Just updates DB and returns updated session.
     */
    setDangerLevel(sessionId: string, dangerLevel: DangerLevel): Session;
    /**
     * Rename session. Updates title in DB and emits session_updated.
     */
    renameSession(sessionId: string, title: string): Session;
    /**
     * Set session running state. Emits running.changed event.
     */
    setRunning(sessionId: string, isRunning: boolean): Session;
    /**
     * Set session provider/model. Updates DB directly.
     */
    setSessionProvider(sessionId: string, providerId: string | null, providerModel: string | null): Session;
    /**
     * Add to the cumulative token usage.
     */
    addTokensUsed(sessionId: string, tokens: number): void;
    /**
     * Increment tool call counter.
     */
    incrementToolCalls(sessionId: string): void;
    /**
     * Add a message. Delegates to EventStore.
     */
    addMessage(sessionId: string, message: Omit<Message, 'id' | 'timestamp'>): Message;
    /**
     * Add an assistant message. Delegates to EventStore.
     */
    addAssistantMessage(sessionId: string, message: Omit<Message, 'id' | 'timestamp' | 'role'>): Message;
    /**
     * Update message stats. Delegates to EventStore (emits message.done if needed).
     */
    updateMessageStats(sessionId: string, messageId: string, _stats: Message['stats']): void;
    /**
     * Update a message. Delegates to EventStore.
     */
    updateMessage(sessionId: string, messageId: string, updates: Partial<Omit<Message, 'id' | 'timestamp' | 'role'>>): void;
    /**
     * Get messages for the current context window.
     */
    getCurrentWindowMessages(sessionId: string): Message[];
    /**
     * Compact context. Delegates to EventStore.
     */
    compactContext(sessionId: string, summary: string, tokenCountAtClose: number): void;
    /**
     * Set current context size (for token tracking).
     * Emits a context.state event with the real promptTokens from the LLM.
     * maxTokens comes from providerManager.getCurrentModelContext() - the currently selected model's limit.
     */
    setCurrentContextSize(sessionId: string, promptTokens: number, subAgentId?: string): void;
    /**
     * Set criteria. Delegates to EventStore.
     */
    setCriteria(sessionId: string, criteria: Criterion[]): void;
    /**
     * Update criterion status. Delegates to EventStore.
     */
    updateCriterionStatus(sessionId: string, criterionId: string, status: CriterionStatus): void;
    /**
     * Reset all criteria verification attempts.
     */
    resetAllCriteriaAttempts(sessionId: string): void;
    /**
     * Add a criterion attempt.
     */
    addCriterionAttempt(sessionId: string, criterionId: string, attempt: Criterion['attempts'][number]): void;
    /**
     * Record that a file was modified.
     */
    addModifiedFile(sessionId: string, filePath: string): void;
    /**
     * Add a criterion. Returns the updated criteria list.
     */
    addCriterion(sessionId: string, criterion: Criterion): {
        criteria: Criterion[];
        actualId: string;
    } | {
        error: string;
    };
    /**
     * Update criterion description.
     */
    updateCriterionFull(sessionId: string, criterionId: string, updates: Partial<Pick<Criterion, 'description'>>): Criterion[];
    /**
     * Remove a criterion.
     */
    removeCriterion(sessionId: string, criterionId: string): Criterion[];
    private messageQueues;
    queueMessage(sessionId: string, mode: 'asap' | 'completion', content: string, attachments?: Attachment[], messageKind?: string): QueuedMessage;
    cancelQueuedMessage(sessionId: string, queueId: string): boolean;
    drainAsapMessages(sessionId: string): QueuedMessage[];
    drainCompletionMessages(sessionId: string): QueuedMessage[];
    getQueueState(sessionId: string): QueuedMessage[];
    hasQueuedMessages(sessionId: string): boolean;
    clearMessageQueue(sessionId: string): void;
    private readFilesCache;
    /**
     * Record that a file was read.
     */
    recordFileRead(sessionId: string, filePath: string, contentHash: string): void;
    /**
     * Get read files cache.
     */
    getReadFiles(sessionId: string): Record<string, {
        hash: string;
        readAt: string;
    }>;
    /**
     * Update file hash after write.
     */
    updateFileHash(sessionId: string, filePath: string, contentHash: string): void;
    /**
     * Record a tool failure.
     */
    recordToolFailure(sessionId: string, tool: string, reason: string): void;
    /**
     * Reset tool failures.
     */
    resetToolFailures(sessionId: string): void;
    /**
     * Update execution state.
     */
    updateExecutionState(sessionId: string, updates: Record<string, unknown>): void;
    setCachedPrompt(sessionId: string, systemPrompt: string, hash: string): void;
    getCachedPrompt(sessionId: string): {
        systemPrompt: string;
        hash: string;
    } | undefined;
    setDynamicContextChanged(sessionId: string, changed: boolean): void;
    getDynamicContextChanged(sessionId: string): boolean;
    /**
     * @deprecated Use addMessage + compactContext instead
     */
    compactMessages(sessionId: string, _messageIds: string[], summary: string): Message;
    /**
     * @deprecated Use addTokensUsed instead
     */
    incrementTokenCount(sessionId: string, tokens: number): void;
    /**
     * Get the current context state for a session.
     */
    getContextState(sessionId: string): ContextState;
    /**
     * Get the LSP manager for a session.
     */
    getLspManager(sessionId: string): LspManager;
    setActiveSession(id: string | null): void;
    getActiveSessionId(): string | null;
    subscribe(callback: (event: SessionEvent) => void): Unsubscribe;
    subscribeToSession(sessionId: string, callback: (event: SessionEvent) => void): Unsubscribe;
    private emit;
    /**
     * Build a full Session object from DB session + EventStore state
     */
    private buildSessionFromDb;
}

interface ToolContext {
    workdir: string;
    sessionId: string;
    sessionManager: SessionManager;
    dangerLevel?: DangerLevel$1;
    signal?: AbortSignal | undefined;
    onProgress?: ((message: string) => void) | undefined;
    onEvent?: ((event: ServerMessage) => void) | undefined;
    lspManager?: LspManagerInterface | undefined;
    llmClient?: LLMClientWithModel | undefined;
    statsIdentity?: StatsIdentity | undefined;
    permittedActions?: Record<string, string[]> | undefined;
    toolCallId?: string;
    agentTimeout?: number;
}
interface Tool {
    name: string;
    definition: LLMToolDefinition;
    execute: (args: Record<string, unknown>, context: ToolContext) => Promise<ToolResult>;
    permittedActions?: string[];
}
interface ToolRegistry {
    tools: Tool[];
    definitions: LLMToolDefinition[];
    execute: (name: string, args: Record<string, unknown>, context: ToolContext) => Promise<ToolResult>;
}

/**
 * Server Context
 *
 * Holds all server dependencies in a single object that can be passed through
 * the application. This replaces singleton imports and enables:
 * - Easy testing with isolated instances
 * - Parallel test execution
 * - Clear dependency flow
 */

interface ServerContext {
    config: Config;
    sessionManager: SessionManager;
    llmClient: LLMClientWithModel;
    toolRegistry: ToolRegistry;
    providerManager?: ProviderManager;
}
interface ServerHandle {
    httpServer: Server;
    ctx: ServerContext;
    /** Start listening on the given port (0 for dynamic) */
    start: (port?: number) => Promise<{
        port: number;
    }>;
    /** Gracefully close the server */
    close: () => Promise<void>;
}

/**
 * Create a server handle that can be started on any port.
 * Returns a ServerHandle with start() and close() methods.
 *
 * Use this for:
 * - In-process testing with isolated instances
 * - Programmatic server control
 */
declare function createServerHandle(config: Config): Promise<ServerHandle>;
/**
 * Create and start a server (convenience function for CLI).
 * Starts listening immediately on the configured port.
 * Sets up SIGINT/SIGTERM handlers.
 */
declare function createServer(config: Config): Promise<void>;

export { createServer, createServerHandle };
