merge goose-acp crate into goose (#8726)

This commit is contained in:
Jack Amadeo 2026-04-21 16:26:49 -04:00 committed by GitHub
parent 05af51f18f
commit 38941b1d26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
48 changed files with 196 additions and 286 deletions

View file

@ -47,7 +47,6 @@ git commit -s # required for DCO sign-off
```
crates/
├── goose # core logic
├── goose-acp # Agent Client Protocol
├── goose-acp-macros # ACP proc macros
├── goose-cli # CLI entry
├── goose-server # backend (binary: goosed)

View file

@ -416,7 +416,7 @@ For the full ACP specification, see the [Agent Client Protocol documentation](ht
- API client example: `ui/desktop/src/api/` (generated TypeScript client)
**ACP**:
- ACP server implementation: `crates/goose-acp/src/server.rs`
- ACP server implementation: `crates/goose/src/acp/server.rs`
- CLI integration: `crates/goose-cli/src/cli.rs` (Command::Acp)
- Protocol library: `sacp` crate (Rust implementation of ACP)
- Test client example: `test_acp_client.py`

42
Cargo.lock generated
View file

@ -4358,9 +4358,12 @@ dependencies = [
"fs-err",
"fs2",
"futures",
"goose-acp-macros",
"goose-mcp",
"goose-sdk",
"goose-test-support",
"http 1.4.0",
"http-body-util",
"ignore",
"include_dir",
"indexmap 2.13.0",
@ -4419,6 +4422,7 @@ dependencies = [
"tokio-cron-scheduler",
"tokio-stream",
"tokio-util",
"tower-http",
"tracing",
"tracing-futures",
"tracing-opentelemetry",
@ -4446,43 +4450,6 @@ dependencies = [
"zip 8.4.0",
]
[[package]]
name = "goose-acp"
version = "1.31.0"
dependencies = [
"agent-client-protocol-schema",
"anyhow",
"async-stream",
"async-trait",
"axum",
"base64 0.22.1",
"fs-err",
"futures",
"goose",
"goose-acp-macros",
"goose-mcp",
"goose-sdk",
"goose-test-support",
"http-body-util",
"regex",
"rmcp",
"sacp",
"schemars 1.2.1",
"serde",
"serde_json",
"sqlx",
"strum 0.27.2",
"tempfile",
"test-case",
"tokio",
"tokio-util",
"tower-http",
"tracing",
"url",
"uuid",
"wiremock",
]
[[package]]
name = "goose-acp-macros"
version = "1.31.0"
@ -4513,7 +4480,6 @@ dependencies = [
"etcetera 0.11.0",
"futures",
"goose",
"goose-acp",
"goose-mcp",
"indicatif",
"open",

View file

@ -205,7 +205,7 @@ check-acp-schema: generate-acp-types
#!/usr/bin/env bash
set -e
echo "🔍 Checking ACP schema and generated types are up-to-date..."
if ! git diff --exit-code crates/goose-acp/acp-schema.json crates/goose-acp/acp-meta.json ui/sdk/src/generated/; then
if ! git diff --exit-code crates/goose/acp-schema.json crates/goose/acp-meta.json ui/sdk/src/generated/; then
echo ""
echo "❌ ACP generated files are out of date!"
echo ""
@ -217,8 +217,8 @@ check-acp-schema: generate-acp-types
# Generate ACP JSON schema from Rust types
generate-acp-schema:
@echo "Generating ACP schema..."
cd crates/goose-acp && cargo run --bin generate-acp-schema
@echo "ACP schema generated: crates/goose-acp/acp-schema.json, crates/goose-acp/acp-meta.json"
cd crates/goose && cargo run --bin generate-acp-schema
@echo "ACP schema generated: crates/goose/acp-schema.json, crates/goose/acp-meta.json"
# Generate ACP TypeScript types from JSON schema (requires generate-acp-schema first)
generate-acp-types: generate-acp-schema

View file

@ -1,67 +0,0 @@
[package]
name = "goose-acp"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
description.workspace = true
[[bin]]
name = "generate-acp-schema"
path = "src/bin/generate_acp_schema.rs"
[features]
default = ["code-mode", "rustls-tls"]
code-mode = ["goose/code-mode"]
local-inference = ["goose/local-inference"]
rustls-tls = ["goose/rustls-tls", "goose-mcp/rustls-tls"]
native-tls = ["goose/native-tls", "goose-mcp/native-tls"]
[lints]
workspace = true
[dependencies]
goose = { path = "../goose", default-features = false }
goose-mcp = { path = "../goose-mcp", default-features = false }
rmcp = { workspace = true }
sacp = { workspace = true, features = ["unstable"] }
agent-client-protocol-schema = { workspace = true }
async-trait = { workspace = true }
anyhow = { workspace = true }
tokio = { workspace = true }
tokio-util = { workspace = true, features = ["compat", "rt"] }
tracing = { workspace = true }
serde_json = { workspace = true }
futures = { workspace = true }
regex = { workspace = true }
fs-err = "3"
strum = { workspace = true }
url = { workspace = true }
# HTTP server dependencies
axum = { workspace = true, features = ["ws"] }
serde = { workspace = true, features = ["derive"] }
tower-http = { workspace = true, features = ["cors"] }
async-stream = { workspace = true }
http-body-util = "0.1.3"
uuid = { workspace = true, features = ["v7"] }
schemars = { workspace = true, features = ["derive"] }
goose-acp-macros = { path = "../goose-acp-macros" }
goose-sdk = { path = "../goose-sdk" }
base64 = { workspace = true }
[dev-dependencies]
async-trait = { workspace = true }
goose-test-support = { path = "../goose-test-support" }
wiremock = { workspace = true }
tempfile = { workspace = true }
test-case = { workspace = true }
axum = { workspace = true }
rmcp = { workspace = true, features = ["transport-streamable-http-server"] }
sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio-rustls", "sqlite"] }
[package.metadata.cargo-machete]
# Used to provide extras imports for sacp
ignored = ["agent-client-protocol-schema"]

View file

@ -1,9 +0,0 @@
#![recursion_limit = "256"]
mod adapters;
pub use goose_sdk::custom_requests;
mod fs;
pub mod server;
pub mod server_factory;
pub(crate) mod tools;
pub mod transport;

View file

@ -22,7 +22,6 @@ path = "src/bin/generate_manpages.rs"
[dependencies]
clap_mangen = "0.2.31"
goose = { path = "../goose", default-features = false }
goose-acp = { path = "../goose-acp", default-features = false }
goose-mcp = { path = "../goose-mcp" }
rmcp = { workspace = true }
clap = { workspace = true }
@ -71,8 +70,8 @@ winapi = { workspace = true }
[features]
default = ["code-mode", "local-inference", "aws-providers", "telemetry", "otel", "rustls-tls"]
code-mode = ["goose/code-mode", "goose-acp/code-mode"]
local-inference = ["goose/local-inference", "goose-acp/local-inference"]
code-mode = ["goose/code-mode"]
local-inference = ["goose/local-inference"]
aws-providers = ["goose/aws-providers"]
cuda = ["goose/cuda", "local-inference"]
telemetry = ["goose/telemetry"]

View file

@ -1064,8 +1064,9 @@ async fn handle_mcp_command(server: McpCommand) -> Result<()> {
}
async fn handle_serve_command(host: String, port: u16, builtins: Vec<String>) -> Result<()> {
use goose::acp::server_factory::{AcpServer, AcpServerFactoryConfig};
use goose::acp::transport::create_router;
use goose::config::paths::Paths;
use goose_acp::server_factory::{AcpServer, AcpServerFactoryConfig};
use std::net::SocketAddr;
use std::sync::Arc;
use tracing::info;
@ -1081,7 +1082,7 @@ async fn handle_serve_command(host: String, port: u16, builtins: Vec<String>) ->
data_dir: Paths::data_dir(),
config_dir: Paths::config_dir(),
}));
let router = goose_acp::transport::create_router(server);
let router = create_router(server);
let addr: SocketAddr = format!("{}:{}", host, port).parse()?;
info!("Starting ACP server on {}", addr);
@ -1766,7 +1767,7 @@ pub async fn cli() -> anyhow::Result<()> {
Some(Command::Doctor {}) => crate::commands::doctor::handle_doctor().await,
Some(Command::Info { verbose }) => handle_info(verbose),
Some(Command::Mcp { server }) => handle_mcp_command(server).await,
Some(Command::Acp { builtins }) => goose_acp::server::run(builtins).await,
Some(Command::Acp { builtins }) => goose::acp::server::run(builtins).await,
Some(Command::Serve {
host,
port,

View file

@ -82,7 +82,7 @@ serde = { workspace = true }
serde_json = { workspace = true }
serde_urlencoded = "0.7"
jsonschema = "0.30.0"
uuid = { workspace = true }
uuid = { workspace = true, features = ["v7"] }
regex = { workspace = true }
async-trait = { workspace = true }
async-stream = { workspace = true }
@ -96,7 +96,7 @@ nanoid = "0.4"
sha2 = { workspace = true }
base64 = { workspace = true }
url = { workspace = true }
axum = { workspace = true }
axum = { workspace = true, features = ["ws"] }
webbrowser = { workspace = true }
lazy_static = "1.5.0"
tracing = { workspace = true }
@ -190,6 +190,9 @@ pem = { version = "3", optional = true }
pkcs1 = { version = "0.7", default-features = false, features = ["pkcs8"], optional = true }
pkcs8 = { version = "0.10", default-features = false, features = ["alloc"], optional = true }
sec1 = { version = "0.7", default-features = false, features = ["der", "pkcs8"], optional = true }
goose-acp-macros = { version = "1.31.0", path = "../goose-acp-macros" }
tower-http = { workspace = true, features = ["cors"] }
http-body-util = "0.1.3"
[target.'cfg(target_os = "windows")'.dependencies]
@ -222,6 +225,7 @@ opentelemetry_sdk = { workspace = true, features = ["testing"] }
goose-test-support = { path = "../goose-test-support" }
bytes.workspace = true
http.workspace = true
goose-mcp = { path = "../goose-mcp" }
[[example]]
name = "agent"
@ -244,6 +248,10 @@ path = "src/bin/analyze_cli.rs"
name = "build_canonical_models"
path = "src/providers/canonical/build_canonical_models.rs"
[[bin]]
name = "generate-acp-schema"
path = "src/bin/generate_acp_schema.rs"
[package.metadata.cargo-machete]
ignored = [
@ -251,4 +259,6 @@ ignored = [
"winapi",
# Used to provide extras imports for sacp
"agent-client-protocol-schema",
# Used via http transport
"http-body-util",
]

View file

@ -1,13 +1,13 @@
use crate::tools::AcpAwareToolMeta;
use crate::acp::tools::AcpAwareToolMeta;
use crate::agents::mcp_client::{Error as McpError, McpClientTrait};
use crate::agents::platform_extensions::developer::edit::{
resolve_path, string_replace, FileEditParams, FileReadParams, FileWriteParams,
};
use crate::agents::platform_extensions::developer::shell::{ShellParams, OUTPUT_LIMIT_BYTES};
use crate::agents::platform_extensions::developer::DeveloperClient;
use agent_client_protocol_schema::TerminalId;
use async_trait::async_trait;
use fs_err as fs;
use goose::agents::mcp_client::{Error as McpError, McpClientTrait};
use goose::agents::platform_extensions::developer::edit::{
resolve_path, string_replace, FileEditParams, FileReadParams, FileWriteParams,
};
use goose::agents::platform_extensions::developer::shell::{ShellParams, OUTPUT_LIMIT_BYTES};
use goose::agents::platform_extensions::developer::DeveloperClient;
use rmcp::model::{CallToolResult, Content as RmcpContent, Tool, ToolAnnotations};
use sacp::schema::{
CreateTerminalRequest, Diff, KillTerminalRequest, ReadTextFileRequest, ReleaseTerminalRequest,
@ -93,7 +93,7 @@ fn read_tool() -> Tool {
}
impl AcpTools {
fn update_tool_call(&self, ctx: &goose::agents::ToolCallContext, fields: ToolCallUpdateFields) {
fn update_tool_call(&self, ctx: &crate::agents::ToolCallContext, fields: ToolCallUpdateFields) {
if let Some(ref req_id) = ctx.tool_call_request_id {
let _ = self
.cx
@ -125,7 +125,7 @@ impl AcpTools {
async fn acp_read(
&self,
arguments: Option<rmcp::model::JsonObject>,
ctx: &goose::agents::ToolCallContext,
ctx: &crate::agents::ToolCallContext,
) -> Result<CallToolResult, McpError> {
let params: FileReadParams = match Self::parse_args(arguments) {
Ok(p) => p,
@ -150,7 +150,7 @@ impl AcpTools {
async fn acp_write(
&self,
arguments: Option<rmcp::model::JsonObject>,
ctx: &goose::agents::ToolCallContext,
ctx: &crate::agents::ToolCallContext,
) -> Result<CallToolResult, McpError> {
let params: FileWriteParams = match Self::parse_args(arguments) {
Ok(p) => p,
@ -187,7 +187,7 @@ impl AcpTools {
async fn acp_edit(
&self,
arguments: Option<rmcp::model::JsonObject>,
ctx: &goose::agents::ToolCallContext,
ctx: &crate::agents::ToolCallContext,
) -> Result<CallToolResult, McpError> {
let params: FileEditParams = match Self::parse_args(arguments) {
Ok(p) => p,
@ -240,7 +240,7 @@ impl AcpTools {
async fn acp_shell(
&self,
arguments: Option<rmcp::model::JsonObject>,
ctx: &goose::agents::ToolCallContext,
ctx: &crate::agents::ToolCallContext,
) -> Result<CallToolResult, McpError> {
let params: ShellParams = match Self::parse_args(arguments) {
Ok(p) => p,
@ -404,7 +404,7 @@ impl McpClientTrait for AcpTools {
async fn call_tool(
&self,
ctx: &goose::agents::ToolCallContext,
ctx: &crate::agents::ToolCallContext,
name: &str,
arguments: Option<rmcp::model::JsonObject>,
cancellation_token: CancellationToken,

View file

@ -1,7 +1,14 @@
mod adapters;
mod common;
pub(crate) mod fs;
mod provider;
pub mod server;
pub mod server_factory;
pub(crate) mod tools;
pub mod transport;
pub use common::{map_permission_response, PermissionDecision};
pub use goose_sdk::custom_requests;
pub use provider::{
extension_configs_to_mcp_servers, AcpProvider, AcpProviderConfig, ACP_CURRENT_MODEL,
};

View file

@ -1,37 +1,36 @@
use crate::custom_requests::*;
use crate::fs::AcpTools;
use crate::tools::AcpAwareToolMeta;
use anyhow::Result;
use fs_err as fs;
use futures::future::BoxFuture;
use goose::acp::{PermissionDecision, ACP_CURRENT_MODEL};
use goose::agents::extension::{Envs, PLATFORM_EXTENSIONS};
use goose::agents::mcp_client::McpClientTrait;
use goose::agents::platform_extensions::developer::DeveloperClient;
use goose::agents::{Agent, AgentConfig, ExtensionConfig, GoosePlatform, SessionConfig};
use goose::builtin_extension::register_builtin_extensions;
use goose::config::base::CONFIG_YAML_NAME;
use goose::config::extensions::get_enabled_extensions_with_config;
use goose::config::paths::Paths;
use goose::config::permission::PermissionManager;
use goose::config::{Config, GooseMode};
use goose::conversation::message::{ActionRequiredData, Message, MessageContent};
use crate::acp::custom_requests::*;
use crate::acp::fs::AcpTools;
use crate::acp::tools::AcpAwareToolMeta;
use crate::acp::{PermissionDecision, ACP_CURRENT_MODEL};
use crate::agents::extension::{Envs, PLATFORM_EXTENSIONS};
use crate::agents::mcp_client::McpClientTrait;
use crate::agents::platform_extensions::developer::DeveloperClient;
use crate::agents::{Agent, AgentConfig, ExtensionConfig, GoosePlatform, SessionConfig};
use crate::config::base::CONFIG_YAML_NAME;
use crate::config::extensions::get_enabled_extensions_with_config;
use crate::config::paths::Paths;
use crate::config::permission::PermissionManager;
use crate::config::{Config, GooseMode};
use crate::conversation::message::{ActionRequiredData, Message, MessageContent};
#[cfg(feature = "local-inference")]
use goose::dictation::providers::transcribe_local;
use goose::dictation::providers::{
use crate::dictation::providers::transcribe_local;
use crate::dictation::providers::{
all_providers, is_configured, transcribe_with_provider, DictationProvider,
};
#[cfg(feature = "local-inference")]
use goose::dictation::whisper;
use goose::mcp_utils::ToolResult;
use goose::permission::permission_confirmation::PrincipalType;
use goose::permission::{Permission, PermissionConfirmation};
use goose::providers::base::Provider;
use goose::providers::inventory::{
use crate::dictation::whisper;
use crate::mcp_utils::ToolResult;
use crate::permission::permission_confirmation::PrincipalType;
use crate::permission::{Permission, PermissionConfirmation};
use crate::providers::base::Provider;
use crate::providers::inventory::{
ProviderInventoryEntry, ProviderInventoryService, RefreshSkipReason,
};
use goose::session::session_manager::SessionType;
use goose::session::{EnabledExtensionsState, Session, SessionManager};
use crate::session::session_manager::SessionType;
use crate::session::{EnabledExtensionsState, Session, SessionManager};
use anyhow::Result;
use fs_err as fs;
use futures::future::BoxFuture;
use goose_acp_macros::custom_methods;
use rmcp::model::{CallToolResult, RawContent, ResourceContents, Role};
use sacp::schema::{
@ -69,7 +68,7 @@ use url::Url;
pub type AcpProviderFactory = Arc<
dyn Fn(
String,
goose::model::ModelConfig,
crate::model::ModelConfig,
Vec<ExtensionConfig>,
) -> BoxFuture<'static, Result<Arc<dyn Provider>>>
+ Send
@ -106,7 +105,7 @@ const ELEVENLABS_TRANSCRIPTION_MODEL: &str = "scribe_v1";
struct GooseAcpSession {
agent: AgentHandle,
internal_session_id: String,
tool_requests: HashMap<String, goose::conversation::message::ToolRequest>,
tool_requests: HashMap<String, crate::conversation::message::ToolRequest>,
cancel_token: Option<CancellationToken>,
/// Working directory set while the agent was still loading.
/// Applied once the agent becomes ready.
@ -127,7 +126,7 @@ struct AgentSetupRequest {
mcp_servers: Vec<McpServer>,
/// Pre-resolved provider name + model config (from config, no network).
/// When present the spawn skips re-deriving these from config.
resolved_provider: Option<(String, goose::model::ModelConfig)>,
resolved_provider: Option<(String, crate::model::ModelConfig)>,
/// Pre-instantiated provider reused from synchronous session initialization.
prebuilt_provider: Option<Arc<dyn Provider>>,
}
@ -140,7 +139,7 @@ pub struct GooseAcpAgent {
client_terminal: OnceCell<bool>,
config_dir: std::path::PathBuf,
session_manager: Arc<SessionManager>,
thread_manager: Arc<goose::session::ThreadManager>,
thread_manager: Arc<crate::session::ThreadManager>,
permission_manager: Arc<PermissionManager>,
goose_mode: GooseMode,
disable_session_naming: bool,
@ -220,7 +219,7 @@ fn is_developer_file_tool(tool_name: &str) -> bool {
}
fn extract_locations_from_meta(
tool_response: &goose::conversation::message::ToolResponse,
tool_response: &crate::conversation::message::ToolResponse,
) -> Option<Vec<ToolCallLocation>> {
let result = tool_response.tool_result.as_ref().ok()?;
let meta = result.meta.as_ref()?;
@ -242,8 +241,8 @@ fn extract_locations_from_meta(
}
fn extract_tool_locations(
tool_request: &goose::conversation::message::ToolRequest,
tool_response: &goose::conversation::message::ToolResponse,
tool_request: &crate::conversation::message::ToolRequest,
tool_response: &crate::conversation::message::ToolResponse,
) -> Vec<ToolCallLocation> {
let mut locations = Vec::new();
@ -385,7 +384,7 @@ fn summarize_tool_call(tool_name: &str, arguments: Option<&serde_json::Value>) -
if !s.is_empty() {
let first_line = s.lines().next().unwrap_or(&s);
if first_line.len() > 60 {
return Some(format!("{}", goose::utils::safe_truncate(first_line, 57)));
return Some(format!("{}", crate::utils::safe_truncate(first_line, 57)));
}
return Some(first_line.to_string());
}
@ -458,7 +457,7 @@ fn inventory_entry_to_dto(entry: ProviderInventoryEntry) -> ProviderInventoryEnt
}
}
fn provider_config_key_to_dto(key: goose::providers::base::ConfigKey) -> ProviderConfigKey {
fn provider_config_key_to_dto(key: crate::providers::base::ConfigKey) -> ProviderConfigKey {
ProviderConfigKey {
name: key.name,
required: key.required,
@ -494,7 +493,7 @@ struct ProviderOptionEntry {
}
async fn list_provider_entries(current_provider: Option<&str>) -> Vec<ProviderOptionEntry> {
let mut providers = goose::providers::providers()
let mut providers = crate::providers::providers()
.await
.into_iter()
.map(|(metadata, _)| ProviderOptionEntry {
@ -548,7 +547,7 @@ fn session_provider_selection(session: &Session) -> &str {
async fn resolve_provider_and_model_from_config(
config: &Config,
goose_session: &Session,
) -> Result<(String, goose::model::ModelConfig), String> {
) -> Result<(String, crate::model::ModelConfig), String> {
let global_provider = config.get_goose_provider().ok();
let provider_override = goose_session
.provider_name
@ -563,17 +562,17 @@ async fn resolve_provider_and_model_from_config(
let model_config = match &goose_session.model_config {
Some(mc) => mc.clone(),
None if explicitly_switched => {
let entry = goose::providers::get_from_registry(&provider_name)
let entry = crate::providers::get_from_registry(&provider_name)
.await
.map_err(|e| e.to_string())?;
let default_model = &entry.metadata().default_model;
goose::model::ModelConfig::new(default_model)
crate::model::ModelConfig::new(default_model)
.map_err(|e| e.to_string())?
.with_canonical_limits(&provider_name)
}
None => {
let model_id = config.get_goose_model().map_err(|e| e.to_string())?;
goose::model::ModelConfig::new(&model_id)
crate::model::ModelConfig::new(&model_id)
.map_err(|e| e.to_string())?
.with_canonical_limits(&provider_name)
}
@ -586,7 +585,7 @@ async fn resolve_provider_and_model_from_config(
async fn resolve_provider_and_model(
config_dir: &std::path::Path,
goose_session: &Session,
) -> Result<(String, goose::model::ModelConfig), String> {
) -> Result<(String, crate::model::ModelConfig), String> {
let config =
Config::new(config_dir.join(CONFIG_YAML_NAME), "goose").map_err(|e| e.to_string())?;
resolve_provider_and_model_from_config(&config, goose_session).await
@ -704,7 +703,7 @@ impl GooseAcpAgent {
disable_session_naming: bool,
) -> Result<Self> {
let session_manager = Arc::new(SessionManager::new(data_dir));
let thread_manager = Arc::new(goose::session::ThreadManager::new(
let thread_manager = Arc::new(crate::session::ThreadManager::new(
session_manager.storage().clone(),
));
let permission_manager = Arc::new(PermissionManager::new(config_dir.clone()));
@ -733,7 +732,7 @@ impl GooseAcpAgent {
async fn create_provider(
&self,
provider_name: &str,
model_config: goose::model::ModelConfig,
model_config: crate::model::ModelConfig,
extensions: Vec<ExtensionConfig>,
) -> Result<Arc<dyn Provider>> {
(self.provider_factory)(provider_name.to_string(), model_config, extensions).await
@ -741,7 +740,7 @@ impl GooseAcpAgent {
async fn prepare_session_init_config(
&self,
resolved: &Result<(String, goose::model::ModelConfig), String>,
resolved: &Result<(String, crate::model::ModelConfig), String>,
mode_state: &SessionModeState,
goose_session: &Session,
) -> (
@ -1187,7 +1186,7 @@ impl GooseAcpAgent {
async fn handle_tool_request(
&self,
tool_request: &goose::conversation::message::ToolRequest,
tool_request: &crate::conversation::message::ToolRequest,
session_id: &SessionId,
session: &mut GooseAcpSession,
cx: &ConnectionTo<Client>,
@ -1235,7 +1234,7 @@ impl GooseAcpAgent {
.map(|a| {
let s = serde_json::to_string(a).unwrap_or_default();
if s.len() > 300 {
format!("{}", goose::utils::safe_truncate(&s, 300))
format!("{}", crate::utils::safe_truncate(&s, 300))
} else {
s
}
@ -1316,7 +1315,7 @@ impl GooseAcpAgent {
async fn handle_tool_response(
&self,
tool_response: &goose::conversation::message::ToolResponse,
tool_response: &crate::conversation::message::ToolResponse,
session_id: &SessionId,
session: &mut GooseAcpSession,
cx: &ConnectionTo<Client>,
@ -1539,7 +1538,7 @@ impl GooseAcpAgent {
.map(|s| s.to_string());
// Create the Thread — this IS the ACP session from the client's perspective.
let thread_metadata = goose::session::ThreadMetadata {
let thread_metadata = crate::session::ThreadMetadata {
provider_id: requested_provider.clone(),
mode: Some(self.goose_mode.to_string()),
..Default::default()
@ -1665,7 +1664,7 @@ impl GooseAcpAgent {
builder = builder.provider_name(provider);
}
if let Some(model) = model_name {
if let Ok(mc) = goose::model::ModelConfig::new(model) {
if let Ok(mc) = crate::model::ModelConfig::new(model) {
builder = builder.model_config(mc);
}
}
@ -1820,7 +1819,7 @@ impl GooseAcpAgent {
// so that handle_tool_response can extract file locations from the
// matching request. No GooseAcpSession required.
let mut replay_tool_requests =
HashMap::<String, goose::conversation::message::ToolRequest>::new();
HashMap::<String, crate::conversation::message::ToolRequest>::new();
let t_replay = std::time::Instant::now();
let mut replay_notifications: u32 = 0;
@ -2090,7 +2089,7 @@ impl GooseAcpAgent {
}
match event {
Ok(goose::agents::AgentEvent::Message(message)) => {
Ok(crate::agents::AgentEvent::Message(message)) => {
self.thread_manager
.append_message(&thread_id, Some(&internal_session_id), &message)
.await
@ -2217,7 +2216,7 @@ impl GooseAcpAgent {
let provider_name = current_provider.get_name().to_string();
let extensions =
EnabledExtensionsState::for_session(&self.session_manager, &internal_id, &config).await;
let model_config = goose::model::ModelConfig::new(model_id)
let model_config = crate::model::ModelConfig::new(model_id)
.map_err(|e| {
sacp::Error::invalid_params().data(format!("Invalid model config: {}", e))
})?
@ -2279,7 +2278,7 @@ impl GooseAcpAgent {
async fn update_thread_metadata(
&self,
thread_id: &str,
f: impl FnOnce(&mut goose::session::ThreadMetadata),
f: impl FnOnce(&mut crate::session::ThreadMetadata),
) -> Result<(), sacp::Error> {
self.thread_manager
.update_metadata(thread_id, f)
@ -2418,7 +2417,7 @@ impl GooseAcpAgent {
current_model
};
let model = model_name.unwrap_or(&default_model);
let model_config = goose::model::ModelConfig::new(model)
let model_config = crate::model::ModelConfig::new(model)
.map_err(|e| {
sacp::Error::invalid_params().data(format!("Invalid model config: {}", e))
})?
@ -2765,8 +2764,8 @@ impl GooseAcpAgent {
#[custom_method(GetExtensionsRequest)]
async fn on_get_extensions(&self) -> Result<GetExtensionsResponse, sacp::Error> {
let extensions = goose::config::extensions::get_all_extensions();
let warnings = goose::config::extensions::get_warnings();
let extensions = crate::config::extensions::get_all_extensions();
let warnings = crate::config::extensions::get_warnings();
let extensions_json = extensions
.into_iter()
.map(|e| serde_json::to_value(&e))
@ -2792,7 +2791,7 @@ impl GooseAcpAgent {
let extensions = EnabledExtensionsState::extensions_or_default(
Some(&session.extension_data),
goose::config::Config::global(),
crate::config::Config::global(),
);
let extensions_json = extensions
@ -2838,9 +2837,9 @@ impl GooseAcpAgent {
let provider_id = provider_id.clone();
tokio::spawn(async move {
let result = async {
let metadata = goose::providers::get_from_registry(&provider_id).await?;
let metadata = crate::providers::get_from_registry(&provider_id).await?;
let model_config =
goose::model::ModelConfig::new(&metadata.metadata().default_model)?
crate::model::ModelConfig::new(&metadata.metadata().default_model)?
.with_canonical_limits(&provider_id);
let provider =
provider_factory(provider_id.clone(), model_config, Vec::new()).await?;
@ -2894,7 +2893,7 @@ impl GooseAcpAgent {
})?;
let response = match config.get_param::<serde_json::Value>(&req.key) {
Ok(value) => ReadConfigResponse { value },
Err(goose::config::ConfigError::NotFound(_)) => ReadConfigResponse {
Err(crate::config::ConfigError::NotFound(_)) => ReadConfigResponse {
value: serde_json::Value::Null,
},
Err(e) => return Err(sacp::Error::internal_error().data(e.to_string())),
@ -3076,7 +3075,7 @@ impl GooseAcpAgent {
&self,
req: CreateSourceRequest,
) -> Result<CreateSourceResponse, sacp::Error> {
let source = goose::sources::create_source(
let source = crate::sources::create_source(
req.source_type,
&req.name,
&req.description,
@ -3092,7 +3091,7 @@ impl GooseAcpAgent {
&self,
req: ListSourcesRequest,
) -> Result<ListSourcesResponse, sacp::Error> {
let sources = goose::sources::list_sources(req.source_type, req.project_dir.as_deref())?;
let sources = crate::sources::list_sources(req.source_type, req.project_dir.as_deref())?;
Ok(ListSourcesResponse { sources })
}
@ -3101,7 +3100,7 @@ impl GooseAcpAgent {
&self,
req: UpdateSourceRequest,
) -> Result<UpdateSourceResponse, sacp::Error> {
let source = goose::sources::update_source(
let source = crate::sources::update_source(
req.source_type,
&req.name,
&req.description,
@ -3117,7 +3116,7 @@ impl GooseAcpAgent {
&self,
req: DeleteSourceRequest,
) -> Result<EmptyResponse, sacp::Error> {
goose::sources::delete_source(
crate::sources::delete_source(
req.source_type,
&req.name,
req.global,
@ -3131,7 +3130,7 @@ impl GooseAcpAgent {
&self,
req: ExportSourceRequest,
) -> Result<ExportSourceResponse, sacp::Error> {
let (json, filename) = goose::sources::export_source(
let (json, filename) = crate::sources::export_source(
req.source_type,
&req.name,
req.global,
@ -3146,7 +3145,7 @@ impl GooseAcpAgent {
req: ImportSourcesRequest,
) -> Result<ImportSourcesResponse, sacp::Error> {
let sources =
goose::sources::import_sources(&req.data, req.global, req.project_dir.as_deref())?;
crate::sources::import_sources(&req.data, req.global, req.project_dir.as_deref())?;
Ok(ImportSourcesResponse { sources })
}
@ -3156,7 +3155,7 @@ impl GooseAcpAgent {
req: DictationTranscribeRequest,
) -> Result<DictationTranscribeResponse, sacp::Error> {
use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
let config = goose::config::Config::global();
let config = crate::config::Config::global();
#[cfg(not(feature = "local-inference"))]
if req.provider == "local" {
@ -3245,7 +3244,7 @@ impl GooseAcpAgent {
&self,
_req: DictationConfigRequest,
) -> Result<DictationConfigResponse, sacp::Error> {
let config = goose::config::Config::global();
let config = crate::config::Config::global();
let mut providers = std::collections::HashMap::new();
for def in all_providers() {
@ -3294,7 +3293,7 @@ impl GooseAcpAgent {
) -> Result<DictationModelsListResponse, sacp::Error> {
#[cfg(feature = "local-inference")]
{
use goose::download_manager::{get_download_manager, DownloadStatus};
use crate::download_manager::{get_download_manager, DownloadStatus};
let manager = get_download_manager();
let models = whisper::available_models()
@ -3326,7 +3325,7 @@ impl GooseAcpAgent {
) -> Result<EmptyResponse, sacp::Error> {
#[cfg(feature = "local-inference")]
{
use goose::download_manager::get_download_manager;
use crate::download_manager::get_download_manager;
let model = whisper::get_model(&_req.model_id)
.ok_or_else(|| sacp::Error::invalid_params().data("Unknown model id"))?;
@ -3339,7 +3338,7 @@ impl GooseAcpAgent {
model.url.to_string(),
model.local_path(),
Some(Box::new(move || {
let config = goose::config::Config::global();
let config = crate::config::Config::global();
// Only auto-select this model if the user has no model
// currently selected. This prevents silently switching
// the active model mid-session when a user downloads an
@ -3381,7 +3380,7 @@ impl GooseAcpAgent {
) -> Result<DictationModelDownloadProgressResponse, sacp::Error> {
#[cfg(feature = "local-inference")]
{
use goose::download_manager::get_download_manager;
use crate::download_manager::get_download_manager;
let manager = get_download_manager();
let progress =
@ -3412,7 +3411,7 @@ impl GooseAcpAgent {
) -> Result<EmptyResponse, sacp::Error> {
#[cfg(feature = "local-inference")]
{
use goose::download_manager::get_download_manager;
use crate::download_manager::get_download_manager;
let manager = get_download_manager();
manager
@ -3485,7 +3484,7 @@ impl GooseAcpAgent {
}
};
goose::config::Config::global()
crate::config::Config::global()
.set_param(key, req.model_id)
.map_err(|e| sacp::Error::internal_error().data(e.to_string()))?;
@ -3875,18 +3874,18 @@ where
}
pub async fn run(builtins: Vec<String>) -> Result<()> {
register_builtin_extensions(goose_mcp::BUILTIN_EXTENSIONS.clone());
info!("listening on stdio");
let outgoing = tokio::io::stdout().compat_write();
let incoming = tokio::io::stdin().compat();
let server =
crate::server_factory::AcpServer::new(crate::server_factory::AcpServerFactoryConfig {
let server = crate::acp::server_factory::AcpServer::new(
crate::acp::server_factory::AcpServerFactoryConfig {
builtins,
data_dir: Paths::data_dir(),
config_dir: Paths::config_dir(),
});
},
);
let agent = server.create_agent().await?;
serve(agent, incoming, outgoing).await
}
@ -3894,7 +3893,7 @@ pub async fn run(builtins: Vec<String>) -> Result<()> {
#[cfg(test)]
mod tests {
use super::*;
use goose::conversation::message::{ToolRequest, ToolResponse};
use crate::conversation::message::{ToolRequest, ToolResponse};
use rmcp::model::{CallToolRequestParams, Content as RmcpContent};
use sacp::schema::{
EnvVariable, HttpHeader, McpServer, McpServerHttp, McpServerSse, McpServerStdio,
@ -4109,14 +4108,14 @@ print(\"hello, world\")
description: "Mock".to_string(),
default_model: "unused".to_string(),
configured: true,
provider_type: goose::providers::base::ProviderType::Builtin,
provider_type: crate::providers::base::ProviderType::Builtin,
config_keys: vec![],
setup_steps: vec![],
supports_refresh: true,
refreshing: false,
models: models
.into_iter()
.map(|id| goose::providers::inventory::InventoryModel {
.map(|id| crate::providers::inventory::InventoryModel {
name: id.clone(),
id,
family: None,
@ -4287,7 +4286,7 @@ print(\"hello, world\")
session_type: SessionType::Acp,
created_at: Default::default(),
updated_at: Default::default(),
extension_data: goose::session::ExtensionData::default(),
extension_data: crate::session::ExtensionData::default(),
total_tokens,
input_tokens,
output_tokens,

View file

@ -1,9 +1,8 @@
use crate::acp::server::{AcpProviderFactory, GooseAcpAgent};
use anyhow::Result;
use std::sync::Arc;
use tracing::info;
use crate::server::{AcpProviderFactory, GooseAcpAgent};
pub struct AcpServerFactoryConfig {
pub builtins: Vec<String>,
pub data_dir: std::path::PathBuf,
@ -23,18 +22,18 @@ impl AcpServer {
let config_path = self
.config
.config_dir
.join(goose::config::base::CONFIG_YAML_NAME);
let config = goose::config::Config::new(&config_path, "goose")?;
.join(crate::config::base::CONFIG_YAML_NAME);
let config = crate::config::Config::new(&config_path, "goose")?;
let goose_mode = config
.get_goose_mode()
.unwrap_or(goose::config::GooseMode::Auto);
.unwrap_or(crate::config::GooseMode::Auto);
let disable_session_naming = config.get_goose_disable_session_naming().unwrap_or(false);
let provider_factory: AcpProviderFactory =
Arc::new(move |provider_name, model_config, extensions| {
Box::pin(async move {
goose::providers::create(&provider_name, model_config, extensions).await
crate::providers::create(&provider_name, model_config, extensions).await
})
});

View file

@ -13,8 +13,8 @@ use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
use tracing::{error, info};
use super::*;
use crate::adapters::{ReceiverToAsyncRead, SenderToAsyncWrite};
use crate::server_factory::AcpServer;
use crate::acp::adapters::{ReceiverToAsyncRead, SenderToAsyncWrite};
use crate::acp::server_factory::AcpServer;
pub(crate) struct HttpState {
server: Arc<AcpServer>,
@ -43,7 +43,8 @@ impl HttpState {
let read_stream = ReceiverToAsyncRead::new(to_agent_rx);
let write_stream = SenderToAsyncWrite::new(from_agent_tx);
let fut = crate::server::serve(agent, read_stream.compat(), write_stream.compat_write());
let fut =
crate::acp::server::serve(agent, read_stream.compat(), write_stream.compat_write());
let handle = tokio::spawn(async move {
if let Err(e) = fut.await {
error!("ACP session error: {}", e);

View file

@ -18,7 +18,7 @@ use serde_json::Value;
use tokio::sync::{mpsc, Mutex};
use tower_http::cors::{Any, CorsLayer};
use crate::server_factory::AcpServer;
use crate::acp::server_factory::AcpServer;
pub(crate) const HEADER_SESSION_ID: &str = "Acp-Session-Id";
pub(crate) const EVENT_STREAM_MIME_TYPE: &str = "text/event-stream";

View file

@ -11,8 +11,8 @@ use tokio_util::compat::{TokioAsyncReadCompatExt, TokioAsyncWriteCompatExt};
use tracing::{debug, error, info, warn};
use super::{TransportSession, HEADER_SESSION_ID};
use crate::adapters::{ReceiverToAsyncRead, SenderToAsyncWrite};
use crate::server_factory::AcpServer;
use crate::acp::adapters::{ReceiverToAsyncRead, SenderToAsyncWrite};
use crate::acp::server_factory::AcpServer;
pub(crate) struct WsState {
server: Arc<AcpServer>,
@ -38,7 +38,8 @@ impl WsState {
let read_stream = ReceiverToAsyncRead::new(to_agent_rx);
let write_stream = SenderToAsyncWrite::new(from_agent_tx);
let fut = crate::server::serve(agent, read_stream.compat(), write_stream.compat_write());
let fut =
crate::acp::server::serve(agent, read_stream.compat(), write_stream.compat_write());
let handle = tokio::spawn(async move {
if let Err(e) = fut.await {
error!("ACP WebSocket session error: {}", e);

View file

@ -1,4 +1,4 @@
use goose_acp::server::GooseAcpAgent;
use goose::acp::server::GooseAcpAgent;
use schemars::SchemaGenerator;
use serde_json::{json, Map, Value};
use std::collections::{BTreeSet, HashMap};

View file

@ -5,6 +5,7 @@ compile_error!("At least one of `rustls-tls` or `native-tls` features must be en
compile_error!("Features `rustls-tls` and `native-tls` are mutually exclusive");
pub mod acp;
pub use goose_sdk::custom_requests;
pub mod action_required_manager;
pub mod agents;
pub mod builtin_extension;

View file

@ -2,16 +2,16 @@
#![recursion_limit = "256"]
#![allow(unused_attributes)]
#[path = "../fixtures/mod.rs"]
#[path = "../acp_fixtures/mod.rs"]
pub mod fixtures;
use fixtures::{
assert_notifications, Connection, FsFixture, Notification, OpenAiFixture, PermissionDecision,
Session, SessionData, TerminalCall, TerminalFixture, TestConnectionConfig,
};
use fs_err as fs;
use goose::acp::server::AcpProviderFactory;
use goose::config::base::CONFIG_YAML_NAME;
use goose::config::GooseMode;
use goose_acp::server::AcpProviderFactory;
use goose_test_support::{McpFixture, FAKE_CODE, TEST_IMAGE_B64, TEST_MODEL};
use sacp::schema::{
ListSessionsResponse, McpServer, McpServerHttp, ModelId, SessionInfo, SessionModeId,
@ -32,7 +32,7 @@ async fn new_basic_session<C: Connection>(config: TestConnectionConfig) -> Basic
let openai = OpenAiFixture::new(
vec![(
r#"</info-msg>\nwhat is 1+1""#.into(),
include_str!("../test_data/openai_basic.txt"),
include_str!("../acp_test_data/openai_basic.txt"),
)],
expected_session_id.clone(),
)
@ -147,11 +147,11 @@ pub async fn run_config_mcp<C: Connection>() {
vec![
(
prompt.to_string(),
include_str!("../test_data/openai_tool_call.txt"),
include_str!("../acp_test_data/openai_tool_call.txt"),
),
(
format!(r#""content":"{FAKE_CODE}""#),
include_str!("../test_data/openai_tool_result.txt"),
include_str!("../acp_test_data/openai_tool_result.txt"),
),
],
expected_session_id.clone(),
@ -198,11 +198,11 @@ pub async fn run_fs_read_text_file_true<C: Connection>() {
vec![
(
prompt.to_string(),
include_str!("../test_data/openai_fs_read_tool_call.txt"),
include_str!("../acp_test_data/openai_fs_read_tool_call.txt"),
),
(
r#""content":"test-read-content-12345""#.into(),
include_str!("../test_data/openai_fs_read_tool_result.txt"),
include_str!("../acp_test_data/openai_fs_read_tool_result.txt"),
),
],
expected_session_id.clone(),
@ -247,11 +247,11 @@ pub async fn run_fs_write_text_file_false<C: Connection>() {
vec![
(
prompt.to_string(),
include_str!("../test_data/openai_fs_write_tool_call.txt"),
include_str!("../acp_test_data/openai_fs_write_tool_call.txt"),
),
(
r#"Created /tmp/test_acp_write.txt"#.into(),
include_str!("../test_data/openai_fs_write_tool_result.txt"),
include_str!("../acp_test_data/openai_fs_write_tool_result.txt"),
),
],
expected_session_id.clone(),
@ -295,11 +295,11 @@ pub async fn run_fs_write_text_file_true<C: Connection>() {
vec![
(
prompt.to_string(),
include_str!("../test_data/openai_fs_write_tool_call.txt"),
include_str!("../acp_test_data/openai_fs_write_tool_call.txt"),
),
(
r#"Created /tmp/test_acp_write.txt"#.into(),
include_str!("../test_data/openai_fs_write_tool_result.txt"),
include_str!("../acp_test_data/openai_fs_write_tool_result.txt"),
),
],
expected_session_id.clone(),
@ -366,11 +366,11 @@ pub async fn run_load_mode<C: Connection>() {
vec![
(
prompt.to_string(),
include_str!("../test_data/openai_tool_call.txt"),
include_str!("../acp_test_data/openai_tool_call.txt"),
),
(
format!(r#""content":"{FAKE_CODE}""#),
include_str!("../test_data/openai_tool_result.txt"),
include_str!("../acp_test_data/openai_tool_result.txt"),
),
],
expected_session_id.clone(),
@ -426,7 +426,7 @@ pub async fn run_load_model<C: Connection>() {
let openai = OpenAiFixture::new(
vec![(
r#""model":"o4-mini""#.into(),
include_str!("../test_data/openai_basic.txt"),
include_str!("../acp_test_data/openai_basic.txt"),
)],
expected_session_id.clone(),
)
@ -460,19 +460,19 @@ pub async fn run_load_session_mcp<C: Connection>() {
vec![
(
prompt.to_string(),
include_str!("../test_data/openai_tool_call.txt"),
include_str!("../acp_test_data/openai_tool_call.txt"),
),
(
format!(r#""content":"{FAKE_CODE}""#),
include_str!("../test_data/openai_tool_result.txt"),
include_str!("../acp_test_data/openai_tool_result.txt"),
),
(
prompt.to_string(),
include_str!("../test_data/openai_tool_call.txt"),
include_str!("../acp_test_data/openai_tool_call.txt"),
),
(
format!(r#""content":"{FAKE_CODE}""#),
include_str!("../test_data/openai_tool_result.txt"),
include_str!("../acp_test_data/openai_tool_result.txt"),
),
],
expected_session_id.clone(),
@ -602,11 +602,11 @@ async fn run_mode_set_impl<C: Connection>(via: SetModeVia) {
vec![
(
prompt.to_string(),
include_str!("../test_data/openai_tool_call.txt"),
include_str!("../acp_test_data/openai_tool_call.txt"),
),
(
format!(r#""content":"{FAKE_CODE}""#),
include_str!("../test_data/openai_tool_result.txt"),
include_str!("../acp_test_data/openai_tool_result.txt"),
),
],
expected_session_id.clone(),
@ -779,12 +779,12 @@ async fn run_model_set_impl<C: Connection>(via: SetModelVia) {
// Session B prompt with switched model
(
r#""model":"o4-mini""#.into(),
include_str!("../test_data/openai_basic.txt"),
include_str!("../acp_test_data/openai_basic.txt"),
),
// Session A prompt with default model
(
format!(r#""model":"{TEST_MODEL}""#),
include_str!("../test_data/openai_basic.txt"),
include_str!("../acp_test_data/openai_basic.txt"),
),
],
expected_session_id.clone(),
@ -919,11 +919,11 @@ pub async fn run_permission_persistence<C: Connection>() {
vec![
(
prompt.to_string(),
include_str!("../test_data/openai_tool_call.txt"),
include_str!("../acp_test_data/openai_tool_call.txt"),
),
(
format!(r#""content":"{FAKE_CODE}""#),
include_str!("../test_data/openai_tool_result.txt"),
include_str!("../acp_test_data/openai_tool_result.txt"),
),
],
expected_session_id.clone(),
@ -961,7 +961,7 @@ pub async fn run_prompt_basic<C: Connection>() {
let openai = OpenAiFixture::new(
vec![(
r#"</info-msg>\nwhat is 1+1""#.into(),
include_str!("../test_data/openai_basic.txt"),
include_str!("../acp_test_data/openai_basic.txt"),
)],
expected_session_id.clone(),
)
@ -989,15 +989,15 @@ pub async fn run_prompt_codemode<C: Connection>() {
vec![
(
format!(r#"</info-msg>\n{prompt}""#),
include_str!("../test_data/openai_builtin_search.txt"),
include_str!("../acp_test_data/openai_builtin_search.txt"),
),
(
r#"export async function getCode"#.into(),
include_str!("../test_data/openai_builtin_execute.txt"),
include_str!("../acp_test_data/openai_builtin_execute.txt"),
),
(
r#"Created /tmp/result.txt"#.into(),
include_str!("../test_data/openai_builtin_final.txt"),
include_str!("../acp_test_data/openai_builtin_final.txt"),
),
],
expected_session_id.clone(),
@ -1037,11 +1037,11 @@ pub async fn run_prompt_image<C: Connection>() {
(
r#"</info-msg>\nUse the get_image tool and describe what you see in its result.""#
.into(),
include_str!("../test_data/openai_image_tool_call.txt"),
include_str!("../acp_test_data/openai_image_tool_call.txt"),
),
(
r#""type":"image_url""#.into(),
include_str!("../test_data/openai_image_tool_result.txt"),
include_str!("../acp_test_data/openai_image_tool_result.txt"),
),
],
expected_session_id.clone(),
@ -1081,7 +1081,7 @@ pub async fn run_prompt_image_attachment<C: Connection>() {
let openai = OpenAiFixture::new(
vec![(
r#""type":"image_url""#.into(),
include_str!("../test_data/openai_image_attachment.txt"),
include_str!("../acp_test_data/openai_image_attachment.txt"),
)],
expected_session_id.clone(),
)
@ -1112,11 +1112,11 @@ pub async fn run_prompt_mcp<C: Connection>() {
vec![
(
r#"</info-msg>\nUse the get_code tool and output only its result.""#.into(),
include_str!("../test_data/openai_tool_call.txt"),
include_str!("../acp_test_data/openai_tool_call.txt"),
),
(
format!(r#""content":"{FAKE_CODE}""#),
include_str!("../test_data/openai_tool_result.txt"),
include_str!("../acp_test_data/openai_tool_result.txt"),
),
],
expected_session_id.clone(),
@ -1178,7 +1178,7 @@ pub async fn run_prompt_skill<C: Connection>() {
let openai = OpenAiFixture::new(
vec![(
"skill-loaded-in-acp-session".to_string(),
include_str!("../test_data/openai_basic.txt"),
include_str!("../acp_test_data/openai_basic.txt"),
)],
expected_session_id.clone(),
)
@ -1209,11 +1209,11 @@ pub async fn run_shell_terminal_false<C: Connection>() {
vec![
(
prompt.clone(),
include_str!("../test_data/openai_shell_tool_call.txt"),
include_str!("../acp_test_data/openai_shell_tool_call.txt"),
),
(
SHELL_TEST_CONTENT.into(),
include_str!("../test_data/openai_shell_tool_result.txt"),
include_str!("../acp_test_data/openai_shell_tool_result.txt"),
),
],
expected_session_id.clone(),
@ -1252,11 +1252,11 @@ pub async fn run_shell_terminal_true<C: Connection>() {
vec![
(
prompt.clone(),
include_str!("../test_data/openai_shell_tool_call.txt"),
include_str!("../acp_test_data/openai_shell_tool_call.txt"),
),
(
SHELL_TEST_CONTENT.into(),
include_str!("../test_data/openai_shell_tool_result.txt"),
include_str!("../acp_test_data/openai_shell_tool_result.txt"),
),
],
expected_session_id.clone(),

View file

@ -1,4 +1,5 @@
#[allow(dead_code)]
#[path = "acp_common_tests/mod.rs"]
mod common_tests;
use common_tests::fixtures::server::AcpServerConnection;
@ -6,10 +7,10 @@ use common_tests::fixtures::{
run_test, send_custom, Connection, PermissionDecision, Session, SessionData,
TestConnectionConfig,
};
use goose::acp::server::AcpProviderFactory;
use goose::model::ModelConfig;
use goose::providers::base::{MessageStream, Provider};
use goose::providers::errors::ProviderError;
use goose_acp::server::AcpProviderFactory;
use goose_test_support::{EnforceSessionId, IgnoreSessionId};
use std::sync::{Arc, Mutex};
@ -238,11 +239,11 @@ fn test_developer_fs_requests_use_acp_session_id() {
(
"Use the read tool to read /tmp/test_acp_read.txt and output only its contents."
.to_string(),
include_str!("test_data/openai_fs_read_tool_call.txt"),
include_str!("acp_test_data/openai_fs_read_tool_call.txt"),
),
(
r#""content":"test-read-content-12345""#.into(),
include_str!("test_data/openai_fs_read_tool_result.txt"),
include_str!("acp_test_data/openai_fs_read_tool_result.txt"),
),
],
Arc::new(IgnoreSessionId),

View file

@ -3,6 +3,7 @@
use async_trait::async_trait;
use fs_err as fs;
use goose::acp::server::{serve, AcpProviderFactory, GooseAcpAgent};
pub use goose::acp::{map_permission_response, PermissionDecision};
use goose::builtin_extension::register_builtin_extensions;
use goose::config::paths::Paths;
@ -11,7 +12,6 @@ use goose::providers::api_client::{ApiClient, AuthMethod as ApiAuthMethod};
use goose::providers::base::Provider;
use goose::providers::openai::OpenAiProvider;
use goose::session_context::SESSION_ID_HEADER;
use goose_acp::server::{serve, AcpProviderFactory, GooseAcpAgent};
use goose_test_support::{ExpectedSessionId, TEST_MODEL};
use sacp::schema::{
CreateTerminalResponse, KillTerminalResponse, ListSessionsResponse, McpServer,
@ -52,7 +52,7 @@ impl OpenAiFixture {
.respond_with(
ResponseTemplate::new(200)
.insert_header("content-type", "application/json")
.set_body_string(include_str!("../test_data/openai_models.json")),
.set_body_string(include_str!("../acp_test_data/openai_models.json")),
)
.mount(&mock_server)
.await;

View file

@ -1,6 +1,7 @@
#![recursion_limit = "256"]
#[allow(dead_code)]
#[path = "acp_common_tests/mod.rs"]
mod common_tests;
use common_tests::fixtures::provider::AcpProviderConnection;
use common_tests::fixtures::run_test;

View file

@ -1,4 +1,5 @@
#[allow(dead_code)]
#[path = "acp_common_tests/mod.rs"]
mod common_tests;
use common_tests::fixtures::run_test;
use common_tests::fixtures::server::AcpServerConnection;

View file

@ -177,7 +177,7 @@ npm install
**Option 1: Auto-launch server (recommended)**
The TUI will automatically start the goose-acp-server if you have it installed:
The TUI will automatically start the goose acp server if you have it installed:
```bash
npm start
@ -191,7 +191,7 @@ For servers that support the draft standard ACP over Streamable HTTP https://git
npm start -- --server http://HOST:PORT
# example server
cargo run -p goose-acp --bin goose-acp-server
cargo run -p goose-cli --bin goose -- serve
```
### Single Prompt Mode

View file

@ -57,7 +57,7 @@ npm link @aaif/goose-sdk
### Schema Generation
The TypeScript types are generated from Rust schemas defined in `crates/goose-acp`.
The TypeScript types are generated from Rust schemas defined in `crates/goose`.
The build process:
1. Builds the `generate-acp-schema` Rust binary

View file

@ -16,8 +16,8 @@ import * as prettier from "prettier";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const ROOT = resolve(__dirname, "../..");
const SCHEMA_PATH = resolve(ROOT, "crates/goose-acp/acp-schema.json");
const META_PATH = resolve(ROOT, "crates/goose-acp/acp-meta.json");
const SCHEMA_PATH = resolve(ROOT, "crates/goose/acp-schema.json");
const META_PATH = resolve(ROOT, "crates/goose/acp-meta.json");
const OUTPUT_DIR = resolve(__dirname, "src/generated");
// Export the main function so it can be imported by build-schema.ts