@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
|
@@ -40,6 +40,9 @@ interface OpenCodeClient {
|
|
|
40
40
|
metadata?: {
|
|
41
41
|
readonly [key: string]: OpenCodeJson;
|
|
42
42
|
};
|
|
43
|
+
/** What the session spent so far, every model call OpenCode made for it (the title too). */
|
|
44
|
+
cost?: number;
|
|
45
|
+
tokens?: OpenCodeTokens;
|
|
43
46
|
}>;
|
|
44
47
|
/** Resolves when the session goes idle. Optional: a safety net for a missed terminal event. */
|
|
45
48
|
wait?(args: {
|
|
@@ -204,6 +207,16 @@ interface OpenCodeFormField {
|
|
|
204
207
|
/** The user may type their own answer instead of picking one of `options`. */
|
|
205
208
|
custom?: boolean;
|
|
206
209
|
}
|
|
210
|
+
/** A token count as OpenCode reports it: `input` is the uncached input, the cache beside it. */
|
|
211
|
+
interface OpenCodeTokens {
|
|
212
|
+
input: number;
|
|
213
|
+
output: number;
|
|
214
|
+
reasoning?: number;
|
|
215
|
+
cache?: {
|
|
216
|
+
read: number;
|
|
217
|
+
write: number;
|
|
218
|
+
};
|
|
219
|
+
}
|
|
207
220
|
|
|
208
221
|
/** How an OpenCode execution ended. */
|
|
209
222
|
type TurnOutcome = {
|
|
@@ -344,6 +357,10 @@ declare class OpenCodeTurn {
|
|
|
344
357
|
private reported;
|
|
345
358
|
private priced;
|
|
346
359
|
private model;
|
|
360
|
+
/** What the session had spent when this turn prompted it; what OpenCode reported since. */
|
|
361
|
+
private baseline;
|
|
362
|
+
private readonly seen;
|
|
363
|
+
private compacted;
|
|
347
364
|
private stepOpen;
|
|
348
365
|
private sawText;
|
|
349
366
|
private separator;
|
|
@@ -352,6 +369,16 @@ declare class OpenCodeTurn {
|
|
|
352
369
|
private ended;
|
|
353
370
|
private stepError;
|
|
354
371
|
constructor(a: OpenCodeTurnArgs);
|
|
372
|
+
/**
|
|
373
|
+
* What the session had spent before this turn prompted it (`session.get`). When the execution
|
|
374
|
+
* ends, what the session spent since that this turn's events did not report — the title OpenCode
|
|
375
|
+
* generates, a compaction: OpenCode records those calls on the session without streaming them — is
|
|
376
|
+
* recorded as a usage row of its own.
|
|
377
|
+
*/
|
|
378
|
+
setBaseline(info: {
|
|
379
|
+
cost?: number;
|
|
380
|
+
tokens?: OpenCodeTokens;
|
|
381
|
+
} | undefined): void;
|
|
355
382
|
/** What the run spent so far: carried from before this turn object, plus what it saw. */
|
|
356
383
|
totalUsage(): OpenCodeUsage;
|
|
357
384
|
get sessionId(): string;
|
|
@@ -418,6 +445,8 @@ declare class OpenCodeTurn {
|
|
|
418
445
|
private onForm;
|
|
419
446
|
private answered;
|
|
420
447
|
private addResult;
|
|
448
|
+
/** What the session spent since the baseline that no event of this turn reported. */
|
|
449
|
+
private unreported;
|
|
421
450
|
private end;
|
|
422
451
|
}
|
|
423
452
|
/**
|
|
@@ -889,6 +918,8 @@ declare class OpenCodeTurns implements OnApplicationShutdown {
|
|
|
889
918
|
*/
|
|
890
919
|
reply(runId: string, input: AgentRunInput, handle: SessionHandle, ask: PendingAsk, reply: HumanReply, spent?: OpenCodeUsage): Promise<SessionHandle>;
|
|
891
920
|
private continueAfterRestart;
|
|
921
|
+
/** What a session spent so far (`session.get`), or nothing when OpenCode does not say. */
|
|
922
|
+
private sessionUsage;
|
|
892
923
|
/** Interrupt the thread's session (cancel). */
|
|
893
924
|
interrupt(input: AgentRunInput): Promise<void>;
|
|
894
925
|
private ensureLive;
|
|
@@ -40,6 +40,9 @@ interface OpenCodeClient {
|
|
|
40
40
|
metadata?: {
|
|
41
41
|
readonly [key: string]: OpenCodeJson;
|
|
42
42
|
};
|
|
43
|
+
/** What the session spent so far, every model call OpenCode made for it (the title too). */
|
|
44
|
+
cost?: number;
|
|
45
|
+
tokens?: OpenCodeTokens;
|
|
43
46
|
}>;
|
|
44
47
|
/** Resolves when the session goes idle. Optional: a safety net for a missed terminal event. */
|
|
45
48
|
wait?(args: {
|
|
@@ -204,6 +207,16 @@ interface OpenCodeFormField {
|
|
|
204
207
|
/** The user may type their own answer instead of picking one of `options`. */
|
|
205
208
|
custom?: boolean;
|
|
206
209
|
}
|
|
210
|
+
/** A token count as OpenCode reports it: `input` is the uncached input, the cache beside it. */
|
|
211
|
+
interface OpenCodeTokens {
|
|
212
|
+
input: number;
|
|
213
|
+
output: number;
|
|
214
|
+
reasoning?: number;
|
|
215
|
+
cache?: {
|
|
216
|
+
read: number;
|
|
217
|
+
write: number;
|
|
218
|
+
};
|
|
219
|
+
}
|
|
207
220
|
|
|
208
221
|
/** How an OpenCode execution ended. */
|
|
209
222
|
type TurnOutcome = {
|
|
@@ -344,6 +357,10 @@ declare class OpenCodeTurn {
|
|
|
344
357
|
private reported;
|
|
345
358
|
private priced;
|
|
346
359
|
private model;
|
|
360
|
+
/** What the session had spent when this turn prompted it; what OpenCode reported since. */
|
|
361
|
+
private baseline;
|
|
362
|
+
private readonly seen;
|
|
363
|
+
private compacted;
|
|
347
364
|
private stepOpen;
|
|
348
365
|
private sawText;
|
|
349
366
|
private separator;
|
|
@@ -352,6 +369,16 @@ declare class OpenCodeTurn {
|
|
|
352
369
|
private ended;
|
|
353
370
|
private stepError;
|
|
354
371
|
constructor(a: OpenCodeTurnArgs);
|
|
372
|
+
/**
|
|
373
|
+
* What the session had spent before this turn prompted it (`session.get`). When the execution
|
|
374
|
+
* ends, what the session spent since that this turn's events did not report — the title OpenCode
|
|
375
|
+
* generates, a compaction: OpenCode records those calls on the session without streaming them — is
|
|
376
|
+
* recorded as a usage row of its own.
|
|
377
|
+
*/
|
|
378
|
+
setBaseline(info: {
|
|
379
|
+
cost?: number;
|
|
380
|
+
tokens?: OpenCodeTokens;
|
|
381
|
+
} | undefined): void;
|
|
355
382
|
/** What the run spent so far: carried from before this turn object, plus what it saw. */
|
|
356
383
|
totalUsage(): OpenCodeUsage;
|
|
357
384
|
get sessionId(): string;
|
|
@@ -418,6 +445,8 @@ declare class OpenCodeTurn {
|
|
|
418
445
|
private onForm;
|
|
419
446
|
private answered;
|
|
420
447
|
private addResult;
|
|
448
|
+
/** What the session spent since the baseline that no event of this turn reported. */
|
|
449
|
+
private unreported;
|
|
421
450
|
private end;
|
|
422
451
|
}
|
|
423
452
|
/**
|
|
@@ -889,6 +918,8 @@ declare class OpenCodeTurns implements OnApplicationShutdown {
|
|
|
889
918
|
*/
|
|
890
919
|
reply(runId: string, input: AgentRunInput, handle: SessionHandle, ask: PendingAsk, reply: HumanReply, spent?: OpenCodeUsage): Promise<SessionHandle>;
|
|
891
920
|
private continueAfterRestart;
|
|
921
|
+
/** What a session spent so far (`session.get`), or nothing when OpenCode does not say. */
|
|
922
|
+
private sessionUsage;
|
|
892
923
|
/** Interrupt the thread's session (cancel). */
|
|
893
924
|
interrupt(input: AgentRunInput): Promise<void>;
|
|
894
925
|
private ensureLive;
|
package/dist/index.cjs
CHANGED
|
@@ -395,6 +395,17 @@ var OpenCodeTurn = class {
|
|
|
395
395
|
reported = emptyUsage();
|
|
396
396
|
priced = false;
|
|
397
397
|
model;
|
|
398
|
+
/** What the session had spent when this turn prompted it; what OpenCode reported since. */
|
|
399
|
+
baseline;
|
|
400
|
+
seen = {
|
|
401
|
+
cost: 0,
|
|
402
|
+
input: 0,
|
|
403
|
+
output: 0,
|
|
404
|
+
reasoning: 0,
|
|
405
|
+
read: 0,
|
|
406
|
+
write: 0
|
|
407
|
+
};
|
|
408
|
+
compacted = false;
|
|
398
409
|
stepOpen = false;
|
|
399
410
|
sawText = false;
|
|
400
411
|
separator = false;
|
|
@@ -406,6 +417,19 @@ var OpenCodeTurn = class {
|
|
|
406
417
|
this.a = a;
|
|
407
418
|
this.model = modelOfLabel(a.input.model);
|
|
408
419
|
}
|
|
420
|
+
/**
|
|
421
|
+
* What the session had spent before this turn prompted it (`session.get`). When the execution
|
|
422
|
+
* ends, what the session spent since that this turn's events did not report — the title OpenCode
|
|
423
|
+
* generates, a compaction: OpenCode records those calls on the session without streaming them — is
|
|
424
|
+
* recorded as a usage row of its own.
|
|
425
|
+
*/
|
|
426
|
+
setBaseline(info) {
|
|
427
|
+
if (info?.tokens === void 0) return;
|
|
428
|
+
this.baseline = {
|
|
429
|
+
cost: Number(info.cost) || 0,
|
|
430
|
+
tokens: info.tokens
|
|
431
|
+
};
|
|
432
|
+
}
|
|
409
433
|
/** What the run spent so far: carried from before this turn object, plus what it saw. */
|
|
410
434
|
totalUsage() {
|
|
411
435
|
return addUsage(this.a.carried, this.spent);
|
|
@@ -662,6 +686,10 @@ var OpenCodeTurn = class {
|
|
|
662
686
|
}
|
|
663
687
|
if (this.ended) return;
|
|
664
688
|
switch (e.type) {
|
|
689
|
+
case "session.compaction.started":
|
|
690
|
+
case "session.compaction.ended":
|
|
691
|
+
this.compacted = true;
|
|
692
|
+
return;
|
|
665
693
|
case "session.step.started":
|
|
666
694
|
case "session.model.selected": {
|
|
667
695
|
const model = d.model;
|
|
@@ -831,6 +859,13 @@ ${delta}` : delta;
|
|
|
831
859
|
async spend(d, purpose) {
|
|
832
860
|
const usage = usageOf(d.tokens);
|
|
833
861
|
const reportedCostUsd = typeof d.cost === "number" && Number.isFinite(d.cost) && d.cost >= 0 ? d.cost : void 0;
|
|
862
|
+
const n = /* @__PURE__ */ __name((v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0, "n");
|
|
863
|
+
this.seen.cost += reportedCostUsd ?? 0;
|
|
864
|
+
this.seen.input += n(d.tokens?.input);
|
|
865
|
+
this.seen.output += n(d.tokens?.output);
|
|
866
|
+
this.seen.reasoning += n(d.tokens?.reasoning);
|
|
867
|
+
this.seen.read += n(d.tokens?.cache?.read);
|
|
868
|
+
this.seen.write += n(d.tokens?.cache?.write);
|
|
834
869
|
const fallback = reportedCostUsd !== void 0 ? {
|
|
835
870
|
costUsd: reportedCostUsd,
|
|
836
871
|
costSource: "provider"
|
|
@@ -1298,9 +1333,39 @@ ${delta}` : delta;
|
|
|
1298
1333
|
this.messageResults.set(messageId, results);
|
|
1299
1334
|
await this.a.store.setMessageToolResults(messageId, results);
|
|
1300
1335
|
}
|
|
1336
|
+
/** What the session spent since the baseline that no event of this turn reported. */
|
|
1337
|
+
async unreported() {
|
|
1338
|
+
const baseline = this.baseline;
|
|
1339
|
+
if (baseline === void 0) return;
|
|
1340
|
+
this.baseline = void 0;
|
|
1341
|
+
const info = await this.a.client.session.get?.({
|
|
1342
|
+
sessionID: this.a.sessionId
|
|
1343
|
+
}).catch(() => void 0);
|
|
1344
|
+
const after = info?.tokens;
|
|
1345
|
+
if (after === void 0) return;
|
|
1346
|
+
const before = baseline.tokens;
|
|
1347
|
+
const left = /* @__PURE__ */ __name((now, then, seen) => Math.max(0, (Number(now) || 0) - (Number(then) || 0) - seen), "left");
|
|
1348
|
+
const tokens = {
|
|
1349
|
+
input: left(after.input, before.input, this.seen.input),
|
|
1350
|
+
output: left(after.output, before.output, this.seen.output),
|
|
1351
|
+
reasoning: left(after.reasoning, before.reasoning, this.seen.reasoning),
|
|
1352
|
+
cache: {
|
|
1353
|
+
read: left(after.cache?.read, before.cache?.read, this.seen.read),
|
|
1354
|
+
write: left(after.cache?.write, before.cache?.write, this.seen.write)
|
|
1355
|
+
}
|
|
1356
|
+
};
|
|
1357
|
+
const total = tokens.input + tokens.output + tokens.reasoning + tokens.cache.read + tokens.cache.write;
|
|
1358
|
+
if (total === 0) return;
|
|
1359
|
+
const cost = left(info?.cost, baseline.cost, this.seen.cost);
|
|
1360
|
+
await this.spend({
|
|
1361
|
+
tokens,
|
|
1362
|
+
cost: cost < 1e-9 ? 0 : cost
|
|
1363
|
+
}, this.compacted ? "history_summary" : "title");
|
|
1364
|
+
}
|
|
1301
1365
|
async end(outcome) {
|
|
1302
1366
|
if (this.ended) return;
|
|
1303
1367
|
this.ended = true;
|
|
1368
|
+
await this.unreported().catch((error) => this.a.logger.warn(`run ${this.a.runId}: ${errorText(error, "could not read the session usage")}`));
|
|
1304
1369
|
if (outcome.status !== "failed" || this.segment.text || this.segment.calls.length > 0 || this.segment.ui.length > 0) {
|
|
1305
1370
|
await this.flush(true);
|
|
1306
1371
|
}
|
|
@@ -2417,6 +2482,7 @@ ${body}
|
|
|
2417
2482
|
})
|
|
2418
2483
|
} : {}
|
|
2419
2484
|
};
|
|
2485
|
+
live.turn.setBaseline(await this.sessionUsage(live.client, handle.sessionId));
|
|
2420
2486
|
await live.client.session.prompt({
|
|
2421
2487
|
sessionID: handle.sessionId,
|
|
2422
2488
|
text: prompt.text,
|
|
@@ -2496,12 +2562,23 @@ ${body}
|
|
|
2496
2562
|
await live.turn.decide(ask, reply, {
|
|
2497
2563
|
tellOpenCode: false
|
|
2498
2564
|
});
|
|
2565
|
+
live.turn.setBaseline(await this.sessionUsage(live.client, handle.sessionId));
|
|
2499
2566
|
await live.client.session.prompt({
|
|
2500
2567
|
sessionID: handle.sessionId,
|
|
2501
2568
|
text: note
|
|
2502
2569
|
});
|
|
2503
2570
|
return handle;
|
|
2504
2571
|
}
|
|
2572
|
+
/** What a session spent so far (`session.get`), or nothing when OpenCode does not say. */
|
|
2573
|
+
async sessionUsage(client, sessionId) {
|
|
2574
|
+
try {
|
|
2575
|
+
return await client.session.get?.({
|
|
2576
|
+
sessionID: sessionId
|
|
2577
|
+
});
|
|
2578
|
+
} catch {
|
|
2579
|
+
return void 0;
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2505
2582
|
/** Interrupt the thread's session (cancel). */
|
|
2506
2583
|
async interrupt(input) {
|
|
2507
2584
|
const known = await this.sessions.get(input.threadId);
|