Skip to main content

ironflow_core/
lib.rs

1//! # ironflow-core
2//!
3//! Core building blocks for the **ironflow** workflow engine. This crate
4//! provides composable, async operations that can be chained via plain Rust
5//! variables to build headless CI/CD, DevOps, and AI-powered workflows.
6//!
7//! # Operations
8//!
9//! | Operation | Description |
10//! |-----------|-------------|
11//! | [`Shell`](operations::shell::Shell) | Execute a shell command with timeout, env control, and `kill_on_drop`. |
12//! | [`Agent`](operations::agent::Agent) | Invoke an AI agent (Claude Code by default) with structured output support. |
13//! | [`Http`](operations::http::Http) | Perform HTTP requests via [`reqwest`] with builder-pattern ergonomics. |
14//!
15//! # Provider trait
16//!
17//! The [`AgentProvider`](provider::AgentProvider) trait abstracts the AI
18//! backend. The built-in [`ClaudeCodeProvider`](providers::claude::ClaudeCodeProvider)
19//! shells out to the `claude` CLI; swap it for
20//! [`RecordReplayProvider`](providers::record_replay::RecordReplayProvider)
21//! in tests for deterministic, zero-cost replay.
22//!
23//! # Known limitations: Structured output
24//!
25//! When using [`AgentConfig::output::<T>()`](provider::AgentConfig::output) to request
26//! structured (typed) output from the Claude CLI, be aware of these upstream bugs:
27//!
28//! | Issue | Impact |
29//! |-------|--------|
30//! | [claude-code#18536] | `structured_output` is always `null` when tools are used alongside `--json-schema`. ironflow prevents this at compile time via typestate (tools and schema are mutually exclusive). |
31//! | [claude-code#9058] | The CLI does not validate output against the provided JSON schema -- non-conforming JSON may be returned. |
32//! | [claude-agent-sdk-python#502] | Wrapper objects with a single array field may be flattened to a bare array (e.g. `[...]` instead of `{"items": [...]}`). |
33//! | [claude-agent-sdk-python#374] | The wrapping behavior is non-deterministic: the same prompt can produce differently shaped output across runs. |
34//!
35//! **Recommended workarounds:**
36//!
37//! 1. **Two-step pattern**: use one agent with tools to gather data, then a second
38//!    agent with `.output::<T>()` (no tools) to structure the result.
39//! 2. **Defensive deserialization**: when deserializing structured output, handle
40//!    both the expected wrapper object and a bare array/value as fallback.
41//! 3. **`max_turns >= 2`**: structured output requires at least 2 turns; setting
42//!    `max_turns(1)` with a schema will fail with `error_max_turns`.
43//!
44//! [claude-code#18536]: https://github.com/anthropics/claude-code/issues/18536
45//! [claude-code#9058]: https://github.com/anthropics/claude-code/issues/9058
46//! [claude-agent-sdk-python#502]: https://github.com/anthropics/claude-agent-sdk-python/issues/502
47//! [claude-agent-sdk-python#374]: https://github.com/anthropics/claude-agent-sdk-python/issues/374
48//!
49//! # Quick start
50//!
51//! ```no_run
52//! use ironflow_core::prelude::*;
53//!
54//! # async fn example() -> Result<(), OperationError> {
55//! let files = Shell::new("ls -la").await?;
56//!
57//! let provider = ClaudeCodeProvider::new();
58//! let review = Agent::new()
59//!     .prompt(&format!("Summarise:\n{}", files.stdout()))
60//!     .model(Model::HAIKU)
61//!     .max_budget_usd(0.10)
62//!     .run(&provider)
63//!     .await?;
64//!
65//! println!("{}", review.text());
66//! # Ok(())
67//! # }
68//! ```
69
70pub mod account;
71pub mod account_strategy;
72pub mod auth_proxy;
73pub mod decision;
74pub mod dry_run;
75pub mod error;
76pub mod metric_names;
77pub mod operation;
78pub mod parallel;
79pub mod pricing;
80pub mod provider;
81pub mod providers;
82pub mod retry;
83pub mod schema_transform;
84pub(crate) mod ssrf;
85#[cfg(feature = "opentelemetry")]
86pub mod telemetry;
87#[cfg(test)]
88pub(crate) mod test_support;
89pub mod trace_context;
90pub mod tracker;
91pub mod utils;
92
93/// Workflow operations (shell commands, agent calls, HTTP requests).
94pub mod operations {
95    pub mod agent;
96    pub mod http;
97    pub mod shell;
98}
99
100/// Re-exports of the most commonly used types.
101pub mod prelude {
102    pub use crate::account::{
103        AccountCredential, AccountKind, AccountSession, AccountWindow, ClaudeSubscriptionKind,
104        RateLimitRecorder, WindowStatus,
105    };
106    pub use crate::account_strategy::{AccountCandidate, AccountStrategy, select_account};
107    pub use crate::decision::{
108        ChoiceAnswer, DecisionAnswer, DecisionOutput, DecisionProvider, DecisionQuestion,
109        DecisionRequest, DecisionUsage, NoulAnswer, NoulCriteria, ScoreAnswer,
110    };
111    pub use crate::dry_run::{DryRunGuard, is_dry_run, set_dry_run};
112    pub use crate::error::{AgentError, DecisionError, OperationError};
113    pub use crate::operation::{
114        NoopSecretResolver, Operation, OperationContext, SecretResolver, SecretValue,
115        TypedOperation,
116    };
117    pub use crate::operations::agent::{Agent, AgentResult, Model, PermissionMode};
118    pub use crate::operations::http::{Http, HttpOutput};
119    pub use crate::operations::shell::{Shell, ShellOutput};
120    pub use crate::parallel::{try_join_all, try_join_all_limited};
121    pub use crate::pricing::{CostBreakdown, ModelPricing, PricingSource, StaticPricing};
122    pub use crate::provider::{AgentConfig, AgentProvider, DebugMessage, DebugToolCall, LogSink};
123    pub use crate::providers::claude::ClaudeCodeProvider;
124    pub use crate::providers::record_replay::RecordReplayProvider;
125    pub use crate::providers::record_replay_decision::RecordReplayDecisionProvider;
126
127    #[cfg(feature = "provider-typesafe")]
128    pub use crate::providers::http::TypeSafeProvider;
129    pub use crate::retry::RetryPolicy;
130    pub use crate::trace_context::WorkflowTraceContext;
131    pub use crate::tracker::WorkflowTracker;
132    pub use schemars::JsonSchema;
133    pub use serde::{Deserialize, Serialize};
134
135    #[cfg(feature = "provider-anthropic-api")]
136    pub use crate::providers::http::AnthropicApiProvider;
137    #[cfg(feature = "provider-gemini")]
138    pub use crate::providers::http::GeminiProvider;
139    #[cfg(feature = "provider-mistral")]
140    pub use crate::providers::http::MistralProvider;
141    #[cfg(feature = "provider-nvidia")]
142    pub use crate::providers::http::NvidiaProvider;
143    #[cfg(feature = "provider-openai")]
144    pub use crate::providers::http::OpenAiProvider;
145
146    pub use crate::providers::router::{ProviderMatcher, ProviderRouter};
147}