@yaklabs-ai/plugin-sdk 0.11.0 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/kay-app.d.ts CHANGED
@@ -1,12 +1,4 @@
1
- import type { ChoiceResponse } from '@typesafe-ai/sdk';
2
- import type { NoulResponse } from '@typesafe-ai/sdk';
3
- import { Questions } from '@typesafe-ai/sdk';
4
- import type { ScoreResponse } from '@typesafe-ai/sdk';
5
1
  import type { StatementSync } from 'node:sqlite';
6
- import { SystemOneRequest } from '@typesafe-ai/sdk';
7
- import { SystemOneResult } from '@typesafe-ai/sdk';
8
- import { TypeSafeClient } from '@typesafe-ai/sdk';
9
- import { Usage } from '@typesafe-ai/sdk';
10
2
  import { z } from 'zod';
11
3
 
12
4
  /**
@@ -31,6 +23,9 @@ declare interface AccountIdentity {
31
23
  readonly avatarUrl?: string;
32
24
  /** Issuer-asserted beta-tester flag; only Kay's product-account service sets it. */
33
25
  readonly betaTester?: boolean;
26
+ readonly activeOrganizationId?: string;
27
+ readonly organizationSelectionState?: "selected" | "unresolved";
28
+ readonly organizationScopeEpoch?: number;
34
29
  /**
35
30
  * Provider-native session id claim (WorkOS's `sid`), needed to call the provider's own
36
31
  * session-revocation endpoint at sign-out (`POST /user_management/sessions/revoke`, not yet
@@ -53,8 +48,18 @@ export declare interface AgentToolResult<T = JsonValue | undefined> {
53
48
  content: (TextContent | ImageContent)[];
54
49
  /** Arbitrary structured details for logs or UI rendering. */
55
50
  details: T;
51
+ /**
52
+ * Machine-readable result matching the tool's `outputSchema`, for programmatic callers. Not sent
53
+ * to the model; `content` remains the model-facing result.
54
+ */
55
+ structuredContent?: JsonValue;
56
56
  /** Usage from the final tool execution itself, if available. Not used for main LLM context accounting. */
57
- usage?: Usage_2;
57
+ usage?: Usage;
58
+ /**
59
+ * Report a failure without throwing. The model sees `content` as an error result, like a thrown
60
+ * error, but `details` and `structuredContent` are kept for the UI and programmatic callers.
61
+ */
62
+ isError?: boolean;
58
63
  /**
59
64
  * Hint that the agent should stop after the current tool batch.
60
65
  * Early termination only happens when every finalized tool result in the batch sets this to true.
@@ -153,8 +158,10 @@ declare interface AssistantMessage {
153
158
  responseId?: string;
154
159
  /** Exact provider-native effort level used for this response. Absent for legacy or unmanaged responses. */
155
160
  providerThinkingLevel?: string;
161
+ /** Pi thinking level the agent loop requested for this response. Absent outside the agent loop and for legacy responses. */
162
+ thinkingLevel?: ModelThinkingLevel;
156
163
  diagnostics?: AssistantMessageDiagnostic[];
157
- usage: Usage_2;
164
+ usage: Usage;
158
165
  stopReason: StopReason;
159
166
  deferred?: DeferredHandle;
160
167
  errorMessage?: string;
