feat: sync latest workspace changes

This commit is contained in:
coso
2026-04-19 18:50:13 +08:00
parent 3715b6e304
commit 9f31ba4cd7
301 changed files with 14618 additions and 14009 deletions
@@ -76,6 +76,7 @@ pub struct AnthropicProvider {
api_client: ApiClient,
model: ModelConfig,
supports_streaming: bool,
automatic_prompt_cache: bool,
name: String,
}
@@ -99,6 +100,7 @@ impl AnthropicProvider {
};
let auth = resolve_anthropic_auth(&host, api_key);
let automatic_prompt_cache = supports_automatic_prompt_cache_for_host(&host);
let api_client =
ApiClient::new(host, auth)?.with_header("anthropic-version", ANTHROPIC_API_VERSION)?;
@@ -107,6 +109,7 @@ impl AnthropicProvider {
api_client,
model,
supports_streaming: true,
automatic_prompt_cache,
name: Self::metadata().name,
})
}
@@ -120,6 +123,7 @@ impl AnthropicProvider {
.get_secret(&config.api_key_env)
.map_err(|_| anyhow::anyhow!("Missing API key: {}", config.api_key_env))?;
let automatic_prompt_cache = supports_automatic_prompt_cache_for_host(&config.base_url);
let auth = resolve_anthropic_auth(&config.base_url, api_key);
let api_client = ApiClient::new(config.base_url, auth)?
@@ -129,10 +133,36 @@ impl AnthropicProvider {
api_client,
model,
supports_streaming: config.supports_streaming.unwrap_or(true),
automatic_prompt_cache,
name: config.name.clone(),
})
}
fn strip_cache_control_markers(value: &mut Value) {
match value {
Value::Object(map) => {
map.remove("cache_control");
for nested in map.values_mut() {
Self::strip_cache_control_markers(nested);
}
}
Value::Array(items) => {
for item in items {
Self::strip_cache_control_markers(item);
}
}
_ => {}
}
}
fn normalize_payload_for_runtime(&self, payload: &mut Value) {
if self.automatic_prompt_cache {
return;
}
Self::strip_cache_control_markers(payload);
}
fn get_conditional_headers(&self) -> Vec<(&str, &str)> {
let mut headers = Vec::new();
@@ -246,7 +276,8 @@ impl Provider for AnthropicProvider {
messages: &[Message],
tools: &[Tool],
) -> Result<(Message, ProviderUsage), ProviderError> {
let payload = create_request(model_config, system, messages, tools)?;
let mut payload = create_request(model_config, system, messages, tools)?;
self.normalize_payload_for_runtime(&mut payload);
let response = self
.with_retry(|| async { self.post(&payload).await })
@@ -301,6 +332,7 @@ impl Provider for AnthropicProvider {
tools: &[Tool],
) -> Result<MessageStream, ProviderError> {
let mut payload = create_request(&self.model, system, messages, tools)?;
self.normalize_payload_for_runtime(&mut payload);
payload
.as_object_mut()
.unwrap()
@@ -339,10 +371,26 @@ impl Provider for AnthropicProvider {
}
}
fn supports_automatic_prompt_cache_for_host(host: &str) -> bool {
let normalized_host = normalize_anthropic_host(host);
if normalized_host.is_empty() {
return true;
}
normalized_host.contains("api.anthropic.com") || should_use_bearer_auth_for_anthropic_host(host)
}
#[cfg(test)]
mod tests {
use super::{resolve_anthropic_auth, should_use_bearer_auth_for_anthropic_host};
use super::{
resolve_anthropic_auth, should_use_bearer_auth_for_anthropic_host,
supports_automatic_prompt_cache_for_host, AnthropicProvider,
};
use crate::conversation::message::Message;
use crate::model::ModelConfig;
use crate::providers::api_client::AuthMethod;
use crate::providers::formats::anthropic::create_request;
use rmcp::model::{CallToolRequestParam, ErrorCode, ErrorData, Tool};
#[test]
fn test_known_official_anthropic_compatible_hosts_use_bearer_auth() {
@@ -376,4 +424,86 @@ mod tests {
_ => panic!("expected x-api-key auth"),
}
}
#[test]
fn test_official_or_known_compatible_hosts_keep_automatic_prompt_cache() {
assert!(supports_automatic_prompt_cache_for_host(
"https://api.anthropic.com"
));
assert!(supports_automatic_prompt_cache_for_host(
"https://api.minimaxi.com/anthropic"
));
}
#[test]
fn test_unknown_compatible_host_disables_automatic_prompt_cache() {
assert!(!supports_automatic_prompt_cache_for_host(
"https://example.com/anthropic"
));
}
#[test]
fn test_strip_cache_control_markers_for_non_automatic_runtime() {
let model_config = ModelConfig::new("claude-sonnet-4-5").expect("valid anthropic model");
let messages = vec![
Message::user().with_text("请输出结构化结果"),
Message::assistant().with_tool_request(
"tool_1",
Ok(CallToolRequestParam {
name: "StructuredOutput".into(),
arguments: Some(rmcp::object!({
"answer": "draft"
})),
}),
),
Message::user().with_tool_response(
"tool_1",
Err(ErrorData::new(
ErrorCode::INVALID_PARAMS,
"Validation failed".to_string(),
None,
)),
),
];
let tools = vec![Tool::new(
"StructuredOutput".to_string(),
"Return the final JSON object".to_string(),
rmcp::object!({
"type": "object",
"properties": {
"answer": { "type": "string" }
},
"required": ["answer"]
}),
)];
let mut payload =
create_request(&model_config, "你必须输出 JSON。", &messages, &tools).expect("request");
assert_eq!(
payload["messages"][2]["content"][0]["cache_control"]["type"],
"ephemeral"
);
assert_eq!(payload["tools"][0]["cache_control"]["type"], "ephemeral");
assert_eq!(payload["system"][0]["cache_control"]["type"], "ephemeral");
AnthropicProvider::strip_cache_control_markers(&mut payload);
assert!(payload["messages"][2]["content"][0]
.get("cache_control")
.is_none());
assert!(payload["tools"][0].get("cache_control").is_none());
assert!(payload["system"][0].get("cache_control").is_none());
assert_eq!(payload["messages"][2]["content"][0]["type"], "tool_result");
assert_eq!(
payload["messages"][2]["content"][0]["tool_use_id"],
"tool_1"
);
assert_eq!(
payload["messages"][2]["content"][0]["content"],
"Error: -32602: Validation failed"
);
assert_eq!(payload["messages"][2]["content"][0]["is_error"], true);
assert_eq!(payload["messages"][1]["content"][0]["id"], "tool_1");
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 20 KiB

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#f7f9d7</color>
<color name="ic_launcher_background">#fff</color>
</resources>
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 769 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

+1 -1
View File
@@ -2,7 +2,7 @@
"$schema": "https://schema.tauri.app/config/2",
"productName": "Lime",
"version": "1.14.0",
"identifier": "com.limecloud.lime",
"identifier": "com.limecloud.lime.headless",
"build": {
"beforeDevCommand": "npm run dev:web-bridge",
"devUrl": "http://127.0.0.1:1420",