@rowan-agent/agent 0.9.24 → 0.10.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
@@ -9,7 +9,6 @@ identity, not a process-local Session object.
9
9
  ```ts
10
10
  import {
11
11
  AgentRuntime,
12
- createCoreTools,
13
12
  InMemoryStore,
14
13
  loadPhases,
15
14
  loadSkills,
@@ -21,6 +20,21 @@ const runtime = await AgentRuntime.init({
21
20
  store: new InMemoryStore(),
22
21
  });
23
22
 
23
+ await runtime.loadAgents({
24
+ sourceId: "workspace",
25
+ values: [{
26
+ name: "workspace-assistant",
27
+ description: "Assist with the current workspace.",
28
+ prompt: "You are helpful.",
29
+ contexts: ["workspace"],
30
+ }],
31
+ });
32
+ await runtime.loadSkills({ sourceId: "workspace", values: skills });
33
+ await runtime.loadPhases({
34
+ sourceId: "workspace",
35
+ values: [...phases.phases.values()],
36
+ });
37
+
24
38
  const agentId = await runtime.createAgent({
25
39
  identity: "example:v1", // Stable config snapshot identity, not the Agent ID
26
40
  model: {
@@ -30,21 +44,17 @@ const agentId = await runtime.createAgent({
30
44
  baseUrl: "https://api.openai.com/v1",
31
45
  apiKey: process.env.OPENAI_API_KEY!,
32
46
  },
33
- definition: {
34
- name: "workspace-assistant",
35
- description: "Assist with the current workspace.",
36
- prompt: "You are helpful.",
37
- contexts: ["workspace"],
38
- },
39
- resources: {
40
- tools: createCoreTools({ root: process.cwd() }),
41
- skills,
42
- contexts: [{
43
- name: "workspace",
44
- value: { root: process.cwd() },
45
- }],
46
- phases,
47
+ definition: { name: "workspace-assistant" },
48
+ resourceView: {
49
+ agents: ["workspace"],
50
+ tools: [],
51
+ skills: ["workspace"],
52
+ phases: ["workspace"],
47
53
  },
54
+ contexts: [{
55
+ name: "workspace",
56
+ value: { root: process.cwd() },
57
+ }],
48
58
  });
49
59
 
50
60
  const run = await runtime.start(agentId, "Summarize the workspace.", {
@@ -93,8 +103,8 @@ lifecycles, and Owner fencing.
93
103
 
94
104
  ## Tool lifecycle
95
105
 
96
- Tools are supplied as `AgentConfig.resources.tools`, selected by the
97
- Definition, and persist through:
106
+ Tools are registered under a source, selected by the Definition, and persist
107
+ through:
98
108
 
99
109
  `pending → running → completed | failed | indeterminate`
100
110
 
@@ -150,17 +160,13 @@ await runtime.loadAgents({
150
160
  prompt: "You are helpful.",
151
161
  }],
152
162
  });
153
- await runtime.loadTools({
154
- sourceId: "workspace",
155
- values: createCoreTools({ root: process.cwd() }),
156
- });
157
163
 
158
164
  const agentId = await runtime.createAgent({
159
165
  identity: "workspace:v1",
160
166
  definition: { name: "workspace-assistant" },
161
167
  resourceView: {
162
168
  agents: ["workspace"],
163
- tools: ["workspace"],
169
+ tools: [],
164
170
  skills: [],
165
171
  phases: [],
166
172
  },
@@ -176,8 +182,11 @@ const agentId = await runtime.createAgent({
176
182
 
177
183
  Each `load*()` call replaces one source atomically; use `directory` or inline
178
184
  `values`. `resourceView` controls visibility, so same-name resources can live
179
- in isolated sources but collide when selected together. The built-in `route`
180
- Tool and `default` Phase are always available and cannot be overridden.
185
+ in isolated sources but collide when selected together. The Runtime supplies the
186
+ core `read`/`bash`/`edit`/`write`/`route` Tools itself, and its `rowan.core`
187
+ source — like an Extension's `rowan.extensions` — is implicit in every view, so
188
+ a Definition can select a built-in Phase without naming that source. Core names
189
+ cannot be claimed by another source.
181
190
 
182
191
  Extensions are Runtime-global. Load them only during `AgentRuntime.init()` via
183
192
  `bootstrap`; after initialization they are frozen until the Runtime closes.
@@ -185,34 +194,22 @@ Definition name lists narrow the selected Tools, Skills, and Phases: omission
185
194
  inherits all candidates, `[]` selects none, and missing names are skipped. The
186
195
  same rule applies to `definition.contexts`.
187
196
 
188
- ### Resources and Definition
197
+ ### Registration, Definition, and View
189
198
 
190
- `resources` and `definition` have different jobs:
199
+ Registration, selection, and visibility have different jobs:
191
200
 
192
- - `resources` supplies the concrete candidates available to one Agent. Its
193
- Tools contain executable `execute()` functions; Skills and Phases contain
194
- their loaded content; Contexts contain JSON-safe values.
195
- - `definition` declares which candidates this Agent uses. `tools`, `skills`,
201
+ - A **source** supplies resources. Tools carry their executable `execute()`,
202
+ Skills and Phases carry their loaded content, and a Definition carries its
203
+ prompt. Register them with `runtime.loadAgents/loadSkills/loadPhases/loadTools`.
204
+ - The **Definition** declares what one Agent uses. `tools`, `skills`,
196
205
  `contexts`, and `phases` are name-based selectors; they cannot create a
197
- resource that is absent from `resources`.
198
-
199
- For a single-process embedding, provide concrete resources directly and omit
200
- the selectors when the Agent should use everything:
201
-
202
- ```ts
203
- const agentId = await runtime.createAgent({
204
- identity: "workspace:v1",
205
- definition: {
206
- name: "workspace-assistant",
207
- description: "Assist with the current workspace.",
208
- prompt: "You are helpful.",
209
- },
210
- resources: { tools, skills, contexts, phases },
211
- model,
212
- });
213
- ```
206
+ resource that no selected source holds.
207
+ - The **Resource View** decides which sources the Agent can see at all, by
208
+ stable source ID.
214
209
 
215
- Use selectors when several Agents share a candidate pool:
210
+ Contexts are the exception: `contexts` and `additionalContexts` ship with the
211
+ configuration request, because they carry host values rather than registered
212
+ resources. Use selectors when several Agents share a candidate pool:
216
213
 
217
214
  ```ts
