@rowan-agent/agent 0.9.21 → 0.9.23

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
@@ -596,12 +596,14 @@ interface SourceInfo {
596
596
  baseDir?: string;
597
597
  displayName?: string;
598
598
  }
599
+ /** Register a Phase by directory path or Phase object; PHASE.md and direct child Skills are loaded atomically when a path is supplied. */
600
+ type PhaseRegistration = string | Phase;
599
601
  /**
600
- * Tool definition for registering LLM-callable tools via `api.registerTool()`.
602
+ * Tool definition for registering LLM-callable tools via `api.tool.register()`.
601
603
  *
602
604
  * @example
603
605
  * ```typescript
604
- * api.registerTool({
606
+ * api.tool.register({
605
607
  * name: "search_docs",
606
608
  * description: "Search documentation",
607
609
  * parameters: { type: "object", properties: { query: { type: "string" } } },
@@ -854,10 +856,13 @@ interface ExtensionAPI {
854
856
  on<K extends HookEventType>(eventType: K, handler: HookHandler<K>): void;
855
857
  /** Unsubscribe from a hook event. */
856
858
  off<K extends HookEventType>(eventType: K, handler: HookHandler<K>): void;
857
- /** Register a custom LLM-callable tool. */
858
- registerTool(tool: ToolDefinition): void;
859
- /** Register a Phase directory bundle. */
860
- registerPhase(path: string): Promise<void>;
859
+ /** Tool capabilities — register and unregister custom tools. */
860
+ tool: {
861
+ /** Register a custom LLM-callable tool. */
862
+ register(tool: ToolDefinition): void;
863
+ /** Unregister a previously registered tool by name. */
864
+ unregister(toolName: string): void;
865
+ };
861
866
  /** Register a model provider. */
862
867
  registerProvider(config: _rowan_agent_models.ProviderConfig): void;
863
868
  /** Unregister a model provider. */
