a4b5b6e3f2
Tier engine strings (claude_haiku/claude_sonnet) were stripped back to azure_mini by per-method whitelists, so both tiers ran gpt-4o-mini and Pro charged 2x for the same model. Add a shared DbnBedrockModelRouter:: deploymentForEngine() helper and route the cloud path through it across summarize, ask, barnevernet, discrepancy, deep-research, and korrespond. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
106 lines
4.7 KiB
PHP
106 lines
4.7 KiB
PHP
<?php
|
||
declare(strict_types=1);
|
||
|
||
require_once __DIR__ . '/bootstrap.php';
|
||
|
||
/**
|
||
* Maps tool names × user tiers to LiteLLM model names for Bedrock Claude.
|
||
*
|
||
* These names must match the model_name keys in Colin's litellm_config.yaml.
|
||
* AWS credentials live only in LiteLLM — not in .env, not here.
|
||
*
|
||
* Both models are already in Colin's litellm_config.yaml:
|
||
* claude-sonnet-bedrock → bedrock/eu.anthropic.claude-sonnet-4-6 (Claude Sonnet 4.6)
|
||
* claude-haiku-bedrock → bedrock/eu.anthropic.claude-haiku-4-5-20251001-v1:0 (Claude Haiku 4.5)
|
||
* AWS IAM key: AKIA46PTFRQF2CQ47ANX (bnl-bedrock user, AmazonBedrockFullAccess)
|
||
*/
|
||
final class DbnBedrockModelRouter
|
||
{
|
||
// LiteLLM model name constants (must match litellm_config.yaml on Colin)
|
||
public const LITELLM_SONNET = 'claude-sonnet-bedrock';
|
||
public const LITELLM_HAIKU = 'claude-haiku-bedrock';
|
||
// Opus — future premium tier; add 'claude-opus-bedrock' to litellm_config.yaml on Colin first
|
||
public const LITELLM_OPUS = 'claude-opus-bedrock';
|
||
|
||
// Actual Bedrock model IDs routed by LiteLLM (for reference)
|
||
public const BEDROCK_SONNET = 'eu.anthropic.claude-sonnet-4-6';
|
||
public const BEDROCK_HAIKU = 'eu.anthropic.claude-haiku-4-5-20251001-v1:0';
|
||
public const BEDROCK_OPUS = 'eu.anthropic.claude-opus-4-7'; // not yet in litellm_config.yaml
|
||
|
||
// Models that support extended thinking (via LiteLLM thinking param passthrough)
|
||
private const THINKING_MODELS = [
|
||
self::LITELLM_SONNET,
|
||
// self::LITELLM_OPUS, // uncomment after claude-opus-bedrock added to litellm_config.yaml
|
||
];
|
||
|
||
// Tools pinned to Azure GPT-4o-mini regardless of DBN_BEDROCK_ENABLED.
|
||
// These are mechanical/structural — regex, date extraction, translation — no quality gain from Claude.
|
||
private const AZURE_PINNED = ['redact', 'translate', 'timeline', 'search-legal', 'search'];
|
||
|
||
// Tools routed to Claude Haiku 4.5 (fast, good Norwegian comprehension, 4x cheaper than Sonnet).
|
||
// Pro users escalate to Sonnet.
|
||
private const HAIKU_TOOLS = ['ask', 'summarize', 'timeline-deep', 'citations'];
|
||
|
||
/**
|
||
* Returns ['gateway' => 'azure'|'bedrock', 'model' => string|null].
|
||
* gateway='azure' means always use Azure regardless of DBN_BEDROCK_ENABLED.
|
||
* gateway='bedrock' means use Bedrock when enabled, fall back to Azure when not.
|
||
* model is null for azure-pinned tools (caller uses DbnAzureOpenAiGateway directly).
|
||
*/
|
||
public static function routeForTool(string $tool, string $tier = 'free'): array
|
||
{
|
||
$tier = in_array($tier, ['free', 'plus', 'pro'], true) ? $tier : 'free';
|
||
|
||
if (in_array($tool, self::AZURE_PINNED, true)) {
|
||
return ['gateway' => 'azure', 'model' => null];
|
||
}
|
||
|
||
if (in_array($tool, self::HAIKU_TOOLS, true)) {
|
||
// Pro users get Sonnet for these tools; free/plus get Haiku
|
||
$model = ($tier === 'pro') ? self::LITELLM_SONNET : self::LITELLM_HAIKU;
|
||
return ['gateway' => 'bedrock', 'model' => $model];
|
||
}
|
||
|
||
// All drafting/reasoning tools → Sonnet (korrespond, legal-analysis, deep-research,
|
||
// barnevernet-analyze, discrepancy-find, advocate)
|
||
return ['gateway' => 'bedrock', 'model' => self::LITELLM_SONNET];
|
||
}
|
||
|
||
/** @deprecated Use routeForTool() — kept for any direct callers outside the factory. */
|
||
public static function modelForTool(string $tool, string $tier = 'free'): string
|
||
{
|
||
$route = self::routeForTool($tool, $tier);
|
||
return $route['model'] ?? self::LITELLM_SONNET;
|
||
}
|
||
|
||
/**
|
||
* Maps a quality-tier engine string to the LiteLLM deployment name passed to
|
||
* withDeployment(). claude_haiku/claude_sonnet route to Bedrock Claude when the
|
||
* active gateway is Bedrock; otherwise they degrade to the Azure GPT-4o family.
|
||
*/
|
||
public static function deploymentForEngine(string $engine, bool $isBedrock): string
|
||
{
|
||
switch ($engine) {
|
||
case 'claude_sonnet': return $isBedrock ? self::LITELLM_SONNET : 'gpt-4o';
|
||
case 'claude_haiku': return $isBedrock ? self::LITELLM_HAIKU : 'gpt-4o-mini';
|
||
case 'azure_full': return 'gpt-4o';
|
||
case 'azure_mini':
|
||
default: return 'gpt-4o-mini';
|
||
}
|
||
}
|
||
|
||
public static function supportsThinking(string $modelName): bool
|
||
{
|
||
return in_array($modelName, self::THINKING_MODELS, true);
|
||
}
|
||
|
||
public static function maxTokensForTool(string $tool): int
|
||
{
|
||
return match ($tool) {
|
||
'deep-research', 'barnevernet-analyze', 'advocate' => 4000,
|
||
'legal-analysis', 'korrespond', 'discrepancy-find' => 3000,
|
||
default => 2000,
|
||
};
|
||
}
|
||
}
|