determinishtic 0.2.0

Blend deterministic Rust code with LLM-powered reasoning
Documentation
# determinishtic

Blend deterministic Rust code with LLM-powered reasoning.

> *Hat tip to [Dave Herman]https://github.com/dherman 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.

```rust
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`:

```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.

```rust
// 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()`.

```rust
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:

```rust
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:

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

Available agents: `claude-code`, `gemini`, `codex`

## Documentation

See the [mdbook](./md) for detailed documentation and RFCs.

## License

MIT OR Apache-2.0