@full-self-browsing/lattice 1.3.0-rc.0 → 1.3.0

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.ts CHANGED
@@ -115,7 +115,7 @@ interface TracerLike {
115
115
  readonly span?: <T>(name: string, fn: () => T | Promise<T>, attributes?: Record<string, unknown>) => T | Promise<T>;
116
116
  readonly event?: (name: string, attributes?: Record<string, unknown>) => void;
117
117
  }
118
- type RunEventKind = "run.start" | "artifact.ingested" | "context.packed" | "router.candidates" | "stage.start" | "stage.complete" | "provider.attempt" | "fallback.activated" | "validation.complete" | "validation.failed" | "artifact.created" | "run.complete" | "run.failed" | "tool.call" | "replay.offline" | "replay.live" | "step.transition" | "recovery.start" | "recovery.complete" | "recovery.failed";
118
+ type RunEventKind = "run.start" | "artifact.ingested" | "context.packed" | "router.candidates" | "stage.start" | "stage.complete" | "provider.attempt" | "fallback.activated" | "validation.complete" | "validation.failed" | "artifact.created" | "run.complete" | "run.failed" | "tool.call" | "replay.offline" | "replay.live" | "step.transition" | "recovery.start" | "recovery.complete" | "recovery.failed" | "capabilities.negotiation.fallback";
119
119
  interface RunEvent {
120
120
  readonly kind: RunEventKind;
121
121
  readonly timestamp: string;
@@ -373,6 +373,130 @@ type TripwireResult = {
373
373
  */
374
374
  declare function evaluateTripwires(output: unknown, invariants: readonly InvariantDeclaration[], detectors?: readonly PiiDetector[]): Promise<TripwireResult>;
375
375
  //#endregion
376
+ //#region src/capabilities/profile.d.ts
377
+ /**
378
+ * Closed enum of the 7 Lattice transport adapters (D-06). Adding a new
379
+ * adapter is a typed breaking change. Phase 34 quirk dispatch reads this
380
+ * field.
381
+ */
382
+ type CapabilityAdapter = "openrouter" | "anthropic" | "openai" | "openai-compat" | "xai" | "gemini" | "lm-studio";
383
+ /**
384
+ * Closed enum of the 5 training-lineage buckets (D-14). Receipt v1.2
385
+ * (Phase 38) carries this value verbatim via the `modelClass` field.
386
+ * Stable across model patches — gpt-4o-2024-05-13 and gpt-4o-2024-08-06
387
+ * share a trainingClass so receipts remain comparable across rebuilds.
388
+ */
389
+ type TrainingClass = "frontier_rlhf" | "mid_tier_rlhf" | "open_weight_instruct" | "open_weight_base" | "local_quantized";
390
+ /**
391
+ * Closed enum of the 5 recommended prompt-tuning buckets (research open
392
+ * question 2). DISTINCT from `TrainingClass`: `reasoning` is orthogonal
393
+ * to lineage (a frontier RLHF model with hidden_cot routes to the
394
+ * `reasoning` strategy bucket); `local` is the granularity boundary
395
+ * for the deployed-locally strategy bucket (vs the `local_quantized`
396
+ * lineage signal). Phase 35 prompt-scaffold dispatch reads this field.
397
+ */
398
+ type RecommendedPromptStrategy = "frontier" | "mid_tier" | "open_weight" | "reasoning" | "local";
399
+ /**
400
+ * Closed enum of the 7 known model-class output-shape failure modes at
401
+ * v1.3.0 (D-12). Adding a member in v1.4+ is an intentional typed
402
+ * breaking change — Phase 36 sanitizer dispatch enforces exhaustiveness
403
+ * via a `_exhaustive: never` switch (see test-d/capabilities.test-d.ts).
404
+ */
405
+ type KnownFailureMode = "internal_envelope_leak" | "reasoning_tag_leak" | "system_prompt_echo" | "template_artifact_leak" | "hallucinated_tool_name" | "malformed_tool_arguments" | "premature_termination";
406
+ /**
407
+ * Closed enum of the 5 reasoning-surface shapes a model exposes. Drives
408
+ * the Phase 36 sanitizer's choice of leak-cleanup pass (e.g., `<think>`
409
+ * tag stripping for `inlined_tags`).
410
+ */
411
+ type ReasoningSurface = "none" | "hidden_cot" | "inlined_tags" | "interleaved_thinking" | "streamed_reasoning";
412
+ /**
413
+ * Closed enum of the 5 tool-call surface shapes a model exposes. Drives
414
+ * the Phase 37 tool-call validator's choice of arguments parser.
415
+ */
416
+ type ToolCallSurface = "none" | "native_strict" | "native_lenient" | "json_only" | "text_only";
417
+ /**
418
+ * Phase 33 — D-05 / D-08 — Capability profile for one (adapter, model)
419
+ * pair. Sibling to `ModelCapability`, not a replacement. Built-time baked
420
+ * via the OpenRouter snapshot generator (Phase 33-03) plus hand-edited
421
+ * supplemental static profiles (Phase 33-04).
422
+ *
423
+ * Canonical key: `${adapter}:${modelId}` — one profile per (adapter,
424
+ * model) pair. `openrouter:openai/gpt-oss-120b` and `openai:gpt-oss-120b`
425
+ * are two distinct entries with the same `originFamily: "openai"`.
426
+ */
427
+ interface ModelCapabilityProfile {
428
+ /**
429
+ * The model identifier as the adapter sees it. For OpenRouter this is
430
+ * the `vendor/model` shape (e.g., `openai/gpt-oss-120b`); for direct
431
+ * adapters this is the provider's native id (e.g., `claude-opus-4`).
432
+ * Combined with `adapter` to form the canonical lookup key `${adapter}:${id}` (D-08).
433
+ */
434
+ readonly id: string;
435
+ /**
436
+ * The Lattice transport adapter that ships this profile (D-05 /
437
+ * D-06). Phase 34 adapter-quirk dispatch reads this field. Closed
438
+ * union of 7 values.
439
+ */
440
+ readonly adapter: CapabilityAdapter;
441
+ /**
442
+ * The model creator (D-07). Open extensible string — new orgs emerge
443
+ * frequently and should not break the type. Examples: `openai`,
444
+ * `anthropic`, `meta`, `mistral`, `google`, `xai`, `deepseek`, `qwen`.
445
+ * Phase 35 prompt-scaffold dispatch falls back to
446
+ * `recommendedPromptStrategy` for unknown originFamily values.
447
+ */
448
+ readonly originFamily: string;
449
+ /**
450
+ * Training-lineage classification (D-14). Receipt v1.2 `modelClass`
451
+ * (Phase 38) carries this value verbatim. Drives the failure-mode
452
+ * default set in the classifier.
453
+ */
454
+ readonly trainingClass: TrainingClass;
455
+ /**
456
+ * Shape of the model's reasoning output. Drives the Phase 36
457
+ * sanitizer's reasoning-leak cleanup pass.
458
+ */
459
+ readonly reasoningSurface: ReasoningSurface;
460
+ /**
461
+ * Shape of the model's tool-call output. Drives the Phase 37
462
+ * tool-call validator's arguments parser.
463
+ */
464
+ readonly toolCallSurface: ToolCallSurface;
465
+ /**
466
+ * The actual context window the adapter will accept on a request, in
467
+ * tokens. For OpenRouter this is `top_provider.context_length ?? context_length`
468
+ * (Phase 33 Pitfall 2) — what OpenRouter routing actually offers, not
469
+ * the model card's aspirational maximum.
470
+ */
471
+ readonly contextWindow: number;
472
+ /**
473
+ * Failure modes this model class is known to exhibit (D-14). Class-
474
+ * derived defaults plus per-family overrides. Phase 36 sanitizer
475
+ * dispatch exhaustively switches on each entry.
476
+ */
477
+ readonly knownFailureModes: readonly KnownFailureMode[];
478
+ /**
479
+ * Recommended prompt-tuning bucket (research open question 2). Phase
480
+ * 35 prompt-scaffold dispatch reads this field. Distinct from
481
+ * `trainingClass` — see `RecommendedPromptStrategy` JSDoc.
482
+ */
483
+ readonly recommendedPromptStrategy: RecommendedPromptStrategy;
484
+ }
485
+ /**
486
+ * Frozen list of every `KnownFailureMode` member. Useful for exhaustive
487
+ * iteration in downstream tests and Phase 36 sanitizer registration.
488
+ * Adding a new mode requires updating this array AND the
489
+ * `KnownFailureMode` union AND the Phase 36 exhaustive switch — the
490
+ * `satisfies` clause enforces array-vs-union parity at compile time.
491
+ */
492
+ declare const ALL_KNOWN_FAILURE_MODES: readonly ["internal_envelope_leak", "reasoning_tag_leak", "system_prompt_echo", "template_artifact_leak", "hallucinated_tool_name", "malformed_tool_arguments", "premature_termination"];
493
+ /**
494
+ * Frozen list of every `TrainingClass` member. Useful for exhaustive
495
+ * iteration when constructing the failure-mode defaults table (D-14)
496
+ * and for Phase 38 receipt-class enumeration.
497
+ */
498
+ declare const ALL_TRAINING_CLASSES: readonly ["frontier_rlhf", "mid_tier_rlhf", "open_weight_instruct", "open_weight_base", "local_quantized"];
499
+ //#endregion
376
500
  //#region src/outputs/contracts.d.ts
377
501
  type TextOutputContract = "text";
378
502
  interface CitationRef {
@@ -469,1478 +593,2111 @@ interface ContextSummarizer {
469
593
  }): Promise<readonly ArtifactRef[]> | readonly ArtifactRef[];
470
594
  }
471
595
  //#endregion
472
- //#region src/providers/provider.d.ts
473
- type CapabilityModality = "text" | "json" | "image" | "audio" | "video" | "document" | "file" | "url" | "tool";
474
- type ProviderTransportMode = "inline" | "json" | "url" | "base64" | "provider-upload" | "file-id" | "extracted-text" | "transcript";
475
- type ProviderLatencyClass = "interactive" | "batch";
476
- interface ProviderPricingHint {
477
- /** @deprecated prefer `inputPer1kTokens` — kept for backward compatibility */
478
- readonly inputCostPer1M?: number;
479
- /** @deprecated prefer `outputPer1kTokens` — kept for backward compatibility */
480
- readonly outputCostPer1M?: number;
481
- /** Per-1000-prompt-token cost in USD. Preferred field for Phase 7+ pricing. */
482
- readonly inputPer1kTokens?: number;
483
- /** Per-1000-completion-token cost in USD. Preferred field for Phase 7+ pricing. */
484
- readonly outputPer1kTokens?: number;
485
- }
596
+ //#region src/runtime/survivability.d.ts
486
597
  /**
487
- * Normalized per-run usage at the result layer.
598
+ * MV3-survivability adapter contract -- Phase 5 (FSB v0.10.0-attempt-2).
488
599
  *
489
- * `costUsd` is `number | null` (not optional, not `0`) so downstream
490
- * consumers can distinguish "free" (`0`) from "unmeasured" (`null`) when
491
- * provider pricing is unknown — see 07-CONTEXT.md "Cost Normalization & Usage".
600
+ * This module is a SIBLING of create-ai.ts (the Lattice runtime facade) and
601
+ * a SIBLING of contract/bands.ts (the hook pipeline factory) and
602
+ * contract/checkpoint.ts (the per-step receipt hook). It does NOT modify
603
+ * any of them; the SurvivabilityAdapter contract is composed from those
604
+ * surfaces by the consumer (FSB's lattice-runtime-adapter.js in Plan 05-05).
492
605
  *
493
- * Distinct from `UsageRecord` on `ProviderAttemptRecord`: `UsageRecord`
494
- * is the per-attempt record, `Usage` is the per-run normalized shape
495
- * surfaced on `RunSuccess` / `RunFailure`.
606
+ * What is the survivability problem?
607
+ * Some host runtimes can evict the execution context mid-flow with no
608
+ * synchronous shutdown signal:
609
+ * - Chrome MV3 service workers: evicted after 30s silence OR 5min idle.
610
+ * - Cloudflare Workers: evicted at end of each request unless waitUntil.
611
+ * - AWS Lambda: process freeze + thaw across invocations.
612
+ * Lattice's existing runtime (create-ai.ts) assumes the process stays
613
+ * live for the duration of a run. The SurvivabilityAdapter contract is
614
+ * the seam where a host runtime tells Lattice "here is how to serialize
615
+ * my state, here is how to deserialize it back, here is how to resume
616
+ * work after I get evicted and recreated."
617
+ *
618
+ * What this module SHIPS:
619
+ * - SurvivabilityAdapter<TState> interface (4 methods)
620
+ * - SerializedSnapshot type (string-encodable opaque envelope)
621
+ * - EvictionHook<TState> type (pre-eviction callback signature)
622
+ * - ResumePolicy literal-union (post-restore reconstruction verdict)
623
+ * - UnsubscribeFn type
624
+ * - createNoopSurvivabilityAdapter() reference implementation
625
+ *
626
+ * What this module DOES NOT ship:
627
+ * - chrome.storage.session integration (FSB-side; Plan 05-05).
628
+ * - offscreen-document message bus (FSB-side; Plan 05-04).
629
+ * - Auto-wiring into create-ai.ts runtime (deferred indefinitely; the
630
+ * contract is consumer-controlled).
631
+ * - Mid-API-request / mid-tool-dispatch recovery dispatcher (CONSERVATIVE
632
+ * recovery wiring is deferred to a follow-on FSB milestone per
633
+ * CONTEXT.md D-22; only the ResumePolicy taxonomy lands here).
634
+ *
635
+ * Composition conventions (NOT enforced; documented for callers):
636
+ * D-09: onEviction hooks SHOULD register in BAND.SAFETY band on the
637
+ * caller's HookPipeline so they run FIRST per Phase 2 priority
638
+ * ordering. This module does NOT auto-register; it ships the
639
+ * contract only.
640
+ * D-10: serialize(state) MAY include the latest checkpoint receipt
641
+ * envelope (Phase 3 createCheckpointHook output) inside the
642
+ * SerializedSnapshot.payload; deserialize() reconstructs session
643
+ * identifiers from the v1.1 receipt body's step-marker fields
644
+ * (stepName, stepIndex, parentStepName, previousStepName,
645
+ * sessionId, timestamp). The payload is opaque to Lattice -- the
646
+ * host runtime defines the shape.
647
+ *
648
+ * ResumePolicy taxonomy (CD-E resolution per attempt-1 02-04-PLAN.md):
649
+ * - SAFE: the snapshot was captured at a safe boundary (BEFORE_ITERATION
650
+ * or BEFORE_NEXT_ITERATION_SCHEDULE step markers) and can be replayed
651
+ * deterministically. The host runtime may re-arm the loop.
652
+ * - RECOVERY_AMBIGUOUS: the snapshot was captured during a tool dispatch
653
+ * where re-execution risk is non-zero (file write, network POST without
654
+ * Idempotency-Key, side-effecting browser action). Host should escalate
655
+ * to the user before deciding.
656
+ * - ON_ERROR_SW_EVICTION_MID_REQUEST: the eviction happened mid-API-call
657
+ * (the provider request was in flight). 6 of 7 FSB providers do NOT
658
+ * document Idempotency-Key headers; replay risks duplicate charges +
659
+ * duplicate responses. Host should treat the run as failed and surface
660
+ * the error to the user.
661
+ * - ON_ERROR_SW_EVICTION_MID_TOOL_DISPATCH: the eviction happened mid-
662
+ * tool-dispatch (a browser action was in progress). Re-execution risk
663
+ * is similar to mid-API-call but lands in a different recovery branch
664
+ * (the host may inspect the page state before deciding).
665
+ *
666
+ * SerializedSnapshot is intentionally opaque + string-encodable. The
667
+ * host runtime defines the payload shape; Lattice's only requirement
668
+ * is that serialize() followed by deserialize() round-trips the state.
669
+ *
670
+ * Ed25519 receipt envelope contract (carries forward from Phase 1-3):
671
+ * Callers MAY embed a v1.1 ReceiptEnvelope inside SerializedSnapshot.payload
672
+ * for signed checkpoint round-trip. verifyReceipt against the embedded
673
+ * envelope MUST return result.ok === true after a serialize -> deserialize
674
+ * cycle (Test 12). This validates that JSON.stringify + JSON.parse over
675
+ * the envelope preserves the JCS-canonical body bytes used by DSSE PAE.
676
+ *
677
+ * Threat model (Phase 5 CONTEXT.md security block):
678
+ * - PII via serialized state: callers MUST ensure SerializedSnapshot.payload
679
+ * contains only stable identifiers + user-controlled state the user has
680
+ * already consented to persist. Mirrors Phase 2 D-04 receipt-body contract
681
+ * (step-marker fields are stable identifiers, not free-form user input).
682
+ * - Snapshot tampering: the noop adapter does NOT sign the snapshot.
683
+ * Callers that need cryptographic integrity SHOULD embed a signed
684
+ * ReceiptEnvelope inside the payload + verify it on deserialize.
685
+ * Phase 5 ships the contract; signature wrapping is a follow-on.
686
+ *
687
+ * Vocabulary separation (carries forward Phase 2 D-12 + Phase 3 D-02):
688
+ * ResumePolicy is the survivability vocabulary -- separate from
689
+ * RunEventKind (tracing) AND separate from HookLifecycleEvent (bands).
690
+ * The three vocabularies meet only when a host runtime composes them.
496
691
  */
497
- interface Usage {
498
- readonly promptTokens: number;
499
- readonly completionTokens: number;
500
- readonly costUsd: number | null;
501
- }
502
- interface ProviderDataPolicyHints {
503
- readonly privacy: readonly ("standard" | "sensitive" | "restricted")[];
504
- readonly uploadRetention?: "none" | "ephemeral" | "provider-default";
505
- readonly supportsNoLogging?: boolean;
506
- readonly supportsNoTraining?: boolean;
507
- }
508
- interface ModelCapability {
509
- readonly providerId: string;
510
- readonly modelId: string;
511
- readonly inputModalities: readonly CapabilityModality[];
512
- readonly outputModalities: readonly CapabilityModality[];
513
- readonly fileTransport: readonly ProviderTransportMode[];
514
- readonly contextWindow: number;
515
- readonly structuredOutput: boolean;
516
- readonly toolUse: boolean;
517
- readonly streaming: boolean;
518
- readonly pricing?: ProviderPricingHint;
519
- readonly latency: ProviderLatencyClass;
520
- readonly dataPolicy: ProviderDataPolicyHints;
521
- readonly available?: boolean;
692
+ /**
693
+ * String-encodable opaque snapshot. The host runtime defines the payload
694
+ * shape; Lattice's only requirement is that serialize() followed by
695
+ * deserialize() round-trips the original state object.
696
+ *
697
+ * Why string-encodable? MV3's chrome.storage.session and most cross-process
698
+ * storage layers accept structured-clone-safe values. JSON-string payloads
699
+ * are the lowest-common-denominator that survives MV3 SW eviction +
700
+ * Cloudflare Worker freeze + Lambda thaw. Callers MAY use a richer payload
701
+ * shape (Uint8Array, Blob) IF the host runtime supports it; the contract
702
+ * does not constrain payload format beyond "deserialize round-trips it".
703
+ */
704
+ interface SerializedSnapshot {
705
+ readonly kind: "survivability-snapshot";
706
+ readonly version: "lattice-survivability/v1";
707
+ readonly payload: string;
708
+ readonly capturedAt: string;
522
709
  }
523
- interface ProviderRef {
710
+ /**
711
+ * Pre-eviction callback. The host runtime CAN attempt to call this hook
712
+ * before the execution context is evicted, but MAY NOT be able to in
713
+ * every case (MV3 eviction has no synchronous signal -- the SW just
714
+ * stops). Callers should treat onEviction as best-effort: useful for
715
+ * gathering final state when the eviction is announced (e.g., user-
716
+ * initiated stop) but not load-bearing for involuntary eviction.
717
+ *
718
+ * The hook receives the current TState by reference. Mutations on the
719
+ * hook side leak to the caller's state -- this is deliberate (the hook
720
+ * is the LAST chance to update state before eviction). Callers who want
721
+ * structuredClone semantics SHOULD wrap state in their own freeze layer.
722
+ */
723
+ type EvictionHook<TState> = (state: TState) => void | Promise<void>;
724
+ /**
725
+ * Return value of onEviction(); calling unsubscribes the hook.
726
+ *
727
+ * Idempotent -- calling twice has the same effect as calling once.
728
+ */
729
+ type UnsubscribeFn = () => void;
730
+ /**
731
+ * Resume policy taxonomy. The host runtime calls adapter.resume(snapshot)
732
+ * after eviction + restore; the returned policy tells the host runtime
733
+ * how to react.
734
+ *
735
+ * The 4 literal members carry forward from FSB v0.10.0-attempt-1's
736
+ * 02-04-PLAN.md CONSERVATIVE recovery dispatch (preserved at
737
+ * .planning/milestones/v0.10.0-attempt-1-pre-pivot/02-state-inspectability-
738
+ * carve-out/02-04-PLAN.md). Per CONTEXT.md CD-E this is the locked union.
739
+ */
740
+ type ResumePolicy = "SAFE" | "RECOVERY_AMBIGUOUS" | "ON_ERROR_SW_EVICTION_MID_REQUEST" | "ON_ERROR_SW_EVICTION_MID_TOOL_DISPATCH";
741
+ /**
742
+ * The SurvivabilityAdapter contract. Host runtimes implement this; Lattice
743
+ * runs against the interface.
744
+ *
745
+ * 4 methods (D-08 locked):
746
+ * - serialize(state): convert in-memory state to SerializedSnapshot
747
+ * - deserialize(snapshot): inverse of serialize
748
+ * - onEviction(hook): register a best-effort pre-eviction callback
749
+ * - resume(snapshot): return ResumePolicy verdict for the post-restore
750
+ * reconstruction. The host runtime acts on the policy.
751
+ *
752
+ * Adapters are POLYMORPHIC over TState -- the host runtime parameterizes
753
+ * the type. Lattice's vitest covers the contract surface with a noop
754
+ * adapter where TState = Record<string, unknown> for ergonomics.
755
+ */
756
+ interface SurvivabilityAdapter<TState> {
757
+ readonly kind: "survivability-adapter";
524
758
  readonly id: string;
525
- readonly kind?: "provider-ref";
759
+ serialize(state: TState): SerializedSnapshot;
760
+ deserialize(snapshot: SerializedSnapshot): TState;
761
+ onEviction(hook: EvictionHook<TState>): UnsubscribeFn;
762
+ resume(snapshot: SerializedSnapshot): Promise<ResumePolicy>;
526
763
  }
527
- interface ProviderRunRequest {
528
- readonly task: string;
529
- readonly artifacts: readonly ArtifactInput[];
530
- readonly outputs: readonly string[];
531
- readonly outputContracts?: OutputContractMap;
532
- readonly policy?: unknown;
764
+ /**
765
+ * Factory options for the reference noop adapter.
766
+ *
767
+ * - id: optional. Defaults to "noop-survivability". Useful when callers
768
+ * want to distinguish multiple adapter instances in test fixtures.
769
+ * - policy: optional. Sets the default ResumePolicy returned by resume().
770
+ * Defaults to "SAFE" (matches noop adapter semantics: no recovery
771
+ * ambiguity if nothing was ever persisted).
772
+ */
773
+ interface NoopSurvivabilityAdapterOptions {
774
+ readonly id?: string;
775
+ readonly policy?: ResumePolicy;
776
+ }
777
+ /**
778
+ * Reference implementation of SurvivabilityAdapter<TState>. Records
779
+ * eviction events but does NOT persist; serialize / deserialize round-
780
+ * trip via JSON.stringify / JSON.parse. Analog to createFakeProvider
781
+ * in the providers/ module -- gives Lattice's vitest a complete shape-
782
+ * conformance target before the real (FSB-side) adapter ships in
783
+ * Plan 05-05.
784
+ *
785
+ * Per CONTEXT.md D-11 the noop adapter ships in Lattice (not FSB)
786
+ * because it covers the contract surface in Lattice's own test suite;
787
+ * FSB's real chrome.storage.session-backed adapter is glue layer.
788
+ */
789
+ declare function createNoopSurvivabilityAdapter<TState = Record<string, unknown>>(options?: NoopSurvivabilityAdapterOptions): SurvivabilityAdapter<TState>;
790
+ //#endregion
791
+ //#region src/tools/tools.d.ts
792
+ interface ToolExecutionContext {
533
793
  readonly signal?: AbortSignal;
534
- readonly plan?: ExecutionPlan;
535
- readonly contextPack?: ContextPack;
536
- readonly providerPackaging?: ProviderPackagingPlan;
537
- readonly packagedArtifacts?: readonly ArtifactRef[];
794
+ readonly emit?: RunEventSink;
538
795
  }
539
- interface ProviderRunResponse {
540
- readonly rawOutputs: Record<string, unknown>;
541
- readonly artifactRefs?: readonly (ArtifactInput | ArtifactRef)[];
796
+ interface ToolDefinition<TSchema extends StandardSchemaV1 = StandardSchemaV1> {
797
+ readonly kind: "tool";
798
+ readonly name: string;
799
+ readonly description?: string;
800
+ readonly inputSchema: TSchema;
801
+ readonly execute: (input: StandardSchemaV1.InferOutput<TSchema>, context: ToolExecutionContext) => Promise<unknown> | unknown;
802
+ }
803
+ interface ToolCallResult {
804
+ readonly callId: string;
805
+ readonly toolName: string;
806
+ readonly artifact: ArtifactInput;
807
+ }
808
+ declare function defineTool<TSchema extends StandardSchemaV1>(definition: Omit<ToolDefinition<TSchema>, "kind">): ToolDefinition<TSchema>;
809
+ declare function runTool<TSchema extends StandardSchemaV1>(tool: ToolDefinition<TSchema>, input: unknown, context?: ToolExecutionContext): Promise<ToolCallResult>;
810
+ interface McpLikeClient {
811
+ readonly listTools?: () => Promise<readonly McpToolDescriptor[]> | readonly McpToolDescriptor[];
812
+ readonly callTool: (input: {
813
+ readonly name: string;
814
+ readonly arguments: unknown;
815
+ }) => Promise<unknown> | unknown;
816
+ }
817
+ interface McpToolDescriptor {
818
+ readonly name: string;
819
+ readonly description?: string;
820
+ readonly inputSchema: StandardSchemaV1;
821
+ }
822
+ declare function importMcpTools(client: McpLikeClient, toolNames?: readonly string[]): Promise<readonly ToolDefinition[]>;
823
+ declare function toolArtifactRef(result: ToolCallResult): ArtifactRef;
824
+ //#endregion
825
+ //#region src/agent/format-tools.d.ts
826
+ /**
827
+ * One turn in the running conversation.
828
+ *
829
+ * `role: "tool"` is used for tool-result turns; `toolCallId` and `toolName`
830
+ * are populated so the model can correlate the result with its prior
831
+ * `tool_call` envelope.
832
+ */
833
+ interface ConversationTurn {
834
+ readonly role: "user" | "assistant" | "tool";
835
+ readonly content: string;
836
+ readonly toolCallId?: string;
837
+ readonly toolName?: string;
838
+ }
839
+ type FormatToolsMode = "native" | "prompt-reencoded" | "auto";
840
+ interface FormatToolsOptions {
542
841
  /**
543
- * @deprecated Legacy per-attempt usage shape. Phase 7+ adapters should
544
- * populate `normalizedUsage` instead Plan 04 will prefer `normalizedUsage`
545
- * when wiring `RunResult.usage`. Kept here for backward compatibility with
546
- * v1.0 adapters that already report this field.
842
+ * Tool-use protocol mode. Defaults to `"auto"`, which currently resolves
843
+ * to `"prompt-reencoded"` for ALL 7 providers (Phase 19 simplification —
844
+ * native tool_use deferred to a follow-on milestone). Reserved for
845
+ * forward compatibility.
547
846
  */
548
- readonly usage?: UsageRecord;
847
+ readonly mode?: FormatToolsMode;
549
848
  /**
550
- * Phase 7 normalized usage shape for `RunResult.usage`. Populated by all
551
- * Phase 7+ adapters (openai, openai-compat, ai-sdk, fake). `costUsd` is
552
- * `null` when pricing is unknown (per the cost-normalization decision in
553
- * 07-CONTEXT.md — distinguishes "free" from "unmeasured").
849
+ * Optional system prompt to prepend. Useful for setting persona /
850
+ * domain-specific instructions on top of the tool-use envelope.
554
851
  */
555
- readonly normalizedUsage?: Usage;
556
- readonly rawResponse?: unknown;
852
+ readonly system?: string;
557
853
  }
558
- interface ProviderAdapter {
559
- readonly id: string;
560
- readonly kind: "provider-adapter";
561
- readonly capabilities?: readonly ModelCapability[];
562
- readonly execute?: (request: ProviderRunRequest) => Promise<ProviderRunResponse>;
854
+ interface FormattedToolsHandle {
855
+ /**
856
+ * Builds the single `task` string passed to `ProviderAdapter.execute()`.
857
+ * Encodes the conversation, available tools, and response-envelope
858
+ * instructions.
859
+ */
860
+ readonly buildTask: (conversation: readonly ConversationTurn[]) => string;
861
+ /**
862
+ * Phase 39 (v1.3): body-only sibling of `buildTask` — identical turn
863
+ * rendering minus the leading system block, so the byte-stable
864
+ * `describeForSystem()` prefix can be hoisted once per crew for
865
+ * prompt-cache sharing without duplication (39-05).
866
+ *
867
+ * Invariant: `describeForSystem() + "\n" + buildTaskBody(conversation)`
868
+ * reconstructs `buildTask(conversation)` byte-for-byte.
869
+ */
870
+ readonly buildTaskBody: (conversation: readonly ConversationTurn[]) => string;
871
+ /**
872
+ * Parses the assistant's response text. Returns:
873
+ * - `ToolUseRequest[]` when the response contains one or more tool-call
874
+ * envelopes (parsed in declaration order).
875
+ * - `null` when the response is a final answer (no tool-call envelopes
876
+ * detected).
877
+ *
878
+ * The parser is forgiving: it tolerates extra prose around the JSON
879
+ * envelope (markdown fences, leading explanations) and the model
880
+ * occasionally drifting on whitespace.
881
+ */
882
+ readonly parseToolUse: (responseText: string) => ReadonlyArray<ToolUseRequest> | null;
883
+ /**
884
+ * Returns the static system block describing available tools. Useful for
885
+ * tracing / logging the exact tool-description text fed to the model.
886
+ */
887
+ readonly describeForSystem: () => string;
888
+ /**
889
+ * Effective mode this handle resolved to (`"prompt-reencoded"` for all
890
+ * v1.2 providers). Exposed for inspectability.
891
+ */
892
+ readonly mode: "prompt-reencoded";
563
893
  }
564
- type ProviderRegistryInput = readonly (ProviderRef | ProviderAdapter | string)[];
894
+ /**
895
+ * Convert a Standard Schema to a JSON Schema-shaped descriptor suitable for
896
+ * inclusion in an LLM tool description. Standard Schema vendors can
897
+ * optionally expose `toJSONSchema` on their schema objects; when absent,
898
+ * we fall back to a minimal structural description that lists the schema
899
+ * vendor + version + a placeholder. Models tolerate placeholder schemas in
900
+ * practice because the tool description is supplementary — what matters
901
+ * is the envelope contract (`{tool_call: {name, args}}`).
902
+ */
903
+ declare function toolSchemaToJsonSchema(schema: StandardSchemaV1): unknown;
904
+ /**
905
+ * Builds the prompt-reencoded tool-use protocol handle for any provider.
906
+ *
907
+ * Phase 19 ships a uniform implementation across all 7 logical providers
908
+ * (openai, openai-compat, anthropic, gemini, xai, openrouter, lm-studio).
909
+ * The `providerName` argument is accepted for forward compatibility but
910
+ * does not branch the implementation in v1.2.
911
+ */
912
+ declare function formatToolsForProvider(providerName: string, tools: ReadonlyArray<ToolDefinition<StandardSchemaV1>>, options?: FormatToolsOptions): FormattedToolsHandle;
913
+ declare function parseToolUseEnvelope(responseText: string): ReadonlyArray<ToolUseRequest> | null;
565
914
  //#endregion
566
- //#region src/plan/plan.d.ts
567
- type ExecutionPlanStatus = "stub" | "planned" | "no-route" | "running" | "completed" | "failed";
568
- type ExecutionStageKind = "analysis" | "transforms" | "context-packing" | "provider-packaging" | "tool-execution" | "execution" | "validation" | "tripwire" | "persistence" | "replay";
569
- type ExecutionStageStatus = "pending" | "running" | "completed" | "skipped" | "failed";
570
- interface ExecutionPlanStage {
571
- readonly id: string;
572
- readonly kind: ExecutionStageKind;
573
- readonly status: ExecutionStageStatus;
574
- readonly inputArtifacts?: readonly string[];
575
- readonly outputArtifacts?: readonly string[];
576
- readonly warnings: readonly string[];
577
- readonly metadata?: Record<string, unknown>;
915
+ //#region src/agent/host.d.ts
916
+ /**
917
+ * Snapshot shape the agent loop serializes between iterations. The full
918
+ * shape is opaque to callers (they only see it through SerializedSnapshot
919
+ * via the configured SurvivabilityAdapter) but it's exported so reference
920
+ * implementations and tests can inspect the round-trip.
921
+ */
922
+ interface AgentSnapshot {
923
+ readonly version: "agent-snapshot/v1";
924
+ readonly iterationIndex: number;
925
+ readonly conversation: readonly ConversationTurn[];
926
+ readonly cumulativeUsage: Usage;
927
+ readonly providerName: string;
928
+ readonly capturedAt: string;
929
+ /**
930
+ * Phase 39 (v1.3): dispatch ancestry chain of crew `AgentSpec` ids
931
+ * (root-first). Absent = root agent (single-agent runs never set it).
932
+ * Optional so existing serialized `agent-snapshot/v1` snapshots
933
+ * deserialize unchanged — the version literal stays `"agent-snapshot/v1"`
934
+ * (D-05; Pitfall 8). The crew dispatcher threads the chain through
935
+ * dispatch context in 39-05; cycle prevention rejects any dispatch whose
936
+ * target id already appears in the chain.
937
+ */
938
+ readonly ancestry?: readonly string[];
578
939
  }
579
- interface RouteRejectReason {
580
- readonly code: string;
581
- readonly message: string;
940
+ /**
941
+ * Scheduler seam — controls how the agent loop yields between iterations.
942
+ *
943
+ * `scheduleNext(iterationIndex)` is called AFTER an AFTER_AGENT_ITERATION
944
+ * emission and BEFORE the next iteration's BEFORE_AGENT_ITERATION. The
945
+ * scheduler decides when to resume — synchronously (sync loop), on next
946
+ * tick (setTimeout/queueMicrotask), via a queue (Durable Object), or any
947
+ * other strategy.
948
+ *
949
+ * Default (noop): resolves immediately.
950
+ */
951
+ interface AgentScheduler {
952
+ scheduleNext(iterationIndex: number): Promise<void>;
582
953
  }
583
- interface RouteCandidate {
584
- readonly providerId: string;
585
- readonly modelId: string;
586
- readonly capability: ModelCapability;
587
- readonly score: number;
588
- readonly accepted: boolean;
589
- readonly reasons: readonly RouteRejectReason[];
590
- readonly estimates: RouteEstimates;
954
+ /**
955
+ * Transport seam — controls how a provider call is dispatched.
956
+ *
957
+ * `call(provider, request)` wraps the provider's `execute()` invocation.
958
+ * Default (noop): pass-through (`provider.execute!(request)`). Cross-process
959
+ * bridges (FSB's offscreen-document host) override to dispatch via
960
+ * `chrome.runtime.sendMessage`.
961
+ *
962
+ * Per the Phase 19 INV-03 parity invariant, the transport seam does NOT
963
+ * modify the `ProviderAdapter` interface — it operates on top of the
964
+ * existing `execute()` method.
965
+ */
966
+ interface AgentTransport {
967
+ call(provider: ProviderAdapter, request: ProviderRunRequest): Promise<ProviderRunResponse>;
591
968
  }
592
- interface RouteEstimates {
593
- readonly inputTokens: number;
594
- readonly outputTokens: number;
595
- readonly costUsd?: number;
596
- readonly latencyMs?: number;
969
+ /**
970
+ * Storage seam — controls how agent state persists between iterations for
971
+ * resume after host eviction.
972
+ *
973
+ * Phase 20 composes this with the Phase 18 `SurvivabilityAdapter`:
974
+ * - The adapter serializes `AgentSnapshot` to `SerializedSnapshot` on
975
+ * each AFTER_AGENT_ITERATION; storage.save() persists the snapshot.
976
+ * - On run start, the agent loop calls storage.load(). If a non-null
977
+ * snapshot is returned, the adapter deserializes it; the loop resumes
978
+ * at the recorded iteration index.
979
+ * - On success, the loop calls storage.clear() so the next run starts
980
+ * fresh.
981
+ *
982
+ * Default (noop): save() is a no-op, load() returns null, clear() is a
983
+ * no-op. Suitable for Node tests where eviction never occurs.
984
+ */
985
+ interface AgentStorage {
986
+ save(snapshot: SerializedSnapshot): Promise<void>;
987
+ load(): Promise<SerializedSnapshot | null>;
988
+ clear(): Promise<void>;
597
989
  }
598
- interface SelectedRoute {
599
- readonly providerId: string;
600
- readonly modelId: string;
601
- readonly score: number;
602
- readonly estimates: RouteEstimates;
603
- readonly inputModalities: readonly CapabilityModality[];
604
- readonly outputModalities: readonly CapabilityModality[];
605
- readonly fileTransport: readonly ProviderTransportMode[];
606
- }
607
- interface FallbackRoute {
608
- readonly providerId: string;
609
- readonly modelId: string;
610
- readonly score: number;
611
- readonly reason: "policy-preserving-fallback";
612
- }
613
- interface RouteDecision {
614
- readonly catalogVersion: string;
615
- readonly selected?: SelectedRoute;
616
- readonly candidates: readonly RouteCandidate[];
617
- readonly rejected: readonly RouteCandidate[];
618
- readonly fallbackChain: readonly FallbackRoute[];
619
- readonly noRouteReasons: readonly RouteRejectReason[];
990
+ /**
991
+ * The host adapter — three optional seams, all swappable independently.
992
+ *
993
+ * Callers pass `host` on `AgentIntent`. The agent runtime falls back to
994
+ * `createNoopAgentHost()` when `intent.host` is absent (so Phase 19
995
+ * single-shot Node usage continues to work without explicit configuration).
996
+ */
997
+ interface AgentHost {
998
+ readonly kind: "agent-host";
999
+ readonly scheduler?: AgentScheduler;
1000
+ readonly transport?: AgentTransport;
1001
+ readonly storage?: AgentStorage;
620
1002
  }
621
- interface ContextPackPlan {
622
- readonly id: string;
623
- readonly tokenBudget: number;
624
- readonly estimatedTokens: number;
625
- readonly included: readonly ContextPackItemPlan[];
626
- readonly summarized: readonly ContextPackItemPlan[];
627
- readonly archived: readonly ContextPackItemPlan[];
628
- readonly omitted: readonly ContextPackItemPlan[];
629
- readonly warnings: readonly string[];
1003
+ /**
1004
+ * Reference implementation suitable for Node tests + the Phase 19 default
1005
+ * behavior.
1006
+ *
1007
+ * - scheduler: resolves immediately (no yield between iterations).
1008
+ * - transport: pass-through to provider.execute().
1009
+ * - storage: save() / clear() are no-ops; load() always returns null.
1010
+ *
1011
+ * Equivalent to passing no host at all.
1012
+ */
1013
+ declare function createNoopAgentHost(): AgentHost;
1014
+ //#endregion
1015
+ //#region src/contract/contract.d.ts
1016
+ /**
1017
+ * Budget invariant declaration attached to a CapabilityContract.
1018
+ *
1019
+ * Phase 7 implements `maxCostUsd` enforcement at pre-flight. The
1020
+ * `p95LatencyMs` field is declared per CONTRACT-02 but is informational
1021
+ * only in Phase 7 — latency observations are wired in a later phase.
1022
+ *
1023
+ * Phase 19 (v1.2) adds `maxIterations` and `maxWallTimeMs` for the agent
1024
+ * runtime. Both are additive and optional; non-agent callers ignore them.
1025
+ * `maxIterations` caps the number of `runAgent` iterations; `maxWallTimeMs`
1026
+ * caps wall-clock duration per `runAgent` invocation. Both are enforced
1027
+ * pre-iteration in the agent loop.
1028
+ */
1029
+ interface BudgetInvariant {
1030
+ readonly maxCostUsd?: number;
1031
+ readonly maxIterations?: number;
1032
+ readonly maxWallTimeMs?: number;
1033
+ readonly p95LatencyMs?: number;
630
1034
  }
631
- interface ContextPackItemPlan {
632
- readonly artifactId?: string;
633
- readonly sessionTurnId?: string;
634
- readonly reason: string;
635
- readonly estimatedTokens: number;
636
- readonly trust: "developer" | "user" | "tool" | "model-summary";
1035
+ /**
1036
+ * Quality-floor invariant.
1037
+ *
1038
+ * `suite` is a fixture-directory path string; `minScore` is in 0..1.
1039
+ * Phase 7 forwards this into the pre-flight evaluator but only enforces
1040
+ * capability-side rejects. Full enforcement lives in Phase 12 (`lattice eval`).
1041
+ */
1042
+ interface QualityFloorInvariant {
1043
+ readonly suite: string;
1044
+ readonly minScore: number;
637
1045
  }
638
- interface ProviderPackagingPlan {
639
- readonly providerId: string;
640
- readonly modelId: string;
641
- readonly artifacts: readonly ProviderPackagedArtifactPlan[];
642
- readonly warnings: readonly string[];
1046
+ /**
1047
+ * The full Capability Contract attached to `RunIntent.contract`.
1048
+ *
1049
+ * All fields are optional. v1.0 callers compile and run unchanged when
1050
+ * the field is omitted entirely. PROJECT.md explicitly rejects mandatory
1051
+ * contracts.
1052
+ */
1053
+ interface CapabilityContract {
1054
+ readonly kind: "capability-contract";
1055
+ readonly budget?: BudgetInvariant;
1056
+ readonly invariants?: readonly InvariantDeclaration[];
1057
+ readonly qualityFloor?: QualityFloorInvariant;
1058
+ readonly requiredModalities?: readonly CapabilityModality[];
1059
+ readonly requiredPrivacy?: "standard" | "sensitive" | "restricted";
643
1060
  }
644
- interface ProviderPackagedArtifactPlan {
645
- readonly artifactId: string;
646
- readonly transport: ProviderTransportMode;
647
- readonly mediaType?: string;
648
- readonly lineageTransform: "provider-packaging";
649
- readonly warnings: readonly string[];
1061
+ /**
1062
+ * Reject-reason taxonomy added to `RouteRejectReason.code` by Phase 7's
1063
+ * pre-flight evaluator. Closed four-value union per the locked decisions
1064
+ * in 07-CONTEXT.md.
1065
+ */
1066
+ type ContractRejectReasonCode = "contract-budget-exceeded" | "contract-quality-floor" | "contract-modality-missing" | "contract-privacy-mismatch";
1067
+ /** Input shape accepted by `contract()`. Mirrors `CapabilityContract` minus `kind`. */
1068
+ interface CapabilityContractInput {
1069
+ readonly budget?: BudgetInvariant;
1070
+ readonly invariants?: readonly InvariantDeclaration[];
1071
+ readonly qualityFloor?: QualityFloorInvariant;
1072
+ readonly requiredModalities?: readonly CapabilityModality[];
1073
+ readonly requiredPrivacy?: "standard" | "sensitive" | "restricted";
650
1074
  }
651
- interface ProviderAttemptRecord {
652
- readonly providerId: string;
653
- readonly modelId: string;
654
- readonly status: "pending" | "running" | "succeeded" | "failed" | "cancelled";
655
- readonly startedAt?: string;
656
- readonly completedAt?: string;
657
- readonly error?: string;
658
- readonly usage?: UsageRecord;
1075
+ /**
1076
+ * Factory for `CapabilityContract` values.
1077
+ *
1078
+ * Mirrors the `output()` and adapter factory style exact-optional safe
1079
+ * (does not emit `field: undefined` properties under `exactOptionalPropertyTypes`).
1080
+ * Returns a frozen value with frozen nested objects so downstream code can
1081
+ * rely on structural immutability when canonicalizing in Phase 9.
1082
+ */
1083
+ declare function contract(input?: CapabilityContractInput): CapabilityContract;
1084
+ //#endregion
1085
+ //#region src/outputs/infer.d.ts
1086
+ type InferOutput<C> = C extends "text" ? string : C extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<C> : C extends CitationsOutputContract ? readonly CitationRef[] : C extends ArtifactRefsOutputContract ? readonly ArtifactRef[] : never;
1087
+ type InferOutputMap<T extends OutputContractMap> = { readonly [K in keyof T]: InferOutput<T[K]> };
1088
+ //#endregion
1089
+ //#region src/results/errors.d.ts
1090
+ interface ValidationIssue {
1091
+ readonly message: string;
1092
+ readonly path?: readonly (string | number | symbol)[];
659
1093
  }
660
- interface UsageRecord {
661
- readonly inputTokens?: number;
662
- readonly outputTokens?: number;
663
- readonly totalTokens?: number;
664
- readonly costUsd?: number;
665
- readonly latencyMs?: number;
1094
+ interface ValidationError {
1095
+ readonly kind: "validation";
1096
+ readonly message: string;
1097
+ readonly output?: string;
1098
+ readonly issues: readonly ValidationIssue[];
666
1099
  }
667
- interface ExecutionPlan {
668
- readonly id: string;
669
- readonly kind: "execution-plan";
670
- readonly version: 1;
671
- readonly createdAt: string;
672
- readonly status: ExecutionPlanStatus;
673
- readonly task: string;
674
- readonly outputNames: readonly string[];
675
- readonly artifactRefs: readonly ArtifactRef[];
676
- readonly route: RouteDecision;
677
- readonly stages: readonly ExecutionPlanStage[];
678
- readonly context?: ContextPackPlan;
679
- readonly providerPackaging?: ProviderPackagingPlan;
680
- readonly attempts: readonly ProviderAttemptRecord[];
681
- readonly warnings: readonly string[];
682
- readonly metadata?: Record<string, unknown>;
1100
+ interface ExecutionUnavailableError {
1101
+ readonly kind: "execution_unavailable";
1102
+ readonly message: string;
683
1103
  }
684
- interface ExecutionPlanStub {
685
- readonly id: string;
686
- readonly kind: "plan-stub";
687
- readonly createdAt: string;
688
- readonly status: "stub";
689
- readonly stages: readonly [];
690
- readonly warnings: readonly string[];
1104
+ interface NoRouteError {
1105
+ readonly kind: "no_route";
1106
+ readonly message: string;
1107
+ readonly reasons: readonly string[];
691
1108
  }
692
- type ResultPlan = ExecutionPlan | ExecutionPlanStub;
693
- //#endregion
694
- //#region src/receipts/types.d.ts
695
- type ContractVerdict = "success" | "tripwire-violated" | "no-contract-match" | "execution-failed" | "validation-failed";
696
- interface ReceiptUsageCanonical {
697
- readonly promptTokens: number;
698
- readonly completionTokens: number;
699
- readonly costUsd: string | null;
1109
+ interface ProviderExecutionError {
1110
+ readonly kind: "provider_execution";
1111
+ readonly message: string;
1112
+ readonly providerId?: string;
1113
+ readonly modelId?: string;
700
1114
  }
701
- interface ReceiptModel {
702
- readonly requested: string;
703
- readonly observed: string | null;
1115
+ interface TimeoutError {
1116
+ readonly kind: "timeout";
1117
+ readonly message: string;
704
1118
  }
705
- interface ReceiptRoute {
706
- readonly providerId: string;
707
- readonly capabilityId: string;
708
- readonly attemptNumber: number;
1119
+ /**
1120
+ * Phase 7 addition: emitted by the runtime when no candidate route can
1121
+ * satisfy the caller-supplied `CapabilityContract` (budget, modality,
1122
+ * privacy, or quality-floor invariants).
1123
+ *
1124
+ * `noRouteReasons` carries the full deterministic-router rejection list
1125
+ * so callers can inspect per-candidate detail. Phase 9 (receipts) will
1126
+ * persist this array for deterministic verdict reconstruction.
1127
+ */
1128
+ interface NoContractMatchError {
1129
+ readonly kind: "no-contract-match";
1130
+ readonly message: string;
1131
+ readonly noRouteReasons: readonly RouteRejectReason[];
709
1132
  }
710
- interface ReceiptRedaction {
711
- readonly path: string;
712
- readonly reason: string;
1133
+ /**
1134
+ * Phase 8 addition: emitted when a `CapabilityContract.invariants` tripwire
1135
+ * fires after the provider returned a schema-valid output. Carries the
1136
+ * `TripwireEvidence` produced by `evaluateTripwires`.
1137
+ *
1138
+ * `terminal: true` is a structural marker — combined with the `isTerminal()`
1139
+ * predicate it tells the fallback chain in `runWithConfig` to refuse retry.
1140
+ * `NoContractMatchError` does NOT carry the field (to avoid breaking Phase 7
1141
+ * callers) but `isTerminal()` still returns true for it via the kind check.
1142
+ */
1143
+ interface TripwireViolationError {
1144
+ readonly kind: "tripwire-violated";
1145
+ readonly message: string;
1146
+ readonly invariantId: string;
1147
+ readonly evidence: TripwireEvidence;
1148
+ readonly terminal: true;
713
1149
  }
714
- interface CapabilityReceiptBody {
715
- readonly version: "lattice-receipt/v1" | "lattice-receipt/v1.1";
716
- readonly receiptId: string;
717
- readonly runId: string;
718
- readonly issuedAt: string;
719
- readonly kid: string;
720
- readonly model: ReceiptModel;
721
- readonly route: ReceiptRoute;
722
- readonly usage: ReceiptUsageCanonical;
723
- readonly contractVerdict: ContractVerdict;
724
- readonly contractHash: string | null;
725
- readonly inputHashes: readonly string[];
726
- readonly outputHash: string | null;
727
- readonly redactionPolicyId: string;
728
- readonly redactions: readonly ReceiptRedaction[];
729
- readonly noRouteReasons?: readonly RouteRejectReason[];
730
- readonly tripwireEvidence?: TripwireEvidence;
731
- readonly stepName?: string;
732
- readonly stepIndex?: number;
733
- readonly parentStepName?: string;
734
- readonly previousStepName?: string;
735
- readonly sessionId?: string;
736
- readonly timestamp?: string;
1150
+ type LatticeRunError = ValidationError | ExecutionUnavailableError | NoRouteError | ProviderExecutionError | TimeoutError | NoContractMatchError | TripwireViolationError;
1151
+ /**
1152
+ * Returns `true` for run errors that MUST NOT be retried by the fallback
1153
+ * chain. Phase 8 covers two kinds:
1154
+ *
1155
+ * - `tripwire-violated` — the contract's invariants rejected the output;
1156
+ * a different provider will not change the verdict, so retry burns
1157
+ * budget for no gain (T-08-06 in 08-02-PLAN threat register).
1158
+ * - `no-contract-match` — no route satisfies the contract at all; the
1159
+ * run never executed and no retry will help.
1160
+ *
1161
+ * All other error kinds return `false` and remain eligible for fallback.
1162
+ * The predicate is exported so Phase 12's eval gate and any user-side
1163
+ * retry wrappers can share one source of truth.
1164
+ */
1165
+ declare function isTerminal(error: LatticeRunError): boolean;
1166
+ //#endregion
1167
+ //#region src/agent/types.d.ts
1168
+ /**
1169
+ * Per-iteration record stored on `AgentSuccess.iterations` for inspectability.
1170
+ *
1171
+ * `toolCalls` carries content-addressed args/result hashes (sha256) so
1172
+ * downstream receipts can reference them without inlining the bodies.
1173
+ *
1174
+ * `deniedReason` is populated on iterations whose `BEFORE_AGENT_ITERATION`
1175
+ * SAFETY-band handler set `controls.deny(...)`.
1176
+ */
1177
+ interface IterationRecord {
1178
+ readonly index: number;
1179
+ readonly provider: string;
1180
+ readonly promptTokens: number;
1181
+ readonly completionTokens: number;
1182
+ readonly costUsd: number | null;
1183
+ readonly durationMs: number;
1184
+ readonly toolCalls: ReadonlyArray<{
1185
+ readonly id: string;
1186
+ readonly name: string;
1187
+ readonly argsHash: string;
1188
+ readonly resultHash: string;
1189
+ }>;
1190
+ readonly deniedReason?: string;
1191
+ readonly receipt?: ReceiptEnvelope;
737
1192
  }
738
- interface ReceiptSignature {
739
- readonly keyid: string;
740
- readonly sig: string;
1193
+ /**
1194
+ * Input shape accepted by `ai.runAgent(intent)`.
1195
+ *
1196
+ * All fields except `task` and `tools` are optional. The runtime supplies
1197
+ * sensible defaults (in-process host, fresh pipeline, no signer, no tracer).
1198
+ *
1199
+ * `TOutputs` parameterizes the final-answer schema map; defaults to a free-form
1200
+ * `{ answer: "text" }` shape when the field is omitted. Validation runs once
1201
+ * against the final assistant message (no intermediate iteration validation).
1202
+ */
1203
+ interface AgentIntent<TOutputs extends OutputContractMap = OutputContractMap> {
1204
+ readonly task: string;
1205
+ readonly tools: ReadonlyArray<ToolDefinition<StandardSchemaV1>>;
1206
+ readonly host?: AgentHost;
1207
+ /**
1208
+ * Phase 20 (v1.2): when the agent loop resumes from a host.storage snapshot,
1209
+ * the configured SurvivabilityAdapter handles the serialize/deserialize
1210
+ * round-trip. When absent, runtime defaults to
1211
+ * `createNoopSurvivabilityAdapter<AgentSnapshot>()`.
1212
+ */
1213
+ readonly survivabilityAdapter?: SurvivabilityAdapter<AgentSnapshot>;
1214
+ readonly contract?: CapabilityContract;
1215
+ readonly policy?: PolicySpec;
1216
+ readonly outputs?: TOutputs;
1217
+ readonly pipeline?: HookPipeline;
1218
+ readonly signer?: ReceiptSigner;
1219
+ readonly tracer?: TracerLike;
1220
+ /**
1221
+ * When `false`, the runtime will NOT auto-register `createCheckpointHook`
1222
+ * even if `signer` is provided. Callers who want full manual control over
1223
+ * receipt minting set this to `false` and register their own hook.
1224
+ * Defaults to `true` (auto-register when signer present).
1225
+ */
1226
+ readonly autoRegisterCheckpoint?: boolean;
741
1227
  }
742
- interface ReceiptEnvelope {
743
- readonly payloadType: "application/vnd.lattice.receipt+json";
744
- readonly payload: string;
745
- readonly signatures: readonly ReceiptSignature[];
1228
+ /**
1229
+ * Success result returned by `ai.runAgent` when the loop reaches a final
1230
+ * answer and (when `outputs` is declared) the final answer validates.
1231
+ *
1232
+ * `iterations[]` records every iteration that ran — including the one that
1233
+ * produced the final answer. `receipt` is the outermost receipt minted at
1234
+ * loop close when `signer` is configured (separate from per-iteration
1235
+ * receipts on `iterations[i].receipt`).
1236
+ */
1237
+ interface AgentSuccess<TOutputs extends OutputContractMap = OutputContractMap> {
1238
+ readonly kind: "success";
1239
+ readonly output: InferOutputMap<TOutputs>;
1240
+ readonly usage: Usage;
1241
+ readonly iterations: ReadonlyArray<IterationRecord>;
1242
+ readonly receipt?: ReceiptEnvelope;
746
1243
  }
747
- interface ReceiptSigner {
748
- readonly kid: string;
749
- sign(bytes: Uint8Array): Promise<Uint8Array>;
750
- readonly publicKeyJwk: JsonWebKey;
1244
+ /**
1245
+ * Failure kinds specific to the agent loop. v1.1 `LatticeRunError.kind`
1246
+ * values remain valid (provider errors, no-contract-match, validation-failed,
1247
+ * tripwire-violated) and are reused verbatim. Phase 19 adds three
1248
+ * agent-specific kinds. Phase 39 (v1.3) adds `crew-budget-exceeded` —
1249
+ * crew-level shared-pool exhaustion, terminal across the parent/child
1250
+ * boundary (D-10).
1251
+ */
1252
+ type AgentFailureKind = LatticeRunError["kind"] | "agent-iteration-denied" | "agent-max-iterations" | "agent-wall-time-exceeded" | "crew-budget-exceeded";
1253
+ /**
1254
+ * Failure result returned by `ai.runAgent`. Discriminates via `kind`.
1255
+ *
1256
+ * `iterations[]` carries any iterations that completed before the failure
1257
+ * (empty if the failure occurred pre-iteration). For `agent-iteration-denied`,
1258
+ * the failing iteration is the LAST entry and carries `deniedReason`.
1259
+ */
1260
+ interface AgentFailure {
1261
+ readonly kind: AgentFailureKind;
1262
+ readonly usage: Usage;
1263
+ readonly iterations: ReadonlyArray<IterationRecord>;
1264
+ readonly reason?: string;
1265
+ readonly cause?: unknown;
1266
+ readonly receipt?: ReceiptEnvelope;
751
1267
  }
752
- type KeyState = "active" | "retired" | "revoked";
753
- interface KeyEntry {
754
- readonly kid: string;
755
- readonly publicKeyJwk: JsonWebKey;
756
- readonly state: KeyState;
1268
+ /**
1269
+ * Discriminated union returned by `ai.runAgent`.
1270
+ */
1271
+ type AgentResult<TOutputs extends OutputContractMap = OutputContractMap> = AgentSuccess<TOutputs> | AgentFailure;
1272
+ /**
1273
+ * Typed error raised when a SAFETY-band handler sets `controls.deny(reason)`
1274
+ * during `BEFORE_AGENT_ITERATION`. Carries `terminal: true` semantics to
1275
+ * align with v1.1 `TripwireViolationError`: the failure is NOT retried by
1276
+ * the fallback chain.
1277
+ *
1278
+ * Surfaced via `AgentFailure { kind: "agent-iteration-denied", reason, ... }`
1279
+ * — callers can also catch the typed error if they prefer.
1280
+ */
1281
+ declare class AgentDeniedError extends Error {
1282
+ readonly kind: "agent-iteration-denied";
1283
+ readonly terminal: true;
1284
+ readonly reason: string;
1285
+ readonly iterationIndex: number;
1286
+ constructor(reason: string, iterationIndex: number);
757
1287
  }
758
- interface KeySet {
759
- lookup(kid: string): KeyEntry | undefined;
1288
+ /**
1289
+ * Returned by `formatToolsForProvider` (Phase 19 Plan 19-03). Re-exported
1290
+ * here for convenience; the canonical declaration lives in format-tools.ts.
1291
+ */
1292
+ interface ToolUseRequest {
1293
+ readonly id: string;
1294
+ readonly name: string;
1295
+ readonly args: unknown;
760
1296
  }
761
- type VerifyErrorKind = "key-not-found" | "key-revoked" | "canonicalization-mismatch" | "signature-invalid" | "envelope-malformed" | "version-mismatch" | "schema-version-too-low";
762
- interface VerifyError {
763
- readonly kind: VerifyErrorKind;
764
- readonly message: string;
1297
+ //#endregion
1298
+ //#region src/tools/tool-call-validation.d.ts
1299
+ type ToolCallValidationFailureReason = "unknown_tool" | "invalid_args" | "extra_fields";
1300
+ interface ValidatedToolCall {
1301
+ readonly id: string;
1302
+ readonly name: string;
1303
+ readonly args: unknown;
765
1304
  }
766
- interface VerifyOk {
767
- readonly ok: true;
768
- readonly body: CapabilityReceiptBody;
769
- readonly keyState: KeyState;
1305
+ type ToolCallValidationTool = Pick<ToolDefinition, "name" | "inputSchema">;
1306
+ interface ValidateToolCallsOption {
1307
+ readonly tools: readonly ToolCallValidationTool[];
1308
+ readonly onFailure?: "throw" | "drop" | "callback";
1309
+ readonly onValidationFailure?: (error: ToolCallValidationError) => void | Promise<void>;
1310
+ readonly allowExtraFields?: boolean;
770
1311
  }
771
- interface VerifyFail {
772
- readonly ok: false;
773
- readonly error: VerifyError;
1312
+ declare class ToolCallValidationError extends Error {
1313
+ readonly kind: "tool-call-validation";
1314
+ readonly reason: ToolCallValidationFailureReason;
1315
+ readonly toolName: string;
1316
+ readonly attemptedArgs: unknown;
1317
+ readonly validationIssues: readonly ValidationIssue[];
1318
+ readonly requestId: string;
1319
+ constructor(input: {
1320
+ readonly reason: ToolCallValidationFailureReason;
1321
+ readonly toolName: string;
1322
+ readonly attemptedArgs: unknown;
1323
+ readonly validationIssues?: readonly ValidationIssue[];
1324
+ readonly requestId: string;
1325
+ });
774
1326
  }
775
- type VerifyResult = VerifyOk | VerifyFail;
776
1327
  //#endregion
777
- //#region src/receipts/receipt.d.ts
1328
+ //#region src/providers/quirks.d.ts
778
1329
  /**
779
- * Public input to createReceipt. Mirrors CapabilityReceiptBody minus:
780
- * - `version` (forced to "lattice-receipt/v1.1" per CRYPTO-01)
781
- * - `kid` (forced from signer.kid — caller cannot mismatch)
782
- * - `redactions[]` (populated by redactReceiptBody)
783
- * - `usage.costUsd` (converted to canonical string by usageToCanonical)
1330
+ * Universal 5-boolean shape every first-party adapter populates (SC-1 / D-03).
784
1331
  *
785
- * receiptId and issuedAt default to runtime-generated values when omitted.
786
- * redactionPolicyId defaults to DEFAULT_REDACTION_POLICY_ID.
1332
+ * - `supportsToolChoice` — adapter supports tool_choice / forced-tool-call mode
1333
+ * - `parallelToolCalls` — adapter supports parallel (multi-tool) calls in one turn
1334
+ * - `structuredOutputs` — adapter honors response_format JSON schema binding
1335
+ * - `responseFormatHonored` — adapter treats response_format as authoritative (false
1336
+ * for vanilla openai-compat servers; true for OpenAI/Anthropic/Gemini)
1337
+ * - `streamingDiverges` — streamed output differs from buffered output (true for
1338
+ * some self-hosted servers; false for OpenAI/Anthropic/Gemini)
787
1339
  */
788
- interface CreateReceiptInput {
789
- readonly runId: string;
790
- readonly issuedAt?: string;
791
- readonly receiptId?: string;
792
- readonly model: ReceiptModel;
793
- readonly route: ReceiptRoute;
794
- readonly usage: Usage;
795
- readonly contractVerdict: ContractVerdict;
796
- readonly contractHash: string | null;
797
- readonly inputHashes: readonly string[];
798
- readonly outputHash: string | null;
799
- readonly redactionPolicyId?: string;
800
- readonly noRouteReasons?: readonly RouteRejectReason[];
801
- readonly tripwireEvidence?: TripwireEvidence;
802
- readonly stepName?: string;
803
- readonly stepIndex?: number;
804
- readonly parentStepName?: string;
805
- readonly previousStepName?: string;
806
- readonly sessionId?: string;
807
- readonly timestamp?: string;
1340
+ interface AdapterQuirks {
1341
+ readonly supportsToolChoice: boolean;
1342
+ readonly parallelToolCalls: boolean;
1343
+ readonly structuredOutputs: boolean;
1344
+ readonly responseFormatHonored: boolean;
1345
+ readonly streamingDiverges: boolean;
808
1346
  }
809
1347
  /**
810
- * Build, redact, canonicalize, sign, and envelope a CapabilityReceipt.
811
- *
812
- * Ordering INVARIANT (09-CONTEXT.md, PITFALLS.md Pitfall #1):
813
- * redact -> canonicalize -> PAE -> sign -> encode
1348
+ * Anthropic adapter quirks (extends AdapterQuirks with 3 Anthropic-specific flags).
814
1349
  *
815
- * The signed digest commits to canonicalize(redact(body)). The function
816
- * structure makes any other ordering impossible to write by accident —
817
- * canonicalizeReceiptBody is ONLY called on the output of redactReceiptBody.
1350
+ * CITED: Anthropic prompt caching docs — https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching
1351
+ * - `promptCachingSupported`: cache_control on system and user turns is supported on
1352
+ * all active Claude models (claude-3-* and claude-*-4 families).
818
1353
  *
819
- * Defense in depth:
820
- * - body.kid is assigned from signer.kid, never from input (input has no
821
- * kid field). The signed body and the envelope keyid CANNOT disagree by
822
- * construction.
823
- * - signer.kid is also written to envelope.signatures[0].keyid, so the
824
- * verifier can cross-check (Step 7 of verifyReceipt).
1354
+ * CITED: Anthropic extended thinking docs — https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking
1355
+ * - `extendedThinkingSupported`: thinking blocks (claude-3-7-sonnet+ and claude-*-4) available
1356
+ * via the "thinking" request parameter.
825
1357
  *
826
- * I-JSON guarantees: usage.costUsd is converted to string (or null) via
827
- * usageToCanonical. Receipts NEVER carry raw floats in the canonical form.
1358
+ * CITED: Anthropic tool use docs https://docs.anthropic.com/en/docs/build-with-claude/tool-use
1359
+ * - `toolUseInputSchemaStrict`: Anthropic tool_use blocks require strict JSON Schema in
1360
+ * the input_schema field; the adapter enforces this at call time.
828
1361
  */
829
- declare function createReceipt(input: CreateReceiptInput, signer: ReceiptSigner): Promise<ReceiptEnvelope>;
830
- //#endregion
831
- //#region src/contract/checkpoint.d.ts
1362
+ interface AnthropicQuirks extends AdapterQuirks {
1363
+ readonly promptCachingSupported: boolean;
1364
+ readonly extendedThinkingSupported: boolean;
1365
+ readonly toolUseInputSchemaStrict: boolean;
1366
+ }
832
1367
  /**
833
- * The tracer event name Lattice's checkpoint hook emits per step transition.
834
- * Identical to the literal added to RunEventKind in tracing.ts.
1368
+ * OpenAI adapter quirks (extends AdapterQuirks with 2 OpenAI-specific flags).
1369
+ *
1370
+ * CITED: OpenAI structured outputs docs — https://platform.openai.com/docs/guides/structured-outputs
1371
+ * - `strictModeSupported`: function-calling strict:true mode available on
1372
+ * gpt-4o-2024-08-06+ and o1+ series.
1373
+ * - `structuredOutputsTier2`: json_schema response_format mode (tier-2 structured outputs)
1374
+ * available on gpt-4o and gpt-4o-mini series.
835
1375
  */
836
- declare const STEP_TRANSITION_EVENT_NAME: "step.transition";
1376
+ interface OpenAIQuirks extends AdapterQuirks {
1377
+ readonly strictModeSupported: boolean;
1378
+ readonly structuredOutputsTier2: boolean;
1379
+ }
837
1380
  /**
838
- * Default band convention for the checkpoint hook (D-06). The caller is
839
- * free to register in a different band but the documented convention is
840
- * OBSERVABILITY -- between SAFETY (runs first) and EXTENSION (runs last).
1381
+ * OpenAI-compatible adapter quirks (same 5 base booleans, no new fields).
1382
+ *
1383
+ * Conservative defaults: openai-compat servers (vLLM, TGI, Ollama, custom)
1384
+ * vary widely in which response_format and tool_choice features they implement.
1385
+ * The factory populates the base fields conservatively (responseFormatHonored:
1386
+ * false, structuredOutputs: false) because the endpoint could be anything.
1387
+ * Consumers pointing at a known-good server should verify quirk values manually.
841
1388
  */
842
- declare const DEFAULT_CHECKPOINT_BAND: Band;
1389
+ interface OpenAICompatQuirks extends AdapterQuirks {}
843
1390
  /**
844
- * Per-step context the caller passes through the hook pipeline.
1391
+ * Gemini adapter quirks (extends AdapterQuirks with 3 Gemini-specific flags).
845
1392
  *
846
- * Fields are stable identifiers (D-04 carryforward); do NOT populate with
847
- * user content -- they appear cleartext in the signed receipt body.
1393
+ * CITED: Gemini API docs — https://ai.google.dev/api/generate-content#v1beta.GenerationConfig
1394
+ * - `responseSchemaSupported`: responseSchema / responseJsonSchema on generateContent
1395
+ * is available on gemini-1.5-pro+ and gemini-2.x models.
1396
+ * - `safetySettingsConfigurable`: all 4 harm categories (HARASSMENT, HATE_SPEECH,
1397
+ * SEXUALLY_EXPLICIT, DANGEROUS_CONTENT) can be set to BLOCK_NONE — verified in
1398
+ * gemini.ts:50-55.
848
1399
  *
849
- * - stepName: required. Stable identifier for this step.
850
- * - stepIndex: required. Monotonically increasing ordinal; caller-owned.
851
- * - parentStepName: optional. Names the enclosing step when nested.
852
- * - previousStepName: optional. Names the immediately-prior step in the
853
- * linked-list timeline (D-09 linked-list threading).
854
- * - timestamp: required. ISO-8601 RFC 3339.
1400
+ * CITED: Gemini API system instruction docs — https://ai.google.dev/api/generate-content#v1beta.GenerateContentRequest
1401
+ * - `systemInstructionSupported`: systemInstruction field on GenerateContentRequest
1402
+ * available on gemini-1.5+ series and later.
855
1403
  */
856
- interface CheckpointHookContext {
857
- readonly stepName: string;
858
- readonly stepIndex: number;
859
- readonly parentStepName?: string;
860
- readonly previousStepName?: string;
861
- readonly timestamp: string;
1404
+ interface GeminiQuirks extends AdapterQuirks {
1405
+ readonly responseSchemaSupported: boolean;
1406
+ readonly safetySettingsConfigurable: boolean;
1407
+ readonly systemInstructionSupported: boolean;
862
1408
  }
863
1409
  /**
864
- * The factory's options.
1410
+ * xAI adapter quirks (extends AdapterQuirks with 2 xAI-specific flags).
865
1411
  *
866
- * - runId: required. Threaded into every receipt body + every tracer event.
867
- * - tracer: optional. When omitted, the handler still mints (when signer
868
- * present) but does NOT emit a tracer event. When provided, the handler
869
- * ALWAYS emits exactly one event per invocation (independent of mint
870
- * success/failure per D-10).
871
- * - signer: optional. When omitted, the handler emits a tracer event only
872
- * (no mint attempted). When provided, the handler attempts to mint via
873
- * createReceipt(...) inside a try/catch (D-07 best-effort).
874
- * - sessionId: optional. Threaded into receipt body and event metadata.
875
- * - model: optional. ReceiptModel descriptor for the receipt body; the
876
- * factory provides a sensible "step" default when omitted.
877
- * - route: optional. ReceiptRoute descriptor for the receipt body; the
878
- * factory provides a sensible "step" default when omitted.
879
- * - contractVerdict: optional. Defaults to "success" -- step transitions
880
- * are observability events, not contract evaluations.
1412
+ * CITED: xAI API docs https://docs.x.ai/api/endpoints
1413
+ * - `reasoningTokensReported`: completion_tokens_details.reasoning_tokens reported
1414
+ * in xAI API responses verified in xai.ts:46-72.
1415
+ * - `logprobsSupported`: grok-4.20 silently ignores logprobs param per observed
1416
+ * behavior; flag indicates whether logprobs fields will be populated.
881
1417
  */
882
- interface CheckpointHookOptions {
883
- readonly runId: string;
884
- readonly tracer?: TracerLike;
885
- readonly signer?: ReceiptSigner;
886
- readonly sessionId?: string;
887
- readonly model?: ReceiptModel;
888
- readonly route?: ReceiptRoute;
889
- readonly contractVerdict?: CreateReceiptInput["contractVerdict"];
1418
+ interface XaiQuirks extends AdapterQuirks {
1419
+ readonly reasoningTokensReported: boolean;
1420
+ readonly logprobsSupported: boolean;
890
1421
  }
891
1422
  /**
892
- * Build a checkpoint hook handler.
1423
+ * OpenRouter adapter quirks (extends AdapterQuirks with 3 OpenRouter-specific flags).
893
1424
  *
894
- * The returned handler is suitable for registration on a HookPipeline
895
- * created via createHookPipeline (see ./bands.ts). The handler does not
896
- * auto-register; the caller passes it to pipeline.register(...) with the
897
- * desired lifecycle event (typically AFTER_TOOL or BEFORE_TOOL) and band
898
- * (typically BAND.OBSERVABILITY, exported as DEFAULT_CHECKPOINT_BAND).
899
- *
900
- * Per-invocation behavior:
901
- * 1. Build event metadata from options + per-call context.
902
- * 2. If signer is configured, attempt createReceipt(...) inside a
903
- * try/catch. On success, set metadata.receiptId + metadata.envelope.
904
- * On failure, set metadata.mintError (string from caught error).
905
- * 3. If tracer is configured, emit exactly one tracer.event?.(
906
- * STEP_TRANSITION_EVENT_NAME, metadata) call.
907
- * 4. Return void.
908
- *
909
- * NO upstream throw (D-07). NO global mutation (D-05).
1425
+ * CITED: OpenRouter provider routing docs https://openrouter.ai/docs/provider-routing
1426
+ * - `providerRoutingArraySupported`: the `provider.order` / `provider.only` /
1427
+ * `provider.ignore` arrays are supported for explicit routing control.
1428
+ * - `floorPricingHints`: `max_price`, `sort: "throughput" | "price"` hints on
1429
+ * GenerationConfig for cost-aware routing.
1430
+ * - `allowFallbacks`: `provider.allow_fallbacks: boolean` controls whether OpenRouter
1431
+ * retries with a different upstream provider on failure.
910
1432
  */
911
- declare function createCheckpointHook(options: CheckpointHookOptions): HookHandler<CheckpointHookContext>;
912
- //#endregion
913
- //#region src/contract/contract.d.ts
1433
+ interface OpenRouterQuirks extends AdapterQuirks {
1434
+ readonly providerRoutingArraySupported: boolean;
1435
+ readonly floorPricingHints: boolean;
1436
+ readonly allowFallbacks: boolean;
1437
+ }
914
1438
  /**
915
- * Budget invariant declaration attached to a CapabilityContract.
1439
+ * LM Studio adapter quirks (extends AdapterQuirks with 2 LM Studio-specific flags).
916
1440
  *
917
- * Phase 7 implements `maxCostUsd` enforcement at pre-flight. The
918
- * `p95LatencyMs` field is declared per CONTRACT-02 but is informational
919
- * only in Phase 7 latency observations are wired in a later phase.
1441
+ * CITED: lmstudio-bug-tracker Jinja template mismatches between model training and
1442
+ * LM Studio server defaults cause output format corruption.
1443
+ * - `customChatTemplateRiskFlag`: LM Studio servers can ship with broken chat templates
1444
+ * that don't match the model's training template; flag signals this risk.
920
1445
  *
921
- * Phase 19 (v1.2) adds `maxIterations` and `maxWallTimeMs` for the agent
922
- * runtime. Both are additive and optional; non-agent callers ignore them.
923
- * `maxIterations` caps the number of `runAgent` iterations; `maxWallTimeMs`
924
- * caps wall-clock duration per `runAgent` invocation. Both are enforced
925
- * pre-iteration in the agent loop.
1446
+ * VERIFIED: lm-studio.ts:35-37 apiKey is optional for LM Studio local servers.
1447
+ * - `noAuthRequired`: apiKey is NOT required for local LM Studio instances (no
1448
+ * authentication by default on localhost:1234).
926
1449
  */
927
- interface BudgetInvariant {
928
- readonly maxCostUsd?: number;
929
- readonly maxIterations?: number;
930
- readonly maxWallTimeMs?: number;
931
- readonly p95LatencyMs?: number;
1450
+ interface LmStudioQuirks extends AdapterQuirks {
1451
+ readonly customChatTemplateRiskFlag: boolean;
1452
+ readonly noAuthRequired: boolean;
932
1453
  }
1454
+ //#endregion
1455
+ //#region src/capabilities/sanitizer-recommendations.d.ts
933
1456
  /**
934
- * Quality-floor invariant.
1457
+ * D-13 — Phase 36 sanitizer registration keys. Closed string-literal union;
1458
+ * adding a 4th sanitizer in v1.4 is an intentional typed breaking change
1459
+ * that mirrors the `KnownFailureMode` discipline.
935
1460
  *
936
- * `suite` is a fixture-directory path string; `minScore` is in 0..1.
937
- * Phase 7 forwards this into the pre-flight evaluator but only enforces
938
- * capability-side rejects. Full enforcement lives in Phase 12 (`lattice eval`).
1461
+ * Phase 36 registers implementations under EXACTLY these 3 ids:
1462
+ * - "stripReasoningTags" — strips <think>/</think> (and model-specific) reasoning tags
1463
+ * - "stripChatTemplateArtifacts" — removes chat-template artifact leaks from output
1464
+ * - "unwrapInternalEnvelope" — extracts the user-visible payload from internal wrapper
939
1465
  */
940
- interface QualityFloorInvariant {
941
- readonly suite: string;
942
- readonly minScore: number;
943
- }
1466
+ type SanitizerKey = "stripReasoningTags" | "stripChatTemplateArtifacts" | "unwrapInternalEnvelope";
944
1467
  /**
945
- * The full Capability Contract attached to `RunIntent.contract`.
1468
+ * D-14 + D-16 Exhaustive mapping from KnownFailureMode to SanitizerKey
1469
+ * (or null when the failure mode is not a sanitizer concern). The
1470
+ * `Record<KnownFailureMode, ...>` annotation enforces compile-time
1471
+ * exhaustiveness — adding a new mode to KnownFailureMode in v1.4+ will
1472
+ * cause a type-check failure here until the planner decides on a mapping.
946
1473
  *
947
- * All fields are optional. v1.0 callers compile and run unchanged when
948
- * the field is omitted entirely. PROJECT.md explicitly rejects mandatory
949
- * contracts.
1474
+ * Null semantics per D-16:
1475
+ * - system_prompt_echo -> null (consumer-side prompt engineering, not a sanitizer)
1476
+ * - hallucinated_tool_name -> null (Phase 37 tool-call validator territory)
1477
+ * - malformed_tool_arguments -> null (Phase 37 tool-call validator territory)
1478
+ * - premature_termination -> null (consumer-side max_tokens config)
950
1479
  */
951
- interface CapabilityContract {
952
- readonly kind: "capability-contract";
953
- readonly budget?: BudgetInvariant;
954
- readonly invariants?: readonly InvariantDeclaration[];
955
- readonly qualityFloor?: QualityFloorInvariant;
956
- readonly requiredModalities?: readonly CapabilityModality[];
957
- readonly requiredPrivacy?: "standard" | "sensitive" | "restricted";
958
- }
1480
+ declare const SANITIZER_BY_FAILURE_MODE: Record<KnownFailureMode, SanitizerKey | null>;
959
1481
  /**
960
- * Reject-reason taxonomy added to `RouteRejectReason.code` by Phase 7's
961
- * pre-flight evaluator. Closed four-value union per the locked decisions
962
- * in 07-CONTEXT.md.
963
- */
964
- type ContractRejectReasonCode = "contract-budget-exceeded" | "contract-quality-floor" | "contract-modality-missing" | "contract-privacy-mismatch";
965
- /** Input shape accepted by `contract()`. Mirrors `CapabilityContract` minus `kind`. */
966
- interface CapabilityContractInput {
967
- readonly budget?: BudgetInvariant;
968
- readonly invariants?: readonly InvariantDeclaration[];
969
- readonly qualityFloor?: QualityFloorInvariant;
970
- readonly requiredModalities?: readonly CapabilityModality[];
971
- readonly requiredPrivacy?: "standard" | "sensitive" | "restricted";
972
- }
973
- /**
974
- * Factory for `CapabilityContract` values.
1482
+ * D-14 / D-15 Maps a list of known failure modes through the recommendation
1483
+ * table and filters nulls. `recommendedSanitizers` always contains real keys.
975
1484
  *
976
- * Mirrors the `output()` and adapter factory style — exact-optional safe
977
- * (does not emit `field: undefined` properties under `exactOptionalPropertyTypes`).
978
- * Returns a frozen value with frozen nested objects so downstream code can
979
- * rely on structural immutability when canonicalizing in Phase 9.
980
- */
981
- declare function contract(input?: CapabilityContractInput): CapabilityContract;
982
- //#endregion
983
- //#region src/contract/preflight.d.ts
984
- /**
985
- * Result of a single pre-flight contract evaluation against a candidate
986
- * capability. `reasons` is empty when `ok` is true and contains one or more
987
- * `RouteRejectReason` entries when `ok` is false.
1485
+ * Implementation:
1486
+ * - Iterates modes in input order (Set insertion order)
1487
+ * - Skips null entries (D-16)
1488
+ * - Deduplicates via Set (so repeated modes yield one key)
1489
+ * - Returns a readonly array (frozen via spread)
988
1490
  *
989
- * The evaluator surfaces ALL failing reasons in a single pass — not the
990
- * first-failing only so the deterministic router can aggregate per-candidate
991
- * rejection detail (CONTEXT.md "Pre-flight surfaces ALL failed candidates
992
- * with per-candidate rejection reasons").
993
- */
994
- interface ContractPreflightResult {
995
- readonly ok: boolean;
996
- readonly reasons: readonly RouteRejectReason[];
997
- }
998
- /**
999
- * Input for the pure cost estimator. Token counts come from the router's
1000
- * existing `estimateRoute()` helper so preflight and router agree on the
1001
- * projected output size (one source of truth — see `evaluateContractAgainstRoute`).
1491
+ * Consumers use this to populate `NegotiatedCapabilities.recommendedSanitizers`.
1492
+ * Phase 36 registers implementations under the same key ids.
1002
1493
  */
1003
- interface EstimateRouteCostInput {
1004
- readonly capability: ModelCapability;
1005
- readonly estimatedInputTokens: number;
1006
- readonly estimatedOutputTokens: number;
1494
+ declare function getRecommendedSanitizers(modes: readonly KnownFailureMode[]): readonly SanitizerKey[];
1495
+ //#endregion
1496
+ //#region src/capabilities/negotiate.d.ts
1497
+ /**
1498
+ * Phase 34 — SC-3 — Consumer-facing capability shape returned by
1499
+ * `adapter.negotiateCapabilities()` and the top-level `negotiateCapabilities()`
1500
+ * helper. Simplified relative to `ModelCapabilityProfile` (the registry
1501
+ * profile); consumers needing the full enum (e.g., native_strict vs
1502
+ * native_lenient) should look up the profile directly via `getCapabilityProfile`.
1503
+ *
1504
+ * Source values (D-09):
1505
+ * - "live" — /models endpoint hit, registry profile intersected
1506
+ * - "registry-fallback" — /models hit failed transiently (5xx/network/timeout),
1507
+ * fell back to Phase 33 static registry (D-09)
1508
+ * - "registry" — adapter intentionally has no /models endpoint
1509
+ * (LM Studio, openai-compat), OR consumer-adapter
1510
+ * fallback path (D-04)
1511
+ */
1512
+ interface NegotiatedCapabilities {
1513
+ readonly modelId: string;
1514
+ readonly contextWindow: number;
1515
+ readonly supports: {
1516
+ readonly nativeToolCalling: boolean;
1517
+ readonly structuredOutputs: boolean;
1518
+ readonly parallelToolCalls: boolean;
1519
+ readonly extendedThinking: boolean;
1520
+ readonly streaming: boolean;
1521
+ };
1522
+ readonly knownFailureModes: readonly KnownFailureMode[];
1523
+ readonly recommendedSanitizers: readonly SanitizerKey[];
1524
+ readonly source: "live" | "registry-fallback" | "registry";
1007
1525
  }
1008
1526
  /**
1009
- * Pure cost estimator. Returns `null` when pricing is unknown (so downstream
1010
- * gates can distinguish "free / zero" from "unmeasured" per the Phase 7
1011
- * cost-normalization decision). Uses static catalog metadata only no probes,
1012
- * no external pricing APIs.
1527
+ * D-10 Typed error thrown by `negotiateCapabilities` when the adapter's
1528
+ * /models endpoint returns 401 or 403. Mirrors `AgentDeniedError` shape
1529
+ * (the only existing v1.2 `class extends Error` precedent in agent/types.ts).
1530
+ *
1531
+ * Why throw (vs return-as-error-union):
1532
+ * - Auth errors indicate a broken apiKey config — it is the caller's bug
1533
+ * - Silently falling back would hide the misconfiguration
1534
+ * - `try/catch` ergonomics work cleanly with `class extends Error`
1535
+ * - `instanceof NegotiationAuthError` is the consumer ergonomic
1536
+ *
1537
+ * IMPORTANT: `NegotiationAuthError` is throwable from `negotiateCapabilities`
1538
+ * ONLY — never from `execute()`. Auth errors from /models do NOT contaminate
1539
+ * the request path.
1540
+ *
1541
+ * T-34-01-02: message field set by adapter implementations in Plans 02-04
1542
+ * MUST NOT include the apiKey. Only adapter, modelId, and httpStatus are carried.
1013
1543
  */
1014
- declare function estimateRouteCost(input: EstimateRouteCostInput): number | null;
1015
- /** Input for the pre-flight evaluator. */
1016
- interface EvaluateContractInput {
1017
- readonly capability: ModelCapability;
1018
- readonly estimatedInputTokens: number;
1019
- readonly estimatedOutputTokens: number;
1544
+ declare class NegotiationAuthError extends Error {
1545
+ readonly kind: "negotiation-auth-failed";
1546
+ readonly adapter: CapabilityAdapter;
1547
+ readonly modelId: string;
1548
+ readonly httpStatus: 401 | 403;
1549
+ constructor(adapter: CapabilityAdapter, modelId: string, httpStatus: 401 | 403, message: string);
1020
1550
  }
1021
1551
  /**
1022
- * Pure pre-flight evaluator. Phase 9 receipts will reuse this for deterministic
1023
- * verdict reconstruction.
1552
+ * Phase 34 D-02 / D-04 Top-level helper for capability negotiation.
1024
1553
  *
1025
- * Token estimation: Phase 7 does NOT define a separate token estimator. Output-
1026
- * token projection is the canonical responsibility of the router's existing
1027
- * `estimateRoute()` helper (in `routing/router.ts`), which already produces an
1028
- * `estimatedOutputTokens` value. The router passes that same value into this
1029
- * evaluator via `EvaluateContractInput.estimatedOutputTokens`, so preflight
1030
- * and the router always agree on the projected output size. Phase 9 receipts
1031
- * will pin the router's estimate as the deterministic input — intentionally
1032
- * one source of truth.
1554
+ * Pitfall 5 (zero live-path logic): delegates verbatim to
1555
+ * `adapter.negotiateCapabilities(modelId)` when the adapter implements it.
1556
+ * No inflight-coalescing, no cache, no source value transformation. The
1557
+ * adapter owns all of that.
1033
1558
  *
1034
- * Reject taxonomy (Phase 7 emits three of four codes):
1035
- * - `contract-budget-exceeded` (CONTRACT-04 + COST-03)
1036
- * - `contract-modality-missing` (CONTRACT-06)
1037
- * - `contract-privacy-mismatch` (CONTRACT-06)
1038
- * - `contract-quality-floor` (reserved for Phase 12 `lattice eval`; NEVER emitted here)
1559
+ * When the adapter has NO `negotiateCapabilities` (consumer-provided v1.2
1560
+ * adapters, third-party adapters), falls back to the Phase 33 registry
1561
+ * via `synthesizeNegotiatedCapabilitiesFromRegistry` with source "registry"
1562
+ * (D-04). Consumer adapters get useful behavior out of the box without any
1563
+ * migration code.
1564
+ *
1565
+ * Verifiable per Pitfall 5: grep for `new Map<` in this function body should
1566
+ * return zero matches; LOC count of the function body is < 10 lines.
1039
1567
  */
1040
- declare function evaluateContractAgainstRoute(contract: CapabilityContract | undefined, input: EvaluateContractInput): ContractPreflightResult;
1041
- //#endregion
1042
- //#region src/receipts/keyset.d.ts
1568
+ declare function negotiateCapabilities(adapter: ProviderAdapter, modelId: string): Promise<NegotiatedCapabilities>;
1043
1569
  /**
1044
- * In-memory KeySet factory.
1570
+ * Phase 34 — D-04 / D-09 — Synthesizes a `NegotiatedCapabilities` shape from
1571
+ * the Phase 33 static registry. Used by:
1572
+ * 1. The top-level helper (above) for consumer-adapter fallback (D-04).
1573
+ * 2. Per-adapter negotiate() implementations (Plans 02-05) when /models
1574
+ * fails transiently (D-09, source "registry-fallback").
1045
1575
  *
1046
- * Verification flow (plan 09-03):
1047
- * - keySet.lookup(kid) returns undefined → VerifyError {kind: "key-not-found"}
1048
- * - entry.state === "revoked" → VerifyError {kind: "key-revoked"}
1049
- * - entry.state === "retired" → VerifyOk + keyState: "retired" (caller may warn)
1050
- * - entry.state === "active" → VerifyOk + keyState: "active"
1576
+ * Exported as a named export so Plans 02-05 can reuse the fallback synthesis
1577
+ * without duplicating the mapping logic.
1051
1578
  *
1052
- * Duplicate kids: last write wins (deterministic callers control entry order).
1053
- * Empty entries array is legal every lookup returns undefined.
1054
- * Returned KeySet exposes only `lookup` no enumeration.
1579
+ * Implementation note: the boolean derivations are intentionally minimal
1580
+ * (heuristic, not definitive). The per-adapter negotiate() implementations
1581
+ * in Plans 02-05 own the richer derivation from live /models data.
1582
+ * This helper is a SAFETY NET for adapters without /models endpoints and
1583
+ * for transient-fallback cases.
1055
1584
  *
1056
- * See 09-CONTEXT.md "Key Management (UNRETROFITTABLE)".
1585
+ * Anti-shape (documented in CONTEXT.md <specifics>): boolean `nativeToolCalling`
1586
+ * loses the strict-vs-lenient distinction in `toolCallSurface`. Consumers
1587
+ * needing the enum should look up the profile directly via `getCapabilityProfile`.
1057
1588
  */
1058
- declare function createMemoryKeySet(entries: readonly KeyEntry[]): KeySet;
1589
+ declare function synthesizeNegotiatedCapabilitiesFromRegistry(adapter: CapabilityAdapter, modelId: string, source: "registry" | "registry-fallback"): NegotiatedCapabilities;
1059
1590
  //#endregion
1060
- //#region src/receipts/sign.d.ts
1061
- interface GeneratedEd25519KeyPair {
1062
- readonly privateKeyJwk: JsonWebKey;
1063
- readonly publicKeyJwk: JsonWebKey;
1591
+ //#region src/providers/provider.d.ts
1592
+ type CapabilityModality = "text" | "json" | "image" | "audio" | "video" | "document" | "file" | "url" | "tool";
1593
+ type ProviderTransportMode = "inline" | "json" | "url" | "base64" | "provider-upload" | "file-id" | "extracted-text" | "transcript";
1594
+ type ProviderLatencyClass = "interactive" | "batch";
1595
+ interface ProviderPricingHint {
1596
+ /** @deprecated prefer `inputPer1kTokens` — kept for backward compatibility */
1597
+ readonly inputCostPer1M?: number;
1598
+ /** @deprecated prefer `outputPer1kTokens` — kept for backward compatibility */
1599
+ readonly outputCostPer1M?: number;
1600
+ /** Per-1000-prompt-token cost in USD. Preferred field for Phase 7+ pricing. */
1601
+ readonly inputPer1kTokens?: number;
1602
+ /** Per-1000-completion-token cost in USD. Preferred field for Phase 7+ pricing. */
1603
+ readonly outputPer1kTokens?: number;
1064
1604
  }
1065
- declare function generateEd25519KeyPairJwk(): Promise<GeneratedEd25519KeyPair>;
1066
- declare function createInMemorySigner(privateKeyJwk: JsonWebKey, options: {
1067
- readonly kid: string;
1068
- readonly publicKeyJwk: JsonWebKey;
1069
- }): ReceiptSigner;
1070
- //#endregion
1071
- //#region src/receipts/verify.d.ts
1072
1605
  /**
1073
- * Pure receipt verifier.
1606
+ * Normalized per-run usage at the result layer.
1074
1607
  *
1075
- * Returns a typed VerifyResult never throws across the verification
1076
- * boundary (PITFALLS.md security: "Verifier panics on malformed receipts
1077
- * -> DoS via crafted input"). All parsing failures become typed errors.
1608
+ * `costUsd` is `number | null` (not optional, not `0`) so downstream
1609
+ * consumers can distinguish "free" (`0`) from "unmeasured" (`null`) when
1610
+ * provider pricing is unknown see 07-CONTEXT.md "Cost Normalization & Usage".
1078
1611
  *
1079
- * Decision tree (first match wins):
1080
- * 1. decodeEnvelope throws OR signatures[] empty -> envelope-malformed
1081
- * 2. payload bytes are not valid JSON -> envelope-malformed
1082
- * 3. body shape check fails OR version unknown literal -> version-mismatch
1083
- * 4. body.version === undefined OR "lattice-receipt/v1"-> schema-version-too-low (CRYPTO-01)
1084
- * 5. keySet.lookup(keyid) === undefined -> key-not-found
1085
- * 6. entry.state === "revoked" -> key-revoked
1086
- * 7. re-canonicalized body != signed payloadBytes -> canonicalization-mismatch
1087
- * 8. Ed25519 verification of PAE fails -> signature-invalid
1088
- * 9. body.kid !== entry.kid (defense in depth) -> signature-invalid
1089
- * 10. otherwise -> ok + keyState
1612
+ * Distinct from `UsageRecord` on `ProviderAttemptRecord`: `UsageRecord`
1613
+ * is the per-attempt record, `Usage` is the per-run normalized shape
1614
+ * surfaced on `RunSuccess` / `RunFailure`.
1090
1615
  */
1091
- declare function verifyReceipt(envelope: ReceiptEnvelope, keySet: KeySet): Promise<VerifyResult>;
1616
+ interface Usage {
1617
+ readonly promptTokens: number;
1618
+ readonly completionTokens: number;
1619
+ readonly costUsd: number | null;
1620
+ }
1621
+ interface ProviderDataPolicyHints {
1622
+ readonly privacy: readonly ("standard" | "sensitive" | "restricted")[];
1623
+ readonly uploadRetention?: "none" | "ephemeral" | "provider-default";
1624
+ readonly supportsNoLogging?: boolean;
1625
+ readonly supportsNoTraining?: boolean;
1626
+ }
1627
+ interface ModelCapability {
1628
+ readonly providerId: string;
1629
+ readonly modelId: string;
1630
+ readonly inputModalities: readonly CapabilityModality[];
1631
+ readonly outputModalities: readonly CapabilityModality[];
1632
+ readonly fileTransport: readonly ProviderTransportMode[];
1633
+ readonly contextWindow: number;
1634
+ readonly structuredOutput: boolean;
1635
+ readonly toolUse: boolean;
1636
+ readonly streaming: boolean;
1637
+ readonly pricing?: ProviderPricingHint;
1638
+ readonly latency: ProviderLatencyClass;
1639
+ readonly dataPolicy: ProviderDataPolicyHints;
1640
+ readonly available?: boolean;
1641
+ }
1642
+ interface ProviderRef {
1643
+ readonly id: string;
1644
+ readonly kind?: "provider-ref";
1645
+ }
1646
+ interface ProviderRunRequest {
1647
+ readonly task: string;
1648
+ readonly artifacts: readonly ArtifactInput[];
1649
+ readonly outputs: readonly string[];
1650
+ readonly outputContracts?: OutputContractMap;
1651
+ readonly policy?: unknown;
1652
+ readonly signal?: AbortSignal;
1653
+ readonly plan?: ExecutionPlan;
1654
+ readonly contextPack?: ContextPack;
1655
+ readonly providerPackaging?: ProviderPackagingPlan;
1656
+ readonly packagedArtifacts?: readonly ArtifactRef[];
1657
+ /**
1658
+ * Phase 39 — opt-in prompt-cache prefix (DELEG-04). Adapters that support
1659
+ * block-granular caching (Anthropic) hoist this to a `cache_control`-marked
1660
+ * system content block; adapters that ignore it MUST receive the prefix
1661
+ * folded into `task` by the caller instead (the crew dispatcher gates on
1662
+ * `quirks.promptCachingSupported`). The field is advisory, additive, and
1663
+ * absent for all existing callers — follows the Phase 37 `toolCalls`
1664
+ * additive-field precedent (request/response additive fields accepted;
1665
+ * `ProviderAdapter` METHODS frozen per INV-03).
1666
+ */
1667
+ readonly cacheSystemPrefix?: string;
1668
+ }
1669
+ interface ProviderRunResponse {
1670
+ readonly rawOutputs: Record<string, unknown>;
1671
+ readonly artifactRefs?: readonly (ArtifactInput | ArtifactRef)[];
1672
+ /**
1673
+ * @deprecated Legacy per-attempt usage shape. Phase 7+ adapters should
1674
+ * populate `normalizedUsage` instead — Plan 04 will prefer `normalizedUsage`
1675
+ * when wiring `RunResult.usage`. Kept here for backward compatibility with
1676
+ * v1.0 adapters that already report this field.
1677
+ */
1678
+ readonly usage?: UsageRecord;
1679
+ /**
1680
+ * Phase 7 normalized usage shape for `RunResult.usage`. Populated by all
1681
+ * Phase 7+ adapters (openai, openai-compat, ai-sdk, fake). `costUsd` is
1682
+ * `null` when pricing is unknown (per the cost-normalization decision in
1683
+ * 07-CONTEXT.md — distinguishes "free" from "unmeasured").
1684
+ */
1685
+ readonly normalizedUsage?: Usage;
1686
+ readonly toolCalls?: readonly ValidatedToolCall[];
1687
+ readonly rawResponse?: unknown;
1688
+ }
1689
+ interface ProviderAdapter {
1690
+ readonly id: string;
1691
+ readonly kind: "provider-adapter";
1692
+ readonly capabilities?: readonly ModelCapability[];
1693
+ readonly execute?: (request: ProviderRunRequest) => Promise<ProviderRunResponse>;
1694
+ /**
1695
+ * Phase 34 — D-01 — Per-adapter behavioral deviation flags. OPTIONAL on the
1696
+ * base interface so v1.2 consumer adapters (4-field literals) continue to work
1697
+ * without modification (non-breaking). First-party adapter factories narrow the
1698
+ * return type to require `quirks` with the specific sub-interface for their adapter.
1699
+ *
1700
+ * D-03 discriminant-narrowing contract: consumers reading this field get
1701
+ * `AdapterQuirks` autocomplete. To access adapter-specific flags, cast after
1702
+ * an `adapter.id` discriminant check OR use the typed factory return directly.
1703
+ * Example: `(adapter.quirks as AnthropicQuirks).promptCachingSupported`.
1704
+ */
1705
+ readonly quirks?: AdapterQuirks;
1706
+ /**
1707
+ * Phase 34 — D-02 — Capability negotiation via the provider's /models endpoint.
1708
+ * OPTIONAL on the base interface (non-breaking for v1.2 consumer adapters).
1709
+ * First-party adapters that have a /models endpoint implement this; adapters
1710
+ * without one (LM Studio, openai-compat) fall back to the Phase 33 registry.
1711
+ *
1712
+ * The top-level `negotiateCapabilities(adapter, modelId)` helper in
1713
+ * `capabilities/negotiate.ts` delegates to this method when present and
1714
+ * synthesizes from the registry otherwise (D-04).
1715
+ */
1716
+ readonly negotiateCapabilities?: (modelId: string) => Promise<NegotiatedCapabilities>;
1717
+ }
1718
+ type ProviderRegistryInput = readonly (ProviderRef | ProviderAdapter | string)[];
1719
+ //#endregion
1720
+ //#region src/plan/plan.d.ts
1721
+ type ExecutionPlanStatus = "stub" | "planned" | "no-route" | "running" | "completed" | "failed";
1722
+ type ExecutionStageKind = "analysis" | "transforms" | "context-packing" | "provider-packaging" | "tool-execution" | "execution" | "validation" | "tripwire" | "persistence" | "replay";
1723
+ type ExecutionStageStatus = "pending" | "running" | "completed" | "skipped" | "failed";
1724
+ interface ExecutionPlanStage {
1725
+ readonly id: string;
1726
+ readonly kind: ExecutionStageKind;
1727
+ readonly status: ExecutionStageStatus;
1728
+ readonly inputArtifacts?: readonly string[];
1729
+ readonly outputArtifacts?: readonly string[];
1730
+ readonly warnings: readonly string[];
1731
+ readonly metadata?: Record<string, unknown>;
1732
+ }
1733
+ interface RouteRejectReason {
1734
+ readonly code: string;
1735
+ readonly message: string;
1736
+ }
1737
+ interface RouteCandidate {
1738
+ readonly providerId: string;
1739
+ readonly modelId: string;
1740
+ readonly capability: ModelCapability;
1741
+ readonly score: number;
1742
+ readonly accepted: boolean;
1743
+ readonly reasons: readonly RouteRejectReason[];
1744
+ readonly estimates: RouteEstimates;
1745
+ }
1746
+ interface RouteEstimates {
1747
+ readonly inputTokens: number;
1748
+ readonly outputTokens: number;
1749
+ readonly costUsd?: number;
1750
+ readonly latencyMs?: number;
1751
+ }
1752
+ interface SelectedRoute {
1753
+ readonly providerId: string;
1754
+ readonly modelId: string;
1755
+ readonly score: number;
1756
+ readonly estimates: RouteEstimates;
1757
+ readonly inputModalities: readonly CapabilityModality[];
1758
+ readonly outputModalities: readonly CapabilityModality[];
1759
+ readonly fileTransport: readonly ProviderTransportMode[];
1760
+ }
1761
+ interface FallbackRoute {
1762
+ readonly providerId: string;
1763
+ readonly modelId: string;
1764
+ readonly score: number;
1765
+ readonly reason: "policy-preserving-fallback";
1766
+ }
1767
+ interface RouteDecision {
1768
+ readonly catalogVersion: string;
1769
+ readonly selected?: SelectedRoute;
1770
+ readonly candidates: readonly RouteCandidate[];
1771
+ readonly rejected: readonly RouteCandidate[];
1772
+ readonly fallbackChain: readonly FallbackRoute[];
1773
+ readonly noRouteReasons: readonly RouteRejectReason[];
1774
+ }
1775
+ interface ContextPackPlan {
1776
+ readonly id: string;
1777
+ readonly tokenBudget: number;
1778
+ readonly estimatedTokens: number;
1779
+ readonly included: readonly ContextPackItemPlan[];
1780
+ readonly summarized: readonly ContextPackItemPlan[];
1781
+ readonly archived: readonly ContextPackItemPlan[];
1782
+ readonly omitted: readonly ContextPackItemPlan[];
1783
+ readonly warnings: readonly string[];
1784
+ }
1785
+ interface ContextPackItemPlan {
1786
+ readonly artifactId?: string;
1787
+ readonly sessionTurnId?: string;
1788
+ readonly reason: string;
1789
+ readonly estimatedTokens: number;
1790
+ readonly trust: "developer" | "user" | "tool" | "model-summary";
1791
+ }
1792
+ interface ProviderPackagingPlan {
1793
+ readonly providerId: string;
1794
+ readonly modelId: string;
1795
+ readonly artifacts: readonly ProviderPackagedArtifactPlan[];
1796
+ readonly warnings: readonly string[];
1797
+ }
1798
+ interface ProviderPackagedArtifactPlan {
1799
+ readonly artifactId: string;
1800
+ readonly transport: ProviderTransportMode;
1801
+ readonly mediaType?: string;
1802
+ readonly lineageTransform: "provider-packaging";
1803
+ readonly warnings: readonly string[];
1804
+ }
1805
+ interface ProviderAttemptRecord {
1806
+ readonly providerId: string;
1807
+ readonly modelId: string;
1808
+ readonly status: "pending" | "running" | "succeeded" | "failed" | "cancelled";
1809
+ readonly startedAt?: string;
1810
+ readonly completedAt?: string;
1811
+ readonly error?: string;
1812
+ readonly usage?: UsageRecord;
1813
+ }
1814
+ interface UsageRecord {
1815
+ readonly inputTokens?: number;
1816
+ readonly outputTokens?: number;
1817
+ readonly totalTokens?: number;
1818
+ readonly costUsd?: number;
1819
+ readonly latencyMs?: number;
1820
+ }
1821
+ interface ExecutionPlan {
1822
+ readonly id: string;
1823
+ readonly kind: "execution-plan";
1824
+ readonly version: 1;
1825
+ readonly createdAt: string;
1826
+ readonly status: ExecutionPlanStatus;
1827
+ readonly task: string;
1828
+ readonly outputNames: readonly string[];
1829
+ readonly artifactRefs: readonly ArtifactRef[];
1830
+ readonly route: RouteDecision;
1831
+ readonly stages: readonly ExecutionPlanStage[];
1832
+ readonly context?: ContextPackPlan;
1833
+ readonly providerPackaging?: ProviderPackagingPlan;
1834
+ readonly attempts: readonly ProviderAttemptRecord[];
1835
+ readonly warnings: readonly string[];
1836
+ readonly metadata?: Record<string, unknown>;
1837
+ }
1838
+ interface ExecutionPlanStub {
1839
+ readonly id: string;
1840
+ readonly kind: "plan-stub";
1841
+ readonly createdAt: string;
1842
+ readonly status: "stub";
1843
+ readonly stages: readonly [];
1844
+ readonly warnings: readonly string[];
1845
+ }
1846
+ type ResultPlan = ExecutionPlan | ExecutionPlanStub;
1092
1847
  //#endregion
1093
- //#region src/results/errors.d.ts
1094
- interface ValidationIssue {
1095
- readonly message: string;
1096
- readonly path?: readonly (string | number | symbol)[];
1848
+ //#region src/receipts/types.d.ts
1849
+ type ContractVerdict = "success" | "tripwire-violated" | "no-contract-match" | "execution-failed" | "validation-failed";
1850
+ interface ReceiptUsageCanonical {
1851
+ readonly promptTokens: number;
1852
+ readonly completionTokens: number;
1853
+ readonly costUsd: string | null;
1097
1854
  }
1098
- interface ValidationError {
1099
- readonly kind: "validation";
1100
- readonly message: string;
1101
- readonly output?: string;
1102
- readonly issues: readonly ValidationIssue[];
1855
+ interface ReceiptModel {
1856
+ readonly requested: string;
1857
+ readonly observed: string | null;
1103
1858
  }
1104
- interface ExecutionUnavailableError {
1105
- readonly kind: "execution_unavailable";
1106
- readonly message: string;
1859
+ interface ReceiptRoute {
1860
+ readonly providerId: string;
1861
+ readonly capabilityId: string;
1862
+ readonly attemptNumber: number;
1107
1863
  }
1108
- interface NoRouteError {
1109
- readonly kind: "no_route";
1110
- readonly message: string;
1111
- readonly reasons: readonly string[];
1864
+ interface ReceiptRedaction {
1865
+ readonly path: string;
1866
+ readonly reason: string;
1112
1867
  }
1113
- interface ProviderExecutionError {
1114
- readonly kind: "provider_execution";
1115
- readonly message: string;
1116
- readonly providerId?: string;
1117
- readonly modelId?: string;
1868
+ interface CapabilityReceiptBody {
1869
+ readonly version: "lattice-receipt/v1" | "lattice-receipt/v1.1" | "lattice-receipt/v1.2";
1870
+ readonly receiptId: string;
1871
+ readonly runId: string;
1872
+ readonly issuedAt: string;
1873
+ readonly kid: string;
1874
+ readonly model: ReceiptModel;
1875
+ readonly route: ReceiptRoute;
1876
+ readonly modelClass?: TrainingClass;
1877
+ readonly parentReceiptCid?: string;
1878
+ readonly usage: ReceiptUsageCanonical;
1879
+ readonly contractVerdict: ContractVerdict;
1880
+ readonly contractHash: string | null;
1881
+ readonly inputHashes: readonly string[];
1882
+ readonly outputHash: string | null;
1883
+ readonly redactionPolicyId: string;
1884
+ readonly redactions: readonly ReceiptRedaction[];
1885
+ readonly noRouteReasons?: readonly RouteRejectReason[];
1886
+ readonly tripwireEvidence?: TripwireEvidence;
1887
+ readonly stepName?: string;
1888
+ readonly stepIndex?: number;
1889
+ readonly parentStepName?: string;
1890
+ readonly previousStepName?: string;
1891
+ readonly sessionId?: string;
1892
+ readonly timestamp?: string;
1118
1893
  }
1119
- interface TimeoutError {
1120
- readonly kind: "timeout";
1121
- readonly message: string;
1894
+ interface ReceiptSignature {
1895
+ readonly keyid: string;
1896
+ readonly sig: string;
1122
1897
  }
1123
- /**
1124
- * Phase 7 addition: emitted by the runtime when no candidate route can
1125
- * satisfy the caller-supplied `CapabilityContract` (budget, modality,
1126
- * privacy, or quality-floor invariants).
1127
- *
1128
- * `noRouteReasons` carries the full deterministic-router rejection list
1129
- * so callers can inspect per-candidate detail. Phase 9 (receipts) will
1130
- * persist this array for deterministic verdict reconstruction.
1131
- */
1132
- interface NoContractMatchError {
1133
- readonly kind: "no-contract-match";
1134
- readonly message: string;
1135
- readonly noRouteReasons: readonly RouteRejectReason[];
1898
+ interface ReceiptEnvelope {
1899
+ readonly payloadType: "application/vnd.lattice.receipt+json";
1900
+ readonly payload: string;
1901
+ readonly signatures: readonly ReceiptSignature[];
1136
1902
  }
1137
- /**
1138
- * Phase 8 addition: emitted when a `CapabilityContract.invariants` tripwire
1139
- * fires after the provider returned a schema-valid output. Carries the
1140
- * `TripwireEvidence` produced by `evaluateTripwires`.
1141
- *
1142
- * `terminal: true` is a structural marker — combined with the `isTerminal()`
1143
- * predicate it tells the fallback chain in `runWithConfig` to refuse retry.
1144
- * `NoContractMatchError` does NOT carry the field (to avoid breaking Phase 7
1145
- * callers) but `isTerminal()` still returns true for it via the kind check.
1146
- */
1147
- interface TripwireViolationError {
1148
- readonly kind: "tripwire-violated";
1149
- readonly message: string;
1150
- readonly invariantId: string;
1151
- readonly evidence: TripwireEvidence;
1152
- readonly terminal: true;
1903
+ interface ReceiptSigner {
1904
+ readonly kid: string;
1905
+ sign(bytes: Uint8Array): Promise<Uint8Array>;
1906
+ readonly publicKeyJwk: JsonWebKey;
1153
1907
  }
1154
- type LatticeRunError = ValidationError | ExecutionUnavailableError | NoRouteError | ProviderExecutionError | TimeoutError | NoContractMatchError | TripwireViolationError;
1155
- /**
1156
- * Returns `true` for run errors that MUST NOT be retried by the fallback
1157
- * chain. Phase 8 covers two kinds:
1158
- *
1159
- * - `tripwire-violated` — the contract's invariants rejected the output;
1160
- * a different provider will not change the verdict, so retry burns
1161
- * budget for no gain (T-08-06 in 08-02-PLAN threat register).
1162
- * - `no-contract-match` — no route satisfies the contract at all; the
1163
- * run never executed and no retry will help.
1164
- *
1165
- * All other error kinds return `false` and remain eligible for fallback.
1166
- * The predicate is exported so Phase 12's eval gate and any user-side
1167
- * retry wrappers can share one source of truth.
1168
- */
1169
- declare function isTerminal(error: LatticeRunError): boolean;
1170
- //#endregion
1171
- //#region src/providers/adapters.d.ts
1172
- interface OpenAICompatibleProviderOptions {
1173
- readonly id?: string;
1174
- readonly model: string;
1175
- readonly baseUrl: string;
1176
- readonly apiKey?: string;
1177
- readonly fetch?: typeof fetch;
1178
- /**
1179
- * Phase 7 addition: caller-supplied per-1k pricing. When provided, the
1180
- * adapter computes `normalizedUsage.costUsd` from the API-reported token
1181
- * counts. When omitted, `normalizedUsage.costUsd` is `null` so downstream
1182
- * consumers can distinguish "unmeasured" from "free" (per 07-CONTEXT.md).
1183
- */
1184
- readonly pricing?: {
1185
- readonly inputPer1kTokens?: number;
1186
- readonly outputPer1kTokens?: number;
1187
- };
1908
+ type KeyState = "active" | "retired" | "revoked";
1909
+ interface KeyEntry {
1910
+ readonly kid: string;
1911
+ readonly publicKeyJwk: JsonWebKey;
1912
+ readonly state: KeyState;
1188
1913
  }
1189
- interface SdkLikeProviderOptions {
1190
- readonly id?: string;
1191
- readonly model: string;
1192
- readonly generate: (input: {
1193
- readonly task: string;
1194
- readonly outputNames: readonly string[];
1195
- }) => Promise<ProviderRunResponse> | ProviderRunResponse;
1914
+ interface KeySet {
1915
+ lookup(kid: string): KeyEntry | undefined;
1196
1916
  }
1197
- declare function createOpenAICompatibleProvider(options: OpenAICompatibleProviderOptions): ProviderAdapter;
1198
- declare function createOpenAIProvider(options: OpenAICompatibleProviderOptions): ProviderAdapter;
1199
- declare function createAISdkProvider(options: SdkLikeProviderOptions): ProviderAdapter;
1200
- //#endregion
1201
- //#region src/providers/anthropic.d.ts
1202
- /**
1203
- * Options for {@link createAnthropicProvider}.
1204
- *
1205
- * Mirrors `OpenAICompatibleProviderOptions` ergonomics (Phase 7 pattern) but
1206
- * for the Anthropic Messages API at `/v1/messages` -- which uses a top-level
1207
- * `system` field and a `content[0].text` response shape that diverges from
1208
- * the OpenAI Chat Completions schema (see FSB v0.9.x `extension/ai/universal-provider.js`
1209
- * lines 280-297 + 566-573 for the production reference).
1210
- *
1211
- * SECURITY: `apiKey` is a runtime parameter -- do NOT hardcode or log it.
1212
- *
1213
- * DEFERRED (Phase 4 carryforward notes):
1214
- * - prompt caching (deferred to a follow-on phase)
1215
- * - streaming (deferred; this adapter is single-shot Promise -- per CONTEXT.md D-06)
1216
- * - tool use (Anthropic tool_use blocks are deferred)
1217
- * - resume-from-eviction -- see Phase 5 (MV3-survivability adapter contract)
1218
- *
1219
- * Ref: FSB v0.10.0-attempt-2 Phase 4 (D-02 + D-07: full custom adapter; preserve top-level `system`).
1220
- */
1221
- interface AnthropicProviderOptions {
1222
- readonly id?: string;
1223
- readonly model: string;
1224
- readonly apiKey: string;
1225
- /** Defaults to `https://api.anthropic.com`. Override for proxies. */
1226
- readonly baseUrl?: string;
1227
- /** Defaults to `2023-06-01`. Override only if the consumer has tested a newer pinned version. */
1228
- readonly anthropicVersion?: string;
1229
- readonly fetch?: typeof fetch;
1230
- readonly pricing?: {
1231
- readonly inputPer1kTokens?: number;
1232
- readonly outputPer1kTokens?: number;
1233
- };
1917
+ type VerifyErrorKind = "key-not-found" | "key-revoked" | "canonicalization-mismatch" | "signature-invalid" | "envelope-malformed" | "version-mismatch" | "schema-version-too-low";
1918
+ interface VerifyError {
1919
+ readonly kind: VerifyErrorKind;
1920
+ readonly message: string;
1234
1921
  }
1235
- declare function createAnthropicProvider(options: AnthropicProviderOptions): ProviderAdapter;
1236
- //#endregion
1237
- //#region src/providers/fake.d.ts
1238
- interface FakeProviderOptions {
1239
- readonly id?: string;
1240
- readonly modelId?: string;
1241
- readonly response?: ProviderRunResponse | ((request: ProviderRunRequest) => ProviderRunResponse | Promise<ProviderRunResponse>);
1242
- readonly artifacts?: readonly ArtifactInput[];
1243
- /**
1244
- * Phase 7 addition: when provided, REPLACES the default single-capability
1245
- * array so callers (notably Plan 07-04's modality/privacy reject tests)
1246
- * can construct a fake adapter with arbitrary
1247
- * `inputModalities` / `outputModalities` / `dataPolicy` / `pricing`
1248
- * without mutating the returned adapter's readonly `capabilities` array.
1249
- * When omitted, the existing default capability is used.
1250
- */
1251
- readonly capabilities?: readonly ModelCapability[];
1922
+ interface VerifyOk {
1923
+ readonly ok: true;
1924
+ readonly body: CapabilityReceiptBody;
1925
+ readonly keyState: KeyState;
1252
1926
  }
1253
- declare function createFakeProvider(options?: FakeProviderOptions): ProviderAdapter;
1254
- //#endregion
1255
- //#region src/providers/gemini.d.ts
1256
- /**
1257
- * Options for {@link createGeminiProvider}.
1258
- *
1259
- * Mirrors `OpenAICompatibleProviderOptions` ergonomics (Phase 7 pattern) but
1260
- * for Google's Generative Language API at
1261
- * `/v1beta/models/{model}:generateContent` -- which uses `contents[].parts[].text`
1262
- * (NOT OpenAI's `messages[]`), `role: "model"` for assistant turns (NOT
1263
- * `"assistant"`), authenticates via `?key=` query string, and applies a
1264
- * 4-category `safetySettings` block at `BLOCK_NONE` thresholds (FSB convention
1265
- * mirrored from `extension/ai/universal-provider.js:255-272`).
1266
- *
1267
- * SECURITY: `apiKey` is a runtime parameter -- do NOT hardcode or log it.
1268
- *
1269
- * DEFERRED (Phase 4 carryforward notes):
1270
- * - multimodal (vision) -- deferred
1271
- * - streaming -- deferred (single-shot Promise per CONTEXT.md D-06)
1272
- * - tool use -- deferred
1273
- * - resume-from-eviction -- see Phase 5 (MV3-survivability adapter contract)
1274
- *
1275
- * Ref: FSB v0.10.0-attempt-2 Phase 4 (D-02 + D-07: full custom adapter; preserve role:"model").
1276
- */
1277
- interface GeminiProviderOptions {
1278
- readonly id?: string;
1279
- readonly model: string;
1280
- readonly apiKey: string;
1281
- /** Defaults to `https://generativelanguage.googleapis.com`. */
1282
- readonly baseUrl?: string;
1283
- readonly fetch?: typeof fetch;
1284
- readonly pricing?: {
1285
- readonly inputPer1kTokens?: number;
1286
- readonly outputPer1kTokens?: number;
1287
- };
1927
+ interface VerifyFail {
1928
+ readonly ok: false;
1929
+ readonly error: VerifyError;
1288
1930
  }
1289
- declare function createGeminiProvider(options: GeminiProviderOptions): ProviderAdapter;
1931
+ type VerifyResult = VerifyOk | VerifyFail;
1290
1932
  //#endregion
1291
- //#region src/providers/lm-studio.d.ts
1933
+ //#region src/receipts/receipt.d.ts
1292
1934
  /**
1293
- * Options for {@link createLmStudioProvider}.
1294
- *
1295
- * Thin wrapper around {@link createOpenAICompatibleProvider} pinned to
1296
- * LM Studio's default local server URL `http://localhost:1234/v1`. Wire
1297
- * shape is OpenAI Chat Completions. LM Studio is no-auth by convention
1298
- * (CD-03): `apiKey` is OPTIONAL; when omitted, the underlying factory
1299
- * sends no `Authorization` header (see
1300
- * `lattice/packages/lattice/src/providers/adapters.ts:53` for the
1301
- * conditional auth-header wiring).
1302
- *
1303
- * DEFERRED (D-16 carryforward):
1304
- * - latency-tail diagnostics -- observability concern; LM Studio is
1305
- * the canary for latency tails (INV-03);
1306
- * diagnostics module deferred to a
1307
- * follow-on observability phase.
1308
- * - streaming -- deferred (single-shot per D-06).
1309
- * - resume-from-eviction -- see Phase 5 (MV3-survivability adapter).
1935
+ * Public input to createReceipt. Mirrors CapabilityReceiptBody minus:
1936
+ * - `version` (forced to "lattice-receipt/v1.2" per Phase 38)
1937
+ * - `kid` (forced from signer.kid caller cannot mismatch)
1938
+ * - `redactions[]` (populated by redactReceiptBody)
1939
+ * - `usage.costUsd` (converted to canonical string by usageToCanonical)
1310
1940
  *
1311
- * Ref: FSB v0.10.0-attempt-2 Phase 4 (D-03: thin wrapper; D-16: latency-tail deferred; CD-03 no-opt-out).
1941
+ * receiptId and issuedAt default to runtime-generated values when omitted.
1942
+ * redactionPolicyId defaults to DEFAULT_REDACTION_POLICY_ID.
1312
1943
  */
1313
- interface LmStudioProviderOptions extends Omit<OpenAICompatibleProviderOptions, "id" | "baseUrl" | "apiKey"> {
1314
- readonly id?: string;
1315
- /** Defaults to `http://localhost:1234/v1`. Override for non-localhost deployments. */
1316
- readonly baseUrl?: string;
1317
- /**
1318
- * Optional. LM Studio is no-auth by convention (CD-03 default).
1319
- * When provided, sent as `Authorization: Bearer <apiKey>` (matches the
1320
- * underlying OpenAI-compat factory). Use only for proxied LM Studio
1321
- * deployments that have a token gate in front.
1322
- */
1323
- readonly apiKey?: string;
1944
+ interface CreateReceiptInput {
1945
+ readonly runId: string;
1946
+ readonly issuedAt?: string;
1947
+ readonly receiptId?: string;
1948
+ readonly model: ReceiptModel;
1949
+ readonly route: ReceiptRoute;
1950
+ readonly modelClass?: TrainingClass;
1951
+ readonly parentReceiptCid?: string;
1952
+ readonly usage: Usage;
1953
+ readonly contractVerdict: ContractVerdict;
1954
+ readonly contractHash: string | null;
1955
+ readonly inputHashes: readonly string[];
1956
+ readonly outputHash: string | null;
1957
+ readonly redactionPolicyId?: string;
1958
+ readonly noRouteReasons?: readonly RouteRejectReason[];
1959
+ readonly tripwireEvidence?: TripwireEvidence;
1960
+ readonly stepName?: string;
1961
+ readonly stepIndex?: number;
1962
+ readonly parentStepName?: string;
1963
+ readonly previousStepName?: string;
1964
+ readonly sessionId?: string;
1965
+ readonly timestamp?: string;
1324
1966
  }
1325
- declare function createLmStudioProvider(options: LmStudioProviderOptions): ProviderAdapter;
1326
- //#endregion
1327
- //#region src/providers/openrouter.d.ts
1328
1967
  /**
1329
- * Options for {@link createOpenRouterProvider}.
1968
+ * Build, redact, canonicalize, sign, and envelope a CapabilityReceipt.
1330
1969
  *
1331
- * Thin wrapper around {@link createOpenAICompatibleProvider} pinned to
1332
- * OpenRouter's base URL `https://openrouter.ai/api/v1`. Wire shape is
1333
- * OpenAI Chat Completions; no provider-specific quirks at the
1334
- * single-shot Promise contract level.
1970
+ * Ordering INVARIANT (09-CONTEXT.md, PITFALLS.md Pitfall #1):
1971
+ * redact -> canonicalize -> PAE -> sign -> encode
1335
1972
  *
1336
- * SECURITY: `apiKey` is a runtime parameter -- do NOT hardcode or log it.
1973
+ * The signed digest commits to canonicalize(redact(body)). The function
1974
+ * structure makes any other ordering impossible to write by accident —
1975
+ * canonicalizeReceiptBody is ONLY called on the output of redactReceiptBody.
1337
1976
  *
1338
- * DEFERRED (D-17 carryforward; Phase 4 ships the named adapter as a
1339
- * first-class OpenAI-compat wrapper):
1340
- * - model-routing array -- caller supplies `model` (single id); OpenRouter's
1341
- * `models: [primary, fallback, ...]` array
1342
- * feature is deferred to a follow-on phase.
1343
- * - fallback-array -- deferred (same phase as model-routing).
1344
- * - per-message routing -- deferred.
1345
- * - streaming -- deferred (single-shot per CONTEXT.md D-06).
1346
- * - resume-from-eviction -- see Phase 5 (MV3-survivability adapter).
1977
+ * Defense in depth:
1978
+ * - body.kid is assigned from signer.kid, never from input (input has no
1979
+ * kid field). The signed body and the envelope keyid CANNOT disagree by
1980
+ * construction.
1981
+ * - signer.kid is also written to envelope.signatures[0].keyid, so the
1982
+ * verifier can cross-check (Step 7 of verifyReceipt).
1347
1983
  *
1348
- * Ref: FSB v0.10.0-attempt-2 Phase 4 (D-03: thin wrapper; D-17: model-routing deferred).
1984
+ * I-JSON guarantees: usage.costUsd is converted to string (or null) via
1985
+ * usageToCanonical. Receipts NEVER carry raw floats in the canonical form.
1349
1986
  */
1350
- interface OpenRouterProviderOptions extends Omit<OpenAICompatibleProviderOptions, "id" | "baseUrl"> {
1351
- readonly id?: string;
1352
- /** Defaults to `https://openrouter.ai/api/v1`. Override for proxies. */
1353
- readonly baseUrl?: string;
1354
- }
1355
- declare function createOpenRouterProvider(options: OpenRouterProviderOptions): ProviderAdapter;
1987
+ declare function createReceipt(input: CreateReceiptInput, signer: ReceiptSigner): Promise<ReceiptEnvelope>;
1356
1988
  //#endregion
1357
- //#region src/providers/xai.d.ts
1989
+ //#region src/contract/checkpoint.d.ts
1358
1990
  /**
1359
- * Options for {@link createXaiProvider}.
1360
- *
1361
- * Thin wrapper around {@link createOpenAICompatibleProvider} pinned to
1362
- * xAI's base URL `https://api.x.ai/v1`. The wire shape is identical to
1363
- * OpenAI Chat Completions, with one provider-specific quirk preserved:
1364
- * `response.usage.completion_tokens_details.reasoning_tokens` (xAI's
1365
- * separate reasoning-token accounting; see FSB
1366
- * `extension/ai/universal-provider.js:585-594` for the production reference).
1367
- *
1368
- * SECURITY: `apiKey` is a runtime parameter -- do NOT hardcode or log it.
1369
- *
1370
- * DEFERRED (Phase 4 carryforward notes):
1371
- * - tool-streaming -- deferred
1372
- * - streaming -- deferred (single-shot Promise per CONTEXT.md D-06)
1373
- * - resume-from-eviction -- see Phase 5 (MV3-survivability adapter contract)
1374
- *
1375
- * Ref: FSB v0.10.0-attempt-2 Phase 4 (D-03 + D-07: thin wrapper; reasoning_tokens quirk preserved).
1991
+ * The tracer event name Lattice's checkpoint hook emits per step transition.
1992
+ * Identical to the literal added to RunEventKind in tracing.ts.
1376
1993
  */
1377
- interface XaiProviderOptions extends Omit<OpenAICompatibleProviderOptions, "id" | "baseUrl"> {
1378
- readonly id?: string;
1379
- /** Defaults to `https://api.x.ai/v1`. Override for proxies. */
1380
- readonly baseUrl?: string;
1381
- }
1382
- declare function createXaiProvider(options: XaiProviderOptions): ProviderAdapter;
1383
- //#endregion
1384
- //#region src/outputs/infer.d.ts
1385
- type InferOutput<C> = C extends "text" ? string : C extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<C> : C extends CitationsOutputContract ? readonly CitationRef[] : C extends ArtifactRefsOutputContract ? readonly ArtifactRef[] : never;
1386
- type InferOutputMap<T extends OutputContractMap> = { readonly [K in keyof T]: InferOutput<T[K]> };
1387
- //#endregion
1388
- //#region src/results/result.d.ts
1389
- interface RunSuccess<TOutputs extends OutputContractMap> {
1390
- readonly ok: true;
1391
- readonly outputs: InferOutputMap<TOutputs>;
1392
- readonly artifacts: readonly ArtifactRef[];
1393
- readonly usage: Usage;
1394
- readonly plan: ResultPlan;
1395
- readonly events?: readonly RunEvent[];
1396
- /**
1397
- * Phase 9 — signed capability receipt issued when `LatticeConfig.signer`
1398
- * is configured. Undefined when no signer is set.
1399
- */
1400
- readonly receipt?: ReceiptEnvelope;
1401
- }
1402
- interface RunFailure {
1403
- readonly ok: false;
1404
- readonly error: LatticeRunError;
1405
- readonly usage: Usage;
1406
- readonly raw?: unknown;
1407
- readonly partialOutputs?: Record<string, unknown>;
1408
- readonly plan: ResultPlan;
1409
- readonly events?: readonly RunEvent[];
1410
- /**
1411
- * Phase 9 — signed capability receipt issued when `LatticeConfig.signer`
1412
- * is configured. Undefined when no signer is set.
1413
- */
1414
- readonly receipt?: ReceiptEnvelope;
1415
- }
1416
- type RunResult<TOutputs extends OutputContractMap> = RunSuccess<TOutputs> | RunFailure;
1417
- //#endregion
1418
- //#region src/runtime/survivability.d.ts
1994
+ declare const STEP_TRANSITION_EVENT_NAME: "step.transition";
1419
1995
  /**
1420
- * MV3-survivability adapter contract -- Phase 5 (FSB v0.10.0-attempt-2).
1421
- *
1422
- * This module is a SIBLING of create-ai.ts (the Lattice runtime facade) and
1423
- * a SIBLING of contract/bands.ts (the hook pipeline factory) and
1424
- * contract/checkpoint.ts (the per-step receipt hook). It does NOT modify
1425
- * any of them; the SurvivabilityAdapter contract is composed from those
1426
- * surfaces by the consumer (FSB's lattice-runtime-adapter.js in Plan 05-05).
1427
- *
1428
- * What is the survivability problem?
1429
- * Some host runtimes can evict the execution context mid-flow with no
1430
- * synchronous shutdown signal:
1431
- * - Chrome MV3 service workers: evicted after 30s silence OR 5min idle.
1432
- * - Cloudflare Workers: evicted at end of each request unless waitUntil.
1433
- * - AWS Lambda: process freeze + thaw across invocations.
1434
- * Lattice's existing runtime (create-ai.ts) assumes the process stays
1435
- * live for the duration of a run. The SurvivabilityAdapter contract is
1436
- * the seam where a host runtime tells Lattice "here is how to serialize
1437
- * my state, here is how to deserialize it back, here is how to resume
1438
- * work after I get evicted and recreated."
1439
- *
1440
- * What this module SHIPS:
1441
- * - SurvivabilityAdapter<TState> interface (4 methods)
1442
- * - SerializedSnapshot type (string-encodable opaque envelope)
1443
- * - EvictionHook<TState> type (pre-eviction callback signature)
1444
- * - ResumePolicy literal-union (post-restore reconstruction verdict)
1445
- * - UnsubscribeFn type
1446
- * - createNoopSurvivabilityAdapter() reference implementation
1447
- *
1448
- * What this module DOES NOT ship:
1449
- * - chrome.storage.session integration (FSB-side; Plan 05-05).
1450
- * - offscreen-document message bus (FSB-side; Plan 05-04).
1451
- * - Auto-wiring into create-ai.ts runtime (deferred indefinitely; the
1452
- * contract is consumer-controlled).
1453
- * - Mid-API-request / mid-tool-dispatch recovery dispatcher (CONSERVATIVE
1454
- * recovery wiring is deferred to a follow-on FSB milestone per
1455
- * CONTEXT.md D-22; only the ResumePolicy taxonomy lands here).
1456
- *
1457
- * Composition conventions (NOT enforced; documented for callers):
1458
- * D-09: onEviction hooks SHOULD register in BAND.SAFETY band on the
1459
- * caller's HookPipeline so they run FIRST per Phase 2 priority
1460
- * ordering. This module does NOT auto-register; it ships the
1461
- * contract only.
1462
- * D-10: serialize(state) MAY include the latest checkpoint receipt
1463
- * envelope (Phase 3 createCheckpointHook output) inside the
1464
- * SerializedSnapshot.payload; deserialize() reconstructs session
1465
- * identifiers from the v1.1 receipt body's step-marker fields
1466
- * (stepName, stepIndex, parentStepName, previousStepName,
1467
- * sessionId, timestamp). The payload is opaque to Lattice -- the
1468
- * host runtime defines the shape.
1469
- *
1470
- * ResumePolicy taxonomy (CD-E resolution per attempt-1 02-04-PLAN.md):
1471
- * - SAFE: the snapshot was captured at a safe boundary (BEFORE_ITERATION
1472
- * or BEFORE_NEXT_ITERATION_SCHEDULE step markers) and can be replayed
1473
- * deterministically. The host runtime may re-arm the loop.
1474
- * - RECOVERY_AMBIGUOUS: the snapshot was captured during a tool dispatch
1475
- * where re-execution risk is non-zero (file write, network POST without
1476
- * Idempotency-Key, side-effecting browser action). Host should escalate
1477
- * to the user before deciding.
1478
- * - ON_ERROR_SW_EVICTION_MID_REQUEST: the eviction happened mid-API-call
1479
- * (the provider request was in flight). 6 of 7 FSB providers do NOT
1480
- * document Idempotency-Key headers; replay risks duplicate charges +
1481
- * duplicate responses. Host should treat the run as failed and surface
1482
- * the error to the user.
1483
- * - ON_ERROR_SW_EVICTION_MID_TOOL_DISPATCH: the eviction happened mid-
1484
- * tool-dispatch (a browser action was in progress). Re-execution risk
1485
- * is similar to mid-API-call but lands in a different recovery branch
1486
- * (the host may inspect the page state before deciding).
1487
- *
1488
- * SerializedSnapshot is intentionally opaque + string-encodable. The
1489
- * host runtime defines the payload shape; Lattice's only requirement
1490
- * is that serialize() followed by deserialize() round-trips the state.
1491
- *
1492
- * Ed25519 receipt envelope contract (carries forward from Phase 1-3):
1493
- * Callers MAY embed a v1.1 ReceiptEnvelope inside SerializedSnapshot.payload
1494
- * for signed checkpoint round-trip. verifyReceipt against the embedded
1495
- * envelope MUST return result.ok === true after a serialize -> deserialize
1496
- * cycle (Test 12). This validates that JSON.stringify + JSON.parse over
1497
- * the envelope preserves the JCS-canonical body bytes used by DSSE PAE.
1498
- *
1499
- * Threat model (Phase 5 CONTEXT.md security block):
1500
- * - PII via serialized state: callers MUST ensure SerializedSnapshot.payload
1501
- * contains only stable identifiers + user-controlled state the user has
1502
- * already consented to persist. Mirrors Phase 2 D-04 receipt-body contract
1503
- * (step-marker fields are stable identifiers, not free-form user input).
1504
- * - Snapshot tampering: the noop adapter does NOT sign the snapshot.
1505
- * Callers that need cryptographic integrity SHOULD embed a signed
1506
- * ReceiptEnvelope inside the payload + verify it on deserialize.
1507
- * Phase 5 ships the contract; signature wrapping is a follow-on.
1508
- *
1509
- * Vocabulary separation (carries forward Phase 2 D-12 + Phase 3 D-02):
1510
- * ResumePolicy is the survivability vocabulary -- separate from
1511
- * RunEventKind (tracing) AND separate from HookLifecycleEvent (bands).
1512
- * The three vocabularies meet only when a host runtime composes them.
1996
+ * Default band convention for the checkpoint hook (D-06). The caller is
1997
+ * free to register in a different band but the documented convention is
1998
+ * OBSERVABILITY -- between SAFETY (runs first) and EXTENSION (runs last).
1513
1999
  */
2000
+ declare const DEFAULT_CHECKPOINT_BAND: Band;
1514
2001
  /**
1515
- * String-encodable opaque snapshot. The host runtime defines the payload
1516
- * shape; Lattice's only requirement is that serialize() followed by
1517
- * deserialize() round-trips the original state object.
2002
+ * Per-step context the caller passes through the hook pipeline.
1518
2003
  *
1519
- * Why string-encodable? MV3's chrome.storage.session and most cross-process
1520
- * storage layers accept structured-clone-safe values. JSON-string payloads
1521
- * are the lowest-common-denominator that survives MV3 SW eviction +
1522
- * Cloudflare Worker freeze + Lambda thaw. Callers MAY use a richer payload
1523
- * shape (Uint8Array, Blob) IF the host runtime supports it; the contract
1524
- * does not constrain payload format beyond "deserialize round-trips it".
2004
+ * Fields are stable identifiers (D-04 carryforward); do NOT populate with
2005
+ * user content -- they appear cleartext in the signed receipt body.
2006
+ *
2007
+ * - stepName: required. Stable identifier for this step.
2008
+ * - stepIndex: required. Monotonically increasing ordinal; caller-owned.
2009
+ * - parentStepName: optional. Names the enclosing step when nested.
2010
+ * - previousStepName: optional. Names the immediately-prior step in the
2011
+ * linked-list timeline (D-09 linked-list threading).
2012
+ * - timestamp: required. ISO-8601 RFC 3339.
1525
2013
  */
1526
- interface SerializedSnapshot {
1527
- readonly kind: "survivability-snapshot";
1528
- readonly version: "lattice-survivability/v1";
1529
- readonly payload: string;
1530
- readonly capturedAt: string;
2014
+ interface CheckpointHookContext {
2015
+ readonly stepName: string;
2016
+ readonly stepIndex: number;
2017
+ readonly parentStepName?: string;
2018
+ readonly previousStepName?: string;
2019
+ readonly timestamp: string;
1531
2020
  }
1532
2021
  /**
1533
- * Pre-eviction callback. The host runtime CAN attempt to call this hook
1534
- * before the execution context is evicted, but MAY NOT be able to in
1535
- * every case (MV3 eviction has no synchronous signal -- the SW just
1536
- * stops). Callers should treat onEviction as best-effort: useful for
1537
- * gathering final state when the eviction is announced (e.g., user-
1538
- * initiated stop) but not load-bearing for involuntary eviction.
2022
+ * The factory's options.
1539
2023
  *
1540
- * The hook receives the current TState by reference. Mutations on the
1541
- * hook side leak to the caller's state -- this is deliberate (the hook
1542
- * is the LAST chance to update state before eviction). Callers who want
1543
- * structuredClone semantics SHOULD wrap state in their own freeze layer.
2024
+ * - runId: required. Threaded into every receipt body + every tracer event.
2025
+ * - tracer: optional. When omitted, the handler still mints (when signer
2026
+ * present) but does NOT emit a tracer event. When provided, the handler
2027
+ * ALWAYS emits exactly one event per invocation (independent of mint
2028
+ * success/failure per D-10).
2029
+ * - signer: optional. When omitted, the handler emits a tracer event only
2030
+ * (no mint attempted). When provided, the handler attempts to mint via
2031
+ * createReceipt(...) inside a try/catch (D-07 best-effort).
2032
+ * - sessionId: optional. Threaded into receipt body and event metadata.
2033
+ * - model: optional. ReceiptModel descriptor for the receipt body; the
2034
+ * factory provides a sensible "step" default when omitted.
2035
+ * - route: optional. ReceiptRoute descriptor for the receipt body; the
2036
+ * factory provides a sensible "step" default when omitted.
2037
+ * - contractVerdict: optional. Defaults to "success" -- step transitions
2038
+ * are observability events, not contract evaluations.
1544
2039
  */
1545
- type EvictionHook<TState> = (state: TState) => void | Promise<void>;
2040
+ interface CheckpointHookOptions {
2041
+ readonly runId: string;
2042
+ readonly tracer?: TracerLike;
2043
+ readonly signer?: ReceiptSigner;
2044
+ readonly sessionId?: string;
2045
+ readonly model?: ReceiptModel;
2046
+ readonly route?: ReceiptRoute;
2047
+ readonly contractVerdict?: CreateReceiptInput["contractVerdict"];
2048
+ }
1546
2049
  /**
1547
- * Return value of onEviction(); calling unsubscribes the hook.
2050
+ * Build a checkpoint hook handler.
1548
2051
  *
1549
- * Idempotent -- calling twice has the same effect as calling once.
2052
+ * The returned handler is suitable for registration on a HookPipeline
2053
+ * created via createHookPipeline (see ./bands.ts). The handler does not
2054
+ * auto-register; the caller passes it to pipeline.register(...) with the
2055
+ * desired lifecycle event (typically AFTER_TOOL or BEFORE_TOOL) and band
2056
+ * (typically BAND.OBSERVABILITY, exported as DEFAULT_CHECKPOINT_BAND).
2057
+ *
2058
+ * Per-invocation behavior:
2059
+ * 1. Build event metadata from options + per-call context.
2060
+ * 2. If signer is configured, attempt createReceipt(...) inside a
2061
+ * try/catch. On success, set metadata.receiptId + metadata.envelope.
2062
+ * On failure, set metadata.mintError (string from caught error).
2063
+ * 3. If tracer is configured, emit exactly one tracer.event?.(
2064
+ * STEP_TRANSITION_EVENT_NAME, metadata) call.
2065
+ * 4. Return void.
2066
+ *
2067
+ * NO upstream throw (D-07). NO global mutation (D-05).
1550
2068
  */
1551
- type UnsubscribeFn = () => void;
2069
+ declare function createCheckpointHook(options: CheckpointHookOptions): HookHandler<CheckpointHookContext>;
2070
+ //#endregion
2071
+ //#region src/contract/preflight.d.ts
1552
2072
  /**
1553
- * Resume policy taxonomy. The host runtime calls adapter.resume(snapshot)
1554
- * after eviction + restore; the returned policy tells the host runtime
1555
- * how to react.
2073
+ * Result of a single pre-flight contract evaluation against a candidate
2074
+ * capability. `reasons` is empty when `ok` is true and contains one or more
2075
+ * `RouteRejectReason` entries when `ok` is false.
1556
2076
  *
1557
- * The 4 literal members carry forward from FSB v0.10.0-attempt-1's
1558
- * 02-04-PLAN.md CONSERVATIVE recovery dispatch (preserved at
1559
- * .planning/milestones/v0.10.0-attempt-1-pre-pivot/02-state-inspectability-
1560
- * carve-out/02-04-PLAN.md). Per CONTEXT.md CD-E this is the locked union.
2077
+ * The evaluator surfaces ALL failing reasons in a single pass — not the
2078
+ * first-failing only so the deterministic router can aggregate per-candidate
2079
+ * rejection detail (CONTEXT.md "Pre-flight surfaces ALL failed candidates
2080
+ * with per-candidate rejection reasons").
1561
2081
  */
1562
- type ResumePolicy = "SAFE" | "RECOVERY_AMBIGUOUS" | "ON_ERROR_SW_EVICTION_MID_REQUEST" | "ON_ERROR_SW_EVICTION_MID_TOOL_DISPATCH";
2082
+ interface ContractPreflightResult {
2083
+ readonly ok: boolean;
2084
+ readonly reasons: readonly RouteRejectReason[];
2085
+ }
1563
2086
  /**
1564
- * The SurvivabilityAdapter contract. Host runtimes implement this; Lattice
1565
- * runs against the interface.
1566
- *
1567
- * 4 methods (D-08 locked):
1568
- * - serialize(state): convert in-memory state to SerializedSnapshot
1569
- * - deserialize(snapshot): inverse of serialize
1570
- * - onEviction(hook): register a best-effort pre-eviction callback
1571
- * - resume(snapshot): return ResumePolicy verdict for the post-restore
1572
- * reconstruction. The host runtime acts on the policy.
1573
- *
1574
- * Adapters are POLYMORPHIC over TState -- the host runtime parameterizes
1575
- * the type. Lattice's vitest covers the contract surface with a noop
1576
- * adapter where TState = Record<string, unknown> for ergonomics.
2087
+ * Input for the pure cost estimator. Token counts come from the router's
2088
+ * existing `estimateRoute()` helper so preflight and router agree on the
2089
+ * projected output size (one source of truth — see `evaluateContractAgainstRoute`).
1577
2090
  */
1578
- interface SurvivabilityAdapter<TState> {
1579
- readonly kind: "survivability-adapter";
1580
- readonly id: string;
1581
- serialize(state: TState): SerializedSnapshot;
1582
- deserialize(snapshot: SerializedSnapshot): TState;
1583
- onEviction(hook: EvictionHook<TState>): UnsubscribeFn;
1584
- resume(snapshot: SerializedSnapshot): Promise<ResumePolicy>;
2091
+ interface EstimateRouteCostInput {
2092
+ readonly capability: ModelCapability;
2093
+ readonly estimatedInputTokens: number;
2094
+ readonly estimatedOutputTokens: number;
1585
2095
  }
1586
2096
  /**
1587
- * Factory options for the reference noop adapter.
1588
- *
1589
- * - id: optional. Defaults to "noop-survivability". Useful when callers
1590
- * want to distinguish multiple adapter instances in test fixtures.
1591
- * - policy: optional. Sets the default ResumePolicy returned by resume().
1592
- * Defaults to "SAFE" (matches noop adapter semantics: no recovery
1593
- * ambiguity if nothing was ever persisted).
2097
+ * Pure cost estimator. Returns `null` when pricing is unknown (so downstream
2098
+ * gates can distinguish "free / zero" from "unmeasured" per the Phase 7
2099
+ * cost-normalization decision). Uses static catalog metadata only — no probes,
2100
+ * no external pricing APIs.
1594
2101
  */
1595
- interface NoopSurvivabilityAdapterOptions {
1596
- readonly id?: string;
1597
- readonly policy?: ResumePolicy;
2102
+ declare function estimateRouteCost(input: EstimateRouteCostInput): number | null;
2103
+ /** Input for the pre-flight evaluator. */
2104
+ interface EvaluateContractInput {
2105
+ readonly capability: ModelCapability;
2106
+ readonly estimatedInputTokens: number;
2107
+ readonly estimatedOutputTokens: number;
1598
2108
  }
1599
2109
  /**
1600
- * Reference implementation of SurvivabilityAdapter<TState>. Records
1601
- * eviction events but does NOT persist; serialize / deserialize round-
1602
- * trip via JSON.stringify / JSON.parse. Analog to createFakeProvider
1603
- * in the providers/ module -- gives Lattice's vitest a complete shape-
1604
- * conformance target before the real (FSB-side) adapter ships in
1605
- * Plan 05-05.
2110
+ * Pure pre-flight evaluator. Phase 9 receipts will reuse this for deterministic
2111
+ * verdict reconstruction.
1606
2112
  *
1607
- * Per CONTEXT.md D-11 the noop adapter ships in Lattice (not FSB)
1608
- * because it covers the contract surface in Lattice's own test suite;
1609
- * FSB's real chrome.storage.session-backed adapter is glue layer.
2113
+ * Token estimation: Phase 7 does NOT define a separate token estimator. Output-
2114
+ * token projection is the canonical responsibility of the router's existing
2115
+ * `estimateRoute()` helper (in `routing/router.ts`), which already produces an
2116
+ * `estimatedOutputTokens` value. The router passes that same value into this
2117
+ * evaluator via `EvaluateContractInput.estimatedOutputTokens`, so preflight
2118
+ * and the router always agree on the projected output size. Phase 9 receipts
2119
+ * will pin the router's estimate as the deterministic input — intentionally
2120
+ * one source of truth.
2121
+ *
2122
+ * Reject taxonomy (Phase 7 emits three of four codes):
2123
+ * - `contract-budget-exceeded` (CONTRACT-04 + COST-03)
2124
+ * - `contract-modality-missing` (CONTRACT-06)
2125
+ * - `contract-privacy-mismatch` (CONTRACT-06)
2126
+ * - `contract-quality-floor` (reserved for Phase 12 `lattice eval`; NEVER emitted here)
1610
2127
  */
1611
- declare function createNoopSurvivabilityAdapter<TState = Record<string, unknown>>(options?: NoopSurvivabilityAdapterOptions): SurvivabilityAdapter<TState>;
2128
+ declare function evaluateContractAgainstRoute(contract: CapabilityContract | undefined, input: EvaluateContractInput): ContractPreflightResult;
1612
2129
  //#endregion
1613
- //#region src/tools/tools.d.ts
1614
- interface ToolExecutionContext {
1615
- readonly signal?: AbortSignal;
1616
- readonly emit?: RunEventSink;
1617
- }
1618
- interface ToolDefinition<TSchema extends StandardSchemaV1 = StandardSchemaV1> {
1619
- readonly kind: "tool";
1620
- readonly name: string;
1621
- readonly description?: string;
1622
- readonly inputSchema: TSchema;
1623
- readonly execute: (input: StandardSchemaV1.InferOutput<TSchema>, context: ToolExecutionContext) => Promise<unknown> | unknown;
1624
- }
1625
- interface ToolCallResult {
1626
- readonly callId: string;
1627
- readonly toolName: string;
1628
- readonly artifact: ArtifactInput;
1629
- }
1630
- declare function defineTool<TSchema extends StandardSchemaV1>(definition: Omit<ToolDefinition<TSchema>, "kind">): ToolDefinition<TSchema>;
1631
- declare function runTool<TSchema extends StandardSchemaV1>(tool: ToolDefinition<TSchema>, input: unknown, context?: ToolExecutionContext): Promise<ToolCallResult>;
1632
- interface McpLikeClient {
1633
- readonly listTools?: () => Promise<readonly McpToolDescriptor[]> | readonly McpToolDescriptor[];
1634
- readonly callTool: (input: {
1635
- readonly name: string;
1636
- readonly arguments: unknown;
1637
- }) => Promise<unknown> | unknown;
1638
- }
1639
- interface McpToolDescriptor {
1640
- readonly name: string;
1641
- readonly description?: string;
1642
- readonly inputSchema: StandardSchemaV1;
2130
+ //#region src/receipts/keyset.d.ts
2131
+ /**
2132
+ * In-memory KeySet factory.
2133
+ *
2134
+ * Verification flow (plan 09-03):
2135
+ * - keySet.lookup(kid) returns undefined → VerifyError {kind: "key-not-found"}
2136
+ * - entry.state === "revoked" → VerifyError {kind: "key-revoked"}
2137
+ * - entry.state === "retired" → VerifyOk + keyState: "retired" (caller may warn)
2138
+ * - entry.state === "active" → VerifyOk + keyState: "active"
2139
+ *
2140
+ * Duplicate kids: last write wins (deterministic callers control entry order).
2141
+ * Empty entries array is legal — every lookup returns undefined.
2142
+ * Returned KeySet exposes only `lookup` — no enumeration.
2143
+ *
2144
+ * See 09-CONTEXT.md "Key Management (UNRETROFITTABLE)".
2145
+ */
2146
+ declare function createMemoryKeySet(entries: readonly KeyEntry[]): KeySet;
2147
+ //#endregion
2148
+ //#region src/receipts/sign.d.ts
2149
+ interface GeneratedEd25519KeyPair {
2150
+ readonly privateKeyJwk: JsonWebKey;
2151
+ readonly publicKeyJwk: JsonWebKey;
1643
2152
  }
1644
- declare function importMcpTools(client: McpLikeClient, toolNames?: readonly string[]): Promise<readonly ToolDefinition[]>;
1645
- declare function toolArtifactRef(result: ToolCallResult): ArtifactRef;
2153
+ declare function generateEd25519KeyPairJwk(): Promise<GeneratedEd25519KeyPair>;
2154
+ declare function createInMemorySigner(privateKeyJwk: JsonWebKey, options: {
2155
+ readonly kid: string;
2156
+ readonly publicKeyJwk: JsonWebKey;
2157
+ }): ReceiptSigner;
1646
2158
  //#endregion
1647
- //#region src/agent/format-tools.d.ts
2159
+ //#region src/receipts/verify.d.ts
1648
2160
  /**
1649
- * One turn in the running conversation.
2161
+ * Pure receipt verifier.
1650
2162
  *
1651
- * `role: "tool"` is used for tool-result turns; `toolCallId` and `toolName`
1652
- * are populated so the model can correlate the result with its prior
1653
- * `tool_call` envelope.
2163
+ * Returns a typed VerifyResult never throws across the verification
2164
+ * boundary (PITFALLS.md security: "Verifier panics on malformed receipts
2165
+ * -> DoS via crafted input"). All parsing failures become typed errors.
2166
+ *
2167
+ * Decision tree (first match wins):
2168
+ * 1. decodeEnvelope throws OR signatures[] empty -> envelope-malformed
2169
+ * 2. payload bytes are not valid JSON -> envelope-malformed
2170
+ * 3. body shape check fails OR version unknown literal -> version-mismatch
2171
+ * 4. body.version === undefined OR "lattice-receipt/v1"-> schema-version-too-low (CRYPTO-01)
2172
+ * 5. keySet.lookup(keyid) === undefined -> key-not-found
2173
+ * 6. entry.state === "revoked" -> key-revoked
2174
+ * 7. re-canonicalized body != signed payloadBytes -> canonicalization-mismatch
2175
+ * 8. Ed25519 verification of PAE fails -> signature-invalid
2176
+ * 9. body.kid !== entry.kid (defense in depth) -> signature-invalid
2177
+ * 10. otherwise -> ok + keyState
1654
2178
  */
1655
- interface ConversationTurn {
1656
- readonly role: "user" | "assistant" | "tool";
1657
- readonly content: string;
1658
- readonly toolCallId?: string;
1659
- readonly toolName?: string;
1660
- }
1661
- type FormatToolsMode = "native" | "prompt-reencoded" | "auto";
1662
- interface FormatToolsOptions {
2179
+ declare function verifyReceipt(envelope: ReceiptEnvelope, keySet: KeySet): Promise<VerifyResult>;
2180
+ //#endregion
2181
+ //#region src/sanitizers/sanitizers.d.ts
2182
+ interface SanitizerContext {
2183
+ readonly providerId: string;
2184
+ readonly modelId?: string;
2185
+ readonly outputName: string;
2186
+ }
2187
+ type SanitizerFn = (text: string, context: SanitizerContext) => string | Promise<string>;
2188
+ type SanitizeOutputOption = SanitizerFn | readonly SanitizerFn[];
2189
+ interface InternalEnvelopeOptions {
2190
+ readonly field?: string;
2191
+ readonly path?: string;
2192
+ readonly schema?: StandardSchemaV1;
2193
+ }
2194
+ declare function stripReasoningTags(): SanitizerFn;
2195
+ declare function stripChatTemplateArtifacts(): SanitizerFn;
2196
+ declare function unwrapInternalEnvelope(schemaOrPath: string | InternalEnvelopeOptions | StandardSchemaV1): SanitizerFn;
2197
+ //#endregion
2198
+ //#region src/providers/adapters.d.ts
2199
+ interface OpenAICompatibleProviderOptions {
2200
+ readonly id?: string;
2201
+ readonly model: string;
2202
+ readonly baseUrl: string;
2203
+ readonly apiKey?: string;
2204
+ readonly fetch?: typeof fetch;
1663
2205
  /**
1664
- * Tool-use protocol mode. Defaults to `"auto"`, which currently resolves
1665
- * to `"prompt-reencoded"` for ALL 7 providers (Phase 19 simplification —
1666
- * native tool_use deferred to a follow-on milestone). Reserved for
1667
- * forward compatibility.
2206
+ * Phase 7 addition: caller-supplied per-1k pricing. When provided, the
2207
+ * adapter computes `normalizedUsage.costUsd` from the API-reported token
2208
+ * counts. When omitted, `normalizedUsage.costUsd` is `null` so downstream
2209
+ * consumers can distinguish "unmeasured" from "free" (per 07-CONTEXT.md).
1668
2210
  */
1669
- readonly mode?: FormatToolsMode;
2211
+ readonly pricing?: {
2212
+ readonly inputPer1kTokens?: number;
2213
+ readonly outputPer1kTokens?: number;
2214
+ };
1670
2215
  /**
1671
- * Optional system prompt to prepend. Useful for setting persona /
1672
- * domain-specific instructions on top of the tool-use envelope.
2216
+ * Phase 34 D-05/D-06/D-08 TTL for the per-instance models cache.
2217
+ * Default 300_000ms (5 minutes). Set to 0 to disable caching.
2218
+ * Set to Infinity for process-lifetime caching.
2219
+ *
2220
+ * NOTE: for createOpenAICompatibleProvider, this option is accepted for
2221
+ * option-bag uniformity but is NOT USED — openai-compat has no /models
2222
+ * endpoint (D-04). Document in JSDoc for consumers pointing at known servers.
1673
2223
  */
1674
- readonly system?: string;
1675
- }
1676
- interface FormattedToolsHandle {
2224
+ readonly modelsCacheTtlMs?: number;
1677
2225
  /**
1678
- * Builds the single `task` string passed to `ProviderAdapter.execute()`.
1679
- * Encodes the conversation, available tools, and response-envelope
1680
- * instructions.
2226
+ * Phase 34 D-11 Number of retry attempts on transient /models errors
2227
+ * (5xx, network, timeout). Default 2. Set to 0 to disable retries.
2228
+ *
2229
+ * NOTE: for createOpenAICompatibleProvider, this option is accepted for
2230
+ * option-bag uniformity but is NOT USED — openai-compat has no /models
2231
+ * endpoint (D-04).
1681
2232
  */
1682
- readonly buildTask: (conversation: readonly ConversationTurn[]) => string;
2233
+ readonly modelsRetryCount?: number;
1683
2234
  /**
1684
- * Parses the assistant's response text. Returns:
1685
- * - `ToolUseRequest[]` when the response contains one or more tool-call
1686
- * envelopes (parsed in declaration order).
1687
- * - `null` when the response is a final answer (no tool-call envelopes
1688
- * detected).
2235
+ * Phase 34 D-12 — Optional RunEventSink for capability negotiation events.
2236
+ * When provided, emits the "capabilities.negotiation.fallback" event on
2237
+ * transient /models errors (5xx, network, timeout).
1689
2238
  *
1690
- * The parser is forgiving: it tolerates extra prose around the JSON
1691
- * envelope (markdown fences, leading explanations) and the model
1692
- * occasionally drifting on whitespace.
2239
+ * NOTE: for createOpenAICompatibleProvider, this option is accepted for
2240
+ * option-bag uniformity but the event is NOT FIRED for source: "registry"
2241
+ * (the documented happy path for openai-compat). Emitting events for the
2242
+ * intentional no-endpoint path would produce noisy false-positives.
1693
2243
  */
1694
- readonly parseToolUse: (responseText: string) => ReadonlyArray<ToolUseRequest> | null;
2244
+ readonly runEventSink?: RunEventSink;
1695
2245
  /**
1696
- * Returns the static system block describing available tools. Useful for
1697
- * tracing / logging the exact tool-description text fed to the model.
2246
+ * Phase 36 Optional output sanitizer pipeline. When provided, string
2247
+ * rawOutputs are transformed in order after provider text extraction and
2248
+ * before the adapter returns.
1698
2249
  */
1699
- readonly describeForSystem: () => string;
2250
+ readonly sanitizeOutput?: SanitizeOutputOption;
1700
2251
  /**
1701
- * Effective mode this handle resolved to (`"prompt-reencoded"` for all
1702
- * v1.2 providers). Exposed for inspectability.
2252
+ * Phase 37 Optional returned tool-call validator. When provided, the
2253
+ * adapter parses prompt-reencoded tool_calls envelopes and returns
2254
+ * normalized validated calls without mutating rawOutputs or rawResponse.
1703
2255
  */
1704
- readonly mode: "prompt-reencoded";
2256
+ readonly validateToolCalls?: ValidateToolCallsOption;
2257
+ }
2258
+ interface SdkLikeProviderOptions {
2259
+ readonly id?: string;
2260
+ readonly model: string;
2261
+ readonly generate: (input: {
2262
+ readonly task: string;
2263
+ readonly outputNames: readonly string[];
2264
+ }) => Promise<ProviderRunResponse> | ProviderRunResponse;
1705
2265
  }
1706
2266
  /**
1707
- * Convert a Standard Schema to a JSON Schema-shaped descriptor suitable for
1708
- * inclusion in an LLM tool description. Standard Schema vendors can
1709
- * optionally expose `toJSONSchema` on their schema objects; when absent,
1710
- * we fall back to a minimal structural description that lists the schema
1711
- * vendor + version + a placeholder. Models tolerate placeholder schemas in
1712
- * practice because the tool description is supplementary — what matters
1713
- * is the envelope contract (`{tool_call: {name, args}}`).
1714
- */
1715
- declare function toolSchemaToJsonSchema(schema: StandardSchemaV1): unknown;
1716
- /**
1717
- * Builds the prompt-reencoded tool-use protocol handle for any provider.
2267
+ * Phase 34 D-04 / QUIRK-02 OpenAI-compatible provider factory.
1718
2268
  *
1719
- * Phase 19 ships a uniform implementation across all 7 logical providers
1720
- * (openai, openai-compat, anthropic, gemini, xai, openrouter, lm-studio).
1721
- * The `providerName` argument is accepted for forward compatibility but
1722
- * does not branch the implementation in v1.2.
2269
+ * This factory is the prototypical "intentional no remote /models endpoint"
2270
+ * adapter per D-04. The consumer points this adapter at any OpenAI-shaped
2271
+ * endpoint (vLLM, TGI, Ollama, custom), and the factory returns conservative
2272
+ * defaults for the quirks block because the server could be anything.
2273
+ *
2274
+ * The `negotiateCapabilities` method performs NO fetch; it returns
2275
+ * synthesizeNegotiatedCapabilitiesFromRegistry with source: "registry"
2276
+ * (the intentional-no-endpoint signal, as distinct from "registry-fallback"
2277
+ * which signals a transient failure). Plan 34-05 (LM Studio) reuses this
2278
+ * same pattern.
2279
+ *
2280
+ * D-04 citation: "consumer adapters without a /models endpoint skip the
2281
+ * fetch layer entirely and delegate to synthesizeNegotiatedCapabilitiesFromRegistry."
1723
2282
  */
1724
- declare function formatToolsForProvider(providerName: string, tools: ReadonlyArray<ToolDefinition<StandardSchemaV1>>, options?: FormatToolsOptions): FormattedToolsHandle;
1725
- //#endregion
1726
- //#region src/agent/host.d.ts
2283
+ declare function createOpenAICompatibleProvider(options: OpenAICompatibleProviderOptions): ProviderAdapter & {
2284
+ readonly quirks: OpenAICompatQuirks;
2285
+ readonly negotiateCapabilities: (modelId: string) => Promise<NegotiatedCapabilities>;
2286
+ };
1727
2287
  /**
1728
- * Snapshot shape the agent loop serializes between iterations. The full
1729
- * shape is opaque to callers (they only see it through SerializedSnapshot
1730
- * via the configured SurvivabilityAdapter) but it's exported so reference
1731
- * implementations and tests can inspect the round-trip.
1732
- */
1733
- interface AgentSnapshot {
1734
- readonly version: "agent-snapshot/v1";
1735
- readonly iterationIndex: number;
1736
- readonly conversation: readonly ConversationTurn[];
1737
- readonly cumulativeUsage: Usage;
1738
- readonly providerName: string;
1739
- readonly capturedAt: string;
1740
- }
2288
+ * Phase 34 QUIRK-02 / NEG-01 / NEG-02 OpenAI provider factory.
2289
+ *
2290
+ * Extends the base OpenAI-compat factory with:
2291
+ * 1. `quirks: OpenAIQuirks` verified per RESEARCH §Q6 OpenAI vocabulary.
2292
+ * 2. `negotiateCapabilities(modelId)` — queries OpenAI /v1/models GET with
2293
+ * Authorization: Bearer header; SPARSE response; intersects with Phase 33
2294
+ * registry for supports.* (per RESEARCH §Anti-patterns — don't assume
2295
+ * OpenAI /v1/models returns capability flags, it doesn't).
2296
+ *
2297
+ * The negotiate() pattern mirrors Plan 34-02 (Anthropic thick reference):
2298
+ * - Per-instance TTL cache (modelsCacheTtlMs, default 300_000ms)
2299
+ * - Single-flight inflight coalescing with .finally cleanup (Pitfall 4)
2300
+ * - Retry with [0, 200, 1000]ms backoff (modelsRetryCount, default 2)
2301
+ * - 401/403 throws NegotiationAuthError (D-10: no retry, no fallback, no event)
2302
+ * - 5xx/network/timeout falls back to registry with source: "registry-fallback"
2303
+ * - emitFallbackEvent fires the "capabilities.negotiation.fallback" RunEvent
2304
+ *
2305
+ * SECURITY (T-34-03-07): inflight Map MUST use .finally cleanup to prevent
2306
+ * leak on rejection. Verifiable: grep `.finally` in this file.
2307
+ */
2308
+ declare function createOpenAIProvider(options: OpenAICompatibleProviderOptions): ProviderAdapter & {
2309
+ readonly quirks: OpenAIQuirks;
2310
+ readonly negotiateCapabilities: (modelId: string) => Promise<NegotiatedCapabilities>;
2311
+ };
2312
+ declare function createAISdkProvider(options: SdkLikeProviderOptions): ProviderAdapter;
2313
+ //#endregion
2314
+ //#region src/providers/anthropic.d.ts
1741
2315
  /**
1742
- * Scheduler seam controls how the agent loop yields between iterations.
2316
+ * Options for {@link createAnthropicProvider}.
1743
2317
  *
1744
- * `scheduleNext(iterationIndex)` is called AFTER an AFTER_AGENT_ITERATION
1745
- * emission and BEFORE the next iteration's BEFORE_AGENT_ITERATION. The
1746
- * scheduler decides when to resume synchronously (sync loop), on next
1747
- * tick (setTimeout/queueMicrotask), via a queue (Durable Object), or any
1748
- * other strategy.
2318
+ * Mirrors `OpenAICompatibleProviderOptions` ergonomics (Phase 7 pattern) but
2319
+ * for the Anthropic Messages API at `/v1/messages` -- which uses a top-level
2320
+ * `system` field and a `content[0].text` response shape that diverges from
2321
+ * the OpenAI Chat Completions schema (see FSB v0.9.x `extension/ai/universal-provider.js`
2322
+ * lines 280-297 + 566-573 for the production reference).
1749
2323
  *
1750
- * Default (noop): resolves immediately.
2324
+ * SECURITY: `apiKey` is a runtime parameter -- do NOT hardcode or log it.
2325
+ *
2326
+ * DEFERRED (Phase 4 carryforward notes):
2327
+ * - prompt caching (Phase 39: opt-in via `ProviderRunRequest.cacheSystemPrefix` —
2328
+ * emitted as a cache_control-marked system block when present)
2329
+ * - streaming (deferred; this adapter is single-shot Promise -- per CONTEXT.md D-06)
2330
+ * - tool use (Anthropic tool_use blocks are deferred)
2331
+ * - resume-from-eviction -- see Phase 5 (MV3-survivability adapter contract)
2332
+ *
2333
+ * Ref: FSB v0.10.0-attempt-2 Phase 4 (D-02 + D-07: full custom adapter; preserve top-level `system`).
1751
2334
  */
1752
- interface AgentScheduler {
1753
- scheduleNext(iterationIndex: number): Promise<void>;
2335
+ interface AnthropicProviderOptions {
2336
+ readonly id?: string;
2337
+ readonly model: string;
2338
+ readonly apiKey: string;
2339
+ /** Defaults to `https://api.anthropic.com`. Override for proxies. */
2340
+ readonly baseUrl?: string;
2341
+ /** Defaults to `2023-06-01`. Override only if the consumer has tested a newer pinned version. */
2342
+ readonly anthropicVersion?: string;
2343
+ readonly fetch?: typeof fetch;
2344
+ readonly pricing?: {
2345
+ readonly inputPer1kTokens?: number;
2346
+ readonly outputPer1kTokens?: number;
2347
+ };
2348
+ /**
2349
+ * D-08: Per-instance TTL for the /v1/models response cache (milliseconds).
2350
+ * Default 300_000 (5 minutes). `0` disables caching (always re-fetch -- for testing).
2351
+ * `Infinity` disables expiry (process-lifetime for the instance).
2352
+ */
2353
+ readonly modelsCacheTtlMs?: number;
2354
+ /**
2355
+ * D-11: Number of retries for transient /v1/models fetch failures (5xx, network,
2356
+ * timeout). Default 2 (3 total attempts). `0` disables retries.
2357
+ * Backoff schedule: [0ms, 200ms, 1000ms].
2358
+ */
2359
+ readonly modelsRetryCount?: number;
2360
+ /**
2361
+ * D-12: Optional RunEventSink for emitting `capabilities.negotiation.fallback`
2362
+ * events when the /v1/models fetch falls back to the Phase 33 static registry.
2363
+ * If absent, fallback emits no event (no-op). Auth errors (401/403) never emit
2364
+ * the fallback event -- they throw `NegotiationAuthError` instead.
2365
+ */
2366
+ readonly runEventSink?: RunEventSink;
2367
+ readonly sanitizeOutput?: SanitizeOutputOption;
2368
+ readonly validateToolCalls?: ValidateToolCallsOption;
2369
+ }
2370
+ declare function createAnthropicProvider(options: AnthropicProviderOptions): ProviderAdapter & {
2371
+ readonly quirks: AnthropicQuirks;
2372
+ readonly negotiateCapabilities: (modelId: string) => Promise<NegotiatedCapabilities>;
2373
+ };
2374
+ //#endregion
2375
+ //#region src/providers/fake.d.ts
2376
+ interface FakeProviderOptions {
2377
+ readonly id?: string;
2378
+ readonly modelId?: string;
2379
+ readonly response?: ProviderRunResponse | ((request: ProviderRunRequest) => ProviderRunResponse | Promise<ProviderRunResponse>);
2380
+ readonly artifacts?: readonly ArtifactInput[];
2381
+ /**
2382
+ * Phase 7 addition: when provided, REPLACES the default single-capability
2383
+ * array so callers (notably Plan 07-04's modality/privacy reject tests)
2384
+ * can construct a fake adapter with arbitrary
2385
+ * `inputModalities` / `outputModalities` / `dataPolicy` / `pricing`
2386
+ * without mutating the returned adapter's readonly `capabilities` array.
2387
+ * When omitted, the existing default capability is used.
2388
+ */
2389
+ readonly capabilities?: readonly ModelCapability[];
1754
2390
  }
2391
+ declare function createFakeProvider(options?: FakeProviderOptions): ProviderAdapter;
2392
+ //#endregion
2393
+ //#region src/providers/gemini.d.ts
1755
2394
  /**
1756
- * Transport seam controls how a provider call is dispatched.
2395
+ * Options for {@link createGeminiProvider}.
1757
2396
  *
1758
- * `call(provider, request)` wraps the provider's `execute()` invocation.
1759
- * Default (noop): pass-through (`provider.execute!(request)`). Cross-process
1760
- * bridges (FSB's offscreen-document host) override to dispatch via
1761
- * `chrome.runtime.sendMessage`.
2397
+ * Mirrors `OpenAICompatibleProviderOptions` ergonomics (Phase 7 pattern) but
2398
+ * for Google's Generative Language API at
2399
+ * `/v1beta/models/{model}:generateContent` -- which uses `contents[].parts[].text`
2400
+ * (NOT OpenAI's `messages[]`), `role: "model"` for assistant turns (NOT
2401
+ * `"assistant"`), authenticates via `?key=` query string for execute(), and applies a
2402
+ * 4-category `safetySettings` block at `BLOCK_NONE` thresholds (FSB convention
2403
+ * mirrored from `extension/ai/universal-provider.js:255-272`).
1762
2404
  *
1763
- * Per the Phase 19 INV-03 parity invariant, the transport seam does NOT
1764
- * modify the `ProviderAdapter` interface — it operates on top of the
1765
- * existing `execute()` method.
2405
+ * SECURITY: `apiKey` is a runtime parameter -- do NOT hardcode or log it.
2406
+ *
2407
+ * DEFERRED (Phase 4 carryforward notes):
2408
+ * - multimodal (vision) -- deferred
2409
+ * - streaming -- deferred (single-shot Promise per CONTEXT.md D-06)
2410
+ * - tool use -- deferred
2411
+ * - resume-from-eviction -- see Phase 5 (MV3-survivability adapter contract)
2412
+ *
2413
+ * NOTE (Phase 34): negotiate() uses x-goog-api-key HEADER (preferred per RESEARCH §Q3).
2414
+ * The existing execute() path uses ?key= query string -- execute() migration is out-of-scope
2415
+ * for Phase 34 (additive only; T-34-04-01).
2416
+ *
2417
+ * Ref: FSB v0.10.0-attempt-2 Phase 4 (D-02 + D-07: full custom adapter; preserve role:"model").
1766
2418
  */
1767
- interface AgentTransport {
1768
- call(provider: ProviderAdapter, request: ProviderRunRequest): Promise<ProviderRunResponse>;
2419
+ interface GeminiProviderOptions {
2420
+ readonly id?: string;
2421
+ readonly model: string;
2422
+ readonly apiKey: string;
2423
+ /** Defaults to `https://generativelanguage.googleapis.com`. */
2424
+ readonly baseUrl?: string;
2425
+ readonly fetch?: typeof fetch;
2426
+ readonly pricing?: {
2427
+ readonly inputPer1kTokens?: number;
2428
+ readonly outputPer1kTokens?: number;
2429
+ };
2430
+ /**
2431
+ * D-08: TTL for per-instance /models response cache, in milliseconds.
2432
+ * Default: 300_000ms (5 minutes). 0 = always refetch (tests). Infinity = process-lifetime.
2433
+ */
2434
+ readonly modelsCacheTtlMs?: number;
2435
+ /**
2436
+ * D-11: Number of retries on transient /models fetch errors. Default: 2.
2437
+ * Retry schedule: immediate + 200ms + 1000ms (3 total attempts at retryCount=2).
2438
+ * 0 = no retries (1 attempt total).
2439
+ */
2440
+ readonly modelsRetryCount?: number;
2441
+ /**
2442
+ * D-12: Optional event sink for observability. When provided, the adapter
2443
+ * emits a "capabilities.negotiation.fallback" RunEvent on transient /models failure.
2444
+ * If absent, no event is emitted (silent fallback).
2445
+ */
2446
+ readonly runEventSink?: RunEventSink;
2447
+ readonly sanitizeOutput?: SanitizeOutputOption;
2448
+ readonly validateToolCalls?: ValidateToolCallsOption;
1769
2449
  }
1770
2450
  /**
1771
- * Storage seamcontrols how agent state persists between iterations for
1772
- * resume after host eviction.
2451
+ * Phase 34D-03 / D-05..D-12 Extended Gemini provider factory.
1773
2452
  *
1774
- * Phase 20 composes this with the Phase 18 `SurvivabilityAdapter`:
1775
- * - The adapter serializes `AgentSnapshot` to `SerializedSnapshot` on
1776
- * each AFTER_AGENT_ITERATION; storage.save() persists the snapshot.
1777
- * - On run start, the agent loop calls storage.load(). If a non-null
1778
- * snapshot is returned, the adapter deserializes it; the loop resumes
1779
- * at the recorded iteration index.
1780
- * - On success, the loop calls storage.clear() so the next run starts
1781
- * fresh.
2453
+ * Returns a `ProviderAdapter` narrowed to expose:
2454
+ * - `quirks: GeminiQuirks` static adapter capability flags
2455
+ * - `negotiateCapabilities(modelId)` live /v1beta/models fetch with medium-thick
2456
+ * derivation (inputTokenLimit + thinking + supportedGenerationMethods from upstream)
2457
+ * intersected with Phase 33 registry; TTL cache + inflight coalescing + retry +
2458
+ * auth-throw + transient-fallback + event.
1782
2459
  *
1783
- * Default (noop): save() is a no-op, load() returns null, clear() is a
1784
- * no-op. Suitable for Node tests where eviction never occurs.
2460
+ * NOTE on auth strategy (T-34-04-01): negotiate() uses x-goog-api-key HEADER
2461
+ * (preferred per RESEARCH §Q3 -- avoids leaking the key in server-side logs that
2462
+ * capture URL query strings). The existing execute() path uses ?key= query string
2463
+ * and is NOT changed by Phase 34 (out-of-scope migration).
1785
2464
  */
1786
- interface AgentStorage {
1787
- save(snapshot: SerializedSnapshot): Promise<void>;
1788
- load(): Promise<SerializedSnapshot | null>;
1789
- clear(): Promise<void>;
1790
- }
2465
+ declare function createGeminiProvider(options: GeminiProviderOptions): ProviderAdapter & {
2466
+ readonly quirks: GeminiQuirks;
2467
+ readonly negotiateCapabilities: (modelId: string) => Promise<NegotiatedCapabilities>;
2468
+ };
2469
+ //#endregion
2470
+ //#region src/providers/lm-studio.d.ts
1791
2471
  /**
1792
- * The host adapter — three optional seams, all swappable independently.
2472
+ * Options for {@link createLmStudioProvider}.
2473
+ *
2474
+ * Thin wrapper around {@link createOpenAICompatibleProvider} pinned to
2475
+ * LM Studio's default local server URL `http://localhost:1234/v1`. Wire
2476
+ * shape is OpenAI Chat Completions. LM Studio is no-auth by convention
2477
+ * (CD-03): `apiKey` is OPTIONAL; when omitted, the underlying factory
2478
+ * sends no `Authorization` header (see
2479
+ * `lattice/packages/lattice/src/providers/adapters.ts:53` for the
2480
+ * conditional auth-header wiring).
2481
+ *
2482
+ * Phase 34 additions:
2483
+ * - `modelsCacheTtlMs` -- Reserved for future /models discovery; LM Studio
2484
+ * currently has no remote /models endpoint. Accepted for option-bag
2485
+ * uniformity but NOT USED (D-04 intentional no-endpoint pattern).
2486
+ * - `runEventSink` -- Accepted for option-bag uniformity but NEVER fired
2487
+ * because source: "registry" is the documented happy path for LM Studio
2488
+ * (no event for intentional no-endpoint per RESEARCH Open Question 5).
2489
+ *
2490
+ * DEFERRED (D-16 carryforward):
2491
+ * - latency-tail diagnostics -- observability concern; LM Studio is
2492
+ * the canary for latency tails (INV-03);
2493
+ * diagnostics module deferred to a
2494
+ * follow-on observability phase.
2495
+ * - streaming -- deferred (single-shot per D-06).
2496
+ * - resume-from-eviction -- see Phase 5 (MV3-survivability adapter).
1793
2497
  *
1794
- * Callers pass `host` on `AgentIntent`. The agent runtime falls back to
1795
- * `createNoopAgentHost()` when `intent.host` is absent (so Phase 19
1796
- * single-shot Node usage continues to work without explicit configuration).
2498
+ * Ref: FSB v0.10.0-attempt-2 Phase 4 (D-03: thin wrapper; D-16: latency-tail deferred; CD-03 no-opt-out).
1797
2499
  */
1798
- interface AgentHost {
1799
- readonly kind: "agent-host";
1800
- readonly scheduler?: AgentScheduler;
1801
- readonly transport?: AgentTransport;
1802
- readonly storage?: AgentStorage;
2500
+ interface LmStudioProviderOptions extends Omit<OpenAICompatibleProviderOptions, "id" | "baseUrl" | "apiKey"> {
2501
+ readonly id?: string;
2502
+ /** Defaults to `http://localhost:1234/v1`. Override for non-localhost deployments. */
2503
+ readonly baseUrl?: string;
2504
+ /**
2505
+ * Optional. LM Studio is no-auth by convention (CD-03 default).
2506
+ * When provided, sent as `Authorization: Bearer <apiKey>` (matches the
2507
+ * underlying OpenAI-compat factory). Use only for proxied LM Studio
2508
+ * deployments that have a token gate in front.
2509
+ */
2510
+ readonly apiKey?: string;
1803
2511
  }
1804
2512
  /**
1805
- * Reference implementation suitable for Node tests + the Phase 19 default
1806
- * behavior.
2513
+ * Phase 34 D-04 / QUIRK-02 LM Studio provider factory.
1807
2514
  *
1808
- * - scheduler: resolves immediately (no yield between iterations).
1809
- * - transport: pass-through to provider.execute().
1810
- * - storage: save() / clear() are no-ops; load() always returns null.
2515
+ * LM Studio is the prototypical "intentional no remote /models endpoint"
2516
+ * adapter per D-04 (alongside OpenAI-compat). The factory returns conservative
2517
+ * defaults for the quirks block because LM Studio runs LOCAL quantized models
2518
+ * whose capabilities vary wildly by chat template + model file.
1811
2519
  *
1812
- * Equivalent to passing no host at all.
2520
+ * The `negotiateCapabilities` method performs NO fetch; it returns
2521
+ * `synthesizeNegotiatedCapabilitiesFromRegistry` with source: "registry"
2522
+ * (the intentional-no-endpoint signal, distinct from "registry-fallback"
2523
+ * which signals a transient failure). Mirrors Plan 34-03 Task 2 (OpenAI-compat
2524
+ * registry-only pattern) verbatim.
2525
+ *
2526
+ * D-04 citation: "consumer adapters without a /models endpoint skip the
2527
+ * fetch layer entirely and delegate to synthesizeNegotiatedCapabilitiesFromRegistry."
2528
+ *
2529
+ * Open Question 5 (RESEARCH §): no event emitted for source: "registry" because
2530
+ * this is the intentional happy path for LM Studio -- emitting a "fallback" event
2531
+ * would produce false-positive noise for consumers monitoring the event stream.
1813
2532
  */
1814
- declare function createNoopAgentHost(): AgentHost;
2533
+ declare function createLmStudioProvider(options: LmStudioProviderOptions): ProviderAdapter & {
2534
+ readonly quirks: LmStudioQuirks;
2535
+ readonly negotiateCapabilities: (modelId: string) => Promise<NegotiatedCapabilities>;
2536
+ };
1815
2537
  //#endregion
1816
- //#region src/agent/types.d.ts
2538
+ //#region src/providers/openrouter.d.ts
1817
2539
  /**
1818
- * Per-iteration record stored on `AgentSuccess.iterations` for inspectability.
2540
+ * Options for {@link createOpenRouterProvider}.
1819
2541
  *
1820
- * `toolCalls` carries content-addressed args/result hashes (sha256) so
1821
- * downstream receipts can reference them without inlining the bodies.
2542
+ * Thin wrapper around {@link createOpenAICompatibleProvider} pinned to
2543
+ * OpenRouter's base URL `https://openrouter.ai/api/v1`. Wire shape is
2544
+ * OpenAI Chat Completions; no provider-specific quirks at the
2545
+ * single-shot Promise contract level.
1822
2546
  *
1823
- * `deniedReason` is populated on iterations whose `BEFORE_AGENT_ITERATION`
1824
- * SAFETY-band handler set `controls.deny(...)`.
1825
- */
1826
- interface IterationRecord {
1827
- readonly index: number;
1828
- readonly provider: string;
1829
- readonly promptTokens: number;
1830
- readonly completionTokens: number;
1831
- readonly costUsd: number | null;
1832
- readonly durationMs: number;
1833
- readonly toolCalls: ReadonlyArray<{
1834
- readonly id: string;
1835
- readonly name: string;
1836
- readonly argsHash: string;
1837
- readonly resultHash: string;
1838
- }>;
1839
- readonly deniedReason?: string;
1840
- readonly receipt?: ReceiptEnvelope;
1841
- }
1842
- /**
1843
- * Input shape accepted by `ai.runAgent(intent)`.
2547
+ * SECURITY: `apiKey` is a runtime parameter -- do NOT hardcode or log it.
1844
2548
  *
1845
- * All fields except `task` and `tools` are optional. The runtime supplies
1846
- * sensible defaults (in-process host, fresh pipeline, no signer, no tracer).
2549
+ * DEFERRED (D-17 carryforward; Phase 4 ships the named adapter as a
2550
+ * first-class OpenAI-compat wrapper):
2551
+ * - model-routing array -- caller supplies `model` (single id); OpenRouter's
2552
+ * `models: [primary, fallback, ...]` array
2553
+ * feature is deferred to a follow-on phase.
2554
+ * - fallback-array -- deferred (same phase as model-routing).
2555
+ * - per-message routing -- deferred.
2556
+ * - streaming -- deferred (single-shot per CONTEXT.md D-06).
2557
+ * - resume-from-eviction -- see Phase 5 (MV3-survivability adapter).
1847
2558
  *
1848
- * `TOutputs` parameterizes the final-answer schema map; defaults to a free-form
1849
- * `{ answer: "text" }` shape when the field is omitted. Validation runs once
1850
- * against the final assistant message (no intermediate iteration validation).
2559
+ * Ref: FSB v0.10.0-attempt-2 Phase 4 (D-03: thin wrapper; D-17: model-routing deferred).
1851
2560
  */
1852
- interface AgentIntent<TOutputs extends OutputContractMap = OutputContractMap> {
1853
- readonly task: string;
1854
- readonly tools: ReadonlyArray<ToolDefinition<StandardSchemaV1>>;
1855
- readonly host?: AgentHost;
2561
+ interface OpenRouterProviderOptions extends Omit<OpenAICompatibleProviderOptions, "id" | "baseUrl"> {
2562
+ readonly id?: string;
2563
+ /** Defaults to `https://openrouter.ai/api/v1`. Override for proxies. */
2564
+ readonly baseUrl?: string;
1856
2565
  /**
1857
- * Phase 20 (v1.2): when the agent loop resumes from a host.storage snapshot,
1858
- * the configured SurvivabilityAdapter handles the serialize/deserialize
1859
- * round-trip. When absent, runtime defaults to
1860
- * `createNoopSurvivabilityAdapter<AgentSnapshot>()`.
2566
+ * D-08: TTL for per-instance /models response cache, in milliseconds.
2567
+ * Default: 300_000ms (5 minutes). 0 = always refetch (tests). Infinity = process-lifetime.
1861
2568
  */
1862
- readonly survivabilityAdapter?: SurvivabilityAdapter<AgentSnapshot>;
1863
- readonly contract?: CapabilityContract;
1864
- readonly policy?: PolicySpec;
1865
- readonly outputs?: TOutputs;
1866
- readonly pipeline?: HookPipeline;
1867
- readonly signer?: ReceiptSigner;
1868
- readonly tracer?: TracerLike;
2569
+ readonly modelsCacheTtlMs?: number;
1869
2570
  /**
1870
- * When `false`, the runtime will NOT auto-register `createCheckpointHook`
1871
- * even if `signer` is provided. Callers who want full manual control over
1872
- * receipt minting set this to `false` and register their own hook.
1873
- * Defaults to `true` (auto-register when signer present).
2571
+ * D-11: Number of retries on transient /models fetch errors. Default: 2.
2572
+ * Retry schedule: immediate + 200ms + 1000ms (3 total attempts at retryCount=2).
2573
+ * 0 = no retries (1 attempt total).
1874
2574
  */
1875
- readonly autoRegisterCheckpoint?: boolean;
1876
- }
2575
+ readonly modelsRetryCount?: number;
2576
+ /**
2577
+ * D-12: Optional event sink for observability. When provided, the adapter
2578
+ * emits a "capabilities.negotiation.fallback" RunEvent on transient /models failure.
2579
+ * If absent, no event is emitted (silent fallback).
2580
+ */
2581
+ readonly runEventSink?: RunEventSink;
2582
+ }
2583
+ /**
2584
+ * Phase 34 — D-03 / D-05..D-12 — Extended OpenRouter provider factory.
2585
+ *
2586
+ * Returns a `ProviderAdapter` narrowed to expose:
2587
+ * - `quirks: OpenRouterQuirks` — static adapter capability flags (8 booleans)
2588
+ * - `negotiateCapabilities(modelId)` — live /api/v1/models fetch with rich /models
2589
+ * intersection (supported_parameters -> nativeToolCalling + structuredOutputs,
2590
+ * top_provider.context_length -> contextWindow) intersected with Phase 33 registry
2591
+ * for knownFailureModes + recommendedSanitizers.
2592
+ *
2593
+ * CRITICAL for ANCHOR CASE STUDY (session_1780792387779):
2594
+ * negotiate("openai/gpt-oss-120b:free") MUST resolve to:
2595
+ * - result.knownFailureModes.includes("internal_envelope_leak") -> TRUE
2596
+ * - result.recommendedSanitizers.includes("unwrapInternalEnvelope") -> TRUE
2597
+ * - result.source === "live" -> TRUE
2598
+ * This proves: live-fetch -> id suffix-strip via stripOpenRouterVariant
2599
+ * -> registry intersection -> getRecommendedSanitizers derivation.
2600
+ *
2601
+ * Anti-pattern (RESEARCH §Anti-pattern, lines 534-535):
2602
+ * The /api/v1/models endpoint is UNAUTHENTICATED (public discovery surface verified
2603
+ * Phase 33). Do NOT send Authorization Bearer to this endpoint -- it is NOT required
2604
+ * and would add unnecessary API key exposure surface in transit logs.
2605
+ */
2606
+ declare function createOpenRouterProvider(options: OpenRouterProviderOptions): ProviderAdapter & {
2607
+ readonly quirks: OpenRouterQuirks;
2608
+ readonly negotiateCapabilities: (modelId: string) => Promise<NegotiatedCapabilities>;
2609
+ };
2610
+ //#endregion
2611
+ //#region src/providers/xai.d.ts
1877
2612
  /**
1878
- * Success result returned by `ai.runAgent` when the loop reaches a final
1879
- * answer and (when `outputs` is declared) the final answer validates.
2613
+ * Options for {@link createXaiProvider}.
1880
2614
  *
1881
- * `iterations[]` records every iteration that ran — including the one that
1882
- * produced the final answer. `receipt` is the outermost receipt minted at
1883
- * loop close when `signer` is configured (separate from per-iteration
1884
- * receipts on `iterations[i].receipt`).
2615
+ * Thin wrapper around {@link createOpenAICompatibleProvider} pinned to
2616
+ * xAI's base URL `https://api.x.ai/v1`. The wire shape is identical to
2617
+ * OpenAI Chat Completions, with one provider-specific quirk preserved:
2618
+ * `response.usage.completion_tokens_details.reasoning_tokens` (xAI's
2619
+ * separate reasoning-token accounting; see FSB
2620
+ * `extension/ai/universal-provider.js:585-594` for the production reference).
2621
+ *
2622
+ * SECURITY: `apiKey` is a runtime parameter -- do NOT hardcode or log it.
2623
+ *
2624
+ * DEFERRED (Phase 4 carryforward notes):
2625
+ * - tool-streaming -- deferred
2626
+ * - streaming -- deferred (single-shot Promise per CONTEXT.md D-06)
2627
+ * - resume-from-eviction -- see Phase 5 (MV3-survivability adapter contract)
2628
+ *
2629
+ * Ref: FSB v0.10.0-attempt-2 Phase 4 (D-03 + D-07: thin wrapper; reasoning_tokens quirk preserved).
2630
+ *
2631
+ * Phase 34 additions:
2632
+ * - `modelsCacheTtlMs?` — D-05/D-06/D-08; default 300_000ms; 0 disables; Infinity = process-lifetime
2633
+ * - `modelsRetryCount?` — D-11; default 2; 0 disables retry
2634
+ * - `runEventSink?` — D-12; fires "capabilities.negotiation.fallback" on transient errors
1885
2635
  */
1886
- interface AgentSuccess<TOutputs extends OutputContractMap = OutputContractMap> {
1887
- readonly kind: "success";
1888
- readonly output: InferOutputMap<TOutputs>;
1889
- readonly usage: Usage;
1890
- readonly iterations: ReadonlyArray<IterationRecord>;
1891
- readonly receipt?: ReceiptEnvelope;
2636
+ interface XaiProviderOptions extends Omit<OpenAICompatibleProviderOptions, "id" | "baseUrl"> {
2637
+ readonly id?: string;
2638
+ /** Defaults to `https://api.x.ai/v1`. Override for proxies. */
2639
+ readonly baseUrl?: string;
1892
2640
  }
1893
2641
  /**
1894
- * Failure kinds specific to the agent loop. v1.1 `LatticeRunError.kind`
1895
- * values remain valid (provider errors, no-contract-match, validation-failed,
1896
- * tripwire-violated) and are reused verbatim. Phase 19 adds three
1897
- * agent-specific kinds.
1898
- */
1899
- type AgentFailureKind = LatticeRunError["kind"] | "agent-iteration-denied" | "agent-max-iterations" | "agent-wall-time-exceeded";
1900
- /**
1901
- * Failure result returned by `ai.runAgent`. Discriminates via `kind`.
2642
+ * Phase 34 QUIRK-02 / NEG-01 / NEG-02 — xAI provider factory.
1902
2643
  *
1903
- * `iterations[]` carries any iterations that completed before the failure
1904
- * (empty if the failure occurred pre-iteration). For `agent-iteration-denied`,
1905
- * the failing iteration is the LAST entry and carries `deniedReason`.
2644
+ * Extends the base OpenAI-compat execution wrapper with:
2645
+ * 1. `quirks: XaiQuirks` verified per RESEARCH §Q6 xAI vocabulary.
2646
+ * 2. `negotiateCapabilities(modelId)` queries xAI /v1/models GET with
2647
+ * Authorization: Bearer header; LENIENT-PARSE sparse OpenAI-shaped
2648
+ * response; intersects with Phase 33 registry for supports.*.
2649
+ *
2650
+ * CITED: RESEARCH §Q4 (INFERRED) — xAI /v1/models shape is undocumented;
2651
+ * assumed OpenAI-compatible based on the chat completions wire format.
2652
+ *
2653
+ * CITED: RESEARCH §A1 — Pitfall 1 lenient parse: if xAI publishes a
2654
+ * different /models shape, only the parsing logic updates; the contract
2655
+ * (source values, NegotiatedCapabilities shape) holds.
2656
+ *
2657
+ * The negotiate() pattern mirrors Plan 34-02 (Anthropic thick reference):
2658
+ * - Per-instance TTL cache (modelsCacheTtlMs, default 300_000ms)
2659
+ * - Single-flight inflight coalescing with .finally cleanup (Pitfall 4)
2660
+ * - Retry with [0, 200, 1000]ms backoff (modelsRetryCount, default 2)
2661
+ * - 401/403 throws NegotiationAuthError with adapter: "xai" (D-10)
2662
+ * - 5xx/network/timeout falls back to registry + emits fallback event
2663
+ *
2664
+ * SECURITY (T-34-03-07): inflight Map MUST use .finally cleanup to prevent
2665
+ * leak on rejection. Verifiable: grep `.finally` in this file.
1906
2666
  */
1907
- interface AgentFailure {
1908
- readonly kind: AgentFailureKind;
2667
+ declare function createXaiProvider(options: XaiProviderOptions): ProviderAdapter & {
2668
+ readonly quirks: XaiQuirks;
2669
+ readonly negotiateCapabilities: (modelId: string) => Promise<NegotiatedCapabilities>;
2670
+ };
2671
+ //#endregion
2672
+ //#region src/results/result.d.ts
2673
+ interface RunSuccess<TOutputs extends OutputContractMap> {
2674
+ readonly ok: true;
2675
+ readonly outputs: InferOutputMap<TOutputs>;
2676
+ readonly artifacts: readonly ArtifactRef[];
1909
2677
  readonly usage: Usage;
1910
- readonly iterations: ReadonlyArray<IterationRecord>;
1911
- readonly reason?: string;
1912
- readonly cause?: unknown;
2678
+ readonly plan: ResultPlan;
2679
+ readonly events?: readonly RunEvent[];
2680
+ /**
2681
+ * Phase 9 — signed capability receipt issued when `LatticeConfig.signer`
2682
+ * is configured. Undefined when no signer is set.
2683
+ */
1913
2684
  readonly receipt?: ReceiptEnvelope;
1914
2685
  }
1915
- /**
1916
- * Discriminated union returned by `ai.runAgent`.
1917
- */
1918
- type AgentResult<TOutputs extends OutputContractMap = OutputContractMap> = AgentSuccess<TOutputs> | AgentFailure;
1919
- /**
1920
- * Typed error raised when a SAFETY-band handler sets `controls.deny(reason)`
1921
- * during `BEFORE_AGENT_ITERATION`. Carries `terminal: true` semantics to
1922
- * align with v1.1 `TripwireViolationError`: the failure is NOT retried by
1923
- * the fallback chain.
1924
- *
1925
- * Surfaced via `AgentFailure { kind: "agent-iteration-denied", reason, ... }`
1926
- * — callers can also catch the typed error if they prefer.
1927
- */
1928
- declare class AgentDeniedError extends Error {
1929
- readonly kind: "agent-iteration-denied";
1930
- readonly terminal: true;
1931
- readonly reason: string;
1932
- readonly iterationIndex: number;
1933
- constructor(reason: string, iterationIndex: number);
1934
- }
1935
- /**
1936
- * Returned by `formatToolsForProvider` (Phase 19 Plan 19-03). Re-exported
1937
- * here for convenience; the canonical declaration lives in format-tools.ts.
1938
- */
1939
- interface ToolUseRequest {
1940
- readonly id: string;
1941
- readonly name: string;
1942
- readonly args: unknown;
2686
+ interface RunFailure {
2687
+ readonly ok: false;
2688
+ readonly error: LatticeRunError;
2689
+ readonly usage: Usage;
2690
+ readonly raw?: unknown;
2691
+ readonly partialOutputs?: Record<string, unknown>;
2692
+ readonly plan: ResultPlan;
2693
+ readonly events?: readonly RunEvent[];
2694
+ /**
2695
+ * Phase 9 — signed capability receipt issued when `LatticeConfig.signer`
2696
+ * is configured. Undefined when no signer is set.
2697
+ */
2698
+ readonly receipt?: ReceiptEnvelope;
1943
2699
  }
2700
+ type RunResult<TOutputs extends OutputContractMap> = RunSuccess<TOutputs> | RunFailure;
1944
2701
  //#endregion
1945
2702
  //#region src/storage/storage.d.ts
1946
2703
  interface ArtifactStore {
@@ -1994,6 +2751,88 @@ interface NormalizedLatticeConfig {
1994
2751
  readonly signer?: ReceiptSigner;
1995
2752
  }
1996
2753
  //#endregion
2754
+ //#region src/agent/crew/agent-spec.d.ts
2755
+ /**
2756
+ * Crew member specification. A literal sibling of `ToolDefinition`
2757
+ * discriminated by `kind: "agent"` (D-03).
2758
+ */
2759
+ interface AgentSpec {
2760
+ readonly kind: "agent";
2761
+ readonly id: string;
2762
+ readonly intent: string;
2763
+ readonly tools: ReadonlyArray<ToolDefinition<StandardSchemaV1>>;
2764
+ readonly childAgents?: ReadonlyArray<AgentSpec>;
2765
+ readonly summaryReturnSchema: StandardSchemaV1;
2766
+ /** Optional per-agent sub-budget (D-07). */
2767
+ readonly contract?: CapabilityContract;
2768
+ }
2769
+ /**
2770
+ * Factory for `AgentSpec` values. Mirrors `defineTool` exactly: spread
2771
+ * preserves input identity (no cloning, no mutation) and absent optional
2772
+ * members stay absent (`exactOptionalPropertyTypes`-safe).
2773
+ */
2774
+ declare function defineAgent(definition: Omit<AgentSpec, "kind">): AgentSpec;
2775
+ //#endregion
2776
+ //#region src/agent/crew/crew-policy.d.ts
2777
+ /** Per-adapter rate-limit override (keyed by `adapter.id` in `limits`). */
2778
+ interface CrewRateLimitOverride {
2779
+ readonly requestsPerMinute?: number;
2780
+ readonly tokensPerMinute?: number;
2781
+ }
2782
+ /** Crew-level policy contract (D-06, D-11, D-16). */
2783
+ interface CrewPolicy {
2784
+ /** Crew-level shared budget pool — `BudgetInvariant` reused verbatim. */
2785
+ readonly budget?: BudgetInvariant;
2786
+ readonly maxTotalIterations?: number;
2787
+ readonly maxIterationsPerAgent?: number;
2788
+ /** Forward-compat field; the v1.3 runtime rejects values > 1 (D-11). */
2789
+ readonly maxConcurrentChildren?: number;
2790
+ /** Delegation depth cap; defaults to 1 (parent→child only, D-05). */
2791
+ readonly maxDepth?: number;
2792
+ /** Per-adapter-id rate-limit overrides (D-16). */
2793
+ readonly limits?: Readonly<Record<string, CrewRateLimitOverride>>;
2794
+ /** "managed" (default) wraps transports in the rate-limit group; "unmanaged" skips it. */
2795
+ readonly coordination?: "managed" | "unmanaged";
2796
+ }
2797
+ //#endregion
2798
+ //#region src/agent/crew/run-crew.d.ts
2799
+ interface RunAgentCrewOptions {
2800
+ readonly root: AgentSpec;
2801
+ readonly hosts: {
2802
+ readonly childHost: AgentHost;
2803
+ };
2804
+ readonly policy?: CrewPolicy;
2805
+ /** Crew-level signer threaded into member loops and completion receipts. */
2806
+ readonly signer?: ReceiptSigner;
2807
+ /** Crew-level tracer threaded into member loops. */
2808
+ readonly tracer?: TracerLike;
2809
+ /** Crew-level hook pipeline threaded into member loops. */
2810
+ readonly pipeline?: HookPipeline;
2811
+ }
2812
+ interface CrewAgentResult {
2813
+ readonly id: string;
2814
+ readonly usage: Usage;
2815
+ readonly iterations: number;
2816
+ readonly receiptCids: readonly string[];
2817
+ }
2818
+ interface CrewResult {
2819
+ /** Parent result, with parent output untouched on success. */
2820
+ readonly result: AgentResult;
2821
+ /** Per-agent accounting records, including root parent and completed children. */
2822
+ readonly perAgent: ReadonlyArray<CrewAgentResult>;
2823
+ /** Crew aggregate usage: parent total + sum(child totals), no double-counting. */
2824
+ readonly usage: Usage;
2825
+ /** Total iterations across every recorded agent. */
2826
+ readonly totalIterations: number;
2827
+ /** All crew completion receipts, including the crew-root envelope. */
2828
+ readonly receipts: ReadonlyArray<ReceiptEnvelope>;
2829
+ readonly crewRootCid?: string;
2830
+ }
2831
+ /**
2832
+ * Execute a crew rooted at `options.root`.
2833
+ */
2834
+ declare function runAgentCrew(options: RunAgentCrewOptions, config?: LatticeConfig): Promise<CrewResult>;
2835
+ //#endregion
1997
2836
  //#region src/runtime/create-ai.d.ts
1998
2837
  interface RuntimeOverrides {
1999
2838
  readonly provider?: string;
@@ -2041,12 +2880,21 @@ interface AI {
2041
2880
  * Phase 19 (v1.2): single-agent execution loop. Drives multiple provider
2042
2881
  * iterations under one call, dispatching tool requests between iterations.
2043
2882
  * Composes with the v1.2 hook pipeline (SAFETY-band veto, OBSERVABILITY-band
2044
- * checkpoint receipts) and the v1.1 capability receipts (when
2883
+ * checkpoint receipts) and the v1.2 capability receipts (when
2045
2884
  * `intent.signer` is provided + `intent.autoRegisterCheckpoint !== false`).
2046
2885
  *
2047
2886
  * See `packages/lattice/src/agent/runtime.ts` for orchestration details.
2048
2887
  */
2049
2888
  runAgent<const TOutputs extends OutputContractMap>(intent: AgentIntent<TOutputs>): Promise<AgentResult<TOutputs>>;
2889
+ /**
2890
+ * Phase 39 (v1.3): opt-in multi-agent crew execution. Runs a literal
2891
+ * `AgentSpec` tree through the existing single-agent loop plus the crew
2892
+ * dispatcher, with shared budget/rate-limit coordination and chained
2893
+ * completion receipts.
2894
+ *
2895
+ * See `packages/lattice/src/agent/crew/run-crew.ts` for orchestration details.
2896
+ */
2897
+ runAgentCrew(options: RunAgentCrewOptions): Promise<CrewResult>;
2050
2898
  }
2051
2899
  declare function createAI(config?: LatticeConfig): AI;
2052
2900
  //#endregion
@@ -2138,6 +2986,10 @@ declare function materializeReplayEnvelope<TOutputs extends OutputContractMap =
2138
2986
  * calling Promise), direct transport (provider.execute()), and in-memory
2139
2987
  * transcript (the `conversation` array). Phase 20 promotes scheduler /
2140
2988
  * transport / storage to the pluggable `AgentHost` adapter.
2989
+ *
2990
+ * Phase 39: `runAgent` is a thin public wrapper over `runAgentInternal`
2991
+ * with no internal options — the public signature and behavior are
2992
+ * unchanged.
2141
2993
  */
2142
2994
  declare function runAgent<TOutputs extends OutputContractMap = OutputContractMap>(intent: AgentIntent<TOutputs>, config?: LatticeConfig): Promise<AgentResult<TOutputs>>;
2143
2995
  //#endregion
@@ -2299,6 +3151,73 @@ declare function createPermissionGuardHook(context: PermissionContext): HookHand
2299
3151
  */
2300
3152
  declare function permissionGuardRegisterOptions(): RegisterOptions;
2301
3153
  //#endregion
3154
+ //#region src/agent/infra/rate-limit-group.d.ts
3155
+ interface RateLimitGroupOptions {
3156
+ /** Requests per minute. Defaults to 50 (Anthropic Tier 1). */
3157
+ readonly requestsPerMinute?: number;
3158
+ /** Input tokens per minute. Defaults to 30_000 (Anthropic Tier 1). */
3159
+ readonly tokensPerMinute?: number;
3160
+ /** Injectable clock for tests (defaults to `Date.now`). */
3161
+ readonly now?: () => number;
3162
+ }
3163
+ interface RateLimitLease {
3164
+ /**
3165
+ * Reconcile the reservation against actual usage. Refunds
3166
+ * `estimate - actual.promptTokens` to the token bucket when positive,
3167
+ * debits the difference when negative. Idempotent — only the first call
3168
+ * has an effect. Requests are never refunded.
3169
+ */
3170
+ release(actual: {
3171
+ promptTokens: number;
3172
+ }): void;
3173
+ }
3174
+ interface RateLimitGroup {
3175
+ readonly kind: "rate-limit-group";
3176
+ /**
3177
+ * Reserve 1 request + `estimate.inputTokens` tokens. Resolves immediately
3178
+ * when both dimensions have capacity; otherwise the caller waits (FIFO)
3179
+ * until continuous drain refills the deficit.
3180
+ */
3181
+ acquire(estimate: {
3182
+ inputTokens: number;
3183
+ }): Promise<RateLimitLease>;
3184
+ }
3185
+ declare function createRateLimitGroup(options?: RateLimitGroupOptions): RateLimitGroup;
3186
+ /**
3187
+ * Wrap an `AgentTransport` so every provider call is gated through `group`.
3188
+ *
3189
+ * Every transport wrapped with the SAME group instance shares one bucket —
3190
+ * `runAgentCrew` (39-06) wraps parent + child hosts with one shared group per
3191
+ * adapter instance, structurally guaranteeing crew-wide coordination (D-13).
3192
+ * `ProviderAdapter` is never modified (INV-03 parity invariant intact).
3193
+ *
3194
+ * - `inner` provided → dispatch nests through `inner.call(provider, request)`,
3195
+ * composing with consumer transports (e.g. cross-process bridges).
3196
+ * - `inner` undefined → falls through to `provider.execute(request)`, guarded
3197
+ * the same way as `createNoopAgentHost` (error names the provider id only).
3198
+ *
3199
+ * Release policy:
3200
+ * - Success → release with `normalizedUsage.promptTokens`; when usage is
3201
+ * missing or non-finite, fall back to the estimate (no NaN arithmetic —
3202
+ * the `costUsd: null` "unmeasured" discipline analog).
3203
+ * - Throw → release with the ORIGINAL estimate (burn — no refund; the
3204
+ * provider may have consumed quota despite the error) and rethrow the
3205
+ * same error unchanged. Request objects and headers are never serialized
3206
+ * into error paths.
3207
+ */
3208
+ declare function withRateLimit(group: RateLimitGroup, inner?: AgentTransport): AgentTransport;
3209
+ //#endregion
3210
+ //#region src/receipts/cid.d.ts
3211
+ /**
3212
+ * Derive the content-addressed CID of a receipt envelope.
3213
+ *
3214
+ * Returns `sha256:<hex>` where `<hex>` is the 64-char lowercase SHA-256
3215
+ * digest of the decoded DSSE payload bytes. No KeySet, signer, or other
3216
+ * key material is required — callers chaining receipts (parentReceiptCid)
3217
+ * compute this from the parent envelope alone.
3218
+ */
3219
+ declare function receiptCid(envelope: ReceiptEnvelope): Promise<string>;
3220
+ //#endregion
2302
3221
  //#region src/agent/eval.d.ts
2303
3222
  /**
2304
3223
  * Summary of an agent run sufficient for regression analysis. Callers
@@ -2355,5 +3274,60 @@ declare function createMemoryArtifactStore(options?: MemoryArtifactStoreOptions)
2355
3274
  //#region src/version.d.ts
2356
3275
  declare const latticeVersion = "0.0.0";
2357
3276
  //#endregion
2358
- export { type AI, type ActionHistory, type ActionHistoryOptions, type ActionRecord, AgentDeniedError, type AgentEvalResult, type AgentFailure, type AgentFailureKind, type AgentHost, type AgentIntent, type AgentResult, type AgentRunSnapshot, type AgentScheduler, type AgentSnapshot, type AgentStorage, type AgentSuccess, type AgentTransport, type AnthropicProviderOptions, type ArtifactFingerprint, type ArtifactInput, type ArtifactKind, type ArtifactLineage, type ArtifactOptions, type ArtifactParentRef, type ArtifactPrivacy, type ArtifactRef, type ArtifactSize, type ArtifactSource, type ArtifactStorageRef, type ArtifactStore, type ArtifactTransformDescriptor, type ArtifactTransformKind, BAND, type BudgetInvariant, type CapabilityContract, type CapabilityContractInput, type CapabilityReceiptBody, type CheckpointHookContext, type CheckpointHookOptions, type ContractRejectReasonCode, type ContractVerdict, type ConversationTurn, type CostBudgetStatus, type CostTracker, type CreateReceiptInput, DEFAULT_CHECKPOINT_BAND, type EvalOptions, type EvalRegression, type EvalRegressionKind, type EvictionHook, type ExecutionPlanStub, type FieldFromTableInvariant, type FormatToolsMode, type FormatToolsOptions, type FormattedToolsHandle, type GeminiProviderOptions, type GoalProgressOptions, type GoalProgressStep, type GoalProgressTracker, type HookControls, type HookDenyDirective, type HookLifecycleEvent, type HookPipeline, type InferOutput, type InferOutputMap, type InvariantDeclaration, type InvariantOptions, type IterationRecord, type KeyEntry, type KeySet, type KeyState, type LatticeConfig, type LatticeRunError, type LmStudioProviderOptions, type MatchesInvariant, type MaterializationError, type MaterializeReplayEnvelopeOptions, type MustCiteInvariant, type NoPiiInvariant, type NormalizedLatticeConfig, type OpenRouterProviderOptions, type OutputContract, type OutputContractMap, type PermissionContext, type PermissionDecisionInput, type PermissionHookContext, type PermissionRule, type PermissionVerdict, type PiiDetector, type PiiDetectorResult, type PolicySpec, type ProgressStatus, type ProviderAdapter, type ProviderRef, type ProviderRunRequest, type ProviderRunResponse, type QualityFloorInvariant, type ReceiptEnvelope, type ReceiptModel, type ReceiptRedaction, type ReceiptRoute, type ReceiptSignature, type ReceiptSigner, type ReceiptUsageCanonical, type ReplayEnvelope, type ResumePolicy, type RunFailure, type RunIntent, type RunResult, type RunSuccess, STEP_TRANSITION_EVENT_NAME, STUCK_REASONS, type SerializedSnapshot, type SessionRef, type StorageLike, type StoredArtifactEnvelope, type StoredArtifactPayloadDescriptor, type StuckReason, type SurvivabilityAdapter, type TokenEstimator, type ToolUseRequest, type TracerLike, type TranscriptStore, type TripwireEvidence, type TripwireResult, type TripwireViolationError, type UnsubscribeFn, type Usage, type ValidationIssue, type VerifyError, type VerifyErrorKind, type VerifyFail, type VerifyOk, type VerifyResult, type XaiProviderOptions, artifact, contract, createAI, createAISdkProvider, createActionHistory, createAnthropicProvider, createCheckpointHook, createCostTracker, createFakeProvider, createGeminiProvider, createGoalProgressTracker, createHookPipeline, createInMemorySigner, createLmStudioProvider, createLocalArtifactStore, createMemoryArtifactStore, createMemoryKeySet, createMemorySessionStore, createNoopAgentHost, createNoopSurvivabilityAdapter, createOpenAICompatibleProvider, createOpenAIProvider, createOpenRouterProvider, createPermissionContext, createPermissionGuardHook, createReceipt, createReplayEnvelope, createTranscriptStore, createXaiProvider, defaultPiiDetectors, defineTool, estimateRouteCost, evalAgentRun, evaluateContractAgainstRoute, evaluateTripwires, formatToolsForProvider, generateEd25519KeyPairJwk, importMcpTools, inv, isTerminal, latticeVersion, materializeReplayEnvelope, output, permissionGuardRegisterOptions, redactArtifactRef, redactPlan, redactReplayEnvelope, replayOffline, rerunLive, runAgent, runTool, toolArtifactRef, toolSchemaToJsonSchema, verifyReceipt };
3277
+ //#region src/capabilities/lookup.d.ts
3278
+ /**
3279
+ * Strip the OpenRouter variant suffix (`:free` or `:thinking`) from an
3280
+ * OpenRouter-shaped id (`vendor/model:variant`). Other adapter id shapes
3281
+ * pass through verbatim — does not, for example, alter
3282
+ * `anthropic:claude-opus-4` (direct-adapter canonical key) or
3283
+ * `openai/gpt-4o:beta` (unrecognized variant per Pitfall 4).
3284
+ *
3285
+ * Exported because Phase 34 (adapter quirks) and Phase 36 (output
3286
+ * sanitizers) need the same normalization. Phase 33 D-11 scope.
3287
+ */
3288
+ declare function stripOpenRouterVariant(id: string): string;
3289
+ /**
3290
+ * D-09 strict lookup — return the capability profile for the exact
3291
+ * `${adapter}:${modelId}` canonical key. Returns `undefined` if the key
3292
+ * is not registered. No fuzzy matching — use `findCapabilityProfile`
3293
+ * for that.
3294
+ *
3295
+ * Examples:
3296
+ * getCapabilityProfile("openrouter:openai/gpt-oss-120b") -> profile
3297
+ * getCapabilityProfile("anthropic:claude-opus-4") -> profile
3298
+ * getCapabilityProfile("not-a-real-key") -> undefined
3299
+ *
3300
+ * The lookup is case-sensitive on the canonical key. Threat T-33-02-01
3301
+ * mitigation: backing store is `Map<string, ModelCapabilityProfile>`,
3302
+ * not a plain object literal, so `__proto__` and other prototype-chain
3303
+ * keys are safe (Map uses SameValueZero, not property lookup).
3304
+ */
3305
+ declare function getCapabilityProfile(canonicalKey: string): ModelCapabilityProfile | undefined;
3306
+ /**
3307
+ * D-10 fuzzy lookup — strip the OpenRouter variant suffix (if any) and
3308
+ * return ALL matching profiles across every adapter, in deterministic
3309
+ * order: direct adapters first (anthropic, openai, gemini, xai,
3310
+ * openai-compat, lm-studio), then OpenRouter.
3311
+ *
3312
+ * Useful for pre-routing capability inspection where the adapter has
3313
+ * not yet been chosen — the consumer can iterate the returned list
3314
+ * and pick the first compatible one. Returns `[]` when no match is
3315
+ * found across any adapter.
3316
+ *
3317
+ * Suffix-strip is OpenRouter-shape-only per D-11. Direct-adapter ids
3318
+ * pass through verbatim:
3319
+ * findCapabilityProfile("openai/gpt-oss-120b:free")
3320
+ * -> [openrouter:openai/gpt-oss-120b]
3321
+ * findCapabilityProfile("claude-opus-4")
3322
+ * -> [anthropic:claude-opus-4, ...] (no suffix-strip)
3323
+ */
3324
+ declare function findCapabilityProfile(id: string): ModelCapabilityProfile[];
3325
+ //#endregion
3326
+ //#region src/prompts/scaffolds.d.ts
3327
+ declare const PROMPT_SCAFFOLD_VERSION: "lattice.prompt-scaffold/v1";
3328
+ declare const PROMPT_STRATEGIES: readonly ["frontier", "mid_tier", "open_weight", "reasoning", "local"];
3329
+ declare function getStructuredOutputContract(strategy: RecommendedPromptStrategy, schema: unknown): string;
3330
+ declare function getToolUseContract(strategy: RecommendedPromptStrategy, tools: unknown): string;
3331
+ //#endregion
3332
+ export { type AI, ALL_KNOWN_FAILURE_MODES, ALL_TRAINING_CLASSES, type ActionHistory, type ActionHistoryOptions, type ActionRecord, type AdapterQuirks, AgentDeniedError, type AgentEvalResult, type AgentFailure, type AgentFailureKind, type AgentHost, type AgentIntent, type AgentResult, type AgentRunSnapshot, type AgentScheduler, type AgentSnapshot, type AgentSpec, type AgentStorage, type AgentSuccess, type AgentTransport, type AnthropicProviderOptions, type AnthropicQuirks, type ArtifactFingerprint, type ArtifactInput, type ArtifactKind, type ArtifactLineage, type ArtifactOptions, type ArtifactParentRef, type ArtifactPrivacy, type ArtifactRef, type ArtifactSize, type ArtifactSource, type ArtifactStorageRef, type ArtifactStore, type ArtifactTransformDescriptor, type ArtifactTransformKind, BAND, type BudgetInvariant, type CapabilityAdapter, type CapabilityContract, type CapabilityContractInput, type CapabilityReceiptBody, type CheckpointHookContext, type CheckpointHookOptions, type ContractRejectReasonCode, type ContractVerdict, type ConversationTurn, type CostBudgetStatus, type CostTracker, type CreateReceiptInput, type CrewAgentResult, type CrewPolicy, type CrewRateLimitOverride, type CrewResult, DEFAULT_CHECKPOINT_BAND, type EvalOptions, type EvalRegression, type EvalRegressionKind, type EvictionHook, type ExecutionPlanStub, type FieldFromTableInvariant, type FormatToolsMode, type FormatToolsOptions, type FormattedToolsHandle, type GeminiProviderOptions, type GeminiQuirks, type GoalProgressOptions, type GoalProgressStep, type GoalProgressTracker, type HookControls, type HookDenyDirective, type HookLifecycleEvent, type HookPipeline, type InferOutput, type InferOutputMap, type InternalEnvelopeOptions, type InvariantDeclaration, type InvariantOptions, type IterationRecord, type KeyEntry, type KeySet, type KeyState, type KnownFailureMode, type LatticeConfig, type LatticeRunError, type LmStudioProviderOptions, type LmStudioQuirks, type MatchesInvariant, type MaterializationError, type MaterializeReplayEnvelopeOptions, type ModelCapabilityProfile, type MustCiteInvariant, type NegotiatedCapabilities, NegotiationAuthError, type NoPiiInvariant, type NormalizedLatticeConfig, type OpenAICompatQuirks, type OpenAIQuirks, type OpenRouterProviderOptions, type OpenRouterQuirks, type OutputContract, type OutputContractMap, PROMPT_SCAFFOLD_VERSION, PROMPT_STRATEGIES, type PermissionContext, type PermissionDecisionInput, type PermissionHookContext, type PermissionRule, type PermissionVerdict, type PiiDetector, type PiiDetectorResult, type PolicySpec, type ProgressStatus, type ProviderAdapter, type ProviderRef, type ProviderRunRequest, type ProviderRunResponse, type QualityFloorInvariant, type RateLimitGroup, type RateLimitGroupOptions, type RateLimitLease, type ReasoningSurface, type ReceiptEnvelope, type ReceiptModel, type ReceiptRedaction, type ReceiptRoute, type ReceiptSignature, type ReceiptSigner, type ReceiptUsageCanonical, type RecommendedPromptStrategy, type ReplayEnvelope, type ResumePolicy, type RunAgentCrewOptions, type RunEvent, type RunEventKind, type RunEventSink, type RunFailure, type RunIntent, type RunResult, type RunSuccess, SANITIZER_BY_FAILURE_MODE, STEP_TRANSITION_EVENT_NAME, STUCK_REASONS, type SanitizeOutputOption, type SanitizerContext, type SanitizerFn, type SanitizerKey, type SerializedSnapshot, type SessionRef, type StorageLike, type StoredArtifactEnvelope, type StoredArtifactPayloadDescriptor, type StuckReason, type SurvivabilityAdapter, type TokenEstimator, type ToolCallSurface, ToolCallValidationError, type ToolCallValidationFailureReason, type ToolUseRequest, type TracerLike, type TrainingClass, type TranscriptStore, type TripwireEvidence, type TripwireResult, type TripwireViolationError, type UnsubscribeFn, type Usage, type ValidateToolCallsOption, type ValidatedToolCall, type ValidationIssue, type VerifyError, type VerifyErrorKind, type VerifyFail, type VerifyOk, type VerifyResult, type XaiProviderOptions, type XaiQuirks, artifact, contract, createAI, createAISdkProvider, createActionHistory, createAnthropicProvider, createCheckpointHook, createCostTracker, createFakeProvider, createGeminiProvider, createGoalProgressTracker, createHookPipeline, createInMemorySigner, createLmStudioProvider, createLocalArtifactStore, createMemoryArtifactStore, createMemoryKeySet, createMemorySessionStore, createNoopAgentHost, createNoopSurvivabilityAdapter, createOpenAICompatibleProvider, createOpenAIProvider, createOpenRouterProvider, createPermissionContext, createPermissionGuardHook, createRateLimitGroup, createReceipt, createReplayEnvelope, createTranscriptStore, createXaiProvider, defaultPiiDetectors, defineAgent, defineTool, estimateRouteCost, evalAgentRun, evaluateContractAgainstRoute, evaluateTripwires, findCapabilityProfile, formatToolsForProvider, generateEd25519KeyPairJwk, getCapabilityProfile, getRecommendedSanitizers, getStructuredOutputContract, getToolUseContract, importMcpTools, inv, isTerminal, latticeVersion, materializeReplayEnvelope, negotiateCapabilities, output, parseToolUseEnvelope, permissionGuardRegisterOptions, receiptCid, redactArtifactRef, redactPlan, redactReplayEnvelope, replayOffline, rerunLive, runAgent, runAgentCrew, runTool, stripChatTemplateArtifacts, stripOpenRouterVariant, stripReasoningTags, synthesizeNegotiatedCapabilitiesFromRegistry, toolArtifactRef, toolSchemaToJsonSchema, unwrapInternalEnvelope, verifyReceipt, withRateLimit };
2359
3333
  //# sourceMappingURL=index.d.ts.map