@danceiny/gotry 0.0.1-rc.9 → 0.2.0-rc.27

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 (507) hide show
  1. package/README.md +172 -219
  2. package/README.zh-CN.md +222 -0
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-booking-copilot.js +53 -0
  5. package/bin/gotry-bootstrap.js +1744 -0
  6. package/bin/gotry-inner.js +733 -83
  7. package/bin/gotry-process-liveness.d.ts +27 -0
  8. package/bin/gotry-process-liveness.js +97 -0
  9. package/bin/gotry-runtime-resolution.d.ts +27 -0
  10. package/bin/gotry-runtime-resolution.js +49 -0
  11. package/bin/gotry.js +1 -1
  12. package/client/client.js +203 -0
  13. package/cordis.gotry-patch.yml +80 -56
  14. package/data/airline-airports.json +39 -0
  15. package/data/stations-12306-verify.json +524 -0
  16. package/dist/capabilities/agent-reach-deep.js +45 -122
  17. package/dist/capabilities/agent-reach.js +101 -146
  18. package/dist/capabilities/anything.js +135 -94
  19. package/dist/capabilities/artifacts.js +370 -0
  20. package/dist/capabilities/channel-health.js +131 -0
  21. package/dist/capabilities/channel-registry.js +256 -0
  22. package/dist/capabilities/doctor.js +546 -0
  23. package/dist/capabilities/effect.js +394 -0
  24. package/dist/capabilities/external-event.js +149 -0
  25. package/dist/capabilities/fact-log.js +55 -0
  26. package/dist/capabilities/flyai-config.js +337 -0
  27. package/dist/capabilities/flyai.js +947 -110
  28. package/dist/capabilities/fx-contract.js +293 -0
  29. package/dist/capabilities/geo-atlas.js +246 -0
  30. package/dist/capabilities/ground-transfer.js +509 -0
  31. package/dist/capabilities/hbcli.js +260 -123
  32. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  33. package/dist/capabilities/incident-log.js +131 -61
  34. package/dist/capabilities/itinerary-artifact.js +190 -0
  35. package/dist/capabilities/itinerary-deck-artifact.js +194 -0
  36. package/dist/capabilities/itinerary-deck-export.js +339 -0
  37. package/dist/capabilities/lavish-local.js +924 -0
  38. package/dist/capabilities/model-override.js +38 -0
  39. package/dist/capabilities/opensky.js +54 -43
  40. package/dist/capabilities/resilience.js +191 -0
  41. package/dist/capabilities/session/action-cache.js +50 -44
  42. package/dist/capabilities/session/adapters/ctrip-flight.js +120 -62
  43. package/dist/capabilities/session/adapters/ctrip-hotel.js +222 -0
  44. package/dist/capabilities/session/adapters/dida-portal.js +274 -0
  45. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  46. package/dist/capabilities/session/adapters/rail-12306.js +342 -0
  47. package/dist/capabilities/session/benchmark.js +189 -0
  48. package/dist/capabilities/session/bridge-ledger.js +224 -0
  49. package/dist/capabilities/session/extension-bridge.js +636 -0
  50. package/dist/capabilities/session/extension-channel.js +109 -0
  51. package/dist/capabilities/session/extension-distribution.js +230 -0
  52. package/dist/capabilities/session/extract.js +31 -21
  53. package/dist/capabilities/session/golden-score.js +114 -0
  54. package/dist/capabilities/session/health-watch.js +215 -0
  55. package/dist/capabilities/session/read-guard.js +75 -24
  56. package/dist/capabilities/session/static-flight-golden.js +150 -0
  57. package/dist/capabilities/session/transport.js +97 -83
  58. package/dist/capabilities/session/wizard.js +117 -0
  59. package/dist/capabilities/session-consent.js +178 -0
  60. package/dist/capabilities/session-login.js +170 -0
  61. package/dist/capabilities/session-search.js +635 -44
  62. package/dist/capabilities/spawn-bounded.js +203 -0
  63. package/dist/capabilities/sponsor-plugin.js +341 -0
  64. package/dist/capabilities/visa-policy.js +140 -0
  65. package/dist/capabilities/weather.js +243 -138
  66. package/dist/data/session-golden-20.json +25 -0
  67. package/dist/data/sf-golden-manifest.json +103 -0
  68. package/dist/data/sf-static-routes.json +91 -0
  69. package/dist/scripts/action-cache-tests.js +24 -59
  70. package/dist/scripts/agent-planning-turn-deadline-e2e.js +242 -0
  71. package/dist/scripts/agent-planning-turn-deadline-tests.js +185 -0
  72. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  73. package/dist/scripts/agent-reach-error-tests.js +354 -0
  74. package/dist/scripts/agent-reach-tests.js +26 -18
  75. package/dist/scripts/agent-reach-wrapper-tests.js +50 -50
  76. package/dist/scripts/anything-tests.js +116 -60
  77. package/dist/scripts/artifact-client-contract-tests.js +220 -0
  78. package/dist/scripts/artifacts-capability-tests.js +727 -0
  79. package/dist/scripts/async-collect.js +50 -11
  80. package/dist/scripts/benchmark-environment-bridge-e2e.js +741 -0
  81. package/dist/scripts/benchmark-environment-bridge-tests.js +1452 -0
  82. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +126 -0
  83. package/dist/scripts/booking-copilot-availability-policy-tests.js +265 -0
  84. package/dist/scripts/booking-copilot-bin-proof-tests.js +66 -0
  85. package/dist/scripts/booking-copilot-cleanup-proof-helper.js +76 -0
  86. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +144 -0
  87. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +424 -0
  88. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +2839 -0
  89. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +309 -0
  90. package/dist/scripts/booking-copilot-dsh-readiness-proof.js +238 -0
  91. package/dist/scripts/booking-copilot-dsh-warmer-proof.js +123 -0
  92. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +156 -0
  93. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +70 -0
  94. package/dist/scripts/booking-copilot-intent-proof-tests.js +422 -0
  95. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +184 -0
  96. package/dist/scripts/booking-copilot-planner-live-probe.js +95 -0
  97. package/dist/scripts/booking-copilot-proof-runtime.js +42 -0
  98. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +210 -0
  99. package/dist/scripts/booking-copilot-runtime-proof-tests.js +2349 -0
  100. package/dist/scripts/booking-copilot-server-proof-tests.js +784 -0
  101. package/dist/scripts/booking-copilot-startup-proof-tests.js +94 -0
  102. package/dist/scripts/booking-executor-tests.js +80 -0
  103. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  104. package/dist/scripts/booking-saga-tests.js +125 -0
  105. package/dist/scripts/booking-surface-contract-proof-tests.js +212 -0
  106. package/dist/scripts/bootstrap-tests.js +1479 -0
  107. package/dist/scripts/bridge-events-tests.js +239 -0
  108. package/dist/scripts/bridge-ledger-tests.js +428 -0
  109. package/dist/scripts/build-changelog.js +238 -0
  110. package/dist/scripts/build-metrics-report.js +331 -0
  111. package/dist/scripts/changelog-tests.js +118 -0
  112. package/dist/scripts/channel-probe-tests.js +103 -0
  113. package/dist/scripts/channel-probe.js +169 -0
  114. package/dist/scripts/channel-registry-tests.js +208 -0
  115. package/dist/scripts/companion-tests.js +25 -70
  116. package/dist/scripts/dida-cookie-probe.js +87 -0
  117. package/dist/scripts/dida-runner-stop-tests.js +311 -0
  118. package/dist/scripts/dida-sw-probe.js +114 -0
  119. package/dist/scripts/diff-test.js +17 -12
  120. package/dist/scripts/doctor-tests.js +564 -0
  121. package/dist/scripts/dsh-artifact-e2e.js +279 -0
  122. package/dist/scripts/dsh-artifact-web-e2e.js +675 -0
  123. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  124. package/dist/scripts/dsh-runtime-closure-tests.js +182 -0
  125. package/dist/scripts/dsh-runtime-closure.js +162 -0
  126. package/dist/scripts/dsh-session-v3-migration-proof.js +109 -0
  127. package/dist/scripts/dsh-subprocess-local-proof.js +150 -0
  128. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  129. package/dist/scripts/effect-tests.js +539 -0
  130. package/dist/scripts/engine-run.js +1 -3
  131. package/dist/scripts/engine-tests.js +16 -10
  132. package/dist/scripts/evaluation-cadence-tests.js +174 -0
  133. package/dist/scripts/evaluation-contract-tests.js +268 -0
  134. package/dist/scripts/extension-distribution-cli.js +39 -0
  135. package/dist/scripts/extension-distribution-tests.js +443 -0
  136. package/dist/scripts/extension-tests.js +988 -0
  137. package/dist/scripts/external-event-tests.js +350 -0
  138. package/dist/scripts/fact-gate-tests.js +869 -0
  139. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  140. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  141. package/dist/scripts/flight-malformed-tests.js +159 -0
  142. package/dist/scripts/flyai-setup-tests.js +228 -0
  143. package/dist/scripts/flyai-setup-tool-tests.js +54 -0
  144. package/dist/scripts/flyai-tests.js +692 -0
  145. package/dist/scripts/flyai-tool-registration-contract-tests.js +91 -0
  146. package/dist/scripts/fx-contract-tests.js +201 -0
  147. package/dist/scripts/g5-guard-tests.js +131 -0
  148. package/dist/scripts/g5-guard.js +189 -0
  149. package/dist/scripts/gen-lunar-anchors.js +106 -0
  150. package/dist/scripts/geo-atlas-tests.js +283 -0
  151. package/dist/scripts/gotry-backend-kernel-tests.js +206 -0
  152. package/dist/scripts/gotry-try-demo-tests.js +79 -0
  153. package/dist/scripts/gotry-try-demo.js +49 -0
  154. package/dist/scripts/ground-transfer-tests.js +956 -0
  155. package/dist/scripts/hbcli-e2e-tests.js +159 -0
  156. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  157. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  158. package/dist/scripts/hbcli-tests.js +121 -69
  159. package/dist/scripts/health-watch-cli.js +73 -0
  160. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  161. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  162. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  163. package/dist/scripts/i18n-tests.js +41 -0
  164. package/dist/scripts/incident-tests.js +281 -87
  165. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  166. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  167. package/dist/scripts/issue-271-liveness-tests.js +569 -0
  168. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  169. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  170. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  171. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  172. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  173. package/dist/scripts/issue436-persisted-routing-e2e.js +247 -0
  174. package/dist/scripts/itinerary-artifact-tests.js +368 -0
  175. package/dist/scripts/itinerary-deck-artifact-tests.js +416 -0
  176. package/dist/scripts/itinerary-deck-export-tests.js +552 -0
  177. package/dist/scripts/itinerary-deck-tests.js +435 -0
  178. package/dist/scripts/itinerary-html-tests.js +426 -0
  179. package/dist/scripts/journey-tests.js +22 -27
  180. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  181. package/dist/scripts/kernel-manifest-gate.js +126 -0
  182. package/dist/scripts/kernel-manifest-tests.js +212 -0
  183. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  184. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  185. package/dist/scripts/kernel-manifest.js +369 -0
  186. package/dist/scripts/lavish-local-tests.js +1226 -0
  187. package/dist/scripts/lavish-product-tools-tests.js +537 -0
  188. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  189. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  190. package/dist/scripts/ledger-tests.js +382 -246
  191. package/dist/scripts/ledger-workflow-crash.js +10 -20
  192. package/dist/scripts/managed-dsh-cleanup-diagnostic-proof.js +184 -0
  193. package/dist/scripts/managed-dsh-close-failure-proof.js +172 -0
  194. package/dist/scripts/managed-dsh-run-port-proof.js +153 -0
  195. package/dist/scripts/managed-dsh-terminal-proof.js +252 -0
  196. package/dist/scripts/map-tools-vendor-package-proof.js +365 -0
  197. package/dist/scripts/memory-capture-tests.js +242 -61
  198. package/dist/scripts/memory-decay-tests.js +18 -52
  199. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  200. package/dist/scripts/memory-lifecycle.js +196 -0
  201. package/dist/scripts/memory-metrics.js +24 -12
  202. package/dist/scripts/memory-value-report.js +631 -0
  203. package/dist/scripts/memory-value-tests.js +328 -0
  204. package/dist/scripts/metrics-report-tests.js +151 -0
  205. package/dist/scripts/model-override-e2e.js +137 -0
  206. package/dist/scripts/nightly-evidence-tests.js +161 -0
  207. package/dist/scripts/nightly-evidence.js +286 -0
  208. package/dist/scripts/nudge-digest.js +39 -28
  209. package/dist/scripts/observability-tests.js +381 -0
  210. package/dist/scripts/onboarding-tests.js +161 -0
  211. package/dist/scripts/opensky-check.js +18 -13
  212. package/dist/scripts/opensky-tests.js +28 -28
  213. package/dist/scripts/persona-surface-guard-tests.js +49 -0
  214. package/dist/scripts/pnpm-dsh-closure-proof.js +17 -0
  215. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  216. package/dist/scripts/price-drift-tests.js +340 -0
  217. package/dist/scripts/price-drift-watch.js +447 -0
  218. package/dist/scripts/probe-poi-tests.js +53 -45
  219. package/dist/scripts/product-metrics.js +483 -0
  220. package/dist/scripts/publish-preverify.js +110 -0
  221. package/dist/scripts/realtime-pricing-tests.js +76 -0
  222. package/dist/scripts/recall-tests.js +513 -0
  223. package/dist/scripts/replay-async.js +20 -18
  224. package/dist/scripts/replay-real.js +18 -18
  225. package/dist/scripts/replay.js +52 -82
  226. package/dist/scripts/session-attach-diagnose.js +20 -20
  227. package/dist/scripts/session-attach-poc.js +34 -37
  228. package/dist/scripts/session-benchmark.js +180 -0
  229. package/dist/scripts/session-dida-live-e2e.js +199 -0
  230. package/dist/scripts/session-extract-tests.js +14 -35
  231. package/dist/scripts/session-link-tests.js +478 -0
  232. package/dist/scripts/session-login.js +27 -46
  233. package/dist/scripts/session-tests.js +796 -96
  234. package/dist/scripts/session-zones-tests.js +358 -0
  235. package/dist/scripts/sf-live-benchmark.js +367 -0
  236. package/dist/scripts/sf-live-challenge-stop-tests.js +453 -0
  237. package/dist/scripts/sf-live-cli-tests.js +92 -0
  238. package/dist/scripts/sf-live-options.js +46 -0
  239. package/dist/scripts/sf-manifest-tests.js +30 -0
  240. package/dist/scripts/sf-manifest.js +33 -0
  241. package/dist/scripts/sf-soft-score-tests.js +67 -0
  242. package/dist/scripts/sf-summary-tests.js +324 -0
  243. package/dist/scripts/sf-summary.js +525 -0
  244. package/dist/scripts/share-tests.js +432 -0
  245. package/dist/scripts/skeleton-check.js +16 -14
  246. package/dist/scripts/skeleton-integration-test.js +28 -11
  247. package/dist/scripts/skills-contract-tests.js +51 -46
  248. package/dist/scripts/smoke-session-gate-tests.js +21 -0
  249. package/dist/scripts/smoke.js +690 -246
  250. package/dist/scripts/spawn-bounded-abort-tests.js +241 -0
  251. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  252. package/dist/scripts/state-cli-tests.js +226 -101
  253. package/dist/scripts/state-cli.js +550 -199
  254. package/dist/scripts/state-repair-cli.js +66 -0
  255. package/dist/scripts/state-repair-tests.js +140 -0
  256. package/dist/scripts/static-golden-tests.js +165 -0
  257. package/dist/scripts/time-eval-tests.js +210 -192
  258. package/dist/scripts/travel-timeline-tests.js +29 -93
  259. package/dist/scripts/turn-handoff-collect-tests.js +169 -0
  260. package/dist/scripts/turn-handoff-collect.js +161 -0
  261. package/dist/scripts/turn-policy-tests.js +55 -0
  262. package/dist/scripts/typed-contract-canary.js +176 -0
  263. package/dist/scripts/tz-resolver-sanity.js +50 -0
  264. package/dist/scripts/tz-resolver-tests.js +584 -0
  265. package/dist/scripts/unified-tests.js +23 -19
  266. package/dist/scripts/visa-policy-tests.js +62 -0
  267. package/dist/scripts/weather-tests.js +276 -41
  268. package/dist/scripts/wish-channel-gate-tests.js +54 -0
  269. package/dist/scripts/write-gate-tests.js +522 -0
  270. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  271. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  272. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  273. package/dist/scripts/z3-race-tests.js +41 -0
  274. package/dist/src/artifact-gate.js +829 -0
  275. package/dist/src/backend/kernel.js +91 -0
  276. package/dist/src/backend/modules/booking-copilot.js +92 -0
  277. package/dist/src/backend/modules/booking-executor.js +124 -0
  278. package/dist/src/backend/modules/session-search.js +551 -0
  279. package/dist/src/benchmark-agent-conformance.js +578 -0
  280. package/dist/src/benchmark-environment-bridge.js +515 -0
  281. package/dist/src/benchmark-headless-child-diagnostics.js +166 -0
  282. package/dist/src/benchmark-tool-isolation.js +151 -0
  283. package/dist/src/bookable-facts.js +533 -0
  284. package/dist/src/booking-saga.js +97 -0
  285. package/dist/src/booking-surface/availability-policy.js +697 -0
  286. package/dist/src/booking-surface/booking-intent.js +43 -0
  287. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  288. package/dist/src/booking-surface/canonical-schema.js +116 -0
  289. package/dist/src/booking-surface/contracts.js +75 -0
  290. package/dist/src/booking-surface/dsh-planner.js +1854 -0
  291. package/dist/src/booking-surface/dsh-plugin.js +378 -0
  292. package/dist/src/booking-surface/dsh-worker.js +98 -0
  293. package/dist/src/booking-surface/error-codes.js +231 -0
  294. package/dist/src/booking-surface/index.js +9 -0
  295. package/dist/src/booking-surface/managed-dsh-cleanup-diagnostic.js +97 -0
  296. package/dist/src/booking-surface/managed-dsh-run-port.js +244 -0
  297. package/dist/src/booking-surface/profile.js +24 -0
  298. package/dist/src/booking-surface/recovery-chain.js +367 -0
  299. package/dist/src/booking-surface/runtime.js +1968 -0
  300. package/dist/src/booking-surface/server.js +674 -0
  301. package/dist/src/booking-surface/startup.js +168 -0
  302. package/dist/src/booking-surface/validation.js +261 -0
  303. package/dist/src/bridge.js +20 -13
  304. package/dist/src/companions.js +48 -74
  305. package/dist/src/contracts.js +21 -43
  306. package/dist/src/dsh-llm.js +97 -111
  307. package/dist/src/engine.js +276 -193
  308. package/dist/src/evaluation-cadence.js +97 -0
  309. package/dist/src/evaluation-contracts.js +283 -0
  310. package/dist/src/flight-pack-adapter.js +54 -0
  311. package/dist/src/flight-pack-contract.js +2 -0
  312. package/dist/src/flyai-setup-tool.js +70 -0
  313. package/dist/src/gotry-backend.js +125 -0
  314. package/dist/src/hotel-date-gate.js +118 -0
  315. package/dist/src/i18n.js +88 -0
  316. package/dist/src/index.js +2227 -882
  317. package/dist/src/itinerary-deck.js +139 -0
  318. package/dist/src/itinerary-doc-shared.js +661 -0
  319. package/dist/src/itinerary-html.js +131 -0
  320. package/dist/src/journey.js +155 -108
  321. package/dist/src/lavish-tools.js +400 -0
  322. package/dist/src/ledger-repair-apply.js +538 -0
  323. package/dist/src/ledger-repair-plan.js +463 -0
  324. package/dist/src/loop.js +319 -160
  325. package/dist/src/memory-capture.js +180 -32
  326. package/dist/src/memory-decay.js +30 -14
  327. package/dist/src/memory-lifecycle.js +1310 -0
  328. package/dist/src/memory-utility.js +27 -40
  329. package/dist/src/mock-llm.js +36 -61
  330. package/dist/src/model.js +81 -36
  331. package/dist/src/realtime-pricing.js +103 -0
  332. package/dist/src/recall/card.js +74 -0
  333. package/dist/src/recall/evaluator.js +140 -0
  334. package/dist/src/recall/integration.js +17 -0
  335. package/dist/src/recall/tick.js +166 -0
  336. package/dist/src/session-link/plan-it-action.js +48 -0
  337. package/dist/src/session-link/session-link.js +248 -0
  338. package/dist/src/session-zones.js +507 -0
  339. package/dist/src/share/adapters.js +51 -0
  340. package/dist/src/share/share-consent.js +76 -0
  341. package/dist/src/share/share-deck.js +58 -0
  342. package/dist/src/share/share-token.js +146 -0
  343. package/dist/src/slot-spec.js +84 -106
  344. package/dist/src/state-ledger.js +435 -516
  345. package/dist/src/state-repair.js +299 -0
  346. package/dist/src/subagent-job-id-guard.js +58 -0
  347. package/dist/src/time-anchor.js +231 -33
  348. package/dist/src/tool-packet.js +20 -8
  349. package/dist/src/travel-slots.js +58 -35
  350. package/dist/src/travel-timeline.js +44 -63
  351. package/dist/src/turn-deadline.js +287 -0
  352. package/dist/src/turn-policy.js +118 -0
  353. package/dist/src/tz-resolver.js +143 -0
  354. package/dist/src/unified.js +535 -359
  355. package/dist/src/wish-pool.js +42 -12
  356. package/dist/src/write-gate.js +495 -0
  357. package/dist/src/z3-shared.js +284 -0
  358. package/extension/README.md +21 -0
  359. package/extension/README.zh-CN.md +21 -0
  360. package/extension/background.js +463 -0
  361. package/extension/content-bridge.js +270 -0
  362. package/extension/content-main.js +111 -0
  363. package/extension/manifest.json +60 -0
  364. package/package.json +407 -14
  365. package/schemas/booking.intent.schema.json +193 -0
  366. package/schemas/booking.surface.schema.json +2622 -0
  367. package/ts/capabilities/agent-reach-deep.ts +114 -0
  368. package/ts/capabilities/agent-reach.ts +198 -0
  369. package/ts/capabilities/anything.ts +255 -0
  370. package/ts/capabilities/artifacts.ts +428 -0
  371. package/ts/capabilities/fact-log.ts +54 -0
  372. package/ts/capabilities/flyai-config.ts +388 -0
  373. package/ts/capabilities/flyai.ts +1274 -0
  374. package/ts/capabilities/hbcli.ts +253 -71
  375. package/ts/capabilities/incident-log.ts +88 -59
  376. package/ts/capabilities/itinerary-artifact.ts +214 -0
  377. package/ts/capabilities/itinerary-deck-artifact.ts +218 -0
  378. package/ts/capabilities/itinerary-deck-export.ts +378 -0
  379. package/ts/capabilities/opensky.ts +121 -0
  380. package/ts/capabilities/session/action-cache.ts +148 -0
  381. package/ts/capabilities/session/adapters/ctrip-flight.ts +181 -0
  382. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  383. package/ts/capabilities/session/adapters/dida-portal.ts +338 -0
  384. package/ts/capabilities/session/adapters/meituan-local.ts +70 -0
  385. package/ts/capabilities/session/adapters/rail-12306.ts +392 -0
  386. package/ts/capabilities/session/benchmark.ts +276 -0
  387. package/ts/capabilities/session/bridge-ledger.ts +333 -0
  388. package/ts/capabilities/session/extension-bridge.ts +794 -0
  389. package/ts/capabilities/session/extension-channel.ts +144 -0
  390. package/ts/capabilities/session/extension-distribution.ts +266 -0
  391. package/ts/capabilities/session/extract.ts +54 -0
  392. package/ts/capabilities/session/golden-score.ts +139 -0
  393. package/ts/capabilities/session/health-watch.ts +264 -0
  394. package/ts/capabilities/session/read-guard.ts +141 -0
  395. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  396. package/ts/capabilities/session/transport.ts +146 -0
  397. package/ts/capabilities/session/wizard.ts +140 -0
  398. package/ts/capabilities/session-consent.ts +211 -0
  399. package/ts/capabilities/session-login.ts +208 -0
  400. package/ts/capabilities/session-search.ts +893 -0
  401. package/ts/capabilities/weather.ts +330 -0
  402. package/ts/dsh-runtime/vendor/README.md +68 -0
  403. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  404. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +405 -0
  405. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +404 -0
  406. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +1584 -0
  407. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  408. package/ts/dsh-runtime/vendor/dsh-map-tools/icon.svg +5 -0
  409. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +595 -0
  410. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  411. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +58 -0
  412. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  413. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  414. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +131 -0
  415. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  416. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/geo.js +232 -0
  417. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +120 -0
  418. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +40 -0
  419. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/staticmap-route.js +115 -0
  420. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  421. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  422. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +267 -0
  423. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +90 -0
  424. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  425. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  426. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  427. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  428. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +23 -0
  429. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  430. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/geo.d.ts +61 -0
  431. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  432. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  433. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/staticmap-route.d.ts +31 -0
  434. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  435. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  436. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +75 -0
  437. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +68 -0
  438. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  439. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +97 -0
  440. package/ts/package.json +293 -3
  441. package/ts/scripts/async-collect.ts +91 -0
  442. package/ts/scripts/map-tools-vendor-package-proof.ts +404 -0
  443. package/ts/scripts/skeleton-check.ts +1 -1
  444. package/ts/scripts/skeleton-integration-test.ts +23 -1
  445. package/ts/scripts/state-cli.ts +568 -0
  446. package/ts/scripts/turn-handoff-collect.ts +178 -0
  447. package/ts/src/artifact-gate.ts +991 -0
  448. package/ts/src/benchmark-agent-conformance.ts +619 -0
  449. package/ts/src/benchmark-environment-bridge.ts +538 -0
  450. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  451. package/ts/src/benchmark-tool-isolation.ts +166 -0
  452. package/ts/src/bookable-facts.ts +837 -0
  453. package/ts/src/booking-saga.ts +133 -0
  454. package/ts/src/booking-surface/availability-policy.ts +522 -0
  455. package/ts/src/booking-surface/booking-intent.ts +86 -0
  456. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  457. package/ts/src/booking-surface/canonical-schema.js +116 -0
  458. package/ts/src/booking-surface/contracts.ts +475 -0
  459. package/ts/src/booking-surface/dsh-planner.ts +1949 -0
  460. package/ts/src/booking-surface/dsh-plugin.js +378 -0
  461. package/ts/src/booking-surface/dsh-worker.ts +110 -0
  462. package/ts/src/booking-surface/error-codes.ts +241 -0
  463. package/ts/src/booking-surface/index.ts +9 -0
  464. package/ts/src/booking-surface/managed-dsh-cleanup-diagnostic.ts +151 -0
  465. package/ts/src/booking-surface/managed-dsh-run-port.ts +273 -0
  466. package/ts/src/booking-surface/profile.ts +42 -0
  467. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  468. package/ts/src/booking-surface/runtime.ts +1793 -0
  469. package/ts/src/booking-surface/server.ts +733 -0
  470. package/ts/src/booking-surface/startup.ts +201 -0
  471. package/ts/src/booking-surface/validation.ts +217 -0
  472. package/ts/src/companions.ts +113 -0
  473. package/ts/src/contracts.ts +13 -3
  474. package/ts/src/dsh-llm.ts +44 -11
  475. package/ts/src/flyai-setup-tool.ts +77 -0
  476. package/ts/src/index.ts +1948 -198
  477. package/ts/src/itinerary-deck.ts +189 -0
  478. package/ts/src/itinerary-doc-shared.ts +741 -0
  479. package/ts/src/itinerary-html.ts +171 -0
  480. package/ts/src/loop.ts +223 -25
  481. package/ts/src/memory-capture.ts +283 -0
  482. package/ts/src/memory-decay.ts +55 -0
  483. package/ts/src/memory-utility.ts +70 -0
  484. package/ts/src/mock-llm.ts +4 -8
  485. package/ts/src/model.ts +88 -2
  486. package/ts/src/recall/card.ts +106 -0
  487. package/ts/src/recall/evaluator.ts +170 -0
  488. package/ts/src/recall/integration.ts +35 -0
  489. package/ts/src/recall/tick.ts +213 -0
  490. package/ts/src/session-link/plan-it-action.ts +78 -0
  491. package/ts/src/session-link/session-link.ts +275 -0
  492. package/ts/src/share/adapters.ts +93 -0
  493. package/ts/src/share/share-consent.ts +105 -0
  494. package/ts/src/share/share-deck.ts +85 -0
  495. package/ts/src/share/share-token.ts +166 -0
  496. package/ts/src/slot-spec.ts +172 -0
  497. package/ts/src/state-ledger.ts +912 -0
  498. package/ts/src/subagent-job-id-guard.ts +72 -0
  499. package/ts/src/time-anchor.ts +338 -0
  500. package/ts/src/tool-packet.ts +32 -0
  501. package/ts/src/travel-slots.ts +219 -0
  502. package/ts/src/travel-timeline.ts +83 -0
  503. package/ts/src/turn-deadline.ts +366 -0
  504. package/ts/src/turn-policy.ts +154 -0
  505. package/ts/src/unified.ts +354 -88
  506. package/ts/src/wish-pool.ts +79 -0
  507. package/dist/scripts/session-attach-wait.js +0 -41
