Files
th-hotel-simple/scripts/superagent-direct-stream-test.sh
2026-07-12 09:57:54 +08:00

346 lines
9.6 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
set -Eeuo pipefail
# Direct SuperAgent Open API stream test.
# Purpose: bypass TH Hotel backend Debug EML / OSS / SourceMessage and test
# whether SuperAgent Open API itself times out or returns usable SSE events.
#
# Usage on test server:
# cd /home/th-hotel-simple
# bash ./superagent-direct-stream-test.sh
#
# You can either edit the variables below, or override them before running:
# ENV_FILE=/home/th-hotel-simple/th-hotel-server.env bash ./superagent-direct-stream-test.sh
#######################################
# Editable parameters
#######################################
# Your test server env file. It can be plain key=value format.
ENV_FILE="${ENV_FILE:-/home/th-hotel-simple/th-hotel-server.env}"
# Output directory for generated request bodies, response headers, and SSE body.
OUTPUT_DIR="${OUTPUT_DIR:-/tmp/th-hotel-superagent-direct}"
# Curl timeout. This is total curl max time, not SuperAgent's own timeout.
TIMEOUT_SECONDS="${TIMEOUT_SECONDS:-1900}"
CONNECT_TIMEOUT_SECONDS="${CONNECT_TIMEOUT_SECONDS:-30}"
# Optional hard overrides. Leave empty to read from ENV_FILE variables.
BASE_URL="${BASE_URL:-}"
API_KEY="${API_KEY:-}"
EXTERNAL_SUBJECT_ID="${EXTERNAL_SUBJECT_ID:-}"
# The direct test message. Keep it simple first; switch MESSAGE_PAYLOAD_FILE to
# a larger JSON later if you want to mimic Debug EML more closely. If you only
# have an .eml file, set EML_FILE and the script will embed the raw EML text in
# the message payload JSON.
MESSAGE_SUBJECT="${MESSAGE_SUBJECT:-timeout test}"
MESSAGE_TEXT="${MESSAGE_TEXT:-This is a direct curl timeout test. Please return a JSON result.}"
MESSAGE_PAYLOAD_FILE="${MESSAGE_PAYLOAD_FILE:-}"
EML_FILE="${EML_FILE:-}"
MESSAGE_PREFIX="${MESSAGE_PREFIX:-请基于以下 Debug 邮件 JSON 输出结构化任务抽取结果,只返回 JSON不要创建订单或任务}"
#######################################
# Helpers
#######################################
require_command() {
if ! command -v "$1" >/dev/null 2>&1; then
echo "Missing required command: $1" >&2
exit 1
fi
}
mask_secret() {
local value="${1:-}"
if [ -z "$value" ]; then
echo ""
return
fi
if [ "${#value}" -le 8 ]; then
echo "****"
return
fi
echo "${value:0:4}****${value: -4}"
}
load_env_file() {
if [ ! -f "$ENV_FILE" ]; then
echo "ENV_FILE not found: $ENV_FILE" >&2
echo "Edit ENV_FILE at the top of this script, or pass ENV_FILE=/path/to/file." >&2
exit 1
fi
# shellcheck disable=SC1090
set -a
source "$ENV_FILE"
set +a
}
normalize_config() {
BASE_URL="${BASE_URL:-${DEERFLOW_TEST_BASE_URL:-${DEERFLOW_BASE_URL:-}}}"
API_KEY="${API_KEY:-${DEERFLOW_TEST_OPEN_API_KEY:-${DEERFLOW_OPEN_API_KEY:-}}}"
if [ -z "$EXTERNAL_SUBJECT_ID" ]; then
EXTERNAL_SUBJECT_ID="${SUPERAGENT_TEST_DEBUG_EML_EXTERNAL_SUBJECT_ID:-${SUPERAGENT_DEBUG_EML_EXTERNAL_SUBJECT_ID:-th-hotel-debug-eml-upload}}"
fi
if [ -z "$BASE_URL" ]; then
echo "BASE_URL is empty. Set DEERFLOW_TEST_BASE_URL / DEERFLOW_BASE_URL or edit BASE_URL." >&2
exit 1
fi
if [ -z "$API_KEY" ]; then
echo "API_KEY is empty. Set DEERFLOW_TEST_OPEN_API_KEY / DEERFLOW_OPEN_API_KEY or edit API_KEY." >&2
exit 1
fi
if [ -z "$EXTERNAL_SUBJECT_ID" ]; then
echo "EXTERNAL_SUBJECT_ID is empty. Set SUPERAGENT_TEST_DEBUG_EML_EXTERNAL_SUBJECT_ID or edit it." >&2
exit 1
fi
if [ -n "$MESSAGE_PAYLOAD_FILE" ] && [ ! -f "$MESSAGE_PAYLOAD_FILE" ]; then
echo "MESSAGE_PAYLOAD_FILE not found: $MESSAGE_PAYLOAD_FILE" >&2
exit 1
fi
if [ -n "$EML_FILE" ] && [ ! -f "$EML_FILE" ]; then
echo "EML_FILE not found: $EML_FILE" >&2
exit 1
fi
BASE_URL="${BASE_URL%/}"
}
print_config() {
echo "=== Direct SuperAgent stream test ==="
echo "ENV_FILE=$ENV_FILE"
echo "OUTPUT_DIR=$OUTPUT_DIR"
echo "BASE_URL=$BASE_URL"
echo "EXTERNAL_SUBJECT_ID=$EXTERNAL_SUBJECT_ID"
echo "API_KEY=$(mask_secret "$API_KEY")"
echo "TIMEOUT_SECONDS=$TIMEOUT_SECONDS"
echo "CONNECT_TIMEOUT_SECONDS=$CONNECT_TIMEOUT_SECONDS"
echo "MESSAGE_SUBJECT=$MESSAGE_SUBJECT"
if [ -n "$MESSAGE_PAYLOAD_FILE" ]; then
echo "MESSAGE_PAYLOAD_FILE=$MESSAGE_PAYLOAD_FILE"
fi
if [ -n "$EML_FILE" ]; then
echo "EML_FILE=$EML_FILE"
fi
echo
}
write_create_body() {
python3 - <<'PY' > "$CREATE_BODY"
import json
import os
run_id = os.environ["RUN_ID"]
subject = os.environ["EXTERNAL_SUBJECT_ID"]
print(json.dumps({
"external_subject_id": subject,
"idempotency_key": f"{run_id}-session",
"metadata": {
"source": "direct-curl",
"debug_run_id": run_id
}
}, ensure_ascii=False))
PY
}
write_stream_body() {
python3 - <<'PY' > "$STREAM_BODY"
import json
import os
from pathlib import Path
run_id = os.environ["RUN_ID"]
payload_file = os.environ.get("MESSAGE_PAYLOAD_FILE", "").strip()
eml_file = os.environ.get("EML_FILE", "").strip()
prefix = os.environ["MESSAGE_PREFIX"]
if payload_file:
payload_text = Path(payload_file).read_text(encoding="utf-8")
elif eml_file:
eml_path = Path(eml_file)
raw_eml = eml_path.read_text(encoding="utf-8", errors="replace")
payload_text = json.dumps({
"source": "direct-curl",
"schema_version": "direct-raw-eml-v1",
"raw_eml_file_name": eml_path.name,
"raw_eml_size_bytes": eml_path.stat().st_size,
"raw_eml": raw_eml,
}, ensure_ascii=False)
else:
payload_text = json.dumps({
"source": "direct-curl",
"subject": os.environ["MESSAGE_SUBJECT"],
"text": os.environ["MESSAGE_TEXT"],
}, ensure_ascii=False)
message = prefix + "\n" + payload_text
print(json.dumps({
"message": message,
"idempotency_key": f"{run_id}-message",
"metadata": {
"source": "direct-curl",
"debug_run_id": run_id,
"source_message_id": "direct-curl",
"hotel_id": "DIRECT"
}
}, ensure_ascii=False))
PY
}
extract_session_id() {
python3 - "$CREATE_RESPONSE" <<'PY'
import json
import sys
path = sys.argv[1]
try:
with open(path, "r", encoding="utf-8") as f:
data = json.load(f)
except Exception:
print("")
raise SystemExit(0)
print(data.get("session_id") or data.get("id") or "")
PY
}
curl_create_session() {
local csrf="$RUN_ID-create"
echo "=== Creating SuperAgent session ==="
set +e
CREATE_HTTP_CODE="$(
curl -sS \
--connect-timeout "$CONNECT_TIMEOUT_SECONDS" \
--max-time "$TIMEOUT_SECONDS" \
-w "%{http_code}" \
-D "$CREATE_HEADERS" \
-o "$CREATE_RESPONSE" \
-X POST "$BASE_URL/api/open/agent-sessions" \
-H "Authorization: Bearer $API_KEY" \
-H "X-CSRF-Token: $csrf" \
-H "Cookie: csrf_token=$csrf" \
-H "Content-Type: application/json" \
--data-binary @"$CREATE_BODY"
)"
CREATE_CURL_EXIT=$?
set -e
echo "create curl exit=$CREATE_CURL_EXIT http=$CREATE_HTTP_CODE"
echo "create headers: $CREATE_HEADERS"
echo "create response: $CREATE_RESPONSE"
if [ "$CREATE_CURL_EXIT" -ne 0 ] || [ "$CREATE_HTTP_CODE" -lt 200 ] || [ "$CREATE_HTTP_CODE" -ge 300 ]; then
echo "Create session failed. Response body:" >&2
cat "$CREATE_RESPONSE" >&2 || true
exit 1
fi
SESSION_ID="$(extract_session_id)"
if [ -z "$SESSION_ID" ]; then
echo "Create session response does not contain session_id or id. Body:" >&2
cat "$CREATE_RESPONSE" >&2 || true
exit 1
fi
echo "SESSION_ID=$SESSION_ID"
echo
}
curl_stream_message() {
local csrf="$RUN_ID-message"
echo "=== Calling SuperAgent message stream ==="
echo "This may run for a long time. Output is saved to: $STREAM_RESPONSE"
local started_at ended_at elapsed
started_at="$(date +%s)"
set +e
STREAM_HTTP_CODE="$(
curl -sS -N --no-buffer \
--connect-timeout "$CONNECT_TIMEOUT_SECONDS" \
--max-time "$TIMEOUT_SECONDS" \
-w "%{http_code}" \
-D "$STREAM_HEADERS" \
-o "$STREAM_RESPONSE" \
-X POST "$BASE_URL/api/open/agent-sessions/$SESSION_ID/messages/stream" \
-H "Authorization: Bearer $API_KEY" \
-H "X-CSRF-Token: $csrf" \
-H "Cookie: csrf_token=$csrf" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
--data-binary @"$STREAM_BODY"
)"
STREAM_CURL_EXIT=$?
set -e
ended_at="$(date +%s)"
elapsed="$((ended_at - started_at))"
echo "stream curl exit=$STREAM_CURL_EXIT http=$STREAM_HTTP_CODE elapsed_seconds=$elapsed"
echo "stream headers: $STREAM_HEADERS"
echo "stream response: $STREAM_RESPONSE"
echo
}
summarize_stream() {
echo "=== Stream headers ==="
cat "$STREAM_HEADERS" || true
echo
echo "=== Stream event summary ==="
if [ -s "$STREAM_RESPONSE" ]; then
grep -E '^event:' "$STREAM_RESPONSE" | sort | uniq -c || true
echo
echo "Last 120 lines:"
tail -n 120 "$STREAM_RESPONSE" || true
else
echo "Stream response file is empty."
fi
echo
}
#######################################
# Main
#######################################
require_command curl
require_command python3
load_env_file
normalize_config
RUN_ID="${RUN_ID:-direct-curl-$(date +%Y%m%d-%H%M%S)}"
export BASE_URL API_KEY EXTERNAL_SUBJECT_ID RUN_ID
export MESSAGE_SUBJECT MESSAGE_TEXT MESSAGE_PAYLOAD_FILE EML_FILE MESSAGE_PREFIX
mkdir -p "$OUTPUT_DIR"
CREATE_BODY="$OUTPUT_DIR/$RUN_ID-create-body.json"
CREATE_HEADERS="$OUTPUT_DIR/$RUN_ID-create.headers"
CREATE_RESPONSE="$OUTPUT_DIR/$RUN_ID-create.json"
STREAM_BODY="$OUTPUT_DIR/$RUN_ID-stream-body.json"
STREAM_HEADERS="$OUTPUT_DIR/$RUN_ID-stream.headers"
STREAM_RESPONSE="$OUTPUT_DIR/$RUN_ID-stream.sse"
export CREATE_BODY STREAM_BODY CREATE_RESPONSE
print_config
write_create_body
write_stream_body
echo "create request body: $CREATE_BODY"
echo "stream request body: $STREAM_BODY"
echo
curl_create_session
curl_stream_message
summarize_stream
echo "Done."