use async_trait::async_trait;
use supercode_harness::formatters::FormatterSpec;
use supercode_harness::lsp::LspServerSpec;
use supercode_harness::{
Agent, ChatMessage, ChatRequest, Config, FunctionCall, Provider, Role, ToolCall, Usage,
};
fn tool_call(id: &str, name: &str, args: serde_json::Value) -> ToolCall {
ToolCall {
id: id.to_string(),
kind: "function".to_string(),
function: FunctionCall {
name: name.to_string(),
arguments: args.to_string(),
},
}
}
fn assistant_with_call(call: ToolCall) -> ChatMessage {
ChatMessage {
role: Role::Assistant,
content: None,
content_parts: None,
tool_calls: Some(vec![call]),
tool_call_id: None,
name: None,
metadata: Default::default(),
}
}
fn tmp(tag: &str) -> std::path::PathBuf {
let dir = std::env::temp_dir().join(format!(
"supercode-lsp-fmt-seam-{tag}-{}-{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(&dir).unwrap();
dir
}
fn python() -> Option<String> {
for candidate in ["python3", "python"] {
if std::process::Command::new(candidate)
.arg("--version")
.output()
.is_ok()
{
return Some(candidate.to_string());
}
}
None
}
const STUB_SERVER_PY: &str = r#"
import sys, json
def read_message():
headers = {}
while True:
line = sys.stdin.buffer.readline()
if not line:
return None
line = line.decode("utf-8", "replace").rstrip("\r\n")
if line == "":
break
if ":" in line:
k, v = line.split(":", 1)
headers[k.strip()] = v.strip()
length = int(headers.get("Content-Length", "0"))
body = sys.stdin.buffer.read(length)
return json.loads(body.decode("utf-8"))
def write_message(obj):
body = json.dumps(obj).encode("utf-8")
sys.stdout.buffer.write(("Content-Length: %d\r\n\r\n" % len(body)).encode("utf-8"))
sys.stdout.buffer.write(body)
sys.stdout.buffer.flush()
def diagnostics_for(text):
if "TODO" in text:
return [{
"range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 4}},
"severity": 1,
"message": "uppercase TODO marker present",
}]
return []
while True:
msg = read_message()
if msg is None:
break
method = msg.get("method")
if method == "initialize":
write_message({"jsonrpc": "2.0", "id": msg["id"], "result": {"capabilities": {}}})
elif method == "initialized":
pass
elif method in ("textDocument/didOpen", "textDocument/didChange"):
params = msg["params"]
if method == "textDocument/didOpen":
uri = params["textDocument"]["uri"]
text = params["textDocument"]["text"]
else:
uri = params["textDocument"]["uri"]
text = params["contentChanges"][0]["text"]
write_message({
"jsonrpc": "2.0",
"method": "textDocument/publishDiagnostics",
"params": {"uri": uri, "diagnostics": diagnostics_for(text)},
})
elif method == "shutdown":
write_message({"jsonrpc": "2.0", "id": msg["id"], "result": None})
elif method == "exit":
break
"#;
struct ScriptedWrite {
calls: std::sync::atomic::AtomicUsize,
file_name: String,
content: String,
}
#[async_trait]
impl Provider for ScriptedWrite {
async fn complete(
&self,
req: &ChatRequest,
_on_delta: &(dyn for<'a> Fn(&'a str) + Send + Sync),
) -> supercode_harness::Result<(ChatMessage, Usage)> {
match self.calls.fetch_add(1, std::sync::atomic::Ordering::SeqCst) {
0 => Ok((
assistant_with_call(tool_call(
"call_1",
"write_file",
serde_json::json!({"path": self.file_name, "content": self.content}),
)),
Usage::default(),
)),
1 => Ok((ChatMessage::assistant("done"), Usage::default())),
n => panic!("unexpected provider call {n}: {:?}", req.messages.last()),
}
}
}
fn last_tool_result(agent: &Agent) -> String {
agent
.history()
.iter()
.rev()
.find(|m| m.role == Role::Tool)
.and_then(|m| m.content.clone())
.expect("a tool-result message must exist")
}
fn upper_formatter_spec() -> (String, FormatterSpec) {
(
"upper".to_string(),
FormatterSpec {
command: "sh".to_string(),
args: vec!["-c".to_string(), "tr 'a-z' 'A-Z'".to_string()],
extensions: vec![".rs".to_string()],
},
)
}
fn stub_lsp_spec(project: &std::path::Path) -> (String, LspServerSpec) {
let script = project.join("stub_lsp.py");
std::fs::write(&script, STUB_SERVER_PY).unwrap();
(
"stub".to_string(),
LspServerSpec {
command: python().expect("python3/python required for this test"),
args: vec![script.to_string_lossy().into_owned()],
extensions: vec![".rs".to_string()],
},
)
}
#[tokio::test]
async fn formatter_runs_before_lsp_so_diagnostics_see_the_formatted_file() {
let Some(_py) = python() else {
eprintln!("skipping: no python3/python on PATH");
return;
};
let project = tmp("order-project");
let shadow = tmp("order-shadow");
let (fmt_name, fmt_spec) = upper_formatter_spec();
let (lsp_name, lsp_spec) = stub_lsp_spec(&project);
let config = Config::builder()
.cwd(project.clone())
.checkpoint_enabled(true)
.checkpoint_dir(shadow.clone())
.formatters_enabled(true)
.formatters(vec![(fmt_name, fmt_spec)])
.formatters_diff_back(true)
.lsp_enabled(true)
.lsp_servers(vec![(lsp_name, lsp_spec)])
.lsp_timeout_secs(5)
.build();
let mut agent = Agent::with_provider(
config,
Box::new(ScriptedWrite {
calls: std::sync::atomic::AtomicUsize::new(0),
file_name: "f.rs".to_string(),
content: "// todo: fix this\nfn main() {}\n".to_string(),
}),
);
let reply = agent.send("write f.rs").await.unwrap();
assert_eq!(reply, "done");
let result = last_tool_result(&agent);
assert!(
result.contains("upper"),
"formatter name in result: {result}"
);
assert!(
result.contains("FN MAIN"),
"diff-back must show the FORMATTED content: {result}"
);
assert!(
result.contains("stub") && result.contains("uppercase TODO marker present"),
"lsp diagnostics must reflect the POST-format file: {result}"
);
let on_disk = std::fs::read_to_string(project.join("f.rs")).unwrap();
assert_eq!(on_disk, "// TODO: FIX THIS\nFN MAIN() {}\n");
let observer = agent.checkpoint_observer().expect("checkpoint is enabled");
let id = observer
.current()
.expect("a checkpoint is open for this turn");
let manifest = observer.store().manifest(&id).unwrap();
assert_eq!(manifest.files.len(), 1);
assert!(
manifest.files[0].blob.is_none(),
"the file didn't exist before this write; checkpoint must record 'did not exist', \
not the formatter's output"
);
observer.store().restore(&id, &project, &[]).unwrap();
assert!(
!project.join("f.rs").exists(),
"restore must undo the whole turn (including the formatter's rewrite), \
giving back the true pre-write state"
);
if let Some(lsp) = agent.lsp_manager() {
lsp.shutdown_all().await;
}
std::fs::remove_dir_all(&project).ok();
std::fs::remove_dir_all(&shadow).ok();
}
#[tokio::test]
async fn diff_back_false_still_composes_with_lsp_but_omits_the_formatter_annotation() {
let Some(_py) = python() else {
eprintln!("skipping: no python3/python on PATH");
return;
};
let project = tmp("diffback-off-project");
let (fmt_name, fmt_spec) = upper_formatter_spec();
let (lsp_name, lsp_spec) = stub_lsp_spec(&project);
let config = Config::builder()
.cwd(project.clone())
.formatters_enabled(true)
.formatters(vec![(fmt_name, fmt_spec)])
.formatters_diff_back(false)
.lsp_enabled(true)
.lsp_servers(vec![(lsp_name, lsp_spec)])
.lsp_timeout_secs(5)
.build();
let mut agent = Agent::with_provider(
config,
Box::new(ScriptedWrite {
calls: std::sync::atomic::AtomicUsize::new(0),
file_name: "f.rs".to_string(),
content: "// todo\n".to_string(),
}),
);
agent.send("write f.rs").await.unwrap();
let result = last_tool_result(&agent);
assert!(
!result.contains("Formatter `upper`"),
"diff_back=false must omit the formatter annotation: {result}"
);
assert!(
result.contains("uppercase TODO marker present"),
"lsp diagnostics must still fire on the (silently) reformatted file: {result}"
);
let on_disk = std::fs::read_to_string(project.join("f.rs")).unwrap();
assert_eq!(on_disk, "// TODO\n", "the file must still be reformatted");
if let Some(lsp) = agent.lsp_manager() {
lsp.shutdown_all().await;
}
std::fs::remove_dir_all(&project).ok();
}
#[tokio::test]
async fn both_off_by_default_is_a_true_noop_even_with_servers_configured() {
let project = tmp("both-off-project");
let (fmt_name, fmt_spec) = upper_formatter_spec();
let lsp_spec = (
"stub".to_string(),
LspServerSpec {
command: "does-not-exist-and-must-never-be-spawned".to_string(),
args: vec![],
extensions: vec![".rs".to_string()],
},
);
let config = Config::builder()
.cwd(project.clone())
.formatters(vec![(fmt_name, fmt_spec)]) .lsp_servers(vec![lsp_spec]) .build();
assert!(!config.formatters_enabled);
assert!(!config.lsp_enabled);
let mut agent = Agent::with_provider(
config,
Box::new(ScriptedWrite {
calls: std::sync::atomic::AtomicUsize::new(0),
file_name: "f.rs".to_string(),
content: "// todo\n".to_string(),
}),
);
agent.send("write f.rs").await.unwrap();
let result = last_tool_result(&agent);
assert_eq!(result, "Wrote 8 bytes to f.rs");
let on_disk = std::fs::read_to_string(project.join("f.rs")).unwrap();
assert_eq!(on_disk, "// todo\n", "no formatter must ever have run");
assert!(agent.lsp_manager().is_none());
std::fs::remove_dir_all(&project).ok();
}