mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-14 19:45:08 +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");
|
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 buildAnthropicOptions(ModelConfigEntity runtimeModel) {
|
||||||
AnthropicChatOptions.Builder builder = AnthropicChatOptions.builder();
|
AnthropicChatOptions.Builder builder = AnthropicChatOptions.builder();
|
||||||
String modelName = runtimeModel.getModelName();
|
String modelName = runtimeModel.getModelName();
|
||||||
if (StringUtils.hasText(modelName)) {
|
if (StringUtils.hasText(modelName)) {
|
||||||
builder.model(modelName);
|
builder.model(modelName);
|
||||||
}
|
}
|
||||||
boolean isClaude47 = isClaude47(modelName);
|
boolean strictSamplingContract = isClaude47OrLater(modelName);
|
||||||
|
|
||||||
// Extended thinking — request-level depth from ThinkingLevelHolder
|
// Extended thinking — request-level depth from ThinkingLevelHolder
|
||||||
String thinkingLevel = ThinkingLevelHolder.get();
|
String thinkingLevel = ThinkingLevelHolder.get();
|
||||||
@ -136,22 +159,22 @@ public class AnthropicChatModelBuilder implements ChatModelBuilder {
|
|||||||
if (thinkingEnabled) {
|
if (thinkingEnabled) {
|
||||||
// Anthropic thinking-mode constraints (pre-4.7): temperature MUST be 1,
|
// Anthropic thinking-mode constraints (pre-4.7): temperature MUST be 1,
|
||||||
// top_p forbidden, max_tokens must accommodate budget_tokens + buffer.
|
// 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.
|
// → HTTP 400) and adds an "xhigh" budget tier between high and max.
|
||||||
int budgetTokens = switch (thinkingLevel.toLowerCase()) {
|
int budgetTokens = switch (thinkingLevel.toLowerCase()) {
|
||||||
case "low" -> 4096;
|
case "low" -> 4096;
|
||||||
case "medium" -> 8192;
|
case "medium" -> 8192;
|
||||||
case "high" -> 16384;
|
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;
|
case "max" -> 32768;
|
||||||
default -> 16384;
|
default -> 16384;
|
||||||
};
|
};
|
||||||
builder.thinking(AnthropicApi.ThinkingType.ENABLED, budgetTokens);
|
builder.thinking(AnthropicApi.ThinkingType.ENABLED, budgetTokens);
|
||||||
builder.maxTokens(Math.max(budgetTokens + 4096,
|
builder.maxTokens(Math.max(budgetTokens + 4096,
|
||||||
runtimeModel.getMaxTokens() != null ? runtimeModel.getMaxTokens() : 8192));
|
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).
|
// temperature=1 (Anthropic-mandated default for thinking).
|
||||||
if (!isClaude47) {
|
if (!strictSamplingContract) {
|
||||||
builder.temperature(1.0);
|
builder.temperature(1.0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -159,14 +182,14 @@ public class AnthropicChatModelBuilder implements ChatModelBuilder {
|
|||||||
// - Pre-4.7: Anthropic accepts EITHER temperature OR top_p (not both).
|
// - 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
|
// - 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.
|
// omit them entirely so operators with legacy configs don't 400.
|
||||||
if (!isClaude47) {
|
if (!strictSamplingContract) {
|
||||||
if (runtimeModel.getTemperature() != null) {
|
if (runtimeModel.getTemperature() != null) {
|
||||||
builder.temperature(runtimeModel.getTemperature());
|
builder.temperature(runtimeModel.getTemperature());
|
||||||
} else if (runtimeModel.getTopP() != null) {
|
} else if (runtimeModel.getTopP() != null) {
|
||||||
builder.topP(runtimeModel.getTopP());
|
builder.topP(runtimeModel.getTopP());
|
||||||
}
|
}
|
||||||
} else if (runtimeModel.getTemperature() != null || runtimeModel.getTopP() != null) {
|
} 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);
|
modelName);
|
||||||
}
|
}
|
||||||
// Anthropic rejects non-positive maxTokens — clamp here so a bad config
|
// 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),
|
(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).
|
-- 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),
|
(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
|
-- Default system settings
|
||||||
MERGE INTO mate_system_setting (id, setting_key, setting_value, description, create_time, update_time)
|
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),
|
(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).
|
-- 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),
|
(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);
|
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
|
-- 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),
|
(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
|
-- 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),
|
(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);
|
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),
|
(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
|
-- 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),
|
(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)
|
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