Install
openclaw skills install alibabacloud-wxz-website-builderUse when building or modifying websites with AI Staff (零号员工/万小智) via Alibaba Cloud OpenAPI. Supports conversation creation, async chat with requirement collection, PRD generation, code generation, and incremental SSE event polling.
openclaw skills install alibabacloud-wxz-website-builderCategory: service
mkdir -p output/alibabacloud-wxz-website-builder
for f in skills/ai/service/alibabacloud-wxz-website-builder/scripts/*.py; do
python3 -m py_compile "$f"
done
echo "py_compile_ok" > output/alibabacloud-wxz-website-builder/validate.txt
Pass criteria: command exits 0 and output/alibabacloud-wxz-website-builder/validate.txt is generated.
output/alibabacloud-wxz-website-builder/.pip install alibabacloud_tea_openapi>=0.4.4 alibabacloud_tea_util>=0.3.14
This skill relies on the Alibaba Cloud default credential chain. Do NOT set AK/SK explicitly. The SDK automatically resolves credentials in the following order:
ALIBABACLOUD_ACCESS_KEY_ID / ALIBABACLOUD_ACCESS_KEY_SECRET~/.alibabacloud/credentialsRegion: ALIBABACLOUD_REGION_ID defaults to cn-hangzhou.
If the user has no AccessKey yet, guide them through these steps (see references/ak-setup-guide.md for full details):
zero2staff:CreateAIStaffConversationzero2staff:CreateAIStaffChatzero2staff:ListAIStaffChatEventszero2staff:ListAIStaffChatMessages~/.alibabacloud/credentials or set environment variablesCRITICAL: When guiding the user, remind them:
If the user encounters auth errors, refer to the troubleshooting table in references/ak-setup-guide.md.
The complete flow has 3 phases. Follow them sequentially.
IMPORTANT — Agent-driven polling: The chat command fires the request and returns immediately. The agent then drives the polling loop via the poll command. Between each poll, the agent MUST show the user a progress message so they know what's happening (use progressDetail for rich messages).
Phase 1: Create Conversation
↓
Phase 2: Fire requirement chat → poll → HITL → Fire resume → poll → ... → PRD ready
↓
Phase 3: Fire code generation → Show link → poll loop with progress → Site ready
Ensure Alibaba Cloud credentials are configured via the default credential chain (see Authentication section above).
MUST create a conversation before any chat operation:
CONV=$(python scripts/aistaff_api.py create-conversation --text "做个popmart首页")
CONV_ID=$(echo $CONV | jq -r '.ConversationId')
CHAT_ID=$(echo $CONV | jq -r '.ChatId')
SITE_ID=$(echo $CONV | jq -r '.SiteId')
Returns flat JSON: {ConversationId, SiteId, ChatId, SectionId, BotId, Title}.
This phase collects requirements and generates a PRD. The platform may ask multiple HITL rounds (basic info → features → language, etc.). To keep things fast:
python scripts/aistaff_api.py chat \
--text "做个popmart首页" \
--conversation-id $CONV_ID \
--biz-id $SITE_ID
Tell user: "正在分析您的需求,请稍候..."
Call poll every 5 seconds until phase is waiting_for_input:
python scripts/aistaff_api.py poll \
--conversation-id $CONV_ID \
--biz-id $SITE_ID \
--last-event-id 0
Between each poll, show the user a progress message based on phase:
processing → "需求分析进行中..."fetching_reference → "正在获取参考网站信息..."waiting_for_input → First HITL form arrived, proceed to Step 3.Extract questions from the metaData.arguments of the message.tool event where name: "AskUserQuestion". Present these questions to the user via the AskUserQuestion tool (typically: app name, business description, target users, reference site).
--phase generate_prdCRITICAL: On the first HITL resume, always pass --phase generate_prd --user-navigation generate_prd.
python scripts/aistaff_api.py chat \
--text '{"应用名称": "POP MART 官网", "主营服务": "潮流玩具", "目标用户": "Z世代潮流青年", "参考网站": "无"}' \
--conversation-id $CONV_ID \
--biz-id $SITE_ID \
--chat-id $CHAT_ID \
--chat-status interrupt \
--phase generate_prd \
--user-navigation generate_prd \
--hidden --without-refer
The --text JSON keys MUST match the header values from the form.
Tell user: "已收到您的需求,正在生成产品方案..."
Poll every 5 seconds. Based on phase / summary, take action:
phase == "waiting_for_input" (another HITL question) → Auto-fill immediately using the answers field from the AskUserQuestion event, then fire resume again. Tell user: "正在完善需求细节..."phase == "generating_prd" → Tell user: "PRD 方案生成中,请稍候..."phase == "fetching_reference" → Tell user: "正在获取参考资料..."summary.chatStatus == "success" + summary.hasPrd == true → PRD ready, proceed to Phase 3.summary.chatStatus == "fail" → Ask user whether to retry.# Poll example:
python scripts/aistaff_api.py poll \
--conversation-id $CONV_ID \
--biz-id $SITE_ID \
--last-event-id $LAST_EVENT_ID
# Auto-fill example (use the "answers" field from the AskUserQuestion event):
python scripts/aistaff_api.py chat \
--text '{"核心功能": ["商品展示", "品牌故事", "新闻资讯"]}' \
--conversation-id $CONV_ID \
--biz-id $SITE_ID \
--chat-id $CHAT_ID \
--chat-status interrupt \
--phase generate_prd \
--user-navigation generate_prd \
--hidden --without-refer
Key rule: The platform's AskUserQuestion event always includes an answers field with sensible defaults. For rounds after the first, always use these defaults directly instead of prompting the user.
When PRD is ready:
python scripts/aistaff_api.py chat \
--text "确认生成应用" \
--conversation-id $CONV_ID \
--biz-id $SITE_ID \
--phase generate_code \
--without-refer
MUST show before and after code generation:
https://wanwang.aliyun.com/webdesign/home#/ai/manage/prd?conversationId=<CONV_ID>
Tell user: "代码生成已启动,通常需要 2-5 分钟。您可以先通过上面的链接查看项目,我会持续跟踪进度..."
Poll every 10 seconds. Show the user progress between each poll:
python scripts/aistaff_api.py poll \
--conversation-id $CONV_ID \
--biz-id $SITE_ID \
--last-event-id $LAST_EVENT_ID
Progress messages to show (use progressDetail for rich messages):
phase == "processing" + progressDetail.latestFile exists → "代码生成中...正在写入: {latestFile.semantic}(已生成 {filesWrittenCount} 个文件)"phase == "processing" + no latestFile → "代码生成中...已处理 N 个事件"phase == "processing" + progressDetail.lastMessage exists → Also show the assistant's latest message as contextphase == "success" → Site is ready! Show link again.phase == "fail" → Ask user whether to retry.summary.chatStatus == "success" → Site is ready. Show site link again.summary.chatStatus == "fail" or summary.hasError == true → Ask user whether to retry. Do NOT auto-retry.chat with --conversation-id to modify the site.summary.chatStatus | summary.hasPrd | Phase | Action |
|---|---|---|---|
interrupt | — | 2 (first round) | Parse AskUserQuestion, collect answers from user, resume with --phase generate_prd |
interrupt | — | 2 (subsequent) | Auto-fill with default answers from the AskUserQuestion event, resume immediately — do NOT ask user |
success | true | 2 | PRD ready → proceed to Phase 3 |
success | false | 3 | Site is ready → show link |
fail | — | any | Ask user whether to retry |
unknown | — | any | Poll timed out → use list-messages fallback |
python scripts/aistaff_api.py create-conversation --text "用户问题"
Returns flat JSON: {ConversationId, SiteId, ChatId, SectionId, BotId, Title}.
Fire an async chat message and return immediately. Automatically drains old SSE events before firing. Use poll afterwards to track progress.
python scripts/aistaff_api.py chat --text "description" --conversation-id <ID> --biz-id <ID> [options]
Key parameters:
--text TEXT: Message text or form answers JSON (required)--conversation-id ID / --biz-id ID: Required identifiers--chat-id ID + --chat-status interrupt: For HITL resume--phase {requirement_collect,generate_prd,generate_code}: Phase to enter--user-navigation TARGET: Navigation target (use generate_prd with --phase generate_prd)--hidden / --without-refer: Hide message / skip reference context--verbose: Show debug infoReturns JSON:
{
"conversationId": "conv-xxx",
"chatId": "chat-xxx",
"status": "fired",
"error": null
}
Single-shot status check — fetches new events once + checks message status, then returns immediately. Designed for agent-driven polling loops where the agent controls the pace and shows progress to the user between calls.
python scripts/aistaff_api.py poll --conversation-id <ID> --biz-id <ID> [--last-event-id N]
Key parameters:
--last-event-id N: Cursor from previous poll (default: 0). Pass the lastEventId from the previous poll result to get only new events.--max-output-events N: Limit events in output (default: 10, 0=unlimited)Returns JSON:
{
"conversationId": "conv-xxx",
"lastEventId": 45,
"newEvents": 3,
"phase": "generating_prd",
"summary": {
"chatStatus": "processing",
"hasError": false,
"errorMsg": "",
"hasPrd": false,
"toolsCalled": ["FetchWebsiteInfo"]
},
"progressDetail": {
"filesWrittenCount": 5,
"activeTools": ["Write"],
"latestFile": {
"path": "/home/wuying/workspace/src/components/Hero.tsx",
"semantic": "首页 Hero 轮播组件",
"status": "wait"
},
"allFiles": [
{"path": "/home/wuying/workspace/src/types/order.ts", "semantic": "订单类型定义"},
{"path": "/home/wuying/workspace/src/components/Hero.tsx", "semantic": "首页 Hero 轮播组件"}
],
"lastMessage": "好的,正在为您生成首页组件...",
"toolProgress": [
{"name": "Write", "status": "done", "semantic": "订单类型定义"},
{"name": "Write", "status": "wait", "semantic": "首页 Hero 轮播组件"}
]
},
"events": ["(last 10 events)"]
}
progressDetail fields — use these to build informative progress messages:
filesWrittenCount: Total number of files generated so far.activeTools: Tools currently in progress (status=wait). Empty when all tools have completed.latestFile: The most recent file being written — show semantic to the user (e.g. "正在生成: 首页 Hero 轮播组件").allFiles: Complete list of files written, each with path and semantic.lastMessage: Latest assistant text message (truncated to 200 chars).toolProgress: Per-tool status list with name, status (wait/done), and semantic.Suggested progress messages based on progressDetail:
latestFile has status == "wait": "正在生成: {latestFile.semantic}..."latestFile has status == "done" and activeTools is empty: "已完成 {filesWrittenCount} 个文件,等待下一步..."filesWrittenCount > 0 and activeTools is not empty: "代码生成中...已生成 {filesWrittenCount} 个文件,正在写入: {latestFile.semantic}"lastMessage is not empty: Show it as additional context.phase values:
| Phase | Meaning | Suggested user message |
|---|---|---|
processing | General processing | "处理中..." |
fetching_reference | Fetching reference site | "正在获取参考网站信息..." |
waiting_for_input | HITL form ready | (parse form and handle) |
generating_prd | PRD generation in progress | "PRD 方案生成中..." |
success | Completed successfully | "完成!" |
fail | Failed | (ask user whether to retry) |
Query the latest chat messages. Returns the last N messages (default: 10).
python scripts/aistaff_api.py list-messages --conversation-id <ID> [--tail 10]
Key usage: Use this to check ChatStatus of the last message when poll shows no progress.
chat command automatically drains old events before firing.poll, pass the lastEventId from the previous poll result to avoid re-processing events.poll command detects this via event summary.| Error | Action |
|---|---|
| Auth error | Ensure credentials are configured via default credential chain (env vars, config file, or RAM role) |
summary.chatStatus == "fail" | Ask user whether to retry. Do NOT auto-retry |
| Poll shows no progress for 5+ minutes | Use list-messages to check actual status |
cd skills/ai/service/alibabacloud-wxz-website-builder
# Phase 1: Create conversation
CONV=$(python scripts/aistaff_api.py create-conversation --text "做个popmart首页")
CONV_ID=$(echo $CONV | jq -r '.ConversationId')
CHAT_ID=$(echo $CONV | jq -r '.ChatId')
SITE_ID=$(echo $CONV | jq -r '.SiteId')
# Phase 2 Step 1: Fire requirement collection
python scripts/aistaff_api.py chat \
--text "做个popmart首页" \
--conversation-id $CONV_ID \
--biz-id $SITE_ID
# → Tell user: "正在分析您的需求,请稍候..."
# Phase 2 Step 2: Poll until first HITL form arrives
# (agent calls this every ~5s, shows progress between calls)
python scripts/aistaff_api.py poll \
--conversation-id $CONV_ID \
--biz-id $SITE_ID \
--last-event-id 0
# → Check phase: "waiting_for_input" means form is ready
# Phase 2 Step 3: Parse AskUserQuestion → collect from user (FIRST round only)
# Phase 2 Step 4: Fire resume with user answers
python scripts/aistaff_api.py chat \
--text '{"应用名称": "POP MART 官网", "主营服务": "潮流玩具", "目标用户": "Z世代潮流青年", "参考网站": "无"}' \
--conversation-id $CONV_ID \
--biz-id $SITE_ID \
--chat-id $CHAT_ID \
--chat-status interrupt \
--phase generate_prd \
--user-navigation generate_prd \
--hidden --without-refer
# → Tell user: "已收到您的需求,正在生成产品方案..."
# Phase 2 Step 5: Poll loop (agent-driven, ~5s interval)
# - phase="waiting_for_input" → auto-fill with defaults, fire resume
# → Tell user: "正在完善需求细节..."
# - phase="generating_prd" → Tell user: "PRD 方案生成中..."
# - summary.chatStatus="success" + summary.hasPrd=true → PRD ready, proceed
# Phase 3 Step 1: Fire code generation
python scripts/aistaff_api.py chat \
--text "确认生成应用" \
--conversation-id $CONV_ID \
--biz-id $SITE_ID \
--phase generate_code \
--without-refer
# Phase 3 Step 2: Show link immediately
echo "Link: https://wanwang.aliyun.com/webdesign/home#/ai/manage/prd?conversationId=$CONV_ID"
# → Tell user: "代码生成已启动,通常需要 2-5 分钟..."
# Phase 3 Step 3: Poll loop with progress (~10s interval)
python scripts/aistaff_api.py poll \
--conversation-id $CONV_ID \
--biz-id $SITE_ID \
--last-event-id $LAST_EVENT_ID
# → Use progressDetail.latestFile.semantic for rich messages
# → phase="success" → show link again, done!
# Modify site (optional, same chat+poll pattern)
python scripts/aistaff_api.py chat \
--text "首页title改下" \
--conversation-id $CONV_ID \
--biz-id $SITE_ID
# → poll loop...