From 50ad31965403191e3b97e7037e4e8df242061f59 Mon Sep 17 00:00:00 2001 From: Dalton Cherry Date: Fri, 15 May 2026 14:30:05 -0500 Subject: [PATCH 1/2] Add Looker WASM plugin 23 tools across search, folders, Looks, dashboards, queries, SQL Runner, LookML models, connections, users, and scheduled plans. Auth uses Looker's API3 client_id/client_secret login flow with a process-scoped token cache that auto-refreshes on 401. All _run_* and _create_* tools clamp `limit` to a max of 5,000 rows (default 100) to prevent runaway responses. Includes prebuilt dist/looker.wasm (~217 KB) and an updated marketplace manifest entry. Co-Authored-By: Claude --- Cargo.lock | 124 ++++++ README.md | 2 +- dist/looker.wasm | Bin 0 -> 221638 bytes manifest.json | 22 +- plugins/looker/Cargo.toml | 12 + plugins/looker/README.md | 53 +++ plugins/looker/src/handlers.rs | 432 ++++++++++++++++++++ plugins/looker/src/lib.rs | 706 +++++++++++++++++++++++++++++++++ plugins/looker/src/tools.rs | 262 ++++++++++++ 9 files changed, 1611 insertions(+), 2 deletions(-) create mode 100644 Cargo.lock create mode 100755 dist/looker.wasm create mode 100644 plugins/looker/Cargo.toml create mode 100644 plugins/looker/README.md create mode 100644 plugins/looker/src/handlers.rs create mode 100644 plugins/looker/src/lib.rs create mode 100644 plugins/looker/src/tools.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..10950b8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,124 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "looker-wasm" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "switchboard-guest-sdk", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "switchboard-guest-sdk" +version = "0.1.0" +source = "git+https://github.com/daltoniam/switchboard.git#62423750d8f845cca1e14e840a81d0775e094c54" +dependencies = [ + "base64", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/README.md b/README.md index dda39b4..36e0b2a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A home for integrations that make more sense as standalone WASM modules than as | Plugin | Tools | Description | |--------|-------|-------------| -| _none yet_ | | | +| [looker](plugins/looker/) | 23 | Looker BI: dashboards, Looks, LookML models, inline analytics queries, SQL Runner | Prebuilt binaries live in [`dist/`](dist/) and are referenced by [`manifest.json`](manifest.json). diff --git a/dist/looker.wasm b/dist/looker.wasm new file mode 100755 index 0000000000000000000000000000000000000000..4514c391df7aa1e6b025d7a1f5dfe16967c5c41f GIT binary patch literal 221638 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 Vec { + s.split(',') + .map(|p| p.trim().to_string()) + .filter(|p| !p.is_empty()) + .collect() +} + +/// Return the inner Value on success or an `err_result` ToolResult. +macro_rules! call { + ($call:expr) => { + match $call { + Ok(v) => v, + Err(e) => return sdk::err_result(&e), + } + }; +} + +fn json_result(v: &serde_json::Value) -> sdk::ToolResult { + match serde_json::to_string(v) { + Ok(s) => sdk::raw_result(s), + Err(e) => sdk::err_result(&format!("encode response: {e}")), + } +} + +// ── Search ───────────────────────────────────────────────────────────────── + +/// Run unified search across dashboards, Looks, and folders. Looker has +/// separate `/dashboards/search`, `/looks/search`, `/folders/search` +/// endpoints (no unified `/search`). Fan out to whichever types are requested +/// and merge results. +pub fn search_content(args: HashMap) -> sdk::ToolResult { + let terms = sdk::arg_str(&args, "terms"); + if terms.is_empty() { + return sdk::err_result("terms is required"); + } + let types = sdk::arg_str(&args, "types"); + let limit = sdk::arg_int(&args, "limit").unwrap_or(25); + let offset = sdk::arg_int(&args, "offset").unwrap_or(0); + + let mut wanted = [true; 3]; // [dashboard, look, folder] + if !types.is_empty() { + wanted = [false; 3]; + for t in types.split(',') { + match t.trim().to_lowercase().as_str() { + "dashboard" => wanted[0] = true, + "look" => wanted[1] = true, + "folder" => wanted[2] = true, + _ => {} + } + } + } + + let mut out = serde_json::Map::new(); + + if wanted[0] { + let path = format!( + "/dashboards/search?title={}&limit={}&offset={}", + query_escape(&terms), + limit, + offset + ); + let v = call!(looker_get(&path)); + out.insert("dashboards".into(), v); + } + if wanted[1] { + let path = format!( + "/looks/search?title={}&limit={}&offset={}", + query_escape(&terms), + limit, + offset + ); + let v = call!(looker_get(&path)); + out.insert("looks".into(), v); + } + if wanted[2] { + // /folders/search uses `name` rather than `title`. + let path = format!( + "/folders/search?name={}&limit={}&offset={}", + query_escape(&terms), + limit, + offset + ); + let v = call!(looker_get(&path)); + out.insert("folders".into(), v); + } + + json_result(&serde_json::Value::Object(out)) +} + +// ── Folders ──────────────────────────────────────────────────────────────── + +pub fn list_folders(args: HashMap) -> sdk::ToolResult { + let fields = sdk::arg_str(&args, "fields"); + let path = if fields.is_empty() { + "/folders".to_string() + } else { + format!("/folders?fields={}", query_escape(&fields)) + }; + let v = call!(looker_get(&path)); + json_result(&v) +} + +pub fn get_folder(args: HashMap) -> sdk::ToolResult { + let id = sdk::arg_str(&args, "folder_id"); + if id.is_empty() { + return sdk::err_result("folder_id is required"); + } + let v = call!(looker_get(&format!("/folders/{}", path_escape(&id)))); + json_result(&v) +} + +// ── Looks ────────────────────────────────────────────────────────────────── + +pub fn list_looks(args: HashMap) -> sdk::ToolResult { + let limit = sdk::arg_int(&args, "limit").unwrap_or(25); + let offset = sdk::arg_int(&args, "offset").unwrap_or(0); + let fields = sdk::arg_str(&args, "fields"); + let mut path = format!("/looks?limit={limit}&offset={offset}"); + if !fields.is_empty() { + path.push_str(&format!("&fields={}", query_escape(&fields))); + } + let v = call!(looker_get(&path)); + json_result(&v) +} + +pub fn get_look(args: HashMap) -> sdk::ToolResult { + let id = sdk::arg_str(&args, "look_id"); + if id.is_empty() { + return sdk::err_result("look_id is required"); + } + let v = call!(looker_get(&format!("/looks/{}", path_escape(&id)))); + json_result(&v) +} + +pub fn run_look(args: HashMap) -> sdk::ToolResult { + let id = sdk::arg_str(&args, "look_id"); + if id.is_empty() { + return sdk::err_result("look_id is required"); + } + let raw_limit = sdk::arg_int(&args, "limit").unwrap_or(0); + let apply_fmt = sdk::arg_bool(&args, "apply_formatting").unwrap_or(false); + let apply_vis = sdk::arg_bool(&args, "apply_vis").unwrap_or(false); + let cache_arg = args.get("cache"); + + let mut q = format!("limit={}", clamp_limit(raw_limit)); + if apply_fmt { + q.push_str("&apply_formatting=true"); + } + if apply_vis { + q.push_str("&apply_vis=true"); + } + if let Some(v) = cache_arg { + let on = sdk::arg_bool(&args, "cache").unwrap_or(true); + if !on && !v.is_null() { + q.push_str("&cache=false"); + } + } + let v = call!(looker_get(&format!( + "/looks/{}/run/json?{q}", + path_escape(&id) + ))); + json_result(&v) +} + +// ── Dashboards ───────────────────────────────────────────────────────────── + +pub fn list_dashboards(args: HashMap) -> sdk::ToolResult { + let limit = sdk::arg_int(&args, "limit").unwrap_or(25); + let offset = sdk::arg_int(&args, "offset").unwrap_or(0); + let fields = sdk::arg_str(&args, "fields"); + let mut path = format!("/dashboards?limit={limit}&offset={offset}"); + if !fields.is_empty() { + path.push_str(&format!("&fields={}", query_escape(&fields))); + } + let v = call!(looker_get(&path)); + json_result(&v) +} + +pub fn get_dashboard(args: HashMap) -> sdk::ToolResult { + let id = sdk::arg_str(&args, "dashboard_id"); + if id.is_empty() { + return sdk::err_result("dashboard_id is required"); + } + let v = call!(looker_get(&format!("/dashboards/{}", path_escape(&id)))); + json_result(&v) +} + +// ── Queries ──────────────────────────────────────────────────────────────── + +/// Build the JSON body shared by `POST /queries` and `POST /queries/run/{format}`. +fn build_query_body( + args: &HashMap, + limit_override: i64, +) -> Result { + let model = sdk::arg_str(args, "model"); + let view = sdk::arg_str(args, "view"); + let fields = sdk::arg_str(args, "fields"); + if model.is_empty() || view.is_empty() || fields.is_empty() { + return Err("model, view, and fields are required".into()); + } + let mut body = serde_json::json!({ + "model": model, + "view": view, + "fields": split_csv(&fields), + }); + let obj = body.as_object_mut().unwrap(); + let sorts = sdk::arg_str(args, "sorts"); + if !sorts.is_empty() { + obj.insert("sorts".into(), serde_json::json!(split_csv(&sorts))); + } + let pivots = sdk::arg_str(args, "pivots"); + if !pivots.is_empty() { + obj.insert("pivots".into(), serde_json::json!(split_csv(&pivots))); + } + let filters = sdk::arg_str(args, "filters"); + if !filters.is_empty() { + let parsed: serde_json::Value = serde_json::from_str(&filters) + .map_err(|e| format!("filters must be a JSON object: {e}"))?; + if !parsed.is_object() { + return Err("filters must be a JSON object".into()); + } + obj.insert("filters".into(), parsed); + } + if limit_override > 0 { + obj.insert( + "limit".into(), + serde_json::json!(limit_override.to_string()), + ); + } + Ok(body) +} + +pub fn run_inline_query(args: HashMap) -> sdk::ToolResult { + let raw_limit = sdk::arg_int(&args, "limit").unwrap_or(0); + let limit = clamp_limit(raw_limit); + let body = match build_query_body(&args, limit) { + Ok(b) => b, + Err(e) => return sdk::err_result(&e), + }; + let v = call!(looker_post("/queries/run/json", &body)); + json_result(&v) +} + +pub fn create_query(args: HashMap) -> sdk::ToolResult { + let raw_limit = sdk::arg_int(&args, "limit").unwrap_or(500); + let body = match build_query_body(&args, clamp_limit(raw_limit)) { + Ok(b) => b, + Err(e) => return sdk::err_result(&e), + }; + let v = call!(looker_post("/queries", &body)); + json_result(&v) +} + +pub fn get_query(args: HashMap) -> sdk::ToolResult { + let id = sdk::arg_str(&args, "query_id"); + if id.is_empty() { + return sdk::err_result("query_id is required"); + } + let v = call!(looker_get(&format!("/queries/{}", path_escape(&id)))); + json_result(&v) +} + +pub fn run_query(args: HashMap) -> sdk::ToolResult { + let id = sdk::arg_str(&args, "query_id"); + if id.is_empty() { + return sdk::err_result("query_id is required"); + } + let raw_limit = sdk::arg_int(&args, "limit").unwrap_or(0); + let apply_fmt = sdk::arg_bool(&args, "apply_formatting").unwrap_or(false); + + let mut q = format!("limit={}", clamp_limit(raw_limit)); + if apply_fmt { + q.push_str("&apply_formatting=true"); + } + if let Some(v) = args.get("cache") { + let on = sdk::arg_bool(&args, "cache").unwrap_or(true); + if !on && !v.is_null() { + q.push_str("&cache=false"); + } + } + let v = call!(looker_get(&format!( + "/queries/{}/run/json?{q}", + path_escape(&id) + ))); + json_result(&v) +} + +// ── SQL Runner ───────────────────────────────────────────────────────────── + +/// Looker requires the two-step SQL Runner pattern: POST /sql_queries to +/// register a query, then GET /sql_queries/{slug}/run/{format} to run it. +pub fn run_sql_query(args: HashMap) -> sdk::ToolResult { + let conn = sdk::arg_str(&args, "connection_name"); + let sql = sdk::arg_str(&args, "sql"); + if conn.is_empty() || sql.is_empty() { + return sdk::err_result("connection_name and sql are required"); + } + let body = serde_json::json!({ + "connection_name": conn, + "sql": sql, + }); + let created = call!(looker_post("/sql_queries", &body)); + let slug = created + .get("slug") + .and_then(|v| v.as_str()) + .unwrap_or("") + .to_string(); + if slug.is_empty() { + return sdk::err_result("sql_query: missing slug in response"); + } + let v = call!(looker_get(&format!( + "/sql_queries/{}/run/json", + path_escape(&slug) + ))); + json_result(&v) +} + +// ── LookML Models ────────────────────────────────────────────────────────── + +pub fn list_models(_args: HashMap) -> sdk::ToolResult { + let v = call!(looker_get("/lookml_models")); + json_result(&v) +} + +pub fn get_model(args: HashMap) -> sdk::ToolResult { + let name = sdk::arg_str(&args, "model_name"); + if name.is_empty() { + return sdk::err_result("model_name is required"); + } + let v = call!(looker_get(&format!( + "/lookml_models/{}", + path_escape(&name) + ))); + json_result(&v) +} + +pub fn get_model_explore(args: HashMap) -> sdk::ToolResult { + let model = sdk::arg_str(&args, "model_name"); + let explore = sdk::arg_str(&args, "explore_name"); + if model.is_empty() || explore.is_empty() { + return sdk::err_result("model_name and explore_name are required"); + } + let v = call!(looker_get(&format!( + "/lookml_models/{}/explores/{}", + path_escape(&model), + path_escape(&explore) + ))); + json_result(&v) +} + +// ── Connections ──────────────────────────────────────────────────────────── + +pub fn list_connections(_args: HashMap) -> sdk::ToolResult { + let v = call!(looker_get("/connections")); + json_result(&v) +} + +pub fn get_connection(args: HashMap) -> sdk::ToolResult { + let name = sdk::arg_str(&args, "connection_name"); + if name.is_empty() { + return sdk::err_result("connection_name is required"); + } + let v = call!(looker_get(&format!("/connections/{}", path_escape(&name)))); + json_result(&v) +} + +// ── Users ────────────────────────────────────────────────────────────────── + +pub fn get_me(_args: HashMap) -> sdk::ToolResult { + let v = call!(looker_get("/user")); + json_result(&v) +} + +pub fn list_users(args: HashMap) -> sdk::ToolResult { + let limit = sdk::arg_int(&args, "limit").unwrap_or(25); + let offset = sdk::arg_int(&args, "offset").unwrap_or(0); + let v = call!(looker_get(&format!("/users?limit={limit}&offset={offset}"))); + json_result(&v) +} + +pub fn get_user(args: HashMap) -> sdk::ToolResult { + let id = sdk::arg_str(&args, "user_id"); + if id.is_empty() { + return sdk::err_result("user_id is required"); + } + let v = call!(looker_get(&format!("/users/{}", path_escape(&id)))); + json_result(&v) +} + +// ── Scheduled plans ──────────────────────────────────────────────────────── + +pub fn list_scheduled_plans(args: HashMap) -> sdk::ToolResult { + let user_id = sdk::arg_str(&args, "user_id"); + let all = sdk::arg_bool(&args, "all").unwrap_or(false); + let mut parts: Vec = Vec::new(); + if !user_id.is_empty() { + parts.push(format!("user_id={}", query_escape(&user_id))); + } + if all { + parts.push("all_users=true".into()); + } + let path = if parts.is_empty() { + "/scheduled_plans".to_string() + } else { + format!("/scheduled_plans?{}", parts.join("&")) + }; + let v = call!(looker_get(&path)); + json_result(&v) +} + +pub fn get_scheduled_plan(args: HashMap) -> sdk::ToolResult { + let id = sdk::arg_str(&args, "scheduled_plan_id"); + if id.is_empty() { + return sdk::err_result("scheduled_plan_id is required"); + } + let v = call!(looker_get(&format!( + "/scheduled_plans/{}", + path_escape(&id) + ))); + json_result(&v) +} + +// Suppress unused-import warning when DEFAULT_ROW_LIMIT is only conceptually used. +#[allow(dead_code)] +const _: i64 = DEFAULT_ROW_LIMIT; diff --git a/plugins/looker/src/lib.rs b/plugins/looker/src/lib.rs new file mode 100644 index 0000000..e39830d --- /dev/null +++ b/plugins/looker/src/lib.rs @@ -0,0 +1,706 @@ +mod handlers; +mod tools; + +use serde::Deserialize; +use std::collections::HashMap; +use std::sync::Mutex; +use std::time::{SystemTime, UNIX_EPOCH}; +use switchboard_guest_sdk as sdk; + +// ── Constants ────────────────────────────────────────────────────────────── + +/// Hard cap on rows returned from any inline/saved query. Prevents +/// accidentally pulling millions of rows into context. +pub(crate) const MAX_ROW_LIMIT: i64 = 5000; + +/// Default row cap when a caller omits `limit`. +pub(crate) const DEFAULT_ROW_LIMIT: i64 = 100; + +/// Buffer subtracted from the Looker `access_token` expiry before treating it +/// as expired. Avoids racing on the wire-side TTL. +const TOKEN_SAFETY_WINDOW_SECS: u64 = 30; + +/// Fallback expiry if the Looker login response omits `expires_in`. +const DEFAULT_TOKEN_TTL_SECS: u64 = 15 * 60; + +// ── Config + token cache ─────────────────────────────────────────────────── + +struct Config { + base_url: String, // includes /api/4.0 + client_id: String, + client_secret: String, +} + +struct TokenCache { + token: String, + /// Unix seconds when the token expires. + expires_at: u64, +} + +static CONFIG: Mutex> = Mutex::new(None); +static TOKEN: Mutex> = Mutex::new(None); + +fn with_config(f: F) -> Result +where + F: FnOnce(&Config) -> R, +{ + let guard = CONFIG.lock().map_err(|e| e.to_string())?; + match guard.as_ref() { + Some(c) => Ok(f(c)), + None => Err("looker: not configured".into()), + } +} + +fn now_secs() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0) +} + +// ── Required ABI exports ─────────────────────────────────────────────────── + +#[no_mangle] +pub extern "C" fn name() -> u64 { + sdk::leaked_string("looker") +} + +#[no_mangle] +pub extern "C" fn metadata() -> u64 { + sdk::leaked_metadata(&sdk::PluginMetadata { + name: "looker".into(), + version: "0.1.0".into(), + abi_version: 1, + description: "Looker BI integration — dashboards, Looks, LookML models, inline analytics queries, SQL Runner.".into(), + author: "daltoniam".into(), + homepage: "https://github.com/daltoniam/switchboard_plugins".into(), + license: "MIT".into(), + capabilities: vec!["http".into()], + credential_keys: vec!["base_url".into(), "client_id".into(), "client_secret".into()], + plain_text_keys: vec!["base_url".into(), "client_id".into()], + optional_keys: vec![], + placeholders: HashMap::from([ + ("base_url".into(), "https://your-instance.cloud.looker.com:19999".into()), + ("client_id".into(), "Looker API3 client_id".into()), + ("client_secret".into(), "Looker API3 client_secret".into()), + ]), + }) +} + +#[no_mangle] +pub extern "C" fn tools() -> u64 { + let defs = tools::tool_definitions(); + let data = serde_json::to_vec(&defs).unwrap_or_default(); + sdk::leaked_result(&data) +} + +#[no_mangle] +pub extern "C" fn configure(ptr_size: u64) -> u64 { + let input = sdk::read_input(ptr_size); + let creds: HashMap = match serde_json::from_slice(&input) { + Ok(c) => c, + Err(e) => return sdk::leaked_string(&format!("looker: invalid credentials JSON: {e}")), + }; + + let client_id = creds.get("client_id").cloned().unwrap_or_default(); + let client_secret = creds.get("client_secret").cloned().unwrap_or_default(); + let raw = creds + .get("base_url") + .map(|s| s.trim_end_matches('/').to_string()) + .unwrap_or_default(); + + if client_id.is_empty() { + return sdk::leaked_string("looker: client_id is required"); + } + if client_secret.is_empty() { + return sdk::leaked_string("looker: client_secret is required"); + } + if raw.is_empty() { + return sdk::leaked_string( + "looker: base_url is required (e.g., https://your-instance.cloud.looker.com:19999)", + ); + } + + // Normalize: ensure /api/4.0 suffix. If the user pasted only the host, + // append it; if they pasted the API root, leave it alone. + let base_url = if raw.contains("/api/") { + raw + } else { + format!("{raw}/api/4.0") + }; + + *CONFIG.lock().unwrap() = Some(Config { + base_url, + client_id, + client_secret, + }); + // Reset any cached token from a previous configuration. + *TOKEN.lock().unwrap() = None; + 0 +} + +#[no_mangle] +pub extern "C" fn execute(ptr_size: u64) -> u64 { + let input = sdk::read_input(ptr_size); + let req: sdk::ExecuteRequest = match serde_json::from_slice(&input) { + Ok(r) => r, + Err(e) => { + let r = sdk::err_result(&format!("invalid request: {e}")); + let data = serde_json::to_vec(&r).unwrap_or_default(); + return sdk::leaked_result(&data); + } + }; + + let result = dispatch(&req.tool_name, req.args); + let data = serde_json::to_vec(&result).unwrap_or_default(); + sdk::leaked_result(&data) +} + +#[no_mangle] +pub extern "C" fn healthy() -> i32 { + match looker_get("/user") { + Ok(_) => 1, + Err(_) => 0, + } +} + +#[no_mangle] +pub extern "C" fn compact_specs() -> u64 { + sdk::leaked_compact_specs(&compact_spec_map()) +} + +// ── Dispatch ─────────────────────────────────────────────────────────────── + +type HandlerFn = fn(HashMap) -> sdk::ToolResult; + +fn dispatch(tool_name: &str, args: HashMap) -> sdk::ToolResult { + let handler: Option = match tool_name { + // Search + "looker_search_content" => Some(handlers::search_content), + // Folders + "looker_list_folders" => Some(handlers::list_folders), + "looker_get_folder" => Some(handlers::get_folder), + // Looks + "looker_list_looks" => Some(handlers::list_looks), + "looker_get_look" => Some(handlers::get_look), + "looker_run_look" => Some(handlers::run_look), + // Dashboards + "looker_list_dashboards" => Some(handlers::list_dashboards), + "looker_get_dashboard" => Some(handlers::get_dashboard), + // Queries + "looker_run_inline_query" => Some(handlers::run_inline_query), + "looker_run_query" => Some(handlers::run_query), + "looker_get_query" => Some(handlers::get_query), + "looker_create_query" => Some(handlers::create_query), + // SQL Runner + "looker_run_sql_query" => Some(handlers::run_sql_query), + // Models + "looker_list_models" => Some(handlers::list_models), + "looker_get_model" => Some(handlers::get_model), + "looker_get_model_explore" => Some(handlers::get_model_explore), + // Connections + "looker_list_connections" => Some(handlers::list_connections), + "looker_get_connection" => Some(handlers::get_connection), + // Users + "looker_get_me" => Some(handlers::get_me), + "looker_list_users" => Some(handlers::list_users), + "looker_get_user" => Some(handlers::get_user), + // Schedules + "looker_list_scheduled_plans" => Some(handlers::list_scheduled_plans), + "looker_get_scheduled_plan" => Some(handlers::get_scheduled_plan), + _ => None, + }; + + match handler { + Some(f) => f(args), + None => sdk::err_result(&format!("unknown tool: {tool_name}")), + } +} + +// ── Auth ─────────────────────────────────────────────────────────────────── + +#[derive(Deserialize)] +struct LoginResponse { + access_token: String, + #[serde(default)] + expires_in: u64, +} + +/// Return a cached, unexpired access token, fetching/refreshing as needed. +/// Process-scoped (module-instance-scoped) cache. +fn ensure_token() -> Result { + { + let guard = TOKEN.lock().map_err(|e| e.to_string())?; + if let Some(tc) = guard.as_ref() { + if !tc.token.is_empty() + && now_secs().saturating_add(TOKEN_SAFETY_WINDOW_SECS) < tc.expires_at + { + return Ok(tc.token.clone()); + } + } + } + + let (base_url, client_id, client_secret) = with_config(|c| { + ( + c.base_url.clone(), + c.client_id.clone(), + c.client_secret.clone(), + ) + })?; + + let body = format!( + "client_id={}&client_secret={}", + form_encode(&client_id), + form_encode(&client_secret), + ); + + let mut headers = HashMap::new(); + headers.insert( + "Content-Type".into(), + "application/x-www-form-urlencoded".into(), + ); + + let req = sdk::HttpRequest { + method: "POST".into(), + url: format!("{base_url}/login"), + headers, + body, + ..Default::default() + }; + + let resp = sdk::host_http_request(&req)?; + if resp.status >= 400 { + return Err(format!( + "looker login failed ({}): {}", + resp.status, resp.body + )); + } + + let lr: LoginResponse = serde_json::from_str(&resp.body) + .map_err(|e| format!("looker login: decode response: {e}"))?; + if lr.access_token.is_empty() { + return Err("looker login: empty access_token".into()); + } + + let ttl = if lr.expires_in == 0 { + DEFAULT_TOKEN_TTL_SECS + } else { + lr.expires_in + }; + let expires_at = now_secs().saturating_add(ttl); + + *TOKEN.lock().map_err(|e| e.to_string())? = Some(TokenCache { + token: lr.access_token.clone(), + expires_at, + }); + Ok(lr.access_token) +} + +/// Form-encode a single value. Looker `client_id`/`client_secret` are typically +/// hex tokens, but we still escape to be safe. +fn form_encode(s: &str) -> String { + let mut out = String::with_capacity(s.len()); + for b in s.as_bytes() { + let c = *b; + let safe = c.is_ascii_alphanumeric() || matches!(c, b'-' | b'_' | b'.' | b'~'); + if safe { + out.push(c as char); + } else { + out.push_str(&format!("%{c:02X}")); + } + } + out +} + +// ── HTTP helpers ─────────────────────────────────────────────────────────── + +/// Send a request to the Looker API and return the raw response body as a +/// `serde_json::Value`. On 401 transparently refresh the token and retry once. +fn do_request( + method: &str, + path: &str, + body: Option<&serde_json::Value>, +) -> Result { + let (raw, status) = send(method, path, body)?; + let (raw, status) = if status == 401 { + *TOKEN.lock().map_err(|e| e.to_string())? = None; + send(method, path, body)? + } else { + (raw, status) + }; + if status >= 400 { + return Err(format!("looker API error ({status}): {raw}")); + } + if status == 204 || raw.is_empty() { + return Ok(serde_json::json!({"status": "success"})); + } + serde_json::from_str(&raw).map_err(|e| format!("looker: decode response: {e}")) +} + +fn send( + method: &str, + path: &str, + body: Option<&serde_json::Value>, +) -> Result<(String, i32), String> { + let token = ensure_token()?; + let base_url = with_config(|c| c.base_url.clone())?; + + let mut headers = HashMap::new(); + headers.insert("Authorization".into(), format!("token {token}")); + headers.insert("Accept".into(), "application/json".into()); + let body_str = if let Some(b) = body { + headers.insert("Content-Type".into(), "application/json".into()); + serde_json::to_string(b).map_err(|e| e.to_string())? + } else { + String::new() + }; + + let req = sdk::HttpRequest { + method: method.into(), + url: format!("{base_url}{path}"), + headers, + body: body_str, + ..Default::default() + }; + + let resp = sdk::host_http_request(&req)?; + Ok((resp.body, resp.status)) +} + +pub(crate) fn looker_get(path: &str) -> Result { + do_request("GET", path, None) +} + +pub(crate) fn looker_post( + path: &str, + body: &serde_json::Value, +) -> Result { + do_request("POST", path, Some(body)) +} + +// ── Helpers ──────────────────────────────────────────────────────────────── + +/// Apply the default and hard-cap row limits to a user-supplied value. +pub(crate) fn clamp_limit(n: i64) -> i64 { + if n <= 0 { + DEFAULT_ROW_LIMIT + } else if n > MAX_ROW_LIMIT { + MAX_ROW_LIMIT + } else { + n + } +} + +/// Percent-encode a path segment. Identical safe-char set to Go's +/// `url.PathEscape`: encodes everything except RFC 3986 unreserved chars. +pub(crate) fn path_escape(s: &str) -> String { + let mut out = String::with_capacity(s.len()); + for b in s.as_bytes() { + let c = *b; + let safe = c.is_ascii_alphanumeric() || matches!(c, b'-' | b'_' | b'.' | b'~'); + if safe { + out.push(c as char); + } else { + out.push_str(&format!("%{c:02X}")); + } + } + out +} + +/// Encode a query-string value (spaces -> %20, no `+` substitution). +pub(crate) fn query_escape(s: &str) -> String { + let mut out = String::with_capacity(s.len()); + for b in s.as_bytes() { + let c = *b; + let safe = c.is_ascii_alphanumeric() || matches!(c, b'-' | b'_' | b'.' | b'~'); + if safe { + out.push(c as char); + } else { + out.push_str(&format!("%{c:02X}")); + } + } + out +} + +// ── Compact specs ────────────────────────────────────────────────────────── + +fn compact_spec_map() -> HashMap> { + // Compaction specs cover read endpoints only. Tools that return user + // analytics data (run_inline_query, run_query, run_look, run_sql_query) + // intentionally have NO specs — their payload IS the answer and must pass + // through untouched. Mutations (create_query) also pass through unmodified. + let mut s: HashMap> = HashMap::new(); + + // Search — wrapper {dashboards:[],looks:[],folders:[]}. + s.insert( + "looker_search_content".into(), + vec![ + "dashboards[].id".into(), + "dashboards[].title".into(), + "dashboards[].description".into(), + "dashboards[].folder.name".into(), + "dashboards[].user_id".into(), + "dashboards[].view_count".into(), + "dashboards[].updated_at".into(), + "looks[].id".into(), + "looks[].title".into(), + "looks[].description".into(), + "looks[].folder.name".into(), + "looks[].user_id".into(), + "looks[].query_id".into(), + "looks[].view_count".into(), + "looks[].updated_at".into(), + "folders[].id".into(), + "folders[].name".into(), + "folders[].parent_id".into(), + ], + ); + + // Folders + s.insert( + "looker_list_folders".into(), + vec![ + "id".into(), + "name".into(), + "parent_id".into(), + "child_count".into(), + ], + ); + s.insert( + "looker_get_folder".into(), + vec![ + "id".into(), + "name".into(), + "parent_id".into(), + "child_count".into(), + "dashboards".into(), + "looks".into(), + ], + ); + + // Looks + s.insert( + "looker_list_looks".into(), + vec![ + "id".into(), + "title".into(), + "description".into(), + "folder.name".into(), + "user_id".into(), + "query_id".into(), + "view_count".into(), + "favorite_count".into(), + "public".into(), + "updated_at".into(), + ], + ); + s.insert( + "looker_get_look".into(), + vec![ + "id".into(), + "title".into(), + "description".into(), + "folder.name".into(), + "folder.id".into(), + "user_id".into(), + "query_id".into(), + "view_count".into(), + "favorite_count".into(), + "public".into(), + "updated_at".into(), + "query.model".into(), + "query.view".into(), + "query.fields".into(), + ], + ); + + // Dashboards + s.insert( + "looker_list_dashboards".into(), + vec![ + "id".into(), + "title".into(), + "description".into(), + "folder.name".into(), + "user_id".into(), + "view_count".into(), + "favorite_count".into(), + "updated_at".into(), + ], + ); + s.insert( + "looker_get_dashboard".into(), + vec![ + "id".into(), + "title".into(), + "description".into(), + "folder.name".into(), + "folder.id".into(), + "user_id".into(), + "view_count".into(), + "favorite_count".into(), + "updated_at".into(), + "dashboard_elements[].id".into(), + "dashboard_elements[].title".into(), + "dashboard_elements[].type".into(), + "dashboard_elements[].query_id".into(), + "dashboard_filters".into(), + ], + ); + + // Queries + s.insert( + "looker_get_query".into(), + vec![ + "id".into(), + "model".into(), + "view".into(), + "fields".into(), + "filters".into(), + "sorts".into(), + "limit".into(), + "pivots".into(), + "share_url".into(), + ], + ); + + // Models / explores + s.insert( + "looker_list_models".into(), + vec![ + "name".into(), + "label".into(), + "project_name".into(), + "explores[].name".into(), + "explores[].label".into(), + "explores[].hidden".into(), + ], + ); + s.insert( + "looker_get_model".into(), + vec![ + "name".into(), + "label".into(), + "project_name".into(), + "allowed_db_connection_names".into(), + "explores[].name".into(), + "explores[].label".into(), + "explores[].description".into(), + "explores[].hidden".into(), + ], + ); + s.insert( + "looker_get_model_explore".into(), + vec![ + "name".into(), + "label".into(), + "description".into(), + "model_name".into(), + "view_name".into(), + "connection_name".into(), + "fields".into(), + "joins[].name".into(), + "joins[].type".into(), + "joins[].relationship".into(), + ], + ); + + // Connections + s.insert( + "looker_list_connections".into(), + vec![ + "name".into(), + "dialect_name".into(), + "host".into(), + "port".into(), + "database".into(), + "schema".into(), + ], + ); + s.insert( + "looker_get_connection".into(), + vec![ + "name".into(), + "dialect_name".into(), + "host".into(), + "port".into(), + "database".into(), + "schema".into(), + "username".into(), + "max_connections".into(), + "ssl".into(), + ], + ); + + // Users + s.insert( + "looker_get_me".into(), + vec![ + "id".into(), + "email".into(), + "display_name".into(), + "first_name".into(), + "last_name".into(), + "role_ids".into(), + "is_disabled".into(), + ], + ); + s.insert( + "looker_list_users".into(), + vec![ + "id".into(), + "email".into(), + "display_name".into(), + "role_ids".into(), + "is_disabled".into(), + ], + ); + s.insert( + "looker_get_user".into(), + vec![ + "id".into(), + "email".into(), + "display_name".into(), + "first_name".into(), + "last_name".into(), + "role_ids".into(), + "group_ids".into(), + "is_disabled".into(), + "verified_looker_employee".into(), + ], + ); + + // Scheduled plans + s.insert( + "looker_list_scheduled_plans".into(), + vec![ + "id".into(), + "name".into(), + "user_id".into(), + "look_id".into(), + "dashboard_id".into(), + "enabled".into(), + "crontab".into(), + "timezone".into(), + "next_run_at".into(), + ], + ); + s.insert( + "looker_get_scheduled_plan".into(), + vec![ + "id".into(), + "name".into(), + "user_id".into(), + "look_id".into(), + "dashboard_id".into(), + "enabled".into(), + "crontab".into(), + "timezone".into(), + "next_run_at".into(), + "scheduled_plan_destination".into(), + "filters_string".into(), + ], + ); + + s +} diff --git a/plugins/looker/src/tools.rs b/plugins/looker/src/tools.rs new file mode 100644 index 0000000..e264263 --- /dev/null +++ b/plugins/looker/src/tools.rs @@ -0,0 +1,262 @@ +use std::collections::HashMap; +use switchboard_guest_sdk::ToolDefinition; + +macro_rules! tool { + ($name:expr, $desc:expr, $params:expr) => { + ToolDefinition { + name: $name.into(), + description: $desc.into(), + parameters: $params, + required: vec![], + } + }; + ($name:expr, $desc:expr, $params:expr, $req:expr) => { + ToolDefinition { + name: $name.into(), + description: $desc.into(), + parameters: $params, + required: $req.iter().map(|s: &&str| s.to_string()).collect(), + } + }; +} + +macro_rules! params { + () => { HashMap::new() }; + ($($k:expr => $v:expr),+ $(,)?) => {{ + let mut m: HashMap = HashMap::new(); + $(m.insert($k.into(), $v.into());)+ + m + }}; +} + +pub fn tool_definitions() -> Vec { + vec![ + // ── Search / discovery ────────────────────────────────────────── + tool!( + "looker_search_content", + "Search Looker dashboards, Looks (saved reports), and folders by title or description. \ + Start here for BI, business intelligence, analytics, reports, visualizations, and finding existing data assets in Looker.", + params!( + "terms" => "Search terms (matches title/description)", + "types" => "Comma-separated content types to include: dashboard, look, folder (default: all)", + "limit" => "Maximum results to return (default: 25)", + "offset" => "Pagination offset (default: 0)" + ), + &["terms"] + ), + + // ── Folders ───────────────────────────────────────────────────── + tool!( + "looker_list_folders", + "List Looker folders (spaces) used to organize dashboards and Looks. Use for navigating BI content organization.", + params!( + "fields" => "Optional comma-separated field selection" + ) + ), + tool!( + "looker_get_folder", + "Get a Looker folder's metadata and child content (dashboards, Looks). Use after list_folders or search_content.", + params!( + "folder_id" => "Folder ID" + ), + &["folder_id"] + ), + + // ── Looks ─────────────────────────────────────────────────────── + tool!( + "looker_list_looks", + "List Looks — saved Looker reports and queries used for BI and analytics dashboards. \ + Use to discover existing saved analytics queries before creating new ones.", + params!( + "limit" => "Maximum Looks to return (default: 25)", + "offset" => "Pagination offset (default: 0)", + "fields" => "Optional comma-separated field selection" + ) + ), + tool!( + "looker_get_look", + "Get a Look's metadata, owner, folder, and underlying query reference. Use after list_looks to inspect a saved BI report.", + params!( + "look_id" => "Look ID" + ), + &["look_id"] + ), + tool!( + "looker_run_look", + "Run a saved Look and return its data rows as JSON. Use for fetching saved BI report results and analytics data. \ + Row count is capped (default 100, max 5000) — pass `limit` to adjust.", + params!( + "look_id" => "Look ID", + "limit" => "Row limit (default: 100, max: 5000)", + "apply_formatting" => "Apply Looker value formatting (default: false)", + "apply_vis" => "Apply visualization options (default: false)", + "cache" => "Use cache (default: true)" + ), + &["look_id"] + ), + + // ── Dashboards ────────────────────────────────────────────────── + tool!( + "looker_list_dashboards", + "List Looker dashboards — interactive BI reports and analytics visualizations. \ + Use for discovering existing dashboards before exploring data.", + params!( + "limit" => "Maximum dashboards to return (default: 25)", + "offset" => "Pagination offset (default: 0)", + "fields" => "Optional comma-separated field selection" + ) + ), + tool!( + "looker_get_dashboard", + "Get a dashboard's metadata, tiles, and filter definitions. Use after list_dashboards or search_content to inspect dashboard contents.", + params!( + "dashboard_id" => "Dashboard ID (numeric for user dashboards, slug-like for LookML)" + ), + &["dashboard_id"] + ), + + // ── Queries (the analytics workhorse) ─────────────────────────── + tool!( + "looker_run_inline_query", + "Run an ad-hoc Looker analytics query against a LookML model/explore and return rows as JSON. \ + This is the main BI tool — compose model + view + fields + filters + sorts to explore data. \ + Use list_models and get_model_explore first to discover available fields. \ + Row count is capped (default 100, max 5000).", + params!( + "model" => "LookML model name (from list_models)", + "view" => "LookML explore/view name (from get_model_explore)", + "fields" => "Comma-separated field names (e.g., 'users.id,users.email,orders.count')", + "filters" => "JSON object of filter expressions, e.g., {\"orders.created_date\":\"7 days\"}", + "sorts" => "Comma-separated sort expressions (e.g., 'orders.count desc')", + "limit" => "Row limit (default: 100, max: 5000)", + "pivots" => "Optional comma-separated pivot field names" + ), + &["model", "view", "fields"] + ), + tool!( + "looker_run_query", + "Run a previously-saved Looker query by ID and return rows as JSON. Use when chaining off get_look (look.query_id) or after create_query.", + params!( + "query_id" => "Query ID", + "limit" => "Row limit override (default: 100, max: 5000)", + "apply_formatting" => "Apply Looker value formatting (default: false)", + "cache" => "Use cache (default: true)" + ), + &["query_id"] + ), + tool!( + "looker_get_query", + "Get the definition of a saved query (model, view, fields, filters, sorts). Use to inspect a Look's query before re-running it.", + params!( + "query_id" => "Query ID" + ), + &["query_id"] + ), + tool!( + "looker_create_query", + "Create a saved Looker query definition (does not run it). Returns the query_id. Use with run_query when you want to reuse the same query multiple times.", + params!( + "model" => "LookML model name", + "view" => "LookML explore/view name", + "fields" => "Comma-separated field names", + "filters" => "JSON object of filter expressions", + "sorts" => "Comma-separated sort expressions", + "limit" => "Saved row limit (default: 500)", + "pivots" => "Optional comma-separated pivot field names" + ), + &["model", "view", "fields"] + ), + + // ── SQL Runner ────────────────────────────────────────────────── + tool!( + "looker_run_sql_query", + "Run a raw SQL query through Looker's SQL Runner against a configured connection. \ + Use for ad-hoc SQL analytics, BI exploration, and bypassing the LookML semantic layer when needed.", + params!( + "connection_name" => "Looker connection name (from list_connections)", + "sql" => "SQL query string" + ), + &["connection_name", "sql"] + ), + + // ── LookML Models ─────────────────────────────────────────────── + tool!( + "looker_list_models", + "List all LookML models available in Looker. LookML is Looker's semantic data modeling layer. Use before run_inline_query to discover models and their explores.", + params!() + ), + tool!( + "looker_get_model", + "Get a LookML model's metadata and list of explores. Use after list_models to find explore (view) names for run_inline_query.", + params!( + "model_name" => "LookML model name" + ), + &["model_name"] + ), + tool!( + "looker_get_model_explore", + "Get a LookML explore's full field metadata (dimensions, measures, filters). Use to discover field names for run_inline_query.", + params!( + "model_name" => "LookML model name", + "explore_name" => "Explore (view) name" + ), + &["model_name", "explore_name"] + ), + + // ── Connections ───────────────────────────────────────────────── + tool!( + "looker_list_connections", + "List database connections configured in Looker. Use to find connection_name for run_sql_query.", + params!() + ), + tool!( + "looker_get_connection", + "Get details of a Looker database connection (host, dialect, schema).", + params!( + "connection_name" => "Connection name" + ), + &["connection_name"] + ), + + // ── Users ─────────────────────────────────────────────────────── + tool!( + "looker_get_me", + "Get the current authenticated Looker user. Use to verify credentials and discover your user_id.", + params!() + ), + tool!( + "looker_list_users", + "List Looker users. Use for admin tasks like finding owners of Looks and dashboards.", + params!( + "limit" => "Maximum users (default: 25)", + "offset" => "Pagination offset (default: 0)" + ) + ), + tool!( + "looker_get_user", + "Get a Looker user's profile, roles, and email.", + params!( + "user_id" => "User ID" + ), + &["user_id"] + ), + + // ── Schedules ─────────────────────────────────────────────────── + tool!( + "looker_list_scheduled_plans", + "List Looker scheduled plans (recurring email/Slack deliveries of dashboards and Looks).", + params!( + "user_id" => "Optional: filter to plans owned by this user", + "all" => "Set 'true' to list across all users (requires admin)" + ) + ), + tool!( + "looker_get_scheduled_plan", + "Get a scheduled plan's details (recipients, frequency, content).", + params!( + "scheduled_plan_id" => "Scheduled plan ID" + ), + &["scheduled_plan_id"] + ), + ] +} From e04f4c58fbdc31928a40a87856cadb03acbce571 Mon Sep 17 00:00:00 2001 From: Dalton Cherry Date: Mon, 18 May 2026 12:11:53 -0500 Subject: [PATCH 2/2] Add Bland WASM plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a standalone Bland.ai plugin so voice AI and org management tools can ship through the plugin marketplace instead of core Switchboard. 💘 Generated with Crush Assisted-by: GPT-5.5 via Crush Co-Authored-By: GPT-5.5 --- Cargo.lock | 9 + README.md | 1 + dist/bland.wasm | Bin 0 -> 223601 bytes manifest.json | 19 ++ plugins/bland/Cargo.toml | 12 + plugins/bland/README.md | 45 +++ plugins/bland/src/handlers.rs | 614 ++++++++++++++++++++++++++++++++++ plugins/bland/src/lib.rs | 563 +++++++++++++++++++++++++++++++ plugins/bland/src/tools.rs | 313 +++++++++++++++++ 9 files changed, 1576 insertions(+) create mode 100755 dist/bland.wasm create mode 100644 plugins/bland/Cargo.toml create mode 100644 plugins/bland/README.md create mode 100644 plugins/bland/src/handlers.rs create mode 100644 plugins/bland/src/lib.rs create mode 100644 plugins/bland/src/tools.rs diff --git a/Cargo.lock b/Cargo.lock index 10950b8..2650c9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,15 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bland-wasm" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "switchboard-guest-sdk", +] + [[package]] name = "itoa" version = "1.0.18" diff --git a/README.md b/README.md index 36e0b2a..c9a7d63 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ A home for integrations that make more sense as standalone WASM modules than as | Plugin | Tools | Description | |--------|-------|-------------| +| [bland](plugins/bland/) | 30 | Bland.ai voice AI: calls, transcripts, voices, pathways, inbound numbers, knowledge bases, org management, billing, audit logs | | [looker](plugins/looker/) | 23 | Looker BI: dashboards, Looks, LookML models, inline analytics queries, SQL Runner | Prebuilt binaries live in [`dist/`](dist/) and are referenced by [`manifest.json`](manifest.json). diff --git a/dist/bland.wasm b/dist/bland.wasm new file mode 100755 index 0000000000000000000000000000000000000000..bee2f78024e2414e4e67f283c7d8d10c3a309ad0 GIT binary patch literal 223601 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�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

