Files
vibn-agent-runner/dist/orchestrator.js

163 lines
6.4 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.listSessions = listSessions;
exports.clearSession = clearSession;
exports.orchestratorChat = orchestratorChat;
const genai_1 = require("@google/genai");
const tools_1 = require("./tools");
const MAX_TURNS = 20;
const sessions = new Map();
function getOrCreateSession(sessionId) {
if (!sessions.has(sessionId)) {
sessions.set(sessionId, {
id: sessionId,
history: [],
createdAt: new Date().toISOString(),
lastActiveAt: new Date().toISOString()
});
}
const session = sessions.get(sessionId);
session.lastActiveAt = new Date().toISOString();
return session;
}
function listSessions() {
return Array.from(sessions.values()).map(s => ({
id: s.id,
messages: s.history.length,
createdAt: s.createdAt,
lastActiveAt: s.lastActiveAt
}));
}
function clearSession(sessionId) {
sessions.delete(sessionId);
}
// ---------------------------------------------------------------------------
// Orchestrator system prompt — full Vibn context
// ---------------------------------------------------------------------------
const SYSTEM_PROMPT = `You are the Master Orchestrator for Vibn — an AI-powered cloud development platform.
You are always running. You have full awareness of the Vibn project and can take autonomous action.
## What Vibn is
Vibn is a platform that lets developers build products using AI agents. It includes:
- A cloud IDE (Theia) at theia.vibnai.com
- A frontend app (Next.js) at vibnai.com
- A backend API at api.vibnai.com
- An agent runner (this system) at agents.vibnai.com
- Self-hosted Git at git.vibnai.com
- Self-hosted deployments via Coolify at coolify.vibnai.com
## Your capabilities
You have access to tools that give you full project control:
**Awareness tools** (use these to understand current state):
- list_repos — see all Git repositories
- list_all_issues — see what work is open or in progress
- list_all_apps — see all deployed apps and their status
- get_app_status — check if a specific app is running and healthy
- read_repo_file — read any file from any repo without cloning
**Action tools** (use these to get things done):
- spawn_agent — dispatch Coder, PM, or Marketing agent to do work on a repo
- get_job_status — check if a spawned agent job is done
- deploy_app — trigger a Coolify deployment after code is committed
- gitea_create_issue — create a tracked issue (also triggers agent webhook if labelled)
- gitea_list_issues, gitea_close_issue — manage issue lifecycle
## Available agents you can spawn
- **Coder** — writes code, edits files, runs commands, commits and pushes
- **PM** — writes documentation, manages issues, creates reports
- **Marketing** — writes copy, blog posts, release notes
## How you work
1. When the user gives you a task, think about what needs to happen.
2. Use awareness tools first to understand current state if needed.
3. Break the task into concrete actions.
4. Spawn the right agents with detailed, specific task descriptions.
5. Check back on job status if the user wants to track progress.
6. Report clearly what was done and what's next.
## Your personality
- Direct and clear. No fluff.
- Proactive — if you notice something that needs fixing, mention it.
- Honest about what you can and can't do.
- You speak for the whole system, not just one agent.
## Important context
- All repos are owned by "mark" on git.vibnai.com
- The main repos are: vibn-frontend, vibn-api, vibn-agent-runner, theia-code-os
- The stack: Next.js (frontend), Node.js (API + agent runner), Theia (IDE)
- Coolify manages all deployments on server 34.19.250.135 (Montreal)
- Agent label routing: agent:coder, agent:pm, agent:marketing on Gitea issues`;
async function orchestratorChat(sessionId, userMessage, ctx) {
const apiKey = process.env.GOOGLE_API_KEY;
if (!apiKey)
throw new Error('GOOGLE_API_KEY not set');
const genai = new genai_1.GoogleGenAI({ apiKey });
const session = getOrCreateSession(sessionId);
// Orchestrator gets ALL tools
const functionDeclarations = tools_1.ALL_TOOLS.map(t => ({
name: t.name,
description: t.description,
parameters: t.parameters
}));
// Add user message to history
session.history.push({ role: 'user', parts: [{ text: userMessage }] });
let turn = 0;
let finalReply = '';
const toolCallNames = [];
while (turn < MAX_TURNS) {
turn++;
const response = await genai.models.generateContent({
model: 'gemini-2.5-flash',
contents: session.history,
config: {
systemInstruction: SYSTEM_PROMPT,
tools: [{ functionDeclarations }],
temperature: 0.3,
maxOutputTokens: 8192
}
});
const candidate = response.candidates?.[0];
if (!candidate)
throw new Error('No response from Gemini');
const modelContent = {
role: 'model',
parts: candidate.content?.parts || []
};
session.history.push(modelContent);
const functionCalls = candidate.content?.parts?.filter(p => p.functionCall) ?? [];
// No more tool calls — we have the final answer
if (functionCalls.length === 0) {
finalReply = candidate.content?.parts
?.filter(p => p.text)
.map(p => p.text)
.join('') ?? '';
break;
}
// Execute tool calls
const toolResultParts = [];
for (const part of functionCalls) {
const call = part.functionCall;
const callName = call.name ?? 'unknown';
const callArgs = (call.args ?? {});
toolCallNames.push(callName);
let result;
try {
result = await (0, tools_1.executeTool)(callName, callArgs, ctx);
}
catch (err) {
result = { error: err instanceof Error ? err.message : String(err) };
}
toolResultParts.push({
functionResponse: { name: callName, response: { result } }
});
}
session.history.push({ role: 'user', parts: toolResultParts });
}
if (turn >= MAX_TURNS && !finalReply) {
finalReply = 'I hit the turn limit. Please try a more specific request.';
}
return { reply: finalReply, sessionId, turns: turn, toolCalls: toolCallNames };
}