Temporary agents and chats
This commit is contained in:
1 parent
fe596761dc
commit
e07f8ee05f
15 files changed
+443
-168
No files matched your search
@@ -6,3 +6,6 @@ horde.db
|
|||||||
/test-data
|
/test-data
|
||||||
/local-data
|
/local-data
|
||||||
/models
|
/models
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
node_modules/
|
||||||
@@ -51,48 +51,33 @@ class ExpertAgent(Agent):
|
|||||||
if prompt:
|
if prompt:
|
||||||
messages.append(LlamaMessage("user", prompt))
|
messages.append(LlamaMessage("user", prompt))
|
||||||
|
|
||||||
model = self.config['model']
|
model_id = self.config['model']
|
||||||
|
db_model = await self.app.get_model(model_id)
|
||||||
|
model_engine = db_model.value["engine"]
|
||||||
|
|
||||||
if type(model) is int:
|
opts = {}
|
||||||
db_model = await self.app.get_model(model)
|
if 'temperature' in self.config:
|
||||||
model_engine = db_model.value["engine"]
|
opts['temperature'] = self.config['temperature']
|
||||||
|
if 'repetition_penalty' in self.config:
|
||||||
|
opts['repetition_penalty'] = self.config['repetition_penalty']
|
||||||
|
|
||||||
opts = {}
|
if model_engine == "llama-cpp":
|
||||||
if 'temperature' in self.config:
|
response = await inference.local_chat_completion(
|
||||||
opts['temperature'] = self.config['temperature']
|
self.app,
|
||||||
if 'repetition_penalty' in self.config:
|
messages,
|
||||||
opts['repetition_penalty'] = self.config['repetition_penalty']
|
model=db_model.value['model'],
|
||||||
|
opts=opts,
|
||||||
|
)
|
||||||
|
elif model_engine == "replicate":
|
||||||
|
if 'parameters' in db_model:
|
||||||
|
opts['parameters'] = db_model['parameters']
|
||||||
|
|
||||||
if model_engine == "llama-cpp":
|
response = await inference.replicate_completion(self.app, messages, model=db_model.value['model'], opts=opts)
|
||||||
response = await inference.local_chat_completion(
|
|
||||||
self.app,
|
|
||||||
messages,
|
|
||||||
model=db_model.value['model'],
|
|
||||||
opts=opts,
|
|
||||||
)
|
|
||||||
|
|
||||||
return response
|
elif model_engine == "ollama":
|
||||||
elif model_engine == "replicate":
|
response = await inference.ollama_chat_completion(self.app, messages, model=db_model.value['model'], opts=opts)
|
||||||
if 'parameters' in db_model:
|
|
||||||
opts['parameters'] = db_model['parameters']
|
|
||||||
|
|
||||||
response = await inference.replicate_completion(self.app, messages, model=db_model.value['model'], opts=opts)
|
|
||||||
else:
|
|
||||||
raise Exception("Unsuported model: " + repr(db_model.value))
|
|
||||||
|
|
||||||
elif model.startswith("ollama:"):
|
|
||||||
response = await inference.ollama_chat_completion(self.app, messages, model=model[7:])
|
|
||||||
elif model == "qwen-big":
|
|
||||||
response = await inference.replicate_qwen_completion(self.app, messages, model=inference.Models.qwen3_235b)
|
|
||||||
elif model == "qwen-small":
|
|
||||||
response = await inference.replicate_qwen_completion(self.app, messages, model=inference.Models.qwen3_8b)
|
|
||||||
elif model == "llama-big":
|
|
||||||
response = await inference.replicate_llama_completion(self.app, messages, model=inference.Models.llama_70b)
|
|
||||||
elif model == "llama-small":
|
|
||||||
response = await inference.replicate_llama_completion(self.app, messages, model=inference.Models.llama_8b)
|
|
||||||
else:
|
else:
|
||||||
# An error here is questionable, model is user configurable
|
raise Exception("Unsuported model: " + repr(db_model.value))
|
||||||
raise Exception("Unkonwn agent model: " + model)
|
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@@ -108,6 +93,8 @@ class ExpertAgent(Agent):
|
|||||||
return 'assistant'
|
return 'assistant'
|
||||||
elif sender == 'user':
|
elif sender == 'user':
|
||||||
return 'user'
|
return 'user'
|
||||||
|
elif sender.startswith("tmp-"):
|
||||||
|
return 'assistant'
|
||||||
else:
|
else:
|
||||||
raise Exception("Unsupported sender: " + sender)
|
raise Exception("Unsupported sender: " + sender)
|
||||||
|
|
||||||
|
|||||||
+44
-11
@@ -13,6 +13,7 @@ import replicate
|
|||||||
import database as db
|
import database as db
|
||||||
import agent as agent_mod
|
import agent as agent_mod
|
||||||
import agents as agents_mod
|
import agents as agents_mod
|
||||||
|
import temporary as tmp
|
||||||
from server import start_server
|
from server import start_server
|
||||||
from chat import ChatView, Message, MESSAGE_PAGE_SIZE
|
from chat import ChatView, Message, MESSAGE_PAGE_SIZE
|
||||||
|
|
||||||
@@ -25,6 +26,8 @@ class App(ChatMixin):
|
|||||||
self.remote_connections = {}
|
self.remote_connections = {}
|
||||||
self.streams = {}
|
self.streams = {}
|
||||||
|
|
||||||
|
self.tmp = tmp.State()
|
||||||
|
|
||||||
# Clients
|
# Clients
|
||||||
self.qdrant_client = QdrantClient(path=f"{self.data_directory}/qdrant_data")
|
self.qdrant_client = QdrantClient(path=f"{self.data_directory}/qdrant_data")
|
||||||
|
|
||||||
@@ -67,9 +70,41 @@ class App(ChatMixin):
|
|||||||
|
|
||||||
# --- Agent Methods (Asynchronous) ---
|
# --- Agent Methods (Asynchronous) ---
|
||||||
|
|
||||||
async def create_agent(self, user_id, name, agentname, description, picture, kind, data, main_chat_id=None):
|
async def get_agent(self, agent_id):
|
||||||
|
if tmp.is_tmp_id(agent_id):
|
||||||
|
agent = self.tmp.agents.get(agent_id)
|
||||||
|
else:
|
||||||
|
agent = await db.Agent.get_or_none(id=agent_id)
|
||||||
|
|
||||||
|
if not agent:
|
||||||
|
raise Exception(f"Agent not found with id {agent_id}")
|
||||||
|
return agent
|
||||||
|
|
||||||
|
async def create_agent(self, user_id, name, agentname, description, picture, kind, data, main_chat_id=None, temporary=False):
|
||||||
print("create_agent; user_id, name:", user_id, name)
|
print("create_agent; user_id, name:", user_id, name)
|
||||||
|
|
||||||
|
if temporary:
|
||||||
|
agent = tmp.Agent.create(
|
||||||
|
self,
|
||||||
|
user_id=user_id,
|
||||||
|
name=name,
|
||||||
|
agentname=agentname,
|
||||||
|
main_chat_id=main_chat_id,
|
||||||
|
description=description,
|
||||||
|
picture=picture,
|
||||||
|
kind=kind,
|
||||||
|
data=data or {}
|
||||||
|
)
|
||||||
|
|
||||||
|
if main_chat_id is not None:
|
||||||
|
if tmp.is_tmp_id(main_chat_id):
|
||||||
|
self.tmp.chats[main_chat_id].participants.append(agent.id)
|
||||||
|
else:
|
||||||
|
print(f"ERROR: cannot use {main_chat_id} as main chat for temporary agent {agentname or agent.id}")
|
||||||
|
agent.main_chat_id = None
|
||||||
|
|
||||||
|
return agent.id
|
||||||
|
|
||||||
if main_chat_id is None:
|
if main_chat_id is None:
|
||||||
chat = await db.Chat.create(
|
chat = await db.Chat.create(
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
@@ -97,9 +132,7 @@ class App(ChatMixin):
|
|||||||
return agent.id
|
return agent.id
|
||||||
|
|
||||||
async def update_agent(self, agent_id, name=None, description=None, picture=None, agentname=None, data=None):
|
async def update_agent(self, agent_id, name=None, description=None, picture=None, agentname=None, data=None):
|
||||||
agent = await db.Agent.get_or_none(id=agent_id)
|
agent = await self.get_agent(agent_id)
|
||||||
if not agent:
|
|
||||||
raise Exception(f"Agent not found with id {agent_id}")
|
|
||||||
|
|
||||||
summary = []
|
summary = []
|
||||||
if name is not None:
|
if name is not None:
|
||||||
@@ -120,11 +153,15 @@ class App(ChatMixin):
|
|||||||
agent.data.update(data)
|
agent.data.update(data)
|
||||||
summary.extend([f"data.{k}" for k in data.keys()])
|
summary.extend([f"data.{k}" for k in data.keys()])
|
||||||
|
|
||||||
await agent.save()
|
if db.is_instance(agent):
|
||||||
|
await agent.save()
|
||||||
print(f"Updated agent #{agent.id} fields: {summary}")
|
print(f"Updated agent #{agent.id} fields: {summary}")
|
||||||
|
|
||||||
async def get_agents(self, user_id):
|
async def get_agents(self, user_id):
|
||||||
agents = await db.Agent.filter(user_id=user_id).all()
|
agents = await db.Agent.filter(user_id=user_id).all()
|
||||||
|
if user_id in self.tmp.user_agents:
|
||||||
|
agents += [self.tmp.agents[agent_id] for agent_id in self.tmp.user_agents[user_id]]
|
||||||
|
|
||||||
return [{
|
return [{
|
||||||
"id": agent.id,
|
"id": agent.id,
|
||||||
"name": agent.name,
|
"name": agent.name,
|
||||||
@@ -176,9 +213,7 @@ class App(ChatMixin):
|
|||||||
# --- Agent Control & Actions ---
|
# --- Agent Control & Actions ---
|
||||||
|
|
||||||
async def get_agent_control(self, agent_id):
|
async def get_agent_control(self, agent_id):
|
||||||
agent = await db.Agent.get_or_none(id=agent_id)
|
agent = await self.get_agent(agent_id)
|
||||||
if not agent:
|
|
||||||
raise Exception(f"Agent not found with id {agent_id}")
|
|
||||||
|
|
||||||
agent_class = next((kind for kind in self.agent_classes if kind.identifier == agent.kind), None)
|
agent_class = next((kind for kind in self.agent_classes if kind.identifier == agent.kind), None)
|
||||||
if agent_class is None:
|
if agent_class is None:
|
||||||
@@ -189,9 +224,7 @@ class App(ChatMixin):
|
|||||||
return control
|
return control
|
||||||
|
|
||||||
async def get_agent_config_fields(self, agent_id):
|
async def get_agent_config_fields(self, agent_id):
|
||||||
agent = await db.Agent.get_or_none(id=agent_id)
|
agent = await self.get_agent(agent_id)
|
||||||
if not agent:
|
|
||||||
raise Exception(f"Agent not found with id {agent_id}")
|
|
||||||
|
|
||||||
agent_class = next((it for it in self.agent_classes if it.identifier == agent.kind), None)
|
agent_class = next((it for it in self.agent_classes if it.identifier == agent.kind), None)
|
||||||
if not agent_class:
|
if not agent_class:
|
||||||
|
|||||||
@@ -2,18 +2,27 @@ import asyncio
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import database as db
|
import database as db
|
||||||
|
import temporary as tmp
|
||||||
from chat import ChatView, Message, MESSAGE_PAGE_SIZE
|
from chat import ChatView, Message, MESSAGE_PAGE_SIZE
|
||||||
from stream import Stream
|
from stream import Stream
|
||||||
|
|
||||||
class ChatMixin:
|
class ChatMixin:
|
||||||
async def create_chat(self, user_id, name, description, picture, members=[]):
|
async def create_chat(self, user_id, name, description, picture, members=[], temporary=False):
|
||||||
# Tortoise uses .create() for one-line instantiation and saving
|
if temporary:
|
||||||
chat = await db.Chat.create(
|
chat = tmp.Chat.create(
|
||||||
user_id=user_id,
|
self,
|
||||||
name=name,
|
user_id=user_id,
|
||||||
description=description,
|
name=name,
|
||||||
picture=picture
|
description=description,
|
||||||
)
|
picture=picture
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
chat = await db.Chat.create(
|
||||||
|
user_id=user_id,
|
||||||
|
name=name,
|
||||||
|
description=description,
|
||||||
|
picture=picture
|
||||||
|
)
|
||||||
print(f"Created chat #{chat.id}: {chat.name}")
|
print(f"Created chat #{chat.id}: {chat.name}")
|
||||||
|
|
||||||
for agent_id in members:
|
for agent_id in members:
|
||||||
@@ -24,6 +33,11 @@ class ChatMixin:
|
|||||||
async def get_chats(self, user_id):
|
async def get_chats(self, user_id):
|
||||||
# Direct filtering on the model class
|
# Direct filtering on the model class
|
||||||
chats = await db.Chat.filter(user_id=user_id).all()
|
chats = await db.Chat.filter(user_id=user_id).all()
|
||||||
|
|
||||||
|
tmp_chats = self.tmp.get_user_chats(user_id)
|
||||||
|
if tmp_chats:
|
||||||
|
chats += [self.tmp.chats[chat_id] for chat_id in tmp_chats]
|
||||||
|
|
||||||
return [{
|
return [{
|
||||||
"id": chat.id,
|
"id": chat.id,
|
||||||
"name": chat.name,
|
"name": chat.name,
|
||||||
@@ -32,13 +46,23 @@ class ChatMixin:
|
|||||||
} for chat in chats]
|
} for chat in chats]
|
||||||
|
|
||||||
async def delete_chat(self, chat_id):
|
async def delete_chat(self, chat_id):
|
||||||
# Filtering and deleting is a one-liner
|
if tmp.is_tmp_id(chat_id):
|
||||||
await db.Membership.filter(chat_id=chat_id).delete()
|
chat = self.tmp.chats[chat_id]
|
||||||
await db.Chat.filter(id=chat_id).delete()
|
# TODO: Delete
|
||||||
# TODO: Delete messages from the chat
|
|
||||||
print(f"Deleted chat #{chat_id} and its memberships.")
|
else:
|
||||||
|
# Filtering and deleting is a one-liner
|
||||||
|
await db.Membership.filter(chat_id=chat_id).delete()
|
||||||
|
await db.Chat.filter(id=chat_id).delete()
|
||||||
|
# TODO: Delete messages from the chat
|
||||||
|
print(f"Deleted chat #{chat_id} and its memberships.")
|
||||||
|
|
||||||
async def get_chat_messages(self, chat_id, earliest_index=None):
|
async def get_chat_messages(self, chat_id, earliest_index=None):
|
||||||
|
if tmp.is_tmp_id(chat_id):
|
||||||
|
chat = self.tmp.chats[chat_id]
|
||||||
|
|
||||||
|
return [message.to_json() for message in chat.messages]
|
||||||
|
|
||||||
query = db.Message.filter(chat_id=chat_id)
|
query = db.Message.filter(chat_id=chat_id)
|
||||||
if earliest_index is not None:
|
if earliest_index is not None:
|
||||||
query = query.filter(id__gt=earliest_index)
|
query = query.filter(id__gt=earliest_index)
|
||||||
@@ -58,18 +82,25 @@ class ChatMixin:
|
|||||||
} for message in messages]
|
} for message in messages]
|
||||||
|
|
||||||
async def create_chat_thread(self, chat_id, name=None):
|
async def create_chat_thread(self, chat_id, name=None):
|
||||||
thread = await db.Thread.create(
|
if tmp.is_tmp_id(chat_id):
|
||||||
chat_id=chat_id,
|
thread = tmp.Thread.create(self, chat_id, name)
|
||||||
name=name
|
else:
|
||||||
)
|
thread = await db.Thread.create(
|
||||||
|
chat_id=chat_id,
|
||||||
|
name=name
|
||||||
|
)
|
||||||
print(f"Created thread #{thread.id}: {thread.name}")
|
print(f"Created thread #{thread.id}: {thread.name}")
|
||||||
return thread.id
|
return thread.id
|
||||||
|
|
||||||
async def add_agent_to_chat(self, chat_id, agent_id):
|
async def add_agent_to_chat(self, chat_id, agent_id):
|
||||||
await db.Membership.create(
|
if tmp.is_tmp_id(chat_id):
|
||||||
chat_id=chat_id,
|
chat = self.tmp.chats[chat_id]
|
||||||
agent_id=agent_id
|
chat.participants.append(agent_id)
|
||||||
)
|
else:
|
||||||
|
await db.Membership.create(
|
||||||
|
chat_id=chat_id,
|
||||||
|
agent_id=agent_id
|
||||||
|
)
|
||||||
print(f"Added agent #{agent_id} to chat #{chat_id}")
|
print(f"Added agent #{agent_id} to chat #{chat_id}")
|
||||||
|
|
||||||
async def send_chat_message(self, chat_id, content, sender='user', thread_id=None, kind=None, subkind=None, format=None):
|
async def send_chat_message(self, chat_id, content, sender='user', thread_id=None, kind=None, subkind=None, format=None):
|
||||||
@@ -82,27 +113,49 @@ class ChatMixin:
|
|||||||
|
|
||||||
# Set to true for streams
|
# Set to true for streams
|
||||||
updating = False
|
updating = False
|
||||||
message = await db.Message.create(
|
if tmp.is_tmp_id(chat_id):
|
||||||
chat_id=chat_id,
|
message = Message(
|
||||||
time=now,
|
tmp.generate_tmp_id(self),
|
||||||
last_edit=now,
|
#chat_id=chat_id,
|
||||||
sender=sender,
|
time=now,
|
||||||
kind=kind or 'message',
|
#last_edit=now,
|
||||||
subkind=subkind,
|
sender=sender,
|
||||||
format=format,
|
kind=kind or 'message',
|
||||||
content=initial_content,
|
subkind=subkind,
|
||||||
thread_id=thread_id
|
#format=format,
|
||||||
)
|
content=initial_content,
|
||||||
|
thread_id=thread_id
|
||||||
|
)
|
||||||
|
message.chat_id = chat_id
|
||||||
|
chat = self.tmp.chats[chat_id]
|
||||||
|
chat.messages.append(message)
|
||||||
|
chat_owner_id = chat.user_id
|
||||||
|
else:
|
||||||
|
message = await db.Message.create(
|
||||||
|
chat_id=chat_id,
|
||||||
|
time=now,
|
||||||
|
last_edit=now,
|
||||||
|
sender=sender,
|
||||||
|
kind=kind or 'message',
|
||||||
|
subkind=subkind,
|
||||||
|
format=format,
|
||||||
|
content=initial_content,
|
||||||
|
thread_id=thread_id
|
||||||
|
)
|
||||||
|
|
||||||
# Fetch chat owner using values_list for efficiency
|
# Fetch chat owner using values_list for efficiency
|
||||||
chat = await db.Chat.get(id=chat_id).prefetch_related("user")
|
chat = await db.Chat.get(id=chat_id).prefetch_related("user")
|
||||||
chat_owner_id = chat.user_id
|
chat_owner_id = chat.user_id
|
||||||
|
|
||||||
# Notification order depends on whether the content is a stream
|
# Notification order depends on whether the content is a stream
|
||||||
|
|
||||||
async def notify_agents():
|
async def notify_agents():
|
||||||
# Fetch participant agents
|
# Fetch participant agents
|
||||||
agent_ids = await db.Membership.filter(chat_id=chat_id).values_list("agent_id", flat=True)
|
if tmp.is_tmp_id(chat_id):
|
||||||
|
agent_ids = self.tmp.chats[chat_id].participants
|
||||||
|
else:
|
||||||
|
agent_ids = await db.Membership.filter(chat_id=chat_id).values_list("agent_id", flat=True)
|
||||||
|
|
||||||
for agent_id in agent_ids:
|
for agent_id in agent_ids:
|
||||||
if str(agent_id) != str(sender):
|
if str(agent_id) != str(sender):
|
||||||
await self.notify_message_to_agent(agent_id, message)
|
await self.notify_message_to_agent(agent_id, message)
|
||||||
@@ -120,7 +173,8 @@ class ChatMixin:
|
|||||||
notify_users()
|
notify_users()
|
||||||
async def end_fn ():
|
async def end_fn ():
|
||||||
message.content = content.content
|
message.content = content.content
|
||||||
await message.save()
|
if db.is_instance(message):
|
||||||
|
await message.save()
|
||||||
await notify_agents()
|
await notify_agents()
|
||||||
notify_users()
|
notify_users()
|
||||||
|
|
||||||
@@ -142,7 +196,10 @@ class ChatMixin:
|
|||||||
}
|
}
|
||||||
|
|
||||||
async def update_chat_message(self, message_id, content=None, kind=None, subkind=None, format=None):
|
async def update_chat_message(self, message_id, content=None, kind=None, subkind=None, format=None):
|
||||||
message = await db.Message.get_or_none(id=message_id)
|
if tmp.is_tmp_id(message_id):
|
||||||
|
raise Exception("Cannot update temporary messages")
|
||||||
|
else:
|
||||||
|
message = await db.Message.get_or_none(id=message_id)
|
||||||
|
|
||||||
if not message:
|
if not message:
|
||||||
raise Exception(f"Message not found with id {message_id}")
|
raise Exception(f"Message not found with id {message_id}")
|
||||||
@@ -161,7 +218,8 @@ class ChatMixin:
|
|||||||
summary.append('format')
|
summary.append('format')
|
||||||
|
|
||||||
if summary:
|
if summary:
|
||||||
await message.save() # Saves the specific instance
|
if db.is_instance(message):
|
||||||
|
await message.save() # Saves the specific instance
|
||||||
print(f"Updated message #{message.id} fields: {summary}")
|
print(f"Updated message #{message.id} fields: {summary}")
|
||||||
|
|
||||||
async def get_chat_view(self, chat_id):
|
async def get_chat_view(self, chat_id):
|
||||||
|
|||||||
+40
-13
@@ -3,17 +3,19 @@ from sqlalchemy.orm import Session
|
|||||||
from sqlalchemy.sql.expression import select
|
from sqlalchemy.sql.expression import select
|
||||||
|
|
||||||
import database as db
|
import database as db
|
||||||
|
import temporary as tmp
|
||||||
|
|
||||||
MESSAGE_PAGE_SIZE = 256
|
MESSAGE_PAGE_SIZE = 256
|
||||||
|
|
||||||
class Message:
|
class Message:
|
||||||
def __init__(self, id, content, sender, time=None, kind='message', subkind=None):
|
def __init__(self, id, content, sender, time=None, kind='message', subkind=None, thread_id=None):
|
||||||
self.id = id
|
self.id = id
|
||||||
self.content = content
|
self.content = content
|
||||||
self.sender = sender
|
self.sender = sender
|
||||||
self.time = time
|
self.time = time
|
||||||
self.kind = kind
|
self.kind = kind
|
||||||
self.subkind = subkind
|
self.subkind = subkind
|
||||||
|
self.thread_id = thread_id
|
||||||
|
|
||||||
def from_db_record(record):
|
def from_db_record(record):
|
||||||
return Message(record.id, record.content, record.sender, record.time)
|
return Message(record.id, record.content, record.sender, record.time)
|
||||||
@@ -24,6 +26,16 @@ class Message:
|
|||||||
def is_from_agent(self, agent_id):
|
def is_from_agent(self, agent_id):
|
||||||
return self.sender == str(agent_id)
|
return self.sender == str(agent_id)
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
"id": self.id,
|
||||||
|
"time": self.time,
|
||||||
|
"sender": self.sender,
|
||||||
|
"kind": self.kind,
|
||||||
|
"content": self.content,
|
||||||
|
"threadId": self.thread_id,
|
||||||
|
}
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
time = self.time if self.time != None else 'no-time'
|
time = self.time if self.time != None else 'no-time'
|
||||||
content = self.content.replace("\n", "\\n")
|
content = self.content.replace("\n", "\\n")
|
||||||
@@ -67,14 +79,18 @@ class ChatView:
|
|||||||
self.current_thread_id = None
|
self.current_thread_id = None
|
||||||
|
|
||||||
self._earliest_message_id = None
|
self._earliest_message_id = None
|
||||||
|
self._earliest_message_time = None
|
||||||
|
|
||||||
async def init_load(self):
|
async def init_load(self):
|
||||||
await self._load_basic_data()
|
await self._load_basic_data()
|
||||||
await self._load_next_messages(MESSAGE_PAGE_SIZE)
|
await self._load_next_messages(MESSAGE_PAGE_SIZE)
|
||||||
|
|
||||||
async def _load_basic_data(self):
|
async def _load_basic_data(self):
|
||||||
# Using get_or_none for cleaner existence checks
|
if tmp.is_tmp_id(self.chat_id):
|
||||||
record = await db.Chat.get_or_none(id=self.chat_id)
|
record = self.app.tmp.chats.get(self.chat_id)
|
||||||
|
else:
|
||||||
|
# Using get_or_none for cleaner existence checks
|
||||||
|
record = await db.Chat.get_or_none(id=self.chat_id)
|
||||||
|
|
||||||
if not record:
|
if not record:
|
||||||
raise Exception(f"Chat not found with id {self.chat_id}")
|
raise Exception(f"Chat not found with id {self.chat_id}")
|
||||||
@@ -83,21 +99,32 @@ class ChatView:
|
|||||||
self.description = record.description
|
self.description = record.description
|
||||||
|
|
||||||
async def _load_next_messages(self, load_count):
|
async def _load_next_messages(self, load_count):
|
||||||
# Start building the filter
|
if tmp.is_tmp_id(self.chat_id):
|
||||||
filters = {"chat_id": self.chat_id}
|
chat = self.app.tmp.chats[self.chat_id]
|
||||||
|
record_batch = [
|
||||||
|
msg for msg in chat.messages
|
||||||
|
if not self._earliest_message_time or msg.id < self._earliest_message_time
|
||||||
|
][:load_count]
|
||||||
|
record_batch.reverse()
|
||||||
|
records_rev = record_batch
|
||||||
|
else:
|
||||||
|
# Start building the filter
|
||||||
|
filters = {"chat_id": self.chat_id}
|
||||||
|
|
||||||
# Add the 'earliest message' condition if it exists
|
# Add the 'earliest message' condition if it exists
|
||||||
if self._earliest_message_id is not None:
|
if self._earliest_message_id is not None:
|
||||||
filters["id__lte"] = self._earliest_message_id
|
filters["id__lte"] = self._earliest_message_id
|
||||||
|
|
||||||
# Tortoise query: filter, order, and limit
|
# Tortoise query: filter, order, and limit
|
||||||
# ordering by id is more robust than by time
|
# ordering by id is more robust than by time
|
||||||
records_rev = await db.Message.filter(**filters).order_by("-id").limit(load_count)
|
records_rev = await db.Message.filter(**filters).order_by("-id").limit(load_count)
|
||||||
|
|
||||||
# Update the earliest id for the next load operation
|
# Update the earliest id for the next load operation
|
||||||
if records_rev:
|
if records_rev:
|
||||||
# Note: Since we ordered by -time (descending), index 0 is the newest in this batch
|
# Note: Since we ordered by -time (descending), index 0 is the newest in this batch (highest id/time)
|
||||||
self._earliest_message_id = records_rev[-1].id # The "earliest" is the one with the smallest ID/Time in this set
|
# The "earliest" or oldest is the one with the smallest ID/Time in this set
|
||||||
|
self._earliest_message_id = records_rev[-1].id
|
||||||
|
self._earliest_message_time = records_rev[-1].time
|
||||||
|
|
||||||
if not self.threads:
|
if not self.threads:
|
||||||
# current thread is the latest known from the newest record in batch
|
# current thread is the latest known from the newest record in batch
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ async def init_database (data_directory):
|
|||||||
)
|
)
|
||||||
await Tortoise.generate_schemas()
|
await Tortoise.generate_schemas()
|
||||||
|
|
||||||
|
# Checks whether an object is an instance of any database model
|
||||||
|
def is_instance (value):
|
||||||
|
isinstance(value, models.Model)
|
||||||
|
|
||||||
class User(models.Model):
|
class User(models.Model):
|
||||||
id = fields.IntField(pk=True)
|
id = fields.IntField(pk=True)
|
||||||
email = fields.CharField(max_length=255)
|
email = fields.CharField(max_length=255)
|
||||||
|
|||||||
+36
-24
@@ -1,4 +1,5 @@
|
|||||||
import threading
|
import threading
|
||||||
|
import asyncio
|
||||||
import ollama
|
import ollama
|
||||||
from stream import Stream
|
from stream import Stream
|
||||||
|
|
||||||
@@ -23,22 +24,33 @@ class Models:
|
|||||||
|
|
||||||
# llama cpp models
|
# llama cpp models
|
||||||
model_cache = {}
|
model_cache = {}
|
||||||
|
last_model_file = None
|
||||||
|
last_model_instance = None
|
||||||
|
|
||||||
|
def get_llama_cpp_model(app, model_file):
|
||||||
|
global last_model_file, last_model_instance
|
||||||
|
if last_model_file == model_file:
|
||||||
|
return last_model_instance
|
||||||
|
|
||||||
|
if last_model_instance is not None:
|
||||||
|
#last_model_instance = None
|
||||||
|
del last_model_instance
|
||||||
|
|
||||||
|
last_model_file = model_file
|
||||||
|
last_model_instance = Llama(
|
||||||
|
model_path=f"{app.data_directory}/models/{model_file}",
|
||||||
|
n_gpu_layers=-1, # Uncomment to use GPU acceleration
|
||||||
|
# seed=1337, # Uncomment to set a specific seed
|
||||||
|
n_ctx=CONTEXT_WINDOW,
|
||||||
|
)
|
||||||
|
return last_model_instance
|
||||||
|
|
||||||
# llama.cpp
|
# llama.cpp
|
||||||
async def local_chat_completion(app, messages, model, opts={}):
|
async def local_chat_completion(app, messages, model, opts={}):
|
||||||
content_stream = Stream(app)
|
content_stream = Stream(app)
|
||||||
|
|
||||||
def worker():
|
def worker():
|
||||||
if model in model_cache:
|
llm = get_llama_cpp_model(app, model)
|
||||||
llm = model_cache[model]
|
|
||||||
else:
|
|
||||||
llm = Llama(
|
|
||||||
model_path=f"{app.data_directory}/models/{model}",
|
|
||||||
n_gpu_layers=-1, # Uncomment to use GPU acceleration
|
|
||||||
# seed=1337, # Uncomment to set a specific seed
|
|
||||||
n_ctx=CONTEXT_WINDOW,
|
|
||||||
)
|
|
||||||
model_cache[model] = llm
|
|
||||||
|
|
||||||
temp = opts.get("temperature")
|
temp = opts.get("temperature")
|
||||||
if temp is None:
|
if temp is None:
|
||||||
@@ -77,23 +89,23 @@ async def ollama_list(app, messages, model, opts={}):
|
|||||||
async def ollama_chat_completion(app, messages, model, opts={}):
|
async def ollama_chat_completion(app, messages, model, opts={}):
|
||||||
content_stream = Stream(app)
|
content_stream = Stream(app)
|
||||||
|
|
||||||
print("START OLLAMA INFERENCE")
|
async def worker():
|
||||||
stream_response = await ollama.AsyncClient().chat(
|
print("START OLLAMA INFERENCE")
|
||||||
model=model,
|
stream_response = await ollama.AsyncClient().chat(
|
||||||
messages=[{'role': msg.role, 'content': msg.content} for msg in messages],
|
model=model,
|
||||||
stream=True,
|
messages=[{'role': msg.role, 'content': msg.content} for msg in messages],
|
||||||
)
|
stream=True,
|
||||||
|
)
|
||||||
|
|
||||||
async for part in stream_response:
|
async for part in stream_response:
|
||||||
content_stream.feed(part.message.content)
|
content_stream.feed(part.message.content)
|
||||||
print(part['message']['content'], end='', flush=True)
|
|
||||||
|
|
||||||
content_stream.close()
|
content_stream.close()
|
||||||
|
print("END OLLAMA INFERENCE")
|
||||||
|
|
||||||
print("END OLLAMA INFERENCE")
|
asyncio.create_task(worker())
|
||||||
return await content_stream.content_wait()
|
|
||||||
|
|
||||||
#return content_stream
|
return content_stream
|
||||||
|
|
||||||
|
|
||||||
async def replicate_completion(app, messages, model=None, opts={}):
|
async def replicate_completion(app, messages, model=None, opts={}):
|
||||||
@@ -104,7 +116,7 @@ async def replicate_completion(app, messages, model=None, opts={}):
|
|||||||
|
|
||||||
arguments = {}
|
arguments = {}
|
||||||
arguments[parameter_names.get('prompt', 'prompt')] = format_instruct(messages)
|
arguments[parameter_names.get('prompt', 'prompt')] = format_instruct(messages)
|
||||||
arguments[parameter_names.get('temperature', 'temperature')] = opts.get('temperature', 0.75)
|
arguments[parameter_names.get('temperature', 'temperature')] = opts.get('temperature') or 0.75
|
||||||
arguments[parameter_names.get('max_tokens', 'max_tokens')] = opts.get('max_tokens', 2048)
|
arguments[parameter_names.get('max_tokens', 'max_tokens')] = opts.get('max_tokens', 2048)
|
||||||
|
|
||||||
arguments[parameter_names.get('system_prompt', 'system_prompt')] = ""
|
arguments[parameter_names.get('system_prompt', 'system_prompt')] = ""
|
||||||
|
|||||||
@@ -162,7 +162,8 @@ def start_server(app):
|
|||||||
description=body.get('description'),
|
description=body.get('description'),
|
||||||
picture=body.get('picture'),
|
picture=body.get('picture'),
|
||||||
kind=body['kind'],
|
kind=body['kind'],
|
||||||
data=body.get('data')
|
data=body.get('data'),
|
||||||
|
temporary=body.get('temporary'),
|
||||||
)
|
)
|
||||||
await send({'message': "agent created", 'agentId': agent_id, 'nonce': nonce})
|
await send({'message': "agent created", 'agentId': agent_id, 'nonce': nonce})
|
||||||
|
|
||||||
@@ -216,6 +217,7 @@ def start_server(app):
|
|||||||
description=body.get('description'),
|
description=body.get('description'),
|
||||||
picture=body.get('picture'),
|
picture=body.get('picture'),
|
||||||
members=body.get('members', []),
|
members=body.get('members', []),
|
||||||
|
temporary=body.get('temporary'),
|
||||||
)
|
)
|
||||||
await send({'message': "chat created", 'chatId': chat_id, 'nonce': nonce})
|
await send({'message': "chat created", 'chatId': chat_id, 'nonce': nonce})
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
|
||||||
|
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 = {}
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
@@ -32,6 +32,10 @@
|
|||||||
payload.identifier = agent.value.identifier;
|
payload.identifier = agent.value.identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (agent.value.temporary) {
|
||||||
|
payload.temporary = true;
|
||||||
|
}
|
||||||
|
|
||||||
let response = await backend.sendAction("create-agent", payload);
|
let response = await backend.sendAction("create-agent", payload);
|
||||||
|
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
@@ -54,39 +58,54 @@
|
|||||||
<h1>Create Agent</h1>
|
<h1>Create Agent</h1>
|
||||||
</TitleBar>
|
</TitleBar>
|
||||||
|
|
||||||
<div class="main-container">
|
<section class="container">
|
||||||
<input v-model="agent.name" type="text" placeholder="name">
|
<input v-model="agent.name" placeholder="Name" />
|
||||||
<input v-model="agent.identifier" type="text" placeholder="identifier">
|
<input v-model="agent.identifier" placeholder="Identifier (optional)" />
|
||||||
<select v-model="agent.kind">
|
<select v-model="agent.kind" :class="{ placeholder: !agent.kind }">
|
||||||
<option v-for="k in kinds" :value="k">{{k}}</option>
|
<option value="" disabled>Select type</option>
|
||||||
|
<option v-for="k in kinds" :key="k" :value="k">{{ k }}</option>
|
||||||
</select>
|
</select>
|
||||||
|
<label class="checkbox">
|
||||||
<button @click="submitAgent()">Create Agent</button>
|
<input type="checkbox" v-model="agent.temporary" />
|
||||||
</div>
|
Temporary
|
||||||
|
</label>
|
||||||
|
<button @click="submitAgent()">Create</button>
|
||||||
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.main-container {
|
section {
|
||||||
display: flex;
|
margin: 1em;
|
||||||
flex-direction: column;
|
padding: 1em;
|
||||||
}
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
.multi-select-box {
|
}
|
||||||
border: 1px solid var(--color-border);
|
.container {
|
||||||
border-radius: var(--border-radius);
|
display: flex;
|
||||||
}
|
flex-direction: column;
|
||||||
|
}
|
||||||
.multi-select-box div {
|
input, select {
|
||||||
border-bottom: 1px solid var(--color-border);
|
padding: 10px;
|
||||||
}
|
border: 1px solid var(--color-border);
|
||||||
.multi-select-box div:last {
|
border-radius: 6px;
|
||||||
border-bottom: none;
|
font-size: 14px;
|
||||||
}
|
background: var(--color-background);
|
||||||
.multi-select-box div:hover {
|
}
|
||||||
background-color: var(--color-background-mute);
|
input::placeholder, select.placeholder {
|
||||||
}
|
color: var(--color-text-light);
|
||||||
.multi-select-box div.selected {
|
}
|
||||||
background-color: var(--color-background-soft);
|
input:focus, select:focus { outline: none; border-color: var(--color-primary); }
|
||||||
}
|
.checkbox { display: flex; align-items: center; gap: 6px; cursor: pointer; }
|
||||||
|
button {
|
||||||
|
margin-top: 4px;
|
||||||
|
padding: 10px;
|
||||||
|
background: var(--color-primary);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
button:hover { opacity: 0.9; }
|
||||||
</style>
|
</style>
|
||||||
@@ -59,11 +59,9 @@
|
|||||||
// === State Management === //
|
// === State Management === //
|
||||||
|
|
||||||
async function loadChatState (newId) {
|
async function loadChatState (newId) {
|
||||||
chatId = parseInt(newId);
|
// This line was converting newId into an integer.
|
||||||
if (chatId == null || isNaN(chatId)) {
|
// Some parts of the program may still rely on it.
|
||||||
console.error("Invalid chat id", chatId);
|
chatId = newId;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an agent name dictionary
|
// Create an agent name dictionary
|
||||||
const _agents = await backend.getAgents();
|
const _agents = await backend.getAgents();
|
||||||
@@ -307,7 +305,7 @@
|
|||||||
|
|
||||||
async function startNewThread () {
|
async function startNewThread () {
|
||||||
const res = await backend.sendAction("create-chat-thread", {chatId});
|
const res = await backend.sendAction("create-chat-thread", {chatId});
|
||||||
console.log("Starting a new thread", res);
|
console.log("Starting a nedeleteChatw thread", res);
|
||||||
if (res.threadId != null) {
|
if (res.threadId != null) {
|
||||||
currentThreadId.value = res.threadId;
|
currentThreadId.value = res.threadId;
|
||||||
expandThread(res.threadId, true);
|
expandThread(res.threadId, true);
|
||||||
@@ -325,6 +323,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function deleteChat (chat) {
|
||||||
|
if (!await ui.confirm(`Delete Chat ${chat.name} with id ${chat.id}`)) return;
|
||||||
|
const res = await backend.sendAction("delete-chat", {chatId: chat.id});
|
||||||
|
console.log("Chat Delete Output", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function renameChat (chat) {
|
||||||
|
ui.alert("TODO: Rename Chats");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// === Special Chat Functions === //
|
// === Special Chat Functions === //
|
||||||
|
|
||||||
@@ -418,6 +426,10 @@
|
|||||||
<main>
|
<main>
|
||||||
<TitleBar>
|
<TitleBar>
|
||||||
<h1>{{ chat.name || 'Chat #' + chat.id }}</h1>
|
<h1>{{ chat.name || 'Chat #' + chat.id }}</h1>
|
||||||
|
<div>
|
||||||
|
<button @click="renameChat(chat)">Rename</button>
|
||||||
|
<button @click="deleteChat(chat)">Delete</button>
|
||||||
|
</div>
|
||||||
</TitleBar>
|
</TitleBar>
|
||||||
|
|
||||||
<div class="messages-container" ref="chatContainerElem">
|
<div class="messages-container" ref="chatContainerElem">
|
||||||
|
|||||||
@@ -12,14 +12,20 @@
|
|||||||
// List of agents, with their id, name, and whether they're currently selected
|
// List of agents, with their id, name, and whether they're currently selected
|
||||||
const agents = ref([]);
|
const agents = ref([]);
|
||||||
const title = ref("");
|
const title = ref("");
|
||||||
|
const temporary = ref(false);
|
||||||
|
|
||||||
async function submitChat () {
|
async function submitChat () {
|
||||||
const selectedAgents = agents.value.filter(agent => agent.selected).map(agent => agent.id);
|
const selectedAgents = agents.value.filter(agent => agent.selected).map(agent => agent.id);
|
||||||
|
|
||||||
let response = await backend.sendAction("create-chat", {
|
let payload = {
|
||||||
'name': title.value,
|
'name': title.value,
|
||||||
'members': selectedAgents,
|
'members': selectedAgents,
|
||||||
});
|
};
|
||||||
|
if (temporary.value) {
|
||||||
|
payload.temporary = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = await backend.sendAction("create-chat", payload);
|
||||||
|
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
ui.alert(`Could not create chat\n${response.error}`);
|
ui.alert(`Could not create chat\n${response.error}`);
|
||||||
@@ -50,6 +56,10 @@
|
|||||||
<div class="multi-select-box">
|
<div class="multi-select-box">
|
||||||
<div v-for="agent in agents" :class="{selected: Boolean(agent.selected)}" @click="agent.selected = !agent.selected">{{agent.name}}</div>
|
<div v-for="agent in agents" :class="{selected: Boolean(agent.selected)}" @click="agent.selected = !agent.selected">{{agent.name}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<label class="checkbox">
|
||||||
|
<input type="checkbox" v-model="temporary" />
|
||||||
|
Temporary
|
||||||
|
</label>
|
||||||
<button @click="submitChat()">Create Chat</button>
|
<button @click="submitChat()">Create Chat</button>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"ws": "^8.20.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,14 +21,15 @@ case "$1" in
|
|||||||
;;
|
;;
|
||||||
"test")
|
"test")
|
||||||
# Setup test data directory
|
# Setup test data directory
|
||||||
mkdir -p test-data
|
data_dir=$(realpath ./test-data)
|
||||||
rm -f test-data/horde.db
|
mkdir -p $data_dir
|
||||||
|
rm -rf $data_dir/*
|
||||||
|
|
||||||
# Start backend in the background
|
# Start backend in the background
|
||||||
python backend/src/app.py ../test-data &
|
python backend/src/app.py $data_dir &
|
||||||
BACKEND_PID=$!
|
BACKEND_PID=$!
|
||||||
echo "Started backend: $BACKEND_PID"
|
echo "Started backend: $BACKEND_PID"
|
||||||
sleep 2
|
sleep 5
|
||||||
|
|
||||||
# Run tests
|
# Run tests
|
||||||
cd testing
|
cd testing
|
||||||
|
|||||||
+16
-1
@@ -1,6 +1,6 @@
|
|||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
|
|
||||||
const USE_LLM = true;
|
const USE_LLM = false;
|
||||||
|
|
||||||
const hostname = 'localhost:5000';
|
const hostname = 'localhost:5000';
|
||||||
const ws = new WebSocket(`ws://${hostname}/ws`);
|
const ws = new WebSocket(`ws://${hostname}/ws`);
|
||||||
@@ -144,6 +144,7 @@ async function runTest() {
|
|||||||
));
|
));
|
||||||
|
|
||||||
await testChats();
|
await testChats();
|
||||||
|
await testTemporary();
|
||||||
|
|
||||||
if (USE_LLM) {
|
if (USE_LLM) {
|
||||||
await testGral(mainAgentId);
|
await testGral(mainAgentId);
|
||||||
@@ -181,6 +182,20 @@ async function testChats () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function testTemporary () {
|
||||||
|
let createAgentResponse = await send('create-agent', {body: {
|
||||||
|
name: 'First Agent',
|
||||||
|
description: 'First agent does nothing',
|
||||||
|
kind: 'expert',
|
||||||
|
temporary: true,
|
||||||
|
data: {
|
||||||
|
system_prompt: 'you respond every message with only the world "Acknowledged"',
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
|
||||||
|
console.log("Created Temporary Agent: ", createAgentResponse);
|
||||||
|
}
|
||||||
|
|
||||||
async function testGral (agentId) {
|
async function testGral (agentId) {
|
||||||
let res = await send('call-agent-action', {
|
let res = await send('call-agent-action', {
|
||||||
body: {
|
body: {
|
||||||
|
|||||||
Reference in new issue
Block a user