@yaklabs-ai/plugin-sdk 0.11.0 → 0.12.3

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.
@@ -1,4 +1,3 @@
1
- import type { TypeSafeClient } from '@typesafe-ai/sdk';
2
1
  import { z } from 'zod';
3
2
 
4
3
  /**
@@ -23,6 +22,9 @@ declare interface AccountIdentity {
23
22
  readonly avatarUrl?: string;
24
23
  /** Issuer-asserted beta-tester flag; only Kay's product-account service sets it. */
25
24
  readonly betaTester?: boolean;
25
+ readonly activeOrganizationId?: string;
26
+ readonly organizationSelectionState?: "selected" | "unresolved";
27
+ readonly organizationScopeEpoch?: number;
26
28
  /**
27
29
  * Provider-native session id claim (WorkOS's `sid`), needed to call the provider's own
28
30
  * session-revocation endpoint at sign-out (`POST /user_management/sessions/revoke`, not yet
@@ -54,8 +56,18 @@ declare interface AgentToolResult<T = JsonValue_3 | undefined> {
54
56
  content: (TextContent | ImageContent)[];
55
57
  /** Arbitrary structured details for logs or UI rendering. */
56
58
  details: T;
59
+ /**
60
+ * Machine-readable result matching the tool's `outputSchema`, for programmatic callers. Not sent
61
+ * to the model; `content` remains the model-facing result.
62
+ */
63
+ structuredContent?: JsonValue_3;
57
64
  /** Usage from the final tool execution itself, if available. Not used for main LLM context accounting. */
58
65
  usage?: Usage;
66
+ /**
67
+ * Report a failure without throwing. The model sees `content` as an error result, like a thrown
68
+ * error, but `details` and `structuredContent` are kept for the UI and programmatic callers.
69
+ */
70
+ isError?: boolean;
59
71
  /**
60
72
  * Hint that the agent should stop after the current tool batch.
61
73
  * Early termination only happens when every finalized tool result in the batch sets this to true.
@@ -246,6 +258,20 @@ declare interface BackgroundTaskSnapshot {
246
258
 
247
259
  declare type BackgroundTaskStatus = "queued" | "running" | "completed" | "failed" | "cancelled";
248
260
 
261
+ /** Fields shared by every catalog entry, regardless of what you can do with it. */
262
+ declare interface BaseModel<TApi extends string> {
263
+ id: string;
264
+ name: string;
265
+ api: TApi;
266
+ provider: ProviderId;
267
+ baseUrl: string;
268
+ input: ("text" | "image")[];
269
+ /** Provider input limits and cache-safe preprocessing metadata. */
270
+ inputLimits?: ModelInputLimits;
271
+ cost: ModelCost;
272
+ headers?: Record<string, string>;
273
+ }
274
+
249
275
  /** Compatibility settings for Amazon Bedrock models. */
