@netlify/agent-runner-cli 1.90.1 → 1.90.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin-local.js +36 -31
- package/dist/bin.js +36 -31
- package/dist/index.js +37 -32
- package/dist/skills/netlify-ai-gateway/SKILL.md +7 -74
- package/dist/skills/netlify-forms/SKILL.md +34 -21
- package/package.json +1 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: netlify-ai-gateway
|
|
3
|
-
description: Use Netlify AI Gateway for AI inference in Netlify Functions and server-side code. Use when adding AI/LLM features with OpenAI, Anthropic, or Google Gemini without managing API keys.
|
|
3
|
+
description: Use Netlify AI Gateway for AI inference in Netlify Functions and server-side code. Use when adding AI/LLM features with OpenAI, Anthropic, or Google Gemini without managing API keys. Must be read before selecting or changing any AI model. Contains the list of supported models.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Netlify AI Gateway
|
|
7
7
|
|
|
8
|
+
> **IMPORTANT:** Only use models listed in the "Available Models" section below. AI Gateway does not support every model a provider offers. Using an unsupported model will cause runtime errors.
|
|
9
|
+
|
|
8
10
|
Zero-config AI inference for Netlify projects. Netlify automatically injects environment variables so official
|
|
9
11
|
provider SDKs work without API keys or configuration.
|
|
10
12
|
|
|
@@ -87,7 +89,7 @@ const response = await openai.responses.create({
|
|
|
87
89
|
console.log(response.output_text)
|
|
88
90
|
```
|
|
89
91
|
|
|
90
|
-
###
|
|
92
|
+
### Gemini
|
|
91
93
|
|
|
92
94
|
```bash
|
|
93
95
|
npm install @google/genai
|
|
@@ -201,24 +203,6 @@ for (const item of response.output) {
|
|
|
201
203
|
}
|
|
202
204
|
```
|
|
203
205
|
|
|
204
|
-
### Google Gemini (Imagen)
|
|
205
|
-
|
|
206
|
-
```typescript
|
|
207
|
-
import { GoogleGenAI } from '@google/genai'
|
|
208
|
-
|
|
209
|
-
const ai = new GoogleGenAI({})
|
|
210
|
-
|
|
211
|
-
const response = await ai.models.generateImages({
|
|
212
|
-
model: 'imagen-4.0-generate-001',
|
|
213
|
-
prompt: 'A cute otter in a river',
|
|
214
|
-
config: { numberOfImages: 1 },
|
|
215
|
-
})
|
|
216
|
-
|
|
217
|
-
for (const image of response.generatedImages) {
|
|
218
|
-
const imageBytes = image.image.imageBytes
|
|
219
|
-
}
|
|
220
|
-
```
|
|
221
|
-
|
|
222
206
|
## Netlify Functions
|
|
223
207
|
|
|
224
208
|
Full example of a Netlify Function using AI Gateway:
|
|
@@ -354,64 +338,13 @@ const response = await fetch(`${process.env.ANTHROPIC_BASE_URL}/v1/messages`, {
|
|
|
354
338
|
|
|
355
339
|
## Available Models
|
|
356
340
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
### Anthropic
|
|
360
|
-
|
|
361
|
-
- `claude-opus-4-6`
|
|
362
|
-
- `claude-opus-4-5-20251101`
|
|
363
|
-
- `claude-opus-4-1-20250805`
|
|
364
|
-
- `claude-sonnet-4-5-20250929`
|
|
365
|
-
- `claude-sonnet-4-20250514`
|
|
366
|
-
- `claude-haiku-4-5-20251001`
|
|
367
|
-
- `claude-3-7-sonnet-20250219`
|
|
368
|
-
- `claude-3-5-haiku-20241022`
|
|
369
|
-
|
|
370
|
-
### OpenAI
|
|
341
|
+
For the latest list, see https://docs.netlify.com/build/ai-gateway/overview/.
|
|
371
342
|
|
|
372
|
-
|
|
373
|
-
- `gpt-5.1`
|
|
374
|
-
- `gpt-5.1-codex`
|
|
375
|
-
- `gpt-5`
|
|
376
|
-
- `gpt-5-mini`
|
|
377
|
-
- `gpt-5-nano`
|
|
378
|
-
- `gpt-4.1`
|
|
379
|
-
- `gpt-4.1-mini`
|
|
380
|
-
- `gpt-4.1-nano`
|
|
381
|
-
- `gpt-4o`
|
|
382
|
-
- `gpt-4o-mini`
|
|
383
|
-
- `o3`
|
|
384
|
-
- `o3-mini`
|
|
385
|
-
- `o4-mini`
|
|
386
|
-
- `gpt-image-1` (image generation)
|
|
387
|
-
- `codex-mini-latest`
|
|
388
|
-
|
|
389
|
-
### Google Gemini
|
|
390
|
-
|
|
391
|
-
- `gemini-3-pro-preview`
|
|
392
|
-
- `gemini-3-flash-preview`
|
|
393
|
-
- `gemini-2.5-pro`
|
|
394
|
-
- `gemini-2.5-flash`
|
|
395
|
-
- `gemini-2.5-flash-lite`
|
|
396
|
-
- `gemini-2.0-flash`
|
|
397
|
-
- `gemini-2.0-flash-lite`
|
|
398
|
-
- `imagen-4.0-generate-001` (image generation)
|
|
399
|
-
- `veo-3.0-generate-preview` (video generation)
|
|
343
|
+
<!-- AVAILABLE_MODELS -->
|
|
400
344
|
|
|
401
345
|
## Rate Limits
|
|
402
346
|
|
|
403
|
-
Tokens per minute (TPM) are scoped per **account** across all projects.
|
|
404
|
-
For Anthropic, cached tokens are excluded; for other providers, cached tokens are included.
|
|
405
|
-
For the latest limits, see https://docs.netlify.com/build/ai-gateway/overview/.
|
|
406
|
-
|
|
407
|
-
| Model | Free | Personal | Pro |
|
|
408
|
-
|-------|------|----------|-----|
|
|
409
|
-
| claude-sonnet-4-5-20250929 | 18,000 | 90,000 | 180,000 |
|
|
410
|
-
| gpt-5 | 18,000 | 90,000 | 180,000 |
|
|
411
|
-
| gpt-4o-mini | 250,000 | 500,000 | 750,000 |
|
|
412
|
-
| gemini-2.5-pro | 24,000 | 120,000 | 240,000 |
|
|
413
|
-
|
|
414
|
-
Set up rate limiting rules on your functions to prevent abuse from client-side callers.
|
|
347
|
+
Tokens per minute (TPM) are scoped per **account** across all projects. For current limits per model and plan tier, see https://docs.netlify.com/build/ai-gateway/overview/.
|
|
415
348
|
|
|
416
349
|
## Limitations
|
|
417
350
|
|
|
@@ -49,7 +49,9 @@ form.addEventListener('submit', async (e) => {
|
|
|
49
49
|
})
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
> **SSR apps (
|
|
52
|
+
> **SSR/SPA apps (React, Vue, TanStack Start, Next.js, SvelteKit, Remix, Nuxt):** You MUST create a static HTML skeleton
|
|
53
|
+
> file for build-time form detection. Without it, Netlify cannot detect the form during build and submissions will
|
|
54
|
+
> silently fail. See [JavaScript Frameworks](#javascript-frameworks-ssr--client-rendered-apps) below.
|
|
53
55
|
|
|
54
56
|
**Critical AJAX requirements:**
|
|
55
57
|
|
|
@@ -58,34 +60,43 @@ form.addEventListener('submit', async (e) => {
|
|
|
58
60
|
```html
|
|
59
61
|
<input type="hidden" name="form-name" value="contact" />
|
|
60
62
|
```
|
|
61
|
-
3. For SSR/SPA apps, POST to `/__forms.html` instead of `/` (see JavaScript Frameworks section)
|
|
62
63
|
|
|
63
64
|
## JavaScript Frameworks (SSR & Client-Rendered Apps)
|
|
64
65
|
|
|
65
|
-
Netlify's build bot cannot detect forms rendered client-side. For any SSR or SPA framework (React, Vue, TanStack Start,
|
|
66
|
+
Netlify's build bot cannot detect forms rendered client-side. For any SSR or SPA framework (React, Vue, TanStack Start,
|
|
67
|
+
Next.js, SvelteKit, Remix, Nuxt), you MUST:
|
|
66
68
|
|
|
67
|
-
1. Create
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
1. **Create a static HTML skeleton** in `public/` for build-time form detection — this is the critical step. Without it,
|
|
70
|
+
Netlify never registers the form and submissions will silently fail or 404.
|
|
71
|
+
2. Submit via AJAX with `e.preventDefault()` — full-page POST will not work in SPAs
|
|
72
|
+
3. Include a hidden `form-name` field matching the form's `name` attribute
|
|
70
73
|
|
|
71
74
|
### Static Form Skeleton
|
|
72
75
|
|
|
73
|
-
Create `public/__forms.html
|
|
76
|
+
Create a static HTML file (e.g. `public/__forms.html`) containing every form your app uses. The file name does not
|
|
77
|
+
matter — Netlify scans all HTML files in the build output:
|
|
74
78
|
|
|
75
79
|
```html
|
|
76
80
|
<!-- public/__forms.html — only for Netlify's build bot detection -->
|
|
77
81
|
<html>
|
|
78
82
|
<body>
|
|
79
|
-
<form name="contact" data-netlify="true" hidden>
|
|
83
|
+
<form name="contact" data-netlify="true" netlify-honeypot="bot-field" hidden>
|
|
80
84
|
<input type="hidden" name="form-name" value="contact" />
|
|
81
85
|
<input name="name" />
|
|
82
86
|
<input name="email" />
|
|
83
87
|
<textarea name="message"></textarea>
|
|
88
|
+
<input name="bot-field" />
|
|
84
89
|
</form>
|
|
85
90
|
</body>
|
|
86
91
|
</html>
|
|
87
92
|
```
|
|
88
93
|
|
|
94
|
+
**Rules:**
|
|
95
|
+
|
|
96
|
+
- The form `name` attribute must exactly match the `form-name` value in your React/Vue component
|
|
97
|
+
- Include every field your component submits — Netlify validates field names against the registered form
|
|
98
|
+
- Add `netlify-honeypot="bot-field"` and a `bot-field` input for spam protection
|
|
99
|
+
|
|
89
100
|
### React Example
|
|
90
101
|
|
|
91
102
|
```jsx
|
|
@@ -94,7 +105,7 @@ function ContactForm() {
|
|
|
94
105
|
e.preventDefault()
|
|
95
106
|
const formData = new FormData(e.target)
|
|
96
107
|
|
|
97
|
-
await fetch('/
|
|
108
|
+
await fetch('/', {
|
|
98
109
|
method: 'POST',
|
|
99
110
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
100
111
|
body: new URLSearchParams(formData).toString(),
|
|
@@ -102,9 +113,14 @@ function ContactForm() {
|
|
|
102
113
|
}
|
|
103
114
|
|
|
104
115
|
return (
|
|
105
|
-
<form name="contact" method="POST" onSubmit={handleSubmit}>
|
|
116
|
+
<form name="contact" method="POST" data-netlify="true" netlify-honeypot="bot-field" onSubmit={handleSubmit}>
|
|
106
117
|
{/* Hidden field required for AJAX */}
|
|
107
118
|
<input type="hidden" name="form-name" value="contact" />
|
|
119
|
+
<p style={{ display: 'none' }}>
|
|
120
|
+
<label>
|
|
121
|
+
Don't fill this out: <input name="bot-field" />
|
|
122
|
+
</label>
|
|
123
|
+
</p>
|
|
108
124
|
<input name="name" required />
|
|
109
125
|
<input name="email" type="email" required />
|
|
110
126
|
<textarea name="message" />
|
|
@@ -203,7 +219,8 @@ The `action` path must:
|
|
|
203
219
|
- Be relative to site root
|
|
204
220
|
- Point to an existing page
|
|
205
221
|
|
|
206
|
-
> **Pretty URLs:** Netlify serves `thank-you.html` at `/thank-you` by default. Use `action="/thank-you"`, not
|
|
222
|
+
> **Pretty URLs:** Netlify serves `thank-you.html` at `/thank-you` by default. Use `action="/thank-you"`, not
|
|
223
|
+
> `action="/thank-you.html"` — the `.html` path returns 404.
|
|
207
224
|
|
|
208
225
|
## Notifications
|
|
209
226
|
|
|
@@ -293,17 +310,13 @@ export default async (req: Request, context: Context) => {
|
|
|
293
310
|
|
|
294
311
|
### Form succeeds but no submissions appear (SSR apps)
|
|
295
312
|
|
|
296
|
-
**Cause:**
|
|
313
|
+
**Cause:** The form was not detected during build. Without a static HTML skeleton, Netlify doesn't register the form, so
|
|
314
|
+
submissions are passed through to the SSR handler (Next.js, TanStack Start, SvelteKit, Remix, Nuxt). The SSR handler
|
|
315
|
+
returns 200, so `fetch()` reports success, but Netlify never processes the submission.
|
|
297
316
|
|
|
298
|
-
**Fix:**
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
await fetch('/__forms.html', {
|
|
302
|
-
method: 'POST',
|
|
303
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
304
|
-
body: new URLSearchParams(formData).toString(),
|
|
305
|
-
})
|
|
306
|
-
```
|
|
317
|
+
**Fix:** Create a static HTML skeleton in `public/` (see
|
|
318
|
+
[JavaScript Frameworks](#javascript-frameworks-ssr--client-rendered-apps) section). Once the form is properly registered
|
|
319
|
+
at build time, Netlify intercepts form POSTs at the CDN level before they reach the SSR handler.
|
|
307
320
|
|
|
308
321
|
### File upload fails
|
|
309
322
|
|