P 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 Oh?Qjt8~i%L_P+qA { + match $call { + Ok(v) => v, + Err(e) => return sdk::err_result(&e), + } + }; +} + +fn json_result(v: &serde_json::Value) -> sdk::ToolResult { + match serde_json::to_string(v) { + Ok(s) => sdk::raw_result(s), + Err(e) => sdk::err_result(&format!("encode response: {e}")), + } +} + +fn required( + args: &HashMap, + key: &str, +) -> Result { + let value = sdk::arg_str(args, key); + if value.is_empty() { + Err(sdk::err_result(&format!("{key} is required"))) + } else { + Ok(value) + } +} + +fn add_str_param( + args: &HashMap, + params: &mut Vec<(String, String)>, + arg: &str, + key: &str, +) { + let value = sdk::arg_str(args, arg); + if !value.is_empty() { + params.push((key.to_string(), value)); + } +} + +fn add_int_param( + args: &HashMap, + params: &mut Vec<(String, String)>, + arg: &str, + key: &str, +) { + if let Some(value) = sdk::arg_int(args, arg) { + params.push((key.to_string(), value.to_string())); + } +} + +fn add_bool_param( + args: &HashMap, + params: &mut Vec<(String, String)>, + arg: &str, + key: &str, +) { + if let Some(value) = sdk::arg_bool(args, arg) { + params.push((key.to_string(), value.to_string())); + } +} + +fn append_query(path: &str, params: &[(String, String)]) -> String { + if params.is_empty() { + return path.to_string(); + } + let query = params + .iter() + .map(|(key, value)| format!("{}={}", query_escape(key), query_escape(value))) + .collect::>() + .join("&"); + format!("{path}?{query}") +} + +fn insert_string_body( + args: &HashMap, + body: &mut serde_json::Map, + key: &str, +) { + let value = sdk::arg_str(args, key); + if !value.is_empty() { + body.insert(key.to_string(), serde_json::json!(value)); + } +} + +fn insert_i64_body( + args: &HashMap, + body: &mut serde_json::Map, + key: &str, +) { + if let Some(value) = sdk::arg_int(args, key) { + body.insert(key.to_string(), serde_json::json!(value)); + } +} + +fn insert_f64_body( + args: &HashMap, + body: &mut serde_json::Map, + key: &str, +) -> Result<(), String> { + match args.get(key) { + Some(serde_json::Value::Number(n)) => { + if let Some(value) = n.as_f64() { + body.insert(key.to_string(), serde_json::json!(value)); + } + } + Some(serde_json::Value::String(s)) if !s.is_empty() => { + let value = s + .parse::() + .map_err(|e| format!("{key} must be a number: {e}"))?; + body.insert(key.to_string(), serde_json::json!(value)); + } + _ => {} + } + Ok(()) +} + +fn insert_bool_body( + args: &HashMap, + body: &mut serde_json::Map, + key: &str, +) { + if let Some(value) = sdk::arg_bool(args, key) { + body.insert(key.to_string(), serde_json::json!(value)); + } +} + +fn insert_json_body( + args: &HashMap, + body: &mut serde_json::Map, + key: &str, +) -> Result<(), String> { + match args.get(key) { + Some(serde_json::Value::String(s)) if !s.is_empty() => { + let parsed: serde_json::Value = + serde_json::from_str(s).map_err(|e| format!("{key} must be valid JSON: {e}"))?; + body.insert(key.to_string(), parsed); + } + Some(v) if !v.is_null() => { + body.insert(key.to_string(), v.clone()); + } + _ => {} + } + Ok(()) +} + +pub fn list_calls(args: HashMap) -> sdk::ToolResult { + let mut params: Vec<(String, String)> = vec![( + "limit".into(), + sdk::arg_int(&args, "limit") + .unwrap_or(20) + .clamp(1, 100) + .to_string(), + )]; + add_int_param(&args, &mut params, "from", "from"); + add_int_param(&args, &mut params, "to", "to"); + add_bool_param(&args, &mut params, "ascending", "ascending"); + add_str_param(&args, &mut params, "sort_by", "sort_by"); + add_str_param(&args, &mut params, "start_date", "start_date"); + add_str_param(&args, &mut params, "end_date", "end_date"); + add_str_param(&args, &mut params, "batch_id", "batch_id"); + add_str_param(&args, &mut params, "answered_by", "answered_by"); + add_bool_param(&args, &mut params, "inbound", "inbound"); + add_bool_param(&args, &mut params, "completed", "completed"); + add_str_param(&args, &mut params, "from_number", "from_number"); + add_str_param(&args, &mut params, "to_number", "to_number"); + add_int_param(&args, &mut params, "duration_gt", "duration_gt"); + add_int_param(&args, &mut params, "duration_lt", "duration_lt"); + + let v = call!(bland_get(&append_query("/calls", ¶ms))); + json_result(&v) +} + +pub fn list_active_calls(_args: HashMap) -> sdk::ToolResult { + let v = call!(bland_get("/calls/active")); + json_result(&v) +} + +pub fn get_call(args: HashMap) -> sdk::ToolResult { + let id = match required(&args, "call_id") { + Ok(v) => v, + Err(e) => return e, + }; + let v = call!(bland_get(&format!("/calls/{}", path_escape(&id)))); + json_result(&v) +} + +pub fn send_call(args: HashMap) -> sdk::ToolResult { + let phone_number = match required(&args, "phone_number") { + Ok(v) => v, + Err(e) => return e, + }; + let task = sdk::arg_str(&args, "task"); + let pathway_id = sdk::arg_str(&args, "pathway_id"); + if task.is_empty() && pathway_id.is_empty() { + return sdk::err_result("task or pathway_id is required"); + } + + let mut body = serde_json::Map::new(); + body.insert("phone_number".into(), serde_json::json!(phone_number)); + if !task.is_empty() { + body.insert("task".into(), serde_json::json!(task)); + } + if !pathway_id.is_empty() { + body.insert("pathway_id".into(), serde_json::json!(pathway_id)); + } + + for key in [ + "voice", + "first_sentence", + "model", + "language", + "from", + "webhook", + "transfer_phone_number", + "timezone", + "background_track", + ] { + insert_string_body(&args, &mut body, key); + } + for key in ["max_duration", "interruption_threshold"] { + insert_i64_body(&args, &mut body, key); + } + for key in ["wait_for_greeting", "record"] { + insert_bool_body(&args, &mut body, key); + } + if let Err(e) = insert_f64_body(&args, &mut body, "temperature") { + return sdk::err_result(&e); + } + for key in ["metadata", "dynamic_data", "tools"] { + if let Err(e) = insert_json_body(&args, &mut body, key) { + return sdk::err_result(&e); + } + } + + let v = call!(bland_post("/calls", &serde_json::Value::Object(body))); + json_result(&v) +} + +pub fn stop_call(args: HashMap) -> sdk::ToolResult { + let id = match required(&args, "call_id") { + Ok(v) => v, + Err(e) => return e, + }; + let v = call!(bland_post( + &format!("/calls/{}/stop", path_escape(&id)), + &serde_json::json!({}) + )); + json_result(&v) +} + +pub fn analyze_call(args: HashMap) -> sdk::ToolResult { + let id = match required(&args, "call_id") { + Ok(v) => v, + Err(e) => return e, + }; + let goal = match required(&args, "goal") { + Ok(v) => v, + Err(e) => return e, + }; + let questions = match args.get("questions") { + Some(serde_json::Value::String(s)) if !s.is_empty() => { + match serde_json::from_str::(s) { + Ok(v) => v, + Err(e) => return sdk::err_result(&format!("questions must be valid JSON: {e}")), + } + } + Some(v) if !v.is_null() => v.clone(), + _ => return sdk::err_result("questions is required"), + }; + if !questions.is_array() { + return sdk::err_result("questions must be a JSON array"); + } + + let body = serde_json::json!({ + "goal": goal, + "questions": questions, + }); + let v = call!(bland_post( + &format!("/calls/{}/analyze", path_escape(&id)), + &body + )); + json_result(&v) +} + +pub fn list_voices(_args: HashMap) -> sdk::ToolResult { + let v = call!(bland_get("/voices")); + json_result(&v) +} + +pub fn get_voice(args: HashMap) -> sdk::ToolResult { + let id = match required(&args, "voice_id") { + Ok(v) => v, + Err(e) => return e, + }; + let v = call!(bland_get(&format!("/voices/{}", path_escape(&id)))); + json_result(&v) +} + +pub fn list_pathways(_args: HashMap) -> sdk::ToolResult { + let v = call!(bland_get("/pathway")); + json_result(&v) +} + +pub fn get_pathway(args: HashMap) -> sdk::ToolResult { + let id = match required(&args, "pathway_id") { + Ok(v) => v, + Err(e) => return e, + }; + let v = call!(bland_get(&format!("/pathway/{}", path_escape(&id)))); + json_result(&v) +} + +pub fn list_numbers(args: HashMap) -> sdk::ToolResult { + let mut params: Vec<(String, String)> = Vec::new(); + add_str_param(&args, &mut params, "encrypted_key", "encrypted_key"); + let v = call!(bland_get(&append_query("/inbound", ¶ms))); + json_result(&v) +} + +pub fn get_number(args: HashMap) -> sdk::ToolResult { + let phone_number = match required(&args, "phone_number") { + Ok(v) => v, + Err(e) => return e, + }; + let v = call!(bland_get(&format!( + "/inbound/{}", + path_escape(&phone_number) + ))); + json_result(&v) +} + +pub fn list_knowledge_bases(args: HashMap) -> sdk::ToolResult { + let mut params: Vec<(String, String)> = vec![ + ( + "page".into(), + sdk::arg_int(&args, "page").unwrap_or(1).max(1).to_string(), + ), + ( + "limit".into(), + sdk::arg_int(&args, "limit") + .unwrap_or(20) + .clamp(1, 100) + .to_string(), + ), + ]; + add_str_param(&args, &mut params, "status", "status"); + let v = call!(bland_get(&append_query("/knowledge", ¶ms))); + json_result(&v) +} + +pub fn get_knowledge_base(args: HashMap) -> sdk::ToolResult { + let id = match required(&args, "knowledge_base_id") { + Ok(v) => v, + Err(e) => return e, + }; + let v = call!(bland_get(&format!("/knowledge/{}", path_escape(&id)))); + json_result(&v) +} + +pub fn get_me(_args: HashMap) -> sdk::ToolResult { + let v = call!(bland_get("/me")); + json_result(&v) +} + +pub fn create_org(args: HashMap) -> sdk::ToolResult { + let name = match required(&args, "name") { + Ok(v) => v, + Err(e) => return e, + }; + let body = serde_json::json!({ "name": name }); + let v = call!(bland_post("/orgs/create", &body)); + json_result(&v) +} + +pub fn get_org(args: HashMap) -> sdk::ToolResult { + let org_id = match required(&args, "org_id") { + Ok(v) => v, + Err(e) => return e, + }; + let v = call!(bland_get(&format!("/orgs/{}", path_escape(&org_id)))); + json_result(&v) +} + +pub fn delete_org(args: HashMap) -> sdk::ToolResult { + let org_id = match required(&args, "org_id") { + Ok(v) => v, + Err(e) => return e, + }; + let delete_confirm = match required(&args, "delete_confirm") { + Ok(v) => v, + Err(e) => return e, + }; + let body = serde_json::json!({ "delete_confirm": delete_confirm }); + let v = call!(bland_delete( + &format!("/orgs/{}", path_escape(&org_id)), + Some(&body) + )); + json_result(&v) +} + +pub fn update_org_properties(args: HashMap) -> sdk::ToolResult { + let org_id = match required(&args, "org_id") { + Ok(v) => v, + Err(e) => return e, + }; + let mut updates = serde_json::Map::new(); + insert_string_body(&args, &mut updates, "org_display_name"); + + let mut preferences = serde_json::Map::new(); + insert_bool_body(&args, &mut preferences, "use_bland_url"); + insert_i64_body(&args, &mut preferences, "recording_lifespan_days"); + if !preferences.is_empty() { + updates.insert("preferences".into(), serde_json::Value::Object(preferences)); + } + if let Err(e) = insert_json_body(&args, &mut updates, "preferences") { + return sdk::err_result(&e); + } + if updates.is_empty() { + return sdk::err_result("at least one update field is required"); + } + + let body = serde_json::json!({ "updates": updates }); + let v = call!(bland_patch( + &format!("/orgs/{}/properties", path_escape(&org_id)), + &body + )); + json_result(&v) +} + +pub fn list_org_members(args: HashMap) -> sdk::ToolResult { + let org_id = match required(&args, "org_id") { + Ok(v) => v, + Err(e) => return e, + }; + let v = call!(bland_get(&format!( + "/orgs/{}/members", + path_escape(&org_id) + ))); + json_result(&v) +} + +pub fn update_org_members(args: HashMap) -> sdk::ToolResult { + let org_id = match required(&args, "org_id") { + Ok(v) => v, + Err(e) => return e, + }; + let action = match required(&args, "action") { + Ok(v) => v, + Err(e) => return e, + }; + let target = match required(&args, "target") { + Ok(v) => v, + Err(e) => return e, + }; + let mut body = serde_json::Map::new(); + body.insert("action".into(), serde_json::json!(action)); + body.insert("target".into(), serde_json::json!(target)); + if let Err(e) = insert_json_body(&args, &mut body, "permissions") { + return sdk::err_result(&e); + } + insert_bool_body(&args, &mut body, "is_invite"); + let v = call!(bland_patch( + &format!("/orgs/{}/members", path_escape(&org_id)), + &serde_json::Value::Object(body) + )); + json_result(&v) +} + +pub fn update_org_member_permissions(args: HashMap) -> sdk::ToolResult { + let org_id = match required(&args, "org_id") { + Ok(v) => v, + Err(e) => return e, + }; + let action = match required(&args, "action") { + Ok(v) => v, + Err(e) => return e, + }; + let target = match required(&args, "target") { + Ok(v) => v, + Err(e) => return e, + }; + let mut body = serde_json::Map::new(); + body.insert("action".into(), serde_json::json!(action)); + body.insert("target".into(), serde_json::json!(target)); + if let Err(e) = insert_json_body(&args, &mut body, "permissions") { + return sdk::err_result(&e); + } + if !body.contains_key("permissions") { + return sdk::err_result("permissions is required"); + } + let v = call!(bland_patch( + &format!("/orgs/{}/members/permissions", path_escape(&org_id)), + &serde_json::Value::Object(body), + )); + json_result(&v) +} + +pub fn list_my_org_memberships(_args: HashMap) -> sdk::ToolResult { + let v = call!(bland_get("/orgs/self/memberships")); + json_result(&v) +} + +pub fn leave_org(args: HashMap) -> sdk::ToolResult { + let org_id = match required(&args, "org_id") { + Ok(v) => v, + Err(e) => return e, + }; + let body = serde_json::json!({ "org_id": org_id }); + let v = call!(bland_delete("/orgs/self/leave", Some(&body))); + json_result(&v) +} + +pub fn get_org_billing(args: HashMap) -> sdk::ToolResult { + let org_id = match required(&args, "org_id") { + Ok(v) => v, + Err(e) => return e, + }; + let v = call!(bland_get(&format!( + "/orgs/{}/billing", + path_escape(&org_id) + ))); + json_result(&v) +} + +pub fn get_org_billing_refill(args: HashMap) -> sdk::ToolResult { + let org_id = match required(&args, "org_id") { + Ok(v) => v, + Err(e) => return e, + }; + let v = call!(bland_get(&format!( + "/orgs/{}/billing/refill", + path_escape(&org_id) + ))); + json_result(&v) +} + +fn org_service_path( + args: &HashMap, + suffix: &str, +) -> Result { + let org_id = required(args, "org_id")?; + let service = sdk::arg_str(args, "service"); + let service = if service.is_empty() { + "api_server".to_string() + } else { + service + }; + Ok(format!( + "/orgs/{}/versions/{}{}", + path_escape(&org_id), + path_escape(&service), + suffix + )) +} + +pub fn get_org_current_version(args: HashMap) -> sdk::ToolResult { + let path = match org_service_path(&args, "/current") { + Ok(v) => v, + Err(e) => return e, + }; + let v = call!(bland_get(&path)); + json_result(&v) +} + +pub fn list_org_versions(args: HashMap) -> sdk::ToolResult { + let path = match org_service_path(&args, "/list") { + Ok(v) => v, + Err(e) => return e, + }; + let v = call!(bland_get(&path)); + json_result(&v) +} + +pub fn update_org_version(args: HashMap) -> sdk::ToolResult { + let path = match org_service_path(&args, "") { + Ok(v) => v, + Err(e) => return e, + }; + let version = match required(&args, "version") { + Ok(v) => v, + Err(e) => return e, + }; + let body = serde_json::json!({ "version": version }); + let v = call!(bland_patch(&path, &body)); + json_result(&v) +} + +pub fn list_audit_logs(args: HashMap) -> sdk::ToolResult { + let mut params: Vec<(String, String)> = vec![ + ( + "page".into(), + sdk::arg_int(&args, "page").unwrap_or(1).max(1).to_string(), + ), + ( + "page_size".into(), + sdk::arg_int(&args, "page_size") + .unwrap_or(50) + .clamp(1, 100) + .to_string(), + ), + ]; + add_str_param(&args, &mut params, "event_type", "event_type"); + add_str_param(&args, &mut params, "actor_id", "actor_id"); + add_str_param(&args, &mut params, "created_after", "created_after"); + add_str_param(&args, &mut params, "created_before", "created_before"); + let v = call!(bland_get(&append_query("/audit/logs", ¶ms))); + json_result(&v) +} diff --git a/plugins/bland/src/lib.rs b/plugins/bland/src/lib.rs new file mode 100644 index 0000000..bdb239c --- /dev/null +++ b/plugins/bland/src/lib.rs @@ -0,0 +1,563 @@ +mod handlers; +mod tools; + +use std::collections::HashMap; +use std::sync::Mutex; +use switchboard_guest_sdk as sdk; + +#[cfg(test)] +#[no_mangle] +pub extern "C" fn host_http_request(_ptr_size: u64) -> u64 { + 0 +} + +#[cfg(test)] +#[no_mangle] +pub extern "C" fn host_log(_ptr: u32, _size: u32) {} + +const API_BASE: &str = "https://api.bland.ai/v1"; + +struct Config { + api_key: String, + org_id: String, +} + +static CONFIG: Mutex> = Mutex::new(None); + +fn with_config(f: F) -> Result +where + F: FnOnce(&Config) -> R, +{ + let guard = CONFIG.lock().map_err(|e| e.to_string())?; + match guard.as_ref() { + Some(c) => Ok(f(c)), + None => Err("bland: not configured".into()), + } +} + +#[no_mangle] +pub extern "C" fn name() -> u64 { + sdk::leaked_string("bland") +} + +#[no_mangle] +pub extern "C" fn metadata() -> u64 { + sdk::leaked_metadata(&sdk::PluginMetadata { + name: "bland".into(), + version: "0.1.0".into(), + abi_version: 1, + description: "Bland.ai voice AI integration for calls, transcripts, agents, voices, pathways, numbers, and knowledge bases.".into(), + author: "daltoniam".into(), + homepage: "https://github.com/daltoniam/switchboard_plugins".into(), + license: "MIT".into(), + capabilities: vec!["http".into()], + credential_keys: vec!["api_key".into(), "org_id".into()], + plain_text_keys: vec!["org_id".into()], + optional_keys: vec!["org_id".into()], + placeholders: HashMap::from([ + ("api_key".into(), "Bland.ai API key".into()), + ("org_id".into(), "Optional Bland organization ID".into()), + ]), + }) +} + +#[no_mangle] +pub extern "C" fn tools() -> u64 { + let defs = tools::tool_definitions(); + let data = serde_json::to_vec(&defs).unwrap_or_default(); + sdk::leaked_result(&data) +} + +#[no_mangle] +pub extern "C" fn configure(ptr_size: u64) -> u64 { + let input = sdk::read_input(ptr_size); + let creds: HashMap = match serde_json::from_slice(&input) { + Ok(c) => c, + Err(e) => return sdk::leaked_string(&format!("bland: invalid credentials JSON: {e}")), + }; + + let api_key = creds.get("api_key").cloned().unwrap_or_default(); + if api_key.is_empty() { + return sdk::leaked_string("bland: api_key is required"); + } + + *CONFIG.lock().unwrap() = Some(Config { + api_key, + org_id: creds.get("org_id").cloned().unwrap_or_default(), + }); + 0 +} + +#[no_mangle] +pub extern "C" fn execute(ptr_size: u64) -> u64 { + let input = sdk::read_input(ptr_size); + let req: sdk::ExecuteRequest = match serde_json::from_slice(&input) { + Ok(r) => r, + Err(e) => { + let r = sdk::err_result(&format!("invalid request: {e}")); + let data = serde_json::to_vec(&r).unwrap_or_default(); + return sdk::leaked_result(&data); + } + }; + + let result = dispatch(&req.tool_name, req.args); + let data = serde_json::to_vec(&result).unwrap_or_default(); + sdk::leaked_result(&data) +} + +#[no_mangle] +pub extern "C" fn healthy() -> i32 { + match bland_get("/voices") { + Ok(_) => 1, + Err(_) => 0, + } +} + +#[no_mangle] +pub extern "C" fn compact_specs() -> u64 { + sdk::leaked_compact_specs(&compact_spec_map()) +} + +type HandlerFn = fn(HashMap) -> sdk::ToolResult; + +fn dispatch(tool_name: &str, args: HashMap) -> sdk::ToolResult { + let handler: Option = match tool_name { + "bland_list_calls" => Some(handlers::list_calls), + "bland_list_active_calls" => Some(handlers::list_active_calls), + "bland_get_call" => Some(handlers::get_call), + "bland_send_call" => Some(handlers::send_call), + "bland_stop_call" => Some(handlers::stop_call), + "bland_analyze_call" => Some(handlers::analyze_call), + "bland_list_voices" => Some(handlers::list_voices), + "bland_get_voice" => Some(handlers::get_voice), + "bland_list_pathways" => Some(handlers::list_pathways), + "bland_get_pathway" => Some(handlers::get_pathway), + "bland_list_numbers" => Some(handlers::list_numbers), + "bland_get_number" => Some(handlers::get_number), + "bland_list_knowledge_bases" => Some(handlers::list_knowledge_bases), + "bland_get_knowledge_base" => Some(handlers::get_knowledge_base), + "bland_get_me" => Some(handlers::get_me), + "bland_create_org" => Some(handlers::create_org), + "bland_get_org" => Some(handlers::get_org), + "bland_delete_org" => Some(handlers::delete_org), + "bland_update_org_properties" => Some(handlers::update_org_properties), + "bland_list_org_members" => Some(handlers::list_org_members), + "bland_update_org_members" => Some(handlers::update_org_members), + "bland_update_org_member_permissions" => Some(handlers::update_org_member_permissions), + "bland_list_my_org_memberships" => Some(handlers::list_my_org_memberships), + "bland_leave_org" => Some(handlers::leave_org), + "bland_get_org_billing" => Some(handlers::get_org_billing), + "bland_get_org_billing_refill" => Some(handlers::get_org_billing_refill), + "bland_get_org_current_version" => Some(handlers::get_org_current_version), + "bland_list_org_versions" => Some(handlers::list_org_versions), + "bland_update_org_version" => Some(handlers::update_org_version), + "bland_list_audit_logs" => Some(handlers::list_audit_logs), + _ => None, + }; + + match handler { + Some(f) => f(args), + None => sdk::err_result(&format!("unknown tool: {tool_name}")), + } +} + +pub(crate) fn bland_get(path: &str) -> Result { + do_request("GET", path, None) +} + +pub(crate) fn bland_post( + path: &str, + body: &serde_json::Value, +) -> Result { + do_request("POST", path, Some(body)) +} + +pub(crate) fn bland_patch( + path: &str, + body: &serde_json::Value, +) -> Result { + do_request("PATCH", path, Some(body)) +} + +pub(crate) fn bland_delete( + path: &str, + body: Option<&serde_json::Value>, +) -> Result { + do_request("DELETE", path, body) +} + +fn do_request( + method: &str, + path: &str, + body: Option<&serde_json::Value>, +) -> Result { + let (api_key, org_id) = with_config(|c| (c.api_key.clone(), c.org_id.clone()))?; + + let mut headers = HashMap::new(); + headers.insert("Authorization".into(), api_key); + headers.insert("Accept".into(), "application/json".into()); + if !org_id.is_empty() { + headers.insert("x-bland-org-id".into(), org_id); + } + + let body_str = if let Some(b) = body { + headers.insert("Content-Type".into(), "application/json".into()); + serde_json::to_string(b).map_err(|e| format!("bland: encode request: {e}"))? + } else { + String::new() + }; + + let req = sdk::HttpRequest { + method: method.into(), + url: format!("{API_BASE}{path}"), + headers, + body: body_str, + ..Default::default() + }; + + let resp = sdk::host_http_request(&req)?; + if resp.status >= 400 { + return Err(format!("bland API error ({}): {}", resp.status, resp.body)); + } + if resp.status == 204 || resp.body.is_empty() { + return Ok(serde_json::json!({"status": "success"})); + } + serde_json::from_str(&resp.body).map_err(|e| format!("bland: decode response: {e}")) +} + +pub(crate) fn path_escape(s: &str) -> String { + encode_component(s) +} + +pub(crate) fn query_escape(s: &str) -> String { + encode_component(s) +} + +fn encode_component(s: &str) -> String { + let mut out = String::with_capacity(s.len()); + for b in s.as_bytes() { + let c = *b; + let safe = c.is_ascii_alphanumeric() || matches!(c, b'-' | b'_' | b'.' | b'~'); + if safe { + out.push(c as char); + } else { + out.push_str(&format!("%{c:02X}")); + } + } + out +} + +fn compact_spec_map() -> HashMap> { + let mut s: HashMap> = HashMap::new(); + + s.insert( + "bland_list_calls".into(), + vec![ + "count".into(), + "total_count".into(), + "calls[].call_id".into(), + "calls[].created_at".into(), + "calls[].to".into(), + "calls[].from".into(), + "calls[].call_length".into(), + "calls[].completed".into(), + "calls[].queue_status".into(), + "calls[].status".into(), + "calls[].error_message".into(), + "calls[].answered_by".into(), + "calls[].inbound".into(), + "calls[].batch_id".into(), + ], + ); + s.insert( + "bland_list_active_calls".into(), + vec![ + "calls[].call_id".into(), + "calls[].phone_number".into(), + "calls[].to".into(), + "calls[].from".into(), + "calls[].status".into(), + "calls[].created_at".into(), + "calls[].started_at".into(), + ], + ); + s.insert( + "bland_get_call".into(), + vec![ + "call_id".into(), + "created_at".into(), + "to".into(), + "from".into(), + "call_length".into(), + "status".into(), + "completed".into(), + "answered_by".into(), + "summary".into(), + "concatenated_transcript".into(), + "transcripts[].created_at".into(), + "transcripts[].user".into(), + "transcripts[].text".into(), + "analysis".into(), + "variables".into(), + "metadata".into(), + ], + ); + s.insert( + "bland_list_voices".into(), + vec![ + "voices[].id".into(), + "voices[].name".into(), + "voices[].description".into(), + "voices[].public".into(), + "voices[].tags".into(), + "voices[].total_ratings".into(), + "voices[].average_rating".into(), + ], + ); + s.insert( + "bland_get_voice".into(), + vec![ + "id".into(), + "name".into(), + "description".into(), + "public".into(), + "tags".into(), + "total_ratings".into(), + "average_rating".into(), + "language".into(), + ], + ); + s.insert( + "bland_list_pathways".into(), + vec![ + "pathways[].id".into(), + "pathways[].pathway_id".into(), + "pathways[].name".into(), + "pathways[].description".into(), + "pathways[].created_at".into(), + "pathways[].updated_at".into(), + ], + ); + s.insert( + "bland_get_pathway".into(), + vec![ + "id".into(), + "pathway_id".into(), + "name".into(), + "description".into(), + "created_at".into(), + "updated_at".into(), + "nodes".into(), + "edges".into(), + ], + ); + s.insert( + "bland_list_numbers".into(), + vec![ + "numbers[].phone_number".into(), + "numbers[].label".into(), + "numbers[].inbound_agent".into(), + "numbers[].created_at".into(), + ], + ); + s.insert( + "bland_get_number".into(), + vec![ + "phone_number".into(), + "label".into(), + "inbound_agent".into(), + "webhook".into(), + "created_at".into(), + ], + ); + s.insert( + "bland_list_knowledge_bases".into(), + vec![ + "knowledge_bases[].id".into(), + "knowledge_bases[].name".into(), + "knowledge_bases[].description".into(), + "knowledge_bases[].created_at".into(), + "knowledge_bases[].updated_at".into(), + "knowledge_bases[].status".into(), + ], + ); + s.insert( + "bland_get_knowledge_base".into(), + vec![ + "id".into(), + "name".into(), + "description".into(), + "created_at".into(), + "updated_at".into(), + "status".into(), + "documents".into(), + ], + ); + s.insert( + "bland_get_me".into(), + vec![ + "status".into(), + "billing.current_balance".into(), + "billing.refill_to".into(), + "total_calls".into(), + ], + ); + s.insert( + "bland_get_org".into(), + vec![ + "data.id".into(), + "data.org_slug".into(), + "data.org_display_name".into(), + "data.org_plan".into(), + "data.org_creation_date".into(), + "data.kyc_level".into(), + "data.is_deleted".into(), + "data.is_stripe_overdue".into(), + "data.is_suspended".into(), + "data.org_rate_limit".into(), + "data.org_type".into(), + "data.entitlements".into(), + "data.preferences".into(), + ], + ); + s.insert( + "bland_list_org_members".into(), + vec![ + "data[].org_id".into(), + "data[].user_id".into(), + "data[].permissions".into(), + "data[].is_owner".into(), + "data[].is_org_creator".into(), + "data[].joined_at".into(), + "data[].first_name".into(), + "data[].last_name".into(), + "data[].member_email".into(), + "data[].member_phone_number".into(), + ], + ); + s.insert( + "bland_update_org_member_permissions".into(), + vec!["data.newPermissions".into(), "errors".into()], + ); + s.insert( + "bland_list_my_org_memberships".into(), + vec![ + "data[].org_id".into(), + "data[].org_slug".into(), + "data[].org_display_name".into(), + "data[].permissions".into(), + "data[].is_owner".into(), + "data[].is_org_creator".into(), + "data[].joined_at".into(), + ], + ); + s.insert( + "bland_get_org_billing".into(), + vec![ + "data.current_balance".into(), + "data.refill_amount".into(), + "data.refill_at".into(), + "errors".into(), + ], + ); + s.insert( + "bland_get_org_billing_refill".into(), + vec!["data".into(), "errors".into()], + ); + s.insert( + "bland_get_org_current_version".into(), + vec!["data.version".into(), "errors".into()], + ); + s.insert( + "bland_list_org_versions".into(), + vec![ + "data.versions[].id".into(), + "data.versions[].friendly_name".into(), + "data.versions[].created_at".into(), + "data.versions[].git_sha".into(), + "data.versions[].tags".into(), + "data.versions[].currently_supported".into(), + "data.versions[].recommended_upgrade_to".into(), + "data.versions[].service".into(), + "data.versions[].placement_group".into(), + ], + ); + s.insert( + "bland_list_audit_logs".into(), + vec![ + "data.events[].id".into(), + "data.events[].org_id".into(), + "data.events[].actor_id".into(), + "data.events[].event_type".into(), + "data.events[].resource_type".into(), + "data.events[].resource_id".into(), + "data.events[].metadata".into(), + "data.events[].created_at".into(), + "data.total".into(), + "data.total_pages".into(), + "data.current_page".into(), + "data.page_size".into(), + ], + ); + + s +} + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashSet; + + #[test] + fn tool_definitions_have_required_metadata() { + let defs = tools::tool_definitions(); + assert_eq!(defs.len(), 30); + + let mut seen = HashSet::new(); + for def in defs { + assert!(def.name.starts_with("bland_")); + assert!(!def.description.is_empty()); + assert!(seen.insert(def.name)); + } + } + + #[test] + fn entry_point_tools_have_start_here_guidance() { + for def in tools::tool_definitions() { + if matches!( + def.name.as_str(), + "bland_list_calls" + | "bland_list_voices" + | "bland_list_pathways" + | "bland_list_numbers" + | "bland_list_knowledge_bases" + ) { + assert!(def.description.contains("Start here"), "{}", def.name); + } + } + } + + #[test] + fn compact_specs_reference_known_tools() { + let defs = tools::tool_definitions() + .into_iter() + .map(|def| def.name) + .collect::>(); + for name in compact_spec_map().keys() { + assert!(defs.contains(name), "{name}"); + } + } + + #[test] + fn unknown_tool_returns_error_result() { + let result = dispatch("bland_missing_tool", HashMap::new()); + assert!(result.is_error); + assert!(result.data.contains("unknown tool")); + } + + #[test] + fn escapes_path_and_query_components() { + assert_eq!(path_escape("+1555 123/abc"), "%2B1555%20123%2Fabc"); + assert_eq!(query_escape("created_at desc"), "created_at%20desc"); + } +} diff --git a/plugins/bland/src/tools.rs b/plugins/bland/src/tools.rs new file mode 100644 index 0000000..adde1db --- /dev/null +++ b/plugins/bland/src/tools.rs @@ -0,0 +1,313 @@ +use std::collections::HashMap; +use switchboard_guest_sdk::ToolDefinition; + +macro_rules! tool { + ($name:expr, $desc:expr, $params:expr) => { + ToolDefinition { + name: $name.into(), + description: $desc.into(), + parameters: $params, + required: vec![], + } + }; + ($name:expr, $desc:expr, $params:expr, $req:expr) => { + ToolDefinition { + name: $name.into(), + description: $desc.into(), + parameters: $params, + required: $req.iter().map(|s: &&str| s.to_string()).collect(), + } + }; +} + +macro_rules! params { + () => { HashMap::new() }; + ($($k:expr => $v:expr),+ $(,)?) => {{ + let mut m: HashMap = HashMap::new(); + $(m.insert($k.into(), $v.into());)+ + m + }}; +} + +pub fn tool_definitions() -> Vec { + vec![ + tool!( + "bland_list_calls", + "List Bland.ai voice AI phone calls with status, phone numbers, duration, completion, errors, and transcript availability. Start here for call history, call logs, outbound calls, inbound calls, conversations, and voice agent debugging.", + params!( + "limit" => "Maximum calls to return (default 20, max 100)", + "from" => "Pagination start index (inclusive)", + "to" => "Pagination end index (exclusive)", + "ascending" => "Sort ascending instead of descending (true/false)", + "sort_by" => "Sort field: created_at or updated_at (default created_at)", + "start_date" => "Filter calls created on or after this ISO date/time", + "end_date" => "Filter calls created on or before this ISO date/time", + "batch_id" => "Filter by Bland batch ID", + "answered_by" => "Filter by answered_by result", + "inbound" => "Filter inbound calls (true/false)", + "completed" => "Filter completed calls (true/false)", + "from_number" => "Filter by originating phone number", + "to_number" => "Filter by destination phone number", + "duration_gt" => "Filter calls longer than this duration in seconds", + "duration_lt" => "Filter calls shorter than this duration in seconds" + ) + ), + tool!( + "bland_list_active_calls", + "List currently active live Bland.ai calls. Use for monitoring in-progress phone conversations before stopping or inspecting them.", + params!() + ), + tool!( + "bland_get_call", + "Get details for a specific Bland.ai call, including status, summary, transcript, corrected transcript fields, analysis, variables, metadata, and conversation timing. Use after list_calls when debugging a call or reading a transcript.", + params!( + "call_id" => "Bland call_id returned by list_calls or send_call" + ), + &["call_id"] + ), + tool!( + "bland_send_call", + "Send or schedule an outbound Bland.ai AI phone call. Creates a voice agent call using either a task prompt or pathway_id, with optional voice, first sentence, metadata, webhook, transfer number, and dynamic variables.", + params!( + "phone_number" => "Destination phone number in E.164 format (for example +15551234567)", + "task" => "Plain-language voice agent task/instructions. Required unless pathway_id is provided", + "pathway_id" => "Existing Bland pathway ID. Required unless task is provided", + "voice" => "Voice ID or voice name", + "first_sentence" => "Opening sentence the AI should say", + "model" => "Bland model name", + "language" => "Language code (for example en-US)", + "from" => "Bland phone number to call from", + "webhook" => "Webhook URL for call events/results", + "metadata" => "JSON object string attached to the call", + "dynamic_data" => "JSON object string for pathway/task variables", + "tools" => "JSON array string of Bland tool definitions", + "transfer_phone_number" => "Phone number to transfer to", + "timezone" => "Timezone for scheduling and context", + "max_duration" => "Maximum call duration in minutes", + "wait_for_greeting" => "Wait for recipient greeting before speaking (true/false)", + "record" => "Whether to record the call (true/false)", + "temperature" => "Model temperature", + "interruption_threshold" => "Interruption sensitivity threshold", + "background_track" => "Background audio track name" + ), + &["phone_number"] + ), + tool!( + "bland_stop_call", + "Stop an active Bland.ai phone call. Use after list_active_calls or get_call when a live voice conversation should be ended.", + params!( + "call_id" => "Bland call_id for the active call to stop" + ), + &["call_id"] + ), + tool!( + "bland_analyze_call", + "Analyze a completed Bland.ai call transcript with AI using a goal and structured questions. Use after get_call to extract outcomes, classifications, lead qualification, sentiment, or custom fields.", + params!( + "call_id" => "Bland call_id to analyze", + "goal" => "Analysis goal or rubric", + "questions" => "JSON array of question objects or strings to answer from the call" + ), + &["call_id", "goal", "questions"] + ), + tool!( + "bland_list_voices", + "List Bland.ai voices for text-to-speech and phone calls, including voice IDs, names, descriptions, tags, public/private status, and ratings. Start here for choosing a call voice.", + params!() + ), + tool!( + "bland_get_voice", + "Get details for a specific Bland.ai voice. Use after list_voices to inspect a voice before using it in send_call.", + params!( + "voice_id" => "Bland voice ID" + ), + &["voice_id"] + ), + tool!( + "bland_list_pathways", + "List Bland.ai conversational pathways and voice agent flows. Start here for discovering pathway IDs to use when sending calls.", + params!() + ), + tool!( + "bland_get_pathway", + "Get a Bland.ai pathway's full configuration. Use after list_pathways to inspect a conversational flow before sending calls with pathway_id.", + params!( + "pathway_id" => "Bland pathway ID" + ), + &["pathway_id"] + ), + tool!( + "bland_list_numbers", + "List Bland.ai inbound phone numbers configured on the account. Start here for phone number inventory, inbound agents, and call routing setup.", + params!( + "encrypted_key" => "Optional encrypted key filter used by Bland for number lookup" + ) + ), + tool!( + "bland_get_number", + "Get details for a specific Bland.ai inbound phone number, including inbound agent and routing configuration. Use after list_numbers.", + params!( + "phone_number" => "Inbound phone number to inspect, usually in E.164 format" + ), + &["phone_number"] + ), + tool!( + "bland_list_knowledge_bases", + "List Bland.ai knowledge bases used by voice agents and pathways. Start here for discovering retrieval sources available to calls.", + params!( + "page" => "Page number (default 1)", + "limit" => "Maximum knowledge bases per page (default 20)" + ) + ), + tool!( + "bland_get_knowledge_base", + "Get a Bland.ai knowledge base's details and documents. Use after list_knowledge_bases to inspect retrieval content available to voice agents.", + params!( + "knowledge_base_id" => "Bland knowledge base ID" + ), + &["knowledge_base_id"] + ), + tool!( + "bland_get_me", + "Get the current Bland.ai account details, billing balance, and total call count. Start here for account management and credential verification.", + params!() + ), + tool!( + "bland_create_org", + "Create a new Bland.ai organization/workspace. Use for account and org management setup.", + params!( + "name" => "Organization display name" + ), + &["name"] + ), + tool!( + "bland_get_org", + "Get a Bland.ai organization's details, slug, plan, preferences, entitlements, rate limit, suspension, and deletion status. Use after list_my_org_memberships.", + params!( + "org_id" => "Bland organization ID" + ), + &["org_id"] + ), + tool!( + "bland_delete_org", + "Delete a Bland.ai organization. Requires delete_confirm with the organization slug for safety.", + params!( + "org_id" => "Bland organization ID", + "delete_confirm" => "Organization slug confirmation required by Bland" + ), + &["org_id", "delete_confirm"] + ), + tool!( + "bland_update_org_properties", + "Update Bland.ai organization properties such as display name and preferences including use_bland_url and recording retention lifespan. Use after get_org.", + params!( + "org_id" => "Bland organization ID", + "org_display_name" => "New organization display name (1-30 characters)", + "use_bland_url" => "Whether to use Bland-hosted URLs (true/false)", + "recording_lifespan_days" => "Recording retention in days (1-1825, or -1 to disable)", + "preferences" => "JSON object string for advanced preferences override" + ), + &["org_id"] + ), + tool!( + "bland_list_org_members", + "List Bland.ai organization members with emails, phone numbers, permissions, owner/admin/operator/viewer roles, join dates, and org metadata. Start here for org user management.", + params!( + "org_id" => "Bland organization ID" + ), + &["org_id"] + ), + tool!( + "bland_update_org_members", + "Add or remove Bland.ai organization members and invites. Use for org member management after list_org_members.", + params!( + "org_id" => "Bland organization ID", + "action" => "Member action: add or remove", + "target" => "Target user ID", + "permissions" => "JSON array of permissions for add: owner, admin, operator, viewer", + "is_invite" => "Whether removal applies to an invite (true/false)" + ), + &["org_id", "action", "target"] + ), + tool!( + "bland_update_org_member_permissions", + "Update Bland.ai organization member permissions and roles. Supports add, remove, reset, or set permissions: owner, admin, operator, viewer. Use after list_org_members.", + params!( + "org_id" => "Bland organization ID", + "action" => "Permission action: add, remove, reset, or set", + "target" => "Target user ID", + "permissions" => "JSON array of permissions: owner, admin, operator, viewer" + ), + &["org_id", "action", "target", "permissions"] + ), + tool!( + "bland_list_my_org_memberships", + "List Bland.ai organizations the current user belongs to, including org IDs, slugs, display names, permissions, owner status, and join dates. Start here to discover org_id values for management tools.", + params!() + ), + tool!( + "bland_leave_org", + "Leave a Bland.ai organization as the current user. Use after list_my_org_memberships.", + params!( + "org_id" => "Bland organization ID to leave" + ), + &["org_id"] + ), + tool!( + "bland_get_org_billing", + "Get Bland.ai organization billing information including current balance, refill amount, and refill threshold. Start here for org billing management.", + params!( + "org_id" => "Bland organization ID" + ), + &["org_id"] + ), + tool!( + "bland_get_org_billing_refill", + "Get Bland.ai organization billing refill threshold information. Use after get_org_billing.", + params!( + "org_id" => "Bland organization ID" + ), + &["org_id"] + ), + tool!( + "bland_get_org_current_version", + "Get the current Bland.ai service version for an organization. Supports api_server and ws_server services.", + params!( + "org_id" => "Bland organization ID", + "service" => "Service name: api_server (default) or ws_server" + ), + &["org_id"] + ), + tool!( + "bland_list_org_versions", + "List available Bland.ai service versions for an organization, including support status and recommended upgrades. Supports api_server and ws_server services.", + params!( + "org_id" => "Bland organization ID", + "service" => "Service name: api_server (default) or ws_server" + ), + &["org_id"] + ), + tool!( + "bland_update_org_version", + "Update a Bland.ai organization's service version. Supports api_server and ws_server services. Use after list_org_versions.", + params!( + "org_id" => "Bland organization ID", + "service" => "Service name: api_server (default) or ws_server", + "version" => "Version identifier to switch to" + ), + &["org_id", "version"] + ), + tool!( + "bland_list_audit_logs", + "List Bland.ai audit logs for enterprise org compliance, security, admin activity, pathway changes, knowledge base updates, and SSO events. Start here for compliance and audit investigations.", + params!( + "event_type" => "Optional exact event type filter", + "actor_id" => "Optional user ID filter", + "created_after" => "Optional ISO 8601 lower bound", + "created_before" => "Optional ISO 8601 upper bound", + "page" => "Page number (default 1)", + "page_size" => "Page size (default 50, max 100)" + ) + ), + ] +}