diff --git a/drizzle/0066_hot_mauler.sql b/drizzle/0066_hot_mauler.sql new file mode 100644 index 000000000..775699480 --- /dev/null +++ b/drizzle/0066_hot_mauler.sql @@ -0,0 +1 @@ +ALTER TABLE "providers" ADD COLUMN "anthropic_adaptive_thinking" jsonb DEFAULT NULL; \ No newline at end of file diff --git a/drizzle/meta/0066_snapshot.json b/drizzle/meta/0066_snapshot.json new file mode 100644 index 000000000..76b03150e --- /dev/null +++ b/drizzle/meta/0066_snapshot.json @@ -0,0 +1,2983 @@ +{ + "id": "6acf6a64-a2b1-41a1-aeda-ee47a6304e29", + "prevId": "5d3e46c6-0881-4776-ae60-4b8e4d06f999", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.error_rules": { + "name": "error_rules", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "pattern": { + "name": "pattern", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "match_type": { + "name": "match_type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'regex'" + }, + "category": { + "name": "category", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "override_response": { + "name": "override_response", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "override_status_code": { + "name": "override_status_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_error_rules_enabled": { + "name": "idx_error_rules_enabled", + "columns": [ + { + "expression": "is_enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "priority", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "unique_pattern": { + "name": "unique_pattern", + "columns": [ + { + "expression": "pattern", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_category": { + "name": "idx_category", + "columns": [ + { + "expression": "category", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_match_type": { + "name": "idx_match_type", + "columns": [ + { + "expression": "match_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.keys": { + "name": "keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "can_login_web_ui": { + "name": "can_login_web_ui", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "limit_5h_usd": { + "name": "limit_5h_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "limit_daily_usd": { + "name": "limit_daily_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "daily_reset_mode": { + "name": "daily_reset_mode", + "type": "daily_reset_mode", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'fixed'" + }, + "daily_reset_time": { + "name": "daily_reset_time", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "default": "'00:00'" + }, + "limit_weekly_usd": { + "name": "limit_weekly_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "limit_monthly_usd": { + "name": "limit_monthly_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "limit_total_usd": { + "name": "limit_total_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "limit_concurrent_sessions": { + "name": "limit_concurrent_sessions", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "provider_group": { + "name": "provider_group", + "type": "varchar(200)", + "primaryKey": false, + "notNull": false, + "default": "'default'" + }, + "cache_ttl_preference": { + "name": "cache_ttl_preference", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_keys_user_id": { + "name": "idx_keys_user_id", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_keys_created_at": { + "name": "idx_keys_created_at", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_keys_deleted_at": { + "name": "idx_keys_deleted_at", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.message_request": { + "name": "message_request", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cost_usd": { + "name": "cost_usd", + "type": "numeric(21, 15)", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "cost_multiplier": { + "name": "cost_multiplier", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": false + }, + "session_id": { + "name": "session_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "request_sequence": { + "name": "request_sequence", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 1 + }, + "provider_chain": { + "name": "provider_chain", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status_code": { + "name": "status_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "api_type": { + "name": "api_type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "endpoint": { + "name": "endpoint", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "original_model": { + "name": "original_model", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "input_tokens": { + "name": "input_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "output_tokens": { + "name": "output_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "ttfb_ms": { + "name": "ttfb_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cache_creation_input_tokens": { + "name": "cache_creation_input_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "cache_read_input_tokens": { + "name": "cache_read_input_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "cache_creation_5m_input_tokens": { + "name": "cache_creation_5m_input_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "cache_creation_1h_input_tokens": { + "name": "cache_creation_1h_input_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "cache_ttl_applied": { + "name": "cache_ttl_applied", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "context_1m_applied": { + "name": "context_1m_applied", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "special_settings": { + "name": "special_settings", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_stack": { + "name": "error_stack", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_cause": { + "name": "error_cause", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "blocked_by": { + "name": "blocked_by", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "blocked_reason": { + "name": "blocked_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "varchar(512)", + "primaryKey": false, + "notNull": false + }, + "messages_count": { + "name": "messages_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_message_request_user_date_cost": { + "name": "idx_message_request_user_date_cost", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "cost_usd", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"message_request\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_message_request_user_query": { + "name": "idx_message_request_user_query", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"message_request\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_message_request_session_id": { + "name": "idx_message_request_session_id", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"message_request\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_message_request_session_id_prefix": { + "name": "idx_message_request_session_id_prefix", + "columns": [ + { + "expression": "\"session_id\" varchar_pattern_ops", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"message_request\".\"deleted_at\" IS NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_message_request_session_seq": { + "name": "idx_message_request_session_seq", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "request_sequence", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"message_request\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_message_request_endpoint": { + "name": "idx_message_request_endpoint", + "columns": [ + { + "expression": "endpoint", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"message_request\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_message_request_blocked_by": { + "name": "idx_message_request_blocked_by", + "columns": [ + { + "expression": "blocked_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"message_request\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_message_request_provider_id": { + "name": "idx_message_request_provider_id", + "columns": [ + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_message_request_user_id": { + "name": "idx_message_request_user_id", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_message_request_key": { + "name": "idx_message_request_key", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_message_request_created_at": { + "name": "idx_message_request_created_at", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_message_request_deleted_at": { + "name": "idx_message_request_deleted_at", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.model_prices": { + "name": "model_prices", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "model_name": { + "name": "model_name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "price_data": { + "name": "price_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'litellm'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_model_prices_latest": { + "name": "idx_model_prices_latest", + "columns": [ + { + "expression": "model_name", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_model_prices_model_name": { + "name": "idx_model_prices_model_name", + "columns": [ + { + "expression": "model_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_model_prices_created_at": { + "name": "idx_model_prices_created_at", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_model_prices_source": { + "name": "idx_model_prices_source", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notification_settings": { + "name": "notification_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "use_legacy_mode": { + "name": "use_legacy_mode", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "circuit_breaker_enabled": { + "name": "circuit_breaker_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "circuit_breaker_webhook": { + "name": "circuit_breaker_webhook", + "type": "varchar(512)", + "primaryKey": false, + "notNull": false + }, + "daily_leaderboard_enabled": { + "name": "daily_leaderboard_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "daily_leaderboard_webhook": { + "name": "daily_leaderboard_webhook", + "type": "varchar(512)", + "primaryKey": false, + "notNull": false + }, + "daily_leaderboard_time": { + "name": "daily_leaderboard_time", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false, + "default": "'09:00'" + }, + "daily_leaderboard_top_n": { + "name": "daily_leaderboard_top_n", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 5 + }, + "cost_alert_enabled": { + "name": "cost_alert_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cost_alert_webhook": { + "name": "cost_alert_webhook", + "type": "varchar(512)", + "primaryKey": false, + "notNull": false + }, + "cost_alert_threshold": { + "name": "cost_alert_threshold", + "type": "numeric(5, 2)", + "primaryKey": false, + "notNull": false, + "default": "'0.80'" + }, + "cost_alert_check_interval": { + "name": "cost_alert_check_interval", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 60 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notification_target_bindings": { + "name": "notification_target_bindings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "notification_type": { + "name": "notification_type", + "type": "notification_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "target_id": { + "name": "target_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "schedule_cron": { + "name": "schedule_cron", + "type": "varchar(100)", + "primaryKey": false, + "notNull": false + }, + "schedule_timezone": { + "name": "schedule_timezone", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "template_override": { + "name": "template_override", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "unique_notification_target_binding": { + "name": "unique_notification_target_binding", + "columns": [ + { + "expression": "notification_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_notification_bindings_type": { + "name": "idx_notification_bindings_type", + "columns": [ + { + "expression": "notification_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_notification_bindings_target": { + "name": "idx_notification_bindings_target", + "columns": [ + { + "expression": "target_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "notification_target_bindings_target_id_webhook_targets_id_fk": { + "name": "notification_target_bindings_target_id_webhook_targets_id_fk", + "tableFrom": "notification_target_bindings", + "tableTo": "webhook_targets", + "columnsFrom": [ + "target_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.provider_endpoint_probe_logs": { + "name": "provider_endpoint_probe_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "endpoint_id": { + "name": "endpoint_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'scheduled'" + }, + "ok": { + "name": "ok", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "status_code": { + "name": "status_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "latency_ms": { + "name": "latency_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "error_type": { + "name": "error_type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_provider_endpoint_probe_logs_endpoint_created_at": { + "name": "idx_provider_endpoint_probe_logs_endpoint_created_at", + "columns": [ + { + "expression": "endpoint_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_provider_endpoint_probe_logs_created_at": { + "name": "idx_provider_endpoint_probe_logs_created_at", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "provider_endpoint_probe_logs_endpoint_id_provider_endpoints_id_fk": { + "name": "provider_endpoint_probe_logs_endpoint_id_provider_endpoints_id_fk", + "tableFrom": "provider_endpoint_probe_logs", + "tableTo": "provider_endpoints", + "columnsFrom": [ + "endpoint_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.provider_endpoints": { + "name": "provider_endpoints", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "vendor_id": { + "name": "vendor_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "provider_type": { + "name": "provider_type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'claude'" + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "varchar(200)", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_probed_at": { + "name": "last_probed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "last_probe_ok": { + "name": "last_probe_ok", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "last_probe_status_code": { + "name": "last_probe_status_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_probe_latency_ms": { + "name": "last_probe_latency_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_probe_error_type": { + "name": "last_probe_error_type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "last_probe_error_message": { + "name": "last_probe_error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "uniq_provider_endpoints_vendor_type_url": { + "name": "uniq_provider_endpoints_vendor_type_url", + "columns": [ + { + "expression": "vendor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "url", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"provider_endpoints\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_provider_endpoints_vendor_type": { + "name": "idx_provider_endpoints_vendor_type", + "columns": [ + { + "expression": "vendor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"provider_endpoints\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_provider_endpoints_enabled": { + "name": "idx_provider_endpoints_enabled", + "columns": [ + { + "expression": "is_enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vendor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"provider_endpoints\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_provider_endpoints_created_at": { + "name": "idx_provider_endpoints_created_at", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_provider_endpoints_deleted_at": { + "name": "idx_provider_endpoints_deleted_at", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "provider_endpoints_vendor_id_provider_vendors_id_fk": { + "name": "provider_endpoints_vendor_id_provider_vendors_id_fk", + "tableFrom": "provider_endpoints", + "tableTo": "provider_vendors", + "columnsFrom": [ + "vendor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.provider_vendors": { + "name": "provider_vendors", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "website_domain": { + "name": "website_domain", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "varchar(200)", + "primaryKey": false, + "notNull": false + }, + "website_url": { + "name": "website_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "favicon_url": { + "name": "favicon_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "uniq_provider_vendors_website_domain": { + "name": "uniq_provider_vendors_website_domain", + "columns": [ + { + "expression": "website_domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_provider_vendors_created_at": { + "name": "idx_provider_vendors_created_at", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.providers": { + "name": "providers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "provider_vendor_id": { + "name": "provider_vendor_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "weight": { + "name": "weight", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "group_priorities": { + "name": "group_priorities", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'null'::jsonb" + }, + "cost_multiplier": { + "name": "cost_multiplier", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": false, + "default": "'1.0'" + }, + "group_tag": { + "name": "group_tag", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + }, + "provider_type": { + "name": "provider_type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'claude'" + }, + "preserve_client_ip": { + "name": "preserve_client_ip", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "model_redirects": { + "name": "model_redirects", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "allowed_models": { + "name": "allowed_models", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'null'::jsonb" + }, + "join_claude_pool": { + "name": "join_claude_pool", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "codex_instructions_strategy": { + "name": "codex_instructions_strategy", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'auto'" + }, + "mcp_passthrough_type": { + "name": "mcp_passthrough_type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "mcp_passthrough_url": { + "name": "mcp_passthrough_url", + "type": "varchar(512)", + "primaryKey": false, + "notNull": false + }, + "limit_5h_usd": { + "name": "limit_5h_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "limit_daily_usd": { + "name": "limit_daily_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "daily_reset_mode": { + "name": "daily_reset_mode", + "type": "daily_reset_mode", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'fixed'" + }, + "daily_reset_time": { + "name": "daily_reset_time", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "default": "'00:00'" + }, + "limit_weekly_usd": { + "name": "limit_weekly_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "limit_monthly_usd": { + "name": "limit_monthly_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "limit_total_usd": { + "name": "limit_total_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "total_cost_reset_at": { + "name": "total_cost_reset_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "limit_concurrent_sessions": { + "name": "limit_concurrent_sessions", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "max_retry_attempts": { + "name": "max_retry_attempts", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "circuit_breaker_failure_threshold": { + "name": "circuit_breaker_failure_threshold", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 5 + }, + "circuit_breaker_open_duration": { + "name": "circuit_breaker_open_duration", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 1800000 + }, + "circuit_breaker_half_open_success_threshold": { + "name": "circuit_breaker_half_open_success_threshold", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 2 + }, + "proxy_url": { + "name": "proxy_url", + "type": "varchar(512)", + "primaryKey": false, + "notNull": false + }, + "proxy_fallback_to_direct": { + "name": "proxy_fallback_to_direct", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "first_byte_timeout_streaming_ms": { + "name": "first_byte_timeout_streaming_ms", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "streaming_idle_timeout_ms": { + "name": "streaming_idle_timeout_ms", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "request_timeout_non_streaming_ms": { + "name": "request_timeout_non_streaming_ms", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "website_url": { + "name": "website_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "favicon_url": { + "name": "favicon_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cache_ttl_preference": { + "name": "cache_ttl_preference", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "context_1m_preference": { + "name": "context_1m_preference", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "codex_reasoning_effort_preference": { + "name": "codex_reasoning_effort_preference", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "codex_reasoning_summary_preference": { + "name": "codex_reasoning_summary_preference", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "codex_text_verbosity_preference": { + "name": "codex_text_verbosity_preference", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "codex_parallel_tool_calls_preference": { + "name": "codex_parallel_tool_calls_preference", + "type": "varchar(10)", + "primaryKey": false, + "notNull": false + }, + "anthropic_max_tokens_preference": { + "name": "anthropic_max_tokens_preference", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "anthropic_thinking_budget_preference": { + "name": "anthropic_thinking_budget_preference", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "anthropic_adaptive_thinking": { + "name": "anthropic_adaptive_thinking", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'null'::jsonb" + }, + "gemini_google_search_preference": { + "name": "gemini_google_search_preference", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "tpm": { + "name": "tpm", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "rpm": { + "name": "rpm", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "rpd": { + "name": "rpd", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "cc": { + "name": "cc", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_providers_enabled_priority": { + "name": "idx_providers_enabled_priority", + "columns": [ + { + "expression": "is_enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "priority", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "weight", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"providers\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_providers_group": { + "name": "idx_providers_group", + "columns": [ + { + "expression": "group_tag", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"providers\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_providers_created_at": { + "name": "idx_providers_created_at", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_providers_deleted_at": { + "name": "idx_providers_deleted_at", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_providers_vendor_type": { + "name": "idx_providers_vendor_type", + "columns": [ + { + "expression": "provider_vendor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"providers\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "providers_provider_vendor_id_provider_vendors_id_fk": { + "name": "providers_provider_vendor_id_provider_vendors_id_fk", + "tableFrom": "providers", + "tableTo": "provider_vendors", + "columnsFrom": [ + "provider_vendor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.request_filters": { + "name": "request_filters", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "varchar(30)", + "primaryKey": false, + "notNull": true + }, + "match_type": { + "name": "match_type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false + }, + "target": { + "name": "target", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replacement": { + "name": "replacement", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "binding_type": { + "name": "binding_type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'global'" + }, + "provider_ids": { + "name": "provider_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "group_tags": { + "name": "group_tags", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_request_filters_enabled": { + "name": "idx_request_filters_enabled", + "columns": [ + { + "expression": "is_enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "priority", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_request_filters_scope": { + "name": "idx_request_filters_scope", + "columns": [ + { + "expression": "scope", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_request_filters_action": { + "name": "idx_request_filters_action", + "columns": [ + { + "expression": "action", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_request_filters_binding": { + "name": "idx_request_filters_binding", + "columns": [ + { + "expression": "is_enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "binding_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sensitive_words": { + "name": "sensitive_words", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "word": { + "name": "word", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "match_type": { + "name": "match_type", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'contains'" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "idx_sensitive_words_enabled": { + "name": "idx_sensitive_words_enabled", + "columns": [ + { + "expression": "is_enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "match_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_sensitive_words_created_at": { + "name": "idx_sensitive_words_created_at", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.system_settings": { + "name": "system_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "site_title": { + "name": "site_title", + "type": "varchar(128)", + "primaryKey": false, + "notNull": true, + "default": "'Claude Code Hub'" + }, + "allow_global_usage_view": { + "name": "allow_global_usage_view", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "currency_display": { + "name": "currency_display", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true, + "default": "'USD'" + }, + "billing_model_source": { + "name": "billing_model_source", + "type": "varchar(20)", + "primaryKey": false, + "notNull": true, + "default": "'original'" + }, + "timezone": { + "name": "timezone", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "enable_auto_cleanup": { + "name": "enable_auto_cleanup", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "cleanup_retention_days": { + "name": "cleanup_retention_days", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 30 + }, + "cleanup_schedule": { + "name": "cleanup_schedule", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false, + "default": "'0 2 * * *'" + }, + "cleanup_batch_size": { + "name": "cleanup_batch_size", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 10000 + }, + "enable_client_version_check": { + "name": "enable_client_version_check", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "verbose_provider_error": { + "name": "verbose_provider_error", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enable_http2": { + "name": "enable_http2", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "intercept_anthropic_warmup_requests": { + "name": "intercept_anthropic_warmup_requests", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "enable_thinking_signature_rectifier": { + "name": "enable_thinking_signature_rectifier", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "enable_thinking_budget_rectifier": { + "name": "enable_thinking_budget_rectifier", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "enable_codex_session_id_completion": { + "name": "enable_codex_session_id_completion", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "enable_claude_metadata_user_id_injection": { + "name": "enable_claude_metadata_user_id_injection", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "enable_response_fixer": { + "name": "enable_response_fixer", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "response_fixer_config": { + "name": "response_fixer_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{\"fixTruncatedJson\":true,\"fixSseFormat\":true,\"fixEncoding\":true,\"maxJsonDepth\":200,\"maxFixSize\":1048576}'::jsonb" + }, + "quota_db_refresh_interval_seconds": { + "name": "quota_db_refresh_interval_seconds", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 10 + }, + "quota_lease_percent_5h": { + "name": "quota_lease_percent_5h", + "type": "numeric(5, 4)", + "primaryKey": false, + "notNull": false, + "default": "'0.05'" + }, + "quota_lease_percent_daily": { + "name": "quota_lease_percent_daily", + "type": "numeric(5, 4)", + "primaryKey": false, + "notNull": false, + "default": "'0.05'" + }, + "quota_lease_percent_weekly": { + "name": "quota_lease_percent_weekly", + "type": "numeric(5, 4)", + "primaryKey": false, + "notNull": false, + "default": "'0.05'" + }, + "quota_lease_percent_monthly": { + "name": "quota_lease_percent_monthly", + "type": "numeric(5, 4)", + "primaryKey": false, + "notNull": false, + "default": "'0.05'" + }, + "quota_lease_cap_usd": { + "name": "quota_lease_cap_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "varchar", + "primaryKey": false, + "notNull": false, + "default": "'user'" + }, + "rpm_limit": { + "name": "rpm_limit", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "daily_limit_usd": { + "name": "daily_limit_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "provider_group": { + "name": "provider_group", + "type": "varchar(200)", + "primaryKey": false, + "notNull": false, + "default": "'default'" + }, + "tags": { + "name": "tags", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "limit_5h_usd": { + "name": "limit_5h_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "limit_weekly_usd": { + "name": "limit_weekly_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "limit_monthly_usd": { + "name": "limit_monthly_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "limit_total_usd": { + "name": "limit_total_usd", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "limit_concurrent_sessions": { + "name": "limit_concurrent_sessions", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "daily_reset_mode": { + "name": "daily_reset_mode", + "type": "daily_reset_mode", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'fixed'" + }, + "daily_reset_time": { + "name": "daily_reset_time", + "type": "varchar(5)", + "primaryKey": false, + "notNull": true, + "default": "'00:00'" + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "allowed_clients": { + "name": "allowed_clients", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "allowed_models": { + "name": "allowed_models", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_users_active_role_sort": { + "name": "idx_users_active_role_sort", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "role", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"users\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_users_enabled_expires_at": { + "name": "idx_users_enabled_expires_at", + "columns": [ + { + "expression": "is_enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"users\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_users_created_at": { + "name": "idx_users_created_at", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_users_deleted_at": { + "name": "idx_users_deleted_at", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.webhook_targets": { + "name": "webhook_targets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "provider_type": { + "name": "provider_type", + "type": "webhook_provider_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "webhook_url": { + "name": "webhook_url", + "type": "varchar(1024)", + "primaryKey": false, + "notNull": false + }, + "telegram_bot_token": { + "name": "telegram_bot_token", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "telegram_chat_id": { + "name": "telegram_chat_id", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "dingtalk_secret": { + "name": "dingtalk_secret", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "custom_template": { + "name": "custom_template", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "custom_headers": { + "name": "custom_headers", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "proxy_url": { + "name": "proxy_url", + "type": "varchar(512)", + "primaryKey": false, + "notNull": false + }, + "proxy_fallback_to_direct": { + "name": "proxy_fallback_to_direct", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_test_at": { + "name": "last_test_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "last_test_result": { + "name": "last_test_result", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.daily_reset_mode": { + "name": "daily_reset_mode", + "schema": "public", + "values": [ + "fixed", + "rolling" + ] + }, + "public.notification_type": { + "name": "notification_type", + "schema": "public", + "values": [ + "circuit_breaker", + "daily_leaderboard", + "cost_alert" + ] + }, + "public.webhook_provider_type": { + "name": "webhook_provider_type", + "schema": "public", + "values": [ + "wechat", + "feishu", + "dingtalk", + "telegram", + "custom" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 222b08392..8d4a676ae 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -463,6 +463,13 @@ "when": 1770607089556, "tag": "0065_stale_vertigo", "breakpoints": true + }, + { + "idx": 66, + "version": "7", + "when": 1770728835628, + "tag": "0066_hot_mauler", + "breakpoints": true } ] -} +} \ No newline at end of file diff --git a/messages/en/settings/providers/form/sections.json b/messages/en/settings/providers/form/sections.json index 30c54a09d..1fd60a337 100644 --- a/messages/en/settings/providers/form/sections.json +++ b/messages/en/settings/providers/form/sections.json @@ -233,10 +233,37 @@ "help": "Override thinking.budget_tokens in request body. Range: 1024-32000. Forces thinking.type to 'enabled' when set.", "options": { "inherit": "No override (follow client)", - "custom": "Custom" + "custom": "Custom", + "adaptive": "Adaptive Thinking" }, "placeholder": "e.g. 10240", "maxOutButton": "Max Out (32000)" + }, + "adaptiveThinking": { + "effort": { + "label": "Effort Level", + "help": "Controls depth of reasoning. Higher effort = deeper thinking.", + "options": { + "low": "Low", + "medium": "Medium", + "high": "High (Recommended)", + "max": "Max" + } + }, + "modelMatchMode": { + "label": "Model Matching", + "help": "Which models should use adaptive thinking.", + "options": { + "all": "All models", + "specific": "Specific models only" + } + }, + "models": { + "label": "Target Models", + "help": "Models that will use adaptive thinking. Non-matching models pass through unchanged.", + "placeholder": "e.g. claude-opus-4-6", + "addButton": "Add Model" + } } }, "geminiOverrides": { diff --git a/messages/ja/settings/providers/form/sections.json b/messages/ja/settings/providers/form/sections.json index 41d264fce..b6cad79ca 100644 --- a/messages/ja/settings/providers/form/sections.json +++ b/messages/ja/settings/providers/form/sections.json @@ -234,10 +234,37 @@ "help": "リクエストボディの thinking.budget_tokens を上書きします。範囲:1024-32000。設定すると thinking.type が 'enabled' に強制されます。", "options": { "inherit": "上書きなし(クライアントに従う)", - "custom": "カスタム" + "custom": "カスタム", + "adaptive": "アダプティブ思考" }, "placeholder": "例: 10240", "maxOutButton": "最大化 (32000)" + }, + "adaptiveThinking": { + "effort": { + "label": "思考レベル", + "help": "推論の深さを制御します。高いほど深く考えます。", + "options": { + "low": "低", + "medium": "中", + "high": "高(推奨)", + "max": "最大" + } + }, + "modelMatchMode": { + "label": "モデルマッチング", + "help": "アダプティブ思考を使用するモデル。", + "options": { + "all": "全モデル", + "specific": "特定モデルのみ" + } + }, + "models": { + "label": "対象モデル", + "help": "アダプティブ思考を使用するモデルリスト。一致しないモデルはそのまま透過されます。", + "placeholder": "例: claude-opus-4-6", + "addButton": "モデル追加" + } } }, "geminiOverrides": { diff --git a/messages/ru/settings/providers/form/sections.json b/messages/ru/settings/providers/form/sections.json index dcb6b089e..6567c5eff 100644 --- a/messages/ru/settings/providers/form/sections.json +++ b/messages/ru/settings/providers/form/sections.json @@ -234,10 +234,37 @@ "help": "Переопределяет thinking.budget_tokens в теле запроса. Диапазон: 1024-32000. При установке принудительно включает thinking.type = 'enabled'.", "options": { "inherit": "Без переопределения (следовать клиенту)", - "custom": "Пользовательское" + "custom": "Пользовательское", + "adaptive": "Адаптивное мышление" }, "placeholder": "напр. 10240", "maxOutButton": "Максимум (32000)" + }, + "adaptiveThinking": { + "effort": { + "label": "Уровень усилий", + "help": "Управляет глубиной рассуждений. Выше = глубже.", + "options": { + "low": "Низкий", + "medium": "Средний", + "high": "Высокий (Рекомендуется)", + "max": "Максимальный" + } + }, + "modelMatchMode": { + "label": "Сопоставление моделей", + "help": "Какие модели используют адаптивное мышление.", + "options": { + "all": "Все модели", + "specific": "Только определённые модели" + } + }, + "models": { + "label": "Целевые модели", + "help": "Модели с адаптивным мышлением. Несовпадающие модели передаются без изменений.", + "placeholder": "напр. claude-opus-4-6", + "addButton": "Добавить модель" + } } }, "geminiOverrides": { diff --git a/messages/zh-CN/settings/providers/form/sections.json b/messages/zh-CN/settings/providers/form/sections.json index be1be70fe..fd43dd54e 100644 --- a/messages/zh-CN/settings/providers/form/sections.json +++ b/messages/zh-CN/settings/providers/form/sections.json @@ -156,10 +156,37 @@ "help": "覆写请求体中的 thinking.budget_tokens。范围:1024-32000。设置后会强制 thinking.type 为 'enabled'。", "options": { "inherit": "不覆写(遵循客户端)", - "custom": "自定义" + "custom": "自定义", + "adaptive": "自适应思考" }, "placeholder": "如 10240", "maxOutButton": "拉满 (32000)" + }, + "adaptiveThinking": { + "effort": { + "label": "思考深度", + "help": "控制推理深度。越高 = 思考越深入。", + "options": { + "low": "低", + "medium": "中", + "high": "高(推荐)", + "max": "最大" + } + }, + "modelMatchMode": { + "label": "模型匹配", + "help": "哪些模型启用自适应思考。", + "options": { + "all": "所有模型", + "specific": "仅特定模型" + } + }, + "models": { + "label": "目标模型", + "help": "启用自适应思考的模型列表。不匹配的模型保持原样透传。", + "placeholder": "如 claude-opus-4-6", + "addButton": "添加模型" + } } }, "geminiOverrides": { diff --git a/messages/zh-TW/settings/providers/form/sections.json b/messages/zh-TW/settings/providers/form/sections.json index 6122584db..3b15f200a 100644 --- a/messages/zh-TW/settings/providers/form/sections.json +++ b/messages/zh-TW/settings/providers/form/sections.json @@ -234,10 +234,37 @@ "help": "覆寫請求體中的 thinking.budget_tokens。範圍:1024-32000。設置後會強制 thinking.type 為 'enabled'。", "options": { "inherit": "不覆寫(遵循客戶端)", - "custom": "自訂" + "custom": "自訂", + "adaptive": "自適應思考" }, "placeholder": "如 10240", "maxOutButton": "拉滿 (32000)" + }, + "adaptiveThinking": { + "effort": { + "label": "思考深度", + "help": "控制推理深度。越高 = 思考越深入。", + "options": { + "low": "低", + "medium": "中", + "high": "高(推薦)", + "max": "最大" + } + }, + "modelMatchMode": { + "label": "模型匹配", + "help": "哪些模型啟用自適應思考。", + "options": { + "all": "所有模型", + "specific": "僅特定模型" + } + }, + "models": { + "label": "目標模型", + "help": "啟用自適應思考的模型列表。不匹配的模型保持原樣透傳。", + "placeholder": "如 claude-opus-4-6", + "addButton": "新增模型" + } } }, "geminiOverrides": { diff --git a/src/actions/providers.ts b/src/actions/providers.ts index 7f78ff0d2..2323f0526 100644 --- a/src/actions/providers.ts +++ b/src/actions/providers.ts @@ -56,6 +56,9 @@ import { } from "@/repository/provider-endpoints"; import type { CacheTtlPreference } from "@/types/cache"; import type { + AnthropicAdaptiveThinkingConfig, + AnthropicMaxTokensPreference, + AnthropicThinkingBudgetPreference, CodexParallelToolCallsPreference, CodexReasoningEffortPreference, CodexReasoningSummaryPreference, @@ -281,6 +284,7 @@ export async function getProviders(): Promise { codexParallelToolCallsPreference: provider.codexParallelToolCallsPreference, anthropicMaxTokensPreference: provider.anthropicMaxTokensPreference, anthropicThinkingBudgetPreference: provider.anthropicThinkingBudgetPreference, + anthropicAdaptiveThinking: provider.anthropicAdaptiveThinking, geminiGoogleSearchPreference: provider.geminiGoogleSearchPreference, tpm: provider.tpm, rpm: provider.rpm, @@ -468,6 +472,9 @@ export async function addProvider(data: { codex_reasoning_summary_preference?: CodexReasoningSummaryPreference | null; codex_text_verbosity_preference?: CodexTextVerbosityPreference | null; codex_parallel_tool_calls_preference?: CodexParallelToolCallsPreference | null; + anthropic_max_tokens_preference?: AnthropicMaxTokensPreference | null; + anthropic_thinking_budget_preference?: AnthropicThinkingBudgetPreference | null; + anthropic_adaptive_thinking?: AnthropicAdaptiveThinkingConfig | null; max_retry_attempts?: number | null; circuit_breaker_failure_threshold?: number; circuit_breaker_open_duration?: number; @@ -635,6 +642,9 @@ export async function editProvider( codex_reasoning_summary_preference?: CodexReasoningSummaryPreference | null; codex_text_verbosity_preference?: CodexTextVerbosityPreference | null; codex_parallel_tool_calls_preference?: CodexParallelToolCallsPreference | null; + anthropic_max_tokens_preference?: AnthropicMaxTokensPreference | null; + anthropic_thinking_budget_preference?: AnthropicThinkingBudgetPreference | null; + anthropic_adaptive_thinking?: AnthropicAdaptiveThinkingConfig | null; max_retry_attempts?: number | null; circuit_breaker_failure_threshold?: number; circuit_breaker_open_duration?: number; diff --git a/src/app/[locale]/settings/providers/_components/forms/provider-form/index.tsx b/src/app/[locale]/settings/providers/_components/forms/provider-form/index.tsx index d66ad7d8d..3f9ad5f48 100644 --- a/src/app/[locale]/settings/providers/_components/forms/provider-form/index.tsx +++ b/src/app/[locale]/settings/providers/_components/forms/provider-form/index.tsx @@ -323,6 +323,10 @@ function ProviderFormContent({ codex_parallel_tool_calls_preference: state.routing.codexParallelToolCallsPreference, anthropic_max_tokens_preference: state.routing.anthropicMaxTokensPreference, anthropic_thinking_budget_preference: state.routing.anthropicThinkingBudgetPreference, + anthropic_adaptive_thinking: + state.routing.anthropicThinkingBudgetPreference === "adaptive" + ? state.routing.anthropicAdaptiveThinking + : null, gemini_google_search_preference: state.routing.geminiGoogleSearchPreference, limit_5h_usd: state.rateLimit.limit5hUsd, limit_daily_usd: state.rateLimit.limitDailyUsd, diff --git a/src/app/[locale]/settings/providers/_components/forms/provider-form/provider-form-context.tsx b/src/app/[locale]/settings/providers/_components/forms/provider-form/provider-form-context.tsx index 11fcc6ba9..1b0c6abc8 100644 --- a/src/app/[locale]/settings/providers/_components/forms/provider-form/provider-form-context.tsx +++ b/src/app/[locale]/settings/providers/_components/forms/provider-form/provider-form-context.tsx @@ -62,6 +62,7 @@ export function createInitialState( anthropicMaxTokensPreference: sourceProvider?.anthropicMaxTokensPreference ?? "inherit", anthropicThinkingBudgetPreference: sourceProvider?.anthropicThinkingBudgetPreference ?? "inherit", + anthropicAdaptiveThinking: sourceProvider?.anthropicAdaptiveThinking ?? null, geminiGoogleSearchPreference: sourceProvider?.geminiGoogleSearchPreference ?? "inherit", }, rateLimit: { @@ -178,9 +179,58 @@ export function providerFormReducer( routing: { ...state.routing, anthropicMaxTokensPreference: action.payload }, }; case "SET_ANTHROPIC_THINKING_BUDGET": + if (action.payload === "adaptive") { + return { + ...state, + routing: { + ...state.routing, + anthropicThinkingBudgetPreference: "adaptive", + anthropicAdaptiveThinking: state.routing.anthropicAdaptiveThinking ?? { + effort: "high", + modelMatchMode: "specific", + models: ["claude-opus-4-6"], + }, + }, + }; + } return { ...state, - routing: { ...state.routing, anthropicThinkingBudgetPreference: action.payload }, + routing: { + ...state.routing, + anthropicThinkingBudgetPreference: action.payload, + anthropicAdaptiveThinking: + action.payload === "inherit" ? null : state.routing.anthropicAdaptiveThinking, + }, + }; + case "SET_ADAPTIVE_THINKING_EFFORT": + return { + ...state, + routing: { + ...state.routing, + anthropicAdaptiveThinking: state.routing.anthropicAdaptiveThinking + ? { ...state.routing.anthropicAdaptiveThinking, effort: action.payload } + : null, + }, + }; + case "SET_ADAPTIVE_THINKING_MODEL_MATCH_MODE": + return { + ...state, + routing: { + ...state.routing, + anthropicAdaptiveThinking: state.routing.anthropicAdaptiveThinking + ? { ...state.routing.anthropicAdaptiveThinking, modelMatchMode: action.payload } + : null, + }, + }; + case "SET_ADAPTIVE_THINKING_MODELS": + return { + ...state, + routing: { + ...state.routing, + anthropicAdaptiveThinking: state.routing.anthropicAdaptiveThinking + ? { ...state.routing.anthropicAdaptiveThinking, models: action.payload } + : null, + }, }; case "SET_GEMINI_GOOGLE_SEARCH": return { diff --git a/src/app/[locale]/settings/providers/_components/forms/provider-form/provider-form-types.ts b/src/app/[locale]/settings/providers/_components/forms/provider-form/provider-form-types.ts index c2c662d5c..93c9f0022 100644 --- a/src/app/[locale]/settings/providers/_components/forms/provider-form/provider-form-types.ts +++ b/src/app/[locale]/settings/providers/_components/forms/provider-form/provider-form-types.ts @@ -1,5 +1,8 @@ import type { Dispatch } from "react"; import type { + AnthropicAdaptiveThinkingConfig, + AnthropicAdaptiveThinkingEffort, + AnthropicAdaptiveThinkingModelMatchMode, AnthropicMaxTokensPreference, AnthropicThinkingBudgetPreference, CodexParallelToolCallsPreference, @@ -53,6 +56,7 @@ export interface RoutingState { // Anthropic-specific anthropicMaxTokensPreference: AnthropicMaxTokensPreference; anthropicThinkingBudgetPreference: AnthropicThinkingBudgetPreference; + anthropicAdaptiveThinking: AnthropicAdaptiveThinkingConfig | null; // Gemini-specific geminiGoogleSearchPreference: GeminiGoogleSearchPreference; } @@ -130,6 +134,12 @@ export type ProviderFormAction = | { type: "SET_CODEX_PARALLEL_TOOL_CALLS"; payload: CodexParallelToolCallsPreference } | { type: "SET_ANTHROPIC_MAX_TOKENS"; payload: AnthropicMaxTokensPreference } | { type: "SET_ANTHROPIC_THINKING_BUDGET"; payload: AnthropicThinkingBudgetPreference } + | { type: "SET_ADAPTIVE_THINKING_EFFORT"; payload: AnthropicAdaptiveThinkingEffort } + | { + type: "SET_ADAPTIVE_THINKING_MODEL_MATCH_MODE"; + payload: AnthropicAdaptiveThinkingModelMatchMode; + } + | { type: "SET_ADAPTIVE_THINKING_MODELS"; payload: string[] } | { type: "SET_GEMINI_GOOGLE_SEARCH"; payload: GeminiGoogleSearchPreference } // Rate limit actions | { type: "SET_LIMIT_5H_USD"; payload: number | null } diff --git a/src/app/[locale]/settings/providers/_components/forms/provider-form/sections/routing-section.tsx b/src/app/[locale]/settings/providers/_components/forms/provider-form/sections/routing-section.tsx index 35fa62592..239a1ebad 100644 --- a/src/app/[locale]/settings/providers/_components/forms/provider-form/sections/routing-section.tsx +++ b/src/app/[locale]/settings/providers/_components/forms/provider-form/sections/routing-section.tsx @@ -18,6 +18,8 @@ import { TagInput } from "@/components/ui/tag-input"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { getProviderTypeConfig } from "@/lib/provider-type-utils"; import type { + AnthropicAdaptiveThinkingEffort, + AnthropicAdaptiveThinkingModelMatchMode, CodexParallelToolCallsPreference, CodexReasoningEffortPreference, CodexReasoningSummaryPreference, @@ -605,7 +607,9 @@ export function RoutingSection() { value={ state.routing.anthropicThinkingBudgetPreference === "inherit" ? "inherit" - : "custom" + : state.routing.anthropicThinkingBudgetPreference === "adaptive" + ? "adaptive" + : "custom" } onValueChange={(val) => { if (val === "inherit") { @@ -613,6 +617,11 @@ export function RoutingSection() { type: "SET_ANTHROPIC_THINKING_BUDGET", payload: "inherit", }); + } else if (val === "adaptive") { + dispatch({ + type: "SET_ANTHROPIC_THINKING_BUDGET", + payload: "adaptive", + }); } else { dispatch({ type: "SET_ANTHROPIC_THINKING_BUDGET", @@ -634,54 +643,56 @@ export function RoutingSection() { {t("sections.routing.anthropicOverrides.thinkingBudget.options.custom")} + + {t( + "sections.routing.anthropicOverrides.thinkingBudget.options.adaptive" + )} + - {state.routing.anthropicThinkingBudgetPreference !== "inherit" && ( - <> - { - const val = e.target.value; - if (val === "") { + {state.routing.anthropicThinkingBudgetPreference !== "inherit" && + state.routing.anthropicThinkingBudgetPreference !== "adaptive" && ( + <> + { + const val = e.target.value; + if (val === "") { + dispatch({ + type: "SET_ANTHROPIC_THINKING_BUDGET", + payload: "inherit", + }); + } else { + dispatch({ + type: "SET_ANTHROPIC_THINKING_BUDGET", + payload: val, + }); + } + }} + placeholder={t( + "sections.routing.anthropicOverrides.thinkingBudget.placeholder" + )} + disabled={state.ui.isPending} + min="1024" + max="32000" + className="flex-1" + /> + - - )} + className="px-3 py-2 text-xs bg-primary/10 hover:bg-primary/20 text-primary rounded-md transition-colors whitespace-nowrap" + disabled={state.ui.isPending} + > + {t("sections.routing.anthropicOverrides.thinkingBudget.maxOutButton")} + + + )} @@ -692,6 +703,134 @@ export function RoutingSection() { + + {state.routing.anthropicThinkingBudgetPreference === "adaptive" && + state.routing.anthropicAdaptiveThinking && ( +
+ + + +
+ + +
+
+ +

+ {t("sections.routing.anthropicOverrides.adaptiveThinking.effort.help")} +

+
+
+
+ + + + +
+ + +
+
+ +

+ {t( + "sections.routing.anthropicOverrides.adaptiveThinking.modelMatchMode.help" + )} +

+
+
+
+ + {state.routing.anthropicAdaptiveThinking.modelMatchMode === "specific" && ( + + + +
+ + dispatch({ + type: "SET_ADAPTIVE_THINKING_MODELS", + payload: models, + }) + } + placeholder={t( + "sections.routing.anthropicOverrides.adaptiveThinking.models.placeholder" + )} + disabled={state.ui.isPending} + /> + +
+
+ +

+ {t( + "sections.routing.anthropicOverrides.adaptiveThinking.models.help" + )} +

+
+
+
+ )} +
+ )} )} diff --git a/src/app/v1/_lib/proxy/thinking-budget-rectifier.ts b/src/app/v1/_lib/proxy/thinking-budget-rectifier.ts index 7a0a34873..d0fc5c04b 100644 --- a/src/app/v1/_lib/proxy/thinking-budget-rectifier.ts +++ b/src/app/v1/_lib/proxy/thinking-budget-rectifier.ts @@ -61,6 +61,24 @@ export function rectifyThinkingBudget( const thinking = message.thinking as Record | undefined; const currentThinkingType = thinking && typeof thinking.type === "string" ? thinking.type : null; + + if (currentThinkingType === "adaptive") { + return { + applied: false, + before: { + maxTokens: currentMaxTokens, + thinkingType: currentThinkingType, + thinkingBudgetTokens: + thinking && typeof thinking.budget_tokens === "number" ? thinking.budget_tokens : null, + }, + after: { + maxTokens: currentMaxTokens, + thinkingType: currentThinkingType, + thinkingBudgetTokens: + thinking && typeof thinking.budget_tokens === "number" ? thinking.budget_tokens : null, + }, + }; + } const currentThinkingBudgetTokens = thinking && typeof thinking.budget_tokens === "number" ? thinking.budget_tokens : null; diff --git a/src/drizzle/schema.ts b/src/drizzle/schema.ts index 7102dc423..7b3400a90 100644 --- a/src/drizzle/schema.ts +++ b/src/drizzle/schema.ts @@ -283,6 +283,12 @@ export const providers = pgTable('providers', { anthropicMaxTokensPreference: varchar('anthropic_max_tokens_preference', { length: 20 }), anthropicThinkingBudgetPreference: varchar('anthropic_thinking_budget_preference', { length: 20 }), + // Anthropic adaptive thinking config (JSONB) + // When anthropicThinkingBudgetPreference === "adaptive", this stores the structured config + anthropicAdaptiveThinking: jsonb('anthropic_adaptive_thinking') + .$type<{ effort: string; modelMatchMode: string; models: string[] } | null>() + .default(null), + // Gemini (generateContent API) parameter overrides (only for gemini/gemini-cli providers) // - 'inherit' or null: follow client request // - 'enabled': force inject googleSearch tool diff --git a/src/lib/anthropic/provider-overrides.ts b/src/lib/anthropic/provider-overrides.ts index 4aeeec4d5..b8c6866ed 100644 --- a/src/lib/anthropic/provider-overrides.ts +++ b/src/lib/anthropic/provider-overrides.ts @@ -1,3 +1,4 @@ +import type { AnthropicAdaptiveThinkingConfig } from "@/types/provider"; import type { ProviderParameterOverrideSpecialSetting } from "@/types/special-settings"; type AnthropicProviderOverrideConfig = { @@ -6,6 +7,7 @@ type AnthropicProviderOverrideConfig = { providerType?: string; anthropicMaxTokensPreference?: string | null; anthropicThinkingBudgetPreference?: string | null; + anthropicAdaptiveThinking?: AnthropicAdaptiveThinkingConfig | null; }; function isPlainObject(value: unknown): value is Record { @@ -58,6 +60,26 @@ export function applyAnthropicProviderOverrides( output.max_tokens = maxTokens; } + if (provider.anthropicThinkingBudgetPreference === "adaptive") { + const config = provider.anthropicAdaptiveThinking; + if (config) { + const modelId = typeof request.model === "string" ? request.model : null; + const isMatch = + config.modelMatchMode === "all" || + (modelId !== null && + config.models.some((m) => modelId === m || modelId.startsWith(`${m}-`))); + if (isMatch) { + ensureCloned(); + output.thinking = { type: "adaptive" }; + const existingOutputConfig = isPlainObject(output.output_config) + ? output.output_config + : {}; + output.output_config = { ...existingOutputConfig, effort: config.effort }; + } + } + return output; + } + const thinkingBudget = normalizeNumericPreference(provider.anthropicThinkingBudgetPreference); if (thinkingBudget !== null) { ensureCloned(); @@ -94,9 +116,12 @@ export function applyAnthropicProviderOverridesWithAudit( } const maxTokens = normalizeNumericPreference(provider.anthropicMaxTokensPreference); - const thinkingBudget = normalizeNumericPreference(provider.anthropicThinkingBudgetPreference); + const isAdaptive = provider.anthropicThinkingBudgetPreference === "adaptive"; + const thinkingBudget = isAdaptive + ? null + : normalizeNumericPreference(provider.anthropicThinkingBudgetPreference); - const hit = maxTokens !== null || thinkingBudget !== null; + const hit = maxTokens !== null || thinkingBudget !== null || isAdaptive; if (!hit) { return { request, audit: null }; @@ -114,6 +139,13 @@ export function applyAnthropicProviderOverridesWithAudit( const afterThinkingType = toAuditValue(afterThinking?.type); const afterThinkingBudgetTokens = toAuditValue(afterThinking?.budget_tokens); + const afterOutputConfig = isPlainObject(nextRequest.output_config) + ? nextRequest.output_config + : null; + const beforeOutputConfig = isPlainObject(request.output_config) ? request.output_config : null; + const afterOutputConfigEffort = toAuditValue(afterOutputConfig?.effort); + const beforeOutputConfigEffort = toAuditValue(beforeOutputConfig?.effort); + const changes: ProviderParameterOverrideSpecialSetting["changes"] = [ { path: "max_tokens", @@ -133,6 +165,12 @@ export function applyAnthropicProviderOverridesWithAudit( after: afterThinkingBudgetTokens, changed: !Object.is(beforeThinkingBudgetTokens, afterThinkingBudgetTokens), }, + { + path: "output_config.effort", + before: beforeOutputConfigEffort, + after: afterOutputConfigEffort, + changed: !Object.is(beforeOutputConfigEffort, afterOutputConfigEffort), + }, ]; const audit: ProviderParameterOverrideSpecialSetting = { diff --git a/src/lib/validation/schemas.ts b/src/lib/validation/schemas.ts index 6697b7e3b..7b630356c 100644 --- a/src/lib/validation/schemas.ts +++ b/src/lib/validation/schemas.ts @@ -43,6 +43,7 @@ const ANTHROPIC_MAX_TOKENS_PREFERENCE = z.union([ const ANTHROPIC_THINKING_BUDGET_PREFERENCE = z.union([ z.literal("inherit"), + z.literal("adaptive"), z .string() .regex(/^\d+$/, 'thinking.budget_tokens 必须为 "inherit" 或数字字符串') @@ -55,6 +56,19 @@ const ANTHROPIC_THINKING_BUDGET_PREFERENCE = z.union([ ), ]); +const ANTHROPIC_ADAPTIVE_THINKING_CONFIG = z + .object({ + effort: z.enum(["low", "medium", "high", "max"]), + modelMatchMode: z.enum(["specific", "all"]), + models: z.array(z.string().min(1).max(100)).max(50), + }) + .refine((data) => data.modelMatchMode !== "specific" || data.models.length > 0, { + message: "models must not be empty when modelMatchMode is 'specific'", + path: ["models"], + }) + .nullable() + .optional(); + // Gemini (generateContent API) Google Search preference // - 'inherit': follow client request (default) // - 'enabled': force inject googleSearch tool @@ -488,6 +502,7 @@ export const CreateProviderSchema = z anthropic_max_tokens_preference: ANTHROPIC_MAX_TOKENS_PREFERENCE.optional().default("inherit"), anthropic_thinking_budget_preference: ANTHROPIC_THINKING_BUDGET_PREFERENCE.optional().default("inherit"), + anthropic_adaptive_thinking: ANTHROPIC_ADAPTIVE_THINKING_CONFIG, gemini_google_search_preference: GEMINI_GOOGLE_SEARCH_PREFERENCE.optional().default("inherit"), max_retry_attempts: z.coerce .number() @@ -581,6 +596,16 @@ export const CreateProviderSchema = z .superRefine((data, ctx) => { const maxTokens = data.anthropic_max_tokens_preference; const budget = data.anthropic_thinking_budget_preference; + if (budget === "adaptive") { + if (!data.anthropic_adaptive_thinking) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "adaptive thinking config is required when mode is adaptive", + path: ["anthropic_adaptive_thinking"], + }); + } + return; + } if (maxTokens && maxTokens !== "inherit" && budget && budget !== "inherit") { const maxTokensNum = Number.parseInt(maxTokens, 10); const budgetNum = Number.parseInt(budget, 10); @@ -686,6 +711,7 @@ export const UpdateProviderSchema = z codex_parallel_tool_calls_preference: CODEX_PARALLEL_TOOL_CALLS_PREFERENCE.optional(), anthropic_max_tokens_preference: ANTHROPIC_MAX_TOKENS_PREFERENCE.optional(), anthropic_thinking_budget_preference: ANTHROPIC_THINKING_BUDGET_PREFERENCE.optional(), + anthropic_adaptive_thinking: ANTHROPIC_ADAPTIVE_THINKING_CONFIG, gemini_google_search_preference: GEMINI_GOOGLE_SEARCH_PREFERENCE.optional(), max_retry_attempts: z.coerce .number() @@ -780,6 +806,16 @@ export const UpdateProviderSchema = z .superRefine((data, ctx) => { const maxTokens = data.anthropic_max_tokens_preference; const budget = data.anthropic_thinking_budget_preference; + if (budget === "adaptive") { + if (!data.anthropic_adaptive_thinking) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "adaptive thinking config is required when mode is adaptive", + path: ["anthropic_adaptive_thinking"], + }); + } + return; + } if (maxTokens && maxTokens !== "inherit" && budget && budget !== "inherit") { const maxTokensNum = Number.parseInt(maxTokens, 10); const budgetNum = Number.parseInt(budget, 10); @@ -905,3 +941,4 @@ export const UpdateSystemSettingsSchema = z.object({ export const anthropicMaxTokensPreferenceSchema = ANTHROPIC_MAX_TOKENS_PREFERENCE; export const anthropicThinkingBudgetPreferenceSchema = ANTHROPIC_THINKING_BUDGET_PREFERENCE; +export const anthropicAdaptiveThinkingConfigSchema = ANTHROPIC_ADAPTIVE_THINKING_CONFIG; diff --git a/src/repository/_shared/transformers.ts b/src/repository/_shared/transformers.ts index 6ab9a8968..4c6d081a4 100644 --- a/src/repository/_shared/transformers.ts +++ b/src/repository/_shared/transformers.ts @@ -126,6 +126,7 @@ export function toProvider(dbProvider: any): Provider { codexParallelToolCallsPreference: dbProvider?.codexParallelToolCallsPreference ?? null, anthropicMaxTokensPreference: dbProvider?.anthropicMaxTokensPreference ?? null, anthropicThinkingBudgetPreference: dbProvider?.anthropicThinkingBudgetPreference ?? null, + anthropicAdaptiveThinking: dbProvider?.anthropicAdaptiveThinking ?? null, geminiGoogleSearchPreference: dbProvider?.geminiGoogleSearchPreference ?? null, tpm: dbProvider?.tpm ?? null, rpm: dbProvider?.rpm ?? null, diff --git a/src/repository/provider.ts b/src/repository/provider.ts index fa5242ab9..54ac46df2 100644 --- a/src/repository/provider.ts +++ b/src/repository/provider.ts @@ -66,6 +66,7 @@ export async function createProvider(providerData: CreateProviderData): Promise< codexParallelToolCallsPreference: providerData.codex_parallel_tool_calls_preference ?? null, anthropicMaxTokensPreference: providerData.anthropic_max_tokens_preference ?? null, anthropicThinkingBudgetPreference: providerData.anthropic_thinking_budget_preference ?? null, + anthropicAdaptiveThinking: providerData.anthropic_adaptive_thinking ?? null, geminiGoogleSearchPreference: providerData.gemini_google_search_preference ?? null, tpm: providerData.tpm, rpm: providerData.rpm, @@ -135,6 +136,7 @@ export async function createProvider(providerData: CreateProviderData): Promise< codexParallelToolCallsPreference: providers.codexParallelToolCallsPreference, anthropicMaxTokensPreference: providers.anthropicMaxTokensPreference, anthropicThinkingBudgetPreference: providers.anthropicThinkingBudgetPreference, + anthropicAdaptiveThinking: providers.anthropicAdaptiveThinking, geminiGoogleSearchPreference: providers.geminiGoogleSearchPreference, tpm: providers.tpm, rpm: providers.rpm, @@ -483,6 +485,8 @@ export async function updateProvider( if (providerData.anthropic_thinking_budget_preference !== undefined) dbData.anthropicThinkingBudgetPreference = providerData.anthropic_thinking_budget_preference ?? null; + if (providerData.anthropic_adaptive_thinking !== undefined) + dbData.anthropicAdaptiveThinking = providerData.anthropic_adaptive_thinking ?? null; if (providerData.gemini_google_search_preference !== undefined) dbData.geminiGoogleSearchPreference = providerData.gemini_google_search_preference ?? null; if (providerData.tpm !== undefined) dbData.tpm = providerData.tpm; @@ -584,6 +588,7 @@ export async function updateProvider( codexParallelToolCallsPreference: providers.codexParallelToolCallsPreference, anthropicMaxTokensPreference: providers.anthropicMaxTokensPreference, anthropicThinkingBudgetPreference: providers.anthropicThinkingBudgetPreference, + anthropicAdaptiveThinking: providers.anthropicAdaptiveThinking, geminiGoogleSearchPreference: providers.geminiGoogleSearchPreference, tpm: providers.tpm, rpm: providers.rpm, diff --git a/src/types/provider.ts b/src/types/provider.ts index 8d4a274db..a1eac206c 100644 --- a/src/types/provider.ts +++ b/src/types/provider.ts @@ -33,8 +33,18 @@ export type CodexParallelToolCallsPreference = "inherit" | "true" | "false"; // Anthropic (Messages API) parameter overrides // - "inherit": follow client request (default) // - numeric string: force override to that value +// - "adaptive": use adaptive thinking mode (read config from anthropicAdaptiveThinking) export type AnthropicMaxTokensPreference = "inherit" | string; -export type AnthropicThinkingBudgetPreference = "inherit" | string; +export type AnthropicThinkingBudgetPreference = "inherit" | "adaptive" | string; + +// Anthropic adaptive thinking configuration +export type AnthropicAdaptiveThinkingEffort = "low" | "medium" | "high" | "max"; +export type AnthropicAdaptiveThinkingModelMatchMode = "specific" | "all"; +export interface AnthropicAdaptiveThinkingConfig { + effort: AnthropicAdaptiveThinkingEffort; + modelMatchMode: AnthropicAdaptiveThinkingModelMatchMode; + models: string[]; +} // Gemini (generateContent API) parameter overrides // - "inherit": follow client request (default) @@ -134,6 +144,7 @@ export interface Provider { // Anthropic (Messages API) parameter overrides (only for claude/claude-auth providers) anthropicMaxTokensPreference: AnthropicMaxTokensPreference | null; anthropicThinkingBudgetPreference: AnthropicThinkingBudgetPreference | null; + anthropicAdaptiveThinking: AnthropicAdaptiveThinkingConfig | null; // Gemini (generateContent API) parameter overrides (only for gemini/gemini-cli providers) geminiGoogleSearchPreference: GeminiGoogleSearchPreference | null; @@ -211,6 +222,7 @@ export interface ProviderDisplay { codexParallelToolCallsPreference: CodexParallelToolCallsPreference | null; anthropicMaxTokensPreference: AnthropicMaxTokensPreference | null; anthropicThinkingBudgetPreference: AnthropicThinkingBudgetPreference | null; + anthropicAdaptiveThinking: AnthropicAdaptiveThinkingConfig | null; geminiGoogleSearchPreference: GeminiGoogleSearchPreference | null; // 废弃字段(保留向后兼容) tpm: number | null; @@ -301,6 +313,7 @@ export interface CreateProviderData { codex_parallel_tool_calls_preference?: CodexParallelToolCallsPreference | null; anthropic_max_tokens_preference?: AnthropicMaxTokensPreference | null; anthropic_thinking_budget_preference?: AnthropicThinkingBudgetPreference | null; + anthropic_adaptive_thinking?: AnthropicAdaptiveThinkingConfig | null; gemini_google_search_preference?: GeminiGoogleSearchPreference | null; // 废弃字段(保留向后兼容) @@ -373,6 +386,7 @@ export interface UpdateProviderData { codex_parallel_tool_calls_preference?: CodexParallelToolCallsPreference | null; anthropic_max_tokens_preference?: AnthropicMaxTokensPreference | null; anthropic_thinking_budget_preference?: AnthropicThinkingBudgetPreference | null; + anthropic_adaptive_thinking?: AnthropicAdaptiveThinkingConfig | null; gemini_google_search_preference?: GeminiGoogleSearchPreference | null; // 废弃字段(保留向后兼容) diff --git a/tests/unit/proxy/anthropic-provider-overrides.test.ts b/tests/unit/proxy/anthropic-provider-overrides.test.ts index 962218a6f..888add3c4 100644 --- a/tests/unit/proxy/anthropic-provider-overrides.test.ts +++ b/tests/unit/proxy/anthropic-provider-overrides.test.ts @@ -772,4 +772,232 @@ describe("Anthropic Provider Overrides", () => { expect(budgetChange?.after).toBe(10000); }); }); + + describe("Adaptive thinking mode", () => { + it("should apply adaptive thinking for matching model (all models mode)", () => { + const provider = { + providerType: "claude", + anthropicThinkingBudgetPreference: "adaptive", + anthropicAdaptiveThinking: { + effort: "high" as const, + modelMatchMode: "all" as const, + models: [], + }, + }; + + const input: Record = { + model: "claude-opus-4-6", + messages: [], + max_tokens: 8000, + }; + + const output = applyAnthropicProviderOverrides(provider, input); + expect(output.thinking).toEqual({ type: "adaptive" }); + expect(output.output_config).toEqual({ effort: "high" }); + }); + + it("should apply adaptive thinking for matching model (specific models mode)", () => { + const provider = { + providerType: "claude", + anthropicThinkingBudgetPreference: "adaptive", + anthropicAdaptiveThinking: { + effort: "max" as const, + modelMatchMode: "specific" as const, + models: ["claude-opus-4-6"], + }, + }; + + const input: Record = { + model: "claude-opus-4-6", + messages: [], + }; + + const output = applyAnthropicProviderOverrides(provider, input); + expect(output.thinking).toEqual({ type: "adaptive" }); + expect(output.output_config).toEqual({ effort: "max" }); + }); + + it("should passthrough for non-matching model (specific models mode)", () => { + const provider = { + providerType: "claude", + anthropicThinkingBudgetPreference: "adaptive", + anthropicAdaptiveThinking: { + effort: "high" as const, + modelMatchMode: "specific" as const, + models: ["claude-opus-4-6"], + }, + }; + + const input: Record = { + model: "claude-sonnet-4-5", + messages: [], + max_tokens: 8000, + thinking: { type: "enabled", budget_tokens: 5000 }, + }; + const snapshot = structuredClone(input); + + const output = applyAnthropicProviderOverrides(provider, input); + expect(output).toEqual(snapshot); + }); + + it("should preserve existing output_config properties", () => { + const provider = { + providerType: "claude", + anthropicThinkingBudgetPreference: "adaptive", + anthropicAdaptiveThinking: { + effort: "medium" as const, + modelMatchMode: "all" as const, + models: [], + }, + }; + + const input: Record = { + model: "claude-opus-4-6", + messages: [], + output_config: { some_other_field: "preserve" }, + }; + + const output = applyAnthropicProviderOverrides(provider, input); + const outputConfig = output.output_config as Record; + expect(outputConfig.effort).toBe("medium"); + expect(outputConfig.some_other_field).toBe("preserve"); + }); + + it("should apply adaptive with effort 'low'", () => { + const provider = { + providerType: "claude", + anthropicThinkingBudgetPreference: "adaptive", + anthropicAdaptiveThinking: { + effort: "low" as const, + modelMatchMode: "all" as const, + models: [], + }, + }; + + const input: Record = { + model: "claude-opus-4-6", + messages: [], + }; + + const output = applyAnthropicProviderOverrides(provider, input); + expect(output.output_config).toEqual({ effort: "low" }); + }); + + it("should remove budget_tokens from existing thinking when applying adaptive", () => { + const provider = { + providerType: "claude", + anthropicThinkingBudgetPreference: "adaptive", + anthropicAdaptiveThinking: { + effort: "high" as const, + modelMatchMode: "all" as const, + models: [], + }, + }; + + const input: Record = { + model: "claude-opus-4-6", + messages: [], + thinking: { type: "enabled", budget_tokens: 10240 }, + }; + + const output = applyAnthropicProviderOverrides(provider, input); + const thinking = output.thinking as Record; + expect(thinking.type).toBe("adaptive"); + expect(thinking.budget_tokens).toBeUndefined(); + }); + + it("should passthrough when adaptive config is null (defensive)", () => { + const provider = { + providerType: "claude", + anthropicThinkingBudgetPreference: "adaptive", + anthropicAdaptiveThinking: null, + }; + + const input: Record = { + model: "claude-opus-4-6", + messages: [], + max_tokens: 8000, + }; + const snapshot = structuredClone(input); + + const output = applyAnthropicProviderOverrides(provider, input); + expect(output).toEqual(snapshot); + }); + + it("should apply adaptive + max_tokens override together", () => { + const provider = { + providerType: "claude", + anthropicMaxTokensPreference: "32000", + anthropicThinkingBudgetPreference: "adaptive", + anthropicAdaptiveThinking: { + effort: "high" as const, + modelMatchMode: "all" as const, + models: [], + }, + }; + + const input: Record = { + model: "claude-opus-4-6", + messages: [], + max_tokens: 8000, + }; + + const output = applyAnthropicProviderOverrides(provider, input); + expect(output.max_tokens).toBe(32000); + expect(output.thinking).toEqual({ type: "adaptive" }); + expect(output.output_config).toEqual({ effort: "high" }); + }); + + it("should match model prefix (claude-opus-4-6 matches claude-opus-4-6-20250514)", () => { + const provider = { + providerType: "claude", + anthropicThinkingBudgetPreference: "adaptive", + anthropicAdaptiveThinking: { + effort: "high" as const, + modelMatchMode: "specific" as const, + models: ["claude-opus-4-6"], + }, + }; + + const input: Record = { + model: "claude-opus-4-6-20250514", + messages: [], + }; + + const output = applyAnthropicProviderOverrides(provider, input); + expect(output.thinking).toEqual({ type: "adaptive" }); + expect(output.output_config).toEqual({ effort: "high" }); + }); + + it("should track output_config.effort in audit for adaptive mode", () => { + const provider = { + id: 1, + name: "adaptive-provider", + providerType: "claude", + anthropicThinkingBudgetPreference: "adaptive", + anthropicAdaptiveThinking: { + effort: "high" as const, + modelMatchMode: "all" as const, + models: [], + }, + }; + + const input: Record = { + model: "claude-opus-4-6", + messages: [], + }; + + const result = applyAnthropicProviderOverridesWithAudit(provider, input); + expect(result.audit?.hit).toBe(true); + expect(result.audit?.changed).toBe(true); + + const effortChange = result.audit?.changes.find((c) => c.path === "output_config.effort"); + expect(effortChange?.before).toBeNull(); + expect(effortChange?.after).toBe("high"); + expect(effortChange?.changed).toBe(true); + + const thinkingTypeChange = result.audit?.changes.find((c) => c.path === "thinking.type"); + expect(thinkingTypeChange?.after).toBe("adaptive"); + }); + }); }); diff --git a/tests/unit/proxy/thinking-budget-rectifier.test.ts b/tests/unit/proxy/thinking-budget-rectifier.test.ts new file mode 100644 index 000000000..0cd71bb35 --- /dev/null +++ b/tests/unit/proxy/thinking-budget-rectifier.test.ts @@ -0,0 +1,54 @@ +import { describe, expect, it } from "vitest"; +import { + detectThinkingBudgetRectifierTrigger, + rectifyThinkingBudget, +} from "@/app/v1/_lib/proxy/thinking-budget-rectifier"; + +describe("ThinkingBudgetRectifier", () => { + describe("detectThinkingBudgetRectifierTrigger", () => { + it("should detect budget_tokens_too_low from typical Anthropic error", () => { + const trigger = detectThinkingBudgetRectifierTrigger( + "thinking.enabled.budget_tokens: Input should be greater than or equal to 1024" + ); + expect(trigger).toBe("budget_tokens_too_low"); + }); + + it("should return null for unrelated errors", () => { + const trigger = detectThinkingBudgetRectifierTrigger("rate limit exceeded"); + expect(trigger).toBeNull(); + }); + + it("should return null for null/undefined input", () => { + expect(detectThinkingBudgetRectifierTrigger(null)).toBeNull(); + expect(detectThinkingBudgetRectifierTrigger(undefined)).toBeNull(); + }); + }); + + describe("rectifyThinkingBudget", () => { + it("should rectify standard thinking budget", () => { + const message: Record = { + model: "claude-opus-4-6", + max_tokens: 4000, + thinking: { type: "enabled", budget_tokens: 500 }, + }; + + const result = rectifyThinkingBudget(message); + expect(result.applied).toBe(true); + expect(result.after.thinkingBudgetTokens).toBe(32000); + expect(result.after.thinkingType).toBe("enabled"); + }); + + it("should skip rectification when thinking.type is adaptive", () => { + const message: Record = { + model: "claude-opus-4-6", + max_tokens: 8000, + thinking: { type: "adaptive" }, + }; + + const result = rectifyThinkingBudget(message); + expect(result.applied).toBe(false); + expect(result.before.thinkingType).toBe("adaptive"); + expect(result.after.thinkingType).toBe("adaptive"); + }); + }); +});