brainwires-reasoning 0.11.0

Layer 3 reasoning — plan/output parsers + provider-agnostic local-inference scorers (router, complexity, relevance, retrieval, strategy, summariser, validator, entity enhancer) for the Brainwires Agent Framework
Documentation
# brainwires-reasoning

Layer 3 — Intelligence. Provider-agnostic reasoning primitives for the
Brainwires Agent Framework: plan / output parsers, local-LLM scorers for
routing and validation, and named reasoning strategies (CoT, ReAct,
Reflexion, Tree-of-Thoughts). Every scorer accepts `Arc<dyn Provider>`
and falls back to pattern-based logic when the provider is unavailable,
so a missing local model degrades gracefully instead of crashing.

## Layout

```
brainwires-reasoning
├── output_parser / plan_parser    # LLM-output → structured data
├── LocalRouter                    # fast model-size selection
├── ComplexityScorer               # score task difficulty
├── RetrievalClassifier            # needs-retrieval gate
├── RelevanceScorer                # rerank retrieved chunks
├── StrategySelector               # pick CoT / ReAct / ...
├── EntityEnhancer                 # extract typed entities + relations
├── LocalSummarizer                # offline summarization / fact extract
├── Validator                      # output sanity checks
└── strategies::{ChainOfThought, ReAct, Reflexion, TreeOfThoughts}
```

## Features

This crate has no Cargo features — every scorer is always compiled.
Individual scorers are enabled at runtime via `LocalInferenceConfig`, so
callers pay the dependency cost once and pick which of the nine
components to wire up.

## Quick start

```rust
use std::sync::Arc;
use brainwires_reasoning::{
    LocalInferenceConfig, LocalRouterBuilder, JsonOutputParser, OutputParser,
    parse_plan_steps,
};

# async fn demo(provider: Arc<dyn brainwires_core::Provider>) -> anyhow::Result<()> {
// Parse a numbered plan.
let steps = parse_plan_steps("1. Research topic\n2. Draft summary\n3. Review");
assert_eq!(steps.len(), 3);

// Parse JSON from LLM output (strips ```json fences automatically).
let parser = JsonOutputParser::new();
let value = parser.parse("```json\n{\"result\": 42}\n```")?;

// Route a prompt to the right model tier.
let router = LocalRouterBuilder::new(provider.clone()).build();
let choice = router.route("summarise the last 50 chat turns").await?;
println!("model = {:?}, confidence = {}", choice.model, choice.confidence);
# Ok(()) }
```

## Configuration

Enable scorers via `LocalInferenceConfig`:

```toml
[local_llm]
enabled = true
use_for_routing = true
use_for_validation = true
use_for_complexity = true
use_for_summarization = true
```

Convenience presets live on the type:

```rust
use brainwires_reasoning::LocalInferenceConfig;

let tier1  = LocalInferenceConfig::tier1_enabled();    // routing + complexity
let tier2  = LocalInferenceConfig::tier2_enabled();    // + validation + summary
let all    = LocalInferenceConfig::all_enabled();
let routing_only       = LocalInferenceConfig::routing_only();
let validation_only    = LocalInferenceConfig::validation_only();
let summarization_only = LocalInferenceConfig::summarization_only();
```

## Components

- **`plan_parser`** — extract numbered steps (`1. foo\n2. bar`) from an
  LLM plan into `ParsedStep { index, text }`. Survives leading prose and
  inter-step blank lines; `steps_to_tasks` converts to core `Task` values.
- **`output_parser`**`JsonOutputParser` (fence-aware),
  `JsonListParser`, `RegexOutputParser`. All implement the shared
  `OutputParser` trait.
- **`LocalRouter`** — pick a small/large model based on prompt length,
  entropy, and task-type cues.
- **`ComplexityScorer`** — multi-factor task-difficulty score used by
  `StrategySelector` to choose a reasoning strategy.
- **`RetrievalClassifier`** — gate retrieval behind a cheap pre-classifier
  so trivially-answerable questions skip the RAG roundtrip.
- **`RelevanceScorer`** — rerank retrieved chunks by query-aware
  relevance; pairs well with `brainwires-knowledge::SpectralReranker` for
  diversity-aware final selection.
- **`StrategySelector`** — input task → recommended strategy
  (`ChainOfThought`, `ReAct`, `Reflexion`, `TreeOfThoughts`) with a
  rationale.
- **`EntityEnhancer`** — pull typed entities and `RelationType`
  relationships out of free text.
- **`LocalSummarizer`** — offline summarisation and `ExtractedFact`
  extraction (typed by `FactCategory`).
- **`Validator`** — safety / format sanity checks on generated output.
- **`strategies`** — concrete implementations of the four reasoning
  strategies behind a shared `ReasoningStrategy` trait, selectable via
  `StrategyPreset`.

## Scope note

An earlier architectural plan (`sleepy-popping-falcon.md`) also proposed
moving the `prompting` subsystem here. It stayed in `brainwires-knowledge`
because `prompting` is tightly coupled to `bks_pks` inside that crate;
moving it would have pulled the entire knowledge-store dependency into
this layer-3 crate. The deviation is intentional — consumers of prompting
should continue to target `brainwires_knowledge::prompting`.

## Observability

Every scorer call emits a `tracing` span with `task`, `model`, `success`
and duration. `log_inference(task, model, latency_ms, success)` and the
RAII `InferenceTimer` (`finish(success)`) are the lower-level entry
points when you need to instrument custom code paths.

## Status

`#[deny(missing_docs)]`. Stable trait surface; scorers evolve additively.