package/dist/src/loop.js CHANGED
@@ -1,15 +1,21 @@
1
+ /**
2
+ * Stage 1 对话循环(S2 段1,docs/design/stage1-top-down-design.md §2.3)。
3
+ *
4
+ * 自顶向下:循环只依赖两个端口——LlmPort(mock/真)与确定性工具(interview_next)。
5
+ * 求解/渲染接线是 S2 后续段;本段验收:重放用户开场白,系统一轮内完成
6
+ * 日历断言 + 访谈补全启动(问出工作窗口与已订资源——Kimi 第 6 轮才问的事)。
7
+ */
8
+ import { buildTimeAnchor, isRealIsoDate, planningWindowBounds, parsePlanningWindow } from './time-anchor.js';
1
9
  import { anythingSearch } from '../capabilities/anything.js';
2
10
  export function newState(year = 2026) {
3
11
  return {
4
- calendar: {
5
- year,
6
- assertedWeekdays: {}
7
- },
12
+ calendar: { year, assertedWeekdays: {} },
8
13
  profile: {},
9
14
  gates: [],
10
- wishes: []
15
+ wishes: [],
11
16
  };
12
17
  }
18
+ /** ADR-9:访谈由缺失字段驱动(确定性,无 LLM 即兴) */
13
19
  export function interviewNext(state) {
14
20
  const p = state.profile;
15
21
  const questions = [];
@@ -18,14 +24,14 @@ export function interviewNext(state) {
18
24
  questions.push({
19
25
  key: 'workWindow',
20
26
  text: '你这两周要远程办公——工作时间是几点到几点、按哪个时区?这决定每天的可玩时段。',
21
- why: '工作窗口直接决定每日节奏(普吉 13:00-22:00 与 9:00-18:00 是两种人生)'
27
+ why: '工作窗口直接决定每日节奏(普吉 13:00-22:00 与 9:00-18:00 是两种人生)',
22
28
  });
23
29
  }
24
30
  if (!p.bookedResources) {
25
31
  questions.push({
26
32
  key: 'bookedResources',
27
33
  text: '已经有订好的航班或酒店吗?(哪怕只是意向)——已订资源是硬锚点,先告诉我再规划。',
28
- why: '已订资源决定哪些段不可动,Kimi 式规划会绕开它们重排'
34
+ why: '已订资源决定哪些段不可动,Kimi 式规划会绕开它们重排',
29
35
  });
30
36
  }
31
37
  if (!p.budgetTier) {
@@ -34,35 +40,28 @@ export function interviewNext(state) {
34
40
  text: '预算档位:经济(¥12.6k 级)/ 舒适(¥16.3k 级)/ 便利优先?',
35
41
  why: '分层预算决定班次与住宿的选型口径',
36
42
  options: [
37
- {
38
- label: '经济',
39
- tradeOff: '省钱,接驳多走路'
40
- },
41
- {
42
- label: '舒适',
43
- tradeOff: 'workation 办公质量优先'
44
- },
45
- {
46
- label: '便利优先',
47
- tradeOff: '时间最省'
48
- }
49
- ]
43
+ { label: '经济', tradeOff: '省钱,接驳多走路' },
44
+ { label: '舒适', tradeOff: 'workation 办公质量优先' },
45
+ { label: '便利优先', tradeOff: '时间最省' },
46
+ ],
50
47
  });
