Compare commits
3 Commits
385bd3eda2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
2ec2aec4c0
|
|||
|
c2cb4ac433
|
|||
|
605a9170b0
|
@@ -133,6 +133,13 @@ impl MessageContent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_text(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
MessageContent::Text(text) => Some(text),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn merge_prompt(&mut self, replace_fn: impl Fn(&str) -> String) {
|
pub fn merge_prompt(&mut self, replace_fn: impl Fn(&str) -> String) {
|
||||||
match self {
|
match self {
|
||||||
MessageContent::Text(text) => *text = replace_fn(text),
|
MessageContent::Text(text) => *text = replace_fn(text),
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ const RAGS_DIR_NAME: &str = "rags";
|
|||||||
const FUNCTIONS_DIR_NAME: &str = "functions";
|
const FUNCTIONS_DIR_NAME: &str = "functions";
|
||||||
const FUNCTIONS_BIN_DIR_NAME: &str = "bin";
|
const FUNCTIONS_BIN_DIR_NAME: &str = "bin";
|
||||||
const AGENTS_DIR_NAME: &str = "agents";
|
const AGENTS_DIR_NAME: &str = "agents";
|
||||||
|
const REPL_HISTORY_DIR_NAME: &str = "repl-history";
|
||||||
const GLOBAL_TOOLS_DIR_NAME: &str = "tools";
|
const GLOBAL_TOOLS_DIR_NAME: &str = "tools";
|
||||||
const GLOBAL_TOOLS_UTILS_DIR_NAME: &str = "utils";
|
const GLOBAL_TOOLS_UTILS_DIR_NAME: &str = "utils";
|
||||||
const BASH_PROMPT_UTILS_FILE_NAME: &str = "prompt-utils.sh";
|
const BASH_PROMPT_UTILS_FILE_NAME: &str = "prompt-utils.sh";
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ use super::{
|
|||||||
SKILLS_DIR_NAME, WORKSPACE_MEMORY_DIR_NAME,
|
SKILLS_DIR_NAME, WORKSPACE_MEMORY_DIR_NAME,
|
||||||
};
|
};
|
||||||
use crate::client::ProviderModels;
|
use crate::client::ProviderModels;
|
||||||
|
use crate::config::REPL_HISTORY_DIR_NAME;
|
||||||
|
use crate::config::session::Session;
|
||||||
use crate::utils::{get_env_name, list_file_names, normalize_env_name};
|
use crate::utils::{get_env_name, list_file_names, normalize_env_name};
|
||||||
|
|
||||||
use anyhow::{Context, Result, anyhow, bail};
|
use anyhow::{Context, Result, anyhow, bail};
|
||||||
@@ -320,6 +322,20 @@ pub fn workspace_memory_dir_for(workspace_root: &Path) -> PathBuf {
|
|||||||
.join(MEMORY_DIR_NAME)
|
.join(MEMORY_DIR_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn repl_history_dir() -> PathBuf {
|
||||||
|
cache_path().join(REPL_HISTORY_DIR_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repl_history_file(session: &Option<Session>) -> PathBuf {
|
||||||
|
let history_key = if let Some(session) = &session {
|
||||||
|
format!("session_{}", session.name().replace('/', "_"))
|
||||||
|
} else {
|
||||||
|
"default".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
repl_history_dir().join(history_key)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn log_config() -> Result<(LevelFilter, Option<PathBuf>)> {
|
pub fn log_config() -> Result<(LevelFilter, Option<PathBuf>)> {
|
||||||
let log_level = env::var(get_env_name("log_level"))
|
let log_level = env::var(get_env_name("log_level"))
|
||||||
.ok()
|
.ok()
|
||||||
|
|||||||
@@ -163,6 +163,14 @@ impl Session {
|
|||||||
self.messages.is_empty() && self.compressed_messages.is_empty()
|
self.messages.is_empty() && self.compressed_messages.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn messages(&self) -> &[Message] {
|
||||||
|
&self.messages
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compressed_messages(&self) -> &[Message] {
|
||||||
|
&self.compressed_messages
|
||||||
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|||||||
+107
-4
@@ -6,7 +6,10 @@ use self::completer::ReplCompleter;
|
|||||||
use self::highlighter::ReplHighlighter;
|
use self::highlighter::ReplHighlighter;
|
||||||
use self::prompt::ReplPrompt;
|
use self::prompt::ReplPrompt;
|
||||||
|
|
||||||
use crate::client::{call_chat_completions, call_chat_completions_streaming, init_client, oauth};
|
use crate::client::{
|
||||||
|
Message, MessageRole, call_chat_completions, call_chat_completions_streaming, init_client,
|
||||||
|
oauth,
|
||||||
|
};
|
||||||
use crate::config::{
|
use crate::config::{
|
||||||
AgentVariables, AppConfig, AssertState, Input, LastMessage, RequestContext, StateFlags,
|
AgentVariables, AppConfig, AssertState, Input, LastMessage, RequestContext, StateFlags,
|
||||||
macro_execute,
|
macro_execute,
|
||||||
@@ -29,9 +32,9 @@ use log::warn;
|
|||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use reedline::CursorConfig;
|
use reedline::CursorConfig;
|
||||||
use reedline::{
|
use reedline::{
|
||||||
ColumnarMenu, EditCommand, EditMode, Emacs, KeyCode, KeyModifiers, Keybindings, Reedline,
|
ColumnarMenu, EditCommand, EditMode, Emacs, FileBackedHistory, KeyCode, KeyModifiers,
|
||||||
ReedlineEvent, ReedlineMenu, ValidationResult, Validator, Vi, default_emacs_keybindings,
|
Keybindings, Reedline, ReedlineEvent, ReedlineMenu, ValidationResult, Validator, Vi,
|
||||||
default_vi_insert_keybindings, default_vi_normal_keybindings,
|
default_emacs_keybindings, default_vi_insert_keybindings, default_vi_normal_keybindings,
|
||||||
};
|
};
|
||||||
use reedline::{MenuBuilder, Signal};
|
use reedline::{MenuBuilder, Signal};
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
@@ -318,6 +321,58 @@ Type ".help" for additional help.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let (messages_snapshot, compressed_count) = {
|
||||||
|
let ctx = self.ctx.read();
|
||||||
|
if let Some(session) = &ctx.session {
|
||||||
|
let msgs: Vec<Message> = session
|
||||||
|
.messages()
|
||||||
|
.iter()
|
||||||
|
.filter(|m| !m.role.is_system())
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
let compressed = session.compressed_messages().len();
|
||||||
|
(msgs, compressed)
|
||||||
|
} else {
|
||||||
|
(vec![], 0)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !messages_snapshot.is_empty() || compressed_count > 0 {
|
||||||
|
let app = Arc::clone(&self.ctx.read().app.config);
|
||||||
|
if compressed_count > 0 {
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
dimmed_text(&format!(
|
||||||
|
"({compressed_count} earlier messages not shown; compressed for context)"
|
||||||
|
))
|
||||||
|
);
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
|
||||||
|
for message in &messages_snapshot {
|
||||||
|
match message.role {
|
||||||
|
MessageRole::User => {
|
||||||
|
if let Some(text) = message.content.as_text() {
|
||||||
|
println!("{}", dimmed_text("You:"));
|
||||||
|
println!("{text}");
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MessageRole::Assistant => {
|
||||||
|
if let Some(text) = message.content.as_text() {
|
||||||
|
app.print_markdown(text)?;
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{}", dimmed_text("─── ↑ previous conversation ↑ ───"));
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if self.abort_signal.aborted_ctrld() {
|
if self.abort_signal.aborted_ctrld() {
|
||||||
break;
|
break;
|
||||||
@@ -393,6 +448,14 @@ Type ".help" for additional help.
|
|||||||
editor = editor.with_buffer_editor(command, temp_file);
|
editor = editor.with_buffer_editor(command, temp_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if app.save_shell_history {
|
||||||
|
let ctx = ctx.read();
|
||||||
|
let history_path = paths::repl_history_file(&ctx.session);
|
||||||
|
if let Ok(history) = FileBackedHistory::with_file(1000, history_path) {
|
||||||
|
editor = editor.with_history(Box::new(history));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(editor)
|
Ok(editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,6 +747,46 @@ pub async fn run_repl_command(
|
|||||||
session.set_autonaming(false);
|
session.set_autonaming(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(session) = &ctx.session {
|
||||||
|
let messages_snapshot: Vec<Message> = session
|
||||||
|
.messages()
|
||||||
|
.iter()
|
||||||
|
.filter(|m| !m.role.is_system())
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
let compressed_count = session.compressed_messages().len();
|
||||||
|
if !messages_snapshot.is_empty() || compressed_count > 0 {
|
||||||
|
if compressed_count > 0 {
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
dimmed_text(&format!(
|
||||||
|
"({compressed_count} earlier messages not shown — compressed for context)"
|
||||||
|
))
|
||||||
|
);
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
for message in &messages_snapshot {
|
||||||
|
match message.role {
|
||||||
|
MessageRole::User => {
|
||||||
|
if let Some(text) = message.content.as_text() {
|
||||||
|
println!("{}", dimmed_text("You:"));
|
||||||
|
println!("{text}");
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MessageRole::Assistant => {
|
||||||
|
if let Some(text) = message.content.as_text() {
|
||||||
|
app.print_markdown(text)?;
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{}", dimmed_text("─── ↑ previous conversation ↑ ───"));
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
".install" => {
|
".install" => {
|
||||||
let trimmed = args.map(str::trim).unwrap_or("");
|
let trimmed = args.map(str::trim).unwrap_or("");
|
||||||
|
|||||||
Reference in New Issue
Block a user