@far-world-labs/verblets 0.1.1

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.
Files changed (167) hide show
  1. package/.eslintrc.json +42 -0
  2. package/.husky/pre-commit +4 -0
  3. package/.release-it.json +9 -0
  4. package/.vite.config.examples.js +8 -0
  5. package/.vite.config.js +8 -0
  6. package/docker-compose.yml +7 -0
  7. package/docs/README.md +41 -0
  8. package/docs/babel.config.js +3 -0
  9. package/docs/blog/2019-05-28-first-blog-post.md +12 -0
  10. package/docs/blog/2019-05-29-long-blog-post.md +44 -0
  11. package/docs/blog/2021-08-01-mdx-blog-post.mdx +20 -0
  12. package/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
  13. package/docs/blog/2021-08-26-welcome/index.md +25 -0
  14. package/docs/blog/authors.yml +17 -0
  15. package/docs/docs/api/bool.md +74 -0
  16. package/docs/docs/api/search.md +51 -0
  17. package/docs/docs/intro.md +47 -0
  18. package/docs/docs/tutorial-basics/_category_.json +8 -0
  19. package/docs/docs/tutorial-basics/congratulations.md +23 -0
  20. package/docs/docs/tutorial-basics/create-a-blog-post.md +34 -0
  21. package/docs/docs/tutorial-basics/create-a-document.md +57 -0
  22. package/docs/docs/tutorial-basics/create-a-page.md +43 -0
  23. package/docs/docs/tutorial-basics/deploy-your-site.md +31 -0
  24. package/docs/docs/tutorial-basics/markdown-features.mdx +152 -0
  25. package/docs/docs/tutorial-extras/_category_.json +7 -0
  26. package/docs/docs/tutorial-extras/img/docsVersionDropdown.png +0 -0
  27. package/docs/docs/tutorial-extras/img/localeDropdown.png +0 -0
  28. package/docs/docs/tutorial-extras/manage-docs-versions.md +55 -0
  29. package/docs/docs/tutorial-extras/translate-your-site.md +88 -0
  30. package/docs/docusaurus.config.js +120 -0
  31. package/docs/package.json +44 -0
  32. package/docs/sidebars.js +31 -0
  33. package/docs/src/components/HomepageFeatures/index.js +61 -0
  34. package/docs/src/components/HomepageFeatures/styles.module.css +11 -0
  35. package/docs/src/css/custom.css +30 -0
  36. package/docs/src/pages/index.js +43 -0
  37. package/docs/src/pages/index.module.css +23 -0
  38. package/docs/src/pages/markdown-page.md +7 -0
  39. package/docs/static/.nojekyll +0 -0
  40. package/docs/static/img/docusaurus-social-card.jpg +0 -0
  41. package/docs/static/img/docusaurus.png +0 -0
  42. package/docs/static/img/favicon.ico +0 -0
  43. package/docs/static/img/logo.svg +1 -0
  44. package/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
  45. package/docs/static/img/undraw_docusaurus_react.svg +170 -0
  46. package/docs/static/img/undraw_docusaurus_tree.svg +40 -0
  47. package/package.json +75 -0
  48. package/scripts/generate-chain/index.js +111 -0
  49. package/scripts/generate-lib/index.js +68 -0
  50. package/scripts/generate-test/index.js +111 -0
  51. package/scripts/generate-verblet/README.md +17 -0
  52. package/scripts/generate-verblet/index.js +110 -0
  53. package/scripts/run.sh +15 -0
  54. package/scripts/runner/index.js +30 -0
  55. package/scripts/simple-editor/README.md +34 -0
  56. package/scripts/simple-editor/index.js +68 -0
  57. package/scripts/summarize-files/index.js +46 -0
  58. package/src/chains/dismantle/dismantle.examples.js +0 -0
  59. package/src/chains/dismantle/index.examples.js +30 -0
  60. package/src/chains/dismantle/index.js +314 -0
  61. package/src/chains/dismantle/index.spec.js +33 -0
  62. package/src/chains/list/index.examples.js +72 -0
  63. package/src/chains/list/index.js +161 -0
  64. package/src/chains/list/index.spec.js +68 -0
  65. package/src/chains/list/schema.json +24 -0
  66. package/src/chains/questions/index.examples.js +68 -0
  67. package/src/chains/questions/index.js +136 -0
  68. package/src/chains/questions/index.spec.js +29 -0
  69. package/src/chains/scan-js/index.js +119 -0
  70. package/src/chains/sort/index.examples.js +40 -0
  71. package/src/chains/sort/index.js +113 -0
  72. package/src/chains/sort/index.spec.js +115 -0
  73. package/src/chains/summary-map/README.md +33 -0
  74. package/src/chains/summary-map/index.examples.js +57 -0
  75. package/src/chains/summary-map/index.js +208 -0
  76. package/src/chains/summary-map/index.spec.js +78 -0
  77. package/src/chains/test/index.js +118 -0
  78. package/src/chains/test-advice/index.js +36 -0
  79. package/src/constants/common.js +9 -0
  80. package/src/constants/messages.js +3 -0
  81. package/src/constants/openai.js +65 -0
  82. package/src/index.js +33 -0
  83. package/src/json-schemas/cars-test.json +11 -0
  84. package/src/json-schemas/index.js +18 -0
  85. package/src/json-schemas/intent.json +38 -0
  86. package/src/json-schemas/schema-dot-org-photograph.json +127 -0
  87. package/src/json-schemas/schema-dot-org-place.json +56 -0
  88. package/src/lib/any-signal/index.js +28 -0
  89. package/src/lib/chatgpt/index.js +143 -0
  90. package/src/lib/editor/index.js +31 -0
  91. package/src/lib/parse-js-parts/index.js +333 -0
  92. package/src/lib/parse-js-parts/index.spec.js +156 -0
  93. package/src/lib/path-aliases/index.js +39 -0
  94. package/src/lib/path-aliases/index.spec.js +70 -0
  95. package/src/lib/pave/index.js +34 -0
  96. package/src/lib/pave/index.spec.js +73 -0
  97. package/src/lib/prompt-cache/index.js +46 -0
  98. package/src/lib/retry/index.js +63 -0
  99. package/src/lib/retry/index.spec.js +86 -0
  100. package/src/lib/search-best-first/index.js +66 -0
  101. package/src/lib/search-js-files/code-features-property-definitions.json +123 -0
  102. package/src/lib/search-js-files/index.examples.js +22 -0
  103. package/src/lib/search-js-files/index.js +158 -0
  104. package/src/lib/search-js-files/index.spec.js +34 -0
  105. package/src/lib/search-js-files/scan-file.js +253 -0
  106. package/src/lib/shorten-text/index.js +30 -0
  107. package/src/lib/shorten-text/index.spec.js +68 -0
  108. package/src/lib/strip-numeric/index.js +5 -0
  109. package/src/lib/strip-response/index.js +35 -0
  110. package/src/lib/timed-abort-controller/index.js +41 -0
  111. package/src/lib/to-bool/index.js +8 -0
  112. package/src/lib/to-enum/index.js +14 -0
  113. package/src/lib/to-number/index.js +12 -0
  114. package/src/lib/to-number-with-units/index.js +51 -0
  115. package/src/lib/transcribe/index.js +61 -0
  116. package/src/prompts/README.md +15 -0
  117. package/src/prompts/as-enum.js +5 -0
  118. package/src/prompts/as-json-schema.js +9 -0
  119. package/src/prompts/as-object-with-schema.js +31 -0
  120. package/src/prompts/as-schema-org-text.js +17 -0
  121. package/src/prompts/as-schema-org-type.js +1 -0
  122. package/src/prompts/blog-post.js +7 -0
  123. package/src/prompts/code-features.js +28 -0
  124. package/src/prompts/constants.js +101 -0
  125. package/src/prompts/features-json-schema.js +27 -0
  126. package/src/prompts/generate-collection.js +26 -0
  127. package/src/prompts/generate-list.js +48 -0
  128. package/src/prompts/generate-questions.js +19 -0
  129. package/src/prompts/index.js +20 -0
  130. package/src/prompts/intent.js +66 -0
  131. package/src/prompts/output-succinct-names.js +3 -0
  132. package/src/prompts/select-from-threshold.js +18 -0
  133. package/src/prompts/sort.js +35 -0
  134. package/src/prompts/style.js +41 -0
  135. package/src/prompts/summarize.js +13 -0
  136. package/src/prompts/token-budget.js +3 -0
  137. package/src/prompts/wrap-list.js +14 -0
  138. package/src/prompts/wrap-variable.js +36 -0
  139. package/src/services/llm-model/index.js +114 -0
  140. package/src/services/llm-model/model.js +21 -0
  141. package/src/services/redis/index.js +84 -0
  142. package/src/verblets/auto/index.examples.js +28 -0
  143. package/src/verblets/auto/index.js +28 -0
  144. package/src/verblets/auto/index.spec.js +34 -0
  145. package/src/verblets/bool/index.examples.js +28 -0
  146. package/src/verblets/bool/index.js +28 -0
  147. package/src/verblets/bool/index.schema.json +14 -0
  148. package/src/verblets/bool/index.spec.js +35 -0
  149. package/src/verblets/enum/index.examples.js +33 -0
  150. package/src/verblets/enum/index.js +15 -0
  151. package/src/verblets/enum/index.spec.js +35 -0
  152. package/src/verblets/intent/index.examples.js +51 -0
  153. package/src/verblets/intent/index.js +72 -0
  154. package/src/verblets/intent/index.spec.js +31 -0
  155. package/src/verblets/number/index.examples.js +33 -0
  156. package/src/verblets/number/index.js +22 -0
  157. package/src/verblets/number/index.spec.js +35 -0
  158. package/src/verblets/number-with-units/index.examples.js +34 -0
  159. package/src/verblets/number-with-units/index.js +19 -0
  160. package/src/verblets/number-with-units/index.spec.js +46 -0
  161. package/src/verblets/schema-org/index.examples.js +56 -0
  162. package/src/verblets/schema-org/index.js +8 -0
  163. package/src/verblets/schema-org/index.spec.js +39 -0
  164. package/src/verblets/to-object/README.md +38 -0
  165. package/src/verblets/to-object/index.examples.js +29 -0
  166. package/src/verblets/to-object/index.js +136 -0
  167. package/src/verblets/to-object/index.spec.js +74 -0
