@rowan-agent/agent 0.8.1 → 0.8.3

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/dist/index.d.ts CHANGED
@@ -1667,6 +1667,7 @@ declare class SqliteStore implements DurableStore {
1667
1667
  private persistState;
1668
1668
  private requireMatchingOwner;
1669
1669
  private immediateTransaction;
1670
+ private readTransaction;
1670
1671
  private assertOpen;
1671
1672
  }
1672
1673
 
package/dist/index.js CHANGED
@@ -3816,6 +3816,7 @@ var TransientRunEventHub = class {
3816
3816
  // src/runtime/durable-runtime.ts
3817
3817
  var DEFAULT_CONCURRENCY = 10;
3818
3818
  var DEFAULT_POLL_MS = 25;
3819
+ var MAX_CONSUMER_IDLE_POLL_MS = 250;
3819
3820
  var OWNER_LEASE_MS = 3e4;
3820
3821
  var OWNER_RENEWAL_MS = 1e4;
3821
3822
  var AgentRuntime = class _AgentRuntime {
@@ -3947,6 +3948,12 @@ var AgentRuntime = class _AgentRuntime {
3947
3948
  });
3948
3949
  void task;
3949
3950
  }
3951
+ } catch (error) {
3952
+ if (error instanceof RuntimeError && error.code === "runtime_ownership_lost") {
3953
+ for (const execution of this.executions.values()) execution.controller.abort();
3954
+ return;
3955
+ }
3956
+ throw error;
3950
3957
  } finally {
3951
3958
  this.pumping = false;
3952
3959
  }
