Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0bebce3
feat(rust-sdk): add RegisterFunctionOptions struct
guibeira Apr 24, 2026
aea57cb
feat(rust-sdk): re-export RegisterFunctionOptions
guibeira Apr 24, 2026
4c5f7ec
feat(rust-sdk)!: align register_function_with with Node/Python order
guibeira Apr 24, 2026
cb99f4a
docs(rust-sdk): update register_function_with rustdoc example
guibeira Apr 24, 2026
cf80e4a
docs(changelog): align Rust register_function_with signature
guibeira Apr 24, 2026
de3f8ae
docs(changelog): fix migration row Rust example
guibeira Apr 24, 2026
015f53a
docs: regenerate Rust SDK API reference for register_function_with re…
guibeira Apr 24, 2026
2e448c9
docs: add RegisterFunctionOptions to rustdoc parser allowlist
guibeira Apr 24, 2026
8bca6ca
feat(console-rust)!: migrate to new register_function_with signature
guibeira Apr 25, 2026
1514d2b
docs(skills): update Rust register_function_with references
guibeira Apr 25, 2026
336b6aa
docs: scan FunctionDoc descriptions/examples in type-reachability filter
guibeira Apr 25, 2026
d3de66c
refactor(rust-sdk)!: collapse to single register_function entry point
guibeira Apr 30, 2026
0da7e2f
fix(rust-sdk): migrate iii-worker sandbox_daemon + fmt the workspace
guibeira Apr 30, 2026
7520ff4
rename(rust-sdk): RegisterFunction::raw -> RegisterFunction::untyped
guibeira Apr 30, 2026
a22bc9e
refactor(rust-sdk)!: collapse to 3 constructors, fix handler error to…
guibeira Apr 30, 2026
3b06e05
fix(rust-sdk): address CodeRabbit review feedback
guibeira Apr 30, 2026
ce657c3
fix(rust-sdk): more CodeRabbit review fixes
guibeira Apr 30, 2026
3b79691
fix(rust-sdk): finalize rebase onto main
guibeira May 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
320 changes: 179 additions & 141 deletions console/packages/console-rust/src/bridge/functions.rs

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion console/packages/console-rust/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ async fn main() -> Result<()> {
}),
otel: otel_config,
headers: None,
..Default::default()
},
);

Expand Down
84 changes: 53 additions & 31 deletions crates/iii-worker/src/cli/worker_manager_daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ use crate::core::{
list as core_list, remove as core_remove, start as core_start, stop as core_stop,
update as core_update,
};
use iii_sdk::{III, InitOptions, OtelConfig, RegisterFunction, WorkerMetadata, register_worker};
use iii_sdk::{
III, IIIError, InitOptions, OtelConfig, RegisterFunction, WorkerMetadata, register_worker,
};
use schemars::{JsonSchema, schema_for};
use serde_json::Value;

Expand Down Expand Up @@ -72,6 +74,18 @@ pub fn bad_request_payload(input_label: &str, e: &serde_json::Error) -> String {
err_payload(&err)
}

fn handler_error(payload: String) -> IIIError {
IIIError::Handler(payload)
}

fn op_error(e: &WorkerOpError) -> IIIError {
handler_error(err_payload(e))
}

fn bad_request_error(input_label: &str, e: &serde_json::Error) -> IIIError {
handler_error(bad_request_payload(input_label, e))
}

