diff --git a/mateclaw-server/src/main/java/vip/mate/agent/context/ConversationWindowManager.java b/mateclaw-server/src/main/java/vip/mate/agent/context/ConversationWindowManager.java index 22482c7a..1e0c4550 100644 --- a/mateclaw-server/src/main/java/vip/mate/agent/context/ConversationWindowManager.java +++ b/mateclaw-server/src/main/java/vip/mate/agent/context/ConversationWindowManager.java @@ -26,7 +26,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** - * 会话历史上下文窗口管理器(Hermes 风格升级版) + * 会话历史上下文窗口管理器(四阶段压缩升级版) *
* 四阶段压缩策略: *
OAuth requests get extra beta headers + a User-Agent that masquerades as * Claude Code. Without these, Anthropic's infrastructure intermittently 500s. - * Reference: hermes-agent {@code anthropic_adapter} lines 226-238 + the - * dispatch in {@code build_anthropic_client} (line 423-433). * *
Order matches hermes-agent {@code anthropic_adapter} line 427: - * {@code common_betas + _OAUTH_ONLY_BETAS} — common betas first, OAuth betas appended. + *
Order is common betas first, OAuth-only betas appended.
*/
public String allBetas() {
return String.join(",",
@@ -61,14 +58,12 @@ public class ClaudeCodeApiHeaders {
* Format: {@code claude-cli/ History note: we previously appended {@code (external, cli)}
- * after hermes-agent's pattern. That turned out to be wrong: Anthropic's
- * anti-abuse gate uses the suffix to fingerprint third-party clients
- * (hermes / OpenCode / Cline) and rate-limits them harder. Real Claude
- * Code (Electron + Node + official Anthropic JS SDK) emits the bare
- * {@code claude-cli/ Reference: hermes-agent {@code anthropic_adapter._read_claude_code_credentials_from_keychain}
- * (line 470) and {@code read_claude_code_credentials} (line 530).
*/
@Slf4j
@Component
@@ -48,8 +45,8 @@ public class ClaudeCodeCredentialsReader {
/** macOS Keychain service name written by Claude Code. */
static final String KEYCHAIN_SERVICE_NAME = "Claude Code-credentials";
- /** Hermes also queries {@code ~/.claude.json primaryApiKey} but that's a
- * managed key, not OAuth — intentionally not read here. */
+ /** {@code ~/.claude.json primaryApiKey} is a managed key, not OAuth —
+ * intentionally not read here. */
static final Path JSON_CREDENTIALS_PATH =
Paths.get(System.getProperty("user.home"), ".claude", ".credentials.json");
diff --git a/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeCredentialsWriter.java b/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeCredentialsWriter.java
index 14ca09f7..e91b5b23 100644
--- a/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeCredentialsWriter.java
+++ b/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeCredentialsWriter.java
@@ -45,10 +45,6 @@ import java.util.concurrent.TimeUnit;
* preserve {@code scopes} (Claude Code >= 2.1.81 requires
* {@code user:inference}) and any future fields we don't know about.
*
Reference: hermes-agent - * {@code anthropic_adapter._write_claude_code_credentials} (line 684-727) - * and {@code _write_claude_code_credentials_to_keychain} (line 730+). */ @Slf4j @Component diff --git a/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeOAuthService.java b/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeOAuthService.java index f3949f99..7ce5c87d 100644 --- a/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeOAuthService.java +++ b/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeOAuthService.java @@ -31,9 +31,6 @@ import java.util.Optional; *
This service does NOT handle the OAuth login flow itself — that is * RFC-062 PR-4. Until then, MateClaw piggybacks on whatever credentials the * user already has on disk from their installed Claude Code client. - * - *
Reference: hermes-agent {@code anthropic_adapter._get_claude_code_token} - * + {@code _ensure_claude_code_token_fresh} (lines 540-605). */ @Slf4j @Service diff --git a/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeTokenRefresher.java b/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeTokenRefresher.java index 0ce3cc04..3da1432f 100644 --- a/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeTokenRefresher.java +++ b/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeTokenRefresher.java @@ -32,16 +32,13 @@ import java.util.Map; *
The refresh request is a vanilla OAuth 2.0 refresh-token grant with the * public Claude Code {@code client_id}. We must spoof the Claude Code * {@code User-Agent} — Anthropic's edge filters drop unrecognised UAs. - * - *
Reference: hermes-agent {@code anthropic_adapter._refresh_claude_code_token} - * (line 605+). */ @Slf4j @Component @RequiredArgsConstructor public class ClaudeCodeTokenRefresher { - /** Public Claude Code OAuth client_id. Same value hermes-agent and OpenCode use. */ + /** Public Claude Code OAuth client_id. */ static final String CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e"; /** Endpoints tried in order until one succeeds. */ diff --git a/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeVersionDetector.java b/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeVersionDetector.java index 389801d0..8e96244e 100644 --- a/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeVersionDetector.java +++ b/mateclaw-server/src/main/java/vip/mate/llm/anthropic/oauth/ClaudeCodeVersionDetector.java @@ -22,9 +22,6 @@ import java.util.regex.Pattern; * where Claude Code isn't installed locally (the OAuth flow may still work via * a manually-imported credentials file). * - *
Reference: hermes-agent {@code anthropic_adapter._detect_claude_code_version} - * (line 239) + {@code _CLAUDE_CODE_VERSION_FALLBACK} (line 235). - * *
Result is cached for the JVM lifetime (Anthropic's UA validation tolerates * a stable version per process). Restart MateClaw to pick up a Claude Code * upgrade. @@ -36,7 +33,7 @@ public class ClaudeCodeVersionDetector { /** * Static fallback version. Update this when bumping the floor at which * Anthropic accepts spoofed Claude Code traffic (track Anthropic's - * announcements + hermes-agent's same constant for cadence). + * announcements for cadence). */ static final String FALLBACK_VERSION = "2.1.74"; diff --git a/mateclaw-server/src/main/java/vip/mate/llm/cache/AnthropicCacheOptionsFactory.java b/mateclaw-server/src/main/java/vip/mate/llm/cache/AnthropicCacheOptionsFactory.java index b76e4c9b..7aa31e50 100644 --- a/mateclaw-server/src/main/java/vip/mate/llm/cache/AnthropicCacheOptionsFactory.java +++ b/mateclaw-server/src/main/java/vip/mate/llm/cache/AnthropicCacheOptionsFactory.java @@ -19,7 +19,7 @@ import java.util.Map; * *
映射规则(对应 RFC-014 Change 1 的 SystemAndTailCacheStrategy 默认行为): *
断点选择规则(按优先级递减): *
- * 对标 hermes-agent 的 skill_manager_tool.py,让 Agent 在对话中自主创建、编辑、 - * 修补和删除 Skill。每次写入前强制安全扫描,失败则拒绝并返回原因。 + * 让 Agent 在对话中自主创建、编辑、修补和删除 Skill。 + * 每次写入前强制安全扫描,失败则拒绝并返回原因。 *
* 系统 prompt 引导 Agent 使用此工具: *
diff --git a/mateclaw-server/src/main/java/vip/mate/tool/image/provider/OpenAiImageProvider.java b/mateclaw-server/src/main/java/vip/mate/tool/image/provider/OpenAiImageProvider.java index 151f53b1..c2add30f 100644 --- a/mateclaw-server/src/main/java/vip/mate/tool/image/provider/OpenAiImageProvider.java +++ b/mateclaw-server/src/main/java/vip/mate/tool/image/provider/OpenAiImageProvider.java @@ -23,8 +23,7 @@ import java.util.Set; * 同步模式:返回图片 URL(DALL-E 系列)或 base64 data URL(gpt-image-2 系列)。 * 复用已有的 OpenAI LLM provider 的 API Key。 * - *gpt-image-2 三档质量做成 3 个虚拟 model ID(参考 hermes-agent - * plugins/image_gen/openai/__init__.py 的 model catalog 设计),让 picker + *
gpt-image-2 三档质量做成 3 个虚拟 model ID,让 picker * 能直接选 fast/balanced/high。三档底层都打到 API model {@code "gpt-image-2"}, * 区别仅在 {@code quality} 参数。 * diff --git a/mateclaw-server/src/main/resources/db/migration/h2/V44__fix_claude_sonnet_47_does_not_exist.sql b/mateclaw-server/src/main/resources/db/migration/h2/V44__fix_claude_sonnet_47_does_not_exist.sql index 4cf55e42..e6a46cfc 100644 --- a/mateclaw-server/src/main/resources/db/migration/h2/V44__fix_claude_sonnet_47_does_not_exist.sql +++ b/mateclaw-server/src/main/resources/db/migration/h2/V44__fix_claude_sonnet_47_does_not_exist.sql @@ -2,9 +2,9 @@ -- is no claude-sonnet-4-7 model. Calls return HTTP 404 with body -- {"type":"not_found_error","message":"model: claude-sonnet-4-7"}. -- --- Reference: hermes-agent anthropic_adapter.py _ANTHROPIC_OUTPUT_LIMITS --- (lines 65-93) lists claude-opus-4-7 but no claude-sonnet-4-7. The latest --- released Sonnet remains claude-sonnet-4-6 (released alongside Opus 4.6). +-- Anthropic's current model line includes claude-opus-4-7 but no +-- claude-sonnet-4-7. The latest released Sonnet remains claude-sonnet-4-6 +-- (released alongside Opus 4.6). -- -- Strategy: rename in place — preserve ids 1000000271, 1000000273, 1000000281 -- so user-customised settings (default flag, enabled flag) survive. diff --git a/mateclaw-server/src/main/resources/db/migration/mysql/V44__fix_claude_sonnet_47_does_not_exist.sql b/mateclaw-server/src/main/resources/db/migration/mysql/V44__fix_claude_sonnet_47_does_not_exist.sql index 27be8b1a..f6eb6d39 100644 --- a/mateclaw-server/src/main/resources/db/migration/mysql/V44__fix_claude_sonnet_47_does_not_exist.sql +++ b/mateclaw-server/src/main/resources/db/migration/mysql/V44__fix_claude_sonnet_47_does_not_exist.sql @@ -2,9 +2,9 @@ -- is no claude-sonnet-4-7 model. Calls return HTTP 404 with body -- {"type":"not_found_error","message":"model: claude-sonnet-4-7"}. -- --- Reference: hermes-agent anthropic_adapter.py _ANTHROPIC_OUTPUT_LIMITS --- (lines 65-93) lists claude-opus-4-7 but no claude-sonnet-4-7. The latest --- released Sonnet remains claude-sonnet-4-6 (released alongside Opus 4.6). +-- Anthropic's current model line includes claude-opus-4-7 but no +-- claude-sonnet-4-7. The latest released Sonnet remains claude-sonnet-4-6 +-- (released alongside Opus 4.6). -- -- Strategy: rename in place — preserve ids 1000000271, 1000000273, 1000000281 -- so user-customised settings (default flag, enabled flag) survive. diff --git a/mateclaw-server/src/test/java/vip/mate/llm/anthropic/oauth/ClaudeCodeApiHeadersTest.java b/mateclaw-server/src/test/java/vip/mate/llm/anthropic/oauth/ClaudeCodeApiHeadersTest.java index c14124c7..4ed3ec3a 100644 --- a/mateclaw-server/src/test/java/vip/mate/llm/anthropic/oauth/ClaudeCodeApiHeadersTest.java +++ b/mateclaw-server/src/test/java/vip/mate/llm/anthropic/oauth/ClaudeCodeApiHeadersTest.java @@ -16,8 +16,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * AND {@code oauth-2025-04-20}, comma-joined (no spaces). *
- {@code User-Agent} must be the bare {@code claude-cli/
*} — * NOT {@code claude-cli/ (external, cli)}. The {@code (external, cli)} - * suffix is what hermes-agent and other third-party clients append, and - * Anthropic uses it as a fingerprint to rate-limit the anti-abuse path. + * suffix is what third-party clients append, and Anthropic uses it as a + * fingerprint to rate-limit the anti-abuse path. * Real Claude Code emits the bare form via the official JS SDK.
Inspired by hermes-agent's plugins/image_gen/openai/__init__.py — three - * virtual model IDs (gpt-image-2-low/medium/high) all map to API model + *
Three virtual model IDs (gpt-image-2-low/medium/high) all map to API model * {@code gpt-image-2} with a different {@code quality} parameter. The new * size set is 1024x1024 / 1024x1536 / 1536x1024, distinct from DALL-E's * 1024x1024 / 1024x1792 / 1792x1024. @@ -86,8 +85,7 @@ class OpenAiImageProviderGptImage2Test { assertEquals("medium", OpenAiImageProvider.qualityForTier("gpt-image-2-medium")); assertEquals("high", OpenAiImageProvider.qualityForTier("gpt-image-2-high")); - // Defensive: any unrecognised id falls back to medium (sane default; - // matches hermes-agent DEFAULT_MODEL = gpt-image-2-medium). + // Defensive: any unrecognised id falls back to medium (sane default). assertEquals("medium", OpenAiImageProvider.qualityForTier("anything-else")); assertEquals("medium", OpenAiImageProvider.qualityForTier("")); } @@ -134,7 +132,7 @@ class OpenAiImageProviderGptImage2Test { @DisplayName("normalizeSize: extra gpt-image-2 aspect-ratio aliases (3:4, 2:3, 4:3, 3:2) work") void normalizeSize_gptImage2_extraAspectAliases() { OpenAiImageProvider p = newProvider(); - // Per hermes-agent's spec: portrait aliases → 1024x1536, landscape → 1536x1024 + // Portrait aliases → 1024x1536, landscape → 1536x1024 assertEquals("1024x1536", p.normalizeSize(null, "3:4", true)); assertEquals("1024x1536", p.normalizeSize(null, "2:3", true)); assertEquals("1536x1024", p.normalizeSize(null, "4:3", true));