From 6530ff0a246d93f5aba680aa40dac34ab2263c54 Mon Sep 17 00:00:00 2001 From: Shivering Ocelot Date: Tue, 1 Jul 2025 21:26:02 -0500 Subject: [PATCH] Agent class description, visible in UI --- backend/agents/conversation.py | 6 ++++++ backend/app.py | 12 +++++++++++- backend/server.py | 3 +++ frontend/lib/agent_screen.dart | 29 +++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/backend/agents/conversation.py b/backend/agents/conversation.py index 3637671..8579b86 100644 --- a/backend/agents/conversation.py +++ b/backend/agents/conversation.py @@ -6,6 +6,11 @@ from string import Template from inference import LlamaMessage, replicate_llama_completion from agent import Agent, AgentField +CLASS_DESCRIPTION = """ +Description of the Conversation Agent. +Here go additional instructions for configuration, like guidelines for the different prompts. +""".strip() + chat_system_prompt_template = Template("""$role The first message contains information about you and a conversation that you're participating in. Respond only with your next message in the conversation. @@ -84,6 +89,7 @@ class ThreadContext: class ConversationAgent(Agent): identifier = "conversation" + description = CLASS_DESCRIPTION schema_fields = [ AgentField('system_prompt', 'string', default="You are a friendly AI having a casual conversation with the user."), ] diff --git a/backend/app.py b/backend/app.py index abb5429..8e680ac 100644 --- a/backend/app.py +++ b/backend/app.py @@ -155,12 +155,22 @@ class App: "id": agent.id, "name": agent.name, "description": agent.description, - "picture": agent.picture + "picture": agent.picture, + "kind": agent.kind, } for agent in agents] def get_agent_kinds(self): return [kind.identifier for kind in self.agent_classes] + def get_agent_kind_info(self, kind): + agent_class = next((it for it in self.agent_classes if it.identifier == kind), None) + if agent_class is None: + raise Exception(f"invalid agent kind: {kind}") + return { + "name": agent_class.identifier, + "description": getattr(agent_class, 'description', None), + } + def delete_chat(self, chat_id): with self.sql_session() as session: session.execute(db.Membership.__table__.delete().where(db.Membership.chat_id == chat_id)) diff --git a/backend/server.py b/backend/server.py index 93bdef3..04be752 100644 --- a/backend/server.py +++ b/backend/server.py @@ -146,6 +146,9 @@ def start_server(app): elif action == "get-agent-kinds": await send({'message': "agents retrieved", 'kinds': app.get_agent_kinds(), 'nonce': nonce}) + elif action == "get-agent-kind-info": + await send({'message': "agent kind retrieved", 'info': app.get_agent_kind_info(body['kind']), 'nonce': nonce}) + elif action == "get-agents": await send({'message': "agents retrieved", 'agents': app.get_agents(user_id), 'nonce': nonce}) diff --git a/frontend/lib/agent_screen.dart b/frontend/lib/agent_screen.dart index 743c8c6..15b6b73 100644 --- a/frontend/lib/agent_screen.dart +++ b/frontend/lib/agent_screen.dart @@ -25,14 +25,36 @@ class AgentScreen extends StatefulWidget { class _AgentScreenState extends State { String? _title; final TextEditingController nameController = TextEditingController(); + String description = ""; List configFields = []; @override void initState() { super.initState(); + _loadAgentInfo(); _loadConfigFields(); } + void _loadAgentInfo() async { + final agentsResponse = await Backend.sendAction('get-agents', {}); + var agentEntry = null; + for (var entry in agentsResponse['agents']) { + if (entry['id'] == widget.agentId) { + agentEntry = entry; + } + } + + if (agentEntry == null) { + print("Agent ${widget.agentId} not found in agents list"); + return; + } + + final kindResponse = await Backend.sendAction('get-agent-kind-info', {'kind': agentEntry['kind']}); + setState(() { + description = kindResponse['info']['description']; + }); + } + void _loadConfigFields() async { final response = await Backend.sendAction('get-agent-config-fields', {'agentId': widget.agentId}); setState(() { @@ -77,6 +99,13 @@ class _AgentScreenState extends State { padding: const EdgeInsets.all(16.0), child: Column( children: [ + Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: Align( + alignment: Alignment.centerLeft, + child: Text(description), + ) + ), ListView.builder( shrinkWrap: true, itemCount: configFields.length,