From 6251e563479d525398dd59ce5b729d7f8e14c5c9 Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Thu, 4 Jun 2026 09:58:31 -0400 Subject: [PATCH] feat(sdk): minimal uniffi setup for cross language sdk (#9593) --- Cargo.lock | 283 +++++++++++++++++- crates/goose-sdk-types/Cargo.toml | 20 ++ .../src/custom_notifications.rs | 0 .../src/custom_requests.rs | 0 crates/goose-sdk-types/src/lib.rs | 8 + crates/goose-sdk/.gitignore | 2 + crates/goose-sdk/Cargo.toml | 22 +- crates/goose-sdk/README.md | 16 + crates/goose-sdk/examples/uniffi/Ping.kt | 9 + crates/goose-sdk/examples/uniffi/ping.py | 21 ++ crates/goose-sdk/justfile | 38 +++ crates/goose-sdk/src/bin/uniffi-bindgen.rs | 3 + crates/goose-sdk/src/bindings.rs | 69 +++++ crates/goose-sdk/src/lib.rs | 23 +- crates/goose-sdk/uniffi.toml | 2 + crates/goose/Cargo.toml | 2 +- crates/goose/src/acp/mod.rs | 3 +- .../src/agents/platform_extensions/summon.rs | 2 +- crates/goose/src/checks/mod.rs | 2 +- crates/goose/src/lib.rs | 3 +- crates/goose/src/skills/client.rs | 2 +- crates/goose/src/skills/mod.rs | 2 +- .../src/slash_commands/skill_slash_command.rs | 4 +- crates/goose/src/sources.rs | 2 +- 24 files changed, 514 insertions(+), 24 deletions(-) create mode 100644 crates/goose-sdk-types/Cargo.toml rename crates/{goose-sdk => goose-sdk-types}/src/custom_notifications.rs (100%) rename crates/{goose-sdk => goose-sdk-types}/src/custom_requests.rs (100%) create mode 100644 crates/goose-sdk-types/src/lib.rs create mode 100644 crates/goose-sdk/.gitignore create mode 100644 crates/goose-sdk/README.md create mode 100644 crates/goose-sdk/examples/uniffi/Ping.kt create mode 100644 crates/goose-sdk/examples/uniffi/ping.py create mode 100644 crates/goose-sdk/justfile create mode 100644 crates/goose-sdk/src/bin/uniffi-bindgen.rs create mode 100644 crates/goose-sdk/src/bindings.rs create mode 100644 crates/goose-sdk/uniffi.toml diff --git a/Cargo.lock b/Cargo.lock index 19995515..fd7f5d23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -268,6 +268,48 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" +[[package]] +name = "askama" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac" +dependencies = [ + "askama_parser", + "basic-toml", + "memchr", + "proc-macro2", + "quote", + "rustc-hash 2.1.2", + "serde", + "serde_derive", + "syn 2.0.117", +] + +[[package]] +name = "askama_parser" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f" +dependencies = [ + "memchr", + "serde", + "serde_derive", + "winnow 0.7.15", +] + [[package]] name = "asn1-rs" version = "0.7.2" @@ -945,7 +987,7 @@ dependencies = [ "arc-swap", "bytes", "either", - "fs-err", + "fs-err 3.3.0", "http 1.4.1", "http-body 1.0.1", "hyper", @@ -1028,6 +1070,15 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +[[package]] +name = "basic-toml" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] + [[package]] name = "bat" version = "0.26.1" @@ -1831,6 +1882,29 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "castaway" version = "0.2.4" @@ -3920,6 +3994,15 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + [[package]] name = "fs-err" version = "3.3.0" @@ -4444,6 +4527,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "goblin" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "goose" version = "1.37.0" @@ -4475,12 +4569,12 @@ dependencies = [ "encoding_rs", "env-lock", "etcetera 0.11.0", - "fs-err", + "fs-err 3.3.0", "fs2", "futures", "goose-acp-macros", "goose-mcp", - "goose-sdk", + "goose-sdk-types", "goose-test-support", "http 1.4.1", "http-body-util", @@ -4671,14 +4765,25 @@ dependencies = [ [[package]] name = "goose-sdk" version = "1.37.0" +dependencies = [ + "agent-client-protocol", + "agent-client-protocol-schema", + "goose-sdk-types", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "uniffi", +] + +[[package]] +name = "goose-sdk-types" +version = "1.37.0" dependencies = [ "agent-client-protocol", "agent-client-protocol-schema", "schemars 1.2.1", "serde", "serde_json", - "tokio", - "tokio-util", ] [[package]] @@ -7692,7 +7797,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.117", @@ -8690,6 +8795,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "scrypt" version = "0.11.0" @@ -8777,6 +8902,10 @@ name = "semver" version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] [[package]] name = "seq-macro" @@ -10943,6 +11072,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.9.12+spec-1.1.0" @@ -11562,6 +11700,127 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "uniffi" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3291800a6b06569f7d3e15bdb6dc235e0f0c8bd3eb07177f430057feb076415f" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "clap", + "uniffi_bindgen", + "uniffi_core", + "uniffi_macros", + "uniffi_pipeline", +] + +[[package]] +name = "uniffi_bindgen" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a04b99fa7796eaaa7b87976a0dbdd1178dc1ee702ea00aca2642003aef9b669e" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "fs-err 2.11.0", + "glob", + "goblin", + "heck", + "indexmap 2.14.0", + "once_cell", + "serde", + "tempfile", + "textwrap", + "toml 0.5.11", + "uniffi_internal_macros", + "uniffi_meta", + "uniffi_pipeline", + "uniffi_udl", +] + +[[package]] +name = "uniffi_core" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38a9a27529ccff732f8efddb831b65b1e07f7dea3fd4cacd4a35a8c4b253b98" +dependencies = [ + "anyhow", + "bytes", + "once_cell", + "static_assertions", +] + +[[package]] +name = "uniffi_internal_macros" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09acd2ce09c777dd65ee97c251d33c8a972afc04873f1e3b21eb3492ade16933" +dependencies = [ + "anyhow", + "indexmap 2.14.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "uniffi_macros" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5596f178c4f7aafa1a501c4e0b96236a96bc2ef92bdb453d83e609dad0040152" +dependencies = [ + "camino", + "fs-err 2.11.0", + "once_cell", + "proc-macro2", + "quote", + "serde", + "syn 2.0.117", + "toml 0.5.11", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beadc1f460eb2e209263c49c4f5b19e9a02e00a3b2b393f78ad10d766346ecff" +dependencies = [ + "anyhow", + "siphasher 0.3.11", + "uniffi_internal_macros", + "uniffi_pipeline", +] + +[[package]] +name = "uniffi_pipeline" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd76b3ac8a2d964ca9fce7df21c755afb4c77b054a85ad7a029ad179cc5abb8a" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.14.0", + "tempfile", + "uniffi_internal_macros", +] + +[[package]] +name = "uniffi_udl" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319cf905911d70d5b97ce0f46f101619a22e9a189c8c46d797a9955e9233716" +dependencies = [ + "anyhow", + "textwrap", + "uniffi_meta", + "weedle2", +] + [[package]] name = "unit-prefix" version = "0.5.2" @@ -11990,6 +12249,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "weedle2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" +dependencies = [ + "nom 7.1.3", +] + [[package]] name = "weezl" version = "0.1.12" @@ -12480,6 +12748,9 @@ name = "winnow" version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] [[package]] name = "winnow" diff --git a/crates/goose-sdk-types/Cargo.toml b/crates/goose-sdk-types/Cargo.toml new file mode 100644 index 00000000..0414365d --- /dev/null +++ b/crates/goose-sdk-types/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "goose-sdk-types" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +description = "Shared types for the Goose SDK" + +[dependencies] +agent-client-protocol = { workspace = true, features = ["unstable"] } +agent-client-protocol-schema = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +schemars = { workspace = true, features = ["derive"] } + +[package.metadata.cargo-machete] +# Used to provide extras imports for agent-client-protocol +ignored = ["agent-client-protocol-schema"] diff --git a/crates/goose-sdk/src/custom_notifications.rs b/crates/goose-sdk-types/src/custom_notifications.rs similarity index 100% rename from crates/goose-sdk/src/custom_notifications.rs rename to crates/goose-sdk-types/src/custom_notifications.rs diff --git a/crates/goose-sdk/src/custom_requests.rs b/crates/goose-sdk-types/src/custom_requests.rs similarity index 100% rename from crates/goose-sdk/src/custom_requests.rs rename to crates/goose-sdk-types/src/custom_requests.rs diff --git a/crates/goose-sdk-types/src/lib.rs b/crates/goose-sdk-types/src/lib.rs new file mode 100644 index 00000000..5b502130 --- /dev/null +++ b/crates/goose-sdk-types/src/lib.rs @@ -0,0 +1,8 @@ +//! Shared types for the Goose SDK. +//! +//! These wire types are used by both the ACP client/server path and the +//! in-process uniffi bindings, keeping a single source of truth for Goose's +//! custom `_goose/*` JSON-RPC methods. + +pub mod custom_notifications; +pub mod custom_requests; diff --git a/crates/goose-sdk/.gitignore b/crates/goose-sdk/.gitignore new file mode 100644 index 00000000..4d0904c0 --- /dev/null +++ b/crates/goose-sdk/.gitignore @@ -0,0 +1,2 @@ +generated +examples/uniffi/*.jar diff --git a/crates/goose-sdk/Cargo.toml b/crates/goose-sdk/Cargo.toml index 5cdfc6bb..17a6ec4b 100644 --- a/crates/goose-sdk/Cargo.toml +++ b/crates/goose-sdk/Cargo.toml @@ -6,14 +6,28 @@ rust-version.workspace = true authors.workspace = true license.workspace = true repository.workspace = true -description = "Rust SDK for talking to Goose over the Agent Client Protocol (ACP)" +description = "Rust SDK for Goose with optional uniffi bindings for Python/Kotlin" + +[lib] +name = "goose_sdk" +crate-type = ["cdylib", "staticlib", "rlib"] + +[[bin]] +name = "goose-uniffi-bindgen" +path = "src/bin/uniffi-bindgen.rs" +required-features = ["uniffi"] + +[features] +default = [] +uniffi = ["dep:uniffi", "dep:thiserror"] [dependencies] +goose-sdk-types = { path = "../goose-sdk-types" } agent-client-protocol = { workspace = true, features = ["unstable"] } agent-client-protocol-schema = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde_json = { workspace = true } -schemars = { workspace = true, features = ["derive"] } + +uniffi = { version = "0.29", features = ["cli"], optional = true } +thiserror = { version = "2", optional = true } [dev-dependencies] tokio = { workspace = true } diff --git a/crates/goose-sdk/README.md b/crates/goose-sdk/README.md new file mode 100644 index 00000000..3dfb839e --- /dev/null +++ b/crates/goose-sdk/README.md @@ -0,0 +1,16 @@ +# goose-sdk + +The bindings layer for Goose. It houses the shared types used for both ACP and +SDK access, and exposes a cross-language version of the Goose API. + +With `--features uniffi` the crate compiles to native bindings for Python and +Kotlin (namespace `aaif_goose` / `aaif.goose`). The published surface is +currently a `ping` -> `pong` stub in `src/bindings.rs` — the scaffold for the +real implementation. + +```bash +just python # build bindings + run examples/uniffi/ping.py +just kotlin # build bindings + run examples/uniffi/Ping.kt +``` + +Both print `pong: aaif.io`. diff --git a/crates/goose-sdk/examples/uniffi/Ping.kt b/crates/goose-sdk/examples/uniffi/Ping.kt new file mode 100644 index 00000000..0f043ee0 --- /dev/null +++ b/crates/goose-sdk/examples/uniffi/Ping.kt @@ -0,0 +1,9 @@ +package aaif.example + +import aaif.goose.Client + +fun main() { + val client = Client() + val pong = client.ping("aaif.io") + println(pong.message) +} diff --git a/crates/goose-sdk/examples/uniffi/ping.py b/crates/goose-sdk/examples/uniffi/ping.py new file mode 100644 index 00000000..9503b048 --- /dev/null +++ b/crates/goose-sdk/examples/uniffi/ping.py @@ -0,0 +1,21 @@ +"""Minimal Goose SDK demo: ping the SDK and print the pong.""" + +from __future__ import annotations + +import sys +from pathlib import Path + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE.parent.parent / "generated")) + +from aaif_goose import Client # noqa: E402 + + +def main() -> None: + client = Client() + pong = client.ping("aaif.io") + print(pong.message) + + +if __name__ == "__main__": + main() diff --git a/crates/goose-sdk/justfile b/crates/goose-sdk/justfile new file mode 100644 index 00000000..4d7acf01 --- /dev/null +++ b/crates/goose-sdk/justfile @@ -0,0 +1,38 @@ +set shell := ["bash", "-cu"] +set working-directory := '../..' + +lib_ext := if os() == "macos" { "dylib" } else if os() == "windows" { "dll" } else { "so" } +lib_dir := "./target/debug" +lib_path := lib_dir / "libgoose_sdk." + lib_ext +bindgen := "./target/debug/goose-uniffi-bindgen" +config := "./crates/goose-sdk/uniffi.toml" +gen_dir := "./crates/goose-sdk/generated" +examples_dir := "./crates/goose-sdk/examples/uniffi" + +default: + @just --list --justfile {{justfile()}} + +_build: + cargo build -p goose-sdk --features uniffi -q + +_generate lang: _build + {{bindgen}} generate --library {{lib_path}} --config {{config}} --language {{lang}} --no-format --out-dir {{gen_dir}} 2>/dev/null + cp {{lib_path}} {{gen_dir}}/ + touch {{gen_dir}}/__init__.py + +python: (_generate "python") + DYLD_LIBRARY_PATH={{lib_dir}} LD_LIBRARY_PATH={{lib_dir}} \ + python3 {{examples_dir}}/ping.py + +kotlin: (_generate "kotlin") + @if [ ! -f {{examples_dir}}/jna.jar ]; then \ + curl -sSL -o {{examples_dir}}/jna.jar \ + https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.14.0/jna-5.14.0.jar; \ + fi + kotlinc -cp {{examples_dir}}/jna.jar -nowarn \ + {{gen_dir}}/aaif/goose/aaif_goose.kt \ + {{examples_dir}}/Ping.kt \ + -include-runtime -d {{examples_dir}}/ping.jar 2>/dev/null + java -Djna.library.path={{lib_dir}} \ + --enable-native-access=ALL-UNNAMED \ + -cp {{examples_dir}}/ping.jar:{{examples_dir}}/jna.jar aaif.example.PingKt diff --git a/crates/goose-sdk/src/bin/uniffi-bindgen.rs b/crates/goose-sdk/src/bin/uniffi-bindgen.rs new file mode 100644 index 00000000..f6cff6cf --- /dev/null +++ b/crates/goose-sdk/src/bin/uniffi-bindgen.rs @@ -0,0 +1,3 @@ +fn main() { + uniffi::uniffi_bindgen_main() +} diff --git a/crates/goose-sdk/src/bindings.rs b/crates/goose-sdk/src/bindings.rs new file mode 100644 index 00000000..a601a744 --- /dev/null +++ b/crates/goose-sdk/src/bindings.rs @@ -0,0 +1,69 @@ +//! In-process uniffi bindings for the Goose SDK. +//! +//! This is the published API surface exposed to Python and Kotlin. Right now it +//! is a minimal `ping` -> `pong` round-trip that proves the uniffi +//! infrastructure end to end without depending on the `goose` core crate. +//! +//! To build the real SDK, add `goose` (and whatever else you need) as +//! dependencies and replace the [`Client`] methods below with the actual +//! agent surface. + +use std::sync::Arc; + +/// Errors surfaced across the uniffi boundary. +#[derive(Debug, thiserror::Error, uniffi::Error)] +pub enum GooseError { + #[error("{0}")] + Generic(String), +} + +/// A reply to a [`Client::ping`] call. +#[derive(Debug, Clone, uniffi::Record)] +pub struct Pong { + /// Echo of the message that was pinged. + pub message: String, +} + +/// The top-level entry point for the Goose SDK. +/// +/// This is the object that consuming languages instantiate. Today it only knows +/// how to answer a ping; extend it with the real agent API. +#[derive(uniffi::Object)] +pub struct Client {} + +#[uniffi::export] +impl Client { + #[uniffi::constructor] + pub fn new() -> Arc { + Arc::new(Self {}) + } + + /// Round-trip a message through the SDK. Returns a [`Pong`] echoing the + /// supplied `message`, prefixed with `pong: `. + pub fn ping(&self, message: String) -> Result { + if message.is_empty() { + return Err(GooseError::Generic("message must not be empty".into())); + } + Ok(Pong { + message: format!("pong: {message}"), + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ping_returns_pong() { + let client = Client::new(); + let pong = client.ping("aaif.io".into()).expect("ping should succeed"); + assert_eq!(pong.message, "pong: aaif.io"); + } + + #[test] + fn empty_ping_errors() { + let client = Client::new(); + assert!(client.ping(String::new()).is_err()); + } +} diff --git a/crates/goose-sdk/src/lib.rs b/crates/goose-sdk/src/lib.rs index eb50a017..bab0fa2a 100644 --- a/crates/goose-sdk/src/lib.rs +++ b/crates/goose-sdk/src/lib.rs @@ -1,2 +1,21 @@ -pub mod custom_notifications; -pub mod custom_requests; +//! Goose SDK. +//! +//! With default features this crate re-exports the shared SDK wire types from +//! `goose-sdk-types` so you can build an Agent Client Protocol (ACP) client +//! that talks to `goose acp` over stdio. +//! +//! With `--features uniffi` the crate additionally compiles as a +//! `cdylib`/`staticlib` and exposes a small in-process API to Python and Kotlin +//! via [uniffi-rs](https://github.com/mozilla/uniffi-rs). +//! +//! The published uniffi surface is intentionally a single `ping` -> `pong` +//! round-trip. It exists as a working scaffold for adding the real Goose SDK +//! API: replace [`bindings`] with the actual implementation. + +pub use goose_sdk_types::{custom_notifications, custom_requests}; + +#[cfg(feature = "uniffi")] +uniffi::setup_scaffolding!("aaif_goose"); + +#[cfg(feature = "uniffi")] +pub mod bindings; diff --git a/crates/goose-sdk/uniffi.toml b/crates/goose-sdk/uniffi.toml new file mode 100644 index 00000000..7c78ef71 --- /dev/null +++ b/crates/goose-sdk/uniffi.toml @@ -0,0 +1,2 @@ +[bindings.kotlin] +package_name = "aaif.goose" diff --git a/crates/goose/Cargo.toml b/crates/goose/Cargo.toml index 909dcb60..90d12ae0 100644 --- a/crates/goose/Cargo.toml +++ b/crates/goose/Cargo.toml @@ -122,7 +122,7 @@ strum = { workspace = true } once_cell = { workspace = true } etcetera = { workspace = true } fs-err = { version = "3.1", default-features = false } -goose-sdk = { path = "../goose-sdk", default-features = false } +goose-sdk-types = { path = "../goose-sdk-types" } rand = { workspace = true } utoipa = { workspace = true, features = ["chrono"] } tokio-cron-scheduler = { version = "0.15", default-features = false } diff --git a/crates/goose/src/acp/mod.rs b/crates/goose/src/acp/mod.rs index 1a0396a4..5b1bf99f 100644 --- a/crates/goose/src/acp/mod.rs +++ b/crates/goose/src/acp/mod.rs @@ -10,8 +10,7 @@ pub(crate) mod tools; pub mod transport; pub use common::{map_permission_response, PermissionDecision}; -pub use goose_sdk::custom_notifications; -pub use goose_sdk::custom_requests; +pub use goose_sdk_types::{custom_notifications, custom_requests}; pub use provider::{ extension_configs_to_mcp_servers, AcpProvider, AcpProviderConfig, ACP_CURRENT_MODEL, }; diff --git a/crates/goose/src/agents/platform_extensions/summon.rs b/crates/goose/src/agents/platform_extensions/summon.rs index 2c67d38d..320d77fb 100644 --- a/crates/goose/src/agents/platform_extensions/summon.rs +++ b/crates/goose/src/agents/platform_extensions/summon.rs @@ -16,7 +16,7 @@ use crate::sources::parse_frontmatter; use crate::utils::safe_truncate; use anyhow::Result; use async_trait::async_trait; -use goose_sdk::custom_requests::{SourceEntry, SourceType}; +use goose_sdk_types::custom_requests::{SourceEntry, SourceType}; use rmcp::model::{ CallToolResult, Content, Implementation, InitializeResult, JsonObject, ListToolsResult, Meta, ServerCapabilities, ServerNotification, Tool, diff --git a/crates/goose/src/checks/mod.rs b/crates/goose/src/checks/mod.rs index 172ca72b..8f0ac458 100644 --- a/crates/goose/src/checks/mod.rs +++ b/crates/goose/src/checks/mod.rs @@ -7,7 +7,7 @@ use crate::sources::parse_frontmatter; use anyhow::{anyhow, bail, Context, Result}; -use goose_sdk::custom_requests::{SourceEntry, SourceType}; +use goose_sdk_types::custom_requests::{SourceEntry, SourceType}; use serde::Deserialize; use std::collections::{BTreeMap, HashMap}; use std::fs; diff --git a/crates/goose/src/lib.rs b/crates/goose/src/lib.rs index 6bc52a14..4b19247d 100644 --- a/crates/goose/src/lib.rs +++ b/crates/goose/src/lib.rs @@ -2,8 +2,7 @@ compile_error!("Features `rustls-tls` and `native-tls` are mutually exclusive"); pub mod acp; -pub use goose_sdk::custom_notifications; -pub use goose_sdk::custom_requests; +pub use goose_sdk_types::{custom_notifications, custom_requests}; pub mod action_required_manager; pub mod agents; pub mod builtin_extension; diff --git a/crates/goose/src/skills/client.rs b/crates/goose/src/skills/client.rs index e26f37da..d23bf5c0 100644 --- a/crates/goose/src/skills/client.rs +++ b/crates/goose/src/skills/client.rs @@ -4,7 +4,7 @@ use crate::agents::extension::PlatformExtensionContext; use crate::agents::mcp_client::{Error, McpClientTrait}; use crate::agents::ToolCallContext; use async_trait::async_trait; -use goose_sdk::custom_requests::{SourceEntry, SourceType}; +use goose_sdk_types::custom_requests::{SourceEntry, SourceType}; use rmcp::model::{ CallToolResult, Content, Implementation, InitializeResult, JsonObject, ListToolsResult, ServerCapabilities, ServerNotification, Tool, diff --git a/crates/goose/src/skills/mod.rs b/crates/goose/src/skills/mod.rs index bc73e868..1645b0d0 100644 --- a/crates/goose/src/skills/mod.rs +++ b/crates/goose/src/skills/mod.rs @@ -14,7 +14,7 @@ use crate::sources::parse_frontmatter; use agent_client_protocol::Error; use anyhow::Result; use arguments::apply_skill_arguments; -use goose_sdk::custom_requests::{SourceEntry, SourceType}; +use goose_sdk_types::custom_requests::{SourceEntry, SourceType}; use serde::Deserialize; use serde_json::Value; use std::collections::{HashMap, HashSet}; diff --git a/crates/goose/src/slash_commands/skill_slash_command.rs b/crates/goose/src/slash_commands/skill_slash_command.rs index 095cb244..f85554dc 100644 --- a/crates/goose/src/slash_commands/skill_slash_command.rs +++ b/crates/goose/src/slash_commands/skill_slash_command.rs @@ -1,6 +1,6 @@ use std::path::Path; -use goose_sdk::custom_requests::{SourceEntry, SourceType}; +use goose_sdk_types::custom_requests::{SourceEntry, SourceType}; use super::types::{SlashCommandEntry, SlashCommandSource}; use super::util::normalize_command_name; @@ -82,7 +82,7 @@ pub(super) fn commands_from_sources(sources: Vec) -> Vec