mirror of
https://github.com/arc53/DocsGPT.git
synced 2025-11-29 00:23:17 +00:00
Merge branch 'main' of https://github.com/manishmadan2882/docsgpt
This commit is contained in:
@@ -15,6 +15,7 @@ from flask_restx import fields, inputs, Namespace, Resource
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
from application.agents.tools.tool_manager import ToolManager
|
||||
from pymongo import ReturnDocument
|
||||
|
||||
from application.api.user.tasks import (
|
||||
ingest,
|
||||
@@ -51,6 +52,7 @@ agents_collection.create_index(
|
||||
name="shared_index",
|
||||
background=True,
|
||||
)
|
||||
users_collection.create_index("user_id", unique=True)
|
||||
|
||||
user = Blueprint("user", __name__)
|
||||
user_ns = Namespace("user", description="User related operations", path="/")
|
||||
@@ -86,32 +88,46 @@ def generate_date_range(start_date, end_date):
|
||||
|
||||
|
||||
def ensure_user_doc(user_id):
|
||||
user_doc = users_collection.find_one({"user_id": user_id})
|
||||
default_prefs = {
|
||||
"pinned": [],
|
||||
"shared_with_me": [],
|
||||
}
|
||||
|
||||
if not user_doc:
|
||||
user_doc = {
|
||||
"user_id": user_id,
|
||||
"agent_preferences": {"pinned": [], "hidden_shared": []},
|
||||
}
|
||||
users_collection.insert_one(user_doc)
|
||||
return user_doc
|
||||
updated = False
|
||||
preferences = user_doc.get("agent_preferences", {})
|
||||
user_doc = users_collection.find_one_and_update(
|
||||
{"user_id": user_id},
|
||||
{"$setOnInsert": {"agent_preferences": default_prefs}},
|
||||
upsert=True,
|
||||
return_document=ReturnDocument.AFTER,
|
||||
)
|
||||
|
||||
prefs = user_doc.get("agent_preferences", {})
|
||||
updates = {}
|
||||
if "pinned" not in prefs:
|
||||
updates["agent_preferences.pinned"] = []
|
||||
if "shared_with_me" not in prefs:
|
||||
updates["agent_preferences.shared_with_me"] = []
|
||||
|
||||
if updates:
|
||||
users_collection.update_one({"user_id": user_id}, {"$set": updates})
|
||||
user_doc = users_collection.find_one({"user_id": user_id})
|
||||
|
||||
if "pinned" not in preferences:
|
||||
preferences["pinned"] = []
|
||||
updated = True
|
||||
if "hidden_shared" not in preferences:
|
||||
preferences["hidden_shared"] = []
|
||||
updated = True
|
||||
if updated:
|
||||
users_collection.update_one(
|
||||
{"user_id": user_id}, {"$set": {"agent_preferences": preferences}}
|
||||
)
|
||||
user_doc["agent_preferences"] = preferences
|
||||
return user_doc
|
||||
|
||||
|
||||
def resolve_tool_details(tool_ids):
|
||||
tools = user_tools_collection.find(
|
||||
{"_id": {"$in": [ObjectId(tid) for tid in tool_ids]}}
|
||||
)
|
||||
return [
|
||||
{
|
||||
"id": str(tool["_id"]),
|
||||
"name": tool.get("name", ""),
|
||||
"display_name": tool.get("displayName", tool.get("name", "")),
|
||||
}
|
||||
for tool in tools
|
||||
]
|
||||
|
||||
|
||||
def get_vector_store(source_id):
|
||||
"""
|
||||
Get the Vector Store
|
||||
@@ -1079,6 +1095,7 @@ class GetAgent(Resource):
|
||||
"retriever": agent.get("retriever", ""),
|
||||
"prompt_id": agent.get("prompt_id", ""),
|
||||
"tools": agent.get("tools", []),
|
||||
"tool_details": resolve_tool_details(agent.get("tools", [])),
|
||||
"agent_type": agent.get("agent_type", ""),
|
||||
"status": agent.get("status", ""),
|
||||
"created_at": agent.get("createdAt", ""),
|
||||
@@ -1128,6 +1145,7 @@ class GetAgents(Resource):
|
||||
"retriever": agent.get("retriever", ""),
|
||||
"prompt_id": agent.get("prompt_id", ""),
|
||||
"tools": agent.get("tools", []),
|
||||
"tool_details": resolve_tool_details(agent.get("tools", [])),
|
||||
"agent_type": agent.get("agent_type", ""),
|
||||
"status": agent.get("status", ""),
|
||||
"created_at": agent.get("createdAt", ""),
|
||||
@@ -1486,26 +1504,25 @@ class PinnedAgents(Resource):
|
||||
decoded_token = request.decoded_token
|
||||
if not decoded_token:
|
||||
return make_response(jsonify({"success": False}), 401)
|
||||
|
||||
user_id = decoded_token.get("sub")
|
||||
|
||||
try:
|
||||
user_doc = ensure_user_doc(user_id)
|
||||
pinned_ids = user_doc.get("agent_preferences", {}).get("pinned", [])
|
||||
hidden_ids = set(
|
||||
user_doc.get("agent_preferences", {}).get("hidden_shared", [])
|
||||
)
|
||||
|
||||
if not pinned_ids:
|
||||
return make_response(jsonify([]), 200)
|
||||
|
||||
pinned_object_ids = [ObjectId(agent_id) for agent_id in pinned_ids]
|
||||
|
||||
pinned_agents_cursor = agents_collection.find(
|
||||
{"_id": {"$in": pinned_object_ids}}
|
||||
)
|
||||
pinned_agents = list(pinned_agents_cursor)
|
||||
existing_ids = {str(agent["_id"]) for agent in pinned_agents}
|
||||
|
||||
existing_agents = pinned_agents
|
||||
existing_ids = {str(agent["_id"]) for agent in existing_agents}
|
||||
|
||||
# Clean up any stale pinned IDs
|
||||
stale_ids = [
|
||||
agent_id for agent_id in pinned_ids if agent_id not in existing_ids
|
||||
]
|
||||
@@ -1522,13 +1539,17 @@ class PinnedAgents(Resource):
|
||||
"description": agent.get("description", ""),
|
||||
"source": (
|
||||
str(db.dereference(agent["source"])["_id"])
|
||||
if "source" in agent and isinstance(agent["source"], DBRef)
|
||||
if "source" in agent
|
||||
and agent["source"]
|
||||
and isinstance(agent["source"], DBRef)
|
||||
and db.dereference(agent["source"]) is not None
|
||||
else ""
|
||||
),
|
||||
"chunks": agent.get("chunks", ""),
|
||||
"retriever": agent.get("retriever", ""),
|
||||
"prompt_id": agent.get("prompt_id", ""),
|
||||
"tools": agent.get("tools", []),
|
||||
"tool_details": resolve_tool_details(agent.get("tools", [])),
|
||||
"agent_type": agent.get("agent_type", ""),
|
||||
"status": agent.get("status", ""),
|
||||
"created_at": agent.get("createdAt", ""),
|
||||
@@ -1542,12 +1563,13 @@ class PinnedAgents(Resource):
|
||||
"pinned": True,
|
||||
}
|
||||
for agent in pinned_agents
|
||||
if ("source" in agent or "retriever" in agent)
|
||||
and str(agent["_id"]) not in hidden_ids
|
||||
if "source" in agent or "retriever" in agent
|
||||
]
|
||||
|
||||
except Exception as err:
|
||||
current_app.logger.error(f"Error retrieving pinned agents: {err}")
|
||||
return make_response(jsonify({"success": False}), 400)
|
||||
|
||||
return make_response(jsonify(list_pinned_agents), 200)
|
||||
|
||||
|
||||
@@ -1594,11 +1616,11 @@ class PinAgent(Resource):
|
||||
return make_response(jsonify({"success": True, "action": action}), 200)
|
||||
|
||||
|
||||
@user_ns.route("/api/hide_shared_agent")
|
||||
class HideSharedAgent(Resource):
|
||||
@user_ns.route("/api/remove_shared_agent")
|
||||
class RemoveSharedAgent(Resource):
|
||||
@api.doc(
|
||||
params={"id": "ID of the shared agent"},
|
||||
description="Hide or unhide a shared agent for the current user",
|
||||
description="Remove a shared agent from the current user's shared list",
|
||||
)
|
||||
def delete(self):
|
||||
decoded_token = request.decoded_token
|
||||
@@ -1611,6 +1633,7 @@ class HideSharedAgent(Resource):
|
||||
return make_response(
|
||||
jsonify({"success": False, "message": "ID is required"}), 400
|
||||
)
|
||||
|
||||
try:
|
||||
agent = agents_collection.find_one(
|
||||
{"_id": ObjectId(agent_id), "shared_publicly": True}
|
||||
@@ -1620,27 +1643,25 @@ class HideSharedAgent(Resource):
|
||||
jsonify({"success": False, "message": "Shared agent not found"}),
|
||||
404,
|
||||
)
|
||||
user_doc = ensure_user_doc(user_id)
|
||||
hidden_list = user_doc.get("agent_preferences", {}).get("hidden_shared", [])
|
||||
|
||||
if agent_id in hidden_list:
|
||||
users_collection.update_one(
|
||||
{"user_id": user_id},
|
||||
{"$pull": {"agent_preferences.hidden_shared": agent_id}},
|
||||
)
|
||||
action = "unhidden"
|
||||
else:
|
||||
users_collection.update_one(
|
||||
{"user_id": user_id},
|
||||
{"$addToSet": {"agent_preferences.hidden_shared": agent_id}},
|
||||
)
|
||||
action = "hidden"
|
||||
ensure_user_doc(user_id)
|
||||
users_collection.update_one(
|
||||
{"user_id": user_id},
|
||||
{
|
||||
"$pull": {
|
||||
"agent_preferences.shared_with_me": agent_id,
|
||||
"agent_preferences.pinned": agent_id,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
return make_response(jsonify({"success": True, "action": "removed"}), 200)
|
||||
|
||||
except Exception as err:
|
||||
current_app.logger.error(f"Error hiding/unhiding shared agent: {err}")
|
||||
current_app.logger.error(f"Error removing shared agent: {err}")
|
||||
return make_response(
|
||||
jsonify({"success": False, "message": "Server error"}), 500
|
||||
)
|
||||
return make_response(jsonify({"success": True, "action": action}), 200)
|
||||
|
||||
|
||||
@user_ns.route("/api/shared_agent")
|
||||
@@ -1658,23 +1679,27 @@ class SharedAgent(Resource):
|
||||
return make_response(
|
||||
jsonify({"success": False, "message": "Token or ID is required"}), 400
|
||||
)
|
||||
try:
|
||||
query = {}
|
||||
query["shared_publicly"] = True
|
||||
query["shared_token"] = shared_token
|
||||
|
||||
try:
|
||||
query = {
|
||||
"shared_publicly": True,
|
||||
"shared_token": shared_token,
|
||||
}
|
||||
shared_agent = agents_collection.find_one(query)
|
||||
if not shared_agent:
|
||||
return make_response(
|
||||
jsonify({"success": False, "message": "Shared agent not found"}),
|
||||
404,
|
||||
)
|
||||
|
||||
agent_id = str(shared_agent["_id"])
|
||||
data = {
|
||||
"id": str(shared_agent["_id"]),
|
||||
"id": agent_id,
|
||||
"user": shared_agent.get("user", ""),
|
||||
"name": shared_agent.get("name", ""),
|
||||
"description": shared_agent.get("description", ""),
|
||||
"tools": shared_agent.get("tools", []),
|
||||
"tool_details": resolve_tool_details(shared_agent.get("tools", [])),
|
||||
"agent_type": shared_agent.get("agent_type", ""),
|
||||
"status": shared_agent.get("status", ""),
|
||||
"created_at": shared_agent.get("createdAt", ""),
|
||||
@@ -1691,15 +1716,29 @@ class SharedAgent(Resource):
|
||||
if tool_data:
|
||||
enriched_tools.append(tool_data.get("name", ""))
|
||||
data["tools"] = enriched_tools
|
||||
|
||||
decoded_token = getattr(request, "decoded_token", None)
|
||||
if decoded_token:
|
||||
user_id = decoded_token.get("sub")
|
||||
owner_id = shared_agent.get("user")
|
||||
|
||||
if user_id != owner_id:
|
||||
ensure_user_doc(user_id)
|
||||
users_collection.update_one(
|
||||
{"user_id": user_id},
|
||||
{"$addToSet": {"agent_preferences.shared_with_me": agent_id}},
|
||||
)
|
||||
|
||||
return make_response(jsonify(data), 200)
|
||||
|
||||
except Exception as err:
|
||||
current_app.logger.error(f"Error retrieving shared agent: {err}")
|
||||
return make_response(jsonify({"success": False}), 400)
|
||||
return make_response(jsonify(data), 200)
|
||||
|
||||
|
||||
@user_ns.route("/api/shared_agents")
|
||||
class SharedAgents(Resource):
|
||||
@api.doc(description="Get shared agents")
|
||||
@api.doc(description="Get shared agents explicitly shared with the user")
|
||||
def get(self):
|
||||
try:
|
||||
decoded_token = request.decoded_token
|
||||
@@ -1708,29 +1747,25 @@ class SharedAgents(Resource):
|
||||
user_id = decoded_token.get("sub")
|
||||
|
||||
user_doc = ensure_user_doc(user_id)
|
||||
pinned_ids = set(user_doc.get("agent_preferences", {}).get("pinned", []))
|
||||
hidden_ids = user_doc.get("agent_preferences", {}).get("hidden_shared", [])
|
||||
hidden_object_ids = [ObjectId(id) for id in hidden_ids]
|
||||
shared_with_ids = user_doc.get("agent_preferences", {}).get(
|
||||
"shared_with_me", []
|
||||
)
|
||||
shared_object_ids = [ObjectId(id) for id in shared_with_ids]
|
||||
|
||||
shared_agents_cursor = agents_collection.find(
|
||||
{"shared_publicly": True, "user": {"$ne": user_id}}
|
||||
{"_id": {"$in": shared_object_ids}, "shared_publicly": True}
|
||||
)
|
||||
shared_agents = list(shared_agents_cursor)
|
||||
|
||||
shared_ids_set = {agent["_id"] for agent in shared_agents}
|
||||
hidden_ids_set = set(hidden_object_ids)
|
||||
|
||||
stale_hidden_ids = [
|
||||
str(id) for id in hidden_ids_set if id not in shared_ids_set
|
||||
]
|
||||
if stale_hidden_ids:
|
||||
found_ids_set = {str(agent["_id"]) for agent in shared_agents}
|
||||
stale_ids = [id for id in shared_with_ids if id not in found_ids_set]
|
||||
if stale_ids:
|
||||
users_collection.update_one(
|
||||
{"user_id": user_id},
|
||||
{"$pullAll": {"agent_preferences.hidden_shared": stale_hidden_ids}},
|
||||
{"$pullAll": {"agent_preferences.shared_with_me": stale_ids}},
|
||||
)
|
||||
visible_shared_agents = [
|
||||
agent for agent in shared_agents if agent["_id"] not in hidden_ids_set
|
||||
]
|
||||
|
||||
pinned_ids = set(user_doc.get("agent_preferences", {}).get("pinned", []))
|
||||
|
||||
list_shared_agents = [
|
||||
{
|
||||
@@ -1738,6 +1773,7 @@ class SharedAgents(Resource):
|
||||
"name": agent.get("name", ""),
|
||||
"description": agent.get("description", ""),
|
||||
"tools": agent.get("tools", []),
|
||||
"tool_details": resolve_tool_details(agent.get("tools", [])),
|
||||
"agent_type": agent.get("agent_type", ""),
|
||||
"status": agent.get("status", ""),
|
||||
"created_at": agent.get("createdAt", ""),
|
||||
@@ -1747,10 +1783,11 @@ class SharedAgents(Resource):
|
||||
"shared_token": agent.get("shared_token", ""),
|
||||
"shared_metadata": agent.get("shared_metadata", {}),
|
||||
}
|
||||
for agent in visible_shared_agents
|
||||
for agent in shared_agents
|
||||
]
|
||||
|
||||
return make_response(jsonify(list_shared_agents), 200)
|
||||
|
||||
except Exception as err:
|
||||
current_app.logger.error(f"Error retrieving shared agents: {err}")
|
||||
return make_response(jsonify({"success": False}), 400)
|
||||
|
||||
@@ -46,7 +46,7 @@ pandas==2.2.3
|
||||
openpyxl==3.1.5
|
||||
pathable==0.4.4
|
||||
pillow==11.1.0
|
||||
portalocker==3.1.1
|
||||
portalocker>=2.7.0,<3.0.0
|
||||
prance==23.6.21.0
|
||||
prompt-toolkit==3.0.51
|
||||
protobuf==5.29.3
|
||||
@@ -62,7 +62,7 @@ python-dotenv==1.0.1
|
||||
python-jose==3.4.0
|
||||
python-pptx==1.0.2
|
||||
redis==5.2.1
|
||||
referencing==0.36.2
|
||||
referencing>=0.28.0,<0.31.0
|
||||
regex==2024.11.6
|
||||
requests==2.32.3
|
||||
retry==0.9.2
|
||||
|
||||
@@ -3,18 +3,18 @@ from application.retriever.duckduck_search import DuckDuckSearch
|
||||
from application.retriever.brave_search import BraveRetSearch
|
||||
|
||||
|
||||
|
||||
class RetrieverCreator:
|
||||
retrievers = {
|
||||
'classic': ClassicRAG,
|
||||
'duckduck_search': DuckDuckSearch,
|
||||
'brave_search': BraveRetSearch,
|
||||
'default': ClassicRAG
|
||||
"classic": ClassicRAG,
|
||||
"duckduck_search": DuckDuckSearch,
|
||||
"brave_search": BraveRetSearch,
|
||||
"default": ClassicRAG,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def create_retriever(cls, type, *args, **kwargs):
|
||||
retiever_class = cls.retrievers.get(type.lower())
|
||||
retriever_type = (type or "default").lower()
|
||||
retiever_class = cls.retrievers.get(retriever_type)
|
||||
if not retiever_class:
|
||||
raise ValueError(f"No retievers class found for type {type}")
|
||||
return retiever_class(*args, **kwargs)
|
||||
return retiever_class(*args, **kwargs)
|
||||
|
||||
@@ -32,22 +32,26 @@ class FaissStore(BaseVectorStore):
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
faiss_path = f"{self.path}/index.faiss"
|
||||
pkl_path = f"{self.path}/index.pkl"
|
||||
|
||||
if not self.storage.file_exists(faiss_path) or not self.storage.file_exists(pkl_path):
|
||||
raise FileNotFoundError(f"Index files not found in storage at {self.path}")
|
||||
|
||||
|
||||
if not self.storage.file_exists(
|
||||
faiss_path
|
||||
) or not self.storage.file_exists(pkl_path):
|
||||
raise FileNotFoundError(
|
||||
f"Index files not found in storage at {self.path}"
|
||||
)
|
||||
|
||||
faiss_file = self.storage.get_file(faiss_path)
|
||||
pkl_file = self.storage.get_file(pkl_path)
|
||||
|
||||
|
||||
local_faiss_path = os.path.join(temp_dir, "index.faiss")
|
||||
local_pkl_path = os.path.join(temp_dir, "index.pkl")
|
||||
|
||||
with open(local_faiss_path, 'wb') as f:
|
||||
|
||||
with open(local_faiss_path, "wb") as f:
|
||||
f.write(faiss_file.read())
|
||||
|
||||
with open(local_pkl_path, 'wb') as f:
|
||||
|
||||
with open(local_pkl_path, "wb") as f:
|
||||
f.write(pkl_file.read())
|
||||
|
||||
|
||||
self.docsearch = FAISS.load_local(
|
||||
temp_dir, self.embeddings, allow_dangerous_deserialization=True
|
||||
)
|
||||
|
||||
@@ -2,6 +2,10 @@ import './locale/i18n';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Outlet, Route, Routes } from 'react-router-dom';
|
||||
|
||||
import Agents from './agents';
|
||||
import SharedAgentGate from './agents/SharedAgentGate';
|
||||
import ActionButtons from './components/ActionButtons';
|
||||
import Spinner from './components/Spinner';
|
||||
import Conversation from './conversation/Conversation';
|
||||
import { SharedConversation } from './conversation/SharedConversation';
|
||||
@@ -10,8 +14,6 @@ import useTokenAuth from './hooks/useTokenAuth';
|
||||
import Navigation from './Navigation';
|
||||
import PageNotFound from './PageNotFound';
|
||||
import Setting from './settings';
|
||||
import Agents from './agents';
|
||||
import ActionButtons from './components/ActionButtons';
|
||||
|
||||
function AuthWrapper({ children }: { children: React.ReactNode }) {
|
||||
const { isAuthLoading } = useTokenAuth();
|
||||
@@ -66,6 +68,7 @@ export default function App() {
|
||||
<Route path="/agents/*" element={<Agents />} />
|
||||
</Route>
|
||||
<Route path="/share/:identifier" element={<SharedConversation />} />
|
||||
<Route path="/shared/agent/:agentId" element={<SharedAgentGate />} />
|
||||
<Route path="/*" element={<PageNotFound />} />
|
||||
</Routes>
|
||||
</div>
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
import { useDarkTheme } from '../hooks';
|
||||
import { selectToken, setSelectedAgent } from '../preferences/preferenceSlice';
|
||||
import { AppDispatch } from '../store';
|
||||
import SharedAgentCard from './SharedAgentCard';
|
||||
import { Agent } from './types';
|
||||
|
||||
export default function SharedAgent() {
|
||||
@@ -193,65 +194,3 @@ export default function SharedAgent() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SharedAgentCard({ agent }: { agent: Agent }) {
|
||||
return (
|
||||
<div className="flex w-full max-w-[720px] flex-col rounded-3xl border border-dark-gray p-6 shadow-sm dark:border-grey sm:w-fit sm:min-w-[480px]">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-12 w-12 items-center justify-center overflow-hidden rounded-full p-1">
|
||||
<img src={Robot} className="h-full w-full object-contain" />
|
||||
</div>
|
||||
<div className="flex max-h-[92px] w-[80%] flex-col gap-px">
|
||||
<h2 className="text-base font-semibold text-[#212121] dark:text-[#E0E0E0] sm:text-lg">
|
||||
{agent.name}
|
||||
</h2>
|
||||
<p className="overflow-y-auto text-wrap break-all text-xs text-[#71717A] dark:text-[#949494] sm:text-sm">
|
||||
{agent.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex items-center gap-8">
|
||||
{agent.shared_metadata?.shared_by && (
|
||||
<p className="text-xs font-light text-[#212121] dark:text-[#E0E0E0] sm:text-sm">
|
||||
by {agent.shared_metadata.shared_by}
|
||||
</p>
|
||||
)}
|
||||
{agent.shared_metadata?.shared_at && (
|
||||
<p className="text-xs font-light text-[#71717A] dark:text-[#949494] sm:text-sm">
|
||||
Shared on{' '}
|
||||
{new Date(agent.shared_metadata.shared_at).toLocaleString('en-US', {
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: true,
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{agent.tools.length > 0 && (
|
||||
<div className="mt-8">
|
||||
<p className="text-sm font-semibold text-[#212121] dark:text-[#E0E0E0] sm:text-base">
|
||||
Connected Tools
|
||||
</p>
|
||||
<div className="mt-2 flex flex-wrap gap-2">
|
||||
{agent.tools.map((tool, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className="flex items-center gap-1 rounded-full bg-bright-gray px-3 py-1 text-xs font-light text-[#212121] dark:bg-dark-charcoal dark:text-[#E0E0E0]"
|
||||
>
|
||||
<img
|
||||
src={`/toolIcons/tool_${tool}.svg`}
|
||||
alt={`${tool} icon`}
|
||||
className="h-3 w-3"
|
||||
/>{' '}
|
||||
{tool}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
69
frontend/src/agents/SharedAgentCard.tsx
Normal file
69
frontend/src/agents/SharedAgentCard.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import Robot from '../assets/robot.svg';
|
||||
import { Agent } from './types';
|
||||
|
||||
export default function SharedAgentCard({ agent }: { agent: Agent }) {
|
||||
return (
|
||||
<div className="flex w-full max-w-[720px] flex-col rounded-3xl border border-dark-gray p-6 shadow-sm dark:border-grey sm:w-fit sm:min-w-[480px]">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-12 w-12 items-center justify-center overflow-hidden rounded-full p-1">
|
||||
<img src={Robot} className="h-full w-full object-contain" />
|
||||
</div>
|
||||
<div className="flex max-h-[92px] w-[80%] flex-col gap-px">
|
||||
<h2 className="text-base font-semibold text-[#212121] dark:text-[#E0E0E0] sm:text-lg">
|
||||
{agent.name}
|
||||
</h2>
|
||||
<p className="overflow-y-auto text-wrap break-all text-xs text-[#71717A] dark:text-[#949494] sm:text-sm">
|
||||
{agent.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{agent.shared_metadata && (
|
||||
<div className="mt-4 flex items-center gap-8">
|
||||
{agent.shared_metadata?.shared_by && (
|
||||
<p className="text-xs font-light text-[#212121] dark:text-[#E0E0E0] sm:text-sm">
|
||||
by {agent.shared_metadata.shared_by}
|
||||
</p>
|
||||
)}
|
||||
{agent.shared_metadata?.shared_at && (
|
||||
<p className="text-xs font-light text-[#71717A] dark:text-[#949494] sm:text-sm">
|
||||
Shared on{' '}
|
||||
{new Date(agent.shared_metadata.shared_at).toLocaleString(
|
||||
'en-US',
|
||||
{
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: true,
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{agent.tool_details && agent.tool_details.length > 0 && (
|
||||
<div className="mt-8">
|
||||
<p className="text-sm font-semibold text-[#212121] dark:text-[#E0E0E0] sm:text-base">
|
||||
Connected Tools
|
||||
</p>
|
||||
<div className="mt-2 flex flex-wrap gap-2">
|
||||
{agent.tool_details.map((tool, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className="flex items-center gap-1 rounded-full bg-bright-gray px-3 py-1 text-xs font-light text-[#212121] dark:bg-dark-charcoal dark:text-[#E0E0E0]"
|
||||
>
|
||||
<img
|
||||
src={`/toolIcons/tool_${tool.name}.svg`}
|
||||
alt={`${tool.name} icon`}
|
||||
className="h-3 w-3"
|
||||
/>{' '}
|
||||
{tool.name}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
7
frontend/src/agents/SharedAgentGate.tsx
Normal file
7
frontend/src/agents/SharedAgentGate.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Navigate, useParams } from 'react-router-dom';
|
||||
|
||||
export default function SharedAgentGate() {
|
||||
const { agentId } = useParams();
|
||||
|
||||
return <Navigate to={`/agents/shared/${agentId}`} replace />;
|
||||
}
|
||||
@@ -286,7 +286,10 @@ function AgentCard({
|
||||
|
||||
const handleHideSharedAgent = async () => {
|
||||
try {
|
||||
const response = await userService.hideSharedAgent(agent.id ?? '', token);
|
||||
const response = await userService.removeSharedAgent(
|
||||
agent.id ?? '',
|
||||
token,
|
||||
);
|
||||
if (!response.ok) throw new Error('Failed to hide shared agent');
|
||||
const updatedAgents = agents.filter(
|
||||
(prevAgent) => prevAgent.id !== agent.id,
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
export type ToolSummary = {
|
||||
id: string;
|
||||
name: string;
|
||||
display_name: string;
|
||||
};
|
||||
|
||||
export type Agent = {
|
||||
id?: string;
|
||||
name: string;
|
||||
@@ -8,6 +14,7 @@ export type Agent = {
|
||||
retriever: string;
|
||||
prompt_id: string;
|
||||
tools: string[];
|
||||
tool_details?: ToolSummary[];
|
||||
agent_type: string;
|
||||
status: string;
|
||||
key?: string;
|
||||
|
||||
@@ -18,7 +18,7 @@ const endpoints = {
|
||||
SHARED_AGENT: (id: string) => `/api/shared_agent?token=${id}`,
|
||||
SHARED_AGENTS: '/api/shared_agents',
|
||||
SHARE_AGENT: `/api/share_agent`,
|
||||
HIDE_SHARED_AGENT: (id: string) => `/api/hide_shared_agent?id=${id}`,
|
||||
REMOVE_SHARED_AGENT: (id: string) => `/api/remove_shared_agent?id=${id}`,
|
||||
AGENT_WEBHOOK: (id: string) => `/api/agent_webhook?id=${id}`,
|
||||
PROMPTS: '/api/get_prompts',
|
||||
CREATE_PROMPT: '/api/create_prompt',
|
||||
|
||||
@@ -41,8 +41,8 @@ const userService = {
|
||||
apiClient.get(endpoints.USER.SHARED_AGENTS, token),
|
||||
shareAgent: (data: any, token: string | null): Promise<any> =>
|
||||
apiClient.put(endpoints.USER.SHARE_AGENT, data, token),
|
||||
hideSharedAgent: (id: string, token: string | null): Promise<any> =>
|
||||
apiClient.delete(endpoints.USER.HIDE_SHARED_AGENT(id), token),
|
||||
removeSharedAgent: (id: string, token: string | null): Promise<any> =>
|
||||
apiClient.delete(endpoints.USER.REMOVE_SHARED_AGENT(id), token),
|
||||
getAgentWebhook: (id: string, token: string | null): Promise<any> =>
|
||||
apiClient.get(endpoints.USER.AGENT_WEBHOOK(id), token),
|
||||
getPrompts: (token: string | null): Promise<any> =>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useDropzone } from 'react-dropzone';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import SharedAgentCard from '../agents/SharedAgentCard';
|
||||
import DragFileUpload from '../assets/DragFileUpload.svg';
|
||||
import MessageInput from '../components/MessageInput';
|
||||
import { useMediaQuery } from '../hooks';
|
||||
@@ -193,6 +194,14 @@ export default function Conversation() {
|
||||
handleFeedback={handleFeedback}
|
||||
queries={queries}
|
||||
status={status}
|
||||
showHeroOnEmpty={selectedAgent ? false : true}
|
||||
headerContent={
|
||||
selectedAgent ? (
|
||||
<div className="flex w-full items-center justify-center py-4">
|
||||
<SharedAgentCard agent={selectedAgent} />
|
||||
</div>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="z-3 flex h-auto w-full max-w-[1300px] flex-col items-end self-center rounded-2xl bg-opacity-0 py-1 md:w-9/12 lg:w-8/12 xl:w-8/12 2xl:w-6/12">
|
||||
|
||||
Reference in New Issue
Block a user