@@ -3995,10 +4002,7 @@ var AgentRuntime = class _AgentRuntime {
3995
4002
  const executionContext = projectModelContext({
3996
4003
  context: {
3997
4004
  ...executionConfig.context,
3998
- phases: executionConfig.context.phases ?? {
3999
- phases: /* @__PURE__ */ new Map([[DEFAULT_PHASE_ID, createDefaultPhase()]]),
4000
- entryPhaseId: DEFAULT_PHASE_ID
4001
- }
4005
+ phases: normalizePhaseRegistry(executionConfig.context.phases)
4002
4006
  },
4003
4007
  messages: claim.history,
4004
4008
  agentId: run.agentId,
@@ -4215,6 +4219,7 @@ var AgentRuntime = class _AgentRuntime {
4215
4219
  let cursor = registration.cursor;
4216
4220
  const waterline = cursorSequence(registration.waterline);
4217
4221
  let caughtUp = false;
4222
+ let pollMs = DEFAULT_POLL_MS;
4218
4223
  while (!subscription.controller.signal.aborted && !this.closed) {
4219
4224
  const events = await this.owned.listEvents(cursor ? { after: cursor } : {});
4220
4225
  for (const event of events) {
@@ -4240,7 +4245,8 @@ var AgentRuntime = class _AgentRuntime {
4240
4245
  caughtUp = true;
4241
4246
  subscription.caughtUp.resolve();
4242
4247
  }
4243
- await delay(DEFAULT_POLL_MS);
4248
+ pollMs = events.length === 0 ? Math.min(MAX_CONSUMER_IDLE_POLL_MS, pollMs * 2) : DEFAULT_POLL_MS;
4249
+ await delay(pollMs);
4244
4250
  }
4245
4251
  if (!caughtUp) subscription.caughtUp.resolve();
4246
4252
  }
@@ -4355,6 +4361,18 @@ function boundaryFromSnapshot(snapshot) {
4355
4361
  function delay(ms) {
4356
4362
  return new Promise((resolve6) => setTimeout(resolve6, ms));
4357
4363
  }
4364
+ function normalizePhaseRegistry(registry) {
4365
+ if (registry?.phases.has(DEFAULT_PHASE_ID)) {
4366
+ throw new TypeError(`Configured Phase collides with Rowan built-in Phase "${DEFAULT_PHASE_ID}".`);
4367
+ }
4368
+ return {
4369
+ phases: new Map([
4370
+ [DEFAULT_PHASE_ID, createDefaultPhase()],
4371
+ ...registry?.phases ?? []
4372
+ ]),
4373
+ entryPhaseId: registry?.entryPhaseId ?? DEFAULT_PHASE_ID
4374
+ };
4375
+ }
4358
4376
  function cursorSequence(cursor) {
4359
4377
  return Number(String(cursor).split(":").at(-1) ?? 0);
4360
4378
  }
@@ -5482,7 +5500,28 @@ var SqliteStore = class {
5482
5500
  return this.invoke(lease, (store, current) => store.listRuns(current, input), false);
5483
5501
  }
5484
5502
  async listEvents(lease, input = {}) {
5485
- return this.invoke(lease, (store, current) => store.listEvents(current, input), false);
5503
+ this.assertOpen();
5504
+ return this.readTransaction(() => {
5505
+ this.requireMatchingOwner(lease, true);
5506
+ const after = input.after ? parseEventCursor(lease, input.after) : 0;
5507
+ if (input.after) {
5508
+ const latest = this.database.query(
5509
+ "SELECT payload_json FROM run_events ORDER BY sequence DESC LIMIT 1"
5510
+ ).get();
5511
+ const waterline = latest ? parseEventCursor(
5512
+ lease,
5513
+ JSON.parse(latest.payload_json).cursor
5514
+ ) : 0;
5515
+ if (after > waterline) {
5516
+ throw new RuntimeError("invalid_cursor", { cursorType: "event", reason: "beyond_waterline" });
5517
+ }
5518
+ if (after === waterline) return [];
5519
+ }
5520
+ const rows = this.database.query(
5521
+ "SELECT payload_json FROM run_events ORDER BY sequence LIMIT -1 OFFSET ?"
5522
+ ).all(after);
5523
+ return rows.map((row) => JSON.parse(row.payload_json));
5524
+ });
5486
5525
  }
5487
5526
  async openConsumer(lease, consumerId) {
5488
5527
  return this.invoke(lease, (store, current) => store.openConsumer(current, consumerId), false);
@@ -5671,6 +5710,20 @@ var SqliteStore = class {
5671
5710
  throw error;
5672
5711
  }
5673
5712
  }
5713
+ readTransaction(operation) {
5714
+ this.database.run("BEGIN");
5715
+ try {
5716
+ const result = operation();
5717
+ this.database.run("COMMIT");
5718
+ return result;
5719
+ } catch (error) {
5720
+ try {
5721
+ this.database.run("ROLLBACK");
5722
+ } catch {
5723
+ }
5724
+ throw error;
5725
+ }
5726
+ }
5674
5727
  assertOpen() {
5675
5728
  if (this.closed) throw new RuntimeError("runtime_closed", null);
5676
5729
  }
@@ -5759,6 +5812,19 @@ function ownerLease(row) {
5759
5812
  expiresAt: new Date(row.expires_at).toISOString()
5760
5813
  };
5761
5814
  }
5815
+ function parseEventCursor(lease, cursor) {
5816
+ const value = String(cursor);
5817
+ const separator = value.lastIndexOf(":");
5818
+ const incarnation = separator < 0 ? "" : value.slice(0, separator);
5819
+ const sequence = separator < 0 ? "" : value.slice(separator + 1);
5820
+ const token = String(lease.token);
5821
+ const ownerSuffix = `:${lease.epoch}:${lease.ownerId}`;
5822
+ const expectedIncarnation = token.endsWith(ownerSuffix) ? token.slice(0, -ownerSuffix.length) : "";
5823
+ if (incarnation !== expectedIncarnation || !/^\d+$/.test(sequence)) {
5824
+ throw new RuntimeError("invalid_cursor", { cursorType: "event", reason: "wrong_store" });
5825
+ }
5826
+ return Number(sequence);
5827
+ }
5762
5828
  function ownershipLost2(lease, row) {
5763
5829
  return new RuntimeError("runtime_ownership_lost", {
5764
5830
  reason: row.epoch > lease.epoch ? "epoch_advanced" : row.owner_id ? "released" : "released",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowan-agent/agent",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",