Skip to content

Commit 3aca847

Browse files
Backport: feat (provider/gateway): add quota entity id to gateway provider options (#14164)
This is an automated backport of #14154 to the release-v6.0 branch. FYI @mclenhard Co-authored-by: mat lenhard <mclenhard@gmail.com>
1 parent 941ebf2 commit 3aca847

File tree

5 files changed

+102
-0
lines changed

5 files changed

+102
-0
lines changed

.changeset/quick-meals-help.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@ai-sdk/gateway": patch
3+
---
4+
5+
feat (provider/gateway): add quotaEntityId gateway provider option

content/providers/01-ai-sdk-providers/00-ai-gateway.mdx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,10 @@ The following gateway provider options are available:
790790

791791
Restricts routing to models and tools from providers that have signed a BAA with Vercel for the use of AI Gateway (requires Vercel HIPAA BAA add on). BYOK credentials are skipped when `hipaaCompliant` is set to `true` to ensure that requests are only routed to providers that support HIPAA compliance.
792792

793+
- **quotaEntityId** _string_
794+
795+
The unique identifier for the entity against which quota is tracked. Used for quota management and enforcement purposes.
796+
793797
- **providerTimeouts** _object_
794798

795799
Per-provider timeouts for BYOK credentials in milliseconds. Controls how long to wait for a provider to start responding before falling back to the next available provider.
@@ -898,6 +902,25 @@ const { text } = await generateText({
898902
});
899903
```
900904

905+
#### Quota Entity ID Example
906+
907+
Set `quotaEntityId` to track and enforce quota against a specific entity. This is useful for multi-tenant applications where you need to manage quota at the entity level (e.g., per organization or team).
908+
909+
```ts
910+
import type { GatewayProviderOptions } from '@ai-sdk/gateway';
911+
import { generateText } from 'ai';
912+
913+
const { text } = await generateText({
914+
model: 'anthropic/claude-sonnet-4.6',
915+
prompt: 'Summarize this report...',
916+
providerOptions: {
917+
gateway: {
918+
quotaEntityId: 'org-123',
919+
} satisfies GatewayProviderOptions,
920+
},
921+
});
922+
```
923+
901924
### Provider-Specific Options
902925

903926
When using provider-specific options through AI Gateway, use the actual provider name (e.g. `anthropic`, `openai`, not `gateway`) as the key:
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { GatewayProviderOptions } from '@ai-sdk/gateway';
2+
import { streamText } from 'ai';
3+
import { run } from '../lib/run';
4+
5+
run(async () => {
6+
const result = streamText({
7+
model: 'openai/gpt-oss-120b',
8+
prompt: 'Tell me the history of the tenrec in a few sentences.',
9+
providerOptions: {
10+
gateway: {
11+
quotaEntityId: 'org-123',
12+
} satisfies GatewayProviderOptions,
13+
},
14+
});
15+
16+
for await (const textPart of result.textStream) {
17+
process.stdout.write(textPart);
18+
}
19+
20+
console.log();
21+
console.log('Token usage:', await result.usage);
22+
console.log('Finish reason:', await result.finishReason);
23+
console.log(
24+
'Provider metadata:',
25+
JSON.stringify(await result.providerMetadata, null, 2),
26+
);
27+
});

packages/gateway/src/gateway-language-model.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,5 +1616,46 @@ describe('GatewayLanguageModel', () => {
16161616
gateway: { zeroDataRetention: true, hipaaCompliant: true },
16171617
});
16181618
});
1619+
1620+
it('should pass quotaEntityId option', async () => {
1621+
prepareJsonResponse({
1622+
content: { type: 'text', text: 'Test response' },
1623+
});
1624+
1625+
await createTestModel().doGenerate({
1626+
prompt: TEST_PROMPT,
1627+
providerOptions: {
1628+
gateway: {
1629+
quotaEntityId: 'entity-123',
1630+
},
1631+
},
1632+
});
1633+
1634+
const requestBody = await server.calls[0].requestBodyJson;
1635+
expect(requestBody.providerOptions).toEqual({
1636+
gateway: { quotaEntityId: 'entity-123' },
1637+
});
1638+
});
1639+
1640+
it('should pass quotaEntityId with other options', async () => {
1641+
prepareJsonResponse({
1642+
content: { type: 'text', text: 'Test response' },
1643+
});
1644+
1645+
await createTestModel().doGenerate({
1646+
prompt: TEST_PROMPT,
1647+
providerOptions: {
1648+
gateway: {
1649+
quotaEntityId: 'entity-123',
1650+
user: 'user-456',
1651+
},
1652+
},
1653+
});
1654+
1655+
const requestBody = await server.calls[0].requestBodyJson;
1656+
expect(requestBody.providerOptions).toEqual({
1657+
gateway: { quotaEntityId: 'entity-123', user: 'user-456' },
1658+
});
1659+
});
16191660
});
16201661
});

packages/gateway/src/gateway-provider-options.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ const gatewayProviderOptions = lazySchema(() =>
7171
* with Vercel AI Gateway for HIPAA compliance will be used.
7272
*/
7373
hipaaCompliant: z.boolean().optional(),
74+
/**
75+
* The unique identifier for the entity against which quota is tracked.
76+
*
77+
* Used for quota management and enforcement purposes.
78+
*/
79+
quotaEntityId: z.string().optional(),
7480
/**
7581
* Per-provider timeouts for BYOK credentials in milliseconds.
7682
* Controls how long to wait for a provider to start responding

0 commit comments

Comments
 (0)