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
91 lines
2.4 KiB
Python
91 lines
2.4 KiB
Python
|
|
from datetime import datetime
|
|
import time
|
|
|
|
def generate_tmp_id(app):
|
|
app.tmp.id_counter += 1
|
|
return "tmp-" + str(app.tmp.id_counter)
|
|
|
|
def is_tmp_id(id):
|
|
return type(id) == str and id.startswith("tmp-")
|
|
|
|
class State:
|
|
def __init__(self):
|
|
self.id_counter = 0
|
|
self.agents = {}
|
|
self.chats = {}
|
|
self.threads = {}
|
|
self.runs = {}
|
|
|
|
# list of temporary agent ids that belong to a real user
|
|
self.user_agents = {}
|
|
# list of temporary chat ids that belong to a real user
|
|
self.user_chats = {}
|
|
# list of temporary chat ids where a real agent is participating
|
|
self.participating = {}
|
|
|
|
def get_user_agents(self, user_id):
|
|
if user_id not in self.user_agents:
|
|
self.user_agents[user_id] = []
|
|
return self.user_agents[user_id]
|
|
|
|
def get_user_chats(self, user_id):
|
|
if user_id not in self.user_chats:
|
|
self.user_chats[user_id] = []
|
|
return self.user_chats[user_id]
|
|
|
|
class Agent:
|
|
def create(app, user_id, name, agentname, main_chat_id, description="", picture=None, kind='default', data={}):
|
|
self = Agent()
|
|
|
|
self.id = None
|
|
self.user_id = user_id
|
|
self.name = name
|
|
self.agentname = agentname
|
|
self.main_chat_id = main_chat_id
|
|
self.description = description
|
|
self.picture = picture
|
|
self.kind = kind
|
|
self.data = data
|
|
|
|
self.id = generate_tmp_id(app)
|
|
app.tmp.agents[self.id] = self
|
|
app.tmp.get_user_agents(user_id).append(self.id)
|
|
|
|
return self
|
|
|
|
class Chat:
|
|
def create(app, user_id, name, description="", picture=None, ordering=None):
|
|
self = Chat()
|
|
self._app = app
|
|
|
|
self.id = None
|
|
self.user_id = user_id
|
|
self.name = name
|
|
self.description = description
|
|
self.picture = picture
|
|
self.ordering = ordering
|
|
|
|
self.messages = []
|
|
self.threads = []
|
|
self.participants = []
|
|
|
|
self.id = generate_tmp_id(app)
|
|
app.tmp.chats[self.id] = self
|
|
app.tmp.get_user_chats(user_id).append(self.id)
|
|
|
|
return self
|
|
|
|
class Thread:
|
|
def create(app, chat_id, name):
|
|
self = Thread()
|
|
|
|
self.chat_id = chat_id
|
|
self.name = name
|
|
self.id = generate_tmp_id(app)
|
|
|
|
app.tmp.threads[self.id] = self
|
|
app.tmp.chats[chat_id].threads.append(self.id)
|
|
|
|
return self
|
|
|