/**
 * TaskClassifier — maps a task prompt to a stable taskPattern slug.
 *
 * Per `specs/provider-portability/10-suggest-and-confirm-ux.md`, the
 * taskPattern is the cache key Phase 5b uses to look up a previously-
 * confirmed framework+model pick. The pattern needs to be:
 *
 *   - Stable: two requests for "refactor the imessage adapter" and
 *     "refactor the threadline router" both classify to
 *     `code-refactor-typescript` (or similar) so the user doesn't
 *     get re-asked for each refactor.
 *
 *   - Narrow: distinct task shapes get distinct patterns. "summarize
 *     this meeting transcript" is NOT the same as "write a function
 *     that summarizes meetings."
 *
 * Implementation: fast-tier LLM call (Haiku-class) with a curated
 * one-shot prompt that emits a single-line slug. Errors collapse to
 * a sentinel pattern that the UX layer treats as a new pattern —
 * which produces an ask, never a silent-use against a bad cache key.
 */
// ---------------------------------------------------------------------------
// Sentinel
// ---------------------------------------------------------------------------
/**
 * Sentinel returned when classification fails (LLM error, unparseable
 * output, etc.). The TriggerGate treats this as a never-seen pattern,
 * which produces an ask — the safe outcome.
 */
export const UNCLASSIFIED_PATTERN = 'unclassified';
// ---------------------------------------------------------------------------
// Default prompt
// ---------------------------------------------------------------------------
const DEFAULT_PROMPT_TEMPLATE = `\
You classify user tasks into stable kebab-case slugs that group tasks of the same shape.

Examples of valid slugs:
  code-refactor-typescript
  code-debug-python
  code-review-pull-request
  summarize-meeting-transcript
  draft-email-followup
  research-technical-deep-dive
  shell-one-liner
  schema-migration-plan

Rules:
  - Lowercase, hyphen-separated, no spaces.
  - 2-4 segments, most general → most specific.
  - Stable: two tasks of the same shape MUST classify the same slug.
  - Output ONLY the slug. No quotes, no explanation, no leading words.

Task:
{{TASK}}

Slug:`;
// ---------------------------------------------------------------------------
// Implementation
// ---------------------------------------------------------------------------
const SLUG_RE = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
export class TaskClassifier {
    intelligence;
    promptTemplate;
    maxTokens;
    constructor(options) {
        this.intelligence = options.intelligence;
        this.promptTemplate = options.promptTemplate ?? DEFAULT_PROMPT_TEMPLATE;
        this.maxTokens = options.maxTokens ?? 16;
    }
    async classify(input) {
        const taskPayload = this.formatTask(input);
        const prompt = this.promptTemplate.replace('{{TASK}}', taskPayload);
        let raw;
        try {
            raw = await this.intelligence.evaluate(prompt, {
                model: 'fast',
                maxTokens: this.maxTokens,
                temperature: 0,
                attribution: { component: 'TaskClassifier' },
            });
        }
        catch {
            return { taskPattern: UNCLASSIFIED_PATTERN, source: 'fallback' };
        }
        const slug = this.parseSlug(raw);
        if (slug === null) {
            return { taskPattern: UNCLASSIFIED_PATTERN, source: 'fallback' };
        }
        return { taskPattern: slug, source: 'ok' };
    }
    formatTask(input) {
        const tags = input.tags && input.tags.length > 0
            ? `\n(tags: ${input.tags.join(', ')})`
            : '';
        // Truncate very long prompts — classifier only needs the shape, not
        // the body. 800 chars is generous for shape detection.
        const truncated = input.prompt.length > 800
            ? input.prompt.slice(0, 800) + ' …'
            : input.prompt;
        return truncated + tags;
    }
    parseSlug(raw) {
        const cleaned = raw
            .trim()
            .toLowerCase()
            // Strip leading "slug:" the model sometimes emits despite instructions.
            .replace(/^slug\s*:\s*/, '')
            // Strip wrapping quotes / backticks if any.
            .replace(/^["'`]+|["'`]+$/g, '')
            .trim();
        // Slug must match the strict pattern AND be reasonable length.
        if (!SLUG_RE.test(cleaned))
            return null;
        if (cleaned.length < 3 || cleaned.length > 80)
            return null;
        // Reject the sentinel coming back from the LLM — that's a model
        // artifact, not a real classification.
        if (cleaned === UNCLASSIFIED_PATTERN)
            return null;
        return cleaned;
    }
}
//# sourceMappingURL=TaskClassifier.js.map