@llblab/pi-actors 0.56.1 → 0.57.1

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.
Files changed (44) hide show
  1. package/AGENTS.md +7 -7
  2. package/BACKLOG.md +4 -14
  3. package/CHANGELOG.md +13 -0
  4. package/README.md +7 -2
  5. package/dist/lib/execution-output.js +13 -2
  6. package/dist/lib/observability.js +9 -14
  7. package/dist/lib/registry.js +82 -117
  8. package/dist/lib/run-delivery.d.ts +1 -1
  9. package/dist/lib/run-delivery.js +146 -32
  10. package/dist/lib/run-ui-runtime.js +18 -27
  11. package/dist/lib/runs-process-windows-mi.d.ts +71 -0
  12. package/dist/lib/runs-process-windows-mi.js +146 -3
  13. package/dist/lib/tools-inspect.js +109 -59
  14. package/dist/lib/tools-local.js +16 -8
  15. package/dist/lib/tools-message.js +76 -65
  16. package/dist/lib/tools-response.d.ts +18 -0
  17. package/dist/lib/tools-response.js +88 -21
  18. package/dist/lib/tools-spawn.js +19 -12
  19. package/dist/skills/actors/SKILL.md +1 -1
  20. package/dist/skills/actors/references/diagnostics.md +3 -0
  21. package/dist/skills/actors/references/runs.md +1 -1
  22. package/docs/README.md +1 -0
  23. package/docs/actor-inspector.md +2 -2
  24. package/docs/agent-experience.md +51 -4
  25. package/docs/coordinator-delivery.md +2 -2
  26. package/docs/inactive-foundations-inventory.md +73 -0
  27. package/docs/inspection.md +9 -8
  28. package/docs/output-projection-map.md +19 -17
  29. package/docs/windows-process-observation.md +2 -2
  30. package/lib/execution-output.ts +13 -2
  31. package/lib/observability.ts +9 -11
  32. package/lib/registry.ts +89 -124
  33. package/lib/run-delivery.ts +130 -31
  34. package/lib/run-ui-runtime.ts +18 -34
  35. package/lib/runs-process-windows-mi.ts +167 -3
  36. package/lib/tools-inspect.ts +109 -59
  37. package/lib/tools-local.ts +26 -15
  38. package/lib/tools-message.ts +85 -58
  39. package/lib/tools-response.ts +97 -20
  40. package/lib/tools-spawn.ts +19 -12
  41. package/package.json +1 -1
  42. package/skills/actors/SKILL.md +1 -1
  43. package/skills/actors/references/diagnostics.md +3 -0
  44. package/skills/actors/references/runs.md +1 -1
@@ -82,6 +82,19 @@ function registrationNextActions(tool, source, callableNow) {
82
82
  : [recipeDoctorAction(source)]),
83
83
  ];
84
84
  }
85
+ const REGISTRY_METADATA_BUDGET = Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1;
86
+ /** Bare block-YAML registry document; builders own whole-value/omission policy and the byte budget. */
87
+ function registryMetadataText(value) {
88
+ return ToolsResponse.renderYamlMetadata(value, REGISTRY_METADATA_BUDGET).text;
89
+ }
90
+ /** One opaque selected scalar as a whole value or an explicit whole-field omission, never a clip. */
91
+ function registrySelected(key, value) {
92
+ return ToolsResponse.selectYamlField(key, value, REGISTRY_METADATA_BUDGET);
93
+ }
94
+ /** Grow whole selected fields in priority order while the complete document still fits. */
95
+ function growRegistryDocument(render, order) {
96
+ return ToolsResponse.growYamlDocument(render, order, REGISTRY_METADATA_BUDGET);
97
+ }
85
98
  /** Read-time text only: callers supply the original post-activation selections, not live ports. */
