@frockbot/kernel-agent-loop 0.3.10 → 0.3.11

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.
Files changed (2) hide show
  1. package/package.json +5 -5
  2. package/src/index.ts +25 -34
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frockbot/kernel-agent-loop",
3
- "version": "0.3.10",
3
+ "version": "0.3.11",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -12,13 +12,13 @@
12
12
  "typecheck": "tsc --noEmit -p tsconfig.json"
13
13
  },
14
14
  "dependencies": {
15
- "@frockbot/kernel-contracts": "0.3.10",
15
+ "@frockbot/kernel-contracts": "0.3.11",
16
16
  "cordis": "4.0.0-rc.8"
17
17
  },
18
18
  "devDependencies": {
19
- "@frockbot/plugin-models": "0.3.10",
20
- "@frockbot/plugin-prompt": "0.3.10",
21
- "@frockbot/plugin-tools": "0.3.10",
19
+ "@frockbot/plugin-models": "0.3.11",
20
+ "@frockbot/plugin-prompt": "0.3.11",
21
+ "@frockbot/plugin-tools": "0.3.11",
22
22
  "@types/bun": "1.4.0",
23
23
  "@types/node": "26.2.0",
24
24
  "typescript": "^7.0.2"
package/src/index.ts CHANGED
@@ -686,24 +686,8 @@ class LoopAgent implements Agent {
686
686
  throw new StepLimitReachedError(this.#maxSteps);
687
687
  } catch (error) {
688
688
  if (this.#turnDeadlineReached) {
689
- // Ahead of both the reconciliation and the cancellation branch on
690
- // purpose. Cancellation, because the deadline aborts the same
691
- // controller Stop does and a Turn the clock ended must not be reported
692
- // to the person as one they stopped. Reconciliation, because the
693
- // reconciliation branch writes no `turn/end` on the promise that the
694
- // run may still resume — and a run the deadline stopped never will.
695
- // Deferring to it left `model/reconciliation-required` as the last
696
- // event of an open Turn, and every later Turn on that Bot refused with
697
- // `409` for the life of the Bot.
698
- //
699
- // The uncertainty is still recorded: whatever the model request wrote
700
- // before the clock ran out stays in the journal. What changes is that
701
- // the Turn is settled here — the open step's tool occurrences closed
702
- // as `interrupted`, then `step/end` and `turn/end` — exactly as
703
- // `kernel-do`'s `settledEventsV1` settles a Stop or a supersede.
704
689
  turnOutcome = "interrupted";
705
- turnReason = turnEndReason(TURN_DEADLINE_REASON_V1);
706
- this.#ctx.emit("agent/error", this, error);
690
+ turnReason = this.#deadlineTurnReason(error);
707
691
  } else if (
708
692
  error instanceof ModelEffectReconciliationRequiredError ||
709
693
  error instanceof ToolEffectReconciliationRequiredError ||
@@ -886,24 +870,8 @@ class LoopAgent implements Agent {
886
870
  throw new StepLimitReachedError(this.#maxSteps);
887
871
  } catch (error) {
888
872
  if (this.#turnDeadlineReached) {
889
- // Ahead of both the reconciliation and the cancellation branch on
890
- // purpose. Cancellation, because the deadline aborts the same
891
- // controller Stop does and a Turn the clock ended must not be reported
892
- // to the person as one they stopped. Reconciliation, because the
893
- // reconciliation branch writes no `turn/end` on the promise that the
894
- // run may still resume — and a run the deadline stopped never will.
895
- // Deferring to it left `model/reconciliation-required` as the last
896
- // event of an open Turn, and every later Turn on that Bot refused with
897
- // `409` for the life of the Bot.
898
- //
899
- // The uncertainty is still recorded: whatever the model request wrote
900
- // before the clock ran out stays in the journal. What changes is that
901
- // the Turn is settled here — the open step's tool occurrences closed
902
- // as `interrupted`, then `step/end` and `turn/end` — exactly as
903
- // `kernel-do`'s `settledEventsV1` settles a Stop or a supersede.
904
873
  turnOutcome = "interrupted";
905
- turnReason = turnEndReason(TURN_DEADLINE_REASON_V1);
906
- this.#ctx.emit("agent/error", this, error);
874
+ turnReason = this.#deadlineTurnReason(error);
907
875
  } else if (
908
876
  error instanceof ModelEffectReconciliationRequiredError ||
909
877
  error instanceof ToolEffectReconciliationRequiredError ||
@@ -1421,6 +1389,29 @@ class LoopAgent implements Agent {
1421
1389
  return decision.kind === "stop";
1422
1390
  }
1423
1391
 
1392
+ /**
1393
+ * The reason a Turn the clock ended carries, and the one place that decides
1394
+ * a deadline is not a cancellation and not a reconciliation.
1395
+ *
1396
+ * Its branch runs ahead of both. Ahead of cancellation, because the deadline
1397
+ * aborts the same controller Stop does and a Turn the clock ended must not
1398
+ * be reported to the person as one they stopped. Ahead of reconciliation,
1399
+ * because that branch writes no `turn/end` on the promise the run may still
1400
+ * resume — and a run the deadline stopped never will. Deferring to it left
1401
+ * `model/reconciliation-required` as the last event of an open Turn, and
1402
+ * every later Turn on that Bot refused with `409` for the life of the Bot.
1403
+ *
1404
+ * The uncertainty is still recorded: whatever the model request wrote before
1405
+ * the clock ran out stays in the journal. What changes is that the Turn is
1406
+ * settled — the open step's tool occurrences closed as `interrupted`, then
1407
+ * `step/end` and `turn/end` — exactly as `kernel-do`'s `settledEventsV1`
1408
+ * settles a Stop or a supersede.
1409
+ */
1410
+ #deadlineTurnReason(error: unknown): string | undefined {
1411
+ this.#ctx.emit("agent/error", this, error);
1412
+ return turnEndReason(TURN_DEADLINE_REASON_V1);
1413
+ }
1414
+
1424
1415
  async #settleCancelledStep(turn: number, step: number): Promise<void> {
1425
1416
  const assistant = this.session.events.findLast(
1426
1417
  (event) =>