@danceiny/gotry 0.0.1-rc.21 → 0.0.1-rc.24

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.
Files changed (327) hide show
  1. package/README.md +102 -194
  2. package/README.zh-CN.md +115 -210
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-bootstrap.js +466 -35
  5. package/bin/gotry-inner.js +255 -36
  6. package/bin/gotry-process-liveness.d.ts +27 -0
  7. package/bin/gotry-process-liveness.js +97 -0
  8. package/bin/gotry-runtime-resolution.d.ts +1 -1
  9. package/bin/gotry-runtime-resolution.js +2 -2
  10. package/client/client.js +174 -0
  11. package/cordis.gotry-patch.yml +70 -93
  12. package/dist/capabilities/agent-reach-deep.js +45 -122
  13. package/dist/capabilities/agent-reach.js +63 -148
  14. package/dist/capabilities/anything.js +89 -75
  15. package/dist/capabilities/artifacts.js +123 -104
  16. package/dist/capabilities/channel-health.js +65 -45
  17. package/dist/capabilities/channel-registry.js +108 -87
  18. package/dist/capabilities/doctor.js +357 -235
  19. package/dist/capabilities/effect.js +223 -309
  20. package/dist/capabilities/fact-log.js +28 -14
  21. package/dist/capabilities/flyai.js +245 -156
  22. package/dist/capabilities/ground-transfer.js +509 -0
  23. package/dist/capabilities/hbcli.js +144 -148
  24. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  25. package/dist/capabilities/incident-log.js +131 -61
  26. package/dist/capabilities/model-override.js +30 -10
  27. package/dist/capabilities/opensky.js +54 -43
  28. package/dist/capabilities/resilience.js +50 -32
  29. package/dist/capabilities/session/action-cache.js +50 -44
  30. package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
  31. package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
  32. package/dist/capabilities/session/adapters/dida-portal.js +206 -0
  33. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  34. package/dist/capabilities/session/adapters/rail-12306.js +169 -112
  35. package/dist/capabilities/session/benchmark.js +85 -149
  36. package/dist/capabilities/session/extension-bridge.js +320 -259
  37. package/dist/capabilities/session/extension-channel.js +57 -76
  38. package/dist/capabilities/session/extension-distribution.js +115 -119
  39. package/dist/capabilities/session/extract.js +31 -21
  40. package/dist/capabilities/session/golden-score.js +55 -33
  41. package/dist/capabilities/session/health-watch.js +146 -154
  42. package/dist/capabilities/session/read-guard.js +55 -47
  43. package/dist/capabilities/session/static-flight-golden.js +49 -36
  44. package/dist/capabilities/session/transport.js +54 -61
  45. package/dist/capabilities/session/wizard.js +63 -93
  46. package/dist/capabilities/session-consent.js +143 -47
  47. package/dist/capabilities/session-login.js +95 -126
  48. package/dist/capabilities/session-search.js +391 -253
  49. package/dist/capabilities/sponsor-plugin.js +341 -0
  50. package/dist/capabilities/visa-policy.js +87 -73
  51. package/dist/capabilities/weather.js +163 -235
  52. package/dist/scripts/action-cache-tests.js +24 -59
  53. package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
  54. package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
  55. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  56. package/dist/scripts/agent-reach-tests.js +26 -18
  57. package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
  58. package/dist/scripts/anything-tests.js +58 -62
  59. package/dist/scripts/artifact-client-contract-tests.js +69 -0
  60. package/dist/scripts/artifacts-capability-tests.js +235 -0
  61. package/dist/scripts/async-collect.js +26 -15
  62. package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
  63. package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
  64. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
  65. package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
  66. package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
  67. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
  68. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
  69. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
  70. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
  71. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
  72. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
  73. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
  74. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
  75. package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
  76. package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
  77. package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
  78. package/dist/scripts/booking-executor-tests.js +80 -0
  79. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  80. package/dist/scripts/booking-saga-tests.js +61 -123
  81. package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
  82. package/dist/scripts/bootstrap-tests.js +1383 -128
  83. package/dist/scripts/build-changelog.js +89 -130
  84. package/dist/scripts/build-metrics-report.js +135 -143
  85. package/dist/scripts/changelog-tests.js +35 -82
  86. package/dist/scripts/channel-probe-tests.js +44 -116
  87. package/dist/scripts/channel-probe.js +84 -167
  88. package/dist/scripts/channel-registry-tests.js +97 -185
  89. package/dist/scripts/companion-tests.js +25 -70
  90. package/dist/scripts/dida-cookie-probe.js +87 -0
  91. package/dist/scripts/dida-sw-probe.js +114 -0
  92. package/dist/scripts/diff-test.js +17 -12
  93. package/dist/scripts/doctor-tests.js +428 -120
  94. package/dist/scripts/dsh-artifact-e2e.js +150 -0
  95. package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
  96. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  97. package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
  98. package/dist/scripts/dsh-runtime-closure.js +75 -63
  99. package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
  100. package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
  101. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  102. package/dist/scripts/effect-tests.js +165 -552
  103. package/dist/scripts/engine-run.js +1 -3
  104. package/dist/scripts/engine-tests.js +16 -10
  105. package/dist/scripts/evaluation-cadence-tests.js +69 -242
  106. package/dist/scripts/evaluation-contract-tests.js +193 -499
  107. package/dist/scripts/extension-distribution-cli.js +19 -15
  108. package/dist/scripts/extension-distribution-tests.js +98 -211
  109. package/dist/scripts/extension-tests.js +366 -389
  110. package/dist/scripts/fact-gate-tests.js +725 -263
  111. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  112. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  113. package/dist/scripts/flight-malformed-tests.js +159 -0
  114. package/dist/scripts/flyai-tests.js +325 -68
  115. package/dist/scripts/g5-guard-tests.js +131 -0
  116. package/dist/scripts/g5-guard.js +189 -0
  117. package/dist/scripts/gen-lunar-anchors.js +106 -0
  118. package/dist/scripts/gotry-backend-kernel-tests.js +79 -0
  119. package/dist/scripts/ground-transfer-tests.js +956 -0
  120. package/dist/scripts/hbcli-e2e-tests.js +71 -90
  121. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  122. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  123. package/dist/scripts/hbcli-tests.js +41 -115
  124. package/dist/scripts/health-watch-cli.js +42 -28
  125. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  126. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  127. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  128. package/dist/scripts/i18n-tests.js +16 -9
  129. package/dist/scripts/incident-tests.js +281 -87
  130. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  131. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  132. package/dist/scripts/issue-271-liveness-tests.js +547 -0
  133. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  134. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  135. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  136. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  137. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  138. package/dist/scripts/journey-tests.js +22 -27
  139. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  140. package/dist/scripts/kernel-manifest-gate.js +126 -0
  141. package/dist/scripts/kernel-manifest-tests.js +212 -0
  142. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  143. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  144. package/dist/scripts/kernel-manifest.js +369 -0
  145. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  146. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  147. package/dist/scripts/ledger-tests.js +325 -340
  148. package/dist/scripts/ledger-workflow-crash.js +10 -20
  149. package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
  150. package/dist/scripts/memory-capture-tests.js +242 -61
  151. package/dist/scripts/memory-decay-tests.js +18 -52
  152. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  153. package/dist/scripts/memory-lifecycle.js +196 -0
  154. package/dist/scripts/memory-metrics.js +24 -12
  155. package/dist/scripts/memory-value-report.js +474 -222
  156. package/dist/scripts/memory-value-tests.js +328 -0
  157. package/dist/scripts/metrics-report-tests.js +62 -199
  158. package/dist/scripts/model-override-e2e.js +66 -105
  159. package/dist/scripts/nightly-evidence-tests.js +64 -89
  160. package/dist/scripts/nightly-evidence.js +108 -111
  161. package/dist/scripts/nudge-digest.js +39 -28
  162. package/dist/scripts/onboarding-tests.js +63 -88
  163. package/dist/scripts/opensky-check.js +18 -13
  164. package/dist/scripts/opensky-tests.js +28 -28
  165. package/dist/scripts/persona-surface-guard-tests.js +37 -12
  166. package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
  167. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  168. package/dist/scripts/price-drift-tests.js +126 -227
  169. package/dist/scripts/price-drift-watch.js +209 -253
  170. package/dist/scripts/probe-poi-tests.js +52 -45
  171. package/dist/scripts/product-metrics.js +187 -273
  172. package/dist/scripts/publish-preverify.js +47 -41
  173. package/dist/scripts/realtime-pricing-tests.js +37 -76
  174. package/dist/scripts/replay-async.js +20 -18
  175. package/dist/scripts/replay-real.js +16 -18
  176. package/dist/scripts/replay.js +52 -82
  177. package/dist/scripts/session-attach-diagnose.js +16 -12
  178. package/dist/scripts/session-attach-poc.js +34 -37
  179. package/dist/scripts/session-benchmark.js +66 -147
  180. package/dist/scripts/session-dida-live-e2e.js +151 -0
  181. package/dist/scripts/session-extract-tests.js +14 -35
  182. package/dist/scripts/session-login.js +14 -13
  183. package/dist/scripts/session-tests.js +545 -583
  184. package/dist/scripts/sf-live-benchmark.js +92 -110
  185. package/dist/scripts/sf-live-cli-tests.js +2 -9
  186. package/dist/scripts/sf-soft-score-tests.js +19 -60
  187. package/dist/scripts/sf-summary-tests.js +149 -0
  188. package/dist/scripts/sf-summary.js +466 -84
  189. package/dist/scripts/skeleton-check.js +16 -14
  190. package/dist/scripts/skeleton-integration-test.js +11 -10
  191. package/dist/scripts/skills-contract-tests.js +51 -46
  192. package/dist/scripts/smoke-session-gate-tests.js +12 -20
  193. package/dist/scripts/smoke.js +541 -422
  194. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  195. package/dist/scripts/state-cli-tests.js +226 -101
  196. package/dist/scripts/state-cli.js +549 -212
  197. package/dist/scripts/static-golden-tests.js +46 -180
  198. package/dist/scripts/time-eval-tests.js +210 -192
  199. package/dist/scripts/travel-timeline-tests.js +29 -93
  200. package/dist/scripts/turn-handoff-collect-tests.js +46 -93
  201. package/dist/scripts/turn-handoff-collect.js +71 -99
  202. package/dist/scripts/turn-policy-tests.js +28 -29
  203. package/dist/scripts/typed-contract-canary.js +77 -162
  204. package/dist/scripts/tz-resolver-sanity.js +50 -0
  205. package/dist/scripts/tz-resolver-tests.js +584 -0
  206. package/dist/scripts/unified-tests.js +23 -19
  207. package/dist/scripts/visa-policy-tests.js +31 -44
  208. package/dist/scripts/weather-tests.js +121 -543
  209. package/dist/scripts/wish-channel-gate-tests.js +29 -86
  210. package/dist/scripts/write-gate-tests.js +522 -0
  211. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  212. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  213. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  214. package/dist/scripts/z3-race-tests.js +18 -12
  215. package/dist/src/artifact-gate.js +652 -221
  216. package/dist/src/backend/kernel.js +91 -0
  217. package/dist/src/backend/modules/booking-copilot.js +55 -0
  218. package/dist/src/backend/modules/booking-executor.js +124 -0
  219. package/dist/src/backend/modules/session-search.js +194 -0
  220. package/dist/src/benchmark-agent-conformance.js +296 -262
  221. package/dist/src/benchmark-environment-bridge.js +298 -413
  222. package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
  223. package/dist/src/benchmark-tool-isolation.js +94 -67
  224. package/dist/src/bookable-facts.js +299 -174
  225. package/dist/src/booking-saga.js +64 -120
  226. package/dist/src/booking-surface/availability-policy.js +443 -576
  227. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  228. package/dist/src/booking-surface/contracts.js +24 -80
  229. package/dist/src/booking-surface/dsh-planner.js +510 -281
  230. package/dist/src/booking-surface/dsh-plugin.js +17 -1
  231. package/dist/src/booking-surface/error-codes.js +82 -10
  232. package/dist/src/booking-surface/index.js +0 -3
  233. package/dist/src/booking-surface/profile.js +10 -54
  234. package/dist/src/booking-surface/recovery-chain.js +367 -0
  235. package/dist/src/booking-surface/runtime.js +765 -891
  236. package/dist/src/booking-surface/server.js +200 -251
  237. package/dist/src/booking-surface/startup.js +58 -54
  238. package/dist/src/booking-surface/validation.js +150 -218
  239. package/dist/src/bridge.js +20 -13
  240. package/dist/src/companions.js +48 -74
  241. package/dist/src/contracts.js +21 -43
  242. package/dist/src/dsh-llm.js +82 -120
  243. package/dist/src/engine.js +253 -239
  244. package/dist/src/evaluation-cadence.js +72 -209
  245. package/dist/src/evaluation-contracts.js +220 -843
  246. package/dist/src/flight-pack-adapter.js +54 -0
  247. package/dist/src/flight-pack-contract.js +2 -0
  248. package/dist/src/gotry-backend.js +70 -0
  249. package/dist/src/hotel-date-gate.js +118 -0
  250. package/dist/src/i18n.js +18 -7
  251. package/dist/src/index.js +1425 -1629
  252. package/dist/src/journey.js +132 -81
  253. package/dist/src/ledger-repair-apply.js +538 -0
  254. package/dist/src/ledger-repair-plan.js +463 -0
  255. package/dist/src/loop.js +257 -166
  256. package/dist/src/memory-capture.js +180 -32
  257. package/dist/src/memory-decay.js +30 -14
  258. package/dist/src/memory-lifecycle.js +1310 -0
  259. package/dist/src/memory-utility.js +27 -40
  260. package/dist/src/mock-llm.js +36 -61
  261. package/dist/src/model.js +81 -36
  262. package/dist/src/realtime-pricing.js +63 -72
  263. package/dist/src/slot-spec.js +84 -106
  264. package/dist/src/state-ledger.js +310 -471
  265. package/dist/src/subagent-job-id-guard.js +58 -0
  266. package/dist/src/time-anchor.js +231 -33
  267. package/dist/src/tool-packet.js +20 -8
  268. package/dist/src/travel-slots.js +58 -35
  269. package/dist/src/travel-timeline.js +44 -63
  270. package/dist/src/turn-deadline.js +121 -127
  271. package/dist/src/turn-policy.js +61 -89
  272. package/dist/src/tz-resolver.js +143 -0
  273. package/dist/src/unified.js +504 -381
  274. package/dist/src/wish-pool.js +39 -14
  275. package/dist/src/write-gate.js +495 -0
  276. package/dist/src/z3-shared.js +273 -7
  277. package/extension/README.md +4 -3
  278. package/extension/background.js +125 -14
  279. package/extension/content-bridge.js +23 -1
  280. package/extension/content-main.js +15 -4
  281. package/extension/manifest.json +16 -8
  282. package/package.json +251 -220
  283. package/ts/capabilities/agent-reach.ts +4 -4
  284. package/ts/capabilities/anything.ts +1 -1
  285. package/ts/capabilities/artifacts.ts +46 -9
  286. package/ts/capabilities/flyai.ts +156 -37
  287. package/ts/capabilities/hbcli.ts +1 -1
  288. package/ts/capabilities/incident-log.ts +88 -59
  289. package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
  290. package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
  291. package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
  292. package/ts/capabilities/session/extension-bridge.ts +226 -101
  293. package/ts/capabilities/session/extension-channel.ts +22 -9
  294. package/ts/capabilities/session/wizard.ts +2 -2
  295. package/ts/capabilities/session-consent.ts +98 -14
  296. package/ts/capabilities/session-login.ts +1 -0
  297. package/ts/capabilities/session-search.ts +315 -31
  298. package/ts/dsh-runtime/vendor/README.md +8 -4
  299. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
  300. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
  301. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
  302. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
  303. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
  304. package/ts/package.json +236 -16
  305. package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
  306. package/ts/scripts/state-cli.ts +418 -51
  307. package/ts/src/artifact-gate.ts +561 -15
  308. package/ts/src/benchmark-environment-bridge.ts +37 -20
  309. package/ts/src/bookable-facts.ts +183 -7
  310. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  311. package/ts/src/booking-surface/dsh-planner.ts +240 -32
  312. package/ts/src/booking-surface/dsh-plugin.js +17 -1
  313. package/ts/src/booking-surface/error-codes.ts +75 -0
  314. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  315. package/ts/src/booking-surface/server.ts +84 -51
  316. package/ts/src/booking-surface/validation.ts +2 -0
  317. package/ts/src/contracts.ts +12 -2
  318. package/ts/src/dsh-llm.ts +4 -8
  319. package/ts/src/index.ts +609 -90
  320. package/ts/src/loop.ts +116 -7
  321. package/ts/src/memory-capture.ts +227 -3
  322. package/ts/src/mock-llm.ts +4 -8
  323. package/ts/src/model.ts +88 -2
  324. package/ts/src/state-ledger.ts +47 -29
  325. package/ts/src/subagent-job-id-guard.ts +72 -0
  326. package/ts/src/time-anchor.ts +217 -13
  327. package/ts/src/unified.ts +316 -54
