/**
 * DeepSeekAdapter -- DeepSeek REST API transport adapter.
 *
 * Implements LlmProviderAdapter for the DeepSeek chat-completions wire
 * format. DeepSeek's HTTP API is OpenAI-compatible, but this adapter
 * implements the wire shape directly (rather than reusing OpenAIAdapter)
 * so that:
 *   - provider-compliance binds 'deepseek' as a separate providerId
 *     (sovereignty: 'cn'). Pack rules can target DeepSeek independently
 *     of OpenAI / Azure.
 *   - the fail-closed `blockedProviders: ['deepseek', ...]` policy on
 *     DORA, EU MDR/IVDR, US FDA 21 CFR 56, UK AI Framework, Illinois
 *     AIVIA, EU DSA, NIS2, NHS DTAC, ISO 20022, UK Equality Act, and
 *     others fires through BaseProviderAdapter.initialize() on
 *     activePacks consultation.
 *   - the spec-compliance suite + provider-compliance registry can audit
 *     DeepSeek the same way they audit Anthropic / OpenAI / Bedrock /
 *     Google / Ollama.
 *
 * Wire format:
 *   POST <baseUrl>/chat/completions
 *   GET  <baseUrl>/models
 *
 * Auth:
 *   Authorization: Bearer <apiKey>  (required)
 *
 * Streaming: Server-Sent Events. Each `data:` line carries a JSON chunk
 * matching the OpenAI streaming shape; final marker is `data: [DONE]`.
 *
 * Tool use: OpenAI-shape tools array in request, tool_calls array in
 * response (function calling). Same wire format as the openai npm SDK
 * because DeepSeek is OpenAI-compatible by design.
 *
 * BAA / Sovereignty:
 *   - DeepSeek does NOT offer a HIPAA BAA.
 *   - sovereignty: 'cn' (data sovereignty under PRC jurisdiction).
 *   - PRC National Intelligence Law concerns mean multiple regulated
 *     packs block this provider entirely. The pack-binding gate runs
 *     in BaseProviderAdapter.initialize() and refuses to construct an
 *     adapter instance when a blocking pack is active.
 *
 * Spec: P3-SUB-01 AC 1-3, 22-27 (LLM Provider Adapter SDK contract)
 * Closes: F-NEW-DEEPSEEK-ADAPTER (source-side adapter parity with
 *         Anthropic / OpenAI / Bedrock / Google / Gemma / Ollama).
 *
 * @connexum/ai-governance
 */
import * as https from 'https';
import * as http from 'http';
import { URL } from 'url';
import { BaseProviderAdapter, registerProviderCompliance, getProviderCompliance } from './base.js';
import { LlmProviderError, LlmAuthError, LlmRateLimitError, LlmModelNotFoundError, } from './index.js';
import { coerceTextContent, detectUnexpectedShape, normalizeToolUseRequest, normalizeToolUseResponse, parseRetryAfterMs, } from './shared.js';
// ---------------------------------------------------------------------------
// Constants (AC 26 -- version pinning)
// ---------------------------------------------------------------------------
/**
 * DeepSeek API version this adapter was tested against.
 *
 * DeepSeek does not publish a formal versioned URL prefix or
 * `Api-Version` response header; the public docs simply reference the
 * `/chat/completions` endpoint at `api.deepseek.com`. We pin to the
 * docs revision date the wire shape was captured against. Re-verify
 * against https://api-docs.deepseek.com/ when bumping.
 *
 * TODO (Vera/Legal, Wire): Confirm pinned date matches the live
 * upstream docs page on the next quarterly review. Flag
 * DEFERRED-DEEPSEEK-API-VERSION.
 */
