/**
 * Assertion mapping and builders for agent harness tasks.
 *
 * Handles agent-specific assertion types (file-exists, file-contains,
 * command-succeeds, diff-matches) as well as standard pass-through
 * assertion types.
 *
 * Templated LLM-rubric assertions (those with `template` + `criteria`)
 * are resolved via the shared rubric-resolution module, producing fully
 * assembled rubric text and dimension metadata. This is critical for
 * scoring — without it, the grader receives empty rubrics and the
 * scoring pipeline has no dimension data to work with (DOC-2029).
 *
 * Agent-specific assertions use file-based references to the assertions
 * runtime module (dist/agent-harness/assertions-runtime.js) because
 * promptfoo's inline `type: javascript` assertions run in a restricted
 * eval() sandbox where require() is unavailable. File-based assertions
 * run in a full Node.js context.
 *
 * @see https://www.promptfoo.dev/docs/configuration/expected-outputs/javascript/
 * @see src/agent-harness/assertions-runtime.ts — runtime implementations
 */
import { resolveTemplatedAssertion } from "../../rubric-resolution.js";
/** Base path for the file-based assertion runtime module */
const RUNTIME = "file://dist/agent-harness/assertions-runtime.js";
// ---------------------------------------------------------------------------
// Assertion mapping
// ---------------------------------------------------------------------------
export function mapAgentAssertion(assertion, options, warnings) {
    switch (assertion.type) {
        case "file-exists":
            return buildFileExistsAssertion(assertion);
        case "file-contains":
            return buildFileContainsAssertion(assertion);
        case "command-succeeds":
            return buildCommandSucceedsAssertion(assertion);
        case "diff-matches":
            return buildDiffMatchesAssertion(assertion);
        // Standard assertions pass through
        case "contains":
        case "equals":
        case "regex":
        case "is-json":
        case "javascript":
        case "python":
            return {
                type: assertion.type,
                ...("value" in assertion ? { value: assertion.value } : {}),
            };
        case "llm-rubric":
            // Templated assertions (template + criteria) need full resolution
            // to produce rubric text and dimension metadata for scoring.
            if ("template" in assertion && "criteria" in assertion) {
                const resolved = resolveTemplatedAssertion(assertion, options?.rubricConfig, options?.graderProvider, warnings);
                return resolved;
            }
            // Non-templated llm-rubric (inline value) — pass through
            return {
                type: "llm-rubric",
                ...("value" in assertion ? { value: assertion.value } : {}),
                ...(options?.graderProvider
                    ? { provider: options.graderProvider }
                    : {}),
            };
        default:
            warnings.push(`Agent task: unknown assertion type "${assertion.type}" — passed through`);
            return {
                type: assertion.type,
                ...("value" in assertion ? { value: assertion.value } : {}),
            };
    }
}
// ---------------------------------------------------------------------------
// Agent-specific assertion builders
//
// Each builder returns a file-based assertion referencing the runtime
// module with parameters passed via the `config` field.
// ---------------------------------------------------------------------------
export function buildFileExistsAssertion(assertion) {
    return {
        type: "javascript",
        value: `${RUNTIME}:fileExists`,
        config: { filePath: String(assertion.value ?? "") },
    };
}
export function buildFileContainsAssertion(assertion) {
    const val = assertion.value;
    return {
        type: "javascript",
        value: `${RUNTIME}:fileContains`,
        config: {
            filePath: val?.path ?? "",
            content: val?.content ?? "",
        },
    };
}
/**
 * SECURITY: Trusted-input boundary.
 *
 * The `command-succeeds` assertion executes an arbitrary shell command
 * inside the sandbox's working directory. The command string comes from
 * task definitions (YAML or TypeScript config files), which are authored
 * by developers — not from user input or LLM output.
 *
 * This is intentional: the assertion is designed to verify agent output
 * by running build/test commands (e.g., "npm test", "tsc --noEmit").
 *
 * Task definitions are the trust boundary. If you accept task definitions
 * from untrusted sources, validate commands against an allowlist first.
 */
export function buildCommandSucceedsAssertion(assertion) {
    return {
        type: "javascript",
        value: `${RUNTIME}:commandSucceeds`,
        config: { command: String(assertion.value ?? "") },
    };
}
export function buildDiffMatchesAssertion(assertion) {
    return {
        type: "javascript",
        value: `${RUNTIME}:diffMatches`,
        config: {
            ...(assertion.value != null ? { expected: assertion.value } : {}),
        },
    };
}
