norn-cli 4.3.1 → 4.4.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
@@ -27,7 +27,7 @@ That means you can:
27
27
  - `.nornenv` files for environments and secrets
28
28
  - `.nornapi` files for reusable endpoint definitions
29
29
  - `.nornsql` files for database queries and commands
30
- - `.nornagent` files for contract-checked AI agents and model-directed delegation
30
+ - `.nornai` or `.nornagent` files for contract-checked AI agents and model-directed delegation
31
31
  - syntax highlighting, IntelliSense, and diagnostics
32
32
  - response inspection, JSON diffing, and click-to-generate assertions
33
33
  - tagged and parameterized test execution in VS Code and the CLI
@@ -140,7 +140,7 @@ Norn can call MCP tools from sequences without leaving the `.norn` runtime. MCP
140
140
 
141
141
  A server can be declared in two places, and an alias resolves through them in this order:
142
142
 
143
- 1. an `mcp <Alias> ... end mcp` block in a `.nornagent` sidecar the file imports — see
143
+ 1. an `mcp <Alias> ... end mcp` block in a `.nornai` sidecar the file imports — see
144
144
  [Contract-Checked Agent Graphs](#contract-checked-agent-graphs), and prefer this when agents
145
145
  use the server too, because the file then says what it connects to;
146
146
  2. `mcp.servers` in the nearest `norn.config.json`.
@@ -194,7 +194,7 @@ Behavior:
194
194
 
195
195
  ## Contract-Checked Agent Graphs
196
196
 
197
- Define agents in an imported `.nornagent` sidecar. An agent can grant another
197
+ Define agents in an imported `.nornai` or `.nornagent` sidecar. Both extensions use the same syntax and behavior. An agent can grant another
198
198
  agent through `agents`; the callee then appears to the calling model as an
199
199
  ordinary tool. Its `accepts` schema constrains and validates the generated tool
200
200
  input, and its `returns` schema validates the result before it travels back up
@@ -277,7 +277,7 @@ Deterministic `run mcp` steps resolve the same aliases, so a server can be prove
277
277
  with no model and no cost:
278
278
 
279
279
  ```norn
280
- import "./agents.nornagent"
280
+ import "./agents.nornai"
281
281
 
282
282
  test sequence ServersUp
283
283
  var tools = run mcp list House
@@ -290,7 +290,7 @@ shape end to end: a browser agent, a backend agent narrowed on the same custom s
290
290
  reporter, and a `judge` over the expected test cases.
291
291
 
292
292
  A prompt that outgrows its sidecar can live in its own file instead. `describe`
293
- and `system` both accept `file <path>`, resolved relative to the `.nornagent`
293
+ and `system` both accept `file <path>`, resolved relative to the agent sidecar
294
294
  file just like an import:
295
295
 
296
296
  ```nornagent
@@ -309,7 +309,7 @@ Run the graph from an ordinary sequence; the same nested contract and retry
309
309
  trace appears in VS Code and the CLI:
310
310
 
311
311
  ```norn
312
- import "./agents.nornagent"
312
+ import "./agents.nornai"
313
313
 
314
314
  test sequence RouteTicket
315
315
  var ticket = run readJson "./ticket.json"
@@ -370,7 +370,7 @@ fixture. `--from` accepts a unique agent name or canonical path such as
370
370
  onward runs live against the current graph.
371
371
 
372
372
  **Norn: Show Agent Graph**, or the CodeLens on any agent block, draws the graph
373
- for a `.nornagent` file: who calls whom, the `accepts`/`returns` contract on each
373
+ for an agent sidecar: who calls whom, the `accepts`/`returns` contract on each
374
374
  boundary, and how each one turned out. Hover an agent or a boundary for the full
375
375
  detail — models, timings, usage, prompts, payloads, contract issues.
376
376
 
package/dist/cli.js CHANGED
@@ -157480,6 +157480,12 @@ var fs36 = __toESM(require("fs"));
157480
157480
  var fsPromises = __toESM(require("fs/promises"));
157481
157481
  var path42 = __toESM(require("path"));
157482
157482
 
157483
+ // src/agents/agentSidecarPath.ts
157484
+ function isAgentSidecarPath(filePath) {
157485
+ const lowerPath = filePath.toLowerCase();
157486
+ return lowerPath.endsWith(".nornagent") || lowerPath.endsWith(".nornai");
157487
+ }
157488
+
157483
157489
  // src/parser.ts
157484
157490
  var path4 = __toESM(require("path"));
157485
157491
 
@@ -158940,6 +158946,7 @@ function parseNornAgentFile(content, sourcePath) {
158940
158946
  let pendingMcp;
158941
158947
  let pendingKnowledge;
158942
158948
  let sawAgent = false;
158949
+ let sawMcpDeclaration = false;
158943
158950
  const reportBareMcpAlias = (mcp) => {
158944
158951
  errors.push(parseError(
158945
158952
  mcp.lineNumber,
@@ -159508,6 +159515,7 @@ end model`,
159508
159515
  }
