F0: establish task backend input and native job spine
This commit is contained in:
@@ -44,7 +44,7 @@ class TaskService:
|
||||
self._listeners.clear()
|
||||
self._jobs.clear()
|
||||
|
||||
async def submit(self, *, assistant_id, conversation_id, tool, instruction, invocation_id):
|
||||
async def submit(self, *, assistant_id, conversation_id, instruction, invocation_id, backend=None, tool=None):
|
||||
if not self.runtime:
|
||||
raise ValueError("后台任务服务尚未启动")
|
||||
if not assistant_id or not conversation_id:
|
||||
@@ -52,15 +52,25 @@ class TaskService:
|
||||
text = instruction.strip()
|
||||
if not text or len(text) > 12000:
|
||||
raise ValueError("任务指令必须为 1-12000 个字符")
|
||||
if tool.type != "task":
|
||||
raise ValueError("请选择后台任务工具")
|
||||
if backend is not None:
|
||||
if backend.type != "opencode":
|
||||
raise ValueError("该任务后端尚未接通")
|
||||
backend_id = backend.id
|
||||
connection = deepcopy(backend.config)
|
||||
connection["_backend_type"] = backend.type
|
||||
secrets = deepcopy(backend.secrets)
|
||||
else:
|
||||
# F0 transition: retired when saved Tool bindings migrate in F1.
|
||||
if tool is None or tool.type != "task":
|
||||
raise ValueError("请选择任务后端")
|
||||
backend_id, connection, secrets = tool.id, deepcopy(tool.definition["config"]), deepcopy(tool.secrets)
|
||||
async with self._submit_lock:
|
||||
record = await self.repository.create(TaskRecord(
|
||||
id="task_" + uuid4().hex,
|
||||
assistant_id=assistant_id, conversation_id=conversation_id,
|
||||
tool_id=tool.id, instruction=text,
|
||||
tool_id=backend_id, instruction=text,
|
||||
origin_key=f"{conversation_id}:{invocation_id}"[:256],
|
||||
connection=deepcopy(tool.definition["config"]), secrets=deepcopy(tool.secrets),
|
||||
connection=connection, secrets=secrets,
|
||||
))
|
||||
if not record.job_id and record.status == "queued":
|
||||
await self._dispatch(record)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
"""F0: explicit simulated backend, real application-owned Pipecat Jobs."""
|
||||
import asyncio
|
||||
import json
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
import unittest
|
||||
|
||||
from services.background_tasks.service import TaskService
|
||||
from tests.test_background_tasks import MemoryRepository, SimulatedExecutor
|
||||
|
||||
|
||||
class TaskBackendSpineTest(unittest.IsolatedAsyncioTestCase):
|
||||
async def test_backend_resource_reaches_native_job_without_tool_definition(self):
|
||||
SimulatedExecutor.release = asyncio.Event()
|
||||
SimulatedExecutor.confirms_stop = True
|
||||
service = TaskService(MemoryRepository(), SimulatedExecutor)
|
||||
backend = SimpleNamespace(id="tb_smoke", type="opencode", config={"url": "https://simulated.test", "directory": "/demo", "timeout_seconds": 30}, secrets={})
|
||||
await service.start()
|
||||
try:
|
||||
task = await service.submit(assistant_id="asst_smoke", conversation_id="conv_smoke", backend=backend, instruction="SIMULATED task", invocation_id="smoke")
|
||||
SimulatedExecutor.release.set()
|
||||
async with asyncio.timeout(3):
|
||||
while (await service.get(task["id"])).status != "succeeded":
|
||||
await asyncio.sleep(.005)
|
||||
record = await service.get(task["id"])
|
||||
self.assertEqual(record.connection["_backend_type"], "opencode")
|
||||
self.assertTrue(record.job_id)
|
||||
artifact = Path(__file__).resolve().parents[2] / "implement-stage/task-backends/backend-spine-smoke.json"
|
||||
artifact.write_text(json.dumps({"simulated_remote": True, "native_job": "completed", "backend_id": backend.id, "tool_definition_required": False}) + "\n")
|
||||
finally:
|
||||
await service.close()
|
||||
Reference in New Issue
Block a user