refactor: rename bot to agent (#628)

pull/629/head
sigoden 3 months ago committed by GitHub
parent 52cd3efd6c
commit d645046d2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -24,9 +24,9 @@ function_calling: false
# e.g. 'execute_command|execute_js_code' 'execute_.*'
dangerously_functions_filter: null
bot_prelude: null # Set a session to use when starting a bot. (e.g. temp, default)
agent_prelude: null # Set a session to use when starting a agent. (e.g. temp, default)
bots:
agents:
- name: todo-sh
model: null
temperature: null
@ -74,7 +74,7 @@ summarize_prompt: 'Summarize the discussion briefly in 200 words or less to use
summary_prompt: 'This is a summary of the chat history as a recap: '
# Custom REPL prompt, see https://github.com/sigoden/aichat/wiki/Custom-REPL-Prompt
left_prompt: '{color.green}{?session {?bot {bot}#}{session}{?role /}}{!session {?bot {bot}}}{role}{?rag @{rag}}{color.cyan}{?session )}{!session >}{color.reset} '
left_prompt: '{color.green}{?session {?agent {agent}#}{session}{?role /}}{!session {?agent {agent}}}{role}{?rag @{rag}}{color.cyan}{?session )}{!session >}{color.reset} '
right_prompt: '{color.purple}{?session {?consume_tokens {consume_tokens}({consume_percent}%)}{!consume_tokens {consume_tokens}}}{color.reset}'
clients:

@ -19,7 +19,7 @@ _aichat() {
case "${cmd}" in
aichat)
opts="-m -r -s -b -e -c -f -H -S -w -h -V --model --prompt --role --session --save-session --bot --rag --serve --execute --code --file --no-highlight --no-stream --wrap --light-theme --dry-run --info --list-models --list-roles --list-sessions --list-bots --list-rags --help --version"
opts="-m -r -s -b -e -c -f -H -S -w -h -V --model --prompt --role --session --save-session --agent --rag --serve --execute --code --file --no-highlight --no-stream --wrap --light-theme --dry-run --info --list-models --list-roles --list-sessions --list-agents --list-rags --help --version"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@ -61,8 +61,8 @@ _aichat() {
COMPREPLY=($(compgen -W "$("$1" --list-sessions)" -- "${cur}"))
return 0
;;
-b|--bot)
COMPREPLY=($(compgen -W "$("$1" --list-bots)" -- "${cur}"))
-b|--agent)
COMPREPLY=($(compgen -W "$("$1" --list-agents)" -- "${cur}"))
return 0
;;
--rag)

@ -3,7 +3,7 @@ complete -c aichat -l prompt -d 'Use the system prompt'
complete -c aichat -s r -l role -x -a "(aichat --list-roles)" -d 'Select a role' -r
complete -c aichat -s s -l session -x -a"(aichat --list-sessions)" -d 'Start or join a session' -r
complete -c aichat -l save-session -d 'Forces the session to be saved'
complete -c aichat -s b -l bot -x -a"(aichat --list-bots)" -d 'Start a bot' -r
complete -c aichat -s b -l agent -x -a"(aichat --list-agents)" -d 'Start a agent' -r
complete -c aichat -l rag -x -a"(aichat --list-rags)" -d 'Start a RAG' -r
complete -c aichat -s f -l file -d 'Include files with the message' -r -F
complete -c aichat -s w -l wrap -d 'Control text wrapping (no, auto, <max-width>)'
@ -18,7 +18,7 @@ complete -c aichat -l info -d 'Display information'
complete -c aichat -l list-models -d 'List all available chat models'
complete -c aichat -l list-roles -d 'List all roles'
complete -c aichat -l list-sessions -d 'List all sessions'
complete -c aichat -l list-bots -d 'List all bots'
complete -c aichat -l list-agents -d 'List all agents'
complete -c aichat -l list-rags -d 'List all RAGs'
complete -c aichat -s h -l help -d 'Print help'
complete -c aichat -s V -l version -d 'Print version'

