@workerdeck/core 2.9.0 → 2.10.0

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.
package/build/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { McpServerStatus, Options, Query, SDKMessage, SDKSessionInfo, SDKUserMessage, SessionMessage } from "@anthropic-ai/claude-agent-sdk";
2
- import { ApiMessage, CreateSessionRequest, EngineCapabilities, McpServerConfigWire, McpServerStatusInfo, MessageAttachment, ModelOption, PermissionMode, PermissionRequest, ProfileEngine, ProfileInfo, SdkSessionSummary, SessionEvent, SessionEventBody, SessionInfo, SessionStatus, ToolCallRequestFrame, ToolExecutionBackend, ToolExecutionOutput } from "@workerdeck/protocol";
2
+ import { ApiMessage, ByModel, CostBreakdown, CreateSessionRequest, EngineCapabilities, McpServerConfigWire, McpServerStatusInfo, MessageAttachment, ModelOption, PermissionMode, PermissionRequest, ProfileEngine, ProfileInfo, SdkSessionSummary, SessionEvent, SessionEventBody, SessionInfo, SessionStatus, ToolCallRequestFrame, ToolExecutionBackend, ToolExecutionOutput } from "@workerdeck/protocol";
3
3
  import { LanguageModel, LanguageModel as LanguageModel$1, ModelMessage, Tool, Tool as Tool$1, ToolSet, ToolSet as ToolSet$1 } from "ai";
4
4
  import { SandboxEngine, SandboxVfs } from "@workerdeck/sandbox";
5
5
  import { Readable, Writable } from "node:stream";
