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

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 (533) 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 +1788 -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 +161 -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 +553 -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 +676 -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/provider-detail-sanitize.js +64 -0
  41. package/dist/capabilities/resilience.js +191 -0
  42. package/dist/capabilities/route-provider-conformance.js +341 -0
  43. package/dist/capabilities/session/action-cache.js +50 -44
  44. package/dist/capabilities/session/adapters/ctrip-flight.js +120 -62
  45. package/dist/capabilities/session/adapters/ctrip-hotel.js +222 -0
  46. package/dist/capabilities/session/adapters/dida-portal.js +274 -0
  47. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  48. package/dist/capabilities/session/adapters/rail-12306.js +342 -0
  49. package/dist/capabilities/session/benchmark.js +189 -0
  50. package/dist/capabilities/session/bridge-ledger.js +224 -0
  51. package/dist/capabilities/session/extension-bridge.js +636 -0
  52. package/dist/capabilities/session/extension-channel.js +109 -0
  53. package/dist/capabilities/session/extension-distribution.js +230 -0
  54. package/dist/capabilities/session/extract.js +31 -21
  55. package/dist/capabilities/session/golden-score.js +114 -0
  56. package/dist/capabilities/session/health-watch.js +215 -0
  57. package/dist/capabilities/session/read-guard.js +75 -24
  58. package/dist/capabilities/session/static-flight-golden.js +150 -0
  59. package/dist/capabilities/session/transport.js +97 -83
  60. package/dist/capabilities/session/wizard.js +117 -0
  61. package/dist/capabilities/session-consent.js +178 -0
  62. package/dist/capabilities/session-login.js +170 -0
  63. package/dist/capabilities/session-search.js +635 -44
  64. package/dist/capabilities/spawn-bounded.js +203 -0
  65. package/dist/capabilities/sponsor-plugin.js +341 -0
  66. package/dist/capabilities/visa-policy.js +140 -0
  67. package/dist/capabilities/weather.js +243 -138
  68. package/dist/data/session-golden-20.json +25 -0
  69. package/dist/data/sf-golden-manifest.json +103 -0
  70. package/dist/data/sf-static-routes.json +91 -0
  71. package/dist/scripts/action-cache-tests.js +24 -59
  72. package/dist/scripts/agent-planning-turn-deadline-e2e.js +242 -0
  73. package/dist/scripts/agent-planning-turn-deadline-tests.js +185 -0
  74. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  75. package/dist/scripts/agent-reach-error-tests.js +354 -0
  76. package/dist/scripts/agent-reach-tests.js +26 -18
  77. package/dist/scripts/agent-reach-wrapper-tests.js +50 -50
  78. package/dist/scripts/anything-path-measure-tests.js +133 -0
  79. package/dist/scripts/anything-path-measure.js +150 -0
  80. package/dist/scripts/anything-tests.js +250 -60
  81. package/dist/scripts/artifact-client-contract-tests.js +220 -0
  82. package/dist/scripts/artifacts-capability-tests.js +727 -0
  83. package/dist/scripts/async-collect.js +50 -11
  84. package/dist/scripts/benchmark-environment-bridge-e2e.js +741 -0
  85. package/dist/scripts/benchmark-environment-bridge-tests.js +1452 -0
  86. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +126 -0
  87. package/dist/scripts/booking-copilot-availability-policy-tests.js +265 -0
  88. package/dist/scripts/booking-copilot-bin-proof-tests.js +66 -0
  89. package/dist/scripts/booking-copilot-cleanup-proof-helper.js +76 -0
  90. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +144 -0
  91. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +424 -0
  92. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +2839 -0
  93. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +309 -0
  94. package/dist/scripts/booking-copilot-dsh-readiness-proof.js +238 -0
  95. package/dist/scripts/booking-copilot-dsh-warmer-proof.js +126 -0
  96. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +156 -0
  97. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +70 -0
  98. package/dist/scripts/booking-copilot-intent-proof-tests.js +422 -0
  99. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +184 -0
  100. package/dist/scripts/booking-copilot-planner-live-probe.js +95 -0
  101. package/dist/scripts/booking-copilot-proof-runtime.js +42 -0
  102. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +210 -0
  103. package/dist/scripts/booking-copilot-runtime-proof-tests.js +2349 -0
  104. package/dist/scripts/booking-copilot-server-proof-tests.js +784 -0
  105. package/dist/scripts/booking-copilot-startup-proof-tests.js +94 -0
  106. package/dist/scripts/booking-executor-tests.js +80 -0
  107. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  108. package/dist/scripts/booking-saga-tests.js +125 -0
  109. package/dist/scripts/booking-surface-contract-proof-tests.js +212 -0
  110. package/dist/scripts/bootstrap-tests.js +1549 -0
  111. package/dist/scripts/bridge-events-tests.js +239 -0
  112. package/dist/scripts/bridge-ledger-tests.js +428 -0
  113. package/dist/scripts/build-changelog.js +238 -0
  114. package/dist/scripts/build-metrics-report.js +331 -0
  115. package/dist/scripts/changelog-tests.js +118 -0
  116. package/dist/scripts/channel-probe-tests.js +103 -0
  117. package/dist/scripts/channel-probe.js +169 -0
  118. package/dist/scripts/channel-registry-tests.js +208 -0
  119. package/dist/scripts/city-scenario-tier-tests.js +234 -0
  120. package/dist/scripts/companion-tests.js +25 -70
  121. package/dist/scripts/dida-cookie-probe.js +87 -0
  122. package/dist/scripts/dida-runner-stop-tests.js +311 -0
  123. package/dist/scripts/dida-sw-probe.js +114 -0
  124. package/dist/scripts/diff-test.js +17 -12
  125. package/dist/scripts/doctor-tests.js +600 -0
  126. package/dist/scripts/drill-multiuser-ledger-tests.js +1076 -0
  127. package/dist/scripts/drill-sdk-descendant-cleanup-tests.js +606 -0
  128. package/dist/scripts/drill-w2a-sensor-tests.js +788 -0
  129. package/dist/scripts/dsh-artifact-e2e.js +279 -0
  130. package/dist/scripts/dsh-artifact-web-e2e.js +675 -0
  131. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  132. package/dist/scripts/dsh-llm-tests.js +437 -0
  133. package/dist/scripts/dsh-runtime-closure-tests.js +182 -0
  134. package/dist/scripts/dsh-runtime-closure.js +162 -0
  135. package/dist/scripts/dsh-session-v3-migration-proof.js +109 -0
  136. package/dist/scripts/dsh-subprocess-local-proof.js +150 -0
  137. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  138. package/dist/scripts/effect-tests.js +539 -0
  139. package/dist/scripts/engine-run.js +1 -3
  140. package/dist/scripts/engine-tests.js +16 -10
  141. package/dist/scripts/evaluation-cadence-tests.js +174 -0
  142. package/dist/scripts/evaluation-contract-tests.js +268 -0
  143. package/dist/scripts/extension-distribution-cli.js +39 -0
  144. package/dist/scripts/extension-distribution-tests.js +443 -0
  145. package/dist/scripts/extension-tests.js +988 -0
  146. package/dist/scripts/external-event-tests.js +350 -0
  147. package/dist/scripts/fact-gate-tests.js +869 -0
  148. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  149. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  150. package/dist/scripts/flight-malformed-tests.js +159 -0
  151. package/dist/scripts/flyai-setup-tests.js +228 -0
  152. package/dist/scripts/flyai-setup-tool-tests.js +54 -0
  153. package/dist/scripts/flyai-tests.js +692 -0
  154. package/dist/scripts/flyai-tool-registration-contract-tests.js +91 -0
  155. package/dist/scripts/fx-contract-tests.js +201 -0
  156. package/dist/scripts/g5-guard-tests.js +150 -0
  157. package/dist/scripts/g5-guard.js +193 -0
  158. package/dist/scripts/gen-lunar-anchors.js +106 -0
  159. package/dist/scripts/geo-atlas-tests.js +283 -0
  160. package/dist/scripts/gotry-backend-kernel-tests.js +206 -0
  161. package/dist/scripts/gotry-try-demo-tests.js +79 -0
  162. package/dist/scripts/gotry-try-demo.js +49 -0
  163. package/dist/scripts/ground-transfer-tests.js +956 -0
  164. package/dist/scripts/hbcli-e2e-tests.js +159 -0
  165. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  166. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  167. package/dist/scripts/hbcli-tests.js +121 -69
  168. package/dist/scripts/health-watch-cli.js +73 -0
  169. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  170. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  171. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  172. package/dist/scripts/i18n-tests.js +41 -0
  173. package/dist/scripts/incident-tests.js +281 -87
  174. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  175. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  176. package/dist/scripts/issue-271-liveness-tests.js +569 -0
  177. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  178. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  179. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  180. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  181. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  182. package/dist/scripts/issue436-persisted-routing-e2e.js +247 -0
  183. package/dist/scripts/itinerary-artifact-tests.js +368 -0
  184. package/dist/scripts/itinerary-deck-artifact-tests.js +416 -0
  185. package/dist/scripts/itinerary-deck-export-tests.js +552 -0
  186. package/dist/scripts/itinerary-deck-tests.js +435 -0
  187. package/dist/scripts/itinerary-html-tests.js +426 -0
  188. package/dist/scripts/journey-tests.js +22 -27
  189. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  190. package/dist/scripts/kernel-manifest-gate.js +126 -0
  191. package/dist/scripts/kernel-manifest-tests.js +212 -0
  192. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  193. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  194. package/dist/scripts/kernel-manifest.js +369 -0
  195. package/dist/scripts/lavish-local-tests.js +1226 -0
  196. package/dist/scripts/lavish-product-tools-tests.js +537 -0
  197. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  198. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  199. package/dist/scripts/ledger-tests.js +382 -246
  200. package/dist/scripts/ledger-workflow-crash.js +10 -20
  201. package/dist/scripts/m3-cohort-tests.js +714 -0
  202. package/dist/scripts/m3-cohort.js +310 -0
  203. package/dist/scripts/managed-dsh-cleanup-diagnostic-proof.js +184 -0
  204. package/dist/scripts/managed-dsh-close-failure-proof.js +172 -0
  205. package/dist/scripts/managed-dsh-run-port-proof.js +153 -0
  206. package/dist/scripts/managed-dsh-terminal-proof.js +252 -0
  207. package/dist/scripts/map-tools-vendor-package-proof.js +365 -0
  208. package/dist/scripts/memory-capture-tests.js +242 -61
  209. package/dist/scripts/memory-decay-tests.js +18 -52
  210. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  211. package/dist/scripts/memory-lifecycle.js +196 -0
  212. package/dist/scripts/memory-metrics.js +24 -12
  213. package/dist/scripts/memory-value-report.js +631 -0
  214. package/dist/scripts/memory-value-tests.js +328 -0
  215. package/dist/scripts/metrics-report-tests.js +151 -0
  216. package/dist/scripts/model-override-e2e.js +137 -0
  217. package/dist/scripts/nightly-evidence-tests.js +203 -0
  218. package/dist/scripts/nightly-evidence.js +303 -0
  219. package/dist/scripts/nudge-digest.js +39 -28
  220. package/dist/scripts/observability-tests.js +381 -0
  221. package/dist/scripts/onboarding-tests.js +161 -0
  222. package/dist/scripts/opensky-check.js +18 -13
  223. package/dist/scripts/opensky-tests.js +28 -28
  224. package/dist/scripts/outcome-projection-tests.js +427 -0
  225. package/dist/scripts/persona-sim-tests.js +603 -0
  226. package/dist/scripts/persona-sim.js +1081 -0
  227. package/dist/scripts/persona-surface-guard-tests.js +49 -0
  228. package/dist/scripts/pnpm-dsh-closure-proof.js +17 -0
  229. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  230. package/dist/scripts/price-drift-tests.js +340 -0
  231. package/dist/scripts/price-drift-watch.js +447 -0
  232. package/dist/scripts/probe-poi-tests.js +53 -45
  233. package/dist/scripts/product-metrics.js +483 -0
  234. package/dist/scripts/publish-preverify.js +110 -0
  235. package/dist/scripts/realtime-pricing-tests.js +76 -0
  236. package/dist/scripts/recall-tests.js +513 -0
  237. package/dist/scripts/replay-async.js +22 -18
  238. package/dist/scripts/replay-real.js +18 -18
  239. package/dist/scripts/replay.js +54 -82
  240. package/dist/scripts/route-provider-conformance-tests.js +391 -0
  241. package/dist/scripts/session-attach-diagnose.js +20 -20
  242. package/dist/scripts/session-attach-poc.js +34 -37
  243. package/dist/scripts/session-benchmark.js +180 -0
  244. package/dist/scripts/session-dida-live-e2e.js +199 -0
  245. package/dist/scripts/session-extract-tests.js +14 -35
  246. package/dist/scripts/session-link-tests.js +478 -0
  247. package/dist/scripts/session-login.js +27 -46
  248. package/dist/scripts/session-tests.js +796 -96
  249. package/dist/scripts/session-zone-crash.js +49 -0
  250. package/dist/scripts/session-zone-ledger-tests.js +432 -0
  251. package/dist/scripts/session-zone-observation-tests.js +492 -0
  252. package/dist/scripts/session-zone-observe.js +135 -0
  253. package/dist/scripts/session-zone-wiring-tests.js +566 -0
  254. package/dist/scripts/session-zones-tests.js +374 -0
  255. package/dist/scripts/sf-live-benchmark.js +367 -0
  256. package/dist/scripts/sf-live-challenge-stop-tests.js +453 -0
  257. package/dist/scripts/sf-live-cli-tests.js +92 -0
  258. package/dist/scripts/sf-live-options.js +46 -0
  259. package/dist/scripts/sf-manifest-tests.js +30 -0
  260. package/dist/scripts/sf-manifest.js +33 -0
  261. package/dist/scripts/sf-soft-score-tests.js +67 -0
  262. package/dist/scripts/sf-summary-tests.js +324 -0
  263. package/dist/scripts/sf-summary.js +525 -0
  264. package/dist/scripts/share-tests.js +432 -0
  265. package/dist/scripts/skeleton-check.js +16 -14
  266. package/dist/scripts/skeleton-integration-test.js +28 -11
  267. package/dist/scripts/skills-contract-tests.js +51 -46
  268. package/dist/scripts/smoke-session-gate-tests.js +21 -0
  269. package/dist/scripts/smoke.js +690 -246
  270. package/dist/scripts/spawn-bounded-abort-tests.js +244 -0
  271. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  272. package/dist/scripts/state-cli-tests.js +226 -101
  273. package/dist/scripts/state-cli.js +565 -198
  274. package/dist/scripts/state-repair-cli.js +66 -0
  275. package/dist/scripts/state-repair-tests.js +140 -0
  276. package/dist/scripts/static-golden-tests.js +165 -0
  277. package/dist/scripts/time-eval-tests.js +212 -192
  278. package/dist/scripts/travel-timeline-tests.js +29 -93
  279. package/dist/scripts/turn-handoff-collect-tests.js +169 -0
  280. package/dist/scripts/turn-handoff-collect.js +161 -0
  281. package/dist/scripts/turn-policy-tests.js +55 -0
  282. package/dist/scripts/typed-contract-canary.js +176 -0
  283. package/dist/scripts/tz-resolver-sanity.js +50 -0
  284. package/dist/scripts/tz-resolver-tests.js +584 -0
  285. package/dist/scripts/unified-tests.js +60 -20
  286. package/dist/scripts/visa-policy-tests.js +62 -0
  287. package/dist/scripts/weather-tests.js +276 -41
  288. package/dist/scripts/wish-channel-gate-tests.js +54 -0
  289. package/dist/scripts/write-gate-tests.js +522 -0
  290. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  291. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  292. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  293. package/dist/scripts/z3-race-tests.js +46 -0
  294. package/dist/src/artifact-gate.js +829 -0
  295. package/dist/src/backend/kernel.js +91 -0
  296. package/dist/src/backend/modules/booking-copilot.js +92 -0
  297. package/dist/src/backend/modules/booking-executor.js +124 -0
  298. package/dist/src/backend/modules/session-search.js +551 -0
  299. package/dist/src/benchmark-agent-conformance.js +578 -0
  300. package/dist/src/benchmark-environment-bridge.js +515 -0
  301. package/dist/src/benchmark-headless-child-diagnostics.js +166 -0
  302. package/dist/src/benchmark-tool-isolation.js +151 -0
  303. package/dist/src/bookable-facts.js +533 -0
  304. package/dist/src/booking-saga.js +97 -0
  305. package/dist/src/booking-surface/availability-policy.js +697 -0
  306. package/dist/src/booking-surface/booking-intent.js +43 -0
  307. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  308. package/dist/src/booking-surface/canonical-schema.js +116 -0
  309. package/dist/src/booking-surface/contracts.js +75 -0
  310. package/dist/src/booking-surface/dsh-planner.js +1854 -0
  311. package/dist/src/booking-surface/dsh-plugin.js +378 -0
  312. package/dist/src/booking-surface/dsh-worker.js +98 -0
  313. package/dist/src/booking-surface/error-codes.js +231 -0
  314. package/dist/src/booking-surface/index.js +9 -0
  315. package/dist/src/booking-surface/managed-dsh-cleanup-diagnostic.js +97 -0
  316. package/dist/src/booking-surface/managed-dsh-run-port.js +244 -0
  317. package/dist/src/booking-surface/profile.js +24 -0
  318. package/dist/src/booking-surface/recovery-chain.js +367 -0
  319. package/dist/src/booking-surface/runtime.js +1968 -0
  320. package/dist/src/booking-surface/server.js +674 -0
  321. package/dist/src/booking-surface/startup.js +168 -0
  322. package/dist/src/booking-surface/validation.js +261 -0
  323. package/dist/src/bridge.js +20 -13
  324. package/dist/src/city-scenario-tier.js +378 -0
  325. package/dist/src/companions.js +48 -74
  326. package/dist/src/contracts.js +21 -43
  327. package/dist/src/dsh-llm.js +171 -115
  328. package/dist/src/engine.js +276 -193
  329. package/dist/src/evaluation-cadence.js +97 -0
  330. package/dist/src/evaluation-contracts.js +283 -0
  331. package/dist/src/flight-pack-adapter.js +54 -0
  332. package/dist/src/flight-pack-contract.js +2 -0
  333. package/dist/src/flyai-setup-tool.js +70 -0
  334. package/dist/src/gotry-backend.js +125 -0
  335. package/dist/src/hotel-date-gate.js +118 -0
  336. package/dist/src/i18n.js +88 -0
  337. package/dist/src/index.js +2385 -881
  338. package/dist/src/itinerary-deck.js +139 -0
  339. package/dist/src/itinerary-doc-shared.js +661 -0
  340. package/dist/src/itinerary-html.js +131 -0
  341. package/dist/src/journey.js +155 -108
  342. package/dist/src/lavish-tools.js +400 -0
  343. package/dist/src/ledger-repair-apply.js +538 -0
  344. package/dist/src/ledger-repair-plan.js +463 -0
  345. package/dist/src/loop.js +331 -161
  346. package/dist/src/m3-cohort.js +1577 -0
  347. package/dist/src/memory-capture.js +180 -32
  348. package/dist/src/memory-decay.js +30 -14
  349. package/dist/src/memory-lifecycle.js +1310 -0
  350. package/dist/src/memory-utility.js +27 -40
  351. package/dist/src/mock-llm.js +36 -61
  352. package/dist/src/model.js +81 -36
  353. package/dist/src/outcome-projection.js +746 -0
  354. package/dist/src/realtime-pricing.js +103 -0
  355. package/dist/src/recall/card.js +74 -0
  356. package/dist/src/recall/evaluator.js +140 -0
  357. package/dist/src/recall/integration.js +17 -0
  358. package/dist/src/recall/tick.js +166 -0
  359. package/dist/src/session-link/plan-it-action.js +48 -0
  360. package/dist/src/session-link/session-link.js +248 -0
  361. package/dist/src/session-zone-ledger.js +312 -0
  362. package/dist/src/session-zone-observation.js +354 -0
  363. package/dist/src/session-zone-wiring.js +658 -0
  364. package/dist/src/session-zones.js +510 -0
  365. package/dist/src/share/adapters.js +51 -0
  366. package/dist/src/share/share-consent.js +76 -0
  367. package/dist/src/share/share-deck.js +58 -0
  368. package/dist/src/share/share-token.js +146 -0
  369. package/dist/src/slot-spec.js +84 -106
  370. package/dist/src/state-ledger.js +696 -524
  371. package/dist/src/state-repair.js +299 -0
  372. package/dist/src/subagent-job-id-guard.js +58 -0
  373. package/dist/src/time-anchor.js +231 -33
  374. package/dist/src/tool-packet.js +20 -8
  375. package/dist/src/travel-slots.js +58 -35
  376. package/dist/src/travel-timeline.js +44 -63
  377. package/dist/src/turn-deadline.js +287 -0
  378. package/dist/src/turn-policy.js +118 -0
  379. package/dist/src/tz-resolver.js +143 -0
  380. package/dist/src/unified.js +600 -360
  381. package/dist/src/wish-pool.js +42 -12
  382. package/dist/src/write-gate.js +495 -0
  383. package/dist/src/z3-shared.js +284 -0
  384. package/extension/README.md +21 -0
  385. package/extension/README.zh-CN.md +21 -0
  386. package/extension/background.js +463 -0
  387. package/extension/content-bridge.js +270 -0
  388. package/extension/content-main.js +111 -0
  389. package/extension/manifest.json +60 -0
  390. package/package.json +407 -14
  391. package/schemas/booking.intent.schema.json +193 -0
  392. package/schemas/booking.surface.schema.json +2622 -0
  393. package/ts/capabilities/agent-reach-deep.ts +114 -0
  394. package/ts/capabilities/agent-reach.ts +198 -0
  395. package/ts/capabilities/anything.ts +282 -0
  396. package/ts/capabilities/artifacts.ts +428 -0
  397. package/ts/capabilities/fact-log.ts +54 -0
  398. package/ts/capabilities/flyai-config.ts +388 -0
  399. package/ts/capabilities/flyai.ts +1274 -0
  400. package/ts/capabilities/hbcli.ts +253 -71
  401. package/ts/capabilities/incident-log.ts +88 -59
  402. package/ts/capabilities/itinerary-artifact.ts +214 -0
  403. package/ts/capabilities/itinerary-deck-artifact.ts +218 -0
  404. package/ts/capabilities/itinerary-deck-export.ts +378 -0
  405. package/ts/capabilities/opensky.ts +121 -0
  406. package/ts/capabilities/session/action-cache.ts +148 -0
  407. package/ts/capabilities/session/adapters/ctrip-flight.ts +181 -0
  408. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  409. package/ts/capabilities/session/adapters/dida-portal.ts +338 -0
  410. package/ts/capabilities/session/adapters/meituan-local.ts +70 -0
  411. package/ts/capabilities/session/adapters/rail-12306.ts +392 -0
  412. package/ts/capabilities/session/benchmark.ts +276 -0
  413. package/ts/capabilities/session/bridge-ledger.ts +333 -0
  414. package/ts/capabilities/session/extension-bridge.ts +794 -0
  415. package/ts/capabilities/session/extension-channel.ts +144 -0
  416. package/ts/capabilities/session/extension-distribution.ts +266 -0
  417. package/ts/capabilities/session/extract.ts +54 -0
  418. package/ts/capabilities/session/golden-score.ts +139 -0
  419. package/ts/capabilities/session/health-watch.ts +264 -0
  420. package/ts/capabilities/session/read-guard.ts +141 -0
  421. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  422. package/ts/capabilities/session/transport.ts +146 -0
  423. package/ts/capabilities/session/wizard.ts +140 -0
  424. package/ts/capabilities/session-consent.ts +211 -0
  425. package/ts/capabilities/session-login.ts +208 -0
  426. package/ts/capabilities/session-search.ts +893 -0
  427. package/ts/capabilities/weather.ts +330 -0
  428. package/ts/dsh-runtime/vendor/README.md +68 -0
  429. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  430. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +405 -0
  431. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +404 -0
  432. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +1584 -0
  433. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  434. package/ts/dsh-runtime/vendor/dsh-map-tools/icon.svg +5 -0
  435. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +595 -0
  436. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  437. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +58 -0
  438. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  439. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  440. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +131 -0
  441. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  442. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/geo.js +232 -0
  443. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +120 -0
  444. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +40 -0
  445. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/staticmap-route.js +115 -0
  446. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  447. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  448. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +267 -0
  449. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +90 -0
  450. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  451. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  452. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  453. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  454. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +23 -0
  455. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  456. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/geo.d.ts +61 -0
  457. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  458. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  459. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/staticmap-route.d.ts +31 -0
  460. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  461. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  462. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +75 -0
  463. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +68 -0
  464. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  465. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +97 -0
  466. package/ts/package.json +293 -3
  467. package/ts/scripts/async-collect.ts +91 -0
  468. package/ts/scripts/map-tools-vendor-package-proof.ts +404 -0
  469. package/ts/scripts/skeleton-check.ts +1 -1
  470. package/ts/scripts/skeleton-integration-test.ts +23 -1
  471. package/ts/scripts/state-cli.ts +586 -0
  472. package/ts/scripts/turn-handoff-collect.ts +178 -0
  473. package/ts/src/artifact-gate.ts +991 -0
  474. package/ts/src/benchmark-agent-conformance.ts +619 -0
  475. package/ts/src/benchmark-environment-bridge.ts +538 -0
  476. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  477. package/ts/src/benchmark-tool-isolation.ts +166 -0
  478. package/ts/src/bookable-facts.ts +837 -0
  479. package/ts/src/booking-saga.ts +133 -0
  480. package/ts/src/booking-surface/availability-policy.ts +522 -0
  481. package/ts/src/booking-surface/booking-intent.ts +86 -0
  482. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  483. package/ts/src/booking-surface/canonical-schema.js +116 -0
  484. package/ts/src/booking-surface/contracts.ts +475 -0
  485. package/ts/src/booking-surface/dsh-planner.ts +1949 -0
  486. package/ts/src/booking-surface/dsh-plugin.js +378 -0
  487. package/ts/src/booking-surface/dsh-worker.ts +110 -0
  488. package/ts/src/booking-surface/error-codes.ts +241 -0
  489. package/ts/src/booking-surface/index.ts +9 -0
  490. package/ts/src/booking-surface/managed-dsh-cleanup-diagnostic.ts +151 -0
  491. package/ts/src/booking-surface/managed-dsh-run-port.ts +273 -0
  492. package/ts/src/booking-surface/profile.ts +42 -0
  493. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  494. package/ts/src/booking-surface/runtime.ts +1793 -0
  495. package/ts/src/booking-surface/server.ts +733 -0
  496. package/ts/src/booking-surface/startup.ts +201 -0
  497. package/ts/src/booking-surface/validation.ts +217 -0
  498. package/ts/src/companions.ts +113 -0
  499. package/ts/src/contracts.ts +17 -3
  500. package/ts/src/dsh-llm.ts +152 -17
  501. package/ts/src/flyai-setup-tool.ts +77 -0
  502. package/ts/src/index.ts +2123 -200
  503. package/ts/src/itinerary-deck.ts +189 -0
  504. package/ts/src/itinerary-doc-shared.ts +741 -0
  505. package/ts/src/itinerary-html.ts +171 -0
  506. package/ts/src/loop.ts +234 -26
  507. package/ts/src/memory-capture.ts +283 -0
  508. package/ts/src/memory-decay.ts +55 -0
  509. package/ts/src/memory-utility.ts +70 -0
  510. package/ts/src/mock-llm.ts +4 -8
  511. package/ts/src/model.ts +88 -2
  512. package/ts/src/recall/card.ts +106 -0
  513. package/ts/src/recall/evaluator.ts +170 -0
  514. package/ts/src/recall/integration.ts +35 -0
  515. package/ts/src/recall/tick.ts +213 -0
  516. package/ts/src/session-link/plan-it-action.ts +78 -0
  517. package/ts/src/session-link/session-link.ts +275 -0
  518. package/ts/src/share/adapters.ts +93 -0
  519. package/ts/src/share/share-consent.ts +105 -0
  520. package/ts/src/share/share-deck.ts +85 -0
  521. package/ts/src/share/share-token.ts +166 -0
  522. package/ts/src/slot-spec.ts +172 -0
  523. package/ts/src/state-ledger.ts +1166 -0
  524. package/ts/src/subagent-job-id-guard.ts +72 -0
  525. package/ts/src/time-anchor.ts +338 -0
  526. package/ts/src/tool-packet.ts +32 -0
  527. package/ts/src/travel-slots.ts +219 -0
  528. package/ts/src/travel-timeline.ts +83 -0
  529. package/ts/src/turn-deadline.ts +366 -0
  530. package/ts/src/turn-policy.ts +154 -0
  531. package/ts/src/unified.ts +444 -105
  532. package/ts/src/wish-pool.ts +79 -0
  533. package/dist/scripts/session-attach-wait.js +0 -41
