mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-21 04:57:58 -05:00
Compare commits
22 Commits
testing-cl
...
feat/agent
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee11623735 | ||
|
|
0bb160e930 | ||
|
|
81a09738dc | ||
|
|
6feedafd7d | ||
|
|
547da633c4 | ||
|
|
6d13dfc688 | ||
|
|
d0d498fa66 | ||
|
|
c843dee317 | ||
|
|
db969c1bf8 | ||
|
|
690fac91e4 | ||
|
|
5368fdc998 | ||
|
|
b9d293f181 | ||
|
|
acbcef77b2 | ||
|
|
e902848e04 | ||
|
|
cd917ec919 | ||
|
|
8ae37491e4 | ||
|
|
f45e5e0d59 | ||
|
|
1231236d87 | ||
|
|
4db0792ade | ||
|
|
81cb6fb1e6 | ||
|
|
c16598eed6 | ||
|
|
7706740308 |
@@ -75,6 +75,7 @@
|
|||||||
"moment": "2.30.1",
|
"moment": "2.30.1",
|
||||||
"next": "15.3.5",
|
"next": "15.3.5",
|
||||||
"next-themes": "0.4.6",
|
"next-themes": "0.4.6",
|
||||||
|
"nuqs": "2.4.3",
|
||||||
"party-js": "2.2.0",
|
"party-js": "2.2.0",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-day-picker": "9.8.0",
|
"react-day-picker": "9.8.0",
|
||||||
|
|||||||
33
autogpt_platform/frontend/pnpm-lock.yaml
generated
33
autogpt_platform/frontend/pnpm-lock.yaml
generated
@@ -155,6 +155,9 @@ importers:
|
|||||||
next-themes:
|
next-themes:
|
||||||
specifier: 0.4.6
|
specifier: 0.4.6
|
||||||
version: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
nuqs:
|
||||||
|
specifier: 2.4.3
|
||||||
|
version: 2.4.3(next@15.3.5(@babel/core@7.28.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||||
party-js:
|
party-js:
|
||||||
specifier: 2.2.0
|
specifier: 2.2.0
|
||||||
version: 2.2.0
|
version: 2.2.0
|
||||||
@@ -5329,6 +5332,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
||||||
engines: {node: '>=16 || 14 >=14.17'}
|
engines: {node: '>=16 || 14 >=14.17'}
|
||||||
|
|
||||||
|
mitt@3.0.1:
|
||||||
|
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
|
||||||
|
|
||||||
module-details-from-path@1.0.4:
|
module-details-from-path@1.0.4:
|
||||||
resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==}
|
resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==}
|
||||||
|
|
||||||
@@ -5459,6 +5465,24 @@ packages:
|
|||||||
nth-check@2.1.1:
|
nth-check@2.1.1:
|
||||||
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
||||||
|
|
||||||
|
nuqs@2.4.3:
|
||||||
|
resolution: {integrity: sha512-BgtlYpvRwLYiJuWzxt34q2bXu/AIS66sLU1QePIMr2LWkb+XH0vKXdbLSgn9t6p7QKzwI7f38rX3Wl9llTXQ8Q==}
|
||||||
|
peerDependencies:
|
||||||
|
'@remix-run/react': '>=2'
|
||||||
|
next: '>=14.2.0'
|
||||||
|
react: '>=18.2.0 || ^19.0.0-0'
|
||||||
|
react-router: ^6 || ^7
|
||||||
|
react-router-dom: ^6 || ^7
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@remix-run/react':
|
||||||
|
optional: true
|
||||||
|
next:
|
||||||
|
optional: true
|
||||||
|
react-router:
|
||||||
|
optional: true
|
||||||
|
react-router-dom:
|
||||||
|
optional: true
|
||||||
|
|
||||||
oas-kit-common@1.0.8:
|
oas-kit-common@1.0.8:
|
||||||
resolution: {integrity: sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==}
|
resolution: {integrity: sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==}
|
||||||
|
|
||||||
@@ -12998,6 +13022,8 @@ snapshots:
|
|||||||
|
|
||||||
minipass@7.1.2: {}
|
minipass@7.1.2: {}
|
||||||
|
|
||||||
|
mitt@3.0.1: {}
|
||||||
|
|
||||||
module-details-from-path@1.0.4: {}
|
module-details-from-path@1.0.4: {}
|
||||||
|
|
||||||
moment@2.30.1: {}
|
moment@2.30.1: {}
|
||||||
@@ -13160,6 +13186,13 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
boolbase: 1.0.0
|
boolbase: 1.0.0
|
||||||
|
|
||||||
|
nuqs@2.4.3(next@15.3.5(@babel/core@7.28.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
mitt: 3.0.1
|
||||||
|
react: 18.3.1
|
||||||
|
optionalDependencies:
|
||||||
|
next: 15.3.5(@babel/core@7.28.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.53.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
|
||||||
oas-kit-common@1.0.8:
|
oas-kit-common@1.0.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-safe-stringify: 2.1.1
|
fast-safe-stringify: 2.1.1
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useParams, useRouter } from "next/navigation";
|
import { useParams, useRouter } from "next/navigation";
|
||||||
|
import { useQueryState } from "nuqs";
|
||||||
import React, {
|
import React, {
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
@@ -45,6 +46,7 @@ import { useToast } from "@/components/molecules/Toast/use-toast";
|
|||||||
|
|
||||||
export default function AgentRunsPage(): React.ReactElement {
|
export default function AgentRunsPage(): React.ReactElement {
|
||||||
const { id: agentID }: { id: LibraryAgentID } = useParams();
|
const { id: agentID }: { id: LibraryAgentID } = useParams();
|
||||||
|
const [executionId, setExecutionId] = useQueryState("executionId");
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const api = useBackendAPI();
|
const api = useBackendAPI();
|
||||||
@@ -202,6 +204,13 @@ export default function AgentRunsPage(): React.ReactElement {
|
|||||||
selectPreset,
|
selectPreset,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (executionId) {
|
||||||
|
selectRun(executionId as GraphExecutionID);
|
||||||
|
setExecutionId(null);
|
||||||
|
}
|
||||||
|
}, [executionId, selectRun, setExecutionId]);
|
||||||
|
|
||||||
// Initial load
|
// Initial load
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refreshPageData();
|
refreshPageData();
|
||||||
@@ -468,7 +477,7 @@ export default function AgentRunsPage(): React.ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container justify-stretch p-0 lg:flex">
|
<div className="container justify-stretch p-0 pt-16 lg:flex">
|
||||||
{/* Sidebar w/ list of runs */}
|
{/* Sidebar w/ list of runs */}
|
||||||
{/* TODO: render this below header in sm and md layouts */}
|
{/* TODO: render this below header in sm and md layouts */}
|
||||||
<AgentRunsSelectorList
|
<AgentRunsSelectorList
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export async function login(
|
|||||||
return await Sentry.withServerActionInstrumentation("login", {}, async () => {
|
return await Sentry.withServerActionInstrumentation("login", {}, async () => {
|
||||||
const supabase = await getServerSupabase();
|
const supabase = await getServerSupabase();
|
||||||
const api = new BackendAPI();
|
const api = new BackendAPI();
|
||||||
|
const isVercelPreview = process.env.VERCEL_ENV === "preview";
|
||||||
|
|
||||||
if (!supabase) {
|
if (!supabase) {
|
||||||
redirect("/error");
|
redirect("/error");
|
||||||
@@ -30,7 +31,7 @@ export async function login(
|
|||||||
|
|
||||||
// Verify Turnstile token if provided
|
// Verify Turnstile token if provided
|
||||||
const success = await verifyTurnstileToken(turnstileToken, "login");
|
const success = await verifyTurnstileToken(turnstileToken, "login");
|
||||||
if (!success) {
|
if (!success && !isVercelPreview) {
|
||||||
return "CAPTCHA verification failed. Please try again.";
|
return "CAPTCHA verification failed. Please try again.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export default function LoginPage() {
|
|||||||
isLoading,
|
isLoading,
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
isCloudEnv,
|
isCloudEnv,
|
||||||
|
shouldNotRenderCaptcha,
|
||||||
isUserLoading,
|
isUserLoading,
|
||||||
isGoogleLoading,
|
isGoogleLoading,
|
||||||
showNotAllowedModal,
|
showNotAllowedModal,
|
||||||
@@ -85,16 +86,18 @@ export default function LoginPage() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Turnstile CAPTCHA Component */}
|
{/* Turnstile CAPTCHA Component */}
|
||||||
<Turnstile
|
{shouldNotRenderCaptcha ? null : (
|
||||||
key={captchaKey}
|
<Turnstile
|
||||||
siteKey={turnstile.siteKey}
|
key={captchaKey}
|
||||||
onVerify={turnstile.handleVerify}
|
siteKey={turnstile.siteKey}
|
||||||
onExpire={turnstile.handleExpire}
|
onVerify={turnstile.handleVerify}
|
||||||
onError={turnstile.handleError}
|
onExpire={turnstile.handleExpire}
|
||||||
setWidgetId={turnstile.setWidgetId}
|
onError={turnstile.handleError}
|
||||||
action="login"
|
setWidgetId={turnstile.setWidgetId}
|
||||||
shouldRender={turnstile.shouldRender}
|
action="login"
|
||||||
/>
|
shouldRender={turnstile.shouldRender}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ export function useLoginPage() {
|
|||||||
resetOnError: true,
|
resetOnError: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const shouldNotRenderCaptcha = isVercelPreview || turnstile.verified;
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof loginFormSchema>>({
|
const form = useForm<z.infer<typeof loginFormSchema>>({
|
||||||
resolver: zodResolver(loginFormSchema),
|
resolver: zodResolver(loginFormSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@@ -125,6 +127,7 @@ export function useLoginPage() {
|
|||||||
isLoading,
|
isLoading,
|
||||||
isCloudEnv,
|
isCloudEnv,
|
||||||
isUserLoading,
|
isUserLoading,
|
||||||
|
shouldNotRenderCaptcha,
|
||||||
isGoogleLoading,
|
isGoogleLoading,
|
||||||
showNotAllowedModal,
|
showNotAllowedModal,
|
||||||
isSupabaseAvailable: !!supabase,
|
isSupabaseAvailable: !!supabase,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export async function signup(
|
|||||||
{},
|
{},
|
||||||
async () => {
|
async () => {
|
||||||
const supabase = await getServerSupabase();
|
const supabase = await getServerSupabase();
|
||||||
|
const isVercelPreview = process.env.VERCEL_ENV === "preview";
|
||||||
|
|
||||||
if (!supabase) {
|
if (!supabase) {
|
||||||
redirect("/error");
|
redirect("/error");
|
||||||
@@ -25,7 +26,7 @@ export async function signup(
|
|||||||
|
|
||||||
// Verify Turnstile token if provided
|
// Verify Turnstile token if provided
|
||||||
const success = await verifyTurnstileToken(turnstileToken, "signup");
|
const success = await verifyTurnstileToken(turnstileToken, "signup");
|
||||||
if (!success) {
|
if (!success && !isVercelPreview) {
|
||||||
return "CAPTCHA verification failed. Please try again.";
|
return "CAPTCHA verification failed. Please try again.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export default function SignupPage() {
|
|||||||
isLoading,
|
isLoading,
|
||||||
isCloudEnv,
|
isCloudEnv,
|
||||||
isUserLoading,
|
isUserLoading,
|
||||||
|
shouldNotRenderCaptcha,
|
||||||
isGoogleLoading,
|
isGoogleLoading,
|
||||||
showNotAllowedModal,
|
showNotAllowedModal,
|
||||||
isSupabaseAvailable,
|
isSupabaseAvailable,
|
||||||
@@ -163,16 +164,18 @@ export default function SignupPage() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Turnstile CAPTCHA Component */}
|
{/* Turnstile CAPTCHA Component */}
|
||||||
<Turnstile
|
{shouldNotRenderCaptcha ? null : (
|
||||||
key={captchaKey}
|
<Turnstile
|
||||||
siteKey={turnstile.siteKey}
|
key={captchaKey}
|
||||||
onVerify={turnstile.handleVerify}
|
siteKey={turnstile.siteKey}
|
||||||
onExpire={turnstile.handleExpire}
|
onVerify={turnstile.handleVerify}
|
||||||
onError={turnstile.handleError}
|
onExpire={turnstile.handleExpire}
|
||||||
setWidgetId={turnstile.setWidgetId}
|
onError={turnstile.handleError}
|
||||||
action="signup"
|
setWidgetId={turnstile.setWidgetId}
|
||||||
shouldRender={turnstile.shouldRender}
|
action="signup"
|
||||||
/>
|
shouldRender={turnstile.shouldRender}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ export function useSignupPage() {
|
|||||||
resetOnError: true,
|
resetOnError: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const shouldNotRenderCaptcha = isVercelPreview || turnstile.verified;
|
||||||
|
|
||||||
const resetCaptcha = useCallback(() => {
|
const resetCaptcha = useCallback(() => {
|
||||||
setCaptchaKey((k) => k + 1);
|
setCaptchaKey((k) => k + 1);
|
||||||
turnstile.reset();
|
turnstile.reset();
|
||||||
@@ -132,6 +134,7 @@ export function useSignupPage() {
|
|||||||
isCloudEnv,
|
isCloudEnv,
|
||||||
isUserLoading,
|
isUserLoading,
|
||||||
isGoogleLoading,
|
isGoogleLoading,
|
||||||
|
shouldNotRenderCaptcha,
|
||||||
showNotAllowedModal,
|
showNotAllowedModal,
|
||||||
isSupabaseAvailable: !!supabase,
|
isSupabaseAvailable: !!supabase,
|
||||||
handleSubmit: form.handleSubmit(handleSignup),
|
handleSubmit: form.handleSubmit(handleSignup),
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ import type { Graph } from "../../models/graph";
|
|||||||
|
|
||||||
import type { GraphExecutionMeta } from "../../models/graphExecutionMeta";
|
import type { GraphExecutionMeta } from "../../models/graphExecutionMeta";
|
||||||
|
|
||||||
|
import type { GraphMeta } from "../../models/graphMeta";
|
||||||
|
|
||||||
import type { GraphModel } from "../../models/graphModel";
|
import type { GraphModel } from "../../models/graphModel";
|
||||||
|
|
||||||
import type { HTTPValidationError } from "../../models/hTTPValidationError";
|
import type { HTTPValidationError } from "../../models/hTTPValidationError";
|
||||||
@@ -47,8 +49,6 @@ import type { PostV1ExecuteGraphAgentParams } from "../../models/postV1ExecuteGr
|
|||||||
|
|
||||||
import type { PostV1StopGraphExecution200 } from "../../models/postV1StopGraphExecution200";
|
import type { PostV1StopGraphExecution200 } from "../../models/postV1StopGraphExecution200";
|
||||||
|
|
||||||
import type { PostV1StopGraphExecutionsParams } from "../../models/postV1StopGraphExecutionsParams";
|
|
||||||
|
|
||||||
import type { SetGraphActiveVersion } from "../../models/setGraphActiveVersion";
|
import type { SetGraphActiveVersion } from "../../models/setGraphActiveVersion";
|
||||||
|
|
||||||
import { customMutator } from "../../../mutators/custom-mutator";
|
import { customMutator } from "../../../mutators/custom-mutator";
|
||||||
@@ -59,7 +59,7 @@ type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
|||||||
* @summary List user graphs
|
* @summary List user graphs
|
||||||
*/
|
*/
|
||||||
export type getV1ListUserGraphsResponse200 = {
|
export type getV1ListUserGraphsResponse200 = {
|
||||||
data: GraphModel[];
|
data: GraphMeta[];
|
||||||
status: 200;
|
status: 200;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1610,130 +1610,6 @@ export const usePostV1StopGraphExecution = <
|
|||||||
|
|
||||||
return useMutation(mutationOptions, queryClient);
|
return useMutation(mutationOptions, queryClient);
|
||||||
};
|
};
|
||||||
/**
|
|
||||||
* @summary Stop graph executions
|
|
||||||
*/
|
|
||||||
export type postV1StopGraphExecutionsResponse200 = {
|
|
||||||
data: GraphExecutionMeta[];
|
|
||||||
status: 200;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type postV1StopGraphExecutionsResponse422 = {
|
|
||||||
data: HTTPValidationError;
|
|
||||||
status: 422;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type postV1StopGraphExecutionsResponseComposite =
|
|
||||||
| postV1StopGraphExecutionsResponse200
|
|
||||||
| postV1StopGraphExecutionsResponse422;
|
|
||||||
|
|
||||||
export type postV1StopGraphExecutionsResponse =
|
|
||||||
postV1StopGraphExecutionsResponseComposite & {
|
|
||||||
headers: Headers;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPostV1StopGraphExecutionsUrl = (
|
|
||||||
params: PostV1StopGraphExecutionsParams,
|
|
||||||
) => {
|
|
||||||
const normalizedParams = new URLSearchParams();
|
|
||||||
|
|
||||||
Object.entries(params || {}).forEach(([key, value]) => {
|
|
||||||
if (value !== undefined) {
|
|
||||||
normalizedParams.append(key, value === null ? "null" : value.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const stringifiedParams = normalizedParams.toString();
|
|
||||||
|
|
||||||
return stringifiedParams.length > 0
|
|
||||||
? `/api/executions?${stringifiedParams}`
|
|
||||||
: `/api/executions`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const postV1StopGraphExecutions = async (
|
|
||||||
params: PostV1StopGraphExecutionsParams,
|
|
||||||
options?: RequestInit,
|
|
||||||
): Promise<postV1StopGraphExecutionsResponse> => {
|
|
||||||
return customMutator<postV1StopGraphExecutionsResponse>(
|
|
||||||
getPostV1StopGraphExecutionsUrl(params),
|
|
||||||
{
|
|
||||||
...options,
|
|
||||||
method: "POST",
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPostV1StopGraphExecutionsMutationOptions = <
|
|
||||||
TError = HTTPValidationError,
|
|
||||||
TContext = unknown,
|
|
||||||
>(options?: {
|
|
||||||
mutation?: UseMutationOptions<
|
|
||||||
Awaited<ReturnType<typeof postV1StopGraphExecutions>>,
|
|
||||||
TError,
|
|
||||||
{ params: PostV1StopGraphExecutionsParams },
|
|
||||||
TContext
|
|
||||||
>;
|
|
||||||
request?: SecondParameter<typeof customMutator>;
|
|
||||||
}): UseMutationOptions<
|
|
||||||
Awaited<ReturnType<typeof postV1StopGraphExecutions>>,
|
|
||||||
TError,
|
|
||||||
{ params: PostV1StopGraphExecutionsParams },
|
|
||||||
TContext
|
|
||||||
> => {
|
|
||||||
const mutationKey = ["postV1StopGraphExecutions"];
|
|
||||||
const { mutation: mutationOptions, request: requestOptions } = options
|
|
||||||
? options.mutation &&
|
|
||||||
"mutationKey" in options.mutation &&
|
|
||||||
options.mutation.mutationKey
|
|
||||||
? options
|
|
||||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
|
||||||
: { mutation: { mutationKey }, request: undefined };
|
|
||||||
|
|
||||||
const mutationFn: MutationFunction<
|
|
||||||
Awaited<ReturnType<typeof postV1StopGraphExecutions>>,
|
|
||||||
{ params: PostV1StopGraphExecutionsParams }
|
|
||||||
> = (props) => {
|
|
||||||
const { params } = props ?? {};
|
|
||||||
|
|
||||||
return postV1StopGraphExecutions(params, requestOptions);
|
|
||||||
};
|
|
||||||
|
|
||||||
return { mutationFn, ...mutationOptions };
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PostV1StopGraphExecutionsMutationResult = NonNullable<
|
|
||||||
Awaited<ReturnType<typeof postV1StopGraphExecutions>>
|
|
||||||
>;
|
|
||||||
|
|
||||||
export type PostV1StopGraphExecutionsMutationError = HTTPValidationError;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Stop graph executions
|
|
||||||
*/
|
|
||||||
export const usePostV1StopGraphExecutions = <
|
|
||||||
TError = HTTPValidationError,
|
|
||||||
TContext = unknown,
|
|
||||||
>(
|
|
||||||
options?: {
|
|
||||||
mutation?: UseMutationOptions<
|
|
||||||
Awaited<ReturnType<typeof postV1StopGraphExecutions>>,
|
|
||||||
TError,
|
|
||||||
{ params: PostV1StopGraphExecutionsParams },
|
|
||||||
TContext
|
|
||||||
>;
|
|
||||||
request?: SecondParameter<typeof customMutator>;
|
|
||||||
},
|
|
||||||
queryClient?: QueryClient,
|
|
||||||
): UseMutationResult<
|
|
||||||
Awaited<ReturnType<typeof postV1StopGraphExecutions>>,
|
|
||||||
TError,
|
|
||||||
{ params: PostV1StopGraphExecutionsParams },
|
|
||||||
TContext
|
|
||||||
> => {
|
|
||||||
const mutationOptions = getPostV1StopGraphExecutionsMutationOptions(options);
|
|
||||||
|
|
||||||
return useMutation(mutationOptions, queryClient);
|
|
||||||
};
|
|
||||||
/**
|
/**
|
||||||
* @summary Get all executions
|
* @summary Get all executions
|
||||||
*/
|
*/
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -37,14 +37,10 @@ import type { HTTPValidationError } from "../../models/hTTPValidationError";
|
|||||||
|
|
||||||
import type { LibraryAgent } from "../../models/libraryAgent";
|
import type { LibraryAgent } from "../../models/libraryAgent";
|
||||||
|
|
||||||
import type { LibraryAgentPreset } from "../../models/libraryAgentPreset";
|
|
||||||
|
|
||||||
import type { LibraryAgentResponse } from "../../models/libraryAgentResponse";
|
import type { LibraryAgentResponse } from "../../models/libraryAgentResponse";
|
||||||
|
|
||||||
import type { LibraryAgentUpdateRequest } from "../../models/libraryAgentUpdateRequest";
|
import type { LibraryAgentUpdateRequest } from "../../models/libraryAgentUpdateRequest";
|
||||||
|
|
||||||
import type { TriggeredPresetSetupParams } from "../../models/triggeredPresetSetupParams";
|
|
||||||
|
|
||||||
import { customMutator } from "../../../mutators/custom-mutator";
|
import { customMutator } from "../../../mutators/custom-mutator";
|
||||||
|
|
||||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||||
@@ -1588,117 +1584,3 @@ export const usePostV2ForkLibraryAgent = <
|
|||||||
|
|
||||||
return useMutation(mutationOptions, queryClient);
|
return useMutation(mutationOptions, queryClient);
|
||||||
};
|
};
|
||||||
/**
|
|
||||||
* Sets up a webhook-triggered `LibraryAgentPreset` for a `LibraryAgent`.
|
|
||||||
Returns the correspondingly created `LibraryAgentPreset` with `webhook_id` set.
|
|
||||||
* @summary Setup Trigger
|
|
||||||
*/
|
|
||||||
export type postV2SetupTriggerResponse200 = {
|
|
||||||
data: LibraryAgentPreset;
|
|
||||||
status: 200;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type postV2SetupTriggerResponse422 = {
|
|
||||||
data: HTTPValidationError;
|
|
||||||
status: 422;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type postV2SetupTriggerResponseComposite =
|
|
||||||
| postV2SetupTriggerResponse200
|
|
||||||
| postV2SetupTriggerResponse422;
|
|
||||||
|
|
||||||
export type postV2SetupTriggerResponse = postV2SetupTriggerResponseComposite & {
|
|
||||||
headers: Headers;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPostV2SetupTriggerUrl = (libraryAgentId: string) => {
|
|
||||||
return `/api/library/agents/${libraryAgentId}/setup-trigger`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const postV2SetupTrigger = async (
|
|
||||||
libraryAgentId: string,
|
|
||||||
triggeredPresetSetupParams: TriggeredPresetSetupParams,
|
|
||||||
options?: RequestInit,
|
|
||||||
): Promise<postV2SetupTriggerResponse> => {
|
|
||||||
return customMutator<postV2SetupTriggerResponse>(
|
|
||||||
getPostV2SetupTriggerUrl(libraryAgentId),
|
|
||||||
{
|
|
||||||
...options,
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json", ...options?.headers },
|
|
||||||
body: JSON.stringify(triggeredPresetSetupParams),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getPostV2SetupTriggerMutationOptions = <
|
|
||||||
TError = HTTPValidationError,
|
|
||||||
TContext = unknown,
|
|
||||||
>(options?: {
|
|
||||||
mutation?: UseMutationOptions<
|
|
||||||
Awaited<ReturnType<typeof postV2SetupTrigger>>,
|
|
||||||
TError,
|
|
||||||
{ libraryAgentId: string; data: TriggeredPresetSetupParams },
|
|
||||||
TContext
|
|
||||||
>;
|
|
||||||
request?: SecondParameter<typeof customMutator>;
|
|
||||||
}): UseMutationOptions<
|
|
||||||
Awaited<ReturnType<typeof postV2SetupTrigger>>,
|
|
||||||
TError,
|
|
||||||
{ libraryAgentId: string; data: TriggeredPresetSetupParams },
|
|
||||||
TContext
|
|
||||||
> => {
|
|
||||||
const mutationKey = ["postV2SetupTrigger"];
|
|
||||||
const { mutation: mutationOptions, request: requestOptions } = options
|
|
||||||
? options.mutation &&
|
|
||||||
"mutationKey" in options.mutation &&
|
|
||||||
options.mutation.mutationKey
|
|
||||||
? options
|
|
||||||
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
|
||||||
: { mutation: { mutationKey }, request: undefined };
|
|
||||||
|
|
||||||
const mutationFn: MutationFunction<
|
|
||||||
Awaited<ReturnType<typeof postV2SetupTrigger>>,
|
|
||||||
{ libraryAgentId: string; data: TriggeredPresetSetupParams }
|
|
||||||
> = (props) => {
|
|
||||||
const { libraryAgentId, data } = props ?? {};
|
|
||||||
|
|
||||||
return postV2SetupTrigger(libraryAgentId, data, requestOptions);
|
|
||||||
};
|
|
||||||
|
|
||||||
return { mutationFn, ...mutationOptions };
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PostV2SetupTriggerMutationResult = NonNullable<
|
|
||||||
Awaited<ReturnType<typeof postV2SetupTrigger>>
|
|
||||||
>;
|
|
||||||
export type PostV2SetupTriggerMutationBody = TriggeredPresetSetupParams;
|
|
||||||
export type PostV2SetupTriggerMutationError = HTTPValidationError;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @summary Setup Trigger
|
|
||||||
*/
|
|
||||||
export const usePostV2SetupTrigger = <
|
|
||||||
TError = HTTPValidationError,
|
|
||||||
TContext = unknown,
|
|
||||||
>(
|
|
||||||
options?: {
|
|
||||||
mutation?: UseMutationOptions<
|
|
||||||
Awaited<ReturnType<typeof postV2SetupTrigger>>,
|
|
||||||
TError,
|
|
||||||
{ libraryAgentId: string; data: TriggeredPresetSetupParams },
|
|
||||||
TContext
|
|
||||||
>;
|
|
||||||
request?: SecondParameter<typeof customMutator>;
|
|
||||||
},
|
|
||||||
queryClient?: QueryClient,
|
|
||||||
): UseMutationResult<
|
|
||||||
Awaited<ReturnType<typeof postV2SetupTrigger>>,
|
|
||||||
TError,
|
|
||||||
{ libraryAgentId: string; data: TriggeredPresetSetupParams },
|
|
||||||
TContext
|
|
||||||
> => {
|
|
||||||
const mutationOptions = getPostV2SetupTriggerMutationOptions(options);
|
|
||||||
|
|
||||||
return useMutation(mutationOptions, queryClient);
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ import type { PostV2CreateANewPresetBody } from "../../models/postV2CreateANewPr
|
|||||||
|
|
||||||
import type { PostV2ExecuteAPreset200 } from "../../models/postV2ExecuteAPreset200";
|
import type { PostV2ExecuteAPreset200 } from "../../models/postV2ExecuteAPreset200";
|
||||||
|
|
||||||
|
import type { TriggeredPresetSetupRequest } from "../../models/triggeredPresetSetupRequest";
|
||||||
|
|
||||||
import { customMutator } from "../../../mutators/custom-mutator";
|
import { customMutator } from "../../../mutators/custom-mutator";
|
||||||
|
|
||||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||||
@@ -779,6 +781,116 @@ export const useDeleteV2DeleteAPreset = <
|
|||||||
|
|
||||||
return useMutation(mutationOptions, queryClient);
|
return useMutation(mutationOptions, queryClient);
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* Sets up a webhook-triggered `LibraryAgentPreset` for a `LibraryAgent`.
|
||||||
|
Returns the correspondingly created `LibraryAgentPreset` with `webhook_id` set.
|
||||||
|
* @summary Setup Trigger
|
||||||
|
*/
|
||||||
|
export type postV2SetupTriggerResponse200 = {
|
||||||
|
data: LibraryAgentPreset;
|
||||||
|
status: 200;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type postV2SetupTriggerResponse422 = {
|
||||||
|
data: HTTPValidationError;
|
||||||
|
status: 422;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type postV2SetupTriggerResponseComposite =
|
||||||
|
| postV2SetupTriggerResponse200
|
||||||
|
| postV2SetupTriggerResponse422;
|
||||||
|
|
||||||
|
export type postV2SetupTriggerResponse = postV2SetupTriggerResponseComposite & {
|
||||||
|
headers: Headers;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPostV2SetupTriggerUrl = () => {
|
||||||
|
return `/api/library/presets/setup-trigger`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const postV2SetupTrigger = async (
|
||||||
|
triggeredPresetSetupRequest: TriggeredPresetSetupRequest,
|
||||||
|
options?: RequestInit,
|
||||||
|
): Promise<postV2SetupTriggerResponse> => {
|
||||||
|
return customMutator<postV2SetupTriggerResponse>(getPostV2SetupTriggerUrl(), {
|
||||||
|
...options,
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json", ...options?.headers },
|
||||||
|
body: JSON.stringify(triggeredPresetSetupRequest),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPostV2SetupTriggerMutationOptions = <
|
||||||
|
TError = HTTPValidationError,
|
||||||
|
TContext = unknown,
|
||||||
|
>(options?: {
|
||||||
|
mutation?: UseMutationOptions<
|
||||||
|
Awaited<ReturnType<typeof postV2SetupTrigger>>,
|
||||||
|
TError,
|
||||||
|
{ data: TriggeredPresetSetupRequest },
|
||||||
|
TContext
|
||||||
|
>;
|
||||||
|
request?: SecondParameter<typeof customMutator>;
|
||||||
|
}): UseMutationOptions<
|
||||||
|
Awaited<ReturnType<typeof postV2SetupTrigger>>,
|
||||||
|
TError,
|
||||||
|
{ data: TriggeredPresetSetupRequest },
|
||||||
|
TContext
|
||||||
|
> => {
|
||||||
|
const mutationKey = ["postV2SetupTrigger"];
|
||||||
|
const { mutation: mutationOptions, request: requestOptions } = options
|
||||||
|
? options.mutation &&
|
||||||
|
"mutationKey" in options.mutation &&
|
||||||
|
options.mutation.mutationKey
|
||||||
|
? options
|
||||||
|
: { ...options, mutation: { ...options.mutation, mutationKey } }
|
||||||
|
: { mutation: { mutationKey }, request: undefined };
|
||||||
|
|
||||||
|
const mutationFn: MutationFunction<
|
||||||
|
Awaited<ReturnType<typeof postV2SetupTrigger>>,
|
||||||
|
{ data: TriggeredPresetSetupRequest }
|
||||||
|
> = (props) => {
|
||||||
|
const { data } = props ?? {};
|
||||||
|
|
||||||
|
return postV2SetupTrigger(data, requestOptions);
|
||||||
|
};
|
||||||
|
|
||||||
|
return { mutationFn, ...mutationOptions };
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PostV2SetupTriggerMutationResult = NonNullable<
|
||||||
|
Awaited<ReturnType<typeof postV2SetupTrigger>>
|
||||||
|
>;
|
||||||
|
export type PostV2SetupTriggerMutationBody = TriggeredPresetSetupRequest;
|
||||||
|
export type PostV2SetupTriggerMutationError = HTTPValidationError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Setup Trigger
|
||||||
|
*/
|
||||||
|
export const usePostV2SetupTrigger = <
|
||||||
|
TError = HTTPValidationError,
|
||||||
|
TContext = unknown,
|
||||||
|
>(
|
||||||
|
options?: {
|
||||||
|
mutation?: UseMutationOptions<
|
||||||
|
Awaited<ReturnType<typeof postV2SetupTrigger>>,
|
||||||
|
TError,
|
||||||
|
{ data: TriggeredPresetSetupRequest },
|
||||||
|
TContext
|
||||||
|
>;
|
||||||
|
request?: SecondParameter<typeof customMutator>;
|
||||||
|
},
|
||||||
|
queryClient?: QueryClient,
|
||||||
|
): UseMutationResult<
|
||||||
|
Awaited<ReturnType<typeof postV2SetupTrigger>>,
|
||||||
|
TError,
|
||||||
|
{ data: TriggeredPresetSetupRequest },
|
||||||
|
TContext
|
||||||
|
> => {
|
||||||
|
const mutationOptions = getPostV2SetupTriggerMutationOptions(options);
|
||||||
|
|
||||||
|
return useMutation(mutationOptions, queryClient);
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Execute a preset with the given graph and node input for the current user.
|
* Execute a preset with the given graph and node input for the current user.
|
||||||
* @summary Execute a preset
|
* @summary Execute a preset
|
||||||
|
|||||||
@@ -24,4 +24,5 @@ export interface BaseGraphOutput {
|
|||||||
forked_from_version?: BaseGraphOutputForkedFromVersion;
|
forked_from_version?: BaseGraphOutputForkedFromVersion;
|
||||||
readonly input_schema: BaseGraphOutputInputSchema;
|
readonly input_schema: BaseGraphOutputInputSchema;
|
||||||
readonly output_schema: BaseGraphOutputOutputSchema;
|
readonly output_schema: BaseGraphOutputOutputSchema;
|
||||||
|
readonly has_external_trigger: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
* OpenAPI spec version: 0.1
|
* OpenAPI spec version: 0.1
|
||||||
*/
|
*/
|
||||||
import type { CredentialsMetaInputTitle } from "./credentialsMetaInputTitle";
|
import type { CredentialsMetaInputTitle } from "./credentialsMetaInputTitle";
|
||||||
import type { ProviderName } from "./providerName";
|
|
||||||
import type { CredentialsMetaInputType } from "./credentialsMetaInputType";
|
import type { CredentialsMetaInputType } from "./credentialsMetaInputType";
|
||||||
|
|
||||||
export interface CredentialsMetaInput {
|
export interface CredentialsMetaInput {
|
||||||
id: string;
|
id: string;
|
||||||
title?: CredentialsMetaInputTitle;
|
title?: CredentialsMetaInputTitle;
|
||||||
provider: ProviderName;
|
/** Provider name for integrations. Can be any string value, including custom provider names. */
|
||||||
|
provider: string;
|
||||||
type: CredentialsMetaInputType;
|
type: CredentialsMetaInputType;
|
||||||
}
|
}
|
||||||
|
|||||||
29
autogpt_platform/frontend/src/app/api/__generated__/models/graphMeta.ts
generated
Normal file
29
autogpt_platform/frontend/src/app/api/__generated__/models/graphMeta.ts
generated
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v7.10.0 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* AutoGPT Agent Server
|
||||||
|
* This server is used to execute agents that are created by the AutoGPT system.
|
||||||
|
* OpenAPI spec version: 0.1
|
||||||
|
*/
|
||||||
|
import type { GraphMetaForkedFromId } from "./graphMetaForkedFromId";
|
||||||
|
import type { GraphMetaForkedFromVersion } from "./graphMetaForkedFromVersion";
|
||||||
|
import type { BaseGraphOutput } from "./baseGraphOutput";
|
||||||
|
import type { GraphMetaInputSchema } from "./graphMetaInputSchema";
|
||||||
|
import type { GraphMetaOutputSchema } from "./graphMetaOutputSchema";
|
||||||
|
import type { GraphMetaCredentialsInputSchema } from "./graphMetaCredentialsInputSchema";
|
||||||
|
|
||||||
|
export interface GraphMeta {
|
||||||
|
id?: string;
|
||||||
|
version?: number;
|
||||||
|
is_active?: boolean;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
forked_from_id?: GraphMetaForkedFromId;
|
||||||
|
forked_from_version?: GraphMetaForkedFromVersion;
|
||||||
|
sub_graphs?: BaseGraphOutput[];
|
||||||
|
user_id: string;
|
||||||
|
readonly input_schema: GraphMetaInputSchema;
|
||||||
|
readonly output_schema: GraphMetaOutputSchema;
|
||||||
|
readonly has_external_trigger: boolean;
|
||||||
|
readonly credentials_input_schema: GraphMetaCredentialsInputSchema;
|
||||||
|
}
|
||||||
9
autogpt_platform/frontend/src/app/api/__generated__/models/graphMetaCredentialsInputSchema.ts
generated
Normal file
9
autogpt_platform/frontend/src/app/api/__generated__/models/graphMetaCredentialsInputSchema.ts
generated
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v7.10.0 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* AutoGPT Agent Server
|
||||||
|
* This server is used to execute agents that are created by the AutoGPT system.
|
||||||
|
* OpenAPI spec version: 0.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type GraphMetaCredentialsInputSchema = { [key: string]: unknown };
|
||||||
9
autogpt_platform/frontend/src/app/api/__generated__/models/graphMetaForkedFromId.ts
generated
Normal file
9
autogpt_platform/frontend/src/app/api/__generated__/models/graphMetaForkedFromId.ts
generated
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v7.10.0 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* AutoGPT Agent Server
|
||||||
|
* This server is used to execute agents that are created by the AutoGPT system.
|
||||||
|
* OpenAPI spec version: 0.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type GraphMetaForkedFromId = string | null;
|
||||||
9
autogpt_platform/frontend/src/app/api/__generated__/models/graphMetaForkedFromVersion.ts
generated
Normal file
9
autogpt_platform/frontend/src/app/api/__generated__/models/graphMetaForkedFromVersion.ts
generated
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v7.10.0 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* AutoGPT Agent Server
|
||||||
|
* This server is used to execute agents that are created by the AutoGPT system.
|
||||||
|
* OpenAPI spec version: 0.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type GraphMetaForkedFromVersion = number | null;
|
||||||
9
autogpt_platform/frontend/src/app/api/__generated__/models/graphMetaInputSchema.ts
generated
Normal file
9
autogpt_platform/frontend/src/app/api/__generated__/models/graphMetaInputSchema.ts
generated
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v7.10.0 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* AutoGPT Agent Server
|
||||||
|
* This server is used to execute agents that are created by the AutoGPT system.
|
||||||
|
* OpenAPI spec version: 0.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type GraphMetaInputSchema = { [key: string]: unknown };
|
||||||
9
autogpt_platform/frontend/src/app/api/__generated__/models/graphMetaOutputSchema.ts
generated
Normal file
9
autogpt_platform/frontend/src/app/api/__generated__/models/graphMetaOutputSchema.ts
generated
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v7.10.0 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* AutoGPT Agent Server
|
||||||
|
* This server is used to execute agents that are created by the AutoGPT system.
|
||||||
|
* OpenAPI spec version: 0.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type GraphMetaOutputSchema = { [key: string]: unknown };
|
||||||
@@ -28,6 +28,6 @@ export interface GraphModel {
|
|||||||
user_id: string;
|
user_id: string;
|
||||||
readonly input_schema: GraphModelInputSchema;
|
readonly input_schema: GraphModelInputSchema;
|
||||||
readonly output_schema: GraphModelOutputSchema;
|
readonly output_schema: GraphModelOutputSchema;
|
||||||
|
readonly has_external_trigger: boolean;
|
||||||
readonly credentials_input_schema: GraphModelCredentialsInputSchema;
|
readonly credentials_input_schema: GraphModelCredentialsInputSchema;
|
||||||
readonly has_webhook_trigger: boolean;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
* This server is used to execute agents that are created by the AutoGPT system.
|
* This server is used to execute agents that are created by the AutoGPT system.
|
||||||
* OpenAPI spec version: 0.1
|
* OpenAPI spec version: 0.1
|
||||||
*/
|
*/
|
||||||
import type { ProviderName } from "./providerName";
|
|
||||||
import type { LibraryAgentTriggerInfoConfigSchema } from "./libraryAgentTriggerInfoConfigSchema";
|
import type { LibraryAgentTriggerInfoConfigSchema } from "./libraryAgentTriggerInfoConfigSchema";
|
||||||
import type { LibraryAgentTriggerInfoCredentialsInputName } from "./libraryAgentTriggerInfoCredentialsInputName";
|
import type { LibraryAgentTriggerInfoCredentialsInputName } from "./libraryAgentTriggerInfoCredentialsInputName";
|
||||||
|
|
||||||
export interface LibraryAgentTriggerInfo {
|
export interface LibraryAgentTriggerInfo {
|
||||||
provider: ProviderName;
|
/** Provider name for integrations. Can be any string value, including custom provider names. */
|
||||||
|
provider: string;
|
||||||
/** Input schema for the trigger block */
|
/** Input schema for the trigger block */
|
||||||
config_schema: LibraryAgentTriggerInfoConfigSchema;
|
config_schema: LibraryAgentTriggerInfoConfigSchema;
|
||||||
credentials_input_name: LibraryAgentTriggerInfoCredentialsInputName;
|
credentials_input_name: LibraryAgentTriggerInfoCredentialsInputName;
|
||||||
|
|||||||
18
autogpt_platform/frontend/src/app/api/__generated__/models/triggeredPresetSetupRequest.ts
generated
Normal file
18
autogpt_platform/frontend/src/app/api/__generated__/models/triggeredPresetSetupRequest.ts
generated
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v7.10.0 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* AutoGPT Agent Server
|
||||||
|
* This server is used to execute agents that are created by the AutoGPT system.
|
||||||
|
* OpenAPI spec version: 0.1
|
||||||
|
*/
|
||||||
|
import type { TriggeredPresetSetupRequestTriggerConfig } from "./triggeredPresetSetupRequestTriggerConfig";
|
||||||
|
import type { TriggeredPresetSetupRequestAgentCredentials } from "./triggeredPresetSetupRequestAgentCredentials";
|
||||||
|
|
||||||
|
export interface TriggeredPresetSetupRequest {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
graph_id: string;
|
||||||
|
graph_version: number;
|
||||||
|
trigger_config: TriggeredPresetSetupRequestTriggerConfig;
|
||||||
|
agent_credentials?: TriggeredPresetSetupRequestAgentCredentials;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v7.10.0 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* AutoGPT Agent Server
|
||||||
|
* This server is used to execute agents that are created by the AutoGPT system.
|
||||||
|
* OpenAPI spec version: 0.1
|
||||||
|
*/
|
||||||
|
import type { CredentialsMetaInput } from "./credentialsMetaInput";
|
||||||
|
|
||||||
|
export type TriggeredPresetSetupRequestAgentCredentials = {
|
||||||
|
[key: string]: CredentialsMetaInput;
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v7.10.0 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* AutoGPT Agent Server
|
||||||
|
* This server is used to execute agents that are created by the AutoGPT system.
|
||||||
|
* OpenAPI spec version: 0.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type TriggeredPresetSetupRequestTriggerConfig = {
|
||||||
|
[key: string]: unknown;
|
||||||
|
};
|
||||||
@@ -5,13 +5,13 @@
|
|||||||
* This server is used to execute agents that are created by the AutoGPT system.
|
* This server is used to execute agents that are created by the AutoGPT system.
|
||||||
* OpenAPI spec version: 0.1
|
* OpenAPI spec version: 0.1
|
||||||
*/
|
*/
|
||||||
import type { ProviderName } from "./providerName";
|
|
||||||
import type { WebhookConfig } from "./webhookConfig";
|
import type { WebhookConfig } from "./webhookConfig";
|
||||||
|
|
||||||
export interface Webhook {
|
export interface Webhook {
|
||||||
id?: string;
|
id?: string;
|
||||||
user_id: string;
|
user_id: string;
|
||||||
provider: ProviderName;
|
/** Provider name for integrations. Can be any string value, including custom provider names. */
|
||||||
|
provider: string;
|
||||||
credentials_id: string;
|
credentials_id: string;
|
||||||
webhook_type: string;
|
webhook_type: string;
|
||||||
resource: string;
|
resource: string;
|
||||||
|
|||||||
@@ -18,8 +18,9 @@
|
|||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/ProviderName",
|
"type": "string",
|
||||||
"title": "The provider to initiate an OAuth flow for"
|
"title": "The provider to initiate an OAuth flow for",
|
||||||
|
"description": "Provider name for integrations. Can be any string value, including custom provider names."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -64,8 +65,9 @@
|
|||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/ProviderName",
|
"type": "string",
|
||||||
"title": "The target provider for this OAuth exchange"
|
"title": "The target provider for this OAuth exchange",
|
||||||
|
"description": "Provider name for integrations. Can be any string value, including custom provider names."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -133,8 +135,9 @@
|
|||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/ProviderName",
|
"type": "string",
|
||||||
"title": "The provider to list credentials for"
|
"title": "The provider to list credentials for",
|
||||||
|
"description": "Provider name for integrations. Can be any string value, including custom provider names."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -173,8 +176,9 @@
|
|||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/ProviderName",
|
"type": "string",
|
||||||
"title": "The provider to create credentials for"
|
"title": "The provider to create credentials for",
|
||||||
|
"description": "Provider name for integrations. Can be any string value, including custom provider names."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -253,8 +257,9 @@
|
|||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/ProviderName",
|
"type": "string",
|
||||||
"title": "The provider to retrieve credentials for"
|
"title": "The provider to retrieve credentials for",
|
||||||
|
"description": "Provider name for integrations. Can be any string value, including custom provider names."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -315,8 +320,9 @@
|
|||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/ProviderName",
|
"type": "string",
|
||||||
"title": "The provider to delete credentials for"
|
"title": "The provider to delete credentials for",
|
||||||
|
"description": "Provider name for integrations. Can be any string value, including custom provider names."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -380,8 +386,9 @@
|
|||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/ProviderName",
|
"type": "string",
|
||||||
"title": "Provider where the webhook was registered"
|
"title": "Provider where the webhook was registered",
|
||||||
|
"description": "Provider name for integrations. Can be any string value, including custom provider names."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -436,6 +443,86 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/integrations/providers": {
|
||||||
|
"get": {
|
||||||
|
"tags": ["v1", "integrations"],
|
||||||
|
"summary": "List Providers",
|
||||||
|
"description": "Get a list of all available provider names.\n\nReturns both statically defined providers (from ProviderName enum)\nand dynamically registered providers (from SDK decorators).\n\nNote: The complete list of provider names is also available as a constant\nin the generated TypeScript client via PROVIDER_NAMES.",
|
||||||
|
"operationId": "getV1ListProviders",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"items": { "type": "string" },
|
||||||
|
"type": "array",
|
||||||
|
"title": "Response Getv1Listproviders"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/integrations/providers/names": {
|
||||||
|
"get": {
|
||||||
|
"tags": ["v1", "integrations"],
|
||||||
|
"summary": "Get Provider Names",
|
||||||
|
"description": "Get all provider names in a structured format.\n\nThis endpoint is specifically designed to expose the provider names\nin the OpenAPI schema so that code generators like Orval can create\nappropriate TypeScript constants.",
|
||||||
|
"operationId": "getV1GetProviderNames",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProviderNamesResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/integrations/providers/constants": {
|
||||||
|
"get": {
|
||||||
|
"tags": ["v1", "integrations"],
|
||||||
|
"summary": "Get Provider Constants",
|
||||||
|
"description": "Get provider names as constants.\n\nThis endpoint returns a model with provider names as constants,\nspecifically designed for OpenAPI code generation tools to create\nTypeScript constants.",
|
||||||
|
"operationId": "getV1GetProviderConstants",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": { "$ref": "#/components/schemas/ProviderConstants" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/integrations/providers/enum-example": {
|
||||||
|
"get": {
|
||||||
|
"tags": ["v1", "integrations"],
|
||||||
|
"summary": "Get Provider Enum Example",
|
||||||
|
"description": "Example endpoint that uses the CompleteProviderNames enum.\n\nThis endpoint exists to ensure that the CompleteProviderNames enum is included\nin the OpenAPI schema, which will cause Orval to generate it as a\nTypeScript enum/constant.",
|
||||||
|
"operationId": "getV1GetProviderEnumExample",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProviderEnumResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/analytics/log_raw_metric": {
|
"/api/analytics/log_raw_metric": {
|
||||||
"post": {
|
"post": {
|
||||||
"tags": ["v1", "analytics"],
|
"tags": ["v1", "analytics"],
|
||||||
@@ -1018,7 +1105,7 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"items": { "$ref": "#/components/schemas/GraphModel" },
|
"items": { "$ref": "#/components/schemas/GraphMeta" },
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"title": "Response Getv1List User Graphs"
|
"title": "Response Getv1List User Graphs"
|
||||||
}
|
}
|
||||||
@@ -1415,49 +1502,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/executions": {
|
"/api/executions": {
|
||||||
"post": {
|
|
||||||
"tags": ["v1", "graphs"],
|
|
||||||
"summary": "Stop graph executions",
|
|
||||||
"operationId": "postV1Stop graph executions",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "graph_id",
|
|
||||||
"in": "query",
|
|
||||||
"required": true,
|
|
||||||
"schema": { "type": "string", "title": "Graph Id" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "graph_exec_id",
|
|
||||||
"in": "query",
|
|
||||||
"required": true,
|
|
||||||
"schema": { "type": "string", "title": "Graph Exec Id" }
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Successful Response",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/components/schemas/GraphExecutionMeta"
|
|
||||||
},
|
|
||||||
"title": "Response Postv1Stop Graph Executions"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"422": {
|
|
||||||
"description": "Validation Error",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": { "$ref": "#/components/schemas/HTTPValidationError" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"get": {
|
"get": {
|
||||||
"tags": ["v1", "graphs"],
|
"tags": ["v1", "graphs"],
|
||||||
"summary": "Get all executions",
|
"summary": "Get all executions",
|
||||||
@@ -1468,10 +1512,10 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "array",
|
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/components/schemas/GraphExecutionMeta"
|
"$ref": "#/components/schemas/GraphExecutionMeta"
|
||||||
},
|
},
|
||||||
|
"type": "array",
|
||||||
"title": "Response Getv1Get All Executions"
|
"title": "Response Getv1Get All Executions"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3014,6 +3058,42 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/library/presets/setup-trigger": {
|
||||||
|
"post": {
|
||||||
|
"tags": ["v2", "presets"],
|
||||||
|
"summary": "Setup Trigger",
|
||||||
|
"description": "Sets up a webhook-triggered `LibraryAgentPreset` for a `LibraryAgent`.\nReturns the correspondingly created `LibraryAgentPreset` with `webhook_id` set.",
|
||||||
|
"operationId": "postV2SetupTrigger",
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/TriggeredPresetSetupRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": { "$ref": "#/components/schemas/LibraryAgentPreset" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"description": "Validation Error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": { "$ref": "#/components/schemas/HTTPValidationError" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/library/presets/{preset_id}/execute": {
|
"/api/library/presets/{preset_id}/execute": {
|
||||||
"post": {
|
"post": {
|
||||||
"tags": ["v2", "presets", "presets"],
|
"tags": ["v2", "presets", "presets"],
|
||||||
@@ -3401,55 +3481,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/library/agents/{library_agent_id}/setup-trigger": {
|
|
||||||
"post": {
|
|
||||||
"tags": ["v2", "library", "private"],
|
|
||||||
"summary": "Setup Trigger",
|
|
||||||
"description": "Sets up a webhook-triggered `LibraryAgentPreset` for a `LibraryAgent`.\nReturns the correspondingly created `LibraryAgentPreset` with `webhook_id` set.",
|
|
||||||
"operationId": "postV2SetupTrigger",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "library_agent_id",
|
|
||||||
"in": "path",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "ID of the library agent",
|
|
||||||
"title": "Library Agent Id"
|
|
||||||
},
|
|
||||||
"description": "ID of the library agent"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"requestBody": {
|
|
||||||
"required": true,
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/TriggeredPresetSetupParams"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Successful Response",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": { "$ref": "#/components/schemas/LibraryAgentPreset" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"422": {
|
|
||||||
"description": "Validation Error",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": { "$ref": "#/components/schemas/HTTPValidationError" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/otto/ask": {
|
"/api/otto/ask": {
|
||||||
"post": {
|
"post": {
|
||||||
"tags": ["v2", "otto"],
|
"tags": ["v2", "otto"],
|
||||||
@@ -3837,10 +3868,21 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "Output Schema",
|
"title": "Output Schema",
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
|
},
|
||||||
|
"has_external_trigger": {
|
||||||
|
"type": "boolean",
|
||||||
|
"title": "Has External Trigger",
|
||||||
|
"readOnly": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["name", "description", "input_schema", "output_schema"],
|
"required": [
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
"input_schema",
|
||||||
|
"output_schema",
|
||||||
|
"has_external_trigger"
|
||||||
|
],
|
||||||
"title": "BaseGraph"
|
"title": "BaseGraph"
|
||||||
},
|
},
|
||||||
"Body_postV1Callback": {
|
"Body_postV1Callback": {
|
||||||
@@ -4101,7 +4143,11 @@
|
|||||||
"anyOf": [{ "type": "string" }, { "type": "null" }],
|
"anyOf": [{ "type": "string" }, { "type": "null" }],
|
||||||
"title": "Title"
|
"title": "Title"
|
||||||
},
|
},
|
||||||
"provider": { "$ref": "#/components/schemas/ProviderName" },
|
"provider": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "Provider",
|
||||||
|
"description": "Provider name for integrations. Can be any string value, including custom provider names."
|
||||||
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["api_key", "oauth2", "user_password", "host_scoped"],
|
"enum": ["api_key", "oauth2", "user_password", "host_scoped"],
|
||||||
@@ -4405,6 +4451,68 @@
|
|||||||
],
|
],
|
||||||
"title": "GraphExecutionWithNodes"
|
"title": "GraphExecutionWithNodes"
|
||||||
},
|
},
|
||||||
|
"GraphMeta": {
|
||||||
|
"properties": {
|
||||||
|
"id": { "type": "string", "title": "Id" },
|
||||||
|
"version": { "type": "integer", "title": "Version", "default": 1 },
|
||||||
|
"is_active": {
|
||||||
|
"type": "boolean",
|
||||||
|
"title": "Is Active",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"name": { "type": "string", "title": "Name" },
|
||||||
|
"description": { "type": "string", "title": "Description" },
|
||||||
|
"forked_from_id": {
|
||||||
|
"anyOf": [{ "type": "string" }, { "type": "null" }],
|
||||||
|
"title": "Forked From Id"
|
||||||
|
},
|
||||||
|
"forked_from_version": {
|
||||||
|
"anyOf": [{ "type": "integer" }, { "type": "null" }],
|
||||||
|
"title": "Forked From Version"
|
||||||
|
},
|
||||||
|
"sub_graphs": {
|
||||||
|
"items": { "$ref": "#/components/schemas/BaseGraph-Output" },
|
||||||
|
"type": "array",
|
||||||
|
"title": "Sub Graphs",
|
||||||
|
"default": []
|
||||||
|
},
|
||||||
|
"user_id": { "type": "string", "title": "User Id" },
|
||||||
|
"input_schema": {
|
||||||
|
"additionalProperties": true,
|
||||||
|
"type": "object",
|
||||||
|
"title": "Input Schema",
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
|
"output_schema": {
|
||||||
|
"additionalProperties": true,
|
||||||
|
"type": "object",
|
||||||
|
"title": "Output Schema",
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
|
"has_external_trigger": {
|
||||||
|
"type": "boolean",
|
||||||
|
"title": "Has External Trigger",
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
|
"credentials_input_schema": {
|
||||||
|
"additionalProperties": true,
|
||||||
|
"type": "object",
|
||||||
|
"title": "Credentials Input Schema",
|
||||||
|
"readOnly": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
"user_id",
|
||||||
|
"input_schema",
|
||||||
|
"output_schema",
|
||||||
|
"has_external_trigger",
|
||||||
|
"credentials_input_schema"
|
||||||
|
],
|
||||||
|
"title": "GraphMeta"
|
||||||
|
},
|
||||||
"GraphModel": {
|
"GraphModel": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": { "type": "string", "title": "Id" },
|
"id": { "type": "string", "title": "Id" },
|
||||||
@@ -4455,16 +4563,16 @@
|
|||||||
"title": "Output Schema",
|
"title": "Output Schema",
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
},
|
},
|
||||||
|
"has_external_trigger": {
|
||||||
|
"type": "boolean",
|
||||||
|
"title": "Has External Trigger",
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
"credentials_input_schema": {
|
"credentials_input_schema": {
|
||||||
"additionalProperties": true,
|
"additionalProperties": true,
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "Credentials Input Schema",
|
"title": "Credentials Input Schema",
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
},
|
|
||||||
"has_webhook_trigger": {
|
|
||||||
"type": "boolean",
|
|
||||||
"title": "Has Webhook Trigger",
|
|
||||||
"readOnly": true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -4474,8 +4582,8 @@
|
|||||||
"user_id",
|
"user_id",
|
||||||
"input_schema",
|
"input_schema",
|
||||||
"output_schema",
|
"output_schema",
|
||||||
"credentials_input_schema",
|
"has_external_trigger",
|
||||||
"has_webhook_trigger"
|
"credentials_input_schema"
|
||||||
],
|
],
|
||||||
"title": "GraphModel"
|
"title": "GraphModel"
|
||||||
},
|
},
|
||||||
@@ -4820,7 +4928,11 @@
|
|||||||
},
|
},
|
||||||
"LibraryAgentTriggerInfo": {
|
"LibraryAgentTriggerInfo": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"provider": { "$ref": "#/components/schemas/ProviderName" },
|
"provider": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "Provider",
|
||||||
|
"description": "Provider name for integrations. Can be any string value, including custom provider names."
|
||||||
|
},
|
||||||
"config_schema": {
|
"config_schema": {
|
||||||
"additionalProperties": true,
|
"additionalProperties": true,
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -5623,51 +5735,44 @@
|
|||||||
"required": ["name", "username", "description", "links"],
|
"required": ["name", "username", "description", "links"],
|
||||||
"title": "ProfileDetails"
|
"title": "ProfileDetails"
|
||||||
},
|
},
|
||||||
"ProviderName": {
|
"ProviderConstants": {
|
||||||
"type": "string",
|
"properties": {
|
||||||
"enum": [
|
"PROVIDER_NAMES": {
|
||||||
"aiml_api",
|
"additionalProperties": { "type": "string" },
|
||||||
"anthropic",
|
"type": "object",
|
||||||
"apollo",
|
"title": "Provider Names",
|
||||||
"compass",
|
"description": "All available provider names as a constant mapping"
|
||||||
"discord",
|
}
|
||||||
"d_id",
|
},
|
||||||
"e2b",
|
"type": "object",
|
||||||
"exa",
|
"title": "ProviderConstants",
|
||||||
"fal",
|
"description": "Model that exposes all provider names as a constant in the OpenAPI schema.\nThis is designed to be converted by Orval into a TypeScript constant."
|
||||||
"generic_webhook",
|
},
|
||||||
"github",
|
"ProviderEnumResponse": {
|
||||||
"google",
|
"properties": {
|
||||||
"google_maps",
|
"provider": {
|
||||||
"groq",
|
"type": "string",
|
||||||
"http",
|
"title": "Provider",
|
||||||
"hubspot",
|
"description": "A provider name from the complete list of providers"
|
||||||
"ideogram",
|
}
|
||||||
"jina",
|
},
|
||||||
"linear",
|
"type": "object",
|
||||||
"llama_api",
|
"required": ["provider"],
|
||||||
"medium",
|
"title": "ProviderEnumResponse",
|
||||||
"mem0",
|
"description": "Response containing a provider from the enum."
|
||||||
"notion",
|
},
|
||||||
"nvidia",
|
"ProviderNamesResponse": {
|
||||||
"ollama",
|
"properties": {
|
||||||
"openai",
|
"providers": {
|
||||||
"openweathermap",
|
"items": { "type": "string" },
|
||||||
"open_router",
|
"type": "array",
|
||||||
"pinecone",
|
"title": "Providers",
|
||||||
"reddit",
|
"description": "List of all available provider names"
|
||||||
"replicate",
|
}
|
||||||
"revid",
|
},
|
||||||
"screenshotone",
|
"type": "object",
|
||||||
"slant3d",
|
"title": "ProviderNamesResponse",
|
||||||
"smartlead",
|
"description": "Response containing list of all provider names."
|
||||||
"smtp",
|
|
||||||
"twitter",
|
|
||||||
"todoist",
|
|
||||||
"unreal_speech",
|
|
||||||
"zerobounce"
|
|
||||||
],
|
|
||||||
"title": "ProviderName"
|
|
||||||
},
|
},
|
||||||
"RefundRequest": {
|
"RefundRequest": {
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -6153,7 +6258,7 @@
|
|||||||
"required": ["transactions", "next_transaction_time"],
|
"required": ["transactions", "next_transaction_time"],
|
||||||
"title": "TransactionHistory"
|
"title": "TransactionHistory"
|
||||||
},
|
},
|
||||||
"TriggeredPresetSetupParams": {
|
"TriggeredPresetSetupRequest": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": { "type": "string", "title": "Name" },
|
"name": { "type": "string", "title": "Name" },
|
||||||
"description": {
|
"description": {
|
||||||
@@ -6161,6 +6266,8 @@
|
|||||||
"title": "Description",
|
"title": "Description",
|
||||||
"default": ""
|
"default": ""
|
||||||
},
|
},
|
||||||
|
"graph_id": { "type": "string", "title": "Graph Id" },
|
||||||
|
"graph_version": { "type": "integer", "title": "Graph Version" },
|
||||||
"trigger_config": {
|
"trigger_config": {
|
||||||
"additionalProperties": true,
|
"additionalProperties": true,
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -6175,8 +6282,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["name", "trigger_config"],
|
"required": ["name", "graph_id", "graph_version", "trigger_config"],
|
||||||
"title": "TriggeredPresetSetupParams"
|
"title": "TriggeredPresetSetupRequest"
|
||||||
},
|
},
|
||||||
"TurnstileVerifyRequest": {
|
"TurnstileVerifyRequest": {
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -6441,7 +6548,11 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"id": { "type": "string", "title": "Id" },
|
"id": { "type": "string", "title": "Id" },
|
||||||
"user_id": { "type": "string", "title": "User Id" },
|
"user_id": { "type": "string", "title": "User Id" },
|
||||||
"provider": { "$ref": "#/components/schemas/ProviderName" },
|
"provider": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "Provider",
|
||||||
|
"description": "Provider name for integrations. Can be any string value, including custom provider names."
|
||||||
|
},
|
||||||
"credentials_id": { "type": "string", "title": "Credentials Id" },
|
"credentials_id": { "type": "string", "title": "Credentials Id" },
|
||||||
"webhook_type": { "type": "string", "title": "Webhook Type" },
|
"webhook_type": { "type": "string", "title": "Webhook Type" },
|
||||||
"resource": { "type": "string", "title": "Resource" },
|
"resource": { "type": "string", "title": "Resource" },
|
||||||
|
|||||||
@@ -1,31 +1,35 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
|
||||||
import { ThemeProviderProps } from "next-themes";
|
|
||||||
import { BackendAPIProvider } from "@/lib/autogpt-server-api/context";
|
|
||||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
||||||
import CredentialsProvider from "@/components/integrations/credentials-provider";
|
|
||||||
import { LaunchDarklyProvider } from "@/components/feature-flag/feature-flag-provider";
|
import { LaunchDarklyProvider } from "@/components/feature-flag/feature-flag-provider";
|
||||||
|
import CredentialsProvider from "@/components/integrations/credentials-provider";
|
||||||
import OnboardingProvider from "@/components/onboarding/onboarding-provider";
|
import OnboardingProvider from "@/components/onboarding/onboarding-provider";
|
||||||
import { QueryClientProvider } from "@tanstack/react-query";
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||||
|
import { BackendAPIProvider } from "@/lib/autogpt-server-api/context";
|
||||||
import { getQueryClient } from "@/lib/react-query/queryClient";
|
import { getQueryClient } from "@/lib/react-query/queryClient";
|
||||||
|
import { QueryClientProvider } from "@tanstack/react-query";
|
||||||
|
import {
|
||||||
|
ThemeProvider as NextThemesProvider,
|
||||||
|
ThemeProviderProps,
|
||||||
|
} from "next-themes";
|
||||||
|
import { NuqsAdapter } from "nuqs/adapters/next/app";
|
||||||
|
|
||||||
export function Providers({ children, ...props }: ThemeProviderProps) {
|
export function Providers({ children, ...props }: ThemeProviderProps) {
|
||||||
const queryClient = getQueryClient();
|
const queryClient = getQueryClient();
|
||||||
return (
|
return (
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<NextThemesProvider {...props}>
|
<NuqsAdapter>
|
||||||
<BackendAPIProvider>
|
<NextThemesProvider {...props}>
|
||||||
<CredentialsProvider>
|
<BackendAPIProvider>
|
||||||
<LaunchDarklyProvider>
|
<CredentialsProvider>
|
||||||
<OnboardingProvider>
|
<LaunchDarklyProvider>
|
||||||
<TooltipProvider>{children}</TooltipProvider>
|
<OnboardingProvider>
|
||||||
</OnboardingProvider>
|
<TooltipProvider>{children}</TooltipProvider>
|
||||||
</LaunchDarklyProvider>
|
</OnboardingProvider>
|
||||||
</CredentialsProvider>
|
</LaunchDarklyProvider>
|
||||||
</BackendAPIProvider>
|
</CredentialsProvider>
|
||||||
</NextThemesProvider>
|
</BackendAPIProvider>
|
||||||
|
</NextThemesProvider>
|
||||||
|
</NuqsAdapter>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { Plus } from "lucide-react";
|
import { Plus } from "lucide-react";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import {
|
import {
|
||||||
GraphExecutionID,
|
GraphExecutionID,
|
||||||
GraphExecutionMeta,
|
GraphExecutionMeta,
|
||||||
@@ -12,14 +11,15 @@ import {
|
|||||||
Schedule,
|
Schedule,
|
||||||
ScheduleID,
|
ScheduleID,
|
||||||
} from "@/lib/autogpt-server-api";
|
} from "@/lib/autogpt-server-api";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { Button } from "@/components/agptui/Button";
|
|
||||||
import { Badge } from "@/components/ui/badge";
|
|
||||||
|
|
||||||
import { agentRunStatusMap } from "@/components/agents/agent-run-status-chip";
|
import { agentRunStatusMap } from "@/components/agents/agent-run-status-chip";
|
||||||
import AgentRunSummaryCard from "@/components/agents/agent-run-summary-card";
|
import AgentRunSummaryCard from "@/components/agents/agent-run-summary-card";
|
||||||
|
import { Button } from "../atoms/Button/Button";
|
||||||
|
|
||||||
interface AgentRunsSelectorListProps {
|
interface AgentRunsSelectorListProps {
|
||||||
agent: LibraryAgent;
|
agent: LibraryAgent;
|
||||||
@@ -72,17 +72,11 @@ export default function AgentRunsSelectorList({
|
|||||||
<aside className={cn("flex flex-col gap-4", className)}>
|
<aside className={cn("flex flex-col gap-4", className)}>
|
||||||
{allowDraftNewRun && (
|
{allowDraftNewRun && (
|
||||||
<Button
|
<Button
|
||||||
size="card"
|
className={"mb-4 hidden lg:flex"}
|
||||||
className={
|
|
||||||
"mb-4 hidden h-16 w-72 items-center gap-2 py-6 lg:flex xl:w-80 " +
|
|
||||||
(selectedView.type == "run" && !selectedView.id
|
|
||||||
? "agpt-card-selected text-accent"
|
|
||||||
: "")
|
|
||||||
}
|
|
||||||
onClick={onSelectDraftNewRun}
|
onClick={onSelectDraftNewRun}
|
||||||
|
leftIcon={<Plus className="h-6 w-6" />}
|
||||||
>
|
>
|
||||||
<Plus className="h-6 w-6" />
|
New {agent.has_external_trigger ? "trigger" : "run"}
|
||||||
<span>New {agent.has_external_trigger ? "trigger" : "run"}</span>
|
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -112,7 +106,7 @@ export default function AgentRunsSelectorList({
|
|||||||
{/* New Run button - only in small layouts */}
|
{/* New Run button - only in small layouts */}
|
||||||
{allowDraftNewRun && (
|
{allowDraftNewRun && (
|
||||||
<Button
|
<Button
|
||||||
size="card"
|
size="large"
|
||||||
className={
|
className={
|
||||||
"flex h-28 w-40 items-center gap-2 py-6 lg:hidden " +
|
"flex h-28 w-40 items-center gap-2 py-6 lg:hidden " +
|
||||||
(selectedView.type == "run" && !selectedView.id
|
(selectedView.type == "run" && !selectedView.id
|
||||||
@@ -120,9 +114,9 @@ export default function AgentRunsSelectorList({
|
|||||||
: "")
|
: "")
|
||||||
}
|
}
|
||||||
onClick={onSelectDraftNewRun}
|
onClick={onSelectDraftNewRun}
|
||||||
|
leftIcon={<Plus className="h-6 w-6" />}
|
||||||
>
|
>
|
||||||
<Plus className="h-6 w-6" />
|
New {agent.has_external_trigger ? "trigger" : "run"}
|
||||||
<span>New {agent.has_external_trigger ? "trigger" : "run"}</span>
|
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { IconAutoGPTLogo, IconType } from "@/components/ui/icons";
|
import { IconAutoGPTLogo, IconType } from "@/components/ui/icons";
|
||||||
import Wallet from "../../agptui/Wallet";
|
import Wallet from "../../agptui/Wallet";
|
||||||
import { AccountMenu } from "./components/AccountMenu/AccountMenu";
|
import { AccountMenu } from "./components/AccountMenu/AccountMenu";
|
||||||
|
import { AgentActivityDropdown } from "./components/AgentActivityDropdown/AgentActivityDropdown";
|
||||||
import { LoginButton } from "./components/LoginButton";
|
import { LoginButton } from "./components/LoginButton";
|
||||||
import { MobileNavBar } from "./components/MobileNavbar/MobileNavBar";
|
import { MobileNavBar } from "./components/MobileNavbar/MobileNavBar";
|
||||||
import { NavbarLink } from "./components/NavbarLink";
|
import { NavbarLink } from "./components/NavbarLink";
|
||||||
@@ -33,6 +34,7 @@ export async function Navbar() {
|
|||||||
<div className="flex flex-1 items-center justify-end gap-4">
|
<div className="flex flex-1 items-center justify-end gap-4">
|
||||||
{isLoggedIn ? (
|
{isLoggedIn ? (
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
<AgentActivityDropdown />
|
||||||
{profile && <Wallet />}
|
{profile && <Wallet />}
|
||||||
<AccountMenu
|
<AccountMenu
|
||||||
userName={profile?.username}
|
userName={profile?.username}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "@/components/ui/popover";
|
||||||
|
import { Bell } from "@phosphor-icons/react";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { ActivityDropdown } from "./components/ActivityDropdown";
|
||||||
|
import { formatNotificationCount } from "./helpers";
|
||||||
|
import { useAgentActivityDropdown } from "./useAgentActivityDropdown";
|
||||||
|
|
||||||
|
export function AgentActivityDropdown() {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const { activeExecutions, recentCompletions, recentFailures } =
|
||||||
|
useAgentActivityDropdown();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover open={isOpen} onOpenChange={setIsOpen}>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<button
|
||||||
|
className={`group relative h-[2.5rem] w-[2.5rem] rounded-full p-2 transition-colors hover:bg-white ${isOpen ? "bg-white" : ""}`}
|
||||||
|
title="Agent Activity"
|
||||||
|
>
|
||||||
|
<Bell size={22} className="text-black" />
|
||||||
|
|
||||||
|
{activeExecutions.length > 0 && (
|
||||||
|
<>
|
||||||
|
{/* Running Agents Rotating Badge */}
|
||||||
|
<div className="absolute right-[1px] top-[0.5px] flex h-5 w-5 items-center justify-center rounded-full bg-purple-600 text-[10px] font-medium text-white">
|
||||||
|
{formatNotificationCount(activeExecutions.length)}
|
||||||
|
<div className="absolute -inset-0.5 animate-spin rounded-full border-[3px] border-transparent border-r-purple-200 border-t-purple-200" />
|
||||||
|
</div>
|
||||||
|
{/* Running Agent Hover Hint */}
|
||||||
|
<div className="absolute bottom-[-2.5rem] left-1/2 z-50 hidden -translate-x-1/2 transform whitespace-nowrap rounded-small bg-white px-4 py-2 shadow-md group-hover:block">
|
||||||
|
<Text variant="body-medium">
|
||||||
|
{activeExecutions.length} running agent
|
||||||
|
{activeExecutions.length > 1 ? "s" : ""}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
|
||||||
|
<PopoverContent className="w-80 p-0" align="center" sideOffset={8}>
|
||||||
|
<ActivityDropdown
|
||||||
|
activeExecutions={activeExecutions}
|
||||||
|
recentCompletions={recentCompletions}
|
||||||
|
recentFailures={recentFailures}
|
||||||
|
/>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus";
|
||||||
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||||
|
import { Bell } from "@phosphor-icons/react";
|
||||||
|
import { AgentExecutionWithInfo, EXECUTION_DISPLAY_LIMIT } from "../helpers";
|
||||||
|
import { ActivityItem } from "./ActivityItem";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
activeExecutions: AgentExecutionWithInfo[];
|
||||||
|
recentCompletions: AgentExecutionWithInfo[];
|
||||||
|
recentFailures: AgentExecutionWithInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ActivityDropdown({
|
||||||
|
activeExecutions,
|
||||||
|
recentCompletions,
|
||||||
|
recentFailures,
|
||||||
|
}: Props) {
|
||||||
|
// Combine and sort all executions - running/queued at top, then by most recent
|
||||||
|
function getSortedExecutions() {
|
||||||
|
const allExecutions = [
|
||||||
|
...activeExecutions.map((e) => ({ ...e, type: "running" as const })),
|
||||||
|
...recentCompletions.map((e) => ({ ...e, type: "completed" as const })),
|
||||||
|
...recentFailures.map((e) => ({ ...e, type: "failed" as const })),
|
||||||
|
];
|
||||||
|
|
||||||
|
return allExecutions
|
||||||
|
.sort((a, b) => {
|
||||||
|
// Running/queued always at top
|
||||||
|
const aIsActive =
|
||||||
|
a.status === AgentExecutionStatus.RUNNING ||
|
||||||
|
a.status === AgentExecutionStatus.QUEUED;
|
||||||
|
const bIsActive =
|
||||||
|
b.status === AgentExecutionStatus.RUNNING ||
|
||||||
|
b.status === AgentExecutionStatus.QUEUED;
|
||||||
|
|
||||||
|
if (aIsActive && !bIsActive) return -1;
|
||||||
|
if (!aIsActive && bIsActive) return 1;
|
||||||
|
|
||||||
|
// Within same category, sort by most recent
|
||||||
|
const aTime = aIsActive ? a.started_at : a.ended_at;
|
||||||
|
const bTime = bIsActive ? b.started_at : b.ended_at;
|
||||||
|
|
||||||
|
if (!aTime || !bTime) return 0;
|
||||||
|
return new Date(bTime).getTime() - new Date(aTime).getTime();
|
||||||
|
})
|
||||||
|
.slice(0, EXECUTION_DISPLAY_LIMIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortedExecutions = getSortedExecutions();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{/* Header */}
|
||||||
|
<div className="sticky top-0 z-10 px-4 pb-1 pt-4">
|
||||||
|
<Text variant="large-semibold" className="!text-black">
|
||||||
|
Agent Activity
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<ScrollArea className="min-h-[10rem]">
|
||||||
|
{sortedExecutions.length > 0 ? (
|
||||||
|
<div className="p-2">
|
||||||
|
{sortedExecutions.map((execution) => (
|
||||||
|
<ActivityItem key={execution.id} execution={execution} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex h-full flex-col items-center justify-center gap-5 pb-8 pt-6">
|
||||||
|
<div className="mx-auto inline-flex flex-col items-center justify-center rounded-full bg-lightGrey p-6">
|
||||||
|
<Bell className="h-6 w-6 text-zinc-300" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col items-center justify-center">
|
||||||
|
<Text variant="body-medium" className="!text-black">
|
||||||
|
Nothing to show yet
|
||||||
|
</Text>
|
||||||
|
<Text variant="body" className="!text-zinc-500">
|
||||||
|
Start an agent to get updates
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</ScrollArea>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus";
|
||||||
|
import { Text } from "@/components/atoms/Text/Text";
|
||||||
|
import {
|
||||||
|
CheckCircle,
|
||||||
|
CircleNotchIcon,
|
||||||
|
Clock,
|
||||||
|
WarningOctagonIcon,
|
||||||
|
StopCircle,
|
||||||
|
CircleDashed,
|
||||||
|
} from "@phosphor-icons/react";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import type { AgentExecutionWithInfo } from "../helpers";
|
||||||
|
import { formatTimeAgo, getExecutionDuration } from "../helpers";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
execution: AgentExecutionWithInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ActivityItem({ execution }: Props) {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
function getStatusIcon() {
|
||||||
|
switch (execution.status) {
|
||||||
|
case AgentExecutionStatus.QUEUED:
|
||||||
|
return <Clock size={18} className="text-purple-500" />;
|
||||||
|
case AgentExecutionStatus.RUNNING:
|
||||||
|
return (
|
||||||
|
<CircleNotchIcon
|
||||||
|
size={18}
|
||||||
|
className="animate-spin text-purple-500"
|
||||||
|
weight="bold"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case AgentExecutionStatus.COMPLETED:
|
||||||
|
return (
|
||||||
|
<CheckCircle size={18} weight="fill" className="text-purple-500" />
|
||||||
|
);
|
||||||
|
case AgentExecutionStatus.FAILED:
|
||||||
|
return <WarningOctagonIcon size={18} className="text-purple-500" />;
|
||||||
|
case AgentExecutionStatus.TERMINATED:
|
||||||
|
return (
|
||||||
|
<StopCircle size={18} className="text-purple-500" weight="fill" />
|
||||||
|
);
|
||||||
|
case AgentExecutionStatus.INCOMPLETE:
|
||||||
|
return <CircleDashed size={18} className="text-purple-500" />;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTimeDisplay() {
|
||||||
|
const isActiveStatus =
|
||||||
|
execution.status === AgentExecutionStatus.RUNNING ||
|
||||||
|
execution.status === AgentExecutionStatus.QUEUED;
|
||||||
|
|
||||||
|
if (isActiveStatus) {
|
||||||
|
const timeAgo = formatTimeAgo(execution.started_at.toString());
|
||||||
|
const statusText =
|
||||||
|
execution.status === AgentExecutionStatus.QUEUED ? "queued" : "running";
|
||||||
|
return `Started ${timeAgo}, ${getExecutionDuration(execution)} ${statusText}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (execution.ended_at) {
|
||||||
|
const timeAgo = formatTimeAgo(execution.ended_at.toString());
|
||||||
|
switch (execution.status) {
|
||||||
|
case AgentExecutionStatus.COMPLETED:
|
||||||
|
return `Completed ${timeAgo}`;
|
||||||
|
case AgentExecutionStatus.FAILED:
|
||||||
|
return `Failed ${timeAgo}`;
|
||||||
|
case AgentExecutionStatus.TERMINATED:
|
||||||
|
return `Stopped ${timeAgo}`;
|
||||||
|
case AgentExecutionStatus.INCOMPLETE:
|
||||||
|
return `Incomplete ${timeAgo}`;
|
||||||
|
default:
|
||||||
|
return `Ended ${timeAgo}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="cursor-pointer border-b border-slate-50 px-2 py-3 transition-colors last:border-b-0 hover:bg-lightGrey"
|
||||||
|
onClick={() => {
|
||||||
|
const agentId = execution.library_agent_id || execution.graph_id;
|
||||||
|
router.push(`/library/agents/${agentId}?executionId=${execution.id}`);
|
||||||
|
}}
|
||||||
|
role="button"
|
||||||
|
>
|
||||||
|
{/* Icon + Agent Name */}
|
||||||
|
<div className="flex items-center space-x-3">
|
||||||
|
{getStatusIcon()}
|
||||||
|
<Text variant="body-medium" className="truncate text-gray-900">
|
||||||
|
{execution.agent_name}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Agent Message - Indented */}
|
||||||
|
<div className="ml-7 pt-1">
|
||||||
|
{/* Time - Indented */}
|
||||||
|
<Text variant="small" className="!text-zinc-500">
|
||||||
|
{getTimeDisplay()}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,373 @@
|
|||||||
|
import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus";
|
||||||
|
import { GraphExecutionMeta as GeneratedGraphExecutionMeta } from "@/app/api/__generated__/models/graphExecutionMeta";
|
||||||
|
import { MyAgent } from "@/app/api/__generated__/models/myAgent";
|
||||||
|
import type { GraphExecution } from "@/lib/autogpt-server-api/types";
|
||||||
|
|
||||||
|
// Time constants
|
||||||
|
const MILLISECONDS_PER_SECOND = 1000;
|
||||||
|
const SECONDS_PER_MINUTE = 60;
|
||||||
|
const MINUTES_PER_HOUR = 60;
|
||||||
|
const HOURS_PER_DAY = 24;
|
||||||
|
const MILLISECONDS_PER_MINUTE = SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND;
|
||||||
|
const MILLISECONDS_PER_HOUR = MINUTES_PER_HOUR * MILLISECONDS_PER_MINUTE;
|
||||||
|
const MILLISECONDS_PER_DAY = HOURS_PER_DAY * MILLISECONDS_PER_HOUR;
|
||||||
|
|
||||||
|
// Display constants
|
||||||
|
export const EXECUTION_DISPLAY_LIMIT = 6;
|
||||||
|
const SHORT_DURATION_THRESHOLD_SECONDS = 5;
|
||||||
|
|
||||||
|
export function formatTimeAgo(dateStr: string): string {
|
||||||
|
const date = new Date(dateStr);
|
||||||
|
const now = new Date();
|
||||||
|
const diffMs = now.getTime() - date.getTime();
|
||||||
|
const diffMins = Math.floor(diffMs / MILLISECONDS_PER_MINUTE);
|
||||||
|
|
||||||
|
if (diffMins < 1) return "just now";
|
||||||
|
if (diffMins < SECONDS_PER_MINUTE) return `${diffMins}m ago`;
|
||||||
|
const diffHours = Math.floor(diffMins / MINUTES_PER_HOUR);
|
||||||
|
if (diffHours < HOURS_PER_DAY) return `${diffHours}h ago`;
|
||||||
|
const diffDays = Math.floor(diffHours / HOURS_PER_DAY);
|
||||||
|
return `${diffDays}d ago`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStatusDisplayText(
|
||||||
|
execution: GeneratedGraphExecutionMeta,
|
||||||
|
): string {
|
||||||
|
switch (execution.status) {
|
||||||
|
case AgentExecutionStatus.QUEUED:
|
||||||
|
return "Queued";
|
||||||
|
case AgentExecutionStatus.RUNNING:
|
||||||
|
return "Running";
|
||||||
|
case AgentExecutionStatus.COMPLETED:
|
||||||
|
return "Completed";
|
||||||
|
case AgentExecutionStatus.FAILED:
|
||||||
|
return "Failed";
|
||||||
|
case AgentExecutionStatus.TERMINATED:
|
||||||
|
return "Stopped";
|
||||||
|
case AgentExecutionStatus.INCOMPLETE:
|
||||||
|
return "Incomplete";
|
||||||
|
default:
|
||||||
|
return execution.status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStatusColorClass(
|
||||||
|
execution: GeneratedGraphExecutionMeta,
|
||||||
|
): string {
|
||||||
|
switch (execution.status) {
|
||||||
|
case AgentExecutionStatus.QUEUED:
|
||||||
|
return "text-yellow-600";
|
||||||
|
case AgentExecutionStatus.RUNNING:
|
||||||
|
return "text-blue-600";
|
||||||
|
case AgentExecutionStatus.COMPLETED:
|
||||||
|
return "text-green-600";
|
||||||
|
case AgentExecutionStatus.FAILED:
|
||||||
|
case AgentExecutionStatus.TERMINATED:
|
||||||
|
return "text-red-600";
|
||||||
|
case AgentExecutionStatus.INCOMPLETE:
|
||||||
|
return "text-gray-600";
|
||||||
|
default:
|
||||||
|
return "text-gray-600";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function truncateGraphId(graphId: string, length: number = 8): string {
|
||||||
|
return `${graphId.slice(0, length)}...`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getExecutionDuration(
|
||||||
|
execution: GeneratedGraphExecutionMeta,
|
||||||
|
): string {
|
||||||
|
if (!execution.started_at) return "Unknown";
|
||||||
|
|
||||||
|
const start = new Date(execution.started_at);
|
||||||
|
const end = execution.ended_at ? new Date(execution.ended_at) : new Date();
|
||||||
|
|
||||||
|
// Check if dates are valid
|
||||||
|
if (isNaN(start.getTime()) || isNaN(end.getTime())) {
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
const durationMs = end.getTime() - start.getTime();
|
||||||
|
|
||||||
|
// Handle negative durations (shouldn't happen but just in case)
|
||||||
|
if (durationMs < 0) return "Unknown";
|
||||||
|
|
||||||
|
const durationSec = Math.floor(durationMs / MILLISECONDS_PER_SECOND);
|
||||||
|
|
||||||
|
// For short durations (< 5 seconds), show "a few seconds"
|
||||||
|
if (durationSec < SHORT_DURATION_THRESHOLD_SECONDS) {
|
||||||
|
return "a few seconds";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (durationSec < SECONDS_PER_MINUTE) return `${durationSec}s`;
|
||||||
|
const durationMin = Math.floor(durationSec / SECONDS_PER_MINUTE);
|
||||||
|
if (durationMin < MINUTES_PER_HOUR)
|
||||||
|
return `${durationMin}m ${durationSec % SECONDS_PER_MINUTE}s`;
|
||||||
|
const durationHr = Math.floor(durationMin / MINUTES_PER_HOUR);
|
||||||
|
return `${durationHr}h ${durationMin % MINUTES_PER_HOUR}m`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldShowNotificationBadge(totalCount: number): boolean {
|
||||||
|
return totalCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatNotificationCount(count: number): string {
|
||||||
|
if (count > 99) return "+99";
|
||||||
|
return count.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AgentExecutionWithInfo extends GeneratedGraphExecutionMeta {
|
||||||
|
agent_name: string;
|
||||||
|
agent_description: string;
|
||||||
|
library_agent_id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotificationState {
|
||||||
|
activeExecutions: AgentExecutionWithInfo[];
|
||||||
|
recentCompletions: AgentExecutionWithInfo[];
|
||||||
|
recentFailures: AgentExecutionWithInfo[];
|
||||||
|
totalCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createAgentInfoMap(
|
||||||
|
agents: MyAgent[],
|
||||||
|
): Map<
|
||||||
|
string,
|
||||||
|
{ name: string; description: string; library_agent_id?: string }
|
||||||
|
> {
|
||||||
|
const agentMap = new Map<
|
||||||
|
string,
|
||||||
|
{ name: string; description: string; library_agent_id?: string }
|
||||||
|
>();
|
||||||
|
|
||||||
|
agents.forEach((agent) => {
|
||||||
|
agentMap.set(agent.agent_id, {
|
||||||
|
name: agent.agent_name,
|
||||||
|
description: agent.description,
|
||||||
|
library_agent_id: undefined, // MyAgent doesn't have library_agent_id
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return agentMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertLegacyExecutionToGenerated(
|
||||||
|
execution: GraphExecution,
|
||||||
|
): GeneratedGraphExecutionMeta {
|
||||||
|
return {
|
||||||
|
id: execution.id,
|
||||||
|
user_id: execution.user_id,
|
||||||
|
graph_id: execution.graph_id,
|
||||||
|
graph_version: execution.graph_version,
|
||||||
|
preset_id: execution.preset_id,
|
||||||
|
status: execution.status as AgentExecutionStatus,
|
||||||
|
started_at: execution.started_at.toISOString(),
|
||||||
|
ended_at: execution.ended_at.toISOString(),
|
||||||
|
stats: execution.stats || {
|
||||||
|
cost: 0,
|
||||||
|
duration: 0,
|
||||||
|
duration_cpu_only: 0,
|
||||||
|
node_exec_time: 0,
|
||||||
|
node_exec_time_cpu_only: 0,
|
||||||
|
node_exec_count: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function enrichExecutionWithAgentInfo(
|
||||||
|
execution: GeneratedGraphExecutionMeta,
|
||||||
|
agentInfoMap: Map<
|
||||||
|
string,
|
||||||
|
{ name: string; description: string; library_agent_id?: string }
|
||||||
|
>,
|
||||||
|
): AgentExecutionWithInfo {
|
||||||
|
const agentInfo = agentInfoMap.get(execution.graph_id);
|
||||||
|
return {
|
||||||
|
...execution,
|
||||||
|
agent_name: agentInfo?.name || `Graph ${execution.graph_id.slice(0, 8)}...`,
|
||||||
|
agent_description: agentInfo?.description ?? "",
|
||||||
|
library_agent_id: agentInfo?.library_agent_id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isActiveExecution(
|
||||||
|
execution: GeneratedGraphExecutionMeta,
|
||||||
|
): boolean {
|
||||||
|
const status = execution.status;
|
||||||
|
return (
|
||||||
|
status === AgentExecutionStatus.RUNNING ||
|
||||||
|
status === AgentExecutionStatus.QUEUED
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isRecentCompletion(
|
||||||
|
execution: GeneratedGraphExecutionMeta,
|
||||||
|
thirtyMinutesAgo: Date,
|
||||||
|
): boolean {
|
||||||
|
const status = execution.status;
|
||||||
|
return (
|
||||||
|
status === AgentExecutionStatus.COMPLETED &&
|
||||||
|
!!execution.ended_at &&
|
||||||
|
new Date(execution.ended_at) > thirtyMinutesAgo
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isRecentFailure(
|
||||||
|
execution: GeneratedGraphExecutionMeta,
|
||||||
|
thirtyMinutesAgo: Date,
|
||||||
|
): boolean {
|
||||||
|
const status = execution.status;
|
||||||
|
return (
|
||||||
|
(status === AgentExecutionStatus.FAILED ||
|
||||||
|
status === AgentExecutionStatus.TERMINATED) &&
|
||||||
|
!!execution.ended_at &&
|
||||||
|
new Date(execution.ended_at) > thirtyMinutesAgo
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isRecentNotification(
|
||||||
|
execution: AgentExecutionWithInfo,
|
||||||
|
thirtyMinutesAgo: Date,
|
||||||
|
): boolean {
|
||||||
|
return execution.ended_at
|
||||||
|
? new Date(execution.ended_at) > thirtyMinutesAgo
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function categorizeExecutions(
|
||||||
|
executions: GeneratedGraphExecutionMeta[],
|
||||||
|
agentInfoMap: Map<
|
||||||
|
string,
|
||||||
|
{ name: string; description: string; library_agent_id?: string }
|
||||||
|
>,
|
||||||
|
): NotificationState {
|
||||||
|
const twentyFourHoursAgo = new Date(Date.now() - MILLISECONDS_PER_DAY);
|
||||||
|
|
||||||
|
const enrichedExecutions = executions.map((execution) =>
|
||||||
|
enrichExecutionWithAgentInfo(execution, agentInfoMap),
|
||||||
|
);
|
||||||
|
|
||||||
|
const activeExecutions = enrichedExecutions
|
||||||
|
.filter(isActiveExecution)
|
||||||
|
.slice(0, EXECUTION_DISPLAY_LIMIT);
|
||||||
|
|
||||||
|
const recentCompletions = enrichedExecutions
|
||||||
|
.filter((execution) => isRecentCompletion(execution, twentyFourHoursAgo))
|
||||||
|
.slice(0, EXECUTION_DISPLAY_LIMIT);
|
||||||
|
|
||||||
|
const recentFailures = enrichedExecutions
|
||||||
|
.filter((execution) => isRecentFailure(execution, twentyFourHoursAgo))
|
||||||
|
.slice(0, EXECUTION_DISPLAY_LIMIT);
|
||||||
|
|
||||||
|
return {
|
||||||
|
activeExecutions,
|
||||||
|
recentCompletions,
|
||||||
|
recentFailures,
|
||||||
|
totalCount:
|
||||||
|
activeExecutions.length +
|
||||||
|
recentCompletions.length +
|
||||||
|
recentFailures.length,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeExecutionFromAllCategories(
|
||||||
|
state: NotificationState,
|
||||||
|
executionId: string,
|
||||||
|
): NotificationState {
|
||||||
|
return {
|
||||||
|
activeExecutions: state.activeExecutions.filter(
|
||||||
|
(e) => e.id !== executionId,
|
||||||
|
),
|
||||||
|
recentCompletions: state.recentCompletions.filter(
|
||||||
|
(e) => e.id !== executionId,
|
||||||
|
),
|
||||||
|
recentFailures: state.recentFailures.filter((e) => e.id !== executionId),
|
||||||
|
totalCount: state.totalCount, // Will be recalculated later
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addExecutionToCategory(
|
||||||
|
state: NotificationState,
|
||||||
|
execution: AgentExecutionWithInfo,
|
||||||
|
): NotificationState {
|
||||||
|
const twentyFourHoursAgo = new Date(Date.now() - MILLISECONDS_PER_DAY);
|
||||||
|
const newState = { ...state };
|
||||||
|
|
||||||
|
if (isActiveExecution(execution)) {
|
||||||
|
newState.activeExecutions = [execution, ...newState.activeExecutions].slice(
|
||||||
|
0,
|
||||||
|
EXECUTION_DISPLAY_LIMIT,
|
||||||
|
);
|
||||||
|
} else if (isRecentCompletion(execution, twentyFourHoursAgo)) {
|
||||||
|
newState.recentCompletions = [
|
||||||
|
execution,
|
||||||
|
...newState.recentCompletions,
|
||||||
|
].slice(0, EXECUTION_DISPLAY_LIMIT);
|
||||||
|
} else if (isRecentFailure(execution, twentyFourHoursAgo)) {
|
||||||
|
newState.recentFailures = [execution, ...newState.recentFailures].slice(
|
||||||
|
0,
|
||||||
|
EXECUTION_DISPLAY_LIMIT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cleanupOldNotifications(
|
||||||
|
state: NotificationState,
|
||||||
|
): NotificationState {
|
||||||
|
const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
recentCompletions: state.recentCompletions.filter((e) =>
|
||||||
|
isRecentNotification(e, twentyFourHoursAgo),
|
||||||
|
),
|
||||||
|
recentFailures: state.recentFailures.filter((e) =>
|
||||||
|
isRecentNotification(e, twentyFourHoursAgo),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function calculateTotalCount(
|
||||||
|
state: NotificationState,
|
||||||
|
): NotificationState {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
totalCount:
|
||||||
|
state.activeExecutions.length +
|
||||||
|
state.recentCompletions.length +
|
||||||
|
state.recentFailures.length,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handleExecutionUpdate(
|
||||||
|
currentState: NotificationState,
|
||||||
|
execution: GraphExecution,
|
||||||
|
agentInfoMap: Map<
|
||||||
|
string,
|
||||||
|
{ name: string; description: string; library_agent_id?: string }
|
||||||
|
>,
|
||||||
|
): NotificationState {
|
||||||
|
// Convert and enrich the execution
|
||||||
|
const convertedExecution = convertLegacyExecutionToGenerated(execution);
|
||||||
|
const enrichedExecution = enrichExecutionWithAgentInfo(
|
||||||
|
convertedExecution,
|
||||||
|
agentInfoMap,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove from all categories first
|
||||||
|
let newState = removeExecutionFromAllCategories(currentState, execution.id);
|
||||||
|
|
||||||
|
// Add to appropriate category
|
||||||
|
newState = addExecutionToCategory(newState, enrichedExecution);
|
||||||
|
|
||||||
|
// Clean up old notifications
|
||||||
|
newState = cleanupOldNotifications(newState);
|
||||||
|
|
||||||
|
// Recalculate total count
|
||||||
|
newState = calculateTotalCount(newState);
|
||||||
|
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
import { useGetV1GetAllExecutions } from "@/app/api/__generated__/endpoints/graphs/graphs";
|
||||||
|
import { useGetV2GetMyAgents } from "@/app/api/__generated__/endpoints/store/store";
|
||||||
|
import { useGetV2ListLibraryAgents } from "@/app/api/__generated__/endpoints/library/library";
|
||||||
|
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
|
||||||
|
import BackendAPI from "@/lib/autogpt-server-api/client";
|
||||||
|
import type { GraphExecution } from "@/lib/autogpt-server-api/types";
|
||||||
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
NotificationState,
|
||||||
|
categorizeExecutions,
|
||||||
|
createAgentInfoMap,
|
||||||
|
handleExecutionUpdate,
|
||||||
|
} from "./helpers";
|
||||||
|
|
||||||
|
type AgentInfoMap = Map<
|
||||||
|
string,
|
||||||
|
{ name: string; description: string; library_agent_id?: string }
|
||||||
|
>;
|
||||||
|
|
||||||
|
export function useAgentActivityDropdown() {
|
||||||
|
const [api] = useState(() => new BackendAPI());
|
||||||
|
const [notifications, setNotifications] = useState<NotificationState>({
|
||||||
|
activeExecutions: [],
|
||||||
|
recentCompletions: [],
|
||||||
|
recentFailures: [],
|
||||||
|
totalCount: 0,
|
||||||
|
});
|
||||||
|
const [isConnected, setIsConnected] = useState(false);
|
||||||
|
const [agentInfoMap, setAgentInfoMap] = useState<AgentInfoMap>(new Map());
|
||||||
|
|
||||||
|
// Get library agents using generated hook
|
||||||
|
const {
|
||||||
|
data: myAgentsResponse,
|
||||||
|
isLoading: isAgentsLoading,
|
||||||
|
error: agentsError,
|
||||||
|
} = useGetV2GetMyAgents({
|
||||||
|
query: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get library agents data to map graph_id to library_agent_id
|
||||||
|
const {
|
||||||
|
data: libraryAgentsResponse,
|
||||||
|
isLoading: isLibraryAgentsLoading,
|
||||||
|
error: libraryAgentsError,
|
||||||
|
} = useGetV2ListLibraryAgents(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
query: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get all executions using generated hook
|
||||||
|
const {
|
||||||
|
data: executionsResponse,
|
||||||
|
isLoading: isExecutionsLoading,
|
||||||
|
error: executionsError,
|
||||||
|
} = useGetV1GetAllExecutions({
|
||||||
|
query: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update agent info map when both agent data sources change
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
myAgentsResponse?.data?.agents &&
|
||||||
|
libraryAgentsResponse?.data &&
|
||||||
|
"agents" in libraryAgentsResponse.data
|
||||||
|
) {
|
||||||
|
const agentMap = createAgentInfoMap(myAgentsResponse.data.agents);
|
||||||
|
|
||||||
|
// Add library agent ID mapping
|
||||||
|
libraryAgentsResponse.data.agents.forEach(
|
||||||
|
(libraryAgent: LibraryAgent) => {
|
||||||
|
const existingInfo = agentMap.get(libraryAgent.graph_id);
|
||||||
|
if (existingInfo) {
|
||||||
|
agentMap.set(libraryAgent.graph_id, {
|
||||||
|
...existingInfo,
|
||||||
|
library_agent_id: libraryAgent.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
setAgentInfoMap(agentMap);
|
||||||
|
}
|
||||||
|
}, [myAgentsResponse, libraryAgentsResponse]);
|
||||||
|
|
||||||
|
// Handle real-time execution updates
|
||||||
|
const handleExecutionEvent = useCallback(
|
||||||
|
(execution: GraphExecution) => {
|
||||||
|
setNotifications((currentState) =>
|
||||||
|
handleExecutionUpdate(currentState, execution, agentInfoMap),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[agentInfoMap],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Process initial execution state when data loads
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
executionsResponse?.data &&
|
||||||
|
!isExecutionsLoading &&
|
||||||
|
agentInfoMap.size > 0
|
||||||
|
) {
|
||||||
|
const newNotifications = categorizeExecutions(
|
||||||
|
executionsResponse.data,
|
||||||
|
agentInfoMap,
|
||||||
|
);
|
||||||
|
|
||||||
|
setNotifications(newNotifications);
|
||||||
|
}
|
||||||
|
}, [executionsResponse, isExecutionsLoading, agentInfoMap]);
|
||||||
|
|
||||||
|
// Initialize WebSocket connection for real-time updates
|
||||||
|
useEffect(() => {
|
||||||
|
const connectHandler = api.onWebSocketConnect(() => {
|
||||||
|
setIsConnected(true);
|
||||||
|
|
||||||
|
// Subscribe to graph executions for all user agents
|
||||||
|
if (myAgentsResponse?.data?.agents) {
|
||||||
|
myAgentsResponse.data.agents.forEach((agent) => {
|
||||||
|
api
|
||||||
|
.subscribeToGraphExecutions(agent.agent_id as any)
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(
|
||||||
|
`[AgentNotifications] Failed to subscribe to graph ${agent.agent_id}:`,
|
||||||
|
error,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const disconnectHandler = api.onWebSocketDisconnect(() => {
|
||||||
|
setIsConnected(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
const messageHandler = api.onWebSocketMessage(
|
||||||
|
"graph_execution_event",
|
||||||
|
handleExecutionEvent,
|
||||||
|
);
|
||||||
|
|
||||||
|
api.connectWebSocket();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
connectHandler();
|
||||||
|
disconnectHandler();
|
||||||
|
messageHandler();
|
||||||
|
api.disconnectWebSocket();
|
||||||
|
};
|
||||||
|
}, [api, handleExecutionEvent, myAgentsResponse]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...notifications,
|
||||||
|
isConnected,
|
||||||
|
isLoading: isAgentsLoading || isExecutionsLoading || isLibraryAgentsLoading,
|
||||||
|
error: agentsError || executionsError || libraryAgentsError,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { useGetV2GetUserProfile } from "@/app/api/__generated__/endpoints/store/store";
|
||||||
|
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||||
|
|
||||||
|
export function useNavbar() {
|
||||||
|
const { isLoggedIn, isUserLoading } = useSupabase();
|
||||||
|
|
||||||
|
console.log("isLoggedIn", isLoggedIn);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: profileResponse,
|
||||||
|
isLoading: isProfileLoading,
|
||||||
|
error: profileError,
|
||||||
|
} = useGetV2GetUserProfile({
|
||||||
|
query: {
|
||||||
|
enabled: isLoggedIn === true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const profile = profileResponse?.data || null;
|
||||||
|
const isLoading = isUserLoading || (isLoggedIn && isProfileLoading);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isLoggedIn,
|
||||||
|
profile,
|
||||||
|
isLoading,
|
||||||
|
profileError,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ const PopoverContent = React.forwardRef<
|
|||||||
align={align}
|
align={align}
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"z-50 w-72 rounded-md border border-neutral-200 bg-white p-4 text-neutral-950 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50",
|
"z-50 w-72 rounded-medium border border-neutral-200 bg-white p-4 text-neutral-950 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -34,8 +34,8 @@ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|||||||
|
|
||||||
export {
|
export {
|
||||||
Popover,
|
Popover,
|
||||||
PopoverTrigger,
|
|
||||||
PopoverContent,
|
|
||||||
PopoverAnchor,
|
PopoverAnchor,
|
||||||
|
PopoverContent,
|
||||||
PopoverPortal,
|
PopoverPortal,
|
||||||
|
PopoverTrigger,
|
||||||
};
|
};
|
||||||
|
|||||||
261
autogpt_platform/frontend/src/tests/agent-notifications.spec.ts
Normal file
261
autogpt_platform/frontend/src/tests/agent-notifications.spec.ts
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
import { test } from "./fixtures";
|
||||||
|
import { LibraryPage } from "./pages/library.page";
|
||||||
|
|
||||||
|
test.describe("Agent Notifications", () => {
|
||||||
|
let libraryPage: LibraryPage;
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page, loginPage, testUser }) => {
|
||||||
|
libraryPage = new LibraryPage(page);
|
||||||
|
|
||||||
|
// Start each test with login using worker auth
|
||||||
|
await page.goto("/login");
|
||||||
|
await loginPage.login(testUser.email, testUser.password);
|
||||||
|
await test.expect(page).toHaveURL("/marketplace");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("notification badge appears when agent is running", async ({ page }) => {
|
||||||
|
// Navigate to library
|
||||||
|
await libraryPage.navigateToLibrary();
|
||||||
|
await test.expect(page).toHaveURL(new RegExp("/library"));
|
||||||
|
|
||||||
|
// Click on first available agent
|
||||||
|
await libraryPage.clickFirstAgent();
|
||||||
|
await libraryPage.waitForAgentPageLoad();
|
||||||
|
|
||||||
|
// Verify we're on agent page
|
||||||
|
await test.expect(libraryPage.isLoaded()).resolves.toBeTruthy();
|
||||||
|
|
||||||
|
// Initially, no notification badge should be visible
|
||||||
|
await test
|
||||||
|
.expect(libraryPage.agentNotifications.isNotificationBadgeVisible())
|
||||||
|
.resolves.toBeFalsy();
|
||||||
|
|
||||||
|
// Run the agent
|
||||||
|
await libraryPage.runAgent();
|
||||||
|
|
||||||
|
// Wait for run to start and notification badge to appear
|
||||||
|
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||||
|
|
||||||
|
// Check that notification badge appears
|
||||||
|
await test
|
||||||
|
.expect(libraryPage.agentNotifications.isNotificationBadgeVisible())
|
||||||
|
.resolves.toBeTruthy();
|
||||||
|
|
||||||
|
// Check that notification count is at least 1
|
||||||
|
const notificationCount =
|
||||||
|
await libraryPage.agentNotifications.getNotificationCount();
|
||||||
|
test.expect(parseInt(notificationCount)).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("notification dropdown shows running agent with correct status", async ({
|
||||||
|
page: _page,
|
||||||
|
}) => {
|
||||||
|
// Navigate to library and run an agent
|
||||||
|
await libraryPage.navigateToLibrary();
|
||||||
|
await libraryPage.clickFirstAgent();
|
||||||
|
await libraryPage.waitForAgentPageLoad();
|
||||||
|
|
||||||
|
const agentName = await libraryPage.getAgentName();
|
||||||
|
|
||||||
|
// Run the agent
|
||||||
|
await libraryPage.runAgent();
|
||||||
|
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||||
|
|
||||||
|
// Click on notification button to open dropdown
|
||||||
|
await libraryPage.agentNotifications.clickNotificationButton();
|
||||||
|
|
||||||
|
// Verify dropdown is visible
|
||||||
|
await test
|
||||||
|
.expect(libraryPage.agentNotifications.isNotificationDropdownVisible())
|
||||||
|
.resolves.toBeTruthy();
|
||||||
|
|
||||||
|
// Check that running agent appears in dropdown
|
||||||
|
await test
|
||||||
|
.expect(
|
||||||
|
libraryPage.agentNotifications.hasNotificationWithStatus("running"),
|
||||||
|
)
|
||||||
|
.resolves.toBeTruthy();
|
||||||
|
|
||||||
|
// Check that the agent name appears in notifications
|
||||||
|
const notification =
|
||||||
|
await libraryPage.agentNotifications.getNotificationByAgentName(
|
||||||
|
agentName,
|
||||||
|
);
|
||||||
|
test.expect(notification).not.toBeNull();
|
||||||
|
test.expect(notification?.status).toBe("running");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("notification dropdown shows completed agent after run finishes", async ({
|
||||||
|
page: _page,
|
||||||
|
}, testInfo) => {
|
||||||
|
// Increase timeout for this test since we need to wait for completion
|
||||||
|
await test.setTimeout(testInfo.timeout * 3);
|
||||||
|
|
||||||
|
// Navigate to library and run an agent
|
||||||
|
await libraryPage.navigateToLibrary();
|
||||||
|
await libraryPage.clickFirstAgent();
|
||||||
|
await libraryPage.waitForAgentPageLoad();
|
||||||
|
|
||||||
|
const agentName = await libraryPage.getAgentName();
|
||||||
|
|
||||||
|
// Run the agent
|
||||||
|
await libraryPage.runAgent();
|
||||||
|
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||||
|
|
||||||
|
// Wait for agent to complete (with longer timeout)
|
||||||
|
await libraryPage.waitForRunToComplete(60000);
|
||||||
|
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||||
|
|
||||||
|
// Click on notification button to open dropdown
|
||||||
|
await libraryPage.agentNotifications.clickNotificationButton();
|
||||||
|
|
||||||
|
// Verify dropdown is visible
|
||||||
|
await test
|
||||||
|
.expect(libraryPage.agentNotifications.isNotificationDropdownVisible())
|
||||||
|
.resolves.toBeTruthy();
|
||||||
|
|
||||||
|
// Check that completed agent appears in dropdown
|
||||||
|
const notification =
|
||||||
|
await libraryPage.agentNotifications.getNotificationByAgentName(
|
||||||
|
agentName,
|
||||||
|
);
|
||||||
|
test.expect(notification).not.toBeNull();
|
||||||
|
test.expect(notification?.status).toMatch(/completed|failed|terminated/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("notification dropdown shows correct time information", async ({
|
||||||
|
page: _page,
|
||||||
|
}) => {
|
||||||
|
// Navigate to library and run an agent
|
||||||
|
await libraryPage.navigateToLibrary();
|
||||||
|
await libraryPage.clickFirstAgent();
|
||||||
|
await libraryPage.waitForAgentPageLoad();
|
||||||
|
|
||||||
|
const agentName = await libraryPage.getAgentName();
|
||||||
|
|
||||||
|
// Run the agent
|
||||||
|
await libraryPage.runAgent();
|
||||||
|
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||||
|
|
||||||
|
// Click on notification button to open dropdown
|
||||||
|
await libraryPage.agentNotifications.clickNotificationButton();
|
||||||
|
|
||||||
|
// Get notification for this agent
|
||||||
|
const notification =
|
||||||
|
await libraryPage.agentNotifications.getNotificationByAgentName(
|
||||||
|
agentName,
|
||||||
|
);
|
||||||
|
test.expect(notification).not.toBeNull();
|
||||||
|
|
||||||
|
// Check that time information is present and contains expected text
|
||||||
|
test.expect(notification?.time).toContain("Started");
|
||||||
|
test.expect(notification?.time).toMatch(/Started.*ago.*seconds/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("notification dropdown shows multiple agents when multiple are running", async ({
|
||||||
|
page: _page,
|
||||||
|
}) => {
|
||||||
|
// Navigate to library
|
||||||
|
await libraryPage.navigateToLibrary();
|
||||||
|
|
||||||
|
// Run first agent
|
||||||
|
await libraryPage.clickFirstAgent();
|
||||||
|
await libraryPage.waitForAgentPageLoad();
|
||||||
|
const firstAgentName = await libraryPage.getAgentName();
|
||||||
|
await libraryPage.runAgent();
|
||||||
|
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||||
|
|
||||||
|
// Go back to library and run another agent (if available)
|
||||||
|
await libraryPage.navigateToLibrary();
|
||||||
|
const agentCards = await libraryPage.agentCards.count();
|
||||||
|
|
||||||
|
if (agentCards > 1) {
|
||||||
|
await libraryPage.agentCards.nth(1).click();
|
||||||
|
await libraryPage.waitForAgentPageLoad();
|
||||||
|
const secondAgentName = await libraryPage.getAgentName();
|
||||||
|
await libraryPage.runAgent();
|
||||||
|
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||||
|
|
||||||
|
// Click on notification button to open dropdown
|
||||||
|
await libraryPage.agentNotifications.clickNotificationButton();
|
||||||
|
|
||||||
|
// Verify both agents appear in dropdown
|
||||||
|
const firstNotification =
|
||||||
|
await libraryPage.agentNotifications.getNotificationByAgentName(
|
||||||
|
firstAgentName,
|
||||||
|
);
|
||||||
|
const secondNotification =
|
||||||
|
await libraryPage.agentNotifications.getNotificationByAgentName(
|
||||||
|
secondAgentName,
|
||||||
|
);
|
||||||
|
|
||||||
|
test.expect(firstNotification).not.toBeNull();
|
||||||
|
test.expect(secondNotification).not.toBeNull();
|
||||||
|
|
||||||
|
// Check that notification count reflects multiple running agents
|
||||||
|
const notificationCount =
|
||||||
|
await libraryPage.agentNotifications.getNotificationCount();
|
||||||
|
test.expect(parseInt(notificationCount)).toBeGreaterThanOrEqual(2);
|
||||||
|
} else {
|
||||||
|
// Skip this part if only one agent is available
|
||||||
|
console.log("Only one agent available, skipping multiple agent test");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("notification dropdown closes when clicking outside", async ({
|
||||||
|
page,
|
||||||
|
}) => {
|
||||||
|
// Navigate to library and run an agent
|
||||||
|
await libraryPage.navigateToLibrary();
|
||||||
|
await libraryPage.clickFirstAgent();
|
||||||
|
await libraryPage.waitForAgentPageLoad();
|
||||||
|
|
||||||
|
// Run the agent
|
||||||
|
await libraryPage.runAgent();
|
||||||
|
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||||
|
|
||||||
|
// Click on notification button to open dropdown
|
||||||
|
await libraryPage.agentNotifications.clickNotificationButton();
|
||||||
|
|
||||||
|
// Verify dropdown is visible
|
||||||
|
await test
|
||||||
|
.expect(libraryPage.agentNotifications.isNotificationDropdownVisible())
|
||||||
|
.resolves.toBeTruthy();
|
||||||
|
|
||||||
|
// Click outside the dropdown
|
||||||
|
await page.click("body");
|
||||||
|
|
||||||
|
// Verify dropdown is no longer visible
|
||||||
|
await test
|
||||||
|
.expect(libraryPage.agentNotifications.isNotificationDropdownVisible())
|
||||||
|
.resolves.toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("notification badge count updates correctly", async ({
|
||||||
|
page: _page,
|
||||||
|
}) => {
|
||||||
|
// Navigate to library and run an agent
|
||||||
|
await libraryPage.navigateToLibrary();
|
||||||
|
await libraryPage.clickFirstAgent();
|
||||||
|
await libraryPage.waitForAgentPageLoad();
|
||||||
|
|
||||||
|
// Initially, no notification badge should be visible
|
||||||
|
await test
|
||||||
|
.expect(libraryPage.agentNotifications.isNotificationBadgeVisible())
|
||||||
|
.resolves.toBeFalsy();
|
||||||
|
|
||||||
|
// Run the agent
|
||||||
|
await libraryPage.runAgent();
|
||||||
|
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||||
|
|
||||||
|
// Check that notification count is 1
|
||||||
|
const notificationCount =
|
||||||
|
await libraryPage.agentNotifications.getNotificationCount();
|
||||||
|
test.expect(notificationCount).toBe("1");
|
||||||
|
|
||||||
|
// Check that badge is visible and animating
|
||||||
|
await test
|
||||||
|
.expect(libraryPage.agentNotifications.isNotificationBadgeVisible())
|
||||||
|
.resolves.toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
import { Locator, Page } from "@playwright/test";
|
||||||
|
|
||||||
|
export class AgentNotificationsPage {
|
||||||
|
constructor(private page: Page) {}
|
||||||
|
|
||||||
|
get notificationButton(): Locator {
|
||||||
|
return this.page.locator('button[title="Agent Activity"]');
|
||||||
|
}
|
||||||
|
|
||||||
|
get notificationBadge(): Locator {
|
||||||
|
return this.page
|
||||||
|
.locator('button[title="Agent Activity"] .animate-spin')
|
||||||
|
.first();
|
||||||
|
}
|
||||||
|
|
||||||
|
get notificationDropdown(): Locator {
|
||||||
|
return this.page.locator('[role="dialog"]:has-text("Agent Activity")');
|
||||||
|
}
|
||||||
|
|
||||||
|
get notificationItems(): Locator {
|
||||||
|
return this.notificationDropdown.locator('[role="button"]');
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickNotificationButton(): Promise<void> {
|
||||||
|
await this.notificationButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async isNotificationBadgeVisible(): Promise<boolean> {
|
||||||
|
return await this.notificationBadge.isVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
async isNotificationDropdownVisible(): Promise<boolean> {
|
||||||
|
return await this.notificationDropdown.isVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getNotificationCount(): Promise<string> {
|
||||||
|
const badge = this.page.locator(
|
||||||
|
'button[title="Agent Activity"] .bg-purple-600',
|
||||||
|
);
|
||||||
|
return (await badge.textContent()) || "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
async getNotificationItems(): Promise<
|
||||||
|
{ name: string; status: string; time: string }[]
|
||||||
|
> {
|
||||||
|
const items = await this.notificationItems.all();
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
const name = (await item.locator(".truncate").textContent()) || "";
|
||||||
|
const time =
|
||||||
|
(await item.locator(".\\!text-zinc-500").textContent()) || "";
|
||||||
|
|
||||||
|
// Determine status from icon classes and text content
|
||||||
|
let status = "unknown";
|
||||||
|
if (await item.locator(".animate-spin").isVisible()) {
|
||||||
|
status = "running";
|
||||||
|
} else if (await item.locator("svg").first().isVisible()) {
|
||||||
|
// For non-animated icons, check the text content to determine status
|
||||||
|
const timeText = time.toLowerCase();
|
||||||
|
if (timeText.includes("completed")) {
|
||||||
|
status = "completed";
|
||||||
|
} else if (timeText.includes("failed")) {
|
||||||
|
status = "failed";
|
||||||
|
} else if (timeText.includes("stopped")) {
|
||||||
|
status = "terminated";
|
||||||
|
} else if (timeText.includes("incomplete")) {
|
||||||
|
status = "incomplete";
|
||||||
|
} else if (timeText.includes("queued")) {
|
||||||
|
status = "queued";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
results.push({ name, status, time });
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitForNotificationUpdate(_timeout = 10000): Promise<void> {
|
||||||
|
await this.page.waitForTimeout(1000); // Wait for potential updates
|
||||||
|
}
|
||||||
|
|
||||||
|
async hasNotificationWithStatus(status: string): Promise<boolean> {
|
||||||
|
const items = await this.getNotificationItems();
|
||||||
|
return items.some((item) => item.status === status);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getNotificationByAgentName(
|
||||||
|
agentName: string,
|
||||||
|
): Promise<{ name: string; status: string; time: string } | null> {
|
||||||
|
const items = await this.getNotificationItems();
|
||||||
|
return items.find((item) => item.name.includes(agentName)) || null;
|
||||||
|
}
|
||||||
|
}
|
||||||
107
autogpt_platform/frontend/src/tests/pages/library.page.ts
Normal file
107
autogpt_platform/frontend/src/tests/pages/library.page.ts
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import { Locator, Page } from "@playwright/test";
|
||||||
|
import { AgentNotificationsPage } from "./agent-notifications.page";
|
||||||
|
|
||||||
|
export class LibraryPage {
|
||||||
|
public agentNotifications: AgentNotificationsPage;
|
||||||
|
|
||||||
|
constructor(private page: Page) {
|
||||||
|
this.agentNotifications = new AgentNotificationsPage(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
get libraryTab(): Locator {
|
||||||
|
return this.page.locator('a[href="/library"]');
|
||||||
|
}
|
||||||
|
|
||||||
|
get agentCards(): Locator {
|
||||||
|
return this.page.locator(".agpt-div").filter({ hasText: /^test-agent-/ });
|
||||||
|
}
|
||||||
|
|
||||||
|
get runButton(): Locator {
|
||||||
|
return this.page.locator('button:has-text("Run")');
|
||||||
|
}
|
||||||
|
|
||||||
|
get newRunButton(): Locator {
|
||||||
|
return this.page.locator('button:has-text("New run")');
|
||||||
|
}
|
||||||
|
|
||||||
|
get runDialogRunButton(): Locator {
|
||||||
|
return this.page.locator('button:has-text("Run"):last-child');
|
||||||
|
}
|
||||||
|
|
||||||
|
get agentTitle(): Locator {
|
||||||
|
return this.page.locator("h1").first();
|
||||||
|
}
|
||||||
|
|
||||||
|
async navigateToLibrary(): Promise<void> {
|
||||||
|
await this.libraryTab.click();
|
||||||
|
await this.page.waitForURL(/.*\/library/);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickFirstAgent(): Promise<void> {
|
||||||
|
const firstAgent = this.agentCards.first();
|
||||||
|
await firstAgent.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async navigateToAgentByName(agentName: string): Promise<void> {
|
||||||
|
const agentCard = this.agentCards.filter({ hasText: agentName }).first();
|
||||||
|
await agentCard.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickRunButton(): Promise<void> {
|
||||||
|
await this.runButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickNewRunButton(): Promise<void> {
|
||||||
|
await this.newRunButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async runAgent(inputs: Record<string, string> = {}): Promise<void> {
|
||||||
|
await this.clickRunButton();
|
||||||
|
|
||||||
|
// Fill in any required inputs
|
||||||
|
for (const [key, value] of Object.entries(inputs)) {
|
||||||
|
const input = this.page.locator(
|
||||||
|
`input[placeholder*="${key}"], textarea[placeholder*="${key}"]`,
|
||||||
|
);
|
||||||
|
if (await input.isVisible()) {
|
||||||
|
await input.fill(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click the run button in the dialog
|
||||||
|
await this.runDialogRunButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitForAgentPageLoad(): Promise<void> {
|
||||||
|
await this.page.waitForURL(/.*\/library\/agents\/[^/]+/);
|
||||||
|
await this.page.waitForLoadState("networkidle");
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAgentName(): Promise<string> {
|
||||||
|
return (await this.agentTitle.textContent()) || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
async isLoaded(): Promise<boolean> {
|
||||||
|
return await this.page.locator("h1").isVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitForRunToComplete(timeout = 30000): Promise<void> {
|
||||||
|
// Wait for completion badge or status change
|
||||||
|
await this.page.waitForSelector(
|
||||||
|
".bg-green-500, .bg-red-500, .bg-purple-500",
|
||||||
|
{ timeout },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRunStatus(): Promise<string> {
|
||||||
|
// Check for different status indicators
|
||||||
|
if (await this.page.locator(".animate-spin").isVisible()) {
|
||||||
|
return "running";
|
||||||
|
} else if (await this.page.locator(".bg-green-500").isVisible()) {
|
||||||
|
return "completed";
|
||||||
|
} else if (await this.page.locator(".bg-red-500").isVisible()) {
|
||||||
|
return "failed";
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user