@zq-silk/yui 0.15.6 → 0.15.8
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 +192 -399
- package/README.md +127 -1149
- package/dist/agent/adapterCatalog.js +15 -2
- package/dist/agent/agent.js +23 -3
- package/dist/agent/argumentPolicy.js +7 -1
- package/dist/agent/connectionPlan.js +62 -0
- package/dist/agent/executionComponents.js +158 -0
- package/dist/agent/launchEnvironment.js +31 -3
- package/dist/agent/managedRuntimeEnvironment.js +3 -5
- package/dist/{turn/turn.js → agentRun/agentRun.js} +166 -109
- package/dist/{turn/turnIdentity.js → agentRun/runIdentity.js} +4 -4
- package/dist/brief/taskBrief.js +12 -0
- package/dist/cli/agentConfigurationPicker.js +13 -0
- package/dist/cli/commandCatalog.js +167 -70
- package/dist/cli/interactionCandidates.js +5 -5
- package/dist/cli/interactionPolicy.js +38 -8
- package/dist/cli/invocationRouter.js +1 -1
- package/dist/cli/managedDiagnostics.js +28 -0
- package/dist/cli/operatorWizard.js +1 -7
- package/dist/cli/roleOptionOrder.js +27 -0
- package/dist/cli/roleWizard.js +50 -14
- package/dist/cli/updateOrchestrator.js +1 -1
- package/dist/cli/updatePorts.js +3 -4
- package/dist/cli.js +188 -95
- package/dist/commands/agentCommands.js +72 -14
- package/dist/commands/capabilityCommands.js +57 -0
- package/dist/commands/configCommands.js +20 -20
- package/dist/commands/deliveryGuardPreflight.js +2 -2
- package/dist/commands/executionAuditCommands.js +24 -24
- package/dist/commands/globalRoleCommands.js +1 -1
- package/dist/commands/grantCommands.js +4 -4
- package/dist/commands/operatorCommands.js +1 -7
- package/dist/commands/projectCommands.js +4 -4
- package/dist/commands/resourcesCommands.js +2 -2
- package/dist/commands/roleConfiguration.js +25 -5
- package/dist/commands/roleRuntimeGuard.js +4 -5
- package/dist/commands/sessionCommands.js +3 -7
- package/dist/commands/taskActivationCommands.js +259 -0
- package/dist/commands/taskActor.js +28 -49
- package/dist/commands/taskCommands.js +1216 -730
- package/dist/commands/taskContextCommand.js +39 -583
- package/dist/commands/taskExecutionCommands.js +32 -32
- package/dist/commands/taskInputCommands.js +40 -104
- package/dist/commands/taskIntegrationCommands.js +3 -2
- package/dist/commands/taskIntegrationQueueCommands.js +1 -1
- package/dist/commands/taskNextActionCommand.js +8 -8
- package/dist/commands/taskOverviewCommand.js +33 -45
- package/dist/commands/taskRemoteDeliveryCommand.js +2 -2
- package/dist/commands/taskRoleRuntimeStatus.js +133 -102
- package/dist/commands/telemetryCommands.js +36 -38
- package/dist/config/configCatalog.js +4 -4
- package/dist/config/yuiConfig.js +8 -8
- package/dist/context/contextSnapshot.js +10 -10
- package/dist/context/dispatchContext.js +11 -11
- package/dist/context/roleSessionContext.js +6 -3
- package/dist/context/{turnContextPack.js → runContextPack.js} +146 -81
- package/dist/context/{turnInputContract.js → runInputContract.js} +73 -60
- package/dist/context/sessionBootstrapManifest.js +21 -2
- package/dist/context/sourceRunContext.js +30 -0
- package/dist/context/taskContext.js +458 -0
- package/dist/context/wakeNotification.js +27 -27
- package/dist/controller/agentRuntimeObserver.js +21 -24
- package/dist/controller/capabilityBridge.js +77 -0
- package/dist/controller/clientRuntime.js +65 -92
- package/dist/controller/controller.js +127 -188
- package/dist/controller/fileSchedulerStoreAdapter.js +787 -887
- package/dist/controller/jobControl.js +54 -85
- package/dist/controller/resourceInventory.js +8 -27
- package/dist/controller/resourceInventoryLinux.js +12 -13
- package/dist/controller/runtime.js +530 -476
- package/dist/controller/runtimeEventInbox.js +55 -25
- package/dist/controller/runtimeEventProcessor.js +22 -31
- package/dist/controller/{runtimeHookTurnFence.js → runtimeHookRunFence.js} +91 -115
- package/dist/controller/runtimeLaunchCoordinator.js +80 -426
- package/dist/controller/runtimeObservationHook.js +14 -18
- package/dist/controller/sessionNotify.js +16 -24
- package/dist/controller/sessionOwnerReconciliation.js +168 -50
- package/dist/controller/structuredProviderObservation.js +138 -99
- package/dist/coordination/workMailbox.js +3 -3
- package/dist/coordination/workMailboxQueue.js +36 -33
- package/dist/core/boundedRpc.js +8 -1
- package/dist/core/controllerClient.js +20 -1
- package/dist/core/controllerServer.js +4 -4
- package/dist/doctor/doctor.js +13 -2
- package/dist/domain/agentResultTransport.js +9 -9
- package/dist/execution/codexThreadNaming.js +2 -8
- package/dist/execution/executionHealth.js +51 -63
- package/dist/execution/reviewMainRun.js +137 -0
- package/dist/execution/workItemExecution.js +28 -29
- package/dist/execution/workItemExecutionProjection.js +99 -107
- package/dist/execution/workItemMainRun.js +141 -0
- package/dist/executor/agentAdapter.js +227 -20
- package/dist/executor/agentConfigurationCatalog.js +126 -4
- package/dist/executor/agentConfigurationProbe.js +162 -4
- package/dist/executor/agentExecutor.js +79 -78
- package/dist/executor/effectiveLaunch.js +105 -18
- package/dist/executor/executorRegistry.js +29 -44
- package/dist/executor/fileRoleLaunchPlanner.js +229 -154
- package/dist/executor/workspacePreflightClassification.js +16 -16
- package/dist/grant/capabilityGrant.js +6 -3
- package/dist/input/inputRequest.js +12 -10
- package/dist/integration/gitIntegrationService.js +4 -11
- package/dist/integration/integrationQueueService.js +4 -4
- package/dist/interaction/operatorPresentation.js +1 -1
- package/dist/kernel/builtinCapabilities.js +423 -0
- package/dist/kernel/capabilityRegistry.js +314 -0
- package/dist/kernel/capabilitySchema.js +91 -0
- package/dist/kernel/instanceHost.js +18 -1
- package/dist/kernel/kernelPorts.js +4 -1
- package/dist/lifecycle/canonicalLifecycleEvent.js +44 -49
- package/dist/lifecycle/exactRunTerminalization.js +449 -0
- package/dist/message/message.js +62 -6
- package/dist/message/messageContinuation.js +204 -0
- package/dist/observability/executionAudit.js +70 -72
- package/dist/observability/faultClassification.js +2 -2
- package/dist/observability/orchestrationMetrics.js +8 -8
- package/dist/operator/operatorSessionHistory.js +1 -7
- package/dist/output/agentConfigurationPresentation.js +8 -3
- package/dist/output/agentRunConfigurationPresentation.js +128 -0
- package/dist/output/rolePresentation.js +54 -3
- package/dist/plugins/pluginChild.js +104 -0
- package/dist/plugins/pluginIntent.js +26 -0
- package/dist/plugins/pluginInterpreter.js +43 -0
- package/dist/plugins/pluginPackage.js +101 -0
- package/dist/plugins/pluginProcess.js +112 -0
- package/dist/plugins/pluginService.js +380 -0
- package/dist/profile/agentProfile.js +1 -1
- package/dist/repository/gitWorkspace.js +26 -4
- package/dist/repository/project.js +19 -4
- package/dist/repository/taskBaseFreshness.js +13 -13
- package/dist/repository/taskWorkspaceCoordinator.js +20 -27
- package/dist/repository/taskWorkspacePreparer.js +344 -83
- package/dist/resources/autoResourceGc.js +3 -3
- package/dist/resources/liveReferences.js +3 -3
- package/dist/resources/projectResource.js +123 -0
- package/dist/resources/projectResourceService.js +421 -0
- package/dist/resources/resourceDiscovery.js +6 -6
- package/dist/resources/resourceGc.js +1 -1
- package/dist/resources/resourceRegistrar.js +1 -1
- package/dist/resources/resourceTypes.js +1 -1
- package/dist/review/deltaRecheck.js +3 -3
- package/dist/review/reviewAcceptance.js +16 -16
- package/dist/review/reviewDecision.js +7 -7
- package/dist/review/reviewRound.js +21 -20
- package/dist/review/reviewerAvailability.js +2 -2
- package/dist/role/role.js +51 -7
- package/dist/role/taskRoleUpdate.js +30 -0
- package/dist/runtime/acpProtocol.js +425 -0
- package/dist/runtime/acpSession.js +731 -0
- package/dist/runtime/acpSessionConfiguration.js +260 -0
- package/dist/runtime/agentDriver.js +30 -11
- package/dist/runtime/agentEndpoint.js +278 -0
- package/dist/runtime/agentEndpointIdentity.js +86 -0
- package/dist/runtime/agentEndpointOwnership.js +239 -0
- package/dist/runtime/agentError.js +2 -10
- package/dist/runtime/agentHost.js +565 -314
- package/dist/runtime/agentRunConfiguration.js +258 -0
- package/dist/runtime/builtinAgentDrivers.js +134 -18
- package/dist/runtime/builtinAgentErrorMappers.js +55 -3
- package/dist/runtime/builtinTranscriptUsage.js +1 -1
- package/dist/runtime/claude-process-owner +0 -0
- package/dist/runtime/codexAppServerRuntime.js +38 -30
- package/dist/runtime/codexInteractiveHost.js +41 -6
- package/dist/runtime/continuationManager.js +2 -6
- package/dist/runtime/executionEnvironment.js +30 -0
- package/dist/runtime/firstProgressAdvisory.js +11 -11
- package/dist/runtime/index.js +4 -3
- package/dist/runtime/jsonLineChannel.js +109 -0
- package/dist/runtime/launchBroker.js +91 -16
- package/dist/runtime/launchDiagnostics.js +2 -2
- package/dist/runtime/lifecycleReservation.js +10 -18
- package/dist/runtime/managedCaller.js +61 -17
- package/dist/runtime/nativeSessionControl.js +102 -0
- package/dist/runtime/ports.js +6 -21
- package/dist/runtime/processExitObservation.js +8 -7
- package/dist/runtime/promptEnvelope.js +17 -6
- package/dist/runtime/providerContinuation.js +3 -9
- package/dist/runtime/providerContinuationReconciliationService.js +4 -13
- package/dist/runtime/providerControl.js +2 -7
- package/dist/runtime/providerRuntimeIdentity.js +110 -222
- package/dist/runtime/providerRuntimeReconciler.js +5 -9
- package/dist/runtime/runtimeBinding.js +0 -1
- package/dist/runtime/runtimeContinuationProjection.js +4 -7
- package/dist/runtime/runtimeDeadlines.js +9 -0
- package/dist/runtime/runtimeHealthPolicy.js +1 -1
- package/dist/runtime/runtimeObservation.js +29 -65
- package/dist/runtime/runtimeProjection.js +43 -51
- package/dist/runtime/runtimeSessionCandidate.js +1 -3
- package/dist/runtime/sessionLaunchRequest.js +3 -7
- package/dist/runtime/sessionOwnerIdentity.js +7 -54
- package/dist/runtime/sessionOwnerRegistry.js +22 -17
- package/dist/runtime/sessionReconciliation.js +4 -8
- package/dist/runtime/sessionTerminationGuard.js +70 -259
- package/dist/runtime/sessionTokenMetrics.js +5 -16
- package/dist/runtime/structuredProviderHost.js +237 -117
- package/dist/runtime/taskRuntimeIsolation.js +39 -122
- package/dist/runtime/tmuxAdapters.js +39 -86
- package/dist/scheduler/activeRoleRunDelivery.js +354 -0
- package/dist/scheduler/leaderWakeupProcessor.js +75 -266
- package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
- package/dist/scheduler/ports.js +80 -9
- package/dist/scheduler/{roleTurnLiveness.js → roleRunLiveness.js} +26 -30
- package/dist/scheduler/{roleTurnStall.js → roleRunStall.js} +128 -139
- package/dist/scheduler/taskExecutionProjection.js +120 -124
- package/dist/scheduler/taskObservabilityProjection.js +29 -29
- package/dist/scheduler/taskWake.js +11 -4
- package/dist/scheduler/wakeReason.js +9 -1
- package/dist/setup/setupCommand.js +1 -0
- package/dist/storage/migrations/agentRunContract.js +159 -0
- package/dist/storage/migrations/removeRuntimeGeneration.js +207 -0
- package/dist/storage/sqliteSchema.js +431 -5
- package/dist/storage/sqliteStore.js +375 -220
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +10 -5
- package/dist/storage/taskStore.js +13 -11
- package/dist/storage/upgrade/upgradeOrchestrator.js +5 -7
- package/dist/surface/surfaceContributions.js +102 -0
- package/dist/task/completionReadiness.js +32 -6
- package/dist/task/deliveryGuard.js +16 -16
- package/dist/task/draftPlan.js +72 -12
- package/dist/task/nextAction.js +144 -128
- package/dist/task/remoteDelivery.js +6 -6
- package/dist/task/task.js +184 -18
- package/dist/task/taskActivation.js +301 -0
- package/dist/task/taskActivationService.js +392 -0
- package/dist/task/taskRecordReference.js +5 -4
- package/dist/task/taskRecordRetirement.js +1 -1
- package/dist/telemetry/sqliteTelemetryStore.js +55 -68
- package/dist/telemetry/telemetryConfig.js +14 -14
- package/dist/telemetry/telemetryWiring.js +2 -2
- package/dist/web/assets/assetManifest.js +2 -0
- package/dist/web/assets/client/app.js +120 -20
- package/dist/web/assets/client/components.js +87 -54
- package/dist/web/assets/client/i18n.js +83 -41
- package/dist/web/assets/client/markdown.js +1 -1
- package/dist/web/assets/client/taskSurface.js +353 -0
- package/dist/web/assets/client/view.js +49 -44
- package/dist/web/assets/shell.js +1 -1
- package/dist/web/assets/styles/cards.js +22 -4
- package/dist/web/controllerWeb.js +60 -0
- package/dist/web/webMutation.js +28 -0
- package/dist/web/webServer.js +118 -8
- package/dist/web/webSnapshot.js +81 -74
- package/dist/web/webTaskSurface.js +64 -0
- package/dist/workItem/dependencyGate.js +1 -1
- package/dist/workItem/workItem.js +80 -48
- package/dist/workspace/workItemChangeSetManager.js +16 -9
- package/docs/agent-result-consumption.md +94 -0
- package/docs/agent-runtime-drivers.md +91 -0
- package/docs/architecture/README.md +38 -0
- package/docs/architecture/capabilities-and-resources.md +79 -0
- package/docs/managed-turn-and-session-runtime.md +222 -0
- package/docs/observability/README.md +81 -0
- package/docs/plugin-sdk.md +290 -0
- package/docs/provider-runtime.md +163 -0
- package/docs/release-workflow.md +303 -0
- package/docs/roles-and-configuration.md +113 -0
- package/docs/sqlite-control-plane-design.md +76 -0
- package/docs/task-dag-semantics.md +57 -0
- package/docs/task-delivery.md +103 -0
- package/docs/task-local-identity.md +6 -6
- package/docs/testing/verification-levels.md +86 -0
- package/i18n/README.zh-CN.md +98 -739
- package/package.json +5 -5
- package/skills/yui-leader/SKILL.md +130 -103
- package/skills/yui-leader/references/integration.md +39 -0
- package/skills/yui-leader/references/replicated-execution.md +42 -0
- package/skills/yui-leader/references/task-plugins.md +33 -0
- package/skills/yui-operator/SKILL.md +30 -59
- package/skills/yui-reviewer/SKILL.md +35 -36
- package/skills/yui-runtime/SKILL.md +88 -24
- package/skills/yui-runtime/references/publication.md +22 -0
- package/skills/yui-runtime/references/recovery.md +64 -0
- package/skills/yui-worker/SKILL.md +37 -39
- package/dist/cli/roleOptionCatalog.js +0 -68
- package/dist/context/sourceTurnContext.js +0 -30
- package/dist/execution/reviewMainTurn.js +0 -161
- package/dist/execution/workItemMainTurn.js +0 -164
- package/dist/lifecycle/exactTurnTerminalization.js +0 -407
- package/dist/runtime/preallocatedNativeSession.js +0 -13
- package/dist/runtime/runtimeStopReceipt.js +0 -42
- package/dist/scheduler/activeRoleTurnDelivery.js +0 -315
|
@@ -22,7 +22,7 @@ const MAX_DETAIL_CHARS = 1_000;
|
|
|
22
22
|
const SECRET_VALUE_PATTERN = /(api[_-]?key|access[_-]?token|refresh[_-]?token|secret|password|passwd|cookie|authorization)(\s*[=:]\s*)([^\s,;]+)/gi;
|
|
23
23
|
// Word boundary keeps "task-5-…" workspace paths from being mistaken for keys.
|
|
24
24
|
const OPENAI_KEY_PATTERN = /\bsk-[A-Za-z0-9_-]{6,}/gu;
|
|
25
|
-
/** A bounded, single-line, secret-redacted launch failure for
|
|
25
|
+
/** A bounded, single-line, secret-redacted launch failure for AgentRun summaries. */
|
|
26
26
|
export class RuntimeLaunchFailure extends Error {
|
|
27
27
|
diagnostic;
|
|
28
28
|
name = "RuntimeLaunchFailure";
|
|
@@ -84,7 +84,7 @@ export function formatRuntimeLaunchDiagnostic(diagnostic) {
|
|
|
84
84
|
}
|
|
85
85
|
if (diagnostic.hint !== undefined)
|
|
86
86
|
fields.push(`hint=${JSON.stringify(diagnostic.hint)}`);
|
|
87
|
-
return `Role
|
|
87
|
+
return `Role AgentRun could not start: ${fields.join(" ")}`;
|
|
88
88
|
}
|
|
89
89
|
export function redactLaunchArgument(value) {
|
|
90
90
|
return tail(redactLaunchText(value), MAX_ARGUMENT_CHARS);
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { mailboxHasWork } from "../coordination/workMailbox.js";
|
|
2
2
|
export const RUNTIME_LIFECYCLE_OWNER = "runtime-lifecycle";
|
|
3
|
-
export const RUNTIME_LAUNCH_RESERVED_REASON = "runtime-launch-reserved";
|
|
4
3
|
export const RUNTIME_CLEANUP_REQUIRED_REASON = "runtime-cleanup-required";
|
|
5
4
|
export const RUNTIME_HOST_DETACH_REQUIRED_REASON = "runtime-host-detach-required";
|
|
5
|
+
export const RUNTIME_SESSION_REPLACE_REQUIRED_REASON = "runtime-session-replace-required";
|
|
6
6
|
/**
|
|
7
|
-
* A Role runtime lifecycle lane already holds an
|
|
8
|
-
*
|
|
9
|
-
* backpressure: the equivalent wake/
|
|
10
|
-
* settles. It is never grounds to terminalize a
|
|
11
|
-
* happens before (or outside) any semantic
|
|
7
|
+
* A Role runtime lifecycle lane already holds an explicit cleanup obligation.
|
|
8
|
+
* This is scheduler
|
|
9
|
+
* backpressure: the equivalent wake/AgentRun must be retried after the lane
|
|
10
|
+
* settles. It is never grounds to terminalize a AgentRun, because the contention
|
|
11
|
+
* happens before (or outside) any semantic AgentRun launch.
|
|
12
12
|
*/
|
|
13
13
|
export class RuntimeLifecycleBusyError extends Error {
|
|
14
14
|
name = "RuntimeLifecycleBusyError";
|
|
@@ -33,15 +33,6 @@ export function runtimeLifecycleSignalKey(owner) {
|
|
|
33
33
|
? `role:${encodeURIComponent(owner.taskId)}/${encodeURIComponent(owner.roleName)}`
|
|
34
34
|
: `global-role:${encodeURIComponent(owner.roleName)}`;
|
|
35
35
|
}
|
|
36
|
-
export function isRuntimeLaunchReservation(processing, runtimeGenerationId) {
|
|
37
|
-
return processing?.owner === RUNTIME_LIFECYCLE_OWNER
|
|
38
|
-
&& processing.batch.reasons.length === 1
|
|
39
|
-
&& processing.batch.reasons[0] === RUNTIME_LAUNCH_RESERVED_REASON
|
|
40
|
-
&& (runtimeGenerationId === undefined || processing.batchId === runtimeGenerationId);
|
|
41
|
-
}
|
|
42
|
-
export function hasRuntimeLaunchReservation(mailbox) {
|
|
43
|
-
return isRuntimeLaunchReservation(mailbox?.processing);
|
|
44
|
-
}
|
|
45
36
|
export function hasRuntimeCleanupObligation(mailbox) {
|
|
46
37
|
return runtimeCleanupDisposition(mailbox) !== null;
|
|
47
38
|
}
|
|
@@ -49,10 +40,10 @@ export function hasRuntimeCleanupObligation(mailbox) {
|
|
|
49
40
|
export function runtimeCleanupDisposition(mailbox) {
|
|
50
41
|
const reasons = [
|
|
51
42
|
...(mailbox?.pending?.reasons ?? []),
|
|
52
|
-
...(
|
|
53
|
-
? mailbox?.processing?.batch.reasons ?? []
|
|
54
|
-
: [])
|
|
43
|
+
...(mailbox?.processing?.batch.reasons ?? [])
|
|
55
44
|
];
|
|
45
|
+
if (reasons.includes(RUNTIME_SESSION_REPLACE_REQUIRED_REASON))
|
|
46
|
+
return "replace-session";
|
|
56
47
|
if (reasons.includes(RUNTIME_CLEANUP_REQUIRED_REASON))
|
|
57
48
|
return "end-session";
|
|
58
49
|
if (reasons.includes(RUNTIME_HOST_DETACH_REQUIRED_REASON))
|
|
@@ -61,6 +52,7 @@ export function runtimeCleanupDisposition(mailbox) {
|
|
|
61
52
|
}
|
|
62
53
|
export function isRuntimeCleanupReason(reason) {
|
|
63
54
|
return reason === RUNTIME_CLEANUP_REQUIRED_REASON
|
|
55
|
+
|| reason === RUNTIME_SESSION_REPLACE_REQUIRED_REASON
|
|
64
56
|
|| reason === RUNTIME_HOST_DETACH_REQUIRED_REASON;
|
|
65
57
|
}
|
|
66
58
|
export function hasRuntimeLifecycleWork(mailbox) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
1
|
import { activeRoleAgentBinding } from "../role/role.js";
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { currentProviderConversation } from "./providerRuntimeIdentity.js";
|
|
3
|
+
/** Native Session identity supplied by the Agent transport. */
|
|
4
|
+
export const MANAGED_NATIVE_SESSION_ENV = "YUI_NATIVE_SESSION_ID";
|
|
5
5
|
/**
|
|
6
6
|
* A managed Session presented valid self-identity but is no longer the current
|
|
7
7
|
* runtime of its Task Role. This is a bounded diagnosis rather than a bare
|
|
@@ -25,12 +25,12 @@ export function managedTaskSessionIdentity(environment) {
|
|
|
25
25
|
throw new ManagedRuntimeDriftError("Managed Task Session identity is incomplete: YUI_TASK_ID and YUI_ROLE are required.");
|
|
26
26
|
}
|
|
27
27
|
const workspace = identity(env.YUI_WORKSPACE);
|
|
28
|
-
const
|
|
28
|
+
const nativeSessionId = identity(env.CODEX_THREAD_ID ?? env[MANAGED_NATIVE_SESSION_ENV]);
|
|
29
29
|
return Object.freeze({
|
|
30
30
|
taskId,
|
|
31
31
|
roleName,
|
|
32
32
|
...(workspace === undefined ? {} : { workspace }),
|
|
33
|
-
...(
|
|
33
|
+
...(nativeSessionId === undefined ? {} : { nativeSessionId })
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
@@ -52,6 +52,29 @@ export function requireManagedTaskCaller(store, environment) {
|
|
|
52
52
|
}
|
|
53
53
|
return caller;
|
|
54
54
|
}
|
|
55
|
+
export function resolveManagedTaskReader(store, environment) {
|
|
56
|
+
const self = managedTaskSessionIdentity(environment);
|
|
57
|
+
if (self === undefined)
|
|
58
|
+
return undefined;
|
|
59
|
+
try {
|
|
60
|
+
return requireCurrentRuntime(store, self);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
const set = store.getTaskRoleSessionSet(self.taskId, self.roleName);
|
|
64
|
+
const session = [...Object.values(set?.sessions ?? {}), ...(set?.history ?? [])]
|
|
65
|
+
.find(candidate => candidate.nativeSessionId === self.nativeSessionId
|
|
66
|
+
&& (self.workspace === undefined || candidate.effective.workspace.root === self.workspace));
|
|
67
|
+
if (session === undefined) {
|
|
68
|
+
const binding = set?.providerBinding;
|
|
69
|
+
if (binding == null || currentProviderConversation(binding).conversationId !== self.nativeSessionId)
|
|
70
|
+
throw error;
|
|
71
|
+
return { taskId: self.taskId, roleName: self.roleName, nativeSessionId: self.nativeSessionId };
|
|
72
|
+
}
|
|
73
|
+
return Object.freeze({
|
|
74
|
+
taskId: self.taskId, roleName: self.roleName, nativeSessionId: session.nativeSessionId
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
55
78
|
/**
|
|
56
79
|
* The current runtime authority for one Task Role, or undefined. Used by
|
|
57
80
|
* command authorization that must not fail the whole invocation, only decline
|
|
@@ -71,36 +94,57 @@ export function currentManagedRuntime(store, environment, taskId, roleName) {
|
|
|
71
94
|
return undefined;
|
|
72
95
|
return caller;
|
|
73
96
|
}
|
|
97
|
+
/** Select execution identity, not a credential or grant. Workers retain their
|
|
98
|
+
* active Assignment; Leader management follows the current Role selection. */
|
|
99
|
+
export function taskRoleRuntimeIdentity(role, activeRun) {
|
|
100
|
+
const effective = role.name !== "leader" && activeRun?.status === "active"
|
|
101
|
+
? activeRun.effective
|
|
102
|
+
: undefined;
|
|
103
|
+
return {
|
|
104
|
+
agentId: effective?.agentId ?? role.activeAgentId,
|
|
105
|
+
adapterId: effective?.adapterId ?? activeRoleAgentBinding(role).adapterId
|
|
106
|
+
};
|
|
107
|
+
}
|
|
74
108
|
function requireCurrentRuntime(store, self) {
|
|
75
109
|
const role = store.getRole(self.taskId, self.roleName);
|
|
76
110
|
if (role === null) {
|
|
77
111
|
throw new ManagedRuntimeDriftError(`This managed Session belongs to ${self.taskId}/${self.roleName}, which no longer exists. `
|
|
78
112
|
+ "A new Session must be launched to act on this Task.");
|
|
79
113
|
}
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
114
|
+
const activeRun = store.getActiveRun(self.taskId, self.roleName);
|
|
115
|
+
const { agentId, adapterId } = taskRoleRuntimeIdentity(role, activeRun);
|
|
116
|
+
const sessions = store.getTaskRoleSessionSet(self.taskId, self.roleName);
|
|
117
|
+
const session = sessions?.sessions[agentId];
|
|
118
|
+
if (self.nativeSessionId === undefined) {
|
|
119
|
+
throw new ManagedRuntimeDriftError(`This managed Session carries no native session id, so it cannot be recognized `
|
|
83
120
|
+ `as the current runtime of ${self.taskId}/${self.roleName}.`);
|
|
84
121
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
122
|
+
if (role.name === "leader" && store.listEvents(self.taskId).some((event) => event.type === "role.agent-bound" && event.payload.role === role.name
|
|
123
|
+
&& event.payload.revokedNativeSessionId === self.nativeSessionId)) {
|
|
124
|
+
throw new ManagedRuntimeDriftError("This Leader native Session's management authority was explicitly revoked.");
|
|
125
|
+
}
|
|
126
|
+
if (sessions?.activeAgentId !== agentId || session === undefined || session.status !== "active"
|
|
127
|
+
|| session.nativeSessionId !== self.nativeSessionId
|
|
128
|
+
|| session.adapterId !== adapterId
|
|
129
|
+
|| (self.workspace !== undefined && self.workspace !== session.effective.workspace.root)) {
|
|
88
130
|
throw new ManagedRuntimeDriftError(`This managed Session is no longer the current runtime of ${self.taskId}/${self.roleName} `
|
|
89
|
-
+ `(the
|
|
90
|
-
+ "rebound, so its
|
|
131
|
+
+ `(the authorized runtime uses Agent ${agentId}). Its native Session was replaced or its Role was `
|
|
132
|
+
+ "rebound, so its native session id no longer matches. Nothing was changed. Read the "
|
|
91
133
|
+ `current state with \`yui task show ${self.taskId}\`; acting requires the Session Yui `
|
|
92
134
|
+ "launched for the current runtime.");
|
|
93
135
|
}
|
|
94
|
-
const activeTurn = store.getActiveTurn(self.taskId, self.roleName);
|
|
95
136
|
return Object.freeze({
|
|
96
137
|
taskId: self.taskId,
|
|
97
138
|
roleName: self.roleName,
|
|
98
139
|
agentId,
|
|
99
|
-
adapterId
|
|
140
|
+
adapterId,
|
|
141
|
+
nativeSessionId: session.nativeSessionId,
|
|
142
|
+
executionAuthority: session.effective.executionAuthority,
|
|
100
143
|
...(self.workspace === undefined ? {} : { workspace: self.workspace }),
|
|
101
|
-
...(
|
|
144
|
+
...(activeRun === null || activeRun.status !== "active"
|
|
145
|
+
|| activeRun.effective.agentId !== agentId
|
|
102
146
|
? {}
|
|
103
|
-
: {
|
|
147
|
+
: { currentRunId: activeRun.id })
|
|
104
148
|
});
|
|
105
149
|
}
|
|
106
150
|
function identity(value) {
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { openCodexInteractiveConnection } from "./structuredProviderHost.js";
|
|
2
|
+
import { CodexAppServerRuntime, codexAppServerErrorIsMissing, codexClientInitialization } from "./codexAppServerRuntime.js";
|
|
3
|
+
import { realpathSync } from "node:fs";
|
|
4
|
+
import { isAbsolute } from "node:path";
|
|
5
|
+
/** A disposable metadata/control client, not an Agent Session or a new Run.
|
|
6
|
+
* Never calls thread/start, thread/resume or turn/start. A lost Host cannot be
|
|
7
|
+
* the only way to stop an existing native execution. */
|
|
8
|
+
export async function stopCodexNativeSession(launch, input, connect = openCodexInteractiveConnection) {
|
|
9
|
+
const channel = await connect(launch);
|
|
10
|
+
try {
|
|
11
|
+
const initialized = await channel.request("initialize", codexClientInitialization());
|
|
12
|
+
await channel.notify("initialized");
|
|
13
|
+
if (launch.expectedAccountHome !== undefined && !isAbsolute(launch.expectedAccountHome)) {
|
|
14
|
+
throw new Error("Recorded native account Home is invalid.");
|
|
15
|
+
}
|
|
16
|
+
const actualHome = typeof initialized.codexHome === "string" && isAbsolute(initialized.codexHome)
|
|
17
|
+
? initialized.codexHome : undefined;
|
|
18
|
+
const sameAccount = launch.expectedAccountHome !== undefined && actualHome !== undefined
|
|
19
|
+
&& accountPath(launch.expectedAccountHome) === accountPath(actualHome);
|
|
20
|
+
if (launch.expectedAccountHome !== undefined && actualHome !== undefined && !sameAccount) {
|
|
21
|
+
throw new Error("Native recovery connected to a different account Home; restore the recorded connection.");
|
|
22
|
+
}
|
|
23
|
+
const runtime = new CodexAppServerRuntime(channel);
|
|
24
|
+
const latestTurn = async () => {
|
|
25
|
+
const page = await channel.request("thread/turns/list", {
|
|
26
|
+
threadId: input.conversationId, limit: 1, sortDirection: "desc", itemsView: "notLoaded"
|
|
27
|
+
});
|
|
28
|
+
return Array.isArray(page.data) ? page.data[0] : undefined;
|
|
29
|
+
};
|
|
30
|
+
const read = async () => {
|
|
31
|
+
try {
|
|
32
|
+
return await runtime.readConversation(input.conversationId, { includeTurns: false });
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (codexAppServerErrorIsMissing(error) && sameAccount)
|
|
36
|
+
return null;
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
let snapshot = await read();
|
|
41
|
+
if (snapshot === null)
|
|
42
|
+
return;
|
|
43
|
+
if (input.clearGoal && await runtime.readGoal(input.conversationId) !== null) {
|
|
44
|
+
await channel.request("thread/goal/clear", { threadId: input.conversationId });
|
|
45
|
+
}
|
|
46
|
+
let active = snapshot.activeTurnId ?? input.nativeTurnId;
|
|
47
|
+
if (snapshot.status === "active" && active === undefined) {
|
|
48
|
+
// Receipt loss does not justify loading an unbounded transcript or
|
|
49
|
+
// guessing which Turn ran. Ask for one metadata-only native record.
|
|
50
|
+
const latest = await latestTurn();
|
|
51
|
+
if (latest?.status === "inProgress" && typeof latest.id === "string")
|
|
52
|
+
active = latest.id;
|
|
53
|
+
}
|
|
54
|
+
if (snapshot.status === "active" && active !== undefined) {
|
|
55
|
+
if (input.nativeTurnId !== undefined && snapshot.activeTurnId !== undefined && active !== input.nativeTurnId) {
|
|
56
|
+
throw new Error("The native conversation has a different active Turn; inspect its owner before stopping it.");
|
|
57
|
+
}
|
|
58
|
+
const interrupted = await runtime.interruptTurn({ conversationId: input.conversationId, turnId: active });
|
|
59
|
+
if (interrupted !== "interrupted") {
|
|
60
|
+
snapshot = await read();
|
|
61
|
+
if (snapshot?.status === "active")
|
|
62
|
+
throw new Error("The exact native Turn could not be stopped; another execution may be active.");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const deadline = Date.now() + 8000;
|
|
66
|
+
for (;;) {
|
|
67
|
+
snapshot = await read();
|
|
68
|
+
if (snapshot === null || snapshot.status === "notLoaded")
|
|
69
|
+
return;
|
|
70
|
+
// A native error can leave the Thread in systemError after its Turn
|
|
71
|
+
// failed. Prove the exact latest Turn is terminal, then drain any
|
|
72
|
+
// background tools; the diagnostic label must not prevent replacement.
|
|
73
|
+
const errorTurn = snapshot.status === "systemError" ? await latestTurn() : undefined;
|
|
74
|
+
const erroredAndTerminal = errorTurn !== undefined && typeof errorTurn.id === "string"
|
|
75
|
+
&& ["completed", "failed", "interrupted"].includes(errorTurn.status);
|
|
76
|
+
if (snapshot.status === "systemError" && !erroredAndTerminal) {
|
|
77
|
+
throw new Error("Native systemError has no proven terminal latest Turn; inspect native execution before replacing it.");
|
|
78
|
+
}
|
|
79
|
+
if (snapshot.status === "idle" || erroredAndTerminal) {
|
|
80
|
+
await channel.request("thread/backgroundTerminals/clean", { threadId: input.conversationId });
|
|
81
|
+
const terminals = await channel.request("thread/backgroundTerminals/list", { threadId: input.conversationId, limit: 1 });
|
|
82
|
+
if (Array.isArray(terminals.data) && terminals.data.length === 0 && terminals.nextCursor == null)
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (Date.now() >= deadline) {
|
|
86
|
+
throw new Error(`Native conversation ${input.conversationId} is not confirmed quiescent (${snapshot.status}).`);
|
|
87
|
+
}
|
|
88
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
channel.close();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function accountPath(path) {
|
|
96
|
+
try {
|
|
97
|
+
return realpathSync(path);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return path;
|
|
101
|
+
}
|
|
102
|
+
}
|
package/dist/runtime/ports.js
CHANGED
|
@@ -1,43 +1,28 @@
|
|
|
1
|
-
/** A
|
|
1
|
+
/** A Session launch may be temporarily unavailable or fail with a diagnosis. */
|
|
2
2
|
export class RuntimeLaunchError extends Error {
|
|
3
3
|
retryable;
|
|
4
|
-
runtimeGenerationId;
|
|
5
4
|
reason;
|
|
6
5
|
name = "RuntimeLaunchError";
|
|
7
|
-
constructor(retryable,
|
|
6
|
+
constructor(retryable, message, reason, options) {
|
|
8
7
|
super(message, options);
|
|
9
8
|
this.retryable = retryable;
|
|
10
|
-
this.runtimeGenerationId = runtimeGenerationId;
|
|
11
9
|
this.reason = reason;
|
|
12
10
|
}
|
|
13
11
|
}
|
|
14
12
|
/** A host-side contention check that occurs before planning or process start. */
|
|
15
|
-
export class RuntimeHostContentionError extends
|
|
13
|
+
export class RuntimeHostContentionError extends RuntimeLaunchError {
|
|
16
14
|
reason;
|
|
17
15
|
name = "RuntimeHostContentionError";
|
|
18
16
|
constructor(reason, message) {
|
|
19
|
-
super(message);
|
|
17
|
+
super(true, message, reason);
|
|
20
18
|
this.reason = reason;
|
|
21
19
|
}
|
|
22
20
|
}
|
|
23
|
-
/** A reused Agent Host acknowledged a different runtime generation. */
|
|
24
|
-
export class RuntimeGenerationMismatchError extends Error {
|
|
25
|
-
expectedRuntimeGenerationId;
|
|
26
|
-
observedRuntimeGenerationId;
|
|
27
|
-
hostState;
|
|
28
|
-
name = "RuntimeGenerationMismatchError";
|
|
29
|
-
constructor(expectedRuntimeGenerationId, observedRuntimeGenerationId, hostState, message) {
|
|
30
|
-
super(message);
|
|
31
|
-
this.expectedRuntimeGenerationId = expectedRuntimeGenerationId;
|
|
32
|
-
this.observedRuntimeGenerationId = observedRuntimeGenerationId;
|
|
33
|
-
this.hostState = hostState;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
21
|
/** A reused Host reported an unusable state; this operation did not create it. */
|
|
37
22
|
export class RuntimeHostUnavailableError extends RuntimeLaunchError {
|
|
38
23
|
hostState;
|
|
39
|
-
constructor(
|
|
40
|
-
super(false,
|
|
24
|
+
constructor(hostState, message, options) {
|
|
25
|
+
super(false, message, undefined, options);
|
|
41
26
|
this.hostState = hostState;
|
|
42
27
|
}
|
|
43
28
|
}
|
|
@@ -9,8 +9,7 @@ export function validateRuntimeProcessExitObservation(observation) {
|
|
|
9
9
|
optionalIdentity(observation.providerProcessInstanceId, "providerProcessInstanceId");
|
|
10
10
|
optionalIdentity(observation.taskId, "taskId");
|
|
11
11
|
identity(observation.roleName, "roleName");
|
|
12
|
-
optionalIdentity(observation.
|
|
13
|
-
identity(observation.runtimeGenerationId, "runtimeGenerationId");
|
|
12
|
+
optionalIdentity(observation.runId, "runId");
|
|
14
13
|
optionalIdentity(observation.nativeSessionId, "nativeSessionId");
|
|
15
14
|
if (observation.processKind !== "agent-host" && observation.processKind !== "provider-child") {
|
|
16
15
|
throw new Error("Runtime process kind is invalid.");
|
|
@@ -26,22 +25,24 @@ export function validateRuntimeProcessExitObservation(observation) {
|
|
|
26
25
|
if (!Number.isFinite(Date.parse(observation.observedAt))) {
|
|
27
26
|
throw new Error("Runtime process observedAt is invalid.");
|
|
28
27
|
}
|
|
29
|
-
|
|
28
|
+
if (observation.stopRequested !== undefined && typeof observation.stopRequested !== "boolean") {
|
|
29
|
+
throw new Error("stopRequested must be boolean.");
|
|
30
|
+
}
|
|
30
31
|
optionalIdentity(observation.lastProviderEventId, "lastProviderEventId");
|
|
31
32
|
optionalIdentity(observation.diagnosticTailRef, "diagnosticTailRef");
|
|
32
33
|
return Object.freeze({ ...observation });
|
|
33
34
|
}
|
|
34
35
|
export function classifyRuntimeProcessExit(observation, input) {
|
|
35
36
|
validateRuntimeProcessExitObservation(observation);
|
|
36
|
-
if (observation.
|
|
37
|
-
return "
|
|
38
|
-
if (observation.processKind === "provider-child" && input.
|
|
37
|
+
if (observation.stopRequested === true)
|
|
38
|
+
return "stop-requested";
|
|
39
|
+
if (observation.processKind === "provider-child" && input.runFailureObserved === true) {
|
|
39
40
|
return "provider-turn-failed";
|
|
40
41
|
}
|
|
41
42
|
if (observation.processKind === "provider-child"
|
|
42
43
|
&& input.childLifecycle === "per-turn"
|
|
43
44
|
&& observation.exitCode === 0
|
|
44
|
-
&& input.
|
|
45
|
+
&& input.runTerminalObserved === true) {
|
|
45
46
|
return "expected-per-turn-exit";
|
|
46
47
|
}
|
|
47
48
|
if ((observation.exitCode !== undefined && observation.exitCode !== 0)
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { requireText, requireTimestamp } from "./validation.js";
|
|
2
|
-
import {
|
|
2
|
+
import { formatRunReceiptId, formatInputRequestReceiptId, validateTaskRecordReference } from "../task/taskRecordReference.js";
|
|
3
3
|
export function createPromptEnvelope(input) {
|
|
4
|
-
if (input.source.kind !== "
|
|
4
|
+
if (input.source.kind !== "run"
|
|
5
5
|
&& input.source.kind !== "turn-input"
|
|
6
|
-
&& input.source.kind !== "input-request") {
|
|
6
|
+
&& input.source.kind !== "input-request" && input.source.kind !== "notification") {
|
|
7
7
|
throw new Error("Prompt source kind is invalid.");
|
|
8
8
|
}
|
|
9
9
|
const source = validateTaskRecordReference({
|
|
10
10
|
taskId: input.source.taskId,
|
|
11
11
|
localId: input.source.localId
|
|
12
|
-
}, input.source.kind === "input-request" ? "inputRequest"
|
|
12
|
+
}, input.source.kind === "input-request" ? "inputRequest"
|
|
13
|
+
: input.source.kind === "notification" ? "taskWake" : "run");
|
|
13
14
|
const id = requireQualifiedReceiptId(input.id, input.source.kind, source.taskId, source.localId);
|
|
14
15
|
return {
|
|
15
16
|
id,
|
|
@@ -23,8 +24,15 @@ export function createPromptEnvelope(input) {
|
|
|
23
24
|
};
|
|
24
25
|
}
|
|
25
26
|
function requireQualifiedReceiptId(value, kind, taskId, localId) {
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
if (kind === "notification") {
|
|
28
|
+
const prefix = `notification:${taskId}/${localId}/`;
|
|
29
|
+
if (!value.startsWith(prefix) || !/^[a-zA-Z0-9-]+$/.test(value.slice(prefix.length))) {
|
|
30
|
+
throw new Error("Notification attempt does not match its wake.");
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
const expected = kind === "run"
|
|
35
|
+
? formatRunReceiptId(taskId, localId)
|
|
28
36
|
: kind === "input-request"
|
|
29
37
|
? formatInputRequestReceiptId(taskId, localId)
|
|
30
38
|
: `turn-input:${taskId}/${localId}/`;
|
|
@@ -35,6 +43,9 @@ function requireQualifiedReceiptId(value, kind, taskId, localId) {
|
|
|
35
43
|
}
|
|
36
44
|
return value;
|
|
37
45
|
}
|
|
46
|
+
if (kind === "run" && value.startsWith(`${expected}/attempt/`)
|
|
47
|
+
&& /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(value.slice(`${expected}/attempt/`.length)))
|
|
48
|
+
return value;
|
|
38
49
|
if (value !== expected)
|
|
39
50
|
throw new Error("Prompt envelope id does not match its source.");
|
|
40
51
|
return expected;
|
|
@@ -4,9 +4,7 @@ export function providerContinuationKey(identity) {
|
|
|
4
4
|
normalized.providerNamespace,
|
|
5
5
|
normalized.accountScope,
|
|
6
6
|
normalized.conversationId,
|
|
7
|
-
normalized.
|
|
8
|
-
normalized.continuationId,
|
|
9
|
-
normalized.generation
|
|
7
|
+
normalized.continuationId
|
|
10
8
|
].join("\u0000");
|
|
11
9
|
}
|
|
12
10
|
export function createProviderContinuation(input) {
|
|
@@ -14,7 +12,7 @@ export function createProviderContinuation(input) {
|
|
|
14
12
|
schemaVersion: 1,
|
|
15
13
|
taskId: text(input.taskId, "Task id"),
|
|
16
14
|
roleName: text(input.roleName, "Role name"),
|
|
17
|
-
|
|
15
|
+
runId: text(input.runId, "AgentRun id"),
|
|
18
16
|
identity: validateProviderContinuationIdentity(input.identity),
|
|
19
17
|
...(input.parentContinuationId === undefined
|
|
20
18
|
? {}
|
|
@@ -152,7 +150,7 @@ export function validateProviderContinuation(value) {
|
|
|
152
150
|
throw new Error("Provider Continuation schemaVersion must be 1.");
|
|
153
151
|
text(value.taskId, "Task id");
|
|
154
152
|
text(value.roleName, "Role name");
|
|
155
|
-
text(value.
|
|
153
|
+
text(value.runId, "AgentRun id");
|
|
156
154
|
validateProviderContinuationIdentity(value.identity);
|
|
157
155
|
if (!["active", "quiescent", "unknown"].includes(value.execution)) {
|
|
158
156
|
throw new Error("Provider Continuation execution is invalid.");
|
|
@@ -203,11 +201,7 @@ export function validateProviderContinuationIdentity(value) {
|
|
|
203
201
|
text(value.providerNamespace, "Provider namespace");
|
|
204
202
|
text(value.accountScope, "Provider account scope");
|
|
205
203
|
text(value.conversationId, "Provider Conversation id");
|
|
206
|
-
text(value.activationId, "Provider Activation id");
|
|
207
204
|
text(value.continuationId, "Provider Continuation id");
|
|
208
|
-
if (!Number.isSafeInteger(value.generation) || value.generation < 1) {
|
|
209
|
-
throw new Error("Provider Continuation generation is invalid.");
|
|
210
|
-
}
|
|
211
205
|
return value;
|
|
212
206
|
}
|
|
213
207
|
function validateProviderReport(value) {
|
|
@@ -89,18 +89,11 @@ function groupDetachedContinuations(continuations, observations) {
|
|
|
89
89
|
const key = [
|
|
90
90
|
continuation.identity.providerNamespace,
|
|
91
91
|
continuation.identity.accountScope,
|
|
92
|
-
continuation.identity.conversationId
|
|
93
|
-
continuation.identity.activationId
|
|
92
|
+
continuation.identity.conversationId
|
|
94
93
|
].join("\u0000");
|
|
95
|
-
const source = [...observations].reverse().find((observation) => (observation.kind.startsWith("continuation.")
|
|
96
|
-
&& observation.fence.driverId === continuation.identity.providerNamespace
|
|
97
|
-
&& observation.fence.agentId === continuation.identity.accountScope
|
|
98
|
-
&& observation.fence.conversationId === continuation.identity.conversationId
|
|
99
|
-
&& observation.fence.activationId === continuation.identity.activationId
|
|
100
|
-
&& observation.fence.continuationId === continuation.identity.continuationId
|
|
101
|
-
&& observation.fence.continuationGeneration === continuation.identity.generation));
|
|
94
|
+
const source = [...observations].reverse().find((observation) => (observation.kind.startsWith("continuation.") && observation.fence.driverId === continuation.identity.providerNamespace && observation.fence.agentId === continuation.identity.accountScope && observation.fence.conversationId === continuation.identity.conversationId && observation.fence.continuationId === continuation.identity.continuationId));
|
|
102
95
|
// A projected continuation without its original durable fence cannot be
|
|
103
|
-
// safely attached to a live
|
|
96
|
+
// safely attached to a live AgentRun. Keep ownership conservative and let the
|
|
104
97
|
// malformed identity remain visible instead of synthesizing a receipt.
|
|
105
98
|
if (source === undefined)
|
|
106
99
|
continue;
|
|
@@ -149,14 +142,12 @@ function reconciliationObservation(continuation, sourceFence, now) {
|
|
|
149
142
|
...sourceFence,
|
|
150
143
|
taskId: continuation.taskId,
|
|
151
144
|
roleName: continuation.roleName,
|
|
152
|
-
|
|
145
|
+
runId: continuation.runId,
|
|
153
146
|
agentId: continuation.identity.accountScope,
|
|
154
147
|
driverId: continuation.identity.providerNamespace,
|
|
155
148
|
conversationId: continuation.identity.conversationId,
|
|
156
|
-
activationId: continuation.identity.activationId,
|
|
157
149
|
nativeSessionId: continuation.identity.conversationId,
|
|
158
150
|
continuationId: continuation.identity.continuationId,
|
|
159
|
-
continuationGeneration: continuation.identity.generation,
|
|
160
151
|
...(continuation.parentContinuationId === undefined
|
|
161
152
|
? {}
|
|
162
153
|
: { parentContinuationId: continuation.parentContinuationId })
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { currentProviderAuthority, currentProviderConversation, validateProviderRuntimeBinding } from "./providerRuntimeIdentity.js";
|
|
2
2
|
/**
|
|
3
3
|
* Applies the durable single-writer fence before any Provider mutation. The
|
|
4
4
|
* Adapter never receives authority to infer or repair identity.
|
|
@@ -33,13 +33,8 @@ export class FencedProviderControl {
|
|
|
33
33
|
const normalized = validateProviderRuntimeBinding(binding);
|
|
34
34
|
this.#assertNamespace(normalized);
|
|
35
35
|
const conversation = currentProviderConversation(normalized);
|
|
36
|
-
const activation = currentProviderActivation(normalized);
|
|
37
36
|
const authority = currentProviderAuthority(normalized);
|
|
38
|
-
if (conversation.conversationId !== fence.conversationId
|
|
39
|
-
|| activation?.activationId !== fence.activationId
|
|
40
|
-
|| authority.epoch !== fence.authorityEpoch
|
|
41
|
-
|| authority.owner !== fence.authorityOwner
|
|
42
|
-
|| authority.holderId !== fence.holderId) {
|
|
37
|
+
if (conversation.conversationId !== fence.conversationId || authority.epoch !== fence.authorityEpoch || authority.owner !== fence.authorityOwner || authority.holderId !== fence.holderId) {
|
|
43
38
|
throw new Error("Provider writer fence is stale.");
|
|
44
39
|
}
|
|
45
40
|
}
|