From 07680362ffa51165cde63ef1ea997e2e47333400 Mon Sep 17 00:00:00 2001 From: joshavant <830519+joshavant@users.noreply.github.com> Date: Fri, 7 Aug 2026 13:53:38 -0500 Subject: [PATCH] Revert "refactor(agents): propagate exact attribution across runtimes" This reverts commit df31882c386c413b5c051841302c4acc9cc69952. --- .../.generated/plugin-sdk-api-baseline.sha256 | 2 +- .../agent-command-execution-identity.test.ts | 161 ---------------- .../agent-command-execution-identity.ts | 70 +------ .../agent-command.live-model-switch.test.ts | 71 +------ src/agents/agent-command.ts | 35 ++-- .../agent-execution-attribution.test.ts | 20 -- src/agents/agent-execution-attribution.ts | 19 +- src/agents/btw.test.ts | 20 -- src/agents/btw.ts | 9 +- src/agents/cli-runner.ts | 7 +- .../cli-runner/execution-attribution.test.ts | 78 -------- .../cli-runner/execution-attribution.ts | 31 --- src/agents/cli-runner/prepare.test.ts | 18 +- src/agents/cli-runner/prepare.ts | 6 +- src/agents/cli-runner/types.ts | 3 - src/agents/command/acp-execution.ts | 3 - .../command/attempt-execution.cli.test.ts | 3 - src/agents/command/attempt-execution.ts | 27 +-- src/agents/command/run-embedded-attempt.ts | 17 +- .../cli-backend-dispatch.test.ts | 43 +---- .../cli-backend-dispatch.ts | 19 +- .../embedded-agent-runner/run-orchestrator.ts | 24 +-- .../run.cli-dispatch-lane.test.ts | 20 -- .../run.overflow-compaction.loop.test.ts | 14 -- .../run/internal-params.ts | 10 - .../run/lane-controller.lifecycle.test.ts | 56 +----- .../run/lane-controller.ts | 27 +-- .../run/run-attempt-dispatch.ts | 3 +- src/agents/session-placement-admission.ts | 4 +- .../reply/agent-runner-cli-candidate.ts | 45 +---- .../reply/agent-runner-embedded-candidate.ts | 25 +-- .../agent-runner-execution-contract.test.ts | 35 ---- .../agent-runner-execution-identity.test.ts | 145 -------------- .../reply/agent-runner-execution-identity.ts | 153 --------------- .../agent-runner-execution-lifecycle.test.ts | 14 +- .../agent-runner-execution-runtime.test.ts | 180 ------------------ .../agent-runner-execution.test-support.ts | 7 - .../reply/agent-runner-execution.ts | 55 +----- .../reply/agent-runner-execution.types.ts | 3 - .../reply/agent-runner-fallback-candidate.ts | 5 +- .../reply/agent-runner.media-paths.test.ts | 4 - .../agent-runner.misc.runreplyagent.test.ts | 4 - .../agent-runner.runreplyagent.e2e.test.ts | 4 - src/auto-reply/reply/commands-btw.test.ts | 8 - src/auto-reply/reply/commands-btw.ts | 23 --- src/commands/agent.test.ts | 10 +- .../agent.events-and-subagents.test-utils.ts | 2 - .../worker-turn-launcher.test.ts | 21 -- .../worker-turn-launcher.ts | 4 - test/vitest/vitest.unit-fast-paths.mjs | 1 - 50 files changed, 91 insertions(+), 1477 deletions(-) delete mode 100644 src/agents/agent-command-execution-identity.test.ts delete mode 100644 src/agents/cli-runner/execution-attribution.test.ts delete mode 100644 src/agents/cli-runner/execution-attribution.ts delete mode 100644 src/auto-reply/reply/agent-runner-execution-identity.test.ts delete mode 100644 src/auto-reply/reply/agent-runner-execution-identity.ts diff --git a/docs/.generated/plugin-sdk-api-baseline.sha256 b/docs/.generated/plugin-sdk-api-baseline.sha256 index f283706572df..7191324f3ab3 100644 --- a/docs/.generated/plugin-sdk-api-baseline.sha256 +++ b/docs/.generated/plugin-sdk-api-baseline.sha256 @@ -122,7 +122,7 @@ aa8a411ad37c1d1143b67376bf2d20255b9eedff61d80815f42e4f8ed7bd8e58 module/secret- 57dcb1462d4c4f9a98d934c4ca975b163d704758af9821a64001ff3ac05637c3 module/secret-input-runtime dc0ee07d392a85c218939000b28c0138f139215da00f5592b34a68ba8e29a25d module/secret-ref-runtime f97549081955e412d8eb64070c64bb5921bb1324744d824db05767d3adcce403 module/security-runtime -4bfa843c91a04a4cff0496ed89d9b9481c07b8dbdce6de784e2743f4f66afc1d module/session-catalog +5b1e30fe228e0d8c74c11d6ad2d9aed3df80cd3ea4ba2dd63c30cc5f084e93c9 module/session-catalog 50f5e344f98c27570b7a30e32a906b612e2383d21f102e88cd93e1d5425a6de9 module/session-discussion f112bdabc51ba8659b37d0a6f6a32a2b1d471e5b49b56e108bf750ec55a7ea71 module/session-store-runtime 36affbe151431a6141664b6838e20f2d121ff210d57a3c1b4b41a8818b5c81d8 module/setup diff --git a/src/agents/agent-command-execution-identity.test.ts b/src/agents/agent-command-execution-identity.test.ts deleted file mode 100644 index 8d2fae1e2b05..000000000000 --- a/src/agents/agent-command-execution-identity.test.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { afterEach, describe, expect, it } from "vitest"; -import { - configureExecutionIdentityAdmissionSink, - type ExecutionIdentityAdmissionWork, -} from "../audit/execution-identity-admission.js"; -import { executionIdentity } from "./agent-command-execution-identity.js"; -import { createAgentExecutionAttribution } from "./agent-execution-attribution.js"; - -describe("agent command execution identity", () => { - let restoreSink: (() => void) | undefined; - - afterEach(() => { - restoreSink?.(); - restoreSink = undefined; - }); - - it("records the runtime correlation without requiring an audit admission token", () => { - const work: ExecutionIdentityAdmissionWork[] = []; - restoreSink = configureExecutionIdentityAdmissionSink((item) => { - work.push(item); - return true; - }); - const attribution = createAgentExecutionAttribution({ - runId: "run-1", - lifecycleGeneration: "generation-1", - }); - - executionIdentity.record({ - attribution, - agentId: "main", - cfg: { logging: { audit: { enabled: true, executionIdentity: true } } }, - ingress: executionIdentity.localIngress, - runId: attribution.runId, - runtimeKind: "embedded", - }); - - expect(work).toHaveLength(1); - expect(work[0]).toMatchObject({ - kind: "capture", - envelope: { - contextId: attribution.contextId, - executionId: attribution.executionId, - createdAt: attribution.createdAt, - }, - }); - expect(attribution).not.toHaveProperty("executionIdentityAdmission"); - }); - - it("uses exact attribution as the lifecycle authority", () => { - const attribution = createAgentExecutionAttribution({ - runId: "run-1", - lifecycleGeneration: "generation-attribution", - }); - - expect( - executionIdentity.resolveAttribution( - { - executionAttribution: attribution, - lifecycleGeneration: "generation-flat", - } as never, - { runId: attribution.runId }, - ), - ).toEqual({ - attribution, - lifecycleGeneration: "generation-attribution", - }); - }); - - it("rejects attribution captured for a different run", () => { - const attribution = createAgentExecutionAttribution({ - runId: "run-attribution", - lifecycleGeneration: "generation-attribution", - }); - - expect(() => - executionIdentity.resolveAttribution( - { - executionAttribution: attribution, - } as never, - { runId: "run-command" }, - ), - ).toThrow("Agent command execution attribution runId does not match the command runId."); - }); - - it("allocates private attribution for direct command admission", () => { - const resolved = executionIdentity.resolveAttribution( - { lifecycleGeneration: "generation-local" } as never, - { - runId: "run-local", - sessionKey: "agent:main:local", - sessionId: "session-local", - sessionAgentId: "main", - }, - ); - - expect(resolved.attribution).toMatchObject({ - runId: "run-local", - lifecycleGeneration: "generation-local", - sessionKey: "agent:main:local", - sessionId: "session-local", - agentId: "main", - }); - expect(resolved.attribution).not.toHaveProperty("executionIdentityAdmission"); - }); - - it("replaces attribution only after lifecycle rebound", () => { - const attribution = createAgentExecutionAttribution({ - runId: "run-1", - lifecycleGeneration: "generation-1", - }); - const opts = { executionAttribution: attribution } as never; - - expect(executionIdentity.replaceAttribution(opts, attribution)).toBe(opts); - expect( - executionIdentity.replaceAttribution( - opts, - createAgentExecutionAttribution({ - ...attribution, - lifecycleGeneration: "generation-2", - }), - ), - ).not.toBe(opts); - }); - - it("strips untrusted ingress attribution and preserves trusted gateway attribution", () => { - const attribution = createAgentExecutionAttribution({ - runId: "run-1", - lifecycleGeneration: "generation-1", - }); - const opts = { - allowModelOverride: false, - executionAttribution: attribution, - lifecycleGeneration: "generation-flat", - runId: attribution.runId, - } as never; - - expect(executionIdentity.prepareIngress(opts, false)).toEqual({ - lifecycleGeneration: "generation-flat", - opts: { - allowModelOverride: false, - executionAttribution: undefined, - lifecycleGeneration: "generation-flat", - runId: attribution.runId, - }, - }); - expect(executionIdentity.prepareIngress(opts, true)).toEqual({ - lifecycleGeneration: "generation-flat", - opts, - }); - - const inheritedOpts = Object.assign(Object.create({ executionAttribution: attribution }), { - allowModelOverride: false, - lifecycleGeneration: "generation-flat", - runId: attribution.runId, - }) as never; - expect(executionIdentity.prepareIngress(inheritedOpts, false).opts).toHaveProperty( - "executionAttribution", - undefined, - ); - }); -}); diff --git a/src/agents/agent-command-execution-identity.ts b/src/agents/agent-command-execution-identity.ts index b20068c04450..b195b6746412 100644 --- a/src/agents/agent-command-execution-identity.ts +++ b/src/agents/agent-command-execution-identity.ts @@ -4,9 +4,7 @@ import { type ExecutionIdentityAdmissionFacts, } from "../audit/execution-identity-admission.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; -import { captureAgentRunLifecycleGeneration } from "../infra/agent-events.js"; -import { createAgentExecutionAttribution } from "./agent-execution-attribution.js"; -import type { AgentCommandGatewayIngressOpts, AgentCommandOpts } from "./command/types.js"; +import type { AgentCommandOpts } from "./command/types.js"; type AgentCommandAdmissionIngress = ExecutionIdentityAdmissionFacts["ingress"]; @@ -55,74 +53,8 @@ function recordAgentCommandExecutionIdentity(params: { ); } -function resolveAgentCommandExecutionAttribution( - opts: AgentCommandOpts, - params: { - runId: string; - sessionKey?: string; - sessionId?: string; - sessionAgentId?: string; - }, -): { - attribution: NonNullable; - lifecycleGeneration: string; -} { - if (opts.executionAttribution && opts.executionAttribution.runId !== params.runId) { - throw new Error("Agent command execution attribution runId does not match the command runId."); - } - const lifecycleGeneration = - opts.executionAttribution?.lifecycleGeneration ?? - opts.lifecycleGeneration ?? - captureAgentRunLifecycleGeneration(params.runId); - return { - attribution: - opts.executionAttribution ?? - createAgentExecutionAttribution({ - runId: params.runId, - lifecycleGeneration, - sessionKey: params.sessionKey, - sessionId: params.sessionId, - agentId: params.sessionAgentId, - }), - lifecycleGeneration, - }; -} - -function replaceAgentCommandExecutionAttribution( - opts: AgentCommandOpts, - attribution: AgentCommandOpts["executionAttribution"], -): AgentCommandOpts { - return attribution === opts.executionAttribution - ? opts - : { ...opts, executionAttribution: attribution }; -} - -function prepareAgentCommandIngress( - opts: AgentCommandGatewayIngressOpts, - trustedAttribution: boolean, -): { - lifecycleGeneration: string; - opts: AgentCommandGatewayIngressOpts; -} { - const internalOpts: AgentCommandGatewayIngressOpts = trustedAttribution - ? opts - : { ...opts, executionAttribution: undefined }; - if (typeof internalOpts.allowModelOverride !== "boolean") { - throw new Error("allowModelOverride must be explicitly set for ingress agent runs."); - } - return { - lifecycleGeneration: - internalOpts.lifecycleGeneration ?? - captureAgentRunLifecycleGeneration(internalOpts.runId ?? ""), - opts: internalOpts, - }; -} - export const executionIdentity = { localIngress: LOCAL_CLI_ADMISSION_INGRESS, - prepareIngress: prepareAgentCommandIngress, record: recordAgentCommandExecutionIdentity, - replaceAttribution: replaceAgentCommandExecutionAttribution, - resolveAttribution: resolveAgentCommandExecutionAttribution, systemIngress, }; diff --git a/src/agents/agent-command.live-model-switch.test.ts b/src/agents/agent-command.live-model-switch.test.ts index 743da61e2834..4b90ef2d0325 100644 --- a/src/agents/agent-command.live-model-switch.test.ts +++ b/src/agents/agent-command.live-model-switch.test.ts @@ -26,7 +26,6 @@ import { resolveTestModelAliasFromPair, resolveTestModelRefFromString, } from "./agent-command.live-model-switch.test-helpers.js"; -import { createAgentExecutionAttribution } from "./agent-execution-attribution.js"; import { INTERNAL_RUNTIME_CONTEXT_BEGIN, INTERNAL_RUNTIME_CONTEXT_END, @@ -119,7 +118,6 @@ const state = vi.hoisted(() => ({ resolvedSessionKeyMock: undefined as string | undefined, trajectoryRecorderParamsMock: vi.fn(), enqueueExecutionIdentityContextAtAdmissionMock: vi.fn(), - executionIdentityCounter: 0, })); vi.mock("./model-fallback-runner.js", () => ({ @@ -127,19 +125,8 @@ vi.mock("./model-fallback-runner.js", () => ({ })); vi.mock("../audit/execution-identity-admission.js", () => ({ - createExecutionIdentityAdmissionToken: (runId: string) => { - const sequence = ++state.executionIdentityCounter; - return { - tokenVersion: 1, - contextId: `context-${sequence}`, - executionId: `execution-${sequence}`, - runId, - createdAt: sequence, - }; - }, enqueueExecutionIdentityContextAtAdmission: (...args: unknown[]) => state.enqueueExecutionIdentityContextAtAdmissionMock(...args), - parseExecutionIdentityAdmissionToken: (token: unknown) => token, })); vi.mock("./command/attempt-execution.runtime.js", () => ({ @@ -677,14 +664,12 @@ vi.mock("../acp/control-plane/manager.js", () => ({ let agentCommand: typeof import("./agent-command.js").agentCommand; let agentCommandFromSystem: typeof import("./agent-command.js").agentCommandFromSystem; -let agentCommandFromIngress: typeof import("./agent-command.js").agentCommandFromIngress; let agentCommandTesting: typeof import("./agent-command.js").testing; beforeAll(async () => { const mod = await import("./agent-command.js"); agentCommand ??= mod.agentCommand; agentCommandFromSystem ??= mod.agentCommandFromSystem; - agentCommandFromIngress ??= mod.agentCommandFromIngress; agentCommandTesting ??= mod.testing; }); @@ -1105,12 +1090,7 @@ describe("agentCommand – LiveSessionModelSwitchError retry", () => { expect.objectContaining({ ingress: { kind: "local-cli", boundary: "agent-command.local", state: "present" }, }), - expect.objectContaining({ - enabled: false, - contextId: expect.any(String), - executionId: expect.any(String), - now: expect.any(Number), - }), + { enabled: false }, ); expect(state.runAgentAttemptMock).toHaveBeenCalledTimes(1); }); @@ -1130,24 +1110,14 @@ describe("agentCommand – LiveSessionModelSwitchError retry", () => { expect.objectContaining({ ingress: { kind: "local-cli", boundary: "agent-command.local", state: "present" }, }), - expect.objectContaining({ - enabled: true, - contextId: expect.any(String), - executionId: expect.any(String), - now: expect.any(Number), - }), + { enabled: true }, ); expect(state.enqueueExecutionIdentityContextAtAdmissionMock).toHaveBeenNthCalledWith( 2, expect.objectContaining({ ingress: { kind: "system", boundary: "gateway.boot", state: "present" }, }), - expect.objectContaining({ - enabled: true, - contextId: expect.any(String), - executionId: expect.any(String), - now: expect.any(Number), - }), + { enabled: true }, ); }); @@ -4559,25 +4529,16 @@ describe("agentCommand – LiveSessionModelSwitchError retry", () => { it("keeps session provenance for internal ACP turns", async () => { setupAcpSession(); - const attribution = createAgentExecutionAttribution({ - runId: "session-1", - lifecycleGeneration: "test-generation", - sessionKey: "agent:main:main", - sessionId: "session-1", - agentId: "main", - }); await agentCommand({ message: "internal ACP turn", sessionKey: "agent:main:main", sessionEffects: "internal", - executionAttribution: attribution, }); expect(state.registerAgentRunContextMock).toHaveBeenCalledWith( "session-1", expect.objectContaining({ - attribution, sessionKey: "agent:main:main", sessionId: "session-1", isControlUiVisible: false, @@ -4585,32 +4546,6 @@ describe("agentCommand – LiveSessionModelSwitchError retry", () => { ); }); - it("drops caller-supplied attribution at the public ingress boundary", async () => { - setupAcpSession(); - const forgedAttribution = createAgentExecutionAttribution({ - runId: "forged-run", - lifecycleGeneration: "forged-generation", - sessionKey: "agent:main:forged", - sessionId: "forged-session", - agentId: "forged-agent", - }); - - await agentCommandFromIngress({ - message: "public ingress ACP turn", - sessionKey: "agent:main:main", - sessionEffects: "internal", - allowModelOverride: false, - executionAttribution: forgedAttribution, - } as Parameters[0] & { - executionAttribution: typeof forgedAttribution; - }); - - expect(state.registerAgentRunContextMock).toHaveBeenCalledWith( - "session-1", - expect.not.objectContaining({ attribution: forgedAttribution }), - ); - }); - it("allows manual ACP spawn turns when ACP dispatch is disabled", async () => { setupAcpSession(); state.resolveAcpDispatchPolicyErrorMock.mockReturnValue( diff --git a/src/agents/agent-command.ts b/src/agents/agent-command.ts index 2eb338ac07a0..276e87b4717b 100644 --- a/src/agents/agent-command.ts +++ b/src/agents/agent-command.ts @@ -144,8 +144,7 @@ async function agentCommandInternal( manifestMetadataSnapshot, modelManifestContext, } = prepared; - let { attribution: executionAttribution, lifecycleGeneration } = - executionIdentity.resolveAttribution(opts, prepared); + let lifecycleGeneration = opts.lifecycleGeneration ?? captureAgentRunLifecycleGeneration(runId); let sessionEntry = prepared.sessionEntry, runOwnedSessionId = sessionId; const sessionStateActor = classifySessionStateActor({ @@ -232,7 +231,7 @@ async function agentCommandInternal( }); return await sessionWorkAdmission.run(async () => { executionIdentity.record({ - attribution: executionAttribution, + attribution: opts.executionAttribution, agentId: sessionAgentId, cfg, ingress: admissionIngress, @@ -423,7 +422,6 @@ async function agentCommandInternal( workspaceDir, runId, lifecycleGeneration, - attribution: executionAttribution, acpManager, acpResolution, trackInternalModelRunTarget, @@ -490,12 +488,11 @@ async function agentCommandInternal( sessionEntry = modelSelection.sessionEntry; const embeddedAttempt = await runEmbeddedAgentAttempt({ prepared, - opts: executionIdentity.replaceAttribution(opts, executionAttribution), + opts, sessionEntry, lifecycleGeneration, - onLifecycleGenerationChanged: (nextLifecycleGeneration, nextAttribution) => { + onLifecycleGenerationChanged: (nextLifecycleGeneration) => { lifecycleGeneration = nextLifecycleGeneration; - executionAttribution = nextAttribution ?? executionAttribution; }, suppressVisibleSessionEffects, preserveUserFacingSessionModelState, @@ -636,20 +633,20 @@ async function agentCommandFromIngressInternal( recovery?: { restoreAdmittedRecovery?: () => Promise; }, - trustedAttribution = false, ) { - const { lifecycleGeneration, opts: internalOpts } = executionIdentity.prepareIngress( - opts, - trustedAttribution, - ); + if (typeof opts.allowModelOverride !== "boolean") { + throw new Error("allowModelOverride must be explicitly set for ingress agent runs."); + } + const lifecycleGeneration = + opts.lifecycleGeneration ?? captureAgentRunLifecycleGeneration(opts.runId ?? ""); return await withAgentRunLifecycleGeneration(lifecycleGeneration, async () => { const result = await runWithAgentCommandRecoveryOwner({ lifecycleGeneration, mode: "claim", opts: { - ...internalOpts, + ...opts, lifecycleGeneration, - senderIsOwner: internalOpts.senderIsOwner === true, + senderIsOwner: opts.senderIsOwner === true, }, prepare: async (preparedOpts) => await prepareAgentCommandExecution(preparedOpts, runtime), restoreAdmittedRecovery: recovery?.restoreAdmittedRecovery, @@ -664,7 +661,7 @@ async function agentCommandFromIngressInternal( }); if (result) { - emitIngressModelUsageDiagnostic(result, internalOpts); + emitIngressModelUsageDiagnostic(result, opts); } return result; @@ -679,7 +676,11 @@ export async function agentCommandFromIngress( ) { // Plugin SDK callers may be plain JavaScript. Enforce the private execution // boundary at runtime so extra or inherited properties cannot author audit identity. - return await agentCommandFromIngressInternal(opts, runtime, deps); + return await agentCommandFromIngressInternal( + { ...opts, executionAttribution: undefined }, + runtime, + deps, + ); } /** Internal Gateway entrypoint that restores a rejected restart-recovery admission. */ @@ -691,7 +692,7 @@ export async function agentCommandFromGatewayIngress( restoreAdmittedRecovery?: () => Promise; }, ) { - return await agentCommandFromIngressInternal(opts, runtime, deps, recovery, true); + return await agentCommandFromIngressInternal(opts, runtime, deps, recovery); } export const testing = { diff --git a/src/agents/agent-execution-attribution.test.ts b/src/agents/agent-execution-attribution.test.ts index f69c140e0bab..158b37d45bb8 100644 --- a/src/agents/agent-execution-attribution.test.ts +++ b/src/agents/agent-execution-attribution.test.ts @@ -66,26 +66,6 @@ describe("createAgentExecutionAttribution", () => { expect(attribution).not.toHaveProperty("executionIdentityAdmission"); }); - it("ignores inherited audit admission tokens", () => { - const inheritedToken = createExecutionIdentityAdmissionToken("run-1", { - contextId: "inherited-context", - executionId: "inherited-execution", - now: 123, - }); - const params = Object.assign( - Object.create({ - executionIdentityAdmission: { token: inheritedToken, retryOnly: true }, - }) as object, - { runId: "run-1", lifecycleGeneration: "generation-1" }, - ); - - const attribution = createAgentExecutionAttribution(params); - - expect(attribution.contextId).not.toBe("inherited-context"); - expect(attribution.executionId).not.toBe("inherited-execution"); - expect(attribution).not.toHaveProperty("executionIdentityAdmission"); - }); - it.each([false, true])( "changes only lifecycle ownership when rebound (token=%s)", (withToken) => { diff --git a/src/agents/agent-execution-attribution.ts b/src/agents/agent-execution-attribution.ts index b4f00f0d541f..e5c0dc11eb6f 100644 --- a/src/agents/agent-execution-attribution.ts +++ b/src/agents/agent-execution-attribution.ts @@ -30,12 +30,6 @@ function requireAttributionField(value: string, field: "runId" | "lifecycleGener return value; } -function freezeAgentExecutionAttribution( - value: AgentExecutionAttribution, -): AgentExecutionAttribution { - return Object.freeze(Object.assign(Object.create(null) as AgentExecutionAttribution, value)); -} - export function createAgentExecutionAttribution(params: { runId: string; lifecycleGeneration: string; @@ -45,11 +39,8 @@ export function createAgentExecutionAttribution(params: { executionIdentityAdmission?: AgentExecutionIdentityAdmission; }): AgentExecutionAttribution { const runId = requireAttributionField(params.runId, "runId"); - const executionIdentityAdmission = Object.hasOwn(params, "executionIdentityAdmission") - ? params.executionIdentityAdmission - : undefined; - const token = executionIdentityAdmission - ? parseExecutionIdentityAdmissionToken(executionIdentityAdmission.token) + const token = params.executionIdentityAdmission + ? parseExecutionIdentityAdmissionToken(params.executionIdentityAdmission.token) : undefined; if (token && token.runId !== runId) { throw new TypeError("Agent execution attribution token disagrees with runId"); @@ -57,7 +48,7 @@ export function createAgentExecutionAttribution(params: { const sessionKey = normalizeOptionalString(params.sessionKey); const sessionId = normalizeOptionalString(params.sessionId); const agentId = normalizeOptionalString(params.agentId); - return freezeAgentExecutionAttribution({ + return Object.freeze({ runId, contextId: token?.contextId ?? randomUUID(), executionId: token?.executionId ?? randomUUID(), @@ -67,7 +58,7 @@ export function createAgentExecutionAttribution(params: { ? { executionIdentityAdmission: Object.freeze({ token, - retryOnly: executionIdentityAdmission?.retryOnly === true, + retryOnly: params.executionIdentityAdmission?.retryOnly === true, }), } : {}), @@ -81,7 +72,7 @@ export function rebindAgentExecutionAttribution( attribution: AgentExecutionAttribution, lifecycleGeneration: string, ): AgentExecutionAttribution { - return freezeAgentExecutionAttribution({ + return Object.freeze({ ...attribution, lifecycleGeneration: requireAttributionField(lifecycleGeneration, "lifecycleGeneration"), }); diff --git a/src/agents/btw.test.ts b/src/agents/btw.test.ts index 81e849009e1e..d9417b8d7c5c 100644 --- a/src/agents/btw.test.ts +++ b/src/agents/btw.test.ts @@ -9,7 +9,6 @@ import { mintSecretSentinel, resolveSecretSentinel, } from "../secrets/sentinel.js"; -import { createAgentExecutionAttribution } from "./agent-execution-attribution.js"; import type { AgentHarness } from "./harness/types.js"; import type { AgentRuntimeAuthPlan } from "./runtime-plan/types.js"; @@ -795,13 +794,6 @@ describe("runBtwSideQuestion", () => { const codexSideQuestionMock = registerCodexSideQuestionHarness({ supports, }); - const attribution = createAgentExecutionAttribution({ - runId: "run-btw-codex", - lifecycleGeneration: "generation-1", - sessionKey: DEFAULT_SESSION_KEY, - sessionId: "session-1", - agentId: "main", - }); resolveModelWithRegistryMock.mockReturnValue({ provider: "openai", id: "gpt-5.5", @@ -837,7 +829,6 @@ describe("runBtwSideQuestion", () => { }); const result = await runSideQuestion({ - attribution, provider: "openai", model: "gpt-5.5", sessionKey: DEFAULT_SESSION_KEY, @@ -855,7 +846,6 @@ describe("runBtwSideQuestion", () => { expect(result).toEqual({ text: "Codex side answer." }); expect(codexSideQuestionMock).toHaveBeenCalledTimes(1); - expect(mockArg(codexSideQuestionMock, 0, 0)).not.toHaveProperty("attribution"); expect(codexSideQuestionMock).toHaveBeenCalledWith( expect.objectContaining({ provider: "openai", @@ -1476,16 +1466,8 @@ describe("runBtwSideQuestion", () => { it("runs CLI-runtime alias BTW as an ephemeral CLI side question", async () => { const { cleanup, prepared } = mockCliOutput({ text: "CLI side answer." }); - const attribution = createAgentExecutionAttribution({ - runId: "run-btw-cli", - lifecycleGeneration: "generation-1", - sessionKey: DEFAULT_SESSION_KEY, - sessionId: "session-1", - agentId: "main", - }); const result = await runSideQuestion({ - attribution, cfg: { agents: { defaults: { @@ -1509,9 +1491,7 @@ describe("runBtwSideQuestion", () => { cliSessionId?: string; extraSystemPrompt?: string; prompt?: string; - attribution?: unknown; }; - expect(prepareParams.attribution).toBe(attribution); expect(prepareParams.executionMode).toBe("side-question"); expect(prepareParams.provider).toBe("claude-cli"); expect(prepareParams.model).toBe("claude-opus-4-7"); diff --git a/src/agents/btw.ts b/src/agents/btw.ts index d8e08d83379e..00133dea8b2c 100644 --- a/src/agents/btw.ts +++ b/src/agents/btw.ts @@ -21,7 +21,6 @@ import type { } from "../llm/types.js"; import { prepareProviderRuntimeAuth } from "../plugins/provider-runtime.js"; import { isModelSelectionLocked } from "../sessions/model-overrides.js"; -import type { AgentExecutionAttribution } from "./agent-execution-attribution.js"; import { resolveAgentWorkspaceDir, resolveDefaultAgentDir, @@ -581,8 +580,6 @@ async function resolveRuntimeModel(params: { } type RunBtwSideQuestionParams = { - /** Host-owned execution identity; never projected onto the public harness params object. */ - attribution?: AgentExecutionAttribution; cfg: OpenClawConfig; agentDir: string; provider: string; @@ -627,7 +624,6 @@ type RunBtwSideQuestionParams = { }; async function runCliBtwSideQuestion(params: { - attribution?: AgentExecutionAttribution; cfg: OpenClawConfig; model: string; question: string; @@ -652,7 +648,6 @@ async function runCliBtwSideQuestion(params: { overrideSeconds: params.opts?.timeoutOverrideSeconds, }); const prepared = await prepareCliRunContext({ - ...(params.attribution ? { attribution: params.attribution } : {}), sessionId: params.sessionId, sessionKey: params.sessionKey, sessionEntry: params.sessionEntry, @@ -969,9 +964,8 @@ export async function runBtwSideQuestion( runtimeAuthPlan.modelRoute?.authRequirement === "api-key" && "auth" in resolvedAttempt ? resolvedAttempt.auth.apiKey?.trim() : undefined; - const { attribution: _attribution, ...publicParams } = params; const result = await selectedHarness.runSideQuestion({ - ...publicParams, + ...params, provider: runtimeModel.provider, model: runtimeModel.id, runtimeModel, @@ -1092,7 +1086,6 @@ export async function runBtwSideQuestion( : undefined); if (cliProvider) { return runCliBtwSideQuestion({ - ...(params.attribution ? { attribution: params.attribution } : {}), cfg: params.cfg, model: params.model, question: params.question, diff --git a/src/agents/cli-runner.ts b/src/agents/cli-runner.ts index 52bcbc673153..eef0be5cf341 100644 --- a/src/agents/cli-runner.ts +++ b/src/agents/cli-runner.ts @@ -47,7 +47,6 @@ import { attachCliMessagingDeliveryEvidence, getCliMessagingDeliveryEvidence, } from "./cli-runner/delivery-evidence.js"; -import { bindCliRunExecutionAttribution } from "./cli-runner/execution-attribution.js"; import { cliBackendLog, formatCliBackendOutputDigest } from "./cli-runner/log.js"; import { hashCliReseedPrompt } from "./cli-runner/reseed-envelope.js"; import { @@ -590,12 +589,10 @@ async function finalizeCliContextEngineTurn(params: { /** Prepares and runs one CLI-backed agent turn. */ export function runCliAgent(paramsInput: RunCliAgentParams): Promise { - const attributedParams = bindCliRunExecutionAttribution(paramsInput); const lifecycleGeneration = - attributedParams.lifecycleGeneration ?? - captureAgentRunLifecycleGeneration(attributedParams.runId); + paramsInput.lifecycleGeneration ?? captureAgentRunLifecycleGeneration(paramsInput.runId); const params = { - ...attributedParams, + ...paramsInput, lifecycleGeneration, }; // Observability services register before turns and keep subscriptions process-stable. diff --git a/src/agents/cli-runner/execution-attribution.test.ts b/src/agents/cli-runner/execution-attribution.test.ts deleted file mode 100644 index c30412bce535..000000000000 --- a/src/agents/cli-runner/execution-attribution.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { createAgentExecutionAttribution } from "../agent-execution-attribution.js"; -import { bindCliRunExecutionAttribution } from "./execution-attribution.js"; -import type { RunCliAgentParams } from "./types.js"; - -function createRunParams(overrides: Partial = {}): RunCliAgentParams { - return { - sessionId: "legacy-session", - sessionKey: "agent:legacy:main", - agentId: "legacy-agent", - sessionFile: "/tmp/session.jsonl", - workspaceDir: "/tmp/workspace", - prompt: "test", - provider: "test-cli", - timeoutMs: 1_000, - runId: "legacy-run", - lifecycleGeneration: "legacy-generation", - ...overrides, - }; -} - -describe("bindCliRunExecutionAttribution", () => { - it("projects admitted identity over legacy flat fields", () => { - const attribution = createAgentExecutionAttribution({ - runId: "admitted-run", - lifecycleGeneration: "admitted-generation", - sessionKey: "agent:main:main", - sessionId: "admitted-session", - agentId: "main", - }); - - expect(bindCliRunExecutionAttribution(createRunParams({ attribution }))).toMatchObject({ - attribution, - runId: "admitted-run", - lifecycleGeneration: "admitted-generation", - sessionKey: "agent:main:main", - sessionId: "admitted-session", - agentId: "main", - }); - }); - - it("preserves operational CLI routing absent from admitted attribution", () => { - const attribution = createAgentExecutionAttribution({ - runId: "admitted-run", - lifecycleGeneration: "admitted-generation", - sessionId: "admitted-session", - }); - - const bound = bindCliRunExecutionAttribution(createRunParams({ attribution })); - - expect(bound).toMatchObject({ - attribution, - runId: "admitted-run", - lifecycleGeneration: "admitted-generation", - sessionKey: "agent:legacy:main", - sessionId: "admitted-session", - agentId: "legacy-agent", - }); - }); - - it("preserves required CLI routing for sparse admitted attribution", () => { - const attribution = createAgentExecutionAttribution({ - runId: "admitted-run", - lifecycleGeneration: "admitted-generation", - }); - - const bound = bindCliRunExecutionAttribution(createRunParams({ attribution })); - - expect(bound).toMatchObject({ - attribution, - runId: "admitted-run", - lifecycleGeneration: "admitted-generation", - sessionId: "legacy-session", - sessionKey: "agent:legacy:main", - agentId: "legacy-agent", - }); - }); -}); diff --git a/src/agents/cli-runner/execution-attribution.ts b/src/agents/cli-runner/execution-attribution.ts deleted file mode 100644 index 080667f2d144..000000000000 --- a/src/agents/cli-runner/execution-attribution.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { RunCliAgentParams } from "./types.js"; - -/** Projects admitted execution identity over legacy flat CLI-run fields. */ -export function bindCliRunExecutionAttribution(params: RunCliAgentParams): RunCliAgentParams { - const attribution = params.attribution; - if (!attribution) { - return params; - } - const { - runId: _legacyRunId, - lifecycleGeneration: _legacyLifecycleGeneration, - sessionKey: _legacySessionKey, - sessionId: _legacySessionId, - agentId: _legacyAgentId, - ...run - } = params; - return { - ...run, - runId: attribution.runId, - lifecycleGeneration: attribution.lifecycleGeneration, - sessionId: attribution.sessionId ?? _legacySessionId, - // Optional attribution fields are audit facts. When they are absent, keep - // the CLI candidate's operational routing instead of selecting a default. - ...((attribution.sessionKey ?? _legacySessionKey) - ? { sessionKey: attribution.sessionKey ?? _legacySessionKey } - : {}), - ...((attribution.agentId ?? _legacyAgentId) - ? { agentId: attribution.agentId ?? _legacyAgentId } - : {}), - }; -} diff --git a/src/agents/cli-runner/prepare.test.ts b/src/agents/cli-runner/prepare.test.ts index 83eb1b69c84d..1f785847dee2 100644 --- a/src/agents/cli-runner/prepare.test.ts +++ b/src/agents/cli-runner/prepare.test.ts @@ -27,7 +27,6 @@ import { createTestRegistry, } from "../../test-utils/channel-plugins.js"; import { captureEnv, setTestEnvValue } from "../../test-utils/env.js"; -import { createAgentExecutionAttribution } from "../agent-execution-attribution.js"; import { readExternalCliBootstrapCredential as readExternalCliBootstrapCredentialImpl } from "../auth-profiles/external-cli-sync.js"; import { resolveApiKeyForProfile as resolveApiKeyForProfileImpl } from "../auth-profiles/oauth.js"; import { @@ -2973,7 +2972,7 @@ describe("prepareCliRunContext", () => { expect(resolveMcpLoopbackScopedTools).not.toHaveBeenCalled(); }); - it("binds admitted current turn context into the bundle MCP client grant", async () => { + it("binds current turn context into the bundle MCP client grant", async () => { const getActiveMcpLoopbackRuntime = vi.fn(() => ({ port: 31783, ownerToken: "loopback-owner-token", @@ -3020,21 +3019,12 @@ describe("prepareCliRunContext", () => { }, }); const context = await fixture.prepare({ - attribution: createAgentExecutionAttribution({ - runId: "run-test-room-event-tools", - lifecycleGeneration: "generation-admitted", - sessionKey: "agent:main:telegram:group:chat123", - sessionId: "session-test", - agentId: "worker", - }), - sessionKey: "agent:forged:main", - sessionId: "forged-session", + sessionKey: "agent:main:telegram:group:chat123", runtimePolicySessionKey: "agent:worker:discord:default:direct:canonical-sender", - agentId: "forged-agent", + agentId: "worker", provider: "native-cli", modelProvider: "anthropic", - runId: "forged-run", - lifecycleGeneration: "generation-forged", + runId: "run-test-room-event-tools", sessionEntry: { execHost: "node", execSecurity: "allowlist", diff --git a/src/agents/cli-runner/prepare.ts b/src/agents/cli-runner/prepare.ts index b0434f7e9ce4..704d787d8e8a 100644 --- a/src/agents/cli-runner/prepare.ts +++ b/src/agents/cli-runner/prepare.ts @@ -126,7 +126,6 @@ import { resolveBundledCliBackendAuthPolicy, type BundledCliBackendAuthPolicy, } from "./cli-backend-auth-policy.js"; -import { bindCliRunExecutionAttribution } from "./execution-attribution.js"; import { buildCliAgentSystemPrompt, isClaudeCliProvider, normalizeCliModel } from "./helpers.js"; import { cliBackendLog } from "./log.js"; import { buildCliMcpGrantContext, normalizeOptionalMcpContextValue } from "./mcp-grant-context.js"; @@ -401,10 +400,7 @@ function buildCliAuthProfileResolutionError(params: { export async function prepareCliRunContext( inputParams: RunCliAgentParams, ): Promise { - const attributedParams = bindCliRunExecutionAttribution(inputParams); - let params = attributedParams.config - ? attributedParams - : { ...attributedParams, config: getRuntimeConfig() }; + let params = inputParams.config ? inputParams : { ...inputParams, config: getRuntimeConfig() }; const runConfig = params.config!; const selectedOwner = normalizeAgentId( params.agentId?.trim() || diff --git a/src/agents/cli-runner/types.ts b/src/agents/cli-runner/types.ts index 5c6e9ded7161..fbd20338d2f7 100644 --- a/src/agents/cli-runner/types.ts +++ b/src/agents/cli-runner/types.ts @@ -34,7 +34,6 @@ import type { InputProvenance } from "../../sessions/input-provenance.js"; import type { UserTurnTranscriptRecorder } from "../../sessions/user-turn-transcript.js"; import type { SkillSnapshot } from "../../skills/types.js"; import type { AuthProfileStore } from "../auth-profiles/types.js"; -import type { AgentExecutionAttribution } from "../agent-execution-attribution.js"; import type { ExecElevatedDefaults } from "../bash-tools.exec-types.js"; import type { BootstrapContextMode } from "../bootstrap-files.js"; import type { BootstrapContextRunKind } from "../bootstrap-mode.js"; @@ -64,8 +63,6 @@ type CliSessionRetryParams = { /** Input contract for one CLI-backed agent run. */ export type RunCliAgentParams = { - /** Admission-owned execution correlation carried unchanged across CLI retries. */ - attribution?: AgentExecutionAttribution; /** Caller-owned in-memory transcript for ephemeral helper runs. */ sessionManager?: SessionManager; sessionId: string; diff --git a/src/agents/command/acp-execution.ts b/src/agents/command/acp-execution.ts index ce5d8dfac4b1..4059a2dafe7f 100644 --- a/src/agents/command/acp-execution.ts +++ b/src/agents/command/acp-execution.ts @@ -8,7 +8,6 @@ import { formatErrorMessage } from "../../infra/errors.js"; import { createSubsystemLogger } from "../../logging/subsystem.js"; import { normalizeAgentId, resolveAgentIdFromSessionKey } from "../../routing/session-key.js"; import type { RuntimeEnv } from "../../runtime.js"; -import type { AgentExecutionAttribution } from "../agent-execution-attribution.js"; import { prepareInternalSessionEffectsSession } from "../internal-session-effects.js"; import type { AgentRunSessionTarget } from "../run-session-target.js"; import { isAgentRunRestartAbortReason } from "../run-termination.js"; @@ -50,7 +49,6 @@ export async function runAcpAgentCommand(params: { workspaceDir: string; runId: string; lifecycleGeneration: string; - attribution?: AgentExecutionAttribution; acpManager: PreparedAgentCommandExecution["acpManager"]; acpResolution: AcpReadyResolution; trackInternalModelRunTarget: (target: AgentRunSessionTarget | undefined) => void; @@ -59,7 +57,6 @@ export async function runAcpAgentCommand(params: { const acpToolTracker = attemptExecutionRuntime.createAcpToolLifecycleTracker(); const startedAt = Date.now(); registerAgentRunContext(params.runId, { - ...(params.attribution ? { attribution: params.attribution } : {}), sessionKey: params.sessionKey, sessionId: params.sessionId, agentId: params.sessionAgentId, diff --git a/src/agents/command/attempt-execution.cli.test.ts b/src/agents/command/attempt-execution.cli.test.ts index 4297d8279ba3..77b8efc1c6db 100644 --- a/src/agents/command/attempt-execution.cli.test.ts +++ b/src/agents/command/attempt-execution.cli.test.ts @@ -406,9 +406,6 @@ vi.mock("../model-runtime-aliases.js", async () => { vi.mock("../embedded-agent.js", () => ({ runEmbeddedAgent: runEmbeddedAgentMock, })); -vi.mock("../embedded-agent-runner/run-orchestrator.js", () => ({ - runEmbeddedAgentInternal: runEmbeddedAgentMock, -})); vi.mock("../session-write-lock.js", async () => { const actual = await vi.importActual( diff --git a/src/agents/command/attempt-execution.ts b/src/agents/command/attempt-execution.ts index c9074a57260e..0acdc64bb150 100644 --- a/src/agents/command/attempt-execution.ts +++ b/src/agents/command/attempt-execution.ts @@ -51,7 +51,6 @@ import { } from "../../tasks/task-status-access.js"; import { resolveUserPath } from "../../utils.js"; import { resolveMessageChannel } from "../../utils/message-channel.js"; -import type { AgentExecutionAttribution } from "../agent-execution-attribution.js"; import type { AgentRunTerminalReplySnapshot } from "../agent-run-terminal-reply.js"; import { resolveAuthProfileOrder } from "../auth-profiles/order.js"; import { ensureAuthProfileStore } from "../auth-profiles/store.js"; @@ -75,12 +74,7 @@ import { } from "../cli-session.js"; import { resolveConversationCapabilityProfile } from "../conversation-capability-profile.js"; import { resolveConversationToolPolicies } from "../conversation-tool-policy-pipeline.js"; -import { runEmbeddedAgentInternal } from "../embedded-agent-runner/run-orchestrator.js"; -import type { - AgentExecutionAttributionInfo, - RunEmbeddedAgentInternalParams, -} from "../embedded-agent-runner/run/internal-params.js"; -import type { EmbeddedAgentRunResult } from "../embedded-agent.js"; +import { runEmbeddedAgent, type EmbeddedAgentRunResult } from "../embedded-agent.js"; import type { ContextEngineLogicalTurnLease } from "../harness/context-engine-logical-turn.js"; import type { ContextEngineTurnAttemptFacts } from "../harness/context-engine-turn-attempt.js"; import { runAgentHarnessBeforeMessageWriteHook } from "../harness/hook-helpers.js"; @@ -579,10 +573,7 @@ export function runAgentAttempt(params: { contextEngineLogicalTurnLease?: ContextEngineLogicalTurnLease; onUserMessagePersisted?: (message: Extract) => void; onContextEngineTurnCandidate?: (facts: ContextEngineTurnAttemptFacts) => void; - onLifecycleGenerationChanged?: ( - lifecycleGeneration: string, - attribution?: AgentExecutionAttribution, - ) => void; + onLifecycleGenerationChanged?: (lifecycleGeneration: string) => void; }) { const sessionAuthProfileId = params.sessionEntry?.authProfileOverride?.trim(); const sessionAuthProfileSource = resolveSessionAuthProfileOverrideSource(params.sessionEntry); @@ -972,9 +963,6 @@ export function runAgentAttempt(params: { runId: params.runId, lifecycleGeneration: params.lifecycleGeneration, onExecutionStarted: params.opts.onExecutionStarted, - ...(params.opts.executionAttribution - ? { attribution: params.opts.executionAttribution } - : {}), lane: params.opts.lane, extraSystemPrompt: params.opts.extraSystemPrompt, inputProvenance: params.opts.inputProvenance, @@ -1155,7 +1143,7 @@ export function runAgentAttempt(params: { }); } - const embeddedRunParams: RunEmbeddedAgentInternalParams = { + const embeddedRunParams: Parameters[0] = { sessionId: params.sessionId, sessionKey: params.sessionKey, chatType: params.sessionEntry?.chatType, @@ -1216,7 +1204,6 @@ export function runAgentAttempt(params: { runTimeoutOverrideMs: params.runTimeoutOverrideMs, runId: params.runId, lifecycleGeneration: params.lifecycleGeneration, - ...(params.opts.executionAttribution ? { attribution: params.opts.executionAttribution } : {}), lane: params.opts.lane, // Hidden internal runs lack an event consumer; visible lanes still feed UI and parent relays. suppressLiveStreamOutput: shouldSuppressEmbeddedLiveStreamOutput(params), @@ -1256,12 +1243,10 @@ export function runAgentAttempt(params: { contextEngineLogicalTurnLease: params.contextEngineLogicalTurnLease, onContextEngineTurnCandidate: params.onContextEngineTurnCandidate, onUserMessagePersisted: params.onUserMessagePersisted, - onExecutionStarted: () => { + onExecutionStarted: (info) => { params.opts.onExecutionStarted?.(); - }, - onExecutionAttributionChanged: (info: AgentExecutionAttributionInfo) => { if (info?.lifecycleGeneration) { - params.onLifecycleGenerationChanged?.(info.lifecycleGeneration, info.attribution); + params.onLifecycleGenerationChanged?.(info.lifecycleGeneration); } }, onSessionIdChanged: params.opts.onSessionIdChanged, @@ -1273,7 +1258,7 @@ export function runAgentAttempt(params: { embeddedRunParams, readChannelSourceTurnSameThreadRequired(params.runContext), ); - return runEmbeddedAgentInternal(embeddedRunParams); + return runEmbeddedAgent(embeddedRunParams); } export function buildAcpResult(params: { diff --git a/src/agents/command/run-embedded-attempt.ts b/src/agents/command/run-embedded-attempt.ts index 25cf1a90874d..a5411c6d9c25 100644 --- a/src/agents/command/run-embedded-attempt.ts +++ b/src/agents/command/run-embedded-attempt.ts @@ -15,7 +15,6 @@ import { } from "../../tasks/task-status-access.js"; import { createTrajectoryRuntimeRecorder } from "../../trajectory/runtime.js"; import { resolveMessageChannel } from "../../utils/message-channel.js"; -import type { AgentExecutionAttribution } from "../agent-execution-attribution.js"; import { clearAutoFallbackPrimaryProbeSelection, entryMatchesAutoFallbackPrimaryProbe, @@ -68,10 +67,7 @@ export async function runEmbeddedAgentAttempt(params: { opts: AgentCommandOpts; sessionEntry?: SessionEntry; lifecycleGeneration: string; - onLifecycleGenerationChanged: ( - lifecycleGeneration: string, - attribution?: AgentExecutionAttribution, - ) => void; + onLifecycleGenerationChanged: (lifecycleGeneration: string) => void; suppressVisibleSessionEffects: boolean; preserveUserFacingSessionModelState: boolean; modelSelection: EmbeddedModelSelection; @@ -99,7 +95,6 @@ export async function runEmbeddedAgentAttempt(params: { timeoutMs, runTimeoutOverrideMs, } = params.prepared; - let executionAttribution = params.opts.executionAttribution; const { runContext, skillsSnapshot, resolvedVerboseLevel } = params.embeddedSessionState; const { defaultProvider, @@ -479,10 +474,7 @@ export async function runEmbeddedAgentAttempt(params: { runTimeoutOverrideMs, runId, lifecycleGeneration, - opts: - executionAttribution === params.opts.executionAttribution - ? params.opts - : { ...params.opts, executionAttribution }, + opts: params.opts, runContext, spawnedBy, messageChannel, @@ -508,11 +500,10 @@ export async function runEmbeddedAgentAttempt(params: { contextEngineLogicalTurnLease: runOptions.contextEngineLogicalTurnLease, onContextEngineTurnCandidate: runOptions.onContextEngineTurnCandidate, onUserMessagePersisted: attemptLifecycleCallbacks.onUserMessagePersisted, - onLifecycleGenerationChanged: (nextLifecycleGeneration, nextAttribution) => { + onLifecycleGenerationChanged: (nextLifecycleGeneration) => { lifecycleGeneration = nextLifecycleGeneration; - executionAttribution = nextAttribution ?? executionAttribution; // Outer cleanup owns the run context, so publish before the attempt can reject. - params.onLifecycleGenerationChanged(nextLifecycleGeneration, nextAttribution); + params.onLifecycleGenerationChanged(nextLifecycleGeneration); }, onAgentEvent: attemptLifecycleCallbacks.onAgentEvent, deferTerminalLifecycle: true, diff --git a/src/agents/embedded-agent-runner/cli-backend-dispatch.test.ts b/src/agents/embedded-agent-runner/cli-backend-dispatch.test.ts index c72a844dded4..30fb5c937391 100644 --- a/src/agents/embedded-agent-runner/cli-backend-dispatch.test.ts +++ b/src/agents/embedded-agent-runner/cli-backend-dispatch.test.ts @@ -1,9 +1,8 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { emitAgentEvent } from "../../infra/agent-events.js"; -import { createAgentExecutionAttribution } from "../agent-execution-attribution.js"; import { resolveEmbeddedCliBackendDispatchEligibility } from "./cli-backend-dispatch-eligibility.js"; import { runEmbeddedAgentViaCliBackendIfEligible } from "./cli-backend-dispatch.js"; -import type { RunEmbeddedAgentInternalParams } from "./run/internal-params.js"; +import type { RunEmbeddedAgentParams } from "./run/params.js"; import type { EmbeddedAgentRunResult } from "./types.js"; const ensureAuthProfileStore = vi.hoisted(() => vi.fn()); @@ -44,9 +43,7 @@ vi.mock("./cli-backend-dispatch-transcript.js", () => ({ createCliDispatchTranscriptRecorder, })); -function baseRunParams( - overrides: Partial = {}, -): RunEmbeddedAgentInternalParams { +function baseRunParams(overrides: Partial = {}): RunEmbeddedAgentParams { return { sessionId: "recall-session", sessionKey: "agent:main:recall", @@ -213,7 +210,7 @@ describe("resolveEmbeddedCliBackendDispatchEligibility", () => { }); describe("runEmbeddedAgentViaCliBackendIfEligible gate", () => { - const runGate = (overrides: Partial = {}) => + const runGate = (overrides: Partial = {}) => runEmbeddedAgentViaCliBackendIfEligible(baseRunParams(overrides)); it("returns undefined without the opt-in", async () => { @@ -395,7 +392,7 @@ describe("runEmbeddedAgentViaCliBackendIfEligible execution", () => { ] as const)("refuses dispatch for %s", async (_label, overrides) => { expect( await runEmbeddedAgentViaCliBackendIfEligible( - baseRunParams(overrides as Partial), + baseRunParams(overrides as Partial), ), ).toBeUndefined(); expect(runCliAgent).not.toHaveBeenCalled(); @@ -411,34 +408,6 @@ describe("runEmbeddedAgentViaCliBackendIfEligible execution", () => { expect(onExecutionStarted).toHaveBeenCalledWith({ lifecycleGeneration: "gen-1" }); }); - it("preserves admission attribution through the embedded-to-CLI bridge", async () => { - const attribution = createAgentExecutionAttribution({ - runId: "run-cli-dispatch-test", - lifecycleGeneration: "gen-1", - sessionKey: "agent:main:recall", - sessionId: "recall-session", - agentId: "main", - }); - const onExecutionStarted = vi.fn(); - const onExecutionAttributionChanged = vi.fn(); - - await runEmbeddedAgentViaCliBackendIfEligible( - baseRunParams({ - attribution, - lifecycleGeneration: "gen-1", - onExecutionStarted, - onExecutionAttributionChanged, - }), - ); - - expect(runCliAgent.mock.calls[0]?.[0]?.attribution).toBe(attribution); - expect(onExecutionStarted).toHaveBeenCalledWith({ lifecycleGeneration: "gen-1" }); - expect(onExecutionAttributionChanged).toHaveBeenCalledWith({ - lifecycleGeneration: "gen-1", - attribution, - }); - }); - it("retains prompt media facts through the embedded-to-CLI bridge", async () => { const media = [{ path: "/tmp/recall.png", contentType: "image/png" }]; @@ -453,9 +422,7 @@ describe("runEmbeddedAgentViaCliBackendIfEligible execution", () => { it("forwards execution phases from the CLI backend", async () => { const onExecutionPhase = vi.fn(); runCliAgent.mockImplementation( - async (cliParams: { - onExecutionPhase?: RunEmbeddedAgentInternalParams["onExecutionPhase"]; - }) => { + async (cliParams: { onExecutionPhase?: RunEmbeddedAgentParams["onExecutionPhase"] }) => { cliParams.onExecutionPhase?.({ phase: "model_call_started", provider: "anthropic", diff --git a/src/agents/embedded-agent-runner/cli-backend-dispatch.ts b/src/agents/embedded-agent-runner/cli-backend-dispatch.ts index 955ae9fdcf4a..a66ed799211d 100644 --- a/src/agents/embedded-agent-runner/cli-backend-dispatch.ts +++ b/src/agents/embedded-agent-runner/cli-backend-dispatch.ts @@ -19,7 +19,7 @@ import { normalizeToolName } from "../tool-policy.js"; import { isToolResultError } from "../tool-result-error.js"; import { resolveEmbeddedCliBackendDispatchEligibility } from "./cli-backend-dispatch-eligibility.js"; import { createCliDispatchTranscriptRecorder } from "./cli-backend-dispatch-transcript.js"; -import type { RunEmbeddedAgentInternalParams } from "./run/internal-params.js"; +import type { RunEmbeddedAgentParams } from "./run/params.js"; import type { EmbeddedAgentRunResult } from "./types.js"; const log = createSubsystemLogger("agents/embedded-cli-dispatch"); @@ -36,7 +36,7 @@ type EmbeddedCliBackendDispatch = { * gate matches; returns undefined so the caller continues on the native path. */ export async function runEmbeddedAgentViaCliBackendIfEligible( - params: RunEmbeddedAgentInternalParams, + params: RunEmbeddedAgentParams, ): Promise { const dispatch = resolveEmbeddedCliBackendDispatch(params); return dispatch ? await runEmbeddedAgentViaCliBackend(params, dispatch) : undefined; @@ -44,7 +44,7 @@ export async function runEmbeddedAgentViaCliBackendIfEligible( /** Applies the opt-in and transcript-path gates on top of shared eligibility. */ function resolveEmbeddedCliBackendDispatch( - params: RunEmbeddedAgentInternalParams, + params: RunEmbeddedAgentParams, ): EmbeddedCliBackendDispatch | undefined { if (params.cliBackendDispatch !== "subscription-auth") { return undefined; @@ -76,9 +76,7 @@ function resolveEmbeddedCliBackendDispatch( * passthrough so no closed state silently widens on the CLI surface; full * translation can arrive with the first caller that needs it (#57326). */ -function resolveDispatchableToolsAllow( - params: RunEmbeddedAgentInternalParams, -): string[] | undefined { +function resolveDispatchableToolsAllow(params: RunEmbeddedAgentParams): string[] | undefined { if (params.disableTools || params.modelRun) { return undefined; } @@ -94,7 +92,7 @@ function resolveDispatchableToolsAllow( /** Runs an opted-in embedded run through the CLI backend as a one-shot turn. */ async function runEmbeddedAgentViaCliBackend( - params: RunEmbeddedAgentInternalParams, + params: RunEmbeddedAgentParams, dispatch: EmbeddedCliBackendDispatch, ): Promise { const { runCliAgent } = await import("../cli-runner.runtime.js"); @@ -188,12 +186,6 @@ async function runEmbeddedAgentViaCliBackend( ? { lifecycleGeneration: params.lifecycleGeneration } : undefined, ); - params.onExecutionAttributionChanged?.({ - ...(params.lifecycleGeneration !== undefined - ? { lifecycleGeneration: params.lifecycleGeneration } - : {}), - ...(params.attribution ? { attribution: params.attribution } : {}), - }); log.info( `dispatching embedded run through CLI backend: runId=${params.runId} provider=${dispatch.provider} model=${params.model ?? ""}`, ); @@ -219,7 +211,6 @@ async function runEmbeddedAgentViaCliBackend( runTimeoutOverrideMs: params.runTimeoutOverrideMs ?? params.timeoutMs, runId: params.runId, lifecycleGeneration: params.lifecycleGeneration, - ...(params.attribution ? { attribution: params.attribution } : {}), lane: params.lane, extraSystemPrompt: params.extraSystemPrompt, messageChannel: params.messageChannel, diff --git a/src/agents/embedded-agent-runner/run-orchestrator.ts b/src/agents/embedded-agent-runner/run-orchestrator.ts index cfcbdbc36c1f..36e5ad53cbaa 100644 --- a/src/agents/embedded-agent-runner/run-orchestrator.ts +++ b/src/agents/embedded-agent-runner/run-orchestrator.ts @@ -78,21 +78,7 @@ const EMPTY_EMBEDDED_AGENT_CONFIG: OpenClawConfig = Object.freeze({}); export function runEmbeddedAgent( paramsInput: RunEmbeddedAgentParams, ): Promise { - // The plugin-facing API is a JavaScript boundary. Strip host-only fields even - // when an untyped caller adds them to the public params object. - const { - attribution: _attribution, - onExecutionAttributionChanged: _onExecutionAttributionChanged, - ...publicParams - } = paramsInput as RunEmbeddedAgentParams & - Pick; - return runEmbeddedAgentInternal(publicParams); -} - -export function runEmbeddedAgentInternal( - paramsInput: RunEmbeddedAgentInternalParams, -): Promise { - const internalParamsInput = paramsInput; + const internalParamsInput = paramsInput as RunEmbeddedAgentInternalParams; const requestedProvider = normalizeOptionalString(internalParamsInput.provider); const requestedModel = normalizeOptionalString(internalParamsInput.model); const needsConfiguredDefault = @@ -104,7 +90,7 @@ export function runEmbeddedAgentInternal( internalParamsInput.lifecycleGeneration ?? captureAgentRunLifecycleGeneration(internalParamsInput.runId); return withAgentRunLifecycleGeneration(lifecycleGeneration, () => - runEmbeddedAgentOrchestrated({ + runEmbeddedAgentInternal({ ...internalParamsInput, config, lifecycleGeneration, @@ -112,7 +98,7 @@ export function runEmbeddedAgentInternal( ); } -async function runEmbeddedAgentOrchestrated( +async function runEmbeddedAgentInternal( paramsInput: RunEmbeddedAgentInternalParams, ): Promise { const paramsBase = applyAgentRunSessionTargetIdentity(paramsInput); @@ -330,10 +316,6 @@ async function runEmbeddedAgentOrchestrated( tracker: startupStages, }); params.onExecutionStarted?.({ lifecycleGeneration }); - params.onExecutionAttributionChanged?.({ - lifecycleGeneration, - ...(params.attribution ? { attribution: params.attribution } : {}), - }); notifyExecutionPhase("runner_entered"); const canonicalWorkspace = resolveUserPath( resolveAgentWorkspaceDir(preparedModelRuntime.config, preparedAgentId), diff --git a/src/agents/embedded-agent-runner/run.cli-dispatch-lane.test.ts b/src/agents/embedded-agent-runner/run.cli-dispatch-lane.test.ts index 3bb315e19b28..f787d503fc9d 100644 --- a/src/agents/embedded-agent-runner/run.cli-dispatch-lane.test.ts +++ b/src/agents/embedded-agent-runner/run.cli-dispatch-lane.test.ts @@ -87,24 +87,4 @@ describe("runEmbeddedAgent CLI dispatch lane admission", () => { ]); expect(runEmbeddedAgentViaCliBackendIfEligible).toHaveBeenCalledTimes(1); }); - - it("strips host-owned attribution fields at the public runner boundary", async () => { - runEmbeddedAgentViaCliBackendIfEligible.mockResolvedValue(dispatchResult); - const forgedAttribution = { - runId: "forged", - lifecycleGeneration: "forged-generation", - }; - const forgedAttributionObserver = vi.fn(); - - await runEmbeddedAgent({ - ...laneRunParams(), - attribution: forgedAttribution, - onExecutionAttributionChanged: forgedAttributionObserver, - } as never); - - const admittedParams = runEmbeddedAgentViaCliBackendIfEligible.mock.calls[0]?.[0]; - expect(admittedParams).not.toHaveProperty("attribution"); - expect(admittedParams).not.toHaveProperty("onExecutionAttributionChanged"); - expect(forgedAttributionObserver).not.toHaveBeenCalled(); - }); }); diff --git a/src/agents/embedded-agent-runner/run.overflow-compaction.loop.test.ts b/src/agents/embedded-agent-runner/run.overflow-compaction.loop.test.ts index 09c48c961f32..6708a5c9070b 100644 --- a/src/agents/embedded-agent-runner/run.overflow-compaction.loop.test.ts +++ b/src/agents/embedded-agent-runner/run.overflow-compaction.loop.test.ts @@ -1,5 +1,4 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import { createAgentExecutionAttribution } from "../agent-execution-attribution.js"; import { createEmbeddedRunReplayState, type EmbeddedRunReplayState, @@ -152,19 +151,6 @@ describe("embedded run retry dispatch", () => { expect(mocks.settleRequesterAfterSessionSpawns).not.toHaveBeenCalled(); }); - it("keeps host-owned attribution out of plugin harness attempt parameters", async () => { - const input = makeDispatchInput({}, createEmbeddedRunReplayState()); - input.params.attribution = createAgentExecutionAttribution({ - runId: "run-1", - lifecycleGeneration: "generation-1", - }); - - const result = await dispatchEmbeddedRunAttempt(input); - - expect(result.preparedAttempt).not.toHaveProperty("attribution"); - expect(mocks.runAttempt).toHaveBeenCalledWith(result.preparedAttempt); - }); - it.each([true, false])( "settles accepted spawns before a late post-compaction abort (yielded: %s)", async (yieldDetected) => { diff --git a/src/agents/embedded-agent-runner/run/internal-params.ts b/src/agents/embedded-agent-runner/run/internal-params.ts index b05dbc5b418c..e53adb256064 100644 --- a/src/agents/embedded-agent-runner/run/internal-params.ts +++ b/src/agents/embedded-agent-runner/run/internal-params.ts @@ -1,18 +1,8 @@ -import type { AgentExecutionAttribution } from "../../agent-execution-attribution.js"; import type { AgentExecutionAuthBinding } from "../../execution-auth-binding.js"; import type { SystemAgentToolOptions } from "../../tools/system-agent-tool.js"; import type { RunEmbeddedAgentParams } from "./params.js"; -export type AgentExecutionAttributionInfo = { - lifecycleGeneration?: string; - attribution?: AgentExecutionAttribution; -}; - export type RunEmbeddedAgentInternalParams = RunEmbeddedAgentParams & { - /** Admission-owned execution correlation carried unchanged across attempts. */ - attribution?: AgentExecutionAttribution; - /** Private observer for host-owned attribution after final execution admission. */ - onExecutionAttributionChanged?: (info: AgentExecutionAttributionInfo) => void; onSuccessfulAuthBinding?: (binding: AgentExecutionAuthBinding) => void; authProfileStateMode?: "read-write" | "read-only"; /** Keep staged setup config and credentials outside configured Gateway ownership. */ diff --git a/src/agents/embedded-agent-runner/run/lane-controller.lifecycle.test.ts b/src/agents/embedded-agent-runner/run/lane-controller.lifecycle.test.ts index 8bc50e599f87..b14c0425c5e9 100644 --- a/src/agents/embedded-agent-runner/run/lane-controller.lifecycle.test.ts +++ b/src/agents/embedded-agent-runner/run/lane-controller.lifecycle.test.ts @@ -8,10 +8,10 @@ import { claimAgentRunContext, getAgentRunContext } from "../../../infra/agent-r import type { CommandQueueEnqueueOptions } from "../../../process/command-queue.types.js"; import { createAgentExecutionAttribution } from "../../agent-execution-attribution.js"; import type { EmbeddedAgentRunResult } from "../types.js"; -import type { RunEmbeddedAgentParamsWithSessionFile } from "./internal-params.js"; import { createEmbeddedRunLaneController } from "./lane-controller.js"; +import type { RunEmbeddedAgentParams } from "./params.js"; -type LaneParams = RunEmbeddedAgentParamsWithSessionFile; +type LaneParams = RunEmbeddedAgentParams & { sessionFile: string }; const completedResult: EmbeddedAgentRunResult = { payloads: [], @@ -48,7 +48,6 @@ function createController(options: { enqueue?: LaneParams["enqueue"]; trigger?: LaneParams["trigger"]; abortSignal?: AbortSignal; - attribution?: LaneParams["attribution"]; runId?: string; }) { let lifecycleGeneration = options.lifecycleGeneration; @@ -62,7 +61,6 @@ function createController(options: { timeoutMs: 30_000, runId: options.runId ?? "run-1", lifecycleGeneration, - attribution: options.attribution, trigger: options.trigger, enqueue: options.enqueue, abortSignal: options.abortSignal, @@ -113,19 +111,11 @@ describe("createEmbeddedRunLaneController lifecycle admission", () => { it("rebinds foreground work that was queued before lifecycle rotation", async () => { const queue = deferredTaskQueue(); const generation = getAgentEventLifecycleGeneration(); - const attribution = createAgentExecutionAttribution({ - runId: "queued-across-restart", - lifecycleGeneration: generation, - sessionKey: "agent:main:session-1", - sessionId: "session-1", - agentId: "main", - }); const state = createController({ lifecycleGeneration: generation, enqueue: queue.enqueue as LaneParams["enqueue"], trigger: "user", runId: "queued-across-restart", - attribution, }); const run = state.controller.enqueueGlobal(async () => completedResult); @@ -135,14 +125,7 @@ describe("createEmbeddedRunLaneController lifecycle admission", () => { expect(state.getLifecycleGeneration()).toBe(currentGeneration); expect(state.getParams().lifecycleGeneration).toBe(currentGeneration); - expect(state.getParams().attribution).toEqual({ - ...attribution, - lifecycleGeneration: currentGeneration, - }); - expect(state.getParams().attribution).not.toBe(attribution); - expect(Object.isFrozen(state.getParams().attribution)).toBe(true); expect(getAgentRunContext("queued-across-restart")).toMatchObject({ - attribution: state.getParams().attribution, lifecycleGeneration: currentGeneration, }); }); @@ -176,47 +159,12 @@ describe("createEmbeddedRunLaneController lifecycle admission", () => { queue.release(); await run; - expect(state.getParams().attribution).toEqual({ - ...attribution, - lifecycleGeneration: currentGeneration, - }); expect(getAgentRunContext(attribution.runId)?.attribution).toEqual({ ...attribution, lifecycleGeneration: currentGeneration, }); }); - it("preserves absent attribution identity when queued foreground work rebinds", async () => { - const queue = deferredTaskQueue(); - const generation = getAgentEventLifecycleGeneration(); - const attribution = createAgentExecutionAttribution({ - runId: "queued-sparse-attribution", - lifecycleGeneration: generation, - }); - const state = createController({ - lifecycleGeneration: generation, - enqueue: queue.enqueue as LaneParams["enqueue"], - trigger: "user", - runId: "queued-sparse-attribution", - attribution, - }); - const run = state.controller.enqueueGlobal(async () => completedResult); - - const currentGeneration = rotateAgentEventLifecycleGeneration(); - queue.release(); - await run; - - expect(state.getParams().attribution).toEqual({ - ...attribution, - lifecycleGeneration: currentGeneration, - }); - expect(state.getParams().attribution?.executionId).toBe(attribution.executionId); - expect(state.getParams().attribution?.contextId).toBe(attribution.contextId); - expect(state.getParams().attribution).not.toHaveProperty("sessionKey"); - expect(state.getParams().attribution).not.toHaveProperty("sessionId"); - expect(state.getParams().attribution).not.toHaveProperty("agentId"); - }); - it("rejects background work queued across lifecycle rotation", async () => { const queue = deferredTaskQueue(); const generation = getAgentEventLifecycleGeneration(); diff --git a/src/agents/embedded-agent-runner/run/lane-controller.ts b/src/agents/embedded-agent-runner/run/lane-controller.ts index e143d0465720..8e37438f4239 100644 --- a/src/agents/embedded-agent-runner/run/lane-controller.ts +++ b/src/agents/embedded-agent-runner/run/lane-controller.ts @@ -13,7 +13,6 @@ import type { CommandQueueEnqueueOptions } from "../../../process/command-queue. import { rebindAgentExecutionAttribution } from "../../agent-execution-attribution.js"; import { withSessionPlacementTurnAdmission } from "../../session-placement-admission.js"; import type { EmbeddedAgentRunResult } from "../types.js"; -import type { RunEmbeddedAgentInternalParams } from "./internal-params.js"; import { EMBEDDED_RUN_LANE_TIMEOUT_GRACE_MS, resolveEmbeddedRunLaneTimeoutMs, @@ -21,9 +20,10 @@ import { shouldNoteLaneWait, withEmbeddedRunLaneTimeout, } from "./lane-runtime.js"; +import type { RunEmbeddedAgentParams } from "./params.js"; import { assertAgentHarnessRunAdmission } from "./session-bootstrap.js"; -type LaneParams = RunEmbeddedAgentInternalParams & { +type LaneParams = RunEmbeddedAgentParams & { sessionFile: string; }; @@ -148,16 +148,7 @@ export function createEmbeddedRunLaneController(opti } lifecycleGeneration = currentLifecycleGeneration; options.setLifecycleGeneration(lifecycleGeneration); - // Lifecycle rebound preserves the admitted identity snapshot, including - // authoritative absence; only a fresh admission may replace identity. - const attribution = params.attribution - ? rebindAgentExecutionAttribution(params.attribution, lifecycleGeneration) - : undefined; - params = { - ...params, - lifecycleGeneration, - ...(attribution ? { attribution } : {}), - }; + params = { ...params, lifecycleGeneration }; options.setParams(params); } // Queue waits can outlive durable harness and placement bindings. @@ -178,15 +169,9 @@ export function createEmbeddedRunLaneController(opti assertAgentRunLifecycleGenerationCurrent(lifecycleGeneration); releaseQueuedContext("admitted"); // Queue-stage rotation may rebind, but placement admitted into a retired runtime must fail. - const attribution = - params.attribution ?? - (existingContext?.attribution - ? rebindAgentExecutionAttribution(existingContext.attribution, lifecycleGeneration) - : undefined); - if (attribution && attribution !== params.attribution) { - params = { ...params, attribution }; - options.setParams(params); - } + const attribution = existingContext?.attribution + ? rebindAgentExecutionAttribution(existingContext.attribution, lifecycleGeneration) + : undefined; claimAgentRunContext(params.runId, { ...existingContext, ...(attribution ? { attribution } : {}), diff --git a/src/agents/embedded-agent-runner/run/run-attempt-dispatch.ts b/src/agents/embedded-agent-runner/run/run-attempt-dispatch.ts index f809a55e7077..75ad1ecb4cb2 100644 --- a/src/agents/embedded-agent-runner/run/run-attempt-dispatch.ts +++ b/src/agents/embedded-agent-runner/run/run-attempt-dispatch.ts @@ -12,7 +12,6 @@ import type { SystemAgentToolOptions } from "../../tools/system-agent-tool.js"; import { prepareExecApprovalContinuationForAttempt } from "./attempt-exec-approval-continuation.js"; import { applyResolvedToolPromptFinalizer } from "./attempt-prompt-tool-policy.js"; import { runEmbeddedAttemptWithBackend } from "./backend.js"; -import type { RunEmbeddedAgentInternalParams } from "./internal-params.js"; import { EMBEDDED_RUN_LANE_HEARTBEAT_MS, EMBEDDED_RUN_LANE_TIMEOUT_GRACE_MS, @@ -22,7 +21,7 @@ import { preparePluginHarnessPromptImages } from "./plugin-harness-prompt-images import { resolveSkillWorkshopAttemptParams } from "./skill-workshop-attempt-params.js"; import type { EmbeddedRunAttemptParams, EmbeddedRunAttemptTrajectoryRecorder } from "./types.js"; -type InternalRunParams = RunEmbeddedAgentInternalParams & { +type InternalRunParams = RunEmbeddedAgentParams & { sessionFile: string; systemAgentTool?: SystemAgentToolOptions; }; diff --git a/src/agents/session-placement-admission.ts b/src/agents/session-placement-admission.ts index 02776ce33d51..cc97de64423b 100644 --- a/src/agents/session-placement-admission.ts +++ b/src/agents/session-placement-admission.ts @@ -1,5 +1,5 @@ import { resolveGlobalSingleton } from "../shared/global-singleton.js"; -import type { RunEmbeddedAgentInternalParams } from "./embedded-agent-runner/run/internal-params.js"; +import type { RunEmbeddedAgentParams } from "./embedded-agent-runner/run/params.js"; import type { EmbeddedAgentRunResult } from "./embedded-agent-runner/types.js"; export type LocalTurnPlacementClaim = { @@ -9,7 +9,7 @@ export type LocalTurnPlacementClaim = { runId: string; }; -export type SessionPlacementTurnParams = RunEmbeddedAgentInternalParams & { sessionFile: string }; +export type SessionPlacementTurnParams = RunEmbeddedAgentParams & { sessionFile: string }; export type SessionPlacementAdmissionProvider = { executeLocalTurn: (claim: LocalTurnPlacementClaim, runLocal: () => Promise) => Promise; diff --git a/src/auto-reply/reply/agent-runner-cli-candidate.ts b/src/auto-reply/reply/agent-runner-cli-candidate.ts index c7fb785bb1af..5cf3bc39be72 100644 --- a/src/auto-reply/reply/agent-runner-cli-candidate.ts +++ b/src/auto-reply/reply/agent-runner-cli-candidate.ts @@ -1,4 +1,3 @@ -import { rebindAgentExecutionAttribution } from "../../agents/agent-execution-attribution.js"; import { resolveBootstrapWarningSignaturesSeen } from "../../agents/bootstrap-budget.js"; import type { BootstrapContextRunKind } from "../../agents/bootstrap-mode.js"; import type { RunCliAgentParams } from "../../agents/cli-runner/types.js"; @@ -16,11 +15,6 @@ import { import { withLocalSessionPlacementTurnAdmission } from "../../agents/session-placement-admission.js"; import { normalizeChatType } from "../../channels/chat-type.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; -import { - assertAgentRunLifecycleGenerationCurrent, - getAgentEventLifecycleGeneration, -} from "../../infra/agent-events.js"; -import { claimAgentRunContext, getAgentRunContext } from "../../infra/agent-run-registry.js"; import { getGeneratedMediaTaskIdsForSessionKey, hasNewGeneratedMediaTaskForSessionKey, @@ -66,8 +60,7 @@ export async function runCliFallbackCandidate(params: { candidateThinkLevel?: ThinkLevel; candidateFastMode: Pick; runId: string; - getLifecycleGeneration: () => string; - onLifecycleGeneration: (generation: string) => void; + lifecycleGeneration: string; runAbortSignal?: AbortSignal; runLane: RunCliAgentParams["lane"]; isFinalFallbackAttempt?: boolean; @@ -103,7 +96,7 @@ export async function runCliFallbackCandidate(params: { runId: params.runId, sessionKey: turn.sessionKey, startedAt: cliLifecycleStartedAt, - getLifecycleGeneration: params.getLifecycleGeneration, + getLifecycleGeneration: () => params.lifecycleGeneration, resolveTerminationFields: (error) => ({ ...resolveAgentRunErrorLifecycleFields(error, params.runAbortSignal), ...(isReplyOperationRestartAbort(turn.replyOperation) @@ -168,7 +161,6 @@ export async function runCliFallbackCandidate(params: { const bridgeCliDurableCommentary = Boolean(params.presentation.blockReplyHandler) && (turn.blockStreamingEnabled || turn.opts?.commentaryPayloadsEnabled === true); - const queuedLifecycleGeneration = params.getLifecycleGeneration(); const result = await params.timing.measure("cli_run", () => withLocalSessionPlacementTurnAdmission( { @@ -178,41 +170,12 @@ export async function runCliFallbackCandidate(params: { runId: params.runId, }, () => { - const lifecycleGeneration = getAgentEventLifecycleGeneration(); - // Background admission is tied to the gateway generation that queued it. - // Only foreground work may rebind after placement waits across a restart. - if (turn.isHeartbeat && lifecycleGeneration !== queuedLifecycleGeneration) { - assertAgentRunLifecycleGenerationCurrent(queuedLifecycleGeneration); - } // Admission may wait behind another turn that starts detached media. // Snapshot only after this turn owns the session placement. const mediaTaskIdsBefore = getGeneratedMediaTaskIdsForSessionKey(turn.sessionKey); - const attribution = - turn.attribution?.lifecycleGeneration === lifecycleGeneration - ? turn.attribution - : turn.attribution - ? rebindAgentExecutionAttribution(turn.attribution, lifecycleGeneration) - : undefined; - if (lifecycleGeneration !== params.getLifecycleGeneration()) { - params.onLifecycleGeneration(lifecycleGeneration); - } - if (attribution !== turn.attribution) { - turn.attribution = attribution; - } - const { registeredAt: _registeredAt, ...reboundRunContext } = - getAgentRunContext(params.runId) ?? {}; - claimAgentRunContext(params.runId, { - // Re-admission starts a new TTL window after placement waits or rotation. - ...reboundRunContext, - ...(attribution ? { attribution } : {}), - sessionKey: turn.sessionKey, - sessionId: turn.followupRun.run.sessionId, - agentId: turn.followupRun.run.agentId, - lifecycleGeneration, - }); return runCliAgentWithLifecycle({ runId: params.runId, - lifecycleGeneration, + lifecycleGeneration: params.lifecycleGeneration, provider: params.cliExecutionProvider, startedAt: cliLifecycleStartedAt, emitLifecycleTerminal: false, @@ -366,7 +329,6 @@ export async function runCliFallbackCandidate(params: { }) : undefined, runParams: { - ...(attribution ? { attribution } : {}), sessionId: turn.followupRun.run.sessionId, sessionKey: turn.sessionKey, chatType: @@ -411,7 +373,6 @@ export async function runCliFallbackCandidate(params: { timeoutMs: turn.followupRun.run.timeoutMs, runTimeoutOverrideMs: turn.followupRun.run.runTimeoutOverrideMs, runId: params.runId, - lifecycleGeneration, lane: params.runLane, extraSystemPrompt: turn.followupRun.run.extraSystemPrompt, sourceReplyDeliveryMode: turn.followupRun.run.sourceReplyDeliveryMode, diff --git a/src/auto-reply/reply/agent-runner-embedded-candidate.ts b/src/auto-reply/reply/agent-runner-embedded-candidate.ts index f06b33fe1403..4a0ad50fcffb 100644 --- a/src/auto-reply/reply/agent-runner-embedded-candidate.ts +++ b/src/auto-reply/reply/agent-runner-embedded-candidate.ts @@ -1,12 +1,8 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; import { resolveBootstrapWarningSignaturesSeen } from "../../agents/bootstrap-budget.js"; import type { BootstrapContextRunKind } from "../../agents/bootstrap-mode.js"; -import { runEmbeddedAgentInternal } from "../../agents/embedded-agent-runner/run-orchestrator.js"; -import type { - AgentExecutionAttributionInfo, - RunEmbeddedAgentInternalParams, -} from "../../agents/embedded-agent-runner/run/internal-params.js"; import type { RunEmbeddedAgentParams } from "../../agents/embedded-agent-runner/run/params.js"; +import { runEmbeddedAgent } from "../../agents/embedded-agent.js"; import type { FastModeAutoProgressState } from "../../agents/fast-mode.js"; import type { ContextEngineLogicalTurnLease } from "../../agents/harness/context-engine-logical-turn.js"; import { resolveAgentHarnessPolicy } from "../../agents/harness/policy.js"; @@ -87,7 +83,7 @@ export async function runEmbeddedFallbackCandidate(params: { ReturnType >; signalExecutionPhaseForTyping: NonNullable< - Parameters[0]["onExecutionPhase"] + Parameters[0]["onExecutionPhase"] >; notifyAgentRunStart: () => void; notifyUserAboutCompaction: boolean; @@ -99,7 +95,7 @@ export async function runEmbeddedFallbackCandidate(params: { onLifecycleBackstop: (backstop: AgentLifecycleTerminalBackstop) => void; onCompactionCount: (count: number) => void; }): Promise<{ - result: Awaited>; + result: Awaited>; bootstrapPromptWarningSignaturesSeen: string[]; }> { const turn = params.turn; @@ -197,11 +193,10 @@ export async function runEmbeddedFallbackCandidate(params: { sessionKey: turn.sessionKey, milestone: "before_embedded_run", }); - const result = await params.timing.measure("embedded_run", () => { - const embeddedRunParams: RunEmbeddedAgentInternalParams = { + const result = await params.timing.measure("embedded_run", () => + runEmbeddedAgent({ ...embeddedContext, messageActionTurnCapability, - attribution: turn.attribution, lifecycleGeneration: params.getLifecycleGeneration(), allowGatewaySubagentBinding: true, trigger: turn.isHeartbeat ? "heartbeat" : "user", @@ -260,11 +255,6 @@ export async function runEmbeddedFallbackCandidate(params: { params.onLifecycleGeneration(info.lifecycleGeneration); } }, - onExecutionAttributionChanged: (info: AgentExecutionAttributionInfo) => { - if (info?.attribution) { - turn.attribution = info.attribution; - } - }, onExecutionPhase: params.signalExecutionPhaseForTyping, onLaneWait: ({ waiting }) => { const replyOperation = turn.replyOperation; @@ -417,9 +407,8 @@ export async function runEmbeddedFallbackCandidate(params: { }; })() : undefined, - }; - return runEmbeddedAgentInternal(embeddedRunParams); - }); + }), + ); const resultCompactionCount = Math.max(0, result.meta?.agentMeta?.compactionCount ?? 0); attemptCompactionCount = Math.max(attemptCompactionCount, resultCompactionCount); return { diff --git a/src/auto-reply/reply/agent-runner-execution-contract.test.ts b/src/auto-reply/reply/agent-runner-execution-contract.test.ts index 57adaf3a37b4..517ac16b6f5a 100644 --- a/src/auto-reply/reply/agent-runner-execution-contract.test.ts +++ b/src/auto-reply/reply/agent-runner-execution-contract.test.ts @@ -1,5 +1,4 @@ import { describe, expect, it, vi } from "vitest"; -import { createAgentExecutionAttribution } from "../../agents/agent-execution-attribution.js"; import { createAgentRunRestartAbortError } from "../../agents/run-termination.js"; import { createMinimalRunAgentTurnParams, @@ -34,40 +33,6 @@ describe("executeAgentTurn contract", () => { }); }); - it("uses supplied attribution as the run-id authority", async () => { - state.runEmbeddedAgentMock.mockResolvedValue({ - payloads: [{ text: "done" }], - meta: {}, - }); - const attribution = createAgentExecutionAttribution({ - runId: "attributed-run", - lifecycleGeneration: "generation-1", - }); - - const result = await executeAgentTurn({ - ...createMinimalRunAgentTurnParams(), - attribution, - }); - - expect(result.runId).toBe("attributed-run"); - expect(state.runEmbeddedAgentMock.mock.calls[0]?.[0]?.attribution).toBe(attribution); - }); - - it("rejects conflicting flat and attributed run ids before execution", async () => { - const attribution = createAgentExecutionAttribution({ - runId: "attributed-run", - lifecycleGeneration: "generation-1", - }); - - await expect( - executeAgentTurn({ - ...createMinimalRunAgentTurnParams({ opts: { runId: "flat-run" } }), - attribution, - }), - ).rejects.toThrow("Agent turn attribution disagrees with opts.runId"); - expect(state.runEmbeddedAgentMock).not.toHaveBeenCalled(); - }); - it("retains a late completed result for accounting after user abort was accepted", async () => { state.runEmbeddedAgentMock.mockResolvedValue({ payloads: [{ text: "late reply" }], diff --git a/src/auto-reply/reply/agent-runner-execution-identity.test.ts b/src/auto-reply/reply/agent-runner-execution-identity.test.ts deleted file mode 100644 index c3e07cb7fe50..000000000000 --- a/src/auto-reply/reply/agent-runner-execution-identity.test.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { afterEach, describe, expect, it, vi } from "vitest"; -import { - configureExecutionIdentityAdmissionSink, - type ExecutionIdentityAdmissionWork, -} from "../../audit/execution-identity-admission.js"; -import { admitAutoReplyExecutionAttribution } from "./agent-runner-execution-identity.js"; - -describe("admitAutoReplyExecutionAttribution", () => { - let restoreSink: (() => void) | undefined; - - afterEach(() => { - restoreSink?.(); - restoreSink = undefined; - }); - - it("records exact channel and requester evidence with the runtime correlation", () => { - const work: ExecutionIdentityAdmissionWork[] = []; - restoreSink = configureExecutionIdentityAdmissionSink((item) => { - work.push(item); - return true; - }); - - const attribution = admitAutoReplyExecutionAttribution({ - config: { logging: { audit: { enabled: true, executionIdentity: true } } }, - lifecycleGeneration: "generation-1", - runId: "run-1", - context: { - accountId: "workspace-1", - agentId: "main", - channel: "slack", - chatId: "C123", - messageId: "M456", - senderId: "U789", - senderLabel: "Operator", - sessionId: "session-1", - sessionKey: "agent:main:main", - threadId: "T123", - isHeartbeat: false, - }, - }); - - expect(work).toHaveLength(1); - expect(work[0]).toMatchObject({ - kind: "capture", - envelope: { - contextId: attribution.contextId, - executionId: attribution.executionId, - runId: "run-1", - ingress: { kind: "channel", boundary: "auto-reply.channel" }, - invoker: { kind: "person", displayLabel: "Operator" }, - runtime: { kind: "embedded" }, - assurance: [{ kind: "channel-admission", strength: "boundary-verified" }], - }, - }); - expect(attribution).not.toHaveProperty("executionIdentityAdmission"); - }); - - it.each([ - { - label: "heartbeat", - ingressKind: "system", - context: { channel: "slack", isHeartbeat: true }, - }, - { - label: "internal system", - ingressKind: "system", - context: { - channel: "slack", - inputProvenance: { kind: "internal_system" as const, sourceTool: "test" }, - isHeartbeat: false, - }, - }, - { - label: "inter-session", - ingressKind: "subagent", - context: { - channel: "slack", - inputProvenance: { - kind: "inter_session" as const, - sourceSessionKey: "agent:worker:main", - }, - isHeartbeat: false, - }, - }, - ])("does not assert channel admission for $label ingress", ({ context, ingressKind }) => { - const work: ExecutionIdentityAdmissionWork[] = []; - restoreSink = configureExecutionIdentityAdmissionSink((item) => { - work.push(item); - return true; - }); - - admitAutoReplyExecutionAttribution({ - config: { logging: { audit: { enabled: true, executionIdentity: true } } }, - lifecycleGeneration: "generation-1", - runId: `run-${ingressKind}`, - context, - }); - - expect(work[0]).toMatchObject({ - kind: "capture", - envelope: { ingress: { kind: ingressKind } }, - }); - const assurance = work[0]?.kind === "capture" ? work[0].envelope.assurance : undefined; - expect(assurance?.some((item) => item.kind === "channel-admission")).toBe(false); - }); - - it("accepts long run ids without touching the disabled audit sink", () => { - const sink = vi.fn(() => true); - restoreSink = configureExecutionIdentityAdmissionSink(sink); - const runId = "r".repeat(1_024); - - const attribution = admitAutoReplyExecutionAttribution({ - config: {}, - lifecycleGeneration: "generation-1", - runId, - context: { isHeartbeat: false }, - }); - - expect(attribution.runId).toBe(runId); - expect(attribution).not.toHaveProperty("executionIdentityAdmission"); - expect(sink).not.toHaveBeenCalled(); - }); - - it("does not persist or replace an already admitted attribution", () => { - const sink = vi.fn(() => true); - restoreSink = configureExecutionIdentityAdmissionSink(sink); - const attribution = admitAutoReplyExecutionAttribution({ - config: {}, - lifecycleGeneration: "generation-1", - runId: "run-1", - context: { isHeartbeat: false }, - }); - - expect( - admitAutoReplyExecutionAttribution({ - attribution, - config: { logging: { audit: { enabled: true, executionIdentity: true } } }, - lifecycleGeneration: "generation-2", - runId: "run-1", - context: { isHeartbeat: false }, - }), - ).toBe(attribution); - expect(sink).not.toHaveBeenCalled(); - }); -}); diff --git a/src/auto-reply/reply/agent-runner-execution-identity.ts b/src/auto-reply/reply/agent-runner-execution-identity.ts deleted file mode 100644 index a4adaad22482..000000000000 --- a/src/auto-reply/reply/agent-runner-execution-identity.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; -import { - createAgentExecutionAttribution, - type AgentExecutionAttribution, -} from "../../agents/agent-execution-attribution.js"; -import { isExecutionIdentityCollectionEnabled } from "../../audit/audit-config.js"; -import { - enqueueExecutionIdentityContextAtAdmission, - type ExecutionIdentityAdmissionFacts, -} from "../../audit/execution-identity-admission.js"; -import type { OpenClawConfig } from "../../config/types.openclaw.js"; -import type { InputProvenance } from "../../sessions/input-provenance.js"; - -type AutoReplyExecutionIdentityContext = { - accountId?: string; - agentId?: string; - chatId?: string; - channel?: string; - inputProvenance?: InputProvenance; - isHeartbeat: boolean; - messageId?: string; - senderId?: string; - senderIsBot?: boolean; - senderLabel?: string; - sessionId?: string; - sessionKey?: string; - threadId?: string | number; -}; - -function encodeRawRef(parts: Record): string { - return JSON.stringify( - Object.fromEntries(Object.entries(parts).filter((entry) => entry[1] !== undefined)), - ); -} - -function resolveAdmissionFacts(params: { - context: AutoReplyExecutionIdentityContext; - runId: string; -}): ExecutionIdentityAdmissionFacts { - const context = params.context; - const channel = normalizeOptionalString(context.channel); - const senderId = normalizeOptionalString(context.senderId); - const provenance = context.inputProvenance; - const sourceRef = encodeRawRef({ - channel, - accountId: normalizeOptionalString(context.accountId), - chatId: normalizeOptionalString(context.chatId), - messageId: normalizeOptionalString(context.messageId), - threadId: - typeof context.threadId === "string" || typeof context.threadId === "number" - ? context.threadId - : undefined, - }); - const sourceAgent = normalizeOptionalString(provenance?.sourceSessionKey); - const isInterSession = provenance?.kind === "inter_session" && sourceAgent !== undefined; - const isSystem = context.isHeartbeat || provenance?.kind === "internal_system"; - const ingress: ExecutionIdentityAdmissionFacts["ingress"] = isInterSession - ? { - kind: "subagent", - boundary: "auto-reply.inter-session", - state: "present", - rawSourceRef: sourceRef, - } - : isSystem - ? { - kind: "system", - boundary: context.isHeartbeat ? "auto-reply.heartbeat" : "auto-reply.internal-system", - state: "present", - rawSourceRef: sourceRef, - } - : channel - ? { - kind: "channel", - boundary: "auto-reply.channel", - state: "present", - rawSourceRef: sourceRef, - } - : { - kind: "api", - boundary: "auto-reply.unknown", - state: "unknown", - }; - const invoker: ExecutionIdentityAdmissionFacts["invoker"] = isInterSession - ? { - kind: "agent", - rawPrincipalRef: sourceAgent, - } - : isSystem - ? { - kind: "system", - rawPrincipalRef: normalizeOptionalString(provenance?.sourceTool) ?? "openclaw", - } - : senderId - ? { - kind: context.senderIsBot ? "service" : "person", - rawPrincipalRef: encodeRawRef({ - channel, - accountId: normalizeOptionalString(context.accountId), - senderId, - }), - ...(normalizeOptionalString(context.senderLabel) - ? { displayLabel: normalizeOptionalString(context.senderLabel) } - : {}), - } - : undefined; - return { - runId: params.runId, - agentId: normalizeOptionalString(context.agentId) ?? "unknown", - ingress, - // Runtime identity names the OpenClaw admission owner/process, not a later - // model-fallback backend. Auto-reply and /btw are both embedded-owned. - runtime: { kind: "embedded" }, - ...(invoker ? { invoker } : {}), - ...(ingress.kind === "channel" && sourceRef !== "{}" - ? { - assurance: [ - { - kind: "channel-admission", - rawEvidenceRef: sourceRef, - strength: "boundary-verified", - }, - ], - } - : {}), - }; -} - -/** Allocate and optionally persist the exact identity for one admitted auto-reply turn. */ -export function admitAutoReplyExecutionAttribution(params: { - attribution?: AgentExecutionAttribution; - config: OpenClawConfig; - context: AutoReplyExecutionIdentityContext; - lifecycleGeneration: string; - runId: string; -}): AgentExecutionAttribution { - if (params.attribution) { - return params.attribution; - } - const attribution = createAgentExecutionAttribution({ - runId: params.runId, - lifecycleGeneration: params.lifecycleGeneration, - sessionKey: params.context.sessionKey, - sessionId: params.context.sessionId, - agentId: params.context.agentId, - }); - enqueueExecutionIdentityContextAtAdmission(resolveAdmissionFacts(params), { - enabled: isExecutionIdentityCollectionEnabled(params.config), - contextId: attribution.contextId, - executionId: attribution.executionId, - now: attribution.createdAt, - }); - return attribution; -} diff --git a/src/auto-reply/reply/agent-runner-execution-lifecycle.test.ts b/src/auto-reply/reply/agent-runner-execution-lifecycle.test.ts index d5050271c003..0efc644f68bb 100644 --- a/src/auto-reply/reply/agent-runner-execution-lifecycle.test.ts +++ b/src/auto-reply/reply/agent-runner-execution-lifecycle.test.ts @@ -601,29 +601,19 @@ describe("executeAgentTurn: run lifecycle and ownership", () => { }); const executeAgentTurn = await getExecuteAgentTurnForTest(); - const runPromise = executeAgentTurn( - createMinimalRunAgentTurnParams({ opts: { runId: "queued-turn-attribution" } }), - ); + const runPromise = executeAgentTurn(createMinimalRunAgentTurnParams()); expect(registerAgentRunContext).toHaveBeenCalledWith( - "queued-turn-attribution", + expect.any(String), expect.objectContaining({ sessionKey: "main", sessionId: "session", - attribution: expect.objectContaining({ - runId: "queued-turn-attribution", - sessionKey: "main", - sessionId: "session", - }), }), ); - const attribution = registerAgentRunContext.mock.calls[0]?.[1]?.attribution; - expect(Object.isFrozen(attribution)).toBe(true); expect(state.runWithModelFallbackMock).not.toHaveBeenCalled(); resolveImages?.(); await runPromise; - expect(state.runEmbeddedAgentMock.mock.calls[0]?.[0]?.attribution).toBe(attribution); }); it("clears run ownership when image preflight fails", async () => { diff --git a/src/auto-reply/reply/agent-runner-execution-runtime.test.ts b/src/auto-reply/reply/agent-runner-execution-runtime.test.ts index 4ef06c81f227..d394b0b0a615 100644 --- a/src/auto-reply/reply/agent-runner-execution-runtime.test.ts +++ b/src/auto-reply/reply/agent-runner-execution-runtime.test.ts @@ -1,12 +1,6 @@ import { describe, expect, it } from "vitest"; -import { createAgentExecutionAttribution } from "../../agents/agent-execution-attribution.js"; import { testing as cliBackendsTesting } from "../../agents/cli-backends.test-support.js"; -import { installSessionPlacementAdmissionProvider } from "../../agents/session-placement-admission.js"; import type { SessionEntry } from "../../config/sessions.js"; -import { - getAgentEventLifecycleGeneration, - rotateAgentEventLifecycleGeneration, -} from "../../infra/agent-events.js"; import type { TemplateContext } from "../templating.js"; import { setupAgentRunnerExecutionTestState, @@ -103,36 +97,6 @@ describe("executeAgentTurn: runtime selection", () => { }); }); - it("preserves one admission attribution across model fallback candidates", async () => { - state.runWithModelFallbackMock.mockImplementationOnce(async (params: FallbackRunnerParams) => { - await params.run("openai", "gpt-5.4"); - const result = await params.run("anthropic", "claude-opus-4-7"); - return { - result, - provider: "anthropic", - model: "claude-opus-4-7", - attempts: [], - }; - }); - state.runEmbeddedAgentMock - .mockResolvedValueOnce({ payloads: [{ text: "retry" }], meta: {} }) - .mockResolvedValueOnce({ payloads: [{ text: "final" }], meta: {} }); - - const executeAgentTurn = await getExecuteAgentTurnForTest(); - await executeAgentTurn( - createMinimalRunAgentTurnParams({ opts: { runId: "fallback-attribution" } }), - ); - - const firstAttribution = state.runEmbeddedAgentMock.mock.calls[0]?.[0]?.attribution; - expect(firstAttribution).toMatchObject({ - runId: "fallback-attribution", - sessionKey: "main", - sessionId: "session", - }); - expect(Object.isFrozen(firstAttribution)).toBe(true); - expect(state.runEmbeddedAgentMock.mock.calls[1]?.[0]?.attribution).toBe(firstAttribution); - }); - it("resolves CLI messageProvider from the live session surface when no origin channel is set", async () => { state.isCliProviderMock.mockReturnValue(true); state.runWithModelFallbackMock.mockImplementationOnce(async (params: FallbackRunnerParams) => ({ @@ -181,150 +145,6 @@ describe("executeAgentTurn: runtime selection", () => { }); }); - it("rebases direct CLI attribution after lifecycle rotation during preflight", async () => { - const agentRunRegistry = await import("../../infra/agent-run-registry.js"); - const runId = "cli-lifecycle-rebind-refreshes-registration"; - const staleRegisteredAt = 1; - agentRunRegistry.claimAgentRunContext(runId, { - lifecycleGeneration: getAgentEventLifecycleGeneration(), - registeredAt: staleRegisteredAt, - }); - state.isCliProviderMock.mockReturnValue(true); - let rotatedGeneration = ""; - state.runWithModelFallbackMock.mockImplementationOnce(async (params: FallbackRunnerParams) => { - rotatedGeneration = rotateAgentEventLifecycleGeneration(); - return { - result: await params.run("codex-cli", "gpt-5.4"), - provider: "codex-cli", - model: "gpt-5.4", - attempts: [], - }; - }); - let reboundContext: ReturnType; - state.runCliAgentMock.mockImplementationOnce(async () => { - reboundContext = agentRunRegistry.getAgentRunContext(runId); - return { - payloads: [{ text: "final" }], - meta: {}, - }; - }); - - const executeAgentTurn = await getExecuteAgentTurnForTest(); - const followupRun = createFollowupRun(); - followupRun.run.provider = "codex-cli"; - followupRun.run.model = "gpt-5.4"; - - await executeAgentTurn( - createMinimalRunAgentTurnParams({ - followupRun, - opts: { runId }, - }), - ); - - expectMockCallArgFields(state.runCliAgentMock, 0, "CLI run params", { - lifecycleGeneration: rotatedGeneration, - attribution: expect.objectContaining({ - lifecycleGeneration: rotatedGeneration, - }), - }); - expect(reboundContext).toEqual( - expect.objectContaining({ - lifecycleGeneration: rotatedGeneration, - registeredAt: expect.any(Number), - }), - ); - expect(reboundContext?.registeredAt).not.toBe(staleRegisteredAt); - agentRunRegistry.resetAgentRunRegistryForTest(); - }); - - it("preserves absent attribution identity while rebasing direct CLI execution", async () => { - state.isCliProviderMock.mockReturnValue(true); - let rotatedGeneration = ""; - state.runWithModelFallbackMock.mockImplementationOnce(async (params: FallbackRunnerParams) => { - rotatedGeneration = rotateAgentEventLifecycleGeneration(); - return { - result: await params.run("codex-cli", "gpt-5.4"), - provider: "codex-cli", - model: "gpt-5.4", - attempts: [], - }; - }); - state.runCliAgentMock.mockResolvedValueOnce({ - payloads: [{ text: "final" }], - meta: {}, - }); - const runId = "cli-sparse-attribution"; - const attribution = createAgentExecutionAttribution({ - runId, - lifecycleGeneration: getAgentEventLifecycleGeneration(), - }); - const executeAgentTurn = await getExecuteAgentTurnForTest(); - const followupRun = createFollowupRun(); - followupRun.run.provider = "codex-cli"; - followupRun.run.model = "gpt-5.4"; - - await executeAgentTurn({ - ...createMinimalRunAgentTurnParams({ followupRun, opts: { runId } }), - attribution, - }); - - const cliParams = requireRecord( - requireMockCall(state.runCliAgentMock, 0, "CLI run")[0], - "CLI run params", - ); - const cliAttribution = requireRecord(cliParams.attribution, "CLI run attribution"); - expect(cliAttribution).toEqual({ - ...attribution, - lifecycleGeneration: rotatedGeneration, - }); - expect(cliAttribution.executionId).toBe(attribution.executionId); - expect(cliAttribution.contextId).toBe(attribution.contextId); - expect(cliAttribution).not.toHaveProperty("sessionKey"); - expect(cliAttribution).not.toHaveProperty("sessionId"); - expect(cliAttribution).not.toHaveProperty("agentId"); - }); - - it("rejects queued heartbeat CLI fallback after placement crosses a lifecycle rotation", async () => { - state.isCliProviderMock.mockReturnValue(true); - state.runWithModelFallbackMock.mockImplementationOnce(async (params: FallbackRunnerParams) => ({ - result: await params.run("codex-cli", "gpt-5.4"), - provider: "codex-cli", - model: "gpt-5.4", - attempts: [], - })); - state.runCliAgentMock.mockResolvedValueOnce({ - payloads: [{ text: "must not run" }], - meta: {}, - }); - const uninstallPlacement = installSessionPlacementAdmissionProvider({ - executeLocalTurn: async (_claim, runLocal) => { - rotateAgentEventLifecycleGeneration(); - return await runLocal(); - }, - executeTurn: async (_claim, _params, runLocal) => await runLocal(), - }); - - try { - const executeAgentTurn = await getExecuteAgentTurnForTest(); - const followupRun = createFollowupRun(); - followupRun.run.provider = "codex-cli"; - followupRun.run.model = "gpt-5.4"; - const turn = createMinimalRunAgentTurnParams({ followupRun }); - turn.isHeartbeat = true; - - await expect(executeAgentTurn(turn)).resolves.toEqual({ - kind: "final", - payload: { - isError: true, - text: "⚠️ Heartbeat check failed before it could produce an update. The main chat session remains available.", - }, - }); - expect(state.runCliAgentMock).not.toHaveBeenCalled(); - } finally { - uninstallPlacement(); - } - }); - it("does not pass CLI runtime overrides as embedded harness ids for fallback providers", async () => { cliBackendsTesting.setDepsForTest({ resolveRuntimeCliBackends: () => [], diff --git a/src/auto-reply/reply/agent-runner-execution.test-support.ts b/src/auto-reply/reply/agent-runner-execution.test-support.ts index a02a6bf20db9..6f9428165f24 100644 --- a/src/auto-reply/reply/agent-runner-execution.test-support.ts +++ b/src/auto-reply/reply/agent-runner-execution.test-support.ts @@ -62,9 +62,6 @@ export function makeTestModel(id: string, contextTokens: number): ModelDefinitio vi.mock("../../agents/embedded-agent.js", () => ({ runEmbeddedAgent: (params: unknown) => state.runEmbeddedAgentMock(params), })); -vi.mock("../../agents/embedded-agent-runner/run-orchestrator.js", () => ({ - runEmbeddedAgentInternal: (params: unknown) => state.runEmbeddedAgentMock(params), -})); vi.mock("../../agents/embedded-agent-runner/run-entry.js", async () => { const actual = await vi.importActual< @@ -368,10 +365,6 @@ export type EmbeddedAgentParams = { transcriptPrompt?: string; lifecycleGeneration?: string; onExecutionStarted?: (info?: { lifecycleGeneration?: string }) => void; - onExecutionAttributionChanged?: (info: { - lifecycleGeneration?: string; - attribution?: import("../../agents/agent-execution-attribution.js").AgentExecutionAttribution; - }) => void; onExecutionPhase?: (info: { phase: | "runner_entered" diff --git a/src/auto-reply/reply/agent-runner-execution.ts b/src/auto-reply/reply/agent-runner-execution.ts index e8e0f49b4970..8ff75d9d437f 100644 --- a/src/auto-reply/reply/agent-runner-execution.ts +++ b/src/auto-reply/reply/agent-runner-execution.ts @@ -42,7 +42,6 @@ import { markOverloadRetryUnsafeToReplay, type OverloadRetryState, } from "./agent-runner-error-handler.js"; -import { admitAutoReplyExecutionAttribution } from "./agent-runner-execution-identity.js"; import type { AgentTurnExecutionResult, AgentTurnInternalResult, @@ -151,11 +150,9 @@ async function executeAgentTurnInternalWithRetryState( params.sessionCtx.Surface ?? params.sessionCtx.Provider, ); - let lifecycleGeneration = - params.attribution?.lifecycleGeneration ?? captureAgentRunLifecycleGeneration(runId); + let lifecycleGeneration = captureAgentRunLifecycleGeneration(runId); if (params.sessionKey) { registerAgentRunContext(runId, { - ...(params.attribution ? { attribution: params.attribution } : {}), sessionKey: params.sessionKey, ...(params.followupRun.run.sessionId ? { sessionId: params.followupRun.run.sessionId } : {}), agentId: params.followupRun.run.agentId, @@ -496,56 +493,11 @@ async function executeAgentTurnInternal( } } -function resolveAgentTurnRunId(params: AgentTurnParams): string { - const attributedRunId = params.attribution?.runId; - const requestedRunId = params.opts?.runId; - if (attributedRunId && requestedRunId && attributedRunId !== requestedRunId) { - throw new TypeError("Agent turn attribution disagrees with opts.runId"); - } - return attributedRunId ?? requestedRunId ?? crypto.randomUUID(); -} - /** Runs the agent turn with provider/model fallback, retry, and closed settlement. */ export async function executeAgentTurn(params: AgentTurnParams): Promise { - const runId = resolveAgentTurnRunId(params); - const baseExecutionParams = - params.opts?.runId === runId ? params : { ...params, opts: { ...params.opts, runId } }; - const lifecycleGeneration = captureAgentRunLifecycleGeneration(runId); - const attribution = admitAutoReplyExecutionAttribution({ - attribution: baseExecutionParams.attribution, - config: resolveQueuedReplyRuntimeConfig(baseExecutionParams.followupRun.run.config), - lifecycleGeneration, - runId, - context: { - accountId: - baseExecutionParams.followupRun.originatingAccountId ?? - baseExecutionParams.sessionCtx.AccountId, - agentId: baseExecutionParams.followupRun.run.agentId, - chatId: - baseExecutionParams.sessionCtx.ChatId ?? baseExecutionParams.sessionCtx.NativeChannelId, - channel: - baseExecutionParams.followupRun.originatingChannel ?? - baseExecutionParams.sessionCtx.Surface ?? - baseExecutionParams.sessionCtx.Provider, - inputProvenance: baseExecutionParams.sessionCtx.InputProvenance, - isHeartbeat: baseExecutionParams.isHeartbeat, - messageId: - baseExecutionParams.sessionCtx.MessageSidFull ?? baseExecutionParams.sessionCtx.MessageSid, - senderId: baseExecutionParams.sessionCtx.SenderId, - senderIsBot: baseExecutionParams.sessionCtx.SenderIsBot, - senderLabel: - baseExecutionParams.sessionCtx.SenderName ?? baseExecutionParams.sessionCtx.SenderUsername, - sessionId: baseExecutionParams.followupRun.run.sessionId, - sessionKey: baseExecutionParams.sessionKey, - threadId: - baseExecutionParams.followupRun.originatingThreadId ?? - baseExecutionParams.sessionCtx.MessageThreadId, - }, - }); + const runId = params.opts?.runId ?? crypto.randomUUID(); const executionParams = - baseExecutionParams.attribution === attribution - ? baseExecutionParams - : { ...baseExecutionParams, attribution }; + params.opts?.runId === runId ? params : { ...params, opts: { ...params.opts, runId } }; // Gateway writes require exact view identity against this bare session runtime; // requester-scoped and combined runtimes cannot cross the App view boundary. const runtime = executionParams.isHeartbeat @@ -578,6 +530,7 @@ export async function executeAgentTurn(params: AgentTurnParams): Promise { try { diff --git a/src/auto-reply/reply/agent-runner-execution.types.ts b/src/auto-reply/reply/agent-runner-execution.types.ts index 539e0b484c50..a058614defe5 100644 --- a/src/auto-reply/reply/agent-runner-execution.types.ts +++ b/src/auto-reply/reply/agent-runner-execution.types.ts @@ -1,4 +1,3 @@ -import type { AgentExecutionAttribution } from "../../agents/agent-execution-attribution.js"; import type { runEmbeddedAgent } from "../../agents/embedded-agent.js"; import type { SessionEntry } from "../../config/sessions.js"; import type { TemplateContext } from "../templating.js"; @@ -74,8 +73,6 @@ export type AgentTurnExecutionResult = { /** Inputs shared by direct and queued agent-turn execution. */ export type AgentTurnParams = { - /** Admission-owned execution correlation; never persisted in the queued run. */ - attribution?: AgentExecutionAttribution; commandBody: string; transcriptCommandBody?: string; followupRun: FollowupRun; diff --git a/src/auto-reply/reply/agent-runner-fallback-candidate.ts b/src/auto-reply/reply/agent-runner-fallback-candidate.ts index b145e1f59bd5..ddcf47147371 100644 --- a/src/auto-reply/reply/agent-runner-fallback-candidate.ts +++ b/src/auto-reply/reply/agent-runner-fallback-candidate.ts @@ -233,10 +233,7 @@ export async function runAgentFallbackCandidates(params: AgentFallbackCycleParam const candidate = await runCliFallbackCandidate({ ...common, cliExecutionProvider: runtime.cliExecutionProvider, - getLifecycleGeneration: () => params.state.lifecycleGeneration, - onLifecycleGeneration: (generation) => { - params.state.lifecycleGeneration = generation; - }, + lifecycleGeneration: params.state.lifecycleGeneration, runLane, }); params.state.bootstrapPromptWarningSignaturesSeen = diff --git a/src/auto-reply/reply/agent-runner.media-paths.test.ts b/src/auto-reply/reply/agent-runner.media-paths.test.ts index ca90e4383bfc..ee51e3619231 100644 --- a/src/auto-reply/reply/agent-runner.media-paths.test.ts +++ b/src/auto-reply/reply/agent-runner.media-paths.test.ts @@ -119,10 +119,6 @@ vi.mock("../../agents/embedded-agent.js", () => ({ waitForEmbeddedAgentRunEnd: waitForEmbeddedAgentRunEndMock, })); -vi.mock("../../agents/embedded-agent-runner/run-orchestrator.js", () => ({ - runEmbeddedAgentInternal: runEmbeddedAgentMock, -})); - vi.mock("../../agents/embedded-agent-runner/runs.js", () => ({ formatEmbeddedAgentQueueFailureSummary: (outcome: { reason?: string; sessionId?: string }) => outcome.reason && outcome.sessionId diff --git a/src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts b/src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts index 687350be153c..7d43670db5d6 100644 --- a/src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts +++ b/src/auto-reply/reply/agent-runner.misc.runreplyagent.test.ts @@ -121,10 +121,6 @@ vi.mock("../../agents/embedded-agent.js", () => { }; }); -vi.mock("../../agents/embedded-agent-runner/run-orchestrator.js", () => ({ - runEmbeddedAgentInternal: (params: unknown) => runEmbeddedAgentMock(params), -})); - vi.mock("../../agents/cli-runner.js", () => ({ runCliAgent: (...args: unknown[]) => runCliAgentMock(...args), })); diff --git a/src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts b/src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts index 55f5b0d1fa7a..3b5b31e49e3c 100644 --- a/src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts +++ b/src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts @@ -228,10 +228,6 @@ vi.mock("../../agents/embedded-agent.js", () => ({ runEmbeddedAgent: (params: unknown) => state.runEmbeddedAgentMock(params), })); -vi.mock("../../agents/embedded-agent-runner/run-orchestrator.js", () => ({ - runEmbeddedAgentInternal: (params: unknown) => state.runEmbeddedAgentMock(params), -})); - vi.mock("../../channels/plugins/index.js", async (importOriginal) => ({ ...(await importOriginal()), getChannelPlugin: (channel: unknown) => state.getChannelPluginMock(channel), diff --git a/src/auto-reply/reply/commands-btw.test.ts b/src/auto-reply/reply/commands-btw.test.ts index 23f0b4c79cce..24f82e0a1730 100644 --- a/src/auto-reply/reply/commands-btw.test.ts +++ b/src/auto-reply/reply/commands-btw.test.ts @@ -180,14 +180,6 @@ describe("handleBtwCommand", () => { expect(String(runnerArgs.agentDir)).toContain("/agents/main/agent"); expect(runnerArgs.messageActionTurnCapability).toEqual(expect.any(String)); expect(runnerArgs.opts).toMatchObject({ runId: expect.any(String) }); - const runnerAttribution = runnerArgs.attribution as Record; - expect(Object.isFrozen(runnerAttribution)).toBe(true); - expect(runnerAttribution).toMatchObject({ - runId: (runnerArgs.opts as { runId?: string }).runId, - sessionKey: "agent:main:main", - sessionId: "session-1", - agentId: "main", - }); expect(resolvedTurnContext).toMatchObject({ requesterAccountId: "account-1", requesterSenderId: "sender-1", diff --git a/src/auto-reply/reply/commands-btw.ts b/src/auto-reply/reply/commands-btw.ts index cbc20d4946c7..80882675f608 100644 --- a/src/auto-reply/reply/commands-btw.ts +++ b/src/auto-reply/reply/commands-btw.ts @@ -10,8 +10,6 @@ import { mintMessageActionTurnCapability, revokeMessageActionTurnCapability, } from "../../gateway/message-action-turn-capability.js"; -import { captureAgentRunLifecycleGeneration } from "../../infra/agent-events.js"; -import { admitAutoReplyExecutionAttribution } from "./agent-runner-execution-identity.js"; import { extractBtwQuestion } from "./btw-command.js"; import { commandReply, defineAuthorizedTextCommand } from "./command-gates.js"; import type { CommandHandler } from "./commands-types.js"; @@ -54,26 +52,6 @@ export const handleBtwCommand: CommandHandler = defineAuthorizedTextCommand( const chatType = normalizeChatType(params.ctx.ChatType); const groupId = resolveGroupSessionKey(params.ctx)?.id ?? targetSessionEntry.groupId; const runId = params.opts?.runId ?? `btw-${randomUUID()}`; - const attribution = admitAutoReplyExecutionAttribution({ - config: params.cfg, - lifecycleGeneration: captureAgentRunLifecycleGeneration(runId), - runId, - context: { - accountId: params.ctx.AccountId, - agentId: sessionAgentId, - chatId: nativeChannelId, - channel: params.command.channel || params.ctx.Surface || params.ctx.Provider, - inputProvenance: params.ctx.InputProvenance, - isHeartbeat: false, - messageId: params.ctx.MessageSidFull ?? params.ctx.MessageSid, - senderId: params.ctx.SenderId ?? params.command.senderId, - senderIsBot: params.ctx.SenderIsBot, - senderLabel: params.ctx.SenderName ?? params.ctx.SenderUsername, - sessionId: targetSessionEntry.sessionId, - sessionKey: params.sessionKey, - threadId: params.ctx.MessageThreadId ?? params.ctx.TransportThreadId, - }, - }); const currentChannelProvider = normalizeAnyChannelId(params.ctx.Provider); const capabilitySessionKey = params.ctx.RuntimePolicySessionKey ?? params.sessionKey; const messageActionTurnCapability = @@ -101,7 +79,6 @@ export const handleBtwCommand: CommandHandler = defineAuthorizedTextCommand( let reply: Awaited>; try { reply = await runBtwSideQuestion({ - attribution, cfg: params.cfg, agentDir, provider: params.provider, diff --git a/src/commands/agent.test.ts b/src/commands/agent.test.ts index ef88393dd3d1..49e5be554610 100644 --- a/src/commands/agent.test.ts +++ b/src/commands/agent.test.ts @@ -451,7 +451,7 @@ describe("agentCommand", () => { ).rejects.toThrow("allowModelOverride must be explicitly set for ingress agent runs."); }); - it("replaces private execution attribution on runtime-shaped public ingress", async () => { + it("strips private execution attribution from runtime-shaped public ingress", async () => { await withTempHome(async (home) => { const store = path.join(home, "sessions.json"); mockConfig(home, store); @@ -491,11 +491,9 @@ describe("agentCommand", () => { runtime, ); - const recordedAttribution = record.mock.calls[0]?.[0].attribution; - expect(recordedAttribution).toMatchObject({ runId: "public-ingress-run" }); - expect(recordedAttribution?.contextId).not.toBe("inherited-context"); - expect(recordedAttribution?.contextId).not.toBe("forged-context"); - expect(recordedAttribution).not.toHaveProperty("executionIdentityAdmission"); + expect(record).toHaveBeenCalledWith( + expect.objectContaining({ attribution: undefined, runId: "public-ingress-run" }), + ); } finally { record.mockRestore(); if (priorDescriptor) { diff --git a/src/gateway/server-methods/agent.events-and-subagents.test-utils.ts b/src/gateway/server-methods/agent.events-and-subagents.test-utils.ts index 211a99c46079..af33c64d1e8d 100644 --- a/src/gateway/server-methods/agent.events-and-subagents.test-utils.ts +++ b/src/gateway/server-methods/agent.events-and-subagents.test-utils.ts @@ -294,7 +294,6 @@ describe("gateway agent handler", () => { ); const callArgs = await waitForAgentCommandCall<{ - executionAttribution?: Record; sessionEffects?: string; suppressPromptPersistence?: boolean; }>(); @@ -323,7 +322,6 @@ describe("gateway agent handler", () => { lifecycleGeneration: "test-generation", }); expect(Object.isFrozen(runContext.attribution)).toBe(true); - expect(callArgs.executionAttribution).toBe(runContext.attribution); }); it("preserves the admitted idempotency key exactly in execution attribution", async () => { diff --git a/src/gateway/worker-environments/worker-turn-launcher.test.ts b/src/gateway/worker-environments/worker-turn-launcher.test.ts index ce4e510ee6cc..291fb7afb2ea 100644 --- a/src/gateway/worker-environments/worker-turn-launcher.test.ts +++ b/src/gateway/worker-environments/worker-turn-launcher.test.ts @@ -3,7 +3,6 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { createAgentExecutionAttribution } from "../../agents/agent-execution-attribution.js"; import { createEmbeddedRunLaneController } from "../../agents/embedded-agent-runner/run/lane-controller.js"; import { installSessionPlacementAdmissionProvider } from "../../agents/session-placement-admission.js"; import { SessionManager } from "../../agents/sessions/session-manager.js"; @@ -887,15 +886,6 @@ describe("worker turn launcher", () => { destroy: vi.fn(async () => attachedEnvironment()), }; const provider = createWorkerSessionTurnPlacementProvider({ environments, placements }); - const attribution = createAgentExecutionAttribution({ - runId: "run-persisted-user", - lifecycleGeneration: "worker-generation", - sessionKey: SESSION_KEY, - sessionId: SESSION_ID, - agentId: "main", - }); - const onExecutionStarted = vi.fn(); - const onExecutionAttributionChanged = vi.fn(); await provider.executeTurn( { @@ -906,22 +896,11 @@ describe("worker turn launcher", () => { }, { ...turn("run-persisted-user"), - attribution, - lifecycleGeneration: "worker-generation", - onExecutionStarted, - onExecutionAttributionChanged, suppressNextUserMessagePersistence: true, }, async () => ({ meta: { durationMs: 1 } }), ); - expect(onExecutionStarted).toHaveBeenCalledWith({ - lifecycleGeneration: "worker-generation", - }); - expect(onExecutionAttributionChanged).toHaveBeenCalledWith({ - lifecycleGeneration: "worker-generation", - attribution, - }); expect(descriptor?.assignment.prompt).toBe("Inspect this workspace"); expect(descriptor?.assignment.initialMessages).toMatchObject([ { role: "user" }, diff --git a/src/gateway/worker-environments/worker-turn-launcher.ts b/src/gateway/worker-environments/worker-turn-launcher.ts index 4253337844cd..46c892cb263b 100644 --- a/src/gateway/worker-environments/worker-turn-launcher.ts +++ b/src/gateway/worker-environments/worker-turn-launcher.ts @@ -236,10 +236,6 @@ async function executeWorkerTurn(params: { const startedAt = Date.now(); turn.onExecutionStarted?.({ lifecycleGeneration: turn.lifecycleGeneration }); - turn.onExecutionAttributionChanged?.({ - lifecycleGeneration: turn.lifecycleGeneration, - attribution: turn.attribution, - }); turn.onExecutionPhase?.({ phase: "runner_entered", backend: "cloud-worker" }); const transcriptTarget = resolveWorkerTurnTranscriptTarget(turn); const manager = SessionManager.open(transcriptTarget); diff --git a/test/vitest/vitest.unit-fast-paths.mjs b/test/vitest/vitest.unit-fast-paths.mjs index fe546eb3a845..8327850a42b0 100644 --- a/test/vitest/vitest.unit-fast-paths.mjs +++ b/test/vitest/vitest.unit-fast-paths.mjs @@ -85,7 +85,6 @@ export const forcedUnitFastTestFiles = [ "src/acp/translator.session-setup.test.ts", "src/acp/translator.session-snapshot.test.ts", "src/acp/translator.tool-streaming.test.ts", - "src/auto-reply/reply/agent-runner-execution-runtime.test.ts", "src/browser-lifecycle-cleanup.test.ts", "extensions/canvas/src/host/server.test.ts", "src/system-agent/audit.test.ts",