Skip to content

Complete integration examples for accessing Hoody AI from containers, AI clients, and custom applications.

This guide shows you exactly how to configure and use Hoody AI across different tools and scenarios.


Hoody AI Endpoint:

https://ai.hoody.icu/api/v1

API Key Format:

container-{containerName}

Compatibility: OpenAI-compatible API


Terminal window
# Chat completion from your container
curl -X POST "https://ai.hoody.icu/api/v1/chat/completions" \
-H "Authorization: Bearer container-dev-env" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-4.5",
"messages": [
{"role": "system", "content": "You are a helpful coding assistant."},
{"role": "user", "content": "Write a Python function to calculate fibonacci numbers"}
],
"max_tokens": 1024,
"temperature": 0.7
}'
# Streaming response
curl -X POST "https://ai.hoody.icu/api/v1/chat/completions" \
-H "Authorization: Bearer container-dev-env" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-4o",
"messages": [{"role": "user", "content": "Explain quantum computing"}],
"stream": true
}'
POST Chat completion with system prompt
https://ai.hoody.icu/api/v1/chat/completions
Click "Run" to execute the request
// Using native fetch (Node 18+)
async function askAI(prompt: string) {
const response = await fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer container-dev-env',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'anthropic/claude-sonnet-4.5',
messages: [
{ role: 'user', content: prompt }
],
max_tokens: 2048
})
});
const data = await response.json();
return data.choices[0].message.content;
}
// Example usage
const answer = await askAI('How do I deploy a Next.js app?');
console.log(answer);
import requests
import json
def ask_ai(prompt: str) -> str:
"""Query Hoody AI with a prompt"""
response = requests.post(
'https://ai.hoody.icu/api/v1/chat/completions',
headers={
'Authorization': 'Bearer container-python-app',
'Content-Type': 'application/json'
},
json={
'model': 'anthropic/claude-sonnet-4.5',
'messages': [
{'role': 'user', 'content': prompt}
],
'max_tokens': 2048
}
)
data = response.json()
return data['choices'][0]['message']['content']
# Example usage
answer = ask_ai('Explain Docker containers in simple terms')
print(answer)

hoody-agent has built-in Hoody AI support:

Terminal window
# Create agent task with Hoody AI
curl -X POST "https://{project}-{container}-workspaces-1.node-us.containers.hoody.icu/api/tasks" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Build a REST API for a todo app with SQLite",
"auto_execute": true,
"mode": "code",
"ai_config": {
"provider": "hoody",
"model": "anthropic/claude-sonnet-4.5"
}
}'

No API key needed - hoody-agent automatically uses container-{name} when configured for Hoody AI.

Settings → Models → Add Custom Provider:

  1. Base URL: https://ai.hoody.icu/api/v1
  2. API Key: container-{yourContainerName}
  3. Provider: Custom (OpenAI-compatible)
  4. Models: Select from dropdown (Claude Opus 4.1, GPT-4o, etc.)

Example .cursor/config.json:

{
"openai": {
"baseURL": "https://ai.hoody.icu/api/v1",
"apiKey": "container-cursor-dev"
},
"defaultModel": "anthropic/claude-sonnet-4.5"
}

Extension Settings:

  1. Open Cline settings in VS Code
  2. API Provider: Custom (OpenAI-compatible)
  3. Base URL: https://ai.hoody.icu/api/v1
  4. API Key: container-{containerName}
  5. Model: anthropic/claude-sonnet-4.5

Cline will now route all AI requests through Hoody AI without exposing real keys.

config.json:

{
"models": [
{
"title": "Hoody AI - Claude Sonnet 4.5",
"provider": "openai",
"model": "anthropic/claude-sonnet-4.5",
"apiKey": "container-continue-dev",
"apiBase": "https://ai.hoody.icu/api/v1"
}
]
}

AI Settings:

  1. Provider: Custom OpenAI-compatible
  2. Endpoint: https://ai.hoody.icu/api/v1
  3. API Key: container-windsurf-env
  4. Model: anthropic/claude-sonnet-4.5 or openai/gpt-4o

app/api/chat/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function POST(req: NextRequest) {
const { message } = await req.json();
const response = await fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer container-nextjs-app',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'anthropic/claude-sonnet-4.5',
messages: [
{ role: 'user', content: message }
],
stream: true // Enable streaming
})
});
// Stream response back to client
return new NextResponse(response.body, {
headers: { 'Content-Type': 'text/event-stream' }
});
}
const express = require('express');
const app = express();
app.use(express.json());
app.post('/api/ask', async (req, res) => {
const { prompt } = req.body;
try {
const response = await fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer container-express-api',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'anthropic/claude-haiku-4.0', // Faster, cheaper model
messages: [
{ role: 'user', content: prompt }
],
max_tokens: 1024
})
});
const data = await response.json();
res.json({ answer: data.choices[0].message.content });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(3000);
'use client';
import { useState } from 'react';
export default function AIChat() {
const [prompt, setPrompt] = useState('');
const [response, setResponse] = useState('');
const [loading, setLoading] = useState(false);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
setResponse('');
const res = await fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer container-react-app',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'anthropic/claude-sonnet-4.5',
messages: [{ role: 'user', content: prompt }],
stream: true
})
});
const reader = res.body?.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader!.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n').filter(line => line.trim());
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.slice(6);
if (data === '[DONE]') continue;
const parsed = JSON.parse(data);
const content = parsed.choices[0]?.delta?.content || '';
setResponse(prev => prev + content);
}
}
}
setLoading(false);
}
return (
<form onSubmit={handleSubmit}>
<input
value={prompt}
onChange={e => setPrompt(e.target.value)}
placeholder="Ask me anything..."
/>
<button type="submit" disabled={loading}>
{loading ? 'Thinking...' : 'Send'}
</button>
{response && <div>{response}</div>}
</form>
);
}