@@ -0,0 +1,447 @@
1
+ /**
2
+ * LLM 官方定价漂移监测(issue #49 长效机制)。
3
+ *
4
+ * 设计纪律(与 ADR-11 / issue #49 一致):
5
+ * - 永不自动 apply 价格变更到 llm-price-table.json——价格调整必须走 PR,
6
+ * 由人 review;founder 2026-08-26 实测「自动 apply 容易把 down 5% 的官方新价错认为我的 bug」;
7
+ * - 本脚本只产出 PR-就绪的 Markdown diff,供人粘贴到 PR 描述;
8
+ * - 联网取数(--fetch 模式)有超时 + 离线 SKIP,默认行为零网络,适配 CI 纪律;
9
+ * - 解析规则保守:任何一行解析失败 → 整家 SKIP + warn,不写未知数据;
10
+ * - 比较口径:与 fixture 缓存的上次官方价对照——若 fixture 不存在,fetch 模式写入新 fixture,
11
+ * diff 模式直接报"首次运行,无 baseline"。
12
+ *
13
+ * 运行(在 ts/ 下):
14
+ * npx tsx scripts/price-drift-watch.ts # 离线模式:对照 fixture 算 diff(零网络)
15
+ * npx tsx scripts/price-drift-watch.ts --fetch # 联网模式:fetch 官方页 + 写 fixture + 算 diff
16
+ * npx tsx scripts/price-drift-watch.ts --format json
17
+ *
18
+ * 输出:stdout Markdown(默认)/JSON(--format json),心形:
19
+ * {
20
+ * schema_version: 'gotry_llm_price_drift_v1',
21
+ * observed_at: '<ISO>',
22
+ * providers: {
23
+ * deepseek: { status: 'unchanged' | 'drift' | 'skipped_no_baseline' | 'skipped_parse_error' | 'skipped_no_network', drift: [...] },
24
+ * minimax: { ... },
25
+ * openai: { ... },
26
+ * anthropic: { ... }
27
+ * },
28
+ * suggested_pr_paragraph: '<可直接粘贴到 PR 描述的一段>'
29
+ * }
30
+ *
31
+ * 心智模型:
32
+ * - provider="deepseek": fixture 文件 data/llm-price-baseline-deepseek.json,
33
+ * 上次 fetch 的官方价(rows 数组 + as_of);若不存在 → "skipped_no_baseline",
34
+ * 提示:首次跑 --fetch 一次入 fixture。
35
+ * - provider="minimax": 同上,data/llm-price-baseline-minimax.json。
36
+ * - provider="openai": 同上,data/llm-price-baseline-openai.json。
37
+ * - provider="anthropic": 同上,data/llm-price-baseline-anthropic.json。
38
+ * - 已入价表的 provider(当前为 deepseek/minimax)才有 baseline 期望;
39
+ * 未入价表的 provider(openai/anthropic)fetch 模式采得就当 narrative 记录,
40
+ * 仍不进 llm-price-table.json(那是未来单独的 PR)。
41
+ */
42
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
43
+ const FETCH_TIMEOUT_MS = 8000;
44
+ const DEFAULT_PROVIDERS = [
45
+ { id: 'deepseek', source_url: 'https://api-docs.deepseek.com/quick_start/pricing', baseline_path: 'data/llm-price-baseline-deepseek.json', parse: parseDeepseekHtml },
46
+ { id: 'minimax', source_url: 'https://platform.minimax.io/docs/guides/pricing-paygo', baseline_path: 'data/llm-price-baseline-minimax.json', parse: parseMinimaxHtml },
47
+ { id: 'openai', source_url: 'https://openai.com/api/pricing/', baseline_path: 'data/llm-price-baseline-openai.json', snapshot_path: 'data/llm-pricing-snapshot-openai.html', parse: parseOpenaiHtml },
48
+ { id: 'anthropic', source_url: 'https://www.anthropic.com/pricing', baseline_path: 'data/llm-price-baseline-anthropic.json', snapshot_path: 'data/llm-pricing-snapshot-anthropic.html', parse: parseAnthropicHtml },
49
+ ];
50
+ async function fetchWithTimeout(url, timeoutMs) {
51
+ const controller = new AbortController();
52
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
53
+ try {
54
+ const res = await fetch(url, { signal: controller.signal, headers: { 'User-Agent': 'GoTry-price-drift-watch/1 (issue #49)' } });
55
+ if (!res.ok)
56
+ throw new Error(`HTTP ${res.status}`);
57
+ return await res.text();
58
+ }
59
+ finally {
60
+ clearTimeout(timer);
61
+ }
62
+ }
63
+ /** DeepSeek 官方定价页是简单 HTML 表格;粗解析:美元数字 $/M token 表行。
64
+ * 失败时不抛:返回 null,watcher 标 skipped_parse_error。 */
65
+ function parseDeepseekHtml(html) {
66
+ // DeepSeek 表格行形如:
67
+ // <td>deepseek-v4-flash</td><td>0.44</td><td>0.014</td><td>1.32</td> (cache_miss/cache_hit/output per 1M)
68
+ const rows = [];
69
+ const rowRe = /<tr[^>]*>([\s\S]*?)<\/tr>/g;
70
+ const cellRe = /<td[^>]*>([\s\S]*?)<\/td>/g;
71
+ let tr;
72
+ while ((tr = rowRe.exec(html)) !== null) {
73
+ const cells = [];
74
+ let m;
75
+ while ((m = cellRe.exec(tr[1])) !== null)
76
+ cells.push(m[1].replace(/<[^>]+>/g, '').trim());
77
+ if (cells.length < 4)
78
+ continue;
79
+ const model = cells[0];
80
+ if (!/^deepseek-v[34]/.test(model))
81
+ continue;
82
+ const miss = Number(cells[1]);
83
+ const hit = Number(cells[2]);
84
+ const out = Number(cells[3]);
85
+ if (!Number.isFinite(miss) || !Number.isFinite(out))
86
+ continue;
87
+ rows.push({ model, input_cache_miss_usd_per_1m: miss, input_cache_hit_usd_per_1m: Number.isFinite(hit) ? hit : null, output_usd_per_1m: out });
88
+ }
89
+ return rows.length > 0 ? rows : null;
90
+ }
91
+ /** MiniMax Pay-as-you-go 页面是 markdown 化 HTML 文档,粗解析:model + $/M tokens 行。 */
92
+ function parseMinimaxHtml(html) {
93
+ const rows = [];
94
+ // 行形如: **MiniMax-M3** … $0.30 / M tokens (Input, ≤512k) … $1.20 / M tokens (Output, ≤512k) … $0.06 / M tokens (Cache Read)
95
+ const lineRe = /<p[^>]*>([\s\S]*?)<\/p>/g;
96
+ let p;
97
+ const seen = new Set();
98
+ while ((p = lineRe.exec(html)) !== null) {
99
+ const text = p[1].replace(/<[^>]+>/g, '').replace(/&nbsp;/g, ' ').replace(/\s+/g, ' ').trim();
100
+ const modelMatch = text.match(/(MiniMax-M2(?:\.1)?(?:-highspeed)?|MiniMax-M3)/);
101
+ if (!modelMatch)
102
+ continue;
103
+ const model = modelMatch[1];
104
+ // 取输入/输出/缓存读取三个数;按出现顺序:Input, Output, Cache Read
105
+ const numbers = Array.from(text.matchAll(/\$([0-9]+(?:\.[0-9]+)?)\s*\/\s*M\s*tokens?/g)).map(m => Number(m[1]));
106
+ if (numbers.length < 2)
107
+ continue;
108
+ // 输入/输出 两个必备;Cache Read 可选
109
+ const [miss, out] = numbers;
110
+ const hit = numbers.length >= 3 ? numbers[2] : null;
111
+ if (seen.has(model))
112
+ continue;
113
+ seen.add(model);
114
+ rows.push({ model, input_cache_miss_usd_per_1m: miss, input_cache_hit_usd_per_1m: hit, output_usd_per_1m: out });
115
+ }
116
+ return rows.length > 0 ? rows : null;
117
+ }
118
+ /** OpenAI 公开页是 React SPA(服务端只返壳 JSON 与内嵌 <script>)。
119
+ * 解析策略:`data/llm-pricing-snapshot-openai.html` snapshot 优先(入 git,CI 零联网);
120
+ * `--fetch` 模式覆盖 snapshot;解析取自 Next.js 嵌入的 `__NEXT_DATA__` JSON dump
121
+ * (其 `props.pageProps` 含 model price 数组),失败回退到段落文字粗解析。 */
122
+ export function parseOpenaiHtml(html) {
123
+ const fromNextData = parseOpenaiNextData(html);
124
+ if (fromNextData)
125
+ return fromNextData;
126
+ return parseOpenaiParagraphFallback(html);
127
+ }
128
+ function parseOpenaiNextData(html) {
129
+ const m = html.match(/<script[^>]*id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);
130
+ if (!m)
131
+ return null;
132
+ try {
133
+ const data = JSON.parse(m[1]);
134
+ const models = data?.props?.pageProps?.models;
135
+ if (!Array.isArray(models) || models.length === 0)
136
+ return null;
137
+ const rows = [];
138
+ for (const m of models) {
139
+ const name = String(m['name'] ?? m['model'] ?? '').trim();
140
+ if (!name)
141
+ continue;
142
+ // 启发式:per-token 数字通常极小(<1),per-1M 数字通常 ≥ 0.1;前者要 ×1_000_000
143
+ const rawMiss = Number(m['input_cost_per_token'] ?? m['input_per_million'] ?? m['input']);
144
+ const rawOut = Number(m['output_cost_per_token'] ?? m['output_per_million'] ?? m['output']);
145
+ const rawHit = Number(m['cached_input_cost_per_token'] ?? m['cached_input_per_million'] ?? m['cache_read']);
146
+ if (!Number.isFinite(rawMiss) || !Number.isFinite(rawOut))
147
+ continue;
148
+ rows.push({
149
+ model: name,
150
+ input_cache_miss_usd_per_1m: rawMiss < 1 ? rawMiss * 1_000_000 : rawMiss,
151
+ input_cache_hit_usd_per_1m: Number.isFinite(rawHit) ? (rawHit < 1 ? rawHit * 1_000_000 : rawHit) : null,
152
+ output_usd_per_1m: rawOut < 1 ? rawOut * 1_000_000 : rawOut,
153
+ });
154
+ }
155
+ return rows.length > 0 ? rows : null;
156
+ }
157
+ catch {
158
+ return null;
159
+ }
160
+ }
161
+ function parseOpenaiParagraphFallback(html) {
162
+ // 兜底:段落文字形如 "gpt-4o … $2.50 / 1M input … $10.00 / 1M output"
163
+ const rows = [];
164
+ const lineRe = /<p[^>]*>([\s\S]*?)<\/p>|<li[^>]*>([\s\S]*?)<\/li>/g;
165
+ let m;
166
+ while ((m = lineRe.exec(html)) !== null) {
167
+ const text = (m[1] ?? m[2] ?? '').replace(/<[^>]+>/g, '').replace(/&nbsp;/g, ' ').replace(/\s+/g, ' ').trim();
168
+ const modelMatch = text.match(/(gpt-4o(?:-mini)?|gpt-4\.1(?:-mini)?|gpt-5(?:-mini)?|o[1-9](?:-mini|-pro)?)/);
169
+ if (!modelMatch)
170
+ continue;
171
+ const numbers = Array.from(text.matchAll(/\$([0-9]+(?:\.[0-9]+)?)\s*\/\s*(?:1M|M)/g)).map(x => Number(x[1]));
172
+ if (numbers.length < 2)
173
+ continue;
174
+ const [miss, out] = numbers;
175
+ rows.push({ model: modelMatch[1], input_cache_miss_usd_per_1m: miss, input_cache_hit_usd_per_1m: null, output_usd_per_1m: out });
176
+ }
177
+ return rows.length > 0 ? rows : null;
178
+ }
179
+ /** Anthropic pricing 页同样 SPA,内嵌 `__NEXT_DATA__` 形态可能变;双路径同 OpenAI。 */
180
+ function parseAnthropicHtml(html) {
181
+ const fromNextData = parseAnthropicNextData(html);
182
+ if (fromNextData)
183
+ return fromNextData;
184
+ return parseAnthropicParagraphFallback(html);
185
+ }
186
+ function parseAnthropicNextData(html) {
187
+ const m = html.match(/<script[^>]*id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/);
188
+ if (!m)
189
+ return null;
190
+ try {
191
+ const data = JSON.parse(m[1]);
192
+ const pricing = data?.props?.pageProps?.pricing;
193
+ if (!Array.isArray(pricing) || pricing.length === 0)
194
+ return null;
195
+ const rows = [];
196
+ for (const p of pricing) {
197
+ const name = String(p['model'] ?? p['name'] ?? '').trim();
198
+ if (!name)
199
+ continue;
200
+ const miss = Number(p['input_cost_per_mtok'] ?? p['input']);
201
+ const out = Number(p['output_cost_per_mtok'] ?? p['output']);
202
+ const hit = Number(p['cache_read_cost_per_mtok'] ?? p['cache_read']);
203
+ if (!Number.isFinite(miss) || !Number.isFinite(out))
204
+ continue;
205
+ rows.push({ model: name, input_cache_miss_usd_per_1m: miss, input_cache_hit_usd_per_1m: Number.isFinite(hit) ? hit : null, output_usd_per_1m: out });
206
+ }
207
+ return rows.length > 0 ? rows : null;
208
+ }
209
+ catch {
210
+ return null;
211
+ }
212
+ }
213
+ function parseAnthropicParagraphFallback(html) {
214
+ const rows = [];
215
+ const lineRe = /<p[^>]*>([\s\S]*?)<\/p>|<li[^>]*>([\s\S]*?)<\/li>/g;
216
+ let m;
217
+ while ((m = lineRe.exec(html)) !== null) {
218
+ const text = (m[1] ?? m[2] ?? '').replace(/<[^>]+>/g, '').replace(/&nbsp;/g, ' ').replace(/\s+/g, ' ').trim();
219
+ const modelMatch = text.match(/(claude-(?:opus|sonnet|haiku)-[0-9](?:\.[0-9])?(?:-[0-9]+k)?)/);
220
+ if (!modelMatch)
221
+ continue;
222
+ const numbers = Array.from(text.matchAll(/\$([0-9]+(?:\.[0-9]+)?)\s*\/\s*(?:1M|M|MT)/g)).map(x => Number(x[1]));
223
+ if (numbers.length < 2)
224
+ continue;
225
+ const [miss, out] = numbers;
226
+ rows.push({ model: modelMatch[1], input_cache_miss_usd_per_1m: miss, input_cache_hit_usd_per_1m: null, output_usd_per_1m: out });
227
+ }
228
+ return rows.length > 0 ? rows : null;
229
+ }
230
+ function diffRows(baseline, current) {
231
+ const baseMap = new Map(baseline.map(r => [r.model, r]));
232
+ const currMap = new Map(current.map(r => [r.model, r]));
233
+ const drift = [];
234
+ for (const [model, curr] of currMap) {
235
+ const base = baseMap.get(model);
236
+ if (!base) {
237
+ drift.push({ model, field: 'input_cache_miss_usd_per_1m', from: null, to: curr.input_cache_miss_usd_per_1m, direction: 'new' });
238
+ continue;
239
+ }
240
+ if (base.input_cache_miss_usd_per_1m !== curr.input_cache_miss_usd_per_1m) {
241
+ drift.push({ model, field: 'input_cache_miss_usd_per_1m', from: base.input_cache_miss_usd_per_1m, to: curr.input_cache_miss_usd_per_1m, direction: curr.input_cache_miss_usd_per_1m > base.input_cache_miss_usd_per_1m ? 'up' : 'down' });
242
+ }
243
+ if (base.input_cache_hit_usd_per_1m !== curr.input_cache_hit_usd_per_1m) {
244
+ drift.push({ model, field: 'input_cache_hit_usd_per_1m', from: base.input_cache_hit_usd_per_1m, to: curr.input_cache_hit_usd_per_1m, direction: (curr.input_cache_hit_usd_per_1m ?? 0) > (base.input_cache_hit_usd_per_1m ?? 0) ? 'up' : 'down' });
245
+ }
246
+ if (base.output_usd_per_1m !== curr.output_usd_per_1m) {
247
+ drift.push({ model, field: 'output_usd_per_1m', from: base.output_usd_per_1m, to: curr.output_usd_per_1m, direction: curr.output_usd_per_1m > base.output_usd_per_1m ? 'up' : 'down' });
248
+ }
249
+ }
250
+ for (const [model, base] of baseMap) {
251
+ if (!currMap.has(model)) {
252
+ drift.push({ model, field: 'input_cache_miss_usd_per_1m', from: base.input_cache_miss_usd_per_1m, to: null, direction: 'removed' });
253
+ }
254
+ }
255
+ return drift;
256
+ }
257
+ function loadBaseline(path) {
258
+ if (!existsSync(path))
259
+ return null;
260
+ try {
261
+ const raw = JSON.parse(readFileSync(path, 'utf8'));
262
+ if (raw['schema_version'] !== 'gotry_llm_price_baseline_v1')
263
+ throw new Error(`baseline ${path} schema_version must be gotry_llm_price_baseline_v1, got ${String(raw['schema_version'])}`);
264
+ const rows = raw['rows'];
265
+ if (!Array.isArray(rows))
266
+ throw new Error(`baseline ${path} rows must be array`);
267
+ return raw;
268
+ }
269
+ catch (error) {
270
+ return null;
271
+ }
272
+ }
273
+ /** 读 snapshot HTML 文件;不存在或空 → null。snapshot 由 `--fetch` 模式首次写盘(founder 手动 PR)。 */
274
+ function loadSnapshot(path) {
275
+ if (!existsSync(path))
276
+ return null;
277
+ try {
278
+ const text = readFileSync(path, 'utf8');
279
+ return text.length > 0 ? text : null;
280
+ }
281
+ catch {
282
+ return null;
283
+ }
284
+ }
285
+ function writeSnapshot(path, html) {
286
+ writeFileSync(path, html, 'utf8');
287
+ }
288
+ function writeBaseline(path, rows, sourceUrl) {
289
+ const payload = {
290
+ schema_version: 'gotry_llm_price_baseline_v1',
291
+ as_of: new Date().toISOString(),
292
+ source_url: sourceUrl,
293
+ rows,
294
+ };
295
+ writeFileSync(path, JSON.stringify(payload, null, 2) + '\n', 'utf8');
296
+ }
297
+ export async function runPriceDriftWatch(options) {
298
+ const observedAt = options.observedAt().toISOString();
299
+ const providers = {};
300
+ const providerSpecs = options.providers ?? DEFAULT_PROVIDERS;
301
+ const fetcher = options.fetcher ?? ((url) => fetchWithTimeout(url, FETCH_TIMEOUT_MS));
302
+ for (const spec of providerSpecs) {
303
+ const baseline = loadBaseline(spec.baseline_path);
304
+ const snapshot = spec.snapshot_path ? loadSnapshot(spec.snapshot_path) : null;
305
+ if (options.mode === 'offline') {
306
+ // 离线模式两种来源:
307
+ // (a) 有 snapshot → 走 snapshot.html parse 出 current,与 baseline diff(零联网,CI 心形)
308
+ // (b) 无 snapshot → 只能报 baseline 状态(无东西可 diff,标 unchanged + 提示)
309
+ if (!baseline) {
310
+ providers[spec.id] = { status: 'skipped_no_baseline', source_url: spec.source_url, reason: `no baseline fixture at ${spec.baseline_path}; run --fetch once to seed` };
311
+ continue;
312
+ }
313
+ if (snapshot === null) {
314
+ if (spec.snapshot_path) {
315
+ providers[spec.id] = { status: 'skipped_no_snapshot', source_url: spec.source_url, reason: `no snapshot at ${spec.snapshot_path}; run --fetch once to seed (or: founder manually save official pricing page HTML as the snapshot)` };
316
+ }
317
+ else {
318
+ providers[spec.id] = { status: 'unchanged', source_url: spec.source_url, reason: 'offline mode; baseline present, run --fetch to compare against current official prices' };
319
+ }
320
+ continue;
321
+ }
322
+ const currentFromSnapshot = spec.parse(snapshot);
323
+ if (!currentFromSnapshot) {
324
+ providers[spec.id] = { status: 'skipped_parse_error', source_url: spec.source_url, reason: 'snapshot present but parser failed to extract rows; refresh snapshot or fix parser' };
325
+ continue;
326
+ }
327
+ const driftFromSnapshot = diffRows(baseline.rows, currentFromSnapshot) ?? [];
328
+ if (driftFromSnapshot.length === 0) {
329
+ providers[spec.id] = { status: 'unchanged', source_url: spec.source_url, reason: 'offline; baseline == snapshot-derived current' };
330
+ }
331
+ else {
332
+ providers[spec.id] = { status: 'drift', source_url: spec.source_url, fetched_at: observedAt, drift: driftFromSnapshot, reason: 'offline diff baseline vs snapshot' };
333
+ }
334
+ continue;
335
+ }
336
+ // fetch mode
337
+ let html;
338
+ try {
339
+ html = await fetcher(spec.source_url);
340
+ }
341
+ catch (error) {
342
+ providers[spec.id] = { status: 'skipped_no_network', source_url: spec.source_url, reason: `fetch failed: ${error.message}` };
343
+ continue;
344
+ }
345
+ // snapshot 写盘:OpenAI/Anthropic SPA 的真实状态在 snapshot 文件里(founder 手动 PR)
346
+ if (spec.snapshot_path)
347
+ writeSnapshot(spec.snapshot_path, html);
348
+ const current = spec.parse(html);
349
+ if (!current) {
350
+ providers[spec.id] = { status: 'skipped_parse_error', source_url: spec.source_url, reason: 'parser did not extract any rows; snapshot was written anyway (manual review of fixture + parser required)' };
351
+ continue;
352
+ }
353
+ if (!baseline) {
354
+ // 首次 fetch 写 fixture
355
+ writeBaseline(spec.baseline_path, current, spec.source_url);
356
+ providers[spec.id] = { status: 'fetched_no_table_entry', source_url: spec.source_url, fetched_at: observedAt, reason: 'first fetch; baseline fixture written; no current llm-price-table.json entry (add a PR if you want this provider in nightly-evidence cost math)' };
357
+ continue;
358
+ }
359
+ const drift = diffRows(baseline.rows, current) ?? [];
360
+ if (drift.length === 0) {
361
+ providers[spec.id] = { status: 'unchanged', source_url: spec.source_url, fetched_at: observedAt };
362
+ }
363
+ else {
364
+ providers[spec.id] = { status: 'drift', source_url: spec.source_url, fetched_at: observedAt, drift };
365
+ }
366
+ }
367
+ const suggestedPrParagraph = renderSuggestedPr(providers, observedAt);
368
+ return {
369
+ schema_version: 'gotry_llm_price_drift_v1',
370
+ observed_at: observedAt,
371
+ mode: options.mode,
372
+ providers,
373
+ suggested_pr_paragraph: suggestedPrParagraph,
374
+ };
375
+ }
376
+ function renderSuggestedPr(providers, observedAt) {
377
+ const lines = [`## LLM 价格漂移监测(${observedAt})`];
378
+ for (const [id, report] of Object.entries(providers)) {
379
+ if (report.status === 'drift' && report.drift && report.drift.length > 0) {
380
+ const driftItems = report.drift;
381
+ lines.push(`- **${id}**(${report.source_url}):${driftItems.length} 项变动`);
382
+ for (const d of driftItems) {
383
+ lines.push(` - \`${d.model}\` ${d.field}: ${d.from ?? '∅'} → ${d.to ?? '∅'} (${d.direction})`);
384
+ }
385
+ lines.push(' - 建议:按 ADR-11 复核,人工提 PR 改 `data/llm-price-table.json`。');
386
+ }
387
+ else if (report.status === 'unchanged') {
388
+ lines.push(`- **${id}**:无变动`);
389
+ }
390
+ else if (report.status === 'fetched_no_table_entry') {
391
+ lines.push(`- **${id}**:首次 fetch,baseline 已写入(${report.reason ?? ''})`);
392
+ }
393
+ else {
394
+ lines.push(`- **${id}** [${report.status}]:${report.reason ?? ''}`);
395
+ }
396
+ }
397
+ lines.push('');
398
+ lines.push('纪律:本监测只产 diff,不自动改价表;价格调整必须人工 PR,符合 ADR-11 「peak only-high-not-low」。');
399
+ return lines.join('\n');
400
+ }
401
+ function formatMarkdown(report) {
402
+ const lines = [`# LLM 价格漂移监测(${report.observed_at},mode=${report.mode})`, ''];
403
+ for (const [id, r] of Object.entries(report.providers)) {
404
+ lines.push(`## ${id} [${r.status}]`);
405
+ lines.push(`source: ${r.source_url}`);
406
+ if (r.reason)
407
+ lines.push(`reason: ${r.reason}`);
408
+ if (r.drift && r.drift.length > 0) {
409
+ lines.push('| model | field | from | to | direction |');
410
+ lines.push('|---|---|---|---|---|');
411
+ for (const d of r.drift)
412
+ lines.push(`| \`${d.model}\` | ${d.field} | ${d.from ?? '∅'} | ${d.to ?? '∅'} | ${d.direction} |`);
413
+ }
414
+ lines.push('');
415
+ }
416
+ lines.push('---');
417
+ lines.push('');
418
+ lines.push(report.suggested_pr_paragraph);
419
+ return lines.join('\n');
420
+ }
421
+ function arg(name) {
422
+ const index = process.argv.indexOf(name);
423
+ return index >= 0 ? process.argv[index + 1] : undefined;
424
+ }
425
+ async function main() {
426
+ const asJson = (arg('--format') ?? 'markdown') === 'json';
427
+ const mode = process.argv.includes('--fetch') ? 'fetch' : 'offline';
428
+ mkdirSync('gotry-state', { recursive: true });
429
+ try {
430
+ const report = await runPriceDriftWatch({ mode, observedAt: () => new Date() });
431
+ if (asJson)
432
+ console.log(JSON.stringify(report, null, 2));
433
+ else
434
+ console.log(formatMarkdown(report));
435
+ }
436
+ catch (error) {
437
+ const payload = { state: 'error', error: error.message };
438
+ if (asJson)
439
+ console.log(JSON.stringify(payload, null, 2));
440
+ else
441
+ console.error(`price-drift-watch error: ${error.message}`);
442
+ process.exitCode = 1;
443
+ }
444
+ }
445
+ if (process.argv[1]?.endsWith('price-drift-watch.ts')) {
446
+ await main();
447
+ }
@@ -1,88 +1,96 @@
1
+ /**
2
+ * probePoi 单测(D-7a 债的产品层测试,不动求解器)
3
+ *
4
+ * ⚠️ 本单测是**稳定性回归**,不验证精确字符串。
5
+ * 原因: tsx + Node 24 experimental-strip-types 在中文 unicode character class
6
+ * 上有微小行为差(regex char class 贪婪+unicode 编码在 tsx 与 node 直接调
7
+ * 时输出不一致)。probePoi 函数本身在 e2e 路径(datasources.runTurn)实
8
+ * 测可工作(commit a5ca01e 已验证);精确字符串覆盖在那里。
9
+ *
10
+ * 单测覆盖:不抛错 + 5 类触发各返回非 null/合理 + 2 类不触发返 null。
11
+ * 运行: cd ts && npx tsx scripts/probe-poi-tests.ts
12
+ */
1
13
  import assert from 'node:assert/strict';
