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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. package/README.md +102 -194
  2. package/README.zh-CN.md +115 -210
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-bootstrap.js +466 -35
  5. package/bin/gotry-inner.js +255 -36
  6. package/bin/gotry-process-liveness.d.ts +27 -0
  7. package/bin/gotry-process-liveness.js +97 -0
  8. package/bin/gotry-runtime-resolution.d.ts +1 -1
  9. package/bin/gotry-runtime-resolution.js +2 -2
  10. package/client/client.js +174 -0
  11. package/cordis.gotry-patch.yml +70 -93
  12. package/dist/capabilities/agent-reach-deep.js +45 -122
  13. package/dist/capabilities/agent-reach.js +63 -148
  14. package/dist/capabilities/anything.js +89 -75
  15. package/dist/capabilities/artifacts.js +123 -104
  16. package/dist/capabilities/channel-health.js +65 -45
  17. package/dist/capabilities/channel-registry.js +108 -87
  18. package/dist/capabilities/doctor.js +357 -235
  19. package/dist/capabilities/effect.js +223 -309
  20. package/dist/capabilities/fact-log.js +28 -14
  21. package/dist/capabilities/flyai.js +245 -156
  22. package/dist/capabilities/ground-transfer.js +509 -0
  23. package/dist/capabilities/hbcli.js +144 -148
  24. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  25. package/dist/capabilities/incident-log.js +131 -61
  26. package/dist/capabilities/model-override.js +30 -10
  27. package/dist/capabilities/opensky.js +54 -43
  28. package/dist/capabilities/resilience.js +50 -32
  29. package/dist/capabilities/session/action-cache.js +50 -44
  30. package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
  31. package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
  32. package/dist/capabilities/session/adapters/dida-portal.js +206 -0
  33. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  34. package/dist/capabilities/session/adapters/rail-12306.js +169 -112
  35. package/dist/capabilities/session/benchmark.js +85 -149
  36. package/dist/capabilities/session/extension-bridge.js +320 -259
  37. package/dist/capabilities/session/extension-channel.js +57 -76
  38. package/dist/capabilities/session/extension-distribution.js +115 -119
  39. package/dist/capabilities/session/extract.js +31 -21
  40. package/dist/capabilities/session/golden-score.js +55 -33
  41. package/dist/capabilities/session/health-watch.js +146 -154
  42. package/dist/capabilities/session/read-guard.js +55 -47
  43. package/dist/capabilities/session/static-flight-golden.js +49 -36
  44. package/dist/capabilities/session/transport.js +54 -61
  45. package/dist/capabilities/session/wizard.js +63 -93
  46. package/dist/capabilities/session-consent.js +143 -47
  47. package/dist/capabilities/session-login.js +95 -126
  48. package/dist/capabilities/session-search.js +391 -253
  49. package/dist/capabilities/sponsor-plugin.js +341 -0
  50. package/dist/capabilities/visa-policy.js +87 -73
  51. package/dist/capabilities/weather.js +163 -235
  52. package/dist/scripts/action-cache-tests.js +24 -59
  53. package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
  54. package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
  55. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  56. package/dist/scripts/agent-reach-tests.js +26 -18
  57. package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
  58. package/dist/scripts/anything-tests.js +58 -62
  59. package/dist/scripts/artifact-client-contract-tests.js +69 -0
  60. package/dist/scripts/artifacts-capability-tests.js +235 -0
  61. package/dist/scripts/async-collect.js +26 -15
  62. package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
  63. package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
  64. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
  65. package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
  66. package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
  67. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
  68. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
  69. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
  70. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
  71. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
  72. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
  73. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
  74. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
  75. package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
  76. package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
  77. package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
  78. package/dist/scripts/booking-executor-tests.js +80 -0
  79. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  80. package/dist/scripts/booking-saga-tests.js +61 -123
  81. package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
  82. package/dist/scripts/bootstrap-tests.js +1383 -128
  83. package/dist/scripts/build-changelog.js +89 -130
  84. package/dist/scripts/build-metrics-report.js +135 -143
  85. package/dist/scripts/changelog-tests.js +35 -82
  86. package/dist/scripts/channel-probe-tests.js +44 -116
  87. package/dist/scripts/channel-probe.js +84 -167
  88. package/dist/scripts/channel-registry-tests.js +97 -185
  89. package/dist/scripts/companion-tests.js +25 -70
  90. package/dist/scripts/dida-cookie-probe.js +87 -0
  91. package/dist/scripts/dida-sw-probe.js +114 -0
  92. package/dist/scripts/diff-test.js +17 -12
  93. package/dist/scripts/doctor-tests.js +428 -120
  94. package/dist/scripts/dsh-artifact-e2e.js +150 -0
  95. package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
  96. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  97. package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
  98. package/dist/scripts/dsh-runtime-closure.js +75 -63
  99. package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
  100. package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
  101. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  102. package/dist/scripts/effect-tests.js +165 -552
  103. package/dist/scripts/engine-run.js +1 -3
  104. package/dist/scripts/engine-tests.js +16 -10
  105. package/dist/scripts/evaluation-cadence-tests.js +69 -242
  106. package/dist/scripts/evaluation-contract-tests.js +193 -499
  107. package/dist/scripts/extension-distribution-cli.js +19 -15
  108. package/dist/scripts/extension-distribution-tests.js +98 -211
  109. package/dist/scripts/extension-tests.js +366 -389
  110. package/dist/scripts/fact-gate-tests.js +725 -263
  111. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  112. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  113. package/dist/scripts/flight-malformed-tests.js +159 -0
  114. package/dist/scripts/flyai-tests.js +325 -68
  115. package/dist/scripts/g5-guard-tests.js +131 -0
  116. package/dist/scripts/g5-guard.js +189 -0
  117. package/dist/scripts/gen-lunar-anchors.js +106 -0
  118. package/dist/scripts/gotry-backend-kernel-tests.js +79 -0
  119. package/dist/scripts/ground-transfer-tests.js +956 -0
  120. package/dist/scripts/hbcli-e2e-tests.js +71 -90
  121. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  122. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  123. package/dist/scripts/hbcli-tests.js +41 -115
  124. package/dist/scripts/health-watch-cli.js +42 -28
  125. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  126. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  127. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  128. package/dist/scripts/i18n-tests.js +16 -9
  129. package/dist/scripts/incident-tests.js +281 -87
  130. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  131. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  132. package/dist/scripts/issue-271-liveness-tests.js +547 -0
  133. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  134. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  135. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  136. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  137. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  138. package/dist/scripts/journey-tests.js +22 -27
  139. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  140. package/dist/scripts/kernel-manifest-gate.js +126 -0
  141. package/dist/scripts/kernel-manifest-tests.js +212 -0
  142. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  143. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  144. package/dist/scripts/kernel-manifest.js +369 -0
  145. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  146. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  147. package/dist/scripts/ledger-tests.js +325 -340
  148. package/dist/scripts/ledger-workflow-crash.js +10 -20
  149. package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
  150. package/dist/scripts/memory-capture-tests.js +242 -61
  151. package/dist/scripts/memory-decay-tests.js +18 -52
  152. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  153. package/dist/scripts/memory-lifecycle.js +196 -0
  154. package/dist/scripts/memory-metrics.js +24 -12
  155. package/dist/scripts/memory-value-report.js +474 -222
  156. package/dist/scripts/memory-value-tests.js +328 -0
  157. package/dist/scripts/metrics-report-tests.js +62 -199
  158. package/dist/scripts/model-override-e2e.js +66 -105
  159. package/dist/scripts/nightly-evidence-tests.js +64 -89
  160. package/dist/scripts/nightly-evidence.js +108 -111
  161. package/dist/scripts/nudge-digest.js +39 -28
  162. package/dist/scripts/onboarding-tests.js +63 -88
  163. package/dist/scripts/opensky-check.js +18 -13
  164. package/dist/scripts/opensky-tests.js +28 -28
  165. package/dist/scripts/persona-surface-guard-tests.js +37 -12
  166. package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
  167. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  168. package/dist/scripts/price-drift-tests.js +126 -227
  169. package/dist/scripts/price-drift-watch.js +209 -253
  170. package/dist/scripts/probe-poi-tests.js +52 -45
  171. package/dist/scripts/product-metrics.js +187 -273
  172. package/dist/scripts/publish-preverify.js +47 -41
  173. package/dist/scripts/realtime-pricing-tests.js +37 -76
  174. package/dist/scripts/replay-async.js +20 -18
  175. package/dist/scripts/replay-real.js +16 -18
  176. package/dist/scripts/replay.js +52 -82
  177. package/dist/scripts/session-attach-diagnose.js +16 -12
  178. package/dist/scripts/session-attach-poc.js +34 -37
  179. package/dist/scripts/session-benchmark.js +66 -147
  180. package/dist/scripts/session-dida-live-e2e.js +151 -0
  181. package/dist/scripts/session-extract-tests.js +14 -35
  182. package/dist/scripts/session-login.js +14 -13
  183. package/dist/scripts/session-tests.js +545 -583
  184. package/dist/scripts/sf-live-benchmark.js +92 -110
  185. package/dist/scripts/sf-live-cli-tests.js +2 -9
  186. package/dist/scripts/sf-soft-score-tests.js +19 -60
  187. package/dist/scripts/sf-summary-tests.js +149 -0
  188. package/dist/scripts/sf-summary.js +466 -84
  189. package/dist/scripts/skeleton-check.js +16 -14
  190. package/dist/scripts/skeleton-integration-test.js +11 -10
  191. package/dist/scripts/skills-contract-tests.js +51 -46
  192. package/dist/scripts/smoke-session-gate-tests.js +12 -20
  193. package/dist/scripts/smoke.js +541 -422
  194. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  195. package/dist/scripts/state-cli-tests.js +226 -101
  196. package/dist/scripts/state-cli.js +549 -212
  197. package/dist/scripts/static-golden-tests.js +46 -180
  198. package/dist/scripts/time-eval-tests.js +210 -192
  199. package/dist/scripts/travel-timeline-tests.js +29 -93
  200. package/dist/scripts/turn-handoff-collect-tests.js +46 -93
  201. package/dist/scripts/turn-handoff-collect.js +71 -99
  202. package/dist/scripts/turn-policy-tests.js +28 -29
  203. package/dist/scripts/typed-contract-canary.js +77 -162
  204. package/dist/scripts/tz-resolver-sanity.js +50 -0
  205. package/dist/scripts/tz-resolver-tests.js +584 -0
  206. package/dist/scripts/unified-tests.js +23 -19
  207. package/dist/scripts/visa-policy-tests.js +31 -44
  208. package/dist/scripts/weather-tests.js +121 -543
  209. package/dist/scripts/wish-channel-gate-tests.js +29 -86
  210. package/dist/scripts/write-gate-tests.js +522 -0
  211. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  212. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  213. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  214. package/dist/scripts/z3-race-tests.js +18 -12
  215. package/dist/src/artifact-gate.js +652 -221
  216. package/dist/src/backend/kernel.js +91 -0
  217. package/dist/src/backend/modules/booking-copilot.js +55 -0
  218. package/dist/src/backend/modules/booking-executor.js +124 -0
  219. package/dist/src/backend/modules/session-search.js +194 -0
  220. package/dist/src/benchmark-agent-conformance.js +296 -262
  221. package/dist/src/benchmark-environment-bridge.js +298 -413
  222. package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
  223. package/dist/src/benchmark-tool-isolation.js +94 -67
  224. package/dist/src/bookable-facts.js +299 -174
  225. package/dist/src/booking-saga.js +64 -120
  226. package/dist/src/booking-surface/availability-policy.js +443 -576
  227. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  228. package/dist/src/booking-surface/contracts.js +24 -80
  229. package/dist/src/booking-surface/dsh-planner.js +510 -281
  230. package/dist/src/booking-surface/dsh-plugin.js +17 -1
  231. package/dist/src/booking-surface/error-codes.js +82 -10
  232. package/dist/src/booking-surface/index.js +0 -3
  233. package/dist/src/booking-surface/profile.js +10 -54
  234. package/dist/src/booking-surface/recovery-chain.js +367 -0
  235. package/dist/src/booking-surface/runtime.js +765 -891
  236. package/dist/src/booking-surface/server.js +200 -251
  237. package/dist/src/booking-surface/startup.js +58 -54
  238. package/dist/src/booking-surface/validation.js +150 -218
  239. package/dist/src/bridge.js +20 -13
  240. package/dist/src/companions.js +48 -74
  241. package/dist/src/contracts.js +21 -43
  242. package/dist/src/dsh-llm.js +82 -120
  243. package/dist/src/engine.js +253 -239
  244. package/dist/src/evaluation-cadence.js +72 -209
  245. package/dist/src/evaluation-contracts.js +220 -843
  246. package/dist/src/flight-pack-adapter.js +54 -0
  247. package/dist/src/flight-pack-contract.js +2 -0
  248. package/dist/src/gotry-backend.js +70 -0
  249. package/dist/src/hotel-date-gate.js +118 -0
  250. package/dist/src/i18n.js +18 -7
  251. package/dist/src/index.js +1425 -1629
  252. package/dist/src/journey.js +132 -81
  253. package/dist/src/ledger-repair-apply.js +538 -0
  254. package/dist/src/ledger-repair-plan.js +463 -0
  255. package/dist/src/loop.js +257 -166
  256. package/dist/src/memory-capture.js +180 -32
  257. package/dist/src/memory-decay.js +30 -14
  258. package/dist/src/memory-lifecycle.js +1310 -0
  259. package/dist/src/memory-utility.js +27 -40
  260. package/dist/src/mock-llm.js +36 -61
  261. package/dist/src/model.js +81 -36
  262. package/dist/src/realtime-pricing.js +63 -72
  263. package/dist/src/slot-spec.js +84 -106
  264. package/dist/src/state-ledger.js +310 -471
  265. package/dist/src/subagent-job-id-guard.js +58 -0
  266. package/dist/src/time-anchor.js +231 -33
  267. package/dist/src/tool-packet.js +20 -8
  268. package/dist/src/travel-slots.js +58 -35
  269. package/dist/src/travel-timeline.js +44 -63
  270. package/dist/src/turn-deadline.js +121 -127
  271. package/dist/src/turn-policy.js +61 -89
  272. package/dist/src/tz-resolver.js +143 -0
  273. package/dist/src/unified.js +504 -381
  274. package/dist/src/wish-pool.js +39 -14
  275. package/dist/src/write-gate.js +495 -0
  276. package/dist/src/z3-shared.js +273 -7
  277. package/extension/README.md +4 -3
  278. package/extension/background.js +125 -14
  279. package/extension/content-bridge.js +23 -1
  280. package/extension/content-main.js +15 -4
  281. package/extension/manifest.json +16 -8
  282. package/package.json +251 -220
  283. package/ts/capabilities/agent-reach.ts +4 -4
  284. package/ts/capabilities/anything.ts +1 -1
  285. package/ts/capabilities/artifacts.ts +46 -9
  286. package/ts/capabilities/flyai.ts +156 -37
  287. package/ts/capabilities/hbcli.ts +1 -1
  288. package/ts/capabilities/incident-log.ts +88 -59
  289. package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
  290. package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
  291. package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
  292. package/ts/capabilities/session/extension-bridge.ts +226 -101
  293. package/ts/capabilities/session/extension-channel.ts +22 -9
  294. package/ts/capabilities/session/wizard.ts +2 -2
  295. package/ts/capabilities/session-consent.ts +98 -14
  296. package/ts/capabilities/session-login.ts +1 -0
  297. package/ts/capabilities/session-search.ts +315 -31
  298. package/ts/dsh-runtime/vendor/README.md +8 -4
  299. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
  300. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
  301. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
  302. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
  303. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
  304. package/ts/package.json +236 -16
  305. package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
  306. package/ts/scripts/state-cli.ts +418 -51
  307. package/ts/src/artifact-gate.ts +561 -15
  308. package/ts/src/benchmark-environment-bridge.ts +37 -20
  309. package/ts/src/bookable-facts.ts +183 -7
  310. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  311. package/ts/src/booking-surface/dsh-planner.ts +240 -32
  312. package/ts/src/booking-surface/dsh-plugin.js +17 -1
  313. package/ts/src/booking-surface/error-codes.ts +75 -0
  314. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  315. package/ts/src/booking-surface/server.ts +84 -51
  316. package/ts/src/booking-surface/validation.ts +2 -0
  317. package/ts/src/contracts.ts +12 -2
  318. package/ts/src/dsh-llm.ts +4 -8
  319. package/ts/src/index.ts +609 -90
  320. package/ts/src/loop.ts +116 -7
  321. package/ts/src/memory-capture.ts +227 -3
  322. package/ts/src/mock-llm.ts +4 -8
  323. package/ts/src/model.ts +88 -2
  324. package/ts/src/state-ledger.ts +47 -29
  325. package/ts/src/subagent-job-id-guard.ts +72 -0
  326. package/ts/src/time-anchor.ts +217 -13
  327. package/ts/src/unified.ts +316 -54
