Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support macro
Browse files Browse the repository at this point in the history
sigoden committed Jan 17, 2025
1 parent 50c60e8 commit 3b05311
Showing 15 changed files with 653 additions and 422 deletions.
7 changes: 6 additions & 1 deletion scripts/completions/aichat.bash
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ _aichat() {

case "${cmd}" in
aichat)
opts="-m -r -s -a -e -c -f -S -h -V --model --prompt --role --session --empty-session --save-session --agent --agent-variable --rag --rebuild-rag --serve --execute --code --file --no-stream --dry-run --info --list-models --list-roles --list-sessions --list-agents --list-rags --help --version"
opts="-m -r -s -a -e -c -f -S -h -V --model --prompt --role --session --empty-session --save-session --agent --agent-variable --rag --rebuild-rag --macro --serve --execute --code --file --no-stream --dry-run --info --list-models --list-roles --list-sessions --list-agents --list-rags --list-macros --help --version"
if [[ ${cur} == -* || ${cword} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@@ -53,6 +53,11 @@ _aichat() {
__ltrim_colon_completions "$cur"
return 0
;;
--macro)
COMPREPLY=($(compgen -W "$("$1" --list-macros)" -- "${cur}"))
__ltrim_colon_completions "$cur"
return 0
;;
-f|--file)
local oldifs
if [[ -v IFS ]]; then
2 changes: 2 additions & 0 deletions scripts/completions/aichat.fish
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ complete -c aichat -s a -l agent -x -a "(aichat --list-agents)" -d 'Start a age
complete -c aichat -l agent-variable -d 'Set agent variables'
complete -c aichat -l rag -x -a"(aichat --list-rags)" -d 'Start a RAG' -r
complete -c aichat -l rebuild-rag -d 'Rebuild the RAG to sync document changes'
complete -c aichat -l macro -x -a"(aichat --list-macros)" -d 'Execute a macro' -r
complete -c aichat -l serve -d 'Serve the LLM API and WebAPP'
complete -c aichat -s e -l execute -d 'Execute commands in natural language'
complete -c aichat -s c -l code -d 'Output code only'
@@ -20,5 +21,6 @@ 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-agents -d 'List all agents'
complete -c aichat -l list-rags -d 'List all RAGs'
complete -c aichat -l list-macros -d 'List all macros'
complete -c aichat -s h -l help -d 'Print help'
complete -c aichat -s V -l version -d 'Print version'
8 changes: 8 additions & 0 deletions scripts/completions/aichat.nu
Original file line number Diff line number Diff line change
@@ -34,6 +34,12 @@ module completions {
| parse "{value}"
}

def "nu-complete aichat macro" [] {
^aichat --list-macros |
| lines
| parse "{value}"
}

# All-in-one chat and copilot CLI that integrates 10+ AI platforms
export extern aichat [
--model(-m): string@"nu-complete aichat model" # Select a LLM model
@@ -46,6 +52,7 @@ module completions {
--agent-variable # Set agent variables
--rag: string@"nu-complete aichat rag" # Start a RAG
--rebuild-rag # Rebuild the RAG to sync document changes
--macro: string@"nu-complete aichat macro" # Execute a macro
--serve # Serve the LLM API and WebAPP
--execute(-e) # Execute commands in natural language
--code(-c) # Output code only
@@ -58,6 +65,7 @@ module completions {
--list-sessions # List all sessions
--list-agents # List all agents
--list-rags # List all RAGs
--list-macros # List all macros
...text: string # Input text
--help(-h) # Print help
--version(-V) # Print version
6 changes: 5 additions & 1 deletion scripts/completions/aichat.ps1
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ Register-ArgumentCompleter -Native -CommandName 'aichat' -ScriptBlock {
[CompletionResult]::new('--agent-variable', '--agent-variable', [CompletionResultType]::ParameterName, 'Set agent variables')
[CompletionResult]::new('--rag', '--rag', [CompletionResultType]::ParameterName, 'Start a RAG')
[CompletionResult]::new('--rebuild-rag', '--rebuild-rag', [CompletionResultType]::ParameterName, 'Rebuild the RAG to sync document changes')
[CompletionResult]::new('--macro', '--macro', [CompletionResultType]::ParameterName, 'Execute a macro')
[CompletionResult]::new('--serve', '--serve', [CompletionResultType]::ParameterName, 'Serve the LLM API and WebAPP')
[CompletionResult]::new('-e', '-e', [CompletionResultType]::ParameterName, 'Execute commands in natural language')
[CompletionResult]::new('--execute', '--execute', [CompletionResultType]::ParameterName, 'Execute commands in natural language')
@@ -50,6 +51,7 @@ Register-ArgumentCompleter -Native -CommandName 'aichat' -ScriptBlock {
[CompletionResult]::new('--list-sessions', '--list-sessions', [CompletionResultType]::ParameterName, 'List all sessions')
[CompletionResult]::new('--list-agents', '--list-agents', [CompletionResultType]::ParameterName, 'List all agents')
[CompletionResult]::new('--list-rags', '--list-rags', [CompletionResultType]::ParameterName, 'List all RAGs')
[CompletionResult]::new('--list-macros', '--list-macros', [CompletionResultType]::ParameterName, 'List all macros')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
[CompletionResult]::new('-V', '-V', [CompletionResultType]::ParameterName, 'Print version')
@@ -77,8 +79,10 @@ Register-ArgumentCompleter -Native -CommandName 'aichat' -ScriptBlock {
$completions = Get-AichatValues "--list-sessions"
} elseif ($flag -ceq "-a" -or $flag -eq "--agent") {
$completions = Get-AichatValues "--list-agents"
} elseif ($flag -ceq "-R" -or $flag -eq "--rag") {
} elseif ($flag -eq "--rag") {
$completions = Get-AichatValues "--list-rags"
} elseif ($flag -eq "--macro") {
$completions = Get-AichatValues "--list-macros"
} elseif ($flag -ceq "-f" -or $flag -eq "--file") {
$completions = @()
}
4 changes: 3 additions & 1 deletion scripts/completions/aichat.zsh
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@ _aichat() {
'--agent-variable[Set agent variables]' \
'--rag[Start a RAG]:RAG:->rags' \
'--rebuild-rag[Rebuild the RAG to sync document changes]' \
'--macro[Execute a macro]:MACRO:->macros' \
'--serve[Serve the LLM API and WebAPP]' \
'-e[Execute commands in natural language]' \
'--execute[Execute commands in natural language]' \
@@ -45,6 +46,7 @@ _aichat() {
'--list-sessions[List all sessions]' \
'--list-agents[List all agents]' \
'--list-rags[List all RAGs]' \
'--list-macros[List all macros]' \
'-h[Print help]' \
'--help[Print help]' \
'-V[Print version]' \
@@ -56,7 +58,7 @@ _aichat() {
_arguments "${_arguments_options[@]}" $common \
&& ret=0
case $state in
models|roles|sessions|agents|rags)
models|roles|sessions|agents|rags|macros)
local -a values expl
values=( ${(f)"$(_call_program values aichat --list-$state)"} )
_wanted values expl $state compadd -a values && ret=0
13 changes: 9 additions & 4 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -33,6 +33,9 @@ pub struct Cli {
/// Rebuild the RAG to sync document changes
#[clap(long)]
pub rebuild_rag: bool,
/// Execute a macro
#[clap(long = "macro", value_name = "MACRO")]
pub macro_name: Option<String>,
/// Serve the LLM API and WebAPP
#[clap(long, value_name = "ADDRESS")]
pub serve: Option<Option<String>>,
@@ -69,17 +72,19 @@ pub struct Cli {
/// List all RAGs
#[clap(long)]
pub list_rags: bool,
/// List all macros
#[clap(long)]
pub list_macros: bool,
/// Input text
#[clap(trailing_var_arg = true)]
text: Vec<String>,
}

impl Cli {
pub fn text(&self) -> Option<String> {
let text = self.text.to_vec().join(" ");
if text.is_empty() {
return None;
match self.text.is_empty() {
true => None,
false => Some(self.text.join(" ")),
}
Some(text)
}
}
6 changes: 3 additions & 3 deletions src/client/message.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{function::ToolResult, utils::dimmed_text};
use crate::{function::ToolResult, multiline_text, utils::dimmed_text};

use serde::{Deserialize, Serialize};

@@ -83,7 +83,7 @@ impl MessageContent {
agent_info: &Option<(String, Vec<String>)>,
) -> String {
match self {
MessageContent::Text(text) => text.to_string(),
MessageContent::Text(text) => multiline_text(text),
MessageContent::Array(list) => {
let (mut concated_text, mut files) = (String::new(), vec![]);
for item in list {
@@ -97,7 +97,7 @@ impl MessageContent {
}
}
if !concated_text.is_empty() {
concated_text = format!(" -- {concated_text}")
concated_text = format!(" -- {}", multiline_text(&concated_text))
}
format!(".file {}{}", files.join(" "), concated_text)
}
26 changes: 18 additions & 8 deletions src/client/model.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ use super::{
};

use crate::config::Config;
use crate::utils::{estimate_token_length, format_option_value};
use crate::utils::estimate_token_length;

use anyhow::{bail, Result};
use serde::{Deserialize, Serialize};
@@ -133,10 +133,10 @@ impl Model {
supports_function_calling,
..
} = &self.data;
let max_input_tokens = format_option_value(max_input_tokens);
let max_output_tokens = format_option_value(max_output_tokens);
let input_price = format_option_value(input_price);
let output_price = format_option_value(output_price);
let max_input_tokens = stringify_option_value(max_input_tokens);
let max_output_tokens = stringify_option_value(max_output_tokens);
let input_price = stringify_option_value(input_price);
let output_price = stringify_option_value(output_price);
let mut capabilities = vec![];
if *supports_vision {
capabilities.push('👁');
@@ -161,9 +161,9 @@ impl Model {
max_batch_size,
..
} = &self.data;
let max_tokens = format_option_value(max_tokens_per_chunk);
let max_batch = format_option_value(max_batch_size);
let price = format_option_value(input_price);
let max_tokens = stringify_option_value(max_tokens_per_chunk);
let max_batch = stringify_option_value(max_batch_size);
let price = stringify_option_value(input_price);
format!("max-tokens:{max_tokens};max-batch:{max_batch};price:{price}")
}
ModelType::Reranker => String::new(),
@@ -366,3 +366,13 @@ impl ModelType {
}
}
}

fn stringify_option_value<T>(value: &Option<T>) -> String
where
T: std::fmt::Display,
{
match value {
Some(value) => value.to_string(),
None => "-".to_string(),
}
}
2 changes: 1 addition & 1 deletion src/config/agent.rs
Original file line number Diff line number Diff line change
@@ -68,7 +68,7 @@ impl Agent {

let rag = if rag_path.exists() {
Some(Arc::new(Rag::load(config, DEFAULT_AGENT_NAME, &rag_path)?))
} else if !definition.documents.is_empty() && !config.read().cli_info_flag {
} else if !definition.documents.is_empty() && !config.read().info_flag {
let mut ans = false;
if *IS_STDOUT_TERMINAL {
ans = Confirm::new("The agent has the documents, init RAG?")
6 changes: 3 additions & 3 deletions src/config/input.rs
Original file line number Diff line number Diff line change
@@ -27,8 +27,8 @@ pub struct Input {
medias: Vec<String>,
data_urls: HashMap<String, String>,
tool_calls: Option<MessageContentToolCalls>,
rag_name: Option<String>,
role: Role,
rag_name: Option<String>,
with_session: bool,
with_agent: bool,
}
@@ -47,8 +47,8 @@ impl Input {
medias: Default::default(),
data_urls: Default::default(),
tool_calls: None,
rag_name: None,
role,
rag_name: None,
with_session,
with_agent,
}
@@ -128,8 +128,8 @@ impl Input {
medias,
data_urls,
tool_calls: Default::default(),
rag_name: None,
role,
rag_name: None,
with_session,
with_agent,
})
308 changes: 242 additions & 66 deletions src/config/mod.rs

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions src/config/session.rs
Original file line number Diff line number Diff line change
@@ -234,8 +234,7 @@ impl Session {
}
MessageRole::User => {
lines.push(format!(
"{}){}",
self.name,
">> {}",
message.content.render_input(resolve_url_fn, agent_info)
));
}
16 changes: 13 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -17,8 +17,8 @@ use crate::client::{
call_chat_completions, call_chat_completions_streaming, list_models, ModelType,
};
use crate::config::{
ensure_parent_exists, list_agents, load_env_file, Config, GlobalConfig, Input, WorkingMode,
CODE_ROLE, EXPLAIN_SHELL_ROLE, SHELL_ROLE, TEMP_SESSION_NAME,
ensure_parent_exists, list_agents, load_env_file, macro_execute, Config, GlobalConfig, Input,
WorkingMode, CODE_ROLE, EXPLAIN_SHELL_ROLE, SHELL_ROLE, TEMP_SESSION_NAME,
};
use crate::render::render_error;
use crate::repl::Repl;
@@ -67,7 +67,7 @@ async fn run(config: GlobalConfig, cli: Cli, text: Option<String>) -> Result<()>
return serve::run(config, addr).await;
}
if cli.info {
config.write().cli_info_flag = true;
config.write().info_flag = true;
}

if cli.list_models {
@@ -91,6 +91,12 @@ async fn run(config: GlobalConfig, cli: Cli, text: Option<String>) -> Result<()>
println!("{rags}");
return Ok(());
}
if cli.list_macros {
let macros = Config::list_macros().join("\n");
println!("{macros}");
return Ok(());
}

if cli.dry_run {
config.write().dry_run = true;
}
@@ -158,6 +164,10 @@ async fn run(config: GlobalConfig, cli: Cli, text: Option<String>) -> Result<()>
return Ok(());
}
}
if let Some(name) = &cli.macro_name {
macro_execute(&config, name, text.as_deref(), abort_signal.clone()).await?;
return Ok(());
}
if cli.execute && !is_repl {
if cfg!(target_os = "macos") && !stdin().is_terminal() {
bail!("Unable to read the pipe for shell execution on MacOS")
643 changes: 324 additions & 319 deletions src/repl/mod.rs

Large diffs are not rendered by default.

25 changes: 15 additions & 10 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -112,16 +112,6 @@ pub fn extract_block(input: &str) -> String {
}
}

pub fn format_option_value<T>(value: &Option<T>) -> String
where
T: std::fmt::Display,
{
match value {
Some(value) => value.to_string(),
None => "-".to_string(),
}
}

pub fn convert_option_string(value: &str) -> Option<String> {
if value.is_empty() {
None
@@ -199,6 +189,21 @@ pub fn dimmed_text(input: &str) -> String {
nu_ansi_term::Style::new().dimmed().paint(input).to_string()
}

pub fn multiline_text(input: &str) -> String {
input
.split('\n')
.enumerate()
.map(|(i, v)| {
if i == 0 {
v.to_string()
} else {
format!(".. {v}")
}
})
.collect::<Vec<String>>()
.join("\n")
}

pub fn temp_file(prefix: &str, suffix: &str) -> PathBuf {
env::temp_dir().join(format!(
"{}-{}{prefix}{}{suffix}",

0 comments on commit 3b05311

Please sign in to comment.