@far-world-labs/verblets 0.1.7 → 0.3.2
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/README.md +86 -213
- package/dist/index.browser.js +74 -0
- package/dist/index.js +548 -0
- package/dist/shared-C6kPWghF.js +7806 -0
- package/package.json +32 -8
- package/.cursor/launch.json +0 -30
- package/.cursor/settings.json +0 -20
- package/.github/workflows/branch-protection.yml +0 -22
- package/.github/workflows/ci.yml +0 -165
- package/.husky/pre-commit +0 -4
- package/.prettierrc +0 -6
- package/.release-it.json +0 -12
- package/.vitest.config.examples.js +0 -8
- package/.vitest.config.js +0 -8
- package/.vscode/launch.json +0 -31
- package/AGENTS.md +0 -220
- package/DEVELOPING.md +0 -105
- package/docker-compose.yml +0 -7
- package/eslint.config.js +0 -80
- package/scripts/generate-chain/index.js +0 -111
- package/scripts/generate-lib/index.js +0 -68
- package/scripts/generate-test/index.js +0 -137
- package/scripts/generate-verblet/README.md +0 -17
- package/scripts/generate-verblet/index.js +0 -110
- package/scripts/run.sh +0 -15
- package/scripts/runner/index.js +0 -56
- package/scripts/simple-editor/README.md +0 -34
- package/scripts/simple-editor/index.js +0 -79
- package/scripts/summarize-files/index.js +0 -70
- package/src/chains/README.md +0 -30
- package/src/chains/anonymize/README.md +0 -21
- package/src/chains/anonymize/index.examples.js +0 -75
- package/src/chains/anonymize/index.js +0 -121
- package/src/chains/anonymize/index.spec.js +0 -78
- package/src/chains/bulk-central-tendency/index.examples.js +0 -138
- package/src/chains/bulk-central-tendency/index.js +0 -91
- package/src/chains/bulk-filter/README.md +0 -21
- package/src/chains/bulk-filter/index.examples.js +0 -22
- package/src/chains/bulk-filter/index.js +0 -58
- package/src/chains/bulk-filter/index.spec.js +0 -38
- package/src/chains/bulk-find/README.md +0 -16
- package/src/chains/bulk-find/index.examples.js +0 -20
- package/src/chains/bulk-find/index.js +0 -30
- package/src/chains/bulk-find/index.spec.js +0 -26
- package/src/chains/bulk-group/README.md +0 -23
- package/src/chains/bulk-group/index.examples.js +0 -18
- package/src/chains/bulk-group/index.js +0 -34
- package/src/chains/bulk-group/index.spec.js +0 -41
- package/src/chains/bulk-map/README.md +0 -43
- package/src/chains/bulk-map/index.examples.js +0 -17
- package/src/chains/bulk-map/index.js +0 -86
- package/src/chains/bulk-map/index.spec.js +0 -44
- package/src/chains/bulk-reduce/README.md +0 -12
- package/src/chains/bulk-reduce/index.examples.js +0 -15
- package/src/chains/bulk-reduce/index.js +0 -13
- package/src/chains/bulk-reduce/index.spec.js +0 -25
- package/src/chains/bulk-score/README.md +0 -16
- package/src/chains/bulk-score/bulk-score-result.json +0 -18
- package/src/chains/bulk-score/index.examples.js +0 -22
- package/src/chains/bulk-score/index.js +0 -133
- package/src/chains/bulk-score/index.spec.js +0 -30
- package/src/chains/category-samples/README.md +0 -61
- package/src/chains/category-samples/index.examples.js +0 -103
- package/src/chains/category-samples/index.js +0 -134
- package/src/chains/collect-terms/README.md +0 -12
- package/src/chains/collect-terms/index.examples.js +0 -16
- package/src/chains/collect-terms/index.js +0 -44
- package/src/chains/collect-terms/index.spec.js +0 -25
- package/src/chains/date/README.md +0 -12
- package/src/chains/date/index.examples.js +0 -47
- package/src/chains/date/index.js +0 -74
- package/src/chains/date/index.spec.js +0 -62
- package/src/chains/disambiguate/README.md +0 -22
- package/src/chains/disambiguate/disambiguate-meanings-result.json +0 -16
- package/src/chains/disambiguate/index.examples.js +0 -18
- package/src/chains/disambiguate/index.js +0 -92
- package/src/chains/disambiguate/index.spec.js +0 -25
- package/src/chains/dismantle/README.md +0 -67
- package/src/chains/dismantle/dismantle.examples.js +0 -27
- package/src/chains/dismantle/index.examples.js +0 -30
- package/src/chains/dismantle/index.js +0 -303
- package/src/chains/dismantle/index.spec.js +0 -32
- package/src/chains/expect/README.md +0 -171
- package/src/chains/expect/index.examples.js +0 -146
- package/src/chains/expect/index.js +0 -173
- package/src/chains/expect/index.spec.js +0 -324
- package/src/chains/filter-ambiguous/README.md +0 -11
- package/src/chains/filter-ambiguous/index.examples.js +0 -20
- package/src/chains/filter-ambiguous/index.js +0 -49
- package/src/chains/filter-ambiguous/index.spec.js +0 -31
- package/src/chains/glossary/README.md +0 -19
- package/src/chains/glossary/index.examples.js +0 -386
- package/src/chains/glossary/index.js +0 -75
- package/src/chains/glossary/index.spec.js +0 -19
- package/src/chains/intersections/README.md +0 -152
- package/src/chains/intersections/index.examples.js +0 -279
- package/src/chains/intersections/index.js +0 -366
- package/src/chains/intersections/intersection-result.json +0 -38
- package/src/chains/list/index.examples.js +0 -68
- package/src/chains/list/index.js +0 -214
- package/src/chains/list/index.spec.js +0 -67
- package/src/chains/list/list-result.json +0 -16
- package/src/chains/list/schema.json +0 -24
- package/src/chains/llm-logger/README.md +0 -208
- package/src/chains/llm-logger/index.js +0 -205
- package/src/chains/llm-logger/index.spec.js +0 -330
- package/src/chains/questions/index.examples.js +0 -69
- package/src/chains/questions/index.js +0 -135
- package/src/chains/questions/index.spec.js +0 -29
- package/src/chains/scan-js/index.js +0 -116
- package/src/chains/set-interval/README.md +0 -81
- package/src/chains/set-interval/index.examples.js +0 -36
- package/src/chains/set-interval/index.js +0 -131
- package/src/chains/set-interval/index.spec.js +0 -70
- package/src/chains/socratic/README.md +0 -17
- package/src/chains/socratic/index.js +0 -64
- package/src/chains/socratic/index.spec.js +0 -24
- package/src/chains/sort/index.examples.js +0 -36
- package/src/chains/sort/index.js +0 -163
- package/src/chains/sort/index.spec.js +0 -112
- package/src/chains/sort/sort-result.json +0 -16
- package/src/chains/summary-map/README.md +0 -41
- package/src/chains/summary-map/index.examples.js +0 -64
- package/src/chains/summary-map/index.js +0 -226
- package/src/chains/summary-map/index.spec.js +0 -153
- package/src/chains/test/index.js +0 -114
- package/src/chains/test-advice/index.js +0 -35
- package/src/chains/themes/README.md +0 -20
- package/src/chains/themes/index.examples.js +0 -17
- package/src/chains/themes/index.js +0 -28
- package/src/chains/themes/index.spec.js +0 -19
- package/src/chains/veiled-variants/index.examples.js +0 -18
- package/src/chains/veiled-variants/index.js +0 -107
- package/src/chains/veiled-variants/index.spec.js +0 -40
- package/src/constants/common.js +0 -7
- package/src/constants/messages.js +0 -3
- package/src/constants/models.js +0 -183
- package/src/index.js +0 -193
- package/src/json-schemas/README.md +0 -13
- package/src/json-schemas/cars-test.json +0 -11
- package/src/json-schemas/index.js +0 -12
- package/src/json-schemas/intent.json +0 -38
- package/src/json-schemas/schema-dot-org-photograph.json +0 -133
- package/src/json-schemas/schema-dot-org-place.json +0 -129
- package/src/lib/README.md +0 -26
- package/src/lib/any-signal/index.js +0 -28
- package/src/lib/bulk-filter/README.md +0 -22
- package/src/lib/bulk-filter/index.examples.js +0 -27
- package/src/lib/bulk-filter/index.js +0 -63
- package/src/lib/bulk-filter/index.spec.js +0 -38
- package/src/lib/bulk-find/README.md +0 -18
- package/src/lib/bulk-find/index.examples.js +0 -19
- package/src/lib/bulk-find/index.js +0 -30
- package/src/lib/bulk-find/index.spec.js +0 -41
- package/src/lib/chatgpt/index.js +0 -163
- package/src/lib/combinations/index.js +0 -30
- package/src/lib/combinations/index.spec.js +0 -23
- package/src/lib/editor/index.js +0 -31
- package/src/lib/functional/index.js +0 -28
- package/src/lib/logger-service/index.js +0 -32
- package/src/lib/parse-js-parts/index.js +0 -321
- package/src/lib/parse-js-parts/index.spec.js +0 -156
- package/src/lib/parse-llm-list/README.md +0 -39
- package/src/lib/parse-llm-list/index.js +0 -54
- package/src/lib/parse-llm-list/index.spec.js +0 -59
- package/src/lib/path-aliases/index.js +0 -37
- package/src/lib/path-aliases/index.spec.js +0 -64
- package/src/lib/pave/index.js +0 -34
- package/src/lib/pave/index.spec.js +0 -76
- package/src/lib/prompt-cache/index.js +0 -50
- package/src/lib/retry/index.js +0 -66
- package/src/lib/retry/index.spec.js +0 -86
- package/src/lib/ring-buffer/README.md +0 -460
- package/src/lib/ring-buffer/index.js +0 -1074
- package/src/lib/search-best-first/city-walk.spec.js +0 -37
- package/src/lib/search-best-first/index.js +0 -97
- package/src/lib/search-best-first/index.spec.js +0 -35
- package/src/lib/search-js-files/code-features-property-definitions.json +0 -123
- package/src/lib/search-js-files/index.examples.js +0 -22
- package/src/lib/search-js-files/index.js +0 -155
- package/src/lib/search-js-files/index.spec.js +0 -34
- package/src/lib/search-js-files/scan-file.js +0 -242
- package/src/lib/shorten-text/index.js +0 -25
- package/src/lib/shorten-text/index.spec.js +0 -68
- package/src/lib/strip-numeric/index.js +0 -5
- package/src/lib/strip-response/index.js +0 -30
- package/src/lib/template-replace/index.js +0 -23
- package/src/lib/template-replace/index.spec.js +0 -60
- package/src/lib/timed-abort-controller/index.js +0 -41
- package/src/lib/to-bool/index.js +0 -8
- package/src/lib/to-date/index.js +0 -11
- package/src/lib/to-enum/index.js +0 -14
- package/src/lib/to-number/index.js +0 -12
- package/src/lib/to-number-with-units/index.js +0 -51
- package/src/lib/transcribe/index.js +0 -78
- package/src/prompts/README.md +0 -17
- package/src/prompts/as-enum.js +0 -5
- package/src/prompts/as-json-schema.js +0 -9
- package/src/prompts/as-object-with-schema.js +0 -26
- package/src/prompts/as-schema-org-text.js +0 -25
- package/src/prompts/as-schema-org-type.js +0 -1
- package/src/prompts/blog-post.js +0 -7
- package/src/prompts/code-features.js +0 -24
- package/src/prompts/constants.js +0 -101
- package/src/prompts/features-json-schema.js +0 -27
- package/src/prompts/generate-collection.js +0 -26
- package/src/prompts/generate-list.js +0 -48
- package/src/prompts/generate-questions.js +0 -19
- package/src/prompts/index.js +0 -20
- package/src/prompts/intent.js +0 -60
- package/src/prompts/output-succinct-names.js +0 -3
- package/src/prompts/select-from-threshold.js +0 -17
- package/src/prompts/sort.js +0 -31
- package/src/prompts/style.js +0 -38
- package/src/prompts/summarize.js +0 -13
- package/src/prompts/token-budget.js +0 -3
- package/src/prompts/wrap-list.js +0 -11
- package/src/prompts/wrap-variable.js +0 -36
- package/src/services/llm-model/global-overrides.spec.js +0 -432
- package/src/services/llm-model/index.js +0 -308
- package/src/services/llm-model/model.js +0 -21
- package/src/services/llm-model/negotiate.spec.js +0 -447
- package/src/services/redis/index.js +0 -147
- package/src/test/setup.js +0 -20
- package/src/verblets/README.md +0 -26
- package/src/verblets/auto/index.examples.js +0 -31
- package/src/verblets/auto/index.js +0 -28
- package/src/verblets/auto/index.spec.js +0 -32
- package/src/verblets/bool/README.md +0 -36
- package/src/verblets/bool/index.examples.js +0 -80
- package/src/verblets/bool/index.js +0 -25
- package/src/verblets/bool/index.schema.json +0 -14
- package/src/verblets/bool/index.spec.js +0 -33
- package/src/verblets/central-tendency/README.md +0 -166
- package/src/verblets/central-tendency/central-tendency-result.json +0 -24
- package/src/verblets/central-tendency/index.examples.js +0 -196
- package/src/verblets/central-tendency/index.js +0 -171
- package/src/verblets/central-tendency/index.spec.js +0 -148
- package/src/verblets/enum/index.examples.js +0 -30
- package/src/verblets/enum/index.js +0 -18
- package/src/verblets/enum/index.spec.js +0 -35
- package/src/verblets/expect/README.md +0 -64
- package/src/verblets/expect/index.examples.js +0 -109
- package/src/verblets/expect/index.js +0 -75
- package/src/verblets/expect/index.spec.js +0 -127
- package/src/verblets/intent/index.examples.js +0 -139
- package/src/verblets/intent/index.js +0 -60
- package/src/verblets/intent/index.spec.js +0 -31
- package/src/verblets/intersection/README.md +0 -16
- package/src/verblets/intersection/index.examples.js +0 -89
- package/src/verblets/intersection/index.js +0 -84
- package/src/verblets/intersection/index.spec.js +0 -60
- package/src/verblets/intersection/intersection-result.json +0 -16
- package/src/verblets/list-expand/README.md +0 -10
- package/src/verblets/list-expand/index.examples.js +0 -14
- package/src/verblets/list-expand/index.js +0 -104
- package/src/verblets/list-expand/index.spec.js +0 -18
- package/src/verblets/list-expand/list-expand-result.json +0 -16
- package/src/verblets/list-filter/README.md +0 -22
- package/src/verblets/list-filter/index.examples.js +0 -26
- package/src/verblets/list-filter/index.js +0 -18
- package/src/verblets/list-filter/index.spec.js +0 -19
- package/src/verblets/list-find/README.md +0 -11
- package/src/verblets/list-find/index.examples.js +0 -15
- package/src/verblets/list-find/index.js +0 -17
- package/src/verblets/list-find/index.spec.js +0 -19
- package/src/verblets/list-group/README.md +0 -16
- package/src/verblets/list-group/index.examples.js +0 -16
- package/src/verblets/list-group/index.js +0 -112
- package/src/verblets/list-group/index.spec.js +0 -35
- package/src/verblets/list-group/list-group-result.json +0 -16
- package/src/verblets/list-map/README.md +0 -11
- package/src/verblets/list-map/index.examples.js +0 -15
- package/src/verblets/list-map/index.js +0 -26
- package/src/verblets/list-map/index.spec.js +0 -17
- package/src/verblets/list-reduce/README.md +0 -10
- package/src/verblets/list-reduce/index.examples.js +0 -14
- package/src/verblets/list-reduce/index.js +0 -21
- package/src/verblets/list-reduce/index.spec.js +0 -27
- package/src/verblets/list-reduce/index.spec.jsx +0 -27
- package/src/verblets/name/README.md +0 -15
- package/src/verblets/name/index.examples.js +0 -28
- package/src/verblets/name/index.js +0 -19
- package/src/verblets/name/index.spec.js +0 -33
- package/src/verblets/name-similar-to/README.md +0 -26
- package/src/verblets/name-similar-to/index.examples.js +0 -18
- package/src/verblets/name-similar-to/index.js +0 -20
- package/src/verblets/name-similar-to/index.spec.js +0 -13
- package/src/verblets/number/index.examples.js +0 -199
- package/src/verblets/number/index.js +0 -25
- package/src/verblets/number/index.spec.js +0 -33
- package/src/verblets/number-with-units/index.examples.js +0 -38
- package/src/verblets/number-with-units/index.js +0 -84
- package/src/verblets/number-with-units/index.spec.js +0 -46
- package/src/verblets/number-with-units/number-with-units-result.json +0 -23
- package/src/verblets/schema-org/index.examples.js +0 -51
- package/src/verblets/schema-org/index.js +0 -37
- package/src/verblets/schema-org/index.spec.js +0 -39
- package/src/verblets/sentiment/README.md +0 -10
- package/src/verblets/sentiment/index.examples.js +0 -20
- package/src/verblets/sentiment/index.js +0 -9
- package/src/verblets/sentiment/index.spec.js +0 -20
- package/src/verblets/to-object/README.md +0 -38
- package/src/verblets/to-object/index.examples.js +0 -29
- package/src/verblets/to-object/index.js +0 -131
- package/src/verblets/to-object/index.spec.js +0 -71
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { longTestTimeout } from '../../constants/common.js';
|
|
3
|
-
import { dismantle } from './index.js';
|
|
4
|
-
|
|
5
|
-
const examples = [
|
|
6
|
-
{
|
|
7
|
-
name: 'Basic usage',
|
|
8
|
-
inputs: { text: 'test' },
|
|
9
|
-
want: { result: {} },
|
|
10
|
-
},
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
describe('Dismantle chain', () => {
|
|
14
|
-
examples.forEach((example) => {
|
|
15
|
-
it(
|
|
16
|
-
example.name,
|
|
17
|
-
async () => {
|
|
18
|
-
const result = await dismantle(example.inputs.text);
|
|
19
|
-
|
|
20
|
-
if (example.want.typeOfResult) {
|
|
21
|
-
expect(JSON.stringify(result.tree)).toStrictEqual(JSON.stringify(example.want.result));
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
longTestTimeout
|
|
25
|
-
);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import Dismantle from './index.js';
|
|
4
|
-
import { longTestTimeout } from '../../constants/common.js';
|
|
5
|
-
|
|
6
|
-
describe('Dismantle chain', () => {
|
|
7
|
-
it(
|
|
8
|
-
'2022 Aprilia Tuono 660',
|
|
9
|
-
async () => {
|
|
10
|
-
const dismantleBike = new Dismantle('2022 Aprilia Tuono 660', {
|
|
11
|
-
enhanceFixes: `
|
|
12
|
-
- IMPORTANT If the component is "Electronics", output empty results.
|
|
13
|
-
- If the component is "Dashboard", output empty results.
|
|
14
|
-
`,
|
|
15
|
-
});
|
|
16
|
-
await dismantleBike.makeSubtree({ depth: 1 });
|
|
17
|
-
await dismantleBike.attachSubtree({
|
|
18
|
-
depth: 1,
|
|
19
|
-
find: (node) => node.name === 'Fuel Injector',
|
|
20
|
-
});
|
|
21
|
-
await dismantleBike.attachSubtree({
|
|
22
|
-
depth: 1,
|
|
23
|
-
find: (node) => node.name === 'Exhaust System',
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
expect(true).toStrictEqual(true);
|
|
27
|
-
},
|
|
28
|
-
longTestTimeout
|
|
29
|
-
);
|
|
30
|
-
});
|
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
import { v4 as uuid } from 'uuid';
|
|
2
|
-
|
|
3
|
-
import chatGPT from '../../lib/chatgpt/index.js';
|
|
4
|
-
import { outputSuccinctNames, constants as promptConstants } from '../../prompts/index.js';
|
|
5
|
-
import modelService from '../../services/llm-model/index.js';
|
|
6
|
-
import toObject from '../../verblets/to-object/index.js';
|
|
7
|
-
|
|
8
|
-
const { onlyJSONStringArray } = promptConstants;
|
|
9
|
-
|
|
10
|
-
const subComponentsPrompt = (component, thing, fixes = '') => {
|
|
11
|
-
let focus = '';
|
|
12
|
-
if (component !== thing) {
|
|
13
|
-
focus = `"${component}" within "${thing}"`;
|
|
14
|
-
} else {
|
|
15
|
-
focus = thing;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return `
|
|
19
|
-
${onlyJSONStringArray}
|
|
20
|
-
|
|
21
|
-
Exhaustively enumerate all physical and logical subcomponents of ${focus}, including containers or abstract components.
|
|
22
|
-
|
|
23
|
-
Apply the specifics listed here when dealing with component or entity:
|
|
24
|
-
- ${outputSuccinctNames()}
|
|
25
|
-
- If some components are subcomponents of others in the list, don't include them.
|
|
26
|
-
- The output must not include "${thing}" or "${component}" in the list.
|
|
27
|
-
- Only subcomponents, no accessories.
|
|
28
|
-
${fixes}
|
|
29
|
-
|
|
30
|
-
${onlyJSONStringArray}
|
|
31
|
-
`;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const componentOptionsPrompt = (component, thing, fixes = '') => {
|
|
35
|
-
let focus = '';
|
|
36
|
-
if (component !== thing) {
|
|
37
|
-
focus = `Considering "${component}" as a separate component within "${thing}" entity`;
|
|
38
|
-
} else {
|
|
39
|
-
focus = `Considering "${component}"`;
|
|
40
|
-
}
|
|
41
|
-
return `
|
|
42
|
-
${onlyJSONStringArray}
|
|
43
|
-
|
|
44
|
-
${focus}, list specific variants for this component. Only provide known variants, don't speculate. Output an empty list if you must.
|
|
45
|
-
|
|
46
|
-
Apply the specifics listed here when dealing with component or entity:
|
|
47
|
-
- ${outputSuccinctNames()}
|
|
48
|
-
- Do not list subcomponents, that's not what this is about.
|
|
49
|
-
${fixes}
|
|
50
|
-
|
|
51
|
-
${onlyJSONStringArray}
|
|
52
|
-
`;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const defaultMatch = () => false;
|
|
56
|
-
|
|
57
|
-
const deepClone = (obj) => JSON.parse(JSON.stringify(obj));
|
|
58
|
-
|
|
59
|
-
const search = (node, { match = defaultMatch, matches = [] } = {}) => {
|
|
60
|
-
if (match(node)) {
|
|
61
|
-
matches.push(node);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (!node.children) {
|
|
65
|
-
return matches.length > 0 ? matches : undefined;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
for (const child of node.children) {
|
|
69
|
-
search(child, { match, matches });
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return matches.length > 0 ? matches : undefined;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const defaultDecompose = async ({
|
|
76
|
-
name,
|
|
77
|
-
focus,
|
|
78
|
-
rootName,
|
|
79
|
-
fixes,
|
|
80
|
-
model = modelService.getBestPublicModel(),
|
|
81
|
-
} = {}) => {
|
|
82
|
-
const focusFormatted = focus ? `: ${focus}` : '';
|
|
83
|
-
|
|
84
|
-
const promptCreated = subComponentsPrompt(`${name}${focusFormatted}`, rootName, fixes);
|
|
85
|
-
const budget = model.budgetTokens(promptCreated);
|
|
86
|
-
return toObject(
|
|
87
|
-
await chatGPT(promptCreated, {
|
|
88
|
-
modelOptions: {
|
|
89
|
-
maxTokens: budget.completion,
|
|
90
|
-
frequencyPenalty: 0.7,
|
|
91
|
-
temperature: 0.7,
|
|
92
|
-
},
|
|
93
|
-
})
|
|
94
|
-
);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const defaultEnhance = async ({
|
|
98
|
-
name,
|
|
99
|
-
rootName,
|
|
100
|
-
fixes,
|
|
101
|
-
model = modelService.getBestPublicModel(),
|
|
102
|
-
} = {}) => {
|
|
103
|
-
const promptCreated = componentOptionsPrompt(name, rootName, fixes);
|
|
104
|
-
const budget = model.budgetTokens(promptCreated);
|
|
105
|
-
const options = toObject(
|
|
106
|
-
await chatGPT(promptCreated, {
|
|
107
|
-
maxTokens: budget.completion,
|
|
108
|
-
frequencyPenalty: 0.5,
|
|
109
|
-
temperature: 0.3,
|
|
110
|
-
})
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
return {
|
|
114
|
-
name,
|
|
115
|
-
options,
|
|
116
|
-
topOptionName: options?.[0],
|
|
117
|
-
};
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const makeNode = async ({
|
|
121
|
-
node = {},
|
|
122
|
-
name: nameInitial,
|
|
123
|
-
rootName,
|
|
124
|
-
decompose = defaultDecompose,
|
|
125
|
-
enhance = defaultEnhance,
|
|
126
|
-
makeId = uuid,
|
|
127
|
-
enhanceFixes,
|
|
128
|
-
decomposeFixes,
|
|
129
|
-
} = {}) => {
|
|
130
|
-
const name = nameInitial ?? rootName;
|
|
131
|
-
|
|
132
|
-
let nodeNew = node;
|
|
133
|
-
|
|
134
|
-
if (!node.isEnhanced) {
|
|
135
|
-
nodeNew = await enhance({
|
|
136
|
-
name,
|
|
137
|
-
rootName,
|
|
138
|
-
fixes: enhanceFixes,
|
|
139
|
-
});
|
|
140
|
-
nodeNew.isEnhanced = true;
|
|
141
|
-
|
|
142
|
-
const focus = node.options?.[0];
|
|
143
|
-
|
|
144
|
-
const childNames = await decompose({
|
|
145
|
-
name,
|
|
146
|
-
focus,
|
|
147
|
-
rootName,
|
|
148
|
-
fixes: decomposeFixes,
|
|
149
|
-
});
|
|
150
|
-
nodeNew.children = childNames.map((childName) => ({
|
|
151
|
-
id: makeId(),
|
|
152
|
-
name: childName,
|
|
153
|
-
}));
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (!node.id) {
|
|
157
|
-
nodeNew.id = makeId();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return {
|
|
161
|
-
...node,
|
|
162
|
-
...nodeNew,
|
|
163
|
-
};
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
const makeSubtree = async ({
|
|
167
|
-
name,
|
|
168
|
-
rootName,
|
|
169
|
-
tree: treeInitial,
|
|
170
|
-
depth = 0,
|
|
171
|
-
decompose,
|
|
172
|
-
enhance,
|
|
173
|
-
enhanceFixes,
|
|
174
|
-
decomposeFixes,
|
|
175
|
-
makeId,
|
|
176
|
-
} = {}) => {
|
|
177
|
-
let tree = { ...(treeInitial ?? {}) };
|
|
178
|
-
|
|
179
|
-
const nodeNew = await makeNode({
|
|
180
|
-
node: tree,
|
|
181
|
-
name: name ?? tree.name,
|
|
182
|
-
rootName,
|
|
183
|
-
enhance,
|
|
184
|
-
decompose,
|
|
185
|
-
makeId,
|
|
186
|
-
enhanceFixes,
|
|
187
|
-
decomposeFixes,
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
tree = {
|
|
191
|
-
...tree,
|
|
192
|
-
...nodeNew,
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
if (depth <= 0) {
|
|
196
|
-
return tree;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const children = [];
|
|
200
|
-
for (const child of tree.children) {
|
|
201
|
-
// eslint-disable-next-line no-await-in-loop
|
|
202
|
-
const subtree = await makeSubtree({
|
|
203
|
-
tree: child,
|
|
204
|
-
rootName,
|
|
205
|
-
decompose,
|
|
206
|
-
enhance,
|
|
207
|
-
depth: depth - 1,
|
|
208
|
-
makeId,
|
|
209
|
-
enhanceFixes,
|
|
210
|
-
decomposeFixes,
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
children.push(subtree);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
tree.children = children;
|
|
217
|
-
|
|
218
|
-
return tree;
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
export const simplifyTree = (node) => {
|
|
222
|
-
if (!node.children || node.children.length === 0) {
|
|
223
|
-
const parts = (node.children ?? []).map((child) => child.name);
|
|
224
|
-
return {
|
|
225
|
-
id: node.id,
|
|
226
|
-
name: `${node.name}${node.options?.[0] ? `: ${node.options?.[0]}` : ''}`,
|
|
227
|
-
parts: parts.length ? parts : undefined,
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const parts = node.children.map((child) => simplifyTree(child));
|
|
232
|
-
return {
|
|
233
|
-
id: node.id,
|
|
234
|
-
name: `${node.name}${node.options?.[0] ? `: ${node.options?.[0]}` : ''}`,
|
|
235
|
-
parts: parts.length ? parts : undefined,
|
|
236
|
-
};
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
class ChainTree {
|
|
240
|
-
constructor(name, { decompose, enhance, makeId, enhanceFixes, decomposeFixes } = {}) {
|
|
241
|
-
this.rootName = name;
|
|
242
|
-
this.tree = {};
|
|
243
|
-
this.decompose = decompose;
|
|
244
|
-
this.enhance = enhance;
|
|
245
|
-
this.makeId = makeId;
|
|
246
|
-
this.enhanceFixes = enhanceFixes;
|
|
247
|
-
this.decomposeFixes = decomposeFixes;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
getTree() {
|
|
251
|
-
return this.tree;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
async attachSubtree({ find, depth }) {
|
|
255
|
-
const clonedTree = deepClone(this.tree);
|
|
256
|
-
|
|
257
|
-
// Find the node to attach the subtree to in the cloned tree
|
|
258
|
-
const targetNodes = search(clonedTree, { match: find });
|
|
259
|
-
|
|
260
|
-
if (!targetNodes || targetNodes.length !== 1) {
|
|
261
|
-
return undefined;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const targetNode = targetNodes[0];
|
|
265
|
-
|
|
266
|
-
const newNode = await makeSubtree({
|
|
267
|
-
...this,
|
|
268
|
-
rootName: clonedTree.name,
|
|
269
|
-
tree: targetNode,
|
|
270
|
-
depth,
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
Object.assign(targetNode, newNode);
|
|
274
|
-
|
|
275
|
-
const nodeStripped = {
|
|
276
|
-
...newNode,
|
|
277
|
-
children: newNode.children.map((child) => ({
|
|
278
|
-
...child,
|
|
279
|
-
children: [],
|
|
280
|
-
})),
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
this.tree = clonedTree;
|
|
284
|
-
|
|
285
|
-
return nodeStripped;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
async makeSubtree(config = {}) {
|
|
289
|
-
this.tree = await makeSubtree({
|
|
290
|
-
...this,
|
|
291
|
-
rootName: this.tree.name || this.rootName,
|
|
292
|
-
...config,
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
return this.tree;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
export const dismantle = (text, options) => {
|
|
300
|
-
return new ChainTree(text, options);
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
export default ChainTree;
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { dismantle } from './index.js';
|
|
4
|
-
|
|
5
|
-
vi.mock('../../lib/chatgpt/index.js', () => ({
|
|
6
|
-
default: vi.fn().mockImplementation((text) => {
|
|
7
|
-
if (/prompt text to match/.test(text)) {
|
|
8
|
-
return 'True';
|
|
9
|
-
}
|
|
10
|
-
return 'undefined';
|
|
11
|
-
}),
|
|
12
|
-
}));
|
|
13
|
-
|
|
14
|
-
const examples = [
|
|
15
|
-
{
|
|
16
|
-
name: 'Basic usage',
|
|
17
|
-
inputs: { text: 'test' },
|
|
18
|
-
want: { result: {} },
|
|
19
|
-
},
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
describe('Dismantle chain', () => {
|
|
23
|
-
examples.forEach((example) => {
|
|
24
|
-
it(example.name, async () => {
|
|
25
|
-
const result = await dismantle(example.inputs.text);
|
|
26
|
-
|
|
27
|
-
if (example.want.typeOfResult) {
|
|
28
|
-
expect(JSON.stringify(result.tree)).toStrictEqual(JSON.stringify(example.want.result));
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
});
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
# LLM Expect Chain
|
|
2
|
-
|
|
3
|
-
Advanced intelligent assertions with debugging features, environment variable modes, and structured results. This chain provides enhanced functionality beyond the basic [expect verblet](../../verblets/expect/).
|
|
4
|
-
|
|
5
|
-
## Why Use the Chain?
|
|
6
|
-
|
|
7
|
-
While the verblet provides simple pass/fail assertions, the chain offers:
|
|
8
|
-
|
|
9
|
-
- **Advanced Debugging**: Automatic code context analysis and intelligent advice
|
|
10
|
-
- **Environment Modes**: Different behaviors for development, testing, and CI
|
|
11
|
-
- **Structured Results**: Detailed information about assertions and failures
|
|
12
|
-
- **Stack Trace Integration**: Automatic detection of calling file and line
|
|
13
|
-
|
|
14
|
-
## Environment Variable Modes
|
|
15
|
-
|
|
16
|
-
Control behavior with the `LLM_EXPECT_MODE` environment variable:
|
|
17
|
-
|
|
18
|
-
### `none` (default)
|
|
19
|
-
Silent mode - returns structured results without throwing or logging
|
|
20
|
-
```bash
|
|
21
|
-
export LLM_EXPECT_MODE=none
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### `info`
|
|
25
|
-
Development mode - logs failures with context and advice to console
|
|
26
|
-
```bash
|
|
27
|
-
export LLM_EXPECT_MODE=info
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### `error`
|
|
31
|
-
CI/Testing mode - throws detailed errors on assertion failures
|
|
32
|
-
```bash
|
|
33
|
-
export LLM_EXPECT_MODE=error
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## API Reference
|
|
37
|
-
|
|
38
|
-
### Enhanced API: `expect(actual, expected?, constraint?)`
|
|
39
|
-
|
|
40
|
-
Returns a tuple `[passed, details]` with structured results:
|
|
41
|
-
|
|
42
|
-
```javascript
|
|
43
|
-
import { expect } from './index.js';
|
|
44
|
-
|
|
45
|
-
const [passed, details] = await expect(
|
|
46
|
-
actualValue,
|
|
47
|
-
"Does this meet our quality standards?"
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
console.log(details);
|
|
51
|
-
/* Returns:
|
|
52
|
-
{
|
|
53
|
-
passed: false,
|
|
54
|
-
advice: "ISSUE: Content lacks specific examples...",
|
|
55
|
-
file: "/path/to/test.js",
|
|
56
|
-
line: 42
|
|
57
|
-
}
|
|
58
|
-
*/
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### Simple API: `expect(actual, expected?, constraint?)`
|
|
62
|
-
|
|
63
|
-
Backward compatible with the verblet - returns boolean:
|
|
64
|
-
|
|
65
|
-
```javascript
|
|
66
|
-
import expect from './index.js';
|
|
67
|
-
|
|
68
|
-
const result = await expect("hello", "hello");
|
|
69
|
-
// Returns: true
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Real-World Use Cases
|
|
73
|
-
|
|
74
|
-
### Content Quality Assurance with Debugging
|
|
75
|
-
|
|
76
|
-
```javascript
|
|
77
|
-
import { expect } from './index.js';
|
|
78
|
-
|
|
79
|
-
// Set development mode for detailed feedback
|
|
80
|
-
process.env.LLM_EXPECT_MODE = 'info';
|
|
81
|
-
|
|
82
|
-
const [passed, details] = await expect(
|
|
83
|
-
generatedCopy,
|
|
84
|
-
"Is this marketing copy professional, engaging, and free of grammatical errors?"
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
if (!passed) {
|
|
88
|
-
console.log(`Failed at ${details.file}:${details.line}`);
|
|
89
|
-
console.log(details.advice);
|
|
90
|
-
// ISSUE: Copy contains informal language and lacks call-to-action
|
|
91
|
-
// FIX: Replace casual phrases with professional alternatives and add clear CTA
|
|
92
|
-
// CONTEXT: Marketing copy should maintain professional tone while being engaging
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Advanced Features
|
|
97
|
-
|
|
98
|
-
### Automatic Code Context Analysis
|
|
99
|
-
|
|
100
|
-
The chain automatically:
|
|
101
|
-
- Detects the calling file and line number
|
|
102
|
-
- Reads 400 lines before and 100 lines after the assertion
|
|
103
|
-
- Provides this context to the LLM for better debugging advice
|
|
104
|
-
|
|
105
|
-
### Intelligent Advice Generation
|
|
106
|
-
|
|
107
|
-
Failed assertions generate structured advice:
|
|
108
|
-
- **ISSUE**: Brief description of why the assertion failed
|
|
109
|
-
- **FIX**: Specific actionable steps to resolve the issue
|
|
110
|
-
- **CONTEXT**: Additional context about the problem and root causes
|
|
111
|
-
|
|
112
|
-
### Environment-Aware Behavior
|
|
113
|
-
|
|
114
|
-
Different modes for different environments:
|
|
115
|
-
- **Development**: Rich console output with advice
|
|
116
|
-
- **Testing**: Detailed error throwing for CI/CD
|
|
117
|
-
- **Production**: Silent operation with structured results
|
|
118
|
-
|
|
119
|
-
## Best Practices
|
|
120
|
-
|
|
121
|
-
### **Write Specific Constraints**
|
|
122
|
-
```javascript
|
|
123
|
-
// ❌ Vague
|
|
124
|
-
await expect(text, "Is this good?");
|
|
125
|
-
|
|
126
|
-
// ✅ Specific
|
|
127
|
-
await expect(text, "Is this text grammatically correct, under 100 words, and written in a professional tone?");
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### **Use Structured Results**
|
|
131
|
-
```javascript
|
|
132
|
-
const [passed, details] = await expect(content, constraint);
|
|
133
|
-
|
|
134
|
-
// Access rich debugging information
|
|
135
|
-
console.log('File:', details.file);
|
|
136
|
-
console.log('Line:', details.line);
|
|
137
|
-
console.log('Advice:', details.advice);
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### **Combine with Traditional Tests**
|
|
141
|
-
```javascript
|
|
142
|
-
// Traditional assertion for structure
|
|
143
|
-
expect(response).toHaveProperty('status');
|
|
144
|
-
expect(response.status).toBe(200);
|
|
145
|
-
|
|
146
|
-
// LLM assertion for content quality
|
|
147
|
-
const [passed] = await expect(
|
|
148
|
-
response.message,
|
|
149
|
-
"Is this error message helpful and user-friendly?"
|
|
150
|
-
);
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Environment Modes
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
# Silent operation (default)
|
|
157
|
-
export LLM_EXPECT_MODE=none
|
|
158
|
-
|
|
159
|
-
# Log debugging advice on failures
|
|
160
|
-
export LLM_EXPECT_MODE=info
|
|
161
|
-
|
|
162
|
-
# Throw with detailed debugging advice
|
|
163
|
-
export LLM_EXPECT_MODE=error
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
## Best Practices
|
|
167
|
-
|
|
168
|
-
- **Be specific**: Use clear, detailed constraints
|
|
169
|
-
- **Test qualitatively**: Verify qualitative details with a clear yes/no answer
|
|
170
|
-
- **Use robust constraints**: Write criteria to pass under a wide range of input hallucinations. Assert cases that classical software can't. Tune the level of rigorousness to the model performing the eval.
|
|
171
|
-
- **Performance**: Remember this makes an LLM call - use judiciously
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, beforeAll, afterAll } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { expect as aiExpect } from './index.js';
|
|
4
|
-
import { longTestTimeout } from '../../constants/common.js';
|
|
5
|
-
|
|
6
|
-
const examples = [
|
|
7
|
-
{
|
|
8
|
-
inputs: {
|
|
9
|
-
actual: 'Hello world!',
|
|
10
|
-
constraint: 'Is this a greeting?',
|
|
11
|
-
},
|
|
12
|
-
want: { result: true },
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
inputs: {
|
|
16
|
-
actual: 'Goodbye cruel world',
|
|
17
|
-
constraint: 'Is this a greeting?',
|
|
18
|
-
},
|
|
19
|
-
want: { result: false },
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
inputs: {
|
|
23
|
-
actual: 'hello',
|
|
24
|
-
expected: 'hello',
|
|
25
|
-
},
|
|
26
|
-
want: { result: true },
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
inputs: {
|
|
30
|
-
actual: 'hello',
|
|
31
|
-
expected: 'goodbye',
|
|
32
|
-
},
|
|
33
|
-
want: { result: false },
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
inputs: {
|
|
37
|
-
actual: 'This is a well-written, professional email with proper grammar and clear intent.',
|
|
38
|
-
constraint: 'Is this text professional and grammatically correct?',
|
|
39
|
-
},
|
|
40
|
-
want: { result: true },
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
inputs: {
|
|
44
|
-
actual: { name: 'John Doe', age: 30, city: 'New York' },
|
|
45
|
-
constraint: 'Does this person data look realistic?',
|
|
46
|
-
},
|
|
47
|
-
want: { result: true },
|
|
48
|
-
},
|
|
49
|
-
];
|
|
50
|
-
|
|
51
|
-
describe('LLM Expect Chain', () => {
|
|
52
|
-
// Set environment mode to 'none' for all tests to avoid throwing
|
|
53
|
-
const originalMode = process.env.LLM_EXPECT_MODE;
|
|
54
|
-
|
|
55
|
-
beforeAll(() => {
|
|
56
|
-
process.env.LLM_EXPECT_MODE = 'none';
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
afterAll(() => {
|
|
60
|
-
if (originalMode !== undefined) {
|
|
61
|
-
process.env.LLM_EXPECT_MODE = originalMode;
|
|
62
|
-
} else {
|
|
63
|
-
delete process.env.LLM_EXPECT_MODE;
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
examples.forEach((example) => {
|
|
68
|
-
const description = example.inputs.constraint
|
|
69
|
-
? `${JSON.stringify(example.inputs.actual).slice(0, 30)}... - ${example.inputs.constraint}`
|
|
70
|
-
: `${JSON.stringify(example.inputs.actual)} === ${JSON.stringify(example.inputs.expected)}`;
|
|
71
|
-
|
|
72
|
-
it(
|
|
73
|
-
description,
|
|
74
|
-
async () => {
|
|
75
|
-
const [result, details] = await aiExpect(
|
|
76
|
-
example.inputs.actual,
|
|
77
|
-
example.inputs.expected,
|
|
78
|
-
example.inputs.constraint
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
expect(result).toBe(example.want.result);
|
|
82
|
-
expect(details).toHaveProperty('passed', example.want.result);
|
|
83
|
-
expect(details).toHaveProperty('file');
|
|
84
|
-
expect(details).toHaveProperty('line');
|
|
85
|
-
expect(typeof details.line).toBe('number');
|
|
86
|
-
},
|
|
87
|
-
longTestTimeout
|
|
88
|
-
);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it(
|
|
92
|
-
'should provide detailed debugging information on failure',
|
|
93
|
-
async () => {
|
|
94
|
-
const [result, details] = await aiExpect(
|
|
95
|
-
'This is clearly wrong content',
|
|
96
|
-
undefined,
|
|
97
|
-
'Is this a professional business email?'
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
expect(result).toBe(false);
|
|
101
|
-
expect(details.passed).toBe(false);
|
|
102
|
-
expect(details.file).toBeDefined();
|
|
103
|
-
expect(details.line).toBeGreaterThan(0);
|
|
104
|
-
|
|
105
|
-
// In none mode, advice should be null for failures
|
|
106
|
-
expect(details.advice).toBeNull();
|
|
107
|
-
},
|
|
108
|
-
longTestTimeout
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
it(
|
|
112
|
-
'should handle complex business logic validation',
|
|
113
|
-
async () => {
|
|
114
|
-
const businessRecommendation =
|
|
115
|
-
'Increase marketing budget by 20% for Q4 to boost holiday sales and target demographics aged 25-45 through social media campaigns';
|
|
116
|
-
|
|
117
|
-
const [result, details] = await aiExpect(
|
|
118
|
-
businessRecommendation,
|
|
119
|
-
undefined,
|
|
120
|
-
'Is this recommendation specific, actionable, and includes measurable targets?'
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
expect(result).toBe(true);
|
|
124
|
-
expect(details.passed).toBe(true);
|
|
125
|
-
expect(details.file).toBeDefined();
|
|
126
|
-
},
|
|
127
|
-
longTestTimeout
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
it(
|
|
131
|
-
'should validate creative content quality',
|
|
132
|
-
async () => {
|
|
133
|
-
const storyOpening =
|
|
134
|
-
'Once upon a time, in a land far away, there lived a brave knight who embarked on a quest to save the kingdom from an ancient curse that had plagued the realm for centuries.';
|
|
135
|
-
|
|
136
|
-
const [result] = await aiExpect(
|
|
137
|
-
storyOpening,
|
|
138
|
-
undefined,
|
|
139
|
-
'Is this story opening engaging, sets up clear conflict, and follows good narrative structure?'
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
expect(result).toBe(true);
|
|
143
|
-
},
|
|
144
|
-
longTestTimeout
|
|
145
|
-
);
|
|
146
|
-
});
|