@far-world-labs/verblets 0.2.0 → 0.4.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/README.md +98 -213
- package/dist/index.browser.js +221 -0
- package/dist/index.js +696 -0
- package/dist/shared-CMgpfDG4.js +10714 -0
- package/package.json +38 -15
- 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 -12
- 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/clear-redis.js +0 -74
- 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/conversation/README.md +0 -26
- package/src/chains/conversation/index.examples.js +0 -398
- package/src/chains/conversation/index.js +0 -126
- package/src/chains/conversation/index.spec.js +0 -148
- package/src/chains/conversation/turn-policies.js +0 -93
- package/src/chains/conversation/turn-policies.md +0 -123
- package/src/chains/conversation/turn-policies.spec.js +0 -135
- 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 -207
- 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 -166
- package/src/chains/intersections/index.examples.js +0 -280
- package/src/chains/intersections/index.js +0 -218
- 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 -366
- package/src/chains/llm-logger/index.js +0 -591
- package/src/chains/llm-logger/index.spec.js +0 -391
- package/src/chains/llm-logger/schema.json +0 -105
- 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 -64
- package/src/chains/set-interval/index.js +0 -152
- 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 -13
- package/src/constants/messages.js +0 -3
- package/src/constants/models.js +0 -184
- package/src/index.js +0 -203
- 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/assert/README.md +0 -84
- package/src/lib/assert/index.js +0 -50
- 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 -82
- package/src/lib/ring-buffer/index.js +0 -235
- package/src/lib/ring-buffer/index.spec.js +0 -388
- 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/conversation-turn/README.md +0 -33
- package/src/verblets/conversation-turn/index.examples.js +0 -218
- package/src/verblets/conversation-turn/index.js +0 -68
- package/src/verblets/conversation-turn/index.spec.js +0 -77
- package/src/verblets/conversation-turn-multi/README.md +0 -31
- package/src/verblets/conversation-turn-multi/index.examples.js +0 -160
- package/src/verblets/conversation-turn-multi/index.js +0 -104
- package/src/verblets/conversation-turn-multi/index.spec.js +0 -63
- 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 -125
- 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/people-list/README.md +0 -28
- package/src/verblets/people-list/index.examples.js +0 -184
- package/src/verblets/people-list/index.js +0 -44
- package/src/verblets/people-list/index.spec.js +0 -49
- 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,447 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import modelService from './index.js';
|
|
3
|
-
import Model from './model.js';
|
|
4
|
-
|
|
5
|
-
// helper tokenizer
|
|
6
|
-
const tokenizer = (t) => t.split(' ');
|
|
7
|
-
|
|
8
|
-
describe('Model negotiation', () => {
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
// Reset models before each test
|
|
11
|
-
modelService.models = {};
|
|
12
|
-
modelService.bestPublicModelKey = 'fastGood';
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
describe('Privacy models', () => {
|
|
16
|
-
it('prefers privacy model when requested and available', () => {
|
|
17
|
-
modelService.models = {
|
|
18
|
-
privacy: new Model({
|
|
19
|
-
name: 'privacy-model',
|
|
20
|
-
maxContextWindow: 128000,
|
|
21
|
-
maxOutputTokens: 8192,
|
|
22
|
-
requestTimeout: 1000,
|
|
23
|
-
tokenizer,
|
|
24
|
-
}),
|
|
25
|
-
fastGood: new Model({
|
|
26
|
-
name: 'fast-good-model',
|
|
27
|
-
maxContextWindow: 128000,
|
|
28
|
-
maxOutputTokens: 16384,
|
|
29
|
-
requestTimeout: 1000,
|
|
30
|
-
tokenizer,
|
|
31
|
-
}),
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const key = modelService.negotiateModel('fastGood', { privacy: true });
|
|
35
|
-
expect(key).toBe('privacy');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('throws error when privacy requested but not configured', () => {
|
|
39
|
-
modelService.models = {
|
|
40
|
-
fastGood: new Model({
|
|
41
|
-
name: 'fast-good-model',
|
|
42
|
-
maxContextWindow: 128000,
|
|
43
|
-
maxOutputTokens: 16384,
|
|
44
|
-
requestTimeout: 1000,
|
|
45
|
-
tokenizer,
|
|
46
|
-
}),
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
expect(modelService.negotiateModel('fastGood', { privacy: true })).toBe(undefined);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
describe('Exact model key matching', () => {
|
|
54
|
-
beforeEach(() => {
|
|
55
|
-
modelService.models = {
|
|
56
|
-
fastGood: new Model({
|
|
57
|
-
name: 'fast-good',
|
|
58
|
-
maxContextWindow: 128000,
|
|
59
|
-
maxOutputTokens: 16384,
|
|
60
|
-
requestTimeout: 1000,
|
|
61
|
-
tokenizer,
|
|
62
|
-
}),
|
|
63
|
-
fastCheap: new Model({
|
|
64
|
-
name: 'fast-cheap',
|
|
65
|
-
maxContextWindow: 128000,
|
|
66
|
-
maxOutputTokens: 8192,
|
|
67
|
-
requestTimeout: 1000,
|
|
68
|
-
tokenizer,
|
|
69
|
-
}),
|
|
70
|
-
fastReasoning: new Model({
|
|
71
|
-
name: 'fast-reasoning',
|
|
72
|
-
maxContextWindow: 200000,
|
|
73
|
-
maxOutputTokens: 100000,
|
|
74
|
-
requestTimeout: 1000,
|
|
75
|
-
tokenizer,
|
|
76
|
-
}),
|
|
77
|
-
fastCheapReasoning: new Model({
|
|
78
|
-
name: 'fast-cheap-reasoning',
|
|
79
|
-
maxContextWindow: 128000,
|
|
80
|
-
maxOutputTokens: 16384,
|
|
81
|
-
requestTimeout: 1000,
|
|
82
|
-
tokenizer,
|
|
83
|
-
}),
|
|
84
|
-
fastGoodMulti: new Model({
|
|
85
|
-
name: 'fast-good-multi',
|
|
86
|
-
maxContextWindow: 1000000,
|
|
87
|
-
maxOutputTokens: 32768,
|
|
88
|
-
requestTimeout: 1000,
|
|
89
|
-
tokenizer,
|
|
90
|
-
}),
|
|
91
|
-
fastCheapReasoningMulti: new Model({
|
|
92
|
-
name: 'fast-cheap-reasoning-multi',
|
|
93
|
-
maxContextWindow: 128000,
|
|
94
|
-
maxOutputTokens: 16384,
|
|
95
|
-
requestTimeout: 1000,
|
|
96
|
-
tokenizer,
|
|
97
|
-
}),
|
|
98
|
-
good: new Model({
|
|
99
|
-
name: 'good',
|
|
100
|
-
maxContextWindow: 128000,
|
|
101
|
-
maxOutputTokens: 16384,
|
|
102
|
-
requestTimeout: 1000,
|
|
103
|
-
tokenizer,
|
|
104
|
-
}),
|
|
105
|
-
reasoning: new Model({
|
|
106
|
-
name: 'reasoning',
|
|
107
|
-
maxContextWindow: 200000,
|
|
108
|
-
maxOutputTokens: 100000,
|
|
109
|
-
requestTimeout: 1000,
|
|
110
|
-
tokenizer,
|
|
111
|
-
}),
|
|
112
|
-
fast: new Model({
|
|
113
|
-
name: 'fast',
|
|
114
|
-
maxContextWindow: 128000,
|
|
115
|
-
maxOutputTokens: 16384,
|
|
116
|
-
requestTimeout: 1000,
|
|
117
|
-
tokenizer,
|
|
118
|
-
}),
|
|
119
|
-
cheap: new Model({
|
|
120
|
-
name: 'cheap',
|
|
121
|
-
maxContextWindow: 128000,
|
|
122
|
-
maxOutputTokens: 8192,
|
|
123
|
-
requestTimeout: 1000,
|
|
124
|
-
tokenizer,
|
|
125
|
-
}),
|
|
126
|
-
};
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('returns highest priority match for fast + cheap', () => {
|
|
130
|
-
// Should find fastCheap since it has both fast and cheap
|
|
131
|
-
const key = modelService.negotiateModel(null, { fast: true, cheap: true });
|
|
132
|
-
expect(key).toBe('fastCheap'); // fastCheap matches both requirements
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it('returns highest priority match for fast + reasoning', () => {
|
|
136
|
-
// Should find fastReasoning since it has both fast and reasoning
|
|
137
|
-
const key = modelService.negotiateModel(null, { fast: true, reasoning: true });
|
|
138
|
-
expect(key).toBe('fastCheapReasoning'); // fastReasoning matches both requirements
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('returns exact match when it exists and has high priority', () => {
|
|
142
|
-
const key = modelService.negotiateModel(null, { fast: true, cheap: true, reasoning: true });
|
|
143
|
-
expect(key).toBe('fastCheapReasoning'); // Exact match exists
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
it('returns exact match for fast + good + multi', () => {
|
|
147
|
-
const key = modelService.negotiateModel(null, { fast: true, good: true, multi: true });
|
|
148
|
-
expect(key).toBe('fastGoodMulti'); // Exact match exists
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it('returns exact match for fast + cheap + reasoning + multi', () => {
|
|
152
|
-
const key = modelService.negotiateModel(null, {
|
|
153
|
-
fast: true,
|
|
154
|
-
cheap: true,
|
|
155
|
-
reasoning: true,
|
|
156
|
-
multi: true,
|
|
157
|
-
});
|
|
158
|
-
expect(key).toBe('fastCheapReasoningMulti'); // Exact match exists
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
describe('Fallback logic', () => {
|
|
163
|
-
beforeEach(() => {
|
|
164
|
-
modelService.models = {
|
|
165
|
-
fastGoodCheap: new Model({
|
|
166
|
-
name: 'fast-good-cheap',
|
|
167
|
-
maxContextWindow: 128000,
|
|
168
|
-
maxOutputTokens: 16384,
|
|
169
|
-
requestTimeout: 1000,
|
|
170
|
-
tokenizer,
|
|
171
|
-
}),
|
|
172
|
-
fastGood: new Model({
|
|
173
|
-
name: 'fast-good',
|
|
174
|
-
maxContextWindow: 128000,
|
|
175
|
-
maxOutputTokens: 16384,
|
|
176
|
-
requestTimeout: 1000,
|
|
177
|
-
tokenizer,
|
|
178
|
-
}),
|
|
179
|
-
fastCheap: new Model({
|
|
180
|
-
name: 'fast-cheap',
|
|
181
|
-
maxContextWindow: 128000,
|
|
182
|
-
maxOutputTokens: 8192,
|
|
183
|
-
requestTimeout: 1000,
|
|
184
|
-
tokenizer,
|
|
185
|
-
}),
|
|
186
|
-
fastReasoning: new Model({
|
|
187
|
-
name: 'fast-reasoning',
|
|
188
|
-
maxContextWindow: 200000,
|
|
189
|
-
maxOutputTokens: 100000,
|
|
190
|
-
requestTimeout: 1000,
|
|
191
|
-
tokenizer,
|
|
192
|
-
}),
|
|
193
|
-
good: new Model({
|
|
194
|
-
name: 'good',
|
|
195
|
-
maxContextWindow: 128000,
|
|
196
|
-
maxOutputTokens: 16384,
|
|
197
|
-
requestTimeout: 1000,
|
|
198
|
-
tokenizer,
|
|
199
|
-
}),
|
|
200
|
-
reasoning: new Model({
|
|
201
|
-
name: 'reasoning',
|
|
202
|
-
maxContextWindow: 200000,
|
|
203
|
-
maxOutputTokens: 100000,
|
|
204
|
-
requestTimeout: 1000,
|
|
205
|
-
tokenizer,
|
|
206
|
-
}),
|
|
207
|
-
fast: new Model({
|
|
208
|
-
name: 'fast',
|
|
209
|
-
maxContextWindow: 128000,
|
|
210
|
-
maxOutputTokens: 16384,
|
|
211
|
-
requestTimeout: 1000,
|
|
212
|
-
tokenizer,
|
|
213
|
-
}),
|
|
214
|
-
cheap: new Model({
|
|
215
|
-
name: 'cheap',
|
|
216
|
-
maxContextWindow: 128000,
|
|
217
|
-
maxOutputTokens: 8192,
|
|
218
|
-
requestTimeout: 1000,
|
|
219
|
-
tokenizer,
|
|
220
|
-
}),
|
|
221
|
-
};
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
it('finds exact match when available', () => {
|
|
225
|
-
const key = modelService.negotiateModel(null, { fast: true, good: true });
|
|
226
|
-
expect(key).toBe('fastGoodCheap');
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
it('requires all specified features to match', () => {
|
|
230
|
-
// Request multi but no multi models exist - should return undefined
|
|
231
|
-
expect(modelService.negotiateModel(null, { fast: true, multi: true })).toBe(undefined);
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it('picks higher priority model when multiple match', () => {
|
|
235
|
-
// Both fastGoodCheap, fastGood and good match { good: true }, should pick fastGoodCheap (highest priority)
|
|
236
|
-
const key = modelService.negotiateModel(null, { good: true });
|
|
237
|
-
expect(key).toBe('fastGoodCheap');
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
it('respects all requirements strictly', () => {
|
|
241
|
-
// Request fast + cheap + reasoning - no exact match available, should return undefined since reasoning is requested
|
|
242
|
-
expect(modelService.negotiateModel(null, { fast: true, cheap: true, reasoning: true })).toBe(
|
|
243
|
-
undefined
|
|
244
|
-
);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it('works with single requirements', () => {
|
|
248
|
-
const key = modelService.negotiateModel(null, { reasoning: true });
|
|
249
|
-
expect(key).toBe('fastReasoning');
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
it('works with multi requirement when available', () => {
|
|
253
|
-
modelService.models.fastGoodMulti = new Model({
|
|
254
|
-
name: 'fast-good-multi',
|
|
255
|
-
maxContextWindow: 1000000,
|
|
256
|
-
maxOutputTokens: 32768,
|
|
257
|
-
requestTimeout: 1000,
|
|
258
|
-
tokenizer,
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
const key = modelService.negotiateModel(null, { fast: true, good: true, multi: true });
|
|
262
|
-
expect(key).toBe('fastGoodMulti');
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('falls back to best public model when no matches found', () => {
|
|
266
|
-
// Request something that doesn't exist with reasoning - should return undefined
|
|
267
|
-
expect(
|
|
268
|
-
modelService.negotiateModel(null, {
|
|
269
|
-
fast: true,
|
|
270
|
-
cheap: true,
|
|
271
|
-
good: true,
|
|
272
|
-
reasoning: true,
|
|
273
|
-
multi: true,
|
|
274
|
-
})
|
|
275
|
-
).toBe(undefined);
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
it('prioritizes better combinations over individual features', () => {
|
|
279
|
-
// Both fast and fastGoodCheap match { fast: true }, should pick fastGoodCheap
|
|
280
|
-
const key = modelService.negotiateModel(null, { fast: true });
|
|
281
|
-
expect(key).toBe('fastGoodCheap');
|
|
282
|
-
});
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
describe('Preferred model handling', () => {
|
|
286
|
-
beforeEach(() => {
|
|
287
|
-
modelService.models = {
|
|
288
|
-
fastGood: new Model({
|
|
289
|
-
name: 'fast-good',
|
|
290
|
-
maxContextWindow: 128000,
|
|
291
|
-
maxOutputTokens: 16384,
|
|
292
|
-
requestTimeout: 1000,
|
|
293
|
-
tokenizer,
|
|
294
|
-
}),
|
|
295
|
-
customModel: new Model({
|
|
296
|
-
name: 'custom',
|
|
297
|
-
maxContextWindow: 64000,
|
|
298
|
-
maxOutputTokens: 8192,
|
|
299
|
-
requestTimeout: 1000,
|
|
300
|
-
tokenizer,
|
|
301
|
-
}),
|
|
302
|
-
};
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
it('returns preferred model when available and no privacy requested', () => {
|
|
306
|
-
const key = modelService.negotiateModel('customModel', { fast: true });
|
|
307
|
-
expect(key).toBe('fastGood');
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
it('ignores preferred model when privacy is requested', () => {
|
|
311
|
-
modelService.models.privacy = new Model({
|
|
312
|
-
name: 'privacy',
|
|
313
|
-
maxContextWindow: 128000,
|
|
314
|
-
maxOutputTokens: 8192,
|
|
315
|
-
requestTimeout: 1000,
|
|
316
|
-
tokenizer,
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
const key = modelService.negotiateModel('customModel', { privacy: true });
|
|
320
|
-
expect(key).toBe('privacy');
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
it('falls back to negotiation when preferred model does not exist', () => {
|
|
324
|
-
const key = modelService.negotiateModel('nonExistentModel', { fast: true });
|
|
325
|
-
expect(key).toBe('fastGood');
|
|
326
|
-
});
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
describe('Edge cases', () => {
|
|
330
|
-
beforeEach(() => {
|
|
331
|
-
modelService.models = {
|
|
332
|
-
fastGood: new Model({
|
|
333
|
-
name: 'fast-good',
|
|
334
|
-
maxContextWindow: 128000,
|
|
335
|
-
maxOutputTokens: 16384,
|
|
336
|
-
requestTimeout: 1000,
|
|
337
|
-
tokenizer,
|
|
338
|
-
}),
|
|
339
|
-
};
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
it('handles empty negotiation object', () => {
|
|
343
|
-
const key = modelService.negotiateModel(null, {});
|
|
344
|
-
expect(key).toBe('fastGood');
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
it('handles undefined negotiation', () => {
|
|
348
|
-
const key = modelService.negotiateModel(null);
|
|
349
|
-
expect(key).toBe('fastGood');
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
it('handles single flag requests', () => {
|
|
353
|
-
const key = modelService.negotiateModel(null, { fast: true });
|
|
354
|
-
expect(key).toBe('fastGood');
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
it('prioritizes reasoning over good when both are requested', () => {
|
|
358
|
-
modelService.models.fastReasoning = new Model({
|
|
359
|
-
name: 'fast-reasoning',
|
|
360
|
-
maxContextWindow: 200000,
|
|
361
|
-
maxOutputTokens: 100000,
|
|
362
|
-
requestTimeout: 1000,
|
|
363
|
-
tokenizer,
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
// Request fast + reasoning + good but no model has all three - should return undefined
|
|
367
|
-
expect(modelService.negotiateModel(null, { fast: true, reasoning: true, good: true })).toBe(
|
|
368
|
-
undefined
|
|
369
|
-
);
|
|
370
|
-
});
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
describe('Property negation', () => {
|
|
374
|
-
beforeEach(() => {
|
|
375
|
-
modelService.models = {
|
|
376
|
-
fastGoodCheap: new Model({
|
|
377
|
-
name: 'fast-good-cheap',
|
|
378
|
-
maxContextWindow: 128000,
|
|
379
|
-
maxOutputTokens: 16384,
|
|
380
|
-
requestTimeout: 1000,
|
|
381
|
-
tokenizer,
|
|
382
|
-
}),
|
|
383
|
-
fastGood: new Model({
|
|
384
|
-
name: 'fast-good',
|
|
385
|
-
maxContextWindow: 128000,
|
|
386
|
-
maxOutputTokens: 16384,
|
|
387
|
-
requestTimeout: 1000,
|
|
388
|
-
tokenizer,
|
|
389
|
-
}),
|
|
390
|
-
good: new Model({
|
|
391
|
-
name: 'good',
|
|
392
|
-
maxContextWindow: 128000,
|
|
393
|
-
maxOutputTokens: 16384,
|
|
394
|
-
requestTimeout: 1000,
|
|
395
|
-
tokenizer,
|
|
396
|
-
}),
|
|
397
|
-
fast: new Model({
|
|
398
|
-
name: 'fast',
|
|
399
|
-
maxContextWindow: 128000,
|
|
400
|
-
maxOutputTokens: 16384,
|
|
401
|
-
requestTimeout: 1000,
|
|
402
|
-
tokenizer,
|
|
403
|
-
}),
|
|
404
|
-
reasoning: new Model({
|
|
405
|
-
name: 'reasoning',
|
|
406
|
-
maxContextWindow: 200000,
|
|
407
|
-
maxOutputTokens: 100000,
|
|
408
|
-
requestTimeout: 1000,
|
|
409
|
-
tokenizer,
|
|
410
|
-
}),
|
|
411
|
-
};
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
it('excludes models with negated properties', () => {
|
|
415
|
-
// Request good but NOT fast - should pick 'good' over 'fastGood'
|
|
416
|
-
const key = modelService.negotiateModel(null, { good: true, fast: false });
|
|
417
|
-
expect(key).toBe('good');
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
it('excludes models with multiple negated properties', () => {
|
|
421
|
-
// Request good but NOT fast and NOT cheap - should pick 'good'
|
|
422
|
-
const key = modelService.negotiateModel(null, { good: true, fast: false, cheap: false });
|
|
423
|
-
expect(key).toBe('good');
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
it('works with only negated properties', () => {
|
|
427
|
-
// Request NOT fast - should pick 'good' (first non-fast model in priority)
|
|
428
|
-
const key = modelService.negotiateModel(null, { fast: false });
|
|
429
|
-
expect(key).toBe('good');
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
it('combines positive and negative requirements', () => {
|
|
433
|
-
// Request fast but NOT good - should pick 'fast' over 'fastGood'
|
|
434
|
-
// fastGoodCheap has both fast and good, so it's excluded by good: false
|
|
435
|
-
// fastGood has both fast and good, so it's excluded by good: false
|
|
436
|
-
// fast has fast but no good, so it matches
|
|
437
|
-
const key = modelService.negotiateModel(null, { fast: true, good: false });
|
|
438
|
-
expect(key).toBe('fast');
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
it('falls back when negation eliminates all matches', () => {
|
|
442
|
-
// Request NOT reasoning (all models are non-reasoning, so should pick first priority)
|
|
443
|
-
const key = modelService.negotiateModel(null, { good: false });
|
|
444
|
-
expect(key).toBe('fast');
|
|
445
|
-
});
|
|
446
|
-
});
|
|
447
|
-
});
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { createClient } from 'redis';
|
|
2
|
-
|
|
3
|
-
let client;
|
|
4
|
-
let constructingClient;
|
|
5
|
-
|
|
6
|
-
class NullRedisClient {
|
|
7
|
-
constructor() {
|
|
8
|
-
this.store = {};
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
get(key) {
|
|
12
|
-
// Redis returns null, not undefined
|
|
13
|
-
return this.store[key] ?? null;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
del(key) {
|
|
17
|
-
delete this.store[key];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
set(key, value, _options) {
|
|
21
|
-
this.store[key] = value;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
disconnect() {
|
|
25
|
-
// no implementation
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
class SafeRedisClient {
|
|
30
|
-
constructor(redisClient) {
|
|
31
|
-
this.redisClient = redisClient;
|
|
32
|
-
this.fallbackClient = new NullRedisClient();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async get(key) {
|
|
36
|
-
try {
|
|
37
|
-
return await this.redisClient.get(key);
|
|
38
|
-
} catch (error) {
|
|
39
|
-
if (this.isConnectionError(error)) {
|
|
40
|
-
console.warn('Redis connection lost, falling back to in-memory cache');
|
|
41
|
-
return this.fallbackClient.get(key);
|
|
42
|
-
}
|
|
43
|
-
throw error;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async set(key, value, options) {
|
|
48
|
-
try {
|
|
49
|
-
return await this.redisClient.set(key, value, options);
|
|
50
|
-
} catch (error) {
|
|
51
|
-
if (this.isConnectionError(error)) {
|
|
52
|
-
console.warn('Redis connection lost, falling back to in-memory cache');
|
|
53
|
-
return this.fallbackClient.set(key, value, options);
|
|
54
|
-
}
|
|
55
|
-
throw error;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async del(key) {
|
|
60
|
-
try {
|
|
61
|
-
return await this.redisClient.del(key);
|
|
62
|
-
} catch (error) {
|
|
63
|
-
if (this.isConnectionError(error)) {
|
|
64
|
-
console.warn('Redis connection lost, falling back to in-memory cache');
|
|
65
|
-
return this.fallbackClient.del(key);
|
|
66
|
-
}
|
|
67
|
-
throw error;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async disconnect() {
|
|
72
|
-
try {
|
|
73
|
-
return await this.redisClient.disconnect();
|
|
74
|
-
} catch {
|
|
75
|
-
// Ignore disconnect errors
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
isConnectionError(error) {
|
|
80
|
-
return (
|
|
81
|
-
error.message.includes('client is closed') ||
|
|
82
|
-
error.message.includes('ECONNREFUSED') ||
|
|
83
|
-
error.message.includes('connection') ||
|
|
84
|
-
error.code === 'ECONNREFUSED'
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const constructClient = async () => {
|
|
90
|
-
if (process.env.TEST === 'true' && process.env.EXAMPLES !== 'true') {
|
|
91
|
-
client = new NullRedisClient();
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const redisClient = createClient({
|
|
96
|
-
host: process.env.REDIS_HOST ?? 'localhost',
|
|
97
|
-
port: process.env.REDIS_PORT ?? 6379,
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
redisClient.on('error', (error) => {
|
|
101
|
-
if (client instanceof NullRedisClient) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (/ECONNREFUSED/.test(error.message)) {
|
|
106
|
-
console.error(
|
|
107
|
-
`Redis service [warning]: "${error.message}" Falling back to mock Redis client. This may incur greater usage costs and have slower response times.`
|
|
108
|
-
);
|
|
109
|
-
client = new NullRedisClient();
|
|
110
|
-
} else {
|
|
111
|
-
console.error(`Redis service [error]: ${error.message}`);
|
|
112
|
-
client = new NullRedisClient();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Safely disconnect the Redis client
|
|
116
|
-
redisClient.disconnect().catch(() => {
|
|
117
|
-
// Ignore disconnect errors
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
await redisClient.connect();
|
|
123
|
-
client = new SafeRedisClient(redisClient);
|
|
124
|
-
} catch (error) {
|
|
125
|
-
console.error(
|
|
126
|
-
`Redis service create [warning]: "${error.message}" Falling back to mock Redis client. This may incur greater usage costs and have slower response times.`
|
|
127
|
-
);
|
|
128
|
-
client = new NullRedisClient();
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
export const getClient = async () => {
|
|
133
|
-
if (client) {
|
|
134
|
-
return client;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (!constructingClient) {
|
|
138
|
-
constructingClient = constructClient();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
await constructingClient;
|
|
142
|
-
return client;
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
export const setClient = (newClient) => {
|
|
146
|
-
client = newClient;
|
|
147
|
-
};
|
package/src/test/setup.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeEach } from 'vitest';
|
|
2
|
-
import dotenv from 'dotenv';
|
|
3
|
-
import { getClient as getRedis } from '../services/redis/index.js';
|
|
4
|
-
|
|
5
|
-
// Load environment variables from .env file
|
|
6
|
-
dotenv.config();
|
|
7
|
-
|
|
8
|
-
let redisClient;
|
|
9
|
-
|
|
10
|
-
beforeEach(async () => {
|
|
11
|
-
// Get a fresh Redis client for each test
|
|
12
|
-
redisClient = await getRedis();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
afterAll(async () => {
|
|
16
|
-
// Clean up Redis client after all tests
|
|
17
|
-
if (redisClient) {
|
|
18
|
-
await redisClient.disconnect();
|
|
19
|
-
}
|
|
20
|
-
});
|
package/src/verblets/README.md
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# Verblets
|
|
2
|
-
|
|
3
|
-
The `verblets` directory contains individual utilities that wrap specific language-model workflows. Each verblet exports a single function and usually includes its own examples, tests and optional JSON schema.
|
|
4
|
-
|
|
5
|
-
Available verblets:
|
|
6
|
-
|
|
7
|
-
- [auto](./auto)
|
|
8
|
-
- [bool](./bool)
|
|
9
|
-
- [name](./name) - generate evocative names from text
|
|
10
|
-
- [enum](./enum)
|
|
11
|
-
- [intent](./intent)
|
|
12
|
-
- [number](./number)
|
|
13
|
-
- [number-with-units](./number-with-units)
|
|
14
|
-
- [date](../chains/date)
|
|
15
|
-
- [sentiment](./sentiment) - classify text sentiment
|
|
16
|
-
- [schema-org](./schema-org)
|
|
17
|
-
- [name-similar-to](./name-similar-to) - suggest short names matching a style
|
|
18
|
-
- [name](./name) - name something from a definition or description
|
|
19
|
-
- [to-object](./to-object) – see its [README](./to-object/README.md) for details.
|
|
20
|
-
- [list-map](./list-map) - map lists with prompts
|
|
21
|
-
- [list-reduce](./list-reduce) - reduce lists prompts
|
|
22
|
-
- [list-filter](./list-filter) - filter lists with custom instructions
|
|
23
|
-
- [list-group](./list-group) - group lists into categories with prompts
|
|
24
|
-
- [list-expand](./list-expand) - expand lists with similar items with prompts
|
|
25
|
-
|
|
26
|
-
Use these modules directly or compose them inside [chains](../chains/README.md).
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import auto from './index.js';
|
|
4
|
-
|
|
5
|
-
const examples = [
|
|
6
|
-
{
|
|
7
|
-
inputs: { text: 'test' },
|
|
8
|
-
want: {
|
|
9
|
-
typeOfResult: 'object',
|
|
10
|
-
hasProperties: ['functionArgsAsArray'],
|
|
11
|
-
},
|
|
12
|
-
},
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
describe('Auto verblet', () => {
|
|
16
|
-
examples.forEach((example) => {
|
|
17
|
-
it(example.inputs.text, async () => {
|
|
18
|
-
const result = await auto(example.inputs.text);
|
|
19
|
-
|
|
20
|
-
if (example.want.typeOfResult) {
|
|
21
|
-
expect(typeof result).toStrictEqual(example.want.typeOfResult);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (example.want.hasProperties) {
|
|
25
|
-
example.want.hasProperties.forEach((prop) => {
|
|
26
|
-
expect(result).toHaveProperty(prop);
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import chatGPT from '../../lib/chatgpt/index.js';
|
|
2
|
-
import schemas from '../../json-schemas/index.js';
|
|
3
|
-
|
|
4
|
-
export default async (text, config = {}) => {
|
|
5
|
-
const { llm, ...options } = config;
|
|
6
|
-
const tools = schemas.map((schema) => ({
|
|
7
|
-
type: 'function',
|
|
8
|
-
function: schema,
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
const functionFound = await chatGPT(text, {
|
|
12
|
-
modelOptions: {
|
|
13
|
-
// toolChoice: 'auto' // by default
|
|
14
|
-
tools,
|
|
15
|
-
...llm,
|
|
16
|
-
},
|
|
17
|
-
...options,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const functionArgs = functionFound.arguments;
|
|
21
|
-
|
|
22
|
-
const functionArgsAsArray = Array.isArray(functionArgs) ? functionArgs : [functionArgs];
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
...functionFound,
|
|
26
|
-
functionArgsAsArray,
|
|
27
|
-
};
|
|
28
|
-
};
|