mirror of
https://github.com/aljazceru/goose.git
synced 2025-12-17 22:24:21 +01:00
feat: V1.0 (#734)
Co-authored-by: Michael Neale <michael.neale@gmail.com> Co-authored-by: Wendy Tang <wendytang@squareup.com> Co-authored-by: Jarrod Sibbison <72240382+jsibbison-square@users.noreply.github.com> Co-authored-by: Alex Hancock <alex.hancock@example.com> Co-authored-by: Alex Hancock <alexhancock@block.xyz> Co-authored-by: Lifei Zhou <lifei@squareup.com> Co-authored-by: Wes <141185334+wesrblock@users.noreply.github.com> Co-authored-by: Max Novich <maksymstepanenko1990@gmail.com> Co-authored-by: Zaki Ali <zaki@squareup.com> Co-authored-by: Salman Mohammed <smohammed@squareup.com> Co-authored-by: Kalvin C <kalvinnchau@users.noreply.github.com> Co-authored-by: Alec Thomas <alec@swapoff.org> Co-authored-by: lily-de <119957291+lily-de@users.noreply.github.com> Co-authored-by: kalvinnchau <kalvin@block.xyz> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Rizel Scarlett <rizel@squareup.com> Co-authored-by: bwrage <bwrage@squareup.com> Co-authored-by: Kalvin Chau <kalvin@squareup.com> Co-authored-by: Alice Hau <110418948+ahau-square@users.noreply.github.com> Co-authored-by: Alistair Gray <ajgray@stripe.com> Co-authored-by: Nahiyan Khan <nahiyan.khan@gmail.com> Co-authored-by: Alex Hancock <alexhancock@squareup.com> Co-authored-by: Nahiyan Khan <nahiyan@squareup.com> Co-authored-by: marcelle <1852848+laanak08@users.noreply.github.com> Co-authored-by: Yingjie He <yingjiehe@block.xyz> Co-authored-by: Yingjie He <yingjiehe@squareup.com> Co-authored-by: Lily Delalande <ldelalande@block.xyz> Co-authored-by: Adewale Abati <acekyd01@gmail.com> Co-authored-by: Ebony Louis <ebony774@gmail.com> Co-authored-by: Angie Jones <jones.angie@gmail.com> Co-authored-by: Ebony Louis <55366651+EbonyLouis@users.noreply.github.com>
This commit is contained in:
8
documentation/docs/goose-architecture/_category_.json
Normal file
8
documentation/docs/goose-architecture/_category_.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"label": "Architecture Overview",
|
||||
"position": 5,
|
||||
"link": {
|
||||
"type": "generated-index",
|
||||
"description": "Extend Goose functionalities with extensions and custom configurations"
|
||||
}
|
||||
}
|
||||
35
documentation/docs/goose-architecture/error-handling.md
Normal file
35
documentation/docs/goose-architecture/error-handling.md
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
title: Error Handling
|
||||
---
|
||||
# Error Handling in Goose
|
||||
|
||||
Error handling is a key performance-driving part of Goose. There are many ways that the non-determinism
|
||||
in the LLM can introduce an error that it can in turn recover from. In a typical Goose session, it's expected for there
|
||||
to be several agent errors that the model can see directly and correct, perhaps entirely behind the scenes.
|
||||
|
||||
## Traditional Errors
|
||||
|
||||
While the agent is operating, there can be intermittent issues in the network, availability of the
|
||||
foundational model, etc. These are raised as errors in the agent API to the caller, who can decide
|
||||
how to handle that. We generally handle these with [anyhow::Error][anyhow-error].
|
||||
|
||||
## Agent Errors
|
||||
|
||||
There are several types of errors where everything is working correctly, but the model generations
|
||||
themselves are somehow causing errors. Things like generating an unknown tool name, incorrect parameters,
|
||||
or a well formed tool call that results in an error in the tool itself. All of these can be surfaced to
|
||||
the LLM to have it attempt to recover.
|
||||
|
||||
The error messages are in some ways prompting - they give instructions to the LLM on how it might go
|
||||
about recovering. We handle these with [thiserror::Error][this-error] and carefully maintain a collection.
|
||||
|
||||
To cover all these cases, both `ToolUse` and `ToolResult` are typically passed through the API as part of a
|
||||
`Result<T, AgentError>`. An error in a `ToolUse` will immediately become an error in a `ToolResult` and
|
||||
passed back to the LLM. A valid `ToolUse` might still end up in an error `ToolResult`, which is also passed
|
||||
back to the LLM.
|
||||
|
||||
The providers then handle translating the agent errors into the various API specs as valid messages.
|
||||
|
||||
|
||||
[anyhow-error]: https://docs.rs/anyhow/latest/anyhow/
|
||||
[this-error]: https://docs.rs/thiserror/latest/thiserror/
|
||||
123
documentation/docs/goose-architecture/extensions-design.md
Normal file
123
documentation/docs/goose-architecture/extensions-design.md
Normal file
@@ -0,0 +1,123 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
# Extensions Design
|
||||
|
||||
This document describes the design and implementation of the Extensions framework in Goose, which enables AI agents to interact with different extensions through a unified tool-based interface.
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Extension
|
||||
An Extension represents any component that can be operated by an AI agent. Extensions expose their capabilities through Tools and maintain their own state. The core interface is defined by the `Extension` trait:
|
||||
|
||||
```rust
|
||||
#[async_trait]
|
||||
pub trait Extension: Send + Sync {
|
||||
fn name(&self) -> &str;
|
||||
fn description(&self) -> &str;
|
||||
fn instructions(&self) -> &str;
|
||||
fn tools(&self) -> &[Tool];
|
||||
async fn status(&self) -> AnyhowResult<HashMap<String, Value>>;
|
||||
async fn call_tool(&self, tool_name: &str, parameters: HashMap<String, Value>) -> ToolResult<Value>;
|
||||
}
|
||||
```
|
||||
|
||||
### Tools
|
||||
Tools are the primary way Extensions expose functionality to agents. Each tool has:
|
||||
- A name
|
||||
- A description
|
||||
- A set of parameters
|
||||
- An implementation that executes the tool's functionality
|
||||
|
||||
A tool must take a Value and return an `AgentResult<Value>` (it must also be async). This
|
||||
is what makes it compatible with the tool calling framework from the agent.
|
||||
|
||||
```rust
|
||||
async fn echo(&self, params: Value) -> AgentResult<Value>
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Component Overview
|
||||
|
||||
1. **Extension Trait**: The core interface that all extensions must implement
|
||||
2. **Error Handling**: Specialized error types for tool execution
|
||||
3. **Proc Macros**: Simplify tool definition and registration [*not yet implemented*]
|
||||
|
||||
### Error Handling
|
||||
|
||||
The system uses two main error types:
|
||||
- `ToolError`: Specific errors related to tool execution
|
||||
- `anyhow::Error`: General purpose errors for extension status and other operations
|
||||
|
||||
This split allows precise error handling for tool execution while maintaining flexibility for general extension operations.
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Tool Design
|
||||
|
||||
1. **Clear Names**: Use clear, action-oriented names for tools (e.g., "create_user" not "user")
|
||||
2. **Descriptive Parameters**: Each parameter should have a clear description
|
||||
3. **Error Handling**: Return specific errors when possible, the errors become "prompts"
|
||||
4. **State Management**: Be explicit about state modifications
|
||||
|
||||
### Extension Implementation
|
||||
|
||||
1. **State Encapsulation**: Keep extension state private and controlled
|
||||
2. **Error Propagation**: Use `?` operator with `ToolError` for tool execution
|
||||
3. **Status Clarity**: Provide clear, structured status information
|
||||
4. **Documentation**: Document all tools and their effects
|
||||
|
||||
### Example Implementation
|
||||
|
||||
Here's a complete example of a simple extension:
|
||||
|
||||
```rust
|
||||
use goose_macros::tool;
|
||||
|
||||
struct FileSystem {
|
||||
registry: ToolRegistry,
|
||||
root_path: PathBuf,
|
||||
}
|
||||
|
||||
impl FileSystem {
|
||||
#[tool(
|
||||
name = "read_file",
|
||||
description = "Read contents of a file"
|
||||
)]
|
||||
async fn read_file(&self, path: String) -> ToolResult<Value> {
|
||||
let full_path = self.root_path.join(path);
|
||||
let content = tokio::fs::read_to_string(full_path)
|
||||
.await
|
||||
.map_err(|e| ToolError::ExecutionError(e.to_string()))?;
|
||||
|
||||
Ok(json!({ "content": content }))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Extension for FileSystem {
|
||||
// ... implement trait methods ...
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Extensions should be tested at multiple levels:
|
||||
1. Unit tests for individual tools
|
||||
2. Integration tests for extension behavior
|
||||
3. Property tests for tool invariants
|
||||
|
||||
Example test:
|
||||
```rust
|
||||
#[tokio::test]
|
||||
async fn test_echo_tool() {
|
||||
let extension = TestExtension::new();
|
||||
let result = extension.call_tool(
|
||||
"echo",
|
||||
hashmap!{ "message" => json!("hello") }
|
||||
).await;
|
||||
|
||||
assert_eq!(result.unwrap(), json!({ "response": "hello" }));
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user