fn schema_for_value<T: JsonSchema>() -> Option<Value> {
serde_json::to_value(schema_for!(T)).ok()
}
Expand Down Expand Up @@ -130,9 +144,10 @@ struct SchemaResponse {

fn register_schema(iii: &III) {
let _ = iii.register_function(
RegisterFunction::new_async("worker::schema", |payload: Value| async move {
"worker::schema",
RegisterFunction::new_async(|payload: Value| async move {
let req: SchemaRequest = serde_json::from_value(payload)
.map_err(|e| bad_request_payload("worker::schema", &e))?;
.map_err(|e| bad_request_error("worker::schema", &e))?;
let all = vec![
(
"worker::add",
Expand Down Expand Up @@ -199,7 +214,7 @@ fn register_schema(iii: &III) {
}
})
.collect();
Ok::<_, String>(SchemaResponse { schemas })
Ok::<_, IIIError>(SchemaResponse { schemas })
})
.description(
"Introspect request/response schemas for worker::* triggers. \
Expand All @@ -210,12 +225,13 @@ fn register_schema(iii: &III) {

fn register_add(iii: &III, project_root: PathBuf) {
let _ = iii.register_function(
RegisterFunction::new_async("worker::add", move |payload: Value| {
"worker::add",
RegisterFunction::new_async(move |payload: Value| {
let project_root = project_root.clone();
async move {
let opts: AddOptions = serde_json::from_value(payload)
.map_err(|e| bad_request_payload("worker::add", &e))?;
let ctx = ProjectCtx::open(project_root).map_err(|e| err_payload(&e))?;
.map_err(|e| bad_request_error("worker::add", &e))?;
let ctx = ProjectCtx::open(project_root).map_err(|e| op_error(&e))?;
core_add::run(
opts,
&ctx,
Expand All @@ -224,7 +240,7 @@ fn register_add(iii: &III, project_root: PathBuf) {
core_add::CallerMode::Trigger,
)
.await
.map_err(|e| err_payload(&e))
.map_err(|e| op_error(&e))
}
})
.description("Install a worker from registry name or OCI ref"),
Expand All @@ -233,15 +249,16 @@ fn register_add(iii: &III, project_root: PathBuf) {

fn register_remove(iii: &III, project_root: PathBuf) {
let _ = iii.register_function(
RegisterFunction::new_async("worker::remove", move |payload: Value| {
"worker::remove",
RegisterFunction::new_async(move |payload: Value| {
let project_root = project_root.clone();
async move {
let opts: RemoveOptions = serde_json::from_value(payload)
.map_err(|e| bad_request_payload("worker::remove", &e))?;
let ctx = ProjectCtx::open(project_root).map_err(|e| err_payload(&e))?;
.map_err(|e| bad_request_error("worker::remove", &e))?;
let ctx = ProjectCtx::open(project_root).map_err(|e| op_error(&e))?;
core_remove::run(opts, &ctx, &NullSink, &CliHostShim)
.await
.map_err(|e| err_payload(&e))
.map_err(|e| op_error(&e))
}
})
.description("Uninstall workers and clear their artifacts"),
Expand All @@ -250,15 +267,16 @@ fn register_remove(iii: &III, project_root: PathBuf) {

fn register_update(iii: &III, project_root: PathBuf) {
let _ = iii.register_function(
RegisterFunction::new_async("worker::update", move |payload: Value| {
"worker::update",
RegisterFunction::new_async(move |payload: Value| {
let project_root = project_root.clone();
async move {
let opts: UpdateOptions = serde_json::from_value(payload)
.map_err(|e| bad_request_payload("worker::update", &e))?;
let ctx = ProjectCtx::open(project_root).map_err(|e| err_payload(&e))?;
.map_err(|e| bad_request_error("worker::update", &e))?;
let ctx = ProjectCtx::open(project_root).map_err(|e| op_error(&e))?;
core_update::run(opts, &ctx, &NullSink, &CliHostShim)
.await
.map_err(|e| err_payload(&e))
.map_err(|e| op_error(&e))
}
})
.description("Reinstall workers preserving config"),
Expand All @@ -267,15 +285,16 @@ fn register_update(iii: &III, project_root: PathBuf) {

fn register_start(iii: &III, project_root: PathBuf) {
let _ = iii.register_function(
RegisterFunction::new_async("worker::start", move |payload: Value| {
"worker::start",
RegisterFunction::new_async(move |payload: Value| {
let project_root = project_root.clone();
async move {
let opts: StartOptions = serde_json::from_value(payload)
.map_err(|e| bad_request_payload("worker::start", &e))?;
let ctx = ProjectCtx::open(project_root).map_err(|e| err_payload(&e))?;
.map_err(|e| bad_request_error("worker::start", &e))?;
let ctx = ProjectCtx::open(project_root).map_err(|e| op_error(&e))?;
core_start::run(opts, &ctx, &NullSink, &CliHostShim)
.await
.map_err(|e| err_payload(&e))
.map_err(|e| op_error(&e))
}
})
.description("Start a configured worker"),
Expand All @@ -284,15 +303,16 @@ fn register_start(iii: &III, project_root: PathBuf) {

fn register_stop(iii: &III, project_root: PathBuf) {
let _ = iii.register_function(
RegisterFunction::new_async("worker::stop", move |payload: Value| {
"worker::stop",
RegisterFunction::new_async(move |payload: Value| {
let project_root = project_root.clone();
async move {
let opts: StopOptions = serde_json::from_value(payload)
.map_err(|e| bad_request_payload("worker::stop", &e))?;
let ctx = ProjectCtx::open(project_root).map_err(|e| err_payload(&e))?;
.map_err(|e| bad_request_error("worker::stop", &e))?;
let ctx = ProjectCtx::open(project_root).map_err(|e| op_error(&e))?;
core_stop::run(opts, &ctx, &NullSink, &CliHostShim)
.await
.map_err(|e| err_payload(&e))
.map_err(|e| op_error(&e))
}
})
.description("Stop a running worker"),
Expand All @@ -301,7 +321,8 @@ fn register_stop(iii: &III, project_root: PathBuf) {

fn register_list(iii: &III, project_root: PathBuf) {
let _ = iii.register_function(
RegisterFunction::new_async("worker::list", move |payload: Value| {
"worker::list",
RegisterFunction::new_async(move |payload: Value| {
let project_root = project_root.clone();
async move {
// Lenient default only for null or empty object. Other shapes
Expand All @@ -311,12 +332,12 @@ fn register_list(iii: &III, project_root: PathBuf) {
Value::Null => ListOptions::default(),
Value::Object(map) if map.is_empty() => ListOptions::default(),
_ => serde_json::from_value(payload)
.map_err(|e| bad_request_payload("worker::list", &e))?,
.map_err(|e| bad_request_error("worker::list", &e))?,
};
let ctx = ProjectCtx::open_unlocked(project_root);
core_list::run(opts, &ctx, &NullSink, &CliHostShim)
.await
.map_err(|e| err_payload(&e))
.map_err(|e| op_error(&e))
}
})
.description("List installed workers"),
Expand All @@ -325,15 +346,16 @@ fn register_list(iii: &III, project_root: PathBuf) {

fn register_clear(iii: &III, project_root: PathBuf) {
let _ = iii.register_function(
RegisterFunction::new_async("worker::clear", move |payload: Value| {
"worker::clear",
RegisterFunction::new_async(move |payload: Value| {
let project_root = project_root.clone();
async move {
let opts: ClearOptions = serde_json::from_value(payload)
.map_err(|e| bad_request_payload("worker::clear", &e))?;
let ctx = ProjectCtx::open(project_root).map_err(|e| err_payload(&e))?;
.map_err(|e| bad_request_error("worker::clear", &e))?;
let ctx = ProjectCtx::open(project_root).map_err(|e| op_error(&e))?;
core_clear::run(opts, &ctx, &NullSink, &CliHostShim)
.await
.map_err(|e| err_payload(&e))
.map_err(|e| op_error(&e))
}
})
.description("Wipe worker artifacts"),
Expand Down
6 changes: 6 additions & 0 deletions crates/iii-worker/src/sandbox_daemon/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,12 @@ impl std::fmt::Debug for SandboxErrorWire {
}
}

impl From<SandboxErrorWire> for iii_sdk::IIIError {
fn from(err: SandboxErrorWire) -> Self {
iii_sdk::IIIError::Handler(err.to_string())
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
16 changes: 5 additions & 11 deletions crates/iii-worker/src/sandbox_daemon/fs/chmod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;

use iii_sdk::{IIIError, RegisterFunctionMessage};
use iii_sdk::IIIError;
use iii_shell_proto::{FsOp, FsResult};
use serde::{Deserialize, Serialize};
use serde_json::Value;
Expand Down Expand Up @@ -91,16 +91,10 @@ pub(super) fn register(
}
}) as Pin<Box<dyn Future<Output = Result<Value, IIIError>> + Send>>
};
let _ = iii.register_function_with(
RegisterFunctionMessage {
id: "sandbox::fs::chmod".to_string(),
description: Some("Change file permissions inside a sandbox".to_string()),
request_format: None,
response_format: None,
metadata: None,
invocation: None,
},
handler,
let _ = iii.register_function(
"sandbox::fs::chmod",
iii_sdk::RegisterFunction::new_async(handler)
.description("Change file permissions inside a sandbox".to_string()),
);
}

Expand Down
16 changes: 5 additions & 11 deletions crates/iii-worker/src/sandbox_daemon/fs/grep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;

use iii_sdk::{IIIError, RegisterFunctionMessage};
use iii_sdk::IIIError;
use iii_shell_proto::{FsMatch, FsOp, FsResult};
use serde::{Deserialize, Serialize};
use serde_json::Value;
Expand Down Expand Up @@ -111,16 +111,10 @@ pub(super) fn register(
}
}) as Pin<Box<dyn Future<Output = Result<Value, IIIError>> + Send>>
};
let _ = iii.register_function_with(
RegisterFunctionMessage {
id: "sandbox::fs::grep".to_string(),
description: Some("Search for a pattern in files inside a sandbox".to_string()),
request_format: None,
response_format: None,
metadata: None,
invocation: None,
},
handler,
let _ = iii.register_function(
"sandbox::fs::grep",
iii_sdk::RegisterFunction::new_async(handler)
.description("Search for a pattern in files inside a sandbox".to_string()),
);
}

Expand Down
16 changes: 5 additions & 11 deletions crates/iii-worker/src/sandbox_daemon/fs/ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;

use iii_sdk::{IIIError, RegisterFunctionMessage};
use iii_sdk::IIIError;
use iii_shell_proto::{FsEntry, FsOp, FsResult};
use serde::{Deserialize, Serialize};
use serde_json::Value;
Expand Down Expand Up @@ -75,16 +75,10 @@ pub(super) fn register(
}
}) as Pin<Box<dyn Future<Output = Result<Value, IIIError>> + Send>>
};
let _ = iii.register_function_with(
RegisterFunctionMessage {
id: "sandbox::fs::ls".to_string(),
description: Some("List directory contents inside a sandbox".to_string()),
request_format: None,
response_format: None,
metadata: None,
invocation: None,
},
handler,
let _ = iii.register_function(
"sandbox::fs::ls",
iii_sdk::RegisterFunction::new_async(handler)
.description("List directory contents inside a sandbox".to_string()),
);
}

Expand Down
16 changes: 5 additions & 11 deletions crates/iii-worker/src/sandbox_daemon/fs/mkdir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;

use iii_sdk::{IIIError, RegisterFunctionMessage};
use iii_sdk::IIIError;
use iii_shell_proto::{FsOp, FsResult};
use serde::{Deserialize, Serialize};
use serde_json::Value;
Expand Down Expand Up @@ -90,16 +90,10 @@ pub(super) fn register(
}
}) as Pin<Box<dyn Future<Output = Result<Value, IIIError>> + Send>>
};
let _ = iii.register_function_with(
RegisterFunctionMessage {
id: "sandbox::fs::mkdir".to_string(),
description: Some("Create a directory inside a sandbox".to_string()),
request_format: None,
response_format: None,
metadata: None,
invocation: None,
},
handler,
let _ = iii.register_function(
"sandbox::fs::mkdir",
iii_sdk::RegisterFunction::new_async(handler)
.description("Create a directory inside a sandbox".to_string()),
);
}

Expand Down
16 changes: 5 additions & 11 deletions crates/iii-worker/src/sandbox_daemon/fs/mv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;

use iii_sdk::{IIIError, RegisterFunctionMessage};
use iii_sdk::IIIError;
use iii_shell_proto::{FsOp, FsResult};
use serde::{Deserialize, Serialize};
use serde_json::Value;
Expand Down Expand Up @@ -85,16 +85,10 @@ pub(super) fn register(
}
}) as Pin<Box<dyn Future<Output = Result<Value, IIIError>> + Send>>
};
let _ = iii.register_function_with(
RegisterFunctionMessage {
id: "sandbox::fs::mv".to_string(),
description: Some("Move or rename a path inside a sandbox".to_string()),
request_format: None,
response_format: None,
metadata: None,
invocation: None,
},
handler,
let _ = iii.register_function(
"sandbox::fs::mv",
iii_sdk::RegisterFunction::new_async(handler)
.description("Move or rename a path inside a sandbox".to_string()),
);
}

Expand Down
Loading
Loading