@dudousxd/nestjs-agent-opencode 0.2.0 → 0.2.1

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,5 +1,5 @@
1
1
  import { AgentEngine } from '@dudousxd/nestjs-agent';
2
- import { O as OpenCodeTurns, a as OpenCodeEngineSettings, b as OpenCodeHost, c as OpenCodeEngineOptions } from '../engine-JnBbcRxh.cjs';
2
+ import { O as OpenCodeTurns, a as OpenCodeEngineSettings, b as OpenCodeHost, c as OpenCodeEngineOptions } from '../engine-0YkBLWZR.cjs';
3
3
  import { AgentRunner, AgentStore, AgentRunInput, AgentRunStartOptions, HumanReply } from '@dudousxd/nestjs-agent-core';
4
4
  import { WorkflowService } from '@dudousxd/nestjs-durable';
5
5
  import { RunGateway, WorkflowCtx } from '@dudousxd/nestjs-durable-core';
@@ -1,5 +1,5 @@
1
1
  import { AgentEngine } from '@dudousxd/nestjs-agent';
2
- import { O as OpenCodeTurns, a as OpenCodeEngineSettings, b as OpenCodeHost, c as OpenCodeEngineOptions } from '../engine-JnBbcRxh.js';
2
+ import { O as OpenCodeTurns, a as OpenCodeEngineSettings, b as OpenCodeHost, c as OpenCodeEngineOptions } from '../engine-0YkBLWZR.js';
3
3
  import { AgentRunner, AgentStore, AgentRunInput, AgentRunStartOptions, HumanReply } from '@dudousxd/nestjs-agent-core';
4
4
  import { WorkflowService } from '@dudousxd/nestjs-durable';
5
5
  import { RunGateway, WorkflowCtx } from '@dudousxd/nestjs-durable-core';
