Files
dobetternorge-tools/includes/DbnBedrockModelRouter.php
daveadmin 8a11001bff Add AWS Bedrock three-tier gateway routing (LiteLLM via Colin)
Routes AI tools across three tiers based on task complexity:
- Azure GPT-4o-mini always: redact, translate, timeline-basic, search-legal (mechanical tasks)
- Claude Haiku 4.5 (Bedrock): ask, summarize, timeline-deep, citations (Norwegian nuance)
- Claude Sonnet 4.6 (Bedrock): korrespond, legal-analysis, deep-research, barnevernet-analyze,
  discrepancy-find, advocate (public-facing legal output)

No AWS credentials in app — credentials live in LiteLLM on Colin (same as nova-lite).
Rollback: DBN_BEDROCK_ENABLED=false in .env, no code push needed.

Includes extended thinking support for Pro deep-research via chatWithThinking().
Claude Opus 4.7 constant added for future premium tier (needs litellm_config.yaml entry).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 15:22:48 +02:00

90 lines
4.0 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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;
}
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,
};
}
}