mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 21:14:31 +00:00
agents: preserve totalTokens on request failure instead of using contextWindow (#34275)
Merged via squash.
Prepared head SHA: f9d111d0a7
Co-authored-by: RealKai42 <44634134+RealKai42@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
This commit is contained in:
@@ -16,6 +16,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
|
- Agents/session usage tracking: preserve accumulated usage metadata on embedded Pi runner error exits so failed turns still update session `totalTokens` from real usage instead of stale prior values. (#34275) thanks @RealKai42.
|
||||||
- Nodes/system.run approval hardening: use explicit argv-mutation signaling when regenerating prepared `rawCommand`, and cover the `system.run.prepare -> system.run` handoff so direct PATH-based `nodes.run` commands no longer fail with `rawCommand does not match command`. (#33137) thanks @Sid-Qin.
|
- Nodes/system.run approval hardening: use explicit argv-mutation signaling when regenerating prepared `rawCommand`, and cover the `system.run.prepare -> system.run` handoff so direct PATH-based `nodes.run` commands no longer fail with `rawCommand does not match command`. (#33137) thanks @Sid-Qin.
|
||||||
- Models/custom provider headers: propagate `models.providers.<name>.headers` across inline, fallback, and registry-found model resolution so header-authenticated proxies consistently receive configured request headers. (#27490) thanks @Sid-Qin.
|
- Models/custom provider headers: propagate `models.providers.<name>.headers` across inline, fallback, and registry-found model resolution so header-authenticated proxies consistently receive configured request headers. (#27490) thanks @Sid-Qin.
|
||||||
- Ollama/custom provider headers: forward resolved model headers into native Ollama stream requests so header-authenticated Ollama proxies receive configured request headers. (#24337) thanks @echoVic.
|
- Ollama/custom provider headers: forward resolved model headers into native Ollama stream requests so header-authenticated Ollama proxies receive configured request headers. (#24337) thanks @echoVic.
|
||||||
|
|||||||
@@ -200,6 +200,43 @@ function resolveActiveErrorContext(params: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build agentMeta for error return paths, preserving accumulated usage so that
|
||||||
|
* session totalTokens reflects the actual context size rather than going stale.
|
||||||
|
* Without this, error returns omit usage and the session keeps whatever
|
||||||
|
* totalTokens was set by the previous successful run.
|
||||||
|
*/
|
||||||
|
function buildErrorAgentMeta(params: {
|
||||||
|
sessionId: string;
|
||||||
|
provider: string;
|
||||||
|
model: string;
|
||||||
|
usageAccumulator: UsageAccumulator;
|
||||||
|
lastRunPromptUsage: ReturnType<typeof normalizeUsage> | undefined;
|
||||||
|
lastAssistant?: { usage?: unknown } | null;
|
||||||
|
/** API-reported total from the most recent call, mirroring the success path correction. */
|
||||||
|
lastTurnTotal?: number;
|
||||||
|
}): EmbeddedPiAgentMeta {
|
||||||
|
const usage = toNormalizedUsage(params.usageAccumulator);
|
||||||
|
// Apply the same lastTurnTotal correction the success path uses so
|
||||||
|
// usage.total reflects the API-reported context size, not accumulated totals.
|
||||||
|
if (usage && params.lastTurnTotal && params.lastTurnTotal > 0) {
|
||||||
|
usage.total = params.lastTurnTotal;
|
||||||
|
}
|
||||||
|
const lastCallUsage = params.lastAssistant
|
||||||
|
? normalizeUsage(params.lastAssistant.usage as UsageLike)
|
||||||
|
: undefined;
|
||||||
|
const promptTokens = derivePromptTokens(params.lastRunPromptUsage);
|
||||||
|
return {
|
||||||
|
sessionId: params.sessionId,
|
||||||
|
provider: params.provider,
|
||||||
|
model: params.model,
|
||||||
|
// Only include usage fields when we have actual data from prior API calls.
|
||||||
|
...(usage ? { usage } : {}),
|
||||||
|
...(lastCallUsage ? { lastCallUsage } : {}),
|
||||||
|
...(promptTokens ? { promptTokens } : {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export async function runEmbeddedPiAgent(
|
export async function runEmbeddedPiAgent(
|
||||||
params: RunEmbeddedPiAgentParams,
|
params: RunEmbeddedPiAgentParams,
|
||||||
): Promise<EmbeddedPiRunResult> {
|
): Promise<EmbeddedPiRunResult> {
|
||||||
@@ -678,6 +715,8 @@ export async function runEmbeddedPiAgent(
|
|||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
let authRetryPending = false;
|
let authRetryPending = false;
|
||||||
|
// Hoisted so the retry-limit error path can use the most recent API total.
|
||||||
|
let lastTurnTotal: number | undefined;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (runLoopIterations >= MAX_RUN_LOOP_ITERATIONS) {
|
if (runLoopIterations >= MAX_RUN_LOOP_ITERATIONS) {
|
||||||
const message =
|
const message =
|
||||||
@@ -699,11 +738,14 @@ export async function runEmbeddedPiAgent(
|
|||||||
],
|
],
|
||||||
meta: {
|
meta: {
|
||||||
durationMs: Date.now() - started,
|
durationMs: Date.now() - started,
|
||||||
agentMeta: {
|
agentMeta: buildErrorAgentMeta({
|
||||||
sessionId: params.sessionId,
|
sessionId: params.sessionId,
|
||||||
provider,
|
provider,
|
||||||
model: model.id,
|
model: model.id,
|
||||||
},
|
usageAccumulator,
|
||||||
|
lastRunPromptUsage,
|
||||||
|
lastTurnTotal,
|
||||||
|
}),
|
||||||
error: { kind: "retry_limit", message },
|
error: { kind: "retry_limit", message },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -806,7 +848,7 @@ export async function runEmbeddedPiAgent(
|
|||||||
// Keep prompt size from the latest model call so session totalTokens
|
// Keep prompt size from the latest model call so session totalTokens
|
||||||
// reflects current context usage, not accumulated tool-loop usage.
|
// reflects current context usage, not accumulated tool-loop usage.
|
||||||
lastRunPromptUsage = lastAssistantUsage ?? attemptUsage;
|
lastRunPromptUsage = lastAssistantUsage ?? attemptUsage;
|
||||||
const lastTurnTotal = lastAssistantUsage?.total ?? attemptUsage?.total;
|
lastTurnTotal = lastAssistantUsage?.total ?? attemptUsage?.total;
|
||||||
const attemptCompactionCount = Math.max(0, attempt.compactionCount ?? 0);
|
const attemptCompactionCount = Math.max(0, attempt.compactionCount ?? 0);
|
||||||
autoCompactionCount += attemptCompactionCount;
|
autoCompactionCount += attemptCompactionCount;
|
||||||
const activeErrorContext = resolveActiveErrorContext({
|
const activeErrorContext = resolveActiveErrorContext({
|
||||||
@@ -998,11 +1040,15 @@ export async function runEmbeddedPiAgent(
|
|||||||
],
|
],
|
||||||
meta: {
|
meta: {
|
||||||
durationMs: Date.now() - started,
|
durationMs: Date.now() - started,
|
||||||
agentMeta: {
|
agentMeta: buildErrorAgentMeta({
|
||||||
sessionId: sessionIdUsed,
|
sessionId: sessionIdUsed,
|
||||||
provider,
|
provider,
|
||||||
model: model.id,
|
model: model.id,
|
||||||
},
|
usageAccumulator,
|
||||||
|
lastRunPromptUsage,
|
||||||
|
lastAssistant,
|
||||||
|
lastTurnTotal,
|
||||||
|
}),
|
||||||
systemPromptReport: attempt.systemPromptReport,
|
systemPromptReport: attempt.systemPromptReport,
|
||||||
error: { kind, message: errorText },
|
error: { kind, message: errorText },
|
||||||
},
|
},
|
||||||
@@ -1028,11 +1074,15 @@ export async function runEmbeddedPiAgent(
|
|||||||
],
|
],
|
||||||
meta: {
|
meta: {
|
||||||
durationMs: Date.now() - started,
|
durationMs: Date.now() - started,
|
||||||
agentMeta: {
|
agentMeta: buildErrorAgentMeta({
|
||||||
sessionId: sessionIdUsed,
|
sessionId: sessionIdUsed,
|
||||||
provider,
|
provider,
|
||||||
model: model.id,
|
model: model.id,
|
||||||
},
|
usageAccumulator,
|
||||||
|
lastRunPromptUsage,
|
||||||
|
lastAssistant,
|
||||||
|
lastTurnTotal,
|
||||||
|
}),
|
||||||
systemPromptReport: attempt.systemPromptReport,
|
systemPromptReport: attempt.systemPromptReport,
|
||||||
error: { kind: "role_ordering", message: errorText },
|
error: { kind: "role_ordering", message: errorText },
|
||||||
},
|
},
|
||||||
@@ -1056,11 +1106,15 @@ export async function runEmbeddedPiAgent(
|
|||||||
],
|
],
|
||||||
meta: {
|
meta: {
|
||||||
durationMs: Date.now() - started,
|
durationMs: Date.now() - started,
|
||||||
agentMeta: {
|
agentMeta: buildErrorAgentMeta({
|
||||||
sessionId: sessionIdUsed,
|
sessionId: sessionIdUsed,
|
||||||
provider,
|
provider,
|
||||||
model: model.id,
|
model: model.id,
|
||||||
},
|
usageAccumulator,
|
||||||
|
lastRunPromptUsage,
|
||||||
|
lastAssistant,
|
||||||
|
lastTurnTotal,
|
||||||
|
}),
|
||||||
systemPromptReport: attempt.systemPromptReport,
|
systemPromptReport: attempt.systemPromptReport,
|
||||||
error: { kind: "image_size", message: errorText },
|
error: { kind: "image_size", message: errorText },
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user