159509
159516
  const mcpMatch = trimmed.match(new RegExp(`^mcp\\s+(${IDENTIFIER})$`, "i"));
159510
159517
  if (mcpMatch) {
159518
+ sawMcpDeclaration = true;
159511
159519
  const alias = mcpMatch[1];
159512
159520
  let invalid = false;
159513
159521
  if (sawAgent) {
@@ -159900,11 +159908,11 @@ end model`,
159900
159908
  "agent-knowledge-end-missing"
159901
159909
  ));
159902
159910
  }
159903
- if (models.size === 0) {
159904
- errors.push(parseError(0, "A .nornagent file must declare at least one model block.", "agent-model-required"));
159911
+ if (!sawMcpDeclaration && models.size === 0) {
159912
+ errors.push(parseError(0, "An agent sidecar must declare at least one model block.", "agent-model-required"));
159905
159913
  }
159906
- if (agentNames.size === 0) {
159907
- errors.push(parseError(0, "A .nornagent file must declare at least one agent.", "agent-required"));
159914
+ if (!sawMcpDeclaration && agentNames.size === 0) {
159915
+ errors.push(parseError(0, "An agent sidecar must declare at least one agent.", "agent-required"));
159908
159916
  }
159909
159917
  const localScope = new Map(agents.map((agent) => [agent.name.toLowerCase(), agent]));
159910
159918
  for (const validationError of validateAgentScope(localScope, { checkUnknownReferences: false })) {
@@ -160491,6 +160499,15 @@ async function resolveImports(text, baseDir, readFile4, alreadyImported = /* @__
160491
160499
  }
160492
160500
  for (const imp of imports) {
160493
160501
  const absolutePath = path4.resolve(baseDir, imp.path);
160502
+ if (imp.path.toLowerCase().endsWith(".ai")) {
160503
+ errors.push({
160504
+ path: imp.path,
160505
+ error: "The .ai extension is not supported for Norn agent sidecars. Rename the file to .nornai and update the import.",
160506
+ lineNumber: imp.lineNumber,
160507
+ blocking: true
160508
+ });
160509
+ continue;
160510
+ }
160494
160511
  if (imp.path.endsWith(".nornsql")) {
160495
160512
  const importedSqlPaths = sqlImportedPathsBySource.get(sourceFilePath);
160496
160513
  if (importedSqlPaths.has(absolutePath)) {
@@ -160534,7 +160551,7 @@ async function resolveImports(text, baseDir, readFile4, alreadyImported = /* @__
160534
160551
  }
160535
160552
  continue;
160536
160553
  }
160537
- if (imp.path.endsWith(".nornagent")) {
160554
+ if (isAgentSidecarPath(imp.path)) {
160538
160555
  const importedAgentPaths = agentImportedPathsBySource.get(sourceFilePath);
160539
160556
  if (importedAgentPaths.has(absolutePath)) {
160540
160557
  continue;
@@ -160739,7 +160756,7 @@ end sequence`);
160739
160756
  }
160740
160757
  const directAgentScope = agentDefinitionsBySource.get(sourceFilePath);
160741
160758
  const directAgentImportsByPath = new Map(
160742
- imports.filter((imp) => imp.path.toLowerCase().endsWith(".nornagent")).map((imp) => [path4.resolve(baseDir, imp.path), imp])
160759
+ imports.filter((imp) => isAgentSidecarPath(imp.path)).map((imp) => [path4.resolve(baseDir, imp.path), imp])
160743
160760
  );