@@ -24,6 +24,28 @@ type LocalCommandResult = {
24
24
  declare function localCommandTranscript(result: LocalCommandResult): string;
25
25
  declare function localCommandContext(pending: readonly string[]): string | undefined;
26
26
  //#endregion
27
+ //#region src/lib/cost-ledger.d.ts
28
+ type CostFigures = {
29
+ byModel?: ByModel;
30
+ reportedCostUsd?: number;
31
+ };
32
+ type CostLedgerState = CostFigures & {
33
+ lifetime?: CostFigures;
34
+ };
35
+ declare class CostLedger {
36
+ #private;
37
+ carry(state: CostLedgerState | undefined): void;
38
+ carryUnlessRestored(state: CostLedgerState | undefined): void;
39
+ observeCumulative(byModel: ByModel | undefined, reportedCostUsd: number | undefined): void;
40
+ observeDelta(byModel: ByModel): void;
41
+ rollover(): void;
42
+ get byModel(): ByModel | undefined;
43
+ get breakdown(): CostBreakdown;
44
+ get costUsd(): number | undefined;
45
+ get reportedCostUsd(): number | undefined;
46
+ snapshot(): CostLedgerState;
47
+ }
48
+ //#endregion
27
49
  //#region src/executors/tool-executor.d.ts
28
50
  type ToolExecutionResult = {
29
51
  status: 'ok';
@@ -117,6 +139,8 @@ interface Runner {
117
139
  settleExecution?(executionId: string, result: ToolExecutionResult): boolean;
118
140
  park?(): RunnerSnapshot | undefined;
119
141
  snapshot?(): RunnerSnapshot | undefined;
142
+ carryCost?(state: CostLedgerState): void;
143
+ costState?(): CostLedgerState;
120
144
  fail(message: string): void;
121
145
  close(reason?: 'client' | 'server' | 'error'): void;
122
146
  }
@@ -162,6 +186,8 @@ declare class SessionRunner implements Runner {
162
186
  get pendingApprovals(): PermissionRequest[];
163
187
  info(): SessionInfo;
164
188
  setTitle(title: string | undefined): void;
189
+ carryCost(state: CostLedgerState): void;
190
+ costState(): CostLedgerState;
165
191
  start(): Promise<void>;
166
192
  sendMessage(text: string, attachments?: readonly AttachmentInput[]): void;
167
193
  queueLocalCommand(result: LocalCommandResult): void;
@@ -221,7 +247,7 @@ type PendingToolCall = {
221
247
  toolCallId: string;
222
248
  toolName: string;
223
249
  input: unknown;
224
- deferred?: boolean;
250
+ parkable?: boolean;
225
251
  expiresAt?: number;
226
252
  };
227
253
  type AiSdkSessionState = {
@@ -229,12 +255,6 @@ type AiSdkSessionState = {
229
255
  pendingToolCalls: PendingToolCall[];
230
256
  dispatched: string[];
231
257
  numTurns: number;
232
- totalUsage: {
233
- input: number;
234
- output: number;
235
- cacheWrite: number;
236
- cacheRead: number;
237
- };
238
258
  turnAccum?: {
239
259
  startedAt: number;
240
260
  input: number;
@@ -267,6 +287,8 @@ declare class AiSdkRunner implements Runner {
267
287
  get pendingApprovals(): PermissionRequest[];
268
288
  get vfs(): SandboxVfs | undefined;
269
289
  info(): SessionInfo;
290
+ carryCost(state: CostLedgerState): void;
291
+ costState(): CostLedgerState;
270
292
  start(): Promise<void>;
271
293
  park(): RunnerSnapshot | undefined;
272
294
  snapshot(): RunnerSnapshot | undefined;
@@ -726,6 +748,10 @@ type AppServerUserInput = {
726
748
  } | {
727
749
  type: 'localImage';
728
750
  path: string;
751
+ } | {
752
+ type: 'skill';
753
+ name: string;
754
+ path: string;
729
755
  };
730
756
  type AppServerConnection = {
731
757
  request(method: string, params?: unknown): Promise<unknown>;
@@ -775,6 +801,8 @@ declare class CodexRunner implements Runner {
775
801
  get pendingApprovals(): PermissionRequest[];
776
802
  info(): SessionInfo;
777
803
  setTitle(title: string | undefined): void;
804
+ carryCost(state: CostLedgerState): void;
805
+ costState(): CostLedgerState;
778
806
  start(): Promise<void>;
779
807
  sendMessage(text: string, attachments?: readonly AttachmentInput[]): void;
780
808
  queueLocalCommand(result: LocalCommandResult): void;
@@ -817,5 +845,5 @@ declare class JsonRpcStdioConnection {
817
845
  //#region src/engines/provider/adapter.d.ts
818
846
  declare const providerAdapter: EngineAdapter;
819
847
  //#endregion
820
- export { AiSdkRunner, type AiSdkRunnerConfig, type AiSdkSessionState, type AppServerConnectFn, type AppServerConnectOptions, type AppServerConnection, type AppServerHistoryTurn, type AppServerItem, type AppServerThreadListResponse, type AppServerThreadSummary, type AppServerTokenUsage, type AppServerTurn, type AppServerUserInput, type AttachmentInput, type AttachmentKind, type BridgeAnswer, BrowserBridgeExecutor, type BrowserBridgeExecutorOptions, CLAUDE_CATALOG, CODEX_CATALOG, type ClaudeAuthProbe, type ClaudeAuthStatus, CodexRunner, type CodexRunnerConfig, type DeferredDispatch, DeferredExecutor, type DeferredExecutorOptions, type EngineAdapter, type EngineAvailability, type EngineRunnerRequest, type EngineSessionOptions, type HistoryFn, type HostFetch, type HostToolDefinition, InputQueue, JsonRpcError, JsonRpcStdioConnection, type LanguageModel, type LocalCommandResult, type McpConnection, type ModelCatalog, type ParkedExecution, type PendingEntry, type PendingKind, type PendingOutcome, PendingRequestRegistry, type PendingToolCall, type PermissionDecision, type QueryFn, QuickJsExecutor, type QuickJsExecutorOptions, type RegisterOptions, type Runner, type RunnerSnapshot, SUPPORTED_ATTACHMENT_TYPES, type SessionEventListener, SessionRunner, type SessionRunnerConfig, type SettledBy, type Tool, type ToolCallOutput, type ToolContext, type ToolContextOptions, type ToolDefinition, type ToolExecutionCall, type ToolExecutionDispatch, type ToolExecutionResult, type ToolExecutor, type ToolSet, type ToolTrust, type WebFetchDigest, type WebFetchFn, type WebFetchOptions, type WebFetchResult, attachmentContentBlocks, attachmentKind, attachmentRef, checkClaudeAuth, claudeAdapter, codexAdapter, connectAppServer, connectMcpTools, createEngineSession, createToolContext, createWebFetch, getEngineAdapter, htmlToMarkdown, isHostAllowed, isPrivateAddress, listCodexSessions, localCommandContext, localCommandTranscript, mcpStatusInfo, modelOptionsFromSdk, normalizeMediaType, normalizeSdkMessage, providerAdapter, replaySlice, resolveBundledClaudeExecutable, resolveBundledCodexExecutable, toApiMessage, toExecutionResult, truncateResultBlocks, withHostTools, withMcpTools };
848
+ export { AiSdkRunner, type AiSdkRunnerConfig, type AiSdkSessionState, type AppServerConnectFn, type AppServerConnectOptions, type AppServerConnection, type AppServerHistoryTurn, type AppServerItem, type AppServerThreadListResponse, type AppServerThreadSummary, type AppServerTokenUsage, type AppServerTurn, type AppServerUserInput, type AttachmentInput, type AttachmentKind, type BridgeAnswer, BrowserBridgeExecutor, type BrowserBridgeExecutorOptions, CLAUDE_CATALOG, CODEX_CATALOG, type ClaudeAuthProbe, type ClaudeAuthStatus, CodexRunner, type CodexRunnerConfig, type CostFigures, CostLedger, type CostLedgerState, type DeferredDispatch, DeferredExecutor, type DeferredExecutorOptions, type EngineAdapter, type EngineAvailability, type EngineRunnerRequest, type EngineSessionOptions, type HistoryFn, type HostFetch, type HostToolDefinition, InputQueue, JsonRpcError, JsonRpcStdioConnection, type LanguageModel, type LocalCommandResult, type McpConnection, type ModelCatalog, type ParkedExecution, type PendingEntry, type PendingKind, type PendingOutcome, PendingRequestRegistry, type PendingToolCall, type PermissionDecision, type QueryFn, QuickJsExecutor, type QuickJsExecutorOptions, type RegisterOptions, type Runner, type RunnerSnapshot, SUPPORTED_ATTACHMENT_TYPES, type SessionEventListener, SessionRunner, type SessionRunnerConfig, type SettledBy, type Tool, type ToolCallOutput, type ToolContext, type ToolContextOptions, type ToolDefinition, type ToolExecutionCall, type ToolExecutionDispatch, type ToolExecutionResult, type ToolExecutor, type ToolSet, type ToolTrust, type WebFetchDigest, type WebFetchFn, type WebFetchOptions, type WebFetchResult, attachmentContentBlocks, attachmentKind, attachmentRef, checkClaudeAuth, claudeAdapter, codexAdapter, connectAppServer, connectMcpTools, createEngineSession, createToolContext, createWebFetch, getEngineAdapter, htmlToMarkdown, isHostAllowed, isPrivateAddress, listCodexSessions, localCommandContext, localCommandTranscript, mcpStatusInfo, modelOptionsFromSdk, normalizeMediaType, normalizeSdkMessage, providerAdapter, replaySlice, resolveBundledClaudeExecutable, resolveBundledCodexExecutable, toApiMessage, toExecutionResult, truncateResultBlocks, withHostTools, withMcpTools };
821
849
  //# sourceMappingURL=index.d.mts.map
package/build/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { createHash, randomUUID } from "node:crypto";
3
3
  import { getSessionInfo, getSessionMessages, listSessions, query } from "@anthropic-ai/claude-agent-sdk";
4
- import { CHECKLIST_TEXT_MAX, ENGINE_CAPABILITIES, PROTOCOL_VERSION, SUBAGENT_HISTORY, TOOL_RESULT_HEAD_CHARS, contextReading, imagePartRef, parseTodoWriteInput, replayCoalesceKey, replayRetains, sanitizeToolTitle, snapshotRetains, transcriptActivity, transcriptContent, transcriptProse } from "@workerdeck/protocol";
4
+ import { CHECKLIST_TEXT_MAX, ENGINE_CAPABILITIES, PROTOCOL_VERSION, SUBAGENT_HISTORY, TOOL_RESULT_HEAD_CHARS, addTokenUsage, byModelTotalTokens, canonicalModel, contextReading, costOfByModel, emptyTokenUsage, imagePartRef, mergeByModel, parseTodoWriteInput, replayCoalesceKey, replayRetains, sanitizeToolTitle, snapshotRetains, tokenUsageFromWire, totalTokens, transcriptActivity, transcriptContent, transcriptProse } from "@workerdeck/protocol";
5
5
  import { ToolLoopAgent, generateText, isStepCount, tool } from "ai";
6
6
  import { execFile, spawn } from "node:child_process";
7
7
  import { appendFileSync, existsSync, mkdirSync, readFileSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
@@ -273,6 +273,18 @@ function parseUnifiedDiff(diff, path) {
273
273
  }
274
274
  //#endregion
275
275
  //#region src/lib/normalize.ts
276
+ function byModelFromSdk(modelUsage) {
277
+ if (!modelUsage) return;
278
+ const out = {};
279
+ for (const [model, entry] of Object.entries(modelUsage)) out[entry.canonicalModel ?? canonicalModel(model)] = {
280
+ ...emptyTokenUsage(),
281
+ input: Math.max(0, entry.inputTokens ?? 0),
282
+ output: Math.max(0, entry.outputTokens ?? 0),
283
+ cacheWrite5m: Math.max(0, entry.cacheCreationInputTokens ?? 0),
284
+ cacheRead: Math.max(0, entry.cacheReadInputTokens ?? 0)
285
+ };
286
+ return Object.keys(out).length === 0 ? void 0 : out;
287
+ }
276
288
  const FAMILY_ORDER = [
277
289
  "fable",
278
290
  "opus",
@@ -445,7 +457,8 @@ function normalizeSdkMessage(msg) {
445
457
  totalCostUsd: msg.total_cost_usd,
446
458
  result: msg.subtype === "success" ? msg.result : void 0,
447
459
  errors: msg.subtype === "success" ? void 0 : msg.errors,
448
- usage: msg.usage
460
+ usage: msg.usage,
461
+ usageByModel: byModelFromSdk(msg.modelUsage)
449
462
  };
450
463
  case "conversation_reset": return {
451
464
  type: "conversation_reset",
@@ -480,6 +493,157 @@ function resolveApprovalTimeoutMs(session, fallback) {
480
493
  return value === void 0 || value === null || value <= 0 ? void 0 : value;
481
494
  }
482
495
  //#endregion
496
+ //#region src/lib/cost-ledger.ts
497
+ function emptyBucket() {
498
+ return {
499
+ byModel: {},
500
+ reportedUsd: void 0
501
+ };
502
+ }
503
+ function bucketOf(figures) {
504
+ return {
505
+ byModel: figures.byModel ?? {},
506
+ reportedUsd: figures.reportedCostUsd
507
+ };
508
+ }
509
+ function figuresOf(bucket) {
510
+ return {
511
+ byModel: Object.keys(bucket.byModel).length === 0 ? void 0 : bucket.byModel,
512
+ reportedCostUsd: bucket.reportedUsd
513
+ };
514
+ }
515
+ function addBuckets(into, add) {
516
+ const reportedUsd = into.reportedUsd === void 0 && add.reportedUsd === void 0 ? void 0 : (into.reportedUsd ?? 0) + (add.reportedUsd ?? 0);
517
+ return {
518
+ byModel: mergeByModel(into.byModel, add.byModel),
519
+ reportedUsd
520
+ };
521
+ }
522
+ function subtractUsage(from, part) {
523
+ return {
524
+ input: Math.max(0, from.input - part.input),
525
+ output: Math.max(0, from.output - part.output),
526
+ cacheWrite5m: Math.max(0, from.cacheWrite5m - part.cacheWrite5m),
527
+ cacheWrite1h: Math.max(0, from.cacheWrite1h - part.cacheWrite1h),
528
+ cacheRead: Math.max(0, from.cacheRead - part.cacheRead)
529
+ };
530
+ }
531
+ function subtractBuckets(from, part) {
532
+ const byModel = {};
533
+ for (const [model, usage] of Object.entries(from.byModel)) {
534
+ const taken = part.byModel[model];
535
+ const rest = taken ? subtractUsage(usage, taken) : usage;
536
+ if (totalTokens(rest) > 0) byModel[model] = rest;
537
+ }
538
+ return {
539
+ byModel,
540
+ reportedUsd: from.reportedUsd === void 0 ? void 0 : Math.max(0, from.reportedUsd - (part.reportedUsd ?? 0))
541
+ };
542
+ }
543
+ function isEmpty(bucket) {
544
+ return byModelTotalTokens(bucket.byModel) === 0 && !((bucket.reportedUsd ?? 0) > 0);
545
+ }
546
+ function canonicalByModel(byModel) {
547
+ const out = {};
548
+ for (const [model, usage] of Object.entries(byModel)) {
549
+ const key = canonicalModel(model);
550
+ out[key] = addTokenUsage(out[key] ?? emptyTokenUsage(), usage);
551
+ }
552
+ return out;
553
+ }
554
+ function coversUsage(have, need) {
555
+ return have.input >= need.input && have.output >= need.output && have.cacheWrite5m >= need.cacheWrite5m && have.cacheWrite1h >= need.cacheWrite1h && have.cacheRead >= need.cacheRead;
556
+ }
557
+ function covers(reading, baseline) {
558
+ let compared = false;
559
+ if (baseline.reportedUsd !== void 0 && reading.reportedUsd !== void 0) {
560
+ if (reading.reportedUsd < baseline.reportedUsd) return false;
561
+ compared = true;
562
+ }
563
+ if (byModelTotalTokens(reading.byModel) > 0 && byModelTotalTokens(baseline.byModel) > 0) {
564
+ const have = canonicalByModel(reading.byModel);
565
+ for (const [model, need] of Object.entries(canonicalByModel(baseline.byModel))) {
566
+ if (totalTokens(need) === 0) continue;
567
+ const got = have[model];
568
+ if (!got || !coversUsage(got, need)) return false;
569
+ }
570
+ compared = true;
571
+ }
572
+ return compared;
573
+ }
574
+ var CostLedger = class {
575
+ #carried = emptyBucket();
576
+ #pending;
577
+ #current = emptyBucket();
578
+ carry(state) {
579
+ if (!state) return;
580
+ this.#carried = addBuckets(this.#carried, bucketOf(state));
581
+ }
582
+ carryUnlessRestored(state) {
583
+ if (!state) return;
584
+ const whole = bucketOf(state);
585
+ const lifetime = state.lifetime ? bucketOf(state.lifetime) : whole;
586
+ if (state.lifetime) this.#carried = addBuckets(this.#carried, subtractBuckets(whole, lifetime));
587
+ this.#pending = addBuckets(this.#pending ?? emptyBucket(), lifetime);
588
+ }
589
+ observeCumulative(byModel, reportedCostUsd) {
590
+ const reading = {
591
+ byModel: byModel ?? {},
592
+ reportedUsd: reportedCostUsd
593
+ };
594
+ if (this.#pending && !isEmpty(reading)) {
595
+ if (!covers(reading, this.#pending)) this.#carried = addBuckets(this.#carried, this.#pending);
596
+ this.#pending = void 0;
597
+ }
598
+ if (byModel !== void 0) this.#current = {
599
+ ...this.#current,
600
+ byModel
601
+ };
602
+ if (reportedCostUsd !== void 0) this.#current = {
603
+ ...this.#current,
604
+ reportedUsd: reportedCostUsd
605
+ };
606
+ }
607
+ observeDelta(byModel) {
608
+ this.#current = {
609
+ ...this.#current,
610
+ byModel: mergeByModel(this.#current.byModel, byModel)
611
+ };
612
+ }
613
+ rollover() {
614
+ this.#carried = addBuckets(this.#carried, this.#lifetime());
615
+ this.#pending = void 0;
616
+ this.#current = emptyBucket();
617
+ }
618
+ get byModel() {
619
+ return figuresOf(this.#total()).byModel;
620
+ }
621
+ get breakdown() {
622
+ return costOfByModel(this.byModel ?? {});
623
+ }
624
+ get costUsd() {
625
+ const byModel = this.byModel;
626
+ if (!byModel) return;
627
+ const cost = costOfByModel(byModel);
628
+ return cost.unpriced ? void 0 : cost.total;
629
+ }
630
+ get reportedCostUsd() {
631
+ return this.#total().reportedUsd;
632
+ }
633
+ snapshot() {
634
+ return {
635
+ ...figuresOf(this.#total()),
636
+ lifetime: figuresOf(this.#lifetime())
637
+ };
638
+ }
639
+ #lifetime() {
640
+ return addBuckets(this.#pending ?? emptyBucket(), this.#current);
641
+ }
642
+ #total() {
643
+ return addBuckets(this.#carried, this.#lifetime());
644
+ }
645
+ };
646
+ //#endregion
483
647
  //#region src/lib/event-log.ts
484
648
  var EventLog = class {
485
649
  #events = [];
@@ -921,7 +1085,7 @@ var SessionRunner = class {
921
1085
  #pending = /* @__PURE__ */ new Map();
922
1086
  #turnOverWhileBlocked = false;
923
1087
  #subagents = new SubagentTracker();
924
- #totalCostUsd;
1088
+ #cost = new CostLedger();
925
1089
  #numTurns;
926
1090
  #input = new InputQueue();
927
1091
  #pendingLocalCommands = [];
@@ -986,7 +1150,9 @@ var SessionRunner = class {
986
1150
  meta: this.#config.meta,
987
1151
  scope: this.#config.scope,
988
1152
  title: sessionTitle(this.#config, this.#engineTitle),
989
- totalCostUsd: this.#totalCostUsd,
1153
+ totalCostUsd: this.#cost.reportedCostUsd,
1154
+ costUsd: this.#cost.costUsd,
1155
+ usageByModel: this.#cost.byModel,
990
1156
  numTurns: this.#numTurns,
991
1157
  lastActivityAt: this.#log.lastActivityAt
992
1158
  };
@@ -994,6 +1160,12 @@ var SessionRunner = class {
994
1160
  setTitle(title) {
995
1161
  this.#config = withTitle(this.#config, title);
996
1162
  }
1163
+ carryCost(state) {
1164
+ this.#cost.carryUnlessRestored(state);
1165
+ }
1166
+ costState() {
1167
+ return this.#cost.snapshot();
1168
+ }
997
1169
  start() {
998
1170
  if (this.#started) return this.#runPromise;
999
1171
  this.#started = true;
@@ -1277,6 +1449,7 @@ var SessionRunner = class {
1277
1449
  if (body) {
1278
1450
  this.#emit(body);
1279
1451
  if (body.type === "conversation_reset") {
1452
+ this.#cost.rollover();
1280
1453
  this.#pendingLocalCommands = [];
1281
1454
  if (body.sdkSessionId) this.#sdkSessionId = body.sdkSessionId;
1282
1455
  this.#fetchContextUsage();
@@ -1284,7 +1457,10 @@ var SessionRunner = class {
1284
1457
  if (body.type === "turn_result") {
1285
1458
  this.#compactionTurns += 1;
1286
1459
  if (this.#compactionTurns > 1) this.#settleCompaction();
1287
- this.#totalCostUsd = body.totalCostUsd;
1460
+ this.#cost.observeCumulative(body.usageByModel, body.totalCostUsd);
1461
+ body.totalCostUsd = this.#cost.reportedCostUsd ?? body.totalCostUsd;
1462
+ body.usageByModel = this.#cost.byModel;
1463
+ body.costUsd = this.#cost.costUsd;
1288
1464
  this.#numTurns = body.numTurns;
1289
1465
  if (this.#pending.size === 0) this.#setStatus("idle");
1290
1466
  else this.#turnOverWhileBlocked = true;
@@ -1587,12 +1763,7 @@ var AiSdkRunner = class {
1587
1763
  #abort;
1588
1764
  #turnAccum;
1589
1765
  #numTurns = 0;
1590
- #totalUsage = {
1591
- input: 0,
1592
- output: 0,
1593
- cacheWrite: 0,
1594
- cacheRead: 0
1595
- };
1766
+ #cost = new CostLedger();
1596
1767
  #started = false;
1597
1768
  #closed = false;
1598
1769
  #parked = false;
@@ -1616,10 +1787,15 @@ var AiSdkRunner = class {
1616
1787
  this.#log.restore(snapshot.events, snapshot.seq, state.lastActivityAt);
1617
1788
  this.#messages = [...state.messages];
1618
1789
  this.#pendingLocalCommands = [...state.pendingLocalCommands ?? []];
1619
- for (const call of state.pendingToolCalls) this.#pendingToolCalls.set(call.toolCallId, call);
1790
+ for (const call of state.pendingToolCalls) {
1791
+ const legacy = call.deferred;
1792
+ this.#pendingToolCalls.set(call.toolCallId, legacy === void 0 ? call : {
1793
+ ...call,
1794
+ parkable: call.parkable ?? legacy
1795
+ });
1796
+ }
1620
1797
  this.#dispatched = new Set(state.dispatched);
1621
1798
  this.#numTurns = state.numTurns;
1622
- this.#totalUsage = { ...state.totalUsage };
1623
1799
  this.#turnAccum = state.turnAccum ? { ...state.turnAccum } : void 0;
1624
1800
  if (this.#turnAccum && state.parkedAt !== void 0) this.#turnAccum.startedAt += Date.now() - state.parkedAt;
1625
1801
  this.#permissionMode = state.permissionMode;
@@ -1672,9 +1848,20 @@ var AiSdkRunner = class {
1672
1848
  scope: this.#config.scope,
1673
1849
  title: sessionTitle(this.#config),
1674
1850
  numTurns: this.#numTurns || void 0,
1851
+ costUsd: this.#cost.costUsd,
1852
+ usageByModel: this.#cost.byModel,
1675
1853
  lastActivityAt: this.#log.lastActivityAt
1676
1854
  };
1677
1855
  }
1856
+ carryCost(state) {
1857
+ this.#cost.carry(state);
1858
+ }
1859
+ costState() {
1860
+ return this.#cost.snapshot();
1861
+ }
1862
+ #turnByModel(accum) {
1863
+ return { [this.#modelId() ?? "unknown"]: tokenUsageFromWire(turnUsage(accum)) };
1864
+ }
1678
1865
  start() {
1679
1866
  if (this.#started) return this.#turnChain;
1680
1867
  this.#started = true;
@@ -1712,7 +1899,6 @@ var AiSdkRunner = class {
1712
1899
  pendingToolCalls: [...this.#pendingToolCalls.values()],
1713
1900
  dispatched: [...this.#dispatched],
1714
1901
  numTurns: this.#numTurns,
1715
- totalUsage: { ...this.#totalUsage },
1716
1902
  turnAccum: this.#turnAccum ? { ...this.#turnAccum } : void 0,
1717
1903
  permissionMode: this.#permissionMode,
1718
1904
  model: this.#modelAlias,
@@ -2090,14 +2276,14 @@ var AiSdkRunner = class {
2090
2276
  signal: this.#abort?.signal
2091
2277
  };
2092
2278
  const profile = executor.describe?.(toolCall) ?? {};
2093
- call.deferred = profile.deferred === true ? true : void 0;
2279
+ call.parkable = profile.deferred === true ? true : void 0;
2094
2280
  call.expiresAt = profile.timeoutMs === void 0 ? void 0 : Date.now() + profile.timeoutMs;
2095
2281
  this.#emit({
2096
2282
  type: "execution_dispatched",
2097
2283
  executionId: call.toolCallId,
2098
2284
  toolName: call.toolName,
2099
2285
  backend: profile.backend ?? this.#config.executionBackend ?? "server",
2100
- deferred: call.deferred,
2286
+ deferred: call.parkable,
2101
2287
  expiresAt: call.expiresAt
2102
2288
  });
2103
2289
  const promise = executor.dispatch(toolCall).then((dispatch) => {
@@ -2110,7 +2296,7 @@ var AiSdkRunner = class {
2110
2296
  });
2111
2297
  });
2112
2298
  return {
2113
- deferred: call.deferred === true,
2299
+ deferred: call.parkable === true,
2114
2300
  promise
2115
2301
  };
2116
2302
  }
@@ -2120,7 +2306,7 @@ var AiSdkRunner = class {
2120
2306
  }
2121
2307
  #restingOnDeferred() {
2122
2308
  if (this.#pendingToolCalls.size === 0) return false;
2123
- for (const call of this.#pendingToolCalls.values()) if (call.deferred !== true) return false;
2309
+ for (const call of this.#pendingToolCalls.values()) if (call.parkable !== true) return false;
2124
2310
  return true;
2125
2311
  }
2126
2312
  #applyExecutionResult(executionId, result) {
@@ -2358,10 +2544,8 @@ var AiSdkRunner = class {
2358
2544
  cacheRead: 0
2359
2545
  };
2360
2546
  this.#numTurns += 1;
2361
- this.#totalUsage.input += accum.input;
2362
- this.#totalUsage.output += accum.output;
2363
- this.#totalUsage.cacheWrite += accum.cacheWrite;
2364
- this.#totalUsage.cacheRead += accum.cacheRead;
2547
+ const byModel = this.#turnByModel(accum);
2548
+ this.#cost.observeDelta(byModel);
2365
2549
  this.#emit({
2366
2550
  type: "turn_result",
2367
2551
  subtype: "success",
@@ -2370,7 +2554,9 @@ var AiSdkRunner = class {
2370
2554
  numTurns: this.#numTurns,
2371
2555
  totalCostUsd: 0,
2372
2556
  result: text,
2373
- usage: turnUsage(accum)
2557
+ usage: turnUsage(accum),
2558
+ usageByModel: this.#cost.byModel,
2559
+ costUsd: this.#cost.costUsd
2374
2560
  });
2375
2561
  this.#turnAccum = void 0;
2376
2562
  this.#setStatus("idle");
@@ -4017,6 +4203,29 @@ function skillInfo(skill) {
4017
4203
  enabled: skill.enabled !== false
4018
4204
  };
4019
4205
  }
4206
+ const SKILL_MENTION = /(^|[^A-Za-z0-9_$-])\$([a-z0-9][a-z0-9-]*)(?![A-Za-z0-9_-])/g;
4207
+ function withSkillItems(input, paths) {
4208
+ const present = new Set(input.flatMap((item) => item.type === "skill" ? [item.name] : []));
4209
+ const added = [];
4210
+ for (const item of input) {
4211
+ if (item.type !== "text") continue;
4212
+ for (const match of item.text.matchAll(SKILL_MENTION)) {
4213
+ const name = match[2];
4214
+ const path = paths.get(name);
4215
+ if (path === void 0 || present.has(name)) continue;
4216
+ present.add(name);
4217
+ added.push({
4218
+ type: "skill",
4219
+ name,
4220
+ path
4221
+ });
4222
+ }
4223
+ }
4224
+ return added.length > 0 ? [...input, ...added] : [...input];
4225
+ }
4226
+ function mentionsSkill(input) {
4227
+ return input.some((item) => item.type === "text" && /(^|[^A-Za-z0-9_$-])\$[a-z0-9]/.test(item.text));
4228
+ }
4020
4229
  function mcpStatusOf(authStatus, update, hasTools) {
4021
4230
  if (update?.status === "failed") return update.failureReason === "reauthenticationRequired" ? "needs-auth" : "failed";
4022
4231
  if (update?.status === "cancelled") return "failed";
@@ -4245,7 +4454,7 @@ var CodexRunner = class {
4245
4454
  #workspaceWrite;
4246
4455
  #threadLoaded = false;
4247
4456
  #numTurns = 0;
4248
- #totalCostUsd;
4457
+ #cost = new CostLedger();
4249
4458
  #started = false;
4250
4459
  #closed = false;
4251
4460
  #imageDir;
@@ -4255,6 +4464,7 @@ var CodexRunner = class {
4255
4464
  #replayingHistory = false;
4256
4465
  #skillsFingerprint;
4257
4466
  #skillsRefresh;
4467
+ #skillPaths = /* @__PURE__ */ new Map();
4258
4468
  #producedPaths = /* @__PURE__ */ new Set();
4259
4469
  #mcpStatus = /* @__PURE__ */ new Map();
4260
4470
  #agents = new CodexAgentTracker();
@@ -4312,7 +4522,9 @@ var CodexRunner = class {
4312
4522
  meta: this.#config.meta,
4313
4523
  scope: this.#config.scope,
4314
4524
  title: sessionTitle(this.#config),
4315
- totalCostUsd: this.#totalCostUsd,
4525
+ totalCostUsd: this.#cost.reportedCostUsd,
4526
+ costUsd: this.#cost.costUsd,
4527
+ usageByModel: this.#cost.byModel,
4316
4528
  numTurns: this.#numTurns || void 0,
4317
4529
  lastActivityAt: this.#log.lastActivityAt,
4318
4530
  subagents: this.#agents.list(),
@@ -4322,6 +4534,12 @@ var CodexRunner = class {
4322
4534
  setTitle(title) {
4323
4535
  this.#config = withTitle(this.#config, title);
4324
4536
  }
4537
+ carryCost(state) {
4538
+ this.#cost.carry(state);
4539
+ }
4540
+ costState() {
4541
+ return this.#cost.snapshot();
4542
+ }
4325
4543
  start() {
4326
4544
  if (this.#started) return this.#turnChain;
4327
4545
  this.#started = true;
@@ -4478,7 +4696,7 @@ var CodexRunner = class {
4478
4696
  type: "text",
4479
4697
  text: context
4480
4698
  });
4481
- return parts;
4699
+ return withSkillItems(parts, this.#skillPaths);
4482
4700
  }
4483
4701
  queueLocalCommand(result) {
4484
4702
  if (this.#closed) throw new Error("session is closed");
@@ -4710,11 +4928,14 @@ var CodexRunner = class {
4710
4928
  const entries = Array.isArray(result?.data) ? result.data : [];
4711
4929
  const seen = /* @__PURE__ */ new Set();
4712
4930
  const skills = [];
4931
+ const paths = /* @__PURE__ */ new Map();
4713
4932
  for (const entry of entries) for (const skill of entry?.skills ?? []) {
4714
4933
  if (typeof skill?.name !== "string" || seen.has(skill.name)) continue;
4715
4934
  seen.add(skill.name);
4716
4935
  skills.push(skillInfo(skill));
4936
+ if (typeof skill.path === "string" && skill.path) paths.set(skill.name, skill.path);
4717
4937
  }
4938
+ this.#skillPaths = paths;
4718
4939
  skills.sort((a, b) => a.name.localeCompare(b.name));
4719
4940
  const fingerprint = JSON.stringify(skills);
4720
4941
  if (fingerprint === this.#skillsFingerprint) return;
@@ -4866,6 +5087,10 @@ var CodexRunner = class {
4866
5087
  this.#activeTurn = active;
4867
5088
  try {
4868
5089
  const connection = await this.#ensureThread();
5090
+ if (mentionsSkill(turn.input)) {
5091
+ await this.#skillsRefresh;
5092
+ turn.input = withSkillItems(turn.input, this.#skillPaths);
5093
+ }
4869
5094
  const params = {
4870
5095
  threadId: this.#sdkSessionId,
4871
5096
  input: turn.input,
@@ -5413,23 +5638,27 @@ var CodexRunner = class {
5413
5638
  message: "Turn ended"
5414
5639
  }, "policy");
5415
5640
  this.#numTurns += 1;
5416
- this.#totalCostUsd = 0;
5417
5641
  const usage = active.sawUsage ? active.usage : void 0;
5642
+ const wire = usage ? {
5643
+ input_tokens: Math.max(0, usage.inputTokens - usage.cachedInputTokens),
5644
+ output_tokens: usage.outputTokens + usage.reasoningOutputTokens,
5645
+ cache_creation_input_tokens: usage.cacheWriteInputTokens ?? 0,
5646
+ cache_read_input_tokens: usage.cachedInputTokens
5647
+ } : void 0;
5648
+ const turnByModel = wire ? { [this.#model ?? this.#resolvedModel ?? "unknown"]: tokenUsageFromWire(wire) } : void 0;
5649
+ if (turnByModel) this.#cost.observeDelta(turnByModel);
5418
5650
  this.#emit({
5419
5651
  type: "turn_result",
5420
5652
  subtype: kind === "success" ? "success" : "error_during_execution",
5421
5653
  isError: kind !== "success",
5422
5654
  durationMs: Date.now() - startedAt,
5423
5655
  numTurns: this.#numTurns,
5424
- totalCostUsd: 0,
5656
+ totalCostUsd: this.#cost.reportedCostUsd ?? 0,
5425
5657
  result: kind === "success" ? active.finalText ?? "" : void 0,
5426
5658
  errors,
5427
- usage: usage ? {
5428
- input_tokens: Math.max(0, usage.inputTokens - usage.cachedInputTokens),
5429
- output_tokens: usage.outputTokens + usage.reasoningOutputTokens,
5430
- cache_creation_input_tokens: usage.cacheWriteInputTokens ?? 0,
5431
- cache_read_input_tokens: usage.cachedInputTokens
5432
- } : void 0
5659
+ usage: wire,
5660
+ usageByModel: this.#cost.byModel,
5661
+ costUsd: this.#cost.costUsd
5433
5662
  });
5434
5663
  this.#emitContextUsage(active);
5435
5664
  this.#setStatus("idle");
@@ -5801,6 +6030,6 @@ function getEngineAdapter(engine) {
5801
6030
  return ADAPTERS[engine ?? "claude"];
5802
6031
  }
5803
6032
  //#endregion
5804
- export { AiSdkRunner, BrowserBridgeExecutor, CLAUDE_CATALOG, CODEX_CATALOG, CodexRunner, DeferredExecutor, InputQueue, JsonRpcError, JsonRpcStdioConnection, PendingRequestRegistry, QuickJsExecutor, SUPPORTED_ATTACHMENT_TYPES, SessionRunner, attachmentContentBlocks, attachmentKind, attachmentRef, checkClaudeAuth, claudeAdapter, codexAdapter, connectAppServer, connectMcpTools, createEngineSession, createToolContext, createWebFetch, getEngineAdapter, htmlToMarkdown, isHostAllowed, isPrivateAddress, listCodexSessions, localCommandContext, localCommandTranscript, mcpStatusInfo, modelOptionsFromSdk, normalizeMediaType, normalizeSdkMessage, providerAdapter, replaySlice, resolveBundledClaudeExecutable, resolveBundledCodexExecutable, toApiMessage, toExecutionResult, truncateResultBlocks, withHostTools, withMcpTools };
6033
+ export { AiSdkRunner, BrowserBridgeExecutor, CLAUDE_CATALOG, CODEX_CATALOG, CodexRunner, CostLedger, DeferredExecutor, InputQueue, JsonRpcError, JsonRpcStdioConnection, PendingRequestRegistry, QuickJsExecutor, SUPPORTED_ATTACHMENT_TYPES, SessionRunner, attachmentContentBlocks, attachmentKind, attachmentRef, checkClaudeAuth, claudeAdapter, codexAdapter, connectAppServer, connectMcpTools, createEngineSession, createToolContext, createWebFetch, getEngineAdapter, htmlToMarkdown, isHostAllowed, isPrivateAddress, listCodexSessions, localCommandContext, localCommandTranscript, mcpStatusInfo, modelOptionsFromSdk, normalizeMediaType, normalizeSdkMessage, providerAdapter, replaySlice, resolveBundledClaudeExecutable, resolveBundledCodexExecutable, toApiMessage, toExecutionResult, truncateResultBlocks, withHostTools, withMcpTools };
5805
6034
 
5806
6035
  //# sourceMappingURL=index.mjs.map