@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,78 +1,59 @@
1
- import { parseAbsoluteDate, ymd } from './time-anchor.js';
1
+ /**
2
+ * 旅行时间线(memory-design M4 层,P1):「去过哪、何时、和谁」的 append-only 事实层。
3
+ *
4
+ * 立场(memory-design §1):确定性事实归代码——日期解析复用 slot-spec(锚点卡词表+绝对),
5
+ * 词表外 unresolved 不猜;每条事件必须带 evidence(用户原话或 wish 确认),溯源 P0。
6
+ * 消费:出发地三级解析(未来行程→时间线→问用户)/「去过不再推」排序通道/
7
+ * 回流率分子(verified_outcome ⟺ timeline 有对应行程)。
8
+ * 多用户前向兼容:append-only + 稳定 trip_id,账本化只换存储面(RFC §6.5)。
9
+ */
10
+ import { ymd } from './time-anchor.js';
2
11
  import { resolveSlotDate } from './slot-spec.js';
12
+ /** 相对/模糊表达 → 绝对日期(守门:词表外返回 null,调用方必须拒收而非猜) */
3
13
  export function resolveTimelineDate(expr, anchor) {
4
14
  return resolveSlotDate(expr, anchor).date;
5
15
  }
16
+ /** 语义主键:同目的地+同 start+同 source = 同一行程(重放 no-op) */
6
17
  export function makeTripId(ev) {
7
18
  return `${ev.destination}|${ev.start}|${ev.source}`.replace(/\s+/g, '_');
8
19
  }
20
+ /**
21
+ * 追加守门(纯函数,不改入参):
22
+ * - destination/evidence 必填,start 必须已是绝对日期(YYYY-MM-DD),否则拒收(null);
23
+ * - end < start 拒收;
24
+ * - 同 trip_id 已存在 → no-op(返回 appended:false,幂等);
25
+ * - 同目的地日期区间重叠(不同 trip_id)→ 拒收(冲突即停,由人裁决)。
26
+ */
9
27
  export function appendTrip(events, ev) {
10
- if (!ev.destination?.trim()) return {
11
- events,
12
- appended: false,
13
- reason: 'destination 必填'
14
- };
15
- if (!ev.evidence?.trim()) return {
16
- events,
17
- appended: false,
18
- reason: 'evidence 必填(用户原话或 wish 确认指针)'
19
- };
20
- if (!/^\d{4}-\d{2}-\d{2}$/.test(ev.start)) return {
21
- events,
22
- appended: false,
23
- reason: 'start 必须为 YYYY-MM-DD(词表外日期由上游解析,不猜)'
24
- };
25
- if (ev.end && ev.end < ev.start) return {
26
- events,
27
- appended: false,
28
- reason: 'end 早于 start'
29
- };
28
+ if (!ev.destination?.trim())
29
+ return { events, appended: false, reason: 'destination 必填' };
30
+ if (!ev.evidence?.trim())
31
+ return { events, appended: false, reason: 'evidence 必填(用户原话或 wish 确认指针)' };
32
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(ev.start))
33
+ return { events, appended: false, reason: 'start 必须为 YYYY-MM-DD(词表外日期由上游解析,不猜)' };
34
+ if (ev.end && ev.end < ev.start)
35
+ return { events, appended: false, reason: 'end 早于 start' };
30
36
  const tripId = makeTripId(ev);
31
- if (events.some((e)=>e.trip_id === tripId)) return {
32
- events,
33
- appended: false,
34
- tripId
35
- };
36
- const overlap = events.find((e)=>e.destination === ev.destination && !(e.end && e.end < ev.start) && !(ev.end && ev.end < e.start));
37
- if (overlap) return {
38
- events,
39
- appended: false,
40
- tripId: overlap.trip_id,
41
- reason: `与已有行程 ${overlap.trip_id} 日期重叠,冲突即停`
42
- };
43
- const full = {
44
- schema: 'travel_timeline.v1',
45
- trip_id: tripId,
46
- ts: new Date().toISOString(),
47
- ...ev
48
- };
49
- return {
50
- events: [
51
- ...events,
52
- full
53
- ],
54
- appended: true,
55
- tripId
56
- };
37
+ if (events.some(e => e.trip_id === tripId))
38
+ return { events, appended: false, tripId };
39
+ const overlap = events.find(e => e.destination === ev.destination && !(e.end && e.end < ev.start) && !(ev.end && ev.end < e.start));
40
+ if (overlap)
41
+ return { events, appended: false, tripId: overlap.trip_id, reason: `与已有行程 ${overlap.trip_id} 日期重叠,冲突即停` };
42
+ const full = { schema: 'travel_timeline.v1', trip_id: tripId, ts: new Date().toISOString(), ...ev };
43
+ return { events: [...events, full], appended: true, tripId };
57
44
  }
