@danceiny/gotry 0.0.1-rc.7 → 0.0.1-rc.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -74
- package/bin/gotry-inner.js +50 -1
- package/bin/gotry-stdio-ask.js +59 -0
- package/cordis.gotry-patch.yml +63 -5
- package/data/flights_2026.json +7 -4
- package/data/hotels_2026.json +102 -15
- package/data/time-slot-eval.json +384 -0
- package/data/yunnan-pack.json +2 -1
- package/dist/capabilities/agent-reach-bridge.py +90 -0
- package/dist/capabilities/anything.js +2 -2
- package/dist/capabilities/flyai.js +131 -0
- package/dist/capabilities/hbcli.js +11 -6
- package/dist/capabilities/incident-log.js +2 -1
- package/dist/capabilities/session/action-cache.js +120 -0
- package/dist/capabilities/session/adapters/ctrip-flight.js +83 -0
- package/dist/capabilities/session/adapters/meituan-local.js +73 -0
- package/dist/capabilities/session/extract.js +40 -0
- package/dist/capabilities/session/read-guard.js +56 -0
- package/dist/capabilities/session/transport.js +95 -0
- package/dist/capabilities/session-search.js +95 -0
- package/dist/scripts/action-cache-tests.js +107 -0
- package/dist/scripts/agent-reach-tests.js +1 -1
- package/dist/scripts/agent-reach-wrapper-tests.js +1 -1
- package/dist/scripts/async-collect.js +26 -7
- package/dist/scripts/companion-tests.js +112 -0
- package/dist/scripts/hbcli-tests.js +18 -2
- package/dist/scripts/ledger-tests.js +344 -0
- package/dist/scripts/ledger-workflow-crash.js +42 -0
- package/dist/scripts/memory-capture-tests.js +77 -0
- package/dist/scripts/memory-decay-tests.js +83 -0
- package/dist/scripts/memory-metrics.js +24 -0
- package/dist/scripts/nudge-digest.js +83 -0
- package/dist/scripts/probe-poi-tests.js +9 -0
- package/dist/scripts/replay.js +73 -1
- package/dist/scripts/session-attach-diagnose.js +31 -0
- package/dist/scripts/session-attach-poc.js +65 -0
- package/dist/scripts/session-attach-wait.js +41 -0
- package/dist/scripts/session-extract-tests.js +81 -0
- package/dist/scripts/session-login.js +48 -0
- package/dist/scripts/session-tests.js +162 -0
- package/dist/scripts/skeleton-check.js +3 -1
- package/dist/scripts/skills-contract-tests.js +85 -0
- package/dist/scripts/smoke.js +242 -4
- package/dist/scripts/state-cli-tests.js +136 -0
- package/dist/scripts/state-cli.js +234 -0
- package/dist/scripts/time-eval-tests.js +318 -0
- package/dist/scripts/travel-timeline-tests.js +123 -0
- package/dist/scripts/unified-tests.js +1 -1
- package/dist/src/companions.js +112 -0
- package/dist/src/dsh-llm.js +27 -7
- package/dist/src/index.js +600 -121
- package/dist/src/loop.js +89 -25
- package/dist/src/memory-capture.js +40 -0
- package/dist/src/memory-decay.js +31 -0
- package/dist/src/memory-utility.js +55 -0
- package/dist/src/mock-llm.js +6 -1
- package/dist/src/slot-spec.js +165 -0
- package/dist/src/state-ledger.js +848 -0
- package/dist/src/time-anchor.js +100 -0
- package/dist/src/tool-packet.js +12 -0
- package/dist/src/travel-slots.js +144 -0
- package/dist/src/travel-timeline.js +78 -0
- package/dist/src/unified.js +3 -1
- package/dist/src/wish-pool.js +27 -0
- package/package.json +6 -2
- package/ts/capabilities/hbcli.ts +6 -6
- package/ts/capabilities/incident-log.ts +6 -3
- package/ts/package.json +3 -0
- package/ts/scripts/skeleton-check.ts +5 -1
- package/ts/src/dsh-llm.ts +27 -7
- package/ts/src/index.ts +439 -91
- package/ts/src/loop.ts +109 -34
- package/ts/src/mock-llm.ts +13 -1
- package/ts/src/unified.ts +6 -1
- package/ts/cordis.gotry-patch.yml +0 -36
package/README.md
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
| | |
|
|
11
11
|
|---|---|
|
|
12
|
-
| **Version** | `v0.0.1-rc.
|
|
13
|
-
| **Status** |
|
|
12
|
+
| **Version** | `v0.0.1-rc.8`(npm **latest 直指本版**,`npx @danceiny/gotry` 即得;[release notes](docs/release-notes.md)) |
|
|
13
|
+
| **Status** | M4 记忆域推进中(2026-08-28):记忆写读闭环 + 效用 sidecar + 「下一次出发」0::1 召回;17 工具;事务化状态账本(ADR-15:SQLite 单文件=唯一权威,旧 JSON/JSONL 为单向导出视图);全栈回归全绿(套件清单见 `scripts/run-all-tests.sh` 分节) |
|
|
14
14
|
| **Repo** | [github.com/Danceiny/gotry](https://github.com/Danceiny/gotry) (private) |
|
|
15
15
|
| **Runtime** | DeepSeek Harness 0.1.1-rc.2 (vendored `ts/dsh-runtime/`, [upstream](https://github.com/deepseek-ai/DeepSeek-Harness)) · Z3 (npm `z3-solver`) · LoopX (pipx, `~/.local/pipx/venvs/loopx/bin/loopx`) · Agent-Reach v1.5.0 (`.venv/bin/agent-reach`) |
|
|
16
16
|
| **License** | **MIT** (2026-08-23 落定,见 [LICENSE](LICENSE)) |
|
|
@@ -38,15 +38,25 @@ GoTry 把「想去哪」变成「能不能、怎么去」:
|
|
|
38
38
|
|
|
39
39
|
## 🚀 快速开始 — Quick start
|
|
40
40
|
|
|
41
|
-
###
|
|
41
|
+
### 一行启动(npm,推荐)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx @danceiny/gotry web # 首跑会提示在当前目录建 .env(LLM_API_KEY=<DeepSeek key>)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
装完即得 :3080 对话界面。已装 dsh 的用户同理——上面的命令会自动以 cordis patch
|
|
48
|
+
挂载 gotry 插件,无需任何额外配置(零成本启动)。
|
|
49
|
+
|
|
50
|
+
> rc.5 为不可用首发(已停止指向);`@rc` tag 当前为 rc.7,`latest` 为 rc.8,两者均可跑。
|
|
51
|
+
|
|
52
|
+
### 源码安装(开发者)
|
|
42
53
|
|
|
43
54
|
```bash
|
|
44
55
|
git clone https://github.com/Danceiny/gotry
|
|
45
56
|
cd gotry
|
|
46
|
-
git checkout v0.0.1-rc.3-dev # 当前的 dev 分支挂在 main 上
|
|
47
57
|
```
|
|
48
58
|
|
|
49
|
-
|
|
59
|
+
#### A. 装 vendored dsh runtime(一次性,约 1 分钟)
|
|
50
60
|
|
|
51
61
|
```bash
|
|
52
62
|
cd ts/dsh-runtime
|
|
@@ -58,21 +68,21 @@ cd ../..
|
|
|
58
68
|
> 避免 npm 一键分发时把整个 dsh 也打包进去。
|
|
59
69
|
> 之后可以重复使用,无需重装。
|
|
60
70
|
|
|
61
|
-
|
|
71
|
+
#### B. 环境前置 — Prerequisites
|
|
62
72
|
|
|
63
73
|
- **Node 22+**(`nvm install 22` 或更高)
|
|
64
74
|
- 一个 LLM API key(默认走 DeepSeek,也支持 OpenAI 兼容协议)
|
|
65
75
|
|
|
66
|
-
|
|
76
|
+
#### C. 配 — Configure
|
|
67
77
|
|
|
68
78
|
```bash
|
|
69
79
|
cp .env.example .env
|
|
70
80
|
# 填 LLM_API_KEY(deepseek: sk-...; 也兼容 OpenAI/Anthropic 兼容协议)
|
|
71
81
|
```
|
|
72
82
|
|
|
73
|
-
|
|
83
|
+
#### D. 跑 — Run(仓内入口,开发者)
|
|
74
84
|
|
|
75
|
-
|
|
85
|
+
gotry 把 **DeepSeek Harness (dsh) 运行时**作为唯一推荐面——任何自然语言输入在那里面都能跟 GoTry 正常对话(自动调用引擎、追问缺失字段、给出证据链)。
|
|
76
86
|
|
|
77
87
|
启动方式有三种,对应三种使用场景:
|
|
78
88
|
|
|
@@ -103,7 +113,7 @@ v0.0.1-rc.3-dev 把 **DeepSeek Harness (dsh) 运行时**作为唯一推荐面—
|
|
|
103
113
|
|
|
104
114
|
<br>
|
|
105
115
|
|
|
106
|
-
*
|
|
116
|
+
*One-liner mental model: `npx @danceiny/gotry@rc web` + `.env` 一行 key — done。dsh 对话框是唯一产品面(旧 shell 前端已删除)。*
|
|
107
117
|
|
|
108
118
|
> 一行安装的关键点: `./gotry web`(终端粘贴即用),或 `./gotry "任务"`(一句问答)。**任何自然语言都能用**(这是 dsh runtime 投资的最大价值)。详见 [known limitations](#-known-limitations)。
|
|
109
119
|
|
|
@@ -159,7 +169,7 @@ GoTry: 收到。先把约束记下来——
|
|
|
159
169
|
```
|
|
160
170
|
┌──────────────────────────────────────────────────────────────┐
|
|
161
171
|
│ L1 对话即界面 chat-as-UI; gates 是消息内选择题 │
|
|
162
|
-
│ L2 编排 dsh 运行时 + GoTry 插件(ReAct);
|
|
172
|
+
│ L2 编排 dsh 运行时 + GoTry 插件(ReAct);13 个工具 │
|
|
163
173
|
│ L3 领域 统一行程模型 + Z3 可行性引擎(枚举/Z3 双形态) │
|
|
164
174
|
│ L4 数据 静态数据包 + hotelbyte-cli 实时桥 + OpenFlights 骨架 │
|
|
165
175
|
│ L5 治理 LoopX(objective / gates / evidence / quota) │
|
|
@@ -168,7 +178,7 @@ GoTry: 收到。先把约束记下来——
|
|
|
168
178
|
|
|
169
179
|
| 层 | 模块 | 角色 |
|
|
170
180
|
|---|---|---|
|
|
171
|
-
| L2 | `ts/src/index.ts` (dsh 插件) | 注册
|
|
181
|
+
| L2 | `ts/src/index.ts` (dsh 插件) | 注册 13 个工具,挂 `{{current_date}}`/`{{time_anchor_card}}`/`{{motivation_brief}}` 变量,工具 execute 异常隔离 + 平铺观察 envelope + uncaughtException 护栏 |
|
|
172
182
|
| L3 | `ts/src/unified.ts` · `py/gotry_feasibility/unified.py` | 唯一求解入口(候选枚举 + 航班链 Z3) |
|
|
173
183
|
| L4 | `ts/capabilities/hbcli.ts` | hotelbyte-cli 进程封装 + 降级到 `data/hotels_2026.json` |
|
|
174
184
|
| L4 | `ts/scripts/skeleton-check.ts` | OpenFlights 168 对枢纽,三值语义(阳性/枢纽对否定≠证伪/枢纽外=无结论) |
|
|
@@ -211,17 +221,11 @@ GoTry: 收到。先把约束记下来——
|
|
|
211
221
|
./scripts/run-all-tests.sh
|
|
212
222
|
```
|
|
213
223
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
| 4 | 对话循环重放(mock,行为级回归) |
|
|
220
|
-
| 5 | 异步工单跨进程闭环 |
|
|
221
|
-
| 6 | 插件 smoke |
|
|
222
|
-
| 7 | hbcli 能力封装(4 断言) |
|
|
223
|
-
| 8 | 进程护栏(2 断言,fsync) |
|
|
224
|
-
| 9 | 双路径稳定性(unified vs unified 同 spec) |
|
|
224
|
+
全栈一次性绿(纯 TS,无 Python 依赖):engine/journey/unified 金标准 · 对话重放 ·
|
|
225
|
+
异步工单跨进程 · 插件 smoke · hbcli · 进程护栏(含工具异常隔离) · 天气 · 航班 ·
|
|
226
|
+
Anything · probePoi · agent-reach(web/deep/wrapper)· 双路径稳定性 ·
|
|
227
|
+
时间感评测(锚点卡/槽位过期校验/评分器/mock 回放;真模型巡检 `time-eval-tests.ts --real`)·
|
|
228
|
+
记忆域(动机合并守门/效用 sidecar/只读指标投影)。
|
|
225
229
|
|
|
226
230
|
---
|
|
227
231
|
|
|
@@ -242,55 +246,6 @@ ADR 与技术债见 [`docs/architecture.md` §8 / §10](docs/architecture.md)。
|
|
|
242
246
|
|
|
243
247
|
---
|
|
244
248
|
|
|
245
|
-
## 📦 发布到 npm — For founder
|
|
246
|
-
|
|
247
|
-
仓库已有 `package.json`(v0.0.1-rc.3,files 白名单 19 个文件,42KB)——发 npm 需**一枚 publish token + 一行命令**:
|
|
248
|
-
|
|
249
|
-
```bash
|
|
250
|
-
# 1. 写入 token(一次性;不要在 git 里跟踪;请去 npmjs.com/settings/tokens 新建)
|
|
251
|
-
npm config set //registry.npmjs.org/:_authToken npm_xxxxxx
|
|
252
|
-
|
|
253
|
-
# 2. 验证
|
|
254
|
-
npm whoami --registry=https://registry.npmjs.org/ # 应输出:danceiny
|
|
255
|
-
|
|
256
|
-
# 3. Dry-run 确认 tarball
|
|
257
|
-
npm pack --dry-run --registry=https://registry.npmjs.org/
|
|
258
|
-
|
|
259
|
-
# 4. 发布到 npm(--access public 让 gotry 名公开)
|
|
260
|
-
npm publish --access public --registry=https://registry.npmjs.org/
|
|
261
|
-
|
|
262
|
-
# 5. 发布成功后任何用户:
|
|
263
|
-
npx @danceiny/gotry web # 一行启动(≥0.0.1-rc.6;rc.5 缺 runtime 不可用)
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
> ⚠️ **注意**: publish 后**不可逆**(30 天内可 `npm unpublish` 但会污染历史)。建议先在 main 打 `v0.0.1-rc.3` tag + GitHub release,再 publish,保证 npm 包与仓库 tag 同步。
|
|
267
|
-
|
|
268
|
-
> 💡 **名可用性**: `gotry` 名在 npm 上未被占(2026-08-22)。检查可用性: `npm view gotry --registry=https://registry.npmjs.org/` (404 即未被占)。
|
|
269
|
-
> ⚠️ **Token 安全**: 任何接触过 `.npmrc` 的会话都可能持久保存 token,记得 publish 完 `npm config delete //registry.npmjs.org/:_authToken`。
|
|
270
|
-
|
|
271
|
-
---
|
|
272
|
-
|
|
273
|
-
## 🎯 待你拍(决策清单 — 在 [docs/decisions-needed.md](docs/decisions-needed.md) 有完整上下文)
|
|
274
|
-
|
|
275
|
-
- **D-2 M4 校准四题** — 4 题 YAML 块在 [docs/m4-calibration-questions.md](docs/m4-calibration-questions.md) 末尾,commit YAML 即吸收进引擎
|
|
276
|
-
- **D-3 npm publish** — 建议先 revoke 你之前明文给我的 token;新 token 走 `NPM_TOKEN=xxx` 注入
|
|
277
|
-
- **D-4a agent-reach** — 已 wrapper 化(反射桥直调上游注册表,gotry 零渠道知识);8 渠道需 Cookie(雪球实测也要),给即接、不催
|
|
278
|
-
- **D-5 OpenSky** — 保留 1 tick(实时 ADS-B 真飞/真没飞)
|
|
279
|
-
- **D-6 OSM 兜底** — A 删 / B 留 Nominatim+Overpass 兜底层
|
|
280
|
-
|
|
281
|
-
> 💡 一句话拍任何一项 → loopx 文档/仓库告知我 → 我立即推进。
|
|
282
|
-
|
|
283
|
-
## 🐍 Python venv 现状(2026-08-23 单 venv 整合后)
|
|
284
|
-
|
|
285
|
-
仓库根 `.venv/` 是**唯一 Python venv**(python3.11),同时装两个包:
|
|
286
|
-
|
|
287
|
-
- `z3-solver 5.1.0` — gotry 引擎 oracle(D-1 留下的求解决策)
|
|
288
|
-
- `agent-reach 1.5.0` — 上游渠道注册表 + doctor(gotry 以反射桥 wrapper 接入,零渠道知识)
|
|
289
|
-
|
|
290
|
-
`agent-reach doctor` 真跑接通;wrapper 反射桥走 `.venv/bin/python` + bridge 脚本,doctor 走 `.venv/bin/agent-reach`(绝对路径解析仓根)。
|
|
291
|
-
|
|
292
|
-
`loopx` 不在仓内 — 通过 `pipx` 装在 `~/.local/pipx/venvs/loopx/bin/loopx` 系统级。loopx todo 命令**不在仓内**跑(`.venv/bin/loopx` 不存在),用 `pipx run loopx ...` 或 `~/.local/pipx/venvs/loopx/bin/loopx ...`。
|
|
293
|
-
|
|
294
249
|
## 📜 License
|
|
295
250
|
|
|
296
251
|
**MIT**(2026-08-23 落定)。与上游 dsh(MIT)/ loopx 一致——宽松、可商用、可闭源分叉。
|
|
@@ -302,11 +257,11 @@ npx @danceiny/gotry web # 一行启动(≥0.0.1-rc.6;rc.5 缺 runtime 不可
|
|
|
302
257
|
## 🌐 中英版 — Locales
|
|
303
258
|
|
|
304
259
|
- **English section summaries** are inline above (italic blockquotes).
|
|
305
|
-
- 本 README
|
|
260
|
+
- 本 README 主语言是中文,面向中国出境首发种子用户群。
|
|
306
261
|
- 完整英文版 README 计划在 v0.1.0 同步([issue 路线](#-known-limitations))。
|
|
307
262
|
|
|
308
263
|
---
|
|
309
264
|
|
|
310
265
|
**Built with**: DeepSeek Harness 0.1.1-rc.2 · Cordis · Z3 (WASM) · loopx (pipx) · hotelbyte-cli · Agent-Reach v1.5.0 (`.venv/`) · OpenFlights · TypeScript · Bun
|
|
311
266
|
|
|
312
|
-
**Last verified against `v0.0.1-rc.
|
|
267
|
+
**Last verified against `v0.0.1-rc.8`(已发布,2026-08-28)** — 全栈回归全绿(发布流程见 `scripts/publish-npm.sh`,内部决策见 [docs/decisions-needed.md](docs/decisions-needed.md)、[docs/tokens.md](docs/tokens.md))。
|
package/bin/gotry-inner.js
CHANGED
|
@@ -112,8 +112,57 @@ if (!existsSync(pluginEntry)) {
|
|
|
112
112
|
console.error(`[gotry] 找不到插件入口: ${pluginEntry}(包不完整?)`)
|
|
113
113
|
process.exit(1)
|
|
114
114
|
}
|
|
115
|
-
|
|
115
|
+
// dsh-map-tools 宿主插件(地图/路线/POI,零 key 走 OSM/OSRM):repo 用 vendored,
|
|
116
|
+
// npm 用依赖解析;都找不到就整块剔除 patch 条目(缺地图不挡旅行规划)
|
|
117
|
+
let mapEntry = ''
|
|
118
|
+
const vendoredMap = join(repoRoot, 'ts/dsh-runtime/node_modules/dsh-map-tools/lib/index.js')
|
|
119
|
+
if (existsSync(vendoredMap)) {
|
|
120
|
+
mapEntry = vendoredMap
|
|
121
|
+
} else {
|
|
122
|
+
// npm 布局:子路径可能被 exports 挡(resolve 抛错不能留下旧值),裸包名返回真实入口
|
|
123
|
+
try { mapEntry = require_.resolve('dsh-map-tools/lib/index.js') } catch { mapEntry = '' }
|
|
124
|
+
if (!mapEntry) { try { mapEntry = require_.resolve('dsh-map-tools') } catch { mapEntry = '' } }
|
|
125
|
+
}
|
|
126
|
+
// 结构化澄清卡(T2):ask_user_question 工具 + user-questions 服务,从 dsh 包
|
|
127
|
+
// 上下文解析(pnpm 嵌套布局下只有 dsh 自己看得见这些依赖);失败整块剔除
|
|
128
|
+
// 澄清卡注入(T2):web 用 dsh 原生卡片;headless+TTY 用 gotry 的 stdio 提供方
|
|
129
|
+
// (终端渲染选择题);headless 非 TTY(CI/管道)不注入——工具收到 NO_PROVIDER
|
|
130
|
+
// 错误,人格契约 (5) 退化文本。GOTRY_ASK_STDIO=1 强制启用(测试/外接答复)。
|
|
131
|
+
const stdioAsk = mode === 'headless' && (process.stdin.isTTY || process.env.GOTRY_ASK_STDIO === '1')
|
|
132
|
+
? join(here, 'gotry-stdio-ask.js') : ''
|
|
133
|
+
let askUserInsert = ''
|
|
134
|
+
if (mode === 'web' || stdioAsk) try {
|
|
135
|
+
const reqFromDsh = createRequire(dshBin)
|
|
136
|
+
// 裸包名解析(这些包的 exports 不暴露 ./lib/index.js 子路径,但裸名返回真实入口)
|
|
137
|
+
// userQuestions 服务默认树已注册(重复插入会崩),只插工具消费者
|
|
138
|
+
const at = reqFromDsh.resolve('@deepseek-ai/dsh-tool-ask-user')
|
|
139
|
+
askUserInsert = (stdioAsk ? ` - id: gotry-stdio-ask\n name: '${stdioAsk}'\n` : '')
|
|
140
|
+
+ ` - id: dsh-tool-ask-user\n name: '${at}'`
|
|
141
|
+
} catch { /* 缺件不挡启动 */ }
|
|
142
|
+
|
|
143
|
+
let patchRaw = readFileSync(staticPatch, 'utf-8')
|
|
116
144
|
.replace(/(name:\s*)'[^']*ts\/src\/index\.ts'/, `$1'${pluginEntry}'`)
|
|
145
|
+
.replace(/^\s*# \{ask-user-insert\}.*\n(\s*# .*\n)?/m, askUserInsert ? askUserInsert + '\n' : '')
|
|
146
|
+
if (mapEntry) {
|
|
147
|
+
patchRaw = patchRaw.replace(/(name:\s*)'placeholder\/dsh-map-tools'/, `$1'${mapEntry}'`)
|
|
148
|
+
} else {
|
|
149
|
+
patchRaw = patchRaw.replace(/\n\s*- id: dsh-map-tools\n\s*name: 'placeholder\/dsh-map-tools'\n/, '\n')
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// dsh-calendar 宿主插件(CalDAV 工作窗口读取;未配置时工具报错降级,不挡启动)
|
|
153
|
+
let calEntry = ''
|
|
154
|
+
const vendoredCal = join(repoRoot, 'ts/dsh-runtime/node_modules/dsh-calendar/lib/index.js')
|
|
155
|
+
if (existsSync(vendoredCal)) {
|
|
156
|
+
calEntry = vendoredCal
|
|
157
|
+
} else {
|
|
158
|
+
try { calEntry = require_.resolve('dsh-calendar/lib/index.js') } catch { calEntry = '' }
|
|
159
|
+
if (!calEntry) { try { calEntry = require_.resolve('dsh-calendar') } catch { calEntry = '' } }
|
|
160
|
+
}
|
|
161
|
+
if (calEntry) {
|
|
162
|
+
patchRaw = patchRaw.replace(/(name:\s*)'placeholder\/dsh-calendar'/, `$1'${calEntry}'`)
|
|
163
|
+
} else {
|
|
164
|
+
patchRaw = patchRaw.replace(/\n\s*- id: dsh-calendar\n\s*name: 'placeholder\/dsh-calendar'\n/, '\n')
|
|
165
|
+
}
|
|
117
166
|
const patchPath = join(tmpdir(), `cordis.gotry.${process.pid}.yml`)
|
|
118
167
|
writeFileSync(patchPath, patchRaw)
|
|
119
168
|
if (!process.env.DEEPSEEK_API_KEY && mode !== 'help') {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gotry stdio 澄清卡提供方(T2 补强,ask_user_question 的 headless/TTY 形态):
|
|
3
|
+
*
|
|
4
|
+
* dsh 的 userQuestions 服务是「单一 UI 提供方」架构——web 界面注册一种,这里注册
|
|
5
|
+
* 终端形态:ask_user_question 在交互终端渲染成选择题,读一行序号作答复。业界对照
|
|
6
|
+
* (Claude Code -p 最终做法是 headless 直接不暴露工具;MCP elicitation 规范:无提供
|
|
7
|
+
* 方应作为错误/优雅降级传回模型)——我们比照实现为:
|
|
8
|
+
* - headless + TTY(人坐在终端前):注册本插件,终端问答(优于纯文本退化)
|
|
9
|
+
* - headless + 非 TTY(CI/管道):不注册 → 工具收到 NO_PROVIDER 错误 → 人格契约
|
|
10
|
+
* (5) 退化文本选择题;GOTRY_ASK_STDIO=1 可强制启用(测试/外接答复管道)
|
|
11
|
+
*
|
|
12
|
+
* 插件形态遵循 dsh 约定(name/inject/apply);纯 JS 无需 dist 编译。
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { createInterface } from 'node:readline'
|
|
16
|
+
|
|
17
|
+
export const name = 'gotry-stdio-ask'
|
|
18
|
+
export const inject = ['userQuestions']
|
|
19
|
+
|
|
20
|
+
export function apply(ctx) {
|
|
21
|
+
const svc = ctx.userQuestions
|
|
22
|
+
if (!svc || typeof svc.registerProvider !== 'function') return
|
|
23
|
+
|
|
24
|
+
svc.registerProvider({
|
|
25
|
+
async ask(request) {
|
|
26
|
+
const answers = []
|
|
27
|
+
for (const q of request.questions ?? []) {
|
|
28
|
+
if (request.signal?.aborted) { answers.push({ id: q.id, selected: [] }); continue }
|
|
29
|
+
const opts = q.options ?? []
|
|
30
|
+
const lines = ['', `❓ ${q.header ? `${q.header} — ` : ''}${q.question}`]
|
|
31
|
+
opts.forEach((o, i) => lines.push(` ${i + 1}. ${o.label}${o.detail ? ` — ${o.detail}` : ''}`))
|
|
32
|
+
lines.push(q.multiSelect ? ' (多选:序号逗号分隔;回车=跳过,可输自定义文本)' : ' (输入序号回车;回车=跳过,可输自定义文本)')
|
|
33
|
+
process.stdout.write(lines.join('\n') + '\n> ')
|
|
34
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout, signal: request.signal })
|
|
35
|
+
let raw = ''
|
|
36
|
+
try {
|
|
37
|
+
raw = (await new Promise((resolve) => {
|
|
38
|
+
rl.once('line', resolve)
|
|
39
|
+
rl.once('close', () => resolve(''))
|
|
40
|
+
if (request.signal) request.signal.addEventListener('abort', () => { try { rl.close() } catch { /* ignore */ } }, { once: true })
|
|
41
|
+
})).trim()
|
|
42
|
+
} finally { try { rl.close() } catch { /* ignore */ } }
|
|
43
|
+
const selected = []
|
|
44
|
+
let custom
|
|
45
|
+
if (raw && /^[0-9,\s]+$/.test(raw)) {
|
|
46
|
+
for (const part of raw.split(/[,\s]+/).filter(Boolean)) {
|
|
47
|
+
const o = opts[Number(part) - 1]
|
|
48
|
+
if (o) selected.push(o.label)
|
|
49
|
+
}
|
|
50
|
+
} else if (raw) {
|
|
51
|
+
custom = raw
|
|
52
|
+
}
|
|
53
|
+
// 空输入=跳过(MCP elicitation 规范:decline 是正常答复,不是错误)
|
|
54
|
+
answers.push({ id: q.id, selected, ...(custom !== undefined ? { custom } : {}) })
|
|
55
|
+
}
|
|
56
|
+
return { answers }
|
|
57
|
+
},
|
|
58
|
+
})
|
|
59
|
+
}
|
package/cordis.gotry-patch.yml
CHANGED
|
@@ -10,19 +10,77 @@
|
|
|
10
10
|
stateRoot: '.'
|
|
11
11
|
timeoutMs: 30000
|
|
12
12
|
hbcliBin: 'hbcli'
|
|
13
|
+
- id: dsh-map-tools
|
|
14
|
+
name: 'placeholder/dsh-map-tools'
|
|
15
|
+
- id: dsh-calendar
|
|
16
|
+
name: 'placeholder/dsh-calendar'
|
|
17
|
+
# {ask-user-insert} ← inner 运行时填充(dsh-user-questions 服务 + ask_user_question
|
|
18
|
+
# 工具,结构化澄清卡);解析失败整块剔除
|
|
19
|
+
|
|
20
|
+
# 注:insert 里 dsh-map-tools 的 name 是占位符,bin/gotry-inner.js 运行时重写为
|
|
21
|
+
# 绝对路径(repo=vendored runtime;npm=依赖解析,裸包名绕 exports 子路径限制);
|
|
22
|
+
# 依赖缺失时该条目整块剔除,不挡启动。地图/路线/POI 工具,零 key 走 OSRM/OSRM。
|
|
13
23
|
|
|
14
24
|
# GoTry 成品人格:行为契约=产品语义
|
|
15
25
|
- id: system-prompt
|
|
16
26
|
config:
|
|
17
27
|
persona: >-
|
|
18
28
|
你是 GoTry——从出发到下一次出发的 AI 旅行伙伴(中国出境首发,workation 场景)。
|
|
19
|
-
今天是 {{current_date}}
|
|
29
|
+
今天是 {{current_date}}。时间锚点卡(相对日期换算的唯一依据,一律查卡不自算):
|
|
30
|
+
{{time_anchor_card}}
|
|
31
|
+
用户记忆 brief(空 = 首访,按 (1) 访谈;非空 = 回访——已答字段不重复问,
|
|
32
|
+
先引用画像再确认变化,冲突以用户当轮为准):
|
|
33
|
+
{{motivation_brief}}
|
|
34
|
+
行为契约:
|
|
20
35
|
(1)动机先行:首轮必问工作窗口(几点到几点/什么时区)与已订资源(航班/酒店);
|
|
21
|
-
(2)
|
|
36
|
+
(2)日历一次断言:日期换算以锚点卡为准并记住,冲突让用户裁决,永不重算;
|
|
22
37
|
(3)翻译不造数:班次/价格只来自工具(gotry_feasibility_check/gotry_skeleton_check/gotry_hotel_search);
|
|
23
38
|
(4)判定归引擎:可行性/全成本由工具计算,你只解释;
|
|
24
|
-
(5)
|
|
39
|
+
(5)待决=选择题:优先用 ask_user_question 工具发结构化选项(2-3 个带 trade-off,
|
|
40
|
+
web 界面渲染成卡片;该工具不可用或无响应时退化为文本选择题);
|
|
25
41
|
(6)憧憬不被拒绝:不可行进 gotry_wish_pool_add(带条件);
|
|
42
|
+
用户表达新的出行意图时,若时间/预算窗口可能命中已存憧憬,先调
|
|
43
|
+
gotry_wish_pool_list 查询再答——命中就用清单里的选项开场(它是用户自己许过的愿);
|
|
44
|
+
「下一次出发」建议一轮至多 surface 1 条(0..1 纪律),条件不命中就不硬推;
|
|
45
|
+
成效归因只能按用户明说的记(wish confirm-outcome),不许自评「有用」;
|
|
26
46
|
(7)证据链:引用工具返回的标注([骨架:openflights]/[实时API:hbcli]/[静态包:估算])。
|
|
27
|
-
(8)
|
|
28
|
-
|
|
47
|
+
(8)时间感知:以锚点卡的今天为锚点——已过的月份不说「将」,当下所在的季节
|
|
48
|
+
直接点明(如「现在正是雨季」而非把当前月份当成远期选项);用户给的绝对日期
|
|
49
|
+
早于今天时,主动点明已过并请用户裁决(笔误还是指明年),不静默顺延;
|
|
50
|
+
周/月/节日表述一律按锚点卡换算,不自算;用户说「在 X 年内完成」时,
|
|
51
|
+
只推荐今天之后的时段,今天之前的一律排除。
|
|
52
|
+
(9)年界断言:「元旦/新年/春节」先断年再谈——今天是 {{current_date}},
|
|
53
|
+
「2026 年内」不含 2027-01-01 元旦;农历节日先换算公历日期再判断归属年份。
|
|
54
|
+
(10)不重复问:预算/日期/窗口/出发地等已问过或用户已给的信息,会话内
|
|
55
|
+
永不重复询问;缺信息先查已有上下文,再决定是否发问。
|
|
56
|
+
(11)零示例泄漏:工具参数里的示例值只是格式占位,不是推荐目的地;
|
|
57
|
+
用户没提过的地点永不主动引入。
|
|
58
|
+
(12)术语不猜:不认识的术语/缩写(如 IRW)直接问用户含义或用工具查,
|
|
59
|
+
绝不假装理解、绝不编造解释。
|
|
60
|
+
(13)外部事实先查工具:价格/班次/政策/新闻等实时或外部事实,
|
|
61
|
+
一律先调工具,不凭记忆作答。
|
|
62
|
+
(14)数据源路由:通用外部事实/内容平台(网页/社媒/行情/视频/播客)优先
|
|
63
|
+
gotry_agent_reach(上游全渠道,不许自行降级跳过);酒店与目的地库存才走
|
|
64
|
+
gotry_hotel_search / gotry_anything_search;天气/航班用专用工具。
|
|
65
|
+
(15)渠道 setup 协助:agent-reach 渠道返回 needs-setup 不是终点——把上游
|
|
66
|
+
配置命令原样给用户(如 agent-reach configure --from-browser chrome
|
|
67
|
+
--platform <渠道>),说明配好后你会复检,并主动提出下一步;绝不就此放弃该渠道。
|
|
68
|
+
(16)域边界(宿主 skill 共存):旅行规划/目的地/行程/预算规划永远是 gotry 的
|
|
69
|
+
工具链,绝不因关键词(差旅/年假/IRW)路由进宿主其他 skill(如 cis-cli);
|
|
70
|
+
只有用户明确要查公司系统(假期余额/出差订单/报销审批)时才调对应 skill;
|
|
71
|
+
交界场景(用年假去旅行)分两步——余额查询归公司 skill,去哪/怎么去归 gotry。
|
|
72
|
+
(17)判定前背景调查:给可行性结论前,先对每个候选目的地取气候背景
|
|
73
|
+
(gotry_weather_check 的 climate 模式);季节性/天气论断必须带
|
|
74
|
+
[实时API:open-meteo@ts] 证据,没查过就不写天气相关理由。
|
|
75
|
+
(18)动态吸收与开放性选题:对话中用户透露的新事实(动机/约束/偏好/
|
|
76
|
+
已订资源/实际经历)当轮即并入动机画像(gotry_motivation_save,
|
|
77
|
+
evidence=用户原话),不等确认;班次/房型/落脚点等开放性选择不外问
|
|
78
|
+
用户——基于已知动机与约束给出最有说服力的方案并说明理由,用户否决
|
|
79
|
+
才改。校准类疑问永不阻塞推进。
|
|
80
|
+
(19)实时价与班期三级路由:机票/火车班次与票价先 gotry_flyai_search
|
|
81
|
+
(飞猪官方只读,主链路);关键决策(临近下单/价差存疑)再用
|
|
82
|
+
gotry_session_search 在用户本人登录态交叉验证,直达/中转分桶比对,
|
|
83
|
+
不比裸最低价;两源皆不可用退静态包并显式标 [静态包:估算]。
|
|
84
|
+
会话工具返回 needs-login→请用户跑 scripts/session-login.ts 并
|
|
85
|
+
继续用官方源推进;返回 challenged→立即停手如实告知,绝不重试
|
|
86
|
+
绝不绕过。[会话:*] 证据链随结论必达用户。
|
package/data/flights_2026.json
CHANGED
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
"f2 起点真实:8.1 从甲米(奥南)出发,周末换防模式:Rawai 7.18-8.1 主基地 + 8.1-3 奥南 2 晚 + 8.7-9 奥南 2 晚(共 3 晚)",
|
|
26
26
|
"住宿模式:Rawai 拉威基地 7.18-8.1,周末甲米换防 2 段(非整体搬迁);demo 主基地+中途换防结构命中",
|
|
27
27
|
"f2 起点真实:8.1 从甲米 KBV 机场出发(不是 HKT)——周末换防 7.31 普吉→甲米,2 晚奥南,8.3 甲米→曼谷(从 KBV 飞,不是本 leg 的 HKT→DMK)",
|
|
28
|
-
"auto-guess 2026-08-24 吸收:f1=HX741 20:20 / f4-SZX≈22:00 / EK329→家 1.5h(docs/decisions-needed.md D-2 auto-guess 块,founder 校正任意行即改)"
|
|
28
|
+
"auto-guess 2026-08-24 吸收:f1=HX741 20:20 / f4-SZX≈22:00 / EK329→家 1.5h(docs/decisions-needed.md D-2 auto-guess 块,founder 校正任意行即改)",
|
|
29
|
+
"f1 真值(founder 2026-08-26):实际乘 ~16:xx 起飞班次(非 CX773 14:45 也非 HX741 20:20),23:00 落地 HKT;13:xx 办完事地铁赴港机正合适。教训:班次=开放性选题,agent 以合理说服选案即可,不应外问",
|
|
30
|
+
"f4 真值(founder 2026-08-26):实际昆明→珠海(动机:没去过,想待半天),因行李不便落地后不久坐顺风车返深圳——auto-guess 的『昆明→深圳直飞 22:00 到』路线错误",
|
|
31
|
+
"EK329 后真值(founder 2026-08-26):深圳无住所;当晚办完通行证事务已晚,按摩店过夜(按摩+过夜比酒店划算且舒服)——auto-guess 的『到家 1.5h』前提(有家)不成立"
|
|
29
32
|
]
|
|
30
33
|
},
|
|
31
34
|
"legs": [
|
|
@@ -58,7 +61,7 @@
|
|
|
58
61
|
"evidence": [
|
|
59
62
|
{
|
|
60
63
|
"tag": "[auto-guess:2026-08-24]",
|
|
61
|
-
"note": "f1 实际=HX741 20:20(晚班;Kimi 7.18 当天飞+早高峰,CX773 12:15 过紧)—founder
|
|
64
|
+
"note": "f1 实际=HX741 20:20(晚班;Kimi 7.18 当天飞+早高峰,CX773 12:15 过紧)—founder 校正即改【已校正 2026-08-26,真值见 meta.reconcil】"
|
|
62
65
|
}
|
|
63
66
|
]
|
|
64
67
|
},
|
|
@@ -87,7 +90,7 @@
|
|
|
87
90
|
"evidence": [
|
|
88
91
|
{
|
|
89
92
|
"tag": "[auto-guess:2026-08-24]",
|
|
90
|
-
"note": "EK329 落地→躺床上≈1.5h(SZX→南山车程;D-6 精力模型落地端附加 1.5h 口径)—founder
|
|
93
|
+
"note": "EK329 落地→躺床上≈1.5h(SZX→南山车程;D-6 精力模型落地端附加 1.5h 口径)—founder 校正即改【已校正 2026-08-26,真值见 meta.reconcil】"
|
|
91
94
|
}
|
|
92
95
|
]
|
|
93
96
|
},
|
|
@@ -207,7 +210,7 @@
|
|
|
207
210
|
"evidence": [
|
|
208
211
|
{
|
|
209
212
|
"tag": "[auto-guess:2026-08-24]",
|
|
210
|
-
"note": "f4 实际到达 SZX≈22:00(MU6088/DZ6252 中间值,给 EK329 红眼留 4h 缓冲)—founder
|
|
213
|
+
"note": "f4 实际到达 SZX≈22:00(MU6088/DZ6252 中间值,给 EK329 红眼留 4h 缓冲)—founder 校正即改【已校正 2026-08-26,真值见 meta.reconcil】"
|
|
211
214
|
}
|
|
212
215
|
]
|
|
213
216
|
}
|
package/data/hotels_2026.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
|
-
"note": "四个住宿块的价格档(经济/舒适/便利),公开渠道估算,非实时报价。workation
|
|
3
|
+
"note": "四个住宿块的价格档(经济/舒适/便利),公开渠道估算,非实时报价。workation 块按『办公室标准』建模。短住场景块(如 dali-short)为公开渠道均价锚定的估算,证据链标 [静态包:估算]。",
|
|
4
4
|
"sources": [
|
|
5
5
|
"HOMA/PropertyScout:查龙服务式公寓月租 27,720-165,000 THB;本地公寓 5,000-10,000 THB/月(6-12 月约)",
|
|
6
6
|
"Expedia/Airbnb:卡塔/卡伦公寓 $18-25/晚起;两周连住议价空间 20-30%",
|
|
@@ -17,9 +17,24 @@
|
|
|
17
17
|
"note": "7.17 深夜落地后的过夜(次日一早过境香港)",
|
|
18
18
|
"nights": 1,
|
|
19
19
|
"options": [
|
|
20
|
-
{
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
{
|
|
21
|
+
"tier": "经济",
|
|
22
|
+
"name": "雅斯特国际酒店(深圳机场 T3 店)",
|
|
23
|
+
"price_cny": 218,
|
|
24
|
+
"why": "免费接送机;但次日需先回市区再过境"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"tier": "便利",
|
|
28
|
+
"name": "福田口岸侧连锁酒店",
|
|
29
|
+
"price_cny": 320,
|
|
30
|
+
"why": "落地后打车约 1h ¥120;清晨 06:30 步行过境,为办证锚点买时间"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"tier": "舒适",
|
|
34
|
+
"name": "深圳机场凯悦嘉寓(航站楼内)",
|
|
35
|
+
"price_cny": 450,
|
|
36
|
+
"why": "落地即睡;但次晨需赶早过境"
|
|
37
|
+
}
|
|
23
38
|
],
|
|
24
39
|
"recommendation": "便利档(口岸侧):a2 办证锚点 09:00 开门,住口岸侧是唯一能睡到 6:40 还从容的选择(全成本视角:落地夜的门到门已耗尽精力,次晨多睡 1h 价值最高)"
|
|
25
40
|
},
|
|
@@ -29,19 +44,47 @@
|
|
|
29
44
|
"nights": 13,
|
|
30
45
|
"location_decision": "查龙/Rawai 基地(数字游民区+潜水码头双吻合);『万xx』候选(考拉克/甲米奥南/董里)留作中途换防 2-3 晚的选项,待 gate 裁决",
|
|
31
46
|
"options": [
|
|
32
|
-
{
|
|
33
|
-
|
|
34
|
-
|
|
47
|
+
{
|
|
48
|
+
"tier": "经济",
|
|
49
|
+
"name": "卡塔/卡伦公寓式(自炊)",
|
|
50
|
+
"price_per_night_cny": 140,
|
|
51
|
+
"why": "$18-25/晚;离查龙码头 20-30min 车程"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"tier": "舒适",
|
|
55
|
+
"name": "查龙/Rawai 服务式公寓(带共享办公)",
|
|
56
|
+
"price_per_night_cny": 300,
|
|
57
|
+
"why": "HOMA 类;workstation 标准:WiFi+办公区+潜水码头 10min 内;两周连住可议价 20-30%"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"tier": "高端",
|
|
61
|
+
"name": "海滨度假公寓(带办公桌)",
|
|
62
|
+
"price_per_night_cny": 550,
|
|
63
|
+
"why": "工作体验与度假体验兼得"
|
|
64
|
+
}
|
|
35
65
|
],
|
|
36
|
-
"requirements_check": [
|
|
66
|
+
"requirements_check": [
|
|
67
|
+
"WiFi ≥50Mbps 且有备用(共享办公区)",
|
|
68
|
+
"书桌+静音(10 个工作日的会议)",
|
|
69
|
+
"近查龙码头(女朋友潜水集合点)",
|
|
70
|
+
"长住议价"
|
|
71
|
+
]
|
|
37
72
|
},
|
|
38
73
|
{
|
|
39
74
|
"id": "s3",
|
|
40
75
|
"note": "曼谷周末(2 晚)",
|
|
41
76
|
"nights": 2,
|
|
42
77
|
"options": [
|
|
43
|
-
{
|
|
44
|
-
|
|
78
|
+
{
|
|
79
|
+
"tier": "经济",
|
|
80
|
+
"name": "BTS 沿线三星(Mo Chit/素坤逸)",
|
|
81
|
+
"price_per_night_cny": 240
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"tier": "舒适",
|
|
85
|
+
"name": "素坤逸/暹罗四星(直通 BTS)",
|
|
86
|
+
"price_per_night_cny": 528
|
|
87
|
+
}
|
|
45
88
|
]
|
|
46
89
|
},
|
|
47
90
|
{
|
|
@@ -49,16 +92,60 @@
|
|
|
49
92
|
"note": "云南一周(6 晚,请假纯旅行;昆明为进出航点,环线待 gate)",
|
|
50
93
|
"nights": 6,
|
|
51
94
|
"options": [
|
|
52
|
-
{
|
|
53
|
-
|
|
95
|
+
{
|
|
96
|
+
"tier": "经济",
|
|
97
|
+
"name": "大理/丽江淡季包周民宿",
|
|
98
|
+
"total_cny": 1200,
|
|
99
|
+
"why": "淡季月租可低至 ¥900-1500/月,包周约 ¥200/晚"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"tier": "舒适",
|
|
103
|
+
"name": "洱海/古城景观民宿",
|
|
104
|
+
"total_cny": 2400,
|
|
105
|
+
"why": "均价 ¥408/晚,一周议价后约 ¥400/晚"
|
|
106
|
+
}
|
|
54
107
|
]
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"id": "dali-short",
|
|
111
|
+
"note": "短住 2-3 晚场景(周末湖边放松);估算锚点=meta.sources 已引 Booking 大理短租均价 ¥408/晚、淡季包周 ¥1,000-2,500,非实时报价",
|
|
112
|
+
"nights": 2,
|
|
113
|
+
"options": [
|
|
114
|
+
{
|
|
115
|
+
"tier": "经济",
|
|
116
|
+
"name": "大理古城内民宿标间",
|
|
117
|
+
"price_cny": 250,
|
|
118
|
+
"why": "低于均价约 4 成;淡季议价空间大,步行古城 but 距洱海 3-5km"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"tier": "舒适",
|
|
122
|
+
"name": "才村/龙龛码头湖景民宿",
|
|
123
|
+
"price_cny": 408,
|
|
124
|
+
"why": "等于 Booking 短租均价;推窗见海,环湖骑行起点"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"tier": "便利",
|
|
128
|
+
"name": "高铁站侧连锁酒店",
|
|
129
|
+
"price_cny": 300,
|
|
130
|
+
"why": "抵达/离开零接驳成本;牺牲湖景,适合早班车次日出发"
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
"recommendation": "舒适档(湖景民宿):短住的目的是『湖边发呆』,景观即产品;经济档把差价花在环湖电动车(约 ¥60/天)体验更佳"
|
|
55
134
|
}
|
|
56
135
|
],
|
|
57
136
|
"budget_tiers_summary": {
|
|
58
137
|
"note": "机票(五段联算 ¥8,380)+ 住宿的分层总预算(gate q2 的决策材料)",
|
|
59
|
-
"经济": {
|
|
60
|
-
|
|
138
|
+
"经济": {
|
|
139
|
+
"flights": 8380,
|
|
140
|
+
"hotels": 4200,
|
|
141
|
+
"total": 12580
|
|
142
|
+
},
|
|
143
|
+
"舒适": {
|
|
144
|
+
"flights": 8380,
|
|
145
|
+
"hotels": 7900,
|
|
146
|
+
"total": 16280
|
|
147
|
+
},
|
|
61
148
|
"hotel_breakdown_economy": "218(或 320 便利档)+140×13+240×2+1200",
|
|
62
149
|
"hotel_breakdown_comfort": "450+300×13+528×2+2400"
|
|
63
150
|
}
|
|
64
|
-
}
|
|
151
|
+
}
|