Skip to main content

harn_vm/
lib.rs

1#![allow(clippy::result_large_err, clippy::cloned_ref_to_slice_refs)]
2
3pub mod a2a;
4pub mod agent_events;
5pub mod agent_sessions;
6pub mod bridge;
7mod builtin_id;
8pub mod checkpoint;
9mod chunk;
10mod compiler;
11pub mod connectors;
12pub mod event_log;
13pub mod events;
14mod http;
15pub mod jsonrpc;
16pub mod llm;
17pub mod llm_config;
18pub mod mcp;
19pub mod mcp_card;
20pub mod mcp_registry;
21pub mod mcp_server;
22pub mod metadata;
23pub mod observability;
24pub mod orchestration;
25pub mod personas;
26pub mod record_filter;
27pub mod runtime_context;
28pub mod runtime_paths;
29pub mod schema;
30pub mod secrets;
31pub(crate) mod shared_state;
32pub mod skills;
33pub mod stdlib;
34pub mod stdlib_modules;
35pub mod store;
36pub(crate) mod synchronization;
37pub mod tenant;
38pub mod tool_annotations;
39pub mod tracing;
40pub mod triggers;
41pub mod trust_graph;
42pub mod value;
43pub mod visible_text;
44mod vm;
45pub mod waitpoints;
46pub mod workspace_path;
47
48pub use builtin_id::BuiltinId;
49pub use checkpoint::register_checkpoint_builtins;
50pub use chunk::*;
51pub use compiler::*;
52pub use connectors::{
53    active_connector_client, active_metrics_registry, clear_active_connector_clients,
54    clear_active_metrics_registry, connector_export_denied_builtin_reason,
55    connector_export_effect_class,
56    cron::{CatchupMode, CronConnector},
57    default_connector_export_policy,
58    harn_module::{
59        load_contract as load_harn_connector_contract, HarnConnector, HarnConnectorContract,
60    },
61    hmac::verify_hmac_signed,
62    install_active_connector_clients, install_active_metrics_registry,
63    load_pending_webhook_handshakes, postprocess_normalized_event, ActivationHandle, ClientError,
64    Connector, ConnectorClient, ConnectorCtx, ConnectorError, ConnectorExportEffectClass,
65    ConnectorHttpResponse, ConnectorMetricsSnapshot, ConnectorNormalizeResult, ConnectorRegistry,
66    GenericWebhookConnector, GitHubConnector, HarnConnectorEffectPolicies, LinearConnector,
67    MetricsRegistry, NotionConnector, PersistedNotionWebhookHandshake, PostNormalizeOutcome,
68    ProviderPayloadSchema, RateLimitConfig, RateLimiterFactory, RawInbound, SlackConnector,
69    StreamConnector, TriggerBinding, TriggerKind, TriggerRegistry, WebhookSignatureVariant,
70};
71pub use http::{register_http_builtins, reset_http_state};
72pub use llm::register_llm_builtins;
73pub use llm::trigger_predicate::TriggerPredicateBudget;
74pub use mcp::{
75    connect_mcp_server, connect_mcp_server_from_json, connect_mcp_server_from_spec,
76    register_mcp_builtins,
77};
78pub use mcp_card::{fetch_server_card, load_server_card_from_path, CardError};
79pub use mcp_registry::{
80    active_handle as mcp_active_handle, ensure_active as mcp_ensure_active,
81    get_registration as mcp_get_registration, install_active as mcp_install_active,
82    is_registered as mcp_is_registered, register_servers as mcp_register_servers,
83    release as mcp_release, reset as mcp_reset_registry, snapshot_status as mcp_snapshot_status,
84    sweep_expired as mcp_sweep_expired, RegisteredMcpServer, RegistryStatus,
85};
86pub use mcp_server::{
87    take_mcp_serve_prompts, take_mcp_serve_registry, take_mcp_serve_resource_templates,
88    take_mcp_serve_resources, tool_registry_to_mcp_tools, McpServer,
89};
90pub use metadata::{register_metadata_builtins, register_scan_builtins};
91pub use personas::{
92    disable_persona, fire_schedule as fire_persona_schedule, fire_trigger as fire_persona_trigger,
93    format_ms as format_persona_ms, now_ms as persona_now_ms, parse_rfc3339_ms as parse_persona_ms,
94    pause_persona, persona_status, record_persona_spend, resume_persona, PersonaBudgetPolicy,
95    PersonaBudgetStatus, PersonaLease, PersonaLifecycleState, PersonaRunCost, PersonaRunReceipt,
96    PersonaRuntimeBinding, PersonaStatus, PersonaTriggerEnvelope, PERSONA_RUNTIME_TOPIC,
97};
98pub use record_filter::{normalize_record_filter_expression, CompiledRecordFilter};
99pub use schema::json_to_vm_value;
100pub use stdlib::hitl::{
101    append_hitl_response, HitlHostResponse, HITL_APPROVALS_TOPIC, HITL_DUAL_CONTROL_TOPIC,
102    HITL_ESCALATIONS_TOPIC, HITL_QUESTIONS_TOPIC,
103};
104pub use stdlib::host::{clear_host_call_bridge, set_host_call_bridge, HostCallBridge};
105pub use stdlib::secret_scan::{
106    append_secret_scan_audit, audit_secret_scan_active, scan_content as secret_scan_content,
107    SecretFinding, SECRET_SCAN_AUDIT_TOPIC,
108};
109pub use stdlib::template::{
110    lookup_prompt_consumers, lookup_prompt_span, prompt_render_indices, record_prompt_render_index,
111    PromptSourceSpan, PromptSpanKind,
112};
113pub use stdlib::waitpoint::{
114    process_waitpoint_resume_event, service_waitpoints_once, WAITPOINT_RESUME_TOPIC,
115};
116pub use stdlib::workflow_messages::{
117    workflow_pause_for_base, workflow_publish_query_for_base, workflow_query_for_base,
118    workflow_respond_update_for_base, workflow_resume_for_base, workflow_signal_for_base,
119    workflow_update_for_base, WorkflowMailboxState,
120};
121pub use stdlib::{
122    register_agent_stdlib, register_core_stdlib, register_io_stdlib, register_vm_stdlib,
123};
124pub use store::register_store_builtins;
125pub use tenant::{
126    tenant_event_topic_prefix, tenant_secret_namespace, tenant_topic, validate_tenant_id, ApiKeyId,
127    TenantApiKeyRecord, TenantBudget, TenantEventLog, TenantRecord, TenantRegistrySnapshot,
128    TenantResolutionError, TenantScope, TenantSecretProvider, TenantStatus, TenantStore,
129    TENANT_EVENT_TOPIC_PREFIX, TENANT_REGISTRY_DIR, TENANT_REGISTRY_FILE,
130    TENANT_SECRET_NAMESPACE_PREFIX,
131};
132pub use triggers::{
133    append_dispatch_cancel_request, begin_in_flight, binding_autonomy_budget_would_exceed,
134    binding_budget_would_exceed, binding_version_as_of, classify_trigger_dlq_error,
135    clear_dispatcher_state, clear_orchestrator_budget, clear_trigger_registry, drain,
136    dynamic_deregister, dynamic_register, expected_predicate_cost_usd_micros, finish_in_flight,
137    install_manifest_triggers, install_orchestrator_budget, micros_to_usd,
138    note_autonomous_decision, note_orchestrator_budget_cost, orchestrator_budget_would_exceed,
139    parse_flow_control_duration, pin_trigger_binding, provider_metadata,
140    record_predicate_cost_sample, redact_headers, register_provider_schema,
141    registered_provider_metadata, registered_provider_schema_names, reset_binding_budget_windows,
142    reset_provider_catalog, reset_provider_catalog_with, resolve_live_or_as_of,
143    resolve_live_trigger_binding, resolve_trigger_binding_as_of, run_trigger_harness_fixture,
144    snapshot_dispatcher_stats, snapshot_orchestrator_budget, snapshot_trigger_bindings,
145    unpin_trigger_binding, usd_to_micros, worker_claims_topic_name, worker_job_topic_name,
146    worker_response_topic_name, ClaimedWorkerJob, DispatchCancelRequest, DispatchError,
147    DispatchOutcome, DispatchStatus, Dispatcher, DispatcherDrainReport, DispatcherStatsSnapshot,
148    HeaderRedactionPolicy, InboxIndex, NotionPolledChangeEvent, OrchestratorBudgetConfig,
149    OrchestratorBudgetSnapshot, ProviderCatalog, ProviderCatalogError, ProviderId,
150    ProviderMetadata, ProviderOutboundMethod, ProviderPayload, ProviderRuntimeMetadata,
151    ProviderSchema, ProviderSecretRequirement, RecordedTriggerBinding, RetryPolicy,
152    SignatureStatus, SignatureVerificationMetadata, StreamEventPayload, TenantId, TraceId,
153    TriggerBatchConfig, TriggerBindingSnapshot, TriggerBindingSource, TriggerBindingSpec,
154    TriggerBudgetExhaustionStrategy, TriggerConcurrencyConfig, TriggerDebounceConfig,
155    TriggerDispatchOutcome, TriggerEvent, TriggerEventId, TriggerExpressionSpec,
156    TriggerFlowControlConfig, TriggerHandlerSpec, TriggerHarnessResult, TriggerId,
157    TriggerMetricsSnapshot, TriggerPredicateSpec, TriggerPriorityOrderConfig,
158    TriggerRateLimitConfig, TriggerRegistryError, TriggerRetryConfig, TriggerSingletonConfig,
159    TriggerState, TriggerThrottleConfig, WorkerQueue, WorkerQueueClaimHandle,
160    WorkerQueueEnqueueReceipt, WorkerQueueJob, WorkerQueueJobState, WorkerQueuePriority,
161    WorkerQueueResponseRecord, WorkerQueueState, WorkerQueueSummary, DEFAULT_INBOX_RETENTION_DAYS,
162    TRIGGERS_LIFECYCLE_TOPIC, TRIGGER_ATTEMPTS_TOPIC, TRIGGER_CANCEL_REQUESTS_TOPIC,
163    TRIGGER_DLQ_TOPIC, TRIGGER_INBOX_CLAIMS_TOPIC, TRIGGER_INBOX_ENVELOPES_TOPIC,
164    TRIGGER_INBOX_LEGACY_TOPIC, TRIGGER_OPERATION_AUDIT_TOPIC, TRIGGER_OUTBOX_TOPIC,
165    TRIGGER_TEST_FIXTURES, WORKER_QUEUE_CATALOG_TOPIC,
166};
167pub use trust_graph::{
168    append_active_trust_record, append_trust_record, group_trust_records_by_trace,
169    policy_for_agent, policy_for_autonomy_tier, query_trust_records, resolve_agent_autonomy_tier,
170    summarize_trust_records, topic_for_agent, trust_score_for, verify_trust_chain, AutonomyTier,
171    TrustAgentSummary, TrustChainReport, TrustOutcome, TrustQueryFilters, TrustRecord, TrustScore,
172    TrustTraceGroup, OPENTRUSTGRAPH_SCHEMA_V0, TRUST_GRAPH_GLOBAL_TOPIC,
173    TRUST_GRAPH_LEGACY_GLOBAL_TOPIC, TRUST_GRAPH_LEGACY_TOPIC_PREFIX, TRUST_GRAPH_TOPIC_PREFIX,
174};
175pub use value::*;
176pub use vm::*;
177
178/// Lex, parse, type-check, and compile source to bytecode in one call.
179/// Bails on the first type error. For callers that need diagnostics
180/// rather than early exit, use `harn_parser::check_source` directly
181/// and then call `Compiler::new().compile(&program)`.
182pub fn compile_source(source: &str) -> Result<Chunk, String> {
183    let program = harn_parser::check_source_strict(source).map_err(|e| e.to_string())?;
184    Compiler::new().compile(&program).map_err(|e| e.to_string())
185}
186
187pub fn json_schema_for_type_expr(type_expr: &harn_parser::TypeExpr) -> Option<serde_json::Value> {
188    let schema = compiler::Compiler::type_expr_to_schema_value(type_expr)?;
189    let json_schema = schema::schema_to_json_schema_value(&schema).ok()?;
190    Some(llm::vm_value_to_json(&json_schema))
191}
192
193pub fn json_schema_for_typed_params(params: &[harn_parser::TypedParam]) -> serde_json::Value {
194    let mut properties = serde_json::Map::new();
195    let mut required = Vec::new();
196
197    for param in params {
198        let param_schema = param
199            .type_expr
200            .as_ref()
201            .and_then(json_schema_for_type_expr)
202            .unwrap_or_else(|| serde_json::json!({}));
203        if param.default_value.is_none() {
204            required.push(serde_json::Value::String(param.name.clone()));
205        }
206        properties.insert(param.name.clone(), param_schema);
207    }
208
209    let mut schema = serde_json::Map::new();
210    schema.insert(
211        "type".to_string(),
212        serde_json::Value::String("object".to_string()),
213    );
214    schema.insert(
215        "properties".to_string(),
216        serde_json::Value::Object(properties),
217    );
218    if !required.is_empty() {
219        schema.insert("required".to_string(), serde_json::Value::Array(required));
220    }
221    serde_json::Value::Object(schema)
222}
223
224/// Reset all thread-local state that can leak between test runs.
225pub fn reset_thread_local_state() {
226    llm::reset_llm_state();
227    llm_config::clear_user_overrides();
228    http::reset_http_state();
229    event_log::reset_active_event_log();
230    stdlib::reset_stdlib_state();
231    connectors::clear_active_connector_clients();
232    orchestration::clear_runtime_hooks();
233    triggers::clear_dispatcher_state();
234    triggers::clear_trigger_registry();
235    events::reset_event_sinks();
236    agent_events::reset_all_sinks();
237    agent_sessions::reset_session_store();
238    mcp_registry::reset();
239}