Skip to main content

bamboo_tools/guide/
context.rs

1//! Context for building tool usage guides.
2//!
3//! This module provides language detection and context building for generating
4//! localized tool usage guidelines that match the language of the system prompt.
5
6/// Language options for guide generation.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum GuideLanguage {
9    Chinese,
10    English,
11}
12
13impl GuideLanguage {
14    /// Detects the language from source text.
15    ///
16    /// Returns `Chinese` if CJK characters are detected, otherwise `English`.
17    pub fn detect(source: &str) -> Self {
18        if source.chars().any(is_cjk) {
19            Self::Chinese
20        } else {
21            Self::English
22        }
23    }
24}
25
26/// Build context for generating tool guides.
27///
28/// Contains language settings and configuration options for guide generation.
29#[derive(Debug, Clone)]
30pub struct GuideBuildContext {
31    /// Detected or configured language for guide content
32    pub language: GuideLanguage,
33    /// Whether to include best practices section
34    pub include_best_practices: bool,
35    /// Maximum number of examples to include per tool
36    pub max_examples_per_tool: usize,
37    /// Discoverable tools that are currently activated for the session.
38    /// Activated discoverable tools render with full guides; inactive ones
39    /// render with short summaries only.
40    pub activated_discoverable_tools: std::collections::BTreeSet<String>,
41}
42
43impl Default for GuideBuildContext {
44    fn default() -> Self {
45        Self {
46            language: GuideLanguage::English,
47            include_best_practices: true,
48            max_examples_per_tool: 2,
49            activated_discoverable_tools: std::collections::BTreeSet::new(),
50        }
51    }
52}
53
54impl GuideBuildContext {
55    /// Creates a build context by detecting language from a system prompt.
56    ///
57    /// # Arguments
58    ///
59    /// * `prompt` - The system prompt to analyze for language detection
60    pub fn from_system_prompt(prompt: &str) -> Self {
61        Self {
62            language: GuideLanguage::detect(prompt),
63            ..Self::default()
64        }
65    }
66
67    /// Returns best practices appropriate for the configured language.
68    pub fn best_practices(&self) -> &'static [&'static str] {
69        match self.language {
70            GuideLanguage::Chinese => &[
71                "Assist with defensive security tasks only; refuse offensive security requests, credential harvesting, and malware-oriented code changes.",
72                "For multi-step or non-trivial work, use Task to maintain a shared task list and keep statuses updated continuously.",
73                "Keep exactly one Task item in in_progress whenever possible; mark items completed immediately after finishing.",
74                "Read existing files before editing them. Use Edit for targeted replacements and Write only for full-file writes.",
75                "Use Glob for file discovery and Grep for content search. Do not use Bash for find/grep/cat/head/tail/sed/awk/echo style file operations when dedicated tools exist.",
76                "For code search, narrow scope first: Glob -> Grep(files_with_matches) -> Read -> Grep(content/multiline).",
77                "Avoid broad Grep queries; keep head_limit small and add path/glob/type before multiline or content-heavy searches.",
78                "Use Bash only for real terminal operations (build/test/git/npm/docker/etc.), not for file browsing or user-facing communication.",
79                "When multiple Bash commands are independent, run them in parallel tool calls. For dependent commands, chain with &&.",
80                "**Parallel tool calls are strongly preferred.** The following read-only tools can safely run in parallel and SHOULD be called together in the same response whenever possible: FileExists, Glob, GetCurrentDir, GetFileInfo, Grep, Read, WebFetch, WebSearch, session_history. For example, if you need to read 3 files, emit all 3 Read calls in one response instead of one at a time.",
81                "For commit requests: inspect git status, git diff, and recent git log first; commit only when explicitly requested; avoid interactive git flags; use HEREDOC for multi-line commit messages.",
82                "For pull request requests: review all commits/diff since base branch, use gh to create PR with summary and test plan, and return the PR URL.",
83                "When referencing code locations in responses, use file_path:line_number format.",
84                "Use ExitPlanMode before switching from planning to implementation.",
85            ],
86            GuideLanguage::English => &[
87                "Assist with defensive security tasks only; refuse offensive security requests, credential harvesting, and malware-oriented code changes.",
88                "For multi-step or non-trivial work, use Task to maintain a shared task list and keep statuses updated continuously.",
89                "Keep exactly one Task item in in_progress whenever possible; mark items completed immediately after finishing.",
90                "Read existing files before editing them. Use Edit for targeted replacements and Write only for full-file writes.",
91                "Use Glob for file discovery and Grep for content search. Do not use Bash for find/grep/cat/head/tail/sed/awk/echo style file operations when dedicated tools exist.",
92                "For code search, narrow scope first: Glob -> Grep(files_with_matches) -> Read -> Grep(content/multiline).",
93                "Avoid broad Grep queries; keep head_limit small and add path/glob/type before multiline or content-heavy searches.",
94                "Use Bash only for real terminal operations (build/test/git/npm/docker/etc.), not for file browsing or user-facing communication.",
95                "When multiple Bash commands are independent, run them in parallel tool calls. For dependent commands, chain with &&.",
96                "**Parallel tool calls are strongly preferred.** The following read-only tools can safely run in parallel and SHOULD be called together in the same response whenever possible: FileExists, Glob, GetCurrentDir, GetFileInfo, Grep, Read, WebFetch, WebSearch, session_history. For example, if you need to read 3 files, emit all 3 Read calls in one response instead of one at a time.",
97                "For commit requests: inspect git status, git diff, and recent git log first; commit only when explicitly requested; avoid interactive git flags; use HEREDOC for multi-line commit messages.",
98                "For pull request requests: review all commits/diff since base branch, use gh to create PR with summary and test plan, and return the PR URL.",
99                "When referencing code locations in responses, use file_path:line_number format.",
100                "Use ExitPlanMode before switching from planning to implementation.",
101            ],
102        }
103    }
104}
105
106fn is_cjk(ch: char) -> bool {
107    matches!(
108        ch,
109        '\u{3400}'..='\u{4DBF}' | '\u{4E00}'..='\u{9FFF}' | '\u{F900}'..='\u{FAFF}'
110    )
111}
112
113#[cfg(test)]
114mod tests {
115    use super::{GuideBuildContext, GuideLanguage};
116
117    #[test]
118    fn detect_language_prefers_chinese_when_cjk_present() {
119        assert_eq!(
120            GuideLanguage::detect("Please help me modify this file"),
121            GuideLanguage::English
122        );
123    }
124
125    #[test]
126    fn detect_language_defaults_to_english_without_cjk() {
127        assert_eq!(
128            GuideLanguage::detect("Please inspect the codebase"),
129            GuideLanguage::English
130        );
131    }
132
133    #[test]
134    fn from_system_prompt_carries_detected_language() {
135        let context = GuideBuildContext::from_system_prompt("You are a coding assistant.");
136        assert_eq!(context.language, GuideLanguage::English);
137    }
138}