apteva 0.4.3 → 0.4.5
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.y11xqt9m.js +227 -0
- package/dist/index.html +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/db.ts +93 -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 +142 -0
- package/src/routes/api/users.ts +148 -0
- package/src/routes/api.ts +32 -3474
- package/src/server.ts +1 -1
- package/src/web/components/api/ApiDocsPage.tsx +259 -0
- 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
package/src/server.ts
CHANGED
|
@@ -421,7 +421,7 @@ if (hasRestarts) {
|
|
|
421
421
|
// Restart in background to not block startup
|
|
422
422
|
(async () => {
|
|
423
423
|
// Import startAgentProcess dynamically to avoid circular dependency
|
|
424
|
-
const { startAgentProcess } = await import("./routes/api");
|
|
424
|
+
const { startAgentProcess } = await import("./routes/api/agent-utils");
|
|
425
425
|
|
|
426
426
|
// Restart MCP servers first (agents may depend on them)
|
|
427
427
|
if (mcpServersToRestart.length > 0) {
|
|
@@ -51,6 +51,256 @@ const METHOD_COLORS: Record<string, string> = {
|
|
|
51
51
|
patch: "#50e3c2",
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
// Try It Out component
|
|
55
|
+
function TryItOut({
|
|
56
|
+
method,
|
|
57
|
+
path,
|
|
58
|
+
parameters,
|
|
59
|
+
requestBody,
|
|
60
|
+
authFetch,
|
|
61
|
+
}: {
|
|
62
|
+
method: string;
|
|
63
|
+
path: string;
|
|
64
|
+
parameters?: Array<{
|
|
65
|
+
name: string;
|
|
66
|
+
in: string;
|
|
67
|
+
required?: boolean;
|
|
68
|
+
schema?: { type: string };
|
|
69
|
+
}>;
|
|
70
|
+
requestBody?: any;
|
|
71
|
+
authFetch: (url: string, options?: RequestInit) => Promise<Response>;
|
|
72
|
+
}) {
|
|
73
|
+
const [paramValues, setParamValues] = useState<Record<string, string>>({});
|
|
74
|
+
const [bodyValue, setBodyValue] = useState("");
|
|
75
|
+
const [response, setResponse] = useState<{ status: number; data: any } | null>(null);
|
|
76
|
+
const [loading, setLoading] = useState(false);
|
|
77
|
+
const [error, setError] = useState<string | null>(null);
|
|
78
|
+
|
|
79
|
+
// Initialize body with example if available
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (requestBody?.content?.["application/json"]?.schema) {
|
|
82
|
+
const schema = requestBody.content["application/json"].schema;
|
|
83
|
+
if (schema.example) {
|
|
84
|
+
setBodyValue(JSON.stringify(schema.example, null, 2));
|
|
85
|
+
} else if (schema.properties) {
|
|
86
|
+
// Generate example from properties
|
|
87
|
+
const example: Record<string, any> = {};
|
|
88
|
+
for (const [key, prop] of Object.entries(schema.properties) as [string, any][]) {
|
|
89
|
+
if (prop.example !== undefined) {
|
|
90
|
+
example[key] = prop.example;
|
|
91
|
+
} else if (prop.type === "string") {
|
|
92
|
+
example[key] = "";
|
|
93
|
+
} else if (prop.type === "number" || prop.type === "integer") {
|
|
94
|
+
example[key] = 0;
|
|
95
|
+
} else if (prop.type === "boolean") {
|
|
96
|
+
example[key] = false;
|
|
97
|
+
} else if (prop.type === "array") {
|
|
98
|
+
example[key] = [];
|
|
99
|
+
} else if (prop.type === "object") {
|
|
100
|
+
example[key] = {};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
setBodyValue(JSON.stringify(example, null, 2));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}, [requestBody]);
|
|
107
|
+
|
|
108
|
+
const execute = async () => {
|
|
109
|
+
setLoading(true);
|
|
110
|
+
setError(null);
|
|
111
|
+
setResponse(null);
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
// Build URL with path parameters
|
|
115
|
+
let url = path;
|
|
116
|
+
const queryParams: string[] = [];
|
|
117
|
+
|
|
118
|
+
for (const param of parameters || []) {
|
|
119
|
+
const value = paramValues[param.name] || "";
|
|
120
|
+
if (param.in === "path") {
|
|
121
|
+
url = url.replace(`{${param.name}}`, encodeURIComponent(value));
|
|
122
|
+
} else if (param.in === "query" && value) {
|
|
123
|
+
queryParams.push(`${param.name}=${encodeURIComponent(value)}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (queryParams.length > 0) {
|
|
128
|
+
url += `?${queryParams.join("&")}`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const options: RequestInit = {
|
|
132
|
+
method: method.toUpperCase(),
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
if (bodyValue && ["post", "put", "patch"].includes(method)) {
|
|
136
|
+
options.headers = { "Content-Type": "application/json" };
|
|
137
|
+
options.body = bodyValue;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const res = await authFetch(`/api${url}`, options);
|
|
141
|
+
let data;
|
|
142
|
+
const contentType = res.headers.get("content-type");
|
|
143
|
+
if (contentType?.includes("application/json")) {
|
|
144
|
+
data = await res.json();
|
|
145
|
+
} else {
|
|
146
|
+
data = await res.text();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
setResponse({ status: res.status, data });
|
|
150
|
+
} catch (err: any) {
|
|
151
|
+
setError(err.message || "Request failed");
|
|
152
|
+
} finally {
|
|
153
|
+
setLoading(false);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const pathParams = parameters?.filter((p) => p.in === "path") || [];
|
|
158
|
+
const queryParams = parameters?.filter((p) => p.in === "query") || [];
|
|
159
|
+
const hasBody = ["post", "put", "patch"].includes(method) && requestBody;
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<div style={{ marginTop: 16, padding: 16, background: "#0a0a14", borderRadius: 6, border: "1px solid #222" }}>
|
|
163
|
+
<h4 style={{ fontSize: 13, color: "#f97316", marginBottom: 12, fontWeight: 600 }}>Try it out</h4>
|
|
164
|
+
|
|
165
|
+
{/* Path Parameters */}
|
|
166
|
+
{pathParams.length > 0 && (
|
|
167
|
+
<div style={{ marginBottom: 12 }}>
|
|
168
|
+
<div style={{ fontSize: 11, color: "#666", marginBottom: 6 }}>Path Parameters</div>
|
|
169
|
+
{pathParams.map((param) => (
|
|
170
|
+
<div key={param.name} style={{ marginBottom: 8 }}>
|
|
171
|
+
<label style={{ fontSize: 12, color: "#888", display: "block", marginBottom: 4 }}>
|
|
172
|
+
{param.name} {param.required && <span style={{ color: "#f66" }}>*</span>}
|
|
173
|
+
</label>
|
|
174
|
+
<input
|
|
175
|
+
type="text"
|
|
176
|
+
value={paramValues[param.name] || ""}
|
|
177
|
+
onChange={(e) => setParamValues({ ...paramValues, [param.name]: e.target.value })}
|
|
178
|
+
placeholder={param.schema?.type || "string"}
|
|
179
|
+
style={{
|
|
180
|
+
width: "100%",
|
|
181
|
+
padding: "8px 12px",
|
|
182
|
+
background: "#111",
|
|
183
|
+
border: "1px solid #333",
|
|
184
|
+
borderRadius: 4,
|
|
185
|
+
color: "#fff",
|
|
186
|
+
fontSize: 13,
|
|
187
|
+
fontFamily: "monospace",
|
|
188
|
+
}}
|
|
189
|
+
/>
|
|
190
|
+
</div>
|
|
191
|
+
))}
|
|
192
|
+
</div>
|
|
193
|
+
)}
|
|
194
|
+
|
|
195
|
+
{/* Query Parameters */}
|
|
196
|
+
{queryParams.length > 0 && (
|
|
197
|
+
<div style={{ marginBottom: 12 }}>
|
|
198
|
+
<div style={{ fontSize: 11, color: "#666", marginBottom: 6 }}>Query Parameters</div>
|
|
199
|
+
{queryParams.map((param) => (
|
|
200
|
+
<div key={param.name} style={{ marginBottom: 8 }}>
|
|
201
|
+
<label style={{ fontSize: 12, color: "#888", display: "block", marginBottom: 4 }}>
|
|
202
|
+
{param.name} {param.required && <span style={{ color: "#f66" }}>*</span>}
|
|
203
|
+
</label>
|
|
204
|
+
<input
|
|
205
|
+
type="text"
|
|
206
|
+
value={paramValues[param.name] || ""}
|
|
207
|
+
onChange={(e) => setParamValues({ ...paramValues, [param.name]: e.target.value })}
|
|
208
|
+
placeholder={param.schema?.type || "string"}
|
|
209
|
+
style={{
|
|
210
|
+
width: "100%",
|
|
211
|
+
padding: "8px 12px",
|
|
212
|
+
background: "#111",
|
|
213
|
+
border: "1px solid #333",
|
|
214
|
+
borderRadius: 4,
|
|
215
|
+
color: "#fff",
|
|
216
|
+
fontSize: 13,
|
|
217
|
+
fontFamily: "monospace",
|
|
218
|
+
}}
|
|
219
|
+
/>
|
|
220
|
+
</div>
|
|
221
|
+
))}
|
|
222
|
+
</div>
|
|
223
|
+
)}
|
|
224
|
+
|
|
225
|
+
{/* Request Body */}
|
|
226
|
+
{hasBody && (
|
|
227
|
+
<div style={{ marginBottom: 12 }}>
|
|
228
|
+
<div style={{ fontSize: 11, color: "#666", marginBottom: 6 }}>Request Body (JSON)</div>
|
|
229
|
+
<textarea
|
|
230
|
+
value={bodyValue}
|
|
231
|
+
onChange={(e) => setBodyValue(e.target.value)}
|
|
232
|
+
rows={6}
|
|
233
|
+
style={{
|
|
234
|
+
width: "100%",
|
|
235
|
+
padding: "8px 12px",
|
|
236
|
+
background: "#111",
|
|
237
|
+
border: "1px solid #333",
|
|
238
|
+
borderRadius: 4,
|
|
239
|
+
color: "#fff",
|
|
240
|
+
fontSize: 12,
|
|
241
|
+
fontFamily: "monospace",
|
|
242
|
+
resize: "vertical",
|
|
243
|
+
}}
|
|
244
|
+
/>
|
|
245
|
+
</div>
|
|
246
|
+
)}
|
|
247
|
+
|
|
248
|
+
{/* Execute Button */}
|
|
249
|
+
<button
|
|
250
|
+
onClick={execute}
|
|
251
|
+
disabled={loading}
|
|
252
|
+
style={{
|
|
253
|
+
padding: "10px 20px",
|
|
254
|
+
background: loading ? "#333" : "#f97316",
|
|
255
|
+
color: loading ? "#666" : "#000",
|
|
256
|
+
border: "none",
|
|
257
|
+
borderRadius: 4,
|
|
258
|
+
cursor: loading ? "not-allowed" : "pointer",
|
|
259
|
+
fontSize: 13,
|
|
260
|
+
fontWeight: 600,
|
|
261
|
+
}}
|
|
262
|
+
>
|
|
263
|
+
{loading ? "Executing..." : "Execute"}
|
|
264
|
+
</button>
|
|
265
|
+
|
|
266
|
+
{/* Error */}
|
|
267
|
+
{error && (
|
|
268
|
+
<div style={{ marginTop: 12, padding: 12, background: "#2a1515", borderRadius: 4, color: "#f66", fontSize: 12 }}>
|
|
269
|
+
{error}
|
|
270
|
+
</div>
|
|
271
|
+
)}
|
|
272
|
+
|
|
273
|
+
{/* Response */}
|
|
274
|
+
{response && (
|
|
275
|
+
<div style={{ marginTop: 12 }}>
|
|
276
|
+
<div style={{ fontSize: 11, color: "#666", marginBottom: 6 }}>
|
|
277
|
+
Response{" "}
|
|
278
|
+
<span style={{ color: response.status >= 200 && response.status < 300 ? "#49cc90" : "#f66" }}>
|
|
279
|
+
{response.status}
|
|
280
|
+
</span>
|
|
281
|
+
</div>
|
|
282
|
+
<pre
|
|
283
|
+
style={{
|
|
284
|
+
padding: 12,
|
|
285
|
+
background: "#111",
|
|
286
|
+
borderRadius: 4,
|
|
287
|
+
color: "#888",
|
|
288
|
+
fontSize: 11,
|
|
289
|
+
fontFamily: "monospace",
|
|
290
|
+
overflow: "auto",
|
|
291
|
+
maxHeight: 300,
|
|
292
|
+
whiteSpace: "pre-wrap",
|
|
293
|
+
wordBreak: "break-word",
|
|
294
|
+
}}
|
|
295
|
+
>
|
|
296
|
+
{typeof response.data === "string" ? response.data : JSON.stringify(response.data, null, 2)}
|
|
297
|
+
</pre>
|
|
298
|
+
</div>
|
|
299
|
+
)}
|
|
300
|
+
</div>
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
54
304
|
export function ApiDocsPage() {
|
|
55
305
|
const { authFetch } = useAuth();
|
|
56
306
|
const [spec, setSpec] = useState<OpenApiSpec | null>(null);
|
|
@@ -516,6 +766,15 @@ export function ApiDocsPage() {
|
|
|
516
766
|
</div>
|
|
517
767
|
</div>
|
|
518
768
|
)}
|
|
769
|
+
|
|
770
|
+
{/* Try It Out */}
|
|
771
|
+
<TryItOut
|
|
772
|
+
method={method}
|
|
773
|
+
path={path}
|
|
774
|
+
parameters={details.parameters}
|
|
775
|
+
requestBody={details.requestBody}
|
|
776
|
+
authFetch={authFetch}
|
|
777
|
+
/>
|
|
519
778
|
</div>
|
|
520
779
|
)}
|
|
521
780
|
</div>
|
|
@@ -44,9 +44,11 @@ function hasMultipleAuthMethods(app: IntegrationApp): boolean {
|
|
|
44
44
|
// Main component
|
|
45
45
|
export function IntegrationsPanel({
|
|
46
46
|
providerId = "composio",
|
|
47
|
+
projectId,
|
|
47
48
|
onConnectionComplete,
|
|
48
49
|
}: {
|
|
49
50
|
providerId?: string;
|
|
51
|
+
projectId?: string | null;
|
|
50
52
|
onConnectionComplete?: () => void;
|
|
51
53
|
}) {
|
|
52
54
|
const { authFetch } = useAuth();
|
|
@@ -80,10 +82,11 @@ export function IntegrationsPanel({
|
|
|
80
82
|
const fetchData = useCallback(async () => {
|
|
81
83
|
setLoading(true);
|
|
82
84
|
setError(null);
|
|
85
|
+
const projectParam = projectId && projectId !== "unassigned" ? `?project_id=${projectId}` : "";
|
|
83
86
|
try {
|
|
84
87
|
const [appsRes, connectedRes] = await Promise.all([
|
|
85
|
-
authFetch(`/api/integrations/${providerId}/apps`),
|
|
86
|
-
authFetch(`/api/integrations/${providerId}/connected`),
|
|
88
|
+
authFetch(`/api/integrations/${providerId}/apps${projectParam}`),
|
|
89
|
+
authFetch(`/api/integrations/${providerId}/connected${projectParam}`),
|
|
87
90
|
]);
|
|
88
91
|
|
|
89
92
|
const appsData = await appsRes.json();
|
|
@@ -96,7 +99,7 @@ export function IntegrationsPanel({
|
|
|
96
99
|
setError("Failed to load integrations");
|
|
97
100
|
}
|
|
98
101
|
setLoading(false);
|
|
99
|
-
}, [authFetch, providerId]);
|
|
102
|
+
}, [authFetch, providerId, projectId]);
|
|
100
103
|
|
|
101
104
|
useEffect(() => {
|
|
102
105
|
fetchData();
|
|
@@ -118,11 +121,12 @@ export function IntegrationsPanel({
|
|
|
118
121
|
// Poll for pending connection status
|
|
119
122
|
useEffect(() => {
|
|
120
123
|
if (!pendingConnection?.connectionId) return;
|
|
124
|
+
const projectParam = projectId && projectId !== "unassigned" ? `?project_id=${projectId}` : "";
|
|
121
125
|
|
|
122
126
|
const pollInterval = setInterval(async () => {
|
|
123
127
|
try {
|
|
124
128
|
const res = await authFetch(
|
|
125
|
-
`/api/integrations/${providerId}/connection/${pendingConnection.connectionId}`
|
|
129
|
+
`/api/integrations/${providerId}/connection/${pendingConnection.connectionId}${projectParam}`
|
|
126
130
|
);
|
|
127
131
|
const data = await res.json();
|
|
128
132
|
|
|
@@ -142,7 +146,7 @@ export function IntegrationsPanel({
|
|
|
142
146
|
}, 2000);
|
|
143
147
|
|
|
144
148
|
return () => clearInterval(pollInterval);
|
|
145
|
-
}, [pendingConnection, authFetch, providerId, fetchData, onConnectionComplete]);
|
|
149
|
+
}, [pendingConnection, authFetch, providerId, projectId, fetchData, onConnectionComplete]);
|
|
146
150
|
|
|
147
151
|
// Initiate connection
|
|
148
152
|
const connectApp = async (app: IntegrationApp, apiKey?: string, forceOAuth?: boolean) => {
|
|
@@ -172,7 +176,8 @@ export function IntegrationsPanel({
|
|
|
172
176
|
};
|
|
173
177
|
}
|
|
174
178
|
|
|
175
|
-
const
|
|
179
|
+
const projectParam = projectId && projectId !== "unassigned" ? `?project_id=${projectId}` : "";
|
|
180
|
+
const res = await authFetch(`/api/integrations/${providerId}/connect${projectParam}`, {
|
|
176
181
|
method: "POST",
|
|
177
182
|
headers: { "Content-Type": "application/json" },
|
|
178
183
|
body: JSON.stringify(body),
|
|
@@ -231,9 +236,10 @@ export function IntegrationsPanel({
|
|
|
231
236
|
|
|
232
237
|
// Disconnect (called after confirmation)
|
|
233
238
|
const disconnectApp = async (account: ConnectedAccount) => {
|
|
239
|
+
const projectParam = projectId && projectId !== "unassigned" ? `?project_id=${projectId}` : "";
|
|
234
240
|
try {
|
|
235
241
|
const res = await authFetch(
|
|
236
|
-
`/api/integrations/${providerId}/connection/${account.id}`,
|
|
242
|
+
`/api/integrations/${providerId}/connection/${account.id}${projectParam}`,
|
|
237
243
|
{ method: "DELETE" }
|
|
238
244
|
);
|
|
239
245
|
|
|
@@ -263,7 +269,8 @@ export function IntegrationsPanel({
|
|
|
263
269
|
setError(null);
|
|
264
270
|
|
|
265
271
|
try {
|
|
266
|
-
const
|
|
272
|
+
const projectParam = projectId && projectId !== "unassigned" ? `?project_id=${projectId}` : "";
|
|
273
|
+
const res = await authFetch(`/api/integrations/${providerId}/configs${projectParam}`, {
|
|
267
274
|
method: "POST",
|
|
268
275
|
headers: { "Content-Type": "application/json" },
|
|
269
276
|
body: JSON.stringify({
|