From b4a0fc5c57ccab5906f8f6499835aecfee18dd9c Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 12 Jul 2026 10:21:31 +0100 Subject: [PATCH] perf(agents): reduce repeated turn setup latency (#105220) * perf(agents): reuse prepared auth route models * chore: leave release notes to release automation --- .../run.overflow-compaction.test.ts | 7 +--- src/agents/embedded-agent-runner/run.ts | 42 ++++++++++++++++++- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/agents/embedded-agent-runner/run.overflow-compaction.test.ts b/src/agents/embedded-agent-runner/run.overflow-compaction.test.ts index 30ed78f05717..77a20cd34d57 100644 --- a/src/agents/embedded-agent-runner/run.overflow-compaction.test.ts +++ b/src/agents/embedded-agent-runner/run.overflow-compaction.test.ts @@ -1922,6 +1922,7 @@ describe("runEmbeddedAgent overflow compaction trigger routing", () => { } expect(mockedGetApiKeyForModel).toHaveBeenCalledTimes(1); + expect(mockedResolveModelAsync).toHaveBeenCalledTimes(1); expect(mockedBuildAgentRuntimePlan).toHaveBeenCalledTimes(1); expect(authStorage.setRuntimeApiKey).toHaveBeenCalledTimes(1); const pluginParams = expectMockCallFields(pluginRunAttempt, { @@ -2840,11 +2841,6 @@ describe("runEmbeddedAgent overflow compaction trigger routing", () => { baseUrl: "https://api.openai.com/v1", authStorage, }); - queueOpenAIResolvedModel({ - api: "openai-responses", - baseUrl: "https://api.openai.com/v1", - authStorage, - }); queueOpenAIResolvedModel({ api: "openai-chatgpt-responses", baseUrl: "https://chatgpt.com/backend-api/codex", @@ -2906,6 +2902,7 @@ describe("runEmbeddedAgent overflow compaction trigger routing", () => { } expect(mockedGetApiKeyForModel).toHaveBeenCalledOnce(); + expect(mockedResolveModelAsync).toHaveBeenCalledTimes(3); expect(pluginRunAttempt).toHaveBeenCalledTimes(2); const firstAttempt = mockCallArg(pluginRunAttempt) as EmbeddedRunAttemptParams; const secondAttempt = mockCallArg(pluginRunAttempt, 1) as EmbeddedRunAttemptParams; diff --git a/src/agents/embedded-agent-runner/run.ts b/src/agents/embedded-agent-runner/run.ts index 550044f784e5..5a61819d0307 100644 --- a/src/agents/embedded-agent-runner/run.ts +++ b/src/agents/embedded-agent-runner/run.ts @@ -1495,6 +1495,7 @@ async function runEmbeddedAgentInternal( agentHarness = selectHarnessForModel(effectiveModel); pluginHarnessOwnsTransport = agentHarness.id !== "openclaw"; + const authStages = log.isEnabled("trace") ? createEmbeddedRunStageTracker() : undefined; const usesOpenAIAuthRouting = provider === OPENAI_PROVIDER_ID; const openClawNativeCodexResponsesNeedsAuthBootstrap = !pluginHarnessOwnsTransport && @@ -1532,6 +1533,7 @@ async function runEmbeddedAgentInternal( params.authProfileIdSource === "user" ? params.authProfileId : undefined, }); } + authStages?.mark("scope"); const attemptAuthProfileStore = usesOpenAIAuthRouting ? ensureAuthProfileStore(agentDir, { externalCliProviderIds: [OPENAI_PROVIDER_ID], @@ -1550,6 +1552,7 @@ async function runEmbeddedAgentInternal( ensureAuthProfileStoreWithoutExternalProfiles(agentDir, { allowKeychainPrompt: false, })); + authStages?.mark("store"); const requestedProfileId = params.authProfileId?.trim() || undefined; const lockedProfileId = params.authProfileIdSource === "user" ? requestedProfileId : undefined; @@ -1586,12 +1589,19 @@ async function runEmbeddedAgentInternal( }), }); - const materializeAuthPlan = async (plan: AgentRuntimeAuthPlan) => { + const materializedRouteModels = new WeakMap< + AgentRuntimeAuthPlan, + Promise + >(); + const materializeAuthPlanUncached = async (plan: AgentRuntimeAuthPlan) => { // Native harness sessions own their model tuple. Route preparation may // attest auth/transport, but must not rediscover or replace that model. if (nativeModelOwned) { return runtimeModel; } + const requiresCredentialScopedResolve = Boolean( + plan.modelRoute && (plan.forwardedAuthProfileId || params.authProfileId), + ); return ( (await materializePreparedRuntimeModel({ plan, @@ -1599,7 +1609,9 @@ async function runEmbeddedAgentInternal( modelId, config: params.config, model: runtimeModel, - forceResolve: Boolean(plan.modelRoute), + // Unscoped direct auth cannot change credential-scoped metadata. + // Reuse an already matching tuple; route mismatches still resolve. + forceResolve: requiresCredentialScopedResolve, resolveModel: ({ config, authProfileId, authProfileMode }) => resolveModelAsync(provider, modelId, agentDir, config, { authStorage, @@ -1614,10 +1626,25 @@ async function runEmbeddedAgentInternal( })) ?? runtimeModel ); }; + const materializeAuthPlan = (plan: AgentRuntimeAuthPlan) => { + if (!plan.modelRoute) { + return materializeAuthPlanUncached(plan); + } + const cached = materializedRouteModels.get(plan); + if (cached) { + return cached; + } + // Prepared plans are immutable within one run. Carry their exact model + // tuple into auth initialization instead of repeating provider discovery. + const materialized = materializeAuthPlanUncached(plan); + materializedRouteModels.set(plan, materialized); + return materialized; + }; let resolvedAuthPreparation = createAuthPreparation(); let preparedAuthAttempts = resolvedAuthPreparation.attempts; let activePreparedAuthPlan = resolvedAuthPreparation.plan; applyResolvedRuntimeModel(await materializeAuthPlan(activePreparedAuthPlan)); + authStages?.mark("prepare-plan"); const finalizedHarness = selectHarnessForPreparedAttempts( effectiveModel, @@ -1640,6 +1667,7 @@ async function runEmbeddedAgentInternal( ); } } + authStages?.mark("harness"); // A selected plugin harness owns context pressure with its native transcript, // even if it cannot expose manual compaction. Generic recovery is OpenClaw-only. const genericCompactionRecoveryAllowed = !pluginHarnessOwnsTransport; @@ -1851,6 +1879,7 @@ async function runEmbeddedAgentInternal( }, log, }); + authStages?.mark("controller"); const advancePluginHarnessAuthAttempt = async (): Promise => { if (!pluginHarnessOwnsTransport || lockedProfileId) { return false; @@ -1951,6 +1980,15 @@ async function runEmbeddedAgentInternal( lastProfileId = forwardedPluginHarnessProfileId; } } + authStages?.mark("initialize"); + if (authStages) { + log.trace( + formatEmbeddedRunStageSummary( + `[trace:embedded-run] auth stages: runId=${params.runId} sessionId=${params.sessionId} phase=auth`, + authStages.snapshot(), + ), + ); + } startupStages.mark("auth"); notifyExecutionPhase("auth", { provider, model: modelId }); const resolveRunAttemptAuthProfileStore = (): AuthProfileStore => {