mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 02:25:55 +00:00
Assistant: switching models no longer reports "Method not found" for session/set_model (#9970) (#10022)
* claim: #9970 Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch> * Agent chat: no error when an agent does not serve session/set_model (#9970) An ACP agent can list models in the unstable `models` field of its session/new reply without serving `session/set_model`; it answers JSON-RPC -32601 and the Assistant showed that as an error each time the model was switched. Agents that offer the model as a configuration option already go through session/set_config_option. A -32601 reply to session/set_model is now logged at debug level instead of shown; every other error still shows. Fixes #9970 Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch> --------- Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>
This commit is contained in:
@@ -143,6 +143,11 @@ impl AcpBackend {
|
||||
out.push(Event::ConfigOptionFinished { id: config_id, result });
|
||||
}
|
||||
}
|
||||
// `session/set_model` is still unstable in ACP: an agent can list `models` and
|
||||
// still not serve it (#9970). It keeps its own model; that is no error to show.
|
||||
(Pending::SetModel, Err((acp::METHOD_NOT_FOUND, message))) => {
|
||||
log::debug!("agent does not serve session/set_model: {message}");
|
||||
}
|
||||
(what, Err((code, message))) => {
|
||||
let config_error = what == Pending::SetConfig;
|
||||
if what == Pending::SetConfig
|
||||
|
||||
@@ -1943,6 +1943,61 @@ done
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// An agent that lists `models` but does not serve the unstable `session/set_model` answers
|
||||
/// "method not found": the choice stays and no error shows (#9970). Other errors still show.
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn set_model_method_not_found_shows_no_error() {
|
||||
let dir = std::env::temp_dir().join(format!("sc-agent-chat-model-unserved-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let log = dir.join("received.log");
|
||||
let script = r#"
|
||||
log="$1"; n=0
|
||||
while IFS= read -r line; do
|
||||
printf '%s\n' "$line" >> "$log"
|
||||
id=$(printf '%s' "$line" | sed -n 's/.*"id":\([0-9][0-9]*\).*/\1/p')
|
||||
case "$line" in
|
||||
*'"method":"initialize"'*) printf '{"jsonrpc":"2.0","id":%s,"result":{"agentInfo":{"name":"fake","version":"1"}}}\n' "$id" ;;
|
||||
*'"method":"session/new"'*) printf '{"jsonrpc":"2.0","id":%s,"result":{"sessionId":"s1","models":{"currentModelId":"fast","availableModels":[{"modelId":"fast","name":"Fast"},{"modelId":"smart","name":"Smart"}]}}}\n' "$id" ;;
|
||||
*'"method":"session/set_model"'*)
|
||||
n=$((n+1))
|
||||
if [ "$n" = 1 ]; then printf '{"jsonrpc":"2.0","id":%s,"error":{"code":-32601,"message":"\\"Method not found\\": session/set_model"}}\n' "$id"
|
||||
else printf '{"jsonrpc":"2.0","id":%s,"error":{"code":-32001,"message":"model unavailable"}}\n' "$id"; fi ;;
|
||||
esac
|
||||
done
|
||||
"#;
|
||||
let argv = vec!["sh".to_string(), "-c".to_string(), script.to_string(), "fake-agent".to_string(), log.to_string_lossy().into_owned()];
|
||||
let start = backend::StartContext { cwd: dir.clone(), bridge: None, tools: None, wake: Box::new(|| {}) };
|
||||
let mut app = SolveApp::new(solidcraft_engine::Session::default(), crate::Services::default());
|
||||
app.agent_chat.backend = Some(Box::new(acp_client::AcpBackend::start(&argv, start).unwrap()));
|
||||
app.agent_chat.state = Some(State::Starting);
|
||||
app.agent_chat.running_id = "fake".into();
|
||||
let ctx = crate::fonts::test_context();
|
||||
let errors = |app: &SolveApp| -> Vec<String> {
|
||||
app.agent_chat.items.iter().filter_map(|i| if let Item::Notice { text, error: true } = i { Some(text.clone()) } else { None }).collect()
|
||||
};
|
||||
let t = std::time::Instant::now();
|
||||
while !(app.agent_chat.state() == State::Ready && models_shown(&app)) {
|
||||
poll(&mut app, &ctx);
|
||||
assert!(t.elapsed() < std::time::Duration::from_secs(20), "agent not ready: {}", status(&app));
|
||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
}
|
||||
set_model(&mut app, "smart");
|
||||
set_model(&mut app, "fast");
|
||||
// Replies come in order: once the second one's error shows, the first reply was handled too.
|
||||
let t = std::time::Instant::now();
|
||||
while !errors(&app).iter().any(|e| e == "model unavailable") {
|
||||
poll(&mut app, &ctx);
|
||||
assert!(t.elapsed() < std::time::Duration::from_secs(20), "no error for the second choice: {:?}", errors(&app));
|
||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||
}
|
||||
assert_eq!(errors(&app), ["model unavailable"], "method not found is no error to show");
|
||||
assert!(app.agent_chat.state().running(), "the chat goes on");
|
||||
assert_eq!(std::fs::read_to_string(&log).unwrap().matches("session/set_model").count(), 2);
|
||||
disconnect(&mut app);
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
// ---- Files attached to a message ----
|
||||
|
||||
/// A folder of files to attach: a picture and a text file.
|
||||
|
||||
Reference in New Issue
Block a user