Skip to main content

rs_adk/plugin/
global_instruction.rs

1//! Global instruction plugin — injects instructions into every agent request.
2//!
3//! Mirrors ADK-Python's `global_instruction_plugin`. Prepends or appends
4//! global instructions to every LLM request regardless of the agent.
5
6use async_trait::async_trait;
7
8use super::{Plugin, PluginResult};
9use crate::context::InvocationContext;
10
11/// Plugin that injects global instructions into every LLM request.
12///
13/// Useful for enforcing organization-wide policies, safety guidelines,
14/// or behavioral constraints across all agents.
15pub struct GlobalInstructionPlugin {
16    /// Instructions to prepend to the system instruction.
17    prepend: Option<String>,
18    /// Instructions to append to the system instruction.
19    append: Option<String>,
20}
21
22impl GlobalInstructionPlugin {
23    /// Create a new global instruction plugin.
24    pub fn new() -> Self {
25        Self {
26            prepend: None,
27            append: None,
28        }
29    }
30
31    /// Set instructions to prepend to every system instruction.
32    pub fn with_prepend(mut self, instruction: impl Into<String>) -> Self {
33        self.prepend = Some(instruction.into());
34        self
35    }
36
37    /// Set instructions to append to every system instruction.
38    pub fn with_append(mut self, instruction: impl Into<String>) -> Self {
39        self.append = Some(instruction.into());
40        self
41    }
42
43    /// Get the prepend instruction, if any.
44    pub fn prepend(&self) -> Option<&str> {
45        self.prepend.as_deref()
46    }
47
48    /// Get the append instruction, if any.
49    pub fn append(&self) -> Option<&str> {
50        self.append.as_deref()
51    }
52}
53
54impl Default for GlobalInstructionPlugin {
55    fn default() -> Self {
56        Self::new()
57    }
58}
59
60#[async_trait]
61impl Plugin for GlobalInstructionPlugin {
62    fn name(&self) -> &str {
63        "global_instruction"
64    }
65
66    async fn before_model(
67        &self,
68        _request: &crate::llm::LlmRequest,
69        _ctx: &InvocationContext,
70    ) -> PluginResult {
71        // The actual instruction injection is applied by the runtime
72        // when constructing the LLM request. The plugin configuration
73        // is read by the request builder.
74        PluginResult::Continue
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn default_empty() {
84        let plugin = GlobalInstructionPlugin::new();
85        assert!(plugin.prepend().is_none());
86        assert!(plugin.append().is_none());
87    }
88
89    #[test]
90    fn with_instructions() {
91        let plugin = GlobalInstructionPlugin::new()
92            .with_prepend("Safety first.")
93            .with_append("Always be helpful.");
94        assert_eq!(plugin.prepend(), Some("Safety first."));
95        assert_eq!(plugin.append(), Some("Always be helpful."));
96    }
97
98    #[test]
99    fn plugin_name() {
100        let plugin = GlobalInstructionPlugin::new();
101        assert_eq!(plugin.name(), "global_instruction");
102    }
103}