/**
 * Per-tool contract for `read_skill`.
 *
 * This reads skill files through the host/API storage path, not through the
 * Modal `/skills` mount. Use it when the agent needs an authoritative read,
 * especially immediately after `modify_skill`, because CloudBucketMount reads
 * can lag external GCS writes.
 */
import { Type } from '@sinclair/typebox';
import { HostToolResultStatus, buildRendererArtifact } from '../../../contracts/host-tool.js';
import { withAbort } from '../../../utils/abort.js';
import { isValidRelativePath, parseModifySkillPath } from '../modify-skill/index.js';
import { READ_SKILL } from '../tool-names.js';
export const READ_SKILL_KIND = 'readSkill';
export const READ_SKILL_TOOL_DESCRIPTION = `
Read a skill file from storage. Pass the skill path shown in the Skills section and the file path to read.
`.trim();
const relativePathSchema = Type.String({
    description: 'Path relative to the skill folder, e.g. SKILL.md or scripts/helper.py.'
});
const readSkillLlmSchema = Type.Object({
    skillPath: Type.String({
        description: 'Skill folder path from the system prompt, e.g. /skills/user/foo or /skills/team/<team-owner-id>/foo.'
    }),
    filePath: relativePathSchema
});
function validateParams(value) {
    if (!value || typeof value !== 'object')
        return false;
    const candidate = value;
    return (parseModifySkillPath(candidate.skillPath) !== null && isValidRelativePath(candidate.filePath));
}
function validateResultDetails(value) {
    if (value === undefined)
        return true;
    if (!value || typeof value !== 'object')
        return false;
    const candidate = value;
    return ((candidate.content === undefined || typeof candidate.content === 'string') &&
        (candidate.file_path === undefined || typeof candidate.file_path === 'string') &&
        (candidate.skill_name === undefined || typeof candidate.skill_name === 'string') &&
        (candidate.skill_path === undefined || typeof candidate.skill_path === 'string') &&
        (candidate.storage_context === undefined ||
            candidate.storage_context === 'user' ||
            candidate.storage_context === 'team') &&
        (candidate.team_id === undefined || typeof candidate.team_id === 'string'));
}
function normalizeResultDetails(value) {
    return value === undefined ? undefined : { ...value };
}
function getResultObservabilityFields(details) {
    if (!validateResultDetails(details) || details === undefined)
        return undefined;
    return {
        ...(details.storage_context !== undefined ? { storage_context: details.storage_context } : {}),
        ...(details.file_path !== undefined ? { file_path: details.file_path } : {}),
        content_length: details.content?.length ?? 0
    };
}
function evaluateApproval() {
    return { required: false };
}
function formatResult(details, isError, userMessage) {
    const text = isError
        ? userMessage || 'Skill read failed.'
        : (details?.content ?? userMessage ?? 'Skill file was empty.');
    return {
        content: [{ type: 'text', text }],
        details: buildRendererArtifact(details, userMessage),
        isError
    };
}
function createLlmTool(options) {
    return {
        name: READ_SKILL,
        label: 'Read Skill',
        isReadOnly: true,
        description: READ_SKILL_TOOL_DESCRIPTION,
        parameters: readSkillLlmSchema,
        async execute(toolCallId, llmArgs, signal) {
            const args = llmArgs;
            const params = {
                skillPath: args.skillPath,
                filePath: args.filePath
            };
            const request = {
                approval: evaluateApproval(),
                heartbeat: {
                    label: 'Reading skill...',
                    toolName: READ_SKILL
                },
                kind: READ_SKILL_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;
            return formatResult(details, isError, result.userMessage);
        }
    };
}
export const readSkillContract = {
    kind: READ_SKILL_KIND,
    createLlmTool,
    evaluateApproval,
    getResultObservabilityFields,
    validateParams,
    validateResultDetails,
    normalizeResultDetails
};
//# sourceMappingURL=contract.js.map