86
99
  function registrationReceiptText(data) {
87
100
  const budget = Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1;
@@ -144,78 +157,33 @@ function registryNoticeText(kind, name) {
144
157
  return ToolsResponse.formatMarkdownField("report", report) + "\n" + selected;
145
158
  }
146
159
  function registrationTransactionFailureText(stage, generation, summary, error) {
147
- const field = ToolsResponse.formatMarkdownField;
148
- const part = (key, value) => {
149
- const wellFormed = value.isWellFormed();
150
- const omitted = `- ${key}: [${wellFormed ? "omitted" : "unavailable"}]\n- ${key}_omission:\n - reason: ${wellFormed ? "response_too_large" : "malformed_selected_text"}\n - shown: 0\n - omitted: 1\n - total: 1`;
151
- const full = wellFormed ? field(key, value) : omitted;
152
- return { full, selected: Buffer.byteLength(full) <= Buffer.byteLength(omitted) ? full : omitted };
153
- };
154
- const selectedGeneration = part("resolution_generation", generation);
155
- const selectedSummary = part("active_skills_summary", summary);
156
- const selectedError = part("error", error);
157
- const render = () => [field("result", "Tool registration transaction failed."), field("stage", stage),
158
- selectedGeneration.selected, selectedSummary.selected, selectedError.selected].join("\n");
160
+ const selectedGeneration = registrySelected("resolution_generation", generation);
161
+ const selectedSummary = registrySelected("active_skills_summary", summary);
162
+ const selectedError = registrySelected("error", error);
163
+ const render = () => ({ result: "Tool registration transaction failed.", stage,
164
+ ...selectedGeneration.selected, ...selectedSummary.selected, ...selectedError.selected });
159
165
  // Keep a fitting surfaced error before large optional resolution metadata.
160
- for (const current of [selectedError, selectedGeneration, selectedSummary]) {
161
- if (current.selected === current.full)
162
- continue;
163
- const previous = current.selected;
164
- current.selected = current.full;
165
- if (Buffer.byteLength(render()) > Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1)
166
- current.selected = previous;
167
- }
168
- return render();
166
+ return growRegistryDocument(render, [selectedError, selectedGeneration, selectedSummary]);
169
167
  }
170
168
  function candidateAdmissionFailureText(data) {
171
- const field = ToolsResponse.formatMarkdownField;
172
- const part = (key, value, literal = false) => {
173
- const wellFormed = value.isWellFormed();
174
- const omitted = `- ${key}: [${wellFormed ? "omitted" : "unavailable"}]\n- ${key}_omission:\n - reason: ${wellFormed ? "response_too_large" : "malformed_selected_text"}\n - shown: 0\n - omitted: 1\n - total: 1`;
175
- const full = wellFormed ? field(key, literal ? ToolsResponse.formatLiteralBlock(value) : value) : omitted;
176
- return { full, selected: Buffer.byteLength(full) <= Buffer.byteLength(omitted) ? full : omitted };
177
- };
178
- const diagnostics = part("diagnostics_summary", data.diagnostics);
179
- const source = data.kind === "source" ? part("source", data.source, true) : undefined;
180
- const summary = data.kind === "source" ? part("active_skills_summary", data.summary) : undefined;
181
- const instruction = data.kind === "source" ? part("instruction", data.instruction) : undefined;
182
- const render = () => [field("field", "recipe"), ...(source ? [source.selected] : []),
183
- field("result", data.kind === "source" ? "Recipe source validation failed." : "Tool recipe validation failed."),
184
- diagnostics.selected, ...(summary ? [summary.selected] : []), ...(instruction ? [instruction.selected] : [])].join("\n");
169
+ const diagnostics = registrySelected("diagnostics_summary", data.diagnostics);
170
+ const source = data.kind === "source" ? registrySelected("source", data.source) : undefined;
171
+ const summary = data.kind === "source" ? registrySelected("active_skills_summary", data.summary) : undefined;
172
+ const instruction = data.kind === "source" ? registrySelected("instruction", data.instruction) : undefined;
173
+ const render = () => ({ field: "recipe", ...(source ? source.selected : {}),
174
+ result: data.kind === "source" ? "Recipe source validation failed." : "Tool recipe validation failed.",
175
+ ...diagnostics.selected, ...(summary ? summary.selected : {}), ...(instruction ? instruction.selected : {}) });
185
176
  // Preserve fitting diagnostics before large optional source/context/advice fields.
186
- for (const current of [diagnostics, source, summary, instruction]) {
187
- if (!current || current.selected === current.full)
188
- continue;
189
- const previous = current.selected;
190
- current.selected = current.full;
191
- if (Buffer.byteLength(render()) > Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1)
192
- current.selected = previous;
193
- }
194
- return render();
177
+ return growRegistryDocument(render, [diagnostics, ...(source ? [source] : []), ...(summary ? [summary] : []), ...(instruction ? [instruction] : [])]);
195
178
  }
196
179
  function sourceNormalizationFailureText(source, reason, summary, instruction) {
197
- const field = ToolsResponse.formatMarkdownField;
198
- const part = (key, value, literal = false) => {
199
- const wellFormed = value.isWellFormed();
200
- const omitted = `- ${key}: [${wellFormed ? "omitted" : "unavailable"}]\n- ${key}_omission:\n - reason: ${wellFormed ? "response_too_large" : "malformed_selected_text"}\n - shown: 0\n - omitted: 1\n - total: 1`;
201
- const full = wellFormed ? field(key, literal ? ToolsResponse.formatLiteralBlock(value) : value) : omitted;
202
- return { full, selected: Buffer.byteLength(full) <= Buffer.byteLength(omitted) ? full : omitted };
203
- };
204
- const selectedSource = part("source", source, true);
205
- const selectedReason = part("reason", reason);
206
- const selectedSummary = part("active_skills_summary", summary);
207
- const selectedInstruction = part("instruction", instruction);
208
- const render = () => [field("field", "from"), selectedSource.selected, field("result", "Recipe source is invalid."),
209
- selectedReason.selected, selectedSummary.selected, selectedInstruction.selected].join("\n");
210
- for (const current of [selectedSource, selectedReason, selectedSummary, selectedInstruction]) {
211
- if (current.selected === current.full)
212
- continue;
213
- const previous = current.selected;
214
- current.selected = current.full;
215
- if (Buffer.byteLength(render()) > Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1)
216
- current.selected = previous;
217
- }
218
- return render();
180
+ const selectedSource = registrySelected("source", source);
181
+ const selectedReason = registrySelected("reason", reason);
182
+ const selectedSummary = registrySelected("active_skills_summary", summary);
183
+ const selectedInstruction = registrySelected("instruction", instruction);
184
+ const render = () => ({ field: "from", ...selectedSource.selected, result: "Recipe source is invalid.",
185
+ ...selectedReason.selected, ...selectedSummary.selected, ...selectedInstruction.selected });
186
+ return growRegistryDocument(render, [selectedSource, selectedReason, selectedSummary, selectedInstruction]);
219
187
  }
220
188
  function activeSkillSummary(resolutionContext) {
221
189
  const names = Object.keys(RecipesReferences.getActiveSkillRecipeNamespaces(resolutionContext.activeSkills))
@@ -224,17 +192,11 @@ function activeSkillSummary(resolutionContext) {
224
192
  return names.length > 0 ? names.join(", ") : "<none>";
225
193
  }
226
194
  function draftPathFailureText(kind, reference) {
227
- const key = kind === "root" ? "allowed_root" : "path";
228
- const render = (selected) => "- field: draft\n" + selected + (kind === "root"
229
- ? "\n- result: Draft must be under the allowed root.\n- instruction: Use inspect target=recipes view=summary to list drafts."
230
- : "\n- result: Draft not found.");
231
- const wellFormed = reference.isWellFormed();
232
- if (wellFormed) {
233
- const complete = render(ToolsResponse.formatMarkdownField(key, ToolsResponse.formatLiteralBlock(reference)));
234
- if (Buffer.byteLength(complete) <= Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1)
235
- return complete;
236
- }
237
- return render(`- ${key}: [${wellFormed ? "omitted" : "unavailable"}]\n- ${key}_omission:\n - reason: ${wellFormed ? "response_too_large" : "malformed_selected_text"}\n - shown: 0\n - omitted: 1\n - total: 1`);
195
+ const selected = registrySelected(kind === "root" ? "allowed_root" : "path", reference);
196
+ const render = () => ({ field: "draft", ...selected.selected,
197
+ result: kind === "root" ? "Draft must be under the allowed root." : "Draft not found.",
198
+ ...(kind === "root" ? { instruction: "Use inspect target=recipes view=summary to list drafts." } : {}) });
199
+ return growRegistryDocument(render, [selected]);
238
200
  }
239
201
  function assertDraftPath(deps, draft) {
240
202
  const draftRoot = resolve(getRecipeRoot(deps), "drafts");
@@ -278,26 +240,15 @@ function draftReceiptText(result, tool, callable, next) {
278
240
  return render().text;
279
241
  }
280
242
  function duplicateRegistrationText(value) {
281
- const render = (selected) => "- field: name\n" + selected + "\n- result: Tool already registered.\n- instruction: Use update=true to overwrite.";
282
- const wellFormed = value.isWellFormed();
283
- if (wellFormed) {
284
- const complete = render(ToolsResponse.formatMarkdownField("value", value));
285
- if (Buffer.byteLength(complete) <= Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1)
286
- return complete;
287
- }
288
- return render(`- value: [${wellFormed ? "omitted" : "unavailable"}]\n- value_omission:\n - reason: ${wellFormed ? "response_too_large" : "malformed_selected_text"}\n - shown: 0\n - omitted: 1\n - total: 1`);
243
+ const selected = registrySelected("value", value);
244
+ const render = () => ({ field: "name", ...selected.selected,
245
+ result: "Tool already registered.", instruction: "Use update=true to overwrite." });
246
+ return growRegistryDocument(render, [selected]);
289
247
  }
290
248
  function draftRecipeFailureText(key, value) {
291
- const header = "- field: draft\n- result: Draft recipe is invalid.";
292
- if (value === undefined)
293
- return header;
294
- const wellFormed = value.isWellFormed();
295
- if (wellFormed) {
296
- const complete = header + "\n" + ToolsResponse.formatMarkdownField(key, value);
297
- if (Buffer.byteLength(complete) <= Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1)
298
- return complete;
299
- }
300
- return header + `\n- ${key}: [${wellFormed ? "omitted" : "unavailable"}]\n- ${key}_omission:\n - reason: ${wellFormed ? "response_too_large" : "malformed_selected_text"}\n - shown: 0\n - omitted: 1\n - total: 1`;
249
+ const selected = value === undefined ? undefined : registrySelected(key, value);
250
+ const render = () => ({ field: "draft", result: "Draft recipe is invalid.", ...(selected ? selected.selected : {}) });
251
+ return growRegistryDocument(render, selected ? [selected] : []);
301
252
  }
302
253
  function promoteDraftRecipe(name, input, ctx, deps) {
303
254
  const draftPath = assertDraftPath(deps, String(input.draft ?? ""));
@@ -438,7 +389,9 @@ function assertTemplateIsNotNestedRecipe(value) {
438
389
  looksLikeRecipeReference(record.template) &&
439
390
  (Object.keys(record).length === 1 ||
440
391
  ["artifacts", "async", "control", "description", "imports", "values"].some((key) => Object.hasOwn(record, key)))) {
441
- throw new Error(ExecutionOutput.formatToolText("- field: template\n- result: Nested Recipe-shaped templates are not a register_tool source mode.\n- instruction: retry with from=<skill>/<recipe> and defaults={...}."));
392
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "template",
393
+ result: "Nested Recipe-shaped templates are not a register_tool source mode.",
394
+ instruction: "retry with from=<skill>/<recipe> and defaults={...}." })));
442
395
  }
