Add an API for reading installed app runtime state (#33843)

## What changed

- Add `app/installed` to return each connector observed in the committed runtime tool snapshot, including its runtime name and effective `enabled` and `callable` state.
- Support evaluating thread-specific configuration with `threadId` and refreshing the hosted connector tool snapshot with `forceRefresh`.
- Preserve observed connector identities as disabled when global or workspace policy disables Apps, and retain the previous snapshot when a refresh fails.

## Testing

- Cover cached and forced reads, policy and configuration filtering, thread-specific configuration, snapshot refresh failures, and protocol serialization.

GitOrigin-RevId: f697b6fb501b7d329a169e947a1c1607806222fe
This commit is contained in:
Matthew Zeng authored and copyberry committed 2026-07-17 15:23:35 +00:00
1 parent 761d504c1a
commit a238b753af
26 files changed
+1518 -2

No files matched your search

@@ -745,6 +745,11 @@ client_request_definitions! {
serialization: None,
response: v2::AppsListResponse,
},
AppsInstalled => "app/installed" {
params: v2::AppsInstalledParams,
serialization: None,
response: v2::AppsInstalledResponse,
},
// File system requests are intentionally concurrent. Desktop already treats local
// file system operations as concurrent, and app-server remote fs mirrors that model.
FsReadFile => "fs/readFile" {
@@ -3109,6 +3114,69 @@ mod tests {
Ok(())
}
#[test]
fn serialize_installed_apps() -> Result<()> {
let request = ClientRequest::AppsInstalled {
request_id: RequestId::Integer(9),
params: v2::AppsInstalledParams::default(),
};
assert_eq!(
json!({
"method": "app/installed",
"id": 9,
"params": {
"threadId": null
}
}),
serde_json::to_value(&request)?,
);
let force_refresh_request = ClientRequest::AppsInstalled {
request_id: RequestId::Integer(10),
params: v2::AppsInstalledParams {
thread_id: Some("thread-1".to_string()),
force_refresh: true,
},
};
assert_eq!(
json!({
"method": "app/installed",
"id": 10,
"params": {
"threadId": "thread-1",
"forceRefresh": true
}
}),
serde_json::to_value(&force_refresh_request)?,
);
Ok(())
}
#[test]
fn serialize_installed_apps_response() -> Result<()> {
let response = v2::AppsInstalledResponse {
apps: vec![v2::InstalledApp {
id: "demo-app".to_string(),
runtime_name: Some("Demo App".to_string()),
enabled: false,
callable: false,
}],
};
assert_eq!(
json!({
"apps": [{
"id": "demo-app",
"runtimeName": "Demo App",
"enabled": false,
"callable": false
}]
}),
serde_json::to_value(response)?,
);
Ok(())
}
#[test]
fn serialize_read_apps() -> Result<()> {
let request = ClientRequest::AppsRead {