@dudousxd/nestjs-agent-opencode 0.1.1 → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  import { AgentDepsFactory, ChatQueueService, AgentEngine } from '@dudousxd/nestjs-agent';
2
2
  import { ConflictException, Logger, OnApplicationShutdown, Type, InjectionToken, Provider } from '@nestjs/common';
3
- import { ElicitationRequest, AgentRunInput, SinkWriter, AgentStore, ApprovalRequirement, AgentUiComponent, HumanReply, Actor, StoredMessage, ToolRegistry, TokenStreamSink, SkillsConfig, MemoryConfig, RolesPolicy, RememberToolInput, AiToolCtx } from '@dudousxd/nestjs-agent-core';
3
+ import { ElicitationRequest, CostSource, AgentRunInput, SinkWriter, AgentStore, ApprovalRequirement, MessageUsage, AgentUiComponent, HumanReply, Actor, StoredMessage, ToolRegistry, TokenStreamSink, SkillsConfig, MemoryConfig, AgentPricingStore, PriceCatalogOptions, RolesPolicy, RememberToolInput, AiToolCtx } from '@dudousxd/nestjs-agent-core';
4
4
  import { IncomingMessage, ServerResponse } from 'node:http';
5
5
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
6
 
@@ -234,14 +234,46 @@ type PendingAsk = {
234
234
  request: ElicitationRequest;
235
235
  messageId?: string;
236
236
  };
237
- /** Where a turn stands: it needs a person, or it is over. */
237
+ /**
238
+ * What a turn spent. `inputTokens` is the whole input side, cached input included (as the library's
239
+ * `MessageUsage` counts it — OpenCode's own `tokens.input` leaves the cache out); `cacheReadTokens`,
240
+ * `cacheWriteTokens` and `reasoningTokens` are subsets. `costUsd` sums every priced call.
241
+ */
242
+ interface OpenCodeUsage {
243
+ inputTokens: number;
244
+ outputTokens: number;
245
+ cacheReadTokens: number;
246
+ cacheWriteTokens: number;
247
+ reasoningTokens: number;
248
+ costUsd: number;
249
+ }
250
+ declare function emptyUsage(): OpenCodeUsage;
251
+ /** `a + b`; a missing side (a milestone journaled before usage travelled) counts as nothing. */
252
+ declare function addUsage(a: OpenCodeUsage | undefined, b: OpenCodeUsage | undefined): OpenCodeUsage;
253
+ /** The model a step ran on, as OpenCode names it (`session.step.started`). */
254
+ interface StepModel {
255
+ providerID: string;
256
+ id: string;
257
+ }
258
+ /** What a model call cost, and where the figure came from. */
259
+ interface StepCost {
260
+ costUsd?: number;
261
+ costSource?: CostSource;
262
+ }
263
+ /**
264
+ * Where a turn stands: it needs a person, or it is over. `usage` is what the turn spent since its
265
+ * previous milestone — journaled with the milestone, so a run resumed in another process still adds
266
+ * up what every process saw.
267
+ */
238
268
  type Milestone = {
239
269
  kind: 'ask';
240
270
  ask: PendingAsk;
241
271
  timeoutMs?: number;
272
+ usage?: OpenCodeUsage;
242
273
  } | {
243
274
  kind: 'finished';
244
275
  outcome: TurnOutcome;
276
+ usage?: OpenCodeUsage;
245
277
  };
