{"record":{"id":"d695be4dc5a1a00c","repo":"JuliusBrussee/caveman","slug":"cave-eve-usage-missing","errorCode":"cave_eve_usage_missing","errorMessage":"cave_eve_usage_missing","messagePattern":"cave_eve_usage_missing","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/adapters.ts","lineNumber":433,"sourceCode":"  }, reasoningRequired, \"cave_mastra_usage_missing\");\n}\n\nfunction usageFromEveEvents(events: unknown[], reasoningRequired: boolean): NormalizedUsage {\n  let totalInputTokens = 0;\n  let outputTokens = 0;\n  let cacheReadTokens = 0;\n  let cacheWriteTokens = 0;\n  let steps = 0;\n  for (const event of events) {\n    if (!isRecord(event) || event.type !== \"step.completed\" || !isRecord(event.data)) continue;\n    const usage = record(event.data.usage, \"cave_eve_usage_missing\");\n    totalInputTokens += strictInteger(usage.inputTokens, \"cave_eve_usage_missing\");\n    outputTokens += strictInteger(usage.outputTokens, \"cave_eve_usage_missing\");\n    cacheReadTokens += strictInteger(usage.cacheReadTokens, \"cave_eve_usage_missing\");\n    cacheWriteTokens += strictInteger(usage.cacheWriteTokens, \"cave_eve_usage_missing\");\n    steps++;\n  }\n  if (steps === 0 || reasoningRequired) throw new Error(\"cave_eve_usage_missing\");\n  if (cacheReadTokens + cacheWriteTokens > totalInputTokens) {\n    throw new Error(\"cave_eve_usage_missing\");\n  }\n  const inputTokens = totalInputTokens - cacheReadTokens - cacheWriteTokens;\n  return normalizeUsage({\n    inputTokens,\n    outputTokens,\n    cacheReadTokens,\n    cacheWriteTokens,\n    reasoningTokens: 0,\n    totalTokens: inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens,\n  }, false, \"cave_eve_usage_missing\");\n}\n\nfunction normalizeUsage(\n  value: Record<keyof NormalizedUsage, unknown>,\n  reasoningRequired: boolean,\n  error: string,","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/packages/agent/src/adapters.ts#L415-L451","documentation":"`usageFromEveEvents` aggregates usage from every `step.completed` event; after the loop it throws (line 433) if zero `step.completed` events with data were seen OR if the plan requires reasoning accounting (`plan.reasoning !== \"none\"`). The Eve durable event contract carries no reasoning-token split, so reasoning-capable plans are structurally unsupported on this adapter — Eve only serves reasoning-off locks — and a session with no billable steps likewise cannot produce usage evidence.","triggerScenarios":"Compiling a plan with reasoning enabled and running it through `createEveAdapter` (always throws); an Eve run that completed without emitting any `step.completed` events because the event log was filtered, empty, or short-circuited.","commonSituations":"Copying a reasoning plan from the Pi/Vercel lane into the Eve lane; event middleware with an allowlist that drops step events; Eve version drift changing the event contract (the adapter pins 0.29.2).","solutions":["Set the plan's reasoning to `\"none\"` (a reasoning-off lock) for Eve runs","Verify the session's events contain `step.completed` entries with `data.usage`","Confirm the runtime really is Eve 0.29.2 so the event contract matches what the adapter parses"],"exampleFix":"// before\nconst plan = await compile({ ...opts, reasoning: 'per-turn' }); // Eve adapter rejects\n// after\nconst plan = await compile({ ...opts, reasoning: 'none' });","handlingStrategy":"validation","validationCode":"// Eve's event contract omits reasoning usage: enforce reasoning-off plans\n// before wiring the adapter\nif (plan.reasoning !== 'none') {\n  throw new Error(`eve adapter requires reasoning: 'none' plans, got '${plan.reasoning}'`);\n}\nreturn createEveAdapter(identity, session);","typeGuard":null,"tryCatchPattern":"try {\n  return await adapter.run(req);\n} catch (e) {\n  if (e instanceof Error && e.message === 'cave_eve_usage_missing' && plan.reasoning !== 'none') {\n    // structural: recompile the plan with reasoning 'none' for the Eve lane\n    return runOnce({ ...req, plan: await compile({ ...opts, reasoning: 'none' }) });\n  }\n  throw e;\n}","preventionTips":["Route reasoning-demanding plans to Pi/Vercel lanes, not Eve","Smoke-test one session and assert a step.completed event with data.usage exists","Keep Eve at the pinned 0.29.2 so the event contract is what the adapter parses"],"tags":["typescript","eve","token-usage","reasoning","llm"],"backgroundTag":"llm-token-usage-missing","analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}