From d1fde3a99504ea381e4f92d382138e693ca4a76c Mon Sep 17 00:00:00 2001 From: root Date: Thu, 16 Jul 2026 19:38:18 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=81=A2=E5=A4=8D=20Workbench=20direct?= =?UTF-8?q?=20admission?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/cloud/server-agent-chat.test.ts | 13 +++++++++- .../cloud/server-code-agent-admission-http.ts | 26 ++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/internal/cloud/server-agent-chat.test.ts b/internal/cloud/server-agent-chat.test.ts index 5167a892..580dba2f 100644 --- a/internal/cloud/server-agent-chat.test.ts +++ b/internal/cloud/server-agent-chat.test.ts @@ -1,4 +1,4 @@ -// SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-20-p2-terminal-outbox-recovery; PJ2026-01060505 Workbench Performance draft-2026-06-17-p0. +// SPEC: PJ2026-010401080313 Workbench实时权威 draft-2026-07-14-p0-pure-kafka-authority; PJ2026-01060505 Workbench Performance draft-2026-06-17-p0. // Responsibility: Cloud API AgentRun adapter and trace observability regression tests. import assert from "node:assert/strict"; @@ -1976,8 +1976,16 @@ test("cloud api AgentRun adapter maps minimax-m3 provider profile to AgentRun ba traceStore, runtimeStore, workbenchRuntime: runtimeStore, + kafkaEventBridge: { + capabilities: { directPublish: true, liveKafkaSse: true, kafkaRefreshReplay: true, transactionalProjector: false, projectionOutboxRelay: false, projectionRealtime: false }, + ready: Promise.resolve(), + subscribeProjectionCommits() { return () => {}; }, + async stop() {} + }, env: { ...TEST_REALTIME_CAPABILITIES_DISABLED, + HWLAB_KAFKA_DIRECT_PUBLISH_ENABLED: "true", + HWLAB_WORKBENCH_LIVE_KAFKA_SSE_ENABLED: "true", HWLAB_CODE_AGENT_ADAPTER: "agentrun-v01", AGENTRUN_MGR_URL: `http://127.0.0.1:${agentRunPort}`, HWLAB_CODE_AGENT_AGENTRUN_ALLOW_NON_K3S_URL: "1", @@ -2021,6 +2029,9 @@ test("cloud api AgentRun adapter maps minimax-m3 provider profile to AgentRun ba const accepted = await submit.json(); assert.equal(accepted.shortConnection, true); + const liveAdmission = await waitForTraceEvent(traceStore, traceId, (event) => event.label === "turn:admitted-live-kafka"); + assert.equal(liveAdmission.waitingFor, "hwlab-live-kafka-sse"); + await waitForTraceEvent(traceStore, traceId, (event) => event.label === "agentrun:dispatch-intent:admitted"); await commitTestKafkaTerminal(runtimeStore, { traceId, diff --git a/internal/cloud/server-code-agent-admission-http.ts b/internal/cloud/server-code-agent-admission-http.ts index 725433b3..3e3146b4 100644 --- a/internal/cloud/server-code-agent-admission-http.ts +++ b/internal/cloud/server-code-agent-admission-http.ts @@ -1,4 +1,4 @@ -// SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-20-p2-terminal-outbox-recovery; PJ2026-010403 API契约 draft-2026-06-20-p2-terminal-outbox-recovery; PJ2026-010205 HWLAB接入 draft-2026-06-25-p0-session-warm-runner-contract; PJ2026-0102 Agent编排 draft-2026-06-17-r0; PJ2026-01060505 Workbench Performance draft-2026-06-17-p0. +// SPEC: PJ2026-010401080313 Workbench实时权威 draft-2026-07-14-p0-pure-kafka-authority; PJ2026-010403 API契约 draft-2026-06-20-p2-terminal-outbox-recovery; PJ2026-010205 HWLAB接入 draft-2026-06-25-p0-session-warm-runner-contract; PJ2026-0102 Agent编排 draft-2026-06-17-r0; PJ2026-01060505 Workbench Performance draft-2026-06-17-p0. // Responsibility: Code Agent HTTP session and turn admission. import { createHash, randomUUID } from "node:crypto"; @@ -1321,6 +1321,30 @@ async function promoteCodeAgentTurnAdmission({ payload = {}, params = {}, option throw error; } const lifecycle = codeAgentTurnLifecycleFields(traceId, params); + const realtimeCapabilities = workbenchRealtimeCapabilities(options.env ?? process.env); + if (!realtimeCapabilities.transactionalProjector) { + const runningOwner = await recordCodeAgentSessionOwner({ payload: { ...payload, status: "running" }, params, options, status: "running" }); + if (!runningOwner) { + const error = new Error("Code Agent live turn did not durably promote the session owner to running."); + error.code = "workbench_admission_owner_not_promoted"; + error.valuesRedacted = true; + throw error; + } + traceStore.append(traceId, { + type: "request", + status: "admitted", + label: "turn:admitted-live-kafka", + message: "Code Agent turn is live after AgentRun durable dispatch; lifecycle visibility is owned only by hwlab.event.v1.", + sessionId: safeSessionId(params.sessionId) || null, + runId: payload.agentRun?.runId ?? null, + commandId: payload.agentRun?.commandId ?? null, + dispatchIntentId: payload.agentRun?.dispatchIntentId ?? null, + waitingFor: "hwlab-live-kafka-sse", + terminal: false, + valuesPrinted: false + }); + return { written: false, promoted: true, outboxCommitted: false, realtimeCapabilities, liveOnly: realtimeCapabilities.liveKafkaSse, valuesPrinted: false }; + } const inputFact = buildCodeAgentSessionInputFact({ params, options,