CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes48downloads
acpModelUtils.ts171 linesDownload Raw Back to utils
1/**2 * @license3 * Copyright 2025 Qwen Team4 * SPDX-License-Identifier: Apache-2.05 */6 7import { AuthType, type Config } from '@qwen-code/qwen-code-core';8import { z } from 'zod';9 10/**11 * ACP model IDs are represented as `${modelId}(${authType})` in the ACP protocol.12 *13 * NOTE: The VSCode webview side mirrors this encoding contract in14 * `packages/vscode-ide-companion/src/webview/utils/discontinuedModel.ts` to15 * detect discontinued Qwen OAuth registry models without changing the wire16 * format. If the encoding here evolves (new authTypes, runtime prefix changes,17 * etc.), update that file too.18 */19export function formatAcpModelId(modelId: string, authType: AuthType): string {20  return `${modelId}(${authType})`;21}22 23export function sanitizeProviderBaseUrl(baseUrl: string): string {24  const scheme = baseUrl.match(/^[A-Za-z][A-Za-z\d+.-]*:\/\//);25  if (!scheme) {26    return baseUrl;27  }28 29  const authorityStart = scheme[0].length;30  const stripAt = (at: number) =>31    `${baseUrl.slice(0, authorityStart)}${baseUrl.slice(at + 1)}`;32  const authorityEnd = findAuthorityEnd(baseUrl, authorityStart);33  const authorityAt = baseUrl34    .slice(authorityStart, authorityEnd)35    .lastIndexOf('@');36  const authorityAtIndex =37    authorityAt === -1 ? -1 : authorityStart + authorityAt;38 39  try {40    const parsed = new URL(baseUrl);41    if (parsed.username || parsed.password) {42      return authorityAtIndex >= authorityStart43        ? stripAt(authorityAtIndex)44        : baseUrl;45    }46    return baseUrl;47  } catch {48    if (authorityAtIndex >= authorityStart) {49      return stripAt(authorityAtIndex);50    }51 52    const fallbackAt = findUnescapedUserInfoFallbackAt(53      baseUrl,54      authorityStart,55      authorityEnd,56    );57    return fallbackAt === -1 ? baseUrl : stripAt(fallbackAt);58  }59}60 61function findUnescapedUserInfoFallbackAt(62  baseUrl: string,63  authorityStart: number,64  authorityEnd: number,65): number {66  const at = baseUrl.lastIndexOf('@');67  if (at < authorityStart || authorityEnd >= at) {68    return -1;69  }70 71  const colon = baseUrl.indexOf(':', authorityStart);72  if (colon === -1 || colon > authorityEnd) {73    return -1;74  }75 76  const portCandidate = baseUrl.slice(colon + 1, authorityEnd);77  return /^\d+$/.test(portCandidate) ? -1 : at;78}79 80function findAuthorityEnd(baseUrl: string, authorityStart: number): number {81  const slash = baseUrl.indexOf('/', authorityStart);82  const query = baseUrl.indexOf('?', authorityStart);83  const hash = baseUrl.indexOf('#', authorityStart);84  let end = baseUrl.length;85  if (slash !== -1) end = Math.min(end, slash);86  if (query !== -1) end = Math.min(end, query);87  if (hash !== -1) end = Math.min(end, hash);88  return end;89}90 91/**92 * Extracts the base model id from an ACP model id string.93 *94 * If the string ends with `(...)`, the suffix is removed; otherwise returns the95 * trimmed input as-is.96 */97export function parseAcpBaseModelId(value: string): string {98  const trimmed = value.trim();99  const closeIdx = trimmed.lastIndexOf(')');100  const openIdx = trimmed.lastIndexOf('(');101  if (openIdx >= 0 && closeIdx === trimmed.length - 1 && openIdx < closeIdx) {102    return trimmed.slice(0, openIdx);103  }104  return trimmed;105}106 107/**108 * Parses an ACP model option string into `{ modelId, authType? }`.109 *110 * Supports the following formats:111 * - `${modelId}(${authType})` - Standard registry model (e.g., "gpt-4(USE_OPENAI)")112 * - `${snapshotId}(${authType})` - Runtime model snapshot (e.g., "$runtime|USE_OPENAI|gpt-4(USE_OPENAI)")113 *   where snapshotId is in format `$runtime|${authType}|${modelId}`114 * - Plain model ID - Returns as-is with no authType115 *116 * If the string ends with `(...)` and `...` is a valid `AuthType`, returns both;117 * otherwise returns the trimmed input as `modelId` only.118 */119export function parseAcpModelOption(input: string): {120  modelId: string;121  authType?: AuthType;122} {123  const trimmed = input.trim();124  const closeIdx = trimmed.lastIndexOf(')');125  const openIdx = trimmed.lastIndexOf('(');126  if (openIdx >= 0 && closeIdx === trimmed.length - 1 && openIdx < closeIdx) {127    const maybeModelId = trimmed.slice(0, openIdx);128    const maybeAuthType = trimmed.slice(openIdx + 1, closeIdx);129    const parsedAuthType = z.nativeEnum(AuthType).safeParse(maybeAuthType);130    if (parsedAuthType.success) {131      return { modelId: maybeModelId, authType: parsedAuthType.data };132    }133  }134  return { modelId: trimmed };135}136 137/**138 * Whether a bare `modelId` resolves to the SAME provider identity as the active139 * content generator — same auth type, base URL, and credential env key.140 *141 * A per-turn inline `modelOverride` reuses the active provider's endpoint and142 * credentials and only swaps the model id; it cannot rebuild baseUrl/envKey for143 * a different provider. Any consumer that applies a `submit_prompt` result's144 * `modelOverride` must gate on this so an override naming a same-id model owned145 * by a different provider (or a different auth type) is never silently sent to146 * the active endpoint/account — even if a future (or untrusted) slash command147 * produces the override instead of the validated `/model` command. `modelId` is148 * the bare id without any `(authType)` suffix.149 */150export function isInlineModelOverrideAllowed(151  config: Config,152  modelId: string,153): boolean {154  const contentGeneratorConfig = config.getContentGeneratorConfig();155  const authType = contentGeneratorConfig?.authType;156  if (!authType) {157    return false;158  }159  const activeBaseUrl = contentGeneratorConfig.baseUrl;160  const activeEnvKey = contentGeneratorConfig.apiKeyEnvKey;161  return config162    .getAvailableModelsForAuthType(authType)163    .filter((m) => !m.fastOnly && !m.voiceOnly)164    .some(165      (m) =>166        m.id === modelId &&167        (m.baseUrl ?? undefined) === (activeBaseUrl ?? undefined) &&168        (m.envKey ?? undefined) === (activeEnvKey ?? undefined),169    );170}171 
basant307/AI_Governance_Project · CoolFace