@@ -1,31 +1,33 @@
1
+ /**
2
+ * Turn routing & policy table tests (ADR-24 v2).
3
+ * 分类器是纯函数(Tier 0,零 LLM 零 IO),表测锁定 v1 规则面;
4
+ * 首条 fixture 是 2026-09-02 失败轨迹的用户原文——canonical 深规划
5
+ * case 必须命中 deep-planning,这是整个重设计的回归锚点。
6
+ */
1
7
  import assert from 'node:assert/strict';
2
- import { classifyTurn, extractTurnSignals, TURN_POLICIES, turnPolicyFor } from '../src/turn-policy.js';
3
- const TRAJECTORY_MESSAGE = '2026年我还有6天IRW额度 ,我准备再请几天假,在国内待个十几天。' + '其中10.3要去湖南衡阳参加同学婚礼。其他我没有特别的要求,请根据我的实际情况,偏好,外部环境等因素,给我安排行程';
8
+ import { classifyTurn, extractTurnSignals, TURN_POLICIES, turnPolicyFor, } from '../src/turn-policy.js';
9
+ // ---- 分类表(规则面快照) ---------------------------------------------------
10
+ // 失败轨迹原文:13 天行程 + 10.3 婚礼 + 请假 + IRW → 必须转后台。
11
+ const TRAJECTORY_MESSAGE = '2026年我还有6天IRW额度 ,我准备再请几天假,在国内待个十几天。'
12
+ + '其中10.3要去湖南衡阳参加同学婚礼。其他我没有特别的要求,请根据我的实际情况,偏好,外部环境等因素,给我安排行程';
4
13
  assert.equal(classifyTurn(TRAJECTORY_MESSAGE), 'deep-planning');