160744
160761
  for (const validationError of validateAgentScope(directAgentScope, {
160745
160762
  skipSameSourceChecks: true,
@@ -184867,7 +184884,7 @@ function resolveMcpServer(startPath, alias, envVariables) {
184867
184884
  const server = config2.servers[alias];
184868
184885
  if (!server) {
184869
184886
  throw new Error(
184870
- `Server alias '${alias}' was not declared by an 'mcp ${alias} ... end mcp' block in the .nornagent sidecar and was not found in ${NORN_CONFIG_FILENAME} mcp.servers`
184887
+ `Server alias '${alias}' was not declared by an 'mcp ${alias} ... end mcp' block in the agent sidecar and was not found in ${NORN_CONFIG_FILENAME} mcp.servers`
184871
184888
  );
184872
184889
  }
184873
184890
  return { filePath, server };
@@ -199538,7 +199555,15 @@ var AgentInvocationRunner = class {
199538
199555
  throw new Error(`Agent root invocation index must be a positive integer, received '${rootInvocationIndex2}'.`);
199539
199556
  }
199540
199557
  const hopPath = `${agent.name}[${rootInvocationIndex2}]`;
199541
- const hop = await this.invokeAgent(agent, input2, 0, void 0, [], [], hopPath);
199558
+ const hop = await this.invokeAgent(
199559
+ agent,
199560
+ input2,
199561
+ 0,
199562
+ void 0,
199563
+ [],
199564
+ [...this.options.initialConversation ?? []],
199565
+ hopPath
199566
+ );
199542
199567
  return { hop, definitions: [...this.definitions.values()] };
199543
199568
  }
199544
199569
  nextInvocationId() {
@@ -203394,7 +203419,7 @@ function walkSidecars(directory) {
203394
203419
  if (entry.isDirectory()) {
203395
203420
  return walkSidecars(candidate);
203396
203421
  }
203397
- return entry.isFile() && entry.name.toLowerCase().endsWith(".nornagent") ? [candidate] : [];
203422
+ return entry.isFile() && isAgentSidecarPath(entry.name) ? [candidate] : [];
203398
203423
  });
203399
203424
  }
203400
203425
  function discoverKnowledgeDeclarations(projectRoot) {
@@ -206653,7 +206678,7 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
206653
206678
  };
206654
206679
  }
206655
206680
  if (!judgeDefinition) {
206656
- const message = `Judge agent '${judgeName}' was not found in the .nornagent files imported directly by this .norn file.`;
206681
+ const message = `Judge agent '${judgeName}' was not found in the agent sidecars imported directly by this .norn file.`;
206657
206682
  errors.push(message);
206658
206683
  await emitFailure(message, step);
206659
206684
  return {
@@ -206693,7 +206718,7 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
206693
206718
  const scope = getCurrentAgentScope();
206694
206719
  const definition = scope?.get(parsedRun.agentName.toLowerCase());
206695
206720
  if (!definition) {
206696
- const message = `Agent '${parsedRun.agentName}' was not found in the .nornagent files imported directly by this .norn file.`;
206721
+ const message = `Agent '${parsedRun.agentName}' was not found in the agent sidecars imported directly by this .norn file.`;
206697
206722
  errors.push(message);
206698
206723
  await emitFailure(message, step);
206699
206724
  return {
@@ -206986,7 +207011,7 @@ async function runSequenceWithJar(sequenceContent, fileVariables, cookieJar, wor
206986
207011
  try {
206987
207012
  const judgeAgent = getCurrentAgentScope()?.get(declaration.judgeAgentName.toLowerCase());
206988
207013
  if (!judgeAgent) {
206989
- throw new Error(`Judge agent '${declaration.judgeAgentName}' was not found in the .nornagent files imported directly by this .norn file.`);
207014
+ throw new Error(`Judge agent '${declaration.judgeAgentName}' was not found in the agent sidecars imported directly by this .norn file.`);
206990
207015
  }
206991
207016
  const evaluatedSubject = evaluateSqlArgumentExpression(declaration.subjectExpression, runtimeVariables);
206992
207017
  if (evaluatedSubject.error) {
@@ -207147,7 +207172,7 @@ ${describeUnmetExpectations(verdict).map((line2) => ` - ${line2}`).join("\n")}`
207147
207172
  const scope = getCurrentAgentScope();
207148
207173
  agent = scope?.get(parsed.agentName.toLowerCase());
207149
207174
  if (!agent) {
207150
- throw new Error(`Agent '${parsed.agentName}' was not found in the .nornagent files imported directly by this .norn file.`);
207175
+ throw new Error(`Agent '${parsed.agentName}' was not found in the agent sidecars imported directly by this .norn file.`);
207151
207176
  }
207152
207177
  const evaluatedInput = evaluateSqlArgumentExpression(parsed.inputExpression, runtimeVariables);
207153
207178
  if (evaluatedInput.error) {
@@ -212913,12 +212938,12 @@ function knowledgeCliHelp() {
212913
212938
  return `
212914
212939
  Norn knowledge membership and topic summary
212915
212940
 
212916
- Usage: norn knowledge ls --explain [sidecar.nornagent]
212941
+ Usage: norn knowledge ls --explain [sidecar.nornai|sidecar.nornagent]
212917
212942
 
212918
212943
  --explain List every source candidate as IN or OUT and name the deciding rule
212919
212944
  -h, --help Show this help
212920
212945
 
212921
- With no path, Norn discovers the one .nornagent sidecar declaring knowledge below the current
212946
+ With no path, Norn discovers the one .nornai or .nornagent sidecar declaring knowledge below the current
212922
212947
  directory, and reports every declaration it holds.
212923
212948
  `;
212924
212949
  }
@@ -212938,7 +212963,7 @@ function parseKnowledgeCliArgs(args) {
212938
212963
  } else if (argument.startsWith("-")) {
212939
212964
  throw new Error(`Unknown knowledge option '${argument}'.`);
212940
212965
  } else if (options.target) {
212941
- throw new Error(`Unexpected knowledge argument '${argument}'. Provide at most one .nornagent path.`);
212966
+ throw new Error(`Unexpected knowledge argument '${argument}'. Provide at most one agent sidecar path.`);
212942
212967
  } else {
212943
212968
  options.target = argument;
212944
212969
  }
@@ -212955,14 +212980,14 @@ function discoverSidecars(directory) {
212955
212980
  if (entry.isDirectory()) {
212956
212981
  return SKIPPED_DIRECTORIES3.has(entry.name) ? [] : discoverSidecars(entryPath);
212957
212982
  }
212958
- return entry.isFile() && entry.name.toLowerCase().endsWith(".nornagent") ? [entryPath] : [];
212983
+ return entry.isFile() && isAgentSidecarPath(entry.name) ? [entryPath] : [];
212959
212984
  });
212960
212985
  }
212961
212986
  function resolveSidecar(target) {
212962
212987
  const resolved = path40.resolve(target ?? process.cwd());
212963
212988
  if (fs34.existsSync(resolved) && fs34.statSync(resolved).isFile()) {
212964
- if (!resolved.toLowerCase().endsWith(".nornagent")) {
212965
- throw new Error(`Knowledge target '${target}' is not a .nornagent sidecar.`);
212989
+ if (!isAgentSidecarPath(resolved)) {
212990
+ throw new Error(`Knowledge target '${target}' is not a .nornai or .nornagent sidecar.`);
212966
212991
  }
212967
212992
  return resolved;
212968
212993
  }
@@ -212979,11 +213004,11 @@ function resolveSidecar(target) {
212979
213004
  }
212980
213005
  });
212981
213006
  if (matches.length === 0) {
212982
- throw new Error(`No .nornagent knowledge declaration was found below '${resolved}'.`);
213007
+ throw new Error(`No agent sidecar knowledge declaration was found below '${resolved}'.`);
212983
213008
  }
212984
213009
  if (matches.length > 1) {
212985
213010
  throw new Error(
212986
- `More than one .nornagent knowledge declaration was found. Provide one explicitly:
213011
+ `More than one agent sidecar knowledge declaration was found. Provide one explicitly:
212987
213012
  ` + matches.map((match2) => ` ${path40.relative(resolved, match2)}`).join("\n")
212988
213013
  );
212989
213014
  }
@@ -213869,7 +213894,7 @@ Usage: norn <file.norn|directory> [options]
213869
213894
  norn replay <recording.json> [--json] [--from <agent-or-hop>] [--env <name>]
213870
213895
  norn secrets <command> [options]
213871
213896
  norn contracts <sync|check> <file.nornapi> [options]
213872
- norn knowledge ls --explain [sidecar.nornagent]
213897
+ norn knowledge ls --explain [sidecar.nornai|sidecar.nornagent]
213873
213898
 
213874
213899
  When given a directory, recursively discovers .norn test sequences within
213875
213900
  that directory and subdirectories.
@@ -214296,7 +214321,7 @@ async function main() {
214296
214321
  }
214297
214322
  const args = rawArgs[0] === "run" ? rawArgs.slice(1) : rawArgs;
214298
214323
  if (args.length === 1 && (args[0] === "--version" || args[0] === "-V")) {
214299
- console.log(`Norn CLI ${"4.3.0"}`);
214324
+ console.log(`Norn CLI ${"4.4.0"}`);
214300
214325
  return;
214301
214326
  }
214302
214327
  if (args.length === 0) {
@@ -7320,6 +7320,12 @@ function queryKnowledgeEditorFacts(query, options = {}) {
7320
7320
  }
7321
7321
  }
7322
7322
 
7323
+ // src/agents/agentSidecarPath.ts
7324
+ function isAgentSidecarPath(filePath) {
7325
+ const lowerPath = filePath.toLowerCase();
7326
+ return lowerPath.endsWith(".nornagent") || lowerPath.endsWith(".nornai");
7327
+ }
7328
+
7323
7329
  // src/knowledge/knowledgeIndexBuilder.ts
7324
7330
  var fs8 = __toESM(require("fs"));
7325
7331
  var path10 = __toESM(require("path"));
@@ -7878,6 +7884,7 @@ function parseNornAgentFile(content, sourcePath) {
7878
7884
  let pendingMcp;
7879
7885
  let pendingKnowledge;
7880
7886
  let sawAgent = false;
7887
+ let sawMcpDeclaration = false;
7881
7888
  const reportBareMcpAlias = (mcp) => {
7882
7889
  errors.push(parseError(
7883
7890
  mcp.lineNumber,
@@ -8446,6 +8453,7 @@ end model`,
8446
8453
  }
8447
8454
  const mcpMatch = trimmed.match(new RegExp(`^mcp\\s+(${IDENTIFIER})$`, "i"));
8448
8455
  if (mcpMatch) {
8456
+ sawMcpDeclaration = true;
8449
8457
  const alias = mcpMatch[1];
8450
8458
  let invalid = false;
8451
8459
  if (sawAgent) {
@@ -8838,11 +8846,11 @@ end model`,
8838
8846
  "agent-knowledge-end-missing"
8839
8847
  ));
8840
8848
  }
8841
- if (models.size === 0) {
8842
- errors.push(parseError(0, "A .nornagent file must declare at least one model block.", "agent-model-required"));
8849
+ if (!sawMcpDeclaration && models.size === 0) {
8850
+ errors.push(parseError(0, "An agent sidecar must declare at least one model block.", "agent-model-required"));
8843
8851
  }
8844
- if (agentNames.size === 0) {
8845
- errors.push(parseError(0, "A .nornagent file must declare at least one agent.", "agent-required"));
8852
+ if (!sawMcpDeclaration && agentNames.size === 0) {
8853
+ errors.push(parseError(0, "An agent sidecar must declare at least one agent.", "agent-required"));
8846
8854
  }
8847
8855
  const localScope = new Map(agents.map((agent) => [agent.name.toLowerCase(), agent]));
8848
8856
  for (const validationError of validateAgentScope(localScope, { checkUnknownReferences: false })) {
@@ -10413,7 +10421,7 @@ function walkSidecars(directory) {
10413
10421
  if (entry.isDirectory()) {
10414
10422
  return walkSidecars(candidate);
10415
10423
  }
10416
- return entry.isFile() && entry.name.toLowerCase().endsWith(".nornagent") ? [candidate] : [];
10424
+ return entry.isFile() && isAgentSidecarPath(entry.name) ? [candidate] : [];
10417
10425
  });
10418
10426
  }
10419
10427
  function discoverKnowledgeDeclarations(projectRoot) {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "norn-cli",
3
3
  "displayName": "Norn",
4
- "description": "Version-controlled API and database tests. Author in VS Code, then run the same files from the CLI and CI.",
5
- "version": "4.3.1",
4
+ "description": "Build version-controlled agentic flows in VS Code and run them from the CLI or CI.",
5
+ "version": "4.4.0",
6
6
  "publisher": "Norn-PeterKrustanov",
7
7
  "author": {
8
8
  "name": "Peter Krastanov"
@@ -48,6 +48,7 @@
48
48
  "onLanguage:nornk8s",
49
49
  "onLanguage:nornagent",
50
50
  "workspaceContains:**/*.nornagent",
51
+ "workspaceContains:**/*.nornai",
51
52
  "workspaceContains:**/norn.config.json",
52
53
  "onChatParticipant:norn.chat",
53
54
  "onView:norn.sidebarHome",
@@ -55,12 +56,12 @@
55
56
  "onCommand:norn.importPostmanEnvironment",
56
57
  "onCommand:norn.createStarterCatalog",
57
58
  "onCommand:norn.createSqlStarterFiles",
58
- "onCommand:norn.createMcpStarterConfig",
59
59
  "onCommand:norn.openTerminal",
60
60
  "onCommand:norn.terminal.focusRawTerminal",
61
61
  "onCommand:norn.debugSequence",
62
62
  "onCommand:norn.debug.runToNextContractFailure",
63
63
  "onCommand:norn.showAgentGraph",
64
+ "onCommand:norn.chatWithAgent",
64
65
  "onCommand:norn.showAgentRunResults",
65
66
  "onDebugResolve:norn"
66
67
  ],
@@ -93,6 +94,11 @@
93
94
  "title": "Show Agent Graph",
94
95
  "category": "Norn"
95
96
  },
97
+ {
98
+ "command": "norn.chatWithAgent",
99
+ "title": "Chat With Agent",
100
+ "category": "Norn"
101
+ },
96
102
  {
97
103
  "command": "norn.showAgentRunResults",
98
104
  "title": "Show Agent Run Results",
@@ -136,7 +142,11 @@
136
142
  {
137
143
  "command": "norn.openTerminal",
138
144
  "title": "Open Terminal",
139
- "category": "Norn"
145
+ "category": "Norn",
146
+ "icon": {
147
+ "light": "./images/nornapi-icon.svg",
148
+ "dark": "./images/nornapi-icon.svg"
149
+ }
140
150
  },
141
151
  {
142
152
  "command": "norn.terminal.focusRawTerminal",
@@ -188,11 +198,6 @@
188
198
  "title": "Open Norn Starter Catalogue",
189
199
  "category": "Norn"
190
200
  },
191
- {
192
- "command": "norn.createMcpStarterConfig",
193
- "title": "Create MCP Starter Config",
194
- "category": "Norn"
195
- },
196
201
  {
197
202
  "command": "norn.encryptSecretAtLine",
198
203
  "title": "Encrypt Secret At Line",
@@ -262,11 +267,6 @@
262
267
  "command": "norn.createStarterCatalog",
263
268
  "when": "explorerResourceIsFolder",
264
269
  "group": "norn@1"
265
- },
266
- {
267
- "command": "norn.createMcpStarterConfig",
268
- "when": "explorerResourceIsFolder",
269
- "group": "norn@2"
270
270
  }
271
271
  ],
272
272
  "debug/toolBar": [
@@ -275,6 +275,12 @@
275
275
  "when": "debugType == norn && debugState == stopped",
276
276
  "group": "navigation@25"
277
277
  }
278
+ ],
279
+ "editor/title": [
280
+ {
281
+ "command": "norn.openTerminal",
282
+ "group": "navigation"
283
+ }
278
284
  ]
279
285
  },
280
286
  "languages": [
@@ -359,7 +365,8 @@
359
365
  "nornagent"
360
366
  ],
361
367
  "extensions": [
362
- ".nornagent"
368
+ ".nornagent",
369
+ ".nornai"
363
370
  ],
364
371
  "icon": {
365
372
  "light": "./images/nornagent-icon.svg",
@@ -486,7 +486,7 @@
486
486
  "agentsSection": {
487
487
  "type": "object",
488
488
  "additionalProperties": false,
489
- "description": "Global recording behavior and global/provider-specific limits for agent runs. Per-agent .nornagent directives override limit values.",
489
+ "description": "Global recording behavior and global/provider-specific limits for agent runs. Per-agent .nornai or .nornagent directives override limit values.",
490
490
  "properties": {
491
491
  "_comment": {
492
492
  "$ref": "#/definitions/comment",