Files
cursor-byok/server/tests/removed_tool_compat.rs
T
jiah0231 edc28de86b 修复:兼容已移除工具,避免旧会话 Resume 中断
兼容 v0.1.5-beta.1 删除 AwaitShell 后的旧会话 Resume,并将未知/已移除工具降级为模型可见失败结果,避免整个 Agent Run 被 Protocol Error 直接终止。
2026-08-28 12:12:50 +08:00

77 lines
2.2 KiB
Rust

use std::collections::{BTreeMap, HashSet};
use cursor_server::{
cursor::tools::{
runtime::{CursorToolRuntime, ExecContext},
ToolBatchState, ToolDispatcher,
},
model::ToolCall,
};
fn tool(name: &str) -> ToolCall {
let arguments = serde_json::json!({
"shell_id": "legacy-shell",
"block_until_ms": 30_000
});
ToolCall {
index: 0,
call_id: "call-1".into(),
model_call_id: "model-call-1".into(),
name: name.into(),
arguments_text: arguments.to_string(),
arguments,
}
}
async fn dispatch(
name: &str,
) -> cursor_server::Result<cursor_server::cursor::tools::DispatchedTool> {
let dispatcher = ToolDispatcher::new(CursorToolRuntime::default());
let completed = HashSet::new();
let started = HashSet::new();
let call = tool(name);
let dispatched = dispatcher
.start_batch(
&[call],
ToolBatchState {
completed: &completed,
started: &started,
response_text: "",
response_thinking: "",
},
&[],
&BTreeMap::new(),
&ExecContext::default(),
)
.await?;
Ok(dispatched.into_iter().next().expect("one dispatched tool"))
}
#[tokio::test]
async fn resumed_await_shell_becomes_a_failed_tool_result_instead_of_a_protocol_error() {
let dispatched = dispatch("AwaitShell").await.unwrap();
assert_eq!(
dispatched.messages.len(),
1,
"started card is still published"
);
let completion = dispatched.completion.expect("compatibility completion");
assert!(completion.result().is_error);
assert!(completion.result().content.contains("older version"));
}
#[tokio::test]
async fn hallucinated_unknown_tool_becomes_a_failed_tool_result_instead_of_a_protocol_error() {
let dispatched = dispatch("OldTool").await.unwrap();
assert_eq!(
dispatched.messages.len(),
1,
"started card is still published"
);
let completion = dispatched.completion.expect("compatibility completion");
assert!(completion.result().is_error);
assert!(completion.result().content.contains("not available"));
}