@@ -1,55 +1,42 @@
1
+ /**
2
+ * 记忆效用 sidecar(RFC S2,post-outcome-memory-utility-attribution 映射):
3
+ * 「被召回 ≠ 有用,自称用了 ≠ 让结果变好」——召回/使用/结果/归因四件语义独立记录,
4
+ * 确定性 reducer 只做投影;verified_outcome 只能来自 owner 确认(owner_correction tier),
5
+ * 模型永远不能自称「有用」。默认 fail-open:sidecar 缺失/损坏不阻塞主路径。
6
+ *
7
+ * 多用户 AaaS 前向兼容(RFC §6.5):append-only 事件流 + 稳定 wish_id,
8
+ * 未来账本化(CAS/receipt)是存储面替换,语义层零改造。
9
+ */
10
+ /** 事件幂等键:同 wish 同类同 ctx 同归因 = 同一事件(重放 no-op) */
1
11
  export function makeEventId(ev) {
2
- return [
3
- ev.wish_id,
4
- ev.kind,
5
- ev.ctx ?? '',
6
- ev.attribution ?? ''
7
- ].join('|');
12
+ return [ev.wish_id, ev.kind, ev.ctx ?? '', ev.attribution ?? ''].join('|');
8
13
  }
14
+ /** 追加不重复(纯函数,不改入参):同 event_id 已存在 → no-op */
9
15
  export function appendEvent(events, ev) {
10
- const full = {
11
- schema: 'memory_utility_observation.v0',
12
- event_id: makeEventId(ev),
13
- ...ev
14
- };
15
- if (events.some((e)=>e.event_id === full.event_id)) return {
16
- events,
17
- appended: false
18
- };
16
+ const full = { schema: 'memory_utility_observation.v0', event_id: makeEventId(ev), ...ev };
17
+ if (events.some(e => e.event_id === full.event_id))
18
+ return { events, appended: false };
19
19
  if (ev.kind === 'verified_outcome' && !ev.attribution) {
20
- return appendEvent(events, {
21
- ...ev,
22
- kind: 'applied'
23
- });
20
+ // 无归因的结果不算归因证据:降级为 applied(六件语义不越界)
21
+ return appendEvent(events, { ...ev, kind: 'applied' });
24
22
  }
25
- return {
26
- events: [
27
- ...events,
28
- full
29
- ],
30
- appended: true
31
- };
23
+ return { events: [...events, full], appended: true };
32
24
  }
