plugin: fix rust pdk wit template probes

This commit is contained in:
Keisuke Hirata 2026-06-20 14:39:10 +09:00
parent 06287aca40
commit 0a9e585c1d
No known key found for this signature in database
12 changed files with 105 additions and 13 deletions

1
Cargo.lock generated
View File

@ -5561,6 +5561,7 @@ version = "0.1.0"
dependencies = [
"serde",
"serde_json",
"tempfile",
"thiserror 2.0.18",
"toml",
"wit-bindgen",

View File

@ -13,4 +13,5 @@ thiserror.workspace = true
wit-bindgen = "0.51.0"
[dev-dependencies]
tempfile.workspace = true
toml.workspace = true

View File

@ -10,9 +10,13 @@
//! [`export_component_tool!`] macro:
//!
//! ```ignore
//! yoi_plugin_pdk::wit_bindgen::generate!({
//! use yoi_plugin_pdk::wit_bindgen;
//!
//! wit_bindgen::generate!({
//! world: "tool",
//! path: "../../../../resources/plugin/wit",
//! generate_all,
//! runtime_path: "yoi_plugin_pdk::wit_bindgen::rt",
//! });
//!
//! fn echo(
@ -42,7 +46,8 @@ pub const TOOL_WORLD: &str = "yoi:plugin/tool@1.0.0";
pub const TOOL_WIT: &str = include_str!("../../../resources/plugin/wit/yoi-plugin-tool-v1.wit");
/// Repository WIT for the grant-bound host APIs importable by Tool components.
pub const HOST_WIT: &str = include_str!("../../../resources/plugin/wit/yoi-host-v1.wit");
pub const HOST_WIT: &str =
include_str!("../../../resources/plugin/wit/deps/yoi-host/yoi-host-v1.wit");
/// Maximum serialized ToolOutput JSON accepted by Yoi's current Plugin runtime.
pub const MAX_TOOL_OUTPUT_BYTES: usize = 64 * 1024;
@ -321,9 +326,11 @@ where
/// Implement the generated Component Model `Guest` trait for a typed JSON
/// handler and export it with the `wit-bindgen` generated `export!` macro.
///
/// The caller must invoke `yoi_plugin_pdk::wit_bindgen::generate!` for the
/// `tool` world first, which defines the `Guest` trait and `export!` macro in
/// the current module. The generated component still imports only WIT-declared
/// The caller must import the PDK's `wit_bindgen` re-export and invoke
/// `wit_bindgen::generate!` for the `tool` world first, with
/// `runtime_path: "yoi_plugin_pdk::wit_bindgen::rt"`. That defines the
/// `Guest` trait and `export!` macro in the current module. The generated
/// component still imports only WIT-declared
/// host APIs; this macro does not grant filesystem, network, or environment
/// authority.
#[macro_export]
@ -464,5 +471,6 @@ mod tests {
assert_eq!(TOOL_WORLD, "yoi:plugin/tool@1.0.0");
assert!(HOST_WIT.contains("interface https"));
assert!(HOST_WIT.contains("interface fs"));
assert!(HOST_WIT.contains("%list: func"));
}
}

View File

