@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/durable/index.d.cts
CHANGED
|
@@ -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-
|
|
2
|
+
import { O as OpenCodeTurns, a as OpenCodeEngineSettings, b as OpenCodeHost, c as OpenCodeEngineOptions } from '../engine-JnBbcRxh.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';
|
package/dist/durable/index.d.ts
CHANGED
|
@@ -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-
|
|
2
|
+
import { O as OpenCodeTurns, a as OpenCodeEngineSettings, b as OpenCodeHost, c as OpenCodeEngineOptions } from '../engine-JnBbcRxh.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';
|
package/dist/durable/index.js
CHANGED
|
@@ -221,6 +221,41 @@ function toFormAnswer(form, answers = {}) {
|
|
|
221
221
|
__name(toFormAnswer, "toFormAnswer");
|
|
222
222
|
|
|
223
223
|
// src/turn.ts
|
|
224
|
+
function emptyUsage() {
|
|
225
|
+
return {
|
|
226
|
+
inputTokens: 0,
|
|
227
|
+
outputTokens: 0,
|
|
228
|
+
cacheReadTokens: 0,
|
|
229
|
+
cacheWriteTokens: 0,
|
|
230
|
+
reasoningTokens: 0,
|
|
231
|
+
costUsd: 0
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
__name(emptyUsage, "emptyUsage");
|
|
235
|
+
function addUsage(a, b) {
|
|
236
|
+
const x = a ?? emptyUsage();
|
|
237
|
+
const y = b ?? emptyUsage();
|
|
238
|
+
return {
|
|
239
|
+
inputTokens: x.inputTokens + (y.inputTokens ?? 0),
|
|
240
|
+
outputTokens: x.outputTokens + (y.outputTokens ?? 0),
|
|
241
|
+
cacheReadTokens: (x.cacheReadTokens ?? 0) + (y.cacheReadTokens ?? 0),
|
|
242
|
+
cacheWriteTokens: (x.cacheWriteTokens ?? 0) + (y.cacheWriteTokens ?? 0),
|
|
243
|
+
reasoningTokens: (x.reasoningTokens ?? 0) + (y.reasoningTokens ?? 0),
|
|
244
|
+
costUsd: x.costUsd + (y.costUsd ?? 0)
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
__name(addUsage, "addUsage");
|
|
248
|
+
function subUsage(a, b) {
|
|
249
|
+
return {
|
|
250
|
+
inputTokens: a.inputTokens - b.inputTokens,
|
|
251
|
+
outputTokens: a.outputTokens - b.outputTokens,
|
|
252
|
+
cacheReadTokens: a.cacheReadTokens - b.cacheReadTokens,
|
|
253
|
+
cacheWriteTokens: a.cacheWriteTokens - b.cacheWriteTokens,
|
|
254
|
+
reasoningTokens: a.reasoningTokens - b.reasoningTokens,
|
|
255
|
+
costUsd: a.costUsd - b.costUsd
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
__name(subUsage, "subUsage");
|
|
224
259
|
var ASK_TOOL_NAME = "ask";
|
|
225
260
|
var FAILED_STATUSES = /* @__PURE__ */ new Set([
|
|
226
261
|
"error",
|
|
@@ -286,11 +321,11 @@ var OpenCodeTurn = class {
|
|
|
286
321
|
hidden = /* @__PURE__ */ new Set();
|
|
287
322
|
milestones = [];
|
|
288
323
|
waiting;
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
324
|
+
/** What this turn object saw spent, and how much of it a milestone already reported. */
|
|
325
|
+
spent = emptyUsage();
|
|
326
|
+
reported = emptyUsage();
|
|
327
|
+
priced = false;
|
|
328
|
+
model;
|
|
294
329
|
stepOpen = false;
|
|
295
330
|
sawText = false;
|
|
296
331
|
separator = false;
|
|
@@ -300,6 +335,11 @@ var OpenCodeTurn = class {
|
|
|
300
335
|
stepError;
|
|
301
336
|
constructor(a) {
|
|
302
337
|
this.a = a;
|
|
338
|
+
this.model = modelOfLabel(a.input.model);
|
|
339
|
+
}
|
|
340
|
+
/** What the run spent so far: carried from before this turn object, plus what it saw. */
|
|
341
|
+
totalUsage() {
|
|
342
|
+
return addUsage(this.a.carried, this.spent);
|
|
303
343
|
}
|
|
304
344
|
get sessionId() {
|
|
305
345
|
return this.a.sessionId;
|
|
@@ -382,7 +422,15 @@ var OpenCodeTurn = class {
|
|
|
382
422
|
this.chain = this.chain.then(() => ask.kind === "approval" ? this.decided(ask, reply, tell) : this.answered(ask, reply, tell)).then(resolve, reject);
|
|
383
423
|
});
|
|
384
424
|
}
|
|
385
|
-
reach(
|
|
425
|
+
reach(reached) {
|
|
426
|
+
const usage = subUsage(this.spent, this.reported);
|
|
427
|
+
this.reported = {
|
|
428
|
+
...this.spent
|
|
429
|
+
};
|
|
430
|
+
const milestone = {
|
|
431
|
+
...reached,
|
|
432
|
+
usage
|
|
433
|
+
};
|
|
386
434
|
const waiting = this.waiting;
|
|
387
435
|
if (waiting !== void 0) {
|
|
388
436
|
this.waiting = void 0;
|
|
@@ -538,9 +586,22 @@ var OpenCodeTurn = class {
|
|
|
538
586
|
}
|
|
539
587
|
}
|
|
540
588
|
async onEvent(e) {
|
|
541
|
-
if (this.ended) return;
|
|
542
589
|
const d = e.data ?? {};
|
|
590
|
+
if (e.type === "session.usage.recorded") {
|
|
591
|
+
await this.usageRecorded(d);
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
if (this.ended) return;
|
|
543
595
|
switch (e.type) {
|
|
596
|
+
case "session.step.started":
|
|
597
|
+
case "session.model.selected": {
|
|
598
|
+
const model = d.model;
|
|
599
|
+
if (typeof model?.id === "string" && typeof model.providerID === "string") this.model = {
|
|
600
|
+
providerID: model.providerID,
|
|
601
|
+
id: model.id
|
|
602
|
+
};
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
544
605
|
case "session.text.delta": {
|
|
545
606
|
const delta = typeof d.delta === "string" ? d.delta : "";
|
|
546
607
|
if (!delta) return;
|
|
@@ -694,42 +755,63 @@ ${delta}` : delta;
|
|
|
694
755
|
});
|
|
695
756
|
}
|
|
696
757
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
};
|
|
708
|
-
|
|
709
|
-
this.
|
|
710
|
-
|
|
711
|
-
|
|
758
|
+
modelId() {
|
|
759
|
+
return this.model !== void 0 ? `${this.model.providerID}/${this.model.id}` : this.a.modelLabel;
|
|
760
|
+
}
|
|
761
|
+
/** One model call's usage and cost, into the ledger and the run's total. */
|
|
762
|
+
async spend(d, purpose) {
|
|
763
|
+
const usage = usageOf(d.tokens);
|
|
764
|
+
const reportedCostUsd = typeof d.cost === "number" && Number.isFinite(d.cost) && d.cost >= 0 ? d.cost : void 0;
|
|
765
|
+
const fallback = reportedCostUsd !== void 0 ? {
|
|
766
|
+
costUsd: reportedCostUsd,
|
|
767
|
+
costSource: "provider"
|
|
768
|
+
} : {};
|
|
769
|
+
let cost = fallback;
|
|
770
|
+
if (this.a.priceStep !== void 0) {
|
|
771
|
+
cost = await this.a.priceStep({
|
|
772
|
+
model: this.model,
|
|
773
|
+
usage,
|
|
774
|
+
reportedCostUsd
|
|
775
|
+
}).catch(() => fallback);
|
|
776
|
+
}
|
|
777
|
+
this.spent = addUsage(this.spent, {
|
|
778
|
+
inputTokens: usage.inputTokens,
|
|
779
|
+
outputTokens: usage.outputTokens,
|
|
780
|
+
cacheReadTokens: usage.cacheReadTokens ?? 0,
|
|
781
|
+
cacheWriteTokens: usage.cacheWriteTokens ?? 0,
|
|
782
|
+
reasoningTokens: usage.reasoningTokens ?? 0,
|
|
783
|
+
costUsd: cost.costUsd ?? 0
|
|
784
|
+
});
|
|
785
|
+
if (cost.costUsd !== void 0) this.priced = true;
|
|
712
786
|
await this.a.store.recordUsage({
|
|
713
787
|
threadId: this.a.input.threadId,
|
|
714
788
|
actorRef: this.a.input.actor.id,
|
|
715
|
-
modelId: this.
|
|
716
|
-
purpose
|
|
789
|
+
modelId: this.modelId(),
|
|
790
|
+
purpose,
|
|
717
791
|
usage,
|
|
718
|
-
...
|
|
719
|
-
costUsd,
|
|
720
|
-
costSource: "provider"
|
|
721
|
-
} : {}
|
|
792
|
+
...cost
|
|
722
793
|
});
|
|
794
|
+
return {
|
|
795
|
+
usage,
|
|
796
|
+
cost
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
/** `session.usage.recorded`: a call OpenCode made besides the steps (the title, a compaction). */
|
|
800
|
+
async usageRecorded(d) {
|
|
801
|
+
await this.spend(d, d.source === "title" ? "title" : "history_summary");
|
|
802
|
+
}
|
|
803
|
+
async stepEnded(d) {
|
|
804
|
+
const { usage, cost } = await this.spend(d, "chat");
|
|
723
805
|
if (!this.stepOpen) return;
|
|
724
806
|
this.stepOpen = false;
|
|
725
807
|
await this.write({
|
|
726
808
|
kind: "step-finish",
|
|
727
809
|
usage,
|
|
728
|
-
costUsd: costUsd ?? null,
|
|
810
|
+
costUsd: cost.costUsd ?? null,
|
|
729
811
|
...this.segment.reasoningMs > 0 ? {
|
|
730
812
|
reasoningMs: this.segment.reasoningMs
|
|
731
813
|
} : {},
|
|
732
|
-
model: this.
|
|
814
|
+
model: this.modelId()
|
|
733
815
|
});
|
|
734
816
|
}
|
|
735
817
|
/**
|
|
@@ -748,12 +830,7 @@ ${delta}` : delta;
|
|
|
748
830
|
content: s.text,
|
|
749
831
|
runId: this.a.runId,
|
|
750
832
|
...final ? {
|
|
751
|
-
usage:
|
|
752
|
-
...this.usage,
|
|
753
|
-
...this.costUsd !== void 0 ? {
|
|
754
|
-
costUsd: this.costUsd
|
|
755
|
-
} : {}
|
|
756
|
-
}
|
|
833
|
+
usage: this.messageUsage()
|
|
757
834
|
} : {},
|
|
758
835
|
...this.a.input.agentName !== void 0 ? {
|
|
759
836
|
agentName: this.a.input.agentName
|
|
@@ -781,6 +858,26 @@ ${delta}` : delta;
|
|
|
781
858
|
]);
|
|
782
859
|
return message.id;
|
|
783
860
|
}
|
|
861
|
+
/** The run's usage as its last message carries it: the whole run, cache tokens included. */
|
|
862
|
+
messageUsage() {
|
|
863
|
+
const total = this.totalUsage();
|
|
864
|
+
return {
|
|
865
|
+
inputTokens: total.inputTokens,
|
|
866
|
+
outputTokens: total.outputTokens,
|
|
867
|
+
...total.cacheReadTokens > 0 ? {
|
|
868
|
+
cacheReadTokens: total.cacheReadTokens
|
|
869
|
+
} : {},
|
|
870
|
+
...total.cacheWriteTokens > 0 ? {
|
|
871
|
+
cacheWriteTokens: total.cacheWriteTokens
|
|
872
|
+
} : {},
|
|
873
|
+
...total.reasoningTokens > 0 ? {
|
|
874
|
+
reasoningTokens: total.reasoningTokens
|
|
875
|
+
} : {},
|
|
876
|
+
...this.priced || (this.a.carried?.costUsd ?? 0) > 0 ? {
|
|
877
|
+
costUsd: total.costUsd
|
|
878
|
+
} : {}
|
|
879
|
+
};
|
|
880
|
+
}
|
|
784
881
|
/** A request recorded by an earlier process (a turn resumed after a restart). */
|
|
785
882
|
async alreadyRecorded(id) {
|
|
786
883
|
return (await this.a.store.toolCallApproval?.(id) ?? null) !== null;
|
|
@@ -1150,6 +1247,35 @@ ${delta}` : delta;
|
|
|
1150
1247
|
});
|
|
1151
1248
|
}
|
|
1152
1249
|
};
|
|
1250
|
+
function modelOfLabel(label) {
|
|
1251
|
+
const slash = label?.indexOf("/") ?? -1;
|
|
1252
|
+
if (label === void 0 || slash <= 0 || slash === label.length - 1) return void 0;
|
|
1253
|
+
return {
|
|
1254
|
+
providerID: label.slice(0, slash),
|
|
1255
|
+
id: label.slice(slash + 1)
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
__name(modelOfLabel, "modelOfLabel");
|
|
1259
|
+
function usageOf(tokens) {
|
|
1260
|
+
const n = /* @__PURE__ */ __name((v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0, "n");
|
|
1261
|
+
const read = n(tokens?.cache?.read);
|
|
1262
|
+
const write = n(tokens?.cache?.write);
|
|
1263
|
+
const reasoning = n(tokens?.reasoning);
|
|
1264
|
+
return {
|
|
1265
|
+
inputTokens: n(tokens?.input) + read + write,
|
|
1266
|
+
outputTokens: n(tokens?.output),
|
|
1267
|
+
...read > 0 ? {
|
|
1268
|
+
cacheReadTokens: read
|
|
1269
|
+
} : {},
|
|
1270
|
+
...write > 0 ? {
|
|
1271
|
+
cacheWriteTokens: write
|
|
1272
|
+
} : {},
|
|
1273
|
+
...reasoning > 0 ? {
|
|
1274
|
+
reasoningTokens: reasoning
|
|
1275
|
+
} : {}
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
__name(usageOf, "usageOf");
|
|
1153
1279
|
|
|
1154
1280
|
// src/mcp.ts
|
|
1155
1281
|
var LOOP_SERVED_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -1414,7 +1540,7 @@ import { Inject as Inject3, Injectable as Injectable2 } from "@nestjs/common";
|
|
|
1414
1540
|
// src/turns.ts
|
|
1415
1541
|
import { randomUUID } from "crypto";
|
|
1416
1542
|
import { AGENT_CHAT_QUEUE } from "@dudousxd/nestjs-agent";
|
|
1417
|
-
import { AGENT_DEPS_FACTORY, AGENT_MEMORY, AGENT_SINK, AGENT_SKILLS, AGENT_STORE, AGENT_TOOL_REGISTRY, DEFAULT_MAX_FACT_CHARS, DefaultApprovalPolicy, RUN_ENDED_BEFORE_TOOL_CALL, actorScope, buildMemoryBlock, defaultScopeResolver, encodeStreamEvent as encodeStreamEvent2, memoryWriteVerdict, publishAgentRunFailed, releaseThreadRun, resolveMemoryDigest, resolveSkillCatalog, streamFailure } from "@dudousxd/nestjs-agent-core";
|
|
1543
|
+
import { AGENT_DEPS_FACTORY, AGENT_MEMORY, AGENT_OPTIONS, AGENT_PRICING_STORE, AGENT_SINK, AGENT_SKILLS, AGENT_STORE, AGENT_TOOL_REGISTRY, DEFAULT_MAX_FACT_CHARS, DefaultApprovalPolicy, ModelPriceResolver, RUN_ENDED_BEFORE_TOOL_CALL, actorScope, buildMemoryBlock, defaultScopeResolver, encodeStreamEvent as encodeStreamEvent2, memoryWriteVerdict, parseBedrockModelId, publishAgentRunFailed, releaseThreadRun, resolveMemoryDigest, resolveSkillCatalog, resolveUsageCost, streamFailure } from "@dudousxd/nestjs-agent-core";
|
|
1418
1544
|
import { Inject as Inject2, Injectable, Logger as Logger2, Optional } from "@nestjs/common";
|
|
1419
1545
|
|
|
1420
1546
|
// src/event-hub.ts
|
|
@@ -1581,7 +1707,7 @@ var OpenCodeTurns = class {
|
|
|
1581
1707
|
spent = /* @__PURE__ */ new Set();
|
|
1582
1708
|
/** When the tools endpoint was last registered for a location (`server|boot|directory|actor`). */
|
|
1583
1709
|
toolsIssued = /* @__PURE__ */ new Map();
|
|
1584
|
-
constructor(host, sessions, settings, store, sink, deps, registry, skills, memory, queue, toolsTokens2) {
|
|
1710
|
+
constructor(host, sessions, settings, store, sink, deps, registry, skills, memory, queue, toolsTokens2, pricingStore, agentOptions) {
|
|
1585
1711
|
this.host = host;
|
|
1586
1712
|
this.sessions = sessions;
|
|
1587
1713
|
this.settings = settings;
|
|
@@ -1593,6 +1719,30 @@ var OpenCodeTurns = class {
|
|
|
1593
1719
|
this.memory = memory;
|
|
1594
1720
|
this.queue = queue;
|
|
1595
1721
|
this.toolsTokens = toolsTokens2;
|
|
1722
|
+
this.prices = new ModelPriceResolver({
|
|
1723
|
+
pricingStore,
|
|
1724
|
+
catalog: agentOptions?.priceCatalog,
|
|
1725
|
+
log: {
|
|
1726
|
+
info: /* @__PURE__ */ __name((message) => this.logger.log(message), "info"),
|
|
1727
|
+
warn: /* @__PURE__ */ __name((message) => this.logger.warn(message), "warn")
|
|
1728
|
+
}
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
prices;
|
|
1732
|
+
/**
|
|
1733
|
+
* What a model call OpenCode made cost, by the same rule the library's loop records its own steps
|
|
1734
|
+
* at: a reported figure wins, else an estimate off the model's price — see
|
|
1735
|
+
* {@link OpenCodeEngineSettings.cost}.
|
|
1736
|
+
*/
|
|
1737
|
+
async priceStep(step) {
|
|
1738
|
+
const { model, usage, reportedCostUsd } = step;
|
|
1739
|
+
const tokens = usage.inputTokens + usage.outputTokens;
|
|
1740
|
+
const reported = reportedCostUsd !== void 0 && (reportedCostUsd > 0 || tokens === 0);
|
|
1741
|
+
if (reported && this.settings.cost !== "estimate") {
|
|
1742
|
+
return resolveUsageCost(usage, reportedCostUsd, void 0);
|
|
1743
|
+
}
|
|
1744
|
+
const price = model !== void 0 && tokens > 0 ? await this.prices.priceFor(priceRef(model)) : void 0;
|
|
1745
|
+
return resolveUsageCost(usage, price === void 0 ? reportedCostUsd : void 0, price);
|
|
1596
1746
|
}
|
|
1597
1747
|
/** The tools server's name in OpenCode. */
|
|
1598
1748
|
get toolsServer() {
|
|
@@ -2182,8 +2332,8 @@ ${body}
|
|
|
2182
2332
|
}
|
|
2183
2333
|
// ---- prompt / observe / reply --------------------------------------------------------------
|
|
2184
2334
|
/** Start listening to the session (so nothing it says is missed), then send the user message. */
|
|
2185
|
-
async prompt(runId, input, handle) {
|
|
2186
|
-
const live = await this.ensureLive(runId, input, handle, false);
|
|
2335
|
+
async prompt(runId, input, handle, spent) {
|
|
2336
|
+
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2187
2337
|
try {
|
|
2188
2338
|
const prompt = await this.host.promptFor?.({
|
|
2189
2339
|
input,
|
|
@@ -2213,9 +2363,12 @@ ${body}
|
|
|
2213
2363
|
* Wait for the turn's next milestone. In a process that was not following the turn (a resumed
|
|
2214
2364
|
* durable run), the turn is rebuilt and first catches up on requests OpenCode raised meanwhile;
|
|
2215
2365
|
* `session.wait` is the safety net for a terminal event that was missed.
|
|
2366
|
+
*
|
|
2367
|
+
* `spent` is what the run spent before (the sum of the `usage` of its earlier milestones): a turn
|
|
2368
|
+
* rebuilt here starts from it, so the answer it persists carries the whole run's usage.
|
|
2216
2369
|
*/
|
|
2217
|
-
async observe(runId, input, handle) {
|
|
2218
|
-
const live = await this.ensureLive(runId, input, handle, true);
|
|
2370
|
+
async observe(runId, input, handle, spent) {
|
|
2371
|
+
const live = await this.ensureLive(runId, input, handle, true, spent);
|
|
2219
2372
|
const { turn, client } = live;
|
|
2220
2373
|
if (turn.hasMilestone()) return this.reached(runId, input, handle, await turn.next());
|
|
2221
2374
|
let done = false;
|
|
@@ -2254,23 +2407,23 @@ ${body}
|
|
|
2254
2407
|
* request is gone with it: a new session is opened, told what the person decided, and prompted
|
|
2255
2408
|
* to go on.
|
|
2256
2409
|
*/
|
|
2257
|
-
async reply(runId, input, handle, ask, reply) {
|
|
2410
|
+
async reply(runId, input, handle, ask, reply, spent) {
|
|
2258
2411
|
const server = await this.host.server(input.actor);
|
|
2259
2412
|
if (server.key !== handle.serverKey || server.bootId !== handle.bootId) {
|
|
2260
|
-
return this.continueAfterRestart(runId, input, server, ask, reply);
|
|
2413
|
+
return this.continueAfterRestart(runId, input, server, ask, reply, spent);
|
|
2261
2414
|
}
|
|
2262
|
-
const live = await this.ensureLive(runId, input, handle, false);
|
|
2415
|
+
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2263
2416
|
await live.turn.decide(ask, reply);
|
|
2264
2417
|
return handle;
|
|
2265
2418
|
}
|
|
2266
|
-
async continueAfterRestart(runId, input, server, ask, reply) {
|
|
2419
|
+
async continueAfterRestart(runId, input, server, ask, reply, spent) {
|
|
2267
2420
|
const approved = "approved" in reply && reply.approved === true;
|
|
2268
2421
|
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.`;
|
|
2269
2422
|
const thread = await this.store.getThread(input.threadId);
|
|
2270
2423
|
const handle = await this.createSession(runId, input, server, thread?.messages ?? [], note);
|
|
2271
2424
|
await this.refreshInstructions(runId, input, server.client, handle.sessionId);
|
|
2272
2425
|
this.drop(runId);
|
|
2273
|
-
const live = await this.ensureLive(runId, input, handle, false);
|
|
2426
|
+
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2274
2427
|
await live.turn.decide(ask, reply, {
|
|
2275
2428
|
tellOpenCode: false
|
|
2276
2429
|
});
|
|
@@ -2290,7 +2443,7 @@ ${body}
|
|
|
2290
2443
|
sessionID: known.sessionId
|
|
2291
2444
|
});
|
|
2292
2445
|
}
|
|
2293
|
-
async ensureLive(runId, input, handle, catchUp) {
|
|
2446
|
+
async ensureLive(runId, input, handle, catchUp, spent) {
|
|
2294
2447
|
const current = this.live.get(runId);
|
|
2295
2448
|
if (current !== void 0 && current.handle.sessionId === handle.sessionId) return current;
|
|
2296
2449
|
current?.stop();
|
|
@@ -2316,6 +2469,10 @@ ${body}
|
|
|
2316
2469
|
} : {}
|
|
2317
2470
|
}), "approvalFor"),
|
|
2318
2471
|
modelLabel: input.model ?? "opencode",
|
|
2472
|
+
priceStep: /* @__PURE__ */ __name((step) => this.priceStep(step), "priceStep"),
|
|
2473
|
+
...spent !== void 0 ? {
|
|
2474
|
+
carried: spent
|
|
2475
|
+
} : {},
|
|
2319
2476
|
logger: this.logger,
|
|
2320
2477
|
onGranted: /* @__PURE__ */ __name((action, id) => {
|
|
2321
2478
|
const grants = this.grants.get(runId) ?? [];
|
|
@@ -2362,20 +2519,14 @@ ${body}
|
|
|
2362
2519
|
}
|
|
2363
2520
|
return milestone;
|
|
2364
2521
|
}
|
|
2365
|
-
/**
|
|
2366
|
-
|
|
2522
|
+
/**
|
|
2523
|
+
* What the run produced, as the host's settle hooks see it. `usage` is what the run spent — the
|
|
2524
|
+
* runner's sum of its milestones' usage, which a resumed run reads back from its journal — else
|
|
2525
|
+
* what the turn this process follows saw.
|
|
2526
|
+
*/
|
|
2527
|
+
async runResult(runId, input, outcome, durationMs, usage) {
|
|
2367
2528
|
const thread = await this.store.getThread(input.threadId);
|
|
2368
2529
|
const messages = (thread?.messages ?? []).filter((m) => m.role === "assistant" && m.runId === runId);
|
|
2369
|
-
const usage = {
|
|
2370
|
-
inputTokens: 0,
|
|
2371
|
-
outputTokens: 0,
|
|
2372
|
-
costUsd: 0
|
|
2373
|
-
};
|
|
2374
|
-
for (const m of messages) {
|
|
2375
|
-
usage.inputTokens += m.usage?.inputTokens ?? 0;
|
|
2376
|
-
usage.outputTokens += m.usage?.outputTokens ?? 0;
|
|
2377
|
-
usage.costUsd += m.usage?.costUsd ?? 0;
|
|
2378
|
-
}
|
|
2379
2530
|
return {
|
|
2380
2531
|
runId,
|
|
2381
2532
|
input,
|
|
@@ -2420,15 +2571,31 @@ ${body}
|
|
|
2420
2571
|
this.logger.warn(`onSettled failed: ${errorText(error, "error")}`);
|
|
2421
2572
|
}
|
|
2422
2573
|
}
|
|
2423
|
-
/**
|
|
2424
|
-
|
|
2574
|
+
/**
|
|
2575
|
+
* What the run spent: the runner's sum of its milestones, or what the turn this process follows
|
|
2576
|
+
* saw (which starts from that sum) when it saw more — a run that failed or was cancelled between
|
|
2577
|
+
* two milestones.
|
|
2578
|
+
*/
|
|
2579
|
+
spentBy(runId, spent) {
|
|
2580
|
+
const seen = this.live.get(runId)?.turn.totalUsage();
|
|
2581
|
+
if (spent === void 0) return seen ?? emptyUsage();
|
|
2582
|
+
if (seen === void 0) return spent;
|
|
2583
|
+
const tokens = /* @__PURE__ */ __name((u) => u.inputTokens + u.outputTokens, "tokens");
|
|
2584
|
+
return tokens(seen) > tokens(spent) ? seen : spent;
|
|
2585
|
+
}
|
|
2586
|
+
/**
|
|
2587
|
+
* End the run's stream and bookkeeping for how its execution ended. `spent` is what the run spent
|
|
2588
|
+
* (the sum of its milestones' `usage`); omit → what the turn this process follows saw.
|
|
2589
|
+
*/
|
|
2590
|
+
async settle(runId, input, outcome, durationMs, spent) {
|
|
2425
2591
|
if (outcome.status === "failed") {
|
|
2426
|
-
await this.settleFailed(runId, input, outcome.error, durationMs);
|
|
2592
|
+
await this.settleFailed(runId, input, outcome.error, durationMs, spent);
|
|
2427
2593
|
return;
|
|
2428
2594
|
}
|
|
2595
|
+
const usage = this.spentBy(runId, spent);
|
|
2429
2596
|
this.forget(runId);
|
|
2430
2597
|
const writer = await this.sink.open(runId);
|
|
2431
|
-
const result = await this.runResult(runId, input, outcome, durationMs);
|
|
2598
|
+
const result = await this.runResult(runId, input, outcome, durationMs, usage);
|
|
2432
2599
|
await this.amend(writer, result);
|
|
2433
2600
|
if (outcome.status === "interrupted") {
|
|
2434
2601
|
this.logger.log(`agent run ${runId} cancelled`);
|
|
@@ -2456,13 +2623,14 @@ ${body}
|
|
|
2456
2623
|
}
|
|
2457
2624
|
await this.settled(result);
|
|
2458
2625
|
}
|
|
2459
|
-
async settleFailed(runId, input, error, durationMs = 0) {
|
|
2626
|
+
async settleFailed(runId, input, error, durationMs = 0, spent) {
|
|
2627
|
+
const usage = this.spentBy(runId, spent);
|
|
2460
2628
|
this.forget(runId);
|
|
2461
2629
|
const writer = await this.sink.open(runId);
|
|
2462
2630
|
const result = await this.runResult(runId, input, {
|
|
2463
2631
|
status: "failed",
|
|
2464
2632
|
error
|
|
2465
|
-
}, durationMs);
|
|
2633
|
+
}, durationMs, usage);
|
|
2466
2634
|
const worded = (await this.amend(writer, result)).error;
|
|
2467
2635
|
const message = worded ?? streamFailure(new Error(error)).message;
|
|
2468
2636
|
this.logger.error(`agent run ${runId} failed: ${error}`);
|
|
@@ -2532,6 +2700,10 @@ OpenCodeTurns = _ts_decorate2([
|
|
|
2532
2700
|
_ts_param2(9, Inject2(AGENT_CHAT_QUEUE)),
|
|
2533
2701
|
_ts_param2(10, Optional()),
|
|
2534
2702
|
_ts_param2(10, Inject2(OPENCODE_TOOLS_TOKENS)),
|
|
2703
|
+
_ts_param2(11, Optional()),
|
|
2704
|
+
_ts_param2(11, Inject2(AGENT_PRICING_STORE)),
|
|
2705
|
+
_ts_param2(12, Optional()),
|
|
2706
|
+
_ts_param2(12, Inject2(AGENT_OPTIONS)),
|
|
2535
2707
|
_ts_metadata2("design:type", Function),
|
|
2536
2708
|
_ts_metadata2("design:paramtypes", [
|
|
2537
2709
|
typeof OpenCodeHost === "undefined" ? Object : OpenCodeHost,
|
|
@@ -2544,6 +2716,8 @@ OpenCodeTurns = _ts_decorate2([
|
|
|
2544
2716
|
typeof SkillsConfig === "undefined" ? Object : SkillsConfig,
|
|
2545
2717
|
typeof MemoryConfig === "undefined" ? Object : MemoryConfig,
|
|
2546
2718
|
typeof ChatQueueService === "undefined" ? Object : ChatQueueService,
|
|
2719
|
+
Object,
|
|
2720
|
+
typeof AgentPricingStore === "undefined" ? Object : AgentPricingStore,
|
|
2547
2721
|
Object
|
|
2548
2722
|
])
|
|
2549
2723
|
], OpenCodeTurns);
|
|
@@ -2586,6 +2760,19 @@ function uiEmitter(scope, push) {
|
|
|
2586
2760
|
};
|
|
2587
2761
|
}
|
|
2588
2762
|
__name(uiEmitter, "uiEmitter");
|
|
2763
|
+
function priceRef(model) {
|
|
2764
|
+
const aliases = [
|
|
2765
|
+
model.id
|
|
2766
|
+
];
|
|
2767
|
+
const tail = model.id.slice(model.id.lastIndexOf("/") + 1);
|
|
2768
|
+
if (tail !== model.id && parseBedrockModelId(tail) !== void 0) aliases.push(tail);
|
|
2769
|
+
return {
|
|
2770
|
+
modelId: `${model.providerID}/${model.id}`,
|
|
2771
|
+
provider: model.providerID,
|
|
2772
|
+
aliases
|
|
2773
|
+
};
|
|
2774
|
+
}
|
|
2775
|
+
__name(priceRef, "priceRef");
|
|
2589
2776
|
|
|
2590
2777
|
// src/runner.ts
|
|
2591
2778
|
function _ts_decorate3(decorators, target, key, desc) {
|
|
@@ -2687,18 +2874,20 @@ var OpenCodeAgentRunner = class {
|
|
|
2687
2874
|
async run(runId, input) {
|
|
2688
2875
|
const started = Date.now();
|
|
2689
2876
|
this.inputs.set(runId, input);
|
|
2877
|
+
let spent = emptyUsage();
|
|
2690
2878
|
try {
|
|
2691
2879
|
let handle = await this.turns.begin(runId, input);
|
|
2692
2880
|
if (this.cancelled.has(runId)) throw new RunCancelledError();
|
|
2693
|
-
await this.turns.prompt(runId, input, handle);
|
|
2881
|
+
await this.turns.prompt(runId, input, handle, spent);
|
|
2694
2882
|
for (; ; ) {
|
|
2695
|
-
const milestone = await this.turns.observe(runId, input, handle);
|
|
2883
|
+
const milestone = await this.turns.observe(runId, input, handle, spent);
|
|
2884
|
+
spent = addUsage(spent, milestone.usage);
|
|
2696
2885
|
if (milestone.kind === "finished") {
|
|
2697
|
-
await this.turns.settle(runId, input, milestone.outcome, Date.now() - started);
|
|
2886
|
+
await this.turns.settle(runId, input, milestone.outcome, Date.now() - started, spent);
|
|
2698
2887
|
return;
|
|
2699
2888
|
}
|
|
2700
2889
|
const reply = await this.park(runId, milestone.ask.id, milestone.ask.kind === "approval" ? "approval" : "answers", milestone.timeoutMs);
|
|
2701
|
-
handle = await this.turns.reply(runId, input, handle, milestone.ask, reply);
|
|
2890
|
+
handle = await this.turns.reply(runId, input, handle, milestone.ask, reply, spent);
|
|
2702
2891
|
}
|
|
2703
2892
|
} catch (error) {
|
|
2704
2893
|
if (error instanceof RunCancelledError) {
|
|
@@ -2708,7 +2897,7 @@ var OpenCodeAgentRunner = class {
|
|
|
2708
2897
|
}, Date.now() - started);
|
|
2709
2898
|
return;
|
|
2710
2899
|
}
|
|
2711
|
-
await this.turns.settleFailed(runId, input, errorText(error, "the turn failed"));
|
|
2900
|
+
await this.turns.settleFailed(runId, input, errorText(error, "the turn failed"), Date.now() - started);
|
|
2712
2901
|
} finally {
|
|
2713
2902
|
this.inputs.delete(runId);
|
|
2714
2903
|
}
|
|
@@ -2880,6 +3069,7 @@ var OpenCodeRunWorkflow = class {
|
|
|
2880
3069
|
this.runs = runs;
|
|
2881
3070
|
}
|
|
2882
3071
|
async run(ctx, input) {
|
|
3072
|
+
let spent = emptyUsage();
|
|
2883
3073
|
try {
|
|
2884
3074
|
const begun = await ctx.localStep("begin", async () => ({
|
|
2885
3075
|
handle: await this.turns.begin(ctx.runId, input),
|
|
@@ -2887,15 +3077,18 @@ var OpenCodeRunWorkflow = class {
|
|
|
2887
3077
|
}));
|
|
2888
3078
|
let handle = begun.handle;
|
|
2889
3079
|
await ctx.localStep("prompt", async () => {
|
|
2890
|
-
await this.turns.prompt(ctx.runId, input, handle);
|
|
3080
|
+
await this.turns.prompt(ctx.runId, input, handle, spent);
|
|
2891
3081
|
return true;
|
|
2892
3082
|
});
|
|
2893
3083
|
for (let n = 0; ; n += 1) {
|
|
2894
|
-
const
|
|
3084
|
+
const before = spent;
|
|
3085
|
+
const milestone = await ctx.localStep(`observe:${n}`, () => this.turns.observe(ctx.runId, input, handle, before));
|
|
3086
|
+
spent = addUsage(spent, milestone.usage);
|
|
3087
|
+
const total = spent;
|
|
2895
3088
|
if (milestone.kind === "finished") {
|
|
2896
3089
|
await ctx.localStep("finish", async () => {
|
|
2897
3090
|
if (await this.cancelled(ctx.runId)) this.turns.drop(ctx.runId);
|
|
2898
|
-
else await this.turns.settle(ctx.runId, input, milestone.outcome, Date.now() - begun.startedAt);
|
|
3091
|
+
else await this.turns.settle(ctx.runId, input, milestone.outcome, Date.now() - begun.startedAt, total);
|
|
2899
3092
|
return true;
|
|
2900
3093
|
});
|
|
2901
3094
|
return {
|
|
@@ -2915,12 +3108,12 @@ var OpenCodeRunWorkflow = class {
|
|
|
2915
3108
|
};
|
|
2916
3109
|
}
|
|
2917
3110
|
const ask = milestone.ask;
|
|
2918
|
-
handle = await ctx.localStep(`reply:${n}`, () => this.turns.reply(ctx.runId, input, handle, ask, reply));
|
|
3111
|
+
handle = await ctx.localStep(`reply:${n}`, () => this.turns.reply(ctx.runId, input, handle, ask, reply, total));
|
|
2919
3112
|
}
|
|
2920
3113
|
} catch (error) {
|
|
2921
3114
|
if (isWorkflowControlFlowSignal(error)) throw error;
|
|
2922
3115
|
await ctx.localStep("fail", async () => {
|
|
2923
|
-
await this.turns.settleFailed(ctx.runId, input, errorText(error, "the turn failed"));
|
|
3116
|
+
await this.turns.settleFailed(ctx.runId, input, errorText(error, "the turn failed"), 0, spent);
|
|
2924
3117
|
return true;
|
|
2925
3118
|
});
|
|
2926
3119
|
return {
|