Skip to content

Commit f99ee6d

Browse files
authored
refactor(ai_assistant): retire the Familiar agent panel (DRAFT — needs focus dogfood) (#218)
* refactor(ai_assistant): extract UI-free dialogue types Move TranscriptPart and its supporting AI-dialogue data types (FormattedTranscriptMessage, AssistantTranscriptPart, MarkdownSegment, CodeBlockIndex, TranscriptPartSubType, CodeBlockMouseStateHandles, markdown_segments_from_text) out of the Familiar panel's utils/transcript UI knot into a new UI-free module, ai_assistant::dialogue_types. This lets server_api/ai.rs and ai_assistant::requests depend on the dialogue data layer without pulling in the AIAssistantPanelView, which is being retired. utils re-exports the types for the still-present panel UI. Tests move to dialogue_types_tests.rs. * refactor(workspace): unwire the Familiar panel from the workspace Remove the AIAssistantPanelView wiring from the workspace ahead of deleting the panel itself: the ToggleAIAssistant/ClickedAIAssistantIcon actions and their warm-welcome siblings, the Familiar EditableBinding (keeping the NewPaneInAgentMode binding on the shared workspace:toggle_ai_assistant id), the panel::init call, and every ai_assistant_panel field, event handler, focus/state site, the legacy tab-bar entry-point button, and the warm-welcome onboarding popup. The panel is now treated as permanently closed; the AskAIType flow is preserved (Agent Mode path is unaffected) and ask_ai_assistant is a no-op for the retired legacy path. WorkspaceState::is_ai_assistant_panel_open is removed. * refactor(ai_assistant): delete the Familiar panel UI knot Delete the AIAssistantPanelView (panel.rs), the Transcript view (transcript.rs) and its tests, the orphaned coven_stream_persist.rs, and the now-orphaned utils.rs (its UI-free dialogue types already moved to dialogue_types; its render_* helpers and AIAssistantAction were panel-only). Drop the panel/transcript/coven_stream_persist/utils module declarations. Gate the now-unused OPENCOVEN_SUCCESS/OPENCOVEN_WARNING brand colours (previously the panel's Coven Gateway status pills) with allow(dead_code), matching OPENCOVEN_MUTED. * test: drop Familiar panel tests and fixtures Remove the ai_assistant_panel_view() integration getter and the Familiar panel integration test (test_ask_warp_ai_keybinding_for_selected_block, its module, registration, and nextest wrapper), the Familiar focus-panel assertions in workspace view_tests, and the panel.rs source-include from the CastCodes public-surface rebrand guard (the panel file is deleted). * style: apply cargo fmt after Familiar panel retirement * test(agent_panel): port the fork-local Coven guards onto the unified panel
1 parent 7e104bd commit f99ee6d

23 files changed

Lines changed: 82 additions & 4240 deletions

app/src/ai/coven_brand.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub(crate) const OPENCOVEN_PURPLE: ColorU = ColorU {
99
};
1010

