@dudousxd/nestjs-agent-opencode 0.4.0 → 0.5.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 +10 -3
- package/dist/durable/index.cjs +272 -13
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.d.cts +3 -2
- package/dist/durable/index.d.ts +3 -2
- package/dist/durable/index.js +273 -14
- package/dist/durable/index.js.map +1 -1
- package/dist/{engine-BNNxQAFV.d.cts → engine-BX6MLzxs.d.cts} +102 -8
- package/dist/{engine-BNNxQAFV.d.ts → engine-BX6MLzxs.d.ts} +102 -8
- package/dist/index.cjs +268 -11
- 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 +268 -12
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
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
|
|
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-BX6MLzxs.cjs';
|
|
2
|
+
export { I as InMemoryOpenCodeSessionStore, L as LOST_ANSWER_ERROR, M as Milestone, j as OpenCodeAmendment, k as OpenCodeCallContext, c as OpenCodeEngineOptions, b as OpenCodeHost, l as OpenCodeKeyValue, m as OpenCodeMessage, n as OpenCodeMessagePart, o as OpenCodeModelRef, p as OpenCodePermissionRequest, q as OpenCodePermissionRule, r as OpenCodeReplyMismatchError, s as OpenCodeRunResult, t as OpenCodeServer, u as OpenCodeSessionCreate, v as OpenCodeSessionRef, w as OpenCodeSessionStore, x as OpenCodeToolCall, y as OpenCodeToolRefusedError, z as OpenCodeToolsClaims, A as OpenCodeToolsOptions, B as OpenCodeToolsTokens, C as OpenCodeTurn, D as OpenCodeTurnContext, E as OpenCodeUsage, P as PendingAsk, S as SessionHandle, F as StepCost, G as StepModel, T as TurnOutcome, H as TurnProgress, J as addUsage, K as emptyUsage, N as keyValueOpenCodeSessionStore, Q as openCode, R as openCodeControllers, U as openCodeProviders, V as usageOf } from './engine-BX6MLzxs.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
|
|
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-BX6MLzxs.js';
|
|
2
|
+
export { I as InMemoryOpenCodeSessionStore, L as LOST_ANSWER_ERROR, M as Milestone, j as OpenCodeAmendment, k as OpenCodeCallContext, c as OpenCodeEngineOptions, b as OpenCodeHost, l as OpenCodeKeyValue, m as OpenCodeMessage, n as OpenCodeMessagePart, o as OpenCodeModelRef, p as OpenCodePermissionRequest, q as OpenCodePermissionRule, r as OpenCodeReplyMismatchError, s as OpenCodeRunResult, t as OpenCodeServer, u as OpenCodeSessionCreate, v as OpenCodeSessionRef, w as OpenCodeSessionStore, x as OpenCodeToolCall, y as OpenCodeToolRefusedError, z as OpenCodeToolsClaims, A as OpenCodeToolsOptions, B as OpenCodeToolsTokens, C as OpenCodeTurn, D as OpenCodeTurnContext, E as OpenCodeUsage, P as PendingAsk, S as SessionHandle, F as StepCost, G as StepModel, T as TurnOutcome, H as TurnProgress, J as addUsage, K as emptyUsage, N as keyValueOpenCodeSessionStore, Q as openCode, R as openCodeControllers, U as openCodeProviders, V as usageOf } from './engine-BX6MLzxs.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
|
@@ -275,6 +275,9 @@ function subUsage(a, b) {
|
|
|
275
275
|
};
|
|
276
276
|
}
|
|
277
277
|
__name(subUsage, "subUsage");
|
|
278
|
+
var LOST_ANSWER_ERROR = "The answer was lost while the agent restarted; ask again.";
|
|
279
|
+
var RECOVER_PAGES = 10;
|
|
280
|
+
var RECOVER_PAGE_SIZE = 100;
|
|
278
281
|
var ASK_TOOL_NAME = "ask";
|
|
279
282
|
var FAILED_STATUSES = /* @__PURE__ */ new Set([
|
|
280
283
|
"error",
|
|
@@ -363,6 +366,14 @@ var OpenCodeTurn = class {
|
|
|
363
366
|
wroteMessage = false;
|
|
364
367
|
ended = false;
|
|
365
368
|
stepError;
|
|
369
|
+
/** What this turn object took from the session's assistant messages (see {@link TurnProgress}). */
|
|
370
|
+
took = {
|
|
371
|
+
text: /* @__PURE__ */ new Map(),
|
|
372
|
+
reasoning: /* @__PURE__ */ new Map(),
|
|
373
|
+
called: /* @__PURE__ */ new Set(),
|
|
374
|
+
settled: /* @__PURE__ */ new Set(),
|
|
375
|
+
steps: /* @__PURE__ */ new Set()
|
|
376
|
+
};
|
|
366
377
|
constructor(a) {
|
|
367
378
|
this.a = a;
|
|
368
379
|
this.model = modelOfLabel(a.input.model);
|
|
@@ -380,6 +391,30 @@ var OpenCodeTurn = class {
|
|
|
380
391
|
tokens: info.tokens
|
|
381
392
|
};
|
|
382
393
|
}
|
|
394
|
+
/** What the turn took so far: carried from before this turn object, plus what it took. */
|
|
395
|
+
progress() {
|
|
396
|
+
const before = this.a.progress;
|
|
397
|
+
const merged = /* @__PURE__ */ __name((carried, own) => {
|
|
398
|
+
const out = {
|
|
399
|
+
...carried ?? {}
|
|
400
|
+
};
|
|
401
|
+
for (const [id, n] of own) out[id] = (out[id] ?? 0) + n;
|
|
402
|
+
return out;
|
|
403
|
+
}, "merged");
|
|
404
|
+
const union = /* @__PURE__ */ __name((carried, own) => [
|
|
405
|
+
.../* @__PURE__ */ new Set([
|
|
406
|
+
...carried ?? [],
|
|
407
|
+
...own
|
|
408
|
+
])
|
|
409
|
+
], "union");
|
|
410
|
+
return {
|
|
411
|
+
text: merged(before?.text, this.took.text),
|
|
412
|
+
reasoning: merged(before?.reasoning, this.took.reasoning),
|
|
413
|
+
called: union(before?.called, this.took.called),
|
|
414
|
+
settled: union(before?.settled, this.took.settled),
|
|
415
|
+
steps: union(before?.steps, this.took.steps)
|
|
416
|
+
};
|
|
417
|
+
}
|
|
383
418
|
/** What the run spent so far: carried from before this turn object, plus what it saw. */
|
|
384
419
|
totalUsage() {
|
|
385
420
|
return addUsage(this.a.carried, this.spent);
|
|
@@ -470,7 +505,11 @@ var OpenCodeTurn = class {
|
|
|
470
505
|
this.reported = {
|
|
471
506
|
...this.spent
|
|
472
507
|
};
|
|
473
|
-
const milestone = {
|
|
508
|
+
const milestone = reached.kind === "ask" ? {
|
|
509
|
+
...reached,
|
|
510
|
+
usage,
|
|
511
|
+
progress: this.progress()
|
|
512
|
+
} : {
|
|
474
513
|
...reached,
|
|
475
514
|
usage
|
|
476
515
|
};
|
|
@@ -525,6 +564,7 @@ var OpenCodeTurn = class {
|
|
|
525
564
|
innerSettled: /* @__PURE__ */ new Set()
|
|
526
565
|
};
|
|
527
566
|
this.tools.set(id, state);
|
|
567
|
+
this.took.called.add(id);
|
|
528
568
|
this.segment.calls.push({
|
|
529
569
|
id,
|
|
530
570
|
name,
|
|
@@ -652,6 +692,7 @@ var OpenCodeTurn = class {
|
|
|
652
692
|
case "session.text.delta": {
|
|
653
693
|
const delta = typeof d.delta === "string" ? d.delta : "";
|
|
654
694
|
if (!delta) return;
|
|
695
|
+
this.count(this.took.text, d.assistantMessageID, delta.length);
|
|
655
696
|
this.endReasoning();
|
|
656
697
|
if (!this.sawText && !delta.trim()) return;
|
|
657
698
|
await this.step();
|
|
@@ -673,6 +714,7 @@ ${delta}` : delta;
|
|
|
673
714
|
case "session.reasoning.delta": {
|
|
674
715
|
const delta = typeof d.delta === "string" ? d.delta : "";
|
|
675
716
|
if (!delta) return;
|
|
717
|
+
this.count(this.took.reasoning, d.assistantMessageID, delta.length);
|
|
676
718
|
this.reasoningSince ??= Date.now();
|
|
677
719
|
await this.step();
|
|
678
720
|
this.segment.reasoning += delta;
|
|
@@ -727,6 +769,7 @@ ${delta}` : delta;
|
|
|
727
769
|
}
|
|
728
770
|
case "session.step.ended":
|
|
729
771
|
this.endReasoning();
|
|
772
|
+
if (typeof d.assistantMessageID === "string") this.took.steps.add(d.assistantMessageID);
|
|
730
773
|
await this.stepEnded(d);
|
|
731
774
|
return;
|
|
732
775
|
case "session.step.failed":
|
|
@@ -767,10 +810,16 @@ ${delta}` : delta;
|
|
|
767
810
|
return;
|
|
768
811
|
}
|
|
769
812
|
}
|
|
813
|
+
/** Characters taken from an assistant message's text or reasoning. */
|
|
814
|
+
count(into, messageId, n) {
|
|
815
|
+
if (typeof messageId !== "string") return;
|
|
816
|
+
into.set(messageId, (into.get(messageId) ?? 0) + n);
|
|
817
|
+
}
|
|
770
818
|
async settleTool(id, ok, error = "failed") {
|
|
771
819
|
const state = this.tool(id);
|
|
772
820
|
if (state.settled) return;
|
|
773
821
|
state.settled = true;
|
|
822
|
+
this.took.settled.add(id);
|
|
774
823
|
if (ok) {
|
|
775
824
|
this.segment.results.push({
|
|
776
825
|
id,
|
|
@@ -1320,9 +1369,171 @@ ${delta}` : delta;
|
|
|
1320
1369
|
cost: cost < 1e-9 ? 0 : cost
|
|
1321
1370
|
}, this.compacted ? "history_summary" : "title");
|
|
1322
1371
|
}
|
|
1323
|
-
|
|
1372
|
+
/**
|
|
1373
|
+
* The session's messages since this turn's prompt, oldest first: everything after its newest user
|
|
1374
|
+
* message. `undefined` when they cannot be read (no `message.list`, no prompt within reach); empty
|
|
1375
|
+
* when the newest prompt is another run's (this turn's never reached the session).
|
|
1376
|
+
*/
|
|
1377
|
+
async messagesSincePrompt() {
|
|
1378
|
+
const messages = this.a.client.message;
|
|
1379
|
+
if (messages === void 0) return void 0;
|
|
1380
|
+
const since = [];
|
|
1381
|
+
let cursor;
|
|
1382
|
+
for (let page = 0; page < RECOVER_PAGES; page += 1) {
|
|
1383
|
+
const listed = await messages.list({
|
|
1384
|
+
sessionID: this.a.sessionId,
|
|
1385
|
+
order: "desc",
|
|
1386
|
+
limit: RECOVER_PAGE_SIZE,
|
|
1387
|
+
...cursor !== void 0 ? {
|
|
1388
|
+
cursor
|
|
1389
|
+
} : {}
|
|
1390
|
+
});
|
|
1391
|
+
for (const message of listed.data) {
|
|
1392
|
+
if (message.type === "user") {
|
|
1393
|
+
const runId = message.metadata?.runId;
|
|
1394
|
+
if (typeof runId === "string" && runId !== this.a.runId) return [];
|
|
1395
|
+
return since.reverse();
|
|
1396
|
+
}
|
|
1397
|
+
since.push(message);
|
|
1398
|
+
}
|
|
1399
|
+
const next = listed.cursor?.next;
|
|
1400
|
+
if (typeof next !== "string" || next.length === 0 || listed.data.length === 0) break;
|
|
1401
|
+
cursor = next;
|
|
1402
|
+
}
|
|
1403
|
+
return void 0;
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* A turn rebuilt after a restart heard only what the session said once it re-attached: what it
|
|
1407
|
+
* said in between — read back from the session's messages since the prompt, less what an earlier
|
|
1408
|
+
* process already took ({@link TurnProgress}) and what this one heard — is taken now, as its
|
|
1409
|
+
* events would have been: text, reasoning, tool calls and results, each step's usage. A session
|
|
1410
|
+
* that left nothing for the turn fails it ({@link LOST_ANSWER_ERROR}) rather than reading as an
|
|
1411
|
+
* empty answer.
|
|
1412
|
+
*/
|
|
1413
|
+
async recover(outcome) {
|
|
1414
|
+
const messages = await this.messagesSincePrompt().catch((error) => {
|
|
1415
|
+
this.a.logger.warn(`run ${this.a.runId}: ${errorText(error, "could not read the session messages")}`);
|
|
1416
|
+
return void 0;
|
|
1417
|
+
});
|
|
1418
|
+
const before = this.a.progress;
|
|
1419
|
+
const text = [];
|
|
1420
|
+
let reasoning = "";
|
|
1421
|
+
let lastError;
|
|
1422
|
+
for (const message of messages ?? []) {
|
|
1423
|
+
if (message.type !== "assistant") continue;
|
|
1424
|
+
const id = message.id;
|
|
1425
|
+
const parts = message.content ?? [];
|
|
1426
|
+
text.push(...missed(parts, "text", before?.text[id] ?? 0, this.took.text.get(id) ?? 0));
|
|
1427
|
+
reasoning += missed(parts, "reasoning", before?.reasoning[id] ?? 0, this.took.reasoning.get(id) ?? 0).map((piece) => piece.text).join("");
|
|
1428
|
+
for (const part of parts) if (part.type === "tool") await this.missedTool(part);
|
|
1429
|
+
if (message.tokens !== void 0 && !before?.steps.includes(id) && !this.took.steps.has(id)) {
|
|
1430
|
+
this.took.steps.add(id);
|
|
1431
|
+
const model = message.model;
|
|
1432
|
+
if (typeof model?.id === "string" && typeof model.providerID === "string") this.model = {
|
|
1433
|
+
providerID: model.providerID,
|
|
1434
|
+
id: model.id
|
|
1435
|
+
};
|
|
1436
|
+
await this.spend({
|
|
1437
|
+
tokens: message.tokens,
|
|
1438
|
+
cost: message.cost
|
|
1439
|
+
}, "chat");
|
|
1440
|
+
}
|
|
1441
|
+
if (message.error?.message) lastError = message.error.message;
|
|
1442
|
+
}
|
|
1443
|
+
const recovered = text.map((piece) => piece.text).join("\n\n").trimStart();
|
|
1444
|
+
if (recovered.trim()) {
|
|
1445
|
+
await this.step();
|
|
1446
|
+
const joint = this.segment.text && !text.at(-1)?.continues ? "\n\n" : "";
|
|
1447
|
+
this.segment.text = `${recovered}${joint}${this.segment.text}`;
|
|
1448
|
+
this.sawText = true;
|
|
1449
|
+
await this.write({
|
|
1450
|
+
kind: "text",
|
|
1451
|
+
text: recovered
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
if (reasoning) {
|
|
1455
|
+
await this.step();
|
|
1456
|
+
this.segment.reasoning = `${reasoning}${this.segment.reasoning}`;
|
|
1457
|
+
await this.write({
|
|
1458
|
+
kind: "reasoning",
|
|
1459
|
+
text: reasoning
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
if (outcome.status !== "succeeded") return outcome;
|
|
1463
|
+
const idle = (messages ?? []).filter((m) => m.type === "idle").at(-1);
|
|
1464
|
+
if (idle?.outcome === "failed") return {
|
|
1465
|
+
status: "failed",
|
|
1466
|
+
error: lastError ?? this.stepError ?? "the execution failed"
|
|
1467
|
+
};
|
|
1468
|
+
if (idle?.outcome === "interrupted") return {
|
|
1469
|
+
status: "interrupted"
|
|
1470
|
+
};
|
|
1471
|
+
const s = this.segment;
|
|
1472
|
+
const said = s.text || s.reasoning || s.calls.length > 0 || s.ui.length > 0;
|
|
1473
|
+
const progress = this.progress();
|
|
1474
|
+
const tookAny = Object.keys(progress.text).length > 0 || progress.called.length > 0 || progress.steps.length > 0;
|
|
1475
|
+
if (!said && !this.wroteMessage && !tookAny) return {
|
|
1476
|
+
status: "failed",
|
|
1477
|
+
error: LOST_ANSWER_ERROR
|
|
1478
|
+
};
|
|
1479
|
+
return outcome;
|
|
1480
|
+
}
|
|
1481
|
+
/** A tool part of a message the turn did not hear: its call, its result, whichever it lacks. */
|
|
1482
|
+
async missedTool(part) {
|
|
1483
|
+
const id = part.id;
|
|
1484
|
+
const name = part.name ?? "tool";
|
|
1485
|
+
if (id === void 0 || HIDDEN_TOOLS.has(name)) return;
|
|
1486
|
+
const state = part.state ?? {};
|
|
1487
|
+
const before = this.a.progress;
|
|
1488
|
+
if (!before?.called.includes(id) && !this.tools.has(id)) {
|
|
1489
|
+
await this.step();
|
|
1490
|
+
this.setInput(id, state.input, name);
|
|
1491
|
+
await this.makeAvailable(id);
|
|
1492
|
+
}
|
|
1493
|
+
const ok = state.status === "completed";
|
|
1494
|
+
if (!ok && state.status !== "error" || before?.settled.includes(id)) return;
|
|
1495
|
+
const error = errorText(state.error, "tool failed");
|
|
1496
|
+
if (this.tools.has(id)) {
|
|
1497
|
+
await this.settleTool(id, ok, error);
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
this.took.settled.add(id);
|
|
1501
|
+
const result = ok ? {
|
|
1502
|
+
id,
|
|
1503
|
+
name,
|
|
1504
|
+
output: {
|
|
1505
|
+
ok: true
|
|
1506
|
+
}
|
|
1507
|
+
} : {
|
|
1508
|
+
id,
|
|
1509
|
+
name,
|
|
1510
|
+
output: {
|
|
1511
|
+
ok: false
|
|
1512
|
+
},
|
|
1513
|
+
error
|
|
1514
|
+
};
|
|
1515
|
+
const messageId = await this.messageOf(id);
|
|
1516
|
+
if (messageId !== void 0) await this.addResult(messageId, result);
|
|
1517
|
+
else this.segment.results.push(result);
|
|
1518
|
+
await this.write(ok ? {
|
|
1519
|
+
kind: "tool-output",
|
|
1520
|
+
id,
|
|
1521
|
+
output: {
|
|
1522
|
+
ok: true
|
|
1523
|
+
}
|
|
1524
|
+
} : {
|
|
1525
|
+
kind: "tool-output-error",
|
|
1526
|
+
id,
|
|
1527
|
+
error
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
async end(ended) {
|
|
1324
1531
|
if (this.ended) return;
|
|
1325
1532
|
this.ended = true;
|
|
1533
|
+
const outcome = this.a.resumed === true ? await this.recover(ended).catch((error) => {
|
|
1534
|
+
this.a.logger.warn(`run ${this.a.runId}: ${errorText(error, "could not recover the turn")}`);
|
|
1535
|
+
return ended;
|
|
1536
|
+
}) : ended;
|
|
1326
1537
|
await this.unreported().catch((error) => this.a.logger.warn(`run ${this.a.runId}: ${errorText(error, "could not read the session usage")}`));
|
|
1327
1538
|
if (outcome.status !== "failed" || this.segment.text || this.segment.calls.length > 0 || this.segment.ui.length > 0) {
|
|
1328
1539
|
await this.flush(true);
|
|
@@ -1339,6 +1550,26 @@ ${delta}` : delta;
|
|
|
1339
1550
|
});
|
|
1340
1551
|
}
|
|
1341
1552
|
};
|
|
1553
|
+
function missed(parts, type, head, tail) {
|
|
1554
|
+
const texts = parts.flatMap((p) => p.type === type && typeof p.text === "string" ? [
|
|
1555
|
+
p.text
|
|
1556
|
+
] : []);
|
|
1557
|
+
const total = texts.reduce((n, t) => n + t.length, 0);
|
|
1558
|
+
const end = total - tail;
|
|
1559
|
+
const out = [];
|
|
1560
|
+
let at = 0;
|
|
1561
|
+
for (const t of texts) {
|
|
1562
|
+
const from = Math.max(head, at);
|
|
1563
|
+
const to = Math.min(end, at + t.length);
|
|
1564
|
+
if (to > from) out.push({
|
|
1565
|
+
text: t.slice(from - at, to - at),
|
|
1566
|
+
continues: to < at + t.length
|
|
1567
|
+
});
|
|
1568
|
+
at += t.length;
|
|
1569
|
+
}
|
|
1570
|
+
return out;
|
|
1571
|
+
}
|
|
1572
|
+
__name(missed, "missed");
|
|
1342
1573
|
function modelOfLabel(label) {
|
|
1343
1574
|
const slash = label?.indexOf("/") ?? -1;
|
|
1344
1575
|
if (label === void 0 || slash <= 0 || slash === label.length - 1) return void 0;
|
|
@@ -1651,7 +1882,7 @@ import { Inject as Inject3, Injectable as Injectable2 } from "@nestjs/common";
|
|
|
1651
1882
|
// src/turns.ts
|
|
1652
1883
|
import { randomUUID } from "crypto";
|
|
1653
1884
|
import { AGENT_CHAT_QUEUE } from "@dudousxd/nestjs-agent";
|
|
1654
|
-
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";
|
|
1885
|
+
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, agentRunContext, buildMemoryBlock, defaultScopeResolver, encodeStreamEvent as encodeStreamEvent2, memoryWriteVerdict, parseBedrockModelId, publishAgentRunCancelled, publishAgentRunFailed, releaseThreadRun, resolveMemoryDigest, resolveSkillCatalog, resolveUsageCost, streamFailure } from "@dudousxd/nestjs-agent-core";
|
|
1655
1886
|
import { Inject as Inject2, Injectable, Logger as Logger2, Optional } from "@nestjs/common";
|
|
1656
1887
|
|
|
1657
1888
|
// src/event-hub.ts
|
|
@@ -2484,7 +2715,11 @@ ${body}
|
|
|
2484
2715
|
text: prompt.text,
|
|
2485
2716
|
...prompt.files?.length ? {
|
|
2486
2717
|
files: prompt.files
|
|
2487
|
-
} : {}
|
|
2718
|
+
} : {},
|
|
2719
|
+
// Marks the prompt as this run's: a turn resumed after a restart reads what came after it.
|
|
2720
|
+
metadata: {
|
|
2721
|
+
runId
|
|
2722
|
+
}
|
|
2488
2723
|
});
|
|
2489
2724
|
} catch (error) {
|
|
2490
2725
|
live.turn.fail(`OpenCode refused the message: ${error.message}`);
|
|
@@ -2497,9 +2732,11 @@ ${body}
|
|
|
2497
2732
|
*
|
|
2498
2733
|
* `spent` is what the run spent before (the sum of the `usage` of its earlier milestones): a turn
|
|
2499
2734
|
* rebuilt here starts from it, so the answer it persists carries the whole run's usage.
|
|
2735
|
+
* `progress` is what the turn took before (its last `ask` milestone's): a turn rebuilt here reads
|
|
2736
|
+
* back from the session's messages, when the execution ends, what nobody heard after that.
|
|
2500
2737
|
*/
|
|
2501
|
-
async observe(runId, input, handle, spent) {
|
|
2502
|
-
const live = await this.ensureLive(runId, input, handle, true, spent);
|
|
2738
|
+
async observe(runId, input, handle, spent, progress) {
|
|
2739
|
+
const live = await this.ensureLive(runId, input, handle, true, spent, progress);
|
|
2503
2740
|
const { turn, client } = live;
|
|
2504
2741
|
if (turn.hasMilestone()) return this.reached(runId, input, handle, await turn.next());
|
|
2505
2742
|
let done = false;
|
|
@@ -2538,12 +2775,12 @@ ${body}
|
|
|
2538
2775
|
* request is gone with it: a new session is opened, told what the person decided, and prompted
|
|
2539
2776
|
* to go on.
|
|
2540
2777
|
*/
|
|
2541
|
-
async reply(runId, input, handle, ask, reply, spent) {
|
|
2778
|
+
async reply(runId, input, handle, ask, reply, spent, progress) {
|
|
2542
2779
|
const server = await this.host.server(input.actor);
|
|
2543
2780
|
if (server.key !== handle.serverKey || server.bootId !== handle.bootId) {
|
|
2544
2781
|
return this.continueAfterRestart(runId, input, server, ask, reply, spent);
|
|
2545
2782
|
}
|
|
2546
|
-
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2783
|
+
const live = await this.ensureLive(runId, input, handle, false, spent, progress);
|
|
2547
2784
|
await live.turn.decide(ask, reply);
|
|
2548
2785
|
return handle;
|
|
2549
2786
|
}
|
|
@@ -2561,7 +2798,10 @@ ${body}
|
|
|
2561
2798
|
live.turn.setBaseline(await this.sessionUsage(live.client, handle.sessionId));
|
|
2562
2799
|
await live.client.session.prompt({
|
|
2563
2800
|
sessionID: handle.sessionId,
|
|
2564
|
-
text: note
|
|
2801
|
+
text: note,
|
|
2802
|
+
metadata: {
|
|
2803
|
+
runId
|
|
2804
|
+
}
|
|
2565
2805
|
});
|
|
2566
2806
|
return handle;
|
|
2567
2807
|
}
|
|
@@ -2585,9 +2825,10 @@ ${body}
|
|
|
2585
2825
|
sessionID: known.sessionId
|
|
2586
2826
|
});
|
|
2587
2827
|
}
|
|
2588
|
-
async ensureLive(runId, input, handle, catchUp, spent) {
|
|
2828
|
+
async ensureLive(runId, input, handle, catchUp, spent, progress) {
|
|
2589
2829
|
const current = this.live.get(runId);
|
|
2590
2830
|
if (current !== void 0 && current.handle.sessionId === handle.sessionId) return current;
|
|
2831
|
+
const resumed = catchUp && current === void 0;
|
|
2591
2832
|
current?.stop();
|
|
2592
2833
|
const server = await this.host.server(input.actor);
|
|
2593
2834
|
const deps = this.deps.forAgent(input.agentName);
|
|
@@ -2618,6 +2859,10 @@ ${body}
|
|
|
2618
2859
|
...spent !== void 0 ? {
|
|
2619
2860
|
carried: spent
|
|
2620
2861
|
} : {},
|
|
2862
|
+
...progress !== void 0 ? {
|
|
2863
|
+
progress
|
|
2864
|
+
} : {},
|
|
2865
|
+
resumed,
|
|
2621
2866
|
logger: this.logger,
|
|
2622
2867
|
onGranted: /* @__PURE__ */ __name((action, id) => {
|
|
2623
2868
|
const grants = this.grants.get(runId) ?? [];
|
|
@@ -2637,7 +2882,7 @@ ${body}
|
|
|
2637
2882
|
stop
|
|
2638
2883
|
};
|
|
2639
2884
|
this.live.set(runId, live);
|
|
2640
|
-
if (
|
|
2885
|
+
if (resumed) await turn.catchUp().catch(() => void 0);
|
|
2641
2886
|
return live;
|
|
2642
2887
|
}
|
|
2643
2888
|
/** Stop following a run in this process. */
|
|
@@ -2751,6 +2996,12 @@ ${body}
|
|
|
2751
2996
|
kind: "cancelled"
|
|
2752
2997
|
}));
|
|
2753
2998
|
await writer.end();
|
|
2999
|
+
publishAgentRunCancelled({
|
|
3000
|
+
runId,
|
|
3001
|
+
threadId: input.threadId,
|
|
3002
|
+
durationMs,
|
|
3003
|
+
context: agentRunContext(input)
|
|
3004
|
+
});
|
|
2754
3005
|
await this.store.recordRunEnd?.({
|
|
2755
3006
|
runId,
|
|
2756
3007
|
status: "cancelled",
|
|
@@ -2781,12 +3032,16 @@ ${body}
|
|
|
2781
3032
|
this.logger.error(`agent run ${runId} failed: ${error}`);
|
|
2782
3033
|
publishAgentRunFailed({
|
|
2783
3034
|
runId,
|
|
3035
|
+
threadId: input.threadId,
|
|
2784
3036
|
code: "opencode_failed",
|
|
2785
|
-
message: error
|
|
3037
|
+
message: error,
|
|
3038
|
+
durationMs,
|
|
3039
|
+
context: agentRunContext(input)
|
|
2786
3040
|
});
|
|
2787
3041
|
await this.store.recordRunEnd?.({
|
|
2788
3042
|
runId,
|
|
2789
3043
|
status: "failed",
|
|
3044
|
+
durationMs,
|
|
2790
3045
|
errorCode: "opencode_failed",
|
|
2791
3046
|
errorMessage: error
|
|
2792
3047
|
});
|
|
@@ -3179,6 +3434,7 @@ __name(openCodeProviders, "openCodeProviders");
|
|
|
3179
3434
|
export {
|
|
3180
3435
|
FormAnswerError,
|
|
3181
3436
|
InMemoryOpenCodeSessionStore,
|
|
3437
|
+
LOST_ANSWER_ERROR,
|
|
3182
3438
|
OPENCODE_HOST,
|
|
3183
3439
|
OPENCODE_MCP_ENDPOINT,
|
|
3184
3440
|
OPENCODE_OPTIONS,
|