443
396
  }
444
397
  function getInputTemplate(value) {
@@ -452,14 +405,15 @@ function getInputTemplate(value) {
452
405
  template: value,
453
406
  });
454
407
  if (steps.length === 0)
455
- throw new Error(ExecutionOutput.formatToolText("- field: template\n- result: Tool template sequence is empty."));
408
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "template", result: "Tool template sequence is empty." })));
456
409
  return value;
457
410
  }
458
411
  if (value && typeof value === "object") {
459
412
  CommandTemplates.expandCommandTemplateConfigs(value);
460
413
  return value;
461
414
  }
462
- throw new Error(ExecutionOutput.formatToolText("- field: template\n- result: unsupported template type\n- supported_types:\n - string\n - object\n - sequence"));
415
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "template", result: "unsupported template type",
416
+ supported_types: ["string", "object", "sequence"] })));
463
417
  }
464
418
  function getRegistrationResolutionContext(ctx, deps) {
465
419
  const runtimeContext = deps.getRecipeResolutionContext?.();
@@ -476,7 +430,7 @@ function normalizeDefaults(value) {
476
430
  if (value === undefined)
477
431
  return undefined;
478
432
  if (!value || typeof value !== "object" || Array.isArray(value)) {
479
- throw new Error(ExecutionOutput.formatToolText("- field: defaults\n- result: Tool defaults must be an object."));
433
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "defaults", result: "Tool defaults must be an object." })));
480
434
  }