1111
/// Brand success colour (`#22C55E`) — used for the Coven Gateway "online" pill.
12+
#[allow(dead_code)]
1213
pub(crate) const OPENCOVEN_SUCCESS: ColorU = ColorU {
1314
r: 34,
1415
g: 197,
@@ -17,6 +18,7 @@ pub(crate) const OPENCOVEN_SUCCESS: ColorU = ColorU {
1718
};
1819

1920
/// Brand warning colour (`#F59E0B`) — used for the Coven Gateway "degraded" pill.
21+
#[allow(dead_code)]
2022
pub(crate) const OPENCOVEN_WARNING: ColorU = ColorU {
2123
r: 245,
2224
g: 158,

app/src/ai_assistant/coven_stream_persist.rs

Lines changed: 0 additions & 98 deletions
This file was deleted.
Lines changed: 22 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,11 @@
1-
/// Common functionality used across different AI Assistant components.
1+
//! UI-free AI-dialogue data types shared by the server API and auth layers.
2+
//!
3+
//! These types describe the question/answer transcript structure used by the
4+
//! legacy hosted-AI dialogue path. They were extracted out of the Familiar
5+
//! panel's `utils`/`transcript` UI knot so that `server_api`/`auth` no longer
6+
//! depend on the (now-retired) panel view.
27
use markdown_parser::{parse_markdown, CodeBlockText, FormattedText, FormattedTextLine};
3-
use pathfinder_color::ColorU;
4-
use warpui::{
5-
elements::{
6-
ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Flex, HighlightedHyperlink,
7-
Icon, MainAxisAlignment, MainAxisSize, MouseStateHandle, ParentElement, Radius, Text,
8-
},
9-
platform::Cursor,
10-
ui_components::{
11-
button::ButtonVariant,
12-
components::{Coords, UiComponent, UiComponentStyles},
13-
},
14-
AppContext, Element, ModelHandle,
15-
};
16-
17-
use crate::{appearance::Appearance, ui_components::blended_colors};
18-
19-
use super::{panel::AIAssistantAction, requests::Requests, transcript::CodeBlockMouseStateHandles};
20-
21-
const PREPARED_RESPONSE_FONT_SIZE: f32 = 11.;
22-
const REQUEST_LIMIT_INFO_FONT_SIZE: f32 = 11.;
23-
24-
const SQUARE_ALERT_SVG_PATH: &str = "bundled/svg/alert-square.svg";
25-
const TRIANGLE_ALERT_SVG_PATH: &str = "bundled/svg/alert-triangle.svg";
8+
use warpui::elements::{HighlightedHyperlink, MouseStateHandle};
269

2710
/// A transcript part is a question and answer _pair_. This is to enforce
2811
/// the invariant that every question has an answer.
@@ -106,6 +89,19 @@ impl FormattedTranscriptMessage {
10689
}
10790
}
10891

92+
/// The mouse-state handles needed to render a single code block. Kept as a
93+
/// UI-free leaf type here (a bundle of `warpui` handles) because
94+
/// `MarkdownSegment::CodeBlock` embeds it.
95+
#[derive(Debug, Clone, Default)]
96+
pub struct CodeBlockMouseStateHandles {
97+
pub play_button: MouseStateHandle,
98+
pub play_button_tooltip: MouseStateHandle,
99+
pub copy_button: MouseStateHandle,
100+
pub copy_button_tooltip: MouseStateHandle,
101+
pub save_as_workflow_button: MouseStateHandle,
102+
pub save_as_workflow_button_tooltip: MouseStateHandle,
103+
}
104+
109105
/// A MarkdownSegment differs from a FormattedText in that we intentionally
110106
/// separate out certain markdown elements.
111107
/// For now, only code blocks are rendered differently.
@@ -257,146 +253,6 @@ impl CodeBlockIndex {
257253
}
258254
}
259255

