@yaklabs-ai/plugin-sdk 0.15.1 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,
@@ -114,14 +114,13 @@ declare interface TranscriptSourceEntryLike extends TranscriptTreeEntryLike {
114
114
 
115
115
  /**
116
116
  * A session entry as {@link branchEntryIds} reads it: the fields above plus the
117
- * tree links the walk follows to find the active branch. No timestamp: the walk
118
- * never reads one, and a live v2 entry carries epoch milliseconds where a raw
119
- * v3 log carries an ISO string, so requiring either shape here would force one
117
+ * parent link the walk follows to find the active branch. No timestamp: the walk
118
+ * never reads one, and callers hold entries whose timestamp is epoch
119
+ * milliseconds or an ISO string, so requiring either shape here would force one
120
120
  * class of caller to convert entries it only wants walked.
121
121
  */
122
122
  declare interface TranscriptTreeEntryLike extends TranscriptEntryLike {
123
123
  readonly parentId?: string | null;
124
- readonly targetId?: string | null;
125
124
  }
126
125
 
127
126
  export { }
@@ -14,7 +14,7 @@ function branchEntryIds(entries) {
14
14
  return EMPTY_BRANCH_IDS;
15
15
  const byId = new Map(entries.map((entry) => [entry.id, entry]));
16
16
  const onBranch = /* @__PURE__ */ new Set();
17
- let cursor = last.type === "leaf" ? last.targetId ?? null : last.id;
17
+ let cursor = last.id;
18
18
  while (cursor !== null && !onBranch.has(cursor)) {
19
19
  onBranch.add(cursor);
20
20
  cursor = byId.get(cursor)?.parentId ?? null;
@@ -3,8 +3,8 @@ import { z } from 'zod';
3
3
  export declare const ATTACHMENTS_CUSTOM_TYPE = "attachments";
4
4
 
5
5
  /**
6
- * The ids on a session's active branch: the leaf chain walked parent-ward from
7
- * the tip, which a trailing `leaf` marker moves. Empty for an empty log.
6
+ * The ids on a session's active branch: the parent chain walked from the tip,
7
+ * the last entry. Empty for an empty log.
8
8
  *
9
9
  * One walk shared by every reader of "is this entry still live", so a rewind
10
10
  * means the same thing to every projection that calls it. Self-guarding
@@ -106,14 +106,13 @@ export declare interface TranscriptSourceEntryLike extends TranscriptTreeEntryLi
106
106
 
107
107
  /**
108
108
  * A session entry as {@link branchEntryIds} reads it: the fields above plus the
109
- * tree links the walk follows to find the active branch. No timestamp: the walk
110
- * never reads one, and a live v2 entry carries epoch milliseconds where a raw
111
- * v3 log carries an ISO string, so requiring either shape here would force one
109
+ * parent link the walk follows to find the active branch. No timestamp: the walk
110
+ * never reads one, and callers hold entries whose timestamp is epoch
111
+ * milliseconds or an ISO string, so requiring either shape here would force one
112
112
  * class of caller to convert entries it only wants walked.
113
113
  */
114
114
  declare interface TranscriptTreeEntryLike extends TranscriptEntryLike {
115
115
  readonly parentId?: string | null;
116
- readonly targetId?: string | null;
117
116
  }
118
117
 
119
118
  /**
@@ -27,7 +27,7 @@ function branchEntryIds(entries) {
27
27
  return EMPTY_BRANCH_IDS;
28
28
  const byId = new Map(entries.map((entry) => [entry.id, entry]));
29
29
  const onBranch = /* @__PURE__ */ new Set();
30
- let cursor = last.type === "leaf" ? last.targetId ?? null : last.id;
30
+ let cursor = last.id;
31
31
  while (cursor !== null && !onBranch.has(cursor)) {
32
32
  onBranch.add(cursor);
33
33
  cursor = byId.get(cursor)?.parentId ?? null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaklabs-ai/plugin-sdk",
3
- "version": "0.15.1",
3
+ "version": "0.15.3",
4
4
  "description": "The Kay plugin SDK — types and helpers for authoring a Kay directory plugin.",
5
5
  "author": "YakLabs",
6
6
  "type": "module",
@@ -45,6 +45,10 @@
45
45
  "types": "./dist/transcript.d.ts",
46
46
  "default": "./dist/transcript.js"
47
47
  },
48
+ "./canonical-transcript": {
49
+ "types": "./dist/canonical-transcript.d.ts",
50
+ "default": "./dist/canonical-transcript.js"
51
+ },
48
52
  "./time": {
49
53
  "types": "./dist/time.d.ts",
50
54
  "default": "./dist/time.js"