# -*- coding: utf-8 -*- """ 可选桌面 E2E 示例(默认不执行:文件名后缀为 .sample)—— **简单问答场景**。 启用方式: 复制本文件为 test_desktop_smoke.py,按目标技能修改提问文案与断言。 运行:pytest tests/desktop/test_desktop_smoke.py -v -s 依赖:pytest、jiangchang_desktop_sdk、匠厂桌面宿主已就绪。 【何时用此模板】 - 技能只需要发一句话给 Main Agent,等回复,做断言(纯问答) - 不涉及上传附件 / 不涉及 RPA 长流程 【何时不要用此模板,改用 test_desktop_smoke_with_attachment.py.sample】 - 需要上传文件(Excel / PDF / 图片)作为附件 - 技能内部跑 RPA / 长流程(> 2 分钟),需要精细等待 【已知 SDK 限制(来自 disburse-payroll-icbc 实战)】 - client.ask() 内部对"找到 user 消息节点"只给 15 秒窗口,找不到就锁死 user_msg_index=-1,后续等待 assistant 永远 return None。如果你的场景里 匠厂启动较慢 / gateway 握手有延迟,client.ask() 可能假死到 timeout。 此模板仍用 ask(),因为它对**简单场景**够用。复杂场景请用 _with_attachment.py.sample 里的"绕开 ask()"模式。 - client.send_file() 在 v2.0.17+ 抛 NotImplementedError,**绝不要调用它**。 需要附件请用 _with_attachment.py.sample 里的拖拽方案。 """ from __future__ import annotations import logging import os import pytest from jiangchang_desktop_sdk import AskOptions, JiangchangDesktopClient _logger = logging.getLogger("skill-template-desktop-e2e-sample") if not _logger.handlers: _logger.setLevel(logging.INFO) _h = logging.StreamHandler() _h.setFormatter(logging.Formatter("[E2E-sample] %(message)s")) _logger.addHandler(_h) _ARTIFACT_DIR = os.path.join(os.path.dirname(__file__), "artifacts") class TestDesktopSmokeSample: """最小 smoke:拉起桌面、等待网关、发一条与技能路由相关的问句并做宽松断言。""" @pytest.fixture(autouse=True) def connect_and_teardown(self, request): client = JiangchangDesktopClient() _logger.info("ensure_app_running") client.ensure_app_running(wait_timeout_s=30) client.bring_to_front() client.wait_gateway_ready(timeout_ms=30000) self.client = client yield try: rep = getattr(request.node, "rep_call", None) if rep is not None and rep.failed: os.makedirs(_ARTIFACT_DIR, exist_ok=True) paths = client.snapshot(_ARTIFACT_DIR, tag=request.node.name) _logger.error("snapshot: %s", paths) finally: client.disconnect() def test_gateway_and_simple_ask(self) -> None: """请将 SKILL 名与路由关键词改成你复制后的真实技能。""" answer = self.client.ask( "请使用当前已安装技能执行一次 health 检查并返回 OK 或等价结果。", AskOptions(timeout=120000, new_task=True), ) assert answer assert "OK" in answer or "ok" in answer.lower() or "健康" in answer