From 4565f48931e9e46219edc49d687415442384a9a3 Mon Sep 17 00:00:00 2001 From: Anderson Leal Date: Fri, 10 Jul 2026 18:33:22 -0300 Subject: [PATCH 1/2] (MOT-3962) Hide internal worker plumbing from engine::functions::list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit engine::functions::list is the candidate universe harness's LLM tool-discovery pulls from. It returned every internal orchestration, config-reload, and write-path function unfiltered — router::chat, session::store::*, provider::*::stream, harness::send/turn/stop, console browser watch handlers, and more — even though most of it is already denied to agents in iii-permissions.yaml. Discovery and authorization were two separate gates; this closes the discovery one too. Tags ~94 non-agent-facing registrations across 10 workers with metadata.internal = true, the field engine::functions::list already checks to hide tagged functions by default. Registrations stay fully callable by id — only discovery is hidden. console gets two extra layers: the browser SDK's client.on() now defaults new registrations to internal, and the WS proxy stamps metadata.internal = true onto any registerfunction frame passing through it, so a stale/cached SPA bundle can't leak a registration. --- console/src/functions/mod.rs | 5 +- console/src/proxy.rs | 82 ++++++++++++++++++- console/web/src/lib/iii-client.ts | 12 ++- context-manager/src/configuration.rs | 3 +- context-manager/src/functions/mod.rs | 33 +++++--- harness/src/configuration.rs | 3 +- harness/src/functions/mod.rs | 55 ++++++++++--- harness/src/subscriptions/notify_agent.rs | 3 +- iii-directory/src/configuration.rs | 3 +- iii-directory/src/main.rs | 3 +- llm-router/src/register.rs | 39 ++++++--- provider-anthropic/src/register.rs | 9 +- provider-openai-codex/src/register.rs | 9 +- provider-openai/src/register.rs | 9 +- provider-xai/src/configuration.rs | 3 +- provider-xai/src/register.rs | 9 +- provider-zai/src/register.rs | 9 +- scrapling/src/guidance.py | 2 + session-manager/src/configuration.rs | 6 +- session-manager/src/functions/mod.rs | 58 ++++++++----- .../src/functions/store_protocol.rs | 36 +++++--- shell/src/configuration.rs | 3 +- shell/src/main.rs | 3 +- web/src/configuration.rs | 6 +- web/src/functions/mod.rs | 3 +- 25 files changed, 306 insertions(+), 100 deletions(-) diff --git a/console/src/functions/mod.rs b/console/src/functions/mod.rs index 4be397f0d..a45e4a553 100644 --- a/console/src/functions/mod.rs +++ b/console/src/functions/mod.rs @@ -40,6 +40,9 @@ fn register_status(iii: &Arc, config: &Arc, engine_url }) .description( "Return the console worker's runtime knobs: http_port, engine_url, and version.", - ), + ) + // console-only plumbing; no other worker (e.g. harness) needs to + // discover or call it. + .metadata(serde_json::json!({ "internal": true })), ); } diff --git a/console/src/proxy.rs b/console/src/proxy.rs index 372d18785..616c243d6 100644 --- a/console/src/proxy.rs +++ b/console/src/proxy.rs @@ -6,9 +6,13 @@ //! between [`axum::extract::ws::Message`] and //! [`tokio_tungstenite::tungstenite::Message`]. //! -//! The proxy is intentionally dumb: no buffering, no rewriting, no auth. -//! The engine WebSocket and the iii-browser-sdk client on the page do -//! all the framing — this module just shuttles bytes. +//! The proxy is intentionally dumb — no buffering, no auth — with ONE +//! exception: browser→engine `registerfunction` messages get +//! `metadata.internal = true` stamped on (see +//! [`stamp_internal_registration`]). Everything a console page registers +//! is a live-update delivery target for that page, never a discoverable +//! API, and stamping here (not just in the SPA) means stale/cached +//! bundles can't pollute `engine::functions::list` either. use std::sync::Arc; @@ -62,6 +66,13 @@ async fn handle_ws(client: WebSocket, engine_url: Arc) { } }; let is_close = matches!(msg, AxumMessage::Close(_)); + let msg = match msg { + AxumMessage::Text(t) => match stamp_internal_registration(&t) { + Some(stamped) => AxumMessage::Text(stamped), + None => AxumMessage::Text(t), + }, + other => other, + }; if let Some(out) = axum_to_tungstenite(msg) { if let Err(e) = engine_tx.send(out).await { tracing::debug!(error = %e, "browser -> engine: engine send error"); @@ -104,6 +115,37 @@ async fn handle_ws(client: WebSocket, engine_url: Arc) { } } +/// If `text` is a wire `registerfunction` message, return a copy with +/// `metadata.internal = true` merged in; `None` means "forward the +/// original untouched" (not a registration, unparseable, or a metadata +/// shape we don't understand). +pub(crate) fn stamp_internal_registration(text: &str) -> Option { + // Fast path: skip the JSON parse for the overwhelming majority of + // frames (invocations, results, stream sends). + if !text.contains("\"registerfunction\"") { + return None; + } + let mut msg: serde_json::Value = serde_json::from_str(text).ok()?; + if msg.get("type").and_then(|t| t.as_str()) != Some("registerfunction") { + return None; + } + let obj = msg.as_object_mut()?; + match obj.get_mut("metadata") { + Some(serde_json::Value::Object(meta)) => { + meta.insert("internal".into(), serde_json::Value::Bool(true)); + } + // Unexpected metadata shape — don't rewrite what we don't understand. + Some(_) => return None, + None => { + obj.insert( + "metadata".into(), + serde_json::json!({ "internal": true }), + ); + } + } + serde_json::to_string(&msg).ok() +} + /// Convert an axum `Message` into a tungstenite `Message`. Returns /// `None` when the variant has no useful tungstenite equivalent. pub(crate) fn axum_to_tungstenite(msg: AxumMessage) -> Option { @@ -190,6 +232,40 @@ mod tests { } } + #[test] + fn stamp_adds_internal_metadata_when_absent() { + let wire = r#"{"type":"registerfunction","id":"console::harness-watch::r0::console-abc"}"#; + let out = stamp_internal_registration(wire).unwrap(); + let v: serde_json::Value = serde_json::from_str(&out).unwrap(); + assert_eq!(v["metadata"]["internal"], serde_json::json!(true)); + assert_eq!(v["id"], "console::harness-watch::r0::console-abc"); + } + + #[test] + fn stamp_merges_into_existing_metadata() { + let wire = r#"{"type":"registerfunction","id":"x","metadata":{"tenant":"acme"}}"#; + let out = stamp_internal_registration(wire).unwrap(); + let v: serde_json::Value = serde_json::from_str(&out).unwrap(); + assert_eq!(v["metadata"]["internal"], serde_json::json!(true)); + assert_eq!(v["metadata"]["tenant"], "acme"); + } + + #[test] + fn stamp_ignores_other_messages_and_bad_input() { + // Different message type — even one that mentions registerfunction in a payload. + assert!(stamp_internal_registration( + r#"{"type":"invokefunction","payload":"\"registerfunction\""}"# + ) + .is_none()); + // Not JSON. + assert!(stamp_internal_registration("registerfunction{").is_none()); + // Metadata of an unexpected shape is left alone. + assert!(stamp_internal_registration( + r#"{"type":"registerfunction","id":"x","metadata":"weird"}"# + ) + .is_none()); + } + #[test] fn raw_frame_is_dropped() { // Raw frames are an internal tungstenite construct; we don't diff --git a/console/web/src/lib/iii-client.ts b/console/web/src/lib/iii-client.ts index 52befcb49..97157defd 100644 --- a/console/web/src/lib/iii-client.ts +++ b/console/web/src/lib/iii-client.ts @@ -21,6 +21,7 @@ import { type IIIConnectionState, type ISdk, + type RegisterFunctionOptions, type RegisterTriggerInput, type RemoteFunctionHandler, registerWorker, @@ -42,6 +43,7 @@ export interface IiiClient { on

