CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes48downloads
fast-path.js398 linesDownload Raw Back to serve
1/**2 * @license3 * Copyright 2025 Qwen Team4 * SPDX-License-Identifier: Apache-2.05 */6import { normalizeServeFastPathArgv } from './fast-path-argv.js';7import { RUNTIME_STARTUP_CANCELLED_MESSAGE } from './runtime-startup-errors.js';8import { getHeadlessYoloSafetyWarning } from '../utils/headlessSafetyWarnings.js';9const HELP_AND_VERSION_FLAGS = new Set(['--help', '-h', '--version', '-v']);10const MCP_BUDGET_WARN_FRACTION = 0.75;11const NUMBER_OPTIONS = new Map([12    ['port', 'port'],13    ['maxSessions', 'max-sessions'],14    ['maxTotalSessions', 'max-total-sessions'],15    ['maxPendingPromptsPerSession', 'max-pending-prompts-per-session'],16    ['maxConnections', 'max-connections'],17    ['eventRingSize', 'event-ring-size'],18    ['mcp-client-budget', 'mcp-client-budget'],19    ['promptDeadlineMs', 'prompt-deadline-ms'],20    ['writerIdleTimeoutMs', 'writer-idle-timeout-ms'],21    ['channelIdleTimeoutMs', 'channel-idle-timeout-ms'],22    ['sessionReapIntervalMs', 'session-reap-interval-ms'],23    ['sessionIdleTimeoutMs', 'session-idle-timeout-ms'],24    ['permissionResponseTimeoutMs', 'permission-response-timeout-ms'],25    ['rateLimitPrompt', 'rate-limit-prompt'],26    ['rateLimitMutation', 'rate-limit-mutation'],27    ['rateLimitRead', 'rate-limit-read'],28    ['rateLimitWindowMs', 'rate-limit-window-ms'],29]);30const NUMBER_OPTION_BY_FLAG = invertOptionMap(NUMBER_OPTIONS);31const STRING_OPTION_BY_FLAG = new Map([32    ['hostname', 'hostname'],33    ['token', 'token'],34    ['workspace', 'workspace'],35    ['tls-cert', 'tlsCert'],36    ['tls-key', 'tlsKey'],37]);38const BOOLEAN_OPTION_BY_FLAG = new Map([39    ['require-auth', 'requireAuth'],40    ['enable-session-shell', 'enableSessionShell'],41    ['web', 'serveWebShell'],42    ['open', 'open'],43    ['http-bridge', 'http-bridge'],44    ['allow-private-auth-base-url', 'allowPrivateAuthBaseUrl'],45    ['experimental-lsp', 'experimentalLsp'],46    ['rate-limit', 'rateLimit'],47]);48function invertOptionMap(source) {49    const out = new Map();50    for (const [target, flag] of source) {51        out.set(flag, target);52    }53    return out;54}55function readOptionValue(argv, index, inlineValue) {56    if (inlineValue !== undefined) {57        return { value: inlineValue, nextIndex: index };58    }59    const value = argv[index + 1];60    if (value === undefined || value.startsWith('-')) {61        return null;62    }63    return { value, nextIndex: index + 1 };64}65function parseNumber(value) {66    if (value.trim() === '')67        return null;68    const parsed = Number(value);69    return Number.isNaN(parsed) ? null : parsed;70}71function parseBooleanValue(value) {72    if (value === 'true')73        return true;74    if (value === 'false')75        return false;76    return null;77}78function parsePositiveIntegerEnv(raw) {79    if (raw === undefined || raw === '')80        return undefined;81    const trimmed = raw?.trim();82    if (!trimmed || !/^\d+$/.test(trimmed))83        return Number.NaN;84    const parsed = Number(trimmed);85    return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : Number.NaN;86}87function isTruthyEnv(value) {88    return value === '1' || value === 'true';89}90function writeStderrLine(line) {91    process.stderr.write(line.endsWith('\n') ? line : `${line}\n`);92}93function setServeOption(options, key, value) {94    options[key] = value;95}96function getRateLimitValidationError(options) {97    for (const [name, value] of [98        ['--rate-limit-prompt', options.rateLimitPrompt],99        ['--rate-limit-mutation', options.rateLimitMutation],100        ['--rate-limit-read', options.rateLimitRead],101    ]) {102        if (value !== undefined &&103            (!Number.isFinite(value) || !Number.isInteger(value) || value <= 0)) {104            return `qwen serve: ${name} must be a positive integer.`;105        }106    }107    if (options.rateLimitWindowMs !== undefined &&108        (!Number.isFinite(options.rateLimitWindowMs) ||109            !Number.isInteger(options.rateLimitWindowMs) ||110            options.rateLimitWindowMs < 1000)) {111        return 'qwen serve: --rate-limit-window-ms must be an integer >= 1000.';112    }113    return null;114}115function getServeFastPathValidationError(parsed) {116    const mcpClientBudget = parsed.options.mcpClientBudget;117    if (mcpClientBudget !== undefined &&118        (!Number.isFinite(mcpClientBudget) ||119            !Number.isInteger(mcpClientBudget) ||120            mcpClientBudget <= 0)) {121        return 'qwen serve: --mcp-client-budget must be a positive integer.';122    }123    if (parsed.options.mcpBudgetMode === 'enforce' &&124        mcpClientBudget === undefined) {125        return 'qwen serve: --mcp-budget-mode=enforce requires --mcp-client-budget=N.';126    }127    const maxPendingPromptsPerSession = parsed.options.maxPendingPromptsPerSession;128    if (maxPendingPromptsPerSession !== undefined &&129        maxPendingPromptsPerSession !== Number.POSITIVE_INFINITY &&130        (!Number.isFinite(maxPendingPromptsPerSession) ||131            !Number.isInteger(maxPendingPromptsPerSession) ||132            maxPendingPromptsPerSession < 0)) {133        return 'qwen serve: --max-pending-prompts-per-session must be a non-negative integer (0 / Infinity = unlimited).';134    }135    return null;136}137function blockForever() {138    return new Promise(() => { });139}140export async function waitForServeRuntimeOrExit(handle) {141    try {142        await handle.runtimeReady;143    }144    catch (err) {145        if (err instanceof Error &&146            err.message === RUNTIME_STARTUP_CANCELLED_MESSAGE) {147            return;148        }149        writeStderrLine(`qwen serve: runtime startup failed after listener was ready: ${err instanceof Error ? err.message : String(err)}`);150        await handle.close().catch(() => undefined);151        process.exit(1);152    }153}154function applyRateLimitEnvDefaults(options, env) {155    if (options.rateLimit === undefined &&156        isTruthyEnv(env['QWEN_SERVE_RATE_LIMIT'])) {157        options.rateLimit = true;158    }159    if (options.rateLimit) {160        options.rateLimitPrompt ??= parsePositiveIntegerEnv(env['QWEN_SERVE_RATE_LIMIT_PROMPT']);161        options.rateLimitMutation ??= parsePositiveIntegerEnv(env['QWEN_SERVE_RATE_LIMIT_MUTATION']);162        options.rateLimitRead ??= parsePositiveIntegerEnv(env['QWEN_SERVE_RATE_LIMIT_READ']);163        options.rateLimitWindowMs ??= parsePositiveIntegerEnv(env['QWEN_SERVE_RATE_LIMIT_WINDOW_MS']);164    }165}166function discardRateLimitTuningWhenDisabled(options) {167    if (options.rateLimit === true)168        return;169    delete options.rateLimitPrompt;170    delete options.rateLimitMutation;171    delete options.rateLimitRead;172    delete options.rateLimitWindowMs;173}174export async function bootstrapServeFastPathEnvironment(workspace) {175    const { loadServeFastPathEnvironment, loadServeFastPathSettings, preResolveServeFastPathHomeEnvOverrides, } = await import('./fast-path-settings.js');176    preResolveServeFastPathHomeEnvOverrides();177    const workspaceDir = workspace ?? process.cwd();178    const settings = loadServeFastPathSettings(workspaceDir);179    loadServeFastPathEnvironment(settings, workspaceDir);180    return settings;181}182export function parseServeFastPathArgs(rawArgv, env = process.env) {183    const argv = normalizeServeFastPathArgv(rawArgv);184    if (argv[0] !== 'serve')185        return { kind: 'fallback' };186    if (argv.some((arg) => HELP_AND_VERSION_FLAGS.has(arg))) {187        return { kind: 'fallback' };188    }189    // Keep this lightweight mirror in sync with commands/serve.ts; unsupported190    // flags intentionally fall back to the full yargs parser.191    const options = {192        hostname: '127.0.0.1',193        mode: 'http-bridge',194        port: 4170,195    };196    let open = false;197    let httpBridge = true;198    let mcpBudgetModeRaw;199    let mcpClientBudget;200    let explicitRateLimit;201    for (let i = 1; i < argv.length; i++) {202        const arg = argv[i];203        if (arg === '--')204            return { kind: 'fallback' };205        if (!arg.startsWith('--'))206            return { kind: 'fallback' };207        const withoutPrefix = arg.slice(2);208        const equalsIndex = withoutPrefix.indexOf('=');209        const rawFlag = equalsIndex === -1 ? withoutPrefix : withoutPrefix.slice(0, equalsIndex);210        const inlineValue = equalsIndex === -1 ? undefined : withoutPrefix.slice(equalsIndex + 1);211        const negated = rawFlag.startsWith('no-');212        const flag = negated ? rawFlag.slice(3) : rawFlag;213        const booleanTarget = BOOLEAN_OPTION_BY_FLAG.get(flag);214        if (booleanTarget) {215            let value = !negated;216            if (inlineValue !== undefined) {217                const parsed = parseBooleanValue(inlineValue);218                if (parsed === null || negated)219                    return { kind: 'fallback' };220                value = parsed;221            }222            if (booleanTarget === 'open') {223                open = value;224            }225            else if (booleanTarget === 'http-bridge') {226                httpBridge = value;227            }228            else {229                setServeOption(options, booleanTarget, value);230                if (booleanTarget === 'rateLimit') {231                    explicitRateLimit = value;232                }233            }234            continue;235        }236        if (negated)237            return { kind: 'fallback' };238        const numberTarget = NUMBER_OPTION_BY_FLAG.get(flag);239        if (numberTarget) {240            const read = readOptionValue(argv, i, inlineValue);241            if (!read)242                return { kind: 'fallback' };243            i = read.nextIndex;244            const value = parseNumber(read.value);245            if (value === null)246                return { kind: 'fallback' };247            if (numberTarget === 'mcp-client-budget') {248                mcpClientBudget = value;249            }250            else {251                setServeOption(options, numberTarget, value);252            }253            continue;254        }255        const stringTarget = STRING_OPTION_BY_FLAG.get(flag);256        if (stringTarget) {257            const read = readOptionValue(argv, i, inlineValue);258            if (!read)259                return { kind: 'fallback' };260            i = read.nextIndex;261            if (stringTarget === 'workspace' &&262                (options.workspace !== undefined || read.value === '')) {263                return { kind: 'fallback' };264            }265            setServeOption(options, stringTarget, read.value);266            continue;267        }268        if (flag === 'mcp-budget-mode') {269            const read = readOptionValue(argv, i, inlineValue);270            if (!read)271                return { kind: 'fallback' };272            i = read.nextIndex;273            mcpBudgetModeRaw = read.value;274            continue;275        }276        if (flag === 'allow-origin') {277            const read = readOptionValue(argv, i, inlineValue);278            if (!read)279                return { kind: 'fallback' };280            i = read.nextIndex;281            options.allowOrigins = [...(options.allowOrigins ?? []), read.value];282            continue;283        }284        return { kind: 'fallback' };285    }286    if (mcpBudgetModeRaw !== undefined &&287        mcpBudgetModeRaw !== 'enforce' &&288        mcpBudgetModeRaw !== 'warn' &&289        mcpBudgetModeRaw !== 'off') {290        return { kind: 'fallback' };291    }292    const mcpBudgetMode = mcpBudgetModeRaw ??293        (mcpClientBudget !== undefined ? 'warn' : 'off');294    if (mcpClientBudget !== undefined)295        options.mcpClientBudget = mcpClientBudget;296    options.mcpBudgetMode = mcpBudgetMode;297    if (explicitRateLimit !== undefined) {298        options.rateLimit = explicitRateLimit;299    }300    applyRateLimitEnvDefaults(options, env);301    return { kind: 'serve', open, httpBridge, options };302}303async function maybeOpenWebShellBrowser(handle, open) {304    if (!open)305        return;306    try {307        await handle.runtimeReady;308    }309    catch {310        return;311    }312    const { maybeOpenWebShellBrowser: openBrowser } = await import('../commands/serve.js');313    await openBrowser(handle, true);314}315function emitHeadlessYoloWarning(settings) {316    if (!settings)317        return;318    const warning = getHeadlessYoloSafetyWarning({319        getApprovalMode: () => settings.tools?.approvalMode,320        getSandbox: () => settings.tools?.sandbox,321    });322    if (warning) {323        writeStderrLine(warning);324    }325}326function writeServeWarnings(parsed) {327    if (!parsed.httpBridge) {328        writeStderrLine('qwen serve: --no-http-bridge (native mode) is not yet implemented; ' +329            'falling back to http-bridge.');330    }331    if (parsed.options.token) {332        writeStderrLine('qwen serve: --token is visible in the process command line; ' +333            'prefer the QWEN_SERVER_TOKEN env var for any non-trivial deployment.');334    }335    const mcpClientBudget = parsed.options.mcpClientBudget;336    if (mcpClientBudget !== undefined) {337        const resolvedMcpMode = parsed.options.mcpBudgetMode ?? 'warn';338        writeStderrLine(`qwen serve: --mcp-client-budget=${mcpClientBudget} mode=${resolvedMcpMode}` +339            (resolvedMcpMode === 'enforce'340                ? ' (servers past the cap will be refused at discovery)'341                : resolvedMcpMode === 'warn'342                    ? ` (warnings at >=${Math.ceil(mcpClientBudget * MCP_BUDGET_WARN_FRACTION)}, no refusal)`343                    : ''));344    }345}346export async function tryRunServeFastPath(rawArgv = process.argv.slice(2)) {347    const parsed = parseServeFastPathArgs(rawArgv);348    if (parsed.kind === 'fallback')349        return false;350    const validationError = getServeFastPathValidationError(parsed) ||351        (parsed.options.rateLimit === true352            ? getRateLimitValidationError(parsed.options)353            : null);354    if (validationError) {355        writeStderrLine(validationError);356        process.exit(1);357    }358    let settings;359    try {360        settings = await bootstrapServeFastPathEnvironment(parsed.options.workspace);361    }362    catch (err) {363        writeStderrLine(`qwen serve: fast-path bootstrap failed, falling back to full startup: ${err instanceof Error ? err.message : String(err)}`);364        return false;365    }366    applyRateLimitEnvDefaults(parsed.options, process.env);367    discardRateLimitTuningWhenDisabled(parsed.options);368    const rateLimitError = getRateLimitValidationError(parsed.options);369    if (rateLimitError) {370        writeStderrLine(rateLimitError);371        process.exit(1);372    }373    writeServeWarnings(parsed);374    const { runQwenServe } = await import('./run-qwen-serve.js');375    let handle;376    try {377        handle = await runQwenServe(parsed.options, {378            ...(settings ? { bootSettings: settings } : {}),379            resolveOnListen: true,380            deferRuntimeUntilFirstHealth: !parsed.open,381        });382        try {383            emitHeadlessYoloWarning(settings);384        }385        catch {386            // Keep the warning best-effort, matching the yargs serve handler.387        }388        await maybeOpenWebShellBrowser(handle, parsed.open);389    }390    catch (err) {391        writeStderrLine(`qwen serve: ${err instanceof Error ? err.message : String(err)}`);392        process.exit(1);393    }394    await waitForServeRuntimeOrExit(handle);395    await blockForever();396    return true;397}398//# sourceMappingURL=fast-path.js.map
basant307/AI_Governance_Project · CoolFace