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