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
4/// Re-export of the unified clock substrate so downstream crates (CLI,
5/// orchestrator, harn-cloud) can depend on a single canonical `Clock`
6/// trait without each adding `harn-clock` as a direct dependency.
7pub use harn_clock as clock;
8
9pub mod a2a;
10pub mod agent_events;
11pub mod agent_sessions;
12pub mod atomic_io;
13pub mod autonomy;
14pub(crate) mod aws_sigv4;
15pub mod bridge;
16mod builtin_id;
17pub mod bytecode_cache;
18pub mod channel_guardrails;
19pub mod channels;
20pub mod checkpoint;
21mod chunk;
22mod compiler;
23pub mod composition;
24pub mod config;
25pub mod connectors;
26pub mod corrections;
27pub mod egress;
28pub mod event_log;
29pub mod events;
30pub mod flow;
31pub mod harness;
32pub(crate) mod harness_crypto;
33pub mod harness_net;
34pub mod harness_system;
35pub mod harness_tenant;
36mod http;
37pub mod jsonrpc;
38pub mod llm;
39pub mod llm_config;
40pub mod mcp;
41pub mod mcp_auth;
42pub mod mcp_card;
43pub mod mcp_elicit;
44pub mod mcp_file_upload;
45pub mod mcp_host;
46pub mod mcp_progress;
47pub mod mcp_protocol;
48pub mod mcp_registry;
49pub mod mcp_sampling;
50pub mod mcp_server;
51pub mod metadata;
52pub mod module_artifact;
53pub mod observability;
54pub mod orchestration;
55pub mod personas;
56pub mod process_sandbox;
57pub mod profile;
58pub mod provenance;
59pub mod provider_catalog;
60pub mod receipts;
61pub mod record_filter;
62pub mod redact;
63pub mod run_events;
64pub mod runtime_context;
65pub(crate) mod runtime_guards;
66pub mod runtime_limits;
67pub mod runtime_paths;
68pub mod schema;
69pub(crate) mod secret_patterns;
70pub mod secrets;
71pub mod session_bundle;
72pub mod sessions;
73pub(crate) mod shared_state;
74pub mod shells;
75pub mod skills;
76pub mod stdlib;
77pub mod stdlib_modules;
78pub mod step_runtime;
79pub mod store;
80pub(crate) mod synchronization;
81pub mod tenant;
82pub(crate) mod term;
83pub mod testbench;
84pub mod tool_annotations;
85pub mod tool_call_cancellations;
86pub mod tool_surface;
87pub mod tracing;
88pub mod triggers;
89pub mod trust_graph;
90pub(crate) mod url_encoding;
91
92/// Crate-wide deterministic clock mock used by stdlib time builtins, the
93/// trigger dispatcher, the cron scheduler, and Rust-side tests. Re-exports
94/// the long-lived implementation under `triggers::test_util::clock` so all
95/// callers go through one source of truth.
96pub mod clock_mock {
97    pub use crate::triggers::test_util::clock::{
98        active_mock_clock, advance, clear_overrides, install_override, instant_now, is_mocked,
99        now_ms, now_utc, sleep, ClockInstant, ClockOverrideGuard, MockClock,
100    };
101
102    /// Runtime audit for capabilities that observe real wall-clock or
103    /// monotonic time while a testbench mock is installed. See the module
104    /// docs for the full design.
105    pub mod leak_audit {
106        #[cfg(test)]
107        pub use crate::triggers::test_util::clock_leak::TEST_LOCK;
108        pub use crate::triggers::test_util::clock_leak::{
109            drain, instant_now, reset, snapshot, wall_now, ClockLeak,
110        };
111    }
112}
113
114pub mod typecheck;
115pub mod value;
116pub mod visible_text;
117mod vm;
118pub mod waitpoints;
119pub mod workspace_anchor;
120pub mod workspace_path;
121
122pub use builtin_id::BuiltinId;
123pub use checkpoint::register_checkpoint_builtins;
124pub use chunk::*;
125pub use compiler::*;
126pub use connectors::{
127    active_connector_client, active_metrics_registry, clear_active_connector_clients,
128    clear_active_metrics_registry, connector_export_denied_builtin_reason,
129    connector_export_effect_class,
130    cron::{CatchupMode, CronConnector},
131    default_connector_export_policy,
132    harn_module::{
133        load_contract as load_harn_connector_contract, HarnConnector, HarnConnectorContract,
134    },
135    hmac::{verify_hmac_signed, SIGNATURE_VERIFY_AUDIT_TOPIC},
136    install_active_connector_clients, install_active_metrics_registry,
137    postprocess_normalized_event, ActivationHandle, ClientError, Connector, ConnectorClient,
138    ConnectorCtx, ConnectorError, ConnectorExportEffectClass, ConnectorHttpResponse,
139    ConnectorMetricsSnapshot, ConnectorNormalizeResult, ConnectorRegistry, GenericWebhookConnector,
140    HarnConnectorEffectPolicies, MetricsRegistry, PostNormalizeOutcome, ProviderPayloadSchema,
141    RateLimitConfig, RateLimiterFactory, RawInbound, StreamConnector, TriggerBinding, TriggerKind,
142    TriggerRegistry, WebhookSignatureVariant,
143};
144pub use corrections::{
145    append_correction_record, apply_corrections_to_policy, correction_query_filters_from_json,
146    correction_record_from_json, policy_with_corrections, query_correction_records,
147    CorrectionQueryFilters, CorrectionRecord, CorrectionScope, CORRECTIONS_TOPIC,
148    CORRECTION_EVENT_KIND, CORRECTION_SCHEMA_V0,
149};
150pub use harness::{
151    DenyEvent, Harness, HarnessCall, HarnessClock, HarnessCrypto, HarnessEnv, HarnessFs,
152    HarnessKind, HarnessLlm, HarnessNet, HarnessProcess, HarnessRandom, HarnessStdio,
153    HarnessSystem, HarnessTenant, HarnessTerm, MockAwareClock, MockHarnessBuilder, VmHarness,
154};
155pub use harness_net::{
156    bypass_enabled as net_policy_bypass_enabled, NetMatcher, NetPolicy, NetPolicyAudit,
157    NetPolicyDecision, NetPolicyDefault, NetPolicyRule, OnViolation, HARN_NET_POLICY_BYPASS_ENV,
158    NET_POLICY_AUDIT_TOPIC,
159};
160pub use harness_tenant::{
161    current_tenant_id, enter_tenant, TenantScopeGuard, MISSING_TENANT_MESSAGE,
162};
163pub use http::{register_http_builtins, reset_http_state};
164pub use llm::register_llm_builtins;
165pub use llm::trigger_predicate::TriggerPredicateBudget;
166pub use llm::{current_agent_session_id, register_session_end_hook};
167pub use mcp::{connect_mcp_server_from_json, connect_mcp_server_from_spec, register_mcp_builtins};
168pub use mcp_card::{fetch_server_card, load_server_card_from_path, CardError};
169pub use mcp_host::{
170    cache_stats as mcp_host_cache_stats, set_allowlist as set_mcp_host_allowlist,
171    AllowlistDecision as McpHostAllowlistDecision, AllowlistGuard as McpHostAllowlistGuard,
172    BreakerState as McpHostBreakerState, CacheStats as McpHostCacheStats, McpHostStatus,
173    SpawnOptions as McpHostSpawnOptions, SupervisionPolicy as McpHostSupervisionPolicy,
174};
175pub use mcp_registry::{
176    active_handle as mcp_active_handle, ensure_active as mcp_ensure_active,
177    get_registration as mcp_get_registration, install_active as mcp_install_active,
178    is_registered as mcp_is_registered, register_servers as mcp_register_servers,
179    release as mcp_release, reset as mcp_reset_registry, snapshot_status as mcp_snapshot_status,
180    sweep_expired as mcp_sweep_expired, RegisteredMcpServer, RegistryStatus,
181};
182pub use mcp_server::{
183    take_mcp_serve_prompts, take_mcp_serve_registry, take_mcp_serve_resource_templates,
184    take_mcp_serve_resources, tool_registry_to_mcp_tools, McpServer,
185};
186pub use metadata::{register_metadata_builtins, register_scan_builtins};
187pub use orchestration::{
188    benchmark_adapted_replay_pair, benchmark_replay_trace, build_replay_benchmark_report,
189    OpenCodeJsonlAdapter, ReplayBenchmarkCloudIngest, ReplayBenchmarkError,
190    ReplayBenchmarkFixtureReceipt, ReplayBenchmarkFixtureReport, ReplayBenchmarkMetrics,
191    ReplayBenchmarkReport, ReplayBenchmarkSuiteIdentity, ReplayBenchmarkSummary,
192    ReplayCategoryMetric, ReplayDebuggingProxyMetrics, ReplayRuntimeCostMetrics,
193    ReplayTraceAdapter, OPENCODE_JSONL_ADAPTER_ID, OPENCODE_JSONL_ADAPTER_SCHEMA_VERSION,
194    REPLAY_BENCHMARK_CLOUD_INGEST_KIND, REPLAY_BENCHMARK_REPORT_SCHEMA_VERSION,
195};
196pub use orchestration::{
197    canonicalize_run, first_divergence, run_replay_oracle_trace, ReplayAllowlistRule,
198    ReplayDivergence, ReplayExpectation, ReplayOracleError, ReplayOracleReport, ReplayOracleTrace,
199    ReplayTraceRun, ReplayTraceRunCounts, REPLAY_TRACE_SCHEMA_VERSION,
200};
201pub use orchestration::{
202    install_handoff_routes, snapshot_handoff_routes, HandoffRouteConfig,
203    HandoffRouteDecisionRecord, HandoffRouteTargetConfig,
204};
205pub use personas::{
206    disable_persona, fire_schedule as fire_persona_schedule, fire_trigger as fire_persona_trigger,
207    format_ms as format_persona_ms, now_ms as persona_now_ms, parse_rfc3339_ms as parse_persona_ms,
208    pause_persona, persona_status, record_persona_spend, register_persona_supervision_sink,
209    register_persona_value_sink, report_repair_worker_status, restore_persona_checkpoint,
210    resume_persona, PersonaAssignmentStatus, PersonaBudgetPolicy, PersonaBudgetStatus,
211    PersonaCheckpointAction, PersonaCheckpointRestoreOutcome, PersonaCheckpointRestoreRequest,
212    PersonaCheckpointResume, PersonaCheckpointUpdate, PersonaHandoffInboxItem, PersonaLease,
213    PersonaLifecycleState, PersonaQueuePositionUpdate, PersonaQueuedWork, PersonaReceiptUpdate,
214    PersonaRepairWorkerLifecycle, PersonaRepairWorkerStatusUpdate, PersonaRunCost,
215    PersonaRunReceipt, PersonaRuntimeBinding, PersonaStatus, PersonaSupervisionEvent,
216    PersonaSupervisionSink, PersonaSupervisionSinkRegistration, PersonaTriggerEnvelope,
217    PersonaValueEvent, PersonaValueEventKind, PersonaValueReceipt, PersonaValueSink,
218    PersonaValueSinkRegistration, StageDecl, StageExit, PERSONA_RUNTIME_TOPIC,
219};
220pub use provenance::{
221    build_signed_receipt, load_or_generate_agent_signing_key, verify_receipt, ProvenanceReceipt,
222    ReceiptBuildOptions, ReceiptVerificationReport,
223};
224pub use receipts::{
225    Receipt, ReceiptSink, ReceiptStatus, ReceiptValidationError, RedactingReceiptSink,
226    RedactionClass, RECEIPT_SCHEMA_ID, RECEIPT_SCHEMA_JSON, RECEIPT_SCHEMA_VERSION,
227};
228pub use record_filter::{normalize_record_filter_expression, CompiledRecordFilter};
229pub use runtime_limits::{
230    RuntimeLimitDescription, RuntimeLimitEntry, RuntimeLimits, RuntimeLimitsReport,
231    RUNTIME_LIMIT_DESCRIPTIONS,
232};
233pub use schema::json_to_vm_value;
234pub use sessions::{
235    CreateSession, ExpireSession, Session, SessionAttributes, SessionError, SessionStore,
236    TouchSession, SESSIONS_TOPIC,
237};
238pub use stdlib::hitl::{
239    append_hitl_response, ApprovalRequest, HitlHostResponse, HITL_APPROVALS_TOPIC,
240    HITL_DUAL_CONTROL_TOPIC, HITL_ESCALATIONS_TOPIC, HITL_QUESTIONS_TOPIC,
241};
242pub use stdlib::host::{clear_host_call_bridge, set_host_call_bridge, HostCallBridge};
243pub use stdlib::io::{set_stdout_passthrough, take_stderr_buffer};
244pub use stdlib::long_running::cancel_handle as cancel_long_running_handle;
245pub use stdlib::secret_scan::{
246    append_secret_scan_audit, audit_secret_scan_active, scan_content as secret_scan_content,
247    SecretFinding, SECRET_SCAN_AUDIT_TOPIC,
248};
249pub use stdlib::template::{
250    lookup_prompt_consumers, lookup_prompt_span, prompt_render_indices, record_prompt_render_index,
251    PromptSourceSpan, PromptSpanKind,
252};
253pub use stdlib::waitpoint::{
254    process_waitpoint_resume_event, service_waitpoints_once, WAITPOINT_RESUME_TOPIC,
255};
256pub use stdlib::workflow_messages::{
257    workflow_pause_for_base, workflow_publish_query_for_base, workflow_query_for_base,
258    workflow_respond_update_for_base, workflow_resume_for_base, workflow_signal_for_base,
259    workflow_update_for_base, WorkflowMailboxState,
260};
261pub use stdlib::{
262    register_agent_stdlib, register_core_stdlib, register_io_stdlib, register_vm_stdlib,
263    register_vm_stdlib_with_deferred_llm,
264};
265pub use store::register_store_builtins;
266pub use tenant::{
267    tenant_event_topic_prefix, tenant_secret_namespace, tenant_topic, validate_tenant_id, ApiKeyId,
268    TenantApiKeyRecord, TenantBudget, TenantEventLog, TenantRecord, TenantRegistrySnapshot,
269    TenantResolutionError, TenantScope, TenantSecretProvider, TenantStatus, TenantStore,
270    TENANT_EVENT_TOPIC_PREFIX, TENANT_REGISTRY_DIR, TENANT_REGISTRY_FILE,
271    TENANT_SECRET_NAMESPACE_PREFIX,
272};
273pub use triggers::{
274    append_dispatch_cancel_request, begin_in_flight, binding_autonomy_budget_would_exceed,
275    binding_budget_would_exceed, binding_version_as_of, classify_trigger_dlq_error,
276    clear_dispatcher_state, clear_orchestrator_budget, clear_trigger_registry, drain,
277    dynamic_deregister, dynamic_register, expected_predicate_cost_usd_micros, finish_in_flight,
278    install_manifest_triggers, install_orchestrator_budget, install_provider_catalog,
279    micros_to_usd, note_autonomous_decision, note_orchestrator_budget_cost,
280    orchestrator_budget_would_exceed, parse_flow_control_duration, pause, pin_trigger_binding,
281    provider_metadata, record_predicate_cost_sample, redact_headers, register_provider_schema,
282    registered_provider_metadata, registered_provider_schema_names, reset_binding_budget_windows,
283    reset_provider_catalog, reset_provider_catalog_with, resolve_live_or_as_of,
284    resolve_live_trigger_binding, resolve_trigger_binding_as_of, resume,
285    run_trigger_harness_fixture, scheduler_in_flight_by_key, scheduler_ready_stats_by_key,
286    snapshot_dispatcher_stats, snapshot_orchestrator_budget, snapshot_trigger_bindings,
287    unpin_trigger_binding, usd_to_micros, worker_claims_topic_name, worker_job_topic_name,
288    worker_response_topic_name, ClaimedWorkerJob, DispatchCancelRequest, DispatchError,
289    DispatchOutcome, DispatchStatus, Dispatcher, DispatcherDrainReport, DispatcherStatsSnapshot,
290    FairnessKey, HeaderRedactionPolicy, InboxIndex, NotionPolledChangeEvent,
291    OrchestratorBudgetConfig, OrchestratorBudgetSnapshot, ProviderCatalog, ProviderCatalogError,
292    ProviderId, ProviderMetadata, ProviderOutboundMethod, ProviderPayload, ProviderRuntimeMetadata,
293    ProviderSchema, ProviderSecretRequirement, ReadyKeyStats, RecordedTriggerBinding, RetryPolicy,
294    SchedulableJob, SchedulerKeyStat, SchedulerPolicy, SchedulerSnapshot, SchedulerState,
295    SchedulerStrategy, SignatureStatus, SignatureVerificationMetadata, StreamEventPayload,
296    TenantId, TraceId, TriggerBatchConfig, TriggerBindingSnapshot, TriggerBindingSource,
297    TriggerBindingSpec, TriggerBudgetExhaustionStrategy, TriggerConcurrencyConfig,
298    TriggerDebounceConfig, TriggerDispatchOutcome, TriggerEvent, TriggerEventId,
299    TriggerExpressionSpec, TriggerFlowControlConfig, TriggerHandlerSpec, TriggerHarnessResult,
300    TriggerId, TriggerMetricsSnapshot, TriggerPredicateSpec, TriggerPriorityOrderConfig,
301    TriggerRateLimitConfig, TriggerRegistryError, TriggerRetryConfig, TriggerSingletonConfig,
302    TriggerState, TriggerThrottleConfig, WorkerQueue, WorkerQueueClaimHandle,
303    WorkerQueueEnqueueReceipt, WorkerQueueInspectSnapshot, WorkerQueueJob, WorkerQueueJobState,
304    WorkerQueuePriority, WorkerQueueResponseRecord, WorkerQueueState, WorkerQueueSummary,
305    DEFAULT_INBOX_RETENTION_DAYS, DEFAULT_STARVATION_AGE_MS, TRIGGERS_LIFECYCLE_TOPIC,
306    TRIGGER_ATTEMPTS_TOPIC, TRIGGER_CANCEL_REQUESTS_TOPIC, TRIGGER_DLQ_TOPIC,
307    TRIGGER_INBOX_CLAIMS_TOPIC, TRIGGER_INBOX_ENVELOPES_TOPIC, TRIGGER_INBOX_LEGACY_TOPIC,
308    TRIGGER_OPERATION_AUDIT_TOPIC, TRIGGER_OUTBOX_TOPIC, TRIGGER_TEST_FIXTURES,
309    WORKER_QUEUE_CATALOG_TOPIC,
310};
311pub use trust_graph::{
312    append_active_trust_record, append_trust_record, export_trust_chain,
313    group_trust_records_by_trace, policy_for_agent, policy_for_autonomy_tier,
314    query_trust_graph_records, query_trust_records, resolve_agent_autonomy_tier,
315    summarize_trust_records, topic_for_agent, trust_score_for, verify_trust_chain, AutonomyTier,
316    TrustAgentSummary, TrustChainExport, TrustChainExportMetadata, TrustChainExportProducer,
317    TrustChainReport, TrustGraphRecord, TrustOutcome, TrustQueryFilters, TrustRecord,
318    TrustRecordActionKind, TrustScore, TrustTraceGroup, METADATA_KEY_EFFECTS_GRANT,
319    METADATA_KEY_EFFECTS_USED, METADATA_KEY_PARENT_RECORD_ID, OPENTRUSTGRAPH_ACCEPTED_SCHEMAS,
320    OPENTRUSTGRAPH_CHAIN_SCHEMA_V0, OPENTRUSTGRAPH_SCHEMA_V0, OPENTRUSTGRAPH_SCHEMA_V0_1,
321    TRUST_ACTION_RELEASE, TRUST_GRAPH_GLOBAL_TOPIC, TRUST_GRAPH_LEGACY_GLOBAL_TOPIC,
322    TRUST_GRAPH_LEGACY_TOPIC_PREFIX, TRUST_GRAPH_RECORDS_TOPIC, TRUST_GRAPH_TOPIC_PREFIX,
323};
324pub use value::*;
325pub use vm::*;
326
327#[cfg(feature = "vm-bench-internals")]
328#[doc(hidden)]
329pub mod bench_internals;
330
331/// Lex, parse, type-check, and compile source to bytecode in one call.
332/// Bails on the first type error. For callers that need diagnostics
333/// rather than early exit, use `harn_parser::check_source` directly
334/// and then call `Compiler::new().compile(&program)`.
335pub fn compile_source(source: &str) -> Result<Chunk, String> {
336    let program = harn_parser::check_source_strict(source).map_err(|e| e.to_string())?;
337    Compiler::new().compile(&program).map_err(|e| e.to_string())
338}
339
340/// Same as [`compile_source`] but compiles a specific named pipeline as
341/// the program entry point instead of the default-pipeline-or-first
342/// selection rule. Returns a runtime error when no pipeline with
343/// `pipeline_name` exists in the source.
344pub fn compile_source_named(source: &str, pipeline_name: &str) -> Result<Chunk, String> {
345    let program = harn_parser::check_source_strict(source).map_err(|e| e.to_string())?;
346    let has_pipeline = program.iter().any(|sn| {
347        let (_, inner) = harn_parser::peel_attributes(sn);
348        matches!(&inner.node, harn_parser::Node::Pipeline { name, .. } if name == pipeline_name)
349    });
350    if !has_pipeline {
351        return Err(format!("no pipeline named `{pipeline_name}` in source"));
352    }
353    Compiler::new()
354        .compile_named(&program, pipeline_name)
355        .map_err(|e| e.to_string())
356}
357
358pub fn json_schema_for_type_expr(type_expr: &harn_parser::TypeExpr) -> Option<serde_json::Value> {
359    let schema = compiler::Compiler::type_expr_to_schema_value(type_expr)?;
360    let json_schema = schema::schema_to_json_schema_value(&schema).ok()?;
361    Some(llm::vm_value_to_json(&json_schema))
362}
363
364pub fn json_schema_for_typed_params(params: &[harn_parser::TypedParam]) -> serde_json::Value {
365    let mut properties = serde_json::Map::new();
366    let mut required = Vec::new();
367
368    for param in params {
369        let param_schema = param
370            .type_expr
371            .as_ref()
372            .and_then(json_schema_for_type_expr)
373            .unwrap_or_else(|| serde_json::json!({}));
374        if param.default_value.is_none() {
375            required.push(serde_json::Value::String(param.name.clone()));
376        }
377        properties.insert(param.name.clone(), param_schema);
378    }
379
380    let mut schema = serde_json::Map::new();
381    schema.insert(
382        "type".to_string(),
383        serde_json::Value::String("object".to_string()),
384    );
385    schema.insert(
386        "properties".to_string(),
387        serde_json::Value::Object(properties),
388    );
389    if !required.is_empty() {
390        schema.insert("required".to_string(), serde_json::Value::Array(required));
391    }
392    serde_json::Value::Object(schema)
393}
394
395/// Reset all thread-local state that can leak between test runs.
396pub fn reset_thread_local_state() {
397    llm::reset_llm_state();
398    llm_config::clear_user_overrides();
399    http::reset_http_state();
400    channels::reset_channel_state();
401    event_log::reset_active_event_log();
402    egress::clear_explicit_egress_policy_requirement_for_host();
403    stdlib::reset_stdlib_state();
404    connectors::clear_active_connector_clients();
405    orchestration::clear_runtime_hooks();
406    orchestration::clear_execution_policy_stacks();
407    orchestration::clear_command_policies();
408    orchestration::clear_pipeline_on_finish();
409    orchestration::reset_lifecycle_receipt_registry();
410    redact::clear_policy_stack();
411    triggers::clear_dispatcher_state();
412    triggers::clear_trigger_registry();
413    events::reset_event_sinks();
414    tracing::set_tracing_enabled(false);
415    tracing::reset_tracing();
416    agent_events::reset_all_sinks();
417    agent_sessions::reset_session_store();
418    mcp_registry::reset();
419    mcp_host::reset_for_tests();
420    clock_mock::leak_audit::reset();
421}