From 7db737d16172e5de3dab7ae5aebbea9d492bf4a0 Mon Sep 17 00:00:00 2001 From: Xin Wang Date: Fri, 23 Oct 2026 23:48:08 +0800 Subject: [PATCH] F4: document task backend operation and publish API contracts --- backend/README.md | 4 +- backend/contracts/openapi.json | 652 ++++++++++++++++++--- docs-developer/docs.json | 2 +- docs-developer/prompt-background-tasks.mdx | 112 +++- docs-developer/prompt-task-backends.mdx | 136 ++--- docs-developer/tool-resources.mdx | 2 + docs-user/features.mdx | 15 + docs-user/quickstart.mdx | 2 + docs-user/status.mdx | 1 + 9 files changed, 746 insertions(+), 180 deletions(-) diff --git a/backend/README.md b/backend/README.md index 131cea9..68357fd 100644 --- a/backend/README.md +++ b/backend/README.md @@ -62,4 +62,6 @@ make contract-check 开发计划中的生产可观测性、并发保护和可靠性工作尚未全部完成,见[单租户生产化计划](../docs-developer/development-plan.mdx)。 -提示词 Pipeline 的远程编程任务接入与迁移步骤见 [后台任务说明](../docs-developer/prompt-background-tasks.mdx)。使用 Pipecat 原生 Jobs,需先迁移数据库并配置已有的远程 OpenCode 服务。 +提示词 Pipeline 支持「对话模型 Speaker + 任务后端」:Speaker 负责交流,独立后端可选内置 Reasoner 或外部 OpenCode。资源在「组件库 → 任务后端」管理,不再作为普通工具绑定。Reasoner 复用 Pipecat `BackendLLMWorker` 与 HTTP/MCP 工具白名单;所有任务使用应用级原生 Jobs,单进程全局并发为 1。 + +配置与运行边界见[任务后端架构](../docs-developer/prompt-task-backends.mdx)及[使用说明](../docs-developer/prompt-background-tasks.mdx)。升级前备份数据库;`20261023_0027` 将旧 task 工具迁为后端资源,不能安全 downgrade,回退需恢复备份。部署时需迁移并同步接口定义;模型、OpenCode 服务及远端权限需要实际配置和联调。 diff --git a/backend/contracts/openapi.json b/backend/contracts/openapi.json index eb0d241..921a309 100644 --- a/backend/contracts/openapi.json +++ b/backend/contracts/openapi.json @@ -348,6 +348,16 @@ "startup": { "$ref": "#/components/schemas/StartupConfig" }, + "taskBackend": { + "anyOf": [ + { + "$ref": "#/components/schemas/AssistantTaskBackendBinding" + }, + { + "type": "null" + } + ] + }, "toolBindings": { "items": { "$ref": "#/components/schemas/ToolBinding" @@ -420,6 +430,53 @@ "title": "AssistantOut", "type": "object" }, + "AssistantTaskBackendBinding": { + "properties": { + "backendId": { + "maxLength": 40, + "minLength": 1, + "title": "Backendid", + "type": "string" + }, + "instructionSource": { + "discriminator": { + "mapping": { + "literal": "#/components/schemas/LiteralValueSource", + "model": "#/components/schemas/ModelValueSource", + "template": "#/components/schemas/TemplateValueSource", + "variable": "#/components/schemas/VariableValueSource" + }, + "propertyName": "source" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/ModelValueSource" + }, + { + "$ref": "#/components/schemas/VariableValueSource" + }, + { + "$ref": "#/components/schemas/LiteralValueSource" + }, + { + "$ref": "#/components/schemas/TemplateValueSource" + } + ], + "title": "Instructionsource" + }, + "instructions": { + "default": "", + "maxLength": 12000, + "title": "Instructions", + "type": "string" + } + }, + "required": [ + "backendId" + ], + "title": "AssistantTaskBackendBinding", + "type": "object" + }, "AssistantUpsert": { "properties": { "analysisConfig": { @@ -517,6 +574,16 @@ "startup": { "$ref": "#/components/schemas/StartupConfig" }, + "taskBackend": { + "anyOf": [ + { + "$ref": "#/components/schemas/AssistantTaskBackendBinding" + }, + { + "type": "null" + } + ] + }, "toolBindings": { "items": { "$ref": "#/components/schemas/ToolBinding" @@ -3337,6 +3404,78 @@ "title": "OpenAIErrorResponse", "type": "object" }, + "OpenCodeBackendConfig": { + "additionalProperties": false, + "properties": { + "agent": { + "default": "", + "maxLength": 128, + "title": "Agent", + "type": "string" + }, + "directory": { + "maxLength": 2048, + "minLength": 1, + "title": "Directory", + "type": "string" + }, + "instructions": { + "default": "", + "maxLength": 16000, + "title": "Instructions", + "type": "string" + }, + "maxConcurrency": { + "const": 1, + "default": 1, + "title": "Maxconcurrency", + "type": "integer" + }, + "modelId": { + "default": "", + "maxLength": 256, + "title": "Modelid", + "type": "string" + }, + "modelProviderId": { + "default": "", + "maxLength": 128, + "title": "Modelproviderid", + "type": "string" + }, + "skillsNote": { + "default": "", + "maxLength": 4000, + "title": "Skillsnote", + "type": "string" + }, + "timeoutSeconds": { + "default": 600, + "maximum": 7200.0, + "minimum": 30.0, + "title": "Timeoutseconds", + "type": "integer" + }, + "url": { + "maxLength": 2048, + "minLength": 1, + "title": "Url", + "type": "string" + }, + "username": { + "default": "opencode", + "maxLength": 128, + "title": "Username", + "type": "string" + } + }, + "required": [ + "url", + "directory" + ], + "title": "OpenCodeBackendConfig", + "type": "object" + }, "OpeningMessageConfig": { "description": "Built-in Prompt opening interaction; it is not a reusable LLM tool.", "properties": { @@ -4037,6 +4176,68 @@ "title": "RealtimeSessionRequest", "type": "object" }, + "ReasonerBackendConfig": { + "additionalProperties": false, + "properties": { + "instructions": { + "default": "", + "maxLength": 16000, + "title": "Instructions", + "type": "string" + }, + "maxConcurrency": { + "const": 1, + "default": 1, + "title": "Maxconcurrency", + "type": "integer" + }, + "modelResourceId": { + "maxLength": 40, + "minLength": 1, + "title": "Modelresourceid", + "type": "string" + }, + "reasoningEffort": { + "default": "provider_default", + "enum": [ + "provider_default", + "low", + "medium", + "high" + ], + "title": "Reasoningeffort", + "type": "string" + }, + "skills": { + "items": { + "$ref": "#/components/schemas/TaskSkill" + }, + "maxItems": 20, + "title": "Skills", + "type": "array" + }, + "timeoutSeconds": { + "default": 600, + "maximum": 7200.0, + "minimum": 30.0, + "title": "Timeoutseconds", + "type": "integer" + }, + "toolBindings": { + "items": { + "$ref": "#/components/schemas/ToolBinding" + }, + "maxItems": 50, + "title": "Toolbindings", + "type": "array" + } + }, + "required": [ + "modelResourceId" + ], + "title": "ReasonerBackendConfig", + "type": "object" + }, "ReplyExpectedBehavior": { "properties": { "assertionType": { @@ -5099,21 +5300,136 @@ "minLength": 1, "title": "Requestid", "type": "string" - }, - "toolId": { - "title": "Toolid", - "type": "string" } }, "required": [ "assistantId", - "toolId", "instruction", "requestId" ], "title": "SubmitTask", "type": "object" }, + "TaskBackendOut": { + "properties": { + "config": { + "anyOf": [ + { + "$ref": "#/components/schemas/ReasonerBackendConfig" + }, + { + "$ref": "#/components/schemas/OpenCodeBackendConfig" + } + ], + "title": "Config" + }, + "description": { + "default": "", + "maxLength": 2048, + "title": "Description", + "type": "string" + }, + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "id": { + "title": "Id", + "type": "string" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "title": "Name", + "type": "string" + }, + "secrets": { + "additionalProperties": true, + "title": "Secrets", + "type": "object" + }, + "type": { + "enum": [ + "reasoner", + "opencode" + ], + "title": "Type", + "type": "string" + }, + "updatedAt": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updatedat" + } + }, + "required": [ + "name", + "type", + "config", + "id" + ], + "title": "TaskBackendOut", + "type": "object" + }, + "TaskBackendUpsert": { + "properties": { + "config": { + "anyOf": [ + { + "$ref": "#/components/schemas/ReasonerBackendConfig" + }, + { + "$ref": "#/components/schemas/OpenCodeBackendConfig" + } + ], + "title": "Config" + }, + "description": { + "default": "", + "maxLength": 2048, + "title": "Description", + "type": "string" + }, + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "name": { + "maxLength": 128, + "minLength": 1, + "title": "Name", + "type": "string" + }, + "secrets": { + "additionalProperties": true, + "title": "Secrets", + "type": "object" + }, + "type": { + "enum": [ + "reasoner", + "opencode" + ], + "title": "Type", + "type": "string" + } + }, + "required": [ + "name", + "type", + "config" + ], + "title": "TaskBackendUpsert", + "type": "object" + }, "TaskInput": { "properties": { "answers": { @@ -5148,80 +5464,27 @@ "title": "TaskInput", "type": "object" }, - "TaskToolConfig": { + "TaskSkill": { + "additionalProperties": false, "properties": { - "allowInterruptions": { - "const": true, - "default": true, - "title": "Allowinterruptions", - "type": "boolean" - }, - "directory": { - "maxLength": 2048, + "content": { + "maxLength": 16000, "minLength": 1, - "title": "Directory", + "title": "Content", "type": "string" }, - "executionMode": { - "const": "immediate", - "default": "immediate", - "title": "Executionmode", - "type": "string" - }, - "provider": { - "const": "opencode", - "default": "opencode", - "title": "Provider", - "type": "string" - }, - "timeoutSeconds": { - "default": 600, - "maximum": 7200.0, - "minimum": 30.0, - "title": "Timeoutseconds", - "type": "integer" - }, - "url": { - "maxLength": 2048, - "minLength": 1, - "title": "Url", - "type": "string" - }, - "username": { - "default": "opencode", + "name": { "maxLength": 128, - "title": "Username", + "minLength": 1, + "title": "Name", "type": "string" } }, "required": [ - "url", - "directory" + "name", + "content" ], - "title": "TaskToolConfig", - "type": "object" - }, - "TaskToolDefinition": { - "properties": { - "config": { - "$ref": "#/components/schemas/TaskToolConfig" - }, - "schemaVersion": { - "default": 2, - "title": "Schemaversion", - "type": "integer" - }, - "type": { - "const": "task", - "default": "task", - "title": "Type", - "type": "string" - } - }, - "required": [ - "config" - ], - "title": "TaskToolDefinition", + "title": "TaskSkill", "type": "object" }, "TemplateValueSource": { @@ -5790,8 +6053,7 @@ "mapping": { "client": "#/components/schemas/ClientToolDefinition", "http": "#/components/schemas/HttpToolDefinition", - "mcp": "#/components/schemas/McpToolDefinition", - "task": "#/components/schemas/TaskToolDefinition" + "mcp": "#/components/schemas/McpToolDefinition" }, "propertyName": "type" }, @@ -5804,9 +6066,6 @@ }, { "$ref": "#/components/schemas/McpToolDefinition" - }, - { - "$ref": "#/components/schemas/TaskToolDefinition" } ], "title": "Definition" @@ -5873,8 +6132,7 @@ "enum": [ "http", "mcp", - "client", - "task" + "client" ], "title": "Type", "type": "string" @@ -6074,8 +6332,7 @@ "mapping": { "client": "#/components/schemas/ClientToolDefinition", "http": "#/components/schemas/HttpToolDefinition", - "mcp": "#/components/schemas/McpToolDefinition", - "task": "#/components/schemas/TaskToolDefinition" + "mcp": "#/components/schemas/McpToolDefinition" }, "propertyName": "type" }, @@ -6088,9 +6345,6 @@ }, { "$ref": "#/components/schemas/McpToolDefinition" - }, - { - "$ref": "#/components/schemas/TaskToolDefinition" } ], "title": "Definition" @@ -8673,6 +8927,242 @@ ] } }, + "/api/task-backends": { + "get": { + "operationId": "list_task_backends_api_task_backends_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/TaskBackendOut" + }, + "title": "Response List Task Backends Api Task Backends Get", + "type": "array" + } + } + }, + "description": "Successful Response" + } + }, + "summary": "List Task Backends", + "tags": [ + "task-backends" + ] + }, + "post": { + "operationId": "create_task_backend_api_task_backends_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskBackendUpsert" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskBackendOut" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Create Task Backend", + "tags": [ + "task-backends" + ] + } + }, + "/api/task-backends/{backend_id}": { + "delete": { + "operationId": "delete_task_backend_api_task_backends__backend_id__delete", + "parameters": [ + { + "in": "path", + "name": "backend_id", + "required": true, + "schema": { + "title": "Backend Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Delete Task Backend", + "tags": [ + "task-backends" + ] + }, + "get": { + "operationId": "get_task_backend_api_task_backends__backend_id__get", + "parameters": [ + { + "in": "path", + "name": "backend_id", + "required": true, + "schema": { + "title": "Backend Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskBackendOut" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Get Task Backend", + "tags": [ + "task-backends" + ] + }, + "put": { + "operationId": "update_task_backend_api_task_backends__backend_id__put", + "parameters": [ + { + "in": "path", + "name": "backend_id", + "required": true, + "schema": { + "title": "Backend Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskBackendUpsert" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskBackendOut" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Update Task Backend", + "tags": [ + "task-backends" + ] + } + }, + "/api/task-backends/{backend_id}/duplicate": { + "post": { + "operationId": "duplicate_task_backend_api_task_backends__backend_id__duplicate_post", + "parameters": [ + { + "in": "path", + "name": "backend_id", + "required": true, + "schema": { + "title": "Backend Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskBackendOut" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Duplicate Task Backend", + "tags": [ + "task-backends" + ] + } + }, "/api/test-assets/images": { "post": { "operationId": "upload_test_image_api_test_assets_images_post", diff --git a/docs-developer/docs.json b/docs-developer/docs.json index b19bdc7..423c9f4 100644 --- a/docs-developer/docs.json +++ b/docs-developer/docs.json @@ -46,7 +46,7 @@ "groups": [ { "group": "开始与对接", - "pages": ["index", "integrations", "tool-resources", "openai-compatibility", "responses-api", "realtime-protocol"] + "pages": ["index", "integrations", "tool-resources", "prompt-task-backends", "prompt-background-tasks", "openai-compatibility", "responses-api", "realtime-protocol"] }, { "group": "开发与质量", diff --git a/docs-developer/prompt-background-tasks.mdx b/docs-developer/prompt-background-tasks.mdx index e987f23..c2ed8fa 100644 --- a/docs-developer/prompt-background-tasks.mdx +++ b/docs-developer/prompt-background-tasks.mdx @@ -1,52 +1,102 @@ --- title: 提示词后台任务 -description: 使用 Pipecat 原生 Jobs 委派远程 OpenCode 任务。 +description: 配置 Speaker 与独立的 Reasoner 或 OpenCode 任务后端。 --- -# 提示词后台任务 MVP +# 配置提示词后台任务 -提示词 Pipeline 可以绑定一个「后台任务」工具。对话模型提交任务后立即获得任务编号,继续对话;应用级 Pipecat Worker 拥有长任务,语音断线不取消远端执行。OpenCode 是当前唯一实现的执行器。 +提示词 Pipeline 的「对话模型 Speaker」负责语音交流与需求澄清;独立的「任务后端」处理需要持续推理或执行的目标。提交后 Speaker 获得任务编号并继续对话,语音断线不会取消后台任务。当前支持内置 Reasoner 和外部 OpenCode;完整架构见[任务后端说明](/prompt-task-backends)。 -## 使用 +## 升级和启动 -1. 更新后端依赖,并执行数据库迁移:`cd backend && .venv/bin/python -m alembic upgrade head`。迁移新增任务记录/事件表,并允许 task 工具类型。 -2. 重启后端。第一版要求单个应用进程(一个 Uvicorn worker),使用原生 AsyncQueueBus。 -3. 在远端准备好仓库、OpenCode 模型与服务。此功能连接已有 `opencode serve`,不会在远端安装软件或启动进程。服务应通过后端可访问的地址提供 HTTP(S),如开启 Basic 鉴权,请配置 `OPENCODE_SERVER_PASSWORD`。 -4. 在「组件库 / 工具」新建「后台任务 · OpenCode」,填写服务地址、远端工作目录、用户名、服务密码和等待时限。服务地址/目录固定于配置,不由 LLM 参数决定。 -5. 在提示词 Pipeline 助手的「外部工具」中选择该工具。默认 instruction 参数由模型提供,可配置固定值或助手变量。任务工具不支持最终结果映射到会话变量。 -6. 保存助手,在手动语音调试中提出任务。展开「后台任务」查看进展、结果,处理远端问题/权限,或停止任务。网页刷新后仍可按助手查询任务。 +升级前先备份数据库。`20261023_0027` 会将旧 task 工具及助手绑定迁移为后端资源,并删除旧工具记录;该资源迁移不能安全 downgrade,回退需恢复迁移前备份。 -前台新增三个控制函数:`get_background_task`、`cancel_background_task`、`send_background_task_message`。主提交函数使用工具资源的函数名。控制函数名由平台保留。单个远端问题可由对话工具回答;权限和多个问题请在网页卡片处理。不会自动批准权限。 +更新后端与前端依赖,然后执行迁移、同步模型接口定义: -## 运行与恢复 +```bash +cd backend +uv pip install --python .venv/bin/python -r requirements.txt +.venv/bin/python -m alembic upgrade head +.venv/bin/python -m db.sync_interface_definitions +cd ../frontend +npm ci +``` -- NativeTaskRuntime 只组装 `WorkerRunner`、常驻 CoordinatorWorker 和 RemoteAgentWorker。派发、超时、取消和 FIFO 串行执行由 Pipecat 原生 Job 系统负责。 -- 等待时限覆盖每次本地 Job(含排队),重启或重新观察后重新计时,不代表累计任务寿命上限;超时触发远端停止核查。原生 Job 全局 FIFO 串行;若另有未结束的远端句柄,新的编码任务不会提交,需先核查或停止旧任务。被阻挡的新任务会标为失败并说明尚未向远端提交;解决旧任务后需重新提交,不会自动恢复。无法约束平台之外的 OpenCode 客户端。 -- 提交回执表示平台接受任务。OpenCode 的 204 只表示远端接收;必须取得关联到本次 messageID 的完成消息才能显示成功。 -- OpenCodeAdapter 负责创建远端 session、订阅 SSE、异步提交、结果查询和 abort。每个任务使用独立远端 session,内部步骤仍由 OpenCode 完成。 -- 原生 Job 取消不代表远端已停止。适配器调用 abort 并查询远端状态;未确认时保留「停止待确认」。 -- 连接中断会尝试重新观察,不重新发送原指令。无法核查时显示「状态待核查」,可显式核查或请求停止。 -- 应用退出仅停止本地监听,不主动 abort 远端任务;重启后使用已保存的远端句柄重新观察。没有远端句柄的中断任务不会自动重新提交。 -- 任务和远端连接配置保存在数据库;公开 API 不返回密码或连接快照。平台保留远端助手文本与错误文本,未保存工具原始执行日志;语音通知超过16000字符时保留首尾并明确标记省略,网页可查看完整已保存文本。资源后续编辑不会改变已运行任务的地址/目录。 -- 在线进度通过现有自定义 app message 传送,网页任务卡片另按助手轮询快照以支持刷新。完成/失败/取消/状态未知/等待输入通过 Pipecat 原生上下文消息触发前台模型回复;用户/助手正在说话时由原生聚合器安排。离线结果只保留在任务卡片,不自动在新语音连接中播报旧结果。 +生产前端还需运行 `npm run build`,随后重启前后端。数据库需已启动,连接使用后端环境配置。也可在仓库根目录运行 `make db-init` 完成迁移与接口定义同步;该命令需要本机安装 `uv`。 -## 第一版边界 +后台任务运行器随后端自动启动。当前要求单个应用进程、一个 Uvicorn worker,所有任务全局并发为 1。 -仅提示词 Pipeline 支持任务工具。Workflow、Realtime、启动 Action 不支持。自动测试/Responses 测试的模拟工具执行路径不提交、查询或控制真实任务;请使用手动语音调试验收。运行中的任意实时 steer 尚未支持;需要修改目标时,先停止,再提交新的任务。 +## 创建任务后端资源 -后端使用现有管理员鉴权;第一版沿用整个管理台的单管理员访问范围,尚无多租户隔离。持久化记录是业务历史和恢复依据,不是另一套任务调度器。 +在「组件库 → 任务后端」点击「添加任务后端」,选择一种类型。 + +### 内置 Reasoner + +1. 选择已启用的 LLM 模型资源;支持 `openai-llm` / `dashscope-llm` 接口,需真实可用的模型和凭据。每个任务会创建独立上下文,不复用 Speaker 的对话历史。 +2. 推理强度默认「模型默认」。只有模型真实支持 `reasoning_effort`,且模型资源已声明 `supportsReasoningEffort` 时,才可选择 low / medium / high;未声明的非默认配置会被拒绝。当前没有通用 thinking budget 设置。 +3. 在「可用工具」绑定允许 Reasoner 调用的 HTTP/MCP 服务端工具。Client 工具依赖浏览器,只能用于当前对话,不能供后台执行。 +4. 按需添加内联技能名称与任务说明。技能指导工作方法,不能授予新工具或扩大权限。 +5. 填写可复用的后端任务指令与任务时限,保存资源。时限默认 600 秒,可设置 30–7200 秒;新任务时限覆盖排队和执行。 + +Reasoner 没有内置通用 Shell/文件执行环境。需要修改仓库或运行远端命令时,使用配置好执行环境的 OpenCode 后端。 + +### 外部 OpenCode + +先在执行机器准备仓库、模型配置和已有的 OpenCode 服务。平台不会代为安装 OpenCode 或启动远端进程。创建资源时填写: + +| 字段 | 内容 | +| --- | --- | +| 服务地址 | 平台后端可访问的 HTTP(S) 地址,例如同机宿主运行时的 `http://127.0.0.1:4096` | +| 远端工作目录 | OpenCode 所在机器的仓库绝对路径,例如 `/workspace/my-project` | +| 服务用户名 | 默认 `opencode`,与远端服务鉴权配置一致 | +| 服务密码 | 对应 `OPENCODE_SERVER_PASSWORD`;编辑时留空保留原凭据 | +| 远端 Agent | 可选;留空使用远端默认 Agent | +| Provider ID / Model ID | 可选,必须成对填写;留空使用远端默认模型,模型凭据在远端配置 | +| 远端技能说明 | 记录已部署技能与配置来源;不会上传或安装技能 | +| 后端任务指令与时限 | 所有引用该资源的助手共享的要求;默认时限 600 秒 | + +如果后端在 Docker 中、OpenCode 在宿主机,需使用容器可访问的宿主地址;浏览器电脑上的 `localhost` 与后端所在机器无关。 + +文件、Shell、沙箱和技能权限由远端 Agent 与执行环境管理。服务密码用于连接服务;工作目录不等于沙箱。远端出现权限请求时,由用户在任务卡片决定,不会自动批准权限。 + +## 绑定提示词助手 + +1. 打开提示词助手,运行方式选择「Pipeline」,在「模型与语音」选择 Speaker、ASR、TTS。 +2. 在独立的「任务后端」区域选择刚创建的资源。无需到「外部工具」绑定 OpenCode,也不需要填写委派函数名。 +3. 按需填写「该助手的任务指令」,例如完成后说明修改范围和验证结果;可引用已声明的动态变量。 +4. 新配置通常保留「任务要求来源 → Speaker 生成任务要求」。旧 task 工具的固定值、变量和模板预设会迁入此处,编辑保存时保留;只有明确修改来源才替换预设。 +5. 保存后,在手动语音调试中提出一个小任务。展开「后台任务」查看进度、结果、回答必要问题或停止任务;网页刷新后仍可查询。 + +Speaker 自动获得 `delegate_task`、`get_background_task`、`cancel_background_task` 和 `send_background_task_message` 控制入口,这些函数名由平台保留。单个待处理问题可通过对话回答;OpenCode 权限和多个问题在网页卡片处理。 + +## 执行、取消与恢复 + +- 提交回执只表示接受。Reasoner 需明确提交完成结果,OpenCode 需返回关联到本次消息的完成记录;普通文字、空闲状态或 HTTP 204 都不直接表示成功。 +- 新任务保存截止时间,覆盖排队、执行和重新观察;重启后使用剩余时间。迁移前未保存截止时间的历史任务保留原有观察窗口语义。 +- 全局 FIFO 串行。已有未结束的 OpenCode 句柄时,新任务不会提交到后端;需先核查或停止旧任务,再重新创建任务。不能约束平台之外的 OpenCode 客户端。 +- 原生 Job 取消后仍需核查执行结果。OpenCode 调用 abort 并确认停止;未确认时显示「停止待确认」。Reasoner 停止本地推理,已发出的 HTTP/MCP 操作仍可能产生副作用,需核查业务系统。 +- 应用重启后,OpenCode 仅使用已保存句柄重新观察,不重复发送未知提交;没有句柄的中断任务显示待核查。Reasoner 标记为中断失败,不自动重放工具调用。 +- 新任务冻结后端连接、模型、工具与技能配置。资源后续修改不会改变已有任务;公开任务 API 不返回密码或连接快照。 +- 插话和断线保留任务。在线结果通过现有 app message 和 Pipecat 上下文通知 Speaker;离线结果保留在任务卡片,新语音连接不自动播报旧结果。 ## 管理接口 -- `GET /api/background-tasks?assistant_id=...`:最多100项任务,优先显示未结束任务;网页显示全部返回项,无分页。 -- `GET /api/background-tasks/{id}`:任务快照。 -- `POST /api/background-tasks`:提交已绑定工具的任务,携带 assistantId/toolId/instruction/requestId;重复 requestId 返回原任务。 +所有管理接口使用现有管理员鉴权。 + +- `GET /api/task-backends`、`POST /api/task-backends`:查询和创建后端资源。 +- `GET /api/task-backends/{id}`、`PUT /api/task-backends/{id}`、`DELETE /api/task-backends/{id}`:读取、修改和删除;被助手引用的资源不能删除。 +- `POST /api/task-backends/{id}/duplicate`:复制资源,凭据在服务端处理。 +- `GET /api/background-tasks?assistant_id=...`:最多 100 项任务,优先未结束任务。 +- `GET /api/background-tasks/{id}`:任务快照,含 `backendId` / `backendType`。 +- `POST /api/background-tasks`:携带 `assistantId`、`instruction`、`requestId`,由助手绑定解析后端;不接收 `toolId`,重复请求 ID 返回原任务。 - `POST /api/background-tasks/{id}/cancel`:请求停止。 -- `POST /api/background-tasks/{id}/refresh`:核查远端并重新观察,不重发原任务。 -- `POST /api/background-tasks/{id}/input`:回复待处理的 permission/question。 +- `POST /api/background-tasks/{id}/refresh`:核查状态;OpenCode 可以重新观察,不重发原任务。 +- `POST /api/background-tasks/{id}/input`:回复当前待处理问题或 OpenCode 权限请求。 -## 验证边界 +## 当前边界与验收 -测试覆盖真实 Pipecat Jobs 的派发/进度/断线独立/取消,以及显式模拟的 OpenCode HTTP/SSE 协议。不把模拟执行结果当作真实代码修改结果。本次在与项目一致的临时 pgvector/PostgreSQL 17 容器中完成了全量 Alembic 迁移、真实任务 API + 原生 Job + 数据库存储验收,覆盖重复请求不重复提交、事件序号与服务重启后的查询;远端仍由 MockTransport 显式模拟。现有开发库未修改,部署时仍需执行迁移,真实 OpenCode 联调待配置服务后进行。 +当前只有提示词 Pipeline 支持任务后端。自动测试/Responses 的模拟工具路径不提交或控制真实后台任务;请在配置好模型、工具和远端服务后使用手动调试验收。运行中任意修改目标尚未支持,需要更改目标时先停止,再提交新任务。 + +测试中的 OpenCode HTTP/SSE 和模型模拟会明确标注,不能据此声称已修改真实仓库或验证了生产权限/沙箱。本版的具体测试、迁移验收记录见 `implement-stage/task-backends/BUILD_NOTE.md`;真实 OpenCode 编码与真实模型联调仍需在部署环境完成。后端沿用单管理员访问范围,尚无多租户隔离。 协议配置可参考 [OpenCode Server 官方文档](https://opencode.ai/docs/server/)。 diff --git a/docs-developer/prompt-task-backends.mdx b/docs-developer/prompt-task-backends.mdx index 70f6134..23e6f2e 100644 --- a/docs-developer/prompt-task-backends.mdx +++ b/docs-developer/prompt-task-backends.mdx @@ -1,21 +1,21 @@ --- title: 提示词助手的对话模型与任务后端 -description: 将任务后端从普通工具资源中迁出的适配草案。 +description: Speaker 与内置 Reasoner、外部 OpenCode 任务后端的配置和运行边界。 --- # 提示词助手的对话模型与任务后端 -状态:设计草案。当前已实现版本仍通过 task 工具资源连接 OpenCode;本文描述下一版迁移目标,不表示新配置或内置 Reasoner 已可使用。 +状态:第一版已实现。任务后端使用独立资源配置;内置 Reasoner 和外部 OpenCode 都有运行路径。真实模型和远端 OpenCode 仍需使用有效连接配置进行部署联调,模拟协议测试不代表完成过真实编码任务。操作步骤见[后台任务使用说明](/prompt-background-tasks)。 ## 范围与职责 -仅提示词 Pipeline。一个助手配置一个 Speaker,可选一个任务后端:内置 Reasoner 或外部 OpenCode。外部 Coding Agent 首版只接 OpenCode。 +仅提示词 Pipeline。一个助手配置一个 Speaker,可选一个任务后端:内置 Reasoner 或外部 OpenCode。Workflow、Realtime 和启动 Action 不支持任务委派。切换为 Realtime 时,界面会先确认解除当前助手的任务后端绑定,后端资源仍保留。 -Speaker 使用现有 ASR → 对话 LLM → TTS 链路,负责交流、澄清、委派与播报。任务后端有独立上下文和执行策略。简单对话由 Speaker 完成,需要较强推理或执行能力时委派任务;任务执行期间 Speaker 继续响应用户。 +Speaker 使用现有 ASR → 对话 LLM → TTS 链路,负责交流、澄清、委派与播报。任务后端使用独立上下文处理目标,执行期间 Speaker 继续响应用户。 ```text 用户 ⇄ ASR / Speaker / TTS - │ 委派、查询、补充输入、取消 + │ 委派、查询、回答问题、取消 ▼ TaskService + 应用级 Coordinator │ Pipecat 原生 Jobs @@ -33,100 +33,104 @@ Speaker 使用现有 ASR → 对话 LLM → TTS 链路,负责交流、澄清 数据库存储 / 网页 / Speaker ``` -产品配置使用「任务后端」资源。模型仍可通过内建 function calling 发起委派,这是模型与平台的通信方式;管理员不再创建 OpenCode Tool、不填写委派函数名,也不把它放入普通工具绑定列表。 +管理员在「组件库 → 任务后端」创建资源,再在提示词助手中选择。普通工具资源只包含 HTTP、MCP、Client。Speaker 通过平台自动注册的 `delegate_task` 发起委派,无需填写函数名或绑定一项 OpenCode 工具。 ## 资源与配置 -新增 `TaskBackendResource`,与模型资源、工具资源并列。首版资源类型为 `reasoner | opencode`,用明确的配置分支,无需通用插件系统。 +`TaskBackendResource` 与模型、工具资源并列,类型为 `reasoner | opencode`。资源负责连接、模型、执行策略和技能;助手的 `taskBackend` 只包含 `backendId`、`instructions` 和 `instructionSource`。 -| 配置位置 | 内置 Reasoner | OpenCode | +| 配置 | 内置 Reasoner | OpenCode | | --- | --- | --- | -| 后端资源 | 名称、说明、启用状态 | 名称、说明、启用状态 | -| 连接与模型 | 引用现有 LLM ModelResource;独立模型凭据由资源解析 | 服务地址、服务鉴权、工作目录、远端 agent;可验证支持时选择远端模型/variant | -| 推理配置 | 该模型支持的推理强度或预算 | 采用远端模型/agent 的配置及能力 | -| 执行策略 | 平台允许的服务端工具、任务时限、取消规则 | 任务时限、取消规则;权限及沙箱以远端实际环境为准 | -| 技能 | 平台管理并向该 Reasoner 加载的任务说明 | 远端已安装的原生技能及 agent 配置 | +| 基本信息 | 名称、说明、启用状态 | 名称、说明、启用状态 | +| 连接与模型 | 引用已启用的 LLM 模型资源,凭据在服务端解析 | 服务地址、用户名、服务密码、远端工作目录 | +| 推理配置 | 模型默认,或经能力声明的 low / medium / high | 可选远端 Agent;可成对指定 Provider ID / Model ID | +| 执行策略 | HTTP/MCP 工具白名单、任务时限;并发固定 1 | 任务时限;权限和沙箱由远端管理;并发固定 1 | +| 技能 | 内联技能名称与说明,加载到任务上下文 | 记录远端已部署技能的说明,平台不上传或安装技能 | +| 任务指令 | 可复用的后端指令,加上该助手的任务指令 | 相同 | -助手新增 `taskBackend` 配置,包含 `backendId`、该助手的任务指令、执行策略和技能选择;连接信息留在可复用的后端资源内。第一版不增加第三个模型角色或多后端路由。 +默认任务时限为 600 秒,可设置 30–7200 秒。资源配置保存时和助手绑定时都会校验模型、工具及变量引用。修改资源不会改变已创建任务的冻结配置。 -Speaker 继续引用现有 LLM 模型绑定。Reasoner 引用独立的 LLM 资源,即使选中同一个模型资源,也必须创建独立的模型服务实例、上下文和运行配置,避免推理强度、工具或对话历史互相影响。 +### 内置 Reasoner -推理强度根据模型实际能力显示:例如模型可能支持 low/medium/high,也可能仅支持 thinking budget。配置由 provider 适配到真实参数,不静默忽略不支持的选项。当前模型工厂主要支持 OpenAI-compatible 接口;未支持的 provider 应明确拒绝,不能仅增加下拉选项。 +Reasoner 引用 `openai-llm` 或 `dashscope-llm` 的 LLM 模型资源。即使与 Speaker 选择同一资源,每个任务也会创建独立的模型服务、上下文和运行设置。 + +推理强度使用实际的 `reasoning_effort` 参数。选择 low / medium / high 前,管理员须确认模型支持该参数,并在模型资源中声明 `values.supportsReasoningEffort = true`。未声明时只能使用「模型默认」;服务端会拒绝非默认值。当前没有通用 thinking budget 配置,也不自动推测模型能力。 + +Reasoner 只能调用该后端显式绑定的 HTTP/MCP 服务端工具,继续复用现有 `ToolExecutor`。Client 工具依赖浏览器连接,不能作为后台工具。技能是工作方法,不能扩大工具许可。平台没有为 Reasoner 增加通用 Shell/文件环境;需要远端编码执行时选择 OpenCode。 + +### 外部 OpenCode + +平台连接已有的 OpenCode 服务,不安装软件、不启动远端进程。地址必须由平台后端可访问;工作目录使用远端机器上的绝对路径。服务鉴权凭据、远端模型 API 凭据与执行权限分别管理。 + +- 服务地址、用户名与密码负责 HTTP Basic 鉴权。 +- `agent` 留空使用远端默认 Agent。 +- `modelProviderId` / `modelId` 同时填写或同时留空;留空使用远端默认模型。模型凭据在 OpenCode 端配置。 +- 文件、Shell、沙箱、技能权限由远端 Agent、运行账号和部署环境执行。工作目录不等于沙箱。 +- `skillsNote` 仅记录远端技能及配置来源;平台不保证自动同步远端 `SKILL.md`。 + +界面没有提供无法实际生效的权限或沙箱开关,也不会自动授予远端执行权限。需要确认权限时由用户在任务卡片处理。 ## Pipecat 复用与任务生命周期 -当前安装的 Pipecat 1.13.0 包含 `BackendLLMWorker`,管理后台 LLM 上下文、多步工具调用和输出;`LLMContextWorker` 封装上下文聚合器。内置 Reasoner 应优先使用这些组件,工具执行桥接现有 ToolExecutor,不另写推理循环。 +应用级 `WorkerRunner`、常驻 Coordinator 和串行任务 Worker 持有执行 Jobs;媒体 Pipeline 只订阅任务事件。断线或用户插话不会取消任务,明确取消时才进入停止流程。 -`LLMWithBackend` / `BackendConnector` 已提供前台委派和后台消息传送语义,可复用其公开能力;`LLMWithBackend` 当前为 alpha,且默认会把 attach 会话绑定到媒体 Pipeline 生命周期。直接替换当前 LLM 槽会改变断线行为,必须保留应用级拥有者。 +内置 Reasoner 使用 Pipecat `BackendLLMWorker` 管理独立的上下文和模型/工具调用循环;业务适配器注册 `complete_task` 与 `ask_user`。必须明确完成或提出问题,普通文本、模型空闲或 attach 回执都不是任务成功证明。平台没有自行实现第二套推理循环,也未修改 Pipecat。 -应用级 Coordinator 拥有后端 attach/执行 Jobs,媒体 Pipeline 只订阅或解除订阅。内置 Reasoner 按任务创建独立 worker/context,任务后端资源只复用配置,不共享所有助手的任务历史。取消一个任务只能影响该任务。 +任务结束后通过公开接口清空上下文、工具与处理器引用。当前 Pipecat 运行器仍保留结束 Worker 的注册对象直到应用关闭;本版适用于 MVP,长期高任务量运行还需要验证该框架行为。 -Pipecat 继续负责 Worker/Job 派发、串行执行、超时和取消。TaskService 负责业务任务 ID、访问归属、后端选择、配置快照、记录与事件投影。OpenCode 适配器继续负责 HTTP/SSE、结果关联、远端 abort 和重新观察。 +`LLMWithBackend` / `BackendConnector` 可供后续评估,但本版没有直接替换 Speaker 的 LLM 槽;保留应用级所有者才能维持语音断线后的执行。 -统一后端边界可保持很小:执行并发出事件、查询状态、回复待处理输入、请求取消。恢复和运行中补充消息按后端实际能力处理,不要求两种后端假装支持相同能力。 +Pipecat 负责 Job 派发、FIFO 串行、超时和取消。`TaskService` 负责业务任务 ID、后端选择、冻结配置、记录和事件投影。数据库记录不代替原生调度器。 -- 原生 attach/idle、普通模型输出及远端接收回执都不是业务任务成功证明。内置 Reasoner 需通过明确的完成/待输入/失败语义返回结果;平台可注册任务内的完成和提问控制函数,复用原生工具回调,不自行实现推理循环。 -- 任务提交携带目标及必要上下文。新任务冻结后端配置和策略,模型只能提交任务要求,不能更改地址、凭据、工作目录或授权。 -- 进度保存在任务记录与网页;Speaker 接收适合用户的结果、问题及必要状态通知,不默认播报推理过程或原始工具日志。 -- 语音插话保留后台任务。用户明确取消时,取消原生 Job 并核查执行后端;未确认远端停止时仍显示停止待确认。 -- OpenCode 重启恢复仍使用已保存的 session/message 句柄重新观察,不重发未知提交。内置 Reasoner 首版在应用重启后标记中断并保留已存结果,不自动重放可能有副作用的工具调用;不声称原生 Job 自动持久恢复。 -- 运行中任意修改目标需要后端能力支持。首版共同提供查询、取消、回答待处理问题;OpenCode 不自动重发目标来模拟实时 steer。 +- **并发与部署**:仅单应用进程、一个 Uvicorn worker;所有任务全局并发固定为 1。已有未结束的 OpenCode 句柄会阻止新任务提交到后端,需先核查或停止旧任务。该约束无法控制平台之外的 OpenCode 客户端。 +- **截止时间**:新任务在创建时保存截止时间,覆盖排队和执行;OpenCode 重连观察或应用重启后使用剩余时间,不重新延长截止时间。迁移前没有截止时间的历史任务保留原有观察时限语义。 +- **成功判定**:OpenCode 的 204 只表示接收。需要取得关联到本次 message ID 的完成消息;Reasoner 需调用明确完成控制函数。 +- **取消**:先取消原生执行 Job,再核查对应后端。OpenCode 需 abort 后确认状态,未确认时保留「停止待确认」。Reasoner 可停止本地执行;已发出的 HTTP/MCP 请求可能已有副作用,应核查业务系统结果。 +- **恢复**:OpenCode 使用已存 session/message 句柄重新观察,不重发未知提交。Reasoner 在应用重启后标为中断失败,保留记录,不自动重放可能有副作用的工具。 +- **输入与目标变更**:共同支持查询、取消、回答当前待处理问题。首版不支持任意运行中 steer;修改目标时先停止,再创建新任务。 +- **通知**:网页保存和展示进度、问题及结果;Speaker 接收必要状态和结果,不默认播报内部推理或原始工具日志。离线结果保留在任务卡片,新语音连接不自动重播旧结果。 -首版仍固定任务并发为 1,使用原生串行 Job,不开放尚未实现的任意并发配置。已有远端任务状态未确认时,保留当前阻止新编码提交的业务规则;其后可按后端/工作区拆分原生 worker。 +自动测试/Responses 的模拟工具执行路径不会提交或控制真实后台任务,不能用该路径证明真实任务后端已连通。 -新任务建议持久化任务截止时间:超时覆盖排队和执行,重启后向原生 Job 传入剩余时间。现有历史任务继续保留原有观察时限语义,不追溯修改历史含义。 +## 数据迁移与升级 -## 工具、技能与权限 +迁移 `20261023_0027` 把旧 task 工具迁为 OpenCode 后端资源,迁移助手绑定,并保留固定值、变量或模板形式的 `instructionSource`。旧工具记录和普通工具绑定会移除。历史任务保留任务 ID、结果、冻结连接和远端句柄,并补充后端来源。 -Speaker 的工具用于当前对话中的即时操作,例如显示消息和拍照按钮。Reasoner 使用单独配置的服务端 HTTP/MCP 工具白名单;客户端工具依赖浏览器连接,不能直接成为断线后继续执行的后台能力。现有 ToolExecutor 没有通用 Shell/文件执行环境,首版编码工作由 OpenCode 执行。 +迁移不可安全 downgrade。升级前备份数据库;回退需要恢复迁移前备份与匹配的旧代码,不要只回退应用版本。若旧数据包含多个 task 绑定或非提示词 Pipeline 绑定,迁移会明确失败,需先修正这些配置。 -技能是工作方法,不能增加执行权限。内置 Reasoner 可先加载平台保存的选中技能文本;实际工具仍按策略校验。OpenCode 优先使用其原生 SKILL.md 发现、加载及权限机制,首版远端技能由管理员部署,平台不承诺自动上传或同步技能文件。 +本机运行时更新依赖后执行: -服务鉴权凭据、模型 API 凭据和执行权限是三个独立概念:OpenCode 服务密码用于访问服务,模型凭据由远端管理,文件/Shell 能力取决于远端 agent 权限和运行账号。 +```bash +cd backend +.venv/bin/python -m alembic upgrade head +.venv/bin/python -m db.sync_interface_definitions +``` -工作目录不等于沙箱。内置 Reasoner 的工具许可由平台执行桥校验;OpenCode 的文件/Shell/技能限制必须由远端 agent/session 或部署环境实际执行。无法经适配器应用或核查的策略应显示「由远端管理」,不能提供看似生效的授权、沙箱开关。首版不建设容器编排系统,也不为了任务执行而自动授予全部权限。 +也可在仓库根目录运行 `make db-init`,它会迁移并同步模型接口定义。不要用演示数据 seed 代替正常升级。 -## 前端适配 +迁移后的原 instruction 预设显示在助手「任务要求来源」中;未修改时保存仍保留该来源。默认「Speaker 生成任务要求」适用于新的对话委派。 -提示词编辑页保留当前设计系统,增加以下配置区: +## 代码位置 -1. 模型与语音:现有 LLM 字段明确为「对话模型 Speaker」,保留 ASR/TTS。 -2. 任务后端:关闭 / 内置 Reasoner / 外部 OpenCode;选择后端资源,按类型展示连接和模型配置。 -3. 执行策略:展示能实际执行的策略与后端环境说明;首版并发固定 1。 -4. 技能:Reasoner 选择平台技能;OpenCode 展示远端技能配置来源与已配置说明。 - -资源库新增「任务后端」,工具页移除创建 task 工具的入口。「外部工具」继续管理普通工具,任务配置不再要求管理员填写函数名或 instruction 参数绑定。现有后台任务卡片保留,统一显示两种后端的结果、待输入和取消状态。 - -## 当前代码的迁移位置 - -| 当前模块 | 调整目标 | +| 模块 | 职责 | | --- | --- | -| schemas.py / models.py / db.models | TaskBackendResource、助手 taskBackend 配置、任务 backend_id/type/快照 | -| config_resolver.py | 分别解析 Speaker、任务后端、Reasoner 工具及技能;敏感连接参数只在服务端组装 | -| background_tasks/service.py | submit 接收解析后的任务后端配置,按类型选择执行后端,移除 RuntimeTool 依赖 | -| brains/prompt_tasks.py | 按助手 taskBackend 配置注册平台任务控制入口,使用统一任务状态与通知 | -| brains/prompt_brain.py | 根据 taskBackend 启用委派指导,普通工具循环仅处理普通工具 | -| background_tasks/native.py | 保留应用级原生 Job 宿主,内置 Reasoner 接入 BackendLLMWorker | -| background_tasks/opencode.py | 保留现有协议逻辑,增加经验证可用的 agent/model 选择 | -| routes/background_tasks.py | 从绑定后端解析配置,提交不再要求 toolId;保留查询/取消/输入接口 | -| 前端工具页 / 提示词编辑器 / api.ts | 新任务后端资源入口、独立配置区、移除 task ToolBinding | +| `task_backend_schemas.py` / `db.models` | 后端资源、助手绑定和任务来源 | +| `routes/task_backends.py` / `services/task_backend_resources.py` | 管理、校验、服务端凭据解析 | +| `services/background_tasks/service.py` / `native.py` | 业务任务投影与应用级原生 Jobs | +| `services/background_tasks/reasoner.py` | `BackendLLMWorker`、完成/提问控制与工具桥 | +| `services/background_tasks/opencode.py` | HTTP/SSE、结果关联、abort、重新观察 | +| `services/brains/prompt_tasks.py` | Speaker 委派入口、查询/输入/取消与通知 | +| `routes/background_tasks.py` | 从助手已绑定的后端解析提交配置,任务 API 不接收 toolId | +| 前端任务后端资源页 / 提示词编辑器 | 独立资源、Speaker 标注、指令预设和任务卡片 | -迁移已有 task 工具时,复制连接与凭据到后端资源,把助手绑定转为 taskBackend 引用。原 instruction 的固定值/变量绑定需明确迁为任务指令预设,不能静默丢弃;无法直接迁移的配置应给出具体提示。历史任务保留原 task_id、结果和冻结连接信息,补后端来源,正在执行的任务继续按原句柄观察。 +## 验证边界 -建议按三个可验收阶段落地: +验收应检查上下文隔离、不支持的推理配置明确拒绝、工具白名单和技能不能扩大权限、状态未知不重复执行、断线继续执行、取消可核查,以及旧凭据和指令预设不会丢失。仓库自动测试中使用的模型和 OpenCode 协议模拟会明确标注;真实 Provider、远端编码执行与部署网络仍需单独联调。具体执行记录以 `implement-stage/task-backends/BUILD_NOTE.md` 为准。 -1. 迁出 task 工具资源和助手绑定,保持 OpenCode 执行与历史恢复可用。 -2. 实现内置 Reasoner 的真实执行路径,复用原生 BackendLLMWorker 和现有服务端工具;前端只展示已实现的能力。 -3. 补齐策略生效校验、技能加载、迁移回归和两种后端的共同验收。 +## 参考 -验收重点为 Speaker 无需等待任务结束才能继续交流;任务上下文隔离;不支持的推理配置明确拒绝;任务状态未知不重复执行;语音断线不取消任务;明确取消可核查;后台不能执行依赖已断开浏览器的客户端工具;技能不能扩大权限;历史连接与指令配置不丢失。 - -## 核查依据 - -- 本地已安装 Pipecat 1.13.0 源码:workers/llm/backend_llm_worker.py、llm_context_worker.py、pipeline/llm_with_backend.py。 - [Pipecat BackendLLMWorker](https://reference-server.pipecat.ai/en/latest/api/pipecat.workers.llm.backend_llm_worker.html) - [Pipecat LLMWithBackend](https://reference-server.pipecat.ai/en/latest/api/pipecat.pipeline.llm_with_backend.html) - [OpenCode Server](https://opencode.ai/docs/server/) - [OpenCode 权限](https://opencode.ai/docs/permissions/) - [OpenCode 技能](https://opencode.ai/docs/skills/) -- [OpenCode 模型配置](https://opencode.ai/docs/models/) diff --git a/docs-developer/tool-resources.mdx b/docs-developer/tool-resources.mdx index c846195..8adc59e 100644 --- a/docs-developer/tool-resources.mdx +++ b/docs-developer/tool-resources.mdx @@ -14,6 +14,8 @@ icon: wrench | 工具资源 | `Tool` | 可复用的连接、请求/响应结构和工具私密 | HTTP、MCP、Client Tool | | 工具绑定 | `toolBindings` / `toolBinding` | 某次使用中的参数来源、模板输入和结果映射 | `order_id` 由模型填写,`tenant` 来自变量 | +提示词 Pipeline 的长任务通过独立的[任务后端资源](/prompt-task-backends)配置,可选内置 Reasoner 或外部 OpenCode。OpenCode 不属于工具资源;Speaker 的 `delegate_task` 等任务控制入口由平台自动注册,无需管理员填写函数名。Reasoner 只使用后端资源显式绑定的 HTTP/MCP 工具。 + ## 平台内建工具 内建工具不是“组件库 / 工具资源”中的记录,也没有 `toolId`。Prompt 在 Assistant 层配置,Workflow 可在全局或独立 Agent 阶段配置。 diff --git a/docs-user/features.mdx b/docs-user/features.mdx index a109905..5d1c62c 100644 --- a/docs-user/features.mdx +++ b/docs-user/features.mdx @@ -42,6 +42,21 @@ Pipeline 的“高级交互配置”可以调整 VAD 阈值、开始/停止确 Prompt Realtime 中,Qwen Audio 已声明部分 HTTP、MCP、Client 和内置工具能力;StepFun Prompt Realtime 尚未声明工具能力。保存助手前,界面和服务端会校验不兼容项。外部 Agent 的上下文、知识库和工具通常由对应服务管理。 +## Speaker 与任务后端 + +提示词 Pipeline 可配置「对话模型 Speaker + 任务后端」。Speaker 负责语音交流、澄清与播报,任务后端有独立上下文,执行期间可继续对话。Workflow 和 Realtime 当前不支持任务后端。 + +在「组件库 → 任务后端」创建资源,再到提示词助手的「任务后端」区域选择。任务后端不在普通工具列表中,也不需要填写委派函数名。 + +| 后端 | 配置 | 执行边界 | +| --- | --- | --- | +| 内置 Reasoner | 独立 LLM 模型、推理强度、HTTP/MCP 工具白名单、内联技能 | 只有模型已声明支持 `reasoning_effort` 才可选非默认强度;Client 工具不可用于后台执行。技能不能扩大工具权限。 | +| 外部 OpenCode | 服务地址、工作目录、用户名/密码,可选 Agent 和远端模型 | 文件、Shell、沙箱与技能由远端环境管理;平台不安装远端软件或技能。 | + +默认任务时限 600 秒,可设置 30–7200 秒,覆盖排队和执行;当前要求单进程运行,全局并发固定 1。展开语音调试中的「后台任务」可查看结果、回答问题或停止任务。插话和语音断线不会自动取消任务;明确停止后需核查执行状态,已发出的操作可能已有副作用。 + +应用重启后,OpenCode 仅重新观察已保存的任务句柄;Reasoner 标记为中断,不自动重放工具。真实模型及远端编码环境仍需联调,不能以模拟测试代替真实执行验收。 + ## 配置建议 - 需要明确控制 ASR、LLM、TTS、VAD 和轮次结束策略时,先选 Pipeline。 diff --git a/docs-user/quickstart.mdx b/docs-user/quickstart.mdx index 91fba50..35df2f9 100644 --- a/docs-user/quickstart.mdx +++ b/docs-user/quickstart.mdx @@ -23,6 +23,8 @@ icon: rocket 保存后从助手详情页打开语音预览。第一次验证建议只检查听取用户语音、生成回复、播放语音和打断;确认基本链路后再添加知识库、视觉、工具或 Workflow。 +确认基本对话链路后,可选配独立任务后端:在「组件库 → 任务后端」创建 Reasoner 或 OpenCode 资源,再回到提示词 Pipeline 助手的「任务后端」区域绑定。Speaker 仍负责对话;Reasoner 使用单独模型与 HTTP/MCP 工具许可,OpenCode 使用其远端执行环境。完整适用范围见[功能与配置](/features)。 + ## 3. 接入业务客户端 语音预览通过后,按[接入方式](/access)选择公开 WebRTC 或 WebSocket。浏览器麦克风需要 localhost 或 HTTPS;公网 WebRTC 通常还要配置 TURN。公开接口以 `assistant:<助手 ID>` 选择助手,第三方客户端不直接提交底层模型密钥。 diff --git a/docs-user/status.mdx b/docs-user/status.mdx index 3ff7a85..08e0c4a 100644 --- a/docs-user/status.mdx +++ b/docs-user/status.mdx @@ -20,6 +20,7 @@ icon: list-checks | Responses 文本接口 | 已实现 | 面向可通过该接口调用的 Pipeline 助手。 | | WebRTC 可选摄像头与视觉处理 | 有条件可用 | 需要助手授权视觉、客户端协商视频轨道,并受运行模式限制。 | | 工具和知识库 | 有条件可用 | 受助手模式、模型 Provider 与资源配置限制。 | +| Speaker + 内置 Reasoner / OpenCode 任务后端 | 已实现,有条件 | 仅提示词 Pipeline;需真实模型或远端配置,单进程全局并发 1。推理强度受模型能力声明限制,远端权限/沙箱/技能由 OpenCode 环境管理。 | | 会话与消息历史 | 已实现 | 可在管理界面查看,辅助排查。 | ## 未实现或尚未承诺