Skip to content

fix(agents): prevent totalTokens crash when assistant usage is missing#34977

Merged
jalehman merged 4 commits intoopenclaw:mainfrom
sp-hk2ldn:codex/fix-missing-usage-totaltokens-crash
Mar 6, 2026
Merged

fix(agents): prevent totalTokens crash when assistant usage is missing#34977
jalehman merged 4 commits intoopenclaw:mainfrom
sp-hk2ldn:codex/fix-missing-usage-totaltokens-crash

Conversation

@sp-hk2ldn
Copy link
Copy Markdown
Contributor

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: openclaw agent --json can crash in compaction/token accounting with TypeError: Cannot read properties of undefined (reading 'totalTokens') when assistant messages have missing/partial usage.
  • Why it matters: a missing usage object can brick the run path and prevent valid JSON response output.
  • What changed: sanitize session history now normalizes assistant usage snapshots defensively before compaction accounting; missing usage becomes a zero snapshot and partial usage fields are normalized to numeric values with computed totals.
  • What changed: added regression tests for missing assistant usage and mixed partial usage fields.
  • What did NOT change (scope boundary): no Mission Control/task-board or unrelated routing/status changes.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

openclaw agent --json no longer crashes when assistant usage is missing in the compaction/token-accounting path; execution continues and JSON output shape remains intact.

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Node 22+, pnpm
  • Model/provider: embedded pi runner / compaction path
  • Integration/channel (if any): CLI (openclaw agent --json)
  • Relevant config (redacted): local config had legacy telegram key warning preventing full live run completion

Steps

  1. Run focused tests:
    • pnpm test src/agents/pi-embedded-runner.sanitize-session-history.test.ts src/agents/usage.test.ts
  2. Run command-path test:
    • pnpm test src/commands/agent.test.ts -t "prints JSON payload when requested"
  3. Attempt live repro command:
    • pnpm openclaw agent --agent sherbert --message "ping" --json

Expected

  • Missing/partial assistant usage does not throw.
  • Token calc path remains numeric and null-safe.

Actual

  • Tests passed: 44/44 and 31/31.
  • Live command no longer showed totalTokens TypeError; run in this environment stopped earlier due local legacy config validation.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios:
    • Assistant message with no usage is normalized to zero snapshot and does not crash path.
    • Assistant message with partial usage fields is normalized to numeric snapshot with computed totalTokens.
  • Edge cases checked:
    • Existing stale-usage compaction sanitization behavior remains in place.
    • JSON command-path test remains green.
  • What you did not verify:
    • Full end-to-end live JSON payload in this shell due local legacy config validation gate.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly:
    • Revert commit e5a18e5cf.
  • Files/config to restore:
    • src/agents/pi-embedded-runner/google.ts
    • src/agents/pi-embedded-runner.sanitize-session-history.test.ts
  • Known bad symptoms reviewers should watch for:
    • Unexpected compaction threshold behavior if assistant usage normalization regresses.

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: Normalizing malformed assistant usage could mask upstream provider payload defects.
    • Mitigation: behavior is intentionally defensive for runtime safety, and tests lock expected normalization semantics.

@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling size: S labels Mar 4, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 4, 2026

Greptile Summary

This PR adds a defensive normalization pass (ensureAssistantUsageSnapshots) to the sanitizeSessionHistory pipeline that ensures every assistant message always carries a structurally valid AssistantUsageSnapshot before token accounting runs. The fix correctly targets the totalTokens crash path reported in #30134 and slots cleanly after the existing stripStaleAssistantUsageBeforeLatestCompaction pass so stale-zeroed messages are not double-processed.

  • normalizeAssistantUsageSnapshot delegates field extraction to the existing normalizeUsage helper (which handles all known provider naming variants), then computes totalTokens as normalized.total ?? input + output + cacheRead + cacheWrite — correctly handling both provider-supplied totals and fully missing totals.
  • ensureAssistantUsageSnapshots uses a 5-field equality check as a fast-path skip for messages that are already in the correct shape; messages that are missing or partially populated are replaced with a fully-formed snapshot.
  • Two regression tests are added that lock the zero-usage and partial-usage normalization semantics.
  • Style concern — equality check omits cost: The skip condition checks input, output, cacheRead, cacheWrite, and totalTokens but does not verify that the cost sub-object is present. A message with all five numeric fields correct but with cost absent would pass through un-normalized; any downstream access to usage.cost.total on such a message would crash with the same class of TypeError this PR fixes.
  • Style concern — normalization zeroes cost: normalizeAssistantUsageSnapshot always bases its return value on makeZeroUsageSnapshot(), so any pre-existing cost data on a partial-usage message is silently discarded. This is harmless in the fully-missing-usage case but could lose real cost information for messages that have partial usage.

