@far-world-labs/verblets 0.1.1 → 0.1.3
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/.cursor/launch.json +30 -0
- package/.cursor/settings.json +20 -0
- package/.github/workflows/branch-protection.yml +22 -0
- package/.github/workflows/ci.yml +120 -0
- package/.prettierrc +6 -0
- package/.release-it.json +4 -1
- package/.vscode/launch.json +31 -0
- package/AGENTS.md +220 -0
- package/DEVELOPING.md +105 -0
- package/README.md +254 -0
- package/eslint.config.js +80 -0
- package/package.json +29 -17
- package/scripts/generate-test/index.js +29 -3
- package/scripts/runner/index.js +26 -0
- package/scripts/simple-editor/index.js +29 -18
- package/scripts/summarize-files/index.js +28 -4
- package/src/chains/README.md +30 -0
- package/src/chains/anonymize/README.md +21 -0
- package/src/chains/anonymize/index.examples.js +75 -0
- package/src/chains/anonymize/index.js +121 -0
- package/src/chains/anonymize/index.spec.js +78 -0
- package/src/chains/bulk-central-tendency/index.examples.js +138 -0
- package/src/chains/bulk-central-tendency/index.js +91 -0
- package/src/chains/bulk-filter/README.md +21 -0
- package/src/chains/bulk-filter/index.examples.js +22 -0
- package/src/chains/bulk-filter/index.js +58 -0
- package/src/chains/bulk-filter/index.spec.js +38 -0
- package/src/chains/bulk-find/README.md +16 -0
- package/src/chains/bulk-find/index.examples.js +20 -0
- package/src/chains/bulk-find/index.js +30 -0
- package/src/chains/bulk-find/index.spec.js +26 -0
- package/src/chains/bulk-group/README.md +23 -0
- package/src/chains/bulk-group/index.examples.js +18 -0
- package/src/chains/bulk-group/index.js +34 -0
- package/src/chains/bulk-group/index.spec.js +41 -0
- package/src/chains/bulk-map/README.md +43 -0
- package/src/chains/bulk-map/index.examples.js +17 -0
- package/src/chains/bulk-map/index.js +86 -0
- package/src/chains/bulk-map/index.spec.js +44 -0
- package/src/chains/bulk-reduce/README.md +12 -0
- package/src/chains/bulk-reduce/index.examples.js +15 -0
- package/src/chains/bulk-reduce/index.js +13 -0
- package/src/chains/bulk-reduce/index.spec.js +25 -0
- package/src/chains/bulk-score/README.md +16 -0
- package/src/chains/bulk-score/bulk-score-result.json +18 -0
- package/src/chains/bulk-score/index.examples.js +22 -0
- package/src/chains/bulk-score/index.js +133 -0
- package/src/chains/bulk-score/index.spec.js +30 -0
- package/src/chains/category-samples/README.md +61 -0
- package/src/chains/category-samples/index.examples.js +103 -0
- package/src/chains/category-samples/index.js +134 -0
- package/src/chains/collect-terms/README.md +12 -0
- package/src/chains/collect-terms/index.examples.js +16 -0
- package/src/chains/collect-terms/index.js +44 -0
- package/src/chains/collect-terms/index.spec.js +25 -0
- package/src/chains/date/README.md +12 -0
- package/src/chains/date/index.examples.js +47 -0
- package/src/chains/date/index.js +74 -0
- package/src/chains/date/index.spec.js +62 -0
- package/src/chains/disambiguate/README.md +22 -0
- package/src/chains/disambiguate/disambiguate-meanings-result.json +16 -0
- package/src/chains/disambiguate/index.examples.js +18 -0
- package/src/chains/disambiguate/index.js +92 -0
- package/src/chains/disambiguate/index.spec.js +25 -0
- package/src/chains/dismantle/README.md +67 -0
- package/src/chains/dismantle/dismantle.examples.js +27 -0
- package/src/chains/dismantle/index.js +6 -17
- package/src/chains/dismantle/index.spec.js +1 -2
- package/src/chains/expect/README.md +171 -0
- package/src/chains/expect/index.examples.js +146 -0
- package/src/chains/expect/index.js +173 -0
- package/src/chains/expect/index.spec.js +324 -0
- package/src/chains/filter-ambiguous/README.md +11 -0
- package/src/chains/filter-ambiguous/index.examples.js +20 -0
- package/src/chains/filter-ambiguous/index.js +49 -0
- package/src/chains/filter-ambiguous/index.spec.js +31 -0
- package/src/chains/glossary/README.md +19 -0
- package/src/chains/glossary/index.examples.js +386 -0
- package/src/chains/glossary/index.js +75 -0
- package/src/chains/glossary/index.spec.js +19 -0
- package/src/chains/intersections/README.md +152 -0
- package/src/chains/intersections/index.examples.js +279 -0
- package/src/chains/intersections/index.js +366 -0
- package/src/chains/intersections/intersection-result.json +38 -0
- package/src/chains/list/index.examples.js +12 -16
- package/src/chains/list/index.js +106 -53
- package/src/chains/list/index.spec.js +8 -9
- package/src/chains/list/list-result.json +16 -0
- package/src/chains/llm-logger/README.md +208 -0
- package/src/chains/llm-logger/index.js +205 -0
- package/src/chains/llm-logger/index.spec.js +330 -0
- package/src/chains/questions/index.examples.js +2 -1
- package/src/chains/questions/index.js +14 -15
- package/src/chains/scan-js/index.js +6 -9
- package/src/chains/set-interval/README.md +81 -0
- package/src/chains/set-interval/index.examples.js +36 -0
- package/src/chains/set-interval/index.js +131 -0
- package/src/chains/set-interval/index.spec.js +70 -0
- package/src/chains/socratic/README.md +17 -0
- package/src/chains/socratic/index.js +64 -0
- package/src/chains/socratic/index.spec.js +24 -0
- package/src/chains/sort/index.examples.js +3 -7
- package/src/chains/sort/index.js +65 -15
- package/src/chains/sort/index.spec.js +5 -8
- package/src/chains/sort/sort-result.json +16 -0
- package/src/chains/summary-map/README.md +9 -1
- package/src/chains/summary-map/index.examples.js +9 -2
- package/src/chains/summary-map/index.js +43 -25
- package/src/chains/summary-map/index.spec.js +78 -3
- package/src/chains/test/index.js +9 -13
- package/src/chains/test-advice/index.js +4 -5
- package/src/chains/themes/README.md +20 -0
- package/src/chains/themes/index.examples.js +17 -0
- package/src/chains/themes/index.js +28 -0
- package/src/chains/themes/index.spec.js +19 -0
- package/src/chains/veiled-variants/index.examples.js +18 -0
- package/src/chains/veiled-variants/index.js +107 -0
- package/src/chains/veiled-variants/index.spec.js +40 -0
- package/src/constants/common.js +0 -2
- package/src/constants/models.js +172 -0
- package/src/index.js +178 -18
- package/src/json-schemas/README.md +13 -0
- package/src/json-schemas/index.js +8 -14
- package/src/json-schemas/schema-dot-org-photograph.json +11 -5
- package/src/json-schemas/schema-dot-org-place.json +78 -5
- package/src/lib/README.md +26 -0
- package/src/lib/bulk-filter/README.md +22 -0
- package/src/lib/bulk-filter/index.examples.js +27 -0
- package/src/lib/bulk-filter/index.js +63 -0
- package/src/lib/bulk-filter/index.spec.js +38 -0
- package/src/lib/bulk-find/README.md +18 -0
- package/src/lib/bulk-find/index.examples.js +19 -0
- package/src/lib/bulk-find/index.js +30 -0
- package/src/lib/bulk-find/index.spec.js +41 -0
- package/src/lib/chatgpt/index.js +63 -43
- package/src/lib/combinations/index.js +30 -0
- package/src/lib/combinations/index.spec.js +23 -0
- package/src/lib/functional/index.js +28 -0
- package/src/lib/logger-service/index.js +32 -0
- package/src/lib/parse-js-parts/index.js +9 -21
- package/src/lib/parse-llm-list/README.md +39 -0
- package/src/lib/parse-llm-list/index.js +54 -0
- package/src/lib/parse-llm-list/index.spec.js +59 -0
- package/src/lib/path-aliases/index.js +1 -3
- package/src/lib/path-aliases/index.spec.js +2 -8
- package/src/lib/pave/index.js +4 -4
- package/src/lib/pave/index.spec.js +6 -3
- package/src/lib/prompt-cache/index.js +14 -10
- package/src/lib/retry/index.js +11 -8
- package/src/lib/ring-buffer/README.md +460 -0
- package/src/lib/ring-buffer/index.js +1074 -0
- package/src/lib/search-best-first/city-walk.spec.js +37 -0
- package/src/lib/search-best-first/index.js +42 -11
- package/src/lib/search-best-first/index.spec.js +35 -0
- package/src/lib/search-js-files/index.js +44 -47
- package/src/lib/search-js-files/scan-file.js +10 -21
- package/src/lib/shorten-text/index.js +2 -7
- package/src/lib/shorten-text/index.spec.js +3 -3
- package/src/lib/strip-response/index.js +2 -7
- package/src/lib/template-replace/index.js +23 -0
- package/src/lib/template-replace/index.spec.js +60 -0
- package/src/lib/to-date/index.js +11 -0
- package/src/lib/to-number/index.js +1 -1
- package/src/lib/transcribe/index.js +26 -9
- package/src/prompts/README.md +3 -1
- package/src/prompts/as-object-with-schema.js +3 -8
- package/src/prompts/as-schema-org-text.js +10 -2
- package/src/prompts/code-features.js +1 -5
- package/src/prompts/constants.js +27 -27
- package/src/prompts/generate-collection.js +1 -1
- package/src/prompts/intent.js +16 -22
- package/src/prompts/select-from-threshold.js +1 -2
- package/src/prompts/sort.js +4 -8
- package/src/prompts/style.js +4 -7
- package/src/prompts/wrap-list.js +1 -4
- package/src/services/llm-model/global-overrides.spec.js +432 -0
- package/src/services/llm-model/index.js +234 -40
- package/src/services/llm-model/model.js +2 -2
- package/src/services/llm-model/negotiate.spec.js +447 -0
- package/src/services/redis/index.js +70 -7
- package/src/test/setup.js +20 -0
- package/src/verblets/README.md +26 -0
- package/src/verblets/auto/index.examples.js +12 -9
- package/src/verblets/auto/index.js +10 -10
- package/src/verblets/auto/index.spec.js +4 -6
- package/src/verblets/bool/README.md +36 -0
- package/src/verblets/bool/index.examples.js +53 -1
- package/src/verblets/bool/index.js +6 -9
- package/src/verblets/bool/index.spec.js +1 -3
- package/src/verblets/central-tendency/README.md +166 -0
- package/src/verblets/central-tendency/central-tendency-result.json +24 -0
- package/src/verblets/central-tendency/index.examples.js +196 -0
- package/src/verblets/central-tendency/index.js +171 -0
- package/src/verblets/central-tendency/index.spec.js +148 -0
- package/src/verblets/enum/index.examples.js +1 -4
- package/src/verblets/enum/index.js +7 -4
- package/src/verblets/expect/README.md +64 -0
- package/src/verblets/expect/index.examples.js +109 -0
- package/src/verblets/expect/index.js +75 -0
- package/src/verblets/expect/index.spec.js +127 -0
- package/src/verblets/intent/index.examples.js +95 -7
- package/src/verblets/intent/index.js +56 -68
- package/src/verblets/intersection/README.md +16 -0
- package/src/verblets/intersection/index.examples.js +89 -0
- package/src/verblets/intersection/index.js +84 -0
- package/src/verblets/intersection/index.spec.js +60 -0
- package/src/verblets/intersection/intersection-result.json +16 -0
- package/src/verblets/list-expand/README.md +10 -0
- package/src/verblets/list-expand/index.examples.js +14 -0
- package/src/verblets/list-expand/index.js +104 -0
- package/src/verblets/list-expand/index.spec.js +18 -0
- package/src/verblets/list-expand/list-expand-result.json +16 -0
- package/src/verblets/list-filter/README.md +22 -0
- package/src/verblets/list-filter/index.examples.js +26 -0
- package/src/verblets/list-filter/index.js +18 -0
- package/src/verblets/list-filter/index.spec.js +19 -0
- package/src/verblets/list-find/README.md +11 -0
- package/src/verblets/list-find/index.examples.js +15 -0
- package/src/verblets/list-find/index.js +17 -0
- package/src/verblets/list-find/index.spec.js +19 -0
- package/src/verblets/list-group/README.md +16 -0
- package/src/verblets/list-group/index.examples.js +16 -0
- package/src/verblets/list-group/index.js +112 -0
- package/src/verblets/list-group/index.spec.js +35 -0
- package/src/verblets/list-group/list-group-result.json +16 -0
- package/src/verblets/list-map/README.md +11 -0
- package/src/verblets/list-map/index.examples.js +15 -0
- package/src/verblets/list-map/index.js +26 -0
- package/src/verblets/list-map/index.spec.js +17 -0
- package/src/verblets/list-reduce/README.md +10 -0
- package/src/verblets/list-reduce/index.examples.js +14 -0
- package/src/verblets/list-reduce/index.js +21 -0
- package/src/verblets/list-reduce/index.spec.js +27 -0
- package/src/verblets/list-reduce/index.spec.jsx +27 -0
- package/src/verblets/name/README.md +15 -0
- package/src/verblets/name/index.examples.js +28 -0
- package/src/verblets/name/index.js +19 -0
- package/src/verblets/name/index.spec.js +33 -0
- package/src/verblets/name-similar-to/README.md +26 -0
- package/src/verblets/name-similar-to/index.examples.js +18 -0
- package/src/verblets/name-similar-to/index.js +20 -0
- package/src/verblets/name-similar-to/index.spec.js +13 -0
- package/src/verblets/number/index.examples.js +173 -7
- package/src/verblets/number/index.js +5 -2
- package/src/verblets/number/index.spec.js +1 -3
- package/src/verblets/number-with-units/index.examples.js +5 -1
- package/src/verblets/number-with-units/index.js +74 -9
- package/src/verblets/number-with-units/number-with-units-result.json +23 -0
- package/src/verblets/schema-org/index.examples.js +2 -7
- package/src/verblets/schema-org/index.js +32 -3
- package/src/verblets/sentiment/README.md +10 -0
- package/src/verblets/sentiment/index.examples.js +20 -0
- package/src/verblets/sentiment/index.js +9 -0
- package/src/verblets/sentiment/index.spec.js +20 -0
- package/src/verblets/to-object/index.js +10 -15
- package/src/verblets/to-object/index.spec.js +1 -4
- package/.eslintrc.json +0 -42
- package/docs/README.md +0 -41
- package/docs/babel.config.js +0 -3
- package/docs/blog/2019-05-28-first-blog-post.md +0 -12
- package/docs/blog/2019-05-29-long-blog-post.md +0 -44
- package/docs/blog/2021-08-01-mdx-blog-post.mdx +0 -20
- package/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
- package/docs/blog/2021-08-26-welcome/index.md +0 -25
- package/docs/blog/authors.yml +0 -17
- package/docs/docs/api/bool.md +0 -74
- package/docs/docs/api/search.md +0 -51
- package/docs/docs/intro.md +0 -47
- package/docs/docs/tutorial-basics/_category_.json +0 -8
- package/docs/docs/tutorial-basics/congratulations.md +0 -23
- package/docs/docs/tutorial-basics/create-a-blog-post.md +0 -34
- package/docs/docs/tutorial-basics/create-a-document.md +0 -57
- package/docs/docs/tutorial-basics/create-a-page.md +0 -43
- package/docs/docs/tutorial-basics/deploy-your-site.md +0 -31
- package/docs/docs/tutorial-basics/markdown-features.mdx +0 -152
- package/docs/docs/tutorial-extras/_category_.json +0 -7
- package/docs/docs/tutorial-extras/img/docsVersionDropdown.png +0 -0
- package/docs/docs/tutorial-extras/img/localeDropdown.png +0 -0
- package/docs/docs/tutorial-extras/manage-docs-versions.md +0 -55
- package/docs/docs/tutorial-extras/translate-your-site.md +0 -88
- package/docs/docusaurus.config.js +0 -120
- package/docs/package.json +0 -44
- package/docs/sidebars.js +0 -31
- package/docs/src/components/HomepageFeatures/index.js +0 -61
- package/docs/src/components/HomepageFeatures/styles.module.css +0 -11
- package/docs/src/css/custom.css +0 -30
- package/docs/src/pages/index.js +0 -43
- package/docs/src/pages/index.module.css +0 -23
- package/docs/src/pages/markdown-page.md +0 -7
- package/docs/static/.nojekyll +0 -0
- package/docs/static/img/docusaurus-social-card.jpg +0 -0
- package/docs/static/img/docusaurus.png +0 -0
- package/docs/static/img/favicon.ico +0 -0
- package/docs/static/img/logo.svg +0 -1
- package/docs/static/img/undraw_docusaurus_mountain.svg +0 -171
- package/docs/static/img/undraw_docusaurus_react.svg +0 -170
- package/docs/static/img/undraw_docusaurus_tree.svg +0 -40
- package/src/constants/openai.js +0 -65
- /package/{.vite.config.examples.js → .vitest.config.examples.js} +0 -0
- /package/{.vite.config.js → .vitest.config.js} +0 -0
package/src/prompts/constants.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
// Basic
|
|
2
|
-
export const asUndefinedByDefault =
|
|
3
|
-
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
export const
|
|
2
|
+
export const asUndefinedByDefault = 'If you are unsure, say "undefined" as your answer.';
|
|
3
|
+
export const asBool = 'Answer the question either with "true" or "false" as your answer.';
|
|
4
|
+
export const asNumber =
|
|
5
|
+
'Answer the question with a number that could be parsed by the JS Number constructor. Do not include formatting, units, digit group separators, or spelled-out numbers in your answer.';
|
|
6
|
+
export const asDate =
|
|
7
|
+
'Answer the question with a date that can be parsed by the JS Date constructor. ISO format is preferred. Do not include additional text or punctuation.';
|
|
8
|
+
export const asJSON =
|
|
9
|
+
'Respond with a JSON object or array that parses with JSON.parse, with no wrapping code block, and no wrapping XML.';
|
|
7
10
|
|
|
8
11
|
// Response steering
|
|
9
|
-
export const useLineNumber =
|
|
10
|
-
'Include the line number where each check is performed.';
|
|
12
|
+
export const useLineNumber = 'Include the line number where each check is performed.';
|
|
11
13
|
export const noFalseInformation = 'Do not include false information.';
|
|
12
14
|
export const strictFormat = 'You MUST follow the format as described.';
|
|
13
|
-
export const tryCompleteData =
|
|
14
|
-
'Err towards giving complete data, even if you have to guess.';
|
|
15
|
+
export const tryCompleteData = 'Err towards giving complete data, even if you have to guess.';
|
|
15
16
|
|
|
16
17
|
// JSON Output
|
|
17
18
|
export const onlyJSON =
|
|
@@ -20,6 +21,8 @@ const onlyJSONArrayBase =
|
|
|
20
21
|
'Respond with a JSON array that parses with JSON.parse, with no additional text, no punctuation, and no code block.';
|
|
21
22
|
export const onlyJSONArray = onlyJSONArrayBase;
|
|
22
23
|
export const onlyJSONStringArray = `${onlyJSONArrayBase} The array should only contain text. No additional structure.`;
|
|
24
|
+
export const onlyJSONStringArrayPerLine =
|
|
25
|
+
'For each input line, return exactly one line containing a JSON array of strings. No additional text, no code blocks.';
|
|
23
26
|
export const onlyJSONObjectArray =
|
|
24
27
|
'Return an array of obects--not strings, and not just the objects.';
|
|
25
28
|
export const onlyJSONStringArrayAlt1 = 'Output an JSON array of strings.';
|
|
@@ -40,27 +43,29 @@ export const contentToJSON = 'Contents to convert to JSON:';
|
|
|
40
43
|
export const contentIsExample = 'Use this as example output only:';
|
|
41
44
|
export const contentIsChoices = 'Choose only from the following:';
|
|
42
45
|
export const contentIsTransformationSource = 'Transform the following object:';
|
|
43
|
-
export const contentListCriteria =
|
|
44
|
-
|
|
45
|
-
export const contentListItemCriteria =
|
|
46
|
-
'Make sure each item meets the following conditions:';
|
|
46
|
+
export const contentListCriteria = 'Create a list of items with the following description:';
|
|
47
|
+
export const contentListItemCriteria = 'Make sure each item meets the following conditions:';
|
|
47
48
|
export const contentListToOmit = 'Do not use any of the following items:';
|
|
48
49
|
export const contentIsExampleObject =
|
|
49
50
|
'The returned object must look like the following, including all the same properties:';
|
|
50
|
-
export const contentIsSchema =
|
|
51
|
-
'Make it conform exactly to the following schema:';
|
|
51
|
+
export const contentIsSchema = 'Make it conform exactly to the following schema:';
|
|
52
52
|
export const contentHasIntent = 'What is the intent of the following message:';
|
|
53
53
|
export const contentIsSortCriteria = 'Sort the following items by:';
|
|
54
|
+
export const contentIsIntent = 'Give me an intent response for the following:';
|
|
55
|
+
export const contentIsOperationOption = 'The extracted operation must be one of the following:';
|
|
56
|
+
export const contentIsParametersOptions =
|
|
57
|
+
'The extracted parameters must be from the following options:';
|
|
54
58
|
|
|
55
59
|
// Give explanation
|
|
56
60
|
export const explainAndSeparate =
|
|
57
61
|
'Give an explanation followed by a succinct answer. The explanation part should come first, and should be at least 100 words. Next, insert a row of 20 equal signs (=) to create a clear separation.';
|
|
58
62
|
export const explainAndSeparateJSON =
|
|
59
63
|
'The content below the dividing line should only be valid JSON that can be parsed with JSON.parse.';
|
|
60
|
-
export const explainAndSeparatePrimitive =
|
|
64
|
+
export const explainAndSeparatePrimitive =
|
|
65
|
+
'Next insert the succinctly-stated answer should be below the dividing line and work as a primitive datatype in JS. Be as succinct as possible as it will be parsed by a script.';
|
|
61
66
|
|
|
62
67
|
// Reflective
|
|
63
|
-
export const thinkStepByStep =
|
|
68
|
+
export const thinkStepByStep = "Let's think step by step";
|
|
64
69
|
export const identifyUnclearInfo =
|
|
65
70
|
'Identify any unclear or ambiguous information in your response, and rephrase it for clarity.';
|
|
66
71
|
export const argueAgainstOutput =
|
|
@@ -76,10 +81,8 @@ export const summarizeRequest =
|
|
|
76
81
|
'Please summarise what I am asking for you before you begin your answer.';
|
|
77
82
|
|
|
78
83
|
// Analytical
|
|
79
|
-
export const considerProsCons =
|
|
80
|
-
|
|
81
|
-
export const provideExamples =
|
|
82
|
-
'Provide specific examples to illustrate your point.';
|
|
84
|
+
export const considerProsCons = 'Consider both pros and cons before arriving at a conclusion.';
|
|
85
|
+
export const provideExamples = 'Provide specific examples to illustrate your point.';
|
|
83
86
|
export const explainReasoning = 'Explain the reasoning behind your answer.';
|
|
84
87
|
export const alternativeSolutions =
|
|
85
88
|
'If there are any alternative solutions or perspectives, please share them.';
|
|
@@ -90,12 +93,9 @@ export const alternativeInterpretations = 'How else could this be interpreted?';
|
|
|
90
93
|
// Evidence-Based
|
|
91
94
|
export const evidenceSupportsView = 'What evidence supports your view?';
|
|
92
95
|
export const expertResponse = 'How would an expert in this field respond?';
|
|
93
|
-
export const limitationsOfApproach =
|
|
94
|
-
'What are the limitations of your approach?';
|
|
96
|
+
export const limitationsOfApproach = 'What are the limitations of your approach?';
|
|
95
97
|
export const missingInformation = 'What information is still missing?';
|
|
96
98
|
export const evaluateDifferingViews = 'How would you evaluate differing views?';
|
|
97
99
|
export const confidenceInResponse = 'How confident are you in your response?';
|
|
98
|
-
export const lessKnowledgeResponse =
|
|
99
|
-
|
|
100
|
-
export const analogyForUnderstanding =
|
|
101
|
-
'Come up with an analogy to make this easier to understand.';
|
|
100
|
+
export const lessKnowledgeResponse = 'How would you answer this if you knew less about the topic?';
|
|
101
|
+
export const analogyForUnderstanding = 'Come up with an analogy to make this easier to understand.';
|
package/src/prompts/intent.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import fs from '
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
4
|
import wrapVariable from './wrap-variable.js';
|
|
5
|
+
import { onlyJSON } from './constants.js';
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
5
9
|
|
|
6
|
-
const contentIsIntent = '
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
10
|
+
const contentIsIntent = 'The intent is:';
|
|
11
|
+
const contentIsSchema = 'The schema is:';
|
|
12
|
+
const contentIsExample = 'An example of the output is:';
|
|
13
|
+
const contentIsOperationOption = 'The possible operations are:';
|
|
14
|
+
const contentIsParametersOptions = 'The possible parameters are:';
|
|
11
15
|
|
|
12
16
|
const exampleJSON = `{
|
|
13
|
-
"
|
|
14
|
-
"intent": {
|
|
15
|
-
"operation": "play-music",
|
|
16
|
-
"displayName": "Play Music"
|
|
17
|
-
},
|
|
17
|
+
"intent": "play_music",
|
|
18
18
|
"parameters": {
|
|
19
19
|
"genre": "rock"
|
|
20
20
|
},
|
|
@@ -23,9 +23,7 @@ const exampleJSON = `{
|
|
|
23
23
|
}
|
|
24
24
|
}`;
|
|
25
25
|
|
|
26
|
-
const intentSchema = JSON.parse(
|
|
27
|
-
await fs.readFile('./src/json-schemas/intent.json')
|
|
28
|
-
);
|
|
26
|
+
const intentSchema = JSON.parse(await fs.readFile(join(__dirname, '../json-schemas/intent.json')));
|
|
29
27
|
|
|
30
28
|
/**
|
|
31
29
|
* Approximates intent recognition like you might find with Wit.ai,
|
|
@@ -35,15 +33,11 @@ const intentSchema = JSON.parse(
|
|
|
35
33
|
export default (text, { operations = [], parameters = [] } = {}) => {
|
|
36
34
|
let operationsSection = '';
|
|
37
35
|
if (operations.length) {
|
|
38
|
-
operationsSection = `\n${contentIsOperationOption} ${operations.join(
|
|
39
|
-
', '
|
|
40
|
-
)}\n`;
|
|
36
|
+
operationsSection = `\n${contentIsOperationOption} ${operations.join(', ')}\n`;
|
|
41
37
|
}
|
|
42
38
|
let parametersSection = '';
|
|
43
39
|
if (parameters.length) {
|
|
44
|
-
parametersSection = `\n${contentIsParametersOptions} ${parameters.join(
|
|
45
|
-
', '
|
|
46
|
-
)}\n`;
|
|
40
|
+
parametersSection = `\n${contentIsParametersOptions} ${parameters.join(', ')}\n`;
|
|
47
41
|
}
|
|
48
42
|
|
|
49
43
|
return `
|
|
@@ -12,7 +12,6 @@ import * as R from 'ramda';
|
|
|
12
12
|
* const openEndedPrompt = `Questions ${openEndedDegree} open-ended. `
|
|
13
13
|
*/
|
|
14
14
|
export default (value, thresholds = []) => {
|
|
15
|
-
const threshold =
|
|
16
|
-
thresholds.find((t) => value <= t.threshold) || R.last(thresholds);
|
|
15
|
+
const threshold = thresholds.find((t) => value <= t.threshold) || R.last(thresholds);
|
|
17
16
|
return threshold.degree;
|
|
18
17
|
};
|
package/src/prompts/sort.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import wrapVariable from './wrap-variable.js';
|
|
2
2
|
import {
|
|
3
|
-
contentIsSortCriteria,
|
|
4
|
-
contentIsMain,
|
|
5
|
-
contentIsFixes,
|
|
6
3
|
contentIsDetails,
|
|
4
|
+
contentIsFixes,
|
|
5
|
+
contentIsMain,
|
|
6
|
+
contentIsSortCriteria,
|
|
7
7
|
onlyJSONStringArray,
|
|
8
8
|
} from './constants.js';
|
|
9
9
|
|
|
@@ -12,11 +12,7 @@ export const defaultFixes = 'Ignore duplicates in the list';
|
|
|
12
12
|
export const defaultSortOrder = 'descending';
|
|
13
13
|
|
|
14
14
|
export default (
|
|
15
|
-
{
|
|
16
|
-
description = defaultSortDescription,
|
|
17
|
-
fixes = defaultFixes,
|
|
18
|
-
sortOrder = defaultSortOrder,
|
|
19
|
-
},
|
|
15
|
+
{ description = defaultSortDescription, fixes = defaultFixes, sortOrder = defaultSortOrder },
|
|
20
16
|
list
|
|
21
17
|
) => {
|
|
22
18
|
const listLines = JSON.stringify(list, undefined, 2);
|
package/src/prompts/style.js
CHANGED
|
@@ -12,17 +12,14 @@ export default (
|
|
|
12
12
|
) => {
|
|
13
13
|
const toneModifiers = `Tone: ${tone.join(', ')}`;
|
|
14
14
|
const vocabularyModifiers = `Vocabulary: ${vocabulary.join(', ')}`;
|
|
15
|
-
const sentenceStructureModifiers = `Sentence structure: ${sentenceStructure.join(
|
|
16
|
-
', '
|
|
17
|
-
)}`;
|
|
15
|
+
const sentenceStructureModifiers = `Sentence structure: ${sentenceStructure.join(', ')}`;
|
|
18
16
|
const pointOfViewModifiers = `Point of view: ${pointOfView.join(', ')}`;
|
|
19
|
-
const lengthModifier = `Use between ${minWords} and ${
|
|
20
|
-
maxWords ?? 'any number'
|
|
21
|
-
} of words`;
|
|
17
|
+
const lengthModifier = `Use between ${minWords} and ${maxWords ?? 'any number'} of words`;
|
|
22
18
|
|
|
23
19
|
let noiseModifier = '';
|
|
24
20
|
if (noise > 0.5) {
|
|
25
|
-
noiseModifier =
|
|
21
|
+
noiseModifier =
|
|
22
|
+
"Completely reshape the ideas here, don't stick with the original structure. Don't change the meaning of the content though.";
|
|
26
23
|
}
|
|
27
24
|
|
|
28
25
|
return `Rewrite the following content:
|
package/src/prompts/wrap-list.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import wrapVariable from './wrap-variable.js';
|
|
2
2
|
|
|
3
|
-
export default (
|
|
4
|
-
list = [],
|
|
5
|
-
{ introText = 'Consider the following items:' } = {}
|
|
6
|
-
) => {
|
|
3
|
+
export default (list = [], { introText = 'Consider the following items:' } = {}) => {
|
|
7
4
|
const listText = list.map((f, i) => ` - ${i + 1}. ${f}`).join('\n');
|
|
8
5
|
|
|
9
6
|
let listFragment = wrapVariable('\n');
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import fetch from 'node-fetch';
|
|
3
|
+
import modelService from './index.js';
|
|
4
|
+
import Model from './model.js';
|
|
5
|
+
|
|
6
|
+
import { run as chatgptRun } from '../../lib/chatgpt/index.js';
|
|
7
|
+
|
|
8
|
+
// Mock node-fetch before importing chatgpt
|
|
9
|
+
vi.mock('node-fetch', () => ({
|
|
10
|
+
default: vi.fn(),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
// Mock Redis
|
|
14
|
+
vi.mock('../../services/redis/index.js', () => ({
|
|
15
|
+
getClient: vi.fn().mockResolvedValue({
|
|
16
|
+
get: vi.fn().mockResolvedValue(null),
|
|
17
|
+
setex: vi.fn().mockResolvedValue('OK'),
|
|
18
|
+
}),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
// Mock the prompt cache to avoid Redis dependencies
|
|
22
|
+
vi.mock('../../lib/prompt-cache/index.js', () => ({
|
|
23
|
+
get: vi.fn().mockResolvedValue({ result: null }),
|
|
24
|
+
set: vi.fn().mockResolvedValue('OK'),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
// Helper tokenizer
|
|
28
|
+
const tokenizer = (t) => t.split(' ');
|
|
29
|
+
|
|
30
|
+
describe('Global Override System', () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
// Reset models and overrides before each test
|
|
33
|
+
modelService.models = {};
|
|
34
|
+
modelService.clearGlobalOverride(); // Clear all overrides
|
|
35
|
+
modelService.bestPublicModelKey = 'fastGood';
|
|
36
|
+
|
|
37
|
+
// Setup basic models for testing
|
|
38
|
+
modelService.models = {
|
|
39
|
+
fastGood: new Model({
|
|
40
|
+
name: 'gpt-4-fast-good',
|
|
41
|
+
maxContextWindow: 128000,
|
|
42
|
+
maxOutputTokens: 16384,
|
|
43
|
+
requestTimeout: 1000,
|
|
44
|
+
apiUrl: 'https://api.openai.com',
|
|
45
|
+
apiKey: 'test-key',
|
|
46
|
+
endpoint: '/v1/chat/completions',
|
|
47
|
+
tokenizer,
|
|
48
|
+
}),
|
|
49
|
+
fastCheap: new Model({
|
|
50
|
+
name: 'gpt-4-fast-cheap',
|
|
51
|
+
maxContextWindow: 128000,
|
|
52
|
+
maxOutputTokens: 8192,
|
|
53
|
+
requestTimeout: 1000,
|
|
54
|
+
apiUrl: 'https://api.openai.com',
|
|
55
|
+
apiKey: 'test-key',
|
|
56
|
+
endpoint: '/v1/chat/completions',
|
|
57
|
+
tokenizer,
|
|
58
|
+
}),
|
|
59
|
+
fastCheapReasoning: new Model({
|
|
60
|
+
name: 'gpt-4-fast-cheap-reasoning',
|
|
61
|
+
maxContextWindow: 200000,
|
|
62
|
+
maxOutputTokens: 50000,
|
|
63
|
+
requestTimeout: 3000,
|
|
64
|
+
apiUrl: 'https://api.openai.com',
|
|
65
|
+
apiKey: 'reasoning-key',
|
|
66
|
+
endpoint: '/v1/chat/completions',
|
|
67
|
+
tokenizer,
|
|
68
|
+
}),
|
|
69
|
+
customModel: new Model({
|
|
70
|
+
name: 'custom-model-name',
|
|
71
|
+
maxContextWindow: 64000,
|
|
72
|
+
maxOutputTokens: 8192,
|
|
73
|
+
requestTimeout: 2000,
|
|
74
|
+
apiUrl: 'https://custom.api.com',
|
|
75
|
+
apiKey: 'custom-key',
|
|
76
|
+
endpoint: '/v1/completions',
|
|
77
|
+
tokenizer,
|
|
78
|
+
}),
|
|
79
|
+
expensiveReasoning: new Model({
|
|
80
|
+
name: 'gpt-4-reasoning',
|
|
81
|
+
maxContextWindow: 200000,
|
|
82
|
+
maxOutputTokens: 100000,
|
|
83
|
+
requestTimeout: 5000,
|
|
84
|
+
apiUrl: 'https://api.openai.com',
|
|
85
|
+
apiKey: 'reasoning-key',
|
|
86
|
+
endpoint: '/v1/chat/completions',
|
|
87
|
+
tokenizer,
|
|
88
|
+
}),
|
|
89
|
+
fastReasoning: new Model({
|
|
90
|
+
name: 'gpt-4-fast-reasoning',
|
|
91
|
+
maxContextWindow: 200000,
|
|
92
|
+
maxOutputTokens: 50000,
|
|
93
|
+
requestTimeout: 3000,
|
|
94
|
+
apiUrl: 'https://api.openai.com',
|
|
95
|
+
apiKey: 'reasoning-key',
|
|
96
|
+
endpoint: '/v1/chat/completions',
|
|
97
|
+
tokenizer,
|
|
98
|
+
}),
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Reset and setup fetch mock for each test
|
|
102
|
+
vi.clearAllMocks();
|
|
103
|
+
fetch.mockResolvedValue({
|
|
104
|
+
ok: true,
|
|
105
|
+
status: 200,
|
|
106
|
+
json: () =>
|
|
107
|
+
Promise.resolve({
|
|
108
|
+
choices: [{ message: { content: 'Test response' } }],
|
|
109
|
+
}),
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
afterEach(() => {
|
|
114
|
+
vi.clearAllMocks();
|
|
115
|
+
modelService.clearGlobalOverride(); // Clean up after each test
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('Global Override Management', () => {
|
|
119
|
+
it('should set and get global overrides', () => {
|
|
120
|
+
modelService.setGlobalOverride('modelName', 'customModel');
|
|
121
|
+
modelService.setGlobalOverride('temperature', 0.8);
|
|
122
|
+
|
|
123
|
+
expect(modelService.getGlobalOverride('modelName')).toBe('customModel');
|
|
124
|
+
expect(modelService.getGlobalOverride('temperature')).toBe(0.8);
|
|
125
|
+
expect(modelService.getGlobalOverride('maxTokens')).toBe(null);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should get all global overrides', () => {
|
|
129
|
+
modelService.setGlobalOverride('modelName', 'customModel');
|
|
130
|
+
modelService.setGlobalOverride('temperature', 0.8);
|
|
131
|
+
|
|
132
|
+
const allOverrides = modelService.getAllGlobalOverrides();
|
|
133
|
+
expect(allOverrides.modelName).toBe('customModel');
|
|
134
|
+
expect(allOverrides.temperature).toBe(0.8);
|
|
135
|
+
expect(allOverrides.maxTokens).toBe(null);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should clear specific global overrides', () => {
|
|
139
|
+
modelService.setGlobalOverride('modelName', 'customModel');
|
|
140
|
+
modelService.setGlobalOverride('temperature', 0.8);
|
|
141
|
+
|
|
142
|
+
modelService.clearGlobalOverride('modelName');
|
|
143
|
+
|
|
144
|
+
expect(modelService.getGlobalOverride('modelName')).toBe(null);
|
|
145
|
+
expect(modelService.getGlobalOverride('temperature')).toBe(0.8);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should clear all global overrides', () => {
|
|
149
|
+
modelService.setGlobalOverride('modelName', 'customModel');
|
|
150
|
+
modelService.setGlobalOverride('temperature', 0.8);
|
|
151
|
+
|
|
152
|
+
modelService.clearGlobalOverride();
|
|
153
|
+
|
|
154
|
+
expect(modelService.getGlobalOverride('modelName')).toBe(null);
|
|
155
|
+
expect(modelService.getGlobalOverride('temperature')).toBe(null);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should throw error for invalid override keys', () => {
|
|
159
|
+
expect(() => {
|
|
160
|
+
modelService.setGlobalOverride('invalidKey', 'value');
|
|
161
|
+
}).toThrow('Invalid override key: invalidKey');
|
|
162
|
+
|
|
163
|
+
expect(() => {
|
|
164
|
+
modelService.clearGlobalOverride('invalidKey');
|
|
165
|
+
}).toThrow('Invalid override key: invalidKey');
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('Model Name Override', () => {
|
|
170
|
+
it('should override model selection globally', async () => {
|
|
171
|
+
// Set global model override
|
|
172
|
+
modelService.setGlobalOverride('modelName', 'customModel');
|
|
173
|
+
|
|
174
|
+
const result = await chatgptRun('Test prompt', {
|
|
175
|
+
modelOptions: {
|
|
176
|
+
modelName: 'fastGood', // This should be overridden
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
expect(result).toBe('Test response');
|
|
181
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
182
|
+
'https://custom.api.com/v1/completions',
|
|
183
|
+
expect.objectContaining({
|
|
184
|
+
headers: {
|
|
185
|
+
Authorization: 'Bearer custom-key',
|
|
186
|
+
'Content-Type': 'application/json',
|
|
187
|
+
},
|
|
188
|
+
body: expect.stringContaining('"model":"custom-model-name"'),
|
|
189
|
+
})
|
|
190
|
+
);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should override even when no modelOptions provided', async () => {
|
|
194
|
+
modelService.setGlobalOverride('modelName', 'expensiveReasoning');
|
|
195
|
+
|
|
196
|
+
const result = await chatgptRun('Test prompt');
|
|
197
|
+
|
|
198
|
+
expect(result).toBe('Test response');
|
|
199
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
200
|
+
'https://api.openai.com/v1/chat/completions',
|
|
201
|
+
expect.objectContaining({
|
|
202
|
+
headers: {
|
|
203
|
+
Authorization: 'Bearer reasoning-key',
|
|
204
|
+
'Content-Type': 'application/json',
|
|
205
|
+
},
|
|
206
|
+
body: expect.stringContaining('"model":"gpt-4-reasoning"'),
|
|
207
|
+
})
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe('Negotiation Override', () => {
|
|
213
|
+
it('should override negotiation options globally', async () => {
|
|
214
|
+
modelService.setGlobalOverride('negotiate', { reasoning: true });
|
|
215
|
+
|
|
216
|
+
const result = await chatgptRun('Test prompt', {
|
|
217
|
+
modelOptions: {
|
|
218
|
+
modelName: 'fastGood',
|
|
219
|
+
negotiate: { fast: true, cheap: true }, // This should be overridden
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
expect(result).toBe('Test response');
|
|
224
|
+
// Should negotiate to reasoning model instead of fast+cheap
|
|
225
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
226
|
+
'https://api.openai.com/v1/chat/completions',
|
|
227
|
+
expect.objectContaining({
|
|
228
|
+
body: expect.stringContaining('"model":"gpt-4-fast-cheap-reasoning"'),
|
|
229
|
+
})
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should apply negotiation when none provided in options', async () => {
|
|
234
|
+
modelService.setGlobalOverride('negotiate', { fast: true, cheap: true });
|
|
235
|
+
|
|
236
|
+
const result = await chatgptRun('Test prompt', {
|
|
237
|
+
modelOptions: {
|
|
238
|
+
modelName: 'expensiveReasoning', // Should be overridden by negotiation
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
expect(result).toBe('Test response');
|
|
243
|
+
// Should negotiate instead of using explicit model
|
|
244
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
245
|
+
'https://api.openai.com/v1/chat/completions',
|
|
246
|
+
expect.objectContaining({
|
|
247
|
+
body: expect.stringContaining('"model":"gpt-4-fast-cheap"'),
|
|
248
|
+
})
|
|
249
|
+
);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
describe('Parameter Overrides', () => {
|
|
254
|
+
it('should override temperature globally', async () => {
|
|
255
|
+
modelService.setGlobalOverride('temperature', 0.9);
|
|
256
|
+
|
|
257
|
+
const result = await chatgptRun('Test prompt', {
|
|
258
|
+
modelOptions: {
|
|
259
|
+
modelName: 'fastGood',
|
|
260
|
+
temperature: 0.1, // This should be overridden
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
expect(result).toBe('Test response');
|
|
265
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
266
|
+
'https://api.openai.com/v1/chat/completions',
|
|
267
|
+
expect.objectContaining({
|
|
268
|
+
body: expect.stringContaining('"temperature":0.9'),
|
|
269
|
+
})
|
|
270
|
+
);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should override multiple parameters', async () => {
|
|
274
|
+
modelService.setGlobalOverride('temperature', 0.8);
|
|
275
|
+
modelService.setGlobalOverride('maxTokens', 1500);
|
|
276
|
+
modelService.setGlobalOverride('topP', 0.95);
|
|
277
|
+
|
|
278
|
+
const result = await chatgptRun('Test prompt', {
|
|
279
|
+
modelOptions: {
|
|
280
|
+
modelName: 'fastGood',
|
|
281
|
+
temperature: 0.1,
|
|
282
|
+
maxTokens: 500,
|
|
283
|
+
topP: 0.5,
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
expect(result).toBe('Test response');
|
|
288
|
+
|
|
289
|
+
const requestBody = JSON.parse(fetch.mock.calls[0][1].body);
|
|
290
|
+
expect(requestBody.temperature).toBe(0.8);
|
|
291
|
+
expect(requestBody.max_tokens).toBe(1500);
|
|
292
|
+
expect(requestBody.top_p).toBe(0.95);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('should preserve non-overridden parameters', async () => {
|
|
296
|
+
modelService.setGlobalOverride('temperature', 0.8);
|
|
297
|
+
|
|
298
|
+
const result = await chatgptRun('Test prompt', {
|
|
299
|
+
modelOptions: {
|
|
300
|
+
modelName: 'fastGood',
|
|
301
|
+
temperature: 0.1,
|
|
302
|
+
maxTokens: 2000,
|
|
303
|
+
topP: 0.7,
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
expect(result).toBe('Test response');
|
|
308
|
+
|
|
309
|
+
const requestBody = JSON.parse(fetch.mock.calls[0][1].body);
|
|
310
|
+
expect(requestBody.temperature).toBe(0.8); // Overridden
|
|
311
|
+
expect(requestBody.max_tokens).toBe(2000); // Preserved
|
|
312
|
+
expect(requestBody.top_p).toBe(0.7); // Preserved
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
describe('Complex Override Scenarios', () => {
|
|
317
|
+
it('should combine model and parameter overrides', async () => {
|
|
318
|
+
modelService.setGlobalOverride('modelName', 'customModel');
|
|
319
|
+
modelService.setGlobalOverride('temperature', 0.9);
|
|
320
|
+
|
|
321
|
+
const result = await chatgptRun('Test prompt', {
|
|
322
|
+
modelOptions: {
|
|
323
|
+
modelName: 'fastGood',
|
|
324
|
+
temperature: 0.1,
|
|
325
|
+
maxTokens: 1000,
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
expect(result).toBe('Test response');
|
|
330
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
331
|
+
'https://custom.api.com/v1/completions',
|
|
332
|
+
expect.objectContaining({
|
|
333
|
+
headers: {
|
|
334
|
+
Authorization: 'Bearer custom-key',
|
|
335
|
+
'Content-Type': 'application/json',
|
|
336
|
+
},
|
|
337
|
+
body: expect.stringContaining('"temperature":0.9'),
|
|
338
|
+
})
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
const requestBody = JSON.parse(fetch.mock.calls[0][1].body);
|
|
342
|
+
expect(requestBody.model).toBe('custom-model-name');
|
|
343
|
+
expect(requestBody.max_tokens).toBe(1000); // Preserved
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('should handle override precedence correctly', async () => {
|
|
347
|
+
// Set both model name and negotiation overrides
|
|
348
|
+
modelService.setGlobalOverride('modelName', 'customModel');
|
|
349
|
+
modelService.setGlobalOverride('negotiate', { reasoning: true });
|
|
350
|
+
|
|
351
|
+
const result = await chatgptRun('Test prompt', {
|
|
352
|
+
modelOptions: {
|
|
353
|
+
modelName: 'fastGood',
|
|
354
|
+
},
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
expect(result).toBe('Test response');
|
|
358
|
+
// Negotiation should take precedence and override the model name
|
|
359
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
360
|
+
'https://api.openai.com/v1/chat/completions',
|
|
361
|
+
expect.objectContaining({
|
|
362
|
+
body: expect.stringContaining('"model":"gpt-4-fast-cheap-reasoning"'),
|
|
363
|
+
})
|
|
364
|
+
);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('should work with empty modelOptions', async () => {
|
|
368
|
+
modelService.setGlobalOverride('modelName', 'customModel');
|
|
369
|
+
modelService.setGlobalOverride('temperature', 0.7);
|
|
370
|
+
|
|
371
|
+
const result = await chatgptRun('Test prompt');
|
|
372
|
+
|
|
373
|
+
expect(result).toBe('Test response');
|
|
374
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
375
|
+
'https://custom.api.com/v1/completions',
|
|
376
|
+
expect.objectContaining({
|
|
377
|
+
headers: {
|
|
378
|
+
Authorization: 'Bearer custom-key',
|
|
379
|
+
'Content-Type': 'application/json',
|
|
380
|
+
},
|
|
381
|
+
body: expect.stringContaining('"temperature":0.7'),
|
|
382
|
+
})
|
|
383
|
+
);
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
describe('Override Isolation', () => {
|
|
388
|
+
it('should not affect subsequent calls after clearing overrides', async () => {
|
|
389
|
+
// Set override and make a call
|
|
390
|
+
modelService.setGlobalOverride('modelName', 'customModel');
|
|
391
|
+
|
|
392
|
+
await chatgptRun('Test prompt 1');
|
|
393
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
394
|
+
'https://custom.api.com/v1/completions',
|
|
395
|
+
expect.anything()
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
// Clear override and make another call
|
|
399
|
+
modelService.clearGlobalOverride('modelName');
|
|
400
|
+
fetch.mockClear();
|
|
401
|
+
|
|
402
|
+
await chatgptRun('Test prompt 2');
|
|
403
|
+
expect(fetch).toHaveBeenCalledWith(
|
|
404
|
+
'https://api.openai.com/v1/chat/completions',
|
|
405
|
+
expect.anything()
|
|
406
|
+
);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it('should apply overrides consistently across multiple calls', async () => {
|
|
410
|
+
modelService.setGlobalOverride('temperature', 0.8);
|
|
411
|
+
|
|
412
|
+
// First call
|
|
413
|
+
await chatgptRun('Test prompt 1', {
|
|
414
|
+
modelOptions: { modelName: 'fastGood', temperature: 0.1 },
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
// Second call
|
|
418
|
+
await chatgptRun('Test prompt 2', {
|
|
419
|
+
modelOptions: { modelName: 'customModel', temperature: 0.2 },
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// Both calls should have temperature overridden to 0.8
|
|
423
|
+
expect(fetch).toHaveBeenCalledTimes(2);
|
|
424
|
+
|
|
425
|
+
const firstCall = JSON.parse(fetch.mock.calls[0][1].body);
|
|
426
|
+
const secondCall = JSON.parse(fetch.mock.calls[1][1].body);
|
|
427
|
+
|
|
428
|
+
expect(firstCall.temperature).toBe(0.8);
|
|
429
|
+
expect(secondCall.temperature).toBe(0.8);
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
});
|