Skip to content

Commit

Permalink
Merge branch 'v1.0' into micn/tabless
Browse files Browse the repository at this point in the history
* v1.0:
  feat: simplify initial session splash (#362)
  fix: hide response form behind flag
  [feat]: Made input resizable + newline support (#359)
  fix: running via Goose.app (#356)
  [app] Layout improvement to correct overflow of markdown content
  prompt tweak only (#353)
  • Loading branch information
michaelneale committed Nov 28, 2024
2 parents b884982 + 4fa9c2a commit d31728c
Show file tree
Hide file tree
Showing 18 changed files with 133 additions and 119 deletions.
2 changes: 1 addition & 1 deletion crates/goose-cli/src/agents/mock_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct MockAgent;
#[async_trait]
impl Agent for MockAgent {
fn add_system(&mut self, _system: Box<dyn System>) {
()

}

async fn reply(&self, _messages: &[Message]) -> Result<BoxStream<'_, Result<Message>>> {
Expand Down
29 changes: 15 additions & 14 deletions crates/goose-cli/src/commands/session.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use console::style;
use rand::{distributions::Alphanumeric, Rng};
use std::path::{Path, PathBuf};

use goose::agent::Agent;
use goose::models::message::Message;
use goose::providers::factory;

use crate::commands::expected_config::get_recommended_models;
Expand All @@ -11,7 +11,6 @@ use crate::profile::{
};
use crate::prompt::cliclack::CliclackPrompt;
use crate::prompt::rustyline::RustylinePrompt;
use crate::prompt::thinking::get_random_goose_action;
use crate::prompt::Prompt;
use crate::session::{ensure_session_dir, Session};

Expand Down Expand Up @@ -48,7 +47,7 @@ pub fn build_session<'a>(
// TODO: Odd to be prepping the provider rather than having that done in the agent?
let provider = factory::get_provider(provider_config).unwrap();
let agent = Box::new(Agent::new(provider));
let mut prompt = match std::env::var("GOOSE_INPUT") {
let prompt = match std::env::var("GOOSE_INPUT") {
Ok(val) => match val.as_str() {
"cliclack" => Box::new(CliclackPrompt::new()) as Box<dyn Prompt>,
"rustyline" => Box::new(RustylinePrompt::new()) as Box<dyn Prompt>,
Expand All @@ -57,17 +56,19 @@ pub fn build_session<'a>(
Err(_) => Box::new(RustylinePrompt::new()),
};

prompt.render(Box::new(Message::assistant().with_text(format!(
r#"{}...
Provider: {}
Model: {}
Session file: {}"#,
get_random_goose_action(),
loaded_profile.provider,
loaded_profile.model,
session_file.display()
))));

println!(
"{} {} {} {} {}",
style("starting session |").dim(),
style("provider:").dim(),
style(loaded_profile.provider).cyan().dim(),
style("model:").dim(),
style(loaded_profile.model).cyan().dim(),
);
println!(
" {} {}",
style("logging to").dim(),
style(session_file.display()).dim().cyan(),
);
Box::new(Session::new(agent, prompt, session_file))
}

Expand Down
19 changes: 3 additions & 16 deletions crates/goose-cli/src/prompt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,9 @@ pub trait Prompt {
fn hide_busy(&self);
fn close(&self);
fn goose_ready(&self) {
self.draw_goose();
}

fn draw_goose(&self) {
println!(
r#" __ - - - -
( 0)> < honk! >
|| - - - -
||
__||_
<=/ \=>
\_____/
| |
^ ^
"#
);
println!("\n");
println!("Goose is running! Enter your instructions, or try asking what goose can do.");
println!("\n");
}
}

Expand Down
52 changes: 0 additions & 52 deletions crates/goose-cli/src/prompt/thinking.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,5 @@
use rand::seq::SliceRandom;

/// List of goose-specific actions for noting goose readiness.
pub const GOOSE_ACTIONS: &[&str] = &[
"Spreading wings",
"Honking thoughtfully",
"Waddling to conclusions",
"Flapping wings excitedly",
"Preening code feathers",
"Gathering digital breadcrumbs",
"Paddling through data",
"Migrating thoughts",
"Nesting ideas",
"Squawking calculations",
"Ruffling algorithmic feathers",
"Pecking at problems",
"Stretching webbed feet",
"Foraging for solutions",
"Grooming syntax",
"Building digital nest",
"Patrolling the codebase",
"Gosling about",
"Strutting with purpose",
"Diving for answers",
"Herding bytes",
"Molting old code",
"Swimming through streams",
"Goose-stepping through logic",
"Synchronizing flock algorithms",
"Navigating code marshes",
"Incubating brilliant ideas",
"Arranging feathers recursively",
"Gliding through branches",
"Migrating to better solutions",
"Nesting functions carefully",
"Hatching clever solutions",
"Preening parse trees",
"Flying through functions",
"Gathering syntax seeds",
"Webbing connections",
"Flocking to optimizations",
"Paddling through protocols",
"Honking success signals",
"Waddling through workflows",
"Nesting in neural networks",
];

/// Extended list of playful thinking messages including both goose and general AI actions
pub const THINKING_MESSAGES: &[&str] = &[
"Thinking",
Expand Down Expand Up @@ -268,10 +223,3 @@ pub fn get_random_thinking_message() -> &'static str {
.choose(&mut rand::thread_rng())
.unwrap_or(&THINKING_MESSAGES[0])
}

/// Returns a random goose-specific action
pub fn get_random_goose_action() -> &'static str {
GOOSE_ACTIONS
.choose(&mut rand::thread_rng())
.unwrap_or(&GOOSE_ACTIONS[0])
}
7 changes: 1 addition & 6 deletions crates/goose-cli/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ impl<'a> Session<'a> {

pub async fn start(&mut self) -> Result<(), Box<dyn std::error::Error>> {
self.setup_session();
self.prompt.goose_ready();

loop {
let input = self.prompt.get_input().unwrap();
Expand Down Expand Up @@ -202,14 +203,8 @@ impl<'a> Session<'a> {
fn setup_session(&mut self) {
let system = Box::new(DeveloperSystem::new());
self.agent.add_system(system);
self.prompt
.render(raw_message("Connected developer system."));
let goosehints_system = Box::new(GooseHintsSystem::new());
self.agent.add_system(goosehints_system);
self.prompt
.render(raw_message("Connected .goosehints system."));

self.prompt.goose_ready();
}

fn close_session(&mut self) {
Expand Down
5 changes: 2 additions & 3 deletions crates/goose-server/src/routes/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ fn convert_messages(incoming: Vec<IncomingMessage>) -> Vec<Message> {
struct ProtocolFormatter;

impl ProtocolFormatter {

fn format_text(text: &str) -> String {
let encoded_text = serde_json::to_string(text).unwrap_or_else(|_| String::new());
format!("0:{}\n", encoded_text)
Expand Down Expand Up @@ -236,8 +235,8 @@ async fn stream_message(
MessageContent::Text(text) => {
for line in text.text.lines() {
let modified_line = format!("{}\n", line);
tx.send(ProtocolFormatter::format_text(&modified_line)).await?;

tx.send(ProtocolFormatter::format_text(&modified_line))
.await?;
}
}
MessageContent::Image(_) => {
Expand Down
10 changes: 7 additions & 3 deletions crates/goose/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ impl MemoryManager {
if let Some(first_line) = lines.next() {
if first_line.starts_with('#') {
let tags = first_line[1..]
.trim()
.split_whitespace()
.map(String::from)
.collect::<Vec<_>>();
Expand Down Expand Up @@ -236,8 +235,7 @@ pub fn execute_tool_call(tool_call: ToolCall) -> Result<String, io::Error> {
.map(|v| v.as_str().unwrap())
.collect();
let is_global = tool_call.arguments["is_global"].as_bool().unwrap();
let _result =
MemoryManager::new()?.remember("context", category, data, &tags, is_global)?;
MemoryManager::new()?.remember("context", category, data, &tags, is_global)?;
Ok(format!("Stored memory in category: {}", category))
}
"retrieve_memories" => {
Expand Down Expand Up @@ -274,6 +272,12 @@ pub struct MemorySystem {
instructions: String,
}

impl Default for MemorySystem {
fn default() -> Self {
Self::new()
}
}

impl MemorySystem {
pub fn new() -> Self {
let memory_manager = MemoryManager::new().expect("Failed to create MemoryManager");
Expand Down
2 changes: 1 addition & 1 deletion crates/goose/src/providers/oauth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl TokenCache {
let hash = format!("{:x}", hasher.finalize());

fs::create_dir_all(get_base_path()).unwrap();
let cache_path = PathBuf::from(get_base_path()).join(format!("{}.json", hash));
let cache_path = get_base_path().join(format!("{}.json", hash));

Self { cache_path }
}
Expand Down
30 changes: 30 additions & 0 deletions ui/desktop/entitlements.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.documents.read-write</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.screen-recording</key>
<true/>
<key>com.apple.security.automation.apple-events</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.device.camera</key>
<true/>
<key>com.apple.security.device.microphone</key>
<true/>
</dict>
</plist>
5 changes: 5 additions & 0 deletions ui/desktop/forge.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ module.exports = {
asar: true,
extraResource: ['src/bin', 'src/images'],
icon: 'src/images/icon',
osxSign: {
entitlements: 'entitlements.plist',
'entitlements-inherit': 'entitlements.plist',
'gatekeeper-assess': false,
},
},
rebuildConfig: {},
makers: [
Expand Down
4 changes: 3 additions & 1 deletion ui/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"debug": "echo 'run --remote-debugging-port=8315' && lldb out/Goose-darwin-arm64/Goose.app",
"test-e2e": "electron-forge start > /tmp/out.txt & ELECTRON_PID=$! && sleep 12 && if grep -q 'renderer: ChatWindow loaded' /tmp/out.txt; then echo 'process is running'; pkill -f electron; else echo 'not starting correctly'; cat /tmp/out.txt; pkill -f electron; exit 1; fi",
"sign-macos": "cd ./out/Goose-darwin-arm64 && codesign --deep --force --verify --sign \"Developer ID Application: Michael Neale (W2L75AE9HQ)\" Goose.app && ditto -c -k --sequesterRsrc --keepParent Goose.app Goose.zip"
"sign-macos": "cd ./out/Goose-darwin-arm64 && codesign --deep --force --verify --sign \"Developer ID Application: Michael Neale (W2L75AE9HQ)\" Goose.app && ditto -c -k --sequesterRsrc --keepParent Goose.app Goose.zip",
"sign-verify": " cd ./out/Goose-darwin-arm64 && codesign --verify --deep --strict Goose.app && codesign -d --entitlements :- Goose.app"
},
"devDependencies": {
"@electron-forge/cli": "^7.5.0",
Expand Down
2 changes: 1 addition & 1 deletion ui/desktop/src/ChatWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ function ChatContent({
setWorking(Working.Idle);

const promptTemplates = [
"You are a simple classifier that takes content and decides if it is asking for input from a person before continuing, or not. If it is a question very clearly, return QUESTION, otherwise READY. ### Message Content:\n" + message.content + "\nYou must provide a response strictly limited to one of the following two words: QUESTION, READY. No other words, phrases, or explanations are allowed. Response:",
"You are a simple classifier that takes content and decides if it is asking for input from a person before continuing if there is more to do, or not. These are questions on if a course of action should proceeed or not, or approval is needed. If it is a question very clearly, return QUESTION, otherwise READY. If it of the form of 'anything else I can do?' sort of question, return READY as that is not the sort of question we are looking for. ### Message Content:\n" + message.content + "\nYou must provide a response strictly limited to one of the following two words: QUESTION, READY. No other words, phrases, or explanations are allowed. Response:",
"You are a simple classifier that takes content and decides if it a list of options or plans to choose from, or not a list of options to choose from It is IMPORTANT that you really know this is a choice, just not numbered steps. If it is a list of options and you are 95% sure, return OPTIONS, otherwise return NO. ### Message Content:\n" + message.content + "\nYou must provide a response strictly limited to one of the following two words:OPTIONS, NO. No other words, phrases, or explanations are allowed. Response:",
"If the content is list of distinct options or plans of action to choose from, and not just a list of things, but clearly a list of things to choose one from, taking into account the Message Content alone, try to format it in a json array, like this JSON array of objects of the form optionTitle:string, optionDescription:string (markdown).\n If is not a list of options or plans to choose from, then return empty list.\n ### Message Content:\n" + message.content + "\n\nYou must provide a response strictly as json in the format descriribed. No other words, phrases, or explanations are allowed. Response:",
];
Expand Down
8 changes: 4 additions & 4 deletions ui/desktop/src/components/GooseMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function GooseMessage({ message, metadata, messages, append }: Go

{message.content && (
<div className="flex bg-goose-bubble text-white rounded-2xl p-4 mb-[16px]">
<ReactMarkdown className="prose prose-xs">{message.content}</ReactMarkdown>
<ReactMarkdown className="prose prose-xs max-w-full overflow-x-auto break-words prose-pre:whitespace-pre-wrap prose-pre:break-words">{message.content}</ReactMarkdown>
</div>
)}

Expand All @@ -43,8 +43,8 @@ export default function GooseMessage({ message, metadata, messages, append }: Go
</div>
)}

{/* append false && to turn this off */}
{metadata && (
{/* Currently disabled */}
{false && metadata && (
<div className="flex mb-[16px]">
<GooseResponseForm
message={message.content}
Expand All @@ -56,4 +56,4 @@ export default function GooseMessage({ message, metadata, messages, append }: Go
</div>
</div>
);
}
}
Loading

0 comments on commit d31728c

Please sign in to comment.