From 9fc51c987137eb2a60812eca8427123d15ec5142 Mon Sep 17 00:00:00 2001 From: Data Date: Sat, 26 Sep 2026 22:45:09 +0200 Subject: [PATCH] fix(ai): strip the provider key from ai.getDefaultModel for user sessions ai.getDefaultModel returned db.get_model(id) as stored, and users hold AI_READ, so a user session still got the default model's provider key. It now goes through models_for_session, like ai.models. Also: - agent.updateProfile returns the error when the user's profile cannot be read, instead of treating it as "no DM language" and dropping it. - The MCP profile perspective update keeps the user's DM language instead of writing None. Implements review 5327106839 on #1167. Co-Authored-By: Claude Opus 5.5 --- rust-executor/src/api/agent_ws.rs | 4 +-- rust-executor/src/api/ai_ws.rs | 42 +++++++++++++++++++++++++ rust-executor/src/mcp/tools/profiles.rs | 8 ++++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/rust-executor/src/api/agent_ws.rs b/rust-executor/src/api/agent_ws.rs index 610ffa3913..94e03e47df 100644 --- a/rust-executor/src/api/agent_ws.rs +++ b/rust-executor/src/api/agent_ws.rs @@ -251,8 +251,8 @@ async fn update_profile(params: Value, ctx: Arc) -> Result) -> Result| { + Arc::new(RequestContext { + capabilities: Ok(vec![AI_READ_CAPABILITY.clone()]), + ..ctx(user_email) + }) + }; + let params = serde_json::json!({ "modelType": "LLM" }); + + let user = get_default_model(params.clone(), session(Some("a@example.org"))) + .await + .unwrap(); + assert_eq!(user["id"], id.as_str()); + assert_eq!(user["api"]["apiKey"], ""); + + let operator = get_default_model(params, session(None)).await.unwrap(); + assert_eq!(operator["api"]["apiKey"], "sk-provider-secret"); + } + #[test] fn operator_sessions_see_the_keys() { let models = models_for_session(vec![remote_model()], &ctx(None)); diff --git a/rust-executor/src/mcp/tools/profiles.rs b/rust-executor/src/mcp/tools/profiles.rs index 1f10406b52..9417ba7eeb 100644 --- a/rust-executor/src/mcp/tools/profiles.rs +++ b/rust-executor/src/mcp/tools/profiles.rs @@ -99,9 +99,15 @@ async fn update_agent_perspective( let agent_data = AgentService::get_user_agent_data(&user_email) .map_err(|e| format!("User agent not available: {}", e))?; + // Keep the user's DM language: this call updates only the perspective. + let direct_message_language = AgentService::with_global_instance(|agent_service| { + agent_service.load_user_agent_profile(&user_email) + }) + .map_err(|e| format!("Failed to load user profile: {}", e))? + .and_then(|profile| profile.direct_message_language); let agent = Agent { did: agent_data.did, - direct_message_language: None, + direct_message_language, perspective: Some(Perspective { links }), };