@recombine-ai/engine 1.0.0 → 1.1.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.
|
@@ -11,12 +11,12 @@ jobs:
|
|
|
11
11
|
timeout-minutes: 10
|
|
12
12
|
steps:
|
|
13
13
|
- name: Checkout
|
|
14
|
-
uses: actions/checkout@
|
|
14
|
+
uses: actions/checkout@v7
|
|
15
15
|
|
|
16
16
|
- name: Setup Node.js
|
|
17
|
-
uses: actions/setup-node@
|
|
17
|
+
uses: actions/setup-node@v6
|
|
18
18
|
with:
|
|
19
|
-
node-version: 24
|
|
19
|
+
node-version: '24.x'
|
|
20
20
|
cache: 'npm'
|
|
21
21
|
|
|
22
22
|
- name: Install dependencies
|
|
@@ -10,27 +10,27 @@ permissions:
|
|
|
10
10
|
contents: read
|
|
11
11
|
|
|
12
12
|
env:
|
|
13
|
-
NODE_VERSION:
|
|
13
|
+
NODE_VERSION: 24
|
|
14
14
|
|
|
15
15
|
jobs:
|
|
16
16
|
publish:
|
|
17
17
|
runs-on: ubuntu-latest
|
|
18
18
|
|
|
19
19
|
steps:
|
|
20
|
-
- uses: actions/checkout@
|
|
20
|
+
- uses: actions/checkout@v7
|
|
21
21
|
with:
|
|
22
22
|
fetch-depth: 0
|
|
23
23
|
|
|
24
24
|
- name: 'Setup Node'
|
|
25
|
-
uses: actions/setup-node@
|
|
25
|
+
uses: actions/setup-node@v6
|
|
26
26
|
with:
|
|
27
|
-
node-version:
|
|
27
|
+
node-version: '${{ env.NODE_VERSION }}.x'
|
|
28
28
|
cache: 'npm'
|
|
29
29
|
registry-url: 'https://registry.npmjs.org'
|
|
30
30
|
|
|
31
|
-
#
|
|
31
|
+
# Keep npm on a major compatible with Node 24.
|
|
32
32
|
- name: Update npm
|
|
33
|
-
run: npm install -g npm
|
|
33
|
+
run: npm install -g npm@^11
|
|
34
34
|
|
|
35
35
|
- name: 'Install dependencies'
|
|
36
36
|
run: npm ci
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/lib/engine.ts"],"names":[],"mappings":"AAIA,OAAO,EAEH,YAAY,EAGZ,OAAO,EAEP,WAAW,EAKd,MAAM,cAAc,CAAA;AAGrB,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/lib/engine.ts"],"names":[],"mappings":"AAIA,OAAO,EAEH,YAAY,EAGZ,OAAO,EAEP,WAAW,EAKd,MAAM,cAAc,CAAA;AAGrB,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAK5D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAAC,GAAG,SAAS,MAAM,EAAE,GAAG,GAAE,YAAiB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAkQxF;AAuDD,wBAAgB,kBAAkB,CAAC,eAAe,GAAE,OAAO,EAAO,GAAG,YAAY,CA2ChF;AAED,wBAAgB,cAAc,CAAC,GAAG,GAAG,OAAO,KAAK,WAAW,CAAC,GAAG,CAAC,CAEhE"}
|
package/build/lib/engine.js
CHANGED
|
@@ -45,6 +45,7 @@ const nunjucks_1 = __importDefault(require("nunjucks"));
|
|
|
45
45
|
const Zod = __importStar(require("zod"));
|
|
46
46
|
const step_tracer_1 = require("./bosun/step-tracer");
|
|
47
47
|
const step_registry_1 = require("./step-registry");
|
|
48
|
+
const STRUCTURED_RESPONSE_MAX_ATTEMPTS = 3;
|
|
48
49
|
/**
|
|
49
50
|
* Creates an AI Engine with the given configuration.
|
|
50
51
|
*
|
|
@@ -146,30 +147,9 @@ function createAIEngine(cfg = {}) {
|
|
|
146
147
|
});
|
|
147
148
|
stepTrace.stringifiedConversation = stringifiedMessages;
|
|
148
149
|
if ('schema' in step) {
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
try {
|
|
153
|
-
parsedJsonResponse = JSON.parse(stringResponse);
|
|
154
|
-
response = step.schema.parse(parsedJsonResponse);
|
|
155
|
-
}
|
|
156
|
-
catch (err) {
|
|
157
|
-
if (err instanceof SyntaxError) {
|
|
158
|
-
logger.error(`AI-generated response is not valid JSON in step ${step.name}`, {
|
|
159
|
-
response: stringResponse,
|
|
160
|
-
schema: Zod.toJSONSchema(step.schema),
|
|
161
|
-
});
|
|
162
|
-
throw new Error(`Response is not valid JSON for step ${step.name}`);
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
logger.error(`AI-generated response in step ${step.name} violates schema`, {
|
|
166
|
-
response: stringResponse,
|
|
167
|
-
schema: Zod.toJSONSchema(step.schema),
|
|
168
|
-
errors: step.schema.safeParse(parsedJsonResponse).error,
|
|
169
|
-
});
|
|
170
|
-
throw new Error(`Response validation failed for step ${step.name}`);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
150
|
+
const { parsedResponse, rawResponse } = await runStructuredStepWithRetries(step.model, prompt, stringifiedMessages, step.name, step.schema);
|
|
151
|
+
response = parsedResponse;
|
|
152
|
+
stepTrace.response = rawResponse;
|
|
173
153
|
}
|
|
174
154
|
else {
|
|
175
155
|
response = await runLLM(step.model, prompt, stringifiedMessages, undefined);
|
|
@@ -239,6 +219,49 @@ function createAIEngine(cfg = {}) {
|
|
|
239
219
|
});
|
|
240
220
|
return nunjucks_1.default.renderString(prompt, context ?? {});
|
|
241
221
|
}
|
|
222
|
+
async function runStructuredStepWithRetries(model, prompt, stringifiedMessages, stepName, schema) {
|
|
223
|
+
for (let attempt = 1; attempt <= STRUCTURED_RESPONSE_MAX_ATTEMPTS; attempt++) {
|
|
224
|
+
const stringResponse = await runLLM(model, prompt, stringifiedMessages, schema);
|
|
225
|
+
let parsedJsonResponse = undefined;
|
|
226
|
+
try {
|
|
227
|
+
parsedJsonResponse = JSON.parse(stringResponse);
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
const hasAttemptsLeft = attempt < STRUCTURED_RESPONSE_MAX_ATTEMPTS;
|
|
231
|
+
if (hasAttemptsLeft) {
|
|
232
|
+
logger.debug(`AI-generated response is not valid JSON in step ${stepName}, retry ${attempt}/${STRUCTURED_RESPONSE_MAX_ATTEMPTS}`);
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
logger.error(`AI-generated response is not valid JSON in step ${stepName}`, {
|
|
236
|
+
response: stringResponse,
|
|
237
|
+
schema: Zod.toJSONSchema(schema),
|
|
238
|
+
});
|
|
239
|
+
throw new Error(`Response is not valid JSON for step ${stepName}`);
|
|
240
|
+
}
|
|
241
|
+
const parsedResponse = schema.safeParse(parsedJsonResponse);
|
|
242
|
+
if (parsedResponse.success) {
|
|
243
|
+
return {
|
|
244
|
+
parsedResponse: parsedResponse.data,
|
|
245
|
+
rawResponse: stringResponse,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const hasAttemptsLeft = attempt < STRUCTURED_RESPONSE_MAX_ATTEMPTS;
|
|
249
|
+
if (hasAttemptsLeft) {
|
|
250
|
+
logger.debug(`AI-generated response in step ${stepName} violates schema, retry ${attempt}/${STRUCTURED_RESPONSE_MAX_ATTEMPTS}`, {
|
|
251
|
+
response: stringResponse,
|
|
252
|
+
errors: parsedResponse.error,
|
|
253
|
+
});
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
logger.error(`AI-generated response in step ${stepName} violates schema`, {
|
|
257
|
+
response: stringResponse,
|
|
258
|
+
schema: Zod.toJSONSchema(schema),
|
|
259
|
+
errors: parsedResponse.error,
|
|
260
|
+
});
|
|
261
|
+
throw new Error(`Response validation failed for step ${stepName}`);
|
|
262
|
+
}
|
|
263
|
+
throw new Error(`Response validation failed for step ${stepName}`);
|
|
264
|
+
}
|
|
242
265
|
return {
|
|
243
266
|
createWorkflow,
|
|
244
267
|
createConversation,
|
package/changelog.md
CHANGED