@zq-silk/yui 0.14.0 → 0.14.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.
Files changed (179) hide show
  1. package/ARCHITECTURE.md +64 -35
  2. package/README.md +258 -125
  3. package/dist/agent/argumentPolicy.js +2 -1
  4. package/dist/agent/managedRuntimeEnvironment.js +5 -8
  5. package/dist/cli/commandCatalog.js +74 -109
  6. package/dist/cli/helpRenderer.js +1 -2
  7. package/dist/cli/interactionCandidates.js +10 -0
  8. package/dist/cli/interactionPolicy.js +76 -37
  9. package/dist/cli/roleWizard.js +5 -6
  10. package/dist/cli/updateOrchestrator.js +10 -8
  11. package/dist/cli/updatePorts.js +17 -13
  12. package/dist/cli/upgradeCommand.js +2 -5
  13. package/dist/cli.js +268 -231
  14. package/dist/commands/agentCommands.js +13 -0
  15. package/dist/commands/configCommands.js +7 -19
  16. package/dist/commands/configOverview.js +3 -2
  17. package/dist/commands/durableJobCommands.js +1 -1
  18. package/dist/commands/executionAuditCommands.js +4 -9
  19. package/dist/commands/globalRoleCommands.js +17 -0
  20. package/dist/commands/profileCommands.js +200 -30
  21. package/dist/commands/sessionCommands.js +1 -1
  22. package/dist/commands/taskActor.js +29 -127
  23. package/dist/commands/taskChangeSetCommands.js +1 -3
  24. package/dist/commands/taskCommands.js +1771 -2107
  25. package/dist/commands/taskCompletionGate.js +27 -103
  26. package/dist/commands/taskContextCommand.js +47 -80
  27. package/dist/commands/taskExecutionCommands.js +9 -27
  28. package/dist/commands/taskInputCommands.js +10 -10
  29. package/dist/commands/taskIntegrationCommands.js +69 -61
  30. package/dist/commands/taskIntegrationQueueCommands.js +1 -1
  31. package/dist/commands/taskNextActionCommand.js +8 -29
  32. package/dist/commands/taskOverviewCommand.js +25 -3
  33. package/dist/commands/taskPublicationCommands.js +151 -85
  34. package/dist/commands/taskPublicationVerifyCommand.js +181 -0
  35. package/dist/commands/taskRemoteDeliveryCommand.js +134 -0
  36. package/dist/commands/taskRoleRuntimeStatus.js +5 -6
  37. package/dist/commands/taskUpstreamCommands.js +79 -95
  38. package/dist/config/configCatalog.js +1 -1
  39. package/dist/context/contextSnapshot.js +17 -2
  40. package/dist/context/sessionBootstrapManifest.js +18 -1
  41. package/dist/context/sourceTurnContext.js +30 -0
  42. package/dist/context/turnContextPack.js +107 -48
  43. package/dist/context/turnInputContract.js +11 -4
  44. package/dist/context/wakeNotification.js +84 -22
  45. package/dist/controller/agentRuntimeObserver.js +9 -12
  46. package/dist/controller/clientRuntime.js +13 -13
  47. package/dist/controller/controller.js +11 -11
  48. package/dist/controller/fileSchedulerStoreAdapter.js +262 -219
  49. package/dist/controller/jobControl.js +11 -10
  50. package/dist/controller/resourceInventory.js +6 -6
  51. package/dist/controller/resourceInventoryLinux.js +2 -2
  52. package/dist/controller/runtime.js +18 -61
  53. package/dist/controller/runtimeEventInbox.js +57 -34
  54. package/dist/controller/runtimeEventProcessor.js +36 -96
  55. package/dist/controller/runtimeHookTurnFence.js +33 -57
  56. package/dist/controller/runtimeLaunchCoordinator.js +44 -40
  57. package/dist/controller/runtimeObservationHook.js +18 -12
  58. package/dist/controller/sessionNotify.js +43 -28
  59. package/dist/controller/sessionOwnerReconciliation.js +21 -21
  60. package/dist/controller/structuredProviderObservation.js +13 -16
  61. package/dist/coordination/workMailboxQueue.js +132 -0
  62. package/dist/core/controllerServer.js +1 -0
  63. package/dist/domain/agentResultTransport.js +60 -0
  64. package/dist/execution/executionHealth.js +111 -118
  65. package/dist/execution/reviewMainTurn.js +161 -0
  66. package/dist/execution/workItemExecution.js +454 -0
  67. package/dist/execution/workItemExecutionProjection.js +309 -0
  68. package/dist/execution/workItemMainTurn.js +164 -0
  69. package/dist/executor/agentExecutor.js +19 -19
  70. package/dist/executor/executorRegistry.js +7 -28
  71. package/dist/executor/fileRoleLaunchPlanner.js +51 -83
  72. package/dist/external/githubPublicationVerifier.js +114 -0
  73. package/dist/external/gitlabPublicationVerifier.js +158 -0
  74. package/dist/external/pinnedCommandRunner.js +73 -0
  75. package/dist/integration/changeSetManifest.js +0 -3
  76. package/dist/integration/deliveryObligation.js +43 -6
  77. package/dist/integration/gitIntegrationService.js +284 -101
  78. package/dist/integration/integrationAttempt.js +64 -14
  79. package/dist/integration/integrationQueueEntry.js +5 -35
  80. package/dist/integration/integrationQueueService.js +65 -194
  81. package/dist/lifecycle/canonicalLifecycleEvent.js +16 -15
  82. package/dist/lifecycle/exactTurnTerminalization.js +100 -97
  83. package/dist/message/message.js +16 -0
  84. package/dist/observability/executionAudit.js +4 -25
  85. package/dist/observability/faultClassification.js +58 -70
  86. package/dist/observability/orchestrationMetrics.js +8 -50
  87. package/dist/profile/agentProfile.js +60 -15
  88. package/dist/profile/agentProfileRuntime.js +100 -0
  89. package/dist/release/releaseWorkflowPorts.js +5 -68
  90. package/dist/repository/executionLaneGitSnapshot.js +80 -0
  91. package/dist/repository/gitWorkspace.js +9 -67
  92. package/dist/repository/taskBaseFreshness.js +3 -1
  93. package/dist/repository/taskWorkspaceCoordinator.js +32 -4
  94. package/dist/repository/taskWorkspacePreparer.js +252 -411
  95. package/dist/resources/liveReferences.js +6 -55
  96. package/dist/resources/resourceDiscovery.js +1 -30
  97. package/dist/resources/resourceRegistrar.js +0 -23
  98. package/dist/review/deltaRecheck.js +8 -65
  99. package/dist/review/reviewAcceptance.js +22 -19
  100. package/dist/review/reviewConfig.js +0 -10
  101. package/dist/review/reviewDecision.js +2 -2
  102. package/dist/review/reviewRound.js +147 -273
  103. package/dist/review/reviewerAvailability.js +13 -23
  104. package/dist/role/role.js +3 -0
  105. package/dist/runtime/agentDriverObservation.js +1 -1
  106. package/dist/runtime/agentHost.js +51 -51
  107. package/dist/runtime/builtinAgentDrivers.js +9 -2
  108. package/dist/runtime/codexAppServerRuntime.js +23 -5
  109. package/dist/runtime/exactControlPlane.js +2 -267
  110. package/dist/runtime/firstProgressAdvisory.js +1 -1
  111. package/dist/runtime/index.js +1 -1
  112. package/dist/runtime/launchBroker.js +11 -11
  113. package/dist/runtime/lifecycleReservation.js +2 -2
  114. package/dist/runtime/managedCaller.js +111 -0
  115. package/dist/runtime/ports.js +16 -3
  116. package/dist/runtime/preallocatedNativeSession.js +2 -2
  117. package/dist/runtime/processExitObservation.js +3 -2
  118. package/dist/runtime/providerContinuationReconciliationService.js +1 -1
  119. package/dist/runtime/runtimeBinding.js +1 -1
  120. package/dist/runtime/runtimeObservation.js +33 -16
  121. package/dist/runtime/runtimeSessionCandidate.js +2 -2
  122. package/dist/runtime/runtimeStopReceipt.js +11 -11
  123. package/dist/runtime/sessionLaunchRequest.js +2 -2
  124. package/dist/runtime/sessionOwnerIdentity.js +9 -9
  125. package/dist/runtime/sessionOwnerRegistry.js +13 -13
  126. package/dist/runtime/sessionReconciliation.js +4 -4
  127. package/dist/runtime/sessionTerminationGuard.js +9 -9
  128. package/dist/runtime/sessionTokenMetrics.js +5 -7
  129. package/dist/runtime/structuredProviderHost.js +5 -5
  130. package/dist/runtime/taskRuntimeIsolation.js +24 -24
  131. package/dist/runtime/tmuxAdapters.js +32 -30
  132. package/dist/scheduler/activeRoleTurnDelivery.js +37 -15
  133. package/dist/scheduler/leaderWakeupProcessor.js +78 -55
  134. package/dist/scheduler/roleTurnLiveness.js +6 -6
  135. package/dist/scheduler/roleTurnStall.js +8 -9
  136. package/dist/scheduler/taskExecutionProjection.js +19 -41
  137. package/dist/scheduler/taskObservabilityProjection.js +75 -122
  138. package/dist/storage/sqliteSchema.js +1 -21
  139. package/dist/storage/sqliteStore.js +62 -47
  140. package/dist/storage/storageSchema.js +1 -8
  141. package/dist/storage/storageVersions.js +7 -4
  142. package/dist/storage/taskStore.js +8 -8
  143. package/dist/storage/upgrade/upgradeOrchestrator.js +112 -83
  144. package/dist/task/completionReadiness.js +17 -98
  145. package/dist/task/deliveryGuard.js +9 -11
  146. package/dist/task/draftPlan.js +142 -0
  147. package/dist/task/nextAction.js +179 -477
  148. package/dist/task/publicationVerification.js +1 -0
  149. package/dist/task/remoteDelivery.js +233 -0
  150. package/dist/task/task.js +108 -4
  151. package/dist/task/taskRecordReference.js +0 -1
  152. package/dist/turn/turn.js +109 -16
  153. package/dist/verification/verificationGateService.js +0 -26
  154. package/dist/web/assets/client/components.js +99 -121
  155. package/dist/web/assets/client/i18n.js +136 -58
  156. package/dist/web/assets/client/view.js +44 -0
  157. package/dist/web/assets/styles/cards.js +3 -15
  158. package/dist/web/assets/styles/widgets.js +4 -0
  159. package/dist/web/webSnapshot.js +29 -14
  160. package/dist/workItem/dependencyGate.js +34 -0
  161. package/dist/workItem/workItem.js +99 -266
  162. package/dist/workspace/workItemChangeSetManager.js +15 -59
  163. package/docs/task-local-identity.md +1 -1
  164. package/i18n/README.zh-CN.md +165 -59
  165. package/package.json +1 -1
  166. package/skills/yui-leader/SKILL.md +272 -782
  167. package/skills/yui-operator/SKILL.md +190 -365
  168. package/skills/yui-reviewer/SKILL.md +40 -33
  169. package/skills/yui-runtime/SKILL.md +27 -6
  170. package/skills/yui-worker/SKILL.md +19 -6
  171. package/dist/execution/candidateConvergence.js +0 -623
  172. package/dist/execution/executionGroup.js +0 -854
  173. package/dist/execution/resourceBroker.js +0 -426
  174. package/dist/executor/launchPlan.js +0 -16
  175. package/dist/review/reviewFinding.js +0 -240
  176. package/dist/review/reviewFindingLedger.js +0 -550
  177. package/dist/review/reviewOutcomeClassifier.js +0 -255
  178. package/dist/scheduler/resourceQueueProjection.js +0 -71
  179. package/dist/task/repairWave.js +0 -150
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { callController } from "../core/controllerClient.js";
3
3
  import { builtinAgentDriverRegistry } from "../runtime/builtinAgentDrivers.js";
4
4
  import { standardAgentError } from "../runtime/agentError.js";
5
+ import { transportAgentResult } from "../domain/agentResultTransport.js";
5
6
  import { createRuntimeObservation, runtimeObservationSemanticKey } from "../runtime/runtimeObservation.js";
6
7
  import { runtimeLifecycleSignalKey } from "../runtime/lifecycleReservation.js";
7
8
  import { isForeignHandoverLockHeld } from "../release/runtimeRelease.js";
@@ -28,8 +29,7 @@ export async function publishStructuredProviderStarted(input) {
28
29
  roleName: fence.roleName,
29
30
  agentId: fence.agentId,
30
31
  driverId: driver.id,
31
- launchId: fence.launchId,
32
- sessionGenerationId: fence.launchId,
32
+ runtimeGenerationId: fence.runtimeGenerationId,
33
33
  conversationId: input.started.conversationId,
34
34
  activationId: requireIdentity(input.activationId, "Provider Activation id"),
35
35
  nativeSessionId: input.started.nativeSessionId,
@@ -56,8 +56,7 @@ export async function publishStructuredProviderAccepted(input) {
56
56
  ...(fence.turnId === undefined ? {} : { turnId: fence.turnId }),
57
57
  agentId: fence.agentId,
58
58
  driverId: driver.id,
59
- launchId: fence.launchId,
60
- sessionGenerationId: fence.launchId,
59
+ runtimeGenerationId: fence.runtimeGenerationId,
61
60
  conversationId: input.receipt.conversationId,
62
61
  activationId: requireIdentity(input.activationId, "Provider Activation id"),
63
62
  nativeSessionId: input.receipt.nativeSessionId,
@@ -107,8 +106,7 @@ export async function publishStructuredProviderOpened(input) {
107
106
  ...(fence.turnId === undefined ? {} : { turnId: fence.turnId }),
108
107
  agentId: fence.agentId,
109
108
  driverId: driver.id,
110
- launchId: fence.launchId,
111
- sessionGenerationId: fence.launchId,
109
+ runtimeGenerationId: fence.runtimeGenerationId,
112
110
  conversationId: input.conversationId,
113
111
  activationId: requireIdentity(input.activationId, "Provider Activation id"),
114
112
  nativeSessionId: input.nativeSessionId,
@@ -153,8 +151,7 @@ export async function publishStructuredProviderGoal(input) {
153
151
  roleName: fence.roleName,
154
152
  agentId: fence.agentId,
155
153
  driverId: driver.id,
156
- launchId: fence.launchId,
157
- sessionGenerationId: fence.launchId,
154
+ runtimeGenerationId: fence.runtimeGenerationId,
158
155
  conversationId: input.conversationId,
159
156
  activationId: requireIdentity(input.activationId, "Provider Activation id"),
160
157
  nativeSessionId: input.conversationId
@@ -180,8 +177,7 @@ export async function publishStructuredConversationRecoverability(input) {
180
177
  ...(fence.turnId === undefined ? {} : { turnId: fence.turnId }),
181
178
  agentId: fence.agentId,
182
179
  driverId: driver.id,
183
- launchId: fence.launchId,
184
- sessionGenerationId: fence.launchId,
180
+ runtimeGenerationId: fence.runtimeGenerationId,
185
181
  conversationId: input.conversationId,
186
182
  activationId: requireIdentity(input.activationId, "Provider Activation id"),
187
183
  nativeSessionId: input.conversationId,
@@ -224,10 +220,13 @@ export async function publishStructuredProviderTerminal(input) {
224
220
  const kind = input.terminal.status === "completed"
225
221
  ? "turn.completed"
226
222
  : input.terminal.status === "cancelled" ? "turn.cancelled" : "turn.failed";
223
+ const transported = transportAgentResult(input.terminal.output);
227
224
  const payload = kind === "turn.completed"
228
225
  ? {
229
226
  ...(input.terminal.input === undefined ? {} : { input: input.terminal.input }),
230
- ...(input.terminal.summary === undefined ? {} : { summary: input.terminal.summary })
227
+ ...(transported.status === "completed"
228
+ ? { output: transported.output }
229
+ : { resultTransportDiagnostic: transported.diagnostic })
231
230
  }
232
231
  : kind === "turn.failed"
233
232
  ? {
@@ -263,8 +262,7 @@ export async function publishStructuredProviderTerminal(input) {
263
262
  ...(fence.turnId === undefined ? {} : { turnId: fence.turnId }),
264
263
  agentId: fence.agentId,
265
264
  driverId: driver.id,
266
- launchId: fence.launchId,
267
- sessionGenerationId: fence.launchId,
265
+ runtimeGenerationId: fence.runtimeGenerationId,
268
266
  conversationId: input.terminal.conversationId,
269
267
  activationId: requireIdentity(input.activationId, "Provider Activation id"),
270
268
  nativeSessionId: input.terminal.nativeSessionId,
@@ -290,8 +288,7 @@ export async function publishStructuredProviderActivationTerminal(input) {
290
288
  ...(fence.turnId === undefined ? {} : { turnId: fence.turnId }),
291
289
  agentId: fence.agentId,
292
290
  driverId: driver.id,
293
- launchId: fence.launchId,
294
- sessionGenerationId: fence.launchId,
291
+ runtimeGenerationId: fence.runtimeGenerationId,
295
292
  conversationId: requireIdentity(input.conversationId, "Provider Conversation id"),
296
293
  activationId: requireIdentity(input.activationId, "Provider Activation id"),
297
294
  nativeSessionId: requireIdentity(input.nativeSessionId, "native Session id"),
@@ -311,7 +308,7 @@ function observation(input) {
311
308
  payload: input.payload ?? {}
312
309
  };
313
310
  return createRuntimeObservation({
314
- schemaVersion: 2,
311
+ schemaVersion: 4,
315
312
  eventId,
316
313
  semanticKey: runtimeObservationSemanticKey(partial),
317
314
  kind: input.kind,
@@ -1,4 +1,11 @@
1
1
  import { completeProcessing, consumePendingBatch, createWorkMailbox, enqueueSignal, mailboxBatches, mailboxEntityRefKey } from "./workMailbox.js";
2
+ const LEGACY_ROLE_TURN_DISPATCH_REASONS = new Set([
3
+ "turn-dispatched",
4
+ "turn-retried",
5
+ "review-requested",
6
+ "workitem-synthesis-ready",
7
+ "review-synthesis-ready"
8
+ ]);
2
9
  /** Atomically useful when called inside the caller's TaskStore transaction. */
3
10
  export function enqueueWork(store, target, reason, occurredAt, refs = [], metadata = {}) {
4
11
  const mailbox = store.getWorkMailbox(target) ?? createWorkMailbox(target);
@@ -11,6 +18,106 @@ export function enqueueWork(store, target, reason, occurredAt, refs = [], metada
11
18
  store.saveWorkMailbox(queued);
12
19
  return queued;
13
20
  }
21
+ /**
22
+ * The sole ordinary Role Turn wake shape. The Turn is durable execution
23
+ * authority; this signal only asks the Controller to deliver that exact Turn.
24
+ * Leader is deliberately excluded because its Role mailbox is reserved for
25
+ * semantic event wakes and force-steer batches. A Leader active Turn is
26
+ * selected directly from durable state by its targeted Controller pass.
27
+ */
28
+ export function enqueueRoleTurnDispatch(store, input) {
29
+ if (input.roleName === "leader")
30
+ return null;
31
+ return enqueueWork(store, roleTurnTarget(input), input.reason, input.occurredAt, [roleTurnRef(input)], {
32
+ source: "turn-dispatch",
33
+ dedupeKey: roleTurnDispatchDedupeKey(input)
34
+ });
35
+ }
36
+ /**
37
+ * Captures only the mailbox prefix that contains one exact Role Turn dispatch.
38
+ * A later signal may append while Provider delivery is in flight; its suffix
39
+ * remains pending when this token is settled.
40
+ */
41
+ export function captureRoleTurnDispatch(mailbox, input) {
42
+ if (input.roleName === "leader"
43
+ || mailbox === null
44
+ || mailbox.target.kind !== "role"
45
+ || mailbox.target.taskId !== input.taskId
46
+ || mailbox.target.roleName !== input.roleName) {
47
+ return null;
48
+ }
49
+ const exactRef = roleTurnRef(input);
50
+ if (mailbox.processing?.executionRef !== undefined
51
+ && mailboxEntityRefKey(mailbox.processing.executionRef) === mailboxEntityRefKey(exactRef)) {
52
+ return {
53
+ kind: "processing",
54
+ batchId: mailbox.processing.batchId
55
+ };
56
+ }
57
+ const pending = mailbox.pending;
58
+ if (pending === null)
59
+ return null;
60
+ const dedupeKey = roleTurnDispatchDedupeKey(input);
61
+ if (mailbox.recentDedupeKeys.includes(dedupeKey))
62
+ return null;
63
+ const keyIndex = pending.dedupeKeys.indexOf(dedupeKey);
64
+ if (keyIndex >= 0 && pending.dedupeKeys.length === pending.requestCount) {
65
+ const turnSequence = pending.fromSequence + keyIndex;
66
+ if (turnSequence <= pending.toSequence) {
67
+ return {
68
+ kind: "pending",
69
+ fromSequence: pending.fromSequence,
70
+ toSequence: turnSequence
71
+ };
72
+ }
73
+ }
74
+ // Valid earlier dispatches used sequence-generated dedupe keys and could
75
+ // include a companion WorkItem ref. Consume that complete legacy batch once
76
+ // the exact Turn reaches an accepted or terminal boundary.
77
+ if (pending.requestCount === 1
78
+ && pending.sources.length === 1
79
+ && pending.sources[0] === "yui"
80
+ && pending.reasons.some((reason) => LEGACY_ROLE_TURN_DISPATCH_REASONS.has(reason))
81
+ && pending.refs.some((ref) => (mailboxEntityRefKey(ref) === mailboxEntityRefKey(exactRef)))) {
82
+ return {
83
+ kind: "pending",
84
+ fromSequence: pending.fromSequence,
85
+ toSequence: pending.toSequence
86
+ };
87
+ }
88
+ return null;
89
+ }
90
+ /**
91
+ * Settles one exact ordinary Role Turn dispatch. Provider acceptance is the
92
+ * normal boundary; terminalization calls the same operation for conclusively
93
+ * unaccepted and valid earlier dispatches.
94
+ */
95
+ export function settleRoleTurnDispatch(store, input, expected) {
96
+ if (expected === null)
97
+ return "absent";
98
+ const target = roleTurnTarget(input);
99
+ const mailbox = store.getWorkMailbox(target);
100
+ const current = captureRoleTurnDispatch(mailbox, input);
101
+ if (current === null || mailbox === null)
102
+ return "absent";
103
+ if (expected !== undefined && !sameRoleTurnDispatchToken(current, expected)) {
104
+ return "state-changed";
105
+ }
106
+ const token = expected ?? current;
107
+ if (token.kind === "processing") {
108
+ if (mailbox.processing?.batchId !== token.batchId)
109
+ return "state-changed";
110
+ store.saveWorkMailbox(completeProcessing(mailbox, token.batchId));
111
+ return "settled";
112
+ }
113
+ if (mailbox.pending === null
114
+ || mailbox.pending.fromSequence !== token.fromSequence
115
+ || mailbox.pending.toSequence < token.toSequence) {
116
+ return "state-changed";
117
+ }
118
+ store.saveWorkMailbox(consumePendingBatch(mailbox, token));
119
+ return "settled";
120
+ }
14
121
  /** Completes only the batch owned by the matching durable execution. */
15
122
  export function completeWorkExecution(store, target, executionRef) {
16
123
  const mailbox = store.getWorkMailbox(target);
@@ -76,6 +183,31 @@ export function settleExactWorkExecution(store, target, executionRef) {
76
183
  function timestamp(value) {
77
184
  return value instanceof Date ? value.toISOString() : value;
78
185
  }
186
+ function roleTurnTarget(input) {
187
+ return {
188
+ kind: "role",
189
+ taskId: input.taskId,
190
+ roleName: input.roleName
191
+ };
192
+ }
193
+ function roleTurnRef(input) {
194
+ return {
195
+ type: "turn",
196
+ taskId: input.taskId,
197
+ id: input.turnId
198
+ };
199
+ }
200
+ function roleTurnDispatchDedupeKey(input) {
201
+ return `role-turn:${input.taskId}:${input.roleName}:${input.turnId}`;
202
+ }
203
+ function sameRoleTurnDispatchToken(left, right) {
204
+ return left.kind === right.kind
205
+ && (left.kind === "pending"
206
+ ? right.kind === "pending"
207
+ && left.fromSequence === right.fromSequence
208
+ && left.toSequence === right.toSequence
209
+ : right.kind === "processing" && left.batchId === right.batchId);
210
+ }
79
211
  function targetLabel(target) {
80
212
  switch (target.kind) {
81
213
  case "operator": return "operator";
@@ -593,6 +593,7 @@ function parseBeginHandoverParams(value) {
593
593
  }
594
594
  const fromReleaseId = record.fromReleaseId;
595
595
  if (fromReleaseId !== undefined
596
+ && fromReleaseId !== null
596
597
  && (typeof fromReleaseId !== "string" || fromReleaseId.length > 256)) {
597
598
  return null;
598
599
  }
@@ -0,0 +1,60 @@
1
+ export const MAX_TURN_RESULT_OUTPUT_BYTES = 512 * 1024;
2
+ export const MAX_TURN_FAILURE_DIAGNOSTIC_BYTES = 16 * 1024;
3
+ /**
4
+ * Validate only the transport envelope of an Agent result. The accepted text
5
+ * remains byte-for-byte unchanged; missing or untransportable text becomes a
6
+ * Core-owned failed outcome so the exact Turn can still terminalize.
7
+ */
8
+ export function transportAgentResult(value) {
9
+ if (typeof value !== "string") {
10
+ return {
11
+ status: "failed",
12
+ diagnostic: "Provider terminal event did not include an Agent result.",
13
+ failureReason: "missing-result"
14
+ };
15
+ }
16
+ if (value.includes("\0")) {
17
+ return {
18
+ status: "failed",
19
+ diagnostic: "Provider terminal event included an Agent result with an invalid NUL byte.",
20
+ failureReason: "missing-result"
21
+ };
22
+ }
23
+ if (value.trim().length === 0) {
24
+ return {
25
+ status: "failed",
26
+ diagnostic: "Provider terminal event included an empty Agent result.",
27
+ failureReason: "missing-result"
28
+ };
29
+ }
30
+ const bytes = Buffer.byteLength(value, "utf8");
31
+ if (bytes > MAX_TURN_RESULT_OUTPUT_BYTES) {
32
+ return {
33
+ status: "failed",
34
+ diagnostic: `Provider Agent result is ${bytes} bytes and exceeds the ${MAX_TURN_RESULT_OUTPUT_BYTES}-byte durable result limit; the result was not stored.`,
35
+ failureReason: "missing-result"
36
+ };
37
+ }
38
+ return { status: "completed", output: value };
39
+ }
40
+ /**
41
+ * Bound Core-owned failure diagnostics without rejecting a terminal event.
42
+ * This is intentionally separate from Agent result transport: successful
43
+ * Agent text is either retained exactly or rejected as a whole, never
44
+ * truncated. Provider/Core diagnostics may be clipped because they are only
45
+ * operational context for a failed Turn.
46
+ */
47
+ export function boundedTurnFailureDiagnostic(value, fallback = "Provider reported a failed Agent Turn.") {
48
+ const candidate = typeof value === "string" && value.trim().length > 0
49
+ ? value
50
+ : fallback;
51
+ const safe = candidate.replaceAll("\0", "\uFFFD");
52
+ if (Buffer.byteLength(safe, "utf8") <= MAX_TURN_FAILURE_DIAGNOSTIC_BYTES) {
53
+ return safe;
54
+ }
55
+ const prefix = Buffer
56
+ .from(safe, "utf8")
57
+ .subarray(0, MAX_TURN_FAILURE_DIAGNOSTIC_BYTES)
58
+ .toString("utf8");
59
+ return prefix.endsWith("\uFFFD") ? prefix.slice(0, -1) : prefix;
60
+ }