( functionId: string, handler: (payload: P) => void | Promise, + options?: RegisterFunctionOptions, ): () => void /** * Register an engine trigger bound to a function id. Thin passthrough to @@ -141,6 +143,7 @@ function wrapSdk(sdk: ISdk, browserId: string): IiiClient { function on

( functionId: string, handler: (payload: P) => void | Promise, + options?: RegisterFunctionOptions, ): () => void { const id = `${functionId}::${browserId}` // Wrap to satisfy the SDK's RemoteFunctionHandler signature (returns @@ -149,7 +152,14 @@ function wrapSdk(sdk: ISdk, browserId: string): IiiClient { await handler(data as P) return null } - const ref = sdk.registerFunction(id, wrapped) + // Every handler registered here is a browser-local console plumbing fn + // (traces, sessions, worktree events, ...) — none are meant for other + // workers (e.g. harness) to discover, so default them out of + // `engine::functions::list`. Callers can still override via `options`. + const ref = sdk.registerFunction(id, wrapped, { + metadata: { internal: true }, + ...options, + }) let active = true const unregister = () => { if (!active) return diff --git a/context-manager/src/configuration.rs b/context-manager/src/configuration.rs index 8e2b38206..94446d422 100644 --- a/context-manager/src/configuration.rs +++ b/context-manager/src/configuration.rs @@ -154,7 +154,8 @@ pub fn register_config_trigger( "Internal: hot-reload context-manager from the authoritative configuration when it \ changes — rebuilds the compaction lease store on a lease_dir change and swaps the \ per-call tuning snapshot otherwise.", - ), + ) + .metadata(json!({ "internal": true })), ); iii.register_trigger(RegisterTriggerInput { diff --git a/context-manager/src/functions/mod.rs b/context-manager/src/functions/mod.rs index 870b8dc1b..8f794a6a7 100644 --- a/context-manager/src/functions/mod.rs +++ b/context-manager/src/functions/mod.rs @@ -71,12 +71,15 @@ pub(crate) async fn resolve_model( } /// Register one typed handler under `id`, mapping `ContextError` into -/// the bus error shape (`code: message`). +/// the bus error shape (`code: message`). `internal` hides the function +/// from the discoverable `engine::functions::list` (trigger/config plumbing +/// stays callable by id); see harness's iii-permissions.yaml. fn register( iii: &Arc, deps: &Arc, id: &str, description: &str, + internal: bool, handler: F, ) where Req: DeserializeOwned + JsonSchema + Send + 'static, @@ -85,25 +88,28 @@ fn register( Fut: Future> + Send + 'static, { let deps = deps.clone(); - iii.register_function( - id, - RegisterFunction::new_async(move |req: Req| { - let deps = deps.clone(); - let handler = handler.clone(); - async move { handler(deps, req).await.map_err(Error::from) } - }) - .description(description), - ); + let reg = RegisterFunction::new_async(move |req: Req| { + let deps = deps.clone(); + let handler = handler.clone(); + async move { handler(deps, req).await.map_err(Error::from) } + }) + .description(description); + let reg = if internal { + reg.metadata(serde_json::json!({ "internal": true })) + } else { + reg + }; + iii.register_function(id, reg); } pub fn register_all(iii: &Arc, deps: &Arc) { - register(iii, deps, ASSEMBLE_ID, ASSEMBLE_DESC, |d, r| async move { + register(iii, deps, ASSEMBLE_ID, ASSEMBLE_DESC, true, |d, r| async move { assemble::handle(&d, r).await }); - register(iii, deps, COMPACT_ID, COMPACT_DESC, |d, r| async move { + register(iii, deps, COMPACT_ID, COMPACT_DESC, true, |d, r| async move { compact::handle(&d, r).await }); - register(iii, deps, PRUNE_ID, PRUNE_DESC, |d, r| async move { + register(iii, deps, PRUNE_ID, PRUNE_DESC, false, |d, r| async move { prune::handle(&d, r).await }); register( @@ -111,6 +117,7 @@ pub fn register_all(iii: &Arc, deps: &Arc) { deps, COUNT_TOKENS_ID, COUNT_TOKENS_DESC, + false, |d, r| async move { count_tokens::handle(&d, r).await }, ); diff --git a/harness/src/configuration.rs b/harness/src/configuration.rs index c8eb1f1e2..198212234 100644 --- a/harness/src/configuration.rs +++ b/harness/src/configuration.rs @@ -278,7 +278,8 @@ pub fn register_config_trigger( "Internal: hot-reload harness from the authoritative configuration when it changes — \ re-binds the cron pending-sweep on a sweep_expression change and swaps the per-call \ tuning snapshot otherwise.", - ), + ) + .metadata(json!({ "internal": true })), ); iii.register_trigger(RegisterTriggerInput { diff --git a/harness/src/functions/mod.rs b/harness/src/functions/mod.rs index 29cfe012e..db50e0f37 100644 --- a/harness/src/functions/mod.rs +++ b/harness/src/functions/mod.rs @@ -111,6 +111,35 @@ fn register( ); } +/// Like [`register`], but tags the registration `metadata.internal = true` so +/// the default `engine::functions::list` hides it: trusted control-plane / +/// loop plumbing, invoked by id, never meant for agent discovery (mirrors the +/// deny rules in iii-permissions.yaml). +fn register_internal( + iii: &Arc, + deps: &Arc, + id: &str, + description: &str, + handler: F, +) where + Req: DeserializeOwned + JsonSchema + Send + 'static, + Resp: Serialize + JsonSchema + Send + 'static, + F: Fn(Arc, Req) -> Fut + Send + Sync + Clone + 'static, + Fut: Future> + Send + 'static, +{ + let deps = deps.clone(); + iii.register_function( + id, + RegisterFunction::new_async(move |req: Req| { + let deps = deps.clone(); + let handler = handler.clone(); + async move { handler(deps, req).await.map_err(Error::from) } + }) + .description(description) + .metadata(serde_json::json!({ "internal": true })), + ); +} + /// Like [`register`], but the handler also receives the per-invocation /// `metadata` sidecar (`engine::register_trigger`'s `metadata`). Used by the /// trigger-bridge target `harness::react`. @@ -139,30 +168,30 @@ fn register_with_metadata( } pub fn register_all(iii: &Arc, deps: &Arc) { - register(iii, deps, SEND_ID, SEND_DESC, |d, r| async move { + register_internal(iii, deps, SEND_ID, SEND_DESC, |d, r| async move { send::handle(&d, r).await }); register(iii, deps, SPAWN_ID, SPAWN_DESC, |d, r| async move { spawn::handle(&d, r).await }); - register(iii, deps, TURN_ID, TURN_DESC, |d, r| async move { + register_internal(iii, deps, TURN_ID, TURN_DESC, |d, r| async move { turn::handle(&d, r).await }); - register( + register_internal( iii, deps, FUNCTION_TRIGGER_ID, FUNCTION_TRIGGER_DESC, |d, r| async move { function_trigger::handle(&d, r).await }, ); - register( + register_internal( iii, deps, FUNCTION_RESOLVE_ID, FUNCTION_RESOLVE_DESC, |d, r| async move { function_resolve::handle(&d, r).await }, ); - register(iii, deps, STOP_ID, STOP_DESC, |d, r| async move { + register_internal(iii, deps, STOP_ID, STOP_DESC, |d, r| async move { stop::handle(&d, r).await }); register(iii, deps, STATUS_ID, STATUS_DESC, |d, r| async move { @@ -170,10 +199,10 @@ pub fn register_all(iii: &Arc, deps: &Arc) { }); // Trusted control-plane (console) — registered, kept off the agent catalog. - register(iii, deps, UNQUEUE_ID, UNQUEUE_DESC, |d, r| async move { + register_internal(iii, deps, UNQUEUE_ID, UNQUEUE_DESC, |d, r| async move { send::unqueue(&d, r).await }); - register( + register_internal( iii, deps, EDIT_QUEUED_ID, @@ -183,28 +212,28 @@ pub fn register_all(iii: &Arc, deps: &Arc) { // Internal filesystem grant controls — registered for trusted callers, kept // off the model-facing catalog. - register( + register_internal( iii, deps, FILESYSTEM_GRANT_ID, FILESYSTEM_GRANT_DESC, |d, r| async move { filesystem::grant(&d, r).await }, ); - register( + register_internal( iii, deps, FILESYSTEM_GRANTS_ID, FILESYSTEM_GRANTS_DESC, |d, r| async move { filesystem::grants(&d, r).await }, ); - register( + register_internal( iii, deps, FILESYSTEM_REVOKE_ID, FILESYSTEM_REVOKE_DESC, |d, r| async move { filesystem::revoke(&d, r).await }, ); - register( + register_internal( iii, deps, FILESYSTEM_INFO_ID, @@ -213,7 +242,7 @@ pub fn register_all(iii: &Arc, deps: &Arc) { ); // Internal cron target — registered, but kept off the public catalog. - register( + register_internal( iii, deps, sweep_pending::SWEEP_PENDING_ID, @@ -222,7 +251,7 @@ pub fn register_all(iii: &Arc, deps: &Arc) { ); // Internal session::deleted cleanup — registered, kept off the catalog. - register( + register_internal( iii, deps, crate::subscriptions::ON_SESSION_DELETED_ID, diff --git a/harness/src/subscriptions/notify_agent.rs b/harness/src/subscriptions/notify_agent.rs index f6f6cba8b..e2d0d00da 100644 --- a/harness/src/subscriptions/notify_agent.rs +++ b/harness/src/subscriptions/notify_agent.rs @@ -95,7 +95,8 @@ pub fn register(deps: Arc) { }) .description(NOTIFY_AGENT_DESC) .request_format(schema_value::()) - .response_format(schema_value::()), + .response_format(schema_value::()) + .metadata(json!({ "internal": true })), ); } diff --git a/iii-directory/src/configuration.rs b/iii-directory/src/configuration.rs index 3db5c6ef6..302947284 100644 --- a/iii-directory/src/configuration.rs +++ b/iii-directory/src/configuration.rs @@ -161,7 +161,8 @@ pub fn register_config_trigger(iii: &IIIClient, state: SharedState) -> Result<() .description( "Internal: reload tunable iii-directory settings from the authoritative \ configuration when it changes.", - ), + ) + .metadata(json!({ "internal": true })), ); iii.register_trigger(RegisterTriggerInput { diff --git a/iii-directory/src/main.rs b/iii-directory/src/main.rs index 15d7d0c63..2dee95a11 100644 --- a/iii-directory/src/main.rs +++ b/iii-directory/src/main.rs @@ -235,7 +235,8 @@ fn setup_auto_download( Ok::<_, Error>(WorkerAddedAck { ok: true }) } }) - .description("Internal: auto-download skills on worker add event."), + .description("Internal: auto-download skills on worker add event.") + .metadata(serde_json::json!({ "internal": true })), ); // Subscribe to the `worker` trigger type with a retry backoff. diff --git a/llm-router/src/register.rs b/llm-router/src/register.rs index ee223efa9..d944dfdd1 100644 --- a/llm-router/src/register.rs +++ b/llm-router/src/register.rs @@ -35,6 +35,14 @@ use crate::surface; use crate::triggers::RouterEvents; use crate::types::errors::invalid_request_from_serde; +/// `metadata.internal = true` keeps a registration out of the default +/// `engine::functions::list`: orchestrator/provider plumbing, invoked by id. +/// Agent-discoverable reads (models::list/get/supports, provider::list) stay +/// visible. +fn internal_meta() -> Value { + json!({ "internal": true }) +} + pub struct RouterRefs { pub registry: Arc, pub catalog: Arc, @@ -81,7 +89,8 @@ pub async fn register_router(iii: IIIClient) -> Result { }, invalid_request_from_serde, ) - .description(surface::CHAT_DESC), + .description(surface::CHAT_DESC) + .metadata(internal_meta()), ); } iii.register_function( @@ -90,11 +99,14 @@ pub async fn register_router(iii: IIIClient) -> Result { make_complete(iii.clone(), pipeline.clone()), invalid_request_from_serde, ) - .description(surface::COMPLETE_DESC), + .description(surface::COMPLETE_DESC) + .metadata(internal_meta()), ); iii.register_function( surface::ABORT_ID, - RegisterFunction::new_async(make_abort(inflight.clone())).description(surface::ABORT_DESC), + RegisterFunction::new_async(make_abort(inflight.clone())) + .description(surface::ABORT_DESC) + .metadata(internal_meta()), ); iii.register_function( surface::MODELS_LIST_ID, @@ -122,7 +134,8 @@ pub async fn register_router(iii: IIIClient) -> Result { iii.clone(), registry.clone(), )) - .description(surface::SYSTEM_PROMPT_GET_DESC), + .description(surface::SYSTEM_PROMPT_GET_DESC) + .metadata(internal_meta()), ); iii.register_function( surface::ROUTE_ID, @@ -131,7 +144,8 @@ pub async fn register_router(iii: IIIClient) -> Result { catalog.clone(), settings.clone(), )) - .description(surface::ROUTE_DESC), + .description(surface::ROUTE_DESC) + .metadata(internal_meta()), ); iii.register_function( surface::PROVIDER_REGISTER_ID, @@ -145,12 +159,14 @@ pub async fn register_router(iii: IIIClient) -> Result { ), invalid_request_from_serde, ) - .description(surface::PROVIDER_REGISTER_DESC), + .description(surface::PROVIDER_REGISTER_DESC) + .metadata(internal_meta()), ); iii.register_function( surface::PROVIDER_RESOLVE_ID, RegisterFunction::new_async(make_provider_resolve(iii.clone(), registry.clone())) - .description(surface::PROVIDER_RESOLVE_DESC), + .description(surface::PROVIDER_RESOLVE_DESC) + .metadata(internal_meta()), ); iii.register_function( surface::UPDATE_CREDENTIAL_ID, @@ -159,7 +175,8 @@ pub async fn register_router(iii: IIIClient) -> Result { registry.clone(), entry_lock, )) - .description(surface::UPDATE_CREDENTIAL_DESC), + .description(surface::UPDATE_CREDENTIAL_DESC) + .metadata(internal_meta()), ); iii.register_function( surface::MODELS_RECONCILE_ID, @@ -167,7 +184,8 @@ pub async fn register_router(iii: IIIClient) -> Result { make_models_reconcile(registry.clone(), catalog.clone(), events.clone()), invalid_request_from_serde, ) - .description(surface::MODELS_RECONCILE_DESC), + .description(surface::MODELS_RECONCILE_DESC) + .metadata(internal_meta()), ); // 5. bound trigger: configuration change (paste-a-key) @@ -192,7 +210,8 @@ pub async fn register_router(iii: IIIClient) -> Result { settings.clone(), 2000, )) - .description(surface::ON_CONFIG_CHANGED_DESC), + .description(surface::ON_CONFIG_CHANGED_DESC) + .metadata(internal_meta()), ); } let _ = iii.register_trigger(RegisterTriggerInput { diff --git a/provider-anthropic/src/register.rs b/provider-anthropic/src/register.rs index d49da60d2..ca516900a 100644 --- a/provider-anthropic/src/register.rs +++ b/provider-anthropic/src/register.rs @@ -135,12 +135,14 @@ pub async fn register_provider(iii: IIIClient) -> Result<(), Error> { make_stream(iii.clone(), http.clone()), invalid_request_from_serde, ) - .description(surface::STREAM_DESC), + .description(surface::STREAM_DESC) + .metadata(json!({ "internal": true })), ); iii.register_function( surface::REFRESH_MODELS_ID, RegisterFunction::new_async(make_refresh_models(iii.clone(), http.clone())) - .description(surface::REFRESH_MODELS_DESC), + .description(surface::REFRESH_MODELS_DESC) + .metadata(json!({ "internal": true })), ); // Re-declare when the router restarts: bind to the router::ready trigger type. @@ -156,7 +158,8 @@ pub async fn register_provider(iii: IIIClient) -> Result<(), Error> { Ok::<_, Error>(ProviderReadyAck { ok: true }) } }) - .description(surface::ON_ROUTER_READY_DESC), + .description(surface::ON_ROUTER_READY_DESC) + .metadata(json!({ "internal": true })), ); } let _ = iii.register_trigger(RegisterTriggerInput { diff --git a/provider-openai-codex/src/register.rs b/provider-openai-codex/src/register.rs index f65ec833a..04262d56e 100644 --- a/provider-openai-codex/src/register.rs +++ b/provider-openai-codex/src/register.rs @@ -140,7 +140,8 @@ pub async fn register_provider(iii: IIIClient) -> Result<(), Error> { make_stream(iii.clone(), http.clone()), invalid_request_from_serde, ) - .description(surface::STREAM_DESC), + .description(surface::STREAM_DESC) + .metadata(json!({ "internal": true })), ); iii.register_function( surface::REFRESH_MODELS_ID, @@ -149,7 +150,8 @@ pub async fn register_provider(iii: IIIClient) -> Result<(), Error> { http.clone(), refresh_state.clone(), )) - .description(surface::REFRESH_MODELS_DESC), + .description(surface::REFRESH_MODELS_DESC) + .metadata(json!({ "internal": true })), ); { @@ -169,7 +171,8 @@ pub async fn register_provider(iii: IIIClient) -> Result<(), Error> { Ok::<_, Error>(ProviderReadyAck { ok: true }) } }) - .description(surface::ON_ROUTER_READY_DESC), + .description(surface::ON_ROUTER_READY_DESC) + .metadata(json!({ "internal": true })), ); } let _ = iii.register_trigger(RegisterTriggerInput { diff --git a/provider-openai/src/register.rs b/provider-openai/src/register.rs index e791ea164..b2c449d5a 100644 --- a/provider-openai/src/register.rs +++ b/provider-openai/src/register.rs @@ -133,12 +133,14 @@ pub async fn register_provider(iii: IIIClient) -> Result<(), Error> { make_stream(iii.clone(), http.clone()), invalid_request_from_serde, ) - .description(surface::STREAM_DESC), + .description(surface::STREAM_DESC) + .metadata(json!({ "internal": true })), ); iii.register_function( surface::REFRESH_MODELS_ID, RegisterFunction::new_async(make_refresh_models(iii.clone(), http.clone())) - .description(surface::REFRESH_MODELS_DESC), + .description(surface::REFRESH_MODELS_DESC) + .metadata(json!({ "internal": true })), ); // Re-declare when the router restarts: bind to the router::ready trigger type. @@ -154,7 +156,8 @@ pub async fn register_provider(iii: IIIClient) -> Result<(), Error> { Ok::<_, Error>(ProviderReadyAck { ok: true }) } }) - .description(surface::ON_ROUTER_READY_DESC), + .description(surface::ON_ROUTER_READY_DESC) + .metadata(json!({ "internal": true })), ); } let _ = iii.register_trigger(RegisterTriggerInput { diff --git a/provider-xai/src/configuration.rs b/provider-xai/src/configuration.rs index e833dc67a..609a484b0 100644 --- a/provider-xai/src/configuration.rs +++ b/provider-xai/src/configuration.rs @@ -89,7 +89,8 @@ pub fn register_config_trigger(iii: &IIIClient, cell: ConfigCell) -> Result<(), "type": "object", "properties": { "ok": { "type": "boolean" } }, })) - .description("Internal: reload provider-xai configuration when it changes."), + .description("Internal: reload provider-xai configuration when it changes.") + .metadata(json!({ "internal": true })), ); iii.register_trigger(RegisterTriggerInput { diff --git a/provider-xai/src/register.rs b/provider-xai/src/register.rs index 9cc13b9ab..932f971b5 100644 --- a/provider-xai/src/register.rs +++ b/provider-xai/src/register.rs @@ -166,12 +166,14 @@ pub async fn register_provider(iii: IIIClient) -> Result<(), Error> { make_stream(iii.clone(), http.clone(), cell.clone()), invalid_request_from_serde, ) - .description(surface::STREAM_DESC), + .description(surface::STREAM_DESC) + .metadata(json!({ "internal": true })), ); iii.register_function( surface::REFRESH_MODELS_ID, RegisterFunction::new_async(make_refresh_models(iii.clone(), http.clone())) - .description(surface::REFRESH_MODELS_DESC), + .description(surface::REFRESH_MODELS_DESC) + .metadata(json!({ "internal": true })), ); // Re-declare when the router restarts: bind to the router::ready trigger type. @@ -187,7 +189,8 @@ pub async fn register_provider(iii: IIIClient) -> Result<(), Error> { Ok::<_, Error>(ProviderReadyAck { ok: true }) } }) - .description(surface::ON_ROUTER_READY_DESC), + .description(surface::ON_ROUTER_READY_DESC) + .metadata(json!({ "internal": true })), ); } let _ = iii.register_trigger(RegisterTriggerInput { diff --git a/provider-zai/src/register.rs b/provider-zai/src/register.rs index 6f03836a9..95b8ff196 100644 --- a/provider-zai/src/register.rs +++ b/provider-zai/src/register.rs @@ -136,12 +136,14 @@ pub async fn register_provider(iii: IIIClient) -> Result<(), Error> { make_stream(iii.clone(), http.clone()), invalid_request_from_serde, ) - .description(surface::STREAM_DESC), + .description(surface::STREAM_DESC) + .metadata(json!({ "internal": true })), ); iii.register_function( surface::REFRESH_MODELS_ID, RegisterFunction::new_async(make_refresh_models(iii.clone())) - .description(surface::REFRESH_MODELS_DESC), + .description(surface::REFRESH_MODELS_DESC) + .metadata(json!({ "internal": true })), ); // Re-declare when the router restarts: bind to the router::ready trigger type. @@ -156,7 +158,8 @@ pub async fn register_provider(iii: IIIClient) -> Result<(), Error> { Ok::<_, Error>(ProviderReadyAck { ok: true }) } }) - .description(surface::ON_ROUTER_READY_DESC), + .description(surface::ON_ROUTER_READY_DESC) + .metadata(json!({ "internal": true })), ); } let _ = iii.register_trigger(RegisterTriggerInput { diff --git a/scrapling/src/guidance.py b/scrapling/src/guidance.py index 4466b9826..8613ebc8a 100644 --- a/scrapling/src/guidance.py +++ b/scrapling/src/guidance.py @@ -208,6 +208,7 @@ def setup(iii: Any) -> None: ), request_format=PRE_GENERATE_REQUEST, response_format=PRE_GENERATE_RESPONSE, + metadata={"internal": True}, ) async def on_registry_changed(_payload: Any) -> dict[str, Any]: @@ -223,6 +224,7 @@ async def on_registry_changed(_payload: Any) -> dict[str, Any]: ), request_format=REGISTRY_CHANGED_REQUEST, response_format=REGISTRY_CHANGED_RESPONSE, + metadata={"internal": True}, ) # Arm the event-driven retries BEFORE the warm-start probe, so a harness that diff --git a/session-manager/src/configuration.rs b/session-manager/src/configuration.rs index ed5007e23..138bba16e 100644 --- a/session-manager/src/configuration.rs +++ b/session-manager/src/configuration.rs @@ -351,7 +351,8 @@ pub fn register_config_trigger(iii: &IIIClient, state: AppState) -> Result<(), E "Internal: hot-reload session-manager from the authoritative configuration when it \ changes — rebuilds the storage adapter and event plumbing on an adapter change \ (replaying current state to subscribers) and swaps the list limits otherwise.", - ), + ) + .metadata(json!({ "internal": true })), ); iii.register_trigger(RegisterTriggerInput { @@ -388,7 +389,8 @@ pub fn register_config_status(iii: &IIIClient, state: AppState) { last_error, and rejected_reloads (count since boot). A rejected outcome or non-zero \ count means a stored config was refused and the active storage adapter diverged from \ the central store. Takes no arguments.", - ), + ) + .metadata(json!({ "internal": true })), ); } diff --git a/session-manager/src/functions/mod.rs b/session-manager/src/functions/mod.rs index dd9ca33a3..97f6a93e9 100644 --- a/session-manager/src/functions/mod.rs +++ b/session-manager/src/functions/mod.rs @@ -50,12 +50,15 @@ pub struct Deps { /// Register one typed handler under `id`, mapping `SessionError` into /// the bus error shape (`code: message`). Each call snapshots the live /// runtime's `service` + `sink` from [`AppState`], so handlers never capture a -/// stale adapter across a hot-reload. +/// stale adapter across a hot-reload. `internal` hides the function from the +/// discoverable `engine::functions::list` (mutating/plumbing surface stays +/// callable by id); see harness's iii-permissions.yaml. fn register( iii: &Arc, state: &AppState, id: &str, description: &str, + internal: bool, handler: F, ) where Req: DeserializeOwned + JsonSchema + Send + 'static, @@ -64,24 +67,27 @@ fn register( Fut: Future> + Send + 'static, { let state = state.clone(); - iii.register_function( - id, - RegisterFunction::new_async(move |req: Req| { - let state = state.clone(); - let handler = handler.clone(); - async move { - let deps = { - let rt = state.runtime.read().await; - Arc::new(Deps { - service: rt.service.clone(), - sink: rt.sink.clone(), - }) - }; - handler(deps, req).await.map_err(Error::from) - } - }) - .description(description), - ); + let reg = RegisterFunction::new_async(move |req: Req| { + let state = state.clone(); + let handler = handler.clone(); + async move { + let deps = { + let rt = state.runtime.read().await; + Arc::new(Deps { + service: rt.service.clone(), + sink: rt.sink.clone(), + }) + }; + handler(deps, req).await.map_err(Error::from) + } + }) + .description(description); + let reg = if internal { + reg.metadata(serde_json::json!({ "internal": true })) + } else { + reg + }; + iii.register_function(id, reg); } pub fn register_all(iii: &Arc, state: &AppState) { @@ -90,6 +96,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::create", "Create a session at status idle; fires session::created.", + true, |d, r| async move { create::handle(&d, r).await }, ); register( @@ -97,6 +104,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::ensure", "Idempotently ensure a session with a given id exists; fires session::created only when it creates.", + true, |d, r| async move { ensure::handle(&d, r).await }, ); register( @@ -104,6 +112,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::get", "Read one session's metadata (null when unknown).", + false, |d, r| async move { get::handle(&d, r).await }, ); register( @@ -111,6 +120,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::list", "List sessions with pagination, ordering, and status/metadata filters.", + false, |d, r| async move { list::handle(&d, r).await }, ); register( @@ -118,6 +128,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::set-meta", "Update a session's title/description/metadata; fires session::meta-updated.", + true, |d, r| async move { set_meta::handle(&d, r).await }, ); register( @@ -125,6 +136,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::set-status", "Set status idle/working/done/error; fires session::status-changed (no-op when unchanged).", + true, |d, r| async move { set_status::handle(&d, r).await }, ); register( @@ -132,6 +144,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::delete", "Delete a session and its entries; fires session::deleted.", + true, |d, r| async move { delete::handle(&d, r).await }, ); register( @@ -139,6 +152,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::append", "Append one entry (idempotent on entry_id); fires session::message-added.", + true, |d, r| async move { append::handle(&d, r).await }, ); register( @@ -146,6 +160,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::append-many", "Append several message entries in order; fires session::message-added per entry.", + true, |d, r| async move { append_many::handle(&d, r).await }, ); register( @@ -153,6 +168,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::update-message", "Replace a message entry's content (optimistic concurrency via expected_revision); fires session::message-updated.", + true, |d, r| async move { update_message::handle(&d, r).await }, ); register( @@ -160,6 +176,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::messages", "Load the active path as messages with entry ids, oldest first; pagination and role filtering.", + false, |d, r| async move { messages::handle(&d, r).await }, ); register( @@ -167,6 +184,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::get-message", "Read a single entry by id (null when unknown).", + false, |d, r| async move { get_message::handle(&d, r).await }, ); register( @@ -174,6 +192,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::fork", "Copy history up to an entry into a new session (copy-on-fork); fires session::created.", + true, |d, r| async move { fork::handle(&d, r).await }, ); register( @@ -181,6 +200,7 @@ pub fn register_all(iii: &Arc, state: &AppState) { state, "session::set-active-leaf", "Move the active path to end at a given entry (branch switch).", + true, |d, r| async move { set_active_leaf::handle(&d, r).await }, ); diff --git a/session-manager/src/functions/store_protocol.rs b/session-manager/src/functions/store_protocol.rs index b75cfbceb..fa336c710 100644 --- a/session-manager/src/functions/store_protocol.rs +++ b/session-manager/src/functions/store_protocol.rs @@ -138,7 +138,8 @@ pub fn register_store_protocol(iii: &Arc, state: AppState) { store.get_meta(&req.session_id).await.map_err(storage_err) } }) - .description("Internal store protocol: read one SessionMeta (null when unknown)."), + .description("Internal store protocol: read one SessionMeta (null when unknown).") + .metadata(serde_json::json!({ "internal": true })), ); let st = state.clone(); @@ -152,7 +153,8 @@ pub fn register_store_protocol(iii: &Arc, state: AppState) { Ok::<_, Error>(OkResponse { ok: true }) } }) - .description("Internal store protocol: write one SessionMeta."), + .description("Internal store protocol: write one SessionMeta.") + .metadata(serde_json::json!({ "internal": true })), ); let st = state.clone(); @@ -169,7 +171,8 @@ pub fn register_store_protocol(iii: &Arc, state: AppState) { Ok::<_, Error>(OkResponse { ok: true }) } }) - .description("Internal store protocol: delete one SessionMeta."), + .description("Internal store protocol: delete one SessionMeta.") + .metadata(serde_json::json!({ "internal": true })), ); let st = state.clone(); @@ -183,7 +186,8 @@ pub fn register_store_protocol(iii: &Arc, state: AppState) { Ok::<_, Error>(ListMetasResponse { metas }) } }) - .description("Internal store protocol: list every SessionMeta."), + .description("Internal store protocol: list every SessionMeta.") + .metadata(serde_json::json!({ "internal": true })), ); let st = state.clone(); @@ -199,7 +203,8 @@ pub fn register_store_protocol(iii: &Arc, state: AppState) { .map_err(storage_err) } }) - .description("Internal store protocol: read one SessionEntry (null when unknown)."), + .description("Internal store protocol: read one SessionEntry (null when unknown).") + .metadata(serde_json::json!({ "internal": true })), ); let st = state.clone(); @@ -216,7 +221,8 @@ pub fn register_store_protocol(iii: &Arc, state: AppState) { Ok::<_, Error>(OkResponse { ok: true }) } }) - .description("Internal store protocol: write one SessionEntry."), + .description("Internal store protocol: write one SessionEntry.") + .metadata(serde_json::json!({ "internal": true })), ); let st = state.clone(); @@ -233,7 +239,8 @@ pub fn register_store_protocol(iii: &Arc, state: AppState) { Ok::<_, Error>(ListEntriesResponse { entries }) } }) - .description("Internal store protocol: list every entry of a session."), + .description("Internal store protocol: list every entry of a session.") + .metadata(serde_json::json!({ "internal": true })), ); let st = state.clone(); @@ -250,7 +257,8 @@ pub fn register_store_protocol(iii: &Arc, state: AppState) { Ok::<_, Error>(OkResponse { ok: true }) } }) - .description("Internal store protocol: delete every entry of a session."), + .description("Internal store protocol: delete every entry of a session.") + .metadata(serde_json::json!({ "internal": true })), ); let st = state.clone(); @@ -267,7 +275,8 @@ pub fn register_store_protocol(iii: &Arc, state: AppState) { Ok::<_, Error>(ActiveLeafResponse { entry_id }) } }) - .description("Internal store protocol: read a session's active leaf pointer."), + .description("Internal store protocol: read a session's active leaf pointer.") + .metadata(serde_json::json!({ "internal": true })), ); let st = state.clone(); @@ -284,7 +293,8 @@ pub fn register_store_protocol(iii: &Arc, state: AppState) { Ok::<_, Error>(OkResponse { ok: true }) } }) - .description("Internal store protocol: move a session's active leaf pointer."), + .description("Internal store protocol: move a session's active leaf pointer.") + .metadata(serde_json::json!({ "internal": true })), ); let st = state.clone(); @@ -301,7 +311,8 @@ pub fn register_store_protocol(iii: &Arc, state: AppState) { Ok::<_, Error>(OkResponse { ok: true }) } }) - .description("Internal store protocol: clear a session's active leaf pointer."), + .description("Internal store protocol: clear a session's active leaf pointer.") + .metadata(serde_json::json!({ "internal": true })), ); let st = state.clone(); @@ -318,7 +329,8 @@ pub fn register_store_protocol(iii: &Arc, state: AppState) { .description( "Internal store protocol: ingest a bridged instance's event envelopes and fan them \ out to local subscribers and every attached bridge.", - ), + ) + .metadata(serde_json::json!({ "internal": true })), ); tracing::info!("session::store::* protocol registered (12 functions)"); diff --git a/shell/src/configuration.rs b/shell/src/configuration.rs index 8cba42037..7a77dd91d 100644 --- a/shell/src/configuration.rs +++ b/shell/src/configuration.rs @@ -336,7 +336,8 @@ pub fn register_config_trigger(iii: &IIIClient, state: AppState) -> Result<(), E Ok::(OnConfigChangeResponse { ok: true }) } }) - .description("Internal: reload the security policy + fs backend on configuration change."), + .description("Internal: reload the security policy + fs backend on configuration change.") + .metadata(json!({ "internal": true })), ); iii.register_trigger(RegisterTriggerInput { diff --git a/shell/src/main.rs b/shell/src/main.rs index f66c17441..0da4f89f4 100644 --- a/shell/src/main.rs +++ b/shell/src/main.rs @@ -401,7 +401,8 @@ async fn main() -> Result<()> { boot). A rejected outcome or non-zero count means a stored config \ was refused and shell is enforcing an older policy than the central \ store. Takes no arguments.", - ), + ) + .metadata(serde_json::json!({ "internal": true })), ); } diff --git a/web/src/configuration.rs b/web/src/configuration.rs index 371388513..9ae44c846 100644 --- a/web/src/configuration.rs +++ b/web/src/configuration.rs @@ -159,7 +159,8 @@ pub async fn setup_harness_hooks(iii: &Arc) { trigger type. Not called directly.", ) .request_format(registry_changed_request_schema()) - .response_format(registry_changed_response_schema()), + .response_format(registry_changed_response_schema()) + .metadata(json!({ "internal": true })), ); // Arm the event-driven retries BEFORE the initial probe, so a harness that comes up @@ -275,7 +276,8 @@ pub fn register_config_trigger(iii: &IIIClient, state: SharedState) -> Result<() }) .description( "Internal: reload web settings from the authoritative configuration on change.", - ), + ) + .metadata(json!({ "internal": true })), ); iii.register_trigger(RegisterTriggerInput { diff --git a/web/src/functions/mod.rs b/web/src/functions/mod.rs index 511a1440b..fe4154f25 100644 --- a/web/src/functions/mod.rs +++ b/web/src/functions/mod.rs @@ -17,6 +17,7 @@ pub fn register_all(iii: &Arc, shared: &SharedConfig) { RegisterFunction::new_async(move |event: inject_guidance::PreGenerateEvent| async move { inject_guidance::handle(event).await }) - .description(inject_guidance::GUIDANCE_HOOK_DESC), + .description(inject_guidance::GUIDANCE_HOOK_DESC) + .metadata(serde_json::json!({ "internal": true })), ); } From c0e48d0242317d282d0e47fb1ee772f6ebc190b2 Mon Sep 17 00:00:00 2001 From: Anderson Leal Date: Fri, 10 Jul 2026 18:34:42 -0300 Subject: [PATCH 2/2] (MOT-3962) fmt: cargo fmt console and context-manager --- console/src/proxy.rs | 5 +---- context-manager/src/functions/mod.rs | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/console/src/proxy.rs b/console/src/proxy.rs index 616c243d6..539bbcc64 100644 --- a/console/src/proxy.rs +++ b/console/src/proxy.rs @@ -137,10 +137,7 @@ pub(crate) fn stamp_internal_registration(text: &str) -> Option { // Unexpected metadata shape — don't rewrite what we don't understand. Some(_) => return None, None => { - obj.insert( - "metadata".into(), - serde_json::json!({ "internal": true }), - ); + obj.insert("metadata".into(), serde_json::json!({ "internal": true })); } } serde_json::to_string(&msg).ok() diff --git a/context-manager/src/functions/mod.rs b/context-manager/src/functions/mod.rs index 8f794a6a7..a905bcb4c 100644 --- a/context-manager/src/functions/mod.rs +++ b/context-manager/src/functions/mod.rs @@ -103,12 +103,22 @@ fn register( } pub fn register_all(iii: &Arc, deps: &Arc) { - register(iii, deps, ASSEMBLE_ID, ASSEMBLE_DESC, true, |d, r| async move { - assemble::handle(&d, r).await - }); - register(iii, deps, COMPACT_ID, COMPACT_DESC, true, |d, r| async move { - compact::handle(&d, r).await - }); + register( + iii, + deps, + ASSEMBLE_ID, + ASSEMBLE_DESC, + true, + |d, r| async move { assemble::handle(&d, r).await }, + ); + register( + iii, + deps, + COMPACT_ID, + COMPACT_DESC, + true, + |d, r| async move { compact::handle(&d, r).await }, + ); register(iii, deps, PRUNE_ID, PRUNE_DESC, false, |d, r| async move { prune::handle(&d, r).await });