@replayci/replay 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,5 +1,66 @@
1
- import { Contract } from '@replayci/contracts-core';
1
+ import { Contract, CommitRequirement, ToolCallResult, ProviderConstraints } from '@replayci/contracts-core';
2
2
 
3
+ declare const CAPTURE_SCHEMA_VERSION_CURRENT: "2026-03-09";
4
+ type CaptureProvider = "openai" | "anthropic";
5
+ type CaptureMessage = Record<string, unknown>;
6
+ type CapturedRequestTool = {
7
+ name: string;
8
+ description?: string;
9
+ parameters?: Record<string, unknown>;
10
+ input_schema?: Record<string, unknown>;
11
+ [key: string]: unknown;
12
+ };
13
+ type CapturedToolCall = {
14
+ name: string;
15
+ arguments?: string;
16
+ };
17
+ type CaptureRequest = {
18
+ messages?: CaptureMessage[];
19
+ tools: CapturedRequestTool[];
20
+ tool_choice?: string;
21
+ };
22
+ type CaptureResponse = {
23
+ tool_calls: CapturedToolCall[];
24
+ content: string | null;
25
+ text_blocks?: string[];
26
+ };
27
+ type CaptureValidation = {
28
+ pass: boolean;
29
+ failures: ContractFailure[];
30
+ retries_used: number;
31
+ contracts_evaluated: string[];
32
+ };
33
+ type CaptureUsage = {
34
+ prompt_tokens: number;
35
+ completion_tokens: number;
36
+ total_tokens: number;
37
+ };
38
+ type CapturedCall = {
39
+ schema_version: typeof CAPTURE_SCHEMA_VERSION_CURRENT;
40
+ agent: string;
41
+ timestamp: string;
42
+ provider: CaptureProvider;
43
+ model_id: string;
44
+ primary_tool_name: string | null;
45
+ tool_names: string[];
46
+ request: CaptureRequest;
47
+ response: CaptureResponse;
48
+ validation?: CaptureValidation;
49
+ usage?: CaptureUsage;
50
+ latency_ms: number;
51
+ sdk_session_id?: string;
52
+ };
53
+
54
+ interface FlushResult {
55
+ /** Number of captures in the buffer when flush was called */
56
+ captured: number;
57
+ /** Number of captures successfully sent to the server */
58
+ sent: number;
59
+ /** Whether the handle is active (false = no apiKey or disabled) */
60
+ active: boolean;
61
+ /** Error messages from send attempts */
62
+ errors: string[];
63
+ }
3
64
  type ContractFailure = {
4
65
  path: string;
5
66
  operator: string;
@@ -93,6 +154,11 @@ type ObserveDiagnosticEvent = {
93
154
  type: "unsupported_client";
94
155
  mode: "observe";
95
156
  detail: string;
157
+ } | {
158
+ type: "activation_warning";
159
+ message: string;
160
+ } | {
161
+ type: "flush_empty";
96
162
  };
97
163
  type ObserveOptions = {
98
164
  agent?: string;
@@ -109,7 +175,7 @@ type ObserveOptions = {
109
175
  };
110
176
  type ObserveHandle<T> = {
111
177
  client: T;
112
- flush: () => Promise<void>;
178
+ flush: () => Promise<FlushResult>;
113
179
  restore: () => void;
114
180
  getHealth: () => ObserveHealthSnapshot;
115
181
  };
@@ -123,4 +189,957 @@ type ValidateOptions = {
123
189
  declare function prepareContracts(input: string | string[] | Contract | Contract[]): Contract[];
124
190
  declare function validate(response: unknown, opts?: ValidateOptions): ValidationResult;
125
191
 
126
- export { type ContractFailure, type ObserveActivationReasonCode, type ObserveDiagnosticEvent, type ObserveHandle, type ObserveHealthSnapshot, type ObserveOptions, type ObserveSessionState, type ValidationResult, observe, prepareContracts, validate };
192
+ type SupportedProvider = "openai" | "anthropic";
193
+
194
+ /**
195
+ * Session state types for cross-step enforcement (v2).
196
+ * @see specs/runtime-replay.md § Stage 6: Finalize executed step
197
+ * @see specs/replay-v2.md § Session state model
198
+ * @see specs/replay-governance-evidence-spine.md § Session state model
199
+ */
200
+
201
+ /**
202
+ * Authoritative session state. Steps contains only committed executed steps.
203
+ * @see specs/replay-v2.md § Session state model
204
+ */
205
+ type SessionState = {
206
+ sessionId: string;
207
+ agent: string | null;
208
+ principal: Record<string, unknown> | null;
209
+ startedAt: Date;
210
+ /** Current enforcement tier. Strong = authoritative server round-trip; compat = local only. */
211
+ tier: "strong" | "compat";
212
+ stateVersion: number;
213
+ controlRevision: number;
214
+ currentPhase: string | null;
215
+ totalStepCount: number;
216
+ totalToolCalls: number;
217
+ actualCost: number;
218
+ totalCost: number;
219
+ toolCallCounts: Map<string, number>;
220
+ forbiddenTools: Set<string>;
221
+ satisfiedPreconditions: Map<string, PreconditionEvidence>;
222
+ steps: CompletedStep[];
223
+ pendingEntries: PendingEntry[];
224
+ lastStep: CompletedStep | null;
225
+ consecutiveBlockCount: number;
226
+ consecutiveErrorCount: number;
227
+ totalBlockCount: number;
228
+ totalUnguardedCalls: number;
229
+ killed: boolean;
230
+ /** Hash of compiled contracts when state was written. Used for drift detection on resume. */
231
+ contractHash: string | null;
232
+ };
233
+ /**
234
+ * A committed executed step in the session record.
235
+ * @see specs/replay-v2.md § Session state model — CompletedStep
236
+ */
237
+ type CompletedStep = {
238
+ stepIndex: number;
239
+ stepId: string;
240
+ toolCalls: CompletedToolCall[];
241
+ proposal_decision: "allowed";
242
+ commit_state: "committed";
243
+ commit_tier: "strong" | "compat";
244
+ max_evidence_level: "acknowledged";
245
+ invariantFailures: ContractFailure[];
246
+ phase: string | null;
247
+ phaseTransition: string | null;
248
+ completedAt: string;
249
+ outputExtract: Record<string, unknown>;
250
+ finish_reason: string | null;
251
+ model: string | null;
252
+ usage: {
253
+ prompt_tokens: number;
254
+ completion_tokens: number;
255
+ } | null;
256
+ };
257
+ /**
258
+ * A committed tool call within a step.
259
+ * @see specs/replay-v2.md § Session state model — CompletedToolCall
260
+ */
261
+ type CompletedToolCall = {
262
+ toolName: string;
263
+ arguments_hash: string;
264
+ proposal_decision: "allowed";
265
+ execution_state: "outcome_recorded";
266
+ evidence_level: "acknowledged";
267
+ commit_requirement: CommitRequirement;
268
+ commit_state: "committed";
269
+ commit_tier: "strong" | "compat";
270
+ executor_attested: boolean;
271
+ contractFile: string | null;
272
+ resourceValues: Record<string, unknown> | null;
273
+ policyVerdict: unknown | null;
274
+ constraintVerdict: unknown | null;
275
+ };
276
+ /**
277
+ * Result of cross-step validation (preconditions + forbids_after).
278
+ * @see specs/replay-v2.md § Stage 3 extensions: Validate
279
+ */
280
+ type CrossStepResult = {
281
+ passed: boolean;
282
+ failures: CrossStepFailure[];
283
+ };
284
+ type CrossStepFailure = {
285
+ toolName: string;
286
+ reason: CrossStepFailureReason;
287
+ detail: string;
288
+ };
289
+ type CrossStepFailureReason = "precondition_not_met" | "forbidden_tool" | "argument_value_mismatch";
290
+ /**
291
+ * A tool call pending execution evidence.
292
+ * @see specs/replay-v2.md § Stage 6: Finalize executed step
293
+ */
294
+ type PendingEntry = {
295
+ stepId: string;
296
+ toolName: string;
297
+ arguments_hash: string;
298
+ tool_call_id: string | null;
299
+ position_index: number;
300
+ createdAt: string;
301
+ };
302
+ /**
303
+ * Evidence stored in the satisfiedPreconditions cache.
304
+ * Key format: "tool_name" or "tool_name:resource_value".
305
+ */
306
+ type PreconditionEvidence = unknown;
307
+ type LoopDetectionResult = {
308
+ triggered: boolean;
309
+ matchCount: number;
310
+ threshold: number;
311
+ window: number;
312
+ };
313
+ type CircuitBreakerResult = {
314
+ triggered: boolean;
315
+ reason: "consecutive_blocks" | "consecutive_errors" | null;
316
+ };
317
+ type DecisionOutcome = "allowed" | "blocked" | "error";
318
+
319
+ /**
320
+ * Store interface for durable session state persistence.
321
+ *
322
+ * compareAndSet() provides atomic version-checked state updates.
323
+ * load() retrieves the current state.
324
+ * appendCapture() appends a capture to the durable log.
325
+ *
326
+ * @see specs/replay-v2.md § Store interface in v2
327
+ */
328
+
329
+ /**
330
+ * Result of a compareAndSet operation.
331
+ */
332
+ type CompareAndSetResult = {
333
+ /** Whether the update was applied. False if currentVersion didn't match. */
334
+ success: boolean;
335
+ };
336
+ /**
337
+ * Durable store interface for session state and captures.
338
+ *
339
+ * The default in-memory implementation (MemoryStore) replicates current
340
+ * closure-variable behavior. Custom implementations can persist to
341
+ * databases, files, or external services.
342
+ */
343
+ interface Store {
344
+ /**
345
+ * Atomic state update with version check.
346
+ * Only applies the update if the store's current stateVersion matches
347
+ * `currentVersion`. Prevents stale writes from concurrent access.
348
+ *
349
+ * @param currentVersion - Expected current stateVersion
350
+ * @param newState - New state to write
351
+ * @returns Whether the update was applied
352
+ */
353
+ compareAndSet(currentVersion: number, newState: SessionState): CompareAndSetResult | Promise<CompareAndSetResult>;
354
+ /**
355
+ * Load the current session state.
356
+ * Returns null if no state has been stored yet.
357
+ */
358
+ load(): SessionState | null | Promise<SessionState | null>;
359
+ /**
360
+ * Append a capture to the durable log.
361
+ * Called for every decision (including blocked calls that don't advance state).
362
+ */
363
+ appendCapture(capture: CapturedCall): void | Promise<void>;
364
+ }
365
+
366
+ /**
367
+ * Types for the replay() enforcement pipeline.
368
+ * @see specs/runtime-replay.md § SDK API surface
369
+ * @see specs/replay-v1.md § SDK API surface
370
+ */
371
+
372
+ /**
373
+ * Workflow attachment options for `replay()`.
374
+ * Either root-create or child-attach — never both.
375
+ * @see specs/replay-v4.md § SDK workflow surface
376
+ */
377
+ type WorkflowOptions = WorkflowRootOptions | WorkflowChildOptions;
378
+ /** Root session workflow options. */
379
+ type WorkflowRootOptions = {
380
+ type: "root";
381
+ /** Workflow ID. Generated by SDK if omitted. */
382
+ workflowId?: string;
383
+ /** Role name this root session fulfils in the workflow. */
384
+ role: string;
385
+ /** Explicit path to workflow.yaml. Overrides auto-discovery from contractsDir. */
386
+ workflowYamlPath?: string;
387
+ };
388
+ /** Child session workflow options. */
389
+ type WorkflowChildOptions = {
390
+ type: "child";
391
+ /** Workflow ID of the parent workflow to attach to. */
392
+ workflowId: string;
393
+ /** Role name this child session fulfils in the workflow. */
394
+ role: string;
395
+ /** Session ID of the parent session that offered the handoff. */
396
+ parentSessionId: string;
397
+ /** Handoff ID to claim. */
398
+ handoffId: string;
399
+ };
400
+ type ReplayMode = "enforce" | "shadow" | "log-only";
401
+ /** @see specs/runtime-replay.md § Stage 4: Gate */
402
+ type GateMode = "reject_all" | "strip_partial" | "strip_blocked";
403
+ /** @see specs/replay-v1.md § SDK API surface — replay() */
404
+ type ReplayOptions = {
405
+ contracts?: Contract | Contract[];
406
+ contractsDir?: string;
407
+ /** Explicit path to session.yaml. Overrides auto-discovery from contractsDir. */
408
+ sessionYamlPath?: string;
409
+ /**
410
+ * v4: Workflow attachment block.
411
+ * When present, the session participates in a durable workflow.
412
+ * Root sessions create the workflow; child sessions claim a handoff.
413
+ * @see specs/replay-v4.md § SDK workflow surface
414
+ */
415
+ workflow?: WorkflowOptions;
416
+ agent?: string;
417
+ sessionId?: string;
418
+ mode?: ReplayMode;
419
+ gate?: GateMode;
420
+ onError?: "block" | "allow";
421
+ unmatchedPolicy?: "block" | "allow";
422
+ /** Caller-supplied identity for policy evaluation (P1). */
423
+ principal?: unknown;
424
+ /** Execution wrapper map — required for state-bearing tools in govern mode. */
425
+ tools?: Record<string, ToolExecutor>;
426
+ onBlock?: (decision: ReplayDecision) => void;
427
+ /** v3: Called when tools are filtered by Stage 1 narrowing. */
428
+ onNarrow?: (narrowing: NarrowResult) => void;
429
+ /** Retry on block (hard cap 5, no prompt modification). */
430
+ maxRetries?: number;
431
+ /**
432
+ * Max unguarded calls before auto-kill (default: 3).
433
+ * Only applies when `onError: "allow"`. Bounds the state-fiction window.
434
+ * @see specs/runtime-replay.md § Failure semantics
435
+ */
436
+ maxUnguardedCalls?: number;
437
+ /** Provider constraints for blocking/warning on incompatible providers. */
438
+ providerConstraints?: ProviderConstraints;
439
+ /**
440
+ * Compat-tier enforcement behavior.
441
+ * - "protective": enforce locally, block illegal calls (default)
442
+ * - "advisory": evaluate but don't block, emit diagnostics only
443
+ * Only applies when tier is "compat" (no authoritative server round-trip).
444
+ * @see specs/replay-v2.md § v2 enforcement tier implications
445
+ */
446
+ compatEnforcement?: "protective" | "advisory";
447
+ /**
448
+ * Optional durable store for session state and captures.
449
+ * When provided, state reads use store.load() and state writes use
450
+ * store.compareAndSet(). Captures are appended via store.appendCapture().
451
+ * When absent, default in-memory store is used (current behavior).
452
+ * @see specs/replay-v2.md § Store interface in v2
453
+ */
454
+ store?: Store;
455
+ /**
456
+ * How narrowing is communicated to the LLM.
457
+ * - "silent" (default): tools removed silently, LLM doesn't know why
458
+ * - "metadata": narrowing info exposed via getState()/getLastNarrowing() only
459
+ * - "inject": a system message is prepended explaining which tools were removed and why.
460
+ * Only non-sensitive reasons are injected (phase, manual_filter, no_contract).
461
+ * policy_denied reasons are redacted to "restricted".
462
+ */
463
+ narrowingFeedback?: "silent" | "metadata" | "inject";
464
+ apiKey?: string;
465
+ /** Runtime API URL for authoritative sessions. Defaults to apiKey endpoint. */
466
+ runtimeUrl?: string;
467
+ captureLevel?: CapturePrivacyTier;
468
+ diagnostics?: (event: ObserveDiagnosticEvent | ReplayDiagnosticEvent) => void;
469
+ };
470
+ /**
471
+ * Raw tool executor provided by the user in `replay()` options.
472
+ * @see specs/runtime-replay.md § Execution constraints — ToolExecutor
473
+ */
474
+ type ToolExecutor = (args: Record<string, unknown>) => unknown | Promise<unknown>;
475
+ /**
476
+ * Wrapped tool executor exposed on `session.tools`.
477
+ * Enforces `execution_constraints` before forwarding to the real executor.
478
+ * @see specs/runtime-replay.md § Execution constraints — WrappedToolExecutor
479
+ */
480
+ type WrappedToolExecutor = (args: Record<string, unknown>) => Promise<WrappedExecutorResult>;
481
+ /**
482
+ * Result returned by a wrapped tool executor.
483
+ * @see specs/runtime-replay.md § Execution constraints
484
+ */
485
+ type WrappedExecutorResult = {
486
+ result: unknown;
487
+ constraint_verdict: ConstraintVerdict;
488
+ };
489
+ /**
490
+ * Result of policy evaluation for a single tool call.
491
+ * @see specs/runtime-replay.md § Authorization kernel — PolicyVerdict
492
+ */
493
+ type PolicyVerdict = {
494
+ allowed: boolean;
495
+ reason: string | null;
496
+ };
497
+ /**
498
+ * Result of execution constraint validation on tool arguments.
499
+ * @see specs/runtime-replay.md § Execution constraints — ConstraintVerdict
500
+ */
501
+ type ConstraintVerdict = {
502
+ passed: boolean;
503
+ failures: ConstraintFailure[];
504
+ };
505
+ type ConstraintFailure = {
506
+ path: string;
507
+ operator: string;
508
+ expected: unknown;
509
+ actual: unknown;
510
+ };
511
+ /**
512
+ * @see specs/replay-v1.md § Return type: ReplaySession
513
+ * @see specs/replay-v2.md § ReplaySession extensions
514
+ */
515
+ type ReplaySession<T> = {
516
+ client: T;
517
+ flush: () => Promise<FlushResult>;
518
+ restore: () => void;
519
+ kill: () => void;
520
+ getHealth: () => ReplayHealthSnapshot;
521
+ /** v2: Return redacted session state snapshot. */
522
+ getState: () => Readonly<SessionStateSnapshot>;
523
+ /**
524
+ * v3: Return the most recent narrowing snapshot.
525
+ * Returns null before first call or when no narrowing occurred.
526
+ */
527
+ getLastNarrowing: () => NarrowingSnapshot | null;
528
+ /**
529
+ * v3: Return the most recent ShadowDelta (shadow mode only).
530
+ * Returns null when not in shadow mode or before first call.
531
+ */
532
+ getLastShadowDelta: () => ShadowDelta | null;
533
+ /**
534
+ * v3: Manually restrict available tools within compiled legal space.
535
+ * Cannot add tools that the compiled session would remove.
536
+ * @see specs/replay-v3.md § narrow() / widen()
537
+ */
538
+ narrow: (toolFilter: string[]) => void;
539
+ /**
540
+ * v3: Remove manual restriction, return to contract-driven narrowing.
541
+ * Does NOT bypass phase/state restrictions.
542
+ * @see specs/replay-v3.md § narrow() / widen()
543
+ */
544
+ widen: () => void;
545
+ /** Present only when `tools` provided at init. */
546
+ tools: Record<string, WrappedToolExecutor>;
547
+ /**
548
+ * v4: Return workflow state from the runtime.
549
+ * Returns null when the session is not part of a workflow.
550
+ * @see specs/replay-v4.md § SDK workflow surface
551
+ */
552
+ getWorkflowState: () => Promise<WorkflowStateSnapshot | null>;
553
+ /**
554
+ * v4: Offer a handoff to another role in the workflow.
555
+ * Returns null when the session is not part of a workflow.
556
+ * @see specs/replay-v4.md § SDK workflow surface
557
+ */
558
+ handoff: (offer: HandoffOfferInput$1) => Promise<HandoffOfferResult$1 | null>;
559
+ };
560
+ /** @see specs/runtime-replay.md § ReplayHealthSnapshot */
561
+ type ReplayHealthSnapshot = {
562
+ status: "healthy" | "degraded" | "inactive";
563
+ authorityState: "active" | "advisory" | "compromised" | "recovering" | "killed" | "inactive";
564
+ protectionLevel: "monitor" | "protect" | "govern";
565
+ durability: "server" | "degraded-local" | "inactive";
566
+ tier: "strong" | "compat";
567
+ compatEnforcement: "protective" | "advisory";
568
+ cluster_detected: boolean;
569
+ bypass_detected: boolean;
570
+ totalSteps: number;
571
+ totalBlocks: number;
572
+ totalErrors: number;
573
+ killed: boolean;
574
+ /** Number of shadow-mode evaluations performed (always 0 in enforce/log-only). */
575
+ shadowEvaluations: number;
576
+ };
577
+ /**
578
+ * Public, redacted, JSON-serializable snapshot of session state.
579
+ * Maps/Sets are converted to plain objects/arrays.
580
+ * @see specs/replay-v2.md § getState() contract
581
+ */
582
+ type SessionStateSnapshot = {
583
+ sessionId: string;
584
+ agent: string | null;
585
+ principal: null;
586
+ startedAt: Date;
587
+ stateVersion: number;
588
+ controlRevision: number;
589
+ currentPhase: string | null;
590
+ totalStepCount: number;
591
+ totalToolCalls: number;
592
+ totalCost: number;
593
+ actualCost: number;
594
+ toolCallCounts: Record<string, number>;
595
+ forbiddenTools: string[];
596
+ satisfiedPreconditions: Record<string, unknown>;
597
+ lastStep: CompletedStepSnapshot | null;
598
+ /** Last narrowing result from the most recent create() call. Null before first call. */
599
+ lastNarrowing: NarrowingSnapshot | null;
600
+ killed: boolean;
601
+ totalUnguardedCalls: number;
602
+ consecutiveBlockCount: number;
603
+ totalBlockCount: number;
604
+ };
605
+ /** Redacted narrowing snapshot for external consumption. */
606
+ type NarrowingSnapshot = {
607
+ removed: Array<{
608
+ tool: string;
609
+ reason: NarrowRemovalReason;
610
+ detail?: string;
611
+ }>;
612
+ removedCount: number;
613
+ allowedCount: number;
614
+ };
615
+ type CompletedStepSnapshot = {
616
+ stepIndex: number;
617
+ stepId: string;
618
+ toolCalls: CompletedToolCallSnapshot[];
619
+ invariantFailures: ContractFailure[];
620
+ phase: string | null;
621
+ phaseTransition: string | null;
622
+ completedAt: string;
623
+ outputExtract: Record<string, unknown>;
624
+ finish_reason: string | null;
625
+ model: string | null;
626
+ };
627
+ type CompletedToolCallSnapshot = {
628
+ toolName: string;
629
+ arguments_hash: string;
630
+ contractFile: string | null;
631
+ };
632
+ /** @see specs/replay-v1.md § Stage 4: Gate */
633
+ type ReplayDecision = {
634
+ action: "allow";
635
+ tool_calls: ToolCallResult[];
636
+ } | {
637
+ action: "block";
638
+ tool_calls: ToolCallResult[];
639
+ blocked: BlockedToolCall[];
640
+ response_modification: GateMode;
641
+ };
642
+ type BlockedToolCall = {
643
+ tool_name: string;
644
+ arguments: string;
645
+ reason: BlockReason;
646
+ contract_file: string;
647
+ failures: ContractFailure[];
648
+ };
649
+ /**
650
+ * Block reasons for v1 + v2.
651
+ * @see specs/replay-v1.md § Stage 4: Gate — BlockReason
652
+ * @see specs/replay-v2.md § Stage 4 extensions: Gate
653
+ */
654
+ type BlockReason = "output_invariant_failed" | "input_invariant_failed" | "response_format_invalid" | "unmatched_tool_blocked" | "policy_denied" | "execution_constraint_violated" | "killed" | "argument_value_mismatch" | "precondition_not_met" | "forbidden_tool" | "session_limit_exceeded" | "loop_detected" | "illegal_phase_transition" | "ambiguous_phase_transition" | "risk_gate_blocked";
655
+ /**
656
+ * A tool definition from the provider request.
657
+ * Must have at least a `name`; other fields vary by provider.
658
+ */
659
+ type ToolDefinition = Record<string, unknown> & {
660
+ name: string;
661
+ };
662
+ /**
663
+ * Result of Stage 1 narrowing.
664
+ * @see specs/replay-v3.md § Stage 1: Narrow
665
+ */
666
+ type NarrowResult = {
667
+ allowed: ToolDefinition[];
668
+ removed: NarrowedTool[];
669
+ };
670
+ /** @see specs/replay-v3.md § Stage 1: Narrow */
671
+ type NarrowedTool = {
672
+ tool: string;
673
+ reason: NarrowRemovalReason;
674
+ detail?: string;
675
+ contract_file?: string;
676
+ };
677
+ type NarrowRemovalReason = "manual_filter" | "no_contract" | "wrong_phase" | "precondition_not_met" | "forbidden_in_state" | "policy_denied";
678
+ /**
679
+ * Result of Stage 3 phase transition validation.
680
+ * @see specs/replay-v3.md § Stage 3 extension: Phase transition validation
681
+ */
682
+ type PhaseTransitionResult = {
683
+ legal: true;
684
+ newPhase: string | null;
685
+ } | {
686
+ legal: false;
687
+ newPhase: string | null;
688
+ blockedTool: string;
689
+ attemptedTransition: string;
690
+ reason: "illegal_phase_transition" | "ambiguous_phase_transition";
691
+ };
692
+ /**
693
+ * Per-stage timing breakdown for the enforcement pipeline.
694
+ * All values in milliseconds. `total_ms` = wall clock from guard start to capture.
695
+ * `enforcement_ms` = `total_ms - llm_call_ms` (actual enforcement overhead).
696
+ */
697
+ type ReplayTiming = {
698
+ narrow_ms: number;
699
+ pre_check_ms: number;
700
+ llm_call_ms: number;
701
+ validate_ms: number;
702
+ cross_step_ms: number;
703
+ phase_ms: number;
704
+ argument_values_ms: number;
705
+ policy_ms: number;
706
+ gate_ms: number;
707
+ finalize_ms: number;
708
+ runtime_ms: number;
709
+ total_ms: number;
710
+ enforcement_ms: number;
711
+ };
712
+ /**
713
+ * @see specs/replay-v1.md § Stage 7: Capture
714
+ * @see specs/replay-v2.md § Stage 7 extensions: Capture
715
+ */
716
+ type ReplayCapture = CapturedCall & {
717
+ replay: {
718
+ session_id: string;
719
+ step_index: number;
720
+ mode: ReplayMode;
721
+ decision: ReplayDecision;
722
+ contract_hashes: string[];
723
+ guard_overhead_ms: number;
724
+ timing?: ReplayTiming;
725
+ commit_tier: "strong" | "compat";
726
+ principal: unknown | null;
727
+ policy_verdict: PolicyVerdict | null;
728
+ execution_constraint_verdict: ConstraintVerdict | null;
729
+ counterfactual: {
730
+ tools_removed: NarrowedTool[];
731
+ calls_blocked: BlockedToolCall[];
732
+ };
733
+ cross_step: CrossStepCaptureResult | null;
734
+ session_state_hash: string | null;
735
+ state_version: number;
736
+ narrowing: NarrowResult | null;
737
+ phase: string | null;
738
+ phase_transition: string | null;
739
+ shadow_delta?: ShadowDelta;
740
+ receipt: null;
741
+ };
742
+ };
743
+ type CrossStepCaptureResult = {
744
+ passed: boolean;
745
+ failures: Array<{
746
+ toolName: string;
747
+ reason: string;
748
+ detail: string;
749
+ }>;
750
+ };
751
+ /**
752
+ * Shadow mode delta: what would have happened under enforce mode.
753
+ * @see specs/replay-v3.md § Shadow mode extensions
754
+ */
755
+ type ShadowDelta = {
756
+ would_have_blocked: BlockedToolCall[];
757
+ would_have_narrowed: NarrowedTool[];
758
+ current_phase: string | null;
759
+ legal_next_phases: string[];
760
+ };
761
+ /** Provider-agnostic response metadata extracted for format invariant checks. */
762
+ type ResponseMetadata = {
763
+ finish_reason: string | null;
764
+ content: string | null;
765
+ tool_calls_present: boolean;
766
+ has_content: boolean;
767
+ };
768
+ type ReplayDiagnosticEvent = {
769
+ type: "replay_activated";
770
+ session_id: string;
771
+ provider: SupportedProvider;
772
+ agent: string;
773
+ mode: ReplayMode;
774
+ } | {
775
+ type: "replay_inactive";
776
+ reason: string;
777
+ error_message?: string;
778
+ } | {
779
+ type: "replay_contract_error";
780
+ details: string;
781
+ } | {
782
+ type: "replay_bypass_detected";
783
+ session_id: string;
784
+ } | {
785
+ type: "replay_kill";
786
+ session_id: string;
787
+ } | {
788
+ type: "replay_block";
789
+ session_id: string;
790
+ tool_name: string;
791
+ reason: BlockReason;
792
+ } | {
793
+ type: "replay_narrow";
794
+ session_id: string;
795
+ removed: NarrowedTool[];
796
+ } | {
797
+ type: "replay_provider_warning";
798
+ provider: string;
799
+ warnings: string[];
800
+ } | {
801
+ type: "replay_compat_advisory";
802
+ session_id: string;
803
+ would_block: BlockedToolCall[];
804
+ details: string;
805
+ } | {
806
+ type: "replay_resumed";
807
+ session_id: string;
808
+ state_version: number;
809
+ contract_drift: boolean;
810
+ } | {
811
+ type: "replay_narrow_injected";
812
+ session_id: string;
813
+ message: string;
814
+ } | {
815
+ type: "replay_workflow_attached";
816
+ session_id: string;
817
+ workflow_id: string;
818
+ role: string;
819
+ attach_type: "root" | "child";
820
+ } | {
821
+ type: "replay_workflow_error";
822
+ session_id: string;
823
+ details: string;
824
+ };
825
+ /**
826
+ * Workflow state snapshot returned by `session.getWorkflowState()`.
827
+ * Server-authoritative — SDK caches but does not derive.
828
+ * @see specs/replay-v4.md § SDK workflow surface
829
+ */
830
+ type WorkflowStateSnapshot = {
831
+ workflowId: string;
832
+ rootSessionId: string;
833
+ status: string;
834
+ stateVersion: number;
835
+ controlRevision: number;
836
+ totalSessionCount: number;
837
+ activeSessionCount: number;
838
+ totalStepCount: number;
839
+ totalCost: number;
840
+ totalHandoffCount: number;
841
+ unresolvedHandoffCount: number;
842
+ lastEventSeq: number;
843
+ killScope: string;
844
+ createdAt: string;
845
+ updatedAt: string;
846
+ };
847
+ /**
848
+ * Input for `session.handoff()`.
849
+ * @see specs/replay-v4.md § SDK workflow surface
850
+ */
851
+ type HandoffOfferInput$1 = {
852
+ toRole: string;
853
+ handoffId: string;
854
+ artifactRefs?: unknown;
855
+ summary?: unknown;
856
+ };
857
+ /**
858
+ * Result from `session.handoff()`.
859
+ * @see specs/replay-v4.md § SDK workflow surface
860
+ */
861
+ type HandoffOfferResult$1 = {
862
+ handoffId: string;
863
+ eventSeq: number;
864
+ stateVersion: number;
865
+ };
866
+
867
+ /**
868
+ * Create an enforcement session wrapper around a provider client.
869
+ *
870
+ * @see specs/replay-v1.md § SDK API surface — replay()
871
+ */
872
+ declare function replay<T extends object>(client: T, opts?: ReplayOptions): ReplaySession<T>;
873
+
874
+ declare class ReplayConfigurationError extends Error {
875
+ constructor(message: string);
876
+ }
877
+
878
+ /**
879
+ * Replay-specific error types.
880
+ * @see specs/replay-v1.md § Error types
881
+ */
882
+
883
+ /**
884
+ * Thrown when enforcement blocks tool calls in `reject_all` or `strip_partial` (all-blocked) mode.
885
+ */
886
+ declare class ReplayContractError extends Error {
887
+ readonly decision: ReplayDecision;
888
+ readonly contractFile: string;
889
+ readonly failures: ContractFailure[];
890
+ constructor(message: string, decision: ReplayDecision, contractFile: string, failures: ContractFailure[]);
891
+ }
892
+ /**
893
+ * Thrown on all create() calls after session.kill().
894
+ */
895
+ declare class ReplayKillError extends Error {
896
+ readonly sessionId: string;
897
+ readonly killedAt: string;
898
+ constructor(sessionId: string, killedAt: string);
899
+ }
900
+ /**
901
+ * Thrown at replay() init time for configuration errors.
902
+ * Extends existing ReplayConfigurationError.
903
+ * @see specs/replay-v1.md § Config errors (fail-closed)
904
+ */
905
+ declare class ReplayConfigError extends ReplayConfigurationError {
906
+ readonly condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible";
907
+ readonly details: string;
908
+ constructor(condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible", details: string);
909
+ }
910
+
911
+ /**
912
+ * In-memory Store implementation.
913
+ * Default store when no custom store is provided — replicates
914
+ * current closure-variable behavior.
915
+ *
916
+ * @see specs/replay-v2.md § Store interface in v2
917
+ */
918
+
919
+ declare class MemoryStore implements Store {
920
+ private state;
921
+ private readonly captures;
922
+ compareAndSet(currentVersion: number, newState: SessionState): CompareAndSetResult;
923
+ load(): SessionState | null;
924
+ appendCapture(capture: CapturedCall): void;
925
+ /** @internal Test-only: get all captured calls. */
926
+ getCapturedCalls(): ReadonlyArray<CapturedCall>;
927
+ }
928
+
929
+ type RuntimeClientOptions = {
930
+ apiKey: string;
931
+ apiUrl?: string;
932
+ timeoutMs?: number;
933
+ fetchImpl?: typeof fetch;
934
+ now?: () => number;
935
+ };
936
+ type RuntimeSessionInit = {
937
+ agent: string;
938
+ sessionId?: string;
939
+ requestedMode: "authoritative" | "advisory";
940
+ requestedTier: "strong" | "compat";
941
+ adapterCapability: "full" | "partial" | "transcript_only";
942
+ allowAdvisoryDowngrade?: boolean;
943
+ provider?: string;
944
+ modelId?: string | null;
945
+ principal?: unknown | null;
946
+ compiledSession?: {
947
+ schemaVersion: string;
948
+ hash: string;
949
+ body: unknown;
950
+ };
951
+ contractHash: string;
952
+ sessionContractHash?: string | null;
953
+ /** v4: Workflow attachment block for root-create or child-attach. */
954
+ workflow?: RuntimeWorkflowInit;
955
+ };
956
+ /** v4: Workflow block in session creation. */
957
+ type RuntimeWorkflowInit = {
958
+ workflowId: string;
959
+ role: string;
960
+ compiledWorkflow?: {
961
+ hash: string;
962
+ body: string;
963
+ };
964
+ parentSessionId?: string;
965
+ handoffId?: string;
966
+ };
967
+ type RuntimeSessionResult = {
968
+ sessionId: string;
969
+ mode: string;
970
+ tier: string;
971
+ status: string;
972
+ stateVersion: number;
973
+ controlRevision: number;
974
+ leaseFence: string | null;
975
+ /** v4: Workflow attachment result, present when workflow block was sent. */
976
+ workflow?: RuntimeWorkflowResult;
977
+ };
978
+ /** v4: Workflow block in session creation response. */
979
+ type RuntimeWorkflowResult = {
980
+ workflowId: string;
981
+ role: string;
982
+ stateVersion: number;
983
+ controlRevision?: number;
984
+ linkId?: string;
985
+ generation?: number;
986
+ depth?: number;
987
+ status?: string;
988
+ };
989
+ type PreflightInput = {
990
+ sessionId: string;
991
+ leaseFence: string;
992
+ requestEnvelope: unknown;
993
+ provider: string;
994
+ modelId: string | null;
995
+ };
996
+ type PreflightResult = {
997
+ preparedRequestId: string;
998
+ stateVersion: number;
999
+ controlRevision: number;
1000
+ leaseFence: string;
1001
+ requestEnvelope: unknown;
1002
+ removedTools: unknown[];
1003
+ };
1004
+ type ProposalInput = {
1005
+ sessionId: string;
1006
+ leaseFence: string;
1007
+ preparedRequestId: string;
1008
+ responseEnvelope: unknown;
1009
+ };
1010
+ type ProposalResult = {
1011
+ decision: "allowed" | "blocked";
1012
+ advisory: boolean;
1013
+ stateVersion: number;
1014
+ pendingCalls: ProposalPendingCall[];
1015
+ blockedCalls: ProposalBlockedCall[];
1016
+ };
1017
+ type ProposalPendingCall = {
1018
+ pendingCallId: string;
1019
+ toolCallId: string;
1020
+ toolName: string;
1021
+ argumentsHash: string;
1022
+ };
1023
+ type ProposalBlockedCall = {
1024
+ toolName: string;
1025
+ reason: string;
1026
+ };
1027
+ type ReceiptInput = {
1028
+ sessionId: string;
1029
+ leaseFence: string;
1030
+ pendingCallId: string;
1031
+ executorKind: "WRAPPED_EXECUTOR" | "GATEWAY_EXECUTOR" | "SERVICE_EXECUTOR";
1032
+ executorId?: string | null;
1033
+ toolName: string;
1034
+ argumentsHash: string;
1035
+ status: "SUCCEEDED" | "FAILED" | "DISCARDED";
1036
+ outputHash?: string | null;
1037
+ outputExtract?: Record<string, unknown> | null;
1038
+ resourceValues?: Record<string, unknown> | null;
1039
+ evidenceArtifactHash?: string | null;
1040
+ startedAt: string;
1041
+ completedAt: string;
1042
+ };
1043
+ type ReceiptResult = {
1044
+ accepted: boolean;
1045
+ commitState: "committed" | "uncommitted";
1046
+ stateAdvanced: boolean;
1047
+ stateVersion: number;
1048
+ };
1049
+ type ToolFilterInput = {
1050
+ sessionId: string;
1051
+ leaseFence: string;
1052
+ allowedTools: string[] | null;
1053
+ };
1054
+ type ToolFilterResult = {
1055
+ controlRevision: number;
1056
+ };
1057
+ type ReportBypassInput = {
1058
+ sessionId: string;
1059
+ source: string;
1060
+ detail?: string | null;
1061
+ };
1062
+ type ReportBypassResult = {
1063
+ status: string;
1064
+ };
1065
+ type KillSessionInput = {
1066
+ sessionId: string;
1067
+ leaseFence: string;
1068
+ reason: string;
1069
+ };
1070
+ type KillSessionResult = {
1071
+ status: string;
1072
+ };
1073
+ /** v4: Workflow state query result. */
1074
+ type WorkflowStateResult = {
1075
+ workflowId: string;
1076
+ rootSessionId: string;
1077
+ status: string;
1078
+ stateVersion: number;
1079
+ controlRevision: number;
1080
+ totalSessionCount: number;
1081
+ activeSessionCount: number;
1082
+ totalStepCount: number;
1083
+ totalCost: number;
1084
+ totalHandoffCount: number;
1085
+ unresolvedHandoffCount: number;
1086
+ lastEventSeq: number;
1087
+ killScope: string;
1088
+ createdAt: string;
1089
+ updatedAt: string;
1090
+ };
1091
+ /** v4: Handoff offer input. */
1092
+ type HandoffOfferInput = {
1093
+ sessionId: string;
1094
+ workflowId: string;
1095
+ fromRole: string;
1096
+ toRole: string;
1097
+ handoffId: string;
1098
+ artifactRefs?: unknown;
1099
+ summary?: unknown;
1100
+ };
1101
+ /** v4: Handoff offer result. */
1102
+ type HandoffOfferResult = {
1103
+ handoffId: string;
1104
+ eventSeq: number;
1105
+ stateVersion: number;
1106
+ };
1107
+ type RuntimeClientHealth = {
1108
+ circuitOpen: boolean;
1109
+ failureCount: number;
1110
+ circuitOpenUntil: number;
1111
+ };
1112
+ declare class RuntimeClientError extends Error {
1113
+ readonly code: string;
1114
+ readonly httpStatus: number;
1115
+ constructor(code: string, message: string, httpStatus: number);
1116
+ }
1117
+ declare function createRuntimeClient(opts: RuntimeClientOptions): RuntimeClient;
1118
+ declare class RuntimeClient {
1119
+ private readonly apiKey;
1120
+ private readonly baseUrl;
1121
+ private readonly timeoutMs;
1122
+ private readonly fetchImpl;
1123
+ private readonly now;
1124
+ private failureCount;
1125
+ private circuitOpenUntil;
1126
+ constructor(opts: RuntimeClientOptions);
1127
+ createSession(input: RuntimeSessionInit): Promise<RuntimeSessionResult>;
1128
+ preflight(input: PreflightInput): Promise<PreflightResult>;
1129
+ submitProposal(input: ProposalInput): Promise<ProposalResult>;
1130
+ submitReceipt(input: ReceiptInput): Promise<ReceiptResult>;
1131
+ setToolFilter(input: ToolFilterInput): Promise<ToolFilterResult>;
1132
+ reportBypass(input: ReportBypassInput): Promise<ReportBypassResult>;
1133
+ killSession(input: KillSessionInput): Promise<KillSessionResult>;
1134
+ /** v4: Get workflow state from the runtime. */
1135
+ getWorkflowState(workflowId: string): Promise<WorkflowStateResult>;
1136
+ /** v4: Offer a handoff from a session. */
1137
+ offerHandoff(input: HandoffOfferInput): Promise<HandoffOfferResult>;
1138
+ getHealth(): RuntimeClientHealth;
1139
+ isCircuitOpen(): boolean;
1140
+ private get;
1141
+ private post;
1142
+ private recordFailure;
1143
+ }
1144
+
1145
+ export { type BlockReason, type BlockedToolCall, type CircuitBreakerResult, type CompareAndSetResult, type CompletedStep, type CompletedStepSnapshot, type CompletedToolCall, type CompletedToolCallSnapshot, type ConstraintFailure, type ConstraintVerdict, type ContractFailure, type CrossStepCaptureResult, type CrossStepFailure, type CrossStepResult, type DecisionOutcome, type FlushResult, type GateMode, type LoopDetectionResult, MemoryStore, type NarrowRemovalReason, type NarrowResult, type NarrowedTool, type ObserveActivationReasonCode, type ObserveDiagnosticEvent, type ObserveHandle, type ObserveHealthSnapshot, type ObserveOptions, type ObserveSessionState, type PendingEntry, type PhaseTransitionResult, type PolicyVerdict, type PreconditionEvidence, type ReplayCapture, ReplayConfigError, ReplayContractError, type ReplayDecision, type ReplayDiagnosticEvent, type ReplayHealthSnapshot, ReplayKillError, type ReplayMode, type ReplayOptions, type ReplaySession, type ReplayTiming, type ResponseMetadata, RuntimeClient, RuntimeClientError, type RuntimeClientHealth, type RuntimeClientOptions, type RuntimeSessionInit, type RuntimeSessionResult, type SessionState, type SessionStateSnapshot, type ShadowDelta, type Store, type ToolDefinition, type ToolExecutor, type ValidationResult, type WrappedExecutorResult, type WrappedToolExecutor, createRuntimeClient, observe, prepareContracts, replay, validate };