apteva 0.4.26 → 0.4.30
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/ActivityPage.41nbye4r.js +3 -0
- package/dist/{ApiDocsPage.3q5x9hhg.js → ApiDocsPage.4smnt8m3.js} +1 -1
- package/dist/{App.9bzz8dqh.js → App.0sbax9et.js} +1 -1
- package/dist/{App.a7h91mxr.js → App.0ws427h8.js} +1 -1
- package/dist/App.6q6bar8b.js +4 -0
- package/dist/App.80301vdb.js +4 -0
- package/dist/App.af2wg84v.js +267 -0
- package/dist/{App.wnap3h7r.js → App.ca1rz1ph.js} +1 -1
- package/dist/{App.e54ynjf2.js → App.ensa6z0r.js} +1 -1
- package/dist/{App.sb2fg71h.js → App.f8g7tych.js} +1 -1
- package/dist/App.mvtqv6qc.js +20 -0
- package/dist/{App.2prdcxgq.js → App.ncgc9cxy.js} +1 -1
- package/dist/{App.r2c5nw36.js → App.p0fb1pds.js} +1 -1
- package/dist/{App.6ftxk387.js → App.pmaq48sj.js} +1 -1
- package/dist/{App.40azyqz6.js → App.yv87t9m5.js} +1 -1
- package/dist/App.zjmfm8p6.js +4 -0
- package/dist/ConnectionsPage.anb3rv9a.js +3 -0
- package/dist/McpPage.y396h6fy.js +3 -0
- package/dist/SettingsPage.p1hc60gk.js +3 -0
- package/dist/SkillsPage.yj3xdsay.js +3 -0
- package/dist/{TasksPage.65dcf4vw.js → TasksPage.sjv0khtv.js} +1 -1
- package/dist/TelemetryPage.2qm4w16r.js +3 -0
- package/dist/TestsPage.zzs4qfj8.js +3 -0
- package/dist/index.html +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/channels/telegram.ts +5 -0
- package/src/crypto.ts +25 -4
- package/src/db.ts +27 -2
- package/src/providers.ts +53 -1
- package/src/routes/api/agent-utils.ts +71 -9
- package/src/routes/api/agents.ts +41 -13
- package/src/routes/api/integrations.ts +16 -6
- package/src/routes/api/mcp.ts +7 -0
- package/src/web/components/activity/ActivityPage.tsx +3 -3
- package/src/web/components/agents/AgentCard.tsx +5 -5
- package/src/web/components/agents/AgentPanel.tsx +81 -20
- package/src/web/components/mcp/McpPage.tsx +16 -5
- package/src/web/components/settings/SettingsPage.tsx +331 -40
- package/src/web/context/ProjectContext.tsx +5 -0
- package/src/web/context/TelemetryContext.tsx +14 -0
- package/src/web/types.ts +20 -2
- package/dist/ActivityPage.cycn14ck.js +0 -3
- package/dist/App.0wwyytz2.js +0 -4
- package/dist/App.fq11mvc7.js +0 -4
- package/dist/App.h6k4j1w9.js +0 -4
- package/dist/App.jq5tmjws.js +0 -267
- package/dist/App.k377qek6.js +0 -20
- package/dist/ConnectionsPage.6fyhqfhz.js +0 -3
- package/dist/McpPage.hk2qt1qt.js +0 -3
- package/dist/SettingsPage.gwpx9v7v.js +0 -3
- package/dist/SkillsPage.j5zech2z.js +0 -3
- package/dist/TelemetryPage.07xrbd7k.js +0 -3
- package/dist/TestsPage.q6zfephf.js +0 -3
package/src/routes/api/agents.ts
CHANGED
|
@@ -110,20 +110,47 @@ export async function handleAgentRoutes(
|
|
|
110
110
|
|
|
111
111
|
const updated = AgentDB.update(agentMatch[1], updates);
|
|
112
112
|
|
|
113
|
-
// If agent is running,
|
|
113
|
+
// If agent is running, handle config update
|
|
114
114
|
if (updated && updated.status === "running" && updated.port) {
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
115
|
+
const providerChanged = body.provider !== undefined && body.provider !== agent.provider;
|
|
116
|
+
|
|
117
|
+
if (providerChanged) {
|
|
118
|
+
// Provider changed — must restart to get new API key in env
|
|
119
|
+
console.log(`Provider changed for ${updated.name} (${agent.provider} -> ${updated.provider}), restarting...`);
|
|
120
|
+
const agentProc = agentProcesses.get(updated.id);
|
|
121
|
+
if (agentProc) {
|
|
122
|
+
// Graceful shutdown
|
|
123
|
+
try {
|
|
124
|
+
await fetch(`http://localhost:${updated.port}/shutdown`, {
|
|
125
|
+
method: "POST",
|
|
126
|
+
signal: AbortSignal.timeout(2000),
|
|
127
|
+
});
|
|
128
|
+
await new Promise(r => setTimeout(r, 500));
|
|
129
|
+
} catch {}
|
|
130
|
+
try { agentProc.proc.kill(); } catch {}
|
|
131
|
+
agentProcesses.delete(updated.id);
|
|
121
132
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
133
|
+
setAgentStatus(updated.id, "stopped", "provider_changed");
|
|
134
|
+
// Start with new provider
|
|
135
|
+
const startResult = await startAgentProcess(updated, { silent: true });
|
|
136
|
+
if (!startResult.success) {
|
|
137
|
+
console.error(`Failed to restart agent after provider change: ${startResult.error}`);
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
// Same provider — just push updated config
|
|
141
|
+
const providerKey = ProviderKeys.getDecrypted(updated.provider);
|
|
142
|
+
if (providerKey) {
|
|
143
|
+
const config = buildAgentConfig(updated, providerKey);
|
|
144
|
+
const configResult = await pushConfigToAgent(updated.id, updated.port, config);
|
|
145
|
+
if (!configResult.success) {
|
|
146
|
+
console.error(`Failed to push config to running agent: ${configResult.error}`);
|
|
147
|
+
}
|
|
148
|
+
// Push skills via /skills endpoint
|
|
149
|
+
if (config.skills?.definitions?.length > 0) {
|
|
150
|
+
const skillsResult = await pushSkillsToAgent(updated.id, updated.port, config.skills.definitions);
|
|
151
|
+
if (!skillsResult.success) {
|
|
152
|
+
console.error(`Failed to push skills to running agent: ${skillsResult.error}`);
|
|
153
|
+
}
|
|
127
154
|
}
|
|
128
155
|
}
|
|
129
156
|
}
|
|
@@ -215,10 +242,11 @@ export async function handleAgentRoutes(
|
|
|
215
242
|
return json({ error: "No API key found for this agent" }, 404);
|
|
216
243
|
}
|
|
217
244
|
|
|
218
|
-
// Return masked key (
|
|
245
|
+
// Return masked key + full key (full key only shown on demand by frontend)
|
|
219
246
|
const masked = apiKey.substring(0, 8) + "..." + apiKey.substring(apiKey.length - 4);
|
|
220
247
|
return json({
|
|
221
248
|
apiKey: masked,
|
|
249
|
+
fullKey: apiKey,
|
|
222
250
|
hasKey: true,
|
|
223
251
|
});
|
|
224
252
|
}
|
|
@@ -518,20 +518,29 @@ export async function handleIntegrationRoutes(
|
|
|
518
518
|
}
|
|
519
519
|
|
|
520
520
|
try {
|
|
521
|
+
console.log(`[agentdojo:add] configId=${configId} projectId=${projectId}`);
|
|
521
522
|
const server = await getAgentDojoServer(apiKey, configId);
|
|
522
523
|
if (!server) {
|
|
524
|
+
console.log(`[agentdojo:add] server not found from AgentDojo API for configId=${configId}`);
|
|
523
525
|
return json({ error: "Config not found" }, 404);
|
|
524
526
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
527
|
+
console.log(`[agentdojo:add] fetched server: slug=${server.slug} name=${server.name} url=${server.url?.substring(0, 80)}`);
|
|
528
|
+
|
|
529
|
+
// Check if already exists — match by slug in URL, scoped to same project
|
|
530
|
+
const effectiveProjectId = projectId && projectId !== "unassigned" ? projectId : null;
|
|
531
|
+
const allServers = McpServerDB.findAll();
|
|
532
|
+
const agentdojoServers = allServers.filter(s => s.source === "agentdojo");
|
|
533
|
+
console.log(`[agentdojo:add] total servers=${allServers.length} agentdojo servers=${agentdojoServers.length}`);
|
|
534
|
+
const existing = agentdojoServers.find(
|
|
535
|
+
s => s.project_id === effectiveProjectId && s.url?.endsWith(`/${server.slug}`)
|
|
529
536
|
);
|
|
530
537
|
if (existing) {
|
|
538
|
+
console.log(`[agentdojo:add] ALREADY EXISTS: id=${existing.id} project_id=${existing.project_id} slug=${server.slug}`);
|
|
531
539
|
return json({ server: existing, message: "Server already exists" });
|
|
532
540
|
}
|
|
533
541
|
|
|
534
542
|
// Create the MCP server entry
|
|
543
|
+
console.log(`[agentdojo:add] creating new server with effectiveProjectId=${effectiveProjectId}`);
|
|
535
544
|
const mcpServer = McpServerDB.create({
|
|
536
545
|
id: generateId(),
|
|
537
546
|
name: server.name,
|
|
@@ -544,12 +553,13 @@ export async function handleIntegrationRoutes(
|
|
|
544
553
|
url: server.url,
|
|
545
554
|
headers: { "X-API-Key": apiKey },
|
|
546
555
|
source: "agentdojo",
|
|
547
|
-
project_id:
|
|
556
|
+
project_id: effectiveProjectId,
|
|
548
557
|
});
|
|
558
|
+
console.log(`[agentdojo:add] created server: id=${mcpServer.id} project_id=${mcpServer.project_id}`);
|
|
549
559
|
|
|
550
560
|
return json({ server: mcpServer, message: "Server added successfully" });
|
|
551
561
|
} catch (e) {
|
|
552
|
-
console.error("Failed to add AgentDojo config:", e);
|
|
562
|
+
console.error("[agentdojo:add] Failed to add AgentDojo config:", e);
|
|
553
563
|
return json({ error: "Failed to add AgentDojo config" }, 500);
|
|
554
564
|
}
|
|
555
565
|
}
|
package/src/routes/api/mcp.ts
CHANGED
|
@@ -25,16 +25,23 @@ export async function handleMcpRoutes(
|
|
|
25
25
|
const forAgent = url.searchParams.get("forAgent"); // agent's project ID (shows global + project)
|
|
26
26
|
|
|
27
27
|
let servers;
|
|
28
|
+
let queryMode: string;
|
|
28
29
|
if (forAgent !== null) {
|
|
29
30
|
// Get servers available for an agent (global + agent's project)
|
|
30
31
|
servers = McpServerDB.findForAgent(forAgent || null);
|
|
32
|
+
queryMode = `forAgent=${forAgent}`;
|
|
31
33
|
} else if (projectFilter === "global") {
|
|
32
34
|
servers = McpServerDB.findGlobal();
|
|
35
|
+
queryMode = "global";
|
|
33
36
|
} else if (projectFilter && projectFilter !== "all") {
|
|
34
37
|
servers = McpServerDB.findByProject(projectFilter);
|
|
38
|
+
queryMode = `project=${projectFilter}`;
|
|
35
39
|
} else {
|
|
36
40
|
servers = McpServerDB.findAll();
|
|
41
|
+
queryMode = "all";
|
|
37
42
|
}
|
|
43
|
+
const agentdojoCount = servers.filter(s => s.source === "agentdojo").length;
|
|
44
|
+
console.log(`[mcp:GET] mode=${queryMode} total=${servers.length} agentdojo=${agentdojoCount}`);
|
|
38
45
|
return json({ servers });
|
|
39
46
|
}
|
|
40
47
|
|
|
@@ -216,7 +216,7 @@ function AgentRow({ agent, selected, onSelect }: {
|
|
|
216
216
|
selected: boolean;
|
|
217
217
|
onSelect: () => void;
|
|
218
218
|
}) {
|
|
219
|
-
const { isActive,
|
|
219
|
+
const { isActive, label } = useAgentActivity(agent.id);
|
|
220
220
|
const isRunning = agent.status === "running";
|
|
221
221
|
|
|
222
222
|
return (
|
|
@@ -244,8 +244,8 @@ function AgentRow({ agent, selected, onSelect }: {
|
|
|
244
244
|
</span>
|
|
245
245
|
<span className="text-[10px] text-[#555] shrink-0">{agent.provider}</span>
|
|
246
246
|
</div>
|
|
247
|
-
{isActive &&
|
|
248
|
-
<p className="text-[11px] text-green-400 truncate">{
|
|
247
|
+
{isActive && label ? (
|
|
248
|
+
<p className="text-[11px] text-green-400 truncate">{label}</p>
|
|
249
249
|
) : (
|
|
250
250
|
<p className={`text-[11px] ${isRunning ? "text-[#555]" : "text-[#444]"}`}>
|
|
251
251
|
{isRunning ? "idle" : "stopped"}
|
|
@@ -26,7 +26,7 @@ export function AgentCard({ agent, selected, onSelect, onToggle, showProject }:
|
|
|
26
26
|
const enabledFeatures = FEATURE_ICONS.filter(f => agent.features?.[f.key]);
|
|
27
27
|
const mcpServers = agent.mcpServerDetails || [];
|
|
28
28
|
const skills = agent.skillDetails || [];
|
|
29
|
-
const { isActive,
|
|
29
|
+
const { isActive, label: activityLabel } = useAgentActivity(agent.id);
|
|
30
30
|
const { projects } = useProjects();
|
|
31
31
|
const { authFetch } = useAuth();
|
|
32
32
|
const project = agent.projectId ? projects.find(p => p.id === agent.projectId) : null;
|
|
@@ -62,7 +62,7 @@ export function AgentCard({ agent, selected, onSelect, onToggle, showProject }:
|
|
|
62
62
|
</p>
|
|
63
63
|
)}
|
|
64
64
|
</div>
|
|
65
|
-
<StatusBadge status={agent.status} isActive={isActive && agent.status === "running"}
|
|
65
|
+
<StatusBadge status={agent.status} isActive={isActive && agent.status === "running"} activityLabel={activityLabel} />
|
|
66
66
|
</div>
|
|
67
67
|
|
|
68
68
|
{enabledFeatures.length > 0 && (
|
|
@@ -165,11 +165,11 @@ export function AgentCard({ agent, selected, onSelect, onToggle, showProject }:
|
|
|
165
165
|
);
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
function StatusBadge({ status, isActive,
|
|
169
|
-
if (status === "running" && isActive &&
|
|
168
|
+
function StatusBadge({ status, isActive, activityLabel }: { status: Agent["status"]; isActive?: boolean; activityLabel?: string }) {
|
|
169
|
+
if (status === "running" && isActive && activityLabel) {
|
|
170
170
|
return (
|
|
171
171
|
<span className="px-2 py-1 rounded text-xs font-medium bg-green-500/20 text-green-400 animate-pulse">
|
|
172
|
-
{
|
|
172
|
+
{activityLabel}
|
|
173
173
|
</span>
|
|
174
174
|
);
|
|
175
175
|
}
|
|
@@ -6,8 +6,8 @@ import { Select } from "../common/Select";
|
|
|
6
6
|
import { useConfirm } from "../common/Modal";
|
|
7
7
|
import { useTelemetry } from "../../context";
|
|
8
8
|
import { useAuth } from "../../context";
|
|
9
|
-
import type { Agent, Provider, AgentFeatures, McpServer, SkillSummary, AgentMode, MultiAgentConfig, Task } from "../../types";
|
|
10
|
-
import { getMultiAgentConfig } from "../../types";
|
|
9
|
+
import type { Agent, Provider, AgentFeatures, McpServer, SkillSummary, AgentMode, MultiAgentConfig, OperatorConfig, Task } from "../../types";
|
|
10
|
+
import { getMultiAgentConfig, getOperatorConfig } from "../../types";
|
|
11
11
|
|
|
12
12
|
type Tab = "chat" | "threads" | "tasks" | "memory" | "files" | "settings";
|
|
13
13
|
|
|
@@ -1123,6 +1123,7 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
|
|
|
1123
1123
|
const [availableMcpServers, setAvailableMcpServers] = useState<McpServer[]>([]);
|
|
1124
1124
|
const [availableSkills, setAvailableSkills] = useState<AvailableSkill[]>([]);
|
|
1125
1125
|
const [apiKey, setApiKey] = useState<string | null>(null);
|
|
1126
|
+
const [apiKeyFull, setApiKeyFull] = useState<string | null>(null);
|
|
1126
1127
|
const [showApiKey, setShowApiKey] = useState(false);
|
|
1127
1128
|
const [subscriptions, setSubscriptions] = useState<{ id: string; trigger_slug: string; enabled: boolean }[]>([]);
|
|
1128
1129
|
|
|
@@ -1148,22 +1149,22 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
|
|
|
1148
1149
|
fetchMcpServers();
|
|
1149
1150
|
}, [authFetch]);
|
|
1150
1151
|
|
|
1151
|
-
// Fetch API key
|
|
1152
|
+
// Fetch API key
|
|
1152
1153
|
useEffect(() => {
|
|
1153
|
-
if (!isDev) return;
|
|
1154
1154
|
const fetchApiKey = async () => {
|
|
1155
1155
|
try {
|
|
1156
1156
|
const res = await authFetch(`/api/agents/${agent.id}/api-key`);
|
|
1157
1157
|
if (res.ok) {
|
|
1158
1158
|
const data = await res.json();
|
|
1159
1159
|
setApiKey(data.apiKey);
|
|
1160
|
+
setApiKeyFull(data.fullKey || null);
|
|
1160
1161
|
}
|
|
1161
1162
|
} catch (e) {
|
|
1162
1163
|
// Ignore - not critical
|
|
1163
1164
|
}
|
|
1164
1165
|
};
|
|
1165
1166
|
fetchApiKey();
|
|
1166
|
-
}, [agent.id,
|
|
1167
|
+
}, [agent.id, authFetch]);
|
|
1167
1168
|
|
|
1168
1169
|
// Fetch available skills
|
|
1169
1170
|
useEffect(() => {
|
|
@@ -1217,19 +1218,13 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
|
|
|
1217
1218
|
const toggleFeature = (key: keyof AgentFeatures) => {
|
|
1218
1219
|
if (key === "agents") {
|
|
1219
1220
|
// Special handling for agents feature - convert to MultiAgentConfig
|
|
1220
|
-
const current = prev => {
|
|
1221
|
-
const agentConfig = getMultiAgentConfig(prev.features, agent.projectId);
|
|
1222
|
-
return agentConfig.enabled;
|
|
1223
|
-
};
|
|
1224
1221
|
setForm(prev => {
|
|
1225
1222
|
const isEnabled = typeof prev.features.agents === "boolean"
|
|
1226
1223
|
? prev.features.agents
|
|
1227
1224
|
: (prev.features.agents as MultiAgentConfig)?.enabled ?? false;
|
|
1228
1225
|
if (isEnabled) {
|
|
1229
|
-
// Turning off - set to false
|
|
1230
1226
|
return { ...prev, features: { ...prev.features, agents: false } };
|
|
1231
1227
|
} else {
|
|
1232
|
-
// Turning on - set to config with defaults
|
|
1233
1228
|
return {
|
|
1234
1229
|
...prev,
|
|
1235
1230
|
features: {
|
|
@@ -1239,6 +1234,22 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
|
|
|
1239
1234
|
};
|
|
1240
1235
|
}
|
|
1241
1236
|
});
|
|
1237
|
+
} else if (key === "operator") {
|
|
1238
|
+
// Special handling for operator feature - convert to OperatorConfig
|
|
1239
|
+
setForm(prev => {
|
|
1240
|
+
const opConfig = getOperatorConfig(prev.features);
|
|
1241
|
+
if (opConfig.enabled) {
|
|
1242
|
+
return { ...prev, features: { ...prev.features, operator: false } };
|
|
1243
|
+
} else {
|
|
1244
|
+
return {
|
|
1245
|
+
...prev,
|
|
1246
|
+
features: {
|
|
1247
|
+
...prev.features,
|
|
1248
|
+
operator: { enabled: true },
|
|
1249
|
+
},
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
});
|
|
1242
1253
|
} else {
|
|
1243
1254
|
setForm(prev => ({
|
|
1244
1255
|
...prev,
|
|
@@ -1274,6 +1285,33 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
|
|
|
1274
1285
|
return config.mode || "worker";
|
|
1275
1286
|
};
|
|
1276
1287
|
|
|
1288
|
+
// Helper to check if operator feature is enabled
|
|
1289
|
+
const isOperatorEnabled = () => {
|
|
1290
|
+
return getOperatorConfig(form.features).enabled;
|
|
1291
|
+
};
|
|
1292
|
+
|
|
1293
|
+
// Get current operator config
|
|
1294
|
+
const getOperatorCfg = (): OperatorConfig => {
|
|
1295
|
+
return getOperatorConfig(form.features);
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1298
|
+
// Get browser providers from the providers list
|
|
1299
|
+
const browserProviders = providers.filter(p => p.type === "browser" && p.hasKey);
|
|
1300
|
+
|
|
1301
|
+
// Set operator browser provider
|
|
1302
|
+
const setOperatorBrowserProvider = (browserProvider: string) => {
|
|
1303
|
+
setForm(prev => {
|
|
1304
|
+
const current = getOperatorConfig(prev.features);
|
|
1305
|
+
return {
|
|
1306
|
+
...prev,
|
|
1307
|
+
features: {
|
|
1308
|
+
...prev.features,
|
|
1309
|
+
operator: { ...current, enabled: true, browser_provider: browserProvider },
|
|
1310
|
+
},
|
|
1311
|
+
};
|
|
1312
|
+
});
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1277
1315
|
const toggleMcpServer = (serverId: string) => {
|
|
1278
1316
|
setForm(prev => ({
|
|
1279
1317
|
...prev,
|
|
@@ -1353,8 +1391,10 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
|
|
|
1353
1391
|
<FormField label="Features">
|
|
1354
1392
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
|
|
1355
1393
|
{FEATURE_CONFIG.map(({ key, label, description, icon: Icon }) => {
|
|
1356
|
-
// For agents
|
|
1357
|
-
const isEnabled = key === "agents" ? isAgentsEnabled()
|
|
1394
|
+
// For agents/operator features, check the enabled property of the config
|
|
1395
|
+
const isEnabled = key === "agents" ? isAgentsEnabled()
|
|
1396
|
+
: key === "operator" ? isOperatorEnabled()
|
|
1397
|
+
: !!form.features[key];
|
|
1358
1398
|
return (
|
|
1359
1399
|
<button
|
|
1360
1400
|
key={key}
|
|
@@ -1420,6 +1460,29 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
|
|
|
1420
1460
|
</FormField>
|
|
1421
1461
|
)}
|
|
1422
1462
|
|
|
1463
|
+
{/* Operator Browser Provider - shown when operator is enabled */}
|
|
1464
|
+
{isOperatorEnabled() && (
|
|
1465
|
+
<FormField label="Browser Provider">
|
|
1466
|
+
{browserProviders.length > 0 ? (
|
|
1467
|
+
<Select
|
|
1468
|
+
value={getOperatorCfg().browser_provider || ""}
|
|
1469
|
+
options={[
|
|
1470
|
+
{ value: "", label: "Auto (first available)" },
|
|
1471
|
+
...browserProviders.map(p => ({
|
|
1472
|
+
value: p.id,
|
|
1473
|
+
label: p.name,
|
|
1474
|
+
})),
|
|
1475
|
+
]}
|
|
1476
|
+
onChange={(value) => setOperatorBrowserProvider(value)}
|
|
1477
|
+
/>
|
|
1478
|
+
) : (
|
|
1479
|
+
<p className="text-sm text-[#666] p-3 border border-[#222] rounded bg-[#0a0a0a]">
|
|
1480
|
+
No browser providers configured. Go to Settings → Providers to add one.
|
|
1481
|
+
</p>
|
|
1482
|
+
)}
|
|
1483
|
+
</FormField>
|
|
1484
|
+
)}
|
|
1485
|
+
|
|
1423
1486
|
{/* Agent Built-in Tools - Anthropic only */}
|
|
1424
1487
|
{form.provider === "anthropic" && (
|
|
1425
1488
|
<FormField label="Agent Built-in Tools">
|
|
@@ -1628,7 +1691,7 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
|
|
|
1628
1691
|
</div>
|
|
1629
1692
|
|
|
1630
1693
|
{/* Developer Info (dev mode only) */}
|
|
1631
|
-
{
|
|
1694
|
+
{apiKey && (
|
|
1632
1695
|
<div className="mt-8 pt-6 border-t border-[#222]">
|
|
1633
1696
|
<p className="text-sm text-[#666] mb-3">Developer Info</p>
|
|
1634
1697
|
<div className="space-y-2">
|
|
@@ -1650,17 +1713,15 @@ function SettingsTab({ agent, providers, onUpdateAgent, onDeleteAgent }: {
|
|
|
1650
1713
|
{showApiKey ? "Hide" : "Show"}
|
|
1651
1714
|
</button>
|
|
1652
1715
|
</div>
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
</code>
|
|
1657
|
-
)}
|
|
1716
|
+
<code className="text-xs bg-[#1a1a1a] px-2 py-1 rounded text-[#888] break-all">
|
|
1717
|
+
{showApiKey ? (apiKeyFull || apiKey) : apiKey}
|
|
1718
|
+
</code>
|
|
1658
1719
|
</div>
|
|
1659
1720
|
{agent.status === "running" && agent.port && (
|
|
1660
1721
|
<div className="flex flex-col gap-1 mt-2">
|
|
1661
1722
|
<span className="text-xs text-[#666]">Test with curl</span>
|
|
1662
1723
|
<code className="text-xs bg-[#1a1a1a] px-2 py-1.5 rounded text-[#666] break-all">
|
|
1663
|
-
curl -H "X-API-Key: {showApiKey ? apiKey : "***"}" http://localhost:{agent.port}/config
|
|
1724
|
+
curl -H "X-API-Key: {showApiKey ? (apiKeyFull || apiKey) : "***"}" http://localhost:{agent.port}/config
|
|
1664
1725
|
</code>
|
|
1665
1726
|
</div>
|
|
1666
1727
|
)}
|
|
@@ -1366,6 +1366,7 @@ function AgentDojoContent({
|
|
|
1366
1366
|
const serversUrl = projectId && projectId !== "unassigned"
|
|
1367
1367
|
? `/api/mcp/servers?project=${encodeURIComponent(projectId)}`
|
|
1368
1368
|
: "/api/mcp/servers";
|
|
1369
|
+
console.log(`[AgentDojo:fetchConfigs] projectId=${projectId} serversUrl=${serversUrl}`);
|
|
1369
1370
|
const [configsRes, serversRes] = await Promise.all([
|
|
1370
1371
|
authFetch(`/api/integrations/agentdojo/configs${projectParam}`),
|
|
1371
1372
|
authFetch(serversUrl),
|
|
@@ -1373,18 +1374,24 @@ function AgentDojoContent({
|
|
|
1373
1374
|
const configsData = await configsRes.json();
|
|
1374
1375
|
const serversData = await serversRes.json();
|
|
1375
1376
|
|
|
1377
|
+
console.log(`[AgentDojo:fetchConfigs] configs=${(configsData.configs || []).length} servers=${(serversData.servers || []).length}`);
|
|
1376
1378
|
setConfigs(configsData.configs || []);
|
|
1377
1379
|
|
|
1378
1380
|
// Track which configs are already added as local servers
|
|
1381
|
+
const agentdojoServers = (serversData.servers || []).filter((s: any) => s.source === "agentdojo");
|
|
1382
|
+
console.log(`[AgentDojo:fetchConfigs] agentdojo servers found: ${agentdojoServers.length}`);
|
|
1383
|
+
for (const s of agentdojoServers) {
|
|
1384
|
+
const match = s.url?.match(/\/mcp\/([^/?]+)/);
|
|
1385
|
+
console.log(`[AgentDojo:fetchConfigs] server: id=${s.id} name=${s.name} project_id=${s.project_id} url=${s.url?.substring(0, 80)} extracted=${match ? match[1] : s.name}`);
|
|
1386
|
+
}
|
|
1379
1387
|
const agentdojoServerIds = new Set(
|
|
1380
|
-
(
|
|
1381
|
-
.filter((s: any) => s.source === "agentdojo")
|
|
1382
|
-
.map((s: any) => {
|
|
1388
|
+
agentdojoServers.map((s: any) => {
|
|
1383
1389
|
// Extract config ID from URL or match by name
|
|
1384
1390
|
const match = s.url?.match(/\/mcp\/([^/?]+)/);
|
|
1385
1391
|
return match ? match[1] : s.name;
|
|
1386
1392
|
})
|
|
1387
1393
|
);
|
|
1394
|
+
console.log(`[AgentDojo:fetchConfigs] addedServers set:`, [...agentdojoServerIds]);
|
|
1388
1395
|
setAddedServers(agentdojoServerIds);
|
|
1389
1396
|
} catch (e) {
|
|
1390
1397
|
console.error("Failed to fetch AgentDojo configs:", e);
|
|
@@ -1396,15 +1403,19 @@ function AgentDojoContent({
|
|
|
1396
1403
|
setAddingConfig(configId);
|
|
1397
1404
|
try {
|
|
1398
1405
|
const projectParam = projectId && projectId !== "unassigned" ? `?project_id=${projectId}` : "";
|
|
1406
|
+
console.log(`[AgentDojo:addConfig] configId=${configId} projectParam=${projectParam}`);
|
|
1399
1407
|
const res = await authFetch(`/api/integrations/agentdojo/configs/${configId}/add${projectParam}`, {
|
|
1400
1408
|
method: "POST",
|
|
1401
1409
|
});
|
|
1410
|
+
const data = await res.json();
|
|
1411
|
+
console.log(`[AgentDojo:addConfig] response status=${res.status} ok=${res.ok} message=${data.message} server.id=${data.server?.id} server.project_id=${data.server?.project_id}`);
|
|
1402
1412
|
if (res.ok) {
|
|
1403
1413
|
const config = configs.find(c => c.id === configId);
|
|
1404
|
-
|
|
1414
|
+
const addKey = config?.slug || configId;
|
|
1415
|
+
console.log(`[AgentDojo:addConfig] marking as added: key=${addKey} config.slug=${config?.slug} config.id=${config?.id} config.name=${config?.name}`);
|
|
1416
|
+
setAddedServers(prev => new Set([...prev, addKey]));
|
|
1405
1417
|
onServerAdded?.();
|
|
1406
1418
|
} else {
|
|
1407
|
-
const data = await res.json();
|
|
1408
1419
|
await alert(data.error || "Failed to add config", { title: "Error", variant: "error" });
|
|
1409
1420
|
}
|
|
1410
1421
|
} catch (e) {
|