45
+ /** 只读投影:按 start 倒序的行程摘要(「去过」行/brief 注入用) */
58
46
  export function projectTimeline(events) {
59
- return [
60
- ...events
61
- ].sort((a, b)=>a.start < b.start ? 1 : -1).map((e)=>({
62
- tripId: e.trip_id,
63
- destination: e.destination,
64
- start: e.start,
65
- end: e.end,
66
- companions: e.companions
67
- }));
47
+ return [...events]
48
+ .sort((a, b) => (a.start < b.start ? 1 : -1))
49
+ .map(e => ({ tripId: e.trip_id, destination: e.destination, start: e.start, end: e.end, companions: e.companions }));
68
50
  }
51
+ /**
52
+ * 交叉一致(回流率分子的质变):verified_outcome 的 wish 应有对应时间线行程。
53
+ * 返回缺口清单(verified 但无 timeline)——巡检口径,不自动补写(补写需要用户确认日期)。
54
+ */
69
55
  export function timelineGapsForVerified(timeline, verifiedWishes) {
70
- const dests = new Set(timeline.map((t)=>t.destination));
71
- return verifiedWishes.filter((w)=>w.destination && !dests.has(w.destination)).map((w)=>({
72
- wishId: w.wishId
73
- }));
56
+ const dests = new Set(timeline.map(t => t.destination));
57
+ return verifiedWishes.filter(w => w.destination && !dests.has(w.destination)).map(w => ({ wishId: w.wishId }));
74
58
  }
75
59
  export { ymd };
76
-
77
-
78
- //# sourceURL=ts/src/travel-timeline.ts
@@ -1,3 +1,21 @@
1
+ /**
2
+ * Per-agent, per-turn wall-clock boundary driven by routing (ADR-24 v2).
3
+ *
4
+ * 职责只有一件:保证每一轮终结在三态之一——当面答完(converge)、转后台
5
+ * 并给出回访承诺(handoff)、或明确暂停。绝不允许第四态:流死掉、什么
6
+ * 都没交付(2026-09-02 轨迹的失败形态)。
7
+ *
8
+ * - 阈值不再固定:每次 user/message 由 `turn-policy.ts` 的确定性分类器
9
+ * 解析 TurnPolicy(softMs/hardMs/exit);benchmark opt-in 用 fixedPolicy
10
+ * 钉死以保证可复现。
11
+ * - 硬阈拒绝时**同步**抑制工具 schema(防同 step 回环),并按 exit 语义
12
+ * 返回两种结构化结果:converge=用已有证据作答;handoff=落
13
+ * `gotry_turn_handoff.v1` 工单并指令模型告知用户 ETA 与回访方式。
14
+ * - handoff 工单是**新的独立格式**,落在 `<stateRoot>/gotry-state/
15
+ * turn-handoffs/`,不与 `async/` 的 loop 求解工单混用——async-collect
16
+ * 对无 spec 的 state 会立即结算 failed(假失败),收集器是未来的
17
+ * agent tick(loopx),不是 async-collect。
18
+ */
1
19
  import { randomUUID } from 'node:crypto';
2
20
  import { mkdir, readdir, readFile, rename, writeFile } from 'node:fs/promises';
3
21
  import { join } from 'node:path';
@@ -14,7 +32,7 @@ export async function writeTurnHandoffTicket(stateRoot, userMessage) {
14
32
  userMessage,
15
33
  requestedAt: new Date().toISOString(),
16
34
  etaLabel: TURN_HANDOFF_ETA_LABEL,
17
- status: 'open'
35
+ status: 'open',
18
36
  };
19
37
  await writeTicketJson(stateRoot, ticket);
20
38
  return ticket;
@@ -25,20 +43,20 @@ function handoffDir(stateRoot) {
25
43
  }
26
44
  async function writeTicketJson(stateRoot, ticket) {
27
45
  const dir = handoffDir(stateRoot);
28
- await mkdir(dir, {
29
- recursive: true
30
- });
46
+ await mkdir(dir, { recursive: true });
31
47
  const path = join(dir, `${ticket.id}.json`);
32
48
  const tmp = `${path}.tmp`;
33
49
  await writeFile(tmp, JSON.stringify(ticket, null, 2), 'utf-8');
34
50
  await rename(tmp, path);
35
51
  return path;
36
52
  }