25
+ /** 只读投影:status = 最后一次 verified_outcome 的归因;无 verified_outcome 永远 unknown */
33
26
  export function projectUtility(events) {
34
27
  const out = {};
35
- for (const ev of events){
36
- const w = out[ev.wish_id] ??= {
37
- wish_id: ev.wish_id,
38
- status: 'unknown',
39
- recalled: 0,
40
- applied: 0,
41
- verified: 0
42
- };
43
- if (ev.kind === 'recalled') w.recalled++;
44
- if (ev.kind === 'applied') w.applied++;
28
+ for (const ev of events) {
29
+ const w = out[ev.wish_id] ??= { wish_id: ev.wish_id, status: 'unknown', recalled: 0, applied: 0, verified: 0 };
30
+ if (ev.kind === 'recalled')
31
+ w.recalled++;
32
+ if (ev.kind === 'applied')
33
+ w.applied++;
45
34
  if (ev.kind === 'verified_outcome') {
46
35
  w.verified++;
47
- if (ev.attribution) w.status = ev.attribution;
36
+ if (ev.attribution)
37
+ w.status = ev.attribution;
48
38
  }
49
39
  w.last_event_ts = ev.ts;
50
40
  }
51
41
  return out;
52
42
  }
53
-
54
-
55
- //# sourceURL=ts/src/memory-utility.ts
@@ -1,103 +1,78 @@
1
+ /**
2
+ * Mock LLM(S2,ADR-8):确定性剧本,重放真实对话的智能侧。
3
+ * 它不做任何「聪明事」——只按剧本返回抽取结果;循环架构的正确性由此验证,
4
+ * 与智能质量解耦。S4 接真 LLM 后,本文件留作回归夹具。
5
+ */
1
6
  import { parseFlightPackToSpec } from './unified.js';
7
+ import { mergeProfileWorkWindow } from './flight-pack-adapter.js';
8
+ /** 剧本:来自真实 Kimi 对话里用户给出关键事实的时刻 */
2
9
  const SCRIPT = [
3
10
  {
4
11
  when: '请给我做机票和酒店的行程规划和推荐',
5
12
  calendar: {
6
13
  year: 2026,
7
14
  assertedWeekdays: {
8
- '2026-07-17': 'fri',
9
- '2026-07-18': 'sat',
10
- '2026-07-31': 'fri',
11
- '2026-08-01': 'sat',
12
- '2026-08-09': 'sun',
13
- '2026-08-10': 'mon'
14
- }
15
+ '2026-07-17': 'fri', '2026-07-18': 'sat', '2026-07-31': 'fri',
16
+ '2026-08-01': 'sat', '2026-08-09': 'sun', '2026-08-10': 'mon',
17
+ },
15
18
  },
16
- profile: {
17
- companions: [
18
- 'girlfriend(先在普吉)'
19
- ]
20
- }
19
+ profile: { companions: ['girlfriend(先在普吉)'] },
21
20
  },
22
21
  {
23
22
  when: '工作时间',
24
23
  profile: {
25
24
  workWindow: {
26
- homeTzOffsetMin: 240,
27
- startMin: 600,
28
- endMin: 1140,
29
- workdays: [
30
- 0,
31
- 1,
32
- 2,
33
- 3,
34
- 4
35
- ],
36
- evidence: '用户原话:我的工作时间是UTC+4的早上10点到下午7点'
37
- }
38
- }
25
+ homeTzOffsetMin: 240, startMin: 600, endMin: 1140, workdays: [0, 1, 2, 3, 4],
26
+ evidence: '用户原话:我的工作时间是UTC+4的早上10点到下午7点',
27
+ },
28
+ },
39
29
  },
