Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/src/ai/coven_brand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub(crate) const OPENCOVEN_PURPLE: ColorU = ColorU {
};

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

/// Brand warning colour (`#F59E0B`) — used for the Coven Gateway "degraded" pill.
#[allow(dead_code)]
pub(crate) const OPENCOVEN_WARNING: ColorU = ColorU {
r: 245,
g: 158,
Expand Down
98 changes: 0 additions & 98 deletions app/src/ai_assistant/coven_stream_persist.rs

This file was deleted.

188 changes: 22 additions & 166 deletions app/src/ai_assistant/utils.rs → app/src/ai_assistant/dialogue_types.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,11 @@
/// Common functionality used across different AI Assistant components.
//! UI-free AI-dialogue data types shared by the server API and auth layers.
//!
//! These types describe the question/answer transcript structure used by the
//! legacy hosted-AI dialogue path. They were extracted out of the Familiar
//! panel's `utils`/`transcript` UI knot so that `server_api`/`auth` no longer
//! depend on the (now-retired) panel view.
use markdown_parser::{parse_markdown, CodeBlockText, FormattedText, FormattedTextLine};
use pathfinder_color::ColorU;
use warpui::{
elements::{
ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Flex, HighlightedHyperlink,
Icon, MainAxisAlignment, MainAxisSize, MouseStateHandle, ParentElement, Radius, Text,
},
platform::Cursor,
ui_components::{
button::ButtonVariant,
components::{Coords, UiComponent, UiComponentStyles},
},
AppContext, Element, ModelHandle,
};

use crate::{appearance::Appearance, ui_components::blended_colors};

use super::{panel::AIAssistantAction, requests::Requests, transcript::CodeBlockMouseStateHandles};

const PREPARED_RESPONSE_FONT_SIZE: f32 = 11.;
const REQUEST_LIMIT_INFO_FONT_SIZE: f32 = 11.;

const SQUARE_ALERT_SVG_PATH: &str = "bundled/svg/alert-square.svg";
const TRIANGLE_ALERT_SVG_PATH: &str = "bundled/svg/alert-triangle.svg";
use warpui::elements::{HighlightedHyperlink, MouseStateHandle};

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

/// The mouse-state handles needed to render a single code block. Kept as a
/// UI-free leaf type here (a bundle of `warpui` handles) because
/// `MarkdownSegment::CodeBlock` embeds it.
#[derive(Debug, Clone, Default)]
pub struct CodeBlockMouseStateHandles {
pub play_button: MouseStateHandle,
pub play_button_tooltip: MouseStateHandle,
pub copy_button: MouseStateHandle,
pub copy_button_tooltip: MouseStateHandle,
pub save_as_workflow_button: MouseStateHandle,
pub save_as_workflow_button_tooltip: MouseStateHandle,
}

/// A MarkdownSegment differs from a FormattedText in that we intentionally
/// separate out certain markdown elements.
/// For now, only code blocks are rendered differently.
Expand Down Expand Up @@ -257,146 +253,6 @@ impl CodeBlockIndex {
}
}

pub fn render_prepared_response_button(
appearance: &Appearance,
mouse_state_handle: MouseStateHandle,
width: Option<f32>,
right_left_padding: Option<f32>,
prompt: &'static str,
) -> Box<dyn Element> {
let theme = appearance.theme();
let default_button_styles = UiComponentStyles {
width,
font_size: Some(PREPARED_RESPONSE_FONT_SIZE),
font_family_id: Some(appearance.ui_font_family()),
font_color: Some(
appearance
.theme()
.main_text_color(appearance.theme().background())
.into(),
),
border_radius: Some(CornerRadius::with_all(Radius::Percentage(50.))),
border_color: Some(theme.accent().into()),
border_width: Some(1.),
padding: Some(Coords {
top: 5.,
bottom: 5.,
left: right_left_padding.unwrap_or(0.),
right: right_left_padding.unwrap_or(0.),
}),
..Default::default()
};
let hovered_and_clicked_styles = UiComponentStyles {
background: Some(theme.accent().into()),
font_color: Some(theme.background().into()),
..default_button_styles
};
appearance
.ui_builder()
.button_with_custom_styles(
ButtonVariant::Text,
mouse_state_handle,
default_button_styles,
Some(hovered_and_clicked_styles),
Some(hovered_and_clicked_styles),
Some(hovered_and_clicked_styles),
)
.with_centered_text_label(prompt.to_string())
.build()
.with_cursor(Cursor::PointingHand)
.on_click(move |ctx, _, _| {
ctx.dispatch_typed_action(AIAssistantAction::PreparedPrompt(prompt))
})
.finish()
}

