跳到正文
cccskills
免费在 GitHub 公开

verify

Build and run computer-use-demo in Docker, then use Playwright to test its Streamlit interface without opening a visible browser. Save conversation transcripts, API exchanges, and screenshots to inspect behavior after changes.

中文简介正在准备中。当前显示英语简介。

原文查看原文说明

Build the computer-use-demo image and drive the Streamlit UI headlessly to verify changes end-to-end.

集成工具Playwright
查看安装方法

适用场景

  • Checking the interface after changing computer-use-demo
  • Testing combinations of models and tool versions
  • Checking Thinking settings and model changes during a session
  • Saving conversations, API exchanges, and screenshots for review

包含的文件(1)

  • SKILL.md6.1 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Verifying changes to this demo

The surface is the Streamlit app inside the container. Build the image from this directory, run it, and drive the UI with Playwright. pytest, ruff, and pyright are CI's job, not evidence.

Build and run

docker build . -t computer-use-demo:verify
docker rm -f cu-verify 2>/dev/null
docker run -d --name cu-verify \
  -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY -e WIDTH=1024 -e HEIGHT=768 \
  -p 18501:8501 -p 18080:8080 -p 16080:6080 computer-use-demo:verify
until curl -sf localhost:18501/_stcore/health >/dev/null; do sleep 1; done

A cold build takes several minutes (apt, LibreOffice, a pyenv Python compile). The requirements.txt layer is cached separately, so source-only changes rebuild in seconds.

To iterate without rebuilding, copy sources over the baked copy before the first browser session compiles the script:

docker cp computer_use_demo/. cu-verify:/home/computeruse/computer_use_demo/

Streamlit's file watcher does not notice docker cp replacements once a session has run. Recreate the container instead of docker restart, which fails on a stale X lock (tint2: could not open display).

Drive the UI

Install Playwright in any venv (pip install playwright && python -m playwright install chromium) and run the script below. It sets the model, picks a tool version, optionally sets the thinking mode, sends a prompt, waits for the loop to go idle, then dumps the chat transcript and every HTTP exchange (request headers and JSON, response JSON) with auth headers redacted.

THINKING=Adaptive python drive.py 18501 claude-sonnet-5 computer_toolset_20260801 \
  "Take a screenshot, then zoom in on the taskbar and list the icons." out/ 240

Pass - for model or tool version to keep the default. THINKING=Off|Adaptive|Extended clicks that radio. TOKEN_EFFICIENT=1 ticks the beta checkbox.

What to read afterwards:

  • out/chat.txt: the rendered conversation, including Tool Use: <name> lines and any error box with its traceback.
  • out/exchange-NN.txt: one file per API round trip. Check tools, anthropic-beta, and the tool_use / tool_result blocks here rather than trusting the chat rendering.
  • out/02-chat.png, out/04-http-logs-expanded.png: full-page screenshots.

Useful probes: an older model with a newer tool version (expect a clean 400 in the error box, not a crash), toggling Thinking to Off before the first message, and switching models mid-session.

"""drive.py <port> <model|-> <tool_version|-> <prompt> <outdir> [wait_secs]"""

import os
import re
import sys
import time
from pathlib import Path

from playwright.sync_api import sync_playwright

port, model, tool_version, prompt, outdir = sys.argv[1:6]
wait_secs = int(sys.argv[6]) if len(sys.argv) > 6 else 180
out = Path(outdir)
out.mkdir(parents=True, exist_ok=True)
MAIN = "[data-testid='stMain'], section.main, [data-testid='stAppViewContainer']"


def log(msg: str) -> None:
    print(f"[{time.strftime('%H:%M:%S')}] {msg}", flush=True)


with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page(viewport={"width": 1400, "height": 1600})
    page.goto(f"http://localhost:{port}", wait_until="networkidle", timeout=120_000)
    page.wait_for_selector("text=Tool Versions", timeout=120_000)
    sidebar = page.locator("[data-testid='stSidebar']")

    model_input = page.get_by_label("Model", exact=True)
    if model != "-":
        model_input.fill(model)
        model_input.press("Enter")  # commits the text_input and fires on_change
        time.sleep(2)
    if tool_version != "-":
        sidebar.get_by_text(tool_version, exact=True).click()
        time.sleep(2)
    if thinking := os.environ.get("THINKING"):
        sidebar.get_by_text(thinking, exact=True).click()
        time.sleep(2)
    if os.environ.get("TOKEN_EFFICIENT"):
        sidebar.get_by_text("Enable token-efficient tools beta", exact=True).click()
        time.sleep(2)
    log(f"model={model_input.input_value()!r} tools={tool_version} thinking={thinking}")
    page.screenshot(path=str(out / "01-sidebar.png"), full_page=True)

    chat = page.locator("textarea[data-testid='stChatInputTextArea']")
    chat.fill(prompt)
    chat.press("Enter")
    log("prompt sent")

    # The status widget is present while the script (and so the sampling loop) runs.
    deadline = time.time() + wait_secs
    time.sleep(5)
    while time.time() < deadline:
        running = page.locator("[data-testid='stStatusWidget']").count() > 0
        msgs = page.locator("[data-testid='stChatMessage']").count()
        log(f"running={running} chat_messages={msgs}")
        if not running and msgs >= 2:
            time.sleep(4)
            if page.locator("[data-testid='stStatusWidget']").count() == 0:
                break
        time.sleep(5)

    page.screenshot(path=str(out / "02-chat.png"), full_page=True)
    (out / "chat.txt").write_text(page.locator(MAIN).first.inner_text(timeout=10_000))

    page.get_by_role("tab", name="HTTP Exchange Logs").click()
    time.sleep(3)
    expanders = page.locator("[data-testid='stExpander']")
    for i in range(expanders.count()):
        exp = expanders.nth(i)
        exp.locator("summary").click()
        time.sleep(1.5)
        txt = exp.inner_text(timeout=15_000)
        txt = re.sub(r"(?im)^(`?)(authorization|x-api-key): .*$", r"\1\2: [REDACTED]", txt)
        (out / f"exchange-{i + 1:02d}.txt").write_text(txt)
    page.screenshot(path=str(out / "04-http-logs-expanded.png"), full_page=True)
    log(f"captured {expanders.count()} exchanges")
    browser.close()

Gotchas

  • The sidebar requires a non-empty API key for the Anthropic provider before it renders the chat. ANTHROPIC_API_KEY in the container env pre-fills it.
  • Each Playwright run is a fresh Streamlit session, so the HTTP exchange log only contains that run's requests. Capture it in the same run.
  • If PYTEST_DISABLE_PLUGIN_AUTOLOAD is set in your shell, pytest silently skips every async test. Run with -p pytest_asyncio or unset it.

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

first-run

免费

Guide a first computer-use agent run from environment checks to a browser-only task and a viewer of the run history. Explain each stage so users can understand the output and review screenshots afterward.

中文简介正在准备中。当前显示英语简介。

  • Checking the environment before a first agent run
  • Trying browser automation without moving the mouse or keyboard
  • Reviewing screenshots and prompts from a completed run
anthropics/claude-quickstarts1.9万2026年10月9日 更新

verify

免费

Verify changes to the copilot-kit-ag-ui demo by building and running its server. Check API routing, cross-origin access settings, and build configuration, then use real credentials to confirm that a requested chart appears.

中文简介正在准备中。当前显示英语简介。

  • Checking server routing after changes
  • Testing API wiring without real Anthropic credentials
  • Checking which website origins can access the server
anthropics/claude-quickstarts1.9万2026年10月9日 更新

查看 anthropics 的全部技能

报告此技能的问题