mirror of
https://github.com/block/goose.git
synced 2026-04-26 10:40:45 +00:00
merge goose-acp crate into goose (#8726)
This commit is contained in:
parent
05af51f18f
commit
38941b1d26
48 changed files with 196 additions and 286 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
42
Cargo.lock
generated
|
|
@ -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",
|
||||
|
|
|
|||
6
Justfile
6
Justfile
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
@ -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;
|
||||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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
|
||||
})
|
||||
});
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
@ -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";
|
||||
|
|
@ -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);
|
||||
|
|
@ -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};
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
@ -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),
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue