@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,8 +1,3 @@
1
- import { Questions } from '@typesafe-ai/sdk';
2
- import { SystemOneRequest } from '@typesafe-ai/sdk';
3
- import { SystemOneResult } from '@typesafe-ai/sdk';
4
- import { TypeSafeClient } from '@typesafe-ai/sdk';
5
- import { Usage } from '@typesafe-ai/sdk';
6
1
  import { z } from 'zod';
7
2
  import type * as z_2 from 'zod';
8
3
 
@@ -28,6 +23,9 @@ export declare interface AccountIdentity {
28
23
  readonly avatarUrl?: string;
29
24
  /** Issuer-asserted beta-tester flag; only Kay's product-account service sets it. */
30
25
  readonly betaTester?: boolean;
26
+ readonly activeOrganizationId?: string;
27
+ readonly organizationSelectionState?: "selected" | "unresolved";
28
+ readonly organizationScopeEpoch?: number;
31
29
  /**
32
30
  * Provider-native session id claim (WorkOS's `sid`), needed to call the provider's own
33
31
  * session-revocation endpoint at sign-out (`POST /user_management/sessions/revoke`, not yet
@@ -100,8 +98,18 @@ export declare interface AgentToolResult<T = JsonValue_2 | undefined> {
100
98
  content: (TextContent | ImageContent)[];
101
99
  /** Arbitrary structured details for logs or UI rendering. */
102
100
  details: T;
101
+ /**
102
+ * Machine-readable result matching the tool's `outputSchema`, for programmatic callers. Not sent
103
+ * to the model; `content` remains the model-facing result.
104
+ */
105
+ structuredContent?: JsonValue_2;
103
106
  /** Usage from the final tool execution itself, if available. Not used for main LLM context accounting. */
104
- usage?: Usage_2;
107
+ usage?: Usage;
108
+ /**
109
+ * Report a failure without throwing. The model sees `content` as an error result, like a thrown
110
+ * error, but `details` and `structuredContent` are kept for the UI and programmatic callers.
111
+ */
112
+ isError?: boolean;
105
113
  /**
106
114
  * Hint that the agent should stop after the current tool batch.
107
115
  * Early termination only happens when every finalized tool result in the batch sets this to true.
@@ -340,6 +348,20 @@ declare interface BackgroundTaskSnapshot {
340
348
 
341
349
  declare type BackgroundTaskStatus = "queued" | "running" | "completed" | "failed" | "cancelled";
342
350
 
351
+ /** Fields shared by every catalog entry, regardless of what you can do with it. */
352
+ declare interface BaseModel<TApi extends string> {
353
+ id: string;
354
+ name: string;
355
+ api: TApi;
356
+ provider: ProviderId;
357
+ baseUrl: string;
358
+ input: ("text" | "image")[];
359
+ /** Provider input limits and cache-safe preprocessing metadata. */
360
+ inputLimits?: ModelInputLimits;
361
+ cost: ModelCost;
362
+ headers?: Record<string, string>;
363
+ }
364
+
343
365
  export declare function basicUriHelp(options: {
344
366
  readonly uri: string;
345
367
  readonly title: string;
@@ -644,6 +666,8 @@ export declare function defineKayAgentAdvertisement(advertisement: KayAgentTarge
644
666
 
645
667
  export declare function defineTool<TParams extends ToolParametersWire = ToolParametersWire, TDetails = unknown>(definition: PluginToolDefinition<TParams, TDetails>): ToolDefinition<TParams, TDetails>;
646
668
 
669
+ declare const DELEGATED_REFRESH_REJECTED: unique symbol;
670
+
647
671
  /**
648
672
  * What `service_connect` hands a delegated scheme's {@link DelegatedAuthScheme.connect}: the
649
673
  * scope being connected plus the host's browser-redirect capability when one is configured.
@@ -665,12 +689,29 @@ declare interface DelegatedConnectContext {
665
689
  /** What a delegated scheme's `connect` resolves with: the material to vault + optional label/provenance. */
666
690
  declare interface DelegatedConnectResult {
667
691
  readonly material: DelegatedSecretMaterial;
692
+ /**
693
+ * A stable account id for this sign-in, used instead of a freshly minted one, so a reconnect
694
+ * overwrites the same record (and keeps it the default) rather than adding a sibling. 1-128
695
+ * characters: letters, digits, and `._:@+-`, starting with a letter or digit; any other value
696
+ * fails the connect. Absent mints a fresh id per connect.
697
+ */
698
+ readonly accountId?: string;
668
699
  /** Account display label; a caller-supplied `service_connect` label takes precedence. */
669
700
  readonly label?: string;
670
701
  /** Structured provenance the scheme derived during connect; persisted via the vault's write-path. */
671
702
  readonly provenance?: AccountProvenance;
672
703
  }
673
704
 
705
+ /**
706
+ * The terminal failure of {@link PluginDelegatedScheme.refresh}: the provider no longer accepts the
707
+ * stored grant (an OAuth `invalid_grant`, say), so only a reconnect helps. Kay marks the account
708
+ * as needing a reconnect. Throw any other error for a failure that may pass on its own.
709
+ */
710
+ export declare class DelegatedRefreshRejectedError extends Error {
711
+ readonly [DELEGATED_REFRESH_REJECTED] = true;
712
+ constructor(message: string, options?: ErrorOptions);
713
+ }
714
+
674
715
  /**
675
716
  * Token material minted by a delegated scheme's extension-provided flow. Core reads only
676
717
  * `accessToken`/`expiresAt` (resolution + proactive refresh); `data` is an opaque blob the
@@ -838,6 +879,366 @@ declare type InferToolInput<TParams extends ToolParametersWire> = TParams extend
838
879
  readonly [toolParametersInput]?: infer TInput;
839
880
  } ? TInput : TParams;
840
881
 
882
+ /**
883
+ * The value a Browser Interaction driver sets as `credentialGuard` to declare that every act runs
884
+ * the page-side credential guard from `@kay/interaction-page-scripts` (never type into or click a
885
+ * sign-in form). The engine refuses to register a browser driver without it.
886
+ */
887
+ export declare const INTERACTION_CREDENTIAL_GUARD = "kay.credential-guard/v1";
888
+
889
+ export declare interface InteractionActed {
890
+ /** The address of the target acted on, when it changed (an open landed in a new page). */
891
+ readonly target?: string;
892
+ readonly url: string;
893
+ readonly title: string;
894
+ /** What the action visibly caused: a dialog, an alert, a page opened beside it. */
895
+ readonly changes?: readonly string[];
896
+ readonly notes?: readonly string[];
897
+ /** Fresh browser sign-in state for the service the engine named in the open spec. */
898
+ readonly webSession?: {
899
+ readonly state: "signed-in" | "signed-out" | "unknown";
900
+ readonly checkedAt: number | null;
901
+ };
902
+ }
903
+
904
+ /**
905
+ * One action over a candidate from the latest observation of the same target. `fill` replaces the
906
+ * field's contents unless `append` is set, and presses Enter afterwards when `submit` is set.
907
+ */
908
+ export declare type InteractionAction = {
909
+ readonly kind: "click";
910
+ readonly element: InteractionCandidate;
911
+ } | {
912
+ readonly kind: "fill";
913
+ readonly element: InteractionCandidate;
914
+ readonly text: string;
915
+ readonly submit?: boolean;
916
+ readonly append?: boolean;
917
+ } | {
918
+ readonly kind: "select";
919
+ readonly element: InteractionCandidate;
920
+ } | {
921
+ readonly kind: "activate";
922
+ readonly element: InteractionCandidate;
923
+ } | {
924
+ readonly kind: "press";
925
+ readonly element: InteractionCandidate;
926
+ }
927
+ /**
928
+ * Scroll by `delta` px (positive is down). With `element` (a `scroll` candidate that names a
929
+ * node), the scroll container that candidate scrolls; without, the whole page or window.
930
+ */
931
+ | {
932
+ readonly kind: "scroll";
933
+ readonly delta: number;
934
+ readonly element?: InteractionCandidate;
935
+ } | {
936
+ readonly kind: "wait";
937
+ };
938
+
939
+ /**
940
+ * One element (or control) an observation offers, with the kind of action it supports. `id` is
941
+ * the driver's per-observation id; the engine mints its own session-unique ids over it. Extra
942
+ * fields are the driver's native identity (a page node number, an accessibility token), returned
943
+ * to the driver untouched in {@link InteractionAction}.
944
+ */
945
+ export declare interface InteractionCandidate {
946
+ readonly id: string;
947
+ readonly kind: InteractionCandidateKind;
948
+ readonly label: string;
949
+ readonly node?: number | undefined;
950
+ readonly role?: string | undefined;
951
+ readonly value?: string | undefined;
952
+ readonly current_value?: string | undefined;
953
+ readonly checked?: string | undefined;
954
+ readonly selected?: string | undefined;
955
+ readonly expanded?: string | undefined;
956
+ readonly delta?: number | undefined;
957
+ /** Where an element outside the visible area sits; absent means on screen. */
958
+ readonly position?: "above" | "below" | "beside" | undefined;
959
+ /** A `press` candidate's key (`return`, `escape`, `tab`); its id is `press_<key>` by convention. */
960
+ readonly key?: string | undefined;
961
+ /** The region the element sits in; see {@link InteractionRegion}. */
962
+ readonly region?: InteractionRegion | undefined;
963
+ /**
964
+ * The `node` of the scroll container (a list or pane that scrolls on its own) the element sits
965
+ * in, matching that container's `scroll` candidates; absent when it sits in none.
966
+ */
967
+ readonly scroller?: number | undefined;
968
+ readonly [native: string]: unknown;
969
+ }
970
+
971
+ /** The candidate kinds a driver may offer. */
972
+ export declare type InteractionCandidateKind = "click" | "fill" | "select" | "scroll" | "wait" | "activate" | "press";
973
+
974
+ export declare interface InteractionDriver {
975
+ /** Unique in the session. `builtin:` is reserved for Kay's own drivers. */
976
+ readonly id: string;
977
+ /** Human-readable name the agent sees beside the driver's targets. */
978
+ readonly label: string;
979
+ readonly kind: InteractionDriverKind;
980
+ /** Required on a `browser` driver; see {@link INTERACTION_CREDENTIAL_GUARD}. */
981
+ readonly credentialGuard?: typeof INTERACTION_CREDENTIAL_GUARD;
982
+ /** Whether the driver can act at all right now (platform, grants, a live connection). */
983
+ isAvailable(): Promise<boolean>;
984
+ targets(): Promise<InteractionOutcome<{
985
+ readonly targets: readonly InteractionTarget[];
986
+ }>>;
987
+ observe(target: string | undefined, options?: {
988
+ readonly fullText?: boolean;
989
+ }): Promise<InteractionOutcome<InteractionObserved>>;
990
+ act(target: string | undefined, action: InteractionAction): Promise<InteractionOutcome<InteractionActed>>;
991
+ screenshot(target: string | undefined): Promise<InteractionOutcome<{
992
+ readonly png: Uint8Array;
993
+ }>>;
994
+ open(spec: InteractionOpenSpec): Promise<InteractionOutcome<InteractionActed>>;
995
+ }
996
+
997
+ /**
998
+ * The Interaction driver contract: what a plugin implements to let Kay's agent drive something
999
+ * on the user's machine (a browser, an app, a remote screen) through the harness-owned
1000
+ * Interaction engine.
1001
+ *
1002
+ * The engine owns everything that is policy: the `interaction_*` tools, the session-unique element
1003
+ * ids the agent sees, the run loop that drives a goal step by step, the permission check before
1004
+ * every action, screenshots, and reports. A driver owns only its own I/O: list what it can drive,
1005
+ * observe one target as a list of actionable candidates, perform one action on a candidate from
1006
+ * its latest observation, capture a screenshot, and open a page or app. It chooses no actions,
1007
+ * maps no permissions, and retries nothing beyond its own transport. That split is what makes
1008
+ * every tool work on every driver.
1009
+ *
1010
+ * Shape mirrors `SearchProvider` behind `web_search`: one tool set owned by the harness, many
1011
+ * backends registered per session, the `builtin:` id namespace reserved for Kay's own.
1012
+ */
1013
+ /** "Browser Interaction" drives web pages; "Computer Use Interaction" drives native apps. */
1014
+ export declare type InteractionDriverKind = "browser" | "computer-use";
1015
+
1016
+ /** A failed operation. `unavailable`: nothing to act on; `refused`: will not run as asked. */
1017
+ export declare interface InteractionFailure {
1018
+ readonly ok: false;
1019
+ readonly reason: "unavailable" | "refused" | "error";
1020
+ readonly message: string;
1021
+ }
1022
+
1023
+ /** What a driver sees on one target. */
1024
+ export declare interface InteractionObservation {
1025
+ readonly url: string;
1026
+ readonly title: string;
1027
+ /** Visible text, or the whole page's text when the observe asked for `fullText`; capped. */
1028
+ readonly text: string;
1029
+ readonly actions: readonly InteractionCandidate[];
1030
+ /** Candidates the driver dropped to stay within its cap. */
1031
+ readonly omitted_actions: number;
1032
+ }
1033
+
1034
+ export declare interface InteractionObserved {
1035
+ /** The address of the target observed; absent when the default target has no address. */
1036
+ readonly target?: string;
1037
+ readonly observation: InteractionObservation;
1038
+ /** Lines the engine shows the agent under the observation (where the target sits, siblings). */
1039
+ readonly notes?: readonly string[];
1040
+ }
1041
+
1042
+ /** Navigate a page to `url`, or launch / switch to the app `app` names (a bundle id or a name). */
1043
+ export declare interface InteractionOpenSpec {
1044
+ readonly target?: string;
1045
+ readonly url?: string;
1046
+ readonly app?: string;
1047
+ /** The service whose browser sign-in state to report after navigation, when the engine knows it. */
1048
+ readonly webSessionServiceId?: string;
1049
+ }
1050
+
1051
+ export declare type InteractionOutcome<T> = ({
1052
+ readonly ok: true;
1053
+ } & T) | InteractionFailure;
1054
+
1055
+ /**
1056
+ * The part of a page or window an element sits in: the open dialog, menu, or sheet it belongs to,
1057
+ * else its landmark (navigation, main, a window). `front` marks the overlay covering the rest: a
1058
+ * modal dialog (or one held by a full-screen overlay), a sheet, or a floating menu, the last such
1059
+ * in the document; elements outside it
1060
+ * usually cannot be clicked while it is open. A docked or always-visible dialog or menu is a
1061
+ * region but never in front.
1062
+ */
1063
+ export declare interface InteractionRegion {
1064
+ readonly role: string;
1065
+ readonly name: string;
1066
+ readonly front?: boolean | undefined;
1067
+ }
1068
+
1069
+ /**
1070
+ * One surface Kay ships, in the driver contract's own shape, so a plugin's driver is the surface
1071
+ * plus an identity: `{ id, label, kind, ...api.interaction.desktop }`. Each call is checked
1072
+ * against the plugin's `interaction.surface {surface}` grant, and then against the session's
1073
+ * permissions exactly as the agent's `interaction_*` tools are: an act is judged as the plugin
1074
+ * permission it amounts to (a Send click in Gmail as a Gmail write), an open as `interaction_open`,
1075
+ * an observation or screenshot as `interaction_read`. A refused or unavailable call answers
1076
+ * `{ ok: false }` (and `isAvailable()` false) rather than throwing.
1077
+ */
1078
+ export declare type InteractionSurface = Pick<InteractionDriver, "isAvailable" | "targets" | "observe" | "act" | "screenshot" | "open">;
1079
+
1080
+ /** The interaction surfaces Kay itself ships, which plugins drive through `api.interaction`. */
1081
+ export declare type InteractionSurfaceName = "browser-pane" | "desktop";
1082
+
1083
+ /**
1084
+ * One thing a driver can be pointed at. `id` is a driver-owned address, unique across every
1085
+ * driver in the session (prefix it with your scheme), that the agent passes back as `target`.
1086
+ * `active` marks the driver's default target.
1087
+ */
1088
+ export declare interface InteractionTarget {
1089
+ readonly id: string;
1090
+ readonly title: string;
1091
+ readonly url?: string;
1092
+ readonly active: boolean;
1093
+ }
1094
+
1095
+ /** Whether `error` is a {@link DelegatedRefreshRejectedError}, including one from another SDK copy. */
1096
+ export declare function isDelegatedRefreshRejected(error: unknown): error is DelegatedRefreshRejectedError;
1097
+
1098
+ export declare type JevAnswer = JevBoolAnswer | JevChoiceAnswer | JevScoreAnswer;
1099
+
1100
+ /** The answer shape one question gets back. */
1101
+ export declare type JevAnswerFor<Q> = Q extends JevBoolQuestion ? JevBoolAnswer : Q extends JevChoiceQuestion<infer L> ? JevChoiceAnswer<L> : Q extends JevScoreQuestion ? JevScoreAnswer : never;
1102
+
1103
+ export declare interface JevBoolAnswer {
1104
+ readonly type: "bool";
1105
+ /** P(yes), from 0 to 1. */
1106
+ readonly probability: number;
1107
+ }
1108
+
1109
+ /** A yes/no question. `criteria` says what yes and what no mean; omit it to leave both open. */
1110
+ export declare interface JevBoolQuestion {
1111
+ readonly type: "bool";
1112
+ readonly instructions: string;
1113
+ readonly criteria?: {
1114
+ readonly true: string;
1115
+ readonly false: string;
1116
+ };
1117
+ }
1118
+
1119
+ /**
1120
+ * The one error `classify` rejects with. It carries a classification, never the provider's own
1121
+ * message or body: those can echo the request state, and this error reaches logs.
1122
+ */
1123
+ export declare class JevCallError extends Error {
1124
+ readonly transport: JevTransport;
1125
+ readonly kind: JevCallErrorKind;
1126
+ /** The final attempt's HTTP status, when a response arrived. */
1127
+ readonly status: number | undefined;
1128
+ constructor(init: {
1129
+ readonly transport: JevTransport;
1130
+ readonly kind: JevCallErrorKind;
1131
+ readonly status?: number | undefined;
1132
+ });
1133
+ }
1134
+
1135
+ /**
1136
+ * Why a Jev call failed, as a closed set:
1137
+ *
1138
+ * - `http`: the route answered with an error status (`status` says which).
1139
+ * - `too-large`: the route refused the request's size (413, or a 400 naming the token limit).
1140
+ * - `network`: no response arrived.
1141
+ * - `aborted`: the call was cancelled.
1142
+ * - `invalid-answer`: the route answered, but not with an answer for every asked question.
1143
+ */
1144
+ export declare type JevCallErrorKind = "http" | "too-large" | "network" | "aborted" | "invalid-answer";
1145
+
1146
+ export declare interface JevChoiceAnswer<L extends string = string> {
1147
+ readonly type: "choice";
1148
+ readonly choice: L;
1149
+ readonly confidence: number;
1150
+ /** P(label) for every offered label. */
1151
+ readonly probabilities: Readonly<Record<L, number>>;
1152
+ }
1153
+
1154
+ /** A choice among labels. Each label maps to what it means; an empty string leaves it open. */
1155
+ export declare interface JevChoiceQuestion<L extends string = string> {
1156
+ readonly type: "choice";
1157
+ readonly instructions: string;
1158
+ readonly criteria: Readonly<Record<L, string>>;
1159
+ }
1160
+
1161
+ /** One answered request: every asked question has an answer of its own kind. */
1162
+ export declare interface JevClassification<Q extends JevQuestions = JevQuestions> {
1163
+ /** The Jev model the host asked. */
1164
+ readonly model: string;
1165
+ readonly answers: {
1166
+ readonly [K in keyof Q]: JevAnswerFor<Q[K]>;
1167
+ };
1168
+ /** Token counts, when the route reported them. */
1169
+ readonly usage?: {
1170
+ readonly inputTokens: number;
1171
+ readonly outputTokens: number;
1172
+ };
1173
+ }
1174
+
1175
+ export declare interface JevClassifyRequest<Q extends JevQuestions = JevQuestions> {
1176
+ readonly state: JevState;
1177
+ readonly questions: Q;
1178
+ }
1179
+
1180
+ /**
1181
+ * The Jev client a `use` body receives. `classify` either resolves with an answer for every
1182
+ * asked question, each of its question's kind, or rejects with a {@link JevCallError}; it never
1183
+ * resolves with a partial or substituted answer.
1184
+ */
1185
+ export declare interface JevClient {
1186
+ classify<const Q extends JevQuestions>(request: JevClassifyRequest<Q>, options?: {
1187
+ readonly signal?: AbortSignal;
1188
+ }): Promise<JevClassification<Q>>;
1189
+ }
1190
+
1191
+ export declare type JevQuestion = JevBoolQuestion | JevChoiceQuestion | JevScoreQuestion;
1192
+
1193
+ /** A rubric: questions keyed by the name each answer comes back under. */
1194
+ export declare type JevQuestions = Readonly<Record<string, JevQuestion>>;
1195
+
1196
+ export declare interface JevScoreAnswer {
1197
+ readonly type: "score";
1198
+ /** The expected score, from 0 to the number of rungs minus one. */
1199
+ readonly score: number;
1200
+ readonly confidence: number;
1201
+ }
1202
+
1203
+ /** A score over ordered rungs: the first criterion scores 0, the next 1, and so on. */
1204
+ export declare interface JevScoreQuestion {
1205
+ readonly type: "score";
1206
+ readonly instructions: string;
1207
+ readonly criteria: readonly string[];
1208
+ }
1209
+
1210
+ /**
1211
+ * ---
1212
+ * responsibility: The plugin-facing CONTRACT for Jev typed-decision inference — the shape of
1213
+ * `api.withJev` on both plugin SDK targets, the {@link JevClient} a `use` body receives, the
1214
+ * question and answer vocabulary it speaks, and the fallback-only implementation a host
1215
+ * without a Jev lane binds.
1216
+ * owns:
1217
+ * - {@link WithJev}, {@link WithJevOptions}, {@link createFallbackOnlyWithJev}.
1218
+ * - {@link JevClient}, the {@link JevQuestion} and {@link JevAnswer} vocabulary, and
1219
+ * {@link JevCallError}.
1220
+ * does_not_own:
1221
+ * - The wire. The host serves `classify` over whichever route the user's Jev provider order
1222
+ * picks; a plugin never sees a vendor client, a vendor type, or a route.
1223
+ * - Credential resolution, the `jev.use` decision, the Jev-branch budget, or usage accounting.
1224
+ * Those are host-side (`@kay/agent-runtime`'s `kay/jev/`).
1225
+ * ---
1226
+ *
1227
+ * The vocabulary is Kay's own (SDK 0.12.0). Before it, `use` received TypeSafe's `TypeSafeClient`
1228
+ * and plugins coded against a vendor's types. It follows pi's classifier contract, which the host
1229
+ * runs Jev through: a yes/no question is `bool` and answers a `probability`, every instruction and
1230
+ * criterion is text, and the state is a JSON object.
1231
+ */
1232
+ /**
1233
+ * The state a rubric reads: a JSON object, never text or an array. Every value must survive
1234
+ * `JSON.stringify` unchanged (no functions or class instances), because it is sent as JSON.
1235
+ * Typed as `object` so a state declared as an interface fits without an index signature.
1236
+ */
1237
+ export declare type JevState = object;
1238
+
1239
+ /** The route a Jev call took: the user's own TypeSafe key, or Bonsai's hosted gateway. */
1240
+ export declare type JevTransport = "direct" | "hosted";
1241
+
841
1242
  /** The frozen `createJsonApiClient` surface — see the module doc for why it stops at these three. */
842
1243
  export declare interface JsonApiClient {
843
1244
  getJson<TBody = unknown>(url: string, options?: PluginApiQueryOptions): Promise<PluginApiResponse<TBody>>;
@@ -872,6 +1273,14 @@ declare type JsonValue_3 = string | number | boolean | null | JsonValue_3[] | {
872
1273
 
873
1274
  declare const JsonValue_3: z.ZodType<JsonValue_3>;
874
1275
 
1276
+ /**
1277
+ * The root selector the host binds to the session family's shared Whiteboard folder. The plugin
1278
+ * that owns the Whiteboard gets the whole folder; every other plugin gets its own
1279
+ * `plugins/<plugin-id>/` folder inside it. Calls on it are claims on
1280
+ * `filesystem.read`/`filesystem.write` with this `root`, decided like any other.
1281
+ */
1282
+ export declare const KAY_FAMILY_WHITEBOARD_FILESYSTEM_ROOT = "family-whiteboard";
1283
+
875
1284
  /** A plugin's Kay agent activation — receives only the brokered {@link KayAgentPluginApi}. */
876
1285
  export declare type KayAgentActivate = (api: KayAgentPluginApi) => void;
877
1286
 
@@ -962,10 +1371,18 @@ export declare interface KayAgentEvents {
962
1371
  publish(localId: string, payload: unknown): void;
963
1372
  }
964
1373
 
965
- /** Claim-checked filesystem operations. Paths are root-relative; canonical host paths never cross the seam. */
1374
+ /**
1375
+ * Claim-checked filesystem operations. Paths are root-relative; canonical host paths never cross
1376
+ * the seam. Writes are atomic: readers see the old file or the new one, never a partial write. A
1377
+ * replace keeps the file's mode but makes a new file, so owner and extended attributes are not
1378
+ * carried over. On a volume without hard links an exclusive create can briefly show an empty file.
1379
+ */
966
1380
  export declare interface KayAgentFilesystem {
967
1381
  readText(location: KayAgentFilesystemLocation): Promise<string>;
968
- writeText(location: KayAgentFilesystemLocation, content: string): Promise<void>;
1382
+ writeText(location: KayAgentFilesystemLocation, content: string, options?: KayAgentFilesystemWriteOptions): Promise<void>;
1383
+ /** The whole file, or the requested window of it. */
1384
+ readBytes(location: KayAgentFilesystemLocation, range?: KayAgentFilesystemByteRange): Promise<Uint8Array>;
1385
+ writeBytes(location: KayAgentFilesystemLocation, bytes: Uint8Array, options?: KayAgentFilesystemWriteOptions): Promise<void>;
969
1386
  mkdir(location: KayAgentFilesystemLocation): Promise<void>;
970
1387
  readDir(location: KayAgentFilesystemLocation): Promise<readonly KayAgentFilesystemEntry[]>;
971
1388
  stat(location: KayAgentFilesystemLocation): Promise<KayAgentFilesystemStat>;
@@ -974,6 +1391,12 @@ export declare interface KayAgentFilesystem {
974
1391
  realpath(location: KayAgentFilesystemLocation): Promise<string>;
975
1392
  }
976
1393
 
1394
+ /** A byte window of a file; `maxBytes` is capped by the host. */
1395
+ export declare interface KayAgentFilesystemByteRange {
1396
+ readonly offset: number;
1397
+ readonly maxBytes: number;
1398
+ }
1399
+
977
1400
  export declare interface KayAgentFilesystemEntry {
978
1401
  readonly name: string;
979
1402
  readonly kind: "file" | "directory" | "symlink" | "other";
@@ -998,6 +1421,35 @@ export declare interface KayAgentFilesystemStat {
998
1421
  readonly modifiedAtMs: number;
999
1422
  }
1000
1423
 
1424
+ export declare interface KayAgentFilesystemWriteOptions {
1425
+ /** Fail with `already_exists` instead of replacing a file already at the location. */
1426
+ readonly exclusive?: boolean;
1427
+ }
1428
+
1429
+ /**
1430
+ * The host's per-session sink a plugin's drivers register into. Bound by the host to the plugin
1431
+ * and the session; a host that composed no Interaction engine drops registrations.
1432
+ */
1433
+ export declare interface KayAgentInteractionDrivers {
1434
+ register(driver: InteractionDriver): void;
1435
+ }
1436
+
1437
+ export declare interface KayAgentInteractionSurfaces {
1438
+ /**
1439
+ * Kay's built-in browser pane: the pages in the user's Bonsai tabs. The page-side credential
1440
+ * guard runs on every act, so a driver over this surface may declare
1441
+ * {@link INTERACTION_CREDENTIAL_GUARD}.
1442
+ */
1443
+ readonly browserPane: InteractionSurface;
1444
+ /**
1445
+ * The user's desktop through the platform's accessibility APIs: native apps as targets
1446
+ * (`app://<bundle id>`), their windows' controls as elements. On macOS Kay drives it with its
1447
+ * bundled accessibility worker under the app's Accessibility permission; on a platform with no
1448
+ * backend it reports itself unavailable.
1449
+ */
1450
+ readonly desktop: InteractionSurface;
1451
+ }
1452
+
1001
1453
  /** One knowledge-index hit — a reference and within-list rank score, never a snippet. */
1002
1454
  export declare interface KayAgentKnowledgeHit {
1003
1455
  readonly uri: string;
@@ -1150,9 +1602,17 @@ export declare interface KayAgentPluginApi {
1150
1602
  * command it is about to run, and against the host's executable binding.
1151
1603
  */
1152
1604
  readonly process: KayAgentProcess;
1605
+ /**
1606
+ * Always present; the interaction surfaces Kay ships (its browser pane, and the desktop through
1607
+ * the platform accessibility APIs), each call checked against `interaction.surface {surface}`
1608
+ * and the session's permissions (see {@link InteractionSurface}).
1609
+ * Wrap one in an {@link InteractionDriver} and register it with
1610
+ * {@link KayAgentPluginApi.registerInteractionDriver} to make it drivable by the agent.
1611
+ */
1612
+ readonly interaction: KayAgentInteractionSurfaces;
1153
1613
  /**
1154
1614
  * Jev typed-decision inference, as an OPTIONAL accelerator with a REQUIRED fallback. Each call
1155
- * is checked against `jev.use` — but a refused grant or a missing saved key both
1615
+ * is checked against `jev.use` — but a refused grant or no usable Jev provider both
1156
1616
  * produce the same outcome: your `fallback` runs.
1157
1617
  *
1158
1618
  * Always present, on every host. That is the point: with no absent state to feature-detect,
@@ -1160,6 +1620,14 @@ export declare interface KayAgentPluginApi {
1160
1620
  * guard it with `if (api.withJev !== undefined)`.
1161
1621
  */
1162
1622
  readonly withJev: WithJev;
1623
+ /**
1624
+ * The daemon's clock and the time zone the user is in, read together on each `snapshot()` call.
1625
+ * Always present and ungated: it confers no authority, since a plugin runs in the daemon's
1626
+ * process and can read the clock itself. Read the user's zone here, never from `Intl` or
1627
+ * `process.env.TZ`, and render user-facing times in it rather than an event's own zone. This is
1628
+ * the same zone-of-record port the session stamp uses; see {@link KayAppTime.snapshot}.
1629
+ */
1630
+ readonly time: KayAppTime;
1163
1631
  /**
1164
1632
  * Publish the plugin's declared events, for example so a default notification rule can tell the
1165
1633
  * user what the agent just did. Always present, like {@link withJev}: there is nothing to
@@ -1181,6 +1649,14 @@ export declare interface KayAgentPluginApi {
1181
1649
  * from `ctx.auth`. A provider without a binding reuses inference credentials or needs none.
1182
1650
  */
1183
1651
  registerSearchProvider(provider: SearchProvider): void;
1652
+ /**
1653
+ * Register an Interaction driver (a backend behind the `interaction_*` tools: something the agent
1654
+ * can read, click, type into, and open). The engine owns the tools, element ids, run loop,
1655
+ * permission checks, and screenshots; the driver owns only its I/O. Declare the driver's `id`
1656
+ * under `contributes.interactionDrivers` in kay-plugin.json first. A `browser` driver must set
1657
+ * `credentialGuard` (see {@link INTERACTION_CREDENTIAL_GUARD}).
1658
+ */
1659
+ registerInteractionDriver(driver: InteractionDriver): void;
1184
1660
  /**
1185
1661
  * Register a content converter (turns raw bytes of a mime type into agent-facing content behind the
1186
1662
  * read tool's finalize stage). Parallel to the kernel's `registerConverter`. Converters are
@@ -1395,6 +1871,81 @@ export declare interface KayAgentWhiteboardUpdateInput {
1395
1871
  readonly title?: string;
1396
1872
  }
1397
1873
 
1874
+ /**
1875
+ * `app.time` / `api.time`: host facts about time. Added to `kay.app` in SDK 0.12.1 and to
1876
+ * `kay.agent` with the calendar zone-of-record work: a plugin that calls it declares
1877
+ * `compatibility.sdk` `^0.12.1`, so an older Bonsai refuses a directory or repository plugin at
1878
+ * load instead of the call failing.
1879
+ */
1880
+ declare interface KayAppTime {
1881
+ /**
1882
+ * Reads the daemon's clock and the user's time zone now.
1883
+ *
1884
+ * Every call asks the host again and returns a new object; nothing is cached. Call it where you
1885
+ * need the value (inside a tool, a handler or a workflow step), not inside `activate()`: a value
1886
+ * read there is as old as the activation, and the host can run a bundled plugin's `activate()`
1887
+ * against a recording api that has no `time`, so a read there throws. The exception is a
1888
+ * directory plugin that declares a workflow with a cron `timezone`: `workflows.define` is legal
1889
+ * only during `activate()`, so it reads the zone there, and the schedule then keeps that zone.
1890
+ * Keep the result for as long as you use it, and not across a long wait (a sleep, a timer, a
1891
+ * queued run): the zone can change while you wait. On a daemon that runs on the user's machine,
1892
+ * a change of the process's `TZ` shows in the next call. A `TZ` that names a zone wins over the
1893
+ * operating system's zone, so a change of the operating-system zone does not show while the
1894
+ * process has one. When `TZ` is unset or does not name a zone, a change of the operating-system
1895
+ * zone is meant to show, but none has been seen on a real machine yet.
1896
+ *
1897
+ * A zone the host cannot determine is an answer (`zoneSource: "utc-fallback"`), not an error.
1898
+ *
1899
+ * Use this to find the zone, not `Intl.DateTimeFormat().resolvedOptions().timeZone`, which can
1900
+ * keep a zone the runtime read earlier, or `process.env.TZ`, which is often unset or not a zone.
1901
+ * Neither says that the zone is unknown.
1902
+ *
1903
+ * It does not use `this`, so it is safe to destructure.
1904
+ */
1905
+ readonly snapshot: () => KayAppTimeSnapshot;
1906
+ }
1907
+
1908
+ /**
1909
+ * The plugin-facing time contract: the daemon's clock and the time zone the user is in,
1910
+ * read together in one call.
1911
+ *
1912
+ * Ungated and always present, like `app.paths`. It confers no authority: a plugin runs in the
1913
+ * daemon's process and can already read the clock. What the door adds is the daemon's answer
1914
+ * for the USER's zone, and a label for the case where that answer is unknown.
1915
+ *
1916
+ * This is a leaf module. It lives beside both target SDKs (rather than inside `kay-app`) so the
1917
+ * `kay.agent` SDK can expose the same door without importing the `kay.app` surface, which pulls
1918
+ * that surface into every agent-facing bundle.
1919
+ */
1920
+ /** One reading of the daemon's clock and the user's time zone. Each call returns a new object. */
1921
+ declare interface KayAppTimeSnapshot {
1922
+ /** The daemon's clock when the snapshot was read: milliseconds since the Unix epoch. */
1923
+ readonly nowMs: number;
1924
+ /**
1925
+ * The time zone the user is in, as an IANA id in the spelling ICU resolves (`America/New_York`).
1926
+ * One zone can have two ids, and ICU picks one: `Asia/Kolkata` comes back as `Asia/Calcutta`. So
1927
+ * never compare zone ids with `===`. A first-party plugin compares with `sameZone` from
1928
+ * `@kay/time`. A plugin that imports only this SDK and node builtins resolves each id with
1929
+ * `new Intl.DateTimeFormat("en-US", { timeZone: id }).resolvedOptions().timeZone` and compares the
1930
+ * results. Pass `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a
1931
+ * time for the user.
1932
+ *
1933
+ * When `zoneSource` is `utc-fallback` the zone is unknown, and this value is `UTC` only because a
1934
+ * value is required.
1935
+ */
1936
+ readonly zone: string;
1937
+ /**
1938
+ * How the daemon found `zone`.
1939
+ * - `host`: the daemon runs on the user's machine, and `zone` is the zone the daemon process
1940
+ * runs in, read for this call: the process's `TZ` when that names a zone, otherwise the
1941
+ * operating system's zone.
1942
+ * - `utc-fallback`: the daemon does not know the user's zone. It runs on another machine (a remote
1943
+ * daemon), or the machine's zone could not be read or is not an IANA id. `zone` is `UTC`, which
1944
+ * here is a placeholder and not a fact about the user: do not show it to the user as their zone.
1945
+ */
1946
+ readonly zoneSource: "host" | "utc-fallback";
1947
+ }
1948
+
1398
1949
  declare const KayPluginManifestV1: z.ZodObject<{
1399
1950
  protocol: z.ZodLiteral<"kay.plugin.v1">;
1400
1951
  id: z.ZodString;
@@ -1490,6 +2041,14 @@ declare const KayPluginManifestV1: z.ZodObject<{
1490
2041
  displayName: z.ZodOptional<z.ZodString>;
1491
2042
  schemes: z.ZodOptional<z.ZodArray<z.ZodString>>;
1492
2043
  }, z.core.$strict>>>;
2044
+ interactionDrivers: z.ZodOptional<z.ZodArray<z.ZodObject<{
2045
+ localId: z.ZodString;
2046
+ displayName: z.ZodOptional<z.ZodString>;
2047
+ kind: z.ZodEnum<{
2048
+ browser: "browser";
2049
+ "computer-use": "computer-use";
2050
+ }>;
2051
+ }, z.core.$strict>>>;
1493
2052
  entityResolvers: z.ZodOptional<z.ZodArray<z.ZodObject<{
1494
2053
  localId: z.ZodString;
1495
2054
  displayName: z.ZodOptional<z.ZodString>;
@@ -1712,6 +2271,9 @@ declare const KayPluginManifestV1: z.ZodObject<{
1712
2271
  kind: z.ZodLiteral<"working-document">;
1713
2272
  }, z.core.$strict>, z.ZodObject<{
1714
2273
  kind: z.ZodLiteral<"browser-pane">;
2274
+ }, z.core.$strict>, z.ZodObject<{
2275
+ kind: z.ZodLiteral<"page">;
2276
+ pageId: z.ZodString;
1715
2277
  }, z.core.$strict>], "kind">;
1716
2278
  variants: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
1717
2279
  resourceKind: z.ZodString;
@@ -1754,12 +2316,12 @@ declare const KayPluginManifestV1: z.ZodObject<{
1754
2316
  capabilities: z.ZodOptional<z.ZodObject<{
1755
2317
  endpoints: z.ZodOptional<z.ZodArray<z.ZodString>>;
1756
2318
  host: z.ZodOptional<z.ZodArray<z.ZodEnum<{
2319
+ "skills.read": "skills.read";
1757
2320
  "automations.run": "automations.run";
1758
2321
  "navigation.open-session": "navigation.open-session";
1759
2322
  "cost.read": "cost.read";
1760
2323
  "billing.read": "billing.read";
1761
2324
  "context.read": "context.read";
1762
- "skills.read": "skills.read";
1763
2325
  "memory.read": "memory.read";
1764
2326
  "usage.read": "usage.read";
1765
2327
  "self-improvement.read": "self-improvement.read";
@@ -2187,7 +2749,7 @@ declare type KayPluginManifestV1 = z.infer<typeof KayPluginManifestV1>;
2187
2749
 
2188
2750
  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";
2189
2751
 
2190
- 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";
2752
+ 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";
2191
2753
 
2192
2754
  declare interface LineRange {
2193
2755
  readonly start: number;
@@ -2245,29 +2807,26 @@ declare interface MistralConversationsCompat {
2245
2807
  supportsMidConvoSystemMessages?: boolean;
2246
2808
  }
2247
2809
 
2248
- declare interface Model<TApi extends Api> {
2249
- id: string;
2250
- name: string;
2251
- api: TApi;
2252
- provider: ProviderId;
2253
- baseUrl: string;
2810
+ /** Chat model: usable with `stream()` and friends. */
2811
+ declare interface Model<TApi extends Api> extends BaseModel<TApi> {
2812
+ /**
2813
+ * Optional: chat is the default model type, so models without `type` are chat
2814
+ * models. Narrow mixed model lists with `isModelType()` instead of comparing
2815
+ * `type` directly.
2816
+ */
2817
+ type?: "chat";
2254
2818
  reasoning: boolean;
2255
2819
  /**
2256
2820
  * Maps pi thinking levels to provider/model-specific values.
2257
2821
  * Missing keys use provider defaults. null marks a level as unsupported.
2258
2822
  */
2259
2823
  thinkingLevelMap?: ThinkingLevelMap;
2260
- input: ("text" | "image")[];
2261
- /** Provider input limits and cache-safe preprocessing metadata. */
2262
- inputLimits?: ModelInputLimits;
2263
- cost: ModelCost;
2264
2824
  /** Prompt cache lifetimes per retention tier. Unset when the provider's cache behavior is unknown. */
2265
2825
  promptCache?: ModelPromptCache;
2266
2826
  contextWindow: number;
2267
2827
  maxTokens: number;
2268
2828
  /** Default sampling parameters for this model. See {@link StreamOptions.samplingParams}; per-request keys override these. */
2269
2829
  samplingParams?: Record<string, unknown>;
2270
- headers?: Record<string, string>;
2271
2830
  /** Compatibility overrides for OpenAI-compatible APIs. If not set, auto-detected from baseUrl. */
2272
2831
  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;
2273
2832
  }
@@ -2800,6 +3359,10 @@ declare const PluginCapabilityRefusalV1: z.ZodObject<{
2800
3359
  target: z.ZodLiteral<"kay.app">;
2801
3360
  slug: z.ZodLiteral<"signals.read">;
2802
3361
  envelope: z.ZodObject<{}, z.core.$strict>;
3362
+ }, z.core.$strict>, z.ZodObject<{
3363
+ target: z.ZodLiteral<"kay.app">;
3364
+ slug: z.ZodLiteral<"skills.read">;
3365
+ envelope: z.ZodObject<{}, z.core.$strict>;
2803
3366
  }, z.core.$strict>, z.ZodObject<{
2804
3367
  target: z.ZodLiteral<"kay.app">;
2805
3368
  slug: z.ZodLiteral<"workspace.command">;
@@ -2904,6 +3467,15 @@ declare const PluginCapabilityRefusalV1: z.ZodObject<{
2904
3467
  target: z.ZodLiteral<"kay.agent">;
2905
3468
  slug: z.ZodLiteral<"tool-interception.register">;
2906
3469
  envelope: z.ZodObject<{}, z.core.$strict>;
3470
+ }, z.core.$strict>, z.ZodObject<{
3471
+ target: z.ZodLiteral<"kay.agent">;
3472
+ slug: z.ZodLiteral<"interaction.surface">;
3473
+ envelope: z.ZodObject<{
3474
+ surface: z.ZodEnum<{
3475
+ "browser-pane": "browser-pane";
3476
+ desktop: "desktop";
3477
+ }>;
3478
+ }, z.core.$strict>;
2907
3479
  }, z.core.$strict>, z.ZodObject<{
2908
3480
  target: z.ZodLiteral<"plugin">;
2909
3481
  slug: z.ZodLiteral<"config.declare-section">;
@@ -2994,8 +3566,15 @@ export declare interface PluginDelegatedScheme {
2994
3566
  /** Run the connect flow and mint the material to store. Throw to fail the connect. */
2995
3567
  readonly connect: (ctx: PluginDelegatedConnectContext) => Promise<PluginDelegatedConnectResult>;
2996
3568
  /**
2997
- * Mint fresh material from the current (expiring) material. Absent means non-refreshable:
2998
- * expired material resolves as-is (like an OAuth scheme without a refresh token).
3569
+ * Mint fresh material from the current (expiring) material, including the `data` the last
3570
+ * connect or refresh returned. Kay calls this only inside its credential authority, which holds
3571
+ * the refresh lease and saves the result; this hook performs the exchange and nothing else.
3572
+ * Returned `data` replaces the stored `data`; omitted `data` keeps it. Returned `expiresAt`
3573
+ * replaces the stored expiry; omitted `expiresAt` means the new material does not expire.
3574
+ * Throw {@link DelegatedRefreshRejectedError} when the provider refused the grant for good (the
3575
+ * user must reconnect); any other throw is retried with backoff and keeps the account connected.
3576
+ * Absent means non-refreshable: expired material resolves as-is (like an OAuth scheme without a
3577
+ * refresh token).
2999
3578
  */
3000
3579
  readonly refresh?: (material: PluginDelegatedSecretMaterial) => Promise<PluginDelegatedSecretMaterial>;
3001
3580
  /**
@@ -3174,8 +3753,6 @@ declare interface ProxiedToolCall {
3174
3753
  readonly input: Record<string, unknown>;
3175
3754
  }
3176
3755
 
3177
- export { Questions }
3178
-
3179
3756
  export declare interface RawResource {
3180
3757
  readonly uri: string;
3181
3758
  readonly content: string | Uint8Array;
@@ -3564,10 +4141,6 @@ declare interface SessionContext {
3564
4141
  * how most third-party APIs use `""` to mean "no value" rather than "the empty string". */
3565
4142
  export declare function str(record: Record<string, unknown> | undefined, key: string): string | undefined;
3566
4143
 
3567
- export { SystemOneRequest }
3568
-
3569
- export { SystemOneResult }
3570
-
3571
4144
  declare interface TextContent {
3572
4145
  type: "text";
3573
4146
  text: string;
@@ -3684,6 +4257,19 @@ declare interface ToolCallModel {
3684
4257
  */
3685
4258
  declare type ToolCallOrigin = "model" | "host";
3686
4259
 
4260
+ /** A call to judge with {@link ToolContext.checkToolCallPermission}. */
4261
+ declare interface ToolCallPermissionCheck {
4262
+ readonly toolName: string;
4263
+ readonly input: Record<string, unknown>;
4264
+ }
4265
+
4266
+ declare type ToolCallPermissionVerdict = {
4267
+ readonly allowed: true;
4268
+ } | {
4269
+ readonly allowed: false;
4270
+ readonly reason: string;
4271
+ };
4272
+
3687
4273
  /**
3688
4274
  * What a tool call ADDRESSES, resolved by the session before execution from facts it already
3689
4275
  * holds for auth scoping: a URI verb's matched module (and the extension that registered it), or
@@ -3726,6 +4312,13 @@ export declare interface ToolContext {
3726
4312
  * behind itself. Present only with a live session. One request may be pending at a time.
3727
4313
  */
3728
4314
  readonly requestMidTurnCompaction?: (customInstructions?: string, trigger?: "command" | "suggestion") => MidTurnCompactionRequest;
4315
+ /**
4316
+ * Put a call this tool is about to cause through the session's permission gate, as if the agent
4317
+ * had made it directly: classification, rules, mode, the auto approver, and the approval card.
4318
+ * The call is only judged, never executed. For a tool whose effect is only knowable at run time
4319
+ * (a click in a web page that turns out to send an email). Present only with a live session.
4320
+ */
4321
+ readonly checkToolCallPermission?: (call: ToolCallPermissionCheck) => Promise<ToolCallPermissionVerdict>;
3729
4322
  /**
3730
4323
  * Re-root the session into `newCwd` mid-run, recomposing the cwd-scoped substrate (builtin tools,
3731
4324
  * the capability registry, the system-prompt project line) in place so subsequent tool calls operate
@@ -4012,7 +4605,11 @@ declare interface ToolPermissionHint {
4012
4605
  /** Controls whether a tool is expected to complete inline or via background adoption. */
4013
4606
  export declare type ToolRunPolicy = "inline" | "background";
4014
4607
 
4015
- export { TypeSafeClient }
4608
+ /** A surface that answers every call `unavailable` with `message`: the uncomposed default. */
4609
+ export declare function unavailableInteractionSurface(message: string): InteractionSurface;
4610
+
4611
+ /** Both surfaces unavailable: a host that composed no Interaction surfaces, a probe, a double. */
4612
+ export declare function unavailableInteractionSurfaces(message: string): KayAgentInteractionSurfaces;
4016
4613
 
4017
4614
  /**
4018
4615
  * One sentence naming the two dialects, for refusal messages. Callers prefix
@@ -4354,6 +4951,21 @@ export declare interface UriModule {
4354
4951
  */
4355
4952
  readonly title?: string;
4356
4953
  readonly fallback?: boolean;
4954
+ /**
4955
+ * Whether this module parses the read tool's trailing line selector out of its own addresses.
4956
+ * Absent or false: the host owns the explicit forms (`:50-200`, `:50-`, `:50+10`, `:raw`). The
4957
+ * read tool strips one before dispatch, hands `read` the bare address, and applies the window
4958
+ * to what comes back, so a module never has to know the grammar for the read tool's own
4959
+ * `Continue with '<address>:N-M'` banner to work on its addresses (#10754). A bare trailing
4960
+ * `:<digits>` is never taken from such a module: it is too common inside real ids (a Figma
4961
+ * node `1:2`), so it reaches the module as written.
4962
+ *
4963
+ * Declare `true` only when the module must see the raw address: its grammar can end in an
4964
+ * explicit-range shape, it wants the bare `:50` form too, or it windows the content itself
4965
+ * (streaming a large file, skipping a cap it applies to an unwindowed read). Such a module
4966
+ * calls `parseLineSelector` itself and reports what it did through `RawResource.selector`.
4967
+ */
4968
+ readonly ownsLineSelectors?: boolean;
4357
4969
  readonly claims?: readonly UriClaim[];
4358
4970
  /** Migration-only prompt summary until structured help/catalog coverage replaces prose. */
4359
4971
  readonly description?: string;
@@ -4363,14 +4975,17 @@ export declare interface UriModule {
4363
4975
  /** Pure route/payload validation applied before a consequential permission ask. */
4364
4976
  readonly preflight?: UriOperationPreflightPolicy;
4365
4977
  /**
4366
- * Structured facts naming the WHOLE consequence of this call, or `undefined` when
4367
- * the route cannot honestly be described on a one-line approval surface. The module
4978
+ * Structured facts for approval surfaces, or `undefined` when unavailable.
4979
+ * A one-line description must name the whole consequence; `preview` instead
4980
+ * supplies expanded, literal-text detail and suppresses one-line approval. The module
4368
4981
  * owns the static action phrase, target resolution, payload decoding and declaration
4369
4982
  * of covered payload fields and query parameters. Unknown fields cost the summary.
4370
4983
  * The host owns framing, the whole-quote fit (no elision) and display-safety admission.
4371
4984
  *
4372
4985
  * Unlike preflight, this hook is async and may do I/O. Resolve names through `ctx`,
4373
- * the same dispatch context used by execution, never an ambient or cached account.
4986
+ * the same dispatch context used by execution, never an ambient or cached account. A name
4987
+ * the module resolved under that account may be cached for a bounded time, keyed by that
4988
+ * account's identity and never answered to another account or after a failed lookup.
4374
4989
  * The host calls it once before raising the ask, enforces the short `ctx.signal`
4375
4990
  * deadline and discards late answers. A throw yields no summary and a module-attributed
4376
4991
  * diagnostic; declining costs a click into the app, never an under-described approval.
@@ -4380,6 +4995,26 @@ export declare interface UriModule {
4380
4995
  readonly uri: string;
4381
4996
  readonly payload: unknown;
4382
4997
  }, ctx: UriResolveContext): Promise<UriOperationDescription | undefined>;
4998
+ /**
4999
+ * A short, render-only name for the resource a settled call on `request.uri` touched, which the
5000
+ * host stamps on the tool result's `details` so a transcript row can name it where it would
5001
+ * otherwise print the address (`#lane-analytics` and `thread`, not a channel id). Answer
5002
+ * `undefined` for any address you cannot honestly name.
5003
+ *
5004
+ * Called once per successful URI verb call, AFTER the verb handler has returned, with the same
5005
+ * dispatch context. Resolve names through `ctx` and nothing else, and prefer a cache your own
5006
+ * verb handlers warm, keyed by the executing account: a name one account saw is never answered
5007
+ * to another, and a failed, blank or aborted lookup is never cached. The host bounds the wait
5008
+ * (a finished result is held at most a quarter of a second), gives `ctx.signal` a hard deadline,
5009
+ * and drops a late, thrown or refused answer without failing the call; a throw is reported as a
5010
+ * module-attributed diagnostic. The label is a label, never an identity: the address remains the
5011
+ * click target, hover text and accessible name. It is UI-only, so it never enters the tool
5012
+ * result's content and no telemetry reads it.
5013
+ *
5014
+ * Unlike `describeOperation` this is not an approval surface: it carries no consequence, no
5015
+ * quote and no coverage claim, and nothing may gate a permission on it.
5016
+ */
5017
+ labelResource?(request: UriResourceLabelRequest, ctx: UriResolveContext): Promise<UriResourceLabel | undefined>;
4383
5018
  /**
4384
5019
  * Per-resource observability: does a `format: "observation"` read of THIS
4385
5020
  * uri render source-native material ({@link UriResolveContext.format})?
@@ -4517,6 +5152,18 @@ export declare interface UriOperationDescription {
4517
5152
  readonly target: string;
4518
5153
  /** Model-authored content; the host flattens, budgets, elides and bounds it. */
4519
5154
  readonly quote?: string;
5155
+ /** Full, render-only detail. Hosts must not turn a rich preview into one-line approval. */
5156
+ readonly preview?: {
5157
+ readonly title: string;
5158
+ readonly description?: string;
5159
+ readonly fields?: readonly {
5160
+ readonly label: string;
5161
+ readonly value: string;
5162
+ readonly oldValue?: string;
5163
+ }[];
5164
+ };
5165
+ /** True only when every displayed fact comes from the input, independent of the executing account. */
5166
+ readonly accountIndependent?: true;
4520
5167
  /** What this description accounts for; the host refuses undeclared input. */
4521
5168
  readonly accounts: {
4522
5169
  /** The payload actually read by the module, after its own decoding. */
@@ -4819,6 +5466,24 @@ export declare interface UriResourceDescription {
4819
5466
  readonly sourceUrl?: string;
4820
5467
  }
4821
5468
 
5469
+ /**
5470
+ * What a settled call touched, as a person would name it.
5471
+ *
5472
+ * `name` is the resource itself (`#lane-analytics`). `section` is the part of it the address
5473
+ * reaches into (`thread`), and is absent when the address is the resource.
5474
+ */
5475
+ export declare interface UriResourceLabel {
5476
+ readonly name: string;
5477
+ readonly section?: string;
5478
+ }
5479
+
5480
+ /** The call a module is asked to label. */
5481
+ export declare interface UriResourceLabelRequest {
5482
+ readonly operation: UriOperation;
5483
+ /** The dispatch address: selector-stripped, the exact form the module's verb handler received. */
5484
+ readonly uri: string;
5485
+ }
5486
+
4822
5487
  declare interface UriSchemeClaim {
4823
5488
  readonly kind: "scheme";
4824
5489
  readonly scheme: string;
@@ -5093,9 +5758,7 @@ declare interface UrlPatternClaim {
5093
5758
  readonly examples?: readonly string[];
5094
5759
  }
5095
5760
 
5096
- export { Usage }
5097
-
5098
- declare interface Usage_2 {
5761
+ declare interface Usage {
5099
5762
  input: number;
5100
5763
  output: number;
5101
5764
  cacheRead: number;
@@ -5275,8 +5938,8 @@ export declare type WhiteboardValue = z.infer<typeof WhiteboardValue>;
5275
5938
  /**
5276
5939
  * Run `use` against a live Jev client, falling back to `fallback` whenever Jev cannot serve the
5277
5940
  * call. The wrapper exists so a feature can ASK for a typed decision without ever depending on
5278
- * one: `fallback` is required, and it runs whenever no host-managed key is saved,
5279
- * the user has not granted `jev.use`, the branch exceeds its budget, `use` throws, or
5941
+ * one: `fallback` is required, and it runs whenever no provider in the user's Jev provider
5942
+ * order holds a usable credential, the user has not granted `jev.use`, the branch exceeds its budget, `use` throws, or
5280
5943
  * `use` declines by returning `undefined`. With valid options, this rejects on an explicit
5281
5944
  * `signal` abort, reaching `deadlineAt`, or `fallback` itself throwing.
5282
5945
  *
@@ -5284,10 +5947,9 @@ export declare type WhiteboardValue = z.infer<typeof WhiteboardValue>;
5284
5947
  * {@link createFallbackOnlyWithJev}, so a caller never branches on availability — branching is
5285
5948
  * exactly how a fallback gets skipped.
5286
5949
  *
5287
- * `jev` is the vendor's own `TypeSafeClient`, configured with the host's default model and base
5288
- * URL. Native `request.model` overrides remain supported. It
5289
- * is valid only for the duration of the callback: a reference retained past `use`'s scope is
5290
- * refused at the transport, and an in-flight request is aborted when the call stops waiting.
5950
+ * `jev` is a {@link JevClient} on the host's Jev model. It is valid only for the duration of
5951
+ * the callback: a reference retained past `use`'s scope is refused at the transport, and an
5952
+ * in-flight request is aborted when the call stops waiting.
5291
5953
  * The callback itself is ABANDONED, not interrupted — a host cannot stop arbitrary JavaScript
5292
5954
  * that is already running, so `use` must not perform side effects it would mind completing
5293
5955
  * unobserved. The same applies to a running fallback: abort/deadline stops waiting for it but
@@ -5296,7 +5958,7 @@ export declare type WhiteboardValue = z.infer<typeof WhiteboardValue>;
5296
5958
  export declare type WithJev = <T>(
5297
5959
  /** Return `undefined` to decline (the fallback runs). A feature whose real result can itself be
5298
5960
  * `undefined` should return `null` or its own wrapper type instead. */
5299
- use: (jev: TypeSafeClient) => T | undefined | PromiseLike<T | undefined>,
5961
+ use: (jev: JevClient) => T | undefined | PromiseLike<T | undefined>,
5300
5962
  /** Required. The behaviour the feature has without Jev. */
5301
5963
  fallback: () => T | PromiseLike<T>, options?: WithJevOptions) => Promise<T>;
5302
5964