diff --git a/iii-directory/Cargo.lock b/iii-directory/Cargo.lock index e3ac9c1f15..69d6f3d987 100644 --- a/iii-directory/Cargo.lock +++ b/iii-directory/Cargo.lock @@ -262,18 +262,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "const-hex" -version = "1.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e2a781ebdf4467d1428dc4593067825fb646f6871475098d8577421af73558" -dependencies = [ - "cfg-if", - "cpufeatures", - "proptest", - "serde_core", -] - [[package]] name = "convert_case" version = "0.10.0" @@ -887,19 +875,6 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "hyper-timeout" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" -dependencies = [ - "hyper", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.20" @@ -1101,23 +1076,20 @@ dependencies = [ ] [[package]] -name = "iii-observability" -version = "0.16.0-next.2" +name = "iii-helpers" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00ee84dacaf7e14750ebdc229523e52029441c4ae1f72d25972bf1f2e1edeb99" +checksum = "09daa7c14a9e4c1f7077c4a181918d207e3f05cdfea8b2d7781bbeb80caf4c5d" dependencies = [ - "async-trait", "futures-util", "opentelemetry", "opentelemetry-http", - "opentelemetry-proto", "opentelemetry_sdk", - "prost", "reqwest", + "schemars", "serde", "serde_json", "sysinfo", - "thiserror 2.0.18", "tokio", "tokio-tungstenite", "tracing", @@ -1126,14 +1098,14 @@ dependencies = [ [[package]] name = "iii-sdk" -version = "0.16.0-next.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53c18b68b2aa09e18c68fb023c78316fe7ccf42181874eab584d66f40119b47e" +checksum = "5957568413b9a5178c11bf91b20909e93e568b187e259e941ba6009a7ec3f5c1" dependencies = [ "async-trait", "futures-util", "hostname", - "iii-observability", + "iii-helpers", "reqwest", "schemars", "serde", @@ -1415,23 +1387,6 @@ dependencies = [ "reqwest", ] -[[package]] -name = "opentelemetry-proto" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" -dependencies = [ - "base64", - "const-hex", - "opentelemetry", - "opentelemetry_sdk", - "prost", - "serde", - "serde_json", - "tonic", - "tonic-prost", -] - [[package]] name = "opentelemetry_sdk" version = "0.31.0" @@ -1551,44 +1506,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "proptest" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" -dependencies = [ - "bitflags", - "num-traits", - "rand", - "rand_chacha", - "rand_xorshift", - "regex-syntax", - "unarray", -] - -[[package]] -name = "prost" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-derive" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "quinn" version = "0.11.9" @@ -1694,15 +1611,6 @@ dependencies = [ "getrandom 0.3.4", ] -[[package]] -name = "rand_xorshift" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" -dependencies = [ - "rand_core", -] - [[package]] name = "redox_users" version = "0.4.6" @@ -2421,43 +2329,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tonic" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" -dependencies = [ - "async-trait", - "base64", - "bytes", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-timeout", - "hyper-util", - "percent-encoding", - "pin-project", - "sync_wrapper", - "tokio", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-prost" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" -dependencies = [ - "bytes", - "prost", - "tonic", -] - [[package]] name = "tower" version = "0.5.3" @@ -2466,15 +2337,11 @@ checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", - "indexmap", "pin-project-lite", - "slab", "sync_wrapper", "tokio", - "tokio-util", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -2619,12 +2486,6 @@ version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" -[[package]] -name = "unarray" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" - [[package]] name = "unicode-ident" version = "1.0.24" diff --git a/iii-directory/Cargo.toml b/iii-directory/Cargo.toml index ea9bdd1145..c16788d655 100644 --- a/iii-directory/Cargo.toml +++ b/iii-directory/Cargo.toml @@ -15,7 +15,7 @@ name = "iii_directory" path = "src/lib.rs" [dependencies] -iii-sdk = "=0.16.0-next.2" +iii-sdk = "=0.20.0" arc-swap = "1" tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "signal", "time", "fs", "process"] } serde = { version = "1", features = ["derive"] } diff --git a/iii-directory/src/configuration.rs b/iii-directory/src/configuration.rs index 2db7b5f5c8..3db5c6ef6a 100644 --- a/iii-directory/src/configuration.rs +++ b/iii-directory/src/configuration.rs @@ -16,7 +16,9 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use std::time::Duration; -use iii_sdk::{IIIError, RegisterFunction, RegisterTriggerInput, TriggerRequest, III}; +use iii_sdk::errors::Error; +use iii_sdk::protocol::{RegisterTriggerInput, TriggerRequest}; +use iii_sdk::{IIIClient, RegisterFunction}; use serde_json::{json, Value}; use crate::config::{SharedConfig, SkillsConfig, Topology}; @@ -67,7 +69,7 @@ impl SharedState { /// Register the `iii-directory` configuration schema with the configuration /// worker. When `seed` is present, its value is installed as `initial_value`. /// Otherwise, built-in defaults are seeded only when no stored value exists. -pub async fn register_config(iii: &III, seed: Option<&SkillsConfig>) -> Result<(), String> { +pub async fn register_config(iii: &IIIClient, seed: Option<&SkillsConfig>) -> Result<(), String> { let mut payload = json!({ "id": CONFIG_ID, "name": "iii-directory", @@ -86,7 +88,7 @@ pub async fn register_config(iii: &III, seed: Option<&SkillsConfig>) -> Result<( /// Read the live `iii-directory` configuration (env-expanded by the /// configuration worker). -pub async fn fetch_config(iii: &III) -> Result { +pub async fn fetch_config(iii: &IIIClient) -> Result { let value = get_config_value(iii).await?; if value.is_null() { tracing::info!("no configuration value found; using built-in default configuration"); @@ -95,7 +97,7 @@ pub async fn fetch_config(iii: &III) -> Result { SkillsConfig::from_json(&value) } -async fn should_seed_default_value(iii: &III) -> Result { +async fn should_seed_default_value(iii: &IIIClient) -> Result { match try_get_config_value(iii).await? { None => Ok(true), Some(value) if value.is_null() => Ok(true), @@ -103,14 +105,14 @@ async fn should_seed_default_value(iii: &III) -> Result { } } -async fn get_config_value(iii: &III) -> Result { +async fn get_config_value(iii: &IIIClient) -> Result { try_get_config_value(iii) .await? .ok_or_else(|| format!("configuration `{CONFIG_ID}` not found")) } /// Returns `Ok(None)` when the entry does not exist (`NOT_FOUND`). -async fn try_get_config_value(iii: &III) -> Result, String> { +async fn try_get_config_value(iii: &IIIClient) -> Result, String> { match trigger_with_retry(iii, "configuration::get", json!({ "id": CONFIG_ID })).await { Ok(resp) => Ok(resp.get("value").cloned()), Err(e) if e.contains("NOT_FOUND") => Ok(None), @@ -143,7 +145,7 @@ struct OnConfigChangeResponse { /// Register the internal config-change handler and bind a `configuration` /// trigger for `configuration:updated` on the `iii-directory` entry. -pub fn register_config_trigger(iii: &III, state: SharedState) -> Result<(), IIIError> { +pub fn register_config_trigger(iii: &IIIClient, state: SharedState) -> Result<(), Error> { let st = state.clone(); let engine = iii.clone(); iii.register_function( @@ -153,7 +155,7 @@ pub fn register_config_trigger(iii: &III, state: SharedState) -> Result<(), IIIE let engine = engine.clone(); async move { on_config_change(&engine, &st).await; - Ok::(OnConfigChangeResponse { ok: true }) + Ok::(OnConfigChangeResponse { ok: true }) } }) .description( @@ -182,7 +184,7 @@ pub fn register_config_trigger(iii: &III, state: SharedState) -> Result<(), IIIE /// download roots without updating persisted state. Re-fetch the stored /// value via `configuration::get` instead. Topology changes are refused — /// the on-disk roots and the auto-download wiring are fixed at boot. -async fn on_config_change(iii: &III, state: &SharedState) { +async fn on_config_change(iii: &IIIClient, state: &SharedState) { let cfg = match fetch_config(iii).await { Ok(cfg) => cfg, Err(e) => { @@ -204,7 +206,11 @@ async fn on_config_change(iii: &III, state: &SharedState) { tracing::info!("iii-directory configuration reloaded (tunable fields applied; caches cleared)"); } -async fn trigger_with_retry(iii: &III, function_id: &str, payload: Value) -> Result { +async fn trigger_with_retry( + iii: &IIIClient, + function_id: &str, + payload: Value, +) -> Result { let mut last_err = String::new(); for attempt in 1..=CONFIG_RETRIES { match iii diff --git a/iii-directory/src/functions/download.rs b/iii-directory/src/functions/download.rs index 0508cc6fd2..57d3770bf8 100644 --- a/iii-directory/src/functions/download.rs +++ b/iii-directory/src/functions/download.rs @@ -11,7 +11,8 @@ use std::sync::Arc; -use iii_sdk::{IIIError, RegisterFunction, III}; +use iii_sdk::errors::Error; +use iii_sdk::{IIIClient, RegisterFunction}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; @@ -108,7 +109,7 @@ pub enum ClassifiedInput { /// with `master`-default repos can override via the `branch` field. pub const DEFAULT_REPO_BRANCH: &str = "main"; -pub fn register(iii: &Arc, cfg: &SharedConfig, subscribers: &super::Subscribers) { +pub fn register(iii: &Arc, cfg: &SharedConfig, subscribers: &super::Subscribers) { register_download(iii, cfg, subscribers); register_download_from_registry(iii, cfg, subscribers); register_download_from_repo(iii, cfg, subscribers); @@ -117,16 +118,16 @@ pub fn register(iii: &Arc, cfg: &SharedConfig, subscribers: &super::Subscri /// Shared pipeline for all three download functions: validate + classify /// the source, pull it, fan out the change notification, build the response. async fn run_and_fan_out( - iii: &III, + iii: &IIIClient, cfg: &SkillsConfig, skills_subs: &SubscriberSet, prompts_subs: &SubscriberSet, input: DownloadInput, -) -> Result { - let classified = classify_input(input).map_err(IIIError::Handler)?; +) -> Result { + let classified = classify_input(input).map_err(Error::Handler)?; let result = run_download(cfg, &classified) .await - .map_err(IIIError::Handler)?; + .map_err(Error::Handler)?; fan_out(iii, skills_subs, prompts_subs, &classified, &result).await; Ok(build_output(&classified, result)) } @@ -135,7 +136,7 @@ async fn run_and_fan_out( /// source set. Kept for back-compat; new callers should prefer the /// explicit `download_from_registry` / `download_from_repo`, whose /// schemas make the source unambiguous. -fn register_download(iii: &Arc, cfg: &SharedConfig, subscribers: &super::Subscribers) { +fn register_download(iii: &Arc, cfg: &SharedConfig, subscribers: &super::Subscribers) { let iii_inner = iii.clone(); let cfg_inner = cfg.clone(); let skills_subs = subscribers.skills.clone(); @@ -166,7 +167,7 @@ fn register_download(iii: &Arc, cfg: &SharedConfig, subscribers: &super::Su /// The required `worker` field makes the source unambiguous at the /// schema level (no "specify exactly one of two groups" guesswork). fn register_download_from_registry( - iii: &Arc, + iii: &Arc, cfg: &SharedConfig, subscribers: &super::Subscribers, ) { @@ -207,7 +208,7 @@ fn register_download_from_registry( /// The required `repo` + `skill` fields make the source unambiguous at /// the schema level. fn register_download_from_repo( - iii: &Arc, + iii: &Arc, cfg: &SharedConfig, subscribers: &super::Subscribers, ) { @@ -368,7 +369,7 @@ fn build_output(classified: &ClassifiedInput, result: DownloadResult) -> Downloa /// least one skill was written (and likewise for prompts) so noisy /// no-op downloads don't churn MCP `notifications/list_changed`. async fn fan_out( - iii: &III, + iii: &IIIClient, skills_subs: &SubscriberSet, prompts_subs: &SubscriberSet, classified: &ClassifiedInput, diff --git a/iii-directory/src/functions/engine_fn.rs b/iii-directory/src/functions/engine_fn.rs index 5ca9a3bc52..39dd91f364 100644 --- a/iii-directory/src/functions/engine_fn.rs +++ b/iii-directory/src/functions/engine_fn.rs @@ -10,7 +10,9 @@ use std::sync::Arc; -use iii_sdk::{IIIError, RegisterFunction, TriggerRequest, III}; +use iii_sdk::errors::Error; +use iii_sdk::protocol::TriggerRequest; +use iii_sdk::{IIIClient, RegisterFunction}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; @@ -48,13 +50,13 @@ pub struct FunctionInfoOutput { // ────────────────── registration ────────────────────────────────────── -pub fn register(iii: &Arc) { +pub fn register(iii: &Arc) { let iii_inner = iii.clone(); iii.register_function( "directory::engine::functions::info", RegisterFunction::new_async(move |req: FunctionInfoInput| { let iii = iii_inner.clone(); - async move { function_info(&iii, req).await.map_err(IIIError::Handler) } + async move { function_info(&iii, req).await.map_err(Error::Handler) } }) .description( "Full detail for one engine function: schemas, owning worker, and \ @@ -66,7 +68,10 @@ pub fn register(iii: &Arc) { // ────────────────── handler ────────────────────────────────────────── -async fn function_info(iii: &III, input: FunctionInfoInput) -> Result { +async fn function_info( + iii: &IIIClient, + input: FunctionInfoInput, +) -> Result { let function_id = input.function_id.trim().to_string(); if function_id.is_empty() { return Err("function_id must be non-empty".into()); diff --git a/iii-directory/src/functions/mod.rs b/iii-directory/src/functions/mod.rs index 2ec7088126..fe725638ba 100644 --- a/iii-directory/src/functions/mod.rs +++ b/iii-directory/src/functions/mod.rs @@ -24,7 +24,7 @@ pub mod skills; use std::sync::Arc; -use iii_sdk::III; +use iii_sdk::IIIClient; use crate::config::{SharedConfig, SkillsConfig}; use crate::fs_source::{self, SourceKind}; @@ -47,7 +47,11 @@ impl From<&RegisteredTriggerTypes> for Subscribers { } } -pub fn register_all(iii: &Arc, cfg: &SharedConfig, trigger_types: &RegisteredTriggerTypes) { +pub fn register_all( + iii: &Arc, + cfg: &SharedConfig, + trigger_types: &RegisteredTriggerTypes, +) { skills::register(iii, cfg); prompts::register(iii, cfg); let subs = Subscribers::from(trigger_types); @@ -62,7 +66,7 @@ pub fn register_all(iii: &Arc, cfg: &SharedConfig, trigger_types: &Register } pub fn register_all_with_cache( - iii: &Arc, + iii: &Arc, cfg: &SharedConfig, trigger_types: &RegisteredTriggerTypes, cache: &std::sync::Arc, diff --git a/iii-directory/src/functions/prompts.rs b/iii-directory/src/functions/prompts.rs index 0335fd5026..2f2f3dc01c 100644 --- a/iii-directory/src/functions/prompts.rs +++ b/iii-directory/src/functions/prompts.rs @@ -16,7 +16,8 @@ use std::sync::Arc; -use iii_sdk::{IIIError, RegisterFunction, III}; +use iii_sdk::errors::Error; +use iii_sdk::{IIIClient, RegisterFunction}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -63,12 +64,12 @@ pub struct PromptGetOutput { pub modified_at: String, } -pub fn register(iii: &Arc, cfg: &SharedConfig) { +pub fn register(iii: &Arc, cfg: &SharedConfig) { register_list_prompts(iii, cfg); register_get_prompt(iii, cfg); } -fn register_list_prompts(iii: &Arc, cfg: &SharedConfig) { +fn register_list_prompts(iii: &Arc, cfg: &SharedConfig) { let cfg_inner = cfg.clone(); iii.register_function( "directory::prompts::list", @@ -90,7 +91,7 @@ fn register_list_prompts(iii: &Arc, cfg: &SharedConfig) { } }) .collect(); - Ok::<_, IIIError>(ListPromptsOutput { prompts: out }) + Ok::<_, Error>(ListPromptsOutput { prompts: out }) } }) .description( @@ -99,13 +100,13 @@ fn register_list_prompts(iii: &Arc, cfg: &SharedConfig) { ); } -fn register_get_prompt(iii: &Arc, cfg: &SharedConfig) { +fn register_get_prompt(iii: &Arc, cfg: &SharedConfig) { let cfg_inner = cfg.clone(); iii.register_function( "directory::prompts::get", RegisterFunction::new_async(move |req: PromptGetInput| { let cfg = cfg_inner.load_full(); - async move { get_prompt(&cfg, req).await.map_err(IIIError::Handler) } + async move { get_prompt(&cfg, req).await.map_err(Error::Handler) } }) .description( "Fetch one filesystem-backed prompt by name. Returns the raw markdown body plus name, \ diff --git a/iii-directory/src/functions/registry.rs b/iii-directory/src/functions/registry.rs index 610494687e..795e946b82 100644 --- a/iii-directory/src/functions/registry.rs +++ b/iii-directory/src/functions/registry.rs @@ -36,7 +36,8 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use std::time::{Duration, Instant}; -use iii_sdk::{IIIError, RegisterFunction, III}; +use iii_sdk::errors::Error; +use iii_sdk::{IIIClient, RegisterFunction}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -296,7 +297,7 @@ impl RegistryCache { // ---------- registration ---------- -pub fn register(iii: &Arc, cfg: &SharedConfig) { +pub fn register(iii: &Arc, cfg: &SharedConfig) { let ttl_ms = cfg.load().registry_cache_ttl_ms; let cache = RegistryCache::new(Duration::from_millis(ttl_ms)); register_with_cache(iii, cfg, cache); @@ -304,12 +305,12 @@ pub fn register(iii: &Arc, cfg: &SharedConfig) { /// Register the registry proxy functions against a shared cache so a /// `configuration:updated` reload can clear it (and repoint `registry_url`). -pub fn register_with_cache(iii: &Arc, cfg: &SharedConfig, cache: RegistryCache) { +pub fn register_with_cache(iii: &Arc, cfg: &SharedConfig, cache: RegistryCache) { register_worker_list(iii, cfg, cache.clone()); register_worker_info(iii, cfg, cache); } -fn register_worker_list(iii: &Arc, cfg: &SharedConfig, cache: RegistryCache) { +fn register_worker_list(iii: &Arc, cfg: &SharedConfig, cache: RegistryCache) { let cfg_inner = cfg.clone(); let cache_inner = cache; iii.register_function( @@ -317,11 +318,7 @@ fn register_worker_list(iii: &Arc, cfg: &SharedConfig, cache: RegistryCache RegisterFunction::new_async(move |req: WorkerListInput| { let cfg = cfg_inner.load_full(); let cache = cache_inner.clone(); - async move { - worker_list(&cfg, &cache, req) - .await - .map_err(IIIError::Handler) - } + async move { worker_list(&cfg, &cache, req).await.map_err(Error::Handler) } }) .description( "List workers from the public registry (api.workers.iii.dev). \ @@ -336,7 +333,7 @@ fn register_worker_list(iii: &Arc, cfg: &SharedConfig, cache: RegistryCache ); } -fn register_worker_info(iii: &Arc, cfg: &SharedConfig, cache: RegistryCache) { +fn register_worker_info(iii: &Arc, cfg: &SharedConfig, cache: RegistryCache) { let cfg_inner = cfg.clone(); let cache_inner = cache; iii.register_function( @@ -344,11 +341,7 @@ fn register_worker_info(iii: &Arc, cfg: &SharedConfig, cache: RegistryCache RegisterFunction::new_async(move |req: WorkerInfoInput| { let cfg = cfg_inner.load_full(); let cache = cache_inner.clone(); - async move { - worker_info(&cfg, &cache, req) - .await - .map_err(IIIError::Handler) - } + async move { worker_info(&cfg, &cache, req).await.map_err(Error::Handler) } }) .description( "Fetch full registry metadata for one worker: worker envelope \ diff --git a/iii-directory/src/functions/skills.rs b/iii-directory/src/functions/skills.rs index f33d3bdada..40842d951d 100644 --- a/iii-directory/src/functions/skills.rs +++ b/iii-directory/src/functions/skills.rs @@ -32,7 +32,9 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use std::time::Instant; -use iii_sdk::{IIIError, RegisterFunction, TriggerRequest, III}; +use iii_sdk::errors::Error; +use iii_sdk::protocol::TriggerRequest; +use iii_sdk::{IIIClient, RegisterFunction}; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; @@ -256,7 +258,7 @@ impl RegisteredWorkersCache { /// is acquired only to check / update the cache entry. A brief /// duplicate fetch on simultaneous cache misses is acceptable and /// far cheaper than serialising all reads behind a 5 s RPC. - pub async fn get_or_fetch(&self, iii: &III) -> Option> { + pub async fn get_or_fetch(&self, iii: &IIIClient) -> Option> { // Phase 1: check for a fresh cache entry under the lock. { let lock = self.inner.lock().await; @@ -278,13 +280,13 @@ impl RegisteredWorkersCache { /// last-known set on error). Used by `directory::skills::index` so a /// just-registered worker shows up immediately instead of waiting on /// the TTL or a worker-add cache invalidation. - pub async fn get_fresh(&self, iii: &III) -> Option> { + pub async fn get_fresh(&self, iii: &IIIClient) -> Option> { self.fetch_and_store(iii).await } /// Fetch `worker::list` from the engine WITHOUT holding the lock, /// then store the result (or fall back to the stale set on error). - async fn fetch_and_store(&self, iii: &III) -> Option> { + async fn fetch_and_store(&self, iii: &IIIClient) -> Option> { let result = iii .trigger(TriggerRequest { function_id: "worker::list".to_string(), @@ -368,7 +370,7 @@ fn parse_worker_names(val: &serde_json::Value) -> HashSet { pub async fn resolve_visible_skills( cfg: &SkillsConfig, cache: &RegisteredWorkersCache, - iii: &III, + iii: &IIIClient, fresh: bool, ) -> Vec { let (merged, _skipped) = @@ -440,7 +442,7 @@ pub(crate) fn filter_to_registered( .collect() } -pub fn register(iii: &Arc, cfg: &SharedConfig) { +pub fn register(iii: &Arc, cfg: &SharedConfig) { let cache = Arc::new(RegisteredWorkersCache::new( cfg.load().registry_cache_ttl_ms, )); @@ -458,7 +460,7 @@ pub fn make_registered_cache(ttl_ms: Arc) -> Arc, + iii: &Arc, cfg: &SharedConfig, cache: &Arc, ) { @@ -467,7 +469,11 @@ pub fn register_with_cache( register_index_skills(iii, cfg, cache); } -fn register_list_skills(iii: &Arc, cfg: &SharedConfig, cache: &Arc) { +fn register_list_skills( + iii: &Arc, + cfg: &SharedConfig, + cache: &Arc, +) { let cfg_inner = cfg.clone(); let iii_inner = iii.clone(); let cache_inner = cache.clone(); @@ -480,7 +486,7 @@ fn register_list_skills(iii: &Arc, cfg: &SharedConfig, cache: &Arc(ListSkillsOutput { skills: out }) + Ok::<_, Error>(ListSkillsOutput { skills: out }) } }) .description( @@ -552,7 +558,11 @@ fn list_skills_filtered(entries: Vec, input: &ListSkillsInput) -> Vec, cfg: &SharedConfig, cache: &Arc) { +fn register_get_skill( + iii: &Arc, + cfg: &SharedConfig, + cache: &Arc, +) { let cfg_inner = cfg.clone(); let iii_inner = iii.clone(); let cache_inner = cache.clone(); @@ -565,7 +575,7 @@ fn register_get_skill(iii: &Arc, cfg: &SharedConfig, cache: &Arc, cfg: &SharedConfig, cache: &Arc, cfg: &SharedConfig, cache: &Arc) { +fn register_index_skills( + iii: &Arc, + cfg: &SharedConfig, + cache: &Arc, +) { let cfg_inner = cfg.clone(); let iii_inner = iii.clone(); let cache_inner = cache.clone(); @@ -592,7 +606,7 @@ fn register_index_skills(iii: &Arc, cfg: &SharedConfig, cache: &Arc(IndexSkillsOutput { + Ok::<_, Error>(IndexSkillsOutput { body, workers_count, }) @@ -839,7 +853,7 @@ fn worker_overview_redirect_note( async fn get_skill_visible( cfg: &SkillsConfig, cache: &RegisteredWorkersCache, - iii: &III, + iii: &IIIClient, req: SkillGetInput, ) -> Result { let id = normalize_get_id(&req.id)?; diff --git a/iii-directory/src/main.rs b/iii-directory/src/main.rs index 8d5b7b7587..15d7d0c638 100644 --- a/iii-directory/src/main.rs +++ b/iii-directory/src/main.rs @@ -27,9 +27,10 @@ use std::sync::Arc; use anyhow::{Context, Result}; use clap::Parser; -use iii_sdk::{ - register_worker, InitOptions, RegisterFunction, TriggerRequest, WorkerMetadata, III, -}; +use iii_sdk::errors::Error; +use iii_sdk::protocol::{RegisterTriggerInput, TriggerRequest}; +use iii_sdk::runtime::WorkerMetadata; +use iii_sdk::{register_worker, IIIClient, InitOptions, RegisterFunction}; use serde_json::json; use iii_directory::config::{SharedConfig, SkillsConfig}; @@ -213,7 +214,7 @@ struct WorkerAddedAck { /// Register the internal `directory::__on_worker_added` handler and /// subscribe to the `worker` trigger type for `add` operations. fn setup_auto_download( - iii: &Arc, + iii: &Arc, cfg: &SharedConfig, cache: &Arc, in_flight: &Arc, @@ -231,7 +232,7 @@ fn setup_auto_download( let in_flight = in_flight_inner.clone(); async move { handle_worker_added(&cfg, &cache, &in_flight, &event).await; - Ok::<_, iii_sdk::IIIError>(WorkerAddedAck { ok: true }) + Ok::<_, Error>(WorkerAddedAck { ok: true }) } }) .description("Internal: auto-download skills on worker add event."), @@ -241,7 +242,7 @@ fn setup_auto_download( let iii_sub = iii.clone(); tokio::spawn(async move { for attempt in 1..=5 { - let result = iii_sub.register_trigger(iii_sdk::RegisterTriggerInput { + let result = iii_sub.register_trigger(RegisterTriggerInput { trigger_type: "worker".to_string(), function_id: "directory::__on_worker_added".to_string(), config: json!({ @@ -346,7 +347,7 @@ async fn reconcile_one( /// /// Returns the worker array on success, or `None` if `worker::list` /// never became available within the retry budget (~30s). -async fn fetch_worker_list_with_retry(iii: &III) -> Option> { +async fn fetch_worker_list_with_retry(iii: &IIIClient) -> Option> { const MAX_ATTEMPTS: u32 = 6; for attempt in 1..=MAX_ATTEMPTS { let result = iii @@ -394,7 +395,7 @@ async fn fetch_worker_list_with_retry(iii: &III) -> Option, + iii: Arc, cfg: SharedConfig, cache: Arc, in_flight: Arc, diff --git a/iii-directory/src/trigger_types.rs b/iii-directory/src/trigger_types.rs index ce50cf9769..ee9b6b4376 100644 --- a/iii-directory/src/trigger_types.rs +++ b/iii-directory/src/trigger_types.rs @@ -26,10 +26,10 @@ use std::collections::HashMap; use std::sync::{Arc, Mutex}; use async_trait::async_trait; -use iii_sdk::{ - IIIError, RegisterTriggerType, TriggerAction, TriggerConfig, TriggerHandler, TriggerRequest, - III, -}; +use iii_sdk::errors::Error; +use iii_sdk::protocol::TriggerRequest; +use iii_sdk::trigger::{TriggerConfig, TriggerHandler}; +use iii_sdk::{IIIClient, RegisterTriggerType, TriggerAction}; use serde_json::Value; pub const SKILLS_ON_CHANGE: &str = "directory::skills::on-change"; @@ -82,7 +82,7 @@ impl SubscriberSet { /// blocked on downstream latency). Failures are logged and swallowed /// because a slow / misbehaving subscriber must not break the write /// path. -pub async fn dispatch(iii: &III, subscribers: &SubscriberSet, payload: Value) { +pub async fn dispatch(iii: &IIIClient, subscribers: &SubscriberSet, payload: Value) { let targets = subscribers.function_ids(); for function_id in targets { let fid = function_id.clone(); @@ -110,7 +110,7 @@ pub struct RegisteredTriggerTypes { pub prompts: SubscriberSet, } -pub fn register_all(iii: &Arc) -> RegisteredTriggerTypes { +pub fn register_all(iii: &Arc) -> RegisteredTriggerTypes { let skills = SubscriberSet::new(); let prompts = SubscriberSet::new(); @@ -147,7 +147,7 @@ impl SkillsTriggerHandler { #[async_trait] impl TriggerHandler for SkillsTriggerHandler { - async fn register_trigger(&self, config: TriggerConfig) -> Result<(), IIIError> { + async fn register_trigger(&self, config: TriggerConfig) -> Result<(), Error> { tracing::info!( trigger_type = %self.name, id = %config.id, @@ -158,7 +158,7 @@ impl TriggerHandler for SkillsTriggerHandler { Ok(()) } - async fn unregister_trigger(&self, config: TriggerConfig) -> Result<(), IIIError> { + async fn unregister_trigger(&self, config: TriggerConfig) -> Result<(), Error> { tracing::info!( trigger_type = %self.name, id = %config.id, diff --git a/iii-directory/tests/common/engine.rs b/iii-directory/tests/common/engine.rs index 1e2eb901da..cc144ee770 100644 --- a/iii-directory/tests/common/engine.rs +++ b/iii-directory/tests/common/engine.rs @@ -7,19 +7,21 @@ use std::sync::Arc; use std::time::Duration; -use iii_sdk::{register_worker, IIIError, InitOptions, TriggerRequest, III}; +use iii_sdk::errors::Error; +use iii_sdk::protocol::TriggerRequest; +use iii_sdk::{register_worker, IIIClient, InitOptions}; use serde_json::json; use tokio::sync::OnceCell; const DEFAULT_WS_URL: &str = "ws://127.0.0.1:49134"; -static ENGINE: OnceCell>> = OnceCell::const_new(); +static ENGINE: OnceCell>> = OnceCell::const_new(); pub fn ws_url() -> String { std::env::var("III_ENGINE_WS_URL").unwrap_or_else(|_| DEFAULT_WS_URL.to_string()) } -pub async fn try_connect_raw() -> Option> { +pub async fn try_connect_raw() -> Option> { let url = ws_url(); let iii = Arc::new(register_worker(&url, InitOptions::default())); @@ -35,7 +37,7 @@ pub async fn try_connect_raw() -> Option> { .await; match probe { Ok(_) => return Some(iii), - Err(IIIError::NotConnected) => continue, + Err(Error::NotConnected) => continue, Err(_) => continue, } } @@ -51,7 +53,7 @@ pub async fn try_connect_raw() -> Option> { /// Get-or-init the shared engine handle. Registers skills's own /// function surface in-process so the BDD scenarios drive the same /// code the production binary would. -pub async fn get_or_init() -> Option> { +pub async fn get_or_init() -> Option> { ENGINE .get_or_init(|| async { let iii = try_connect_raw().await?; diff --git a/iii-directory/tests/common/workers.rs b/iii-directory/tests/common/workers.rs index 934a5097d1..0deac1b789 100644 --- a/iii-directory/tests/common/workers.rs +++ b/iii-directory/tests/common/workers.rs @@ -18,7 +18,7 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::Result; -use iii_sdk::III; +use iii_sdk::IIIClient; use tokio::sync::OnceCell; use wiremock::MockServer; @@ -44,7 +44,7 @@ pub struct Shared { static SHARED: OnceCell> = OnceCell::const_new(); /// Idempotent: the first caller registers; subsequent callers reuse. -pub async fn register_all(iii: &Arc) -> Result> { +pub async fn register_all(iii: &Arc) -> Result> { if let Some(s) = SHARED.get() { return Ok(s.clone()); } diff --git a/iii-directory/tests/common/world.rs b/iii-directory/tests/common/world.rs index c724b752e4..5b7749e462 100644 --- a/iii-directory/tests/common/world.rs +++ b/iii-directory/tests/common/world.rs @@ -14,7 +14,7 @@ use std::path::PathBuf; use std::sync::Arc; use cucumber::World; -use iii_sdk::III; +use iii_sdk::IIIClient; use serde_json::Value; use iii_directory::config::SkillsConfig; @@ -22,7 +22,7 @@ use iii_directory::config::SkillsConfig; #[derive(World)] #[world(init = Self::new)] pub struct IiiSkillsWorld { - pub iii: Option>, + pub iii: Option>, pub cfg: Arc, pub stash: HashMap, /// Path of the per-binary `skills_folder` tempdir. Mirrors what the diff --git a/iii-directory/tests/steps/download_registry.rs b/iii-directory/tests/steps/download_registry.rs index af6aafd82f..d405c6cde0 100644 --- a/iii-directory/tests/steps/download_registry.rs +++ b/iii-directory/tests/steps/download_registry.rs @@ -6,7 +6,7 @@ //! them between scenarios. use cucumber::{given, when}; -use iii_sdk::TriggerRequest; +use iii_sdk::protocol::TriggerRequest; use serde_json::{json, Value}; use wiremock::matchers::{method, path, query_param}; use wiremock::{Mock, ResponseTemplate}; diff --git a/iii-directory/tests/steps/download_repo.rs b/iii-directory/tests/steps/download_repo.rs index b397da547f..b32494033b 100644 --- a/iii-directory/tests/steps/download_repo.rs +++ b/iii-directory/tests/steps/download_repo.rs @@ -11,7 +11,7 @@ use std::process::Command; use std::sync::Mutex; use cucumber::{given, then, when}; -use iii_sdk::TriggerRequest; +use iii_sdk::protocol::TriggerRequest; use serde_json::{json, Value}; use crate::common::world::IiiSkillsWorld; diff --git a/iii-directory/tests/steps/prompts.rs b/iii-directory/tests/steps/prompts.rs index 9679ea9c82..2c74cc8dae 100644 --- a/iii-directory/tests/steps/prompts.rs +++ b/iii-directory/tests/steps/prompts.rs @@ -5,7 +5,7 @@ //! role/messages wrapper. use cucumber::{given, then, when}; -use iii_sdk::TriggerRequest; +use iii_sdk::protocol::TriggerRequest; use serde_json::{json, Value}; use crate::common::world::IiiSkillsWorld; diff --git a/iii-directory/tests/steps/read.rs b/iii-directory/tests/steps/read.rs index 5fcf54ea6a..aeee16ddb7 100644 --- a/iii-directory/tests/steps/read.rs +++ b/iii-directory/tests/steps/read.rs @@ -7,7 +7,7 @@ //! batched fetch) is gone — see [`crate::functions::skills`]. use cucumber::{given, then, when}; -use iii_sdk::TriggerRequest; +use iii_sdk::protocol::TriggerRequest; use serde_json::{json, Value}; use crate::common::world::IiiSkillsWorld; diff --git a/iii-directory/tests/steps/registry.rs b/iii-directory/tests/steps/registry.rs index b7da0c47b4..dd124b4b45 100644 --- a/iii-directory/tests/steps/registry.rs +++ b/iii-directory/tests/steps/registry.rs @@ -6,7 +6,7 @@ //! the shared wiremock server in `common::workers`. use cucumber::{given, then, when}; -use iii_sdk::TriggerRequest; +use iii_sdk::protocol::TriggerRequest; use serde_json::Value; use wiremock::matchers::{method, path, query_param}; use wiremock::{Mock, Request, ResponseTemplate};