53
+ /**
54
+ * 结算工单:交付物落 `<id>.deliverable.md`(settled=规划产物;failed=诚实
55
+ * 失败说明),工单 json 原子更新 status/settledAt/deliverableFile/error。
56
+ */
37
57
  export async function settleTurnHandoffTicket(stateRoot, ticket, status, deliverable, error) {
38
58
  const dir = handoffDir(stateRoot);
39
- await mkdir(dir, {
40
- recursive: true
41
- });
59
+ await mkdir(dir, { recursive: true });
42
60
  const deliverablePath = join(dir, `${ticket.id}.deliverable.md`);
43
61
  const deliverableTmp = `${deliverablePath}.tmp`;
44
62
  await writeFile(deliverableTmp, deliverable, 'utf-8');
@@ -48,58 +66,56 @@ export async function settleTurnHandoffTicket(stateRoot, ticket, status, deliver
48
66
  status,
49
67
  settledAt: new Date().toISOString(),
50
68
  deliverableFile: `${ticket.id}.deliverable.md`,
51
- ...error ? {
52
- error
53
- } : {}
69
+ ...(error ? { error } : {}),
54
70
  };
55
71
  const ticketPath = await writeTicketJson(stateRoot, settled);
56
- return {
57
- ticketPath,
58
- deliverablePath
59
- };
72
+ return { ticketPath, deliverablePath };
60
73
  }
74
+ /** 复访查询:按请求时间倒序列出工单;settled 附交付物摘录(≤600 字)。 */
61
75
  export async function listTurnHandoffTickets(stateRoot) {
62
76
  const dir = handoffDir(stateRoot);
63
77
  let names;
64
78
  try {
65
79
  names = await readdir(dir);
66
- } catch {
80
+ }
81
+ catch {
67
82
  return [];
68
83
  }
69
84
  const views = [];
70
- for (const name of names){
71
- if (!name.endsWith('.json')) continue;
85
+ for (const name of names) {
86
+ if (!name.endsWith('.json'))
87
+ continue;
72
88
  try {
73
89
  const raw = JSON.parse(await readFile(join(dir, name), 'utf-8'));
74
- if (raw?.schema !== TURN_HANDOFF_SCHEMA) continue;
90
+ if (raw?.schema !== TURN_HANDOFF_SCHEMA)
91
+ continue;
75
92
  const view = {
76
93
  id: raw.id,
77
94
  status: raw.status,
78
95
  objective: raw.objective,
79
96
  requestedAt: raw.requestedAt,
80
97
  etaLabel: raw.etaLabel,
81
- ...raw.settledAt ? {
82
- settledAt: raw.settledAt
83
- } : {},
84
- ...raw.error ? {
85
- error: raw.error
86
- } : {}
98
+ ...(raw.settledAt ? { settledAt: raw.settledAt } : {}),
99
+ ...(raw.error ? { error: raw.error } : {}),
87
100
  };
88
101
  if (raw.status !== 'open' && raw.deliverableFile) {
89
102
  try {
90
103
  const text = await readFile(join(dir, raw.deliverableFile), 'utf-8');
91
104
  view.deliverableExcerpt = text.length > 600 ? `${text.slice(0, 600)}…` : text;
92
- } catch {}
105
+ }
106
+ catch { /* 交付物缺失时视图降级,不阻塞列表 */ }
93
107
  }
94
108
  views.push(view);
95
- } catch {}
109
+ }
110
+ catch { /* 单个坏工单不阻塞列表 */ }
96
111
  }
97
- views.sort((a, b)=>a.requestedAt < b.requestedAt ? 1 : -1);
112
+ views.sort((a, b) => (a.requestedAt < b.requestedAt ? 1 : -1));
98
113
  return views;
99
114
  }
100
115
  function resolveEnvPin(name) {
101
116
  const raw = process.env[name];
102
- if (!raw) return null;
117
+ if (!raw)
118
+ return null;
103
119
  const parsed = Number.parseInt(raw, 10);
104
120
  return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
105
121
  }
