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    install_handoff_routes, snapshot_handoff_routes, HandoffRouteConfig,
121    HandoffRouteDecisionRecord, HandoffRouteTargetConfig,
122};
123pub use personas::{
124    disable_persona, fire_schedule as fire_persona_schedule, fire_trigger as fire_persona_trigger,
125    format_ms as format_persona_ms, now_ms as persona_now_ms, parse_rfc3339_ms as parse_persona_ms,
126    pause_persona, persona_status, record_persona_spend, register_persona_value_sink,
127    resume_persona, PersonaBudgetPolicy, PersonaBudgetStatus, PersonaLease, PersonaLifecycleState,
128    PersonaRunCost, PersonaRunReceipt, PersonaRuntimeBinding, PersonaStatus,
129    PersonaTriggerEnvelope, PersonaValueEvent, PersonaValueEventKind, PersonaValueSink,
130    PersonaValueSinkRegistration, PERSONA_RUNTIME_TOPIC,
131};
132pub use provenance::{
133    build_signed_receipt, load_or_generate_agent_signing_key, verify_receipt, ProvenanceReceipt,
134    ReceiptBuildOptions, ReceiptVerificationReport,
135};
136pub use receipts::{
137    Receipt, ReceiptSink, ReceiptStatus, ReceiptValidationError, RedactionClass, RECEIPT_SCHEMA_ID,
138    RECEIPT_SCHEMA_JSON, RECEIPT_SCHEMA_VERSION,
139};
140pub use record_filter::{normalize_record_filter_expression, CompiledRecordFilter};
141pub use schema::json_to_vm_value;
142pub use sessions::{
143    CreateSession, ExpireSession, Session, SessionAttributes, SessionError, SessionStore,
144    TouchSession, SESSIONS_TOPIC,
145};
146pub use stdlib::hitl::{
147    append_hitl_response, ApprovalRequest, HitlHostResponse, HITL_APPROVALS_TOPIC,
148    HITL_DUAL_CONTROL_TOPIC, HITL_ESCALATIONS_TOPIC, HITL_QUESTIONS_TOPIC,
149};
150pub use stdlib::host::{clear_host_call_bridge, set_host_call_bridge, HostCallBridge};
151pub use stdlib::io::{set_stdout_passthrough, take_stderr_buffer};
152pub use stdlib::long_running::cancel_handle as cancel_long_running_handle;
153pub use stdlib::secret_scan::{
154    append_secret_scan_audit, audit_secret_scan_active, scan_content as secret_scan_content,
155    SecretFinding, SECRET_SCAN_AUDIT_TOPIC,
156};
157pub use stdlib::template::{
158    lookup_prompt_consumers, lookup_prompt_span, prompt_render_indices, record_prompt_render_index,
159    PromptSourceSpan, PromptSpanKind,
160};
161pub use stdlib::waitpoint::{
162    process_waitpoint_resume_event, service_waitpoints_once, WAITPOINT_RESUME_TOPIC,
163};
164pub use stdlib::workflow_messages::{
165    workflow_pause_for_base, workflow_publish_query_for_base, workflow_query_for_base,
166    workflow_respond_update_for_base, workflow_resume_for_base, workflow_signal_for_base,
167    workflow_update_for_base, WorkflowMailboxState,
168};
169pub use stdlib::{
170    register_agent_stdlib, register_core_stdlib, register_io_stdlib, register_vm_stdlib,
171};
172pub use store::register_store_builtins;
173pub use tenant::{
174    tenant_event_topic_prefix, tenant_secret_namespace, tenant_topic, validate_tenant_id, ApiKeyId,
175    TenantApiKeyRecord, TenantBudget, TenantEventLog, TenantRecord, TenantRegistrySnapshot,
176    TenantResolutionError, TenantScope, TenantSecretProvider, TenantStatus, TenantStore,
177    TENANT_EVENT_TOPIC_PREFIX, TENANT_REGISTRY_DIR, TENANT_REGISTRY_FILE,
178    TENANT_SECRET_NAMESPACE_PREFIX,
179};
180pub use triggers::{
181    append_dispatch_cancel_request, begin_in_flight, binding_autonomy_budget_would_exceed,
182    binding_budget_would_exceed, binding_version_as_of, classify_trigger_dlq_error,
183    clear_dispatcher_state, clear_orchestrator_budget, clear_trigger_registry, drain,
184    dynamic_deregister, dynamic_register, expected_predicate_cost_usd_micros, finish_in_flight,
185    install_manifest_triggers, install_orchestrator_budget, micros_to_usd,
186    note_autonomous_decision, note_orchestrator_budget_cost, orchestrator_budget_would_exceed,
187    parse_flow_control_duration, pin_trigger_binding, provider_metadata,
188    record_predicate_cost_sample, redact_headers, register_provider_schema,
189    registered_provider_metadata, registered_provider_schema_names, reset_binding_budget_windows,
190    reset_provider_catalog, reset_provider_catalog_with, resolve_live_or_as_of,
191    resolve_live_trigger_binding, resolve_trigger_binding_as_of, run_trigger_harness_fixture,
192    scheduler_in_flight_by_key, scheduler_ready_stats_by_key, snapshot_dispatcher_stats,
193    snapshot_orchestrator_budget, snapshot_trigger_bindings, unpin_trigger_binding, usd_to_micros,
194    worker_claims_topic_name, worker_job_topic_name, worker_response_topic_name, ClaimedWorkerJob,
195    DispatchCancelRequest, DispatchError, DispatchOutcome, DispatchStatus, Dispatcher,
196    DispatcherDrainReport, DispatcherStatsSnapshot, FairnessKey, HeaderRedactionPolicy, InboxIndex,
197    NotionPolledChangeEvent, OrchestratorBudgetConfig, OrchestratorBudgetSnapshot, ProviderCatalog,
198    ProviderCatalogError, ProviderId, ProviderMetadata, ProviderOutboundMethod, ProviderPayload,
199    ProviderRuntimeMetadata, ProviderSchema, ProviderSecretRequirement, ReadyKeyStats,
200    RecordedTriggerBinding, RetryPolicy, SchedulableJob, SchedulerKeyStat, SchedulerPolicy,
201    SchedulerSnapshot, SchedulerState, SchedulerStrategy, SignatureStatus,
202    SignatureVerificationMetadata, StreamEventPayload, TenantId, TraceId, TriggerBatchConfig,
203    TriggerBindingSnapshot, TriggerBindingSource, TriggerBindingSpec,
204    TriggerBudgetExhaustionStrategy, TriggerConcurrencyConfig, TriggerDebounceConfig,
205    TriggerDispatchOutcome, TriggerEvent, TriggerEventId, TriggerExpressionSpec,
206    TriggerFlowControlConfig, TriggerHandlerSpec, TriggerHarnessResult, TriggerId,
207    TriggerMetricsSnapshot, TriggerPredicateSpec, TriggerPriorityOrderConfig,
208    TriggerRateLimitConfig, TriggerRegistryError, TriggerRetryConfig, TriggerSingletonConfig,
209    TriggerState, TriggerThrottleConfig, WorkerQueue, WorkerQueueClaimHandle,
210    WorkerQueueEnqueueReceipt, WorkerQueueInspectSnapshot, WorkerQueueJob, WorkerQueueJobState,
211    WorkerQueuePriority, WorkerQueueResponseRecord, WorkerQueueState, WorkerQueueSummary,
212    DEFAULT_INBOX_RETENTION_DAYS, DEFAULT_STARVATION_AGE_MS, TRIGGERS_LIFECYCLE_TOPIC,
213    TRIGGER_ATTEMPTS_TOPIC, TRIGGER_CANCEL_REQUESTS_TOPIC, TRIGGER_DLQ_TOPIC,
214    TRIGGER_INBOX_CLAIMS_TOPIC, TRIGGER_INBOX_ENVELOPES_TOPIC, TRIGGER_INBOX_LEGACY_TOPIC,
215    TRIGGER_OPERATION_AUDIT_TOPIC, TRIGGER_OUTBOX_TOPIC, TRIGGER_TEST_FIXTURES,
216    WORKER_QUEUE_CATALOG_TOPIC,
217};
218pub use trust_graph::{
219    append_active_trust_record, append_trust_record, export_trust_chain,
220    group_trust_records_by_trace, policy_for_agent, policy_for_autonomy_tier,
221    query_trust_graph_records, query_trust_records, resolve_agent_autonomy_tier,
222    summarize_trust_records, topic_for_agent, trust_score_for, verify_trust_chain, AutonomyTier,
223    TrustAgentSummary, TrustChainExport, TrustChainExportMetadata, TrustChainExportProducer,
224    TrustChainReport, TrustGraphRecord, TrustOutcome, TrustQueryFilters, TrustRecord, TrustScore,
225    TrustTraceGroup, OPENTRUSTGRAPH_CHAIN_SCHEMA_V0, OPENTRUSTGRAPH_SCHEMA_V0,
226    TRUST_GRAPH_GLOBAL_TOPIC, TRUST_GRAPH_LEGACY_GLOBAL_TOPIC, TRUST_GRAPH_LEGACY_TOPIC_PREFIX,
227    TRUST_GRAPH_RECORDS_TOPIC, TRUST_GRAPH_TOPIC_PREFIX,
228};
229pub use value::*;
230pub use vm::*;
231
232/// Lex, parse, type-check, and compile source to bytecode in one call.
233/// Bails on the first type error. For callers that need diagnostics
234/// rather than early exit, use `harn_parser::check_source` directly
235/// and then call `Compiler::new().compile(&program)`.
236pub fn compile_source(source: &str) -> Result<Chunk, String> {
237    let program = harn_parser::check_source_strict(source).map_err(|e| e.to_string())?;
238    Compiler::new().compile(&program).map_err(|e| e.to_string())
239}
240
241/// Same as [`compile_source`] but compiles a specific named pipeline as
242/// the program entry point instead of the default-pipeline-or-first
243/// selection rule. Returns a runtime error when no pipeline with
244/// `pipeline_name` exists in the source.
245pub fn compile_source_named(source: &str, pipeline_name: &str) -> Result<Chunk, String> {
246    let program = harn_parser::check_source_strict(source).map_err(|e| e.to_string())?;
247    let has_pipeline = program.iter().any(|sn| {
248        let (_, inner) = harn_parser::peel_attributes(sn);
249        matches!(&inner.node, harn_parser::Node::Pipeline { name, .. } if name == pipeline_name)
250    });
251    if !has_pipeline {
252        return Err(format!("no pipeline named `{pipeline_name}` in source"));
253    }
254    Compiler::new()
255        .compile_named(&program, pipeline_name)
256        .map_err(|e| e.to_string())
257}
258
259pub fn json_schema_for_type_expr(type_expr: &harn_parser::TypeExpr) -> Option<serde_json::Value> {
260    let schema = compiler::Compiler::type_expr_to_schema_value(type_expr)?;
261    let json_schema = schema::schema_to_json_schema_value(&schema).ok()?;
262    Some(llm::vm_value_to_json(&json_schema))
263}
264
265pub fn json_schema_for_typed_params(params: &[harn_parser::TypedParam]) -> serde_json::Value {
266    let mut properties = serde_json::Map::new();
267    let mut required = Vec::new();
268
269    for param in params {
270        let param_schema = param
271            .type_expr
272            .as_ref()
273            .and_then(json_schema_for_type_expr)
274            .unwrap_or_else(|| serde_json::json!({}));
275        if param.default_value.is_none() {
276            required.push(serde_json::Value::String(param.name.clone()));
277        }
278        properties.insert(param.name.clone(), param_schema);
279    }
280
281    let mut schema = serde_json::Map::new();
282    schema.insert(
283        "type".to_string(),
284        serde_json::Value::String("object".to_string()),
285    );
286    schema.insert(
287        "properties".to_string(),
288        serde_json::Value::Object(properties),
289    );
290    if !required.is_empty() {
291        schema.insert("required".to_string(), serde_json::Value::Array(required));
292    }
293    serde_json::Value::Object(schema)
294}
295
296/// Reset all thread-local state that can leak between test runs.
297pub fn reset_thread_local_state() {
298    llm::reset_llm_state();
299    llm_config::clear_user_overrides();
300    http::reset_http_state();
301    event_log::reset_active_event_log();
302    stdlib::reset_stdlib_state();
303    connectors::clear_active_connector_clients();
304    orchestration::clear_runtime_hooks();
305    orchestration::clear_execution_policy_stacks();
306    orchestration::clear_command_policies();
307    triggers::clear_dispatcher_state();
308    triggers::clear_trigger_registry();
309    events::reset_event_sinks();
310    agent_events::reset_all_sinks();
311    agent_sessions::reset_session_store();
312    mcp_registry::reset();
313}