1#![recursion_limit = "256"]
2#![allow(clippy::result_large_err, clippy::cloned_ref_to_slice_refs)]
3pub use harn_clock as clock;
23
24mod runtime_stack;
25pub use runtime_stack::RUNTIME_STACK_SIZE;
26
27pub mod a2a;
28pub mod actor_chain;
29pub mod agent_events;
30pub(crate) mod agent_session_journal;
31pub mod agent_session_restore;
32pub mod agent_sessions;
33pub mod agent_transcript_budget;
34pub mod atomic_io;
35pub mod autonomy;
36#[cfg(feature = "cloud-aws")]
37pub(crate) mod aws_sigv4;
38#[cfg(not(feature = "cloud-aws"))]
39#[path = "aws_sigv4_disabled.rs"]
40pub(crate) mod aws_sigv4;
41pub mod boundary;
42pub mod bridge;
43pub use bridge::{
44 inject_leading_authorities, inject_leading_authority, leading_authority_param_count,
45};
46pub mod builtin_profile;
47pub mod bytecode_cache;
48pub mod call_budget;
49pub mod canonical_json;
50pub mod channel_guardrails;
51pub mod channels;
52pub mod checkpoint;
53mod chunk;
54mod compiler;
55pub mod composition;
56pub mod conditional_replace;
57pub mod config;
58pub mod connectors;
59pub mod context_manifest;
60pub mod corrections;
61pub mod coverage;
62pub(crate) mod durable_rate_limit;
63pub mod duration_parse;
64pub mod egress;
65pub mod environment_registry;
66pub mod event_log;
67pub mod events;
68pub mod external_agent;
69pub mod flow;
70pub mod harness;
71pub mod harness_auth;
72pub(crate) mod harness_crypto;
73pub mod harness_net;
74pub mod harness_system;
75pub mod harness_tenant;
76pub mod host_attachments;
77mod http;
78pub mod jsonrpc;
79pub(crate) mod limits;
80pub mod linked_program;
81pub mod llm;
82pub mod llm_config;
83pub mod mcp;
84pub mod mcp_allowlist;
85pub mod mcp_auth;
86pub mod mcp_bulk_auth;
87pub mod mcp_card;
88pub mod mcp_client_roots;
89pub mod mcp_elicit;
90pub mod mcp_host;
91pub mod mcp_identity;
92pub mod mcp_input;
93pub mod mcp_json_discovery;
94pub mod mcp_oauth;
95pub mod mcp_presets;
96pub mod mcp_progress;
97pub mod mcp_protocol;
98pub mod mcp_registry;
99pub mod mcp_sampling;
100pub mod mcp_server;
101pub mod mcp_tasks;
102pub mod metadata;
103pub mod module_artifact;
104pub mod module_source;
105pub mod observability;
106pub mod op_interrupt;
107pub mod orchestration;
108mod persistent_state;
109pub mod personas;
110pub mod portable;
111mod prepared_module;
112pub mod prepared_run;
113pub mod process_sandbox;
114pub mod profile;
115pub mod provenance;
116pub mod provider_catalog;
117pub mod receipts;
118pub mod record_filter;
119pub mod redact;
120pub mod run_events;
121pub mod runtime_context;
122pub(crate) mod runtime_guards;
123pub mod runtime_limits;
124pub mod runtime_paths;
125pub(crate) mod runtime_sqlite;
126pub mod schema;
127pub(crate) mod secret_patterns;
128pub mod secrets;
129pub mod security;
130pub mod session_bundle;
131pub mod session_timeline;
132pub mod sessions;
133pub(crate) mod shared_state;
134pub mod shells;
135pub mod skills;
136pub mod stdlib;
137pub use stdlib::session_change::{
139 subscribe as subscribe_session_changes, SessionChangeSubscription,
140};
141pub use stdlib::session_store::open_canonical_store;
142pub mod stdlib_modules;
143pub mod step_runtime;
144pub mod store;
145pub(crate) mod synchronization;
146pub mod tenant;
147pub(crate) mod term;
148pub(crate) mod test_env;
149pub mod testbench;
150pub mod text;
151pub mod text_diff;
152pub mod tool_annotations;
153pub mod tool_call_cancellations;
154pub mod tool_surface;
155pub mod tracing;
156pub mod triggers;
157pub mod trust_graph;
158pub(crate) mod url_encoding;
159pub mod user_dirs;
160
161pub fn initialize_runtime_assets() {
169 secret_patterns::initialize_default_secret_patterns();
170}
171
172pub fn initialize_runtime() -> Result<(), environment_registry::EnvironmentValidationError> {
175 environment_registry::validate_startup_environment()?;
176 initialize_runtime_assets();
177 Ok(())
178}
179
180pub mod clock_mock {
185 pub(crate) use crate::triggers::test_util::clock::scope_capability_clock;
186 pub use crate::triggers::test_util::clock::{
187 active_clock, active_mock_clock, advance, clear_overrides, install_override, instant_now,
188 is_mocked, now_ms, now_utc, sleep, ClockInstant, ClockOverrideGuard, MockClock,
189 };
190
191 pub mod leak_audit {
195 pub use crate::triggers::test_util::clock_leak::{
196 drain, enter_scope, install_scope, instant_now, reset, snapshot, wall_now, ClockLeak,
197 ClockLeakScope, ClockLeakScopeGuard,
198 };
199 }
200}
201
202pub(crate) mod text_index;
203pub mod typecheck;
204pub mod value;
205pub mod verification;
206pub mod visible_text;
207mod vm;
208pub(crate) mod wait_for_graph;
209pub mod waitpoints;
210pub mod windows_path;
211pub mod workspace_anchor;
212pub mod workspace_path;
213
214pub use persistent_state::{register_persistent_state_builtins_at_root, PersistentStateRoot};
215pub use prepared_module::{PreparedModuleCache, PreparedModuleCacheStats};
216
217pub use actor_chain::{
218 ActorChain, ActorChainEntry, ActorChainError, Principal, ScopeAttenuationMode,
219 ScopeAttenuationPolicy, ScopeAttenuationViolation,
220};
221pub use call_budget::{
222 charge_mcp_call, charge_pg_query, install_mcp_call_budget, install_pg_query_budget,
223 McpCallBudgetGuard, PgQueryBudgetGuard,
224};
225pub use checkpoint::register_checkpoint_builtins;
226pub use chunk::*;
227pub use compiler::*;
228pub use connectors::{
229 active_connector_client, active_metrics_registry, clear_active_connector_clients,
230 clear_active_metrics_registry, connector_export_denied_builtin_reason,
231 connector_export_denied_harness_method_reason, connector_export_effect_class,
232 cron::{CatchupMode, CronConnector},
233 declared_secret_ids, default_connector_export_policy,
234 harn_module::{
235 load_contract as load_harn_connector_contract, HarnConnector, HarnConnectorContract,
236 },
237 hmac::{verify_hmac_signed, SIGNATURE_VERIFY_AUDIT_TOPIC},
238 install_active_connector_clients, install_active_metrics_registry,
239 postprocess_normalized_event, ActivationHandle, ClientError, Connector, ConnectorClient,
240 ConnectorCtx, ConnectorError, ConnectorExportEffectClass, ConnectorHttpResponse,
241 ConnectorMetricsSnapshot, ConnectorNormalizeResult, ConnectorRegistry, GenericWebhookConnector,
242 HarnConnectorEffectPolicies, MetricsRegistry, PostNormalizeOutcome, ProviderPayloadSchema,
243 RateLimitConfig, RateLimiterFactory, RawInbound, StreamConnector, TriggerBinding, TriggerKind,
244 TriggerRegistry, WebhookSignatureVariant,
245};
246pub use corrections::{
247 append_correction_record, apply_corrections_to_policy, correction_query_filters_from_json,
248 correction_record_from_json, policy_with_corrections, query_correction_records,
249 CorrectionQueryFilters, CorrectionRecord, CorrectionScope, CORRECTIONS_TOPIC,
250 CORRECTION_EVENT_KIND, CORRECTION_SCHEMA_V0,
251};
252pub use harn_kernel::BuiltinId;
253pub use harness::{
254 DenyEvent, Harness, HarnessAgent, HarnessCall, HarnessChannels, HarnessClock, HarnessEnv,
255 HarnessFs, HarnessKind, HarnessLlm, HarnessMemory, HarnessNet, HarnessObs, HarnessPostgres,
256 HarnessProcess, HarnessRandom, HarnessSecrets, HarnessSqlite, HarnessStdio, HarnessSystem,
257 HarnessTenant, HarnessTerm, HarnessTesting, MockHarnessBuilder, VmHarness,
258};
259pub use harness_auth::{
260 current_auth_principal, enter_auth_principal, AuthPrincipal, AuthPrincipalScopeGuard,
261 MISSING_PRINCIPAL_MESSAGE,
262};
263pub use harness_net::{
264 bypass_enabled as net_policy_bypass_enabled, NetMatcher, NetPolicy, NetPolicyAudit,
265 NetPolicyDecision, NetPolicyDefault, NetPolicyRule, OnViolation, HARN_NET_POLICY_BYPASS_ENV,
266 NET_POLICY_AUDIT_TOPIC,
267};
268pub use harness_tenant::{
269 current_tenant_id, enter_tenant, TenantScopeGuard, MISSING_TENANT_MESSAGE,
270};
271pub use http::{register_http_builtins, reset_http_state};
272pub use llm::register_llm_builtins;
273pub use llm::trigger_predicate::TriggerPredicateBudget;
274pub use llm::{
275 current_agent_session_id, install_llm_cost_budget, install_llm_token_budget,
276 peek_llm_cost_budget, peek_llm_token_budget, register_session_end_hook, set_llm_cost_budget,
277 set_llm_token_budget, LlmBudgetGuard, LlmTokenBudgetGuard, SessionEndHookRegistration,
278};
279pub use mcp::{connect_mcp_server_from_json, connect_mcp_server_from_spec, register_mcp_builtins};
280pub use mcp_allowlist::{
281 build_catalog as build_mcp_catalog, catalog_for_request as mcp_catalog_for_request,
282 AdvertisedItem as McpAdvertisedItem, CatalogRequest as McpCatalogRequest, McpAllowlist,
283 McpAllowlistItem, McpCatalog, McpCatalogItem, McpCatalogServer, McpItemKind,
284 MCP_ALLOWLIST_SCHEMA_VERSION,
285};
286pub use mcp_card::{fetch_server_card, load_server_card_from_path, CardError};
287pub use mcp_host::{
288 cache_stats as mcp_host_cache_stats, set_allowlist as set_mcp_host_allowlist,
289 AllowlistDecision as McpHostAllowlistDecision, AllowlistGuard as McpHostAllowlistGuard,
290 BreakerState as McpHostBreakerState, CacheStats as McpHostCacheStats, McpHostStatus,
291 SpawnOptions as McpHostSpawnOptions, SupervisionPolicy as McpHostSupervisionPolicy,
292};
293pub use mcp_registry::{
294 active_handle as mcp_active_handle, ensure_active as mcp_ensure_active,
295 get_registration as mcp_get_registration, install_active as mcp_install_active,
296 is_registered as mcp_is_registered, register_servers as mcp_register_servers,
297 release as mcp_release, reset as mcp_reset_registry, snapshot_status as mcp_snapshot_status,
298 sweep_expired as mcp_sweep_expired, RegisteredMcpServer, RegistryStatus,
299};
300pub use mcp_server::{
301 take_mcp_serve_metadata, take_mcp_serve_prompts, take_mcp_serve_registry,
302 take_mcp_serve_resource_templates, take_mcp_serve_resources, tool_registry_to_mcp_tools,
303 McpServer, McpServerMetadata,
304};
305pub use metadata::register_metadata_builtins;
306pub use observability::audit::{audit_events as audit_obs_events, AuditFinding, AuditFindingKind};
307pub use observability::execution_scope::{
308 current_execution_scope, enter_execution_scope, mint_execution_scope, ExecutionScopeGuard,
309};
310pub use observability::request_id::{current_request_id, enter_request_id, RequestIdScopeGuard};
311pub use orchestration::{
312 benchmark_adapted_replay_pair, benchmark_replay_trace, build_replay_benchmark_report,
313 OpenCodeJsonlAdapter, ReplayBenchmarkCloudIngest, ReplayBenchmarkError,
314 ReplayBenchmarkFixtureReceipt, ReplayBenchmarkFixtureReport, ReplayBenchmarkMetrics,
315 ReplayBenchmarkReport, ReplayBenchmarkSuiteIdentity, ReplayBenchmarkSummary,
316 ReplayCategoryMetric, ReplayDebuggingProxyMetrics, ReplayRuntimeCostMetrics,
317 ReplayTraceAdapter, OPENCODE_JSONL_ADAPTER_ID, OPENCODE_JSONL_ADAPTER_SCHEMA_VERSION,
318 REPLAY_BENCHMARK_CLOUD_INGEST_KIND, REPLAY_BENCHMARK_REPORT_SCHEMA_VERSION,
319};
320pub use orchestration::{
321 canonicalize_run, first_divergence, run_replay_oracle_trace, ReplayAllowlistRule,
322 ReplayDivergence, ReplayExpectation, ReplayOracleError, ReplayOracleReport, ReplayOracleTrace,
323 ReplayTraceRun, ReplayTraceRunCounts, REPLAY_TRACE_SCHEMA_VERSION,
324};
325pub use orchestration::{
326 install_handoff_routes, snapshot_handoff_routes, HandoffRouteConfig,
327 HandoffRouteDecisionRecord, HandoffRouteTargetConfig,
328};
329pub use personas::{
330 disable_persona, fire_schedule as fire_persona_schedule, fire_trigger as fire_persona_trigger,
331 format_ms as format_persona_ms, now_ms as persona_now_ms, parse_rfc3339_ms as parse_persona_ms,
332 pause_persona, persona_status, record_persona_spend, register_persona_supervision_sink,
333 register_persona_value_sink, report_repair_worker_status, restore_persona_checkpoint,
334 resume_persona, PersonaAssignmentStatus, PersonaBudgetPolicy, PersonaBudgetStatus,
335 PersonaCheckpointAction, PersonaCheckpointRestoreOutcome, PersonaCheckpointRestoreRequest,
336 PersonaCheckpointResume, PersonaCheckpointUpdate, PersonaHandoffInboxItem, PersonaLease,
337 PersonaLifecycleState, PersonaQueuePositionUpdate, PersonaQueuedWork, PersonaReceiptUpdate,
338 PersonaRepairWorkerLifecycle, PersonaRepairWorkerStatusUpdate, PersonaRunCost,
339 PersonaRunReceipt, PersonaRuntimeBinding, PersonaStatus, PersonaSupervisionEvent,
340 PersonaSupervisionSink, PersonaSupervisionSinkRegistration, PersonaTriggerEnvelope,
341 PersonaValueEvent, PersonaValueEventKind, PersonaValueReceipt, PersonaValueSink,
342 PersonaValueSinkRegistration, StageDecl, StageExit, PERSONA_RUNTIME_TOPIC,
343};
344pub use provenance::{
345 build_signed_receipt, load_or_generate_agent_signing_key, verify_receipt, ProvenanceReceipt,
346 ReceiptBuildOptions, ReceiptVerificationReport,
347};
348pub use receipts::{
349 Receipt, ReceiptSink, ReceiptStatus, ReceiptValidationError, RedactingReceiptSink,
350 RedactionClass, RECEIPT_SCHEMA_ID, RECEIPT_SCHEMA_JSON, RECEIPT_SCHEMA_VERSION,
351};
352pub use record_filter::{normalize_record_filter_expression, CompiledRecordFilter};
353pub use runtime_limits::{
354 RuntimeLimitDescription, RuntimeLimitEntry, RuntimeLimits, RuntimeLimitsReport,
355 RUNTIME_LIMIT_DESCRIPTIONS,
356};
357pub use schema::json_to_vm_value;
358pub use sessions::{
359 CreateSession, ExpireSession, Session, SessionAttributes, SessionError, SessionStore,
360 TouchSession, SESSIONS_TOPIC,
361};
362pub use stdlib::fs::ignore_policy;
368#[doc(hidden)]
369pub use stdlib::fs::invalidate_cached_file_text;
370pub use stdlib::hitl::{
371 append_hitl_response, ApprovalRequest, HitlHostResponse, HITL_APPROVALS_TOPIC,
372 HITL_DUAL_CONTROL_TOPIC, HITL_ESCALATIONS_TOPIC, HITL_QUESTIONS_TOPIC,
373};
374pub use stdlib::host::turn_cache as host_turn_cache;
376pub use stdlib::host::{
377 clear_host_call_bridge, dispatch_host_operation, host_call_ready, install_host_call_bridge,
378 set_host_call_bridge, HostCallBridge, HostCallBridgeGuard, HostCallDispatchFuture,
379};
380pub use stdlib::http_response::{
381 parse_envelope as parse_http_envelope, HttpEnvelope, HttpHeaderValue, WsUpgradeSpec,
382 HTTP_RESPONSE_TAG_KEY, HTTP_RESPONSE_TAG_VERSION,
383};
384#[cfg(feature = "postgres")]
385pub use stdlib::install_shared_pool_registry;
386pub use stdlib::io::{
387 reserve_stdio_for_current_thread, set_stdout_passthrough, take_stderr_buffer,
388 StdioReservationGuard,
389};
390pub use stdlib::long_running::cancel_handle as cancel_long_running_handle;
391pub use stdlib::observability::install_default_backend as install_obs_default_backend;
392pub use stdlib::secret_scan::{
393 append_secret_scan_audit, audit_secret_scan_active, scan_content as secret_scan_content,
394 SecretFinding, SECRET_SCAN_AUDIT_TOPIC,
395};
396pub use stdlib::template::{
397 lookup_prompt_consumers, lookup_prompt_span, prompt_render_indices, record_prompt_render_index,
398 PromptSourceSpan, PromptSpanKind,
399};
400pub use stdlib::waitpoint::{
401 process_waitpoint_resume_event, service_waitpoints_once, WAITPOINT_RESUME_TOPIC,
402};
403pub use stdlib::workflow_messages::{
404 workflow_pause_for_base, workflow_publish_query_for_base, workflow_query_for_base,
405 workflow_respond_update_for_base, workflow_resume_for_base, workflow_signal_for_base,
406 workflow_update_for_base, WorkflowMailboxState,
407};
408pub use stdlib::{
409 register_agent_stdlib, register_core_stdlib, register_io_stdlib, register_vm_stdlib,
410};
411pub use store::register_store_builtins;
412pub use tenant::{
413 tenant_event_topic_prefix, tenant_secret_namespace, tenant_topic, validate_tenant_id, ApiKeyId,
414 TenantApiKeyRecord, TenantBudget, TenantEventLog, TenantRecord, TenantRegistrySnapshot,
415 TenantResolutionError, TenantScope, TenantSecretProvider, TenantStatus, TenantStore,
416 TENANT_EVENT_TOPIC_PREFIX, TENANT_REGISTRY_DIR, TENANT_REGISTRY_FILE,
417 TENANT_SECRET_NAMESPACE_PREFIX,
418};
419pub use triggers::{
420 append_dispatch_cancel_request, begin_in_flight, binding_autonomy_budget_would_exceed,
421 binding_budget_would_exceed, binding_version_as_of, classify_trigger_dlq_error,
422 clear_dispatcher_state, clear_orchestrator_budget, clear_trigger_registry, drain,
423 dynamic_deregister, dynamic_register, expected_predicate_cost_usd_micros, finish_in_flight,
424 install_manifest_triggers, install_orchestrator_budget, micros_to_usd,
425 note_autonomous_decision, note_orchestrator_budget_cost, orchestrator_budget_would_exceed,
426 parse_flow_control_duration, pause, pin_trigger_binding, provider_metadata,
427 record_predicate_cost_sample, redact_headers, register_provider_schemas,
428 registered_provider_metadata, registered_provider_schema_names, reset_binding_budget_windows,
429 reset_provider_catalog, resolve_live_or_as_of, resolve_live_trigger_binding,
430 resolve_trigger_binding_as_of, resume, run_trigger_harness_fixture, scheduler_in_flight_by_key,
431 scheduler_ready_stats_by_key, snapshot_dispatcher_stats, snapshot_orchestrator_budget,
432 snapshot_trigger_bindings, unpin_trigger_binding, usd_to_micros, worker_claims_topic_name,
433 worker_job_topic_name, worker_response_topic_name, ClaimedWorkerJob, DispatchCancelRequest,
434 DispatchError, DispatchOutcome, DispatchStatus, Dispatcher, DispatcherDrainReport,
435 DispatcherStatsSnapshot, ExtensionProviderPayload, FairnessKey, HeaderRedactionPolicy,
436 InboxIndex, OrchestratorBudgetConfig, OrchestratorBudgetSnapshot, ProviderCatalog,
437 ProviderCatalogError, ProviderId, ProviderMetadata, ProviderOutboundMethod, ProviderPayload,
438 ProviderRuntimeMetadata, ProviderSchema, ProviderSecretRequirement, ReadyKeyStats,
439 RecordedTriggerBinding, RetryPolicy, SchedulableJob, SchedulerKeyStat, SchedulerPolicy,
440 SchedulerSnapshot, SchedulerState, SchedulerStrategy, SignatureStatus,
441 SignatureVerificationMetadata, StreamEventPayload, TenantId, TraceId, TriggerBatchConfig,
442 TriggerBindingSnapshot, TriggerBindingSource, TriggerBindingSpec,
443 TriggerBudgetExhaustionStrategy, TriggerConcurrencyConfig, TriggerDebounceConfig,
444 TriggerDispatchOutcome, TriggerEvent, TriggerEventId, TriggerExpressionSpec,
445 TriggerFlowControlConfig, TriggerHandlerSpec, TriggerHarnessResult, TriggerId,
446 TriggerMetricsSnapshot, TriggerPredicateSpec, TriggerPriorityOrderConfig,
447 TriggerRateLimitConfig, TriggerRegistryError, TriggerRetryConfig, TriggerSingletonConfig,
448 TriggerState, TriggerThrottleConfig, WorkerQueue, WorkerQueueClaimHandle,
449 WorkerQueueEnqueueReceipt, WorkerQueueInspectSnapshot, WorkerQueueJob, WorkerQueueJobState,
450 WorkerQueuePriority, WorkerQueueResponseRecord, WorkerQueueState, WorkerQueueSummary,
451 DEFAULT_INBOX_RETENTION_DAYS, DEFAULT_STARVATION_AGE_MS, TRIGGERS_LIFECYCLE_TOPIC,
452 TRIGGER_ATTEMPTS_TOPIC, TRIGGER_CANCEL_REQUESTS_TOPIC, TRIGGER_DLQ_TOPIC,
453 TRIGGER_INBOX_CLAIMS_TOPIC, TRIGGER_INBOX_ENVELOPES_TOPIC, TRIGGER_INBOX_LEGACY_TOPIC,
454 TRIGGER_INBOX_OBSERVABILITY_TOPIC, TRIGGER_OPERATION_AUDIT_TOPIC, TRIGGER_OUTBOX_TOPIC,
455 TRIGGER_TEST_FIXTURES, WORKER_QUEUE_CATALOG_TOPIC,
456};
457pub use trust_graph::{
458 append_active_scope_attenuation_alert, append_active_trust_record,
459 append_scope_attenuation_alert, append_trust_record, export_trust_chain,
460 group_trust_records_by_trace, policy_for_agent, policy_for_autonomy_tier,
461 query_trust_graph_records, query_trust_records, resolve_agent_autonomy_tier,
462 summarize_trust_records, topic_for_agent, trust_score_for, verify_trust_chain, AutonomyTier,
463 TrustAgentSummary, TrustChainExport, TrustChainExportMetadata, TrustChainExportProducer,
464 TrustChainReport, TrustGraphRecord, TrustOutcome, TrustQueryFilters, TrustRecord,
465 TrustRecordActionKind, TrustScore, TrustTraceGroup, METADATA_KEY_ACTOR_CHAIN,
466 METADATA_KEY_ACTOR_CHAIN_ALERT, METADATA_KEY_EFFECTS_GRANT, METADATA_KEY_EFFECTS_USED,
467 METADATA_KEY_PARENT_RECORD_ID, OPENTRUSTGRAPH_ACCEPTED_SCHEMAS, OPENTRUSTGRAPH_CHAIN_SCHEMA_V0,
468 OPENTRUSTGRAPH_SCHEMA_V0, OPENTRUSTGRAPH_SCHEMA_V0_1, TRUST_ACTION_RELEASE,
469 TRUST_GRAPH_GLOBAL_TOPIC, TRUST_GRAPH_LEGACY_GLOBAL_TOPIC, TRUST_GRAPH_LEGACY_TOPIC_PREFIX,
470 TRUST_GRAPH_RECORDS_TOPIC, TRUST_GRAPH_TOPIC_PREFIX,
471};
472pub use value::*;
473pub use vm::*;
474
475#[cfg(feature = "vm-bench-internals")]
476#[doc(hidden)]
477pub mod bench_internals;
478
479pub fn compile_source(source: &str) -> Result<Chunk, String> {
484 let program = harn_parser::check_source_strict(source).map_err(|e| e.to_string())?;
485 Compiler::new().compile(&program).map_err(|e| e.to_string())
486}
487
488pub fn compile_source_named(source: &str, pipeline_name: &str) -> Result<Chunk, String> {
493 let program = harn_parser::check_source_strict(source).map_err(|e| e.to_string())?;
494 let has_pipeline = program.iter().any(|sn| {
495 let (_, inner) = harn_parser::peel_attributes(sn);
496 matches!(&inner.node, harn_parser::Node::Pipeline { name, .. } if name == pipeline_name)
497 });
498 if !has_pipeline {
499 return Err(format!("no pipeline named `{pipeline_name}` in source"));
500 }
501 Compiler::new()
502 .compile_named(&program, pipeline_name)
503 .map_err(|e| e.to_string())
504}
505
506pub struct SchemaAliasResolver {
514 compiler: compiler::Compiler,
515}
516
517impl SchemaAliasResolver {
518 pub fn empty() -> Self {
521 Self {
522 compiler: compiler::Compiler::new(),
523 }
524 }
525
526 pub fn from_program(program: &[harn_parser::SNode]) -> Self {
529 let mut compiler = compiler::Compiler::new();
530 compiler.collect_type_aliases(program);
531 Self { compiler }
532 }
533
534 pub fn json_schema_for_type_expr(
537 &self,
538 type_expr: &harn_parser::TypeExpr,
539 ) -> Option<serde_json::Value> {
540 let expanded = self.compiler.expand_alias(type_expr);
541 let schema = compiler::Compiler::type_expr_to_schema_value(&expanded)?;
542 let json_schema = schema::schema_to_json_schema_value(&schema).ok()?;
543 Some(llm::vm_value_to_json(&json_schema))
544 }
545
546 pub fn json_schema_for_typed_params(
549 &self,
550 params: &[harn_parser::TypedParam],
551 ) -> serde_json::Value {
552 let mut properties = serde_json::Map::new();
553 let mut required = Vec::new();
554
555 for param in params {
556 let param_schema = param
557 .type_expr
558 .as_ref()
559 .and_then(|type_expr| self.json_schema_for_type_expr(type_expr))
560 .unwrap_or_else(|| serde_json::json!({}));
561 if param.default_value.is_none() {
562 required.push(serde_json::Value::String(param.name.clone()));
563 }
564 properties.insert(param.name.clone(), param_schema);
565 }
566
567 let mut schema = serde_json::Map::new();
568 schema.insert(
569 "type".to_string(),
570 serde_json::Value::String("object".to_string()),
571 );
572 schema.insert(
573 "properties".to_string(),
574 serde_json::Value::Object(properties),
575 );
576 if !required.is_empty() {
577 schema.insert("required".to_string(), serde_json::Value::Array(required));
578 }
579 serde_json::Value::Object(schema)
580 }
581}
582
583pub fn json_schema_for_type_expr(type_expr: &harn_parser::TypeExpr) -> Option<serde_json::Value> {
587 SchemaAliasResolver::empty().json_schema_for_type_expr(type_expr)
588}
589
590pub fn json_schema_for_typed_params(params: &[harn_parser::TypedParam]) -> serde_json::Value {
591 SchemaAliasResolver::empty().json_schema_for_typed_params(params)
592}
593
594#[cfg(test)]
595mod schema_alias_resolver_tests {
596 use super::*;
597
598 fn fn_params_schema(src: &str) -> serde_json::Value {
599 let program = harn_parser::parse_source(src).expect("parse test source");
600 let resolver = SchemaAliasResolver::from_program(&program);
601 for node in &program {
602 let (_, inner) = harn_parser::peel_attributes(node);
603 if let harn_parser::Node::FnDecl { params, .. } = &inner.node {
604 return resolver.json_schema_for_typed_params(params);
605 }
606 }
607 panic!("no fn decl in test source");
608 }
609
610 #[test]
611 fn named_shape_alias_projects_like_inline_shape() {
612 let inline = fn_params_schema("pub fn f(p: {kind: string, path: string}) {}");
613 let aliased =
614 fn_params_schema("type Src = {kind: string, path: string}\npub fn f(p: Src) {}");
615 assert_eq!(
616 aliased, inline,
617 "a named shape alias must project the same inputSchema as its inline shape",
618 );
619 assert_ne!(
620 aliased["properties"]["p"],
621 serde_json::json!({}),
622 "the alias parameter must not erase to an empty schema",
623 );
624 }
625
626 #[test]
627 fn literal_union_alias_projects_json_enum() {
628 let schema = fn_params_schema("type Kind = \"local\" | \"ssh\"\npub fn f(p: Kind) {}");
629 let p = &schema["properties"]["p"];
630 assert_eq!(p["type"], "string");
631 assert_eq!(p["enum"], serde_json::json!(["local", "ssh"]));
632 }
633
634 #[test]
635 fn unknown_named_type_still_erases_to_empty() {
636 let schema = fn_params_schema("pub fn f(p: Unknown) {}");
638 assert_eq!(schema["properties"]["p"], serde_json::json!({}));
639 }
640}
641
642fn reset_llm_state_for_thread_reset() {
643 llm::reset_llm_state();
644 #[cfg(test)]
645 reset_thread_local_state_test_hooks::before_llm_global_reset();
646 llm::reset_rate_limit_registry();
649 llm_config::clear_user_overrides();
650 llm_config::clear_runtime_provider_endpoint_overrides();
651}
652
653#[cfg(test)]
654mod reset_thread_local_state_test_hooks {
655 use std::sync::{Arc, Mutex, OnceLock};
656
657 type Hook = Arc<dyn Fn() + Send + Sync + 'static>;
658
659 static BEFORE_LLM_GLOBAL_RESET: OnceLock<Mutex<Option<Hook>>> = OnceLock::new();
660
661 fn before_llm_global_reset_hook() -> &'static Mutex<Option<Hook>> {
662 BEFORE_LLM_GLOBAL_RESET.get_or_init(|| Mutex::new(None))
663 }
664
665 pub(crate) struct HookGuard;
666
667 impl Drop for HookGuard {
668 fn drop(&mut self) {
669 let mut hook = before_llm_global_reset_hook()
670 .lock()
671 .unwrap_or_else(std::sync::PoisonError::into_inner);
672 *hook = None;
673 }
674 }
675
676 pub(crate) fn install_before_llm_global_reset(hook: Hook) -> HookGuard {
677 let mut slot = before_llm_global_reset_hook()
678 .lock()
679 .unwrap_or_else(std::sync::PoisonError::into_inner);
680 *slot = Some(hook);
681 HookGuard
682 }
683
684 pub(crate) fn before_llm_global_reset() {
685 let hook = before_llm_global_reset_hook()
686 .lock()
687 .unwrap_or_else(std::sync::PoisonError::into_inner)
688 .clone();
689 if let Some(hook) = hook {
690 hook();
691 }
692 }
693}
694
695pub fn reset_thread_local_state() {
697 #[cfg(test)]
698 {
699 let _guard = llm::env_guard();
704 reset_llm_state_for_thread_reset();
705 }
706 #[cfg(not(test))]
707 reset_llm_state_for_thread_reset();
708
709 http::reset_http_state();
710 channels::reset_channel_state();
711 event_log::reset_active_event_log();
712 egress::clear_explicit_egress_policy_requirement_for_host();
713 egress::clear_ssrf_guard_requirement_for_host();
714 stdlib::reset_stdlib_state();
715 connectors::clear_active_connector_clients();
716 orchestration::clear_runtime_hooks();
717 orchestration::clear_file_edit_queue();
718 orchestration::clear_execution_policy_stacks();
719 orchestration::clear_command_policies();
720 orchestration::clear_pipeline_on_finish();
721 orchestration::reset_lifecycle_receipt_registry();
722 orchestration::agent_inbox::reset();
723 tool_call_cancellations::reset_registry();
724 redact::clear_policy_stack();
725 security::reset_thread_state();
726 triggers::clear_dispatcher_state();
727 triggers::clear_trigger_registry();
728 events::reset_event_sinks();
729 tracing::set_tracing_enabled(false);
730 tracing::reset_tracing();
731 agent_events::reset_all_sinks();
743 agent_sessions::reset_session_store();
744 mcp_registry::reset();
745 mcp_host::reset_for_tests();
746 call_budget::reset_call_budget_state();
747 clock_mock::leak_audit::reset();
748}
749
750#[cfg(test)]
751mod reset_leak_tests {
752 use super::*;
758 use crate::value::VmValue;
759
760 #[test]
761 fn reset_drains_pending_file_edit_notifications() {
762 orchestration::queue_file_edited("stale.harn", serde_json::json!({"operation": "write"}));
763
764 reset_thread_local_state();
765
766 assert!(
767 orchestration::drain_file_edits().is_empty(),
768 "a later VM run must not receive file edits queued by the previous run"
769 );
770 }
771
772 #[test]
781 fn builtin_profile_recording_ends_with_its_run_not_with_a_global_reset() {
782 let _lock = builtin_profile::test_lock()
783 .lock()
784 .unwrap_or_else(std::sync::PoisonError::into_inner);
785 let recording = builtin_profile::enable();
786 builtin_profile::record("run_shell", std::time::Duration::from_millis(5));
787 assert!(builtin_profile::is_enabled());
788 assert!(!builtin_profile::snapshot().is_empty());
789
790 reset_thread_local_state();
791
792 assert!(
793 builtin_profile::is_enabled(),
794 "an unrelated global reset must not disarm an in-flight profiled run"
795 );
796 assert!(
797 !builtin_profile::snapshot().is_empty(),
798 "an unrelated global reset must not drop totals the run still owns"
799 );
800
801 drop(recording);
802
803 assert!(
804 !builtin_profile::is_enabled(),
805 "a profiled run must not leave the recorder on for the next one"
806 );
807 assert!(
808 builtin_profile::snapshot().is_empty(),
809 "builtin totals must be empty once the run's guard drops"
810 );
811 }
812
813 #[test]
818 fn reset_drains_session_changed_paths() {
819 let session = "sess-leak";
820 agent_sessions::open_or_create(Some(session.to_string()));
821 agent_sessions::record_session_changed_path(session, "/tmp/written-by-a-dead-run.txt");
822 assert!(!agent_sessions::session_changed_paths(session).is_empty());
823 reset_thread_local_state();
824 assert!(
825 agent_sessions::session_changed_paths(session).is_empty(),
826 "a receipt must not inherit an abandoned session's writes"
827 );
828 }
829
830 #[test]
831 fn reset_drains_agent_inbox() {
832 orchestration::agent_inbox::reset();
833 orchestration::agent_inbox::push("sess-2660", "note", "leak", "test");
834 assert!(orchestration::agent_inbox::session_count() > 0);
835 reset_thread_local_state();
836 assert_eq!(
837 orchestration::agent_inbox::session_count(),
838 0,
839 "agent_inbox must be empty after reset"
840 );
841 }
842
843 #[test]
844 fn reset_drains_tool_call_cancellation_registry() {
845 tool_call_cancellations::reset_registry();
846 let registered = tool_call_cancellations::register("sess-2660", "call-1", "tool");
849 if let Some((_handle, guard)) = registered {
850 std::mem::forget(guard);
851 }
852 assert!(tool_call_cancellations::registry_len() > 0);
853 reset_thread_local_state();
854 assert_eq!(
855 tool_call_cancellations::registry_len(),
856 0,
857 "tool-call cancellation registry must be empty after reset"
858 );
859 }
860
861 #[test]
862 fn reset_drains_routing_policy_registry() {
863 llm::routing::clear_policy_registry();
864 let mut config: crate::value::DictMap = crate::value::DictMap::new();
865 config.insert(
866 crate::value::intern_key("chain"),
867 VmValue::List(std::sync::Arc::new(vec![VmValue::String(
868 arcstr::ArcStr::from("mock:mock"),
869 )])),
870 );
871 llm::routing::build_routing_policy(&config).expect("intern a routing policy");
872 assert!(llm::routing::policy_registry_len() > 0);
873 reset_thread_local_state();
874 assert_eq!(
875 llm::routing::policy_registry_len(),
876 0,
877 "routing policy registry must be empty after reset"
878 );
879 }
880
881 #[test]
882 fn reset_holds_llm_env_guard_while_wiping_llm_globals() {
883 let observed = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
884 let observed_hook = std::sync::Arc::clone(&observed);
885 let _hook = reset_thread_local_state_test_hooks::install_before_llm_global_reset(
886 std::sync::Arc::new(move || {
887 assert!(
888 matches!(
889 llm::env_lock().try_lock(),
890 Err(std::sync::TryLockError::WouldBlock)
891 ),
892 "reset_thread_local_state must hold env_guard before wiping LLM globals"
893 );
894 observed_hook.store(true, std::sync::atomic::Ordering::SeqCst);
895 }),
896 );
897
898 reset_thread_local_state();
899 assert!(
900 observed.load(std::sync::atomic::Ordering::SeqCst),
901 "LLM global reset hook should have run"
902 );
903 }
904}