chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
import type { ConverseStreamOutput } from '@aws-sdk/client-bedrock-runtime'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { randomFloat } from '@sim/utils/random'
|
||||
import { trackForcedToolUsage } from '@/providers/utils'
|
||||
|
||||
const logger = createLogger('BedrockUtils')
|
||||
|
||||
export interface BedrockStreamUsage {
|
||||
inputTokens: number
|
||||
outputTokens: number
|
||||
}
|
||||
|
||||
export function createReadableStreamFromBedrockStream(
|
||||
bedrockStream: AsyncIterable<ConverseStreamOutput>,
|
||||
onComplete?: (content: string, usage: BedrockStreamUsage) => void
|
||||
): ReadableStream<Uint8Array> {
|
||||
let fullContent = ''
|
||||
let inputTokens = 0
|
||||
let outputTokens = 0
|
||||
|
||||
return new ReadableStream({
|
||||
async start(controller) {
|
||||
try {
|
||||
for await (const event of bedrockStream) {
|
||||
if (event.contentBlockDelta?.delta?.text) {
|
||||
const text = event.contentBlockDelta.delta.text
|
||||
fullContent += text
|
||||
controller.enqueue(new TextEncoder().encode(text))
|
||||
} else if (event.metadata?.usage) {
|
||||
inputTokens = event.metadata.usage.inputTokens ?? 0
|
||||
outputTokens = event.metadata.usage.outputTokens ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
if (onComplete) {
|
||||
onComplete(fullContent, { inputTokens, outputTokens })
|
||||
}
|
||||
|
||||
controller.close()
|
||||
} catch (err) {
|
||||
controller.error(err)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function checkForForcedToolUsage(
|
||||
toolUseBlocks: Array<{ name: string }>,
|
||||
toolChoice: any,
|
||||
forcedTools: string[],
|
||||
usedForcedTools: string[]
|
||||
): { hasUsedForcedTool: boolean; usedForcedTools: string[] } | null {
|
||||
if (typeof toolChoice === 'object' && toolChoice !== null && toolUseBlocks.length > 0) {
|
||||
const adaptedToolCalls = toolUseBlocks.map((tool) => ({ name: tool.name }))
|
||||
const adaptedToolChoice = toolChoice.tool
|
||||
? { function: { name: toolChoice.tool.name } }
|
||||
: toolChoice
|
||||
|
||||
return trackForcedToolUsage(
|
||||
adaptedToolCalls,
|
||||
adaptedToolChoice,
|
||||
logger,
|
||||
'bedrock',
|
||||
forcedTools,
|
||||
usedForcedTools
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique tool use ID for Bedrock.
|
||||
* AWS Bedrock requires toolUseId to be 1-64 characters, pattern [a-zA-Z0-9_-]+
|
||||
*/
|
||||
export function generateToolUseId(toolName: string): string {
|
||||
const timestamp = Date.now().toString(36) // Base36 timestamp (9 chars)
|
||||
const random = randomFloat().toString(36).substring(2, 7) // 5 random chars
|
||||
const suffix = `-${timestamp}-${random}` // ~15 chars
|
||||
const maxNameLength = 64 - suffix.length
|
||||
const truncatedName = toolName.substring(0, maxNameLength).replace(/[^a-zA-Z0-9_-]/g, '_')
|
||||
return `${truncatedName}${suffix}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Models whose AWS model cards state geo/cross-region inference profiles are
|
||||
* not supported ("Geo inference ID: Not supported"). These must be invoked
|
||||
* with the bare in-region model ID — prefixing them with a geo profile
|
||||
* (e.g. us.mistral...) produces an invalid model identifier.
|
||||
*/
|
||||
const GEO_PROFILE_UNSUPPORTED_MODEL_IDS = new Set([
|
||||
'mistral.mistral-large-3-675b-instruct',
|
||||
'mistral.mistral-large-2411-v1:0',
|
||||
'mistral.mistral-large-2407-v1:0',
|
||||
'mistral.magistral-small-2509',
|
||||
'mistral.ministral-3-14b-instruct',
|
||||
'mistral.ministral-3-8b-instruct',
|
||||
'mistral.ministral-3-3b-instruct',
|
||||
'mistral.mixtral-8x7b-instruct-v0:1',
|
||||
'amazon.titan-text-premier-v1:0',
|
||||
'cohere.command-r-v1:0',
|
||||
'cohere.command-r-plus-v1:0',
|
||||
])
|
||||
|
||||
/**
|
||||
* Converts a model ID to the Bedrock inference profile format.
|
||||
* AWS Bedrock requires inference profile IDs (e.g., us.anthropic.claude-...)
|
||||
* for on-demand invocation of newer models, while some models only accept
|
||||
* the bare in-region model ID.
|
||||
*
|
||||
* @param modelId - The model ID (e.g., "bedrock/anthropic.claude-sonnet-4-5-20250929-v1:0")
|
||||
* @param region - The AWS region (e.g., "us-east-1")
|
||||
* @returns The inference profile ID (e.g., "us.anthropic.claude-sonnet-4-5-20250929-v1:0")
|
||||
*/
|
||||
export function getBedrockInferenceProfileId(modelId: string, region: string): string {
|
||||
const baseModelId = modelId.startsWith('bedrock/') ? modelId.slice(8) : modelId
|
||||
|
||||
if (/^(us-gov|us|eu|apac|au|ca|jp|global)\./.test(baseModelId)) {
|
||||
return baseModelId
|
||||
}
|
||||
|
||||
if (GEO_PROFILE_UNSUPPORTED_MODEL_IDS.has(baseModelId)) {
|
||||
return baseModelId
|
||||
}
|
||||
|
||||
let inferencePrefix: string
|
||||
if (region.startsWith('us-gov-')) {
|
||||
inferencePrefix = 'us-gov'
|
||||
} else if (region.startsWith('us-') || region.startsWith('ca-')) {
|
||||
inferencePrefix = 'us'
|
||||
} else if (region.startsWith('eu-') || region === 'il-central-1') {
|
||||
inferencePrefix = 'eu'
|
||||
} else if (region.startsWith('ap-') || region.startsWith('me-')) {
|
||||
inferencePrefix = 'apac'
|
||||
} else if (region.startsWith('sa-')) {
|
||||
inferencePrefix = 'us'
|
||||
} else if (region.startsWith('af-')) {
|
||||
inferencePrefix = 'eu'
|
||||
} else {
|
||||
inferencePrefix = 'us'
|
||||
}
|
||||
|
||||
return `${inferencePrefix}.${baseModelId}`
|
||||
}
|
||||
Reference in New Issue
Block a user