@ -22,8 +22,8 @@ module completions {
| parse "{value}"
}
def "nu-complete aichat bot" [] {
^aichat --list-bots |
def "nu-complete aichat agent" [] {
^aichat --list-agents |
| lines
| parse "{value}"
}
@ -41,7 +41,7 @@ module completions {
--role(-r): string@"nu-complete aichat role" # Select a role
--session(-s): string@"nu-complete aichat role" # Start or join a session
--save-session # Forces the session to be saved
--bot(-b): string@"nu-complete aichat bot" # Start a bot
--agent(-b): string@"nu-complete aichat agent" # Start a agent
--rag: string@"nu-complete aichat rag" # Start a RAG
--serve # Serve the LLM API and WebAPP
--execute(-e) # Execute commands in natural language
@ -56,7 +56,7 @@ module completions {
--list-models # List all available chat models
--list-roles # List all roles
--list-sessions # List all sessions
--list-bots # List all bots
--list-agents # List all agents
--list-rags # List all RAGs
...text: string # Input text
--help(-h) # Print help

@ -28,8 +28,8 @@ Register-ArgumentCompleter -Native -CommandName 'aichat' -ScriptBlock {
[CompletionResult]::new('-s', '-s', [CompletionResultType]::ParameterName, 'Start or join a session')
[CompletionResult]::new('--session', '--session', [CompletionResultType]::ParameterName, 'Start or join a session')
[CompletionResult]::new('--save-session', '--save-session', [CompletionResultType]::ParameterName, 'Forces the session to be saved')
[CompletionResult]::new('-b', '-b', [CompletionResultType]::ParameterName, 'Start a bot')
[CompletionResult]::new('--bot', '--bot', [CompletionResultType]::ParameterName, 'Start a bot')
[CompletionResult]::new('-b', '-b', [CompletionResultType]::ParameterName, 'Start a agent')
[CompletionResult]::new('--agent', '--agent', [CompletionResultType]::ParameterName, 'Start a agent')
[CompletionResult]::new('--rag', '--rag', [CompletionResultType]::ParameterName, 'Start a RAG')
[CompletionResult]::new('-f', '-f', [CompletionResultType]::ParameterName, 'Include files with the message')
[CompletionResult]::new('--file', '--file', [CompletionResultType]::ParameterName, 'Include files with the message')
@ -50,7 +50,7 @@ Register-ArgumentCompleter -Native -CommandName 'aichat' -ScriptBlock {
[CompletionResult]::new('--list-models', '--list-models', [CompletionResultType]::ParameterName, 'List all available chat models')
[CompletionResult]::new('--list-roles', '--list-roles', [CompletionResultType]::ParameterName, 'List all roles')
[CompletionResult]::new('--list-sessions', '--list-sessions', [CompletionResultType]::ParameterName, 'List all sessions')
[CompletionResult]::new('--list-bots', '--list-bots', [CompletionResultType]::ParameterName, 'List all bots')
[CompletionResult]::new('--list-agents', '--list-agents', [CompletionResultType]::ParameterName, 'List all agents')
[CompletionResult]::new('--list-rags', '--list-rags', [CompletionResultType]::ParameterName, 'List all RAGs')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
@ -76,8 +76,8 @@ Register-ArgumentCompleter -Native -CommandName 'aichat' -ScriptBlock {
$completions = Get-AichatValues "--list-roles"
} elseif ($flag -eq "-s" -or $flag -eq "--session") {
$completions = Get-AichatValues "--list-sessions"
} elseif ($flag -eq "-b" -or $flag -eq "--bot") {
$completions = Get-AichatValues "--list-bots"
} elseif ($flag -eq "-b" -or $flag -eq "--agent") {
$completions = Get-AichatValues "--list-agents"
} elseif ($flag -eq "--rag") {
$completions = Get-AichatValues "--list-rags"
} elseif ($flag -eq "-f" -or $flag -eq "--file") {

@ -23,8 +23,8 @@ _aichat() {
'-s+[Start or join a session]:SESSION:->sessions' \
'--session=[Start or join a session]:SESSION:->sessions' \
'--save-session[Forces the session to be saved]' \
'-b+[Start a bot]:BOT:->bots' \
'--bot=[Start a bot]:BOT:->bots' \
'-b+[Start a agent]:BOT:->agents' \
'--agent=[Start a agent]:BOT:->agents' \
'--rag=[Start a RAG]:RAG:->rags' \
'*-f+[Include files with the message]:FILE:_files' \
'*--file=[Include files with the message]:FILE:_files' \
@ -45,7 +45,7 @@ _aichat() {
'--list-models[List all available chat models]' \
'--list-roles[List all roles]' \
'--list-sessions[List all sessions]' \
'--list-bots[List all bots]' \
'--list-agents[List all agents]' \
'--list-rags[List all RAGs]' \
'-h[Print help]' \
'--help[Print help]' \
@ -58,7 +58,7 @@ _aichat() {
_arguments "${_arguments_options[@]}" $common \
&& ret=0
case $state in
models|roles|sessions|bots|rags)
models|roles|sessions|agents|rags)
local -a values expl
values=( ${(f)"$(_call_program values aichat --list-$state)"} )
_wanted values expl $state compadd -a values && ret=0

@ -18,9 +18,9 @@ pub struct Cli {
/// Forces the session to be saved
#[clap(long)]
pub save_session: bool,
/// Start a bot
/// Start a agent
#[clap(short = 'b', long)]
pub bot: Option<String>,
pub agent: Option<String>,
/// Start a RAG
#[clap(long)]
pub rag: Option<String>,
@ -63,9 +63,9 @@ pub struct Cli {
/// List all sessions
#[clap(long)]
pub list_sessions: bool,
/// List all bots
/// List all agents
#[clap(long)]
pub list_bots: bool,
pub list_agents: bool,
/// List all RAGs
#[clap(long)]
pub list_rags: bool,

@ -11,10 +11,10 @@ use std::{fs::read_to_string, path::Path};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
pub struct Bot {
pub struct Agent {
name: String,
config: BotConfig,
definition: BotDefinition,
config: AgentConfig,
definition: AgentDefinition,
#[serde(skip)]
functions: Functions,
#[serde(skip)]
@ -23,32 +23,32 @@ pub struct Bot {
model: Model,
}
impl Bot {
impl Agent {
pub async fn init(
config: &GlobalConfig,
name: &str,
abort_signal: AbortSignal,
) -> Result<Self> {
let definition_path = Config::bot_definition_file(name)?;
let functions_path = Config::bot_functions_file(name)?;
let rag_path = Config::bot_rag_file(name)?;
let embeddings_dir = Config::bot_embeddings_dir(name)?;
let definition = BotDefinition::load(&definition_path)?;
let definition_path = Config::agent_definition_file(name)?;
let functions_path = Config::agent_functions_file(name)?;
let rag_path = Config::agent_rag_file(name)?;
let embeddings_dir = Config::agent_embeddings_dir(name)?;
let definition = AgentDefinition::load(&definition_path)?;
let functions = if functions_path.exists() {
Functions::init(&functions_path)?
} else {
Functions::default()
};
let bot_config = config
let agent_config = config
.read()
.bots
.agents
.iter()
.find(|v| v.name == name)
.cloned()
.unwrap_or_else(|| BotConfig::new(name));
.unwrap_or_else(|| AgentConfig::new(name));
let model = {
let config = config.read();
match bot_config.model_id.as_ref() {
match agent_config.model_id.as_ref() {
Some(model_id) => Model::retrieve_chat(&config, model_id)?,
None => config.current_model().clone(),
}
@ -56,7 +56,7 @@ impl Bot {
let rag = if rag_path.exists() {
Some(Arc::new(Rag::load(config, "rag", &rag_path)?))
} else if embeddings_dir.is_dir() {
println!("The bot uses an embeddings directory, initializing RAG...");
println!("The agent uses an embeddings directory, initializing RAG...");
let doc_path = embeddings_dir.display().to_string();
Some(Arc::new(
Rag::init(config, "rag", &rag_path, &[doc_path], abort_signal).await?,
@ -67,7 +67,7 @@ impl Bot {
Ok(Self {
name: name.to_string(),
config: bot_config,
config: agent_config,
definition,
functions,
rag,
@ -77,11 +77,11 @@ impl Bot {
pub fn export(&self) -> Result<String> {
let mut value = serde_json::json!(self);
value["functions_dir"] = Config::bot_source_dir(&self.name)?
value["functions_dir"] = Config::agent_source_dir(&self.name)?
.display()
.to_string()
.into();
value["config_dir"] = Config::bot_config_dir(&self.name)?
value["config_dir"] = Config::agent_config_dir(&self.name)?
.display()
.to_string()
.into();
@ -97,7 +97,7 @@ impl Bot {
&self.name
}
pub fn config(&self) -> &BotConfig {
pub fn config(&self) -> &AgentConfig {
&self.config
}
@ -105,7 +105,7 @@ impl Bot {
&self.functions
}
pub fn definition(&self) -> &BotDefinition {
pub fn definition(&self) -> &AgentDefinition {
&self.definition
}
@ -118,7 +118,7 @@ impl Bot {
}
}
impl RoleLike for Bot {
impl RoleLike for Agent {
fn to_role(&self) -> Role {
let mut role = Role::new("", &self.definition.instructions);
role.sync(self);
@ -166,7 +166,7 @@ impl RoleLike for Bot {
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct BotConfig {
pub struct AgentConfig {
pub name: String,
#[serde(rename(serialize = "model", deserialize = "model"))]
pub model_id: Option<String>,
@ -178,7 +178,7 @@ pub struct BotConfig {
pub dangerously_functions_filter: Option<FunctionsFilter>,
}
impl BotConfig {
impl AgentConfig {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
@ -188,7 +188,7 @@ impl BotConfig {
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct BotDefinition {
pub struct AgentDefinition {
pub name: String,
#[serde(default)]
pub description: String,
@ -199,17 +199,17 @@ pub struct BotDefinition {
pub conversation_starters: Vec<String>,
}
impl BotDefinition {
impl AgentDefinition {
pub fn load(path: &Path) -> Result<Self> {
let contents = read_to_string(path)
.with_context(|| format!("Failed to read bot index file at '{}'", path.display()))?;
.with_context(|| format!("Failed to read agent index file at '{}'", path.display()))?;
let definition: Self = serde_yaml::from_str(&contents)
.with_context(|| format!("Failed to load bot at '{}'", path.display()))?;
.with_context(|| format!("Failed to load agent at '{}'", path.display()))?;
Ok(definition)
}
fn banner(&self) -> String {
let BotDefinition {
let AgentDefinition {
name,
description,
version,
@ -238,14 +238,14 @@ impl BotDefinition {
}
}
pub fn list_bots() -> Vec<String> {
list_bots_impl().unwrap_or_default()
pub fn list_agents() -> Vec<String> {
list_agents_impl().unwrap_or_default()
}
fn list_bots_impl() -> Result<Vec<String>> {
fn list_agents_impl() -> Result<Vec<String>> {
let base_dir = Config::functions_dir()?;
let contents = read_to_string(base_dir.join("bots.txt"))?;
let bots = contents
let contents = read_to_string(base_dir.join("agents.txt"))?;
let agents = contents
.split('\n')
.filter_map(|line| {
let line = line.trim();
@ -256,5 +256,5 @@ fn list_bots_impl() -> Result<Vec<String>> {
}
})
.collect();
Ok(bots)
Ok(agents)
}

@ -38,12 +38,12 @@ pub struct Input {
rag_name: Option<String>,
role: Role,
with_session: bool,
with_bot: bool,
with_agent: bool,
}
impl Input {
pub fn from_str(config: &GlobalConfig, text: &str, role: Option<Role>) -> Self {
let (role, with_session, with_bot) = resolve_role(&config.read(), role);
let (role, with_session, with_agent) = resolve_role(&config.read(), role);
Self {
config: config.clone(),
text: text.to_string(),
@ -56,7 +56,7 @@ impl Input {
rag_name: None,
role,
with_session,
with_bot,
with_agent,
}
}
@ -102,7 +102,7 @@ impl Input {
}
}
let (role, with_session, with_bot) = resolve_role(&config.read(), role);
let (role, with_session, with_agent) = resolve_role(&config.read(), role);
Ok(Self {
config: config.clone(),
text: texts.join("\n"),
@ -115,7 +115,7 @@ impl Input {
rag_name: None,
role,
with_session,
with_bot,
with_agent,
})
}
@ -289,8 +289,8 @@ impl Input {
}
}
pub fn with_bot(&self) -> bool {
self.with_bot
pub fn with_agent(&self) -> bool {
self.with_agent
}
pub fn summary(&self) -> String {
@ -361,7 +361,7 @@ fn resolve_role(config: &Config, role: Option<Role>) -> (Role, bool, bool) {
None => (
config.extract_role(),
config.session.is_some(),
config.bot.is_some(),
config.agent.is_some(),
),
}
}

@ -1,9 +1,9 @@
mod bot;
mod agent;
mod input;
mod role;
mod session;
pub use self::bot::{list_bots, Bot, BotConfig};
pub use self::agent::{list_agents, Agent, AgentConfig};
pub use self::input::Input;
pub use self::role::{Role, RoleLike, CODE_ROLE, EXPLAIN_SHELL_ROLE, SHELL_ROLE};
use self::session::Session;
@ -46,7 +46,7 @@ const RAGS_DIR_NAME: &str = "rags";
const FUNCTIONS_DIR_NAME: &str = "functions";
const FUNCTIONS_FILE_NAME: &str = "functions.json";
const FUNCTIONS_BIN_DIR_NAME: &str = "bin";
const BOTS_DIR_NAME: &str = "bots";
const BOTS_DIR_NAME: &str = "agents";
const BOT_DEFINITION_FILE_NAME: &str = "index.yaml";
const BOT_EMBEDDINGS_DIR: &str = "embeddings";
const BOT_RAG_FILE_NAME: &str = "rag.bin";
@ -75,7 +75,7 @@ And answer according to the language of the user's question.
Given the context information, answer the query.
Query: __INPUT__"#;
const LEFT_PROMPT: &str = "{color.green}{?session {?bot {bot}#}{session}{?role /}}{!session {?bot {bot}}}{role}{?rag @{rag}}{color.cyan}{?session )}{!session >}{color.reset} ";
const LEFT_PROMPT: &str = "{color.green}{?session {?agent {agent}#}{session}{?role /}}{!session {?agent {agent}}}{role}{?rag @{rag}}{color.cyan}{?session )}{!session >}{color.reset} ";
const RIGHT_PROMPT: &str = "{color.purple}{?session {?consume_tokens {consume_tokens}({consume_percent}%)}{!consume_tokens {consume_tokens}}}{color.reset}";
#[derive(Debug, Clone, Deserialize)]
@ -99,8 +99,8 @@ pub struct Config {
pub buffer_editor: Option<String>,
pub function_calling: bool,
pub dangerously_functions_filter: Option<FunctionsFilter>,
pub bot_prelude: Option<String>,
pub bots: Vec<BotConfig>,
pub agent_prelude: Option<String>,
pub agents: Vec<AgentConfig>,
pub rag_embedding_model: Option<String>,
pub rag_rerank_model: Option<String>,
pub rag_chunk_size: Option<usize>,
@ -125,7 +125,7 @@ pub struct Config {
#[serde(skip)]
pub rag: Option<Arc<Rag>>,
#[serde(skip)]
pub bot: Option<Bot>,
pub agent: Option<Agent>,
#[serde(skip)]
pub model: Model,
#[serde(skip)]
@ -155,8 +155,8 @@ impl Default for Config {
buffer_editor: None,
function_calling: false,
dangerously_functions_filter: None,
bot_prelude: None,
bots: vec![],
agent_prelude: None,
agents: vec![],
rag_embedding_model: None,
rag_rerank_model: None,
rag_chunk_size: None,
@ -176,7 +176,7 @@ impl Default for Config {
role: None,
session: None,
rag: None,
bot: None,
agent: None,
model: Default::default(),
functions: Default::default(),
working_mode: WorkingMode::Command,
@ -250,22 +250,22 @@ impl Config {
}
pub fn messages_file(&self) -> Result<PathBuf> {
match &self.bot {
match &self.agent {
None => match env::var(get_env_name("messages_file")) {
Ok(value) => Ok(PathBuf::from(value)),
Err(_) => Self::local_path(MESSAGES_FILE_NAME),
},
Some(bot) => Ok(Self::bot_config_dir(bot.name())?.join(MESSAGES_FILE_NAME)),
Some(agent) => Ok(Self::agent_config_dir(agent.name())?.join(MESSAGES_FILE_NAME)),
}
}
pub fn sessions_dir(&self) -> Result<PathBuf> {
match &self.bot {
match &self.agent {
None => match env::var(get_env_name("sessions_dir")) {
Ok(value) => Ok(PathBuf::from(value)),
Err(_) => Self::local_path(SESSIONS_DIR_NAME),
},
Some(bot) => Ok(Self::bot_config_dir(bot.name())?.join(SESSIONS_DIR_NAME)),
Some(agent) => Ok(Self::agent_config_dir(agent.name())?.join(SESSIONS_DIR_NAME)),
}
}
@ -296,7 +296,7 @@ impl Config {
}
pub fn rag_file(&self, name: &str) -> Result<PathBuf> {
let path = if self.bot.is_none() {
let path = if self.agent.is_none() {
Self::rags_dir()?.join(format!("{name}.bin"))
} else {
Self::rags_dir()?
@ -306,35 +306,35 @@ impl Config {
Ok(path)
}
pub fn bots_dir() -> Result<PathBuf> {
match env::var(get_env_name("bots_dir")) {
pub fn agents_dir() -> Result<PathBuf> {
match env::var(get_env_name("agents_dir")) {
Ok(value) => Ok(PathBuf::from(value)),
Err(_) => Self::local_path(BOTS_DIR_NAME),
}
}
pub fn bot_config_dir(name: &str) -> Result<PathBuf> {
Ok(Self::bots_dir()?.join(name))
pub fn agent_config_dir(name: &str) -> Result<PathBuf> {
Ok(Self::agents_dir()?.join(name))
}
pub fn bot_rag_file(name: &str) -> Result<PathBuf> {
Ok(Self::bot_config_dir(name)?.join(BOT_RAG_FILE_NAME))
pub fn agent_rag_file(name: &str) -> Result<PathBuf> {
Ok(Self::agent_config_dir(name)?.join(BOT_RAG_FILE_NAME))
}
pub fn bot_source_dir(name: &str) -> Result<PathBuf> {
pub fn agent_source_dir(name: &str) -> Result<PathBuf> {
Ok(Self::functions_dir()?.join(BOTS_DIR_NAME).join(name))
}
pub fn bot_functions_file(name: &str) -> Result<PathBuf> {
Ok(Self::bot_source_dir(name)?.join(FUNCTIONS_FILE_NAME))
pub fn agent_functions_file(name: &str) -> Result<PathBuf> {
Ok(Self::agent_source_dir(name)?.join(FUNCTIONS_FILE_NAME))
}
pub fn bot_definition_file(name: &str) -> Result<PathBuf> {
Ok(Self::bot_source_dir(name)?.join(BOT_DEFINITION_FILE_NAME))
pub fn agent_definition_file(name: &str) -> Result<PathBuf> {
Ok(Self::agent_source_dir(name)?.join(BOT_DEFINITION_FILE_NAME))
}
pub fn bot_embeddings_dir(name: &str) -> Result<PathBuf> {
Ok(Self::bot_source_dir(name)?.join(BOT_EMBEDDINGS_DIR))
pub fn agent_embeddings_dir(name: &str) -> Result<PathBuf> {
Ok(Self::agent_source_dir(name)?.join(BOT_EMBEDDINGS_DIR))
}
pub fn state(&self) -> StateFlags {
@ -346,7 +346,7 @@ impl Config {
flags |= StateFlags::SESSION;
}
}
if self.bot.is_some() {
if self.agent.is_some() {
flags |= StateFlags::BOT;
}
if self.role.is_some() {
@ -361,8 +361,8 @@ impl Config {
pub fn current_model(&self) -> &Model {
if let Some(session) = self.session.as_ref() {
session.model()
} else if let Some(bot) = self.bot.as_ref() {
bot.model()
} else if let Some(agent) = self.agent.as_ref() {
agent.model()
} else if let Some(role) = self.role.as_ref() {
role.model()
} else {
@ -373,8 +373,8 @@ impl Config {
pub fn role_like_mut(&mut self) -> Option<&mut dyn RoleLike> {
if let Some(session) = self.session.as_mut() {
Some(session)
} else if let Some(bot) = self.bot.as_mut() {
Some(bot)
} else if let Some(agent) = self.agent.as_mut() {
Some(agent)
} else if let Some(role) = self.role.as_mut() {
Some(role)
} else {
@ -385,8 +385,8 @@ impl Config {
pub fn extract_role(&self) -> Role {
let mut role = if let Some(session) = self.session.as_ref() {
session.to_role()
} else if let Some(bot) = self.bot.as_ref() {
bot.to_role()
} else if let Some(agent) = self.agent.as_ref() {
agent.to_role()
} else if let Some(role) = self.role.as_ref() {
role.clone()
} else {
@ -404,8 +404,8 @@ impl Config {
}
pub fn info(&self) -> Result<String> {
if let Some(bot) = &self.bot {
let output = bot.export()?;
if let Some(agent) = &self.agent {
let output = agent.export()?;
if let Some(session) = &self.session {
let session = session
.export()?
@ -466,7 +466,7 @@ impl Config {
("roles_file", display_path(&Self::roles_file()?)),
("functions_dir", display_path(&Self::functions_dir()?)),
("rags_dir", display_path(&Self::rags_dir()?)),
("bots_dir", display_path(&Self::bots_dir()?)),
("agents_dir", display_path(&Self::agents_dir()?)),
("sessions_dir", display_path(&self.sessions_dir()?)),
("messages_file", display_path(&self.messages_file()?)),
];
@ -613,8 +613,8 @@ impl Config {
}
pub fn use_role_obj(&mut self, role: Role) -> Result<()> {
if self.bot.is_some() {
bail!("Cannot perform this action because you are using a bot")
if self.agent.is_some() {
bail!("Cannot perform this action because you are using a agent")
}
if let Some(session) = self.session.as_mut() {
session.guard_empty()?;
@ -696,7 +696,7 @@ impl Config {
if let Some(session) = session.as_mut() {
if session.is_empty() {
if let Some((input, output)) = &self.last_message {
if self.bot.is_some() == input.with_bot() {
if self.agent.is_some() == input.with_agent() {
let ans = Confirm::new(
"Start a session that incorporates the last question and answer?",
)
@ -840,8 +840,8 @@ impl Config {
rag: Option<&str>,
abort_signal: AbortSignal,
) -> Result<()> {
if config.read().bot.is_some() {
bail!("Cannot perform this action because you are using a bot")
if config.read().agent.is_some() {
bail!("Cannot perform this action because you are using a agent")
}
let rag = match rag {
None => {
@ -911,49 +911,49 @@ impl Config {
.replace("__INPUT__", text)
}
pub async fn use_bot(
pub async fn use_agent(
config: &GlobalConfig,
name: &str,
session: Option<&str>,
abort_signal: AbortSignal,
) -> Result<()> {
if !config.read().function_calling {
bail!("Before using the bot, please configure function calling first.");
bail!("Before using the agent, please configure function calling first.");
}
if config.read().bot.is_some() {
bail!("Already in a bot, please run '.exit bot' first to exit the current bot.");
if config.read().agent.is_some() {
bail!("Already in a agent, please run '.exit agent' first to exit the current agent.");
}
let bot = Bot::init(config, name, abort_signal).await?;
config.write().rag = bot.rag();
config.write().bot = Some(bot);
let agent = Agent::init(config, name, abort_signal).await?;
config.write().rag = agent.rag();
config.write().agent = Some(agent);
let session = session
.map(|v| v.to_string())
.or_else(|| config.read().bot_prelude.clone());
.or_else(|| config.read().agent_prelude.clone());
if let Some(session) = session {
config.write().use_session(Some(&session))?;
}
Ok(())
}
pub fn bot_info(&self) -> Result<String> {
if let Some(bot) = &self.bot {
bot.export()
pub fn agent_info(&self) -> Result<String> {
if let Some(agent) = &self.agent {
agent.export()
} else {
bail!("No bot")
bail!("No agent")
}
}
pub fn bot_banner(&self) -> Result<String> {
if let Some(bot) = &self.bot {
Ok(bot.banner())
pub fn agent_banner(&self) -> Result<String> {
if let Some(agent) = &self.agent {
Ok(agent.banner())
} else {
bail!("No bot")
bail!("No agent")
}
}
pub fn exit_bot(&mut self) -> Result<()> {
pub fn exit_agent(&mut self) -> Result<()> {
self.exit_session()?;
if self.bot.take().is_some() {
if self.agent.take().is_some() {
self.rag.take();
self.last_message = None;
}
@ -995,8 +995,8 @@ impl Config {
if self.function_calling {
let filter = role.functions_filter();
if let Some(filter) = filter {
functions = match &self.bot {
Some(bot) => bot.functions().select(&filter),
functions = match &self.agent {
Some(agent) => agent.functions().select(&filter),
None => self.functions.select(&filter),
};
if !model.supports_function_calling() {
@ -1014,8 +1014,8 @@ impl Config {
if get_env_bool("no_dangerously_functions") {
return false;
}
let dangerously_functions_filter = match &self.bot {
Some(bot) => bot.config().dangerously_functions_filter.as_ref(),
let dangerously_functions_filter = match &self.agent {
Some(agent) => agent.config().dangerously_functions_filter.as_ref(),
None => self.dangerously_functions_filter.as_ref(),
};
match dangerously_functions_filter {
@ -1054,9 +1054,9 @@ impl Config {
.map(|v| (v, None))
.collect(),
".rag" => self.list_rags().into_iter().map(|v| (v, None)).collect(),
".bot" => list_bots().into_iter().map(|v| (v, None)).collect(),
".starter" => match &self.bot {
Some(bot) => bot
".agent" => list_agents().into_iter().map(|v| (v, None)).collect(),
".starter" => match &self.agent {
Some(agent) => agent
.conversation_staters()
.iter()
.map(|v| (v.clone(), None))
@ -1212,8 +1212,8 @@ impl Config {
if let Some(rag) = &self.rag {
output.insert("rag", rag.name().to_string());
}
if let Some(bot) = &self.bot {
output.insert("bot", bot.name().to_string());
if let Some(agent) = &self.agent {
output.insert("agent", agent.name().to_string());
}
if self.highlight {
@ -1277,7 +1277,7 @@ impl Config {
let timestamp = now();
let summary = input.summary();
let input_markdown = input.render();
let scope = if self.bot.is_none() {
let scope = if self.agent.is_none() {
let role_name = if input.role().is_derived() {
None
} else {

@ -77,10 +77,10 @@ impl Session {
session.name = name.to_string();
session.path = Some(path.display().to_string());
if let Some(bot) = &config.bot {
if let Some(agent) = &config.agent {
session
.role_prompt
.clone_from(&bot.definition().instructions);
.clone_from(&agent.definition().instructions);
}
Ok(session)

@ -163,18 +163,18 @@ impl ToolCall {
pub fn eval(&self, config: &GlobalConfig) -> Result<Value> {
let function_name = self.name.clone();
let is_dangerously = config.read().is_dangerously_function(&function_name);
let (call_name, cmd_name, mut cmd_args) = match &config.read().bot {
Some(bot) => {
if !bot.functions().contains(&function_name) {
let (call_name, cmd_name, mut cmd_args) = match &config.read().agent {
Some(agent) => {
if !agent.functions().contains(&function_name) {
bail!(
"Unexpected call: {} {function_name} {}",
bot.name(),
agent.name(),
self.arguments
);
}
(
format!("{}:{}", bot.name(), function_name),
bot.name().to_string(),
format!("{}:{}", agent.name(), function_name),
agent.name().to_string(),
vec![function_name],
)
}

@ -16,8 +16,8 @@ extern crate log;
use crate::cli::Cli;
use crate::client::{chat_completion_streaming, list_chat_models, ChatCompletionsOutput};
use crate::config::{
list_bots, Config, GlobalConfig, Input, WorkingMode, CODE_ROLE, EXPLAIN_SHELL_ROLE, SHELL_ROLE,
TEMP_SESSION_NAME,
list_agents, Config, GlobalConfig, Input, WorkingMode, CODE_ROLE, EXPLAIN_SHELL_ROLE,
SHELL_ROLE, TEMP_SESSION_NAME,
};
use crate::function::{eval_tool_calls, need_send_tool_results};
use crate::render::{render_error, MarkdownRender};
@ -70,9 +70,9 @@ async fn main() -> Result<()> {
.for_each(|v| println!("{}", v.name()));
return Ok(());
}
if cli.list_bots {
let bots = list_bots().join("\n");
println!("{bots}");
if cli.list_agents {
let agents = list_agents().join("\n");
println!("{agents}");
return Ok(());
}
if cli.list_rags {
@ -90,12 +90,12 @@ async fn main() -> Result<()> {
config.write().dry_run = true;
}
if let Some(bot) = &cli.bot {
if let Some(agent) = &cli.agent {
let session = cli.session.as_ref().map(|v| match v {
Some(v) => v.as_str(),
None => TEMP_SESSION_NAME,
});
Config::use_bot(&config, bot, session, abort_signal.clone()).await?
Config::use_agent(&config, agent, session, abort_signal.clone()).await?
} else {
if let Some(prompt) = &cli.prompt {
config.write().use_prompt(prompt)?;

@ -102,10 +102,10 @@ lazy_static! {
"Leave the rag",
AssertState::TrueFalse(StateFlags::RAG, StateFlags::BOT),
),
ReplCommand::new(".bot", "Use a bot", AssertState::bare()),
ReplCommand::new(".agent", "Use a agent", AssertState::bare()),
ReplCommand::new(
".info bot",
"View bot info",
".info agent",
"View agent info",
AssertState::True(StateFlags::BOT),
),
ReplCommand::new(
@ -114,8 +114,8 @@ lazy_static! {
AssertState::True(StateFlags::BOT)
),
ReplCommand::new(
".exit bot",
"Leave the bot",
".exit agent",
"Leave the agent",
AssertState::True(StateFlags::BOT)
),
ReplCommand::new(
@ -221,8 +221,8 @@ impl Repl {
let info = self.config.read().rag_info()?;
println!("{}", info);
}
Some("bot") => {
let info = self.config.read().bot_info()?;
Some("agent") => {
let info = self.config.read().agent_info()?;
println!("{}", info);
}
Some(_) => unknown_command()?,
@ -262,12 +262,12 @@ impl Repl {
".rag" => {
Config::use_rag(&self.config, args, self.abort_signal.clone()).await?;
}
".bot" => match args {
".agent" => match args {
Some(name) => {
Config::use_bot(&self.config, name, None, self.abort_signal.clone())
Config::use_agent(&self.config, name, None, self.abort_signal.clone())
.await?;
}
None => println!(r#"Usage: .bot <name>"#),
None => println!(r#"Usage: .agent <name>"#),
},
".starter" => match args {
Some(value) => {
@ -275,7 +275,7 @@ impl Repl {
ask(&self.config, self.abort_signal.clone(), input, true).await?;
}
None => {
let banner = self.config.read().bot_banner()?;
let banner = self.config.read().agent_banner()?;
let output = format!(
r#"Usage: .starter <text>...
@ -362,8 +362,8 @@ Tips: use <tab> to autocomplete conversation starter text.
Some("rag") => {
self.config.write().exit_rag()?;
}
Some("bot") => {
self.config.write().exit_bot()?;
Some("agent") => {
self.config.write().exit_agent()?;
}
Some(_) => unknown_command()?,
None => {

Loading…
Cancel
Save