@zq-silk/yui 0.15.11 → 0.16.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.
- package/ARCHITECTURE.md +11 -6
- package/ARCHITECTURE.zh-CN.md +8 -4
- package/README.md +13 -5
- package/dist/agentRun/agentRun.js +3 -0
- package/dist/artifacts/artifactCommitLock.js +16 -55
- package/dist/artifacts/taskArtifactRepository.js +3 -3
- package/dist/cli/agentConfigurationPicker.js +1 -1
- package/dist/cli/commandCatalog.js +92 -48
- package/dist/cli/completion.js +18 -18
- package/dist/cli/completionWizard.js +1 -1
- package/dist/cli/dynamicCompletion.js +1 -1
- package/dist/cli/interactionPolicy.js +11 -3
- package/dist/cli/invocationAuthority.js +64 -0
- package/dist/cli/managedDiagnostics.js +2 -2
- package/dist/cli/parseRepeatable.js +35 -0
- package/dist/cli/updatePorts.js +26 -5
- package/dist/cli.js +1303 -1235
- package/dist/commands/agentCommands.js +4 -4
- package/dist/commands/capabilityCommands.js +1 -1
- package/dist/commands/configCommands.js +6 -57
- package/dist/commands/configOverview.js +2 -2
- package/dist/commands/durableJobCommands.js +12 -6
- package/dist/commands/executionAuditCommands.js +10 -0
- package/dist/commands/globalRoleCommands.js +78 -29
- package/dist/commands/grantCommands.js +0 -3
- package/dist/commands/jobCommands.js +1 -4
- package/dist/commands/operatorCommands.js +3 -3
- package/dist/commands/projectCommands.js +45 -25
- package/dist/commands/resourcesCommands.js +10 -40
- package/dist/commands/roleConfiguration.js +2 -6
- package/dist/commands/taskActivationCommands.js +4 -8
- package/dist/commands/taskAgentCapabilities.js +9 -0
- package/dist/commands/taskCommandSupport.js +155 -0
- package/dist/commands/taskCommandTypes.js +1 -0
- package/dist/commands/taskCommands.js +355 -732
- package/dist/commands/taskCompletionGate.js +1 -1
- package/dist/commands/taskExecutionCommands.js +1 -1
- package/dist/commands/taskFactCommands.js +325 -0
- package/dist/commands/taskInputCommands.js +12 -42
- package/dist/commands/taskIntegrationCommands.js +20 -58
- package/dist/commands/taskNextActionCommand.js +7 -6
- package/dist/commands/taskPublicationAdoptCommand.js +127 -0
- package/dist/commands/taskPublicationCommands.js +12 -3
- package/dist/commands/taskPublicationVerifyCommand.js +24 -40
- package/dist/commands/taskRemoteDeliveryCommand.js +5 -86
- package/dist/commands/taskUpstreamCommands.js +19 -8
- package/dist/commands/workflowCommands.js +6 -1
- package/dist/completion/completionInstaller.js +26 -26
- package/dist/completion/completionState.js +26 -26
- package/dist/completion/fileCompletionManager.js +6 -11
- package/dist/config/configCatalog.js +0 -2
- package/dist/config/timeZone.js +14 -0
- package/dist/config/yuiConfig.js +0 -29
- package/dist/context/runContextPack.js +5 -3
- package/dist/context/taskCatalog.js +185 -0
- package/dist/context/taskContext.js +152 -151
- package/dist/context/wakeRunReferences.js +11 -0
- package/dist/controller/agentCapabilities.js +58 -0
- package/dist/controller/agentRuntimeObserver.js +6 -11
- package/dist/controller/clientRuntime.js +22 -14
- package/dist/controller/controller.js +20 -24
- package/dist/controller/fileSchedulerStoreAdapter.js +191 -225
- package/dist/controller/globalInputDelivery.js +13 -0
- package/dist/controller/jobClient.js +4 -4
- package/dist/controller/jobControl.js +60 -25
- package/dist/controller/jobSupervisor.js +4 -4
- package/dist/controller/providerRetryAdmission.js +100 -0
- package/dist/controller/providerRetryDelivery.js +218 -0
- package/dist/controller/runtime.js +85 -43
- package/dist/controller/runtimeEventProcessor.js +0 -5
- package/dist/controller/sessionOwnerReconciliation.js +5 -0
- package/dist/controller/taskAgentError.js +35 -0
- package/dist/coordination/workMailboxQueue.js +2 -24
- package/dist/core/controllerClient.js +2 -2
- package/dist/core/fileLockOwner.js +74 -0
- package/dist/decision/decision.js +17 -0
- package/dist/doctor/doctor.js +18 -9
- package/dist/event/taskEvent.js +12 -0
- package/dist/execution/workItemExecutionProjection.js +2 -2
- package/dist/executor/agentCapabilityConfig.js +43 -0
- package/dist/executor/agentConfigurationCatalog.js +49 -11
- package/dist/executor/agentExecutor.js +5 -8
- package/dist/executor/fileRoleLaunchPlanner.js +11 -53
- package/dist/executor/taskAgentCapabilities.js +64 -0
- package/dist/integration/deliveryObligation.js +1 -69
- package/dist/integration/gitIntegrationService.js +79 -90
- package/dist/integration/integrationAttempt.js +3 -14
- package/dist/integration/integrationSourceApplication.js +4 -12
- package/dist/integration/manifestTags.js +2 -2
- package/dist/job/durableJob.js +4 -25
- package/dist/job/jobAssignmentScope.js +22 -0
- package/dist/job/jobOperation.js +16 -0
- package/dist/job/jobRunner.js +2 -1
- package/dist/job/stepDirectory.js +15 -0
- package/dist/kernel/builtinCapabilities.js +15 -11
- package/dist/kernel/kernelPorts.js +1 -17
- package/dist/lifecycle/exactRunTerminalization.js +5 -10
- package/dist/message/globalProviderRetry.js +15 -0
- package/dist/message/inputControlResolution.js +3 -4
- package/dist/message/message.js +17 -20
- package/dist/message/messageContinuation.js +1 -1
- package/dist/milestone/milestone.js +11 -0
- package/dist/observability/executionAudit.js +19 -0
- package/dist/observability/orchestrationMetrics.js +24 -1
- package/dist/observability/runtimeIdentity.js +1 -17
- package/dist/output/agentConfigurationPresentation.js +2 -0
- package/dist/output/timePresentation.js +1 -14
- package/dist/plugins/pluginService.js +12 -4
- package/dist/release/releaseWorkflowPorts.js +45 -96
- package/dist/release/runtimeRelease.js +9 -15
- package/dist/repository/gitWorkspace.js +371 -105
- package/dist/repository/projectMaintenanceLock.js +98 -82
- package/dist/repository/taskBaseFreshness.js +1 -1
- package/dist/repository/taskWorkspaceCoordinator.js +82 -144
- package/dist/repository/taskWorkspacePreparer.js +113 -47
- package/dist/repository/workspaceCleanupInspection.js +187 -0
- package/dist/resources/autoResourceGc.js +4 -77
- package/dist/resources/liveReferences.js +7 -54
- package/dist/resources/resourceDiscovery.js +5 -118
- package/dist/resources/resourceGc.js +233 -181
- package/dist/resources/resourceRegistrar.js +5 -4
- package/dist/resources/resourceRegistry.js +3 -37
- package/dist/resources/resourceRegistryStore.js +13 -36
- package/dist/resources/sqliteResourceRegistry.js +43 -26
- package/dist/review/deltaRecheck.js +1 -1
- package/dist/review/reviewAcceptance.js +1 -1
- package/dist/review/reviewDecision.js +1 -1
- package/dist/review/reviewRound.js +8 -7
- package/dist/review/taskFinalReviewContractResolution.js +1 -1
- package/dist/runtime/acpProtocol.js +4 -51
- package/dist/runtime/acpSession.js +10 -75
- package/dist/runtime/acpSessionConfiguration.js +1 -8
- package/dist/runtime/agentEndpoint.js +3 -2
- package/dist/runtime/agentError.js +5 -3
- package/dist/runtime/agentFailureContext.js +43 -0
- package/dist/runtime/agentHost.js +42 -25
- package/dist/runtime/builtinAgentErrorMappers.js +91 -0
- package/dist/runtime/codexAppServerRuntime.js +34 -3
- package/dist/runtime/codexInteractiveHost.js +2 -2
- package/dist/runtime/index.js +0 -1
- package/dist/runtime/managedCaller.js +21 -1
- package/dist/runtime/providerControl.js +5 -1
- package/dist/runtime/providerErrors.js +38 -0
- package/dist/runtime/providerRetry.js +198 -0
- package/dist/runtime/providerRuntimeIdentity.js +28 -2
- package/dist/runtime/runtimeObservation.js +0 -5
- package/dist/runtime/runtimeSessionCandidate.js +2 -3
- package/dist/runtime/sessionOwnerIdentity.js +1 -1
- package/dist/runtime/sessionTokenMetrics.js +15 -5
- package/dist/runtime/structuredProviderHost.js +10 -43
- package/dist/runtime/taskUsageMetrics.js +275 -0
- package/dist/runtime/tmuxAdapters.js +6 -8
- package/dist/scheduler/activeRoleRunDelivery.js +19 -7
- package/dist/scheduler/leaderWakeupProcessor.js +24 -6
- package/dist/scheduler/operatorEvent.js +12 -20
- package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
- package/dist/scheduler/ports.js +5 -8
- package/dist/scheduler/roleRunLiveness.js +4 -4
- package/dist/scheduler/roleRunStall.js +16 -23
- package/dist/scheduler/taskExecutionProjection.js +49 -36
- package/dist/scheduler/taskObservabilityProjection.js +6 -45
- package/dist/scheduler/taskWake.js +5 -10
- package/dist/scheduler/wakeReason.js +2 -0
- package/dist/scheduler/wakeupQueue.js +2 -4
- package/dist/setup/setupCommand.js +1 -1
- package/dist/storage/contextRecords.js +106 -0
- package/dist/storage/currentTaskStore.js +1 -1
- package/dist/storage/homeLayout.js +13 -17
- package/dist/storage/migrations/agentFailureContext.js +22 -0
- package/dist/storage/migrations/currentInputContract.js +86 -0
- package/dist/storage/migrations/currentRuntimeContract.js +228 -0
- package/dist/storage/migrations/historicalVerificationPlan.js +35 -0
- package/dist/storage/migrations/integrationContinuation.js +5 -4
- package/dist/storage/migrations/narrowAgentFailureContext.js +65 -0
- package/dist/storage/migrations/notificationOnlyWakes.js +74 -0
- package/dist/storage/migrations/verificationPlanV1.js +162 -0
- package/dist/storage/migrations/verificationPolicy.js +74 -0
- package/dist/storage/migrations/workItemHistory.js +46 -0
- package/dist/storage/persistenceWorker.js +12 -4
- package/dist/storage/recordValidation.js +87 -0
- package/dist/storage/sqliteSchema.js +173 -1
- package/dist/storage/sqliteStore.js +172 -161
- package/dist/storage/storageSchema.js +2 -14
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +16 -7
- package/dist/storage/taskCatalog.js +123 -0
- package/dist/storage/taskStore.js +5 -7
- package/dist/storage/upgrade/upgradeOrchestrator.js +25 -37
- package/dist/task/archiveDiagnostics.js +1 -0
- package/dist/task/archivePreflight.js +124 -0
- package/dist/task/completionReadiness.js +5 -24
- package/dist/task/draftPlan.js +0 -53
- package/dist/task/nextAction.js +7 -13
- package/dist/task/publicationAdoption.js +56 -0
- package/dist/task/publicationReference.js +10 -0
- package/dist/task/remoteDelivery.js +31 -16
- package/dist/task/remoteDeliveryService.js +89 -0
- package/dist/task/taskActivation.js +2 -25
- package/dist/task/taskActivationService.js +0 -2
- package/dist/task/taskRecordReference.js +0 -1
- package/dist/task/taskSubmission.js +3 -14
- package/dist/telemetry/sqliteTelemetryBatch.js +29 -0
- package/dist/telemetry/sqliteTelemetryStore.js +49 -49
- package/dist/telemetry/telemetryWiring.js +4 -3
- package/dist/tmux/tmuxManager.js +29 -20
- package/dist/verification/gateArtifact.js +15 -24
- package/dist/verification/gateArtifactStore.js +14 -7
- package/dist/verification/verificationGateService.js +29 -88
- package/dist/verification/verificationPlan.js +27 -72
- package/dist/web/assets/client/app.js +92 -17
- package/dist/web/assets/client/components.js +55 -13
- package/dist/web/assets/client/i18n.js +72 -4
- package/dist/web/assets/client/taskSurface.js +6 -5
- package/dist/web/assets/client/view.js +35 -7
- package/dist/web/assets/shell.js +6 -0
- package/dist/web/assets/styles/layout.js +7 -0
- package/dist/web/webServer.js +12 -3
- package/dist/web/webSnapshot.js +14 -85
- package/dist/web/webTaskSurface.js +17 -46
- package/dist/workItem/workItem.js +1 -12
- package/dist/workspace/cleanupInspection.js +63 -0
- package/dist/workspace/workItemChangeSetManager.js +110 -50
- package/docs/agent-result-consumption.md +4 -0
- package/docs/agent-result-consumption.zh-CN.md +3 -0
- package/docs/agent-runtime-drivers.md +7 -0
- package/docs/agent-runtime-drivers.zh-CN.md +5 -0
- package/docs/architecture/README.md +2 -0
- package/docs/architecture/README.zh-CN.md +3 -1
- package/docs/architecture/capabilities-and-resources.md +42 -5
- package/docs/architecture/capabilities-and-resources.zh-CN.md +33 -3
- package/docs/managed-turn-and-session-runtime.md +121 -1
- package/docs/managed-turn-and-session-runtime.zh-CN.md +96 -2
- package/docs/observability/README.md +62 -0
- package/docs/observability/README.zh-CN.md +47 -0
- package/docs/plugin-sdk.md +4 -2
- package/docs/project-refresh.md +77 -0
- package/docs/project-refresh.zh-CN.md +59 -0
- package/docs/provider-retry.md +70 -0
- package/docs/provider-runtime.md +3 -1
- package/docs/provider-runtime.zh-CN.md +4 -2
- package/docs/release-workflow.md +190 -7
- package/docs/release-workflow.zh-CN.md +139 -5
- package/docs/roles-and-configuration.md +29 -0
- package/docs/roles-and-configuration.zh-CN.md +21 -0
- package/docs/sqlite-control-plane-design.md +16 -3
- package/docs/sqlite-control-plane-design.zh-CN.md +13 -2
- package/docs/task-dag-semantics.md +3 -3
- package/docs/task-dag-semantics.zh-CN.md +2 -2
- package/docs/task-delivery.md +223 -17
- package/docs/task-delivery.zh-CN.md +171 -14
- package/docs/task-discovery.md +101 -0
- package/docs/task-discovery.zh-CN.md +85 -0
- package/docs/testing/verification-levels.md +161 -9
- package/docs/testing/verification-levels.zh-CN.md +116 -9
- package/i18n/README.zh-CN.md +13 -7
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +5 -0
- package/skills/yui-leader/references/execution.md +3 -2
- package/skills/yui-leader/references/integration.md +9 -5
- package/skills/yui-leader/references/planning.md +9 -3
- package/skills/yui-operator/SKILL.md +24 -8
- package/skills/yui-reviewer/SKILL.md +4 -0
- package/skills/yui-runtime/SKILL.md +17 -2
- package/skills/yui-runtime/references/publication.md +26 -4
- package/skills/yui-runtime/references/recovery.md +71 -0
- package/dist/agent/agentRegistry.js +0 -10
- package/dist/agentRun/runIdentity.js +0 -22
- package/dist/commands/deliveryGuardPreflight.js +0 -30
- package/dist/commands/taskIntegrationQueueCommands.js +0 -226
- package/dist/commands/taskOverviewCommand.js +0 -376
- package/dist/completion/completionWizard.js +0 -125
- package/dist/context/dispatchContext.js +0 -110
- package/dist/context/wakeNotification.js +0 -144
- package/dist/integration/integrationCheckEvidenceReuse.js +0 -53
- package/dist/integration/integrationQueueEntry.js +0 -191
- package/dist/integration/integrationQueueService.js +0 -810
- package/dist/release/fakeReleasePorts.js +0 -55
- package/dist/runtime/sessionOwnerRegistry.js +0 -137
- package/dist/task/deliveryGuard.js +0 -226
- /package/dist/{commands/taskActor.js → task/taskAuthority.js} +0 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
export const PROVIDER_RETRY_LIMIT = 5;
|
|
2
|
+
export const PROVIDER_RETRY_BUDGET_MS = 600_000;
|
|
3
|
+
export function providerRetryPending(binding) {
|
|
4
|
+
return binding?.retry?.status === "waiting" || binding?.retry?.status === "in-flight";
|
|
5
|
+
}
|
|
6
|
+
/** Called only in the transaction recording the exact failed/rejected input. */
|
|
7
|
+
export function recordProviderFailure(binding, input) {
|
|
8
|
+
let turn = binding.run;
|
|
9
|
+
const previous = binding.retry;
|
|
10
|
+
if (turn === null || !["failed", "rejected", "delivery-unknown"].includes(turn.status))
|
|
11
|
+
return binding;
|
|
12
|
+
turn = { ...turn, failure: { error: input.error, ref: input.failureRef } };
|
|
13
|
+
binding = { ...binding, run: turn };
|
|
14
|
+
if (turn.status === "delivery-unknown")
|
|
15
|
+
return binding;
|
|
16
|
+
if (previous?.currentAttemptId === turn.attemptId
|
|
17
|
+
&& ["cancelled", "exhausted", "needs-attention"].includes(previous.status))
|
|
18
|
+
return binding;
|
|
19
|
+
if (previous?.failedAttemptId === turn.attemptId && previous.status !== "in-flight")
|
|
20
|
+
return binding;
|
|
21
|
+
if (input.error.retryable !== true || input.error.inputDisposition === "unknown"
|
|
22
|
+
|| input.error.sessionDisposition !== "recoverable"
|
|
23
|
+
|| binding.authority.owner !== "controller" || binding.retryDisabled === true
|
|
24
|
+
|| turn.status === "failed" && (turn.nativeTurnId === undefined || input.error.inputDisposition !== "accepted")) {
|
|
25
|
+
return providerRetryPending(binding)
|
|
26
|
+
? cancelProviderRetry(binding, "failure-not-safely-retryable", input.at) : binding;
|
|
27
|
+
}
|
|
28
|
+
const continuing = previous?.status === "in-flight" && previous.currentAttemptId === turn.attemptId;
|
|
29
|
+
const originalInput = continuing ? previous.input : turn.input;
|
|
30
|
+
if (originalInput === undefined)
|
|
31
|
+
return binding; // no owned input: never replay arbitrary native chat
|
|
32
|
+
const current = {
|
|
33
|
+
policyVersion: 1,
|
|
34
|
+
chainId: continuing ? previous.chainId : turn.attemptId,
|
|
35
|
+
status: "waiting",
|
|
36
|
+
input: originalInput,
|
|
37
|
+
nativeSessionId: binding.conversations.find(c => c.epoch === binding.currentConversationEpoch).conversationId,
|
|
38
|
+
authorityEpoch: binding.authority.epoch,
|
|
39
|
+
attempts: continuing ? previous.attempts - (input.noProviderWrite && previous.successorAutomatic !== false ? 1 : 0) : 0,
|
|
40
|
+
transportSequence: continuing ? previous.transportSequence : 0,
|
|
41
|
+
startedAt: continuing ? previous.startedAt : iso(input.at),
|
|
42
|
+
intentAt: continuing ? previous.intentAt : turn.submittedAt,
|
|
43
|
+
deadline: continuing ? previous.deadline : iso(input.at + PROVIDER_RETRY_BUDGET_MS),
|
|
44
|
+
nextEligibleAt: iso(input.at),
|
|
45
|
+
updatedAt: iso(input.at),
|
|
46
|
+
failedAttemptId: turn.attemptId,
|
|
47
|
+
failureAttemptId: turn.nativeTurnId !== undefined || !continuing ? turn.attemptId : previous.failureAttemptId,
|
|
48
|
+
...((turn.nativeTurnId ?? (continuing ? previous.failedNativeTurnId : undefined)) === undefined ? {}
|
|
49
|
+
: { failedNativeTurnId: turn.nativeTurnId ?? previous.failedNativeTurnId }),
|
|
50
|
+
...(turn.runId === undefined ? {} : { previousRunId: turn.runId }),
|
|
51
|
+
failureRef: input.failureRef,
|
|
52
|
+
error: input.error
|
|
53
|
+
};
|
|
54
|
+
const random = unitRandom(input.random ?? Math.random);
|
|
55
|
+
const window = Math.min(60_000, 5_000 * 2 ** current.attempts);
|
|
56
|
+
const backoff = Math.ceil(window * (0.5 + random / 2));
|
|
57
|
+
const serverWait = input.error.retryAfterMs;
|
|
58
|
+
const delay = serverWait === undefined ? backoff
|
|
59
|
+
: Math.max(backoff, serverWait + 1 + Math.ceil(random * 1_000));
|
|
60
|
+
const eligible = input.at + delay;
|
|
61
|
+
const exhausted = current.attempts >= PROVIDER_RETRY_LIMIT || eligible >= Date.parse(current.deadline);
|
|
62
|
+
return {
|
|
63
|
+
...binding,
|
|
64
|
+
...(!continuing && previous !== undefined
|
|
65
|
+
? { retryHistory: [...(binding.retryHistory ?? []), previous] } : {}),
|
|
66
|
+
retry: {
|
|
67
|
+
// A terminal chain has no next submission. Keep its bounded deadline
|
|
68
|
+
// representable even for huge hints; the unshortened hint stays in error.
|
|
69
|
+
...current, nextEligibleAt: iso(exhausted ? Math.min(eligible, Date.parse(current.deadline)) : eligible),
|
|
70
|
+
...(turn.retrySupported !== true ? { status: "needs-attention", reason: "host-safe-retry-unsupported" }
|
|
71
|
+
: exhausted ? { status: "exhausted", reason: current.attempts >= PROVIDER_RETRY_LIMIT
|
|
72
|
+
? "automatic-attempt-limit" : "retry-after-exceeds-deadline" } : {})
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Atomically called at the shared native write admission, never by a timer alone. */
|
|
77
|
+
export function admitProviderRetry(binding, input) {
|
|
78
|
+
const retry = binding.retry;
|
|
79
|
+
if (retry?.status === "in-flight" && retry.currentAttemptId === input.attemptId)
|
|
80
|
+
return binding;
|
|
81
|
+
if (retry?.status !== "waiting"
|
|
82
|
+
|| input.at < Date.parse(retry.nextEligibleAt)
|
|
83
|
+
|| retry.successorAutomatic !== false && (binding.retryDisabled === true
|
|
84
|
+
|| input.at >= Date.parse(retry.deadline) || retry.attempts >= PROVIDER_RETRY_LIMIT)
|
|
85
|
+
|| binding.authority.owner !== "controller" || binding.authority.epoch !== retry.authorityEpoch
|
|
86
|
+
|| binding.conversations.find(c => c.epoch === binding.currentConversationEpoch)?.conversationId !== retry.nativeSessionId
|
|
87
|
+
|| binding.run?.attemptId !== retry.failedAttemptId
|
|
88
|
+
|| !["failed", "rejected", "deferred"].includes(binding.run.status)) {
|
|
89
|
+
throw new Error("Provider retry is not eligible under the current input, Session, authority or budget.");
|
|
90
|
+
}
|
|
91
|
+
return { ...binding, retry: {
|
|
92
|
+
...retry, status: "in-flight", attempts: retry.attempts + (retry.successorAutomatic === false ? 0 : 1),
|
|
93
|
+
transportSequence: retry.transportSequence + 1,
|
|
94
|
+
currentAttemptId: input.attemptId, updatedAt: iso(input.at)
|
|
95
|
+
} };
|
|
96
|
+
}
|
|
97
|
+
/** Busy/preflight refusal is not a model attempt. Keep its exact receipt visible. */
|
|
98
|
+
export function deferProviderRetry(binding, at, reason) {
|
|
99
|
+
const retry = binding.retry;
|
|
100
|
+
if (retry?.status !== "in-flight" || retry.currentAttemptId !== binding.run?.attemptId)
|
|
101
|
+
return binding;
|
|
102
|
+
const { currentAttemptId: _attempt, successorRunId, ...remaining } = retry;
|
|
103
|
+
return { ...binding, retry: {
|
|
104
|
+
...remaining, attempts: retry.attempts - (retry.successorAutomatic === false ? 0 : 1),
|
|
105
|
+
failedAttemptId: binding.run.attemptId,
|
|
106
|
+
...(reason === undefined && successorRunId !== undefined ? { successorRunId } : {}),
|
|
107
|
+
...(reason !== undefined && binding.run?.runId !== undefined ? { previousRunId: binding.run.runId } : {}),
|
|
108
|
+
status: reason === undefined ? "waiting" : "needs-attention",
|
|
109
|
+
nextEligibleAt: iso(Math.min(at + 1_000, Date.parse(retry.deadline))),
|
|
110
|
+
updatedAt: iso(at), ...(reason === undefined ? {} : { reason })
|
|
111
|
+
} };
|
|
112
|
+
}
|
|
113
|
+
export function cancelProviderRetry(binding, reason, at) {
|
|
114
|
+
return !providerRetryPending(binding) ? binding : {
|
|
115
|
+
...binding, retry: { ...binding.retry, status: "cancelled", reason, updatedAt: iso(at) }
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export function completeProviderRetry(binding, turn) {
|
|
119
|
+
const retry = binding.retry;
|
|
120
|
+
return retry === undefined || !["in-flight", "cancelled", "needs-attention"].includes(retry.status)
|
|
121
|
+
|| retry.currentAttemptId !== turn.attemptId
|
|
122
|
+
|| turn.status !== "completed" ? binding : {
|
|
123
|
+
...binding, retry: { ...retry, status: "recovered", updatedAt: turn.updatedAt }
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
export function providerRetryAttemptId(retry) {
|
|
127
|
+
return `provider-retry:${retry.chainId}/${retry.transportSequence + 1}`;
|
|
128
|
+
}
|
|
129
|
+
export function providerRetryPrompt(retry, original) {
|
|
130
|
+
if (retry.failedNativeTurnId === undefined)
|
|
131
|
+
return original;
|
|
132
|
+
return [
|
|
133
|
+
"Yui infrastructure recovery, not new user authorization.",
|
|
134
|
+
`Continue the existing input after failed attempt ${retry.failureAttemptId}`,
|
|
135
|
+
`(native Turn ${retry.failedNativeTurnId}; failure ${retry.failureRef}).`,
|
|
136
|
+
"Read current authorized context and the original input. Inspect existing work and receipts first;",
|
|
137
|
+
"continue only unfinished work. Preserve local changes and do not repeat confirmed side effects.",
|
|
138
|
+
original
|
|
139
|
+
].join("\n");
|
|
140
|
+
}
|
|
141
|
+
/** The same presentation is consumed by CLI, Context and Web. */
|
|
142
|
+
export function providerRetryProjection(binding) {
|
|
143
|
+
const retry = binding?.retry;
|
|
144
|
+
if (retry === undefined)
|
|
145
|
+
return null;
|
|
146
|
+
return {
|
|
147
|
+
chainId: retry.chainId,
|
|
148
|
+
status: retry.status === "in-flight" && binding?.run?.status === "delivery-unknown"
|
|
149
|
+
? "delivery-unknown" : retry.status,
|
|
150
|
+
attempts: retry.status === "recovered" ? 0 : retry.attempts,
|
|
151
|
+
limit: PROVIDER_RETRY_LIMIT, nextEligibleAt: retry.nextEligibleAt, deadline: retry.deadline,
|
|
152
|
+
category: retry.error.category, preservesWork: true, nativeSessionId: retry.nativeSessionId,
|
|
153
|
+
...(retry.reason === undefined ? {} : { reason: retry.reason }),
|
|
154
|
+
failureRef: retry.failureRef,
|
|
155
|
+
...(retry.previousRunId === undefined ? {} : { previousRunId: retry.previousRunId }),
|
|
156
|
+
...(retry.successorRunId === undefined ? {} : { successorRunId: retry.successorRunId })
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
export function controlProviderRetry(binding, action, at) {
|
|
160
|
+
if (action === "enable")
|
|
161
|
+
return { ...binding, retryDisabled: false };
|
|
162
|
+
return { ...cancelProviderRetry(binding, `user-${action}`, at),
|
|
163
|
+
...(action === "disable" ? { retryDisabled: true } : {}) };
|
|
164
|
+
}
|
|
165
|
+
export function renderProviderRetry(binding) {
|
|
166
|
+
const view = providerRetryProjection(binding);
|
|
167
|
+
return view === null ? `Provider retry: ${binding?.retryDisabled ? "disabled" : "none"}`
|
|
168
|
+
: `Provider retry: ${view.category}/${view.status}; ${view.attempts}/${view.limit}; next=${view.nextEligibleAt}; `
|
|
169
|
+
+ `deadline=${view.deadline}; existing work preserved${view.reason === undefined ? "" : `; ${view.reason}`}`;
|
|
170
|
+
}
|
|
171
|
+
export function validateProviderRetry(retry) {
|
|
172
|
+
if (retry.policyVersion !== 1 || !["waiting", "in-flight", "recovered", "cancelled", "exhausted", "needs-attention"].includes(retry.status)
|
|
173
|
+
|| !Number.isSafeInteger(retry.attempts) || retry.attempts < 0 || retry.attempts > PROVIDER_RETRY_LIMIT
|
|
174
|
+
|| !Number.isSafeInteger(retry.transportSequence) || retry.transportSequence < retry.attempts
|
|
175
|
+
|| !Number.isSafeInteger(retry.authorityEpoch) || retry.authorityEpoch < 1
|
|
176
|
+
|| [retry.chainId, retry.nativeSessionId, retry.failedAttemptId, retry.failureRef].some(v => typeof v !== "string" || v.length === 0)
|
|
177
|
+
|| [retry.startedAt, retry.intentAt, retry.deadline, retry.nextEligibleAt, retry.updatedAt].some(v => !Number.isFinite(Date.parse(v)))
|
|
178
|
+
|| Date.parse(retry.deadline) - Date.parse(retry.startedAt) !== PROVIDER_RETRY_BUDGET_MS
|
|
179
|
+
|| retry.status === "in-flight" && !retry.currentAttemptId)
|
|
180
|
+
throw new Error("Invalid Provider retry record.");
|
|
181
|
+
validateProviderInput(retry.input);
|
|
182
|
+
}
|
|
183
|
+
export function validateProviderInput(input) {
|
|
184
|
+
const fields = input.kind === "run" ? [input.taskId, input.runId]
|
|
185
|
+
: input.kind === "wake" ? [input.taskId, input.wakeId]
|
|
186
|
+
: input.kind === "message" ? [input.roleName, input.messageId]
|
|
187
|
+
: input.kind === "text" ? [input.text] : [];
|
|
188
|
+
if (fields.length === 0 || fields.some(v => typeof v !== "string" || !v.trim())) {
|
|
189
|
+
throw new Error("Invalid owned Provider input.");
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function iso(at) { return new Date(at).toISOString(); }
|
|
193
|
+
function unitRandom(random) {
|
|
194
|
+
const value = random();
|
|
195
|
+
if (!Number.isFinite(value) || value < 0 || value > 1)
|
|
196
|
+
throw new Error("Retry RNG must return a unit fraction.");
|
|
197
|
+
return value;
|
|
198
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { cancelProviderRetry, completeProviderRetry, validateProviderInput, validateProviderRetry } from "./providerRetry.js";
|
|
2
|
+
import { isStandardAgentError } from "./agentError.js";
|
|
1
3
|
export function createProviderRuntimeBinding(input) {
|
|
2
4
|
const startedAt = timestamp(input.startedAt, "Provider Conversation startedAt");
|
|
3
5
|
return validateProviderRuntimeBinding({
|
|
@@ -84,7 +86,7 @@ export function transferProviderAuthority(raw, input) {
|
|
|
84
86
|
});
|
|
85
87
|
}
|
|
86
88
|
export function beginProviderTurn(raw, input) {
|
|
87
|
-
|
|
89
|
+
let binding = validateProviderRuntimeBinding(raw);
|
|
88
90
|
const attemptId = identity(input.attemptId, "Provider input attempt id");
|
|
89
91
|
const runId = input.runId === undefined ? undefined : identity(input.runId, "AgentRun id");
|
|
90
92
|
const currentRun = binding.run;
|
|
@@ -104,6 +106,9 @@ export function beginProviderTurn(raw, input) {
|
|
|
104
106
|
throw new Error("Provider Conversation already has an unsettled AgentRun.");
|
|
105
107
|
}
|
|
106
108
|
const submittedAt = timestamp(input.submittedAt, "Provider Turn submittedAt");
|
|
109
|
+
if (binding.retry?.currentAttemptId !== attemptId) {
|
|
110
|
+
binding = cancelProviderRetry(binding, "superseded-by-explicit-input", Date.parse(submittedAt));
|
|
111
|
+
}
|
|
107
112
|
return validateProviderRuntimeBinding({
|
|
108
113
|
...binding,
|
|
109
114
|
run: {
|
|
@@ -111,6 +116,8 @@ export function beginProviderTurn(raw, input) {
|
|
|
111
116
|
attemptId,
|
|
112
117
|
authorityEpoch: input.authorityEpoch,
|
|
113
118
|
status: "submitting",
|
|
119
|
+
...(input.input === undefined ? {} : { input: input.input }),
|
|
120
|
+
...(input.retrySupported === undefined ? {} : { retrySupported: input.retrySupported }),
|
|
114
121
|
submittedAt,
|
|
115
122
|
updatedAt: submittedAt
|
|
116
123
|
}
|
|
@@ -221,7 +228,7 @@ export function settleProviderTurn(raw, input) {
|
|
|
221
228
|
throw new Error("Provider Turn settlement does not match the current AgentRun.");
|
|
222
229
|
}
|
|
223
230
|
const settledAt = orderedRunTimestamp(run, input.settledAt, "Provider Turn settledAt");
|
|
224
|
-
|
|
231
|
+
const settled = validateProviderRuntimeBinding({
|
|
225
232
|
...binding,
|
|
226
233
|
run: {
|
|
227
234
|
...run,
|
|
@@ -233,6 +240,7 @@ export function settleProviderTurn(raw, input) {
|
|
|
233
240
|
: { terminalReason: identity(input.reason, "Provider Turn terminal reason") })
|
|
234
241
|
}
|
|
235
242
|
});
|
|
243
|
+
return completeProviderRetry(settled, settled.run);
|
|
236
244
|
}
|
|
237
245
|
/** Explicitly abandon an engineering input only after its execution resources
|
|
238
246
|
* are quiescent. This does not invent native acceptance, a Turn id or success. */
|
|
@@ -367,6 +375,24 @@ export function validateProviderRuntimeBinding(value) {
|
|
|
367
375
|
throw new Error("Provider Runtime Binding requires Goal state.");
|
|
368
376
|
if (value.goal !== null)
|
|
369
377
|
validateProviderGoal(value.goal);
|
|
378
|
+
if (value.retry !== undefined)
|
|
379
|
+
validateProviderRetry(value.retry);
|
|
380
|
+
if (value.retryHistory !== undefined) {
|
|
381
|
+
if (!Array.isArray(value.retryHistory))
|
|
382
|
+
throw new Error("Provider retry audit must be an array.");
|
|
383
|
+
for (const retry of value.retryHistory) {
|
|
384
|
+
validateProviderRetry(retry);
|
|
385
|
+
if (retry.status === "waiting" || retry.status === "in-flight")
|
|
386
|
+
throw new Error("Provider retry audit cannot schedule work.");
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (value.retryDisabled !== undefined && typeof value.retryDisabled !== "boolean")
|
|
390
|
+
throw new Error("Provider retry switch must be boolean.");
|
|
391
|
+
if (value.run?.input !== undefined)
|
|
392
|
+
validateProviderInput(value.run.input);
|
|
393
|
+
if (value.run?.failure !== undefined
|
|
394
|
+
&& (!isStandardAgentError(value.run.failure.error) || !value.run.failure.ref))
|
|
395
|
+
throw new Error("Invalid Provider input failure.");
|
|
370
396
|
return value;
|
|
371
397
|
}
|
|
372
398
|
function validateProviderGoal(goal) {
|
|
@@ -547,11 +547,6 @@ function requireTimestamp(value, label) {
|
|
|
547
547
|
throw new Error(`${label} is invalid.`);
|
|
548
548
|
return timestamp;
|
|
549
549
|
}
|
|
550
|
-
function requireNonNegativeInteger(value, minimum, label) {
|
|
551
|
-
if (!Number.isSafeInteger(value) || value < minimum)
|
|
552
|
-
throw new Error(`${label} is invalid.`);
|
|
553
|
-
return value;
|
|
554
|
-
}
|
|
555
550
|
function requireIdentity(value, label) {
|
|
556
551
|
const identity = requireText(value, label);
|
|
557
552
|
if (identity.includes("/../") || identity === "__proto__")
|
|
@@ -18,11 +18,10 @@ export function projectRuntimeSessionCandidate(sessions) {
|
|
|
18
18
|
sessionUpdatedAt: active.updatedAt
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
-
/** Deterministic owner order
|
|
21
|
+
/** Deterministic owner order for current runtime discovery. */
|
|
22
22
|
export function compareRuntimeSessionCandidates(left, right) {
|
|
23
23
|
if (left.owner.scope !== right.owner.scope) {
|
|
24
|
-
//
|
|
25
|
-
// bounded global Role set.
|
|
24
|
+
// Task owners precede the bounded global Role set.
|
|
26
25
|
return left.owner.scope === "task" ? -1 : 1;
|
|
27
26
|
}
|
|
28
27
|
if (left.owner.scope === "task" && right.owner.scope === "task") {
|
|
@@ -17,7 +17,7 @@ export function createSessionOwnerIdentity(input) {
|
|
|
17
17
|
throw new TypeError("Global session owner must not carry a task id.");
|
|
18
18
|
}
|
|
19
19
|
const providerRoot = input.providerRoot;
|
|
20
|
-
if (!["
|
|
20
|
+
if (!["pane-pid", "owned-child"].includes(providerRoot.attribution)) {
|
|
21
21
|
throw new TypeError("Session owner process attribution is invalid.");
|
|
22
22
|
}
|
|
23
23
|
if (!Number.isSafeInteger(providerRoot.pid) || providerRoot.pid <= 0) {
|
|
@@ -26,11 +26,21 @@ export function resolveSessionTokenIdentity(input) {
|
|
|
26
26
|
export function projectSessionTokenMetrics(events, identity) {
|
|
27
27
|
if (identity === null)
|
|
28
28
|
return unobservedSessionTokenMetrics();
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
return projectSessionTokenObservations(events.flatMap((event) => {
|
|
30
|
+
const observation = runtimeObservationFromTaskEvent(event);
|
|
31
|
+
return observation === null ? [] : [observation];
|
|
32
|
+
}), identity);
|
|
33
|
+
}
|
|
34
|
+
/** Shared reducer for authorized, already decoded canonical observations. */
|
|
35
|
+
export function projectSessionTokenObservations(input, identity) {
|
|
36
|
+
const observations = input
|
|
37
|
+
.filter((observation) => (isRuntimeTokenEvidence(observation)
|
|
38
|
+
&& matchesSessionIdentity(observation, identity)
|
|
39
|
+
&& (observation.authority === "provider-structured" || observation.authority === "driver-inferred")
|
|
40
|
+
// Child counters have no declared inclusion relationship with the
|
|
41
|
+
// Session's parent counter. They must never be added as extra requests.
|
|
42
|
+
&& observation.fence.continuationId === undefined
|
|
43
|
+
&& observation.fence.parentContinuationId === undefined))
|
|
34
44
|
.sort(compareObservations);
|
|
35
45
|
const incompleteBoundaries = observations.filter(({ payload }) => (payload.usage === undefined));
|
|
36
46
|
const request = observations.filter(({ payload }) => (payload.usage?.semantics === "request-context"));
|
|
@@ -2,13 +2,14 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { Duplex } from "node:stream";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { ProviderConversationMissingError, ProviderDeliveryUnknownError, ProviderTurnBusyError, ProviderTurnRejectedError } from "./providerErrors.js";
|
|
5
6
|
import WebSocket from "ws";
|
|
6
|
-
import {
|
|
7
|
-
import { serializeAgentErrorRaw } from "./agentError.js";
|
|
7
|
+
import { YUI_VERSION } from "../version.js";
|
|
8
8
|
import { AcpStructuredProviderSession } from "./acpSession.js";
|
|
9
9
|
import { acpDesiredSessionConfiguration } from "./acpSessionConfiguration.js";
|
|
10
|
+
import { serializeAgentErrorRaw } from "./agentError.js";
|
|
10
11
|
import { unsupportedAgentRunConfiguration } from "./agentRunConfiguration.js";
|
|
11
|
-
import {
|
|
12
|
+
import { codexAppServerErrorIsMissing, CodexAppServerRequestError, CodexAppServerRuntime, codexClientInitialization, codexGoalNotification, codexTurnInput, codexTurnOutput } from "./codexAppServerRuntime.js";
|
|
12
13
|
import { JsonLineChannel, PROVIDER_MESSAGE_MAX_BYTES, terminateProcessGroup } from "./jsonLineChannel.js";
|
|
13
14
|
import { PROVIDER_ACCEPT_TIMEOUT_MS } from "./runtimeDeadlines.js";
|
|
14
15
|
const CODEX_PROXY_HANDSHAKE_TIMEOUT_MS = 10_000;
|
|
@@ -18,44 +19,6 @@ const CODEX_PROXY_HANDSHAKE_TIMEOUT_MS = 10_000;
|
|
|
18
19
|
*/
|
|
19
20
|
const CODEX_RUN_CONFIGURATION = unsupportedAgentRunConfiguration("The Codex app-server protocol");
|
|
20
21
|
const CLAUDE_RUN_CONFIGURATION = unsupportedAgentRunConfiguration("Claude Code's stream-json interface");
|
|
21
|
-
export class ProviderDeliveryUnknownError extends Error {
|
|
22
|
-
attemptId;
|
|
23
|
-
name = "ProviderDeliveryUnknownError";
|
|
24
|
-
constructor(message, attemptId,
|
|
25
|
-
// Wrapping must not become the end of the causal chain: the original
|
|
26
|
-
// transport or Controller failure is the reason a reader needs.
|
|
27
|
-
options) {
|
|
28
|
-
super(message, options);
|
|
29
|
-
this.attemptId = attemptId;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
export class ProviderTurnRejectedError extends Error {
|
|
33
|
-
attemptId;
|
|
34
|
-
name = "ProviderTurnRejectedError";
|
|
35
|
-
constructor(message, attemptId, options) {
|
|
36
|
-
super(message, options);
|
|
37
|
-
this.attemptId = attemptId;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
/** Another ordinary client currently owns the thread's active Turn. */
|
|
41
|
-
export class ProviderTurnBusyError extends Error {
|
|
42
|
-
attemptId;
|
|
43
|
-
activeTurnId;
|
|
44
|
-
name = "ProviderTurnBusyError";
|
|
45
|
-
constructor(message, attemptId, activeTurnId) {
|
|
46
|
-
super(message);
|
|
47
|
-
this.attemptId = attemptId;
|
|
48
|
-
this.activeTurnId = activeTurnId;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
export class ProviderConversationMissingError extends Error {
|
|
52
|
-
conversationId;
|
|
53
|
-
name = "ProviderConversationMissingError";
|
|
54
|
-
constructor(conversationId, message) {
|
|
55
|
-
super(message);
|
|
56
|
-
this.conversationId = conversationId;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
22
|
export async function startStructuredProviderSession(payload, input = {}) {
|
|
60
23
|
const control = payload.providerControl;
|
|
61
24
|
if (control === undefined) {
|
|
@@ -462,7 +425,7 @@ class CodexStructuredProviderSession {
|
|
|
462
425
|
? {}
|
|
463
426
|
: {
|
|
464
427
|
error: recovered.error ?? "Provider Turn failed.",
|
|
465
|
-
rawError:
|
|
428
|
+
...(recovered.rawError === undefined ? {} : { rawError: recovered.rawError })
|
|
466
429
|
})
|
|
467
430
|
};
|
|
468
431
|
session.#clientOwnedTurnId = undefined;
|
|
@@ -594,7 +557,11 @@ class CodexStructuredProviderSession {
|
|
|
594
557
|
conversationId: this.conversationId,
|
|
595
558
|
attemptId: turn.attemptId,
|
|
596
559
|
text: turn.boundedText,
|
|
597
|
-
expectedNoActiveTurn: true
|
|
560
|
+
expectedNoActiveTurn: true,
|
|
561
|
+
...(turn.requireQuiescent ? { requireQuiescent: true } : {}),
|
|
562
|
+
...(turn.expectedFailedNativeTurnId === undefined ? {} : {
|
|
563
|
+
expectedFailedNativeTurnId: turn.expectedFailedNativeTurnId
|
|
564
|
+
})
|
|
598
565
|
});
|
|
599
566
|
if (acceptance.status === "unknown") {
|
|
600
567
|
throw new ProviderDeliveryUnknownError(acceptance.reason, turn.attemptId);
|