481
435
  return { ...value };
482
436
  }
@@ -508,13 +462,17 @@ function buildAuthoredRecipe(input, existing, existingRecipe) {
508
462
  const from = typeof input.from === "string" ? input.from.trim() : "";
509
463
  const description = (input.description ?? existing?.description ?? "").trim();
510
464
  if (!description && !from) {
511
- throw new Error(ExecutionOutput.formatToolText("- field: description\n- result: Tool description is required for command-template registration."));
465
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "description",
466
+ result: "Tool description is required for command-template registration." })));
512
467
  }
513
468
  const inputDefaults = normalizeDefaults(input.defaults);
514
469
  if (from) {
515
470
  const runtimeOwnedDefault = Object.keys(inputDefaults ?? {}).find((key) => RecipesReferences.isRuntimeOwnedRecipeInput(key));
516
471
  if (runtimeOwnedDefault) {
517
- throw new Error(ExecutionOutput.formatToolText(`- field: defaults\n- key: ${runtimeOwnedDefault}\n- result: Tool defaults cannot set runtime-owned input.\n- instruction: remove that default and retry register_tool; the runtime supplies it.`));
472
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "defaults",
473
+ ...registrySelected("key", runtimeOwnedDefault).selected,
474
+ result: "Tool defaults cannot set runtime-owned input.",
475
+ instruction: "remove that default and retry register_tool; the runtime supplies it." })));
518
476
  }
