mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-02-08 13:55:06 -05:00
Compare commits
7 Commits
fix/execut
...
kpczerwins
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ee23cc8cf | ||
|
|
887ef58fa1 | ||
|
|
fb773fbb83 | ||
|
|
266cac057b | ||
|
|
56affddad7 | ||
|
|
725b38425a | ||
|
|
250ffdfaed |
@@ -99,6 +99,65 @@ async def create_library_agent(
|
||||
) from e
|
||||
|
||||
|
||||
async def get_library_agent(
|
||||
store_listing_version_id: str, user_id: str
|
||||
) -> backend.data.graph.Graph | None:
|
||||
"""
|
||||
Get user agent from the store listing version
|
||||
"""
|
||||
logger.debug(
|
||||
f"Getting agent by store listing version {store_listing_version_id} for user {user_id}"
|
||||
)
|
||||
|
||||
try:
|
||||
# Get store listing version to find agent
|
||||
store_listing_version = (
|
||||
await prisma.models.StoreListingVersion.prisma().find_unique(
|
||||
where={"id": store_listing_version_id}, include={"Agent": True}
|
||||
)
|
||||
)
|
||||
|
||||
if not store_listing_version or not store_listing_version.Agent:
|
||||
logger.warning(
|
||||
f"Store listing version not found: {store_listing_version_id}"
|
||||
)
|
||||
raise backend.server.v2.store.exceptions.AgentNotFoundError(
|
||||
f"Store listing version {store_listing_version_id} not found"
|
||||
)
|
||||
|
||||
agent = store_listing_version.Agent
|
||||
|
||||
# Check if user already has this agent
|
||||
existing_user_agent = await prisma.models.AgentGraph.prisma().find_first(
|
||||
where={
|
||||
"userId": user_id,
|
||||
"id": agent.id,
|
||||
"version": agent.version,
|
||||
}
|
||||
)
|
||||
|
||||
if existing_user_agent:
|
||||
logger.debug(f"User {user_id} has agent {agent.id} in their library")
|
||||
return backend.data.graph.Graph(
|
||||
id=agent.id,
|
||||
version=agent.version,
|
||||
is_active=agent.isActive,
|
||||
name=agent.name or "",
|
||||
description=agent.description or "",
|
||||
)
|
||||
|
||||
logger.debug(f"User {user_id} does not have agent {agent.id} in their library")
|
||||
return None
|
||||
|
||||
except backend.server.v2.store.exceptions.AgentNotFoundError:
|
||||
raise
|
||||
except prisma.errors.PrismaError as e:
|
||||
logger.error(f"Database error checking library agent: {str(e)}")
|
||||
raise backend.server.v2.store.exceptions.DatabaseError(
|
||||
"Failed to check library agent"
|
||||
) from e
|
||||
|
||||
|
||||
async def update_agent_version_in_library(
|
||||
user_id: str, agent_id: str, agent_version: int
|
||||
) -> None:
|
||||
@@ -158,7 +217,7 @@ async def update_library_agent(
|
||||
|
||||
async def add_store_agent_to_library(
|
||||
store_listing_version_id: str, user_id: str
|
||||
) -> None:
|
||||
) -> backend.data.graph.Graph | None:
|
||||
"""
|
||||
Finds the agent from the store listing version and adds it to the user's library (LibraryAgent table)
|
||||
if they don't already have it
|
||||
@@ -206,10 +265,16 @@ async def add_store_agent_to_library(
|
||||
logger.debug(
|
||||
f"User {user_id} already has agent {agent.id} in their library"
|
||||
)
|
||||
return
|
||||
return backend.data.graph.Graph(
|
||||
id=agent.id,
|
||||
version=agent.version,
|
||||
is_active=agent.isActive,
|
||||
name=agent.name or "",
|
||||
description=agent.description or "",
|
||||
)
|
||||
|
||||
# Create LibraryAgent entry
|
||||
await prisma.models.LibraryAgent.prisma().create(
|
||||
library_agent = await prisma.models.LibraryAgent.prisma().create(
|
||||
data=prisma.types.LibraryAgentCreateInput(
|
||||
userId=user_id,
|
||||
agentId=agent.id,
|
||||
@@ -218,6 +283,13 @@ async def add_store_agent_to_library(
|
||||
)
|
||||
)
|
||||
logger.debug(f"Added agent {agent.id} to library for user {user_id}")
|
||||
return backend.data.graph.Graph(
|
||||
id=library_agent.agentId,
|
||||
version=library_agent.agentVersion,
|
||||
is_active=agent.isActive,
|
||||
name=agent.name or "",
|
||||
description=agent.description or "",
|
||||
)
|
||||
|
||||
except backend.server.v2.store.exceptions.AgentNotFoundError:
|
||||
raise
|
||||
|
||||
@@ -6,6 +6,8 @@ import autogpt_libs.auth.middleware
|
||||
import autogpt_libs.utils.cache
|
||||
import fastapi
|
||||
|
||||
import backend.data
|
||||
import backend.data.graph
|
||||
import backend.server.v2.library.db
|
||||
import backend.server.v2.library.model
|
||||
import backend.server.v2.store.exceptions
|
||||
@@ -38,6 +40,43 @@ async def get_library_agents(
|
||||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/agents/{store_listing_version_id}",
|
||||
tags=["library", "private"],
|
||||
dependencies=[fastapi.Depends(autogpt_libs.auth.middleware.auth_middleware)],
|
||||
)
|
||||
async def get_library_agent(
|
||||
store_listing_version_id: str,
|
||||
user_id: typing.Annotated[
|
||||
str, fastapi.Depends(autogpt_libs.auth.depends.get_user_id)
|
||||
],
|
||||
) -> backend.data.graph.Graph | None:
|
||||
"""
|
||||
Get an agent from the user's library by store listing version ID.
|
||||
|
||||
Args:
|
||||
store_listing_version_id (str): ID of the store listing version to get
|
||||
user_id (str): ID of the authenticated user
|
||||
|
||||
Returns:
|
||||
backend.data.graph.Graph: Agent from the user's library
|
||||
None: If the agent is not found in the user's library
|
||||
|
||||
Raises:
|
||||
HTTPException: If there is an error getting the agent from the library
|
||||
"""
|
||||
try:
|
||||
agent = await backend.server.v2.library.db.get_library_agent(
|
||||
store_listing_version_id, user_id
|
||||
)
|
||||
return agent
|
||||
except Exception:
|
||||
logger.exception("Exception occurred whilst getting library agent")
|
||||
raise fastapi.HTTPException(
|
||||
status_code=500, detail="Failed to get library agent"
|
||||
)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/agents/{store_listing_version_id}",
|
||||
tags=["library", "private"],
|
||||
@@ -49,7 +88,7 @@ async def add_agent_to_library(
|
||||
user_id: typing.Annotated[
|
||||
str, fastapi.Depends(autogpt_libs.auth.depends.get_user_id)
|
||||
],
|
||||
) -> fastapi.Response:
|
||||
) -> backend.data.graph.Graph | None:
|
||||
"""
|
||||
Add an agent from the store to the user's library.
|
||||
|
||||
@@ -58,17 +97,17 @@ async def add_agent_to_library(
|
||||
user_id (str): ID of the authenticated user
|
||||
|
||||
Returns:
|
||||
fastapi.Response: 201 status code on success
|
||||
backend.data.graph.Graph: Agent added to the user's library
|
||||
None: On failure
|
||||
|
||||
Raises:
|
||||
HTTPException: If there is an error adding the agent to the library
|
||||
"""
|
||||
try:
|
||||
# Use the database function to add the agent to the library
|
||||
await backend.server.v2.library.db.add_store_agent_to_library(
|
||||
return await backend.server.v2.library.db.add_store_agent_to_library(
|
||||
store_listing_version_id, user_id
|
||||
)
|
||||
return fastapi.Response(status_code=201)
|
||||
|
||||
except backend.server.v2.store.exceptions.AgentNotFoundError:
|
||||
raise fastapi.HTTPException(
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
import * as React from "react";
|
||||
import { IconPlay, StarRatingIcons } from "@/components/ui/icons";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import BackendAPI from "@/lib/autogpt-server-api";
|
||||
import BackendAPI, { GraphMeta } from "@/lib/autogpt-server-api";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
|
||||
import useSupabase from "@/hooks/useSupabase";
|
||||
import { DownloadIcon, LoaderIcon } from "lucide-react";
|
||||
import { DownloadIcon, LoaderIcon, CheckIcon } from "lucide-react";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
interface AgentInfoProps {
|
||||
name: string;
|
||||
creator: string;
|
||||
@@ -36,61 +37,88 @@ export const AgentInfo: React.FC<AgentInfoProps> = ({
|
||||
storeListingVersionId,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const api = React.useMemo(() => new BackendAPI(), []);
|
||||
const api = useBackendAPI();
|
||||
const { user } = useSupabase();
|
||||
const { toast } = useToast();
|
||||
const [userAgent, setUserAgent] = React.useState<GraphMeta | null>(null);
|
||||
// Either downloading or adding to library
|
||||
const [processing, setProcessing] = React.useState(false);
|
||||
|
||||
const [downloading, setDownloading] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
const fetchAgent = async () => {
|
||||
try {
|
||||
const agent = await api.getUserLibraryAgent(storeListingVersionId);
|
||||
setUserAgent(agent);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch library agent:", error);
|
||||
}
|
||||
};
|
||||
fetchAgent();
|
||||
}, [api, storeListingVersionId]);
|
||||
|
||||
const handleAddToLibrary = React.useCallback(async () => {
|
||||
if (!user || userAgent) {
|
||||
return;
|
||||
}
|
||||
|
||||
toast({
|
||||
title: "Adding to Library",
|
||||
description: "Adding agent to library and opening builder...",
|
||||
duration: 2000,
|
||||
});
|
||||
setProcessing(true);
|
||||
|
||||
const handleAddToLibrary = async () => {
|
||||
try {
|
||||
await api.addAgentToLibrary(storeListingVersionId);
|
||||
const agent = await api.addAgentToLibrary(storeListingVersionId);
|
||||
if (!agent) {
|
||||
throw new Error();
|
||||
}
|
||||
console.log("Agent added to library successfully");
|
||||
router.push("/monitoring");
|
||||
router.push(`/build?flowID=${agent.id}`);
|
||||
} catch (error) {
|
||||
console.error("Failed to add agent to library:", error);
|
||||
}
|
||||
};
|
||||
setProcessing(false);
|
||||
}, [api, router, storeListingVersionId, toast, user, userAgent]);
|
||||
|
||||
const handleDownloadToLibrary = async () => {
|
||||
const downloadAgent = async (): Promise<void> => {
|
||||
setDownloading(true);
|
||||
try {
|
||||
const file = await api.downloadStoreAgent(storeListingVersionId);
|
||||
const handleDownloadToLibrary = React.useCallback(async () => {
|
||||
setProcessing(true);
|
||||
try {
|
||||
const file = await api.downloadStoreAgent(storeListingVersionId);
|
||||
|
||||
// Similar to Marketplace v1
|
||||
const jsonData = JSON.stringify(file, null, 2);
|
||||
// Create a Blob from the file content
|
||||
const blob = new Blob([jsonData], { type: "application/json" });
|
||||
// Similar to Marketplace v1
|
||||
const jsonData = JSON.stringify(file, null, 2);
|
||||
// Create a Blob from the file content
|
||||
const blob = new Blob([jsonData], { type: "application/json" });
|
||||
|
||||
// Create a temporary URL for the Blob
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
// Create a temporary URL for the Blob
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
|
||||
// Create a temporary anchor element
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = `agent_${storeListingVersionId}.json`; // Set the filename
|
||||
// Create a temporary anchor element
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = `agent_${storeListingVersionId}.json`; // Set the filename
|
||||
|
||||
// Append the anchor to the body, click it, and remove it
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
// Append the anchor to the body, click it, and remove it
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
|
||||
// Revoke the temporary URL
|
||||
window.URL.revokeObjectURL(url);
|
||||
// Revoke the temporary URL
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
toast({
|
||||
title: "Download Complete",
|
||||
description: "Your agent has been successfully downloaded.",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Error downloading agent:`, error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
await downloadAgent();
|
||||
setDownloading(false);
|
||||
};
|
||||
toast({
|
||||
title: "Download Complete",
|
||||
description: "Your agent has been successfully downloaded.",
|
||||
duration: 2000,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Error downloading agent:`, error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
setProcessing(false);
|
||||
}, [api, storeListingVersionId, toast]);
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-[396px] px-4 sm:px-6 lg:w-[396px] lg:px-0">
|
||||
@@ -123,29 +151,40 @@ export const AgentInfo: React.FC<AgentInfoProps> = ({
|
||||
<button
|
||||
onClick={handleAddToLibrary}
|
||||
className="inline-flex w-full items-center justify-center gap-2 rounded-[38px] bg-violet-600 px-4 py-3 transition-colors hover:bg-violet-700 sm:w-auto sm:gap-2.5 sm:px-5 sm:py-3.5 lg:px-6 lg:py-4"
|
||||
disabled={processing || userAgent !== null}
|
||||
>
|
||||
<IconPlay className="h-5 w-5 text-white sm:h-5 sm:w-5 lg:h-6 lg:w-6" />
|
||||
{processing ? (
|
||||
<LoaderIcon className="h-5 w-5 animate-spin text-white sm:h-5 sm:w-5 lg:h-6 lg:w-6" />
|
||||
) : userAgent ? (
|
||||
<CheckIcon className="h-5 w-5 text-white sm:h-5 sm:w-5 lg:h-6 lg:w-6" />
|
||||
) : (
|
||||
<IconPlay className="h-5 w-5 text-white sm:h-5 sm:w-5 lg:h-6 lg:w-6" />
|
||||
)}
|
||||
<span className="font-poppins text-base font-medium text-neutral-50 sm:text-lg">
|
||||
Add To Library
|
||||
{processing
|
||||
? "Adding to Library..."
|
||||
: userAgent
|
||||
? "Already in Library"
|
||||
: "Add Agent to Library"}
|
||||
</span>
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={handleDownloadToLibrary}
|
||||
className={`inline-flex w-full items-center justify-center gap-2 rounded-[38px] px-4 py-3 transition-colors sm:w-auto sm:gap-2.5 sm:px-5 sm:py-3.5 lg:px-6 lg:py-4 ${
|
||||
downloading
|
||||
processing
|
||||
? "bg-neutral-400"
|
||||
: "bg-violet-600 hover:bg-violet-700"
|
||||
}`}
|
||||
disabled={downloading}
|
||||
disabled={processing}
|
||||
>
|
||||
{downloading ? (
|
||||
{processing ? (
|
||||
<LoaderIcon className="h-5 w-5 animate-spin text-white sm:h-5 sm:w-5 lg:h-6 lg:w-6" />
|
||||
) : (
|
||||
<DownloadIcon className="h-5 w-5 text-white sm:h-5 sm:w-5 lg:h-6 lg:w-6" />
|
||||
)}
|
||||
<span className="font-poppins text-base font-medium text-neutral-50 sm:text-lg">
|
||||
{downloading ? "Downloading..." : "Download Agent as File"}
|
||||
{processing ? "Downloading..." : "Download Agent as File"}
|
||||
</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
// "use client";
|
||||
// import Link from "next/link";
|
||||
// import { ArrowLeft, Download, Calendar, Tag } from "lucide-react";
|
||||
// import { Button } from "@/components/ui/button";
|
||||
// import BackendAPI, { GraphCreatable } from "@/lib/autogpt-server-api";
|
||||
// import "@xyflow/react/dist/style.css";
|
||||
// import { useToast } from "../ui/use-toast";
|
||||
|
||||
// function AgentDetailContent({ agent }: { agent: GraphCreatable }) {
|
||||
// const { toast } = useToast();
|
||||
|
||||
// // const downloadAgent = async (id: string): Promise<void> => {
|
||||
// // const api = new MarketplaceAPI();
|
||||
// // try {
|
||||
// // const file = await api.downloadAgentFile(id);
|
||||
// // console.debug(`Agent file downloaded:`, file);
|
||||
|
||||
// // // Create a Blob from the file content
|
||||
// // const blob = new Blob([file], { type: "application/json" });
|
||||
|
||||
// // // Create a temporary URL for the Blob
|
||||
// // const url = window.URL.createObjectURL(blob);
|
||||
|
||||
// // // Create a temporary anchor element
|
||||
// // const a = document.createElement("a");
|
||||
// // a.href = url;
|
||||
// // a.download = `agent_${id}.json`; // Set the filename
|
||||
|
||||
// // // Append the anchor to the body, click it, and remove it
|
||||
// // document.body.appendChild(a);
|
||||
// // a.click();
|
||||
// // document.body.removeChild(a);
|
||||
|
||||
// // // Revoke the temporary URL
|
||||
// // window.URL.revokeObjectURL(url);
|
||||
// // } catch (error) {
|
||||
// // console.error(`Error downloading agent:`, error);
|
||||
// // throw error;
|
||||
// // }
|
||||
// // };
|
||||
|
||||
// return (
|
||||
// <div className="mx-auto max-w-7xl px-4 py-4 sm:px-6 lg:px-8">
|
||||
// <div className="mb-4 flex items-center justify-between">
|
||||
// <Link
|
||||
// href="/marketplace"
|
||||
// className="inline-flex items-center text-indigo-600 hover:text-indigo-500"
|
||||
// >
|
||||
// <ArrowLeft className="mr-2" size={20} />
|
||||
// Back to Marketplace
|
||||
// </Link>
|
||||
// <div className="flex space-x-4">
|
||||
// <Button
|
||||
// onClick={() => downloadAgent(agent.id)}
|
||||
// className="inline-flex items-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
|
||||
// >
|
||||
// <Download className="mr-2" size={16} />
|
||||
// Download Agent
|
||||
// </Button>
|
||||
// </div>
|
||||
// </div>
|
||||
// <div className="overflow-hidden bg-white shadow sm:rounded-lg">
|
||||
// <div className="px-4 py-5 sm:px-6">
|
||||
// <h1 className="text-3xl font-bold text-gray-900">{agent.name}</h1>
|
||||
// <p className="mt-1 max-w-2xl text-sm text-gray-500">
|
||||
// {agent.description}
|
||||
// </p>
|
||||
// </div>
|
||||
// <div className="border-t border-gray-300 px-4 py-5 sm:p-0">
|
||||
// <dl className="sm:divide-y sm:divide-gray-200">
|
||||
// <div className="py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
||||
// <dt className="flex items-center text-sm font-medium text-gray-500">
|
||||
// <Calendar className="mr-2" size={16} />
|
||||
// Last Updated
|
||||
// </dt>
|
||||
// <dd className="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
// {new Date(agent.updatedAt).toLocaleDateString()}
|
||||
// </dd>
|
||||
// </div>
|
||||
// <div className="py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
||||
// <dt className="flex items-center text-sm font-medium text-gray-500">
|
||||
// <Tag className="mr-2" size={16} />
|
||||
// Categories
|
||||
// </dt>
|
||||
// <dd className="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
|
||||
// {agent.categories.join(", ")}
|
||||
// </dd>
|
||||
// </div>
|
||||
// </dl>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
|
||||
// export default AgentDetailContent;
|
||||
@@ -1,18 +0,0 @@
|
||||
// "use server";
|
||||
|
||||
// import * as Sentry from "@sentry/nextjs";
|
||||
// import MarketplaceAPI, { AnalyticsEvent } from "@/lib/marketplace-api";
|
||||
// import { checkAuth } from "@/lib/supabase/server";
|
||||
|
||||
// export async function makeAnalyticsEvent(event: AnalyticsEvent) {
|
||||
// return await Sentry.withServerActionInstrumentation(
|
||||
// "makeAnalyticsEvent",
|
||||
// {},
|
||||
// async () => {
|
||||
// await checkAuth();
|
||||
// const apiUrl = process.env.AGPT_SERVER_API_URL;
|
||||
// const api = new MarketplaceAPI();
|
||||
// await api.makeAnalyticsEvent(event);
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
@@ -400,8 +400,19 @@ export default class BackendAPI {
|
||||
return this._get("/library/agents");
|
||||
}
|
||||
|
||||
async addAgentToLibrary(storeListingVersionId: string): Promise<void> {
|
||||
await this._request("POST", `/library/agents/${storeListingVersionId}`);
|
||||
getUserLibraryAgent(
|
||||
storeListingVersionId: string,
|
||||
): Promise<GraphMeta | null> {
|
||||
return this._get(`/library/agents/${storeListingVersionId}`);
|
||||
}
|
||||
|
||||
async addAgentToLibrary(
|
||||
storeListingVersionId: string,
|
||||
): Promise<GraphMeta | null> {
|
||||
return await this._request(
|
||||
"POST",
|
||||
`/library/agents/${storeListingVersionId}`,
|
||||
);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user