Skip to main content

llm_pipeline/
lib.rs

1//! # LLM Pipeline
2//!
3//! Reusable node payloads for LLM workflows, with optional sequential chaining.
4//!
5//! This crate provides the building blocks for LLM-powered workflows:
6//! **payloads** that execute LLM calls, **parsing utilities** for messy
7//! model output, and a **chain** helper for sequential composition.
8//!
9//! Orchestration (routing, loops, concurrency, checkpoints) belongs in your
10//! graph runtime (e.g. LangGraph). This crate provides what runs *inside*
11//! each node.
12//!
13//! ## Core Concepts
14//!
15//! - **[`Payload`]** — object-safe trait for executable units. Takes a
16//!   `serde_json::Value` input, returns a [`PayloadOutput`].
17//! - **[`ExecCtx`]** — shared execution context (HTTP client, endpoint,
18//!   template vars, cancellation, optional event handler).
19//! - **[`LlmCall`]** — the primary payload: renders prompts, calls Ollama,
20//!   parses responses.
21//! - **[`Chain`]** — sequential composition of payloads.
22//! - **[`PayloadOutput`]** — `Value`-based output with `parse_as::<T>()` for
23//!   typed extraction at workflow edges.
24//!
25//! ## Quick Start (Payload API)
26//!
27//! ```no_run
28//! use llm_pipeline::{LlmCall, Chain, ExecCtx};
29//! use llm_pipeline::payload::Payload;
30//! use serde::Deserialize;
31//! use serde_json::json;
32//!
33//! #[derive(Debug, Deserialize)]
34//! struct Analysis { summary: String }
35//!
36//! #[tokio::main]
37//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
38//!     let ctx = ExecCtx::builder("http://localhost:11434").build();
39//!
40//!     let chain = Chain::new("analyze")
41//!         .push(Box::new(
42//!             LlmCall::new("draft", "Analyze: {input}")
43//!                 .with_config(llm_pipeline::LlmConfig::default().with_json_mode(true))
44//!         ))
45//!         .push(Box::new(
46//!             LlmCall::new("refine", "Refine this analysis: {input}")
47//!                 .with_config(llm_pipeline::LlmConfig::default().with_json_mode(true))
48//!         ));
49//!
50//!     let output = chain.execute(&ctx, json!("Your text here")).await?;
51//!     let result: Analysis = output.parse_as()?;
52//!     println!("{}", result.summary);
53//!     Ok(())
54//! }
55//! ```
56//!
57//! ## Pipeline API (compatibility)
58//!
59//! The original `Pipeline<T>` API is still available and works as before.
60//! Internally it now uses [`LlmCall`] payloads.
61//!
62//! ```no_run
63//! use llm_pipeline::{Pipeline, Stage, PipelineInput};
64//! use serde::{Deserialize, Serialize};
65//!
66//! #[derive(Debug, Clone, Serialize, Deserialize)]
67//! struct Analysis { summary: String, insights: Vec<String> }
68//!
69//! #[tokio::main]
70//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
71//!     let client = reqwest::Client::new();
72//!     let pipeline = Pipeline::<Analysis>::builder()
73//!         .add_stage(Stage::new("analyze", "Analyze: {input}").with_json_mode(true))
74//!         .add_stage(Stage::new("refine", "Refine: {input}").with_json_mode(true))
75//!         .build()?;
76//!
77//!     let result = pipeline.execute(
78//!         &client, "http://localhost:11434", PipelineInput::new("Your text"),
79//!     ).await?;
80//!     println!("{}", result.final_output.summary);
81//!     Ok(())
82//! }
83//! ```
84
85// --- New payload layer ---
86pub mod backend;
87pub mod chain;
88pub mod diagnostics;
89pub mod events;
90#[allow(deprecated)]
91pub mod exec_ctx;
92pub mod limits;
93pub mod llm_call;
94pub mod output_parser;
95pub mod output_strategy;
96pub mod parsing;
97#[allow(deprecated)]
98pub mod payload;
99pub mod retry;
100pub mod retry_policy;
101pub mod streaming;
102pub mod tool_loop;
103#[allow(deprecated)]
104pub mod trace;
105
106// --- Original modules (still public) ---
107pub mod client;
108pub mod error;
109#[allow(deprecated)]
110pub mod pipeline;
111pub mod prompt;
112pub mod stage;
113pub mod types;
114
115// --- Primary exports: new payload API ---
116#[cfg(feature = "openai")]
117pub use backend::OpenAiBackend;
118pub use backend::{BackoffConfig, MockBackend, OllamaBackend, RecordingBackend};
119pub use chain::Chain;
120pub use diagnostics::ParseDiagnostics;
121pub use exec_ctx::{ExecCtx, ExecCtxBuilder};
122pub use limits::PipelineLimits;
123pub use llm_call::LlmCall;
124pub use output_strategy::OutputStrategy;
125pub use payload::{BoxFut, Payload, PayloadOutput};
126pub use retry::RetryConfig;
127pub use retry_policy::{SemanticRetryPolicy, TransportRetryPolicy};
128pub use streaming::StreamingDecoder;
129pub use tool_loop::{
130    ToolInvocation, ToolLoopChoice, ToolLoopRequest, ToolLoopResponse, ToolLoopRunner,
131};
132#[allow(deprecated)]
133pub use trace::TraceId;
134
135// --- Canonical cross-crate trace/identity re-exports from stack-ids ---
136pub use stack_ids::TraceCtx;
137
138// --- Re-exports: original API (compatibility) ---
139pub use client::LlmConfig;
140pub use error::{PipelineError, Result};
141pub use pipeline::{Pipeline, PipelineBuilder};
142pub use stage::{Stage, StageBuilder};
143pub use types::{
144    BudgetDebitV1, ExecutionOutcome, PipelineContext, PipelineExecutionReceiptV1, PipelineInput,
145    PipelineProgress, PipelineResult, ProviderCallReceiptV1, RetrievedContextProvenanceV1,
146    RetryCause, RetryDecision, RetryDecisionReceiptV1, StageOutput,
147};