mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
feat(llm): add Claude Opus 4.8 + 4.8 Fast model entries
This commit is contained in:
parent
0141b00270
commit
82538ca3aa
@ -121,13 +121,36 @@ public class AnthropicChatModelBuilder implements ChatModelBuilder {
|
||||
return lower.contains("4-7") || lower.contains("4.7");
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect Claude 4.8 model variants (including the {@code -fast} sibling).
|
||||
* Claude 4.8 inherits 4.7's strict API contract: temperature / top_p /
|
||||
* top_k must be unset, and the "xhigh" thinking tier is available.
|
||||
*/
|
||||
static boolean isClaude48(String modelName) {
|
||||
if (modelName == null) return false;
|
||||
String lower = modelName.toLowerCase();
|
||||
if (!lower.contains("claude")) return false;
|
||||
// Matches claude-opus-4-8, claude-opus-4.8, the "-fast" sibling
|
||||
// (claude-opus-4-8-fast / claude-opus-4.8-fast), and OpenRouter
|
||||
// prefixed forms (anthropic/claude-opus-4-8...).
|
||||
return lower.contains("4-8") || lower.contains("4.8");
|
||||
}
|
||||
|
||||
/**
|
||||
* True for any Claude 4.7+ model — the family that drops temperature /
|
||||
* top_p / top_k and exposes the "xhigh" thinking tier between high and max.
|
||||
*/
|
||||
static boolean isClaude47OrLater(String modelName) {
|
||||
return isClaude47(modelName) || isClaude48(modelName);
|
||||
}
|
||||
|
||||
AnthropicChatOptions buildAnthropicOptions(ModelConfigEntity runtimeModel) {
|
||||
AnthropicChatOptions.Builder builder = AnthropicChatOptions.builder();
|
||||
String modelName = runtimeModel.getModelName();
|
||||
if (StringUtils.hasText(modelName)) {
|
||||
builder.model(modelName);
|
||||
}
|
||||
boolean isClaude47 = isClaude47(modelName);
|
||||
boolean strictSamplingContract = isClaude47OrLater(modelName);
|
||||
|
||||
// Extended thinking — request-level depth from ThinkingLevelHolder
|
||||
String thinkingLevel = ThinkingLevelHolder.get();
|
||||
@ -136,22 +159,22 @@ public class AnthropicChatModelBuilder implements ChatModelBuilder {
|
||||
if (thinkingEnabled) {
|
||||
// Anthropic thinking-mode constraints (pre-4.7): temperature MUST be 1,
|
||||
// top_p forbidden, max_tokens must accommodate budget_tokens + buffer.
|
||||
// Claude 4.7 forbids temperature/top_p/top_k entirely (any non-null value
|
||||
// Claude 4.7+ forbids temperature/top_p/top_k entirely (any non-null value
|
||||
// → HTTP 400) and adds an "xhigh" budget tier between high and max.
|
||||
int budgetTokens = switch (thinkingLevel.toLowerCase()) {
|
||||
case "low" -> 4096;
|
||||
case "medium" -> 8192;
|
||||
case "high" -> 16384;
|
||||
case "xhigh" -> 24576; // 4.7 only — between high (16k) and max (32k)
|
||||
case "xhigh" -> 24576; // 4.7+ only — between high (16k) and max (32k)
|
||||
case "max" -> 32768;
|
||||
default -> 16384;
|
||||
};
|
||||
builder.thinking(AnthropicApi.ThinkingType.ENABLED, budgetTokens);
|
||||
builder.maxTokens(Math.max(budgetTokens + 4096,
|
||||
runtimeModel.getMaxTokens() != null ? runtimeModel.getMaxTokens() : 8192));
|
||||
// Claude 4.7: omit temperature entirely. Pre-4.7 thinking mode requires
|
||||
// Claude 4.7+: omit temperature entirely. Pre-4.7 thinking mode requires
|
||||
// temperature=1 (Anthropic-mandated default for thinking).
|
||||
if (!isClaude47) {
|
||||
if (!strictSamplingContract) {
|
||||
builder.temperature(1.0);
|
||||
}
|
||||
} else {
|
||||
@ -159,14 +182,14 @@ public class AnthropicChatModelBuilder implements ChatModelBuilder {
|
||||
// - Pre-4.7: Anthropic accepts EITHER temperature OR top_p (not both).
|
||||
// - 4.7+: rejects all of temperature/top_p/top_k unless null/default. We
|
||||
// omit them entirely so operators with legacy configs don't 400.
|
||||
if (!isClaude47) {
|
||||
if (!strictSamplingContract) {
|
||||
if (runtimeModel.getTemperature() != null) {
|
||||
builder.temperature(runtimeModel.getTemperature());
|
||||
} else if (runtimeModel.getTopP() != null) {
|
||||
builder.topP(runtimeModel.getTopP());
|
||||
}
|
||||
} else if (runtimeModel.getTemperature() != null || runtimeModel.getTopP() != null) {
|
||||
log.debug("Ignoring temperature/top_p for Claude 4.7 model {} (API rejects sampling params)",
|
||||
log.debug("Ignoring temperature/top_p for Claude 4.7+ model {} (API rejects sampling params)",
|
||||
modelName);
|
||||
}
|
||||
// Anthropic rejects non-positive maxTokens — clamp here so a bad config
|
||||
|
||||
@ -339,7 +339,15 @@ MERGE INTO mate_model_config (id, name, provider, model_name, description, tempe
|
||||
(1000000273, 'Claude Sonnet 4.6', 'openrouter', 'anthropic/claude-sonnet-4-6', 'Claude Sonnet 4.6 via OpenRouter', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
-- RFC-062: Claude 4.7 via Claude Code OAuth subscription (Pro/Max plan).
|
||||
(1000000280, 'Claude Opus 4.7', 'anthropic-claude-code', 'claude-opus-4-7', 'Claude Opus 4.7 via Claude Code Pro/Max subscription', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000281, 'Claude Sonnet 4.6', 'anthropic-claude-code', 'claude-sonnet-4-6', 'Claude Sonnet 4.6 via Claude Code Pro/Max subscription', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0);
|
||||
(1000000281, 'Claude Sonnet 4.6', 'anthropic-claude-code', 'claude-sonnet-4-6', 'Claude Sonnet 4.6 via Claude Code Pro/Max subscription', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
-- Claude 4.8 series (direct Anthropic + OpenRouter, including the -fast variant).
|
||||
-- Shares 4.7's strict sampling contract (temperature/top_p/top_k must be NULL)
|
||||
-- and the new xhigh thinking tier — handled in AnthropicChatModelBuilder.
|
||||
(1000000290, 'Claude Opus 4.8', 'anthropic', 'claude-opus-4-8', 'Anthropic Claude Opus 4.8 (xhigh adaptive thinking)', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000291, 'Claude Opus 4.8 Fast', 'anthropic', 'claude-opus-4-8-fast', 'Claude Opus 4.8 fast variant (higher output speed, 2x pricing)', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000292, 'Claude Opus 4.8', 'openrouter', 'anthropic/claude-opus-4-8', 'Claude Opus 4.8 via OpenRouter', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000293, 'Claude Opus 4.8 Fast', 'openrouter', 'anthropic/claude-opus-4-8-fast', 'Claude Opus 4.8 fast variant via OpenRouter', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000294, 'Claude Opus 4.8', 'anthropic-claude-code', 'claude-opus-4-8', 'Claude Opus 4.8 via Claude Code Pro/Max subscription', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0);
|
||||
|
||||
-- Default system settings
|
||||
MERGE INTO mate_system_setting (id, setting_key, setting_value, description, create_time, update_time)
|
||||
|
||||
@ -387,7 +387,15 @@ VALUES
|
||||
(1000000273, 'Claude Sonnet 4.6', 'openrouter', 'anthropic/claude-sonnet-4-6', 'Claude Sonnet 4.6 via OpenRouter', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
-- RFC-062: Claude 4.7 via Claude Code OAuth subscription (Pro/Max plan).
|
||||
(1000000280, 'Claude Opus 4.7', 'anthropic-claude-code', 'claude-opus-4-7', 'Claude Opus 4.7 via Claude Code Pro/Max subscription', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000281, 'Claude Sonnet 4.6', 'anthropic-claude-code', 'claude-sonnet-4-6', 'Claude Sonnet 4.6 via Claude Code Pro/Max subscription', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0)
|
||||
(1000000281, 'Claude Sonnet 4.6', 'anthropic-claude-code', 'claude-sonnet-4-6', 'Claude Sonnet 4.6 via Claude Code Pro/Max subscription', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
-- Claude 4.8 series (direct Anthropic + OpenRouter, including the -fast variant).
|
||||
-- Shares 4.7's strict sampling contract (temperature/top_p/top_k must be NULL)
|
||||
-- and the new xhigh thinking tier — handled in AnthropicChatModelBuilder.
|
||||
(1000000290, 'Claude Opus 4.8', 'anthropic', 'claude-opus-4-8', 'Anthropic Claude Opus 4.8 (xhigh adaptive thinking)', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000291, 'Claude Opus 4.8 Fast', 'anthropic', 'claude-opus-4-8-fast', 'Claude Opus 4.8 fast variant (higher output speed, 2x pricing)', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000292, 'Claude Opus 4.8', 'openrouter', 'anthropic/claude-opus-4-8', 'Claude Opus 4.8 via OpenRouter', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000293, 'Claude Opus 4.8 Fast', 'openrouter', 'anthropic/claude-opus-4-8-fast', 'Claude Opus 4.8 fast variant via OpenRouter', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000294, 'Claude Opus 4.8', 'anthropic-claude-code', 'claude-opus-4-8', 'Claude Opus 4.8 via Claude Code Pro/Max subscription', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0)
|
||||
ON DUPLICATE KEY UPDATE name=VALUES(name), provider=VALUES(provider), model_name=VALUES(model_name), description=VALUES(description), temperature=VALUES(temperature), max_tokens=VALUES(max_tokens), top_p=VALUES(top_p), builtin=VALUES(builtin), enabled=VALUES(enabled), is_default=VALUES(is_default), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
||||
|
||||
-- Default system settings
|
||||
|
||||
@ -384,7 +384,14 @@ VALUES
|
||||
(1000000273, 'Claude Sonnet 4.6', 'openrouter', 'anthropic/claude-sonnet-4-6', 'OpenRouter 代理 Claude Sonnet 4.6', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
-- RFC-062:通过 Claude Code Pro/Max 订阅调用 Claude 4.7
|
||||
(1000000280, 'Claude Opus 4.7', 'anthropic-claude-code', 'claude-opus-4-7', '通过 Claude Code Pro/Max 订阅调用 Claude Opus 4.7', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000281, 'Claude Sonnet 4.6', 'anthropic-claude-code', 'claude-sonnet-4-6', '通过 Claude Code Pro/Max 订阅调用 Claude Sonnet 4.6', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0)
|
||||
(1000000281, 'Claude Sonnet 4.6', 'anthropic-claude-code', 'claude-sonnet-4-6', '通过 Claude Code Pro/Max 订阅调用 Claude Sonnet 4.6', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
-- Claude 4.8 系列(直连 Anthropic + OpenRouter,包含 -fast 高速变体)
|
||||
-- 与 4.7 共享严格采样契约:temperature / top_p / top_k 必须为空,新增 xhigh 思考档位
|
||||
(1000000290, 'Claude Opus 4.8', 'anthropic', 'claude-opus-4-8', 'Anthropic Claude Opus 4.8(xhigh 自适应思考)', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000291, 'Claude Opus 4.8 Fast', 'anthropic', 'claude-opus-4-8-fast', 'Claude Opus 4.8 高速变体(输出更快、单价 2x)', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000292, 'Claude Opus 4.8', 'openrouter', 'anthropic/claude-opus-4-8', 'OpenRouter 代理 Claude Opus 4.8', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000293, 'Claude Opus 4.8 Fast', 'openrouter', 'anthropic/claude-opus-4-8-fast', 'OpenRouter 代理 Claude Opus 4.8 高速变体', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000294, 'Claude Opus 4.8', 'anthropic-claude-code', 'claude-opus-4-8', '通过 Claude Code Pro/Max 订阅调用 Claude Opus 4.8', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0)
|
||||
ON DUPLICATE KEY UPDATE name=VALUES(name), provider=VALUES(provider), model_name=VALUES(model_name), description=VALUES(description), temperature=VALUES(temperature), max_tokens=VALUES(max_tokens), top_p=VALUES(top_p), builtin=VALUES(builtin), enabled=VALUES(enabled), is_default=VALUES(is_default), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
||||
|
||||
-- 默认系统设置
|
||||
|
||||
@ -341,7 +341,14 @@ MERGE INTO mate_model_config (id, name, provider, model_name, description, tempe
|
||||
(1000000273, 'Claude Sonnet 4.6', 'openrouter', 'anthropic/claude-sonnet-4-6', 'OpenRouter 代理 Claude Sonnet 4.6', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
-- RFC-062:通过 Claude Code Pro/Max 订阅调用 Claude 4.7
|
||||
(1000000280, 'Claude Opus 4.7', 'anthropic-claude-code', 'claude-opus-4-7', '通过 Claude Code Pro/Max 订阅调用 Claude Opus 4.7', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000281, 'Claude Sonnet 4.6', 'anthropic-claude-code', 'claude-sonnet-4-6', '通过 Claude Code Pro/Max 订阅调用 Claude Sonnet 4.6', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0);
|
||||
(1000000281, 'Claude Sonnet 4.6', 'anthropic-claude-code', 'claude-sonnet-4-6', '通过 Claude Code Pro/Max 订阅调用 Claude Sonnet 4.6', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
-- Claude 4.8 系列(直连 Anthropic + OpenRouter,包含 -fast 高速变体)
|
||||
-- 与 4.7 共享严格采样契约:temperature / top_p / top_k 必须为空,新增 xhigh 思考档位
|
||||
(1000000290, 'Claude Opus 4.8', 'anthropic', 'claude-opus-4-8', 'Anthropic Claude Opus 4.8(xhigh 自适应思考)', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000291, 'Claude Opus 4.8 Fast', 'anthropic', 'claude-opus-4-8-fast', 'Claude Opus 4.8 高速变体(输出更快、单价 2x)', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000292, 'Claude Opus 4.8', 'openrouter', 'anthropic/claude-opus-4-8', 'OpenRouter 代理 Claude Opus 4.8', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000293, 'Claude Opus 4.8 Fast', 'openrouter', 'anthropic/claude-opus-4-8-fast', 'OpenRouter 代理 Claude Opus 4.8 高速变体', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000294, 'Claude Opus 4.8', 'anthropic-claude-code', 'claude-opus-4-8', '通过 Claude Code Pro/Max 订阅调用 Claude Opus 4.8', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0);
|
||||
|
||||
-- 默认系统设置
|
||||
MERGE INTO mate_system_setting (id, setting_key, setting_value, description, create_time, update_time)
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
-- Add Claude Opus 4.8 (regular + -fast variant) model entries to
|
||||
-- mate_model_config for existing deployments. New installs pick these up via
|
||||
-- DatabaseBootstrapRunner from data-{en,zh}.sql; this migration covers
|
||||
-- operators who already have V1 baseline + earlier versions applied.
|
||||
--
|
||||
-- Claude 4.8 inherits 4.7's strict API contract: temperature / top_p / top_k
|
||||
-- must be NULL (otherwise HTTP 400), and the "xhigh" thinking tier is
|
||||
-- available. Both are handled in AnthropicChatModelBuilder via the
|
||||
-- isClaude47OrLater() detector.
|
||||
--
|
||||
-- MERGE INTO is the H2 idempotent upsert; running this twice is a no-op.
|
||||
-- Same V number is used in mysql/ for cross-dialect parity.
|
||||
|
||||
MERGE INTO mate_model_config (id, name, provider, model_name, description, temperature, max_tokens, top_p, builtin, enabled, is_default, create_time, update_time, deleted)
|
||||
KEY (id)
|
||||
VALUES
|
||||
-- Direct Anthropic
|
||||
(1000000290, 'Claude Opus 4.8', 'anthropic', 'claude-opus-4-8', 'Anthropic Claude Opus 4.8 (xhigh adaptive thinking)', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000291, 'Claude Opus 4.8 Fast', 'anthropic', 'claude-opus-4-8-fast', 'Claude Opus 4.8 fast variant (higher output speed, 2x pricing)', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
-- OpenRouter passthrough
|
||||
(1000000292, 'Claude Opus 4.8', 'openrouter', 'anthropic/claude-opus-4-8', 'Claude Opus 4.8 via OpenRouter', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000293, 'Claude Opus 4.8 Fast', 'openrouter', 'anthropic/claude-opus-4-8-fast', 'Claude Opus 4.8 fast variant via OpenRouter', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
-- Claude Code OAuth (Pro/Max subscription)
|
||||
(1000000294, 'Claude Opus 4.8', 'anthropic-claude-code', 'claude-opus-4-8', 'Claude Opus 4.8 via Claude Code Pro/Max subscription', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0);
|
||||
@ -0,0 +1,36 @@
|
||||
-- Add Claude Opus 4.8 (regular + -fast variant) model entries to
|
||||
-- mate_model_config for existing deployments. New installs pick these up via
|
||||
-- DatabaseBootstrapRunner from data-mysql-{en,zh}.sql; this migration covers
|
||||
-- operators who already have earlier Flyway versions applied.
|
||||
--
|
||||
-- Claude 4.8 inherits 4.7's strict API contract: temperature / top_p / top_k
|
||||
-- must be NULL (otherwise HTTP 400), and the "xhigh" thinking tier is
|
||||
-- available. Both are handled in AnthropicChatModelBuilder via the
|
||||
-- isClaude47OrLater() detector.
|
||||
--
|
||||
-- INSERT ... ON DUPLICATE KEY UPDATE is the MySQL idempotent upsert.
|
||||
-- Same V number is used in h2/ for cross-dialect parity.
|
||||
|
||||
INSERT INTO mate_model_config (id, name, provider, model_name, description, temperature, max_tokens, top_p, builtin, enabled, is_default, create_time, update_time, deleted)
|
||||
VALUES
|
||||
-- Direct Anthropic
|
||||
(1000000290, 'Claude Opus 4.8', 'anthropic', 'claude-opus-4-8', 'Anthropic Claude Opus 4.8 (xhigh adaptive thinking)', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000291, 'Claude Opus 4.8 Fast', 'anthropic', 'claude-opus-4-8-fast', 'Claude Opus 4.8 fast variant (higher output speed, 2x pricing)', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
-- OpenRouter passthrough
|
||||
(1000000292, 'Claude Opus 4.8', 'openrouter', 'anthropic/claude-opus-4-8', 'Claude Opus 4.8 via OpenRouter', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
(1000000293, 'Claude Opus 4.8 Fast', 'openrouter', 'anthropic/claude-opus-4-8-fast', 'Claude Opus 4.8 fast variant via OpenRouter', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0),
|
||||
-- Claude Code OAuth (Pro/Max subscription)
|
||||
(1000000294, 'Claude Opus 4.8', 'anthropic-claude-code', 'claude-opus-4-8', 'Claude Opus 4.8 via Claude Code Pro/Max subscription', NULL, 4096, NULL, TRUE, TRUE, FALSE, NOW(), NOW(), 0)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
name = VALUES(name),
|
||||
provider = VALUES(provider),
|
||||
model_name = VALUES(model_name),
|
||||
description = VALUES(description),
|
||||
temperature = VALUES(temperature),
|
||||
max_tokens = VALUES(max_tokens),
|
||||
top_p = VALUES(top_p),
|
||||
builtin = VALUES(builtin),
|
||||
enabled = VALUES(enabled),
|
||||
is_default = VALUES(is_default),
|
||||
update_time = VALUES(update_time),
|
||||
deleted = VALUES(deleted);
|
||||
@ -0,0 +1,88 @@
|
||||
package vip.mate.llm.chatmodel;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* {@link AnthropicChatModelBuilder#isClaude48} must correctly classify the
|
||||
* Claude 4.8 model variants we'll see in production — including the
|
||||
* higher-priced {@code -fast} sibling.
|
||||
*
|
||||
* <p>Claude 4.8 inherits 4.7's strict API contract: temperature / top_p /
|
||||
* top_k must be unset, and the "xhigh" thinking tier is available. The
|
||||
* builder uses {@link AnthropicChatModelBuilder#isClaude47OrLater} to share
|
||||
* the gating logic across both generations.</p>
|
||||
*/
|
||||
class AnthropicChatModelBuilderClaude48Test {
|
||||
|
||||
@Test
|
||||
@DisplayName("isClaude48 detects hyphenated direct-API model names")
|
||||
void detect_hyphenated() {
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude48("claude-opus-4-8"));
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude48("claude-opus-4-8-fast"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("isClaude48 detects dotted variants (e.g. OpenRouter / mixed dialects)")
|
||||
void detect_dotted() {
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude48("claude-opus-4.8"));
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude48("claude-opus-4.8-fast"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("isClaude48 detects OpenRouter-style prefixed model ids")
|
||||
void detect_openrouterPrefix() {
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude48("anthropic/claude-opus-4-8"));
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude48("anthropic/claude-opus-4-8-fast"));
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude48("anthropic/claude-opus-4.8"));
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude48("anthropic/claude-opus-4.8-fast"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("isClaude48 ignores 4.5 / 4.6 / 4.7 / 3.x and unrelated names")
|
||||
void detect_negatives() {
|
||||
assertFalse(AnthropicChatModelBuilder.isClaude48("claude-opus-4-7"));
|
||||
assertFalse(AnthropicChatModelBuilder.isClaude48("claude-opus-4-6"));
|
||||
assertFalse(AnthropicChatModelBuilder.isClaude48("claude-sonnet-4-5"));
|
||||
assertFalse(AnthropicChatModelBuilder.isClaude48("claude-3-7-sonnet"));
|
||||
// The "claude" prefix guard prevents non-Anthropic models from spuriously
|
||||
// matching even if they contain "4-8" / "4.8" substrings.
|
||||
assertFalse(AnthropicChatModelBuilder.isClaude48("gpt-4-8"),
|
||||
"Non-Claude models must NOT match — claude prefix guard active");
|
||||
assertFalse(AnthropicChatModelBuilder.isClaude48("nemotron-4-8-instruct"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("isClaude48 null-safe")
|
||||
void detect_nullSafe() {
|
||||
assertFalse(AnthropicChatModelBuilder.isClaude48(null));
|
||||
assertFalse(AnthropicChatModelBuilder.isClaude48(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("isClaude48 tolerates date-stamped variants")
|
||||
void detect_dateStamped() {
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude48("claude-opus-4-8-20260601"));
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude48("claude-opus-4-8-fast-20260601"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("isClaude47OrLater unifies the 4.7 + 4.8 sampling-forbidden contract")
|
||||
void claude47OrLater_unifiesGenerations() {
|
||||
// 4.7 still matches via the legacy detector
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude47OrLater("claude-opus-4-7"));
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude47OrLater("anthropic/claude-opus-4.7"));
|
||||
// 4.8 (regular + -fast) matches via the new detector
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude47OrLater("claude-opus-4-8"));
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude47OrLater("claude-opus-4-8-fast"));
|
||||
assertTrue(AnthropicChatModelBuilder.isClaude47OrLater("anthropic/claude-opus-4.8-fast"));
|
||||
// Older Claude generations fall through
|
||||
assertFalse(AnthropicChatModelBuilder.isClaude47OrLater("claude-opus-4-6"));
|
||||
assertFalse(AnthropicChatModelBuilder.isClaude47OrLater("claude-sonnet-4-5"));
|
||||
assertFalse(AnthropicChatModelBuilder.isClaude47OrLater("claude-3-7-sonnet"));
|
||||
// Null-safe
|
||||
assertFalse(AnthropicChatModelBuilder.isClaude47OrLater(null));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user