@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.
- package/README.md +29 -1
- package/dist/durable/index.cjs +268 -74
- 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 +269 -75
- package/dist/durable/index.js.map +1 -1
- package/dist/{engine-Bij6AdoF.d.cts → engine-JnBbcRxh.d.cts} +123 -19
- package/dist/{engine-Bij6AdoF.d.ts → engine-JnBbcRxh.d.ts} +123 -19
- package/dist/index.cjs +267 -71
- 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 +264 -71
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,8 @@ __export(index_exports, {
|
|
|
38
38
|
OpenCodeToolsTokens: () => OpenCodeToolsTokens,
|
|
39
39
|
OpenCodeTurn: () => OpenCodeTurn,
|
|
40
40
|
OpenCodeTurns: () => OpenCodeTurns,
|
|
41
|
+
addUsage: () => addUsage,
|
|
42
|
+
emptyUsage: () => emptyUsage,
|
|
41
43
|
keyValueOpenCodeSessionStore: () => keyValueOpenCodeSessionStore,
|
|
42
44
|
openCode: () => openCode,
|
|
43
45
|
openCodeControllers: () => openCodeControllers,
|
|
@@ -45,7 +47,8 @@ __export(index_exports, {
|
|
|
45
47
|
sessionOf: () => sessionOf,
|
|
46
48
|
toElicitation: () => toElicitation,
|
|
47
49
|
toFormAnswer: () => toFormAnswer,
|
|
48
|
-
toQuestion: () => toQuestion
|
|
50
|
+
toQuestion: () => toQuestion,
|
|
51
|
+
usageOf: () => usageOf
|
|
49
52
|
});
|
|
50
53
|
module.exports = __toCommonJS(index_exports);
|
|
51
54
|
|
|
@@ -287,6 +290,41 @@ function toFormAnswer(form, answers = {}) {
|
|
|
287
290
|
__name(toFormAnswer, "toFormAnswer");
|
|
288
291
|
|
|
289
292
|
// src/turn.ts
|
|
293
|
+
function emptyUsage() {
|
|
294
|
+
return {
|
|
295
|
+
inputTokens: 0,
|
|
296
|
+
outputTokens: 0,
|
|
297
|
+
cacheReadTokens: 0,
|
|
298
|
+
cacheWriteTokens: 0,
|
|
299
|
+
reasoningTokens: 0,
|
|
300
|
+
costUsd: 0
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
__name(emptyUsage, "emptyUsage");
|
|
304
|
+
function addUsage(a, b) {
|
|
305
|
+
const x = a ?? emptyUsage();
|
|
306
|
+
const y = b ?? emptyUsage();
|
|
307
|
+
return {
|
|
308
|
+
inputTokens: x.inputTokens + (y.inputTokens ?? 0),
|
|
309
|
+
outputTokens: x.outputTokens + (y.outputTokens ?? 0),
|
|
310
|
+
cacheReadTokens: (x.cacheReadTokens ?? 0) + (y.cacheReadTokens ?? 0),
|
|
311
|
+
cacheWriteTokens: (x.cacheWriteTokens ?? 0) + (y.cacheWriteTokens ?? 0),
|
|
312
|
+
reasoningTokens: (x.reasoningTokens ?? 0) + (y.reasoningTokens ?? 0),
|
|
313
|
+
costUsd: x.costUsd + (y.costUsd ?? 0)
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
__name(addUsage, "addUsage");
|
|
317
|
+
function subUsage(a, b) {
|
|
318
|
+
return {
|
|
319
|
+
inputTokens: a.inputTokens - b.inputTokens,
|
|
320
|
+
outputTokens: a.outputTokens - b.outputTokens,
|
|
321
|
+
cacheReadTokens: a.cacheReadTokens - b.cacheReadTokens,
|
|
322
|
+
cacheWriteTokens: a.cacheWriteTokens - b.cacheWriteTokens,
|
|
323
|
+
reasoningTokens: a.reasoningTokens - b.reasoningTokens,
|
|
324
|
+
costUsd: a.costUsd - b.costUsd
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
__name(subUsage, "subUsage");
|
|
290
328
|
var ASK_TOOL_NAME = "ask";
|
|
291
329
|
var FAILED_STATUSES = /* @__PURE__ */ new Set([
|
|
292
330
|
"error",
|
|
@@ -352,11 +390,11 @@ var OpenCodeTurn = class {
|
|
|
352
390
|
hidden = /* @__PURE__ */ new Set();
|
|
353
391
|
milestones = [];
|
|
354
392
|
waiting;
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
393
|
+
/** What this turn object saw spent, and how much of it a milestone already reported. */
|
|
394
|
+
spent = emptyUsage();
|
|
395
|
+
reported = emptyUsage();
|
|
396
|
+
priced = false;
|
|
397
|
+
model;
|
|
360
398
|
stepOpen = false;
|
|
361
399
|
sawText = false;
|
|
362
400
|
separator = false;
|
|
@@ -366,6 +404,11 @@ var OpenCodeTurn = class {
|
|
|
366
404
|
stepError;
|
|
367
405
|
constructor(a) {
|
|
368
406
|
this.a = a;
|
|
407
|
+
this.model = modelOfLabel(a.input.model);
|
|
408
|
+
}
|
|
409
|
+
/** What the run spent so far: carried from before this turn object, plus what it saw. */
|
|
410
|
+
totalUsage() {
|
|
411
|
+
return addUsage(this.a.carried, this.spent);
|
|
369
412
|
}
|
|
370
413
|
get sessionId() {
|
|
371
414
|
return this.a.sessionId;
|
|
@@ -448,7 +491,15 @@ var OpenCodeTurn = class {
|
|
|
448
491
|
this.chain = this.chain.then(() => ask.kind === "approval" ? this.decided(ask, reply, tell) : this.answered(ask, reply, tell)).then(resolve, reject);
|
|
449
492
|
});
|
|
450
493
|
}
|
|
451
|
-
reach(
|
|
494
|
+
reach(reached) {
|
|
495
|
+
const usage = subUsage(this.spent, this.reported);
|
|
496
|
+
this.reported = {
|
|
497
|
+
...this.spent
|
|
498
|
+
};
|
|
499
|
+
const milestone = {
|
|
500
|
+
...reached,
|
|
501
|
+
usage
|
|
502
|
+
};
|
|
452
503
|
const waiting = this.waiting;
|
|
453
504
|
if (waiting !== void 0) {
|
|
454
505
|
this.waiting = void 0;
|
|
@@ -604,9 +655,22 @@ var OpenCodeTurn = class {
|
|
|
604
655
|
}
|
|
605
656
|
}
|
|
606
657
|
async onEvent(e) {
|
|
607
|
-
if (this.ended) return;
|
|
608
658
|
const d = e.data ?? {};
|
|
659
|
+
if (e.type === "session.usage.recorded") {
|
|
660
|
+
await this.usageRecorded(d);
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
if (this.ended) return;
|
|
609
664
|
switch (e.type) {
|
|
665
|
+
case "session.step.started":
|
|
666
|
+
case "session.model.selected": {
|
|
667
|
+
const model = d.model;
|
|
668
|
+
if (typeof model?.id === "string" && typeof model.providerID === "string") this.model = {
|
|
669
|
+
providerID: model.providerID,
|
|
670
|
+
id: model.id
|
|
671
|
+
};
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
610
674
|
case "session.text.delta": {
|
|
611
675
|
const delta = typeof d.delta === "string" ? d.delta : "";
|
|
612
676
|
if (!delta) return;
|
|
@@ -760,41 +824,63 @@ ${delta}` : delta;
|
|
|
760
824
|
});
|
|
761
825
|
}
|
|
762
826
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
};
|
|
774
|
-
|
|
775
|
-
this.
|
|
776
|
-
|
|
777
|
-
|
|
827
|
+
modelId() {
|
|
828
|
+
return this.model !== void 0 ? `${this.model.providerID}/${this.model.id}` : this.a.modelLabel;
|
|
829
|
+
}
|
|
830
|
+
/** One model call's usage and cost, into the ledger and the run's total. */
|
|
831
|
+
async spend(d, purpose) {
|
|
832
|
+
const usage = usageOf(d.tokens);
|
|
833
|
+
const reportedCostUsd = typeof d.cost === "number" && Number.isFinite(d.cost) && d.cost >= 0 ? d.cost : void 0;
|
|
834
|
+
const fallback = reportedCostUsd !== void 0 ? {
|
|
835
|
+
costUsd: reportedCostUsd,
|
|
836
|
+
costSource: "provider"
|
|
837
|
+
} : {};
|
|
838
|
+
let cost = fallback;
|
|
839
|
+
if (this.a.priceStep !== void 0) {
|
|
840
|
+
cost = await this.a.priceStep({
|
|
841
|
+
model: this.model,
|
|
842
|
+
usage,
|
|
843
|
+
reportedCostUsd
|
|
844
|
+
}).catch(() => fallback);
|
|
845
|
+
}
|
|
846
|
+
this.spent = addUsage(this.spent, {
|
|
847
|
+
inputTokens: usage.inputTokens,
|
|
848
|
+
outputTokens: usage.outputTokens,
|
|
849
|
+
cacheReadTokens: usage.cacheReadTokens ?? 0,
|
|
850
|
+
cacheWriteTokens: usage.cacheWriteTokens ?? 0,
|
|
851
|
+
reasoningTokens: usage.reasoningTokens ?? 0,
|
|
852
|
+
costUsd: cost.costUsd ?? 0
|
|
853
|
+
});
|
|
854
|
+
if (cost.costUsd !== void 0) this.priced = true;
|
|
778
855
|
await this.a.store.recordUsage({
|
|
779
856
|
threadId: this.a.input.threadId,
|
|
780
857
|
actorRef: this.a.input.actor.id,
|
|
781
|
-
modelId: this.
|
|
782
|
-
purpose
|
|
858
|
+
modelId: this.modelId(),
|
|
859
|
+
purpose,
|
|
783
860
|
usage,
|
|
784
|
-
...
|
|
785
|
-
costUsd
|
|
786
|
-
} : {}
|
|
861
|
+
...cost
|
|
787
862
|
});
|
|
863
|
+
return {
|
|
864
|
+
usage,
|
|
865
|
+
cost
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
/** `session.usage.recorded`: a call OpenCode made besides the steps (the title, a compaction). */
|
|
869
|
+
async usageRecorded(d) {
|
|
870
|
+
await this.spend(d, d.source === "title" ? "title" : "history_summary");
|
|
871
|
+
}
|
|
872
|
+
async stepEnded(d) {
|
|
873
|
+
const { usage, cost } = await this.spend(d, "chat");
|
|
788
874
|
if (!this.stepOpen) return;
|
|
789
875
|
this.stepOpen = false;
|
|
790
876
|
await this.write({
|
|
791
877
|
kind: "step-finish",
|
|
792
878
|
usage,
|
|
793
|
-
costUsd: costUsd ?? null,
|
|
879
|
+
costUsd: cost.costUsd ?? null,
|
|
794
880
|
...this.segment.reasoningMs > 0 ? {
|
|
795
881
|
reasoningMs: this.segment.reasoningMs
|
|
796
882
|
} : {},
|
|
797
|
-
model: this.
|
|
883
|
+
model: this.modelId()
|
|
798
884
|
});
|
|
799
885
|
}
|
|
800
886
|
/**
|
|
@@ -813,12 +899,7 @@ ${delta}` : delta;
|
|
|
813
899
|
content: s.text,
|
|
814
900
|
runId: this.a.runId,
|
|
815
901
|
...final ? {
|
|
816
|
-
usage:
|
|
817
|
-
...this.usage,
|
|
818
|
-
...this.costUsd !== void 0 ? {
|
|
819
|
-
costUsd: this.costUsd
|
|
820
|
-
} : {}
|
|
821
|
-
}
|
|
902
|
+
usage: this.messageUsage()
|
|
822
903
|
} : {},
|
|
823
904
|
...this.a.input.agentName !== void 0 ? {
|
|
824
905
|
agentName: this.a.input.agentName
|
|
@@ -846,6 +927,26 @@ ${delta}` : delta;
|
|
|
846
927
|
]);
|
|
847
928
|
return message.id;
|
|
848
929
|
}
|
|
930
|
+
/** The run's usage as its last message carries it: the whole run, cache tokens included. */
|
|
931
|
+
messageUsage() {
|
|
932
|
+
const total = this.totalUsage();
|
|
933
|
+
return {
|
|
934
|
+
inputTokens: total.inputTokens,
|
|
935
|
+
outputTokens: total.outputTokens,
|
|
936
|
+
...total.cacheReadTokens > 0 ? {
|
|
937
|
+
cacheReadTokens: total.cacheReadTokens
|
|
938
|
+
} : {},
|
|
939
|
+
...total.cacheWriteTokens > 0 ? {
|
|
940
|
+
cacheWriteTokens: total.cacheWriteTokens
|
|
941
|
+
} : {},
|
|
942
|
+
...total.reasoningTokens > 0 ? {
|
|
943
|
+
reasoningTokens: total.reasoningTokens
|
|
944
|
+
} : {},
|
|
945
|
+
...this.priced || (this.a.carried?.costUsd ?? 0) > 0 ? {
|
|
946
|
+
costUsd: total.costUsd
|
|
947
|
+
} : {}
|
|
948
|
+
};
|
|
949
|
+
}
|
|
849
950
|
/** A request recorded by an earlier process (a turn resumed after a restart). */
|
|
850
951
|
async alreadyRecorded(id) {
|
|
851
952
|
return (await this.a.store.toolCallApproval?.(id) ?? null) !== null;
|
|
@@ -1215,6 +1316,35 @@ ${delta}` : delta;
|
|
|
1215
1316
|
});
|
|
1216
1317
|
}
|
|
1217
1318
|
};
|
|
1319
|
+
function modelOfLabel(label) {
|
|
1320
|
+
const slash = label?.indexOf("/") ?? -1;
|
|
1321
|
+
if (label === void 0 || slash <= 0 || slash === label.length - 1) return void 0;
|
|
1322
|
+
return {
|
|
1323
|
+
providerID: label.slice(0, slash),
|
|
1324
|
+
id: label.slice(slash + 1)
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
__name(modelOfLabel, "modelOfLabel");
|
|
1328
|
+
function usageOf(tokens) {
|
|
1329
|
+
const n = /* @__PURE__ */ __name((v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0, "n");
|
|
1330
|
+
const read = n(tokens?.cache?.read);
|
|
1331
|
+
const write = n(tokens?.cache?.write);
|
|
1332
|
+
const reasoning = n(tokens?.reasoning);
|
|
1333
|
+
return {
|
|
1334
|
+
inputTokens: n(tokens?.input) + read + write,
|
|
1335
|
+
outputTokens: n(tokens?.output),
|
|
1336
|
+
...read > 0 ? {
|
|
1337
|
+
cacheReadTokens: read
|
|
1338
|
+
} : {},
|
|
1339
|
+
...write > 0 ? {
|
|
1340
|
+
cacheWriteTokens: write
|
|
1341
|
+
} : {},
|
|
1342
|
+
...reasoning > 0 ? {
|
|
1343
|
+
reasoningTokens: reasoning
|
|
1344
|
+
} : {}
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
__name(usageOf, "usageOf");
|
|
1218
1348
|
|
|
1219
1349
|
// src/mcp.ts
|
|
1220
1350
|
var LOOP_SERVED_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -1646,7 +1776,7 @@ var OpenCodeTurns = class {
|
|
|
1646
1776
|
spent = /* @__PURE__ */ new Set();
|
|
1647
1777
|
/** When the tools endpoint was last registered for a location (`server|boot|directory|actor`). */
|
|
1648
1778
|
toolsIssued = /* @__PURE__ */ new Map();
|
|
1649
|
-
constructor(host, sessions, settings, store, sink, deps, registry, skills, memory, queue, toolsTokens2) {
|
|
1779
|
+
constructor(host, sessions, settings, store, sink, deps, registry, skills, memory, queue, toolsTokens2, pricingStore, agentOptions) {
|
|
1650
1780
|
this.host = host;
|
|
1651
1781
|
this.sessions = sessions;
|
|
1652
1782
|
this.settings = settings;
|
|
@@ -1658,6 +1788,30 @@ var OpenCodeTurns = class {
|
|
|
1658
1788
|
this.memory = memory;
|
|
1659
1789
|
this.queue = queue;
|
|
1660
1790
|
this.toolsTokens = toolsTokens2;
|
|
1791
|
+
this.prices = new import_nestjs_agent_core4.ModelPriceResolver({
|
|
1792
|
+
pricingStore,
|
|
1793
|
+
catalog: agentOptions?.priceCatalog,
|
|
1794
|
+
log: {
|
|
1795
|
+
info: /* @__PURE__ */ __name((message) => this.logger.log(message), "info"),
|
|
1796
|
+
warn: /* @__PURE__ */ __name((message) => this.logger.warn(message), "warn")
|
|
1797
|
+
}
|
|
1798
|
+
});
|
|
1799
|
+
}
|
|
1800
|
+
prices;
|
|
1801
|
+
/**
|
|
1802
|
+
* What a model call OpenCode made cost, by the same rule the library's loop records its own steps
|
|
1803
|
+
* at: a reported figure wins, else an estimate off the model's price — see
|
|
1804
|
+
* {@link OpenCodeEngineSettings.cost}.
|
|
1805
|
+
*/
|
|
1806
|
+
async priceStep(step) {
|
|
1807
|
+
const { model, usage, reportedCostUsd } = step;
|
|
1808
|
+
const tokens = usage.inputTokens + usage.outputTokens;
|
|
1809
|
+
const reported = reportedCostUsd !== void 0 && (reportedCostUsd > 0 || tokens === 0);
|
|
1810
|
+
if (reported && this.settings.cost !== "estimate") {
|
|
1811
|
+
return (0, import_nestjs_agent_core4.resolveUsageCost)(usage, reportedCostUsd, void 0);
|
|
1812
|
+
}
|
|
1813
|
+
const price = model !== void 0 && tokens > 0 ? await this.prices.priceFor(priceRef(model)) : void 0;
|
|
1814
|
+
return (0, import_nestjs_agent_core4.resolveUsageCost)(usage, price === void 0 ? reportedCostUsd : void 0, price);
|
|
1661
1815
|
}
|
|
1662
1816
|
/** The tools server's name in OpenCode. */
|
|
1663
1817
|
get toolsServer() {
|
|
@@ -2247,8 +2401,8 @@ ${body}
|
|
|
2247
2401
|
}
|
|
2248
2402
|
// ---- prompt / observe / reply --------------------------------------------------------------
|
|
2249
2403
|
/** Start listening to the session (so nothing it says is missed), then send the user message. */
|
|
2250
|
-
async prompt(runId, input, handle) {
|
|
2251
|
-
const live = await this.ensureLive(runId, input, handle, false);
|
|
2404
|
+
async prompt(runId, input, handle, spent) {
|
|
2405
|
+
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2252
2406
|
try {
|
|
2253
2407
|
const prompt = await this.host.promptFor?.({
|
|
2254
2408
|
input,
|
|
@@ -2278,9 +2432,12 @@ ${body}
|
|
|
2278
2432
|
* Wait for the turn's next milestone. In a process that was not following the turn (a resumed
|
|
2279
2433
|
* durable run), the turn is rebuilt and first catches up on requests OpenCode raised meanwhile;
|
|
2280
2434
|
* `session.wait` is the safety net for a terminal event that was missed.
|
|
2435
|
+
*
|
|
2436
|
+
* `spent` is what the run spent before (the sum of the `usage` of its earlier milestones): a turn
|
|
2437
|
+
* rebuilt here starts from it, so the answer it persists carries the whole run's usage.
|
|
2281
2438
|
*/
|
|
2282
|
-
async observe(runId, input, handle) {
|
|
2283
|
-
const live = await this.ensureLive(runId, input, handle, true);
|
|
2439
|
+
async observe(runId, input, handle, spent) {
|
|
2440
|
+
const live = await this.ensureLive(runId, input, handle, true, spent);
|
|
2284
2441
|
const { turn, client } = live;
|
|
2285
2442
|
if (turn.hasMilestone()) return this.reached(runId, input, handle, await turn.next());
|
|
2286
2443
|
let done = false;
|
|
@@ -2319,23 +2476,23 @@ ${body}
|
|
|
2319
2476
|
* request is gone with it: a new session is opened, told what the person decided, and prompted
|
|
2320
2477
|
* to go on.
|
|
2321
2478
|
*/
|
|
2322
|
-
async reply(runId, input, handle, ask, reply) {
|
|
2479
|
+
async reply(runId, input, handle, ask, reply, spent) {
|
|
2323
2480
|
const server = await this.host.server(input.actor);
|
|
2324
2481
|
if (server.key !== handle.serverKey || server.bootId !== handle.bootId) {
|
|
2325
|
-
return this.continueAfterRestart(runId, input, server, ask, reply);
|
|
2482
|
+
return this.continueAfterRestart(runId, input, server, ask, reply, spent);
|
|
2326
2483
|
}
|
|
2327
|
-
const live = await this.ensureLive(runId, input, handle, false);
|
|
2484
|
+
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2328
2485
|
await live.turn.decide(ask, reply);
|
|
2329
2486
|
return handle;
|
|
2330
2487
|
}
|
|
2331
|
-
async continueAfterRestart(runId, input, server, ask, reply) {
|
|
2488
|
+
async continueAfterRestart(runId, input, server, ask, reply, spent) {
|
|
2332
2489
|
const approved = "approved" in reply && reply.approved === true;
|
|
2333
2490
|
const note = ask.kind === "approval" ? approved ? `The user approved the action ${ask.action} you asked permission for. Continue the task.` : `The user did not approve the action ${ask.action}. Continue without it and explain.` : `The user answered your question: ${JSON.stringify("answers" in reply ? reply.answers : {})}. Continue.`;
|
|
2334
2491
|
const thread = await this.store.getThread(input.threadId);
|
|
2335
2492
|
const handle = await this.createSession(runId, input, server, thread?.messages ?? [], note);
|
|
2336
2493
|
await this.refreshInstructions(runId, input, server.client, handle.sessionId);
|
|
2337
2494
|
this.drop(runId);
|
|
2338
|
-
const live = await this.ensureLive(runId, input, handle, false);
|
|
2495
|
+
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2339
2496
|
await live.turn.decide(ask, reply, {
|
|
2340
2497
|
tellOpenCode: false
|
|
2341
2498
|
});
|
|
@@ -2355,7 +2512,7 @@ ${body}
|
|
|
2355
2512
|
sessionID: known.sessionId
|
|
2356
2513
|
});
|
|
2357
2514
|
}
|
|
2358
|
-
async ensureLive(runId, input, handle, catchUp) {
|
|
2515
|
+
async ensureLive(runId, input, handle, catchUp, spent) {
|
|
2359
2516
|
const current = this.live.get(runId);
|
|
2360
2517
|
if (current !== void 0 && current.handle.sessionId === handle.sessionId) return current;
|
|
2361
2518
|
current?.stop();
|
|
@@ -2381,6 +2538,10 @@ ${body}
|
|
|
2381
2538
|
} : {}
|
|
2382
2539
|
}), "approvalFor"),
|
|
2383
2540
|
modelLabel: input.model ?? "opencode",
|
|
2541
|
+
priceStep: /* @__PURE__ */ __name((step) => this.priceStep(step), "priceStep"),
|
|
2542
|
+
...spent !== void 0 ? {
|
|
2543
|
+
carried: spent
|
|
2544
|
+
} : {},
|
|
2384
2545
|
logger: this.logger,
|
|
2385
2546
|
onGranted: /* @__PURE__ */ __name((action, id) => {
|
|
2386
2547
|
const grants = this.grants.get(runId) ?? [];
|
|
@@ -2427,20 +2588,14 @@ ${body}
|
|
|
2427
2588
|
}
|
|
2428
2589
|
return milestone;
|
|
2429
2590
|
}
|
|
2430
|
-
/**
|
|
2431
|
-
|
|
2591
|
+
/**
|
|
2592
|
+
* What the run produced, as the host's settle hooks see it. `usage` is what the run spent — the
|
|
2593
|
+
* runner's sum of its milestones' usage, which a resumed run reads back from its journal — else
|
|
2594
|
+
* what the turn this process follows saw.
|
|
2595
|
+
*/
|
|
2596
|
+
async runResult(runId, input, outcome, durationMs, usage) {
|
|
2432
2597
|
const thread = await this.store.getThread(input.threadId);
|
|
2433
2598
|
const messages = (thread?.messages ?? []).filter((m) => m.role === "assistant" && m.runId === runId);
|
|
2434
|
-
const usage = {
|
|
2435
|
-
inputTokens: 0,
|
|
2436
|
-
outputTokens: 0,
|
|
2437
|
-
costUsd: 0
|
|
2438
|
-
};
|
|
2439
|
-
for (const m of messages) {
|
|
2440
|
-
usage.inputTokens += m.usage?.inputTokens ?? 0;
|
|
2441
|
-
usage.outputTokens += m.usage?.outputTokens ?? 0;
|
|
2442
|
-
usage.costUsd += m.usage?.costUsd ?? 0;
|
|
2443
|
-
}
|
|
2444
2599
|
return {
|
|
2445
2600
|
runId,
|
|
2446
2601
|
input,
|
|
@@ -2485,15 +2640,31 @@ ${body}
|
|
|
2485
2640
|
this.logger.warn(`onSettled failed: ${errorText(error, "error")}`);
|
|
2486
2641
|
}
|
|
2487
2642
|
}
|
|
2488
|
-
/**
|
|
2489
|
-
|
|
2643
|
+
/**
|
|
2644
|
+
* What the run spent: the runner's sum of its milestones, or what the turn this process follows
|
|
2645
|
+
* saw (which starts from that sum) when it saw more — a run that failed or was cancelled between
|
|
2646
|
+
* two milestones.
|
|
2647
|
+
*/
|
|
2648
|
+
spentBy(runId, spent) {
|
|
2649
|
+
const seen = this.live.get(runId)?.turn.totalUsage();
|
|
2650
|
+
if (spent === void 0) return seen ?? emptyUsage();
|
|
2651
|
+
if (seen === void 0) return spent;
|
|
2652
|
+
const tokens = /* @__PURE__ */ __name((u) => u.inputTokens + u.outputTokens, "tokens");
|
|
2653
|
+
return tokens(seen) > tokens(spent) ? seen : spent;
|
|
2654
|
+
}
|
|
2655
|
+
/**
|
|
2656
|
+
* End the run's stream and bookkeeping for how its execution ended. `spent` is what the run spent
|
|
2657
|
+
* (the sum of its milestones' `usage`); omit → what the turn this process follows saw.
|
|
2658
|
+
*/
|
|
2659
|
+
async settle(runId, input, outcome, durationMs, spent) {
|
|
2490
2660
|
if (outcome.status === "failed") {
|
|
2491
|
-
await this.settleFailed(runId, input, outcome.error, durationMs);
|
|
2661
|
+
await this.settleFailed(runId, input, outcome.error, durationMs, spent);
|
|
2492
2662
|
return;
|
|
2493
2663
|
}
|
|
2664
|
+
const usage = this.spentBy(runId, spent);
|
|
2494
2665
|
this.forget(runId);
|
|
2495
2666
|
const writer = await this.sink.open(runId);
|
|
2496
|
-
const result = await this.runResult(runId, input, outcome, durationMs);
|
|
2667
|
+
const result = await this.runResult(runId, input, outcome, durationMs, usage);
|
|
2497
2668
|
await this.amend(writer, result);
|
|
2498
2669
|
if (outcome.status === "interrupted") {
|
|
2499
2670
|
this.logger.log(`agent run ${runId} cancelled`);
|
|
@@ -2521,13 +2692,14 @@ ${body}
|
|
|
2521
2692
|
}
|
|
2522
2693
|
await this.settled(result);
|
|
2523
2694
|
}
|
|
2524
|
-
async settleFailed(runId, input, error, durationMs = 0) {
|
|
2695
|
+
async settleFailed(runId, input, error, durationMs = 0, spent) {
|
|
2696
|
+
const usage = this.spentBy(runId, spent);
|
|
2525
2697
|
this.forget(runId);
|
|
2526
2698
|
const writer = await this.sink.open(runId);
|
|
2527
2699
|
const result = await this.runResult(runId, input, {
|
|
2528
2700
|
status: "failed",
|
|
2529
2701
|
error
|
|
2530
|
-
}, durationMs);
|
|
2702
|
+
}, durationMs, usage);
|
|
2531
2703
|
const worded = (await this.amend(writer, result)).error;
|
|
2532
2704
|
const message = worded ?? (0, import_nestjs_agent_core4.streamFailure)(new Error(error)).message;
|
|
2533
2705
|
this.logger.error(`agent run ${runId} failed: ${error}`);
|
|
@@ -2597,6 +2769,10 @@ OpenCodeTurns = _ts_decorate2([
|
|
|
2597
2769
|
_ts_param2(9, (0, import_common4.Inject)(import_nestjs_agent.AGENT_CHAT_QUEUE)),
|
|
2598
2770
|
_ts_param2(10, (0, import_common4.Optional)()),
|
|
2599
2771
|
_ts_param2(10, (0, import_common4.Inject)(OPENCODE_TOOLS_TOKENS)),
|
|
2772
|
+
_ts_param2(11, (0, import_common4.Optional)()),
|
|
2773
|
+
_ts_param2(11, (0, import_common4.Inject)(import_nestjs_agent_core4.AGENT_PRICING_STORE)),
|
|
2774
|
+
_ts_param2(12, (0, import_common4.Optional)()),
|
|
2775
|
+
_ts_param2(12, (0, import_common4.Inject)(import_nestjs_agent_core4.AGENT_OPTIONS)),
|
|
2600
2776
|
_ts_metadata2("design:type", Function),
|
|
2601
2777
|
_ts_metadata2("design:paramtypes", [
|
|
2602
2778
|
typeof OpenCodeHost === "undefined" ? Object : OpenCodeHost,
|
|
@@ -2609,6 +2785,8 @@ OpenCodeTurns = _ts_decorate2([
|
|
|
2609
2785
|
typeof SkillsConfig === "undefined" ? Object : SkillsConfig,
|
|
2610
2786
|
typeof MemoryConfig === "undefined" ? Object : MemoryConfig,
|
|
2611
2787
|
typeof ChatQueueService === "undefined" ? Object : ChatQueueService,
|
|
2788
|
+
Object,
|
|
2789
|
+
typeof AgentPricingStore === "undefined" ? Object : AgentPricingStore,
|
|
2612
2790
|
Object
|
|
2613
2791
|
])
|
|
2614
2792
|
], OpenCodeTurns);
|
|
@@ -2651,6 +2829,19 @@ function uiEmitter(scope, push) {
|
|
|
2651
2829
|
};
|
|
2652
2830
|
}
|
|
2653
2831
|
__name(uiEmitter, "uiEmitter");
|
|
2832
|
+
function priceRef(model) {
|
|
2833
|
+
const aliases = [
|
|
2834
|
+
model.id
|
|
2835
|
+
];
|
|
2836
|
+
const tail = model.id.slice(model.id.lastIndexOf("/") + 1);
|
|
2837
|
+
if (tail !== model.id && (0, import_nestjs_agent_core4.parseBedrockModelId)(tail) !== void 0) aliases.push(tail);
|
|
2838
|
+
return {
|
|
2839
|
+
modelId: `${model.providerID}/${model.id}`,
|
|
2840
|
+
provider: model.providerID,
|
|
2841
|
+
aliases
|
|
2842
|
+
};
|
|
2843
|
+
}
|
|
2844
|
+
__name(priceRef, "priceRef");
|
|
2654
2845
|
|
|
2655
2846
|
// src/runner.ts
|
|
2656
2847
|
function _ts_decorate3(decorators, target, key, desc) {
|
|
@@ -2752,18 +2943,20 @@ var OpenCodeAgentRunner = class {
|
|
|
2752
2943
|
async run(runId, input) {
|
|
2753
2944
|
const started = Date.now();
|
|
2754
2945
|
this.inputs.set(runId, input);
|
|
2946
|
+
let spent = emptyUsage();
|
|
2755
2947
|
try {
|
|
2756
2948
|
let handle = await this.turns.begin(runId, input);
|
|
2757
2949
|
if (this.cancelled.has(runId)) throw new import_nestjs_agent_core5.RunCancelledError();
|
|
2758
|
-
await this.turns.prompt(runId, input, handle);
|
|
2950
|
+
await this.turns.prompt(runId, input, handle, spent);
|
|
2759
2951
|
for (; ; ) {
|
|
2760
|
-
const milestone = await this.turns.observe(runId, input, handle);
|
|
2952
|
+
const milestone = await this.turns.observe(runId, input, handle, spent);
|
|
2953
|
+
spent = addUsage(spent, milestone.usage);
|
|
2761
2954
|
if (milestone.kind === "finished") {
|
|
2762
|
-
await this.turns.settle(runId, input, milestone.outcome, Date.now() - started);
|
|
2955
|
+
await this.turns.settle(runId, input, milestone.outcome, Date.now() - started, spent);
|
|
2763
2956
|
return;
|
|
2764
2957
|
}
|
|
2765
2958
|
const reply = await this.park(runId, milestone.ask.id, milestone.ask.kind === "approval" ? "approval" : "answers", milestone.timeoutMs);
|
|
2766
|
-
handle = await this.turns.reply(runId, input, handle, milestone.ask, reply);
|
|
2959
|
+
handle = await this.turns.reply(runId, input, handle, milestone.ask, reply, spent);
|
|
2767
2960
|
}
|
|
2768
2961
|
} catch (error) {
|
|
2769
2962
|
if (error instanceof import_nestjs_agent_core5.RunCancelledError) {
|
|
@@ -2773,7 +2966,7 @@ var OpenCodeAgentRunner = class {
|
|
|
2773
2966
|
}, Date.now() - started);
|
|
2774
2967
|
return;
|
|
2775
2968
|
}
|
|
2776
|
-
await this.turns.settleFailed(runId, input, errorText(error, "the turn failed"));
|
|
2969
|
+
await this.turns.settleFailed(runId, input, errorText(error, "the turn failed"), Date.now() - started);
|
|
2777
2970
|
} finally {
|
|
2778
2971
|
this.inputs.delete(runId);
|
|
2779
2972
|
}
|
|
@@ -2926,6 +3119,8 @@ __name(openCodeProviders, "openCodeProviders");
|
|
|
2926
3119
|
OpenCodeToolsTokens,
|
|
2927
3120
|
OpenCodeTurn,
|
|
2928
3121
|
OpenCodeTurns,
|
|
3122
|
+
addUsage,
|
|
3123
|
+
emptyUsage,
|
|
2929
3124
|
keyValueOpenCodeSessionStore,
|
|
2930
3125
|
openCode,
|
|
2931
3126
|
openCodeControllers,
|
|
@@ -2933,6 +3128,7 @@ __name(openCodeProviders, "openCodeProviders");
|
|
|
2933
3128
|
sessionOf,
|
|
2934
3129
|
toElicitation,
|
|
2935
3130
|
toFormAnswer,
|
|
2936
|
-
toQuestion
|
|
3131
|
+
toQuestion,
|
|
3132
|
+
usageOf
|
|
2937
3133
|
});
|
|
2938
3134
|
//# sourceMappingURL=index.cjs.map
|