Skip to main content

harn_vm/
lib.rs

1#![recursion_limit = "256"]
2#![allow(clippy::result_large_err, clippy::cloned_ref_to_slice_refs)]
3
4pub mod a2a;
5pub mod agent_events;
6pub mod agent_sessions;
7pub mod atomic_io;
8pub mod autonomy;
9pub mod bridge;
10mod builtin_id;
11pub mod checkpoint;
12mod chunk;
13mod compiler;
14pub mod connectors;
15pub mod corrections;
16pub mod egress;
17pub mod event_log;
18pub mod events;
19pub mod flow;
20mod http;
21pub mod jsonrpc;
22pub mod llm;
23pub mod llm_config;
24pub mod mcp;
25pub mod mcp_card;
26pub mod mcp_elicit;
27pub mod mcp_progress;
28pub mod mcp_protocol;
29pub mod mcp_registry;
30pub mod mcp_sampling;
31pub mod mcp_server;
32pub mod metadata;
33pub mod observability;
34pub mod orchestration;
35pub mod personas;
36pub mod process_sandbox;
37pub mod profile;
38pub mod provenance;
39pub mod receipts;
40pub mod record_filter;
41pub mod runtime_context;
42pub mod runtime_paths;
43pub mod schema;
44pub mod secrets;
45pub mod sessions;
46pub(crate) mod shared_state;
47pub mod shells;
48pub mod skills;
49pub mod stdlib;
50pub mod stdlib_modules;
51pub mod step_runtime;
52pub mod store;
53pub(crate) mod synchronization;
54pub mod tenant;
55pub mod tool_annotations;
56pub mod tool_surface;
57pub mod tracing;
58pub mod triggers;
59pub mod trust_graph;
60pub mod typecheck;
61pub mod value;
62pub mod visible_text;
63mod vm;
64pub mod waitpoints;
65pub mod workspace_path;
66
67pub use builtin_id::BuiltinId;
68pub use checkpoint::register_checkpoint_builtins;
69pub use chunk::*;
70pub use compiler::*;
71pub use connectors::{
72    active_connector_client, active_metrics_registry, clear_active_connector_clients,
73    clear_active_metrics_registry, connector_export_denied_builtin_reason,
74    connector_export_effect_class,
75    cron::{CatchupMode, CronConnector},
76    default_connector_export_policy,
77    harn_module::{
78        load_contract as load_harn_connector_contract, HarnConnector, HarnConnectorContract,
79    },
80    hmac::{verify_hmac_signed, SIGNATURE_VERIFY_AUDIT_TOPIC},
81    install_active_connector_clients, install_active_metrics_registry,
82    postprocess_normalized_event, ActivationHandle, ClientError, Connector, ConnectorClient,
83    ConnectorCtx, ConnectorError, ConnectorExportEffectClass, ConnectorHttpResponse,
84    ConnectorMetricsSnapshot, ConnectorNormalizeResult, ConnectorRegistry, GenericWebhookConnector,
85    HarnConnectorEffectPolicies, MetricsRegistry, PostNormalizeOutcome, ProviderPayloadSchema,
86    RateLimitConfig, RateLimiterFactory, RawInbound, StreamConnector, TriggerBinding, TriggerKind,
87    TriggerRegistry, WebhookSignatureVariant,
88};
89pub use corrections::{
90    append_correction_record, apply_corrections_to_policy, correction_query_filters_from_json,
91    correction_record_from_json, policy_with_corrections, query_correction_records,
92    CorrectionQueryFilters, CorrectionRecord, CorrectionScope, CORRECTIONS_TOPIC,
93    CORRECTION_EVENT_KIND, CORRECTION_SCHEMA_V0,
94};
95pub use http::{register_http_builtins, reset_http_state};
96pub use llm::register_llm_builtins;
97pub use llm::trigger_predicate::TriggerPredicateBudget;
98pub use llm::{
99    current_agent_session_id, drain_global_pending_feedback, push_pending_feedback_global,
100    register_session_end_hook, wait_for_global_pending_feedback,
101};
102pub use mcp::{
103    connect_mcp_server, connect_mcp_server_from_json, connect_mcp_server_from_spec,
104    register_mcp_builtins,
105};
106pub use mcp_card::{fetch_server_card, load_server_card_from_path, CardError};
107pub use mcp_registry::{
108    active_handle as mcp_active_handle, ensure_active as mcp_ensure_active,
109    get_registration as mcp_get_registration, install_active as mcp_install_active,
110    is_registered as mcp_is_registered, register_servers as mcp_register_servers,
111    release as mcp_release, reset as mcp_reset_registry, snapshot_status as mcp_snapshot_status,
112    sweep_expired as mcp_sweep_expired, RegisteredMcpServer, RegistryStatus,
113};
114pub use mcp_server::{
115    take_mcp_serve_prompts, take_mcp_serve_registry, take_mcp_serve_resource_templates,
116    take_mcp_serve_resources, tool_registry_to_mcp_tools, McpServer,
117};
118pub use metadata::{register_metadata_builtins, register_scan_builtins};
119pub use orchestration::{
120    canonicalize_run, first_divergence, run_replay_oracle_trace, ReplayAllowlistRule,
121    ReplayDivergence, ReplayExpectation, ReplayOracleError, ReplayOracleReport, ReplayOracleTrace,
122    ReplayTraceRun, ReplayTraceRunCounts, REPLAY_TRACE_SCHEMA_VERSION,
123};
124pub use orchestration::{
125    install_handoff_routes, snapshot_handoff_routes, HandoffRouteConfig,
126    HandoffRouteDecisionRecord, HandoffRouteTargetConfig,
127};
128pub use personas::{
129    disable_persona, fire_schedule as fire_persona_schedule, fire_trigger as fire_persona_trigger,
130    format_ms as format_persona_ms, now_ms as persona_now_ms, parse_rfc3339_ms as parse_persona_ms,
131    pause_persona, persona_status, record_persona_spend, register_persona_value_sink,
132    resume_persona, PersonaAssignmentStatus, PersonaBudgetPolicy, PersonaBudgetStatus,
133    PersonaHandoffInboxItem, PersonaLease, PersonaLifecycleState, PersonaQueuedWork,
134    PersonaRunCost, PersonaRunReceipt, PersonaRuntimeBinding, PersonaStatus,
135    PersonaTriggerEnvelope, PersonaValueEvent, PersonaValueEventKind, PersonaValueReceipt,
136    PersonaValueSink, PersonaValueSinkRegistration, PERSONA_RUNTIME_TOPIC,
137};
138pub use provenance::{
139    build_signed_receipt, load_or_generate_agent_signing_key, verify_receipt, ProvenanceReceipt,
140    ReceiptBuildOptions, ReceiptVerificationReport,
141};
142pub use receipts::{
143    Receipt, ReceiptSink, ReceiptStatus, ReceiptValidationError, RedactionClass, RECEIPT_SCHEMA_ID,
144    RECEIPT_SCHEMA_JSON, RECEIPT_SCHEMA_VERSION,
145};
146pub use record_filter::{normalize_record_filter_expression, CompiledRecordFilter};
147pub use schema::json_to_vm_value;
148pub use sessions::{
149    CreateSession, ExpireSession, Session, SessionAttributes, SessionError, SessionStore,
150    TouchSession, SESSIONS_TOPIC,
151};
152pub use stdlib::hitl::{
153    append_hitl_response, ApprovalRequest, HitlHostResponse, HITL_APPROVALS_TOPIC,
154    HITL_DUAL_CONTROL_TOPIC, HITL_ESCALATIONS_TOPIC, HITL_QUESTIONS_TOPIC,
155};
156pub use stdlib::host::{clear_host_call_bridge, set_host_call_bridge, HostCallBridge};
157pub use stdlib::io::{set_stdout_passthrough, take_stderr_buffer};
158pub use stdlib::long_running::cancel_handle as cancel_long_running_handle;
159pub use stdlib::secret_scan::{
160    append_secret_scan_audit, audit_secret_scan_active, scan_content as secret_scan_content,
161    SecretFinding, SECRET_SCAN_AUDIT_TOPIC,
162};
163pub use stdlib::template::{
164    lookup_prompt_consumers, lookup_prompt_span, prompt_render_indices, record_prompt_render_index,
165    PromptSourceSpan, PromptSpanKind,
166};
167pub use stdlib::waitpoint::{
168    process_waitpoint_resume_event, service_waitpoints_once, WAITPOINT_RESUME_TOPIC,
169};
170pub use stdlib::workflow_messages::{
171    workflow_pause_for_base, workflow_publish_query_for_base, workflow_query_for_base,
172    workflow_respond_update_for_base, workflow_resume_for_base, workflow_signal_for_base,
173    workflow_update_for_base, WorkflowMailboxState,
174};
175pub use stdlib::{
176    register_agent_stdlib, register_core_stdlib, register_io_stdlib, register_vm_stdlib,
177};
178pub use store::register_store_builtins;
179pub use tenant::{
180    tenant_event_topic_prefix, tenant_secret_namespace, tenant_topic, validate_tenant_id, ApiKeyId,
181    TenantApiKeyRecord, TenantBudget, TenantEventLog, TenantRecord, TenantRegistrySnapshot,
182    TenantResolutionError, TenantScope, TenantSecretProvider, TenantStatus, TenantStore,
183    TENANT_EVENT_TOPIC_PREFIX, TENANT_REGISTRY_DIR, TENANT_REGISTRY_FILE,
184    TENANT_SECRET_NAMESPACE_PREFIX,
185};
186pub use triggers::{
187    append_dispatch_cancel_request, begin_in_flight, binding_autonomy_budget_would_exceed,
188    binding_budget_would_exceed, binding_version_as_of, classify_trigger_dlq_error,
189    clear_dispatcher_state, clear_orchestrator_budget, clear_trigger_registry, drain,
190    dynamic_deregister, dynamic_register, expected_predicate_cost_usd_micros, finish_in_flight,
191    install_manifest_triggers, install_orchestrator_budget, install_provider_catalog,
192    micros_to_usd, note_autonomous_decision, note_orchestrator_budget_cost,
193    orchestrator_budget_would_exceed, parse_flow_control_duration, pin_trigger_binding,
194    provider_metadata, record_predicate_cost_sample, redact_headers, register_provider_schema,
195    registered_provider_metadata, registered_provider_schema_names, reset_binding_budget_windows,
196    reset_provider_catalog, reset_provider_catalog_with, resolve_live_or_as_of,
197    resolve_live_trigger_binding, resolve_trigger_binding_as_of, run_trigger_harness_fixture,
198    scheduler_in_flight_by_key, scheduler_ready_stats_by_key, snapshot_dispatcher_stats,
199    snapshot_orchestrator_budget, snapshot_trigger_bindings, unpin_trigger_binding, usd_to_micros,
200    worker_claims_topic_name, worker_job_topic_name, worker_response_topic_name, ClaimedWorkerJob,
201    DispatchCancelRequest, DispatchError, DispatchOutcome, DispatchStatus, Dispatcher,
202    DispatcherDrainReport, DispatcherStatsSnapshot, FairnessKey, HeaderRedactionPolicy, InboxIndex,
203    NotionPolledChangeEvent, OrchestratorBudgetConfig, OrchestratorBudgetSnapshot, ProviderCatalog,
204    ProviderCatalogError, ProviderId, ProviderMetadata, ProviderOutboundMethod, ProviderPayload,
205    ProviderRuntimeMetadata, ProviderSchema, ProviderSecretRequirement, ReadyKeyStats,
206    RecordedTriggerBinding, RetryPolicy, SchedulableJob, SchedulerKeyStat, SchedulerPolicy,
207    SchedulerSnapshot, SchedulerState, SchedulerStrategy, SignatureStatus,
208    SignatureVerificationMetadata, StreamEventPayload, TenantId, TraceId, TriggerBatchConfig,
209    TriggerBindingSnapshot, TriggerBindingSource, TriggerBindingSpec,
210    TriggerBudgetExhaustionStrategy, TriggerConcurrencyConfig, TriggerDebounceConfig,
211    TriggerDispatchOutcome, TriggerEvent, TriggerEventId, TriggerExpressionSpec,
212    TriggerFlowControlConfig, TriggerHandlerSpec, TriggerHarnessResult, TriggerId,
213    TriggerMetricsSnapshot, TriggerPredicateSpec, TriggerPriorityOrderConfig,
214    TriggerRateLimitConfig, TriggerRegistryError, TriggerRetryConfig, TriggerSingletonConfig,
215    TriggerState, TriggerThrottleConfig, WorkerQueue, WorkerQueueClaimHandle,
216    WorkerQueueEnqueueReceipt, WorkerQueueInspectSnapshot, WorkerQueueJob, WorkerQueueJobState,
217    WorkerQueuePriority, WorkerQueueResponseRecord, WorkerQueueState, WorkerQueueSummary,
218    DEFAULT_INBOX_RETENTION_DAYS, DEFAULT_STARVATION_AGE_MS, TRIGGERS_LIFECYCLE_TOPIC,
219    TRIGGER_ATTEMPTS_TOPIC, TRIGGER_CANCEL_REQUESTS_TOPIC, TRIGGER_DLQ_TOPIC,
220    TRIGGER_INBOX_CLAIMS_TOPIC, TRIGGER_INBOX_ENVELOPES_TOPIC, TRIGGER_INBOX_LEGACY_TOPIC,
221    TRIGGER_OPERATION_AUDIT_TOPIC, TRIGGER_OUTBOX_TOPIC, TRIGGER_TEST_FIXTURES,
222    WORKER_QUEUE_CATALOG_TOPIC,
223};
224pub use trust_graph::{
225    append_active_trust_record, append_trust_record, export_trust_chain,
226    group_trust_records_by_trace, policy_for_agent, policy_for_autonomy_tier,
227    query_trust_graph_records, query_trust_records, resolve_agent_autonomy_tier,
228    summarize_trust_records, topic_for_agent, trust_score_for, verify_trust_chain, AutonomyTier,
229    TrustAgentSummary, TrustChainExport, TrustChainExportMetadata, TrustChainExportProducer,
230    TrustChainReport, TrustGraphRecord, TrustOutcome, TrustQueryFilters, TrustRecord, TrustScore,
231    TrustTraceGroup, OPENTRUSTGRAPH_CHAIN_SCHEMA_V0, OPENTRUSTGRAPH_SCHEMA_V0,
232    TRUST_GRAPH_GLOBAL_TOPIC, TRUST_GRAPH_LEGACY_GLOBAL_TOPIC, TRUST_GRAPH_LEGACY_TOPIC_PREFIX,
233    TRUST_GRAPH_RECORDS_TOPIC, TRUST_GRAPH_TOPIC_PREFIX,
234};
235pub use value::*;
236pub use vm::*;
237
238#[cfg(feature = "vm-bench-internals")]
239#[doc(hidden)]
240pub mod bench_internals;
241
242/// Lex, parse, type-check, and compile source to bytecode in one call.
243/// Bails on the first type error. For callers that need diagnostics
244/// rather than early exit, use `harn_parser::check_source` directly
245/// and then call `Compiler::new().compile(&program)`.
246pub fn compile_source(source: &str) -> Result<Chunk, String> {
247    let program = harn_parser::check_source_strict(source).map_err(|e| e.to_string())?;
248    Compiler::new().compile(&program).map_err(|e| e.to_string())
249}
250
251/// Same as [`compile_source`] but compiles a specific named pipeline as
252/// the program entry point instead of the default-pipeline-or-first
253/// selection rule. Returns a runtime error when no pipeline with
254/// `pipeline_name` exists in the source.
255pub fn compile_source_named(source: &str, pipeline_name: &str) -> Result<Chunk, String> {
256    let program = harn_parser::check_source_strict(source).map_err(|e| e.to_string())?;
257    let has_pipeline = program.iter().any(|sn| {
258        let (_, inner) = harn_parser::peel_attributes(sn);
259        matches!(&inner.node, harn_parser::Node::Pipeline { name, .. } if name == pipeline_name)
260    });
261    if !has_pipeline {
262        return Err(format!("no pipeline named `{pipeline_name}` in source"));
263    }
264    Compiler::new()
265        .compile_named(&program, pipeline_name)
266        .map_err(|e| e.to_string())
267}
268
269pub fn json_schema_for_type_expr(type_expr: &harn_parser::TypeExpr) -> Option<serde_json::Value> {
270    let schema = compiler::Compiler::type_expr_to_schema_value(type_expr)?;
271    let json_schema = schema::schema_to_json_schema_value(&schema).ok()?;
272    Some(llm::vm_value_to_json(&json_schema))
273}
274
275pub fn json_schema_for_typed_params(params: &[harn_parser::TypedParam]) -> serde_json::Value {
276    let mut properties = serde_json::Map::new();
277    let mut required = Vec::new();
278
279    for param in params {
280        let param_schema = param
281            .type_expr
282            .as_ref()
283            .and_then(json_schema_for_type_expr)
284            .unwrap_or_else(|| serde_json::json!({}));
285        if param.default_value.is_none() {
286            required.push(serde_json::Value::String(param.name.clone()));
287        }
288        properties.insert(param.name.clone(), param_schema);
289    }
290
291    let mut schema = serde_json::Map::new();
292    schema.insert(
293        "type".to_string(),
294        serde_json::Value::String("object".to_string()),
295    );
296    schema.insert(
297        "properties".to_string(),
298        serde_json::Value::Object(properties),
299    );
300    if !required.is_empty() {
301        schema.insert("required".to_string(), serde_json::Value::Array(required));
302    }
303    serde_json::Value::Object(schema)
304}
305
306/// Reset all thread-local state that can leak between test runs.
307pub fn reset_thread_local_state() {
308    llm::reset_llm_state();
309    llm_config::clear_user_overrides();
310    http::reset_http_state();
311    event_log::reset_active_event_log();
312    stdlib::reset_stdlib_state();
313    connectors::clear_active_connector_clients();
314    orchestration::clear_runtime_hooks();
315    orchestration::clear_execution_policy_stacks();
316    orchestration::clear_command_policies();
317    triggers::clear_dispatcher_state();
318    triggers::clear_trigger_registry();
319    events::reset_event_sinks();
320    agent_events::reset_all_sinks();
321    agent_sessions::reset_session_store();
322    mcp_registry::reset();
323}