export const TESTED_API_VERSION = '2025-01-20';
/** Official DeepSeek API base URL. */
const DEFAULT_BASE_URL = 'https://api.deepseek.com';
const DEEPSEEK_MODELS = [
    {
        modelId: 'deepseek-chat',
        family: 'unknown', // No 'deepseek' family in the canonical list yet.
        displayName: 'DeepSeek-V3 (deepseek-chat)',
        contextWindow: 64_000,
        reasoningMode: false,
    },
    {
        modelId: 'deepseek-reasoner',
        family: 'unknown',
        displayName: 'DeepSeek-R1 (reasoning)',
        contextWindow: 64_000,
        reasoningMode: true,
    },
    {
        modelId: 'deepseek-coder',
        family: 'unknown',
        displayName: 'DeepSeek-Coder',
        contextWindow: 128_000,
        reasoningMode: false,
    },
];
const KNOWN_DEEPSEEK_MODELS = new Set(DEEPSEEK_MODELS.map((m) => m.modelId));
/** Look up reasoning-mode flag for a given model id. */
export function isDeepSeekReasoningModel(modelId) {
    const meta = DEEPSEEK_MODELS.find((m) => m.modelId === modelId);
    return meta?.reasoningMode ?? false;
}
function httpRequest(urlStr, method, headers, body, timeoutMs) {
    return new Promise((resolve, reject) => {
        let url;
        try {
            url = new URL(urlStr);
        }
        catch {
            reject(new Error(`Invalid URL: ${urlStr}`));
            return;
        }
        const isHttps = url.protocol === 'https:';
        const transport = isHttps ? https : http;
        const reqHeaders = { ...headers };
        if (body !== null) {
            reqHeaders['Content-Length'] = Buffer.byteLength(body).toString();
        }
        const options = {
            hostname: url.hostname,
            port: url.port || (isHttps ? 443 : 80),
            path: url.pathname + url.search,
            method,
            headers: reqHeaders,
        };
        const req = transport.request(options, (res) => {
            const chunks = [];
            res.on('data', (chunk) => chunks.push(chunk));
            res.on('end', () => {
                resolve({
                    statusCode: res.statusCode ?? 0,
                    headers: res.headers,
                    body: Buffer.concat(chunks).toString('utf-8'),
                });
            });
            res.on('error', reject);
        });
        req.setTimeout(timeoutMs, () => {
            req.destroy(new Error(`Request timed out after ${timeoutMs}ms`));
        });
        req.on('error', reject);
        if (body !== null) {
            req.write(body);
        }
        req.end();
    });
}
// ---------------------------------------------------------------------------
// Register DeepSeek compliance metadata on module load (AC 19)
// ---------------------------------------------------------------------------
//
// sovereignty: 'cn' is the type-system value for the PRC sovereignty
// scope. Pack policy reads providerId='deepseek' and applies the
// blockedProviders gate at runtime via BaseProviderAdapter.initialize().
//
// baa: false    -- DeepSeek offers no HIPAA BAA.
// gdprDpa: false -- no published DPA; treated as fail-closed for EU
//                   workloads.
// soc2Type2: false -- no public SOC 2 Type II report.
// reviewCadence: '90d' -- short cadence due to PRC jurisdictional
//                          volatility.
registerProviderCompliance({
    providerId: 'deepseek',
    baa: false,
    gdprDpa: false,
    soc2Type2: false,
    sovereignty: 'cn',
    attestationUrl: 'https://platform.deepseek.com/api-docs/',
    attestationDate: '2026-05-09',
    reviewCadence: '90d',
    baaNote: 'DeepSeek is a PRC-based provider. No HIPAA BAA. Subject to PRC ' +
        'National Intelligence Law (Article 7). Multiple compliance packs ' +
        '(DORA, EU MDR/IVDR, US FDA 21 CFR 56, UK AI Framework, Illinois ' +
        'AIVIA, EU DSA, NIS2, NHS DTAC, ISO 20022, UK Equality Act) block ' +
        'this provider via blockedProviders pack policy.',
});
// ---------------------------------------------------------------------------
// DeepSeekAdapter
// ---------------------------------------------------------------------------
export class DeepSeekAdapter extends BaseProviderAdapter {
    adapterId = 'deepseek';
    providerId = 'deepseek';
    deepseekConfig = null;
    // ---------------------------------------------------------------------------
    // Lifecycle
    // ---------------------------------------------------------------------------
    initialize(config) {
        const cfg = config;
        // Auth gate: DeepSeek requires a Bearer token. Throw synchronously
        // (no network call) per LlmProviderAdapter contract.
        if (!cfg.apiKey || typeof cfg.apiKey !== 'string' || cfg.apiKey.trim().length === 0) {
            throw new LlmAuthError({
                message: 'DeepSeekAdapter: apiKey is required. Provide a non-empty string ' +
                    '(set the DEEPSEEK_API_KEY environment variable and pass it through).',
                providerId: this.providerId,
                adapterId: this.adapterId,
            });
        }
        // Validate baseUrl if explicitly provided.
        const baseUrl = cfg.baseUrl ?? DEFAULT_BASE_URL;
        try {
            new URL(baseUrl);
        }
        catch {
            throw new LlmAuthError({
                message: `DeepSeekAdapter: baseUrl '${baseUrl}' is not a valid URL.`,
                providerId: this.providerId,
                adapterId: this.adapterId,
            });
        }
        // BaseProviderAdapter.initialize() consults ProviderCompliance.check()
        // when activePacks is non-empty and refuses to initialize when DeepSeek
        // is blocked by an active pack. This is the single fail-closed gate
        // for the PRC-jurisdiction packs above.
        super.initialize({ ...config, baseUrl });
        this.deepseekConfig = { ...cfg, baseUrl };
    }
    // ---------------------------------------------------------------------------
    // URL builder
    // ---------------------------------------------------------------------------
    buildUrl(path) {
        const base = (this.deepseekConfig?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
        return `${base}${path}`;
    }
    authHeaders() {
        const apiKey = this.deepseekConfig?.apiKey ?? '';
        return {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'Authorization': `Bearer ${apiKey}`,
        };
    }
    // ---------------------------------------------------------------------------
    // Message conversion: LlmMessage[] -> DeepSeekMessage[]
    // ---------------------------------------------------------------------------
    convertMessages(request) {
        const messages = [];
        if ('systemPrompt' in request && request.systemPrompt) {
            messages.push({ role: 'system', content: request.systemPrompt });
        }
        for (const msg of request.messages) {
            // DeepSeek (text-only OpenAI-compatible API) does not support image
            // parts. Reject array content with image_url at the boundary.
            const text = coerceTextContent(msg, {
                providerId: this.providerId,
                adapterId: this.adapterId,
            });
            const out = {
                role: msg.role,
                content: text,
            };
            if (msg.toolCallId) {
                out.tool_call_id = msg.toolCallId;
            }
            messages.push(out);
        }
        return messages;
    }
    // ---------------------------------------------------------------------------
    // Validate model ID
    // ---------------------------------------------------------------------------
    validateModelId(modelId) {
        if (!modelId || typeof modelId !== 'string') {
            throw new LlmModelNotFoundError({
                message: `DeepSeekAdapter: invalid modelId '${modelId}'. Provide a non-empty ` +
                    `string (e.g. 'deepseek-chat', 'deepseek-reasoner', 'deepseek-coder').`,
                providerId: this.providerId,
                adapterId: this.adapterId,
                requestedModelId: String(modelId ?? ''),
            });
        }
    }
    // ---------------------------------------------------------------------------
    // chat (POST /chat/completions, non-streaming)
    // ---------------------------------------------------------------------------
    async chat(request) {
        this.ensureInitialized();
        this.validateModelId(request.modelId);
        return this.withRetry(async () => this.chatOnce(request));
    }
    async chatOnce(request) {
        const messages = this.convertMessages(request);
        const payload = {
            model: request.modelId,
            messages,
            stream: false,
            max_tokens: request.maxTokens,
            temperature: request.temperature,
        };
        if (request.tools && request.tools.length > 0) {
            const normalized = normalizeToolUseRequest(request.tools, 'openai');
            payload.tools = normalized;
        }
        const url = this.buildUrl('/chat/completions');
        const rawBody = JSON.stringify(payload);
        const timeoutMs = this.deepseekConfig?.timeoutMs ?? 30_000;
        const response = await httpRequest(url, 'POST', this.authHeaders(), rawBody, timeoutMs);
        this.handleHttpErrors(response, request.modelId);
        let parsed;
        try {
            parsed = JSON.parse(response.body);
        }
        catch {
            throw new LlmProviderError({
                message: 'DeepSeekAdapter: failed to parse response as JSON',
                code: 'UNEXPECTED_RESPONSE_SHAPE',
                providerId: this.providerId,
                adapterId: this.adapterId,
                raw: response.body.slice(0, 500),
            });
        }
        detectUnexpectedShape(parsed, ['choices'], this.providerId, this.adapterId);
        const choice = parsed.choices[0];
        if (!choice) {
            throw new LlmProviderError({
                message: 'DeepSeekAdapter: response.choices is empty',
                code: 'UNEXPECTED_RESPONSE_SHAPE',
                providerId: this.providerId,
                adapterId: this.adapterId,
                raw: JSON.stringify(parsed).slice(0, 500),
            });
        }
        const content = choice.message?.content ?? '';
        const rawToolCalls = choice.message?.tool_calls ?? [];
        const toolCalls = rawToolCalls.length > 0
            ? normalizeToolUseResponse(rawToolCalls, 'openai')
            : undefined;
        const usage = parsed.usage
            ? {
                inputTokens: parsed.usage.prompt_tokens,
                outputTokens: parsed.usage.completion_tokens,
                totalTokens: parsed.usage.total_tokens,
            }
            : undefined;
        return {
            modelId: parsed.model ?? request.modelId,
            content: typeof content === 'string' ? content : '',
            finishReason: this.mapFinishReason(choice.finish_reason),
            toolCalls,
            usage,
            _raw: parsed,
        };
    }
    // ---------------------------------------------------------------------------
    // chatStream (POST /chat/completions stream:true, SSE)
    // ---------------------------------------------------------------------------
    async *chatStream(request) {
        this.ensureInitialized();
        this.validateModelId(request.modelId);
        const messages = this.convertMessages(request);
        const payload = {
            model: request.modelId,
            messages,
            stream: true,
            max_tokens: request.maxTokens,
            temperature: request.temperature,
        };
        const url = this.buildUrl('/chat/completions');
        const rawBody = JSON.stringify(payload);
        const headers = {
            ...this.authHeaders(),
            'Accept': 'text/event-stream',
        };
        const timeoutMs = this.deepseekConfig?.timeoutMs ?? 60_000;
        const response = await httpRequest(url, 'POST', headers, rawBody, timeoutMs);
        this.handleHttpErrors(response, request.modelId);
        // Parse SSE: lines starting with "data: " carry JSON; "data: [DONE]"
        // is the stream terminator.
        const lines = response.body.split('\n');
        for (const line of lines) {
            const trimmed = line.trim();
            if (!trimmed)
                continue;
            if (!trimmed.startsWith('data:'))
                continue;
            const payloadStr = trimmed.slice(5).trim();
            if (payloadStr === '[DONE]') {
                return;
            }
            let chunk;
            try {
                chunk = JSON.parse(payloadStr);
            }
            catch {
                continue;
            }
            const choice = chunk.choices?.[0];
            if (!choice)
                continue;
            const delta = choice.delta?.content ?? '';
            const finishReason = choice.finish_reason
                ? this.mapFinishReason(choice.finish_reason)
                : undefined;
            const usage = chunk.usage
                ? {
                    inputTokens: chunk.usage.prompt_tokens,
                    outputTokens: chunk.usage.completion_tokens,
                    totalTokens: chunk.usage.total_tokens,
                }
                : undefined;
            const out = { delta };
            if (finishReason !== undefined)
                out.finishReason = finishReason;
            if (usage !== undefined)
                out.usage = usage;
            yield out;
        }
    }
    // ---------------------------------------------------------------------------
    // invokeToolUse (POST /chat/completions with tools)
    // ---------------------------------------------------------------------------
    async invokeToolUse(request) {
        this.ensureInitialized();
        this.validateModelId(request.modelId);
        return this.withRetry(async () => this.invokeToolUseOnce(request));
    }
    async invokeToolUseOnce(request) {
        if (!request.tools || request.tools.length === 0) {
            throw new LlmProviderError({
                message: 'DeepSeekAdapter.invokeToolUse: at least one tool definition is required.',
                code: 'TOOL_USE_FAILURE',
                providerId: this.providerId,
                adapterId: this.adapterId,
            });
        }
        const messages = this.convertMessages(request);
        const tools = normalizeToolUseRequest(request.tools, 'openai');
        const payload = {
            model: request.modelId,
            messages,
            stream: false,
            tools,
            max_tokens: request.maxTokens,
            temperature: request.temperature,
        };
        const url = this.buildUrl('/chat/completions');
        const rawBody = JSON.stringify(payload);
        const timeoutMs = this.deepseekConfig?.timeoutMs ?? 30_000;
        const response = await httpRequest(url, 'POST', this.authHeaders(), rawBody, timeoutMs);
        this.handleHttpErrors(response, request.modelId);
        let parsed;
        try {
            parsed = JSON.parse(response.body);
        }
        catch {
            throw new LlmProviderError({
                message: 'DeepSeekAdapter: failed to parse tool-use response as JSON',
                code: 'UNEXPECTED_RESPONSE_SHAPE',
                providerId: this.providerId,
                adapterId: this.adapterId,
                raw: response.body.slice(0, 500),
            });
        }
        detectUnexpectedShape(parsed, ['choices'], this.providerId, this.adapterId);
        const choice = parsed.choices[0];
        if (!choice) {
            throw new LlmProviderError({
                message: 'DeepSeekAdapter: response.choices is empty',
                code: 'UNEXPECTED_RESPONSE_SHAPE',
                providerId: this.providerId,
                adapterId: this.adapterId,
                raw: JSON.stringify(parsed).slice(0, 500),
            });
        }
        const rawToolCalls = choice.message?.tool_calls ?? [];
        const toolCalls = normalizeToolUseResponse(rawToolCalls, 'openai');
        const content = typeof choice.message?.content === 'string' ? choice.message.content : undefined;
        const usage = parsed.usage
            ? {
                inputTokens: parsed.usage.prompt_tokens,
                outputTokens: parsed.usage.completion_tokens,
                totalTokens: parsed.usage.total_tokens,
            }
            : undefined;
        return {
            modelId: parsed.model ?? request.modelId,
            toolCalls,
            content: content || undefined,
            finishReason: this.mapFinishReason(choice.finish_reason),
            usage,
            _raw: parsed,
        };
    }
    // ---------------------------------------------------------------------------
    // enumerateModels (GET /models, fallback to known catalog)
    // ---------------------------------------------------------------------------
    async enumerateModels() {
        this.ensureInitialized();
        // DeepSeek exposes /models (OpenAI-compatible). If the call fails or
        // returns an unexpected shape, fall back to the static known-models
        // catalog rather than throwing -- model enumeration is advisory, not
        // critical-path.
        try {
            const url = this.buildUrl('/models');
            const timeoutMs = this.deepseekConfig?.timeoutMs ?? 15_000;
            const response = await httpRequest(url, 'GET', this.authHeaders(), null, timeoutMs);
            if (response.statusCode >= 200 && response.statusCode < 300) {
                const parsed = JSON.parse(response.body);
                const data = Array.isArray(parsed.data) ? parsed.data : [];
                if (data.length > 0) {
                    return data.map((entry) => {
                        const meta = DEEPSEEK_MODELS.find((m) => m.modelId === entry.id);
                        return {
                            modelId: entry.id,
                            family: meta?.family ?? 'unknown',
                            displayName: meta?.displayName ?? entry.id,
                            ...(meta?.contextWindow !== undefined
                                ? { contextWindow: meta.contextWindow }
                                : {}),
                            deprecated: meta?.deprecated ?? false,
                        };
                    });
                }
            }
        }
        catch {
            // Fall through to static catalog.
        }
        return DEEPSEEK_MODELS.map((m) => ({
            modelId: m.modelId,
            family: m.family,
            displayName: m.displayName,
            contextWindow: m.contextWindow,
            deprecated: m.deprecated ?? false,
        }));
    }
    // ---------------------------------------------------------------------------
    // translateError
    // ---------------------------------------------------------------------------
    translateError(raw) {
        if (raw instanceof LlmProviderError)
            return raw;
        const isObj = (v) => typeof v === 'object' && v !== null;
        let httpStatus;
        let errorMessage;
        let errorBody;
        if (isObj(raw)) {
            httpStatus = typeof raw['status'] === 'number' ? raw['status'] : undefined;
            const err = raw['error'];
            if (typeof err === 'string') {
                errorMessage = err;
            }
            else if (isObj(err)) {
                errorBody = err;
                errorMessage = typeof err['message'] === 'string' ? err['message'] : undefined;
            }
        }
        else if (raw instanceof Error) {
            errorMessage = raw.message;
        }
        else {
            errorMessage = String(raw);
        }
        const rawStr = isObj(raw) ? JSON.stringify(raw).slice(0, 500) : String(raw).slice(0, 500);
        if (httpStatus === 401 || httpStatus === 403) {
            return new LlmAuthError({
                message: errorMessage ?? `DeepSeek auth failure (HTTP ${httpStatus})`,
                providerId: this.providerId,
                adapterId: this.adapterId,
                httpStatus,
                raw: rawStr,
            });
        }
        if (httpStatus === 429) {
            return new LlmRateLimitError({
                message: errorMessage ?? 'DeepSeek rate limit exceeded',
                providerId: this.providerId,
                adapterId: this.adapterId,
                httpStatus,
                retryAfterMs: 1_000,
                raw: rawStr,
            });
        }
        if (httpStatus === 404 ||
            (errorBody && errorBody['code'] === 'model_not_found') ||
            (errorMessage && errorMessage.toLowerCase().includes('model'))) {
            const requestedModelId = this.deepseekConfig?.defaultModelId ?? 'unknown';
            return new LlmModelNotFoundError({
                message: errorMessage ?? `DeepSeek model not found (HTTP ${httpStatus ?? 'unknown'})`,
                providerId: this.providerId,
                adapterId: this.adapterId,
                httpStatus,
                requestedModelId,
                raw: rawStr,
            });
        }
        return new LlmProviderError({
            message: errorMessage ?? `DeepSeek error (HTTP ${httpStatus ?? 'unknown'})`,
            code: 'PROVIDER_ERROR',
            providerId: this.providerId,
            adapterId: this.adapterId,
            httpStatus,
            raw: rawStr,
        });
    }
    // ---------------------------------------------------------------------------
    // getCapabilities
    // ---------------------------------------------------------------------------
    getCapabilities() {
        return {
            chat: true,
            streaming: true,
            toolUse: true,
            modelEnumeration: true, // GET /models
            baa: false,
            multimodal: false,
        };
    }
    // ---------------------------------------------------------------------------
    // Private helpers
    // ---------------------------------------------------------------------------
    handleHttpErrors(response, requestedModelId) {
        if (response.statusCode >= 200 && response.statusCode < 300)
            return;
        let errorBody = null;
        try {
            errorBody = JSON.parse(response.body);
        }
        catch {
            // Body may not be JSON (e.g. nginx 502 HTML); swallow and report
            // the raw status.
        }
        const isObj = (v) => typeof v === 'object' && v !== null;
        let errorMessage;
        let errorCode;
        if (isObj(errorBody)) {
            const err = errorBody['error'];
            if (isObj(err)) {
                if (typeof err['message'] === 'string')
                    errorMessage = err['message'];
                if (typeof err['code'] === 'string')
                    errorCode = err['code'];
            }
            else if (typeof err === 'string') {
                errorMessage = err;
            }
        }
        const raw = response.body.slice(0, 500);
        if (response.statusCode === 401 || response.statusCode === 403) {
            throw new LlmAuthError({
                message: errorMessage ?? `DeepSeek auth failure (HTTP ${response.statusCode})`,
                providerId: this.providerId,
                adapterId: this.adapterId,
                httpStatus: response.statusCode,
                raw,
            });
        }
        if (response.statusCode === 429) {
            const retryAfterMs = parseRetryAfterMs(response.headers['retry-after']);
            throw new LlmRateLimitError({
                message: errorMessage ?? 'DeepSeek rate limit exceeded',
                providerId: this.providerId,
                adapterId: this.adapterId,
                httpStatus: response.statusCode,
                retryAfterMs: retryAfterMs > 0 ? retryAfterMs : 1_000,
                raw,
            });
        }
        if (response.statusCode === 404 || errorCode === 'model_not_found') {
            throw new LlmModelNotFoundError({
                message: errorMessage ??
                    `DeepSeek model not found: ${requestedModelId}`,
                providerId: this.providerId,
                adapterId: this.adapterId,
                httpStatus: response.statusCode,
                requestedModelId,
                raw,
            });
        }
        throw new LlmProviderError({
            message: errorMessage ?? `DeepSeek error (HTTP ${response.statusCode})`,
            code: 'PROVIDER_ERROR',
            providerId: this.providerId,
            adapterId: this.adapterId,
            httpStatus: response.statusCode,
            raw,
        });
    }
    mapFinishReason(reason) {
        switch (reason) {
            case 'stop':
                return 'stop';
            case 'length':
                return 'length';
            case 'tool_calls':
            case 'function_call':
                return 'tool_calls';
            case 'content_filter':
                return 'content_filter';
            default:
                return reason ? 'unknown' : 'unknown';
        }
    }
}
// ---------------------------------------------------------------------------
// Suppress unused-import warning for KNOWN_DEEPSEEK_MODELS
// ---------------------------------------------------------------------------
// Exported for consumers that want to gate UX on the known-model list
// without re-importing the meta catalog.
export const DEEPSEEK_KNOWN_MODEL_IDS = KNOWN_DEEPSEEK_MODELS;
/**
 * Test-only re-export of `getProviderCompliance` bound to the same
 * module instance that ran `registerProviderCompliance()` at load time.
 *
 * Required because under tsx --test, importing
 * `getProviderCompliance` from `'../../../../src/llm-adapters/base'`
 * may resolve to a different module instance than the one
 * `deepseek.ts` imports as `'./base'` -- the in-process registry Map
 * is then split across instances and the registration is invisible
 * to the test.
 *
 * Production code should always import `getProviderCompliance` from
 * `@connexum/ai-governance/adapters` (the barrel) -- that single
 * canonical export point guarantees a single Map instance.
 */
export const __getProviderComplianceForTests = getProviderCompliance;
//# sourceMappingURL=deepseek.js.map