@@ -250,6 +257,20 @@ declare interface BackgroundTaskSnapshot {
250
257
 
251
258
  declare type BackgroundTaskStatus = "queued" | "running" | "completed" | "failed" | "cancelled";
252
259
 
260
+ /** Fields shared by every catalog entry, regardless of what you can do with it. */
261
+ declare interface BaseModel<TApi extends string> {
262
+ id: string;
263
+ name: string;
264
+ api: TApi;
265
+ provider: ProviderId;
266
+ baseUrl: string;
267
+ input: ("text" | "image")[];
268
+ /** Provider input limits and cache-safe preprocessing metadata. */
269
+ inputLimits?: ModelInputLimits;
270
+ cost: ModelCost;
271
+ headers?: Record<string, string>;
272
+ }
273
+
253
274
  /** Compatibility settings for Amazon Bedrock models. */
254
275
  declare interface BedrockCompat {
255
276
  /** Whether the model supports Bedrock strict tool schemas. Default: false. */
@@ -261,7 +282,7 @@ declare interface BranchSummaryEntry extends EntryBase {
261
282
  fromId: string | null;
262
283
  summary: string;
263
284
  details?: JsonValue_2;
264
- usage?: Usage_2;
285
+ usage?: Usage;
265
286
  fromHook: boolean;
266
287
  }
267
288
 
@@ -272,15 +293,13 @@ declare type ChatTemplateKwargValue = string | number | boolean | null | {
272
293
  omitWhenOff?: boolean;
273
294
  };
274
295
 
275
- export { ChoiceResponse }
276
-
277
296
  declare interface CompactionEntry extends EntryBase {
278
297
  type: "compaction";
279
298
  summary: string;
280
299
  retainedTail: AgentMessage[];
281
300
  tokensBefore: number;
282
301
  details?: JsonValue_2;
283
- usage?: Usage_2;
302
+ usage?: Usage;
284
303
  fromHook: boolean;
285
304
  }
286
305
 
@@ -406,6 +425,12 @@ export declare function createFallbackOnlySignals(): KayAppSignals;
406
425
  */
407
426
  export declare function createFallbackOnlyWithJev(): WithJev;
408
427
 
428
+ /**
429
+ * The `app.skills` a host with no skill store or catalog binds: every read answers
430
+ * `not-available`, so a plugin's code path never depends on host composition.
431
+ */
432
+ export declare function createUnavailableSkills(message: string): KayAppSkills;
433
+
409
434
  declare interface CustomEntry extends EntryBase {
410
435
  type: "custom";
411
436
  customType: string;
@@ -608,6 +633,150 @@ declare type IsJsonProperty<T> = IsAny<T> extends true ? false : unknown extends
608
633
  */
609
634
  export declare function isRetryable(result: KayAppAccountAssertionFailure): boolean;
610
635
 
636
+ export declare type JevAnswer = JevBoolAnswer | JevChoiceAnswer | JevScoreAnswer;
637
+
638
+ /** The answer shape one question gets back. */
639
+ export declare type JevAnswerFor<Q> = Q extends JevBoolQuestion ? JevBoolAnswer : Q extends JevChoiceQuestion<infer L> ? JevChoiceAnswer<L> : Q extends JevScoreQuestion ? JevScoreAnswer : never;
640
+
641
+ export declare interface JevBoolAnswer {
642
+ readonly type: "bool";
643
+ /** P(yes), from 0 to 1. */
644
+ readonly probability: number;
645
+ }
646
+
647
+ /** A yes/no question. `criteria` says what yes and what no mean; omit it to leave both open. */
648
+ export declare interface JevBoolQuestion {
649
+ readonly type: "bool";
650
+ readonly instructions: string;
651
+ readonly criteria?: {
652
+ readonly true: string;
653
+ readonly false: string;
654
+ };
655
+ }
656
+
657
+ /**
658
+ * The one error `classify` rejects with. It carries a classification, never the provider's own
659
+ * message or body: those can echo the request state, and this error reaches logs.
660
+ */
661
+ export declare class JevCallError extends Error {
662
+ readonly transport: JevTransport;
663
+ readonly kind: JevCallErrorKind;
664
+ /** The final attempt's HTTP status, when a response arrived. */
665
+ readonly status: number | undefined;
666
+ constructor(init: {
667
+ readonly transport: JevTransport;
668
+ readonly kind: JevCallErrorKind;
669
+ readonly status?: number | undefined;
670
+ });
671
+ }
672
+
673
+ /**
674
+ * Why a Jev call failed, as a closed set:
675
+ *
676
+ * - `http`: the route answered with an error status (`status` says which).
677
+ * - `too-large`: the route refused the request's size (413, or a 400 naming the token limit).
678
+ * - `network`: no response arrived.
679
+ * - `aborted`: the call was cancelled.
680
+ * - `invalid-answer`: the route answered, but not with an answer for every asked question.
681
+ */
682
+ export declare type JevCallErrorKind = "http" | "too-large" | "network" | "aborted" | "invalid-answer";
683
+
684
+ export declare interface JevChoiceAnswer<L extends string = string> {
685
+ readonly type: "choice";
686
+ readonly choice: L;
687
+ readonly confidence: number;
688
+ /** P(label) for every offered label. */
689
+ readonly probabilities: Readonly<Record<L, number>>;
690
+ }
691
+
692
+ /** A choice among labels. Each label maps to what it means; an empty string leaves it open. */
693
+ export declare interface JevChoiceQuestion<L extends string = string> {
694
+ readonly type: "choice";
695
+ readonly instructions: string;
696
+ readonly criteria: Readonly<Record<L, string>>;
697
+ }
698
+
699
+ /** One answered request: every asked question has an answer of its own kind. */
700
+ export declare interface JevClassification<Q extends JevQuestions = JevQuestions> {
701
+ /** The Jev model the host asked. */
702
+ readonly model: string;
703
+ readonly answers: {
704
+ readonly [K in keyof Q]: JevAnswerFor<Q[K]>;
705
+ };
706
+ /** Token counts, when the route reported them. */
707
+ readonly usage?: {
708
+ readonly inputTokens: number;
709
+ readonly outputTokens: number;
710
+ };
711
+ }
712
+
713
+ export declare interface JevClassifyRequest<Q extends JevQuestions = JevQuestions> {
714
+ readonly state: JevState;
715
+ readonly questions: Q;
716
+ }
717
+
718
+ /**
719
+ * The Jev client a `use` body receives. `classify` either resolves with an answer for every
720
+ * asked question, each of its question's kind, or rejects with a {@link JevCallError}; it never
721
+ * resolves with a partial or substituted answer.
722
+ */
723
+ export declare interface JevClient {
724
+ classify<const Q extends JevQuestions>(request: JevClassifyRequest<Q>, options?: {
725
+ readonly signal?: AbortSignal;
726
+ }): Promise<JevClassification<Q>>;
727
+ }
728
+
729
+ export declare type JevQuestion = JevBoolQuestion | JevChoiceQuestion | JevScoreQuestion;
730
+
731
+ /** A rubric: questions keyed by the name each answer comes back under. */
732
+ export declare type JevQuestions = Readonly<Record<string, JevQuestion>>;
733
+
734
+ export declare interface JevScoreAnswer {
735
+ readonly type: "score";
736
+ /** The expected score, from 0 to the number of rungs minus one. */
737
+ readonly score: number;
738
+ readonly confidence: number;
739
+ }
740
+
741
+ /** A score over ordered rungs: the first criterion scores 0, the next 1, and so on. */
742
+ export declare interface JevScoreQuestion {
743
+ readonly type: "score";
744
+ readonly instructions: string;
745
+ readonly criteria: readonly string[];
746
+ }
747
+
748
+ /**
749
+ * ---
750
+ * responsibility: The plugin-facing CONTRACT for Jev typed-decision inference — the shape of
751
+ * `api.withJev` on both plugin SDK targets, the {@link JevClient} a `use` body receives, the
752
+ * question and answer vocabulary it speaks, and the fallback-only implementation a host
753
+ * without a Jev lane binds.
754
+ * owns:
755
+ * - {@link WithJev}, {@link WithJevOptions}, {@link createFallbackOnlyWithJev}.
756
+ * - {@link JevClient}, the {@link JevQuestion} and {@link JevAnswer} vocabulary, and
757
+ * {@link JevCallError}.
758
+ * does_not_own:
759
+ * - The wire. The host serves `classify` over whichever route the user's Jev provider order
760
+ * picks; a plugin never sees a vendor client, a vendor type, or a route.
761
+ * - Credential resolution, the `jev.use` decision, the Jev-branch budget, or usage accounting.
762
+ * Those are host-side (`@kay/agent-runtime`'s `kay/jev/`).
763
+ * ---
764
+ *
765
+ * The vocabulary is Kay's own (SDK 0.12.0). Before it, `use` received TypeSafe's `TypeSafeClient`
766
+ * and plugins coded against a vendor's types. It follows pi's classifier contract, which the host
767
+ * runs Jev through: a yes/no question is `bool` and answers a `probability`, every instruction and
768
+ * criterion is text, and the state is a JSON object.
769
+ */
770
+ /**
771
+ * The state a rubric reads: a JSON object, never text or an array. Every value must survive
772
+ * `JSON.stringify` unchanged (no functions or class instances), because it is sent as JSON.
773
+ * Typed as `object` so a state declared as an interface fits without an index signature.
774
+ */
775
+ export declare type JevState = object;
776
+
777
+ /** The route a Jev call took: the user's own TypeSafe key, or Bonsai's hosted gateway. */
778
+ export declare type JevTransport = "direct" | "hosted";
779
+
611
780
  declare type JsonObject = {
612
781
  [key: string]: JsonValue;
613
782
  };
@@ -792,7 +961,10 @@ export declare interface KayAppAccount {
792
961
  * verdict — not only on identity moves. A listener whose reaction is expensive
793
962
  * (tearing down state, re-registering sources) must gate itself: re-read with
794
963
  * `profile`/`assertResult`, compare against the last-seen identity, and act only on a
795
- * real move (kay#8553 is the looping-reconnect bug the looser reading licensed).
964
+ * real move (kay#8553 is the looping-reconnect bug the looser reading licensed). A gate
965
+ * that re-registers account-scoped sources must also act when a registration reports
966
+ * {@link KayAppDataSourceRegistration.isRetired}: the host's identity change is not always
967
+ * one `profile` shows, and a gate reading only the identity leaves the source retired.
796
968
  */
797
969
  subscribe(listener: () => void): () => void;
798
970
  }
@@ -1399,15 +1571,16 @@ export declare type KayAppAutomationMatch = {
1399
1571
  * {@link KayAppAutomationRunDetail.artifacts} and `externalResources` report,
1400
1572
  * deduplicated by URI. A session-scoped `output://` URI is one row per session.
1401
1573
  * `uri` is a `scheme://` URI, an absolute local file path, or an external
1402
- * resource's canonical https URL.
1574
+ * resource's canonical https URL. Stated action evidence wins over inferred
1575
+ * verb evidence; within the same certainty, action precedence decides.
1403
1576
  */
1404
1577
  export declare interface KayAppAutomationProducedResourceItem {
1405
1578
  readonly uri: string;
1406
- /** By precedence `deleted` > `created` > `updated`; only an artifact receipt reports `deleted`. */
1579
+ /** Stated evidence beats inferred evidence; within one certainty, `deleted` > `created` > `updated`. Only an artifact receipt reports `deleted`. */
1407
1580
  readonly action: "created" | "updated" | "deleted";
1408
- /** The session that produced it, and the one a session-scoped URI resolves against. */
1581
+ /** The first activity-ordered session carrying the winning certainty and action; for a session-scoped URI, the session it resolves against. */
1409
1582
  readonly sessionId: string;
1410
- /** A real revision the run recorded for this URI, and how many; absent when it recorded none. */
1583
+ /** The last revision recorded for the winning certainty/action, or the last revision of the highest-ranked revision-bearing contribution (stated before inferred, then action precedence), and how many distinct revisions there were; ordered by activity, not time. */
1411
1584
  readonly revision?: {
1412
1585
  readonly id: string;
1413
1586
  readonly count: number;
@@ -1833,6 +2006,8 @@ export declare interface KayAppCorpus {
1833
2006
  * indexed path and validates the opaque cursor before opening it. When `throughEntryId` is
1834
2007
  * supplied, the cursor stops at that entry's transaction line; a V4 line may carry later
1835
2008
  * entries, which are returned for the caller to filter and are replayed on the next page.
2009
+ * A page can hold no entries at all (a run of storage lines) while more follows; a record
2010
+ * longer than the page is stepped over and counted in `oversizedRecords`.
1836
2011
  */
1837
2012
  readEntryBatch?(sessionId: string, options?: {
1838
2013
  readonly cursor?: JsonValue_4;
@@ -1855,10 +2030,23 @@ export declare interface KayAppCorpusEntryBatch {
1855
2030
  /** Opaque cursor at the physical page start, for a partial logical chunk. */
1856
2031
  readonly pageStartCursor?: JsonValue_4;
1857
2032
  readonly mode: "replace" | "append";
2033
+ /**
2034
+ * `record-too-large`: a record longer than the page that the host could not step over, because
2035
+ * its end is not written yet or lies past the host's scan limit.
2036
+ */
1858
2037
  readonly status: "complete" | "more" | "awaiting-append" | "record-too-large";
1859
2038
  /** Present when a caller supplied `throughEntryId`. */
1860
2039
  readonly anchorFound?: boolean;
2040
+ /** Records on this page the host could not parse; its other entries are returned. */
1861
2041
  readonly malformedRecords: number;
2042
+ /**
2043
+ * Records longer than the page that this read stepped over without parsing them: at most one,
2044
+ * and the page then holds no entries. When the caller's `throughEntryId` is inside it,
2045
+ * `anchorFound` is true and the cursor is after it.
2046
+ */
2047
+ readonly oversizedRecords?: number;
2048
+ /** Bytes of the stepped-over record, when there is one. */
2049
+ readonly oversizedRecordBytes?: number;
1862
2050
  }
1863
2051
 
1864
2052
  /** One stored session, as the granted corpus enumerates them. Keyed by its stable `sessionId`. */
@@ -1896,7 +2084,8 @@ export declare interface KayAppData {
1896
2084
  * the registration in a `register()` you call both at activation and from your
1897
2085
  * `app.account.subscribe` listener. A source registered once at activation is gone for the
1898
2086
  * life of the process after the first identity change, and the renderer retries attaching to
1899
- * it forever.
2087
+ * it forever. If that listener gates on identity, re-register as well whenever the current
2088
+ * registration's {@link KayAppDataSourceRegistration.isRetired} answers `true`.
1900
2089
  */
1901
2090
  registerSource(sourceId: string, definition: KayAppDataSourceDefinition): KayAppDataSourceRegistration;
1902
2091
  /**
@@ -1994,6 +2183,16 @@ export declare interface KayAppDataSourceRegistration {
1994
2183
  invalidate(): void;
1995
2184
  /** Optional on older hosts; keep the producer's normal lifecycle when absent. */
1996
2185
  readonly demand?: KayAppDataSourceDemand;
2186
+ /**
2187
+ * Whether the host no longer serves this registration: it was disposed, replaced by a newer
2188
+ * registration of the same source, or retired by an account identity change (see
2189
+ * {@link KayAppData.registerSource}). A retired registration never comes back; register again.
2190
+ * An `app.account` listener that gates its re-registration on its own reading of the identity
2191
+ * must also re-register when this is `true`: the host's identity change and the one a plugin
2192
+ * can observe need not coincide. The common case is the first sign-in resolution after boot,
2193
+ * when `profile()` already carries the last-known subject. Optional on older hosts.
2194
+ */
2195
+ isRetired?(): boolean;
1997
2196
  dispose(): void;
1998
2197
  }
1999
2198
 
@@ -2028,7 +2227,7 @@ export declare type KayAppDataUnavailableReason =
2028
2227
  /** The backing read was attempted and threw. Look for the failure in the host's own log. */
2029
2228
  | "read-failed"
2030
2229
  /** A valid steady state with nothing to show — signed out, empty scope, feature off. */
2031
- | "intentionally-unavailable";
2230
+ | "intentionally-unavailable" | "needs-reauthentication" | "device-reconnect-required";
2032
2231
 
2033
2232
  /** App-lifetime cleanup registered by a `kay.app` plugin during activation. */
2034
2233
  export declare type KayAppDisposer = () => void | Promise<void>;
@@ -2492,6 +2691,13 @@ export declare interface KayAppPluginApi {
2492
2691
  * posture to tighten if plugin execution is ever isolated (#3266).
2493
2692
  */
2494
2693
  readonly paths: KayAppPaths;
2694
+ /**
2695
+ * The daemon's clock and the time zone the user is in, with a label for a zone the host does not
2696
+ * know. Always present and ungated, like {@link paths}: it confers no authority, since a plugin
2697
+ * runs in the daemon's process and can read the clock itself. Read the zone here and not from
2698
+ * `Intl` or `process.env.TZ`; see {@link KayAppTime.snapshot}.
2699
+ */
2700
+ readonly time: KayAppTime;
2495
2701
  /**
2496
2702
  * Read/arrange access to the live desktop workspace. Present whenever the host has a workspace
2497
2703
  * (a headless daemon may not); absence is a host fact, never a grant signal. Reading the snapshot
@@ -2576,7 +2782,7 @@ export declare interface KayAppPluginApi {
2576
2782
  readonly models: KayAppModels;
2577
2783
  /**
2578
2784
  * Jev typed-decision inference, as an OPTIONAL accelerator with a REQUIRED fallback. Each call
2579
- * is checked against `jev.use` — but a refused grant or a missing saved key both
2785
+ * is checked against `jev.use` — but a refused grant or no usable Jev provider both
2580
2786
  * produce the same outcome: your `fallback` runs.
2581
2787
  *
2582
2788
  * Always present, on every host, unlike the grant-gated and host-fact-gated members above. That
@@ -2587,8 +2793,8 @@ export declare interface KayAppPluginApi {
2587
2793
  readonly withJev: WithJev;
2588
2794
  /**
2589
2795
  * Recorded Jev signals. `observe` runs a Jev inference and records the answer as a durable,
2590
- * provenance-stamped row; each call is checked against `jev.use`, and a refused grant, a
2591
- * missing saved key, a timeout, or a vendor error all produce the same outcome: an
2796
+ * provenance-stamped row; each call is checked against `jev.use`, and a refused grant, no
2797
+ * usable Jev provider, a timeout, or a vendor error all produce the same outcome: an
2592
2798
  * `unavailable` observation with `stored: false`. A name that breaks the recorded-name grammar
2593
2799
  * is refused as `invalid` before any of that. `list` and `listDetectors` read EVERY plugin's
2594
2800
  * recorded signals back, each call checked against `signals.read`, answering `unavailable` or
@@ -2598,6 +2804,15 @@ export declare interface KayAppPluginApi {
2598
2804
  * defined baseline beside it.
2599
2805
  */
2600
2806
  readonly signals: KayAppSignals;
2807
+ /**
2808
+ * Read-only metadata about the user's managed skills: identity, the exact `git-tree:<oid>`
2809
+ * version each serves (the same identity skill invocations record), revision history, and
2810
+ * suggested changes. Each call is checked against `skills.read`; a refused grant or a host
2811
+ * with no skill store resolves to `{ status: "unavailable" }`, never a rejection, while the
2812
+ * plugin is enabled. After it is disabled, a kept handle's methods throw synchronously. Always
2813
+ * present, like {@link signals}.
2814
+ */
2815
+ readonly skills: KayAppSkills;
2601
2816
  /** The app-wide endpoint bus (register handlers a consuming surface invokes). */
2602
2817
  readonly endpoints: KayAppEndpoints;
2603
2818
  /** Publish one event declared by this plugin's `kay.app` manifest target. */
@@ -2754,16 +2969,17 @@ export declare type KayAppSessionCreator = SessionCreator;
2754
2969
 
2755
2970
  export declare type KayAppSessionDefiner = SessionDefiner;
2756
2971
 
2757
- export declare type KayAppSessionEvent = KayAppHumanMessageSessionEvent | KayAppTurnSettledSessionEvent | KayAppPhaseShiftSessionEvent;
2972
+ export declare type KayAppSessionEvent = KayAppHumanMessageSessionEvent | KayAppTurnSettledSessionEvent | KayAppPhaseShiftSessionEvent | KayAppUiActionSessionEvent;
2758
2973
 
2759
2974
  declare interface KayAppSessionEventBase {
2760
2975
  readonly sessionId: string;
2761
2976
  /**
2762
2977
  * The event's own anchor entry: the projected human carrier, the settled turn's own last
2763
- * entry, or the phase-shift observation's `observationEntryId`. A handler bounds its OWN logical
2764
- * corpus interval using this id (via whatever packet-building helpers the plugin already owns);
2765
- * the door hands out no `readEntries()` closure, and re-validating what was read against the
2766
- * CURRENT branch — a rewind can race between publish and read — is the handler's own job.
2978
+ * entry, the phase-shift observation's `observationEntryId`, or the projected `ui_action`
2979
+ * entry. A handler bounds its OWN logical corpus interval using this id (via whatever
2980
+ * packet-building helpers the plugin already owns); the door hands out no `readEntries()`
2981
+ * closure, and re-validating what was read against the CURRENT branch — a rewind can race
2982
+ * between publish and read — is the handler's own job.
2767
2983
  */
2768
2984
  readonly entryId: string;
2769
2985
  /** ISO-8601 publish time. */
@@ -2864,12 +3080,12 @@ export declare interface KayAppSessionEventsSubscribeOptions {
2864
3080
  }
2865
3081
 
2866
3082
  /**
2867
- * A closed, extensible union: a projected human message, a settled turn, or an accepted
2868
- * phase-shift observation. They share one subscribable set now that there is no dispatcher
2869
- * chaining one job's completion into another's `when`. Adding a fourth type is additive, never
2870
- * breaking.
3083
+ * A closed, extensible union: a projected human message, a settled turn, an accepted phase-shift
3084
+ * observation, or a projected interface action. They share one subscribable set now that there is
3085
+ * no dispatcher chaining one job's completion into another's `when`. Adding a type is additive,
3086
+ * never breaking: `ui-action` was the fourth.
2871
3087
  */
2872
- export declare type KayAppSessionEventType = "human-message" | "turn-settled" | "phase-shift";
3088
+ export declare type KayAppSessionEventType = "human-message" | "turn-settled" | "phase-shift" | "ui-action";
2873
3089
 
2874
3090
  export declare type KayAppSessionIntent = SessionIntent;
2875
3091
 
@@ -3160,7 +3376,7 @@ export declare interface KayAppSignal {
3160
3376
  readonly source: KayAppSignalSource;
3161
3377
  readonly recordedAtMs: number;
3162
3378
  /** Keyed by question name, full probability distributions included. */
3163
- readonly answers: Readonly<Record<string, NoulResponse | ChoiceResponse | ScoreResponse>>;
3379
+ readonly answers: Readonly<Record<string, KayAppSignalAnswer>>;
3164
3380
  /** The inference that produced the answers; absent when the host recorded only part of it. */
3165
3381
  readonly inference?: {
3166
3382
  readonly model: string;
@@ -3172,6 +3388,9 @@ export declare interface KayAppSignal {
3172
3388
  readonly inputDigest: string;
3173
3389
  }
3174
3390
 
3391
+ /** One stored answer: a {@link JevAnswer}, or a yes/no answer recorded before SDK 0.12.0. */
3392
+ export declare type KayAppSignalAnswer = JevAnswer | KayAppSignalNoulAnswer;
3393
+
3175
3394
  /** One version of one detector, under one rubric, as the catalog lists it. */
3176
3395
  export declare interface KayAppSignalDetector {
3177
3396
  readonly pluginId: string;
@@ -3182,16 +3401,26 @@ export declare interface KayAppSignalDetector {
3182
3401
  * version mean the rubric was edited without a version bump.
3183
3402
  */
3184
3403
  readonly rubricDigest: string;
3185
- readonly questions: Questions;
3404
+ readonly questions: Readonly<Record<string, KayAppSignalRubricQuestion>>;
3186
3405
  readonly firstRecordedAtMs: number;
3187
3406
  readonly lastRecordedAtMs: number;
3188
3407
  }
3189
3408
 
3409
+ /**
3410
+ * A yes/no answer as rows recorded before SDK 0.12.0 carry it, in TypeSafe's vocabulary:
3411
+ * `noul` is P(yes). Stored rows are never rewritten, so a reader still meets these.
3412
+ */
3413
+ export declare interface KayAppSignalNoulAnswer {
3414
+ readonly type: "noul";
3415
+ readonly noul: number;
3416
+ }
3417
+
3190
3418
  /**
3191
3419
  * The result of one observe call. `status` is the only field a caller must switch on:
3192
3420
  *
3193
- * - `classified`: Jev answered; `answers`, `model`, and `usage` are the vendor's verbatim
3194
- * response, and `stored` says whether the row landed in the durable store.
3421
+ * - `classified`: Jev answered; `answers` (one {@link JevAnswer} per question), `model`, and
3422
+ * `usage` are what the Jev call returned, and `stored` says whether the row landed in the
3423
+ * durable store.
3195
3424
  * - `unavailable`: Jev could not answer (no key, refused grant, timeout, vendor error, or a
3196
3425
  * malformed response), or the host has no signals store at all (`reason: "no-store"`).
3197
3426
  * `reason` names the host's classification; no row is written, so the same input can be
@@ -3242,6 +3471,18 @@ export declare interface KayAppSignalPage {
3242
3471
  readonly nextCursor?: string;
3243
3472
  }
3244
3473
 
3474
+ /**
3475
+ * One question of a stored rubric, as the recording plugin wrote it. Rubrics recorded before
3476
+ * SDK 0.12.0 use TypeSafe's vocabulary (`noul` for yes/no, and instructions or criteria that
3477
+ * may be JSON rather than text), and a stored rubric is never rewritten, so only `type` is
3478
+ * guaranteed.
3479
+ */
3480
+ export declare interface KayAppSignalRubricQuestion {
3481
+ readonly type: string;
3482
+ readonly instructions?: unknown;
3483
+ readonly criteria?: unknown;
3484
+ }
3485
+
3245
3486
  /**
3246
3487
  * The plugin's signal door. `observe` runs the fused inference-and-record step; `list` and
3247
3488
  * `listDetectors` read recorded signals back. The plugin id is stamped by the host at the
@@ -3364,16 +3605,16 @@ export declare interface KayAppSignalsObserveInput {
3364
3605
  * transcript the source points at. So the projection must be a pure function of the
3365
3606
  * transcript and the detector version, or the row's evidence cannot be reproduced.
3366
3607
  */
3367
- readonly state: unknown;
3608
+ readonly state: JevState;
3368
3609
  /**
3369
- * The typed questions to answer, as the vendor SDK accepts them. Stored once per digest. A
3610
+ * The typed questions to answer. Stored once per digest. A
3370
3611
  * rubric asks 1 to 64 questions. Each name is an identifier (letters, digits, and `_`, not
3371
3612
  * starting with a digit), at most 64 characters, because a reader types it into a `where`
3372
3613
  * filter. A choice question offers at most {@link MAX_CHOICE_LABELS} labels, each 1 to 64
3373
3614
  * characters with no `,`, `@`, or control or invisible character (`\p{C}`), and no whitespace
3374
3615
  * but single spaces between words, so a reader can copy it back exactly from rendered text.
3375
3616
  */
3376
- readonly questions: Questions;
3617
+ readonly questions: JevQuestions;
3377
3618
  readonly options?: WithJevOptions;
3378
3619
  }
3379
3620
 
@@ -3455,6 +3696,184 @@ export declare interface KayAppSignalsSessionQuery {
3455
3696
  readonly limit?: number;
3456
3697
  }
3457
3698
 
3699
+ /** One managed skill, as the skill catalog admits it. */
3700
+ export declare interface KayAppSkill {
3701
+ /** Canonical id, `<canonical source id>/<name>`. Equal to a skill invocation's `resourceId`. */
3702
+ readonly skillId: string;
3703
+ /** `skill://<sourceId>/<name>`, the address sessions read the skill at. */
3704
+ readonly uri: string;
3705
+ /** The source's display id (`user`, a plugin slug, …) — never the canonical minted id. */
3706
+ readonly sourceId: string;
3707
+ readonly name: string;
3708
+ readonly description: string;
3709
+ }
3710
+
3711
+ /** One skill with its current version and its suggestions. */
3712
+ export declare interface KayAppSkillDetail extends KayAppSkill {
3713
+ readonly versioning: KayAppSkillVersioning;
3714
+ /**
3715
+ * The version a session loading the skill now receives, as `git-tree:<oid>`. Absent when Kay
3716
+ * keeps no history of the skill (`unversioned`), cannot read it, or the skill's files hold
3717
+ * bytes no revision has recorded (`uncommitted`).
3718
+ */
3719
+ readonly version?: string;
3720
+ /** The current revision id, when {@link version} is present. */
3721
+ readonly revision?: string;
3722
+ /**
3723
+ * The skill's files hold bytes no revision has recorded: uncommitted changes, or files the
3724
+ * skill's own `.gitignore` names, which a session loading it still receives.
3725
+ */
3726
+ readonly uncommitted: boolean;
3727
+ /** Every suggestion recorded for the skill, any status, newest `createdAt` first. */
3728
+ readonly suggestions: readonly KayAppSkillSuggestion[];
3729
+ }
3730
+
3731
+ export declare interface KayAppSkillHistoryOptions {
3732
+ /** At most this many revisions, newest first. Default 50, clamped to 1..500. */
3733
+ readonly limit?: number;
3734
+ }
3735
+
3736
+ export declare type KayAppSkillHistoryResult = {
3737
+ readonly status: "ok";
3738
+ readonly versioning: KayAppSkillVersioning;
3739
+ /** Newest first. Empty when the skill is `unversioned` or `unavailable`. */
3740
+ readonly revisions: readonly KayAppSkillRevision[];
3741
+ /** More revisions exist than were returned. */
3742
+ readonly truncated: boolean;
3743
+ } | KayAppSkillNotFound | KayAppSkillsUnavailable;
3744
+
3745
+ /**
3746
+ * The named skill is not one the catalog admits. Only answered when every skill source could be
3747
+ * read: a name missing from a partial catalog answers `unavailable` instead, because its own
3748
+ * source may be the unreadable one.
3749
+ */
3750
+ export declare interface KayAppSkillNotFound {
3751
+ readonly status: "not-found";
3752
+ readonly message: string;
3753
+ }
3754
+
3755
+ /** Who made a revision, as Kay recorded it when the revision was made. Absent fields are unknown. */
3756
+ export declare interface KayAppSkillProvenance {
3757
+ /** The session whose work the revision records. */
3758
+ readonly sessionId?: string;
3759
+ /** Who that session acted as: `user`, `subagent`, `system/<surface>`, `followup/<surface>`. */
3760
+ readonly actor?: string;
3761
+ }
3762
+
3763
+ export declare type KayAppSkillReadResult = {
3764
+ readonly status: "ok";
3765
+ readonly skill: KayAppSkillDetail;
3766
+ } | KayAppSkillNotFound | KayAppSkillsUnavailable;
3767
+
3768
+ /**
3769
+ * The plugin-facing `kay.app` skills contract: a read-only view of the user's managed skills —
3770
+ * which skills exist, the exact version each one serves, how each version came about, and the
3771
+ * suggested changes waiting for (or already given) a person's review.
3772
+ *
3773
+ * Every call is checked against the `skills.read` claim at the call, so a grant or revocation
3774
+ * takes effect on the next one. Like `app.signals`, the member is ALWAYS present and no call
3775
+ * rejects while the plugin is enabled: an environment failure or a refused grant resolves to
3776
+ * `{ status: "unavailable" }`. After the plugin is disabled, a kept handle's methods throw
3777
+ * synchronously.
3778
+ *
3779
+ * It is metadata only. A skill's bytes are read through `skill://` (an agent's door), and there
3780
+ * is no write here: a plugin changes a skill the way any session does, through `skill://`.
3781
+ *
3782
+ * ## Versions
3783
+ *
3784
+ * `version` is always `git-tree:<oid>` — the SAME identity a session records when it loads a
3785
+ * skill (`CorpusResourceInvocation.version`). So "did this session load the skill before or
3786
+ * after its last accepted suggestion?" is a comparison of values from the two APIs: find the
3787
+ * newest revision in {@link KayAppSkills.history} that carries `acceptedSuggestionId`; a loaded
3788
+ * version is at or after it when it equals that revision's version or a newer one's. A session
3789
+ * that loaded the skill while its files held unrecorded bytes (uncommitted edits, or files its
3790
+ * own `.gitignore` names) recorded a version no revision carries, so it cannot be placed.
3791
+ */
3792
+ /**
3793
+ * Which skill a call is about: its canonical id (`KayAppSkill.skillId`, the same value as a skill
3794
+ * invocation's `resourceId`) or its `skill://<sourceId>/<name>` address.
3795
+ */
3796
+ export declare type KayAppSkillRef = string;
3797
+
3798
+ /** One revision of a skill's history. */
3799
+ export declare interface KayAppSkillRevision {
3800
+ readonly revision: string;
3801
+ /** `git-tree:<oid>`: the version a session loading this revision recorded. */
3802
+ readonly version: string;
3803
+ /** ISO-8601 time the revision was authored. */
3804
+ readonly at: string;
3805
+ /** `upstream`: the source shipped these bytes. `local`: they were changed on this machine. */
3806
+ readonly line: "local" | "upstream";
3807
+ /** One line about the change. */
3808
+ readonly summary: string;
3809
+ /** Set when accepting this suggestion made this revision the skill's content. */
3810
+ readonly acceptedSuggestionId?: string;
3811
+ readonly provenance?: KayAppSkillProvenance;
3812
+ }
3813
+
3814
+ /** One exact point in a skill's history. */
3815
+ export declare interface KayAppSkillRevisionRef {
3816
+ /** The revision id, as `skill://<sourceId>/<name>/@revision/<id>` takes it. */
3817
+ readonly revision: string;
3818
+ /** `git-tree:<oid>`. Absent only when the revision can no longer be read. */
3819
+ readonly version?: string;
3820
+ }
3821
+
3822
+ /** `app.skills`: read-only skill metadata, each call checked against `skills.read`. */
3823
+ export declare interface KayAppSkills {
3824
+ /** Every managed skill the catalog admits, ordered by source then name. */
3825
+ list(): Promise<KayAppSkillsListResult>;
3826
+ /** One skill's identity, current version, and suggestions. */
3827
+ read(skill: KayAppSkillRef): Promise<KayAppSkillReadResult>;
3828
+ /** One skill's revisions, newest first, each with its version and how it came about. */
3829
+ history(skill: KayAppSkillRef, options?: KayAppSkillHistoryOptions): Promise<KayAppSkillHistoryResult>;
3830
+ }
3831
+
3832
+ export declare type KayAppSkillsListResult = {
3833
+ readonly status: "ok";
3834
+ readonly skills: readonly KayAppSkill[];
3835
+ /**
3836
+ * `false` when some source could not be read: an absent skill is then not proof that the
3837
+ * user has no such skill.
3838
+ */
3839
+ readonly complete: boolean;
3840
+ } | KayAppSkillsUnavailable;
3841
+
3842
+ /** One suggested change to a skill, in any status. */
3843
+ export declare interface KayAppSkillSuggestion {
3844
+ readonly id: string;
3845
+ readonly status: "pending" | "accepted" | "declined";
3846
+ /** The proposer's stated reason, when one was recorded. */
3847
+ readonly reason?: string;
3848
+ readonly createdAt: string;
3849
+ readonly updatedAt: string;
3850
+ /** The skill revision the change was proposed against. */
3851
+ readonly base: KayAppSkillRevisionRef;
3852
+ /** The proposed content. */
3853
+ readonly candidate: KayAppSkillRevisionRef;
3854
+ /** What became the skill's content on acceptance; present only when `status` is `accepted`. */
3855
+ readonly accepted?: KayAppSkillRevisionRef;
3856
+ /** Who proposed it, from the candidate revision's own record. */
3857
+ readonly provenance?: KayAppSkillProvenance;
3858
+ }
3859
+
3860
+ /**
3861
+ * Why a skills read could not be answered. `not-granted`: the user has not granted `skills.read`.
3862
+ * `not-available`: this host has no skill store or catalog, or could not read it right now.
3863
+ */
3864
+ export declare interface KayAppSkillsUnavailable {
3865
+ readonly status: "unavailable";
3866
+ readonly reason: "not-granted" | "not-available";
3867
+ readonly message: string;
3868
+ }
3869
+
3870
+ /**
3871
+ * Whether Kay keeps a history for the skill, and how its local copy relates to its source.
3872
+ * `unversioned`: the skill's files are the user's own, and Kay keeps no history of them.
3873
+ * `unavailable`: Kay does keep one and cannot read it right now.
3874
+ */
3875
+ export declare type KayAppSkillVersioning = "pristine" | "customized" | "update-available" | "diverged" | "unversioned" | "unavailable";
3876
+
3458
3877
  /** Granted access to the plugin's isolated SQLite database. */
3459
3878
  export declare interface KayAppSqliteStorage {
3460
3879
  /** Open the database once per activation; repeated calls return the same handle. */
@@ -3470,6 +3889,76 @@ export declare interface KayAppStorage {
3470
3889
  /** Kay's reasoning-effort ladder, in ascending order. */
3471
3890
  export declare type KayAppThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
3472
3891
 
3892
+ /**
3893
+ * `app.time`: host facts about time. Added in SDK 0.12.1: a plugin that calls it declares
3894
+ * `compatibility.sdk` `^0.12.1`, so an older Bonsai refuses a directory or repository plugin at
3895
+ * load instead of the call failing.
3896
+ */
3897
+ export declare interface KayAppTime {
3898
+ /**
3899
+ * Reads the daemon's clock and the user's time zone now.
3900
+ *
3901
+ * Every call asks the host again and returns a new object; nothing is cached. Call it where you
3902
+ * need the value (inside a tool, a handler or a workflow step), not inside `activate()`: a value
3903
+ * read there is as old as the activation, and the host can run a bundled plugin's `activate()`
3904
+ * against a recording api that has no `time`, so a read there throws. The exception is a
3905
+ * directory plugin that declares a workflow with a cron `timezone`: `workflows.define` is legal
3906
+ * only during `activate()`, so it reads the zone there, and the schedule then keeps that zone.
3907
+ * Keep the result for as long as you use it, and not across a long wait (a sleep, a timer, a
3908
+ * queued run): the zone can change while you wait. On a daemon that runs on the user's machine,
3909
+ * a change of the process's `TZ` shows in the next call. A `TZ` that names a zone wins over the
3910
+ * operating system's zone, so a change of the operating-system zone does not show while the
3911
+ * process has one. When `TZ` is unset or does not name a zone, a change of the operating-system
3912
+ * zone is meant to show, but none has been seen on a real machine yet.
3913
+ *
3914
+ * A zone the host cannot determine is an answer (`zoneSource: "utc-fallback"`), not an error.
3915
+ *
3916
+ * Use this to find the zone, not `Intl.DateTimeFormat().resolvedOptions().timeZone`, which can
3917
+ * keep a zone the runtime read earlier, or `process.env.TZ`, which is often unset or not a zone.
3918
+ * Neither says that the zone is unknown.
3919
+ *
3920
+ * It does not use `this`, so it is safe to destructure.
3921
+ */
3922
+ readonly snapshot: () => KayAppTimeSnapshot;
3923
+ }
3924
+
3925
+ /**
3926
+ * The plugin-facing `kay.app` time contract: the daemon's clock and the time zone the user is in,
3927
+ * read together in one call.
3928
+ *
3929
+ * Ungated and always present, like `app.paths`. It confers no authority: a plugin runs in the
3930
+ * daemon's process and can already read the clock. What `app.time` adds is the daemon's answer
3931
+ * for the USER's zone, and a label for the case where that answer is unknown.
3932
+ */
3933
+ /** One reading of the daemon's clock and the user's time zone. Each call returns a new object. */
3934
+ export declare interface KayAppTimeSnapshot {
3935
+ /** The daemon's clock when the snapshot was read: milliseconds since the Unix epoch. */
3936
+ readonly nowMs: number;
3937
+ /**
3938
+ * The time zone the user is in, as an IANA id in the spelling ICU resolves (`America/New_York`).
3939
+ * One zone can have two ids, and ICU picks one: `Asia/Kolkata` comes back as `Asia/Calcutta`. So
3940
+ * never compare zone ids with `===`. A first-party plugin compares with `sameZone` from
3941
+ * `@kay/time`. A plugin that imports only this SDK and node builtins resolves each id with
3942
+ * `new Intl.DateTimeFormat("en-US", { timeZone: id }).resolvedOptions().timeZone` and compares the
3943
+ * results. Pass `zone` as the `timeZone` of `Intl.DateTimeFormat` or `toLocaleString` to format a
3944
+ * time for the user.
3945
+ *
3946
+ * When `zoneSource` is `utc-fallback` the zone is unknown, and this value is `UTC` only because a
3947
+ * value is required.
3948
+ */
3949
+ readonly zone: string;
3950
+ /**
3951
+ * How the daemon found `zone`.
3952
+ * - `host`: the daemon runs on the user's machine, and `zone` is the zone the daemon process
3953
+ * runs in, read for this call: the process's `TZ` when that names a zone, otherwise the
3954
+ * operating system's zone.
3955
+ * - `utc-fallback`: the daemon does not know the user's zone. It runs on another machine (a remote
3956
+ * daemon), or the machine's zone could not be read or is not an IANA id. `zone` is `UTC`, which
3957
+ * here is a placeholder and not a fact about the user: do not show it to the user as their zone.
3958
+ */
3959
+ readonly zoneSource: "host" | "utc-fallback";
3960
+ }
3961
+
3473
3962
  /**
3474
3963
  * The host-stamped per-call context an app-contributed tool's `execute` receives. The app
3475
3964
  * activation is app-lifetime code serving EVERY session, so unlike a kernel tool (whose session
@@ -3587,6 +4076,22 @@ export declare interface KayAppTurnSettledSessionEvent extends KayAppSessionEven
3587
4076
  readonly originSurface?: string;
3588
4077
  }
3589
4078
 
4079
+ /**
4080
+ * The person answered a card the agent drew with `ui_render` (pressed Send on a drafted message,
4081
+ * submitted a form), published once the answer is projected into the source session's transcript.
4082
+ *
4083
+ * It names the answer and the call it answers, never the answer's content: a handler reads the
4084
+ * `ui_action` entry and the `ui_render` call through the granted `KayAppCorpus`, like every other
4085
+ * event here. A typed message does NOT publish this (it publishes `human-message`), and a click
4086
+ * does not publish `human-message`. A click the host refuses at admission (a stale or duplicate
4087
+ * card) is never projected and publishes nothing, so there is one event per accepted answer.
4088
+ */
4089
+ export declare interface KayAppUiActionSessionEvent extends KayAppSessionEventBase {
4090
+ readonly type: "ui-action";
4091
+ /** The `ui_render` tool call the answer is for (the `ui_action` message's own `toolCallId`). */
4092
+ readonly toolCallId: string;
4093
+ }
4094
+
3590
4095
  export declare interface KayAppWhiteboard {
3591
4096
  /**
3592
4097
  * Binds read-only Whiteboard access to the exact context issued to this plugin's session source.
@@ -3715,6 +4220,14 @@ export declare interface KayAppWorkflowContext {
3715
4220
  * is gone. Settled memo results return directly. A crash after a turn settles but before its
3716
4221
  * memo commits can cause one extra continuation turn in the same session.
3717
4222
  *
4223
+ * A keyed child whose turn fails for a transient reason (`network`, `stream_interrupted`,
4224
+ * `overloaded`, `rate_limit`, `server_error`, or `timeout` when you declared no `timeoutMs`) is
4225
+ * continued the same way: Kay waits, waits for the network when it can probe it, and sends a
4226
+ * continuation to the same session, up to six times and for at most 20 hours after the first
4227
+ * failure. A continuation the host refuses counts as one attempt and keeps the failure. Only
4228
+ * the final outcome returns and is memoized. Unkeyed children and every other failure return at
4229
+ * once.
4230
+ *
3718
4231
  * This does not resume an interrupted tool's JavaScript. The continued agent may call it
3719
4232
  * again, so external effects still need idempotency when duplicates would matter.
3720
4233
  */
@@ -4000,7 +4513,7 @@ export declare interface KayAppWorkspaceTabSnapshot {
4000
4513
 
4001
4514
  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";
4002
4515
 
4003
- 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";
4516
+ 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";
4004
4517
 
4005
4518
  declare interface LineRange {
4006
4519
  readonly start: number;
@@ -4062,29 +4575,26 @@ declare interface MistralConversationsCompat {
4062
4575
  supportsMidConvoSystemMessages?: boolean;
4063
4576
  }
4064
4577
 
4065
- declare interface Model<TApi extends Api> {
4066
- id: string;
4067
- name: string;
4068
- api: TApi;
4069
- provider: ProviderId;
4070
- baseUrl: string;
4578
+ /** Chat model: usable with `stream()` and friends. */
4579
+ declare interface Model<TApi extends Api> extends BaseModel<TApi> {
4580
+ /**
4581
+ * Optional: chat is the default model type, so models without `type` are chat
4582
+ * models. Narrow mixed model lists with `isModelType()` instead of comparing
4583
+ * `type` directly.
4584
+ */
4585
+ type?: "chat";
4071
4586
  reasoning: boolean;
4072
4587
  /**
4073
4588
  * Maps pi thinking levels to provider/model-specific values.
4074
4589
  * Missing keys use provider defaults. null marks a level as unsupported.
4075
4590
  */
4076
4591
  thinkingLevelMap?: ThinkingLevelMap;
4077
- input: ("text" | "image")[];
4078
- /** Provider input limits and cache-safe preprocessing metadata. */
4079
- inputLimits?: ModelInputLimits;
4080
- cost: ModelCost;
4081
4592
  /** Prompt cache lifetimes per retention tier. Unset when the provider's cache behavior is unknown. */
4082
4593
  promptCache?: ModelPromptCache;
4083
4594
  contextWindow: number;
4084
4595
  maxTokens: number;
4085
4596
  /** Default sampling parameters for this model. See {@link StreamOptions.samplingParams}; per-request keys override these. */
4086
4597
  samplingParams?: Record<string, unknown>;
4087
- headers?: Record<string, string>;
4088
4598
  /** Compatibility overrides for OpenAI-compatible APIs. If not set, auto-detected from baseUrl. */
4089
4599
  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;
4090
4600
  }
@@ -4137,7 +4647,27 @@ declare type ModelPromptCache = Partial<Record<Exclude<CacheRetention, "none">,
4137
4647
 
4138
4648
  declare type ModelThinkingLevel = "off" | ThinkingLevel;
4139
4649
 
4140
- export { NoulResponse }
4650
+ /** A tool call that another tool made while it ran, for example from a codemode script. */
4651
+ declare interface NestedToolCallRecord {
4652
+ id: string;
4653
+ name: string;
4654
+ /** Omitted when over the size limits; `argumentsBytes` then gives their size. */
4655
+ arguments?: JsonObject;
4656
+ /** UTF-8 size of the arguments as JSON, set when `arguments` is omitted. */
4657
+ argumentsBytes?: number;
4658
+ /** `unfinished`: the call was still running when the calling tool finished. */
4659
+ status: "ok" | "error" | "unfinished";
4660
+ durationMs?: number;
4661
+ /** Error text, truncated. */
4662
+ error?: string;
4663
+ }
4664
+
4665
+ /** Bounded record of the nested calls a tool made. Results are not recorded. */
4666
+ declare interface NestedToolCalls {
4667
+ calls: NestedToolCallRecord[];
4668
+ /** False when calls were dropped, arguments omitted, or calls had not finished. */
4669
+ complete: boolean;
4670
+ }
4141
4671
 
4142
4672
  /**
4143
4673
  * Compatibility settings for OpenAI-compatible completions APIs.
@@ -4304,6 +4834,11 @@ declare interface OpenRouterRouting {
4304
4834
  };
4305
4835
  }
4306
4836
 
4837
+ export declare function parseLineSelector(input: string): {
4838
+ address: string;
4839
+ selector: LineSelector;
4840
+ };
4841
+
4307
4842
  export declare function payload(name: string, schema: SchemaInput, options?: UriPayloadOptions): UriPayloadContract;
4308
4843
 
4309
4844
  declare type PhaseShiftCost = z.infer<typeof phaseShiftCostSchema>;
@@ -4420,8 +4955,6 @@ declare interface ProxiedToolCall {
4420
4955
  readonly input: Record<string, unknown>;
4421
4956
  }
4422
4957
 
4423
- export { Questions }
4424
-
4425
4958
  declare interface RawResource {
4426
4959
  readonly uri: string;
4427
4960
  readonly content: string | Uint8Array;
@@ -4615,8 +5148,6 @@ declare interface ScopeRequirement {
4615
5148
  readonly alternatives: readonly ScopeAlternative[];
4616
5149
  }
4617
5150
 
4618
- export { ScoreResponse }
4619
-
4620
5151
  /**
4621
5152
  * Every SDK capability that can mint a session. A new door adds a value here.
4622
5153
  *
@@ -4674,6 +5205,7 @@ declare const SessionCausedByEvent: z.ZodObject<{
4674
5205
  "turn-settled": "turn-settled";
4675
5206
  "phase-shift": "phase-shift";
4676
5207
  "human-message": "human-message";
5208
+ "ui-action": "ui-action";
4677
5209
  }>;
4678
5210
  entryId: z.ZodString;
4679
5211
  runId: z.ZodOptional<z.ZodString>;
@@ -4872,6 +5404,7 @@ declare const SessionProvenanceRecord: z.ZodObject<{
4872
5404
  "turn-settled": "turn-settled";
4873
5405
  "phase-shift": "phase-shift";
4874
5406
  "human-message": "human-message";
5407
+ "ui-action": "ui-action";
4875
5408
  }>;
4876
5409
  entryId: z.ZodString;
4877
5410
  runId: z.ZodOptional<z.ZodString>;
@@ -4943,10 +5476,6 @@ declare interface SystemMessage {
4943
5476
  timestamp: number;
4944
5477
  }
4945
5478
 
4946
- export { SystemOneRequest }
4947
-
4948
- export { SystemOneResult }
4949
-
4950
5479
  declare interface TextContent {
4951
5480
  type: "text";
4952
5481
  text: string;
@@ -5007,6 +5536,19 @@ declare interface ToolCall {
5007
5536
  namespace?: string;
5008
5537
  }
5009
5538
 
5539
+ /** A call to judge with {@link ToolContext.checkToolCallPermission}. */
5540
+ declare interface ToolCallPermissionCheck {
5541
+ readonly toolName: string;
5542
+ readonly input: Record<string, unknown>;
5543
+ }
5544
+
5545
+ declare type ToolCallPermissionVerdict = {
5546
+ readonly allowed: true;
5547
+ } | {
5548
+ readonly allowed: false;
5549
+ readonly reason: string;
5550
+ };
5551
+
5010
5552
  declare interface ToolContext {
5011
5553
  readonly cwd: string;
5012
5554
  readonly model: Model<any> | undefined;
@@ -5031,6 +5573,13 @@ declare interface ToolContext {
5031
5573
  * behind itself. Present only with a live session. One request may be pending at a time.
5032
5574
  */
5033
5575
  readonly requestMidTurnCompaction?: (customInstructions?: string, trigger?: "command" | "suggestion") => MidTurnCompactionRequest;
5576
+ /**
5577
+ * Put a call this tool is about to cause through the session's permission gate, as if the agent
5578
+ * had made it directly: classification, rules, mode, the auto approver, and the approval card.
5579
+ * The call is only judged, never executed. For a tool whose effect is only knowable at run time
5580
+ * (a click in a web page that turns out to send an email). Present only with a live session.
5581
+ */
5582
+ readonly checkToolCallPermission?: (call: ToolCallPermissionCheck) => Promise<ToolCallPermissionVerdict>;
5034
5583
  /**
5035
5584
  * Re-root the session into `newCwd` mid-run, recomposing the cwd-scoped substrate (builtin tools,
5036
5585
  * the capability registry, the system-prompt project line) in place so subsequent tool calls operate
@@ -5317,7 +5866,9 @@ declare type ToolResultMessage<TDetails = JsonValue> = IsJsonCompatible<TDetails
5317
5866
  content: (TextContent | ImageContent)[];
5318
5867
  details?: JsonRepresentation<TDetails>;
5319
5868
  /** Usage from the tool execution itself, if available. Not part of main LLM context accounting. */
5320
- usage?: Usage_2;
5869
+ usage?: Usage;
5870
+ /** Calls this tool made to other tools. Kept for the session record; not sent to the model. */
5871
+ nestedCalls?: NestedToolCalls;
5321
5872
  isError: boolean;
5322
5873
  timestamp: number;
5323
5874
  } : never;
@@ -5343,8 +5894,6 @@ export declare function transcriptRoleLabel(role: "user" | "assistant"): "User"
5343
5894
  declare interface TSchema {
5344
5895
  }
5345
5896
 
5346
- export { TypeSafeClient }
5347
-
5348
5897
  declare interface UriAgentHint {
5349
5898
  readonly summary: string;
5350
5899
  readonly commonFlows?: readonly UriCommonFlow[];
@@ -5619,6 +6168,13 @@ export declare interface UriModule {
5619
6168
  * only after all specific (fallback-falsy) modules miss.
5620
6169
  */
5621
6170
  readonly fallback?: boolean;
6171
+ /**
6172
+ * The module parses the read tool's trailing line selector itself. Absent: the host strips
6173
+ * an explicit range (`:50-200`, `:50-`, `:50+10`, `:raw`, never a bare `:50`), dispatches the
6174
+ * bare address, and windows the result (`hostLineWindow`). Mirrors `@herd/uri`'s `UriModule.ownsLineSelectors`, which owns the
6175
+ * full contract (#10754).
6176
+ */
6177
+ readonly ownsLineSelectors?: boolean;
5622
6178
  readonly claims?: readonly UriClaim[];
5623
6179
  /**
5624
6180
  * Optional; injected into the system prompt when the module is active. Omit
@@ -5646,6 +6202,13 @@ export declare interface UriModule {
5646
6202
  readonly uri: string;
5647
6203
  readonly payload: unknown;
5648
6204
  }, ctx: UriResolveContext): Promise<UriOperationDescription | undefined>;
6205
+ /**
6206
+ * Name what a settled call on `request.uri` touched, for a transcript row (mirrors the protocol
6207
+ * contract in `@herd/uri`). The host asks once per successful URI verb call after the handler
6208
+ * returns, bounds the wait, and stamps the admitted answer on the result's `details` only; a
6209
+ * throw, a late answer or a refused one costs the label, never the call.
6210
+ */
6211
+ labelResource?(request: UriResourceLabelRequest, ctx: UriResolveContext): Promise<UriResourceLabel | undefined>;
5649
6212
  /**
5650
6213
  * Set false when the generic write tool must reject `source` copies before
5651
6214
  * fetching the source. Inline `content` writes remain available.
@@ -6167,6 +6730,24 @@ declare interface UriResourceDescription {
6167
6730
  readonly sourceUrl?: string;
6168
6731
  }
6169
6732
 
6733
+ /**
6734
+ * What a settled call touched, as a person would name it.
6735
+ *
6736
+ * `name` is the resource itself (`#lane-analytics`). `section` is the part of it the address
6737
+ * reaches into (`thread`), and is absent when the address is the resource.
6738
+ */
6739
+ declare interface UriResourceLabel {
6740
+ readonly name: string;
6741
+ readonly section?: string;
6742
+ }
6743
+
6744
+ /** The call a module is asked to label. */
6745
+ declare interface UriResourceLabelRequest {
6746
+ readonly operation: UriOperation;
6747
+ /** The dispatch address: selector-stripped, the exact form the module's verb handler received. */
6748
+ readonly uri: string;
6749
+ }
6750
+
6170
6751
  declare interface UriSchemeClaim {
6171
6752
  readonly kind: "scheme";
6172
6753
  readonly scheme: string;
@@ -6338,9 +6919,7 @@ declare interface UrlPatternClaim {
6338
6919
  readonly examples?: readonly string[];
6339
6920
  }
6340
6921
 
6341
- export { Usage }
6342
-
6343
- declare interface Usage_2 {
6922
+ declare interface Usage {
6344
6923
  input: number;
6345
6924
  output: number;
6346
6925
  cacheRead: number;
@@ -6502,8 +7081,8 @@ export declare type WhiteboardValue = z.infer<typeof WhiteboardValue>;
6502
7081
  /**
6503
7082
  * Run `use` against a live Jev client, falling back to `fallback` whenever Jev cannot serve the
6504
7083
  * call. The wrapper exists so a feature can ASK for a typed decision without ever depending on
6505
- * one: `fallback` is required, and it runs whenever no host-managed key is saved,
6506
- * the user has not granted `jev.use`, the branch exceeds its budget, `use` throws, or
7084
+ * one: `fallback` is required, and it runs whenever no provider in the user's Jev provider
7085
+ * order holds a usable credential, the user has not granted `jev.use`, the branch exceeds its budget, `use` throws, or
6507
7086
  * `use` declines by returning `undefined`. With valid options, this rejects on an explicit
6508
7087
  * `signal` abort, reaching `deadlineAt`, or `fallback` itself throwing.
6509
7088
  *
@@ -6511,10 +7090,9 @@ export declare type WhiteboardValue = z.infer<typeof WhiteboardValue>;
6511
7090
  * {@link createFallbackOnlyWithJev}, so a caller never branches on availability — branching is
6512
7091
  * exactly how a fallback gets skipped.
6513
7092
  *
6514
- * `jev` is the vendor's own `TypeSafeClient`, configured with the host's default model and base
6515
- * URL. Native `request.model` overrides remain supported. It
6516
- * is valid only for the duration of the callback: a reference retained past `use`'s scope is
6517
- * refused at the transport, and an in-flight request is aborted when the call stops waiting.
7093
+ * `jev` is a {@link JevClient} on the host's Jev model. It is valid only for the duration of
7094
+ * the callback: a reference retained past `use`'s scope is refused at the transport, and an
7095
+ * in-flight request is aborted when the call stops waiting.
6518
7096
  * The callback itself is ABANDONED, not interrupted — a host cannot stop arbitrary JavaScript
6519
7097
  * that is already running, so `use` must not perform side effects it would mind completing
6520
7098
  * unobserved. The same applies to a running fallback: abort/deadline stops waiting for it but
@@ -6523,7 +7101,7 @@ export declare type WhiteboardValue = z.infer<typeof WhiteboardValue>;
6523
7101
  export declare type WithJev = <T>(
6524
7102
  /** Return `undefined` to decline (the fallback runs). A feature whose real result can itself be
6525
7103
  * `undefined` should return `null` or its own wrapper type instead. */
6526
- use: (jev: TypeSafeClient) => T | undefined | PromiseLike<T | undefined>,
7104
+ use: (jev: JevClient) => T | undefined | PromiseLike<T | undefined>,
6527
7105
  /** Required. The behaviour the feature has without Jev. */
6528
7106
  fallback: () => T | PromiseLike<T>, options?: WithJevOptions) => Promise<T>;
6529
7107