Hermy HQ: self-hostable mission-control template for your Hermes agent
A Next.js 16 + Prisma/Postgres dashboard that pairs with a local Hermes agent over a Postgres message bus: dispatch work, approve side-effecting actions, browse the agent's memory, and watch it run. Ships with an agent-onboarding prompt (ONBOARDING.md) so your Hermes can install it for you step by step. All secrets are env-configured; nothing sensitive is bundled. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
interface AgentChatRequest {
|
||||
agentId: string;
|
||||
message: string;
|
||||
history?: Array<{ role: 'user' | 'assistant'; content: string }>;
|
||||
}
|
||||
|
||||
interface AgentChatResponse {
|
||||
reply: string;
|
||||
agentId: string;
|
||||
}
|
||||
|
||||
const AGENT_PROMPTS: Record<string, string> = {
|
||||
max: "You are Max 🐺, an AI executive assistant and COO-level strategist helping the user run their business. The user is a founder and content creator who runs AI trading bots. Be sharp, concise, strategic. Give real actionable advice.",
|
||||
sage: "You are Sage 🌿, X/Twitter content specialist for the user. You write viral tweets in their voice — conversational, sharp, specific. Focus on hooks that make people stop scrolling. No fluff.",
|
||||
knox: "You are Knox 🔐, operations and trading analyst for the user. You analyze Polymarket and Hyperliquid trading performance, spot patterns, suggest strategy improvements. Be data-driven and direct.",
|
||||
nova: "You are Nova ⭐, YouTube strategy specialist for the user. You write scripts, hooks, thumbnails, titles. Think Mr Beast structure applied to the user's niche.",
|
||||
pixel: "You are Pixel 🎨, web app product specialist for the user's products. You find UX improvements, feature ideas, competitor gaps. Think product manager + growth hacker.",
|
||||
};
|
||||
|
||||
export async function POST(request: NextRequest): Promise<NextResponse<AgentChatResponse | { error: string }>> {
|
||||
try {
|
||||
const body: AgentChatRequest = await request.json();
|
||||
const { agentId, message, history = [] } = body;
|
||||
|
||||
// Validate inputs
|
||||
if (!agentId || !message) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Missing agentId or message' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (!AGENT_PROMPTS[agentId]) {
|
||||
return NextResponse.json(
|
||||
{ error: `Unknown agent: ${agentId}` },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const systemPrompt = AGENT_PROMPTS[agentId];
|
||||
const apiKey = process.env.OPENROUTER_API_KEY;
|
||||
|
||||
if (!apiKey) {
|
||||
console.error('OPENROUTER_API_KEY not configured');
|
||||
return NextResponse.json(
|
||||
{ error: 'API configuration error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
// Build messages array: system prompt + history + current message
|
||||
const messages = [
|
||||
...history,
|
||||
{ role: 'user' as const, content: message },
|
||||
];
|
||||
|
||||
// Call OpenRouter API
|
||||
const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
'HTTP-Referer': 'https://your-app.vercel.app',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'anthropic/claude-haiku-4-5',
|
||||
messages: [
|
||||
{ role: 'system', content: systemPrompt },
|
||||
...messages,
|
||||
],
|
||||
max_tokens: 800,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
console.error('OpenRouter API error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to get response from AI model' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const reply = data.choices?.[0]?.message?.content || '';
|
||||
|
||||
if (!reply) {
|
||||
return NextResponse.json(
|
||||
{ error: 'No response from AI model' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
reply,
|
||||
agentId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Agent chat error:', error);
|
||||
return NextResponse.json(
|
||||
{ error: 'Internal server error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user