Use different models for different tasks:

async function orchestrateTask(userRequest: string) {
// Fast model for classification
const classification = await fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer container-orchestrator',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'anthropic/claude-haiku-4.0', // Fast & cheap
messages: [
{ role: 'user', content: `Classify this request: "${userRequest}".
Categories: code, creative, data, general. Reply with one word.` }
]
})
});
const category = await classification.json();
// Choose model based on category
const modelMap = {
'code': 'anthropic/claude-sonnet-4.5',
'creative': 'openai/gpt-4o',
'data': 'google/gemini-2.5-pro-exp',
'general': 'anthropic/claude-haiku-4.0'
};
const selectedModel = modelMap[category.choices[0].message.content.trim()];
// Execute with optimal model
const response = await fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer container-orchestrator',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: selectedModel,
messages: [{ role: 'user', content: userRequest }]
})
});
return response.json();
}

Execute multiple AI requests simultaneously:

async function parallelAnalysis(text: string) {
const [summary, sentiment, keywords] = await Promise.all([
// Summarization
fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer container-analyzer',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'anthropic/claude-haiku-4.0',
messages: [
{ role: 'user', content: `Summarize in one sentence: ${text}` }
]
})
}).then(r => r.json()),
// Sentiment analysis
fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer container-analyzer',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'anthropic/claude-haiku-4.0',
messages: [
{ role: 'user', content: `Sentiment (positive/negative/neutral): ${text}` }
]
})
}).then(r => r.json()),
// Keyword extraction
fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer container-analyzer',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'anthropic/claude-haiku-4.0',
messages: [
{ role: 'user', content: `Extract 5 keywords: ${text}` }
]
})
}).then(r => r.json())
]);
return { summary, sentiment, keywords };
}
class HoodyAI {
private apiKey: string;
private baseURL = 'https://ai.hoody.icu/api/v1';
private maxRetries = 3;
constructor(containerName: string) {
this.apiKey = `container-${containerName}`;
}
async chat(messages: any[], model: string = 'anthropic/claude-sonnet-4.5') {
let lastError;
for (let attempt = 0; attempt < this.maxRetries; attempt++) {
try {
const response = await fetch(`${this.baseURL}/chat/completions`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ model, messages })
});
if (response.status === 429) {
// Rate limited - exponential backoff
const waitTime = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, waitTime));
continue;
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
return await response.json();
} catch (error) {
lastError = error;
if (attempt < this.maxRetries - 1) {
await new Promise(resolve => setTimeout(resolve, 1000 * (attempt + 1)));
}
}
}
throw lastError;
}
}
// Usage
const ai = new HoodyAI('production-api');
const result = await ai.chat([
{ role: 'user', content: 'Hello!' }
]);

Build a production API that uses AI without key exposure:

// hoody-exec script: api/analyze-code.ts (deploy via scripts/write)
// @mode serverless
// @cors reflective
const { code, language } = req.body;
const aiResponse = await fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer container-code-analyzer',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'anthropic/claude-sonnet-4.5',
messages: [
{
role: 'system',
content: 'You are a code review expert. Analyze code and provide constructive feedback.'
},
{
role: 'user',
content: `Review this ${language} code:\n\n${code}`
}
]
})
});
const analysis = await aiResponse.json();
return {
feedback: analysis.choices[0].message.content,
language,
timestamp: new Date().toISOString()
};

Accessible at:

https://{project}-{container}-exec-1.node-us.containers.hoody.icu/api/analyze-code
// Maintain conversation history
class AIChatSession {
private messages: any[] = [];
private containerKey: string;
constructor(containerName: string) {
this.containerKey = `container-${containerName}`;
}
async send(userMessage: string) {
// Add user message to history
this.messages.push({
role: 'user',
content: userMessage
});
// Get AI response
const response = await fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.containerKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'anthropic/claude-sonnet-4.5',
messages: this.messages
})
});
const data = await response.json();
const assistantMessage = data.choices[0].message;
// Add to history
this.messages.push(assistantMessage);
return assistantMessage.content;
}
reset() {
this.messages = [];
}
}
// Usage
const chat = new AIChatSession('chatbot-prod');
await chat.send('What is Hoody?');
await chat.send('How does it work?'); // Has context from previous message

Use cheaper models for:

  • Classification tasks
  • Simple Q&A
  • Keyword extraction
  • Quick validations
const cheapModel = 'anthropic/claude-haiku-4.0'; // Fast & economical

Use expensive models for:

  • Complex reasoning
  • Code generation
  • Creative writing
  • Multi-step analysis
const powerModel = 'anthropic/claude-opus-4.1'; // Most capable

Always handle AI errors gracefully:

async function safeAICall(prompt: string) {
try {
const response = await fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer container-app',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'anthropic/claude-sonnet-4.5',
messages: [{ role: 'user', content: prompt }]
})
});
if (!response.ok) {
// Log error for monitoring
console.error('AI Error:', response.status, await response.text());
return { error: 'AI service unavailable' };
}
return await response.json();
} catch (error) {
console.error('Network error:', error);
return { error: 'Network error' };
}
}

Always use streaming for user-facing applications:

const response = await fetch('https://ai.hoody.icu/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer container-frontend',
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'anthropic/claude-sonnet-4.5',
messages: [{ role: 'user', content: prompt }],
stream: true // Enable streaming
})
});

Users see results as they’re generated instead of waiting for complete response.