This commit is contained in:
+110
-5
@@ -86,6 +86,7 @@ def test_config_update_rebuilds_runtime_without_restart(monkeypatch, tmp_path):
|
||||
model_provider=values.get("model_provider", state["settings"].model_provider),
|
||||
ollama_model=values.get("ollama_model", state["settings"].ollama_model),
|
||||
codex_model=values.get("codex_model", state["settings"].codex_model),
|
||||
deepseek_model=values.get("deepseek_model", state["settings"].deepseek_model),
|
||||
)
|
||||
return {"values": values, "fields": {}, "secrets_configured": {}, "app_data_dir": str(tmp_path)}
|
||||
|
||||
@@ -114,19 +115,120 @@ def test_config_update_rebuilds_runtime_without_restart(monkeypatch, tmp_path):
|
||||
|
||||
updated = client.post(
|
||||
"/api/config",
|
||||
json={"values": {"model_provider": "codex", "codex_model": "gpt-5.4"}},
|
||||
json={"values": {"model_provider": "deepseek", "deepseek_model": "deepseek-v4-flash"}},
|
||||
).json()
|
||||
assert updated["restart_required"] is False
|
||||
|
||||
after = client.get("/api/health").json()
|
||||
assert after["model_provider"] == "codex"
|
||||
assert after["inference"]["provider"] == "codex"
|
||||
assert after["model_provider"] == "deepseek"
|
||||
assert after["inference"]["provider"] == "deepseek"
|
||||
|
||||
chat = client.post("/api/chat", json={"message": "hi", "thread_id": "thread-1", "images": []}).json()
|
||||
assert chat["message"] == "codex:gpt-5.4"
|
||||
assert chat["message"] == "deepseek:deepseek-v4-flash"
|
||||
|
||||
|
||||
def make_settings(tmp_path, model_provider="ollama", ollama_model="qwen3.5:9b", codex_model="gpt-5.4"):
|
||||
def test_plan_draft_endpoint_returns_agent_draft(monkeypatch, tmp_path):
|
||||
state = {"settings": make_settings(tmp_path)}
|
||||
|
||||
class FakeScheduler:
|
||||
def __init__(self, memory):
|
||||
self.memory = memory
|
||||
|
||||
def bind_agent(self, agent):
|
||||
self.agent = agent
|
||||
|
||||
def bind_plan_runner(self, plan_runner):
|
||||
self.plan_runner = plan_runner
|
||||
|
||||
def bind_uex_notifications(self, uex, poll_seconds=60):
|
||||
self.uex = uex
|
||||
self.poll_seconds = poll_seconds
|
||||
|
||||
def start(self):
|
||||
return None
|
||||
|
||||
def shutdown(self):
|
||||
return None
|
||||
|
||||
def list_jobs(self):
|
||||
return []
|
||||
|
||||
class FakeUEXClient:
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
async def get_user(self, username=None, authenticated=False):
|
||||
return {}
|
||||
|
||||
class FakeToolRegistry:
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.pending_actions = {}
|
||||
self.plan_runner = None
|
||||
|
||||
async def approve(self, action_id):
|
||||
return {"approved": action_id}
|
||||
|
||||
async def decline(self, action_id):
|
||||
return {"declined": action_id}
|
||||
|
||||
class FakePlanRunner:
|
||||
def __init__(self, store, tools, memory, agent=None):
|
||||
self.store = store
|
||||
self.tools = tools
|
||||
self.memory = memory
|
||||
self.agent = agent
|
||||
|
||||
def bind_agent(self, agent):
|
||||
self.agent = agent
|
||||
|
||||
class FakeClient:
|
||||
def __init__(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def fake_get_settings():
|
||||
return state["settings"]
|
||||
|
||||
monkeypatch.setattr(server, "WakeScheduler", FakeScheduler)
|
||||
monkeypatch.setattr(server, "UEXClient", FakeUEXClient)
|
||||
monkeypatch.setattr(server, "ToolRegistry", FakeToolRegistry)
|
||||
monkeypatch.setattr(server, "ContinualPlanRunner", FakePlanRunner)
|
||||
monkeypatch.setattr(server, "SCMDBClient", FakeClient)
|
||||
monkeypatch.setattr(server, "CornerstoneClient", FakeClient)
|
||||
monkeypatch.setattr(server, "StarCitizenWikiClient", FakeClient)
|
||||
monkeypatch.setattr(server, "get_settings", fake_get_settings)
|
||||
monkeypatch.setattr(
|
||||
server,
|
||||
"settings_payload",
|
||||
lambda settings=None: {"app_data_dir": str(tmp_path), "values": {}, "fields": {}, "secrets_configured": {}},
|
||||
)
|
||||
|
||||
async def fake_generate_plan_draft(self, title="", objective="", kind="buying", constraints=None, items=None):
|
||||
return {
|
||||
"title": title or "Draft title",
|
||||
"objective": objective or "Draft objective",
|
||||
"kind": kind,
|
||||
"cadence": "0 */3 * * *",
|
||||
"constraints": {"message_tone": "friendly and direct", "instructions": "Start with the best listings."},
|
||||
"items": [{"item_name": "RCMBNT-RGL-1", "desired_quantity": 1, "max_unit_price": None}],
|
||||
}
|
||||
|
||||
monkeypatch.setattr(server.OllamaAgent, "generate_plan_draft", fake_generate_plan_draft)
|
||||
|
||||
app = server.create_app()
|
||||
with TestClient(app) as client:
|
||||
response = client.post(
|
||||
"/api/plans/draft",
|
||||
json={"title": "Polaris parts", "objective": "Find the required parts", "kind": "buying", "constraints": {}, "items": []},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
draft = response.json()["draft"]
|
||||
assert draft["cadence"] == "0 */3 * * *"
|
||||
assert draft["constraints"]["instructions"] == "Start with the best listings."
|
||||
assert draft["items"][0]["item_name"] == "RCMBNT-RGL-1"
|
||||
|
||||
|
||||
def make_settings(tmp_path, model_provider="ollama", ollama_model="qwen3.5:9b", codex_model="gpt-5.4", deepseek_model="deepseek-v4-flash"):
|
||||
return SimpleNamespace(
|
||||
traderai_memory_path=str(tmp_path / "memory.sqlite3"),
|
||||
model_provider=model_provider,
|
||||
@@ -136,6 +238,9 @@ def make_settings(tmp_path, model_provider="ollama", ollama_model="qwen3.5:9b",
|
||||
openai_base_url="https://api.openai.com/v1",
|
||||
openai_api_key=None,
|
||||
openai_model="gpt-5.4-mini",
|
||||
deepseek_base_url="https://api.deepseek.com",
|
||||
deepseek_api_key=None,
|
||||
deepseek_model=deepseek_model,
|
||||
model_reasoning_effort="medium",
|
||||
codex_command="codex",
|
||||
codex_model=codex_model,
|
||||
|
||||
Reference in New Issue
Block a user