246
278
  interface OpenCodeTurnArgs {
247
279
  runId: string;
@@ -252,8 +284,19 @@ interface OpenCodeTurnArgs {
252
284
  store: AgentStore;
253
285
  /** What an action needs before it runs (the module's `ApprovalPolicy`). */
254
286
  approvalFor: (action: string) => Promise<ApprovalRequirement>;
255
- /** The model label usage is recorded under. */
287
+ /** The model label usage is recorded under until OpenCode names the step's model. */
256
288
  modelLabel: string;
289
+ /**
290
+ * What a model call cost: OpenCode's reported figure, or the library's estimate. Omit → OpenCode's
291
+ * figure as reported.
292
+ */
293
+ priceStep?: (step: {
294
+ model: StepModel | undefined;
295
+ usage: MessageUsage;
296
+ reportedCostUsd: number | undefined;
297
+ }) => Promise<StepCost>;
298
+ /** What the run spent before this turn object existed (an earlier process, an earlier session). */
299
+ carried?: OpenCodeUsage;
257
300
  logger: Logger;
258
301
  /**
259
302
  * An action OpenCode was allowed to run (a person approved it, or the policy did): the approval
@@ -296,8 +339,11 @@ declare class OpenCodeTurn {
296
339
  private readonly hidden;
297
340
  private readonly milestones;
298
341
  private waiting;
299
- private readonly usage;
300
- private costUsd;
342
+ /** What this turn object saw spent, and how much of it a milestone already reported. */
343
+ private spent;
344
+ private reported;
345
+ private priced;
346
+ private model;
301
347
  private stepOpen;
302
348
  private sawText;
303
349
  private separator;
@@ -306,6 +352,8 @@ declare class OpenCodeTurn {
306
352
  private ended;
307
353
  private stepError;
308
354
  constructor(a: OpenCodeTurnArgs);
355
+ /** What the run spent so far: carried from before this turn object, plus what it saw. */
356
+ totalUsage(): OpenCodeUsage;
309
357
  get sessionId(): string;
310
358
  get finished(): boolean;
311
359
  /** Feed one of the session's events. */
@@ -348,12 +396,19 @@ declare class OpenCodeTurn {
348
396
  private innerCalls;
349
397
  private onEvent;
350
398
  private settleTool;
399
+ private modelId;
400
+ /** One model call's usage and cost, into the ledger and the run's total. */
401
+ private spend;
402
+ /** `session.usage.recorded`: a call OpenCode made besides the steps (the title, a compaction). */
403
+ private usageRecorded;
351
404
  private stepEnded;
352
405
  /**
353
406
  * Persist what the turn produced since the last flush as one assistant message — the message a
354
407
  * call put to a person hangs on, or the turn's last one. Returns its id.
355
408
  */
356
409
  private flush;
410
+ /** The run's usage as its last message carries it: the whole run, cache tokens included. */
411
+ private messageUsage;
357
412
  /** A request recorded by an earlier process (a turn resumed after a restart). */
358
413
  private alreadyRecorded;
359
414
  /** The persisted assistant message carrying call `id`, so its result lands on the same message. */
@@ -365,6 +420,12 @@ declare class OpenCodeTurn {
365
420
  private addResult;
366
421
  private end;
367
422
  }
423
+ /**
424
+ * OpenCode's token counts as the library's `MessageUsage`. OpenCode reports the uncached input in
425
+ * `input` and the cache reads and writes beside it; the library counts the whole input side in
426
+ * `inputTokens`, the cache counts being subsets of it.
427
+ */
428
+ declare function usageOf(tokens: any): MessageUsage;
368
429
 
369
430
  /**
370
431
  * Where a turn runs and how its OpenCode session is set up — the part only the host knows. The
@@ -471,11 +532,12 @@ interface OpenCodeRunResult {
471
532
  text: string;
472
533
  /** The run's assistant messages, as stored. */
473
534
  messages: StoredMessage[];
474
- usage: {
475
- inputTokens: number;
476
- outputTokens: number;
477
- costUsd: number;
478
- };
535
+ /**
536
+ * What the run spent, over every model call OpenCode made for it (its steps, the title, a
537
+ * compaction) and every process that ran a part of it. `inputTokens` counts cached input too;
538
+ * `cacheReadTokens`/`cacheWriteTokens` are subsets of it.
539
+ */
540
+ usage: OpenCodeUsage;
479
541
  durationMs: number;
480
542
  }
481
543
  /** See {@link OpenCodeHost.beforeSettle}. */
@@ -648,6 +710,19 @@ interface OpenCodeEngineSettings {
648
710
  * parked on a person is not observing: this bounds one stretch of OpenCode working on its own.
649
711
  */
650
712
  turnTimeoutMs?: number;
713
+ /**
714
+ * Whose figure a model call is recorded at. OpenCode prices each call itself, off its model
715
+ * catalog (the `cost` its config declares, else models.dev's list price):
716
+ *
717
+ * - `'reported'` (default) — OpenCode's figure when it has one (`cost_source` `'provider'`); a call
718
+ * OpenCode priced at 0 (no price for the model) is estimated from the library's price instead
719
+ * (`priceCatalog`, the pricing store, the built-in GovCloud Bedrock table, models.dev;
720
+ * `cost_source` `'estimate'`).
721
+ * - `'estimate'` — the library's price whenever it has one, OpenCode's figure otherwise. For
722
+ * models OpenCode prices at a list price that is not yours (Bedrock in GovCloud, a negotiated
723
+ * rate) when you would rather not declare `cost` in OpenCode's config.
724
+ */
725
+ cost?: 'reported' | 'estimate';
651
726
  }
652
727
  /** A thread's session, as the steps of a turn pass it along (and a durable run journals it). */
653
728
  interface SessionHandle {
@@ -699,7 +774,20 @@ declare class OpenCodeTurns implements OnApplicationShutdown {
699
774
  private readonly spent;
700
775
  /** When the tools endpoint was last registered for a location (`server|boot|directory|actor`). */
701
776
  private readonly toolsIssued;
702
- constructor(host: OpenCodeHost, sessions: OpenCodeSessionStore, settings: OpenCodeEngineSettings, store: AgentStore, sink: TokenStreamSink, deps: AgentDepsFactory, registry: ToolRegistry, skills?: SkillsConfig | undefined, memory?: MemoryConfig | undefined, queue?: ChatQueueService | undefined, toolsTokens?: (OpenCodeToolsTokens | null) | undefined);
777
+ constructor(host: OpenCodeHost, sessions: OpenCodeSessionStore, settings: OpenCodeEngineSettings, store: AgentStore, sink: TokenStreamSink, deps: AgentDepsFactory, registry: ToolRegistry, skills?: SkillsConfig | undefined, memory?: MemoryConfig | undefined, queue?: ChatQueueService | undefined, toolsTokens?: (OpenCodeToolsTokens | null) | undefined, pricingStore?: AgentPricingStore, agentOptions?: {
778
+ priceCatalog?: PriceCatalogOptions | false;
779
+ });
780
+ private readonly prices;
781
+ /**
782
+ * What a model call OpenCode made cost, by the same rule the library's loop records its own steps
783
+ * at: a reported figure wins, else an estimate off the model's price — see
784
+ * {@link OpenCodeEngineSettings.cost}.
785
+ */
786
+ priceStep(step: {
787
+ model: StepModel | undefined;
788
+ usage: MessageUsage;
789
+ reportedCostUsd: number | undefined;
790
+ }): Promise<StepCost>;
703
791
  /** The tools server's name in OpenCode. */
704
792
  get toolsServer(): string;
705
793
  /** The roles policy a turn's tools are gated by (the agent's own). */
@@ -784,19 +872,22 @@ declare class OpenCodeTurns implements OnApplicationShutdown {
784
872
  */
785
873
  private addTools;
786
874
  /** Start listening to the session (so nothing it says is missed), then send the user message. */
787
- prompt(runId: string, input: AgentRunInput, handle: SessionHandle): Promise<void>;
875
+ prompt(runId: string, input: AgentRunInput, handle: SessionHandle, spent?: OpenCodeUsage): Promise<void>;
788
876
  /**
789
877
  * Wait for the turn's next milestone. In a process that was not following the turn (a resumed
790
878
  * durable run), the turn is rebuilt and first catches up on requests OpenCode raised meanwhile;
791
879
  * `session.wait` is the safety net for a terminal event that was missed.
880
+ *
881
+ * `spent` is what the run spent before (the sum of the `usage` of its earlier milestones): a turn
882
+ * rebuilt here starts from it, so the answer it persists carries the whole run's usage.
792
883
  */
793
- observe(runId: string, input: AgentRunInput, handle: SessionHandle): Promise<Milestone>;
884
+ observe(runId: string, input: AgentRunInput, handle: SessionHandle, spent?: OpenCodeUsage): Promise<Milestone>;
794
885
  /**
795
886
  * Hand a person's answer back to OpenCode. When the server restarted while the turn waited, the
796
887
  * request is gone with it: a new session is opened, told what the person decided, and prompted
797
888
  * to go on.
798
889
  */
799
- reply(runId: string, input: AgentRunInput, handle: SessionHandle, ask: PendingAsk, reply: HumanReply): Promise<SessionHandle>;
890
+ reply(runId: string, input: AgentRunInput, handle: SessionHandle, ask: PendingAsk, reply: HumanReply, spent?: OpenCodeUsage): Promise<SessionHandle>;
800
891
  private continueAfterRestart;
801
892
  /** Interrupt the thread's session (cancel). */
802
893
  interrupt(input: AgentRunInput): Promise<void>;
@@ -807,7 +898,11 @@ declare class OpenCodeTurns implements OnApplicationShutdown {
807
898
  private forget;
808
899
  /** A person was asked something: tell the host (cards in other channels, wake-ups). */
809
900
  private reached;
810
- /** What the run produced, as the host's settle hooks see it. */
901
+ /**
902
+ * What the run produced, as the host's settle hooks see it. `usage` is what the run spent — the
903
+ * runner's sum of its milestones' usage, which a resumed run reads back from its journal — else
904
+ * what the turn this process follows saw.
905
+ */
811
906
  private runResult;
812
907
  /**
813
908
  * The host's last word on the answer before the stream ends: components to append (a guardrail
@@ -816,9 +911,18 @@ declare class OpenCodeTurns implements OnApplicationShutdown {
816
911
  private amend;
817
912
  /** Delivery, telemetry, spend: after the run settled. Errors are the host's, never the run's. */
818
913
  private settled;
819
- /** End the run's stream and bookkeeping for how its execution ended. */
820
- settle(runId: string, input: AgentRunInput, outcome: TurnOutcome, durationMs: number): Promise<void>;
821
- settleFailed(runId: string, input: AgentRunInput, error: string, durationMs?: number): Promise<void>;
914
+ /**
915
+ * What the run spent: the runner's sum of its milestones, or what the turn this process follows
916
+ * saw (which starts from that sum) when it saw more — a run that failed or was cancelled between
917
+ * two milestones.
918
+ */
919
+ private spentBy;
920
+ /**
921
+ * End the run's stream and bookkeeping for how its execution ended. `spent` is what the run spent
922
+ * (the sum of its milestones' `usage`); omit → what the turn this process follows saw.
923
+ */
924
+ settle(runId: string, input: AgentRunInput, outcome: TurnOutcome, durationMs: number, spent?: OpenCodeUsage): Promise<void>;
925
+ settleFailed(runId: string, input: AgentRunInput, error: string, durationMs?: number, spent?: OpenCodeUsage): Promise<void>;
822
926
  /** Starts the next queued message of the thread; set by the runner (it owns `start`). */
823
927
  startNext: ((next: AgentRunInput, runId: string) => Promise<unknown>) | undefined;
824
928
  /** As `InlineAgentRunner`: hand the thread to its next queued message, and say so on the stream. */
@@ -846,4 +950,4 @@ declare function openCodeControllers(options: OpenCodeEngineSettings): Type<obje
846
950
  /** The providers every OpenCode engine needs: host, session store, settings and the turn steps. */
847
951
  declare function openCodeProviders(options: OpenCodeEngineOptions): Provider[];
848
952
 
849
- export { OpenCodeTurn as A, type OpenCodeTurnContext as B, keyValueOpenCodeSessionStore as C, openCode as D, openCodeControllers as E, openCodeProviders as F, InMemoryOpenCodeSessionStore as I, type Milestone as M, OpenCodeTurns as O, type PendingAsk as P, type SessionHandle as S, type TurnOutcome as T, type OpenCodeEngineSettings as a, type OpenCodeHost as b, type OpenCodeEngineOptions as c, type OpenCodeClient as d, type OpenCodeEvent as e, type OpenCodeForm as f, type OpenCodeFormValue as g, type OpenCodeFormField as h, OpenCodeMcpEndpoint as i, type OpenCodeAmendment as j, type OpenCodeCallContext as k, type OpenCodeKeyValue as l, type OpenCodeModelRef as m, type OpenCodePermissionRequest as n, type OpenCodePermissionRule as o, OpenCodeReplyMismatchError as p, type OpenCodeRunResult as q, type OpenCodeServer as r, type OpenCodeSessionCreate as s, type OpenCodeSessionRef as t, type OpenCodeSessionStore as u, type OpenCodeToolCall as v, OpenCodeToolRefusedError as w, type OpenCodeToolsClaims as x, type OpenCodeToolsOptions as y, OpenCodeToolsTokens as z };
953
+ export { OpenCodeTurn as A, type OpenCodeTurnContext as B, type OpenCodeUsage as C, type StepCost as D, type StepModel as E, addUsage as F, emptyUsage as G, keyValueOpenCodeSessionStore as H, InMemoryOpenCodeSessionStore as I, openCode as J, openCodeControllers as K, openCodeProviders as L, type Milestone as M, usageOf as N, OpenCodeTurns as O, type PendingAsk as P, type SessionHandle as S, type TurnOutcome as T, type OpenCodeEngineSettings as a, type OpenCodeHost as b, type OpenCodeEngineOptions as c, type OpenCodeClient as d, type OpenCodeEvent as e, type OpenCodeForm as f, type OpenCodeFormValue as g, type OpenCodeFormField as h, OpenCodeMcpEndpoint as i, type OpenCodeAmendment as j, type OpenCodeCallContext as k, type OpenCodeKeyValue as l, type OpenCodeModelRef as m, type OpenCodePermissionRequest as n, type OpenCodePermissionRule as o, OpenCodeReplyMismatchError as p, type OpenCodeRunResult as q, type OpenCodeServer as r, type OpenCodeSessionCreate as s, type OpenCodeSessionRef as t, type OpenCodeSessionStore as u, type OpenCodeToolCall as v, OpenCodeToolRefusedError as w, type OpenCodeToolsClaims as x, type OpenCodeToolsOptions as y, OpenCodeToolsTokens as z };
@@ -1,6 +1,6 @@
1
1
  import { AgentDepsFactory, ChatQueueService, AgentEngine } from '@dudousxd/nestjs-agent';
2
2
  import { ConflictException, Logger, OnApplicationShutdown, Type, InjectionToken, Provider } from '@nestjs/common';
3
- import { ElicitationRequest, AgentRunInput, SinkWriter, AgentStore, ApprovalRequirement, AgentUiComponent, HumanReply, Actor, StoredMessage, ToolRegistry, TokenStreamSink, SkillsConfig, MemoryConfig, RolesPolicy, RememberToolInput, AiToolCtx } from '@dudousxd/nestjs-agent-core';
3
+ import { ElicitationRequest, CostSource, AgentRunInput, SinkWriter, AgentStore, ApprovalRequirement, MessageUsage, AgentUiComponent, HumanReply, Actor, StoredMessage, ToolRegistry, TokenStreamSink, SkillsConfig, MemoryConfig, AgentPricingStore, PriceCatalogOptions, RolesPolicy, RememberToolInput, AiToolCtx } from '@dudousxd/nestjs-agent-core';
4
4
  import { IncomingMessage, ServerResponse } from 'node:http';
5
5
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
6
 
@@ -234,14 +234,46 @@ type PendingAsk = {
234
234
  request: ElicitationRequest;
235
235
  messageId?: string;
236
236
  };
237
- /** Where a turn stands: it needs a person, or it is over. */
237
+ /**
238
+ * What a turn spent. `inputTokens` is the whole input side, cached input included (as the library's
239
+ * `MessageUsage` counts it — OpenCode's own `tokens.input` leaves the cache out); `cacheReadTokens`,
240
+ * `cacheWriteTokens` and `reasoningTokens` are subsets. `costUsd` sums every priced call.
241
+ */
242
+ interface OpenCodeUsage {
243
+ inputTokens: number;
244
+ outputTokens: number;
245
+ cacheReadTokens: number;
246
+ cacheWriteTokens: number;
247
+ reasoningTokens: number;
248
+ costUsd: number;
249
+ }
250
+ declare function emptyUsage(): OpenCodeUsage;
251
+ /** `a + b`; a missing side (a milestone journaled before usage travelled) counts as nothing. */
252
+ declare function addUsage(a: OpenCodeUsage | undefined, b: OpenCodeUsage | undefined): OpenCodeUsage;
253
+ /** The model a step ran on, as OpenCode names it (`session.step.started`). */
254
+ interface StepModel {
255
+ providerID: string;
256
+ id: string;
257
+ }
258
+ /** What a model call cost, and where the figure came from. */
259
+ interface StepCost {
260
+ costUsd?: number;
261
+ costSource?: CostSource;
262
+ }
263
+ /**
264
+ * Where a turn stands: it needs a person, or it is over. `usage` is what the turn spent since its
265
+ * previous milestone — journaled with the milestone, so a run resumed in another process still adds
266
+ * up what every process saw.
267
+ */
238
268
  type Milestone = {
239
269
  kind: 'ask';
240
270
  ask: PendingAsk;
241
271
  timeoutMs?: number;
272
+ usage?: OpenCodeUsage;
242
273
  } | {
243
274
  kind: 'finished';
244
275
  outcome: TurnOutcome;
276
+ usage?: OpenCodeUsage;
245
277
  };
246
278
  interface OpenCodeTurnArgs {
247
279
  runId: string;
@@ -252,8 +284,19 @@ interface OpenCodeTurnArgs {
252
284
  store: AgentStore;
253
285
  /** What an action needs before it runs (the module's `ApprovalPolicy`). */
254
286
  approvalFor: (action: string) => Promise<ApprovalRequirement>;
255
- /** The model label usage is recorded under. */
287
+ /** The model label usage is recorded under until OpenCode names the step's model. */
256
288
  modelLabel: string;
289
+ /**
290
+ * What a model call cost: OpenCode's reported figure, or the library's estimate. Omit → OpenCode's
291
+ * figure as reported.
292
+ */
293
+ priceStep?: (step: {
294
+ model: StepModel | undefined;
295
+ usage: MessageUsage;
296
+ reportedCostUsd: number | undefined;
297
+ }) => Promise<StepCost>;
298
+ /** What the run spent before this turn object existed (an earlier process, an earlier session). */
299
+ carried?: OpenCodeUsage;
257
300
  logger: Logger;
258
301
  /**
259
302
  * An action OpenCode was allowed to run (a person approved it, or the policy did): the approval
@@ -296,8 +339,11 @@ declare class OpenCodeTurn {
296
339
  private readonly hidden;
297
340
  private readonly milestones;
298
341
  private waiting;
299
- private readonly usage;
300
- private costUsd;
342
+ /** What this turn object saw spent, and how much of it a milestone already reported. */
343
+ private spent;
344
+ private reported;
345
+ private priced;
346
+ private model;
301
347
  private stepOpen;
302
348
  private sawText;
303
349
  private separator;
@@ -306,6 +352,8 @@ declare class OpenCodeTurn {
306
352
  private ended;
307
353
  private stepError;
308
354
  constructor(a: OpenCodeTurnArgs);
355
+ /** What the run spent so far: carried from before this turn object, plus what it saw. */
356
+ totalUsage(): OpenCodeUsage;
309
357
  get sessionId(): string;
310
358
  get finished(): boolean;
311
359
  /** Feed one of the session's events. */
@@ -348,12 +396,19 @@ declare class OpenCodeTurn {
348
396
  private innerCalls;
349
397
  private onEvent;
350
398
  private settleTool;
399
+ private modelId;
400
+ /** One model call's usage and cost, into the ledger and the run's total. */
401
+ private spend;
402
+ /** `session.usage.recorded`: a call OpenCode made besides the steps (the title, a compaction). */
403
+ private usageRecorded;
351
404
  private stepEnded;
352
405
  /**
353
406
  * Persist what the turn produced since the last flush as one assistant message — the message a
354
407
  * call put to a person hangs on, or the turn's last one. Returns its id.
355
408
  */
356
409
  private flush;
410
+ /** The run's usage as its last message carries it: the whole run, cache tokens included. */
411
+ private messageUsage;
357
412
  /** A request recorded by an earlier process (a turn resumed after a restart). */
358
413
  private alreadyRecorded;
359
414
  /** The persisted assistant message carrying call `id`, so its result lands on the same message. */
@@ -365,6 +420,12 @@ declare class OpenCodeTurn {
365
420
  private addResult;
366
421
  private end;
367
422
  }
423
+ /**
424
+ * OpenCode's token counts as the library's `MessageUsage`. OpenCode reports the uncached input in
425
+ * `input` and the cache reads and writes beside it; the library counts the whole input side in
426
+ * `inputTokens`, the cache counts being subsets of it.
427
+ */
428
+ declare function usageOf(tokens: any): MessageUsage;
368
429
 
369
430
  /**
370
431
  * Where a turn runs and how its OpenCode session is set up — the part only the host knows. The
@@ -471,11 +532,12 @@ interface OpenCodeRunResult {
471
532
  text: string;
472
533
  /** The run's assistant messages, as stored. */
473
534
  messages: StoredMessage[];
474
- usage: {
475
- inputTokens: number;
476
- outputTokens: number;
477
- costUsd: number;
478
- };
535
+ /**
536
+ * What the run spent, over every model call OpenCode made for it (its steps, the title, a
537
+ * compaction) and every process that ran a part of it. `inputTokens` counts cached input too;
538
+ * `cacheReadTokens`/`cacheWriteTokens` are subsets of it.
539
+ */
540
+ usage: OpenCodeUsage;
479
541
  durationMs: number;
480
542
  }
481
543
  /** See {@link OpenCodeHost.beforeSettle}. */
@@ -648,6 +710,19 @@ interface OpenCodeEngineSettings {
648
710
  * parked on a person is not observing: this bounds one stretch of OpenCode working on its own.
649
711
  */
650
712
  turnTimeoutMs?: number;
713
+ /**
714
+ * Whose figure a model call is recorded at. OpenCode prices each call itself, off its model
715
+ * catalog (the `cost` its config declares, else models.dev's list price):
716
+ *
717
+ * - `'reported'` (default) — OpenCode's figure when it has one (`cost_source` `'provider'`); a call
718
+ * OpenCode priced at 0 (no price for the model) is estimated from the library's price instead
719
+ * (`priceCatalog`, the pricing store, the built-in GovCloud Bedrock table, models.dev;
720
+ * `cost_source` `'estimate'`).
721
+ * - `'estimate'` — the library's price whenever it has one, OpenCode's figure otherwise. For
722
+ * models OpenCode prices at a list price that is not yours (Bedrock in GovCloud, a negotiated
723
+ * rate) when you would rather not declare `cost` in OpenCode's config.
724
+ */
725
+ cost?: 'reported' | 'estimate';
651
726
  }
652
727
  /** A thread's session, as the steps of a turn pass it along (and a durable run journals it). */
653
728
  interface SessionHandle {
@@ -699,7 +774,20 @@ declare class OpenCodeTurns implements OnApplicationShutdown {
699
774
  private readonly spent;
700
775
  /** When the tools endpoint was last registered for a location (`server|boot|directory|actor`). */
701
776
  private readonly toolsIssued;
702
- constructor(host: OpenCodeHost, sessions: OpenCodeSessionStore, settings: OpenCodeEngineSettings, store: AgentStore, sink: TokenStreamSink, deps: AgentDepsFactory, registry: ToolRegistry, skills?: SkillsConfig | undefined, memory?: MemoryConfig | undefined, queue?: ChatQueueService | undefined, toolsTokens?: (OpenCodeToolsTokens | null) | undefined);
777
+ constructor(host: OpenCodeHost, sessions: OpenCodeSessionStore, settings: OpenCodeEngineSettings, store: AgentStore, sink: TokenStreamSink, deps: AgentDepsFactory, registry: ToolRegistry, skills?: SkillsConfig | undefined, memory?: MemoryConfig | undefined, queue?: ChatQueueService | undefined, toolsTokens?: (OpenCodeToolsTokens | null) | undefined, pricingStore?: AgentPricingStore, agentOptions?: {
778
+ priceCatalog?: PriceCatalogOptions | false;
779
+ });
780
+ private readonly prices;
781
+ /**
782
+ * What a model call OpenCode made cost, by the same rule the library's loop records its own steps
783
+ * at: a reported figure wins, else an estimate off the model's price — see
784
+ * {@link OpenCodeEngineSettings.cost}.
785
+ */
786
+ priceStep(step: {
787
+ model: StepModel | undefined;
788
+ usage: MessageUsage;
789
+ reportedCostUsd: number | undefined;
790
+ }): Promise<StepCost>;
703
791
  /** The tools server's name in OpenCode. */
704
792
  get toolsServer(): string;
705
793
  /** The roles policy a turn's tools are gated by (the agent's own). */
@@ -784,19 +872,22 @@ declare class OpenCodeTurns implements OnApplicationShutdown {
784
872
  */
785
873
  private addTools;
786
874
  /** Start listening to the session (so nothing it says is missed), then send the user message. */
787
- prompt(runId: string, input: AgentRunInput, handle: SessionHandle): Promise<void>;
875
+ prompt(runId: string, input: AgentRunInput, handle: SessionHandle, spent?: OpenCodeUsage): Promise<void>;
788
876
  /**
789
877
  * Wait for the turn's next milestone. In a process that was not following the turn (a resumed
790
878
  * durable run), the turn is rebuilt and first catches up on requests OpenCode raised meanwhile;
791
879
  * `session.wait` is the safety net for a terminal event that was missed.
880
+ *
881
+ * `spent` is what the run spent before (the sum of the `usage` of its earlier milestones): a turn
882
+ * rebuilt here starts from it, so the answer it persists carries the whole run's usage.
792
883
  */
793
- observe(runId: string, input: AgentRunInput, handle: SessionHandle): Promise<Milestone>;
884
+ observe(runId: string, input: AgentRunInput, handle: SessionHandle, spent?: OpenCodeUsage): Promise<Milestone>;
794
885
  /**
795
886
  * Hand a person's answer back to OpenCode. When the server restarted while the turn waited, the
796
887
  * request is gone with it: a new session is opened, told what the person decided, and prompted
797
888
  * to go on.
798
889
  */
799
- reply(runId: string, input: AgentRunInput, handle: SessionHandle, ask: PendingAsk, reply: HumanReply): Promise<SessionHandle>;
890
+ reply(runId: string, input: AgentRunInput, handle: SessionHandle, ask: PendingAsk, reply: HumanReply, spent?: OpenCodeUsage): Promise<SessionHandle>;
800
891
  private continueAfterRestart;
801
892
  /** Interrupt the thread's session (cancel). */
802
893
  interrupt(input: AgentRunInput): Promise<void>;
@@ -807,7 +898,11 @@ declare class OpenCodeTurns implements OnApplicationShutdown {
807
898
  private forget;
808
899
  /** A person was asked something: tell the host (cards in other channels, wake-ups). */
809
900
  private reached;
810
- /** What the run produced, as the host's settle hooks see it. */
901
+ /**
902
+ * What the run produced, as the host's settle hooks see it. `usage` is what the run spent — the
903
+ * runner's sum of its milestones' usage, which a resumed run reads back from its journal — else
904
+ * what the turn this process follows saw.
905
+ */
811
906
  private runResult;
812
907
  /**
813
908
  * The host's last word on the answer before the stream ends: components to append (a guardrail
@@ -816,9 +911,18 @@ declare class OpenCodeTurns implements OnApplicationShutdown {
816
911
  private amend;
817
912
  /** Delivery, telemetry, spend: after the run settled. Errors are the host's, never the run's. */
818
913
  private settled;
819
- /** End the run's stream and bookkeeping for how its execution ended. */
820
- settle(runId: string, input: AgentRunInput, outcome: TurnOutcome, durationMs: number): Promise<void>;
821
- settleFailed(runId: string, input: AgentRunInput, error: string, durationMs?: number): Promise<void>;
914
+ /**
915
+ * What the run spent: the runner's sum of its milestones, or what the turn this process follows
916
+ * saw (which starts from that sum) when it saw more — a run that failed or was cancelled between
917
+ * two milestones.
918
+ */
919
+ private spentBy;
920
+ /**
921
+ * End the run's stream and bookkeeping for how its execution ended. `spent` is what the run spent
922
+ * (the sum of its milestones' `usage`); omit → what the turn this process follows saw.
923
+ */
924
+ settle(runId: string, input: AgentRunInput, outcome: TurnOutcome, durationMs: number, spent?: OpenCodeUsage): Promise<void>;
925
+ settleFailed(runId: string, input: AgentRunInput, error: string, durationMs?: number, spent?: OpenCodeUsage): Promise<void>;
822
926
  /** Starts the next queued message of the thread; set by the runner (it owns `start`). */
823
927
  startNext: ((next: AgentRunInput, runId: string) => Promise<unknown>) | undefined;
824
928
  /** As `InlineAgentRunner`: hand the thread to its next queued message, and say so on the stream. */
@@ -846,4 +950,4 @@ declare function openCodeControllers(options: OpenCodeEngineSettings): Type<obje
846
950
  /** The providers every OpenCode engine needs: host, session store, settings and the turn steps. */
847
951
  declare function openCodeProviders(options: OpenCodeEngineOptions): Provider[];
848
952
 
849
- export { OpenCodeTurn as A, type OpenCodeTurnContext as B, keyValueOpenCodeSessionStore as C, openCode as D, openCodeControllers as E, openCodeProviders as F, InMemoryOpenCodeSessionStore as I, type Milestone as M, OpenCodeTurns as O, type PendingAsk as P, type SessionHandle as S, type TurnOutcome as T, type OpenCodeEngineSettings as a, type OpenCodeHost as b, type OpenCodeEngineOptions as c, type OpenCodeClient as d, type OpenCodeEvent as e, type OpenCodeForm as f, type OpenCodeFormValue as g, type OpenCodeFormField as h, OpenCodeMcpEndpoint as i, type OpenCodeAmendment as j, type OpenCodeCallContext as k, type OpenCodeKeyValue as l, type OpenCodeModelRef as m, type OpenCodePermissionRequest as n, type OpenCodePermissionRule as o, OpenCodeReplyMismatchError as p, type OpenCodeRunResult as q, type OpenCodeServer as r, type OpenCodeSessionCreate as s, type OpenCodeSessionRef as t, type OpenCodeSessionStore as u, type OpenCodeToolCall as v, OpenCodeToolRefusedError as w, type OpenCodeToolsClaims as x, type OpenCodeToolsOptions as y, OpenCodeToolsTokens as z };
953
+ export { OpenCodeTurn as A, type OpenCodeTurnContext as B, type OpenCodeUsage as C, type StepCost as D, type StepModel as E, addUsage as F, emptyUsage as G, keyValueOpenCodeSessionStore as H, InMemoryOpenCodeSessionStore as I, openCode as J, openCodeControllers as K, openCodeProviders as L, type Milestone as M, usageOf as N, OpenCodeTurns as O, type PendingAsk as P, type SessionHandle as S, type TurnOutcome as T, type OpenCodeEngineSettings as a, type OpenCodeHost as b, type OpenCodeEngineOptions as c, type OpenCodeClient as d, type OpenCodeEvent as e, type OpenCodeForm as f, type OpenCodeFormValue as g, type OpenCodeFormField as h, OpenCodeMcpEndpoint as i, type OpenCodeAmendment as j, type OpenCodeCallContext as k, type OpenCodeKeyValue as l, type OpenCodeModelRef as m, type OpenCodePermissionRequest as n, type OpenCodePermissionRule as o, OpenCodeReplyMismatchError as p, type OpenCodeRunResult as q, type OpenCodeServer as r, type OpenCodeSessionCreate as s, type OpenCodeSessionRef as t, type OpenCodeSessionStore as u, type OpenCodeToolCall as v, OpenCodeToolRefusedError as w, type OpenCodeToolsClaims as x, type OpenCodeToolsOptions as y, OpenCodeToolsTokens as z };