51
48
  }
52
- return {
53
- questions,
54
- missing: questions.map((q)=>q.key)
55
- };
49
+ return { questions, missing: questions.map(q => q.key) };
56
50
  }
51
+ /** spec 校验闸:LLM 翻译产物进求解器前的确定性形状检查(责任边界的执行点)。 */
57
52
  export function validateSpec(spec) {
58
- if (!Array.isArray(spec.segments) || spec.segments.length === 0) return '没有段(segments)';
59
- for (const seg of spec.segments){
60
- if (!seg.id) return '存在缺少 id 的段';
61
- if (!Array.isArray(seg.options) || seg.options.length === 0) return `段 ${seg.id} 没有可选方案`;
62
- for (const opt of seg.options){
53
+ if (!Array.isArray(spec.segments) || spec.segments.length === 0)
54
+ return '没有段(segments)';
55
+ for (const seg of spec.segments) {
56
+ if (!seg.id)
57
+ return '存在缺少 id 的段';
58
+ if (!Array.isArray(seg.options) || seg.options.length === 0)
59
+ return `段 ${seg.id} 没有可选方案`;
60
+ for (const opt of seg.options) {
63
61
  const svcs = opt.move?.services;
64
- if (!Array.isArray(svcs) || svcs.length === 0) return `段 ${seg.id} 的方案 ${opt.id} 缺少班次(services)`;
65
- for (const s of svcs){
62
+ if (!Array.isArray(svcs) || svcs.length === 0)
63
+ return `段 ${seg.id} 的方案 ${opt.id} 缺少班次(services)`;
64
+ for (const s of svcs) {
66
65
  if (typeof s.depMin !== 'number' || typeof s.arrMin !== 'number') {
67
66
  return `段 ${seg.id}/${opt.id} 的班次 ${s.id ?? '?'} 缺少时刻(depMin/arrMin)`;
68
67
  }
@@ -71,7 +70,108 @@ export function validateSpec(spec) {
71
70
  }
72
71
  return null;
73
72
  }
73
+ function isoDateInBounds(date, bounds) {
74
+ const m = date.match(/^(\d{4})-(\d{2})-(\d{2})$/);
75
+ if (!m || !isRealIsoDate(Number(m[1]), Number(m[2]), Number(m[3])))
76
+ return false;
77
+ return date >= bounds.start && date <= bounds.end;
78
+ }
79
+ function hasDatedCandidates(spec) {
80
+ return spec.segments.some(segment => segment.date !== undefined || segment.options.some(option => option.date !== undefined));
81
+ }
82
+ /**
83
+ * Enforce a named-year future window at the planner boundary. Historical
84
+ * lookup/backtesting remains an explicit bypass; an expired named year fails
85
+ * instead of being silently rolled into a different year.
86
+ */
87
+ export function applyPlanningWindow(spec, window, anchor, options = {}) {
88
+ // Dated recommendations are future-oriented even without optional named-year context.
89
+ // Fully dateless legacy calculations remain untouched; historical bypass is explicit.
90
+ if (window?.intent === 'historical')
91
+ return { spec, rejected: [] };
92
+ const implicitFutureFloor = !window && options.defaultDatedFuture === true && hasDatedCandidates(spec);
93
+ if (!window && !implicitFutureFloor)
94
+ return { spec, rejected: [] };
95
+ const currentYear = Number(anchor.today.slice(0, 4));
96
+ if (window && window.requestedYear < currentYear) {
97
+ return {
98
+ spec,
99
+ rejected: [],
100
+ error: `${window.requestedYear} 年已结束(当前规划参考日 ${anchor.today}),不会自动改用其他年份;如需历史查询请明确说明“历史/回测”。`,
101
+ };
102
+ }
103
+ const bounds = window
104
+ ? planningWindowBounds(window, anchor)
105
+ : { start: anchor.today, end: '9999-12-31' };
106
+ if (!bounds)
107
+ return { spec, rejected: [], error: `无法建立 ${window.requestedYear} 年的未来规划窗口。` };
108
+ const rejected = [];
109
+ const guardedSegments = spec.segments.map(segment => ({
110
+ ...segment,
111
+ options: segment.options.filter(option => {
112
+ const date = option.date ?? segment.date;
113
+ if (date && isoDateInBounds(date, bounds))
114
+ return true;
115
+ rejected.push({ segmentId: segment.id, optionId: option.id, date: date ?? '未提供明确日期' });
116
+ return false;
117
+ }),
118
+ }));
119
+ if (guardedSegments.some(segment => segment.options.length === 0)) {
120
+ return {
121
+ spec: { ...spec, segments: guardedSegments },
122
+ rejected,
123
+ error: implicitFutureFloor
124
+ ? `带日期的未来推荐必须不早于当前规划参考日 ${bounds.start};没有带明确日期且在未来窗口内的可接受方案。`
125
+ : `${window.requestedYear} 年未来规划窗口为 ${bounds.start} 至 ${bounds.end};没有带明确日期且落在窗口内的可接受方案。`,
126
+ };
127
+ }
128
+ return { spec: { ...spec, segments: guardedSegments }, rejected };
129
+ }
130
+ function latestPlanningWindow(history, userMsg, anchor) {
131
+ const turns = [...history, { role: 'user', text: userMsg }];
132
+ for (let i = turns.length - 1; i >= 0; i--) {
133
+ const turn = turns[i];
134
+ if (turn?.role !== 'user')
135
+ continue;
136
+ const parsed = parsePlanningWindow(turn.text, anchor);
137
+ if (parsed)
138
+ return parsed;
139
+ }
140
+ return null;
141
+ }
142
+ export const ASYNC_TERMINAL_SCHEMA = 'gotry_async_terminal.v1';
143
+ function asyncTerminalOutcome(ticketId, checks) {
144
+ const failedChecks = Object.entries(checks).filter(([, passed]) => !passed).map(([name]) => name);
145
+ return {
146
+ schema: ASYNC_TERMINAL_SCHEMA,
147
+ ticket_id: ticketId,
148
+ status: failedChecks.length === 0 ? 'succeeded' : 'failed',
149
+ passed: Object.values(checks).filter(Boolean).length,
150
+ total: 4,
151
+ checks,
152
+ failed_checks: failedChecks,
153
+ };
154
+ }
155
+ function terminalOutcomeFromState(ticketId, state) {
156
+ if (!state.spec || !state.solve) {
157
+ return asyncTerminalOutcome(ticketId, {
158
+ '1_承诺时间后必有明确产物': false,
159
+ '2_产物通过自检清单': false,
160
+ '3_待决问题全部是简单选择题': false,
161
+ '4_做不到的诚实说': false,
162
+ });
163
+ }
164
+ return asyncTerminalOutcome(ticketId, {
165
+ '1_承诺时间后必有明确产物': Boolean(state.solve.legs?.length || state.solve.verdicts?.length),
166
+ '2_产物通过自检清单': state.solve.feasible
167
+ ? (state.solve.legs?.every(l => l['energy_pct'] !== undefined) ?? false)
168
+ : Boolean(state.solve.unsat_core?.length),
169
+ '3_待决问题全部是简单选择题': state.gates.every(g => g.id === 'budget' || g.options.length >= 2),
170
+ '4_做不到的诚实说': state.solve.feasible || Boolean(state.solve.suggestions?.length),
171
+ });
172
+ }
74
173
  export function isComplex(state) {
174
+ /** 复杂度判据(架构占位,后续可细化):多段或多约束即深规划 */
75
175
  const p = state.profile;
76
176
  return Boolean(p.workWindow && p.bookedResources) && (state.gates.length > 0 || Boolean(state.spec));
77
177
  }
@@ -80,135 +180,149 @@ export async function requestDeepPlanning(state) {
80
180
  id: `dp-${Date.now().toString(36)}`,
81
181
  objective: '生成已验证的行程方案:全成本核算 + 动机/约束匹配 + 不失望四条',
82
182
  requestedAt: new Date().toISOString(),
83
- etaLabel: '约 1 小时(mock 期:秒级)'
84
- };
85
- state.gates.push({
86
- id: `async-${ticket.id}`,
87
- question: `深度规划已启动(${ticket.etaLabel})`,
88
- options: []
89
- });
90
- const reply = '这趟行程跨度大(两周 workation + 三城 + 红眼返程),我切到**深度规划模式**:后台做多轮校验' + '(锚点/工作窗口/全成本/负例排查),做好后通知你。**先留一道选择题给你**,回来直接定:' + '\n1. 预算档位?(经济/舒适/便利优先)';
91
- return {
92
- reply,
93
- ticket
183
+ etaLabel: '约 1 小时(mock 期:秒级)',
94
184
  };
185
+ state.gates.push({ id: `async-${ticket.id}`, question: `深度规划已启动(${ticket.etaLabel})`, options: [] });
186
+ const reply = '这趟行程跨度大(两周 workation + 三城 + 红眼返程),我切到**深度规划模式**:后台做多轮校验'
187
+ + '(锚点/工作窗口/全成本/负例排查),做好后通知你。**先留一道选择题给你**,回来直接定:'
188
+ + '\n1. 预算档位?(经济/舒适/便利优先)';
189
+ return { reply, ticket };
95
190
  }
96
191
  export async function collectDeepPlanning(state, ticket, solve) {
97
192
  const spec = state.spec;
98
- if (!spec) return {
99
- reply: '(内部状态缺失 spec——深度规划未就绪,这是不应发生的路径)',
100
- state
101
- };
193
+ if (!spec) {
194
+ const outcome = terminalOutcomeFromState(ticket.id, state);
195
+ return { reply: '(内部状态缺失 spec——深度规划未就绪,这是不应发生的路径)', state, outcome };
196
+ }
102
197
  state.solve = await solve(spec);
103
- state.gates = state.gates.filter((g)=>!g.id.startsWith('async-'));
104
- const checks = {
105
- '1_承诺时间后必有明确产物': Boolean(state.solve.legs?.length || state.solve.verdicts?.length),
106
- '2_产物通过自检清单': state.solve.feasible ? state.solve.legs?.every((l)=>l['energy_pct'] !== undefined) ?? false : Boolean(state.solve.unsat_core?.length),
107
- '3_待决问题全部是简单选择题': state.gates.every((g)=>g.id === 'budget' || g.options.length >= 2),
108
- '4_做不到的诚实说': state.solve.feasible || Boolean(state.solve.suggestions?.length)
109
- };
110
- const head = `# 回访交付:${ticket.objective}\n(工单 ${ticket.id},不失望四条:${Object.values(checks).every(Boolean) ? '4/4 ✅' : '有未达项 ❌'})`;
111
- return {
112
- reply: `${head}\n\n${renderSolve(state)}`,
113
- state
114
- };
198
+ state.gates = state.gates.filter(g => !g.id.startsWith('async-'));
199
+ // 不失望四条自检(交付物自带,总纲 3.6)
200
+ const outcome = terminalOutcomeFromState(ticket.id, state);
201
+ const head = `# 回访交付:${ticket.objective}\n(工单 ${ticket.id},不失望四条:${outcome.status === 'succeeded' ? '4/4 ✅' : '有未达项 ❌'})`;
202
+ return { reply: `${head}\n\n${renderSolve(state)}`, state, outcome };
115
203
  }
204
+ /** 求解结果 → 人话(模板;S4 可由 LLM 润色,数字与判定不可改) */
116
205
  export function renderSolve(state) {
117
206
  const s = state.solve;
118
- if (!s) return '(无求解结果)';
207
+ if (!s)
208
+ return '(无求解结果)';
119
209
  const lines = [];
120
210
  if (s.feasible) {
121
211
  lines.push(`**方案可行,机票合计 ¥${s.money_cny}**`);
122
- for (const lg of s.legs ?? []){
123
- const l = lg;
124
- lines.push(`- ${l['leg']} ${l['service']}:${l['dep']} 起飞,${l['wake']} 出发,${l['arrive_stay']} 到,` + `门到门 ${l['door_to_door']},落地精力 ${l['energy_pct']}%,¥${l['price_cny']}`);
212
+ // §7-1 issue #559 卡点 4:从 s.skeleton_notes 字符串编码里推断 unscaffolded 的 seg.id,
213
+ // 不动 unified.ts/journey.ts(内核冻结面 #234),用户面给 ⚠ 前缀与「枢纽对未在骨架覆盖」补充。
214
+ // skeleton_notes 单条形态:`<seg.id>: [骨架:openflights] ❌ ...` 或 `<seg.id>: [骨架:openflights] ✅ ...`
215
+ const unscaffoldedSegIds = new Set();
216
+ for (const n of s.skeleton_notes ?? []) {
217
+ const m = /^([^:]+):\s*\[骨架:openflights\]\s*❌/.exec(n);
218
+ if (m)
219
+ unscaffoldedSegIds.add(m[1]);
125
220
  }
126
- for (const e of s.work_window_exclusions ?? []){
127
- lines.push(`- 已排除 ${e.option}(工作窗口):${e.reason}`);
221
+ for (const lg of s.legs ?? []) {
222
+ const l = lg;
223
+ const unscaffoldedFlag = unscaffoldedSegIds.has(String(l['leg'])) ? '⚠ ' : '';
224
+ const unscaffoldedNote = unscaffoldedSegIds.has(String(l['leg'])) ? '(枢纽对未在骨架覆盖,实时源以新航线为准)' : '';
225
+ lines.push(`- ${unscaffoldedFlag}${l['leg']} ${l['service']}:${l['dep']} 起飞,${l['wake']} 出发,${l['arrive_stay']} 到,`
226
+ + `门到门 ${l['door_to_door']},落地精力 ${l['energy_pct']}%,¥${l['price_cny']}${unscaffoldedNote ? ` ${unscaffoldedNote}` : ''}`);
128
227
  }
129
- for (const n of s.skeleton_notes ?? [])lines.push(`- ${n}`);
130
- for (const f of s.red_flags ?? [])lines.push(`- ⚠️ ${f}`);
131
- } else {
228
+ for (const n of s.skeleton_notes ?? [])
229
+ lines.push(`- ${n}`);
230
+ for (const f of s.red_flags ?? [])
231
+ lines.push(`- ⚠️ ${f}`);
232
+ }
233
+ else {
132
234
  lines.push(`**当前约束下不可行——冲突:${(s.unsat_core ?? []).join('、')}`);
133
- for (const sg of s.suggestions ?? [])lines.push(`- 放宽「${sg.relax}」可解(约 ¥${sg.money_cny})`);
235
+ for (const sg of s.suggestions ?? [])
236
+ lines.push(`- 放宽「${sg.relax}」可解(约 ¥${sg.money_cny})`);
237
+ }
238
+ for (const e of s.work_window_exclusions ?? []) {
239
+ lines.push(`- 已排除 ${e.option}(工作窗口):${e.reason}`);
134
240
  }
135
241
  if (state.gates.length) {
136
242
  lines.push('', '**待你决定(选择题)**');
137
- for (const g of state.gates){
138
- lines.push(`- ${g.question} → ${g.options.map((o)=>o.label + (o.tradeOff ? `(${o.tradeOff})` : '')).join(' / ')}`);
243
+ for (const g of state.gates) {
244
+ lines.push(`- ${g.question} → ${g.options.map(o => o.label + (o.tradeOff ? `(${o.tradeOff})` : '')).join(' / ')}`);
139
245
  }
140
246
  }
141
247
  return lines.join('\n');
142
248
  }
143
- export async function runTurn(state, userMsg, llm, history = [], solve = null) {
144
- const facts = await llm.extractFacts([
145
- ...history,
146
- {
147
- role: 'user',
148
- text: userMsg
149
- }
150
- ], state);
249
+ /** 一次对话回合:抽取事实(冲突即指出)→ 增量访谈 → 约束齐备则求解+渲染。 */
250
+ export async function runTurn(state, userMsg, llm, history = [], solve = null, now = new Date()) {
251
+ const anchor = buildTimeAnchor(now);
252
+ const facts = await llm.extractFacts([...history, { role: 'user', text: userMsg }], state);
151
253
  const conflicts = [];
152
254
  if (facts.calendar?.assertedWeekdays) {
153
- for (const [date, wd] of Object.entries(facts.calendar.assertedWeekdays)){
255
+ for (const [date, wd] of Object.entries(facts.calendar.assertedWeekdays)) {
154
256
  const prev = state.calendar.assertedWeekdays[date];
155
257
  if (prev && prev !== wd) {
156
258
  conflicts.push(`${date}:已有断言 ${prev},新说法 ${wd}——以先断言为准,如需改请明确说`);
157
- } else {
259
+ }
260
+ else {
158
261
  state.calendar.assertedWeekdays[date] = wd;
159
262
  }
160
263
  }
161
264
  }
162
265
  Object.assign(state.profile, facts.profile ?? {});
266
+ // 访谈:workWindow/bookedResources 是求解前置;budgetTier 转为 gate(不阻塞规划)
163
267
  const { questions } = interviewNext(state);
164
- const blocking = questions.filter((q)=>q.key !== 'budgetTier');
165
- const budgetQ = questions.find((q)=>q.key === 'budgetTier');
166
- if (budgetQ && !state.gates.some((g)=>g.id === 'budget')) {
268
+ const blocking = questions.filter(q => q.key !== 'budgetTier');
269
+ const budgetQ = questions.find(q => q.key === 'budgetTier');
270
+ if (budgetQ && !state.gates.some(g => g.id === 'budget')) {
167
271
  state.gates.push({
168
272
  id: 'budget',
169
273
  question: budgetQ.text,
170
- options: budgetQ.options ?? [
171
- {
172
- label: '经济'
173
- },
174
- {
175
- label: '舒适'
176
- },
177
- {
178
- label: '便利优先'
179
- }
180
- ]
274
+ options: budgetQ.options ?? [{ label: '经济' }, { label: '舒适' }, { label: '便利优先' }],
181
275
  });
182
276
  }
183
277
  const parts = [];
184
- if (conflicts.length) parts.push(`⚠️ 日历冲突:\n${conflicts.map((c)=>`- ${c}`).join('\n')}`);
278
+ if (conflicts.length)
279
+ parts.push(`⚠️ 日历冲突:\n${conflicts.map(c => `- ${c}`).join('\n')}`);
280
+ // D-7a 例外: blocking>0 时,用户消息含"查+地名/酒店/天气"信号时,直接调 anything_search
281
+ // 走 PoI 真相(datasources 层主动调,不动 polling 状态机,不改求解器)
185
282
  const poiProbe = probePoi(userMsg);
186
283
  if (poiProbe) {
187
- const ar = await anythingSearch({
188
- keyword: poiProbe
189
- });
284
+ const ar = await anythingSearch({ keyword: poiProbe });
190
285
  if (ar.verdict === 'hit' && ar.hits && ar.hits.length > 0) {
191
286
  const top = ar.hits.slice(0, 5);
192
- const lines = top.map((h, i)=>{
193
- const latlng = h.latitude !== undefined && h.longitude !== undefined ? ` @ (${h.latitude.toFixed(3)},${h.longitude.toFixed(3)})` : '';
287
+ const lines = top.map((h, i) => {
288
+ const latlng = h.latitude !== undefined && h.longitude !== undefined
289
+ ? ` @ (${h.latitude.toFixed(3)},${h.longitude.toFixed(3)})`
290
+ : '';
194
291
  return ` ${i + 1}. [${h.type}] ${h.name}${latlng}`;
195
292
  }).join('\n');
196
293
  parts.push(`**${poiProbe} → hit (${ar.hits.length} 候选项)**\n${lines}\n${ar.evidence}`);
197
- } else if (ar.verdict === 'miss') {
294
+ }
295
+ else if (ar.verdict === 'miss') {
198
296
  parts.push(`**${poiProbe} → miss** (酒店-be Anything 一切正常但无候选)\n${ar.evidence}`);
199
- } else {
200
- parts.push(`**${poiProbe} → unavailable** (${ar.error ?? 'hbcli 不可达'})\n${ar.evidence}`);
297
+ }
298
+ else {
299
+ // 用户面只给人话原因 + 来源 tag:evidence 里的上游原话是溯源契约(能力层测试锁),
300
+ // 其中的进程噪音(如 `(exit null)`)不该渲染进回复。
301
+ const sourceTag = ar.evidence.match(/^\[[^\]]+\]/)?.[0];
302
+ parts.push(`**${poiProbe} → 实时查询不可用**(${ar.error ?? 'hbcli 不可达'})——这条不阻塞本轮规划,只影响实时数据源,其余结论照常带来源标注${sourceTag ? `\n${sourceTag}` : ''}`);
201
303
  }
202
304
  }
203
- for (const q of blocking)parts.push(await llm.polishQuestion(q));
305
+ for (const q of blocking)
306
+ parts.push(await llm.polishQuestion(q));
307
+ // 约束齐备(无阻塞问题)→ 翻译 spec → **校验闸 + 日期一致性闸** → 求解 → 渲染
204
308
  if (blocking.length === 0 && solve) {
205
- const spec = await llm.extractSpec([
206
- ...history,
207
- {
208
- role: 'user',
209
- text: userMsg
210
- }
211
- ], state);
309
+ const extractedSpec = await llm.extractSpec([...history, { role: 'user', text: userMsg }], state);
310
+ const planning = latestPlanningWindow(history, userMsg, anchor);
311
+ const planningCheck = extractedSpec ? applyPlanningWindow(extractedSpec, planning, anchor) : null;
312
+ if (planningCheck?.error) {
313
+ state.spec = undefined;
314
+ state.solve = undefined;
315
+ parts.push(`⚠️ ${planningCheck.error}`);
316
+ return { reply: parts.join('\n\n'), state };
317
+ }
318
+ if (planningCheck?.rejected.length) {
319
+ const rejected = planningCheck.rejected
320
+ .map(r => `${r.segmentId}/${r.optionId}(${r.date})`)
321
+ .join('、');
322
+ parts.push(`已排除规划窗口外的候选:${rejected}`);
323
+ }
324
+ const spec = planningCheck?.spec ?? extractedSpec;
325
+ // 场景路由:erhai 候选标记 → 候选求解(洱海金标准的引擎判定)——纯 TS unify 路径
212
326
  if (spec && spec.note === 'erhai-candidates') {
213
327
  const { readFile } = await import('node:fs/promises');
214
328
  const { join } = await import('node:path');
@@ -222,56 +336,52 @@ export async function runTurn(state, userMsg, llm, history = [], solve = null) {
222
336
  const result = solveChoiceSegment(erhaiSpec, req);
223
337
  state.solve = result;
224
338
  parts.push(result.answer_md ?? '(候选求解完成)');
225
- } catch {
339
+ }
340
+ catch {
226
341
  parts.push('(洱海候选求解暂不可用——退回访谈)');
227
342
  }
228
- } else {
343
+ }
344
+ else {
229
345
  const invalid = spec ? validateSpec(spec) : '翻译器未产出 spec';
230
346
  if (spec && !invalid) {
231
- const ext = await llm.extractSlots([
232
- ...history,
233
- {
234
- role: 'user',
235
- text: userMsg
236
- }
237
- ]);
347
+ // D-10 切片 C:spec↔槽位日期一致性闸(ADR-10 翻译≠造数的执行点)。
348
+ // LLM 翻译的 spec 日期与代码层换算的槽位日期分歧时不求解、不猜,追问确认——
349
+ // 日期是求解关键输入,错日期 = 错判决。槽位缺失/unresolved 不参与(不造假阳性)。
350
+ const ext = await llm.extractSlots([...history, { role: 'user', text: userMsg }], now);
238
351
  if (ext) {
239
352
  const { resolveSlots, specDateMismatches } = await import('./slot-spec.js');
240
- const { buildTimeAnchor } = await import('./time-anchor.js');
241
- const mismatches = specDateMismatches(spec, resolveSlots(ext, buildTimeAnchor()));
353
+ const mismatches = specDateMismatches(spec, resolveSlots(ext, anchor));
242
354
  if (mismatches.length > 0) {
243
- const lines = mismatches.map((m)=>`- ${m.specAt}:翻译说 ${m.specDate},你的原话换算是 ${m.slotDate}(${m.field})`);
355
+ const lines = mismatches.map(m => `- ${m.specAt}:翻译说 ${m.specDate},你的原话换算是 ${m.slotDate}(${m.field})`);
244
356
  parts.push(`⚠️ 日期分歧,确认后我再算(以你为准):\n${lines.join('\n')}`);
245
- return {
246
- reply: parts.join('\n\n'),
247
- state
248
- };
357
+ return { reply: parts.join('\n\n'), state };
249
358
  }
250
359
  }
251
360
  state.spec = spec;
252
361
  state.solve = await solve(spec);
253
362
  parts.push(llm.render ? await llm.render(state) : renderSolve(state));
254
- } else if (blocking.length === 0 && invalid) {
363
+ }
364
+ else if (blocking.length === 0 && invalid) {
255
365
  parts.push(`(行程骨架还不完整:${invalid}——请补充对应信息,我不猜)`);
256
366
  }
257
367
  }
258
- } else if (blocking.length === 0) {
368
+ }
369
+ else if (blocking.length === 0) {
259
370
  parts.push('(约束齐备——进入规划,S3 接线后此处产出方案与选择题)');
260
371
  }
261
- return {
262
- reply: parts.join('\n\n'),
263
- state
264
- };
372
+ return { reply: parts.join('\n\n'), state };
265
373
  }
374
+ // ---- 异步工单持久化(S5 编排半段 → ADR-15 durable 工单):真正的「一小时后」必须跨进程存续 ----
375
+ // 权威 = 账本 workflow_runs/workflow_steps(单事务;崩溃后 done 步骤不重执行);
376
+ // {id}.json / {id}.deliverable.md 降级为视图(AGENTS.md 清扫合同 + 人工检视),
377
+ // tmp+rename 原子写——此前裸 writeFile 的非原子缺口(RFC §1.1)就此关闭。
266
378
  import { join } from 'node:path';
267
379
  import { mkdir, rename, writeFile, readFile } from 'node:fs/promises';
268
380
  import { ensureLedger, openLedgerIfExists } from './state-ledger.js';
269
381
  async function asyncDir(stateRoot) {
270
382
  const root = stateRoot === '.' ? process.cwd() : stateRoot;
271
383
  const dir = join(root, 'gotry-state', 'async');
272
- await mkdir(dir, {
273
- recursive: true
274
- });
384
+ await mkdir(dir, { recursive: true });
275
385
  return dir;
276
386
  }
277
387
  async function atomicWrite(path, text) {
@@ -281,45 +391,73 @@ async function atomicWrite(path, text) {
281
391
  }
282
392
  export async function persistAsyncTicket(ticket, state, stateRoot = '.') {
283
393
  const ledger = ensureLedger(stateRoot);
284
- ledger.createWorkflowRun({
285
- id: ticket.id,
286
- goal: ticket.objective,
287
- ticket,
288
- state
289
- });
394
+ ledger.createWorkflowRun({ id: ticket.id, goal: ticket.objective, ticket, state });
290
395
  const dir = await asyncDir(stateRoot);
291
396
  const p = join(dir, `${ticket.id}.json`);
292
- await atomicWrite(p, JSON.stringify({
293
- ticket,
294
- state
295
- }, null, 2));
397
+ await atomicWrite(p, JSON.stringify({ ticket, state }, null, 2));
296
398
  return p;
297
399
  }
298
400
  export async function loadAsyncTicket(ticketId, stateRoot = '.') {
401
+ // 账本优先;无账本的 root 回退旧 json 文件(只读,兼容存量已交付工单)
299
402
  const ledger = openLedgerIfExists(stateRoot);
300
403
  const run = ledger?.getWorkflowRun(ticketId);
301
404
  if (run) {
302
405
  return {
303
406
  ticket: JSON.parse(run.ticket_json),
304
- state: JSON.parse(run.state_json)
407
+ state: JSON.parse(run.state_json),
305
408
  };
306
409
  }
307
410
  try {
308
411
  const p = join(await asyncDir(stateRoot), `${ticketId}.json`);
309
412
  return JSON.parse(await readFile(p, 'utf-8'));
310
- } catch {
413
+ }
414
+ catch {
311
415
  return null;
312
416
  }
313
417
  }
314
- export async function settleAsyncTicket(ticketId, reply, stateRoot = '.') {
315
- openLedgerIfExists(stateRoot)?.settleWorkflowRun(ticketId, reply);
418
+ export async function settleAsyncTicket(ticketId, reply, stateRoot = '.', outcome) {
419
+ const ledger = openLedgerIfExists(stateRoot);
420
+ const terminalOutcome = outcome ?? recoverAsyncTerminalOutcome(ledger, ticketId);
421
+ if (ledger && !terminalOutcome) {
422
+ throw new Error(`workflow ${ticketId} 缺少可恢复的 ${ASYNC_TERMINAL_SCHEMA},拒绝误结算`);
423
+ }
424
+ if (terminalOutcome?.status === 'failed')
425
+ ledger?.failWorkflowRun(ticketId, reply, terminalOutcome);
426
+ else
427
+ ledger?.settleWorkflowRun(ticketId, reply, terminalOutcome);
316
428
  const dir = await asyncDir(stateRoot);
317
429
  const p = join(dir, `${ticketId}.deliverable.md`);
318
430
  await atomicWrite(p, reply);
319
431
  return p;
320
432
  }
433
+ function recoverAsyncTerminalOutcome(ledger, ticketId) {
434
+ if (!ledger)
435
+ return undefined;
436
+ const run = ledger.getWorkflowRun(ticketId);
437
+ if (!run)
438
+ return undefined;
439
+ try {
440
+ const state = JSON.parse(run.state_json);
441
+ if (!state.spec)
442
+ return terminalOutcomeFromState(ticketId, state);
443
+ const solveStep = ledger.getWorkflowStep(ticketId, 'solve');
444
+ if (solveStep?.status !== 'done' || !solveStep.result)
445
+ return undefined;
446
+ state.solve = JSON.parse(solveStep.result);
447
+ state.gates = state.gates.filter(g => !g.id.startsWith('async-'));
448
+ return terminalOutcomeFromState(ticketId, state);
449
+ }
450
+ catch {
451
+ return undefined;
452
+ }
453
+ }
454
+ /**
455
+ * 可日志化 solve 端口(ADR-15 步骤日志,intent-before-execute):
456
+ * 先记 intent 再执行,done 后结果落账本——任意进程恢复时 done 的步骤直接复用
457
+ * 结果不重执行(exactly-once:LLM/求解调用不重复花钱),intent 悬挂的重试。
458
+ */
321
459
  export function makeJournaledSolvePort(ledger, runId, solve, opts) {
322
- return async (spec)=>{
460
+ return async (spec) => {
323
461
  const step = ledger.getWorkflowStep(runId, 'solve');
324
462
  if (step?.status === 'done' && step.result) {
325
463
  return JSON.parse(step.result);
@@ -331,30 +469,51 @@ export function makeJournaledSolvePort(ledger, runId, solve, opts) {
331
469
  return r;
332
470
  };
333
471
  }
472
+ /**
473
+ * probePoi:从 user msg 探测"查 POI/酒店" 信号,返回关键词。
474
+ * 触发的不是关键词,是**结构**;关键词抓取有方向性——
475
+ * 1) 显式搜索动词(查/搜/找/看看/推荐/告诉我/检索)+ 宾语在动词后;
476
+ * 2) 住宿名词(酒店/民宿/客栈/饭店):优先取名词**之后**的名称段(须含拉丁/数字,
477
+ * 「我订了酒店:The Title…」→ The Title…);退路是名词前 2-6 字紧邻地名
478
+ * (「大理酒店」→ 大理;「机票和」类垃圾后缀拒);
479
+ * 3) 开放问(有什么/玩什么/有哪些):取名词前的地名;
480
+ * 4) 短裸地名:≤12 字、无标点、无陈述动词(「大理」✓;「明天有空」「我的工作时间是…」✗——
481
+ * 2026-08-28 巡检收紧:旧版 ≤24 直通把访谈答案整句当关键词,垃圾 hbcli 调用+证据噪音)。
482
+ * 不是意图(改求解器),只是 datasources 编排层的"提早调 anything"提示。
483
+ */
484
+ /** 住宿名称段上界:路径 2 已要求含拉丁/数字且被标点截断,旧 24 字会把
485
+ * 「The Title East Wing Rawai」这类真实酒店名截残后回显给用户(2026-09-22)。 */
486
+ const POI_NAME_MAX = 48;
334
487
  export function probePoi(msg) {
335
488
  const trimmed = msg.trim();
336
- if (!trimmed) return null;
337
- const cutAtPunct = (s)=>s.split(/[,,。.;;!!??]/)[0]?.trim() ?? '';
489
+ if (!trimmed)
490
+ return null;
491
+ const cutAtPunct = (s) => s.split(/[,,。.;;!!??]/)[0]?.trim() ?? '';
492
+ // 1) 显式搜索动词 + 宾语
338
493
  const m = trimmed.match(/(查一下|查|搜|找|看看|推荐|告诉我|检索)\s*(.{2,24})/);
339
494
  if (m?.[2]) {
340
495
  const obj = cutAtPunct(m[2]);
341
- if (obj.length >= 2) return obj.slice(0, 24);
496
+ if (obj.length >= 2)
497
+ return obj.slice(0, 24);
342
498
  }
499
+ // 2) 住宿名词:名称段在名词后
343
500
  if (/(酒店|民宿|客栈|饭店)/.test(trimmed)) {
344
501
  const parts = trimmed.split(/(酒店|民宿|客栈|饭店)/);
345
502
  const after = cutAtPunct((parts[2] ?? '').replace(/^[的::\s]+/, ''));
346
- if (after.length >= 2 && /[A-Za-z0-9]/.test(after)) return after.slice(0, 24);
503
+ if (after.length >= 2 && /[A-Za-z0-9]/.test(after))
504
+ return after.length > POI_NAME_MAX ? `${after.slice(0, POI_NAME_MAX - 1)}…` : after;
347
505
  const nounAt = trimmed.search(/(酒店|民宿|客栈|饭店)/);
348
506
  const pre = trimmed.slice(Math.max(0, nounAt - 6), nounAt).match(/[一-龥]{2,6}$/);
349
- if (pre && !/(机票|车票|和|做|订|的)$/.test(pre[0])) return pre[0];
507
+ if (pre && !/(机票|车票|和|做|订|的)$/.test(pre[0]))
508
+ return pre[0];
350
509
  }
510
+ // 3) 开放问:地名在疑问词前
351
511
  const q = trimmed.match(/([一-龥a-zA-Z]{2,12})\s*(?:有什么|玩什么|有哪些)/);
352
- if (q?.[1]) return q[1];
512
+ if (q?.[1])
513
+ return q[1];
514
+ // 4) 短裸地名(≤12 字,无标点,无陈述动词)
353
515
  if (trimmed.length <= 12 && !/[,,。.;;!!??::]/.test(trimmed) && !/[是有在要想得到说订吧呢]/.test(trimmed)) {
354
516
  return trimmed.slice(0, 24);
355
517
  }
356
518
  return null;
357
519
  }
358
-
359
-
360
- //# sourceURL=/Users/bytedance/work/gotry/ts/src/loop.ts