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