@llblab/pi-actors 0.55.0 → 0.56.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.
- package/AGENTS.md +108 -20
- package/BACKLOG.md +198 -4
- package/CHANGELOG.md +17 -0
- package/README.md +31 -1
- package/dist/index.js +1 -1
- package/dist/lib/async-runs.d.ts +37 -0
- package/dist/lib/async-runs.js +131 -62
- package/dist/lib/automatic-review-runtime.d.ts +2 -0
- package/dist/lib/automatic-review-runtime.js +3 -2
- package/dist/lib/command-templates.d.ts +37 -0
- package/dist/lib/command-templates.js +263 -129
- package/dist/lib/execution-files.d.ts +32 -0
- package/dist/lib/execution-files.js +128 -0
- package/dist/lib/execution-output.js +5 -4
- package/dist/lib/execution-sessions.d.ts +19 -1
- package/dist/lib/execution-sessions.js +62 -26
- package/dist/lib/execution.d.ts +4 -1
- package/dist/lib/execution.js +6 -1
- package/dist/lib/extension-runtime.d.ts +9 -2
- package/dist/lib/extension-runtime.js +92 -14
- package/dist/lib/file-state.js +21 -2
- package/dist/lib/inspector-command.js +2 -2
- package/dist/lib/inspector-overlay.d.ts +25 -7
- package/dist/lib/inspector-overlay.js +562 -262
- package/dist/lib/inspector.d.ts +20 -10
- package/dist/lib/inspector.js +80 -91
- package/dist/lib/limits.d.ts +1 -0
- package/dist/lib/limits.js +1 -0
- package/dist/lib/observability.d.ts +15 -1
- package/dist/lib/observability.js +216 -99
- package/dist/lib/pi.d.ts +5 -4
- package/dist/lib/pi.js +64 -10
- package/dist/lib/recipe-projection.d.ts +18 -0
- package/dist/lib/recipe-projection.js +220 -0
- package/dist/lib/recipes-context.d.ts +2 -0
- package/dist/lib/recipes-context.js +30 -6
- package/dist/lib/registry.js +280 -36
- package/dist/lib/run-delivery.d.ts +213 -5
- package/dist/lib/run-delivery.js +1909 -40
- package/dist/lib/run-supervision.d.ts +107 -0
- package/dist/lib/run-supervision.js +412 -0
- package/dist/lib/run-ui-runtime.d.ts +9 -2
- package/dist/lib/run-ui-runtime.js +283 -60
- package/dist/lib/runs-artifacts.d.ts +26 -1
- package/dist/lib/runs-artifacts.js +68 -2
- package/dist/lib/runs-context-exports.d.ts +451 -0
- package/dist/lib/runs-context-exports.js +2315 -0
- package/dist/lib/runs-context-index.d.ts +97 -0
- package/dist/lib/runs-context-index.js +368 -0
- package/dist/lib/runs-control-delivery.js +46 -7
- package/dist/lib/runs-control.d.ts +78 -2
- package/dist/lib/runs-control.js +334 -2
- package/dist/lib/runs-controls.js +4 -1
- package/dist/lib/runs-descendant-launches.d.ts +80 -0
- package/dist/lib/runs-descendant-launches.js +287 -0
- package/dist/lib/runs-execution-evidence.d.ts +110 -0
- package/dist/lib/runs-execution-evidence.js +282 -0
- package/dist/lib/runs-index.d.ts +66 -1
- package/dist/lib/runs-index.js +349 -13
- package/dist/lib/runs-native-launches.d.ts +73 -0
- package/dist/lib/runs-native-launches.js +227 -0
- package/dist/lib/runs-outcomes.d.ts +141 -0
- package/dist/lib/runs-outcomes.js +292 -0
- package/dist/lib/runs-ownership.d.ts +10 -1
- package/dist/lib/runs-ownership.js +36 -4
- package/dist/lib/runs-process-windows-mi.d.ts +46 -0
- package/dist/lib/runs-process-windows-mi.js +114 -0
- package/dist/lib/runs-process.d.ts +34 -1
- package/dist/lib/runs-process.js +158 -26
- package/dist/lib/runs-results.d.ts +116 -0
- package/dist/lib/runs-results.js +518 -0
- package/dist/lib/runs-retention.d.ts +15 -2
- package/dist/lib/runs-retention.js +148 -9
- package/dist/lib/runs-session-exports.d.ts +95 -0
- package/dist/lib/runs-session-exports.js +470 -0
- package/dist/lib/runs-snapshot.d.ts +58 -0
- package/dist/lib/runs-snapshot.js +92 -0
- package/dist/lib/runs-start.d.ts +2 -0
- package/dist/lib/runs-start.js +44 -3
- package/dist/lib/runs-status.d.ts +15 -1
- package/dist/lib/runs-status.js +337 -13
- package/dist/lib/runs-supervision.d.ts +105 -0
- package/dist/lib/runs-supervision.js +501 -0
- package/dist/lib/runs-trace.d.ts +1 -0
- package/dist/lib/runs-trace.js +14 -3
- package/dist/lib/runtime.js +22 -3
- package/dist/lib/session-evidence.d.ts +37 -0
- package/dist/lib/session-evidence.js +59 -3
- package/dist/lib/state-readers.d.ts +4 -1
- package/dist/lib/state-readers.js +14 -8
- package/dist/lib/temp.d.ts +2 -4
- package/dist/lib/temp.js +4 -56
- package/dist/lib/tools-access.d.ts +3 -0
- package/dist/lib/tools-access.js +13 -0
- package/dist/lib/tools-inspect.d.ts +1 -0
- package/dist/lib/tools-inspect.js +110 -43
- package/dist/lib/tools-local.d.ts +3 -0
- package/dist/lib/tools-local.js +18 -6
- package/dist/lib/tools-message.d.ts +4 -1
- package/dist/lib/tools-message.js +126 -31
- package/dist/lib/tools-response.d.ts +31 -3
- package/dist/lib/tools-response.js +311 -47
- package/dist/lib/tools-spawn.d.ts +3 -0
- package/dist/lib/tools-spawn.js +29 -7
- package/dist/lib/trace-projection.d.ts +20 -0
- package/dist/lib/trace-projection.js +192 -43
- package/dist/scripts/async-runner.mjs +272 -194
- package/dist/scripts/conformance.mjs +14 -2
- package/dist/skills/actors/SKILL.md +46 -2
- package/dist/skills/actors/references/diagnostics.md +40 -0
- package/dist/skills/actors/references/runs.md +55 -1
- package/docs/README.md +9 -1
- package/docs/actor-inspector.md +84 -15
- package/docs/agent-experience.md +216 -0
- package/docs/async-runs.md +18 -2
- package/docs/composition-transport.md +103 -0
- package/docs/coordinator-delivery.md +204 -4
- package/docs/inspection.md +38 -2
- package/docs/output-projection-map.md +130 -0
- package/docs/releasing.md +19 -2
- package/docs/run-supervision.md +1622 -0
- package/docs/template-recipes.md +4 -0
- package/docs/windows-process-observation.md +248 -0
- package/index.ts +1 -1
- package/lib/async-runs.ts +164 -73
- package/lib/automatic-review-runtime.ts +4 -2
- package/lib/command-templates.ts +287 -138
- package/lib/execution-files.ts +118 -0
- package/lib/execution-output.ts +4 -4
- package/lib/execution-sessions.ts +57 -27
- package/lib/execution.ts +8 -0
- package/lib/extension-runtime.ts +102 -12
- package/lib/file-state.ts +16 -2
- package/lib/inspector-command.ts +2 -2
- package/lib/inspector-overlay.ts +524 -261
- package/lib/inspector.ts +101 -130
- package/lib/limits.ts +1 -0
- package/lib/observability.ts +235 -116
- package/lib/pi.ts +59 -11
- package/lib/recipe-projection.ts +232 -0
- package/lib/recipes-context.ts +27 -6
- package/lib/registry.ts +275 -36
- package/lib/run-delivery.ts +1737 -49
- package/lib/run-supervision.ts +411 -0
- package/lib/run-ui-runtime.ts +237 -73
- package/lib/runs-artifacts.ts +73 -1
- package/lib/runs-context-exports.ts +1871 -0
- package/lib/runs-context-index.ts +372 -0
- package/lib/runs-control-delivery.ts +36 -18
- package/lib/runs-control.ts +297 -1
- package/lib/runs-controls.ts +3 -1
- package/lib/runs-descendant-launches.ts +338 -0
- package/lib/runs-execution-evidence.ts +302 -0
- package/lib/runs-index.ts +345 -17
- package/lib/runs-native-launches.ts +270 -0
- package/lib/runs-outcomes.ts +377 -0
- package/lib/runs-ownership.ts +37 -4
- package/lib/runs-process-windows-mi.ts +113 -0
- package/lib/runs-process.ts +210 -34
- package/lib/runs-results.ts +601 -0
- package/lib/runs-retention.ts +134 -10
- package/lib/runs-session-exports.ts +406 -0
- package/lib/runs-snapshot.ts +143 -0
- package/lib/runs-start.ts +44 -2
- package/lib/runs-status.ts +252 -10
- package/lib/runs-supervision.ts +394 -0
- package/lib/runs-trace.ts +14 -3
- package/lib/runtime.ts +22 -3
- package/lib/session-evidence.ts +76 -4
- package/lib/state-readers.ts +16 -7
- package/lib/temp.ts +3 -56
- package/lib/tools-access.ts +13 -0
- package/lib/tools-inspect.ts +110 -51
- package/lib/tools-local.ts +37 -24
- package/lib/tools-message.ts +120 -37
- package/lib/tools-response.ts +273 -50
- package/lib/tools-spawn.ts +31 -10
- package/lib/trace-projection.ts +165 -42
- package/package.json +10 -6
- package/scripts/async-runner.mjs +272 -194
- package/scripts/conformance.mjs +14 -2
- package/skills/actors/SKILL.md +46 -2
- package/skills/actors/references/diagnostics.md +40 -0
- package/skills/actors/references/runs.md +55 -1
- package/banner.jpg +0 -0
- package/dist/lib/inspector-actions.d.ts +0 -16
- package/dist/lib/inspector-actions.js +0 -57
- package/lib/inspector-actions.ts +0 -79
package/lib/registry.ts
CHANGED
|
@@ -16,11 +16,13 @@ import {
|
|
|
16
16
|
writeTextAtomic,
|
|
17
17
|
} from "./file-state.ts";
|
|
18
18
|
import * as Identity from "./identity.ts";
|
|
19
|
+
import * as Limits from "./limits.ts";
|
|
19
20
|
import * as Paths from "./paths.ts";
|
|
20
21
|
import * as RecipesContext from "./recipes-context.ts";
|
|
21
22
|
import * as RecipesDiscovery from "./recipes-discovery.ts";
|
|
22
23
|
import * as RecipesReferences from "./recipes-references.ts";
|
|
23
24
|
import * as Schema from "./schema.ts";
|
|
25
|
+
import * as ToolsResponse from "./tools-response.ts";
|
|
24
26
|
|
|
25
27
|
export interface RegisterToolInput {
|
|
26
28
|
name?: string;
|
|
@@ -89,17 +91,32 @@ function textContent(text: string) {
|
|
|
89
91
|
return { type: "text" as const, text };
|
|
90
92
|
}
|
|
91
93
|
|
|
94
|
+
function registryListText(rows: readonly string[]): string {
|
|
95
|
+
const budget = Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1;
|
|
96
|
+
const coverage = (shown: number, reason?: string) => ({ ...(reason ? { reason } : {}), shown, omitted: rows.length - shown, total: rows.length });
|
|
97
|
+
const malformed = rows.some(row => !row.isWellFormed());
|
|
98
|
+
if (!malformed) {
|
|
99
|
+
// Remove only the compiler prefix after the original key coercion and join.
|
|
100
|
+
const complete = ToolsResponse.renderYamlMetadata({ registered_tools: rows.map(row => row.slice(2)), registered_tools_coverage: coverage(rows.length) }, budget);
|
|
101
|
+
if (complete.state === "available") return complete.text;
|
|
102
|
+
}
|
|
103
|
+
const fallback = ToolsResponse.renderYamlMetadata({ registered_tools: malformed ? "[unavailable]" : "[omitted]", registered_tools_coverage: coverage(0, malformed ? "malformed_selected_text" : "response_too_large") }, budget);
|
|
104
|
+
// Fixed keys/reasons and finite array-length counts are bounded far below budget.
|
|
105
|
+
return (fallback as Extract<ToolsResponse.YamlMetadataRendering, { state: "available" }>).text;
|
|
106
|
+
}
|
|
107
|
+
|
|
92
108
|
function listTools<TContext>(
|
|
93
109
|
deps: RegisterToolRuntimeDeps<TContext>,
|
|
94
110
|
): RegisterToolResult {
|
|
95
111
|
const names = [...deps.getTools().keys()].sort();
|
|
112
|
+
const rows = names.length > 0 ? names.map((name) => `- ${name}`) : [];
|
|
113
|
+
// Retain the original conditional map/join observations before read-time projection.
|
|
114
|
+
void (names.length > 0 ? `Registered tools:\n${rows.join("\n")}` : "No registered tools.");
|
|
96
115
|
return {
|
|
97
116
|
content: [
|
|
98
117
|
textContent(
|
|
99
118
|
ExecutionOutput.formatToolText(
|
|
100
|
-
|
|
101
|
-
? `Registered tools:\n${names.map((name) => `- ${name}`).join("\n")}`
|
|
102
|
-
: "No registered tools.",
|
|
119
|
+
registryListText(rows),
|
|
103
120
|
),
|
|
104
121
|
),
|
|
105
122
|
],
|
|
@@ -155,6 +172,139 @@ function registrationNextActions(
|
|
|
155
172
|
];
|
|
156
173
|
}
|
|
157
174
|
|
|
175
|
+
/** Read-time text only: callers supply the original post-activation selections, not live ports. */
|
|
176
|
+
function registrationReceiptText(data: {
|
|
177
|
+
tool: string; result: "registered" | "updated" | "persisted"; source: string; callable: boolean;
|
|
178
|
+
boundary?: string; required: readonly unknown[]; optional: readonly unknown[];
|
|
179
|
+
warnings: readonly unknown[]; next: string;
|
|
180
|
+
}): string {
|
|
181
|
+
const budget = Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1;
|
|
182
|
+
const renderPart = (value: Record<string, unknown>) => ToolsResponse.renderYamlMetadata(value, budget);
|
|
183
|
+
const omission = (key: string, count: number, malformed: boolean): Record<string, unknown> => ({
|
|
184
|
+
[key]: malformed ? "[unavailable]" : "[omitted]",
|
|
185
|
+
[key + "_omission"]: { reason: malformed ? "malformed_selected_text" : "response_too_large", shown: 0, omitted: count, total: count },
|
|
186
|
+
});
|
|
187
|
+
const part = (full: Record<string, unknown>, omitted: Record<string, unknown>) => {
|
|
188
|
+
const complete = renderPart(full), fallback = renderPart(omitted);
|
|
189
|
+
return { full, selected: complete.state === "available" && fallback.state === "available" && Buffer.byteLength(complete.text) <= Buffer.byteLength(fallback.text) ? full : omitted };
|
|
190
|
+
};
|
|
191
|
+
const scalar = (key: string, value: string) => {
|
|
192
|
+
const wellFormed = value.isWellFormed();
|
|
193
|
+
const omitted = omission(key, 1, !wellFormed);
|
|
194
|
+
return part(wellFormed ? { [key]: value } : omitted, omitted);
|
|
195
|
+
};
|
|
196
|
+
const sequence = (key: string, values: readonly unknown[]) => {
|
|
197
|
+
const rows: string[] = [];
|
|
198
|
+
let malformed = false;
|
|
199
|
+
for (let index = 0; index < values.length; index++) {
|
|
200
|
+
const value = values[index];
|
|
201
|
+
if (typeof value !== "string" || !value.isWellFormed()) { malformed = true; break; }
|
|
202
|
+
rows.push(value);
|
|
203
|
+
}
|
|
204
|
+
const omitted = omission(key, values.length, malformed);
|
|
205
|
+
return part(malformed ? omitted : { [key]: rows }, omitted);
|
|
206
|
+
};
|
|
207
|
+
const tool = scalar("tool", data.tool);
|
|
208
|
+
const source = scalar("source", data.source);
|
|
209
|
+
const required = sequence("required_args", data.required), optional = sequence("optional_args", data.optional);
|
|
210
|
+
const warnings = data.warnings.length ? sequence("warnings", data.warnings) : undefined;
|
|
211
|
+
const nextWellFormed = data.next.isWellFormed();
|
|
212
|
+
const omittedNext = omission("next_action", 1, !nextWellFormed);
|
|
213
|
+
// This producer knows only its existing status hint; invocation advice stays opaque.
|
|
214
|
+
const next = part(nextWellFormed
|
|
215
|
+
? data.callable ? { instruction: data.next } : { next: { tool: "inspect", target: `tool:${data.tool}`, view: "status" } }
|
|
216
|
+
: omittedNext, omittedNext);
|
|
217
|
+
const render = () => renderPart({ ...tool.selected, result: data.result, ...source.selected, callable_now: data.callable,
|
|
218
|
+
...(data.boundary === undefined ? {} : { activation_boundary: data.boundary }), ...required.selected, ...optional.selected,
|
|
219
|
+
...(warnings ? warnings.selected : {}), ...next.selected });
|
|
220
|
+
// Preserve complete safety notes before large argument lists; all seeds are monotone.
|
|
221
|
+
for (const current of [...(warnings ? [warnings] : []), tool, source, next, required, optional]) {
|
|
222
|
+
if (current.selected === current.full) continue;
|
|
223
|
+
const previous = current.selected;
|
|
224
|
+
current.selected = current.full;
|
|
225
|
+
if (render().state !== "available") current.selected = previous;
|
|
226
|
+
}
|
|
227
|
+
return (render() as Extract<ToolsResponse.YamlMetadataRendering, { state: "available" }>).text;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function registryNoticeText(kind: "activated" | "promoted" | "deleted", name: string): string {
|
|
231
|
+
const report = { activated: "Tool activated", promoted: "Promoted draft recipe", deleted: "Deleted tool" }[kind];
|
|
232
|
+
const selected = name.isWellFormed() ? ToolsResponse.formatMarkdownField("tool", name)
|
|
233
|
+
: "- tool: [unavailable]\n- tool_omission:\n - reason: malformed_selected_text\n - shown: 0\n - omitted: 1\n - total: 1";
|
|
234
|
+
return ToolsResponse.formatMarkdownField("report", report) + "\n" + selected;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function registrationTransactionFailureText(stage: string, generation: string, summary: string, error: string): string {
|
|
238
|
+
const field = ToolsResponse.formatMarkdownField;
|
|
239
|
+
const part = (key: string, value: string) => {
|
|
240
|
+
const wellFormed = value.isWellFormed();
|
|
241
|
+
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`;
|
|
242
|
+
const full = wellFormed ? field(key, value) : omitted;
|
|
243
|
+
return { full, selected: Buffer.byteLength(full) <= Buffer.byteLength(omitted) ? full : omitted };
|
|
244
|
+
};
|
|
245
|
+
const selectedGeneration = part("resolution_generation", generation);
|
|
246
|
+
const selectedSummary = part("active_skills_summary", summary);
|
|
247
|
+
const selectedError = part("error", error);
|
|
248
|
+
const render = () => [field("result", "Tool registration transaction failed."), field("stage", stage),
|
|
249
|
+
selectedGeneration.selected, selectedSummary.selected, selectedError.selected].join("\n");
|
|
250
|
+
// Keep a fitting surfaced error before large optional resolution metadata.
|
|
251
|
+
for (const current of [selectedError, selectedGeneration, selectedSummary]) {
|
|
252
|
+
if (current.selected === current.full) continue;
|
|
253
|
+
const previous = current.selected;
|
|
254
|
+
current.selected = current.full;
|
|
255
|
+
if (Buffer.byteLength(render()) > Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1) current.selected = previous;
|
|
256
|
+
}
|
|
257
|
+
return render();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function candidateAdmissionFailureText(data: { kind: "source"; source: string; diagnostics: string; summary: string; instruction: string } | { kind: "recipe"; diagnostics: string }): string {
|
|
261
|
+
const field = ToolsResponse.formatMarkdownField;
|
|
262
|
+
const part = (key: string, value: string, literal = false) => {
|
|
263
|
+
const wellFormed = value.isWellFormed();
|
|
264
|
+
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`;
|
|
265
|
+
const full = wellFormed ? field(key, literal ? ToolsResponse.formatLiteralBlock(value) : value) : omitted;
|
|
266
|
+
return { full, selected: Buffer.byteLength(full) <= Buffer.byteLength(omitted) ? full : omitted };
|
|
267
|
+
};
|
|
268
|
+
const diagnostics = part("diagnostics_summary", data.diagnostics);
|
|
269
|
+
const source = data.kind === "source" ? part("source", data.source, true) : undefined;
|
|
270
|
+
const summary = data.kind === "source" ? part("active_skills_summary", data.summary) : undefined;
|
|
271
|
+
const instruction = data.kind === "source" ? part("instruction", data.instruction) : undefined;
|
|
272
|
+
const render = () => [field("field", "recipe"), ...(source ? [source.selected] : []),
|
|
273
|
+
field("result", data.kind === "source" ? "Recipe source validation failed." : "Tool recipe validation failed."),
|
|
274
|
+
diagnostics.selected, ...(summary ? [summary.selected] : []), ...(instruction ? [instruction.selected] : [])].join("\n");
|
|
275
|
+
// Preserve fitting diagnostics before large optional source/context/advice fields.
|
|
276
|
+
for (const current of [diagnostics, source, summary, instruction]) {
|
|
277
|
+
if (!current || current.selected === current.full) continue;
|
|
278
|
+
const previous = current.selected;
|
|
279
|
+
current.selected = current.full;
|
|
280
|
+
if (Buffer.byteLength(render()) > Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1) current.selected = previous;
|
|
281
|
+
}
|
|
282
|
+
return render();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function sourceNormalizationFailureText(source: string, reason: string, summary: string, instruction: string): string {
|
|
286
|
+
const field = ToolsResponse.formatMarkdownField;
|
|
287
|
+
const part = (key: string, value: string, literal = false) => {
|
|
288
|
+
const wellFormed = value.isWellFormed();
|
|
289
|
+
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`;
|
|
290
|
+
const full = wellFormed ? field(key, literal ? ToolsResponse.formatLiteralBlock(value) : value) : omitted;
|
|
291
|
+
return { full, selected: Buffer.byteLength(full) <= Buffer.byteLength(omitted) ? full : omitted };
|
|
292
|
+
};
|
|
293
|
+
const selectedSource = part("source", source, true);
|
|
294
|
+
const selectedReason = part("reason", reason);
|
|
295
|
+
const selectedSummary = part("active_skills_summary", summary);
|
|
296
|
+
const selectedInstruction = part("instruction", instruction);
|
|
297
|
+
const render = () => [field("field", "from"), selectedSource.selected, field("result", "Recipe source is invalid."),
|
|
298
|
+
selectedReason.selected, selectedSummary.selected, selectedInstruction.selected].join("\n");
|
|
299
|
+
for (const current of [selectedSource, selectedReason, selectedSummary, selectedInstruction]) {
|
|
300
|
+
if (current.selected === current.full) continue;
|
|
301
|
+
const previous = current.selected;
|
|
302
|
+
current.selected = current.full;
|
|
303
|
+
if (Buffer.byteLength(render()) > Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1) current.selected = previous;
|
|
304
|
+
}
|
|
305
|
+
return render();
|
|
306
|
+
}
|
|
307
|
+
|
|
158
308
|
function activeSkillSummary(
|
|
159
309
|
resolutionContext: RecipesContext.RecipeResolutionContext,
|
|
160
310
|
): string {
|
|
@@ -168,6 +318,19 @@ function activeSkillSummary(
|
|
|
168
318
|
return names.length > 0 ? names.join(", ") : "<none>";
|
|
169
319
|
}
|
|
170
320
|
|
|
321
|
+
function draftPathFailureText(kind: "root" | "missing", reference: string): string {
|
|
322
|
+
const key = kind === "root" ? "allowed_root" : "path";
|
|
323
|
+
const render = (selected: string) => "- field: draft\n" + selected + (kind === "root"
|
|
324
|
+
? "\n- result: Draft must be under the allowed root.\n- instruction: Use inspect target=recipes view=summary to list drafts."
|
|
325
|
+
: "\n- result: Draft not found.");
|
|
326
|
+
const wellFormed = reference.isWellFormed();
|
|
327
|
+
if (wellFormed) {
|
|
328
|
+
const complete = render(ToolsResponse.formatMarkdownField(key, ToolsResponse.formatLiteralBlock(reference)));
|
|
329
|
+
if (Buffer.byteLength(complete) <= Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1) return complete;
|
|
330
|
+
}
|
|
331
|
+
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`);
|
|
332
|
+
}
|
|
333
|
+
|
|
171
334
|
function assertDraftPath<TContext>(
|
|
172
335
|
deps: RegisterToolRuntimeDeps<TContext>,
|
|
173
336
|
draft: string,
|
|
@@ -182,16 +345,63 @@ function assertDraftPath<TContext>(
|
|
|
182
345
|
) {
|
|
183
346
|
throw new Error(
|
|
184
347
|
ExecutionOutput.formatToolText(
|
|
185
|
-
|
|
348
|
+
draftPathFailureText("root", `${draftRoot}`),
|
|
186
349
|
),
|
|
187
350
|
);
|
|
188
351
|
}
|
|
189
352
|
if (!existsSync(path)) {
|
|
190
|
-
throw new Error(ExecutionOutput.formatToolText(
|
|
353
|
+
throw new Error(ExecutionOutput.formatToolText(draftPathFailureText("missing", `${path}`)));
|
|
191
354
|
}
|
|
192
355
|
return path;
|
|
193
356
|
}
|
|
194
357
|
|
|
358
|
+
function draftReceiptText(result: "updated" | "registered", tool: string, callable: string, next: string): string {
|
|
359
|
+
const budget = Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1;
|
|
360
|
+
const renderPart = (value: Record<string, unknown>) => ToolsResponse.renderYamlMetadata(value, budget);
|
|
361
|
+
const part = (key: string, value: string, rendered: Record<string, unknown>) => {
|
|
362
|
+
const wellFormed = value.isWellFormed();
|
|
363
|
+
const omitted: Record<string, unknown> = { [key]: wellFormed ? "[omitted]" : "[unavailable]",
|
|
364
|
+
[key + "_omission"]: { reason: wellFormed ? "response_too_large" : "malformed_selected_text", shown: 0, omitted: 1, total: 1 } };
|
|
365
|
+
const full = wellFormed ? rendered : omitted;
|
|
366
|
+
const complete = renderPart(full), fallback = renderPart(omitted);
|
|
367
|
+
return { full, selected: complete.state === "available" && fallback.state === "available" && Buffer.byteLength(complete.text) <= Buffer.byteLength(fallback.text) ? full : omitted };
|
|
368
|
+
};
|
|
369
|
+
const identity = part("tool", tool, { tool });
|
|
370
|
+
const flag = part("callable_now", callable, { callable_now: callable });
|
|
371
|
+
// Only this producer's exact canonical read-only status hint is typed, never body advice.
|
|
372
|
+
const status = /^inspect target=(tool:[a-z][a-z0-9_]{0,63}) view=status$/u.exec(next);
|
|
373
|
+
const hint = part("next_action", next, status ? { next: { tool: "inspect", target: status[1], view: "status" } } : { instruction: next });
|
|
374
|
+
const render = () => renderPart({ ...identity.selected, result, source: "draft", ...flag.selected, ...hint.selected });
|
|
375
|
+
for (const current of [identity, flag, hint]) {
|
|
376
|
+
if (current.selected === current.full) continue;
|
|
377
|
+
const previous = current.selected;
|
|
378
|
+
current.selected = current.full;
|
|
379
|
+
if (render().state !== "available") current.selected = previous;
|
|
380
|
+
}
|
|
381
|
+
return (render() as Extract<ToolsResponse.YamlMetadataRendering, { state: "available" }>).text;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function duplicateRegistrationText(value: string): string {
|
|
385
|
+
const render = (selected: string) => "- field: name\n" + selected + "\n- result: Tool already registered.\n- instruction: Use update=true to overwrite.";
|
|
386
|
+
const wellFormed = value.isWellFormed();
|
|
387
|
+
if (wellFormed) {
|
|
388
|
+
const complete = render(ToolsResponse.formatMarkdownField("value", value));
|
|
389
|
+
if (Buffer.byteLength(complete) <= Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1) return complete;
|
|
390
|
+
}
|
|
391
|
+
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`);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function draftRecipeFailureText(key: "reason" | "diagnostics_summary", value?: string): string {
|
|
395
|
+
const header = "- field: draft\n- result: Draft recipe is invalid.";
|
|
396
|
+
if (value === undefined) return header;
|
|
397
|
+
const wellFormed = value.isWellFormed();
|
|
398
|
+
if (wellFormed) {
|
|
399
|
+
const complete = header + "\n" + ToolsResponse.formatMarkdownField(key, value);
|
|
400
|
+
if (Buffer.byteLength(complete) <= Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1) return complete;
|
|
401
|
+
}
|
|
402
|
+
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`;
|
|
403
|
+
}
|
|
404
|
+
|
|
195
405
|
function promoteDraftRecipe<TContext>(
|
|
196
406
|
name: string,
|
|
197
407
|
input: RegisterToolInput,
|
|
@@ -207,7 +417,7 @@ function promoteDraftRecipe<TContext>(
|
|
|
207
417
|
if ((existing || existsSync(targetPath)) && !input.update) {
|
|
208
418
|
throw new Error(
|
|
209
419
|
ExecutionOutput.formatToolText(
|
|
210
|
-
|
|
420
|
+
duplicateRegistrationText(`${name}`),
|
|
211
421
|
),
|
|
212
422
|
);
|
|
213
423
|
}
|
|
@@ -216,7 +426,7 @@ function promoteDraftRecipe<TContext>(
|
|
|
216
426
|
const reason = RecipesReferences.diagnoseRawRecipeConfigFailure(draftPath);
|
|
217
427
|
throw new Error(
|
|
218
428
|
ExecutionOutput.formatToolText(
|
|
219
|
-
|
|
429
|
+
draftRecipeFailureText("reason", reason ? `${reason}` : undefined),
|
|
220
430
|
),
|
|
221
431
|
);
|
|
222
432
|
}
|
|
@@ -239,7 +449,7 @@ function promoteDraftRecipe<TContext>(
|
|
|
239
449
|
if (!candidate.validated || !candidate.tool) {
|
|
240
450
|
throw new Error(
|
|
241
451
|
ExecutionOutput.formatToolText(
|
|
242
|
-
|
|
452
|
+
draftRecipeFailureText("diagnostics_summary", `${candidate.diagnostics.join("; ")}`),
|
|
243
453
|
),
|
|
244
454
|
);
|
|
245
455
|
}
|
|
@@ -254,12 +464,13 @@ function promoteDraftRecipe<TContext>(
|
|
|
254
464
|
const argSummary = RecipesDiscovery.summarizeRegisteredToolArgs(promoted);
|
|
255
465
|
const callableNow = activation?.callable_now ?? false;
|
|
256
466
|
const nextActions = registrationNextActions(name, "draft", callableNow);
|
|
257
|
-
deps.notify(ctx,
|
|
467
|
+
deps.notify(ctx, registryNoticeText("promoted", `${name}`), "info");
|
|
258
468
|
return {
|
|
259
469
|
content: [
|
|
260
470
|
textContent(
|
|
261
471
|
ExecutionOutput.formatToolText(
|
|
262
|
-
|
|
472
|
+
// Preserve the old name→flag→hint template conversions here, after notify.
|
|
473
|
+
draftReceiptText(existing ? "updated" : "registered", `${name}`, `${callableNow}`, `${nextActions[0]}`),
|
|
263
474
|
),
|
|
264
475
|
),
|
|
265
476
|
],
|
|
@@ -296,6 +507,19 @@ function persistToolRecipe<TContext>(
|
|
|
296
507
|
return path;
|
|
297
508
|
}
|
|
298
509
|
|
|
510
|
+
function registryDeletionText(name: string, result: "deleted" | "not found"): string {
|
|
511
|
+
const budget = Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1;
|
|
512
|
+
const facts = { result, ...(result === "deleted" ? { instruction: "Reload to remove it from the complete registry." } : {}) };
|
|
513
|
+
const wellFormed = name.isWellFormed();
|
|
514
|
+
if (wellFormed) {
|
|
515
|
+
const complete = ToolsResponse.renderYamlMetadata({ tool: name, ...facts }, budget);
|
|
516
|
+
if (complete.state === "available") return complete.text;
|
|
517
|
+
}
|
|
518
|
+
const fallback = ToolsResponse.renderYamlMetadata({ tool: wellFormed ? "[omitted]" : "[unavailable]", tool_omission: { reason: wellFormed ? "response_too_large" : "malformed_selected_text", shown: 0, omitted: 1, total: 1 }, ...facts }, budget);
|
|
519
|
+
// Fixed metadata is well formed and bounded far below budget.
|
|
520
|
+
return (fallback as Extract<ToolsResponse.YamlMetadataRendering, { state: "available" }>).text;
|
|
521
|
+
}
|
|
522
|
+
|
|
299
523
|
function deleteTool<TContext>(
|
|
300
524
|
name: string,
|
|
301
525
|
ctx: TContext,
|
|
@@ -306,7 +530,7 @@ function deleteTool<TContext>(
|
|
|
306
530
|
return {
|
|
307
531
|
content: [
|
|
308
532
|
textContent(
|
|
309
|
-
ExecutionOutput.formatToolText(
|
|
533
|
+
ExecutionOutput.formatToolText(registryDeletionText(`${name}`, "not found")),
|
|
310
534
|
),
|
|
311
535
|
],
|
|
312
536
|
details: { tool: name },
|
|
@@ -318,12 +542,12 @@ function deleteTool<TContext>(
|
|
|
318
542
|
deps.setActiveTools(
|
|
319
543
|
deps.getActiveTools().filter((toolName) => toolName !== name),
|
|
320
544
|
);
|
|
321
|
-
deps.notify(ctx,
|
|
545
|
+
deps.notify(ctx, registryNoticeText("deleted", `${name}`), "info");
|
|
322
546
|
return {
|
|
323
547
|
content: [
|
|
324
548
|
textContent(
|
|
325
549
|
ExecutionOutput.formatToolText(
|
|
326
|
-
|
|
550
|
+
registryDeletionText(`${name}`, "deleted"),
|
|
327
551
|
),
|
|
328
552
|
),
|
|
329
553
|
],
|
|
@@ -384,7 +608,7 @@ function assertTemplateIsNotNestedRecipe(value: unknown): void {
|
|
|
384
608
|
) {
|
|
385
609
|
throw new Error(
|
|
386
610
|
ExecutionOutput.formatToolText(
|
|
387
|
-
"Nested Recipe-shaped templates are not a register_tool source mode
|
|
611
|
+
"- field: template\n- result: Nested Recipe-shaped templates are not a register_tool source mode.\n- instruction: retry with from=<skill>/<recipe> and defaults={...}.",
|
|
388
612
|
),
|
|
389
613
|
);
|
|
390
614
|
}
|
|
@@ -402,7 +626,7 @@ function getInputTemplate(
|
|
|
402
626
|
});
|
|
403
627
|
if (steps.length === 0)
|
|
404
628
|
throw new Error(
|
|
405
|
-
ExecutionOutput.formatToolText("Tool template sequence is empty."),
|
|
629
|
+
ExecutionOutput.formatToolText("- field: template\n- result: Tool template sequence is empty."),
|
|
406
630
|
);
|
|
407
631
|
return value;
|
|
408
632
|
}
|
|
@@ -414,7 +638,7 @@ function getInputTemplate(
|
|
|
414
638
|
}
|
|
415
639
|
throw new Error(
|
|
416
640
|
ExecutionOutput.formatToolText(
|
|
417
|
-
"
|
|
641
|
+
"- field: template\n- result: unsupported template type\n- supported_types:\n - string\n - object\n - sequence",
|
|
418
642
|
),
|
|
419
643
|
);
|
|
420
644
|
}
|
|
@@ -441,7 +665,7 @@ function normalizeDefaults(value: unknown): Record<string, unknown> | undefined
|
|
|
441
665
|
if (value === undefined) return undefined;
|
|
442
666
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
443
667
|
throw new Error(
|
|
444
|
-
ExecutionOutput.formatToolText("Tool defaults must be an object."),
|
|
668
|
+
ExecutionOutput.formatToolText("- field: defaults\n- result: Tool defaults must be an object."),
|
|
445
669
|
);
|
|
446
670
|
}
|
|
447
671
|
return { ...(value as Record<string, unknown>) };
|
|
@@ -502,7 +726,7 @@ function buildAuthoredRecipe(
|
|
|
502
726
|
if (!description && !from) {
|
|
503
727
|
throw new Error(
|
|
504
728
|
ExecutionOutput.formatToolText(
|
|
505
|
-
"Tool description is required for command-template registration.",
|
|
729
|
+
"- field: description\n- result: Tool description is required for command-template registration.",
|
|
506
730
|
),
|
|
507
731
|
);
|
|
508
732
|
}
|
|
@@ -514,7 +738,7 @@ function buildAuthoredRecipe(
|
|
|
514
738
|
if (runtimeOwnedDefault) {
|
|
515
739
|
throw new Error(
|
|
516
740
|
ExecutionOutput.formatToolText(
|
|
517
|
-
|
|
741
|
+
`- 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.`,
|
|
518
742
|
),
|
|
519
743
|
);
|
|
520
744
|
}
|
|
@@ -534,7 +758,7 @@ function buildAuthoredRecipe(
|
|
|
534
758
|
const template = getInputTemplate(input.template);
|
|
535
759
|
if (template === null) {
|
|
536
760
|
throw new Error(
|
|
537
|
-
ExecutionOutput.formatToolText("Tool template cannot be null here."),
|
|
761
|
+
ExecutionOutput.formatToolText("- field: template\n- result: Tool template cannot be null here."),
|
|
538
762
|
);
|
|
539
763
|
}
|
|
540
764
|
const finalTemplate =
|
|
@@ -543,7 +767,7 @@ function buildAuthoredRecipe(
|
|
|
543
767
|
: template;
|
|
544
768
|
if (!finalTemplate) {
|
|
545
769
|
throw new Error(
|
|
546
|
-
ExecutionOutput.formatToolText("Tool template is required."),
|
|
770
|
+
ExecutionOutput.formatToolText("- field: template\n- result: Tool template is required."),
|
|
547
771
|
);
|
|
548
772
|
}
|
|
549
773
|
const authored: Record<string, unknown> = {
|
|
@@ -569,7 +793,7 @@ function assertRegisterToolInputModes(input: RegisterToolInput): void {
|
|
|
569
793
|
if (Object.hasOwn(record, "values")) {
|
|
570
794
|
throw new Error(
|
|
571
795
|
ExecutionOutput.formatToolText(
|
|
572
|
-
"register_tool values was removed
|
|
796
|
+
"- 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.",
|
|
573
797
|
),
|
|
574
798
|
);
|
|
575
799
|
}
|
|
@@ -580,7 +804,7 @@ function assertRegisterToolInputModes(input: RegisterToolInput): void {
|
|
|
580
804
|
) {
|
|
581
805
|
throw new Error(
|
|
582
806
|
ExecutionOutput.formatToolText(
|
|
583
|
-
"Tool from must be a non-empty Recipe reference.
|
|
807
|
+
"- 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.",
|
|
584
808
|
),
|
|
585
809
|
);
|
|
586
810
|
}
|
|
@@ -592,7 +816,7 @@ function assertRegisterToolInputModes(input: RegisterToolInput): void {
|
|
|
592
816
|
if (modeCount > 1) {
|
|
593
817
|
throw new Error(
|
|
594
818
|
ExecutionOutput.formatToolText(
|
|
595
|
-
"Use exactly one register_tool source mode
|
|
819
|
+
"- 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.",
|
|
596
820
|
),
|
|
597
821
|
);
|
|
598
822
|
}
|
|
@@ -602,12 +826,22 @@ function assertRegisterToolInputModes(input: RegisterToolInput): void {
|
|
|
602
826
|
) {
|
|
603
827
|
throw new Error(
|
|
604
828
|
ExecutionOutput.formatToolText(
|
|
605
|
-
"register_tool from inherits args and async behavior
|
|
829
|
+
"- 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.",
|
|
606
830
|
),
|
|
607
831
|
);
|
|
608
832
|
}
|
|
609
833
|
}
|
|
610
834
|
|
|
835
|
+
function reservedRegistrationNameText(value: string): string {
|
|
836
|
+
const render = (selected: string) => "- field: name\n" + selected + "\n- result: Reserved tool name.";
|
|
837
|
+
const wellFormed = value.isWellFormed();
|
|
838
|
+
if (wellFormed) {
|
|
839
|
+
const complete = render(ToolsResponse.formatMarkdownField("value", value));
|
|
840
|
+
if (Buffer.byteLength(complete) <= Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1) return complete;
|
|
841
|
+
}
|
|
842
|
+
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`);
|
|
843
|
+
}
|
|
844
|
+
|
|
611
845
|
function executeRegisterToolUnlocked<TContext>(
|
|
612
846
|
params: unknown,
|
|
613
847
|
ctx: TContext,
|
|
@@ -622,10 +856,10 @@ function executeRegisterToolUnlocked<TContext>(
|
|
|
622
856
|
if (!input.name) return listTools(deps);
|
|
623
857
|
const name = Identity.normalizeToolName(input.name);
|
|
624
858
|
if (!name)
|
|
625
|
-
throw new Error(ExecutionOutput.formatToolText("Invalid tool name."));
|
|
859
|
+
throw new Error(ExecutionOutput.formatToolText("- field: name\n- result: Invalid tool name."));
|
|
626
860
|
if (deps.reservedToolNames.has(name)) {
|
|
627
861
|
throw new Error(
|
|
628
|
-
ExecutionOutput.formatToolText(
|
|
862
|
+
ExecutionOutput.formatToolText(reservedRegistrationNameText(`${name}`)),
|
|
629
863
|
);
|
|
630
864
|
}
|
|
631
865
|
if (typeof input.draft === "string" && input.draft.trim()) {
|
|
@@ -647,7 +881,7 @@ function executeRegisterToolUnlocked<TContext>(
|
|
|
647
881
|
: requestedSource ?? "";
|
|
648
882
|
throw new Error(
|
|
649
883
|
ExecutionOutput.formatToolText(
|
|
650
|
-
|
|
884
|
+
sourceNormalizationFailureText(`${requestedSource}`, `${reason}`, `${activeSkillSummary(resolutionContext)}`, `${recipeDoctorAction(diagnosticSource)}`),
|
|
651
885
|
),
|
|
652
886
|
);
|
|
653
887
|
}
|
|
@@ -664,14 +898,14 @@ function executeRegisterToolUnlocked<TContext>(
|
|
|
664
898
|
if ((authoritative.exists || existing) && !input.update) {
|
|
665
899
|
throw new Error(
|
|
666
900
|
ExecutionOutput.formatToolText(
|
|
667
|
-
|
|
901
|
+
duplicateRegistrationText(`${name}`),
|
|
668
902
|
),
|
|
669
903
|
);
|
|
670
904
|
}
|
|
671
905
|
if (template === undefined && !input.from && !existing) {
|
|
672
906
|
throw new Error(
|
|
673
907
|
ExecutionOutput.formatToolText(
|
|
674
|
-
"New registration requires exactly one source mode
|
|
908
|
+
"- 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.",
|
|
675
909
|
),
|
|
676
910
|
);
|
|
677
911
|
}
|
|
@@ -688,8 +922,8 @@ function executeRegisterToolUnlocked<TContext>(
|
|
|
688
922
|
);
|
|
689
923
|
if (!candidate.validated || !candidate.tool) {
|
|
690
924
|
const sourceDiagnostic = requestedSource
|
|
691
|
-
?
|
|
692
|
-
:
|
|
925
|
+
? candidateAdmissionFailureText({ kind: "source", source: `${requestedSource}`, diagnostics: `${candidate.diagnostics.join("; ")}`, summary: `${activeSkillSummary(resolutionContext)}`, instruction: `${recipeDoctorAction(requestedSource)}` })
|
|
926
|
+
: candidateAdmissionFailureText({ kind: "recipe", diagnostics: `${candidate.diagnostics.join("; ")}` });
|
|
693
927
|
throw new Error(ExecutionOutput.formatToolText(sourceDiagnostic));
|
|
694
928
|
}
|
|
695
929
|
const activeBefore = deps.getActiveTools();
|
|
@@ -739,11 +973,11 @@ function executeRegisterToolUnlocked<TContext>(
|
|
|
739
973
|
deps.setActiveTools(activeBefore);
|
|
740
974
|
throw new Error(
|
|
741
975
|
ExecutionOutput.formatToolText(
|
|
742
|
-
|
|
976
|
+
registrationTransactionFailureText(`${transactionStage}`, `${resolutionContext.generation}`, `${activeSkillSummary(resolutionContext)}`, `${error instanceof Error ? error.message : String(error)}`),
|
|
743
977
|
),
|
|
744
978
|
);
|
|
745
979
|
}
|
|
746
|
-
deps.notify(ctx,
|
|
980
|
+
deps.notify(ctx, registryNoticeText("activated", `${name}`), "info");
|
|
747
981
|
const templateWarnings = CommandTemplates.getCommandTemplateWarnings(
|
|
748
982
|
typeof cfg.recipe?.template === "object" && !Array.isArray(cfg.recipe.template)
|
|
749
983
|
? cfg.recipe.template
|
|
@@ -757,14 +991,19 @@ function executeRegisterToolUnlocked<TContext>(
|
|
|
757
991
|
const source = requestedSource ?? "template";
|
|
758
992
|
const argSummary = RecipesDiscovery.summarizeRegisteredToolArgs(cfg);
|
|
759
993
|
const nextActions = registrationNextActions(name, source, callableNow);
|
|
994
|
+
let displayBoundary: string | undefined;
|
|
760
995
|
const outcomeText = callableNow
|
|
761
996
|
? `${existing ? "Updated" : "Registered"} tool "${name}" from ${source}; callable_now=true`
|
|
762
|
-
: `Persisted tool "${name}" from ${source}; callable_now=false; activation_boundary=${activationBoundary(activation)}`;
|
|
997
|
+
: `Persisted tool "${name}" from ${source}; callable_now=false; activation_boundary=${displayBoundary = activationBoundary(activation)}`;
|
|
998
|
+
// Keep original fallible advisory evaluation/order after effects, before the new text.
|
|
999
|
+
void `${outcomeText}; required=${Schema.formatToolArgs(argSummary.required)}; optional=${Schema.formatToolArgs(argSummary.optional)}; next=${nextActions[0]}.${warningText}`;
|
|
763
1000
|
return {
|
|
764
1001
|
content: [
|
|
765
1002
|
textContent(
|
|
766
1003
|
ExecutionOutput.formatToolText(
|
|
767
|
-
|
|
1004
|
+
registrationReceiptText({ tool: name, result: callableNow ? existing ? "updated" : "registered" : "persisted",
|
|
1005
|
+
source, callable: Boolean(callableNow), boundary: displayBoundary, required: argSummary.required,
|
|
1006
|
+
optional: argSummary.optional, warnings: templateWarnings, next: nextActions[0] }),
|
|
768
1007
|
),
|
|
769
1008
|
),
|
|
770
1009
|
],
|