@dudousxd/nestjs-agent-opencode 0.4.0 → 0.4.1
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 +261 -12
- 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 +261 -12
- 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 +257 -10
- 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 +256 -10
- 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-BX6MLzxs.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';
|
|
@@ -53,7 +53,8 @@ declare function decisionToken(runId: string, toolCallId: string): string;
|
|
|
53
53
|
* the steps from their checkpoints and replying to OpenCode from there (`OpenCodeTurns` rebuilds the
|
|
54
54
|
* live turn, and re-prompts a fresh session when OpenCode itself restarted meanwhile). A process
|
|
55
55
|
* that dies while OpenCode works re-runs that `observe` step, which catches up on what OpenCode
|
|
56
|
-
* asked while nobody listened
|
|
56
|
+
* asked while nobody listened, and — when the execution ends — on what it said: the text, tool
|
|
57
|
+
* calls and usage it streamed meanwhile, read back from the session's messages.
|
|
57
58
|
*/
|
|
58
59
|
declare class OpenCodeRunWorkflow {
|
|
59
60
|
private readonly turns;
|
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-BX6MLzxs.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';
|
|
@@ -53,7 +53,8 @@ declare function decisionToken(runId: string, toolCallId: string): string;
|
|
|
53
53
|
* the steps from their checkpoints and replying to OpenCode from there (`OpenCodeTurns` rebuilds the
|
|
54
54
|
* live turn, and re-prompts a fresh session when OpenCode itself restarted meanwhile). A process
|
|
55
55
|
* that dies while OpenCode works re-runs that `observe` step, which catches up on what OpenCode
|
|
56
|
-
* asked while nobody listened
|
|
56
|
+
* asked while nobody listened, and — when the execution ends — on what it said: the text, tool
|
|
57
|
+
* calls and usage it streamed meanwhile, read back from the session's messages.
|
|
57
58
|
*/
|
|
58
59
|
declare class OpenCodeRunWorkflow {
|
|
59
60
|
private readonly turns;
|
package/dist/durable/index.js
CHANGED
|
@@ -257,6 +257,9 @@ function subUsage(a, b) {
|
|
|
257
257
|
};
|
|
258
258
|
}
|
|
259
259
|
__name(subUsage, "subUsage");
|
|
260
|
+
var LOST_ANSWER_ERROR = "The answer was lost while the agent restarted; ask again.";
|
|
261
|
+
var RECOVER_PAGES = 10;
|
|
262
|
+
var RECOVER_PAGE_SIZE = 100;
|
|
260
263
|
var ASK_TOOL_NAME = "ask";
|
|
261
264
|
var FAILED_STATUSES = /* @__PURE__ */ new Set([
|
|
262
265
|
"error",
|
|
@@ -345,6 +348,14 @@ var OpenCodeTurn = class {
|
|
|
345
348
|
wroteMessage = false;
|
|
346
349
|
ended = false;
|
|
347
350
|
stepError;
|
|
351
|
+
/** What this turn object took from the session's assistant messages (see {@link TurnProgress}). */
|
|
352
|
+
took = {
|
|
353
|
+
text: /* @__PURE__ */ new Map(),
|
|
354
|
+
reasoning: /* @__PURE__ */ new Map(),
|
|
355
|
+
called: /* @__PURE__ */ new Set(),
|
|
356
|
+
settled: /* @__PURE__ */ new Set(),
|
|
357
|
+
steps: /* @__PURE__ */ new Set()
|
|
358
|
+
};
|
|
348
359
|
constructor(a) {
|
|
349
360
|
this.a = a;
|
|
350
361
|
this.model = modelOfLabel(a.input.model);
|
|
@@ -362,6 +373,30 @@ var OpenCodeTurn = class {
|
|
|
362
373
|
tokens: info.tokens
|
|
363
374
|
};
|
|
364
375
|
}
|
|
376
|
+
/** What the turn took so far: carried from before this turn object, plus what it took. */
|
|
377
|
+
progress() {
|
|
378
|
+
const before = this.a.progress;
|
|
379
|
+
const merged = /* @__PURE__ */ __name((carried, own) => {
|
|
380
|
+
const out = {
|
|
381
|
+
...carried ?? {}
|
|
382
|
+
};
|
|
383
|
+
for (const [id, n] of own) out[id] = (out[id] ?? 0) + n;
|
|
384
|
+
return out;
|
|
385
|
+
}, "merged");
|
|
386
|
+
const union = /* @__PURE__ */ __name((carried, own) => [
|
|
387
|
+
.../* @__PURE__ */ new Set([
|
|
388
|
+
...carried ?? [],
|
|
389
|
+
...own
|
|
390
|
+
])
|
|
391
|
+
], "union");
|
|
392
|
+
return {
|
|
393
|
+
text: merged(before?.text, this.took.text),
|
|
394
|
+
reasoning: merged(before?.reasoning, this.took.reasoning),
|
|
395
|
+
called: union(before?.called, this.took.called),
|
|
396
|
+
settled: union(before?.settled, this.took.settled),
|
|
397
|
+
steps: union(before?.steps, this.took.steps)
|
|
398
|
+
};
|
|
399
|
+
}
|
|
365
400
|
/** What the run spent so far: carried from before this turn object, plus what it saw. */
|
|
366
401
|
totalUsage() {
|
|
367
402
|
return addUsage(this.a.carried, this.spent);
|
|
@@ -452,7 +487,11 @@ var OpenCodeTurn = class {
|
|
|
452
487
|
this.reported = {
|
|
453
488
|
...this.spent
|
|
454
489
|
};
|
|
455
|
-
const milestone = {
|
|
490
|
+
const milestone = reached.kind === "ask" ? {
|
|
491
|
+
...reached,
|
|
492
|
+
usage,
|
|
493
|
+
progress: this.progress()
|
|
494
|
+
} : {
|
|
456
495
|
...reached,
|
|
457
496
|
usage
|
|
458
497
|
};
|
|
@@ -507,6 +546,7 @@ var OpenCodeTurn = class {
|
|
|
507
546
|
innerSettled: /* @__PURE__ */ new Set()
|
|
508
547
|
};
|
|
509
548
|
this.tools.set(id, state);
|
|
549
|
+
this.took.called.add(id);
|
|
510
550
|
this.segment.calls.push({
|
|
511
551
|
id,
|
|
512
552
|
name,
|
|
@@ -634,6 +674,7 @@ var OpenCodeTurn = class {
|
|
|
634
674
|
case "session.text.delta": {
|
|
635
675
|
const delta = typeof d.delta === "string" ? d.delta : "";
|
|
636
676
|
if (!delta) return;
|
|
677
|
+
this.count(this.took.text, d.assistantMessageID, delta.length);
|
|
637
678
|
this.endReasoning();
|
|
638
679
|
if (!this.sawText && !delta.trim()) return;
|
|
639
680
|
await this.step();
|
|
@@ -655,6 +696,7 @@ ${delta}` : delta;
|
|
|
655
696
|
case "session.reasoning.delta": {
|
|
656
697
|
const delta = typeof d.delta === "string" ? d.delta : "";
|
|
657
698
|
if (!delta) return;
|
|
699
|
+
this.count(this.took.reasoning, d.assistantMessageID, delta.length);
|
|
658
700
|
this.reasoningSince ??= Date.now();
|
|
659
701
|
await this.step();
|
|
660
702
|
this.segment.reasoning += delta;
|
|
@@ -709,6 +751,7 @@ ${delta}` : delta;
|
|
|
709
751
|
}
|
|
710
752
|
case "session.step.ended":
|
|
711
753
|
this.endReasoning();
|
|
754
|
+
if (typeof d.assistantMessageID === "string") this.took.steps.add(d.assistantMessageID);
|
|
712
755
|
await this.stepEnded(d);
|
|
713
756
|
return;
|
|
714
757
|
case "session.step.failed":
|
|
@@ -749,10 +792,16 @@ ${delta}` : delta;
|
|
|
749
792
|
return;
|
|
750
793
|
}
|
|
751
794
|
}
|
|
795
|
+
/** Characters taken from an assistant message's text or reasoning. */
|
|
796
|
+
count(into, messageId, n) {
|
|
797
|
+
if (typeof messageId !== "string") return;
|
|
798
|
+
into.set(messageId, (into.get(messageId) ?? 0) + n);
|
|
799
|
+
}
|
|
752
800
|
async settleTool(id, ok, error = "failed") {
|
|
753
801
|
const state = this.tool(id);
|
|
754
802
|
if (state.settled) return;
|
|
755
803
|
state.settled = true;
|
|
804
|
+
this.took.settled.add(id);
|
|
756
805
|
if (ok) {
|
|
757
806
|
this.segment.results.push({
|
|
758
807
|
id,
|
|
@@ -1302,9 +1351,171 @@ ${delta}` : delta;
|
|
|
1302
1351
|
cost: cost < 1e-9 ? 0 : cost
|
|
1303
1352
|
}, this.compacted ? "history_summary" : "title");
|
|
1304
1353
|
}
|
|
1305
|
-
|
|
1354
|
+
/**
|
|
1355
|
+
* The session's messages since this turn's prompt, oldest first: everything after its newest user
|
|
1356
|
+
* message. `undefined` when they cannot be read (no `message.list`, no prompt within reach); empty
|
|
1357
|
+
* when the newest prompt is another run's (this turn's never reached the session).
|
|
1358
|
+
*/
|
|
1359
|
+
async messagesSincePrompt() {
|
|
1360
|
+
const messages = this.a.client.message;
|
|
1361
|
+
if (messages === void 0) return void 0;
|
|
1362
|
+
const since = [];
|
|
1363
|
+
let cursor;
|
|
1364
|
+
for (let page = 0; page < RECOVER_PAGES; page += 1) {
|
|
1365
|
+
const listed = await messages.list({
|
|
1366
|
+
sessionID: this.a.sessionId,
|
|
1367
|
+
order: "desc",
|
|
1368
|
+
limit: RECOVER_PAGE_SIZE,
|
|
1369
|
+
...cursor !== void 0 ? {
|
|
1370
|
+
cursor
|
|
1371
|
+
} : {}
|
|
1372
|
+
});
|
|
1373
|
+
for (const message of listed.data) {
|
|
1374
|
+
if (message.type === "user") {
|
|
1375
|
+
const runId = message.metadata?.runId;
|
|
1376
|
+
if (typeof runId === "string" && runId !== this.a.runId) return [];
|
|
1377
|
+
return since.reverse();
|
|
1378
|
+
}
|
|
1379
|
+
since.push(message);
|
|
1380
|
+
}
|
|
1381
|
+
const next = listed.cursor?.next;
|
|
1382
|
+
if (typeof next !== "string" || next.length === 0 || listed.data.length === 0) break;
|
|
1383
|
+
cursor = next;
|
|
1384
|
+
}
|
|
1385
|
+
return void 0;
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* A turn rebuilt after a restart heard only what the session said once it re-attached: what it
|
|
1389
|
+
* said in between — read back from the session's messages since the prompt, less what an earlier
|
|
1390
|
+
* process already took ({@link TurnProgress}) and what this one heard — is taken now, as its
|
|
1391
|
+
* events would have been: text, reasoning, tool calls and results, each step's usage. A session
|
|
1392
|
+
* that left nothing for the turn fails it ({@link LOST_ANSWER_ERROR}) rather than reading as an
|
|
1393
|
+
* empty answer.
|
|
1394
|
+
*/
|
|
1395
|
+
async recover(outcome) {
|
|
1396
|
+
const messages = await this.messagesSincePrompt().catch((error) => {
|
|
1397
|
+
this.a.logger.warn(`run ${this.a.runId}: ${errorText(error, "could not read the session messages")}`);
|
|
1398
|
+
return void 0;
|
|
1399
|
+
});
|
|
1400
|
+
const before = this.a.progress;
|
|
1401
|
+
const text = [];
|
|
1402
|
+
let reasoning = "";
|
|
1403
|
+
let lastError;
|
|
1404
|
+
for (const message of messages ?? []) {
|
|
1405
|
+
if (message.type !== "assistant") continue;
|
|
1406
|
+
const id = message.id;
|
|
1407
|
+
const parts = message.content ?? [];
|
|
1408
|
+
text.push(...missed(parts, "text", before?.text[id] ?? 0, this.took.text.get(id) ?? 0));
|
|
1409
|
+
reasoning += missed(parts, "reasoning", before?.reasoning[id] ?? 0, this.took.reasoning.get(id) ?? 0).map((piece) => piece.text).join("");
|
|
1410
|
+
for (const part of parts) if (part.type === "tool") await this.missedTool(part);
|
|
1411
|
+
if (message.tokens !== void 0 && !before?.steps.includes(id) && !this.took.steps.has(id)) {
|
|
1412
|
+
this.took.steps.add(id);
|
|
1413
|
+
const model = message.model;
|
|
1414
|
+
if (typeof model?.id === "string" && typeof model.providerID === "string") this.model = {
|
|
1415
|
+
providerID: model.providerID,
|
|
1416
|
+
id: model.id
|
|
1417
|
+
};
|
|
1418
|
+
await this.spend({
|
|
1419
|
+
tokens: message.tokens,
|
|
1420
|
+
cost: message.cost
|
|
1421
|
+
}, "chat");
|
|
1422
|
+
}
|
|
1423
|
+
if (message.error?.message) lastError = message.error.message;
|
|
1424
|
+
}
|
|
1425
|
+
const recovered = text.map((piece) => piece.text).join("\n\n").trimStart();
|
|
1426
|
+
if (recovered.trim()) {
|
|
1427
|
+
await this.step();
|
|
1428
|
+
const joint = this.segment.text && !text.at(-1)?.continues ? "\n\n" : "";
|
|
1429
|
+
this.segment.text = `${recovered}${joint}${this.segment.text}`;
|
|
1430
|
+
this.sawText = true;
|
|
1431
|
+
await this.write({
|
|
1432
|
+
kind: "text",
|
|
1433
|
+
text: recovered
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
if (reasoning) {
|
|
1437
|
+
await this.step();
|
|
1438
|
+
this.segment.reasoning = `${reasoning}${this.segment.reasoning}`;
|
|
1439
|
+
await this.write({
|
|
1440
|
+
kind: "reasoning",
|
|
1441
|
+
text: reasoning
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
if (outcome.status !== "succeeded") return outcome;
|
|
1445
|
+
const idle = (messages ?? []).filter((m) => m.type === "idle").at(-1);
|
|
1446
|
+
if (idle?.outcome === "failed") return {
|
|
1447
|
+
status: "failed",
|
|
1448
|
+
error: lastError ?? this.stepError ?? "the execution failed"
|
|
1449
|
+
};
|
|
1450
|
+
if (idle?.outcome === "interrupted") return {
|
|
1451
|
+
status: "interrupted"
|
|
1452
|
+
};
|
|
1453
|
+
const s = this.segment;
|
|
1454
|
+
const said = s.text || s.reasoning || s.calls.length > 0 || s.ui.length > 0;
|
|
1455
|
+
const progress = this.progress();
|
|
1456
|
+
const tookAny = Object.keys(progress.text).length > 0 || progress.called.length > 0 || progress.steps.length > 0;
|
|
1457
|
+
if (!said && !this.wroteMessage && !tookAny) return {
|
|
1458
|
+
status: "failed",
|
|
1459
|
+
error: LOST_ANSWER_ERROR
|
|
1460
|
+
};
|
|
1461
|
+
return outcome;
|
|
1462
|
+
}
|
|
1463
|
+
/** A tool part of a message the turn did not hear: its call, its result, whichever it lacks. */
|
|
1464
|
+
async missedTool(part) {
|
|
1465
|
+
const id = part.id;
|
|
1466
|
+
const name = part.name ?? "tool";
|
|
1467
|
+
if (id === void 0 || HIDDEN_TOOLS.has(name)) return;
|
|
1468
|
+
const state = part.state ?? {};
|
|
1469
|
+
const before = this.a.progress;
|
|
1470
|
+
if (!before?.called.includes(id) && !this.tools.has(id)) {
|
|
1471
|
+
await this.step();
|
|
1472
|
+
this.setInput(id, state.input, name);
|
|
1473
|
+
await this.makeAvailable(id);
|
|
1474
|
+
}
|
|
1475
|
+
const ok = state.status === "completed";
|
|
1476
|
+
if (!ok && state.status !== "error" || before?.settled.includes(id)) return;
|
|
1477
|
+
const error = errorText(state.error, "tool failed");
|
|
1478
|
+
if (this.tools.has(id)) {
|
|
1479
|
+
await this.settleTool(id, ok, error);
|
|
1480
|
+
return;
|
|
1481
|
+
}
|
|
1482
|
+
this.took.settled.add(id);
|
|
1483
|
+
const result = ok ? {
|
|
1484
|
+
id,
|
|
1485
|
+
name,
|
|
1486
|
+
output: {
|
|
1487
|
+
ok: true
|
|
1488
|
+
}
|
|
1489
|
+
} : {
|
|
1490
|
+
id,
|
|
1491
|
+
name,
|
|
1492
|
+
output: {
|
|
1493
|
+
ok: false
|
|
1494
|
+
},
|
|
1495
|
+
error
|
|
1496
|
+
};
|
|
1497
|
+
const messageId = await this.messageOf(id);
|
|
1498
|
+
if (messageId !== void 0) await this.addResult(messageId, result);
|
|
1499
|
+
else this.segment.results.push(result);
|
|
1500
|
+
await this.write(ok ? {
|
|
1501
|
+
kind: "tool-output",
|
|
1502
|
+
id,
|
|
1503
|
+
output: {
|
|
1504
|
+
ok: true
|
|
1505
|
+
}
|
|
1506
|
+
} : {
|
|
1507
|
+
kind: "tool-output-error",
|
|
1508
|
+
id,
|
|
1509
|
+
error
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1512
|
+
async end(ended) {
|
|
1306
1513
|
if (this.ended) return;
|
|
1307
1514
|
this.ended = true;
|
|
1515
|
+
const outcome = this.a.resumed === true ? await this.recover(ended).catch((error) => {
|
|
1516
|
+
this.a.logger.warn(`run ${this.a.runId}: ${errorText(error, "could not recover the turn")}`);
|
|
1517
|
+
return ended;
|
|
1518
|
+
}) : ended;
|
|
1308
1519
|
await this.unreported().catch((error) => this.a.logger.warn(`run ${this.a.runId}: ${errorText(error, "could not read the session usage")}`));
|
|
1309
1520
|
if (outcome.status !== "failed" || this.segment.text || this.segment.calls.length > 0 || this.segment.ui.length > 0) {
|
|
1310
1521
|
await this.flush(true);
|
|
@@ -1321,6 +1532,26 @@ ${delta}` : delta;
|
|
|
1321
1532
|
});
|
|
1322
1533
|
}
|
|
1323
1534
|
};
|
|
1535
|
+
function missed(parts, type, head, tail) {
|
|
1536
|
+
const texts = parts.flatMap((p) => p.type === type && typeof p.text === "string" ? [
|
|
1537
|
+
p.text
|
|
1538
|
+
] : []);
|
|
1539
|
+
const total = texts.reduce((n, t) => n + t.length, 0);
|
|
1540
|
+
const end = total - tail;
|
|
1541
|
+
const out = [];
|
|
1542
|
+
let at = 0;
|
|
1543
|
+
for (const t of texts) {
|
|
1544
|
+
const from = Math.max(head, at);
|
|
1545
|
+
const to = Math.min(end, at + t.length);
|
|
1546
|
+
if (to > from) out.push({
|
|
1547
|
+
text: t.slice(from - at, to - at),
|
|
1548
|
+
continues: to < at + t.length
|
|
1549
|
+
});
|
|
1550
|
+
at += t.length;
|
|
1551
|
+
}
|
|
1552
|
+
return out;
|
|
1553
|
+
}
|
|
1554
|
+
__name(missed, "missed");
|
|
1324
1555
|
function modelOfLabel(label) {
|
|
1325
1556
|
const slash = label?.indexOf("/") ?? -1;
|
|
1326
1557
|
if (label === void 0 || slash <= 0 || slash === label.length - 1) return void 0;
|
|
@@ -2466,7 +2697,11 @@ ${body}
|
|
|
2466
2697
|
text: prompt.text,
|
|
2467
2698
|
...prompt.files?.length ? {
|
|
2468
2699
|
files: prompt.files
|
|
2469
|
-
} : {}
|
|
2700
|
+
} : {},
|
|
2701
|
+
// Marks the prompt as this run's: a turn resumed after a restart reads what came after it.
|
|
2702
|
+
metadata: {
|
|
2703
|
+
runId
|
|
2704
|
+
}
|
|
2470
2705
|
});
|
|
2471
2706
|
} catch (error) {
|
|
2472
2707
|
live.turn.fail(`OpenCode refused the message: ${error.message}`);
|
|
@@ -2479,9 +2714,11 @@ ${body}
|
|
|
2479
2714
|
*
|
|
2480
2715
|
* `spent` is what the run spent before (the sum of the `usage` of its earlier milestones): a turn
|
|
2481
2716
|
* rebuilt here starts from it, so the answer it persists carries the whole run's usage.
|
|
2717
|
+
* `progress` is what the turn took before (its last `ask` milestone's): a turn rebuilt here reads
|
|
2718
|
+
* back from the session's messages, when the execution ends, what nobody heard after that.
|
|
2482
2719
|
*/
|
|
2483
|
-
async observe(runId, input, handle, spent) {
|
|
2484
|
-
const live = await this.ensureLive(runId, input, handle, true, spent);
|
|
2720
|
+
async observe(runId, input, handle, spent, progress) {
|
|
2721
|
+
const live = await this.ensureLive(runId, input, handle, true, spent, progress);
|
|
2485
2722
|
const { turn, client } = live;
|
|
2486
2723
|
if (turn.hasMilestone()) return this.reached(runId, input, handle, await turn.next());
|
|
2487
2724
|
let done = false;
|
|
@@ -2520,12 +2757,12 @@ ${body}
|
|
|
2520
2757
|
* request is gone with it: a new session is opened, told what the person decided, and prompted
|
|
2521
2758
|
* to go on.
|
|
2522
2759
|
*/
|
|
2523
|
-
async reply(runId, input, handle, ask, reply, spent) {
|
|
2760
|
+
async reply(runId, input, handle, ask, reply, spent, progress) {
|
|
2524
2761
|
const server = await this.host.server(input.actor);
|
|
2525
2762
|
if (server.key !== handle.serverKey || server.bootId !== handle.bootId) {
|
|
2526
2763
|
return this.continueAfterRestart(runId, input, server, ask, reply, spent);
|
|
2527
2764
|
}
|
|
2528
|
-
const live = await this.ensureLive(runId, input, handle, false, spent);
|
|
2765
|
+
const live = await this.ensureLive(runId, input, handle, false, spent, progress);
|
|
2529
2766
|
await live.turn.decide(ask, reply);
|
|
2530
2767
|
return handle;
|
|
2531
2768
|
}
|
|
@@ -2543,7 +2780,10 @@ ${body}
|
|
|
2543
2780
|
live.turn.setBaseline(await this.sessionUsage(live.client, handle.sessionId));
|
|
2544
2781
|
await live.client.session.prompt({
|
|
2545
2782
|
sessionID: handle.sessionId,
|
|
2546
|
-
text: note
|
|
2783
|
+
text: note,
|
|
2784
|
+
metadata: {
|
|
2785
|
+
runId
|
|
2786
|
+
}
|
|
2547
2787
|
});
|
|
2548
2788
|
return handle;
|
|
2549
2789
|
}
|
|
@@ -2567,9 +2807,10 @@ ${body}
|
|
|
2567
2807
|
sessionID: known.sessionId
|
|
2568
2808
|
});
|
|
2569
2809
|
}
|
|
2570
|
-
async ensureLive(runId, input, handle, catchUp, spent) {
|
|
2810
|
+
async ensureLive(runId, input, handle, catchUp, spent, progress) {
|
|
2571
2811
|
const current = this.live.get(runId);
|
|
2572
2812
|
if (current !== void 0 && current.handle.sessionId === handle.sessionId) return current;
|
|
2813
|
+
const resumed = catchUp && current === void 0;
|
|
2573
2814
|
current?.stop();
|
|
2574
2815
|
const server = await this.host.server(input.actor);
|
|
2575
2816
|
const deps = this.deps.forAgent(input.agentName);
|
|
@@ -2600,6 +2841,10 @@ ${body}
|
|
|
2600
2841
|
...spent !== void 0 ? {
|
|
2601
2842
|
carried: spent
|
|
2602
2843
|
} : {},
|
|
2844
|
+
...progress !== void 0 ? {
|
|
2845
|
+
progress
|
|
2846
|
+
} : {},
|
|
2847
|
+
resumed,
|
|
2603
2848
|
logger: this.logger,
|
|
2604
2849
|
onGranted: /* @__PURE__ */ __name((action, id) => {
|
|
2605
2850
|
const grants = this.grants.get(runId) ?? [];
|
|
@@ -2619,7 +2864,7 @@ ${body}
|
|
|
2619
2864
|
stop
|
|
2620
2865
|
};
|
|
2621
2866
|
this.live.set(runId, live);
|
|
2622
|
-
if (
|
|
2867
|
+
if (resumed) await turn.catchUp().catch(() => void 0);
|
|
2623
2868
|
return live;
|
|
2624
2869
|
}
|
|
2625
2870
|
/** Stop following a run in this process. */
|
|
@@ -3197,6 +3442,7 @@ var OpenCodeRunWorkflow = class {
|
|
|
3197
3442
|
}
|
|
3198
3443
|
async run(ctx, input) {
|
|
3199
3444
|
let spent = emptyUsage();
|
|
3445
|
+
let progress;
|
|
3200
3446
|
try {
|
|
3201
3447
|
const begun = await ctx.localStep("begin", async () => ({
|
|
3202
3448
|
handle: await this.turns.begin(ctx.runId, input),
|
|
@@ -3209,7 +3455,8 @@ var OpenCodeRunWorkflow = class {
|
|
|
3209
3455
|
});
|
|
3210
3456
|
for (let n = 0; ; n += 1) {
|
|
3211
3457
|
const before = spent;
|
|
3212
|
-
const
|
|
3458
|
+
const taken = progress;
|
|
3459
|
+
const milestone = await ctx.localStep(`observe:${n}`, () => this.turns.observe(ctx.runId, input, handle, before, taken));
|
|
3213
3460
|
spent = addUsage(spent, milestone.usage);
|
|
3214
3461
|
const total = spent;
|
|
3215
3462
|
if (milestone.kind === "finished") {
|
|
@@ -3235,7 +3482,9 @@ var OpenCodeRunWorkflow = class {
|
|
|
3235
3482
|
};
|
|
3236
3483
|
}
|
|
3237
3484
|
const ask = milestone.ask;
|
|
3238
|
-
|
|
3485
|
+
progress = milestone.progress ?? progress;
|
|
3486
|
+
const tookSoFar = progress;
|
|
3487
|
+
handle = await ctx.localStep(`reply:${n}`, () => this.turns.reply(ctx.runId, input, handle, ask, reply, total, tookSoFar));
|
|
3239
3488
|
}
|
|
3240
3489
|
} catch (error) {
|
|
3241
3490
|
if (isWorkflowControlFlowSignal(error)) throw error;
|