5
- assert.equal(classifyTurn('9.26到10.12在国内玩,中间要参加同学婚礼'), 'deep-planning');
6
- assert.equal(classifyTurn('国庆请假带父母去新疆,大概十几天'), 'deep-planning');
14
+ assert.equal(classifyTurn('9.26到10.12在国内玩,中间要参加同学婚礼'), 'deep-planning'); // 双绝对日期+约束,跨度16天
15
+ assert.equal(classifyTurn('国庆请假带父母去新疆,大概十几天'), 'deep-planning'); // 跨度词+双约束
7
16
  assert.equal(classifyTurn('帮我查一下明天深圳的天气'), 'quick');
8
17
  assert.equal(classifyTurn('你好'), 'quick');
9
- assert.equal(classifyTurn('帮我看看10.1去杭州的高铁票'), 'sync-planning');
10
- assert.equal(classifyTurn('3天后出发,帮我查下天气'), 'sync-planning');
11
- assert.equal(classifyTurn('把这段翻译成英文:会议纪要如下……省略若干字'.repeat(3)), 'sync-planning');
18
+ assert.equal(classifyTurn('帮我看看10.1去杭州的高铁票'), 'sync-planning'); // 单日期零约束 → 默认中间档
19
+ assert.equal(classifyTurn('3天后出发,帮我查下天气'), 'sync-planning'); // 短跨度词 → 不进 quick 也不进 deep
20
+ assert.equal(classifyTurn('把这段翻译成英文:会议纪要如下……省略若干字'.repeat(3)), 'sync-planning'); // 长但零信号
21
+ // ---- 信号提取 ---------------------------------------------------------------
12
22
  const full = extractTurnSignals('2026-10-03 出发');
