mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-30 03:00:41 -04:00
Merge branch 'dev' into lluisagusti/secrt-1329-storybook-ci-review-deploy-adjustments
This commit is contained in:
@@ -279,6 +279,7 @@ class AgentServer(backend.util.service.AppProcess):
|
||||
|
||||
@staticmethod
|
||||
async def test_delete_graph(graph_id: str, user_id: str):
|
||||
"""Used for clean-up after a test run"""
|
||||
await backend.server.v2.library.db.delete_library_agent_by_graph_id(
|
||||
graph_id=graph_id, user_id=user_id
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
from typing import Literal, Optional
|
||||
|
||||
import fastapi
|
||||
import prisma.errors
|
||||
@@ -122,7 +122,7 @@ async def list_library_agents(
|
||||
except Exception as e:
|
||||
# Skip this agent if there was an error
|
||||
logger.error(
|
||||
f"Error parsing LibraryAgent when getting library agents from db: {e}"
|
||||
f"Error parsing LibraryAgent #{agent.id} from DB item: {e}"
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -168,7 +168,7 @@ async def get_library_agent(id: str, user_id: str) -> library_model.LibraryAgent
|
||||
)
|
||||
|
||||
if not library_agent:
|
||||
raise store_exceptions.AgentNotFoundError(f"Library agent #{id} not found")
|
||||
raise NotFoundError(f"Library agent #{id} not found")
|
||||
|
||||
return library_model.LibraryAgent.from_db(library_agent)
|
||||
|
||||
@@ -346,8 +346,8 @@ async def update_library_agent(
|
||||
auto_update_version: Optional[bool] = None,
|
||||
is_favorite: Optional[bool] = None,
|
||||
is_archived: Optional[bool] = None,
|
||||
is_deleted: Optional[bool] = None,
|
||||
) -> None:
|
||||
is_deleted: Optional[Literal[False]] = None,
|
||||
) -> library_model.LibraryAgent:
|
||||
"""
|
||||
Updates the specified LibraryAgent record.
|
||||
|
||||
@@ -357,15 +357,18 @@ async def update_library_agent(
|
||||
auto_update_version: Whether the agent should auto-update to active version.
|
||||
is_favorite: Whether this agent is marked as a favorite.
|
||||
is_archived: Whether this agent is archived.
|
||||
is_deleted: Whether this agent is deleted.
|
||||
|
||||
Returns:
|
||||
The updated LibraryAgent.
|
||||
|
||||
Raises:
|
||||
NotFoundError: If the specified LibraryAgent does not exist.
|
||||
DatabaseError: If there's an error in the update operation.
|
||||
"""
|
||||
logger.debug(
|
||||
f"Updating library agent {library_agent_id} for user {user_id} with "
|
||||
f"auto_update_version={auto_update_version}, is_favorite={is_favorite}, "
|
||||
f"is_archived={is_archived}, is_deleted={is_deleted}"
|
||||
f"is_archived={is_archived}"
|
||||
)
|
||||
update_fields: prisma.types.LibraryAgentUpdateManyMutationInput = {}
|
||||
if auto_update_version is not None:
|
||||
@@ -375,17 +378,46 @@ async def update_library_agent(
|
||||
if is_archived is not None:
|
||||
update_fields["isArchived"] = is_archived
|
||||
if is_deleted is not None:
|
||||
if is_deleted is True:
|
||||
raise RuntimeError(
|
||||
"Use delete_library_agent() to (soft-)delete library agents"
|
||||
)
|
||||
update_fields["isDeleted"] = is_deleted
|
||||
if not update_fields:
|
||||
raise ValueError("No values were passed to update")
|
||||
|
||||
try:
|
||||
await prisma.models.LibraryAgent.prisma().update_many(
|
||||
where={"id": library_agent_id, "userId": user_id}, data=update_fields
|
||||
n_updated = await prisma.models.LibraryAgent.prisma().update_many(
|
||||
where={"id": library_agent_id, "userId": user_id},
|
||||
data=update_fields,
|
||||
)
|
||||
if n_updated < 1:
|
||||
raise NotFoundError(f"Library agent {library_agent_id} not found")
|
||||
|
||||
return await get_library_agent(
|
||||
id=library_agent_id,
|
||||
user_id=user_id,
|
||||
)
|
||||
except prisma.errors.PrismaError as e:
|
||||
logger.error(f"Database error updating library agent: {str(e)}")
|
||||
raise store_exceptions.DatabaseError("Failed to update library agent") from e
|
||||
|
||||
|
||||
async def delete_library_agent(
|
||||
library_agent_id: str, user_id: str, soft_delete: bool = True
|
||||
) -> None:
|
||||
if soft_delete:
|
||||
deleted_count = await prisma.models.LibraryAgent.prisma().update_many(
|
||||
where={"id": library_agent_id, "userId": user_id}, data={"isDeleted": True}
|
||||
)
|
||||
else:
|
||||
deleted_count = await prisma.models.LibraryAgent.prisma().delete_many(
|
||||
where={"id": library_agent_id, "userId": user_id}
|
||||
)
|
||||
if deleted_count < 1:
|
||||
raise NotFoundError(f"Library agent #{library_agent_id} not found")
|
||||
|
||||
|
||||
async def delete_library_agent_by_graph_id(graph_id: str, user_id: str) -> None:
|
||||
"""
|
||||
Deletes a library agent for the given user
|
||||
|
||||
@@ -333,6 +333,3 @@ class LibraryAgentUpdateRequest(pydantic.BaseModel):
|
||||
is_archived: Optional[bool] = pydantic.Field(
|
||||
default=None, description="Archive the agent"
|
||||
)
|
||||
is_deleted: Optional[bool] = pydantic.Field(
|
||||
default=None, description="Delete the agent"
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@ from typing import Any, Optional
|
||||
|
||||
import autogpt_libs.auth as autogpt_auth_lib
|
||||
from fastapi import APIRouter, Body, Depends, HTTPException, Path, Query, status
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.responses import Response
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
import backend.server.v2.library.db as library_db
|
||||
@@ -179,12 +179,11 @@ async def add_marketplace_agent_to_library(
|
||||
) from e
|
||||
|
||||
|
||||
@router.put(
|
||||
@router.patch(
|
||||
"/{library_agent_id}",
|
||||
summary="Update Library Agent",
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
responses={
|
||||
204: {"description": "Agent updated successfully"},
|
||||
200: {"description": "Agent updated successfully"},
|
||||
500: {"description": "Server error"},
|
||||
},
|
||||
)
|
||||
@@ -192,7 +191,7 @@ async def update_library_agent(
|
||||
library_agent_id: str,
|
||||
payload: library_model.LibraryAgentUpdateRequest,
|
||||
user_id: str = Depends(autogpt_auth_lib.depends.get_user_id),
|
||||
) -> JSONResponse:
|
||||
) -> library_model.LibraryAgent:
|
||||
"""
|
||||
Update the library agent with the given fields.
|
||||
|
||||
@@ -201,25 +200,22 @@ async def update_library_agent(
|
||||
payload: Fields to update (auto_update_version, is_favorite, etc.).
|
||||
user_id: ID of the authenticated user.
|
||||
|
||||
Returns:
|
||||
204 (No Content) on success.
|
||||
|
||||
Raises:
|
||||
HTTPException(500): If a server/database error occurs.
|
||||
"""
|
||||
try:
|
||||
await library_db.update_library_agent(
|
||||
return await library_db.update_library_agent(
|
||||
library_agent_id=library_agent_id,
|
||||
user_id=user_id,
|
||||
auto_update_version=payload.auto_update_version,
|
||||
is_favorite=payload.is_favorite,
|
||||
is_archived=payload.is_archived,
|
||||
is_deleted=payload.is_deleted,
|
||||
)
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_204_NO_CONTENT,
|
||||
content={"message": "Agent updated successfully"},
|
||||
)
|
||||
except NotFoundError as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=str(e),
|
||||
) from e
|
||||
except store_exceptions.DatabaseError as e:
|
||||
logger.error(f"Database error while updating library agent: {e}")
|
||||
raise HTTPException(
|
||||
@@ -234,6 +230,45 @@ async def update_library_agent(
|
||||
) from e
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/{library_agent_id}",
|
||||
summary="Delete Library Agent",
|
||||
responses={
|
||||
204: {"description": "Agent deleted successfully"},
|
||||
404: {"description": "Agent not found"},
|
||||
500: {"description": "Server error"},
|
||||
},
|
||||
)
|
||||
async def delete_library_agent(
|
||||
library_agent_id: str,
|
||||
user_id: str = Depends(autogpt_auth_lib.depends.get_user_id),
|
||||
) -> Response:
|
||||
"""
|
||||
Soft-delete the specified library agent.
|
||||
|
||||
Args:
|
||||
library_agent_id: ID of the library agent to delete.
|
||||
user_id: ID of the authenticated user.
|
||||
|
||||
Returns:
|
||||
204 No Content if successful.
|
||||
|
||||
Raises:
|
||||
HTTPException(404): If the agent does not exist.
|
||||
HTTPException(500): If a server/database error occurs.
|
||||
"""
|
||||
try:
|
||||
await library_db.delete_library_agent(
|
||||
library_agent_id=library_agent_id, user_id=user_id
|
||||
)
|
||||
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
||||
except NotFoundError as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=str(e),
|
||||
) from e
|
||||
|
||||
|
||||
@router.post("/{library_agent_id}/fork", summary="Fork Library Agent")
|
||||
async def fork_library_agent(
|
||||
library_agent_id: str,
|
||||
|
||||
@@ -152,9 +152,16 @@ async def main():
|
||||
print(f"Inserting {NUM_USERS * MAX_AGENTS_PER_USER} user agents")
|
||||
for user in users:
|
||||
num_agents = random.randint(MIN_AGENTS_PER_USER, MAX_AGENTS_PER_USER)
|
||||
for _ in range(num_agents): # Create 1 LibraryAgent per user
|
||||
graph = random.choice(agent_graphs)
|
||||
preset = random.choice(agent_presets)
|
||||
|
||||
# Get a shuffled list of graphs to ensure uniqueness per user
|
||||
available_graphs = agent_graphs.copy()
|
||||
random.shuffle(available_graphs)
|
||||
|
||||
# Limit to available unique graphs
|
||||
num_agents = min(num_agents, len(available_graphs))
|
||||
|
||||
for i in range(num_agents):
|
||||
graph = available_graphs[i] # Use unique graph for each library agent
|
||||
user_agent = await db.libraryagent.create(
|
||||
data={
|
||||
"userId": user.id,
|
||||
@@ -180,7 +187,7 @@ async def main():
|
||||
MIN_EXECUTIONS_PER_GRAPH, MAX_EXECUTIONS_PER_GRAPH
|
||||
)
|
||||
for _ in range(num_executions):
|
||||
matching_presets = [p for p in agent_presets if p.agentId == graph.id]
|
||||
matching_presets = [p for p in agent_presets if p.agentGraphId == graph.id]
|
||||
preset = (
|
||||
random.choice(matching_presets)
|
||||
if matching_presets and random.random() < 0.5
|
||||
@@ -355,7 +362,7 @@ async def main():
|
||||
store_listing_versions = []
|
||||
print(f"Inserting {NUM_USERS} store listing versions")
|
||||
for listing in store_listings:
|
||||
graph = [g for g in agent_graphs if g.id == listing.agentId][0]
|
||||
graph = [g for g in agent_graphs if g.id == listing.agentGraphId][0]
|
||||
version = await db.storelistingversion.create(
|
||||
data={
|
||||
"agentGraphId": graph.id,
|
||||
|
||||
@@ -518,9 +518,7 @@ export default function AgentRunsPage(): React.ReactElement {
|
||||
onOpenChange={setAgentDeleteDialogOpen}
|
||||
onDoDelete={() =>
|
||||
agent &&
|
||||
api
|
||||
.updateLibraryAgent(agent.id, { is_deleted: true })
|
||||
.then(() => router.push("/library"))
|
||||
api.deleteLibraryAgent(agent.id).then(() => router.push("/library"))
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@@ -271,12 +271,10 @@ export const FlowInfo: React.FC<
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() => {
|
||||
api
|
||||
.updateLibraryAgent(flow.id, { is_deleted: true })
|
||||
.then(() => {
|
||||
setIsDeleteModalOpen(false);
|
||||
refresh();
|
||||
});
|
||||
api.deleteLibraryAgent(flow.id).then(() => {
|
||||
setIsDeleteModalOpen(false);
|
||||
refresh();
|
||||
});
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
|
||||
@@ -630,16 +630,19 @@ export default class BackendAPI {
|
||||
});
|
||||
}
|
||||
|
||||
async updateLibraryAgent(
|
||||
updateLibraryAgent(
|
||||
libraryAgentId: LibraryAgentID,
|
||||
params: {
|
||||
auto_update_version?: boolean;
|
||||
is_favorite?: boolean;
|
||||
is_archived?: boolean;
|
||||
is_deleted?: boolean;
|
||||
},
|
||||
): Promise<void> {
|
||||
await this._request("PUT", `/library/agents/${libraryAgentId}`, params);
|
||||
): Promise<LibraryAgent> {
|
||||
return this._request("PATCH", `/library/agents/${libraryAgentId}`, params);
|
||||
}
|
||||
|
||||
async deleteLibraryAgent(libraryAgentId: LibraryAgentID): Promise<void> {
|
||||
await this._request("DELETE", `/library/agents/${libraryAgentId}`);
|
||||
}
|
||||
|
||||
forkLibraryAgent(libraryAgentId: LibraryAgentID): Promise<LibraryAgent> {
|
||||
|
||||
@@ -3,6 +3,13 @@
|
||||
import BackendAPI from "./client";
|
||||
import React, { createContext, useMemo } from "react";
|
||||
|
||||
// Add window.api type declaration for global access
|
||||
declare global {
|
||||
interface Window {
|
||||
api?: BackendAPI;
|
||||
}
|
||||
}
|
||||
|
||||
const BackendAPIProviderContext = createContext<BackendAPI | null>(null);
|
||||
|
||||
export function BackendAPIProvider({
|
||||
@@ -12,6 +19,13 @@ export function BackendAPIProvider({
|
||||
}): React.ReactNode {
|
||||
const api = useMemo(() => new BackendAPI(), []);
|
||||
|
||||
if (
|
||||
process.env.NEXT_PUBLIC_BEHAVE_AS == "LOCAL" &&
|
||||
typeof window !== "undefined"
|
||||
) {
|
||||
window.api = api; // Expose the API globally for debugging purposes
|
||||
}
|
||||
|
||||
return (
|
||||
<BackendAPIProviderContext.Provider value={api}>
|
||||
{children}
|
||||
|
||||
Reference in New Issue
Block a user