AI-Powered Scripts
Section titled “AI-Powered Scripts”Add // @ai true to any script (not the pre and post middleware files, .ts or .js, where magic comments have no effect and the helpers are not available) and hoody-exec injects the Vercel AI SDK helpers into the script context: generateText, streamText, and generateObject. There is nothing to import, no SDK to set up, and no API key to manage. The helpers reach 300+ models through Hoody AI.
Because a script file is already an HTTP endpoint, any script can serve AI responses over HTTP.
The @ai magic comment
Section titled “The @ai magic comment”Add the @ai magic comment to any script:
// @mode serverless// @ai true
const { text } = await generateText({ model, prompt: 'Explain quantum computing in one sentence'});
return { answer: text };The script now has:
model: a pre-configured AI model, from@ai-modelor the defaultopenai: the Vercel AI SDK provider factory (createOpenAI), called asopenai(modelId)ai: the helper namespace, withai.generate,ai.stream, andai.objectgenerateText(): returns a complete text responsestreamText(): streams a text responsegenerateObject(): returns a structured JSON object
AI magic comment reference
Section titled “AI magic comment reference”Control AI behavior with these magic comments:
| Comment | Values | Default | Description |
|---|---|---|---|
@ai | true | false | true | Enable AI helpers |
@ai-model | model name | Server default (hoody-ai/hoody-free) | Which model to use |
@ai-temperature | 0 - 2 | Provider default | Creativity level (0 = deterministic, 2 = very creative) |
@ai-max-tokens | positive integer | Provider default | Maximum response length. Other values are ignored |
@ai-key | string | generated default key | API key override (the server-wide default can be set with --ai-key) |
The @ai-model value uses Hoody AI model identifiers in provider/model format:
// Hoody Free (default)// @ai-model hoody-ai/hoody-free// xAI Grok 4.5// @ai-model x-ai/grok-4.5// Moonshot Kimi K3// @ai-model moonshotai/kimi-k3// Meta Llama 4// @ai-model meta-llama/llama-4-maverick// DeepSeek V4// @ai-model deepseek/deepseek-v4-proInjected AI helpers
Section titled “Injected AI helpers”When @ai true is set, these are available in your script:
openai, provider factory
Section titled “openai, provider factory”A Vercel AI SDK provider factory (createOpenAI), pre-connected to the Hoody AI gateway (default https://ai.hoody.com/api/v1) with a server-configured API key, so there is no endpoint or key to set up on your side. Call openai('<model-id>') to build a model instance for a model other than the default, then pass it to generateText, streamText, or generateObject. openai('<model-id>') and the injected model use the chat completions endpoint, which serves every model on the gateway, the free models included. openai.responses('<model-id>') builds a model on the Responses API instead, for a paid model that supports it.
// @ai true
// Build a model from the provider factory and call the AI SDKconst { text } = await generateText({ model: openai('deepseek/deepseek-v4-pro'), prompt: 'Hello!'});
return { reply: text };model, pre-configured model
Section titled “model, pre-configured model”A pre-configured Vercel AI SDK model instance from the @ai-sdk/openai package. Uses the model name from @ai-model, or the server default (hoody-ai/hoody-free unless the server sets --ai-default-model). Pass this to generateText, streamText, or generateObject.
// @ai true// @ai-model deepseek/deepseek-v4-pro
// `model` is already configured with the above modelconst { text } = await generateText({ model, prompt: 'Hello!' });ai, helper namespace
Section titled “ai, helper namespace”A namespace of three convenience methods over the Vercel AI SDK:
ai.generate(options)returns a complete text response and wrapsgenerateTextai.stream(options)streams text chunks as they are produced and wrapsstreamTextai.object(options)returns structured JSON validated against a schema and wrapsgenerateObject
// @ai true
const { text } = await ai.generate({ prompt: 'Hello!' });const { textStream } = await ai.stream({ prompt: 'Write a poem' });const { z } = require('zod');
const schema = z.object({ label: z.string() });const { object } = await ai.object({ schema, prompt: 'Classify this' });generateText(options), text completion
Section titled “generateText(options), text completion”Generate a complete text response. Returns when the full response is ready.
Options: { prompt?, messages?, model, system?, temperature?, maxOutputTokens? } (model is required here: pass the injected model, or openai('<model-id>'))
// @ai true// @ai-model deepseek/deepseek-v4-pro
const { text } = await generateText({ model, prompt: 'Write a haiku about HTTP'});
return { haiku: text };streamText(options), streaming responses
Section titled “streamText(options), streaming responses”Stream response chunks as they are generated. Use it for long responses or real-time UIs.
Options: { prompt?, messages?, model, system?, temperature?, maxOutputTokens? } (model is required here: pass the injected model, or openai('<model-id>'))
// @ai true// @ai-model deepseek/deepseek-v4-pro// @timeout 60000
const { textStream } = await streamText({ model, prompt: req.body.question});
// Stream back to clientres.writeHead(200, { 'Content-Type': 'text/plain' });for await (const chunk of textStream) { res.write(chunk);}res.end();generateObject(options), structured JSON output
Section titled “generateObject(options), structured JSON output”Generate structured JSON that matches a provided schema. A Zod schema validates the AI response automatically. A jsonSchema(...) schema, as in the example below, is only sent to the model: the result is not checked unless you pass an options object with a validate function as its second argument: jsonSchema(schema, { validate }).
Options: { prompt?, messages?, model, schema, system?, temperature?, maxOutputTokens? } (pass the injected model as above)
// @ai true// @ai-model deepseek/deepseek-v4-pro
const { jsonSchema } = require('ai');
const { object } = await generateObject({ model, schema: jsonSchema({ type: 'object', properties: { sentiment: { type: 'string', enum: ['positive', 'negative', 'neutral'] }, confidence: { type: 'number' }, keywords: { type: 'array', items: { type: 'string' } } } }), prompt: `Analyze the sentiment of: "${req.body.text}"`});
return object;// → { sentiment: 'positive', confidence: 0.92, keywords: ['great', 'love'] }AI configuration defaults
Section titled “AI configuration defaults”When @ai true is set, these defaults apply:
| Setting | Default | Override |
|---|---|---|
| AI URL | https://ai.hoody.com/api/v1 | Server-launch --ai-url flag |
| Model | hoody-ai/hoody-free | Server-launch --ai-default-model flag, or @ai-model magic comment per script |
| API Key | A generated default key (container- plus a short hash of the scripts folder path, so containers using the same path get the same key), unless the server sets --ai-key | Server-launch --ai-key flag, or @ai-key magic comment per script |
| Temperature | Provider default | @ai-temperature magic comment (applies to ai.* only) |
| Max Tokens | Provider default | @ai-max-tokens magic comment (applies to ai.* only) |
Override the model, API key, temperature, and max tokens per script with the matching magic comment. The AI URL is set server-wide with --ai-url only.
For example:
// @ai true// @ai-model meta-llama/llama-4-maverick// @ai-key sk-custom-key-here// @ai-temperature 0.3// @ai-max-tokens 2048@ai-key configures the injected openai provider, and @ai-model picks the injected model and the default model of the ai.* helpers. A model you name yourself, such as openai('<model-id>'), overrides @ai-model for that call. @ai-temperature and @ai-max-tokens are applied by the ai.* helpers alone: pass temperature and maxOutputTokens at the call site when you use generateText, streamText, or generateObject directly.
Error handling
Section titled “Error handling”@timeout bounds how long the caller waits, not how long the AI provider runs. If the deadline passes before your script has sent anything, the client gets a 504; if the response has already started streaming, the timeout does not interrupt it. Either way a provider call that has started is left to finish, so a slow model still consumes its tokens and its concurrency slot. The deadline also counts loading the script and waiting for a @concurrent slot; a script that has not started by then never runs, unless pre.ts or pre.js had already sent headers, left the response open and returned nothing, in which case the main script still starts after the deadline. Requests from a proxy hook use the hook’s own deadline instead, which can cut off a stream already under way.
// @ai true// Client gives up after 30 seconds// @timeout 30000
const { text } = await generateText({ model, prompt: req.body.question});
return { answer: text };The AI SDK retries a failed call twice on its own before the error reaches your script, for failures it classifies as retryable (a network error, a 5xx, a rate limit). Nothing in Hoody Exec turns that off. Count it when you wrap a call in your own retry loop: three script-level attempts around a call that already retries twice is nine requests to the provider, not three. Retries cover starting a call only: once a stream has started, an error is not retried, and textStream just ends, so a streamed reply can stop partway with no error. Read fullStream to see error events.
To change how often a call is retried, set maxRetries on a raw generateText, streamText or generateObject call instead of writing your own loop (the ai.* helpers ignore it). maxRetries: 1 allows at most two attempts, and a failure that is not retryable fails at once:
// @ai true// @timeout 60000
const { text } = await generateText({ model, prompt: req.body.question, maxRetries: 1});
return { answer: text };AI magic comment validation
Section titled “AI magic comment validation”To validate AI-related magic comments without executing a script, use the magic comments validation endpoint:
curl -s -X POST "https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.com/api/v1/exec/validate/magic-comments" \ -H "Content-Type: application/json" \ -d '{ "code": "// @ai true\n// @ai-model meta-llama/llama-4-maverick\n// @ai-temperature 0.5\nreturn {};" }'Retrieve the full magic comments schema, including every @ai-* directive, with:
curl "https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.com/api/v1/exec/magic-comments/schema"Example AI endpoints
Section titled “Example AI endpoints”Text summarizer
Section titled “Text summarizer”// @mode serverless// @ai true// @ai-model deepseek/deepseek-v4-pro// @ai-temperature 0.3// @cors reflective// @timeout 30000
if (!req.body?.content) { res.statusCode = 400; return { error: 'Missing content field' };}
// ai.generate applies @ai-temperature above (and @ai-max-tokens, if set);// raw generateText({ model, ... }) uses @ai-model but not the temperatureconst { text } = await ai.generate({ prompt: `Summarize the following text in 2-3 sentences:\n\n${req.body.content}`});
return { summary: text, originalLength: req.body.content.length, summaryLength: text.length};Content classifier
Section titled “Content classifier”// @mode serverless// @ai true// @ai-model hoody-ai/hoody-free// @ai-temperature 0// @cors reflective
const { z } = require('zod');
// ai.object applies the @ai-temperature 0 aboveconst { object } = await ai.object({ schema: z.object({ category: z.enum(['bug', 'feature', 'question', 'docs', 'other']), priority: z.enum(['low', 'medium', 'high', 'critical']), summary: z.string() }), prompt: `Classify this support ticket:\n\n${req.body.ticket}`});
return object;Streaming chatbot
Section titled “Streaming chatbot”// @mode serverless// @ai true// @ai-model deepseek/deepseek-v4-pro// @ai-temperature 0.7// @ai-max-tokens 2048// @cors reflective// @timeout 60000
const messages = req.body.messages || [];
// The system prompt goes in `system`, not in `messages`const { textStream } = await ai.stream({ system: 'You are a helpful assistant. Be concise.', messages});
// Stream Server-Sent Eventsres.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive'});
for await (const chunk of textStream) { res.write(`data: ${JSON.stringify({ text: chunk })}\n\n`);}
res.write('data: [DONE]\n\n');res.end();AI MITM pattern
Section titled “AI MITM pattern”A hoody-exec worker script can act as a MITM (Man-In-The-Middle) proxy for AI requests. Any client pointed at it sends every request through your script, which can intercept, analyze, modify, block, or enhance the interaction.
Deploy the MITM script once, then change one URL in your AI client:
Without MITM: https://ai.hoody.com/api/v1With MITM: https://PROJECT_ID-CONTAINER_ID-exec-1.node-us.containers.hoody.com/api/v1Patterns this enables:
- Tool call tampering: redirect file writes, block dangerous commands
- Human-in-the-loop: pause the AI for approval on high-stakes operations
- Cost optimization: compress prompts, cache responses, route to cheaper models
- Context injection: enhance prompts from your knowledge base automatically
- Observability: log every prompt, response, and decision
Hoody AI Intercept & Control has the complete MITM guide with full examples.