@@ -107,16 +123,8 @@ function convergenceContext(code, text) {
107
123
  return {
108
124
  id: randomUUID(),
109
125
  role: 'user',
110
- content: [
111
- {
112
- type: 'text',
113
- text: `${code}: ${text}`
114
- }
115
- ],
116
- source: {
117
- kind: 'plugin',
118
- plugin: 'gotry-turn-deadline'
119
- }
126
+ content: [{ type: 'text', text: `${code}: ${text}` }],
127
+ source: { kind: 'plugin', plugin: 'gotry-turn-deadline' },
120
128
  };
121
129
  }
122
130
  function exhaustionResult(reason) {
@@ -124,20 +132,10 @@ function exhaustionResult(reason) {
124
132
  isError: true,
125
133
  error: {
126
134
  message: reason,
127
- info: {
128
- name: 'TurnDeadlineError',
129
- code: TURN_DEADLINE_EXHAUSTED
130
- }
135
+ info: { name: 'TurnDeadlineError', code: TURN_DEADLINE_EXHAUSTED },
131
136
  },
132
- content: [
133
- {
134
- type: 'text',
135
- text: reason
136
- }
137
- ],
138
- additionalContexts: [
139
- convergenceContext(TURN_DEADLINE_EXHAUSTED, 'No more tool dispatches are permitted in this turn. Produce the final answer from existing results.')
140
- ]
137
+ content: [{ type: 'text', text: reason }],
138
+ additionalContexts: [convergenceContext(TURN_DEADLINE_EXHAUSTED, 'No more tool dispatches are permitted in this turn. Produce the final answer from existing results.')],
141
139
  };
142
140
  }
143
141
  function handoffResult(ticket) {
@@ -146,70 +144,72 @@ function handoffResult(ticket) {
146
144
  isError: true,
147
145
  error: {
148
146
  message: `${TURN_DEADLINE_HANDOFF}: sync window exhausted for a deep-planning turn; ticket ${ticket.id}`,
149
- info: {
150
- name: 'TurnDeadlineHandoff',
151
- code: TURN_DEADLINE_HANDOFF
152
- }
147
+ info: { name: 'TurnDeadlineHandoff', code: TURN_DEADLINE_HANDOFF },
153
148
  },
154
- content: [
155
- {
156
- type: 'text',
157
- text: `${TURN_DEADLINE_HANDOFF}: ${instruction}`
158
- }
159
- ],
160
- additionalContexts: [
161
- convergenceContext(TURN_DEADLINE_HANDOFF, instruction)
162
- ]
149
+ content: [{ type: 'text', text: `${TURN_DEADLINE_HANDOFF}: ${instruction}` }],
150
+ additionalContexts: [convergenceContext(TURN_DEADLINE_HANDOFF, instruction)],
163
151
  };
164
152
  }
