@rowan-agent/agent 0.8.2 → 0.8.4

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
@@ -1391,7 +1391,7 @@ declare class InMemoryStore implements DurableStore {
1391
1391
  ownerId: string;
1392
1392
  leaseMs: number;
1393
1393
  }): Promise<OwnedStore>;
1394
- assertOwner(lease: OwnerLease): void;
1394
+ assertOwner(lease: OwnerLease, requireLive?: boolean): void;
1395
1395
  renewOwner(lease: OwnerLease, leaseMs: number): OwnerLease;
1396
1396
  releaseOwner(lease: OwnerLease): void;
1397
1397
  reserveAgent(lease: OwnerLease, input: {
@@ -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
@@ -767,6 +767,15 @@ var EmptyResponseError = class extends Error {
767
767
  this.name = "EmptyResponseError";
768
768
  }
769
769
  };
770
+ var ModelOutputLimitError = class extends Error {
771
+ constructor(limit) {
772
+ super(`Model output exceeded the ${limit}-character safety limit.`);
773
+ this.limit = limit;
774
+ this.name = "ModelOutputLimitError";
775
+ }
776
+ limit;
777
+ code = "model_output_limit";
778
+ };
770
779
  var LoopGuard = {
771
780
  /** Returns abort result if signal is aborted */
772
781
  checkAbort(signal) {
@@ -778,6 +787,7 @@ var LoopGuard = {
778
787
  };
779
788
 
780
789
  // src/loop/stream-collector.ts
790
+ var MAX_STREAMED_OUTPUT_CHARACTERS = 1024 * 1024;
781
791
  async function invokeModel(input) {
782
792
  const events = input.config.stream(input.request, { signal: input.config.signal });
783
793
  const result = await collectStreamResult({
@@ -811,7 +821,22 @@ async function collectStreamResult(input) {
811
821
  let lastPartial;
812
822
  let stopReason;
813
823
  let doneResponse;
824
+ let streamedOutputCharacters = 0;
825
+ const toolCallsWithDeltas = /* @__PURE__ */ new Set();
814
826
  for await (const event of input.events) {
827
+ if (event.type === "text_delta") {
828
+ streamedOutputCharacters += event.text.length;
829
+ } else if (event.type === "thinking_delta") {
830
+ streamedOutputCharacters += event.thinking.length;
831
+ } else if (event.type === "tool_call_delta") {
832
+ streamedOutputCharacters += event.arguments.length;
833
+ toolCallsWithDeltas.add(event.id);
834
+ } else if (event.type === "tool_call_end" && !toolCallsWithDeltas.has(event.id)) {
835
+ streamedOutputCharacters += event.arguments.length;
836
+ }
837
+ if (streamedOutputCharacters > MAX_STREAMED_OUTPUT_CHARACTERS) {
838
+ throw new ModelOutputLimitError(MAX_STREAMED_OUTPUT_CHARACTERS);
839
+ }
815
840
  const abortResult2 = LoopGuard.checkAbort(input.config.signal);
816
841
  if (abortResult2.stopReason !== "none") {
817
842
  if (activeMessageId) {
@@ -3816,6 +3841,7 @@ var TransientRunEventHub = class {
3816
3841
  // src/runtime/durable-runtime.ts
3817
3842
  var DEFAULT_CONCURRENCY = 10;
3818
3843
  var DEFAULT_POLL_MS = 25;
3844
+ var MAX_CONSUMER_IDLE_POLL_MS = 250;
3819
3845
  var OWNER_LEASE_MS = 3e4;
3820
3846
  var OWNER_RENEWAL_MS = 1e4;
3821
3847
  var AgentRuntime = class _AgentRuntime {
@@ -4218,6 +4244,7 @@ var AgentRuntime = class _AgentRuntime {
4218
4244
  let cursor = registration.cursor;
4219
4245
  const waterline = cursorSequence(registration.waterline);
4220
4246
  let caughtUp = false;
4247
+ let pollMs = DEFAULT_POLL_MS;
4221
4248
  while (!subscription.controller.signal.aborted && !this.closed) {
4222
4249
  const events = await this.owned.listEvents(cursor ? { after: cursor } : {});
4223
4250
  for (const event of events) {
@@ -4243,7 +4270,8 @@ var AgentRuntime = class _AgentRuntime {
4243
4270
  caughtUp = true;
4244
4271
  subscription.caughtUp.resolve();
4245
4272
  }
4246
- await delay(DEFAULT_POLL_MS);
4273
+ pollMs = events.length === 0 ? Math.min(MAX_CONSUMER_IDLE_POLL_MS, pollMs * 2) : DEFAULT_POLL_MS;
4274
+ await delay(pollMs);
4247
4275
  }
4248
4276
  if (!caughtUp) subscription.caughtUp.resolve();
4249
4277
  }
@@ -4492,17 +4520,17 @@ var InMemoryStore = class _InMemoryStore {
4492
4520
  };
4493
4521
  return new MemoryOwnedStore(this, clone(this.owner));
4494
4522
  }
4495
- assertOwner(lease) {
4523
+ assertOwner(lease, requireLive = true) {
4496
4524
  const actual = this.owner;
4497
4525
  if (!actual || actual.token !== lease.token || actual.epoch !== lease.epoch || actual.ownerId !== lease.ownerId) {
4498
4526
  throw ownershipLost(lease, actual, "epoch_advanced");
4499
4527
  }
4500
- if (Date.parse(actual.expiresAt) <= Date.now()) {
4528
+ if (requireLive && Date.parse(actual.expiresAt) <= Date.now()) {
4501
4529
  throw ownershipLost(lease, actual, "expired");
4502
4530
  }
4503
4531
  }
4504
4532
  renewOwner(lease, leaseMs) {
4505
- this.assertOwner(lease);
4533
+ this.assertOwner(lease, false);
4506
4534
  assertLeaseDuration(leaseMs);
4507
4535
  this.owner.expiresAt = expiry(leaseMs);
4508
4536
  return clone(this.owner);
@@ -4597,23 +4625,25 @@ var InMemoryStore = class _InMemoryStore {
4597
4625
  if ([...this.runs.values()].some((candidate) => candidate.agentId === run.agentId && candidate.id !== run.id && ["running", "input_required"].includes(candidate.state))) {
4598
4626
  throw new RuntimeError("run_state_conflict", { runId: run.id, expected: ["queued"], actual: run.state });
4599
4627
  }
4600
- const messageId = input.messageId ?? createId("msg");
4601
4628
  if (run.pinnedConfigToken && input.configToken && run.pinnedConfigToken !== input.configToken) {
4602
4629
  throw new RuntimeError("run_state_conflict", { runId: run.id, expected: ["queued"], actual: run.state });
4603
4630
  }
4604
4631
  if (!run.pinnedConfigToken && input.configToken) run.pinnedConfigToken = input.configToken;
4605
- const userInput = normalizeUserInput(run.input);
4606
- const message = {
4607
- id: messageId,
4608
- agentId: run.agentId,
4609
- runId: run.id,
4610
- role: "user",
4611
- content: userInputContent(userInput),
4612
- ...userInputMetadata(userInput) ? { metadata: clone(userInputMetadata(userInput)) } : {},
4613
- sequenceWithinRun: this.nextMessageSequence(run.id),
4614
- createdAt: createTimestamp()
4615
- };
4616
- this.messages.set(message.id, message);
4632
+ let message;
4633
+ if (!run.checkpoint) {
4634
+ const userInput = normalizeUserInput(run.input);
4635
+ message = {
4636
+ id: input.messageId ?? createId("msg"),
4637
+ agentId: run.agentId,
4638
+ runId: run.id,
4639
+ role: "user",
4640
+ content: userInputContent(userInput),
4641
+ ...userInputMetadata(userInput) ? { metadata: clone(userInputMetadata(userInput)) } : {},
4642
+ sequenceWithinRun: this.nextMessageSequence(run.id),
4643
+ createdAt: createTimestamp()
4644
+ };
4645
+ this.messages.set(message.id, message);
4646
+ }
4617
4647
  const execution = {
4618
4648
  runId: run.id,
4619
4649
  ownerEpoch: lease.epoch,
@@ -4623,7 +4653,7 @@ var InMemoryStore = class _InMemoryStore {
4623
4653
  run.execution = execution;
4624
4654
  run.revision += 1;
4625
4655
  run.updatedAt = createTimestamp();
4626
- this.appendMessage(run, message);
4656
+ if (message) this.appendMessage(run, message);
4627
4657
  this.appendTransition(run, "queued", "running");
4628
4658
  const result = { run: clone(run), execution: clone(execution), history: this.history(run.agentId, run.agentSequence) };
4629
4659
  this.writeOperationReceipt(operationKey, operationPayload, result);
@@ -5497,7 +5527,28 @@ var SqliteStore = class {
5497
5527
  return this.invoke(lease, (store, current) => store.listRuns(current, input), false);
5498
5528
  }
5499
5529
  async listEvents(lease, input = {}) {
5500
- return this.invoke(lease, (store, current) => store.listEvents(current, input), false);
5530
+ this.assertOpen();
5531
+ return this.readTransaction(() => {
5532
+ this.requireMatchingOwner(lease, true);
5533
+ const after = input.after ? parseEventCursor(lease, input.after) : 0;
5534
+ if (input.after) {
5535
+ const latest = this.database.query(
5536
+ "SELECT payload_json FROM run_events ORDER BY sequence DESC LIMIT 1"
5537
+ ).get();
5538
+ const waterline = latest ? parseEventCursor(
5539
+ lease,
5540
+ JSON.parse(latest.payload_json).cursor
5541
+ ) : 0;
5542
+ if (after > waterline) {
5543
+ throw new RuntimeError("invalid_cursor", { cursorType: "event", reason: "beyond_waterline" });
5544
+ }
5545
+ if (after === waterline) return [];
5546
+ }
5547
+ const rows = this.database.query(
5548
+ "SELECT payload_json FROM run_events ORDER BY sequence LIMIT -1 OFFSET ?"
5549
+ ).all(after);
5550
+ return rows.map((row) => JSON.parse(row.payload_json));
5551
+ });
5501
5552
  }
5502
5553
  async openConsumer(lease, consumerId) {
5503
5554
  return this.invoke(lease, (store, current) => store.openConsumer(current, consumerId), false);
@@ -5509,7 +5560,7 @@ var SqliteStore = class {
5509
5560
  this.assertOpen();
5510
5561
  assertOwnerInput(lease.ownerId, leaseMs);
5511
5562
  return this.immediateTransaction(() => {
5512
- const row = this.requireMatchingOwner(lease, true);
5563
+ const row = this.requireMatchingOwner(lease, false);
5513
5564
  const expiresAt = Date.now() + leaseMs;
5514
5565
  this.writeOwner({ ...row, expires_at: expiresAt });
5515
5566
  return { ...lease, expiresAt: new Date(expiresAt).toISOString() };
@@ -5686,6 +5737,20 @@ var SqliteStore = class {
5686
5737
  throw error;
5687
5738
  }
5688
5739
  }
5740
+ readTransaction(operation) {
5741
+ this.database.run("BEGIN");
5742
+ try {
5743
+ const result = operation();
5744
+ this.database.run("COMMIT");
5745
+ return result;
5746
+ } catch (error) {
5747
+ try {
5748
+ this.database.run("ROLLBACK");
5749
+ } catch {
5750
+ }
5751
+ throw error;
5752
+ }
5753
+ }
5689
5754
  assertOpen() {
5690
5755
  if (this.closed) throw new RuntimeError("runtime_closed", null);
5691
5756
  }
@@ -5774,6 +5839,19 @@ function ownerLease(row) {
5774
5839
  expiresAt: new Date(row.expires_at).toISOString()
5775
5840
  };
5776
5841
  }
5842
+ function parseEventCursor(lease, cursor) {
5843
+ const value = String(cursor);
5844
+ const separator = value.lastIndexOf(":");
5845
+ const incarnation = separator < 0 ? "" : value.slice(0, separator);
5846
+ const sequence = separator < 0 ? "" : value.slice(separator + 1);
5847
+ const token = String(lease.token);
5848
+ const ownerSuffix = `:${lease.epoch}:${lease.ownerId}`;
5849
+ const expectedIncarnation = token.endsWith(ownerSuffix) ? token.slice(0, -ownerSuffix.length) : "";
5850
+ if (incarnation !== expectedIncarnation || !/^\d+$/.test(sequence)) {
5851
+ throw new RuntimeError("invalid_cursor", { cursorType: "event", reason: "wrong_store" });
5852
+ }
5853
+ return Number(sequence);
5854
+ }
5777
5855
  function ownershipLost2(lease, row) {
5778
5856
  return new RuntimeError("runtime_ownership_lost", {
5779
5857
  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.2",
3
+ "version": "0.8.4",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",