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