-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(agents): **EXPERIMENTAL** Agents in Swiftide (#463)
Agents are coming to Swiftide! We are still ironing out all the kinks, while we make it ready for a proper release. You can already experiment with agents, see the rustdocs for documentation, and an example in `/examples`, and feel free to contact us via github or discord. Better documentation, examples, and tutorials are coming soon. Run completions in a loop, define tools with two handy macros, customize the agent by hooking in on lifecycle events, and much more. Besides documentation, expect a big release for what we build this for soon! 🎉
- Loading branch information
Showing
63 changed files
with
5,016 additions
and
269 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
//! This is an example of how to build a Swiftide agent | ||
//! | ||
//! A swiftide agent runs completions in a loop, optionally with tools, to complete a task | ||
//! autonomously. Agents stop when either the LLM calls the always included `stop` tool, or | ||
//! (configurable) if the last message in the completion chain was from the assistant. | ||
//! | ||
//! Tools can be created by using the `tool` attribute macro as shown here. For more control (i.e. | ||
//! internal state), there | ||
//! is also a `Tool` derive macro for convenience. Anything that implements the `Tool` trait can | ||
//! act as a tool. | ||
//! | ||
//! Agents operate on an `AgentContext`, which is responsible for managaging the completion history | ||
//! and providing access to the outside world. For the latter, the context is expected to have a | ||
//! `ToolExecutor`, which by default runs locally. | ||
//! | ||
//! When building the agent, hooks are available to influence the state, completions, and general | ||
//! behaviour of the agent. Hooks are also traits. | ||
//! | ||
//! Refer to the api documentation for more detailed information. | ||
use anyhow::Result; | ||
use swiftide::{ | ||
agents, | ||
chat_completion::{errors::ToolError, ToolOutput}, | ||
traits::{AgentContext, Command}, | ||
}; | ||
|
||
#[swiftide_macros::tool( | ||
description = "Searches code", | ||
param(name = "code_query", description = "The code query") | ||
)] | ||
async fn search_code( | ||
context: &dyn AgentContext, | ||
code_query: &str, | ||
) -> Result<ToolOutput, ToolError> { | ||
let command_output = context | ||
.exec_cmd(&Command::shell(format!("rg '{code_query}'"))) | ||
.await?; | ||
|
||
Ok(command_output.into()) | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<()> { | ||
println!("Hello, agents!"); | ||
|
||
let openai = swiftide::integrations::openai::OpenAI::builder() | ||
.default_embed_model("text-embeddings-3-small") | ||
.default_prompt_model("gpt-4o-mini") | ||
.build()?; | ||
|
||
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<String>(); | ||
|
||
tokio::spawn(async move { | ||
while let Some(msg) = rx.recv().await { | ||
println!("{}", msg); | ||
} | ||
}); | ||
|
||
agents::Agent::builder() | ||
.llm(&openai) | ||
.tools(vec![search_code()]) | ||
.before_all(move |_context| { | ||
// This is a hook that runs before any command is executed | ||
// No native async closures in Rust yet, so we have to use Box::pin | ||
Box::pin(async move { | ||
println!("Hello hook!"); | ||
Ok(()) | ||
}) | ||
}) | ||
// Every message added by the agent will be printed to stdout | ||
.on_new_message(move |_, msg| { | ||
let msg = msg.to_string(); | ||
let tx = tx.clone(); | ||
Box::pin(async move { | ||
tx.send(msg).unwrap(); | ||
Ok(()) | ||
}) | ||
}) | ||
.build()? | ||
.query("In what file can I find an example of a swiftide agent?") | ||
.await?; | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
[package] | ||
name = "swiftide-agents" | ||
version.workspace = true | ||
edition.workspace = true | ||
license.workspace = true | ||
readme.workspace = true | ||
keywords.workspace = true | ||
description.workspace = true | ||
categories.workspace = true | ||
repository.workspace = true | ||
homepage.workspace = true | ||
|
||
[dependencies] | ||
swiftide-core = { path = "../swiftide-core", version = "0.14" } | ||
swiftide-macros = { path = "../swiftide-macros", version = "0.14" } | ||
anyhow.workspace = true | ||
async-trait.workspace = true | ||
dyn-clone.workspace = true | ||
derive_builder.workspace = true | ||
tokio.workspace = true | ||
indoc.workspace = true | ||
tracing.workspace = true | ||
pretty_assertions.workspace = true | ||
strum.workspace = true | ||
strum_macros.workspace = true | ||
serde.workspace = true | ||
serde_json.workspace = true | ||
|
||
[dev-dependencies] | ||
swiftide-core = { path = "../swiftide-core", version = "0.14", features = [ | ||
"test-utils", | ||
] } | ||
swiftide-integrations = { path = "../swiftide-integrations", version = "0.14", features = [ | ||
"openai", | ||
] } | ||
mockall.workspace = true | ||
test-log.workspace = true | ||
temp-dir.workspace = true | ||
insta.workspace = true | ||
|
||
[lints] | ||
workspace = true |
Oops, something went wrong.