From 7853b715875d0c0963683fd9dd35c1c19717f713 Mon Sep 17 00:00:00 2001 From: Shivering Ocelot Date: Thu, 17 Jul 2025 19:50:14 -0500 Subject: [PATCH] Introduce Expert Agent. Prompt agents from UI. --- backend/src/agents/__init__.py | 2 + backend/src/agents/expert.py | 53 +++++++++++++ backend/src/app.py | 17 ++-- backend/src/inference.py | 1 - backend/src/server.py | 11 ++- frontend/src/views/Agent.vue | 138 ++++++++++++++++++++++++++++----- 6 files changed, 194 insertions(+), 28 deletions(-) create mode 100644 backend/src/agents/__init__.py create mode 100644 backend/src/agents/expert.py diff --git a/backend/src/agents/__init__.py b/backend/src/agents/__init__.py new file mode 100644 index 0000000..8e1aea1 --- /dev/null +++ b/backend/src/agents/__init__.py @@ -0,0 +1,2 @@ +from .character import CharacterAgent +from .expert import ExpertAgent \ No newline at end of file diff --git a/backend/src/agents/expert.py b/backend/src/agents/expert.py new file mode 100644 index 0000000..3aba9f0 --- /dev/null +++ b/backend/src/agents/expert.py @@ -0,0 +1,53 @@ +import re +import json +import inspect +from string import Template + +from inference import LlamaMessage, replicate_llama_completion, Models +from agent import Agent, AgentField + +CLASS_DESCRIPTION = """ +Expert AI in any field, powered by Llama 3 70b. +Will get guidelines, documents, and other advanced features in the future. +""".strip() + +class ExpertAgent(Agent): + identifier = "expert" + description = CLASS_DESCRIPTION + schema_fields = [ + AgentField('system_prompt', 'string', default="You are an expert AI assistant."), + ] + + def __init__(self, app, data): + Agent.__init__(self, app, data) + + async def prompt(self, instruction, input=None, **kwargs): + # if instruction and input are passed, instruction extends the system prompt + # otherwise, use the one passed as the user prompt, with the regular system prompt + + # TODO: if 'history' in kwargs: interpret it as user-agent turns assuming list[str] + + system = self.config['system_prompt'] + if instruction != None and input != None: + system += "\n" + instruction + + prompt = input if input != None else instruction + messages = [ + LlamaMessage("system", system), + LlamaMessage("user", prompt) + ] + + response = await replicate_llama_completion(self.app, messages, model=Models.llama_70b) + return response + + async def received_message(self, message): + raise Exception("TODO: expert chat support") + + messages = [] + response = await replicate_llama_completion(self.app, messages, model=Models.llama_70b) + self.app.send_chat_message( + chat_id=message.chat_id, + sender=self.id, + content=response, + thread_id=message.thread_id, + ) \ No newline at end of file diff --git a/backend/src/app.py b/backend/src/app.py index 700542f..f0a30f7 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -12,10 +12,10 @@ import replicate import database as db import agent as agent_mod +import agents as agents_mod from server import start_server from chat import ChatView, Message, MESSAGE_PAGE_SIZE -from agents.character import CharacterAgent from app_mixins import ChatMixin class App(ChatMixin): @@ -37,12 +37,13 @@ class App(ChatMixin): # `Agent` is the kind 'basic', will be class `BasicAgent` in the future self.agent_classes = [ agent_mod.BasicAgent, - CharacterAgent, + agents_mod.CharacterAgent, + agents_mod.ExpertAgent, - agent_mod.LlamaAgent, - agent_mod.CoderV1Agent, - agent_mod.ToolUsingAgent, - agent_mod.DebugAgent, + #agent_mod.LlamaAgent, + #agent_mod.CoderV1Agent, + #agent_mod.ToolUsingAgent, + #agent_mod.DebugAgent, ] def sql_session(self): @@ -231,9 +232,9 @@ class App(ChatMixin): return fields return {} - async def send_agent_prompt(self, agent_id, message): + async def send_agent_prompt(self, agent_id, instruction, input=None, options={}): control = self.get_agent_control(agent_id) - response = await control.prompt(message) + response = await control.prompt(instruction, input, **options) return response async def call_agent_action(self, agent_id, action, args): diff --git a/backend/src/inference.py b/backend/src/inference.py index 3b641bd..ab93f7d 100644 --- a/backend/src/inference.py +++ b/backend/src/inference.py @@ -1,7 +1,6 @@ import threading from stream import Stream -LLAMA3_MODEL = "meta/meta-llama-3-8b-instruct" VALID_ROLES = ['user', 'agent', 'system'] class LlamaMessage: diff --git a/backend/src/server.py b/backend/src/server.py index 0cd57e4..3cc3b71 100644 --- a/backend/src/server.py +++ b/backend/src/server.py @@ -224,7 +224,16 @@ def start_server(app): await send({'message': "chat thread created", 'threadId': thread_id, 'nonce': nonce}) elif action == "send-agent-prompt": - response = await app.send_agent_prompt(body['agentId'], body['content']) + if 'instruction' not in body and 'input' not in body: + await send({'error': "instruction or input required"}) + continue + + response = await app.send_agent_prompt( + body['agentId'], + body.get('instruction'), + body.get('input'), + body.get('options', {}) + ) await send({'message': "propmt sent", 'response': response, 'nonce': nonce}) elif action == "call-agent-action": diff --git a/frontend/src/views/Agent.vue b/frontend/src/views/Agent.vue index c52df21..9ec54cb 100644 --- a/frontend/src/views/Agent.vue +++ b/frontend/src/views/Agent.vue @@ -1,6 +1,6 @@