var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { listBundledSkillManifests, listProjectSkillManifests, } from "./skills/registry.js";
export const DEFAULT_AGENT_SYSTEM_PROMPT = [
    "You are helpful AI Assistant for Admin Panel.",
    // about admin
    "Admin panel has resources which represent some physical data storage (e.g. table/collection), each resource defines list of columns.",
    "Each resource stores data records. Record represents a data item of resource.",
    //about user
    "Assume user is not technical so does not talk to him in terms of API calls, databases/sql/json etc.",
    // prevent extra talk
    "Try to achieve user's goal with as few steps as possible. Talk with him only when you need some important decision, otherwise act immediately and call tools asap",
    // tone of voice
    "Be warm, friendly, and sincere.",
    "Keep responses short, clear, and practical.",
    "Answer only what is needed.",
    "Do not add extra explanations or suggestions unless the user asks.",
    "Adapt to the user's tone and style of speaking, mirroring their vibe and wording.",
    "if the user speaks casually, you should respond casually too",
    "Never mutate data without user confirmation for a clearly described mutation plan.",
    "One confirmation may cover one mutation or one explicitly described batch/sequence of related mutations.",
    "If the confirmed plan has multiple steps, you may execute the whole confirmed plan without asking again between those steps.",
    "If the plan changes, expands, or you want to do anything beyond the confirmed plan, ask for confirmation again.",
    "Do not reuse an old confirmation for a new mutation plan.",
].join(" ");
export function appendCustomSystemPrompt(systemPrompt, customSystemPrompt) {
    const normalizedCustomSystemPrompt = customSystemPrompt === null || customSystemPrompt === void 0 ? void 0 : customSystemPrompt.trim();
    if (!normalizedCustomSystemPrompt) {
        return systemPrompt;
    }
    return `${systemPrompt}\n\n${normalizedCustomSystemPrompt}`;
}
function formatLanguagePrompt(language) {
    if (!language || language.ambiguous) {
        return "Respond in the user's language.";
    }
    return `Respond in ${language.language} (${language.code}).`;
}
function formatAdminUserPrompt(adminUser, usernameField) {
    const adminUserContext = {
        id: adminUser.pk,
        email: adminUser.dbUser[usernameField],
    };
    return [
        "Current admin user context:",
        JSON.stringify(adminUserContext, null, 2),
        "Use this admin user email when the user asks to send information to themselves, the current admin, or the logged-in user.",
    ].join("\n");
}
export function buildAgentTurnSystemPrompt(input) {
    return [
        input.agentSystemPrompt,
        formatAdminUserPrompt(input.adminUser, input.usernameField),
        formatLanguagePrompt(input.userLanguage),
    ].join("\n\n");
}
function formatResources(resources) {
    return resources
        .map((resource) => `- resourceId: ${resource.resourceId}\n  label: ${resource.label}`)
        .join("\n");
}
function formatSkills(skills, label) {
    return skills
        .map((skill) => `- ${label}: ${skill.name}\n  description: ${skill.description}`)
        .join("\n");
}
export function buildAgentSystemPrompt(adminforth_1) {
    return __awaiter(this, arguments, void 0, function* (adminforth, hiddenResourceIds = []) {
        const [primarySkills, defaultSkills] = yield Promise.all([
            listProjectSkillManifests(adminforth.config.customization.customComponentsDir),
            listBundledSkillManifests(),
        ]);
        const adminBasePath = adminforth.config.baseUrlSlashed;
        const hiddenResourceIdSet = new Set(hiddenResourceIds);
        const visibleResources = adminforth.config.resources.filter((resource) => !hiddenResourceIdSet.has(resource.resourceId));
        const sections = [
            DEFAULT_AGENT_SYSTEM_PROMPT,
            `ADMIN_BASE_PATH: ${adminBasePath}`,
            `List of resources:\n${formatResources(visibleResources)}`,
            primarySkills.length > 0
                ? `You have primary skills set:\n${formatSkills(primarySkills, "skill_name")}`
                : "",
            "You have next default skills which you can fallback to if primary skill set does not provide a good skill:\n" +
                formatSkills(defaultSkills, "skill_name"),
            "Before using any skill, call fetch_skill to load its full instructions.",
            "The fetched skill response starts with 'Tools mentioned in this skill'. Read that list first.",
            "You can use get_resource immediately to inspect resource structure and column names.",
            "If the user wants to create, update, delete, or run actions on records, load mutate_data first.",
            "If the user wants to fetch records, load fetch_data first. If the user wants analytics or charts, load analyze_data first.",
            "Only call fetch_tool_schema for tool names that are explicitly mentioned in a fetched skill and are not already available as base tools.",
            "If a fetched skill lists a non-base tool you need, call fetch_tool_schema for it immediately instead of telling the user the tool is unavailable.",
            "For example: for record creation load mutate_data, read its tool list, call fetch_tool_schema for create_record, and then use create_record after confirmation.",
            "When fetch_tool_schema succeeds, that tool becomes available on the next step.",
            "All admin links must be relative paths and must start with ADMIN_BASE_PATH.",
            "Build record links as ADMIN_BASE_PATH + resource/{resourceId}/show/{primary key}. Do not prepend any extra slash before resource.",
            "Try to call as many tools as possible in parallel in one step.",
        ];
        return sections.filter(Boolean).join("\n\n");
    });
}