519
477
  const authored = {
520
478
  ...(description ? { description } : {}),
@@ -530,13 +488,13 @@ function buildAuthoredRecipe(input, existing, existingRecipe) {
530
488
  }
531
489
  const template = getInputTemplate(input.template);
532
490
  if (template === null) {
533
- throw new Error(ExecutionOutput.formatToolText("- field: template\n- result: Tool template cannot be null here."));
491
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "template", result: "Tool template cannot be null here." })));
534
492
  }
535
493
  const finalTemplate = template === undefined || template === ""
536
494
  ? existingRecipe?.template ?? existing?.template
537
495
  : template;
538
496
  if (!finalTemplate) {
539
- throw new Error(ExecutionOutput.formatToolText("- field: template\n- result: Tool template is required."));
497
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "template", result: "Tool template is required." })));
540
498
  }
541
499
  const authored = {
542
500
  ...(existingRecipe ?? {}),
@@ -564,33 +522,38 @@ function buildAuthoredRecipe(input, existing, existingRecipe) {
564
522
  function assertRegisterToolInputModes(input) {
565
523
  const record = input;
566
524
  if (Object.hasOwn(record, "values")) {
567
- throw new Error(ExecutionOutput.formatToolText("- field: values\n- result: register_tool values was removed.\n- replacement_fields:\n - defaults\n - from\n- instruction: retry register_tool with defaults for caller inputs, or use from=<skill>/<recipe> for maintained composition."));
525
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "values", result: "register_tool values was removed.",
526
+ replacement_fields: ["defaults", "from"],
527
+ instruction: "retry register_tool with defaults for caller inputs, or use from=<skill>/<recipe> for maintained composition." })));
568
528
  }
569
529
  const fromProvided = Object.hasOwn(record, "from");
570
530
  if (fromProvided &&
571
531
  (typeof input.from !== "string" || input.from.trim().length === 0)) {
572
- throw new Error(ExecutionOutput.formatToolText("- field: from\n- result: Tool from must be a non-empty Recipe reference.\n- reference_forms:\n - <skill>/<recipe>\n - explicit .json path\n - explicit .md path\n- instruction: retry register_tool with from=<skill>/<recipe> or an explicit .json/.md path."));
532
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "from",
533
+ result: "Tool from must be a non-empty Recipe reference.",
534
+ reference_forms: ["<skill>/<recipe>", "explicit .json path", "explicit .md path"],
535
+ instruction: "retry register_tool with from=<skill>/<recipe> or an explicit .json/.md path." })));
573
536
  }
574
537
  const draftProvided = typeof input.draft === "string" && input.draft.trim().length > 0;
575
538
  const templateProvided = Object.hasOwn(record, "template");
576
539
  const modeCount = Number(fromProvided) + Number(draftProvided) + Number(templateProvided);
