@yaklabs-ai/plugin-sdk 0.15.1 → 0.15.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.
@@ -505,6 +505,7 @@ declare interface CustomAgentMessages {
505
505
  userInvoked: UserInvokedMessage;
506
506
  availabilityFacts: AvailabilityFactsMessage;
507
507
  midTurnCompactionOutcome: MidTurnCompactionOutcomeMessage;
508
+ runContinuationCarrier: RunContinuationCarrierMessage;
508
509
  subagentResult: SubagentResultMessage;
509
510
  backgroundTaskResult: BackgroundTaskResultMessage;
510
511
  }
@@ -1235,12 +1236,23 @@ declare interface KayAppCorpus {
1235
1236
  */
1236
1237
  readEntries(sessionId: string): AsyncIterable<TranscriptEntry>;
1237
1238
  /**
1238
- * Read one bounded physical JSONL page. The host resolves `sessionId` to its authoritative
1239
- * indexed path and validates the opaque cursor before opening it. When `throughEntryId` is
1240
- * supplied, the cursor stops at that entry's transaction line; a V4 line may carry later
1241
- * entries, which are returned for the caller to filter and are replayed on the next page.
1242
- * A page can hold no entries at all (a run of storage lines) while more follows; a record
1243
- * longer than the page is stepped over and counted in `oversizedRecords`.
1239
+ * Active-branch entries from the latest canonical human turn opener (send companions included)
1240
+ * through the anchor, oldest first. Mid-turn steers and machine wakes remain inside that window;
1241
+ * attachment-only openers and fresh card answers count. Missing sessions/anchors return [];
1242
+ * unsupported hosts may omit it.
1243
+ * Reads never fall back to materializing the full log.
1244
+ */
1245
+ readLatestHumanWindow?(sessionId: string, options?: {
1246
+ readonly throughEntryId?: string;
1247
+ }): Promise<readonly TranscriptEntry[]>;
1248
+ /**
1249
+ * Read one bounded page of a session's stored transcript. The host resolves `sessionId` to its
1250
+ * authoritative indexed path and validates the opaque cursor before reading. When
1251
+ * `throughEntryId` is supplied, the page ends at that entry and the cursor stays at the start of
1252
+ * the commit holding it: the commit's other entries are returned for the caller to filter, and
1253
+ * the next page replays that commit. A page can hold no entries at all (storage records with no
1254
+ * entry) while more follows; a record longer than the page is stepped over and counted in
1255
+ * `oversizedRecords`.
1244
1256
  */
1245
1257
  readEntryBatch?(sessionId: string, options?: {
1246
1258
  readonly cursor?: JsonValue_3;
@@ -1255,7 +1267,7 @@ declare interface KayAppCorpus {
1255
1267
  readSessionSourceMark(sessionId: string): Promise<KayAppCorpusSourceMark | undefined>;
1256
1268
  }
1257
1269
 
1258
- /** One bounded physical page from the host's incremental JSONL reader. */
1270
+ /** One bounded page from the host's stored transcript reader. */
1259
1271
  declare interface KayAppCorpusEntryBatch {
1260
1272
  readonly entries: readonly TranscriptEntry[];
1261
1273
  /** Opaque JSON cursor after the physical page; only the host may interpret it or open its path. */
@@ -1758,13 +1770,7 @@ declare interface MessageEntry extends EntryBase {
1758
1770
  /** TypeBox instantiation metrics */
1759
1771
  declare const Metrics: TMetrics;
1760
1772
 
1761
- /**
1762
- * A hidden kernel statement delivered before resuming a tool-requested compaction stop.
1763
- *
1764
- * Module-local, unlike every sibling above it: this message is never rendered and never matched
1765
- * by name outside this file, so exporting the string would only publish something no surface
1766
- * consumes. It earns an export the day one needs to recognise it.
1767
- */
1773
+ /** A hidden kernel statement delivered before resuming a tool-requested compaction stop. */
1768
1774
  declare const MID_TURN_COMPACTION_OUTCOME_CUSTOM_TYPE = "mid_turn_compaction_outcome";
1769
1775
 
1770
1776
  declare interface MidTurnCompactionOutcomeDetails {
@@ -2424,6 +2430,34 @@ declare function ReturnType_2<Type extends TSchema>(type: Type, options?: TSchem
2424
2430
  /** Creates a deferred ReturnType action. */
2425
2431
  declare function ReturnTypeDeferred<Type extends TSchema>(type: Type, options?: TSchemaOptions): TReturnTypeDeferred<Type>;
2426
2432
 
2433
+ /**
2434
+ * The hidden message a continued run rides as its admission ticket (a mid-turn compaction
2435
+ * resume, a run-recovery re-drive). The engine writes it; this package's placement rows keep it
2436
+ * out of the canonical transcript.
2437
+ */
2438
+ declare const RUN_CONTINUATION_CARRIER_CUSTOM_TYPE = "herd_run_continuation";
2439
+
2440
+ /**
2441
+ * What a {@link RUN_CONTINUATION_CARRIER_CUSTOM_TYPE} carrier records about the failed turns it
2442
+ * continues.
2443
+ */
2444
+ declare interface RunContinuationCarrierDetails {
2445
+ readonly provenance: {
2446
+ readonly source: "core";
2447
+ };
2448
+ /**
2449
+ * Visible text the failed turns since the previous carrier streamed before they died. Absent
2450
+ * when they showed none (thinking, an unexecuted tool call, or a thrown attempt): such a
2451
+ * carrier is plain.
2452
+ */
2453
+ readonly shownText?: string;
2454
+ }
2455
+
2456
+ declare type RunContinuationCarrierMessage = CustomMessage<RunContinuationCarrierDetails> & {
2457
+ readonly customType: typeof RUN_CONTINUATION_CARRIER_CUSTOM_TYPE;
2458
+ readonly display: false;
2459
+ };
2460
+
2427
2461
  /**
2428
2462
  * A durable runtime notice: the daemon telling the HUMAN, in the transcript,
2429
2463
  * that something it was going to do on their behalf did not happen — and why.
package/dist/kay-app.d.ts CHANGED
@@ -755,6 +755,7 @@ declare interface CustomAgentMessages {
755
755
  userInvoked: UserInvokedMessage;
756
756
  availabilityFacts: AvailabilityFactsMessage;
757
757
  midTurnCompactionOutcome: MidTurnCompactionOutcomeMessage;
758
+ runContinuationCarrier: RunContinuationCarrierMessage;
758
759
  subagentResult: SubagentResultMessage;
759
760
  backgroundTaskResult: BackgroundTaskResultMessage;
760
761
  }
@@ -921,6 +922,18 @@ declare interface DeferredHandle {
921
922
  data?: JsonValue_4;
922
923
  }
923
924
 
925
+ /**
926
+ * Register an ordinary workflow that polls connected accounts with independent JSON cursors.
927
+ * First polls initialize silently. Failed or skipped accounts retain their cursor; removed
928
+ * accounts are pruned. Publication finishes before replacement state is returned.
929
+ *
930
+ * Credential resolution and provider reads share a step so credentials are never step outputs.
931
+ * Poll callbacks must keep secrets out of their returned cursor, events, and summary. Resolution
932
+ * errors fail the run with a sanitized message; provider poll errors isolate the account.
933
+ * Key events at their source: a step can repeat before its result commits or after an engine update.
934
+ */
935
+ export declare function definePoller<Cursor extends JsonValue>(app: Pick<KayAppPluginApi, "workflows" | "auth" | "events">, localId: string, options: KayAppPollerOptions<Cursor>): void;
936
+
924
937
  /** Creates a Dependent type */
925
938
  declare function Dependent<If extends TSchema, Then extends TSchema, Else extends TSchema>(if_: If, then_: Then, else_: Else, options?: TSchemaOptions): TDependent<If, Then, Else>;
926
939
 
@@ -1397,6 +1410,14 @@ declare const Factor: (input: string) => [unknown, string] | [];
1397
1410
 
1398
1411
  declare function FactorMapping(input: [unknown, unknown, unknown, unknown, unknown]): unknown;
1399
1412
 
1413
+ /**
1414
+ * The `ErrorOptions` for a workflow that fails BECAUSE this run failed: the run's retained
1415
+ * failure ref as the error's `cause`, so the host reports that failure, with the same identity
1416
+ * the session kept, instead of guessing from whichever run settled last. Empty when the run kept
1417
+ * no failure: the throw is then the workflow's own.
1418
+ */
1419
+ export declare function failedRunCause(outcome: KayAppSessionRunOutcome): ErrorOptions;
1420
+
1400
1421
  declare type ForecastInterval = "step" | "minute" | "hour" | "day" | "week" | "month" | "quarter" | "year";
1401
1422
 
1402
1423
  /** Creates a Function type. */
@@ -2468,11 +2489,25 @@ export declare interface KayAppAutomationBinding {
2468
2489
  readonly nextDueAtMs?: number;
2469
2490
  readonly expiresAtMs?: number;
2470
2491
  readonly maxRuns?: number;
2492
+ readonly concurrency?: KayAppAutomationConcurrency;
2471
2493
  readonly runCount: number;
2472
2494
  /** Why a script binding's last tick failed and paused it, when it did. */
2473
2495
  readonly scriptLastError?: string;
2474
2496
  }
2475
2497
 
2498
+ /**
2499
+ * How many of an automation's runs may be in progress at once. Absent means `sequential`: one at
2500
+ * a time, in order. `parallel` runs up to `limit` at once (1 to 32, default 4), for an automation
2501
+ * whose runs each handle their own event and can safely overlap, such as replying to separate
2502
+ * emails.
2503
+ */
2504
+ export declare type KayAppAutomationConcurrency = {
2505
+ readonly mode: "sequential";
2506
+ } | {
2507
+ readonly mode: "parallel";
2508
+ readonly limit?: number;
2509
+ };
2510
+
2476
2511
  export declare type KayAppAutomationCondition = KayAppAutomationPluginEventCondition | Extract<KayAppAutomationConditionInput, {
2477
2512
  readonly kind: "time";
2478
2513
  }> | KayAppAutomationUriChangeCondition | {
@@ -2709,7 +2744,7 @@ export declare interface KayAppAutomationRun {
2709
2744
  readonly id: string;
2710
2745
  readonly bindingId: string;
2711
2746
  readonly logicalKey: string;
2712
- readonly status: "claimed" | "queued" | "running" | "succeeded" | "failed" | "skipped" | "abandoned";
2747
+ readonly status: "claimed" | "queued" | "running" | "succeeded" | "failed" | "skipped";
2713
2748
  readonly match: KayAppAutomationMatch;
2714
2749
  readonly generation: string;
2715
2750
  readonly claimedAtMs: number;
@@ -2783,16 +2818,17 @@ export declare type KayAppAutomationRunOutcome = {
2783
2818
  } | {
2784
2819
  readonly status: "failed";
2785
2820
  readonly summary?: KayAppRunSummary | undefined;
2786
- readonly reason: "executor_failed" | "permission_denied" | "surface_unavailable" | "target_gone";
2821
+ /**
2822
+ * Which part of the lane refused or failed. Absent on a run an earlier build recorded with
2823
+ * a reason this build no longer names; nothing is reconstructed.
2824
+ */
2825
+ readonly reason?: "executor_failed" | "permission_denied" | "surface_unavailable" | "owner_missing" | "target_missing" | "declaration_gone" | undefined;
2787
2826
  readonly message?: string | undefined;
2788
2827
  /** How many tries the run's effect took, when more than one. */
2789
2828
  readonly tries?: number | undefined;
2790
2829
  } | {
2791
2830
  readonly status: "skipped";
2792
- readonly reason: "already_running" | "binding_inactive" | "circuit_breaker" | "concurrency_capped" | "guard_not_satisfied" | "missed_window" | "timer_cancelled";
2793
- } | {
2794
- readonly status: "abandoned";
2795
- readonly reason: "daemon_restart";
2831
+ readonly reason: "already_running" | "binding_inactive" | "guard_not_satisfied" | "missed_window" | "timer_cancelled";
2796
2832
  };
2797
2833
 
2798
2834
  export declare interface KayAppAutomations {
@@ -2831,6 +2867,7 @@ export declare interface KayAppAutomations {
2831
2867
  readonly catchUpGraceMs?: number;
2832
2868
  readonly expiresAtMs?: number;
2833
2869
  readonly maxRuns?: number;
2870
+ readonly concurrency?: KayAppAutomationConcurrency;
2834
2871
  }, ctx: KayAppAutomationContext): Promise<{
2835
2872
  readonly kind: "created";
2836
2873
  readonly binding: KayAppAutomationBinding;
@@ -3115,12 +3152,23 @@ export declare interface KayAppCorpus {
3115
3152
  */
3116
3153
  readEntries(sessionId: string): AsyncIterable<TranscriptEntry>;
3117
3154
  /**
3118
- * Read one bounded physical JSONL page. The host resolves `sessionId` to its authoritative
3119
- * indexed path and validates the opaque cursor before opening it. When `throughEntryId` is
3120
- * supplied, the cursor stops at that entry's transaction line; a V4 line may carry later
3121
- * entries, which are returned for the caller to filter and are replayed on the next page.
3122
- * A page can hold no entries at all (a run of storage lines) while more follows; a record
3123
- * longer than the page is stepped over and counted in `oversizedRecords`.
3155
+ * Active-branch entries from the latest canonical human turn opener (send companions included)
3156
+ * through the anchor, oldest first. Mid-turn steers and machine wakes remain inside that window;
3157
+ * attachment-only openers and fresh card answers count. Missing sessions/anchors return [];
3158
+ * unsupported hosts may omit it.
3159
+ * Reads never fall back to materializing the full log.
3160
+ */
3161
+ readLatestHumanWindow?(sessionId: string, options?: {
3162
+ readonly throughEntryId?: string;
3163
+ }): Promise<readonly TranscriptEntry[]>;
3164
+ /**
3165
+ * Read one bounded page of a session's stored transcript. The host resolves `sessionId` to its
3166
+ * authoritative indexed path and validates the opaque cursor before reading. When
3167
+ * `throughEntryId` is supplied, the page ends at that entry and the cursor stays at the start of
3168
+ * the commit holding it: the commit's other entries are returned for the caller to filter, and
3169
+ * the next page replays that commit. A page can hold no entries at all (storage records with no
3170
+ * entry) while more follows; a record longer than the page is stepped over and counted in
3171
+ * `oversizedRecords`.
3124
3172
  */
3125
3173
  readEntryBatch?(sessionId: string, options?: {
3126
3174
  readonly cursor?: JsonValue;
@@ -3135,7 +3183,7 @@ export declare interface KayAppCorpus {
3135
3183
  readSessionSourceMark(sessionId: string): Promise<KayAppCorpusSourceMark | undefined>;
3136
3184
  }
3137
3185
 
3138
- /** One bounded physical page from the host's incremental JSONL reader. */
3186
+ /** One bounded page from the host's stored transcript reader. */
3139
3187
  export declare interface KayAppCorpusEntryBatch {
3140
3188
  readonly entries: readonly TranscriptEntry[];
3141
3189
  /** Opaque JSON cursor after the physical page; only the host may interpret it or open its path. */
@@ -3785,11 +3833,9 @@ export declare interface KayAppPaths {
3785
3833
  *
3786
3834
  * Unlike `telemetryRoot`, this can be granted yet absent: compositions that spawn no log lane
3787
3835
  * (test and eval hosts) hand the daemon no logs directory, and the field is then omitted rather
3788
- * than guessed. Event content redaction differs by lane and configuration — the daemon lane
3789
- * omits tool content outright; the Desktop lane captures it when `observability.contentCapture`
3790
- * is on (off by default in packaged builds, on by default unpackaged — a packaged user CAN
3791
- * enable it, so never assume rows from a packaged install are content-free). Absent `content`
3792
- * on a row is the normal case.
3836
+ * than guessed. Desktop and daemon logs contain the same diagnostic facts exported to
3837
+ * PostHog; call content is never recorded. Historical files can contain private content
3838
+ * from older builds, and diagnostic errors/stacks can contain file paths.
3793
3839
  */
3794
3840
  readonly logsRoot?: string;
3795
3841
  }
@@ -3926,7 +3972,7 @@ export declare interface KayAppPluginApi {
3926
3972
  */
3927
3973
  readonly sessionEvents: KayAppSessionEvents;
3928
3974
  /**
3929
- * Grant-gated time-triggered workflow registration. Present for a plugin the host has a workflow
3975
+ * Grant-gated workflow registration, started on a time schedule or the plugin's own events. Present for a plugin the host has a workflow
3930
3976
  * namespace for; `undefined` otherwise. The first `define` asks for the `workflows.define` claim
3931
3977
  * in the user's grant ledger — no manifest request and no source-class gate — and it is decided
3932
3978
  * once `activate()` resolves: an ungranted plugin does not start until the user allows it. A
@@ -4039,6 +4085,36 @@ export declare interface KayAppPluginEvents {
4039
4085
  publish(localId: string, input: PluginEventPublishInput): void;
4040
4086
  }
4041
4087
 
4088
+ export declare interface KayAppPollerEvent {
4089
+ readonly localId: string;
4090
+ readonly input: PluginEventPublishInput;
4091
+ }
4092
+
4093
+ export declare interface KayAppPollerOptions<Cursor extends JsonValue> {
4094
+ readonly name: string;
4095
+ readonly description: string;
4096
+ /** Interval in milliseconds; the workflow engine enforces its scheduling floor. */
4097
+ readonly every: number;
4098
+ readonly serviceId: string;
4099
+ readonly schemeId?: string;
4100
+ readonly resolveCredential: (account: KayAppAccountSummary, runId: string) => Promise<KayAppBackgroundCredentialResult>;
4101
+ /** Cursor, events, and summary must contain no credentials or other secrets. */
4102
+ readonly poll: (input: {
4103
+ readonly account: KayAppAccountSummary;
4104
+ readonly cursor: Cursor | undefined;
4105
+ readonly credential: Extract<KayAppBackgroundCredentialResult, {
4106
+ readonly status: "resolved";
4107
+ }>;
4108
+ readonly runId: string;
4109
+ }) => Promise<KayAppPollResult<Cursor>>;
4110
+ }
4111
+
4112
+ export declare interface KayAppPollResult<Cursor extends JsonValue> {
4113
+ readonly cursor: Cursor;
4114
+ readonly events?: readonly KayAppPollerEvent[];
4115
+ readonly summary?: string;
4116
+ }
4117
+
4042
4118
  export declare type KayAppProcessingSpeed = "standard" | "fast";
4043
4119
 
4044
4120
  /**
@@ -4482,6 +4558,17 @@ export declare type KayAppSessionRunCompletion = {
4482
4558
  /** Provider-neutral recorded classification; an unclassified failure omits the field. */
4483
4559
  export declare type KayAppSessionRunFailureReason = Exclude<RunFailureReason, "unknown">;
4484
4560
 
4561
+ /**
4562
+ * The identity of a failed run's retained failure: the same ref the runtime keeps on the
4563
+ * session and the automation run. A workflow that fails BECAUSE this run failed passes it as
4564
+ * its error's `cause` (`{ cause: { failureRef } }`), and the host reports that failure, not a
4565
+ * guess from whichever run settled last.
4566
+ */
4567
+ export declare interface KayAppSessionRunFailureRef {
4568
+ readonly authority: string;
4569
+ readonly id: string;
4570
+ }
4571
+
4485
4572
  /** One host-tool name in a one-shot system run's explicit ceiling. */
4486
4573
  export declare type KayAppSessionRunHostToolName = string;
4487
4574
 
@@ -4568,6 +4655,8 @@ export declare interface KayAppSessionRunInput {
4568
4655
 
4569
4656
  export declare type KayAppSessionRunOutcome = (KayAppSessionRunBase & {
4570
4657
  readonly state: "failed";
4658
+ /** The retained failure's identity, when the runtime kept one for this run. */
4659
+ readonly failureRef?: KayAppSessionRunFailureRef | undefined;
4571
4660
  /** Present when the runtime could classify the failure. */
4572
4661
  readonly failureReason?: KayAppSessionRunFailureReason | undefined;
4573
4662
  /** Bounded provider-suggested delay before retrying this terminal failure. */
@@ -6009,14 +6098,13 @@ export declare interface KayAppWhiteboardTypes {
6009
6098
  * - **Do not hold state in module scope and expect it to survive.** A recovery may happen in a
6010
6099
  * different process. Anything you need later belongs in a step's return value.
6011
6100
  */
6012
- export declare interface KayAppWorkflowContext {
6101
+ export declare interface KayAppWorkflowContext<Trigger extends KayAppWorkflowTrigger = KayAppWorkflowTimeTrigger> {
6013
6102
  /** State from the last successful run; undefined until a run saves it. */
6014
6103
  readonly state: JsonValue | undefined;
6015
6104
  readonly automationId: string;
6016
6105
  readonly runId: string;
6017
- readonly match: Extract<KayAppAutomationMatch, {
6018
- readonly kind: "time" | "manual";
6019
- }>;
6106
+ /** What started this run; see {@link KayAppWorkflowMatch}. */
6107
+ readonly match: KayAppWorkflowMatch<Trigger>;
6020
6108
  /**
6021
6109
  * Record a step's result for replay.
6022
6110
  *
@@ -6074,17 +6162,23 @@ export declare interface KayAppWorkflowContext {
6074
6162
  runAgent(agent: KayAppAgentDefinitionRef, input: Omit<KayAppSessionRunInput, "agent">): Promise<KayAppSessionRunOutcome>;
6075
6163
  }
6076
6164
 
6077
- export declare interface KayAppWorkflowDefinition {
6165
+ export declare interface KayAppWorkflowDefinition<Trigger extends KayAppWorkflowTrigger = KayAppWorkflowTimeTrigger> {
6078
6166
  readonly name: string;
6079
6167
  /** Plain-text purpose, at most 280 characters. */
6080
6168
  readonly description: string;
6081
6169
  readonly instructions?: readonly KayAppWorkflowInstruction[];
6082
6170
  readonly perRunNote?: string;
6083
- readonly trigger: Extract<KayAppAutomationConditionInput, {
6084
- readonly kind: "time";
6085
- }>;
6086
- readonly run: (context: KayAppWorkflowContext) => Promise<{
6087
- /** Replacement JSON state, at most 64 KiB; omission keeps the previous value. */
6171
+ readonly trigger: Trigger;
6172
+ /**
6173
+ * How many runs may be in progress at once. Absent means `sequential`. A `parallel` workflow
6174
+ * suits an event trigger whose runs each handle their own event; it cannot return `state`.
6175
+ */
6176
+ readonly concurrency?: KayAppAutomationConcurrency;
6177
+ readonly run: (context: KayAppWorkflowContext<Trigger>) => Promise<{
6178
+ /**
6179
+ * Replacement JSON state, at most 64 KiB; omission keeps the previous value. Only a
6180
+ * sequential workflow may return it: a `parallel` run that does fails.
6181
+ */
6088
6182
  readonly state?: JsonValue | undefined;
6089
6183
  readonly summary: KayAppRunSummary;
6090
6184
  readonly produced?: KayAppRunProduced;
@@ -6092,6 +6186,16 @@ export declare interface KayAppWorkflowDefinition {
6092
6186
  }>;
6093
6187
  }
6094
6188
 
6189
+ /**
6190
+ * The event that started a run, as the publisher sent it. The publishing session is withheld.
6191
+ * This is the run's private input, so it carries `payload`, `related` and `key`, which the
6192
+ * public run history's event identity leaves out.
6193
+ */
6194
+ export declare type KayAppWorkflowEvent = Readonly<Omit<PluginEventEnvelope, "related" | "source">> & {
6195
+ readonly related?: Readonly<Record<string, string | readonly string[]>> | undefined;
6196
+ readonly source: Readonly<Omit<PluginEventEnvelope["source"], "sessionId">>;
6197
+ };
6198
+
6095
6199
  /** Fail a workflow while retaining its own explanation beside this attempt. */
6096
6200
  export declare class KayAppWorkflowFailure extends Error {
6097
6201
  readonly summary: KayAppRunSummary;
@@ -6123,11 +6227,43 @@ export declare type KayAppWorkflowInstruction = {
6123
6227
  readonly ref: KayAppAutomationScriptRef;
6124
6228
  };
6125
6229
 
6230
+ /**
6231
+ * What started a run, by trigger: a time workflow sees `time`, an event workflow sees
6232
+ * `plugin-event`, and either sees `manual` for Run now and retries. A retry, even of an event run,
6233
+ * arrives as `manual` without the event.
6234
+ */
6235
+ export declare type KayAppWorkflowMatch<Trigger extends KayAppWorkflowTrigger = KayAppWorkflowTimeTrigger> = Extract<KayAppAutomationMatch, {
6236
+ readonly kind: "manual";
6237
+ }> | (Trigger extends {
6238
+ readonly kind: "plugin-event";
6239
+ } ? {
6240
+ readonly kind: "plugin-event";
6241
+ readonly event: KayAppWorkflowEvent;
6242
+ } : Extract<KayAppAutomationMatch, {
6243
+ readonly kind: "time";
6244
+ }>);
6245
+
6126
6246
  export declare interface KayAppWorkflows {
6127
- define(localId: string, definition: KayAppWorkflowDefinition): void;
6247
+ define<Trigger extends KayAppWorkflowTrigger>(localId: string, definition: KayAppWorkflowDefinition<Trigger>): void;
6128
6248
  inspect(localId: string, options?: KayAppWorkflowInspectOptions): Promise<KayAppWorkflowInspection>;
6129
6249
  }
6130
6250
 
6251
+ export declare type KayAppWorkflowTimeTrigger = Extract<KayAppAutomationConditionInput, {
6252
+ readonly kind: "time";
6253
+ }>;
6254
+
6255
+ /**
6256
+ * What starts a workflow: a time schedule, or one or more of this plugin's own declared events.
6257
+ *
6258
+ * An event trigger names full event types (`google.gmail.message.received`) and takes the same
6259
+ * filters as a `plugin-event` automation. Each matching event starts one run. Only events this
6260
+ * plugin declares are accepted; another plugin's events are refused at `define`.
6261
+ *
6262
+ * A run is not started by an event that one of this workflow's own runs published, as long as the
6263
+ * publish names the run: pass `source: { runId: ctx.runId }` (the Poller helper does).
6264
+ */
6265
+ export declare type KayAppWorkflowTrigger = KayAppWorkflowTimeTrigger | KayAppAutomationPluginEventCondition;
6266
+
6131
6267
  /**
6132
6268
  * Read/arrange access to the live desktop workspace (tabs, panes, the shell chrome). Always
6133
6269
  * present. `snapshot` is ungated; `execute` is checked per call against the `workspace.command`
@@ -6534,13 +6670,7 @@ declare interface MessageEntry extends EntryBase {
6534
6670
  /** TypeBox instantiation metrics */
6535
6671
  declare const Metrics: TMetrics;
6536
6672
 
6537
- /**
6538
- * A hidden kernel statement delivered before resuming a tool-requested compaction stop.
6539
- *
6540
- * Module-local, unlike every sibling above it: this message is never rendered and never matched
6541
- * by name outside this file, so exporting the string would only publish something no surface
6542
- * consumes. It earns an export the day one needs to recognise it.
6543
- */
6673
+ /** A hidden kernel statement delivered before resuming a tool-requested compaction stop. */
6544
6674
  declare const MID_TURN_COMPACTION_OUTCOME_CUSTOM_TYPE = "mid_turn_compaction_outcome";
6545
6675
 
6546
6676
  /**
@@ -7705,9 +7835,37 @@ declare function ReturnType_2<Type extends TSchema>(type: Type, options?: TSchem
7705
7835
  /** Creates a deferred ReturnType action. */
7706
7836
  declare function ReturnTypeDeferred<Type extends TSchema>(type: Type, options?: TSchemaOptions): TReturnTypeDeferred<Type>;
7707
7837
 
7838
+ /**
7839
+ * The hidden message a continued run rides as its admission ticket (a mid-turn compaction
7840
+ * resume, a run-recovery re-drive). The engine writes it; this package's placement rows keep it
7841
+ * out of the canonical transcript.
7842
+ */
7843
+ declare const RUN_CONTINUATION_CARRIER_CUSTOM_TYPE = "herd_run_continuation";
7844
+
7708
7845
  /** Observed cause of a failed request or interrupted run. */
7709
7846
  declare const RUN_FAILURE_REASONS: readonly ["auth", "cancelled", "content_blocked", "context_overflow", "invalid_request", "model_disabled", "model_unavailable", "network", "organization_unavailable", "overloaded", "quota_exhausted", "rate_limit", "runtime_interrupted", "safeguard_block", "seat_unpaid", "server_error", "sign_in_required", "stream_interrupted", "timeout", "unknown"];
7710
7847
 
7848
+ /**
7849
+ * What a {@link RUN_CONTINUATION_CARRIER_CUSTOM_TYPE} carrier records about the failed turns it
7850
+ * continues.
7851
+ */
7852
+ declare interface RunContinuationCarrierDetails {
7853
+ readonly provenance: {
7854
+ readonly source: "core";
7855
+ };
7856
+ /**
7857
+ * Visible text the failed turns since the previous carrier streamed before they died. Absent
7858
+ * when they showed none (thinking, an unexecuted tool call, or a thrown attempt): such a
7859
+ * carrier is plain.
7860
+ */
7861
+ readonly shownText?: string;
7862
+ }
7863
+
7864
+ declare type RunContinuationCarrierMessage = CustomMessage<RunContinuationCarrierDetails> & {
7865
+ readonly customType: typeof RUN_CONTINUATION_CARRIER_CUSTOM_TYPE;
7866
+ readonly display: false;
7867
+ };
7868
+
7711
7869
  declare type RunFailureReason = (typeof RUN_FAILURE_REASONS)[number];
7712
7870
 
7713
7871
  /**
package/dist/kay-app.js CHANGED
@@ -449,6 +449,154 @@ var KAY_APP_AUTOMATION_CONDITION_KINDS = [
449
449
  "delayed-occurrence"
450
450
  ];
451
451
 
452
+ // packages/plugin-sdk/dist/kay-app/poller.js
453
+ function accountCursors(state) {
454
+ if (state === void 0)
455
+ return [];
456
+ if (state === null || typeof state !== "object" || Array.isArray(state) || !Array.isArray(state.accounts)) {
457
+ throw new Error("Invalid Poller state");
458
+ }
459
+ return state.accounts.map((entry) => {
460
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry) || typeof entry.schemeId !== "string" || typeof entry.accountId !== "string" || !("cursor" in entry)) {
461
+ throw new Error("Invalid Poller account cursor");
462
+ }
463
+ return {
464
+ schemeId: entry.schemeId,
465
+ accountId: entry.accountId,
466
+ cursor: entry.cursor
467
+ };
468
+ });
469
+ }
470
+ function ordinal(left, right) {
471
+ return left < right ? -1 : left > right ? 1 : 0;
472
+ }
473
+ function plainText(value, max) {
474
+ let text = "";
475
+ for (const character of value) {
476
+ const code = character.charCodeAt(0);
477
+ const printable = code < 32 || code === 127 ? " " : character;
478
+ if (text.length + printable.length > max)
479
+ break;
480
+ text += printable;
481
+ }
482
+ return text;
483
+ }
484
+ function definePoller(app, localId, options) {
485
+ const { workflows, auth, events } = app;
486
+ if (!workflows)
487
+ throw new Error("Poller requires workflows");
488
+ if (!Number.isSafeInteger(options.every) || options.every <= 0) {
489
+ throw new TypeError("Poller interval must be a positive integer in milliseconds");
490
+ }
491
+ workflows.define(localId, {
492
+ name: options.name,
493
+ description: options.description,
494
+ trigger: {
495
+ kind: "time",
496
+ schedule: { kind: "every", intervalMs: options.every, anchorAtMs: 0 }
497
+ },
498
+ async run(ctx) {
499
+ if (!auth)
500
+ throw new Error("Poller requires account listing");
501
+ const previous = accountCursors(ctx.state);
502
+ const accounts = await ctx.runStep(async () => {
503
+ const listed = await auth.listAccounts({
504
+ serviceId: options.serviceId,
505
+ ...options.schemeId === void 0 ? {} : { schemeId: options.schemeId }
506
+ });
507
+ return [...listed].sort((a, b) => ordinal(a.schemeId, b.schemeId) || ordinal(a.accountId, b.accountId));
508
+ }, { name: "list-poller-accounts" });
509
+ const next = [];
510
+ const details = [];
511
+ let published = 0;
512
+ let initialized = 0;
513
+ let skipped = 0;
514
+ let failed = 0;
515
+ for (const account of accounts) {
516
+ const saved = previous.find((entry) => entry.schemeId === account.schemeId && entry.accountId === account.accountId);
517
+ const outcome = await ctx.runStep(async () => {
518
+ if (account.status === "needs_reauth" || account.status === "refresh_failed" || account.status === "revoked") {
519
+ return {
520
+ status: "skipped",
521
+ summary: `Sign-in required (${account.status})`
522
+ };
523
+ }
524
+ let credential;
525
+ try {
526
+ credential = await options.resolveCredential(account, ctx.runId);
527
+ } catch {
528
+ throw new Error("Poller credential resolution failed");
529
+ }
530
+ if (credential.status !== "resolved") {
531
+ return {
532
+ status: "skipped",
533
+ summary: credential.status === "requires-auth" ? "Sign-in or required scope missing" : "Credential missing"
534
+ };
535
+ }
536
+ try {
537
+ const result = await options.poll({
538
+ account,
539
+ cursor: structuredClone(saved?.cursor),
540
+ credential,
541
+ runId: ctx.runId
542
+ });
543
+ return {
544
+ status: "polled",
545
+ result: {
546
+ cursor: result.cursor,
547
+ ...saved === void 0 || result.events === void 0 ? {} : { events: result.events },
548
+ ...result.summary === void 0 ? {} : { summary: plainText(result.summary, 600) }
549
+ }
550
+ };
551
+ } catch {
552
+ return {
553
+ status: "failed",
554
+ summary: "Provider poll failed; cursor retained"
555
+ };
556
+ }
557
+ }, { name: "poll-account" });
558
+ if (outcome.status !== "polled") {
559
+ if (saved !== void 0)
560
+ next.push(saved);
561
+ if (outcome.status === "skipped")
562
+ skipped++;
563
+ else
564
+ failed++;
565
+ details.push(`${account.schemeId}/${account.accountId}: ${outcome.summary}`);
566
+ continue;
567
+ }
568
+ await ctx.runStep(async () => {
569
+ for (const event of outcome.result.events ?? []) {
570
+ events.publish(event.localId, {
571
+ ...event.input,
572
+ source: { poller: localId, runId: ctx.runId }
573
+ });
574
+ }
575
+ return null;
576
+ }, { name: "publish-poller-events" });
577
+ published += outcome.result.events?.length ?? 0;
578
+ if (saved === void 0)
579
+ initialized++;
580
+ next.push({
581
+ schemeId: account.schemeId,
582
+ accountId: account.accountId,
583
+ cursor: outcome.result.cursor
584
+ });
585
+ if (outcome.result.summary)
586
+ details.push(`${account.schemeId}/${account.accountId}: ${outcome.result.summary}`);
587
+ }
588
+ return {
589
+ state: { accounts: next },
590
+ summary: {
591
+ headline: plainText(`${published} events; ${initialized} initialized; ${skipped} skipped; ${failed} failed`, 100),
592
+ ...details.length === 0 ? {} : { details: plainText(details.join("; "), 600) },
593
+ author: "automation"
594
+ }
595
+ };
596
+ }
597
+ });
598
+ }
599
+
452
600
  // packages/plugin-sdk/dist/kay-app/skills.js
453
601
  function createUnavailableSkills(message) {
454
602
  const unavailable = {
@@ -506,6 +654,9 @@ function createUnavailableUsage(message) {
506
654
  }
507
655
 
508
656
  // packages/plugin-sdk/dist/kay-app/workflows.js
657
+ function failedRunCause(outcome) {
658
+ return outcome.kind === "ran" && outcome.state === "failed" && outcome.failureRef !== void 0 ? { cause: { failureRef: outcome.failureRef } } : {};
659
+ }
509
660
  var KayAppWorkflowFailure = class extends Error {
510
661
  summary;
511
662
  constructor(summary, options) {
@@ -538,6 +689,8 @@ export {
538
689
  createUnavailableSkills,
539
690
  createUnavailableTools,
540
691
  createUnavailableUsage,
692
+ definePoller,
693
+ failedRunCause,
541
694
  invalidObservation,
542
695
  isRetryable,
543
696
  parseLineSelector,