


























@@ -15,6 +15,7 @@ import {
1515formatEmbeddedAgentQueueFailureSummary,
1616queueEmbeddedAgentMessageWithOutcomeAsync,
1717} from "../../agents/embedded-agent-runner/runs.js";
18+import { resolveFastModeState } from "../../agents/fast-mode.js";
1819import { resolveModelAuthMode } from "../../agents/model-auth.js";
1920import { isCliProvider } from "../../agents/model-selection.js";
2021import { deriveContextPromptTokens, hasNonzeroUsage, normalizeUsage } from "../../agents/usage.js";
@@ -39,6 +40,8 @@ import {
3940freezeDiagnosticTraceContext,
4041} from "../../infra/diagnostic-trace-context.js";
4142import { measureDiagnosticsTimelineSpan } from "../../infra/diagnostics-timeline.js";
43+import { getProviderUsageLimitsCached } from "../../infra/provider-usage.limits.js";
44+import { resolveAgentIdentity } from "../../agents/identity.js";
4245import { enqueueSystemEvent } from "../../infra/system-events.js";
4346import { CommandLaneClearedError, GatewayDrainingError } from "../../process/command-queue.js";
4447import { shouldPreserveUserFacingSessionStateForInputProvenance } from "../../sessions/input-provenance.js";
@@ -117,6 +120,7 @@ import { createReplyMediaContext } from "./reply-media-paths.js";
117120import { replyRunRegistry, type ReplyOperation } from "./reply-run-registry.js";
118121import { createReplyToModeFilterForChannel, resolveReplyToMode } from "./reply-threading.js";
119122import { admitReplyTurn, resolveReplyTurnKind } from "./reply-turn-admission.js";
123+import { recordReplyUsageState } from "./reply-usage-state.js";
120124import { resolveRoutedDeliveryThreadId } from "./routed-delivery-thread.js";
121125import { incrementRunCompactionCount, persistRunSessionUsage } from "./session-run-accounting.js";
122126import { resolveSourceReplyVisibilityPolicy } from "./source-reply-delivery-mode.js";
@@ -1735,6 +1739,74 @@ export async function runReplyAgent(params: {
17351739const modelUsed = runResult.meta?.agentMeta?.model ?? fallbackModel ?? defaultModel;
17361740const providerUsed =
17371741runResult.meta?.agentMeta?.provider ?? fallbackProvider ?? followupRun.run.provider;
1742+1743+// Hand the turn's execution state to the reply_payload_sending hook (harness-
1744+// agnostic: every harness produces runResult.meta). A footer/readout plugin
1745+// reads it at deliver time, correlated by runId/sessionKey.
1746+{
1747+const winnerProvider = runResult.meta?.executionTrace?.winnerProvider ?? providerUsed;
1748+const winnerModel = runResult.meta?.executionTrace?.winnerModel ?? modelUsed;
1749+const ctxTokens = runResult.meta?.agentMeta?.contextTokens;
1750+const compactions = runResult.meta?.agentMeta?.compactionCount;
1751+recordReplyUsageState(
1752+{ runId, sessionKey },
1753+{
1754+provider: providerUsed,
1755+model: modelUsed,
1756+resolvedRef:
1757+winnerProvider && winnerModel ? `${winnerProvider}/${winnerModel}` : undefined,
1758+reasoningEffort:
1759+typeof followupRun.run.thinkLevel === "string" ? followupRun.run.thinkLevel : undefined,
1760+fastMode: resolveFastModeState({
1761+ cfg,
1762+provider: providerUsed ?? "",
1763+model: modelUsed ?? "",
1764+agentId: followupRun.run.agentId,
1765+sessionEntry: activeSessionEntry,
1766+}).enabled,
1767+fallbackUsed: runResult.meta?.executionTrace?.fallbackUsed === true,
1768+// Richer per-turn atoms for usage rendering (/usage + plugins).
1769+agentId: followupRun.run.agentId,
1770+sessionId: followupRun.run.sessionId,
1771+chatType: typeof sessionCtx.ChatType === "string" ? sessionCtx.ChatType : undefined,
1772+authMode: runResult.meta?.requestShaping?.authMode ?? undefined,
1773+overrideSource: activeSessionEntry?.modelOverrideSource ?? undefined,
1774+requested:
1775+followupRun.run.provider && followupRun.run.model
1776+ ? `${followupRun.run.provider}/${followupRun.run.model}`
1777+ : undefined,
1778+turnUsd: usage
1779+ ? estimateUsageCost({
1780+ usage,
1781+cost: resolveModelCostConfig({
1782+provider: providerUsed,
1783+model: modelUsed,
1784+config: cfg,
1785+}),
1786+})
1787+ : undefined,
1788+durationMs: Date.now() - runStartedAt,
1789+identity: resolveAgentIdentity(cfg, followupRun.run.agentId),
1790+compactionCount: typeof compactions === "number" ? compactions : undefined,
1791+contextTokenBudget:
1792+typeof ctxTokens === "number" && Number.isFinite(ctxTokens) ? ctxTokens : undefined,
1793+usage: usage
1794+ ? {
1795+input: usage.input,
1796+output: usage.output,
1797+cacheRead: usage.cacheRead,
1798+cacheWrite: usage.cacheWrite,
1799+total: usage.total,
1800+}
1801+ : undefined,
1802+// Provider subscription/limit windows for the 📊 readout. Non-blocking
1803+// (stale-while-revalidate): returns cached windows or undefined on a
1804+// cold cache and refreshes in the background, so it never delays the
1805+// reply. Undefined for api-key / unmapped providers.
1806+limits: getProviderUsageLimitsCached(providerUsed),
1807+},
1808+);
1809+}
17381810const verboseEnabled = resolvedVerboseLevel !== "off";
17391811const preserveUserFacingSessionState = shouldPreserveUserFacingSessionStateForInputProvenance(
17401812followupRun.run.inputProvenance,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。