feat: deepseek
Build Release EXE / build-windows-exe (release) Successful in 1m2s

This commit is contained in:
2026-06-08 23:41:46 -04:00
parent 00cf6f8747
commit 454bb57484
24 changed files with 1719 additions and 183 deletions
+140
View File
@@ -12,6 +12,7 @@ from traderai.scheduler import WakeScheduler
from traderai.scmdb_client import SCMDBClient
from traderai.starcitizen_wiki_client import StarCitizenWikiClient
from traderai.uex_client import UEXClient
from traderai.wikelo_projects_client import WikeloProjectsClient
ToolHandler = Callable[..., Awaitable[dict[str, Any]]]
@@ -172,6 +173,7 @@ class ToolRegistry:
scmdb: SCMDBClient | None = None,
cornerstone: CornerstoneClient | None = None,
scwiki: StarCitizenWikiClient | None = None,
wikelo: WikeloProjectsClient | None = None,
plan_store: Any | None = None,
plan_runner: Any | None = None,
) -> None:
@@ -179,6 +181,7 @@ class ToolRegistry:
self.scmdb = scmdb or SCMDBClient()
self.cornerstone = cornerstone or CornerstoneClient()
self.scwiki = scwiki or StarCitizenWikiClient()
self.wikelo = wikelo or WikeloProjectsClient()
self.require_write_approval = require_write_approval
self.memory = memory
self.scheduler = scheduler
@@ -214,6 +217,8 @@ class ToolRegistry:
"get_scwiki_page": self.get_scwiki_page,
"search_scwiki_vehicles": self.search_scwiki_vehicles,
"get_scwiki_vehicle": self.get_scwiki_vehicle,
"search_wikelo_ship_projects": self.search_wikelo_ship_projects,
"get_wikelo_ship_project": self.get_wikelo_ship_project,
"search_cornerstone_items": self.search_cornerstone_items,
"get_cornerstone_item_locations": self.get_cornerstone_item_locations,
"get_cornerstone_item_media": self.get_cornerstone_item_media,
@@ -244,6 +249,7 @@ class ToolRegistry:
*self._uex_delete_schemas(),
*self._scmdb_schemas(),
*self._scwiki_schemas(),
*self._wikelo_schemas(),
*self._cornerstone_schemas(),
{
"type": "function",
@@ -1071,6 +1077,39 @@ class ToolRegistry:
},
]
@classmethod
def _wikelo_schemas(cls) -> list[dict[str, Any]]:
return [
{
"type": "function",
"function": {
"name": "search_wikelo_ship_projects",
"description": "Search Wikelo ship projects and their required materials from wikelo-projects.com. Use this when the user asks for Wikelo ship requirements or build materials.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Ship or project name to search for, such as Polaris, Idris, Zeus, or Guardian."},
"limit": {"type": "integer", "minimum": 1, "maximum": 10, "default": 5},
},
},
},
},
{
"type": "function",
"function": {
"name": "get_wikelo_ship_project",
"description": "Fetch one Wikelo ship project with its required materials and contribution progress.",
"parameters": {
"type": "object",
"properties": {
"project_id": {"type": "string", "description": "Wikelo ship project id."},
"ship_name": {"type": "string", "description": "Ship or project name if the project id is not known."},
},
},
},
},
]
@classmethod
def _cornerstone_schemas(cls) -> list[dict[str, Any]]:
return [
@@ -1740,6 +1779,51 @@ class ToolRegistry:
vehicle = await self.scwiki.get_vehicle(resolved_slug)
return {"source": self.scwiki.api_base_url, "vehicle": self._summarize_scwiki_vehicle(vehicle)}
async def search_wikelo_ship_projects(self, query: str, limit: int = 5) -> dict[str, Any]:
projects = await self.wikelo.list_ship_projects()
q = (query or "").casefold().strip()
matches = []
for project in projects:
score = self._wikelo_ship_match_score(q, project)
if q and score <= 0:
continue
matches.append((score, project))
matches.sort(
key=lambda match: (
-match[0],
str(match[1].get("ship_name") or "").casefold(),
str(match[1].get("id") or ""),
)
)
limit = max(1, min(limit, 10))
return {
"source": f"{self.wikelo.base_url}/Ships",
"query": query,
"matched": len(matches),
"projects": [self._summarize_wikelo_ship_project(item) for _, item in matches[:limit]],
}
async def get_wikelo_ship_project(self, project_id: str | None = None, ship_name: str | None = None) -> dict[str, Any]:
projects = await self.wikelo.list_ship_projects()
if project_id:
for project in projects:
if str(project.get("id") or "").strip() == str(project_id).strip():
return {"source": f"{self.wikelo.base_url}/Ships", "project": self._summarize_wikelo_ship_project(project, detailed=True)}
return {"error": "No Wikelo ship project matched that id."}
if not ship_name:
return {"error": "Provide project_id or ship_name."}
ranked = [
(self._wikelo_ship_match_score(ship_name.casefold().strip(), project), project)
for project in projects
]
ranked = [match for match in ranked if match[0] > 0]
ranked.sort(key=lambda match: (-match[0], str(match[1].get("ship_name") or "").casefold()))
if not ranked:
return {"error": "No Wikelo ship project matched."}
return {"source": f"{self.wikelo.base_url}/Ships", "project": self._summarize_wikelo_ship_project(ranked[0][1], detailed=True)}
async def search_cornerstone_items(
self,
query: str = "",
@@ -2492,6 +2576,62 @@ class ToolRegistry:
"version": vehicle.get("version"),
}
@staticmethod
def _wikelo_ship_match_score(query: str, project: dict[str, Any]) -> int:
if not query:
return 1
ship_name = str(project.get("ship_name") or "").casefold()
description = str(project.get("description") or "").casefold()
materials = " ".join(
str(item.get("material_name") or "").casefold()
for item in (project.get("required_materials") or [])
if isinstance(item, dict)
)
haystack = " ".join(part for part in [ship_name, description, materials] if part)
if ship_name == query:
return 10000
if query in ship_name:
return 9000 - ship_name.index(query)
if query in description:
return 7000 - description.index(query)
if query in materials:
return 5000 - materials.index(query)
tokens = [token for token in query.split() if token]
if tokens and all(token in haystack for token in tokens):
return 3000 - len(haystack)
return 0
@classmethod
def _summarize_wikelo_ship_project(cls, project: dict[str, Any], detailed: bool = False) -> dict[str, Any]:
materials = []
for item in (project.get("required_materials") or []):
if not isinstance(item, dict):
continue
quantity_needed = item.get("quantity_needed")
quantity_collected = item.get("quantity_collected")
materials.append(
{
"material_name": item.get("material_name"),
"quantity_needed": int(quantity_needed) if isinstance(quantity_needed, (int, float)) and float(quantity_needed).is_integer() else quantity_needed,
"quantity_collected": int(quantity_collected) if isinstance(quantity_collected, (int, float)) and float(quantity_collected).is_integer() else quantity_collected,
}
)
summary = {
"id": project.get("id"),
"ship_name": project.get("ship_name"),
"description": project.get("description"),
"status": project.get("status"),
"privacy": project.get("privacy"),
"owner_name": project.get("owner_name"),
"org_name": project.get("org_name"),
"home_port": project.get("home_port"),
"ship_image": project.get("ship_image"),
"materials_count": len(materials),
"required_materials": materials if detailed else materials[:12],
"source_url": f"https://wikelo-projects.com/Ships",
}
return {key: value for key, value in summary.items() if value not in (None, "", [], {})}
@classmethod
def _summarize_negotiation(cls, negotiation: dict[str, Any]) -> dict[str, Any]:
summary = cls._project_item(negotiation, mode="summary")