d25d482dc2
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
173 lines
4.3 KiB
TypeScript
173 lines
4.3 KiB
TypeScript
/**
|
|
* Utility functions for tokenization
|
|
*/
|
|
|
|
import { createLogger } from '@sim/logger'
|
|
import { toError } from '@sim/utils/errors'
|
|
import { truncate } from '@sim/utils/string'
|
|
import {
|
|
LLM_BLOCK_TYPES,
|
|
MAX_PREVIEW_LENGTH,
|
|
TOKENIZATION_CONFIG,
|
|
} from '@/lib/tokenization/constants'
|
|
import { createTokenizationError } from '@/lib/tokenization/errors'
|
|
import type { ProviderTokenizationConfig, TokenUsage } from '@/lib/tokenization/types'
|
|
import type { BlockTokens } from '@/executor/types'
|
|
import { getProviderFromModel } from '@/providers/utils'
|
|
|
|
const logger = createLogger('TokenizationUtils')
|
|
|
|
/**
|
|
* Gets tokenization configuration for a specific provider
|
|
*/
|
|
export function getProviderConfig(providerId: string): ProviderTokenizationConfig {
|
|
const config =
|
|
TOKENIZATION_CONFIG.providers[providerId as keyof typeof TOKENIZATION_CONFIG.providers]
|
|
|
|
if (!config) {
|
|
logger.debug(`No specific config for provider ${providerId}, using fallback`, { providerId })
|
|
return TOKENIZATION_CONFIG.fallback
|
|
}
|
|
|
|
return config
|
|
}
|
|
|
|
/**
|
|
* Extracts provider ID from model name
|
|
*/
|
|
export function getProviderForTokenization(model: string): string {
|
|
try {
|
|
return getProviderFromModel(model)
|
|
} catch (error) {
|
|
logger.warn(`Failed to get provider for model ${model}, using default`, {
|
|
model,
|
|
error: toError(error).message,
|
|
})
|
|
return TOKENIZATION_CONFIG.defaults.provider
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if a block type should be tokenized
|
|
*/
|
|
export function isTokenizableBlockType(blockType?: string): boolean {
|
|
if (!blockType) return false
|
|
return LLM_BLOCK_TYPES.includes(blockType as any)
|
|
}
|
|
|
|
/**
|
|
* Checks if tokens/cost data is meaningful (non-zero)
|
|
*/
|
|
export function hasRealTokenData(
|
|
tokens?: Pick<BlockTokens, 'total' | 'input' | 'output'>
|
|
): boolean {
|
|
if (!tokens) return false
|
|
return (tokens.total ?? 0) > 0 || (tokens.input ?? 0) > 0 || (tokens.output ?? 0) > 0
|
|
}
|
|
|
|
/**
|
|
* Checks if cost data is meaningful (non-zero)
|
|
*/
|
|
export function hasRealCostData(cost?: {
|
|
total?: number
|
|
input?: number
|
|
output?: number
|
|
}): boolean {
|
|
if (!cost) return false
|
|
return (cost.total || 0) > 0 || (cost.input || 0) > 0 || (cost.output || 0) > 0
|
|
}
|
|
|
|
/**
|
|
* Safely extracts text content from various input formats
|
|
*/
|
|
export function extractTextContent(input: unknown): string {
|
|
if (typeof input === 'string') {
|
|
return input.trim()
|
|
}
|
|
|
|
if (input && typeof input === 'object') {
|
|
try {
|
|
return JSON.stringify(input)
|
|
} catch (error) {
|
|
logger.warn('Failed to stringify input object', {
|
|
inputType: typeof input,
|
|
error: toError(error).message,
|
|
})
|
|
return ''
|
|
}
|
|
}
|
|
|
|
return String(input || '')
|
|
}
|
|
|
|
/**
|
|
* Creates a preview of text for logging (truncated)
|
|
*/
|
|
export function createTextPreview(text: string): string {
|
|
return truncate(text, MAX_PREVIEW_LENGTH)
|
|
}
|
|
|
|
/**
|
|
* Validates tokenization input
|
|
*/
|
|
export function validateTokenizationInput(
|
|
model: string,
|
|
inputText: string,
|
|
outputText: string
|
|
): void {
|
|
if (!model?.trim()) {
|
|
throw createTokenizationError('INVALID_MODEL', 'Model is required for tokenization', { model })
|
|
}
|
|
|
|
if (!inputText?.trim() && !outputText?.trim()) {
|
|
throw createTokenizationError(
|
|
'MISSING_TEXT',
|
|
'Either input text or output text must be provided',
|
|
{
|
|
inputLength: inputText?.length || 0,
|
|
outputLength: outputText?.length || 0,
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Formats token count for display
|
|
*/
|
|
export function formatTokenCount(count: number): string {
|
|
if (count === 0) return '0'
|
|
if (count < 1000) return count.toString()
|
|
if (count < 1000000) return `${(count / 1000).toFixed(1)}K`
|
|
return `${(count / 1000000).toFixed(1)}M`
|
|
}
|
|
|
|
/**
|
|
* Logs tokenization operation details
|
|
*/
|
|
export function logTokenizationDetails(
|
|
operation: string,
|
|
details: {
|
|
blockId?: string
|
|
blockType?: string
|
|
model?: string
|
|
provider?: string
|
|
inputLength?: number
|
|
outputLength?: number
|
|
tokens?: TokenUsage
|
|
cost?: { input?: number; output?: number; total?: number }
|
|
method?: string
|
|
}
|
|
): void {
|
|
logger.info(`${operation}`, {
|
|
blockId: details.blockId,
|
|
blockType: details.blockType,
|
|
model: details.model,
|
|
provider: details.provider,
|
|
inputLength: details.inputLength,
|
|
outputLength: details.outputLength,
|
|
tokens: details.tokens,
|
|
cost: details.cost,
|
|
method: details.method,
|
|
})
|
|
}
|