import { resolve } from 'node:path';
import { ProviderCredentialRepository } from '../../../core/auth/index.js';
import { DEFAULT_OPENAI_MODEL } from '../../../core/config.js';
import { HeddleEventType } from '../../../core/event-types.js';
import { AgentRunService } from '../../../core/agent/index.js';
import { AgentSkillsRuntimeContextService } from '../../../core/skills/index.js';
import { LlmAdapterService } from '../../../core/llm/index.js';
import { createLogger } from '../../../core/utils/logger.js';
import { RuntimeCredentialService } from '../credentials/index.js';
import { RuntimeToolService } from '../tools/index.js';
import { AgentLoopCheckpointService } from './checkpoint.js';
/**
 * Main programmatic runtime boundary for one evented agent loop execution.
 */
export class AgentLoopRuntimeService {
    static async run(options) {
        const runId = AgentLoopCheckpointService.generateRunId();
        const model = options.model ?? options.llm?.info?.model ?? process.env.OPENAI_MODEL ?? process.env.ANTHROPIC_MODEL ?? DEFAULT_OPENAI_MODEL;
        const provider = LlmAdapterService.inferProvider(model);
        const workspaceRoot = resolve(options.workspaceRoot ?? process.cwd());
        const apiKey = options.apiKey ?? RuntimeCredentialService.resolveApiKeyForModel(model);
        const credentialStorePath = this.resolveCredentialStorePath({ workspaceRoot, stateDir: options.stateDir });
        const providerCredentialSource = RuntimeCredentialService.resolveCredentialSourceForModel(model, {
            apiKey,
            apiKeyProvider: options.apiKey ? 'explicit' : apiKey ? provider : undefined,
            credentialStorePath,
        });
        const llm = options.llm ?? await this.createLoopLlmAdapter({
            model,
            apiKey,
            credentialStorePath,
            reasoningEffort: options.reasoningEffort,
        });
        const logger = options.logger ?? createLogger({ pretty: false, level: 'info', console: false });
        const tools = this.resolveTools(options, {
            model,
            apiKey,
            providerCredentialSource,
            workspaceRoot,
            credentialStorePath,
        });
        const systemContext = await this.resolveSystemContext({
            options,
            tools,
            workspaceRoot,
        });
        const now = () => new Date().toISOString();
        const startedAt = now();
        logger.info({
            model,
            provider,
            credentialSource: providerCredentialSource.type,
            credentialProvider: 'provider' in providerCredentialSource ? providerCredentialSource.provider : undefined,
        }, 'Agent runtime configured');
        const resumeMetadata = AgentLoopCheckpointService.resolveResumeMetadata(options.resumeFrom);
        options.onEvent?.({
            source: 'agent-loop',
            type: HeddleEventType.loopStarted,
            runId,
            goal: options.goal,
            model,
            provider,
            workspaceRoot,
            resumedFromCheckpoint: resumeMetadata?.checkpointRunId,
            timestamp: startedAt,
        });
        if (resumeMetadata) {
            options.onEvent?.({
                type: HeddleEventType.loopResumed,
                runId,
                fromCheckpoint: resumeMetadata.checkpointRunId,
                priorTraceEvents: resumeMetadata.priorTraceEvents,
                timestamp: now(),
            });
        }
        const result = await AgentRunService.run({
            goal: options.goal,
            llm,
            tools,
            workspaceRoot,
            maxSteps: options.maxSteps,
            logger,
            history: AgentLoopCheckpointService.resolveHistory(options),
            systemContext,
            onEvent: (event) => {
                AgentLoopRuntimeService.emitAgentRunEvent({ event, runId, now, options });
            },
            approvalPolicies: options.approvalPolicies,
            approveToolCall: options.approveToolCall,
            shouldStop: options.shouldStop,
            abortSignal: options.abortSignal,
        });
        const finishedAt = now();
        const state = AgentLoopCheckpointService.createFinishedState({
            runId,
            goal: options.goal,
            model,
            provider,
            workspaceRoot,
            startedAt,
            finishedAt,
            result,
        });
        options.onEvent?.({
            source: 'agent-loop',
            type: HeddleEventType.loopFinished,
            runId,
            outcome: result.outcome,
            summary: result.summary,
            usage: result.usage,
            state,
            timestamp: finishedAt,
        });
        return {
            ...result,
            model,
            provider,
            workspaceRoot,
            state,
        };
    }
    static emitAgentRunEvent(args) {
        const { event, runId, now, options } = args;
        if (event.type === HeddleEventType.trace) {
            options.onEvent?.({ type: HeddleEventType.trace, runId, event: event.event, timestamp: now() });
            options.onTraceEvent?.(event.event);
            return;
        }
        options.onEvent?.({ source: 'agent-loop', ...event, runId, timestamp: now() });
    }
    static resolveCredentialStorePath(args) {
        return args.stateDir
            ? ProviderCredentialRepository.resolveStorePath(resolve(args.workspaceRoot, args.stateDir))
            : undefined;
    }
    static async createLoopLlmAdapter(options) {
        return LlmAdapterService.create({
            model: options.model,
            credentials: {
                apiKey: options.apiKey,
                credentialStorePath: options.credentialStorePath,
            },
            runtime: {
                reasoningEffort: options.reasoningEffort,
            },
        });
    }
    static resolveTools(options, runtime) {
        const providedTools = options.tools ?? [];
        const extraTools = options.extraTools ?? [];
        if (options.includeDefaultTools === false) {
            return [...providedTools, ...extraTools];
        }
        return [
            ...RuntimeToolService.createDefaultAgentTools({
                model: runtime.model,
                apiKey: runtime.apiKey,
                providerCredentialSource: runtime.providerCredentialSource,
                credentialStorePath: runtime.credentialStorePath,
                workspaceRoot: runtime.workspaceRoot,
                stateDir: options.stateDir,
                stateRoot: this.resolveStateRoot(runtime.workspaceRoot, options.stateDir),
                memoryDir: options.memoryDir,
                searchIgnoreDirs: options.searchIgnoreDirs,
                includePlanTool: options.includePlanTool,
            }),
            ...providedTools,
            ...extraTools,
        ];
    }
    static async resolveSystemContext(args) {
        if (!args.tools.some((tool) => tool.name === 'read_agent_skill')) {
            return args.options.systemContext;
        }
        return await AgentSkillsRuntimeContextService.appendActivatedCatalog({
            workspaceRoot: args.workspaceRoot,
            stateRoot: this.resolveStateRoot(args.workspaceRoot, args.options.stateDir),
            systemContext: args.options.systemContext,
            readToolName: 'read_agent_skill',
        });
    }
    static resolveStateRoot(workspaceRoot, stateDir) {
        return resolve(workspaceRoot, stateDir ?? '.heddle');
    }
}
//# sourceMappingURL=service.js.map