@agentex/agent 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +107 -10
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -26,7 +26,8 @@ const result = await claude.execute({
26
26
  },
27
27
  onEvent: (event) => {
28
28
  if (event.type === "assistant") process.stdout.write(event.text);
29
- if (event.type === "tool_call") console.log(`Tool: ${event.name}`);
29
+ if (event.type === "tool_call") console.log(`Tool ${event.name} (toolCallId=${event.toolCallId})`);
30
+ // event.sessionId, event.messageId, event.eventId are populated per-provider
30
31
  },
31
32
  });
32
33
 
@@ -34,7 +35,11 @@ console.log(result.status); // "completed"
34
35
  console.log(result.summary); // "Added try/catch to all route handlers..."
35
36
  console.log(result.durationMs); // 12340
36
37
  console.log(result.costUsd); // 0.0342
37
- console.log(result.usage); // { "claude-sonnet-4-6": { inputTokens: 1200, outputTokens: 350, ... } }
38
+ console.log(result.usage); // { "claude-sonnet-4-6": { inputTokens: 1200, outputTokens: 350, costUsd: 0.0342, ... } }
39
+ console.log(result.stopReason); // "end_turn"
40
+ console.log(result.numTurns); // 3
41
+ console.log(result.rateLimits); // [{ status: "allowed", ... }]
42
+ console.log(result.raw); // the final provider-native event, verbatim (escape hatch)
38
43
  ```
39
44
 
40
45
  ## Built-in Providers
@@ -109,7 +114,7 @@ interface ExecutionResult {
109
114
  durationMs: number;
110
115
  errorMessage: string | null;
111
116
  errorCode: string | null;
112
- usage?: Record<string, TokenUsage>; // keyed by model ID
117
+ usage?: Record<string, ModelUsage>; // keyed by model ID
113
118
  costUsd: number | null;
114
119
  model: string | null;
115
120
  summary: string | null;
@@ -117,8 +122,40 @@ interface ExecutionResult {
117
122
  sessionDisplayId: string | null;
118
123
  clearSession: boolean;
119
124
  billingType: "api" | "subscription" | "metered_api" | null;
120
- raw?: Record<string, unknown> | null;
121
- workspace?: PreparedWorkspace; // Present if config.workspace was set
125
+
126
+ // Provider-reported run metadata populated when the provider emits it.
127
+ // Claude populates all of these; Codex leaves them undefined/null.
128
+ stopReason?: string | null; // "end_turn" | "max_turns" | "tool_use" | ...
129
+ terminalReason?: string | null; // CLI's own terminal reason ("completed" | "error" | ...)
130
+ numTurns?: number | null;
131
+ durationApiMs?: number | null; // Time in model API calls, separate from wall clock
132
+ permissionDenials?: unknown[]; // Claude permission_denials array, verbatim
133
+ rateLimits?: RateLimitInfo[]; // Rate-limit signals observed during the run
134
+
135
+ raw?: Record<string, unknown> | null; // True escape hatch: final provider-native event verbatim
136
+ workspace?: PreparedWorkspace; // Present if config.workspace was set
137
+ }
138
+
139
+ interface TokenUsage {
140
+ inputTokens: number;
141
+ outputTokens: number;
142
+ cachedInputTokens?: number; // Claude cache_read ∪ Codex cached_input_tokens
143
+ cacheCreationInputTokens?: number; // Claude only
144
+ }
145
+
146
+ interface ModelUsage extends TokenUsage {
147
+ costUsd?: number; // Per-model cost (Claude's modelUsage)
148
+ webSearchRequests?: number;
149
+ contextWindow?: number;
150
+ maxOutputTokens?: number;
151
+ }
152
+
153
+ interface RateLimitInfo {
154
+ status: string; // "allowed" | "rejected" | ...
155
+ limitType: string | null; // "five_hour" | "weekly" | ...
156
+ resetAt: string | null; // ISO timestamp when the window resets
157
+ overageStatus: string | null;
158
+ isUsingOverage: boolean | null;
122
159
  }
123
160
  ```
124
161
 
@@ -126,17 +163,77 @@ Use `aggregateUsage(result.usage)` to collapse per-model usage into a single tot
126
163
 
127
164
  ## Stream Events
128
165
 
129
- Emitted during execution via `onEvent`. All events include `timestamp`.
166
+ Emitted during execution via `onEvent`. Every event carries the same normalized ID set on top of its variant-specific fields:
167
+
168
+ ```typescript
169
+ interface BaseStreamEventFields {
170
+ timestamp: string;
171
+ providerType: string; // "claude" | "codex" | "cursor" | ...
172
+ sessionId: string | null; // Stable session/thread ID across turns
173
+ messageId: string | null; // Provider-native message ID
174
+ eventId: string | null; // Per-event-line ID (Claude only — Codex = null)
175
+ turnId: string | null; // Native turn ID (Codex v2 app-server only; NDJSON & Claude = null)
176
+ parentToolCallId: string | null; // Sub-agent origin — same namespace as tool_call.toolCallId (Claude only)
177
+ raw: Record<string, unknown>; // Original provider event verbatim
178
+ }
179
+ ```
180
+
181
+ Variants:
130
182
 
131
- - `system` — Session init (`sessionId`, `model`, `subtype`)
183
+ - `system` — Session init (`subtype`, `model`, `cwd`, `tools`, `permissionMode`)
132
184
  - `assistant` — Text output from the agent (`text`)
133
185
  - `thinking` — Agent's internal reasoning (`text`)
