Expose model settings in app-server thread metadata (#42151)

## What changed

- Add nullable `model` and `reasoningEffort` fields to the shared app-server `Thread` object and generated schemas.
- Report current settings for loaded threads and the latest persisted settings for unloaded threads across thread read, list, start, resume, rollback, metadata update, and notification paths.
- Keep unavailable legacy or filesystem-only settings nullable, and allow metadata reads without loading a thread or dispatching queued work.

## Testing

- Cover live-setting precedence, persisted settings after restart, null legacy values, and model metadata returned by thread lifecycle operations.

GitOrigin-RevId: 22ebe8a8d1910a820d90a97730d812a00d8c1372
This commit is contained in:
Brent Traut authored and copyberry committed 2026-09-01 22:56:18 +00:00
1 parent 6b59cefcbb
commit 986ff1cc7c
50 files changed
+633 -33

No files matched your search

@@ -1991,6 +1991,8 @@ impl ThreadRequestProcessor {
);
if let Ok(loaded_thread) = self.thread_manager.get_thread(thread_uuid).await {
thread.session_id = loaded_thread.session_configured().session_id.to_string();
let config_snapshot = loaded_thread.config_snapshot().await;
apply_live_model_settings(&mut thread, &config_snapshot);
}
self.attach_thread_name(thread_uuid, &mut thread).await;
thread.status = resolve_thread_status(
@@ -2981,6 +2983,7 @@ impl ThreadRequestProcessor {
} else {
fallback_thread
};
apply_live_model_settings(&mut thread, &config_snapshot);
self.apply_thread_read_store_fields(thread_id, &mut thread, include_turns, loaded_thread)
.await?;
Ok(thread)
@@ -4279,6 +4282,7 @@ impl ThreadRequestProcessor {
);
thread_summary.session_id = existing_thread.session_configured().session_id.to_string();
thread_summary.thread_source = config_snapshot.thread_source.clone().map(Into::into);
apply_live_model_settings(&mut thread_summary, &config_snapshot);
thread_summary.can_accept_direct_input = Some(can_accept_direct_input(
existing_thread.multi_agent_version(),
&config_snapshot.session_source,
@@ -4643,6 +4647,7 @@ impl ThreadRequestProcessor {
)),
};
let mut thread = thread?;
apply_live_model_settings(&mut thread, &config_snapshot);
thread.can_accept_direct_input = Some(can_accept_direct_input);
thread.id = thread_id.to_string();
thread.session_id = session_id;
@@ -5140,6 +5145,7 @@ impl ThreadRequestProcessor {
));
thread.session_id = session_configured.session_id.to_string();
thread.thread_source = config_snapshot.thread_source.clone().map(Into::into);
apply_live_model_settings(&mut thread, &config_snapshot);
if thread.path.is_none() {
thread.project_id = inherited_project_id.clone();
}
@@ -5926,6 +5932,8 @@ pub(crate) fn thread_from_stored_thread(
} else {
thread.model_provider
},
model: thread.model,
reasoning_effort: thread.reasoning_effort,
created_at: thread.created_at.timestamp(),
updated_at: thread.updated_at.timestamp(),
recency_at: Some(thread.recency_at.timestamp()),
@@ -6097,6 +6105,8 @@ fn build_thread_from_snapshot(
project_id: None,
history_mode: config_snapshot.history_mode.into(),
model_provider: config_snapshot.model_provider_id.clone(),
model: Some(config_snapshot.model.clone()),
reasoning_effort: config_snapshot.reasoning_effort.clone(),
created_at: now,
updated_at: now,
recency_at: Some(now),