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