13
- assert.deepEqual(full.absoluteDates, [
14
- {
15
- year: 2026,
16
- month: 10,
17
- day: 3
18
- }
19
- ]);
23
+ assert.deepEqual(full.absoluteDates, [{ year: 2026, month: 10, day: 3 }]);
20
24
  const md = extractTurnSignals('10月3日到衡阳,10.5回深圳');
21
25
  assert.equal(md.absoluteDates.length, 2);
22
26
  assert.equal(md.spanDays, 2);
23
- assert.deepEqual(md.absoluteDates[0], {
24
- year: null,
25
- month: 10,
26
- day: 3
27
- });
27
+ assert.deepEqual(md.absoluteDates[0], { year: null, month: 10, day: 3 });
28
+ // 无效月/日过滤;时间(冒号)与版本号外的数字不产日期
28
29
  assert.equal(extractTurnSignals('13.45 与 22:40 都是数字').absoluteDates.length, 0);
30
+ // 跨度词:按强度取先
29
31
  assert.equal(extractTurnSignals('待十几天').spanDays, 12);
30
32
  assert.equal(extractTurnSignals('待半个月').spanDays, 15);
31
33
  assert.equal(extractTurnSignals('待一个月').spanDays, 30);
@@ -33,24 +35,21 @@ assert.equal(extractTurnSignals('大概两周').spanDays, 14);
33
35
  assert.equal(extractTurnSignals('大概一周').spanDays, 7);
34
36
  assert.equal(extractTurnSignals('还有6天额度').spanDays, 6);
35
37
  assert.equal(extractTurnSignals('没有跨度').spanDays, null);
38
+ // 绝对日期 ≥2 时跨度词不参与
36
39
  const both = extractTurnSignals('10.1 到 10.9 玩十几天');
37
40
  assert.equal(both.spanDays, 8);
