Skip to content
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

feat: a system for non developers to augment developer system #524

Open
wants to merge 14 commits into
base: v1.0
Choose a base branch
from
38 changes: 36 additions & 2 deletions crates/goose-server/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,26 @@ use goose::{
developer::DeveloperSystem,
memory::MemorySystem,
providers::{configs::ProviderConfig, factory},
systems::goose_hints::GooseHintsSystem,
systems::{goose_hints::GooseHintsSystem, non_developer::NonDeveloperSystem},
};
use std::{env, sync::Arc};
use std::{env, path::Path, process::Command, sync::Arc};
use tokio::sync::Mutex;

/// Check if the current directory or any parent directory contains a .git folder
fn is_in_git_repository() -> bool {
let output = Command::new("git")
.arg("rev-parse")
.arg("--git-dir")
.output();

matches!(output, Ok(output) if output.status.success())
}

/// Check if a .goosehints file exists in the current directory
fn has_goosehints_file() -> bool {
Path::new(".goosehints").exists()
}

/// Shared application state
pub struct AppState {
pub provider_config: ProviderConfig,
Expand All @@ -21,15 +36,34 @@ impl AppState {
pub fn new(provider_config: ProviderConfig, secret_key: String) -> Result<Self> {
let provider = factory::get_provider(provider_config.clone())?;
let mut agent = Agent::new(provider);

dbg!("Adding DeveloperSystem");
agent.add_system(Box::new(DeveloperSystem::new()));

// Only add NonDeveloperSystem if we're not in a git repository and don't have a .goosehints file
let in_git = is_in_git_repository();
let has_hints = has_goosehints_file();

if !in_git && !has_hints {
dbg!("Adding NonDeveloperSystem");
agent.add_system(Box::new(NonDeveloperSystem::new()));
} else {
dbg!("Skipping NonDeveloperSystem");
}

// Add memory system only if GOOSE_SERVER__MEMORY is set to "true"
if let Ok(memory_enabled) = env::var("GOOSE_SERVER__MEMORY") {
if memory_enabled.to_lowercase() == "true" {
dbg!("Adding MemorySystem");
agent.add_system(Box::new(MemorySystem::new()));
} else {
dbg!("Skipping MemorySystem (GOOSE_SERVER__MEMORY not 'true')");
}
} else {
dbg!("Skipping MemorySystem (GOOSE_SERVER__MEMORY not set)");
}

dbg!("Adding GooseHintsSystem");
let goosehints_system = Box::new(GooseHintsSystem::new());
agent.add_system(goosehints_system);

Expand Down
1 change: 1 addition & 0 deletions crates/goose/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ keyring = { version = "3.6.1", features = [
shellexpand = "3.1.0"
rust_decimal = "1.36.0"
rust_decimal_macros = "1.36.0"
tempfile = "3.8"

[dev-dependencies]
sysinfo = "0.32.1"
Expand Down
49 changes: 37 additions & 12 deletions crates/goose/src/providers/ollama.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ mod tests {
#[tokio::test]
async fn test_complete_basic() -> Result<()> {
let model_name = "gpt-4o";
let expected_response = "Hello! How can I assist you today?";
// Mock response for normal completion
let response_body =
create_mock_open_ai_response(model_name, "Hello! How can I assist you today?");
let response_body = create_mock_open_ai_response(model_name, expected_response);

let (_, provider) = _setup_mock_server(response_body).await;
let (mock_server, provider) = _setup_mock_server(response_body).await;

// Prepare input messages
let messages = vec![Message::user().with_text("Hello?")];
Expand All @@ -113,16 +113,41 @@ mod tests {
.await?;

// Assert the response
if let MessageContent::Text(text) = &message.content[0] {
assert_eq!(text.text, "Hello! How can I assist you today?");
} else {
panic!("Expected Text content");
assert!(
!message.content.is_empty(),
"Message content should not be empty"
);
match &message.content[0] {
MessageContent::Text(text) => {
assert_eq!(
text.text, expected_response,
"Response text does not match expected"
);
}
other => panic!("Expected Text content, got {:?}", other),
}
assert_eq!(usage.usage.input_tokens, Some(TEST_INPUT_TOKENS));
assert_eq!(usage.usage.output_tokens, Some(TEST_OUTPUT_TOKENS));
assert_eq!(usage.usage.total_tokens, Some(TEST_TOTAL_TOKENS));
assert_eq!(usage.model, model_name);
assert_eq!(usage.cost, None);

// Verify usage metrics
assert_eq!(
usage.usage.input_tokens,
Some(TEST_INPUT_TOKENS),
"Input tokens mismatch"
);
assert_eq!(
usage.usage.output_tokens,
Some(TEST_OUTPUT_TOKENS),
"Output tokens mismatch"
);
assert_eq!(
usage.usage.total_tokens,
Some(TEST_TOTAL_TOKENS),
"Total tokens mismatch"
);
assert_eq!(usage.model, model_name, "Model name mismatch");
assert_eq!(usage.cost, None, "Cost should be None");

// Ensure mock server handled the request
mock_server.verify().await;

Ok(())
}
Expand Down
1 change: 1 addition & 0 deletions crates/goose/src/systems/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ mod system;
pub use system::System;

pub mod goose_hints;
pub mod non_developer;
Loading
Loading