Confidence Score: 4/5

  • Safe to merge — the fix is narrowly scoped, defensive, and covered by regression tests; only style-level gaps remain.
  • The crash fix is correct and well-tested. The two style concerns (missing cost check in the equality skip, and cost zeroing on normalization) represent potential follow-up crash vectors and data-loss edge cases but are not introduced regressions — they mirror the existing behavior of stripStaleAssistantUsageBeforeLatestCompaction which also zeroes cost via makeZeroUsageSnapshot(). No logic regressions were found in the sanitization pipeline ordering or the normalization arithmetic.
  • src/agents/pi-embedded-runner/google.ts — the ensureAssistantUsageSnapshots equality check and normalizeAssistantUsageSnapshot cost-zeroing behaviour are worth a follow-up to guard against the same class of crash on the cost sub-object.

Last reviewed commit: e5a18e5

Comment on lines +236 to +244
if (
message.usage &&
typeof message.usage === "object" &&
(message.usage as { input?: unknown }).input === normalizedUsage.input &&
(message.usage as { output?: unknown }).output === normalizedUsage.output &&
(message.usage as { cacheRead?: unknown }).cacheRead === normalizedUsage.cacheRead &&
(message.usage as { cacheWrite?: unknown }).cacheWrite === normalizedUsage.cacheWrite &&
(message.usage as { totalTokens?: unknown }).totalTokens === normalizedUsage.totalTokens
) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Equality check omits the cost sub-object

The fast-path equality check compares the five numeric fields but never checks whether the cost sub-object is present. AssistantUsageSnapshot requires cost: { input, output, cacheRead, cacheWrite, total } (see usage.ts makeZeroUsageSnapshot). A message that arrives with all five numeric fields already correct but with cost absent (or undefined) will satisfy every condition here and be skipped without normalization — leaving cost absent downstream.

If any consumer later does usage.cost.total (or similar) on such a message it will crash with the same class of TypeError this PR is fixing for totalTokens.

Consider adding a cost presence guard to the skip condition:

Suggested change
if (
message.usage &&
typeof message.usage === "object" &&
(message.usage as { input?: unknown }).input === normalizedUsage.input &&
(message.usage as { output?: unknown }).output === normalizedUsage.output &&
(message.usage as { cacheRead?: unknown }).cacheRead === normalizedUsage.cacheRead &&
(message.usage as { cacheWrite?: unknown }).cacheWrite === normalizedUsage.cacheWrite &&
(message.usage as { totalTokens?: unknown }).totalTokens === normalizedUsage.totalTokens
) {
if (
message.usage &&
typeof message.usage === "object" &&
typeof (message.usage as { cost?: unknown }).cost === "object" &&
(message.usage as { input?: unknown }).input === normalizedUsage.input &&
(message.usage as { output?: unknown }).output === normalizedUsage.output &&
(message.usage as { cacheRead?: unknown }).cacheRead === normalizedUsage.cacheRead &&
(message.usage as { cacheWrite?: unknown }).cacheWrite === normalizedUsage.cacheWrite &&
(message.usage as { totalTokens?: unknown }).totalTokens === normalizedUsage.totalTokens
) {
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/google.ts
Line: 236-244

Comment:
**Equality check omits the `cost` sub-object**

The fast-path equality check compares the five numeric fields but never checks whether the `cost` sub-object is present. `AssistantUsageSnapshot` requires `cost: { input, output, cacheRead, cacheWrite, total }` (see `usage.ts` `makeZeroUsageSnapshot`). A message that arrives with all five numeric fields already correct but with `cost` absent (or `undefined`) will satisfy every condition here and be skipped without normalization — leaving `cost` absent downstream.

If any consumer later does `usage.cost.total` (or similar) on such a message it will crash with the same class of `TypeError` this PR is fixing for `totalTokens`.

Consider adding a `cost` presence guard to the skip condition:
```suggestion
    if (
      message.usage &&
      typeof message.usage === "object" &&
      typeof (message.usage as { cost?: unknown }).cost === "object" &&
      (message.usage as { input?: unknown }).input === normalizedUsage.input &&
      (message.usage as { output?: unknown }).output === normalizedUsage.output &&
      (message.usage as { cacheRead?: unknown }).cacheRead === normalizedUsage.cacheRead &&
      (message.usage as { cacheWrite?: unknown }).cacheWrite === normalizedUsage.cacheWrite &&
      (message.usage as { totalTokens?: unknown }).totalTokens === normalizedUsage.totalTokens
    ) {
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +203 to +221
function normalizeAssistantUsageSnapshot(usage: unknown) {
const normalized = normalizeUsage((usage ?? undefined) as UsageLike | undefined);
if (!normalized) {
return makeZeroUsageSnapshot();
}
const input = normalized.input ?? 0;
const output = normalized.output ?? 0;
const cacheRead = normalized.cacheRead ?? 0;
const cacheWrite = normalized.cacheWrite ?? 0;
const totalTokens = normalized.total ?? input + output + cacheRead + cacheWrite;
return {
...makeZeroUsageSnapshot(),
input,
output,
cacheRead,
cacheWrite,
totalTokens,
};
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normalization silently zeroes the cost sub-object

When a message has a partial-but-non-empty usage (e.g. { output: 3, cache_read_input_tokens: 9 }), the function calls normalizeUsage to recover the numeric fields and then spreads makeZeroUsageSnapshot() as the base. Because makeZeroUsageSnapshot() always sets cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, any real cost information that was already present on the usage object is silently discarded.

For the missing-usage crash-fix path this is harmless (there was no cost to preserve). For the partial-usage normalization path it could mask genuine cost data from providers that do supply cost but omit totalTokens. If preserving cost is important, consider extracting it before building the normalized snapshot:

function normalizeAssistantUsageSnapshot(usage: unknown) {
  const normalized = normalizeUsage((usage ?? undefined) as UsageLike | undefined);
  if (!normalized) {
    return makeZeroUsageSnapshot();
  }
  const input = normalized.input ?? 0;
  const output = normalized.output ?? 0;
  const cacheRead = normalized.cacheRead ?? 0;
  const cacheWrite = normalized.cacheWrite ?? 0;
  const totalTokens = normalized.total ?? input + output + cacheRead + cacheWrite;
  const base = makeZeroUsageSnapshot();
  // Preserve existing cost if already present and well-formed
  const existingCost =
    usage && typeof usage === "object" && typeof (usage as { cost?: unknown }).cost === "object"
      ? (usage as { cost: typeof base.cost }).cost
      : base.cost;
  return { ...base, cost: existingCost, input, output, cacheRead, cacheWrite, totalTokens };
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/google.ts
Line: 203-221

Comment:
**Normalization silently zeroes the `cost` sub-object**

When a message has a partial-but-non-empty usage (e.g. `{ output: 3, cache_read_input_tokens: 9 }`), the function calls `normalizeUsage` to recover the numeric fields and then spreads `makeZeroUsageSnapshot()` as the base. Because `makeZeroUsageSnapshot()` always sets `cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }`, any real cost information that was already present on the usage object is silently discarded.

For the missing-usage crash-fix path this is harmless (there was no cost to preserve). For the partial-usage normalization path it could mask genuine cost data from providers that do supply cost but omit `totalTokens`. If preserving cost is important, consider extracting it before building the normalized snapshot:

```ts
function normalizeAssistantUsageSnapshot(usage: unknown) {
  const normalized = normalizeUsage((usage ?? undefined) as UsageLike | undefined);
  if (!normalized) {
    return makeZeroUsageSnapshot();
  }
  const input = normalized.input ?? 0;
  const output = normalized.output ?? 0;
  const cacheRead = normalized.cacheRead ?? 0;
  const cacheWrite = normalized.cacheWrite ?? 0;
  const totalTokens = normalized.total ?? input + output + cacheRead + cacheWrite;
  const base = makeZeroUsageSnapshot();
  // Preserve existing cost if already present and well-formed
  const existingCost =
    usage && typeof usage === "object" && typeof (usage as { cost?: unknown }).cost === "object"
      ? (usage as { cost: typeof base.cost }).cost
      : base.cost;
  return { ...base, cost: existingCost, input, output, cacheRead, cacheWrite, totalTokens };
}
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e5a18e5cf8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +214 to +219
...makeZeroUsageSnapshot(),
input,
output,
cacheRead,
cacheWrite,
totalTokens,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve usage cost when normalizing assistant snapshots

When a message needs normalization (for example legacy usage with prompt_tokens/completion_tokens, or missing zero-valued cache fields), this rebuilds the snapshot from makeZeroUsageSnapshot() and overwrites any existing usage.cost with zeros. Because sanitizeSessionHistory output is fed back into session state before runs, historical cost data can be silently lost and downstream reports that sum msg.usage.cost will under-report spend for affected sessions.

Useful? React with 👍 / 👎.

@sp-hk2ldn
Copy link
Copy Markdown
Contributor Author

Addressed the non-spam review feedback in follow-up commit 75301450e.

Changes made:

  • Preserved existing usage.cost values during assistant usage normalization (instead of always zeroing cost).
  • Tightened the fast-path equality guard so messages missing usage.cost are normalized instead of skipped.
  • Added regression coverage for:
    • preserving cost on partial usage normalization
    • filling missing cost even when numeric usage fields already match

Validation run:

  • pnpm test src/agents/pi-embedded-runner.sanitize-session-history.test.ts
  • pnpm test src/agents/usage.test.ts

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 75301450e3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +236 to +237
if (!rawCost || typeof rawCost !== "object") {
return base;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve unknown cost when normalizing assistant usage

When an assistant message has token counts but no usage.cost (common in legacy/provider-limited transcripts), this path returns a zeroed cost object and ensureAssistantUsageSnapshots persists it back into session history. That changes semantics from “cost unknown” to “cost is exactly zero,” so downstream aggregation in src/infra/session-cost-usage.ts (which treats finite cost.total as authoritative) will stop counting these turns as missing-cost entries and under-report spend after compaction. Keep cost undefined when the source usage has no cost block instead of synthesizing zeros.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eaea29ea90

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +210 to +212
if (!normalized) {
return makeZeroUsageSnapshot();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve cost when usage has no token counters

If an assistant message carries a valid usage.cost block but no token fields, normalizeAssistantUsageSnapshot returns makeZeroUsageSnapshot() immediately and never calls normalizeAssistantUsageCost, so non-zero historical cost is overwritten with zeros during sanitization. This regresses billing/report accuracy for legacy/provider-limited transcripts that only persisted cost metadata. Fresh evidence in this commit: the new early return at normalizeAssistantUsageSnapshot bypasses all cost-preservation logic when normalizeUsage(...) is falsy.

Useful? React with 👍 / 👎.

@jalehman jalehman self-assigned this Mar 6, 2026
@jalehman jalehman force-pushed the codex/fix-missing-usage-totaltokens-crash branch from eaea29e to 8522537 Compare March 6, 2026 22:58
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8522537e19

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +210 to +212
if (!normalized) {
return makeZeroUsageSnapshot();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve cost-only snapshots during usage normalization

If an assistant message carries only usage.cost (with no token counters), normalizeUsage(...) returns undefined and this branch replaces the message with makeZeroUsageSnapshot(), wiping the original non-zero cost in ensureAssistantUsageSnapshots. Since sanitizeSessionHistory feeds this normalized transcript back into the active session, downstream reporting (for example extractCostBreakdown in src/infra/session-cost-usage.ts) will read cost.total = 0 instead of the recorded value and under-report spend for legacy/provider-limited turns.

Useful? React with 👍 / 👎.

@jalehman jalehman force-pushed the codex/fix-missing-usage-totaltokens-crash branch from 8522537 to bb100cf Compare March 6, 2026 23:05
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bb100cf538

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +210 to +212
if (!normalized) {
return makeZeroUsageSnapshot();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve cost-only assistant snapshots during normalization

If an assistant message carries usage.cost but no token counters (common in legacy/provider-limited transcripts), normalizeUsage(...) returns undefined and this branch replaces the message with makeZeroUsageSnapshot(), which sets cost.total to 0. ensureAssistantUsageSnapshots then persists that normalized value back into session history, so downstream cost aggregation reads an authoritative zero instead of the recorded spend and under-reports usage costs for those turns.

Useful? React with 👍 / 👎.

@jalehman jalehman force-pushed the codex/fix-missing-usage-totaltokens-crash branch from bb100cf to 1c14094 Compare March 6, 2026 23:42
@jalehman jalehman merged commit 942c53e into openclaw:main Mar 6, 2026
28 of 29 checks passed
@jalehman
Copy link
Copy Markdown
Contributor

jalehman commented Mar 6, 2026

Merged via squash.

Thanks @sp-hk2ldn!

vincentkoc pushed a commit to BryanTegomoh/openclaw-fork that referenced this pull request Mar 8, 2026
openclaw#34977)

Merged via squash.

Prepared head SHA: 1c14094
Co-authored-by: sp-hk2ldn <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman
Saitop pushed a commit to NomiciAI/openclaw that referenced this pull request Mar 8, 2026
openclaw#34977)

Merged via squash.

Prepared head SHA: 1c14094
Co-authored-by: sp-hk2ldn <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman
jenawant pushed a commit to jenawant/openclaw that referenced this pull request Mar 10, 2026
openclaw#34977)

Merged via squash.

Prepared head SHA: 1c14094
Co-authored-by: sp-hk2ldn <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman
dhoman pushed a commit to dhoman/chrono-claw that referenced this pull request Mar 11, 2026
openclaw#34977)

Merged via squash.

Prepared head SHA: 1c14094
Co-authored-by: sp-hk2ldn <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman
senw-developers pushed a commit to senw-developers/va-openclaw that referenced this pull request Mar 17, 2026
openclaw#34977)

Merged via squash.

Prepared head SHA: 1c14094
Co-authored-by: sp-hk2ldn <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman
V-Gutierrez pushed a commit to V-Gutierrez/openclaw-vendor that referenced this pull request Mar 17, 2026
openclaw#34977)

Merged via squash.

Prepared head SHA: 1c14094
Co-authored-by: sp-hk2ldn <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Session permanently stuck after hook-based compaction: Cannot read properties of undefined (reading 'totalTokens')

2 participants