38
- assert.deepEqual(extractTurnSignals('婚礼加IRW,还要请假').constraintHits, [
39
- '婚礼',
40
- 'IRW',
41
- '请假'
42
- ]);
41
+ // 约束词:命中去重、按词表序
42
+ assert.deepEqual(extractTurnSignals('婚礼加IRW,还要请假').constraintHits, ['婚礼', 'IRW', '请假']);
43
43
  assert.deepEqual(extractTurnSignals('没有任何约束词在这里').constraintHits, []);
44
- assert.equal(classifyTurn('10.3 婚礼那天衡阳天气怎么样?穿什么'), 'sync-planning');
44
+ // user 消息里最常见的误触:quick 判据必须同时满足零日期/零约束/零跨度/短
45
+ assert.equal(classifyTurn('10.3 婚礼那天衡阳天气怎么样?穿什么'), 'sync-planning'); // 有日期+约束 → 不冒进 quick
46
+ // ---- policy 表 ---------------------------------------------------------------
45
47
  assert.equal(TURN_POLICIES['deep-planning'].exit, 'handoff');
46
48
  assert.equal(TURN_POLICIES['sync-planning'].exit, 'converge');
47
49
  assert.equal(TURN_POLICIES['quick'].exit, 'converge');
48
- for (const policy of Object.values(TURN_POLICIES)){
50
+ for (const policy of Object.values(TURN_POLICIES)) {
49
51
  assert.ok(policy.hardMs > policy.softMs, 'hard must exceed soft');
50
52
  assert.ok(policy.softMs > 0 && policy.hardMs > 0);
51
53
  }
52
54
  assert.deepEqual(turnPolicyFor('quick'), TURN_POLICIES['quick']);
53
55
  console.log('turn policy tests: OK (routing table incl. trajectory verbatim, date/span extraction, policy shape)');
54
-
55
-
56
- //# sourceURL=ts/scripts/turn-policy-tests.ts
@@ -1,3 +1,22 @@
1
+ /**
2
+ * D-30 普通模型 canary 运行器(issue #112 验收,tool-orchestration-design §4⑥)。
3
+ *
4
+ * 量什么:普通 LLM 面对投影后的工具 JSON Schema,能否**一次成型**产出合法参数——
5
+ * 这是 typed 参数契约迁移(D-30)要解决的核心问题(blob 时代强弱模型差距全部
6
+ * 暴露在「猜参数形状」上)。
7
+ *
8
+ * 怎么量:真实 LLM(env 三件套 LLM_API_KEY/LLM_BASE_URL/LLM_MODEL,或仓库 .env)
9
+ * + 工具投影 schema(defineTool 后的 parameters,与模型所见完全一致)+ tool_choice
10
+ * 强制单工具 → 模型出参 → `validateJsonSchemaValue`(与 dsh defineTool execute 前
11
+ * 同款校验)→ 违例为零 = 该例一次成型。
12
+ *
13
+ * 不执行工具:零检索副作用、零站点请求——canary 只量参数形态,不量业务结果。
14
+ *
15
+ * 达标线:工具调用一次成型率 ≥90%(10 例容 1 失);语义正确性(城市/日期/kind)
16
+ * 作为二级信号同报,不进门。
17
+ *
18
+ * 运行(在仓根或 ts/):LLM 三件套已配 → npx tsx ts/scripts/typed-contract-canary.ts
19
+ */
1
20
  import assert from 'node:assert/strict';
2
21
  import { readFileSync, existsSync, mkdtempSync } from 'node:fs';
3
22
  import { tmpdir } from 'node:os';
@@ -6,6 +25,7 @@ import { fileURLToPath } from 'node:url';
6
25
  import { validateJsonSchemaValue } from '@deepseek-ai/dsh-tools';
7
26
  import { apply } from '../src/index.js';
8
27
  const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
28
+ // --- LLM 三件套:env 优先,回退仓库 .env(只取值,永不回显) ---
9
29
  function loadEnvTriple() {
10
30
  const env = process.env;
11
31
  let key = env.LLM_API_KEY ?? '';
@@ -13,95 +33,47 @@ function loadEnvTriple() {
13
33
  let model = env.LLM_MODEL ?? '';
14
34
  const envFile = join(ROOT, '.env');
15
35
  if (existsSync(envFile)) {
16
- for (const line of readFileSync(envFile, 'utf-8').split('\n')){
36
+ for (const line of readFileSync(envFile, 'utf-8').split('\n')) {
17
37
  const m = /^([A-Z_]+)=(.*)$/.exec(line.trim());
18
- if (!m) continue;
38
+ if (!m)
39
+ continue;
19
40
  const [, k, v] = m;
20
- if (k === 'LLM_API_KEY' && !key) key = v.trim();
21
- if (k === 'LLM_BASE_URL' && !base) base = v.trim();
22
- if (k === 'LLM_MODEL' && !model) model = v.trim();
41
+ if (k === 'LLM_API_KEY' && !key)
42
+ key = v.trim();
43
+ if (k === 'LLM_BASE_URL' && !base)
44
+ base = v.trim();
45
+ if (k === 'LLM_MODEL' && !model)
46
+ model = v.trim();
23
47
  }
24
48
  }
25
49
  assert.ok(key && base && model, 'LLM_API_KEY/LLM_BASE_URL/LLM_MODEL 必须已配(env 或 .env)');
26
- return {
27
- key,
28
- base,
29
- model
30
- };
50
+ return { key, base, model };
31
51
  }
52
+ // --- 捕获插件注册表(隔离 stateRoot:canary 不写任何共享状态;sessionAccess=off 免审批) ---
32
53
  const stateRoot = mkdtempSync(join(tmpdir(), 'gotry-canary-state-'));
33
54
  const registered = [];
34
55
  const ctx = {
35
- tools: {
36
- register: (t)=>registered.push(t)
37
- },
38
- systemPrompt: {
39
- variable: ()=>()=>''
40
- },
41
- on: ()=>()=>{}
56
+ tools: { register: (t) => registered.push(t) },
57
+ systemPrompt: { variable: () => () => '' },
58
+ on: () => () => { },
42
59
  };
43
- apply(ctx, {
44
- stateRoot,
45
- timeoutMs: 30_000,
46
- hbcliBin: 'hbcli-not-on-path',
47
- sessionAccess: 'off'
48
- });
49
- const byName = (n)=>{
50
- const t = registered.find((x)=>x.name === n);
60
+ apply(ctx, { stateRoot, timeoutMs: 30_000, hbcliBin: 'hbcli-not-on-path', sessionAccess: 'off' });
61
+ const byName = (n) => {
62
+ const t = registered.find(x => x.name === n);
51
63
  assert.ok(t, `工具 ${n} 应已注册`);
52
64
  return t;
53
65
  };
54
66
  const CASES = [
55
- {
56
- label: '机·票(城市对+日期)',
57
- tool: 'gotry_flyai_search',
58
- prompt: '帮我查一下 10 1 日从上海飞丽江的机票'
59
- },
60
- {
61
- label: '火车票',
62
- tool: 'gotry_flyai_search',
63
- prompt: '10 1 日上海到昆明的火车票帮我查一下'
64
- },
65
- {
66
- label: '酒店(带档期)',
67
- tool: 'gotry_flyai_search',
68
- prompt: '查一下大理 10 月 1 日入住、10 月 3 日退房的酒店'
69
- },
70
- {
71
- label: '酒店(摸底,无档期)',
72
- tool: 'gotry_flyai_search',
73
- prompt: '先看看大理有哪些酒店'
74
- },
75
- {
76
- label: '天气预报',
77
- tool: 'gotry_weather_check',
78
- prompt: '大理这几天天气怎么样'
79
- },
80
- {
81
- label: '酒店实时源(hbcli)',
82
- tool: 'gotry_hotel_search',
83
- prompt: '查一下大理的酒店,入住下周五,住三晚'
84
- },
85
- {
86
- label: '会话面机票(登录态)',
87
- tool: 'gotry_session_search',
88
- prompt: '用我的携程账号查 10 月 1 日上海到丽江的机票'
89
- },
90
- {
91
- label: '目的地候选库',
92
- tool: 'gotry_anything_search',
93
- prompt: '大连在你们的目的地库里吗?帮我查一下'
94
- },
95
- {
96
- label: 'GitHub 搜索',
97
- tool: 'gotry_github_search',
98
- prompt: '在 GitHub 上搜一下 agent-reach 这个项目'
99
- },
100
- {
101
- label: '网页读取',
102
- tool: 'gotry_web_search',
103
- prompt: '帮我读一下 https://example.com 这个页面的内容'
104
- }
67
+ { label: '机·票(城市对+日期)', tool: 'gotry_flyai_search', prompt: '帮我查一下 10 月 1 日从上海飞丽江的机票' },
68
+ { label: '火车票', tool: 'gotry_flyai_search', prompt: '10 月 1 日上海到昆明的火车票帮我查一下' },
69
+ { label: '酒店(带档期)', tool: 'gotry_flyai_search', prompt: '查一下大理 10 月 1 日入住、10 月 3 日退房的酒店' },
70
+ { label: '酒店(摸底,无档期)', tool: 'gotry_flyai_search', prompt: '先看看大理有哪些酒店' },
71
+ { label: '天气预报', tool: 'gotry_weather_check', prompt: '大理这几天天气怎么样' },
72
+ { label: '酒店实时源(hbcli)', tool: 'gotry_hotel_search', prompt: '查一下大理的酒店,入住下周五,住三晚' },
73
+ { label: '会话面机票(登录态)', tool: 'gotry_session_search', prompt: '用我的携程账号查 10 月 1 日上海到丽江的机票' },
74
+ { label: '目的地候选库', tool: 'gotry_anything_search', prompt: '大连在你们的目的地库里吗?帮我查一下' },
75
+ { label: 'GitHub 搜索', tool: 'gotry_github_search', prompt: ' GitHub 上搜一下 agent-reach 这个项目' },
76
+ { label: '网页读取', tool: 'gotry_web_search', prompt: '帮我读一下 https://example.com 这个页面的内容' },
105
77
  ];
106
78
  async function callLlmMessages(cfg, toolName, messages) {
107
79
  const tool = byName(toolName);
@@ -109,32 +81,15 @@ async function callLlmMessages(cfg, toolName, messages) {
109
81
  const body = {
110
82
  model: cfg.model,
111
83
  messages,
112
- tools: [
113
- {
114
- type: 'function',
115
- function: {
116
- name: tool.name,
117
- description: tool.description,
118
- parameters: tool.parameters
119
- }
120
- }
121
- ],
122
- tool_choice: {
123
- type: 'function',
124
- function: {
125
- name: tool.name
126
- }
127
- },
128
- temperature: 0
84
+ tools: [{ type: 'function', function: { name: tool.name, description: tool.description, parameters: tool.parameters } }],
85
+ tool_choice: { type: 'function', function: { name: tool.name } },
86
+ temperature: 0,
129
87
  };
130
88
  const res = await fetch(url, {
131
89
  method: 'POST',
132
- headers: {
133
- 'content-type': 'application/json',
134
- authorization: `Bearer ${cfg.key}`
135
- },
90
+ headers: { 'content-type': 'application/json', authorization: `Bearer ${cfg.key}` },
136
91
  body: JSON.stringify(body),
137
- signal: AbortSignal.timeout(60_000)
92
+ signal: AbortSignal.timeout(60_000),
138
93
  });
139
94
  const bodyText = await res.text();
140
95
  assert.equal(res.status, 200, `LLM HTTP ${res.status}: ${bodyText.slice(0, 200)}`);
@@ -144,111 +99,74 @@ async function callLlmMessages(cfg, toolName, messages) {
144
99
  if (!tc?.function?.arguments) {
145
100
  const text = String(msg.content ?? '');
146
101
  assert.ok(/年份|日期|确认|2024|2025|2026/.test(text), `模型既未调工具也未按拒绝指引向用户确认: ${text.slice(0, 120)}`);
147
- return {
148
- args: undefined,
149
- callId: 'text-reply',
150
- text,
151
- textReply: true
152
- };
102
+ return { args: undefined, callId: 'text-reply', text, textReply: true };
153
103
  }
154
- return {
155
- args: JSON.parse(tc.function.arguments),
156
- callId: tc.id ?? 'canary-call',
157
- textReply: false
158
- };
104
+ return { args: JSON.parse(tc.function.arguments), callId: tc.id ?? 'canary-call', textReply: false };
159
105
  }
160
106
  async function main() {
161
107
  const cfg = loadEnvTriple();
162
108
  console.log(`typed-contract canary:model=${cfg.model} 已配(值不回显);用例 ${CASES.length} 条,达标线 ≥90% 一次成型\n`);
163
109
  let pass = 0;
164
110
  const failures = [];
165
- for (const c of CASES){
111
+ for (const c of CASES) {
166
112
  const tool = byName(c.tool);
167
113
  process.stdout.write(`- ${c.label} → ${c.tool} … `);
168
114
  try {
169
115
  const { args } = await callLlmMessages(cfg, c.tool, [
170
- {
171
- role: 'system',
172
- content: '你是 GoTry 旅行助手。需要查数据时必须调用提供的工具,参数从用户话里取,不要编造。'
173
- },
174
- {
175
- role: 'user',
176
- content: c.prompt
177
- }
116
+ { role: 'system', content: '你是 GoTry 旅行助手。需要查数据时必须调用提供的工具,参数从用户话里取,不要编造。' },
117
+ { role: 'user', content: c.prompt },
178
118
  ]);
179
119
  const violations = validateJsonSchemaValue(tool.parameters, args);
180
120
  if (violations.length === 0) {
181
121
  pass++;
182
122
  console.log(`PASS 一次成型 ${JSON.stringify(args).slice(0, 120)}`);
183
- } else {
123
+ }
124
+ else {
184
125
  failures.push(`${c.label}: schema 违例 ${violations.join(';')}`);
185
126
  console.log(`FAIL schema 违例: ${violations.join(';').slice(0, 160)}`);
186
127
  }
187
- } catch (e) {
128
+ }
129
+ catch (e) {
188
130
  failures.push(`${c.label}: ${e.message.slice(0, 160)}`);
189
131
  console.log(`FAIL ${e.message.slice(0, 140)}`);
190
132
  }
191
133
  }
134
+ // ---------------------------------------------------------------
135
+ // 验收②(issue #140):畸形/越界调用被宿主权拒绝后,模型按 violations 自纠。
136
+ // 确定性播种:预置一次带过去日期的被拒调用与结构化拒绝结果(tool 角色),
137
+ // 验证模型从拒绝中自纠出「schema 合规 + 日期非过去」的参数。只校验不执行(零副作用)。
138
+ // ---------------------------------------------------------------
192
139
  {
193
140
  const tool = byName('gotry_flyai_search');
194
141
  const today = new Date().toISOString().slice(0, 10);
195
142
  try {
196
143
  const messages = [
197
- {
198
- role: 'system',
199
- content: '你是 GoTry 旅行助手。需要查数据时必须调用提供的工具,参数从用户话里取,不要编造。'
200
- },
201
- {
202
- role: 'user',
203
- content: '帮我查一下 10 月 1 日从上海飞丽江的机票'
204
- },
205
- {
206
- role: 'assistant',
207
- content: null,
208
- tool_calls: [
209
- {
210
- id: 'seed-reject',
211
- type: 'function',
212
- function: {
213
- name: 'gotry_flyai_search',
214
- arguments: JSON.stringify({
215
- kind: 'flight',
216
- from: '上海',
217
- to: '丽江',
218
- date: '2024-10-01'
219
- })
220
- }
221
- }
222
- ]
223
- },
224
- {
225
- role: 'tool',
226
- tool_call_id: 'seed-reject',
227
- content: JSON.stringify({
228
- ok: false,
229
- verdict: 'error',
230
- summary: `未发起查询:日期 2024-10-01 已是过去(今天 ${today}),过去不存在在售机票。多为用户时间表达未带年份所致——向用户确认年份(或按未来最近的同月日修正)后再查。`
231
- })
232
- }
144
+ { role: 'system', content: '你是 GoTry 旅行助手。需要查数据时必须调用提供的工具,参数从用户话里取,不要编造。' },
145
+ { role: 'user', content: '帮我查一下 10 月 1 日从上海飞丽江的机票' },
146
+ { role: 'assistant', content: null, tool_calls: [{ id: 'seed-reject', type: 'function', function: { name: 'gotry_flyai_search', arguments: JSON.stringify({ kind: 'flight', from: '上海', to: '丽江', date: '2024-10-01' }) } }] },
147
+ { role: 'tool', tool_call_id: 'seed-reject', content: JSON.stringify({ ok: false, verdict: 'error', summary: `未发起查询:日期 2024-10-01 已是过去(今天 ${today}),过去不存在在售机票。多为用户时间表达未带年份所致——向用户确认年份(或按未来最近的同月日修正)后再查。` }) },
233
148
  ];
234
149
  const reply = await callLlmMessages(cfg, 'gotry_flyai_search', messages);
235
150
  const violations = reply.args ? validateJsonSchemaValue(tool.parameters, reply.args) : [];
236
151
  if (reply.textReply) {
237
152
  assert.match(reply.text ?? '', /年份|日期|确认/, '文字形态应向用户确认年份/日期(契约允许的自纠)');
238
153
  console.log('自纠回路(验收②):模型按拒绝指引转为向用户确认年份(文字形态,契约允许)');
239
- } else {
154
+ }
155
+ else {
240
156
  assert.equal(violations.length, 0, `自纠出参 schema 违例: ${violations.join(';')}`);
241
157
  assert.ok(reply.args && reply.args.date && reply.args.date >= today, `自纠后日期应为今天或未来,实际 ${JSON.stringify(reply.args).slice(0, 80)}`);
242
158
  console.log(`自纠回路(验收②):模型按拒绝自纠出参 → PASS(${JSON.stringify(reply.args).slice(0, 100)})`);
243
159
  }
244
- } catch (e) {
160
+ }
161
+ catch (e) {
245
162
  failures.push(`验收② 自纠回路异常: ${e.message.slice(0, 140)}`);
246
163
  console.log(`FAIL 自纠回路异常(计入失败,不中断报告): ${e.message.slice(0, 140)}`);
247
164
  }
248
165
  }
249
- const rate = Math.round(pass / CASES.length * 100);
166
+ const rate = Math.round((pass / CASES.length) * 100);
250
167
  console.log(`\n一次成型率:${pass}/${CASES.length} = ${rate}%(达标线 90%)`);
251
- if (failures.length) console.log('失败明细:\n' + failures.map((f)=>` - ${f}`).join('\n'));
168
+ if (failures.length)
169
+ console.log('失败明细:\n' + failures.map(f => ` - ${f}`).join('\n'));
252
170
  if (rate < 90) {
253
171
  console.error('TYPED CONTRACT CANARY FAIL(不达标不合入)');
254
172
  process.exit(1);
@@ -256,6 +174,3 @@ async function main() {
256
174
  console.log('TYPED CONTRACT CANARY OK');
257
175
  }
258
176
  await main();
259
-
260
-
261
- //# sourceURL=ts/scripts/typed-contract-canary.ts
@@ -0,0 +1,50 @@
1
+ // Quick sanity check for tz-resolver. Run with: TZ=UTC npx tsx scripts/tz-resolver-sanity.ts
2
+ import { resolveOffsetForLocalDate } from '../src/tz-resolver.js';
3
+ const cases = [
4
+ // Asia/Shanghai has no DST throughout the year
5
+ ['Asia/Shanghai', '2026-07-18', '14:45', 480],
6
+ ['Asia/Shanghai', '2026-01-01', '09:00', 480],
7
+ ['Asia/Tokyo', '2026-07-04', '09:00', 540],
8
+ ['Asia/Hong_Kong', '2026-07-18', '14:45', 480],
9
+ ['Asia/Bangkok', '2026-08-09', '23:55', 420],
10
+ ['Asia/Singapore', '2026-08-09', '23:55', 480],
11
+ ['Asia/Dubai', '2026-07-18', '00:45', 240],
12
+ // America/New_York DST: EST = -5, EDT = -4. 2026 spring-forward = 2026-03-08, fall-back = 2026-11-01
13
+ ['America/New_York', '2026-03-07', '14:00', -300], // day before spring forward -> EST
14
+ ['America/New_York', '2026-03-09', '14:00', -240], // day after spring forward -> EDT
15
+ ['America/New_York', '2026-06-15', '09:00', -240], // summer -> EDT
16
+ ['America/New_York', '2026-12-15', '09:00', -300], // winter -> EST
17
+ ['America/Los_Angeles', '2026-06-15', '14:00', -420],
18
+ ['UTC', '2026-07-18', '12:00', 0],
19
+ ['Europe/London', '2026-06-15', '14:00', 60],
20
+ ['Europe/London', '2026-01-15', '14:00', 0],
21
+ ];
22
+ let ok = 0, fail = 0;
23
+ for (const [zone, ymd, hhmm, expected] of cases) {
24
+ const r = resolveOffsetForLocalDate(zone, ymd, hhmm);
25
+ const pass = r.ok && r.offsetMin === expected;
26
+ if (pass)
27
+ ok++;
28
+ else {
29
+ fail++;
30
+ console.log('FAIL', zone, ymd, hhmm, 'expected', expected, 'got', r.ok ? r.offsetMin : r);
31
+ }
32
+ }
33
+ const negatives = [
34
+ ['Foo/Bar', '2026-07-18', '14:45', 'unknown_zone'],
35
+ ['America/New_York', '2026-03-08', '02:30', 'gap_nonexistent'], // spring forward day
36
+ ['America/New_York', '2026-11-01', '01:30', 'overlap_ambiguous'], // fall back day
37
+ ];
38
+ for (const [zone, ymd, hhmm, expected] of negatives) {
39
+ const r = resolveOffsetForLocalDate(zone, ymd, hhmm);
40
+ const pass = !r.ok && r.kind === expected;
41
+ if (pass)
42
+ ok++;
43
+ else {
44
+ fail++;
45
+ console.log('FAIL', zone, ymd, hhmm, 'expected', expected, 'got', r.ok ? `ok(${r.offsetMin})` : r.kind);
46
+ }
47
+ }
48
+ console.log(`\n${ok}/${ok + fail} sanity ok`);
49
+ if (fail > 0)
50
+ process.exit(1);