@@ -0,0 +1,28 @@
1
+ import {
2
+ asJSON,
3
+ explainAndSeparate,
4
+ explainAndSeparateJSON,
5
+ } from './constants.js';
6
+
7
+ export default ({ text, schema }) => {
8
+ return `Analyze the following code to provide scores for each of the features described below.
9
+
10
+ For each feature, assign a score between 0.0 and 1.0 based on the criteria outlined in the description. If the code does not exhibit the feature, provide a score of 0.0.
11
+
12
+ Ensure that all scores are assigned as numeric decimal values, even if the feature is not applicable or not present in the code.
13
+
14
+ Include only the properties defined in the schema, no comment, description, summary, evaluation or any similar properties.
15
+
16
+ <json-schema defines-output output-shape>
17
+ ${JSON.stringify(schema, null, 2)}
18
+ </json-schema>
19
+
20
+ <code-to-analyze do-not-output>
21
+ ${text}
22
+ </code-to-analyze>
23
+
24
+ ${asJSON}
25
+
26
+ ${explainAndSeparate} ${explainAndSeparateJSON}
27
+ `;
28
+ };
@@ -0,0 +1,101 @@
1
+ // Basic
2
+ export const asUndefinedByDefault =
3
+ 'If you are unsure, say "undefined" as your answer.';
4
+ export const asBool = `Answer the question either with "true" or "false" as your answer.`;
5
+ export const asNumber = `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 asJSON = `Respond with a JSON object or array that parses with JSON.parse, with no wrapping code block, and no wrapping XML.`;
7
+
8
+ // Response steering
9
+ export const useLineNumber =
10
+ 'Include the line number where each check is performed.';
11
+ export const noFalseInformation = 'Do not include false information.';
12
+ 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
+
16
+ // JSON Output
17
+ export const onlyJSON =
18
+ 'Respond with a JSON object or array that parses with JSON.parse, with no other text and no code block.';
19
+ const onlyJSONArrayBase =
20
+ 'Respond with a JSON array that parses with JSON.parse, with no additional text, no punctuation, and no code block.';
21
+ export const onlyJSONArray = onlyJSONArrayBase;
22
+ export const onlyJSONStringArray = `${onlyJSONArrayBase} The array should only contain text. No additional structure.`;
23
+ export const onlyJSONObjectArray =
24
+ 'Return an array of obects--not strings, and not just the objects.';
25
+ export const onlyJSONStringArrayAlt1 = 'Output an JSON array of strings.';
26
+ export const asSplitIntoJSONArray = 'Split the following to a JSON array.';
27
+ export const onlyFullCode =
28
+ 'Output only the full code generated, with no other text and no code block.';
29
+ export const asNumberWithUnits = `${onlyJSON} It should take the form "{ "value": 42, "unit": "<SI or other unit name>" }".`;
30
+ export const shapeAsJSON =
31
+ 'Even if the input is not JSON, describe as much as possible in a JSON structure that corresponds to the input.';
32
+
33
+ // Content headers
34
+ export const contentIsQuestion = 'Question:';
35
+ export const contentIsInstructions = 'Instructions:';
36
+ export const contentIsDetails = 'Details:';
37
+ export const contentIsFixes = 'Fixes:';
38
+ export const contentIsMain = 'Focus all efforts on this content here:';
39
+ export const contentToJSON = 'Contents to convert to JSON:';
40
+ export const contentIsExample = 'Use this as example output only:';
41
+ export const contentIsChoices = 'Choose only from the following:';
42
+ export const contentIsTransformationSource = 'Transform the following object:';
43
+ export const contentListCriteria =
44
+ 'Create a list of items with the following description:';
45
+ export const contentListItemCriteria =
46
+ 'Make sure each item meets the following conditions:';
47
+ export const contentListToOmit = 'Do not use any of the following items:';
48
+ export const contentIsExampleObject =
49
+ '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:';
52
+ export const contentHasIntent = 'What is the intent of the following message:';
53
+ export const contentIsSortCriteria = 'Sort the following items by:';
54
+
55
+ // Give explanation
56
+ export const explainAndSeparate =
57
+ '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
+ export const explainAndSeparateJSON =
59
+ 'The content below the dividing line should only be valid JSON that can be parsed with JSON.parse.';
60
+ export const explainAndSeparatePrimitive = `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
+
62
+ // Reflective
63
+ export const thinkStepByStep = `Let's think step by step`;
64
+ export const identifyUnclearInfo =
65
+ 'Identify any unclear or ambiguous information in your response, and rephrase it for clarity.';
66
+ export const argueAgainstOutput =
67
+ 'Try to argue against your own output and see if you can find any flaws. If so, address them. Walk me through the process';
68
+ export const rateBasic =
69
+ 'Rate on a scale in the decimal from 0-1 how the content satisfies the following criteria. Be candidly critical and strict in your assessment.';
70
+ export const rateSatisfaction =
71
+ 'Rate on a scale in the decimal from 0-1 how well you satisfied each point in the initial prompt. Be very critical, no need to justify yourself.';
72
+ export const rewriteBasedOnRating = 'If 0.3 or lower, rewrite to address.';
73
+ export const requestAdditionalInput =
74
+ 'What additional input do you need from me to help you write better output?';
75
+ export const summarizeRequest =
76
+ 'Please summarise what I am asking for you before you begin your answer.';
77
+
78
+ // Analytical
79
+ export const considerProsCons =
80
+ 'Consider both pros and cons before arriving at a conclusion.';
81
+ export const provideExamples =
82
+ 'Provide specific examples to illustrate your point.';
83
+ export const explainReasoning = 'Explain the reasoning behind your answer.';
84
+ export const alternativeSolutions =
85
+ 'If there are any alternative solutions or perspectives, please share them.';
86
+ export const explainToChild = 'How would you explain this topic to a child?';
87
+ export const identifyAssumptions = 'What assumptions are you making?';
88
+ export const alternativeInterpretations = 'How else could this be interpreted?';
89
+
90
+ // Evidence-Based
91
+ export const evidenceSupportsView = 'What evidence supports your view?';
92
+ export const expertResponse = 'How would an expert in this field respond?';
93
+ export const limitationsOfApproach =
94
+ 'What are the limitations of your approach?';
95
+ export const missingInformation = 'What information is still missing?';
96
+ export const evaluateDifferingViews = 'How would you evaluate differing views?';
97
+ export const confidenceInResponse = 'How confident are you in your response?';
98
+ export const lessKnowledgeResponse =
99
+ 'How would you answer this if you knew less about the topic?';
100
+ export const analogyForUnderstanding =
101
+ 'Come up with an analogy to make this easier to understand.';
@@ -0,0 +1,27 @@
1
+ const makeFeatureDefinition = ({ name, criteria, score0, score1 }) => {
2
+ const descriptionPrompt = `criteria: "${criteria}", scoring: "${score0} ${score1}"`;
3
+
4
+ return {
5
+ [name]: {
6
+ type: 'number',
7
+ minimum: 0,
8
+ maximum: 1,
9
+ description: descriptionPrompt,
10
+ },
11
+ };
12
+ };
13
+
14
+ export default (features) => {
15
+ if (!features?.length) {
16
+ throw new Error('Features json schema [error]: Features list not defined');
17
+ }
18
+
19
+ return {
20
+ $schema: 'http://json-schema.org/draft-07/schema#',
21
+ type: 'object',
22
+ properties: features.reduce((acc, feature) => {
23
+ return { ...acc, ...makeFeatureDefinition(feature) };
24
+ }, {}),
25
+ required: features.map((f) => f.name),
26
+ };
27
+ };
@@ -0,0 +1,26 @@
1
+ import {
2
+ onlyJSON,
3
+ onlyJSONObjectArray,
4
+ contentListItemCriteria,
5
+ tryCompleteData,
6
+ } from './constants.js';
7
+ import asObjectWithSchema from './as-object-with-schema.js';
8
+
9
+ const schemaDefault = {
10
+ type: 'object',
11
+ properties: {
12
+ name: {
13
+ type: 'string',
14
+ },
15
+ },
16
+ };
17
+
18
+ export default (text, { schema = schemaDefault } = {}) => {
19
+ return `Make an array of "${text}" objects.
20
+
21
+ ${contentListItemCriteria}
22
+ - ${asObjectWithSchema(schema)}
23
+ - ${tryCompleteData}
24
+
25
+ ${onlyJSON} ${onlyJSONObjectArray}`;
26
+ };
@@ -0,0 +1,48 @@
1
+ import {
2
+ contentIsDetails,
3
+ contentListCriteria,
4
+ contentListItemCriteria,
5
+ contentListToOmit,
6
+ onlyJSONStringArray,
7
+ } from './constants.js';
8
+ import wrapVariable from './wrap-variable.js';
9
+
10
+ const instruction = 'Please continue building the list.';
11
+
12
+ const targetNewItemsCountDefault = 10;
13
+
14
+ export default (
15
+ description,
16
+ {
17
+ existing = [],
18
+ attachments = {},
19
+ fixes = '',
20
+ targetNewItemsCount = targetNewItemsCountDefault,
21
+ } = {}
22
+ ) => {
23
+ const existingJoined = JSON.stringify(existing, null, 2);
24
+
25
+ const attachmentsJoined = Object.entries(attachments).map(([key, value]) => {
26
+ return `${wrapVariable(value, { tag: 'reference-material', name: key })}
27
+ `;
28
+ });
29
+
30
+ return `${onlyJSONStringArray}
31
+ ${contentListCriteria} ${wrapVariable(description, { tag: 'criteria' })}
32
+
33
+ ${attachmentsJoined}
34
+
35
+ ${contentListToOmit} ${wrapVariable(existingJoined, { tag: 'omitted' })}
36
+
37
+ ${instruction}
38
+ You must return least ${targetNewItemsCount} unless the items are thoroughly exhausted.
39
+
40
+ ${contentListItemCriteria}
41
+ - Meet the description criteria
42
+ - Not already in the list
43
+ - Not a duplicate or a variant of an existing item
44
+
45
+ ${contentIsDetails} ${wrapVariable(fixes, { tag: 'fixes' })}
46
+
47
+ ${onlyJSONStringArray}`;
48
+ };
@@ -0,0 +1,19 @@
1
+ import {
2
+ contentIsQuestion,
3
+ contentListToOmit,
4
+ expertResponse,
5
+ onlyJSONStringArrayAlt1,
6
+ } from './constants.js';
7
+ import wrapVariable from './wrap-variable.js';
8
+
9
+ export default (text, { existing = [] } = {}) => {
10
+ const existingJoined = existing.map((item) => `"${item}"`).join(', ');
11
+
12
+ return `Instead of answering the following question, I would like you to generate additional questions. Consider interesting perspectives. Consider what information is unknown. ${expertResponse}. Overall, just come up with good questions.
13
+
14
+ ${contentIsQuestion} ${text}
15
+
16
+ ${contentListToOmit} ${wrapVariable(existingJoined, { tag: 'omitted' })}
17
+
18
+ ${onlyJSONStringArrayAlt1} One question per string.`;
19
+ };
@@ -0,0 +1,20 @@
1
+ export * as constants from './constants.js';
2
+
3
+ export { default as asEnum } from './as-enum.js';
4
+ export { default as asJSONSchema } from './as-json-schema.js';
5
+ export { default as asObjectWithSchema } from './as-object-with-schema.js';
6
+ export { default as asSchemaOrgText } from './as-schema-org-text.js';
7
+ export { default as asSchemaOrgType } from './as-schema-org-type.js';
8
+ export { default as blogPost } from './blog-post.js';
9
+ export { default as generateCollection } from './generate-collection.js';
10
+ export { default as generateList } from './generate-list.js';
11
+ export { default as generateQuestions } from './generate-questions.js';
12
+ export { default as intent } from './intent.js';
13
+ export { default as selectFromThreshold } from './select-from-threshold.js';
14
+ export { default as outputSuccinctNames } from './output-succinct-names.js';
15
+ export { default as wrapVariable } from './wrap-variable.js';
16
+ export { default as sort } from './sort.js';
17
+ export { default as style } from './style.js';
18
+ export { default as tokenBudget } from './token-budget.js';
19
+ export { default as summarize } from './summarize.js';
20
+ export { default as wrapList } from './wrap-list.js';
@@ -0,0 +1,66 @@
1
+ import fs from 'node:fs/promises';
2
+
3
+ import { contentIsExample, contentIsSchema, onlyJSON } from './constants.js';
4
+ import wrapVariable from './wrap-variable.js';
5
+
6
+ const contentIsIntent = 'Give me an intent response for the following:';
7
+ const contentIsOperationOption =
8
+ 'The extracted operation must be one of the following:';
9
+ const contentIsParametersOptions =
10
+ 'The extracted perameters must be from the following options:';
11
+
12
+ const exampleJSON = `{
13
+ "queryText": "play some music",
14
+ "intent": {
15
+ "operation": "play-music",
16
+ "displayName": "Play Music"
17
+ },
18
+ "parameters": {
19
+ "genre": "rock"
20
+ },
21
+ "optionalParameters": {
22
+ "artist": "The Beatles"
23
+ }
24
+ }`;
25
+
26
+ const intentSchema = JSON.parse(
27
+ await fs.readFile('./src/json-schemas/intent.json')
28
+ );
29
+
30
+ /**
31
+ * Approximates intent recognition like you might find with Wit.ai,
32
+ * for tasks where you want the model to extract the intent and parameters
33
+ * so an existing function can compute the result.
34
+ */
35
+ export default (text, { operations = [], parameters = [] } = {}) => {
36
+ let operationsSection = '';
37
+ if (operations.length) {
38
+ operationsSection = `\n${contentIsOperationOption} ${operations.join(
39
+ ', '
40
+ )}\n`;
41
+ }
42
+ let parametersSection = '';
43
+ if (parameters.length) {
44
+ parametersSection = `\n${contentIsParametersOptions} ${parameters.join(
45
+ ', '
46
+ )}\n`;
47
+ }
48
+
49
+ return `
50
+ ${contentIsIntent} ${wrapVariable(text ?? 'None given', { tag: 'input' })}
51
+
52
+ ${contentIsSchema} ${wrapVariable(intentSchema ?? 'None given', {
53
+ tag: 'schema',
54
+ })}
55
+
56
+ ${contentIsExample} ${wrapVariable(exampleJSON ?? 'None given', {
57
+ tag: 'example',
58
+ })}
59
+ ${operationsSection ?? ''}${parametersSection ?? ''}
60
+ Ensure the result is sufficiently abstract.
61
+ Include the full list of supplied parameters.
62
+ Don't include optional parameters under "parameters" unless they were found when the intent was parsed.
63
+
64
+ ${onlyJSON}
65
+ `;
66
+ };
@@ -0,0 +1,3 @@
1
+ export default (numWords = 10) => {
2
+ return `Provide a (<${numWords} words) descriptive name for each result.`;
3
+ };
@@ -0,0 +1,18 @@
1
+ import * as R from 'ramda';
2
+
3
+ // Returns a modifier function that generates a prompt fragment based on a given value
4
+ /*
5
+ * let openEndedDegree = findDegreeModifier(openEnded, [
6
+ * { threshold: 0.2, degree: 'must not be' },
7
+ * { threshold: 0.4, degree: 'must be minimally' },
8
+ * { threshold: 0.6, degree: 'must be somewhat' },
9
+ * { threshold: 0.8, degree: 'must be very' },
10
+ * { threshold: 1.0, degree: 'must be extremely' },
11
+ * ]);
12
+ * const openEndedPrompt = `Questions ${openEndedDegree} open-ended. `
13
+ */
14
+ export default (value, thresholds = []) => {
15
+ const threshold =
16
+ thresholds.find((t) => value <= t.threshold) || R.last(thresholds);
17
+ return threshold.degree;
18
+ };
@@ -0,0 +1,35 @@
1
+ import wrapVariable from './wrap-variable.js';
2
+ import {
3
+ contentIsSortCriteria,
4
+ contentIsMain,
5
+ contentIsFixes,
6
+ contentIsDetails,
7
+ onlyJSONStringArray,
8
+ } from './constants.js';
9
+
10
+ export const defaultSortDescription = 'alphabetical order';
11
+ export const defaultFixes = 'Ignore duplicates in the list';
12
+ export const defaultSortOrder = 'descending';
13
+
14
+ export default (
15
+ {
16
+ description = defaultSortDescription,
17
+ fixes = defaultFixes,
18
+ sortOrder = defaultSortOrder,
19
+ },
20
+ list
21
+ ) => {
22
+ const listLines = JSON.stringify(list, undefined, 2);
23
+
24
+ return `${contentIsSortCriteria} ${wrapVariable(description, {
25
+ tag: 'criteria',
26
+ })}
27
+
28
+ ${contentIsMain} ${wrapVariable(listLines, { tag: 'main-content' })}
29
+
30
+ ${contentIsDetails} ${sortOrder} order
31
+
32
+ ${contentIsFixes} ${wrapVariable(fixes, { tag: 'fixes' })}
33
+
34
+ ${onlyJSONStringArray}`;
35
+ };
@@ -0,0 +1,41 @@
1
+ export default (
2
+ text,
3
+ {
4
+ tone = ['informal'],
5
+ vocabulary = ['software engineering'],
6
+ sentenceStructure = ['varied sentence length', 'active voice'],
7
+ pointOfView = ['first person plural'],
8
+ noise = 0,
9
+ minWords = 0,
10
+ maxWords,
11
+ } = {}
12
+ ) => {
13
+ const toneModifiers = `Tone: ${tone.join(', ')}`;
14
+ const vocabularyModifiers = `Vocabulary: ${vocabulary.join(', ')}`;
15
+ const sentenceStructureModifiers = `Sentence structure: ${sentenceStructure.join(
16
+ ', '
17
+ )}`;
18
+ const pointOfViewModifiers = `Point of view: ${pointOfView.join(', ')}`;
19
+ const lengthModifier = `Use between ${minWords} and ${
20
+ maxWords ?? 'any number'
21
+ } of words`;
22
+
23
+ let noiseModifier = '';
24
+ if (noise > 0.5) {
25
+ noiseModifier = `Completely reshape the ideas here, don't stick with the original structure. Don't change the meaning of the content though.`;
26
+ }
27
+
28
+ return `Rewrite the following content:
29
+ \`\`\`
30
+ ${text}
31
+ \`\`\`
32
+
33
+ Use the following style:
34
+ ${toneModifiers}
35
+ ${vocabularyModifiers}
36
+ ${sentenceStructureModifiers}
37
+ ${pointOfViewModifiers}
38
+ ${lengthModifier}
39
+ ${noiseModifier}
40
+ `;
41
+ };
@@ -0,0 +1,13 @@
1
+ import wrapVariable from './wrap-variable.js';
2
+ import { onlyFullCode } from './constants.js';
3
+
4
+ export default (text, instructions = '') => {
5
+ return `Summarize the following content. ${onlyFullCode}
6
+
7
+ ${wrapVariable(instructions, {
8
+ forceHTML: true,
9
+ tag: 'summarization-instructions',
10
+ })}
11
+
12
+ ${wrapVariable(text, { forceHTML: true, tag: 'content-to-summarize' })}`;
13
+ };
@@ -0,0 +1,3 @@
1
+ export default (budget = 10) => {
2
+ return `Keep the output within ${budget} tokens.`;
3
+ };
@@ -0,0 +1,14 @@
1
+ import wrapVariable from './wrap-variable.js';
2
+
3
+ export default (
4
+ list = [],
5
+ { introText = 'Consider the following items:' } = {}
6
+ ) => {
7
+ const listText = list.map((f, i) => ` - ${i + 1}. ${f}`).join('\n');
8
+
9
+ let listFragment = wrapVariable('\n');
10
+ if (list.length) {
11
+ listFragment = `${introText} ${wrapVariable(listText)}`;
12
+ }
13
+ return listFragment;
14
+ };
@@ -0,0 +1,36 @@
1
+ export default (
2
+ variable,
3
+ { forceHTML = false, name, tag = 'data', title, fit = 'comfortable' } = {}
4
+ ) => {
5
+ if (!variable) {
6
+ return '';
7
+ }
8
+
9
+ let nameAttribute = '';
10
+ if (name) {
11
+ nameAttribute = `name="${name}"`;
12
+ }
13
+
14
+ let variableResolved = typeof variable !== 'undefined' ? variable : '';
15
+ if (typeof variable !== 'string') {
16
+ variableResolved = JSON.stringify(variable, null, 2);
17
+ }
18
+
19
+ const isHTML = /\n/.test(variableResolved) || forceHTML || name;
20
+ let variableWrapped = !isHTML ? `"${variableResolved}"` : variableResolved;
21
+ if (isHTML) {
22
+ let fitChar = '\n';
23
+ if (fit !== 'comfortable') {
24
+ fitChar = '';
25
+ }
26
+
27
+ variableWrapped = `<${tag}${nameAttribute}>${fitChar}${variableResolved}${fitChar}</${tag}>`;
28
+ }
29
+
30
+ let titlePrefixed = variableWrapped;
31
+ if (title && variableResolved.length > 0) {
32
+ titlePrefixed = `${title} ${variableWrapped}`;
33
+ }
34
+
35
+ return titlePrefixed;
36
+ };
@@ -0,0 +1,114 @@
1
+ import { camelCase, camelCaseTransformMerge } from 'change-case';
2
+ import * as tokenizer from 'gpt-tokenizer';
3
+
4
+ import Model from './model.js';
5
+ import {
6
+ frequencyPenalty as frequencyPenaltyConfig,
7
+ models,
8
+ presencePenalty as presencePenaltyConfig,
9
+ temperature as temperatureConfig,
10
+ topP as topPConfig,
11
+ } from '../../constants/openai.js';
12
+
13
+ class ModelService {
14
+ constructor() {
15
+ this.models = {};
16
+ this.models = Object.entries(models).reduce(
17
+ (acc, [key, modelDef]) => ({
18
+ ...acc,
19
+ [key]:
20
+ new Model({
21
+ ...modelDef,
22
+ tokenizer: tokenizer.encode,
23
+ }),
24
+ }),
25
+ {}
26
+ );
27
+
28
+ this.bestAvailableModel = this.models.gpt4 ?? this.models.gpt35Turbo;
29
+ if (process.env.TEST === 'true') {
30
+ // this.bestAvailableModel = this.models.textDavinci003;
31
+ this.bestAvailableModel = this.models.gpt35Turbo;
32
+ }
33
+ }
34
+
35
+ getBestAvailableModel() {
36
+ return this.bestAvailableModel;
37
+ }
38
+
39
+ updateBestAvailableModel(name) {
40
+ this.bestAvailableModel = this.getModel(name);
41
+ }
42
+
43
+ getModel(name) {
44
+ let modelFound = this.getBestAvailableModel();
45
+ if (name && process.env.TEST !== 'true') {
46
+ modelFound = this.models[name];
47
+ if (!modelFound) {
48
+ throw new Error(`Get model by name [error]: '${name}' not found.`);
49
+ }
50
+ }
51
+ return modelFound;
52
+ }
53
+
54
+ getRequestParameters(options = {}) {
55
+ const frequencyPenalty = options.frequencyPenalty ?? frequencyPenaltyConfig;
56
+ const presencePenalty = options.presencePenalty ?? presencePenaltyConfig;
57
+ const temperature = options.temperature ?? temperatureConfig;
58
+ const topP = options.topP ?? topPConfig;
59
+ const { maxTokens, modelName, prompt } = options;
60
+
61
+ const modelFound = this.getModel(modelName);
62
+
63
+ let maxTokensFound = maxTokens;
64
+ if (!maxTokens) {
65
+ maxTokensFound = modelFound.maxTokens - modelFound.toTokens(prompt);
66
+ }
67
+
68
+ return {
69
+ model: modelFound.name,
70
+ temperature,
71
+ max_tokens: maxTokensFound,
72
+ top_p: topP,
73
+ frequency_penalty: frequencyPenalty,
74
+ presence_penalty: presencePenalty,
75
+ };
76
+ }
77
+
78
+ getRequestConfig(options) {
79
+ const {
80
+ tools,
81
+ toolChoice,
82
+ modelName,
83
+ prompt,
84
+ systemPrompt,
85
+ } = options;
86
+
87
+ const modelFound = this.getModel(modelName);
88
+
89
+ let requestPrompt = { prompt: prompt };
90
+ if (/chat/.test(modelFound.endpoint)) {
91
+ const userMessage = { role: 'user', content: prompt };
92
+ const systemMessages = systemPrompt ? [{
93
+ role: 'system',
94
+ content: systemPrompt,
95
+ }] : [];
96
+ requestPrompt = {
97
+ messages: [
98
+ ...systemMessages,
99
+ userMessage
100
+ ],
101
+ tools,
102
+ tool_choice: (tools && !toolChoice) ? 'auto' : toolChoice,
103
+ };
104
+ }
105
+ const data = this.getRequestParameters(options);
106
+
107
+ return {
108
+ ...requestPrompt,
109
+ ...data,
110
+ };
111
+ }
112
+ }
113
+
114
+ export default new ModelService();
@@ -0,0 +1,21 @@
1
+ export default class Model {
2
+ constructor(options) {
3
+ Object.assign(this, options);
4
+ }
5
+
6
+ toTokens(text) {
7
+ return this.tokenizer(text);
8
+ }
9
+
10
+ budgetTokens(text, { completionMax = Infinity } = {}) {
11
+ const prompt = this.toTokens(text).length;
12
+ const total = this.maxTokens;
13
+ const completion = Math.min(total - prompt, completionMax);
14
+
15
+ return {
16
+ completion,
17
+ prompt,
18
+ total,
19
+ };
20
+ }
21
+ }