@zq-silk/yui 0.15.7 → 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 +157 -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 +178 -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 +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 +1188 -710
- 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 +17 -6
- package/dist/controller/clientRuntime.js +65 -92
- package/dist/controller/controller.js +114 -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 +247 -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 +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 +2 -2
- 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
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { Duplex } from "node:stream";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
4
5
|
import WebSocket from "ws";
|
|
5
|
-
import { CodexAppServerRequestError, CodexAppServerRuntime, codexGoalNotification, codexAppServerErrorIsMissing, codexTurnInput, codexTurnOutput } from "./codexAppServerRuntime.js";
|
|
6
|
+
import { CodexAppServerRequestError, CodexAppServerRuntime, codexClientInitialization, codexGoalNotification, codexAppServerErrorIsMissing, codexTurnInput, codexTurnOutput } from "./codexAppServerRuntime.js";
|
|
6
7
|
import { serializeAgentErrorRaw } from "./agentError.js";
|
|
7
|
-
import {
|
|
8
|
+
import { AcpStructuredProviderSession } from "./acpSession.js";
|
|
9
|
+
import { acpDesiredSessionConfiguration } from "./acpSessionConfiguration.js";
|
|
10
|
+
import { unsupportedAgentRunConfiguration } from "./agentRunConfiguration.js";
|
|
8
11
|
import { YUI_VERSION } from "../version.js";
|
|
9
|
-
|
|
12
|
+
import { JsonLineChannel, PROVIDER_MESSAGE_MAX_BYTES, terminateProcessGroup } from "./jsonLineChannel.js";
|
|
13
|
+
import { PROVIDER_ACCEPT_TIMEOUT_MS } from "./runtimeDeadlines.js";
|
|
10
14
|
const CODEX_PROXY_HANDSHAKE_TIMEOUT_MS = 10_000;
|
|
15
|
+
/**
|
|
16
|
+
* These Session implementations do not expose run-configuration observations.
|
|
17
|
+
* Do not echo launch flags as Provider confirmation.
|
|
18
|
+
*/
|
|
19
|
+
const CODEX_RUN_CONFIGURATION = unsupportedAgentRunConfiguration("The Codex app-server protocol");
|
|
20
|
+
const CLAUDE_RUN_CONFIGURATION = unsupportedAgentRunConfiguration("Claude Code's stream-json interface");
|
|
11
21
|
export class ProviderDeliveryUnknownError extends Error {
|
|
12
22
|
attemptId;
|
|
13
23
|
name = "ProviderDeliveryUnknownError";
|
|
@@ -51,7 +61,8 @@ export async function startStructuredProviderSession(payload, input = {}) {
|
|
|
51
61
|
if (control === undefined) {
|
|
52
62
|
throw new Error("Managed Agent Host launch requires Provider control metadata.");
|
|
53
63
|
}
|
|
54
|
-
const
|
|
64
|
+
const ownedClaude = control.adapterId === "claude" && control.transport !== "acp-stdio";
|
|
65
|
+
const child = spawn(ownedClaude ? fileURLToPath(new URL("./claude-process-owner", import.meta.url)) : payload.command, ownedClaude ? [payload.command, ...payload.args] : [...payload.args], {
|
|
55
66
|
cwd: payload.cwd,
|
|
56
67
|
env: { ...payload.environment },
|
|
57
68
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -63,8 +74,40 @@ export async function startStructuredProviderSession(payload, input = {}) {
|
|
|
63
74
|
child.stderr.on("data", (chunk) => mirror("stderr", chunk));
|
|
64
75
|
const exit = childExit(child, processInstanceId);
|
|
65
76
|
try {
|
|
77
|
+
// Dispatch is on the negotiated transport, not on a product name: every
|
|
78
|
+
// Agent that speaks a given transport is opened by the same code.
|
|
79
|
+
if (control.transport === "acp-stdio") {
|
|
80
|
+
const session = await AcpStructuredProviderSession.open({
|
|
81
|
+
child,
|
|
82
|
+
exit,
|
|
83
|
+
processInstanceId,
|
|
84
|
+
clientVersion: YUI_VERSION,
|
|
85
|
+
cwd: payload.cwd,
|
|
86
|
+
...(control.acpSession?.additionalDirectories === undefined
|
|
87
|
+
? {}
|
|
88
|
+
: { additionalDirectories: control.acpSession.additionalDirectories }),
|
|
89
|
+
...(control.acpSession?.sessionBootstrap === undefined
|
|
90
|
+
? {}
|
|
91
|
+
: { sessionBootstrap: control.acpSession.sessionBootstrap }),
|
|
92
|
+
...(control.acpSession?.desiredConfiguration === undefined
|
|
93
|
+
? {}
|
|
94
|
+
: {
|
|
95
|
+
desiredConfiguration: acpDesiredSessionConfiguration(control.acpSession.desiredConfiguration)
|
|
96
|
+
}),
|
|
97
|
+
// The product identity comes from the Agent binding the launch was
|
|
98
|
+
// compiled from. It is needed for one decision only — which mode value
|
|
99
|
+
// grants bypass — and is never inferred from the command that was run.
|
|
100
|
+
...(control.component === undefined ? {} : { component: control.component }),
|
|
101
|
+
...(control.nativeSessionId === undefined
|
|
102
|
+
? {}
|
|
103
|
+
: { nativeSessionId: control.nativeSessionId }),
|
|
104
|
+
...(input.onTerminal === undefined ? {} : { onTerminal: input.onTerminal }),
|
|
105
|
+
mirror
|
|
106
|
+
});
|
|
107
|
+
return Object.freeze({ session });
|
|
108
|
+
}
|
|
66
109
|
if (control.adapterId === "codex") {
|
|
67
|
-
const opened = await CodexStructuredProviderSession.open(child, exit, processInstanceId, payload, control, input.onStarted, input.onTerminal, input.onGoal, mirror);
|
|
110
|
+
const opened = await CodexStructuredProviderSession.open(child, exit, processInstanceId, payload, control, input.onStarted, input.onTerminal, input.onGoal, input.onInput, input.onActivity, mirror);
|
|
68
111
|
return Object.freeze({
|
|
69
112
|
session: opened.session,
|
|
70
113
|
...(opened.recoveredTerminal === undefined
|
|
@@ -73,7 +116,7 @@ export async function startStructuredProviderSession(payload, input = {}) {
|
|
|
73
116
|
goal: opened.goal
|
|
74
117
|
});
|
|
75
118
|
}
|
|
76
|
-
const session = await ClaudeStructuredProviderSession.open(child, exit, processInstanceId, control, input.onTerminal, input.onGoal, mirror);
|
|
119
|
+
const session = await ClaudeStructuredProviderSession.open(child, exit, processInstanceId, control, input.onAccepted, input.onTerminal, input.onGoal, input.onActivity, mirror);
|
|
77
120
|
return Object.freeze({ session });
|
|
78
121
|
}
|
|
79
122
|
catch (error) {
|
|
@@ -168,7 +211,10 @@ class CodexProxyWebSocketChannel {
|
|
|
168
211
|
throw this.#closedError;
|
|
169
212
|
const id = String(this.#nextId++);
|
|
170
213
|
const response = new Promise((resolvePromise, reject) => {
|
|
171
|
-
|
|
214
|
+
// A live turn submission may legitimately outlast the observation
|
|
215
|
+
// deadline. Retain its exact callback until acknowledgement or actual
|
|
216
|
+
// disconnect; a clock alone is not evidence of unknown delivery.
|
|
217
|
+
const timer = method === "turn/start" || method === "turn/steer" ? undefined : setTimeout(() => {
|
|
172
218
|
this.#pending.delete(id);
|
|
173
219
|
reject(new Error(`Provider request timed out: ${method}.`));
|
|
174
220
|
}, PROVIDER_ACCEPT_TIMEOUT_MS);
|
|
@@ -305,73 +351,6 @@ class ChildProcessDuplex extends Duplex {
|
|
|
305
351
|
return this;
|
|
306
352
|
}
|
|
307
353
|
}
|
|
308
|
-
class JsonLineChannel {
|
|
309
|
-
child;
|
|
310
|
-
mirror;
|
|
311
|
-
#listeners = new Set();
|
|
312
|
-
#buffer = "";
|
|
313
|
-
#closedError;
|
|
314
|
-
constructor(child, mirror) {
|
|
315
|
-
this.child = child;
|
|
316
|
-
this.mirror = mirror;
|
|
317
|
-
child.stdout.setEncoding("utf8");
|
|
318
|
-
child.stdout.on("data", (chunk) => this.#receive(chunk));
|
|
319
|
-
child.once("error", (error) => this.#close(error));
|
|
320
|
-
child.once("close", (code, signal) => this.#close(new Error(`Provider process exited (code=${code ?? "none"}, signal=${signal ?? "none"}).`)));
|
|
321
|
-
}
|
|
322
|
-
onMessage(listener) {
|
|
323
|
-
this.#listeners.add(listener);
|
|
324
|
-
return () => this.#listeners.delete(listener);
|
|
325
|
-
}
|
|
326
|
-
async send(message) {
|
|
327
|
-
if (this.#closedError !== undefined)
|
|
328
|
-
throw this.#closedError;
|
|
329
|
-
const line = `${JSON.stringify(message)}\n`;
|
|
330
|
-
if (Buffer.byteLength(line, "utf8") > PROVIDER_MESSAGE_MAX_BYTES) {
|
|
331
|
-
throw new Error("Provider request exceeds its message bound.");
|
|
332
|
-
}
|
|
333
|
-
await new Promise((resolvePromise, reject) => {
|
|
334
|
-
this.child.stdin.write(line, "utf8", (error) => {
|
|
335
|
-
if (error === null || error === undefined)
|
|
336
|
-
resolvePromise();
|
|
337
|
-
else
|
|
338
|
-
reject(error);
|
|
339
|
-
});
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
#receive(chunk) {
|
|
343
|
-
this.mirror("stdout", chunk);
|
|
344
|
-
this.#buffer += chunk;
|
|
345
|
-
if (Buffer.byteLength(this.#buffer, "utf8") > PROVIDER_MESSAGE_MAX_BYTES) {
|
|
346
|
-
this.#close(new Error("Provider response line exceeds its message bound."));
|
|
347
|
-
terminateProcessGroup(this.child, "SIGTERM");
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
for (;;) {
|
|
351
|
-
const newline = this.#buffer.indexOf("\n");
|
|
352
|
-
if (newline < 0)
|
|
353
|
-
return;
|
|
354
|
-
const line = this.#buffer.slice(0, newline).trim();
|
|
355
|
-
this.#buffer = this.#buffer.slice(newline + 1);
|
|
356
|
-
if (line.length === 0)
|
|
357
|
-
continue;
|
|
358
|
-
try {
|
|
359
|
-
const parsed = JSON.parse(line);
|
|
360
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
|
|
361
|
-
continue;
|
|
362
|
-
for (const listener of this.#listeners)
|
|
363
|
-
listener(parsed);
|
|
364
|
-
}
|
|
365
|
-
catch {
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
#close(error) {
|
|
371
|
-
if (this.#closedError === undefined)
|
|
372
|
-
this.#closedError = error;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
354
|
class CodexStructuredProviderSession {
|
|
376
355
|
child;
|
|
377
356
|
exit;
|
|
@@ -381,6 +360,10 @@ class CodexStructuredProviderSession {
|
|
|
381
360
|
onStarted;
|
|
382
361
|
onTerminal;
|
|
383
362
|
onGoal;
|
|
363
|
+
onInput;
|
|
364
|
+
onActivity;
|
|
365
|
+
nativeAccountHome;
|
|
366
|
+
#turnAttempts = new Map();
|
|
384
367
|
adapterId = "codex";
|
|
385
368
|
#activeTurnId;
|
|
386
369
|
#clientOwnedTurnId;
|
|
@@ -388,7 +371,8 @@ class CodexStructuredProviderSession {
|
|
|
388
371
|
#submissionPending = false;
|
|
389
372
|
#bufferedStarts = [];
|
|
390
373
|
#bufferedTerminals = [];
|
|
391
|
-
|
|
374
|
+
#bufferedActivities = [];
|
|
375
|
+
constructor(child, exit, processInstanceId, conversationId, runtime, onStarted, onTerminal, onGoal, onInput, onActivity, nativeAccountHome) {
|
|
392
376
|
this.child = child;
|
|
393
377
|
this.exit = exit;
|
|
394
378
|
this.processInstanceId = processInstanceId;
|
|
@@ -397,18 +381,15 @@ class CodexStructuredProviderSession {
|
|
|
397
381
|
this.onStarted = onStarted;
|
|
398
382
|
this.onTerminal = onTerminal;
|
|
399
383
|
this.onGoal = onGoal;
|
|
384
|
+
this.onInput = onInput;
|
|
385
|
+
this.onActivity = onActivity;
|
|
386
|
+
this.nativeAccountHome = nativeAccountHome;
|
|
400
387
|
}
|
|
401
|
-
static async open(child, exit, processInstanceId, payload, control, onStarted, onTerminal, onGoal, mirror) {
|
|
388
|
+
static async open(child, exit, processInstanceId, payload, control, onStarted, onTerminal, onGoal, onInput, onActivity, mirror) {
|
|
402
389
|
const channel = await CodexProxyWebSocketChannel.connect(child, mirror);
|
|
403
390
|
const openingMessages = [];
|
|
404
391
|
const stopOpeningBuffer = channel.onMessage((message) => openingMessages.push(message));
|
|
405
|
-
await channel.request("initialize",
|
|
406
|
-
clientInfo: { name: "yui", title: "Yui", version: YUI_VERSION },
|
|
407
|
-
capabilities: {
|
|
408
|
-
experimentalApi: true,
|
|
409
|
-
requestAttestation: false
|
|
410
|
-
}
|
|
411
|
-
});
|
|
392
|
+
const initialized = await channel.request("initialize", codexClientInitialization());
|
|
412
393
|
await channel.notify("initialized");
|
|
413
394
|
const runtime = new CodexAppServerRuntime(channel);
|
|
414
395
|
let conversationId;
|
|
@@ -443,11 +424,13 @@ class CodexStructuredProviderSession {
|
|
|
443
424
|
name: control.sessionTitle
|
|
444
425
|
});
|
|
445
426
|
}
|
|
446
|
-
const session = new CodexStructuredProviderSession(child, exit, processInstanceId, conversationId, runtime, onStarted, onTerminal, onGoal);
|
|
427
|
+
const session = new CodexStructuredProviderSession(child, exit, processInstanceId, conversationId, runtime, onStarted, onTerminal, onGoal, onInput, onActivity, optionalId(initialized.codexHome));
|
|
447
428
|
session.#activeTurnId = resumedActiveTurnId;
|
|
448
429
|
const ownedTurn = control.kind === "restore" ? control.ownedTurn : undefined;
|
|
449
430
|
session.#clientOwnedTurnId = ownedTurn?.turnId;
|
|
450
431
|
session.#clientOwnedAttemptId = ownedTurn?.attemptId;
|
|
432
|
+
if (ownedTurn !== undefined)
|
|
433
|
+
session.#turnAttempts.set(ownedTurn.turnId, ownedTurn.attemptId);
|
|
451
434
|
stopOpeningBuffer();
|
|
452
435
|
let recoveredTerminal;
|
|
453
436
|
for (const message of openingMessages) {
|
|
@@ -507,6 +490,38 @@ class CodexStructuredProviderSession {
|
|
|
507
490
|
this.onGoal?.(goal);
|
|
508
491
|
return undefined;
|
|
509
492
|
}
|
|
493
|
+
if (emit && (method === "item/started" || method === "item/completed"
|
|
494
|
+
|| method === "item/agentMessage/delta" || method === "item/reasoning/summaryTextDelta")) {
|
|
495
|
+
const item = object(params.item);
|
|
496
|
+
const id = optionalId(item?.id) ?? optionalId(params.itemId);
|
|
497
|
+
const nativeTurnId = optionalId(params.turnId);
|
|
498
|
+
const tool = ["commandExecution", "mcpToolCall", "dynamicToolCall", "fileChange"].includes(String(item?.type));
|
|
499
|
+
const model = ["agentMessage", "reasoning"].includes(String(item?.type)) || method.endsWith("Delta") || method.endsWith("/delta");
|
|
500
|
+
if (id !== undefined && nativeTurnId !== undefined && (tool || model)) {
|
|
501
|
+
const activity = {
|
|
502
|
+
conversationId: this.conversationId, nativeSessionId: this.conversationId,
|
|
503
|
+
nativeTurnId, id, observedAt: new Date().toISOString(),
|
|
504
|
+
phase: model ? "model" : method === "item/started" ? "started"
|
|
505
|
+
: item?.status === "failed" || (typeof item?.exitCode === "number" && item.exitCode !== 0)
|
|
506
|
+
? "failed" : "completed"
|
|
507
|
+
};
|
|
508
|
+
if (this.#submissionPending)
|
|
509
|
+
this.#bufferedActivities.push(activity);
|
|
510
|
+
else
|
|
511
|
+
this.#emitActivity(activity);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (method === "item/completed") {
|
|
515
|
+
const item = object(params.item);
|
|
516
|
+
const nativeTurnId = optionalId(params.turnId);
|
|
517
|
+
const inputId = optionalId(item?.id);
|
|
518
|
+
const input = item === null ? undefined : codexTurnInput({ items: [item] });
|
|
519
|
+
if (emit && nativeTurnId !== undefined && inputId !== undefined && input !== undefined) {
|
|
520
|
+
this.onInput?.({ conversationId: this.conversationId, nativeSessionId: this.conversationId,
|
|
521
|
+
nativeTurnId, inputId, input, observedAt: new Date().toISOString() });
|
|
522
|
+
}
|
|
523
|
+
return undefined;
|
|
524
|
+
}
|
|
510
525
|
if (method === "turn/started") {
|
|
511
526
|
const turnId = nestedId(params, "turn") ?? optionalId(params.turnId);
|
|
512
527
|
if (turnId !== undefined) {
|
|
@@ -563,6 +578,12 @@ class CodexStructuredProviderSession {
|
|
|
563
578
|
get activeTurnId() {
|
|
564
579
|
return this.#activeTurnId;
|
|
565
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* This implementation has no run-configuration observation reader.
|
|
583
|
+
*/
|
|
584
|
+
get runConfiguration() {
|
|
585
|
+
return CODEX_RUN_CONFIGURATION;
|
|
586
|
+
}
|
|
566
587
|
async submitTurn(turn) {
|
|
567
588
|
if (this.#activeTurnId !== undefined) {
|
|
568
589
|
throw new ProviderTurnBusyError(`Provider Conversation already has active Turn ${this.#activeTurnId}.`, turn.attemptId, this.#activeTurnId);
|
|
@@ -587,6 +608,7 @@ class CodexStructuredProviderSession {
|
|
|
587
608
|
this.#activeTurnId = acceptance.turnId;
|
|
588
609
|
this.#clientOwnedTurnId = acceptance.turnId;
|
|
589
610
|
this.#clientOwnedAttemptId = turn.attemptId;
|
|
611
|
+
this.#turnAttempts.set(acceptance.turnId, turn.attemptId);
|
|
590
612
|
return Object.freeze({
|
|
591
613
|
attemptId: turn.attemptId,
|
|
592
614
|
conversationId: this.conversationId,
|
|
@@ -602,6 +624,8 @@ class CodexStructuredProviderSession {
|
|
|
602
624
|
for (const started of starts)
|
|
603
625
|
this.#emitStarted(started);
|
|
604
626
|
const buffered = this.#bufferedTerminals.splice(0);
|
|
627
|
+
for (const activity of this.#bufferedActivities.splice(0))
|
|
628
|
+
this.#emitActivity(activity);
|
|
605
629
|
for (const terminal of buffered)
|
|
606
630
|
this.#emitTerminal(terminal);
|
|
607
631
|
}
|
|
@@ -635,6 +659,11 @@ class CodexStructuredProviderSession {
|
|
|
635
659
|
#emitTerminal(terminal) {
|
|
636
660
|
this.#completeTerminal(terminal, true);
|
|
637
661
|
}
|
|
662
|
+
#emitActivity(activity) {
|
|
663
|
+
const attemptId = this.#turnAttempts.get(activity.nativeTurnId);
|
|
664
|
+
if (attemptId !== undefined)
|
|
665
|
+
this.onActivity?.({ ...activity, attemptId });
|
|
666
|
+
}
|
|
638
667
|
#emitStarted(started) {
|
|
639
668
|
this.onStarted?.({
|
|
640
669
|
...started,
|
|
@@ -642,12 +671,12 @@ class CodexStructuredProviderSession {
|
|
|
642
671
|
});
|
|
643
672
|
}
|
|
644
673
|
#completeTerminal(terminal, emit) {
|
|
645
|
-
const
|
|
646
|
-
|
|
647
|
-
const
|
|
674
|
+
const attemptId = terminal.nativeTurnId === undefined ? undefined
|
|
675
|
+
: this.#turnAttempts.get(terminal.nativeTurnId);
|
|
676
|
+
const clientOwned = attemptId !== undefined;
|
|
648
677
|
if (terminal.nativeTurnId === this.#activeTurnId)
|
|
649
678
|
this.#activeTurnId = undefined;
|
|
650
|
-
if (
|
|
679
|
+
if (terminal.nativeTurnId === this.#clientOwnedTurnId) {
|
|
651
680
|
this.#clientOwnedTurnId = undefined;
|
|
652
681
|
this.#clientOwnedAttemptId = undefined;
|
|
653
682
|
}
|
|
@@ -663,6 +692,16 @@ class CodexStructuredProviderSession {
|
|
|
663
692
|
waitForExit() {
|
|
664
693
|
return this.exit;
|
|
665
694
|
}
|
|
695
|
+
async cancelTurn(attemptId) {
|
|
696
|
+
if (this.#clientOwnedAttemptId !== attemptId || this.#clientOwnedTurnId === undefined) {
|
|
697
|
+
return this.#submissionPending ? "unknown" : "not-active";
|
|
698
|
+
}
|
|
699
|
+
const result = await this.runtime.interruptTurn({
|
|
700
|
+
conversationId: this.conversationId,
|
|
701
|
+
turnId: this.#clientOwnedTurnId
|
|
702
|
+
});
|
|
703
|
+
return result === "interrupted" ? "requested" : result;
|
|
704
|
+
}
|
|
666
705
|
terminate(signal) {
|
|
667
706
|
terminateProcessGroup(this.child, signal);
|
|
668
707
|
}
|
|
@@ -675,7 +714,12 @@ class ClaudeStructuredProviderSession {
|
|
|
675
714
|
channel;
|
|
676
715
|
onGoal;
|
|
677
716
|
adapterId = "claude";
|
|
717
|
+
get ownedProcessId() { return this.child.pid; }
|
|
678
718
|
#activeAttemptId;
|
|
719
|
+
#acceptedAttemptId;
|
|
720
|
+
#cancelledAttemptId;
|
|
721
|
+
#seenAssistantIds = new Set();
|
|
722
|
+
#openToolIds = new Set();
|
|
679
723
|
#resultAttempts = new Map();
|
|
680
724
|
#lastGoalKey;
|
|
681
725
|
constructor(child, exit, processInstanceId, conversationId, channel, onGoal) {
|
|
@@ -686,14 +730,30 @@ class ClaudeStructuredProviderSession {
|
|
|
686
730
|
this.channel = channel;
|
|
687
731
|
this.onGoal = onGoal;
|
|
688
732
|
}
|
|
689
|
-
static async open(child, exit, processInstanceId, control, onTerminal, onGoal, mirror) {
|
|
733
|
+
static async open(child, exit, processInstanceId, control, onAccepted, onTerminal, onGoal, onActivity, mirror) {
|
|
690
734
|
const channel = new JsonLineChannel(child, mirror);
|
|
691
735
|
const nativeSessionId = control.nativeSessionId;
|
|
692
736
|
if (nativeSessionId === undefined) {
|
|
693
737
|
throw new Error("Managed Claude launch requires a preallocated native Session id.");
|
|
694
738
|
}
|
|
695
739
|
const session = new ClaudeStructuredProviderSession(child, exit, processInstanceId, nativeSessionId, channel, onGoal);
|
|
696
|
-
channel.onMessage((message) => session.#receive(message, onTerminal));
|
|
740
|
+
channel.onMessage((message) => session.#receive(message, onTerminal, onAccepted, onActivity));
|
|
741
|
+
// This client owns the whole Claude execution process, unlike a Codex
|
|
742
|
+
// proxy. An exit without a result ends the exact local input as failure,
|
|
743
|
+
// not as continuing work merely because the supervising Host is alive.
|
|
744
|
+
void exit.then(result => {
|
|
745
|
+
const attemptId = session.#activeAttemptId;
|
|
746
|
+
if (attemptId === undefined)
|
|
747
|
+
return;
|
|
748
|
+
session.#activeAttemptId = undefined;
|
|
749
|
+
onTerminal?.({
|
|
750
|
+
conversationId: nativeSessionId, nativeSessionId, attemptId,
|
|
751
|
+
clientOwned: true,
|
|
752
|
+
status: session.#cancelledAttemptId === attemptId ? "cancelled" : "failed",
|
|
753
|
+
observedAt: new Date().toISOString(),
|
|
754
|
+
error: `Owned Provider process exited before a terminal result (code=${result.code}, signal=${result.signal}).`
|
|
755
|
+
});
|
|
756
|
+
});
|
|
697
757
|
return session;
|
|
698
758
|
}
|
|
699
759
|
get nativeSessionId() {
|
|
@@ -703,9 +763,15 @@ class ClaudeStructuredProviderSession {
|
|
|
703
763
|
// stream-json result.uuid is a message identity, not an execution identity.
|
|
704
764
|
return undefined;
|
|
705
765
|
}
|
|
766
|
+
/**
|
|
767
|
+
* This implementation has no run-configuration observation reader.
|
|
768
|
+
*/
|
|
769
|
+
get runConfiguration() {
|
|
770
|
+
return CLAUDE_RUN_CONFIGURATION;
|
|
771
|
+
}
|
|
706
772
|
async submitTurn(turn) {
|
|
707
773
|
if (this.#activeAttemptId !== undefined) {
|
|
708
|
-
throw new
|
|
774
|
+
throw new ProviderTurnBusyError("Provider Conversation already has an unsettled Turn.", turn.attemptId);
|
|
709
775
|
}
|
|
710
776
|
// Reserve before the pipe write: a fast result can precede its callback.
|
|
711
777
|
// A failed write is ambiguous and must retain the same occupancy.
|
|
@@ -723,10 +789,10 @@ class ClaudeStructuredProviderSession {
|
|
|
723
789
|
throw new ProviderDeliveryUnknownError(`Claude input write did not complete: ${error instanceof Error ? error.message : String(error)}`, turn.attemptId, { cause: error });
|
|
724
790
|
}
|
|
725
791
|
// AgentHost is the sole writer to this dedicated stream-json process.
|
|
726
|
-
// A
|
|
727
|
-
//
|
|
728
|
-
//
|
|
729
|
-
//
|
|
792
|
+
// A pipe write is transport evidence only. The later result establishes
|
|
793
|
+
// native acceptance and completion through this exact serialized local
|
|
794
|
+
// attempt. A main assistant response can confirm acceptance earlier, without
|
|
795
|
+
// inventing a provider execution id or trusting the echoed user input.
|
|
730
796
|
return Object.freeze({
|
|
731
797
|
attemptId: turn.attemptId,
|
|
732
798
|
conversationId: this.conversationId,
|
|
@@ -738,13 +804,20 @@ class ClaudeStructuredProviderSession {
|
|
|
738
804
|
async steerTurn(turn) {
|
|
739
805
|
throw new ProviderTurnRejectedError("Claude stream-json does not expose an exact native Turn identity for steering.", turn.attemptId);
|
|
740
806
|
}
|
|
807
|
+
async cancelTurn(attemptId) {
|
|
808
|
+
if (this.#activeAttemptId !== attemptId)
|
|
809
|
+
return "not-active";
|
|
810
|
+
this.#cancelledAttemptId = attemptId;
|
|
811
|
+
terminateProcessGroup(this.child, "SIGTERM");
|
|
812
|
+
return "requested";
|
|
813
|
+
}
|
|
741
814
|
waitForExit() {
|
|
742
815
|
return this.exit;
|
|
743
816
|
}
|
|
744
817
|
terminate(signal) {
|
|
745
818
|
terminateProcessGroup(this.child, signal);
|
|
746
819
|
}
|
|
747
|
-
#receive(message, onTerminal) {
|
|
820
|
+
#receive(message, onTerminal, onAccepted, onActivity) {
|
|
748
821
|
const goal = claudeActiveGoal(message, this.conversationId);
|
|
749
822
|
if (goal !== undefined) {
|
|
750
823
|
const key = JSON.stringify(goal === null ? null : {
|
|
@@ -757,8 +830,64 @@ class ClaudeStructuredProviderSession {
|
|
|
757
830
|
this.onGoal?.(goal);
|
|
758
831
|
}
|
|
759
832
|
}
|
|
760
|
-
|
|
833
|
+
const activity = (id, phase) => {
|
|
834
|
+
if (this.#activeAttemptId !== undefined)
|
|
835
|
+
onActivity?.({
|
|
836
|
+
conversationId: this.conversationId, nativeSessionId: this.conversationId,
|
|
837
|
+
attemptId: this.#activeAttemptId, id, phase, observedAt: new Date().toISOString()
|
|
838
|
+
});
|
|
839
|
+
};
|
|
840
|
+
if (message.type === "user") {
|
|
841
|
+
if (optionalId(message.session_id) !== this.conversationId || message.parent_tool_use_id != null)
|
|
842
|
+
return;
|
|
843
|
+
const body = object(message.message);
|
|
844
|
+
for (const raw of Array.isArray(body?.content) ? body.content : []) {
|
|
845
|
+
const block = object(raw), id = optionalId(block?.tool_use_id);
|
|
846
|
+
if (block?.type === "tool_result" && id !== undefined && this.#openToolIds.delete(id)) {
|
|
847
|
+
activity(id, block.is_error === true ? "failed" : "completed");
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
if (message.type === "assistant") {
|
|
853
|
+
if (optionalId(message.session_id) !== this.conversationId
|
|
854
|
+
|| message.parent_tool_use_id != null
|
|
855
|
+
|| object(message.message)?.role !== "assistant")
|
|
856
|
+
return;
|
|
857
|
+
const messageId = optionalId(message.uuid);
|
|
858
|
+
if (messageId === undefined || this.#seenAssistantIds.has(messageId))
|
|
859
|
+
return;
|
|
860
|
+
this.#seenAssistantIds.add(messageId);
|
|
861
|
+
const attemptId = this.#activeAttemptId;
|
|
862
|
+
if (attemptId === undefined)
|
|
863
|
+
return;
|
|
864
|
+
// This dedicated stream has exactly one owned input in flight. Main
|
|
865
|
+
// assistant output proves it is being processed; init, echo and child
|
|
866
|
+
// output do not. Keep the local attempt identity, not the message UUID,
|
|
867
|
+
// as the correlation key (Claude exposes no exact native Turn id).
|
|
868
|
+
if (this.#acceptedAttemptId !== attemptId) {
|
|
869
|
+
this.#acceptedAttemptId = attemptId;
|
|
870
|
+
onAccepted?.({
|
|
871
|
+
attemptId,
|
|
872
|
+
conversationId: this.conversationId,
|
|
873
|
+
nativeSessionId: this.conversationId,
|
|
874
|
+
acceptedAt: new Date().toISOString(),
|
|
875
|
+
acceptance: "provider"
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
const body = object(message.message);
|
|
879
|
+
for (const raw of Array.isArray(body?.content) ? body.content : []) {
|
|
880
|
+
const block = object(raw), id = optionalId(block?.id);
|
|
881
|
+
if (block?.type === "tool_use" && id !== undefined && !this.#openToolIds.has(id)) {
|
|
882
|
+
this.#openToolIds.add(id);
|
|
883
|
+
activity(id, "started");
|
|
884
|
+
}
|
|
885
|
+
else if (block?.type === "text" || block?.type === "thinking") {
|
|
886
|
+
activity(messageId, "model");
|
|
887
|
+
}
|
|
888
|
+
}
|
|
761
889
|
return;
|
|
890
|
+
}
|
|
762
891
|
if (message.type !== "result"
|
|
763
892
|
|| optionalId(message.session_id) !== this.conversationId)
|
|
764
893
|
return;
|
|
@@ -772,12 +901,14 @@ class ClaudeStructuredProviderSession {
|
|
|
772
901
|
return;
|
|
773
902
|
if (resultId !== undefined)
|
|
774
903
|
this.#resultAttempts.set(resultId, attemptId);
|
|
775
|
-
if (attemptId === this.#activeAttemptId)
|
|
904
|
+
if (attemptId === this.#activeAttemptId) {
|
|
776
905
|
this.#activeAttemptId = undefined;
|
|
906
|
+
this.#openToolIds.clear();
|
|
907
|
+
}
|
|
777
908
|
const failed = message.is_error === true || message.subtype === "error_during_execution";
|
|
778
909
|
const result = typeof message.result === "string" && message.result.length > 0
|
|
779
910
|
? message.result
|
|
780
|
-
:
|
|
911
|
+
: providerErrorEvidence(message).error;
|
|
781
912
|
onTerminal?.({
|
|
782
913
|
conversationId: this.conversationId,
|
|
783
914
|
nativeSessionId: this.conversationId,
|
|
@@ -861,21 +992,6 @@ function childExit(child, processInstanceId) {
|
|
|
861
992
|
})));
|
|
862
993
|
});
|
|
863
994
|
}
|
|
864
|
-
function terminateProcessGroup(child, signal) {
|
|
865
|
-
if (child.pid === undefined)
|
|
866
|
-
return;
|
|
867
|
-
// Managed Providers are spawned detached and therefore own a process group.
|
|
868
|
-
// Kill that exact group so a CLI helper cannot outlive the Agent Host. The
|
|
869
|
-
// direct-child fallback covers embedded runtimes that cannot create setsid.
|
|
870
|
-
try {
|
|
871
|
-
process.kill(-child.pid, signal);
|
|
872
|
-
}
|
|
873
|
-
catch (error) {
|
|
874
|
-
if (error.code !== "ESRCH")
|
|
875
|
-
throw error;
|
|
876
|
-
child.kill(signal);
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
995
|
function defaultMirrorOutput(stream, text) {
|
|
880
996
|
(stream === "stdout" ? process.stdout : process.stderr).write(text);
|
|
881
997
|
}
|
|
@@ -895,10 +1011,14 @@ function nestedId(value, key) {
|
|
|
895
1011
|
}
|
|
896
1012
|
function providerErrorEvidence(value) {
|
|
897
1013
|
const error = object(value);
|
|
1014
|
+
const errors = Array.isArray(error?.errors)
|
|
1015
|
+
? error.errors.filter((entry) => typeof entry === "string" && entry.length > 0)
|
|
1016
|
+
: [];
|
|
898
1017
|
const message = typeof error?.message === "string" && error.message.length > 0
|
|
899
1018
|
? error.message
|
|
900
|
-
:
|
|
901
|
-
|
|
902
|
-
|
|
1019
|
+
: errors.length > 0 ? errors.join("\n")
|
|
1020
|
+
: typeof value === "string" && value.length > 0
|
|
1021
|
+
? value
|
|
1022
|
+
: "Provider Turn failed.";
|
|
903
1023
|
return { error: message, rawError: serializeAgentErrorRaw(value) };
|
|
904
1024
|
}
|