"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildWorkerDecisionContract = buildWorkerDecisionContract;
exports.buildWorkerContinuationIssueContract = buildWorkerContinuationIssueContract;
exports.buildWorkerDecisionSchema = buildWorkerDecisionSchema;
exports.toWorkerDecisionValidationIssues = toWorkerDecisionValidationIssues;
exports.formatWorkerDecisionValidationIssues = formatWorkerDecisionValidationIssues;
const zod_1 = require("zod");
const catalog_1 = require("../i18n/catalog");
const types_1 = require("../workflows/types");
const constants_1 = require("./constants");
const decision_contract_rules_1 = require("./decision-contract-rules");
const decision_contract_schema_1 = require("./decision-contract-schema");
const decision_contract_support_1 = require("./decision-contract-support");
const structured_contract_support_1 = require("./structured-contract-support");
const types_2 = require("./types");
function buildWorkerDecisionContract(workflow, outputLanguage = catalog_1.DEFAULT_APP_LOCALE) {
    const schema = buildWorkerDecisionSchema(workflow);
    return {
        ...(0, structured_contract_support_1.buildWorkerStructuredContract)({
            schema,
            promptSchema: buildWorkerDecisionPromptSchema(workflow),
            example: (0, decision_contract_support_1.buildWorkerDecisionExample)(workflow, outputLanguage),
            rules: (0, decision_contract_rules_1.buildWorkerDecisionRules)(workflow),
        }),
        stepPromptSchemas: {
            task: (0, structured_contract_support_1.toWorkerPromptJsonSchema)(decision_contract_schema_1.taskStepSchema),
            workflowRef: (0, structured_contract_support_1.toWorkerPromptJsonSchema)(decision_contract_schema_1.workflowRefStepSchema),
            childIssue: (0, structured_contract_support_1.toWorkerPromptJsonSchema)(decision_contract_schema_1.childIssueStepSchema),
        },
    };
}
function buildWorkerContinuationIssueContract() {
    return {
        schema: decision_contract_schema_1.workerContinuationIssueSelectionSchema,
        example: {
            action: types_2.WORKER_CONTINUATION_ISSUE_ACTIONS.reuseExistingIssue,
            targetIssueId: "123",
        },
        rules: [
            "Return exactly one JSON object in the decision block.",
            "action must be one of reuse_existing_issue or create_new_child_issue.",
            "targetIssueId is required when action is reuse_existing_issue.",
            "targetIssueId must be omitted when action is create_new_child_issue.",
        ],
    };
}
function buildWorkerDecisionSchema(workflow) {
    if (isWorkflowSelectionWorkflow(workflow)) {
        return buildWorkflowSelectionWorkerDecisionSchema(workflow);
    }
    if (isWorkflowStepBatchReconciliationWorkflow(workflow)) {
        return buildStepBatchReconciliationWorkerDecisionSchema(workflow);
    }
    if (isWorkflowClosingWorkflow(workflow)) {
        return buildWorkflowClosingWorkerDecisionSchema(workflow);
    }
    const workflowSchema = buildWorkflowSchema(workflow);
    return buildWorkerDecisionObjectSchema(workflow, {
        ...createSharedWorkerDecisionFields(),
        ...(0, decision_contract_schema_1.createWorkerPlanningDecisionFields)(),
        selection: createWorkerSelectionDecisionField(),
        ...createWorkflowWorkerDecisionFields(workflowSchema, {
            workflow,
            includeContinuation: true,
            includeFollowupRecommendation: isWorkflowFollowupRecommendationEnabled(workflow),
            followupMaxIssuesPerSource: workflow?.followupMaxIssuesPerSource,
        }),
    });
}
function buildStepBatchReconciliationWorkerDecisionSchema(workflow) {
    const workflowSchema = buildWorkflowSchema(workflow);
    return buildWorkerDecisionObjectSchema(workflow, {
        ...createSharedWorkerDecisionFields(),
        stepResults: zod_1.z.array(decision_contract_schema_1.workerStepDecisionResultSchema).min(1).meta({
            description: "Final per-step results for every reconciled workflow step in the batch.",
        }),
        ...createWorkflowWorkerDecisionFields(workflowSchema, {
            workflow,
            includeContinuation: true,
            includeFollowupRecommendation: isWorkflowFollowupRecommendationEnabled(workflow),
            followupMaxIssuesPerSource: workflow.followupMaxIssuesPerSource,
        }),
    });
}
function buildWorkflowClosingWorkerDecisionSchema(workflow) {
    const workflowSchema = buildWorkflowSchema(workflow);
    return buildWorkerDecisionObjectSchema(workflow, {
        ...createSharedWorkerDecisionFields(),
        ...createWorkflowWorkerDecisionFields(workflowSchema, {
            workflow,
            includeContinuation: true,
            includeFollowupRecommendation: isWorkflowFollowupRecommendationEnabled(workflow),
            followupMaxIssuesPerSource: workflow.followupMaxIssuesPerSource,
        }),
    });
}
function buildWorkerDecisionPromptSchema(workflow) {
    if (!isWorkflowExecuteWorkflow(workflow) &&
        !isWorkflowStepBatchReconciliationWorkflow(workflow) &&
        !isWorkflowClosingWorkflow(workflow)) {
        const promptSchema = (0, structured_contract_support_1.toWorkerPromptJsonSchema)(buildWorkerDecisionObjectSchema(workflow, createWorkerDecisionPromptFields(workflow)));
        return isWorkflowPlanWorkflow(workflow)
            ? stripPlanPatchPromptSchemaDescriptions(promptSchema)
            : promptSchema;
    }
    const { priorityRank: _priorityRank, ...sharedFields } = createSharedWorkerDecisionFields();
    const workflowFields = isWorkflowStepBatchReconciliationWorkflow(workflow)
        ? {
            stepResults: zod_1.z.array(decision_contract_schema_1.workerStepDecisionResultSchema).min(1),
            ...createWorkflowWorkerDecisionFields(buildWorkflowSchema(workflow), {
                workflow,
                includeContinuation: true,
                includeFollowupRecommendation: isWorkflowFollowupRecommendationEnabled(workflow),
                followupMaxIssuesPerSource: workflow.followupMaxIssuesPerSource,
            }),
        }
        : createWorkflowWorkerDecisionFields(buildWorkflowSchema(workflow), {
            workflow,
            includeContinuation: true,
            includeFollowupRecommendation: isWorkflowFollowupRecommendationEnabled(workflow),
            followupMaxIssuesPerSource: workflow.followupMaxIssuesPerSource,
        });
    return stripWorkflowExecutePromptSchemaDescriptions((0, structured_contract_support_1.toWorkerPromptJsonSchema)(buildWorkerDecisionObjectSchema(workflow, {
        ...sharedFields,
        ...workflowFields,
    })));
}
const WORKFLOW_EXECUTE_PROMPT_SCHEMA_DESCRIPTION_PATHS = new Set([
    "properties.result.properties.resultSummary",
    "properties.result.properties.evidence",
    "properties.result.properties.humanComment.anyOf.0",
]);
function stripPlanPatchPromptSchemaDescriptions(schema) {
    return stripPromptSchemaDescriptionsUnderPath(schema, [
        "properties",
        "planPatch",
    ]);
}
function stripPromptSchemaDescriptionsUnderPath(value, targetPath, path = [], stripping = false) {
    if (Array.isArray(value)) {
        return value.map((entry, index) => stripPromptSchemaDescriptionsUnderPath(entry, targetPath, [...path, String(index)], stripping || isPathPrefix(path, targetPath)));
    }
    if (value === null || typeof value !== "object") {
        return value;
    }
    const shouldStrip = stripping || isPathPrefix(path, targetPath);
    return Object.fromEntries(Object.entries(value).flatMap(([key, entry]) => {
        if (shouldStrip && key === "description") {
            return [];
        }
        return [
            [
                key,
                stripPromptSchemaDescriptionsUnderPath(entry, targetPath, [...path, key], shouldStrip),
            ],
        ];
    }));
}
function isPathPrefix(path, target) {
    return target.every((part, index) => path[index] === part);
}
function stripWorkflowExecutePromptSchemaDescriptions(schema) {
    return stripPromptSchemaDescriptions(schema);
}
function stripPromptSchemaDescriptions(value, path = []) {
    if (Array.isArray(value)) {
        return value.map((entry, index) => stripPromptSchemaDescriptions(entry, [...path, String(index)]));
    }
    if (value === null || typeof value !== "object") {
        return value;
    }
    return Object.fromEntries(Object.entries(value).flatMap(([key, entry]) => {
        if (key === "description" &&
            !WORKFLOW_EXECUTE_PROMPT_SCHEMA_DESCRIPTION_PATHS.has(path.join("."))) {
            return [];
        }
        return [[key, stripPromptSchemaDescriptions(entry, [...path, key])]];
    }));
}
function buildWorkflowSelectionWorkerDecisionSchema(workflow) {
    const workflowSchema = buildWorkflowSchema(workflow);
    return buildWorkerDecisionObjectSchema(workflow, {
        ...createSharedWorkerDecisionFields(),
        selection: createWorkerSelectionDecisionField(),
        ...createWorkflowWorkerDecisionFields(workflowSchema, {
            workflow,
            includeContinuation: true,
            includeFollowupRecommendation: false,
        }),
    });
}
function createWorkerDecisionPromptFields(workflow) {
    const workflowSchema = buildWorkflowSchema(workflow);
    const workflowFields = createWorkflowWorkerDecisionFields(workflowSchema, {
        workflow,
        includeContinuation: false,
        includeFollowupRecommendation: false,
    });
    if (isWorkflowSelectionWorkflow(workflow)) {
        return {
            ...createSharedWorkerDecisionFields(),
            selection: createWorkerSelectionDecisionField(),
            ...workflowFields,
        };
    }
    return {
        ...createSharedWorkerDecisionFields(),
        ...(0, decision_contract_schema_1.createWorkerPlanningDecisionFields)(getPromptPlanningDecisionFieldOptions(workflow)),
        selection: createWorkerSelectionDecisionField(),
        ...workflowFields,
    };
}
function getPromptPlanningDecisionFieldOptions(workflow) {
    if (!isWorkflowPlanWorkflow(workflow)) {
        return undefined;
    }
    const isReplanning = workflow.planningIntent === "replan" ||
        workflow.planningIntent === "revise_plan";
    return {
        includePlan: !isReplanning,
        includePlanPatch: isReplanning,
    };
}
function buildWorkerDecisionObjectSchema(workflow, fields) {
    return zod_1.z
        .object(fields)
        .strict()
        .superRefine((decision, context) => (0, decision_contract_support_1.validateWorkerDecisionSemanticRules)(decision, workflow, context));
}
function createSharedWorkerDecisionFields() {
    return {
        outcome: zod_1.z
            .enum([
            constants_1.WORKER_OUTCOMES.proceed,
            constants_1.WORKER_OUTCOMES.waitHuman,
            constants_1.WORKER_OUTCOMES.fail,
        ])
            .meta({
            description: "Worker outcome. Must be proceed, wait_human, or fail.",
        }),
        result: decision_contract_schema_1.workerDecisionResultSchema.meta({
            description: "Structured worker result fields.",
        }),
        commitMessage: zod_1.z
            .string()
            .max(decision_contract_schema_1.WORKER_DECISION_SCHEMA_LIMITS.commitMessageCharacters)
            .nullable()
            .optional()
            .meta({
            description: "Optional commit message. Use null only when explicitly present.",
        }),
        priorityRank: zod_1.z
            .number()
            .int()
            .safe()
            .nonnegative()
            .nullable()
            .optional()
            .meta({
            description: "Optional workflow planning priority. Use null or a non-negative safe integer.",
        }),
    };
}
function createWorkerSelectionDecisionField() {
    return decision_contract_schema_1.workerSelectionSchema.nullable().optional().meta({
        description: "Workflow selection. Required for selection proceed decisions. Decide whether to use a repository-specific candidate template, use the built-in default workflow, or request a missing reusable template for the active workflow surface only when the template slot is auto.",
    });
}
function createWorkflowWorkerDecisionFields(workflowSchema, options) {
    return {
        ...(options.includeContinuation
            ? {
                continuation: decision_contract_schema_1.workerContinuationSchema.optional().meta({
                    description: "Only allowed when outcome is proceed and workflow mode is workflow_execute, workflow_reconcile_step_batch, or workflow_closing.",
                }),
            }
            : {}),
        needsHumanReason: createWorkerNeedsHumanReasonSchema(options.workflow),
        ...(options.includeFollowupRecommendation
            ? {
                followupRecommendation: (0, decision_contract_schema_1.createWorkerFollowupRecommendationSchema)(options.followupMaxIssuesPerSource ??
                    types_1.DEFAULT_WORKFLOW_FOLLOWUP_MAX_ISSUES_PER_SOURCE, options.workflow?.state?.followup?.proposalApproval ?? "auto")
                    .optional()
                    .meta({
                    description: "Optional closing follow-up recommendation. Omit unless follow-up proposal policy is enabled and the source issue is completing.",
                }),
            }
            : {}),
        workflow: workflowSchema,
    };
}
function createWorkerNeedsHumanReasonSchema(workflow) {
    if (isWorkflowReviewReadyAllowed(workflow)) {
        return zod_1.z.enum(types_2.WORKER_HUMAN_REASONS).optional().meta({
            description: "Only allowed when outcome is wait_human.",
        });
    }
    return zod_1.z
        .enum(["question"])
        .optional()
        .meta({
        description: "Only allowed when outcome is wait_human.",
    });
}
function isWorkflowReviewReadyAllowed(workflow) {
    return (isWorkflowClosingWorkflow(workflow) &&
        !(workflow?.workflowSurface === "issue" &&
            workflow.issueCompletion?.target === "pull_request"));
}
function isWorkflowSelectionWorkflow(workflow) {
    return workflow?.mode === types_2.WORKER_RUN_MODES.workflowSelect;
}
function isWorkflowExecuteWorkflow(workflow) {
    return workflow?.mode === types_2.WORKER_RUN_MODES.workflowExecute;
}
function isWorkflowPlanWorkflow(workflow) {
    return workflow?.mode === types_2.WORKER_RUN_MODES.workflowPlan;
}
function isWorkflowStepBatchReconciliationWorkflow(workflow) {
    return workflow?.mode === types_2.WORKER_RUN_MODES.workflowReconcileStepBatch;
}
function isWorkflowClosingWorkflow(workflow) {
    return workflow?.mode === types_2.WORKER_RUN_MODES.workflowClosing;
}
function isWorkflowFollowupRecommendationEnabled(workflow) {
    return (isWorkflowClosingWorkflow(workflow) &&
        workflow.state?.followup !== undefined &&
        workflow.state.followup.proposalPolicy !== "off");
}
function buildWorkflowSchema(workflow) {
    if (!workflow) {
        return decision_contract_schema_1.workerWorkflowMetadataSchema.nullable().optional();
    }
    return zod_1.z
        .object({
        mode: zod_1.z.literal(workflow.mode),
        templateName: zod_1.z.literal(workflow.templateName),
    })
        .strict();
}
function toWorkerDecisionValidationIssues(error) {
    if (!(error instanceof zod_1.z.ZodError)) {
        return [
            {
                path: [],
                code: "invalid_json",
                message: formatValidationMessage(error),
            },
        ];
    }
    return error.issues.map((issue) => normalizeZodIssue(issue));
}
function formatWorkerDecisionValidationIssues(issues) {
    if (issues.length === 0) {
        return "No validation issues were reported.";
    }
    return issues
        .map((issue) => {
        const path = issue.path.length > 0 ? issue.path.join(".") : "(root)";
        return `${path}: ${issue.code}: ${issue.message}`;
    })
        .join("; ");
}
function normalizeZodIssue(issue) {
    return {
        path: issue.path,
        code: issue.code,
        message: issue.message,
    };
}
function formatValidationMessage(error) {
    if (error instanceof Error) {
        return error.message;
    }
    return String(error);
}
