@rowan-agent/agent 0.8.6 → 0.8.7

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
@@ -11,24 +11,39 @@ import {
11
11
  AgentRuntime,
12
12
  createCoreTools,
13
13
  InMemoryStore,
14
+ loadPhases,
15
+ loadSkills,
14
16
  } from "@rowan-agent/agent";
15
17
 
18
+ const skills = await loadSkills("./.rowan/skills");
19
+ const phases = await loadPhases("./.rowan/phases");
16
20
  const runtime = await AgentRuntime.init({
17
21
  store: new InMemoryStore(),
18
22
  });
19
23
 
20
24
  const agentId = await runtime.createAgent({
21
25
  identity: "example:v1", // Stable config snapshot identity, not the Agent ID
22
- model: { provider: "openai", id: "gpt-4o" },
23
- stream,
26
+ model: {
27
+ provider: "openai",
28
+ id: "gpt-4o",
29
+ protocol: "openai-responses",
30
+ baseUrl: "https://api.openai.com/v1",
31
+ apiKey: process.env.OPENAI_API_KEY!,
32
+ },
24
33
  definition: {
25
34
  name: "workspace-assistant",
26
35
  description: "Assist with the current workspace.",
27
- content: "You are helpful.",
36
+ prompt: "You are helpful.",
37
+ contexts: ["workspace"],
28
38
  },
29
39
  resources: {
30
40
  tools: createCoreTools({ root: process.cwd() }),
31
- skills: [],
41
+ skills,
42
+ contexts: [{
43
+ name: "workspace",
44
+ value: { root: process.cwd() },
45
+ }],
46
+ phases,
32
47
  },
33
48
  });
34
49
 
@@ -126,7 +141,7 @@ await runtime.loadAgents({
126
141
  values: [{
127
142
  name: "workspace-assistant",
128
143
  description: "Assist with the current workspace.",
129
- content: "You are helpful.",
144
+ prompt: "You are helpful.",
130
145
  }],
131
146
  });
