Skip to content

[Bug][Cursor] After restart of 2.7.35, agent/tool flow without checkpoint continuously reports active context as output-only #373

Closed

Description

@jhste102lab

요약

#245의 후속 보고입니다. #245 및 PR #274는 같은 Cursor conversation에서 이미 관측한 checkpoint를 tool-turn early finalize 뒤에도 carry-forward하도록 수정했습니다.

그러나 OpenCodex를 2.7.35로 업데이트하고 프록시가 재시작된 뒤, cursor/grok-4.5 agent session의 모든 새 요청이 다시 inputTokens = 0, totalTokens = outputTokens로 기록되고 있습니다. 재시작으로 process-local tracker가 비어 있는 상태에서 checkpoint가 한 번도 seed되지 않는 흐름을 현재 fallback이 처리하지 못하는 것으로 보입니다.

이 이슈는 실제 Grok이 수백 토큰만 받거나 사용했다는 주장이 아닙니다. Cursor transport가 authoritative usage를 매 응답 제공하지 않는 상황에서, Codex에 전달되는 active-context usage가 수십~수천 output token으로 축소되어 Context 상태/compaction 판단이 잘못 보이는 문제입니다.

#245와의 관계 및 차이

  • #245가 해결한 범위: 같은 Cursor conversation에서 앞서 받은 absolute checkpoint가 존재할 때, checkpoint 없는 tool finalize가 그 값을 작은 output-only total로 덮어쓰지 않도록 carry-forward.
  • 이번 범위: 프록시 재시작 직후 또는 처음부터 checkpoint 없는 agent/tool-heavy 흐름에서는 carry-forward의 seed가 없습니다. 이 경우 새 2.7.35 코드도 0 + tokenDelta를 그대로 usage로 내보냅니다.
  • request/conversation id가 매 요청마다 달라지는지 여부는 usage.jsonl만으로 단정하지 않았습니다. 다만 current checkpoint와 carry-forward checkpoint가 모두 없는 61개 연속 요청에서 동일한 output-only 결과가 관측됐습니다.

환경

항목 값
OpenCodex 2.7.35 (2.7.33에서 업데이트)
업데이트 완료 2026-07-24T02:16:47.010Z
새 프록시 process 시작 2026-07-24 11:16:46 KST
OS Linux / WSL2
Provider Cursor OAuth, api2.cursor.sh
Model cursor/grok-4.5
Requested effort 관측된 업데이트 후 요청 61/61 high
Local context cap providerContextCaps.cursor = 250000 (catalog context_window=250000, auto-compact limit 225000)

위 context cap은 visible window의 상한을 낮추는 별도 설정입니다. totalTokens가 111, 487, 2,912처럼 output token 수치로 리셋되는 현상을 설명하지는 못합니다.

관측 결과

~/.opencodex/usage.jsonl에서 업데이트 완료 시각 이후 provider=cursor, model=grok-4.5 항목을 집계했습니다.

  • 관측 구간: 2026-07-24 11:33:41 ~ 11:47:04 KST
  • 성공 요청: 61 / 61 (HTTP 200)
  • effort: 61 / 61 high
  • usageStatus: 61 / 61 estimated
  • absolute context가 보고된 행 (totalTokens > outputTokens): 0 / 61
  • output-only 행: 61 / 61
  • 최근 output token 예: 722, 170, 4,048, 114, 941, 875, 2,994, 494, 154, 2,912, 111, 487

대표 형태(프롬프트, 인증 정보, request id는 제외):

{
  "provider": "cursor",
  "model": "grok-4.5",
  "status": 200,
  "usageStatus": "estimated",
  "usage": {
    "inputTokens": 0,
    "outputTokens": 487,
    "totalTokens": 487,
    "estimated": true
  }
}

업데이트 전 같은 provider/model에서는 수만~십수만 단위 totalTokens가 간헐적으로 관측됐습니다. 따라서 Catalog window나 Codex가 custom usage를 무시하는 문제라기보다, checkpoint/carry가 없는 turn의 fallback 문제로 보입니다.

현재 코드 경로에서의 해석

Cursor live transport의 유효한 token 신호는 서로 다른 의미를 가집니다.

conversationCheckpointUpdate.tokenDetails.usedTokens
  -> absolute active context (optional checkpoint)
interactionUpdate.tokenDelta
  -> current turn output delta only

2.7.35의 CursorContextUsageTracker는 conversation id별 마지막 checkpoint를 process-local, numeric-only TTL/LRU Map에 유지합니다. finalizeTurnEvents()는 다음 순서로 total을 선택합니다.

current turn checkpoint
  -> use it
