@dudousxd/nestjs-agent-opencode 0.2.0 → 0.3.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 +6 -1
- package/dist/durable/index.cjs +107 -0
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.d.cts +1 -1
- package/dist/durable/index.d.ts +1 -1
- package/dist/durable/index.js +108 -1
- package/dist/durable/index.js.map +1 -1
- package/dist/{engine-JnBbcRxh.d.cts → engine-Cp5uysaN.d.cts} +46 -1
- package/dist/{engine-JnBbcRxh.d.ts → engine-Cp5uysaN.d.ts} +46 -1
- package/dist/index.cjs +107 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +108 -1
- 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-Cp5uysaN.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-Cp5uysaN.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
|
@@ -132,7 +132,7 @@ import { toJsonSchemaCompat } from "@modelcontextprotocol/sdk/server/zod-json-sc
|
|
|
132
132
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
133
133
|
|
|
134
134
|
// src/turn.ts
|
|
135
|
-
import { encodeStreamEvent, settleElicitation } from "@dudousxd/nestjs-agent-core";
|
|
135
|
+
import { encodeStreamEvent, resolveToolConfirmation, settleElicitation } from "@dudousxd/nestjs-agent-core";
|
|
136
136
|
import { ConflictException } from "@nestjs/common";
|
|
137
137
|
|
|
138
138
|
// src/forms.ts
|
|
@@ -326,6 +326,17 @@ var OpenCodeTurn = class {
|
|
|
326
326
|
reported = emptyUsage();
|
|
327
327
|
priced = false;
|
|
328
328
|
model;
|
|
329
|
+
/** What the session had spent when this turn prompted it; what OpenCode reported since. */
|
|
330
|
+
baseline;
|
|
331
|
+
seen = {
|
|
332
|
+
cost: 0,
|
|
333
|
+
input: 0,
|
|
334
|
+
output: 0,
|
|
335
|
+
reasoning: 0,
|
|
336
|
+
read: 0,
|
|
337
|
+
write: 0
|
|
338
|
+
};
|
|
339
|
+
compacted = false;
|
|
329
340
|
stepOpen = false;
|
|
330
341
|
sawText = false;
|
|
331
342
|
separator = false;
|
|
@@ -337,6 +348,19 @@ var OpenCodeTurn = class {
|
|
|
337
348
|
this.a = a;
|
|
338
349
|
this.model = modelOfLabel(a.input.model);
|
|
339
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* What the session had spent before this turn prompted it (`session.get`). When the execution
|
|
353
|
+
* ends, what the session spent since that this turn's events did not report — the title OpenCode
|
|
354
|
+
* generates, a compaction: OpenCode records those calls on the session without streaming them — is
|
|
355
|
+
* recorded as a usage row of its own.
|
|
356
|
+
*/
|
|
357
|
+
setBaseline(info) {
|
|
358
|
+
if (info?.tokens === void 0) return;
|
|
359
|
+
this.baseline = {
|
|
360
|
+
cost: Number(info.cost) || 0,
|
|
361
|
+
tokens: info.tokens
|
|
362
|
+
};
|
|
363
|
+
}
|
|
340
364
|
/** What the run spent so far: carried from before this turn object, plus what it saw. */
|
|
341
365
|
totalUsage() {
|
|
342
366
|
return addUsage(this.a.carried, this.spent);
|
|
@@ -593,6 +617,10 @@ var OpenCodeTurn = class {
|
|
|
593
617
|
}
|
|
594
618
|
if (this.ended) return;
|
|
595
619
|
switch (e.type) {
|
|
620
|
+
case "session.compaction.started":
|
|
621
|
+
case "session.compaction.ended":
|
|
622
|
+
this.compacted = true;
|
|
623
|
+
return;
|
|
596
624
|
case "session.step.started":
|
|
597
625
|
case "session.model.selected": {
|
|
598
626
|
const model = d.model;
|
|
@@ -762,6 +790,13 @@ ${delta}` : delta;
|
|
|
762
790
|
async spend(d, purpose) {
|
|
763
791
|
const usage = usageOf(d.tokens);
|
|
764
792
|
const reportedCostUsd = typeof d.cost === "number" && Number.isFinite(d.cost) && d.cost >= 0 ? d.cost : void 0;
|
|
793
|
+
const n = /* @__PURE__ */ __name((v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0, "n");
|
|
794
|
+
this.seen.cost += reportedCostUsd ?? 0;
|
|
795
|
+
this.seen.input += n(d.tokens?.input);
|
|
796
|
+
this.seen.output += n(d.tokens?.output);
|
|
797
|
+
this.seen.reasoning += n(d.tokens?.reasoning);
|
|
798
|
+
this.seen.read += n(d.tokens?.cache?.read);
|
|
799
|
+
this.seen.write += n(d.tokens?.cache?.write);
|
|
765
800
|
const fallback = reportedCostUsd !== void 0 ? {
|
|
766
801
|
costUsd: reportedCostUsd,
|
|
767
802
|
costSource: "provider"
|
|
@@ -967,6 +1002,8 @@ ${delta}` : delta;
|
|
|
967
1002
|
}
|
|
968
1003
|
const ttlMs = requirement.ttlMs !== void 0 && Number.isFinite(requirement.ttlMs) && requirement.ttlMs > 0 ? Math.floor(requirement.ttlMs) : void 0;
|
|
969
1004
|
const expiresAt = ttlMs !== void 0 ? new Date(Date.now() + ttlMs).toISOString() : void 0;
|
|
1005
|
+
const tool = this.a.approvalPresentation?.(action);
|
|
1006
|
+
const confirmation = tool !== void 0 ? resolveToolConfirmation(tool.name, args, tool.presentation) : void 0;
|
|
970
1007
|
this.segment.calls.push({
|
|
971
1008
|
id: req.id,
|
|
972
1009
|
name: action,
|
|
@@ -981,6 +1018,9 @@ ${delta}` : delta;
|
|
|
981
1018
|
toolType: "action",
|
|
982
1019
|
input: args,
|
|
983
1020
|
status: "pending_approval",
|
|
1021
|
+
...confirmation !== void 0 ? {
|
|
1022
|
+
confirmation
|
|
1023
|
+
} : {},
|
|
984
1024
|
runId: this.a.runId,
|
|
985
1025
|
approver: requirement.approver,
|
|
986
1026
|
...expiresAt !== void 0 ? {
|
|
@@ -998,6 +1038,9 @@ ${delta}` : delta;
|
|
|
998
1038
|
kind: "approval-requested",
|
|
999
1039
|
id: req.id,
|
|
1000
1040
|
approver: requirement.approver,
|
|
1041
|
+
...confirmation !== void 0 ? {
|
|
1042
|
+
confirmation
|
|
1043
|
+
} : {},
|
|
1001
1044
|
...expiresAt !== void 0 ? {
|
|
1002
1045
|
expiresAt
|
|
1003
1046
|
} : {}
|
|
@@ -1229,9 +1272,39 @@ ${delta}` : delta;
|
|
|
1229
1272
|
this.messageResults.set(messageId, results);
|
|
1230
1273
|
await this.a.store.setMessageToolResults(messageId, results);
|
|
1231
1274
|
}
|
|
1275
|
+
/** What the session spent since the baseline that no event of this turn reported. */
|
|
1276
|
+
async unreported() {
|
|
1277
|
+
const baseline = this.baseline;
|
|
1278
|
+
if (baseline === void 0) return;
|
|
1279
|
+
this.baseline = void 0;
|
|
1280
|
+
const info = await this.a.client.session.get?.({
|
|
1281
|
+
sessionID: this.a.sessionId
|
|
1282
|
+
}).catch(() => void 0);
|
|
1283
|
+
const after = info?.tokens;
|
|
1284
|
+
if (after === void 0) return;
|
|
1285
|
+
const before = baseline.tokens;
|
|
1286
|
+
const left = /* @__PURE__ */ __name((now, then, seen) => Math.max(0, (Number(now) || 0) - (Number(then) || 0) - seen), "left");
|
|
1287
|
+
const tokens = {
|
|
1288
|
+
input: left(after.input, before.input, this.seen.input),
|
|
1289
|
+
output: left(after.output, before.output, this.seen.output),
|
|
1290
|
+
reasoning: left(after.reasoning, before.reasoning, this.seen.reasoning),
|
|
1291
|
+
cache: {
|
|
1292
|
+
read: left(after.cache?.read, before.cache?.read, this.seen.read),
|
|
1293
|
+
write: left(after.cache?.write, before.cache?.write, this.seen.write)
|
|
1294
|
+
}
|
|
1295
|
+
};
|
|
1296
|
+
const total = tokens.input + tokens.output + tokens.reasoning + tokens.cache.read + tokens.cache.write;
|
|
1297
|
+
if (total === 0) return;
|
|
1298
|
+
const cost = left(info?.cost, baseline.cost, this.seen.cost);
|
|
1299
|
+
await this.spend({
|
|
1300
|
+
tokens,
|
|
1301
|
+
cost: cost < 1e-9 ? 0 : cost
|
|
1302
|
+
}, this.compacted ? "history_summary" : "title");
|
|
1303
|
+
}
|
|
1232
1304
|
async end(outcome) {
|
|
1233
1305
|
if (this.ended) return;
|
|
1234
1306
|
this.ended = true;
|
|
1307
|
+
await this.unreported().catch((error) => this.a.logger.warn(`run ${this.a.runId}: ${errorText(error, "could not read the session usage")}`));
|
|
1235
1308
|
if (outcome.status !== "failed" || this.segment.text || this.segment.calls.length > 0 || this.segment.ui.length > 0) {
|
|
1236
1309
|
await this.flush(true);
|
|
1237
1310
|
}
|
|
@@ -1748,6 +1821,25 @@ var OpenCodeTurns = class {
|
|
|
1748
1821
|
get toolsServer() {
|
|
1749
1822
|
return this.settings.tools?.server ?? "aviary";
|
|
1750
1823
|
}
|
|
1824
|
+
/** The app tool an OpenCode permission `action` names, and its presentation — `undefined` for a built-in. */
|
|
1825
|
+
presentationOf(action) {
|
|
1826
|
+
if (this.settings.tools === void 0) return void 0;
|
|
1827
|
+
const server = this.toolsServer;
|
|
1828
|
+
for (const prefix of [
|
|
1829
|
+
`${server}.`,
|
|
1830
|
+
`${server}_`
|
|
1831
|
+
]) {
|
|
1832
|
+
if (!action.startsWith(prefix)) continue;
|
|
1833
|
+
const spec = this.registry.spec(action.slice(prefix.length));
|
|
1834
|
+
if (spec !== void 0) return {
|
|
1835
|
+
name: spec.name,
|
|
1836
|
+
...spec.presentation !== void 0 ? {
|
|
1837
|
+
presentation: spec.presentation
|
|
1838
|
+
} : {}
|
|
1839
|
+
};
|
|
1840
|
+
}
|
|
1841
|
+
return void 0;
|
|
1842
|
+
}
|
|
1751
1843
|
/** The roles policy a turn's tools are gated by (the agent's own). */
|
|
1752
1844
|
rolesPolicyFor(input) {
|
|
1753
1845
|
return this.deps.forAgent(input.agentName).rolesPolicy;
|
|
@@ -2348,6 +2440,7 @@ ${body}
|
|
|
2348
2440
|
})
|
|
2349
2441
|
} : {}
|
|
2350
2442
|
};
|
|
2443
|
+
live.turn.setBaseline(await this.sessionUsage(live.client, handle.sessionId));
|
|
2351
2444
|
await live.client.session.prompt({
|
|
2352
2445
|
sessionID: handle.sessionId,
|
|
2353
2446
|
text: prompt.text,
|
|
@@ -2427,12 +2520,23 @@ ${body}
|
|
|
2427
2520
|
await live.turn.decide(ask, reply, {
|
|
2428
2521
|
tellOpenCode: false
|
|
2429
2522
|
});
|
|
2523
|
+
live.turn.setBaseline(await this.sessionUsage(live.client, handle.sessionId));
|
|
2430
2524
|
await live.client.session.prompt({
|
|
2431
2525
|
sessionID: handle.sessionId,
|
|
2432
2526
|
text: note
|
|
2433
2527
|
});
|
|
2434
2528
|
return handle;
|
|
2435
2529
|
}
|
|
2530
|
+
/** What a session spent so far (`session.get`), or nothing when OpenCode does not say. */
|
|
2531
|
+
async sessionUsage(client, sessionId) {
|
|
2532
|
+
try {
|
|
2533
|
+
return await client.session.get?.({
|
|
2534
|
+
sessionID: sessionId
|
|
2535
|
+
});
|
|
2536
|
+
} catch {
|
|
2537
|
+
return void 0;
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2436
2540
|
/** Interrupt the thread's session (cancel). */
|
|
2437
2541
|
async interrupt(input) {
|
|
2438
2542
|
const known = await this.sessions.get(input.threadId);
|
|
@@ -2468,6 +2572,9 @@ ${body}
|
|
|
2468
2572
|
agentName: input.agentName
|
|
2469
2573
|
} : {}
|
|
2470
2574
|
}), "approvalFor"),
|
|
2575
|
+
// An app tool reaches OpenCode as `<server>.<name>` / `<server>_<name>`: its own presentation
|
|
2576
|
+
// words the approval card. OpenCode's built-ins (`bash`, `edit`) have none.
|
|
2577
|
+
approvalPresentation: /* @__PURE__ */ __name((action) => this.presentationOf(action), "approvalPresentation"),
|
|
2471
2578
|
modelLabel: input.model ?? "opencode",
|
|
2472
2579
|
priceStep: /* @__PURE__ */ __name((step) => this.priceStep(step), "priceStep"),
|
|
2473
2580
|
...spent !== void 0 ? {
|