@specverse/engines 6.32.0 → 6.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/analyse-runner.d.ts.map +1 -1
- package/dist/ai/analyse-runner.js +8 -1
- package/dist/ai/analyse-runner.js.map +1 -1
- package/dist/ai/behaviours-runner.d.ts.map +1 -1
- package/dist/ai/behaviours-runner.js +35 -7
- package/dist/ai/behaviours-runner.js.map +1 -1
- package/dist/ai/create-runner.d.ts.map +1 -1
- package/dist/ai/create-runner.js +6 -0
- package/dist/ai/create-runner.js.map +1 -1
- package/dist/ai/deployment-emitter.d.ts +3 -0
- package/dist/ai/deployment-emitter.d.ts.map +1 -1
- package/dist/ai/deployment-emitter.js +145 -0
- package/dist/ai/deployment-emitter.js.map +1 -1
- package/dist/ai/manifest-emitter.d.ts +35 -10
- package/dist/ai/manifest-emitter.d.ts.map +1 -1
- package/dist/ai/manifest-emitter.js +140 -54
- package/dist/ai/manifest-emitter.js.map +1 -1
- package/dist/ai/skeleton-emitter.d.ts +1 -1
- package/dist/ai/skeleton-emitter.d.ts.map +1 -1
- package/dist/ai/skeleton-emitter.js +152 -14
- package/dist/ai/skeleton-emitter.js.map +1 -1
- package/dist/analyse-prepass/imports-graph.d.ts +407 -0
- package/dist/analyse-prepass/imports-graph.d.ts.map +1 -0
- package/dist/analyse-prepass/imports-graph.js +1200 -0
- package/dist/analyse-prepass/imports-graph.js.map +1 -0
- package/dist/analyse-prepass/index.d.ts +33 -0
- package/dist/analyse-prepass/index.d.ts.map +1 -1
- package/dist/analyse-prepass/index.js +35 -0
- package/dist/analyse-prepass/index.js.map +1 -1
- package/dist/inference/logical/generators/view-generator.d.ts +10 -0
- package/dist/inference/logical/generators/view-generator.d.ts.map +1 -1
- package/dist/inference/logical/generators/view-generator.js +20 -0
- package/dist/inference/logical/generators/view-generator.js.map +1 -1
- package/dist/libs/instance-factories/orms/templates/prisma/schema-generator.js +66 -4
- package/dist/parser/unified-parser.d.ts.map +1 -1
- package/dist/parser/unified-parser.js +103 -0
- package/dist/parser/unified-parser.js.map +1 -1
- package/dist/realize/index.d.ts.map +1 -1
- package/dist/realize/index.js +73 -148
- package/dist/realize/index.js.map +1 -1
- package/dist/realize/per-action-emitter.d.ts +235 -0
- package/dist/realize/per-action-emitter.d.ts.map +1 -0
- package/dist/realize/per-action-emitter.js +229 -0
- package/dist/realize/per-action-emitter.js.map +1 -0
- package/dist/realize/per-action-llm-emit.d.ts +87 -0
- package/dist/realize/per-action-llm-emit.d.ts.map +1 -0
- package/dist/realize/per-action-llm-emit.js +427 -0
- package/dist/realize/per-action-llm-emit.js.map +1 -0
- package/dist/realize/per-action-runner.d.ts +127 -0
- package/dist/realize/per-action-runner.d.ts.map +1 -0
- package/dist/realize/per-action-runner.js +269 -0
- package/dist/realize/per-action-runner.js.map +1 -0
- package/dist/realize/structural-validator.d.ts +71 -0
- package/dist/realize/structural-validator.d.ts.map +1 -0
- package/dist/realize/structural-validator.js +167 -0
- package/dist/realize/structural-validator.js.map +1 -0
- package/libs/instance-factories/orms/templates/prisma/__tests__/schema-generator.test.ts +416 -0
- package/libs/instance-factories/orms/templates/prisma/schema-generator.ts +182 -5
- package/package.json +3 -3
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-action LLM emit hook — Phase 3 of the L3 redesign.
|
|
3
|
+
*
|
|
4
|
+
* Builds an `LlmEmitFn` (the dependency-injection seam exposed by
|
|
5
|
+
* `per-action-emitter.ts`) that loads `realize-action.prompt.yaml`,
|
|
6
|
+
* calls `runPrompt` with the assembled per-action context, runs the
|
|
7
|
+
* structural validator over the LLM output, and surgically retries
|
|
8
|
+
* once on parse failure (DR3-aligned).
|
|
9
|
+
*
|
|
10
|
+
* Three quality gates run on every LLM emission:
|
|
11
|
+
* 1. Markdown extraction — pull the ```typescript fenced block out of
|
|
12
|
+
* the LLM response. Empty / missing block → null (caller falls
|
|
13
|
+
* through to γ stub).
|
|
14
|
+
* 2. Structural preservation (DR3) — every pre-baked snippet must
|
|
15
|
+
* appear verbatim in the body. A rewritten snippet is a loud
|
|
16
|
+
* failure; we throw with a diff so the user knows the LLM
|
|
17
|
+
* misbehaved.
|
|
18
|
+
* 3. esbuild parse check — the body must be syntactically valid TS.
|
|
19
|
+
* On parse failure we run ONE surgical retry with the parse error
|
|
20
|
+
* fed back as a userPrefix; if it fails again we return null and
|
|
21
|
+
* the caller emits the γ stub.
|
|
22
|
+
*
|
|
23
|
+
* The realize-action.prompt.yaml asset (Phase 2 deliverable) lives in
|
|
24
|
+
* `@specverse/assets/prompts/core/standard/default/realize-action.prompt.yaml`
|
|
25
|
+
* once that package is republished. Until then, we fall back to a
|
|
26
|
+
* filesystem path under specverse-self/assets/ so Phase 3 doesn't have
|
|
27
|
+
* to wait on a registry roundtrip.
|
|
28
|
+
*/
|
|
29
|
+
import { readFileSync, existsSync } from 'fs';
|
|
30
|
+
import { dirname, join, resolve } from 'path';
|
|
31
|
+
import { fileURLToPath } from 'url';
|
|
32
|
+
import { createRequire } from 'module';
|
|
33
|
+
import yaml from 'js-yaml';
|
|
34
|
+
import { loadPrompt, runPrompt as runPromptFn, assembleSystem, assembleUser, } from '../ai/prompt-runner.js';
|
|
35
|
+
import { validateLlmOutputPreservesConventions, } from './structural-validator.js';
|
|
36
|
+
const require = createRequire(import.meta.url);
|
|
37
|
+
/**
|
|
38
|
+
* Build an {@link LlmEmitFn} for use in per-action realize emission.
|
|
39
|
+
*
|
|
40
|
+
* The returned function:
|
|
41
|
+
* 1. Builds the prompt input from the per-action emitter's request.
|
|
42
|
+
* 2. Calls runPrompt({ operation: 'realize-action', ... }).
|
|
43
|
+
* 3. Extracts the ```typescript block from the response.
|
|
44
|
+
* 4. Runs the structural validator (DR3); throws on rewrite.
|
|
45
|
+
* 5. Runs an esbuild parse check; surgical-retries once on failure.
|
|
46
|
+
* 6. Returns the body string, or null when all attempts fail (caller
|
|
47
|
+
* falls through to γ stub).
|
|
48
|
+
*/
|
|
49
|
+
export function createRealizeActionLlmEmit(opts = {}) {
|
|
50
|
+
const runPrompt = opts.runPromptOverride ?? runPromptFn;
|
|
51
|
+
const loadPromptResolved = opts.loadPromptOverride ?? loadRealizeActionPrompt;
|
|
52
|
+
const parseCheck = opts.parseCheckOverride ?? esbuildParseCheck;
|
|
53
|
+
return async (request) => {
|
|
54
|
+
// 1. Pre-bake snippets for the structural validator. Pull from the
|
|
55
|
+
// per-step matches; matched ones contribute, unmatched skip.
|
|
56
|
+
const prebakedSnippets = [];
|
|
57
|
+
request.perStepMatches.forEach((match, idx) => {
|
|
58
|
+
if (match?.matched && match.call) {
|
|
59
|
+
prebakedSnippets.push({
|
|
60
|
+
stepNum: idx + 1,
|
|
61
|
+
stepText: request.action.steps[idx] ?? '',
|
|
62
|
+
snippet: match.call,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
// 2. Build prompt values.
|
|
67
|
+
const promptValues = buildPromptValues({
|
|
68
|
+
action: request.action,
|
|
69
|
+
context: request.context,
|
|
70
|
+
perStepMatches: request.perStepMatches,
|
|
71
|
+
availableClients: opts.availableClients,
|
|
72
|
+
siblingActions: opts.siblingActions,
|
|
73
|
+
processContext: opts.processContext,
|
|
74
|
+
});
|
|
75
|
+
// 3. Surgical retry loop (cap at 1).
|
|
76
|
+
const maxAttempts = opts.disableSurgicalRetry ? 1 : 2;
|
|
77
|
+
let lastParseError = null;
|
|
78
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
79
|
+
const userPrefix = lastParseError
|
|
80
|
+
? buildSurgicalRetryPrefix(lastParseError, request.action.name)
|
|
81
|
+
: '';
|
|
82
|
+
let runResult;
|
|
83
|
+
try {
|
|
84
|
+
const runOpts = {
|
|
85
|
+
operation: 'realize-action',
|
|
86
|
+
values: promptValues,
|
|
87
|
+
model: opts.model,
|
|
88
|
+
timeoutMs: opts.timeoutMs,
|
|
89
|
+
userPrefix,
|
|
90
|
+
};
|
|
91
|
+
// The default loadPrompt searches @specverse/assets first, then
|
|
92
|
+
// engines' bundled assets dir. Most environments hit one of those.
|
|
93
|
+
// For the local-development dev-loop where realize-action.prompt.yaml
|
|
94
|
+
// is freshly added but assets isn't republished yet, we fall back
|
|
95
|
+
// to a filesystem path inside specverse-self/assets/.
|
|
96
|
+
runResult = await callRunPromptWithFallback(runPrompt, runOpts, loadPromptResolved);
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
// Any error from runPrompt — bubble up as null (γ stub).
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
// 4. Extract the ```typescript fenced block.
|
|
103
|
+
const body = extractTypescriptBlock(runResult.text);
|
|
104
|
+
if (!body || body.trim().length === 0) {
|
|
105
|
+
// No usable body — γ stub.
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
// 5. Structural validator — DR3. A rewritten pre-baked snippet
|
|
109
|
+
// is a LOUD failure (not a silent retry).
|
|
110
|
+
const structural = validateLlmOutputPreservesConventions(body, prebakedSnippets);
|
|
111
|
+
if (structural.ok === false) {
|
|
112
|
+
throw new Error(`[realize-action] structural-preservation failed for ${request.action.ownerName}.${request.action.name}:\n${structural.reason}`);
|
|
113
|
+
}
|
|
114
|
+
// 6. esbuild parse check — surgical retry once on parse failure.
|
|
115
|
+
const parseError = await parseCheck(body);
|
|
116
|
+
if (parseError === null) {
|
|
117
|
+
// All gates green — return the body.
|
|
118
|
+
return body;
|
|
119
|
+
}
|
|
120
|
+
lastParseError = parseError;
|
|
121
|
+
// Loop continues only if we have an attempt left.
|
|
122
|
+
}
|
|
123
|
+
// Exhausted retries — fall through to γ stub.
|
|
124
|
+
return null;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// ─── Prompt loading + assets fallback ────────────────────────────────
|
|
128
|
+
/**
|
|
129
|
+
* Default loader — uses the canonical loadPrompt('realize-action') path
|
|
130
|
+
* (@specverse/assets first, then engine-bundled assets).
|
|
131
|
+
*/
|
|
132
|
+
function loadRealizeActionPrompt() {
|
|
133
|
+
return loadPrompt('realize-action');
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Wrapper around runPrompt that falls back to a workspace-relative
|
|
137
|
+
* specverse-self/assets/ lookup when realize-action.prompt.yaml isn't
|
|
138
|
+
* yet in the installed @specverse/assets package. Returns the same shape
|
|
139
|
+
* as runPrompt.
|
|
140
|
+
*
|
|
141
|
+
* This is a Phase 3 bridging concern — once @specverse/assets ships
|
|
142
|
+
* realize-action.prompt.yaml, the fallback is dead code (but harmless).
|
|
143
|
+
*/
|
|
144
|
+
async function callRunPromptWithFallback(runPromptImpl, opts, fallbackLoader) {
|
|
145
|
+
// First try: just call runPrompt — it does its own loadPrompt.
|
|
146
|
+
try {
|
|
147
|
+
return await runPromptImpl(opts);
|
|
148
|
+
}
|
|
149
|
+
catch (e) {
|
|
150
|
+
const msg = e?.message ?? String(e);
|
|
151
|
+
if (!/prompt file not found for "realize-action"/i.test(msg)) {
|
|
152
|
+
throw e;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Second try: load the prompt via the fallback resolver and call the
|
|
156
|
+
// generateText path manually. We use runPrompt's public assembleSystem /
|
|
157
|
+
// assembleUser helpers so we don't reimplement the substitution logic.
|
|
158
|
+
const prompt = fallbackLoader();
|
|
159
|
+
const system = assembleSystem(prompt);
|
|
160
|
+
const baseUser = assembleUser(prompt, opts.values);
|
|
161
|
+
const user = (opts.userPrefix || '') + baseUser;
|
|
162
|
+
// Fire onAssembled so callers (audit-trail recorders) see the input.
|
|
163
|
+
if (typeof opts.onAssembled === 'function') {
|
|
164
|
+
opts.onAssembled({ system, user });
|
|
165
|
+
}
|
|
166
|
+
// Defer to the AI SDK directly — same shape as runPrompt's body but
|
|
167
|
+
// with the prompt content already loaded.
|
|
168
|
+
const aiSdk = await import('ai');
|
|
169
|
+
const { resolveModel } = await import('../ai/model-resolver.js');
|
|
170
|
+
const model = opts.model ?? resolveModel({ ...(opts.modelOptions ?? {}), timeout: opts.timeoutMs ?? 300_000 });
|
|
171
|
+
const t0 = Date.now();
|
|
172
|
+
const result = await aiSdk.generateText({
|
|
173
|
+
model,
|
|
174
|
+
system,
|
|
175
|
+
prompt: user,
|
|
176
|
+
abortSignal: AbortSignal.timeout(opts.timeoutMs ?? 300_000),
|
|
177
|
+
});
|
|
178
|
+
const duration_ms = Date.now() - t0;
|
|
179
|
+
return {
|
|
180
|
+
text: result.text,
|
|
181
|
+
tokens: {
|
|
182
|
+
input: result.usage?.inputTokens?.total ?? null,
|
|
183
|
+
output: result.usage?.outputTokens?.total ?? null,
|
|
184
|
+
},
|
|
185
|
+
duration_ms,
|
|
186
|
+
system,
|
|
187
|
+
user,
|
|
188
|
+
providerId: model.provider,
|
|
189
|
+
modelId: model.modelId,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Filesystem fallback for realize-action.prompt.yaml when the installed
|
|
194
|
+
* @specverse/assets package predates Phase 2's prompt addition.
|
|
195
|
+
*
|
|
196
|
+
* Searches a small fixed set of candidate paths relative to the engines
|
|
197
|
+
* package's installed location and the worktree layout used in
|
|
198
|
+
* specverse-self repo. Returns null when none are found; runPrompt then
|
|
199
|
+
* surfaces the canonical "prompt file not found" error.
|
|
200
|
+
*/
|
|
201
|
+
export function loadRealizeActionPromptFromFallback() {
|
|
202
|
+
const candidates = [];
|
|
203
|
+
// 1. @specverse/assets package (covers the post-Phase-2 publish case).
|
|
204
|
+
try {
|
|
205
|
+
const pkg = require.resolve('@specverse/assets/package.json');
|
|
206
|
+
candidates.push(join(dirname(pkg), 'prompts/core/standard/default/realize-action.prompt.yaml'), join(dirname(pkg), 'prompts/core/standard/v9/realize-action.prompt.yaml'));
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
/* assets not installed */
|
|
210
|
+
}
|
|
211
|
+
// 2. Engine-bundled assets (engines ≤ 6.0.2-style layouts).
|
|
212
|
+
try {
|
|
213
|
+
const enginesPkg = require.resolve('@specverse/engines/package.json');
|
|
214
|
+
candidates.push(join(dirname(enginesPkg), 'assets/prompts/core/standard/default/realize-action.prompt.yaml'), join(dirname(enginesPkg), 'assets/prompts/core/standard/v9/realize-action.prompt.yaml'));
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
/* engines not installed at this path */
|
|
218
|
+
}
|
|
219
|
+
// 3. Worktree fallback — specverse-self lives next to specverse-engines.
|
|
220
|
+
// The path here is from `engines/dist/realize/per-action-llm-emit.js`
|
|
221
|
+
// (or `engines/src/realize/per-action-llm-emit.ts` in dev) up to the
|
|
222
|
+
// SpecVerse parent dir. Resolved at runtime so we tolerate either layout.
|
|
223
|
+
try {
|
|
224
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
225
|
+
const specverseSelfFallbacks = [
|
|
226
|
+
resolve(here, '../../../../specverse-self/assets/prompts/core/standard/default/realize-action.prompt.yaml'),
|
|
227
|
+
resolve(here, '../../../../specverse-self/assets/prompts/core/standard/v9/realize-action.prompt.yaml'),
|
|
228
|
+
resolve(here, '../../../../../specverse-self/assets/prompts/core/standard/default/realize-action.prompt.yaml'),
|
|
229
|
+
resolve(here, '../../../../../specverse-self/assets/prompts/core/standard/v9/realize-action.prompt.yaml'),
|
|
230
|
+
];
|
|
231
|
+
candidates.push(...specverseSelfFallbacks);
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
/* import.meta.url unavailable — skip */
|
|
235
|
+
}
|
|
236
|
+
for (const p of candidates) {
|
|
237
|
+
if (existsSync(p)) {
|
|
238
|
+
try {
|
|
239
|
+
return yaml.load(readFileSync(p, 'utf-8'));
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
/* try next */
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Convert an ActionSpec + per-step matcher results into the variable
|
|
250
|
+
* map consumed by realize-action.prompt.yaml's `user.template`.
|
|
251
|
+
*
|
|
252
|
+
* Variables (matching the prompt template):
|
|
253
|
+
* - ownerKind, ownerName, actionName
|
|
254
|
+
* - actionSpec — yaml block of the action's spec body
|
|
255
|
+
* - parameterList, returnType — for the signature line
|
|
256
|
+
* - perStepScaffolding — annotated [PRE-BAKED] / [WRITE] step list
|
|
257
|
+
* - availableClients, siblingActions, processContext — context
|
|
258
|
+
* strings the caller composes (default placeholder when omitted)
|
|
259
|
+
*/
|
|
260
|
+
function buildPromptValues(args) {
|
|
261
|
+
const { action, perStepMatches, availableClients, siblingActions, processContext } = args;
|
|
262
|
+
const actionSpecYaml = yamlDumpAction(action);
|
|
263
|
+
const parameterList = buildParameterList(action);
|
|
264
|
+
const returnType = buildReturnType(action);
|
|
265
|
+
const perStepScaffolding = buildPerStepScaffolding(action.steps, perStepMatches);
|
|
266
|
+
return {
|
|
267
|
+
ownerKind: action.ownerKind,
|
|
268
|
+
ownerName: action.ownerName,
|
|
269
|
+
actionName: action.name,
|
|
270
|
+
actionSpec: actionSpecYaml,
|
|
271
|
+
parameterList,
|
|
272
|
+
returnType,
|
|
273
|
+
perStepScaffolding,
|
|
274
|
+
availableClients: availableClients ?? '(none)',
|
|
275
|
+
siblingActions: siblingActions ?? '(none listed)',
|
|
276
|
+
processContext: processContext ?? '(no related processes)',
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
/** Render the action's spec body as YAML for the SOURCE OF TRUTH section. */
|
|
280
|
+
function yamlDumpAction(action) {
|
|
281
|
+
const body = {};
|
|
282
|
+
if (action.description)
|
|
283
|
+
body.description = action.description;
|
|
284
|
+
if (action.parameters)
|
|
285
|
+
body.parameters = action.parameters;
|
|
286
|
+
if (action.returns)
|
|
287
|
+
body.returns = action.returns;
|
|
288
|
+
if (action.steps?.length)
|
|
289
|
+
body.steps = action.steps;
|
|
290
|
+
if (action.requires?.length)
|
|
291
|
+
body.requires = action.requires;
|
|
292
|
+
if (action.ensures?.length)
|
|
293
|
+
body.ensures = action.ensures;
|
|
294
|
+
if (action.publishes?.length)
|
|
295
|
+
body.publishes = action.publishes;
|
|
296
|
+
return yaml.dump({ [action.name]: body }, { lineWidth: 100, noRefs: true });
|
|
297
|
+
}
|
|
298
|
+
/** Build the param list for the signature line shown to the LLM. */
|
|
299
|
+
function buildParameterList(action) {
|
|
300
|
+
if (!action.parameters || Object.keys(action.parameters).length === 0) {
|
|
301
|
+
return '';
|
|
302
|
+
}
|
|
303
|
+
return Object.entries(action.parameters)
|
|
304
|
+
.map(([name, spec]) => `${name}: ${specTypeToTs(spec)}`)
|
|
305
|
+
.join(', ');
|
|
306
|
+
}
|
|
307
|
+
/** Build the return-type string for the signature line. */
|
|
308
|
+
function buildReturnType(action) {
|
|
309
|
+
if (!action.returns)
|
|
310
|
+
return 'void';
|
|
311
|
+
return specTypeToTs(action.returns);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Translate spec-type strings into approximate TS types. The realize
|
|
315
|
+
* pipeline has a more rigorous translator; this is a "good enough for
|
|
316
|
+
* the prompt" version. The LLM only uses it as documentation — the
|
|
317
|
+
* realize template does the real signature emission.
|
|
318
|
+
*/
|
|
319
|
+
function specTypeToTs(specType) {
|
|
320
|
+
// "UUID required" → "string"; "Decimal required" → "number"; etc.
|
|
321
|
+
const tokens = specType.split(/\s+/);
|
|
322
|
+
const head = tokens[0]?.toLowerCase() ?? '';
|
|
323
|
+
switch (head) {
|
|
324
|
+
case 'string':
|
|
325
|
+
case 'uuid':
|
|
326
|
+
case 'date':
|
|
327
|
+
case 'datetime':
|
|
328
|
+
return 'string';
|
|
329
|
+
case 'integer':
|
|
330
|
+
case 'int':
|
|
331
|
+
case 'float':
|
|
332
|
+
case 'number':
|
|
333
|
+
case 'decimal':
|
|
334
|
+
return 'number';
|
|
335
|
+
case 'boolean':
|
|
336
|
+
case 'bool':
|
|
337
|
+
return 'boolean';
|
|
338
|
+
case 'object':
|
|
339
|
+
case 'json':
|
|
340
|
+
return 'Record<string, unknown>';
|
|
341
|
+
default:
|
|
342
|
+
// Domain types like `OrderResult` come through verbatim.
|
|
343
|
+
return tokens[0] ?? 'unknown';
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
/** Render the per-step scaffolding block: annotated [PRE-BAKED] / [WRITE]. */
|
|
347
|
+
function buildPerStepScaffolding(steps, perStepMatches) {
|
|
348
|
+
if (steps.length === 0)
|
|
349
|
+
return '(no steps)';
|
|
350
|
+
const lines = [];
|
|
351
|
+
for (let i = 0; i < steps.length; i++) {
|
|
352
|
+
const stepText = steps[i];
|
|
353
|
+
const match = perStepMatches[i];
|
|
354
|
+
if (match?.matched && match.call) {
|
|
355
|
+
lines.push(` ${i + 1}. [PRE-BAKED] "${stepText}"`);
|
|
356
|
+
// Indent the snippet so it's clearly nested under the step.
|
|
357
|
+
const snippetLines = match.call.split('\n').map((l) => ` ${l.trimStart()}`);
|
|
358
|
+
lines.push(...snippetLines);
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
lines.push(` ${i + 1}. [WRITE] "${stepText}"`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return lines.join('\n');
|
|
365
|
+
}
|
|
366
|
+
// ─── Output extraction + parse check ─────────────────────────────────
|
|
367
|
+
/**
|
|
368
|
+
* Pull the first ```typescript fenced block out of an LLM response.
|
|
369
|
+
* Tolerates plain ``` (no language tag) when the body starts with
|
|
370
|
+
* recognisably-TS content. Returns null if no block is found.
|
|
371
|
+
*/
|
|
372
|
+
export function extractTypescriptBlock(text) {
|
|
373
|
+
const tsBlock = text.match(/```(?:typescript|ts)\s*\n([\s\S]*?)```/);
|
|
374
|
+
if (tsBlock?.[1])
|
|
375
|
+
return tsBlock[1].trim();
|
|
376
|
+
// Generic ``` block — accept when the content looks like TS (has at
|
|
377
|
+
// least one of: const, let, await, return, throw at start of line).
|
|
378
|
+
const generic = text.match(/```\s*\n([\s\S]*?)```/);
|
|
379
|
+
if (generic?.[1]) {
|
|
380
|
+
const candidate = generic[1].trim();
|
|
381
|
+
if (/^(const|let|await|return|throw|if|try)\b/m.test(candidate)) {
|
|
382
|
+
return candidate;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* esbuild parse check on a method body. We wrap the body in a synthetic
|
|
389
|
+
* async function so esbuild can parse top-level await + return as
|
|
390
|
+
* function-scoped statements.
|
|
391
|
+
*
|
|
392
|
+
* Returns null on success, a brief error message on failure. Skipped
|
|
393
|
+
* silently (returns null) if esbuild isn't installed — matches the
|
|
394
|
+
* existing per-step ai-behaviors-generator's tolerance.
|
|
395
|
+
*/
|
|
396
|
+
async function esbuildParseCheck(body) {
|
|
397
|
+
try {
|
|
398
|
+
const esbuild = await import('esbuild');
|
|
399
|
+
const wrapped = `export async function __realizeAction(): Promise<unknown> {\n${body}\n}`;
|
|
400
|
+
await esbuild.transform(wrapped, { loader: 'ts', format: 'esm', target: 'es2022' });
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
catch (err) {
|
|
404
|
+
const msg = err?.errors?.[0]?.text || err?.message || 'unknown parse error';
|
|
405
|
+
return msg;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Build the user-prefix prepended on the surgical-retry attempt. Frames
|
|
410
|
+
* the prior parse error as a fix-up directive without re-stating the
|
|
411
|
+
* whole prompt.
|
|
412
|
+
*/
|
|
413
|
+
function buildSurgicalRetryPrefix(parseError, actionName) {
|
|
414
|
+
return [
|
|
415
|
+
`Your previous output for ${actionName} failed esbuild parse:`,
|
|
416
|
+
'',
|
|
417
|
+
parseError,
|
|
418
|
+
'',
|
|
419
|
+
'Re-emit the method body, fixing the syntax error. Same output format ' +
|
|
420
|
+
'(```typescript fenced block, body only). Preserve all [PRE-BAKED] ' +
|
|
421
|
+
'snippets verbatim.',
|
|
422
|
+
'',
|
|
423
|
+
'---',
|
|
424
|
+
'',
|
|
425
|
+
].join('\n');
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=per-action-llm-emit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"per-action-llm-emit.js","sourceRoot":"","sources":["../../src/realize/per-action-llm-emit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-action realize runner — Phase 3 of the L3 redesign.
|
|
3
|
+
*
|
|
4
|
+
* The orchestration glue between the spec walker (controllers + services
|
|
5
|
+
* + their actions/operations) and the per-action emitter. This is the
|
|
6
|
+
* call site that REPLACES the legacy `generateAiBehaviors` step in
|
|
7
|
+
* `realize/index.ts` when the per-action path is enabled.
|
|
8
|
+
*
|
|
9
|
+
* Responsibilities:
|
|
10
|
+
* 1. Walk the spec's controllers + services and collect every custom
|
|
11
|
+
* action (controller actions + service operations) along with the
|
|
12
|
+
* owning entity name + step list + spec metadata.
|
|
13
|
+
* 2. For each action, build an ActionSpec + RealizeContext and call
|
|
14
|
+
* emitActionBody. The matcher (prisma / mongo-native / pg-native)
|
|
15
|
+
* and conventions array are passed through as injected
|
|
16
|
+
* dependencies — same shape the legacy ai-behaviors path uses.
|
|
17
|
+
* 3. Group results by owner and emit one `<Owner>.ai.ts` file per
|
|
18
|
+
* owner, containing one exported async function per action with
|
|
19
|
+
* the LLM-emitted (or stub-γ-emitted) body inline.
|
|
20
|
+
*
|
|
21
|
+
* Concurrency: the LLM call site (when a real LLM is configured) is
|
|
22
|
+
* sequential per owner — keeps surgical-retry's parse-error feedback
|
|
23
|
+
* clean and bounds the API spend in the worst case. A future Phase
|
|
24
|
+
* could parallelise across owners; not the default in V1.
|
|
25
|
+
*
|
|
26
|
+
* The legacy `<Owner>.ai.ts` emitted by `ai-behaviors-generator.ts`
|
|
27
|
+
* contains per-STEP helpers; the new file contains per-ACTION pure
|
|
28
|
+
* functions. DR2 says keep the filename, repurpose the content shape.
|
|
29
|
+
* Both shapes co-exist when this runner runs alongside the legacy
|
|
30
|
+
* generator (gated by env flag); the new file overwrites the legacy
|
|
31
|
+
* output when both are run for the same owner. The integration test
|
|
32
|
+
* pins the new shape; the env flag governs which runs in realize.
|
|
33
|
+
*/
|
|
34
|
+
import { type ActionSpec, type LlmEmitFn, type SharedConvention, type SharedStepContext, type MatcherFn } from './per-action-emitter.js';
|
|
35
|
+
/**
|
|
36
|
+
* One action collected from the spec walk. Tracks both the owning
|
|
37
|
+
* entity (for grouping into a single `.ai.ts` file) and the spec
|
|
38
|
+
* metadata the per-action emitter needs.
|
|
39
|
+
*/
|
|
40
|
+
export interface CollectedAction {
|
|
41
|
+
ownerKind: 'controller' | 'service' | 'model';
|
|
42
|
+
/** Controller / service name (the file owner). */
|
|
43
|
+
ownerName: string;
|
|
44
|
+
/** The controller's `model:` reference (or service's "self" name). */
|
|
45
|
+
modelName: string;
|
|
46
|
+
/** Action / operation name as it appears in the spec. */
|
|
47
|
+
actionName: string;
|
|
48
|
+
/** Original ActionSpec — passed straight to emitActionBody. */
|
|
49
|
+
spec: ActionSpec;
|
|
50
|
+
}
|
|
51
|
+
/** Per-owner emission result — drives the `.ai.ts` file write. */
|
|
52
|
+
export interface OwnerEmissionResult {
|
|
53
|
+
ownerName: string;
|
|
54
|
+
/** Map<actionName, body> — the body strings the emitter produced. */
|
|
55
|
+
bodies: Map<string, string>;
|
|
56
|
+
/** Per-action ActionSpec lookup, for shaping the `.ai.ts` signatures. */
|
|
57
|
+
specs: Map<string, ActionSpec>;
|
|
58
|
+
}
|
|
59
|
+
/** Options for {@link runPerActionEmission}. */
|
|
60
|
+
export interface RunPerActionEmissionOptions {
|
|
61
|
+
/** The full spec (already parsed / inferred). */
|
|
62
|
+
spec: any;
|
|
63
|
+
/** Output directory — `.ai.ts` files go under `${outputDir}/backend/src/behaviors/`. */
|
|
64
|
+
outputDir: string;
|
|
65
|
+
/** Convention matcher (matchAgainstConventions, or a test stub). */
|
|
66
|
+
matcher?: MatcherFn;
|
|
67
|
+
/** ORM-specific convention list — prisma / mongo-native / pg-native. */
|
|
68
|
+
conventions?: ReadonlyArray<SharedConvention<SharedStepContext>>;
|
|
69
|
+
/** AI-args expression for the matcher's fallback shape. */
|
|
70
|
+
aiArgsExpr?: (inputs: string[], paramNames: string[]) => string;
|
|
71
|
+
/** LLM emit hook — typically createRealizeActionLlmEmit(). When omitted,
|
|
72
|
+
* every action falls through to γ-stub mode. */
|
|
73
|
+
llmEmit?: LlmEmitFn;
|
|
74
|
+
/** LLM availability predicate. Default mirrors the per-action emitter. */
|
|
75
|
+
canCallLLM?: () => boolean;
|
|
76
|
+
/** When true, skip writing to disk and return the in-memory result.
|
|
77
|
+
* Used by tests to assert the produced bodies without touching fs. */
|
|
78
|
+
dryRun?: boolean;
|
|
79
|
+
/** Quiet mode for tests — suppress console.log progress lines. */
|
|
80
|
+
silent?: boolean;
|
|
81
|
+
}
|
|
82
|
+
/** Aggregate result from {@link runPerActionEmission}. */
|
|
83
|
+
export interface RunPerActionEmissionResult {
|
|
84
|
+
/** One entry per owning entity (controller or service). */
|
|
85
|
+
owners: OwnerEmissionResult[];
|
|
86
|
+
/** Files actually written to disk (empty in dryRun mode). */
|
|
87
|
+
filesWritten: string[];
|
|
88
|
+
/** Aggregate counters for logging / report assembly. */
|
|
89
|
+
totals: {
|
|
90
|
+
actionCount: number;
|
|
91
|
+
ownerCount: number;
|
|
92
|
+
stubCount: number;
|
|
93
|
+
llmCount: number;
|
|
94
|
+
fullyMatchedCount: number;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Walk the spec, dispatch each custom action through the per-action
|
|
99
|
+
* emitter, and write per-owner `.ai.ts` files.
|
|
100
|
+
*
|
|
101
|
+
* Collection rules:
|
|
102
|
+
* - Controllers: every entry under `controller.actions` becomes a
|
|
103
|
+
* CollectedAction. CURVED ops (`controller.cured.{create,...}`)
|
|
104
|
+
* are skipped — the L1 instance-factory templates handle those
|
|
105
|
+
* deterministically.
|
|
106
|
+
* - Services: every entry under `service.operations` becomes a
|
|
107
|
+
* CollectedAction. Service operations don't have CURVED kinship.
|
|
108
|
+
* - Model behaviours (`model.behaviors.<name>`) are NOT collected by
|
|
109
|
+
* this runner — the controller / service is the realized surface;
|
|
110
|
+
* model behaviours flow through controllers via the inference
|
|
111
|
+
* pipeline before realize sees them. A future phase could collect
|
|
112
|
+
* them directly if needed.
|
|
113
|
+
*/
|
|
114
|
+
export declare function runPerActionEmission(opts: RunPerActionEmissionOptions): Promise<RunPerActionEmissionResult>;
|
|
115
|
+
/**
|
|
116
|
+
* Walk the spec and collect every custom controller action + service
|
|
117
|
+
* operation that has a non-empty `steps:` block. Without steps, the
|
|
118
|
+
* per-action emitter has no work to do — those actions stay as
|
|
119
|
+
* placeholder methods on the controller / service.
|
|
120
|
+
*/
|
|
121
|
+
export declare function collectActions(spec: any): CollectedAction[];
|
|
122
|
+
/**
|
|
123
|
+
* Render the `.ai.ts` content for one owner. Exported so tests can
|
|
124
|
+
* assert on the produced shape without going to disk.
|
|
125
|
+
*/
|
|
126
|
+
export declare function renderOwnerAiFile(owner: OwnerEmissionResult): string;
|
|
127
|
+
//# sourceMappingURL=per-action-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"per-action-runner.d.ts","sourceRoot":"","sources":["../../src/realize/per-action-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAIH,OAAO,EAEL,KAAK,UAAU,EAEf,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACf,MAAM,yBAAyB,CAAC;AAEjC;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC;IAC9C,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,kEAAkE;AAClE,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,yEAAyE;IACzE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CAChC;AAED,gDAAgD;AAChD,MAAM,WAAW,2BAA2B;IAC1C,iDAAiD;IACjD,IAAI,EAAE,GAAG,CAAC;IACV,wFAAwF;IACxF,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,wEAAwE;IACxE,WAAW,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACjE,2DAA2D;IAC3D,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC;IAChE;qDACiD;IACjD,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAC3B;2EACuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,0DAA0D;AAC1D,MAAM,WAAW,0BAA0B;IACzC,2DAA2D;IAC3D,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,6DAA6D;IAC7D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,wDAAwD;IACxD,MAAM,EAAE;QACN,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,2BAA2B,GAChC,OAAO,CAAC,0BAA0B,CAAC,CA0DrC;AAID;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,GAAG,GAAG,eAAe,EAAE,CAqD3D;AAuDD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAgCpE"}
|