Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions rust-executor/src/api/agent_ws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,8 @@ async fn update_profile(params: Value, ctx: Arc<RequestContext>) -> Result<Value
let direct_message_language = AgentService::with_global_instance(|agent_service| {
agent_service.load_user_agent_profile(&user_email)
})
.ok()
.flatten()
// A failed read must not look like "no DM language", or the store below drops it.
.map_err(|e| WsRpcError::internal(format!("Failed to load user profile: {}", e)))?
.and_then(|profile| profile.direct_message_language);
let agent = Agent {
did: agent_data.did,
Expand Down
42 changes: 42 additions & 0 deletions rust-executor/src/api/ai_ws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ async fn get_default_model(params: Value, ctx: Arc<RequestContext>) -> Result<Va
} else {
None
};
// The default model is the one most likely to carry a key: same strip as `ai.models`.
let model = model.and_then(|model| models_for_session(vec![model], &ctx).pop());

Ok(serde_json::to_value(model)?)
}
Expand Down Expand Up @@ -599,6 +601,46 @@ mod model_key_tests {
assert_eq!(models[0].api.as_ref().unwrap().model, "gpt");
}

// Goes through the `ai.getDefaultModel` handler, which returned the stored model
// unfiltered.
#[tokio::test]
async fn user_sessions_get_the_default_model_without_its_provider_key() {
use crate::types::ModelApiInput;
Ad4mDb::init_global_instance(":memory:").unwrap();
let id = Ad4mDb::with_global_instance(|db| {
db.add_model(&ModelInput {
name: "Remote".to_string(),
api: Some(ModelApiInput {
base_url: "https://api.example.org/v1".to_string(),
api_key: "sk-provider-secret".to_string(),
model: "gpt".to_string(),
api_type: "OPEN_AI".to_string(),
max_num_ctx: None,
}),
local: None,
model_type: ModelType::Llm,
})
})
.unwrap();
Ad4mDb::with_global_instance(|db| db.set_default_model(ModelType::Llm, &id)).unwrap();
let session = |user_email: Option<&str>| {
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));
Expand Down
8 changes: 7 additions & 1 deletion rust-executor/src/mcp/tools/profiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }),
};

Expand Down