@danceiny/gotry 0.0.1-rc.16 → 0.0.1-rc.17

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 (229) hide show
  1. package/README.md +47 -13
  2. package/README.zh-CN.md +20 -10
  3. package/bin/gotry-booking-copilot.js +53 -0
  4. package/bin/gotry-bootstrap.js +111 -51
  5. package/bin/gotry-inner.js +442 -60
  6. package/bin/gotry-runtime-resolution.d.ts +27 -0
  7. package/bin/gotry-runtime-resolution.js +50 -0
  8. package/bin/gotry.js +1 -1
  9. package/cordis.gotry-patch.yml +5 -1
  10. package/dist/capabilities/agent-reach-deep.js +1 -1
  11. package/dist/capabilities/agent-reach.js +1 -1
  12. package/dist/capabilities/anything.js +1 -1
  13. package/dist/capabilities/artifacts.js +1 -1
  14. package/dist/capabilities/effect.js +1 -1
  15. package/dist/capabilities/fact-log.js +1 -1
  16. package/dist/capabilities/flyai.js +20 -6
  17. package/dist/capabilities/hbcli.js +1 -1
  18. package/dist/capabilities/incident-log.js +1 -1
  19. package/dist/capabilities/model-override.js +18 -0
  20. package/dist/capabilities/opensky.js +1 -1
  21. package/dist/capabilities/resilience.js +1 -1
  22. package/dist/capabilities/session/action-cache.js +1 -1
  23. package/dist/capabilities/session/adapters/ctrip-flight.js +1 -1
  24. package/dist/capabilities/session/adapters/meituan-local.js +1 -1
  25. package/dist/capabilities/session/benchmark.js +1 -1
  26. package/dist/capabilities/session/extension-bridge.js +19 -6
  27. package/dist/capabilities/session/extension-channel.js +3 -3
  28. package/dist/capabilities/session/extension-distribution.js +234 -0
  29. package/dist/capabilities/session/extract.js +1 -1
  30. package/dist/capabilities/session/golden-score.js +92 -0
  31. package/dist/capabilities/session/health-watch.js +1 -1
  32. package/dist/capabilities/session/read-guard.js +1 -1
  33. package/dist/capabilities/session/static-flight-golden.js +137 -0
  34. package/dist/capabilities/session/transport.js +1 -1
  35. package/dist/capabilities/session/wizard.js +21 -251
  36. package/dist/capabilities/session-consent.js +1 -1
  37. package/dist/capabilities/session-login.js +11 -5
  38. package/dist/capabilities/session-search.js +46 -4
  39. package/dist/capabilities/weather.js +168 -46
  40. package/dist/data/session-golden-20.json +25 -0
  41. package/dist/data/sf-golden-manifest.json +102 -0
  42. package/dist/data/sf-static-routes.json +91 -0
  43. package/dist/scripts/action-cache-tests.js +1 -1
  44. package/dist/scripts/agent-planning-budget-e2e.js +227 -0
  45. package/dist/scripts/agent-planning-budget-tests.js +173 -0
  46. package/dist/scripts/agent-reach-deep-tests.js +1 -1
  47. package/dist/scripts/agent-reach-tests.js +1 -1
  48. package/dist/scripts/agent-reach-wrapper-tests.js +1 -1
  49. package/dist/scripts/anything-tests.js +1 -1
  50. package/dist/scripts/async-collect.js +1 -1
  51. package/dist/scripts/benchmark-environment-bridge-e2e.js +981 -0
  52. package/dist/scripts/benchmark-environment-bridge-tests.js +2544 -0
  53. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +335 -0
  54. package/dist/scripts/booking-copilot-availability-policy-v2-tests.js +1355 -0
  55. package/dist/scripts/booking-copilot-bin-proof-tests.js +89 -0
  56. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +113 -0
  57. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +356 -0
  58. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +557 -0
  59. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +140 -0
  60. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +202 -0
  61. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +102 -0
  62. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +374 -0
  63. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +447 -0
  64. package/dist/scripts/booking-copilot-runtime-proof-tests.js +205 -0
  65. package/dist/scripts/booking-copilot-server-proof-tests.js +317 -0
  66. package/dist/scripts/booking-copilot-startup-proof-tests.js +283 -0
  67. package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +3935 -0
  68. package/dist/scripts/booking-saga-tests.js +1 -1
  69. package/dist/scripts/booking-surface-contract-proof-tests.js +393 -0
  70. package/dist/scripts/booking-surface-v2-contract-proof-tests.js +1174 -0
  71. package/dist/scripts/bootstrap-tests.js +30 -10
  72. package/dist/scripts/build-changelog.js +1 -1
  73. package/dist/scripts/changelog-tests.js +1 -1
  74. package/dist/scripts/companion-tests.js +1 -1
  75. package/dist/scripts/diff-test.js +1 -1
  76. package/dist/scripts/dsh-runtime-closure-tests.js +225 -0
  77. package/dist/scripts/dsh-runtime-closure.js +150 -0
  78. package/dist/scripts/effect-tests.js +1 -1
  79. package/dist/scripts/engine-run.js +1 -1
  80. package/dist/scripts/engine-tests.js +1 -1
  81. package/dist/scripts/evaluation-cadence-tests.js +347 -0
  82. package/dist/scripts/evaluation-contract-tests.js +574 -0
  83. package/dist/scripts/extension-distribution-cli.js +35 -0
  84. package/dist/scripts/extension-distribution-tests.js +341 -0
  85. package/dist/scripts/extension-tests.js +128 -23
  86. package/dist/scripts/fact-gate-tests.js +1 -1
  87. package/dist/scripts/flyai-tests.js +1 -1
  88. package/dist/scripts/hbcli-e2e-tests.js +1 -1
  89. package/dist/scripts/hbcli-tests.js +1 -1
  90. package/dist/scripts/health-watch-cli.js +1 -1
  91. package/dist/scripts/i18n-tests.js +1 -1
  92. package/dist/scripts/incident-tests.js +1 -1
  93. package/dist/scripts/journey-tests.js +1 -1
  94. package/dist/scripts/ledger-tests.js +1 -1
  95. package/dist/scripts/ledger-workflow-crash.js +1 -1
  96. package/dist/scripts/memory-capture-tests.js +1 -1
  97. package/dist/scripts/memory-decay-tests.js +1 -1
  98. package/dist/scripts/memory-metrics.js +1 -1
  99. package/dist/scripts/memory-value-report.js +1 -1
  100. package/dist/scripts/model-override-e2e.js +176 -0
  101. package/dist/scripts/nightly-evidence-tests.js +1 -1
  102. package/dist/scripts/nightly-evidence.js +1 -1
  103. package/dist/scripts/nudge-digest.js +1 -1
  104. package/dist/scripts/onboarding-tests.js +21 -53
  105. package/dist/scripts/opensky-check.js +1 -1
  106. package/dist/scripts/opensky-tests.js +1 -1
  107. package/dist/scripts/pnpm-dsh-closure-proof.js +20 -0
  108. package/dist/scripts/price-drift-tests.js +1 -1
  109. package/dist/scripts/price-drift-watch.js +1 -1
  110. package/dist/scripts/probe-poi-tests.js +1 -1
  111. package/dist/scripts/product-metrics.js +1 -1
  112. package/dist/scripts/publish-preverify.js +40 -4
  113. package/dist/scripts/realtime-pricing-tests.js +1 -1
  114. package/dist/scripts/replay-async.js +1 -1
  115. package/dist/scripts/replay-real.js +1 -1
  116. package/dist/scripts/replay.js +1 -1
  117. package/dist/scripts/session-attach-diagnose.js +1 -1
  118. package/dist/scripts/session-attach-poc.js +1 -1
  119. package/dist/scripts/session-benchmark.js +1 -1
  120. package/dist/scripts/session-extract-tests.js +1 -1
  121. package/dist/scripts/session-login.js +1 -1
  122. package/dist/scripts/session-tests.js +70 -20
  123. package/dist/scripts/sf-live-benchmark.js +338 -0
  124. package/dist/scripts/sf-live-cli-tests.js +21 -0
  125. package/dist/scripts/sf-soft-score-tests.js +108 -0
  126. package/dist/scripts/sf-summary.js +93 -0
  127. package/dist/scripts/skeleton-check.js +1 -1
  128. package/dist/scripts/skeleton-integration-test.js +1 -1
  129. package/dist/scripts/skills-contract-tests.js +1 -1
  130. package/dist/scripts/smoke-session-gate-tests.js +29 -0
  131. package/dist/scripts/smoke.js +79 -33
  132. package/dist/scripts/state-cli-tests.js +1 -1
  133. package/dist/scripts/state-cli.js +1 -1
  134. package/dist/scripts/static-golden-tests.js +299 -0
  135. package/dist/scripts/time-eval-tests.js +1 -1
  136. package/dist/scripts/travel-timeline-tests.js +1 -1
  137. package/dist/scripts/unified-tests.js +1 -1
  138. package/dist/scripts/weather-tests.js +694 -44
  139. package/dist/scripts/z3-race-tests.js +1 -1
  140. package/dist/src/artifact-gate.js +1 -1
  141. package/dist/src/benchmark-agent-conformance.js +370 -0
  142. package/dist/src/benchmark-environment-bridge.js +384 -0
  143. package/dist/src/benchmark-headless-child-diagnostics.js +173 -0
  144. package/dist/src/benchmark-tool-isolation.js +124 -0
  145. package/dist/src/bookable-facts.js +1 -1
  146. package/dist/src/booking-saga.js +1 -1
  147. package/dist/src/booking-surface/availability-policy-v2.js +830 -0
  148. package/dist/src/booking-surface/canonical-schema.js +113 -0
  149. package/dist/src/booking-surface/contracts-v2.js +89 -0
  150. package/dist/src/booking-surface/contracts.js +46 -0
  151. package/dist/src/booking-surface/dsh-planner.js +453 -0
  152. package/dist/src/booking-surface/dsh-plugin.js +93 -0
  153. package/dist/src/booking-surface/error-codes.js +94 -0
  154. package/dist/src/booking-surface/index.js +15 -0
  155. package/dist/src/booking-surface/profile.js +68 -0
  156. package/dist/src/booking-surface/runtime-v2.js +1771 -0
  157. package/dist/src/booking-surface/runtime.js +351 -0
  158. package/dist/src/booking-surface/server-v2.js +334 -0
  159. package/dist/src/booking-surface/server.js +302 -0
  160. package/dist/src/booking-surface/startup.js +159 -0
  161. package/dist/src/booking-surface/validation-v2.js +319 -0
  162. package/dist/src/booking-surface/validation.js +809 -0
  163. package/dist/src/bridge.js +1 -1
  164. package/dist/src/companions.js +1 -1
  165. package/dist/src/contracts.js +1 -1
  166. package/dist/src/dsh-llm.js +1 -1
  167. package/dist/src/engine.js +1 -1
  168. package/dist/src/evaluation-cadence.js +234 -0
  169. package/dist/src/evaluation-contracts.js +906 -0
  170. package/dist/src/i18n.js +1 -1
  171. package/dist/src/index.js +50 -19
  172. package/dist/src/journey.js +1 -1
  173. package/dist/src/loop.js +1 -1
  174. package/dist/src/memory-capture.js +1 -1
  175. package/dist/src/memory-decay.js +1 -1
  176. package/dist/src/memory-utility.js +1 -1
  177. package/dist/src/mock-llm.js +1 -1
  178. package/dist/src/model.js +1 -1
  179. package/dist/src/realtime-pricing.js +1 -1
  180. package/dist/src/slot-spec.js +1 -1
  181. package/dist/src/state-ledger.js +2 -1
  182. package/dist/src/time-anchor.js +1 -1
  183. package/dist/src/tool-budget.js +136 -0
  184. package/dist/src/tool-packet.js +1 -1
  185. package/dist/src/travel-slots.js +1 -1
  186. package/dist/src/travel-timeline.js +1 -1
  187. package/dist/src/unified.js +1 -1
  188. package/dist/src/wish-pool.js +1 -1
  189. package/dist/src/z3-shared.js +1 -1
  190. package/extension/README.md +31 -7
  191. package/package.json +286 -11
  192. package/schemas/booking.surface.v1.schema.json +927 -0
  193. package/schemas/booking.surface.v2.schema.json +61 -0
  194. package/ts/capabilities/flyai.ts +16 -3
  195. package/ts/capabilities/session/extension-bridge.ts +37 -14
  196. package/ts/capabilities/session/extension-channel.ts +6 -3
  197. package/ts/capabilities/session/extension-distribution.ts +264 -0
  198. package/ts/capabilities/session/golden-score.ts +139 -0
  199. package/ts/capabilities/session/health-watch.ts +1 -1
  200. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  201. package/ts/capabilities/session/wizard.ts +34 -176
  202. package/ts/capabilities/session-login.ts +15 -5
  203. package/ts/capabilities/session-search.ts +40 -3
  204. package/ts/capabilities/weather.ts +141 -52
  205. package/ts/package.json +3 -3
  206. package/ts/src/benchmark-agent-conformance.ts +448 -0
  207. package/ts/src/benchmark-environment-bridge.ts +348 -0
  208. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  209. package/ts/src/benchmark-tool-isolation.ts +166 -0
  210. package/ts/src/booking-surface/availability-policy-v2.ts +523 -0
  211. package/ts/src/booking-surface/canonical-schema.js +113 -0
  212. package/ts/src/booking-surface/contracts-v2.ts +118 -0
  213. package/ts/src/booking-surface/contracts.ts +380 -0
  214. package/ts/src/booking-surface/dsh-planner.ts +452 -0
  215. package/ts/src/booking-surface/dsh-plugin.js +93 -0
  216. package/ts/src/booking-surface/error-codes.ts +101 -0
  217. package/ts/src/booking-surface/index.ts +12 -0
  218. package/ts/src/booking-surface/profile.ts +42 -0
  219. package/ts/src/booking-surface/runtime-v2.ts +1466 -0
  220. package/ts/src/booking-surface/runtime.ts +483 -0
  221. package/ts/src/booking-surface/server-v2.ts +247 -0
  222. package/ts/src/booking-surface/server.ts +324 -0
  223. package/ts/src/booking-surface/startup.ts +196 -0
  224. package/ts/src/booking-surface/validation-v2.ts +205 -0
  225. package/ts/src/booking-surface/validation.ts +453 -0
  226. package/ts/src/index.ts +64 -11
  227. package/ts/src/state-ledger.ts +1 -0
  228. package/ts/src/tool-budget.ts +165 -0
  229. package/dist/scripts/wizard-bootstrap.js +0 -32
