@zq-silk/yui 0.15.7 → 0.15.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 +194 -399
- package/ARCHITECTURE.zh-CN.md +151 -0
- package/README.md +306 -1131
- 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/artifacts/artifactCapability.js +74 -0
- package/dist/artifacts/artifactCommitLock.js +249 -0
- package/dist/artifacts/artifactPaths.js +151 -0
- package/dist/artifacts/gitArtifactRef.js +146 -0
- package/dist/artifacts/managedGit.js +332 -0
- package/dist/artifacts/taskArtifactRepository.js +277 -0
- package/dist/brief/taskBrief.js +12 -0
- package/dist/cli/agentConfigurationPicker.js +13 -0
- package/dist/cli/commandCatalog.js +165 -74
- 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 +245 -95
- package/dist/commands/agentCommands.js +72 -14
- package/dist/commands/capabilityCommands.js +9 -6
- 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 +34 -9
- 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 +281 -0
- package/dist/commands/taskActor.js +28 -49
- package/dist/commands/taskCommands.js +1461 -720
- 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} +158 -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 +481 -0
- package/dist/context/wakeNotification.js +27 -27
- package/dist/controller/agentRuntimeObserver.js +21 -24
- package/dist/controller/capabilityBridge.js +17 -6
- package/dist/controller/clientRuntime.js +65 -92
- package/dist/controller/controller.js +120 -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 +529 -479
- 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 +255 -12
- package/dist/kernel/capabilityRegistry.js +64 -18
- package/dist/kernel/instanceHost.js +12 -1
- package/dist/kernel/kernelPorts.js +2 -2
- package/dist/lifecycle/canonicalLifecycleEvent.js +44 -49
- package/dist/lifecycle/exactRunTerminalization.js +449 -0
- package/dist/message/message.js +118 -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 +388 -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 +75 -0
- package/dist/resources/projectResourceService.js +343 -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 +3 -7
- package/dist/storage/migrations/agentRunContract.js +159 -0
- package/dist/storage/migrations/artifactsToGit.js +338 -0
- package/dist/storage/migrations/removeRuntimeGeneration.js +207 -0
- package/dist/storage/migrations/submitIntent.js +126 -0
- package/dist/storage/sqliteSchema.js +467 -7
- package/dist/storage/sqliteStore.js +355 -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 +327 -0
- package/dist/task/taskActivationService.js +408 -0
- package/dist/task/taskRecordReference.js +5 -4
- package/dist/task/taskRecordRetirement.js +1 -1
- package/dist/task/taskSubmission.js +236 -0
- 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 +121 -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 +442 -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 +133 -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 +84 -48
- package/dist/workspace/workItemChangeSetManager.js +16 -9
- package/docs/agent-result-consumption.md +96 -0
- package/docs/agent-result-consumption.zh-CN.md +81 -0
- package/docs/agent-runtime-drivers.md +93 -0
- package/docs/agent-runtime-drivers.zh-CN.md +77 -0
- package/docs/architecture/README.md +50 -0
- package/docs/architecture/README.zh-CN.md +43 -0
- package/docs/architecture/capabilities-and-resources.md +118 -0
- package/docs/architecture/capabilities-and-resources.zh-CN.md +83 -0
- package/docs/managed-turn-and-session-runtime.md +224 -0
- package/docs/managed-turn-and-session-runtime.zh-CN.md +180 -0
- package/docs/observability/README.md +83 -0
- package/docs/observability/README.zh-CN.md +71 -0
- package/docs/plugin-sdk.md +393 -0
- package/docs/plugin-sdk.zh-CN.md +293 -0
- package/docs/provider-runtime.md +165 -0
- package/docs/provider-runtime.zh-CN.md +132 -0
- package/docs/release-workflow.md +305 -0
- package/docs/release-workflow.zh-CN.md +237 -0
- package/docs/roles-and-configuration.md +115 -0
- package/docs/roles-and-configuration.zh-CN.md +96 -0
- package/docs/sqlite-control-plane-design.md +78 -0
- package/docs/sqlite-control-plane-design.zh-CN.md +62 -0
- package/docs/task-dag-semantics.md +80 -0
- package/docs/task-dag-semantics.zh-CN.md +59 -0
- package/docs/task-delivery.md +105 -0
- package/docs/task-delivery.zh-CN.md +82 -0
- package/docs/task-local-identity.md +8 -6
- package/docs/task-local-identity.zh-CN.md +58 -0
- package/docs/testing/verification-levels.md +88 -0
- package/docs/testing/verification-levels.zh-CN.md +69 -0
- package/i18n/README.zh-CN.md +270 -722
- package/package.json +3 -2
- package/skills/yui-leader/SKILL.md +88 -304
- package/skills/yui-leader/references/execution.md +303 -0
- package/skills/yui-leader/references/integration.md +39 -0
- package/skills/yui-leader/references/planning.md +109 -0
- package/skills/yui-leader/references/replicated-execution.md +42 -0
- package/skills/yui-leader/references/task-plugins.md +37 -0
- package/skills/yui-operator/SKILL.md +46 -62
- 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
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a live Agent Session can be asked about the run configuration it is
|
|
3
|
+
* actually operating under.
|
|
4
|
+
*
|
|
5
|
+
* Yui already records what a launch *requested*: a Role's model, reasoning
|
|
6
|
+
* effort and permission strategy resolve into an effective launch snapshot that
|
|
7
|
+
* every `show` surface prints. That snapshot is an expectation, and it is
|
|
8
|
+
* complete on its own terms. What it cannot answer is whether the Agent agreed:
|
|
9
|
+
* a requested model the Agent does not offer, a permission mode it silently
|
|
10
|
+
* substituted, or an axis it reset when a later call landed are all invisible to
|
|
11
|
+
* a record written before the process started.
|
|
12
|
+
*
|
|
13
|
+
* This is the read path for that second question, and it is deliberately
|
|
14
|
+
* separate from the first. Presenting configuration expectation as execution
|
|
15
|
+
* fact is the specific failure this vocabulary exists to prevent, so every
|
|
16
|
+
* value here carries how it was learned, and the three ways of not knowing stay
|
|
17
|
+
* distinct instead of collapsing into one blank:
|
|
18
|
+
*
|
|
19
|
+
* - `unknown` means nobody could be asked. There is no live Session, or the
|
|
20
|
+
* Session exists but could not be reached. It says nothing about the Agent.
|
|
21
|
+
* - `unsupported` means this Session implementation has no observation reader.
|
|
22
|
+
* It does not claim the underlying product can never report these facts.
|
|
23
|
+
* - `observed` carries what the Agent itself reported, and only that.
|
|
24
|
+
*
|
|
25
|
+
* Nothing here performs I/O or holds a product name. A Session that can answer
|
|
26
|
+
* projects its own protocol's report into this shape; a Session that cannot
|
|
27
|
+
* returns the `unsupported` branch. Reading it never sends a protocol message,
|
|
28
|
+
* because a query that configured or prompted the Agent would change the thing
|
|
29
|
+
* it claims to describe.
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* The answer when there is no live Session to ask, or it could not be reached.
|
|
33
|
+
*
|
|
34
|
+
* Kept apart from `unsupported` because the two would otherwise both render as
|
|
35
|
+
* "no data" while meaning opposite things: this one says Yui did not get an
|
|
36
|
+
* answer, the other says the Agent has none to give.
|
|
37
|
+
*/
|
|
38
|
+
export function unknownAgentRunConfiguration(reason) {
|
|
39
|
+
return Object.freeze({ status: "unknown", reason });
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The answer for a Session implementation without a run-configuration reader.
|
|
43
|
+
*
|
|
44
|
+
* Stated once so the two implementations that share this position cannot drift
|
|
45
|
+
* into describing it differently, and so the reason travels with the status
|
|
46
|
+
* instead of being reconstructed by whoever renders it.
|
|
47
|
+
*/
|
|
48
|
+
export function unsupportedAgentRunConfiguration(protocolDescription) {
|
|
49
|
+
return Object.freeze({
|
|
50
|
+
status: "unsupported",
|
|
51
|
+
reason: `${protocolDescription}: this Yui Session implementation exposes no run configuration observation, so Yui cannot `
|
|
52
|
+
+ `confirm which model, reasoning effort or permission mode this Session is `
|
|
53
|
+
+ `operating under. See the Session's pinned launch request; current Role settings may differ.`
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Project a negotiated capability exchange into the shared handshake shape.
|
|
58
|
+
*
|
|
59
|
+
* The parameter is described structurally rather than by naming a protocol type,
|
|
60
|
+
* so this module stays free of any one protocol while still being the single
|
|
61
|
+
* place the projection happens. That matters because the two callers learn the
|
|
62
|
+
* same facts at different moments — a capability probe before any Session
|
|
63
|
+
* exists, and a live Session at launch — and a second copy of this mapping would
|
|
64
|
+
* let `yui config agent capabilities` and a Session inspect disagree about the
|
|
65
|
+
* same Agent's advertised capabilities.
|
|
66
|
+
*
|
|
67
|
+
* Only enabled capabilities are listed, and a silent Agent stays `unknown`
|
|
68
|
+
* rather than being resolved into a product by anything Yui knows about the
|
|
69
|
+
* command it ran.
|
|
70
|
+
*/
|
|
71
|
+
export function handshakeObservationFrom(negotiated) {
|
|
72
|
+
return Object.freeze({
|
|
73
|
+
status: "observed",
|
|
74
|
+
protocolVersion: negotiated.protocolVersion,
|
|
75
|
+
agentName: negotiated.agentName ?? "unknown",
|
|
76
|
+
agentVersion: negotiated.agentVersion ?? "unknown",
|
|
77
|
+
capabilities: Object.freeze(Object.entries(negotiated.capabilities)
|
|
78
|
+
.filter(([, enabled]) => enabled)
|
|
79
|
+
.map(([name]) => name)
|
|
80
|
+
.sort()),
|
|
81
|
+
authMethods: Object.freeze(negotiated.authMethods.map((method) => method.id).sort())
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Read an observation back from a parsed control response.
|
|
86
|
+
*
|
|
87
|
+
* This value is produced inside the Agent Host and read by a CLI process, so it
|
|
88
|
+
* arrives as untyped JSON from another program. A malformed one must not
|
|
89
|
+
* degrade into a confident-looking partial reading: an entry missing its
|
|
90
|
+
* confirmation would render as a blank cell that looks like agreement. So
|
|
91
|
+
* anything that does not parse becomes `unknown` with the reason saying so,
|
|
92
|
+
* which is the same answer as a Session that could not be reached — because
|
|
93
|
+
* that is exactly what it is.
|
|
94
|
+
*/
|
|
95
|
+
export function readAgentRunConfigurationObservation(value) {
|
|
96
|
+
const malformed = unknownAgentRunConfiguration("The Agent Host reported run configuration in a shape this build does not "
|
|
97
|
+
+ "recognize, so nothing about the live Session's configuration can be shown.");
|
|
98
|
+
const observation = asRecord(value);
|
|
99
|
+
if (observation === undefined)
|
|
100
|
+
return malformed;
|
|
101
|
+
if (observation.status === "unknown" || observation.status === "unsupported") {
|
|
102
|
+
const reason = text(observation.reason);
|
|
103
|
+
if (reason === undefined)
|
|
104
|
+
return malformed;
|
|
105
|
+
return Object.freeze({ status: observation.status, reason });
|
|
106
|
+
}
|
|
107
|
+
if (observation.status !== "observed")
|
|
108
|
+
return malformed;
|
|
109
|
+
const observedAt = text(observation.observedAt);
|
|
110
|
+
const handshake = readHandshake(observation.handshake);
|
|
111
|
+
if (observedAt === undefined || !Number.isFinite(Date.parse(observedAt))
|
|
112
|
+
|| handshake === undefined)
|
|
113
|
+
return malformed;
|
|
114
|
+
if (!Array.isArray(observation.requested) || !Array.isArray(observation.axes))
|
|
115
|
+
return malformed;
|
|
116
|
+
const requested = [];
|
|
117
|
+
for (const entry of observation.requested) {
|
|
118
|
+
const request = readRequest(entry);
|
|
119
|
+
// One unreadable entry cannot be skipped: the list would then look complete
|
|
120
|
+
// while silently omitting a requested value, which is the difference between
|
|
121
|
+
// "not requested" and "requested, outcome lost".
|
|
122
|
+
if (request === undefined)
|
|
123
|
+
return malformed;
|
|
124
|
+
requested.push(request);
|
|
125
|
+
}
|
|
126
|
+
const axes = [];
|
|
127
|
+
for (const entry of observation.axes) {
|
|
128
|
+
const axis = readAxis(entry);
|
|
129
|
+
if (axis === undefined)
|
|
130
|
+
return malformed;
|
|
131
|
+
axes.push(axis);
|
|
132
|
+
}
|
|
133
|
+
return Object.freeze({
|
|
134
|
+
status: "observed",
|
|
135
|
+
observedAt,
|
|
136
|
+
handshake,
|
|
137
|
+
requested: Object.freeze(requested),
|
|
138
|
+
axes: Object.freeze(axes)
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function readRequest(value) {
|
|
142
|
+
const entry = asRecord(value);
|
|
143
|
+
if (entry === undefined)
|
|
144
|
+
return undefined;
|
|
145
|
+
const field = entry.field;
|
|
146
|
+
const key = text(entry.key);
|
|
147
|
+
const requestedValue = text(entry.value);
|
|
148
|
+
const confirmation = entry.confirmation;
|
|
149
|
+
if (field !== "model" && field !== "effort" && field !== "permission")
|
|
150
|
+
return undefined;
|
|
151
|
+
if (key === undefined || requestedValue === undefined)
|
|
152
|
+
return undefined;
|
|
153
|
+
if (confirmation !== "already" && confirmation !== "observed" && confirmation !== "acknowledged") {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
const current = readCurrentValue(entry.current);
|
|
157
|
+
if (current === undefined)
|
|
158
|
+
return undefined;
|
|
159
|
+
return Object.freeze({ field, key, value: requestedValue, confirmation, current });
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Read the current value and its evidence, shared by both tables.
|
|
163
|
+
*
|
|
164
|
+
* One reader because one shape: an axis and a requested value answer the same
|
|
165
|
+
* question about evidence, and a second implementation is where the two would
|
|
166
|
+
* eventually come to disagree about what counts as observed.
|
|
167
|
+
*/
|
|
168
|
+
function readCurrentValue(value) {
|
|
169
|
+
const current = asRecord(value);
|
|
170
|
+
if (current === undefined)
|
|
171
|
+
return undefined;
|
|
172
|
+
if (current.status === "observed") {
|
|
173
|
+
const observed = text(current.value);
|
|
174
|
+
return observed === undefined
|
|
175
|
+
? undefined
|
|
176
|
+
: Object.freeze({ status: "observed", value: observed });
|
|
177
|
+
}
|
|
178
|
+
if (current.status !== "unobserved")
|
|
179
|
+
return undefined;
|
|
180
|
+
const reason = text(current.reason);
|
|
181
|
+
return reason === undefined ? undefined : Object.freeze({ status: "unobserved", reason });
|
|
182
|
+
}
|
|
183
|
+
function readAxis(value) {
|
|
184
|
+
const entry = asRecord(value);
|
|
185
|
+
if (entry === undefined)
|
|
186
|
+
return undefined;
|
|
187
|
+
const key = text(entry.key);
|
|
188
|
+
const current = readCurrentValue(entry.current);
|
|
189
|
+
if (key === undefined || current === undefined)
|
|
190
|
+
return undefined;
|
|
191
|
+
if (!Array.isArray(entry.offered))
|
|
192
|
+
return undefined;
|
|
193
|
+
const offered = [];
|
|
194
|
+
for (const candidate of entry.offered) {
|
|
195
|
+
const offer = text(candidate);
|
|
196
|
+
if (offer === undefined)
|
|
197
|
+
return undefined;
|
|
198
|
+
offered.push(offer);
|
|
199
|
+
}
|
|
200
|
+
const category = text(entry.category);
|
|
201
|
+
return Object.freeze({
|
|
202
|
+
key,
|
|
203
|
+
...(category === undefined ? {} : { category }),
|
|
204
|
+
current,
|
|
205
|
+
offered: Object.freeze(offered)
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
function readHandshake(value) {
|
|
209
|
+
const handshake = asRecord(value);
|
|
210
|
+
if (handshake === undefined)
|
|
211
|
+
return undefined;
|
|
212
|
+
if (handshake.status === "unsupported") {
|
|
213
|
+
const reason = text(handshake.reason);
|
|
214
|
+
return reason === undefined ? undefined : Object.freeze({ status: "unsupported", reason });
|
|
215
|
+
}
|
|
216
|
+
if (handshake.status !== "observed")
|
|
217
|
+
return undefined;
|
|
218
|
+
const protocolVersion = handshake.protocolVersion;
|
|
219
|
+
const agentName = text(handshake.agentName);
|
|
220
|
+
const agentVersion = text(handshake.agentVersion);
|
|
221
|
+
if (typeof protocolVersion !== "number" || !Number.isSafeInteger(protocolVersion))
|
|
222
|
+
return undefined;
|
|
223
|
+
if (agentName === undefined || agentVersion === undefined)
|
|
224
|
+
return undefined;
|
|
225
|
+
if (!Array.isArray(handshake.capabilities) || !Array.isArray(handshake.authMethods)) {
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
const capabilities = [];
|
|
229
|
+
for (const candidate of handshake.capabilities) {
|
|
230
|
+
const capability = text(candidate);
|
|
231
|
+
if (capability === undefined)
|
|
232
|
+
return undefined;
|
|
233
|
+
capabilities.push(capability);
|
|
234
|
+
}
|
|
235
|
+
const authMethods = [];
|
|
236
|
+
for (const candidate of handshake.authMethods) {
|
|
237
|
+
const method = text(candidate);
|
|
238
|
+
if (method === undefined)
|
|
239
|
+
return undefined;
|
|
240
|
+
authMethods.push(method);
|
|
241
|
+
}
|
|
242
|
+
return Object.freeze({
|
|
243
|
+
status: "observed",
|
|
244
|
+
protocolVersion,
|
|
245
|
+
agentName,
|
|
246
|
+
agentVersion,
|
|
247
|
+
capabilities: Object.freeze(capabilities),
|
|
248
|
+
authMethods: Object.freeze(authMethods)
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
function asRecord(value) {
|
|
252
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
253
|
+
? value
|
|
254
|
+
: undefined;
|
|
255
|
+
}
|
|
256
|
+
function text(value) {
|
|
257
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
258
|
+
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { AgentDriverRegistry } from "./agentDriver.js";
|
|
2
2
|
import { claudeTranscriptObserver, codexTranscriptObserver, transcriptObserverSource } from "./builtinTranscriptObserver.js";
|
|
3
|
-
import { mapClaudeAgentError, mapCodexAgentError } from "./builtinAgentErrorMappers.js";
|
|
3
|
+
import { mapAcpAgentError, mapClaudeAgentError, mapCodexAgentError } from "./builtinAgentErrorMappers.js";
|
|
4
4
|
import { serializeAgentErrorRaw, standardAgentError } from "./agentError.js";
|
|
5
5
|
import { transportAgentResult } from "../domain/agentResultTransport.js";
|
|
6
6
|
export const CODEX_DRIVER_ID = "openai/codex";
|
|
7
7
|
export const CLAUDE_CODE_DRIVER_ID = "anthropic/claude-code";
|
|
8
|
+
/**
|
|
9
|
+
* The Agent Client Protocol Driver is named after the protocol, not a product:
|
|
10
|
+
* every ACP Agent is observed through this one entry, so adding a second ACP
|
|
11
|
+
* CLI needs a launch descriptor and no new Driver.
|
|
12
|
+
*/
|
|
13
|
+
export const ACP_DRIVER_ID = "acp/agent-client-protocol";
|
|
8
14
|
export function builtinDriverIdForAdapter(adapterId) {
|
|
9
15
|
return builtinAgentDriverRegistry().requireByAdapterId(adapterId).id;
|
|
10
16
|
}
|
|
@@ -27,6 +33,9 @@ const STRUCTURED_CLI_CAPABILITIES = Object.freeze({
|
|
|
27
33
|
resume: true,
|
|
28
34
|
sendTurn: true,
|
|
29
35
|
interrupt: true,
|
|
36
|
+
// Conservative default: a Driver that has not stated otherwise is assumed
|
|
37
|
+
// to cancel by stopping the process Yui owns.
|
|
38
|
+
interruptDelivery: "owned-process",
|
|
30
39
|
stop: true
|
|
31
40
|
}),
|
|
32
41
|
conversation: Object.freeze({
|
|
@@ -94,7 +103,6 @@ export const BUILTIN_AGENT_DRIVERS = Object.freeze([
|
|
|
94
103
|
terminal: isTerminalHook(hookEventName),
|
|
95
104
|
...(hookEventName !== "SubagentStop" ? {} : {
|
|
96
105
|
continuationId: subagentId(payload),
|
|
97
|
-
continuationGeneration: continuationGeneration(payload)
|
|
98
106
|
})
|
|
99
107
|
}),
|
|
100
108
|
observer: Object.freeze({
|
|
@@ -123,6 +131,12 @@ export const BUILTIN_AGENT_DRIVERS = Object.freeze([
|
|
|
123
131
|
acceptance: "exact",
|
|
124
132
|
idempotency: "unavailable"
|
|
125
133
|
}),
|
|
134
|
+
control: Object.freeze({
|
|
135
|
+
...STRUCTURED_CLI_CAPABILITIES.control,
|
|
136
|
+
// Managed Codex interrupts its Turn through the App Server, which
|
|
137
|
+
// leaves the Session (and its process) alive.
|
|
138
|
+
interruptDelivery: "native"
|
|
139
|
+
}),
|
|
126
140
|
descendants: Object.freeze({
|
|
127
141
|
lineage: "partial",
|
|
128
142
|
detachedQuery: "partial",
|
|
@@ -152,7 +166,6 @@ export const BUILTIN_AGENT_DRIVERS = Object.freeze([
|
|
|
152
166
|
terminal: isTerminalHook(hookEventName),
|
|
153
167
|
...(hookEventName !== "SubagentStop" ? {} : {
|
|
154
168
|
continuationId: subagentId(payload),
|
|
155
|
-
continuationGeneration: continuationGeneration(payload)
|
|
156
169
|
})
|
|
157
170
|
}),
|
|
158
171
|
observer: Object.freeze({
|
|
@@ -160,6 +173,119 @@ export const BUILTIN_AGENT_DRIVERS = Object.freeze([
|
|
|
160
173
|
sample: codexTranscriptObserver
|
|
161
174
|
})
|
|
162
175
|
})
|
|
176
|
+
}),
|
|
177
|
+
Object.freeze({
|
|
178
|
+
id: ACP_DRIVER_ID,
|
|
179
|
+
label: "Agent Client Protocol",
|
|
180
|
+
protocolVersion: 1,
|
|
181
|
+
adapterId: "acp",
|
|
182
|
+
/**
|
|
183
|
+
* Declared from ACP v1 itself, not from any product's abilities.
|
|
184
|
+
*
|
|
185
|
+
* ACP is a client-driven JSON-RPC protocol: Yui owns the pipe and learns
|
|
186
|
+
* everything from request/response pairs, so there is no Hook ingress and
|
|
187
|
+
* no transcript file to sample. Several capabilities are therefore
|
|
188
|
+
* genuinely unavailable rather than merely unimplemented, and saying so is
|
|
189
|
+
* what keeps managed admission fail-closed.
|
|
190
|
+
*/
|
|
191
|
+
capabilities: Object.freeze({
|
|
192
|
+
// No interactive surface: `acp` mode is a machine protocol on stdio.
|
|
193
|
+
surfaces: Object.freeze(["managed-protocol"]),
|
|
194
|
+
lifecycle: Object.freeze({
|
|
195
|
+
host: "persistent",
|
|
196
|
+
providerProcess: "persistent",
|
|
197
|
+
// `session/load` is ACP's exact Conversation resume, so the protocol
|
|
198
|
+
// does define one and managed admission — which runs adapter-wide,
|
|
199
|
+
// before any connection exists — is right to see it here. What a
|
|
200
|
+
// *given* Agent implements is negotiated per connection via
|
|
201
|
+
// `agentCapabilities.loadSession`, and that answer cannot be predicted
|
|
202
|
+
// by a static table. The live Session therefore reports its own
|
|
203
|
+
// recoverability after the handshake, and that value, not this one, is
|
|
204
|
+
// what gets published and stored. An Agent that never advertised
|
|
205
|
+
// `loadSession` also fails loudly inside `session/load` rather than
|
|
206
|
+
// silently degrading a running Turn.
|
|
207
|
+
nativeConversationResume: "exact",
|
|
208
|
+
compaction: "unknown",
|
|
209
|
+
compactionEvents: "unavailable",
|
|
210
|
+
contextUsage: "unavailable",
|
|
211
|
+
inSessionContinuation: true,
|
|
212
|
+
deliveryDeduplication: "unsupported"
|
|
213
|
+
}),
|
|
214
|
+
control: Object.freeze({
|
|
215
|
+
start: true,
|
|
216
|
+
resume: true,
|
|
217
|
+
sendTurn: true,
|
|
218
|
+
// `session/cancel` is a notification the Agent MUST answer with the
|
|
219
|
+
// `cancelled` stop reason, but halting the work is only a SHOULD.
|
|
220
|
+
interrupt: true,
|
|
221
|
+
interruptDelivery: "native",
|
|
222
|
+
stop: true
|
|
223
|
+
}),
|
|
224
|
+
conversation: Object.freeze({
|
|
225
|
+
// `session/new` returns the Agent's own Session id.
|
|
226
|
+
persistentIdentity: "exact",
|
|
227
|
+
// Same as `nativeConversationResume`: `session/load` is how ACP carries
|
|
228
|
+
// a Conversation across processes, so the capability exists. Whether
|
|
229
|
+
// this Agent honours it is the live Session's answer, not this table's.
|
|
230
|
+
crossProcessResume: true,
|
|
231
|
+
// `session/load` replays the Conversation, but ACP exposes no way to
|
|
232
|
+
// read back a Session's history without reloading it.
|
|
233
|
+
readback: "unavailable"
|
|
234
|
+
}),
|
|
235
|
+
input: Object.freeze({
|
|
236
|
+
startTurn: true,
|
|
237
|
+
// One Turn is one `session/prompt` request; ACP defines no way to add
|
|
238
|
+
// input to a Turn already in flight.
|
|
239
|
+
steer: "unavailable",
|
|
240
|
+
inject: "unavailable",
|
|
241
|
+
// The prompt response IS the terminal, so ACP defines no separate
|
|
242
|
+
// acceptance message. This is a permanent protocol fact, not a
|
|
243
|
+
// per-Agent gap: a completed pipe write is all that can be observed
|
|
244
|
+
// before the Turn's own result arrives.
|
|
245
|
+
acceptance: "unavailable",
|
|
246
|
+
idempotency: "unavailable"
|
|
247
|
+
}),
|
|
248
|
+
descendants: Object.freeze({
|
|
249
|
+
lineage: "unavailable",
|
|
250
|
+
detachedQuery: "unavailable",
|
|
251
|
+
resultRouting: "unavailable"
|
|
252
|
+
}),
|
|
253
|
+
// The prompt response carries an explicit stopReason, which is an exact
|
|
254
|
+
// structured terminal for the Turn that requested it.
|
|
255
|
+
bounded: Object.freeze({ structuredTerminal: true }),
|
|
256
|
+
observation: Object.freeze({
|
|
257
|
+
sessionIdentity: "exact",
|
|
258
|
+
sessionBootstrap: "discovered",
|
|
259
|
+
// ACP has no "ready" signal beyond `initialize` answering.
|
|
260
|
+
preInputReadiness: "unavailable",
|
|
261
|
+
promptAcceptance: "unavailable",
|
|
262
|
+
// The terminal status and its correlation to the exact request are
|
|
263
|
+
// both exact. What ACP lacks is intermediate progress, which is
|
|
264
|
+
// recorded as absent operations and usage rather than by understating
|
|
265
|
+
// the lifecycle Yui does observe.
|
|
266
|
+
turnLifecycle: "exact",
|
|
267
|
+
goalLifecycle: "unavailable",
|
|
268
|
+
operations: Object.freeze([]),
|
|
269
|
+
waiting: Object.freeze([]),
|
|
270
|
+
usage: "unavailable",
|
|
271
|
+
delivery: "host-only"
|
|
272
|
+
})
|
|
273
|
+
}),
|
|
274
|
+
runtime: Object.freeze({
|
|
275
|
+
// ACP delivers no Hooks. Identity comes from the protocol Session the
|
|
276
|
+
// managed Endpoint already holds, so there is no payload to mine here —
|
|
277
|
+
// and inventing a Turn id from a JSON-RPC request id would present a
|
|
278
|
+
// Yui-owned value as a Provider identity.
|
|
279
|
+
nativeSessionId: ({ payload }) => (optionalIdentityFrom(payload, ["sessionId"])),
|
|
280
|
+
nativeTurnId: () => undefined,
|
|
281
|
+
mapError: mapAcpAgentError,
|
|
282
|
+
mapHook: ({ hookEventName }) => {
|
|
283
|
+
throw new Error(`ACP Driver receives no native Hooks: ${hookEventName}.`);
|
|
284
|
+
},
|
|
285
|
+
classifyHook: ({ hookEventName }) => {
|
|
286
|
+
throw new Error(`ACP Driver receives no native Hooks: ${hookEventName}.`);
|
|
287
|
+
}
|
|
288
|
+
})
|
|
163
289
|
})
|
|
164
290
|
]);
|
|
165
291
|
export function builtinAgentDriverRegistry() {
|
|
@@ -185,8 +311,7 @@ function mapClaudeLifecycleHook(name, payload, occurrenceId) {
|
|
|
185
311
|
payload.source === "startup"
|
|
186
312
|
? mapped("session.ready")
|
|
187
313
|
: mapped("session.started"),
|
|
188
|
-
mapped("conversation.observed", { recoverability: "recoverable" })
|
|
189
|
-
mapped("activation.started")
|
|
314
|
+
mapped("conversation.observed", { recoverability: "recoverable" })
|
|
190
315
|
];
|
|
191
316
|
case "UserPromptSubmit":
|
|
192
317
|
return mapped("turn.accepted");
|
|
@@ -261,7 +386,7 @@ function mapClaudeLifecycleHook(name, payload, occurrenceId) {
|
|
|
261
386
|
// Native CLI exit ends this local Provider attachment, not the
|
|
262
387
|
// resumable Conversation. Durable Session end is an explicit Yui
|
|
263
388
|
// mutation or a Provider fact that the Conversation is unrecoverable.
|
|
264
|
-
return
|
|
389
|
+
return [];
|
|
265
390
|
default:
|
|
266
391
|
throw new Error(`Claude Code Driver does not support Hook event: ${name}.`);
|
|
267
392
|
}
|
|
@@ -336,8 +461,7 @@ function mapCodexHook(name, payload, occurrenceId) {
|
|
|
336
461
|
case "SessionStart":
|
|
337
462
|
return [
|
|
338
463
|
mapped("session.started"),
|
|
339
|
-
mapped("conversation.observed", { recoverability: "recoverable" })
|
|
340
|
-
mapped("activation.started")
|
|
464
|
+
mapped("conversation.observed", { recoverability: "recoverable" })
|
|
341
465
|
];
|
|
342
466
|
case "UserPromptSubmit":
|
|
343
467
|
return mapped("turn.accepted");
|
|
@@ -380,7 +504,7 @@ function mapCodexHook(name, payload, occurrenceId) {
|
|
|
380
504
|
case "Stop":
|
|
381
505
|
return mapped("turn.completed", optionalResultOutput(payload));
|
|
382
506
|
case "SessionEnd":
|
|
383
|
-
return
|
|
507
|
+
return [];
|
|
384
508
|
default:
|
|
385
509
|
throw new Error(`Codex Driver does not support Hook event: ${name}.`);
|
|
386
510
|
}
|
|
@@ -394,10 +518,8 @@ function mapped(kind, payload = {}, fence) {
|
|
|
394
518
|
}
|
|
395
519
|
function continuationObservation(kind, native, payload) {
|
|
396
520
|
const continuationId = subagentId(native);
|
|
397
|
-
const generation = continuationGeneration(native);
|
|
398
521
|
return mapped(kind, payload, {
|
|
399
522
|
continuationId,
|
|
400
|
-
continuationGeneration: generation,
|
|
401
523
|
...(optionalIdentityFrom(native, ["parent_agent_id", "parent_subagent_id"]) === undefined
|
|
402
524
|
? {}
|
|
403
525
|
: {
|
|
@@ -405,12 +527,6 @@ function continuationObservation(kind, native, payload) {
|
|
|
405
527
|
})
|
|
406
528
|
});
|
|
407
529
|
}
|
|
408
|
-
function continuationGeneration(native) {
|
|
409
|
-
return typeof native.generation === "number"
|
|
410
|
-
&& Number.isSafeInteger(native.generation) && native.generation >= 1
|
|
411
|
-
? native.generation
|
|
412
|
-
: 1;
|
|
413
|
-
}
|
|
414
530
|
function reportId(payload) {
|
|
415
531
|
return optionalIdentityFrom(payload, ["report_id", "message_id", "agent_id", "subagent_id"])
|
|
416
532
|
?? subagentId(payload);
|
|
@@ -491,7 +607,7 @@ function claudeFailure(payload) {
|
|
|
491
607
|
}),
|
|
492
608
|
...(lastOutput === undefined ? {} : { lastOutput }),
|
|
493
609
|
...(payload.run_terminal === true || payload.unrecoverable === true
|
|
494
|
-
? {
|
|
610
|
+
? { runTerminal: true }
|
|
495
611
|
: {})
|
|
496
612
|
},
|
|
497
613
|
summary: [
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/** Provider-specific Claude Code failure recognition. */
|
|
2
2
|
export function mapClaudeAgentError(input) {
|
|
3
3
|
const text = `${input.message}\n${input.raw}`;
|
|
4
|
+
if (/^No conversation found with session ID: [A-Za-z0-9-]+\.?$/imu.test(input.message)) {
|
|
5
|
+
return sessionUnavailable("provider.session-not-found");
|
|
6
|
+
}
|
|
4
7
|
if (/^server_error$/iu.test(input.message) || /\bapi_error\b/iu.test(text)) {
|
|
5
8
|
return recoverable("availability", "provider.server-error");
|
|
6
9
|
}
|
|
@@ -44,6 +47,49 @@ export function mapCodexAgentError(input) {
|
|
|
44
47
|
}
|
|
45
48
|
return mapSharedAgentError(text, "codex");
|
|
46
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Agent Client Protocol failure recognition.
|
|
52
|
+
*
|
|
53
|
+
* ACP rides on JSON-RPC 2.0, so its failures arrive as numeric codes rather
|
|
54
|
+
* than provider prose. The codes are recognized first because they are the
|
|
55
|
+
* protocol's own exact vocabulary; only then does the shared text matcher run,
|
|
56
|
+
* which is what catches the transport failures underneath the protocol.
|
|
57
|
+
*/
|
|
58
|
+
export function mapAcpAgentError(input) {
|
|
59
|
+
const text = `${input.message}\n${input.raw}`;
|
|
60
|
+
// -32800 is ACP's own "request cancelled". It is the expected answer to
|
|
61
|
+
// `session/cancel`, not a fault.
|
|
62
|
+
if (/-32800/u.test(text) || /request[\s_-]?cancell?ed/iu.test(text)) {
|
|
63
|
+
return Object.freeze({
|
|
64
|
+
category: "cancelled",
|
|
65
|
+
code: "acp.request-cancelled",
|
|
66
|
+
sessionDisposition: "recoverable"
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
// -32601 method not found / -32602 invalid params: Yui asked for something
|
|
70
|
+
// this Agent does not implement, or asked for it wrongly. Either way the
|
|
71
|
+
// request is at fault, and retrying it unchanged cannot help.
|
|
72
|
+
if (/-32601/u.test(text)) {
|
|
73
|
+
return classification("invalid-request", "acp.method-not-found");
|
|
74
|
+
}
|
|
75
|
+
if (/-32602/u.test(text)) {
|
|
76
|
+
return classification("invalid-request", "acp.invalid-params");
|
|
77
|
+
}
|
|
78
|
+
if (/-3270[01]/u.test(text)) {
|
|
79
|
+
return classification("invalid-request", "acp.invalid-request");
|
|
80
|
+
}
|
|
81
|
+
// -32603 is the catch-all internal error: the Agent failed, but the protocol
|
|
82
|
+
// says nothing about whether this Session survived.
|
|
83
|
+
if (/-32603/u.test(text)) {
|
|
84
|
+
return recoverable("runtime", "acp.internal-error");
|
|
85
|
+
}
|
|
86
|
+
// ACP's authentication path: the Agent requires `authenticate` first. Yui
|
|
87
|
+
// never performs it on the user's behalf, so this is a genuine access fact.
|
|
88
|
+
if (/auth[\s_-]?required|requires? authentication|-32000/iu.test(text)) {
|
|
89
|
+
return classification("access", "acp.authentication-required");
|
|
90
|
+
}
|
|
91
|
+
return mapSharedAgentError(text, "acp");
|
|
92
|
+
}
|
|
47
93
|
function mapSharedAgentError(text, namespace) {
|
|
48
94
|
if (/stream error:.*INTERNAL_ERROR/iu.test(text)) {
|
|
49
95
|
return recoverable("transport", "transport.stream-internal-error");
|
|
@@ -124,13 +170,19 @@ function mapSharedAgentError(text, namespace) {
|
|
|
124
170
|
return recoverable("runtime", "runtime.process-exited");
|
|
125
171
|
}
|
|
126
172
|
if (/invalid[\s_-]?request|validation[\s_-]?error|bad[\s_-]?request|unknown[\s_-]?(?:flag|tool|argument)|unexpected argument|invalid schema/iu.test(text)
|
|
127
|
-
|| (namespace
|
|
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))) {
|
|
173
|
+
|| namespacedModelError(namespace).test(text)) {
|
|
130
174
|
return classification("invalid-request", "provider.invalid-request");
|
|
131
175
|
}
|
|
132
176
|
return classification("unknown", "unknown");
|
|
133
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* The `[<namespace>:<code>]` model-error tag, built from the caller's own
|
|
180
|
+
* namespace. Enumerating the namespaces here instead would silently test one
|
|
181
|
+
* provider's tag against another provider's text.
|
|
182
|
+
*/
|
|
183
|
+
function namespacedModelError(namespace) {
|
|
184
|
+
return new RegExp(String.raw `\[${namespace}:(?:unrecognized_model|invalid_model|model_not_found)\]`, "iu");
|
|
185
|
+
}
|
|
134
186
|
function classification(category, code) {
|
|
135
187
|
return Object.freeze({ category, code });
|
|
136
188
|
}
|
|
@@ -14,7 +14,7 @@ export function codexTranscriptUsage(transcript) {
|
|
|
14
14
|
export function codexTranscriptUsageReport(transcript) {
|
|
15
15
|
// Codex token_count events are cumulative Session snapshots. Per-request
|
|
16
16
|
// input is the non-negative delta between consecutive snapshots; the first
|
|
17
|
-
// snapshot only establishes the
|
|
17
|
+
// snapshot only establishes the Session baseline.
|
|
18
18
|
let latestInput = 0;
|
|
19
19
|
let latestCached = 0;
|
|
20
20
|
let latestOutput = 0;
|
|
Binary file
|