else prior carry-forward checkpoint for same conversation
  -> use it
else
  -> emit state.usage only (input=0, total=output tokenDelta)

프록시 재시작 후 tracker는 비어 있습니다. 위 관측에서는 61개 요청 모두에 현재 checkpoint도 carry-forward checkpoint도 없었으므로 마지막 분기가 선택된 것으로 해석됩니다.

기대 동작

checkpoint가 없는 요청에서 정확한 active context를 알 수 없다면, Codex가 실제로 거의 빈 context라고 해석하는 input=0, total=output-only를 보내면 안 됩니다.

다음 중 하나가 필요합니다.

  1. 안전한 compaction/reset 경계를 보존하면서 numeric last-known context를 response/conversation state에 지속해 restart 후에도 seed로 사용
  2. seed가 전혀 없는 요청에서는 outgoing request/state로부터 보수적 input estimate를 만들고 계속 estimated: true 유지
  3. 신뢰 가능한 estimate가 불가능하다면, near-empty context로 오인될 totalTokens 대신 context usage를 명시적으로 unknown/unavailable로 표현

제안하는 회귀 테스트

  1. checkpoint를 받은 conversation을 proxy restart 뒤 복원하고, 다음 turn이 checkpoint 없이 tool/client-tool finalize되는 경우
  2. 새 conversation의 첫 agent/tool turn이 checkpoint 없이 끝나는 경우
  3. request/conversation id rotation 후 carry가 없거나 rekey가 실패하는 경우
  4. compaction 직후에는 stale carry를 사용하지 않는 경계
  5. diagnostic log에 raw prompt 없이 checkpoint=current|carry|missing, context source, reset 여부, 해시된 conversation correlation만 기록

재현에 필요한 최소 조건

  • Cursor provider를 OpenCodex의 live transport로 사용
  • Responses/Codex client가 tool을 사용할 수 있는 agent turn 생성
  • proxy restart 직후 또는 아직 checkpoint가 기록되지 않은 conversation에서 여러 turn 실행
  • usage.jsonl 또는 dashboard Logs에서 inputTokens=0 및 totalTokens=outputTokens 반복 확인

원본 프롬프트, OAuth token/cookie, tool arguments, raw provider payload, request id는 의도적으로 첨부하지 않았습니다.

