├── .devcontainer └── devcontainer.json ├── .eslintrc.js ├── .github └── workflows │ ├── ci.yml │ ├── publish-npm.yml │ ├── release-doctor.yml │ └── stale.yaml ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── .release-please-manifest.json ├── .stats.yml ├── Brewfile ├── CHANGELOG.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── api.md ├── bin ├── check-release-environment └── publish-npm ├── examples ├── .keep ├── chat_completion.js ├── chat_completion_stop.js └── chat_completion_streaming.js ├── jest.config.ts ├── package.json ├── release-please-config.json ├── scripts ├── bootstrap ├── build ├── format ├── lint ├── mock ├── test └── utils │ ├── check-is-in-git-install.sh │ ├── check-version.cjs │ ├── fix-index-exports.cjs │ ├── git-swap.sh │ ├── make-dist-package-json.cjs │ ├── postprocess-files.cjs │ └── upload-artifact.sh ├── src ├── _shims │ ├── MultipartBody.ts │ ├── README.md │ ├── auto │ │ ├── runtime-bun.ts │ │ ├── runtime-deno.ts │ │ ├── runtime-node.ts │ │ ├── runtime.ts │ │ ├── types-deno.ts │ │ ├── types-node.ts │ │ ├── types.d.ts │ │ ├── types.js │ │ └── types.mjs │ ├── bun-runtime.ts │ ├── index-deno.ts │ ├── index.d.ts │ ├── index.js │ ├── index.mjs │ ├── manual-types.d.ts │ ├── manual-types.js │ ├── manual-types.mjs │ ├── node-runtime.ts │ ├── node-types.d.ts │ ├── node-types.js │ ├── node-types.mjs │ ├── registry.ts │ ├── web-runtime.ts │ ├── web-types.d.ts │ ├── web-types.js │ └── web-types.mjs ├── core.ts ├── error.ts ├── index.ts ├── lib │ ├── .keep │ └── streaming.ts ├── resource.ts ├── resources.ts ├── resources │ ├── audio.ts │ ├── audio │ │ ├── audio.ts │ │ ├── index.ts │ │ ├── speech.ts │ │ ├── transcriptions.ts │ │ └── translations.ts │ ├── batches.ts │ ├── chat.ts │ ├── chat │ │ ├── chat.ts │ │ ├── completions.ts │ │ └── index.ts │ ├── completions.ts │ ├── embeddings.ts │ ├── files.ts │ ├── index.ts │ ├── models.ts │ └── shared.ts ├── shims │ ├── node.ts │ └── web.ts ├── uploads.ts └── version.ts ├── tests ├── api-resources │ ├── audio │ │ ├── speech.test.ts │ │ ├── transcriptions.test.ts │ │ └── translations.test.ts │ ├── batches.test.ts │ ├── chat │ │ └── completions.test.ts │ ├── embeddings.test.ts │ ├── files.test.ts │ └── models.test.ts ├── form.test.ts ├── index.test.ts ├── responses.test.ts ├── stringifyQuery.test.ts └── uploads.test.ts ├── tsc-multi.json ├── tsconfig.build.json ├── tsconfig.deno.json ├── tsconfig.dist-src.json ├── tsconfig.json └── yarn.lock /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/debian 3 | { 4 | "name": "Development", 5 | "image": "mcr.microsoft.com/devcontainers/typescript-node:latest", 6 | "features": { 7 | "ghcr.io/devcontainers/features/node:1": {} 8 | }, 9 | "postCreateCommand": "yarn install", 10 | "customizations": { 11 | "vscode": { 12 | "extensions": [ 13 | "esbenp.prettier-vscode" 14 | ] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | plugins: ['@typescript-eslint', 'unused-imports', 'prettier'], 4 | rules: { 5 | 'no-unused-vars': 'off', 6 | 'prettier/prettier': 'error', 7 | 'unused-imports/no-unused-imports': 'error', 8 | }, 9 | root: true, 10 | }; 11 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches-ignore: 5 | - 'generated' 6 | - 'codegen/**' 7 | - 'integrated/**' 8 | - 'stl-preview-head/**' 9 | - 'stl-preview-base/**' 10 | 11 | jobs: 12 | lint: 13 | timeout-minutes: 10 14 | name: lint 15 | runs-on: ${{ github.repository == 'stainless-sdks/groqcloud-node' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Set up Node 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: '18' 23 | 24 | - name: Bootstrap 25 | run: ./scripts/bootstrap 26 | 27 | - name: Check types 28 | run: ./scripts/lint 29 | 30 | build: 31 | timeout-minutes: 5 32 | name: build 33 | runs-on: ${{ github.repository == 'stainless-sdks/groqcloud-node' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} 34 | permissions: 35 | contents: read 36 | id-token: write 37 | steps: 38 | - uses: actions/checkout@v4 39 | 40 | - name: Set up Node 41 | uses: actions/setup-node@v4 42 | with: 43 | node-version: '18' 44 | 45 | - name: Bootstrap 46 | run: ./scripts/bootstrap 47 | 48 | - name: Check build 49 | run: ./scripts/build 50 | 51 | - name: Get GitHub OIDC Token 52 | if: github.repository == 'stainless-sdks/groqcloud-node' 53 | id: github-oidc 54 | uses: actions/github-script@v6 55 | with: 56 | script: core.setOutput('github_token', await core.getIDToken()); 57 | 58 | - name: Upload tarball 59 | if: github.repository == 'stainless-sdks/groqcloud-node' 60 | env: 61 | URL: https://pkg.stainless.com/s 62 | AUTH: ${{ steps.github-oidc.outputs.github_token }} 63 | SHA: ${{ github.sha }} 64 | run: ./scripts/utils/upload-artifact.sh 65 | test: 66 | timeout-minutes: 10 67 | name: test 68 | runs-on: ${{ github.repository == 'stainless-sdks/groqcloud-node' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} 69 | steps: 70 | - uses: actions/checkout@v4 71 | 72 | - name: Set up Node 73 | uses: actions/setup-node@v4 74 | with: 75 | node-version: '20' 76 | 77 | - name: Bootstrap 78 | run: ./scripts/bootstrap 79 | 80 | - name: Run tests 81 | run: ./scripts/test 82 | -------------------------------------------------------------------------------- /.github/workflows/publish-npm.yml: -------------------------------------------------------------------------------- 1 | # This workflow is triggered when a GitHub release is created. 2 | # It can also be run manually to re-publish to NPM in case it failed for some reason. 3 | # You can run this workflow by navigating to https://www.github.com/groq/groq-typescript/actions/workflows/publish-npm.yml 4 | name: Publish NPM 5 | on: 6 | workflow_dispatch: 7 | 8 | release: 9 | types: [published] 10 | 11 | jobs: 12 | publish: 13 | name: publish 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Set up Node 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: '20' 23 | 24 | - name: Install dependencies 25 | run: | 26 | yarn install 27 | 28 | - name: Publish to NPM 29 | run: | 30 | bash ./bin/publish-npm 31 | env: 32 | NPM_TOKEN: ${{ secrets.GROQ_NPM_TOKEN || secrets.NPM_TOKEN }} 33 | -------------------------------------------------------------------------------- /.github/workflows/release-doctor.yml: -------------------------------------------------------------------------------- 1 | name: Release Doctor 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | workflow_dispatch: 7 | 8 | jobs: 9 | release_doctor: 10 | name: release doctor 11 | runs-on: ubuntu-latest 12 | if: github.repository == 'groq/groq-typescript' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Check release environment 18 | run: | 19 | bash ./bin/check-release-environment 20 | env: 21 | NPM_TOKEN: ${{ secrets.GROQ_NPM_TOKEN || secrets.NPM_TOKEN }} 22 | 23 | -------------------------------------------------------------------------------- /.github/workflows/stale.yaml: -------------------------------------------------------------------------------- 1 | ##################################### 2 | # DO NOT EDIT DIRECTLY. # 3 | # This file is managed by Terraform # 4 | ##################################### 5 | 6 | name: "Close stale PRs" 7 | on: 8 | schedule: 9 | - cron: "30 1 * * *" 10 | 11 | jobs: 12 | stale: 13 | runs-on: ubuntu-latest 14 | # Read repo and write to PRs 15 | permissions: 16 | contents: read 17 | pull-requests: write 18 | issues: write 19 | steps: 20 | - uses: actions/stale@v9 21 | with: 22 | stale-pr-message: "This PR is stale because it has been open for 30 days with no activity. Remove stale label or comment or this will be closed in 7 days." 23 | close-pr-message: "This PR was closed because it has been stalled for 7 days with no activity." 24 | days-before-pr-stale: 30 25 | days-before-pr-close: 7 26 | exempt-pr-labels: "dependencies,security" 27 | operations-per-run: 60 # Default is 30 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .prism.log 2 | node_modules 3 | yarn-error.log 4 | codegen.log 5 | Brewfile.lock.json 6 | dist 7 | dist-deno 8 | /*.tgz 9 | .idea/ 10 | 11 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | CHANGELOG.md 2 | /ecosystem-tests/*/** 3 | /node_modules 4 | /deno 5 | 6 | # don't format tsc output, will break source maps 7 | /dist 8 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "experimentalTernaries": true, 4 | "printWidth": 110, 5 | "singleQuote": true, 6 | "trailingComma": "all" 7 | } 8 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "0.23.0" 3 | } 4 | -------------------------------------------------------------------------------- /.stats.yml: -------------------------------------------------------------------------------- 1 | configured_endpoints: 17 2 | openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/groqcloud%2Fgroqcloud-a2ddf0c5cb796758690f28d02fef6ae46d2eab3fdc3e2d2cf99ef2b75cca4022.yml 3 | openapi_spec_hash: 0f3cd640ddd5f1f4e8ea20b9cfd86025 4 | config_hash: 6b1c374dcc1ffa3165dd22f52a77ff89 5 | -------------------------------------------------------------------------------- /Brewfile: -------------------------------------------------------------------------------- 1 | brew "node" 2 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @gradenr 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Setting up the environment 2 | 3 | This repository uses [`yarn@v1`](https://classic.yarnpkg.com/lang/en/docs/install). 4 | Other package managers may work but are not officially supported for development. 5 | 6 | To set up the repository, run: 7 | 8 | ```sh 9 | $ yarn 10 | $ yarn build 11 | ``` 12 | 13 | This will install all the required dependencies and build output files to `dist/`. 14 | 15 | ## Modifying/Adding code 16 | 17 | Most of the SDK is generated code. Modifications to code will be persisted between generations, but may 18 | result in merge conflicts between manual patches and changes from the generator. The generator will never 19 | modify the contents of the `src/lib/` and `examples/` directories. 20 | 21 | ## Adding and running examples 22 | 23 | All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. 24 | 25 | ```ts 26 | // add an example to examples/.ts 27 | 28 | #!/usr/bin/env -S npm run tsn -T 29 | … 30 | ``` 31 | 32 | ```sh 33 | $ chmod +x examples/.ts 34 | # run the example against your api 35 | $ yarn tsn -T examples/.ts 36 | ``` 37 | 38 | ## Using the repository from source 39 | 40 | If you’d like to use the repository from source, you can either install from git or link to a cloned repository: 41 | 42 | To install via git: 43 | 44 | ```sh 45 | $ npm install git+ssh://git@github.com:groq/groq-typescript.git 46 | ``` 47 | 48 | Alternatively, to link a local copy of the repo: 49 | 50 | ```sh 51 | # Clone 52 | $ git clone https://www.github.com/groq/groq-typescript 53 | $ cd groq-typescript 54 | 55 | # With yarn 56 | $ yarn link 57 | $ cd ../my-package 58 | $ yarn link groq-sdk 59 | 60 | # With pnpm 61 | $ pnpm link --global 62 | $ cd ../my-package 63 | $ pnpm link -—global groq-sdk 64 | ``` 65 | 66 | ## Running tests 67 | 68 | Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. 69 | 70 | ```sh 71 | $ npx prism mock path/to/your/openapi.yml 72 | ``` 73 | 74 | ```sh 75 | $ yarn run test 76 | ``` 77 | 78 | ## Linting and formatting 79 | 80 | This repository uses [prettier](https://www.npmjs.com/package/prettier) and 81 | [eslint](https://www.npmjs.com/package/eslint) to format the code in the repository. 82 | 83 | To lint: 84 | 85 | ```sh 86 | $ yarn lint 87 | ``` 88 | 89 | To format and fix all lint issues automatically: 90 | 91 | ```sh 92 | $ yarn fix 93 | ``` 94 | 95 | ## Publishing and releases 96 | 97 | Changes made to this repository via the automated release PR pipeline should publish to npm automatically. If 98 | the changes aren't made through the automated pipeline, you may want to make releases manually. 99 | 100 | ### Publish with a GitHub workflow 101 | 102 | You can release to package managers by using [the `Publish NPM` GitHub action](https://www.github.com/groq/groq-typescript/actions/workflows/publish-npm.yml). This requires a setup organization or repository secret to be set up. 103 | 104 | ### Publish manually 105 | 106 | If you need to manually release a package, you can run the `bin/publish-npm` script with an `NPM_TOKEN` set on 107 | the environment. 108 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2025 Groq 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Groq Node API Library 2 | 3 | [![NPM version](https://img.shields.io/npm/v/groq-sdk.svg)](https://npmjs.org/package/groq-sdk) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/groq-sdk) 4 | 5 | This library provides convenient access to the Groq REST API from server-side TypeScript or JavaScript. 6 | 7 | The REST API documentation can be found on [console.groq.com](https://console.groq.com/docs). The full API of this library can be found in [api.md](api.md). 8 | 9 | It is generated with [Stainless](https://www.stainless.com/). 10 | 11 | ## Installation 12 | 13 | ```sh 14 | npm install groq-sdk 15 | ``` 16 | 17 | ## Usage 18 | 19 | The full API of this library can be found in [api.md](api.md). 20 | 21 | 22 | ```js 23 | import Groq from 'groq-sdk'; 24 | 25 | const client = new Groq({ 26 | apiKey: process.env['GROQ_API_KEY'], // This is the default and can be omitted 27 | }); 28 | 29 | async function main() { 30 | const chatCompletion = await client.chat.completions.create({ 31 | messages: [{ role: 'user', content: 'Explain the importance of low latency LLMs' }], 32 | model: 'llama3-8b-8192', 33 | }); 34 | 35 | console.log(chatCompletion[choices[0].message.content]); 36 | } 37 | 38 | main(); 39 | ``` 40 | 41 | ### Request & Response types 42 | 43 | This library includes TypeScript definitions for all request params and response fields. You may import and use them like so: 44 | 45 | 46 | ```ts 47 | import Groq from 'groq-sdk'; 48 | 49 | const client = new Groq({ 50 | apiKey: process.env['GROQ_API_KEY'], // This is the default and can be omitted 51 | }); 52 | 53 | async function main() { 54 | const params: Groq.Chat.CompletionCreateParams = { 55 | messages: [ 56 | { role: 'system', content: 'You are a helpful assistant.' }, 57 | { role: 'user', content: 'Explain the importance of low latency LLMs' }, 58 | ], 59 | model: 'llama3-8b-8192', 60 | }; 61 | const chatCompletion: Groq.Chat.ChatCompletion = await client.chat.completions.create(params); 62 | } 63 | 64 | main(); 65 | ``` 66 | 67 | Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors. 68 | 69 | ## File uploads 70 | 71 | Request parameters that correspond to file uploads can be passed in many different forms: 72 | 73 | - `File` (or an object with the same structure) 74 | - a `fetch` `Response` (or an object with the same structure) 75 | - an `fs.ReadStream` 76 | - the return value of our `toFile` helper 77 | 78 | ```ts 79 | import fs from 'fs'; 80 | import fetch from 'node-fetch'; 81 | import Groq, { toFile } from 'groq-sdk'; 82 | 83 | const client = new Groq(); 84 | 85 | // If you have access to Node `fs` we recommend using `fs.createReadStream()`: 86 | await client.audio.transcriptions.create({ 87 | model: 'whisper-large-v3-turbo', 88 | file: fs.createReadStream('/path/to/file'), 89 | }); 90 | 91 | // Or if you have the web `File` API you can pass a `File` instance: 92 | await client.audio.transcriptions.create({ 93 | model: 'whisper-large-v3-turbo', 94 | file: new File(['my bytes'], 'file'), 95 | }); 96 | 97 | // You can also pass a `fetch` `Response`: 98 | await client.audio.transcriptions.create({ 99 | model: 'whisper-large-v3-turbo', 100 | file: await fetch('https://somesite/file'), 101 | }); 102 | 103 | // Finally, if none of the above are convenient, you can use our `toFile` helper: 104 | await client.audio.transcriptions.create({ 105 | model: 'whisper-large-v3-turbo', 106 | file: await toFile(Buffer.from('my bytes'), 'file'), 107 | }); 108 | await client.audio.transcriptions.create({ 109 | model: 'whisper-large-v3-turbo', 110 | file: await toFile(new Uint8Array([0, 1, 2]), 'file'), 111 | }); 112 | ``` 113 | 114 | ## Handling errors 115 | 116 | When the library is unable to connect to the API, 117 | or if the API returns a non-success status code (i.e., 4xx or 5xx response), 118 | a subclass of `APIError` will be thrown: 119 | 120 | 121 | ```ts 122 | async function main() { 123 | const chatCompletion = await client.chat.completions 124 | .create({ 125 | messages: [ 126 | { role: 'system', content: 'You are a helpful assistant.' }, 127 | { role: 'user', content: 'Explain the importance of low latency LLMs' }, 128 | ], 129 | model: 'llama3-8b-8192', 130 | }) 131 | .catch(async (err) => { 132 | if (err instanceof Groq.APIError) { 133 | console.log(err.status); // 400 134 | console.log(err.name); // BadRequestError 135 | console.log(err.headers); // {server: 'nginx', ...} 136 | } else { 137 | throw err; 138 | } 139 | }); 140 | } 141 | 142 | main(); 143 | ``` 144 | 145 | Error codes are as follows: 146 | 147 | | Status Code | Error Type | 148 | | ----------- | -------------------------- | 149 | | 400 | `BadRequestError` | 150 | | 401 | `AuthenticationError` | 151 | | 403 | `PermissionDeniedError` | 152 | | 404 | `NotFoundError` | 153 | | 422 | `UnprocessableEntityError` | 154 | | 429 | `RateLimitError` | 155 | | >=500 | `InternalServerError` | 156 | | N/A | `APIConnectionError` | 157 | 158 | ### Retries 159 | 160 | Certain errors will be automatically retried 2 times by default, with a short exponential backoff. 161 | Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, 162 | 429 Rate Limit, and >=500 Internal errors will all be retried by default. 163 | 164 | You can use the `maxRetries` option to configure or disable this: 165 | 166 | 167 | ```js 168 | // Configure the default for all requests: 169 | const client = new Groq({ 170 | maxRetries: 0, // default is 2 171 | }); 172 | 173 | // Or, configure per-request: 174 | await client.chat.completions.create({ messages: [{ role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Explain the importance of low latency LLMs' }], model: 'llama3-8b-8192' }, { 175 | maxRetries: 5, 176 | }); 177 | ``` 178 | 179 | ### Timeouts 180 | 181 | Requests time out after 1 minute by default. You can configure this with a `timeout` option: 182 | 183 | 184 | ```ts 185 | // Configure the default for all requests: 186 | const client = new Groq({ 187 | timeout: 20 * 1000, // 20 seconds (default is 1 minute) 188 | }); 189 | 190 | // Override per-request: 191 | await client.chat.completions.create({ messages: [{ role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Explain the importance of low latency LLMs' }], model: 'llama3-8b-8192' }, { 192 | timeout: 5 * 1000, 193 | }); 194 | ``` 195 | 196 | On timeout, an `APIConnectionTimeoutError` is thrown. 197 | 198 | Note that requests which time out will be [retried twice by default](#retries). 199 | 200 | ## Advanced Usage 201 | 202 | ### Accessing raw Response data (e.g., headers) 203 | 204 | The "raw" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return. 205 | 206 | You can also use the `.withResponse()` method to get the raw `Response` along with the parsed data. 207 | 208 | 209 | ```ts 210 | const client = new Groq(); 211 | 212 | const response = await client.chat.completions 213 | .create({ 214 | messages: [ 215 | { role: 'system', content: 'You are a helpful assistant.' }, 216 | { role: 'user', content: 'Explain the importance of low latency LLMs' }, 217 | ], 218 | model: 'llama3-8b-8192', 219 | }) 220 | .asResponse(); 221 | console.log(response.headers.get('X-My-Header')); 222 | console.log(response.statusText); // access the underlying Response object 223 | 224 | const { data: chatCompletion, response: raw } = await client.chat.completions 225 | .create({ 226 | messages: [ 227 | { role: 'system', content: 'You are a helpful assistant.' }, 228 | { role: 'user', content: 'Explain the importance of low latency LLMs' }, 229 | ], 230 | model: 'llama3-8b-8192', 231 | }) 232 | .withResponse(); 233 | console.log(raw.headers.get('X-My-Header')); 234 | console.log(chatCompletion.id); 235 | ``` 236 | 237 | ### Making custom/undocumented requests 238 | 239 | This library is typed for convenient access to the documented API. If you need to access undocumented 240 | endpoints, params, or response properties, the library can still be used. 241 | 242 | #### Undocumented endpoints 243 | 244 | To make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs. 245 | Options on the client, such as retries, will be respected when making these requests. 246 | 247 | ```ts 248 | await client.post('/some/path', { 249 | body: { some_prop: 'foo' }, 250 | query: { some_query_arg: 'bar' }, 251 | }); 252 | ``` 253 | 254 | #### Undocumented request params 255 | 256 | To make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented 257 | parameter. This library doesn't validate at runtime that the request matches the type, so any extra values you 258 | send will be sent as-is. 259 | 260 | ```ts 261 | client.foo.create({ 262 | foo: 'my_param', 263 | bar: 12, 264 | // @ts-expect-error baz is not yet public 265 | baz: 'undocumented option', 266 | }); 267 | ``` 268 | 269 | For requests with the `GET` verb, any extra params will be in the query, all other requests will send the 270 | extra param in the body. 271 | 272 | If you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request 273 | options. 274 | 275 | #### Undocumented response properties 276 | 277 | To access undocumented response properties, you may access the response object with `// @ts-expect-error` on 278 | the response object, or cast the response object to the requisite type. Like the request params, we do not 279 | validate or strip extra properties from the response from the API. 280 | 281 | ### Customizing the fetch client 282 | 283 | By default, this library uses `node-fetch` in Node, and expects a global `fetch` function in other environments. 284 | 285 | If you would prefer to use a global, web-standards-compliant `fetch` function even in a Node environment, 286 | (for example, if you are running Node with `--experimental-fetch` or using NextJS which polyfills with `undici`), 287 | add the following import before your first import `from "Groq"`: 288 | 289 | ```ts 290 | // Tell TypeScript and the package to use the global web fetch instead of node-fetch. 291 | // Note, despite the name, this does not add any polyfills, but expects them to be provided if needed. 292 | import 'groq-sdk/shims/web'; 293 | import Groq from 'groq-sdk'; 294 | ``` 295 | 296 | To do the inverse, add `import "groq-sdk/shims/node"` (which does import polyfills). 297 | This can also be useful if you are getting the wrong TypeScript types for `Response` ([more details](https://github.com/groq/groq-typescript/tree/main/src/_shims#readme)). 298 | 299 | ### Logging and middleware 300 | 301 | You may also provide a custom `fetch` function when instantiating the client, 302 | which can be used to inspect or alter the `Request` or `Response` before/after each request: 303 | 304 | ```ts 305 | import { fetch } from 'undici'; // as one example 306 | import Groq from 'groq-sdk'; 307 | 308 | const client = new Groq({ 309 | fetch: async (url: RequestInfo, init?: RequestInit): Promise => { 310 | console.log('About to make a request', url, init); 311 | const response = await fetch(url, init); 312 | console.log('Got response', response); 313 | return response; 314 | }, 315 | }); 316 | ``` 317 | 318 | Note that if given a `DEBUG=true` environment variable, this library will log all requests and responses automatically. 319 | This is intended for debugging purposes only and may change in the future without notice. 320 | 321 | ### Configuring an HTTP(S) Agent (e.g., for proxies) 322 | 323 | By default, this library uses a stable agent for all http/https requests to reuse TCP connections, eliminating many TCP & TLS handshakes and shaving around 100ms off most requests. 324 | 325 | If you would like to disable or customize this behavior, for example to use the API behind a proxy, you can pass an `httpAgent` which is used for all requests (be they http or https), for example: 326 | 327 | 328 | ```ts 329 | import http from 'http'; 330 | import { HttpsProxyAgent } from 'https-proxy-agent'; 331 | 332 | // Configure the default for all requests: 333 | const client = new Groq({ 334 | httpAgent: new HttpsProxyAgent(process.env.PROXY_URL), 335 | }); 336 | 337 | // Override per-request: 338 | await client.chat.completions.create( 339 | { 340 | messages: [ 341 | { role: 'system', content: 'You are a helpful assistant.' }, 342 | { role: 'user', content: 'Explain the importance of low latency LLMs' }, 343 | ], 344 | model: 'llama3-8b-8192', 345 | }, 346 | { 347 | httpAgent: new http.Agent({ keepAlive: false }), 348 | }, 349 | ); 350 | ``` 351 | 352 | ## Semantic versioning 353 | 354 | This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: 355 | 356 | 1. Changes that only affect static types, without breaking runtime behavior. 357 | 2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ 358 | 3. Changes that we do not expect to impact the vast majority of users in practice. 359 | 360 | We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. 361 | 362 | We are keen for your feedback; please open an [issue](https://www.github.com/groq/groq-typescript/issues) with questions, bugs, or suggestions. 363 | 364 | ## Requirements 365 | 366 | TypeScript >= 4.5 is supported. 367 | 368 | The following runtimes are supported: 369 | 370 | - Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions. 371 | - Deno v1.28.0 or higher. 372 | - Bun 1.0 or later. 373 | - Cloudflare Workers. 374 | - Vercel Edge Runtime. 375 | - Jest 28 or greater with the `"node"` environment (`"jsdom"` is not supported at this time). 376 | - Nitro v2.6 or greater. 377 | - Web browsers: disabled by default to avoid exposing your secret API credentials. Enable browser support by explicitly setting `dangerouslyAllowBrowser` to true'. 378 |
379 | More explanation 380 | 381 | ### Why is this dangerous? 382 | 383 | Enabling the `dangerouslyAllowBrowser` option can be dangerous because it exposes your secret API credentials in the client-side code. Web browsers are inherently less secure than server environments, 384 | any user with access to the browser can potentially inspect, extract, and misuse these credentials. This could lead to unauthorized access using your credentials and potentially compromise sensitive data or functionality. 385 | 386 | ### When might this not be dangerous? 387 | 388 | In certain scenarios where enabling browser support might not pose significant risks: 389 | 390 | - Internal Tools: If the application is used solely within a controlled internal environment where the users are trusted, the risk of credential exposure can be mitigated. 391 | - Public APIs with Limited Scope: If your API has very limited scope and the exposed credentials do not grant access to sensitive data or critical operations, the potential impact of exposure is reduced. 392 | - Development or debugging purpose: Enabling this feature temporarily might be acceptable, provided the credentials are short-lived, aren't also used in production environments, or are frequently rotated. 393 | 394 |
395 | 396 | Note that React Native is not supported at this time. 397 | 398 | If you are interested in other runtime environments, please open or upvote an issue on GitHub. 399 | 400 | ## Contributing 401 | 402 | See [the contributing documentation](./CONTRIBUTING.md). 403 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting Security Issues 4 | 5 | This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. 6 | 7 | To report a security issue, please contact the Stainless team at security@stainless.com. 8 | 9 | ## Responsible Disclosure 10 | 11 | We appreciate the efforts of security researchers and individuals who help us maintain the security of 12 | SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible 13 | disclosure practices by allowing us a reasonable amount of time to investigate and address the issue 14 | before making any information public. 15 | 16 | ## Reporting Non-SDK Related Security Issues 17 | 18 | If you encounter security issues that are not directly related to SDKs but pertain to the services 19 | or products provided by Groq, please follow the respective company's security reporting guidelines. 20 | 21 | ### Groq Terms and Policies 22 | 23 | Please contact support@groq.com for any questions or concerns regarding the security of our services. 24 | 25 | --- 26 | 27 | Thank you for helping us keep the SDKs and systems they interact with secure. 28 | -------------------------------------------------------------------------------- /api.md: -------------------------------------------------------------------------------- 1 | # Shared 2 | 3 | Types: 4 | 5 | - ErrorObject 6 | - FunctionDefinition 7 | - FunctionParameters 8 | 9 | # Completions 10 | 11 | Types: 12 | 13 | - CompletionUsage 14 | 15 | # Chat 16 | 17 | ## Completions 18 | 19 | Types: 20 | 21 | - ChatCompletion 22 | - ChatCompletionAssistantMessageParam 23 | - ChatCompletionChunk 24 | - ChatCompletionContentPart 25 | - ChatCompletionContentPartImage 26 | - ChatCompletionContentPartText 27 | - ChatCompletionFunctionCallOption 28 | - ChatCompletionFunctionMessageParam 29 | - ChatCompletionMessage 30 | - ChatCompletionMessageParam 31 | - ChatCompletionMessageToolCall 32 | - ChatCompletionNamedToolChoice 33 | - ChatCompletionRole 34 | - ChatCompletionSystemMessageParam 35 | - ChatCompletionTokenLogprob 36 | - ChatCompletionTool 37 | - ChatCompletionToolChoiceOption 38 | - ChatCompletionToolMessageParam 39 | - ChatCompletionUserMessageParam 40 | 41 | Methods: 42 | 43 | - client.chat.completions.create({ ...params }) -> ChatCompletion 44 | 45 | # Embeddings 46 | 47 | Types: 48 | 49 | - CreateEmbeddingResponse 50 | - Embedding 51 | 52 | Methods: 53 | 54 | - client.embeddings.create({ ...params }) -> CreateEmbeddingResponse 55 | 56 | # Audio 57 | 58 | ## Speech 59 | 60 | Methods: 61 | 62 | - client.audio.speech.create({ ...params }) -> Response 63 | 64 | ## Transcriptions 65 | 66 | Types: 67 | 68 | - Transcription 69 | 70 | Methods: 71 | 72 | - client.audio.transcriptions.create({ ...params }) -> Transcription 73 | 74 | ## Translations 75 | 76 | Types: 77 | 78 | - Translation 79 | 80 | Methods: 81 | 82 | - client.audio.translations.create({ ...params }) -> Translation 83 | 84 | # Models 85 | 86 | Types: 87 | 88 | - Model 89 | - ModelDeleted 90 | - ModelListResponse 91 | 92 | Methods: 93 | 94 | - client.models.retrieve(model) -> Model 95 | - client.models.list() -> ModelListResponse 96 | - client.models.delete(model) -> ModelDeleted 97 | 98 | # Batches 99 | 100 | Types: 101 | 102 | - BatchCreateResponse 103 | - BatchRetrieveResponse 104 | - BatchListResponse 105 | - BatchCancelResponse 106 | 107 | Methods: 108 | 109 | - client.batches.create({ ...params }) -> BatchCreateResponse 110 | - client.batches.retrieve(batchId) -> BatchRetrieveResponse 111 | - client.batches.list() -> BatchListResponse 112 | - client.batches.cancel(batchId) -> BatchCancelResponse 113 | 114 | # Files 115 | 116 | Types: 117 | 118 | - FileCreateResponse 119 | - FileListResponse 120 | - FileDeleteResponse 121 | - FileInfoResponse 122 | 123 | Methods: 124 | 125 | - client.files.create({ ...params }) -> FileCreateResponse 126 | - client.files.list() -> FileListResponse 127 | - client.files.delete(fileId) -> FileDeleteResponse 128 | - client.files.content(fileId) -> Response 129 | - client.files.info(fileId) -> FileInfoResponse 130 | -------------------------------------------------------------------------------- /bin/check-release-environment: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | errors=() 4 | 5 | if [ -z "${NPM_TOKEN}" ]; then 6 | errors+=("The GROQ_NPM_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets") 7 | fi 8 | 9 | lenErrors=${#errors[@]} 10 | 11 | if [[ lenErrors -gt 0 ]]; then 12 | echo -e "Found the following errors in the release environment:\n" 13 | 14 | for error in "${errors[@]}"; do 15 | echo -e "- $error\n" 16 | done 17 | 18 | exit 1 19 | fi 20 | 21 | echo "The environment is ready to push releases!" 22 | 23 | -------------------------------------------------------------------------------- /bin/publish-npm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eux 4 | 5 | npm config set '//registry.npmjs.org/:_authToken' "$NPM_TOKEN" 6 | 7 | yarn build 8 | cd dist 9 | 10 | # Get latest version from npm 11 | # 12 | # If the package doesn't exist, yarn will return 13 | # {"type":"error","data":"Received invalid response from npm."} 14 | # where .data.version doesn't exist so LAST_VERSION will be an empty string. 15 | LAST_VERSION="$(yarn info --json 2> /dev/null | jq -r '.data.version')" 16 | 17 | # Get current version from package.json 18 | VERSION="$(node -p "require('./package.json').version")" 19 | 20 | # Check if current version is pre-release (e.g. alpha / beta / rc) 21 | CURRENT_IS_PRERELEASE=false 22 | if [[ "$VERSION" =~ -([a-zA-Z]+) ]]; then 23 | CURRENT_IS_PRERELEASE=true 24 | CURRENT_TAG="${BASH_REMATCH[1]}" 25 | fi 26 | 27 | # Check if last version is a stable release 28 | LAST_IS_STABLE_RELEASE=true 29 | if [[ -z "$LAST_VERSION" || "$LAST_VERSION" =~ -([a-zA-Z]+) ]]; then 30 | LAST_IS_STABLE_RELEASE=false 31 | fi 32 | 33 | # Use a corresponding alpha/beta tag if there already is a stable release and we're publishing a prerelease. 34 | if $CURRENT_IS_PRERELEASE && $LAST_IS_STABLE_RELEASE; then 35 | TAG="$CURRENT_TAG" 36 | else 37 | TAG="latest" 38 | fi 39 | 40 | # Publish with the appropriate tag 41 | yarn publish --access public --tag "$TAG" 42 | -------------------------------------------------------------------------------- /examples/.keep: -------------------------------------------------------------------------------- 1 | File generated from our OpenAPI spec by Stainless. 2 | 3 | This directory can be used to store example files demonstrating usage of this SDK. 4 | It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. 5 | -------------------------------------------------------------------------------- /examples/chat_completion.js: -------------------------------------------------------------------------------- 1 | const Groq = require('groq-sdk'); 2 | 3 | const groq = new Groq(); 4 | 5 | async function main() { 6 | groq.chat.completions 7 | .create({ 8 | // 9 | // Required parameters 10 | // 11 | messages: [ 12 | // Set an optional system message. This sets the behavior of the 13 | // assistant and can be used to provide specific instructions for 14 | // how it should behave throughout the conversation. 15 | { 16 | role: 'system', 17 | content: 'you are a helpful assistant.', 18 | }, 19 | // Set a user message for the assistant to respond to. 20 | { 21 | role: 'user', 22 | content: 'Explain the importance of low latency LLMs', 23 | }, 24 | ], 25 | 26 | // The language model which will generate the completion. 27 | model: 'mixtral-8x7b-32768', 28 | 29 | // 30 | // Optional parameters 31 | // 32 | 33 | // Controls randomness: lowering results in less random completions. 34 | // As the temperature approaches zero, the model will become deterministic 35 | // and repetitive. 36 | temperature: 0.5, 37 | 38 | // The maximum number of tokens to generate. Requests can use up to 39 | // 2048 tokens shared between prompt and completion. 40 | max_tokens: 1024, 41 | 42 | // Controls diversity via nucleus sampling: 0.5 means half of all 43 | // likelihood-weighted options are considered. 44 | top_p: 1, 45 | 46 | // A stop sequence is a predefined or user-specified text string that 47 | // signals an AI to stop generating content, ensuring its responses 48 | // remain focused and concise. Examples include punctuation marks and 49 | // markers like "[end]". 50 | stop: null, 51 | 52 | // If set, partial message deltas will be sent. 53 | stream: false, 54 | }) 55 | .then((chatCompletion) => { 56 | process.stdout.write(chatCompletion.choices[0]?.message?.content || ''); 57 | }); 58 | } 59 | 60 | main(); 61 | -------------------------------------------------------------------------------- /examples/chat_completion_stop.js: -------------------------------------------------------------------------------- 1 | const Groq = require('groq-sdk'); 2 | 3 | const groq = new Groq(); 4 | 5 | async function main() { 6 | const stream = await groq.chat.completions.create({ 7 | // 8 | // Required parameters 9 | // 10 | messages: [ 11 | // Set an optional system message. This sets the behavior of the 12 | // assistant and can be used to provide specific instructions for 13 | // how it should behave throughout the conversation. 14 | { 15 | role: 'system', 16 | content: 'you are a helpful assistant.', 17 | }, 18 | // Set a user message for the assistant to respond to. 19 | { 20 | role: 'user', 21 | content: 'Start at 1 and count to 10. Separate each number with a comma and a space', 22 | }, 23 | ], 24 | 25 | // The language model which will generate the completion. 26 | model: 'mixtral-8x7b-32768', 27 | 28 | // 29 | // Optional parameters 30 | // 31 | 32 | // Controls randomness: lowering results in less random completions. 33 | // As the temperature approaches zero, the model will become deterministic 34 | // and repetitive. 35 | temperature: 0.5, 36 | 37 | // The maximum number of tokens to generate. Requests can use up to 38 | // 2048 tokens shared between prompt and completion. 39 | max_tokens: 1024, 40 | 41 | // Controls diversity via nucleus sampling: 0.5 means half of all 42 | // likelihood-weighted options are considered. 43 | top_p: 1, 44 | 45 | // A stop sequence is a predefined or user-specified text string that 46 | // signals an AI to stop generating content, ensuring its responses 47 | // remain focused and concise. Examples include punctuation marks and 48 | // markers like "[end]". 49 | // 50 | // For this example, we will use ", 6" so that the llm stops counting at 5. 51 | // If multiple stop values are needed, an array of string may be passed, 52 | // stop: [", 6", ", six", ", Six"] 53 | stop: ', 6', 54 | 55 | // If set, partial message deltas will be sent. 56 | stream: true, 57 | }); 58 | for await (const chunk of stream) { 59 | process.stdout.write(chunk.choices[0]?.delta?.content || ''); 60 | } 61 | } 62 | 63 | main(); 64 | -------------------------------------------------------------------------------- /examples/chat_completion_streaming.js: -------------------------------------------------------------------------------- 1 | const Groq = require('groq-sdk'); 2 | 3 | const groq = new Groq(); 4 | 5 | async function main() { 6 | const stream = await groq.chat.completions.create({ 7 | // 8 | // Required parameters 9 | // 10 | messages: [ 11 | // Set an optional system message. This sets the behavior of the 12 | // assistant and can be used to provide specific instructions for 13 | // how it should behave throughout the conversation. 14 | { 15 | role: 'system', 16 | content: 'you are a helpful assistant.', 17 | }, 18 | // Set a user message for the assistant to respond to. 19 | { 20 | role: 'user', 21 | content: 'Explain the importance of low latency LLMs', 22 | }, 23 | ], 24 | 25 | // The language model which will generate the completion. 26 | model: 'mixtral-8x7b-32768', 27 | 28 | // 29 | // Optional parameters 30 | // 31 | 32 | // Controls randomness: lowering results in less random completions. 33 | // As the temperature approaches zero, the model will become deterministic 34 | // and repetitive. 35 | temperature: 0.5, 36 | 37 | // The maximum number of tokens to generate. Requests can use up to 38 | // 2048 tokens shared between prompt and completion. 39 | max_tokens: 1024, 40 | 41 | // Controls diversity via nucleus sampling: 0.5 means half of all 42 | // likelihood-weighted options are considered. 43 | top_p: 1, 44 | 45 | // A stop sequence is a predefined or user-specified text string that 46 | // signals an AI to stop generating content, ensuring its responses 47 | // remain focused and concise. Examples include punctuation marks and 48 | // markers like "[end]". 49 | stop: null, 50 | 51 | // If set, partial message deltas will be sent. 52 | stream: true, 53 | }); 54 | for await (const chunk of stream) { 55 | process.stdout.write(chunk.choices[0]?.delta?.content || ''); 56 | } 57 | } 58 | 59 | main(); 60 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { JestConfigWithTsJest } from 'ts-jest'; 2 | 3 | const config: JestConfigWithTsJest = { 4 | preset: 'ts-jest/presets/default-esm', 5 | testEnvironment: 'node', 6 | transform: { 7 | '^.+\\.(t|j)sx?$': ['@swc/jest', { sourceMaps: 'inline' }], 8 | }, 9 | moduleNameMapper: { 10 | '^groq-sdk$': '/src/index.ts', 11 | '^groq-sdk/_shims/auto/(.*)$': '/src/_shims/auto/$1-node', 12 | '^groq-sdk/(.*)$': '/src/$1', 13 | }, 14 | modulePathIgnorePatterns: [ 15 | '/ecosystem-tests/', 16 | '/dist/', 17 | '/deno/', 18 | '/deno_tests/', 19 | ], 20 | testPathIgnorePatterns: ['scripts'], 21 | }; 22 | 23 | export default config; 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "groq-sdk", 3 | "version": "0.23.0", 4 | "description": "The official TypeScript library for the Groq API", 5 | "author": "Groq ", 6 | "types": "dist/index.d.ts", 7 | "main": "dist/index.js", 8 | "type": "commonjs", 9 | "repository": "github:groq/groq-typescript", 10 | "license": "Apache-2.0", 11 | "packageManager": "yarn@1.22.22", 12 | "files": [ 13 | "**/*" 14 | ], 15 | "private": false, 16 | "scripts": { 17 | "test": "./scripts/test", 18 | "build": "./scripts/build", 19 | "prepublishOnly": "echo 'to publish, run yarn build && (cd dist; yarn publish)' && exit 1", 20 | "format": "prettier --write --cache --cache-strategy metadata . !dist", 21 | "prepare": "if ./scripts/utils/check-is-in-git-install.sh; then ./scripts/build && ./scripts/utils/git-swap.sh; fi", 22 | "tsn": "ts-node -r tsconfig-paths/register", 23 | "lint": "./scripts/lint", 24 | "fix": "./scripts/format" 25 | }, 26 | "dependencies": { 27 | "@types/node": "^18.11.18", 28 | "@types/node-fetch": "^2.6.4", 29 | "abort-controller": "^3.0.0", 30 | "agentkeepalive": "^4.2.1", 31 | "form-data-encoder": "1.7.2", 32 | "formdata-node": "^4.3.2", 33 | "node-fetch": "^2.6.7" 34 | }, 35 | "devDependencies": { 36 | "@swc/core": "^1.3.102", 37 | "@swc/jest": "^0.2.29", 38 | "@types/jest": "^29.4.0", 39 | "@typescript-eslint/eslint-plugin": "^6.7.0", 40 | "@typescript-eslint/parser": "^6.7.0", 41 | "eslint": "^8.49.0", 42 | "eslint-plugin-prettier": "^5.0.1", 43 | "eslint-plugin-unused-imports": "^3.0.0", 44 | "iconv-lite": "^0.6.3", 45 | "jest": "^29.4.0", 46 | "prettier": "^3.0.0", 47 | "ts-jest": "^29.1.0", 48 | "ts-node": "^10.5.0", 49 | "tsc-multi": "^1.1.0", 50 | "tsconfig-paths": "^4.0.0", 51 | "typescript": "^4.8.2" 52 | }, 53 | "sideEffects": [ 54 | "./_shims/index.js", 55 | "./_shims/index.mjs", 56 | "./shims/node.js", 57 | "./shims/node.mjs", 58 | "./shims/web.js", 59 | "./shims/web.mjs" 60 | ], 61 | "imports": { 62 | "groq-sdk": ".", 63 | "groq-sdk/*": "./src/*" 64 | }, 65 | "exports": { 66 | "./_shims/auto/*": { 67 | "deno": { 68 | "types": "./dist/_shims/auto/*.d.ts", 69 | "require": "./dist/_shims/auto/*.js", 70 | "default": "./dist/_shims/auto/*.mjs" 71 | }, 72 | "bun": { 73 | "types": "./dist/_shims/auto/*.d.ts", 74 | "require": "./dist/_shims/auto/*-bun.js", 75 | "default": "./dist/_shims/auto/*-bun.mjs" 76 | }, 77 | "browser": { 78 | "types": "./dist/_shims/auto/*.d.ts", 79 | "require": "./dist/_shims/auto/*.js", 80 | "default": "./dist/_shims/auto/*.mjs" 81 | }, 82 | "worker": { 83 | "types": "./dist/_shims/auto/*.d.ts", 84 | "require": "./dist/_shims/auto/*.js", 85 | "default": "./dist/_shims/auto/*.mjs" 86 | }, 87 | "workerd": { 88 | "types": "./dist/_shims/auto/*.d.ts", 89 | "require": "./dist/_shims/auto/*.js", 90 | "default": "./dist/_shims/auto/*.mjs" 91 | }, 92 | "node": { 93 | "types": "./dist/_shims/auto/*-node.d.ts", 94 | "require": "./dist/_shims/auto/*-node.js", 95 | "default": "./dist/_shims/auto/*-node.mjs" 96 | }, 97 | "types": "./dist/_shims/auto/*.d.ts", 98 | "require": "./dist/_shims/auto/*.js", 99 | "default": "./dist/_shims/auto/*.mjs" 100 | }, 101 | ".": { 102 | "require": { 103 | "types": "./dist/index.d.ts", 104 | "default": "./dist/index.js" 105 | }, 106 | "types": "./dist/index.d.mts", 107 | "default": "./dist/index.mjs" 108 | }, 109 | "./*.mjs": { 110 | "types": "./dist/*.d.ts", 111 | "default": "./dist/*.mjs" 112 | }, 113 | "./*.js": { 114 | "types": "./dist/*.d.ts", 115 | "default": "./dist/*.js" 116 | }, 117 | "./*": { 118 | "types": "./dist/*.d.ts", 119 | "require": "./dist/*.js", 120 | "default": "./dist/*.mjs" 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": { 3 | ".": {} 4 | }, 5 | "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", 6 | "include-v-in-tag": true, 7 | "include-component-in-tag": false, 8 | "versioning": "prerelease", 9 | "prerelease": true, 10 | "bump-minor-pre-major": true, 11 | "bump-patch-for-minor-pre-major": false, 12 | "pull-request-header": "Automated Release PR", 13 | "pull-request-title-pattern": "release: ${version}", 14 | "changelog-sections": [ 15 | { 16 | "type": "feat", 17 | "section": "Features" 18 | }, 19 | { 20 | "type": "fix", 21 | "section": "Bug Fixes" 22 | }, 23 | { 24 | "type": "perf", 25 | "section": "Performance Improvements" 26 | }, 27 | { 28 | "type": "revert", 29 | "section": "Reverts" 30 | }, 31 | { 32 | "type": "chore", 33 | "section": "Chores" 34 | }, 35 | { 36 | "type": "docs", 37 | "section": "Documentation" 38 | }, 39 | { 40 | "type": "style", 41 | "section": "Styles" 42 | }, 43 | { 44 | "type": "refactor", 45 | "section": "Refactors" 46 | }, 47 | { 48 | "type": "test", 49 | "section": "Tests", 50 | "hidden": true 51 | }, 52 | { 53 | "type": "build", 54 | "section": "Build System" 55 | }, 56 | { 57 | "type": "ci", 58 | "section": "Continuous Integration", 59 | "hidden": true 60 | } 61 | ], 62 | "reviewers": [ 63 | "gradenr" 64 | ], 65 | "release-type": "node", 66 | "extra-files": [ 67 | "src/version.ts", 68 | "README.md" 69 | ] 70 | } 71 | -------------------------------------------------------------------------------- /scripts/bootstrap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ]; then 8 | brew bundle check >/dev/null 2>&1 || { 9 | echo "==> Installing Homebrew dependencies…" 10 | brew bundle 11 | } 12 | fi 13 | 14 | echo "==> Installing Node dependencies…" 15 | 16 | PACKAGE_MANAGER=$(command -v yarn >/dev/null 2>&1 && echo "yarn" || echo "npm") 17 | 18 | $PACKAGE_MANAGER install 19 | -------------------------------------------------------------------------------- /scripts/build: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exuo pipefail 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | node scripts/utils/check-version.cjs 8 | 9 | # Build into dist and will publish the package from there, 10 | # so that src/resources/foo.ts becomes /resources/foo.js 11 | # This way importing from `"groq-sdk/resources/foo"` works 12 | # even with `"moduleResolution": "node"` 13 | 14 | rm -rf dist; mkdir dist 15 | # Copy src to dist/src and build from dist/src into dist, so that 16 | # the source map for index.js.map will refer to ./src/index.ts etc 17 | cp -rp src README.md dist 18 | rm dist/src/_shims/*-deno.ts dist/src/_shims/auto/*-deno.ts 19 | for file in LICENSE CHANGELOG.md; do 20 | if [ -e "${file}" ]; then cp "${file}" dist; fi 21 | done 22 | if [ -e "bin/cli" ]; then 23 | mkdir dist/bin 24 | cp -p "bin/cli" dist/bin/; 25 | fi 26 | # this converts the export map paths for the dist directory 27 | # and does a few other minor things 28 | node scripts/utils/make-dist-package-json.cjs > dist/package.json 29 | 30 | # build to .js/.mjs/.d.ts files 31 | npm exec tsc-multi 32 | # copy over handwritten .js/.mjs/.d.ts files 33 | cp src/_shims/*.{d.ts,js,mjs,md} dist/_shims 34 | cp src/_shims/auto/*.{d.ts,js,mjs} dist/_shims/auto 35 | # we need to add exports = module.exports = Groq to index.js; 36 | # No way to get that from index.ts because it would cause compile errors 37 | # when building .mjs 38 | node scripts/utils/fix-index-exports.cjs 39 | # with "moduleResolution": "nodenext", if ESM resolves to index.d.ts, 40 | # it'll have TS errors on the default import. But if it resolves to 41 | # index.d.mts the default import will work (even though both files have 42 | # the same export default statement) 43 | cp dist/index.d.ts dist/index.d.mts 44 | cp tsconfig.dist-src.json dist/src/tsconfig.json 45 | 46 | node scripts/utils/postprocess-files.cjs 47 | 48 | # make sure that nothing crashes when we require the output CJS or 49 | # import the output ESM 50 | (cd dist && node -e 'require("groq-sdk")') 51 | (cd dist && node -e 'import("groq-sdk")' --input-type=module) 52 | 53 | if [ -e ./scripts/build-deno ] 54 | then 55 | ./scripts/build-deno 56 | fi 57 | -------------------------------------------------------------------------------- /scripts/format: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | echo "==> Running eslint --fix" 8 | ESLINT_USE_FLAT_CONFIG="false" ./node_modules/.bin/eslint --fix --ext ts,js . 9 | -------------------------------------------------------------------------------- /scripts/lint: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | echo "==> Running eslint" 8 | ESLINT_USE_FLAT_CONFIG="false" ./node_modules/.bin/eslint --ext ts,js . 9 | 10 | echo "==> Running tsc" 11 | ./node_modules/.bin/tsc --noEmit 12 | -------------------------------------------------------------------------------- /scripts/mock: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | if [[ -n "$1" && "$1" != '--'* ]]; then 8 | URL="$1" 9 | shift 10 | else 11 | URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" 12 | fi 13 | 14 | # Check if the URL is empty 15 | if [ -z "$URL" ]; then 16 | echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" 17 | exit 1 18 | fi 19 | 20 | echo "==> Starting mock server with URL ${URL}" 21 | 22 | # Run prism mock on the given spec 23 | if [ "$1" == "--daemon" ]; then 24 | npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" &> .prism.log & 25 | 26 | # Wait for server to come online 27 | echo -n "Waiting for server" 28 | while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do 29 | echo -n "." 30 | sleep 0.1 31 | done 32 | 33 | if grep -q "✖ fatal" ".prism.log"; then 34 | cat .prism.log 35 | exit 1 36 | fi 37 | 38 | echo 39 | else 40 | npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" 41 | fi 42 | -------------------------------------------------------------------------------- /scripts/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | RED='\033[0;31m' 8 | GREEN='\033[0;32m' 9 | YELLOW='\033[0;33m' 10 | NC='\033[0m' # No Color 11 | 12 | function prism_is_running() { 13 | curl --silent "http://localhost:4010" >/dev/null 2>&1 14 | } 15 | 16 | kill_server_on_port() { 17 | pids=$(lsof -t -i tcp:"$1" || echo "") 18 | if [ "$pids" != "" ]; then 19 | kill "$pids" 20 | echo "Stopped $pids." 21 | fi 22 | } 23 | 24 | function is_overriding_api_base_url() { 25 | [ -n "$TEST_API_BASE_URL" ] 26 | } 27 | 28 | if ! is_overriding_api_base_url && ! prism_is_running ; then 29 | # When we exit this script, make sure to kill the background mock server process 30 | trap 'kill_server_on_port 4010' EXIT 31 | 32 | # Start the dev server 33 | ./scripts/mock --daemon 34 | fi 35 | 36 | if is_overriding_api_base_url ; then 37 | echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" 38 | echo 39 | elif ! prism_is_running ; then 40 | echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" 41 | echo -e "running against your OpenAPI spec." 42 | echo 43 | echo -e "To run the server, pass in the path or url of your OpenAPI" 44 | echo -e "spec to the prism command:" 45 | echo 46 | echo -e " \$ ${YELLOW}npm exec --package=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" 47 | echo 48 | 49 | exit 1 50 | else 51 | echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" 52 | echo 53 | fi 54 | 55 | echo "==> Running tests" 56 | ./node_modules/.bin/jest "$@" 57 | -------------------------------------------------------------------------------- /scripts/utils/check-is-in-git-install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Check if you happen to call prepare for a repository that's already in node_modules. 3 | [ "$(basename "$(dirname "$PWD")")" = 'node_modules' ] || 4 | # The name of the containing directory that 'npm` uses, which looks like 5 | # $HOME/.npm/_cacache/git-cloneXXXXXX 6 | [ "$(basename "$(dirname "$PWD")")" = 'tmp' ] || 7 | # The name of the containing directory that 'yarn` uses, which looks like 8 | # $(yarn cache dir)/.tmp/XXXXX 9 | [ "$(basename "$(dirname "$PWD")")" = '.tmp' ] 10 | -------------------------------------------------------------------------------- /scripts/utils/check-version.cjs: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const main = () => { 5 | const pkg = require('../../package.json'); 6 | const version = pkg['version']; 7 | if (!version) throw 'The version property is not set in the package.json file'; 8 | if (typeof version !== 'string') { 9 | throw `Unexpected type for the package.json version field; got ${typeof version}, expected string`; 10 | } 11 | 12 | const versionFile = path.resolve(__dirname, '..', '..', 'src', 'version.ts'); 13 | const contents = fs.readFileSync(versionFile, 'utf8'); 14 | const output = contents.replace(/(export const VERSION = ')(.*)(')/g, `$1${version}$3`); 15 | fs.writeFileSync(versionFile, output); 16 | }; 17 | 18 | if (require.main === module) { 19 | main(); 20 | } 21 | -------------------------------------------------------------------------------- /scripts/utils/fix-index-exports.cjs: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const indexJs = 5 | process.env['DIST_PATH'] ? 6 | path.resolve(process.env['DIST_PATH'], 'index.js') 7 | : path.resolve(__dirname, '..', '..', 'dist', 'index.js'); 8 | 9 | let before = fs.readFileSync(indexJs, 'utf8'); 10 | let after = before.replace( 11 | /^\s*exports\.default\s*=\s*(\w+)/m, 12 | 'exports = module.exports = $1;\nexports.default = $1', 13 | ); 14 | fs.writeFileSync(indexJs, after, 'utf8'); 15 | -------------------------------------------------------------------------------- /scripts/utils/git-swap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -exuo pipefail 3 | # the package is published to NPM from ./dist 4 | # we want the final file structure for git installs to match the npm installs, so we 5 | 6 | # delete everything except ./dist and ./node_modules 7 | find . -maxdepth 1 -mindepth 1 ! -name 'dist' ! -name 'node_modules' -exec rm -rf '{}' + 8 | 9 | # move everything from ./dist to . 10 | mv dist/* . 11 | 12 | # delete the now-empty ./dist 13 | rmdir dist 14 | -------------------------------------------------------------------------------- /scripts/utils/make-dist-package-json.cjs: -------------------------------------------------------------------------------- 1 | const pkgJson = require(process.env['PKG_JSON_PATH'] || '../../package.json'); 2 | 3 | function processExportMap(m) { 4 | for (const key in m) { 5 | const value = m[key]; 6 | if (typeof value === 'string') m[key] = value.replace(/^\.\/dist\//, './'); 7 | else processExportMap(value); 8 | } 9 | } 10 | processExportMap(pkgJson.exports); 11 | 12 | for (const key of ['types', 'main', 'module']) { 13 | if (typeof pkgJson[key] === 'string') pkgJson[key] = pkgJson[key].replace(/^(\.\/)?dist\//, './'); 14 | } 15 | 16 | delete pkgJson.devDependencies; 17 | delete pkgJson.scripts.prepack; 18 | delete pkgJson.scripts.prepublishOnly; 19 | delete pkgJson.scripts.prepare; 20 | 21 | console.log(JSON.stringify(pkgJson, null, 2)); 22 | -------------------------------------------------------------------------------- /scripts/utils/postprocess-files.cjs: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { parse } = require('@typescript-eslint/parser'); 4 | 5 | const pkgImportPath = process.env['PKG_IMPORT_PATH'] ?? 'groq-sdk/'; 6 | 7 | const distDir = 8 | process.env['DIST_PATH'] ? 9 | path.resolve(process.env['DIST_PATH']) 10 | : path.resolve(__dirname, '..', '..', 'dist'); 11 | const distSrcDir = path.join(distDir, 'src'); 12 | 13 | /** 14 | * Quick and dirty AST traversal 15 | */ 16 | function traverse(node, visitor) { 17 | if (!node || typeof node.type !== 'string') return; 18 | visitor.node?.(node); 19 | visitor[node.type]?.(node); 20 | for (const key in node) { 21 | const value = node[key]; 22 | if (Array.isArray(value)) { 23 | for (const elem of value) traverse(elem, visitor); 24 | } else if (value instanceof Object) { 25 | traverse(value, visitor); 26 | } 27 | } 28 | } 29 | 30 | /** 31 | * Helper method for replacing arbitrary ranges of text in input code. 32 | * 33 | * The `replacer` is a function that will be called with a mini-api. For example: 34 | * 35 | * replaceRanges('foobar', ({ replace }) => replace([0, 3], 'baz')) // 'bazbar' 36 | * 37 | * The replaced ranges must not be overlapping. 38 | */ 39 | function replaceRanges(code, replacer) { 40 | const replacements = []; 41 | replacer({ replace: (range, replacement) => replacements.push({ range, replacement }) }); 42 | 43 | if (!replacements.length) return code; 44 | replacements.sort((a, b) => a.range[0] - b.range[0]); 45 | const overlapIndex = replacements.findIndex( 46 | (r, index) => index > 0 && replacements[index - 1].range[1] > r.range[0], 47 | ); 48 | if (overlapIndex >= 0) { 49 | throw new Error( 50 | `replacements overlap: ${JSON.stringify(replacements[overlapIndex - 1])} and ${JSON.stringify( 51 | replacements[overlapIndex], 52 | )}`, 53 | ); 54 | } 55 | 56 | const parts = []; 57 | let end = 0; 58 | for (const { 59 | range: [from, to], 60 | replacement, 61 | } of replacements) { 62 | if (from > end) parts.push(code.substring(end, from)); 63 | parts.push(replacement); 64 | end = to; 65 | } 66 | if (end < code.length) parts.push(code.substring(end)); 67 | return parts.join(''); 68 | } 69 | 70 | /** 71 | * Like calling .map(), where the iteratee is called on the path in every import or export from statement. 72 | * @returns the transformed code 73 | */ 74 | function mapModulePaths(code, iteratee) { 75 | const ast = parse(code, { range: true }); 76 | return replaceRanges(code, ({ replace }) => 77 | traverse(ast, { 78 | node(node) { 79 | switch (node.type) { 80 | case 'ImportDeclaration': 81 | case 'ExportNamedDeclaration': 82 | case 'ExportAllDeclaration': 83 | case 'ImportExpression': 84 | if (node.source) { 85 | const { range, value } = node.source; 86 | const transformed = iteratee(value); 87 | if (transformed !== value) { 88 | replace(range, JSON.stringify(transformed)); 89 | } 90 | } 91 | } 92 | }, 93 | }), 94 | ); 95 | } 96 | 97 | async function* walk(dir) { 98 | for await (const d of await fs.promises.opendir(dir)) { 99 | const entry = path.join(dir, d.name); 100 | if (d.isDirectory()) yield* walk(entry); 101 | else if (d.isFile()) yield entry; 102 | } 103 | } 104 | 105 | async function postprocess() { 106 | for await (const file of walk(path.resolve(__dirname, '..', '..', 'dist'))) { 107 | if (!/\.([cm]?js|(\.d)?[cm]?ts)$/.test(file)) continue; 108 | 109 | const code = await fs.promises.readFile(file, 'utf8'); 110 | 111 | let transformed = mapModulePaths(code, (importPath) => { 112 | if (file.startsWith(distSrcDir)) { 113 | if (importPath.startsWith(pkgImportPath)) { 114 | // convert self-references in dist/src to relative paths 115 | let relativePath = path.relative( 116 | path.dirname(file), 117 | path.join(distSrcDir, importPath.substring(pkgImportPath.length)), 118 | ); 119 | if (!relativePath.startsWith('.')) relativePath = `./${relativePath}`; 120 | return relativePath; 121 | } 122 | return importPath; 123 | } 124 | if (importPath.startsWith('.')) { 125 | // add explicit file extensions to relative imports 126 | const { dir, name } = path.parse(importPath); 127 | const ext = /\.mjs$/.test(file) ? '.mjs' : '.js'; 128 | return `${dir}/${name}${ext}`; 129 | } 130 | return importPath; 131 | }); 132 | 133 | if (file.startsWith(distSrcDir) && !file.endsWith('_shims/index.d.ts')) { 134 | // strip out `unknown extends Foo ? never :` shim guards in dist/src 135 | // to prevent errors from appearing in Go To Source 136 | transformed = transformed.replace( 137 | new RegExp('unknown extends (typeof )?\\S+ \\? \\S+ :\\s*'.replace(/\s+/, '\\s+'), 'gm'), 138 | // replace with same number of characters to avoid breaking source maps 139 | (match) => ' '.repeat(match.length), 140 | ); 141 | } 142 | 143 | if (file.endsWith('.d.ts')) { 144 | // work around bad tsc behavior 145 | // if we have `import { type Readable } from 'groq-sdk/_shims/index'`, 146 | // tsc sometimes replaces `Readable` with `import("stream").Readable` inline 147 | // in the output .d.ts 148 | transformed = transformed.replace(/import\("stream"\).Readable/g, 'Readable'); 149 | } 150 | 151 | // strip out lib="dom" and types="node" references; these are needed at build time, 152 | // but would pollute the user's TS environment 153 | transformed = transformed.replace( 154 | /^ *\/\/\/ * ' '.repeat(match.length - 1) + '\n', 157 | ); 158 | 159 | if (transformed !== code) { 160 | await fs.promises.writeFile(file, transformed, 'utf8'); 161 | console.error(`wrote ${path.relative(process.cwd(), file)}`); 162 | } 163 | } 164 | } 165 | postprocess(); 166 | -------------------------------------------------------------------------------- /scripts/utils/upload-artifact.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -exuo pipefail 3 | 4 | RESPONSE=$(curl -X POST "$URL" \ 5 | -H "Authorization: Bearer $AUTH" \ 6 | -H "Content-Type: application/json") 7 | 8 | SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') 9 | 10 | if [[ "$SIGNED_URL" == "null" ]]; then 11 | echo -e "\033[31mFailed to get signed URL.\033[0m" 12 | exit 1 13 | fi 14 | 15 | UPLOAD_RESPONSE=$(tar -cz dist | curl -v -X PUT \ 16 | -H "Content-Type: application/gzip" \ 17 | --data-binary @- "$SIGNED_URL" 2>&1) 18 | 19 | if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then 20 | echo -e "\033[32mUploaded build to Stainless storage.\033[0m" 21 | echo -e "\033[32mInstallation: npm install 'https://pkg.stainless.com/s/groqcloud-node/$SHA'\033[0m" 22 | else 23 | echo -e "\033[31mFailed to upload artifact.\033[0m" 24 | exit 1 25 | fi 26 | -------------------------------------------------------------------------------- /src/_shims/MultipartBody.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | export class MultipartBody { 5 | constructor(public body: any) {} 6 | get [Symbol.toStringTag](): string { 7 | return 'MultipartBody'; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/_shims/README.md: -------------------------------------------------------------------------------- 1 | # 👋 Wondering what everything in here does? 2 | 3 | `groq-sdk` supports a wide variety of runtime environments like Node.js, Deno, Bun, browsers, and various 4 | edge runtimes, as well as both CommonJS (CJS) and EcmaScript Modules (ESM). 5 | 6 | To do this, `groq-sdk` provides shims for either using `node-fetch` when in Node (because `fetch` is still experimental there) or the global `fetch` API built into the environment when not in Node. 7 | 8 | It uses [conditional exports](https://nodejs.org/api/packages.html#conditional-exports) to 9 | automatically select the correct shims for each environment. However, conditional exports are a fairly new 10 | feature and not supported everywhere. For instance, the TypeScript `"moduleResolution": "node"` 11 | 12 | setting doesn't consult the `exports` map, compared to `"moduleResolution": "nodeNext"`, which does. 13 | Unfortunately that's still the default setting, and it can result in errors like 14 | getting the wrong raw `Response` type from `.asResponse()`, for example. 15 | 16 | The user can work around these issues by manually importing one of: 17 | 18 | - `import 'groq-sdk/shims/node'` 19 | - `import 'groq-sdk/shims/web'` 20 | 21 | All of the code here in `_shims` handles selecting the automatic default shims or manual overrides. 22 | 23 | ### How it works - Runtime 24 | 25 | Runtime shims get installed by calling `setShims` exported by `groq-sdk/_shims/registry`. 26 | 27 | Manually importing `groq-sdk/shims/node` or `groq-sdk/shims/web`, calls `setShims` with the respective runtime shims. 28 | 29 | All client code imports shims from `groq-sdk/_shims/index`, which: 30 | 31 | - checks if shims have been set manually 32 | - if not, calls `setShims` with the shims from `groq-sdk/_shims/auto/runtime` 33 | - re-exports the installed shims from `groq-sdk/_shims/registry`. 34 | 35 | `groq-sdk/_shims/auto/runtime` exports web runtime shims. 36 | If the `node` export condition is set, the export map replaces it with `groq-sdk/_shims/auto/runtime-node`. 37 | 38 | ### How it works - Type time 39 | 40 | All client code imports shim types from `groq-sdk/_shims/index`, which selects the manual types from `groq-sdk/_shims/manual-types` if they have been declared, otherwise it exports the auto types from `groq-sdk/_shims/auto/types`. 41 | 42 | `groq-sdk/_shims/manual-types` exports an empty namespace. 43 | Manually importing `groq-sdk/shims/node` or `groq-sdk/shims/web` merges declarations into this empty namespace, so they get picked up by `groq-sdk/_shims/index`. 44 | 45 | `groq-sdk/_shims/auto/types` exports web type definitions. 46 | If the `node` export condition is set, the export map replaces it with `groq-sdk/_shims/auto/types-node`, though TS only picks this up if `"moduleResolution": "nodenext"` or `"moduleResolution": "bundler"`. 47 | -------------------------------------------------------------------------------- /src/_shims/auto/runtime-bun.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | export * from '../bun-runtime'; 5 | -------------------------------------------------------------------------------- /src/_shims/auto/runtime-deno.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | export * from '../web-runtime'; 5 | -------------------------------------------------------------------------------- /src/_shims/auto/runtime-node.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | export * from '../node-runtime'; 5 | -------------------------------------------------------------------------------- /src/_shims/auto/runtime.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | export * from '../web-runtime'; 5 | -------------------------------------------------------------------------------- /src/_shims/auto/types-deno.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | export * from '../web-types'; 5 | -------------------------------------------------------------------------------- /src/_shims/auto/types-node.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | export * from '../node-types'; 5 | -------------------------------------------------------------------------------- /src/_shims/auto/types.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | export type Agent = any; 5 | 6 | // @ts-ignore 7 | declare const _fetch: unknown extends typeof fetch ? never : typeof fetch; 8 | export { _fetch as fetch }; 9 | 10 | // @ts-ignore 11 | type _Request = unknown extends Request ? never : Request; 12 | export { _Request as Request }; 13 | 14 | // @ts-ignore 15 | type _RequestInfo = unknown extends RequestInfo ? never : RequestInfo; 16 | export { type _RequestInfo as RequestInfo }; 17 | 18 | // @ts-ignore 19 | type _RequestInit = unknown extends RequestInit ? never : RequestInit; 20 | export { type _RequestInit as RequestInit }; 21 | 22 | // @ts-ignore 23 | type _Response = unknown extends Response ? never : Response; 24 | export { _Response as Response }; 25 | 26 | // @ts-ignore 27 | type _ResponseInit = unknown extends ResponseInit ? never : ResponseInit; 28 | export { type _ResponseInit as ResponseInit }; 29 | 30 | // @ts-ignore 31 | type _ResponseType = unknown extends ResponseType ? never : ResponseType; 32 | export { type _ResponseType as ResponseType }; 33 | 34 | // @ts-ignore 35 | type _BodyInit = unknown extends BodyInit ? never : BodyInit; 36 | export { type _BodyInit as BodyInit }; 37 | 38 | // @ts-ignore 39 | type _Headers = unknown extends Headers ? never : Headers; 40 | export { _Headers as Headers }; 41 | 42 | // @ts-ignore 43 | type _HeadersInit = unknown extends HeadersInit ? never : HeadersInit; 44 | export { type _HeadersInit as HeadersInit }; 45 | 46 | type EndingType = 'native' | 'transparent'; 47 | 48 | export interface BlobPropertyBag { 49 | endings?: EndingType; 50 | type?: string; 51 | } 52 | 53 | export interface FilePropertyBag extends BlobPropertyBag { 54 | lastModified?: number; 55 | } 56 | 57 | export type FileFromPathOptions = Omit; 58 | 59 | // @ts-ignore 60 | type _FormData = unknown extends FormData ? never : FormData; 61 | // @ts-ignore 62 | declare const _FormData: unknown extends typeof FormData ? never : typeof FormData; 63 | export { _FormData as FormData }; 64 | 65 | // @ts-ignore 66 | type _File = unknown extends File ? never : File; 67 | // @ts-ignore 68 | declare const _File: unknown extends typeof File ? never : typeof File; 69 | export { _File as File }; 70 | 71 | // @ts-ignore 72 | type _Blob = unknown extends Blob ? never : Blob; 73 | // @ts-ignore 74 | declare const _Blob: unknown extends typeof Blob ? never : typeof Blob; 75 | export { _Blob as Blob }; 76 | 77 | export declare class Readable { 78 | readable: boolean; 79 | readonly readableEnded: boolean; 80 | readonly readableFlowing: boolean | null; 81 | readonly readableHighWaterMark: number; 82 | readonly readableLength: number; 83 | readonly readableObjectMode: boolean; 84 | destroyed: boolean; 85 | read(size?: number): any; 86 | pause(): this; 87 | resume(): this; 88 | isPaused(): boolean; 89 | destroy(error?: Error): this; 90 | [Symbol.asyncIterator](): AsyncIterableIterator; 91 | } 92 | 93 | export declare class FsReadStream extends Readable { 94 | path: {}; // node type is string | Buffer 95 | } 96 | 97 | // @ts-ignore 98 | type _ReadableStream = unknown extends ReadableStream ? never : ReadableStream; 99 | // @ts-ignore 100 | declare const _ReadableStream: unknown extends typeof ReadableStream ? never : typeof ReadableStream; 101 | export { _ReadableStream as ReadableStream }; 102 | -------------------------------------------------------------------------------- /src/_shims/auto/types.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | -------------------------------------------------------------------------------- /src/_shims/auto/types.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | -------------------------------------------------------------------------------- /src/_shims/bun-runtime.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | import { type Shims } from './registry'; 5 | import { getRuntime as getWebRuntime } from './web-runtime'; 6 | import { ReadStream as FsReadStream } from 'node:fs'; 7 | 8 | export function getRuntime(): Shims { 9 | const runtime = getWebRuntime(); 10 | function isFsReadStream(value: any): value is FsReadStream { 11 | return value instanceof FsReadStream; 12 | } 13 | return { ...runtime, isFsReadStream }; 14 | } 15 | -------------------------------------------------------------------------------- /src/_shims/index-deno.ts: -------------------------------------------------------------------------------- 1 | import { MultipartBody } from './MultipartBody'; 2 | import { type RequestOptions } from '../core'; 3 | 4 | export const kind: string = 'web'; 5 | 6 | export type Agent = any; 7 | 8 | const _fetch = fetch; 9 | type _fetch = typeof fetch; 10 | export { _fetch as fetch }; 11 | 12 | const _Request = Request; 13 | type _Request = Request; 14 | export { _Request as Request }; 15 | 16 | type _RequestInfo = RequestInfo; 17 | export { type _RequestInfo as RequestInfo }; 18 | 19 | type _RequestInit = RequestInit; 20 | export { type _RequestInit as RequestInit }; 21 | 22 | const _Response = Response; 23 | type _Response = Response; 24 | export { _Response as Response }; 25 | 26 | type _ResponseInit = ResponseInit; 27 | export { type _ResponseInit as ResponseInit }; 28 | 29 | type _ResponseType = ResponseType; 30 | export { type _ResponseType as ResponseType }; 31 | 32 | type _BodyInit = BodyInit; 33 | export { type _BodyInit as BodyInit }; 34 | 35 | const _Headers = Headers; 36 | type _Headers = Headers; 37 | export { _Headers as Headers }; 38 | 39 | type _HeadersInit = HeadersInit; 40 | export { type _HeadersInit as HeadersInit }; 41 | 42 | type EndingType = 'native' | 'transparent'; 43 | 44 | export interface BlobPropertyBag { 45 | endings?: EndingType; 46 | type?: string; 47 | } 48 | 49 | export interface FilePropertyBag extends BlobPropertyBag { 50 | lastModified?: number; 51 | } 52 | 53 | export type FileFromPathOptions = Omit; 54 | 55 | const _FormData = FormData; 56 | type _FormData = FormData; 57 | export { _FormData as FormData }; 58 | 59 | const _File = File; 60 | type _File = File; 61 | export { _File as File }; 62 | 63 | const _Blob = Blob; 64 | type _Blob = Blob; 65 | export { _Blob as Blob }; 66 | 67 | export async function getMultipartRequestOptions>( 68 | form: FormData, 69 | opts: RequestOptions, 70 | ): Promise> { 71 | return { 72 | ...opts, 73 | body: new MultipartBody(form) as any, 74 | }; 75 | } 76 | 77 | export function getDefaultAgent(url: string) { 78 | return undefined; 79 | } 80 | export function fileFromPath() { 81 | throw new Error( 82 | 'The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/groq/groq-typescript#file-uploads', 83 | ); 84 | } 85 | 86 | export const isFsReadStream = (value: any) => false; 87 | 88 | export declare class Readable { 89 | readable: boolean; 90 | readonly readableEnded: boolean; 91 | readonly readableFlowing: boolean | null; 92 | readonly readableHighWaterMark: number; 93 | readonly readableLength: number; 94 | readonly readableObjectMode: boolean; 95 | destroyed: boolean; 96 | read(size?: number): any; 97 | pause(): this; 98 | resume(): this; 99 | isPaused(): boolean; 100 | destroy(error?: Error): this; 101 | [Symbol.asyncIterator](): AsyncIterableIterator; 102 | } 103 | 104 | export declare class FsReadStream extends Readable { 105 | path: {}; // node type is string | Buffer 106 | } 107 | 108 | const _ReadableStream = ReadableStream; 109 | type _ReadableStream = ReadableStream; 110 | export { _ReadableStream as ReadableStream }; 111 | 112 | export const init = () => {}; 113 | -------------------------------------------------------------------------------- /src/_shims/index.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | import { manual } from './manual-types'; 5 | import * as auto from 'groq-sdk/_shims/auto/types'; 6 | import { type RequestOptions } from '../core'; 7 | 8 | type SelectType = unknown extends Manual ? Auto : Manual; 9 | 10 | export const kind: string; 11 | 12 | // @ts-ignore 13 | export type Agent = SelectType; 14 | 15 | // @ts-ignore 16 | export const fetch: SelectType; 17 | 18 | // @ts-ignore 19 | export type Request = SelectType; 20 | // @ts-ignore 21 | export type RequestInfo = SelectType; 22 | // @ts-ignore 23 | export type RequestInit = SelectType; 24 | 25 | // @ts-ignore 26 | export type Response = SelectType; 27 | // @ts-ignore 28 | export type ResponseInit = SelectType; 29 | // @ts-ignore 30 | export type ResponseType = SelectType; 31 | // @ts-ignore 32 | export type BodyInit = SelectType; 33 | // @ts-ignore 34 | export type Headers = SelectType; 35 | // @ts-ignore 36 | export const Headers: SelectType; 37 | // @ts-ignore 38 | export type HeadersInit = SelectType; 39 | 40 | // @ts-ignore 41 | export type BlobPropertyBag = SelectType; 42 | // @ts-ignore 43 | export type FilePropertyBag = SelectType; 44 | // @ts-ignore 45 | export type FileFromPathOptions = SelectType; 46 | // @ts-ignore 47 | export type FormData = SelectType; 48 | // @ts-ignore 49 | export const FormData: SelectType; 50 | // @ts-ignore 51 | export type File = SelectType; 52 | // @ts-ignore 53 | export const File: SelectType; 54 | // @ts-ignore 55 | export type Blob = SelectType; 56 | // @ts-ignore 57 | export const Blob: SelectType; 58 | 59 | // @ts-ignore 60 | export type Readable = SelectType; 61 | // @ts-ignore 62 | export type FsReadStream = SelectType; 63 | // @ts-ignore 64 | export type ReadableStream = SelectType; 65 | // @ts-ignore 66 | export const ReadableStream: SelectType; 67 | 68 | export function getMultipartRequestOptions>( 69 | form: FormData, 70 | opts: RequestOptions, 71 | ): Promise>; 72 | 73 | export function getDefaultAgent(url: string): any; 74 | 75 | // @ts-ignore 76 | export type FileFromPathOptions = SelectType; 77 | 78 | export function fileFromPath(path: string, options?: FileFromPathOptions): Promise; 79 | export function fileFromPath(path: string, filename?: string, options?: FileFromPathOptions): Promise; 80 | 81 | export function isFsReadStream(value: any): value is FsReadStream; 82 | 83 | export const init: () => void; 84 | -------------------------------------------------------------------------------- /src/_shims/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | const shims = require('./registry'); 5 | const auto = require('groq-sdk/_shims/auto/runtime'); 6 | exports.init = () => { 7 | if (!shims.kind) shims.setShims(auto.getRuntime(), { auto: true }); 8 | }; 9 | for (const property of Object.keys(shims)) { 10 | Object.defineProperty(exports, property, { 11 | get() { 12 | return shims[property]; 13 | }, 14 | }); 15 | } 16 | 17 | exports.init(); 18 | -------------------------------------------------------------------------------- /src/_shims/index.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | import * as shims from './registry.mjs'; 5 | import * as auto from 'groq-sdk/_shims/auto/runtime'; 6 | export const init = () => { 7 | if (!shims.kind) shims.setShims(auto.getRuntime(), { auto: true }); 8 | }; 9 | export * from './registry.mjs'; 10 | 11 | init(); 12 | -------------------------------------------------------------------------------- /src/_shims/manual-types.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | /** 5 | * Types will get added to this namespace when you import one of the following: 6 | * 7 | * import 'groq-sdk/shims/node' 8 | * import 'groq-sdk/shims/web' 9 | * 10 | * Importing more than one will cause type and runtime errors. 11 | */ 12 | export namespace manual {} 13 | -------------------------------------------------------------------------------- /src/_shims/manual-types.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | -------------------------------------------------------------------------------- /src/_shims/manual-types.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | -------------------------------------------------------------------------------- /src/_shims/node-runtime.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | import * as nf from 'node-fetch'; 5 | import * as fd from 'formdata-node'; 6 | import { type File, type FilePropertyBag } from 'formdata-node'; 7 | import KeepAliveAgent from 'agentkeepalive'; 8 | import { AbortController as AbortControllerPolyfill } from 'abort-controller'; 9 | import { ReadStream as FsReadStream } from 'node:fs'; 10 | import { type Agent } from 'node:http'; 11 | import { FormDataEncoder } from 'form-data-encoder'; 12 | import { Readable } from 'node:stream'; 13 | import { type RequestOptions } from '../core'; 14 | import { MultipartBody } from './MultipartBody'; 15 | import { type Shims } from './registry'; 16 | import { ReadableStream } from 'node:stream/web'; 17 | 18 | type FileFromPathOptions = Omit; 19 | 20 | let fileFromPathWarned = false; 21 | 22 | /** 23 | * @deprecated use fs.createReadStream('./my/file.txt') instead 24 | */ 25 | async function fileFromPath(path: string): Promise; 26 | async function fileFromPath(path: string, filename?: string): Promise; 27 | async function fileFromPath(path: string, options?: FileFromPathOptions): Promise; 28 | async function fileFromPath(path: string, filename?: string, options?: FileFromPathOptions): Promise; 29 | async function fileFromPath(path: string, ...args: any[]): Promise { 30 | // this import fails in environments that don't handle export maps correctly, like old versions of Jest 31 | const { fileFromPath: _fileFromPath } = await import('formdata-node/file-from-path'); 32 | 33 | if (!fileFromPathWarned) { 34 | console.warn(`fileFromPath is deprecated; use fs.createReadStream(${JSON.stringify(path)}) instead`); 35 | fileFromPathWarned = true; 36 | } 37 | // @ts-ignore 38 | return await _fileFromPath(path, ...args); 39 | } 40 | 41 | const defaultHttpAgent: Agent = new KeepAliveAgent({ keepAlive: true, timeout: 5 * 60 * 1000 }); 42 | const defaultHttpsAgent: Agent = new KeepAliveAgent.HttpsAgent({ keepAlive: true, timeout: 5 * 60 * 1000 }); 43 | 44 | async function getMultipartRequestOptions>( 45 | form: fd.FormData, 46 | opts: RequestOptions, 47 | ): Promise> { 48 | const encoder = new FormDataEncoder(form); 49 | const readable = Readable.from(encoder); 50 | const body = new MultipartBody(readable); 51 | const headers = { 52 | ...opts.headers, 53 | ...encoder.headers, 54 | 'Content-Length': encoder.contentLength, 55 | }; 56 | 57 | return { ...opts, body: body as any, headers }; 58 | } 59 | 60 | export function getRuntime(): Shims { 61 | // Polyfill global object if needed. 62 | if (typeof AbortController === 'undefined') { 63 | // @ts-expect-error (the types are subtly different, but compatible in practice) 64 | globalThis.AbortController = AbortControllerPolyfill; 65 | } 66 | return { 67 | kind: 'node', 68 | fetch: nf.default, 69 | Request: nf.Request, 70 | Response: nf.Response, 71 | Headers: nf.Headers, 72 | FormData: fd.FormData, 73 | Blob: fd.Blob, 74 | File: fd.File, 75 | ReadableStream, 76 | getMultipartRequestOptions, 77 | getDefaultAgent: (url: string): Agent => (url.startsWith('https') ? defaultHttpsAgent : defaultHttpAgent), 78 | fileFromPath, 79 | isFsReadStream: (value: any): value is FsReadStream => value instanceof FsReadStream, 80 | }; 81 | } 82 | -------------------------------------------------------------------------------- /src/_shims/node-types.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | import * as nf from 'node-fetch'; 5 | import * as fd from 'formdata-node'; 6 | 7 | export { type Agent } from 'node:http'; 8 | export { type Readable } from 'node:stream'; 9 | export { type ReadStream as FsReadStream } from 'node:fs'; 10 | export { ReadableStream } from 'node:stream/web'; 11 | 12 | export const fetch: typeof nf.default; 13 | 14 | export type Request = nf.Request; 15 | export type RequestInfo = nf.RequestInfo; 16 | export type RequestInit = nf.RequestInit; 17 | 18 | export type Response = nf.Response; 19 | export type ResponseInit = nf.ResponseInit; 20 | export type ResponseType = nf.ResponseType; 21 | export type BodyInit = nf.BodyInit; 22 | export type Headers = nf.Headers; 23 | export type HeadersInit = nf.HeadersInit; 24 | 25 | type EndingType = 'native' | 'transparent'; 26 | export interface BlobPropertyBag { 27 | endings?: EndingType; 28 | type?: string; 29 | } 30 | 31 | export interface FilePropertyBag extends BlobPropertyBag { 32 | lastModified?: number; 33 | } 34 | 35 | export type FileFromPathOptions = Omit; 36 | 37 | export type FormData = fd.FormData; 38 | export const FormData: typeof fd.FormData; 39 | export type File = fd.File; 40 | export const File: typeof fd.File; 41 | export type Blob = fd.Blob; 42 | export const Blob: typeof fd.Blob; 43 | -------------------------------------------------------------------------------- /src/_shims/node-types.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | -------------------------------------------------------------------------------- /src/_shims/node-types.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | -------------------------------------------------------------------------------- /src/_shims/registry.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | import { type RequestOptions } from '../core'; 5 | 6 | export interface Shims { 7 | kind: string; 8 | fetch: any; 9 | Request: any; 10 | Response: any; 11 | Headers: any; 12 | FormData: any; 13 | Blob: any; 14 | File: any; 15 | ReadableStream: any; 16 | getMultipartRequestOptions: >( 17 | form: Shims['FormData'], 18 | opts: RequestOptions, 19 | ) => Promise>; 20 | getDefaultAgent: (url: string) => any; 21 | fileFromPath: 22 | | ((path: string, filename?: string, options?: {}) => Promise) 23 | | ((path: string, options?: {}) => Promise); 24 | isFsReadStream: (value: any) => boolean; 25 | } 26 | 27 | export let auto = false; 28 | export let kind: Shims['kind'] | undefined = undefined; 29 | export let fetch: Shims['fetch'] | undefined = undefined; 30 | export let Request: Shims['Request'] | undefined = undefined; 31 | export let Response: Shims['Response'] | undefined = undefined; 32 | export let Headers: Shims['Headers'] | undefined = undefined; 33 | export let FormData: Shims['FormData'] | undefined = undefined; 34 | export let Blob: Shims['Blob'] | undefined = undefined; 35 | export let File: Shims['File'] | undefined = undefined; 36 | export let ReadableStream: Shims['ReadableStream'] | undefined = undefined; 37 | export let getMultipartRequestOptions: Shims['getMultipartRequestOptions'] | undefined = undefined; 38 | export let getDefaultAgent: Shims['getDefaultAgent'] | undefined = undefined; 39 | export let fileFromPath: Shims['fileFromPath'] | undefined = undefined; 40 | export let isFsReadStream: Shims['isFsReadStream'] | undefined = undefined; 41 | 42 | export function setShims(shims: Shims, options: { auto: boolean } = { auto: false }) { 43 | if (auto) { 44 | throw new Error( 45 | `you must \`import 'groq-sdk/shims/${shims.kind}'\` before importing anything else from groq-sdk`, 46 | ); 47 | } 48 | if (kind) { 49 | throw new Error( 50 | `can't \`import 'groq-sdk/shims/${shims.kind}'\` after \`import 'groq-sdk/shims/${kind}'\``, 51 | ); 52 | } 53 | auto = options.auto; 54 | kind = shims.kind; 55 | fetch = shims.fetch; 56 | Request = shims.Request; 57 | Response = shims.Response; 58 | Headers = shims.Headers; 59 | FormData = shims.FormData; 60 | Blob = shims.Blob; 61 | File = shims.File; 62 | ReadableStream = shims.ReadableStream; 63 | getMultipartRequestOptions = shims.getMultipartRequestOptions; 64 | getDefaultAgent = shims.getDefaultAgent; 65 | fileFromPath = shims.fileFromPath; 66 | isFsReadStream = shims.isFsReadStream; 67 | } 68 | -------------------------------------------------------------------------------- /src/_shims/web-runtime.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | import { MultipartBody } from './MultipartBody'; 5 | import { type RequestOptions } from '../core'; 6 | import { type Shims } from './registry'; 7 | 8 | export function getRuntime({ manuallyImported }: { manuallyImported?: boolean } = {}): Shims { 9 | const recommendation = 10 | manuallyImported ? 11 | `You may need to use polyfills` 12 | : `Add one of these imports before your first \`import … from 'groq-sdk'\`: 13 | - \`import 'groq-sdk/shims/node'\` (if you're running on Node) 14 | - \`import 'groq-sdk/shims/web'\` (otherwise) 15 | `; 16 | 17 | let _fetch, _Request, _Response, _Headers; 18 | try { 19 | // @ts-ignore 20 | _fetch = fetch; 21 | // @ts-ignore 22 | _Request = Request; 23 | // @ts-ignore 24 | _Response = Response; 25 | // @ts-ignore 26 | _Headers = Headers; 27 | } catch (error) { 28 | throw new Error( 29 | `this environment is missing the following Web Fetch API type: ${ 30 | (error as any).message 31 | }. ${recommendation}`, 32 | ); 33 | } 34 | 35 | return { 36 | kind: 'web', 37 | fetch: _fetch, 38 | Request: _Request, 39 | Response: _Response, 40 | Headers: _Headers, 41 | FormData: 42 | // @ts-ignore 43 | typeof FormData !== 'undefined' ? FormData : ( 44 | class FormData { 45 | // @ts-ignore 46 | constructor() { 47 | throw new Error( 48 | `file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`, 49 | ); 50 | } 51 | } 52 | ), 53 | Blob: 54 | typeof Blob !== 'undefined' ? Blob : ( 55 | class Blob { 56 | constructor() { 57 | throw new Error( 58 | `file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`, 59 | ); 60 | } 61 | } 62 | ), 63 | File: 64 | // @ts-ignore 65 | typeof File !== 'undefined' ? File : ( 66 | class File { 67 | // @ts-ignore 68 | constructor() { 69 | throw new Error( 70 | `file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`, 71 | ); 72 | } 73 | } 74 | ), 75 | ReadableStream: 76 | // @ts-ignore 77 | typeof ReadableStream !== 'undefined' ? ReadableStream : ( 78 | class ReadableStream { 79 | // @ts-ignore 80 | constructor() { 81 | throw new Error( 82 | `streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`, 83 | ); 84 | } 85 | } 86 | ), 87 | getMultipartRequestOptions: async >( 88 | // @ts-ignore 89 | form: FormData, 90 | opts: RequestOptions, 91 | ): Promise> => ({ 92 | ...opts, 93 | body: new MultipartBody(form) as any, 94 | }), 95 | getDefaultAgent: (url: string) => undefined, 96 | fileFromPath: () => { 97 | throw new Error( 98 | 'The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/groq/groq-typescript#file-uploads', 99 | ); 100 | }, 101 | isFsReadStream: (value: any) => false, 102 | }; 103 | } 104 | -------------------------------------------------------------------------------- /src/_shims/web-types.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | export type Agent = any; 5 | 6 | declare const _fetch: typeof fetch; 7 | export { _fetch as fetch }; 8 | 9 | type _Request = Request; 10 | export { _Request as Request }; 11 | 12 | type _RequestInfo = RequestInfo; 13 | export { type _RequestInfo as RequestInfo }; 14 | 15 | type _RequestInit = RequestInit; 16 | export { type _RequestInit as RequestInit }; 17 | 18 | type _Response = Response; 19 | export { _Response as Response }; 20 | 21 | type _ResponseInit = ResponseInit; 22 | export { type _ResponseInit as ResponseInit }; 23 | 24 | type _ResponseType = ResponseType; 25 | export { type _ResponseType as ResponseType }; 26 | 27 | type _BodyInit = BodyInit; 28 | export { type _BodyInit as BodyInit }; 29 | 30 | type _Headers = Headers; 31 | export { _Headers as Headers }; 32 | 33 | type _HeadersInit = HeadersInit; 34 | export { type _HeadersInit as HeadersInit }; 35 | 36 | type EndingType = 'native' | 'transparent'; 37 | 38 | export interface BlobPropertyBag { 39 | endings?: EndingType; 40 | type?: string; 41 | } 42 | 43 | export interface FilePropertyBag extends BlobPropertyBag { 44 | lastModified?: number; 45 | } 46 | 47 | export type FileFromPathOptions = Omit; 48 | 49 | type _FormData = FormData; 50 | declare const _FormData: typeof FormData; 51 | export { _FormData as FormData }; 52 | 53 | type _File = File; 54 | declare const _File: typeof File; 55 | export { _File as File }; 56 | 57 | type _Blob = Blob; 58 | declare const _Blob: typeof Blob; 59 | export { _Blob as Blob }; 60 | 61 | export declare class Readable { 62 | readable: boolean; 63 | readonly readableEnded: boolean; 64 | readonly readableFlowing: boolean | null; 65 | readonly readableHighWaterMark: number; 66 | readonly readableLength: number; 67 | readonly readableObjectMode: boolean; 68 | destroyed: boolean; 69 | read(size?: number): any; 70 | pause(): this; 71 | resume(): this; 72 | isPaused(): boolean; 73 | destroy(error?: Error): this; 74 | [Symbol.asyncIterator](): AsyncIterableIterator; 75 | } 76 | 77 | export declare class FsReadStream extends Readable { 78 | path: {}; // node type is string | Buffer 79 | } 80 | 81 | type _ReadableStream = ReadableStream; 82 | declare const _ReadableStream: typeof ReadableStream; 83 | export { _ReadableStream as ReadableStream }; 84 | -------------------------------------------------------------------------------- /src/_shims/web-types.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | -------------------------------------------------------------------------------- /src/_shims/web-types.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * Disclaimer: modules in _shims aren't intended to be imported by SDK users. 3 | */ 4 | -------------------------------------------------------------------------------- /src/error.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { castToError, Headers } from './core'; 4 | 5 | export class GroqError extends Error {} 6 | 7 | export class APIError< 8 | TStatus extends number | undefined = number | undefined, 9 | THeaders extends Headers | undefined = Headers | undefined, 10 | TError extends Object | undefined = Object | undefined, 11 | > extends GroqError { 12 | /** HTTP status for the response that caused the error */ 13 | readonly status: TStatus; 14 | /** HTTP headers for the response that caused the error */ 15 | readonly headers: THeaders; 16 | /** JSON body of the response that caused the error */ 17 | readonly error: TError; 18 | 19 | constructor(status: TStatus, error: TError, message: string | undefined, headers: THeaders) { 20 | super(`${APIError.makeMessage(status, error, message)}`); 21 | this.status = status; 22 | this.headers = headers; 23 | this.error = error; 24 | } 25 | 26 | private static makeMessage(status: number | undefined, error: any, message: string | undefined) { 27 | const msg = 28 | error?.message ? 29 | typeof error.message === 'string' ? 30 | error.message 31 | : JSON.stringify(error.message) 32 | : error ? JSON.stringify(error) 33 | : message; 34 | 35 | if (status && msg) { 36 | return `${status} ${msg}`; 37 | } 38 | if (status) { 39 | return `${status} status code (no body)`; 40 | } 41 | if (msg) { 42 | return msg; 43 | } 44 | return '(no status code or body)'; 45 | } 46 | 47 | static generate( 48 | status: number | undefined, 49 | errorResponse: Object | undefined, 50 | message: string | undefined, 51 | headers: Headers | undefined, 52 | ): APIError { 53 | if (!status || !headers) { 54 | return new APIConnectionError({ message, cause: castToError(errorResponse) }); 55 | } 56 | 57 | const error = errorResponse as Record; 58 | 59 | if (status === 400) { 60 | return new BadRequestError(status, error, message, headers); 61 | } 62 | 63 | if (status === 401) { 64 | return new AuthenticationError(status, error, message, headers); 65 | } 66 | 67 | if (status === 403) { 68 | return new PermissionDeniedError(status, error, message, headers); 69 | } 70 | 71 | if (status === 404) { 72 | return new NotFoundError(status, error, message, headers); 73 | } 74 | 75 | if (status === 409) { 76 | return new ConflictError(status, error, message, headers); 77 | } 78 | 79 | if (status === 422) { 80 | return new UnprocessableEntityError(status, error, message, headers); 81 | } 82 | 83 | if (status === 429) { 84 | return new RateLimitError(status, error, message, headers); 85 | } 86 | 87 | if (status >= 500) { 88 | return new InternalServerError(status, error, message, headers); 89 | } 90 | 91 | return new APIError(status, error, message, headers); 92 | } 93 | } 94 | 95 | export class APIUserAbortError extends APIError { 96 | constructor({ message }: { message?: string } = {}) { 97 | super(undefined, undefined, message || 'Request was aborted.', undefined); 98 | } 99 | } 100 | 101 | export class APIConnectionError extends APIError { 102 | constructor({ message, cause }: { message?: string | undefined; cause?: Error | undefined }) { 103 | super(undefined, undefined, message || 'Connection error.', undefined); 104 | // in some environments the 'cause' property is already declared 105 | // @ts-ignore 106 | if (cause) this.cause = cause; 107 | } 108 | } 109 | 110 | export class APIConnectionTimeoutError extends APIConnectionError { 111 | constructor({ message }: { message?: string } = {}) { 112 | super({ message: message ?? 'Request timed out.' }); 113 | } 114 | } 115 | 116 | export class BadRequestError extends APIError<400, Headers> {} 117 | 118 | export class AuthenticationError extends APIError<401, Headers> {} 119 | 120 | export class PermissionDeniedError extends APIError<403, Headers> {} 121 | 122 | export class NotFoundError extends APIError<404, Headers> {} 123 | 124 | export class ConflictError extends APIError<409, Headers> {} 125 | 126 | export class UnprocessableEntityError extends APIError<422, Headers> {} 127 | 128 | export class RateLimitError extends APIError<429, Headers> {} 129 | 130 | export class InternalServerError extends APIError {} 131 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { type Agent } from './_shims/index'; 4 | import * as Core from './core'; 5 | import * as Errors from './error'; 6 | import * as Uploads from './uploads'; 7 | import * as API from './resources/index'; 8 | import { 9 | BatchCreateParams, 10 | BatchCreateResponse, 11 | BatchListResponse, 12 | BatchRetrieveResponse, 13 | Batches, 14 | } from './resources/batches'; 15 | import { CompletionUsage, Completions } from './resources/completions'; 16 | import { 17 | CreateEmbeddingResponse, 18 | Embedding, 19 | EmbeddingCreateParams, 20 | Embeddings, 21 | } from './resources/embeddings'; 22 | import { 23 | FileCreateParams, 24 | FileCreateResponse, 25 | FileDeleteResponse, 26 | FileInfoResponse, 27 | FileListResponse, 28 | Files, 29 | } from './resources/files'; 30 | import { Model, ModelDeleted, ModelListResponse, Models } from './resources/models'; 31 | import { Audio } from './resources/audio/audio'; 32 | import { Chat } from './resources/chat/chat'; 33 | 34 | export interface ClientOptions { 35 | /** 36 | * Defaults to process.env['GROQ_API_KEY']. 37 | */ 38 | apiKey?: string | undefined; 39 | 40 | /** 41 | * Override the default base URL for the API, e.g., "https://api.example.com/v2/" 42 | * 43 | * Defaults to process.env['GROQ_BASE_URL']. 44 | */ 45 | baseURL?: string | null | undefined; 46 | 47 | /** 48 | * The maximum amount of time (in milliseconds) that the client should wait for a response 49 | * from the server before timing out a single request. 50 | * 51 | * Note that request timeouts are retried by default, so in a worst-case scenario you may wait 52 | * much longer than this timeout before the promise succeeds or fails. 53 | */ 54 | timeout?: number | undefined; 55 | 56 | /** 57 | * An HTTP agent used to manage HTTP(S) connections. 58 | * 59 | * If not provided, an agent will be constructed by default in the Node.js environment, 60 | * otherwise no agent is used. 61 | */ 62 | httpAgent?: Agent | undefined; 63 | 64 | /** 65 | * Specify a custom `fetch` function implementation. 66 | * 67 | * If not provided, we use `node-fetch` on Node.js and otherwise expect that `fetch` is 68 | * defined globally. 69 | */ 70 | fetch?: Core.Fetch | undefined; 71 | 72 | /** 73 | * The maximum number of times that the client will retry a request in case of a 74 | * temporary failure, like a network error or a 5XX error from the server. 75 | * 76 | * @default 2 77 | */ 78 | maxRetries?: number | undefined; 79 | 80 | /** 81 | * Default headers to include with every request to the API. 82 | * 83 | * These can be removed in individual requests by explicitly setting the 84 | * header to `undefined` or `null` in request options. 85 | */ 86 | defaultHeaders?: Core.Headers | undefined; 87 | 88 | /** 89 | * Default query parameters to include with every request to the API. 90 | * 91 | * These can be removed in individual requests by explicitly setting the 92 | * param to `undefined` in request options. 93 | */ 94 | defaultQuery?: Core.DefaultQuery | undefined; 95 | 96 | /** 97 | * By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers. 98 | * Only set this option to `true` if you understand the risks and have appropriate mitigations in place. 99 | */ 100 | dangerouslyAllowBrowser?: boolean | undefined; 101 | } 102 | 103 | /** 104 | * API Client for interfacing with the Groq API. 105 | */ 106 | export class Groq extends Core.APIClient { 107 | apiKey: string; 108 | 109 | private _options: ClientOptions; 110 | 111 | /** 112 | * API Client for interfacing with the Groq API. 113 | * 114 | * @param {string | undefined} [opts.apiKey=process.env['GROQ_API_KEY'] ?? undefined] 115 | * @param {string} [opts.baseURL=process.env['GROQ_BASE_URL'] ?? https://api.groq.com] - Override the default base URL for the API. 116 | * @param {number} [opts.timeout=1 minute] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out. 117 | * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections. 118 | * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation. 119 | * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request. 120 | * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API. 121 | * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API. 122 | * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers. 123 | */ 124 | constructor({ 125 | baseURL = Core.readEnv('GROQ_BASE_URL'), 126 | apiKey = Core.readEnv('GROQ_API_KEY'), 127 | ...opts 128 | }: ClientOptions = {}) { 129 | if (apiKey === undefined) { 130 | throw new Errors.GroqError( 131 | "The GROQ_API_KEY environment variable is missing or empty; either provide it, or instantiate the Groq client with an apiKey option, like new Groq({ apiKey: 'My API Key' }).", 132 | ); 133 | } 134 | 135 | const options: ClientOptions = { 136 | apiKey, 137 | ...opts, 138 | baseURL: baseURL || `https://api.groq.com`, 139 | }; 140 | 141 | if (!options.dangerouslyAllowBrowser && Core.isRunningInBrowser()) { 142 | throw new Errors.GroqError( 143 | "It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew Groq({ apiKey, dangerouslyAllowBrowser: true })", 144 | ); 145 | } 146 | 147 | super({ 148 | baseURL: options.baseURL!, 149 | timeout: options.timeout ?? 60000 /* 1 minute */, 150 | httpAgent: options.httpAgent, 151 | maxRetries: options.maxRetries, 152 | fetch: options.fetch, 153 | }); 154 | 155 | this._options = options; 156 | 157 | this.apiKey = apiKey; 158 | } 159 | 160 | completions: API.Completions = new API.Completions(this); 161 | chat: API.Chat = new API.Chat(this); 162 | embeddings: API.Embeddings = new API.Embeddings(this); 163 | audio: API.Audio = new API.Audio(this); 164 | models: API.Models = new API.Models(this); 165 | batches: API.Batches = new API.Batches(this); 166 | files: API.Files = new API.Files(this); 167 | 168 | protected override defaultQuery(): Core.DefaultQuery | undefined { 169 | return this._options.defaultQuery; 170 | } 171 | 172 | protected override defaultHeaders(opts: Core.FinalRequestOptions): Core.Headers { 173 | return { 174 | ...super.defaultHeaders(opts), 175 | ...this._options.defaultHeaders, 176 | }; 177 | } 178 | 179 | protected override authHeaders(opts: Core.FinalRequestOptions): Core.Headers { 180 | return { Authorization: `Bearer ${this.apiKey}` }; 181 | } 182 | 183 | static Groq = this; 184 | static DEFAULT_TIMEOUT = 60000; // 1 minute 185 | 186 | static GroqError = Errors.GroqError; 187 | static APIError = Errors.APIError; 188 | static APIConnectionError = Errors.APIConnectionError; 189 | static APIConnectionTimeoutError = Errors.APIConnectionTimeoutError; 190 | static APIUserAbortError = Errors.APIUserAbortError; 191 | static NotFoundError = Errors.NotFoundError; 192 | static ConflictError = Errors.ConflictError; 193 | static RateLimitError = Errors.RateLimitError; 194 | static BadRequestError = Errors.BadRequestError; 195 | static AuthenticationError = Errors.AuthenticationError; 196 | static InternalServerError = Errors.InternalServerError; 197 | static PermissionDeniedError = Errors.PermissionDeniedError; 198 | static UnprocessableEntityError = Errors.UnprocessableEntityError; 199 | 200 | static toFile = Uploads.toFile; 201 | static fileFromPath = Uploads.fileFromPath; 202 | } 203 | 204 | Groq.Completions = Completions; 205 | Groq.Chat = Chat; 206 | Groq.Embeddings = Embeddings; 207 | Groq.Audio = Audio; 208 | Groq.Models = Models; 209 | Groq.Batches = Batches; 210 | Groq.Files = Files; 211 | export declare namespace Groq { 212 | export type RequestOptions = Core.RequestOptions; 213 | 214 | export { Completions as Completions, type CompletionUsage as CompletionUsage }; 215 | 216 | export { Chat as Chat }; 217 | 218 | export { 219 | Embeddings as Embeddings, 220 | type CreateEmbeddingResponse as CreateEmbeddingResponse, 221 | type Embedding as Embedding, 222 | type EmbeddingCreateParams as EmbeddingCreateParams, 223 | }; 224 | 225 | export { Audio as Audio }; 226 | 227 | export { 228 | Models as Models, 229 | type Model as Model, 230 | type ModelDeleted as ModelDeleted, 231 | type ModelListResponse as ModelListResponse, 232 | }; 233 | 234 | export { 235 | Batches as Batches, 236 | type BatchCreateResponse as BatchCreateResponse, 237 | type BatchRetrieveResponse as BatchRetrieveResponse, 238 | type BatchListResponse as BatchListResponse, 239 | type BatchCreateParams as BatchCreateParams, 240 | }; 241 | 242 | export { 243 | Files as Files, 244 | type FileCreateResponse as FileCreateResponse, 245 | type FileListResponse as FileListResponse, 246 | type FileDeleteResponse as FileDeleteResponse, 247 | type FileInfoResponse as FileInfoResponse, 248 | type FileCreateParams as FileCreateParams, 249 | }; 250 | 251 | export type ErrorObject = API.ErrorObject; 252 | export type FunctionDefinition = API.FunctionDefinition; 253 | export type FunctionParameters = API.FunctionParameters; 254 | } 255 | 256 | export { toFile, fileFromPath } from './uploads'; 257 | export { 258 | GroqError, 259 | APIError, 260 | APIConnectionError, 261 | APIConnectionTimeoutError, 262 | APIUserAbortError, 263 | NotFoundError, 264 | ConflictError, 265 | RateLimitError, 266 | BadRequestError, 267 | AuthenticationError, 268 | InternalServerError, 269 | PermissionDeniedError, 270 | UnprocessableEntityError, 271 | } from './error'; 272 | 273 | export default Groq; 274 | -------------------------------------------------------------------------------- /src/lib/.keep: -------------------------------------------------------------------------------- 1 | File generated from our OpenAPI spec by Stainless. 2 | 3 | This directory can be used to store custom files to expand the SDK. 4 | It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. 5 | -------------------------------------------------------------------------------- /src/lib/streaming.ts: -------------------------------------------------------------------------------- 1 | import { ReadableStream, type Response } from '../_shims/index'; 2 | import { GroqError } from '../error'; 3 | 4 | import { APIError } from '../error'; 5 | 6 | type Bytes = string | ArrayBuffer | Uint8Array | Buffer | null | undefined; 7 | 8 | export type ServerSentEvent = { 9 | event: string | null; 10 | data: string; 11 | raw: string[]; 12 | }; 13 | 14 | export class Stream implements AsyncIterable { 15 | controller: AbortController; 16 | 17 | constructor( 18 | private iterator: () => AsyncIterator, 19 | controller: AbortController, 20 | ) { 21 | this.controller = controller; 22 | } 23 | 24 | static fromSSEResponse(response: Response, controller: AbortController) { 25 | let consumed = false; 26 | const decoder = new SSEDecoder(); 27 | 28 | async function* iterMessages(): AsyncGenerator { 29 | if (!response.body) { 30 | controller.abort(); 31 | throw new GroqError(`Attempted to iterate over a response with no body`); 32 | } 33 | 34 | const lineDecoder = new LineDecoder(); 35 | 36 | const iter = readableStreamAsyncIterable(response.body); 37 | for await (const chunk of iter) { 38 | for (const line of lineDecoder.decode(chunk)) { 39 | const sse = decoder.decode(line); 40 | if (sse) yield sse; 41 | } 42 | } 43 | 44 | for (const line of lineDecoder.flush()) { 45 | const sse = decoder.decode(line); 46 | if (sse) yield sse; 47 | } 48 | } 49 | 50 | async function* iterator(): AsyncIterator { 51 | if (consumed) { 52 | throw new Error('Cannot iterate over a consumed stream, use `.tee()` to split the stream.'); 53 | } 54 | consumed = true; 55 | let done = false; 56 | try { 57 | for await (const sse of iterMessages()) { 58 | if (done) continue; 59 | 60 | if (sse.data.startsWith('[DONE]')) { 61 | done = true; 62 | continue; 63 | } 64 | 65 | if (sse.event === null || sse.event === 'error') { 66 | let data; 67 | 68 | try { 69 | data = JSON.parse(sse.data); 70 | } catch (e) { 71 | console.error(`Could not parse message into JSON:`, sse.data); 72 | console.error(`From chunk:`, sse.raw); 73 | throw e; 74 | } 75 | 76 | if (data && data.error) { 77 | throw new APIError(data.error.status_code, data.error, data.error.message, undefined); 78 | } 79 | 80 | yield data; 81 | } 82 | } 83 | done = true; 84 | } catch (e) { 85 | // If the user calls `stream.controller.abort()`, we should exit without throwing. 86 | if (e instanceof Error && e.name === 'AbortError') return; 87 | throw e; 88 | } finally { 89 | // If the user `break`s, abort the ongoing request. 90 | if (!done) controller.abort(); 91 | } 92 | } 93 | 94 | return new Stream(iterator, controller); 95 | } 96 | 97 | /** 98 | * Generates a Stream from a newline-separated ReadableStream 99 | * where each item is a JSON value. 100 | */ 101 | static fromReadableStream(readableStream: ReadableStream, controller: AbortController) { 102 | let consumed = false; 103 | 104 | async function* iterLines(): AsyncGenerator { 105 | const lineDecoder = new LineDecoder(); 106 | 107 | const iter = readableStreamAsyncIterable(readableStream); 108 | for await (const chunk of iter) { 109 | for (const line of lineDecoder.decode(chunk)) { 110 | yield line; 111 | } 112 | } 113 | 114 | for (const line of lineDecoder.flush()) { 115 | yield line; 116 | } 117 | } 118 | 119 | async function* iterator(): AsyncIterator { 120 | if (consumed) { 121 | throw new Error('Cannot iterate over a consumed stream, use `.tee()` to split the stream.'); 122 | } 123 | consumed = true; 124 | let done = false; 125 | try { 126 | for await (const line of iterLines()) { 127 | if (done) continue; 128 | if (line) yield JSON.parse(line); 129 | } 130 | done = true; 131 | } catch (e) { 132 | // If the user calls `stream.controller.abort()`, we should exit without throwing. 133 | if (e instanceof Error && e.name === 'AbortError') return; 134 | throw e; 135 | } finally { 136 | // If the user `break`s, abort the ongoing request. 137 | if (!done) controller.abort(); 138 | } 139 | } 140 | 141 | return new Stream(iterator, controller); 142 | } 143 | 144 | [Symbol.asyncIterator](): AsyncIterator { 145 | return this.iterator(); 146 | } 147 | 148 | /** 149 | * Splits the stream into two streams which can be 150 | * independently read from at different speeds. 151 | */ 152 | tee(): [Stream, Stream] { 153 | const left: Array>> = []; 154 | const right: Array>> = []; 155 | const iterator = this.iterator(); 156 | 157 | const teeIterator = (queue: Array>>): AsyncIterator => { 158 | return { 159 | next: () => { 160 | if (queue.length === 0) { 161 | const result = iterator.next(); 162 | left.push(result); 163 | right.push(result); 164 | } 165 | return queue.shift()!; 166 | }, 167 | }; 168 | }; 169 | 170 | return [ 171 | new Stream(() => teeIterator(left), this.controller), 172 | new Stream(() => teeIterator(right), this.controller), 173 | ]; 174 | } 175 | 176 | /** 177 | * Converts this stream to a newline-separated ReadableStream of 178 | * JSON stringified values in the stream 179 | * which can be turned back into a Stream with `Stream.fromReadableStream()`. 180 | */ 181 | toReadableStream(): ReadableStream { 182 | const self = this; 183 | let iter: AsyncIterator; 184 | const encoder = new TextEncoder(); 185 | 186 | return new ReadableStream({ 187 | async start() { 188 | iter = self[Symbol.asyncIterator](); 189 | }, 190 | async pull(ctrl) { 191 | try { 192 | const { value, done } = await iter.next(); 193 | if (done) return ctrl.close(); 194 | 195 | const bytes = encoder.encode(JSON.stringify(value) + '\n'); 196 | 197 | ctrl.enqueue(bytes); 198 | } catch (err) { 199 | ctrl.error(err); 200 | } 201 | }, 202 | async cancel() { 203 | await iter.return?.(); 204 | }, 205 | }); 206 | } 207 | } 208 | 209 | class SSEDecoder { 210 | private data: string[]; 211 | private event: string | null; 212 | private chunks: string[]; 213 | 214 | constructor() { 215 | this.event = null; 216 | this.data = []; 217 | this.chunks = []; 218 | } 219 | 220 | decode(line: string) { 221 | if (line.endsWith('\r')) { 222 | line = line.substring(0, line.length - 1); 223 | } 224 | 225 | if (!line) { 226 | // empty line and we didn't previously encounter any messages 227 | if (!this.event && !this.data.length) return null; 228 | 229 | const sse: ServerSentEvent = { 230 | event: this.event, 231 | data: this.data.join('\n'), 232 | raw: this.chunks, 233 | }; 234 | 235 | this.event = null; 236 | this.data = []; 237 | this.chunks = []; 238 | 239 | return sse; 240 | } 241 | 242 | this.chunks.push(line); 243 | 244 | if (line.startsWith(':')) { 245 | return null; 246 | } 247 | 248 | let [fieldname, _, value] = partition(line, ':'); 249 | 250 | if (value.startsWith(' ')) { 251 | value = value.substring(1); 252 | } 253 | 254 | if (fieldname === 'event') { 255 | this.event = value; 256 | } else if (fieldname === 'data') { 257 | this.data.push(value); 258 | } 259 | 260 | return null; 261 | } 262 | } 263 | 264 | /** 265 | * A re-implementation of httpx's `LineDecoder` in Python that handles incrementally 266 | * reading lines from text. 267 | * 268 | * https://github.com/encode/httpx/blob/920333ea98118e9cf617f246905d7b202510941c/httpx/_decoders.py#L258 269 | */ 270 | class LineDecoder { 271 | // prettier-ignore 272 | static NEWLINE_CHARS = new Set(['\n', '\r', '\x0b', '\x0c', '\x1c', '\x1d', '\x1e', '\x85', '\u2028', '\u2029']); 273 | static NEWLINE_REGEXP = /\r\n|[\n\r\x0b\x0c\x1c\x1d\x1e\x85\u2028\u2029]/g; 274 | 275 | buffer: string[]; 276 | trailingCR: boolean; 277 | textDecoder: any; // TextDecoder found in browsers; not typed to avoid pulling in either "dom" or "node" types. 278 | 279 | constructor() { 280 | this.buffer = []; 281 | this.trailingCR = false; 282 | } 283 | 284 | decode(chunk: Bytes): string[] { 285 | let text = this.decodeText(chunk); 286 | 287 | if (this.trailingCR) { 288 | text = '\r' + text; 289 | this.trailingCR = false; 290 | } 291 | if (text.endsWith('\r')) { 292 | this.trailingCR = true; 293 | text = text.slice(0, -1); 294 | } 295 | 296 | if (!text) { 297 | return []; 298 | } 299 | 300 | const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || ''); 301 | let lines = text.split(LineDecoder.NEWLINE_REGEXP); 302 | 303 | if (lines.length === 1 && !trailingNewline) { 304 | this.buffer.push(lines[0]!); 305 | return []; 306 | } 307 | 308 | if (this.buffer.length > 0) { 309 | lines = [this.buffer.join('') + lines[0], ...lines.slice(1)]; 310 | this.buffer = []; 311 | } 312 | 313 | if (!trailingNewline) { 314 | this.buffer = [lines.pop() || '']; 315 | } 316 | 317 | return lines; 318 | } 319 | 320 | decodeText(bytes: Bytes): string { 321 | if (bytes == null) return ''; 322 | if (typeof bytes === 'string') return bytes; 323 | 324 | // Node: 325 | if (typeof Buffer !== 'undefined') { 326 | if (bytes instanceof Buffer) { 327 | return bytes.toString(); 328 | } 329 | if (bytes instanceof Uint8Array) { 330 | return Buffer.from(bytes).toString(); 331 | } 332 | 333 | throw new GroqError( 334 | `Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global "Buffer" defined, which this library assumes to be Node. Please report this error.`, 335 | ); 336 | } 337 | 338 | // Browser 339 | if (typeof TextDecoder !== 'undefined') { 340 | if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) { 341 | this.textDecoder ??= new TextDecoder('utf8'); 342 | return this.textDecoder.decode(bytes); 343 | } 344 | 345 | throw new GroqError( 346 | `Unexpected: received non-Uint8Array/ArrayBuffer (${ 347 | (bytes as any).constructor.name 348 | }) in a web platform. Please report this error.`, 349 | ); 350 | } 351 | 352 | throw new GroqError( 353 | `Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`, 354 | ); 355 | } 356 | 357 | flush(): string[] { 358 | if (!this.buffer.length && !this.trailingCR) { 359 | return []; 360 | } 361 | 362 | const lines = [this.buffer.join('')]; 363 | this.buffer = []; 364 | this.trailingCR = false; 365 | return lines; 366 | } 367 | } 368 | 369 | function partition(str: string, delimiter: string): [string, string, string] { 370 | const index = str.indexOf(delimiter); 371 | if (index !== -1) { 372 | return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)]; 373 | } 374 | 375 | return [str, '', '']; 376 | } 377 | 378 | /** 379 | * Most browsers don't yet have async iterable support for ReadableStream, 380 | * and Node has a very different way of reading bytes from its "ReadableStream". 381 | * 382 | * This polyfill was pulled from https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490 383 | */ 384 | export function readableStreamAsyncIterable(stream: any): AsyncIterableIterator { 385 | if (stream[Symbol.asyncIterator]) return stream; 386 | 387 | const reader = stream.getReader(); 388 | return { 389 | async next() { 390 | try { 391 | const result = await reader.read(); 392 | if (result?.done) reader.releaseLock(); // release lock when stream becomes closed 393 | return result; 394 | } catch (e) { 395 | reader.releaseLock(); // release lock when stream becomes errored 396 | throw e; 397 | } 398 | }, 399 | async return() { 400 | const cancelPromise = reader.cancel(); 401 | reader.releaseLock(); 402 | await cancelPromise; 403 | return { done: true, value: undefined }; 404 | }, 405 | [Symbol.asyncIterator]() { 406 | return this; 407 | }, 408 | }; 409 | } 410 | -------------------------------------------------------------------------------- /src/resource.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import type { Groq } from './index'; 4 | 5 | export class APIResource { 6 | protected _client: Groq; 7 | 8 | constructor(client: Groq) { 9 | this._client = client; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/resources.ts: -------------------------------------------------------------------------------- 1 | export * from './resources/index'; 2 | -------------------------------------------------------------------------------- /src/resources/audio.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export * from './audio/index'; 4 | -------------------------------------------------------------------------------- /src/resources/audio/audio.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { APIResource } from '../../resource'; 4 | import * as SpeechAPI from './speech'; 5 | import { Speech, SpeechCreateParams } from './speech'; 6 | import * as TranscriptionsAPI from './transcriptions'; 7 | import { Transcription, TranscriptionCreateParams, Transcriptions } from './transcriptions'; 8 | import * as TranslationsAPI from './translations'; 9 | import { Translation, TranslationCreateParams, Translations } from './translations'; 10 | 11 | export class Audio extends APIResource { 12 | speech: SpeechAPI.Speech = new SpeechAPI.Speech(this._client); 13 | transcriptions: TranscriptionsAPI.Transcriptions = new TranscriptionsAPI.Transcriptions(this._client); 14 | translations: TranslationsAPI.Translations = new TranslationsAPI.Translations(this._client); 15 | } 16 | 17 | Audio.Speech = Speech; 18 | Audio.Transcriptions = Transcriptions; 19 | Audio.Translations = Translations; 20 | 21 | export declare namespace Audio { 22 | export { Speech as Speech, type SpeechCreateParams as SpeechCreateParams }; 23 | 24 | export { 25 | Transcriptions as Transcriptions, 26 | type Transcription as Transcription, 27 | type TranscriptionCreateParams as TranscriptionCreateParams, 28 | }; 29 | 30 | export { 31 | Translations as Translations, 32 | type Translation as Translation, 33 | type TranslationCreateParams as TranslationCreateParams, 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /src/resources/audio/index.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export { Audio } from './audio'; 4 | export { Speech, type SpeechCreateParams } from './speech'; 5 | export { Transcriptions, type Transcription, type TranscriptionCreateParams } from './transcriptions'; 6 | export { Translations, type Translation, type TranslationCreateParams } from './translations'; 7 | -------------------------------------------------------------------------------- /src/resources/audio/speech.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { APIResource } from '../../resource'; 4 | import * as Core from '../../core'; 5 | import { type Response } from '../../_shims/index'; 6 | 7 | export class Speech extends APIResource { 8 | /** 9 | * Generates audio from the input text. 10 | * 11 | * @example 12 | * ```ts 13 | * const speech = await client.audio.speech.create({ 14 | * input: 'The quick brown fox jumped over the lazy dog', 15 | * model: 'playai-tts', 16 | * voice: 'Fritz-PlayAI', 17 | * }); 18 | * 19 | * const content = await speech.blob(); 20 | * console.log(content); 21 | * ``` 22 | */ 23 | create(body: SpeechCreateParams, options?: Core.RequestOptions): Core.APIPromise { 24 | return this._client.post('/openai/v1/audio/speech', { 25 | body, 26 | ...options, 27 | headers: { Accept: 'audio/wav', ...options?.headers }, 28 | __binaryResponse: true, 29 | }); 30 | } 31 | } 32 | 33 | export interface SpeechCreateParams { 34 | /** 35 | * The text to generate audio for. 36 | */ 37 | input: string; 38 | 39 | /** 40 | * One of the [available TTS models](/docs/text-to-speech). 41 | */ 42 | model: (string & {}) | 'playai-tts' | 'playai-tts-arabic'; 43 | 44 | /** 45 | * The voice to use when generating the audio. List of voices can be found 46 | * [here](/docs/text-to-speech). 47 | */ 48 | voice: string; 49 | 50 | /** 51 | * The format of the generated audio. Supported formats are 52 | * `flac, mp3, mulaw, ogg, wav`. 53 | */ 54 | response_format?: 'flac' | 'mp3' | 'mulaw' | 'ogg' | 'wav'; 55 | 56 | /** 57 | * The sample rate for generated audio 58 | */ 59 | sample_rate?: 8000 | 16000 | 22050 | 24000 | 32000 | 44100 | 48000; 60 | 61 | /** 62 | * The speed of the generated audio. 63 | */ 64 | speed?: number; 65 | } 66 | 67 | export declare namespace Speech { 68 | export { type SpeechCreateParams as SpeechCreateParams }; 69 | } 70 | -------------------------------------------------------------------------------- /src/resources/audio/transcriptions.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { APIResource } from '../../resource'; 4 | import * as Core from '../../core'; 5 | 6 | export class Transcriptions extends APIResource { 7 | /** 8 | * Transcribes audio into the input language. 9 | * 10 | * @example 11 | * ```ts 12 | * const transcription = 13 | * await client.audio.transcriptions.create({ 14 | * model: 'whisper-large-v3-turbo', 15 | * }); 16 | * ``` 17 | */ 18 | create(body: TranscriptionCreateParams, options?: Core.RequestOptions): Core.APIPromise { 19 | return this._client.post( 20 | '/openai/v1/audio/transcriptions', 21 | Core.multipartFormRequestOptions({ body, ...options }), 22 | ); 23 | } 24 | } 25 | 26 | /** 27 | * Represents a transcription response returned by model, based on the provided 28 | * input. 29 | */ 30 | export interface Transcription { 31 | /** 32 | * The transcribed text. 33 | */ 34 | text: string; 35 | } 36 | 37 | export interface TranscriptionCreateParams { 38 | /** 39 | * ID of the model to use. `whisper-large-v3` and `whisper-large-v3-turbo` are 40 | * currently available. 41 | */ 42 | model: (string & {}) | 'whisper-large-v3' | 'whisper-large-v3-turbo'; 43 | 44 | /** 45 | * The audio file object (not file name) to transcribe, in one of these formats: 46 | * flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. Either a file or a URL must 47 | * be provided. Note that the file field is not supported in Batch API requests. 48 | */ 49 | file?: Core.Uploadable; 50 | 51 | /** 52 | * The language of the input audio. Supplying the input language in 53 | * [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) format will 54 | * improve accuracy and latency. 55 | */ 56 | language?: 57 | | (string & {}) 58 | | 'en' 59 | | 'zh' 60 | | 'de' 61 | | 'es' 62 | | 'ru' 63 | | 'ko' 64 | | 'fr' 65 | | 'ja' 66 | | 'pt' 67 | | 'tr' 68 | | 'pl' 69 | | 'ca' 70 | | 'nl' 71 | | 'ar' 72 | | 'sv' 73 | | 'it' 74 | | 'id' 75 | | 'hi' 76 | | 'fi' 77 | | 'vi' 78 | | 'he' 79 | | 'uk' 80 | | 'el' 81 | | 'ms' 82 | | 'cs' 83 | | 'ro' 84 | | 'da' 85 | | 'hu' 86 | | 'ta' 87 | | 'no' 88 | | 'th' 89 | | 'ur' 90 | | 'hr' 91 | | 'bg' 92 | | 'lt' 93 | | 'la' 94 | | 'mi' 95 | | 'ml' 96 | | 'cy' 97 | | 'sk' 98 | | 'te' 99 | | 'fa' 100 | | 'lv' 101 | | 'bn' 102 | | 'sr' 103 | | 'az' 104 | | 'sl' 105 | | 'kn' 106 | | 'et' 107 | | 'mk' 108 | | 'br' 109 | | 'eu' 110 | | 'is' 111 | | 'hy' 112 | | 'ne' 113 | | 'mn' 114 | | 'bs' 115 | | 'kk' 116 | | 'sq' 117 | | 'sw' 118 | | 'gl' 119 | | 'mr' 120 | | 'pa' 121 | | 'si' 122 | | 'km' 123 | | 'sn' 124 | | 'yo' 125 | | 'so' 126 | | 'af' 127 | | 'oc' 128 | | 'ka' 129 | | 'be' 130 | | 'tg' 131 | | 'sd' 132 | | 'gu' 133 | | 'am' 134 | | 'yi' 135 | | 'lo' 136 | | 'uz' 137 | | 'fo' 138 | | 'ht' 139 | | 'ps' 140 | | 'tk' 141 | | 'nn' 142 | | 'mt' 143 | | 'sa' 144 | | 'lb' 145 | | 'my' 146 | | 'bo' 147 | | 'tl' 148 | | 'mg' 149 | | 'as' 150 | | 'tt' 151 | | 'haw' 152 | | 'ln' 153 | | 'ha' 154 | | 'ba' 155 | | 'jv' 156 | | 'su' 157 | | 'yue'; 158 | 159 | /** 160 | * An optional text to guide the model's style or continue a previous audio 161 | * segment. The [prompt](/docs/speech-text) should match the audio language. 162 | */ 163 | prompt?: string; 164 | 165 | /** 166 | * The format of the transcript output, in one of these options: `json`, `text`, or 167 | * `verbose_json`. 168 | */ 169 | response_format?: 'json' | 'text' | 'verbose_json'; 170 | 171 | /** 172 | * The sampling temperature, between 0 and 1. Higher values like 0.8 will make the 173 | * output more random, while lower values like 0.2 will make it more focused and 174 | * deterministic. If set to 0, the model will use 175 | * [log probability](https://en.wikipedia.org/wiki/Log_probability) to 176 | * automatically increase the temperature until certain thresholds are hit. 177 | */ 178 | temperature?: number; 179 | 180 | /** 181 | * The timestamp granularities to populate for this transcription. 182 | * `response_format` must be set `verbose_json` to use timestamp granularities. 183 | * Either or both of these options are supported: `word`, or `segment`. Note: There 184 | * is no additional latency for segment timestamps, but generating word timestamps 185 | * incurs additional latency. 186 | */ 187 | timestamp_granularities?: Array<'word' | 'segment'>; 188 | 189 | /** 190 | * The audio URL to translate/transcribe (supports Base64URL). Either a file or a 191 | * URL must be provided. For Batch API requests, the URL field is required since 192 | * the file field is not supported. 193 | */ 194 | url?: string; 195 | } 196 | 197 | export declare namespace Transcriptions { 198 | export { type Transcription as Transcription, type TranscriptionCreateParams as TranscriptionCreateParams }; 199 | } 200 | -------------------------------------------------------------------------------- /src/resources/audio/translations.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { APIResource } from '../../resource'; 4 | import * as Core from '../../core'; 5 | 6 | export class Translations extends APIResource { 7 | /** 8 | * Translates audio into English. 9 | * 10 | * @example 11 | * ```ts 12 | * const translation = await client.audio.translations.create({ 13 | * model: 'whisper-large-v3-turbo', 14 | * }); 15 | * ``` 16 | */ 17 | create(body: TranslationCreateParams, options?: Core.RequestOptions): Core.APIPromise { 18 | return this._client.post( 19 | '/openai/v1/audio/translations', 20 | Core.multipartFormRequestOptions({ body, ...options }), 21 | ); 22 | } 23 | } 24 | 25 | export interface Translation { 26 | text: string; 27 | } 28 | 29 | export interface TranslationCreateParams { 30 | /** 31 | * ID of the model to use. `whisper-large-v3` and `whisper-large-v3-turbo` are 32 | * currently available. 33 | */ 34 | model: (string & {}) | 'whisper-large-v3' | 'whisper-large-v3-turbo'; 35 | 36 | /** 37 | * The audio file object (not file name) translate, in one of these formats: flac, 38 | * mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. 39 | */ 40 | file?: Core.Uploadable; 41 | 42 | /** 43 | * An optional text to guide the model's style or continue a previous audio 44 | * segment. The [prompt](/docs/guides/speech-to-text/prompting) should be in 45 | * English. 46 | */ 47 | prompt?: string; 48 | 49 | /** 50 | * The format of the transcript output, in one of these options: `json`, `text`, or 51 | * `verbose_json`. 52 | */ 53 | response_format?: 'json' | 'text' | 'verbose_json'; 54 | 55 | /** 56 | * The sampling temperature, between 0 and 1. Higher values like 0.8 will make the 57 | * output more random, while lower values like 0.2 will make it more focused and 58 | * deterministic. If set to 0, the model will use 59 | * [log probability](https://en.wikipedia.org/wiki/Log_probability) to 60 | * automatically increase the temperature until certain thresholds are hit. 61 | */ 62 | temperature?: number; 63 | 64 | /** 65 | * The audio URL to translate/transcribe (supports Base64URL). Either file or url 66 | * must be provided. When using the Batch API only url is supported. 67 | */ 68 | url?: string; 69 | } 70 | 71 | export declare namespace Translations { 72 | export { type Translation as Translation, type TranslationCreateParams as TranslationCreateParams }; 73 | } 74 | -------------------------------------------------------------------------------- /src/resources/chat.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export * from './chat/index'; 4 | -------------------------------------------------------------------------------- /src/resources/chat/chat.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { APIResource } from '../../resource'; 4 | import * as CompletionsAPI from './completions'; 5 | import { 6 | ChatCompletion, 7 | ChatCompletionAssistantMessageParam, 8 | ChatCompletionChunk, 9 | ChatCompletionContentPart, 10 | ChatCompletionContentPartImage, 11 | ChatCompletionContentPartText, 12 | ChatCompletionFunctionCallOption, 13 | ChatCompletionFunctionMessageParam, 14 | ChatCompletionMessage, 15 | ChatCompletionMessageParam, 16 | ChatCompletionMessageToolCall, 17 | ChatCompletionNamedToolChoice, 18 | ChatCompletionRole, 19 | ChatCompletionSystemMessageParam, 20 | ChatCompletionTokenLogprob, 21 | ChatCompletionTool, 22 | ChatCompletionToolChoiceOption, 23 | ChatCompletionToolMessageParam, 24 | ChatCompletionUserMessageParam, 25 | CompletionCreateParams, 26 | Completions, 27 | } from './completions'; 28 | 29 | export class Chat extends APIResource { 30 | completions: CompletionsAPI.Completions = new CompletionsAPI.Completions(this._client); 31 | } 32 | 33 | Chat.Completions = Completions; 34 | 35 | export declare namespace Chat { 36 | export { 37 | Completions as Completions, 38 | type ChatCompletion as ChatCompletion, 39 | type ChatCompletionAssistantMessageParam as ChatCompletionAssistantMessageParam, 40 | type ChatCompletionChunk as ChatCompletionChunk, 41 | type ChatCompletionContentPart as ChatCompletionContentPart, 42 | type ChatCompletionContentPartImage as ChatCompletionContentPartImage, 43 | type ChatCompletionContentPartText as ChatCompletionContentPartText, 44 | type ChatCompletionFunctionCallOption as ChatCompletionFunctionCallOption, 45 | type ChatCompletionFunctionMessageParam as ChatCompletionFunctionMessageParam, 46 | type ChatCompletionMessage as ChatCompletionMessage, 47 | type ChatCompletionMessageParam as ChatCompletionMessageParam, 48 | type ChatCompletionMessageToolCall as ChatCompletionMessageToolCall, 49 | type ChatCompletionNamedToolChoice as ChatCompletionNamedToolChoice, 50 | type ChatCompletionRole as ChatCompletionRole, 51 | type ChatCompletionSystemMessageParam as ChatCompletionSystemMessageParam, 52 | type ChatCompletionTokenLogprob as ChatCompletionTokenLogprob, 53 | type ChatCompletionTool as ChatCompletionTool, 54 | type ChatCompletionToolChoiceOption as ChatCompletionToolChoiceOption, 55 | type ChatCompletionToolMessageParam as ChatCompletionToolMessageParam, 56 | type ChatCompletionUserMessageParam as ChatCompletionUserMessageParam, 57 | type CompletionCreateParams as CompletionCreateParams, 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /src/resources/chat/index.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export { Chat } from './chat'; 4 | export { 5 | Completions, 6 | type ChatCompletion, 7 | type ChatCompletionAssistantMessageParam, 8 | type ChatCompletionChunk, 9 | type ChatCompletionContentPart, 10 | type ChatCompletionContentPartImage, 11 | type ChatCompletionContentPartText, 12 | type ChatCompletionFunctionCallOption, 13 | type ChatCompletionFunctionMessageParam, 14 | type ChatCompletionMessage, 15 | type ChatCompletionMessageParam, 16 | type ChatCompletionMessageToolCall, 17 | type ChatCompletionNamedToolChoice, 18 | type ChatCompletionRole, 19 | type ChatCompletionSystemMessageParam, 20 | type ChatCompletionTokenLogprob, 21 | type ChatCompletionTool, 22 | type ChatCompletionToolChoiceOption, 23 | type ChatCompletionToolMessageParam, 24 | type ChatCompletionUserMessageParam, 25 | type CompletionCreateParams, 26 | } from './completions'; 27 | -------------------------------------------------------------------------------- /src/resources/completions.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { APIResource } from '../resource'; 4 | 5 | export class Completions extends APIResource {} 6 | 7 | /** 8 | * Usage statistics for the completion request. 9 | */ 10 | export interface CompletionUsage { 11 | /** 12 | * Number of tokens in the generated completion. 13 | */ 14 | completion_tokens: number; 15 | 16 | /** 17 | * Number of tokens in the prompt. 18 | */ 19 | prompt_tokens: number; 20 | 21 | /** 22 | * Total number of tokens used in the request (prompt + completion). 23 | */ 24 | total_tokens: number; 25 | 26 | /** 27 | * Time spent generating tokens 28 | */ 29 | completion_time?: number; 30 | 31 | /** 32 | * Time spent processing input tokens 33 | */ 34 | prompt_time?: number; 35 | 36 | /** 37 | * Time the requests was spent queued 38 | */ 39 | queue_time?: number; 40 | 41 | /** 42 | * completion time and prompt time combined 43 | */ 44 | total_time?: number; 45 | } 46 | 47 | export declare namespace Completions { 48 | export { type CompletionUsage as CompletionUsage }; 49 | } 50 | -------------------------------------------------------------------------------- /src/resources/embeddings.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { APIResource } from '../resource'; 4 | import * as Core from '../core'; 5 | 6 | export class Embeddings extends APIResource { 7 | /** 8 | * Creates an embedding vector representing the input text. 9 | * 10 | * @example 11 | * ```ts 12 | * const createEmbeddingResponse = 13 | * await client.embeddings.create({ 14 | * input: 'The quick brown fox jumped over the lazy dog', 15 | * model: 'nomic-embed-text-v1_5', 16 | * }); 17 | * ``` 18 | */ 19 | create( 20 | body: EmbeddingCreateParams, 21 | options?: Core.RequestOptions, 22 | ): Core.APIPromise { 23 | return this._client.post('/openai/v1/embeddings', { body, ...options }); 24 | } 25 | } 26 | 27 | export interface CreateEmbeddingResponse { 28 | /** 29 | * The list of embeddings generated by the model. 30 | */ 31 | data: Array; 32 | 33 | /** 34 | * The name of the model used to generate the embedding. 35 | */ 36 | model: string; 37 | 38 | /** 39 | * The object type, which is always "list". 40 | */ 41 | object: 'list'; 42 | 43 | /** 44 | * The usage information for the request. 45 | */ 46 | usage: CreateEmbeddingResponse.Usage; 47 | } 48 | 49 | export namespace CreateEmbeddingResponse { 50 | /** 51 | * The usage information for the request. 52 | */ 53 | export interface Usage { 54 | /** 55 | * The number of tokens used by the prompt. 56 | */ 57 | prompt_tokens: number; 58 | 59 | /** 60 | * The total number of tokens used by the request. 61 | */ 62 | total_tokens: number; 63 | } 64 | } 65 | 66 | /** 67 | * Represents an embedding vector returned by embedding endpoint. 68 | */ 69 | export interface Embedding { 70 | /** 71 | * The embedding vector, which is a list of floats. The length of vector depends on 72 | * the model as listed in the [embedding guide](/docs/guides/embeddings). 73 | */ 74 | embedding: Array | string; 75 | 76 | /** 77 | * The index of the embedding in the list of embeddings. 78 | */ 79 | index: number; 80 | 81 | /** 82 | * The object type, which is always "embedding". 83 | */ 84 | object: 'embedding'; 85 | } 86 | 87 | export interface EmbeddingCreateParams { 88 | /** 89 | * Input text to embed, encoded as a string or array of tokens. To embed multiple 90 | * inputs in a single request, pass an array of strings or array of token arrays. 91 | * The input must not exceed the max input tokens for the model, cannot be an empty 92 | * string, and any array must be 2048 dimensions or less. 93 | */ 94 | input: string | Array; 95 | 96 | /** 97 | * ID of the model to use. 98 | */ 99 | model: (string & {}) | 'nomic-embed-text-v1_5'; 100 | 101 | /** 102 | * The format to return the embeddings in. Can only be `float` or `base64`. 103 | */ 104 | encoding_format?: 'float' | 'base64'; 105 | 106 | /** 107 | * A unique identifier representing your end-user, which can help us monitor and 108 | * detect abuse. 109 | */ 110 | user?: string | null; 111 | } 112 | 113 | export declare namespace Embeddings { 114 | export { 115 | type CreateEmbeddingResponse as CreateEmbeddingResponse, 116 | type Embedding as Embedding, 117 | type EmbeddingCreateParams as EmbeddingCreateParams, 118 | }; 119 | } 120 | -------------------------------------------------------------------------------- /src/resources/files.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { APIResource } from '../resource'; 4 | import * as Core from '../core'; 5 | import { type Response } from '../_shims/index'; 6 | 7 | export class Files extends APIResource { 8 | /** 9 | * Upload a file that can be used across various endpoints. 10 | * 11 | * The Batch API only supports `.jsonl` files up to 100 MB in size. The input also 12 | * has a specific required [format](/docs/batch). 13 | * 14 | * Please contact us if you need to increase these storage limits. 15 | */ 16 | create(body: FileCreateParams, options?: Core.RequestOptions): Core.APIPromise { 17 | return this._client.post('/openai/v1/files', Core.multipartFormRequestOptions({ body, ...options })); 18 | } 19 | 20 | /** 21 | * Returns a list of files. 22 | */ 23 | list(options?: Core.RequestOptions): Core.APIPromise { 24 | return this._client.get('/openai/v1/files', options); 25 | } 26 | 27 | /** 28 | * Delete a file. 29 | */ 30 | delete(fileId: string, options?: Core.RequestOptions): Core.APIPromise { 31 | return this._client.delete(`/openai/v1/files/${fileId}`, options); 32 | } 33 | 34 | /** 35 | * Returns the contents of the specified file. 36 | */ 37 | content(fileId: string, options?: Core.RequestOptions): Core.APIPromise { 38 | return this._client.get(`/openai/v1/files/${fileId}/content`, { 39 | ...options, 40 | headers: { Accept: 'application/octet-stream', ...options?.headers }, 41 | __binaryResponse: true, 42 | }); 43 | } 44 | 45 | /** 46 | * Returns information about a file. 47 | */ 48 | info(fileId: string, options?: Core.RequestOptions): Core.APIPromise { 49 | return this._client.get(`/openai/v1/files/${fileId}`, options); 50 | } 51 | } 52 | 53 | /** 54 | * The `File` object represents a document that has been uploaded. 55 | */ 56 | export interface FileCreateResponse { 57 | /** 58 | * The file identifier, which can be referenced in the API endpoints. 59 | */ 60 | id?: string; 61 | 62 | /** 63 | * The size of the file, in bytes. 64 | */ 65 | bytes?: number; 66 | 67 | /** 68 | * The Unix timestamp (in seconds) for when the file was created. 69 | */ 70 | created_at?: number; 71 | 72 | /** 73 | * The name of the file. 74 | */ 75 | filename?: string; 76 | 77 | /** 78 | * The object type, which is always `file`. 79 | */ 80 | object?: 'file'; 81 | 82 | /** 83 | * The intended purpose of the file. Supported values are `batch`, and 84 | * `batch_output`. 85 | */ 86 | purpose?: 'batch' | 'batch_output'; 87 | } 88 | 89 | export interface FileListResponse { 90 | data: Array; 91 | 92 | object: 'list'; 93 | } 94 | 95 | export namespace FileListResponse { 96 | /** 97 | * The `File` object represents a document that has been uploaded. 98 | */ 99 | export interface Data { 100 | /** 101 | * The file identifier, which can be referenced in the API endpoints. 102 | */ 103 | id?: string; 104 | 105 | /** 106 | * The size of the file, in bytes. 107 | */ 108 | bytes?: number; 109 | 110 | /** 111 | * The Unix timestamp (in seconds) for when the file was created. 112 | */ 113 | created_at?: number; 114 | 115 | /** 116 | * The name of the file. 117 | */ 118 | filename?: string; 119 | 120 | /** 121 | * The object type, which is always `file`. 122 | */ 123 | object?: 'file'; 124 | 125 | /** 126 | * The intended purpose of the file. Supported values are `batch`, and 127 | * `batch_output`. 128 | */ 129 | purpose?: 'batch' | 'batch_output'; 130 | } 131 | } 132 | 133 | export interface FileDeleteResponse { 134 | id: string; 135 | 136 | deleted: boolean; 137 | 138 | object: 'file'; 139 | } 140 | 141 | /** 142 | * The `File` object represents a document that has been uploaded. 143 | */ 144 | export interface FileInfoResponse { 145 | /** 146 | * The file identifier, which can be referenced in the API endpoints. 147 | */ 148 | id?: string; 149 | 150 | /** 151 | * The size of the file, in bytes. 152 | */ 153 | bytes?: number; 154 | 155 | /** 156 | * The Unix timestamp (in seconds) for when the file was created. 157 | */ 158 | created_at?: number; 159 | 160 | /** 161 | * The name of the file. 162 | */ 163 | filename?: string; 164 | 165 | /** 166 | * The object type, which is always `file`. 167 | */ 168 | object?: 'file'; 169 | 170 | /** 171 | * The intended purpose of the file. Supported values are `batch`, and 172 | * `batch_output`. 173 | */ 174 | purpose?: 'batch' | 'batch_output'; 175 | } 176 | 177 | export interface FileCreateParams { 178 | /** 179 | * The File object (not file name) to be uploaded. 180 | */ 181 | file: Core.Uploadable; 182 | 183 | /** 184 | * The intended purpose of the uploaded file. Use "batch" for 185 | * [Batch API](/docs/api-reference#batches). 186 | */ 187 | purpose: 'batch'; 188 | } 189 | 190 | export declare namespace Files { 191 | export { 192 | type FileCreateResponse as FileCreateResponse, 193 | type FileListResponse as FileListResponse, 194 | type FileDeleteResponse as FileDeleteResponse, 195 | type FileInfoResponse as FileInfoResponse, 196 | type FileCreateParams as FileCreateParams, 197 | }; 198 | } 199 | -------------------------------------------------------------------------------- /src/resources/index.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export * from './shared'; 4 | export { Audio } from './audio/audio'; 5 | export { 6 | Batches, 7 | type BatchCreateResponse, 8 | type BatchRetrieveResponse, 9 | type BatchListResponse, 10 | type BatchCancelResponse, 11 | type BatchCreateParams, 12 | } from './batches'; 13 | export { Chat } from './chat/chat'; 14 | export { Completions, type CompletionUsage } from './completions'; 15 | export { 16 | Embeddings, 17 | type CreateEmbeddingResponse, 18 | type Embedding, 19 | type EmbeddingCreateParams, 20 | } from './embeddings'; 21 | export { 22 | Files, 23 | type FileCreateResponse, 24 | type FileListResponse, 25 | type FileDeleteResponse, 26 | type FileInfoResponse, 27 | type FileCreateParams, 28 | } from './files'; 29 | export { Models, type Model, type ModelDeleted, type ModelListResponse } from './models'; 30 | -------------------------------------------------------------------------------- /src/resources/models.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { APIResource } from '../resource'; 4 | import * as Core from '../core'; 5 | 6 | export class Models extends APIResource { 7 | /** 8 | * Get a specific model 9 | */ 10 | retrieve(model: string, options?: Core.RequestOptions): Core.APIPromise { 11 | return this._client.get(`/openai/v1/models/${model}`, options); 12 | } 13 | 14 | /** 15 | * get all available models 16 | */ 17 | list(options?: Core.RequestOptions): Core.APIPromise { 18 | return this._client.get('/openai/v1/models', options); 19 | } 20 | 21 | /** 22 | * Delete a model 23 | */ 24 | delete(model: string, options?: Core.RequestOptions): Core.APIPromise { 25 | return this._client.delete(`/openai/v1/models/${model}`, options); 26 | } 27 | } 28 | 29 | /** 30 | * Describes an OpenAI model offering that can be used with the API. 31 | */ 32 | export interface Model { 33 | /** 34 | * The model identifier, which can be referenced in the API endpoints. 35 | */ 36 | id: string; 37 | 38 | /** 39 | * The Unix timestamp (in seconds) when the model was created. 40 | */ 41 | created: number; 42 | 43 | /** 44 | * The object type, which is always "model". 45 | */ 46 | object: 'model'; 47 | 48 | /** 49 | * The organization that owns the model. 50 | */ 51 | owned_by: string; 52 | } 53 | 54 | export interface ModelDeleted { 55 | id: string; 56 | 57 | deleted: boolean; 58 | 59 | object: string; 60 | } 61 | 62 | export interface ModelListResponse { 63 | data: Array; 64 | 65 | object: 'list'; 66 | } 67 | 68 | export declare namespace Models { 69 | export { 70 | type Model as Model, 71 | type ModelDeleted as ModelDeleted, 72 | type ModelListResponse as ModelListResponse, 73 | }; 74 | } 75 | -------------------------------------------------------------------------------- /src/resources/shared.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | export interface ErrorObject { 4 | code: string | null; 5 | 6 | message: string; 7 | 8 | param: string | null; 9 | 10 | type: string; 11 | } 12 | 13 | export interface FunctionDefinition { 14 | /** 15 | * The name of the function to be called. Must be a-z, A-Z, 0-9, or contain 16 | * underscores and dashes, with a maximum length of 64. 17 | */ 18 | name: string; 19 | 20 | /** 21 | * A description of what the function does, used by the model to choose when and 22 | * how to call the function. 23 | */ 24 | description?: string; 25 | 26 | /** 27 | * The parameters the functions accepts, described as a JSON Schema object. See the 28 | * docs on [tool use](/docs/tool-use) for examples, and the 29 | * [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for 30 | * documentation about the format. 31 | * 32 | * Omitting `parameters` defines a function with an empty parameter list. 33 | */ 34 | parameters?: FunctionParameters; 35 | } 36 | 37 | /** 38 | * The parameters the functions accepts, described as a JSON Schema object. See the 39 | * docs on [tool use](/docs/tool-use) for examples, and the 40 | * [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for 41 | * documentation about the format. 42 | * 43 | * Omitting `parameters` defines a function with an empty parameter list. 44 | */ 45 | export type FunctionParameters = Record; 46 | -------------------------------------------------------------------------------- /src/shims/node.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import * as types from '../_shims/node-types'; 3 | import { setShims } from '../_shims/registry'; 4 | import { getRuntime } from '../_shims/node-runtime'; 5 | setShims(getRuntime()); 6 | 7 | declare module '../_shims/manual-types' { 8 | export namespace manual { 9 | // @ts-ignore 10 | export type Agent = types.Agent; 11 | // @ts-ignore 12 | export import fetch = types.fetch; 13 | // @ts-ignore 14 | export type Request = types.Request; 15 | // @ts-ignore 16 | export type RequestInfo = types.RequestInfo; 17 | // @ts-ignore 18 | export type RequestInit = types.RequestInit; 19 | // @ts-ignore 20 | export type Response = types.Response; 21 | // @ts-ignore 22 | export type ResponseInit = types.ResponseInit; 23 | // @ts-ignore 24 | export type ResponseType = types.ResponseType; 25 | // @ts-ignore 26 | export type BodyInit = types.BodyInit; 27 | // @ts-ignore 28 | export type Headers = types.Headers; 29 | // @ts-ignore 30 | export type HeadersInit = types.HeadersInit; 31 | // @ts-ignore 32 | export type BlobPropertyBag = types.BlobPropertyBag; 33 | // @ts-ignore 34 | export type FilePropertyBag = types.FilePropertyBag; 35 | // @ts-ignore 36 | export type FileFromPathOptions = types.FileFromPathOptions; 37 | // @ts-ignore 38 | export import FormData = types.FormData; 39 | // @ts-ignore 40 | export import File = types.File; 41 | // @ts-ignore 42 | export import Blob = types.Blob; 43 | // @ts-ignore 44 | export type Readable = types.Readable; 45 | // @ts-ignore 46 | export type FsReadStream = types.FsReadStream; 47 | // @ts-ignore 48 | export import ReadableStream = types.ReadableStream; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/shims/web.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import * as types from '../_shims/web-types'; 3 | import { setShims } from '../_shims/registry'; 4 | import { getRuntime } from '../_shims/web-runtime'; 5 | setShims(getRuntime({ manuallyImported: true })); 6 | 7 | declare module '../_shims/manual-types' { 8 | export namespace manual { 9 | // @ts-ignore 10 | export type Agent = types.Agent; 11 | // @ts-ignore 12 | export import fetch = types.fetch; 13 | // @ts-ignore 14 | export type Request = types.Request; 15 | // @ts-ignore 16 | export type RequestInfo = types.RequestInfo; 17 | // @ts-ignore 18 | export type RequestInit = types.RequestInit; 19 | // @ts-ignore 20 | export type Response = types.Response; 21 | // @ts-ignore 22 | export type ResponseInit = types.ResponseInit; 23 | // @ts-ignore 24 | export type ResponseType = types.ResponseType; 25 | // @ts-ignore 26 | export type BodyInit = types.BodyInit; 27 | // @ts-ignore 28 | export type Headers = types.Headers; 29 | // @ts-ignore 30 | export type HeadersInit = types.HeadersInit; 31 | // @ts-ignore 32 | export type BlobPropertyBag = types.BlobPropertyBag; 33 | // @ts-ignore 34 | export type FilePropertyBag = types.FilePropertyBag; 35 | // @ts-ignore 36 | export type FileFromPathOptions = types.FileFromPathOptions; 37 | // @ts-ignore 38 | export import FormData = types.FormData; 39 | // @ts-ignore 40 | export import File = types.File; 41 | // @ts-ignore 42 | export import Blob = types.Blob; 43 | // @ts-ignore 44 | export type Readable = types.Readable; 45 | // @ts-ignore 46 | export type FsReadStream = types.FsReadStream; 47 | // @ts-ignore 48 | export import ReadableStream = types.ReadableStream; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/uploads.ts: -------------------------------------------------------------------------------- 1 | import { type RequestOptions } from './core'; 2 | import { 3 | FormData, 4 | File, 5 | type Blob, 6 | type FilePropertyBag, 7 | getMultipartRequestOptions, 8 | type FsReadStream, 9 | isFsReadStream, 10 | } from './_shims/index'; 11 | import { MultipartBody } from './_shims/MultipartBody'; 12 | export { fileFromPath } from './_shims/index'; 13 | 14 | type BlobLikePart = string | ArrayBuffer | ArrayBufferView | BlobLike | Uint8Array | DataView; 15 | export type BlobPart = string | ArrayBuffer | ArrayBufferView | Blob | Uint8Array | DataView; 16 | 17 | /** 18 | * Typically, this is a native "File" class. 19 | * 20 | * We provide the {@link toFile} utility to convert a variety of objects 21 | * into the File class. 22 | * 23 | * For convenience, you can also pass a fetch Response, or in Node, 24 | * the result of fs.createReadStream(). 25 | */ 26 | export type Uploadable = FileLike | ResponseLike | FsReadStream; 27 | 28 | /** 29 | * Intended to match web.Blob, node.Blob, node-fetch.Blob, etc. 30 | */ 31 | export interface BlobLike { 32 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/size) */ 33 | readonly size: number; 34 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/type) */ 35 | readonly type: string; 36 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text) */ 37 | text(): Promise; 38 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) */ 39 | slice(start?: number, end?: number): BlobLike; 40 | // unfortunately @types/node-fetch@^2.6.4 doesn't type the arrayBuffer method 41 | } 42 | 43 | /** 44 | * Intended to match web.File, node.File, node-fetch.File, etc. 45 | */ 46 | export interface FileLike extends BlobLike { 47 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) */ 48 | readonly lastModified: number; 49 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) */ 50 | readonly name: string; 51 | } 52 | 53 | /** 54 | * Intended to match web.Response, node.Response, node-fetch.Response, etc. 55 | */ 56 | export interface ResponseLike { 57 | url: string; 58 | blob(): Promise; 59 | } 60 | 61 | export const isResponseLike = (value: any): value is ResponseLike => 62 | value != null && 63 | typeof value === 'object' && 64 | typeof value.url === 'string' && 65 | typeof value.blob === 'function'; 66 | 67 | export const isFileLike = (value: any): value is FileLike => 68 | value != null && 69 | typeof value === 'object' && 70 | typeof value.name === 'string' && 71 | typeof value.lastModified === 'number' && 72 | isBlobLike(value); 73 | 74 | /** 75 | * The BlobLike type omits arrayBuffer() because @types/node-fetch@^2.6.4 lacks it; but this check 76 | * adds the arrayBuffer() method type because it is available and used at runtime 77 | */ 78 | export const isBlobLike = (value: any): value is BlobLike & { arrayBuffer(): Promise } => 79 | value != null && 80 | typeof value === 'object' && 81 | typeof value.size === 'number' && 82 | typeof value.type === 'string' && 83 | typeof value.text === 'function' && 84 | typeof value.slice === 'function' && 85 | typeof value.arrayBuffer === 'function'; 86 | 87 | export const isUploadable = (value: any): value is Uploadable => { 88 | return isFileLike(value) || isResponseLike(value) || isFsReadStream(value); 89 | }; 90 | 91 | export type ToFileInput = Uploadable | Exclude | AsyncIterable; 92 | 93 | /** 94 | * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats 95 | * @param value the raw content of the file. Can be an {@link Uploadable}, {@link BlobLikePart}, or {@link AsyncIterable} of {@link BlobLikePart}s 96 | * @param {string=} name the name of the file. If omitted, toFile will try to determine a file name from bits if possible 97 | * @param {Object=} options additional properties 98 | * @param {string=} options.type the MIME type of the content 99 | * @param {number=} options.lastModified the last modified timestamp 100 | * @returns a {@link File} with the given properties 101 | */ 102 | export async function toFile( 103 | value: ToFileInput | PromiseLike, 104 | name?: string | null | undefined, 105 | options?: FilePropertyBag | undefined, 106 | ): Promise { 107 | // If it's a promise, resolve it. 108 | value = await value; 109 | 110 | // If we've been given a `File` we don't need to do anything 111 | if (isFileLike(value)) { 112 | return value; 113 | } 114 | 115 | if (isResponseLike(value)) { 116 | const blob = await value.blob(); 117 | name ||= new URL(value.url).pathname.split(/[\\/]/).pop() ?? 'unknown_file'; 118 | 119 | // we need to convert the `Blob` into an array buffer because the `Blob` class 120 | // that `node-fetch` defines is incompatible with the web standard which results 121 | // in `new File` interpreting it as a string instead of binary data. 122 | const data = isBlobLike(blob) ? [(await blob.arrayBuffer()) as any] : [blob]; 123 | 124 | return new File(data, name, options); 125 | } 126 | 127 | const bits = await getBytes(value); 128 | 129 | name ||= getName(value) ?? 'unknown_file'; 130 | 131 | if (!options?.type) { 132 | const type = (bits[0] as any)?.type; 133 | if (typeof type === 'string') { 134 | options = { ...options, type }; 135 | } 136 | } 137 | 138 | return new File(bits, name, options); 139 | } 140 | 141 | async function getBytes(value: ToFileInput): Promise> { 142 | let parts: Array = []; 143 | if ( 144 | typeof value === 'string' || 145 | ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc. 146 | value instanceof ArrayBuffer 147 | ) { 148 | parts.push(value); 149 | } else if (isBlobLike(value)) { 150 | parts.push(await value.arrayBuffer()); 151 | } else if ( 152 | isAsyncIterableIterator(value) // includes Readable, ReadableStream, etc. 153 | ) { 154 | for await (const chunk of value) { 155 | parts.push(chunk as BlobPart); // TODO, consider validating? 156 | } 157 | } else { 158 | throw new Error( 159 | `Unexpected data type: ${typeof value}; constructor: ${value?.constructor 160 | ?.name}; props: ${propsForError(value)}`, 161 | ); 162 | } 163 | 164 | return parts; 165 | } 166 | 167 | function propsForError(value: any): string { 168 | const props = Object.getOwnPropertyNames(value); 169 | return `[${props.map((p) => `"${p}"`).join(', ')}]`; 170 | } 171 | 172 | function getName(value: any): string | undefined { 173 | return ( 174 | getStringFromMaybeBuffer(value.name) || 175 | getStringFromMaybeBuffer(value.filename) || 176 | // For fs.ReadStream 177 | getStringFromMaybeBuffer(value.path)?.split(/[\\/]/).pop() 178 | ); 179 | } 180 | 181 | const getStringFromMaybeBuffer = (x: string | Buffer | unknown): string | undefined => { 182 | if (typeof x === 'string') return x; 183 | if (typeof Buffer !== 'undefined' && x instanceof Buffer) return String(x); 184 | return undefined; 185 | }; 186 | 187 | const isAsyncIterableIterator = (value: any): value is AsyncIterableIterator => 188 | value != null && typeof value === 'object' && typeof value[Symbol.asyncIterator] === 'function'; 189 | 190 | export const isMultipartBody = (body: any): body is MultipartBody => 191 | body && typeof body === 'object' && body.body && body[Symbol.toStringTag] === 'MultipartBody'; 192 | 193 | /** 194 | * Returns a multipart/form-data request if any part of the given request body contains a File / Blob value. 195 | * Otherwise returns the request as is. 196 | */ 197 | export const maybeMultipartFormRequestOptions = async >( 198 | opts: RequestOptions, 199 | ): Promise> => { 200 | if (!hasUploadableValue(opts.body)) return opts; 201 | 202 | const form = await createForm(opts.body); 203 | return getMultipartRequestOptions(form, opts); 204 | }; 205 | 206 | export const multipartFormRequestOptions = async >( 207 | opts: RequestOptions, 208 | ): Promise> => { 209 | const form = await createForm(opts.body); 210 | return getMultipartRequestOptions(form, opts); 211 | }; 212 | 213 | export const createForm = async >(body: T | undefined): Promise => { 214 | const form = new FormData(); 215 | await Promise.all(Object.entries(body || {}).map(([key, value]) => addFormValue(form, key, value))); 216 | return form; 217 | }; 218 | 219 | const hasUploadableValue = (value: unknown): boolean => { 220 | if (isUploadable(value)) return true; 221 | if (Array.isArray(value)) return value.some(hasUploadableValue); 222 | if (value && typeof value === 'object') { 223 | for (const k in value) { 224 | if (hasUploadableValue((value as any)[k])) return true; 225 | } 226 | } 227 | return false; 228 | }; 229 | 230 | const addFormValue = async (form: FormData, key: string, value: unknown): Promise => { 231 | if (value === undefined) return; 232 | if (value == null) { 233 | throw new TypeError( 234 | `Received null for "${key}"; to pass null in FormData, you must use the string 'null'`, 235 | ); 236 | } 237 | 238 | // TODO: make nested formats configurable 239 | if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { 240 | form.append(key, String(value)); 241 | } else if (isUploadable(value)) { 242 | const file = await toFile(value); 243 | form.append(key, file as File); 244 | } else if (Array.isArray(value)) { 245 | await Promise.all(value.map((entry) => addFormValue(form, key + '[]', entry))); 246 | } else if (typeof value === 'object') { 247 | await Promise.all( 248 | Object.entries(value).map(([name, prop]) => addFormValue(form, `${key}[${name}]`, prop)), 249 | ); 250 | } else { 251 | throw new TypeError( 252 | `Invalid value given to form, expected a string, number, boolean, object, Array, File or Blob but got ${value} instead`, 253 | ); 254 | } 255 | }; 256 | -------------------------------------------------------------------------------- /src/version.ts: -------------------------------------------------------------------------------- 1 | export const VERSION = '0.23.0'; // x-release-please-version 2 | -------------------------------------------------------------------------------- /tests/api-resources/audio/speech.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import Groq from 'groq-sdk'; 4 | 5 | const client = new Groq({ 6 | apiKey: 'My API Key', 7 | baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', 8 | }); 9 | 10 | describe('resource speech', () => { 11 | // binary tests are currently broken 12 | test.skip('create: required and optional params', async () => { 13 | const response = await client.audio.speech.create({ 14 | input: 'The quick brown fox jumped over the lazy dog', 15 | model: 'playai-tts', 16 | voice: 'Fritz-PlayAI', 17 | response_format: 'flac', 18 | sample_rate: 48000, 19 | speed: 1, 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /tests/api-resources/audio/transcriptions.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import Groq, { toFile } from 'groq-sdk'; 4 | import { Response } from 'node-fetch'; 5 | 6 | const client = new Groq({ 7 | apiKey: 'My API Key', 8 | baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', 9 | }); 10 | 11 | describe('resource transcriptions', () => { 12 | // Unsupported either condition 13 | test.skip('create: only required params', async () => { 14 | const responsePromise = client.audio.transcriptions.create({ model: 'whisper-large-v3-turbo' }); 15 | const rawResponse = await responsePromise.asResponse(); 16 | expect(rawResponse).toBeInstanceOf(Response); 17 | const response = await responsePromise; 18 | expect(response).not.toBeInstanceOf(Response); 19 | const dataAndResponse = await responsePromise.withResponse(); 20 | expect(dataAndResponse.data).toBe(response); 21 | expect(dataAndResponse.response).toBe(rawResponse); 22 | }); 23 | 24 | // Unsupported either condition 25 | test.skip('create: required and optional params', async () => { 26 | const response = await client.audio.transcriptions.create({ 27 | model: 'whisper-large-v3-turbo', 28 | file: await toFile(Buffer.from('# my file contents'), 'README.md'), 29 | language: 'string', 30 | prompt: 'prompt', 31 | response_format: 'json', 32 | temperature: 0, 33 | timestamp_granularities: ['word'], 34 | url: 'url', 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /tests/api-resources/audio/translations.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import Groq, { toFile } from 'groq-sdk'; 4 | import { Response } from 'node-fetch'; 5 | 6 | const client = new Groq({ 7 | apiKey: 'My API Key', 8 | baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', 9 | }); 10 | 11 | describe('resource translations', () => { 12 | // Unsupported either condition 13 | test.skip('create: only required params', async () => { 14 | const responsePromise = client.audio.translations.create({ model: 'whisper-large-v3-turbo' }); 15 | const rawResponse = await responsePromise.asResponse(); 16 | expect(rawResponse).toBeInstanceOf(Response); 17 | const response = await responsePromise; 18 | expect(response).not.toBeInstanceOf(Response); 19 | const dataAndResponse = await responsePromise.withResponse(); 20 | expect(dataAndResponse.data).toBe(response); 21 | expect(dataAndResponse.response).toBe(rawResponse); 22 | }); 23 | 24 | // Unsupported either condition 25 | test.skip('create: required and optional params', async () => { 26 | const response = await client.audio.translations.create({ 27 | model: 'whisper-large-v3-turbo', 28 | file: await toFile(Buffer.from('# my file contents'), 'README.md'), 29 | prompt: 'prompt', 30 | response_format: 'json', 31 | temperature: 0, 32 | url: 'url', 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /tests/api-resources/batches.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import Groq from 'groq-sdk'; 4 | import { Response } from 'node-fetch'; 5 | 6 | const client = new Groq({ 7 | apiKey: 'My API Key', 8 | baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', 9 | }); 10 | 11 | describe('resource batches', () => { 12 | test('create: only required params', async () => { 13 | const responsePromise = client.batches.create({ 14 | completion_window: 'completion_window', 15 | endpoint: '/v1/chat/completions', 16 | input_file_id: 'input_file_id', 17 | }); 18 | const rawResponse = await responsePromise.asResponse(); 19 | expect(rawResponse).toBeInstanceOf(Response); 20 | const response = await responsePromise; 21 | expect(response).not.toBeInstanceOf(Response); 22 | const dataAndResponse = await responsePromise.withResponse(); 23 | expect(dataAndResponse.data).toBe(response); 24 | expect(dataAndResponse.response).toBe(rawResponse); 25 | }); 26 | 27 | test('create: required and optional params', async () => { 28 | const response = await client.batches.create({ 29 | completion_window: 'completion_window', 30 | endpoint: '/v1/chat/completions', 31 | input_file_id: 'input_file_id', 32 | metadata: { foo: 'string' }, 33 | }); 34 | }); 35 | 36 | test('retrieve', async () => { 37 | const responsePromise = client.batches.retrieve('batch_id'); 38 | const rawResponse = await responsePromise.asResponse(); 39 | expect(rawResponse).toBeInstanceOf(Response); 40 | const response = await responsePromise; 41 | expect(response).not.toBeInstanceOf(Response); 42 | const dataAndResponse = await responsePromise.withResponse(); 43 | expect(dataAndResponse.data).toBe(response); 44 | expect(dataAndResponse.response).toBe(rawResponse); 45 | }); 46 | 47 | test('retrieve: request options instead of params are passed correctly', async () => { 48 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 49 | await expect(client.batches.retrieve('batch_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( 50 | Groq.NotFoundError, 51 | ); 52 | }); 53 | 54 | test('list', async () => { 55 | const responsePromise = client.batches.list(); 56 | const rawResponse = await responsePromise.asResponse(); 57 | expect(rawResponse).toBeInstanceOf(Response); 58 | const response = await responsePromise; 59 | expect(response).not.toBeInstanceOf(Response); 60 | const dataAndResponse = await responsePromise.withResponse(); 61 | expect(dataAndResponse.data).toBe(response); 62 | expect(dataAndResponse.response).toBe(rawResponse); 63 | }); 64 | 65 | test('list: request options instead of params are passed correctly', async () => { 66 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 67 | await expect(client.batches.list({ path: '/_stainless_unknown_path' })).rejects.toThrow( 68 | Groq.NotFoundError, 69 | ); 70 | }); 71 | 72 | test('cancel', async () => { 73 | const responsePromise = client.batches.cancel('batch_id'); 74 | const rawResponse = await responsePromise.asResponse(); 75 | expect(rawResponse).toBeInstanceOf(Response); 76 | const response = await responsePromise; 77 | expect(response).not.toBeInstanceOf(Response); 78 | const dataAndResponse = await responsePromise.withResponse(); 79 | expect(dataAndResponse.data).toBe(response); 80 | expect(dataAndResponse.response).toBe(rawResponse); 81 | }); 82 | 83 | test('cancel: request options instead of params are passed correctly', async () => { 84 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 85 | await expect(client.batches.cancel('batch_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( 86 | Groq.NotFoundError, 87 | ); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /tests/api-resources/chat/completions.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import Groq from 'groq-sdk'; 4 | import { Response } from 'node-fetch'; 5 | 6 | const client = new Groq({ 7 | apiKey: 'My API Key', 8 | baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', 9 | }); 10 | 11 | describe('resource completions', () => { 12 | test('create: only required params', async () => { 13 | const responsePromise = client.chat.completions.create({ 14 | messages: [{ content: 'content', role: 'system' }], 15 | model: 'meta-llama/llama-4-scout-17b-16e-instruct', 16 | }); 17 | const rawResponse = await responsePromise.asResponse(); 18 | expect(rawResponse).toBeInstanceOf(Response); 19 | const response = await responsePromise; 20 | expect(response).not.toBeInstanceOf(Response); 21 | const dataAndResponse = await responsePromise.withResponse(); 22 | expect(dataAndResponse.data).toBe(response); 23 | expect(dataAndResponse.response).toBe(rawResponse); 24 | }); 25 | 26 | test('create: required and optional params', async () => { 27 | const response = await client.chat.completions.create({ 28 | messages: [{ content: 'content', role: 'system', name: 'name' }], 29 | model: 'meta-llama/llama-4-scout-17b-16e-instruct', 30 | exclude_domains: ['string'], 31 | frequency_penalty: -2, 32 | function_call: 'none', 33 | functions: [{ name: 'name', description: 'description', parameters: { foo: 'bar' } }], 34 | include_domains: ['string'], 35 | logit_bias: { foo: 0 }, 36 | logprobs: true, 37 | max_completion_tokens: 0, 38 | max_tokens: 0, 39 | metadata: { foo: 'string' }, 40 | n: 1, 41 | parallel_tool_calls: true, 42 | presence_penalty: -2, 43 | reasoning_format: 'hidden', 44 | response_format: { type: 'text' }, 45 | search_settings: { exclude_domains: ['string'], include_domains: ['string'], include_images: true }, 46 | seed: 0, 47 | service_tier: 'auto', 48 | stop: '\n', 49 | store: true, 50 | stream: true, 51 | temperature: 1, 52 | tool_choice: 'none', 53 | tools: [ 54 | { 55 | function: { name: 'name', description: 'description', parameters: { foo: 'bar' } }, 56 | type: 'function', 57 | }, 58 | ], 59 | top_logprobs: 0, 60 | top_p: 1, 61 | user: 'user', 62 | }); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /tests/api-resources/embeddings.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import Groq from 'groq-sdk'; 4 | import { Response } from 'node-fetch'; 5 | 6 | const client = new Groq({ 7 | apiKey: 'My API Key', 8 | baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', 9 | }); 10 | 11 | describe('resource embeddings', () => { 12 | test('create: only required params', async () => { 13 | const responsePromise = client.embeddings.create({ 14 | input: 'The quick brown fox jumped over the lazy dog', 15 | model: 'nomic-embed-text-v1_5', 16 | }); 17 | const rawResponse = await responsePromise.asResponse(); 18 | expect(rawResponse).toBeInstanceOf(Response); 19 | const response = await responsePromise; 20 | expect(response).not.toBeInstanceOf(Response); 21 | const dataAndResponse = await responsePromise.withResponse(); 22 | expect(dataAndResponse.data).toBe(response); 23 | expect(dataAndResponse.response).toBe(rawResponse); 24 | }); 25 | 26 | test('create: required and optional params', async () => { 27 | const response = await client.embeddings.create({ 28 | input: 'The quick brown fox jumped over the lazy dog', 29 | model: 'nomic-embed-text-v1_5', 30 | encoding_format: 'float', 31 | user: 'user', 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /tests/api-resources/files.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import Groq, { toFile } from 'groq-sdk'; 4 | import { Response } from 'node-fetch'; 5 | 6 | const client = new Groq({ 7 | apiKey: 'My API Key', 8 | baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', 9 | }); 10 | 11 | describe('resource files', () => { 12 | test('create: only required params', async () => { 13 | const responsePromise = client.files.create({ 14 | file: await toFile(Buffer.from('# my file contents'), 'README.md'), 15 | purpose: 'batch', 16 | }); 17 | const rawResponse = await responsePromise.asResponse(); 18 | expect(rawResponse).toBeInstanceOf(Response); 19 | const response = await responsePromise; 20 | expect(response).not.toBeInstanceOf(Response); 21 | const dataAndResponse = await responsePromise.withResponse(); 22 | expect(dataAndResponse.data).toBe(response); 23 | expect(dataAndResponse.response).toBe(rawResponse); 24 | }); 25 | 26 | test('create: required and optional params', async () => { 27 | const response = await client.files.create({ 28 | file: await toFile(Buffer.from('# my file contents'), 'README.md'), 29 | purpose: 'batch', 30 | }); 31 | }); 32 | 33 | test('list', async () => { 34 | const responsePromise = client.files.list(); 35 | const rawResponse = await responsePromise.asResponse(); 36 | expect(rawResponse).toBeInstanceOf(Response); 37 | const response = await responsePromise; 38 | expect(response).not.toBeInstanceOf(Response); 39 | const dataAndResponse = await responsePromise.withResponse(); 40 | expect(dataAndResponse.data).toBe(response); 41 | expect(dataAndResponse.response).toBe(rawResponse); 42 | }); 43 | 44 | test('list: request options instead of params are passed correctly', async () => { 45 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 46 | await expect(client.files.list({ path: '/_stainless_unknown_path' })).rejects.toThrow(Groq.NotFoundError); 47 | }); 48 | 49 | test('delete', async () => { 50 | const responsePromise = client.files.delete('file_id'); 51 | const rawResponse = await responsePromise.asResponse(); 52 | expect(rawResponse).toBeInstanceOf(Response); 53 | const response = await responsePromise; 54 | expect(response).not.toBeInstanceOf(Response); 55 | const dataAndResponse = await responsePromise.withResponse(); 56 | expect(dataAndResponse.data).toBe(response); 57 | expect(dataAndResponse.response).toBe(rawResponse); 58 | }); 59 | 60 | test('delete: request options instead of params are passed correctly', async () => { 61 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 62 | await expect(client.files.delete('file_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( 63 | Groq.NotFoundError, 64 | ); 65 | }); 66 | 67 | test('content: request options instead of params are passed correctly', async () => { 68 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 69 | await expect(client.files.content('file_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( 70 | Groq.NotFoundError, 71 | ); 72 | }); 73 | 74 | test('info', async () => { 75 | const responsePromise = client.files.info('file_id'); 76 | const rawResponse = await responsePromise.asResponse(); 77 | expect(rawResponse).toBeInstanceOf(Response); 78 | const response = await responsePromise; 79 | expect(response).not.toBeInstanceOf(Response); 80 | const dataAndResponse = await responsePromise.withResponse(); 81 | expect(dataAndResponse.data).toBe(response); 82 | expect(dataAndResponse.response).toBe(rawResponse); 83 | }); 84 | 85 | test('info: request options instead of params are passed correctly', async () => { 86 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 87 | await expect(client.files.info('file_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( 88 | Groq.NotFoundError, 89 | ); 90 | }); 91 | }); 92 | -------------------------------------------------------------------------------- /tests/api-resources/models.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import Groq from 'groq-sdk'; 4 | import { Response } from 'node-fetch'; 5 | 6 | const client = new Groq({ 7 | apiKey: 'My API Key', 8 | baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', 9 | }); 10 | 11 | describe('resource models', () => { 12 | test('retrieve', async () => { 13 | const responsePromise = client.models.retrieve('model'); 14 | const rawResponse = await responsePromise.asResponse(); 15 | expect(rawResponse).toBeInstanceOf(Response); 16 | const response = await responsePromise; 17 | expect(response).not.toBeInstanceOf(Response); 18 | const dataAndResponse = await responsePromise.withResponse(); 19 | expect(dataAndResponse.data).toBe(response); 20 | expect(dataAndResponse.response).toBe(rawResponse); 21 | }); 22 | 23 | test('retrieve: request options instead of params are passed correctly', async () => { 24 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 25 | await expect(client.models.retrieve('model', { path: '/_stainless_unknown_path' })).rejects.toThrow( 26 | Groq.NotFoundError, 27 | ); 28 | }); 29 | 30 | test('list', async () => { 31 | const responsePromise = client.models.list(); 32 | const rawResponse = await responsePromise.asResponse(); 33 | expect(rawResponse).toBeInstanceOf(Response); 34 | const response = await responsePromise; 35 | expect(response).not.toBeInstanceOf(Response); 36 | const dataAndResponse = await responsePromise.withResponse(); 37 | expect(dataAndResponse.data).toBe(response); 38 | expect(dataAndResponse.response).toBe(rawResponse); 39 | }); 40 | 41 | test('list: request options instead of params are passed correctly', async () => { 42 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 43 | await expect(client.models.list({ path: '/_stainless_unknown_path' })).rejects.toThrow( 44 | Groq.NotFoundError, 45 | ); 46 | }); 47 | 48 | test('delete', async () => { 49 | const responsePromise = client.models.delete('model'); 50 | const rawResponse = await responsePromise.asResponse(); 51 | expect(rawResponse).toBeInstanceOf(Response); 52 | const response = await responsePromise; 53 | expect(response).not.toBeInstanceOf(Response); 54 | const dataAndResponse = await responsePromise.withResponse(); 55 | expect(dataAndResponse.data).toBe(response); 56 | expect(dataAndResponse.response).toBe(rawResponse); 57 | }); 58 | 59 | test('delete: request options instead of params are passed correctly', async () => { 60 | // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error 61 | await expect(client.models.delete('model', { path: '/_stainless_unknown_path' })).rejects.toThrow( 62 | Groq.NotFoundError, 63 | ); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /tests/form.test.ts: -------------------------------------------------------------------------------- 1 | import { multipartFormRequestOptions, createForm } from 'groq-sdk/core'; 2 | import { Blob } from 'groq-sdk/_shims/index'; 3 | import { toFile } from 'groq-sdk'; 4 | 5 | describe('form data validation', () => { 6 | test('valid values do not error', async () => { 7 | await multipartFormRequestOptions({ 8 | body: { 9 | foo: 'foo', 10 | string: 1, 11 | bool: true, 12 | file: await toFile(Buffer.from('some-content')), 13 | blob: new Blob(['Some content'], { type: 'text/plain' }), 14 | }, 15 | }); 16 | }); 17 | 18 | test('null', async () => { 19 | await expect(() => 20 | multipartFormRequestOptions({ 21 | body: { 22 | null: null, 23 | }, 24 | }), 25 | ).rejects.toThrow(TypeError); 26 | }); 27 | 28 | test('undefined is stripped', async () => { 29 | const form = await createForm({ 30 | foo: undefined, 31 | bar: 'baz', 32 | }); 33 | expect(form.has('foo')).toBe(false); 34 | expect(form.get('bar')).toBe('baz'); 35 | }); 36 | 37 | test('nested undefined property is stripped', async () => { 38 | const form = await createForm({ 39 | bar: { 40 | baz: undefined, 41 | }, 42 | }); 43 | expect(Array.from(form.entries())).toEqual([]); 44 | 45 | const form2 = await createForm({ 46 | bar: { 47 | foo: 'string', 48 | baz: undefined, 49 | }, 50 | }); 51 | expect(Array.from(form2.entries())).toEqual([['bar[foo]', 'string']]); 52 | }); 53 | 54 | test('nested undefined array item is stripped', async () => { 55 | const form = await createForm({ 56 | bar: [undefined, undefined], 57 | }); 58 | expect(Array.from(form.entries())).toEqual([]); 59 | 60 | const form2 = await createForm({ 61 | bar: [undefined, 'foo'], 62 | }); 63 | expect(Array.from(form2.entries())).toEqual([['bar[]', 'foo']]); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /tests/responses.test.ts: -------------------------------------------------------------------------------- 1 | import { createResponseHeaders } from 'groq-sdk/core'; 2 | import { Headers } from 'groq-sdk/_shims/index'; 3 | 4 | describe('response parsing', () => { 5 | // TODO: test unicode characters 6 | test('headers are case agnostic', async () => { 7 | const headers = createResponseHeaders(new Headers({ 'Content-Type': 'foo', Accept: 'text/plain' })); 8 | expect(headers['content-type']).toEqual('foo'); 9 | expect(headers['Content-type']).toEqual('foo'); 10 | expect(headers['Content-Type']).toEqual('foo'); 11 | expect(headers['accept']).toEqual('text/plain'); 12 | expect(headers['Accept']).toEqual('text/plain'); 13 | expect(headers['Hello-World']).toBeUndefined(); 14 | }); 15 | 16 | test('duplicate headers are concatenated', () => { 17 | const headers = createResponseHeaders( 18 | new Headers([ 19 | ['Content-Type', 'text/xml'], 20 | ['Content-Type', 'application/json'], 21 | ]), 22 | ); 23 | expect(headers['content-type']).toBe('text/xml, application/json'); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /tests/stringifyQuery.test.ts: -------------------------------------------------------------------------------- 1 | // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. 2 | 3 | import { Groq } from 'groq-sdk'; 4 | 5 | const { stringifyQuery } = Groq.prototype as any; 6 | 7 | describe(stringifyQuery, () => { 8 | for (const [input, expected] of [ 9 | [{ a: '1', b: 2, c: true }, 'a=1&b=2&c=true'], 10 | [{ a: null, b: false, c: undefined }, 'a=&b=false'], 11 | [{ 'a/b': 1.28341 }, `${encodeURIComponent('a/b')}=1.28341`], 12 | [ 13 | { 'a/b': 'c/d', 'e=f': 'g&h' }, 14 | `${encodeURIComponent('a/b')}=${encodeURIComponent('c/d')}&${encodeURIComponent( 15 | 'e=f', 16 | )}=${encodeURIComponent('g&h')}`, 17 | ], 18 | ]) { 19 | it(`${JSON.stringify(input)} -> ${expected}`, () => { 20 | expect(stringifyQuery(input)).toEqual(expected); 21 | }); 22 | } 23 | 24 | for (const value of [[], {}, new Date()]) { 25 | it(`${JSON.stringify(value)} -> `, () => { 26 | expect(() => stringifyQuery({ value })).toThrow(`Cannot stringify type ${typeof value}`); 27 | }); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /tests/uploads.test.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import { toFile, type ResponseLike } from 'groq-sdk/uploads'; 3 | import { File } from 'groq-sdk/_shims/index'; 4 | 5 | class MyClass { 6 | name: string = 'foo'; 7 | } 8 | 9 | function mockResponse({ url, content }: { url: string; content?: Blob }): ResponseLike { 10 | return { 11 | url, 12 | blob: async () => content as any, 13 | }; 14 | } 15 | 16 | describe('toFile', () => { 17 | it('throws a helpful error for mismatched types', async () => { 18 | await expect( 19 | // @ts-expect-error intentionally mismatched type 20 | toFile({ foo: 'string' }), 21 | ).rejects.toThrowErrorMatchingInlineSnapshot( 22 | `"Unexpected data type: object; constructor: Object; props: ["foo"]"`, 23 | ); 24 | 25 | await expect( 26 | // @ts-expect-error intentionally mismatched type 27 | toFile(new MyClass()), 28 | ).rejects.toThrowErrorMatchingInlineSnapshot( 29 | `"Unexpected data type: object; constructor: MyClass; props: ["name"]"`, 30 | ); 31 | }); 32 | 33 | it('disallows string at the type-level', async () => { 34 | // @ts-expect-error we intentionally do not type support for `string` 35 | // to help people avoid passing a file path 36 | const file = await toFile('contents'); 37 | expect(file.text()).resolves.toEqual('contents'); 38 | }); 39 | 40 | it('extracts a file name from a Response', async () => { 41 | const response = mockResponse({ url: 'https://example.com/my/audio.mp3' }); 42 | const file = await toFile(response); 43 | expect(file.name).toEqual('audio.mp3'); 44 | }); 45 | 46 | it('extracts a file name from a File', async () => { 47 | const input = new File(['foo'], 'input.jsonl'); 48 | const file = await toFile(input); 49 | expect(file.name).toEqual('input.jsonl'); 50 | }); 51 | 52 | it('extracts a file name from a ReadStream', async () => { 53 | const input = fs.createReadStream('tests/uploads.test.ts'); 54 | const file = await toFile(input); 55 | expect(file.name).toEqual('uploads.test.ts'); 56 | }); 57 | 58 | it('does not copy File objects', async () => { 59 | const input = new File(['foo'], 'input.jsonl', { type: 'jsonl' }); 60 | const file = await toFile(input); 61 | expect(file).toBe(input); 62 | expect(file.name).toEqual('input.jsonl'); 63 | expect(file.type).toBe('jsonl'); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /tsc-multi.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { "extname": ".js", "module": "commonjs" }, 4 | { "extname": ".mjs", "module": "esnext" } 5 | ], 6 | "projects": ["tsconfig.build.json"] 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["dist/src"], 4 | "exclude": ["dist/src/_shims/*-deno.ts"], 5 | "compilerOptions": { 6 | "rootDir": "./dist/src", 7 | "paths": { 8 | "groq-sdk/*": ["dist/src/*"], 9 | "groq-sdk": ["dist/src/index.ts"], 10 | }, 11 | "noEmit": false, 12 | "declaration": true, 13 | "declarationMap": true, 14 | "outDir": "dist", 15 | "pretty": true, 16 | "sourceMap": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["dist-deno"], 4 | "exclude": [], 5 | "compilerOptions": { 6 | "rootDir": "./dist-deno", 7 | "lib": ["es2020", "DOM"], 8 | "noEmit": true, 9 | "declaration": true, 10 | "declarationMap": true, 11 | "outDir": "dist-deno", 12 | "pretty": true, 13 | "sourceMap": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.dist-src.json: -------------------------------------------------------------------------------- 1 | { 2 | // this config is included in the published src directory to prevent TS errors 3 | // from appearing when users go to source, and VSCode opens the source .ts file 4 | // via declaration maps 5 | "include": ["index.ts"], 6 | "compilerOptions": { 7 | "target": "es2015", 8 | "lib": ["DOM"], 9 | "moduleResolution": "node" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src", "tests", "examples"], 3 | "exclude": ["src/_shims/**/*-deno.ts"], 4 | "compilerOptions": { 5 | "target": "es2020", 6 | "lib": ["es2020"], 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "esModuleInterop": true, 10 | "baseUrl": "./", 11 | "paths": { 12 | "groq-sdk/_shims/auto/*": ["src/_shims/auto/*-node"], 13 | "groq-sdk/*": ["src/*"], 14 | "groq-sdk": ["src/index.ts"] 15 | }, 16 | "noEmit": true, 17 | 18 | "resolveJsonModule": true, 19 | 20 | "forceConsistentCasingInFileNames": true, 21 | 22 | "strict": true, 23 | "noImplicitAny": true, 24 | "strictNullChecks": true, 25 | "strictFunctionTypes": true, 26 | "strictBindCallApply": true, 27 | "strictPropertyInitialization": true, 28 | "noImplicitThis": true, 29 | "noImplicitReturns": true, 30 | "alwaysStrict": true, 31 | "exactOptionalPropertyTypes": true, 32 | "noUncheckedIndexedAccess": true, 33 | "noImplicitOverride": true, 34 | "noPropertyAccessFromIndexSignature": true, 35 | "isolatedModules": false, 36 | 37 | "skipLibCheck": true 38 | } 39 | } 40 | --------------------------------------------------------------------------------