F2: delegate prompt tasks to native Reasoner or OpenCode backends

This commit is contained in:
Xin Wang
2026-10-23 23:46:29 +08:00
parent 529250173d
commit 16ebfe358c
14 changed files with 784 additions and 110 deletions
+4 -12
View File
@@ -6,8 +6,6 @@ from types import SimpleNamespace
from services.background_tasks.service import TaskService
from services.background_tasks.records import TERMINAL
from schemas import ToolUpsert
from routes.tools import _payload
class MemoryRepository:
@@ -58,7 +56,7 @@ class TaskServiceTest(unittest.IsolatedAsyncioTestCase):
SimulatedExecutor.confirms_stop = True
self.service = TaskService(MemoryRepository(), SimulatedExecutor)
await self.service.start()
self.tool = SimpleNamespace(type="task", id="tool_task", definition={"config": {"url": "https://remote.test", "directory": "/demo", "timeout_seconds": 30}}, secrets={"password": "never-public"})
self.backend = SimpleNamespace(type="opencode", id="backend_test", config={"url": "https://remote.test", "directory": "/demo", "timeout_seconds": 30}, secrets={"password": "never-public"})
async def asyncTearDown(self):
await self.service.close()
async def wait_status(self, task_id, expected):
@@ -66,7 +64,7 @@ class TaskServiceTest(unittest.IsolatedAsyncioTestCase):
while (await self.service.get(task_id)).status != expected:
await asyncio.sleep(.005)
async def submit(self, key="call_1"):
return await self.service.submit(assistant_id="asst_1", conversation_id="conv_1", tool=self.tool, instruction="执行测试", invocation_id=key)
return await self.service.submit(assistant_id="asst_1", conversation_id="conv_1", backend=self.backend, instruction="执行测试", invocation_id=key)
async def test_idempotence_public_projection_and_completion(self):
task = await self.submit()
again = await self.submit()
@@ -152,12 +150,6 @@ class TaskServiceTest(unittest.IsolatedAsyncioTestCase):
self.assertEqual(result["status"], "waiting_input")
self.assertEqual(result["inputRequest"], question)
def test_task_tool_preserves_masked_password(self):
body = ToolUpsert(name="后台编程", functionName="coding_task", definition={"type": "task", "config": {"url": "https://remote.test", "directory": "/demo"}}, secrets={"password": "****"})
data = _payload(body, {"password": "old-password"})
self.assertEqual(data["secrets"]["password"], "old-password")
class TaskApiTest(unittest.IsolatedAsyncioTestCase):
async def test_admin_auth_and_real_native_job_through_http_api(self):
import httpx
@@ -174,14 +166,14 @@ class TaskApiTest(unittest.IsolatedAsyncioTestCase):
async def database():
yield None
app.dependency_overrides[get_session] = database
cfg = SimpleNamespace(type="prompt", runtimeMode="pipeline", tool_bindings=[SimpleNamespace(tool_id="tool_task")], tools=[SimpleNamespace(type="task", id="tool_task", definition={"config": {"url": "https://remote.test", "directory": "/demo", "timeout_seconds": 30}}, secrets={})])
cfg = SimpleNamespace(type="prompt", runtimeMode="pipeline", task_backend=SimpleNamespace(type="opencode", id="backend_test", config={"url": "https://remote.test", "directory": "/demo", "timeout_seconds": 30}, secrets={}), dynamic_variables={}, dynamic_variable_definitions={}, secret_dynamic_variables={})
try:
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="https://platform.test") as client:
unauthenticated = await client.get("/api/background-tasks?assistant_id=asst_1")
self.assertEqual(unauthenticated.status_code, 401)
app.dependency_overrides[require_admin] = lambda: {"username": "test"}
with patch.object(routes, "task_service", service), patch.object(routes, "resolve_runtime_config", AsyncMock(return_value=cfg)):
response = await client.post("/api/background-tasks", json={"assistantId": "asst_1", "toolId": "tool_task", "instruction": "测试请求", "requestId": "request_1"})
response = await client.post("/api/background-tasks", json={"assistantId": "asst_1", "instruction": "测试请求", "requestId": "request_1"})
self.assertEqual(response.status_code, 200)
task_id = response.json()["id"]
self.assertEqual(response.json()["assistantId"], "asst_1")