218
215
  definition: {
@@ -225,10 +222,6 @@ definition: {
225
222
  }
226
223
  ```
227
224
 
228
- For process-boundary persistence, use the Resource Registry form shown above:
229
- `resourceView` stores stable source IDs instead of executable resource
230
- closures, and the Runtime resolves those sources into an immutable
231
- Configuration Snapshot. This lets a restarted Runtime resolve the same
232
- resource revisions while keeping each Run pinned to the snapshot that created
233
- it. Direct `resources` are simpler for embedding; `resourceView` is the
234
- declarative form for shared, reloadable, and restart-resolvable resources.
225
+ Each Run resolves its view once into an immutable Configuration Snapshot and
226
+ stays pinned to it: replacing a source afterwards cannot change an active or
227
+ input-waiting Run, and a restarted Runtime re-resolves the same source IDs.
package/dist/index.d.ts CHANGED
@@ -1521,10 +1521,9 @@ type ConfigurationSnapshot = Readonly<{
1521
1521
  }>;
1522
1522
  /** Resolve one Definition request into one immutable, source-qualified snapshot. */
1523
1523
  declare function resolveConfigurationSnapshot(registry: ResourceRegistry, input: AgentConfiguration): ConfigurationSnapshot;
1524
- /** Materialize the immutable resolver output at the legacy execution seam.
1525
- * The conversion is intentionally one-way: callers cannot feed concrete
1526
- * candidate bags back through the public configuration request. */
1527
- declare function materializeConfigurationSnapshot(snapshot: ConfigurationSnapshot): AgentConfig;
1524
+ /** Whether one stored configuration is already a resolved snapshot. A snapshot
1525
+ * is used as it stands; a request is resolved against the current sources. */
1526
+ declare function isConfigurationSnapshot(config: AgentConfiguration | ConfigurationSnapshot): config is ConfigurationSnapshot;
1528
1527
 
1529
1528
  type UserInput = string | Readonly<{
1530
1529
  content: UserContent;
@@ -1597,16 +1596,6 @@ type AfterToolCall = (input: Readonly<{
1597
1596
  context: ToolInvocationContext;
1598
1597
  signal: AbortSignal;
1599
1598
  }>) => ToolExecutionResult$1 | Promise<ToolExecutionResult$1>;
1600
- type AgentResources = Readonly<{
1601
- tools: readonly Tool[];
1602
- skills: readonly Skill[];
1603
- phases?: PhaseRegistry;
1604
- contexts?: readonly ContextCandidate[];
1605
- /** Source-qualified snapshot metadata retained for restart/recovery checks. */
1606
- resourceView?: ResourceView;
1607
- resourceRefs?: readonly ResourceRef[];
1608
- resourceRevisions?: Readonly<Record<ResourceKind, readonly string[]>>;
1609
- }>;
1610
1599
  type InvocationSource = "auto" | "implicit" | "external";
1611
1600
  type InvocationCatalogEntry = Readonly<{
1612
1601
  kind: "phase" | "skill";
@@ -1618,25 +1607,6 @@ type InvocationCatalogEntry = Readonly<{
1618
1607
  disableImplicitInvocation: boolean;
1619
1608
  filePath: string;
1620
1609
  }>;
1621
- type AgentConfig = Readonly<{
1622
- identity: string;
1623
- definition: AgentDefinition;
1624
- resources: AgentResources;
1625
- /** Host-owned Contexts rendered in the System Prompt with the selected Contexts. */
1626
- additionalContexts?: readonly ContextCandidate[];
1627
- cwd?: string;
1628
- maxAttempts?: number;
1629
- beforeToolCall?: BeforeToolCall;
1630
- afterToolCall?: AfterToolCall;
1631
- } & ({
1632
- model: ModelConfig;
1633
- stream?: never;
1634
- } | {
1635
- model: ModelRef;
1636
- stream: StreamFn;
1637
- })>;
1638
- /** Definition-reference request accepted at the public Runtime seam. */
1639
- type AgentConfigRequest = AgentConfig | AgentConfiguration;
1640
1610
  type AgentRecord = Readonly<{
1641
1611
  id: AgentId;
1642
1612
  metadata?: Metadata;
@@ -1816,7 +1786,7 @@ type RunBoundary = Readonly<{
1816
1786
  }>;
1817
1787
  type ConfigResolution = Readonly<{
1818
1788
  kind: "available";
1819
- config: AgentConfigRequest;
1789
+ config: AgentConfiguration | ConfigurationSnapshot;
1820
1790
  } | {
1821
1791
  kind: "deferred";
1822
1792
  retryAfterMs?: number;
@@ -1834,7 +1804,7 @@ interface ConfigProvider {
1834
1804
  put(input: {
1835
1805
  agentId: AgentId;
1836
1806
  agentMetadata?: Metadata;
1837
- config: AgentConfigRequest;
1807
+ config: AgentConfiguration | ConfigurationSnapshot;
1838
1808
  operationId: string;
1839
1809
  signal: AbortSignal;
1840
1810
  }): Promise<ConfigPutResult>;
@@ -2031,12 +2001,12 @@ interface AgentRuntime$1 {
2031
2001
  kind: ResourceKind;
2032
2002
  sourceId: string;
2033
2003
  }>): Promise<LoadResult>;
2034
- createAgent(config: AgentConfigRequest, options?: {
2004
+ createAgent(config: AgentConfiguration, options?: {
2035
2005
  idempotencyKey?: string;
2036
2006
  metadata?: Metadata;
2037
2007
  historySeed?: HistorySeed;
2038
2008
  }): Promise<AgentId>;
2039
- updateAgentConfig(agentId: AgentId, config: AgentConfigRequest, options: {
2009
+ updateAgentConfig(agentId: AgentId, config: AgentConfiguration, options: {
2040
2010
  idempotencyKey: string;
2041
2011
  }): Promise<void>;
2042
2012
  deleteAgent(input: AgentDeletionRequest): Promise<void>;
@@ -2122,12 +2092,12 @@ declare class AgentRuntime implements AgentRuntime$1 {
2122
2092
  kind: ResourceKind;
2123
2093
  sourceId: string;
2124
2094
  }>): Promise<LoadResult>;
2125
- createAgent(config: AgentConfigRequest, options?: {
2095
+ createAgent(config: AgentConfiguration, options?: {
2126
2096
  idempotencyKey?: string;
2127
2097
  metadata?: Metadata;
2128
2098
  historySeed?: HistorySeed;
2129
2099
  }): Promise<AgentId>;
2130
- updateAgentConfig(agentId: AgentId, config: AgentConfigRequest, options: {
2100
+ updateAgentConfig(agentId: AgentId, config: AgentConfiguration, options: {
2131
2101
  idempotencyKey: string;
2132
2102
  }): Promise<void>;
2133
2103
  deleteAgent(input: AgentDeletionRequest): Promise<void>;
@@ -2211,7 +2181,9 @@ declare class AgentRuntime implements AgentRuntime$1 {
2211
2181
  signal?: AbortSignal;
2212
2182
  }): Promise<RunBoundary>;
2213
2183
  private assertOpen;
2214
- private materializeConfig;
2184
+ /** Resolve one stored configuration to the snapshot this execution uses. A
2185
+ * stored snapshot is already source-qualified and is used as it stands. */
2186
+ private resolveConfig;
2215
2187
  private startHeartbeat;
2216
2188
  }
2217
2189
 
@@ -2627,7 +2599,7 @@ declare class InMemoryConfigProvider implements ConfigProvider {
2627
2599
  put(input: {
2628
2600
  agentId: AgentId;
2629
2601
  agentMetadata?: Metadata;
2630
- config: AgentConfigRequest;
2602
+ config: AgentConfiguration | ConfigurationSnapshot;
2631
2603
  operationId: string;
2632
2604
  signal: AbortSignal;
2633
2605
  }): Promise<ConfigPutResult>;
@@ -2810,4 +2782,4 @@ declare function parseFrontmatter<T = Record<string, unknown>>(raw: string): Fro
2810
2782
 
2811
2783
  declare function createCoreTools(input?: CoreToolContext): Tool[];
2812
2784
 
2813
- export { type AfterToolCall, type AgentConfig, type AgentConfigRequest, type AgentConfiguration, type AgentDefinition, type AgentId, type AgentListCursor, type AgentRecord, type AgentResources, type AgentRun, AgentRuntime, type AgentRuntimeOptions, type AgentSummary, type AnyRuntimeError, type AssistantContent, type AssistantMessage, type BeforeToolCall, COMPACT_PHASE_ID, type ConfigProvider, type ConfigPutResult, type ConfigResolution, type ConfigToken, type ConfigurationSnapshot, type ContextCandidate, type ContextCompactionRecord, type ContextStatus, type CoreToolContext, DEFAULT_PHASE_ID, type DefinitionLayer, type DurableConsumer, type DurableRunEvent, type DurableStore, type DurableToolResult, type EventCursor, type EventId, type ExecutionCheckpoint, type ExecutionId, type ExecutionToken, type ExtensionAPI, type ExtensionActivationError, type ExtensionActivationResult, type ExtensionContribution, type ExtensionDisposer, type ExtensionFactory, type ExtensionFactoryResult, ExtensionLifetimeError, type ExtensionLifetimeErrorCode, type ExtensionLoadInput, type FrontmatterResult, type HistorySeed, type HookEvent, type HookEventType, type HookHandler, InMemoryConfigProvider, InMemoryStore, type InputRequest, type InputRequestId, type InputRequiredCommit, type InvocationCatalogEntry, type InvocationSource, type JsonObject, type JsonPrimitive, type JsonValue, type LoadExtensionsResult, type LoadInput, type LoadResult, type LoadedExtension, type Message, type MessageBase, type MessageCommitted, type MessageContent, type MessageDelta, type MessageId, type MessageRevised, type MessageRevisionResult, type Metadata, type OpaqueId, type Outcome, type OwnerLease, type OwnerToken, type Page, type Phase, type PhaseContext, type PhaseContribution, type PhaseExecution, type PhaseExecutionIdentity, type PhaseInput, type PhaseInteraction, PhaseInteractionBoundary, PhaseInteractionCancelledError, type PhaseInteractionDriver, type PhaseInteractionKind, type PhaseInteractionState, type PhaseInteractionStatus, type PhaseInvocation, type PhaseMessageManager, type PhaseOutput, type PhaseRegistry, type PhaseRegistrySelection, type PhaseSettingsBadge, type PhaseSettingsContext, type PhaseSettingsControl, type PhaseSettingsDefinition, type PhaseSettingsItem, type PhaseSettingsOption, type PhaseSettingsProvider, type PhaseSettingsSection, type PhaseState, type PhaseStatus, type PhaseStatusState, type ResolvedResourceView, type ResourceDiagnostic, type ResourceKind, type ResourceRef, ResourceRegistry, ResourceRegistryError, type ResourceRegistryErrorCode, type ResourceSourceId, type ResourceView, type RetentionResult, type RunBoundary, type RunClaim, type RunEvent, type RunFailure, type RunId, type RunListCursor, type RunRecord, type RunSnapshot, type RunState, type RunStateChanged, type RunSummary, RuntimeBootstrapRegistry, RuntimeError, type RuntimeErrorCode, type RuntimeErrorDetails, RuntimeExtensionLifetime, STOP_PHASE_ID, type Skill, SqliteStore, type TextContent, type ThinkingContent, type ThinkingDelta, type Tool, type ToolCallId, type ToolCallSnapshot, type ToolCallState, type ToolContribution, type ToolDefinition, type ToolExecutionResult$1 as ToolExecutionResult, type ToolInvocationContext, type ToolMessage, type ToolMessageContent, type ToolProgress, type ToolResultContent, type ToolStateChanged, type ToolUseContent, type UserContent, type UserInput, type UserMessage, brandConfigToken, createCompactPhase, createCorePhases, createCoreTools, createDefaultPhase, createStopPhase, isRuntimeError, loadExtensionsFromPath as loadExtensions, loadPhase, loadPhaseSettings, loadPhases, loadSkill, loadSkills, materializeConfigurationSnapshot, parseAgentDefinition, parseFrontmatter, resolveConfigurationSnapshot };
2785
+ export { type AfterToolCall, type AgentConfiguration, type AgentDefinition, type AgentId, type AgentListCursor, type AgentRecord, type AgentRun, AgentRuntime, type AgentRuntimeOptions, type AgentSummary, type AnyRuntimeError, type AssistantContent, type AssistantMessage, type BeforeToolCall, COMPACT_PHASE_ID, type ConfigProvider, type ConfigPutResult, type ConfigResolution, type ConfigToken, type ConfigurationSnapshot, type ContextCandidate, type ContextCompactionRecord, type ContextStatus, type CoreToolContext, DEFAULT_PHASE_ID, type DefinitionLayer, type DurableConsumer, type DurableRunEvent, type DurableStore, type DurableToolResult, type EventCursor, type EventId, type ExecutionCheckpoint, type ExecutionId, type ExecutionToken, type ExtensionAPI, type ExtensionActivationError, type ExtensionActivationResult, type ExtensionContribution, type ExtensionDisposer, type ExtensionFactory, type ExtensionFactoryResult, ExtensionLifetimeError, type ExtensionLifetimeErrorCode, type ExtensionLoadInput, type FrontmatterResult, type HistorySeed, type HookEvent, type HookEventType, type HookHandler, InMemoryConfigProvider, InMemoryStore, type InputRequest, type InputRequestId, type InputRequiredCommit, type InvocationCatalogEntry, type InvocationSource, type JsonObject, type JsonPrimitive, type JsonValue, type LoadExtensionsResult, type LoadInput, type LoadResult, type LoadedExtension, type Message, type MessageBase, type MessageCommitted, type MessageContent, type MessageDelta, type MessageId, type MessageRevised, type MessageRevisionResult, type Metadata, type OpaqueId, type Outcome, type OwnerLease, type OwnerToken, type Page, type Phase, type PhaseContext, type PhaseContribution, type PhaseExecution, type PhaseExecutionIdentity, type PhaseInput, type PhaseInteraction, PhaseInteractionBoundary, PhaseInteractionCancelledError, type PhaseInteractionDriver, type PhaseInteractionKind, type PhaseInteractionState, type PhaseInteractionStatus, type PhaseInvocation, type PhaseMessageManager, type PhaseOutput, type PhaseRegistry, type PhaseRegistrySelection, type PhaseSettingsBadge, type PhaseSettingsContext, type PhaseSettingsControl, type PhaseSettingsDefinition, type PhaseSettingsItem, type PhaseSettingsOption, type PhaseSettingsProvider, type PhaseSettingsSection, type PhaseState, type PhaseStatus, type PhaseStatusState, type ResolvedResourceView, type ResourceDiagnostic, type ResourceKind, type ResourceRef, ResourceRegistry, ResourceRegistryError, type ResourceRegistryErrorCode, type ResourceSourceId, type ResourceView, type RetentionResult, type RunBoundary, type RunClaim, type RunEvent, type RunFailure, type RunId, type RunListCursor, type RunRecord, type RunSnapshot, type RunState, type RunStateChanged, type RunSummary, RuntimeBootstrapRegistry, RuntimeError, type RuntimeErrorCode, type RuntimeErrorDetails, RuntimeExtensionLifetime, STOP_PHASE_ID, type Skill, SqliteStore, type TextContent, type ThinkingContent, type ThinkingDelta, type Tool, type ToolCallId, type ToolCallSnapshot, type ToolCallState, type ToolContribution, type ToolDefinition, type ToolExecutionResult$1 as ToolExecutionResult, type ToolInvocationContext, type ToolMessage, type ToolMessageContent, type ToolProgress, type ToolResultContent, type ToolStateChanged, type ToolUseContent, type UserContent, type UserInput, type UserMessage, brandConfigToken, createCompactPhase, createCorePhases, createCoreTools, createDefaultPhase, createStopPhase, isConfigurationSnapshot, isRuntimeError, loadExtensionsFromPath as loadExtensions, loadPhase, loadPhaseSettings, loadPhases, loadSkill, loadSkills, parseAgentDefinition, parseFrontmatter, resolveConfigurationSnapshot };
package/dist/index.js CHANGED
@@ -3463,9 +3463,6 @@ function thinkingLevelFromMessages(messages) {
3463
3463
  }
3464
3464
  return void 0;
3465
3465
  }
3466
- function isAgentConfiguration(config) {
3467
- return !("resources" in config);
3468
- }
3469
3466
  var METADATA_LIMIT = 64 * 1024;
3470
3467
  var IDENTITY_LIMIT = 256;
3471
3468
  function isRecord3(value) {
@@ -3521,35 +3518,7 @@ function isToolResult(value) {
3521
3518
  if (JSON.stringify(Object.keys(value).sort()) !== JSON.stringify(expected)) return false;
3522
3519
  return value.ok || typeof value.error === "string";
3523
3520
  }
3524
- function assertAgentConfig(config) {
3525
- if (typeof config.identity !== "string" || config.identity.length === 0) throw new TypeError("config.identity must be non-empty");
3526
- assertUtf8ByteLimit(config.identity, IDENTITY_LIMIT, "config.identity");
3527
- assertAgentDefinition(config.definition);
3528
- if (!config.resources || !Array.isArray(config.resources.tools) || !Array.isArray(config.resources.skills)) {
3529
- throw new TypeError("config.resources is invalid");
3530
- }
3531
- for (const tool of config.resources.tools) projectToolDefinition(tool);
3532
- const names = /* @__PURE__ */ new Set();
3533
- for (const context of config.resources.contexts ?? []) {
3534
- if (typeof context.name !== "string" || context.name.trim() === "") {
3535
- throw new TypeError("Context candidate name must be non-empty");
3536
- }
3537
- if (names.has(context.name)) throw new TypeError(`Duplicate Context candidate "${context.name}".`);
3538
- names.add(context.name);
3539
- assertJsonValue(context.value, `Context candidate "${context.name}" value`);
3540
- }
3541
- for (const context of config.additionalContexts ?? []) {
3542
- if (typeof context.name !== "string" || context.name.trim() === "") {
3543
- throw new TypeError("Additional Context candidate name must be non-empty");
3544
- }
3545
- assertJsonValue(context.value, `Additional Context candidate "${context.name}" value`);
3546
- }
3547
- }
3548
- function assertAgentConfigRequest(config) {
3549
- if (!isAgentConfiguration(config)) {
3550
- assertAgentConfig(config);
3551
- return;
3552
- }
3521
+ function assertAgentConfiguration(config) {
3553
3522
  if (typeof config.identity !== "string" || config.identity.length === 0) throw new TypeError("config.identity must be non-empty");
3554
3523
  assertUtf8ByteLimit(config.identity, IDENTITY_LIMIT, "config.identity");
3555
3524
  if (!config.definition || typeof config.definition.name !== "string" || config.definition.name.trim() === "") {
@@ -3579,11 +3548,110 @@ function assertAgentConfigRequest(config) {
3579
3548
  function assertToolExecutionResult(value) {
3580
3549
  if (!isToolResult(value)) throw new TypeError("Tool result must be JSON-safe and contain no Runtime identity");
3581
3550
  }
3582
- function projectToolDefinition(tool) {
3583
- if (typeof tool.name !== "string" || tool.name.length === 0 || typeof tool.description !== "string") throw new TypeError("Tool definition is invalid");
3584
- assertJsonValue(tool.parameters, "tool.parameters");
3585
- if (!isRecord3(tool.parameters)) throw new TypeError("tool.parameters must be a JSON object");
3586
- return { name: tool.name, description: tool.description, parameters: JSON.parse(canonicalJson(tool.parameters)) };
3551
+
3552
+ // src/runtime/configuration-snapshot.ts
3553
+ function resolveConfigurationSnapshot(registry, input) {
3554
+ validateMaxAttempts(input.maxAttempts);
3555
+ const resolved = registry.resolveView(input.resourceView);
3556
+ const base = resolved.agents.find(({ name }) => name === input.definition.name);
3557
+ if (!base) {
3558
+ throw new Error(`Agent Definition "${input.definition.name}" is not available in the Resource View.`);
3559
+ }
3560
+ const layer = input.definition.layer;
3561
+ const selectedContexts = selectNamedResources(input.contexts ?? [], base.contexts, "Context");
3562
+ const additionalContexts = deduplicateContexts(input.additionalContexts ?? [], selectedContexts);
3563
+ const definition = applyDefinitionLayer(base, layer);
3564
+ const tools = selectNamedResources(resolved.tools, definition.tools, "Tool");
3565
+ const skills = mergeSkills(
3566
+ selectNamedResources(resolved.skills, definition.skills, "Skill"),
3567
+ definition.bundledSkills
3568
+ );
3569
+ const phases = resolvePhases(resolved.phases, definition.phases);
3570
+ return {
3571
+ identity: input.identity,
3572
+ definition,
3573
+ resources: {
3574
+ tools,
3575
+ skills,
3576
+ ...phases ? { phases } : {},
3577
+ revisions: resolved.revisions,
3578
+ refs: {
3579
+ agent: selectedRefs(resolved.refs.agent, [base.name]),
3580
+ tool: selectedRefs(resolved.refs.tool, tools.map(({ name }) => name)),
3581
+ skill: selectedRefs(resolved.refs.skill, skills.map(({ name }) => name)),
3582
+ phase: selectedRefs(resolved.refs.phase, [...phases?.phases.keys() ?? []])
3583
+ }
3584
+ },
3585
+ contexts: selectedContexts,
3586
+ additionalContexts,
3587
+ resourceView: input.resourceView,
3588
+ ...input.cwd === void 0 ? {} : { cwd: input.cwd },
3589
+ ...input.maxAttempts === void 0 ? {} : { maxAttempts: input.maxAttempts },
3590
+ ..."stream" in input && input.stream ? { model: layer?.model ?? input.model, stream: input.stream } : { model: layer?.model ?? input.model }
3591
+ };
3592
+ }
3593
+ function isConfigurationSnapshot(config) {
3594
+ return "resources" in config;
3595
+ }
3596
+ function applyDefinitionLayer(base, layer) {
3597
+ if (!layer) return { ...base };
3598
+ return {
3599
+ ...base,
3600
+ ...layer.description === void 0 ? {} : { description: layer.description },
3601
+ ...layer.prompt === void 0 ? {} : { prompt: layer.prompt },
3602
+ ...layer.model === void 0 ? {} : { model: layer.model },
3603
+ ...layer.tools === void 0 ? {} : { tools: intersectNames(base.tools, layer.tools, "Tool") },
3604
+ ...layer.skills === void 0 ? {} : { skills: intersectNames(base.skills, layer.skills, "Skill") },
3605
+ ...layer.phases === void 0 ? {} : { phases: intersectPhaseSelection(base.phases, layer.phases) }
3606
+ };
3607
+ }
3608
+ function deduplicateContexts(additional, existing = []) {
3609
+ const contexts = [];
3610
+ const seen = new Set(existing.map(({ name }) => name));
3611
+ for (const context of additional) {
3612
+ if (seen.has(context.name)) continue;
3613
+ seen.add(context.name);
3614
+ contexts.push(context);
3615
+ }
3616
+ return contexts;
3617
+ }
3618
+ function intersectNames(parent, layer, kind) {
3619
+ if (parent === void 0) return [...layer];
3620
+ const parentNames = new Set(parent);
3621
+ for (const name of layer) {
3622
+ if (!parentNames.has(name)) console.warn(`${kind} "${name}" is not available and will be skipped.`);
3623
+ }
3624
+ return layer.filter((name) => parentNames.has(name));
3625
+ }
3626
+ function intersectPhaseSelection(parent, layer) {
3627
+ if (!parent) return layer;
3628
+ const parentNames = new Set(parent.phaseIds);
3629
+ for (const name of layer.phaseIds) {
3630
+ if (!parentNames.has(name)) console.warn(`Phase "${name}" is not available and will be skipped.`);
3631
+ }
3632
+ return {
3633
+ entryPhaseId: layer.entryPhaseId,
3634
+ phaseIds: layer.phaseIds.filter((name) => parentNames.has(name))
3635
+ };
3636
+ }
3637
+ function resolvePhases(candidates, selection) {
3638
+ const coreNames = /* @__PURE__ */ new Set([DEFAULT_PHASE_ID, STOP_PHASE_ID, COMPACT_PHASE_ID]);
3639
+ const core = candidates.filter((phase) => phase.core || coreNames.has(phase.name));
3640
+ const authored = candidates.filter((phase) => !coreNames.has(phase.name) && !phase.core);
3641
+ const selected = [...core, ...selectNamedResources(authored, selection?.phaseIds, "Phase")];
3642
+ const entryPhaseId = selection?.entryPhaseId ?? null;
3643
+ if (entryPhaseId !== null && entryPhaseId !== DEFAULT_PHASE_ID && !selected.some(({ name }) => name === entryPhaseId)) {
3644
+ console.warn(`Phase entry "${entryPhaseId}" is not available and will be skipped.`);
3645
+ return { phases: new Map(selected.map((phase) => [phase.name, phase])), entryPhaseId: null };
3646
+ }
3647
+ return {
3648
+ phases: new Map(selected.map((phase) => [phase.name, phase])),
3649
+ entryPhaseId
3650
+ };
3651
+ }
3652
+ function selectedRefs(refs, names) {
3653
+ const selected = new Set(names);
3654
+ return refs.filter(({ name }) => selected.has(name));
3587
3655
  }
3588
3656
 
3589
3657
  // src/runtime/idempotency.ts
@@ -3669,58 +3737,54 @@ function validateConfigResolution(agentId, value) {
3669
3737
  }
3670
3738
  function snapshotConfig(config) {
3671
3739
  validateMaxAttempts(config.maxAttempts);
3672
- if (isAgentConfiguration(config)) return snapshotConfiguration(config);
3740
+ return isConfigurationSnapshot(config) ? snapshotConfigurationSnapshot(config) : snapshotConfiguration(config);
3741
+ }
3742
+ function snapshotConfigurationSnapshot(snapshot) {
3673
3743
  const definition = Object.freeze({
3674
- ...config.definition,
3675
- ...config.definition.tools ? { tools: Object.freeze([...config.definition.tools]) } : {},
3676
- ...config.definition.skills ? { skills: Object.freeze([...config.definition.skills]) } : {},
3677
- ...config.definition.bundledSkills ? {
3678
- bundledSkills: Object.freeze(config.definition.bundledSkills.map((skill) => Object.freeze({ ...skill })))
3744
+ ...snapshot.definition,
3745
+ ...snapshot.definition.tools ? { tools: Object.freeze([...snapshot.definition.tools]) } : {},
3746
+ ...snapshot.definition.skills ? { skills: Object.freeze([...snapshot.definition.skills]) } : {},
3747
+ ...snapshot.definition.bundledSkills ? {
3748
+ bundledSkills: Object.freeze(snapshot.definition.bundledSkills.map((skill) => Object.freeze({ ...skill })))
3679
3749
  } : {},
3680
- ...config.definition.phases ? {
3750
+ ...snapshot.definition.phases ? {
3681
3751
  phases: Object.freeze({
3682
- entryPhaseId: config.definition.phases.entryPhaseId,
3683
- phaseIds: Object.freeze([...config.definition.phases.phaseIds])
3752
+ entryPhaseId: snapshot.definition.phases.entryPhaseId,
3753
+ phaseIds: Object.freeze([...snapshot.definition.phases.phaseIds])
3684
3754
  })
3685
3755
  } : {},
3686
- ...config.definition.contexts ? { contexts: Object.freeze([...config.definition.contexts]) } : {}
3756
+ ...snapshot.definition.contexts ? { contexts: Object.freeze([...snapshot.definition.contexts]) } : {}
3687
3757
  });
3688
3758
  const resources = Object.freeze({
3689
- ...config.resources,
3690
- tools: Object.freeze([...config.resources.tools]),
3691
- skills: Object.freeze([...config.resources.skills]),
3692
- ...config.resources.phases ? { phases: snapshotPhaseRegistry(config.resources.phases) } : {},
3693
- ...config.resources.resourceView ? {
3694
- resourceView: Object.freeze({
3695
- agents: Object.freeze([...config.resources.resourceView.agents]),
3696
- tools: Object.freeze([...config.resources.resourceView.tools]),
3697
- skills: Object.freeze([...config.resources.resourceView.skills]),
3698
- phases: Object.freeze([...config.resources.resourceView.phases])
3699
- })
3700
- } : {},
3701
- ...config.resources.resourceRefs ? { resourceRefs: Object.freeze(config.resources.resourceRefs.map((ref) => Object.freeze({ ...ref }))) } : {},
3702
- ...config.resources.resourceRevisions ? {
3703
- resourceRevisions: Object.freeze(Object.fromEntries(
3704
- Object.entries(config.resources.resourceRevisions).map(([kind, revisions]) => [kind, Object.freeze([...revisions])])
3705
- ))
3706
- } : {},
3707
- ...config.resources.contexts ? {
3708
- contexts: Object.freeze(config.resources.contexts.map((context) => Object.freeze({
3709
- name: context.name,
3710
- value: snapshotJsonValue(context.value)
3711
- })))
3712
- } : {}
3759
+ ...snapshot.resources,
3760
+ tools: Object.freeze([...snapshot.resources.tools]),
3761
+ skills: Object.freeze([...snapshot.resources.skills]),
3762
+ ...snapshot.resources.phases ? { phases: snapshotPhaseRegistry(snapshot.resources.phases) } : {},
3763
+ revisions: Object.freeze(Object.fromEntries(
3764
+ Object.entries(snapshot.resources.revisions).map(([kind, revisions]) => [kind, Object.freeze([...revisions])])
3765
+ )),
3766
+ refs: Object.freeze(Object.fromEntries(
3767
+ Object.entries(snapshot.resources.refs).map(([kind, refs]) => [kind, Object.freeze(refs.map((ref) => Object.freeze({ ...ref })))])
3768
+ ))
3713
3769
  });
3714
3770
  return Object.freeze({
3715
- ...config,
3771
+ ...snapshot,
3716
3772
  definition,
3717
3773
  resources,
3718
- ...config.additionalContexts ? {
3719
- additionalContexts: Object.freeze(config.additionalContexts.map((context) => Object.freeze({
3720
- name: context.name,
3721
- value: snapshotJsonValue(context.value)
3722
- })))
3723
- } : {}
3774
+ contexts: Object.freeze(snapshot.contexts.map((context) => Object.freeze({
3775
+ name: context.name,
3776
+ value: snapshotJsonValue(context.value)
3777
+ }))),
3778
+ additionalContexts: Object.freeze(snapshot.additionalContexts.map((context) => Object.freeze({
3779
+ name: context.name,
3780
+ value: snapshotJsonValue(context.value)
3781
+ }))),
3782
+ resourceView: Object.freeze({
3783
+ agents: Object.freeze([...snapshot.resourceView.agents]),
3784
+ tools: Object.freeze([...snapshot.resourceView.tools]),
3785
+ skills: Object.freeze([...snapshot.resourceView.skills]),
3786
+ phases: Object.freeze([...snapshot.resourceView.phases])
3787
+ })
3724
3788
  });
3725
3789
  }
3726
3790
  function snapshotPhaseRegistry(registry) {
@@ -3833,7 +3897,7 @@ var ConfigCommandService = class {
3833
3897
  configs;
3834
3898
  storeIncarnation;
3835
3899
  async createAgent(input) {
3836
- assertAgentConfigRequest(input.config);
3900
+ assertAgentConfiguration(input.config);
3837
3901
  assertIdentity(input.config.identity);
3838
3902
  const reserved = await this.store.reserveAgent({
3839
3903
  idempotencyKey: input.idempotencyKey,
@@ -3856,7 +3920,7 @@ var ConfigCommandService = class {
3856
3920
  return reserved.id;
3857
3921
  }
3858
3922
  async updateAgentConfig(input) {
3859
- assertAgentConfigRequest(input.config);
3923
+ assertAgentConfiguration(input.config);
3860
3924
  assertIdentity(input.config.identity);
3861
3925
  const agent = await this.findAgent(input.agentId);
3862
3926
  const operationId = this.operationId("update_agent_config", input.agentId, input.idempotencyKey);
@@ -3887,7 +3951,7 @@ var ConfigCommandService = class {
3887
3951
  * The durable Run pins this token at claim time, so later Source replacement
3888
3952
  * cannot mutate an active or input-waiting Run. */
3889
3953
  async storeSnapshot(input) {
3890
- assertAgentConfigRequest(input.config);
3954
+ assertAgentConfiguration(input.config);
3891
3955
  const result = await this.put({
3892
3956
  agentId: input.agent.id,
3893
3957
  agentMetadata: input.agent.metadata,
@@ -4140,26 +4204,17 @@ function jsonText(value) {
4140
4204
  }
4141
4205
 
4142
4206
  // src/runtime/extensions.ts
4143
- function assembleRegisteredExtensions(config, runner, options = {}) {
4144
- const extensionTools = runner.getAllRegisteredTools().map(adaptExtensionTool);
4207
+ function assembleRegisteredExtensions(snapshot, runner, options = {}) {
4145
4208
  const coreTools = createRuntimeCoreTools({
4146
- root: config.cwd,
4209
+ root: snapshot.cwd,
4147
4210
  ...options.toolArchiveDir ? { archiveDir: options.toolArchiveDir } : {}
4148
4211
  });
4149
4212
  const coreNames = new Set(coreTools.map((tool) => tool.name));
4150
4213
  const tools = [
4151
- ...config.resources.tools.filter((tool) => !coreNames.has(tool.name)),
4214
+ ...snapshot.resources.tools.filter((tool) => !coreNames.has(tool.name)),
4152
4215
  ...coreTools
4153
4216
  ];
4154
- const names = new Set(tools.map((tool) => tool.name));
4155
- for (const tool of extensionTools) {
4156
- if (names.has(tool.name)) throw new TypeError(`Extension Tool collides with Context Tool "${tool.name}"`);
4157
- names.add(tool.name);
4158
- tools.push(tool);
4159
- }
4160
- const extensionPhases = runner.createPhaseRegistry({ entryPhaseId: null });
4161
- const phases = mergePhases(config.resources.phases, extensionPhases);
4162
- const context = resolveDefinitionContext(config, { tools, phases });
4217
+ const context = resolveDefinitionContext(snapshot, tools);
4163
4218
  return {
4164
4219
  context,
4165
4220
  beforePhase: (phaseId, input) => runner.emitBeforePhase(phaseId, input),
@@ -4180,83 +4235,41 @@ function assembleRegisteredExtensions(config, runner, options = {}) {
4180
4235
  }
4181
4236
  };
4182
4237
  }
4183
- function resolveDefinitionContext(config, assembled = {}) {
4184
- const candidateTools = assembled.tools ?? config.resources.tools;
4185
- const coreTools = candidateTools.filter((tool) => tool.core);
4186
- const authoredTools = candidateTools.filter((tool) => !tool.core);
4238
+ function resolveDefinitionContext(snapshot, assembled) {
4239
+ const coreTools = assembled.filter((tool) => tool.core);
4240
+ const authoredTools = assembled.filter((tool) => !tool.core);
4187
4241
  const tools = [
4188
- ...selectNamedResources(authoredTools, config.definition.tools, "Tool"),
4242
+ ...selectNamedResources(authoredTools, snapshot.definition.tools, "Tool"),
4189
4243
  ...coreTools
4190
4244
  ];
4191
4245
  const skills = mergeSkills(
4192
- selectNamedResources(config.resources.skills, config.definition.skills, "Skill"),
4193
- config.definition.bundledSkills
4246
+ selectNamedResources(snapshot.resources.skills, snapshot.definition.skills, "Skill"),
4247
+ snapshot.definition.bundledSkills
4194
4248
  );
4195
4249
  const contexts = [
4196
- ...selectNamedResources(
4197
- config.resources.contexts ?? [],
4198
- config.definition.contexts,
4199
- "Context"
4200
- ),
4201
- ...config.additionalContexts ?? []
4250
+ ...selectNamedResources(snapshot.contexts, snapshot.definition.contexts, "Context"),
4251
+ ...snapshot.additionalContexts
4202
4252
  ];
4203
- const candidateRegistry = assembled.phases ?? config.resources.phases;
4204
- const phaseCandidates = [...candidateRegistry?.phases.values() ?? []];
4253
+ const phaseCandidates = [...snapshot.resources.phases?.phases.values() ?? []];
4205
4254
  const coreNames = /* @__PURE__ */ new Set([DEFAULT_PHASE_ID, STOP_PHASE_ID, COMPACT_PHASE_ID]);
4206
4255
  const selectedPhases = [
4207
4256
  ...phaseCandidates.filter((phase) => phase.core || coreNames.has(phase.name)),
4208
4257
  ...selectNamedResources(
4209
4258
  phaseCandidates.filter((phase) => !phase.core && !coreNames.has(phase.name)),
4210
- config.definition.phases?.phaseIds,
4259
+ snapshot.definition.phases?.phaseIds,
4211
4260
  "Phase"
4212
4261
  )
4213
4262
  ];
4214
4263
  const phases = new Map(selectedPhases.map((phase) => [phase.name, phase]));
4215
- const requestedEntry = config.definition.phases ? config.definition.phases.entryPhaseId : candidateRegistry?.entryPhaseId ?? null;
4264
+ const requestedEntry = snapshot.definition.phases ? snapshot.definition.phases.entryPhaseId : snapshot.resources.phases?.entryPhaseId ?? null;
4216
4265
  const entryPhaseId = requestedEntry === DEFAULT_PHASE_ID ? DEFAULT_PHASE_ID : requestedEntry && phases.has(requestedEntry) ? requestedEntry : null;
4217
- if (requestedEntry && requestedEntry !== DEFAULT_PHASE_ID && !phases.has(requestedEntry)) {
4218
- console.warn(`Phase entry "${requestedEntry}" is not available; Rowan will use "default".`);
4219
- }
4220
4266
  return {
4221
- systemPrompt: [config.definition.prompt, buildContextDescription(contexts)].filter((section) => section.length > 0).join("\n\n"),
4267
+ systemPrompt: [snapshot.definition.prompt, buildContextDescription(contexts)].filter((section) => section.length > 0).join("\n\n"),
4222
4268
  tools,
4223
4269
  skills,
4224
4270
  phases: { phases, entryPhaseId }
4225
4271
  };
4226
4272
  }
4227
- function mergePhases(base, extension) {
4228
- const core = createCorePhases();
4229
- const coreNames = new Set(core.map(({ name }) => name));
4230
- const phases = new Map(core.map((phase) => [phase.name, phase]));
4231
- for (const [name, phase] of base?.phases ?? []) {
4232
- if (coreNames.has(name)) {
4233
- if (!phase.core) throw new TypeError(`Configured Phase collides with Rowan built-in Phase "${name}".`);
4234
- continue;
4235
- }
4236
- phases.set(name, phase);
4237
- }
4238
- for (const [name, phase] of extension.phases) {
4239
- if (phases.has(name)) throw new TypeError(`Extension Phase collides with Context Phase "${name}"`);
4240
- phases.set(name, phase);
4241
- }
4242
- return {
4243
- phases,
4244
- entryPhaseId: base?.entryPhaseId ?? extension.entryPhaseId ?? DEFAULT_PHASE_ID
4245
- };
4246
- }
4247
- function adaptExtensionTool(input) {
4248
- const definition = input.definition;
4249
- return {
4250
- name: definition.name,
4251
- description: definition.description,
4252
- parameters: definition.parameters,
4253
- execute: async (args, _context, signal) => {
4254
- const result = await definition.execute(args, signal);
4255
- const content = JSON.parse(JSON.stringify(result.content));
4256
- return result.isError ? { ok: false, content, error: "Extension Tool failed." } : { ok: true, content };
4257
- }
4258
- };
4259
- }
4260
4273
  function toLoopResult(result, toolCallId, toolName) {
4261
4274
  return {
4262
4275
  toolCallId,
@@ -5677,7 +5690,7 @@ var RuntimeBootstrapRegistry = class extends ResourceRegistry {
5677
5690
  })();
5678
5691
  const normalized = await loaded;
5679
5692
  const result = await this.extensions.activate(normalized.extensions);
5680
- await this.replaceImplicit("tool", this.extensionSourceId, this.extensions.tools().map(adaptExtensionTool2));
5693
+ await this.replaceImplicit("tool", this.extensionSourceId, this.extensions.tools().map(adaptExtensionTool));
5681
5694
  await this.replaceImplicit("phase", this.extensionSourceId, [...this.extensions.phases()]);
5682
5695
  return {
5683
5696
  ...result,
@@ -5704,7 +5717,7 @@ var RuntimeBootstrapRegistry = class extends ResourceRegistry {
5704
5717
  await this.extensions.close();
5705
5718
  }
5706
5719
  };
5707
- function adaptExtensionTool2(input) {
5720
+ function adaptExtensionTool(input) {
5708
5721
  const definition = input.definition;
5709
5722
  return {
5710
5723
  name: definition.name,
@@ -5718,132 +5731,6 @@ function adaptExtensionTool2(input) {
5718
5731
  };
5719
5732
  }
5720
5733
 
5721
- // src/runtime/configuration-snapshot.ts
5722
- function resolveConfigurationSnapshot(registry, input) {
5723
- validateMaxAttempts(input.maxAttempts);
5724
- const resolved = registry.resolveView(input.resourceView);
5725
- const base = resolved.agents.find(({ name }) => name === input.definition.name);
5726
- if (!base) {
5727
- throw new Error(`Agent Definition "${input.definition.name}" is not available in the Resource View.`);
5728
- }
5729
- const layer = input.definition.layer;
5730
- const selectedContexts = selectNamedResources(input.contexts ?? [], base.contexts, "Context");
5731
- const additionalContexts = deduplicateContexts(input.additionalContexts ?? [], selectedContexts);
5732
- const definition = applyDefinitionLayer(base, layer);
5733
- const tools = selectNamedResources(resolved.tools, definition.tools, "Tool");
5734
- const skills = mergeSkills(
5735
- selectNamedResources(resolved.skills, definition.skills, "Skill"),
5736
- definition.bundledSkills
5737
- );
5738
- const phases = resolvePhases(resolved.phases, definition.phases);
5739
- return {
5740
- identity: input.identity,
5741
- definition,
5742
- resources: {
5743
- tools,
5744
- skills,
5745
- ...phases ? { phases } : {},
5746
- revisions: resolved.revisions,
5747
- refs: {
5748
- agent: selectedRefs(resolved.refs.agent, [base.name]),
5749
- tool: selectedRefs(resolved.refs.tool, tools.map(({ name }) => name)),
5750
- skill: selectedRefs(resolved.refs.skill, skills.map(({ name }) => name)),
5751
- phase: selectedRefs(resolved.refs.phase, [...phases?.phases.keys() ?? []])
5752
- }
5753
- },
5754
- contexts: selectedContexts,
5755
- additionalContexts,
5756
- resourceView: input.resourceView,
5757
- ...input.cwd === void 0 ? {} : { cwd: input.cwd },
5758
- ...input.maxAttempts === void 0 ? {} : { maxAttempts: input.maxAttempts },
5759
- ..."stream" in input && input.stream ? { model: layer?.model ?? input.model, stream: input.stream } : { model: layer?.model ?? input.model }
5760
- };
5761
- }
5762
- function materializeConfigurationSnapshot(snapshot) {
5763
- return {
5764
- identity: snapshot.identity,
5765
- definition: snapshot.definition,
5766
- resources: {
5767
- tools: snapshot.resources.tools,
5768
- skills: snapshot.resources.skills,
5769
- ...snapshot.resources.phases ? { phases: snapshot.resources.phases } : {},
5770
- ...snapshot.contexts.length > 0 ? { contexts: snapshot.contexts } : {},
5771
- resourceView: snapshot.resourceView,
5772
- resourceRefs: [
5773
- ...snapshot.resources.refs.agent,
5774
- ...snapshot.resources.refs.tool,
5775
- ...snapshot.resources.refs.skill,
5776
- ...snapshot.resources.refs.phase
5777
- ],
5778
- resourceRevisions: snapshot.resources.revisions
5779
- },
5780
- ...snapshot.additionalContexts.length > 0 ? { additionalContexts: snapshot.additionalContexts } : {},
5781
- ...snapshot.cwd === void 0 ? {} : { cwd: snapshot.cwd },
5782
- ...snapshot.maxAttempts === void 0 ? {} : { maxAttempts: snapshot.maxAttempts },
5783
- ..."stream" in snapshot && snapshot.stream ? { model: snapshot.model, stream: snapshot.stream } : { model: snapshot.model }
5784
- };
5785
- }
5786
- function applyDefinitionLayer(base, layer) {
5787
- if (!layer) return { ...base };
5788
- return {
5789
- ...base,
5790
- ...layer.description === void 0 ? {} : { description: layer.description },
5791
- ...layer.prompt === void 0 ? {} : { prompt: layer.prompt },
5792
- ...layer.model === void 0 ? {} : { model: layer.model },
5793
- ...layer.tools === void 0 ? {} : { tools: intersectNames(base.tools, layer.tools, "Tool") },
5794
- ...layer.skills === void 0 ? {} : { skills: intersectNames(base.skills, layer.skills, "Skill") },
5795
- ...layer.phases === void 0 ? {} : { phases: intersectPhaseSelection(base.phases, layer.phases) }
5796
- };
5797
- }
5798
- function deduplicateContexts(additional, existing = []) {
5799
- const contexts = [];
5800
- const seen = new Set(existing.map(({ name }) => name));
5801
- for (const context of additional) {
5802
- if (seen.has(context.name)) continue;
5803
- seen.add(context.name);
5804
- contexts.push(context);
5805
- }
5806
- return contexts;
5807
- }
5808
- function intersectNames(parent, layer, kind) {
5809
- if (parent === void 0) return [...layer];
5810
- const parentNames = new Set(parent);
5811
- for (const name of layer) {
5812
- if (!parentNames.has(name)) console.warn(`${kind} "${name}" is not available and will be skipped.`);
5813
- }
5814
- return layer.filter((name) => parentNames.has(name));
5815
- }
5816
- function intersectPhaseSelection(parent, layer) {
5817
- if (!parent) return layer;
5818
- const parentNames = new Set(parent.phaseIds);
5819
- for (const name of layer.phaseIds) {
5820
- if (!parentNames.has(name)) console.warn(`Phase "${name}" is not available and will be skipped.`);
5821
- }
5822
- return {
5823
- entryPhaseId: layer.entryPhaseId,
5824
- phaseIds: layer.phaseIds.filter((name) => parentNames.has(name))
5825
- };
5826
- }
5827
- function resolvePhases(candidates, selection) {
5828
- const coreNames = /* @__PURE__ */ new Set([DEFAULT_PHASE_ID, STOP_PHASE_ID, COMPACT_PHASE_ID]);
5829
- const core = candidates.filter((phase) => phase.core || coreNames.has(phase.name));
5830
- const authored = candidates.filter((phase) => !coreNames.has(phase.name) && !phase.core);
5831
- const selected = [...core, ...selectNamedResources(authored, selection?.phaseIds, "Phase")];
5832
- const entryPhaseId = selection?.entryPhaseId ?? null;
5833
- if (entryPhaseId !== null && entryPhaseId !== DEFAULT_PHASE_ID && !selected.some(({ name }) => name === entryPhaseId)) {
5834
- console.warn(`Phase entry "${entryPhaseId}" is not available and will be skipped.`);
5835
- return { phases: new Map(selected.map((phase) => [phase.name, phase])), entryPhaseId: null };
5836
- }
5837
- return {
5838
- phases: new Map(selected.map((phase) => [phase.name, phase])),
5839
- entryPhaseId
5840
- };
5841
- }
5842
- function selectedRefs(refs, names) {
5843
- const selected = new Set(names);
5844
- return refs.filter(({ name }) => selected.has(name));
5845
- }
5846
-
5847
5734
  // src/runtime/durable-runtime.ts
5848
5735
  var DEFAULT_CONCURRENCY = 10;
5849
5736
  var DEFAULT_POLL_MS = 25;
@@ -6045,7 +5932,7 @@ var AgentRuntime = class _AgentRuntime {
6045
5932
  reason: resolution.kind === "deferred" ? "Configuration is deferred." : resolution.reason
6046
5933
  });
6047
5934
  }
6048
- const config = isAgentConfiguration(resolution.config) ? this.materializeConfig(resolution.config) : resolution.config;
5935
+ const config = this.resolveConfig(resolution.config);
6049
5936
  const assembly = assembleRegisteredExtensions(config, this.resources.extensionRunner, {
6050
5937
  toolArchiveDir: this.archiveDirFor(agentId)
6051
5938
  });
@@ -6206,9 +6093,9 @@ var AgentRuntime = class _AgentRuntime {
6206
6093
  return;
6207
6094
  }
6208
6095
  let resolvedConfig = resolution.config;
6209
- if (isAgentConfiguration(resolvedConfig)) {
6096
+ if (!isConfigurationSnapshot(resolvedConfig)) {
6210
6097
  try {
6211
- const snapshot = this.materializeConfig(resolvedConfig);
6098
+ const snapshot = this.resolveConfig(resolvedConfig);
6212
6099
  token = await this.commands.storeSnapshot({
6213
6100
  agent,
6214
6101
  config: snapshot,
@@ -6220,7 +6107,7 @@ var AgentRuntime = class _AgentRuntime {
6220
6107
  return;
6221
6108
  }
6222
6109
  }
6223
- const config = resolvedConfig;
6110
+ const config = this.resolveConfig(resolvedConfig);
6224
6111
  const controlKind = controlRunKind(run);
6225
6112
  if (!controlKind && !this.autoCompactionRuns.has(run.id)) {
6226
6113
  const contextWindow = await resolveContextWindowForConfig(config);
@@ -6283,8 +6170,8 @@ var AgentRuntime = class _AgentRuntime {
6283
6170
  let executionContext = buildExecutionContext(modelMessages);
6284
6171
  const executionTools = {
6285
6172
  tools: assembly.context.tools,
6286
- beforeToolCall: assembly.beforeToolCall ?? config.beforeToolCall,
6287
- afterToolCall: assembly.afterToolCall ?? config.afterToolCall
6173
+ beforeToolCall: assembly.beforeToolCall,
6174
+ afterToolCall: assembly.afterToolCall
6288
6175
  };
6289
6176
  const executeModel = (context) => executeOnce({
6290
6177
  canonicalMessages: context.messages,
@@ -6492,7 +6379,7 @@ var AgentRuntime = class _AgentRuntime {
6492
6379
  if (!agent.currentConfigToken) return 128e3;
6493
6380
  const resolution = await this.commands.resolve({ agent, token: agent.currentConfigToken });
6494
6381
  if (resolution.kind !== "available") return 128e3;
6495
- const config = isAgentConfiguration(resolution.config) ? this.materializeConfig(resolution.config) : resolution.config;
6382
+ const config = this.resolveConfig(resolution.config);
6496
6383
  return resolveContextWindowForConfig(config);
6497
6384
  }
6498
6385
  async executeTool(input) {
@@ -6715,9 +6602,10 @@ var AgentRuntime = class _AgentRuntime {
6715
6602
  assertOpen() {
6716
6603
  if (this.closed) throw new RuntimeError("runtime_closed", null);
6717
6604
  }
6718
- materializeConfig(config) {
6719
- if (!isAgentConfiguration(config)) return config;
6720
- return materializeConfigurationSnapshot(resolveConfigurationSnapshot(this.resources, config));
6605
+ /** Resolve one stored configuration to the snapshot this execution uses. A
6606
+ * stored snapshot is already source-qualified and is used as it stands. */
6607
+ resolveConfig(config) {
6608
+ return isConfigurationSnapshot(config) ? config : resolveConfigurationSnapshot(this.resources, config);
6721
6609
  }
6722
6610
  startHeartbeat() {
6723
6611
  this.heartbeat = setInterval(() => {
@@ -9036,6 +8924,7 @@ export {
9036
8924
  createCoreTools2 as createCoreTools,
9037
8925
  createDefaultPhase,
9038
8926
  createStopPhase,
8927
+ isConfigurationSnapshot,
9039
8928
  isRuntimeError,
9040
8929
  loadExtensionsFromPath as loadExtensions,
9041
8930
  loadPhase,
@@ -9043,7 +8932,6 @@ export {
9043
8932
  loadPhases,
9044
8933
  loadSkill,
9045
8934
  loadSkills,
9046
- materializeConfigurationSnapshot,
9047
8935
  parseAgentDefinition,
9048
8936
  parseFrontmatter,
9049
8937
  resolveConfigurationSnapshot
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowan-agent/agent",
3
- "version": "0.9.24",
3
+ "version": "0.10.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",