refactor: 重构 Tool Result 契约,移除 ui_hints 统一使用 result 字段
- ToolAgentOutput 移除 result_summary 和 ui_hints,统一使用 result 字段 - 日历/用户查找工具移除 ui_hints 输出,改为机器可读的结构化结果 - Agent History 移除 tool 消息的 ui_hints 处理逻辑 - App 版本检查改为 manifest.json 方式,支持多渠道发布 - 更新 settings 配置和测试用例适配新结构
This commit is contained in:
@@ -19,6 +19,8 @@ SOCIAL_WEB__WORKERS=2
|
||||
############
|
||||
# LiteLLM Proxy 网关配置
|
||||
############
|
||||
# 可选:覆盖官方 LiteLLM 镜像(默认使用 compose 内置 digest)
|
||||
# SOCIAL_LITELLM_IMAGE=ghcr.io/berriai/litellm@sha256:b959a1816fa454a14d2842242d0fa1cd0d39f96fc94d3a1f4e1de4e48e2398c6
|
||||
SOCIAL_LITELLM__PORT=3875
|
||||
|
||||
############
|
||||
@@ -85,11 +87,6 @@ SOCIAL_LLM__PROVIDER_KEYS__ZAI=
|
||||
############
|
||||
# App 版本更新配置
|
||||
############
|
||||
# 安装包目录,相对于项目根目录下的 deploy/static/
|
||||
SOCIAL_APP_VERSION__RELEASES_DIR=releases
|
||||
# 当前版本号(语义化版本)
|
||||
SOCIAL_APP_VERSION__CURRENT_VERSION=0.1.0
|
||||
# 当前构建号(整数,每次打包递增)
|
||||
SOCIAL_APP_VERSION__CURRENT_BUILD=1
|
||||
# 下载链接基础域名(生产环境需配置)
|
||||
SOCIAL_APP_VERSION__MANIFEST_PATH=deploy/static/releases/manifest.json
|
||||
SOCIAL_APP_VERSION__RELEASE_PATH_PREFIX=releases
|
||||
SOCIAL_APP_VERSION__DOWNLOAD_BASE_URL=
|
||||
|
||||
+7
-2
@@ -81,7 +81,8 @@ cp deploy/.env.prod.example deploy/.env.prod
|
||||
### 2) 启动常驻服务
|
||||
|
||||
```bash
|
||||
docker compose --env-file deploy/.env.prod -f deploy/docker-compose.prod.yml up -d redis litellm web worker-critical worker-default worker-bulk
|
||||
docker compose --env-file deploy/.env.prod -f deploy/docker-compose.prod.yml up -d redis litellm-config-job
|
||||
docker compose --env-file deploy/.env.prod -f deploy/docker-compose.prod.yml up -d litellm web worker-critical worker-default worker-bulk
|
||||
```
|
||||
|
||||
### 3) 执行一次性 bootstrap
|
||||
@@ -118,7 +119,11 @@ docker compose --env-file deploy/.env.prod -f deploy/docker-compose.prod.yml up
|
||||
- 如果 nginx 运行在宿主机,`web` 需要保留 `127.0.0.1:host_port:container_port` 端口映射。
|
||||
- 如果 nginx 也运行在 Docker 同网络内,可以移除 `web.ports`,改为容器内反向代理(例如 `proxy_pass http://web:5775`)。
|
||||
|
||||
### App 安装包下载代理(必须配置)
|
||||
|
||||
在 nginx 增加静态目录映射:`location /releases/ { alias /你的项目绝对路径/deploy/static/releases/; }`,这样 `https://你的域名/releases/xxx.apk` 可直接下载安装包。并在 `deploy/.env.prod` 设置 `SOCIAL_APP_VERSION__DOWNLOAD_BASE_URL=https://你的域名` 与 `SOCIAL_APP_VERSION__RELEASE_PATH_PREFIX=releases`,确保 `check-updates` 返回的 `download_url` 指向该路径。
|
||||
|
||||
## 已知约束
|
||||
|
||||
- LiteLLM 会在容器启动时动态生成 `/tmp/litellm-proxy-config.yaml`,依赖 `SOCIAL_LLM__PROVIDER_KEYS__*` 已配置。
|
||||
- LiteLLM 配置由 `litellm-config-job` 一次性生成到共享 volume(`litellm_config`)。若更新了 LLM 目录或 Provider Key,需重新执行 `up -d litellm-config-job` 后重启 `litellm`。
|
||||
- `init-job` 为一次性任务,不长期驻留。
|
||||
|
||||
Executable
+178
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(git rev-parse --show-toplevel)"
|
||||
APPS_DIR="$ROOT_DIR/apps"
|
||||
OUTPUT_APK="$APPS_DIR/build/app/outputs/flutter-apk/app-release.apk"
|
||||
RELEASES_DIR="$ROOT_DIR/deploy/static/releases"
|
||||
MANIFEST_FILE="$RELEASES_DIR/manifest.json"
|
||||
|
||||
BACKEND_HOST=""
|
||||
CHANNEL="release"
|
||||
RELEASE_NOTES=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--backend-host)
|
||||
BACKEND_HOST="$2"
|
||||
shift 2
|
||||
;;
|
||||
--channel)
|
||||
CHANNEL="$2"
|
||||
shift 2
|
||||
;;
|
||||
--release-notes)
|
||||
RELEASE_NOTES="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
printf 'Unknown arg: %s\n' "$1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$BACKEND_HOST" ]]; then
|
||||
printf 'Usage: %s --backend-host <ip-or-domain> [--channel release] [--release-notes "..."]\n' "$0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$BACKEND_HOST" == *":"* ]]; then
|
||||
printf 'Invalid backend host: do not include port (%s)\n' "$BACKEND_HOST" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ "$CHANNEL" =~ ^[a-z0-9_-]+$ ]]; then
|
||||
printf 'Invalid channel: %s\n' "$CHANNEL" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BACKEND_URL="http://$BACKEND_HOST"
|
||||
|
||||
readarray -t VERSION_INFO < <(
|
||||
python - <<'PY'
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
text = Path("apps/pubspec.yaml").read_text(encoding="utf-8")
|
||||
match = re.search(r"^version:\s*([0-9]+\.[0-9]+\.[0-9]+)\+([0-9]+)\s*$", text, re.MULTILINE)
|
||||
if not match:
|
||||
raise SystemExit("pubspec.yaml version format invalid")
|
||||
print(match.group(1))
|
||||
print(match.group(2))
|
||||
PY
|
||||
)
|
||||
|
||||
VERSION_NAME="${VERSION_INFO[0]}"
|
||||
CURRENT_VERSION_CODE="${VERSION_INFO[1]}"
|
||||
NEXT_VERSION_CODE="$((CURRENT_VERSION_CODE + 1))"
|
||||
FILE_NAME="social-app-android-v${VERSION_NAME}+${NEXT_VERSION_CODE}-${CHANNEL}.apk"
|
||||
TARGET_APK="$RELEASES_DIR/$FILE_NAME"
|
||||
|
||||
mkdir -p "$RELEASES_DIR"
|
||||
|
||||
pushd "$APPS_DIR" >/dev/null
|
||||
flutter build apk --release \
|
||||
--build-name="$VERSION_NAME" \
|
||||
--build-number="$NEXT_VERSION_CODE" \
|
||||
--dart-define="BACKEND_URL=$BACKEND_URL" \
|
||||
--target-platform=android-arm64 \
|
||||
--split-per-abi \
|
||||
--target "lib/main.dart"
|
||||
popd >/dev/null
|
||||
|
||||
SOURCE_APK="$APPS_DIR/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk"
|
||||
if [[ ! -f "$SOURCE_APK" ]]; then
|
||||
SOURCE_APK="$OUTPUT_APK"
|
||||
fi
|
||||
|
||||
cp "$SOURCE_APK" "$TARGET_APK"
|
||||
|
||||
FILE_SIZE="$(stat -c%s "$TARGET_APK")"
|
||||
SHA256="$(sha256sum "$TARGET_APK" | cut -d' ' -f1)"
|
||||
|
||||
python - <<'PY' "$ROOT_DIR/apps/pubspec.yaml" "$VERSION_NAME" "$NEXT_VERSION_CODE"
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
pubspec_path = Path(sys.argv[1])
|
||||
version_name = sys.argv[2]
|
||||
version_code = sys.argv[3]
|
||||
|
||||
content = pubspec_path.read_text(encoding="utf-8")
|
||||
updated, count = re.subn(
|
||||
r"^version:\s*[0-9]+\.[0-9]+\.[0-9]+\+[0-9]+\s*$",
|
||||
f"version: {version_name}+{version_code}",
|
||||
content,
|
||||
count=1,
|
||||
flags=re.MULTILINE,
|
||||
)
|
||||
if count != 1:
|
||||
raise SystemExit("failed to update version in pubspec.yaml")
|
||||
pubspec_path.write_text(updated, encoding="utf-8")
|
||||
PY
|
||||
|
||||
RELEASE_NOTES="$RELEASE_NOTES" python - <<'PY' "$MANIFEST_FILE" "$FILE_NAME" "$VERSION_NAME" "$NEXT_VERSION_CODE" "$CHANNEL" "$FILE_SIZE" "$SHA256"
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
manifest_path = Path(sys.argv[1])
|
||||
file_name = sys.argv[2]
|
||||
version_name = sys.argv[3]
|
||||
version_code = int(sys.argv[4])
|
||||
channel = sys.argv[5]
|
||||
file_size = int(sys.argv[6])
|
||||
sha256 = sys.argv[7]
|
||||
release_notes = os.environ.get("RELEASE_NOTES", "")
|
||||
|
||||
if manifest_path.is_file():
|
||||
data = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
else:
|
||||
data = {"releases": []}
|
||||
|
||||
releases = data.get("releases") or []
|
||||
releases = [
|
||||
item
|
||||
for item in releases
|
||||
if not (
|
||||
item.get("platform") == "android"
|
||||
and item.get("channel") == channel
|
||||
and item.get("version_code") == version_code
|
||||
)
|
||||
]
|
||||
releases.append(
|
||||
{
|
||||
"platform": "android",
|
||||
"channel": channel,
|
||||
"version_name": version_name,
|
||||
"version_code": version_code,
|
||||
"min_supported_version_code": version_code,
|
||||
"file_name": file_name,
|
||||
"release_notes": release_notes or None,
|
||||
"file_size": file_size,
|
||||
"sha256": sha256,
|
||||
}
|
||||
)
|
||||
releases.sort(
|
||||
key=lambda item: (
|
||||
item.get("platform", ""),
|
||||
item.get("channel", ""),
|
||||
item.get("version_code", 0),
|
||||
)
|
||||
)
|
||||
|
||||
manifest_path.write_text(
|
||||
json.dumps({"releases": releases}, indent=2, ensure_ascii=True) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
PY
|
||||
|
||||
printf 'Build completed\n'
|
||||
printf 'Version: %s+%s\n' "$VERSION_NAME" "$NEXT_VERSION_CODE"
|
||||
printf 'Previous buildNumber: %s\n' "$CURRENT_VERSION_CODE"
|
||||
printf 'Backend URL: %s\n' "$BACKEND_URL"
|
||||
printf 'Package: %s\n' "$TARGET_APK"
|
||||
printf 'SHA256: %s\n' "$SHA256"
|
||||
@@ -17,19 +17,38 @@ services:
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
|
||||
litellm:
|
||||
litellm-config-job:
|
||||
image: ${SOCIAL_BACKEND_IMAGE:-social-app-backend:prod}
|
||||
container_name: social-prod-litellm
|
||||
restart: unless-stopped
|
||||
container_name: social-prod-litellm-config-job
|
||||
restart: "no"
|
||||
env_file:
|
||||
- ./.env.prod
|
||||
environment:
|
||||
- PYTHONPATH=/app/backend/src
|
||||
- PYTHONDONTWRITEBYTECODE=1
|
||||
- SOCIAL_REDIS__HOST=redis
|
||||
- SOCIAL_REDIS__PORT=6379
|
||||
command: >
|
||||
sh -c '.venv/bin/python backend/scripts/build_litellm_proxy_config.py --output /tmp/litellm-proxy-config.yaml && .venv/bin/litellm --config /tmp/litellm-proxy-config.yaml --host ${SOCIAL_LITELLM__BIND_HOST:-0.0.0.0} --port ${SOCIAL_LITELLM__PORT:-3875}'
|
||||
.venv/bin/python backend/scripts/build_litellm_proxy_config.py --output /config/litellm-proxy-config.yaml
|
||||
volumes:
|
||||
- litellm_config:/config
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
|
||||
litellm:
|
||||
image: ${SOCIAL_LITELLM_IMAGE:-ghcr.io/berriai/litellm@sha256:b959a1816fa454a14d2842242d0fa1cd0d39f96fc94d3a1f4e1de4e48e2398c6}
|
||||
container_name: social-prod-litellm
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- ./.env.prod
|
||||
command: >
|
||||
--config /config/litellm-proxy-config.yaml --host ${SOCIAL_LITELLM__BIND_HOST:-0.0.0.0} --port ${SOCIAL_LITELLM__PORT:-3875}
|
||||
volumes:
|
||||
- litellm_config:/config:ro
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
litellm-config-job:
|
||||
condition: service_completed_successfully
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
@@ -68,7 +87,7 @@ services:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ../logs:/app/logs
|
||||
- ./static/releases:/app/static/releases:ro
|
||||
- ./static/releases:/app/deploy/static/releases:ro
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
@@ -105,7 +124,7 @@ services:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ../logs:/app/logs
|
||||
- ./static/releases:/app/static/releases:ro
|
||||
- ./static/releases:/app/deploy/static/releases:ro
|
||||
|
||||
worker-default:
|
||||
image: ${SOCIAL_BACKEND_IMAGE:-social-app-backend:prod}
|
||||
@@ -131,7 +150,7 @@ services:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ../logs:/app/logs
|
||||
- ./static/releases:/app/static/releases:ro
|
||||
- ./static/releases:/app/deploy/static/releases:ro
|
||||
|
||||
worker-bulk:
|
||||
image: ${SOCIAL_BACKEND_IMAGE:-social-app-backend:prod}
|
||||
@@ -157,7 +176,7 @@ services:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ../logs:/app/logs
|
||||
- ./static/releases:/app/static/releases:ro
|
||||
- ./static/releases:/app/deploy/static/releases:ro
|
||||
|
||||
init-job:
|
||||
image: ${SOCIAL_BACKEND_IMAGE:-social-app-backend:prod}
|
||||
@@ -182,9 +201,10 @@ services:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ../logs:/app/logs
|
||||
- ./static/releases:/app/static/releases:ro
|
||||
- ./static/releases:/app/deploy/static/releases:ro
|
||||
profiles:
|
||||
- job
|
||||
|
||||
volumes:
|
||||
redis_data:
|
||||
litellm_config:
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"releases": [
|
||||
{
|
||||
"platform": "android",
|
||||
"channel": "release",
|
||||
"version_name": "0.1.0",
|
||||
"version_code": 1,
|
||||
"min_supported_version_code": 1,
|
||||
"file_name": "social-app-android-v0.1.0+1-release.apk",
|
||||
"release_notes": "\u95ee\u9898\u4fee\u590d\u548c\u4f53\u9a8c\u4f18\u5316",
|
||||
"file_size": 21371504,
|
||||
"sha256": "6cf53601f36e0037b6de909ea3567d1e18a1bcec1164e1b70d88c1802eafd44b"
|
||||
},
|
||||
{
|
||||
"platform": "android",
|
||||
"channel": "release",
|
||||
"version_name": "0.1.0",
|
||||
"version_code": 2,
|
||||
"min_supported_version_code": 2,
|
||||
"file_name": "social-app-android-v0.1.0+2-release.apk",
|
||||
"release_notes": "\u95ee\u9898\u4fee\u590d\u548c\u4f53\u9a8c\u4f18\u5316",
|
||||
"file_size": 21371504,
|
||||
"sha256": "8f769bda3ba5414dfd5712ac026d8a13663990b7e83a4e92b8e85caf9945d5eb"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user