diff --git a/core/archipelago/src/api/rpc/content.rs b/core/archipelago/src/api/rpc/content.rs index eb36b875..6eacf538 100644 --- a/core/archipelago/src/api/rpc/content.rs +++ b/core/archipelago/src/api/rpc/content.rs @@ -1223,6 +1223,11 @@ impl RpcHandler { "synopsis": p.synopsis.clone().unwrap_or_default(), "poster": p.poster.clone().unwrap_or_default(), "year": p.year_num(), + // Films are video by definition. The UI adapter buckets + // purely on mime/extension, so an item carrying neither + // silently classified 'excluded' and this scope's + // surface could never render a card. + "mime_type": "video/mp4", })) }) .collect(); diff --git a/core/archipelago/src/assistant/tools.rs b/core/archipelago/src/assistant/tools.rs index ff2918a5..5a99dbf5 100644 --- a/core/archipelago/src/assistant/tools.rs +++ b/core/archipelago/src/assistant/tools.rs @@ -747,6 +747,14 @@ pub async fn dispatch(name: &str, args: &ToolArgs, handler: &RpcHandler) -> Resu "apps_list" => handler .assistant_dispatch_tool("container-list", None) .await + // `container-list` answers a bare array, but surface consumers + // read `{ items: [...] }` — a bare array is silently dropped by + // the broker and the apps grid never renders. Wrap here, at the + // tool boundary, so the shared RPC's own shape is untouched. + .map(|v| match v { + serde_json::Value::Array(_) => json!({ "items": v }), + other => other, + }) .map_err(|e| format!("tool execution failed: {e}")), "app_logs" => { let ToolArgs::AppLogs(a) = args else {