forge-core
Core types, provider traits, telemetry, and configuration for the Forge SDK
Core types, provider traits, telemetry, and configuration for the Forge SDK
Package contract
| Field | Value |
|---|---|
| Language | rust |
| Source version | 0.2.0 |
| Manifest | forge-rs/crates/forge-core/Cargo.toml |
| Source files | 18 |
| Evidence | Source reference; registry publication and runtime conformance are separate checks |
Import boundary
use forge_core;Use a source checkout or your verified private registry. Manifest coordinates identify the package; they do not establish that a public registry release exists.
Crate boundary
The following entries are taken from src/lib.rs. Feature conditions in the exact source still apply.
pub mod brew;
pub mod brew_builder;
pub mod brew_resolver;
pub mod config;
pub mod error;
pub mod message;
pub mod model;
pub mod output;
pub mod provider;
pub mod provider_runtime;
pub mod replay;
pub mod routing;
pub mod schema;
pub mod telemetry;
pub mod tool;
pub mod topology;
pub mod types;
pub mod prelude;
pub use crate::brew::{
Brew, BrewEdge, BrewEdgeKind, BrewId, BrewNode, BrewNodeKind, BrewVersion, JoinMode, NodeId,
};
pub use crate::brew_builder::BrewBuilder;
pub use crate::brew_resolver::{
BrewEnvironment, BrewResolutionError, BrewResolutionErrorKind, ResolvedBrewPlan,
ResolvedNode, ResolvedNodeKind,
};
pub use crate::config::{EmbedOptions, GenerateOptions};
pub use crate::error::{ForgeError, ForgeResult};
pub use crate::message::{MessagePart, ModelMessage, Role};
pub use crate::model::LanguageModel;
pub use crate::output::{FinishReason, GenerateResult, StreamChunk, Usage};
pub use crate::provider::{ProviderRef, ProviderRegistry};
pub use crate::provider_runtime::{
ProviderNegotiationRequest, ProviderNegotiationResult, ProviderRuntimeCapabilities,
ProviderSessionEvent, ProviderSessionState, ProviderUsageSummary, RuntimeCapability,
};
pub use crate::replay::{
legacy_accept_from_env, ReplayConfig, ReplayError, ReplayValidator, DEFAULT_CLOCK_SKEW,
DEFAULT_NONCE_CACHE_SIZE,
};
pub use crate::routing::{
DefaultModelRouter, ExecutionTopology, ModelRouter, ResolvedRoute, RoutingContext, TaskMode,
};
pub use crate::schema::JsonSchema;
pub use crate::telemetry::{ForgeEvent, ForgeSpan, TelemetryEmitter};
pub use crate::tool::{ToolApproval, ToolCall, ToolDefinition, ToolResult, ToolTier};
pub use crate::topology::{
CostPreference, LatencyPreference, ModelSlot, ModelTopology, TopologyBuilder,
};
pub use crate::types::{AgentDid, Timestamp};Source reference
Download package reference JSON. Each original source file and generated declaration artifact has its own SHA-256 digest. Function bodies and constant values are omitted from downloads. These are source declaration inventories, not compiler-resolved rustdoc, TypeDoc, DocC, or Dokka output. Private modules can contain public declarations that are not reachable through the package boundary; consult the entry point before importing.
brew.rs
Read declaration text · 15 declaration entries
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct BrewId(String);
pub fn new(id: impl Into<String>) -> Self;
pub fn as_str(&self) -> &str;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct NodeId(String);
pub fn new(id: impl Into<String>) -> Self;
pub fn as_str(&self) -> &str;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct BrewVersion(String);
pub fn new(version: impl Into<String>) -> Self;
pub fn as_str(&self) -> &str;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum JoinMode {
/// Wait for all branches to complete. Fail if any branch fails.
AwaitAll,
/// Return as soon as one branch completes successfully.
FirstSuccess,
/// Return as soon as N branches complete successfully.
FirstN(u32),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum BrewNodeKind {
/// An agent step: send a prompt to a model, optionally with tools.
///
/// Maps to a single invocation of the Forge agent execution loop.
AgentStep {
/// Provider reference (e.g., `openai:gpt-4o`). Symbolic -- resolved
/// during the freeze step.
provider: ProviderRef,
/// Optional system prompt for this step.
#[serde(default, skip_serializing_if = "Option::is_none")]
system_prompt: Option<String>,
/// Maximum tool-loop steps for this agent invocation.
max_steps: u32,
},
/// A direct tool invocation without an LLM in the loop.
ToolInvocation {
/// Tool identifier. Must resolve to a registered tool at freeze time.
tool_id: String,
/// Tool tier classification.
tier: ToolTier,
},
/// An MCP tool call routed through a connected MCP server.
McpCall {
/// MCP server identifier (URI or alias).
server_id: String,
/// MCP tool name on the remote server.
tool_name: String,
},
/// A web operation (HTTP request, browser action, etc.).
WebOperation {
/// The operation kind identifier.
operation: String,
},
/// A conditional branch that routes to one of two targets based on a
/// condition expression.
ConditionalBranch {
/// JSONPath or simple expression evaluated against incoming data.
condition_expr: String,
/// The node to route to when the condition is true.
true_target: NodeId,
/// The node to route to when the condition is false.
false_target: NodeId,
},
/// A parallel fork that spawns concurrent execution of multiple
/// downstream paths, then joins their results.
ParallelFork {
/// The set of branch targets to execute concurrently.
branches: Vec<NodeId>,
/// Strategy for joining parallel results.
join_mode: JoinMode,
},
/// A reference to another brew, enabling composition. The referenced
/// brew is resolved and inlined at freeze time.
SubBrewRef {
/// The referenced brew's identifier.
brew_id: BrewId,
},
/// A human-in-the-loop checkpoint that suspends execution until a
/// human provides approval or input.
HumanCheckpoint {
/// The prompt displayed to the human reviewer.
prompt: String,
/// Maximum wait time in milliseconds before timeout. `None` means
/// wait indefinitely.
#[serde(default, skip_serializing_if = "Option::is_none")]
timeout_ms: Option<u64>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BrewNode {
/// Stable identifier within this brew.
pub id: NodeId,
/// The node's execution semantics.
pub kind: BrewNodeKind,
/// Arbitrary key-value metadata for tooling and visualization.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub metadata: BTreeMap<String, String>
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum BrewEdgeKind {
/// Data flow: output of source is fed as input to target.
DataFlow,
/// Control flow: target executes after source completes.
ControlFlow,
/// Error flow: target executes when source fails.
ErrorFlow,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct BrewEdge {
/// Source node.
pub from: NodeId,
/// Target node.
pub to: NodeId,
/// Edge semantics.
pub kind: BrewEdgeKind
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Brew {
/// Unique identifier for this brew definition.
pub id: BrewId,
/// Semantic version of this brew definition.
pub version: BrewVersion,
/// The graph's nodes, keyed by stable node ID.
/// `BTreeMap` ensures deterministic serialization order.
pub nodes: BTreeMap<NodeId, BrewNode>,
/// The graph's edges. `BTreeSet` ensures deterministic ordering
/// by `(from, to, kind)`.
pub edges: BTreeSet<BrewEdge>,
/// Designated entry nodes. Execution begins at these nodes.
pub entry_nodes: Vec<NodeId>,
/// Designated exit nodes. When all exit nodes complete, the brew
/// execution is complete.
pub exit_nodes: Vec<NodeId>,
/// Optional model topology for this brew. When set, it provides
/// the multi-model slot configuration for agent steps.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub topology: Option<ModelTopology>
}brew_builder.rs
Read declaration text · 9 declaration entries
#[derive(Debug)]
pub struct BrewBuilder {
}
pub fn new(id: impl Into<String>, version: impl Into<String>) -> Self;
pub fn add_node(&mut self, node_id: impl Into<String>, kind: BrewNodeKind) -> &mut Self;
pub fn add_edge(
&mut self,
from: impl Into<String>,
to: impl Into<String>,
edge_kind: BrewEdgeKind,
) -> &mut Self;
pub fn set_entry(&mut self, node_id: impl Into<String>) -> &mut Self;
pub fn set_exit(&mut self, node_id: impl Into<String>) -> &mut Self;
pub fn with_topology(&mut self, topology: ModelTopology) -> &mut Self;
pub fn with_metadata(
&mut self,
node_id: impl AsRef<str>,
key: impl Into<String>,
value: impl Into<String>,
) -> &mut Self;
pub fn build(&mut self) -> ForgeResult<Brew>;brew_resolver.rs
Read declaration text · 7 declaration entries
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BrewEnvironment {
/// Registered model providers, keyed by their `namespace:model` string.
pub providers: BTreeMap<String, ProviderRef>,
/// Registered tool names available in this environment.
pub tools: BTreeSet<String>,
/// Connected MCP server identifiers (URIs or aliases).
pub mcp_servers: BTreeSet<String>,
/// Web capabilities available in this environment.
pub web_capabilities: BTreeSet<String>,
/// Brew definitions available for sub-brew composition.
pub sub_brews: BTreeSet<BrewId>
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum BrewResolutionErrorKind {
/// A provider reference in an `AgentStep` node is not registered.
ProviderUnavailable,
/// A tool name in a `ToolInvocation` node is not registered.
ToolNotFound,
/// An MCP server in an `McpCall` node is not connected.
McpServerNotFound,
/// A web capability in a `WebOperation` node is not available.
WebCapabilityUnavailable,
/// A sub-brew reference in a `SubBrewRef` node is not in the registry.
SubBrewNotFound,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BrewResolutionError {
/// The node that failed resolution.
pub node_id: NodeId,
/// What went wrong.
pub error_kind: BrewResolutionErrorKind
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ResolvedNodeKind {
/// Agent step with verified provider.
AgentStep {
/// Verified provider reference.
provider: ProviderRef,
/// Optional system prompt.
#[serde(default, skip_serializing_if = "Option::is_none")]
system_prompt: Option<String>,
/// Maximum tool-loop steps.
max_steps: u32,
},
/// Tool invocation with verified tool name.
ToolInvocation {
/// Verified tool identifier.
tool_id: String,
/// Tool tier classification.
tier: ToolTier,
},
/// MCP call with verified server and tool.
McpCall {
/// Verified MCP server identifier.
server_id: String,
/// Tool name on the remote server.
tool_name: String,
},
/// Web operation with verified capability.
WebOperation {
/// Verified operation kind.
operation: String,
},
/// Conditional branch with verified targets.
ConditionalBranch {
/// Condition expression.
condition_expr: String,
/// Verified true target.
true_target: NodeId,
/// Verified false target.
false_target: NodeId,
},
/// Parallel fork with verified branches.
ParallelFork {
/// Verified branch targets.
branches: Vec<NodeId>,
/// Join strategy.
join_mode: JoinMode,
},
/// Sub-brew reference (verified to exist).
SubBrewRef {
/// Verified brew identifier.
brew_id: BrewId,
},
/// Human checkpoint (no external references to verify).
HumanCheckpoint {
/// Prompt text.
prompt: String,
/// Optional timeout.
#[serde(default, skip_serializing_if = "Option::is_none")]
timeout_ms: Option<u64>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResolvedNode {
/// The node identifier.
pub id: NodeId,
/// The resolved (verified) node kind.
pub kind: ResolvedNodeKind
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResolvedBrewPlan {
/// Deterministic plan identifier: `BLAKE3(brew_id || brew_version ||
/// environment_hash)`. Does **not** include timestamps.
pub plan_id: String,
/// The source brew's identifier.
pub brew_id: BrewId,
/// The source brew's version.
pub brew_version: BrewVersion,
/// ISO 8601 timestamp of when resolution occurred. Runtime metadata,
/// **not** included in `plan_id`.
pub resolved_at: String,
/// BLAKE3 hash of the serialized `BrewEnvironment`.
pub environment_hash: String,
/// Resolved nodes keyed by node ID.
pub nodes: BTreeMap<NodeId, ResolvedNode>,
/// Edges from the original brew (unchanged -- edges carry no symbolic
/// references that need resolution).
pub edges: BTreeSet<BrewEdge>,
/// Topologically sorted execution order.
pub execution_order: Vec<NodeId>,
/// Entry nodes from the original brew.
pub entry_nodes: Vec<NodeId>,
/// Exit nodes from the original brew.
pub exit_nodes: Vec<NodeId>
}
pub fn resolve(
brew: &Brew,
environment: &BrewEnvironment,
) -> Result<ResolvedBrewPlan, Vec<BrewResolutionError>>;config.rs
Read declaration text · 13 declaration entries
pub use crate::replay::{ReplayConfig, DEFAULT_CLOCK_SKEW, DEFAULT_NONCE_CACHE_SIZE};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct GenerateOptions {
/// Sampling temperature (0.0 = deterministic, 2.0 = maximum randomness).
#[serde(skip_serializing_if = "Option::is_none")]
pub temperature: Option<f64>,
/// Maximum tokens to generate.
#[serde(skip_serializing_if = "Option::is_none")]
pub max_tokens: Option<u32>,
/// Top-p (nucleus) sampling threshold.
#[serde(skip_serializing_if = "Option::is_none")]
pub top_p: Option<f64>,
/// Stop sequences — generation stops when any of these are produced.
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_sequences: Option<Vec<String>>,
/// Frequency penalty (-2.0 to 2.0).
#[serde(skip_serializing_if = "Option::is_none")]
pub frequency_penalty: Option<f64>,
/// Presence penalty (-2.0 to 2.0).
#[serde(skip_serializing_if = "Option::is_none")]
pub presence_penalty: Option<f64>,
/// Seed for deterministic generation (if supported by provider).
#[serde(skip_serializing_if = "Option::is_none")]
pub seed: Option<u64>,
/// JSON schema for structured output enforcement.
#[serde(skip_serializing_if = "Option::is_none")]
pub output_schema: Option<JsonSchema>
}
pub fn with_temperature(mut self, temperature: f64) -> Self;
pub fn with_max_tokens(mut self, max_tokens: u32) -> Self;
pub fn with_top_p(mut self, top_p: f64) -> Self;
pub fn with_stop_sequences(mut self, sequences: Vec<String>) -> Self;
pub fn with_frequency_penalty(mut self, penalty: f64) -> Self;
pub fn with_presence_penalty(mut self, penalty: f64) -> Self;
pub fn with_seed(mut self, seed: u64) -> Self;
pub fn with_output_schema(mut self, schema: JsonSchema) -> Self;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct EmbedOptions {
/// The embedding model to use (if different from default).
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
/// Dimensionality of the output embeddings (if configurable).
#[serde(skip_serializing_if = "Option::is_none")]
pub dimensions: Option<u32>
}
pub fn with_model(mut self, model: impl Into<String>) -> Self;
pub fn with_dimensions(mut self, dimensions: u32) -> Self;error.rs
Read declaration text · 2 declaration entries
#[derive(Debug, Error)]
pub enum ForgeError {
/// A provider was not found in the registry.
#[error("provider '{provider_ref}' not found in registry; register it with ProviderRegistry::register() before use")]
ProviderNotFound {
/// The provider reference that was looked up (e.g., "openai:gpt-4o").
provider_ref: String,
},
/// A provider reference string is malformed.
#[error("invalid provider reference '{input}': expected format 'namespace:model' (e.g., 'openai:gpt-4o')")]
InvalidProviderRef {
/// The malformed input string.
input: String,
},
/// JSON schema validation failed.
#[error("schema validation failed at path '{path}': {reason}")]
SchemaValidation {
/// JSON pointer path to the failing field.
path: String,
/// Human-readable description of what was expected.
reason: String,
},
/// An invalid lifecycle state transition was attempted.
///
/// See ANVIL Spec §5.1 — Lifecycle State Machine for valid transitions.
#[error("invalid lifecycle transition from {from} to {to}: {reason} (see ANVIL Spec §5.1)")]
InvalidLifecycleTransition {
/// The current state.
from: String,
/// The attempted target state.
to: String,
/// Why this transition is invalid.
reason: String,
},
/// A tool invocation was denied due to insufficient capabilities.
#[error("tool '{tool_name}' invocation denied: agent {agent_did} lacks capability '{required_capability}' in Arsenal ACT {act_id}")]
ToolInvocationDenied {
/// The tool that was being invoked.
tool_name: String,
/// The agent's DID.
agent_did: String,
/// The capability that was required but missing.
required_capability: String,
/// The ACT that was checked.
act_id: String,
},
/// A tool execution failed.
#[error("tool '{tool_name}' execution failed: {reason}")]
ToolExecutionFailed {
/// The tool that failed.
tool_name: String,
/// What went wrong.
reason: String,
},
/// JSON serialization or deserialization failed.
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
/// A required configuration value is missing.
#[error("missing configuration: {field} is required ({hint})")]
MissingConfig {
/// The configuration field name.
field: String,
/// A hint about where to set this value.
hint: String,
},
/// The stop condition limit was reached.
#[error("generation stopped: {reason} (steps={steps}, tokens={tokens})")]
StopConditionReached {
/// Why generation was stopped.
reason: String,
/// Number of steps completed.
steps: u32,
/// Total tokens consumed.
tokens: u64,
},
/// A telemetry emission failed. Non-fatal but logged.
#[error("telemetry emission failed: {reason}")]
TelemetryError {
/// What went wrong with telemetry.
reason: String,
},
/// The model does not support the requested operation.
#[error("model '{model}' does not support {operation}")]
UnsupportedOperation {
/// The model identifier.
model: String,
/// The operation that was requested.
operation: String,
},
/// The provider exists but is not currently available.
#[error("provider '{provider_ref}' is unavailable: {reason}")]
ProviderUnavailable {
/// The provider reference that could not be used.
provider_ref: String,
/// Human-readable unavailability reason.
reason: String,
},
/// Provider authentication failed.
#[error("provider '{provider_ref}' authentication failed: {reason}")]
ProviderAuthenticationFailed {
/// The provider reference that failed authentication.
provider_ref: String,
/// Human-readable authentication failure reason.
reason: String,
},
/// The provider does not support a required runtime capability.
#[error("provider '{provider_ref}' does not support runtime capability '{capability}'")]
CapabilityUnsupported {
/// The provider reference that was negotiated.
provider_ref: String,
/// The missing runtime capability.
capability: String,
},
/// Provider runtime negotiation failed.
#[error("provider '{provider_ref}' negotiation failed: {reason}")]
ProviderNegotiationFailed {
/// The provider reference that was negotiated.
provider_ref: String,
/// Human-readable negotiation failure reason.
reason: String,
},
/// The provider session expired before the requested action could complete.
#[error("provider '{provider_ref}' session '{session_id}' expired before the requested action completed")]
ProviderSessionExpired {
/// The provider reference for the expired session.
provider_ref: String,
/// The expired session identifier.
session_id: String,
},
/// The provider does not support interrupts.
#[error("provider '{provider_ref}' does not support session interrupts")]
ProviderInterruptUnsupported {
/// The provider reference that lacks interrupt support.
provider_ref: String,
},
/// The provider does not support resuming sessions.
#[error("provider '{provider_ref}' does not support session resume")]
ProviderResumeUnsupported {
/// The provider reference that lacks resume support.
provider_ref: String,
},
/// An internal error that should not occur in normal operation.
#[error("internal error: {0}")]
Internal(String),
}
pub type ForgeResult<T> = Result<T, ForgeError>;lib.rs
Read declaration text · 35 declaration entries
pub mod brew;
pub mod brew_builder;
pub mod brew_resolver;
pub mod config;
pub mod error;
pub mod message;
pub mod model;
pub mod output;
pub mod provider;
pub mod provider_runtime;
pub mod replay;
pub mod routing;
pub mod schema;
pub mod telemetry;
pub mod tool;
pub mod topology;
pub mod types;
pub mod prelude;
pub use crate::brew::{
Brew, BrewEdge, BrewEdgeKind, BrewId, BrewNode, BrewNodeKind, BrewVersion, JoinMode, NodeId,
};
pub use crate::brew_builder::BrewBuilder;
pub use crate::brew_resolver::{
BrewEnvironment, BrewResolutionError, BrewResolutionErrorKind, ResolvedBrewPlan,
ResolvedNode, ResolvedNodeKind,
};
pub use crate::config::{EmbedOptions, GenerateOptions};
pub use crate::error::{ForgeError, ForgeResult};
pub use crate::message::{MessagePart, ModelMessage, Role};
pub use crate::model::LanguageModel;
pub use crate::output::{FinishReason, GenerateResult, StreamChunk, Usage};
pub use crate::provider::{ProviderRef, ProviderRegistry};
pub use crate::provider_runtime::{
ProviderNegotiationRequest, ProviderNegotiationResult, ProviderRuntimeCapabilities,
ProviderSessionEvent, ProviderSessionState, ProviderUsageSummary, RuntimeCapability,
};
pub use crate::replay::{
legacy_accept_from_env, ReplayConfig, ReplayError, ReplayValidator, DEFAULT_CLOCK_SKEW,
DEFAULT_NONCE_CACHE_SIZE,
};
pub use crate::routing::{
DefaultModelRouter, ExecutionTopology, ModelRouter, ResolvedRoute, RoutingContext, TaskMode,
};
pub use crate::schema::JsonSchema;
pub use crate::telemetry::{ForgeEvent, ForgeSpan, TelemetryEmitter};
pub use crate::tool::{ToolApproval, ToolCall, ToolDefinition, ToolResult, ToolTier};
pub use crate::topology::{
CostPreference, LatencyPreference, ModelSlot, ModelTopology, TopologyBuilder,
};
pub use crate::types::{AgentDid, Timestamp};message.rs
Read declaration text · 17 declaration entries
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Role {
/// System instructions that configure agent behavior.
System,
/// User-provided input.
User,
/// Model-generated output.
Assistant,
/// Tool execution results.
Tool,
}
pub fn as_str(&self) -> &'static str;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum MessagePart {
/// Plain text content.
Text {
/// The text content.
text: String,
},
/// An image (base64 or URL).
Image {
/// Base64-encoded image data, or a URL.
data: String,
/// MIME type (e.g., "image/png").
media_type: String,
},
/// A tool call request from the model.
ToolCall {
/// Unique identifier for this tool call.
id: String,
/// The tool name.
name: String,
/// JSON arguments for the tool.
arguments: serde_json::Value,
},
/// A result from a tool execution.
ToolResult {
/// The tool call ID this result corresponds to.
tool_call_id: String,
/// The tool name.
name: String,
/// The result content (typically stringified).
content: String,
/// Whether the tool execution resulted in an error.
is_error: bool,
},
}
pub fn text(text: impl Into<String>) -> Self;
pub fn image(data: impl Into<String>, media_type: impl Into<String>) -> Self;
pub fn tool_call(
id: impl Into<String>,
name: impl Into<String>,
arguments: serde_json::Value,
) -> Self;
pub fn tool_result(
tool_call_id: impl Into<String>,
name: impl Into<String>,
content: impl Into<String>,
is_error: bool,
) -> Self;
pub fn is_tool_call(&self) -> bool;
pub fn is_tool_result(&self) -> bool;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ModelMessage {
}
pub fn new(role: Role, parts: Vec<MessagePart>) -> Self;
pub fn text(role: Role, text: impl Into<String>) -> Self;
pub fn role(&self) -> Role;
pub fn parts(&self) -> &[MessagePart];
pub fn parts_mut(&mut self) -> &mut Vec<MessagePart>;
pub fn tool_calls(&self) -> Vec<&MessagePart>;
pub fn text_content(&self) -> String;model.rs
Read declaration text · 5 declaration entries
pub type StreamChunkResult = ForgeResult<StreamChunk>;
pub type ChunkStream<'a> = Pin<Box<dyn Stream<Item = StreamChunkResult> + Send + 'a>>;
pub fn buffered_into_chunks(chunks: Vec<StreamChunk>) -> ChunkStream<'static>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelCapabilities {
/// Whether the model supports text generation.
pub text_generation: bool,
/// Whether the model supports structured output (JSON mode).
pub structured_output: bool,
/// Whether the model supports tool calling.
pub tool_calling: bool,
/// Whether the model supports vision (image input).
pub vision: bool,
/// Whether the model supports audio input/output.
pub audio: bool,
/// Whether the model supports embedding generation.
pub embedding: bool,
/// Maximum number of tokens in the context window.
pub max_context_tokens: u32,
/// Maximum number of tokens the model can generate in a single response.
pub max_output_tokens: u32
}
#[async_trait]
pub trait LanguageModel: Send + Sync {
/// Returns the model identifier (e.g., "gpt-4o", "claude-sonnet-4-5-20250929").
fn model_id(&self) -> &str;
/// Returns the provider namespace (e.g., "openai", "anthropic").
fn provider(&self) -> &str;
/// Generates a complete response from the model.
///
/// # Arguments
///
/// * `messages` - The conversation history.
/// * `tools` - Available tool definitions for this inference call.
/// * `options` - Generation options (temperature, max_tokens, etc.).
///
/// # Returns
///
/// A `GenerateResult` containing the model's response, usage statistics,
/// and finish reason.
///
/// # Errors
///
/// Returns `ForgeError` if the provider call fails, times out, or returns
/// an invalid response.
async fn generate(
&self,
messages: &[ModelMessage],
tools: &[ToolDefinition],
options: &GenerateOptions,
) -> ForgeResult<GenerateResult>;
/// Streams a response from the model as chunks.
///
/// **Deprecated.** Returns the full `Vec<StreamChunk>` after the upstream
/// provider has yielded its terminal `Done`. Despite the name, this
/// method does not deliver chunks incrementally — use
/// [`stream_chunks`](Self::stream_chunks) for real per-token streaming.
///
/// Will be removed in v0.3.0 once every in-tree provider has a native
/// [`stream_chunks`] implementation.
///
/// # Errors
///
/// Returns `ForgeError` if the provider call fails.
#[deprecated(
since = "0.2.0",
note = "use `stream_chunks` for real per-token streaming; this method buffers the entire response before returning. Will be removed in 0.3.0."
)]
async fn stream(
&self,
messages: &[ModelMessage],
tools: &[ToolDefinition],
options: &GenerateOptions,
) -> ForgeResult<Vec<StreamChunk>>;
/// **Real per-token streaming.** Returns a stream that yields each chunk
/// as soon as the upstream provider produces it on the wire.
///
/// Per RFC 0001 (`rfcs/0001-stream-chunks.md`): each item is itself a
/// `Result` so mid-stream errors don't lose already-received chunks. The
/// outer `Result` covers connect-time failures (DNS, TLS, auth, malformed
/// request); per-item `Err` covers mid-stream failures.
///
/// # Default implementation (TRANSITIONAL)
///
/// The default impl calls the (deprecated) [`stream`](Self::stream) method
/// and wraps the resulting `Vec<StreamChunk>` via [`buffered_into_chunks`].
/// **This is a transitional shim — it is NOT real streaming.** It exists
/// only so existing providers compile against the new trait method while
/// they are being rewritten one at a time for native streaming.
///
/// **Providers MUST override this method with a native streaming
/// implementation before 0.3.0.** Once every in-tree provider has a
/// native `stream_chunks`, the default will be removed (the trait method
/// becomes required) and `stream` will be deleted entirely.
///
/// To find providers that still rely on the default impl, grep for
/// `buffered_into_chunks` in their `stream_chunks` method body — that's
/// the native-streaming migration checklist.
///
/// # Arguments
///
/// * `messages` - The conversation history.
/// * `tools` - Available tool definitions for this inference call.
/// * `options` - Generation options.
///
/// # Returns
///
/// A [`ChunkStream`] that yields [`StreamChunkResult`] items.
///
/// # Errors
///
/// - Outer `ForgeResult<...>` returns `Err` for connect-time failures.
/// - Per-item `Err` for mid-stream failures (caller decides whether to
/// abort the stream).
async fn stream_chunks(
&self,
messages: &[ModelMessage],
tools: &[ToolDefinition],
options: &GenerateOptions,
) -> ForgeResult<ChunkStream<'static>> ;
/// Returns `true` if this model supports tool calling.
fn supports_tool_calling(&self) -> bool ;
/// Returns `true` if this model supports structured output (JSON mode).
fn supports_structured_output(&self) -> bool ;
/// Returns `true` if this model supports image input.
fn supports_image_input(&self) -> bool ;
/// Returns `true` if this model supports streaming.
fn supports_streaming(&self) -> bool ;
/// Returns the model's capabilities.
///
/// The default implementation constructs a [`ModelCapabilities`] from the
/// individual `supports_*` methods. Override this to provide accurate values
/// for `max_context_tokens` and `max_output_tokens`.
///
/// # ANVIL Spec Reference
///
/// ANVIL Spec section 6.2 -- Model Capabilities.
///
/// # Returns
///
/// A [`ModelCapabilities`] describing what this model can do.
fn capabilities(&self) -> ModelCapabilities ;
}output.rs
Read declaration text · 23 declaration entries
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenerateResult {
/// The model's response message.
pub message: ModelMessage,
/// Why generation stopped.
pub finish_reason: FinishReason,
/// Token usage statistics.
pub usage: Usage
}
pub fn text(&self) -> String;
pub fn has_tool_calls(&self) -> bool;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum FinishReason {
/// The model produced a natural stop.
Stop,
/// The maximum token limit was reached.
MaxTokens,
/// The model requested tool calls.
ToolCalls,
/// A stop sequence was matched.
StopSequence,
/// A content filter blocked the output.
ContentFilter,
/// An error occurred during generation.
Error,
}
pub fn is_complete(&self) -> bool;
pub fn is_tool_call(&self) -> bool;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Usage {
/// Tokens consumed by the input prompt.
pub prompt_tokens: u64,
/// Tokens generated in the response.
pub completion_tokens: u64,
/// Total tokens (prompt + completion).
pub total_tokens: u64
}
pub fn zero() -> Self;
pub fn add(&self, other: &Usage) -> Usage;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum StreamChunk {
/// A text content delta.
TextDelta {
/// The text fragment.
text: String,
},
/// A tool call delta (streaming tool arguments).
ToolCallDelta {
/// The tool call index (for parallel tool calls).
index: u32,
/// The tool call ID (may be empty until fully received).
id: String,
/// The tool name (may be empty until fully received).
name: String,
/// Partial JSON arguments.
arguments_delta: String,
},
/// Signals the start of a tool call.
///
/// Emitted when the model begins a tool invocation. The `id` uniquely
/// identifies the tool call, and `name` is the tool being invoked.
ToolCallStart {
/// The tool call ID.
id: String,
/// The tool name being called.
name: String,
},
/// Signals the end of a tool call.
///
/// Emitted when a tool invocation completes. The `id` matches the
/// corresponding `ToolCallStart`.
ToolCallEnd {
/// The tool call ID.
id: String,
},
/// Metadata chunk with usage information.
///
/// Emitted at any point during streaming to provide intermediate or
/// final token usage statistics.
Metadata {
/// Token usage statistics.
usage: Usage,
},
/// An error occurred during streaming.
///
/// The stream may continue after an error or terminate, depending on
/// the provider implementation.
Error {
/// The error message.
message: String,
},
/// The stream has finished.
Done {
/// Why generation stopped.
finish_reason: FinishReason,
/// Final usage statistics.
usage: Usage,
},
}
pub fn text_delta(text: impl Into<String>) -> Self;
pub fn done(finish_reason: FinishReason, usage: Usage) -> Self;
pub fn tool_call_start(id: impl Into<String>, name: impl Into<String>) -> Self;
pub fn tool_call_end(id: impl Into<String>) -> Self;
pub fn metadata(usage: Usage) -> Self;
pub fn error(message: impl Into<String>) -> Self;
pub fn is_text_delta(&self) -> bool;
pub fn is_done(&self) -> bool;
pub fn is_tool_call_start(&self) -> bool;
pub fn is_tool_call_end(&self) -> bool;
pub fn is_metadata(&self) -> bool;
pub fn is_error(&self) -> bool;
pub fn as_text(&self) -> Option<&str>;provider.rs
Read declaration text · 17 declaration entries
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ProviderRef {
}
pub fn parse(input: &str) -> ForgeResult<Self>;
pub fn namespace(&self) -> &str;
pub fn model(&self) -> &str;
pub fn as_str(&self) -> &str;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderMetadata {
/// Human-readable name.
pub name: String,
/// Provider namespace (e.g., "openai").
pub namespace: String,
/// Whether the provider supports tool calling.
pub supports_tool_calling: bool,
/// Whether the provider supports structured output.
pub supports_structured_output: bool,
/// Whether the provider supports streaming.
pub supports_streaming: bool,
/// Whether the provider supports image input.
pub supports_image_input: bool,
/// Runtime capabilities advertised by the provider (coding-provider negotiation).
#[serde(default)]
pub runtime_capabilities: ProviderRuntimeCapabilities
}
pub struct ProviderRegistry {
}
pub fn new() -> Self;
pub fn register(
&mut self,
provider_ref: &str,
model: Arc<dyn LanguageModel>,
) -> ForgeResult<()>;
pub fn register_with_runtime(
&mut self,
provider_ref: &str,
model: Arc<dyn LanguageModel>,
runtime: ProviderRuntimeCapabilities,
) -> ForgeResult<()>;
pub fn negotiate(
&self,
request: &ProviderNegotiationRequest,
) -> ForgeResult<ProviderNegotiationResult>;
pub fn get(&self, provider_ref: &str) -> Option<Arc<dyn LanguageModel>>;
pub fn require(&self, provider_ref: &str) -> ForgeResult<Arc<dyn LanguageModel>>;
pub fn metadata(&self, provider_ref: &str) -> Option<&ProviderMetadata>;
pub fn list(&self) -> Vec<&str>;
pub fn len(&self) -> usize;
pub fn is_empty(&self) -> bool;provider_runtime.rs
Read declaration text · 10 declaration entries
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum RuntimeCapability {
ToolCalls,
DelegatedAgents,
TerminalSession,
StructuredPatch,
Attachments,
Interrupts,
ResumeSession,
ApprovalCheckpoints,
UsageStreaming,
TranscriptExport,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct ProviderRuntimeCapabilities {
/// Whether the provider satisfies the mandatory Forge coding baseline.
pub baseline_contract: bool,
/// Explicit advanced capabilities advertised by the provider.
pub capabilities: BTreeSet<RuntimeCapability>
}
pub fn baseline() -> Self;
pub fn with_capability(mut self, capability: RuntimeCapability) -> Self;
pub fn supports(&self, capability: &RuntimeCapability) -> bool;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ProviderNegotiationRequest {
pub provider_ref: String,
pub require_baseline_contract: bool,
pub required_capabilities: Vec<RuntimeCapability>
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ProviderNegotiationResult {
pub provider_ref: String,
pub baseline_contract: bool,
pub negotiated_capabilities: Vec<RuntimeCapability>
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ProviderSessionState {
Created,
Ready,
Running,
Interrupted,
Completed,
Cancelled,
Failed,
Expired,
Closed,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct ProviderUsageSummary {
pub input_tokens: u64,
pub output_tokens: u64,
pub total_tokens: u64
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ProviderSessionEvent {
pub session_id: String,
pub state: ProviderSessionState,
pub message: Option<String>,
pub usage: Option<ProviderUsageSummary>
}replay.rs
Read declaration text · 14 declaration entries
pub const DEFAULT_CLOCK_SKEW: Duration;
pub const DEFAULT_NONCE_CACHE_SIZE: usize;
#[derive(Debug, Clone)]
pub struct ReplayConfig {
/// Maximum allowed clock skew between sender and receiver, applied in
/// both directions. A timestamp that is more than this far in the past
/// or future (relative to the receiver's wall clock) is rejected.
pub max_clock_skew: Duration,
/// Maximum number of nonces to remember. When full, the least-recently-used
/// nonce is evicted to make room for a new entry. Must be non-zero.
pub nonce_cache_size: usize,
/// If `true`, messages lacking a nonce/timestamp (legacy wire format)
/// are accepted with a `WARN` log line. If `false` (default), legacy
/// messages are rejected with [`ReplayError::LegacyMessageFormat`].
///
/// This flag is also controllable via the `FORGE_ACCEPT_LEGACY_MESSAGES`
/// environment variable; see [`legacy_accept_from_env`].
pub accept_legacy: bool
}
pub fn with_max_clock_skew(mut self, skew: Duration) -> Self;
pub fn with_nonce_cache_size(mut self, size: usize) -> Self;
pub fn with_accept_legacy(mut self, accept: bool) -> Self;
pub fn legacy_accept_from_env() -> bool;
#[derive(Debug, Error, PartialEq, Eq)]
pub enum ReplayError {
/// The envelope timestamp is outside the accepted clock-skew window.
#[error(
"replay protection rejected message: timestamp {timestamp_ms}ms is outside the \
±{max_skew_ms}ms clock-skew window (now={now_ms}ms)"
)]
TimestampExpired {
/// The timestamp carried by the message, in milliseconds since epoch.
timestamp_ms: i64,
/// The receiver's current wall-clock time, in milliseconds since epoch.
now_ms: i64,
/// The configured maximum skew, in milliseconds.
max_skew_ms: i64,
},
/// The envelope's nonce was already seen within the validity window.
#[error(
"replay protection rejected message: nonce {nonce_hex} has already been accepted \
within the clock-skew window"
)]
NonceReplay {
/// Hex-encoded nonce, included for operator diagnostics.
nonce_hex: String,
},
/// The envelope is missing nonce and/or timestamp and legacy acceptance
/// is disabled.
#[error(
"replay protection rejected message: legacy wire format (no nonce/timestamp); \
set FORGE_ACCEPT_LEGACY_MESSAGES=true to opt into legacy acceptance"
)]
LegacyMessageFormat,
/// The validator's internal cache lock was poisoned. This indicates that
/// another thread panicked while holding the lock; callers should treat
/// this as an unrecoverable condition for that validator instance.
#[error("replay validator internal lock poisoned (a prior thread panicked)")]
LockPoisoned,
}
pub struct ReplayValidator {
}
pub fn new(config: ReplayConfig) -> Self;
pub fn config(&self) -> &ReplayConfig;
pub fn validate(&self, timestamp_ms: i64, nonce: &[u8; 16]) -> Result<(), ReplayError>;
pub fn accept_legacy(&self, context: &str) -> Result<(), ReplayError>;
#[doc(hidden)]
pub fn nonce_cache_len(&self) -> usize;routing.rs
Read declaration text · 7 declaration entries
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TaskMode {
/// Strategic reasoning, goal decomposition, plan generation.
Planning,
/// Direct task execution (code generation, content creation, data processing).
Execution,
/// Reviewing, grading, or verifying outputs from prior steps.
Evaluation,
/// Condensing, abstracting, or reformatting prior outputs.
Summarization,
}
pub fn as_role_name(&self) -> &'static str;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ExecutionTopology {
/// A single sequential call.
#[default]
Sequential,
/// One of N parallel calls that will be aggregated.
ParallelFanOut,
/// The aggregation call after a fan-out completes.
FanIn,
/// A call within a retry/fallback chain.
Retry,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct RoutingContext {
/// The domain classification for this call.
///
/// Examples: "code", "math", "creative", "analysis", "general".
/// When `None`, the router does not attempt domain-based matching.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub domain: Option<String>,
/// The task mode for this call.
///
/// When `None`, the router does not attempt task-mode-based matching.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub task_mode: Option<TaskMode>,
/// The execution topology for this call.
///
/// Describes how this inference call relates to other concurrent calls.
/// When `None`, defaults to `Sequential`.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub execution_topology: Option<ExecutionTopology>,
/// Tool capabilities required for the model selected by this route.
///
/// Specific tool names that must be callable. The router may use this
/// information to select a model that supports the required tools.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub tool_requirements: Vec<String>,
/// Explicit role override.
///
/// When set, the router returns the slot with this role name without
/// applying strategy logic. Analogous to `tier_override` in the
/// Aut0 Router.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub role_override: Option<String>
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResolvedRoute {
/// The role name of the selected slot.
pub slot_role: String,
/// The specific `ProviderRef` to use (primary or one of the fallbacks).
pub provider: ProviderRef,
/// The model capabilities of the selected provider.
pub model_capabilities: ModelCapabilities,
/// Whether a fallback model was selected instead of the primary.
pub fallback_used: bool
}
pub trait ModelRouter: Send + Sync {
/// Returns the name of this routing strategy (for telemetry and debugging).
fn name(&self) -> &str;
/// Selects a slot from the topology.
///
/// The router must return a `ResolvedRoute` that references a slot present
/// in the topology. Returning a role name that does not exist in the
/// topology is a routing error.
///
/// # Arguments
///
/// * `context` - The routing context describing the current task.
/// * `topology` - The model topology to select from.
///
/// # Returns
///
/// A `ResolvedRoute` identifying the selected slot and provider.
///
/// # Errors
///
/// Returns `ForgeError` if routing fails (e.g., requested role not found).
fn route(
&self,
context: &RoutingContext,
topology: &ModelTopology,
) -> ForgeResult<ResolvedRoute>;
}
pub struct DefaultModelRouter;schema.rs
Read declaration text · 20 declaration entries
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct JsonSchema {
/// The schema type.
#[serde(rename = "type")]
pub schema_type: SchemaType,
/// Human-readable description of this schema element.
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
/// Properties (for object type).
#[serde(skip_serializing_if = "Option::is_none")]
pub properties: Option<BTreeMap<String, JsonSchema>>,
/// Required property names (for object type).
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "required")]
pub required_fields: Option<Vec<String>>,
/// Whether additional properties are allowed (for object type).
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "additionalProperties")]
pub additional_properties: Option<bool>,
/// Items schema (for array type).
#[serde(skip_serializing_if = "Option::is_none")]
pub items: Option<Box<JsonSchema>>,
/// Allowed string values.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "enum")]
pub enum_values: Option<Vec<serde_json::Value>>,
/// Minimum numeric value.
#[serde(skip_serializing_if = "Option::is_none")]
pub minimum: Option<f64>,
/// Maximum numeric value.
#[serde(skip_serializing_if = "Option::is_none")]
pub maximum: Option<f64>,
/// Minimum string length.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "minLength")]
pub min_length: Option<u64>,
/// Maximum string length.
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "maxLength")]
pub max_length: Option<u64>
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SchemaType {
/// A JSON string.
String,
/// A JSON number (floating point).
Number,
/// A JSON integer.
Integer,
/// A JSON boolean.
Boolean,
/// A JSON array.
Array,
/// A JSON object.
Object,
/// A JSON null.
Null,
}
pub fn string() -> Self;
pub fn number() -> Self;
pub fn integer() -> Self;
pub fn boolean() -> Self;
pub fn array() -> Self;
pub fn object() -> Self;
pub fn null() -> Self;
pub fn description(mut self, desc: impl Into<String>) -> Self;
pub fn property(mut self, name: impl Into<String>, schema: JsonSchema) -> Self;
pub fn required(mut self, name: impl Into<String>) -> Self;
pub fn items_schema(mut self, schema: JsonSchema) -> Self;
pub fn enum_values(mut self, values: Vec<serde_json::Value>) -> Self;
pub fn minimum(mut self, min: impl Into<f64>) -> Self;
pub fn maximum(mut self, max: impl Into<f64>) -> Self;
pub fn min_length(mut self, len: u64) -> Self;
pub fn max_length(mut self, len: u64) -> Self;
pub fn additional_properties(mut self, allowed: bool) -> Self;
pub fn validate(&self, value: &serde_json::Value) -> ForgeResult<()>;telemetry.rs
Read declaration text · 21 declaration entries
pub const SPAN_GENERATE: &str;
pub const SPAN_TOOL_INVOKE: &str;
pub const SPAN_TASK_DELEGATE: &str;
pub const SPAN_TASK_EXECUTE: &str;
pub const SPAN_SESSION: &str;
pub const SPAN_LIFECYCLE: &str;
pub const SPAN_MESSAGE_SEND: &str;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AuditEventKind {
/// An agent was instantiated with identity and capabilities.
AgentInstantiated,
/// A capability check was performed against an Arsenal ACT.
CapabilityCheck,
/// A tool was invoked by the agent.
ToolInvocation,
/// A network access operation occurred (HTTP, WebSocket, etc.).
NetworkAccess,
/// An inter-agent message was sent or received.
InterAgentMessage,
/// A lifecycle state transition occurred.
LifecycleTransition,
/// A resource quota event was triggered (usage approaching or exceeding limits).
ResourceQuota,
/// An agent joined a session.
SessionJoin,
/// An agent left a session.
SessionLeave,
/// A task was delegated to a sub-agent.
TaskDelegation,
/// An interrupt signal was received and processed.
Interrupt,
/// A write to the agent's context or memory occurred.
ContextWrite,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ForgeSpan {
/// The span name (e.g., "forge.agent.generate", "forge.tool.execute").
pub name: String,
/// Span start time.
pub start_time: Timestamp,
/// Span end time (set when span completes).
pub end_time: Option<Timestamp>,
/// Key-value attributes.
pub attributes: HashMap<String, SpanAttribute>,
/// Span status.
pub status: SpanStatus,
/// Parent span ID for distributed tracing.
pub parent_id: Option<String>,
/// This span's unique ID.
pub span_id: String
}
pub fn new(name: impl Into<String>) -> Self;
pub fn set_attribute(&mut self, key: impl Into<String>, value: impl Into<SpanAttribute>);
pub fn end(&mut self);
pub fn end_with_error(&mut self, message: impl Into<String>);
pub fn with_parent(mut self, parent_id: impl Into<String>) -> Self;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ForgeEvent {
/// The event name.
pub name: String,
/// When the event occurred.
pub timestamp: Timestamp,
/// Key-value attributes.
pub attributes: HashMap<String, SpanAttribute>
}
pub fn new(name: impl Into<String>) -> Self;
pub fn set_attribute(&mut self, key: impl Into<String>, value: impl Into<SpanAttribute>);
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "code", rename_all = "snake_case")]
pub enum SpanStatus {
/// Status not set (default).
Unset,
/// Operation completed successfully.
Ok,
/// Operation failed with an error.
Error {
/// Error message.
message: String,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum SpanAttribute {
/// A string value.
String(String),
/// An integer value.
Int(i64),
/// A floating-point value.
Float(f64),
/// A boolean value.
Bool(bool),
}
pub trait TelemetryEmitter: Send + Sync {
/// Emits a completed span.
fn emit_span(&self, span: &ForgeSpan);
/// Emits an event.
fn emit_event(&self, event: &ForgeEvent);
}
pub struct NoopEmitter;tool.rs
Read declaration text · 17 declaration entries
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ToolTier {
/// Tier 1 -- Platform tools provided by the runtime.
///
/// Always available, no authorization needed. Examples: clock, crypto, logging.
#[serde(rename = "platform")]
Platform,
/// Tier 2 -- External tools that execute outside the sandbox.
///
/// Require Arsenal ACT authorization. Examples: web browsing, database, APIs.
#[serde(rename = "external", alias = "host")]
External,
/// Tier 3 -- Embedded tools compiled into the agent WASM module.
///
/// Scoped to the module. Examples: data parsing, computation, pure functions.
#[serde(rename = "embedded")]
Embedded,
}
pub fn requires_authorization(&self) -> bool;
pub fn as_str(&self) -> &'static str;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolDefinition {
}
pub fn builder(name: impl Into<String>) -> ToolDefinitionBuilder;
pub fn name(&self) -> &str;
pub fn description(&self) -> &str;
pub fn parameters(&self) -> &JsonSchema;
pub fn tier(&self) -> ToolTier;
pub struct ToolDefinitionBuilder {
}
pub fn description(mut self, desc: impl Into<String>) -> Self;
pub fn parameters(mut self, schema: JsonSchema) -> Self;
pub fn tier(mut self, tier: ToolTier) -> Self;
pub fn build(self) -> ToolDefinition;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ToolCall {
/// Unique identifier for this call (used to match with results).
pub id: String,
/// The tool name being invoked.
pub name: String,
/// JSON arguments for the tool.
pub arguments: serde_json::Value
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ToolResult {
/// The tool call ID this result corresponds to.
pub tool_call_id: String,
/// The tool name.
pub name: String,
/// The result content (stringified).
pub content: String,
/// Whether the tool execution resulted in an error.
pub is_error: bool
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ToolApproval {
/// The tool call is approved as-is.
Approve,
/// The tool call is denied with a reason.
Deny {
/// Why the tool call was denied.
reason: String,
},
/// The tool call is approved but with modified arguments.
Modify {
/// The modified arguments to use instead.
arguments: serde_json::Value,
},
}topology.rs
Read declaration text · 24 declaration entries
pub const DEFAULT_ROLE: &str;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CostPreference {
/// Prefer the cheapest model that satisfies requirements.
Minimize,
/// Accept moderate cost for better quality.
Balanced,
/// Ignore cost; select the best model regardless of price.
Ignore,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum LatencyPreference {
/// Prefer the lowest-latency model.
Low,
/// Accept moderate latency for better quality.
Balanced,
/// Ignore latency; select the best model regardless of response time.
Tolerant,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelSlot {
/// The role name for this slot (e.g., "planner", "coder", "default").
///
/// Role names are freeform strings. The reserved name "default" designates
/// the slot used when no routing decision applies. Every topology must
/// have exactly one slot with role "default".
pub role: String,
/// Primary model for this slot.
pub primary: ProviderRef,
/// Ordered fallback models. Tried in sequence when the primary is
/// unavailable or fails negotiation.
#[serde(default)]
pub fallbacks: Vec<ProviderRef>,
/// Runtime capabilities required for this slot. The router validates
/// that the selected model satisfies these before returning a route.
#[serde(default)]
pub required_capabilities: Vec<RuntimeCapability>,
/// Optional cost preference for the router.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cost_preference: Option<CostPreference>,
/// Optional latency preference for the router.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub latency_preference: Option<LatencyPreference>,
/// Optional Arsenal scope narrowing applied when this slot is selected.
/// If set, the agent's ACT is intersected with these scopes before
/// the model call. The intersection can only narrow, never widen.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub arsenal_scope_narrowing: Option<Vec<String>>
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModelTopology {
}
pub fn single(provider_ref: ProviderRef) -> Self;
pub fn builder() -> TopologyBuilder;
pub fn name(&self) -> &str;
pub fn default_role(&self) -> &str;
pub fn default_slot(&self) -> &ModelSlot;
pub fn slot_for_role(&self, role: &str) -> &ModelSlot;
pub fn slots(&self) -> &BTreeMap<String, ModelSlot>;
pub fn all_provider_refs(&self) -> Vec<&ProviderRef>;
pub fn has_role(&self, role: &str) -> bool;
pub fn slot_count(&self) -> usize;
#[derive(Debug)]
pub struct TopologyBuilder {
}
pub fn name(mut self, name: impl Into<String>) -> Self;
pub fn slot(mut self, role: impl Into<String>, primary: ProviderRef) -> Self;
pub fn with_fallback(mut self, role: impl AsRef<str>, fallback: ProviderRef) -> Self;
pub fn with_required_capability(
mut self,
role: impl AsRef<str>,
cap: RuntimeCapability,
) -> Self;
pub fn with_cost_preference(mut self, role: impl AsRef<str>, pref: CostPreference) -> Self;
pub fn with_latency_preference(
mut self,
role: impl AsRef<str>,
pref: LatencyPreference,
) -> Self;
pub fn with_scope_narrowing(mut self, role: impl AsRef<str>, scopes: Vec<String>) -> Self;
pub fn build(self) -> ForgeResult<ModelTopology>;types.rs
Read declaration text · 10 declaration entries
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AgentDid(String);
pub fn new(did: &str) -> Option<Self>;
pub fn from_trusted(did: String) -> Self;
pub fn as_str(&self) -> &str;
pub fn into_string(self) -> String;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Timestamp(chrono::DateTime<chrono::Utc>);
pub fn now() -> Self;
pub fn from_iso8601(s: &str) -> Option<Self>;
pub fn to_iso8601(self) -> String;
pub fn as_chrono(&self) -> &chrono::DateTime<chrono::Utc>;