250
276
  declare interface BedrockCompat {
251
277
  /** Whether the model supports Bedrock strict tool schemas. Default: false. */
@@ -371,6 +397,13 @@ declare interface DelegatedConnectContext {
371
397
  /** What a delegated scheme's `connect` resolves with: the material to vault + optional label/provenance. */
372
398
  declare interface DelegatedConnectResult {
373
399
  readonly material: DelegatedSecretMaterial;
400
+ /**
401
+ * A stable account id for this sign-in, used instead of a freshly minted one, so a reconnect
402
+ * overwrites the same record (and keeps it the default) rather than adding a sibling. 1-128
403
+ * characters: letters, digits, and `._:@+-`, starting with a letter or digit; any other value
404
+ * fails the connect. Absent mints a fresh id per connect.
405
+ */
406
+ readonly accountId?: string;
374
407
  /** Account display label; a caller-supplied `service_connect` label takes precedence. */
375
408
  readonly label?: string;
376
409
  /** Structured provenance the scheme derived during connect; persisted via the vault's write-path. */
@@ -498,24 +531,8 @@ declare interface ExtensionPaths {
498
531
  export declare function fauxAuthContext(overrides?: Partial<ExtensionAuthContext>): ExtensionAuthContext;
499
532
 
500
533
  /** The capability handles a `KayAgentPluginApi` always carries — authority is decided per call. */
501
- export declare type FauxKayAgentCapabilities = Pick<KayAgentPluginApi, "filesystem" | "network" | "webSession" | "process" | "whiteboard" | "interceptToolCall" | "withJev" | "events">;
534
+ export declare type FauxKayAgentCapabilities = Pick<KayAgentPluginApi, "filesystem" | "network" | "webSession" | "process" | "whiteboard" | "interaction" | "interceptToolCall" | "withJev" | "events" | "time">;
502
535
 
503
- /**
504
- * The brokered capability handles every `KayAgentPluginApi` carries, as doubles that refuse
505
- * to be used. Spread them into a hand-rolled activation fake:
506
- *
507
- * ```ts
508
- * createMyPluginKayAgent()({ ...fauxKayAgentCapabilities(), uri: { registerModule }, ... });
509
- * ```
510
- *
511
- * They exist because the handles are ALWAYS present on the real api — the daemon composes every
512
- * brokered capability unconditionally and decides authority at each call (`filesystem.read
513
- * {root}`, `network.connect {connect}`, ...), so presence is not a grant signal a plugin may
514
- * feature-detect, and a fake that omits one is not a `KayAgentPluginApi`. The four I/O brokers
515
- * reject on use; `interceptToolCall` is a registration, so like the fakes' own `registerTool` it
516
- * accepts and drops. A test that exercises a capability overrides that one handle after the
517
- * spread; the rest keep refusing.
518
- */
519
536
  export declare function fauxKayAgentCapabilities(): FauxKayAgentCapabilities;
520
537
 
521
538
  /**
@@ -531,6 +548,216 @@ declare interface ImageContent {
531
548
  mimeType: string;
532
549
  }
533
550
 
551
+ /**
552
+ * The value a Browser Interaction driver sets as `credentialGuard` to declare that every act runs
553
+ * the page-side credential guard from `@kay/interaction-page-scripts` (never type into or click a
554
+ * sign-in form). The engine refuses to register a browser driver without it.
555
+ */
556
+ declare const INTERACTION_CREDENTIAL_GUARD = "kay.credential-guard/v1";
557
+
558
+ declare interface InteractionActed {
559
+ /** The address of the target acted on, when it changed (an open landed in a new page). */
560
+ readonly target?: string;
561
+ readonly url: string;
562
+ readonly title: string;
563
+ /** What the action visibly caused: a dialog, an alert, a page opened beside it. */
564
+ readonly changes?: readonly string[];
565
+ readonly notes?: readonly string[];
566
+ /** Fresh browser sign-in state for the service the engine named in the open spec. */
567
+ readonly webSession?: {
568
+ readonly state: "signed-in" | "signed-out" | "unknown";
569
+ readonly checkedAt: number | null;
570
+ };
571
+ }
572
+
573
+ /**
574
+ * One action over a candidate from the latest observation of the same target. `fill` replaces the
575
+ * field's contents unless `append` is set, and presses Enter afterwards when `submit` is set.
576
+ */
577
+ declare type InteractionAction = {
578
+ readonly kind: "click";
579
+ readonly element: InteractionCandidate;
580
+ } | {
581
+ readonly kind: "fill";
582
+ readonly element: InteractionCandidate;
583
+ readonly text: string;
584
+ readonly submit?: boolean;
585
+ readonly append?: boolean;
586
+ } | {
587
+ readonly kind: "select";
588
+ readonly element: InteractionCandidate;
589
+ } | {
590
+ readonly kind: "activate";
591
+ readonly element: InteractionCandidate;
592
+ } | {
593
+ readonly kind: "press";
594
+ readonly element: InteractionCandidate;
595
+ }
596
+ /**
597
+ * Scroll by `delta` px (positive is down). With `element` (a `scroll` candidate that names a
598
+ * node), the scroll container that candidate scrolls; without, the whole page or window.
599
+ */
600
+ | {
601
+ readonly kind: "scroll";
602
+ readonly delta: number;
603
+ readonly element?: InteractionCandidate;
604
+ } | {
605
+ readonly kind: "wait";
606
+ };
607
+
608
+ /**
609
+ * One element (or control) an observation offers, with the kind of action it supports. `id` is
610
+ * the driver's per-observation id; the engine mints its own session-unique ids over it. Extra
611
+ * fields are the driver's native identity (a page node number, an accessibility token), returned
612
+ * to the driver untouched in {@link InteractionAction}.
613
+ */
614
+ declare interface InteractionCandidate {
615
+ readonly id: string;
616
+ readonly kind: InteractionCandidateKind;
617
+ readonly label: string;
618
+ readonly node?: number | undefined;
619
+ readonly role?: string | undefined;
620
+ readonly value?: string | undefined;
621
+ readonly current_value?: string | undefined;
622
+ readonly checked?: string | undefined;
623
+ readonly selected?: string | undefined;
624
+ readonly expanded?: string | undefined;
625
+ readonly delta?: number | undefined;
626
+ /** Where an element outside the visible area sits; absent means on screen. */
627
+ readonly position?: "above" | "below" | "beside" | undefined;
628
+ /** A `press` candidate's key (`return`, `escape`, `tab`); its id is `press_<key>` by convention. */
629
+ readonly key?: string | undefined;
630
+ /** The region the element sits in; see {@link InteractionRegion}. */
631
+ readonly region?: InteractionRegion | undefined;
632
+ /**
633
+ * The `node` of the scroll container (a list or pane that scrolls on its own) the element sits
634
+ * in, matching that container's `scroll` candidates; absent when it sits in none.
635
+ */
636
+ readonly scroller?: number | undefined;
637
+ readonly [native: string]: unknown;
638
+ }
639
+
640
+ /** The candidate kinds a driver may offer. */
641
+ declare type InteractionCandidateKind = "click" | "fill" | "select" | "scroll" | "wait" | "activate" | "press";
642
+
643
+ declare interface InteractionDriver {
644
+ /** Unique in the session. `builtin:` is reserved for Kay's own drivers. */
645
+ readonly id: string;
646
+ /** Human-readable name the agent sees beside the driver's targets. */
647
+ readonly label: string;
648
+ readonly kind: InteractionDriverKind;
649
+ /** Required on a `browser` driver; see {@link INTERACTION_CREDENTIAL_GUARD}. */
650
+ readonly credentialGuard?: typeof INTERACTION_CREDENTIAL_GUARD;
651
+ /** Whether the driver can act at all right now (platform, grants, a live connection). */
652
+ isAvailable(): Promise<boolean>;
653
+ targets(): Promise<InteractionOutcome<{
654
+ readonly targets: readonly InteractionTarget[];
655
+ }>>;
656
+ observe(target: string | undefined, options?: {
657
+ readonly fullText?: boolean;
658
+ }): Promise<InteractionOutcome<InteractionObserved>>;
659
+ act(target: string | undefined, action: InteractionAction): Promise<InteractionOutcome<InteractionActed>>;
660
+ screenshot(target: string | undefined): Promise<InteractionOutcome<{
661
+ readonly png: Uint8Array;
662
+ }>>;
663
+ open(spec: InteractionOpenSpec): Promise<InteractionOutcome<InteractionActed>>;
664
+ }
665
+
666
+ /**
667
+ * The Interaction driver contract: what a plugin implements to let Kay's agent drive something
668
+ * on the user's machine (a browser, an app, a remote screen) through the harness-owned
669
+ * Interaction engine.
670
+ *
671
+ * The engine owns everything that is policy: the `interaction_*` tools, the session-unique element
672
+ * ids the agent sees, the run loop that drives a goal step by step, the permission check before
673
+ * every action, screenshots, and reports. A driver owns only its own I/O: list what it can drive,
674
+ * observe one target as a list of actionable candidates, perform one action on a candidate from
675
+ * its latest observation, capture a screenshot, and open a page or app. It chooses no actions,
676
+ * maps no permissions, and retries nothing beyond its own transport. That split is what makes
677
+ * every tool work on every driver.
678
+ *
679
+ * Shape mirrors `SearchProvider` behind `web_search`: one tool set owned by the harness, many
680
+ * backends registered per session, the `builtin:` id namespace reserved for Kay's own.
681
+ */
682
+ /** "Browser Interaction" drives web pages; "Computer Use Interaction" drives native apps. */
683
+ declare type InteractionDriverKind = "browser" | "computer-use";
684
+
685
+ /** A failed operation. `unavailable`: nothing to act on; `refused`: will not run as asked. */
686
+ declare interface InteractionFailure {
687
+ readonly ok: false;
688
+ readonly reason: "unavailable" | "refused" | "error";
689
+ readonly message: string;
690
+ }
691
+
692
+ /** What a driver sees on one target. */
693
+ declare interface InteractionObservation {
694
+ readonly url: string;
695
+ readonly title: string;
696
+ /** Visible text, or the whole page's text when the observe asked for `fullText`; capped. */
697
+ readonly text: string;
698
+ readonly actions: readonly InteractionCandidate[];
699
+ /** Candidates the driver dropped to stay within its cap. */
700
+ readonly omitted_actions: number;
701
+ }
702
+
703
+ declare interface InteractionObserved {
704
+ /** The address of the target observed; absent when the default target has no address. */
705
+ readonly target?: string;
706
+ readonly observation: InteractionObservation;
707
+ /** Lines the engine shows the agent under the observation (where the target sits, siblings). */
708
+ readonly notes?: readonly string[];
709
+ }
710
+
711
+ /** Navigate a page to `url`, or launch / switch to the app `app` names (a bundle id or a name). */
712
+ declare interface InteractionOpenSpec {
713
+ readonly target?: string;
714
+ readonly url?: string;
715
+ readonly app?: string;
716
+ /** The service whose browser sign-in state to report after navigation, when the engine knows it. */
717
+ readonly webSessionServiceId?: string;
718
+ }
719
+
720
+ declare type InteractionOutcome<T> = ({
721
+ readonly ok: true;
722
+ } & T) | InteractionFailure;
723
+
724
+ /**
725
+ * The part of a page or window an element sits in: the open dialog, menu, or sheet it belongs to,
726
+ * else its landmark (navigation, main, a window). `front` marks the overlay covering the rest: a
727
+ * modal dialog (or one held by a full-screen overlay), a sheet, or a floating menu, the last such
728
+ * in the document; elements outside it
729
+ * usually cannot be clicked while it is open. A docked or always-visible dialog or menu is a
730
+ * region but never in front.
731
+ */
732
+ declare interface InteractionRegion {
733
+ readonly role: string;
734
+ readonly name: string;
735
+ readonly front?: boolean | undefined;
736
+ }
737
+
738
+ /**
739
+ * One surface Kay ships, in the driver contract's own shape, so a plugin's driver is the surface
740
+ * plus an identity: `{ id, label, kind, ...api.interaction.desktop }`. Each call is checked
741
+ * against the plugin's `interaction.surface {surface}` grant, and then against the session's
742
+ * permissions exactly as the agent's `interaction_*` tools are: an act is judged as the plugin
743
+ * permission it amounts to (a Send click in Gmail as a Gmail write), an open as `interaction_open`,
744
+ * an observation or screenshot as `interaction_read`. A refused or unavailable call answers
745
+ * `{ ok: false }` (and `isAvailable()` false) rather than throwing.
746
+ */
747
+ declare type InteractionSurface = Pick<InteractionDriver, "isAvailable" | "targets" | "observe" | "act" | "screenshot" | "open">;
748
+
749
+ /**
750
+ * One thing a driver can be pointed at. `id` is a driver-owned address, unique across every
751
+ * driver in the session (prefix it with your scheme), that the agent passes back as `target`.
752
+ * `active` marks the driver's default target.
753
+ */
754
+ declare interface InteractionTarget {
755
+ readonly id: string;
756
+ readonly title: string;
757
+ readonly url?: string;
758
+ readonly active: boolean;
759
+ }
760
+
534
761
  /**
535
762
  * Invoke a plugin tool definition's `execute` in a test, owning the **one sanctioned cast** past
536
763
  * `ToolExecutionAwareParams<unknown>` — the phantom-wire-shaped type every `ToolDefinition`'s
@@ -549,6 +776,118 @@ declare interface ImageContent {
549
776
  */
550
777
  export declare function invokeToolForTest<TDetails = unknown>(tool: ToolDefinition<any, TDetails>, params: Record<string, unknown>, ctx?: ToolContext): Promise<AgentToolResult<TDetails>>;
551
778
 
779
+ /** The answer shape one question gets back. */
780
+ declare type JevAnswerFor<Q> = Q extends JevBoolQuestion ? JevBoolAnswer : Q extends JevChoiceQuestion<infer L> ? JevChoiceAnswer<L> : Q extends JevScoreQuestion ? JevScoreAnswer : never;
781
+
782
+ declare interface JevBoolAnswer {
783
+ readonly type: "bool";
784
+ /** P(yes), from 0 to 1. */
785
+ readonly probability: number;
786
+ }
787
+
788
+ /** A yes/no question. `criteria` says what yes and what no mean; omit it to leave both open. */
789
+ declare interface JevBoolQuestion {
790
+ readonly type: "bool";
791
+ readonly instructions: string;
792
+ readonly criteria?: {
793
+ readonly true: string;
794
+ readonly false: string;
795
+ };
796
+ }
797
+
798
+ declare interface JevChoiceAnswer<L extends string = string> {
799
+ readonly type: "choice";
800
+ readonly choice: L;
801
+ readonly confidence: number;
802
+ /** P(label) for every offered label. */
803
+ readonly probabilities: Readonly<Record<L, number>>;
804
+ }
805
+
806
+ /** A choice among labels. Each label maps to what it means; an empty string leaves it open. */
807
+ declare interface JevChoiceQuestion<L extends string = string> {
808
+ readonly type: "choice";
809
+ readonly instructions: string;
810
+ readonly criteria: Readonly<Record<L, string>>;
811
+ }
812
+
813
+ /** One answered request: every asked question has an answer of its own kind. */
814
+ declare interface JevClassification<Q extends JevQuestions = JevQuestions> {
815
+ /** The Jev model the host asked. */
816
+ readonly model: string;
817
+ readonly answers: {
818
+ readonly [K in keyof Q]: JevAnswerFor<Q[K]>;
819
+ };
820
+ /** Token counts, when the route reported them. */
821
+ readonly usage?: {
822
+ readonly inputTokens: number;
823
+ readonly outputTokens: number;
824
+ };
825
+ }
826
+
827
+ declare interface JevClassifyRequest<Q extends JevQuestions = JevQuestions> {
828
+ readonly state: JevState;
829
+ readonly questions: Q;
830
+ }
831
+
832
+ /**
833
+ * The Jev client a `use` body receives. `classify` either resolves with an answer for every
834
+ * asked question, each of its question's kind, or rejects with a {@link JevCallError}; it never
835
+ * resolves with a partial or substituted answer.
836
+ */
837
+ declare interface JevClient {
838
+ classify<const Q extends JevQuestions>(request: JevClassifyRequest<Q>, options?: {
839
+ readonly signal?: AbortSignal;
840
+ }): Promise<JevClassification<Q>>;
841
+ }
842
+
843
+ declare type JevQuestion = JevBoolQuestion | JevChoiceQuestion | JevScoreQuestion;
844
+
845
+ /** A rubric: questions keyed by the name each answer comes back under. */
846
+ declare type JevQuestions = Readonly<Record<string, JevQuestion>>;
847
+
848
+ declare interface JevScoreAnswer {
849
+ readonly type: "score";
850
+ /** The expected score, from 0 to the number of rungs minus one. */
851
+ readonly score: number;
852
+ readonly confidence: number;
853
+ }
854
+
855
+ /** A score over ordered rungs: the first criterion scores 0, the next 1, and so on. */
856
+ declare interface JevScoreQuestion {
857
+ readonly type: "score";
858
+ readonly instructions: string;
859
+ readonly criteria: readonly string[];
860
+ }
861
+
862
+ /**
863
+ * ---
864
+ * responsibility: The plugin-facing CONTRACT for Jev typed-decision inference — the shape of
865
+ * `api.withJev` on both plugin SDK targets, the {@link JevClient} a `use` body receives, the
866
+ * question and answer vocabulary it speaks, and the fallback-only implementation a host
867
+ * without a Jev lane binds.
868
+ * owns:
869
+ * - {@link WithJev}, {@link WithJevOptions}, {@link createFallbackOnlyWithJev}.
870
+ * - {@link JevClient}, the {@link JevQuestion} and {@link JevAnswer} vocabulary, and
871
+ * {@link JevCallError}.
872
+ * does_not_own:
873
+ * - The wire. The host serves `classify` over whichever route the user's Jev provider order
874
+ * picks; a plugin never sees a vendor client, a vendor type, or a route.
875
+ * - Credential resolution, the `jev.use` decision, the Jev-branch budget, or usage accounting.
876
+ * Those are host-side (`@kay/agent-runtime`'s `kay/jev/`).
877
+ * ---
878
+ *
879
+ * The vocabulary is Kay's own (SDK 0.12.0). Before it, `use` received TypeSafe's `TypeSafeClient`
880
+ * and plugins coded against a vendor's types. It follows pi's classifier contract, which the host
881
+ * runs Jev through: a yes/no question is `bool` and answers a `probability`, every instruction and
882
+ * criterion is text, and the state is a JSON object.
883
+ */
884
+ /**
885
+ * The state a rubric reads: a JSON object, never text or an array. Every value must survive
886
+ * `JSON.stringify` unchanged (no functions or class instances), because it is sent as JSON.
887
+ * Typed as `object` so a state declared as an interface fits without an index signature.
888
+ */
889
+ declare type JevState = object;
890
+
552
891
  declare type JsonObject = {
553
892
  [key: string]: JsonValue_3;
554
893
  };
@@ -586,10 +925,18 @@ declare interface KayAgentEvents {
586
925
  publish(localId: string, payload: unknown): void;
587
926
  }
588
927
 
589
- /** Claim-checked filesystem operations. Paths are root-relative; canonical host paths never cross the seam. */
928
+ /**
929
+ * Claim-checked filesystem operations. Paths are root-relative; canonical host paths never cross
930
+ * the seam. Writes are atomic: readers see the old file or the new one, never a partial write. A
931
+ * replace keeps the file's mode but makes a new file, so owner and extended attributes are not
932
+ * carried over. On a volume without hard links an exclusive create can briefly show an empty file.
933
+ */
590
934
  declare interface KayAgentFilesystem {
591
935
  readText(location: KayAgentFilesystemLocation): Promise<string>;
592
- writeText(location: KayAgentFilesystemLocation, content: string): Promise<void>;
936
+ writeText(location: KayAgentFilesystemLocation, content: string, options?: KayAgentFilesystemWriteOptions): Promise<void>;
937
+ /** The whole file, or the requested window of it. */
938
+ readBytes(location: KayAgentFilesystemLocation, range?: KayAgentFilesystemByteRange): Promise<Uint8Array>;
939
+ writeBytes(location: KayAgentFilesystemLocation, bytes: Uint8Array, options?: KayAgentFilesystemWriteOptions): Promise<void>;
593
940
  mkdir(location: KayAgentFilesystemLocation): Promise<void>;
594
941
  readDir(location: KayAgentFilesystemLocation): Promise<readonly KayAgentFilesystemEntry[]>;
595
942
  stat(location: KayAgentFilesystemLocation): Promise<KayAgentFilesystemStat>;
@@ -598,6 +945,12 @@ declare interface KayAgentFilesystem {
598
945
  realpath(location: KayAgentFilesystemLocation): Promise<string>;
599
946
  }
600
947
 
948
+ /** A byte window of a file; `maxBytes` is capped by the host. */
949
+ declare interface KayAgentFilesystemByteRange {
950
+ readonly offset: number;
951
+ readonly maxBytes: number;
952
+ }
953
+
601
954
  declare interface KayAgentFilesystemEntry {
602
955
  readonly name: string;
603
956
  readonly kind: "file" | "directory" | "symlink" | "other";
@@ -615,6 +968,27 @@ declare interface KayAgentFilesystemStat {
615
968
  readonly modifiedAtMs: number;
616
969
  }
617
970
 
971
+ declare interface KayAgentFilesystemWriteOptions {
972
+ /** Fail with `already_exists` instead of replacing a file already at the location. */
973
+ readonly exclusive?: boolean;
974
+ }
975
+
976
+ declare interface KayAgentInteractionSurfaces {
977
+ /**
978
+ * Kay's built-in browser pane: the pages in the user's Bonsai tabs. The page-side credential
979
+ * guard runs on every act, so a driver over this surface may declare
980
+ * {@link INTERACTION_CREDENTIAL_GUARD}.
981
+ */
982
+ readonly browserPane: InteractionSurface;
983
+ /**
984
+ * The user's desktop through the platform's accessibility APIs: native apps as targets
985
+ * (`app://<bundle id>`), their windows' controls as elements. On macOS Kay drives it with its
986
+ * bundled accessibility worker under the app's Accessibility permission; on a platform with no
987
+ * backend it reports itself unavailable.
988
+ */
989
+ readonly desktop: InteractionSurface;
990
+ }
991
+
618
992
  /** One knowledge-index hit — a reference and within-list rank score, never a snippet. */
619
993
  declare interface KayAgentKnowledgeHit {
620
994
  readonly uri: string;
@@ -767,9 +1141,17 @@ declare interface KayAgentPluginApi {
767
1141
  * command it is about to run, and against the host's executable binding.
768
1142
  */
769
1143
  readonly process: KayAgentProcess;
1144
+ /**
1145
+ * Always present; the interaction surfaces Kay ships (its browser pane, and the desktop through
1146
+ * the platform accessibility APIs), each call checked against `interaction.surface {surface}`
1147
+ * and the session's permissions (see {@link InteractionSurface}).
1148
+ * Wrap one in an {@link InteractionDriver} and register it with
1149
+ * {@link KayAgentPluginApi.registerInteractionDriver} to make it drivable by the agent.
1150
+ */
1151
+ readonly interaction: KayAgentInteractionSurfaces;
770
1152
  /**
771
1153
  * Jev typed-decision inference, as an OPTIONAL accelerator with a REQUIRED fallback. Each call
772
- * is checked against `jev.use` — but a refused grant or a missing saved key both
1154
+ * is checked against `jev.use` — but a refused grant or no usable Jev provider both
773
1155
  * produce the same outcome: your `fallback` runs.
774
1156
  *
775
1157
  * Always present, on every host. That is the point: with no absent state to feature-detect,
@@ -777,6 +1159,14 @@ declare interface KayAgentPluginApi {
777
1159
  * guard it with `if (api.withJev !== undefined)`.
778
1160
  */
779
1161
  readonly withJev: WithJev;
1162
+ /**
1163
+ * The daemon's clock and the time zone the user is in, read together on each `snapshot()` call.
1164
+ * Always present and ungated: it confers no authority, since a plugin runs in the daemon's
1165
+ * process and can read the clock itself. Read the user's zone here, never from `Intl` or
1166
+ * `process.env.TZ`, and render user-facing times in it rather than an event's own zone. This is
1167
+ * the same zone-of-record port the session stamp uses; see {@link KayAppTime.snapshot}.
1168
+ */
1169
+ readonly time: KayAppTime;
780
1170
  /**
781
1171
  * Publish the plugin's declared events, for example so a default notification rule can tell the
782
1172
  * user what the agent just did. Always present, like {@link withJev}: there is nothing to
@@ -798,6 +1188,14 @@ declare interface KayAgentPluginApi {
798
1188
  * from `ctx.auth`. A provider without a binding reuses inference credentials or needs none.
799
1189
  */
800
1190
  registerSearchProvider(provider: SearchProvider): void;
1191
+ /**
1192
+ * Register an Interaction driver (a backend behind the `interaction_*` tools: something the agent
1193
+ * can read, click, type into, and open). The engine owns the tools, element ids, run loop,
1194
+ * permission checks, and screenshots; the driver owns only its I/O. Declare the driver's `id`
1195
+ * under `contributes.interactionDrivers` in kay-plugin.json first. A `browser` driver must set
1196
+ * `credentialGuard` (see {@link INTERACTION_CREDENTIAL_GUARD}).
1197
+ */
1198
+ registerInteractionDriver(driver: InteractionDriver): void;
801
1199
  /**
802
1200
  * Register a content converter (turns raw bytes of a mime type into agent-facing content behind the
803
1201
  * read tool's finalize stage). Parallel to the kernel's `registerConverter`. Converters are
@@ -998,9 +1396,84 @@ declare interface KayAgentWhiteboardUpdateInput {
998
1396
  readonly title?: string;
999
1397
  }
1000
1398
 
1399
+ /**
1400
+ * `app.time` / `api.time`: host facts about time. Added to `kay.app` in SDK 0.12.1 and to
1401
+ * `kay.agent` with the calendar zone-of-record work: a plugin that calls it declares
1402
+ * `compatibility.sdk` `^0.12.1`, so an older Bonsai refuses a directory or repository plugin at
1403
+ * load instead of the call failing.
1404
+ */
1405
+ declare interface KayAppTime {
1406
+ /**
1407
+ * Reads the daemon's clock and the user's time zone now.
1408
+ *
1409
+ * Every call asks the host again and returns a new object; nothing is cached. Call it where you
1410
+ * need the value (inside a tool, a handler or a workflow step), not inside `activate()`: a value
1411
+ * read there is as old as the activation, and the host can run a bundled plugin's `activate()`
1412
+ * against a recording api that has no `time`, so a read there throws. The exception is a
1413
+ * directory plugin that declares a workflow with a cron `timezone`: `workflows.define` is legal
1414
+ * only during `activate()`, so it reads the zone there, and the schedule then keeps that zone.
1415
+ * Keep the result for as long as you use it, and not across a long wait (a sleep, a timer, a
1416
+ * queued run): the zone can change while you wait. On a daemon that runs on the user's machine,
1417
+ * a change of the process's `TZ` shows in the next call. A `TZ` that names a zone wins over the
1418
+ * operating system's zone, so a change of the operating-system zone does not show while the
1419
+ * process has one. When `TZ` is unset or does not name a zone, a change of the operating-system
1420
+ * zone is meant to show, but none has been seen on a real machine yet.
1421
+ *
1422
+ * A zone the host cannot determine is an answer (`zoneSource: "utc-fallback"`), not an error.
1423
+ *
1424
+ * Use this to find the zone, not `Intl.DateTimeFormat().resolvedOptions().timeZone`, which can
1425
+ * keep a zone the runtime read earlier, or `process.env.TZ`, which is often unset or not a zone.
1426
+ * Neither says that the zone is unknown.
1427
+ *
1428
+ * It does not use `this`, so it is safe to destructure.
1429
+ */
1430
+ readonly snapshot: () => KayAppTimeSnapshot;
1431
+ }
1432
+
1433
+ /**
1434
+ * The plugin-facing time contract: the daemon's clock and the time zone the user is in,
1435
+ * read together in one call.
1436
+ *
1437
+ * Ungated and always present, like `app.paths`. It confers no authority: a plugin runs in the
1438
+ * daemon's process and can already read the clock. What the door adds is the daemon's answer
1439
+ * for the USER's zone, and a label for the case where that answer is unknown.
1440
+ *
1441
+ * This is a leaf module. It lives beside both target SDKs (rather than inside `kay-app`) so the
1442
+ * `kay.agent` SDK can expose the same door without importing the `kay.app` surface, which pulls
1443
+ * that surface into every agent-facing bundle.
1444
+ */
1445
+ /** One reading of the daemon's clock and the user's time zone. Each call returns a new object. */
1446
+ declare interface KayAppTimeSnapshot {
1447
+ /** The daemon's clock when the snapshot was read: milliseconds since the Unix epoch. */
1448
+ readonly nowMs: number;
1449
+ /**
1450
+ * The time zone the user is in, as an IANA id in the spelling ICU resolves (`America/New_York`).
1451
+ * One zone can have two ids, and ICU picks one: `Asia/Kolkata` comes back as `Asia/Calcutta`. So
1452
+ * never compare zone ids with `===`. A first-party plugin compares with `sameZone` from
1453
+ * `@kay/time`. A plugin that imports only this SDK and node builtins resolves each id with
1454
+ * `new Intl.DateTimeFormat("en-US", { timeZone: id }).resolvedOptions().timeZone` and compares the
1455
+ * results. Pass `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a
1456
+ * time for the user.
1457
+ *
1458
+ * When `zoneSource` is `utc-fallback` the zone is unknown, and this value is `UTC` only because a
1459
+ * value is required.
1460
+ */
1461
+ readonly zone: string;
1462
+ /**
1463
+ * How the daemon found `zone`.
1464
+ * - `host`: the daemon runs on the user's machine, and `zone` is the zone the daemon process
1465
+ * runs in, read for this call: the process's `TZ` when that names a zone, otherwise the
1466
+ * operating system's zone.
1467
+ * - `utc-fallback`: the daemon does not know the user's zone. It runs on another machine (a remote
1468
+ * daemon), or the machine's zone could not be read or is not an IANA id. `zone` is `UTC`, which
1469
+ * here is a placeholder and not a fact about the user: do not show it to the user as their zone.
1470
+ */
1471
+ readonly zoneSource: "host" | "utc-fallback";
1472
+ }
1473
+
1001
1474
  declare type KnownApi = "openai-completions" | "mistral-conversations" | "openai-responses" | "azure-openai-responses" | "openai-codex-responses" | "anthropic-messages" | "bedrock-converse-stream" | "google-generative-ai" | "google-vertex" | "pi-messages";
1002
1475
 
1003
- declare type KnownProvider = "amazon-bedrock" | "ant-ling" | "anthropic" | "google" | "google-vertex" | "openai" | "azure-openai-responses" | "openai-codex" | "radius" | "nvidia" | "deepseek" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "vercel-ai-gateway" | "zai" | "zai-coding-cn" | "mistral" | "minimax" | "minimax-cn" | "moonshotai" | "moonshotai-cn" | "huggingface" | "fireworks" | "together" | "baseten" | "opencode" | "opencode-go" | "kimi-coding" | "meta" | "cloudflare-workers-ai" | "cloudflare-ai-gateway" | "qwen-token-plan" | "qwen-token-plan-cn" | "qwen-token-plan-individual" | "xiaomi" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-sgp";
1476
+ declare type KnownProvider = "amazon-bedrock" | "ant-ling" | "anthropic" | "google" | "google-vertex" | "openai" | "azure-openai-responses" | "openai-codex" | "radius" | "typesafe" | "nvidia" | "deepseek" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "vercel-ai-gateway" | "zai" | "zai-coding-cn" | "mistral" | "minimax" | "minimax-cn" | "moonshotai" | "moonshotai-cn" | "huggingface" | "fireworks" | "together" | "baseten" | "opencode" | "opencode-go" | "kimi-coding" | "meta" | "cloudflare-workers-ai" | "cloudflare-ai-gateway" | "qwen-token-plan" | "qwen-token-plan-cn" | "qwen-token-plan-individual" | "xiaomi" | "xiaomi-token-plan-cn" | "xiaomi-token-plan-ams" | "xiaomi-token-plan-sgp";
1004
1477
 
1005
1478
  declare interface LineRange {
1006
1479
  readonly start: number;
@@ -1051,29 +1524,26 @@ declare interface MistralConversationsCompat {
1051
1524
  supportsMidConvoSystemMessages?: boolean;
1052
1525
  }
1053
1526
 
1054
- declare interface Model<TApi extends Api> {
1055
- id: string;
1056
- name: string;
1057
- api: TApi;
1058
- provider: ProviderId;
1059
- baseUrl: string;
1527
+ /** Chat model: usable with `stream()` and friends. */
1528
+ declare interface Model<TApi extends Api> extends BaseModel<TApi> {
1529
+ /**
1530
+ * Optional: chat is the default model type, so models without `type` are chat
1531
+ * models. Narrow mixed model lists with `isModelType()` instead of comparing
1532
+ * `type` directly.
1533
+ */
1534
+ type?: "chat";
1060
1535
  reasoning: boolean;
1061
1536
  /**
1062
1537
  * Maps pi thinking levels to provider/model-specific values.
1063
1538
  * Missing keys use provider defaults. null marks a level as unsupported.
1064
1539
  */
1065
1540
  thinkingLevelMap?: ThinkingLevelMap;
1066
- input: ("text" | "image")[];
1067
- /** Provider input limits and cache-safe preprocessing metadata. */
1068
- inputLimits?: ModelInputLimits;
1069
- cost: ModelCost;
1070
1541
  /** Prompt cache lifetimes per retention tier. Unset when the provider's cache behavior is unknown. */
1071
1542
  promptCache?: ModelPromptCache;
1072
1543
  contextWindow: number;
1073
1544
  maxTokens: number;
1074
1545
  /** Default sampling parameters for this model. See {@link StreamOptions.samplingParams}; per-request keys override these. */
1075
1546
  samplingParams?: Record<string, unknown>;
1076
- headers?: Record<string, string>;
1077
1547
  /** Compatibility overrides for OpenAI-compatible APIs. If not set, auto-detected from baseUrl. */
1078
1548
  compat?: TApi extends "openai-completions" ? OpenAICompletionsCompat : TApi extends "openai-responses" | "azure-openai-responses" | "openai-codex-responses" ? OpenAIResponsesCompat : TApi extends "anthropic-messages" ? AnthropicMessagesCompat : TApi extends "bedrock-converse-stream" ? BedrockCompat : TApi extends "mistral-conversations" ? MistralConversationsCompat : never;
1079
1549
  }
@@ -1386,8 +1856,15 @@ declare interface PluginDelegatedScheme {
1386
1856
  /** Run the connect flow and mint the material to store. Throw to fail the connect. */
1387
1857
  readonly connect: (ctx: PluginDelegatedConnectContext) => Promise<PluginDelegatedConnectResult>;
1388
1858
  /**
1389
- * Mint fresh material from the current (expiring) material. Absent means non-refreshable:
1390
- * expired material resolves as-is (like an OAuth scheme without a refresh token).
1859
+ * Mint fresh material from the current (expiring) material, including the `data` the last
1860
+ * connect or refresh returned. Kay calls this only inside its credential authority, which holds
1861
+ * the refresh lease and saves the result; this hook performs the exchange and nothing else.
1862
+ * Returned `data` replaces the stored `data`; omitted `data` keeps it. Returned `expiresAt`
1863
+ * replaces the stored expiry; omitted `expiresAt` means the new material does not expire.
1864
+ * Throw {@link DelegatedRefreshRejectedError} when the provider refused the grant for good (the
1865
+ * user must reconnect); any other throw is retried with backoff and keeps the account connected.
1866
+ * Absent means non-refreshable: expired material resolves as-is (like an OAuth scheme without a
1867
+ * refresh token).
1391
1868
  */
1392
1869
  readonly refresh?: (material: PluginDelegatedSecretMaterial) => Promise<PluginDelegatedSecretMaterial>;
1393
1870
  /**
@@ -1996,6 +2473,19 @@ declare interface ToolCallModel {
1996
2473
  */
1997
2474
  declare type ToolCallOrigin = "model" | "host";
1998
2475
 
2476
+ /** A call to judge with {@link ToolContext.checkToolCallPermission}. */
2477
+ declare interface ToolCallPermissionCheck {
2478
+ readonly toolName: string;
2479
+ readonly input: Record<string, unknown>;
2480
+ }
2481
+
2482
+ declare type ToolCallPermissionVerdict = {
2483
+ readonly allowed: true;
2484
+ } | {
2485
+ readonly allowed: false;
2486
+ readonly reason: string;
2487
+ };
2488
+
1999
2489
  /**
2000
2490
  * What a tool call ADDRESSES, resolved by the session before execution from facts it already
2001
2491
  * holds for auth scoping: a URI verb's matched module (and the extension that registered it), or
@@ -2038,6 +2528,13 @@ declare interface ToolContext {
2038
2528
  * behind itself. Present only with a live session. One request may be pending at a time.
2039
2529
  */
2040
2530
  readonly requestMidTurnCompaction?: (customInstructions?: string, trigger?: "command" | "suggestion") => MidTurnCompactionRequest;
2531
+ /**
2532
+ * Put a call this tool is about to cause through the session's permission gate, as if the agent
2533
+ * had made it directly: classification, rules, mode, the auto approver, and the approval card.
2534
+ * The call is only judged, never executed. For a tool whose effect is only knowable at run time
2535
+ * (a click in a web page that turns out to send an email). Present only with a live session.
2536
+ */
2537
+ readonly checkToolCallPermission?: (call: ToolCallPermissionCheck) => Promise<ToolCallPermissionVerdict>;
2041
2538
  /**
2042
2539
  * Re-root the session into `newCwd` mid-run, recomposing the cwd-scoped substrate (builtin tools,
2043
2540
  * the capability registry, the system-prompt project line) in place so subsequent tool calls operate
@@ -2607,6 +3104,21 @@ declare interface UriModule {
2607
3104
  */
2608
3105
  readonly title?: string;
2609
3106
  readonly fallback?: boolean;
3107
+ /**
3108
+ * Whether this module parses the read tool's trailing line selector out of its own addresses.
3109
+ * Absent or false: the host owns the explicit forms (`:50-200`, `:50-`, `:50+10`, `:raw`). The
3110
+ * read tool strips one before dispatch, hands `read` the bare address, and applies the window
3111
+ * to what comes back, so a module never has to know the grammar for the read tool's own
3112
+ * `Continue with '<address>:N-M'` banner to work on its addresses (#10754). A bare trailing
3113
+ * `:<digits>` is never taken from such a module: it is too common inside real ids (a Figma
3114
+ * node `1:2`), so it reaches the module as written.
3115
+ *
3116
+ * Declare `true` only when the module must see the raw address: its grammar can end in an
3117
+ * explicit-range shape, it wants the bare `:50` form too, or it windows the content itself
3118
+ * (streaming a large file, skipping a cap it applies to an unwindowed read). Such a module
3119
+ * calls `parseLineSelector` itself and reports what it did through `RawResource.selector`.
3120
+ */
3121
+ readonly ownsLineSelectors?: boolean;
2610
3122
  readonly claims?: readonly UriClaim[];
2611
3123
  /** Migration-only prompt summary until structured help/catalog coverage replaces prose. */
2612
3124
  readonly description?: string;
@@ -2616,14 +3128,17 @@ declare interface UriModule {
2616
3128
  /** Pure route/payload validation applied before a consequential permission ask. */
2617
3129
  readonly preflight?: UriOperationPreflightPolicy;
2618
3130
  /**
2619
- * Structured facts naming the WHOLE consequence of this call, or `undefined` when
2620
- * the route cannot honestly be described on a one-line approval surface. The module
3131
+ * Structured facts for approval surfaces, or `undefined` when unavailable.
3132
+ * A one-line description must name the whole consequence; `preview` instead
3133
+ * supplies expanded, literal-text detail and suppresses one-line approval. The module
2621
3134
  * owns the static action phrase, target resolution, payload decoding and declaration
2622
3135
  * of covered payload fields and query parameters. Unknown fields cost the summary.
2623
3136
  * The host owns framing, the whole-quote fit (no elision) and display-safety admission.
2624
3137
  *
2625
3138
  * Unlike preflight, this hook is async and may do I/O. Resolve names through `ctx`,
2626
- * the same dispatch context used by execution, never an ambient or cached account.
3139
+ * the same dispatch context used by execution, never an ambient or cached account. A name
3140
+ * the module resolved under that account may be cached for a bounded time, keyed by that
3141
+ * account's identity and never answered to another account or after a failed lookup.
2627
3142
  * The host calls it once before raising the ask, enforces the short `ctx.signal`
2628
3143
  * deadline and discards late answers. A throw yields no summary and a module-attributed
2629
3144
  * diagnostic; declining costs a click into the app, never an under-described approval.
@@ -2633,6 +3148,26 @@ declare interface UriModule {
2633
3148
  readonly uri: string;
2634
3149
  readonly payload: unknown;
2635
3150
  }, ctx: UriResolveContext): Promise<UriOperationDescription | undefined>;
3151
+ /**
3152
+ * A short, render-only name for the resource a settled call on `request.uri` touched, which the
3153
+ * host stamps on the tool result's `details` so a transcript row can name it where it would
3154
+ * otherwise print the address (`#lane-analytics` and `thread`, not a channel id). Answer
3155
+ * `undefined` for any address you cannot honestly name.
3156
+ *
3157
+ * Called once per successful URI verb call, AFTER the verb handler has returned, with the same
3158
+ * dispatch context. Resolve names through `ctx` and nothing else, and prefer a cache your own
3159
+ * verb handlers warm, keyed by the executing account: a name one account saw is never answered
3160
+ * to another, and a failed, blank or aborted lookup is never cached. The host bounds the wait
3161
+ * (a finished result is held at most a quarter of a second), gives `ctx.signal` a hard deadline,
3162
+ * and drops a late, thrown or refused answer without failing the call; a throw is reported as a
3163
+ * module-attributed diagnostic. The label is a label, never an identity: the address remains the
3164
+ * click target, hover text and accessible name. It is UI-only, so it never enters the tool
3165
+ * result's content and no telemetry reads it.
3166
+ *
3167
+ * Unlike `describeOperation` this is not an approval surface: it carries no consequence, no
3168
+ * quote and no coverage claim, and nothing may gate a permission on it.
3169
+ */
3170
+ labelResource?(request: UriResourceLabelRequest, ctx: UriResolveContext): Promise<UriResourceLabel | undefined>;
2636
3171
  /**
2637
3172
  * Per-resource observability: does a `format: "observation"` read of THIS
2638
3173
  * uri render source-native material ({@link UriResolveContext.format})?
@@ -2753,6 +3288,18 @@ declare interface UriOperationDescription {
2753
3288
  readonly target: string;
2754
3289
  /** Model-authored content; the host flattens, budgets, elides and bounds it. */
2755
3290
  readonly quote?: string;
3291
+ /** Full, render-only detail. Hosts must not turn a rich preview into one-line approval. */
3292
+ readonly preview?: {
3293
+ readonly title: string;
3294
+ readonly description?: string;
3295
+ readonly fields?: readonly {
3296
+ readonly label: string;
3297
+ readonly value: string;
3298
+ readonly oldValue?: string;
3299
+ }[];
3300
+ };
3301
+ /** True only when every displayed fact comes from the input, independent of the executing account. */
3302
+ readonly accountIndependent?: true;
2756
3303
  /** What this description accounts for; the host refuses undeclared input. */
2757
3304
  readonly accounts: {
2758
3305
  /** The payload actually read by the module, after its own decoding. */
@@ -3016,6 +3563,24 @@ declare interface UriResourceDescription {
3016
3563
  readonly sourceUrl?: string;
3017
3564
  }
3018
3565
 
3566
+ /**
3567
+ * What a settled call touched, as a person would name it.
3568
+ *
3569
+ * `name` is the resource itself (`#lane-analytics`). `section` is the part of it the address
3570
+ * reaches into (`thread`), and is absent when the address is the resource.
3571
+ */
3572
+ declare interface UriResourceLabel {
3573
+ readonly name: string;
3574
+ readonly section?: string;
3575
+ }
3576
+
3577
+ /** The call a module is asked to label. */
3578
+ declare interface UriResourceLabelRequest {
3579
+ readonly operation: UriOperation;
3580
+ /** The dispatch address: selector-stripped, the exact form the module's verb handler received. */
3581
+ readonly uri: string;
3582
+ }
3583
+
3019
3584
  declare interface UriSchemeClaim {
3020
3585
  readonly kind: "scheme";
3021
3586
  readonly scheme: string;
@@ -3332,8 +3897,8 @@ declare type WhiteboardValue = z.infer<typeof WhiteboardValue>;
3332
3897
  /**
3333
3898
  * Run `use` against a live Jev client, falling back to `fallback` whenever Jev cannot serve the
3334
3899
  * call. The wrapper exists so a feature can ASK for a typed decision without ever depending on
3335
- * one: `fallback` is required, and it runs whenever no host-managed key is saved,
3336
- * the user has not granted `jev.use`, the branch exceeds its budget, `use` throws, or
3900
+ * one: `fallback` is required, and it runs whenever no provider in the user's Jev provider
3901
+ * order holds a usable credential, the user has not granted `jev.use`, the branch exceeds its budget, `use` throws, or
3337
3902
  * `use` declines by returning `undefined`. With valid options, this rejects on an explicit
3338
3903
  * `signal` abort, reaching `deadlineAt`, or `fallback` itself throwing.
3339
3904
  *
@@ -3341,10 +3906,9 @@ declare type WhiteboardValue = z.infer<typeof WhiteboardValue>;
3341
3906
  * {@link createFallbackOnlyWithJev}, so a caller never branches on availability — branching is
3342
3907
  * exactly how a fallback gets skipped.
3343
3908
  *
3344
- * `jev` is the vendor's own `TypeSafeClient`, configured with the host's default model and base
3345
- * URL. Native `request.model` overrides remain supported. It
3346
- * is valid only for the duration of the callback: a reference retained past `use`'s scope is
3347
- * refused at the transport, and an in-flight request is aborted when the call stops waiting.
3909
+ * `jev` is a {@link JevClient} on the host's Jev model. It is valid only for the duration of
3910
+ * the callback: a reference retained past `use`'s scope is refused at the transport, and an
3911
+ * in-flight request is aborted when the call stops waiting.
3348
3912
  * The callback itself is ABANDONED, not interrupted — a host cannot stop arbitrary JavaScript
3349
3913
  * that is already running, so `use` must not perform side effects it would mind completing
3350
3914
  * unobserved. The same applies to a running fallback: abort/deadline stops waiting for it but
@@ -3353,7 +3917,7 @@ declare type WhiteboardValue = z.infer<typeof WhiteboardValue>;
3353
3917
  declare type WithJev = <T>(
3354
3918
  /** Return `undefined` to decline (the fallback runs). A feature whose real result can itself be
3355
3919
  * `undefined` should return `null` or its own wrapper type instead. */
3356
- use: (jev: TypeSafeClient) => T | undefined | PromiseLike<T | undefined>,
3920
+ use: (jev: JevClient) => T | undefined | PromiseLike<T | undefined>,
3357
3921
  /** Required. The behaviour the feature has without Jev. */
3358
3922
  fallback: () => T | PromiseLike<T>, options?: WithJevOptions) => Promise<T>;
3359
3923