feat: chat
This commit is contained in:
@@ -8,6 +8,7 @@ from typing import Any, Awaitable, Callable
|
||||
|
||||
from traderai.cornerstone_client import CornerstoneClient, parse_cornerstone_item_page
|
||||
from traderai.memory import MemoryStore
|
||||
from traderai.negotiations import UEX_NEGOTIATION_CLOSE_ENDPOINT
|
||||
from traderai.scheduler import WakeScheduler
|
||||
from traderai.scmdb_client import SCMDBClient
|
||||
from traderai.starcitizen_wiki_client import StarCitizenWikiClient
|
||||
@@ -150,6 +151,7 @@ UEX_RESOURCE_DESCRIPTIONS = {
|
||||
UEX_PRODUCTION_WRITE_RESOURCES = {
|
||||
"marketplace_advertise",
|
||||
"marketplace_negotiations_messages",
|
||||
UEX_NEGOTIATION_CLOSE_ENDPOINT,
|
||||
}
|
||||
|
||||
|
||||
@@ -176,6 +178,7 @@ class ToolRegistry:
|
||||
wikelo: WikeloProjectsClient | None = None,
|
||||
plan_store: Any | None = None,
|
||||
plan_runner: Any | None = None,
|
||||
negotiation_sync: Any | None = None,
|
||||
) -> None:
|
||||
self.uex = uex
|
||||
self.scmdb = scmdb or SCMDBClient()
|
||||
@@ -187,6 +190,7 @@ class ToolRegistry:
|
||||
self.scheduler = scheduler
|
||||
self.plan_store = plan_store
|
||||
self.plan_runner = plan_runner
|
||||
self.negotiation_sync = negotiation_sync
|
||||
self.pending_actions: dict[str, PendingAction] = {}
|
||||
self._chat_images_var: ContextVar[list[dict[str, Any]]] = ContextVar("chat_images", default=[])
|
||||
self.handlers: dict[str, ToolHandler] = {
|
||||
@@ -196,6 +200,11 @@ class ToolRegistry:
|
||||
"list_marketplace_negotiations": self.list_marketplace_negotiations,
|
||||
"get_negotiation_messages": self.get_negotiation_messages,
|
||||
"draft_negotiation_message": self.draft_negotiation_message,
|
||||
"list_local_negotiations": self.list_local_negotiations,
|
||||
"get_local_negotiation": self.get_local_negotiation,
|
||||
"search_local_negotiation_messages": self.search_local_negotiation_messages,
|
||||
"draft_negotiation_close": self.draft_negotiation_close,
|
||||
"draft_negotiation_rating": self.draft_negotiation_rating,
|
||||
"draft_marketplace_listing": self.draft_marketplace_listing,
|
||||
"remember_user_fact": self.remember_user_fact,
|
||||
"recall_memory": self.recall_memory,
|
||||
@@ -354,6 +363,97 @@ class ToolRegistry:
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "list_local_negotiations",
|
||||
"description": "List locally synced UEX negotiations with unread and status details.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {"type": "string", "enum": ["all", "open", "closed"]},
|
||||
"unread_only": {"type": "boolean"},
|
||||
"search": {"type": "string"},
|
||||
"limit": {"type": "integer", "minimum": 1, "maximum": 50},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_local_negotiation",
|
||||
"description": "Get a locally synced UEX negotiation with compact metadata and recent messages.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hash": {"type": "string"},
|
||||
},
|
||||
"required": ["hash"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "search_local_negotiation_messages",
|
||||
"description": "Search locally cached negotiation message text so the assistant can reference prior UEX conversations without re-fetching them.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {"type": "string"},
|
||||
"limit": {"type": "integer", "minimum": 1, "maximum": 20},
|
||||
},
|
||||
"required": ["query"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "draft_negotiation_close",
|
||||
"description": "Draft closing or rating a UEX negotiation. This creates a pending action that must be approved before sending.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hash": {"type": "string"},
|
||||
"id_negotiation": {"type": "integer"},
|
||||
"deal_closed": {"type": "boolean"},
|
||||
"deal_value": {"type": "number"},
|
||||
"currency": {"type": "string"},
|
||||
"clarity_rating": {"type": "integer", "minimum": 1, "maximum": 5},
|
||||
"speed_rating": {"type": "integer", "minimum": 1, "maximum": 5},
|
||||
"respect_rating": {"type": "integer", "minimum": 1, "maximum": 5},
|
||||
"fairness_rating": {"type": "integer", "minimum": 1, "maximum": 5},
|
||||
"comment": {"type": "string"},
|
||||
},
|
||||
"required": ["deal_closed"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "draft_negotiation_rating",
|
||||
"description": "Alias for drafting a UEX negotiation close/rating action.",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hash": {"type": "string"},
|
||||
"id_negotiation": {"type": "integer"},
|
||||
"deal_closed": {"type": "boolean"},
|
||||
"deal_value": {"type": "number"},
|
||||
"currency": {"type": "string"},
|
||||
"clarity_rating": {"type": "integer", "minimum": 1, "maximum": 5},
|
||||
"speed_rating": {"type": "integer", "minimum": 1, "maximum": 5},
|
||||
"respect_rating": {"type": "integer", "minimum": 1, "maximum": 5},
|
||||
"fairness_rating": {"type": "integer", "minimum": 1, "maximum": 5},
|
||||
"comment": {"type": "string"},
|
||||
},
|
||||
"required": ["deal_closed"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
@@ -1418,6 +1518,37 @@ class ToolRegistry:
|
||||
async def get_negotiation_messages(self, hash: str | None = None, id_negotiation: int | None = None) -> dict[str, Any]:
|
||||
return await self.uex.get("marketplace_negotiations_messages", {"hash": hash, "id_negotiation": id_negotiation}, authenticated=True)
|
||||
|
||||
async def list_local_negotiations(
|
||||
self,
|
||||
status: str = "all",
|
||||
unread_only: bool = False,
|
||||
search: str = "",
|
||||
limit: int = 10,
|
||||
) -> dict[str, Any]:
|
||||
if self.negotiation_sync is None:
|
||||
return {"error": "Negotiation sync is not configured."}
|
||||
negotiations = self.negotiation_sync.list_negotiations(
|
||||
status=status,
|
||||
unread_only=unread_only,
|
||||
search=search,
|
||||
limit=limit,
|
||||
)
|
||||
return {"count": len(negotiations), "negotiations": negotiations}
|
||||
|
||||
async def get_local_negotiation(self, hash: str) -> dict[str, Any]:
|
||||
if self.negotiation_sync is None:
|
||||
return {"error": "Negotiation sync is not configured."}
|
||||
negotiation = self.negotiation_sync.get_negotiation(hash, mark_read=False)
|
||||
if not negotiation:
|
||||
return {"error": f"Negotiation not found: {hash}"}
|
||||
return {"negotiation": negotiation}
|
||||
|
||||
async def search_local_negotiation_messages(self, query: str, limit: int = 8) -> dict[str, Any]:
|
||||
if self.negotiation_sync is None:
|
||||
return {"error": "Negotiation sync is not configured."}
|
||||
matches = self.negotiation_sync.search_messages(query, limit=limit)
|
||||
return {"count": len(matches), "matches": matches}
|
||||
|
||||
async def draft_negotiation_message(
|
||||
self,
|
||||
message: str,
|
||||
@@ -1453,6 +1584,41 @@ class ToolRegistry:
|
||||
metadata=attached_image.get("metadata"),
|
||||
)
|
||||
|
||||
async def draft_negotiation_close(
|
||||
self,
|
||||
deal_closed: bool,
|
||||
hash: str | None = None,
|
||||
id_negotiation: int | None = None,
|
||||
deal_value: float | None = None,
|
||||
currency: str | None = None,
|
||||
clarity_rating: int | None = None,
|
||||
speed_rating: int | None = None,
|
||||
respect_rating: int | None = None,
|
||||
fairness_rating: int | None = None,
|
||||
comment: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
payload = {
|
||||
"hash": hash,
|
||||
"id_negotiation": id_negotiation,
|
||||
"deal_closed": 1 if deal_closed else 0,
|
||||
"deal_value": deal_value,
|
||||
"currency": currency,
|
||||
"clarity_rating": clarity_rating,
|
||||
"speed_rating": speed_rating,
|
||||
"respect_rating": respect_rating,
|
||||
"fairness_rating": fairness_rating,
|
||||
"comment": comment,
|
||||
}
|
||||
metadata = {
|
||||
"hash": hash,
|
||||
"id_negotiation": id_negotiation,
|
||||
"kind": "negotiation_close",
|
||||
}
|
||||
return self._pending("Close negotiation", UEX_NEGOTIATION_CLOSE_ENDPOINT, payload, metadata=metadata)
|
||||
|
||||
async def draft_negotiation_rating(self, **payload: Any) -> dict[str, Any]:
|
||||
return await self.draft_negotiation_close(**payload)
|
||||
|
||||
async def draft_marketplace_listing_with_cornerstone_image(
|
||||
self,
|
||||
item_query: str,
|
||||
|
||||
Reference in New Issue
Block a user