版本: 1.0.0
基础 URL: https://www.trvaelmind.online/api/agent
更新: 2026-07-15 (P7 文档落地)
---
白名单鉴权 (requireAdmin 中间件): 5 个写端点 + 1 个只读 audit 端点 = 6 个需要鉴权
userId 参数 (在 body 或 query)TRAVELMIND_ADMIN_USERS 环境变量 → approvalStore._trips 中所有 userId 兜底{ success: false, error: "Forbidden" }
{
"success": true,
"data": { ... }
}
错误响应:
{
"success": false,
"error": "错误描述",
"message": "补充说明 (可选)"
}
---
用途: 老版 PolicyAgent, 调用 policyAgent.execute(). 用于旧前端表单兼容性, 新代码请用 /policy/check-now
请求体:
{
"destination": "北京",
"userLevel": "M4",
"days": 2,
"estimatedBudget": 1500
}
响应示例:
{
"success": true,
"data": {
"compliant": true,
"allowedTransportTypes": ["flight", "train", "bus"],
"maxAllowedPrice": { "flight": 1500, "train": 800, "bus": 300 },
"allowedClasses": { "flight": "economy", "train": "second" }
}
}
错误码: 500 内部异常
---
用途: 获取目的地城市的差标标准 (PolicyAgent 兼容接口)
Query 参数:
destination (必需): 城市名, 如 "北京"响应示例:
{
"success": true,
"data": {
"compliant": true,
"allowedTransportTypes": ["flight", "train", "bus"],
"maxAllowedPrice": { "flight": 1500, "train": 800, "bus": 300 },
"allowedClasses": { "flight": "economy", "train": "second" }
}
}
---
用途: 实时检查行程方案是否合规. 新代码都用这个
请求体:
{
"plan": {
"hotel": { "name": "北京汉庭", "price": 350 },
"transport": [
{ "type": "train", "seatType": "二等座", "price": 200 }
],
"destination": "北京"
},
"ctx": {
"destination": "北京",
"userLevel": "M4"
}
}
响应示例 (合规):
{
"success": true,
"data": {
"compliant": true,
"violations": [],
"limits": {
"hotelDailyLimit": 600,
"hotelLimitSource": "北京._default",
"trainAllowedClass": "second",
"mealSubsidyEstimate": 100,
"mealSubsidyTier": "A"
},
"specialApprovalRequired": false,
"degraded": false,
"checkDurationMs": 0,
"configVersion": "1.0.0",
"checkedAt": "2026-07-15T10:46:33.951Z"
}
}
响应示例 (违规):
{
"success": true,
"data": {
"compliant": false,
"violations": [
{
"rule": "hotel",
"severity": "block",
"message": "酒店每晚 ¥1500 超限 ¥600 (北京._default)",
"suggestion": "建议选择每晚 ≤ ¥600 的酒店"
}
],
"specialApprovalRequired": true,
"degraded": false,
...
}
}
规则详解:
| rule | severity 触发 | 说明 |
|---|---|---|
hotel_price_missing |
block | 酒店无价格 (price ≤ 0 / undefined) |
hotel |
warn / block | 超限 1.2 倍内=warn, 超 1.2 倍=block |
train_class_unknown |
warn | 席别名无法识别 |
train_class |
warn / block | 超 1 级=warn, 超 2 级=block |
flight_cabin |
warn / block | 商务舱/头等舱=block |
flight_discount |
warn | 机票折扣超 limit |
降级: 配置损坏 / 异常 → { degraded: true, compliant: true (放行) }, 不阻断主流程
---
用途: 读取差标配置全量 JSON
Query 参数:
userId (必需): 白名单用户 ID响应示例:
{
"success": true,
"data": {
"rules": {
"version": "1.0.0",
"updatedAt": "2026-07-15",
"cityTiers": {
"A": ["北京", "上海", "广州", ...],
"B": ["义乌", "温州", ...],
"C": ["建德", "淳安", ...]
},
"hotel": {
"_default_by_tier": { "A": 600, "B": 400, "C": 300 },
"北京": { "_default": 600 },
...
},
"meal": { "_default_by_tier": { "A": 100, "B": 100, "C": 60 } },
"taxi": { "perRideCap": 30, "dailyCap": 100, ... },
"flight": { "discountCap": 0.6, "allowedCabin": "economy" },
"train": { "allowedClass": "second" },
"loan": { "formula": "hotel_daily * nights + transport_total" }
}
}
}
---
共同特性:
config/backups/policy-rules.json.bak-{ISO timestamp}.jsonconfig/audit.log (JSONL, 含 before/after 完整快照)用途: 改酒店限价. 支持单城市覆盖 或 tier 默认
请求体:
{
"userId": "E1001",
"updates": {
"上海": { "value": 555, "isCity": true },
"tier_A": { "value": 650, "isTier": true }
}
}
tier_ 开头 → tier 默认 (A/B/C), 后端自动剥前缀响应: { success: true, data: { message, smoke: { blockCount, totalBlock, results } } }
错误码:
---
用途: 改餐补
请求体:
{
"userId": "E1001",
"updates": {
"tier_A": { "value": 120, "isTier": true }
}
}
⚠️ 已知 Bug: P4 测试残留, 传 tier_* 报 "无效餐补". 临时方案: 直接改 JSON 文件 + 重启服务
---
用途: 改机票规则
请求体:
{
"userId": "E1001",
"updates": {
"discountCap": 0.55,
"allowedCabin": "premium"
}
}
字段:
discountCap: 折扣上限 (0.6 = 6 折)allowedCabin: economy / premium / business / first---
用途: 改火车规则
请求体:
{
"userId": "E1001",
"updates": {
"allowedClass": "first"
}
}
字段:
allowedClass: second (二等座) / first (一等座) / business (商务座)---
用途: 增删城市分级 (A/B/C)
请求体:
{
"userId": "E1001",
"ops": [
{ "action": "add", "city": "南京", "tier": "A" },
{ "action": "remove", "city": "拉萨", "tier": "C" },
{ "action": "move", "city": "温州", "from": "B", "to": "A" }
]
}
action 类型:
add: 城市加到 tier (重复加 = 幂等 noop)remove: 从 tier 移除move: 从 from tier 移到 to tier---
用途: 列出所有历史备份
Query 参数:
userId (必需)响应:
{
"success": true,
"data": {
"backups": [
"policy-rules.json.bak-2026-07-15_10-46-33-951Z.json",
"policy-rules.json.bak-2026-07-15_10-46-33-172Z.json",
"policy-rules.json.bak-2026-07-15_10-46-32-711Z.json",
"policy-rules.json.bak-2026-07-15_10-46-31-205Z.json",
"policy-rules.json.bak-2026-07-15_cleanup-junk-keys.json"
]
}
}
---
用途: 恢复到指定备份
请求体:
{
"userId": "E1001",
"backup": "policy-rules.json.bak-2026-07-15_10-46-33-951Z.json"
}
⚠️: backup 必须是 GET /backups 返回的完整文件名, 不支持 "latest" 简写
---
用途: 查 admin 操作审计日志 (谁在什么时间改了什么)
Query 参数:
userId (必需)?limit=50 (可选, 默认 50)?action=/policy/rules/hotel (可选, 按 action 筛)?userId=E1001 与 userId 鉴权参数同位置 → 用 qUserId 区分 - 实际: 鉴权 userId 和查询 userId 共用 query, 故查其他人历史请用 action 过滤
响应:
{
"success": true,
"data": {
"entries": [
{
"ts": "2026-07-15T10:44:54.552Z",
"userId": "E1001",
"action": "/policy/rules/train",
"path": "/policy/rules/train",
"before": { /* 完整旧配置 */ },
"after": { /* 完整新配置 */ },
"ip": "::ffff:127.0.0.1",
"ua": "curl/7.81.0"
}
],
"total": 3,
"stats": {
"total": 15,
"byUser": { "E1001": 8, "E1002": 5, "E1003": 2 },
"byAction": {
"/policy/rules/hotel": 4,
"/policy/rules/train": 3,
"/policy/rules/flight": 3,
"/policy/rules/cities": 2,
"/policy/rules/meal": 1,
"/policy/rules/restore": 2
}
}
}
}
---
# Step 1: 看现状
curl 'https://www.trvaelmind.online/api/agent/policy/rules?userId=E1001' | jq .data.rules.hotel
# Step 2: 改上海到 ¥555
curl -X POST 'https://www.trvaelmind.online/api/agent/policy/rules/hotel' \
-H 'Content-Type: application/json' \
-d '{"userId":"E1001","updates":{"上海":{"value":555}}}'
# Step 3: 验证生效
curl -X POST 'https://www.trvaelmind.online/api/agent/policy/check-now' \
-H 'Content-Type: application/json' \
-d '{"plan":{"hotel":{"name":"上海希尔顿","price":700},"transport":[],"destination":"上海"},"ctx":{"destination":"上海"}}'
# Step 4: 查审计
curl 'https://www.trvaelmind.online/api/agent/policy/audit?userId=E1001&limit=5'
# Step 1: 列出备份
curl 'https://www.trvaelmind.online/api/agent/policy/rules/backups?userId=E1001' | jq .data.backups
# Step 2: 选最近的备份恢复
BACKUP=$(curl -s 'https://www.trvaelmind.online/api/agent/policy/rules/backups?userId=E1001' | jq -r '.data.backups[0]')
curl -X POST 'https://www.trvaelmind.online/api/agent/policy/rules/restore' \
-H 'Content-Type: application/json' \
-d "{\"userId\":\"E1001\",\"backup\":\"$BACKUP\"}"
---
| HTTP | 含义 | 触发场景 |
|---|---|---|
| 200 | 成功 | - |
| 400 | 请求参数错 | 数值无效 / tier 不是 A/B/C |
| 403 | 鉴权失败 | 不带 userId / 不在白名单 |
| 404 | 端点不存在 | - |
| 409 | 冒烟测试拒收 | regressionCount ≥ 1 |
| 500 | 内部异常 | 配置文件损坏 / 写失败 |
---
| 文件 | 路径 | 大小限制 | 切分策略 |
|---|---|---|---|
| 配置 | config/policy-rules.json |
- | 写前自动备份 |
| 备份 | config/backups/policy-rules.json.bak-*.json |
无上限 | 保留所有历史 |
| 审计 | config/audit.log (JSONL) |
5MB | 超 5MB 切到 audit.log.{timestamp} |
---
| # | 描述 | 临时方案 | 修复计划 |
|---|---|---|---|
| 1 | meal 端点传 tier_* 报 "无效餐补" |
直接改 JSON + 重启 | P5 修 (合并 patchRules 同款容错) |
| 2 | restore 不支持 "latest" 简写 | 必须传完整文件名 | P6: 加 alias |
| 3 | audit 查询参数 userId 与鉴权 userId 冲突 | 用 action 过滤查他人 | P6: 改用 qUserId |
---
文档维护: 改 policy 端点时同步更新本文件
位置: /var/www/travelmind/admin/api-docs.html (Web 版)
离线版: ~/.openclaw/workspace/policy-api-docs.md