2
14
  import { probePoi } from '../src/loop.js';
3
15
  function pass(name, body) {
4
16
  body();
5
17
  console.log(` ${name} OK`);
6
18
  }
7
- pass('1. 不抛错 + 空串/纯空白返 null', ()=>{
8
- assert.doesNotThrow(()=>probePoi(''));
19
+ pass('1. 不抛错 + 空串/纯空白返 null', () => {
20
+ assert.doesNotThrow(() => probePoi(''));
9
21
  assert.equal(probePoi(''), null);
10
22
  assert.equal(probePoi(' '), null);
11
23
  });
12
- pass('2. 短纯地名(<24 字符非问句)触发', ()=>{
13
- for (const t of [
14
- '普吉',
15
- '清迈',
16
- '大理',
17
- '北京 酒店',
18
- '丽江市'
19
- ]){
24
+ pass('2. 短纯地名(<24 字符非问句)触发', () => {
25
+ for (const t of ['普吉', '清迈', '大理', '北京 酒店', '丽江市']) {
20
26
  const r = probePoi(t);
21
- if (r === null) throw new Error(`${JSON.stringify(t)} 应触发,得 null`);
22
- if (typeof r !== 'string') throw new Error(`返类型错: ${typeof r}`);
23
- if (r.length < 2 || r.length > 24) throw new Error(`长度越界: ${r.length}`);
27
+ if (r === null)
28
+ throw new Error(`${JSON.stringify(t)} 应触发,得 null`);
29
+ if (typeof r !== 'string')
30
+ throw new Error(`返类型错: ${typeof r}`);
31
+ if (r.length < 2 || r.length > 24)
32
+ throw new Error(`长度越界: ${r.length}`);
24
33
  }
25
34
  });
26
- pass('3. 结构触发 — 含"查/搜/找/看看/推荐/告诉我/检索"', ()=>{
27
- for (const t of [
28
- '查一下 大理',
29
- '搜 普吉',
30
- '找清迈',
31
- '看看曼谷',
32
- '推荐 沙巴'
33
- ]){
35
+ pass('3. 结构触发 — 含"查/搜/找/看看/推荐/告诉我/检索"', () => {
36
+ for (const t of ['查一下 大理', '搜 普吉', '找清迈', '看看曼谷', '推荐 沙巴']) {
34
37
  const r = probePoi(t);
35
- if (r === null) throw new Error(`${JSON.stringify(t)} 应触发,得 null`);
38
+ if (r === null)
39
+ throw new Error(`${JSON.stringify(t)} 应触发,得 null`);
36
40
  }
37
41
  });
38
- pass('4. 内容触发 — 含"酒店/民宿/客栈/有什么/玩什么/有哪些"', ()=>{
39
- for (const t of [
40
- '大理酒店',
41
- '清迈民宿',
42
- '曼谷有什么',
43
- '丽江有哪些'
44
- ]){
42
+ pass('4. 内容触发 — 含"酒店/民宿/客栈/有什么/玩什么/有哪些"', () => {
43
+ for (const t of ['大理酒店', '清迈民宿', '曼谷有什么', '丽江有哪些']) {
45
44
  const r = probePoi(t);
46
- if (r === null) throw new Error(`${JSON.stringify(t)} 应触发,得 null`);
45
+ if (r === null)
46
+ throw new Error(`${JSON.stringify(t)} 应触发,得 null`);
47
47
  }
48
48
  });
49
- pass('5. 不触发 — 长问句(>24 字符 触发上限 isShort 拒)', ()=>{
49
+ pass('5. 不触发 — 长问句(>24 字符 触发上限 isShort 拒)', () => {
50
+ // 短查询直通(<=24)是设计意图,产品行为快照:任何短查询都返回原句做关键词。
51
+ // 因此"3.4 k"等英文短查询也返,不期望 null。
52
+ // 长问句(>24 字符)才是不触发场景。
50
53
  for (const t of [
51
- 'lorem ipsum dolor sit amet consect',
52
- '我想查询从北京到上海的高铁票价格'
53
- ]){
54
+ 'lorem ipsum dolor sit amet consect', // 35 字符
55
+ '我想查询从北京到上海的高铁票价格', // 16 字符 ≤ 24 短查询直通(返原句),产品行为
56
+ ]) {
54
57
  const r = probePoi(t);
55
58
  if (t.length > 24) {
56
- if (r !== null) throw new Error(`>24 字符 ${JSON.stringify(t)} 应不触发,得 ${JSON.stringify(r)}`);
57
- } else {
58
- if (r === null) throw new Error(`<=24 字符 ${JSON.stringify(t)} 应触发,得 null`);
59
+ if (r !== null)
60
+ throw new Error(`>24 字符 ${JSON.stringify(t)} 应不触发,得 ${JSON.stringify(r)}`);
61
+ }
62
+ else {
63
+ if (r === null)
64
+ throw new Error(`<=24 字符 ${JSON.stringify(t)} 应触发,得 null`);
59
65
  }
60
66
  }
61
67
  });
62
- pass('6. 不抛错 + 返回类型是 string 或 null(边界)', ()=>{
68
+ pass('6. 不抛错 + 返回类型是 string 或 null(边界)', () => {
63
69
  for (const t of [
64
70
  'a'.repeat(200),
65
71
  'a?'.repeat(50),
66
72
  '!@#',
67
73
  '中文' + 'a'.repeat(100),
68
- ' 前后空格 '
69
- ]){
74
+ ' 前后空格 ',
75
+ ]) {
70
76
  const r = probePoi(t);
71
77
  if (r !== null && typeof r !== 'string') {
72
78
  throw new Error(`返类型错: ${typeof r}`);
73
79
  }
74
80
  }
75
81
  });
76
- pass('7. 金标准对话噪音回归(2026-08-28 巡检:访谈答案/多段首查不再误触发)', ()=>{
82
+ pass('7. 金标准对话噪音回归(2026-08-28 巡检:访谈答案/多段首查不再误触发)', () => {
83
+ // 旧版 ≤24 直通把短访谈答案整句当关键词 → 垃圾 hbcli 调用 + 证据噪音
77
84
  assert.equal(probePoi('我的工作时间是UTC+4的早上10点到下午7点'), null, '访谈答案(>12 字含陈述动词)不触发');
78
85
  assert.equal(probePoi('明天有空'), null, '短句含陈述动词不触发');
86
+ // 多段行程首轮:动词宾语为句号/宾语为垃圾后缀 → 不触发(宁可不探,不垃圾探)
79
87
  assert.equal(probePoi('7.17周五22:40落地深圳,7.18早上去香港办银行开户&保险签约;争取7.18当天飞泰国普吉岛……8.10周一凌晨从深圳起飞,周一上班前到迪拜。请给我做机票和酒店的行程规划和推荐。'), null, '多段首查无 POI 信号不触发');
88
+ // 住宿名词后段优先:订了酒店:名称 → 抓名称而非「我订了」
80
89
  const booking = probePoi('我订了酒店:The Title East Wing Rawai,7.18入住 7.23 退房');
81
- if (!booking || !booking.includes('Title')) throw new Error(`订酒店应抓名称段,得 ${JSON.stringify(booking)}`);
90
+ if (!booking || !booking.includes('Title'))
91
+ throw new Error(`订酒店应抓名称段,得 ${JSON.stringify(booking)}`);
92
+ assert.equal(booking, 'The Title East Wing Rawai', '真实酒店名须原样回显(旧 24 字上界会截成 …Rawa 且无省略标记)');
82
93
  console.log(' 7a. 访谈答案/多段首查 → null OK');
83
94
  console.log(' 7b. 订酒店抓名称段(The Title…) OK');
84
95
  });
85
96
  console.log('\nprobePoi TESTS: 6 类 OK(不崩 + 5 类触发 + 1 类不触发返 null)');
86
-
87
-
88
- //# sourceURL=/Users/bytedance/work/gotry/ts/scripts/probe-poi-tests.ts