feat(quick-pane): add follow-up chat renewal
This commit is contained in:
@@ -46,7 +46,6 @@ pub struct QuickPaneSettings {
|
||||
pub follow_up_provider: String,
|
||||
pub follow_up_model: String,
|
||||
pub instructions: String,
|
||||
pub maximum_seconds: u32,
|
||||
pub maximum_tool_calls: u32,
|
||||
}
|
||||
|
||||
@@ -58,8 +57,7 @@ impl Default for QuickPaneSettings {
|
||||
model: String::new(),
|
||||
follow_up_provider: String::new(),
|
||||
follow_up_model: String::new(),
|
||||
instructions: "Answer quickly. Do not use subagents. Prefer read-only inspection. Escalate mutations, multi-step work, or work likely to exceed budget.".to_owned(),
|
||||
maximum_seconds: 60,
|
||||
instructions: "Answer quickly. Do not use subagents. Prefer read-only inspection. Escalate mutations, multi-step work, or complex work.".to_owned(),
|
||||
maximum_tool_calls: 6,
|
||||
}
|
||||
}
|
||||
@@ -232,9 +230,8 @@ pub fn validate(state: &UiStateV1) -> Result<(), String> {
|
||||
if quick.instructions.is_empty() || quick.instructions.len() > 4096 {
|
||||
return Err("Quick-pane instructions must contain 1 to 4096 bytes".to_owned());
|
||||
}
|
||||
if !(1..=600).contains(&quick.maximum_seconds) || !(1..=64).contains(&quick.maximum_tool_calls)
|
||||
{
|
||||
return Err("Quick-pane limits are outside the supported range".to_owned());
|
||||
if !(1..=64).contains(&quick.maximum_tool_calls) {
|
||||
return Err("Quick-pane tool-call limit is outside the supported range".to_owned());
|
||||
}
|
||||
total_string_bytes = total_string_bytes
|
||||
.saturating_add(quick.workspace.len())
|
||||
@@ -281,7 +278,16 @@ pub fn load_from(app_data_dir: &Path) -> Result<UiStateV1, String> {
|
||||
if content.len() > MAX_FILE_BYTES {
|
||||
return Err("UI state file exceeds the size limit".to_owned());
|
||||
}
|
||||
let state: UiStateV1 = serde_json::from_slice(&content)
|
||||
let mut value: serde_json::Value = serde_json::from_slice(&content)
|
||||
.map_err(|error| format!("UI state is corrupt or unsupported: {error}"))?;
|
||||
// Read legacy persisted cap once, but never retain or serialize it again.
|
||||
if let Some(quick_pane) = value
|
||||
.get_mut("quickPane")
|
||||
.and_then(serde_json::Value::as_object_mut)
|
||||
{
|
||||
quick_pane.remove("maximumSeconds");
|
||||
}
|
||||
let state: UiStateV1 = serde_json::from_value(value)
|
||||
.map_err(|error| format!("UI state is corrupt or unsupported: {error}"))?;
|
||||
validate(&state)?;
|
||||
Ok(state)
|
||||
@@ -443,11 +449,27 @@ mod tests {
|
||||
state.quick_pane.follow_up_provider = "provider".into();
|
||||
state.quick_pane.follow_up_model = "follow-up-model".into();
|
||||
assert!(validate(&state).is_ok());
|
||||
state.quick_pane.maximum_seconds = 0;
|
||||
state.quick_pane.maximum_tool_calls = 0;
|
||||
assert!(validate(&state).is_err());
|
||||
fs::remove_dir_all(root).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_maximum_seconds_loads_but_is_not_serialized() {
|
||||
let root = temp_dir("quick-pane-legacy-seconds");
|
||||
fs::create_dir_all(&root).unwrap();
|
||||
let path = state_path(&root);
|
||||
fs::write(
|
||||
&path,
|
||||
r#"{"version":1,"quickPane":{"workspace":"","provider":"","model":"","followUpProvider":"","followUpModel":"","instructions":"valid","maximumSeconds":60,"maximumToolCalls":6}}"#,
|
||||
)
|
||||
.unwrap();
|
||||
let state = load_from(&root).unwrap();
|
||||
save_to(&root, &state).unwrap();
|
||||
assert!(!fs::read_to_string(&path).unwrap().contains("maximumSeconds"));
|
||||
fs::remove_dir_all(root).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn second_save_replaces_valid_state_without_leaving_temporary_files() {
|
||||
let root = temp_dir("replace");
|
||||
|
||||
Reference in New Issue
Block a user