@@ -0,0 +1,557 @@
1
+ import assert from 'node:assert/strict';
2
+ import { DSH_EMBEDDED_BOOKING_TOOL_NAMES, buildDshPlannerEnvironment, createDshEmbeddedBookingPlanner, createDshEmbeddedBookingPlannerV2 } from '../src/booking-surface/dsh-planner.js';
3
+ const task = {
4
+ schemaVersion: 'booking.surface.v1',
5
+ taskId: 'task-dsh-1',
6
+ contextRef: 'ctx-dsh-1',
7
+ surface: 'tenant',
8
+ revision: 0,
9
+ allowedActions: [
10
+ 'search.patch',
11
+ 'search.run'
12
+ ],
13
+ userTurnCount: 1,
14
+ lastUserTurnDigest: 'request-digest',
15
+ phase: 'planning',
16
+ lastSequence: 0
17
+ };
18
+ const workspace = {
19
+ schemaVersion: 'booking.surface.v1',
20
+ contextRef: task.contextRef,
21
+ surface: 'tenant',
22
+ revision: 0,
23
+ locale: 'zh-CN',
24
+ currency: 'AED',
25
+ searchDraft: {},
26
+ results: {
27
+ status: 'idle'
28
+ },
29
+ visibleHotels: [],
30
+ loadedOffers: [],
31
+ shortlistedOfferRefs: [],
32
+ capabilities: {
33
+ surface: 'tenant',
34
+ allowedActions: [
35
+ 'search.patch',
36
+ 'search.run'
37
+ ]
38
+ }
39
+ };
40
+ const searchRun = {
41
+ schemaVersion: 'booking.surface.v1',
42
+ kind: 'search.run',
43
+ actionId: 'action-dsh-1',
44
+ contextRef: task.contextRef,
45
+ expectedRevision: 0,
46
+ reason: 'Run the authoritative workspace search.',
47
+ factRefs: [],
48
+ input: {}
49
+ };
50
+ const hotelSelect = {
51
+ ...searchRun,
52
+ kind: 'hotel.select',
53
+ actionId: 'action-dsh-select-1',
54
+ reason: 'Select the requested hotel.',
55
+ input: {
56
+ hotelRef: 'hotel-1'
57
+ }
58
+ };
59
+ const prompts = [];
60
+ const sessionIds = [];
61
+ let runIndex = 0;
62
+ const runPort = {
63
+ async run (prompt, options) {
64
+ prompts.push(prompt);
65
+ sessionIds.push(options.sessionId);
66
+ runIndex += 1;
67
+ if (runIndex === 1) {
68
+ return {
69
+ finalResponse: '{"kind":"book","input":{}}',
70
+ events: [
71
+ {
72
+ type: 'tool/call',
73
+ data: {
74
+ name: 'booking_search_hotels',
75
+ arguments: JSON.stringify({
76
+ decision: {
77
+ kind: 'operation',
78
+ action: searchRun
79
+ }
80
+ })
81
+ }
82
+ }
83
+ ]
84
+ };
85
+ }
86
+ if (runIndex === 3) {
87
+ return {
88
+ finalResponse: '',
89
+ events: [
90
+ {
91
+ type: 'tool/call',
92
+ data: {
93
+ name: 'booking_refine_results',
94
+ arguments: JSON.stringify({
95
+ decision: {
96
+ kind: 'operation',
97
+ action: hotelSelect
98
+ }
99
+ })
100
+ }
101
+ }
102
+ ]
103
+ };
104
+ }
105
+ return {
106
+ finalResponse: '{"kind":"search.run","input":{}}',
107
+ events: [
108
+ {
109
+ type: 'tool/call',
110
+ data: {
111
+ name: 'booking_search_hotels',
112
+ arguments: JSON.stringify({
113
+ decision: {
114
+ kind: 'terminal',
115
+ terminal: {
116
+ status: 'completed',
117
+ summary: 'Stopped at search results.',
118
+ factRefs: []
119
+ }
120
+ }
121
+ })
122
+ }
123
+ }
124
+ ]
125
+ };
126
+ },
127
+ async close () {}
128
+ };
129
+ const adapter = await createDshEmbeddedBookingPlanner({
130
+ runPort
131
+ });
132
+ const session = adapter.plannerFactory(task);
133
+ const first = await session.next({
134
+ task,
135
+ turn: {
136
+ schemaVersion: 'booking.surface.v1',
137
+ kind: 'user.turn',
138
+ taskId: task.taskId,
139
+ workspace: {
140
+ ...workspace,
141
+ capabilities: {
142
+ ...workspace.capabilities,
143
+ allowedActions: [
144
+ ...workspace.capabilities.allowedActions
145
+ ]
146
+ }
147
+ },
148
+ request: {
149
+ text: '执行当前搜索'
150
+ }
151
+ }
152
+ });
153
+ assert.deepEqual(first, [
154
+ {
155
+ kind: 'operation',
156
+ action: searchRun
157
+ }
158
+ ], 'typed dsh tool call becomes one operation');
159
+ const receipt = {
160
+ schemaVersion: 'booking.surface.v1',
161
+ kind: 'action.receipt',
162
+ actionId: searchRun.actionId,
163
+ contextRef: task.contextRef,
164
+ status: 'applied',
165
+ revision: 1,
166
+ observation: {
167
+ kind: 'search.state',
168
+ searchSessionRef: 'search-dsh-1',
169
+ resultCount: 4
170
+ },
171
+ resultContract: {
172
+ outcome: 'complete',
173
+ hardCriteriaMet: true,
174
+ factRefs: [],
175
+ gapCodes: []
176
+ }
177
+ };
178
+ const continuedTask = {
179
+ ...task,
180
+ revision: 1,
181
+ lastReceipt: receipt
182
+ };
183
+ const second = await session.next({
184
+ task: continuedTask,
185
+ turn: {
186
+ schemaVersion: 'booking.surface.v1',
187
+ kind: 'action.receipt.continuation',
188
+ taskId: task.taskId,
189
+ workspace: {
190
+ ...workspace,
191
+ revision: 1,
192
+ capabilities: {
193
+ ...workspace.capabilities,
194
+ allowedActions: [
195
+ ...workspace.capabilities.allowedActions
196
+ ]
197
+ }
198
+ },
199
+ receipt
200
+ }
201
+ });
202
+ assert.deepEqual(second, [
203
+ {
204
+ kind: 'terminal',
205
+ terminal: {
206
+ status: 'completed',
207
+ summary: 'Stopped at search results.',
208
+ factRefs: []
209
+ }
210
+ }
211
+ ]);
212
+ assert.equal(sessionIds[0], sessionIds[1], 'one task keeps one dsh session across receipt continuation');
213
+ assert.match(prompts[1], /action-dsh-1/, 'receipt continuation reaches the same task-scoped planner session');
214
+ const paymentTask = {
215
+ ...task,
216
+ taskId: 'task-payment-1',
217
+ surface: 'payment_link',
218
+ allowedActions: [
219
+ 'hotel.select'
220
+ ],
221
+ revision: 0
222
+ };
223
+ const paymentSession = adapter.plannerFactory(paymentTask);
224
+ const selected = await paymentSession.next({
225
+ task: paymentTask,
226
+ turn: {
227
+ schemaVersion: 'booking.surface.v1',
228
+ kind: 'user.turn',
229
+ taskId: paymentTask.taskId,
230
+ workspace: {
231
+ ...workspace,
232
+ surface: 'payment_link',
233
+ capabilities: {
234
+ surface: 'payment_link',
235
+ allowedActions: [
236
+ 'hotel.select'
237
+ ]
238
+ }
239
+ },
240
+ request: {
241
+ text: '选择酒店'
242
+ }
243
+ }
244
+ });
245
+ assert.deepEqual(selected, [
246
+ {
247
+ kind: 'operation',
248
+ action: hotelSelect
249
+ }
250
+ ], 'refine-results can emit typed hotel.select on payment_link');
251
+ assert.deepEqual(DSH_EMBEDDED_BOOKING_TOOL_NAMES, [
252
+ 'booking_search_hotels',
253
+ 'booking_refine_results',
254
+ 'booking_find_room_offers',
255
+ 'booking_compare_offers',
256
+ 'booking_prepare_booking',
257
+ 'booking_observe_booking'
258
+ ]);
259
+ assert.ok(!DSH_EMBEDDED_BOOKING_TOOL_NAMES.some((name)=>/book$|trade|payment/i.test(name)), 'profile has no Book/payment tool');
260
+ const childEnv = buildDshPlannerEnvironment({
261
+ PATH: '/usr/bin',
262
+ LANG: 'en_US.UTF-8',
263
+ LLM_API_KEY: 'model-key',
264
+ LLM_BASE_URL: 'http://model.invalid/v1',
265
+ PORTAL_TOKEN: 'forbidden',
266
+ HOTELBYTE_TOKEN: 'forbidden',
267
+ GOTRY_BOOKING_COPILOT_API_KEY: 'bff-only'
268
+ });
269
+ assert.equal(childEnv.DEEPSEEK_API_KEY, 'model-key');
270
+ assert.equal(childEnv.DEEPSEEK_BASE_URL, 'http://model.invalid/v1');
271
+ assert.equal(childEnv.PORTAL_TOKEN, undefined);
272
+ assert.equal(childEnv.HOTELBYTE_TOKEN, undefined);
273
+ assert.equal(childEnv.GOTRY_BOOKING_COPILOT_API_KEY, undefined);
274
+ const proseOnlyPort = {
275
+ async run () {
276
+ return {
277
+ finalResponse: JSON.stringify({
278
+ kind: 'operation',
279
+ action: searchRun
280
+ }),
281
+ events: []
282
+ };
283
+ },
284
+ async close () {}
285
+ };
286
+ const proseOnly = await createDshEmbeddedBookingPlanner({
287
+ runPort: proseOnlyPort
288
+ });
289
+ const proseDecisions = await proseOnly.plannerFactory(task).next({
290
+ task,
291
+ turn: {
292
+ schemaVersion: 'booking.surface.v1',
293
+ kind: 'user.turn',
294
+ taskId: task.taskId,
295
+ workspace: {
296
+ ...workspace,
297
+ capabilities: {
298
+ ...workspace.capabilities,
299
+ allowedActions: [
300
+ ...workspace.capabilities.allowedActions
301
+ ]
302
+ }
303
+ },
304
+ request: {
305
+ text: 'JSON prose must stay prose'
306
+ }
307
+ }
308
+ });
309
+ assert.equal(proseDecisions[0]?.kind, 'error', 'JSON-looking assistant prose is never executable');
310
+ const forbiddenPort = {
311
+ async run () {
312
+ return {
313
+ finalResponse: '',
314
+ events: [
315
+ {
316
+ type: 'tool/call',
317
+ data: {
318
+ name: 'gotry_book',
319
+ arguments: JSON.stringify({
320
+ decision: {
321
+ kind: 'operation',
322
+ action: {
323
+ ...searchRun,
324
+ kind: 'book'
325
+ }
326
+ }
327
+ })
328
+ }
329
+ }
330
+ ]
331
+ };
332
+ },
333
+ async close () {}
334
+ };
335
+ const forbidden = await createDshEmbeddedBookingPlanner({
336
+ runPort: forbiddenPort
337
+ });
338
+ await assert.rejects(forbidden.plannerFactory(task).next({
339
+ task,
340
+ turn: {
341
+ schemaVersion: 'booking.surface.v1',
342
+ kind: 'user.turn',
343
+ taskId: task.taskId,
344
+ workspace: {
345
+ ...workspace,
346
+ capabilities: {
347
+ ...workspace.capabilities,
348
+ allowedActions: [
349
+ ...workspace.capabilities.allowedActions
350
+ ]
351
+ }
352
+ },
353
+ request: {
354
+ text: '帮我下单'
355
+ }
356
+ }
357
+ }), /planner_forbidden_tool/);
358
+ const v2Task = {
359
+ schemaVersion: 'booking.surface.v2',
360
+ taskId: 'task-dsh-v2',
361
+ contextRef: 'ctx-dsh-v2',
362
+ surface: 'tenant',
363
+ revision: 0,
364
+ allowedActions: [
365
+ 'search.run'
366
+ ],
367
+ userTurnCount: 1,
368
+ operationCount: 0,
369
+ phase: 'planning',
370
+ lastSequence: 0,
371
+ availability: {
372
+ initialized: true,
373
+ recoveryStarted: true,
374
+ availabilityPhase: 'terminal',
375
+ activeHotelOrdinal: 0,
376
+ hotelRefs: [],
377
+ hotels: {},
378
+ attempts: [],
379
+ queryReservations: [],
380
+ terminal: {
381
+ code: 'availability_exhausted_complete',
382
+ hotelRefs: [],
383
+ reason: 'no_current_offers',
384
+ evidence: 'conclusive'
385
+ }
386
+ }
387
+ };
388
+ const v2Workspace = {
389
+ schemaVersion: 'booking.surface.v2',
390
+ contextRef: v2Task.contextRef,
391
+ surface: 'tenant',
392
+ revision: 0,
393
+ locale: 'en-US',
394
+ currency: 'AED',
395
+ searchDraft: {},
396
+ results: {
397
+ status: 'idle'
398
+ },
399
+ visibleHotels: [],
400
+ loadedOffers: [],
401
+ shortlistedOfferRefs: [],
402
+ capabilities: {
403
+ surface: 'tenant',
404
+ allowedActions: [
405
+ 'search.run'
406
+ ]
407
+ }
408
+ };
409
+ let v2Runs = 0;
410
+ const v2Port = {
411
+ async run () {
412
+ v2Runs++;
413
+ return v2Runs === 1 ? {
414
+ finalResponse: '',
415
+ events: [
416
+ {
417
+ type: 'tool/call',
418
+ data: {
419
+ name: 'booking_search_hotels',
420
+ arguments: JSON.stringify({
421
+ decision: {
422
+ kind: 'operation',
423
+ action: {
424
+ ...searchRun,
425
+ schemaVersion: 'booking.surface.v2',
426
+ contextRef: v2Task.contextRef,
427
+ actionId: 'action-dsh-v2'
428
+ }
429
+ }
430
+ })
431
+ }
432
+ }
433
+ ]
434
+ } : {
435
+ finalResponse: '',
436
+ events: [
437
+ {
438
+ type: 'tool/call',
439
+ data: {
440
+ name: 'booking_search_hotels',
441
+ arguments: JSON.stringify({
442
+ decision: {
443
+ kind: 'terminal',
444
+ terminal: {
445
+ status: 'stopped',
446
+ summary: 'receipt continuation handled',
447
+ factRefs: []
448
+ }
449
+ }
450
+ })
451
+ }
452
+ }
453
+ ]
454
+ };
455
+ },
456
+ async close () {}
457
+ };
458
+ const v2Adapter = await createDshEmbeddedBookingPlannerV2({
459
+ runPort: v2Port
460
+ });
461
+ const v2Decisions = await v2Adapter.plannerFactory(v2Task).next({
462
+ task: v2Task,
463
+ turn: {
464
+ schemaVersion: 'booking.surface.v2',
465
+ kind: 'user.turn',
466
+ taskId: v2Task.taskId,
467
+ turnId: 'dsh-v2-turn-1',
468
+ workspace: v2Workspace,
469
+ request: {
470
+ text: 'find hotels'
471
+ }
472
+ }
473
+ });
474
+ assert.equal(v2Decisions[0]?.kind, 'operation', 'real DSH adapter accepts canonical v2 typed action');
475
+ assert.equal(v2Decisions[0]?.kind === 'operation' ? v2Decisions[0].action.schemaVersion : '', 'booking.surface.v2');
476
+ const v2Continuation = {
477
+ schemaVersion: 'booking.surface.v2',
478
+ kind: 'action.receipt.continuation',
479
+ taskId: v2Task.taskId,
480
+ workspace: {
481
+ ...v2Workspace,
482
+ revision: 1
483
+ },
484
+ receipt: {
485
+ schemaVersion: 'booking.surface.v2',
486
+ kind: 'action.receipt',
487
+ actionId: 'action-dsh-v2',
488
+ contextRef: v2Task.contextRef,
489
+ status: 'applied',
490
+ revision: 1,
491
+ observation: {
492
+ kind: 'search.state',
493
+ resultCount: 1
494
+ },
495
+ resultContract: {
496
+ outcome: 'complete',
497
+ hardCriteriaMet: true,
498
+ factRefs: [],
499
+ gapCodes: [],
500
+ blockers: [],
501
+ relaxationsApplied: []
502
+ }
503
+ }
504
+ };
505
+ const v2ContinuationDecision = await v2Adapter.plannerFactory(v2Task).next({
506
+ task: {
507
+ ...v2Task,
508
+ revision: 1,
509
+ lastReceipt: v2Continuation.receipt
510
+ },
511
+ turn: v2Continuation
512
+ });
513
+ assert.deepEqual(v2ContinuationDecision, [
514
+ {
515
+ kind: 'terminal',
516
+ terminal: {
517
+ status: 'stopped',
518
+ summary: 'receipt continuation handled',
519
+ factRefs: []
520
+ }
521
+ }
522
+ ], 'real DSH v2 planner handles receipt continuation through the typed seam');
523
+ await assert.rejects(v2Adapter.plannerFactory(v2Task).next({
524
+ task: v2Task,
525
+ turn: {
526
+ schemaVersion: 'booking.surface.v2',
527
+ kind: 'user.turn.ingress',
528
+ requestKey: 'browser-request',
529
+ surfaceHint: 'tenant',
530
+ workspace: {
531
+ schemaVersion: 'booking.surface.v2',
532
+ revision: 0,
533
+ locale: 'en-US',
534
+ currency: 'AED',
535
+ searchDraft: {},
536
+ results: {
537
+ status: 'idle'
538
+ },
539
+ visibleHotels: [],
540
+ loadedOffers: [],
541
+ shortlistedOfferRefs: []
542
+ },
543
+ request: {
544
+ text: 'browser ingress must be BFF-bound'
545
+ }
546
+ }
547
+ }), /planner_identity_required/);
548
+ await Promise.all([
549
+ adapter.close(),
550
+ proseOnly.close(),
551
+ forbidden.close(),
552
+ v2Adapter.close()
553
+ ]);
554
+ console.log('BOOKING COPILOT DSH PLANNER PROOF: task session/typed tool decisions/no Book/no prose parser/no portal token OK');
555
+
556
+
557
+ //# sourceURL=ts/scripts/booking-copilot-dsh-planner-proof-tests.ts
@@ -0,0 +1,140 @@
1
+ import assert from 'node:assert/strict';
2
+ import { Ajv2020 } from 'ajv/dist/2020.js';
3
+ import { apply, embeddedBookingToolDefinitions } from '../src/booking-surface/dsh-plugin.js';
4
+ const registered = [];
5
+ apply({
6
+ tools: {
7
+ register (tool) {
8
+ registered.push(tool);
9
+ }
10
+ }
11
+ });
12
+ assert.equal(registered.length, 6);
13
+ assert.deepEqual(registered.map((tool)=>tool.name), [
14
+ 'booking_search_hotels',
15
+ 'booking_refine_results',
16
+ 'booking_find_room_offers',
17
+ 'booking_compare_offers',
18
+ 'booking_prepare_booking',
19
+ 'booking_observe_booking'
20
+ ]);
21
+ assert.deepEqual(registered, embeddedBookingToolDefinitions);
22
+ assert.ok(!registered.some((tool)=>/gotry_book|trade|payment/i.test(String(tool.name))));
23
+ assert.ok(registered.every((tool)=>{
24
+ const parameters = tool.parameters;
25
+ return parameters.additionalProperties === false && Object.keys(parameters.properties ?? {}).join(',') === 'decision';
26
+ }), 'every model-facing tool accepts only one typed decision envelope');
27
+ const prepare = registered.find((tool)=>tool.name === 'booking_prepare_booking');
28
+ const prepareParameters = prepare.parameters;
29
+ const operationBranches = prepareParameters.properties.decision.oneOf[0]?.properties?.action?.oneOf ?? [];
30
+ assert.equal(operationBranches.length, 2, 'prepare-booking exposes offer.check + checkout.prepare only');
31
+ assert.ok(!JSON.stringify(prepare.parameters).includes('book"'), 'schema has no Book discriminator');
32
+ const search = registered.find((tool)=>tool.name === 'booking_search_hotels');
33
+ const validateSearchTool = new Ajv2020({
34
+ allErrors: true,
35
+ strict: true
36
+ }).compile(search.parameters);
37
+ const validSearchDecision = {
38
+ decision: {
39
+ kind: 'operation',
40
+ action: {
41
+ schemaVersion: 'booking.surface.v1',
42
+ kind: 'search.patch',
43
+ actionId: 'action-model-1',
44
+ contextRef: 'ctx-model-1',
45
+ expectedRevision: 0,
46
+ reason: 'Apply the requested budget.',
47
+ factRefs: [],
48
+ input: {
49
+ patch: {
50
+ budget: {
51
+ strength: 'must',
52
+ value: {
53
+ max: {
54
+ amount: '1000',
55
+ currency: 'AED',
56
+ sourceFactRef: 'fact-budget-1'
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ };
65
+ assert.equal(validateSearchTool(validSearchDecision), true, JSON.stringify(validateSearchTool.errors));
66
+ assert.equal(validateSearchTool({
67
+ decision: {
68
+ kind: 'operation',
69
+ action: {
70
+ schemaVersion: 'booking.surface.v2',
71
+ kind: 'search.run',
72
+ actionId: 'action-model-v2',
73
+ contextRef: 'ctx-model-1',
74
+ expectedRevision: 0,
75
+ reason: 'Run the authoritative workspace search.',
76
+ factRefs: [],
77
+ input: {}
78
+ }
79
+ }
80
+ }), true, JSON.stringify(validateSearchTool.errors));
81
+ assert.equal(validateSearchTool({
82
+ ...validSearchDecision,
83
+ decision: {
84
+ ...validSearchDecision.decision,
85
+ action: {
86
+ ...validSearchDecision.decision.action,
87
+ input: {
88
+ patch: {
89
+ unknownCriterion: {
90
+ strength: 'must',
91
+ value: true
92
+ }
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }), false, 'model-facing tool schema closes nested search criteria');
98
+ assert.equal(validateSearchTool({
99
+ ...validSearchDecision,
100
+ decision: {
101
+ ...validSearchDecision.decision,
102
+ action: {
103
+ ...validSearchDecision.decision.action,
104
+ input: {
105
+ patch: {
106
+ budget: {
107
+ strength: 'must',
108
+ value: {
109
+ max: {
110
+ amount: 1000,
111
+ currency: 'AED',
112
+ sourceFactRef: 'fact-budget-1'
113
+ }
114
+ }
115
+ }
116
+ }
117
+ }
118
+ }
119
+ }
120
+ }), false, 'model-facing Money.amount rejects numbers');
121
+ assert.equal(validateSearchTool({
122
+ ...validSearchDecision,
123
+ decision: {
124
+ ...validSearchDecision.decision,
125
+ action: {
126
+ ...validSearchDecision.decision.action,
127
+ input: {
128
+ patch: {
129
+ holder: {
130
+ email: 'x@example.com'
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }), false, 'model-facing tool schema rejects nested holder data');
137
+ console.log('BOOKING COPILOT DSH PLUGIN PROOF: exact six typed tools/no Book OK');
138
+
139
+
140
+ //# sourceURL=ts/scripts/booking-copilot-dsh-plugin-proof-tests.ts