134
- - `tool_call` — Agent invoked a tool (`name`, `input`, `callId?`)
135
- - `tool_result` — Tool returned a result (`toolCallId`, `content`, `isError`)
136
- - `result` — Final result (`text`, `cost`, `isError`)
186
+ - `tool_call` — Agent invoked a tool (`toolCallId: string | null`, `name`, `input`)
187
+ - `unknown` — Fallback for unrecognized wire events (`subtype` = the provider's `type` field). Forward-compat access to new CLI events via `raw` without a library update.
188
+ - `tool_result` — Tool returned a result (`toolCallId: string | null`, `content`, `isError`, `exitCode: number | null`)
189
+ - `rate_limit` — Provider reported rate-limit state (`status`, `limitType`, `resetAt`, `overageStatus`, `isUsingOverage`)
190
+ - `result` — Final result (`text`, `costUsd`, `isError`, `stopReason`, `terminalReason`, `numTurns`, `durationMs`)
137
191
 
138
192
  Lifecycle events (via `onLifecycle`) report phases: `preparing`, `spawning`, `running`, `waiting_for_input`, `completed`, `cancelled`, `error`.
139
193
 
194
+ ### What each provider surfaces on stream events
195
+
196
+ Verified live against `claude 2.1.116` and `codex-cli 0.122.0` (2026-04-21). Other providers emit stubs — see precedence table at the end of this section.
197
+
198
+ | Field on `StreamEvent` | Claude source | Codex source |
199
+ | ---------------------- | -------------------------------------------------- | ------------------------------------------------ |
200
+ | `sessionId` | `session_id` (UUID, stable across turns + resume) | `thread_id` (UUIDv7, emitted once on `thread.started`, tracked across lines) |
201
+ | `messageId` | `message.id` (Anthropic API message, e.g. `msg_*`) | v2 app-server: globally unique (`msg_*`, `rs_*`, `call_*`). NDJSON: `item_N` — **turn-local, not globally unique** |
202
+ | `eventId` | Top-level per-line `uuid` | **null** — Codex doesn't emit a per-event ID |
203
+ | `turnId` | **null** — Claude doesn't model turns | v2 app-server: native UUIDv7 from `params.turnId`. NDJSON: **null** — no turn id in legacy format |
204
+ | `parentToolCallId` | `parent_tool_use_id` (set for sub-agent messages) | **null** — not emitted |
205
+ | Tool correlation | `tool_use.id` (`toolu_*`) ↔ `tool_result.tool_use_id` | `item.id` reappears on the same item's `item.completed` |
206
+ | `tool_result.exitCode` | **null** (Claude doesn't expose shell exit codes) | `item.exit_code` for `command_execution` |
207
+ | Assistant message span | One `message.id` may span multiple event lines (thinking + tool_use emitted separately with distinct `uuid`s) | One `item.completed` per agent message |
208
+
209
+ On `ExecutionResult`:
210
+
211
+ | Field | Claude | Codex |
212
+ | ------------------ | -------------------------------------------------------------- | -------------------------------------------------------------------- |
213
+ | `costUsd` | ✓ `total_cost_usd` | **always null** — Codex JSONL doesn't report cost |
214
+ | `usage.*.costUsd` | ✓ per-model from `modelUsage` payload | — not available |
215
+ | `usage` cache keys | ✓ `cachedInputTokens` + `cacheCreationInputTokens` | ✓ `cachedInputTokens` only (maps from `cached_input_tokens`) |
216
+ | `model` | ✓ from `system.init` / `message.model` | **null from stdout** — falls back to the requested model |
217
+ | `raw.stopReason` | ✓ `result.stop_reason` | — not emitted |
218
+ | `raw.terminalReason` | ✓ `result.terminal_reason` | — not emitted |
219
+ | `raw.numTurns` | ✓ | — not emitted |
220
+ | `raw.rateLimits` | ✓ parsed from `rate_limit_event` events | — not emitted |
221
+ | `raw.permissionDenials` | ✓ `result.permission_denials` | — not emitted |
222
+ | `raw.finalEvent` | ✓ the `result` event verbatim | ✓ the `turn.completed` / `turn.failed` / `error` event verbatim |
223
+ | Per-model breakdown | ✓ multiple models can appear — Claude quietly calls haiku alongside the main model for summarization | single requested model only |
224
+
225
+ ### Storing events in a database
226
+
227
+ For Claude, `eventId` is a safe unique key for a per-event row. `messageId` is a safe key for "one logical assistant message" — multiple event lines can share it when the message contains both thinking and tool_use blocks.
228
+
229
+ For Codex, `item.id` values like `item_0`, `item_1` **reset every turn** (including on `codex exec resume`). Do not use them as unique keys on their own. Use `(sessionId, turn_index, messageId)` or mint your own UUID at insert time. There is no `eventId` — Codex doesn't emit one.
230
+
231
+ When in doubt, `raw` is the verbatim provider event — parse it yourself for anything the normalized fields don't cover.
232
+
233
+ ### Other providers
234
+
235
+ `cursor`, `gemini`, `opencode`, `pi`, `openclaw` emit the same `StreamEvent` shape but currently stub most IDs to `null`. Their `raw` field is populated; enrichment to match the Claude/Codex level of fidelity is tracked separately and has not been audited against live CLI output.
236
+
140
237
  ## Sessions (multi-turn)
141
238
 
142
239
  Providers with `capabilities.sessions = true` (Claude, Codex) can host a persistent session where you send multiple user messages and reuse context across turns.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentex/agent",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Programmatic execution of AI coding agents (Claude Code, Codex, OpenClaw)",
5
5
  "type": "module",
6
6
  "exports": {