@rowan-agent/agent 0.6.1 → 0.7.0

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 CHANGED
@@ -136,9 +136,9 @@ dead-lettered.
136
136
 
137
137
  ### Process Recovery
138
138
 
139
- Runtime startup recovers abandoned Leases into durable queued work without
140
- constructing Agent Bindings. The host supplies its current executable resources
141
- when it reconstructs an Agent:
139
+ Runtime startup and periodic recovery return expired Leases to durable queued
140
+ work without disturbing unexpired Leases owned by another process. The host
141
+ supplies its current executable resources when it reconstructs an Agent:
142
142
 
143
143
  ```ts
144
144
  const runtime = await AgentRuntime.start({ stateStore, sessionProvider });
@@ -337,17 +337,17 @@ const tools = createCoreTools({
337
337
  bashTimeoutMs?, // default: 30s
338
338
  maxBashOutputBytes?, // default: 64KB
339
339
  });
340
- // Returns: read, write, edit, bash
340
+ // Returns: read, bash, edit, write
341
341
  ```
342
342
 
343
343
  ### Built-in Tools
344
344
 
345
345
  | Tool | Description | Parameters |
346
346
  |------|-------------|------------|
347
- | `read` | Reads a text file within the workspace | `path` (required), `maxBytes?`, `type?` ("skill" \| "phase" \| "markdown" \| "code" \| "file") |
348
- | `write` | Writes content to a file, creating parent directories as needed | `path` (required), `content` (required) |
349
- | `edit` | Replaces exact `oldText` with `newText` in a file | `path` (required), `oldText` (required), `newText` (required), `replaceAll?` |
350
- | `bash` | Runs a bash command within the workspace | `command` (required), `cwd?`, `timeoutMs?`, `maxOutputBytes?` |
347
+ | `read` | Reads a file, optionally by line range | `path` (required), `offset?`, `limit?` |
348
+ | `bash` | Runs a bash command in the workspace | `command` (required), `timeout?` (seconds) |
349
+ | `edit` | Applies exact replacements, including multiple disjoint edits in one call | `path` (required), `edits[]` (each with `oldText` and `newText`) |
350
+ | `write` | Creates or overwrites a file | `path` (required), `content` (required) |
351
351
 
352
352
  ### Custom Tools
353
353
 
@@ -616,7 +616,7 @@ Two sources, merged by priority:
616
616
 
617
617
  ```yaml
618
618
  ---
619
- name: Code Review
619
+ name: review
620
620
  description: Review code for correctness and style
621
621
  tools: [read, bash]
622
622
  target: execute
@@ -625,15 +625,14 @@ target: execute
625
625
  Review the current implementation for bugs and style issues.
626
626
  ```
627
627
 
628
- **Extension-registered** — via `api.registerPhase()`. Same id overrides file-based phases.
628
+ **Extension-registered** — via `api.registerPhase()`. The phase name is used as its identity.
629
629
 
630
630
  ```ts
631
631
  import type { ExtensionAPI } from "@rowan-agent/agent";
632
632
 
633
633
  export default function myPlugin(api: ExtensionAPI) {
634
634
  api.registerPhase({
635
- id: "review",
636
- name: "Code Review",
635
+ name: "review",
637
636
  description: "Review code for correctness",
638
637
  tools: ["read", "bash"],
639
638
  async run(context, execution) {
@@ -648,8 +647,7 @@ export default function myPlugin(api: ExtensionAPI) {
648
647
 
649
648
  ```ts
