apteva 0.4.4 → 0.4.6
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/App.csbvbyak.js +227 -0
- package/dist/index.html +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/db.ts +98 -19
- package/src/integrations/agentdojo.ts +350 -0
- package/src/openapi.ts +195 -0
- package/src/providers.ts +78 -7
- package/src/routes/api/agent-utils.ts +638 -0
- package/src/routes/api/agents.ts +743 -0
- package/src/routes/api/helpers.ts +12 -0
- package/src/routes/api/integrations.ts +608 -0
- package/src/routes/api/mcp.ts +377 -0
- package/src/routes/api/meta-agent.ts +145 -0
- package/src/routes/api/projects.ts +95 -0
- package/src/routes/api/providers.ts +269 -0
- package/src/routes/api/skills.ts +538 -0
- package/src/routes/api/system.ts +215 -0
- package/src/routes/api/telemetry.ts +143 -0
- package/src/routes/api/users.ts +148 -0
- package/src/routes/api.ts +32 -3477
- package/src/server.ts +1 -1
- package/src/web/components/api/ApiDocsPage.tsx +259 -0
- package/src/web/components/dashboard/Dashboard.tsx +92 -3
- package/src/web/components/mcp/IntegrationsPanel.tsx +15 -8
- package/src/web/components/mcp/McpPage.tsx +458 -174
- package/src/web/components/settings/SettingsPage.tsx +275 -36
- package/src/web/components/skills/SkillsPage.tsx +330 -1
- package/src/web/components/tasks/TasksPage.tsx +187 -58
- package/src/web/context/TelemetryContext.tsx +14 -1
- package/src/web/hooks/useAgents.ts +9 -0
- package/src/web/types.ts +22 -4
- package/dist/App.mbp9atpm.js +0 -227
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { json, debug } from "./helpers";
|
|
2
|
+
import { startAgentProcess, setAgentStatus } from "./agent-utils";
|
|
3
|
+
import { AgentDB, UserDB } from "../../db";
|
|
4
|
+
import { ProviderKeys, Onboarding, getProvidersWithStatus, PROVIDERS, type ProviderId } from "../../providers";
|
|
5
|
+
import { createUser } from "../../auth";
|
|
6
|
+
import { agentProcesses } from "../../server";
|
|
7
|
+
|
|
8
|
+
export async function handleProviderRoutes(
|
|
9
|
+
req: Request,
|
|
10
|
+
path: string,
|
|
11
|
+
method: string,
|
|
12
|
+
authContext?: unknown,
|
|
13
|
+
): Promise<Response | null> {
|
|
14
|
+
// ==================== PROVIDERS ====================
|
|
15
|
+
|
|
16
|
+
// GET /api/providers - List supported providers and models with key status
|
|
17
|
+
if (path === "/api/providers" && method === "GET") {
|
|
18
|
+
const providers = getProvidersWithStatus();
|
|
19
|
+
return json({ providers });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// GET /api/providers/ollama/models - Fetch available models from Ollama
|
|
23
|
+
if (path === "/api/providers/ollama/models" && method === "GET") {
|
|
24
|
+
// Get configured Ollama base URL or use default
|
|
25
|
+
const ollamaUrl = ProviderKeys.getDecrypted("ollama") || "http://localhost:11434";
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const response = await fetch(`${ollamaUrl}/api/tags`, {
|
|
29
|
+
method: "GET",
|
|
30
|
+
headers: { "Accept": "application/json" },
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
return json({ error: "Failed to connect to Ollama", models: [] }, 200);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const data = await response.json() as { models?: Array<{ name: string; size: number; modified_at: string }> };
|
|
38
|
+
const models = (data.models || []).map((m: { name: string; size: number }) => ({
|
|
39
|
+
value: m.name,
|
|
40
|
+
label: m.name,
|
|
41
|
+
size: m.size,
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
return json({ models, connected: true });
|
|
45
|
+
} catch (err) {
|
|
46
|
+
// Ollama not running or not reachable
|
|
47
|
+
return json({
|
|
48
|
+
error: "Ollama not reachable. Make sure Ollama is running.",
|
|
49
|
+
models: [],
|
|
50
|
+
connected: false,
|
|
51
|
+
}, 200);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// GET /api/providers/ollama/status - Check if Ollama is running
|
|
56
|
+
if (path === "/api/providers/ollama/status" && method === "GET") {
|
|
57
|
+
const ollamaUrl = ProviderKeys.getDecrypted("ollama") || "http://localhost:11434";
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const response = await fetch(`${ollamaUrl}/api/tags`, {
|
|
61
|
+
method: "GET",
|
|
62
|
+
signal: AbortSignal.timeout(3000),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (response.ok) {
|
|
66
|
+
const data = await response.json() as { models?: Array<{ name: string }> };
|
|
67
|
+
return json({
|
|
68
|
+
connected: true,
|
|
69
|
+
url: ollamaUrl,
|
|
70
|
+
modelCount: data.models?.length || 0,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return json({ connected: false, url: ollamaUrl, error: "Ollama not responding" });
|
|
74
|
+
} catch {
|
|
75
|
+
return json({ connected: false, url: ollamaUrl, error: "Ollama not reachable" });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ==================== ONBOARDING ====================
|
|
80
|
+
|
|
81
|
+
// GET /api/onboarding/status - Check onboarding status
|
|
82
|
+
if (path === "/api/onboarding/status" && method === "GET") {
|
|
83
|
+
return json(Onboarding.getStatus());
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// POST /api/onboarding/complete - Mark onboarding as complete
|
|
87
|
+
if (path === "/api/onboarding/complete" && method === "POST") {
|
|
88
|
+
Onboarding.complete();
|
|
89
|
+
return json({ success: true });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// POST /api/onboarding/reset - Reset onboarding (for testing)
|
|
93
|
+
if (path === "/api/onboarding/reset" && method === "POST") {
|
|
94
|
+
Onboarding.reset();
|
|
95
|
+
return json({ success: true });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// POST /api/onboarding/user - Create first user during onboarding
|
|
99
|
+
// This endpoint only works when no users exist (enforced by middleware)
|
|
100
|
+
if (path === "/api/onboarding/user" && method === "POST") {
|
|
101
|
+
debug("POST /api/onboarding/user");
|
|
102
|
+
// Double-check no users exist
|
|
103
|
+
if (UserDB.hasUsers()) {
|
|
104
|
+
debug("Users already exist");
|
|
105
|
+
return json({ error: "Users already exist" }, 403);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const body = await req.json();
|
|
110
|
+
debug("Onboarding body:", JSON.stringify(body));
|
|
111
|
+
const { username, password, email } = body;
|
|
112
|
+
|
|
113
|
+
if (!username || !password) {
|
|
114
|
+
debug("Missing username or password");
|
|
115
|
+
return json({ error: "Username and password are required" }, 400);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Create first user as admin
|
|
119
|
+
debug("Creating user:", username);
|
|
120
|
+
const result = await createUser({
|
|
121
|
+
username,
|
|
122
|
+
password,
|
|
123
|
+
email: email || undefined, // Optional, for password recovery
|
|
124
|
+
role: "admin",
|
|
125
|
+
});
|
|
126
|
+
debug("Create user result:", result.success, result.error);
|
|
127
|
+
|
|
128
|
+
if (!result.success) {
|
|
129
|
+
return json({ error: result.error }, 400);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return json({
|
|
133
|
+
success: true,
|
|
134
|
+
user: {
|
|
135
|
+
id: result.user!.id,
|
|
136
|
+
username: result.user!.username,
|
|
137
|
+
role: result.user!.role,
|
|
138
|
+
},
|
|
139
|
+
}, 201);
|
|
140
|
+
} catch (e) {
|
|
141
|
+
debug("Onboarding error:", e);
|
|
142
|
+
return json({ error: "Invalid request body" }, 400);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ==================== API KEYS ====================
|
|
147
|
+
|
|
148
|
+
// GET /api/keys - List all configured provider keys (without actual keys)
|
|
149
|
+
if (path === "/api/keys" && method === "GET") {
|
|
150
|
+
return json({ keys: ProviderKeys.getAll() });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// GET /api/keys/:provider - Get all keys for a provider
|
|
154
|
+
const getProviderKeysMatch = path.match(/^\/api\/keys\/([^/]+)$/);
|
|
155
|
+
|
|
156
|
+
// POST /api/keys/:provider/test - Test an API key (must match before generic :provider routes)
|
|
157
|
+
const testKeyMatch = path.match(/^\/api\/keys\/([^/]+)\/test$/);
|
|
158
|
+
if (testKeyMatch && method === "POST") {
|
|
159
|
+
const providerId = testKeyMatch[1];
|
|
160
|
+
|
|
161
|
+
// Validate provider exists
|
|
162
|
+
if (!PROVIDERS[providerId as ProviderId]) {
|
|
163
|
+
return json({ error: "Unknown provider" }, 400);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
const body = await req.json().catch(() => ({}));
|
|
168
|
+
const { key } = body as { key?: string };
|
|
169
|
+
|
|
170
|
+
// Test with provided key or stored key
|
|
171
|
+
const result = await ProviderKeys.test(providerId, key);
|
|
172
|
+
return json(result);
|
|
173
|
+
} catch (e) {
|
|
174
|
+
return json({ error: "Test failed" }, 500);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// DELETE /api/keys/by-id/:id - Remove a specific API key by ID
|
|
179
|
+
const deleteKeyByIdMatch = path.match(/^\/api\/keys\/by-id\/([^/]+)$/);
|
|
180
|
+
if (deleteKeyByIdMatch && method === "DELETE") {
|
|
181
|
+
const keyId = deleteKeyByIdMatch[1];
|
|
182
|
+
const deleted = ProviderKeys.deleteById(keyId);
|
|
183
|
+
return json({ success: deleted });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (getProviderKeysMatch && method === "GET") {
|
|
187
|
+
const providerId = getProviderKeysMatch[1];
|
|
188
|
+
const keys = ProviderKeys.getAllByProvider(providerId);
|
|
189
|
+
return json({ keys });
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// POST /api/keys/:provider - Save an API key for a provider
|
|
193
|
+
if (getProviderKeysMatch && method === "POST") {
|
|
194
|
+
const providerId = getProviderKeysMatch[1];
|
|
195
|
+
|
|
196
|
+
// Validate provider exists
|
|
197
|
+
if (!PROVIDERS[providerId as ProviderId]) {
|
|
198
|
+
return json({ error: "Unknown provider" }, 400);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
const body = await req.json();
|
|
203
|
+
const { key, project_id, name } = body as { key?: string; project_id?: string | null; name?: string | null };
|
|
204
|
+
|
|
205
|
+
if (!key) {
|
|
206
|
+
return json({ error: "API key is required" }, 400);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const result = await ProviderKeys.save(providerId, key, project_id || null, name || null);
|
|
210
|
+
if (!result.success) {
|
|
211
|
+
return json({ error: result.error }, 400);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Restart any running agents that use this provider (including meta agent)
|
|
215
|
+
const runningAgents = AgentDB.findAll().filter(
|
|
216
|
+
a => a.status === "running" && a.provider === providerId
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
const restartResults: Array<{ id: string; name: string; success: boolean; error?: string }> = [];
|
|
220
|
+
for (const agent of runningAgents) {
|
|
221
|
+
try {
|
|
222
|
+
// Stop the agent
|
|
223
|
+
const agentProc = agentProcesses.get(agent.id);
|
|
224
|
+
if (agentProc) {
|
|
225
|
+
agentProc.proc.kill();
|
|
226
|
+
agentProcesses.delete(agent.id);
|
|
227
|
+
}
|
|
228
|
+
setAgentStatus(agent.id, "stopped", "provider_restart");
|
|
229
|
+
|
|
230
|
+
// Wait a moment for port to be released
|
|
231
|
+
await new Promise(r => setTimeout(r, 500));
|
|
232
|
+
|
|
233
|
+
// Restart the agent with new key
|
|
234
|
+
const startResult = await startAgentProcess(agent, { silent: true });
|
|
235
|
+
restartResults.push({
|
|
236
|
+
id: agent.id,
|
|
237
|
+
name: agent.name,
|
|
238
|
+
success: startResult.success,
|
|
239
|
+
error: startResult.error,
|
|
240
|
+
});
|
|
241
|
+
} catch (e) {
|
|
242
|
+
restartResults.push({
|
|
243
|
+
id: agent.id,
|
|
244
|
+
name: agent.name,
|
|
245
|
+
success: false,
|
|
246
|
+
error: String(e),
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return json({
|
|
252
|
+
success: true,
|
|
253
|
+
message: "API key saved successfully",
|
|
254
|
+
restartedAgents: restartResults.length > 0 ? restartResults : undefined,
|
|
255
|
+
});
|
|
256
|
+
} catch (e) {
|
|
257
|
+
return json({ error: "Invalid request body" }, 400);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// DELETE /api/keys/:provider - Remove a global API key
|
|
262
|
+
if (getProviderKeysMatch && method === "DELETE") {
|
|
263
|
+
const providerId = getProviderKeysMatch[1];
|
|
264
|
+
const deleted = ProviderKeys.delete(providerId);
|
|
265
|
+
return json({ success: deleted });
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return null;
|
|
269
|
+
}
|