mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-09 15:17:59 -05:00
* Added listing, sorting, filtering and ordering of agents * feat(market): general upkeep for vscode and small docs * feat(market): most of search * fix(market): hinting on the sort was weird + linting * feat(market): migrations and schema updates * lint(market): autolint * feat(market): better search * feat(market): file download * feat(market): analytics of downloads * Added tracking of views * changed all imports to be fully qualified * Upgrade sentry sdk * Added an admin endpoint to submit new agents * fixes * Added endpoint that just tracks download * Starting adding the marketplace page * Marketplace client * Create template of the marketplace page * Updated client * fix(market): debug port * feat(market): agents by downloads * fix(market, builder): hook up frontend and backend * feat(builder, market): build a "better" market page that loads data * feat(builder): updated search (working) and page (kinda working) * feat(builder): add a feature agents ui (not backed yet) * feat(builder): improve detail page content * Added run script * Added pre populate database command * Add AnalyticsTracker on create agent * Add download counts for top agents * Add hb page prometheus metrics * Added featured agents funcitonality * renamed endpoint to health * Adding download flow * normalised api routes * update readme * feat(market) : default featured * formatting * revert changes to autogpt and forge * Updated Readme * Eerror when creating an agent from a template installed from (#7697) fix creating graph from template * Add dockerfile * z level fix * Updated env vars * updated populate url * formatting * fixed linting error * Set defaults * Allow only next.js dev server * fixed url * removed graph reassignment as due to change in master --------- Co-authored-by: Nicholas Tindle <nicholas.tindle@agpt.co>
204 lines
6.7 KiB
TypeScript
204 lines
6.7 KiB
TypeScript
"use client";
|
|
|
|
import { useMemo, useState } from "react";
|
|
import Link from "next/link";
|
|
import {
|
|
ArrowLeft,
|
|
Download,
|
|
Calendar,
|
|
Tag,
|
|
ChevronDown,
|
|
ChevronUp,
|
|
} from "lucide-react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { AgentDetailResponse } from "@/lib/marketplace-api";
|
|
import dynamic from "next/dynamic";
|
|
import { Node, Edge, NodeTypes, EdgeTypes } from "reactflow";
|
|
import MarketplaceAPI from "@/lib/marketplace-api";
|
|
import AutoGPTServerAPI, { GraphCreatable } from "@/lib/autogpt-server-api";
|
|
|
|
const ReactFlow = dynamic(
|
|
() => import("reactflow").then((mod) => mod.default),
|
|
{ ssr: false },
|
|
);
|
|
const Controls = dynamic(
|
|
() => import("reactflow").then((mod) => mod.Controls),
|
|
{ ssr: false },
|
|
);
|
|
const Background = dynamic(
|
|
() => import("reactflow").then((mod) => mod.Background),
|
|
{ ssr: false },
|
|
);
|
|
|
|
import "reactflow/dist/style.css";
|
|
import CustomNode from "./CustomNode";
|
|
import { CustomEdge } from "./CustomEdge";
|
|
import ConnectionLine from "./ConnectionLine";
|
|
import { beautifyString } from "@/lib/utils";
|
|
|
|
function convertGraphToReactFlow(graph: any): { nodes: Node[]; edges: Edge[] } {
|
|
const nodes: Node[] = graph.nodes.map((node: any) => {
|
|
let label = node.block_id || "Unknown";
|
|
try {
|
|
label = beautifyString(label);
|
|
} catch (error) {
|
|
console.error("Error beautifying node label:", error);
|
|
}
|
|
|
|
return {
|
|
id: node.id,
|
|
position: node.metadata.position || { x: 0, y: 0 },
|
|
data: {
|
|
label,
|
|
blockId: node.block_id,
|
|
inputDefault: node.input_default || {},
|
|
...node, // Include all other node data
|
|
},
|
|
type: "custom",
|
|
};
|
|
});
|
|
|
|
const edges: Edge[] = graph.links.map((link: any) => ({
|
|
id: `${link.source_id}-${link.sink_id}`,
|
|
source: link.source_id,
|
|
target: link.sink_id,
|
|
sourceHandle: link.source_name,
|
|
targetHandle: link.sink_name,
|
|
type: "custom",
|
|
data: {
|
|
sourceId: link.source_id,
|
|
targetId: link.sink_id,
|
|
sourceName: link.source_name,
|
|
targetName: link.sink_name,
|
|
isStatic: link.is_static,
|
|
},
|
|
}));
|
|
|
|
return { nodes, edges };
|
|
}
|
|
|
|
async function installGraph(id: string): Promise<void> {
|
|
const apiUrl =
|
|
process.env.NEXT_PUBLIC_AGPT_MARKETPLACE_URL ||
|
|
"http://localhost:8001/api/v1/market";
|
|
const api = new MarketplaceAPI(apiUrl);
|
|
|
|
const serverAPIUrl = process.env.AGPT_SERVER_API_URL;
|
|
const serverAPI = new AutoGPTServerAPI(serverAPIUrl);
|
|
try {
|
|
console.log(`Installing agent with id: ${id}`);
|
|
let agent = await api.downloadAgent(id);
|
|
console.log(`Agent downloaded:`, agent);
|
|
const data: GraphCreatable = {
|
|
id: agent.id,
|
|
version: agent.version,
|
|
is_active: true,
|
|
is_template: false,
|
|
name: agent.name,
|
|
description: agent.description,
|
|
nodes: agent.graph.nodes,
|
|
links: agent.graph.links,
|
|
};
|
|
await serverAPI.createTemplate(data);
|
|
console.log(`Agent installed successfully`);
|
|
} catch (error) {
|
|
console.error(`Error installing agent:`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
function AgentDetailContent({ agent }: { agent: AgentDetailResponse }) {
|
|
const [isGraphExpanded, setIsGraphExpanded] = useState(false);
|
|
const { nodes, edges } = convertGraphToReactFlow(agent.graph);
|
|
|
|
const nodeTypes: NodeTypes = useMemo(() => ({ custom: CustomNode }), []);
|
|
const edgeTypes: EdgeTypes = useMemo(() => ({ custom: CustomEdge }), []);
|
|
|
|
return (
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<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>
|
|
<Button
|
|
onClick={() => installGraph(agent.id)}
|
|
className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
|
>
|
|
<Download className="mr-2" size={16} />
|
|
Download Agent
|
|
</Button>
|
|
</div>
|
|
<div className="bg-white shadow overflow-hidden 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-200 px-4 py-5 sm:p-0">
|
|
<dl className="sm:divide-y sm:divide-gray-200">
|
|
<div className="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
<dt className="text-sm font-medium text-gray-500 flex items-center">
|
|
<Calendar className="mr-2" size={16} />
|
|
Last Updated
|
|
</dt>
|
|
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
|
{new Date(agent.updatedAt).toLocaleDateString()}
|
|
</dd>
|
|
</div>
|
|
<div className="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
|
<dt className="text-sm font-medium text-gray-500 flex items-center">
|
|
<Tag className="mr-2" size={16} />
|
|
Categories
|
|
</dt>
|
|
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
|
{agent.categories.join(", ")}
|
|
</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
<div className="border-t border-gray-200 px-4 py-5 sm:px-6">
|
|
<button
|
|
className="flex items-center justify-between w-full text-left text-sm font-medium text-indigo-600 hover:text-indigo-500"
|
|
onClick={() => setIsGraphExpanded(!isGraphExpanded)}
|
|
>
|
|
<span>Agent Graph</span>
|
|
{isGraphExpanded ? (
|
|
<ChevronUp size={20} />
|
|
) : (
|
|
<ChevronDown size={20} />
|
|
)}
|
|
</button>
|
|
{isGraphExpanded && (
|
|
<div className="mt-4" style={{ height: "600px" }}>
|
|
<ReactFlow
|
|
nodes={nodes}
|
|
edges={edges}
|
|
// nodeTypes={nodeTypes}
|
|
// edgeTypes={edgeTypes}
|
|
// connectionLineComponent={ConnectionLine}
|
|
fitView
|
|
attributionPosition="bottom-left"
|
|
nodesConnectable={false}
|
|
nodesDraggable={false}
|
|
zoomOnScroll={false}
|
|
panOnScroll={false}
|
|
elementsSelectable={false}
|
|
>
|
|
<Controls showInteractive={false} />
|
|
<Background />
|
|
</ReactFlow>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default AgentDetailContent;
|