Compare commits
3 Commits
codex
...
debug-llm-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ecd3f5342 | ||
|
|
e48bf6b2cf | ||
|
|
6f708b0cda |
1
assets/icons/microscope.svg
Normal file
1
assets/icons/microscope.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-microscope"><path d="M6 18h8"/><path d="M3 22h18"/><path d="M14 22a7 7 0 1 0 0-14h-1"/><path d="M9 14h2"/><path d="M9 12a2 2 0 0 1-2-2V6h6v4a2 2 0 0 1-2 2Z"/><path d="M12 6V3a1 1 0 0 0-1-1H9a1 1 0 0 0-1 1v3"/></svg>
|
||||||
|
After Width: | Height: | Size: 418 B |
@@ -64,13 +64,13 @@ use std::{
|
|||||||
};
|
};
|
||||||
use terminal_view::{terminal_panel::TerminalPanel, TerminalView};
|
use terminal_view::{terminal_panel::TerminalPanel, TerminalView};
|
||||||
use text::OffsetRangeExt;
|
use text::OffsetRangeExt;
|
||||||
use ui::TintColor;
|
|
||||||
use ui::{
|
use ui::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
utils::{format_distance_from_now, DateTimeType},
|
utils::{format_distance_from_now, DateTimeType},
|
||||||
Avatar, AvatarShape, ButtonLike, ContextMenu, Disclosure, ElevationIndex, KeyBinding, ListItem,
|
Avatar, AvatarShape, ButtonLike, ContextMenu, Disclosure, ElevationIndex, KeyBinding, ListItem,
|
||||||
ListItemSpacing, PopoverMenu, PopoverMenuHandle, Tooltip,
|
ListItemSpacing, PopoverMenu, PopoverMenuHandle, Tooltip,
|
||||||
};
|
};
|
||||||
|
use ui::{TintColor, ToggleButton};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
dock::{DockPosition, Panel, PanelEvent},
|
dock::{DockPosition, Panel, PanelEvent},
|
||||||
@@ -1587,7 +1587,7 @@ impl WorkflowStepStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
struct ActiveWorkflowStep {
|
struct ActiveWorkflowStep {
|
||||||
range: Range<language::Anchor>,
|
range: Range<language::Anchor>,
|
||||||
resolved: bool,
|
resolved: bool,
|
||||||
@@ -1617,6 +1617,7 @@ pub struct ContextEditor {
|
|||||||
active_workflow_step: Option<ActiveWorkflowStep>,
|
active_workflow_step: Option<ActiveWorkflowStep>,
|
||||||
assistant_panel: WeakView<AssistantPanel>,
|
assistant_panel: WeakView<AssistantPanel>,
|
||||||
error_message: Option<SharedString>,
|
error_message: Option<SharedString>,
|
||||||
|
debug_editor: Option<View<Editor>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_TAB_TITLE: &str = "New Context";
|
const DEFAULT_TAB_TITLE: &str = "New Context";
|
||||||
@@ -1676,6 +1677,7 @@ impl ContextEditor {
|
|||||||
active_workflow_step: None,
|
active_workflow_step: None,
|
||||||
assistant_panel,
|
assistant_panel,
|
||||||
error_message: None,
|
error_message: None,
|
||||||
|
debug_editor: None,
|
||||||
};
|
};
|
||||||
this.update_message_headers(cx);
|
this.update_message_headers(cx);
|
||||||
this.insert_slash_command_output_sections(sections, cx);
|
this.insert_slash_command_output_sections(sections, cx);
|
||||||
@@ -1872,7 +1874,10 @@ impl ContextEditor {
|
|||||||
cx.propagate();
|
cx.propagate();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debug_workflow_steps(&mut self, _: &DebugWorkflowSteps, cx: &mut ViewContext<Self>) {
|
fn update_debug_editor(&self, cx: &mut ViewContext<Self>) {
|
||||||
|
let Some(editor) = &self.debug_editor else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
for (i, step) in self.context.read(cx).workflow_steps().iter().enumerate() {
|
for (i, step) in self.context.read(cx).workflow_steps().iter().enumerate() {
|
||||||
output.push_str(&format!("Step {}:\n", i + 1));
|
output.push_str(&format!("Step {}:\n", i + 1));
|
||||||
@@ -1892,7 +1897,20 @@ impl ContextEditor {
|
|||||||
}) => {
|
}) => {
|
||||||
output.push_str("Resolution:\n");
|
output.push_str("Resolution:\n");
|
||||||
output.push_str(&format!(" {:?}\n", title));
|
output.push_str(&format!(" {:?}\n", title));
|
||||||
output.push_str(&format!(" {:?}\n", suggestions));
|
for (buffer, suggestions) in suggestions {
|
||||||
|
let path = buffer
|
||||||
|
.read(cx)
|
||||||
|
.file()
|
||||||
|
.and_then(|file| file.path().to_str())
|
||||||
|
.unwrap_or("untitled");
|
||||||
|
writeln!(output, " Path: {path}").ok();
|
||||||
|
if !suggestions.is_empty() {
|
||||||
|
writeln!(output, " Suggestions:").ok();
|
||||||
|
for suggestion in suggestions {
|
||||||
|
writeln!(output, " {suggestion:?}").ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
crate::WorkflowStepStatus::Pending(_) => {
|
crate::WorkflowStepStatus::Pending(_) => {
|
||||||
output.push_str("Resolution: Pending\n");
|
output.push_str("Resolution: Pending\n");
|
||||||
@@ -1903,15 +1921,31 @@ impl ContextEditor {
|
|||||||
}
|
}
|
||||||
output.push('\n');
|
output.push('\n');
|
||||||
}
|
}
|
||||||
|
editor.update(cx, |this, cx| {
|
||||||
|
this.set_text(output, cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn debug_workflow_steps(&mut self, _: &DebugWorkflowSteps, cx: &mut ViewContext<Self>) {
|
||||||
let editor = self
|
let editor = self
|
||||||
.workspace
|
.workspace
|
||||||
.update(cx, |workspace, cx| Editor::new_in_workspace(workspace, cx));
|
.update(cx, |workspace, cx| Editor::new_in_workspace(workspace, cx));
|
||||||
|
|
||||||
if let Ok(editor) = editor {
|
if let Ok(editor) = editor {
|
||||||
cx.spawn(|_, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
let editor = editor.await?;
|
let editor = editor.await?;
|
||||||
editor.update(&mut cx, |editor, cx| editor.set_text(output, cx))
|
editor
|
||||||
|
.update(&mut cx, |editor, cx| {
|
||||||
|
editor.set_read_only(true);
|
||||||
|
editor.buffer().update(cx, |this, cx| {
|
||||||
|
this.set_title("Assistant Output".into(), cx);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
|
this.debug_editor = Some(editor);
|
||||||
|
this.update_debug_editor(cx);
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.detach_and_notify_err(cx);
|
.detach_and_notify_err(cx);
|
||||||
}
|
}
|
||||||
@@ -2046,10 +2080,12 @@ impl ContextEditor {
|
|||||||
}
|
}
|
||||||
ContextEvent::WorkflowStepsRemoved(removed) => {
|
ContextEvent::WorkflowStepsRemoved(removed) => {
|
||||||
self.remove_workflow_steps(removed, cx);
|
self.remove_workflow_steps(removed, cx);
|
||||||
|
self.update_debug_editor(cx);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
ContextEvent::WorkflowStepUpdated(updated) => {
|
ContextEvent::WorkflowStepUpdated(updated) => {
|
||||||
self.update_workflow_step(updated.clone(), cx);
|
self.update_workflow_step(updated.clone(), cx);
|
||||||
|
self.update_debug_editor(cx);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
ContextEvent::SummaryChanged => {
|
ContextEvent::SummaryChanged => {
|
||||||
@@ -2492,8 +2528,19 @@ impl ContextEditor {
|
|||||||
self.hide_workflow_step(old_step.range, cx);
|
self.hide_workflow_step(old_step.range, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(new_step) = new_step {
|
if let Some(editor) = &self.debug_editor {
|
||||||
|
let is_active = self
|
||||||
|
.workspace
|
||||||
|
.update(cx, |this, cx| this.activate_item(editor, true, false, cx))
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
if !is_active {
|
||||||
|
self.debug_editor.take();
|
||||||
|
}
|
||||||
|
} else if let Some(new_step) = new_step.clone() {
|
||||||
self.show_workflow_step(new_step.range.clone(), cx);
|
self.show_workflow_step(new_step.range.clone(), cx);
|
||||||
|
}
|
||||||
|
if let Some(new_step) = new_step {
|
||||||
self.active_workflow_step = Some(new_step);
|
self.active_workflow_step = Some(new_step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3660,6 +3707,61 @@ impl Render for ContextEditorToolbarItem {
|
|||||||
|
|
||||||
let right_side = h_flex()
|
let right_side = h_flex()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
|
.child(
|
||||||
|
IconButton::new("toggle-debug-mode", IconName::Microscope)
|
||||||
|
.tooltip(|cx| Tooltip::text("Inspect LLM responses", cx))
|
||||||
|
.visible_on_hover("toolbar")
|
||||||
|
.selected(self.active_context_editor.as_ref().map_or(false, |this| {
|
||||||
|
this.update(cx, |this, cx| {
|
||||||
|
if let Some(debug_editor) = &this.debug_editor {
|
||||||
|
this.workspace
|
||||||
|
.update(cx, |this, cx| {
|
||||||
|
this.active_item(cx).map_or(false, |item| {
|
||||||
|
item.item_id() == debug_editor.entity_id()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
|
}))
|
||||||
|
.on_click(cx.listener(|this, _, cx| {
|
||||||
|
this.active_context_editor.as_ref().map(|editor| {
|
||||||
|
editor
|
||||||
|
.update(cx, |this, cx| {
|
||||||
|
if let Some(debug_editor) = &this.debug_editor {
|
||||||
|
let activated = this
|
||||||
|
.workspace
|
||||||
|
.update(cx, |this, cx| {
|
||||||
|
if this.active_item(cx).map_or(false, |item| {
|
||||||
|
item.item_id() != debug_editor.entity_id()
|
||||||
|
}) {
|
||||||
|
this.activate_item(
|
||||||
|
debug_editor,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
.unwrap_or_default();
|
||||||
|
if !activated {
|
||||||
|
this.debug_editor.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if this.debug_editor.is_none() {
|
||||||
|
this.debug_workflow_steps(&Default::default(), cx);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
});
|
||||||
|
})),
|
||||||
|
)
|
||||||
.child(ModelSelector::new(
|
.child(ModelSelector::new(
|
||||||
self.fs.clone(),
|
self.fs.clone(),
|
||||||
ButtonLike::new("active-model")
|
ButtonLike::new("active-model")
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ pub enum IconName {
|
|||||||
MessageBubbles,
|
MessageBubbles,
|
||||||
Mic,
|
Mic,
|
||||||
MicMute,
|
MicMute,
|
||||||
|
Microscope,
|
||||||
Minimize,
|
Minimize,
|
||||||
Option,
|
Option,
|
||||||
PageDown,
|
PageDown,
|
||||||
@@ -366,6 +367,7 @@ impl IconName {
|
|||||||
IconName::MessageBubbles => "icons/conversations.svg",
|
IconName::MessageBubbles => "icons/conversations.svg",
|
||||||
IconName::Mic => "icons/mic.svg",
|
IconName::Mic => "icons/mic.svg",
|
||||||
IconName::MicMute => "icons/mic_mute.svg",
|
IconName::MicMute => "icons/mic_mute.svg",
|
||||||
|
IconName::Microscope => "icons/microscope.svg",
|
||||||
IconName::Minimize => "icons/minimize.svg",
|
IconName::Minimize => "icons/minimize.svg",
|
||||||
IconName::Option => "icons/option.svg",
|
IconName::Option => "icons/option.svg",
|
||||||
IconName::PageDown => "icons/page_down.svg",
|
IconName::PageDown => "icons/page_down.svg",
|
||||||
|
|||||||
Reference in New Issue
Block a user