This commit is contained in:
+68
-5
@@ -31,6 +31,7 @@ from traderai.starcitizen_wiki_client import StarCitizenWikiClient
|
||||
from traderai.tools import ToolRegistry
|
||||
from traderai.uex_client import UEXClient
|
||||
from traderai.version import RELEASES_API_URL, RELEASES_URL, __version__
|
||||
from traderai.wikelo_projects_client import WikeloProjectsClient
|
||||
|
||||
|
||||
def resource_path(*parts: str) -> Path:
|
||||
@@ -85,6 +86,14 @@ class ContinualPlanCreateRequest(BaseModel):
|
||||
items: list[ContinualPlanItemRequest] = []
|
||||
|
||||
|
||||
class ContinualPlanDraftRequest(BaseModel):
|
||||
title: str = ""
|
||||
objective: str = ""
|
||||
kind: str = "buying"
|
||||
constraints: dict[str, Any] = {}
|
||||
items: list[ContinualPlanItemRequest] = []
|
||||
|
||||
|
||||
class ContinualPlanEventRequest(BaseModel):
|
||||
kind: str = "note"
|
||||
message: str
|
||||
@@ -115,6 +124,7 @@ def create_app() -> FastAPI:
|
||||
scmdb = SCMDBClient(current_settings.scmdb_base_url)
|
||||
cornerstone = CornerstoneClient(current_settings.cornerstone_base_url)
|
||||
scwiki = StarCitizenWikiClient(current_settings.scwiki_base_url, current_settings.scwiki_api_base_url)
|
||||
wikelo = WikeloProjectsClient()
|
||||
tools = ToolRegistry(
|
||||
uex,
|
||||
current_settings.require_write_approval,
|
||||
@@ -123,6 +133,7 @@ def create_app() -> FastAPI:
|
||||
scmdb=scmdb,
|
||||
cornerstone=cornerstone,
|
||||
scwiki=scwiki,
|
||||
wikelo=wikelo,
|
||||
plan_store=plan_store,
|
||||
)
|
||||
plan_runner = ContinualPlanRunner(plan_store, tools, memory)
|
||||
@@ -493,6 +504,18 @@ def create_app() -> FastAPI:
|
||||
raise HTTPException(status_code=400, detail=result["error"])
|
||||
return result
|
||||
|
||||
@app.post("/api/plans/draft")
|
||||
async def draft_continual_plan(request: ContinualPlanDraftRequest) -> dict:
|
||||
agent = runtime["agent"]
|
||||
draft = await agent.generate_plan_draft(
|
||||
title=request.title,
|
||||
objective=request.objective,
|
||||
kind=request.kind,
|
||||
constraints=request.constraints,
|
||||
items=[item.model_dump() for item in request.items],
|
||||
)
|
||||
return {"draft": draft}
|
||||
|
||||
@app.get("/api/plans/{plan_id}")
|
||||
async def continual_plan(plan_id: str) -> dict:
|
||||
plan = plan_store.get_plan(plan_id)
|
||||
@@ -592,6 +615,8 @@ async def inspect_model_provider() -> dict[str, Any]:
|
||||
settings = get_settings()
|
||||
if settings.model_provider == "openai":
|
||||
return await inspect_openai()
|
||||
if settings.model_provider == "deepseek":
|
||||
return await inspect_deepseek()
|
||||
if settings.model_provider == "codex":
|
||||
return await inspect_codex()
|
||||
return await inspect_ollama()
|
||||
@@ -602,6 +627,16 @@ async def inspect_openai() -> dict[str, Any]:
|
||||
return await inspect_cloud_provider_config("openai", settings.openai_base_url, settings.openai_api_key, settings.openai_model)
|
||||
|
||||
|
||||
async def inspect_deepseek() -> dict[str, Any]:
|
||||
settings = get_settings()
|
||||
return await inspect_cloud_provider_config(
|
||||
"deepseek",
|
||||
settings.deepseek_base_url,
|
||||
settings.deepseek_api_key,
|
||||
settings.deepseek_model,
|
||||
)
|
||||
|
||||
|
||||
async def inspect_codex() -> dict[str, Any]:
|
||||
settings = get_settings()
|
||||
command = find_codex_cli(settings.codex_command)
|
||||
@@ -638,6 +673,8 @@ async def inspect_cloud_provider() -> dict[str, Any]:
|
||||
settings = get_settings()
|
||||
if settings.model_provider == "codex":
|
||||
return await inspect_codex()
|
||||
if settings.model_provider == "deepseek":
|
||||
return await inspect_deepseek()
|
||||
return await inspect_openai()
|
||||
|
||||
|
||||
@@ -647,6 +684,8 @@ async def inspect_provider_models(provider: str | None = None) -> dict[str, Any]
|
||||
return await inspect_codex()
|
||||
if normalized == "ollama":
|
||||
return await inspect_ollama()
|
||||
if normalized == "deepseek":
|
||||
return await inspect_deepseek()
|
||||
return await inspect_openai()
|
||||
|
||||
|
||||
@@ -669,8 +708,8 @@ async def inspect_cloud_provider_config(
|
||||
"provider": provider,
|
||||
"model_available": False,
|
||||
"configured_model": model,
|
||||
"configured_reasoning_effort": settings.model_reasoning_effort,
|
||||
"reasoning_efforts": reasoning_effort_options(),
|
||||
"configured_reasoning_effort": canonical_provider_reasoning_effort(provider, settings.model_reasoning_effort),
|
||||
"reasoning_efforts": provider_reasoning_efforts(provider, model),
|
||||
"base_url": base_url,
|
||||
"models": [],
|
||||
"message": f"{provider_name} is selected, but no API key is configured.",
|
||||
@@ -698,8 +737,8 @@ async def inspect_cloud_provider_config(
|
||||
"provider": provider,
|
||||
"model_available": model_available,
|
||||
"configured_model": model,
|
||||
"configured_reasoning_effort": settings.model_reasoning_effort,
|
||||
"reasoning_efforts": reasoning_effort_options(),
|
||||
"configured_reasoning_effort": canonical_provider_reasoning_effort(provider, settings.model_reasoning_effort),
|
||||
"reasoning_efforts": provider_reasoning_efforts(provider, model),
|
||||
"base_url": base_url,
|
||||
"models": models,
|
||||
"message": cloud_status_message(provider, online, bool(api_key), model_available, model),
|
||||
@@ -783,13 +822,15 @@ def codex_status_message(installed: bool, logged_in: bool, model_available: bool
|
||||
def provider_settings(settings: Any) -> tuple[str, str, str | None]:
|
||||
if settings.model_provider == "openai":
|
||||
return settings.openai_base_url, settings.openai_model, settings.openai_api_key
|
||||
if settings.model_provider == "deepseek":
|
||||
return settings.deepseek_base_url, settings.deepseek_model, settings.deepseek_api_key
|
||||
if settings.model_provider == "codex":
|
||||
return settings.codex_command, settings.codex_model, None
|
||||
return settings.ollama_base_url, settings.ollama_model, None
|
||||
|
||||
|
||||
def provider_display_name(provider: str) -> str:
|
||||
return {"openai": "OpenAI", "codex": "Codex"}.get(provider, "Ollama")
|
||||
return {"openai": "OpenAI", "deepseek": "DeepSeek", "codex": "Codex"}.get(provider, "Ollama")
|
||||
|
||||
|
||||
def find_codex_cli(configured_command: str | None = None) -> Path | None:
|
||||
@@ -1056,6 +1097,28 @@ def reasoning_effort_options() -> list[str]:
|
||||
return ["none", "minimal", "low", "medium", "high", "xhigh"]
|
||||
|
||||
|
||||
def deepseek_reasoning_efforts(model: str) -> list[str]:
|
||||
supported_models = {"deepseek-v4-flash", "deepseek-v4-pro", "deepseek-chat", "deepseek-reasoner"}
|
||||
return ["none", "high", "max"] if model in supported_models else ["none", "high"]
|
||||
|
||||
|
||||
def provider_reasoning_efforts(provider: str, model: str) -> list[str]:
|
||||
if provider == "deepseek":
|
||||
return deepseek_reasoning_efforts(model)
|
||||
return reasoning_effort_options()
|
||||
|
||||
|
||||
def canonical_provider_reasoning_effort(provider: str, effort: str) -> str:
|
||||
normalized = str(effort or "medium").strip().casefold()
|
||||
if provider != "deepseek":
|
||||
return normalized
|
||||
if normalized in {"none", "minimal"}:
|
||||
return "none"
|
||||
if normalized in {"xhigh", "max"}:
|
||||
return "max"
|
||||
return "high"
|
||||
|
||||
|
||||
def find_ollama_executable() -> Path | None:
|
||||
candidates = [
|
||||
shutil.which("ollama"),
|
||||
|
||||
Reference in New Issue
Block a user