Skip to content

refactor(agents): remove transcript token cost enrichment#1994

Open
yyovil wants to merge 5 commits into
AgentWrapper:mainfrom
yyovil:fix/codex-session-info-jsonl-oom
Open

refactor(agents): remove transcript token cost enrichment#1994
yyovil wants to merge 5 commits into
AgentWrapper:mainfrom
yyovil:fix/codex-session-info-jsonl-oom

Conversation

@yyovil
Copy link
Copy Markdown
Contributor

@yyovil yyovil commented May 21, 2026

Summary

  • remove AgentSessionInfo.cost / CostEstimate and delete live token/cost aggregation from agent session-info paths
  • keep Codex and Claude session enrichment lightweight: use persisted native metadata when available and bounded JSONL reads only for restore/session metadata discovery
  • bound Aider/Cursor/Kimi summary reads and remove stale token/cost assumptions across agent tests/docs

This is a follow-up cleanup after #1992 and #1996. It keeps the Codex thread-id lookup/restore behavior needed for legacy sessions while making dashboard/session-list enrichment safe by construction.

Related: #1991, #1935.

Tests

  • pnpm --filter @aoagents/ao-plugin-agent-codex test
  • pnpm --filter @aoagents/ao-plugin-agent-codex typecheck
  • pnpm --filter @aoagents/ao-plugin-agent-claude-code test
  • pnpm --filter @aoagents/ao-plugin-agent-claude-code typecheck
  • pnpm --filter @aoagents/ao-plugin-agent-aider test
  • pnpm --filter @aoagents/ao-plugin-agent-aider typecheck
  • pnpm --filter @aoagents/ao-plugin-agent-cursor test
  • pnpm --filter @aoagents/ao-plugin-agent-cursor typecheck
  • pnpm --filter @aoagents/ao-plugin-agent-kimicode test
  • pnpm --filter @aoagents/ao-plugin-agent-kimicode typecheck
  • pnpm --filter @aoagents/ao-plugin-agent-opencode test
  • pnpm --filter @aoagents/ao-plugin-agent-opencode typecheck
  • pnpm --filter @aoagents/ao-plugin-agent-grok test
  • pnpm --filter @aoagents/ao-plugin-agent-grok typecheck
  • pnpm --filter @aoagents/ao-core typecheck
  • pnpm --filter @aoagents/ao-core exec vitest run src/__tests__/activity-events-migration.test.ts
  • pnpm --filter @aoagents/ao-web test -- src/lib/__tests__/serialize.test.ts
  • selected plugin builds required by web services, then pnpm --filter @aoagents/ao-web typecheck
  • pnpm lint
  • git diff --check

Notes: full pnpm build is blocked locally by existing packages/notifier-macos Swift build environment error (SOURCE_DATE_EPOCH empty). Full pnpm --filter @aoagents/ao-core test is blocked locally by timeouts in activity-events-migration.test.ts; the same test file passes when run directly as listed above.

Copilot AI review requested due to automatic review settings May 21, 2026 21:22
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: 9b93dfad18

ℹ️ 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 thread packages/plugins/agent-codex/src/index.ts Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Codex agent plugin to avoid expensive JSONL streaming/parsing on request paths for sessions that are already terminal (or runtime-missing) by returning a cheap AgentSessionInfo derived from persisted restore metadata (codexThreadId / codexModel). It also adds a short-lived cache so repeated getSessionInfo() / getRestoreCommand() calls within the same refresh window don’t duplicate JSONL parsing work.

Changes:

  • Add a metadata-only fast path for getSessionInfo() when codexThreadId is already persisted (especially for terminal/runtime-missing sessions).
  • Add a module-level cache + in-flight dedupe for streamed Codex session data to avoid repeated parsing within a TTL window.
  • Extend tests to cover “no JSONL streaming for terminal sessions” and “streamed data is cached across repeated calls”.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/plugins/agent-codex/src/index.ts Adds metadata-only getSessionInfo() path and introduces cached/deduped JSONL streaming for session data.
packages/plugins/agent-codex/src/index.test.ts Adds coverage for metadata-only fast path and the new streamed-session-data cache behavior.

Comment thread packages/plugins/agent-codex/src/index.ts Outdated
Comment thread packages/plugins/agent-codex/src/index.ts Outdated
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 21, 2026

Greptile Summary

This PR fixes a Codex-session-manager OOM path by avoiding full-file JSONL streaming for sessions that already have codexThreadId/codexModel persisted to metadata, and by replacing the unbounded streamCodexSessionData with readCodexSessionMetadata which caps reads at 100 lines / 1 MB. Cost-estimation logic is removed entirely from all agent plugins as part of this change.

  • Fast path for terminal sessions: buildPersistedCodexSessionInfo returns session info directly from persisted metadata without touching the filesystem, fixing the OOM trigger for long-dead sessions that were being re-streamed on every refresh cycle.
  • Bounded JSONL prefix scan: readCodexSessionMetadata replaces streamCodexSessionData, reading at most 100 lines or 1 MB instead of the entire (potentially 100 MB+) file; a new maxBytes guard is added to readJsonlPrefixLines.
  • Cost estimation removed: CostEstimate interface and all per-plugin token-counting / cost-aggregation code are deleted across codex, claude-code, aider, cursor, kimicode, and opencode plugins.

