Skip to content

Commit 6b0fd5c

Browse files
authored
feat: Persona enablement (#2222)
* adds persona definition * adds persona custom deserialization logic * adds impl for visitor permission eval * custom impl of PartialEq and Hash for PermissionSubject * implements PermissionCandidate for all tools * flattens agent config * refactors states (context and tool managers) to accept agents * migrates context manager functions to agent collection * adds test for agent collection * reworks tool name translation * handles tool name conflict * removes unneccessary returns * removes execute_bash * fixes tool permission prompting * fixex permission with execute command tools * rewires existing context functionalities * awaits display task for to avoid buffer interleave * adds hook name before they get executed * wires up tool permissioning with agent persona * fixes compilation errors from merge * fixes test * fixes typos * fixes errors from merge * adds debug for permission eval result * fixes typo * fixes errors from merge * fixes clippy warnings * addresses various comments * modifies mcp cli command for agent * fixes built in tools permissioning not reading camel case * fixes tests for mcp subcommand * adds migration routine for agent * refines migration logic * moves profile level migration to slash command * renames persona to agent * wip: reworks profile migration * temp changes for lints * fixes test * moves migrations to an interactive experience * dedupes context merge * adds migration routine for global mcp config * fixes typo * adds example agent config * deprecates use of profile flags * fixes error from merge * gates migration workflow behind a flag * fixes permission for in memory default agent * fixes test * removes debug log * fixes errors from merge
1 parent 65aa928 commit 6b0fd5c

25 files changed

+2481
-1722
lines changed

crates/chat-cli/src/cli/agent.rs

Lines changed: 1082 additions & 0 deletions
Large diffs are not rendered by default.

crates/chat-cli/src/cli/chat/cli/context.rs

Lines changed: 21 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ pub enum ContextSubcommand {
4949
},
5050
/// Add context rules (filenames or glob patterns)
5151
Add {
52-
/// Add to global rules (available in all profiles)
53-
#[arg(short, long)]
54-
global: bool,
5552
/// Include even if matched files exceed size limits
5653
#[arg(short, long)]
5754
force: bool,
@@ -61,18 +58,11 @@ pub enum ContextSubcommand {
6158
/// Remove specified rules from current profile
6259
#[command(alias = "rm")]
6360
Remove {
64-
/// Remove specified rules globally
65-
#[arg(short, long)]
66-
global: bool,
6761
#[arg(required = true)]
6862
paths: Vec<String>,
6963
},
7064
/// Remove all rules from current profile
71-
Clear {
72-
/// Remove global rules
73-
#[arg(short, long)]
74-
global: bool,
75-
},
65+
Clear,
7666
#[command(hide = true)]
7767
Hooks,
7868
}
@@ -94,66 +84,7 @@ impl ContextSubcommand {
9484

9585
match self {
9686
Self::Show { expand } => {
97-
// Display global context
98-
execute!(
99-
session.stderr,
100-
style::SetAttribute(Attribute::Bold),
101-
style::SetForegroundColor(Color::Magenta),
102-
style::Print("\n🌍 global:\n"),
103-
style::SetAttribute(Attribute::Reset),
104-
)?;
105-
let mut global_context_files = HashSet::new();
106-
let mut profile_context_files = HashSet::new();
107-
if context_manager.global_config.paths.is_empty() {
108-
execute!(
109-
session.stderr,
110-
style::SetForegroundColor(Color::DarkGrey),
111-
style::Print(" <none>\n"),
112-
style::SetForegroundColor(Color::Reset)
113-
)?;
114-
} else {
115-
for path in &context_manager.global_config.paths {
116-
execute!(session.stderr, style::Print(format!(" {} ", path)))?;
117-
if let Ok(context_files) = context_manager.get_context_files_by_path(os, path).await {
118-
execute!(
119-
session.stderr,
120-
style::SetForegroundColor(Color::Green),
121-
style::Print(format!(
122-
"({} match{})",
123-
context_files.len(),
124-
if context_files.len() == 1 { "" } else { "es" }
125-
)),
126-
style::SetForegroundColor(Color::Reset)
127-
)?;
128-
global_context_files.extend(context_files);
129-
}
130-
execute!(session.stderr, style::Print("\n"))?;
131-
}
132-
}
133-
134-
if expand {
135-
execute!(
136-
session.stderr,
137-
style::SetAttribute(Attribute::Bold),
138-
style::SetForegroundColor(Color::DarkYellow),
139-
style::Print("\n 🔧 Hooks:\n")
140-
)?;
141-
print_hook_section(
142-
&mut session.stderr,
143-
&context_manager.global_config.hooks,
144-
HookTrigger::ConversationStart,
145-
)
146-
.map_err(map_chat_error)?;
147-
148-
print_hook_section(
149-
&mut session.stderr,
150-
&context_manager.global_config.hooks,
151-
HookTrigger::PerPrompt,
152-
)
153-
.map_err(map_chat_error)?;
154-
}
155-
156-
// Display profile context
87+
let profile_context_files = HashSet::<(String, String)>::new();
15788
execute!(
15889
session.stderr,
15990
style::SetAttribute(Attribute::Bold),
@@ -183,7 +114,6 @@ impl ContextSubcommand {
183114
)),
184115
style::SetForegroundColor(Color::Reset)
185116
)?;
186-
profile_context_files.extend(context_files);
187117
}
188118
execute!(session.stderr, style::Print("\n"))?;
189119
}
@@ -212,23 +142,19 @@ impl ContextSubcommand {
212142
execute!(session.stderr, style::Print("\n"))?;
213143
}
214144

215-
if global_context_files.is_empty() && profile_context_files.is_empty() {
145+
if profile_context_files.is_empty() {
216146
execute!(
217147
session.stderr,
218148
style::SetForegroundColor(Color::DarkGrey),
219149
style::Print("No files in the current directory matched the rules above.\n\n"),
220150
style::SetForegroundColor(Color::Reset)
221151
)?;
222152
} else {
223-
let total = global_context_files.len() + profile_context_files.len();
224-
let total_tokens = global_context_files
153+
let total = profile_context_files.len();
154+
let total_tokens = profile_context_files
225155
.iter()
226156
.map(|(_, content)| TokenCounter::count_tokens(content))
227-
.sum::<usize>()
228-
+ profile_context_files
229-
.iter()
230-
.map(|(_, content)| TokenCounter::count_tokens(content))
231-
.sum::<usize>();
157+
.sum::<usize>();
232158
execute!(
233159
session.stderr,
234160
style::SetForegroundColor(Color::Green),
@@ -242,25 +168,6 @@ impl ContextSubcommand {
242168
style::SetAttribute(Attribute::Reset)
243169
)?;
244170

245-
for (filename, content) in &global_context_files {
246-
let est_tokens = TokenCounter::count_tokens(content);
247-
execute!(
248-
session.stderr,
249-
style::Print(format!("🌍 {} ", filename)),
250-
style::SetForegroundColor(Color::DarkGrey),
251-
style::Print(format!("(~{} tkns)\n", est_tokens)),
252-
style::SetForegroundColor(Color::Reset),
253-
)?;
254-
if expand {
255-
execute!(
256-
session.stderr,
257-
style::SetForegroundColor(Color::DarkGrey),
258-
style::Print(format!("{}\n\n", content)),
259-
style::SetForegroundColor(Color::Reset)
260-
)?;
261-
}
262-
}
263-
264171
for (filename, content) in &profile_context_files {
265172
let est_tokens = TokenCounter::count_tokens(content);
266173
execute!(
@@ -284,13 +191,8 @@ impl ContextSubcommand {
284191
execute!(session.stderr, style::Print(format!("{}\n\n", "▔".repeat(3))),)?;
285192
}
286193

287-
let mut combined_files: Vec<(String, String)> = global_context_files
288-
.iter()
289-
.chain(profile_context_files.iter())
290-
.cloned()
291-
.collect();
292-
293-
let dropped_files = drop_matched_context_files(&mut combined_files, CONTEXT_FILES_MAX_SIZE).ok();
194+
let mut files_as_vec = profile_context_files.iter().cloned().collect::<Vec<_>>();
195+
let dropped_files = drop_matched_context_files(&mut files_as_vec, CONTEXT_FILES_MAX_SIZE).ok();
294196

295197
execute!(
296198
session.stderr,
@@ -357,38 +259,12 @@ impl ContextSubcommand {
357259
}
358260
}
359261
},
360-
Self::Add { global, force, paths } => {
361-
match context_manager.add_paths(os, paths.clone(), global, force).await {
362-
Ok(_) => {
363-
let target = if global { "global" } else { "profile" };
364-
execute!(
365-
session.stderr,
366-
style::SetForegroundColor(Color::Green),
367-
style::Print(format!("\nAdded {} path(s) to {} context.\n\n", paths.len(), target)),
368-
style::SetForegroundColor(Color::Reset)
369-
)?;
370-
},
371-
Err(e) => {
372-
execute!(
373-
session.stderr,
374-
style::SetForegroundColor(Color::Red),
375-
style::Print(format!("\nError: {}\n\n", e)),
376-
style::SetForegroundColor(Color::Reset)
377-
)?;
378-
},
379-
}
380-
},
381-
Self::Remove { global, paths } => match context_manager.remove_paths(os, paths.clone(), global).await {
262+
Self::Add { force, paths } => match context_manager.add_paths(os, paths.clone(), force).await {
382263
Ok(_) => {
383-
let target = if global { "global" } else { "profile" };
384264
execute!(
385265
session.stderr,
386266
style::SetForegroundColor(Color::Green),
387-
style::Print(format!(
388-
"\nRemoved {} path(s) from {} context.\n\n",
389-
paths.len(),
390-
target
391-
)),
267+
style::Print(format!("\nAdded {} path(s) to context.\n\n", paths.len())),
392268
style::SetForegroundColor(Color::Reset)
393269
)?;
394270
},
@@ -401,17 +277,12 @@ impl ContextSubcommand {
401277
)?;
402278
},
403279
},
404-
Self::Clear { global } => match context_manager.clear(os, global).await {
280+
Self::Remove { paths } => match context_manager.remove_paths(paths.clone()) {
405281
Ok(_) => {
406-
let target = if global {
407-
"global".to_string()
408-
} else {
409-
format!("profile '{}'", context_manager.current_profile)
410-
};
411282
execute!(
412283
session.stderr,
413284
style::SetForegroundColor(Color::Green),
414-
style::Print(format!("\nCleared context for {}\n\n", target)),
285+
style::Print(format!("\nRemoved {} path(s) from context.\n\n", paths.len(),)),
415286
style::SetForegroundColor(Color::Reset)
416287
)?;
417288
},
@@ -424,6 +295,15 @@ impl ContextSubcommand {
424295
)?;
425296
},
426297
},
298+
Self::Clear => {
299+
context_manager.clear();
300+
execute!(
301+
session.stderr,
302+
style::SetForegroundColor(Color::Green),
303+
style::Print("\nCleared context\n\n"),
304+
style::SetForegroundColor(Color::Reset)
305+
)?;
306+
},
427307
Self::Hooks => {
428308
execute!(
429309
session.stderr,

0 commit comments

Comments
 (0)