@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/dist/lib/registry.js
CHANGED
|
@@ -10,21 +10,38 @@ import * as Config from "./config.js";
|
|
|
10
10
|
import * as ExecutionOutput from "./execution-output.js";
|
|
11
11
|
import { withFileMutationLock, writeJsonAtomic, writeTextAtomic, } from "./file-state.js";
|
|
12
12
|
import * as Identity from "./identity.js";
|
|
13
|
+
import * as Limits from "./limits.js";
|
|
13
14
|
import * as Paths from "./paths.js";
|
|
14
15
|
import * as RecipesContext from "./recipes-context.js";
|
|
15
16
|
import * as RecipesDiscovery from "./recipes-discovery.js";
|
|
16
17
|
import * as RecipesReferences from "./recipes-references.js";
|
|
17
18
|
import * as Schema from "./schema.js";
|
|
19
|
+
import * as ToolsResponse from "./tools-response.js";
|
|
18
20
|
function textContent(text) {
|
|
19
21
|
return { type: "text", text };
|
|
20
22
|
}
|
|
23
|
+
function registryListText(rows) {
|
|
24
|
+
const budget = Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1;
|
|
25
|
+
const coverage = (shown, reason) => ({ ...(reason ? { reason } : {}), shown, omitted: rows.length - shown, total: rows.length });
|
|
26
|
+
const malformed = rows.some(row => !row.isWellFormed());
|
|
27
|
+
if (!malformed) {
|
|
28
|
+
// Remove only the compiler prefix after the original key coercion and join.
|
|
29
|
+
const complete = ToolsResponse.renderYamlMetadata({ registered_tools: rows.map(row => row.slice(2)), registered_tools_coverage: coverage(rows.length) }, budget);
|
|
30
|
+
if (complete.state === "available")
|
|
31
|
+
return complete.text;
|
|
32
|
+
}
|
|
33
|
+
const fallback = ToolsResponse.renderYamlMetadata({ registered_tools: malformed ? "[unavailable]" : "[omitted]", registered_tools_coverage: coverage(0, malformed ? "malformed_selected_text" : "response_too_large") }, budget);
|
|
34
|
+
// Fixed keys/reasons and finite array-length counts are bounded far below budget.
|
|
35
|
+
return fallback.text;
|
|
36
|
+
}
|
|
21
37
|
function listTools(deps) {
|
|
22
38
|
const names = [...deps.getTools().keys()].sort();
|
|
39
|
+
const rows = names.length > 0 ? names.map((name) => `- ${name}`) : [];
|
|
40
|
+
// Retain the original conditional map/join observations before read-time projection.
|
|
41
|
+
void (names.length > 0 ? `Registered tools:\n${rows.join("\n")}` : "No registered tools.");
|
|
23
42
|
return {
|
|
24
43
|
content: [
|
|
25
|
-
textContent(ExecutionOutput.formatToolText(
|
|
26
|
-
? `Registered tools:\n${names.map((name) => `- ${name}`).join("\n")}`
|
|
27
|
-
: "No registered tools.")),
|
|
44
|
+
textContent(ExecutionOutput.formatToolText(registryListText(rows))),
|
|
28
45
|
],
|
|
29
46
|
details: { tool: "register_tool" },
|
|
30
47
|
};
|
|
@@ -65,12 +82,160 @@ function registrationNextActions(tool, source, callableNow) {
|
|
|
65
82
|
: [recipeDoctorAction(source)]),
|
|
66
83
|
];
|
|
67
84
|
}
|
|
85
|
+
/** Read-time text only: callers supply the original post-activation selections, not live ports. */
|
|
86
|
+
function registrationReceiptText(data) {
|
|
87
|
+
const budget = Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1;
|
|
88
|
+
const renderPart = (value) => ToolsResponse.renderYamlMetadata(value, budget);
|
|
89
|
+
const omission = (key, count, malformed) => ({
|
|
90
|
+
[key]: malformed ? "[unavailable]" : "[omitted]",
|
|
91
|
+
[key + "_omission"]: { reason: malformed ? "malformed_selected_text" : "response_too_large", shown: 0, omitted: count, total: count },
|
|
92
|
+
});
|
|
93
|
+
const part = (full, omitted) => {
|
|
94
|
+
const complete = renderPart(full), fallback = renderPart(omitted);
|
|
95
|
+
return { full, selected: complete.state === "available" && fallback.state === "available" && Buffer.byteLength(complete.text) <= Buffer.byteLength(fallback.text) ? full : omitted };
|
|
96
|
+
};
|
|
97
|
+
const scalar = (key, value) => {
|
|
98
|
+
const wellFormed = value.isWellFormed();
|
|
99
|
+
const omitted = omission(key, 1, !wellFormed);
|
|
100
|
+
return part(wellFormed ? { [key]: value } : omitted, omitted);
|
|
101
|
+
};
|
|
102
|
+
const sequence = (key, values) => {
|
|
103
|
+
const rows = [];
|
|
104
|
+
let malformed = false;
|
|
105
|
+
for (let index = 0; index < values.length; index++) {
|
|
106
|
+
const value = values[index];
|
|
107
|
+
if (typeof value !== "string" || !value.isWellFormed()) {
|
|
108
|
+
malformed = true;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
rows.push(value);
|
|
112
|
+
}
|
|
113
|
+
const omitted = omission(key, values.length, malformed);
|
|
114
|
+
return part(malformed ? omitted : { [key]: rows }, omitted);
|
|
115
|
+
};
|
|
116
|
+
const tool = scalar("tool", data.tool);
|
|
117
|
+
const source = scalar("source", data.source);
|
|
118
|
+
const required = sequence("required_args", data.required), optional = sequence("optional_args", data.optional);
|
|
119
|
+
const warnings = data.warnings.length ? sequence("warnings", data.warnings) : undefined;
|
|
120
|
+
const nextWellFormed = data.next.isWellFormed();
|
|
121
|
+
const omittedNext = omission("next_action", 1, !nextWellFormed);
|
|
122
|
+
// This producer knows only its existing status hint; invocation advice stays opaque.
|
|
123
|
+
const next = part(nextWellFormed
|
|
124
|
+
? data.callable ? { instruction: data.next } : { next: { tool: "inspect", target: `tool:${data.tool}`, view: "status" } }
|
|
125
|
+
: omittedNext, omittedNext);
|
|
126
|
+
const render = () => renderPart({ ...tool.selected, result: data.result, ...source.selected, callable_now: data.callable,
|
|
127
|
+
...(data.boundary === undefined ? {} : { activation_boundary: data.boundary }), ...required.selected, ...optional.selected,
|
|
128
|
+
...(warnings ? warnings.selected : {}), ...next.selected });
|
|
129
|
+
// Preserve complete safety notes before large argument lists; all seeds are monotone.
|
|
130
|
+
for (const current of [...(warnings ? [warnings] : []), tool, source, next, required, optional]) {
|
|
131
|
+
if (current.selected === current.full)
|
|
132
|
+
continue;
|
|
133
|
+
const previous = current.selected;
|
|
134
|
+
current.selected = current.full;
|
|
135
|
+
if (render().state !== "available")
|
|
136
|
+
current.selected = previous;
|
|
137
|
+
}
|
|
138
|
+
return render().text;
|
|
139
|
+
}
|
|
140
|
+
function registryNoticeText(kind, name) {
|
|
141
|
+
const report = { activated: "Tool activated", promoted: "Promoted draft recipe", deleted: "Deleted tool" }[kind];
|
|
142
|
+
const selected = name.isWellFormed() ? ToolsResponse.formatMarkdownField("tool", name)
|
|
143
|
+
: "- tool: [unavailable]\n- tool_omission:\n - reason: malformed_selected_text\n - shown: 0\n - omitted: 1\n - total: 1";
|
|
144
|
+
return ToolsResponse.formatMarkdownField("report", report) + "\n" + selected;
|
|
145
|
+
}
|
|
146
|
+
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");
|
|
159
|
+
// 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();
|
|
169
|
+
}
|
|
170
|
+
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");
|
|
185
|
+
// 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();
|
|
195
|
+
}
|
|
196
|
+
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();
|
|
219
|
+
}
|
|
68
220
|
function activeSkillSummary(resolutionContext) {
|
|
69
221
|
const names = Object.keys(RecipesReferences.getActiveSkillRecipeNamespaces(resolutionContext.activeSkills))
|
|
70
222
|
.sort()
|
|
71
223
|
.slice(0, 20);
|
|
72
224
|
return names.length > 0 ? names.join(", ") : "<none>";
|
|
73
225
|
}
|
|
226
|
+
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`);
|
|
238
|
+
}
|
|
74
239
|
function assertDraftPath(deps, draft) {
|
|
75
240
|
const draftRoot = resolve(getRecipeRoot(deps), "drafts");
|
|
76
241
|
const path = resolve(draft);
|
|
@@ -78,13 +243,62 @@ function assertDraftPath(deps, draft) {
|
|
|
78
243
|
if (relation === "" ||
|
|
79
244
|
relation.startsWith("..") ||
|
|
80
245
|
resolve(relation) === relation) {
|
|
81
|
-
throw new Error(ExecutionOutput.formatToolText(
|
|
246
|
+
throw new Error(ExecutionOutput.formatToolText(draftPathFailureText("root", `${draftRoot}`)));
|
|
82
247
|
}
|
|
83
248
|
if (!existsSync(path)) {
|
|
84
|
-
throw new Error(ExecutionOutput.formatToolText(
|
|
249
|
+
throw new Error(ExecutionOutput.formatToolText(draftPathFailureText("missing", `${path}`)));
|
|
85
250
|
}
|
|
86
251
|
return path;
|
|
87
252
|
}
|
|
253
|
+
function draftReceiptText(result, tool, callable, next) {
|
|
254
|
+
const budget = Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1;
|
|
255
|
+
const renderPart = (value) => ToolsResponse.renderYamlMetadata(value, budget);
|
|
256
|
+
const part = (key, value, rendered) => {
|
|
257
|
+
const wellFormed = value.isWellFormed();
|
|
258
|
+
const omitted = { [key]: wellFormed ? "[omitted]" : "[unavailable]",
|
|
259
|
+
[key + "_omission"]: { reason: wellFormed ? "response_too_large" : "malformed_selected_text", shown: 0, omitted: 1, total: 1 } };
|
|
260
|
+
const full = wellFormed ? rendered : omitted;
|
|
261
|
+
const complete = renderPart(full), fallback = renderPart(omitted);
|
|
262
|
+
return { full, selected: complete.state === "available" && fallback.state === "available" && Buffer.byteLength(complete.text) <= Buffer.byteLength(fallback.text) ? full : omitted };
|
|
263
|
+
};
|
|
264
|
+
const identity = part("tool", tool, { tool });
|
|
265
|
+
const flag = part("callable_now", callable, { callable_now: callable });
|
|
266
|
+
// Only this producer's exact canonical read-only status hint is typed, never body advice.
|
|
267
|
+
const status = /^inspect target=(tool:[a-z][a-z0-9_]{0,63}) view=status$/u.exec(next);
|
|
268
|
+
const hint = part("next_action", next, status ? { next: { tool: "inspect", target: status[1], view: "status" } } : { instruction: next });
|
|
269
|
+
const render = () => renderPart({ ...identity.selected, result, source: "draft", ...flag.selected, ...hint.selected });
|
|
270
|
+
for (const current of [identity, flag, hint]) {
|
|
271
|
+
if (current.selected === current.full)
|
|
272
|
+
continue;
|
|
273
|
+
const previous = current.selected;
|
|
274
|
+
current.selected = current.full;
|
|
275
|
+
if (render().state !== "available")
|
|
276
|
+
current.selected = previous;
|
|
277
|
+
}
|
|
278
|
+
return render().text;
|
|
279
|
+
}
|
|
280
|
+
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`);
|
|
289
|
+
}
|
|
290
|
+
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`;
|
|
301
|
+
}
|
|
88
302
|
function promoteDraftRecipe(name, input, ctx, deps) {
|
|
89
303
|
const draftPath = assertDraftPath(deps, String(input.draft ?? ""));
|
|
90
304
|
const targetPath = getToolRecipePath(deps, name);
|
|
@@ -94,12 +308,12 @@ function promoteDraftRecipe(name, input, ctx, deps) {
|
|
|
94
308
|
if (blocker)
|
|
95
309
|
throw new Error(ExecutionOutput.formatToolText(blocker));
|
|
96
310
|
if ((existing || existsSync(targetPath)) && !input.update) {
|
|
97
|
-
throw new Error(ExecutionOutput.formatToolText(
|
|
311
|
+
throw new Error(ExecutionOutput.formatToolText(duplicateRegistrationText(`${name}`)));
|
|
98
312
|
}
|
|
99
313
|
const raw = RecipesReferences.readRawRecipeConfig(draftPath);
|
|
100
314
|
if (!raw) {
|
|
101
315
|
const reason = RecipesReferences.diagnoseRawRecipeConfigFailure(draftPath);
|
|
102
|
-
throw new Error(ExecutionOutput.formatToolText(
|
|
316
|
+
throw new Error(ExecutionOutput.formatToolText(draftRecipeFailureText("reason", reason ? `${reason}` : undefined)));
|
|
103
317
|
}
|
|
104
318
|
const authoredRecipe = buildAuthoredRecipe({
|
|
105
319
|
...input,
|
|
@@ -109,7 +323,7 @@ function promoteDraftRecipe(name, input, ctx, deps) {
|
|
|
109
323
|
const resolutionContext = getRegistrationResolutionContext(ctx, deps);
|
|
110
324
|
const candidate = RecipesDiscovery.admitUserRecipe(targetPath, resolutionContext, authoredRecipe);
|
|
111
325
|
if (!candidate.validated || !candidate.tool) {
|
|
112
|
-
throw new Error(ExecutionOutput.formatToolText(
|
|
326
|
+
throw new Error(ExecutionOutput.formatToolText(draftRecipeFailureText("diagnostics_summary", `${candidate.diagnostics.join("; ")}`)));
|
|
113
327
|
}
|
|
114
328
|
mkdirSync(dirname(targetPath), { recursive: true });
|
|
115
329
|
writeJsonAtomic(targetPath, authoredRecipe);
|
|
@@ -119,10 +333,12 @@ function promoteDraftRecipe(name, input, ctx, deps) {
|
|
|
119
333
|
const argSummary = RecipesDiscovery.summarizeRegisteredToolArgs(promoted);
|
|
120
334
|
const callableNow = activation?.callable_now ?? false;
|
|
121
335
|
const nextActions = registrationNextActions(name, "draft", callableNow);
|
|
122
|
-
deps.notify(ctx,
|
|
336
|
+
deps.notify(ctx, registryNoticeText("promoted", `${name}`), "info");
|
|
123
337
|
return {
|
|
124
338
|
content: [
|
|
125
|
-
textContent(ExecutionOutput.formatToolText(
|
|
339
|
+
textContent(ExecutionOutput.formatToolText(
|
|
340
|
+
// Preserve the old name→flag→hint template conversions here, after notify.
|
|
341
|
+
draftReceiptText(existing ? "updated" : "registered", `${name}`, `${callableNow}`, `${nextActions[0]}`))),
|
|
126
342
|
],
|
|
127
343
|
details: {
|
|
128
344
|
active_tool: activation?.active_tool ?? false,
|
|
@@ -151,12 +367,25 @@ function persistToolRecipe(deps, name, recipe) {
|
|
|
151
367
|
writeJsonAtomic(path, recipe);
|
|
152
368
|
return path;
|
|
153
369
|
}
|
|
370
|
+
function registryDeletionText(name, result) {
|
|
371
|
+
const budget = Limits.RUN_DELIVERY_MODEL_MAX_BYTES - 1;
|
|
372
|
+
const facts = { result, ...(result === "deleted" ? { instruction: "Reload to remove it from the complete registry." } : {}) };
|
|
373
|
+
const wellFormed = name.isWellFormed();
|
|
374
|
+
if (wellFormed) {
|
|
375
|
+
const complete = ToolsResponse.renderYamlMetadata({ tool: name, ...facts }, budget);
|
|
376
|
+
if (complete.state === "available")
|
|
377
|
+
return complete.text;
|
|
378
|
+
}
|
|
379
|
+
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);
|
|
380
|
+
// Fixed metadata is well formed and bounded far below budget.
|
|
381
|
+
return fallback.text;
|
|
382
|
+
}
|
|
154
383
|
function deleteTool(name, ctx, deps) {
|
|
155
384
|
const tools = deps.getTools();
|
|
156
385
|
if (!tools.has(name)) {
|
|
157
386
|
return {
|
|
158
387
|
content: [
|
|
159
|
-
textContent(ExecutionOutput.formatToolText(
|
|
388
|
+
textContent(ExecutionOutput.formatToolText(registryDeletionText(`${name}`, "not found"))),
|
|
160
389
|
],
|
|
161
390
|
details: { tool: name },
|
|
162
391
|
};
|
|
@@ -166,10 +395,10 @@ function deleteTool(name, ctx, deps) {
|
|
|
166
395
|
unlinkSync(recipePath);
|
|
167
396
|
tools.delete(name);
|
|
168
397
|
deps.setActiveTools(deps.getActiveTools().filter((toolName) => toolName !== name));
|
|
169
|
-
deps.notify(ctx,
|
|
398
|
+
deps.notify(ctx, registryNoticeText("deleted", `${name}`), "info");
|
|
170
399
|
return {
|
|
171
400
|
content: [
|
|
172
|
-
textContent(ExecutionOutput.formatToolText(
|
|
401
|
+
textContent(ExecutionOutput.formatToolText(registryDeletionText(`${name}`, "deleted"))),
|
|
173
402
|
],
|
|
174
403
|
details: { tool: name },
|
|
175
404
|
};
|
|
@@ -209,7 +438,7 @@ function assertTemplateIsNotNestedRecipe(value) {
|
|
|
209
438
|
looksLikeRecipeReference(record.template) &&
|
|
210
439
|
(Object.keys(record).length === 1 ||
|
|
211
440
|
["artifacts", "async", "control", "description", "imports", "values"].some((key) => Object.hasOwn(record, key)))) {
|
|
212
|
-
throw new Error(ExecutionOutput.formatToolText("Nested Recipe-shaped templates are not a register_tool source mode
|
|
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={...}."));
|
|
213
442
|
}
|
|
214
443
|
}
|
|
215
444
|
function getInputTemplate(value) {
|
|
@@ -223,14 +452,14 @@ function getInputTemplate(value) {
|
|
|
223
452
|
template: value,
|
|
224
453
|
});
|
|
225
454
|
if (steps.length === 0)
|
|
226
|
-
throw new Error(ExecutionOutput.formatToolText("Tool template sequence is empty."));
|
|
455
|
+
throw new Error(ExecutionOutput.formatToolText("- field: template\n- result: Tool template sequence is empty."));
|
|
227
456
|
return value;
|
|
228
457
|
}
|
|
229
458
|
if (value && typeof value === "object") {
|
|
230
459
|
CommandTemplates.expandCommandTemplateConfigs(value);
|
|
231
460
|
return value;
|
|
232
461
|
}
|
|
233
|
-
throw new Error(ExecutionOutput.formatToolText("
|
|
462
|
+
throw new Error(ExecutionOutput.formatToolText("- field: template\n- result: unsupported template type\n- supported_types:\n - string\n - object\n - sequence"));
|
|
234
463
|
}
|
|
235
464
|
function getRegistrationResolutionContext(ctx, deps) {
|
|
236
465
|
const runtimeContext = deps.getRecipeResolutionContext?.();
|
|
@@ -247,7 +476,7 @@ function normalizeDefaults(value) {
|
|
|
247
476
|
if (value === undefined)
|
|
248
477
|
return undefined;
|
|
249
478
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
250
|
-
throw new Error(ExecutionOutput.formatToolText("Tool defaults must be an object."));
|
|
479
|
+
throw new Error(ExecutionOutput.formatToolText("- field: defaults\n- result: Tool defaults must be an object."));
|
|
251
480
|
}
|
|
252
481
|
return { ...value };
|
|
253
482
|
}
|
|
@@ -279,13 +508,13 @@ function buildAuthoredRecipe(input, existing, existingRecipe) {
|
|
|
279
508
|
const from = typeof input.from === "string" ? input.from.trim() : "";
|
|
280
509
|
const description = (input.description ?? existing?.description ?? "").trim();
|
|
281
510
|
if (!description && !from) {
|
|
282
|
-
throw new Error(ExecutionOutput.formatToolText("Tool description is required for command-template registration."));
|
|
511
|
+
throw new Error(ExecutionOutput.formatToolText("- field: description\n- result: Tool description is required for command-template registration."));
|
|
283
512
|
}
|
|
284
513
|
const inputDefaults = normalizeDefaults(input.defaults);
|
|
285
514
|
if (from) {
|
|
286
515
|
const runtimeOwnedDefault = Object.keys(inputDefaults ?? {}).find((key) => RecipesReferences.isRuntimeOwnedRecipeInput(key));
|
|
287
516
|
if (runtimeOwnedDefault) {
|
|
288
|
-
throw new Error(ExecutionOutput.formatToolText(
|
|
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.`));
|
|
289
518
|
}
|
|
290
519
|
const authored = {
|
|
291
520
|
...(description ? { description } : {}),
|
|
@@ -301,13 +530,13 @@ function buildAuthoredRecipe(input, existing, existingRecipe) {
|
|
|
301
530
|
}
|
|
302
531
|
const template = getInputTemplate(input.template);
|
|
303
532
|
if (template === null) {
|
|
304
|
-
throw new Error(ExecutionOutput.formatToolText("Tool template cannot be null here."));
|
|
533
|
+
throw new Error(ExecutionOutput.formatToolText("- field: template\n- result: Tool template cannot be null here."));
|
|
305
534
|
}
|
|
306
535
|
const finalTemplate = template === undefined || template === ""
|
|
307
536
|
? existingRecipe?.template ?? existing?.template
|
|
308
537
|
: template;
|
|
309
538
|
if (!finalTemplate) {
|
|
310
|
-
throw new Error(ExecutionOutput.formatToolText("Tool template is required."));
|
|
539
|
+
throw new Error(ExecutionOutput.formatToolText("- field: template\n- result: Tool template is required."));
|
|
311
540
|
}
|
|
312
541
|
const authored = {
|
|
313
542
|
...(existingRecipe ?? {}),
|
|
@@ -335,24 +564,34 @@ function buildAuthoredRecipe(input, existing, existingRecipe) {
|
|
|
335
564
|
function assertRegisterToolInputModes(input) {
|
|
336
565
|
const record = input;
|
|
337
566
|
if (Object.hasOwn(record, "values")) {
|
|
338
|
-
throw new Error(ExecutionOutput.formatToolText("register_tool values was removed
|
|
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."));
|
|
339
568
|
}
|
|
340
569
|
const fromProvided = Object.hasOwn(record, "from");
|
|
341
570
|
if (fromProvided &&
|
|
342
571
|
(typeof input.from !== "string" || input.from.trim().length === 0)) {
|
|
343
|
-
throw new Error(ExecutionOutput.formatToolText("Tool from must be a non-empty Recipe reference.
|
|
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."));
|
|
344
573
|
}
|
|
345
574
|
const draftProvided = typeof input.draft === "string" && input.draft.trim().length > 0;
|
|
346
575
|
const templateProvided = Object.hasOwn(record, "template");
|
|
347
576
|
const modeCount = Number(fromProvided) + Number(draftProvided) + Number(templateProvided);
|
|
348
577
|
if (modeCount > 1) {
|
|
349
|
-
throw new Error(ExecutionOutput.formatToolText("Use exactly one register_tool source mode
|
|
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."));
|
|
350
579
|
}
|
|
351
580
|
if (fromProvided &&
|
|
352
581
|
(Object.hasOwn(record, "args") || Object.hasOwn(record, "async"))) {
|
|
353
|
-
throw new Error(ExecutionOutput.formatToolText("register_tool from inherits args and async behavior
|
|
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."));
|
|
354
583
|
}
|
|
355
584
|
}
|
|
585
|
+
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`);
|
|
594
|
+
}
|
|
356
595
|
function executeRegisterToolUnlocked(params, ctx, deps) {
|
|
357
596
|
const rawInput = params && typeof params === "object"
|
|
358
597
|
? params
|
|
@@ -363,9 +602,9 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
|
|
|
363
602
|
return listTools(deps);
|
|
364
603
|
const name = Identity.normalizeToolName(input.name);
|
|
365
604
|
if (!name)
|
|
366
|
-
throw new Error(ExecutionOutput.formatToolText("Invalid tool name."));
|
|
605
|
+
throw new Error(ExecutionOutput.formatToolText("- field: name\n- result: Invalid tool name."));
|
|
367
606
|
if (deps.reservedToolNames.has(name)) {
|
|
368
|
-
throw new Error(ExecutionOutput.formatToolText(
|
|
607
|
+
throw new Error(ExecutionOutput.formatToolText(reservedRegistrationNameText(`${name}`)));
|
|
369
608
|
}
|
|
370
609
|
if (typeof input.draft === "string" && input.draft.trim()) {
|
|
371
610
|
return promoteDraftRecipe(name, input, ctx, deps);
|
|
@@ -384,7 +623,7 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
|
|
|
384
623
|
const diagnosticSource = requestedSource?.startsWith("skill:")
|
|
385
624
|
? requestedSource.slice("skill:".length)
|
|
386
625
|
: requestedSource ?? "";
|
|
387
|
-
throw new Error(ExecutionOutput.formatToolText(
|
|
626
|
+
throw new Error(ExecutionOutput.formatToolText(sourceNormalizationFailureText(`${requestedSource}`, `${reason}`, `${activeSkillSummary(resolutionContext)}`, `${recipeDoctorAction(diagnosticSource)}`)));
|
|
388
627
|
}
|
|
389
628
|
}
|
|
390
629
|
const templateProvided = Object.hasOwn(input, "template");
|
|
@@ -398,18 +637,18 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
|
|
|
398
637
|
if (blocker)
|
|
399
638
|
throw new Error(ExecutionOutput.formatToolText(blocker));
|
|
400
639
|
if ((authoritative.exists || existing) && !input.update) {
|
|
401
|
-
throw new Error(ExecutionOutput.formatToolText(
|
|
640
|
+
throw new Error(ExecutionOutput.formatToolText(duplicateRegistrationText(`${name}`)));
|
|
402
641
|
}
|
|
403
642
|
if (template === undefined && !input.from && !existing) {
|
|
404
|
-
throw new Error(ExecutionOutput.formatToolText("New registration requires exactly one source mode
|
|
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."));
|
|
405
644
|
}
|
|
406
645
|
const recipePath = getToolRecipePath(deps, name);
|
|
407
646
|
const authoredRecipe = buildAuthoredRecipe(input, existing, authoritative.recipe);
|
|
408
647
|
const candidate = RecipesDiscovery.admitUserRecipe(recipePath, resolutionContext, authoredRecipe);
|
|
409
648
|
if (!candidate.validated || !candidate.tool) {
|
|
410
649
|
const sourceDiagnostic = requestedSource
|
|
411
|
-
?
|
|
412
|
-
:
|
|
650
|
+
? candidateAdmissionFailureText({ kind: "source", source: `${requestedSource}`, diagnostics: `${candidate.diagnostics.join("; ")}`, summary: `${activeSkillSummary(resolutionContext)}`, instruction: `${recipeDoctorAction(requestedSource)}` })
|
|
651
|
+
: candidateAdmissionFailureText({ kind: "recipe", diagnostics: `${candidate.diagnostics.join("; ")}` });
|
|
413
652
|
throw new Error(ExecutionOutput.formatToolText(sourceDiagnostic));
|
|
414
653
|
}
|
|
415
654
|
const activeBefore = deps.getActiveTools();
|
|
@@ -451,9 +690,9 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
|
|
|
451
690
|
tools.delete(name);
|
|
452
691
|
}
|
|
453
692
|
deps.setActiveTools(activeBefore);
|
|
454
|
-
throw new Error(ExecutionOutput.formatToolText(
|
|
693
|
+
throw new Error(ExecutionOutput.formatToolText(registrationTransactionFailureText(`${transactionStage}`, `${resolutionContext.generation}`, `${activeSkillSummary(resolutionContext)}`, `${error instanceof Error ? error.message : String(error)}`)));
|
|
455
694
|
}
|
|
456
|
-
deps.notify(ctx,
|
|
695
|
+
deps.notify(ctx, registryNoticeText("activated", `${name}`), "info");
|
|
457
696
|
const templateWarnings = CommandTemplates.getCommandTemplateWarnings(typeof cfg.recipe?.template === "object" && !Array.isArray(cfg.recipe.template)
|
|
458
697
|
? cfg.recipe.template
|
|
459
698
|
: { template: cfg.recipe?.template ?? cfg.template });
|
|
@@ -464,12 +703,17 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
|
|
|
464
703
|
const source = requestedSource ?? "template";
|
|
465
704
|
const argSummary = RecipesDiscovery.summarizeRegisteredToolArgs(cfg);
|
|
466
705
|
const nextActions = registrationNextActions(name, source, callableNow);
|
|
706
|
+
let displayBoundary;
|
|
467
707
|
const outcomeText = callableNow
|
|
468
708
|
? `${existing ? "Updated" : "Registered"} tool "${name}" from ${source}; callable_now=true`
|
|
469
|
-
: `Persisted tool "${name}" from ${source}; callable_now=false; activation_boundary=${activationBoundary(activation)}`;
|
|
709
|
+
: `Persisted tool "${name}" from ${source}; callable_now=false; activation_boundary=${displayBoundary = activationBoundary(activation)}`;
|
|
710
|
+
// Keep original fallible advisory evaluation/order after effects, before the new text.
|
|
711
|
+
void `${outcomeText}; required=${Schema.formatToolArgs(argSummary.required)}; optional=${Schema.formatToolArgs(argSummary.optional)}; next=${nextActions[0]}.${warningText}`;
|
|
470
712
|
return {
|
|
471
713
|
content: [
|
|
472
|
-
textContent(ExecutionOutput.formatToolText(
|
|
714
|
+
textContent(ExecutionOutput.formatToolText(registrationReceiptText({ tool: name, result: callableNow ? existing ? "updated" : "registered" : "persisted",
|
|
715
|
+
source, callable: Boolean(callableNow), boundary: displayBoundary, required: argSummary.required,
|
|
716
|
+
optional: argSummary.optional, warnings: templateWarnings, next: nextActions[0] }))),
|
|
473
717
|
],
|
|
474
718
|
details: {
|
|
475
719
|
active_tool: activation?.active_tool ?? false,
|