Skip to content

Commit 2f39a2b

Browse files
feat(api): Tool calling features
Add parallel tool calling option to chat completions Allow 'required' as a function call option
1 parent 3b235dd commit 2f39a2b

File tree

8 files changed

+65
-45
lines changed

8 files changed

+65
-45
lines changed

.stats.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
configured_endpoints: 7
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/groqcloud%2Fgroqcloud-0f93f9ac6d4ad16dacaddd7608e104374c83f3bd9d0b9ed4c0273eb27ed998b7.yml
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/groqcloud%2Fgroqcloud-a4c1214ecaa24ad37fbb3c12b8392787ebe0fd51c5e7e08bdf25d7608dc7900b.yml

README.md

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Groq Node API Library
22

3-
[![NPM version](https://img.shields.io/npm/v/groq-sdk.svg)](https://npmjs.org/package/groq-sdk)
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)
44

55
This library provides convenient access to the Groq REST API from server-side TypeScript or JavaScript.
66

@@ -22,12 +22,14 @@ The full API of this library can be found in [api.md](api.md).
2222
```js
2323
import Groq from 'groq-sdk';
2424

25-
const groq = new Groq();
25+
const groq = new Groq({
26+
apiKey: process.env['GROQ_API_KEY'], // This is the default and can be omitted
27+
});
2628

2729
async function main() {
2830
const chatCompletion = await groq.chat.completions.create({
2931
messages: [{ role: 'user', content: 'Explain the importance of low latency LLMs' }],
30-
model: 'mixtral-8x7b-32768',
32+
model: 'llama3-8b-8192',
3133
});
3234

3335
console.log(chatCompletion.choices[0].message.content);
@@ -44,15 +46,17 @@ This library includes TypeScript definitions for all request params and response
4446
```ts
4547
import Groq from 'groq-sdk';
4648

47-
const groq = new Groq();
49+
const groq = new Groq({
50+
apiKey: process.env['GROQ_API_KEY'], // This is the default and can be omitted
51+
});
4852

4953
async function main() {
5054
const params: Groq.Chat.CompletionCreateParams = {
5155
messages: [
5256
{ role: 'system', content: 'You are a helpful assistant.' },
5357
{ role: 'user', content: 'Explain the importance of low latency LLMs' },
5458
],
55-
model: 'mixtral-8x7b-32768',
59+
model: 'llama3-8b-8192',
5660
};
5761
const chatCompletion: Groq.Chat.ChatCompletion = await groq.chat.completions.create(params);
5862
}
@@ -77,7 +81,7 @@ async function main() {
7781
{ role: 'system', content: 'You are a helpful assistant.' },
7882
{ role: 'user', content: 'Explain the importance of low latency LLMs' },
7983
],
80-
model: 'mixtral-8x7b-32768',
84+
model: 'llama3-8b-8192',
8185
})
8286
.catch(async (err) => {
8387
if (err instanceof Groq.APIError) {
@@ -122,7 +126,7 @@ const groq = new Groq({
122126
});
123127

124128
// Or, configure per-request:
125-
await groq.chat.completions.create({ messages: [{ role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Explain the importance of low latency LLMs' }], model: 'mixtral-8x7b-32768' }, {
129+
await groq.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' }, {
126130
maxRetries: 5,
127131
});
128132
```
@@ -139,7 +143,7 @@ const groq = new Groq({
139143
});
140144

141145
// Override per-request:
142-
await groq.chat.completions.create({ messages: [{ role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Explain the importance of low latency LLMs' }], model: 'mixtral-8x7b-32768' }, {
146+
await groq.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' }, {
143147
timeout: 5 * 1000,
144148
});
145149
```
@@ -166,7 +170,7 @@ const response = await groq.chat.completions
166170
{ role: 'system', content: 'You are a helpful assistant.' },
167171
{ role: 'user', content: 'Explain the importance of low latency LLMs' },
168172
],
169-
model: 'mixtral-8x7b-32768',
173+
model: 'llama3-8b-8192',
170174
})
171175
.asResponse();
172176
console.log(response.headers.get('X-My-Header'));
@@ -178,7 +182,7 @@ const { data: chatCompletion, response: raw } = await groq.chat.completions
178182
{ role: 'system', content: 'You are a helpful assistant.' },
179183
{ role: 'user', content: 'Explain the importance of low latency LLMs' },
180184
],
181-
model: 'mixtral-8x7b-32768',
185+
model: 'llama3-8b-8192',
182186
})
183187
.withResponse();
184188
console.log(raw.headers.get('X-My-Header'));
@@ -292,7 +296,7 @@ await groq.chat.completions.create(
292296
{ role: 'system', content: 'You are a helpful assistant.' },
293297
{ role: 'user', content: 'Explain the importance of low latency LLMs' },
294298
],
295-
model: 'mixtral-8x7b-32768',
299+
model: 'llama3-8b-8192',
296300
},
297301
{
298302
httpAgent: new http.Agent({ keepAlive: false }),

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
"scripts": {
1717
"test": "./scripts/test",
1818
"build": "./scripts/build",
19-
"prepack": "echo 'to pack, run yarn build && (cd dist; yarn pack)' && exit 1",
2019
"prepublishOnly": "echo 'to publish, run yarn build && (cd dist; yarn publish)' && exit 1",
2120
"format": "prettier --write --cache --cache-strategy metadata . !dist",
2221
"prepare": "if ./scripts/utils/check-is-in-git-install.sh; then ./scripts/build; fi",

src/core.ts

+27-8
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
type HeadersInit,
2020
} from './_shims/index';
2121
export { type Response };
22-
import { isMultipartBody } from './uploads';
22+
import { BlobLike, isBlobLike, isMultipartBody } from './uploads';
2323
export {
2424
maybeMultipartFormRequestOptions,
2525
multipartFormRequestOptions,
@@ -249,7 +249,17 @@ export abstract class APIClient {
249249
path: string,
250250
opts?: PromiseOrValue<RequestOptions<Req>>,
251251
): APIPromise<Rsp> {
252-
return this.request(Promise.resolve(opts).then((opts) => ({ method, path, ...opts })));
252+
return this.request(
253+
Promise.resolve(opts).then(async (opts) => {
254+
const body =
255+
opts && isBlobLike(opts?.body) ? new DataView(await opts.body.arrayBuffer())
256+
: opts?.body instanceof DataView ? opts.body
257+
: opts?.body instanceof ArrayBuffer ? new DataView(opts.body)
258+
: opts && ArrayBuffer.isView(opts?.body) ? new DataView(opts.body.buffer)
259+
: opts?.body;
260+
return { method, path, ...opts, body };
261+
}),
262+
);
253263
}
254264

255265
getAPIList<Item, PageClass extends AbstractPage<Item> = AbstractPage<Item>>(
@@ -271,6 +281,8 @@ export abstract class APIClient {
271281
const encoded = encoder.encode(body);
272282
return encoded.length.toString();
273283
}
284+
} else if (ArrayBuffer.isView(body)) {
285+
return body.byteLength.toString();
274286
}
275287

276288
return null;
@@ -280,7 +292,9 @@ export abstract class APIClient {
280292
const { method, path, query, headers: headers = {} } = options;
281293

282294
const body =
283-
isMultipartBody(options.body) ? options.body.body
295+
ArrayBuffer.isView(options.body) || (options.__binaryRequest && typeof options.body === 'string') ?
296+
options.body
297+
: isMultipartBody(options.body) ? options.body.body
284298
: options.body ? JSON.stringify(options.body, null, 2)
285299
: null;
286300
const contentLength = this.calculateContentLength(body);
@@ -735,7 +749,9 @@ export type Headers = Record<string, string | null | undefined>;
735749
export type DefaultQuery = Record<string, string | undefined>;
736750
export type KeysEnum<T> = { [P in keyof Required<T>]: true };
737751

738-
export type RequestOptions<Req = unknown | Record<string, unknown> | Readable> = {
752+
export type RequestOptions<
753+
Req = unknown | Record<string, unknown> | Readable | BlobLike | ArrayBufferView | ArrayBuffer,
754+
> = {
739755
method?: HTTPMethod;
740756
path?: string;
741757
query?: Req | undefined;
@@ -749,6 +765,7 @@ export type RequestOptions<Req = unknown | Record<string, unknown> | Readable> =
749765
signal?: AbortSignal | undefined | null;
750766
idempotencyKey?: string;
751767

768+
__binaryRequest?: boolean | undefined;
752769
__binaryResponse?: boolean | undefined;
753770
__streamClass?: typeof Stream;
754771
};
@@ -770,6 +787,7 @@ const requestOptionsKeys: KeysEnum<RequestOptions> = {
770787
signal: true,
771788
idempotencyKey: true,
772789

790+
__binaryRequest: true,
773791
__binaryResponse: true,
774792
__streamClass: true,
775793
};
@@ -783,10 +801,11 @@ export const isRequestOptions = (obj: unknown): obj is RequestOptions => {
783801
);
784802
};
785803

786-
export type FinalRequestOptions<Req = unknown | Record<string, unknown> | Readable> = RequestOptions<Req> & {
787-
method: HTTPMethod;
788-
path: string;
789-
};
804+
export type FinalRequestOptions<Req = unknown | Record<string, unknown> | Readable | DataView> =
805+
RequestOptions<Req> & {
806+
method: HTTPMethod;
807+
path: string;
808+
};
790809

791810
declare const Deno: any;
792811
declare const EdgeRuntime: any;

src/resources/chat/completions.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ export interface ChatCompletionTool {
623623
* `none` is the default when no tools are present. `auto` is the default if tools
624624
* are present.
625625
*/
626-
export type ChatCompletionToolChoiceOption = 'none' | 'auto' | ChatCompletionNamedToolChoice;
626+
export type ChatCompletionToolChoiceOption = 'none' | 'auto' | 'required' | ChatCompletionNamedToolChoice;
627627

628628
export interface ChatCompletionToolMessageParam {
629629
/**
@@ -695,7 +695,7 @@ export interface ChatCompletionCreateParamsBase {
695695
* `none` is the default when no functions are present. `auto` is the default if
696696
* functions are present.
697697
*/
698-
function_call?: 'none' | 'auto' | ChatCompletionFunctionCallOption | null;
698+
function_call?: 'none' | 'auto' | 'required' | ChatCompletionFunctionCallOption | null;
699699

700700
/**
701701
* Deprecated in favor of `tools`.
@@ -726,11 +726,16 @@ export interface ChatCompletionCreateParamsBase {
726726

727727
/**
728728
* How many chat completion choices to generate for each input message. Note that
729-
* you will be charged based on the number of generated tokens across all of the
730-
* choices. Keep `n` as `1` to minimize costs.
729+
* the current moment, only n=1 is supported. Other values will result in a 400
730+
* response.
731731
*/
732732
n?: number | null;
733733

734+
/**
735+
* Whether to enable parallel function calling during tool use.
736+
*/
737+
parallel_tool_calls?: boolean | null;
738+
734739
/**
735740
* Number between -2.0 and 2.0. Positive values penalize new tokens based on
736741
* whether they appear in the text so far, increasing the model's likelihood to
@@ -841,7 +846,7 @@ export namespace CompletionCreateParams {
841846

842847
/**
843848
* The parameters the functions accepts, described as a JSON Schema object. See the
844-
* [guide](/docs/guides/text-generation/function-calling) for examples, and the
849+
* docs on [tool use](/docs/tool-use) for examples, and the
845850
* [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for
846851
* documentation about the format.
847852
*

src/resources/embeddings.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export interface EmbeddingCreateParams {
8888
/**
8989
* ID of the model to use.
9090
*/
91-
model: string;
91+
model: (string & {}) | 'nomic-embed-text-v1_5';
9292

9393
/**
9494
* The format to return the embeddings in. Can only be `float` or `base64`.

src/resources/shared.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export interface FunctionDefinition {
2525

2626
/**
2727
* The parameters the functions accepts, described as a JSON Schema object. See the
28-
* [guide](/docs/guides/text-generation/function-calling) for examples, and the
28+
* docs on [tool use](/docs/tool-use) for examples, and the
2929
* [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for
3030
* documentation about the format.
3131
*
@@ -36,7 +36,7 @@ export interface FunctionDefinition {
3636

3737
/**
3838
* The parameters the functions accepts, described as a JSON Schema object. See the
39-
* [guide](/docs/guides/text-generation/function-calling) for examples, and the
39+
* docs on [tool use](/docs/tool-use) for examples, and the
4040
* [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for
4141
* documentation about the format.
4242
*

tests/api-resources/chat/completions.test.ts

+9-16
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,7 @@ const groq = new Groq({
1111
describe('resource completions', () => {
1212
test('create: only required params', async () => {
1313
const responsePromise = groq.chat.completions.create({
14-
messages: [
15-
{ content: 'string', role: 'system' },
16-
{ content: 'string', role: 'system' },
17-
{ content: 'string', role: 'system' },
18-
],
14+
messages: [{ content: 'string', role: 'system' }],
1915
model: 'string',
2016
});
2117
const rawResponse = await responsePromise.asResponse();
@@ -29,11 +25,7 @@ describe('resource completions', () => {
2925

3026
test('create: required and optional params', async () => {
3127
const response = await groq.chat.completions.create({
32-
messages: [
33-
{ content: 'string', role: 'system', name: 'string', tool_call_id: 'string' },
34-
{ content: 'string', role: 'system', name: 'string', tool_call_id: 'string' },
35-
{ content: 'string', role: 'system', name: 'string', tool_call_id: 'string' },
36-
],
28+
messages: [{ content: 'string', role: 'system', name: 'string' }],
3729
model: 'string',
3830
frequency_penalty: -2,
3931
function_call: 'none',
@@ -46,20 +38,21 @@ describe('resource completions', () => {
4638
logprobs: true,
4739
max_tokens: 0,
4840
n: 1,
41+
parallel_tool_calls: true,
4942
presence_penalty: -2,
50-
response_format: { type: 'string' },
43+
response_format: { type: 'json_object' },
5144
seed: 0,
5245
stop: '\n',
5346
stream: true,
54-
temperature: 0,
47+
temperature: 1,
5548
tool_choice: 'none',
5649
tools: [
57-
{ function: { description: 'string', name: 'string', parameters: { foo: 'bar' } }, type: 'function' },
58-
{ function: { description: 'string', name: 'string', parameters: { foo: 'bar' } }, type: 'function' },
59-
{ function: { description: 'string', name: 'string', parameters: { foo: 'bar' } }, type: 'function' },
50+
{ type: 'function', function: { description: 'string', name: 'string', parameters: { foo: 'bar' } } },
51+
{ type: 'function', function: { description: 'string', name: 'string', parameters: { foo: 'bar' } } },
52+
{ type: 'function', function: { description: 'string', name: 'string', parameters: { foo: 'bar' } } },
6053
],
6154
top_logprobs: 0,
62-
top_p: 0,
55+
top_p: 1,
6356
user: 'string',
6457
});
6558
});

0 commit comments

Comments
 (0)