import { z } from "zod";
import { logger } from "../logger.js";
import { runSideCall } from "./model-provider.js";
import { channelDisplayName } from "./message-format.js";
const MAX_TOKENS = 2048;
const RecipientReplySchema = z.object({
    channel: z
        .string()
        .describe("The channel name, exactly as it appears in the incoming messages (e.g. 'telegram', 'discord', 'gmail')."),
    sender: z
        .string()
        .describe("The sender identifier, exactly as it appears in the incoming messages."),
    reply: z
        .string()
        .describe("A personalized, concise reply for this specific recipient (1-3 sentences)."),
});
const FastResponseSchema = z.object({
    replies: z
        .array(RecipientReplySchema)
        .describe("One reply per unique (channel, sender) pair from the incoming messages. " +
        "Each reply should be personalized — address the sender by name and reference their specific message(s)."),
    needsPrimaryAction: z
        .boolean()
        .describe("Should be true unless you are 100% sure you have fully handled all of them (e.g. pure status queries)."),
    briefForPrimary: z
        .string()
        .describe("A concise summary for the primary agent describing what these messages are about and what you told each sender."),
});
/**
 * Make a single lightweight API call to acknowledge one or more user messages
 * that arrived while the primary agent is busy. Handles the batch case where
 * multiple messages arrive in quick succession — the model sees all of them
 * and produces per-sender personalized replies + a unified briefing.
 *
 * Uses {@link runSideCall} so the request is routed through the same engine
 * (Claude SDK or Pi one-shot `complete()`) as the main agent.
 *
 * Returns null if the call fails so the caller can fall back to the original
 * interrupt-injection path.
 */
export async function fastRespond(options) {
    const { systemPrompt, messages, activitySummary, config, mode = "interrupt", compacting = false, learning = false, } = options;
    // Gmail messages are threaded and asynchronous — skip fast replies for them.
    // System messages are internal and have no channel adapter.
    const eligible = messages.filter((m) => m.channel !== "gmail" && m.channel !== "system");
    if (eligible.length === 0)
        return null;
    // Pre-compute unique recipients so the prompt can list them explicitly
    const recipientKeys = new Map();
    for (const m of eligible) {
        const key = `${m.channel}::${m.sender}`;
        if (!recipientKeys.has(key)) {
            recipientKeys.set(key, { channel: m.channel, sender: m.sender });
        }
    }
    const recipientList = [...recipientKeys.values()]
        .map((r) => `  - channel="${r.channel}", sender="${r.sender}"`)
        .join("\n");
    const messageSummary = eligible
        .map((m) => {
        const parts = [
            `- [${channelDisplayName(m.channel)}] from ${m.sender} at ${m.timestamp}: ${m.text}`,
        ];
        if (m.attachments.length > 0) {
            parts.push(`  Attachments: ${m.attachments.map((a) => `[${a.type}] ${a.filename ?? a.url ?? "(embedded)"}`).join(", ")}`);
        }
        return parts.join("\n");
    })
        .join("\n");
    const preamble = learning
        ? [
            `You are currently in Skill Learning Mode — merging an upstream update into one of your built-in skills. This takes a moment.`,
            "1. Let the user know you are in the middle of learning/updating your skills and will be available shortly.",
            "2. Ask them to wait a moment — you'll get back to them once the skill merge is done.",
            "3. Keep the reply concise and friendly (1-2 sentences). Match the user's language.",
            "4. Do NOT ask the user any questions — you are only an acknowledgment layer.",
            "5. Do NOT commit to performing any new action.",
        ]
        : compacting
            ? [
                `You are currently compressing your context (memory cleanup). This takes a moment.`,
                "1. Let the user know you are in the middle of context compression and will be available shortly.",
                "2. Ask them to wait a moment — you'll get back to them once the compression is done.",
                "3. Keep the reply concise and friendly (1-2 sentences). Match the user's language.",
                "4. Do NOT ask the user any questions — you are only an acknowledgment layer.",
                "5. Do NOT commit to performing any new action.",
            ]
            : mode === "watchdog"
                ? [
                    `You are working on a task but haven't responded to the user yet. Send a quick acknowledgment so they know their message was received and you are working on it.`,
                    "1. Acknowledge the user's message(s) so they know they were received.",
                    "2. If the message is a simple greeting or conversational, respond naturally.",
                    "3. If the user sends a task or request, let them know you're starting on it.",
                    "4. Keep each reply concise and friendly (1-3 sentences).",
                    "5. Do NOT ask the user any questions — you are only an acknowledgment layer.",
                    "6. If the user's follow-up can be answered confidently from the recent conversation context alone, answer it briefly. Otherwise, just confirm receipt and say you're working on it.",
                    "7. Do NOT commit to performing any new action (e.g., searching, browsing, sending emails). Only relay information already available in the conversation context.",
                ]
                : [
                    `Because you are currently working on a task, this is a side process that you should handle the incoming messages as quickly as possible.`,
                    "1. Acknowledge the user's message(s) so they know they were received.",
                    "2. If the user is asking about status or what the agent is doing, summarize the current activity.",
                    "3. If the user sends a new task or request, tell them it has been queued.",
                    "4. Keep each reply concise and friendly (1-3 sentences).",
                    "5. Do NOT ask the user any questions — you are only an acknowledgment layer.",
                    "6. If the user's follow-up can be answered confidently from the recent conversation context alone, answer it briefly. Otherwise, just confirm receipt and say it has been queued.",
                    "7. Do NOT commit to performing any new action (e.g., searching, browsing, sending emails). Only relay information already available in the conversation context.",
                ];
    try {
        return await runSideCall(config, {
            systemPrompt: buildFastResponderSystemPrompt(systemPrompt, preamble, recipientList),
            userMessage: buildFastResponderUserPrompt(activitySummary, eligible.length, messageSummary),
            schema: FastResponseSchema,
            schemaName: "fast_response",
            maxTokens: MAX_TOKENS,
        });
    }
    catch (err) {
        logger.warn(`Fast responder failed: ${err instanceof Error ? err.message : String(err)}`);
        return null;
    }
}
function buildFastResponderSystemPrompt(systemPrompt, preamble, recipientList) {
    return systemPrompt + [
        ...preamble,
        "",
        `You MUST produce exactly one reply per unique recipient. The recipients are:\n${recipientList}`,
        "Each reply should be personalized — address the sender and reference their specific message(s).",
        "Use the exact channel and sender strings listed above in your output.",
        "Treat `channel=\"weixin\"` as a remote messaging transport from the owner. It does NOT mean you should inspect or operate the desktop WeChat app unless the message explicitly asks you to do that.",
        "Be VERY careful about `needsPrimaryAction`, set it to true if anything is unclear, needs take actions like search/read file/... or requires the main process to follow up.",
        "",
        "IMPORTANT: You must NOT commit to performing any action. You can only acknowledge, summarize status, and inform the user their message(s) are queued.",
    ].join("\n");
}
function buildFastResponderUserPrompt(activitySummary, eligibleMessageCount, messageSummary) {
    return [
        "## Current Agent Activity",
        activitySummary,
        "",
        `## Incoming Message${eligibleMessageCount > 1 ? `s (${eligibleMessageCount})` : ""}`,
        messageSummary,
    ].join("\n");
}
//# sourceMappingURL=fast-responder.js.map