Refactor agent execution to use AgentRun with OpenAI-compatible API
Major refactoring to support isolated run objects with streaming, events, and OpenAI-compatible endpoints. ## Backend Changes - **Agent class**: Added `run()` method, `received_message()` wraps chat into AgentRun - **AgentRun class**: New class for run state with event system, serialization, and user tracking - **inference.py**: Complete refactor with `build_messages()`, `chat_completion()`, tool support for llama-cpp/ollama/replicate - **tools.py**: New centralized tool management (ToolSpec, ToolParameter, format_tools_for_engine) - **tools.py**: Removed legacy Toolset/Action/ToolDescription system - **server.py**: Added OpenAI-compatible `/api/openai/v1/chat/completions` endpoint with streaming support - **temporary.py**: Added `self.runs` dict to State class - **expert.py**: Refactored to use new Agent.run() signature - **scripted.py**: Updated to raise NotImplementedError ## Frontend Changes - **backend.js**: Added `onRunEvents()` for run event subscriptions - **Sidebar.vue**: Added runs navigation mode - **router/index.js**: Renamed User route to RunsView - **RunsView.vue**: New view for listing/monitoring agent runs ## Breaking Changes - Agent `prompt()` signature changed: `(instruction, input=None, **kwargs)` instead of `(content)` - Agent `received_message()` must use AgentRun pattern - Tools.py removed, functionality moved to tool.py - Deprecated tool prompt/action system removed
This commit is contained in:
1 parent
eb9a1ad9e8
commit
4e15b44d39
14 files changed
+1151
-522
No files matched your search
@@ -1,10 +1,4 @@
|
||||
import re
|
||||
import json
|
||||
import inspect
|
||||
from string import Template
|
||||
|
||||
import inference
|
||||
from inference import LlamaMessage
|
||||
from agent import Agent, AgentField
|
||||
|
||||
CLASS_DESCRIPTION = """
|
||||
@@ -27,90 +21,37 @@ class ExpertAgent(Agent):
|
||||
def __init__(self, app, data):
|
||||
Agent.__init__(self, app, data)
|
||||
|
||||
async def prompt(self, instruction, input=None, **kwargs):
|
||||
# Instruction extends system if there's input or messages
|
||||
# Otherwise instruction is the user prompt
|
||||
# Input is always added as a user message at the end, if present
|
||||
|
||||
# Use 'messages' as starting point when passed
|
||||
messages = []
|
||||
if 'messages' in kwargs:
|
||||
messages = [LlamaMessage(msg['role'], msg['content']) for msg in kwargs['messages']]
|
||||
|
||||
# Construct the default messages
|
||||
system = self.config['system_prompt']
|
||||
prompt = input
|
||||
|
||||
if input == None and not messages:
|
||||
prompt = instruction
|
||||
elif instruction:
|
||||
system += "\n" + instruction
|
||||
|
||||
# Add default messages to list
|
||||
messages.insert(0, LlamaMessage("system", system))
|
||||
if prompt:
|
||||
messages.append(LlamaMessage("user", prompt))
|
||||
|
||||
model_id = self.config['model']
|
||||
db_model = await self.app.get_model(model_id)
|
||||
model_engine = db_model.value["engine"]
|
||||
|
||||
async def run(self, run):
|
||||
inp = run.input or {}
|
||||
opts = {}
|
||||
if 'temperature' in self.config:
|
||||
opts['temperature'] = self.config['temperature']
|
||||
if 'repetition_penalty' in self.config:
|
||||
opts['repetition_penalty'] = self.config['repetition_penalty']
|
||||
|
||||
if model_engine == "llama-cpp":
|
||||
response = await inference.local_chat_completion(
|
||||
self.app,
|
||||
messages,
|
||||
model=db_model.value['model'],
|
||||
opts=opts,
|
||||
)
|
||||
elif model_engine == "replicate":
|
||||
if 'parameters' in db_model:
|
||||
opts['parameters'] = db_model['parameters']
|
||||
if 'format' in db_model:
|
||||
opts['format'] = db_model['format']
|
||||
|
||||
response = await inference.replicate_completion(self.app, messages, model=db_model.value['model'], opts=opts)
|
||||
if self.config.get("temperature") is not None:
|
||||
opts["temperature"] = self.config["temperature"]
|
||||
if self.config.get("repetition_penalty") is not None:
|
||||
opts["repetition_penalty"] = self.config["repetition_penalty"]
|
||||
|
||||
elif model_engine == "ollama":
|
||||
response = await inference.ollama_chat_completion(self.app, messages, model=db_model.value['model'], opts=opts)
|
||||
# 1. Build message list based on input mode
|
||||
if "messages" in inp:
|
||||
messages = inp["messages"]
|
||||
else:
|
||||
raise Exception("Unsuported model: " + repr(db_model.value))
|
||||
instruction = inp.get("instruction")
|
||||
input_text = inp.get("input")
|
||||
messages = inference.build_messages(
|
||||
system_prompt=self.config.get("system_prompt", ""),
|
||||
instruction=instruction,
|
||||
input=input_text,
|
||||
messages=inp.get("messages"),
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
async def received_message(self, message):
|
||||
chat_view = await self.app.get_chat_view(message.chat_id)
|
||||
thread = chat_view.get_thread(message.thread_id)
|
||||
|
||||
def msg_role(message):
|
||||
sender = message.sender
|
||||
is_digit = isinstance(sender, (int, str)) and str(sender).isdigit()
|
||||
|
||||
if is_digit and str(sender) == str(self.id):
|
||||
return 'assistant'
|
||||
elif sender == 'user':
|
||||
return 'user'
|
||||
elif sender.startswith("tmp-"):
|
||||
return 'assistant'
|
||||
else:
|
||||
raise Exception("Unsupported sender: " + sender)
|
||||
|
||||
messages = [{'role': msg_role(msg), 'content': msg.content} for msg in thread.messages]
|
||||
|
||||
response = await self.prompt(
|
||||
instruction=None,
|
||||
input=None,
|
||||
messages=messages
|
||||
# 2. Call inference, passing the run so it feeds run.stream
|
||||
# and can emit tool_call events through the run.
|
||||
await inference.chat_completion(
|
||||
self.app,
|
||||
model_id=self.config.get("model"),
|
||||
messages=messages,
|
||||
tools=inp.get("tools", []),
|
||||
opts=opts,
|
||||
agent_run=run,
|
||||
)
|
||||
|
||||
await self.app.send_chat_message(
|
||||
chat_id=message.chat_id,
|
||||
sender=self.id,
|
||||
content=response,
|
||||
thread_id=message.thread_id,
|
||||
)
|
||||
run.stream.listen(lambda chunk: None, lambda: run.close())
|
||||
Reference in new issue
Block a user