@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.
- package/README.md +6 -1
- package/dist/durable/index.cjs +77 -0
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.d.cts +1 -1
- package/dist/durable/index.d.ts +1 -1
- package/dist/durable/index.js +77 -0
- package/dist/durable/index.js.map +1 -1
- package/dist/{engine-JnBbcRxh.d.cts → engine-0YkBLWZR.d.cts} +31 -0
- package/dist/{engine-JnBbcRxh.d.ts → engine-0YkBLWZR.d.ts} +31 -0
- package/dist/index.cjs +77 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +77 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ export class AppModule {}
|
|
|
54
54
|
| --- | --- |
|
|
55
55
|
| `session.text.delta` / `session.reasoning.delta` | `text` / `reasoning` |
|
|
56
56
|
| a step (`session.step.ended`) | `step-start` … `step-finish` with usage and cost; a `chat` usage row per step (see [Cost and usage](#cost-and-usage)) |
|
|
57
|
-
|
|
|
57
|
+
| the title OpenCode generates, a compaction | a `title` / `history_summary` usage row (see [Cost and usage](#cost-and-usage)) |
|
|
58
58
|
| tools (`session.tool.*`) | `tool-input-*` / `tool-output*`, code-mode inner calls nested by `parentId` |
|
|
59
59
|
| `permission.asked` | an `action` call + `approval-requested`, recorded `pending_approval`; `approve` / `reject` → `permission.reply` |
|
|
60
60
|
| `form.created` | `elicitation`; `answer` / `skip` → `session.form.reply` / `cancel` |
|
|
@@ -72,6 +72,11 @@ compaction — goes to the same token-usage ledger the library's own loop writes
|
|
|
72
72
|
`agent_token_usage` with `cost_usd` and `cost_source`), so the ledger quota (`quota: { limits }`),
|
|
73
73
|
the dashboard and `GET /quota` see an OpenCode turn like any other.
|
|
74
74
|
|
|
75
|
+
- **The title and compactions.** OpenCode records those calls on the session without streaming
|
|
76
|
+
them. The turn reads what the session had spent (`session.get`) before it prompts, and when the
|
|
77
|
+
execution ends records what the session spent since that its steps did not report, as a `title`
|
|
78
|
+
row (`history_summary` when a compaction ran). A `session.usage.recorded` event, from an OpenCode
|
|
79
|
+
that streams it, is recorded as it arrives and not counted twice.
|
|
75
80
|
- **Tokens.** OpenCode reports the uncached input in `tokens.input` and the cache beside it; the row
|
|
76
81
|
counts the whole input side in `inputTokens`, with `cacheReadTokens` / `cacheWriteTokens` as
|
|
77
82
|
subsets (the library's `MessageUsage`). The row's model is the one OpenCode names for the step
|
package/dist/durable/index.cjs
CHANGED
|
@@ -354,6 +354,17 @@ var OpenCodeTurn = class {
|
|
|
354
354
|
reported = emptyUsage();
|
|
355
355
|
priced = false;
|
|
356
356
|
model;
|
|
357
|
+
/** What the session had spent when this turn prompted it; what OpenCode reported since. */
|
|
358
|
+
baseline;
|
|
359
|
+
seen = {
|
|
360
|
+
cost: 0,
|
|
361
|
+
input: 0,
|
|
362
|
+
output: 0,
|
|
363
|
+
reasoning: 0,
|
|
364
|
+
read: 0,
|
|
365
|
+
write: 0
|
|
366
|
+
};
|
|
367
|
+
compacted = false;
|
|
357
368
|
stepOpen = false;
|
|
358
369
|
sawText = false;
|
|
359
370
|
separator = false;
|
|
@@ -365,6 +376,19 @@ var OpenCodeTurn = class {
|
|
|
365
376
|
this.a = a;
|
|
366
377
|
this.model = modelOfLabel(a.input.model);
|
|
367
378
|
}
|
|
379
|
+
/**
|
|
380
|
+
* What the session had spent before this turn prompted it (`session.get`). When the execution
|
|
381
|
+
* ends, what the session spent since that this turn's events did not report — the title OpenCode
|
|
382
|
+
* generates, a compaction: OpenCode records those calls on the session without streaming them — is
|
|
383
|
+
* recorded as a usage row of its own.
|
|
384
|
+
*/
|
|
385
|
+
setBaseline(info) {
|
|
386
|
+
if (info?.tokens === void 0) return;
|
|
387
|
+
this.baseline = {
|
|
388
|
+
cost: Number(info.cost) || 0,
|
|
389
|
+
tokens: info.tokens
|
|
390
|
+
};
|
|
391
|
+
}
|
|
368
392
|
/** What the run spent so far: carried from before this turn object, plus what it saw. */
|
|
369
393
|
totalUsage() {
|
|
370
394
|
return addUsage(this.a.carried, this.spent);
|
|
@@ -621,6 +645,10 @@ var OpenCodeTurn = class {
|
|
|
621
645
|
}
|
|
622
646
|
if (this.ended) return;
|
|
623
647
|
switch (e.type) {
|
|
648
|
+
case "session.compaction.started":
|
|
649
|
+
case "session.compaction.ended":
|
|
650
|
+
this.compacted = true;
|
|
651
|
+
return;
|
|
624
652
|
case "session.step.started":
|
|
625
653
|
case "session.model.selected": {
|
|
626
654
|
const model = d.model;
|
|
@@ -790,6 +818,13 @@ ${delta}` : delta;
|
|
|
790
818
|
async spend(d, purpose) {
|
|
791
819
|
const usage = usageOf(d.tokens);
|
|
792
820
|
const reportedCostUsd = typeof d.cost === "number" && Number.isFinite(d.cost) && d.cost >= 0 ? d.cost : void 0;
|
|
821
|
+
const n = /* @__PURE__ */ __name((v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0, "n");
|
|
822
|
+
this.seen.cost += reportedCostUsd ?? 0;
|
|
823
|
+
this.seen.input += n(d.tokens?.input);
|
|
824
|
+
this.seen.output += n(d.tokens?.output);
|
|
825
|
+
this.seen.reasoning += n(d.tokens?.reasoning);
|
|
826
|
+
this.seen.read += n(d.tokens?.cache?.read);
|
|
827
|
+
this.seen.write += n(d.tokens?.cache?.write);
|
|
793
828
|
const fallback = reportedCostUsd !== void 0 ? {
|
|
794
829
|
costUsd: reportedCostUsd,
|
|
795
830
|
costSource: "provider"
|
|
@@ -1257,9 +1292,39 @@ ${delta}` : delta;
|
|
|
1257
1292
|
this.messageResults.set(messageId, results);
|
|
1258
1293
|
await this.a.store.setMessageToolResults(messageId, results);
|
|
1259
1294
|
}
|
|
1295
|
+
/** What the session spent since the baseline that no event of this turn reported. */
|
|
1296
|
+
async unreported() {
|
|
1297
|
+
const baseline = this.baseline;
|
|
1298
|
+
if (baseline === void 0) return;
|
|
1299
|
+
this.baseline = void 0;
|
|
1300
|
+
const info = await this.a.client.session.get?.({
|
|
1301
|
+
sessionID: this.a.sessionId
|
|
1302
|
+
}).catch(() => void 0);
|
|
1303
|
+
const after = info?.tokens;
|
|
1304
|
+
if (after === void 0) return;
|
|
1305
|
+
const before = baseline.tokens;
|
|
1306
|
+
const left = /* @__PURE__ */ __name((now, then, seen) => Math.max(0, (Number(now) || 0) - (Number(then) || 0) - seen), "left");
|
|
1307
|
+
const tokens = {
|
|
1308
|
+
input: left(after.input, before.input, this.seen.input),
|
|
1309
|
+
output: left(after.output, before.output, this.seen.output),
|
|
1310
|
+
reasoning: left(after.reasoning, before.reasoning, this.seen.reasoning),
|
|
1311
|
+
cache: {
|
|
1312
|
+
read: left(after.cache?.read, before.cache?.read, this.seen.read),
|
|
1313
|
+
write: left(after.cache?.write, before.cache?.write, this.seen.write)
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
1316
|
+
const total = tokens.input + tokens.output + tokens.reasoning + tokens.cache.read + tokens.cache.write;
|
|
1317
|
+
if (total === 0) return;
|
|
1318
|
+
const cost = left(info?.cost, baseline.cost, this.seen.cost);
|
|
1319
|
+
await this.spend({
|
|
1320
|
+
tokens,
|
|
1321
|
+
cost: cost < 1e-9 ? 0 : cost
|
|
1322
|
+
}, this.compacted ? "history_summary" : "title");
|
|
1323
|
+
}
|
|
1260
1324
|
async end(outcome) {
|
|
1261
1325
|
if (this.ended) return;
|
|
1262
1326
|
this.ended = true;
|
|
1327
|
+
await this.unreported().catch((error) => this.a.logger.warn(`run ${this.a.runId}: ${errorText(error, "could not read the session usage")}`));
|
|
1263
1328
|
if (outcome.status !== "failed" || this.segment.text || this.segment.calls.length > 0 || this.segment.ui.length > 0) {
|
|
1264
1329
|
await this.flush(true);
|
|
1265
1330
|
}
|
|
@@ -2376,6 +2441,7 @@ ${body}
|
|
|
2376
2441
|
})
|
|
2377
2442
|
} : {}
|
|
2378
2443
|
};
|
|
2444
|
+
live.turn.setBaseline(await this.sessionUsage(live.client, handle.sessionId));
|
|
2379
2445
|
await live.client.session.prompt({
|
|
2380
2446
|
sessionID: handle.sessionId,
|
|
2381
2447
|
text: prompt.text,
|
|
@@ -2455,12 +2521,23 @@ ${body}
|
|
|
2455
2521
|
await live.turn.decide(ask, reply, {
|
|
2456
2522
|
tellOpenCode: false
|
|
2457
2523
|
});
|
|
2524
|
+
live.turn.setBaseline(await this.sessionUsage(live.client, handle.sessionId));
|
|
2458
2525
|
await live.client.session.prompt({
|
|
2459
2526
|
sessionID: handle.sessionId,
|
|
2460
2527
|
text: note
|
|
2461
2528
|
});
|
|
2462
2529
|
return handle;
|
|
2463
2530
|
}
|
|
2531
|
+
/** What a session spent so far (`session.get`), or nothing when OpenCode does not say. */
|
|
2532
|
+
async sessionUsage(client, sessionId) {
|
|
2533
|
+
try {
|
|
2534
|
+
return await client.session.get?.({
|
|
2535
|
+
sessionID: sessionId
|
|
2536
|
+
});
|
|
2537
|
+
} catch {
|
|
2538
|
+
return void 0;
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2464
2541
|
/** Interrupt the thread's session (cancel). */
|
|
2465
2542
|
async interrupt(input) {
|
|
2466
2543
|
const known = await this.sessions.get(input.threadId);
|