Skip to content

Commit 27e91d7

Browse files
authored
Merge pull request #66 from nikomatsakis/main
update to9.0
2 parents fa300e1 + 57fdb0d commit 27e91d7

File tree

22 files changed

+428
-641
lines changed

22 files changed

+428
-641
lines changed

Cargo.lock

Lines changed: 168 additions & 102 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@ members = [
1313
resolver = "2"
1414

1515
[workspace.dependencies]
16-
sacp = "3.0.0"
17-
sacp-tokio = "3.0.0"
18-
sacp-conductor = "5.0.0"
19-
sacp-rmcp = "0.9.0"
20-
sacp-tee = "0.2.0"
21-
sacp-test = "1.0.0"
22-
sacp-acp-client = "0.1.0"
23-
yopo = "2.0.0"
24-
elizacp = "4.0.0"
16+
sacp = "9.0.0"
17+
sacp-tokio = "9.0.0"
18+
sacp-conductor = "9.0.0"
19+
sacp-rmcp = "9.0.0"
20+
sacp-tee = "9.0.0"
21+
sacp-test = "9.0.0"
22+
yopo = "9.0.0"
23+
elizacp = "9.0.0"
2524
jsonrpcmsg = "0.1.2"
2625

2726
# Core async runtime
@@ -49,7 +48,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
4948
rmcp = { version = "0.9", features = ["server", "transport-io", "schemars"] }
5049

5150
# Sparkle integration
52-
sparkle = { package = "sparkle-mcp", version = "0.1.7" }
51+
sparkle = { package = "sparkle-mcp", version = "0.2.1" }
5352

5453
# CLI parsing
5554
clap = { version = "4.0", features = ["derive"] }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The response should describe that serde_json::from_value takes a serde_json::Value and deserializes it into a type T. It should mention that it returns a Result<T, Error>.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Please use the `rust_crate_query` tool from the `rust-crate-sources` MCP server to research the signature of the serde_json::from_value API and describe what inputs it accepts. Do not try to read files from disk - use the MCP tool.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
## `serde_json::from_value` Signature
2+
3+
```rust
4+
pub fn from_value<T>(value: Value) -> Result<T, Error>
5+
where
6+
T: DeserializeOwned,
7+
```
8+
9+
### Inputs
10+
11+
- **`value: Value`** - A `serde_json::Value` (the JSON value type). Takes ownership of the value.
12+
13+
### Type Parameter
14+
15+
- **`T: DeserializeOwned`** - The target type must implement `DeserializeOwned` (equivalent to `T: for<'de> Deserialize<'de>`), meaning it can deserialize without borrowing from input data.
16+
17+
### Return Value
18+
19+
- **`Result<T, Error>`** - Returns `Ok(T)` on success, or `Err(serde_json::Error)` on failure.
20+
21+
### When It Fails
22+
23+
1. Structure mismatch (e.g., `T` expects a struct but `Value` is not an object)
24+
2. `T`'s `Deserialize` implementation rejects the data (missing required fields, number overflow, etc.)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
PASS
2+
3+
The actual response correctly describes that `serde_json::from_value` takes a `serde_json::Value` and deserializes it into a type `T`, and that it returns a `Result<T, Error>`. The response actually exceeds the expected requirements by also including:
4+
- The full function signature with the trait bound
5+
- Explanation of the `DeserializeOwned` constraint
6+
- Examples of when deserialization can fail

setup/src/acp.rs

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,18 @@ use anyhow::{Context, Result, anyhow};
44
use std::path::{Path, PathBuf};
55
use std::process::Command;
66

7-
/// Install ACP binaries: sacp-conductor, elizacp, sacp-tee from crates.io,
8-
/// and symposium-acp-proxy from local repository
7+
/// Install ACP binaries from local repository
98
pub fn install_acp_binaries(repo_root: &Path, dry_run: bool) -> Result<()> {
109
println!("📦 Installing ACP binaries...");
1110

1211
// Verify we're in the symposium repository
1312
verify_symposium_repo(repo_root)?;
1413

1514
// Install from crates.io
16-
install_from_crates_io(&["sacp-conductor", "elizacp", "sacp-tee"], dry_run)?;
15+
install_from_crates_io(&["elizacp"], dry_run)?;
1716

18-
// Install symposium-acp-proxy from local repository
19-
install_symposium_acp_proxy(repo_root, dry_run)?;
17+
// Install symposium-acp-agent from local repository
18+
install_local_binaries(repo_root, dry_run)?;
2019

2120
if !dry_run {
2221
println!("✅ ACP binaries installed successfully!");
@@ -74,39 +73,44 @@ fn install_from_crates_io(crates: &[&str], dry_run: bool) -> Result<()> {
7473
Ok(())
7574
}
7675

77-
/// Install symposium-acp-proxy from local repository
78-
fn install_symposium_acp_proxy(repo_root: &Path, dry_run: bool) -> Result<()> {
79-
let symposium_acp_proxy_dir = repo_root.join("src/symposium-acp-proxy");
76+
/// Install local symposium binaries from the repository
77+
fn install_local_binaries(repo_root: &Path, dry_run: bool) -> Result<()> {
78+
for binary_name in ["symposium-acp-agent"] {
79+
let binary_dir = repo_root.join("src").join(binary_name);
8080

81-
if !symposium_acp_proxy_dir.exists() {
82-
return Err(anyhow!(
83-
"❌ symposium-acp-proxy directory not found at: {}",
84-
symposium_acp_proxy_dir.display()
85-
));
86-
}
81+
if !binary_dir.exists() {
82+
return Err(anyhow!(
83+
"❌ {} directory not found at: {}",
84+
binary_name,
85+
binary_dir.display()
86+
));
87+
}
8788

88-
println!(" Path: {}", symposium_acp_proxy_dir.display());
89+
if dry_run {
90+
println!(" Would install {} from local repository", binary_name);
91+
} else {
92+
println!(" Installing {} from local repository...", binary_name);
8993

90-
if dry_run {
91-
println!(" Would install symposium-acp-proxy from local repository");
92-
} else {
93-
println!(" Installing symposium-acp-proxy from local repository...");
94+
let output = Command::new("cargo")
95+
.args(["install", "--path", ".", "--force"])
96+
.current_dir(&binary_dir)
97+
.output()
98+
.context(format!(
99+
"Failed to execute cargo install for {}",
100+
binary_name
101+
))?;
94102

95-
let output = Command::new("cargo")
96-
.args(["install", "--path", ".", "--force"])
97-
.current_dir(&symposium_acp_proxy_dir)
98-
.output()
99-
.context("Failed to execute cargo install for symposium-acp-proxy")?;
103+
if !output.status.success() {
104+
let stderr = String::from_utf8_lossy(&output.stderr);
105+
return Err(anyhow!(
106+
"❌ Failed to install {}:\n Error: {}",
107+
binary_name,
108+
stderr.trim()
109+
));
110+
}
100111

101-
if !output.status.success() {
102-
let stderr = String::from_utf8_lossy(&output.stderr);
103-
return Err(anyhow!(
104-
"❌ Failed to install symposium-acp-proxy:\n Error: {}",
105-
stderr.trim()
106-
));
112+
println!(" ✅ {} installed", binary_name);
107113
}
108-
109-
println!(" ✅ symposium-acp-proxy installed");
110114
}
111115
Ok(())
112116
}

setup/src/main.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,8 @@ fn main() -> Result<()> {
102102
}
103103

104104
if configure_zed {
105-
let conductor_path = acp::get_binary_path("sacp-conductor")?;
106-
let symposium_acp_proxy_path = acp::get_binary_path("symposium-acp-proxy")?;
107-
zed::configure_zed(&conductor_path, &symposium_acp_proxy_path, args.dry_run)?;
105+
let symposium_acp_agent_path = acp::get_binary_path("symposium-acp-agent")?;
106+
zed::configure_zed(&symposium_acp_agent_path, args.dry_run)?;
108107
println!();
109108
}
110109

@@ -143,10 +142,8 @@ fn print_completion_message(
143142

144143
if installed_acp {
145144
println!("📦 ACP binaries installed to ~/.cargo/bin/:");
146-
println!(" • sacp-conductor");
147145
println!(" • elizacp");
148-
println!(" • sacp-tee");
149-
println!(" • symposium-acp-proxy");
146+
println!(" • symposium-acp-agent");
150147
println!();
151148
}
152149

setup/src/zed.rs

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,7 @@ fn is_command_available(cmd: &str) -> bool {
6262
}
6363

6464
/// Configure Zed with detected agents
65-
pub fn configure_zed(
66-
conductor_path: &Path,
67-
symposium_acp_path: &Path,
68-
dry_run: bool,
69-
) -> Result<()> {
65+
pub fn configure_zed(symposium_acp_agent_path: &Path, dry_run: bool) -> Result<()> {
7066
let zed_config_path = get_zed_config_path()?;
7167

7268
if !zed_config_path.exists() {
@@ -105,8 +101,7 @@ pub fn configure_zed(
105101
for agent in &agents {
106102
let config_name = agent.config_name();
107103

108-
let agent_config =
109-
create_agent_config(conductor_path, symposium_acp_path, agent.npx_package());
104+
let agent_config = create_agent_config(symposium_acp_agent_path, agent.npx_package());
110105

111106
if dry_run {
112107
println!(" Would add configuration for: {}", config_name);
@@ -137,19 +132,11 @@ pub fn configure_zed(
137132
}
138133

139134
/// Create an agent server configuration entry
140-
fn create_agent_config(
141-
conductor_path: &Path,
142-
symposium_acp_path: &Path,
143-
npx_package: &str,
144-
) -> Value {
135+
fn create_agent_config(symposium_acp_agent_path: &Path, npx_package: &str) -> Value {
145136
json!({
146-
"default_mode": "bypassPermissions",
147-
"command": conductor_path.to_string_lossy(),
148-
"args": [
149-
"agent",
150-
symposium_acp_path.to_string_lossy(),
151-
format!("npx -y '{}'", npx_package)
152-
],
137+
"type": "custom",
138+
"command": symposium_acp_agent_path.to_string_lossy(),
139+
"args": ["--", "npx", "-y", npx_package],
153140
"env": {}
154141
})
155142
}

src/symposium-benchmark/src/main.rs

Lines changed: 24 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@
55
66
use anyhow::Result;
77
use clap::Parser;
8-
use sacp::{ByteStreams, Component, DynComponent};
8+
use sacp::DynComponent;
99
use sacp_conductor::Conductor;
1010
use sacp_tokio::AcpAgent;
1111
use std::path::PathBuf;
1212
use std::str::FromStr;
13-
use tokio::io::duplex;
14-
use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
1513

1614
#[derive(Parser, Debug)]
1715
#[command(name = "symposium-benchmark")]
@@ -56,19 +54,8 @@ async fn main() -> Result<()> {
5654

5755
// Initialize tracing based on --log argument
5856
if let Some(log_targets) = &args.log {
59-
let mut filter = tracing_subscriber::EnvFilter::from_default_env();
60-
for target in log_targets.split(',') {
61-
let target = target.trim();
62-
if !target.is_empty() {
63-
// If target already has a level (contains '='), use as-is; otherwise default to debug
64-
let directive = if target.contains('=') {
65-
target.to_string()
66-
} else {
67-
format!("{}=debug", target)
68-
};
69-
filter = filter.add_directive(directive.parse().unwrap());
70-
}
71-
}
57+
let filter =
58+
tracing_subscriber::EnvFilter::try_new(log_targets).expect("invalid log filter syntax");
7259
tracing_subscriber::fmt()
7360
.with_env_filter(filter)
7461
.with_writer(std::io::stderr)
@@ -115,66 +102,37 @@ async fn run_benchmark(benchmark: &Benchmark, output_dir: &PathBuf) -> Result<()
115102
let research_prompt = benchmark.prompt;
116103
let expected_result = benchmark.expected;
117104

118-
// Create components: rust-crate-sources-proxy + Claude Code
119-
let proxy = symposium_crate_sources_proxy::CrateSourcesProxy;
120-
let claude_agent = AcpAgent::from_str("npx -y '@zed-industries/claude-code-acp'")?;
121-
122-
// Create duplex streams for editor <-> conductor communication
123-
let (editor_write, conductor_read) = duplex(8192);
124-
let (conductor_write, editor_read) = duplex(8192);
125-
126-
// Spawn conductor with proxy + agent chain (with tees for debugging)
127-
let conductor_handle = tokio::spawn(async move {
128-
Conductor::new(
129-
"benchmark-conductor".to_string(),
130-
vec![DynComponent::new(proxy), DynComponent::new(claude_agent)],
131-
Default::default(),
132-
)
133-
.trace_to_path("killme.jsons")
134-
.map_err(sacp::util::internal_error)?
135-
.run(ByteStreams::new(
136-
conductor_write.compat_write(),
137-
conductor_read.compat(),
138-
))
139-
.await
140-
});
141-
142-
// Send prompt using yopo
143-
let response = yopo::prompt(
144-
ByteStreams::new(editor_write.compat_write(), editor_read.compat()),
145-
research_prompt,
105+
// Build conductor with crate sources proxy and agent
106+
let conductor = Conductor::new(
107+
"benchmark-conductor".to_string(),
108+
vec![
109+
DynComponent::new(symposium_crate_sources_proxy::CrateSourcesProxy),
110+
DynComponent::new(AcpAgent::from_str(
111+
"npx -y '@zed-industries/claude-code-acp'",
112+
)?),
113+
],
114+
Default::default(),
146115
)
147-
.await?;
116+
.trace_to_path("killme.jsons")
117+
.map_err(sacp::util::internal_error)?;
118+
119+
// Run prompt
120+
let response = yopo::prompt(conductor, research_prompt).await?;
148121

149122
tracing::info!("Research response received: {} chars", response.len());
150123

151124
// Validate response using another Claude Code instance
152125
tracing::info!("Validating response");
153126

154-
let validator_agent = AcpAgent::from_str("npx -y '@zed-industries/claude-code-acp'")?;
155-
let (validator_write, validator_read) = duplex(8192);
156-
let (validator_out_write, validator_out_read) = duplex(8192);
157-
158-
let validator_handle = tokio::spawn(async move {
159-
validator_agent
160-
.serve(ByteStreams::new(
161-
validator_out_write.compat_write(),
162-
validator_read.compat(),
163-
))
164-
.await
165-
});
166-
167-
let validation_prompt = format!(
168-
"Compare this response to the expected result and respond with PASS or FAIL. \
127+
let validation_result = yopo::prompt(
128+
AcpAgent::from_str("npx -y '@zed-industries/claude-code-acp'")?,
129+
&format!(
130+
"Compare this response to the expected result and respond with PASS or FAIL. \
169131
If FAIL, explain what's missing.\n\n\
170132
Expected: {}\n\n\
171133
Actual response:\n{}",
172-
expected_result, response
173-
);
174-
175-
let validation_result = yopo::prompt(
176-
ByteStreams::new(validator_write.compat_write(), validator_out_read.compat()),
177-
&validation_prompt,
134+
expected_result, response
135+
),
178136
)
179137
.await?;
180138

@@ -199,9 +157,5 @@ async fn run_benchmark(benchmark: &Benchmark, output_dir: &PathBuf) -> Result<()
199157
println!("VALIDATION RESULT:\n{}", validation_result);
200158
println!("========================\n");
201159

202-
// Clean up
203-
validator_handle.await??;
204-
conductor_handle.await??;
205-
206160
Ok(())
207161
}

0 commit comments

Comments
 (0)