Confidence Score: 5/5

Safe to merge — the OOM fix is well-scoped and the bounded-read approach correctly prevents large JSONL files from being loaded into memory.

All changes are additive safeguards (byte limits, fast paths) or pure deletions of cost-estimation code with no remaining callers. The fast path for terminal sessions is covered by new tests, and the bounded JSONL scan mirrors the existing cwd-match scan approach. The two observations are minor ordering/optimization nits that do not affect correctness for real-world session files.

packages/plugins/agent-codex/src/index.ts — specifically the byte-limit ordering in readJsonlPrefixLines and the missing early-exit in readCodexSessionMetadata.

Important Files Changed

Filename Overview
packages/plugins/agent-codex/src/index.ts Core change: replaces unbounded JSONL streaming with a bounded prefix scan, adds buildPersistedCodexSessionInfo fast path, and removes cost estimation. Logic is correct; minor ordering note on byte-limit break vs. newline processing.
packages/plugins/agent-codex/src/index.test.ts Test suite updated to replace stream mocks with file-handle mocks, adds coverage for terminal fast-path, live sessions with/without model metadata, and lifecycle-driven terminal detection.
packages/core/src/types.ts Removes CostEstimate interface and its cost field from AgentSessionInfo; doc-comment updates only.
packages/plugins/agent-claude-code/src/index.ts Removes extractCost and cost-related JSONL fields; simplifies parseJsonlFileTail to always use a file handle with bounded reads. Behavior for tail-read logic is unchanged.
packages/plugins/agent-aider/src/index.ts Switches extractAiderSummary from readFile to a bounded 64 KB head read via open. Correct since the first user message (#### prefix) is always near the start of .aider.chat.history.md.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[getSessionInfo called] --> B{buildPersistedCodexSessionInfo}
    B --> C{codexThreadId in metadata?}
    C -- No --> D[findCodexSessionFileCached]
    C -- Yes --> E{codexModel in metadata?}
    E -- Yes --> F[Return info from metadata no I/O]
    E -- No --> G{isTerminalSession?}
    G -- Yes --> H[Return info from metadata no I/O, summary=null]
    G -- No --> D
    D --> I{Session file found?}
    I -- No --> J[return null]
    I -- Yes --> K[readCodexSessionMetadata first 100 lines / 1 MB]
    K --> L{threadId or model found?}
    L -- No --> J
    L -- Yes --> M[buildCodexSessionInfo persists codexModel to metadata]
    M --> N[Return AgentSessionInfo]
    F --> N
    H --> N
Loading
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
packages/plugins/agent-codex/src/index.ts:158-163
The byte-limit guard fires **before** the newline-processing loop, so all complete lines that happen to land in the chunk that pushes `totalBytesRead` past `maxBytes` are silently discarded. In the worst case a batch of lines that would have been within the effective budget (accumulated in `partialLine`) is lost when the loop breaks. Moving the byte-limit check to after the newline loop ensures every complete line already decoded from the last chunk is captured.

```suggestion
      partialLine += decoder.write(buffer.subarray(0, bytesRead));

      let newlineIndex = partialLine.indexOf("\n");
      while (newlineIndex !== -1 && lines.length < maxLines) {
        const line = partialLine.slice(0, newlineIndex).trim();
        if (line) lines.push(line);
        partialLine = partialLine.slice(newlineIndex + 1);
        newlineIndex = partialLine.indexOf("\n");
      }

      if (totalBytesRead > maxBytes) {
        break;
      }

      newlineIndex = partialLine.indexOf("\n");
```

### Issue 2 of 2
packages/plugins/agent-codex/src/index.ts:321-334
`readCodexSessionMetadata` continues iterating through all 100 lines even after both `threadId` and `model` have been populated. Since `session_meta` (with the thread ID) and `turn_context` (with the model) are nearly always the first two lines of a Codex JSONL file, adding an early-exit saves unnecessary JSON parsing for the remaining lines on every refresh that takes the live path.

```suggestion
        if (entry.type === "turn_context" && typeof payload.model === "string" && payload.model) {
          data.model = payload.model;
        } else if (!data.model && typeof payload.model === "string" && payload.model) {
          data.model = payload.model;
        }

        if (data.threadId && data.model) break;
      } catch {
        // Skip malformed lines
      }
    }
  } catch {
    return null;
  }

  return data.threadId || data.model ? data : null;
```

Reviews (3): Last reviewed commit: "refactor(agents): remove session token c..." | Re-trigger Greptile

Comment thread packages/plugins/agent-codex/src/index.ts
Comment thread packages/plugins/agent-codex/src/index.ts Outdated
@yyovil yyovil changed the title fix(agent-codex): avoid JSONL parsing for persisted terminal sessions refactor(agents): remove transcript token cost enrichment May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants