@zq-silk/yui 0.13.7 → 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/ARCHITECTURE.md +40 -4
- package/README.md +23 -4
- package/dist/cli/commandCatalog.js +21 -2
- package/dist/cli/updatePorts.js +4 -4
- package/dist/cli.js +43 -14
- 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 +93 -21
- package/dist/commands/taskContextCommand.js +1 -1
- package/dist/commands/taskExecutionCommands.js +0 -5
- package/dist/commands/taskOverviewCommand.js +5 -1
- package/dist/commands/taskRoleRuntimeStatus.js +3 -16
- package/dist/config/configCatalog.js +1 -6
- package/dist/config/yuiConfig.js +0 -79
- package/dist/context/sessionBootstrapManifest.js +26 -23
- package/dist/controller/clientRuntime.js +40 -3
- package/dist/controller/controller.js +29 -54
- package/dist/controller/fileSchedulerStoreAdapter.js +372 -1117
- 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 +103 -93
- package/dist/executor/executorRegistry.js +8 -20
- package/dist/executor/fileRoleLaunchPlanner.js +26 -93
- package/dist/executor/turnCompletion.js +5 -5
- package/dist/lifecycle/exactRunTerminalization.js +2 -4
- package/dist/observability/executionAudit.js +40 -94
- package/dist/operator/operatorSessionHistory.js +7 -5
- package/dist/output/rolePresentation.js +0 -1
- package/dist/repository/taskWorkspacePreparer.js +0 -1
- package/dist/role/role.js +13 -21
- 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 +1 -2
- package/dist/runtime/launchBroker.js +5 -19
- package/dist/runtime/lifecycleReservation.js +20 -4
- package/dist/runtime/providerRuntimeIdentity.js +11 -19
- 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 +220 -178
- package/dist/scheduler/activeTaskProgress.js +1 -4
- package/dist/scheduler/leaderWakeupProcessor.js +123 -88
- package/dist/scheduler/roleRunLiveness.js +4 -1
- package/dist/scheduler/roleRunStall.js +10 -14
- package/dist/scheduler/wakeReason.js +4 -0
- package/dist/storage/migration/productionRegistry.js +475 -0
- package/dist/storage/sqliteSchema.js +54 -2
- package/dist/storage/sqliteStore.js +11 -44
- package/dist/storage/taskStore.js +8 -36
- package/dist/web/webSnapshot.js +3 -0
- package/i18n/README.zh-CN.md +11 -3
- 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 +11 -8
- 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
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/** Provider-specific Claude Code failure recognition. */
|
|
2
|
+
export function mapClaudeAgentError(input) {
|
|
3
|
+
const text = `${input.message}\n${input.raw}`;
|
|
4
|
+
if (/^server_error$/iu.test(input.message) || /\bapi_error\b/iu.test(text)) {
|
|
5
|
+
return recoverable("availability", "provider.server-error");
|
|
6
|
+
}
|
|
7
|
+
if (/^overloaded_error$/iu.test(input.message) || /\boverloaded\b/iu.test(text)) {
|
|
8
|
+
return recoverable("availability", "provider.overloaded");
|
|
9
|
+
}
|
|
10
|
+
if (/^rate_limit_error$/iu.test(input.message) || /rate[\s_-]?limit/iu.test(text)) {
|
|
11
|
+
return recoverable("rate-limit", "provider.rate-limit");
|
|
12
|
+
}
|
|
13
|
+
if (/^(authentication_error|permission_error)$/iu.test(input.message)) {
|
|
14
|
+
return classification("access", "provider.access-denied");
|
|
15
|
+
}
|
|
16
|
+
if (/^not_found_error$/iu.test(input.message)) {
|
|
17
|
+
return sessionUnavailable("provider.session-not-found");
|
|
18
|
+
}
|
|
19
|
+
return mapSharedAgentError(text, "claude-code");
|
|
20
|
+
}
|
|
21
|
+
/** Provider-specific Codex failure recognition. */
|
|
22
|
+
export function mapCodexAgentError(input) {
|
|
23
|
+
const text = `${input.message}\n${input.raw}`;
|
|
24
|
+
if (/^server_error$/iu.test(input.message)) {
|
|
25
|
+
return recoverable("availability", "provider.server-error");
|
|
26
|
+
}
|
|
27
|
+
if (/^overloaded_error$/iu.test(input.message)
|
|
28
|
+
|| /selected model is at capacity/iu.test(text)
|
|
29
|
+
|| /\bmodel\b.*\bat capacity\b/iu.test(text)) {
|
|
30
|
+
return recoverable("availability", "provider.model-capacity");
|
|
31
|
+
}
|
|
32
|
+
if (/^rate_limit_error$/iu.test(input.message)) {
|
|
33
|
+
return recoverable("rate-limit", "provider.rate-limit");
|
|
34
|
+
}
|
|
35
|
+
if (/^(authentication_error|permission_error)$/iu.test(input.message)) {
|
|
36
|
+
return classification("access", "provider.access-denied");
|
|
37
|
+
}
|
|
38
|
+
if (/\[codex:(unrecognized_model|invalid_model|model_not_found)\]/iu.test(text)
|
|
39
|
+
|| /model.*not supported|invalid.*model|model.*not found/iu.test(text)) {
|
|
40
|
+
return classification("invalid-request", "provider.invalid-model");
|
|
41
|
+
}
|
|
42
|
+
if (/stream disconnected/iu.test(text)) {
|
|
43
|
+
return recoverable("transport", "transport.stream-disconnected");
|
|
44
|
+
}
|
|
45
|
+
return mapSharedAgentError(text, "codex");
|
|
46
|
+
}
|
|
47
|
+
function mapSharedAgentError(text, namespace) {
|
|
48
|
+
if (/stream error:.*INTERNAL_ERROR/iu.test(text)) {
|
|
49
|
+
return recoverable("transport", "transport.stream-internal-error");
|
|
50
|
+
}
|
|
51
|
+
if (/stream error:.*PROTOCOL_ERROR/iu.test(text)) {
|
|
52
|
+
return recoverable("transport", "transport.stream-protocol-error");
|
|
53
|
+
}
|
|
54
|
+
if (/stream error/iu.test(text))
|
|
55
|
+
return recoverable("transport", "transport.stream-error");
|
|
56
|
+
if (/\b429\b/u.test(text) || /rate[\s_-]?limit/iu.test(text)) {
|
|
57
|
+
return recoverable("rate-limit", "provider.rate-limit");
|
|
58
|
+
}
|
|
59
|
+
if (/\b40[0-9]\b/u.test(text))
|
|
60
|
+
return classification("invalid-request", "provider.http-4xx");
|
|
61
|
+
if (/\b50[0-9]\b/u.test(text)
|
|
62
|
+
|| /bad gateway|service unavailable|temporarily unavailable/iu.test(text)) {
|
|
63
|
+
return recoverable("availability", "provider.http-5xx");
|
|
64
|
+
}
|
|
65
|
+
if (/server[\s_-]?error/iu.test(text)) {
|
|
66
|
+
return recoverable("availability", "provider.server-error");
|
|
67
|
+
}
|
|
68
|
+
if (/\boverloaded\b/iu.test(text)) {
|
|
69
|
+
return recoverable("availability", "provider.overloaded");
|
|
70
|
+
}
|
|
71
|
+
if (/gateway timeout|timed?[ -]?out|etimedout/iu.test(text)) {
|
|
72
|
+
return recoverable("transport", "transport.timeout");
|
|
73
|
+
}
|
|
74
|
+
if (/connection[\s_-]?reset|econnreset|socket hang up/iu.test(text)) {
|
|
75
|
+
return recoverable("transport", "transport.connection-reset");
|
|
76
|
+
}
|
|
77
|
+
if (/connection[\s_-]?lost/iu.test(text)) {
|
|
78
|
+
return recoverable("transport", "transport.connection-lost");
|
|
79
|
+
}
|
|
80
|
+
if (/\beconnrefused\b|connection refused|connect[^\n]*refused/iu.test(text)) {
|
|
81
|
+
return recoverable("transport", "transport.connection-refused");
|
|
82
|
+
}
|
|
83
|
+
if (/\bepipe\b|broken pipe/iu.test(text)) {
|
|
84
|
+
return recoverable("transport", "transport.broken-pipe");
|
|
85
|
+
}
|
|
86
|
+
if (/\b(?:enotfound|eai_again)\b|dns[^\n]*(?:failed|unavailable)/iu.test(text)) {
|
|
87
|
+
return recoverable("transport", "transport.name-resolution");
|
|
88
|
+
}
|
|
89
|
+
if (/\benoent\b[^\n]*(?:socket|agent-host)|no such file[^\n]*(?:socket|agent-host)/iu.test(text)) {
|
|
90
|
+
return recoverable("transport", "transport.endpoint-missing");
|
|
91
|
+
}
|
|
92
|
+
if (/delivery[^\n]*unknown|acknowledgement[^\n]*unknown/iu.test(text)) {
|
|
93
|
+
return Object.freeze({
|
|
94
|
+
category: "transport",
|
|
95
|
+
code: "transport.delivery-unknown",
|
|
96
|
+
inputDisposition: "unknown",
|
|
97
|
+
sessionDisposition: "recoverable"
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (/unsettled turn|turn[^\n]*busy|session[^\n]*busy|writer fence|writer authority|human writer/iu.test(text)) {
|
|
101
|
+
return Object.freeze({
|
|
102
|
+
category: "conflict",
|
|
103
|
+
code: "runtime.session-busy",
|
|
104
|
+
inputDisposition: "not-accepted",
|
|
105
|
+
sessionDisposition: "recoverable"
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
if (/cyber[_-]?policy|policy[\s_-]?violation|usage[\s_-]?policy|content[\s_-]?policy|safety[\s_-]?policy/iu.test(text)) {
|
|
109
|
+
return classification("access", "provider.policy-denied");
|
|
110
|
+
}
|
|
111
|
+
if (/maximum context length|context length exceeded|context window (?:is )?(?:full|exceeded)|prompt (?:is )?too long|too many tokens/iu.test(text)) {
|
|
112
|
+
return classification("context", "provider.context-capacity");
|
|
113
|
+
}
|
|
114
|
+
if (/session[\s_-]?not[\s_-]?found|no[\s_-]?such[\s_-]?(?:session|thread)|thread[\s_-]?not[\s_-]?found/iu.test(text)) {
|
|
115
|
+
return sessionUnavailable("provider.session-not-found");
|
|
116
|
+
}
|
|
117
|
+
if (/session[\s_-]?(?:has[\s_-]?)?expired/iu.test(text)) {
|
|
118
|
+
return sessionUnavailable("provider.session-expired");
|
|
119
|
+
}
|
|
120
|
+
if (/session[\s_-]?(?:has[\s_-]?)?ended/iu.test(text)) {
|
|
121
|
+
return sessionUnavailable("provider.session-ended");
|
|
122
|
+
}
|
|
123
|
+
if (/process[\s_-]?exited/iu.test(text)) {
|
|
124
|
+
return recoverable("runtime", "runtime.process-exited");
|
|
125
|
+
}
|
|
126
|
+
if (/invalid[\s_-]?request|validation[\s_-]?error|bad[\s_-]?request|unknown[\s_-]?(?:flag|tool|argument)|unexpected argument|invalid schema/iu.test(text)
|
|
127
|
+
|| (namespace === "codex"
|
|
128
|
+
? /\[codex:(?:unrecognized_model|invalid_model|model_not_found)\]/iu.test(text)
|
|
129
|
+
: /\[claude-code:(?:unrecognized_model|invalid_model|model_not_found)\]/iu.test(text))) {
|
|
130
|
+
return classification("invalid-request", "provider.invalid-request");
|
|
131
|
+
}
|
|
132
|
+
return classification("unknown", "unknown");
|
|
133
|
+
}
|
|
134
|
+
function classification(category, code) {
|
|
135
|
+
return Object.freeze({ category, code });
|
|
136
|
+
}
|
|
137
|
+
function recoverable(category, code) {
|
|
138
|
+
return Object.freeze({
|
|
139
|
+
category,
|
|
140
|
+
code,
|
|
141
|
+
sessionDisposition: "recoverable"
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function sessionUnavailable(code) {
|
|
145
|
+
return Object.freeze({
|
|
146
|
+
category: "session",
|
|
147
|
+
code,
|
|
148
|
+
sessionDisposition: "unrecoverable"
|
|
149
|
+
});
|
|
150
|
+
}
|
|
@@ -304,21 +304,16 @@ export function assertExactTaskRuntimeState(runtime, store, options = {}) {
|
|
|
304
304
|
&& isRuntimeLaunchReservation(lifecycleMailbox?.processing, runtime.launchId);
|
|
305
305
|
const sessionLaunch = runtime.launchId !== undefined
|
|
306
306
|
&& session?.launchId === runtime.launchId;
|
|
307
|
-
const executionRef = lifecycleMailbox?.processing?.executionRef;
|
|
308
307
|
const preallocated = options.preallocatedDriverSessionReservation;
|
|
309
|
-
const
|
|
310
|
-
&& runtime.launchId !== undefined
|
|
308
|
+
const exactHostLaunchReservation = runtime.launchId !== undefined
|
|
311
309
|
&& reservation
|
|
312
|
-
&& !hasRuntimeCleanupObligation(lifecycleMailbox)
|
|
313
|
-
|
|
314
|
-
&& executionRef.taskId === runtime.taskId
|
|
315
|
-
&& executionRef.id === runtime.runId;
|
|
316
|
-
const terminalSessionReplacementReservation = exactRunLaunchReservation
|
|
310
|
+
&& !hasRuntimeCleanupObligation(lifecycleMailbox);
|
|
311
|
+
const terminalSessionReplacementReservation = exactHostLaunchReservation
|
|
317
312
|
&& session !== undefined
|
|
318
|
-
&&
|
|
313
|
+
&& session.status === "ended";
|
|
319
314
|
const exactPreallocatedReservation = preallocated !== undefined
|
|
320
315
|
&& runtime.adapterId === preallocated.adapterId
|
|
321
|
-
&&
|
|
316
|
+
&& exactHostLaunchReservation
|
|
322
317
|
&& runtime.nativeSessionId !== undefined
|
|
323
318
|
&& (session === undefined || terminalSessionReplacementReservation)
|
|
324
319
|
&& runtime.nativeSessionId === nativeSessionIdForLaunch(preallocated.yuiHome, runtime.launchId, runtime.agentId, runtime.adapterId);
|
|
@@ -346,8 +341,7 @@ export function assertExactTaskRuntimeState(runtime, store, options = {}) {
|
|
|
346
341
|
|| session.adapterId !== runtime.adapterId
|
|
347
342
|
|| session.nativeSessionId !== runtime.nativeSessionId
|
|
348
343
|
|| session.launchId !== runtime.launchId
|
|
349
|
-
|| session.status === "
|
|
350
|
-
|| session.status === "broken"
|
|
344
|
+
|| session.status === "ended"
|
|
351
345
|
|| session.effective.agentId !== runtime.agentId
|
|
352
346
|
|| session.effective.adapterId !== runtime.adapterId
|
|
353
347
|
|| canonicalPath(session.effective.workspace.root) !== runtime.workspace) {
|
package/dist/runtime/index.js
CHANGED
|
@@ -14,8 +14,7 @@ export { formatRuntimeLaunchDiagnostic, redactLaunchArgument, redactLaunchText,
|
|
|
14
14
|
export { DEFAULT_FORCED_GRACE_MS, DEFAULT_GRACEFUL_GRACE_MS, terminateSessionOwners } from "./sessionTerminationGuard.js";
|
|
15
15
|
export { ProviderContinuationReconciliationService } from "./providerContinuationReconciliationService.js";
|
|
16
16
|
export { codexNotificationBoundary, codexAppServerErrorIsMissing, CodexAppServerRequestError, CodexAppServerRuntime } from "./codexAppServerRuntime.js";
|
|
17
|
-
export { createProviderRuntimeBinding, acceptProviderTurn, beginProviderTurn, currentProviderActivation, currentProviderAuthority, currentProviderConversation, endProviderActivation, markProviderTurnDeliveryUnknown,
|
|
17
|
+
export { createProviderRuntimeBinding, acceptProviderTurn, beginProviderTurn, currentProviderActivation, currentProviderAuthority, currentProviderConversation, endProviderActivation, markProviderTurnDeliveryUnknown, rejectProviderTurn, settleProviderTurnSubmission, settleProviderTurn, startProviderActivation, supersedeProviderConversation, transferProviderAuthority, updateProviderConversationRecoverability, validateProviderRuntimeBinding } from "./providerRuntimeIdentity.js";
|
|
18
18
|
export { FencedProviderControl } from "./providerControl.js";
|
|
19
19
|
export { sameProviderAuthorityFence, validateProviderAuthorityFence } from "./providerAuthorityFence.js";
|
|
20
|
-
export { decideProviderRecovery } from "./providerRecoveryDecision.js";
|
|
21
20
|
export { reconcileSessionOwners } from "./sessionReconciliation.js";
|
|
@@ -98,22 +98,16 @@ function validateProviderControl(control) {
|
|
|
98
98
|
if (control.mode !== "new" && control.mode !== "resume") {
|
|
99
99
|
throw new Error("Agent Host Provider control mode is invalid.");
|
|
100
100
|
}
|
|
101
|
-
if (control.kind !== "
|
|
101
|
+
if (control.kind !== "start" && control.kind !== "restore") {
|
|
102
102
|
throw new Error("Agent Host Provider control kind is invalid.");
|
|
103
103
|
}
|
|
104
|
-
if ((control.kind === "
|
|
104
|
+
if ((control.kind === "start") !== (control.mode === "new")) {
|
|
105
105
|
throw new Error("Agent Host Provider control kind does not match its transport mode.");
|
|
106
106
|
}
|
|
107
|
-
if (control.kind !== "
|
|
108
|
-
throw new Error("
|
|
107
|
+
if (control.kind !== "restore" && "ownedTurn" in control) {
|
|
108
|
+
throw new Error("Only Session restore can reconcile an owned Turn.");
|
|
109
109
|
}
|
|
110
|
-
if (control.kind === "
|
|
111
|
-
throw new Error("Managed Provider ensure launch cannot carry a new Turn.");
|
|
112
|
-
}
|
|
113
|
-
if (control.kind !== "ensure" && "ownedTurn" in control) {
|
|
114
|
-
throw new Error("Only a managed Provider ensure launch can recover an owned Turn.");
|
|
115
|
-
}
|
|
116
|
-
if (control.kind === "ensure" && control.ownedTurn !== undefined) {
|
|
110
|
+
if (control.kind === "restore" && control.ownedTurn !== undefined) {
|
|
117
111
|
if (control.adapterId !== "codex") {
|
|
118
112
|
throw new Error("Only Managed Codex can recover an owned Turn across client attachment.");
|
|
119
113
|
}
|
|
@@ -135,14 +129,6 @@ function validateProviderControl(control) {
|
|
|
135
129
|
}
|
|
136
130
|
}
|
|
137
131
|
validateProviderAuthorityFence(control.authority);
|
|
138
|
-
if (control.initialTurn !== undefined) {
|
|
139
|
-
text(control.initialTurn.attemptId, "Provider input attemptId");
|
|
140
|
-
if (typeof control.initialTurn.boundedText !== "string"
|
|
141
|
-
|| control.initialTurn.boundedText.includes("\0")
|
|
142
|
-
|| Buffer.byteLength(control.initialTurn.boundedText, "utf8") > 32 * 1024) {
|
|
143
|
-
throw new Error("Agent Host Provider input must be bounded bootstrap text.");
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
132
|
}
|
|
147
133
|
function validateCodexThreadOptions(options) {
|
|
148
134
|
if (options === null || typeof options !== "object" || Array.isArray(options)) {
|
|
@@ -2,6 +2,7 @@ import { mailboxHasWork } from "../coordination/workMailbox.js";
|
|
|
2
2
|
export const RUNTIME_LIFECYCLE_OWNER = "runtime-lifecycle";
|
|
3
3
|
export const RUNTIME_LAUNCH_RESERVED_REASON = "runtime-launch-reserved";
|
|
4
4
|
export const RUNTIME_CLEANUP_REQUIRED_REASON = "runtime-cleanup-required";
|
|
5
|
+
export const RUNTIME_HOST_DETACH_REQUIRED_REASON = "runtime-host-detach-required";
|
|
5
6
|
/**
|
|
6
7
|
* A Role runtime lifecycle lane already holds an in-flight operation (a
|
|
7
8
|
* launch reservation or a cleanup obligation). This is scheduler
|
|
@@ -42,10 +43,25 @@ export function hasRuntimeLaunchReservation(mailbox) {
|
|
|
42
43
|
return isRuntimeLaunchReservation(mailbox?.processing);
|
|
43
44
|
}
|
|
44
45
|
export function hasRuntimeCleanupObligation(mailbox) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
return runtimeCleanupDisposition(mailbox) !== null;
|
|
47
|
+
}
|
|
48
|
+
/** Explicit Session end dominates a coalesced physical Host detach request. */
|
|
49
|
+
export function runtimeCleanupDisposition(mailbox) {
|
|
50
|
+
const reasons = [
|
|
51
|
+
...(mailbox?.pending.normal?.reasons ?? []),
|
|
52
|
+
...(!isRuntimeLaunchReservation(mailbox?.processing)
|
|
53
|
+
? mailbox?.processing?.batch.reasons ?? []
|
|
54
|
+
: [])
|
|
55
|
+
];
|
|
56
|
+
if (reasons.includes(RUNTIME_CLEANUP_REQUIRED_REASON))
|
|
57
|
+
return "end-session";
|
|
58
|
+
if (reasons.includes(RUNTIME_HOST_DETACH_REQUIRED_REASON))
|
|
59
|
+
return "detach-host";
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
export function isRuntimeCleanupReason(reason) {
|
|
63
|
+
return reason === RUNTIME_CLEANUP_REQUIRED_REASON
|
|
64
|
+
|| reason === RUNTIME_HOST_DETACH_REQUIRED_REASON;
|
|
49
65
|
}
|
|
50
66
|
export function hasRuntimeLifecycleWork(mailbox) {
|
|
51
67
|
return mailbox !== null && mailboxHasWork(mailbox);
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
export function createProviderRuntimeBinding(input) {
|
|
2
2
|
const startedAt = timestamp(input.startedAt, "Provider Activation startedAt");
|
|
3
3
|
return validateProviderRuntimeBinding({
|
|
4
|
-
schemaVersion:
|
|
4
|
+
schemaVersion: 3,
|
|
5
5
|
providerNamespace: identity(input.providerNamespace, "Provider namespace"),
|
|
6
6
|
accountScope: identity(input.accountScope, "Provider account scope"),
|
|
7
|
-
runId: identity(input.runId, "Run id"),
|
|
8
7
|
currentConversationEpoch: 1,
|
|
9
8
|
conversations: [{
|
|
10
9
|
conversationId: identity(input.conversationId, "Provider Conversation id"),
|
|
@@ -40,17 +39,6 @@ export function currentProviderActivation(binding) {
|
|
|
40
39
|
const conversation = currentProviderConversation(binding);
|
|
41
40
|
return [...binding.activations].reverse().find((entry) => (entry.conversationId === conversation.conversationId && entry.status === "active")) ?? null;
|
|
42
41
|
}
|
|
43
|
-
/** Rebinds the live Conversation state to the next Yui Run without resetting authority. */
|
|
44
|
-
export function rebindProviderRuntimeRun(raw, runId) {
|
|
45
|
-
const binding = validateProviderRuntimeBinding(raw);
|
|
46
|
-
if (providerTurnIsActive(binding.turn)) {
|
|
47
|
-
throw new Error("Provider Runtime cannot bind another Run while a Turn is unsettled.");
|
|
48
|
-
}
|
|
49
|
-
return validateProviderRuntimeBinding({
|
|
50
|
-
...binding,
|
|
51
|
-
runId: identity(runId, "Run id")
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
42
|
export function startProviderActivation(raw, input) {
|
|
55
43
|
const binding = validateProviderRuntimeBinding(raw);
|
|
56
44
|
if (currentProviderActivation(binding) !== null) {
|
|
@@ -158,8 +146,10 @@ export function transferProviderAuthority(raw, input) {
|
|
|
158
146
|
}
|
|
159
147
|
export function beginProviderTurn(raw, input) {
|
|
160
148
|
const binding = validateProviderRuntimeBinding(raw);
|
|
149
|
+
const runId = identity(input.runId, "Run id");
|
|
161
150
|
const attemptId = identity(input.attemptId, "Provider input attempt id");
|
|
162
|
-
if (binding.turn?.
|
|
151
|
+
if (binding.turn?.runId === runId
|
|
152
|
+
&& binding.turn.attemptId === attemptId
|
|
163
153
|
&& binding.turn.authorityEpoch === input.authorityEpoch
|
|
164
154
|
&& binding.turn.status === "submitting") {
|
|
165
155
|
return binding;
|
|
@@ -176,6 +166,7 @@ export function beginProviderTurn(raw, input) {
|
|
|
176
166
|
return validateProviderRuntimeBinding({
|
|
177
167
|
...binding,
|
|
178
168
|
turn: {
|
|
169
|
+
runId,
|
|
179
170
|
attemptId,
|
|
180
171
|
authorityEpoch: input.authorityEpoch,
|
|
181
172
|
status: "submitting",
|
|
@@ -236,7 +227,7 @@ export function rejectProviderTurn(raw, input) {
|
|
|
236
227
|
}
|
|
237
228
|
});
|
|
238
229
|
}
|
|
239
|
-
/** Resolves an Agent Host submission
|
|
230
|
+
/** Resolves an Agent Host submission; an unknown delivery may later gain exact negative evidence. */
|
|
240
231
|
export function settleProviderTurnSubmission(raw, input) {
|
|
241
232
|
const binding = validateProviderRuntimeBinding(raw);
|
|
242
233
|
const attemptId = identity(input.attemptId, "Provider input attempt id");
|
|
@@ -245,7 +236,8 @@ export function settleProviderTurnSubmission(raw, input) {
|
|
|
245
236
|
}
|
|
246
237
|
if (binding.turn.status === input.status)
|
|
247
238
|
return binding;
|
|
248
|
-
if (binding.turn.status !== "submitting"
|
|
239
|
+
if (binding.turn.status !== "submitting"
|
|
240
|
+
&& !(binding.turn.status === "delivery-unknown" && input.status === "rejected")) {
|
|
249
241
|
throw new Error("Provider Turn does not match a resolvable delivery state.");
|
|
250
242
|
}
|
|
251
243
|
return input.status === "delivery-unknown"
|
|
@@ -350,11 +342,10 @@ export function supersedeProviderConversation(raw, input) {
|
|
|
350
342
|
});
|
|
351
343
|
}
|
|
352
344
|
export function validateProviderRuntimeBinding(value) {
|
|
353
|
-
if (value.schemaVersion !==
|
|
354
|
-
throw new Error("Provider Runtime Binding schemaVersion must be
|
|
345
|
+
if (value.schemaVersion !== 3)
|
|
346
|
+
throw new Error("Provider Runtime Binding schemaVersion must be 3.");
|
|
355
347
|
identity(value.providerNamespace, "Provider namespace");
|
|
356
348
|
identity(value.accountScope, "Provider account scope");
|
|
357
|
-
identity(value.runId, "Run id");
|
|
358
349
|
integer(value.currentConversationEpoch, 1, "Current Provider Conversation epoch");
|
|
359
350
|
if (!Array.isArray(value.conversations) || value.conversations.length === 0) {
|
|
360
351
|
throw new Error("Provider Runtime Binding requires a Conversation.");
|
|
@@ -459,6 +450,7 @@ export function validateProviderRuntimeBinding(value) {
|
|
|
459
450
|
return value;
|
|
460
451
|
}
|
|
461
452
|
function validateProviderTurn(turn, currentAuthorityEpoch) {
|
|
453
|
+
identity(turn.runId, "Run id");
|
|
462
454
|
identity(turn.attemptId, "Provider input attempt id");
|
|
463
455
|
integer(turn.authorityEpoch, 1, "Provider Turn authority epoch");
|
|
464
456
|
if (turn.authorityEpoch > currentAuthorityEpoch) {
|
|
@@ -5,27 +5,6 @@ export function createRuntimeBinding(input) {
|
|
|
5
5
|
const hostCreated = input.hostCreated === undefined
|
|
6
6
|
? undefined
|
|
7
7
|
: requireBoolean(input.hostCreated, "Runtime host-created flag");
|
|
8
|
-
const initialTurnRunId = input.initialTurnRunId === undefined
|
|
9
|
-
? undefined
|
|
10
|
-
: requireSafeIdentity(input.initialTurnRunId, "Initial Turn Run id");
|
|
11
|
-
const initialTurnDeliveryUnknownRunId = input.initialTurnDeliveryUnknownRunId === undefined
|
|
12
|
-
? undefined
|
|
13
|
-
: requireSafeIdentity(input.initialTurnDeliveryUnknownRunId, "Delivery-unknown initial Turn Run id");
|
|
14
|
-
const initialTurnRejectedRunId = input.initialTurnRejectedRunId === undefined
|
|
15
|
-
? undefined
|
|
16
|
-
: requireSafeIdentity(input.initialTurnRejectedRunId, "Rejected initial Turn Run id");
|
|
17
|
-
const initialTurnBusyRunId = input.initialTurnBusyRunId === undefined
|
|
18
|
-
? undefined
|
|
19
|
-
: requireSafeIdentity(input.initialTurnBusyRunId, "Busy initial Turn Run id");
|
|
20
|
-
if ([
|
|
21
|
-
initialTurnRunId,
|
|
22
|
-
initialTurnDeliveryUnknownRunId,
|
|
23
|
-
initialTurnBusyRunId,
|
|
24
|
-
initialTurnRejectedRunId
|
|
25
|
-
]
|
|
26
|
-
.filter((value) => value !== undefined).length > 1) {
|
|
27
|
-
throw new TypeError("Runtime binding must report at most one initial Turn outcome.");
|
|
28
|
-
}
|
|
29
8
|
return {
|
|
30
9
|
id: requireSafeIdentity(input.id, "Runtime binding id"),
|
|
31
10
|
launchId: requireSafeIdentity(input.launchId, "Launch id"),
|
|
@@ -34,12 +13,6 @@ export function createRuntimeBinding(input) {
|
|
|
34
13
|
adapterId: requireSafeIdentity(input.adapterId, "Agent adapter id"),
|
|
35
14
|
hostRef: requireText(input.hostRef, "Session host reference"),
|
|
36
15
|
...(hostCreated === undefined ? {} : { hostCreated }),
|
|
37
|
-
...(initialTurnRunId === undefined ? {} : { initialTurnRunId }),
|
|
38
|
-
...(initialTurnDeliveryUnknownRunId === undefined
|
|
39
|
-
? {}
|
|
40
|
-
: { initialTurnDeliveryUnknownRunId }),
|
|
41
|
-
...(initialTurnBusyRunId === undefined ? {} : { initialTurnBusyRunId }),
|
|
42
|
-
...(initialTurnRejectedRunId === undefined ? {} : { initialTurnRejectedRunId }),
|
|
43
16
|
...(input.nativeSessionId === undefined
|
|
44
17
|
? {}
|
|
45
18
|
: { nativeSessionId: requireText(input.nativeSessionId, "Native session id") }),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { requireDriverId } from "./agentDriver.js";
|
|
3
|
+
import { isStandardAgentError } from "./agentError.js";
|
|
3
4
|
export const RUNTIME_OBSERVATION_TASK_EVENT = "runtime.observation";
|
|
4
5
|
/**
|
|
5
6
|
* Numeric usage and value-less partial request boundaries are both durable
|
|
@@ -435,7 +436,7 @@ export function runtimeObservationSemanticKey(input) {
|
|
|
435
436
|
...continuationIdentity,
|
|
436
437
|
fence.continuationId ?? fence.nativeTurnId ?? "none",
|
|
437
438
|
input.kind,
|
|
438
|
-
input.payload?.outcome ?? input.payload?.failure?.code ?? "terminal",
|
|
439
|
+
input.payload?.outcome ?? input.payload?.failure?.error.code ?? "terminal",
|
|
439
440
|
input.kind === "continuation.settled" ? input.payload?.resultRef ?? "none" : "none",
|
|
440
441
|
input.kind === "turn.failed" && input.payload?.failure?.runTerminal === true
|
|
441
442
|
? "run-terminal"
|
|
@@ -494,21 +495,17 @@ function normalizeFailure(input) {
|
|
|
494
495
|
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
495
496
|
throw new Error("Runtime failure evidence must be an object.");
|
|
496
497
|
}
|
|
498
|
+
if (!isStandardAgentError(input.error)) {
|
|
499
|
+
throw new Error("Runtime failure requires a standard Agent error.");
|
|
500
|
+
}
|
|
497
501
|
return Object.freeze({
|
|
498
|
-
|
|
499
|
-
code: requireText(input.code, "Runtime failure code"),
|
|
500
|
-
...(input.details === undefined
|
|
501
|
-
? {}
|
|
502
|
-
: { details: requireText(input.details, "Runtime failure details") }),
|
|
502
|
+
error: Object.freeze({ ...input.error }),
|
|
503
503
|
...(input.lastOutput === undefined
|
|
504
504
|
? {}
|
|
505
505
|
: { lastOutput: requireText(input.lastOutput, "Runtime failure last output") }),
|
|
506
506
|
...(input.runTerminal === undefined
|
|
507
507
|
? {}
|
|
508
|
-
: { runTerminal: requireBoolean(input.runTerminal, "Runtime failure runTerminal") })
|
|
509
|
-
...(input.retryAfterMs === undefined
|
|
510
|
-
? {}
|
|
511
|
-
: { retryAfterMs: requirePositiveMilliseconds(input.retryAfterMs) })
|
|
508
|
+
: { runTerminal: requireBoolean(input.runTerminal, "Runtime failure runTerminal") })
|
|
512
509
|
});
|
|
513
510
|
}
|
|
514
511
|
function requireBoolean(value, label) {
|
|
@@ -516,12 +513,6 @@ function requireBoolean(value, label) {
|
|
|
516
513
|
throw new Error(`${label} must be boolean.`);
|
|
517
514
|
return value;
|
|
518
515
|
}
|
|
519
|
-
function requirePositiveMilliseconds(value) {
|
|
520
|
-
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
521
|
-
throw new Error("Runtime failure retryAfterMs must be a positive safe integer.");
|
|
522
|
-
}
|
|
523
|
-
return value;
|
|
524
|
-
}
|
|
525
516
|
function validateUsage(input) {
|
|
526
517
|
if (!["cumulative-session", "request-context", "remaining-context"].includes(input.semantics)) {
|
|
527
518
|
throw new Error("Runtime usage semantics are invalid.");
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import { activeRoleAgentSession } from "../executor/agentExecutor.js";
|
|
2
|
-
/**
|
|
3
|
-
export function runtimeSessionRequiresCleanup(input) {
|
|
4
|
-
if (input.status === "stopped" || input.status === "broken")
|
|
5
|
-
return false;
|
|
6
|
-
return input.status === "running" || input.launchId !== undefined;
|
|
7
|
-
}
|
|
8
|
-
/** Projects only the current active Agent Session; stopped history disappears. */
|
|
2
|
+
/** Projects only the current active Agent Session; ended history disappears. */
|
|
9
3
|
export function projectRuntimeSessionCandidate(sessions) {
|
|
10
4
|
const active = activeRoleAgentSession(sessions);
|
|
11
|
-
if (active === null || active.status === "
|
|
5
|
+
if (active === null || active.status === "ended")
|
|
12
6
|
return null;
|
|
13
7
|
return {
|
|
14
8
|
owner: sessions.owner.scope === "task"
|
|
@@ -22,9 +16,8 @@ export function projectRuntimeSessionCandidate(sessions) {
|
|
|
22
16
|
adapterId: active.adapterId,
|
|
23
17
|
nativeSessionId: active.nativeSessionId,
|
|
24
18
|
...(active.launchId === undefined ? {} : { launchId: active.launchId }),
|
|
25
|
-
status: active.status,
|
|
26
19
|
sessionUpdatedAt: active.updatedAt,
|
|
27
|
-
cleanupRequired:
|
|
20
|
+
cleanupRequired: active.launchId !== undefined
|
|
28
21
|
};
|
|
29
22
|
}
|
|
30
23
|
/** Deterministic owner order shared by all storage backends. */
|
|
@@ -18,8 +18,7 @@ export function createSessionLaunchRequest(input) {
|
|
|
18
18
|
if (runtimeIsolation !== undefined && (input.owner.scope !== "task"
|
|
19
19
|
|| runtimeIsolation.taskId !== input.owner.taskId
|
|
20
20
|
|| runtimeIsolation.workspace.root !== workspace
|
|
21
|
-
|| runtimeIsolation.generation.launchId !== input.launchId
|
|
22
|
-
|| runtimeIsolation.generation.runId !== input.runId)) {
|
|
21
|
+
|| runtimeIsolation.generation.launchId !== input.launchId)) {
|
|
23
22
|
throw new TypeError("Session launch request does not match its Task runtime isolation descriptor.");
|
|
24
23
|
}
|
|
25
24
|
const common = {
|
|
@@ -41,14 +41,14 @@ function reconcileOne(record, input) {
|
|
|
41
41
|
mismatch = "identity-conflict";
|
|
42
42
|
}
|
|
43
43
|
else if (physical?.alive === true) {
|
|
44
|
-
if (durable === undefined || durable.status === "
|
|
44
|
+
if (durable === undefined || durable.status === "ended") {
|
|
45
45
|
mismatch = "durable-terminal-physical-live";
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
else if (physical === undefined) {
|
|
49
49
|
verificationGap = "/proc identity unavailable";
|
|
50
50
|
}
|
|
51
|
-
else if (durable !== undefined && durable.status === "
|
|
51
|
+
else if (durable !== undefined && durable.status === "active") {
|
|
52
52
|
mismatch = "durable-live-physical-absent";
|
|
53
53
|
}
|
|
54
54
|
const terminalTask = taskStatus === "completed"
|