release: opensource snapshot 2026-02-27 19:25:00

This commit is contained in:
saturn
2026-02-27 19:25:00 +08:00
commit 5de9622c8b
1055 changed files with 164772 additions and 0 deletions

View File

@@ -0,0 +1,293 @@
import { promises as fs } from 'node:fs'
import path from 'node:path'
const CATALOG_DIR = path.resolve(process.cwd(), 'standards/pricing')
const CAPABILITY_CATALOG_FILE = path.resolve(process.cwd(), 'standards/capabilities/image-video.catalog.json')
const API_TYPES = new Set(['text', 'image', 'video', 'voice', 'voice-design', 'lip-sync'])
const PRICING_MODES = new Set(['flat', 'capability'])
const TEXT_TOKEN_TYPES = new Set(['input', 'output'])
function isRecord(value) {
return !!value && typeof value === 'object' && !Array.isArray(value)
}
function isNonEmptyString(value) {
return typeof value === 'string' && value.trim().length > 0
}
function isCapabilityValue(value) {
return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean'
}
function isFiniteNumber(value) {
return typeof value === 'number' && Number.isFinite(value)
}
function pushIssue(issues, file, index, field, message) {
issues.push({ file, index, field, message })
}
function getProviderKey(providerId) {
const marker = providerId.indexOf(':')
return marker === -1 ? providerId : providerId.slice(0, marker)
}
function buildModelKey(modelType, provider, modelId) {
return `${modelType}::${provider}::${modelId}`
}
async function listCatalogFiles() {
const entries = await fs.readdir(CATALOG_DIR, { withFileTypes: true })
return entries
.filter((entry) => entry.isFile() && entry.name.endsWith('.json'))
.map((entry) => path.join(CATALOG_DIR, entry.name))
}
async function readCatalog(filePath) {
const raw = await fs.readFile(filePath, 'utf8')
const parsed = JSON.parse(raw)
if (!Array.isArray(parsed)) {
throw new Error(`catalog must be an array: ${filePath}`)
}
return parsed
}
async function readCapabilityCatalog() {
const raw = await fs.readFile(CAPABILITY_CATALOG_FILE, 'utf8')
const parsed = JSON.parse(raw)
if (!Array.isArray(parsed)) {
throw new Error(`capability catalog must be an array: ${CAPABILITY_CATALOG_FILE}`)
}
return parsed
}
function extractCapabilityOptionFields(modelType, capabilities) {
if (!isRecord(capabilities)) return new Set()
const namespace = capabilities[modelType]
if (!isRecord(namespace)) return new Set()
const fields = new Set()
for (const [key, value] of Object.entries(namespace)) {
if (!key.endsWith('Options')) continue
if (!Array.isArray(value) || value.length === 0) continue
const field = key.slice(0, -'Options'.length)
fields.add(field)
}
return fields
}
function buildCapabilityOptionFieldMap(capabilityEntries) {
const map = new Map()
for (const entry of capabilityEntries) {
if (!isRecord(entry)) continue
const modelType = typeof entry.modelType === 'string' ? entry.modelType.trim() : ''
const provider = typeof entry.provider === 'string' ? entry.provider.trim() : ''
const modelId = typeof entry.modelId === 'string' ? entry.modelId.trim() : ''
if (!modelType || !provider || !modelId) continue
const fields = extractCapabilityOptionFields(modelType, entry.capabilities)
map.set(buildModelKey(modelType, provider, modelId), fields)
const providerKey = getProviderKey(provider)
const fallbackKey = buildModelKey(modelType, providerKey, modelId)
if (!map.has(fallbackKey)) {
map.set(fallbackKey, fields)
}
}
return map
}
function validateTier(issues, file, index, tier, tierIndex) {
if (!isRecord(tier)) {
pushIssue(issues, file, index, `pricing.tiers[${tierIndex}]`, 'tier must be object')
return
}
if (!isRecord(tier.when) || Object.keys(tier.when).length === 0) {
pushIssue(issues, file, index, `pricing.tiers[${tierIndex}].when`, 'when must be non-empty object')
} else {
for (const [field, value] of Object.entries(tier.when)) {
if (!isCapabilityValue(value)) {
pushIssue(
issues,
file,
index,
`pricing.tiers[${tierIndex}].when.${field}`,
'condition value must be string/number/boolean',
)
}
}
}
if (!isFiniteNumber(tier.amount) || tier.amount < 0) {
pushIssue(issues, file, index, `pricing.tiers[${tierIndex}].amount`, 'amount must be finite number >= 0')
}
}
function validateTextCapabilityTiers(issues, file, index, tiers) {
const seenTokenTypes = new Set()
for (let tierIndex = 0; tierIndex < tiers.length; tierIndex += 1) {
const tier = tiers[tierIndex]
if (!isRecord(tier) || !isRecord(tier.when)) continue
const whenFields = Object.keys(tier.when)
if (whenFields.length !== 1 || whenFields[0] !== 'tokenType') {
pushIssue(issues, file, index, `pricing.tiers[${tierIndex}].when`, 'text capability tier must only contain tokenType')
continue
}
const tokenType = tier.when.tokenType
if (typeof tokenType !== 'string' || !TEXT_TOKEN_TYPES.has(tokenType)) {
pushIssue(issues, file, index, `pricing.tiers[${tierIndex}].when.tokenType`, 'tokenType must be input or output')
continue
}
if (seenTokenTypes.has(tokenType)) {
pushIssue(issues, file, index, `pricing.tiers[${tierIndex}].when.tokenType`, `duplicate tokenType tier: ${tokenType}`)
continue
}
seenTokenTypes.add(tokenType)
}
for (const requiredTokenType of TEXT_TOKEN_TYPES) {
if (!seenTokenTypes.has(requiredTokenType)) {
pushIssue(issues, file, index, 'pricing.tiers', `missing text tier tokenType=${requiredTokenType}`)
}
}
}
function validateMediaCapabilityTierFields(issues, file, index, item, tiers, capabilityOptionFieldsMap) {
const modelType = item.apiType
const provider = item.provider
const modelId = item.modelId
const modelKey = buildModelKey(modelType, provider, modelId)
const fallbackKey = buildModelKey(modelType, getProviderKey(provider), modelId)
const optionFields = capabilityOptionFieldsMap.get(modelKey) || capabilityOptionFieldsMap.get(fallbackKey)
if (!optionFields || optionFields.size === 0) {
pushIssue(issues, file, index, 'pricing.tiers', `no capability option fields found for ${modelType} ${provider}/${modelId}`)
return
}
for (let tierIndex = 0; tierIndex < tiers.length; tierIndex += 1) {
const tier = tiers[tierIndex]
if (!isRecord(tier) || !isRecord(tier.when)) continue
for (const field of Object.keys(tier.when)) {
if (!optionFields.has(field)) {
pushIssue(
issues,
file,
index,
`pricing.tiers[${tierIndex}].when.${field}`,
`field ${field} is not declared in capabilities options for ${modelType} ${provider}/${modelId}`,
)
}
}
}
}
function validateDuplicateCapabilityTiers(issues, file, index, tiers) {
const seen = new Set()
for (let tierIndex = 0; tierIndex < tiers.length; tierIndex += 1) {
const tier = tiers[tierIndex]
if (!isRecord(tier) || !isRecord(tier.when)) continue
const signature = JSON.stringify(Object.entries(tier.when).sort((left, right) => left[0].localeCompare(right[0])))
if (seen.has(signature)) {
pushIssue(issues, file, index, `pricing.tiers[${tierIndex}].when`, 'duplicate capability tier condition')
continue
}
seen.add(signature)
}
}
function validatePricing(issues, file, index, item, capabilityOptionFieldsMap) {
const pricing = item.pricing
if (!isRecord(pricing)) {
pushIssue(issues, file, index, 'pricing', 'pricing must be object')
return
}
if (!isNonEmptyString(pricing.mode) || !PRICING_MODES.has(pricing.mode)) {
pushIssue(issues, file, index, 'pricing.mode', 'pricing.mode must be flat or capability')
return
}
if (pricing.mode === 'flat') {
if (!isFiniteNumber(pricing.flatAmount) || pricing.flatAmount < 0) {
pushIssue(issues, file, index, 'pricing.flatAmount', 'flatAmount must be finite number >= 0')
}
return
}
if (!Array.isArray(pricing.tiers) || pricing.tiers.length === 0) {
pushIssue(issues, file, index, 'pricing.tiers', 'tiers must be non-empty array')
return
}
for (let tierIndex = 0; tierIndex < pricing.tiers.length; tierIndex += 1) {
validateTier(issues, file, index, pricing.tiers[tierIndex], tierIndex)
}
validateDuplicateCapabilityTiers(issues, file, index, pricing.tiers)
if (item.apiType === 'text') {
validateTextCapabilityTiers(issues, file, index, pricing.tiers)
return
}
if (item.apiType === 'image' || item.apiType === 'video') {
validateMediaCapabilityTierFields(issues, file, index, item, pricing.tiers, capabilityOptionFieldsMap)
}
}
async function main() {
const issues = []
const files = await listCatalogFiles()
const capabilityCatalog = await readCapabilityCatalog()
const capabilityOptionFieldsMap = buildCapabilityOptionFieldMap(capabilityCatalog)
if (files.length === 0) {
throw new Error(`no pricing files found in ${CATALOG_DIR}`)
}
for (const filePath of files) {
const items = await readCatalog(filePath)
for (let index = 0; index < items.length; index += 1) {
const item = items[index]
if (!isRecord(item)) {
pushIssue(issues, filePath, index, 'entry', 'entry must be object')
continue
}
if (!isNonEmptyString(item.apiType) || !API_TYPES.has(item.apiType)) {
pushIssue(issues, filePath, index, 'apiType', 'apiType must be one of text/image/video/voice/voice-design/lip-sync')
}
if (!isNonEmptyString(item.provider)) {
pushIssue(issues, filePath, index, 'provider', 'provider must be non-empty string')
}
if (!isNonEmptyString(item.modelId)) {
pushIssue(issues, filePath, index, 'modelId', 'modelId must be non-empty string')
}
validatePricing(issues, filePath, index, item, capabilityOptionFieldsMap)
}
}
if (issues.length === 0) {
process.stdout.write(`[check-pricing-catalog] OK (${files.length} files)\n`)
return
}
const maxPrint = 50
for (const issue of issues.slice(0, maxPrint)) {
process.stdout.write(`[check-pricing-catalog] ${issue.file}#${issue.index} ${issue.field}: ${issue.message}\n`)
}
if (issues.length > maxPrint) {
process.stdout.write(`[check-pricing-catalog] ... ${issues.length - maxPrint} more issues\n`)
}
process.exitCode = 1
}
main().catch((error) => {
process.stderr.write(`[check-pricing-catalog] failed: ${String(error)}\n`)
process.exitCode = 1
})