/**
 * Per-tool contract for `take_screenshot`. Adapter captures range PNGs via the
 * platform host, stashes them in the main-thread screenshot-cache keyed by
 * tool_call_id (the renderer reads from there — image bytes do NOT travel in
 * `details`), then sends them + query to a vision LLM. Approval is never required.
 */
import { Type } from '@sinclair/typebox';
import { HostToolResultStatus, buildRendererArtifact } from '../../../contracts/host-tool.js';
import { withAbort } from '../../../utils/abort.js';
import { TAKE_SCREENSHOT } from '../tool-names.js';
export const TAKE_SCREENSHOT_KIND = 'takeScreenshot';
export const TAKE_SCREENSHOT_GEMINI_MODEL = 'gemini-3-flash-preview';
export const TAKE_SCREENSHOT_HAIKU_MODEL = 'claude-haiku-4-5-20251001';
export const TAKE_SCREENSHOT_MIN_RANGES = 1;
export const TAKE_SCREENSHOT_MAX_RANGES = 10;
export const TAKE_SCREENSHOT_OUTPUT_TOKENS = 16_384;
export const TAKE_SCREENSHOT_TIMEOUT_SECONDS = 120;
export const TAKE_SCREENSHOT_SYSTEM_PROMPT = `You are given one or more screenshots of spreadsheet ranges. Analyze them according to the query.

Strengths — you are good at:
- Column widths, row heights, and general layout/spacing
- Overall appearance: fonts, text size, bold/italic, alignment
- Identifying colors (background fills, text colors, borders) by approximate name
- Reading cell values and text content in small-to-medium ranges

Limitations — be honest about:
- Precise cell coordinates can be inaccurate for large ranges
- You can identify colors visually but CANNOT determine exact hex codes or RGB values — recommend programmatic methods for precise color extraction

Screenshot capture caveats — the screenshots may have artifacts:
- The image is cropped and is not the same as the purported range, say so explicitly.
- Frozen panes (pinned header rows/columns) may appear in the screenshot even if they are outside the requested range. Look for a freeze line (thin gray/blue divider) and note if frozen headers are present.
- If the screenshot looks wrong (blank, garbled, or clearly not matching the requested range), flag it — do not treat it as ground truth.

Rules:
- Be clear and concise — your output is consumed by an agent, not a human. Minimize tokens.
- Answer the query directly. Do not repeat the query or add preamble.
- If the screenshot appears incomplete, cropped, or contain artifacts, you MUST let the main agent know
- If multiple screenshots are provided, reference them by sheet name and range
- Report exactly what you see — do not infer data that is not visible
- Format into markdown objects like tables or lists only when they add clarity, not by default`;
export const TAKE_SCREENSHOT_TOOL_DESCRIPTION = `Take screenshots of spreadsheet ranges and analyze them with a vision LLM.
Use this to understand and verify non-data spreadsheet elements that are otherwise difficult to access or understand via code execution.
For example: complex formatting, chart rendering, pivots, sparklines, understand layout, or see what the user sees.
Do not use this for reading cell values or data, and never as a replacement for code execution.
Do not take screenshots bigger than 40 rows x 10 columns per range.`;
export const TAKE_SCREENSHOT_RANGES_DESCRIPTION = 'List of sheet:range pairs to capture.';
export const TAKE_SCREENSHOT_SHEET_DESCRIPTION = 'Sheet name to capture.';
export const TAKE_SCREENSHOT_CELL_RANGE_DESCRIPTION = 'Range to capture, e.g. "A1:G10".';
export const TAKE_SCREENSHOT_QUERY_DESCRIPTION = 'What to analyze about the screenshots.';
export const TAKE_SCREENSHOT_MODEL_DESCRIPTION = `Vision model to use for analysis. Default: '${TAKE_SCREENSHOT_GEMINI_MODEL}'.`;
const rangeSchema = Type.Object({
    sheet: Type.String({ description: TAKE_SCREENSHOT_SHEET_DESCRIPTION }),
    cell_range: Type.String({ description: TAKE_SCREENSHOT_CELL_RANGE_DESCRIPTION })
});
const takeScreenshotLlmSchema = Type.Object({
    ranges: Type.Array(rangeSchema, {
        description: TAKE_SCREENSHOT_RANGES_DESCRIPTION,
        minItems: TAKE_SCREENSHOT_MIN_RANGES,
        maxItems: TAKE_SCREENSHOT_MAX_RANGES
    }),
    query: Type.String({
        description: TAKE_SCREENSHOT_QUERY_DESCRIPTION,
        minLength: 1
    }),
    model: Type.Optional(Type.String({ description: TAKE_SCREENSHOT_MODEL_DESCRIPTION }))
});
function isScreenshotRange(value) {
    if (!value || typeof value !== 'object')
        return false;
    const c = value;
    return typeof c.sheet === 'string' && typeof c.cell_range === 'string';
}
function validateParams(value) {
    if (!value || typeof value !== 'object')
        return false;
    const c = value;
    if (!Array.isArray(c.ranges))
        return false;
    if (c.ranges.length < TAKE_SCREENSHOT_MIN_RANGES)
        return false;
    if (c.ranges.length > TAKE_SCREENSHOT_MAX_RANGES)
        return false;
    for (const r of c.ranges) {
        if (!isScreenshotRange(r))
            return false;
    }
    if (typeof c.query !== 'string')
        return false;
    if (c.model !== undefined && typeof c.model !== 'string')
        return false;
    return true;
}
function validateResultDetails(value) {
    if (value === undefined)
        return true;
    if (!value || typeof value !== 'object')
        return false;
    const c = value;
    if (c.ranges !== undefined) {
        if (!Array.isArray(c.ranges))
            return false;
        for (const r of c.ranges) {
            if (!isScreenshotRange(r))
                return false;
        }
    }
    return ((c.model === undefined || typeof c.model === 'string') &&
        (c.screenshot_count === undefined || typeof c.screenshot_count === 'number') &&
        (c.body === undefined || typeof c.body === 'string') &&
        (c.error === undefined || typeof c.error === 'boolean'));
}
function normalizeResultDetails(value) {
    if (value === undefined)
        return undefined;
    return {
        ...value,
        ...(value.ranges ? { ranges: value.ranges.map((r) => ({ ...r })) } : {})
    };
}
function getResultObservabilityFields(details) {
    if (!validateResultDetails(details) || details === undefined)
        return undefined;
    const metadata = {
        ...(details.model !== undefined ? { model: details.model } : {}),
        ...(details.screenshot_count !== undefined
            ? { screenshot_count: details.screenshot_count }
            : {}),
        ...(details.error !== undefined ? { error: details.error } : {})
    };
    return Object.keys(metadata).length > 0 ? metadata : undefined;
}
function evaluateApproval() {
    return { required: false };
}
function formatResult(details, isError, userMessage) {
    const fallback = isError
        ? 'Screenshot analysis failed.'
        : 'Screenshot analysis returned no text.';
    const text = isError ? userMessage || fallback : details?.body || userMessage || fallback;
    return {
        content: [{ type: 'text', text }],
        details: buildRendererArtifact(details, userMessage),
        isError
    };
}
function createLlmTool(options) {
    return {
        name: TAKE_SCREENSHOT,
        label: 'Take Screenshot',
        isReadOnly: true,
        description: TAKE_SCREENSHOT_TOOL_DESCRIPTION,
        parameters: takeScreenshotLlmSchema,
        async execute(toolCallId, llmArgs, signal) {
            const args = llmArgs;
            const params = {
                ranges: args.ranges,
                query: args.query,
                ...(args.model !== undefined ? { model: args.model } : {})
            };
            void options.sessionPolicy;
            const request = {
                approval: evaluateApproval(),
                heartbeat: {
                    label: 'Taking screenshot...',
                    toolName: TAKE_SCREENSHOT
                },
                kind: TAKE_SCREENSHOT_KIND,
                params,
                requestId: toolCallId
            };
            const result = await withAbort(signal, async () => options.pendingHostToolRequests.request(request));
            const details = result.details;
            const isError = result.status === HostToolResultStatus.Failed ||
                result.status === HostToolResultStatus.Cancelled ||
                details?.error === true;
            return formatResult(details, isError, result.userMessage);
        }
    };
}
export const takeScreenshotContract = {
    kind: TAKE_SCREENSHOT_KIND,
    createLlmTool,
    evaluateApproval,
    getResultObservabilityFields,
    validateParams,
    validateResultDetails,
    normalizeResultDetails
};
//# sourceMappingURL=contract.js.map