@@ -326,6 +326,17 @@ var OpenCodeTurn = class {
326
326
  reported = emptyUsage();
327
327
  priced = false;
328
328
  model;
329
+ /** What the session had spent when this turn prompted it; what OpenCode reported since. */
330
+ baseline;
331
+ seen = {
332
+ cost: 0,
333
+ input: 0,
334
+ output: 0,
335
+ reasoning: 0,
336
+ read: 0,
337
+ write: 0
338
+ };
339
+ compacted = false;
329
340
  stepOpen = false;
330
341
  sawText = false;
331
342
  separator = false;
@@ -337,6 +348,19 @@ var OpenCodeTurn = class {
337
348
  this.a = a;
338
349
  this.model = modelOfLabel(a.input.model);
339
350
  }
351
+ /**
352
+ * What the session had spent before this turn prompted it (`session.get`). When the execution
353
+ * ends, what the session spent since that this turn's events did not report — the title OpenCode
354
+ * generates, a compaction: OpenCode records those calls on the session without streaming them — is
355
+ * recorded as a usage row of its own.
356
+ */
357
+ setBaseline(info) {
358
+ if (info?.tokens === void 0) return;
359
+ this.baseline = {
360
+ cost: Number(info.cost) || 0,
361
+ tokens: info.tokens
362
+ };
363
+ }
340
364
  /** What the run spent so far: carried from before this turn object, plus what it saw. */
341
365
  totalUsage() {
342
366
  return addUsage(this.a.carried, this.spent);
@@ -593,6 +617,10 @@ var OpenCodeTurn = class {
593
617
  }
594
618
  if (this.ended) return;
595
619
  switch (e.type) {
620
+ case "session.compaction.started":
621
+ case "session.compaction.ended":
622
+ this.compacted = true;
623
+ return;
596
624
  case "session.step.started":
597
625
  case "session.model.selected": {
598
626
  const model = d.model;
@@ -762,6 +790,13 @@ ${delta}` : delta;
762
790
  async spend(d, purpose) {
763
791
  const usage = usageOf(d.tokens);
764
792
  const reportedCostUsd = typeof d.cost === "number" && Number.isFinite(d.cost) && d.cost >= 0 ? d.cost : void 0;
793
+ const n = /* @__PURE__ */ __name((v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0, "n");
794
+ this.seen.cost += reportedCostUsd ?? 0;
795
+ this.seen.input += n(d.tokens?.input);
796
+ this.seen.output += n(d.tokens?.output);
797
+ this.seen.reasoning += n(d.tokens?.reasoning);
798
+ this.seen.read += n(d.tokens?.cache?.read);
799
+ this.seen.write += n(d.tokens?.cache?.write);
765
800
  const fallback = reportedCostUsd !== void 0 ? {
766
801
  costUsd: reportedCostUsd,
767
802
  costSource: "provider"
@@ -1229,9 +1264,39 @@ ${delta}` : delta;
1229
1264
  this.messageResults.set(messageId, results);
1230
1265
  await this.a.store.setMessageToolResults(messageId, results);
1231
1266
  }
1267
+ /** What the session spent since the baseline that no event of this turn reported. */
1268
+ async unreported() {
1269
+ const baseline = this.baseline;
1270
+ if (baseline === void 0) return;
1271
+ this.baseline = void 0;
1272
+ const info = await this.a.client.session.get?.({
1273
+ sessionID: this.a.sessionId
1274
+ }).catch(() => void 0);
1275
+ const after = info?.tokens;
1276
+ if (after === void 0) return;
1277
+ const before = baseline.tokens;
1278
+ const left = /* @__PURE__ */ __name((now, then, seen) => Math.max(0, (Number(now) || 0) - (Number(then) || 0) - seen), "left");
1279
+ const tokens = {
1280
+ input: left(after.input, before.input, this.seen.input),
1281
+ output: left(after.output, before.output, this.seen.output),
1282
+ reasoning: left(after.reasoning, before.reasoning, this.seen.reasoning),
1283
+ cache: {
1284
+ read: left(after.cache?.read, before.cache?.read, this.seen.read),
1285
+ write: left(after.cache?.write, before.cache?.write, this.seen.write)
1286
+ }
1287
+ };
1288
+ const total = tokens.input + tokens.output + tokens.reasoning + tokens.cache.read + tokens.cache.write;
1289
+ if (total === 0) return;
1290
+ const cost = left(info?.cost, baseline.cost, this.seen.cost);
1291
+ await this.spend({
1292
+ tokens,
1293
+ cost: cost < 1e-9 ? 0 : cost
1294
+ }, this.compacted ? "history_summary" : "title");
1295
+ }
1232
1296
  async end(outcome) {
1233
1297
  if (this.ended) return;
1234
1298
  this.ended = true;
1299
+ await this.unreported().catch((error) => this.a.logger.warn(`run ${this.a.runId}: ${errorText(error, "could not read the session usage")}`));
1235
1300
  if (outcome.status !== "failed" || this.segment.text || this.segment.calls.length > 0 || this.segment.ui.length > 0) {
1236
1301
  await this.flush(true);
1237
1302
  }
@@ -2348,6 +2413,7 @@ ${body}
2348
2413
  })
2349
2414
  } : {}
2350
2415
  };
2416
+ live.turn.setBaseline(await this.sessionUsage(live.client, handle.sessionId));
2351
2417
  await live.client.session.prompt({
2352
2418
  sessionID: handle.sessionId,
2353
2419
  text: prompt.text,
@@ -2427,12 +2493,23 @@ ${body}
2427
2493
  await live.turn.decide(ask, reply, {
2428
2494
  tellOpenCode: false
2429
2495
  });
2496
+ live.turn.setBaseline(await this.sessionUsage(live.client, handle.sessionId));
2430
2497
  await live.client.session.prompt({
2431
2498
  sessionID: handle.sessionId,
2432
2499
  text: note
2433
2500
  });
2434
2501
  return handle;
2435
2502
  }
2503
+ /** What a session spent so far (`session.get`), or nothing when OpenCode does not say. */
2504
+ async sessionUsage(client, sessionId) {
2505
+ try {
2506
+ return await client.session.get?.({
2507
+ sessionID: sessionId
2508
+ });
2509
+ } catch {
2510
+ return void 0;
2511
+ }
2512
+ }
2436
2513
  /** Interrupt the thread's session (cancel). */
2437
2514
  async interrupt(input) {
2438
2515
  const known = await this.sessions.get(input.threadId);