153
+ /**
154
+ * Install the runtime boundary, kept separate from the GoTry tool catalog so
155
+ * the actual Cordis waterfalls can be exercised without booting every tool.
156
+ */
165
157
  export function installTurnDeadline(ctx, options = {}) {
166
- if (options.enabled === false) return;
167
- if (typeof ctx.on !== 'function') return;
168
- const now = options.now ?? (()=>Date.now());
158
+ if (options.enabled === false)
159
+ return;
160
+ // Some offline contract tests intentionally provide a registration-only
161
+ // Context slice. They do not drive an agent loop, so there is no boundary
162
+ // to install and no reason to require an event bus.
163
+ if (typeof ctx.on !== 'function')
164
+ return;
165
+ const now = options.now ?? (() => Date.now());
166
+ // Test/benchmark seam only: pin the resolved numbers without touching the
167
+ // routed exit strategy. Product runs never set these.
169
168
  const softPin = resolveEnvPin('GOTRY_TURN_DEADLINE_SOFT_MS');
170
169
  const hardPin = resolveEnvPin('GOTRY_TURN_DEADLINE_HARD_MS');
171
170
  const defaultPolicy = options.fixedPolicy ?? turnPolicyFor('sync-planning');
172
- const routePolicy = (message)=>{
173
- if (options.fixedPolicy) return {
174
- ...options.fixedPolicy
175
- };
171
+ const routePolicy = (message) => {
172
+ if (options.fixedPolicy)
173
+ return { ...options.fixedPolicy };
176
174
  const policy = turnPolicyFor(classifyTurn(message));
177
- return {
178
- ...policy,
179
- softMs: softPin ?? policy.softMs,
180
- hardMs: hardPin ?? policy.hardMs
181
- };
175
+ return { ...policy, softMs: softPin ?? policy.softMs, hardMs: hardPin ?? policy.hardMs };
182
176
  };
183
177
  const stateByAgent = new Map();
184
178
  const softExecutions = new Map();
185
179
  const finalOnlyDisposers = new Map();
186
- const clearAgent = (agentId)=>{
180
+ const clearAgent = (agentId) => {
187
181
  stateByAgent.delete(agentId);
188
- for (const [token, owner] of softExecutions){
189
- if (owner.agentId === agentId) softExecutions.delete(token);
182
+ for (const [token, owner] of softExecutions) {
183
+ if (owner.agentId === agentId)
184
+ softExecutions.delete(token);
190
185
  }
191
186
  finalOnlyDisposers.get(agentId)?.();
192
187
  finalOnlyDisposers.delete(agentId);
193
188
  };
194
- const enterFinalOnly = (agent)=>{
189
+ const enterFinalOnly = (agent) => {
195
190
  const agentId = String(agent.id);
196
- if (finalOnlyDisposers.has(agentId)) return;
191
+ if (finalOnlyDisposers.has(agentId))
192
+ return;
197
193
  const globalTools = ctx.tools;
198
194
  const scopedTools = agent.ctx?.tools;
199
195
  if (typeof globalTools.schemas !== 'function' || typeof scopedTools?.restrict !== 'function') {
196
+ // No registry to suppress: subsequent tool calls in the same turn hit the
197
+ // same per-call denial branch and stay refused until the next turn.
200
198
  return;
201
199
  }
202
- const inheritedNames = globalTools.schemas().map((schema)=>schema.name).filter((name)=>name !== 'run_code');
203
- if (inheritedNames.length === 0) return;
204
- finalOnlyDisposers.set(agentId, scopedTools.restrict({
205
- deny: inheritedNames
206
- }));
200
+ const inheritedNames = globalTools.schemas()
201
+ .map(schema => schema.name)
202
+ .filter(name => name !== 'run_code');
203
+ if (inheritedNames.length === 0)
204
+ return;
205
+ finalOnlyDisposers.set(agentId, scopedTools.restrict({ deny: inheritedNames }));
207
206
  };
208
- const keyOfAgent = (agent)=>{
207
+ // 事件主体是 session 对象;agent 归属同一 session 时共用同一预算键。
208
+ const keyOfAgent = (agent) => {
209
209
  const session = agent.session;
210
210
  return String(session?.id ?? agent.id);
211
211
  };
212
- ctx.on('session/event', (subject, event)=>{
212
+ ctx.on('session/event', (subject, event) => {
213
213
  const agentId = String(subject.id);
214
214
  if (event.type === 'turn/end') {
215
215
  clearAgent(agentId);
@@ -221,72 +221,66 @@ export function installTurnDeadline(ctx, options = {}) {
221
221
  if (!stateByAgent.has(agentId)) {
222
222
  stateByAgent.set(agentId, {
223
223
  startedAt: now(),
224
- policy: {
225
- ...defaultPolicy,
226
- softMs: softPin ?? defaultPolicy.softMs,
227
- hardMs: hardPin ?? defaultPolicy.hardMs
228
- }
224
+ policy: { ...defaultPolicy, softMs: softPin ?? defaultPolicy.softMs, hardMs: hardPin ?? defaultPolicy.hardMs },
229
225
  });
230
226
  }
231
227
  return;
232
228
  }
233
229
  if (event.type === 'user/message') {
230
+ // dsh 事件载荷在 event.data 下(benchmark-agent-conformance 同型读法)。
234
231
  const message = event.data;
235
- if (message?.source?.kind !== 'user') return;
236
- const text = (message.content ?? []).find((block)=>block.type === 'text')?.text ?? '';
237
- if (!text.trim()) return;
238
- stateByAgent.set(agentId, {
239
- startedAt: now(),
240
- policy: routePolicy(text),
241
- userMessage: text
242
- });
232
+ if (message?.source?.kind !== 'user')
233
+ return;
234
+ const text = (message.content ?? []).find(block => block.type === 'text')?.text ?? '';
235
+ if (!text.trim())
236
+ return;
237
+ // 每个 user 消息 = 新的预算:路由分类 + 时钟重置。plugin/skill 注入
238
+ // 的 user/message(source.kind !== 'user')不参与路由。
239
+ stateByAgent.set(agentId, { startedAt: now(), policy: routePolicy(text), userMessage: text });
243
240
  }
244
241
  });
245
- ctx.on('session/disposed', (subject)=>clearAgent(String(subject.id)));
246
- ctx.on('tools/execute', (exec, next)=>{
247
- if (!exec.agent) return next();
242
+ ctx.on('session/disposed', subject => clearAgent(String(subject.id)));
243
+ ctx.on('tools/execute', (exec, next) => {
244
+ // Programmatic/direct calls are not part of a model planner turn.
245
+ if (!exec.agent)
246
+ return next();
248
247
  const agentId = keyOfAgent(exec.agent);
249
- const state = stateByAgent.get(agentId) ?? {
250
- startedAt: now(),
251
- policy: {
252
- ...defaultPolicy,
253
- softMs: softPin ?? defaultPolicy.softMs,
254
- hardMs: hardPin ?? defaultPolicy.hardMs
255
- }
256
- };
248
+ const state = stateByAgent.get(agentId)
249
+ ?? { startedAt: now(), policy: { ...defaultPolicy, softMs: softPin ?? defaultPolicy.softMs, hardMs: hardPin ?? defaultPolicy.hardMs } };
257
250
  stateByAgent.set(agentId, state);
258
251
  const elapsed = now() - state.startedAt;
259
252
  if (elapsed > state.policy.hardMs) {
253
+ // Synchronous schema suppression so same-step follow-up calls cannot
254
+ // loop on refusal results (the 2026-09-02 trajectory failure).
260
255
  enterFinalOnly(exec.agent);
261
256
  if (state.policy.exit === 'handoff' && state.userMessage && options.stateRoot) {
262
- return writeTurnHandoffTicket(options.stateRoot, state.userMessage).then((ticket)=>handoffResult(ticket)).catch(()=>exhaustionResult(`${TURN_DEADLINE_EXHAUSTED}: hard deadline ${state.policy.hardMs}ms reached (ticket persistence failed; degraded to converge)`));
257
+ return writeTurnHandoffTicket(options.stateRoot, state.userMessage)
258
+ .then(ticket => handoffResult(ticket))
259
+ .catch(() => exhaustionResult(`${TURN_DEADLINE_EXHAUSTED}: hard deadline ${state.policy.hardMs}ms reached (ticket persistence failed; degraded to converge)`));
263
260
  }
264
261
  return Promise.resolve(exhaustionResult(`${TURN_DEADLINE_EXHAUSTED}: turn exceeded hard deadline of ${state.policy.hardMs}ms (elapsed ${elapsed}ms); provide a final answer using existing results`));
265
262
  }
266
263
  if (elapsed > state.policy.softMs) {
267
- softExecutions.set(exec.token, {
268
- agentId,
269
- exit: state.policy.exit
270
- });
264
+ softExecutions.set(exec.token, { agentId, exit: state.policy.exit });
271
265
  }
272
266
  return next();
273
267
  });
274
- ctx.on('tools/post-execute', (exec, _result, next)=>{
275
- return next().then((decision)=>{
268
+ ctx.on('tools/post-execute', (exec, _result, next) => {
269
+ return next().then(decision => {
276
270
  const owner = softExecutions.get(exec.token);
277
- if (!owner) return decision;
271
+ if (!owner)
272
+ return decision;
278
273
  softExecutions.delete(exec.token);
279
- const text = owner.exit === 'handoff' ? 'Turn has crossed the soft deadline of a deep-planning turn. Wrap up context gathering now; the turn will hand off to background planning at the hard deadline.' : 'Turn has crossed the soft deadline. Stop dispatching new tools and produce the final answer from gathered evidence.';
274
+ const text = owner.exit === 'handoff'
275
+ ? 'Turn has crossed the soft deadline of a deep-planning turn. Wrap up context gathering now; the turn will hand off to background planning at the hard deadline.'
276
+ : 'Turn has crossed the soft deadline. Stop dispatching new tools and produce the final answer from gathered evidence.';
280
277
  return {
281
278
  ...decision,
282
279
  additionalContexts: [
283
- ...decision.additionalContexts ?? [],
284
- convergenceContext(TURN_DEADLINE_SOFT, text)
285
- ]
280
+ ...(decision.additionalContexts ?? []),
281
+ convergenceContext(TURN_DEADLINE_SOFT, text),
282
+ ],
286
283
  };
287
284
  });
288
285
  });
289
286
  }
290
-
291
-
292
- //# sourceURL=ts/src/turn-deadline.ts