@@ -870,8 +875,12 @@ interface ExtensionAPI {
870
875
  context: ExtensionContext;
871
876
  /** Shared event bus for inter-extension communication. */
872
877
  events: EventBus;
873
- /** Phase execution capabilities — rovides Phase In/Out, phase identity, and phase routing. */
878
+ /** Phase execution capabilities — provides Phase In/Out, phase identity, phase routing, and registration. */
874
879
  phase: {
880
+ /** Register a Phase directory bundle or Phase object. */
881
+ register(phase: PhaseRegistration): Promise<void>;
882
+ /** Unregister a previously registered phase by name. */
883
+ unregister(phaseName: string): void;
875
884
  /** Phase In: get payload from previous phase */
876
885
  getPayload(): unknown;
877
886
  /** Phase Out: set payload for next phase */
@@ -1409,7 +1418,10 @@ declare class ExtensionRunner {
1409
1418
  */
1410
1419
  private createExtensionAPI;
1411
1420
  private registerTool;
1421
+ private unregisterTool;
1412
1422
  private registerPhase;
1423
+ private registerPhaseDefinition;
1424
+ private unregisterPhase;
1413
1425
  private loadRegisteredPhase;
1414
1426
  private registerProvider;
1415
1427
  private unregisterProvider;
@@ -2395,6 +2407,12 @@ declare class InMemoryStore implements DurableStore {
2395
2407
  private writeReceipt;
2396
2408
  private replayOperation;
2397
2409
  private writeOperationReceipt;
2410
+ /**
2411
+ * A Claim receipt exists for idempotent replay of one live Execution Attempt
2412
+ * and carries that Attempt's history. Dropping it when the Attempt ends keeps
2413
+ * one history snapshot per Agent instead of one per Attempt.
2414
+ */
2415
+ private dropClaimReceipt;
2398
2416
  private requireAgent;
2399
2417
  private requireRun;
2400
2418
  private requireToolCall;
package/dist/index.js CHANGED
@@ -1208,13 +1208,15 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
1208
1208
  assertActive();
1209
1209
  hooks?.off(eventType, handler);
1210
1210
  },
1211
- registerTool: (tool) => {
1212
- assertActive();
1213
- options?.registerTool?.(tool);
1214
- },
1215
- registerPhase: async (registration) => {
1216
- assertActive();
1217
- await options?.registerPhase?.(registration);
1211
+ tool: {
1212
+ register: (tool) => {
1213
+ assertActive();
1214
+ options?.registerTool?.(tool);
1215
+ },
1216
+ unregister: (toolName) => {
1217
+ assertActive();
1218
+ options?.unregisterTool?.(toolName);
1219
+ }
1218
1220
  },
1219
1221
  registerProvider: (config) => {
1220
1222
  assertActive();
@@ -1246,6 +1248,14 @@ function createExtensionAPI(hooks, options, runtime, eventBus) {
1246
1248
  }, emit: () => {
1247
1249
  }, has: () => false, count: () => 0 },
1248
1250
  phase: {
1251
+ register: async (registration) => {
1252
+ assertActive();
1253
+ await options?.registerPhase?.(registration);
1254
+ },
1255
+ unregister: (phaseName) => {
1256
+ assertActive();
1257
+ options?.unregisterPhase?.(phaseName);
1258
+ },
1249
1259
  getPayload: () => outputPayload,
1250
1260
  setPayload: (p) => {
1251
1261
  outputPayload = p;
@@ -4925,9 +4935,11 @@ var ExtensionRunner = class {
4925
4935
  };
4926
4936
  return createExtensionAPI(this.hooks, {
4927
4937
  registerPhase: (registration) => this.registerPhase(extension, registration),
4938
+ unregisterPhase: (phaseName) => this.unregisterPhase(extension, phaseName),
4928
4939
  registerProvider: (config) => this.registerProvider(config),
4929
4940
  unregisterProvider: (name) => this.unregisterProvider(name),
4930
4941
  registerTool: (tool) => this.registerTool(extension, tool),
4942
+ unregisterTool: (toolName) => this.unregisterTool(extension, toolName),
4931
4943
  context: extContext,
4932
4944
  manifest,
4933
4945
  trackCleanup: (cleanup) => extension.cleanup.push(cleanup)
@@ -4954,11 +4966,43 @@ var ExtensionRunner = class {
4954
4966
  sourceInfo
4955
4967
  });
4956
4968
  }
4957
- registerPhase(extension, registration) {
4958
- if (typeof registration !== "string" || registration.length === 0) {
4959
- throw new Error(`Phase registration requires a directory path.`);
4969
+ unregisterTool(extension, toolName) {
4970
+ if (extension.tools.has(toolName)) {
4971
+ extension.tools.delete(toolName);
4972
+ }
4973
+ }
4974
+ async registerPhase(extension, registration) {
4975
+ if (typeof registration === "string") {
4976
+ if (registration.length === 0) {
4977
+ throw new Error(`Phase registration requires a directory path.`);
4978
+ }
4979
+ return this.loadRegisteredPhase(extension, registration);
4980
+ }
4981
+ if (typeof registration === "object" && registration !== null && "name" in registration) {
4982
+ return this.registerPhaseDefinition(extension, registration);
4983
+ }
4984
+ throw new Error(`Phase registration requires a directory path or Phase object.`);
4985
+ }
4986
+ registerPhaseDefinition(extension, phase) {
4987
+ const name = phase.name;
4988
+ if (this.phases.has(name)) {
4989
+ throw new Error(`Duplicate phase name: ${name}`);
4990
+ }
4991
+ const registered = {
4992
+ definition: phase,
4993
+ source: { extensionPath: extension.path }
4994
+ };
4995
+ this.phases.set(name, registered);
4996
+ extension.phases.add(name);
4997
+ this._phaseCache = null;
4998
+ }
4999
+ unregisterPhase(extension, phaseName) {
5000
+ const registered = this.phases.get(phaseName);
5001
+ if (registered && registered.source.extensionPath === extension.path) {
5002
+ this.phases.delete(phaseName);
5003
+ extension.phases.delete(phaseName);
5004
+ this._phaseCache = null;
4960
5005
  }
4961
- return this.loadRegisteredPhase(extension, registration);
4962
5006
  }
4963
5007
  async loadRegisteredPhase(extension, registration) {
4964
5008
  const extensionBase = extension.path.startsWith("<") ? this.cwd : dirname5(extension.path);
@@ -5804,6 +5848,7 @@ function selectedRefs(refs, names) {
5804
5848
  var DEFAULT_CONCURRENCY = 10;
5805
5849
  var DEFAULT_POLL_MS = 25;
5806
5850
  var MAX_CONSUMER_IDLE_POLL_MS = 250;
5851
+ var RUN_STATE_CHECK_INTERVAL_MS = 1e3;
5807
5852
  var OWNER_LEASE_MS = 3e4;
5808
5853
  var OWNER_RENEWAL_MS = 1e4;
5809
5854
  var MAX_INLINE_TOOL_RESULT_BYTES = 16 * 1024;
@@ -6608,15 +6653,25 @@ var AgentRuntime = class _AgentRuntime {
6608
6653
  async *observe(runId, options = {}) {
6609
6654
  let cursor = options.after;
6610
6655
  const subscription = this.transientEvents.subscribe(runId);
6656
+ let nextRunStateCheckAtMs = 0;
6611
6657
  try {
6612
6658
  while (true) {
6659
+ const published = subscription.shift();
6660
+ if (published) {
6661
+ yield published;
6662
+ continue;
6663
+ }
6613
6664
  const observationVersion = subscription.checkpoint();
6614
- const snapshot = await this.owned.snapshotRun(runId);
6615
- const terminal = ["completed", "failed", "cancelled"].includes(snapshot.state);
6616
- if (options.signal?.aborted && !terminal) throw abortError();
6617
- if (terminal) {
6618
- const pending = await this.owned.listEvents(cursor ? { after: cursor } : {});
6619
- if (!pending.some((event) => event.runId === runId)) return;
6665
+ const aborted = options.signal?.aborted === true;
6666
+ if (aborted || Date.now() >= nextRunStateCheckAtMs) {
6667
+ nextRunStateCheckAtMs = Date.now() + RUN_STATE_CHECK_INTERVAL_MS;
6668
+ const snapshot = await this.owned.snapshotRun(runId);
6669
+ const terminal = ["completed", "failed", "cancelled"].includes(snapshot.state);
6670
+ if (aborted && !terminal) throw abortError();
6671
+ if (terminal) {
6672
+ const pending = await this.owned.listEvents(cursor ? { after: cursor } : {});
6673
+ if (!pending.some((event) => event.runId === runId)) return;
6674
+ }
6620
6675
  }
6621
6676
  const events = await this.owned.listEvents(cursor ? { after: cursor } : {});
6622
6677
  for (const event of events) {
@@ -6913,6 +6968,7 @@ var InMemoryStore = class _InMemoryStore {
6913
6968
  const failure = indeterminateToolCallIds.length > 0 ? { code: "tool_indeterminate", message, toolCallIds: indeterminateToolCallIds } : { code: "runtime_interrupted", message, ownerEpoch };
6914
6969
  run.state = "failed";
6915
6970
  run.failure = failure;
6971
+ this.dropClaimReceipt(run.execution);
6916
6972
  delete run.execution;
6917
6973
  run.revision += 1;
6918
6974
  run.updatedAt = createTimestamp();
@@ -7142,6 +7198,7 @@ var InMemoryStore = class _InMemoryStore {
7142
7198
  delete run.openInputRequest;
7143
7199
  delete run.checkpoint;
7144
7200
  }
7201
+ this.dropClaimReceipt(run.execution);
7145
7202
  delete run.execution;
7146
7203
  run.state = "cancelled";
7147
7204
  run.cancellationReason = "Run superseded by Message revision.";
@@ -7325,6 +7382,7 @@ var InMemoryStore = class _InMemoryStore {
7325
7382
  delete run.openInteractions;
7326
7383
  delete run.interactionAnswers;
7327
7384
  }
7385
+ this.dropClaimReceipt(run.execution);
7328
7386
  delete run.execution;
7329
7387
  run.revision += 1;
7330
7388
  run.updatedAt = createTimestamp();
@@ -7579,6 +7637,7 @@ var InMemoryStore = class _InMemoryStore {
7579
7637
  };
7580
7638
  run.state = "failed";
7581
7639
  run.failure = failure;
7640
+ this.dropClaimReceipt(run.execution);
7582
7641
  delete run.execution;
7583
7642
  run.revision += 1;
7584
7643
  run.updatedAt = createTimestamp();
@@ -7609,6 +7668,7 @@ var InMemoryStore = class _InMemoryStore {
7609
7668
  run.state = nextState;
7610
7669
  if (input.outcome) run.outcome = clone(input.outcome);
7611
7670
  if (input.failure) run.failure = clone(input.failure);
7671
+ this.dropClaimReceipt(run.execution);
7612
7672
  delete run.execution;
7613
7673
  delete run.openInteractions;
7614
7674
  delete run.interactionAnswers;
@@ -7655,6 +7715,7 @@ var InMemoryStore = class _InMemoryStore {
7655
7715
  run.state = "failed";
7656
7716
  run.failure = failure;
7657
7717
  delete run.cancellationReason;
7718
+ this.dropClaimReceipt(run.execution);
7658
7719
  delete run.execution;
7659
7720
  delete run.openInputRequest;
7660
7721
  delete run.openInteractions;
@@ -7668,6 +7729,7 @@ var InMemoryStore = class _InMemoryStore {
7668
7729
  }
7669
7730
  run.state = "cancelled";
7670
7731
  run.cancellationReason = input.reason;
7732
+ this.dropClaimReceipt(run.execution);
7671
7733
  delete run.execution;
7672
7734
  delete run.openInputRequest;
7673
7735
  delete run.openInteractions;
@@ -7841,6 +7903,14 @@ var InMemoryStore = class _InMemoryStore {
7841
7903
  writeOperationReceipt(key, payload, result) {
7842
7904
  this.operationReceipts.set(key, { payload, result: clone(result) });
7843
7905
  }
7906
+ /**
7907
+ * A Claim receipt exists for idempotent replay of one live Execution Attempt
7908
+ * and carries that Attempt's history. Dropping it when the Attempt ends keeps
7909
+ * one history snapshot per Agent instead of one per Attempt.
7910
+ */
7911
+ dropClaimReceipt(execution) {
7912
+ if (execution) this.operationReceipts.delete(`claim:${execution.executionId}`);
7913
+ }
7844
7914
  requireAgent(agentId) {
7845
7915
  const agent = this.agents.get(agentId);
7846
7916
  if (!agent) throw new RuntimeError("agent_not_found", { agentId });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowan-agent/agent",
3
- "version": "0.9.21",
3
+ "version": "0.9.23",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",