@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.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as OpenCodeClient, e as OpenCodeEvent, f as OpenCodeForm, g as OpenCodeFormValue, h as OpenCodeFormField, i as OpenCodeMcpEndpoint, O as OpenCodeTurns, a as OpenCodeEngineSettings } from './engine-
|
|
2
|
-
export { I as InMemoryOpenCodeSessionStore, M as Milestone, j as OpenCodeAmendment, k as OpenCodeCallContext, c as OpenCodeEngineOptions, b as OpenCodeHost, l as OpenCodeKeyValue, m as OpenCodeModelRef, n as OpenCodePermissionRequest, o as OpenCodePermissionRule, p as OpenCodeReplyMismatchError, q as OpenCodeRunResult, r as OpenCodeServer, s as OpenCodeSessionCreate, t as OpenCodeSessionRef, u as OpenCodeSessionStore, v as OpenCodeToolCall, w as OpenCodeToolRefusedError, x as OpenCodeToolsClaims, y as OpenCodeToolsOptions, z as OpenCodeToolsTokens, A as OpenCodeTurn, B as OpenCodeTurnContext, P as PendingAsk, S as SessionHandle, T as TurnOutcome,
|
|
1
|
+
import { d as OpenCodeClient, e as OpenCodeEvent, f as OpenCodeForm, g as OpenCodeFormValue, h as OpenCodeFormField, i as OpenCodeMcpEndpoint, O as OpenCodeTurns, a as OpenCodeEngineSettings } from './engine-JnBbcRxh.cjs';
|
|
2
|
+
export { I as InMemoryOpenCodeSessionStore, M as Milestone, j as OpenCodeAmendment, k as OpenCodeCallContext, c as OpenCodeEngineOptions, b as OpenCodeHost, l as OpenCodeKeyValue, m as OpenCodeModelRef, n as OpenCodePermissionRequest, o as OpenCodePermissionRule, p as OpenCodeReplyMismatchError, q as OpenCodeRunResult, r as OpenCodeServer, s as OpenCodeSessionCreate, t as OpenCodeSessionRef, u as OpenCodeSessionStore, v as OpenCodeToolCall, w as OpenCodeToolRefusedError, x as OpenCodeToolsClaims, y as OpenCodeToolsOptions, z as OpenCodeToolsTokens, A as OpenCodeTurn, B as OpenCodeTurnContext, C as OpenCodeUsage, P as PendingAsk, S as SessionHandle, D as StepCost, E as StepModel, T as TurnOutcome, F as addUsage, G as emptyUsage, H as keyValueOpenCodeSessionStore, J as openCode, K as openCodeControllers, L as openCodeProviders, N as usageOf } from './engine-JnBbcRxh.cjs';
|
|
3
3
|
import { ElicitationRequest, ElicitationQuestion, AgentRunner, AgentRunInput, AgentRunStartOptions, HumanReply } from '@dudousxd/nestjs-agent-core';
|
|
4
4
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
5
|
import '@dudousxd/nestjs-agent';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as OpenCodeClient, e as OpenCodeEvent, f as OpenCodeForm, g as OpenCodeFormValue, h as OpenCodeFormField, i as OpenCodeMcpEndpoint, O as OpenCodeTurns, a as OpenCodeEngineSettings } from './engine-
|
|
2
|
-
export { I as InMemoryOpenCodeSessionStore, M as Milestone, j as OpenCodeAmendment, k as OpenCodeCallContext, c as OpenCodeEngineOptions, b as OpenCodeHost, l as OpenCodeKeyValue, m as OpenCodeModelRef, n as OpenCodePermissionRequest, o as OpenCodePermissionRule, p as OpenCodeReplyMismatchError, q as OpenCodeRunResult, r as OpenCodeServer, s as OpenCodeSessionCreate, t as OpenCodeSessionRef, u as OpenCodeSessionStore, v as OpenCodeToolCall, w as OpenCodeToolRefusedError, x as OpenCodeToolsClaims, y as OpenCodeToolsOptions, z as OpenCodeToolsTokens, A as OpenCodeTurn, B as OpenCodeTurnContext, P as PendingAsk, S as SessionHandle, T as TurnOutcome,
|
|
1
|
+
import { d as OpenCodeClient, e as OpenCodeEvent, f as OpenCodeForm, g as OpenCodeFormValue, h as OpenCodeFormField, i as OpenCodeMcpEndpoint, O as OpenCodeTurns, a as OpenCodeEngineSettings } from './engine-JnBbcRxh.js';
|
|
2
|
+
export { I as InMemoryOpenCodeSessionStore, M as Milestone, j as OpenCodeAmendment, k as OpenCodeCallContext, c as OpenCodeEngineOptions, b as OpenCodeHost, l as OpenCodeKeyValue, m as OpenCodeModelRef, n as OpenCodePermissionRequest, o as OpenCodePermissionRule, p as OpenCodeReplyMismatchError, q as OpenCodeRunResult, r as OpenCodeServer, s as OpenCodeSessionCreate, t as OpenCodeSessionRef, u as OpenCodeSessionStore, v as OpenCodeToolCall, w as OpenCodeToolRefusedError, x as OpenCodeToolsClaims, y as OpenCodeToolsOptions, z as OpenCodeToolsTokens, A as OpenCodeTurn, B as OpenCodeTurnContext, C as OpenCodeUsage, P as PendingAsk, S as SessionHandle, D as StepCost, E as StepModel, T as TurnOutcome, F as addUsage, G as emptyUsage, H as keyValueOpenCodeSessionStore, J as openCode, K as openCodeControllers, L as openCodeProviders, N as usageOf } from './engine-JnBbcRxh.js';
|
|
3
3
|
import { ElicitationRequest, ElicitationQuestion, AgentRunner, AgentRunInput, AgentRunStartOptions, HumanReply } from '@dudousxd/nestjs-agent-core';
|
|
4
4
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
5
|
import '@dudousxd/nestjs-agent';
|
package/dist/index.js
CHANGED
|
@@ -239,6 +239,41 @@ function toFormAnswer(form, answers = {}) {
|
|
|
239
239
|
__name(toFormAnswer, "toFormAnswer");
|
|
240
240
|
|
|
241
241
|
// src/turn.ts
|
|
242
|
+
function emptyUsage() {
|
|
243
|
+
return {
|
|
244
|
+
inputTokens: 0,
|
|
245
|
+
outputTokens: 0,
|
|
246
|
+
cacheReadTokens: 0,
|
|
247
|
+
cacheWriteTokens: 0,
|
|
248
|
+
reasoningTokens: 0,
|
|
249
|
+
costUsd: 0
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
__name(emptyUsage, "emptyUsage");
|
|
253
|
+
function addUsage(a, b) {
|
|
254
|
+
const x = a ?? emptyUsage();
|
|
255
|
+
const y = b ?? emptyUsage();
|
|
256
|
+
return {
|
|
257
|
+
inputTokens: x.inputTokens + (y.inputTokens ?? 0),
|
|
258
|
+
outputTokens: x.outputTokens + (y.outputTokens ?? 0),
|
|
259
|
+
cacheReadTokens: (x.cacheReadTokens ?? 0) + (y.cacheReadTokens ?? 0),
|
|
260
|
+
cacheWriteTokens: (x.cacheWriteTokens ?? 0) + (y.cacheWriteTokens ?? 0),
|
|
261
|
+
reasoningTokens: (x.reasoningTokens ?? 0) + (y.reasoningTokens ?? 0),
|
|
262
|
+
costUsd: x.costUsd + (y.costUsd ?? 0)
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
__name(addUsage, "addUsage");
|
|
266
|
+
function subUsage(a, b) {
|
|
267
|
+
return {
|
|
268
|
+
inputTokens: a.inputTokens - b.inputTokens,
|
|
269
|
+
outputTokens: a.outputTokens - b.outputTokens,
|
|
270
|
+
cacheReadTokens: a.cacheReadTokens - b.cacheReadTokens,
|
|
271
|
+
cacheWriteTokens: a.cacheWriteTokens - b.cacheWriteTokens,
|
|
272
|
+
reasoningTokens: a.reasoningTokens - b.reasoningTokens,
|
|
273
|
+
costUsd: a.costUsd - b.costUsd
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
__name(subUsage, "subUsage");
|
|
242
277
|
var ASK_TOOL_NAME = "ask";
|
|
243
278
|
var FAILED_STATUSES = /* @__PURE__ */ new Set([
|
|
244
279
|
"error",
|
|
@@ -304,11 +339,11 @@ var OpenCodeTurn = class {
|
|
|
304
339
|
hidden = /* @__PURE__ */ new Set();
|
|
305
340
|
milestones = [];
|
|
306
341
|
waiting;
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
342
|
+
/** What this turn object saw spent, and how much of it a milestone already reported. */
|
|
343
|
+
spent = emptyUsage();
|
|
344
|
+
reported = emptyUsage();
|
|
345
|
+
priced = false;
|
|
346
|
+
model;
|
|
312
347
|
stepOpen = false;
|
|
313
348
|
sawText = false;
|
|
314
349
|
separator = false;
|
|
@@ -318,6 +353,11 @@ var OpenCodeTurn = class {
|
|
|
318
353
|
stepError;
|
|
319
354
|
constructor(a) {
|
|
320
355
|
this.a = a;
|
|
356
|
+
this.model = modelOfLabel(a.input.model);
|
|
357
|
+
}
|
|
358
|
+
/** What the run spent so far: carried from before this turn object, plus what it saw. */
|
|
359
|
+
totalUsage() {
|
|
360
|
+
return addUsage(this.a.carried, this.spent);
|
|
321
361
|
}
|
|
322
362
|
get sessionId() {
|
|
323
363
|
return this.a.sessionId;
|
|
@@ -400,7 +440,15 @@ var OpenCodeTurn = class {
|
|
|
400
440
|
this.chain = this.chain.then(() => ask.kind === "approval" ? this.decided(ask, reply, tell) : this.answered(ask, reply, tell)).then(resolve, reject);
|
|
401
441
|
});
|
|
402
442
|
}
|
|
403
|
-
reach(
|
|
443
|
+
reach(reached) {
|
|
444
|
+
const usage = subUsage(this.spent, this.reported);
|
|
445
|
+
this.reported = {
|
|
446
|
+
...this.spent
|
|
447
|
+
};
|
|
448
|
+
const milestone = {
|
|
449
|
+
...reached,
|
|
450
|
+
usage
|
|
451
|
+
};
|
|
404
452
|
const waiting = this.waiting;
|
|
405
453
|
if (waiting !== void 0) {
|
|
406
454
|
this.waiting = void 0;
|
|
@@ -556,9 +604,22 @@ var OpenCodeTurn = class {
|
|
|
556
604
|
}
|
|
557
605
|
}
|
|
558
606
|
async onEvent(e) {
|
|
559
|
-
if (this.ended) return;
|
|
560
607
|
const d = e.data ?? {};
|
|
608
|
+
if (e.type === "session.usage.recorded") {
|
|
609
|
+
await this.usageRecorded(d);
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
if (this.ended) return;
|
|
561
613
|
switch (e.type) {
|
|
614
|
+
case "session.step.started":
|
|
615
|
+
case "session.model.selected": {
|
|
616
|
+
const model = d.model;
|
|
617
|
+
if (typeof model?.id === "string" && typeof model.providerID === "string") this.model = {
|
|
618
|
+
providerID: model.providerID,
|
|
619
|
+
id: model.id
|
|
620
|
+
};
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
562
623
|
case "session.text.delta": {
|
|
563
624
|
const delta = typeof d.delta === "string" ? d.delta : "";
|
|
564
625
|
if (!delta) return;
|
|
@@ -712,41 +773,63 @@ ${delta}` : delta;
|
|
|
712
773
|
});
|
|
713
774
|
}
|
|
714
775
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
};
|
|
726
|
-
|
|
727
|
-
this.
|
|
728
|
-
|
|
729
|
-
|
|
776
|
+
modelId() {
|
|
777
|
+
return this.model !== void 0 ? `${this.model.providerID}/${this.model.id}` : this.a.modelLabel;
|
|
778
|
+
}
|
|
779
|
+
/** One model call's usage and cost, into the ledger and the run's total. */
|
|
780
|
+
async spend(d, purpose) {
|
|
781
|
+
const usage = usageOf(d.tokens);
|
|
782
|
+
const reportedCostUsd = typeof d.cost === "number" && Number.isFinite(d.cost) && d.cost >= 0 ? d.cost : void 0;
|
|
783
|
+
const fallback = reportedCostUsd !== void 0 ? {
|
|
784
|
+
costUsd: reportedCostUsd,
|
|
785
|
+
costSource: "provider"
|
|
786
|
+
} : {};
|
|
787
|
+
let cost = fallback;
|
|
788
|
+
if (this.a.priceStep !== void 0) {
|
|
789
|
+
cost = await this.a.priceStep({
|
|
790
|
+
model: this.model,
|
|
791
|
+
usage,
|
|
792
|
+
reportedCostUsd
|
|
793
|
+
}).catch(() => fallback);
|
|
794
|
+
}
|
|
795
|
+
this.spent = addUsage(this.spent, {
|
|
796
|
+
inputTokens: usage.inputTokens,
|
|
797
|
+
outputTokens: usage.outputTokens,
|
|
798
|
+
cacheReadTokens: usage.cacheReadTokens ?? 0,
|
|
799
|
+
cacheWriteTokens: usage.cacheWriteTokens ?? 0,
|
|
800
|
+
reasoningTokens: usage.reasoningTokens ?? 0,
|
|
801
|
+
costUsd: cost.costUsd ?? 0
|
|
802
|
+
});
|
|
803
|
+
if (cost.costUsd !== void 0) this.priced = true;
|
|
730
804
|
await this.a.store.recordUsage({
|
|
731
805
|
threadId: this.a.input.threadId,
|
|
732
806
|
actorRef: this.a.input.actor.id,
|
|
733
|
-
modelId: this.
|
|
734
|
-
purpose
|
|
807
|
+
modelId: this.modelId(),
|
|
808
|
+
purpose,
|
|
735
809
|
usage,
|
|
736
|
-
...
|
|
737
|
-
costUsd
|
|
738
|
-
} : {}
|
|
810
|
+
...cost
|
|
739
811
|
});
|
|
812
|
+
return {
|
|
813
|
+
usage,
|
|
814
|
+
cost
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
/** `session.usage.recorded`: a call OpenCode made besides the steps (the title, a compaction). */
|
|
818
|
+
async usageRecorded(d) {
|
|
819
|
+
await this.spend(d, d.source === "title" ? "title" : "history_summary");
|
|
820
|
+
}
|
|
821
|
+
async stepEnded(d) {
|
|
822
|
+
const { usage, cost } = await this.spend(d, "chat");
|
|
740
823
|
if (!this.stepOpen) return;
|
|
741
824
|
this.stepOpen = false;
|
|
742
825
|
await this.write({
|
|
743
826
|
kind: "step-finish",
|
|
744
827
|
usage,
|
|
745
|
-
costUsd: costUsd ?? null,
|
|
828
|
+
costUsd: cost.costUsd ?? null,
|
|
746
829
|
...this.segment.reasoningMs > 0 ? {
|
|
747
830
|
reasoningMs: this.segment.reasoningMs
|
|
748
831
|
} : {},
|
|
749
|
-
model: this.
|
|
832
|
+
model: this.modelId()
|
|
750
833
|
});
|
|
751
834
|
}
|
|
752
835
|
/**
|
|
@@ -765,12 +848,7 @@ ${delta}` : delta;
|
|
|
765
848
|
content: s.text,
|
|
766
849
|
runId: this.a.runId,
|
|
767
850
|
...final ? {
|
|
768
|
-
usage:
|
|
769
|
-
...this.usage,
|
|
770
|
-
...this.costUsd !== void 0 ? {
|
|
771
|
-
costUsd: this.costUsd
|
|
772
|
-
} : {}
|
|
773
|
-
}
|
|
851
|
+
usage: this.messageUsage()
|
|
774
852
|
} : {},
|
|
775
853
|
...this.a.input.agentName !== void 0 ? {
|
|
776
854
|
agentName: this.a.input.agentName
|
|
@@ -798,6 +876,26 @@ ${delta}` : delta;
|
|
|
798
876
|
]);
|
|
799
877
|
return message.id;
|
|
800
878
|
}
|
|
879
|
+
/** The run's usage as its last message carries it: the whole run, cache tokens included. */
|
|
880
|
+
messageUsage() {
|
|
881
|
+
const total = this.totalUsage();
|
|
882
|
+
return {
|
|
883
|
+
inputTokens: total.inputTokens,
|
|
884
|
+
outputTokens: total.outputTokens,
|
|
885
|
+
...total.cacheReadTokens > 0 ? {
|
|
886
|
+
cacheReadTokens: total.cacheReadTokens
|
|
887
|
+
} : {},
|
|
888
|
+
...total.cacheWriteTokens > 0 ? {
|
|
889
|
+
cacheWriteTokens: total.cacheWriteTokens
|
|
890
|
+
} : {},
|
|
891
|
+
...total.reasoningTokens > 0 ? {
|
|
892
|
+
reasoningTokens: total.reasoningTokens
|
|
893
|
+
} : {},
|
|
894
|
+
...this.priced || (this.a.carried?.costUsd ?? 0) > 0 ? {
|
|
895
|
+
costUsd: total.costUsd
|
|
896
|
+
} : {}
|
|
897
|
+
};
|
|
898
|
+
}
|
|
801
899
|
/** A request recorded by an earlier process (a turn resumed after a restart). */
|
|
802
900
|
async alreadyRecorded(id) {
|
|
803
901
|
return (await this.a.store.toolCallApproval?.(id) ?? null) !== null;
|
|
@@ -1167,6 +1265,35 @@ ${delta}` : delta;
|
|
|
1167
1265
|
});
|
|
1168
1266
|
}
|
|
1169
1267
|
};
|
|
1268
|
+
function modelOfLabel(label) {
|
|
1269
|
+
const slash = label?.indexOf("/") ?? -1;
|
|
1270
|
+
if (label === void 0 || slash <= 0 || slash === label.length - 1) return void 0;
|
|
1271
|
+
return {
|
|
1272
|
+
providerID: label.slice(0, slash),
|
|
1273
|
+
id: label.slice(slash + 1)
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
__name(modelOfLabel, "modelOfLabel");
|
|
1277
|
+
function usageOf(tokens) {
|
|
1278
|
+
const n = /* @__PURE__ */ __name((v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0, "n");
|
|
1279
|
+
const read = n(tokens?.cache?.read);
|
|
1280
|
+
const write = n(tokens?.cache?.write);
|
|
1281
|
+
const reasoning = n(tokens?.reasoning);
|
|
1282
|
+
return {
|
|
1283
|
+
inputTokens: n(tokens?.input) + read + write,
|
|
1284
|
+
outputTokens: n(tokens?.output),
|
|
1285
|
+
...read > 0 ? {
|
|
1286
|
+
cacheReadTokens: read
|
|
1287
|
+
} : {},
|
|
1288
|
+
...write > 0 ? {
|
|
1289
|
+
cacheWriteTokens: write
|
|
1290
|
+
} : {},
|
|
1291
|
+
...reasoning > 0 ? {
|
|
1292
|
+
reasoningTokens: reasoning
|
|
1293
|
+
} : {}
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
__name(usageOf, "usageOf");
|
|
1170
1297
|
|
|
1171
1298
|
// src/mcp.ts
|
|
1172
1299
|
var LOOP_SERVED_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -1431,7 +1558,7 @@ import { Inject as Inject3, Injectable as Injectable2 } from "@nestjs/common";
|
|
|
1431
1558
|
// src/turns.ts
|
|
1432
1559
|
import { randomUUID } from "crypto";
|
|
1433
1560
|
import { AGENT_CHAT_QUEUE } from "@dudousxd/nestjs-agent";
|
|
1434
|
-
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";
|
|
1561
|
+
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";
|
|
1435
1562
|
import { Inject as Inject2, Injectable, Logger as Logger2, Optional } from "@nestjs/common";
|
|
1436
1563
|
|
|
1437
1564
|
// src/event-hub.ts
|
|
@@ -1598,7 +1725,7 @@ var OpenCodeTurns = class {
|
|
|
1598
1725
|
spent = /* @__PURE__ */ new Set();
|
|
1599
1726
|
/** When the tools endpoint was last registered for a location (`server|boot|directory|actor`). */
|
|
1600
1727
|
toolsIssued = /* @__PURE__ */ new Map();
|
|
1601
|
-
constructor(host, sessions, settings, store, sink, deps, registry, skills, memory, queue, toolsTokens2) {
|
|
1728
|
+
constructor(host, sessions, settings, store, sink, deps, registry, skills, memory, queue, toolsTokens2, pricingStore, agentOptions) {
|
|
1602
1729
|
this.host = host;
|
|
1603
1730
|
this.sessions = sessions;
|
|
1604
1731
|
this.settings = settings;
|
|
@@ -1610,6 +1737,30 @@ var OpenCodeTurns = class {
|
|
|
1610
1737
|
this.memory = memory;
|
|
1611
1738
|
this.queue = queue;
|
|
1612
1739
|
this.toolsTokens = toolsTokens2;
|
|
1740
|
+
this.prices = new ModelPriceResolver({
|
|
1741
|
+
pricingStore,
|
|
1742
|
+
catalog: agentOptions?.priceCatalog,
|
|
1743
|
+
log: {
|
|
1744
|
+
info: /* @__PURE__ */ __name((message) => this.logger.log(message), "info"),
|
|
1745
|
+
warn: /* @__PURE__ */ __name((message) => this.logger.warn(message), "warn")
|
|
1746
|
+
}
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
prices;
|
|
1750
|
+
/**
|
|
1751
|
+
* What a model call OpenCode made cost, by the same rule the library's loop records its own steps
|
|
1752
|
+
* at: a reported figure wins, else an estimate off the model's price — see
|
|
1753
|
+
* {@link OpenCodeEngineSettings.cost}.
|
|
1754
|
+
*/
|
|
1755
|
+
async priceStep(step) {
|
|
1756
|
+
const { model, usage, reportedCostUsd } = step;
|
|
1757
|
+
const tokens = usage.inputTokens + usage.outputTokens;
|
|
1758
|
+
const reported = reportedCostUsd !== void 0 && (reportedCostUsd > 0 || tokens === 0);
|
|
1759
|
+
if (reported && this.settings.cost !== "estimate") {
|
|
1760
|
+
return resolveUsageCost(usage, reportedCostUsd, void 0);
|
|
1761
|
+
}
|
|
1762
|
+
const price = model !== void 0 && tokens > 0 ? await this.prices.priceFor(priceRef(model)) : void 0;
|
|
1763
|
+
return resolveUsageCost(usage, price === void 0 ? reportedCostUsd : void 0, price);
|
|
1613
1764
|
}
|
|
1614
1765
|
/** The tools server's name in OpenCode. */
|
|
1615
1766
|
get toolsServer() {
|
|
@@ -2199,8 +2350,8 @@ ${body}
|
|
|
2199
2350
|
}
|
|
2200
2351
|
// ---- prompt / observe / reply --------------------------------------------------------------
|
|
2201
2352
|
/** Start listening to the session (so nothing it says is missed), then send the user message. */
|
|
2202
|
-
async prompt(runId, input, handle) {
|
|
2203
|
-
const live = await this.ensureLive(runId, input, handle, false);
|
|
2353
|
+
async prompt(runId, input, handle, spent) {
|
|
2354
|
+
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2204
2355
|
try {
|
|
2205
2356
|
const prompt = await this.host.promptFor?.({
|
|
2206
2357
|
input,
|
|
@@ -2230,9 +2381,12 @@ ${body}
|
|
|
2230
2381
|
* Wait for the turn's next milestone. In a process that was not following the turn (a resumed
|
|
2231
2382
|
* durable run), the turn is rebuilt and first catches up on requests OpenCode raised meanwhile;
|
|
2232
2383
|
* `session.wait` is the safety net for a terminal event that was missed.
|
|
2384
|
+
*
|
|
2385
|
+
* `spent` is what the run spent before (the sum of the `usage` of its earlier milestones): a turn
|
|
2386
|
+
* rebuilt here starts from it, so the answer it persists carries the whole run's usage.
|
|
2233
2387
|
*/
|
|
2234
|
-
async observe(runId, input, handle) {
|
|
2235
|
-
const live = await this.ensureLive(runId, input, handle, true);
|
|
2388
|
+
async observe(runId, input, handle, spent) {
|
|
2389
|
+
const live = await this.ensureLive(runId, input, handle, true, spent);
|
|
2236
2390
|
const { turn, client } = live;
|
|
2237
2391
|
if (turn.hasMilestone()) return this.reached(runId, input, handle, await turn.next());
|
|
2238
2392
|
let done = false;
|
|
@@ -2271,23 +2425,23 @@ ${body}
|
|
|
2271
2425
|
* request is gone with it: a new session is opened, told what the person decided, and prompted
|
|
2272
2426
|
* to go on.
|
|
2273
2427
|
*/
|
|
2274
|
-
async reply(runId, input, handle, ask, reply) {
|
|
2428
|
+
async reply(runId, input, handle, ask, reply, spent) {
|
|
2275
2429
|
const server = await this.host.server(input.actor);
|
|
2276
2430
|
if (server.key !== handle.serverKey || server.bootId !== handle.bootId) {
|
|
2277
|
-
return this.continueAfterRestart(runId, input, server, ask, reply);
|
|
2431
|
+
return this.continueAfterRestart(runId, input, server, ask, reply, spent);
|
|
2278
2432
|
}
|
|
2279
|
-
const live = await this.ensureLive(runId, input, handle, false);
|
|
2433
|
+
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2280
2434
|
await live.turn.decide(ask, reply);
|
|
2281
2435
|
return handle;
|
|
2282
2436
|
}
|
|
2283
|
-
async continueAfterRestart(runId, input, server, ask, reply) {
|
|
2437
|
+
async continueAfterRestart(runId, input, server, ask, reply, spent) {
|
|
2284
2438
|
const approved = "approved" in reply && reply.approved === true;
|
|
2285
2439
|
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.`;
|
|
2286
2440
|
const thread = await this.store.getThread(input.threadId);
|
|
2287
2441
|
const handle = await this.createSession(runId, input, server, thread?.messages ?? [], note);
|
|
2288
2442
|
await this.refreshInstructions(runId, input, server.client, handle.sessionId);
|
|
2289
2443
|
this.drop(runId);
|
|
2290
|
-
const live = await this.ensureLive(runId, input, handle, false);
|
|
2444
|
+
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2291
2445
|
await live.turn.decide(ask, reply, {
|
|
2292
2446
|
tellOpenCode: false
|
|
2293
2447
|
});
|
|
@@ -2307,7 +2461,7 @@ ${body}
|
|
|
2307
2461
|
sessionID: known.sessionId
|
|
2308
2462
|
});
|
|
2309
2463
|
}
|
|
2310
|
-
async ensureLive(runId, input, handle, catchUp) {
|
|
2464
|
+
async ensureLive(runId, input, handle, catchUp, spent) {
|
|
2311
2465
|
const current = this.live.get(runId);
|
|
2312
2466
|
if (current !== void 0 && current.handle.sessionId === handle.sessionId) return current;
|
|
2313
2467
|
current?.stop();
|
|
@@ -2333,6 +2487,10 @@ ${body}
|
|
|
2333
2487
|
} : {}
|
|
2334
2488
|
}), "approvalFor"),
|
|
2335
2489
|
modelLabel: input.model ?? "opencode",
|
|
2490
|
+
priceStep: /* @__PURE__ */ __name((step) => this.priceStep(step), "priceStep"),
|
|
2491
|
+
...spent !== void 0 ? {
|
|
2492
|
+
carried: spent
|
|
2493
|
+
} : {},
|
|
2336
2494
|
logger: this.logger,
|
|
2337
2495
|
onGranted: /* @__PURE__ */ __name((action, id) => {
|
|
2338
2496
|
const grants = this.grants.get(runId) ?? [];
|
|
@@ -2379,20 +2537,14 @@ ${body}
|
|
|
2379
2537
|
}
|
|
2380
2538
|
return milestone;
|
|
2381
2539
|
}
|
|
2382
|
-
/**
|
|
2383
|
-
|
|
2540
|
+
/**
|
|
2541
|
+
* What the run produced, as the host's settle hooks see it. `usage` is what the run spent — the
|
|
2542
|
+
* runner's sum of its milestones' usage, which a resumed run reads back from its journal — else
|
|
2543
|
+
* what the turn this process follows saw.
|
|
2544
|
+
*/
|
|
2545
|
+
async runResult(runId, input, outcome, durationMs, usage) {
|
|
2384
2546
|
const thread = await this.store.getThread(input.threadId);
|
|
2385
2547
|
const messages = (thread?.messages ?? []).filter((m) => m.role === "assistant" && m.runId === runId);
|
|
2386
|
-
const usage = {
|
|
2387
|
-
inputTokens: 0,
|
|
2388
|
-
outputTokens: 0,
|
|
2389
|
-
costUsd: 0
|
|
2390
|
-
};
|
|
2391
|
-
for (const m of messages) {
|
|
2392
|
-
usage.inputTokens += m.usage?.inputTokens ?? 0;
|
|
2393
|
-
usage.outputTokens += m.usage?.outputTokens ?? 0;
|
|
2394
|
-
usage.costUsd += m.usage?.costUsd ?? 0;
|
|
2395
|
-
}
|
|
2396
2548
|
return {
|
|
2397
2549
|
runId,
|
|
2398
2550
|
input,
|
|
@@ -2437,15 +2589,31 @@ ${body}
|
|
|
2437
2589
|
this.logger.warn(`onSettled failed: ${errorText(error, "error")}`);
|
|
2438
2590
|
}
|
|
2439
2591
|
}
|
|
2440
|
-
/**
|
|
2441
|
-
|
|
2592
|
+
/**
|
|
2593
|
+
* What the run spent: the runner's sum of its milestones, or what the turn this process follows
|
|
2594
|
+
* saw (which starts from that sum) when it saw more — a run that failed or was cancelled between
|
|
2595
|
+
* two milestones.
|
|
2596
|
+
*/
|
|
2597
|
+
spentBy(runId, spent) {
|
|
2598
|
+
const seen = this.live.get(runId)?.turn.totalUsage();
|
|
2599
|
+
if (spent === void 0) return seen ?? emptyUsage();
|
|
2600
|
+
if (seen === void 0) return spent;
|
|
2601
|
+
const tokens = /* @__PURE__ */ __name((u) => u.inputTokens + u.outputTokens, "tokens");
|
|
2602
|
+
return tokens(seen) > tokens(spent) ? seen : spent;
|
|
2603
|
+
}
|
|
2604
|
+
/**
|
|
2605
|
+
* End the run's stream and bookkeeping for how its execution ended. `spent` is what the run spent
|
|
2606
|
+
* (the sum of its milestones' `usage`); omit → what the turn this process follows saw.
|
|
2607
|
+
*/
|
|
2608
|
+
async settle(runId, input, outcome, durationMs, spent) {
|
|
2442
2609
|
if (outcome.status === "failed") {
|
|
2443
|
-
await this.settleFailed(runId, input, outcome.error, durationMs);
|
|
2610
|
+
await this.settleFailed(runId, input, outcome.error, durationMs, spent);
|
|
2444
2611
|
return;
|
|
2445
2612
|
}
|
|
2613
|
+
const usage = this.spentBy(runId, spent);
|
|
2446
2614
|
this.forget(runId);
|
|
2447
2615
|
const writer = await this.sink.open(runId);
|
|
2448
|
-
const result = await this.runResult(runId, input, outcome, durationMs);
|
|
2616
|
+
const result = await this.runResult(runId, input, outcome, durationMs, usage);
|
|
2449
2617
|
await this.amend(writer, result);
|
|
2450
2618
|
if (outcome.status === "interrupted") {
|
|
2451
2619
|
this.logger.log(`agent run ${runId} cancelled`);
|
|
@@ -2473,13 +2641,14 @@ ${body}
|
|
|
2473
2641
|
}
|
|
2474
2642
|
await this.settled(result);
|
|
2475
2643
|
}
|
|
2476
|
-
async settleFailed(runId, input, error, durationMs = 0) {
|
|
2644
|
+
async settleFailed(runId, input, error, durationMs = 0, spent) {
|
|
2645
|
+
const usage = this.spentBy(runId, spent);
|
|
2477
2646
|
this.forget(runId);
|
|
2478
2647
|
const writer = await this.sink.open(runId);
|
|
2479
2648
|
const result = await this.runResult(runId, input, {
|
|
2480
2649
|
status: "failed",
|
|
2481
2650
|
error
|
|
2482
|
-
}, durationMs);
|
|
2651
|
+
}, durationMs, usage);
|
|
2483
2652
|
const worded = (await this.amend(writer, result)).error;
|
|
2484
2653
|
const message = worded ?? streamFailure(new Error(error)).message;
|
|
2485
2654
|
this.logger.error(`agent run ${runId} failed: ${error}`);
|
|
@@ -2549,6 +2718,10 @@ OpenCodeTurns = _ts_decorate2([
|
|
|
2549
2718
|
_ts_param2(9, Inject2(AGENT_CHAT_QUEUE)),
|
|
2550
2719
|
_ts_param2(10, Optional()),
|
|
2551
2720
|
_ts_param2(10, Inject2(OPENCODE_TOOLS_TOKENS)),
|
|
2721
|
+
_ts_param2(11, Optional()),
|
|
2722
|
+
_ts_param2(11, Inject2(AGENT_PRICING_STORE)),
|
|
2723
|
+
_ts_param2(12, Optional()),
|
|
2724
|
+
_ts_param2(12, Inject2(AGENT_OPTIONS)),
|
|
2552
2725
|
_ts_metadata2("design:type", Function),
|
|
2553
2726
|
_ts_metadata2("design:paramtypes", [
|
|
2554
2727
|
typeof OpenCodeHost === "undefined" ? Object : OpenCodeHost,
|
|
@@ -2561,6 +2734,8 @@ OpenCodeTurns = _ts_decorate2([
|
|
|
2561
2734
|
typeof SkillsConfig === "undefined" ? Object : SkillsConfig,
|
|
2562
2735
|
typeof MemoryConfig === "undefined" ? Object : MemoryConfig,
|
|
2563
2736
|
typeof ChatQueueService === "undefined" ? Object : ChatQueueService,
|
|
2737
|
+
Object,
|
|
2738
|
+
typeof AgentPricingStore === "undefined" ? Object : AgentPricingStore,
|
|
2564
2739
|
Object
|
|
2565
2740
|
])
|
|
2566
2741
|
], OpenCodeTurns);
|
|
@@ -2603,6 +2778,19 @@ function uiEmitter(scope, push) {
|
|
|
2603
2778
|
};
|
|
2604
2779
|
}
|
|
2605
2780
|
__name(uiEmitter, "uiEmitter");
|
|
2781
|
+
function priceRef(model) {
|
|
2782
|
+
const aliases = [
|
|
2783
|
+
model.id
|
|
2784
|
+
];
|
|
2785
|
+
const tail = model.id.slice(model.id.lastIndexOf("/") + 1);
|
|
2786
|
+
if (tail !== model.id && parseBedrockModelId(tail) !== void 0) aliases.push(tail);
|
|
2787
|
+
return {
|
|
2788
|
+
modelId: `${model.providerID}/${model.id}`,
|
|
2789
|
+
provider: model.providerID,
|
|
2790
|
+
aliases
|
|
2791
|
+
};
|
|
2792
|
+
}
|
|
2793
|
+
__name(priceRef, "priceRef");
|
|
2606
2794
|
|
|
2607
2795
|
// src/runner.ts
|
|
2608
2796
|
function _ts_decorate3(decorators, target, key, desc) {
|
|
@@ -2704,18 +2892,20 @@ var OpenCodeAgentRunner = class {
|
|
|
2704
2892
|
async run(runId, input) {
|
|
2705
2893
|
const started = Date.now();
|
|
2706
2894
|
this.inputs.set(runId, input);
|
|
2895
|
+
let spent = emptyUsage();
|
|
2707
2896
|
try {
|
|
2708
2897
|
let handle = await this.turns.begin(runId, input);
|
|
2709
2898
|
if (this.cancelled.has(runId)) throw new RunCancelledError();
|
|
2710
|
-
await this.turns.prompt(runId, input, handle);
|
|
2899
|
+
await this.turns.prompt(runId, input, handle, spent);
|
|
2711
2900
|
for (; ; ) {
|
|
2712
|
-
const milestone = await this.turns.observe(runId, input, handle);
|
|
2901
|
+
const milestone = await this.turns.observe(runId, input, handle, spent);
|
|
2902
|
+
spent = addUsage(spent, milestone.usage);
|
|
2713
2903
|
if (milestone.kind === "finished") {
|
|
2714
|
-
await this.turns.settle(runId, input, milestone.outcome, Date.now() - started);
|
|
2904
|
+
await this.turns.settle(runId, input, milestone.outcome, Date.now() - started, spent);
|
|
2715
2905
|
return;
|
|
2716
2906
|
}
|
|
2717
2907
|
const reply = await this.park(runId, milestone.ask.id, milestone.ask.kind === "approval" ? "approval" : "answers", milestone.timeoutMs);
|
|
2718
|
-
handle = await this.turns.reply(runId, input, handle, milestone.ask, reply);
|
|
2908
|
+
handle = await this.turns.reply(runId, input, handle, milestone.ask, reply, spent);
|
|
2719
2909
|
}
|
|
2720
2910
|
} catch (error) {
|
|
2721
2911
|
if (error instanceof RunCancelledError) {
|
|
@@ -2725,7 +2915,7 @@ var OpenCodeAgentRunner = class {
|
|
|
2725
2915
|
}, Date.now() - started);
|
|
2726
2916
|
return;
|
|
2727
2917
|
}
|
|
2728
|
-
await this.turns.settleFailed(runId, input, errorText(error, "the turn failed"));
|
|
2918
|
+
await this.turns.settleFailed(runId, input, errorText(error, "the turn failed"), Date.now() - started);
|
|
2729
2919
|
} finally {
|
|
2730
2920
|
this.inputs.delete(runId);
|
|
2731
2921
|
}
|
|
@@ -2877,6 +3067,8 @@ export {
|
|
|
2877
3067
|
OpenCodeToolsTokens,
|
|
2878
3068
|
OpenCodeTurn,
|
|
2879
3069
|
OpenCodeTurns,
|
|
3070
|
+
addUsage,
|
|
3071
|
+
emptyUsage,
|
|
2880
3072
|
keyValueOpenCodeSessionStore,
|
|
2881
3073
|
openCode,
|
|
2882
3074
|
openCodeControllers,
|
|
@@ -2884,6 +3076,7 @@ export {
|
|
|
2884
3076
|
sessionOf,
|
|
2885
3077
|
toElicitation,
|
|
2886
3078
|
toFormAnswer,
|
|
2887
|
-
toQuestion
|
|
3079
|
+
toQuestion,
|
|
3080
|
+
usageOf
|
|
2888
3081
|
};
|
|
2889
3082
|
//# sourceMappingURL=index.js.map
|