132
147
  await runtime.loadTools({
@@ -143,8 +158,13 @@ const agentId = await runtime.createAgent({
143
158
  skills: [],
144
159
  phases: [],
145
160
  },
146
- model: { provider: "openai", id: "gpt-4o" },
147
- stream,
161
+ model: {
162
+ provider: "openai",
163
+ id: "gpt-4o",
164
+ protocol: "openai-responses",
165
+ baseUrl: "https://api.openai.com/v1",
166
+ apiKey: process.env.OPENAI_API_KEY!,
167
+ },
148
168
  });
149
169
  ```
150
170
 
@@ -156,4 +176,53 @@ Tool and `default` Phase are always available and cannot be overridden.
156
176
  Extensions are Runtime-global. Load them only during `AgentRuntime.init()` via
157
177
  `bootstrap`; after initialization they are frozen until the Runtime closes.
158
178
  Definition name lists narrow the selected Tools, Skills, and Phases: omission
159
- inherits all candidates, `[]` selects none, and missing names are skipped.
179
+ inherits all candidates, `[]` selects none, and missing names are skipped. The
180
+ same rule applies to `definition.contexts`.
181
+
182
+ ### Resources and Definition
183
+
184
+ `resources` and `definition` have different jobs:
185
+
186
+ - `resources` supplies the concrete candidates available to one Agent. Its
187
+ Tools contain executable `execute()` functions; Skills and Phases contain
188
+ their loaded content; Contexts contain JSON-safe values.
189
+ - `definition` declares which candidates this Agent uses. `tools`, `skills`,
190
+ `contexts`, and `phases` are name-based selectors; they cannot create a
191
+ resource that is absent from `resources`.
192
+
193
+ For a single-process embedding, provide concrete resources directly and omit
194
+ the selectors when the Agent should use everything:
195
+
196
+ ```ts
197
+ const agentId = await runtime.createAgent({
198
+ identity: "workspace:v1",
199
+ definition: {
200
+ name: "workspace-assistant",
201
+ description: "Assist with the current workspace.",
202
+ prompt: "You are helpful.",
203
+ },
204
+ resources: { tools, skills, contexts, phases },
205
+ model,
206
+ });
207
+ ```
208
+
209
+ Use selectors when several Agents share a candidate pool:
210
+
211
+ ```ts
212
+ definition: {
213
+ name: "read-only-assistant",
214
+ description: "Inspect the workspace without changing it.",
215
+ prompt: "You are helpful.",
216
+ tools: ["read"],
217
+ contexts: ["workspace"],
218
+ phases: { entryPhaseId: "review", phaseIds: ["review"] },
219
+ }
220
+ ```
221
+
222
+ For process-boundary persistence, use the Resource Registry form shown above:
223
+ `resourceView` stores stable source IDs instead of executable resource
224
+ closures, and the Runtime resolves those sources into an immutable
225
+ Configuration Snapshot. This lets a restarted Runtime resolve the same
226
+ resource revisions while keeping each Run pinned to the snapshot that created
227
+ it. Direct `resources` are simpler for embedding; `resourceView` is the
228
+ declarative form for shared, reloadable, and restart-resolvable resources.
package/dist/index.d.ts CHANGED
@@ -627,11 +627,11 @@ type PhaseRegistrySelection = Readonly<{
627
627
  type AgentDefinition = Readonly<{
628
628
  name: string;
629
629
  description: string;
630
- content: string;
630
+ prompt: string;
631
631
  tools?: readonly string[];
632
632
  skills?: readonly string[];
633
633
  phases?: PhaseRegistrySelection;
634
- context?: readonly string[];
634
+ contexts?: readonly string[];
635
635
  model?: ModelRef;
636
636
  }>;
637
637
  /** Parse one Markdown definition using the same frontmatter vocabulary as Phase resources. */
@@ -1233,7 +1233,7 @@ declare class RuntimeBootstrapRegistry extends ResourceRegistry {
1233
1233
 
1234
1234
  type DefinitionLayer = Readonly<{
1235
1235
  description?: string;
1236
- content?: string;
1236
+ prompt?: string;
1237
1237
  model?: ModelRef;
1238
1238
  tools?: readonly string[];
1239
1239
  skills?: readonly string[];
package/dist/index.js CHANGED
@@ -1045,13 +1045,15 @@ import { dirname as dirname3, join, resolve as resolve3 } from "path";
1045
1045
  import { parseModelRef } from "@rowan-agent/models";
1046
1046
  function assertAgentDefinition(value) {
1047
1047
  if (!isRecord(value)) throw new TypeError("config.definition is invalid");
1048
+ if ("content" in value) throw new TypeError("definition.content is not supported; use definition.prompt");
1049
+ if ("context" in value) throw new TypeError("definition.context is not supported; use definition.contexts");
1048
1050
  requiredString(value.name, "definition.name");
1049
1051
  requiredString(value.description, "definition.description");
1050
- requiredString(value.content, "definition.content");
1052
+ requiredString(value.prompt, "definition.prompt");
1051
1053
  optionalStringList(value.tools, "definition.tools");
1052
1054
  optionalStringList(value.skills, "definition.skills");
1053
1055
  optionalPhaseRegistrySelection(value.phases, "definition.phases");
1054
- optionalStringList(value.context, "definition.context");
1056
+ optionalStringList(value.contexts, "definition.contexts");
1055
1057
  if ("extensions" in value) throw new TypeError("definition.extensions is not supported; Extensions are Runtime-global");
1056
1058
  if ("entryPhase" in value) throw new TypeError("definition.entryPhase is not supported; use definition.phases.entryPhaseId");
1057
1059
  if (value.model !== void 0) {
@@ -1064,17 +1066,19 @@ function parseAgentDefinition(raw) {
1064
1066
  const { frontmatter, body } = parseFrontmatter(raw);
1065
1067
  return normalizeAgentDefinition(frontmatter, body);
1066
1068
  }
1067
- function normalizeAgentDefinition(frontmatter, content, options = {}) {
1069
+ function normalizeAgentDefinition(frontmatter, prompt, options = {}) {
1070
+ if (frontmatter.content !== void 0) throw new TypeError("content is not supported; use prompt and the document body");
1071
+ if (frontmatter.context !== void 0) throw new TypeError("context is not supported; use contexts");
1068
1072
  const name = frontmatter.name === void 0 && options.fallbackName ? options.fallbackName : requiredString(frontmatter.name, "name");
1069
1073
  const description = requiredString(frontmatter.description, "description");
1070
- const normalizedContent = requiredString(content, "content");
1074
+ const normalizedPrompt = requiredString(prompt, "prompt");
1071
1075
  const tools = optionalStringList(frontmatter.tools, "tools");
1072
1076
  const skills = optionalStringList(frontmatter.skills, "skills");
1073
1077
  const phases = optionalPhaseRegistrySelection(frontmatter.phases, "phases");
1074
1078
  if (frontmatter.extensions !== void 0) {
1075
1079
  throw new TypeError("extensions is not supported; Extensions are Runtime-global");
1076
1080
  }
1077
- const context = optionalStringList(frontmatter.context, "context");
1081
+ const contexts = optionalStringList(frontmatter.contexts, "contexts");
1078
1082
  if (frontmatter.entryPhase !== void 0) {
1079
1083
  throw new TypeError("entryPhase is not supported; use phases.entryPhaseId");
1080
1084
  }
@@ -1082,11 +1086,11 @@ function normalizeAgentDefinition(frontmatter, content, options = {}) {
1082
1086
  return {
1083
1087
  name,
1084
1088
  description,
1085
- content: normalizedContent,
1089
+ prompt: normalizedPrompt,
1086
1090
  ...tools ? { tools } : {},
1087
1091
  ...skills ? { skills } : {},
1088
1092
  ...phases ? { phases } : {},
1089
- ...context ? { context } : {},
1093
+ ...contexts ? { contexts } : {},
1090
1094
  ...model ? { model } : {}
1091
1095
  };
1092
1096
  }
@@ -1273,7 +1277,7 @@ async function loadPhase(targetPath) {
1273
1277
  isolated: metadata.isolated,
1274
1278
  filePath: resolved,
1275
1279
  baseDir,
1276
- content: definition.content,
1280
+ content: definition.prompt,
1277
1281
  model: definition.model
1278
1282
  };
1279
1283
  const codePath = await discoverPhaseCode(baseDir);
@@ -2784,6 +2788,9 @@ function assertAgentConfigRequest(config) {
2784
2788
  if (!config.definition || typeof config.definition.name !== "string" || config.definition.name.trim() === "") {
2785
2789
  throw new TypeError("config.definition.name must be non-empty");
2786
2790
  }
2791
+ if (config.definition.layer && "content" in config.definition.layer) {
2792
+ throw new TypeError("definition.layer.content is not supported; use definition.layer.prompt");
2793
+ }
2787
2794
  const view = config.resourceView;
2788
2795
  if (!view || !Array.isArray(view.agents) || !Array.isArray(view.tools) || !Array.isArray(view.skills) || !Array.isArray(view.phases)) {
2789
2796
  throw new TypeError("config.resourceView is invalid");
@@ -2901,7 +2908,7 @@ function snapshotConfig(config) {
2901
2908
  phaseIds: Object.freeze([...config.definition.phases.phaseIds])
2902
2909
  })
2903
2910
  } : {},
2904
- ...config.definition.context ? { context: Object.freeze([...config.definition.context]) } : {}
2911
+ ...config.definition.contexts ? { contexts: Object.freeze([...config.definition.contexts]) } : {}
2905
2912
  });
2906
2913
  const resources = Object.freeze({
2907
2914
  ...config.resources,
@@ -3365,7 +3372,7 @@ function resolveDefinitionContext(config, assembled = {}) {
3365
3372
  );
3366
3373
  const contexts = selectNamedResources(
3367
3374
  config.resources.contexts ?? [],
3368
- config.definition.context,
3375
+ config.definition.contexts,
3369
3376
  "Context"
3370
3377
  );
3371
3378
  const candidateRegistry = assembled.phases ?? config.resources.phases;
@@ -3381,7 +3388,7 @@ function resolveDefinitionContext(config, assembled = {}) {
3381
3388
  console.warn(`Phase entry "${requestedEntry}" is not available; Rowan will use "default".`);
3382
3389
  }
3383
3390
  return {
3384
- systemPrompt: [config.definition.content, buildContextDescription(contexts)].filter((section) => section.length > 0).join("\n\n"),
3391
+ systemPrompt: [config.definition.prompt, buildContextDescription(contexts)].filter((section) => section.length > 0).join("\n\n"),
3385
3392
  tools,
3386
3393
  skills,
3387
3394
  phases: { phases, entryPhaseId }
@@ -4568,6 +4575,7 @@ var ResourceRegistry = class {
4568
4575
  assertSourceId(sourceId);
4569
4576
  const names = /* @__PURE__ */ new Set();
4570
4577
  for (const value of values) {
4578
+ if (kind === "agent") assertAgentDefinition(value);
4571
4579
  assertNamedResource(value, kind, sourceId);
4572
4580
  if (isImplicitCoreName(kind, value.name) && sourceId !== "rowan.core") {
4573
4581
  throw new ResourceRegistryError(
@@ -4922,7 +4930,7 @@ function resolveConfigurationSnapshot(registry, input) {
4922
4930
  const tools = selectNamedResources(resolved.tools, definition.tools, "Tool");
4923
4931
  const skills = selectNamedResources(resolved.skills, definition.skills, "Skill");
4924
4932
  const phases = resolvePhases(resolved.phases, definition.phases);
4925
- const contexts = selectNamedResources(input.contexts ?? [], base.context, "Context");
4933
+ const contexts = selectNamedResources(input.contexts ?? [], base.contexts, "Context");
4926
4934
  return {
4927
4935
  identity: input.identity,
4928
4936
  definition,
@@ -4973,7 +4981,7 @@ function applyDefinitionLayer(base, layer) {
4973
4981
  return {
4974
4982
  ...base,
4975
4983
  ...layer.description === void 0 ? {} : { description: layer.description },
4976
- ...layer.content === void 0 ? {} : { content: layer.content },
4984
+ ...layer.prompt === void 0 ? {} : { prompt: layer.prompt },
4977
4985
  ...layer.model === void 0 ? {} : { model: layer.model },
4978
4986
  ...layer.tools === void 0 ? {} : { tools: intersectNames(base.tools, layer.tools, "Tool") },
4979
4987
  ...layer.skills === void 0 ? {} : { skills: intersectNames(base.skills, layer.skills, "Skill") },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowan-agent/agent",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",