@dudousxd/nestjs-agent-opencode 0.1.2 → 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 -75
- 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 -76
- 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 -72
- 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 -72
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
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,42 +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
|
-
costSource: "provider"
|
|
787
|
-
} : {}
|
|
861
|
+
...cost
|
|
788
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");
|
|
789
874
|
if (!this.stepOpen) return;
|
|
790
875
|
this.stepOpen = false;
|
|
791
876
|
await this.write({
|
|
792
877
|
kind: "step-finish",
|
|
793
878
|
usage,
|
|
794
|
-
costUsd: costUsd ?? null,
|
|
879
|
+
costUsd: cost.costUsd ?? null,
|
|
795
880
|
...this.segment.reasoningMs > 0 ? {
|
|
796
881
|
reasoningMs: this.segment.reasoningMs
|
|
797
882
|
} : {},
|
|
798
|
-
model: this.
|
|
883
|
+
model: this.modelId()
|
|
799
884
|
});
|
|
800
885
|
}
|
|
801
886
|
/**
|
|
@@ -814,12 +899,7 @@ ${delta}` : delta;
|
|
|
814
899
|
content: s.text,
|
|
815
900
|
runId: this.a.runId,
|
|
816
901
|
...final ? {
|
|
817
|
-
usage:
|
|
818
|
-
...this.usage,
|
|
819
|
-
...this.costUsd !== void 0 ? {
|
|
820
|
-
costUsd: this.costUsd
|
|
821
|
-
} : {}
|
|
822
|
-
}
|
|
902
|
+
usage: this.messageUsage()
|
|
823
903
|
} : {},
|
|
824
904
|
...this.a.input.agentName !== void 0 ? {
|
|
825
905
|
agentName: this.a.input.agentName
|
|
@@ -847,6 +927,26 @@ ${delta}` : delta;
|
|
|
847
927
|
]);
|
|
848
928
|
return message.id;
|
|
849
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
|
+
}
|
|
850
950
|
/** A request recorded by an earlier process (a turn resumed after a restart). */
|
|
851
951
|
async alreadyRecorded(id) {
|
|
852
952
|
return (await this.a.store.toolCallApproval?.(id) ?? null) !== null;
|
|
@@ -1216,6 +1316,35 @@ ${delta}` : delta;
|
|
|
1216
1316
|
});
|
|
1217
1317
|
}
|
|
1218
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");
|
|
1219
1348
|
|
|
1220
1349
|
// src/mcp.ts
|
|
1221
1350
|
var LOOP_SERVED_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -1647,7 +1776,7 @@ var OpenCodeTurns = class {
|
|
|
1647
1776
|
spent = /* @__PURE__ */ new Set();
|
|
1648
1777
|
/** When the tools endpoint was last registered for a location (`server|boot|directory|actor`). */
|
|
1649
1778
|
toolsIssued = /* @__PURE__ */ new Map();
|
|
1650
|
-
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) {
|
|
1651
1780
|
this.host = host;
|
|
1652
1781
|
this.sessions = sessions;
|
|
1653
1782
|
this.settings = settings;
|
|
@@ -1659,6 +1788,30 @@ var OpenCodeTurns = class {
|
|
|
1659
1788
|
this.memory = memory;
|
|
1660
1789
|
this.queue = queue;
|
|
1661
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);
|
|
1662
1815
|
}
|
|
1663
1816
|
/** The tools server's name in OpenCode. */
|
|
1664
1817
|
get toolsServer() {
|
|
@@ -2248,8 +2401,8 @@ ${body}
|
|
|
2248
2401
|
}
|
|
2249
2402
|
// ---- prompt / observe / reply --------------------------------------------------------------
|
|
2250
2403
|
/** Start listening to the session (so nothing it says is missed), then send the user message. */
|
|
2251
|
-
async prompt(runId, input, handle) {
|
|
2252
|
-
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);
|
|
2253
2406
|
try {
|
|
2254
2407
|
const prompt = await this.host.promptFor?.({
|
|
2255
2408
|
input,
|
|
@@ -2279,9 +2432,12 @@ ${body}
|
|
|
2279
2432
|
* Wait for the turn's next milestone. In a process that was not following the turn (a resumed
|
|
2280
2433
|
* durable run), the turn is rebuilt and first catches up on requests OpenCode raised meanwhile;
|
|
2281
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.
|
|
2282
2438
|
*/
|
|
2283
|
-
async observe(runId, input, handle) {
|
|
2284
|
-
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);
|
|
2285
2441
|
const { turn, client } = live;
|
|
2286
2442
|
if (turn.hasMilestone()) return this.reached(runId, input, handle, await turn.next());
|
|
2287
2443
|
let done = false;
|
|
@@ -2320,23 +2476,23 @@ ${body}
|
|
|
2320
2476
|
* request is gone with it: a new session is opened, told what the person decided, and prompted
|
|
2321
2477
|
* to go on.
|
|
2322
2478
|
*/
|
|
2323
|
-
async reply(runId, input, handle, ask, reply) {
|
|
2479
|
+
async reply(runId, input, handle, ask, reply, spent) {
|
|
2324
2480
|
const server = await this.host.server(input.actor);
|
|
2325
2481
|
if (server.key !== handle.serverKey || server.bootId !== handle.bootId) {
|
|
2326
|
-
return this.continueAfterRestart(runId, input, server, ask, reply);
|
|
2482
|
+
return this.continueAfterRestart(runId, input, server, ask, reply, spent);
|
|
2327
2483
|
}
|
|
2328
|
-
const live = await this.ensureLive(runId, input, handle, false);
|
|
2484
|
+
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2329
2485
|
await live.turn.decide(ask, reply);
|
|
2330
2486
|
return handle;
|
|
2331
2487
|
}
|
|
2332
|
-
async continueAfterRestart(runId, input, server, ask, reply) {
|
|
2488
|
+
async continueAfterRestart(runId, input, server, ask, reply, spent) {
|
|
2333
2489
|
const approved = "approved" in reply && reply.approved === true;
|
|
2334
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.`;
|
|
2335
2491
|
const thread = await this.store.getThread(input.threadId);
|
|
2336
2492
|
const handle = await this.createSession(runId, input, server, thread?.messages ?? [], note);
|
|
2337
2493
|
await this.refreshInstructions(runId, input, server.client, handle.sessionId);
|
|
2338
2494
|
this.drop(runId);
|
|
2339
|
-
const live = await this.ensureLive(runId, input, handle, false);
|
|
2495
|
+
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2340
2496
|
await live.turn.decide(ask, reply, {
|
|
2341
2497
|
tellOpenCode: false
|
|
2342
2498
|
});
|
|
@@ -2356,7 +2512,7 @@ ${body}
|
|
|
2356
2512
|
sessionID: known.sessionId
|
|
2357
2513
|
});
|
|
2358
2514
|
}
|
|
2359
|
-
async ensureLive(runId, input, handle, catchUp) {
|
|
2515
|
+
async ensureLive(runId, input, handle, catchUp, spent) {
|
|
2360
2516
|
const current = this.live.get(runId);
|
|
2361
2517
|
if (current !== void 0 && current.handle.sessionId === handle.sessionId) return current;
|
|
2362
2518
|
current?.stop();
|
|
@@ -2382,6 +2538,10 @@ ${body}
|
|
|
2382
2538
|
} : {}
|
|
2383
2539
|
}), "approvalFor"),
|
|
2384
2540
|
modelLabel: input.model ?? "opencode",
|
|
2541
|
+
priceStep: /* @__PURE__ */ __name((step) => this.priceStep(step), "priceStep"),
|
|
2542
|
+
...spent !== void 0 ? {
|
|
2543
|
+
carried: spent
|
|
2544
|
+
} : {},
|
|
2385
2545
|
logger: this.logger,
|
|
2386
2546
|
onGranted: /* @__PURE__ */ __name((action, id) => {
|
|
2387
2547
|
const grants = this.grants.get(runId) ?? [];
|
|
@@ -2428,20 +2588,14 @@ ${body}
|
|
|
2428
2588
|
}
|
|
2429
2589
|
return milestone;
|
|
2430
2590
|
}
|
|
2431
|
-
/**
|
|
2432
|
-
|
|
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) {
|
|
2433
2597
|
const thread = await this.store.getThread(input.threadId);
|
|
2434
2598
|
const messages = (thread?.messages ?? []).filter((m) => m.role === "assistant" && m.runId === runId);
|
|
2435
|
-
const usage = {
|
|
2436
|
-
inputTokens: 0,
|
|
2437
|
-
outputTokens: 0,
|
|
2438
|
-
costUsd: 0
|
|
2439
|
-
};
|
|
2440
|
-
for (const m of messages) {
|
|
2441
|
-
usage.inputTokens += m.usage?.inputTokens ?? 0;
|
|
2442
|
-
usage.outputTokens += m.usage?.outputTokens ?? 0;
|
|
2443
|
-
usage.costUsd += m.usage?.costUsd ?? 0;
|
|
2444
|
-
}
|
|
2445
2599
|
return {
|
|
2446
2600
|
runId,
|
|
2447
2601
|
input,
|
|
@@ -2486,15 +2640,31 @@ ${body}
|
|
|
2486
2640
|
this.logger.warn(`onSettled failed: ${errorText(error, "error")}`);
|
|
2487
2641
|
}
|
|
2488
2642
|
}
|
|
2489
|
-
/**
|
|
2490
|
-
|
|
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) {
|
|
2491
2660
|
if (outcome.status === "failed") {
|
|
2492
|
-
await this.settleFailed(runId, input, outcome.error, durationMs);
|
|
2661
|
+
await this.settleFailed(runId, input, outcome.error, durationMs, spent);
|
|
2493
2662
|
return;
|
|
2494
2663
|
}
|
|
2664
|
+
const usage = this.spentBy(runId, spent);
|
|
2495
2665
|
this.forget(runId);
|
|
2496
2666
|
const writer = await this.sink.open(runId);
|
|
2497
|
-
const result = await this.runResult(runId, input, outcome, durationMs);
|
|
2667
|
+
const result = await this.runResult(runId, input, outcome, durationMs, usage);
|
|
2498
2668
|
await this.amend(writer, result);
|
|
2499
2669
|
if (outcome.status === "interrupted") {
|
|
2500
2670
|
this.logger.log(`agent run ${runId} cancelled`);
|
|
@@ -2522,13 +2692,14 @@ ${body}
|
|
|
2522
2692
|
}
|
|
2523
2693
|
await this.settled(result);
|
|
2524
2694
|
}
|
|
2525
|
-
async settleFailed(runId, input, error, durationMs = 0) {
|
|
2695
|
+
async settleFailed(runId, input, error, durationMs = 0, spent) {
|
|
2696
|
+
const usage = this.spentBy(runId, spent);
|
|
2526
2697
|
this.forget(runId);
|
|
2527
2698
|
const writer = await this.sink.open(runId);
|
|
2528
2699
|
const result = await this.runResult(runId, input, {
|
|
2529
2700
|
status: "failed",
|
|
2530
2701
|
error
|
|
2531
|
-
}, durationMs);
|
|
2702
|
+
}, durationMs, usage);
|
|
2532
2703
|
const worded = (await this.amend(writer, result)).error;
|
|
2533
2704
|
const message = worded ?? (0, import_nestjs_agent_core4.streamFailure)(new Error(error)).message;
|
|
2534
2705
|
this.logger.error(`agent run ${runId} failed: ${error}`);
|
|
@@ -2598,6 +2769,10 @@ OpenCodeTurns = _ts_decorate2([
|
|
|
2598
2769
|
_ts_param2(9, (0, import_common4.Inject)(import_nestjs_agent.AGENT_CHAT_QUEUE)),
|
|
2599
2770
|
_ts_param2(10, (0, import_common4.Optional)()),
|
|
2600
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)),
|
|
2601
2776
|
_ts_metadata2("design:type", Function),
|
|
2602
2777
|
_ts_metadata2("design:paramtypes", [
|
|
2603
2778
|
typeof OpenCodeHost === "undefined" ? Object : OpenCodeHost,
|
|
@@ -2610,6 +2785,8 @@ OpenCodeTurns = _ts_decorate2([
|
|
|
2610
2785
|
typeof SkillsConfig === "undefined" ? Object : SkillsConfig,
|
|
2611
2786
|
typeof MemoryConfig === "undefined" ? Object : MemoryConfig,
|
|
2612
2787
|
typeof ChatQueueService === "undefined" ? Object : ChatQueueService,
|
|
2788
|
+
Object,
|
|
2789
|
+
typeof AgentPricingStore === "undefined" ? Object : AgentPricingStore,
|
|
2613
2790
|
Object
|
|
2614
2791
|
])
|
|
2615
2792
|
], OpenCodeTurns);
|
|
@@ -2652,6 +2829,19 @@ function uiEmitter(scope, push) {
|
|
|
2652
2829
|
};
|
|
2653
2830
|
}
|
|
2654
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");
|
|
2655
2845
|
|
|
2656
2846
|
// src/runner.ts
|
|
2657
2847
|
function _ts_decorate3(decorators, target, key, desc) {
|
|
@@ -2753,18 +2943,20 @@ var OpenCodeAgentRunner = class {
|
|
|
2753
2943
|
async run(runId, input) {
|
|
2754
2944
|
const started = Date.now();
|
|
2755
2945
|
this.inputs.set(runId, input);
|
|
2946
|
+
let spent = emptyUsage();
|
|
2756
2947
|
try {
|
|
2757
2948
|
let handle = await this.turns.begin(runId, input);
|
|
2758
2949
|
if (this.cancelled.has(runId)) throw new import_nestjs_agent_core5.RunCancelledError();
|
|
2759
|
-
await this.turns.prompt(runId, input, handle);
|
|
2950
|
+
await this.turns.prompt(runId, input, handle, spent);
|
|
2760
2951
|
for (; ; ) {
|
|
2761
|
-
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);
|
|
2762
2954
|
if (milestone.kind === "finished") {
|
|
2763
|
-
await this.turns.settle(runId, input, milestone.outcome, Date.now() - started);
|
|
2955
|
+
await this.turns.settle(runId, input, milestone.outcome, Date.now() - started, spent);
|
|
2764
2956
|
return;
|
|
2765
2957
|
}
|
|
2766
2958
|
const reply = await this.park(runId, milestone.ask.id, milestone.ask.kind === "approval" ? "approval" : "answers", milestone.timeoutMs);
|
|
2767
|
-
handle = await this.turns.reply(runId, input, handle, milestone.ask, reply);
|
|
2959
|
+
handle = await this.turns.reply(runId, input, handle, milestone.ask, reply, spent);
|
|
2768
2960
|
}
|
|
2769
2961
|
} catch (error) {
|
|
2770
2962
|
if (error instanceof import_nestjs_agent_core5.RunCancelledError) {
|
|
@@ -2774,7 +2966,7 @@ var OpenCodeAgentRunner = class {
|
|
|
2774
2966
|
}, Date.now() - started);
|
|
2775
2967
|
return;
|
|
2776
2968
|
}
|
|
2777
|
-
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);
|
|
2778
2970
|
} finally {
|
|
2779
2971
|
this.inputs.delete(runId);
|
|
2780
2972
|
}
|
|
@@ -2927,6 +3119,8 @@ __name(openCodeProviders, "openCodeProviders");
|
|
|
2927
3119
|
OpenCodeToolsTokens,
|
|
2928
3120
|
OpenCodeTurn,
|
|
2929
3121
|
OpenCodeTurns,
|
|
3122
|
+
addUsage,
|
|
3123
|
+
emptyUsage,
|
|
2930
3124
|
keyValueOpenCodeSessionStore,
|
|
2931
3125
|
openCode,
|
|
2932
3126
|
openCodeControllers,
|
|
@@ -2934,6 +3128,7 @@ __name(openCodeProviders, "openCodeProviders");
|
|
|
2934
3128
|
sessionOf,
|
|
2935
3129
|
toElicitation,
|
|
2936
3130
|
toFormAnswer,
|
|
2937
|
-
toQuestion
|
|
3131
|
+
toQuestion,
|
|
3132
|
+
usageOf
|
|
2938
3133
|
});
|
|
2939
3134
|
//# sourceMappingURL=index.cjs.map
|