Activity

  1. changed the title [-][Bug][Cursor] 2.7.35 재시작 직후 checkpoint 없는 agent/tool 흐름이 active context를 output-only로 계속 보고함[/-] [+][Bug][Cursor] After restart of 2.7.35, agent/tool flow without checkpoint continuously reports active context as output-only[/+] on Jul 24, 2026
  2. github-actions commented on Jul 24, 2026

    @github-actions
    Contributor

    English translation (original: ko)

    Summary

    This is a follow-up report to #245. #245 and PR #274 modified the system to carry forward already observed checkpoints in the same Cursor conversation even after an early finalize of tool-turn.

    However, after updating OpenCodex to 2.7.35 and restarting the proxy, all new requests from the cursor/grok-4.5 agent session are once again recorded as inputTokens = 0, totalTokens = outputTokens. It seems that the current fallback is unable to handle the flow where the process-local tracker is empty after the restart and the checkpoint is never seeded.

    This issue does not claim that the actual Grok used only hundreds of tokens. In the situation where the Cursor transport does not provide authoritative usage in every response, the active-context usage being passed to Codex is reduced to dozens or thousands of output tokens, resulting in incorrect perceptions of the state/compaction of the Context.

    Relationship and Differences with #245

    • Scope resolved by [Bug][Cursor] 에이전트/툴 턴에서 active context 미보고로 Context 100% left 고정 (grok-4.5 재현) #245: When there is an existing absolute checkpoint received earlier in the same Cursor conversation, ensure that a tool finalize without a checkpoint does not overwrite that value with a small output-only total.
    • Current scope: Right after the proxy restart or in a checkpoint-less agent/tool-heavy flow from the beginning, there is no seed for carry-forward. In this case, the new 2.7.35 code also emits 0 + tokenDelta as usage.
    • Whether the request/conversation ID changes with each request was not determined solely by usage.jsonl. However, identical output-only results were observed in 61 consecutive requests where both the current checkpoint and carry-forward checkpoint were absent.

    Environment

    Item Value
    OpenCodex 2.7.35 (updated from 2.7.33)
    Update completed 2026-07-24T02:16:47.010Z
    New Proxy process start 2026-07-24 11:16:46 KST
    OS Linux / WSL2
    Provider Cursor OAuth, api2.cursor.sh
    Model cursor/grok-4.5
    Requested effort Observed update after requests 61/61 high
    Local context cap providerContextCaps.cursor = 250000 (catalog context_window=250000, auto-compact limit 225000)

    The above context cap is a separate setting that lowers the upper limit of the visible window. It cannot explain the phenomenon where totalTokens resets to output token numbers like 111, 487, 2,912.

    Observations

    Aggregated the items with provider=cursor, model=grok-4.5 in ~/.opencodex/usage.jsonl after the update completion time.

    • Observation period: 2026-07-24 11:33:41 ~ 11:47:04 KST
    • Successful requests: 61 / 61 (HTTP 200)
    • Effort: 61 / 61 high
    • usageStatus: 61 / 61 estimated
    • Rows reporting absolute context (totalTokens > outputTokens): 0 / 61
    • Output-only rows: 61 / 61
    • Recent output token examples: 722, 170, 4,048, 114, 941, 875, 2,994, 494, 154, 2,912, 111, 487

    Representative form (prompt, authentication info, request id excluded):

    {
      "provider": "cursor",
      "model": "grok-4.5",
      "status": 200,
      "usageStatus": "estimated",
      "usage": {
        "inputTokens": 0,
        "outputTokens": 487,
        "totalTokens": 487,
        "estimated": true
      }
    }

    Prior to the update, several tens of thousands to hundreds of thousands of totalTokens were sporadically observed with the same provider/model. Therefore, this issue seems more related to the fallback problem of turns without checkpoint/carry rather than the Catalog window or Codex disregarding custom usage.

    Interpretation in Current Code Path

    The valid token signals in Cursor live transport have different meanings.

    conversationCheckpointUpdate.tokenDetails.usedTokens
      -> absolute active context (optional checkpoint)
    interactionUpdate.tokenDelta
      -> current turn output delta only
    

    In 2.7.35, the CursorContextUsageTracker keeps the last checkpoint per conversation in a process-local, numeric-only TTL/LRU Map. The finalizeTurnEvents() chooses the total in the following order:

    current turn checkpoint
      -> use it
    else prior carry-forward checkpoint for same conversation
      -> use it
    else
      -> emit state.usage only (input=0, total=output tokenDelta)
    

    After a proxy restart, the tracker is empty. In the above observations, since there was neither a current checkpoint nor a carry-forward checkpoint for all 61 requests, it can be interpreted that the last branch was chosen.

    Expected Behavior

    If accurate active context cannot be known for requests without checkpoints, Codex should not send input=0, total=output-only, interpreting it as nearly an empty context.

    One of the following is required:

    1. Preserve safe compaction/reset boundaries while continuing to use a numeric last-known context in the response/conversation state after restart.
    2. For requests with no seeds at all, create a conservative input estimate from outgoing request/state while keeping estimated: true.
    3. If a reliable estimate is not possible, explicitly express context usage as unknown/unavailable instead of totalTokens, which may be mistaken for near-empty context.

    Suggested Regression Tests

    1. Restore a conversation that received checkpoints after a proxy restart, and if the next turn finalizes without checkpoints for tool/client-tool.
    2. The first agent/tool turn of a new conversation ends without a checkpoint.
    3. After request/conversation ID rotation, when there is no carry or the rekey fails.
    4. After compaction, a boundary that does not use stale carry.
    5. In the diagnostic log, only record checkpoint=current|carry|missing, context source, reset status, and hashed conversation correlation without the raw prompt.

    Minimum Conditions Required for Reproduction

    • Use the Cursor provider with OpenCodex's live transport.
    • Generate agent turns where the Responses/Codex client can use the tool.
    • Execute multiple turns immediately after a proxy restart or in conversations where checkpoints are not yet recorded.
    • Repeatedly check usage.jsonl or dashboard Logs for inputTokens=0 and totalTokens=outputTokens.

    The original prompt, OAuth token/cookie, tool arguments, raw provider payload, and request ID have been intentionally omitted.

  3. jhste102lab commented on Jul 24, 2026

    @jhste102lab
    ContributorAuthor

    추가 증거: Cursor usage export와 OpenCodex usage 로그 비교

    캐시가 실제로 사용되는지와 active-context telemetry 문제를 분리하기 위해, 동일 기간의 Cursor usage CSV와 OpenCodex usage.jsonl을 비교했습니다. 관련 cache-display 이슈는 #275입니다.

    첨부 예정 artifact

    opencodex-cursor-grok-cache-evidence-issue-373-20260724.zip

    구성:

    • cursor-usage-events-2026-07-24.csv: 제공된 Cursor usage export 원본
    • opencodex-cursor-grok-usage-redacted.jsonl: 같은 시간 범위의 provider=cursor, model=grok-4.5 OpenCodex usage 행. request id, prompt/input, tool arguments, headers, credentials, raw upstream payload 및 상세 오류는 제거됨
    • cache-comparison-summary.json, README.md, manifest.json

    Cursor export 관측

    CSV의 token 필드가 있는 Included 행 859개(2026-07-22 11:28:27 ~ 2026-07-24 11:57:54 KST)를 집계했습니다.

    항목 값
    Cache Read > 0 854 / 859 (99.4%)
    Cache Read 합계 29,966,336
    Input (w/o Cache Write) 합계 79,642,345
    Output Tokens 합계 1,005,482
    Total Tokens 합계 110,614,163
    Input (w/ Cache Write) 0 (모든 token 행)

    Cache Read / (Input (w/o Cache Write) + Cache Read)를 단순 cache-read share proxy로 계산하면 전체 가중 비중은 **27.3%**입니다. 이는 CSV가 제공하는 공식 hit-rate 필드는 아니며, event/agent correlation id가 비어 있으므로 request별 정확한 cache hit rate로 해석하면 안 됩니다.

    proxy restart 뒤의 교차 관측

    2.7.35 update/restart 완료(2026-07-24 11:16:47 KST) 이후 CSV 범위에서:

    source events input cache read output total
    Cursor export 85 7,558,534 1,632,896 100,938 9,292,368
    OpenCodex usage 89 410,082 unreported 84,147 494,229
    • Cursor export의 restart 후 85/85 행은 모두 Cache Read > 0입니다. 즉 proxy restart가 Cursor-side cache를 완전히 없앤 것으로 보이지는 않습니다.
    • 반면 같은 시간창의 OpenCodex usage 89개 중 86개는 inputTokens=0, totalTokens=outputTokens였습니다.
    • OpenCodex Cursor adapter에는 cachedInputTokens, cacheReadInputTokens, cacheCreationInputTokens를 수집·기록하는 경로가 현재 없습니다.

    해석

    1. Grok/Cursor cache는 실제로 사용 중입니다. OpenCodex Logs에서 cache가 비어 보이는 것을 cache miss로 해석하면 안 됩니다.
    2. Cursor의 별도 usage/export 계층에는 cache read 총계가 있지만, OpenCodex가 사용하는 live protobuf 경로는 per-response cache read/write 수치를 제공하지 않습니다. #275가 UI를 "unknown/unreported"로 바꾼 이유와 일치합니다.
    3. #373의 active-context 문제는 cache read 문제와 별개입니다. checkpoint/carry가 없으면 OpenCodex가 output delta만 total로 보내므로 Codex가 near-empty context로 오인합니다.
    4. CSV에 Cloud Agent ID, Automation ID, request id가 없으므로, export 행을 OpenCodex response와 안전하게 1:1 join하여 cache 값을 실시간 backfill할 수는 없습니다.

    후속 진단에 유용한 instrumentation 제안

    raw prompt나 credential을 남기지 않고 다음의 숫자/상태만 debug telemetry에 추가하면 원인 구분에 도움이 됩니다.

    • context source: checkpoint=current|carry|missing
    • hashed Cursor conversation correlation id 및 reset/rekey 여부
    • live stream에서 cache usage field가 absent인지, 향후 별도 usage source를 사용했는지
    • response별 cache enrichment가 가능할 때만 correlation method와 confidence

    이 자료는 "캐시가 꺼졌다"는 주장보다는, Cursor export와 OpenCodex live telemetry가 서로 다른 usage plane을 보고 있으며 OpenCodex가 cache 세부값을 얻지 못한다는 재현 증거입니다.

  4. jhste102lab commented on Jul 24, 2026

    @jhste102lab
    ContributorAuthor
  5. linked a pull request that will close this issuefix(cursor): estimate context after restart #376on Jul 25, 2026
  6. lidge-jun commented on Jul 25, 2026

    @lidge-jun
    Owner

    Fixed on dev in 28066934, included in integration SHA a5ec15e3.

    When a restarted/checkpoint-less Cursor turn has neither a current checkpoint nor carry-forward total, OpenCodex now derives a request-local input estimate from the bytes actually sent after pruning. Authoritative current checkpoints and carry-forward totals still win, and the estimate is never persisted into the conversation tracker. Regression tests cover restart/no-checkpoint, precedence, pruning, UTF-8 byte budgets, and live-transport wiring.

    Validation: Cross-platform CI and Service lifecycle passed for the exact integration SHA. PR #376 is being closed separately as superseded by the integrated implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions