@zq-silk/yui 0.13.8 → 0.13.9
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/README.md +9 -8
- package/dist/cli/commandCatalog.js +21 -2
- package/dist/cli.js +42 -13
- package/dist/commands/agentCommands.js +1 -1
- package/dist/commands/configCommands.js +1 -86
- package/dist/commands/executionAuditCommands.js +17 -16
- package/dist/commands/globalRoleCommands.js +4 -4
- package/dist/commands/sessionCommands.js +2 -6
- package/dist/commands/taskActor.js +1 -2
- package/dist/commands/taskCommands.js +92 -9
- package/dist/commands/taskRoleRuntimeStatus.js +3 -3
- package/dist/config/configCatalog.js +1 -6
- package/dist/config/yuiConfig.js +0 -79
- package/dist/controller/clientRuntime.js +40 -3
- package/dist/controller/controller.js +29 -52
- package/dist/controller/fileSchedulerStoreAdapter.js +305 -1056
- package/dist/controller/runtime.js +12 -5
- package/dist/controller/runtimeHookRunFence.js +3 -9
- package/dist/controller/runtimeLaunchCoordinator.js +44 -67
- package/dist/controller/structuredProviderObservation.js +18 -5
- package/dist/coordination/workMailbox.js +4 -4
- package/dist/execution/executionHealth.js +1 -1
- package/dist/executor/agentExecutor.js +92 -68
- package/dist/executor/executorRegistry.js +8 -20
- package/dist/executor/fileRoleLaunchPlanner.js +24 -90
- package/dist/executor/turnCompletion.js +5 -5
- package/dist/lifecycle/exactRunTerminalization.js +1 -1
- package/dist/observability/executionAudit.js +40 -94
- package/dist/operator/operatorSessionHistory.js +7 -5
- package/dist/role/role.js +1 -1
- package/dist/run/agentRun.js +4 -54
- package/dist/runtime/agentDriver.js +2 -0
- package/dist/runtime/agentError.js +114 -0
- package/dist/runtime/agentHost.js +55 -82
- package/dist/runtime/builtinAgentDrivers.js +21 -9
- package/dist/runtime/builtinAgentErrorMappers.js +150 -0
- package/dist/runtime/exactControlPlane.js +6 -12
- package/dist/runtime/index.js +0 -1
- package/dist/runtime/launchBroker.js +5 -19
- package/dist/runtime/lifecycleReservation.js +20 -4
- package/dist/runtime/providerRuntimeIdentity.js +3 -2
- package/dist/runtime/runtimeBinding.js +0 -27
- package/dist/runtime/runtimeObservation.js +7 -16
- package/dist/runtime/runtimeSessionCandidate.js +3 -10
- package/dist/runtime/sessionLaunchRequest.js +1 -2
- package/dist/runtime/sessionReconciliation.js +2 -2
- package/dist/runtime/structuredProviderHost.js +44 -79
- package/dist/runtime/taskRuntimeIsolation.js +0 -7
- package/dist/runtime/tmuxAdapters.js +6 -49
- package/dist/scheduler/activeRoleRunDelivery.js +218 -168
- package/dist/scheduler/leaderWakeupProcessor.js +126 -86
- package/dist/scheduler/roleRunLiveness.js +4 -1
- package/dist/scheduler/roleRunStall.js +7 -11
- package/dist/scheduler/wakeReason.js +4 -0
- package/dist/storage/migration/productionRegistry.js +332 -0
- package/dist/storage/sqliteSchema.js +54 -2
- package/dist/storage/sqliteStore.js +11 -44
- package/dist/storage/taskStore.js +7 -35
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +30 -8
- package/skills/yui-operator/SKILL.md +14 -6
- package/skills/yui-runtime/SKILL.md +6 -4
- package/dist/lifecycle/providerErrorClass.js +0 -152
- package/dist/run/providerRetry.js +0 -226
- package/dist/run/providerRetryConfig.js +0 -27
- package/dist/runtime/providerErrorCodes.js +0 -278
- package/dist/runtime/providerRecoveryDecision.js +0 -55
|
@@ -86,26 +86,6 @@ function roleBucket(roleName) {
|
|
|
86
86
|
}
|
|
87
87
|
return "other";
|
|
88
88
|
}
|
|
89
|
-
/** Maps a provider-retry lifecycle event to its last recorded decision. */
|
|
90
|
-
function providerRetryDecision(event) {
|
|
91
|
-
if (event.type === "runtime.provider-retry-waiting")
|
|
92
|
-
return "waiting";
|
|
93
|
-
if (event.type === "runtime.provider-retry-resume")
|
|
94
|
-
return "resume";
|
|
95
|
-
if (event.type === "runtime.provider-retry-session-dead")
|
|
96
|
-
return "session-dead";
|
|
97
|
-
if (event.type === "runtime.provider-retry-budget-exhausted")
|
|
98
|
-
return "budget-exhausted";
|
|
99
|
-
if (event.payload.note === "native-turn-completion-durable")
|
|
100
|
-
return "suppressed:completion-durable";
|
|
101
|
-
if (event.payload.note === "retry-budget-exhausted")
|
|
102
|
-
return "budget-exhausted";
|
|
103
|
-
if (event.payload.wouldRetry === "true")
|
|
104
|
-
return "retrying";
|
|
105
|
-
if (event.payload.shadow === "true")
|
|
106
|
-
return "shadow";
|
|
107
|
-
return "not-retried";
|
|
108
|
-
}
|
|
109
89
|
function durationMs(run) {
|
|
110
90
|
if (run.endedAt === undefined)
|
|
111
91
|
return 0;
|
|
@@ -205,7 +185,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
|
|
|
205
185
|
integrations: section,
|
|
206
186
|
publications: section,
|
|
207
187
|
events: section,
|
|
208
|
-
|
|
188
|
+
agentErrors: section,
|
|
209
189
|
workItems: section,
|
|
210
190
|
orchestration: section,
|
|
211
191
|
storage: section,
|
|
@@ -378,13 +358,13 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
|
|
|
378
358
|
const history = Array.isArray(set.history) ? set.history : [];
|
|
379
359
|
for (const session of [...history, ...Object.values(set.sessions)]) {
|
|
380
360
|
generations += 1;
|
|
381
|
-
if (session.status === "
|
|
361
|
+
if (session.status === "ended" && session.endReason === "failed")
|
|
382
362
|
broken += 1;
|
|
383
|
-
else if (session.status === "
|
|
363
|
+
else if (session.status === "ended")
|
|
384
364
|
stopped += 1;
|
|
385
365
|
else
|
|
386
366
|
other += 1;
|
|
387
|
-
if (session.status === "
|
|
367
|
+
if (session.status === "ended") {
|
|
388
368
|
classifyTerminalSessionRunRelation(runs, set.owner.roleName, session, terminalByRunRelation);
|
|
389
369
|
}
|
|
390
370
|
}
|
|
@@ -608,51 +588,38 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
|
|
|
608
588
|
return failed(error);
|
|
609
589
|
}
|
|
610
590
|
})();
|
|
611
|
-
const
|
|
591
|
+
const agentErrors = (() => {
|
|
612
592
|
try {
|
|
613
|
-
const entries =
|
|
593
|
+
const entries = [];
|
|
594
|
+
const categories = new Map();
|
|
614
595
|
for (const taskId of taskIds) {
|
|
615
596
|
for (const event of store.listEvents(taskId)) {
|
|
616
|
-
if (!inWindow(event.createdAt, options))
|
|
617
|
-
continue;
|
|
618
|
-
if (!event.type.startsWith("runtime.provider-retry-"))
|
|
619
|
-
continue;
|
|
620
|
-
const runId = event.payload.runId;
|
|
621
|
-
if (typeof runId !== "string")
|
|
597
|
+
if (!inWindow(event.createdAt, options) || event.type !== "runtime.agent-error") {
|
|
622
598
|
continue;
|
|
623
|
-
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
const terminal = decision === "session-dead" || decision === "budget-exhausted";
|
|
628
|
-
const next = {
|
|
599
|
+
}
|
|
600
|
+
const category = event.payload.category ?? "unknown";
|
|
601
|
+
categories.set(category, (categories.get(category) ?? 0) + 1);
|
|
602
|
+
entries.push({
|
|
629
603
|
taskId,
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
? { lastBackoffAt: previous.lastBackoffAt }
|
|
644
|
-
: {}),
|
|
645
|
-
decision,
|
|
646
|
-
terminal: (previous?.terminal ?? false) || terminal
|
|
647
|
-
};
|
|
648
|
-
entries.set(key, next);
|
|
604
|
+
eventId: event.id,
|
|
605
|
+
runId: event.payload.runId ?? "",
|
|
606
|
+
roleName: event.payload.roleName ?? "",
|
|
607
|
+
source: event.payload.source ?? "unknown",
|
|
608
|
+
phase: event.payload.phase ?? "unknown",
|
|
609
|
+
category,
|
|
610
|
+
code: event.payload.code ?? "unknown",
|
|
611
|
+
message: event.payload.message ?? "",
|
|
612
|
+
raw: event.payload.raw ?? "",
|
|
613
|
+
inputDisposition: event.payload.inputDisposition ?? "unknown",
|
|
614
|
+
sessionDisposition: event.payload.sessionDisposition ?? "unknown",
|
|
615
|
+
createdAt: event.createdAt
|
|
616
|
+
});
|
|
649
617
|
}
|
|
650
618
|
}
|
|
651
|
-
const list = [...entries.values()];
|
|
652
619
|
return ok({
|
|
653
|
-
total:
|
|
654
|
-
|
|
655
|
-
entries
|
|
620
|
+
total: entries.length,
|
|
621
|
+
byCategory: Object.fromEntries(categories),
|
|
622
|
+
entries
|
|
656
623
|
});
|
|
657
624
|
}
|
|
658
625
|
catch (error) {
|
|
@@ -748,16 +715,10 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
|
|
|
748
715
|
try {
|
|
749
716
|
const protocolVersions = new Map();
|
|
750
717
|
const manifestDigests = new Set();
|
|
751
|
-
const
|
|
718
|
+
const agentErrorCategories = new Map();
|
|
752
719
|
const exitClassifications = new Map();
|
|
753
720
|
const usageSemantics = new Map();
|
|
754
|
-
let
|
|
755
|
-
let activeConsecutiveFailures = 0;
|
|
756
|
-
let activeDispatchedRetries = 0;
|
|
757
|
-
let retryClassifiedEvents = 0;
|
|
758
|
-
let retryDispatchedEvents = 0;
|
|
759
|
-
let retryRecoveredEvents = 0;
|
|
760
|
-
let retryExhaustedEvents = 0;
|
|
721
|
+
let agentErrors = 0;
|
|
761
722
|
let contextCapacityFailures = 0;
|
|
762
723
|
let processExitObservations = 0;
|
|
763
724
|
let compactionEvents = 0;
|
|
@@ -770,26 +731,17 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
|
|
|
770
731
|
if (run.effective.sessionManifestCompatibilityDigest !== undefined) {
|
|
771
732
|
manifestDigests.add(run.effective.sessionManifestCompatibilityDigest);
|
|
772
733
|
}
|
|
773
|
-
if (run.providerRetry !== undefined) {
|
|
774
|
-
activeRetryEpisodes += 1;
|
|
775
|
-
retryStates.set(run.providerRetry.state, (retryStates.get(run.providerRetry.state) ?? 0) + 1);
|
|
776
|
-
activeConsecutiveFailures += run.providerRetry.consecutiveFailures;
|
|
777
|
-
activeDispatchedRetries += run.providerRetry.dispatchedRetries;
|
|
778
|
-
}
|
|
779
734
|
}
|
|
780
735
|
for (const event of store.listEvents(taskId)) {
|
|
781
736
|
if (!inWindow(event.createdAt, options))
|
|
782
737
|
continue;
|
|
783
|
-
if (event.type === "runtime.
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
retryExhaustedEvents += 1;
|
|
791
|
-
else if (event.type === "runtime.context-capacity-failure")
|
|
792
|
-
contextCapacityFailures += 1;
|
|
738
|
+
if (event.type === "runtime.agent-error") {
|
|
739
|
+
agentErrors += 1;
|
|
740
|
+
const category = event.payload.category ?? "unknown";
|
|
741
|
+
agentErrorCategories.set(category, (agentErrorCategories.get(category) ?? 0) + 1);
|
|
742
|
+
if (category === "context")
|
|
743
|
+
contextCapacityFailures += 1;
|
|
744
|
+
}
|
|
793
745
|
else if (event.type === "runtime.process-exit-observed") {
|
|
794
746
|
processExitObservations += 1;
|
|
795
747
|
const classification = event.payload.classification ?? "unknown";
|
|
@@ -808,14 +760,8 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
|
|
|
808
760
|
return ok({
|
|
809
761
|
contextProtocolVersions: Object.fromEntries(protocolVersions),
|
|
810
762
|
manifestCompatibilityDigests: manifestDigests.size,
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
activeConsecutiveFailures,
|
|
814
|
-
activeDispatchedRetries,
|
|
815
|
-
retryClassifiedEvents,
|
|
816
|
-
retryDispatchedEvents,
|
|
817
|
-
retryRecoveredEvents,
|
|
818
|
-
retryExhaustedEvents,
|
|
763
|
+
agentErrors,
|
|
764
|
+
agentErrorCategories: Object.fromEntries(agentErrorCategories),
|
|
819
765
|
contextCapacityFailures,
|
|
820
766
|
processExitObservations,
|
|
821
767
|
processExitClassifications: Object.fromEntries(exitClassifications),
|
|
@@ -870,7 +816,7 @@ export function runExecutionAudit(home, options = {}, ports = createProductionEx
|
|
|
870
816
|
integrations,
|
|
871
817
|
publications,
|
|
872
818
|
events,
|
|
873
|
-
|
|
819
|
+
agentErrors,
|
|
874
820
|
workItems,
|
|
875
821
|
orchestration,
|
|
876
822
|
storage,
|
|
@@ -25,7 +25,7 @@ export function projectOperatorStatus(sessions, activeAgentId, activeAdapterId)
|
|
|
25
25
|
}
|
|
26
26
|
return Object.freeze({
|
|
27
27
|
writer: {
|
|
28
|
-
state: matchingActive.status === "
|
|
28
|
+
state: matchingActive.status === "ended" ? "inactive" : "active",
|
|
29
29
|
agentId: matchingActive.agentId,
|
|
30
30
|
adapterId: matchingActive.adapterId,
|
|
31
31
|
sessionRef: activeRef,
|
|
@@ -42,7 +42,7 @@ export function listOperatorSessions(sessions) {
|
|
|
42
42
|
if (sessions === null)
|
|
43
43
|
return [];
|
|
44
44
|
validateRoleSessionSet(sessions);
|
|
45
|
-
const current = Object.values(sessions.sessions).map((session) => (listItem(session, session.status === "
|
|
45
|
+
const current = Object.values(sessions.sessions).map((session) => (listItem(session, session.status === "ended"
|
|
46
46
|
? "current"
|
|
47
47
|
: "running")));
|
|
48
48
|
const history = Object.values(sessions.history ?? {}).map((session) => (listItem(session, "history")));
|
|
@@ -92,7 +92,8 @@ export function prepareOperatorResumeSession(sessions, ref, now) {
|
|
|
92
92
|
delete history[normalizedRef];
|
|
93
93
|
nextSessions[selected.agentId] = {
|
|
94
94
|
...selected,
|
|
95
|
-
status: "
|
|
95
|
+
status: "ended",
|
|
96
|
+
endReason: "stopped",
|
|
96
97
|
updatedAt: requireDate(now)
|
|
97
98
|
};
|
|
98
99
|
return validateRoleSessionSet({
|
|
@@ -104,12 +105,13 @@ export function prepareOperatorResumeSession(sessions, ref, now) {
|
|
|
104
105
|
});
|
|
105
106
|
}
|
|
106
107
|
function archiveCurrent(history, session) {
|
|
107
|
-
if (session.status !== "
|
|
108
|
+
if (session.status !== "ended") {
|
|
108
109
|
throw new Error(`Cannot replace Operator session while its native process is ${session.status}.`);
|
|
109
110
|
}
|
|
110
111
|
const archived = {
|
|
111
112
|
...session,
|
|
112
|
-
status: "
|
|
113
|
+
status: "ended",
|
|
114
|
+
endReason: session.endReason ?? "stopped"
|
|
113
115
|
};
|
|
114
116
|
return {
|
|
115
117
|
...history,
|
package/dist/role/role.js
CHANGED
|
@@ -130,7 +130,7 @@ export function unbindRoleAgent(role, sessions, agentId, now) {
|
|
|
130
130
|
throw new Error(`Cannot unbind Role Agent with an active Run: ${normalizedAgentId}.`);
|
|
131
131
|
}
|
|
132
132
|
const targetSession = sessions.sessions[normalizedAgentId];
|
|
133
|
-
if (targetSession !== undefined && targetSession.status
|
|
133
|
+
if (targetSession !== undefined && targetSession.status === "active") {
|
|
134
134
|
throw new Error(`Cannot unbind Role Agent while its native session is ${targetSession.status}: `
|
|
135
135
|
+ `${normalizedAgentId}.`);
|
|
136
136
|
}
|
package/dist/run/agentRun.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { validateEffectiveLaunchSnapshot } from "../executor/effectiveLaunch.js";
|
|
2
2
|
import { formatAgentRunReceiptId, validateTaskRecordReference } from "../task/taskRecordReference.js";
|
|
3
|
-
import { prepareProviderRetryDispatch, validateAgentRunProviderRetry } from "./providerRetry.js";
|
|
4
3
|
import { validateYieldReceipt } from "./yieldReceipt.js";
|
|
5
4
|
import { validateAgentRunControlRequest } from "./runControlRequest.js";
|
|
6
5
|
import { validateManagedWorkspace } from "../worktree/managedWorkspace.js";
|
|
@@ -30,7 +29,7 @@ export function createAgentRun(id, taskId, roleName, mode, assignment, now, cont
|
|
|
30
29
|
})
|
|
31
30
|
: validateRunAssignment(assignment);
|
|
32
31
|
return {
|
|
33
|
-
schemaVersion:
|
|
32
|
+
schemaVersion: 10,
|
|
34
33
|
id: requireSafeIdentity(id, "Agent run id"),
|
|
35
34
|
taskId: requireSafeIdentity(taskId, "Task id"),
|
|
36
35
|
roleName: requireSafeIdentity(roleName, "Role name"),
|
|
@@ -104,8 +103,8 @@ export function markAgentRunDelivered(run, now) {
|
|
|
104
103
|
};
|
|
105
104
|
}
|
|
106
105
|
export function validateAgentRun(run) {
|
|
107
|
-
if (run.schemaVersion !==
|
|
108
|
-
throw new Error("Agent run must use schemaVersion
|
|
106
|
+
if (run.schemaVersion !== 10)
|
|
107
|
+
throw new Error("Agent run must use schemaVersion 10.");
|
|
109
108
|
validateTaskRecordReference({ taskId: run.taskId, localId: run.id }, "agentRun");
|
|
110
109
|
requireSafeIdentity(run.roleName, "Role name");
|
|
111
110
|
if (run.mode !== "new" && run.mode !== "resume") {
|
|
@@ -266,12 +265,6 @@ export function validateAgentRun(run) {
|
|
|
266
265
|
}
|
|
267
266
|
}
|
|
268
267
|
}
|
|
269
|
-
if (run.providerRetry !== undefined) {
|
|
270
|
-
validateAgentRunProviderRetry(run.providerRetry);
|
|
271
|
-
if (run.status !== "active") {
|
|
272
|
-
throw new Error("A terminal Agent run cannot carry a providerRetry projection.");
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
268
|
if (run.controlRequest !== undefined) {
|
|
276
269
|
validateAgentRunControlRequest(run.controlRequest);
|
|
277
270
|
if (run.status !== "active") {
|
|
@@ -304,60 +297,17 @@ function finishAgentRun(run, status, summary, now) {
|
|
|
304
297
|
updatedAt: timestamp,
|
|
305
298
|
endedAt: timestamp
|
|
306
299
|
};
|
|
307
|
-
// A terminal Run no longer waits for a retry; the projection is cleared so
|
|
308
|
-
// old and new readers agree the Run is settled.
|
|
309
|
-
if (terminal.providerRetry !== undefined) {
|
|
310
|
-
delete terminal.providerRetry;
|
|
311
|
-
}
|
|
312
300
|
if (terminal.controlRequest !== undefined)
|
|
313
301
|
delete terminal.controlRequest;
|
|
314
302
|
return terminal;
|
|
315
303
|
}
|
|
316
|
-
/**
|
|
317
|
-
* Attaches (or advances) the Issue 04 in-place retry projection on an active
|
|
318
|
-
* Run. The Run stays `active`; only the projection changes.
|
|
319
|
-
*/
|
|
320
|
-
export function withProviderRetry(run, retry) {
|
|
321
|
-
if (run.status !== "active") {
|
|
322
|
-
throw new Error(`Cannot schedule provider retry on a terminal Agent run: ${run.id}.`);
|
|
323
|
-
}
|
|
324
|
-
return validateAgentRun({ ...run, providerRetry: retry });
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* Reopens an active retry-waiting Run for another in-place attempt on its
|
|
328
|
-
* original Native Session. The original Run transport/acceptance timestamps
|
|
329
|
-
* remain historical facts; the new delivery receipt and `dispatching` retry
|
|
330
|
-
* state make the delivery path send only the short continuation envelope.
|
|
331
|
-
*/
|
|
332
|
-
export function reopenRunForProviderRetry(run, receiptId, now, mode = "resume") {
|
|
333
|
-
if (run.status !== "active" || run.providerRetry === undefined) {
|
|
334
|
-
throw new Error(`Agent run is not waiting for a provider retry: ${run.id}.`);
|
|
335
|
-
}
|
|
336
|
-
const timestamp = now.toISOString();
|
|
337
|
-
const { providerRetry, ...rest } = run;
|
|
338
|
-
return validateAgentRun({
|
|
339
|
-
...rest,
|
|
340
|
-
mode,
|
|
341
|
-
deliveryReceiptId: receiptId,
|
|
342
|
-
updatedAt: timestamp,
|
|
343
|
-
providerRetry: prepareProviderRetryDispatch(providerRetry, receiptId, now)
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
/** Any exact correlated provider progress ends the active consecutive-failure episode. */
|
|
347
|
-
export function clearProviderRetryOnProgress(run) {
|
|
348
|
-
if (run.providerRetry === undefined)
|
|
349
|
-
return run;
|
|
350
|
-
const { providerRetry: _providerRetry, ...rest } = run;
|
|
351
|
-
return validateAgentRun(rest);
|
|
352
|
-
}
|
|
353
304
|
export function agentRunDeliveryReceiptId(run) {
|
|
354
305
|
return run.deliveryReceiptId
|
|
355
306
|
?? run.controlRequest?.receiptId
|
|
356
|
-
?? run.providerRetry?.lastRetryReceiptId
|
|
357
307
|
?? formatAgentRunReceiptId(run.taskId, run.id);
|
|
358
308
|
}
|
|
359
309
|
export function withAgentRunControlRequest(run, request, now) {
|
|
360
|
-
if (run.status !== "active"
|
|
310
|
+
if (run.status !== "active") {
|
|
361
311
|
throw new Error(`Agent run cannot accept a control request: ${run.id}.`);
|
|
362
312
|
}
|
|
363
313
|
return validateAgentRun({
|
|
@@ -233,6 +233,7 @@ export class AgentDriverRegistry {
|
|
|
233
233
|
}
|
|
234
234
|
if (typeof input.runtime.nativeSessionId !== "function"
|
|
235
235
|
|| typeof input.runtime.nativeTurnId !== "function"
|
|
236
|
+
|| typeof input.runtime.mapError !== "function"
|
|
236
237
|
|| typeof input.runtime.mapHook !== "function"
|
|
237
238
|
|| typeof input.runtime.classifyHook !== "function"
|
|
238
239
|
|| (input.runtime.observer !== undefined
|
|
@@ -249,6 +250,7 @@ export class AgentDriverRegistry {
|
|
|
249
250
|
runtime: Object.freeze({
|
|
250
251
|
nativeSessionId: input.runtime.nativeSessionId,
|
|
251
252
|
nativeTurnId: input.runtime.nativeTurnId,
|
|
253
|
+
mapError: input.runtime.mapError,
|
|
252
254
|
mapHook: input.runtime.mapHook,
|
|
253
255
|
classifyHook: input.runtime.classifyHook,
|
|
254
256
|
...(input.runtime.observer === undefined
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-neutral Agent failure facts.
|
|
3
|
+
*
|
|
4
|
+
* Drivers recognize provider-native failures. Core persists the resulting
|
|
5
|
+
* facts and routes them to an Agent; it does not attach a recovery policy.
|
|
6
|
+
* `unknown` is the required fallback and the complete native payload is always
|
|
7
|
+
* retained in `raw`.
|
|
8
|
+
*/
|
|
9
|
+
export const AGENT_ERROR_CATEGORIES = Object.freeze([
|
|
10
|
+
"availability",
|
|
11
|
+
"rate-limit",
|
|
12
|
+
"transport",
|
|
13
|
+
"access",
|
|
14
|
+
"invalid-request",
|
|
15
|
+
"context",
|
|
16
|
+
"session",
|
|
17
|
+
"runtime",
|
|
18
|
+
"conflict",
|
|
19
|
+
"cancelled",
|
|
20
|
+
"unknown"
|
|
21
|
+
]);
|
|
22
|
+
export function standardAgentError(input) {
|
|
23
|
+
const classification = input.classification ?? UNKNOWN_AGENT_ERROR_CLASSIFICATION;
|
|
24
|
+
const retryAfterMs = input.retryAfterMs;
|
|
25
|
+
if (retryAfterMs !== undefined
|
|
26
|
+
&& (!Number.isSafeInteger(retryAfterMs) || retryAfterMs < 0)) {
|
|
27
|
+
throw new Error("Agent error retryAfterMs must be a non-negative safe integer.");
|
|
28
|
+
}
|
|
29
|
+
return Object.freeze({
|
|
30
|
+
source: input.source,
|
|
31
|
+
phase: input.phase,
|
|
32
|
+
category: classification.category,
|
|
33
|
+
code: requiredErrorText(classification.code, "Agent error code"),
|
|
34
|
+
message: requiredErrorText(input.message, "Agent error message"),
|
|
35
|
+
raw: requiredErrorText(input.raw, "Agent error raw payload"),
|
|
36
|
+
inputDisposition: input.inputDisposition
|
|
37
|
+
?? classification.inputDisposition
|
|
38
|
+
?? "unknown",
|
|
39
|
+
sessionDisposition: input.sessionDisposition
|
|
40
|
+
?? classification.sessionDisposition
|
|
41
|
+
?? "unknown",
|
|
42
|
+
...(retryAfterMs === undefined ? {} : { retryAfterMs })
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
export const UNKNOWN_AGENT_ERROR_CLASSIFICATION = Object.freeze({
|
|
46
|
+
category: "unknown",
|
|
47
|
+
code: "unknown"
|
|
48
|
+
});
|
|
49
|
+
export function isAgentErrorCategory(value) {
|
|
50
|
+
return typeof value === "string"
|
|
51
|
+
&& AGENT_ERROR_CATEGORIES.includes(value);
|
|
52
|
+
}
|
|
53
|
+
export function isStandardAgentError(value) {
|
|
54
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
55
|
+
return false;
|
|
56
|
+
const error = value;
|
|
57
|
+
return ["provider", "driver", "host", "yui"].includes(error.source ?? "")
|
|
58
|
+
&& [
|
|
59
|
+
"host-start",
|
|
60
|
+
"session-start",
|
|
61
|
+
"session-restore",
|
|
62
|
+
"turn-submit",
|
|
63
|
+
"turn-execute",
|
|
64
|
+
"turn-reconcile",
|
|
65
|
+
"host-stop"
|
|
66
|
+
].includes(error.phase ?? "")
|
|
67
|
+
&& isAgentErrorCategory(error.category)
|
|
68
|
+
&& isErrorText(error.code)
|
|
69
|
+
&& isErrorText(error.message)
|
|
70
|
+
&& isErrorText(error.raw)
|
|
71
|
+
&& ["accepted", "not-accepted", "unknown"].includes(error.inputDisposition ?? "")
|
|
72
|
+
&& ["recoverable", "unrecoverable", "unknown"].includes(error.sessionDisposition ?? "")
|
|
73
|
+
&& (error.retryAfterMs === undefined
|
|
74
|
+
|| (Number.isSafeInteger(error.retryAfterMs) && error.retryAfterMs >= 0));
|
|
75
|
+
}
|
|
76
|
+
export function serializeAgentErrorRaw(value) {
|
|
77
|
+
if (typeof value === "string")
|
|
78
|
+
return requiredErrorText(value, "Agent error raw payload");
|
|
79
|
+
if (value === undefined)
|
|
80
|
+
return "Agent operation failed without an error payload.";
|
|
81
|
+
try {
|
|
82
|
+
const seen = new WeakSet();
|
|
83
|
+
const serialized = JSON.stringify(value, (_key, member) => {
|
|
84
|
+
if (typeof member === "bigint")
|
|
85
|
+
return member.toString();
|
|
86
|
+
if (member !== null && typeof member === "object") {
|
|
87
|
+
if (seen.has(member))
|
|
88
|
+
return "[Circular]";
|
|
89
|
+
seen.add(member);
|
|
90
|
+
if (member instanceof Error) {
|
|
91
|
+
return Object.fromEntries(Object.getOwnPropertyNames(member).map((name) => [
|
|
92
|
+
name,
|
|
93
|
+
member[name]
|
|
94
|
+
]));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return member;
|
|
98
|
+
});
|
|
99
|
+
return serialized === undefined
|
|
100
|
+
? String(value)
|
|
101
|
+
: requiredErrorText(serialized, "Agent error raw payload");
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return requiredErrorText(String(value), "Agent error raw payload");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function isErrorText(value) {
|
|
108
|
+
return typeof value === "string" && value.trim().length > 0 && !value.includes("\0");
|
|
109
|
+
}
|
|
110
|
+
function requiredErrorText(value, label) {
|
|
111
|
+
if (!isErrorText(value))
|
|
112
|
+
throw new Error(`${label} is required.`);
|
|
113
|
+
return value;
|
|
114
|
+
}
|