Shorten provider stalls and fix selection copy

This commit is contained in:
Ryan Ward
2026-08-26 11:31:53 -05:00
parent c25e823e56
commit dde129b9c7
4 changed files with 30 additions and 20 deletions
+1 -1
View File
@@ -134,7 +134,7 @@ context_size = 128000
Key invariants: Key invariants:
- Every direct-provider `AgentRuntime::start_turn` performs exactly one model call; only `ProviderRun` may schedule another turn or retry - Every direct-provider `AgentRuntime::start_turn` performs exactly one model call; only `ProviderRun` may schedule another turn or retry
- Direct-provider model calls allow 120 seconds for stream startup and 300 seconds between stream events; either timeout is a recoverable transport failure that enters the existing bounded retry lifecycle with the same work identity - Direct-provider model calls allow 120 seconds for stream startup and 90 seconds between stream events; either timeout is a recoverable transport failure that enters the existing bounded retry lifecycle with the same work identity
- Direct-provider remote telemetry records requested, started, retry-scheduled, and finished model-turn phases with explicit `llm_finished` state; root `provider_run_finished` records distinguish clean completion from failure or cancellation and mark the response stream terminal - Direct-provider remote telemetry records requested, started, retry-scheduled, and finished model-turn phases with explicit `llm_finished` state; root `provider_run_finished` records distinguish clean completion from failure or cancellation and mark the response stream terminal
- `use_rig` and provider selection may choose request/transport details but must never choose lifecycle ownership - `use_rig` and provider selection may choose request/transport details but must never choose lifecycle ownership
- Direct-provider output may be projected through `ResponseStream`, but provider progress must not depend on response-stream result draining or `AfterStreamFinished` - Direct-provider output may be projected through `ResponseStream`, but provider progress must not depend on response-stream result draining or `AfterStreamFinished`
+9 -1
View File
@@ -5287,9 +5287,18 @@ impl AIBlock {
/// There **shouldn't** be more than one instance of selected text at any given time across /// There **shouldn't** be more than one instance of selected text at any given time across
/// any view within the same `AIBlock` view sub-hierarchy. /// any view within the same `AIBlock` view sub-hierarchy.
pub fn selected_text(&self, ctx: &AppContext) -> Option<String> { pub fn selected_text(&self, ctx: &AppContext) -> Option<String> {
// A completed block-level drag is the newest selection whenever it is present. Prefer it
// over stale nested selections that could not be cleared while their SelectableArea was
// still mid-drag; otherwise copy can return an older single-word child selection.
self.selected_text
.read()
.clone()
.filter(|selection| !selection.is_empty())
.or_else(|| {
self.code_editor_views self.code_editor_views
.iter() .iter()
.find_map(|editor_view| editor_view.view.as_ref(ctx).selected_text(ctx)) .find_map(|editor_view| editor_view.view.as_ref(ctx).selected_text(ctx))
})
.or_else(|| { .or_else(|| {
self.requested_commands self.requested_commands
.values() .values()
@@ -5315,7 +5324,6 @@ impl AIBlock {
.values() .values()
.find_map(|comment| comment.rich_text_editor.as_ref(ctx).selected_text(ctx)) .find_map(|comment| comment.rich_text_editor.as_ref(ctx).selected_text(ctx))
}) })
.or_else(|| self.selected_text.read().clone())
.filter(|selection| !selection.is_empty()) .filter(|selection| !selection.is_empty())
} }
@@ -24,7 +24,7 @@ use crate::ai::model_output_logging;
pub(crate) const BASE_PROVIDER_PROFILE: &str = "base"; pub(crate) const BASE_PROVIDER_PROFILE: &str = "base";
pub(crate) const CLI_MONITOR_PROVIDER_PROFILE: &str = "cli-monitor"; pub(crate) const CLI_MONITOR_PROVIDER_PROFILE: &str = "cli-monitor";
const PROVIDER_MODEL_START_TIMEOUT: Duration = Duration::from_secs(120); const PROVIDER_MODEL_START_TIMEOUT: Duration = Duration::from_secs(120);
const PROVIDER_MODEL_EVENT_IDLE_TIMEOUT: Duration = Duration::from_secs(300); const PROVIDER_MODEL_EVENT_IDLE_TIMEOUT: Duration = Duration::from_secs(90);
const PROVIDER_MODEL_RETRY_DELAYS: [Duration; 3] = [ const PROVIDER_MODEL_RETRY_DELAYS: [Duration; 3] = [
Duration::from_secs(1), Duration::from_secs(1),
Duration::from_secs(3), Duration::from_secs(3),
+16 -14
View File
@@ -16601,7 +16601,22 @@ impl TerminalView {
} }
fn copy(&mut self, ctx: &mut ViewContext<Self>) { fn copy(&mut self, ctx: &mut ViewContext<Self>) {
// First check if there's selected text in the CLI subagent views // Prefer the terminal model's active selection. Nested CLI views can retain stale text
// after focus moves, which otherwise makes copy return an older single-word selection.
let semantic_selection = SemanticSelection::as_ref(ctx);
if let Some(selected) = self.model.lock().selection_to_string(
semantic_selection,
self.is_inverted_blocklist(ctx),
ctx,
) {
if !selected.is_empty() {
ctx.clipboard()
.write(ClipboardContent::plain_text(selected));
}
return;
}
// Then check if there's selected text in the CLI subagent views.
for subagent_view in self.cli_subagent_views.values() { for subagent_view in self.cli_subagent_views.values() {
if let Some(selected_text) = subagent_view.as_ref(ctx).selected_text(ctx) { if let Some(selected_text) = subagent_view.as_ref(ctx).selected_text(ctx) {
ctx.clipboard() ctx.clipboard()
@@ -16622,19 +16637,6 @@ impl TerminalView {
} }
} }
let semantic_selection = SemanticSelection::as_ref(ctx);
if let Some(selected) = self.model.lock().selection_to_string(
semantic_selection,
self.is_inverted_blocklist(ctx),
ctx,
) {
if !selected.is_empty() {
ctx.clipboard()
.write(ClipboardContent::plain_text(selected));
}
return;
}
// Prioritize selected text in the input over selected blocks (APP-4330): // Prioritize selected text in the input over selected blocks (APP-4330):
// it's possible to have both a block and input text selected at the same // it's possible to have both a block and input text selected at the same
// time, and in that case the user almost always means to copy the input. // time, and in that case the user almost always means to copy the input.