import { ResultErr } from '@polywrap/result';
import { basicFunctionCallLoop, LlmQuery, LlmQueryBuilder, ChatLogs, agentFunctionBaseToAgentFunction, executeAgentFunction, } from '../../agent-core/index.js';
export class Agent {
    config;
    context;
    constructor(config, context) {
        this.config = config;
        this.context = context;
    }
    get workspace() {
        return this.context.workspace;
    }
    async init() {
        await this.context.chat.persistent([
            {
                role: 'system',
                content: 'Variables are annotated using the ${variable-name} syntax. Variables can be used as function argument using the ${variable-name} syntax. Variables are created as needed, and do not exist unless otherwise stated.',
            },
            ...this.config.prompts.initialMessages(),
        ]);
    }
    async *run(args) {
        await this.initRun(args);
        const { chat } = this.context;
        if (this.config.timeout) {
            setTimeout(this.config.timeout.callback, this.config.timeout.milliseconds);
        }
        try {
            this.config.functions.forEach(fn => {
                chat.addFunction(fn.getDefinition());
            });
            if (this.config.timeout) {
                setTimeout(this.config.timeout.callback, this.config.timeout.milliseconds);
            }
            return yield* basicFunctionCallLoop(this.context, (functionCalled) => {
                return this.config.shouldTerminate(functionCalled);
            }, this.config.prompts.loopPreventionPrompt, this.config.prompts.agentSpeakPrompt, this.beforeLlmResponse.bind(this));
        }
        catch (err) {
            await this.context.logger.error(err);
            return ResultErr('Unrecoverable error encountered.');
        }
    }
    onFirstRun(_, chat) {
        return Promise.resolve();
    }
    async initRun(args) {
        await this.context.chat.persistent(this.config.prompts.runMessages(args));
    }
    async executeFunction(func, args, chat) {
        const fn = agentFunctionBaseToAgentFunction(this)(func);
        const { result } = await executeAgentFunction([args, fn], JSON.stringify(args), this.context);
        for (const message of result.messages) {
            if (message.role !== 'function') {
                continue;
            }
            const functionResult = message.content || '';
            if (result.storeInVariable || this.context.variables.shouldSave(functionResult)) {
                const varName = await this.context.variables.save(func.name, functionResult);
                message.content = `\${${varName}}`;
            }
        }
        await chat.temporary(result.messages);
    }
    query(msgs) {
        return new LlmQuery(this.context.llm, this.context.chat.tokenizer, ChatLogs.from(msgs ?? [], [], this.context.chat.tokenizer));
    }
    queryBuilder(msgs) {
        return new LlmQueryBuilder(this.context.llm, this.context.chat.tokenizer, msgs);
    }
    askLlm(query, opts) {
        return this.query().ask(query.toString(), opts);
    }
    async createEmbeddingVector(text) {
        return (await this.context.embedding.createEmbeddings(text))[0].embedding;
    }
    async beforeLlmResponse() {
        return {
            logs: this.context.chat.chatLogs,
            agentFunctions: this.config.functions.map(x => x.getDefinition()),
            allFunctions: this.config.functions.map(agentFunctionBaseToAgentFunction(this)),
        };
    }
}