260-
pub fn render_prepared_response_button(
261-
appearance: &Appearance,
262-
mouse_state_handle: MouseStateHandle,
263-
width: Option<f32>,
264-
right_left_padding: Option<f32>,
265-
prompt: &'static str,
266-
) -> Box<dyn Element> {
267-
let theme = appearance.theme();
268-
let default_button_styles = UiComponentStyles {
269-
width,
270-
font_size: Some(PREPARED_RESPONSE_FONT_SIZE),
271-
font_family_id: Some(appearance.ui_font_family()),
272-
font_color: Some(
273-
appearance
274-
.theme()
275-
.main_text_color(appearance.theme().background())
276-
.into(),
277-
),
278-
border_radius: Some(CornerRadius::with_all(Radius::Percentage(50.))),
279-
border_color: Some(theme.accent().into()),
280-
border_width: Some(1.),
281-
padding: Some(Coords {
282-
top: 5.,
283-
bottom: 5.,
284-
left: right_left_padding.unwrap_or(0.),
285-
right: right_left_padding.unwrap_or(0.),
286-
}),
287-
..Default::default()
288-
};
289-
let hovered_and_clicked_styles = UiComponentStyles {
290-
background: Some(theme.accent().into()),
291-
font_color: Some(theme.background().into()),
292-
..default_button_styles
293-
};
294-
appearance
295-
.ui_builder()
296-
.button_with_custom_styles(
297-
ButtonVariant::Text,
298-
mouse_state_handle,
299-
default_button_styles,
300-
Some(hovered_and_clicked_styles),
301-
Some(hovered_and_clicked_styles),
302-
Some(hovered_and_clicked_styles),
303-
)
304-
.with_centered_text_label(prompt.to_string())
305-
.build()
306-
.with_cursor(Cursor::PointingHand)
307-
.on_click(move |ctx, _, _| {
308-
ctx.dispatch_typed_action(AIAssistantAction::PreparedPrompt(prompt))
309-
})
310-
.finish()
311-
}
312-
313-
pub fn render_request_limit_info(
314-
request_model: &ModelHandle<Requests>,
315-
app: &AppContext,
316-
appearance: &Appearance,
317-
) -> Box<dyn Element> {
318-
let text_color: ColorU =
319-
blended_colors::text_sub(appearance.theme(), appearance.theme().background());
320-
321-
let num_requests_used = request_model.as_ref(app).num_requests_used();
322-
let num_requests_remaining = request_model.as_ref(app).num_remaining_reqs();
323-
let request_limit = request_model.as_ref(app).request_limit();
324-
let next_refresh_time = request_model.as_ref(app).serialized_time_until_refresh();
325-
326-
// Always show the remaining requests count.
327-
let mut row = Flex::row()
328-
.with_main_axis_size(MainAxisSize::Max)
329-
.with_main_axis_alignment(MainAxisAlignment::Center)
330-
.with_cross_axis_alignment(CrossAxisAlignment::Center)
331-
.with_child(
332-
Text::new_inline(
333-
format!("Credits used: {num_requests_used} / {request_limit}.",),
334-
appearance.ui_font_family(),
335-
REQUEST_LIMIT_INFO_FONT_SIZE,
336-
)
337-
.with_color(text_color)
338-
.finish(),
339-
);
340-
341-
// Add the warning icon if necessary.
342-
let icon = if num_requests_remaining == 0 {
343-
Some(Icon::new(
344-
TRIANGLE_ALERT_SVG_PATH,
345-
appearance.theme().ui_error_color(),
346-
))
347-
} else if num_requests_remaining <= 10 {
348-
Some(Icon::new(
349-
SQUARE_ALERT_SVG_PATH,
350-
appearance.theme().ui_warning_color(),
351-
))
352-
} else {
353-
None
354-
};
355-
356-
if let Some(icon) = icon {
357-
row.add_child(
358-
Container::new(
359-
ConstrainedBox::new(icon.finish())
360-
.with_height(16.)
361-
.with_width(16.)
362-
.finish(),
363-
)
364-
.with_margin_left(5.)
365-
.finish(),
366-
);
367-
}
368-
369-
// Show the next refresh time if it's valid.
370-
if let Some(next_refresh_time) = next_refresh_time {
371-
row.add_child(
372-
Container::new(
373-
Text::new_inline(
374-
format!("{next_refresh_time} until refresh."),
375-
appearance.ui_font_family(),
376-
REQUEST_LIMIT_INFO_FONT_SIZE,
377-
)
378-
.with_color(text_color)
379-
.finish(),
380-
)
381-
.with_margin_left(5.)
382-
.finish(),
383-
);
384-
}
385-
386-
row.finish()
387-
}
388-
389-
pub fn code_block_position_id(code_block_index: CodeBlockIndex) -> String {
390-
format!("code_block_id_{}", code_block_index.as_id_str(),)
391-
}
392-
393-
pub fn save_as_workflow_position_id(code_block_index: CodeBlockIndex) -> String {
394-
format!(
395-
"{}_save_as_workflow",
396-
code_block_position_id(code_block_index)
397-
)
398-
}
399-
400256
pub fn markdown_segments_from_text(
401257
transcript_part_index: usize,
402258
transcript_part_type: TranscriptPartSubType,
@@ -475,5 +331,5 @@ fn translate_formatted_text_into_markdown_segments(
475331
}
476332

477333
#[cfg(test)]
478-
#[path = "utils_tests.rs"]
479-
mod utils_tests;
334+
#[path = "dialogue_types_tests.rs"]
335+
mod dialogue_types_tests;

app/src/ai_assistant/utils_tests.rs renamed to app/src/ai_assistant/dialogue_types_tests.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ use crate::ai_assistant::test_util::{
33
default_other_segment,
44
};
55

6-
use super::{FormattedTranscriptMessage, TranscriptPart, TranscriptPartSubType};
7-
8-
use crate::ai_assistant::utils::CodeBlockIndex;
6+
use super::{CodeBlockIndex, FormattedTranscriptMessage, TranscriptPart, TranscriptPartSubType};
97

108
// Mocked data to make it easy to test.
119
lazy_static::lazy_static! {

app/src/ai_assistant/mod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,9 @@ use warp_graphql::{
2121

2222
#[cfg(feature = "cast-agent")]
2323
pub mod coven_entry;
24-
#[cfg(feature = "cast-agent")]
25-
pub mod coven_stream_persist;
24+
pub mod dialogue_types;
2625
pub mod execution_context;
27-
pub mod panel;
2826
pub mod requests;
29-
pub mod transcript;
30-
pub mod utils;
3127

3228
#[cfg(test)]
3329
mod test_util;

0 commit comments

Comments
 (0)