pub fn render_request_limit_info(
request_model: &ModelHandle<Requests>,
app: &AppContext,
appearance: &Appearance,
) -> Box<dyn Element> {
let text_color: ColorU =
blended_colors::text_sub(appearance.theme(), appearance.theme().background());

let num_requests_used = request_model.as_ref(app).num_requests_used();
let num_requests_remaining = request_model.as_ref(app).num_remaining_reqs();
let request_limit = request_model.as_ref(app).request_limit();
let next_refresh_time = request_model.as_ref(app).serialized_time_until_refresh();

// Always show the remaining requests count.
let mut row = Flex::row()
.with_main_axis_size(MainAxisSize::Max)
.with_main_axis_alignment(MainAxisAlignment::Center)
.with_cross_axis_alignment(CrossAxisAlignment::Center)
.with_child(
Text::new_inline(
format!("Credits used: {num_requests_used} / {request_limit}.",),
appearance.ui_font_family(),
REQUEST_LIMIT_INFO_FONT_SIZE,
)
.with_color(text_color)
.finish(),
);

// Add the warning icon if necessary.
let icon = if num_requests_remaining == 0 {
Some(Icon::new(
TRIANGLE_ALERT_SVG_PATH,
appearance.theme().ui_error_color(),
))
} else if num_requests_remaining <= 10 {
Some(Icon::new(
SQUARE_ALERT_SVG_PATH,
appearance.theme().ui_warning_color(),
))
} else {
None
};

if let Some(icon) = icon {
row.add_child(
Container::new(
ConstrainedBox::new(icon.finish())
.with_height(16.)
.with_width(16.)
.finish(),
)
.with_margin_left(5.)
.finish(),
);
}

// Show the next refresh time if it's valid.
if let Some(next_refresh_time) = next_refresh_time {
row.add_child(
Container::new(
Text::new_inline(
format!("{next_refresh_time} until refresh."),
appearance.ui_font_family(),
REQUEST_LIMIT_INFO_FONT_SIZE,
)
.with_color(text_color)
.finish(),
)
.with_margin_left(5.)
.finish(),
);
}

row.finish()
}

pub fn code_block_position_id(code_block_index: CodeBlockIndex) -> String {
format!("code_block_id_{}", code_block_index.as_id_str(),)
}

pub fn save_as_workflow_position_id(code_block_index: CodeBlockIndex) -> String {
format!(
"{}_save_as_workflow",
code_block_position_id(code_block_index)
)
}

pub fn markdown_segments_from_text(
transcript_part_index: usize,
transcript_part_type: TranscriptPartSubType,
Expand Down Expand Up @@ -475,5 +331,5 @@ fn translate_formatted_text_into_markdown_segments(
}

#[cfg(test)]
#[path = "utils_tests.rs"]
mod utils_tests;
#[path = "dialogue_types_tests.rs"]
mod dialogue_types_tests;
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ use crate::ai_assistant::test_util::{
default_other_segment,
};

use super::{FormattedTranscriptMessage, TranscriptPart, TranscriptPartSubType};

use crate::ai_assistant::utils::CodeBlockIndex;
use super::{CodeBlockIndex, FormattedTranscriptMessage, TranscriptPart, TranscriptPartSubType};

// Mocked data to make it easy to test.
lazy_static::lazy_static! {
Expand Down
6 changes: 1 addition & 5 deletions app/src/ai_assistant/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,9 @@ use warp_graphql::{

#[cfg(feature = "cast-agent")]
pub mod coven_entry;
#[cfg(feature = "cast-agent")]
pub mod coven_stream_persist;
pub mod dialogue_types;
pub mod execution_context;
pub mod panel;
pub mod requests;
pub mod transcript;
pub mod utils;

#[cfg(test)]
mod test_util;
Expand Down
Loading
Loading