@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,171 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import chatGPT from '../../lib/chatgpt/index.js';
|
|
5
|
-
import { onlyJSON, strictFormat } from '../../prompts/constants.js';
|
|
6
|
-
|
|
7
|
-
// Get the directory of this module
|
|
8
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname = path.dirname(__filename);
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Load the JSON schema for central tendency results
|
|
13
|
-
* @returns {Promise<Object>} JSON schema for validation
|
|
14
|
-
*/
|
|
15
|
-
async function getCentralTendencySchema() {
|
|
16
|
-
const schemaPath = path.join(__dirname, 'central-tendency-result.json');
|
|
17
|
-
return JSON.parse(await fs.readFile(schemaPath, 'utf8'));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Core prompt template for central tendency evaluation using cognitive science principles.
|
|
22
|
-
* Suitable for both individual and bulk processing.
|
|
23
|
-
*/
|
|
24
|
-
export const CENTRAL_TENDENCY_PROMPT = `Use cognitive science principles of prototype theory and family resemblance:
|
|
25
|
-
|
|
26
|
-
{context}
|
|
27
|
-
{coreFeatures}
|
|
28
|
-
|
|
29
|
-
COGNITIVE PRINCIPLES:
|
|
30
|
-
1. Prototype Theory: Categories have graded structure with central and peripheral members
|
|
31
|
-
2. Family Resemblance: Members share overlapping features without identical characteristics
|
|
32
|
-
3. Feature Analysis: Consider both core (definitional) and characteristic (typical) features
|
|
33
|
-
4. Functional Centrality: Assess how well the item serves the category's purpose
|
|
34
|
-
|
|
35
|
-
ASSESSMENT CRITERIA:
|
|
36
|
-
- Feature overlap with seed items
|
|
37
|
-
- Possession of core definitional features
|
|
38
|
-
- Functional alignment with category purpose
|
|
39
|
-
- Typicality relative to category prototype
|
|
40
|
-
|
|
41
|
-
CENTRALITY SCORING GUIDE (use precise decimals):
|
|
42
|
-
• 0.0-0.1: Not a category member (completely unrelated)
|
|
43
|
-
• 0.1-0.2: Extremely peripheral (minimal connection, metaphorical only)
|
|
44
|
-
• 0.2-0.3: Peripheral member (weak connection, few shared features)
|
|
45
|
-
• 0.3-0.4: Marginal member (some shared features but atypical)
|
|
46
|
-
• 0.4-0.5: Borderline member (mixed typical/atypical features)
|
|
47
|
-
• 0.5-0.6: Atypical but clear member (definitionally belongs but unusual)
|
|
48
|
-
• 0.6-0.7: Moderately typical (good example with some variations)
|
|
49
|
-
• 0.7-0.8: Highly typical (strong example, most expected features)
|
|
50
|
-
• 0.8-0.9: Very prototypical (excellent example, nearly all expected features)
|
|
51
|
-
• 0.9-1.0: Maximally prototypical (perfect/ideal example of the category)
|
|
52
|
-
|
|
53
|
-
{outputRequirements}`;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Build a prompt for evaluating centrality
|
|
57
|
-
* @param {string} item - The item to evaluate (for single) or placeholder for bulk
|
|
58
|
-
* @param {string[]} seedItems - Array of seed items for comparison
|
|
59
|
-
* @param {Object} config - Configuration options
|
|
60
|
-
* @returns {string} Complete prompt
|
|
61
|
-
*/
|
|
62
|
-
export function buildCentralTendencyPrompt(
|
|
63
|
-
item,
|
|
64
|
-
seedItems,
|
|
65
|
-
{ context = '', coreFeatures = [], outputRequirements = null } = {}
|
|
66
|
-
) {
|
|
67
|
-
const contextLine = context ? `Context: ${context}` : '';
|
|
68
|
-
const coreFeaturesLine =
|
|
69
|
-
coreFeatures.length > 0 ? `Core Features: ${coreFeatures.join(', ')}` : '';
|
|
70
|
-
|
|
71
|
-
// Default structured output requirements for individual verblet use
|
|
72
|
-
const defaultOutputRequirements = `OUTPUT REQUIREMENTS:
|
|
73
|
-
${onlyJSON}
|
|
74
|
-
${strictFormat}
|
|
75
|
-
|
|
76
|
-
Required JSON structure:
|
|
77
|
-
{
|
|
78
|
-
"score": <number between 0.0 and 1.0>,
|
|
79
|
-
"reason": "<brief explanation of the centrality assessment>",
|
|
80
|
-
"confidence": <number between 0.0 and 1.0 indicating confidence in the assessment>
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
The "reason" should briefly explain why the item received its centrality score based on feature overlap, typicality, and functional alignment with the seed items.
|
|
84
|
-
The "confidence" should reflect how certain you are about the assessment (higher for clear cases, lower for borderline cases).`;
|
|
85
|
-
|
|
86
|
-
const outputRequirementsLine = outputRequirements || defaultOutputRequirements;
|
|
87
|
-
|
|
88
|
-
const prompt = CENTRAL_TENDENCY_PROMPT.replace('{context}', contextLine)
|
|
89
|
-
.replace('{coreFeatures}', coreFeaturesLine)
|
|
90
|
-
.replace('{outputRequirements}', outputRequirementsLine);
|
|
91
|
-
|
|
92
|
-
return `Evaluate how central "${item}" is among these category members: ${seedItems.join(', ')}
|
|
93
|
-
|
|
94
|
-
${prompt}`;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Create model options for structured outputs
|
|
99
|
-
* @param {string|Object} llm - LLM model name or configuration object
|
|
100
|
-
* @param {string} schemaName - Name for the JSON schema
|
|
101
|
-
* @param {Object} [customSchema] - Custom schema to use instead of default
|
|
102
|
-
* @returns {Promise<Object>} Model options for chatGPT
|
|
103
|
-
*/
|
|
104
|
-
async function createModelOptions(
|
|
105
|
-
llm = 'fastGoodCheap',
|
|
106
|
-
schemaName = 'central_tendency_result',
|
|
107
|
-
customSchema = null
|
|
108
|
-
) {
|
|
109
|
-
const schema = customSchema || (await getCentralTendencySchema());
|
|
110
|
-
|
|
111
|
-
const responseFormat = {
|
|
112
|
-
type: 'json_schema',
|
|
113
|
-
json_schema: {
|
|
114
|
-
name: schemaName,
|
|
115
|
-
schema,
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
if (typeof llm === 'string') {
|
|
120
|
-
return {
|
|
121
|
-
modelName: llm,
|
|
122
|
-
response_format: responseFormat,
|
|
123
|
-
};
|
|
124
|
-
} else {
|
|
125
|
-
return {
|
|
126
|
-
...llm,
|
|
127
|
-
response_format: responseFormat,
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Parse response from chatGPT
|
|
134
|
-
* @param {string|Object} response - Response from chatGPT
|
|
135
|
-
* @returns {Object} Parsed response object
|
|
136
|
-
*/
|
|
137
|
-
function parseResponse(response) {
|
|
138
|
-
return typeof response === 'string' ? JSON.parse(response) : response;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Evaluate how central an item is among category members using cognitive science principles.
|
|
143
|
-
*
|
|
144
|
-
* Based on prototype theory and family resemblance, this function assesses graded typicality
|
|
145
|
-
* by analyzing feature overlap, core characteristics, and functional alignment with seed items.
|
|
146
|
-
*
|
|
147
|
-
* @param {string} item - The item to evaluate for centrality
|
|
148
|
-
* @param {string[]} seedItems - Array of known category members for comparison
|
|
149
|
-
* @param {Object} [config={}] - Configuration options
|
|
150
|
-
* @param {string} [config.context=''] - Context description for evaluation
|
|
151
|
-
* @param {string[]} [config.coreFeatures=[]] - Known core/definitional features of the category
|
|
152
|
-
* @param {string} [config.llm='fastGoodCheap'] - LLM model to use
|
|
153
|
-
* @returns {Promise<{score: number, reason: string, confidence: number}>}
|
|
154
|
-
*/
|
|
155
|
-
export default async function centralTendency(item, seedItems, config = {}) {
|
|
156
|
-
if (!item || typeof item !== 'string') {
|
|
157
|
-
throw new Error('Item must be a non-empty string');
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (!Array.isArray(seedItems) || seedItems.length === 0) {
|
|
161
|
-
throw new Error('seedItems must be a non-empty array');
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const { context = '', coreFeatures = [], llm = 'fastGoodCheap' } = config;
|
|
165
|
-
|
|
166
|
-
const prompt = buildCentralTendencyPrompt(item, seedItems, { context, coreFeatures });
|
|
167
|
-
const modelOptions = await createModelOptions(llm, 'central_tendency_result');
|
|
168
|
-
|
|
169
|
-
const response = await chatGPT(prompt, { modelOptions });
|
|
170
|
-
return parseResponse(response);
|
|
171
|
-
}
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import centralTendency from './index.js';
|
|
3
|
-
|
|
4
|
-
// Mock the LLM service
|
|
5
|
-
vi.mock('../../lib/chatgpt/index.js', () => ({
|
|
6
|
-
default: vi.fn(),
|
|
7
|
-
}));
|
|
8
|
-
|
|
9
|
-
import chatGPT from '../../lib/chatgpt/index.js';
|
|
10
|
-
|
|
11
|
-
describe('centralTendency', () => {
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
vi.clearAllMocks();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('evaluates centrality with config object', async () => {
|
|
17
|
-
const mockResponse = {
|
|
18
|
-
score: 0.85,
|
|
19
|
-
reason: 'High feature overlap with seed items',
|
|
20
|
-
confidence: 0.9,
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
chatGPT.mockResolvedValue(mockResponse);
|
|
24
|
-
|
|
25
|
-
const result = await centralTendency('robin', ['sparrow', 'bluejay', 'cardinal'], {
|
|
26
|
-
context: 'Evaluate based on typical bird characteristics',
|
|
27
|
-
coreFeatures: ['feathers', 'beak', 'lays eggs'],
|
|
28
|
-
llm: 'fastGoodCheap',
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
expect(result).toEqual({
|
|
32
|
-
score: 0.85,
|
|
33
|
-
reason: 'High feature overlap with seed items',
|
|
34
|
-
confidence: 0.9,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
expect(chatGPT).toHaveBeenCalledWith(
|
|
38
|
-
expect.stringContaining('Evaluate how central "robin" is among these category members'),
|
|
39
|
-
{ modelOptions: expect.objectContaining({ modelName: 'fastGoodCheap' }) }
|
|
40
|
-
);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('uses default LLM model when not specified', async () => {
|
|
44
|
-
const mockResponse = {
|
|
45
|
-
score: 0.75,
|
|
46
|
-
reason: 'Good match',
|
|
47
|
-
confidence: 0.8,
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
chatGPT.mockResolvedValue(mockResponse);
|
|
51
|
-
|
|
52
|
-
const result = await centralTendency('penguin', ['robin', 'sparrow'], {
|
|
53
|
-
context: 'Bird evaluation',
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
expect(result.score).toBe(0.75);
|
|
57
|
-
expect(chatGPT).toHaveBeenCalledWith(expect.any(String), {
|
|
58
|
-
modelOptions: expect.objectContaining({ modelName: 'fastGoodCheap' }),
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('throws error for invalid item', async () => {
|
|
63
|
-
await expect(centralTendency('', ['seed1', 'seed2'])).rejects.toThrow(
|
|
64
|
-
'Item must be a non-empty string'
|
|
65
|
-
);
|
|
66
|
-
await expect(centralTendency(null, ['seed1', 'seed2'])).rejects.toThrow(
|
|
67
|
-
'Item must be a non-empty string'
|
|
68
|
-
);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('throws error for invalid seedItems', async () => {
|
|
72
|
-
await expect(centralTendency('item', [])).rejects.toThrow(
|
|
73
|
-
'seedItems must be a non-empty array'
|
|
74
|
-
);
|
|
75
|
-
await expect(centralTendency('item', null)).rejects.toThrow(
|
|
76
|
-
'seedItems must be a non-empty array'
|
|
77
|
-
);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('handles JSON string response', async () => {
|
|
81
|
-
const mockResponse = JSON.stringify({
|
|
82
|
-
score: 0.6,
|
|
83
|
-
reason: 'Moderate centrality',
|
|
84
|
-
confidence: 0.7,
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
chatGPT.mockResolvedValue(mockResponse);
|
|
88
|
-
|
|
89
|
-
const result = await centralTendency('item', ['seed1', 'seed2']);
|
|
90
|
-
|
|
91
|
-
expect(result).toEqual({
|
|
92
|
-
score: 0.6,
|
|
93
|
-
reason: 'Moderate centrality',
|
|
94
|
-
confidence: 0.7,
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('handles object response directly', async () => {
|
|
99
|
-
const mockResponse = {
|
|
100
|
-
score: 0.8,
|
|
101
|
-
reason: 'High centrality',
|
|
102
|
-
confidence: 0.9,
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
chatGPT.mockResolvedValue(mockResponse);
|
|
106
|
-
|
|
107
|
-
const result = await centralTendency('item', ['seed1', 'seed2']);
|
|
108
|
-
|
|
109
|
-
expect(result).toEqual(mockResponse);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('builds correct prompt with context and core features', async () => {
|
|
113
|
-
const mockResponse = {
|
|
114
|
-
score: 0.7,
|
|
115
|
-
reason: 'Test result',
|
|
116
|
-
confidence: 0.8,
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
chatGPT.mockResolvedValue(mockResponse);
|
|
120
|
-
|
|
121
|
-
await centralTendency('robin', ['sparrow', 'bluejay'], {
|
|
122
|
-
context: 'Bird evaluation context',
|
|
123
|
-
coreFeatures: ['feathers', 'beak', 'flight'],
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
const calledPrompt = chatGPT.mock.calls[0][0];
|
|
127
|
-
expect(calledPrompt).toContain('Context: Bird evaluation context');
|
|
128
|
-
expect(calledPrompt).toContain('Core Features: feathers, beak, flight');
|
|
129
|
-
expect(calledPrompt).toContain('sparrow, bluejay');
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('uses JSON schema validation', async () => {
|
|
133
|
-
const mockResponse = {
|
|
134
|
-
score: 0.6,
|
|
135
|
-
reason: 'Assessment with schema',
|
|
136
|
-
confidence: 0.8,
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
chatGPT.mockResolvedValue(mockResponse);
|
|
140
|
-
|
|
141
|
-
await centralTendency('item', ['seed1', 'seed2'], {});
|
|
142
|
-
|
|
143
|
-
const modelOptions = chatGPT.mock.calls[0][1].modelOptions;
|
|
144
|
-
expect(modelOptions).toHaveProperty('response_format');
|
|
145
|
-
expect(modelOptions.response_format.type).toBe('json_schema');
|
|
146
|
-
expect(modelOptions.response_format.json_schema.name).toBe('central_tendency_result');
|
|
147
|
-
});
|
|
148
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import enumValue from './index.js';
|
|
4
|
-
import { longTestTimeout } from '../../constants/common.js';
|
|
5
|
-
|
|
6
|
-
const examples = [
|
|
7
|
-
{
|
|
8
|
-
inputs: {
|
|
9
|
-
text: 'What is the top color on a traffic light',
|
|
10
|
-
enum: { green: 1, yellow: 1, red: 1, purple: 1 },
|
|
11
|
-
},
|
|
12
|
-
want: { result: 'red' },
|
|
13
|
-
},
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
describe('Enum verblet', () => {
|
|
17
|
-
examples.forEach((example) => {
|
|
18
|
-
it(
|
|
19
|
-
example.inputs.text,
|
|
20
|
-
async () => {
|
|
21
|
-
const result = await enumValue(example.inputs.text, example.inputs.enum);
|
|
22
|
-
|
|
23
|
-
if (example.want.result) {
|
|
24
|
-
expect(result).toStrictEqual(example.want.result);
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
longTestTimeout
|
|
28
|
-
);
|
|
29
|
-
});
|
|
30
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import chatGPT from '../../lib/chatgpt/index.js';
|
|
2
|
-
import stripResponse from '../../lib/strip-response/index.js';
|
|
3
|
-
import toEnum from '../../lib/to-enum/index.js';
|
|
4
|
-
import { asEnum, constants } from '../../prompts/index.js';
|
|
5
|
-
|
|
6
|
-
const { asUndefinedByDefault, contentIsQuestion, explainAndSeparate } = constants;
|
|
7
|
-
|
|
8
|
-
export default async (text, enumVal, config = {}) => {
|
|
9
|
-
const { llm, ...options } = config;
|
|
10
|
-
const enumText = `${contentIsQuestion} ${text}\n\n${explainAndSeparate}
|
|
11
|
-
|
|
12
|
-
${asEnum(enumVal)} ${asUndefinedByDefault}`;
|
|
13
|
-
|
|
14
|
-
return toEnum(
|
|
15
|
-
stripResponse(await chatGPT(enumText, { modelOptions: { ...llm }, ...options })),
|
|
16
|
-
enumVal
|
|
17
|
-
);
|
|
18
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import enumValue from './index.js';
|
|
4
|
-
|
|
5
|
-
vi.mock('../../lib/chatgpt/index.js', () => ({
|
|
6
|
-
default: vi.fn().mockImplementation((text) => {
|
|
7
|
-
if (/traffic light/.test(text)) {
|
|
8
|
-
return 'red';
|
|
9
|
-
}
|
|
10
|
-
return 'undefined';
|
|
11
|
-
}),
|
|
12
|
-
}));
|
|
13
|
-
|
|
14
|
-
const examples = [
|
|
15
|
-
{
|
|
16
|
-
name: 'Basic usage',
|
|
17
|
-
inputs: {
|
|
18
|
-
text: 'What is the top color on a traffic light',
|
|
19
|
-
enum: { green: 1, yellow: 1, red: 1, purple: 1 },
|
|
20
|
-
},
|
|
21
|
-
want: { result: 'red' },
|
|
22
|
-
},
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
describe('Enum verblet', () => {
|
|
26
|
-
examples.forEach((example) => {
|
|
27
|
-
it(example.name, async () => {
|
|
28
|
-
const result = await enumValue(example.inputs.text, example.inputs.enum);
|
|
29
|
-
|
|
30
|
-
if (example.want.result) {
|
|
31
|
-
expect(result).toStrictEqual(example.want.result);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
});
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# LLM Expect
|
|
2
|
-
|
|
3
|
-
Make intelligent assertions using natural language. A single LLM call that validates content based on meaning, intent, and context.
|
|
4
|
-
|
|
5
|
-
## Quick Start
|
|
6
|
-
|
|
7
|
-
```javascript
|
|
8
|
-
import expect, { llmAssert } from './index.js';
|
|
9
|
-
|
|
10
|
-
// Simple equality check (throws on failure)
|
|
11
|
-
await expect("hello").toEqual("hello");
|
|
12
|
-
// ✅ Passes silently
|
|
13
|
-
|
|
14
|
-
// Constraint-based validation
|
|
15
|
-
await expect("Hello world!").toSatisfy("Is this a greeting?");
|
|
16
|
-
// ✅ Passes silently
|
|
17
|
-
|
|
18
|
-
// Failed assertion throws
|
|
19
|
-
try {
|
|
20
|
-
await expect("goodbye").toEqual("hello");
|
|
21
|
-
} catch (error) {
|
|
22
|
-
console.log(error.message);
|
|
23
|
-
// "LLM assertion failed: Does the actual value strictly equal the expected value?"
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Direct helper with custom options
|
|
27
|
-
const passed = await llmAssert({
|
|
28
|
-
actual: "hello",
|
|
29
|
-
equals: "hello",
|
|
30
|
-
llm: { temperature: 0 },
|
|
31
|
-
throws: false,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// Custom message when the assertion fails
|
|
35
|
-
await expect("bad").toEqual("good", {
|
|
36
|
-
message: ({ actual, equals }) => `Expected ${equals} but got ${actual}`,
|
|
37
|
-
});
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Use `throws: false` to return a boolean instead of throwing when the assertion fails.
|
|
41
|
-
|
|
42
|
-
## Enhanced Chain Implementation
|
|
43
|
-
|
|
44
|
-
For advanced debugging, detailed error analysis, and enhanced features, use the **[expect chain](../../chains/expect/)**:
|
|
45
|
-
|
|
46
|
-
### Environment Modes
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
# Silent operation (default)
|
|
50
|
-
export LLM_EXPECT_MODE=none
|
|
51
|
-
|
|
52
|
-
# Log debugging advice on failures
|
|
53
|
-
export LLM_EXPECT_MODE=info
|
|
54
|
-
|
|
55
|
-
# Throw with detailed debugging advice
|
|
56
|
-
export LLM_EXPECT_MODE=error
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Best Practices
|
|
60
|
-
|
|
61
|
-
- **Be specific**: Use clear, detailed constraints
|
|
62
|
-
- **Test qualitatively**: Verify qualitative details with a clear yes/no answer
|
|
63
|
-
- **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.
|
|
64
|
-
- **Performance**: Remember this makes an LLM call - use judiciously
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import aiExpect from './index.js';
|
|
4
|
-
import { longTestTimeout } from '../../constants/common.js';
|
|
5
|
-
|
|
6
|
-
const examples = [
|
|
7
|
-
{
|
|
8
|
-
inputs: {
|
|
9
|
-
actual: 'hello',
|
|
10
|
-
expected: 'hello',
|
|
11
|
-
},
|
|
12
|
-
want: { result: true },
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
inputs: {
|
|
16
|
-
actual: 'hello',
|
|
17
|
-
expected: 'goodbye',
|
|
18
|
-
},
|
|
19
|
-
want: { result: false },
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
inputs: {
|
|
23
|
-
actual: 'Hello world!',
|
|
24
|
-
constraint: 'Is this a greeting?',
|
|
25
|
-
},
|
|
26
|
-
want: { result: true },
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
inputs: {
|
|
30
|
-
actual: 'Goodbye cruel world',
|
|
31
|
-
constraint: 'Is this a greeting?',
|
|
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 Verblet', () => {
|
|
52
|
-
examples.forEach((example) => {
|
|
53
|
-
const description = example.inputs.constraint
|
|
54
|
-
? `${JSON.stringify(example.inputs.actual).slice(0, 30)}... - ${example.inputs.constraint}`
|
|
55
|
-
: `${JSON.stringify(example.inputs.actual)} === ${JSON.stringify(example.inputs.expected)}`;
|
|
56
|
-
|
|
57
|
-
it(
|
|
58
|
-
description,
|
|
59
|
-
async () => {
|
|
60
|
-
const result =
|
|
61
|
-
example.inputs.expected !== undefined
|
|
62
|
-
? await aiExpect(example.inputs.actual).toEqual(example.inputs.expected, {
|
|
63
|
-
throws: false,
|
|
64
|
-
})
|
|
65
|
-
: await aiExpect(example.inputs.actual).toSatisfy(example.inputs.constraint, {
|
|
66
|
-
throws: false,
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
expect(result).toBe(example.want.result);
|
|
70
|
-
},
|
|
71
|
-
longTestTimeout
|
|
72
|
-
);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it(
|
|
76
|
-
'should throw by default on failure',
|
|
77
|
-
async () => {
|
|
78
|
-
await expect(async () => {
|
|
79
|
-
await aiExpect('hello').toEqual('goodbye');
|
|
80
|
-
}).rejects.toThrow('LLM assertion failed');
|
|
81
|
-
},
|
|
82
|
-
longTestTimeout
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
it(
|
|
86
|
-
'should not throw when throws option is false',
|
|
87
|
-
async () => {
|
|
88
|
-
const result = await aiExpect('hello').toEqual('goodbye', { throws: false });
|
|
89
|
-
expect(result).toBe(false);
|
|
90
|
-
},
|
|
91
|
-
longTestTimeout
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
it(
|
|
95
|
-
'should handle business logic validation',
|
|
96
|
-
async () => {
|
|
97
|
-
const businessRecommendation =
|
|
98
|
-
'Increase marketing budget by 20% for Q4 to boost holiday sales and target demographics aged 25-45 through social media campaigns';
|
|
99
|
-
|
|
100
|
-
const result = await aiExpect(businessRecommendation).toSatisfy(
|
|
101
|
-
'Is this recommendation specific, actionable, and includes measurable targets?',
|
|
102
|
-
{ throws: false }
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
expect(result).toBe(true);
|
|
106
|
-
},
|
|
107
|
-
longTestTimeout
|
|
108
|
-
);
|
|
109
|
-
});
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import chatgpt from '../../lib/chatgpt/index.js';
|
|
2
|
-
|
|
3
|
-
function buildEqualityPrompt({ actual, expected, context }) {
|
|
4
|
-
return `Does the actual value strictly equal the expected value?\n\nActual: ${JSON.stringify(
|
|
5
|
-
actual,
|
|
6
|
-
null,
|
|
7
|
-
2
|
|
8
|
-
)}\nExpected: ${JSON.stringify(expected, null, 2)}\n\n${
|
|
9
|
-
context ? `Context: ${JSON.stringify(context, null, 2)}\n` : ''
|
|
10
|
-
}Answer only "True" or "False".`;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function buildConstraintPrompt({ actual, constraint, context }) {
|
|
14
|
-
return `Given this constraint: "${constraint}"\n\nActual value: ${JSON.stringify(
|
|
15
|
-
actual,
|
|
16
|
-
null,
|
|
17
|
-
2
|
|
18
|
-
)}\n\n${
|
|
19
|
-
context ? `Additional context: ${JSON.stringify(context, null, 2)}\n` : ''
|
|
20
|
-
}Does the actual value satisfy the constraint? Answer only "True" or "False".`;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export async function llmAssert({
|
|
24
|
-
actual,
|
|
25
|
-
equals,
|
|
26
|
-
constraint,
|
|
27
|
-
context,
|
|
28
|
-
throws = true,
|
|
29
|
-
message,
|
|
30
|
-
llm = {},
|
|
31
|
-
}) {
|
|
32
|
-
if (equals === undefined && !constraint)
|
|
33
|
-
throw new TypeError('Provide either "equals" or "constraint".');
|
|
34
|
-
|
|
35
|
-
const prompt =
|
|
36
|
-
equals !== undefined
|
|
37
|
-
? buildEqualityPrompt({ actual, expected: equals, context })
|
|
38
|
-
: buildConstraintPrompt({ actual, constraint, context });
|
|
39
|
-
|
|
40
|
-
const answer = await chatgpt(prompt, { modelOptions: llm });
|
|
41
|
-
const text = typeof answer === 'string' ? answer : answer.content;
|
|
42
|
-
const passed = /^true$/i.test(text.trim());
|
|
43
|
-
|
|
44
|
-
if (!passed && throws) {
|
|
45
|
-
let msg;
|
|
46
|
-
if (typeof message === 'function') {
|
|
47
|
-
msg = message({ actual, equals, constraint });
|
|
48
|
-
} else {
|
|
49
|
-
msg = message;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (!msg) {
|
|
53
|
-
msg =
|
|
54
|
-
equals !== undefined
|
|
55
|
-
? 'LLM assertion failed: Does the actual value strictly equal the expected value?'
|
|
56
|
-
: `LLM assertion failed: ${constraint}`;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
throw new Error(msg);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return passed;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export default function expect(actual, shared = {}) {
|
|
66
|
-
const run = (payload, opts) => llmAssert({ actual, ...payload, ...shared, ...opts });
|
|
67
|
-
return {
|
|
68
|
-
toEqual(expected, opts) {
|
|
69
|
-
return run({ equals: expected }, opts);
|
|
70
|
-
},
|
|
71
|
-
toSatisfy(constraint, opts) {
|
|
72
|
-
return run({ constraint }, opts);
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
|
-
}
|