#!/usr/bin/env bash set -Eeuo pipefail if [ "${PASCAL_SMOKE_CONFIRM:-}" != "1" ]; then printf '%s\n' \ 'This check makes one real model request and then deletes its temporary scene.' \ 'Run with PASCAL_SMOKE_CONFIRM=1 after confirming provider usage is acceptable.' >&2 exit 2 fi command -v curl >/dev/null 2>&1 || { printf 'curl is required.\n' >&2; exit 1; } command -v node >/dev/null 2>&1 || { printf 'node is required.\n' >&2; exit 1; } PASCAL_ENV_FILE="${PASCAL_ENV_FILE:-/opt/pascal-editor/.env.production}" PASCAL_PORT="${PASCAL_PORT:-3002}" PASCAL_BASE_PATH="${PASCAL_BASE_PATH:-/pascal-service}" PASCAL_BASE_PATH="/${PASCAL_BASE_PATH#/}" PASCAL_BASE_PATH="${PASCAL_BASE_PATH%/}" BASE_URL="${PASCAL_INTERNAL_URL:-http://127.0.0.1:${PASCAL_PORT}}${PASCAL_BASE_PATH}" USER_ID="deployment-smoke-test" SCENE_ID="deployment-smoke-scene" read_env_value() { sed -n "s/^${1}=//p" "$PASCAL_ENV_FILE" | tail -n 1 } SECRET="${PASCAL_PROXY_SECRET:-$(read_env_value PASCAL_AGENT_PROXY_SECRET)}" [ -n "$SECRET" ] || { printf 'PASCAL proxy secret is not configured.\n' >&2 exit 1 } stream_file="$(mktemp)" scene_file="$(mktemp)" prompt="${PASCAL_SMOKE_PROMPT:-创建一个4米乘4米的简单房间,添加一扇门和一扇窗,检查结构后保存。}" cleanup() { curl -sS -o /dev/null -X DELETE \ -H "X-Pascal-Scene-Token: $SECRET" \ -H "X-Pascal-User-Id: $USER_ID" \ "$BASE_URL/api/scenes/$SCENE_ID" || true rm -f "$stream_file" "$scene_file" } trap cleanup EXIT cleanup payload="$(node -e ' const sceneId = process.argv[1]; const prompt = process.argv[2]; process.stdout.write(JSON.stringify({ sceneId, messages: [{ id: "deployment-smoke-message", role: "user", parts: [{ type: "text", text: prompt }], }], })); ' "$SCENE_ID" "$prompt")" curl -fsS -X POST \ -H 'Content-Type: application/json' \ -H "X-Pascal-Scene-Token: $SECRET" \ -H "X-Pascal-User-Id: $USER_ID" \ --data "{\"id\":\"$SCENE_ID\",\"name\":\"Deployment smoke test\",\"graph\":{\"nodes\":{},\"rootNodeIds\":[]}}" \ "$BASE_URL/api/scenes" >/dev/null http_code="$(curl -sS --max-time "${PASCAL_SMOKE_TIMEOUT_SECONDS:-360}" \ -o "$stream_file" \ -w '%{http_code}' \ -X POST \ -H 'Content-Type: application/json' \ -H "X-Pascal-Agent-Proxy-Secret: $SECRET" \ -H "X-Pascal-User-Id: $USER_ID" \ --data "$payload" \ "$BASE_URL/api/agent/chat")" [ "$http_code" = "200" ] || { printf 'Agent smoke request returned HTTP %s.\n' "$http_code" >&2 exit 1 } if grep -q '"type":"error"' "$stream_file"; then printf 'Agent smoke stream reported an error.\n' >&2 exit 1 fi curl -fsS \ -H "X-Pascal-Scene-Token: $SECRET" \ -H "X-Pascal-User-Id: $USER_ID" \ "$BASE_URL/api/scenes/$SCENE_ID" >"$scene_file" node -e ' const fs = require("node:fs"); const scene = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); const expectedOwner = process.argv[2]; if (!(scene.nodeCount > 0)) throw new Error("Agent did not persist scene nodes"); if (scene.ownerId !== expectedOwner) throw new Error("Scene owner mismatch"); console.log(JSON.stringify({ nodeCount: scene.nodeCount, ownerId: scene.ownerId, version: scene.version })); ' "$scene_file" "$USER_ID" printf '[pascal-smoke] Real model and MCP persistence check passed.\n'