T24f Agent: control and cost
HumanInputRequest asks a question with answers to pick and a line to write one; CostBreakdown totals a session and splits it by part. InterruptButton, TokenUsageChart, TraceViewer and EvalResultTable point to chat::stop_button, a stacked BarChart, TimelineProfiler and DataTable. UsageBar shows amounts as its owner writes them. MemoryPanel and HumanInputRequest share agent::line::send_line; the chapter's bool callbacks take forms::OnFlag. DataTable scrolls columns wider than its box sideways, pinned or not, and leaves a plain wheel to the page; sortable headers are Tab stops. TimelineProfiler fits its ruler to its lane, its spans are Tab stops, and a picked span takes accent.
This commit is contained in:
1 parent
061be8a0ff
commit
37e53a5ecb
20 files changed
+934
-180
No files matched your search
@@ -0,0 +1,96 @@
|
||||
use gpui::{
|
||||
AppContext as _, Context, Entity, IntoElement, KeyBinding, ParentElement, Render, Styled,
|
||||
TestAppContext, VisualTestContext, Window, div, px,
|
||||
};
|
||||
|
||||
use super::{press, settle};
|
||||
use crate::{
|
||||
agent::{CostBreakdown, HumanInputRequest},
|
||||
forms::{self, TextInput},
|
||||
primitives::FocusNext,
|
||||
theme::Theme,
|
||||
};
|
||||
|
||||
/// A question with two answers to pick, and the answers given.
|
||||
struct Asked {
|
||||
field: Entity<TextInput>,
|
||||
answers: Vec<String>,
|
||||
}
|
||||
|
||||
impl Render for Asked {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let view = cx.entity();
|
||||
div().w(px(420.0)).child(
|
||||
HumanInputRequest::new(
|
||||
"asked",
|
||||
"Keep the accents?",
|
||||
&self.field,
|
||||
move |answer, _, cx| {
|
||||
view.update(cx, |asked, _| asked.answers.push(answer.to_string()))
|
||||
},
|
||||
)
|
||||
.choices(["Keep them", "Lift further"]),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn asked(cx: &mut TestAppContext) -> (Entity<Asked>, &mut VisualTestContext) {
|
||||
cx.update(|cx| {
|
||||
Theme::init(cx);
|
||||
forms::bind_keys(cx);
|
||||
cx.bind_keys([KeyBinding::new("tab", FocusNext, None)]);
|
||||
});
|
||||
let (view, cx) = cx.add_window_view(|window, cx| Asked {
|
||||
field: cx.new(|cx| TextInput::new(window, cx)),
|
||||
answers: Vec::new(),
|
||||
});
|
||||
cx.update(|window, _| window.activate_window());
|
||||
settle(cx);
|
||||
(view, cx)
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn a_pick_answers_the_question(cx: &mut TestAppContext) {
|
||||
let (view, cx) = asked(cx);
|
||||
cx.update(|window, _| window.focus_next());
|
||||
cx.update(|window, _| window.focus_next());
|
||||
press("enter", cx);
|
||||
assert_eq!(
|
||||
view.read_with(cx, |asked, _| asked.answers.clone()),
|
||||
["Lift further"]
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn enter_sends_a_written_answer_and_skips_a_blank_one(cx: &mut TestAppContext) {
|
||||
let (view, cx) = asked(cx);
|
||||
for _ in 0..3 {
|
||||
cx.update(|window, _| window.focus_next());
|
||||
}
|
||||
cx.simulate_input(" ");
|
||||
press("enter", cx);
|
||||
cx.simulate_input("Lift them to 18%");
|
||||
press("enter", cx);
|
||||
view.read_with(cx, |asked, cx| {
|
||||
assert_eq!(asked.answers, ["Lift them to 18%"]);
|
||||
assert_eq!(asked.field.read(cx).text(), "");
|
||||
});
|
||||
}
|
||||
|
||||
/// A breakdown of a session that has cost nothing yet.
|
||||
struct Nothing;
|
||||
|
||||
impl Render for Nothing {
|
||||
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||
div()
|
||||
.w(px(320.0))
|
||||
.child(CostBreakdown::new("This session", "USD"))
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn a_session_that_cost_nothing_draws_its_total(cx: &mut TestAppContext) {
|
||||
cx.update(Theme::init);
|
||||
let (_, cx) = cx.add_window_view(|_, _| Nothing);
|
||||
settle(cx);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ use gpui::{
|
||||
};
|
||||
|
||||
mod changes;
|
||||
mod control;
|
||||
mod environment;
|
||||
mod previews;
|
||||
|
||||
|
||||
Reference in new issue
Block a user