577
540
  if (modeCount > 1) {
578
- throw new Error(ExecutionOutput.formatToolText("- result: Use exactly one register_tool source mode.\n- source_modes:\n - from\n - template\n - draft\n- instruction: remove the extra source fields and retry register_tool."));
541
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ result: "Use exactly one register_tool source mode.",
542
+ source_modes: ["from", "template", "draft"],
543
+ instruction: "remove the extra source fields and retry register_tool." })));
579
544
  }
580
545
  if (fromProvided &&
581
546
  (Object.hasOwn(record, "args") || Object.hasOwn(record, "async"))) {
582
- throw new Error(ExecutionOutput.formatToolText("- field: from\n- result: register_tool from inherits args and async behavior.\n- inherited_fields:\n - args\n - async\n- instruction: retry register_tool with from and optional defaults only; omit args and async."));
547
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "from",
548
+ result: "register_tool from inherits args and async behavior.",
549
+ inherited_fields: ["args", "async"],
550
+ instruction: "retry register_tool with from and optional defaults only; omit args and async." })));
583
551
  }
584
552
  }
585
553
  function reservedRegistrationNameText(value) {
586
- const render = (selected) => "- field: name\n" + selected + "\n- result: Reserved tool name.";
587
- const wellFormed = value.isWellFormed();
588
- if (wellFormed) {
589
- const complete = render(ToolsResponse.formatMarkdownField("value", value));
590
- if (Buffer.byteLength(complete) <= Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1)
591
- return complete;
592
- }
593
- return render(`- value: [${wellFormed ? "omitted" : "unavailable"}]\n- value_omission:\n - reason: ${wellFormed ? "response_too_large" : "malformed_selected_text"}\n - shown: 0\n - omitted: 1\n - total: 1`);
554
+ const selected = registrySelected("value", value);
555
+ const render = () => ({ field: "name", ...selected.selected, result: "Reserved tool name." });
556
+ return growRegistryDocument(render, [selected]);
594
557
  }
595
558
  function executeRegisterToolUnlocked(params, ctx, deps) {
596
559
  const rawInput = params && typeof params === "object"
@@ -602,7 +565,7 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
602
565
  return listTools(deps);
603
566
  const name = Identity.normalizeToolName(input.name);
604
567
  if (!name)
605
- throw new Error(ExecutionOutput.formatToolText("- field: name\n- result: Invalid tool name."));
568
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "name", result: "Invalid tool name." })));
606
569
  if (deps.reservedToolNames.has(name)) {
607
570
  throw new Error(ExecutionOutput.formatToolText(reservedRegistrationNameText(`${name}`)));
608
571
  }
@@ -640,7 +603,9 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
640
603
  throw new Error(ExecutionOutput.formatToolText(duplicateRegistrationText(`${name}`)));
641
604
  }
642
605
  if (template === undefined && !input.from && !existing) {
643
- throw new Error(ExecutionOutput.formatToolText("- result: New registration requires exactly one source mode.\n- source_modes:\n - from\n - template\n - draft\n- instruction: retry register_tool with one source field."));
606
+ throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ result: "New registration requires exactly one source mode.",
607
+ source_modes: ["from", "template", "draft"],
608
+ instruction: "retry register_tool with one source field." })));
644
609
  }
645
610
  const recipePath = getToolRecipePath(deps, name);
646
611
  const authoredRecipe = buildAuthoredRecipe(input, existing, authoritative.recipe);
@@ -66,7 +66,7 @@ export interface RunCompletionBatch {
66
66
  /** Retained singleton capture; absence preserves older indexed bytes. Never a new-capture selector. */
67
67
  readonly single_result?: true;
68
68
  /** Captured record-list shape; no public format/version choice or source authority. */
69
- readonly result_layout?: "records" | "run_headers" | "headings" | "headings_flat_omissions" | "headings_outcomes" | "headings_shared_results" | "headings_shared_kinds" | "frontmatter_v1" | "frontmatter_v2" | "completion_yaml_core_v1";
69
+ readonly result_layout?: "records" | "run_headers" | "headings" | "headings_flat_omissions" | "headings_outcomes" | "headings_shared_results" | "headings_shared_kinds" | "frontmatter_v1" | "frontmatter_v2" | "completion_yaml_core_v1" | "completion_yaml_files_v1";
70
70
  /** Immutable scope/order/range data, not a caller-selected format or allocation authority. */
71
71
  readonly numbering?: RunCompletionNumbering;
72
72
  /** Formatting version/data only; no recipient ownership, read or publication capability. */