Skip to content

symposium-dev/determinishtic

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

determinishtic

Blend deterministic Rust code with LLM-powered reasoning.

Hat tip to Dave Herman for the name.

Philosophy

Do things deterministically that are deterministic. File discovery, iteration, and I/O happen in Rust. Summarization, analysis, and judgment happen via the LLM.

use determinishtic::Determinishtic;
use sacp_tokio::AcpAgent;

#[tokio::main]
async fn main() -> Result<(), determinishtic::Error> {
    let d = Determinishtic::new(AcpAgent::zed_claude_code()).await?;

    // Rust handles the deterministic parts
    let files = std::fs::read_dir("./docs")?
        .filter_map(|e| e.ok())
        .filter(|e| e.path().extension() == Some("md".as_ref()))
        .collect::<Vec<_>>();

    for entry in files {
        let contents = std::fs::read_to_string(entry.path())?;

        // LLM handles the non-deterministic reasoning
        let summary: String = d.think()
            .text("Summarize in one sentence:")
            .display(&contents)
            .await?;

        println!("{}: {}", entry.path().display(), summary);
    }

    Ok(())
}

Installation

Add to your Cargo.toml:

[dependencies]
determinishtic = "0.1"
sacp = "11.0.0-alpha.1"

[dev-dependencies]
sacp-tokio = "11.0.0-alpha.1"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }

Core Concepts

Determinishtic

The main entry point. Wraps a connection to an LLM agent and provides the think() method.

// Connect to an agent
let d = Determinishtic::new(AcpAgent::zed_claude_code()).await?;

// Or use an existing connection (e.g., inside a proxy)
let d = Determinishtic::from_connection(cx.connection_to());

ThinkBuilder

A builder for composing prompts with embedded tools. Created via d.think().

let result: MyOutput = d.think()
    .text("Analyze this data:")
    .display(&data)
    .textln("")
    .text("Focus on trends and anomalies.")
    .await?;

The output type must implement JsonSchema and Deserialize - the LLM returns structured data by calling a return_result tool.

Tools

Register tools that the LLM can call during reasoning:

use sacp::tool_fn_mut;

let mut results = Vec::new();

let output: Summary = d.think()
    .text("Process each item using the provided tool")
    .tool(
        "process_item",
        "Process a single item and return the result",
        async |input: ItemInput, _cx| {
            let output = process(&input);
            results.push(output.clone());
            Ok(output)
        },
        tool_fn_mut!(),
    )
    .await?;

Tools can capture references from the stack frame - no 'static requirement. The tool_fn_mut!() macro is required due to Rust async closure limitations.

  • .tool() - Register a tool and mention it in the prompt
  • .define_tool() - Register a tool without mentioning it in the prompt

Examples

Run the summarize_docs example:

cargo run --example summarize_docs -- --agent claude-code ./docs

Available agents: claude-code, gemini, codex

Documentation

See the mdbook for detailed documentation and RFCs.

License

MIT OR Apache-2.0

About

An API for 'mostly deterministic' scripting using ACP agents.

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages