Skip to main content

deepstrike_sdk/
lib.rs

1pub mod governance;
2pub mod harness;
3pub mod harness_loop;
4pub mod knowledge;
5pub mod memory;
6pub mod providers;
7pub mod run_event;
8pub mod runtime;
9pub mod safety;
10pub mod signals;
11pub mod tools;
12
13#[cfg(test)]
14mod tests;
15
16pub use deepstrike_core::context::renderer::RenderedContext;
17pub use deepstrike_core::governance::permission::PermissionAction;
18pub use deepstrike_core::governance::quota::ResourceQuota;
19// Session entropy (heartbeat watch source): the kernel emits `entropy_sample` /
20// `entropy_alert` observations through the shared JSON ABI; these types are for hosts
21// configuring the watch (`set_entropy_watch` / `configure_run.entropy_watch`) or folding
22// their own samples when driving the kernel manually.
23pub use deepstrike_core::{EntropySample, EntropyTracker, EntropyWatchConfig};
24pub use deepstrike_core::mm::memory::{
25    MemoryKind, MemoryMetadata, MemoryPolicy, MemoryQuery, MemoryRetrieval, MemoryWriteRequest,
26};
27// Workflow surface (DELIBERATE floor, not a gap): the Rust SDK has no `run_workflow` driver — the
28// node/python/wasm SDKs own async node execution. These re-exports are for MANUAL driving: build a
29// spec with the templates, hold a `WorkflowRun` (a pure state machine), call `ready_batch()` /
30// `spawn_info()` / `record_completion()` from your own executor. Everything the drivers do is
31// reachable this way; a batteries-included Rust driver lands only when a real consumer needs it.
32pub use deepstrike_core::orchestration::workflow::{
33    fanout_synthesize, gen_eval, generate_and_filter, verify_rules, WorkflowNode, WorkflowSpec,
34};
35pub use deepstrike_core::orchestration::workflow::{JudgeMatch, WorkflowRun, WorkflowSpawnInfo};
36pub use governance::{Governance, GovernanceVerdict};
37pub use harness::{CriterionResult, Harness, HarnessEvent, HarnessOutcome, HarnessRequest, QualityGate};
38pub use harness_loop::{EvalLoopHarness, HarnessLoop, SinglePassHarness, VerdictCtx, VerdictFn};
39pub use knowledge::KnowledgeSource;
40pub use memory::{DreamResult, DreamStore, InMemoryDreamStore, WorkingMemory};
41pub use providers::RuntimePolicy;
42pub use providers::anthropic::AnthropicProvider;
43pub use providers::openai::{OpenAIProvider, deepseek, kimi, minimax, ollama, qwen};
44pub use providers::{LLMProvider, ProviderRunState, ProviderToolSpec, StreamEvent, TokenUsage};
45pub use run_event::RunEvent;
46pub use runtime::{
47    ChainedCredentialVault, CredentialVault, EnvCredentialVault, InMemoryCredentialVault,
48};
49pub use runtime::{ExecutionPlane, LocalExecutionPlane};
50pub use runtime::{FileSessionLog, InMemorySessionLog, SessionEntry, SessionLog};
51pub use runtime::replay_provider::{ReplayProvider, ReplayProviderOpts};
52pub use runtime::replay_fixture::{extract_recorded_messages, extract_recorded_messages_from_entries};
53pub use runtime::eval::{judge, build_eval_messages, parse_verdict, verdict_output_schema, Criterion, Verdict};
54pub use runtime::{McpProxyPlane, McpServerConfig};
55pub use runtime::{
56    AttentionPolicy, GovernancePolicy, MemoryWriteRateLimit, NativeOsProfile, OsProfile,
57    SchedulerBudget, assert_native_profile, default_native_governance_policy, os_profile,
58    DEFAULT_NATIVE_ATTENTION_POLICY,
59};
60pub use runtime::{
61    MilestoneEvaluationContext, MilestoneEvaluationHandler, MilestonePolicy, RuntimeOptions,
62    RuntimeRunner, collect_text,
63};
64pub use runtime::{
65    PermissionRequest, PermissionRequestHandler, PermissionResponse, RunContext,
66    ToolSuspendHandler, ToolSuspendRequest,
67};
68pub use runtime::{ProcessSandboxPlane, SandboxOptions};
69pub use runtime::{RemoteVpcOptions, RemoteVpcPlane};
70pub use safety::{Permission, PermissionDecision, PermissionManager, PermissionMode};
71pub use signals::{GatewayReceiver, RuntimeSignal, ScheduledPrompt, SignalGateway, SignalSource};
72pub use tools::{
73    RegisteredTool, SafeToolResult, TextToolSession, ToolChunk, ToolEnvelope, ToolEnvelopeFail,
74    ToolEnvelopeOk, ToolSession, ToolStep, execute_tools, fail, ok, read_file_tool, safe_tool,
75    tool_fail, validate_tool_arguments,
76};
77
78#[derive(Debug, thiserror::Error)]
79pub enum Error {
80    #[error("provider error: {0}")]
81    Provider(String),
82    #[error("tool error: {0}")]
83    Tool(String),
84    #[error("io error: {0}")]
85    Io(#[from] std::io::Error),
86    #[error("tool execution failed: {output}")]
87    ToolExecutionFailed {
88        output: String,
89        is_fatal: bool,
90        error_kind: Option<deepstrike_core::types::message::ToolErrorKind>,
91    },
92    /// Tool author signalled a structured failure with optional machine-readable `code` and a
93    /// self-correcting `hint`. Parity with the Node/Python `ToolError` + `safe_tool` envelope:
94    /// surfaced to the model as JSON `{message, code?, hint?}` (via `format_tool_error`) so the
95    /// agent can branch on `code` instead of pattern-matching a free-form string.
96    #[error("{output}")]
97    ToolFail {
98        output: String,
99        code: Option<String>,
100        hint: Option<String>,
101        is_fatal: bool,
102        error_kind: Option<deepstrike_core::types::message::ToolErrorKind>,
103    },
104    #[error("{0}")]
105    Other(String),
106}
107
108/// Error-aware serialization for tool-execution error paths. Replaces `e.to_string()` at the
109/// sites that hand the model a failure message:
110///
111/// - `Error::Tool(s)` → `s` (drops the `"tool error: "` prefix from `e.to_string()`).
112/// - `Error::ToolExecutionFailed { output, .. }` → `output` (drops the `"tool execution failed: "` prefix).
113/// - `Error::ToolFail { output, code:None, hint:None, .. }` → `output`.
114/// - `Error::ToolFail { output, code, hint, .. }` (either set) → JSON `{message, code?, hint?}`.
115/// - everything else → `e.to_string()` (the `thiserror`-formatted string).
116pub fn format_tool_error(e: &Error) -> String {
117    match e {
118        Error::Tool(s) => s.clone(),
119        Error::ToolExecutionFailed { output, .. } => output.clone(),
120        Error::ToolFail { output, code, hint, .. } => {
121            if code.is_none() && hint.is_none() {
122                return output.clone();
123            }
124            let mut obj = serde_json::Map::with_capacity(3);
125            obj.insert("message".to_string(), serde_json::Value::String(output.clone()));
126            if let Some(c) = code {
127                obj.insert("code".to_string(), serde_json::Value::String(c.clone()));
128            }
129            if let Some(h) = hint {
130                obj.insert("hint".to_string(), serde_json::Value::String(h.clone()));
131            }
132            serde_json::to_string(&serde_json::Value::Object(obj)).unwrap_or_else(|_| output.clone())
133        }
134        _ => e.to_string(),
135    }
136}
137
138pub type Result<T> = std::result::Result<T, Error>;