diff --git a/examples/facts.ts b/examples/facts.ts index 7c2b233e..e5cadb62 100644 --- a/examples/facts.ts +++ b/examples/facts.ts @@ -2,7 +2,7 @@ import dotenv from 'dotenv-safe' import { OpenAIClient } from 'openai-fetch' import { z } from 'zod' -import { Agentic } from './../src/llm' +import { Agentic } from '../src' dotenv.config() @@ -11,46 +11,48 @@ async function main() { const ai = new Agentic({ openai }) const out = await ai - .gpt4(`I need random facts about {{topic}}`) + .gpt4(`Give me random facts about {{topic}}`) .output(z.array(z.string())) .input(z.object({ topic: z.string() })) .modelParams({ temperature: 0.9 }) .call({ topic: 'cats' }) + console.log(out) + /* - Example output: - [ - 'The scientific name for the domestic cat is Felis catus.', - 'Cats spend 70% of their lives sleeping.', - 'A group of cats is called a clowder.', - 'Cats have over 100 different vocal sounds.', - 'A cat’s nose pad is ridged with a unique pattern, just like a human fingerprint.', - 'Cats can jump up to six times their length.', - 'Cats can make over 20 different sounds.', - 'Cats have five toes on each front paw, but only four toes on each back paw.', - 'A cat’s whiskers are highly sensitive and can detect changes in air currents.', - 'Cats have a flexible spine and can rotate their ears 180 degrees.', - 'Cats can run up to 30 miles per hour.', - 'Cats are believed to be the only mammals who don’t taste sweetness.', - 'Cats have excellent night vision and can see at one-sixth the light level required for human vision.', - 'Cats can’t see directly under their nose.', - 'Cats can make more than 100 different sounds.', - 'A cat can travel at a top speed of approximately 31 mph (49 km) over a short distance.', - 'Cats are capable of walking very precisely. When they take a step, they place their back paw almost exactly in the same place as their front paw was – this is called ‘direct registering’.', - 'A cat’s hearing is much more sensitive than humans and dogs.', - 'Cats have been domesticated for around 4,000 years.', - 'Cats use their tails to maintain balance and communicate their mood.', - 'A cat’s brain is biologically more similar to a human brain than it is to a dog’s.', - 'Cats conserve energy by sleeping for an average of 13 to 14 hours a day.', - 'A cat has a total of 24 whiskers – 4 first-order, 8 second-order, and 12 third-order.', - 'Cats can pick up on changes in the weather, which can indicate to them that a storm is coming.', - 'Cats have an acute sense of hearing and can detect an ultra-sonic range of sounds up to two octaves higher than humans.', - 'Cats can learn to manipulate humans with their meows.', - 'Cats have 32 muscles in each ear.', - 'The average lifespan of an indoor cat is 13 to 17 years.', - 'Cats are one of the most popular pets in the world, and there are more than 500 million domestic cats in existence.' - ] - */ + Example output: + [ + 'The scientific name for the domestic cat is Felis catus.', + 'Cats spend 70% of their lives sleeping.', + 'A group of cats is called a clowder.', + 'Cats have over 100 different vocal sounds.', + 'A cat’s nose pad is ridged with a unique pattern, just like a human fingerprint.', + 'Cats can jump up to six times their length.', + 'Cats can make over 20 different sounds.', + 'Cats have five toes on each front paw, but only four toes on each back paw.', + 'A cat’s whiskers are highly sensitive and can detect changes in air currents.', + 'Cats have a flexible spine and can rotate their ears 180 degrees.', + 'Cats can run up to 30 miles per hour.', + 'Cats are believed to be the only mammals who don’t taste sweetness.', + 'Cats have excellent night vision and can see at one-sixth the light level required for human vision.', + 'Cats can’t see directly under their nose.', + 'Cats can make more than 100 different sounds.', + 'A cat can travel at a top speed of approximately 31 mph (49 km) over a short distance.', + 'Cats are capable of walking very precisely. When they take a step, they place their back paw almost exactly in the same place as their front paw was – this is called ‘direct registering’.', + 'A cat’s hearing is much more sensitive than humans and dogs.', + 'Cats have been domesticated for around 4,000 years.', + 'Cats use their tails to maintain balance and communicate their mood.', + 'A cat’s brain is biologically more similar to a human brain than it is to a dog’s.', + 'Cats conserve energy by sleeping for an average of 13 to 14 hours a day.', + 'A cat has a total of 24 whiskers – 4 first-order, 8 second-order, and 12 third-order.', + 'Cats can pick up on changes in the weather, which can indicate to them that a storm is coming.', + 'Cats have an acute sense of hearing and can detect an ultra-sonic range of sounds up to two octaves higher than humans.', + 'Cats can learn to manipulate humans with their meows.', + 'Cats have 32 muscles in each ear.', + 'The average lifespan of an indoor cat is 13 to 17 years.', + 'Cats are one of the most popular pets in the world, and there are more than 500 million domestic cats in existence.' + ] + */ } main() diff --git a/src/fluent-scratch.ts b/examples/misc.ts similarity index 81% rename from src/fluent-scratch.ts rename to examples/misc.ts index 0c1683b4..8a533d4e 100644 --- a/src/fluent-scratch.ts +++ b/examples/misc.ts @@ -1,13 +1,18 @@ +import dotenv from 'dotenv-safe' +import { OpenAIClient } from 'openai-fetch' import { z } from 'zod' -async function main() { - const $ = {} as any +import { Agentic } from '../src' - // work with a single input or an array of inputs using p-map under the hood +dotenv.config() + +async function main() { + const openai = new OpenAIClient({ apiKey: process.env.OPENAI_API_KEY! }) + const $ = new Agentic({ openai }) const ex0 = await $.gpt4(`give me a single boolean value: `) .output(z.boolean()) - .retry({ attempts: 3 }) + // .retry({ attempts: 3 }) .call() // LLM @@ -17,7 +22,8 @@ async function main() { const ex1 = await $.gpt4('give me a list of character names from star wars') .output(z.array(z.string().nonempty())) - .stream() + // .stream() + .call() const ex2 = await $.gpt4(`Summarize the following text: {{text}}`) .output(z.string().nonempty()) @@ -26,11 +32,11 @@ async function main() { text: 'The quick brown fox jumps over the lazy dog.' }) - const ext22 = await $.gpt4({ temperature: 0 }).call({ - messages: [ - // TEST - ] - }) + // const ext22 = await $.gpt4({ temperature: 0 }).call({ + // messages: [ + // // TEST + // ] + // }) const ex3 = await $.gpt4({ temperature: 0, @@ -75,3 +81,5 @@ async function main() { .output(z.string().nonempty()) .call() } + +main() diff --git a/examples/scratch.ts b/examples/scratch.ts new file mode 100644 index 00000000..23964105 --- /dev/null +++ b/examples/scratch.ts @@ -0,0 +1,37 @@ +import dotenv from 'dotenv-safe' +import { OpenAIClient } from 'openai-fetch' +import { z } from 'zod' + +import { Agentic } from '../src' + +dotenv.config() + +async function main() { + const openai = new OpenAIClient({ apiKey: process.env.OPENAI_API_KEY! }) + const $ = new Agentic({ openai }) + + // const ex0 = await $.gpt4(`give me a single boolean value`) + // .output(z.boolean()) + // // .retry({ attempts: 3 }) + // .call() + // console.log(ex0) + + // const ex1 = await $.gpt4(`give me fake data`) + // .output(z.object({ foo: z.string(), bar: z.number() })) + // // .output(z.string()) + // // .retry({ attempts: 3 }) + // .call() + // console.log(ex1) + + const getBoolean = $.gpt4(`are you {{mood}}?`) + .input(z.object({ mood: z.string() })) + .output(z.boolean()) + + const results = await Promise.all([ + getBoolean.call({ mood: 'happy' }), + getBoolean.call({ mood: 'sad' }) + ]) + console.log(results) +} + +main() diff --git a/package.json b/package.json index 5ec80e1b..d1ee4aaa 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "pre-commit": "lint-staged", "pretest": "run-s build", "test": "run-p test:*", + "test:unit": "ava", "test:prettier": "prettier '**/*.{js,jsx,ts,tsx}' --check" }, "dependencies": { @@ -29,7 +30,6 @@ "mustache": "^4.2.0", "openai-fetch": "^1.2.1", "p-map": "^6.0.0", - "parse-json": "^7.0.0", "ts-dedent": "^2.2.0", "type-fest": "^3.10.0", "zod": "^3.21.4", @@ -40,6 +40,7 @@ "@trivago/prettier-plugin-sort-imports": "^4.1.1", "@types/mustache": "^4.2.2", "@types/node": "^20.2.0", + "ava": "^5.3.0", "del-cli": "^5.0.0", "husky": "^8.0.3", "lint-staged": "^13.2.2", @@ -54,6 +55,14 @@ "prettier --write" ] }, + "ava": { + "extensions": { + "ts": "module" + }, + "nodeArguments": [ + "--loader=tsx" + ] + }, "keywords": [ "ai", "agent", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9a0d8d7e..91cfa83f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,9 +19,6 @@ dependencies: p-map: specifier: ^6.0.0 version: 6.0.0 - parse-json: - specifier: ^7.0.0 - version: 7.0.0(typescript@5.0.4) ts-dedent: specifier: ^2.2.0 version: 2.2.0 @@ -48,6 +45,9 @@ devDependencies: '@types/node': specifier: ^20.2.0 version: 20.2.0 + ava: + specifier: ^5.3.0 + version: 5.3.0 del-cli: specifier: ^5.0.0 version: 5.0.0 @@ -80,6 +80,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.18.6 + dev: true /@babel/generator@7.17.7: resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==} @@ -125,6 +126,7 @@ packages: /@babel/helper-validator-identifier@7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} + dev: true /@babel/highlight@7.18.6: resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} @@ -133,6 +135,7 @@ packages: '@babel/helper-validator-identifier': 7.19.1 chalk: 2.4.2 js-tokens: 4.0.0 + dev: true /@babel/parser@7.21.8: resolution: {integrity: sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==} @@ -500,6 +503,17 @@ packages: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} dev: true + /acorn-walk@8.2.0: + resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn@8.8.2: + resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -538,6 +552,7 @@ packages: engines: {node: '>=4'} dependencies: color-convert: 1.9.3 + dev: true /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} @@ -563,6 +578,12 @@ packages: picomatch: 2.3.1 dev: true + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true + /array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: @@ -570,21 +591,93 @@ packages: is-array-buffer: 3.0.2 dev: true + /array-find-index@1.0.2: + resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} + engines: {node: '>=0.10.0'} + dev: true + /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} dev: true + /arrgv@1.0.2: + resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} + engines: {node: '>=8.0.0'} + dev: true + /arrify@1.0.1: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} dev: true + /arrify@3.0.0: + resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} + engines: {node: '>=12'} + dev: true + /astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} dev: true + /ava@5.3.0: + resolution: {integrity: sha512-QYvBdyygl1LGX13IuYsC4bkwVCzZeovMGbxYkD73i7DVJxNlWnFa06YgrBOTbjw2QvSKUl5fOJ92Kj5WK9hSeg==} + engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} + hasBin: true + peerDependencies: + '@ava/typescript': '*' + peerDependenciesMeta: + '@ava/typescript': + optional: true + dependencies: + acorn: 8.8.2 + acorn-walk: 8.2.0 + ansi-styles: 6.2.1 + arrgv: 1.0.2 + arrify: 3.0.0 + callsites: 4.0.0 + cbor: 8.1.0 + chalk: 5.2.0 + chokidar: 3.5.3 + chunkd: 2.0.1 + ci-info: 3.8.0 + ci-parallel-vars: 1.0.1 + clean-yaml-object: 0.1.0 + cli-truncate: 3.1.0 + code-excerpt: 4.0.0 + common-path-prefix: 3.0.0 + concordance: 5.0.4 + currently-unhandled: 0.4.1 + debug: 4.3.4 + emittery: 1.0.1 + figures: 5.0.0 + globby: 13.1.4 + ignore-by-default: 2.1.0 + indent-string: 5.0.0 + is-error: 2.2.2 + is-plain-object: 5.0.0 + is-promise: 4.0.0 + matcher: 5.0.0 + mem: 9.0.2 + ms: 2.1.3 + p-event: 5.0.1 + p-map: 5.5.0 + picomatch: 2.3.1 + pkg-conf: 4.0.0 + plur: 5.1.0 + pretty-ms: 8.0.0 + resolve-cwd: 3.0.0 + stack-utils: 2.0.6 + strip-ansi: 7.0.1 + supertap: 3.0.1 + temp-dir: 3.0.0 + write-file-atomic: 5.0.1 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + dev: true + /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} @@ -599,6 +692,10 @@ packages: engines: {node: '>=8'} dev: true + /blueimp-md5@2.19.0: + resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} + dev: true + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -639,6 +736,11 @@ packages: get-intrinsic: 1.2.1 dev: true + /callsites@4.0.0: + resolution: {integrity: sha512-y3jRROutgpKdz5vzEhWM34TidDU8vkJppF8dszITeb1PQmSqV3DTxyV8G/lyO/DNvtE1YTedehmw9MPZsCBHxQ==} + engines: {node: '>=12.20'} + dev: true + /camelcase-keys@7.0.2: resolution: {integrity: sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==} engines: {node: '>=12'} @@ -654,6 +756,13 @@ packages: engines: {node: '>=10'} dev: true + /cbor@8.1.0: + resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} + engines: {node: '>=12.19'} + dependencies: + nofilter: 3.1.0 + dev: true + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -661,6 +770,7 @@ packages: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 + dev: true /chalk@5.2.0: resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==} @@ -682,6 +792,19 @@ packages: fsevents: 2.3.2 dev: true + /chunkd@2.0.1: + resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} + dev: true + + /ci-info@3.8.0: + resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} + engines: {node: '>=8'} + dev: true + + /ci-parallel-vars@1.0.1: + resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} + dev: true + /clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} @@ -694,6 +817,11 @@ packages: escape-string-regexp: 5.0.0 dev: true + /clean-yaml-object@0.1.0: + resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} + engines: {node: '>=0.10.0'} + dev: true + /cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -717,10 +845,27 @@ packages: string-width: 5.1.2 dev: true + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /code-excerpt@4.0.0: + resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + convert-to-spaces: 2.0.1 + dev: true + /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 + dev: true /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -731,6 +876,7 @@ packages: /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: true /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -750,10 +896,33 @@ packages: engines: {node: '>= 6'} dev: true + /common-path-prefix@3.0.0: + resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} + dev: true + /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true + /concordance@5.0.4: + resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} + engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} + dependencies: + date-time: 3.1.0 + esutils: 2.0.3 + fast-diff: 1.3.0 + js-string-escape: 1.0.1 + lodash: 4.17.21 + md5-hex: 3.0.1 + semver: 7.5.1 + well-known-symbols: 2.0.0 + dev: true + + /convert-to-spaces@2.0.1: + resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /cross-spawn@6.0.5: resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} engines: {node: '>=4.8'} @@ -774,6 +943,20 @@ packages: which: 2.0.2 dev: true + /currently-unhandled@0.4.1: + resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} + engines: {node: '>=0.10.0'} + dependencies: + array-find-index: 1.0.2 + dev: true + + /date-time@3.1.0: + resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} + engines: {node: '>=6'} + dependencies: + time-zone: 1.0.0 + dev: true + /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -857,6 +1040,11 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true + /emittery@1.0.1: + resolution: {integrity: sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==} + engines: {node: '>=14.16'} + dev: true + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true @@ -869,6 +1057,7 @@ packages: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 + dev: true /es-abstract@1.21.2: resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==} @@ -958,15 +1147,37 @@ packages: '@esbuild/win32-x64': 0.17.19 dev: true + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + dev: true /escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} dev: true + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -997,6 +1208,10 @@ packages: strip-final-newline: 3.0.0 dev: true + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + dev: true + /fast-glob@3.2.12: resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} engines: {node: '>=8.6.0'} @@ -1014,6 +1229,14 @@ packages: reusify: 1.0.4 dev: true + /figures@5.0.0: + resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} + engines: {node: '>=14'} + dependencies: + escape-string-regexp: 5.0.0 + is-unicode-supported: 1.3.0 + dev: true + /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -1029,6 +1252,14 @@ packages: path-exists: 4.0.0 dev: true + /find-up@6.3.0: + resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + dev: true + /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: @@ -1065,6 +1296,11 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + /get-intrinsic@1.2.1: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} dependencies: @@ -1177,6 +1413,7 @@ packages: /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} + dev: true /has-property-descriptors@1.0.0: resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} @@ -1235,11 +1472,21 @@ packages: hasBin: true dev: true + /ignore-by-default@2.1.0: + resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} + engines: {node: '>=10 <11 || >=12 <13 || >=14'} + dev: true + /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} dev: true + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + /indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} @@ -1270,6 +1517,11 @@ packages: side-channel: 1.0.4 dev: true + /irregular-plurals@3.5.0: + resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} + engines: {node: '>=8'} + dev: true + /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} dependencies: @@ -1280,6 +1532,7 @@ packages: /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} @@ -1320,6 +1573,10 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-error@2.2.2: + resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} + dev: true + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -1374,6 +1631,15 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: true + + /is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + dev: true + /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -1423,6 +1689,11 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + dev: true + /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: @@ -1442,8 +1713,22 @@ packages: engines: {node: '>=10'} dev: true + /js-string-escape@1.0.1: + resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} + engines: {node: '>= 0.8'} + dev: true + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} @@ -1459,11 +1744,6 @@ packages: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} dev: true - /json-parse-even-better-errors@3.0.0: - resolution: {integrity: sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - dev: false - /jsonrepair@3.1.0: resolution: {integrity: sha512-idqReg23J0PVRAADmZMc5xQM3xeOX5bTB6OTyMnzq33IXJXmn9iJuWIEvGmrN80rQf4d7uLTMEDwpzujNcI0Rg==} hasBin: true @@ -1488,11 +1768,6 @@ packages: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true - /lines-and-columns@2.0.3: - resolution: {integrity: sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dev: false - /lint-staged@13.2.2: resolution: {integrity: sha512-71gSwXKy649VrSU09s10uAT0rWCcY3aewhMaHyl2N84oBk4Xs9HgxvUp3AYu+bNsK4NrOYYxvSgg7FyGJ+jGcA==} engines: {node: ^14.13.1 || >=16.0.0} @@ -1545,6 +1820,11 @@ packages: strip-bom: 3.0.0 dev: true + /load-json-file@7.0.1: + resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /load-tsconfig@0.2.5: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1557,6 +1837,13 @@ packages: p-locate: 5.0.0 dev: true + /locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-locate: 6.0.0 + dev: true + /lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} dev: true @@ -1582,6 +1869,13 @@ packages: yallist: 4.0.0 dev: true + /map-age-cleaner@0.1.3: + resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} + engines: {node: '>=6'} + dependencies: + p-defer: 1.0.0 + dev: true + /map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -1592,6 +1886,28 @@ packages: engines: {node: '>=8'} dev: true + /matcher@5.0.0: + resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + escape-string-regexp: 5.0.0 + dev: true + + /md5-hex@3.0.1: + resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} + engines: {node: '>=8'} + dependencies: + blueimp-md5: 2.19.0 + dev: true + + /mem@9.0.2: + resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==} + engines: {node: '>=12.20'} + dependencies: + map-age-cleaner: 0.1.3 + mimic-fn: 4.0.0 + dev: true + /memorystream@0.3.1: resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} engines: {node: '>= 0.10.0'} @@ -1666,6 +1982,10 @@ packages: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + /mustache@4.2.0: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} hasBin: true @@ -1683,6 +2003,11 @@ packages: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} dev: true + /nofilter@3.1.0: + resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} + engines: {node: '>=12.19'} + dev: true + /normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: @@ -1788,6 +2113,18 @@ packages: zod: 3.21.4 dev: false + /p-defer@1.0.0: + resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} + engines: {node: '>=4'} + dev: true + + /p-event@5.0.1: + resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-timeout: 5.1.0 + dev: true + /p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -1795,6 +2132,13 @@ packages: yocto-queue: 0.1.0 dev: true + /p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + yocto-queue: 1.0.0 + dev: true + /p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} @@ -1802,6 +2146,13 @@ packages: p-limit: 3.1.0 dev: true + /p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-limit: 4.0.0 + dev: true + /p-map@4.0.0: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} engines: {node: '>=10'} @@ -1821,6 +2172,11 @@ packages: engines: {node: '>=16'} dev: false + /p-timeout@5.1.0: + resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} + engines: {node: '>=12'} + dev: true + /parse-json@4.0.0: resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} @@ -1839,24 +2195,21 @@ packages: lines-and-columns: 1.2.4 dev: true - /parse-json@7.0.0(typescript@5.0.4): - resolution: {integrity: sha512-kP+TQYAzAiVnzOlWOe0diD6L35s9bJh0SCn95PIbZFKrOYuIRQsQkeWEYxzVDuHTt9V9YqvYCJ2Qo4z9wdfZPw==} - engines: {node: '>=16'} - dependencies: - '@babel/code-frame': 7.21.4 - error-ex: 1.3.2 - json-parse-even-better-errors: 3.0.0 - lines-and-columns: 2.0.3 - type-fest: 3.10.0(typescript@5.0.4) - transitivePeerDependencies: - - typescript - dev: false + /parse-ms@3.0.0: + resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} + engines: {node: '>=12'} + dev: true /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} dev: true + /path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -1920,6 +2273,21 @@ packages: engines: {node: '>= 6'} dev: true + /pkg-conf@4.0.0: + resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + find-up: 6.3.0 + load-json-file: 7.0.1 + dev: true + + /plur@5.1.0: + resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + irregular-plurals: 3.5.0 + dev: true + /postcss-load-config@3.1.4: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} @@ -1942,6 +2310,13 @@ packages: hasBin: true dev: true + /pretty-ms@8.0.0: + resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} + engines: {node: '>=14.16'} + dependencies: + parse-ms: 3.0.0 + dev: true + /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} @@ -2008,6 +2383,18 @@ packages: functions-have-names: 1.2.3 dev: true + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + /resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} @@ -2087,6 +2474,13 @@ packages: lru-cache: 6.0.0 dev: true + /serialize-error@7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + dependencies: + type-fest: 0.13.1 + dev: true + /shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} @@ -2127,6 +2521,11 @@ packages: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true + /signal-exit@4.0.2: + resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} + engines: {node: '>=14'} + dev: true + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -2209,6 +2608,17 @@ packages: resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} dev: true + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true + + /stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + dev: true + /string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -2316,17 +2726,33 @@ packages: ts-interface-checker: 0.1.13 dev: true + /supertap@3.0.1: + resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + indent-string: 5.0.0 + js-yaml: 3.14.1 + serialize-error: 7.0.1 + strip-ansi: 7.0.1 + dev: true + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} dependencies: has-flag: 3.0.0 + dev: true /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} dev: true + /temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} + dev: true + /thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -2344,6 +2770,11 @@ packages: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} dev: true + /time-zone@1.0.0: + resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} + engines: {node: '>=4'} + dev: true + /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} @@ -2432,6 +2863,11 @@ packages: fsevents: 2.3.2 dev: true + /type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + dev: true + /type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} @@ -2484,6 +2920,11 @@ packages: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} dev: true + /well-known-symbols@2.0.0: + resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} + engines: {node: '>=6'} + dev: true + /whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} dependencies: @@ -2551,6 +2992,19 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true + /write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.0.2 + dev: true + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true @@ -2570,11 +3024,34 @@ packages: engines: {node: '>=10'} dev: true + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true + /yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + dev: true + /zod-to-ts@1.1.4(typescript@5.0.4)(zod@3.21.4): resolution: {integrity: sha512-jsCg+pTNxLAdJOfW4ul+SpechdGYEJPPnssSbqWdR2LSIkotT22k+UvqPb1nEHwe/YbEcbUOlZUfGM0npgR+Jg==} peerDependencies: diff --git a/src/agentic.ts b/src/agentic.ts new file mode 100644 index 00000000..838e4b4b --- /dev/null +++ b/src/agentic.ts @@ -0,0 +1,67 @@ +import * as types from './types' +import { defaultOpenAIModel } from './constants' +import { OpenAIChatModelBuilder } from './openai' + +export class Agentic { + _client: types.openai.OpenAIClient + _verbosity: number + _defaults: Pick< + types.BaseLLMOptions, + 'provider' | 'model' | 'modelParams' | 'timeoutMs' | 'retryConfig' + > + + constructor(opts: { + openai: types.openai.OpenAIClient + verbosity?: number + defaults?: Pick< + types.BaseLLMOptions, + 'provider' | 'model' | 'modelParams' | 'timeoutMs' | 'retryConfig' + > + }) { + this._client = opts.openai + this._verbosity = opts.verbosity ?? 0 + this._defaults = { + provider: 'openai', + model: defaultOpenAIModel, + modelParams: {}, + timeoutMs: 30000, + retryConfig: { + attempts: 3, + strategy: 'heal', + ...opts.defaults?.retryConfig + }, + ...opts.defaults + } + } + + gpt4( + promptOrChatCompletionParams: + | string + | Omit + ) { + let options: Omit + + if (typeof promptOrChatCompletionParams === 'string') { + options = { + messages: [ + { + role: 'user', + content: promptOrChatCompletionParams + } + ] + } + } else { + options = promptOrChatCompletionParams + + if (!options.messages) { + throw new Error('messages must be provided') + } + } + + return new OpenAIChatModelBuilder(this._client, { + ...(this._defaults as any), // TODO + model: 'gpt-4', + ...options + }) + } +} diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 00000000..9cb5dbf1 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1 @@ +export const defaultOpenAIModel = 'gpt-3.5-turbo' diff --git a/src/index.ts b/src/index.ts index 5e04feac..e86266ab 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,4 @@ +export * from './agentic' export * from './llm' +export * from './openai' export * from './tokenizer' diff --git a/src/llm.ts b/src/llm.ts index 1e9eda22..c8ac815a 100644 --- a/src/llm.ts +++ b/src/llm.ts @@ -1,79 +1,6 @@ -import { jsonrepair } from 'jsonrepair' -import Mustache from 'mustache' -import { dedent } from 'ts-dedent' -import type { SetRequired } from 'type-fest' import { ZodRawShape, ZodTypeAny, z } from 'zod' -import { printNode, zodToTs } from 'zod-to-ts' import * as types from './types' -import { - extractJSONArrayFromString, - extractJSONObjectFromString -} from './utils' - -const defaultOpenAIModel = 'gpt-3.5-turbo' - -export class Agentic { - _client: types.openai.OpenAIClient - _verbosity: number - _defaults: Pick< - types.BaseLLMOptions, - 'provider' | 'model' | 'modelParams' | 'timeoutMs' | 'retryConfig' - > - - constructor(opts: { - openai: types.openai.OpenAIClient - verbosity?: number - defaults?: Pick< - types.BaseLLMOptions, - 'provider' | 'model' | 'modelParams' | 'timeoutMs' | 'retryConfig' - > - }) { - this._client = opts.openai - this._verbosity = opts.verbosity ?? 0 - this._defaults = { - provider: 'openai', - model: defaultOpenAIModel, - modelParams: {}, - timeoutMs: 30000, - retryConfig: { - attempts: 3, - strategy: 'heal', - ...opts.defaults?.retryConfig - }, - ...opts.defaults - } - } - - gpt4( - promptOrChatCompletionParams: string | types.openai.ChatCompletionParams - ) { - let options: Omit - - if (typeof promptOrChatCompletionParams === 'string') { - options = { - messages: [ - { - role: 'user', - content: promptOrChatCompletionParams - } - ] - } - } else { - options = promptOrChatCompletionParams - - if (!options.messages) { - throw new Error('messages must be provided') - } - } - - return new OpenAIChatModelBuilder(this._client, { - ...(this._defaults as any), // TODO - model: 'gpt-4', - ...options - }) - } -} export abstract class BaseLLMCallBuilder< TInput extends ZodRawShape | ZodTypeAny = ZodTypeAny, @@ -148,138 +75,3 @@ export abstract class ChatModelBuilder< this._messages = options.messages } } - -export class OpenAIChatModelBuilder< - TInput extends ZodRawShape | ZodTypeAny = ZodTypeAny, - TOutput extends ZodRawShape | ZodTypeAny = z.ZodType -> extends ChatModelBuilder< - TInput, - TOutput, - SetRequired, 'model'> -> { - _client: types.openai.OpenAIClient - - constructor( - client: types.openai.OpenAIClient, - options: types.ChatModelOptions< - TInput, - TOutput, - Omit - > - ) { - super({ - provider: 'openai', - model: defaultOpenAIModel, - ...options - }) - - this._client = client - } - - override async call( - input?: types.ParsedData - ): Promise> { - if (this._options.input) { - const inputSchema = - this._options.input instanceof z.ZodType - ? this._options.input - : z.object(this._options.input) - - // TODO: handle errors gracefully - input = inputSchema.parse(input) - } - - // TODO: validate input message variables against input schema - - const messages = this._messages - .map((message) => { - return { - ...message, - content: message.content - ? Mustache.render(dedent(message.content), input).trim() - : '' - } - }) - .filter((message) => message.content) - - if (this._options.output) { - const outputSchema = - this._options.output instanceof z.ZodType - ? this._options.output - : z.object(this._options.output) - - const { node } = zodToTs(outputSchema) - - if (node.kind === 152) { - // ignore raw strings - messages.push({ - role: 'system', - content: dedent`Output a string` - }) - } else { - const tsTypeString = printNode(node, { - removeComments: false, - // TODO: this doesn't seem to actually work, so we're doing it manually below - omitTrailingSemicolon: true, - noEmitHelpers: true - }) - .replace(/^ /gm, ' ') - .replace(/;$/gm, '') - - messages.push({ - role: 'system', - content: dedent`Output JSON only in the following format: - \`\`\`ts - ${tsTypeString} - \`\`\`` - }) - } - } - - // TODO: filter/compress messages based on token counts - - console.log('>>>') - console.log(messages) - const completion = await this._client.createChatCompletion({ - model: defaultOpenAIModel, // TODO: this shouldn't be necessary but TS is complaining - ...this._options.modelParams, - messages - }) - - if (this._options.output) { - const outputSchema = - this._options.output instanceof z.ZodType - ? this._options.output - : z.object(this._options.output) - - let output: any = completion.message.content - console.log('===') - console.log(output) - console.log('<<<') - - if (outputSchema instanceof z.ZodArray) { - try { - const trimmedOutput = extractJSONArrayFromString(output) - output = JSON.parse(jsonrepair(trimmedOutput ?? output)) - } catch (err) { - // TODO - throw err - } - } else if (outputSchema instanceof z.ZodObject) { - try { - const trimmedOutput = extractJSONObjectFromString(output) - output = JSON.parse(jsonrepair(trimmedOutput ?? output)) - } catch (err) { - // TODO - throw err - } - } - - // TODO: handle errors, retry logic, and self-healing - - return outputSchema.parse(output) - } else { - return completion.message.content as any - } - } -} diff --git a/src/openai.ts b/src/openai.ts new file mode 100644 index 00000000..770558de --- /dev/null +++ b/src/openai.ts @@ -0,0 +1,188 @@ +import { jsonrepair } from 'jsonrepair' +import Mustache from 'mustache' +import { dedent } from 'ts-dedent' +import type { SetRequired } from 'type-fest' +import { ZodRawShape, ZodTypeAny, z } from 'zod' +import { printNode, zodToTs } from 'zod-to-ts' + +import * as types from './types' +import { defaultOpenAIModel } from './constants' +import { ChatModelBuilder } from './llm' +import { + extractJSONArrayFromString, + extractJSONObjectFromString +} from './utils' + +export class OpenAIChatModelBuilder< + TInput extends ZodRawShape | ZodTypeAny = ZodTypeAny, + TOutput extends ZodRawShape | ZodTypeAny = z.ZodType +> extends ChatModelBuilder< + TInput, + TOutput, + SetRequired, 'model'> +> { + _client: types.openai.OpenAIClient + + constructor( + client: types.openai.OpenAIClient, + options: types.ChatModelOptions< + TInput, + TOutput, + Omit + > + ) { + super({ + provider: 'openai', + model: defaultOpenAIModel, + ...options + }) + + this._client = client + } + + override async call( + input?: types.ParsedData + ): Promise> { + if (this._options.input) { + const inputSchema = + this._options.input instanceof z.ZodType + ? this._options.input + : z.object(this._options.input) + + // TODO: handle errors gracefully + input = inputSchema.parse(input) + } + + // TODO: validate input message variables against input schema + + const messages = this._messages + .map((message) => { + return { + ...message, + content: message.content + ? Mustache.render(dedent(message.content), input).trim() + : '' + } + }) + .filter((message) => message.content) + + if (this._options.examples?.length) { + // TODO: smarter example selection + for (const example of this._options.examples) { + messages.push({ + role: 'system', + content: `Example input: ${example.input}\n\nExample output: ${example.output}` + }) + } + } + + if (this._options.output) { + const outputSchema = + this._options.output instanceof z.ZodType + ? this._options.output + : z.object(this._options.output) + + const { node } = zodToTs(outputSchema) + + if (node.kind === 152) { + // handle raw strings differently + messages.push({ + role: 'system', + content: dedent`Output a raw string only, without any additional text.` + }) + } else { + const tsTypeString = printNode(node, { + removeComments: false, + // TODO: this doesn't seem to actually work, so we're doing it manually below + omitTrailingSemicolon: true, + noEmitHelpers: true + }) + .replace(/^ /gm, ' ') + .replace(/;$/gm, '') + + messages.push({ + role: 'system', + content: dedent`Output JSON only in the following format: + \`\`\`ts + ${tsTypeString} + \`\`\`` + }) + } + } + + // TODO: filter/compress messages based on token counts + + console.log('>>>') + console.log(messages) + const completion = await this._client.createChatCompletion({ + model: defaultOpenAIModel, // TODO: this shouldn't be necessary but TS is complaining + ...this._options.modelParams, + messages + }) + + if (this._options.output) { + const outputSchema = + this._options.output instanceof z.ZodType + ? this._options.output + : z.object(this._options.output) + + let output: any = completion.message.content + console.log('===') + console.log(output) + console.log('<<<') + + if (outputSchema instanceof z.ZodArray) { + try { + const trimmedOutput = extractJSONArrayFromString(output) + output = JSON.parse(jsonrepair(trimmedOutput ?? output)) + } catch (err) { + // TODO + throw err + } + } else if (outputSchema instanceof z.ZodObject) { + try { + const trimmedOutput = extractJSONObjectFromString(output) + output = JSON.parse(jsonrepair(trimmedOutput ?? output)) + } catch (err) { + // TODO + throw err + } + } else if (outputSchema instanceof z.ZodBoolean) { + output = output.toLowerCase().trim() + const booleanOutputs = { + true: true, + false: false, + yes: true, + no: false, + 1: true, + 0: false + } + + const booleanOutput = booleanOutputs[output] + if (booleanOutput !== undefined) { + output = booleanOutput + } else { + throw new Error(`invalid boolean output: ${output}`) + } + } else if (outputSchema instanceof z.ZodNumber) { + output = output.trim() + + const numberOutput = outputSchema.isInt + ? parseInt(output) + : parseFloat(output) + + if (isNaN(numberOutput)) { + throw new Error(`invalid number output: ${output}`) + } else { + output = numberOutput + } + } + + // TODO: handle errors, retry logic, and self-healing + + return outputSchema.parse(output) + } else { + return completion.message.content as any + } + } +} diff --git a/src/temp.ts b/src/temp.ts deleted file mode 100644 index 632c22bf..00000000 --- a/src/temp.ts +++ /dev/null @@ -1,38 +0,0 @@ -import dotenv from 'dotenv-safe' -import { OpenAIClient } from 'openai-fetch' -import { z } from 'zod' - -import { Agentic } from './llm' - -// import { LLMQuery } from '@agentic/llm-query' - -dotenv.config() - -async function main() { - const openai = new OpenAIClient({ apiKey: process.env.OPENAI_API_KEY! }) - const $ = new Agentic({ openai }) - - // const ex0 = await $.gpt4(`give me a single boolean value`) - // .output(z.boolean()) - // // .retry({ attempts: 3 }) - // .call() - // console.log(ex0) - - const ex1 = await $.gpt4(`give me fake data`) - .output(z.object({ foo: z.string(), bar: z.number() })) - // .output(z.string()) - // .retry({ attempts: 3 }) - .call() - console.log(ex1) - - // const getBoolean = $.gpt4(`give me a single boolean value {{foo}}`) - // .input(z.object({ foo: z.string() })) - // .output(z.boolean()) - - // await Promise.all([ - // getBoolean.call({ foo: 'foo' }), - // getBoolean.call({ foo: 'bar' }) - // ]) -} - -main() diff --git a/src/temp2.ts b/src/temp2.ts deleted file mode 100644 index 9bae58e8..00000000 --- a/src/temp2.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ZodRawShape, ZodType, ZodTypeAny, z } from 'zod' - -import * as types from './types' - -class Test { - _schema: T - - schema(schema: U): Test { - ;(this as unknown as Test)._schema = schema - return this as unknown as Test - } - - call(value: types.ParsedData): types.ParsedData { - const finalSchema = - this._schema instanceof ZodType ? this._schema : z.object(this._schema) - return finalSchema.parse(value) - } -} - -async function main() { - const t = new Test() - const t2 = t.schema(z.string()) - const t3 = t2.call('foo') - - console.log(t3) -} - -main()