40
30
  {
41
31
  when: '订了酒店',
42
32
  profile: {
43
33
  bookedResources: [
44
- {
45
- kind: 'hotel',
46
- ref: 'The Title East Wing Rawai(7.18-23, 5 晚)',
47
- window: '2026-07-18~07-23'
48
- }
49
- ]
50
- }
51
- }
34
+ { kind: 'hotel', ref: 'The Title East Wing Rawai(7.18-23, 5 晚)', window: '2026-07-18~07-23' },
35
+ ],
36
+ },
37
+ },
52
38
  ];
53
39
  export function createMockLlm(flightPackPath, slotScript = []) {
54
40
  let stepIdx = 0;
55
41
  return {
56
- async extractFacts (history, _state) {
42
+ async extractFacts(history, _state) {
57
43
  const last = history[history.length - 1]?.text ?? '';
44
+ // 剧本顺序消费:真实对话里事实按此顺序浮出;未命中则无新事实
58
45
  const step = SCRIPT[stepIdx];
59
46
  if (step && last.includes(step.when)) {
60
47
  stepIdx++;
61
48
  return {
62
49
  calendar: step.calendar,
63
50
  profile: step.profile,
64
- assumptions: Object.keys({
65
- ...step.profile
66
- }).map((f)=>({
67
- field: f,
68
- source: 'user-verbatim'
69
- }))
51
+ assumptions: Object.keys({ ...step.profile }).map(f => ({ field: f, source: 'user-verbatim' })),
70
52
  };
71
53
  }
72
- return {
73
- assumptions: []
74
- };
54
+ return { assumptions: [] };
75
55
  },
76
- async extractSpec (history, state) {
77
- if (!state.profile.workWindow || !state.profile.bookedResources) return null;
78
- if (!flightPackPath) return null;
56
+ async extractSpec(history, state) {
57
+ // mock 翻译:工作窗口与已订资源齐备后,「翻译」= 装载航班包并挂上真实工作窗口
58
+ if (!state.profile.workWindow || !state.profile.bookedResources)
59
+ return null;
60
+ if (!flightPackPath)
61
+ return null;
79
62
  const { readFile } = await import('node:fs/promises');
80
63
  const pack = JSON.parse(await readFile(flightPackPath, 'utf-8'));
81
64
  const spec = parseFlightPackToSpec(pack);
82
- spec.workWindow = {
83
- homeTzOffsetMin: state.profile.workWindow.homeTzOffsetMin,
84
- startMin: state.profile.workWindow.startMin,
85
- endMin: state.profile.workWindow.endMin,
86
- workdays: state.profile.workWindow.workdays
87
- };
88
- spec.budgetCny = 9000;
89
- return spec;
65
+ const merged = mergeProfileWorkWindow(spec, state.profile.workWindow);
66
+ merged.budgetCny = 9000;
67
+ return merged;
90
68
  },
91
- async extractSlots (history) {
69
+ async extractSlots(history) {
92
70
  const last = history[history.length - 1]?.text ?? '';
93
- const hit = slotScript.find((s)=>last.includes(s.when));
71
+ const hit = slotScript.find(s => last.includes(s.when));
94
72
  return hit ? structuredClone(hit.extraction) : null;
95
73
  },
96
- async polishQuestion (q) {
74
+ async polishQuestion(q) {
97
75
  return `【${q.key}】${q.text}\n(为什么问:${q.why})`;
98
- }
76
+ },
99
77
  };
100
78
  }
101
-
102
-
103
- //# sourceURL=ts/src/mock-llm.ts
package/dist/src/model.js CHANGED
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Gotry 可行性引擎领域模型(TS 版,与 py/gotry_feasibility/model.py 逐行对齐)。
3
+ *
4
+ * 双实现纪律:Python 版是**对照实现(oracle)**,TS 版是产品运行时实现;
5
+ * 同一输入两版必须给出相同判定(ts/scripts/diff-test.ts 做差分验证)。
6
+ * 算术(门到门全成本)在此层与求解完全分离,两边各自可测。
7
+ */
1
8
  export function hhmmToMin(s) {
2
9
  const [h, m] = s.split(':');
3
10
  return Number(h) * 60 + Number(m);
@@ -8,6 +15,7 @@ export function minToHhmm(m) {
8
15
  export function requiredUsableHours(mot) {
9
16
  return mot.baseUsableHours + mot.escapeHoursPerWeight * (mot.weights['escape_rest'] ?? 0);
10
17
  }
18
+ // ---- 精力模型(可校准参数,与 Python 版一致) --------------------------------
11
19
  export const WAKE_PENALTY_BEFORE_5 = 30;
12
20
  export const WAKE_PENALTY_BEFORE_6 = 25;
13
21
  export const WAKE_PENALTY_BEFORE_630 = 15;
@@ -19,56 +27,46 @@ export const DAY2_START_MIN = 9 * 60;
19
27
  export const DAY2_QUALITY = 0.9;
20
28
  export const LATEST_ARRIVE_STAY_MIN = 18 * 60;
21
29
  export function parseMotivation(d) {
22
- const hard = d['hard'] ?? {};
23
- const rawWeights = d['weights'] ?? d;
30
+ const hard = (d['hard'] ?? {});
31
+ const rawWeights = (d['weights'] ?? d);
24
32
  const weights = {};
25
- for (const [k, v] of Object.entries(rawWeights)){
26
- if (typeof v === 'number') weights[k] = v;
33
+ for (const [k, v] of Object.entries(rawWeights)) {
34
+ if (typeof v === 'number')
35
+ weights[k] = v;
27
36
  }
28
37
  return {
29
38
  weights,
30
39
  wakeFloorMin: hhmmToMin(String(hard['wake_not_before'] ?? '06:30')),
31
40
  minArrivalEnergyPct: Number(hard['min_arrival_energy_pct'] ?? 40),
32
41
  baseUsableHours: 4.0,
33
- escapeHoursPerWeight: 2.0
42
+ escapeHoursPerWeight: 2.0,
34
43
  };
35
44
  }
36
45
  export function parseRequest(d) {
37
46
  const home = (d['home'] ?? {})['hubs'] ?? {};
38
47
  const homeHubAccess = {};
39
- for (const [hub, acc] of Object.entries(home)){
40
- homeHubAccess[hub] = {
41
- hub,
42
- toHubMin: Number(acc['to_hub_min'])
43
- };
48
+ for (const [hub, acc] of Object.entries(home)) {
49
+ homeHubAccess[hub] = { hub, toHubMin: Number(acc['to_hub_min']) };
44
50
  }
45
51
  return {
46
52
  note: String(d['note'] ?? ''),
47
53
  motivation: parseMotivation(d['motivation']),
48
54
  windowDays: Number(d['window_days']),
49
55
  budgetCny: Number(d['budget_cny']),
50
- homeHubAccess
56
+ homeHubAccess,
51
57
  };
52
58
  }
53
59
  function parseService(d) {
54
- return {
55
- id: String(d['id']),
56
- depMin: hhmmToMin(String(d['dep'])),
57
- arrMin: hhmmToMin(String(d['arr'])),
58
- priceCny: Number(d['price_cny'])
59
- };
60
+ return { id: String(d['id']), depMin: hhmmToMin(String(d['dep'])), arrMin: hhmmToMin(String(d['arr'])), priceCny: Number(d['price_cny']) };
60
61
  }
61
62
  function parseTransfer(d) {
62
- return {
63
- mode: String(d['mode']),
64
- minutes: Number(d['min']),
65
- priceCny: Number(d['price_cny'])
66
- };
63
+ return { mode: String(d['mode']), minutes: Number(d['min']), priceCny: Number(d['price_cny']) };
67
64
  }
68
65
  export function parseCandidate(d) {
69
66
  return {
70
67
  id: String(d['id']),
71
68
  name: String(d['name']),
69
+ date: typeof d['date'] === 'string' ? d['date'] : undefined,
72
70
  hub: String(d['hub']),
73
71
  bufferOutMin: Number(d['buffer_out_min'] ?? 60),
74
72
  bufferRetMin: Number(d['buffer_ret_min'] ?? 60),
@@ -79,29 +77,79 @@ export function parseCandidate(d) {
79
77
  localDailyCny: Number(d['local_daily_cny']),
80
78
  minDaysForPurpose: Number(d['min_days_for_purpose']),
81
79
  imageryMatch: Number(d['imagery_match']),
82
- bestMonths: (d['best_months'] ?? []).map(Number)
80
+ bestMonths: (d['best_months'] ?? []).map(Number),
83
81
  };
84
82
  }
83
+ /** Issue #343 d2d canonical arithmetic。 */
84
+ export class NonpositiveDurationError extends Error {
85
+ /** 'arr_not_after_dep' | 'legacy_negative_offset' */
86
+ kind;
87
+ code = 'nonpositive_duration';
88
+ constructor(kind, message) {
89
+ super(message);
90
+ this.kind = kind;
91
+ this.name = 'NonpositiveDurationError';
92
+ }
93
+ }
94
+ /**
95
+ * 单段门到门时长(分)。v2 路径用真实 UTC instant(跨日 / 反向日界线 / DST 切换正确),
96
+ * 且强制 `arrUtcMs > depUtcMs` — parse 边界也会再做一次防御性 throw。
97
+ * v1 路径用墙上分钟差 - tzOffsetMin(原数值口径,字节不变,即使结果为负也照旧返回)。
98
+ *
99
+ * v2:arrUtcMs 必须严格大于 depUtcMs;否则抛 NonpositiveDurationError(arr_not_after_dep)。
100
+ * v1:沿用 legacy 公式,字节不变;不抛错。
101
+ *
102
+ * 调用方(unified.ts evaluateOptionMove)只负责拿到 doorToDoorMin 并包装 LegReport。
103
+ */
104
+ export function doorToDoorFromMove(svc, mv) {
105
+ if (typeof svc.depUtcMs === 'number' && typeof svc.arrUtcMs === 'number') {
106
+ if (svc.arrUtcMs <= svc.depUtcMs) {
107
+ throw new NonpositiveDurationError('arr_not_after_dep', `service ${svc.id}: arrUtcMs (${svc.arrUtcMs}) must be strictly greater than depUtcMs (${svc.depUtcMs})`);
108
+ }
109
+ const trueFlightMin = (svc.arrUtcMs - svc.depUtcMs) / 60_000;
110
+ const doorToDoorMin = mv.bufferMin + mv.originTransferMin + trueFlightMin + mv.destTransferMin;
111
+ return { trueFlightMin, doorToDoorMin };
112
+ }
113
+ // v1 legacy 字节不变:不校验正负,沿用原公式。
114
+ const trueFlightMin = (svc.arrMin - svc.depMin) - (mv.tzOffsetMin ?? 0);
115
+ const doorToDoorMin = mv.bufferMin + mv.originTransferMin + trueFlightMin + mv.destTransferMin;
116
+ return { trueFlightMin, doorToDoorMin };
117
+ }
85
118
  export function evaluateChoice(cand, req, ch) {
119
+ /** 门到门全成本核算(与 Python evaluate_choice 完全一致)。 */
86
120
  const access = req.homeHubAccess[cand.hub];
121
+ const outTransferMin = typeof ch.outTransfer.minutesOut === 'number'
122
+ ? ch.outTransfer.minutesOut
123
+ : ch.outTransfer.minutes;
124
+ const retTransferMin = typeof ch.retTransfer.minutesRet === 'number'
125
+ ? ch.retTransfer.minutesRet
126
+ : ch.retTransfer.minutes;
87
127
  const wake = ch.outService.depMin - cand.bufferOutMin - access.toHubMin;
88
- const arriveStay = ch.outService.arrMin + ch.outTransfer.minutes;
128
+ const arriveStay = ch.outService.arrMin + outTransferMin;
89
129
  const d2dOut = arriveStay - wake;
90
130
  let energy = 100;
91
- if (wake < 5 * 60) energy -= WAKE_PENALTY_BEFORE_5;
92
- else if (wake < 6 * 60) energy -= WAKE_PENALTY_BEFORE_6;
93
- else if (wake < hhmmToMin('06:30')) energy -= WAKE_PENALTY_BEFORE_630;
131
+ if (wake < 5 * 60)
132
+ energy -= WAKE_PENALTY_BEFORE_5;
133
+ else if (wake < 6 * 60)
134
+ energy -= WAKE_PENALTY_BEFORE_6;
135
+ else if (wake < hhmmToMin('06:30'))
136
+ energy -= WAKE_PENALTY_BEFORE_630;
94
137
  energy -= 2 * TRANSFER_PENALTY;
95
- if (arriveStay > 21 * 60) energy -= LATE_ARRIVAL_PENALTY;
96
- if (d2dOut > 6 * 60) energy -= LONG_D2D_PENALTY;
138
+ if (arriveStay > 21 * 60)
139
+ energy -= LATE_ARRIVAL_PENALTY;
140
+ if (d2dOut > 6 * 60)
141
+ energy -= LONG_D2D_PENALTY;
97
142
  energy = Math.max(0, energy);
98
143
  const day1Raw = Math.max(0, DAY_END_MIN - arriveStay) / 60;
99
144
  const day1 = day1Raw * (0.5 + energy / 200);
100
- const leaveStayRet = ch.retService.depMin - cand.bufferRetMin - ch.retTransfer.minutes;
145
+ const leaveStayRet = ch.retService.depMin - cand.bufferRetMin - retTransferMin;
101
146
  const day2 = Math.max(0, leaveStayRet - DAY2_START_MIN) / 60 * DAY2_QUALITY;
102
147
  const midDays = Math.max(0, ch.days - 2);
103
148
  const usable = day1 + day2 + midDays * 8.0 * DAY2_QUALITY;
104
- const money = ch.outService.priceCny + ch.retService.priceCny + ch.outTransfer.priceCny + ch.retTransfer.priceCny + cand.stayCnyPerNight * (ch.days - 1) + cand.localDailyCny * ch.days;
149
+ const money = ch.outService.priceCny + ch.retService.priceCny
150
+ + ch.outTransfer.priceCny + ch.retTransfer.priceCny
151
+ + cand.stayCnyPerNight * (ch.days - 1)
152
+ + cand.localDailyCny * ch.days;
105
153
  return {
106
154
  moneyCny: money,
107
155
  wakeMin: wake,
@@ -112,7 +160,7 @@ export function evaluateChoice(cand, req, ch) {
112
160
  usableDay1Hours: day1,
113
161
  usableDay2Hours: day2,
114
162
  departHomeRetMin: leaveStayRet,
115
- arriveHomeRetMin: ch.retService.arrMin + access.toHubMin
163
+ arriveHomeRetMin: ch.retService.arrMin + access.toHubMin,
116
164
  };
117
165
  }
118
166
  export function trueCostToDict(t) {
@@ -126,9 +174,6 @@ export function trueCostToDict(t) {
126
174
  usable_day1_hours: Math.round(t.usableDay1Hours * 10) / 10,
127
175
  usable_day2_hours: Math.round(t.usableDay2Hours * 10) / 10,
128
176
  leave_stay_return: minToHhmm(t.departHomeRetMin),
129
- arrive_home_return: minToHhmm(Math.min(1440, t.arriveHomeRetMin))
177
+ arrive_home_return: minToHhmm(Math.min(1440, t.arriveHomeRetMin)),
130
178
  };
131
179
  }
132
-
133
-
134
- //# sourceURL=ts/src/model.ts
@@ -1,51 +1,52 @@
1
+ /**
2
+ * 实时票价 overlay(README Known limitation「机票实时数据」清偿件):
3
+ * 静态包(data/flights_2026.json)仍是兜底,不再是唯一票价源——dated 航班链 spec
4
+ * (段带 date + route 词表内城市对)可经 FlyAI 官方只读通道(gotry_flyai_search 同源
5
+ * `capabilities/flyai.ts`)取实时价,按航班号精确匹配覆写 spec 价格后进求解,
6
+ * 证据链 `[实时API:flyai@ts]` 随行(data-sources §6)。
7
+ *
8
+ * 三值语义(永不抛错,与 hbcli/weather/opensky/anything 同构,L4 不变量):
9
+ * - hit 且价正 → 覆写 + 记 evidence(静态原价留档对账);
10
+ * - miss/error/打码价(如 "1xxx",非正数)/无匹配 → 段原样保留(静态价即降级);
11
+ * - 查询实现注入(测试离线确定性);默认关,`GOTRY_REALTIME_PRICING=1` 开启产品面。
12
+ */
1
13
  import { interpretEffect } from '../capabilities/effect.js';
14
+ /** FlyAI CLI 收中文城市名;route 提示是 IATA 码(spec 层骨架词表,与 skeleton-check 同源) */
2
15
  const IATA_TO_CITY = {
3
- HKG: '香港',
4
- HKT: '普吉',
5
- BKK: '曼谷',
6
- KMG: '昆明',
7
- SZX: '深圳',
8
- DXB: '迪拜',
9
- LJG: '丽江',
10
- DLU: '大理',
11
- SHA: '上海',
12
- PVG: '上海',
13
- PEK: '北京',
14
- CTU: '成都'
16
+ HKG: '香港', HKT: '普吉', BKK: '曼谷', KMG: '昆明', SZX: '深圳', DXB: '迪拜',
17
+ LJG: '丽江', DLU: '大理', SHA: '上海', PVG: '上海', PEK: '北京', CTU: '成都',
15
18
  };
19
+ /**
20
+ * dated 航班链 spec 的实时票价覆写:
21
+ * - 只碰 `date`(YYYY-MM-DD)且 route 落在词表内的段;火车段(无 route 词表)原样;
22
+ * - 段内 option 按 service id(=航班号,大小写不敏感)与 FlyAI 条目精确匹配;
23
+ * - 任何失败(查询 error/miss、价格非正数、无匹配)→ 该段原样保留,绝不抛错。
24
+ */
16
25
  export async function overlayRealtimeFlightPrices(spec, opts = {}) {
17
- const out = {
18
- spec,
19
- matched: [],
20
- notes: []
21
- };
26
+ const out = { spec, matched: [], notes: [] };
22
27
  const flights = [];
23
- for (const seg of spec.segments){
24
- if (!seg.date || !/^\d{4}-\d{2}-\d{2}$/.test(seg.date)) continue;
28
+ for (const seg of spec.segments) {
29
+ if (!seg.date || !/^\d{4}-\d{2}-\d{2}$/.test(seg.date))
30
+ continue;
25
31
  const route = seg.route;
26
- if (!route || !route.includes('->')) continue;
27
- const [a, b] = route.split('->').map((s)=>IATA_TO_CITY[s.trim()]);
28
- if (!a || !b) continue;
29
- if (seg.options.some((o)=>!o.move)) continue;
30
- flights.push({
31
- seg,
32
- date: seg.date,
33
- origin: a,
34
- destination: b
35
- });
32
+ if (!route || !route.includes('->'))
33
+ continue;
34
+ const [a, b] = route.split('->').map(s => IATA_TO_CITY[s.trim()]);
35
+ if (!a || !b)
36
+ continue;
37
+ if (seg.options.some(o => !o.move))
38
+ continue;
39
+ flights.push({ seg, date: seg.date, origin: a, destination: b });
36
40
  }
37
- if (flights.length === 0) return out;
41
+ if (flights.length === 0)
42
+ return out;
38
43
  const query = opts.query ?? defaultQuery;
39
- for (const f of flights){
44
+ for (const f of flights) {
40
45
  let result;
41
46
  try {
42
- result = await query({
43
- kind: 'flight',
44
- origin: f.origin,
45
- destination: f.destination,
46
- depDate: f.date
47
- });
48
- } catch (e) {
47
+ result = await query({ kind: 'flight', origin: f.origin, destination: f.destination, depDate: f.date });
48
+ }
49
+ catch (e) {
49
50
  out.notes.push(`${f.seg.id}: 实时票价不可用(降级静态包):${e.message?.slice(0, 80)} [实时API:flyai@error]`);
50
51
  continue;
51
52
  }
@@ -55,58 +56,48 @@ export async function overlayRealtimeFlightPrices(spec, opts = {}) {
55
56
  }
56
57
  const ts = /@(\d{4}-\d{2}-\d{2}T[\d:.]+Z)\]/.exec(result.evidence)?.[1] ?? new Date().toISOString();
57
58
  const byNo = new Map();
58
- for (const o of result.options){
59
- if (Number.isFinite(o.price) && o.price > 0) byNo.set(o.no.toUpperCase(), o);
59
+ for (const o of result.options) {
60
+ if (Number.isFinite(o.price) && o.price > 0)
61
+ byNo.set(o.no.toUpperCase(), o);
60
62
  }
61
- for (const opt of f.seg.options){
63
+ for (const opt of f.seg.options) {
62
64
  const svc = opt.move.services[0];
63
65
  const rt = byNo.get(svc.id.toUpperCase());
64
- if (!rt) continue;
66
+ if (!rt)
67
+ continue;
65
68
  const evidence = `[实时API:flyai@${ts}] ${rt.no} ¥${rt.price}(静态包原价 ¥${svc.priceCny})`;
66
- out.matched.push({
67
- segment: f.seg.id,
68
- option: opt.id,
69
- staticCny: svc.priceCny,
70
- realtimeCny: rt.price,
71
- evidence
72
- });
69
+ out.matched.push({ segment: f.seg.id, option: opt.id, staticCny: svc.priceCny, realtimeCny: rt.price, evidence });
73
70
  out.notes.push(evidence);
74
71
  svc.priceCny = rt.price;
75
72
  }
76
73
  }
77
74
  return out;
78
75
  }
79
- const defaultQuery = async (q)=>{
80
- const itp = await interpretEffect({
81
- effect: 'FLYAI_SEARCH',
82
- params: {
83
- kind: q.kind,
84
- origin: q.origin,
85
- destination: q.destination,
86
- depDate: q.depDate
87
- }
88
- });
89
- if (!itp.result) throw new Error(itp.trace.evidence.join(';'));
76
+ /** 默认查询面走效应解译器(ADR-18):多段行程连查享有退避重试/断路器保护——
77
+ * 断路拒绝(上游连环失败)时抛错,一并落在「实时票价不可用(降级静态包)」既有兜底里 */
78
+ const defaultQuery = async (q) => {
79
+ const itp = await interpretEffect({ effect: 'FLYAI_SEARCH', params: { kind: q.kind, origin: q.origin, destination: q.destination, depDate: q.depDate } });
80
+ if (!itp.result)
81
+ throw new Error(itp.trace.evidence.join(';'));
90
82
  return itp.result;
91
83
  };
84
+ /** 求解端口包装(产品接缝):`GOTRY_REALTIME_PRICING=1`(或 opts.enabled)时 dated 航班链段
85
+ * 先经 FlyAI 实时价覆写,证据行并进结果 skeleton_notes;关闸/零覆写零改动,永不抛错。 */
92
86
  export function realtimeSolvePort(base, opts = {}) {
93
- return async (spec)=>{
87
+ return async (spec) => {
94
88
  const enabled = opts.enabled ?? process.env['GOTRY_REALTIME_PRICING'] === '1';
95
- if (!enabled) return base(spec);
89
+ if (!enabled)
90
+ return base(spec);
96
91
  try {
97
92
  const ov = await overlayRealtimeFlightPrices(spec, opts);
98
- if (ov.matched.length === 0 && ov.notes.length === 0) return base(ov.spec);
93
+ if (ov.matched.length === 0 && ov.notes.length === 0)
94
+ return base(ov.spec);
99
95
  const res = await base(ov.spec);
100
- res.skeleton_notes = [
101
- ...res.skeleton_notes ?? [],
102
- ...ov.notes
103
- ];
96
+ res.skeleton_notes = [...(res.skeleton_notes ?? []), ...ov.notes];
104
97
  return res;
105
- } catch {
106
- return base(spec);
98
+ }
99
+ catch {
100
+ return base(spec); // 覆写层任何异常 → 纯静态包原路求解
107
101
  }
108
102
  };
109
103
  }
110
-
111
-
112
- //# sourceURL=ts/src/realtime-pricing.ts