feat(models): generate Command Code catalog snapshot
This commit is contained in:
@@ -1,18 +1,24 @@
|
|||||||
import { execFile } from "node:child_process"
|
import { execFile } from "node:child_process"
|
||||||
import { mkdtemp, readFile, rm } from "node:fs/promises"
|
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"
|
||||||
import { tmpdir } from "node:os"
|
import { tmpdir } from "node:os"
|
||||||
import { join, resolve } from "node:path"
|
import { join, resolve } from "node:path"
|
||||||
import { pathToFileURL } from "node:url"
|
import { pathToFileURL } from "node:url"
|
||||||
import { promisify } from "node:util"
|
import { promisify } from "node:util"
|
||||||
|
|
||||||
import { COMMAND_CODE_CLI_VERSION } from "../../src/core.ts"
|
import {
|
||||||
import { MODEL_EFFORTS, MODEL_INPUT_MODALITIES } from "../../src/models.ts"
|
COMMAND_CODE_CLI_VERSION,
|
||||||
|
MODEL_EFFORTS,
|
||||||
|
MODEL_INPUT_MODALITIES,
|
||||||
|
} from "../../src/commandcode-catalog.ts"
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile)
|
const execFileAsync = promisify(execFile)
|
||||||
const MODELS_REFERENCE_PATH = "dist/bundled/command-code-knowledge/reference/models.md"
|
const MODELS_REFERENCE_PATH = "dist/bundled/command-code-knowledge/reference/models.md"
|
||||||
const CLI_BUNDLE_PATH = "dist/cli.mjs"
|
const CLI_BUNDLE_PATH = "dist/cli.mjs"
|
||||||
const TEXT_ONLY_MARKER = ',__name(isKnownTextOnlyModel,"isKnownTextOnlyModel")'
|
const TEXT_ONLY_MARKER = ',__name(isKnownTextOnlyModel,"isKnownTextOnlyModel")'
|
||||||
const VALID_EFFORTS = new Set(["low", "medium", "high", "xhigh", "max"])
|
const VALID_EFFORTS = new Set(["minimal", "low", "medium", "high", "xhigh", "max"])
|
||||||
|
const CATALOG_SOURCE_PATH = new URL("../../src/commandcode-catalog.ts", import.meta.url)
|
||||||
|
const README_PATH = new URL("../../README.md", import.meta.url)
|
||||||
|
const CHANGELOG_PATH = new URL("../../CHANGELOG.md", import.meta.url)
|
||||||
|
|
||||||
export interface CommandCodeModelMetadata {
|
export interface CommandCodeModelMetadata {
|
||||||
imageModelIds: readonly string[]
|
imageModelIds: readonly string[]
|
||||||
@@ -20,6 +26,7 @@ export interface CommandCodeModelMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ModelMetadataDiff {
|
export interface ModelMetadataDiff {
|
||||||
|
versionChanged: boolean
|
||||||
addedImageModelIds: readonly string[]
|
addedImageModelIds: readonly string[]
|
||||||
removedImageModelIds: readonly string[]
|
removedImageModelIds: readonly string[]
|
||||||
addedReasoningModelIds: readonly string[]
|
addedReasoningModelIds: readonly string[]
|
||||||
@@ -144,6 +151,8 @@ export function currentModelMetadata(): CommandCodeModelMetadata {
|
|||||||
export function diffModelMetadata(
|
export function diffModelMetadata(
|
||||||
current: CommandCodeModelMetadata,
|
current: CommandCodeModelMetadata,
|
||||||
upstream: CommandCodeModelMetadata,
|
upstream: CommandCodeModelMetadata,
|
||||||
|
currentVersion = COMMAND_CODE_CLI_VERSION,
|
||||||
|
upstreamVersion = COMMAND_CODE_CLI_VERSION,
|
||||||
): ModelMetadataDiff {
|
): ModelMetadataDiff {
|
||||||
const currentImages = new Set(current.imageModelIds)
|
const currentImages = new Set(current.imageModelIds)
|
||||||
const upstreamImages = new Set(upstream.imageModelIds)
|
const upstreamImages = new Set(upstream.imageModelIds)
|
||||||
@@ -153,6 +162,7 @@ export function diffModelMetadata(
|
|||||||
const upstreamReasoningSet = new Set(upstreamReasoningIds)
|
const upstreamReasoningSet = new Set(upstreamReasoningIds)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
versionChanged: currentVersion !== upstreamVersion,
|
||||||
addedImageModelIds: sorted(
|
addedImageModelIds: sorted(
|
||||||
upstream.imageModelIds.filter((modelId) => !currentImages.has(modelId)),
|
upstream.imageModelIds.filter((modelId) => !currentImages.has(modelId)),
|
||||||
),
|
),
|
||||||
@@ -177,7 +187,10 @@ export function diffModelMetadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function hasModelMetadataDiff(diff: ModelMetadataDiff): boolean {
|
export function hasModelMetadataDiff(diff: ModelMetadataDiff): boolean {
|
||||||
return Object.values(diff).some((modelIds) => modelIds.length > 0)
|
return (
|
||||||
|
diff.versionChanged ||
|
||||||
|
Object.entries(diff).some(([key, modelIds]) => key !== "versionChanged" && modelIds.length > 0)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatList(modelIds: readonly string[]): string {
|
function formatList(modelIds: readonly string[]): string {
|
||||||
@@ -200,6 +213,66 @@ function formatReasoningChanges(
|
|||||||
.join("<br>")
|
.join("<br>")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function quoted(value: string): string {
|
||||||
|
return JSON.stringify(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function recordEntries(
|
||||||
|
values: Readonly<Record<string, readonly string[]>>,
|
||||||
|
): readonly [string, readonly string[]][] {
|
||||||
|
return Object.entries(values).sort(([left], [right]) => left.localeCompare(right))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderCommandCodeCatalog(
|
||||||
|
packageVersion: string,
|
||||||
|
metadata: CommandCodeModelMetadata,
|
||||||
|
): string {
|
||||||
|
const imageEntries = sorted(metadata.imageModelIds)
|
||||||
|
.map((modelId) => ` ${quoted(modelId)}: ["text", "image"],`)
|
||||||
|
.join("\n")
|
||||||
|
const reasoningEntries = recordEntries(metadata.reasoningEfforts)
|
||||||
|
.map(
|
||||||
|
([modelId, efforts]) =>
|
||||||
|
` ${quoted(modelId)}: [${efforts.map((effort) => quoted(effort)).join(", ")}],`,
|
||||||
|
)
|
||||||
|
.join("\n")
|
||||||
|
|
||||||
|
return `export const COMMAND_CODE_CLI_VERSION = ${quoted(packageVersion)}\n\nexport type CommandCodeInputType = "text" | "image"\nexport type CommandCodeReasoningEffort = "minimal" | "low" | "medium" | "high" | "xhigh" | "max"\n\n/**\n * Generated from command-code@${packageVersion} by \`npm run sync:commandcode-catalog\`.\n * Do not edit manually.\n */\nexport const MODEL_INPUT_MODALITIES: Readonly<Record<string, readonly CommandCodeInputType[]>> = {\n${imageEntries}\n}\n\nexport const MODEL_EFFORTS: Readonly<Record<string, readonly CommandCodeReasoningEffort[]>> = {\n${reasoningEntries}\n}\n`
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDocumentedCatalogVersion(
|
||||||
|
contents: string,
|
||||||
|
packageVersion: string,
|
||||||
|
context: string,
|
||||||
|
): string {
|
||||||
|
const pattern = /command-code@\d+\.\d+\.\d+(?:[-+][^`\s,]+)?/
|
||||||
|
if (!pattern.test(contents)) throw new Error(`Could not find the ${context} catalog version`)
|
||||||
|
return contents.replace(pattern, `command-code@${packageVersion}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateReadmeCatalogVersion(readme: string, packageVersion: string): string {
|
||||||
|
return updateDocumentedCatalogVersion(readme, packageVersion, "README")
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateChangelogCatalogVersion(changelog: string, packageVersion: string): string {
|
||||||
|
return updateDocumentedCatalogVersion(changelog, packageVersion, "changelog")
|
||||||
|
}
|
||||||
|
|
||||||
|
async function writeSynchronizedCatalog(
|
||||||
|
packageVersion: string,
|
||||||
|
metadata: CommandCodeModelMetadata,
|
||||||
|
): Promise<void> {
|
||||||
|
const [readme, changelog] = await Promise.all([
|
||||||
|
readFile(README_PATH, "utf-8"),
|
||||||
|
readFile(CHANGELOG_PATH, "utf-8"),
|
||||||
|
])
|
||||||
|
await Promise.all([
|
||||||
|
writeFile(CATALOG_SOURCE_PATH, renderCommandCodeCatalog(packageVersion, metadata), "utf-8"),
|
||||||
|
writeFile(README_PATH, updateReadmeCatalogVersion(readme, packageVersion), "utf-8"),
|
||||||
|
writeFile(CHANGELOG_PATH, updateChangelogCatalogVersion(changelog, packageVersion), "utf-8"),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
function metadataReport(
|
function metadataReport(
|
||||||
packageVersion: string,
|
packageVersion: string,
|
||||||
current: CommandCodeModelMetadata,
|
current: CommandCodeModelMetadata,
|
||||||
@@ -219,6 +292,7 @@ function metadataReport(
|
|||||||
"",
|
"",
|
||||||
"| Change | Models |",
|
"| Change | Models |",
|
||||||
"| --- | --- |",
|
"| --- | --- |",
|
||||||
|
`| CLI version | ${diff.versionChanged ? `\`${COMMAND_CODE_CLI_VERSION}\` → \`${packageVersion}\`` : "Current"} |`,
|
||||||
`| New image support | ${formatList(diff.addedImageModelIds)} |`,
|
`| New image support | ${formatList(diff.addedImageModelIds)} |`,
|
||||||
`| Removed image support | ${formatList(diff.removedImageModelIds)} |`,
|
`| Removed image support | ${formatList(diff.removedImageModelIds)} |`,
|
||||||
`| New reasoning metadata | ${formatList(diff.addedReasoningModelIds)} |`,
|
`| New reasoning metadata | ${formatList(diff.addedReasoningModelIds)} |`,
|
||||||
@@ -289,10 +363,17 @@ async function inspectPackedPackage(packageSpec: string): Promise<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
async function main(): Promise<void> {
|
||||||
const packageSpec = process.argv[2] ?? "command-code@latest"
|
const write = process.argv.includes("--write")
|
||||||
|
const packageSpec =
|
||||||
|
process.argv.find((argument) => argument.startsWith("command-code@")) ?? "command-code@latest"
|
||||||
const current = currentModelMetadata()
|
const current = currentModelMetadata()
|
||||||
const upstreamPackage = await inspectPackedPackage(packageSpec)
|
const upstreamPackage = await inspectPackedPackage(packageSpec)
|
||||||
const diff = diffModelMetadata(current, upstreamPackage.metadata)
|
const diff = diffModelMetadata(
|
||||||
|
current,
|
||||||
|
upstreamPackage.metadata,
|
||||||
|
COMMAND_CODE_CLI_VERSION,
|
||||||
|
upstreamPackage.packageVersion,
|
||||||
|
)
|
||||||
const report = metadataReport(
|
const report = metadataReport(
|
||||||
upstreamPackage.packageVersion,
|
upstreamPackage.packageVersion,
|
||||||
current,
|
current,
|
||||||
@@ -302,6 +383,12 @@ async function main(): Promise<void> {
|
|||||||
|
|
||||||
console.log(report)
|
console.log(report)
|
||||||
|
|
||||||
|
if (write) {
|
||||||
|
await writeSynchronizedCatalog(upstreamPackage.packageVersion, upstreamPackage.metadata)
|
||||||
|
console.log(`Synchronized static metadata with command-code@${upstreamPackage.packageVersion}.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (hasModelMetadataDiff(diff)) {
|
if (hasModelMetadataDiff(diff)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Static model metadata differs from command-code@${upstreamPackage.packageVersion}. Update src/models.ts and the snapshot version.`,
|
`Static model metadata differs from command-code@${upstreamPackage.packageVersion}. Update src/models.ts and the snapshot version.`,
|
||||||
|
|||||||
+2
-1
@@ -35,7 +35,8 @@
|
|||||||
"format": "prettier --write '**/*.{ts,mjs,json,md}'",
|
"format": "prettier --write '**/*.{ts,mjs,json,md}'",
|
||||||
"pi:isolated": "node scripts/pi-isolated.mjs",
|
"pi:isolated": "node scripts/pi-isolated.mjs",
|
||||||
"pi:authenticated": "node scripts/pi-authenticated.mjs",
|
"pi:authenticated": "node scripts/pi-authenticated.mjs",
|
||||||
"check:model-metadata": "tsx .github/scripts/check-commandcode-model-metadata.ts command-code@latest",
|
"check:commandcode-catalog": "tsx .github/scripts/check-commandcode-model-metadata.ts command-code@latest",
|
||||||
|
"sync:commandcode-catalog": "tsx .github/scripts/check-commandcode-model-metadata.ts command-code@latest --write",
|
||||||
"test:quota": "tsx tests/test-quota.ts && tsx tests/test-quota-command.ts",
|
"test:quota": "tsx tests/test-quota.ts && tsx tests/test-quota-command.ts",
|
||||||
"test:unit": "tsx tests/test-api-key.ts && tsx tests/test-pure-functions.ts && tsx tests/test-models.ts && tsx tests/test-model-metadata-check.ts && tsx tests/test-runtime.ts && tsx tests/test-pricing.ts && tsx tests/test-cost.ts && tsx tests/test-oauth.ts && tsx tests/test-abort.ts && tsx tests/test-overflow.ts && tsx tests/test-stream.ts && tsx tests/test-quota.ts && tsx tests/test-quota-command.ts && tsx tests/test-retry.ts && tsx tests/test-transport.ts",
|
"test:unit": "tsx tests/test-api-key.ts && tsx tests/test-pure-functions.ts && tsx tests/test-models.ts && tsx tests/test-model-metadata-check.ts && tsx tests/test-runtime.ts && tsx tests/test-pricing.ts && tsx tests/test-cost.ts && tsx tests/test-oauth.ts && tsx tests/test-abort.ts && tsx tests/test-overflow.ts && tsx tests/test-stream.ts && tsx tests/test-quota.ts && tsx tests/test-quota-command.ts && tsx tests/test-retry.ts && tsx tests/test-transport.ts",
|
||||||
"test:api-key": "tsx tests/test-api-key.ts",
|
"test:api-key": "tsx tests/test-api-key.ts",
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
export const COMMAND_CODE_CLI_VERSION = "1.32.2"
|
||||||
|
|
||||||
|
export type CommandCodeInputType = "text" | "image"
|
||||||
|
export type CommandCodeReasoningEffort = "minimal" | "low" | "medium" | "high" | "xhigh" | "max"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generated from command-code@1.32.2 by `npm run sync:commandcode-catalog`.
|
||||||
|
* Do not edit manually.
|
||||||
|
*/
|
||||||
|
export const MODEL_INPUT_MODALITIES: Readonly<Record<string, readonly CommandCodeInputType[]>> = {
|
||||||
|
"claude-fable-5": ["text", "image"],
|
||||||
|
"claude-haiku-4-5-20251001": ["text", "image"],
|
||||||
|
"claude-opus-4-7": ["text", "image"],
|
||||||
|
"claude-opus-4-8": ["text", "image"],
|
||||||
|
"claude-opus-5": ["text", "image"],
|
||||||
|
"claude-sonnet-4-6": ["text", "image"],
|
||||||
|
"claude-sonnet-5": ["text", "image"],
|
||||||
|
"deepseek/deepseek-v4-flash-vision-exp": ["text", "image"],
|
||||||
|
"google/gemini-3.1-flash-lite": ["text", "image"],
|
||||||
|
"google/gemini-3.5-flash": ["text", "image"],
|
||||||
|
"google/gemini-3.5-flash-lite": ["text", "image"],
|
||||||
|
"google/gemini-3.6-flash": ["text", "image"],
|
||||||
|
"google/gemini-3.7-flash": ["text", "image"],
|
||||||
|
"gpt-5.3-codex": ["text", "image"],
|
||||||
|
"gpt-5.4": ["text", "image"],
|
||||||
|
"gpt-5.4-mini": ["text", "image"],
|
||||||
|
"gpt-5.5": ["text", "image"],
|
||||||
|
"gpt-5.6-luna": ["text", "image"],
|
||||||
|
"gpt-5.6-sol": ["text", "image"],
|
||||||
|
"gpt-5.6-terra": ["text", "image"],
|
||||||
|
"meta/muse-spark-1.1": ["text", "image"],
|
||||||
|
"meta/muse-spark-1.2": ["text", "image"],
|
||||||
|
"meta/muse-spark-1.2-contributor": ["text", "image"],
|
||||||
|
"MiniMaxAI/MiniMax-M3": ["text", "image"],
|
||||||
|
"moonshotai/Kimi-K2.5": ["text", "image"],
|
||||||
|
"moonshotai/Kimi-K2.6": ["text", "image"],
|
||||||
|
"moonshotai/Kimi-K2.7-Code": ["text", "image"],
|
||||||
|
"moonshotai/Kimi-K2.7-Code-Highspeed": ["text", "image"],
|
||||||
|
"moonshotai/Kimi-K3": ["text", "image"],
|
||||||
|
"Qwen/Qwen3.6-Plus": ["text", "image"],
|
||||||
|
"Qwen/Qwen3.7-Flash": ["text", "image"],
|
||||||
|
"Qwen/Qwen3.7-Plus": ["text", "image"],
|
||||||
|
"Qwen/Qwen3.8-27B": ["text", "image"],
|
||||||
|
"Qwen/Qwen3.8-Max": ["text", "image"],
|
||||||
|
"sakana/fugu-ultra": ["text", "image"],
|
||||||
|
"stealth/ox-alpha": ["text", "image"],
|
||||||
|
"stepfun/Step-3.7-Flash": ["text", "image"],
|
||||||
|
"thinkingmachines/inkling": ["text", "image"],
|
||||||
|
"thinkingmachines/inkling-small": ["text", "image"],
|
||||||
|
"xai/grok-4.5": ["text", "image"],
|
||||||
|
"xiaomi/mimo-v2.5": ["text", "image"],
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MODEL_EFFORTS: Readonly<Record<string, readonly CommandCodeReasoningEffort[]>> = {
|
||||||
|
"claude-fable-5": ["low", "medium", "high", "xhigh", "max"],
|
||||||
|
"claude-opus-4-7": ["low", "medium", "high", "xhigh", "max"],
|
||||||
|
"claude-opus-4-8": ["low", "medium", "high", "xhigh", "max"],
|
||||||
|
"claude-opus-5": ["low", "medium", "high", "xhigh", "max"],
|
||||||
|
"claude-sonnet-4-6": ["low", "medium", "high", "xhigh", "max"],
|
||||||
|
"claude-sonnet-5": ["low", "medium", "high", "xhigh", "max"],
|
||||||
|
"deepseek/deepseek-v4-flash": ["high", "max"],
|
||||||
|
"deepseek/deepseek-v4-flash-vision-exp": ["high", "max"],
|
||||||
|
"deepseek/deepseek-v4-pro": ["high", "max"],
|
||||||
|
"google/gemini-3.1-flash-lite": ["low", "medium", "high"],
|
||||||
|
"google/gemini-3.5-flash": ["low", "medium", "high"],
|
||||||
|
"google/gemini-3.5-flash-lite": ["low", "medium", "high"],
|
||||||
|
"google/gemini-3.6-flash": ["low", "medium", "high"],
|
||||||
|
"google/gemini-3.7-flash": ["low", "medium", "high"],
|
||||||
|
"gpt-5.3-codex": ["low", "medium", "high", "xhigh"],
|
||||||
|
"gpt-5.4": ["low", "medium", "high", "xhigh"],
|
||||||
|
"gpt-5.4-mini": ["low", "medium", "high"],
|
||||||
|
"gpt-5.5": ["low", "medium", "high", "xhigh"],
|
||||||
|
"gpt-5.6-luna": ["low", "medium", "high", "xhigh", "max"],
|
||||||
|
"gpt-5.6-sol": ["low", "medium", "high", "xhigh", "max"],
|
||||||
|
"gpt-5.6-terra": ["low", "medium", "high", "xhigh", "max"],
|
||||||
|
"Qwen/Qwen3.8-27B": ["low", "medium", "xhigh"],
|
||||||
|
"Qwen/Qwen3.8-Max": ["low", "medium", "xhigh"],
|
||||||
|
"sakana/fugu-ultra": ["high", "xhigh"],
|
||||||
|
"stealth/ox-alpha": ["low", "high", "max"],
|
||||||
|
"xai/grok-4.5": ["low", "medium", "high"],
|
||||||
|
"xai/grok-4.6": ["low", "medium", "high", "xhigh"],
|
||||||
|
"zai-org/GLM-5.2": ["high", "max"],
|
||||||
|
"zai-org/GLM-5.3": ["low", "high", "max"],
|
||||||
|
}
|
||||||
+2
-1
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import { randomUUID } from "node:crypto"
|
import { randomUUID } from "node:crypto"
|
||||||
|
|
||||||
|
import { COMMAND_CODE_CLI_VERSION } from "./commandcode-catalog.ts"
|
||||||
import { commandCodeErrorMessage, redactCommandCodeErrorText } from "./overflow.ts"
|
import { commandCodeErrorMessage, redactCommandCodeErrorText } from "./overflow.ts"
|
||||||
import { modelSupportsImageInput } from "./models.ts"
|
import { modelSupportsImageInput } from "./models.ts"
|
||||||
import {
|
import {
|
||||||
@@ -43,7 +44,7 @@ export * from "./overflow.ts"
|
|||||||
export * from "./types.ts"
|
export * from "./types.ts"
|
||||||
|
|
||||||
export const DEFAULT_API_BASE = "https://api.commandcode.ai"
|
export const DEFAULT_API_BASE = "https://api.commandcode.ai"
|
||||||
export const COMMAND_CODE_CLI_VERSION = "1.32.2"
|
export { COMMAND_CODE_CLI_VERSION }
|
||||||
|
|
||||||
const DEFAULT_GENERATE_MAX_TOKENS = 64_000
|
const DEFAULT_GENERATE_MAX_TOKENS = 64_000
|
||||||
const DEFAULT_MAX_RETRIES = 0
|
const DEFAULT_MAX_RETRIES = 0
|
||||||
|
|||||||
+10
-93
@@ -1,6 +1,16 @@
|
|||||||
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises"
|
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises"
|
||||||
import { dirname } from "node:path"
|
import { dirname } from "node:path"
|
||||||
|
|
||||||
|
import {
|
||||||
|
MODEL_EFFORTS,
|
||||||
|
MODEL_INPUT_MODALITIES,
|
||||||
|
type CommandCodeInputType,
|
||||||
|
type CommandCodeReasoningEffort,
|
||||||
|
} from "./commandcode-catalog.ts"
|
||||||
|
|
||||||
|
export { MODEL_EFFORTS, MODEL_INPUT_MODALITIES }
|
||||||
|
export type { CommandCodeInputType }
|
||||||
|
|
||||||
export const DEFAULT_PROVIDER_API_BASE = "https://api.commandcode.ai/provider/v1"
|
export const DEFAULT_PROVIDER_API_BASE = "https://api.commandcode.ai/provider/v1"
|
||||||
export const DEFAULT_MODELS_URL = `${DEFAULT_PROVIDER_API_BASE}/models`
|
export const DEFAULT_MODELS_URL = `${DEFAULT_PROVIDER_API_BASE}/models`
|
||||||
export const DEFAULT_MODELS_TIMEOUT_MS = 10_000
|
export const DEFAULT_MODELS_TIMEOUT_MS = 10_000
|
||||||
@@ -9,56 +19,6 @@ const DEFAULT_MAX_OUTPUT_TOKENS = 65_536
|
|||||||
const MODEL_CACHE_VERSION = 1
|
const MODEL_CACHE_VERSION = 1
|
||||||
|
|
||||||
export type CommandCodeApi = "openai-completions" | "anthropic-messages"
|
export type CommandCodeApi = "openai-completions" | "anthropic-messages"
|
||||||
export type CommandCodeInputType = "text" | "image"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Model input modalities from the command-code@1.32.2 bundled catalog.
|
|
||||||
* Models omitted here remain text-only so newly discovered IDs never claim
|
|
||||||
* image support without upstream evidence.
|
|
||||||
*/
|
|
||||||
export const MODEL_INPUT_MODALITIES: Readonly<Record<string, readonly CommandCodeInputType[]>> = {
|
|
||||||
"MiniMaxAI/MiniMax-M3": ["text", "image"],
|
|
||||||
"Qwen/Qwen3.6-Plus": ["text", "image"],
|
|
||||||
"Qwen/Qwen3.7-Flash": ["text", "image"],
|
|
||||||
"Qwen/Qwen3.7-Plus": ["text", "image"],
|
|
||||||
"Qwen/Qwen3.8-27B": ["text", "image"],
|
|
||||||
"Qwen/Qwen3.8-Max": ["text", "image"],
|
|
||||||
"claude-fable-5": ["text", "image"],
|
|
||||||
"claude-haiku-4-5-20251001": ["text", "image"],
|
|
||||||
"claude-opus-4-7": ["text", "image"],
|
|
||||||
"claude-opus-4-8": ["text", "image"],
|
|
||||||
"claude-opus-5": ["text", "image"],
|
|
||||||
"claude-sonnet-4-6": ["text", "image"],
|
|
||||||
"claude-sonnet-5": ["text", "image"],
|
|
||||||
"deepseek/deepseek-v4-flash-vision-exp": ["text", "image"],
|
|
||||||
"google/gemini-3.1-flash-lite": ["text", "image"],
|
|
||||||
"google/gemini-3.5-flash": ["text", "image"],
|
|
||||||
"google/gemini-3.5-flash-lite": ["text", "image"],
|
|
||||||
"google/gemini-3.6-flash": ["text", "image"],
|
|
||||||
"google/gemini-3.7-flash": ["text", "image"],
|
|
||||||
"gpt-5.3-codex": ["text", "image"],
|
|
||||||
"gpt-5.4": ["text", "image"],
|
|
||||||
"gpt-5.4-mini": ["text", "image"],
|
|
||||||
"gpt-5.5": ["text", "image"],
|
|
||||||
"gpt-5.6-luna": ["text", "image"],
|
|
||||||
"gpt-5.6-sol": ["text", "image"],
|
|
||||||
"gpt-5.6-terra": ["text", "image"],
|
|
||||||
"meta/muse-spark-1.1": ["text", "image"],
|
|
||||||
"meta/muse-spark-1.2": ["text", "image"],
|
|
||||||
"meta/muse-spark-1.2-contributor": ["text", "image"],
|
|
||||||
"moonshotai/Kimi-K2.5": ["text", "image"],
|
|
||||||
"moonshotai/Kimi-K2.6": ["text", "image"],
|
|
||||||
"moonshotai/Kimi-K2.7-Code": ["text", "image"],
|
|
||||||
"moonshotai/Kimi-K2.7-Code-Highspeed": ["text", "image"],
|
|
||||||
"moonshotai/Kimi-K3": ["text", "image"],
|
|
||||||
"sakana/fugu-ultra": ["text", "image"],
|
|
||||||
"stealth/ox-alpha": ["text", "image"],
|
|
||||||
"stepfun/Step-3.7-Flash": ["text", "image"],
|
|
||||||
"thinkingmachines/inkling": ["text", "image"],
|
|
||||||
"thinkingmachines/inkling-small": ["text", "image"],
|
|
||||||
"xai/grok-4.5": ["text", "image"],
|
|
||||||
"xiaomi/mimo-v2.5": ["text", "image"],
|
|
||||||
}
|
|
||||||
|
|
||||||
const TEXT_INPUT_ONLY = ["text"] as const
|
const TEXT_INPUT_ONLY = ["text"] as const
|
||||||
|
|
||||||
@@ -72,49 +32,6 @@ export function modelSupportsImageInput(modelId: string): boolean {
|
|||||||
|
|
||||||
export type PiThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"
|
export type PiThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"
|
||||||
|
|
||||||
type CommandCodeReasoningEffort = Exclude<PiThinkingLevel, "off">
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Per-model reasoning efforts supported by Command Code's generate endpoint.
|
|
||||||
*
|
|
||||||
* The Provider API does not expose reasoning metadata. This is an exact
|
|
||||||
* snapshot of `reasoningEfforts` from the command-code@1.32.2 model catalog
|
|
||||||
* (`packages/shared/src/model-catalog.ts`, also published in the generated
|
|
||||||
* `dist/bundled/command-code-knowledge/reference/models.md`). Models omitted
|
|
||||||
* here let Command Code choose their reasoning depth, matching the CLI.
|
|
||||||
*/
|
|
||||||
export const MODEL_EFFORTS: Readonly<Record<string, readonly CommandCodeReasoningEffort[]>> = {
|
|
||||||
"Qwen/Qwen3.8-27B": ["low", "medium", "xhigh"],
|
|
||||||
"Qwen/Qwen3.8-Max": ["low", "medium", "xhigh"],
|
|
||||||
"claude-fable-5": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"claude-opus-4-7": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"claude-opus-4-8": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"claude-opus-5": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"claude-sonnet-4-6": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"claude-sonnet-5": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"deepseek/deepseek-v4-flash": ["high", "max"],
|
|
||||||
"deepseek/deepseek-v4-flash-vision-exp": ["high", "max"],
|
|
||||||
"deepseek/deepseek-v4-pro": ["high", "max"],
|
|
||||||
"gpt-5.3-codex": ["low", "medium", "high", "xhigh"],
|
|
||||||
"gpt-5.4": ["low", "medium", "high", "xhigh"],
|
|
||||||
"gpt-5.4-mini": ["low", "medium", "high"],
|
|
||||||
"gpt-5.5": ["low", "medium", "high", "xhigh"],
|
|
||||||
"gpt-5.6-luna": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"gpt-5.6-sol": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"gpt-5.6-terra": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"google/gemini-3.1-flash-lite": ["low", "medium", "high"],
|
|
||||||
"google/gemini-3.5-flash": ["low", "medium", "high"],
|
|
||||||
"google/gemini-3.5-flash-lite": ["low", "medium", "high"],
|
|
||||||
"google/gemini-3.6-flash": ["low", "medium", "high"],
|
|
||||||
"google/gemini-3.7-flash": ["low", "medium", "high"],
|
|
||||||
"sakana/fugu-ultra": ["high", "xhigh"],
|
|
||||||
"stealth/ox-alpha": ["low", "high", "max"],
|
|
||||||
"xai/grok-4.5": ["low", "medium", "high"],
|
|
||||||
"xai/grok-4.6": ["low", "medium", "high", "xhigh"],
|
|
||||||
"zai-org/GLM-5.2": ["high", "max"],
|
|
||||||
"zai-org/GLM-5.3": ["low", "high", "max"],
|
|
||||||
}
|
|
||||||
|
|
||||||
const PI_THINKING_LEVELS: readonly PiThinkingLevel[] = [
|
const PI_THINKING_LEVELS: readonly PiThinkingLevel[] = [
|
||||||
"off",
|
"off",
|
||||||
"minimal",
|
"minimal",
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import {
|
|||||||
parseKnownTextOnlyModelIds,
|
parseKnownTextOnlyModelIds,
|
||||||
parseModelsReference,
|
parseModelsReference,
|
||||||
parsePackageVersion,
|
parsePackageVersion,
|
||||||
|
renderCommandCodeCatalog,
|
||||||
|
updateChangelogCatalogVersion,
|
||||||
|
updateReadmeCatalogVersion,
|
||||||
type CommandCodeModelMetadata,
|
type CommandCodeModelMetadata,
|
||||||
} from "../.github/scripts/check-commandcode-model-metadata.ts"
|
} from "../.github/scripts/check-commandcode-model-metadata.ts"
|
||||||
|
|
||||||
@@ -68,6 +71,7 @@ describe("Command Code model metadata checker", () => {
|
|||||||
const diff = diffModelMetadata(current, upstream)
|
const diff = diffModelMetadata(current, upstream)
|
||||||
|
|
||||||
assert.deepEqual(diff, {
|
assert.deepEqual(diff, {
|
||||||
|
versionChanged: false,
|
||||||
addedImageModelIds: ["added-image"],
|
addedImageModelIds: ["added-image"],
|
||||||
removedImageModelIds: ["removed-image"],
|
removedImageModelIds: ["removed-image"],
|
||||||
addedReasoningModelIds: ["added-reasoning"],
|
addedReasoningModelIds: ["added-reasoning"],
|
||||||
@@ -77,6 +81,63 @@ describe("Command Code model metadata checker", () => {
|
|||||||
assert.equal(hasModelMetadataDiff(diff), true)
|
assert.equal(hasModelMetadataDiff(diff), true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("reports CLI version drift even when model metadata is unchanged", () => {
|
||||||
|
const metadata: CommandCodeModelMetadata = {
|
||||||
|
imageModelIds: ["vision-model"],
|
||||||
|
reasoningEfforts: { "vision-model": ["low"] },
|
||||||
|
}
|
||||||
|
|
||||||
|
const diff = diffModelMetadata(metadata, metadata, "1.32.2", "1.33.0")
|
||||||
|
|
||||||
|
assert.equal(diff.versionChanged, true)
|
||||||
|
assert.equal(hasModelMetadataDiff(diff), true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders a deterministic generated catalog and updates the README version", () => {
|
||||||
|
assert.equal(
|
||||||
|
renderCommandCodeCatalog("1.33.0", {
|
||||||
|
imageModelIds: ["b-model", "a-model"],
|
||||||
|
reasoningEfforts: {
|
||||||
|
"b-model": ["high", "max"],
|
||||||
|
"a-model": ["low"],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
`export const COMMAND_CODE_CLI_VERSION = "1.33.0"
|
||||||
|
|
||||||
|
export type CommandCodeInputType = "text" | "image"
|
||||||
|
export type CommandCodeReasoningEffort = "minimal" | "low" | "medium" | "high" | "xhigh" | "max"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generated from command-code@1.33.0 by \`npm run sync:commandcode-catalog\`.
|
||||||
|
* Do not edit manually.
|
||||||
|
*/
|
||||||
|
export const MODEL_INPUT_MODALITIES: Readonly<Record<string, readonly CommandCodeInputType[]>> = {
|
||||||
|
"a-model": ["text", "image"],
|
||||||
|
"b-model": ["text", "image"],
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MODEL_EFFORTS: Readonly<Record<string, readonly CommandCodeReasoningEffort[]>> = {
|
||||||
|
"a-model": ["low"],
|
||||||
|
"b-model": ["high", "max"],
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
assert.equal(
|
||||||
|
updateReadmeCatalogVersion(
|
||||||
|
"The capability snapshot currently follows `command-code@1.32.2`.",
|
||||||
|
"1.33.0",
|
||||||
|
),
|
||||||
|
"The capability snapshot currently follows `command-code@1.33.0`.",
|
||||||
|
)
|
||||||
|
assert.equal(
|
||||||
|
updateChangelogCatalogVersion(
|
||||||
|
"- Refresh capabilities from `command-code@1.32.2`, including metadata.",
|
||||||
|
"1.33.0",
|
||||||
|
),
|
||||||
|
"- Refresh capabilities from `command-code@1.33.0`, including metadata.",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it("rejects unexpected upstream structures instead of silently passing", () => {
|
it("rejects unexpected upstream structures instead of silently passing", () => {
|
||||||
assert.throws(() => parseModelsReference("# no catalog"), /No model rows/)
|
assert.throws(() => parseModelsReference("# no catalog"), /No model rows/)
|
||||||
assert.throws(
|
assert.throws(
|
||||||
|
|||||||
+14
-34
@@ -4,6 +4,7 @@ import { tmpdir } from "node:os"
|
|||||||
import { join } from "node:path"
|
import { join } from "node:path"
|
||||||
import { describe, it } from "node:test"
|
import { describe, it } from "node:test"
|
||||||
|
|
||||||
|
import { COMMAND_CODE_CLI_VERSION } from "../src/commandcode-catalog.ts"
|
||||||
import {
|
import {
|
||||||
apiForModelId,
|
apiForModelId,
|
||||||
baseUrlForModel,
|
baseUrlForModel,
|
||||||
@@ -100,7 +101,7 @@ describe("commandCodeModelsFromApiResponse()", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("matches command-code@1.32.2 image input capabilities", () => {
|
it(`uses the command-code@${COMMAND_CODE_CLI_VERSION} image capability catalog`, () => {
|
||||||
assert.deepEqual(inputModalitiesForModel("gpt-5.6-luna"), ["text", "image"])
|
assert.deepEqual(inputModalitiesForModel("gpt-5.6-luna"), ["text", "image"])
|
||||||
assert.deepEqual(inputModalitiesForModel("meta/muse-spark-1.2"), ["text", "image"])
|
assert.deepEqual(inputModalitiesForModel("meta/muse-spark-1.2"), ["text", "image"])
|
||||||
assert.deepEqual(inputModalitiesForModel("deepseek/deepseek-v4-flash-vision-exp"), [
|
assert.deepEqual(inputModalitiesForModel("deepseek/deepseek-v4-flash-vision-exp"), [
|
||||||
@@ -117,7 +118,10 @@ describe("commandCodeModelsFromApiResponse()", () => {
|
|||||||
assert.equal(modelSupportsImageInput("deepseek/deepseek-v4-flash-vision-exp"), true)
|
assert.equal(modelSupportsImageInput("deepseek/deepseek-v4-flash-vision-exp"), true)
|
||||||
assert.equal(modelSupportsImageInput("stealth/ox-alpha"), true)
|
assert.equal(modelSupportsImageInput("stealth/ox-alpha"), true)
|
||||||
assert.equal(modelSupportsImageInput("deepseek/deepseek-v4-pro"), false)
|
assert.equal(modelSupportsImageInput("deepseek/deepseek-v4-pro"), false)
|
||||||
assert.equal(Object.keys(MODEL_INPUT_MODALITIES).length, 41)
|
assert.ok(Object.keys(MODEL_INPUT_MODALITIES).length > 0)
|
||||||
|
for (const modalities of Object.values(MODEL_INPUT_MODALITIES)) {
|
||||||
|
assert.deepEqual(modalities, ["text", "image"])
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it("marks only known reasoning models as reasoning-capable", () => {
|
it("marks only known reasoning models as reasoning-capable", () => {
|
||||||
@@ -133,38 +137,14 @@ describe("commandCodeModelsFromApiResponse()", () => {
|
|||||||
assert.equal(models[1]?.reasoning, false)
|
assert.equal(models[1]?.reasoning, false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("matches the exact command-code@1.32.2 reasoning effort catalog", () => {
|
it(`uses the command-code@${COMMAND_CODE_CLI_VERSION} reasoning effort catalog`, () => {
|
||||||
assert.deepEqual(MODEL_EFFORTS, {
|
const validEfforts = new Set(["minimal", "low", "medium", "high", "xhigh", "max"])
|
||||||
"Qwen/Qwen3.8-27B": ["low", "medium", "xhigh"],
|
assert.ok(Object.keys(MODEL_EFFORTS).length > 0)
|
||||||
"Qwen/Qwen3.8-Max": ["low", "medium", "xhigh"],
|
for (const efforts of Object.values(MODEL_EFFORTS)) {
|
||||||
"claude-fable-5": ["low", "medium", "high", "xhigh", "max"],
|
assert.ok(efforts.length > 0)
|
||||||
"claude-opus-4-7": ["low", "medium", "high", "xhigh", "max"],
|
assert.equal(new Set(efforts).size, efforts.length)
|
||||||
"claude-opus-4-8": ["low", "medium", "high", "xhigh", "max"],
|
assert.ok(efforts.every((effort) => validEfforts.has(effort)))
|
||||||
"claude-opus-5": ["low", "medium", "high", "xhigh", "max"],
|
}
|
||||||
"claude-sonnet-4-6": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"claude-sonnet-5": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"deepseek/deepseek-v4-flash": ["high", "max"],
|
|
||||||
"deepseek/deepseek-v4-flash-vision-exp": ["high", "max"],
|
|
||||||
"deepseek/deepseek-v4-pro": ["high", "max"],
|
|
||||||
"gpt-5.3-codex": ["low", "medium", "high", "xhigh"],
|
|
||||||
"gpt-5.4": ["low", "medium", "high", "xhigh"],
|
|
||||||
"gpt-5.4-mini": ["low", "medium", "high"],
|
|
||||||
"gpt-5.5": ["low", "medium", "high", "xhigh"],
|
|
||||||
"gpt-5.6-luna": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"gpt-5.6-sol": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"gpt-5.6-terra": ["low", "medium", "high", "xhigh", "max"],
|
|
||||||
"google/gemini-3.1-flash-lite": ["low", "medium", "high"],
|
|
||||||
"google/gemini-3.5-flash": ["low", "medium", "high"],
|
|
||||||
"google/gemini-3.5-flash-lite": ["low", "medium", "high"],
|
|
||||||
"google/gemini-3.6-flash": ["low", "medium", "high"],
|
|
||||||
"google/gemini-3.7-flash": ["low", "medium", "high"],
|
|
||||||
"sakana/fugu-ultra": ["high", "xhigh"],
|
|
||||||
"stealth/ox-alpha": ["low", "high", "max"],
|
|
||||||
"xai/grok-4.5": ["low", "medium", "high"],
|
|
||||||
"xai/grok-4.6": ["low", "medium", "high", "xhigh"],
|
|
||||||
"zai-org/GLM-5.2": ["high", "max"],
|
|
||||||
"zai-org/GLM-5.3": ["low", "high", "max"],
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("builds separate canonical pi and OMP metadata", () => {
|
it("builds separate canonical pi and OMP metadata", () => {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
import assert from "node:assert/strict"
|
import assert from "node:assert/strict"
|
||||||
import { after, before, beforeEach, describe, it } from "node:test"
|
import { after, before, beforeEach, describe, it } from "node:test"
|
||||||
|
|
||||||
|
import { COMMAND_CODE_CLI_VERSION } from "../src/commandcode-catalog.ts"
|
||||||
import type { AssistantMessageEvent } from "../src/core.ts"
|
import type { AssistantMessageEvent } from "../src/core.ts"
|
||||||
import { MODEL_EFFORTS, thinkingLevelMapForEfforts } from "../src/models.ts"
|
import { MODEL_EFFORTS, thinkingLevelMapForEfforts } from "../src/models.ts"
|
||||||
import {
|
import {
|
||||||
@@ -569,7 +570,7 @@ describe("streamCommandCode — request serialization", () => {
|
|||||||
|
|
||||||
const headers = server.lastRequestHeaders()
|
const headers = server.lastRequestHeaders()
|
||||||
assert.equal(headers.authorization, "Bearer mock-key")
|
assert.equal(headers.authorization, "Bearer mock-key")
|
||||||
assert.equal(headers["x-command-code-version"], "1.32.2")
|
assert.equal(headers["x-command-code-version"], COMMAND_CODE_CLI_VERSION)
|
||||||
assert.equal(headers["x-project-slug"], "repo")
|
assert.equal(headers["x-project-slug"], "repo")
|
||||||
assert.equal(headers["x-taste-learning"], "true")
|
assert.equal(headers["x-taste-learning"], "true")
|
||||||
assert.equal(headers["x-co-flag"], "false")
|
assert.equal(headers["x-co-flag"], "false")
|
||||||
|
|||||||
Reference in New Issue
Block a user