650
649
  interface Phase {
651
- id: string;
652
- name: string;
650
+ name: string; // unique identity and display name
653
651
  description: string;
654
652
  tools?: string[]; // restrict tools (undefined = all)
655
653
  skills?: string[]; // restrict skills
@@ -674,7 +672,7 @@ interface PhaseContext {
674
672
 
675
673
  type PhaseOutput = {
676
674
  message: string;
677
- route: string; // "continue" | "stop" | <phase-id>
675
+ route: string; // "continue" | "stop" | <phase-name>
678
676
  payload?: unknown; // data passed to the next phase
679
677
  };
680
678
  ```
@@ -731,7 +729,7 @@ import type { ExtensionAPI } from "@rowan-agent/agent";
731
729
  export default function myPlugin(rowan: ExtensionAPI) {
732
730
  rowan.on("agent_start", (event) => { ... });
733
731
  rowan.registerTool({ name: "my_tool", description: "...", parameters: {...}, execute: async (args) => {...} });
734
- rowan.registerPhase({ id: "review", description: "...", run: async (ctx) => {...} });
732
+ rowan.registerPhase({ name: "review", description: "...", run: async (ctx) => {...} });
735
733
  rowan.events.emit("my-plugin:ready", {});
736
734
  }
737
735
  ```
@@ -775,7 +773,7 @@ type LoopMetrics = {
775
773
  | `Skill` | Loaded skill bundle |
776
774
  | `Phase` | Phase definition with content, execution, and routing config |
777
775
  | `PhaseContext` / `PhaseOutput` | Phase input and output |
778
- | `PhaseRegistry` | Map of phase ids to Phase objects plus entry phase id |
776
+ | `PhaseRegistry` | Map of phase names to Phase objects plus entry phase name |
779
777
  | `Outcome` | Terminal result with message and tool results |
780
778
  | `LoopMetrics` | Loop iteration, timing, and phase transition stats |
781
779
  | `SessionManagerProvider` | Session lifecycle seam used by the Runtime |
package/dist/index.d.ts CHANGED
@@ -30,6 +30,7 @@ type RuntimeEventId = OpaqueId<"RuntimeEventId">;
30
30
  type LeaseId = OpaqueId<"LeaseId">;
31
31
  type RuntimeToolCallId = OpaqueId<"RuntimeToolCallId">;
32
32
  type AgentLifecycleState = "active" | "paused";
33
+ type SessionLifecycleState = "active" | "archived" | "deleting";
33
34
  type RuntimeMessageState = "queued" | "leased" | "acknowledged" | "dead_lettered";
34
35
  type AgentRunState = "queued" | "running" | "suspended" | "completed" | "failed" | "cancelled";
35
36
  /** Opaque execution checkpoint owned by the Agent loop and persisted by Runtime. */
@@ -46,6 +47,8 @@ type AgentRecord = {
46
47
  id: AgentId;
47
48
  sessionId: string;
48
49
  state: AgentLifecycleState;
50
+ lifecycleState: SessionLifecycleState;
51
+ parentSessionId?: string;
49
52
  createdAt: string;
50
53
  updatedAt: string;
51
54
  };
@@ -84,7 +87,7 @@ type AgentRunRecord = {
84
87
  createdAt: string;
85
88
  updatedAt: string;
86
89
  };
87
- type RuntimeEventKind = "agent_created" | "agent_paused" | "agent_resumed" | "message_enqueued" | "run_enqueued" | "run_leased" | "lease_expired" | "lease_recovered" | "run_suspended" | "run_retry_scheduled" | "run_completed" | "run_aborted" | "message_acknowledged" | "message_dead_lettered" | "tool_call_created" | "tool_call_started" | "tool_call_failed" | "tool_call_completed" | "tool_call_indeterminate";
90
+ type RuntimeEventKind = "agent_created" | "agent_paused" | "agent_resumed" | "session_archived" | "session_unarchived" | "message_enqueued" | "run_enqueued" | "run_leased" | "lease_expired" | "lease_recovered" | "run_suspended" | "run_retry_scheduled" | "run_completed" | "run_aborted" | "message_acknowledged" | "message_dead_lettered" | "tool_call_created" | "tool_call_started" | "tool_call_failed" | "tool_call_completed" | "tool_call_indeterminate";
88
91
  type RuntimeEvent = {
89
92
  id: RuntimeEventId;
90
93
  sequence: number;
@@ -325,9 +328,7 @@ interface PhaseContext {
325
328
  * Loaded Phase object
326
329
  */
327
330
  interface Phase {
328
- /** Unique identifier */
329
- id: string;
330
- /** Display name */
331
+ /** Unique phase identity and display name. */
331
332
  name: string;
332
333
  /** Description */
333
334
  description: string;
@@ -358,9 +359,9 @@ interface Phase {
358
359
  * Phase registry containing all loaded phases
359
360
  */
360
361
  interface PhaseRegistry {
361
- /** Map of phase id to Phase object */
362
+ /** Map of phase name to Phase object */
362
363
  phases: Map<string, Phase>;
363
- /** Entry phase id (null until Agent applies its default phase) */
364
+ /** Entry phase name (null until Agent applies its default phase) */
364
365
  entryPhaseId: string | null;
365
366
  }
366
367
 
@@ -372,7 +373,6 @@ interface PhaseRegistry {
372
373
  type PhaseRun = (context: PhaseContext, execution: PhaseExecution) => Promise<PhaseOutput | void>;
373
374
  /** Phase definition shape used by extensions */
374
375
  type PhaseDefinition = {
375
- id: string;
376
376
  name: string;
377
377
  description: string;
378
378
  run?: PhaseRun;
@@ -382,7 +382,7 @@ type PhaseDefinition = {
382
382
  input?: Record<string, string>;
383
383
  model?: string;
384
384
  };
385
- type PhaseRegistration = Partial<Omit<PhaseDefinition, 'run'>> & {
385
+ type PhaseRegistration = Omit<PhaseDefinition, 'run'> & {
386
386
  /** Optional execution override — takes over model invocation */
387
387
  run?: PhaseRun;
388
388
  };
@@ -480,7 +480,6 @@ interface ExtensionManifest {
480
480
  entry?: string;
481
481
  name?: string;
482
482
  phase?: {
483
- id?: string;
484
483
  name?: string;
485
484
  description?: string;
486
485
  tools?: string[];
@@ -603,7 +602,7 @@ interface EventBus {
603
602
  */
604
603
  interface BeforePhaseEvent {
605
604
  type: "before_phase";
606
- /** Phase ID about to execute */
605
+ /** Phase name about to execute */
607
606
  phaseId: string;
608
607
  /** Phase input */
609
608
  input: PhaseContext;
@@ -617,7 +616,7 @@ interface BeforePhaseEvent {
617
616
  */
618
617
  interface AfterPhaseEvent {
619
618
  type: "after_phase";
620
- /** Phase ID that completed */
619
+ /** Phase name that completed */
621
620
  phaseId: string;
622
621
  /** Phase output */
623
622
  output: PhaseOutput;
@@ -629,7 +628,7 @@ interface AfterPhaseEvent {
629
628
  */
630
629
  interface BeforePromptEvent {
631
630
  type: "before_prompt";
632
- /** Current phase ID */
631
+ /** Current phase name */
633
632
  phaseId: string;
634
633
  /** Phase input (modifiable) */
635
634
  input: PhaseContext;
@@ -961,10 +960,10 @@ interface ExtensionContext {
961
960
  }>;
962
961
  /** Get skill content by name */
963
962
  getSkillContent?(skillName: string): string;
964
- /** Get all available phase IDs */
963
+ /** Get all available phase names */
965
964
  getAvailablePhases?(): string[];
966
- /** Get phase content by ID */
967
- getPhaseContent?(phaseId: string): string;
965
+ /** Get phase content by name */
966
+ getPhaseContent?(phaseName: string): string;
968
967
  }
969
968
  /**
970
969
  * Utility functions available to extensions.
@@ -1033,10 +1032,10 @@ interface ExtensionAPI {
1033
1032
  setPayload(payload: unknown): void;
1034
1033
  /** Phase Out: set outcome message */
1035
1034
  setMessage(message: string): void;
1036
- /** Get current phase id */
1035
+ /** Get current phase name */
1037
1036
  getCurrentPhase(): string;
1038
1037
  /** Set next phase (lower priority than PHASE.md target) */
1039
- setNextPhase(phaseId: string): void;
1038
+ setNextPhase(phaseName: string): void;
1040
1039
  /** Get the next phase set by setNextPhase */
1041
1040
  getNextPhase(): string | undefined;
1042
1041
  /** Get the message set by setMessage */
@@ -1055,7 +1054,7 @@ type ExtensionFactory = (api: ExtensionAPI) => void | Promise<void>;
1055
1054
  * Scans for subdirectories containing PHASE.md files.
1056
1055
  * Returns PhaseRegistry with entryPhaseId:
1057
1056
  * - null by default (caller must explicitly set to start from a specific phase)
1058
- * - Set to a specific phase id to start from that phase
1057
+ * - Set to a specific phase name to start from that phase
1059
1058
  *
1060
1059
  * When entryPhaseId is null, Agent normalizes the registry to start from its default phase.
1061
1060
  */
@@ -1212,6 +1211,19 @@ declare const SkillSchema: Type.TObject<{
1212
1211
  }>;
1213
1212
  type Skill = Type.Static<typeof SkillSchema>;
1214
1213
 
1214
+ type SessionHeader = {
1215
+ type: "header";
1216
+ id: string;
1217
+ version: string;
1218
+ createdAt: string;
1219
+ updatedAt: string;
1220
+ systemPrompt: string;
1221
+ input: string;
1222
+ parentSessionId?: string;
1223
+ skills: Skill[];
1224
+ title?: string;
1225
+ currentLeafId?: string | null;
1226
+ };
1215
1227
  type SessionAgentContext<TTool = unknown> = {
1216
1228
  systemPrompt: string;
1217
1229
  messages: AgentMessage[];
@@ -1241,6 +1253,7 @@ type SessionListItem = {
1241
1253
  };
1242
1254
  type SessionManager = {
1243
1255
  getSessionId(): string;
1256
+ getHeader(): Promise<SessionHeader>;
1244
1257
  appendMessage(message: AgentMessage): Promise<string>;
1245
1258
  appendOutcome(outcome: Outcome): Promise<string>;
1246
1259
  appendModelTranscript(transcript: ModelTranscript, meta?: {
@@ -1252,10 +1265,13 @@ type SessionManager = {
1252
1265
  type SessionManagerProvider = {
1253
1266
  create(input: CreateSessionManagerInput): Promise<SessionManager>;
1254
1267
  open(sessionId: string): Promise<SessionManager | undefined>;
1268
+ list(): Promise<SessionListItem[]>;
1269
+ delete(sessionId: string): Promise<boolean>;
1255
1270
  };
1256
1271
 
1257
1272
  type CreateAgentInput = {
1258
1273
  sessionId: string;
1274
+ parentSessionId?: string;
1259
1275
  };
1260
1276
  type EnqueueAgentInput = {
1261
1277
  agentId: AgentId;
@@ -1344,6 +1360,9 @@ interface RuntimeStateStore {
1344
1360
  getAgent(agentId: AgentId): Promise<AgentRecord | undefined>;
1345
1361
  listAgents(): Promise<AgentRecord[]>;
1346
1362
  setAgentState(agentId: AgentId, state: AgentLifecycleState): Promise<AgentRecord>;
1363
+ setAgentLifecycleState(agentId: AgentId, state: SessionLifecycleState): Promise<AgentRecord>;
1364
+ getAgentBySessionId(sessionId: string): Promise<AgentRecord | undefined>;
1365
+ deleteAgentData(agentId: AgentId): Promise<void>;
1347
1366
  enqueueAgentInput(input: EnqueueAgentInput): Promise<EnqueuedAgentInput>;
1348
1367
  getMessage(messageId: RuntimeMessageId): Promise<RuntimeMessage | undefined>;
1349
1368
  getRun(runId: AgentRunId): Promise<AgentRunRecord | undefined>;
@@ -1399,6 +1418,17 @@ type RuntimeEventConsumer = {
1399
1418
  caughtUp: Promise<void>;
1400
1419
  stop(): void;
1401
1420
  };
1421
+ type RuntimeSessionSummary = {
1422
+ id: string;
1423
+ state: SessionLifecycleState;
1424
+ createdAt: string;
1425
+ updatedAt: string;
1426
+ archivedAt?: string;
1427
+ parentSessionId?: string;
1428
+ agentId: AgentId;
1429
+ activeRunCount: number;
1430
+ title?: string;
1431
+ };
1402
1432
  declare class AgentRuntime {
1403
1433
  private readonly stateStore;
1404
1434
  private readonly sessionProvider?;
@@ -1409,6 +1439,7 @@ declare class AgentRuntime {
1409
1439
  private readonly toolRuntime;
1410
1440
  private readonly bindings;
1411
1441
  private readonly agents;
1442
+ private readonly invalidatedAgents;
1412
1443
  private readonly runHandles;
1413
1444
  private readonly runWaiters;
1414
1445
  private readonly pendingRuns;
@@ -1420,6 +1451,7 @@ declare class AgentRuntime {
1420
1451
  private runningRuns;
1421
1452
  private pumping;
1422
1453
  private nextWorkerId;
1454
+ private leaseRecoveryTimer;
1423
1455
  private stopped;
1424
1456
  private constructor();
1425
1457
  static start(options: AgentRuntimeOptions): Promise<AgentRuntime>;
@@ -1435,6 +1467,13 @@ declare class AgentRuntime {
1435
1467
  getRun(runId: AgentRunId): Promise<AgentRunRecord | undefined>;
1436
1468
  listActiveRuns(): Promise<AgentRunRecord[]>;
1437
1469
  listRuns(input?: ListRunsInput): Promise<AgentRunRecord[]>;
1470
+ listSessions(input?: {
1471
+ state?: SessionLifecycleState;
1472
+ }): Promise<RuntimeSessionSummary[]>;
1473
+ archiveSession(sessionId: string): Promise<void>;
1474
+ unarchiveSession(sessionId: string): Promise<void>;
1475
+ deleteSession(sessionId: string): Promise<void>;
1476
+ private requireSessionAgent;
1438
1477
  getAgent(agentId: AgentId): Agent | undefined;
1439
1478
  getMessage(messageId: RuntimeMessageId): Promise<RuntimeMessage | undefined>;
1440
1479
  getToolCall(toolCallId: RuntimeToolCallId): Promise<RuntimeToolCall | undefined>;
@@ -1443,6 +1482,8 @@ declare class AgentRuntime {
1443
1482
  private registerEventConsumer;
1444
1483
  listEvents(cursor?: RuntimeEventCursor): Promise<RuntimeEvent[]>;
1445
1484
  private recover;
1485
+ private startLeaseRecovery;
1486
+ private recoverExpiredLeases;
1446
1487
  private scheduleQueuedRuns;
1447
1488
  private attachAgent;
1448
1489
  private submitAgentInput;
@@ -1534,6 +1575,14 @@ declare class InMemorySessionStore implements SessionManagerProvider {
1534
1575
  private readonly sessions;
1535
1576
  create(input: CreateSessionManagerInput): Promise<SessionManager>;
1536
1577
  open(sessionId: string): Promise<SessionManager | undefined>;
1578
+ list(): Promise<{
1579
+ id: string;
1580
+ title: string | undefined;
1581
+ createdAt: string;
1582
+ updatedAt: string;
1583
+ messageCount: any;
1584
+ }[]>;
1585
+ delete(sessionId: string): Promise<boolean>;
1537
1586
  }
1538
1587
  declare class JsonlSessionStore implements SessionManagerProvider {
1539
1588
  private readonly sessionsDir;
@@ -1541,6 +1590,7 @@ declare class JsonlSessionStore implements SessionManagerProvider {
1541
1590
  create(input: CreateSessionManagerInput): Promise<SessionManager>;
1542
1591
  open(sessionId: string): Promise<SessionManager | undefined>;
1543
1592
  list(): Promise<SessionListItem[]>;
1593
+ delete(sessionId: string): Promise<boolean>;
1544
1594
  }
1545
1595
 
1546
1596
  type CoreToolContext = {
@@ -1560,8 +1610,11 @@ declare class InMemoryRuntimeStateStore implements RuntimeStateStore {
1560
1610
  private readonly eventCheckpoints;
1561
1611
  createAgent(input: CreateAgentInput): Promise<AgentRecord>;
1562
1612
  getAgent(agentId: AgentId): Promise<AgentRecord | undefined>;
1613
+ getAgentBySessionId(sessionId: string): Promise<AgentRecord | undefined>;
1563
1614
  listAgents(): Promise<AgentRecord[]>;
1564
1615
  setAgentState(agentId: AgentId, state: AgentRecord["state"]): Promise<AgentRecord>;
1616
+ setAgentLifecycleState(agentId: AgentId, state: AgentRecord["lifecycleState"]): Promise<AgentRecord>;
1617
+ deleteAgentData(agentId: AgentId): Promise<void>;
1565
1618
  enqueueAgentInput(input: EnqueueAgentInput): Promise<EnqueuedAgentInput>;
1566
1619
  private enqueueAgentInputState;
1567
1620
  getMessage(messageId: RuntimeMessageId): Promise<RuntimeMessage | undefined>;
@@ -1600,8 +1653,11 @@ declare class SqliteRuntimeStateStore implements RuntimeStateStore {
1600
1653
  close(): void;
1601
1654
  createAgent(input: CreateAgentInput): Promise<AgentRecord>;
1602
1655
  getAgent(agentId: AgentId): Promise<AgentRecord | undefined>;
1656
+ getAgentBySessionId(sessionId: string): Promise<AgentRecord | undefined>;
1603
1657
  listAgents(): Promise<AgentRecord[]>;
1604
1658
  setAgentState(agentId: AgentId, state: AgentRecord["state"]): Promise<AgentRecord>;
1659
+ setAgentLifecycleState(agentId: AgentId, state: AgentRecord["lifecycleState"]): Promise<AgentRecord>;
1660
+ deleteAgentData(agentId: AgentId): Promise<void>;
1605
1661
  enqueueAgentInput(input: EnqueueAgentInput): Promise<EnqueuedAgentInput>;
1606
1662
  private enqueueAgentInputState;
1607
1663
  getMessage(messageId: RuntimeMessageId): Promise<RuntimeMessage | undefined>;
@@ -1645,4 +1701,4 @@ declare class SqliteRuntimeStateStore implements RuntimeStateStore {
1645
1701
  private recordEventInternal;
1646
1702
  }
1647
1703
 
1648
- export { type AfterToolCall, Agent, type AgentContext, type AgentId, type AgentInputRequest, type AgentOptions, AgentRun, type AgentRunExecutionState, type AgentRunId, type AgentRunListener, type AgentRunMetadata, type AgentRunRecord, type AgentRunState, AgentRuntime, type AgentRuntimeOptions, type BeforeToolCall, type CoreToolContext, type ExecutionTurn, type ExtensionAPI, type ExtensionFactory, type HookEvent, type HookEventType, type HookHandler, InMemoryRuntimeStateStore, InMemorySessionStore, JsonlSessionStore, type LoadExtensionsResult, type LoadedExtension, type LoopMetrics, type ModelTranscript, type Phase, type PhaseContext, type PhaseExecution, type PhaseInvocation, type PhaseOutput, type PhaseRegistration, type PhaseRegistry, type PhaseState, type RuntimeEvent, type RuntimeEventConsumer, type RuntimeEventCursor, type RuntimeEventDisposition, type RuntimeEventKind, type RuntimeEventListener, type RuntimeMessage, type RuntimeMessageId, type RuntimeToolCall, type RuntimeToolCallId, type SessionManagerProvider, SqliteRuntimeStateStore, type Tool, type ToolContext, type ToolDefinition, type ToolExecutionMode, type ToolExecutionResult, type ToolRuntimePolicy, type Unsubscribe, createCoreTools, createMessage };
1704
+ export { type AfterToolCall, Agent, type AgentContext, type AgentId, type AgentInputRequest, type AgentOptions, AgentRun, type AgentRunExecutionState, type AgentRunId, type AgentRunListener, type AgentRunMetadata, type AgentRunRecord, type AgentRunState, AgentRuntime, type AgentRuntimeOptions, type BeforeToolCall, type CoreToolContext, type ExecutionTurn, type ExtensionAPI, type ExtensionFactory, type HookEvent, type HookEventType, type HookHandler, InMemoryRuntimeStateStore, InMemorySessionStore, JsonlSessionStore, type LoadExtensionsResult, type LoadedExtension, type LoopMetrics, type ModelTranscript, type Phase, type PhaseContext, type PhaseExecution, type PhaseInvocation, type PhaseOutput, type PhaseRegistration, type PhaseRegistry, type PhaseState, type RuntimeEvent, type RuntimeEventConsumer, type RuntimeEventCursor, type RuntimeEventDisposition, type RuntimeEventKind, type RuntimeEventListener, type RuntimeMessage, type RuntimeMessageId, type RuntimeSessionSummary, type RuntimeToolCall, type RuntimeToolCallId, type SessionLifecycleState, type SessionManagerProvider, SqliteRuntimeStateStore, type Tool, type ToolContext, type ToolDefinition, type ToolExecutionMode, type ToolExecutionResult, type ToolRuntimePolicy, type Unsubscribe, createCoreTools, createMessage };