Expose thread originators through the app-server API (#42458)

## What changed

- Add the creation-time `originator` to app-server thread responses and `thread/started` notifications.
- Persist originators in thread metadata and preserve the first recorded value across list, read, resume, rollout, and SQLite paths.
- Add an `originators` allowlist to `thread/list` for hosted backends. The local app-server accepts omitted or empty values but rejects nonempty filters.

## Testing

- Cover originator persistence across server restarts and list, read, and resume requests.
- Verify local `thread/list` handling for nonempty, omitted, null, and empty originator filters.
- Heap-allocate large TUI dispatcher futures in affected tests to keep them within the Windows test-thread stack.

GitOrigin-RevId: 73ad6e61b8fdd2d93a22d1f971723a19ec7be3fc
This commit is contained in:
Can Sar authored and copyberry committed 2026-09-03 06:02:25 +00:00
1 parent 8ff74cc9b1
commit 728cb12fe5
75 files changed
+511 -12

No files matched your search

@@ -2513,6 +2513,7 @@ impl ThreadRequestProcessor {
sort_direction,
model_providers,
source_kinds,
originators,
archived,
section_id,
project_id,
@@ -2522,6 +2523,14 @@ impl ThreadRequestProcessor {
parent_thread_id,
ancestor_thread_id,
} = params;
if originators
.as_ref()
.is_some_and(|values| !values.is_empty())
{
return Err(invalid_params(
"originator filtering is not supported by the local app-server",
));
}
if project_id.is_some() && !self.thread_store.supports_projects() {
return Err(unsupported_thread_store_operation("projects"));
}
@@ -5948,6 +5957,7 @@ pub(crate) fn thread_from_stored_thread(
path,
cwd,
cli_version: thread.cli_version,
originator: thread.originator,
agent_nickname: source.get_nickname(),
agent_role: source.get_agent_role(),
source: source.into(),
@@ -6128,6 +6138,8 @@ fn build_thread_from_snapshot(
path,
cwd: config_snapshot.cwd().clone(),
cli_version: env!("CARGO_PKG_VERSION").to_string(),
originator: (!config_snapshot.originator.is_empty())
.then(|| config_snapshot.originator.clone()),
agent_nickname: config_snapshot.session_source.get_nickname(),
agent_role: config_snapshot.session_source.get_agent_role(),
source: config_snapshot.session_source.clone().into(),