-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Platform Extension MOIM (Minus One Info Message) #5027
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 32 commits
c22d3f8
c821645
fd6e6c4
e9c48e2
5c28a48
250b3c8
beb11cd
0acdc97
9ec9fe8
7813fb5
7a444c0
d1499c5
599f61c
f85335d
ba2004e
811da83
f099955
780e0ad
b286cbd
d2f075f
07c0ce2
528282a
fae6e77
0604895
b7b00ae
94f83e2
4853b30
5f228ab
5607fd5
b153859
3cdc5be
7871fa0
2eb9c81
2774671
df80a59
a7344a1
a954dc6
282775e
29fc6f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -926,10 +926,15 @@ impl Agent { | |
| } | ||
| } | ||
|
|
||
| let conversation_with_moim = super::moim::inject_moim( | ||
| conversation.clone(), | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this replaces conversation, so I don't think we need to clone here |
||
| &self.extension_manager, | ||
| ).await; | ||
|
|
||
| let mut stream = Self::stream_response_from_provider( | ||
| self.provider().await?, | ||
| &system_prompt, | ||
| conversation.messages(), | ||
| conversation_with_moim.messages(), | ||
| &tools, | ||
| &toolshim_tools, | ||
| ).await?; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1167,6 +1167,30 @@ impl ExtensionManager { | |
| .get(&name.into()) | ||
| .map(|ext| ext.get_client()) | ||
| } | ||
|
|
||
| pub async fn collect_moim(&self) -> Option<String> { | ||
| use chrono::Local; | ||
tlongwell-block marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| let timestamp = Local::now().format("%Y-%m-%d %H:%M:%S").to_string(); | ||
| let mut content = format!("<info-msg>\nDatetime: {}\n", timestamp); | ||
tlongwell-block marked this conversation as resolved.
Show resolved
Hide resolved
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a list with join would be more memory effiicient |
||
|
|
||
| let extensions = self.extensions.lock().await; | ||
| for (name, extension) in extensions.iter() { | ||
| if let ExtensionConfig::Platform { .. } = &extension.config { | ||
| let client = extension.get_client(); | ||
| let client_guard = client.lock().await; | ||
| if let Some(moim_content) = client_guard.get_moim().await { | ||
| tracing::debug!("MOIM content from {}: {} chars", name, moim_content.len()); | ||
| content.push('\n'); | ||
| content.push_str(&moim_content); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| content.push_str("\n</info-msg>"); | ||
|
|
||
| Some(content) | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| use crate::agents::extension_manager::ExtensionManager; | ||
| use crate::conversation::message::Message; | ||
| use crate::conversation::Conversation; | ||
| use rmcp::model::Role; | ||
|
|
||
| /// The Minus One Info message provides ephemeral context that's included in LLM calls | ||
| /// but never persisted to conversation history. | ||
tlongwell-block marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| pub async fn inject_moim( | ||
tlongwell-block marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| conversation: Conversation, | ||
| extension_manager: &ExtensionManager, | ||
| ) -> Conversation { | ||
| let config = crate::config::Config::global(); | ||
| if !config.get_param("GOOSE_MOIM_ENABLED").unwrap_or(true) { | ||
| return conversation; | ||
| } | ||
|
|
||
| if let Some(moim) = extension_manager.collect_moim().await { | ||
| let mut messages = conversation.messages().clone(); | ||
| let idx = messages | ||
| .iter() | ||
| .rposition(|m| m.role == Role::Assistant) | ||
| .unwrap_or(messages.len()); | ||
| messages.insert(idx, Message::user().with_text(moim)); | ||
| return Conversation::new_unvalidated(messages); | ||
| } | ||
tlongwell-block marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| conversation | ||
tlongwell-block marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
tlongwell-block marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[tokio::test] | ||
| async fn test_moim_injection_before_assistant() { | ||
| let em = ExtensionManager::new_without_provider(); | ||
|
|
||
| let conv = Conversation::new_unvalidated(vec![ | ||
| Message::user().with_text("Hello"), | ||
| Message::assistant().with_text("Hi"), | ||
| Message::user().with_text("Bye"), | ||
| Message::assistant().with_text("Goodbye"), | ||
| ]); | ||
| let result = inject_moim(conv, &em).await; | ||
| let msgs = result.messages(); | ||
| assert_eq!(msgs.len(), 5); // Original 4 + 1 MOIM | ||
| assert_eq!(msgs[2].content[0].as_text().unwrap(), "Bye"); | ||
| assert!(msgs[3].content[0].as_text().unwrap().contains("<info-msg>")); // MOIM before last assistant | ||
| assert_eq!(msgs[4].content[0].as_text().unwrap(), "Goodbye"); | ||
| } | ||
|
|
||
| #[tokio::test] | ||
| async fn test_moim_injection_no_assistant() { | ||
| let em = ExtensionManager::new_without_provider(); | ||
|
|
||
| let conv = Conversation::new_unvalidated(vec![Message::user().with_text("Hello")]); | ||
| let result = inject_moim(conv, &em).await; | ||
| assert_eq!(result.messages().len(), 2); | ||
| assert_eq!(result.messages()[0].content[0].as_text().unwrap(), "Hello"); | ||
| assert!(result.messages()[1].content[0] | ||
| .as_text() | ||
| .unwrap() | ||
| .contains("<info-msg>")); | ||
| } | ||
tlongwell-block marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.