@yaklabs-ai/plugin-sdk 0.15.3 → 0.27.0

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.
@@ -14,10 +14,12 @@ var BACKGROUND_TASK_RESULT_CUSTOM_TYPE = "background_task_result";
14
14
 
15
15
  // packages/herd-transcript/dist/run-failure-reason.js
16
16
  var RUN_FAILURE_REASONS = [
17
+ "account_unreachable",
17
18
  "auth",
18
19
  "cancelled",
19
20
  "content_blocked",
20
21
  "context_overflow",
22
+ "final_output_missing",
21
23
  "invalid_request",
22
24
  "model_disabled",
23
25
  "model_unavailable",
@@ -402,15 +404,16 @@ var HerdSessionProjection = z4.discriminatedUnion("type", [
402
404
  z4.strictObject({
403
405
  type: z4.literal("herd.custom.entry.appended"),
404
406
  customType: z4.string().min(1),
405
- data: z4.json()
407
+ data: z4.json(),
408
+ entryId: z4.string().min(1).optional()
406
409
  }),
407
410
  z4.strictObject({
408
411
  type: z4.literal("herd.context.window.updated"),
409
412
  snapshot: HerdContextWindowSnapshot,
410
413
  /**
411
- * Why this snapshot was taken. `provider_request` — emitted synchronously
414
+ * Why this snapshot was taken. `provider_request` - emitted synchronously
412
415
  * from the model-boundary context hook (every LLM request boundary);
413
- * `refresh` — emitted on all other paths (post-compaction rebuild, model
416
+ * `refresh` - emitted on all other paths (post-compaction rebuild, model
414
417
  * change, post-run settlement). Absent on legacy stored projections.
415
418
  */
416
419
  cause: z4.enum(["provider_request", "refresh"]).optional(),
@@ -419,7 +422,7 @@ var HerdSessionProjection = z4.discriminatedUnion("type", [
419
422
  * projection whose pass actually elided something. Absent means the pass was a no-op for
420
423
  * that request, never "unknown". `reclaimedTokens` is CARRIED (re-counted on every later
421
424
  * request the elision keeps content off the wire), and `firstRequestAfterBoundary` is the cold/warm
422
- * discriminator any pricing MUST split on — see `ContextElisionStats` in herd's
425
+ * discriminator any pricing MUST split on - see `ContextElisionStats` in herd's
423
426
  * context-projection module for the full read rules.
424
427
  */
425
428
  elision: z4.strictObject({
@@ -464,7 +467,7 @@ function finalOutputCaptureFromDetails(toolCallId, details) {
464
467
  toolCallId,
465
468
  ...typeof value.terminatesRun === "boolean" ? { terminatesRun: value.terminatesRun } : {},
466
469
  // Legacy transcripts carry the duplicated reply prose; new entries do
467
- // not. Read it only when it is actually a string — durable data.
470
+ // not. Read it only when it is actually a string - durable data.
468
471
  ...typeof value.message === "string" ? { message: value.message } : {},
469
472
  result: value.result,
470
473
  // Re-checked on the way out of durable storage, not trusted from it: a
@@ -540,6 +543,11 @@ function isKernelMessageRole(role) {
540
543
  return Object.hasOwn(KERNEL_MESSAGE_ROLES, role);
541
544
  }
542
545
 
546
+ // packages/herd-transcript/dist/is-object.js
547
+ function isObject(value) {
548
+ return typeof value === "object" && value !== null && !Array.isArray(value);
549
+ }
550
+
543
551
  // packages/herd-transcript/dist/run-failure-classifier.js
544
552
  var MAX_FAILURE_TEXT_CHARS = 2e3;
545
553
  function boundedFailureText(text) {
@@ -617,13 +625,6 @@ function parsePresentationAnchor(value) {
617
625
 
618
626
  // packages/herd-transcript/dist/tool-call-failure.js
619
627
  import { z as z5 } from "zod";
620
-
621
- // packages/herd-transcript/dist/is-object.js
622
- function isObject(value) {
623
- return typeof value === "object" && value !== null && !Array.isArray(value);
624
- }
625
-
626
- // packages/herd-transcript/dist/tool-call-failure.js
627
628
  var TOOL_CALL_FAILURE_DETAILS_KEY = "toolCallFailure";
628
629
  var TOOL_CALL_FAILURE_DOMAIN = "tool-call";
629
630
  var TOOL_CALL_FAILURE_CATEGORIES = [
@@ -636,6 +637,7 @@ var TOOL_CALL_FAILURE_CATEGORIES = [
636
637
  "timeout",
637
638
  "unavailable",
638
639
  "cancelled",
640
+ "waiting",
639
641
  "unknown"
640
642
  ];
641
643
  var TOOL_CALL_FAILURE_ACTIONS = [
@@ -643,6 +645,7 @@ var TOOL_CALL_FAILURE_ACTIONS = [
643
645
  "connect",
644
646
  "retry",
645
647
  "none",
648
+ "wait",
646
649
  "unknown"
647
650
  ];
648
651
  var TOOL_CALL_FAILURE_CODES = [
@@ -653,6 +656,8 @@ var TOOL_CALL_FAILURE_CODES = [
653
656
  "tool.not_found",
654
657
  "tool.unavailable",
655
658
  "tool.execution_failed",
659
+ "tool.auth_unavailable",
660
+ "tool.replies_owed",
656
661
  "provider.http",
657
662
  "provider.api",
658
663
  "provider.transport",
@@ -673,7 +678,7 @@ var toolCallFailureDetailsSchema = z5.strictObject({
673
678
  moduleId: z5.string().optional(),
674
679
  /**
675
680
  * [#5042] The registration that owns the FAILING TOOL, host-stamped from the
676
- * session's own tool source index — `herd.core` for a kernel tool,
681
+ * session's own tool source index - `herd.core` for a kernel tool,
677
682
  * `kay.task-introspection` for a daemon app-extension's, a plugin's id for a
678
683
  * plugin's, and the bare layer sentinel (`builtin`, `host`, `extension`) when
679
684
  * a registration named no owner.
@@ -681,7 +686,7 @@ var toolCallFailureDetailsSchema = z5.strictObject({
681
686
  * Distinct from {@link moduleId}, which names a URI MODULE and is stamped
682
687
  * only by a URI verb dispatch (#4954). Every failure has an owning tool; only
683
688
  * a URI dispatch has a module. Read together they answer "who failed" for
684
- * every tool call rather than only the URI ones — the fall-through #4954 left
689
+ * every tool call rather than only the URI ones - the fall-through #4954 left
685
690
  * open, where a `task`-kind tool throwing a plain `Error` reached the
686
691
  * classifier's terminal branch with nothing to attribute it to.
687
692
  *
@@ -692,7 +697,16 @@ var toolCallFailureDetailsSchema = z5.strictObject({
692
697
  operation: z5.string().optional(),
693
698
  uri: z5.string().optional(),
694
699
  path: z5.string().optional(),
695
- validationField: z5.string().optional(),
700
+ /**
701
+ * The dotted path of the first argument the tool's schema rejected
702
+ * (`result.status`, `root` for the whole object), and the rule it broke
703
+ * ("must have required property 'summary'"). Both come from the schema, so
704
+ * they are exportable; neither ever carries the rejected value. One
705
+ * exception to "from the schema": a free-form map puts its own keys in the
706
+ * path, so both are capped.
707
+ */
708
+ validationField: z5.string().max(200).optional(),
709
+ validationRule: z5.string().max(200).optional(),
696
710
  errorName: z5.string().optional(),
697
711
  errorCode: z5.string().optional(),
698
712
  providerCode: z5.string().optional(),
@@ -1047,9 +1061,10 @@ function reduceMessageStart(state, event, replay) {
1047
1061
  }
1048
1062
  function reduceMessageUpdate(state, event, replay) {
1049
1063
  const messageId = getMessageId(event) ?? state.streamingAssistantId;
1050
- const current = messageId !== void 0 ? findMessageItem(state, messageId, replay) : void 0;
1064
+ const liveIndex = messageId === void 0 || replay !== void 0 ? -1 : lastMessageIndex(state.items, messageId);
1065
+ const current = replay !== void 0 ? messageId === void 0 ? void 0 : findMessageItem(state, messageId, replay) : liveIndex === -1 ? void 0 : state.items[liveIndex];
1051
1066
  const updated = current === void 0 ? void 0 : mergeMessageUpdate(current, event);
1052
- const baseState = updated !== void 0 ? replaceMessageItem(state, updated, replay) : reduceMessageStart(state, {
1067
+ const baseState = updated !== void 0 ? replay === void 0 ? replaceItemAt(state, liveIndex, updated) : replaceMessageItem(state, updated, replay) : reduceMessageStart(state, {
1053
1068
  ...event,
1054
1069
  role: "assistant"
1055
1070
  }, replay);
@@ -1098,7 +1113,7 @@ function mergeMessageContent(item, event, status) {
1098
1113
  // The terminal merge (message_end) stamps completion; `startedAt` was
1099
1114
  // stamped at message_start and is never overwritten by later events.
1100
1115
  ...status === "streaming" || item.completedAt !== void 0 ? {} : stringField("completedAt", getTimestamp(event)),
1101
- ...messageMetadata(event, textPhaseFor(event, effectiveParts), effectiveParts)
1116
+ ...messageMetadata(event, textPhaseFor(event, effectiveParts, item.parts), effectiveParts)
1102
1117
  };
1103
1118
  }
1104
1119
  function mergeMessageDelta(item, event) {
@@ -1248,12 +1263,12 @@ function messageFailureReason(event) {
1248
1263
  ...errorText === void 0 ? {} : { failureText: readableFailureText(errorText) }
1249
1264
  };
1250
1265
  }
1251
- function textPhaseFor(event, parts) {
1266
+ function textPhaseFor(event, parts, streamedParts = []) {
1252
1267
  if (event.type !== "message_end")
1253
1268
  return "provisional";
1269
+ const isCall = (part) => part.type === "tool_call";
1270
+ const callsTool = parts.some(isCall) || streamedParts.some(isCall);
1254
1271
  switch (finishReasonFor(event, parts)) {
1255
- case "tool_use":
1256
- return "narration";
1257
1272
  case "complete":
1258
1273
  return "final";
1259
1274
  case "interrupted":
@@ -1261,8 +1276,11 @@ function textPhaseFor(event, parts) {
1261
1276
  return "interrupted";
1262
1277
  case "error":
1263
1278
  return "error";
1279
+ // Text is narration only beside a call it leads into. A provider can report `tool_use`
1280
+ // with no call in the message; that text is the reply, as a stop's would be.
1281
+ case "tool_use":
1264
1282
  case "unknown":
1265
- return parts.some((part) => part.type === "tool_call") ? "narration" : "final";
1283
+ return callsTool ? "narration" : "final";
1266
1284
  case void 0:
1267
1285
  return "final";
1268
1286
  }
@@ -1693,6 +1711,14 @@ function upsertMessageItem(state, item, replay) {
1693
1711
  }
1694
1712
  return replaceMessageItem(state, item, replay);
1695
1713
  }
1714
+ function lastMessageIndex(items, messageId) {
1715
+ return items.findLastIndex((candidate) => candidate.type === "message" && candidate.id === messageId);
1716
+ }
1717
+ function replaceItemAt(state, index, item) {
1718
+ const items = state.items.slice();
1719
+ items[index] = item;
1720
+ return { ...state, items };
1721
+ }
1696
1722
  function replaceMessageItem(state, item, replay) {
1697
1723
  if (replay !== void 0) {
1698
1724
  const itemIndex = replay.messageIndexById.get(item.id);
@@ -1762,7 +1788,9 @@ function upsertToolCall(state, update, options = {}, replay) {
1762
1788
  };
1763
1789
  let items;
1764
1790
  if (replay === void 0) {
1765
- items = previous === void 0 ? [...state.items, nextItem] : state.items.map((candidate) => candidate.type === "tool" && candidate.id === itemId ? nextItem : candidate);
1791
+ items = liveToolItems(state, previous, nextItem);
1792
+ if (items === state.items)
1793
+ return state;
1766
1794
  } else if (previous === void 0) {
1767
1795
  const index = replay.items.length;
1768
1796
  replay.items.push(nextItem);
@@ -1795,6 +1823,21 @@ function upsertToolCall(state, update, options = {}, replay) {
1795
1823
  nextItemIndex: previous === void 0 ? nextItemIndexAfter(state, itemId) : state.nextItemIndex
1796
1824
  };
1797
1825
  }
1826
+ function liveToolItems(state, previous, next) {
1827
+ if (previous === void 0)
1828
+ return [...state.items, next];
1829
+ const pending = state.pendingToolsByCallId[next.toolCallId];
1830
+ const pendingUnchanged = isTerminalToolStatus(next.status) ? pending === void 0 : pending === next.id;
1831
+ if (pendingUnchanged && sameToolCall(previous, next))
1832
+ return state.items;
1833
+ const copy = state.items.slice();
1834
+ copy[lastToolIndex(state.items, next.id)] = next;
1835
+ return copy;
1836
+ }
1837
+ function sameToolCall(a, b) {
1838
+ const keys = Object.keys(a);
1839
+ return keys.length === Object.keys(b).length && keys.every((key) => Object.hasOwn(b, key) && a[key] === b[key]);
1840
+ }
1798
1841
  function isEmptyStructuredArguments(value) {
1799
1842
  const trimmed = value?.trim();
1800
1843
  return trimmed === "{}" || trimmed === "[]";
@@ -1805,7 +1848,7 @@ function findToolItemByAttemptId(state, attemptId, replay) {
1805
1848
  const item = replayIndex === void 0 ? void 0 : replay.items[replayIndex];
1806
1849
  return item?.type === "tool" ? item : void 0;
1807
1850
  }
1808
- return state.items.find((candidate) => candidate.type === "tool" && candidate.attemptId === attemptId);
1851
+ return state.items.findLast((candidate) => candidate.type === "tool" && candidate.attemptId === attemptId);
1809
1852
  }
1810
1853
  function nextAttemptGeneration(state, toolCallId, replay) {
1811
1854
  if (replay !== void 0) {
@@ -1836,7 +1879,11 @@ function findToolItem(state, itemId, replay) {
1836
1879
  const item = replayIndex === void 0 ? void 0 : replay.items[replayIndex];
1837
1880
  return item?.type === "tool" ? item : void 0;
1838
1881
  }
1839
- return state.items.find((candidate) => candidate.type === "tool" && candidate.id === itemId);
1882
+ const index = lastToolIndex(state.items, itemId);
1883
+ return index === -1 ? void 0 : state.items[index];
1884
+ }
1885
+ function lastToolIndex(items, itemId) {
1886
+ return items.findLastIndex((candidate) => candidate.type === "tool" && candidate.id === itemId);
1840
1887
  }
1841
1888
  function findToolItemByCallId(state, toolCallId, replay) {
1842
1889
  if (replay !== void 0) {
@@ -3053,12 +3100,42 @@ function projectCanonicalTranscript(state, placements) {
3053
3100
  const latestSegment = segments[segments.length - 1];
3054
3101
  const transcriptEndsWithAgentSegment = turns[turns.length - 1] === void 0;
3055
3102
  for (const segment of segments) {
3056
- turns[segment.slot] = projectAgentTurn(segment.items, segment.causedByUserMessageId, segment.causeItem, transcriptEndsWithAgentSegment && segment === latestSegment, projectedState, anchorIndex, placements);
3103
+ const isLatestTurn = transcriptEndsWithAgentSegment && segment === latestSegment;
3104
+ turns[segment.slot] = isLatestTurn ? projectAgentTurn(segment.items, segment.causedByUserMessageId, segment.causeItem, true, projectedState, anchorIndex, placements) : projectSettledAgentTurn(segment, anchorIndex, projectedState, placements);
3057
3105
  }
3058
3106
  return {
3059
3107
  turns: withRecoveryFlags(turns.filter((turn) => turn !== void 0))
3060
3108
  };
3061
3109
  }
3110
+ var settledTurnProjections = /* @__PURE__ */ new WeakMap();
3111
+ function projectSettledAgentTurn(segment, anchorIndex, state, placements) {
3112
+ const { items, causedByUserMessageId, causeItem } = segment;
3113
+ const ranks = items.map((item) => anchorIndex?.firstRankByTypeAndId.get(item.type)?.get(item.id));
3114
+ const first = items[0];
3115
+ const previous = settledTurnProjections.get(first);
3116
+ if (previous !== void 0 && previous.causedByUserMessageId === causedByUserMessageId && previous.causeItem === causeItem && previous.placements === placements && sameElements(previous.items, items) && sameElements(previous.ranks, ranks)) {
3117
+ return previous.turn;
3118
+ }
3119
+ const turn = projectAgentTurn(items, causedByUserMessageId, causeItem, false, state, anchorIndex, placements);
3120
+ settledTurnProjections.set(first, {
3121
+ items,
3122
+ causedByUserMessageId,
3123
+ causeItem,
3124
+ placements,
3125
+ ranks,
3126
+ turn
3127
+ });
3128
+ return turn;
3129
+ }
3130
+ function sameElements(a, b) {
3131
+ if (a.length !== b.length)
3132
+ return false;
3133
+ for (let index = 0; index < a.length; index += 1) {
3134
+ if (a[index] !== b[index])
3135
+ return false;
3136
+ }
3137
+ return true;
3138
+ }
3062
3139
  function dropRepeatedDeliveries(items) {
3063
3140
  const seen = /* @__PURE__ */ new Set();
3064
3141
  let dropped = false;
@@ -3738,6 +3815,19 @@ function optional(key, value) {
3738
3815
  return value === void 0 ? {} : { [key]: value };
3739
3816
  }
3740
3817
 
3818
+ // packages/herd-transcript/dist/interactive/stored-run-state.js
3819
+ var RUN_TERMINAL_CUSTOM_TYPE = "session_run_state";
3820
+ function storedRunOutcome(value) {
3821
+ return value === "interrupted" || value === "cancelled" || value === "failed" || value === "completed" ? value : void 0;
3822
+ }
3823
+ function storedRunOutcomeOfRecord(data) {
3824
+ const runState = storedRunOutcome(data["runState"]);
3825
+ if (runState === "cancelled" && data["stop"] === void 0) {
3826
+ return "interrupted";
3827
+ }
3828
+ return runState;
3829
+ }
3830
+
3741
3831
  // packages/herd-transcript/dist/interactive/reconstruct.js
3742
3832
  function eventsForEntry(entry) {
3743
3833
  if (entry.type === "compaction") {
@@ -3796,27 +3886,12 @@ function reconstructInteractiveState(entries) {
3796
3886
  return reduceInteractiveModeEventsForReplay(replayEvents());
3797
3887
  }
3798
3888
  function runBoundaryReplayEvent(entry) {
3799
- if (entry.type !== "custom" || entry.customType !== "session_run_state") {
3889
+ if (entry.type !== "custom" || entry.customType !== RUN_TERMINAL_CUSTOM_TYPE) {
3800
3890
  return void 0;
3801
3891
  }
3802
3892
  const data = asRecord3(entry.data);
3803
- const runState = data?.["runState"];
3804
- switch (runState) {
3805
- case "completed":
3806
- case "failed":
3807
- case "interrupted":
3808
- case "cancelled":
3809
- return {
3810
- type: "host_run_status",
3811
- run: {
3812
- status: "settled",
3813
- // Bare cancelled entries predate the interrupt/cancel split.
3814
- outcome: runState === "cancelled" && data?.["stop"] === void 0 ? "interrupted" : runState
3815
- }
3816
- };
3817
- default:
3818
- return void 0;
3819
- }
3893
+ const outcome = data === void 0 ? void 0 : storedRunOutcomeOfRecord(data);
3894
+ return outcome === void 0 ? void 0 : { type: "host_run_status", run: { status: "settled", outcome } };
3820
3895
  }
3821
3896
  function contentText(content) {
3822
3897
  if (typeof content === "string")