fix(worker): remove Wip prefix from gateway tool names (T-712)

Expose Discover, Inspect, and Call in WIP mode and update schema descriptions and current documentation. Preserve execution, argument schemas, internal types, and ordinary Tools mode. Add a registered-tool discovery/inspection/call regression.

Validation: cargo test -p worker --lib wip::tests:: (43 passed); cargo test -p worker (827 unit + 110 integration passed); root cargo check; cargo fmt --all -- --check; git diff --check HEAD.
This commit is contained in:
2026-10-07 00:31:33 +09:00
parent 13055d7ee1
commit ed3bcf35bd
3 changed files with 78 additions and 16 deletions
+70 -8
View File
@@ -2426,7 +2426,7 @@ fn one() -> u32 {
#[derive(Debug, Deserialize, schemars::JsonSchema)]
struct WipInspectInput {
/// Opaque interface reference returned by WipDiscover.
/// Opaque interface reference returned by Discover.
interface: String,
/// Explicitly supersede the cached descriptor observation.
#[serde(default)]
@@ -2435,11 +2435,11 @@ struct WipInspectInput {
#[derive(Debug, Deserialize, schemars::JsonSchema)]
struct WipCallInput {
/// Exact object path returned by WipDiscover.
/// Exact object path returned by Discover.
path: String,
/// Exact interface reference selected from that object.
interface: String,
/// Exact operation name from WipInspect.
/// Exact operation name from Inspect.
operation: String,
/// Original operation arguments. Compatibility operations accept the original tool object here.
arguments: Json,
@@ -2521,7 +2521,7 @@ fn wip_tool_definitions(runtime: Arc<WipRuntime>) -> Vec<ToolDefinition> {
Arc::new(move || {
let schema = schemars::schema_for!(WipDiscoverInput);
(
ToolMeta::new("WipDiscover")
ToolMeta::new("Discover")
.description("Explore the authorized WIP Worldspace and stateful Known Space. Start at `/`; use reset after reconnect or authority changes.")
.input_schema(serde_json::to_value(schema).expect("WIP discover schema serializes")),
Arc::new(WipDiscoverTool {
@@ -2532,8 +2532,8 @@ fn wip_tool_definitions(runtime: Arc<WipRuntime>) -> Vec<ToolDefinition> {
Arc::new(move || {
let schema = schemars::schema_for!(WipInspectInput);
(
ToolMeta::new("WipInspect")
.description("Fetch and validate one descriptor returned by WipDiscover. Inspect before calling an operation.")
ToolMeta::new("Inspect")
.description("Fetch and validate one descriptor returned by Discover. Inspect before calling an operation.")
.input_schema(serde_json::to_value(schema).expect("WIP inspect schema serializes")),
Arc::new(WipInspectTool {
runtime: Arc::clone(&inspect_runtime),
@@ -2543,7 +2543,7 @@ fn wip_tool_definitions(runtime: Arc<WipRuntime>) -> Vec<ToolDefinition> {
Arc::new(move || {
let schema = schemars::schema_for!(WipCallInput);
(
ToolMeta::new("WipCall")
ToolMeta::new("Call")
.description("Invoke an operation only from fresh object/interface observations. Stale validators and invalid original JSON Schema inputs fail closed; unknown write outcomes must not be retried automatically.")
.input_schema(serde_json::to_value(schema).expect("WIP call schema serializes")),
Arc::new(WipCallTool {
@@ -3093,12 +3093,74 @@ mod tests {
.into_iter()
.map(|definition| definition.name)
.collect::<Vec<_>>(),
["WipCall", "WipDiscover", "WipInspect"]
["Call", "Discover", "Inspect"]
);
let metrics = runtime.metrics();
assert!(metrics.ordinary_schema_bytes > metrics.wip_schema_bytes);
}
#[tokio::test]
async fn renamed_gateway_tools_discover_inspect_and_call_through_registered_surface() {
let calls = Arc::new(AtomicUsize::new(0));
let mut engine = Engine::<_, Mutable, ()>::new_annotated(DummyClient);
engine.register_tool(echo_definition("Echo".into(), Arc::clone(&calls)));
install_wip_mode(&mut engine, None, "worker-a".into()).unwrap();
let tools = engine.tool_server_handle();
tools.flush_pending();
let discovered = transport_output_json(
tools
.call_tool(
"Discover",
r#"{"path":"/","depth":2}"#,
ToolExecutionContext::direct(),
)
.await
.unwrap(),
);
let object = discovered["known_space"]
.as_array()
.unwrap()
.iter()
.find(|item| item["path"] == "/tools/Echo")
.unwrap();
assert_eq!(object["state"], "fresh");
let interface = object["object"]["interfaces"][0].as_str().unwrap();
let inspected = transport_output_json(
tools
.call_tool(
"Inspect",
&json!({"interface": interface}).to_string(),
ToolExecutionContext::direct(),
)
.await
.unwrap(),
);
assert_eq!(inspected["interface"], interface);
assert_eq!(inspected["state"], "fresh");
assert_eq!(inspected["descriptor"]["operations"][0]["name"], "call");
let arguments = json!({"message": "hello"});
let output = tools
.call_tool(
"Call",
&json!({
"path": object["path"],
"interface": interface,
"operation": "call",
"arguments": arguments,
})
.to_string(),
ToolExecutionContext::direct(),
)
.await
.unwrap();
assert_eq!(output.summary, arguments.to_string());
assert!(output.content.is_none());
assert!(output.attachments.is_empty());
assert_eq!(calls.load(Ordering::SeqCst), 1);
}
#[test]
fn mount_collision_and_native_replacement_are_explicit() {
struct Native;