@ -1,3 +1,7 @@
use std::fs;
use std::path::Path;
use std::process::Command;
use toml::Value;
const TEMPLATE_CARGO: &str =
@ -15,6 +19,7 @@ const PDK_CARGO: &str = include_str!("../Cargo.toml");
fn rust_component_tool_template_has_expected_files() {
let cargo: Value = toml::from_str(TEMPLATE_CARGO).expect("template Cargo.toml parses");
assert_eq!(cargo["package"]["edition"].as_str(), Some("2024"));
assert!(cargo["workspace"].is_table());
assert_eq!(cargo["lib"]["crate-type"][0].as_str(), Some("cdylib"));
assert_eq!(
cargo["dependencies"]["yoi-plugin-pdk"]["path"].as_str(),
@ -31,7 +36,10 @@ fn rust_component_tool_template_has_expected_files() {
);
assert!(plugin["tools"].as_array().expect("tools array").len() == 1);
assert!(TEMPLATE_LIB.contains("yoi_plugin_pdk::wit_bindgen::generate!"));
assert!(TEMPLATE_LIB.contains("use yoi_plugin_pdk::wit_bindgen"));
assert!(TEMPLATE_LIB.contains("wit_bindgen::generate!"));
assert!(TEMPLATE_LIB.contains("generate_all"));
assert!(TEMPLATE_LIB.contains("runtime_path: \"yoi_plugin_pdk::wit_bindgen::rt\""));
assert!(TEMPLATE_LIB.contains("yoi_plugin_pdk::export_component_tool!"));
assert!(TEMPLATE_LIB.contains("ToolOutput::json"));
assert!(TEMPLATE_README.contains("Component Model Tool Plugin"));
@ -39,11 +47,47 @@ fn rust_component_tool_template_has_expected_files() {
#[test]
fn documented_sample_uses_pdk_component_path() {
assert!(SAMPLE_LIB.contains("yoi_plugin_pdk::wit_bindgen::generate!"));
assert!(SAMPLE_LIB.contains("use yoi_plugin_pdk::wit_bindgen"));
assert!(SAMPLE_LIB.contains("wit_bindgen::generate!"));
assert!(SAMPLE_LIB.contains("generate_all"));
assert!(SAMPLE_LIB.contains("runtime_path: \"yoi_plugin_pdk::wit_bindgen::rt\""));
assert!(SAMPLE_LIB.contains("yoi_plugin_pdk::export_component_tool!"));
assert!(!SAMPLE_LIB.contains("export_name"));
}
#[test]
fn embedded_template_cargo_checks_for_wasm_target() {
let crate_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let template_dir = crate_dir.join("../../resources/plugin/templates/rust-component-tool");
let manifest_path = template_dir.join("Cargo.toml");
let lock_path = template_dir.join("Cargo.lock");
let _ = fs::remove_file(&lock_path);
let target_dir = tempfile::tempdir().expect("temporary cargo target dir");
let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string());
let output = Command::new(cargo)
.arg("check")
.arg("--manifest-path")
.arg(&manifest_path)
.arg("--target")
.arg("wasm32-unknown-unknown")
.arg("--offline")
.arg("--target-dir")
.arg(target_dir.path())
.env("CARGO_TERM_COLOR", "never")
.output()
.expect("spawn cargo check for embedded template");
let _ = fs::remove_file(&lock_path);
assert!(
output.status.success(),
"template cargo check failed\nstatus: {}\nstdout:\n{}\nstderr:\n{}",
output.status,
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn pdk_runtime_dependencies_are_guest_side_only() {
let cargo: Value = toml::from_str(PDK_CARGO).expect("PDK Cargo.toml parses");

View File

@ -0,0 +1,25 @@
use yoi_plugin_pdk::wit_bindgen;
wit_bindgen::generate!({
world: "tool",
path: "../../resources/plugin/wit",
generate_all,
runtime_path: "yoi_plugin_pdk::wit_bindgen::rt",
});
struct Probe;
impl Guest for Probe {
fn call(tool_name: String, input_json: String) -> String {
yoi_plugin_pdk::run_json_tool(&tool_name, &input_json, |_ctx, input: serde_json::Value| {
yoi_plugin_pdk::ToolOutput::json("probe ok", input)
})
}
}
#[test]
fn wit_bindgen_generates_current_tool_world() {
let output = <Probe as Guest>::call("probe".to_string(), r#"{"ok":true}"#.to_string());
let value: serde_json::Value = serde_json::from_str(&output).unwrap();
assert_eq!(value["summary"], "probe ok");
}

View File

@ -119,11 +119,14 @@ The important authoring shape is:
```rust
use serde::{Deserialize, Serialize};
use yoi_plugin_pdk::wit_bindgen;
use yoi_plugin_pdk::{ToolContext, ToolError, ToolOutput};
yoi_plugin_pdk::wit_bindgen::generate!({
wit_bindgen::generate!({
world: "tool",
path: "../../../resources/plugin/wit",
generate_all,
runtime_path: "yoi_plugin_pdk::wit_bindgen::rt",
});
#[derive(Deserialize)]

View File

@ -4,11 +4,14 @@
//! and package the adapted component as `plugin.component.wasm`.
use serde::{Deserialize, Serialize};
use yoi_plugin_pdk::wit_bindgen;
use yoi_plugin_pdk::{ToolContext, ToolError, ToolOutput};
yoi_plugin_pdk::wit_bindgen::generate!({
wit_bindgen::generate!({
world: "tool",
path: "../../../resources/plugin/wit",
generate_all,
runtime_path: "yoi_plugin_pdk::wit_bindgen::rt",
});
#[derive(Debug, Deserialize)]

View File

@ -40,7 +40,7 @@ rustPlatform.buildRustPackage rec {
filter = sourceFilter;
};
cargoHash = "sha256-gMDU496wWn3LYhlXwxczHW/tT3IJxclwJtIY6ZjomtQ=";
cargoHash = "sha256-ci9h0U83YQQBeT3xlsGuKULnl1Aphgpg3pR4n0se16I=";
depsExtraArgs = {
# Older fetchCargoVendor utilities used crates.io's API download endpoint,

View File

@ -5,6 +5,10 @@ edition = "2024"
license = "MIT"
publish = false
# Keep the embedded template checkable in-place without making it a member of
# Yoi's root workspace. A copied starter remains a normal standalone package.
[workspace]
[lib]
crate-type = ["cdylib"]

View File

@ -14,7 +14,7 @@ The PDK is guest-side only. It does not grant filesystem, network, or environmen
## Checkout/development dependency
Inside the Yoi checkout this template uses a local path dependency:
Inside the Yoi checkout this template uses a local path dependency and declares an empty `[workspace]` so it can be checked in place without becoming a member of Yoi's root workspace:
```toml
yoi-plugin-pdk = { path = "../../../../crates/plugin-pdk" }

View File

@ -1,9 +1,12 @@
use serde::{Deserialize, Serialize};
use yoi_plugin_pdk::wit_bindgen;
use yoi_plugin_pdk::{ToolContext, ToolError, ToolOutput};
yoi_plugin_pdk::wit_bindgen::generate!({
wit_bindgen::generate!({
world: "tool",
path: "../../../../resources/plugin/wit",
generate_all,
runtime_path: "yoi_plugin_pdk::wit_bindgen::rt",
});
#[derive(Debug, Deserialize)]

View File

@ -10,6 +10,6 @@ interface https {
/// Grant-bound filesystem host API. No ambient WASI filesystem is exposed.
interface fs {
read: func(request-json: string) -> string;
list: func(request-json: string) -> string;
%list: func(request-json: string) -> string;
write: func(request-json: string) -> string;
}