@danceiny/gotry 0.0.1-rc.18 → 0.0.1-rc.20

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 (176) hide show
  1. package/README.md +42 -16
  2. package/README.zh-CN.md +37 -15
  3. package/bin/gotry-bootstrap.js +309 -30
  4. package/bin/gotry-inner.js +74 -23
  5. package/bin/gotry-runtime-resolution.d.ts +1 -1
  6. package/bin/gotry-runtime-resolution.js +7 -8
  7. package/cordis.gotry-patch.yml +22 -8
  8. package/data/stations-12306-verify.json +524 -0
  9. package/dist/capabilities/agent-reach.js +4 -4
  10. package/dist/capabilities/anything.js +62 -29
  11. package/dist/capabilities/channel-health.js +103 -0
  12. package/dist/capabilities/channel-registry.js +213 -0
  13. package/dist/capabilities/doctor.js +307 -0
  14. package/dist/capabilities/effect.js +178 -5
  15. package/dist/capabilities/flyai.js +13 -0
  16. package/dist/capabilities/hbcli.js +28 -2
  17. package/dist/capabilities/session/adapters/ctrip-hotel.js +207 -0
  18. package/dist/capabilities/session/adapters/rail-12306.js +285 -0
  19. package/dist/capabilities/session/extension-bridge.js +14 -1
  20. package/dist/capabilities/session/extension-channel.js +4 -2
  21. package/dist/capabilities/session/extension-distribution.js +1 -1
  22. package/dist/capabilities/session-search.js +311 -0
  23. package/dist/capabilities/visa-policy.js +126 -0
  24. package/dist/scripts/agent-planning-turn-deadline-e2e.js +305 -0
  25. package/dist/scripts/agent-planning-turn-deadline-tests.js +281 -0
  26. package/dist/scripts/anything-tests.js +70 -21
  27. package/dist/scripts/benchmark-environment-bridge-e2e.js +139 -37
  28. package/dist/scripts/benchmark-environment-bridge-tests.js +1099 -306
  29. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +26 -26
  30. package/dist/scripts/{booking-copilot-availability-policy-v2-tests.js → booking-copilot-availability-policy-tests.js} +115 -115
  31. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +41 -1
  32. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +75 -120
  33. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +370 -61
  34. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +2 -2
  35. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +7 -3
  36. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +15 -9
  37. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +19 -11
  38. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +16 -52
  39. package/dist/scripts/booking-copilot-runtime-proof-tests.js +3953 -155
  40. package/dist/scripts/booking-copilot-server-proof-tests.js +58 -23
  41. package/dist/scripts/booking-copilot-startup-proof-tests.js +10 -119
  42. package/dist/scripts/booking-surface-contract-proof-tests.js +1154 -326
  43. package/dist/scripts/bootstrap-tests.js +113 -2
  44. package/dist/scripts/build-metrics-report.js +339 -0
  45. package/dist/scripts/channel-probe-tests.js +148 -0
  46. package/dist/scripts/channel-probe.js +252 -0
  47. package/dist/scripts/channel-registry-tests.js +262 -0
  48. package/dist/scripts/doctor-tests.js +175 -0
  49. package/dist/scripts/effect-tests.js +274 -1
  50. package/dist/scripts/extension-tests.js +129 -11
  51. package/dist/scripts/fact-gate-tests.js +91 -2
  52. package/dist/scripts/flyai-tests.js +17 -1
  53. package/dist/scripts/hbcli-e2e-tests.js +1 -3
  54. package/dist/scripts/hbcli-tests.js +38 -1
  55. package/dist/scripts/metrics-report-tests.js +288 -0
  56. package/dist/scripts/persona-surface-guard-tests.js +19 -0
  57. package/dist/scripts/session-tests.js +401 -1
  58. package/dist/scripts/smoke.js +100 -83
  59. package/dist/scripts/turn-handoff-collect-tests.js +216 -0
  60. package/dist/scripts/turn-handoff-collect.js +189 -0
  61. package/dist/scripts/turn-policy-tests.js +56 -0
  62. package/dist/scripts/typed-contract-canary.js +261 -0
  63. package/dist/scripts/visa-policy-tests.js +75 -0
  64. package/dist/scripts/wish-channel-gate-tests.js +111 -0
  65. package/dist/src/artifact-gate.js +91 -3
  66. package/dist/src/benchmark-agent-conformance.js +39 -16
  67. package/dist/src/benchmark-environment-bridge.js +316 -52
  68. package/dist/src/bookable-facts.js +62 -3
  69. package/dist/src/booking-surface/{availability-policy-v2.js → availability-policy.js} +89 -89
  70. package/dist/src/booking-surface/canonical-schema.js +8 -22
  71. package/dist/src/booking-surface/contracts.js +70 -19
  72. package/dist/src/booking-surface/dsh-planner.js +310 -177
  73. package/dist/src/booking-surface/dsh-plugin.js +3 -3
  74. package/dist/src/booking-surface/index.js +1 -5
  75. package/dist/src/booking-surface/profile.js +1 -1
  76. package/dist/src/booking-surface/runtime.js +1682 -247
  77. package/dist/src/booking-surface/server.js +371 -185
  78. package/dist/src/booking-surface/startup.js +17 -27
  79. package/dist/src/booking-surface/validation.js +270 -760
  80. package/dist/src/index.js +739 -150
  81. package/dist/src/turn-deadline.js +292 -0
  82. package/dist/src/turn-policy.js +146 -0
  83. package/dist/src/wish-pool.js +5 -0
  84. package/extension/background.js +23 -4
  85. package/extension/content-main.js +47 -9
  86. package/extension/manifest.json +27 -9
  87. package/package.json +7 -26
  88. package/schemas/booking.surface.schema.json +2593 -0
  89. package/ts/capabilities/agent-reach.ts +4 -4
  90. package/ts/capabilities/anything.ts +89 -38
  91. package/ts/capabilities/flyai.ts +21 -3
  92. package/ts/capabilities/hbcli.ts +53 -4
  93. package/ts/capabilities/session/action-cache.ts +1 -1
  94. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  95. package/ts/capabilities/session/adapters/rail-12306.ts +293 -0
  96. package/ts/capabilities/session/extension-bridge.ts +32 -2
  97. package/ts/capabilities/session/extension-channel.ts +9 -8
  98. package/ts/capabilities/session/extension-distribution.ts +3 -1
  99. package/ts/capabilities/session/health-watch.ts +1 -1
  100. package/ts/capabilities/session/read-guard.ts +1 -1
  101. package/ts/capabilities/session/wizard.ts +1 -1
  102. package/ts/capabilities/session-search.ts +323 -1
  103. package/ts/dsh-runtime/vendor/README.md +60 -0
  104. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  105. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +200 -0
  106. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +202 -0
  107. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +216 -0
  108. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  109. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +371 -0
  110. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  111. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +56 -0
  112. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  113. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  114. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +126 -0
  115. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  116. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +109 -0
  117. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +27 -0
  118. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  119. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  120. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +170 -0
  121. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +53 -0
  122. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  123. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  124. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  125. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  126. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +20 -0
  127. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  128. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  129. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  130. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  131. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  132. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +16 -0
  133. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +55 -0
  134. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  135. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +91 -0
  136. package/ts/package.json +9 -0
  137. package/ts/scripts/turn-handoff-collect.ts +178 -0
  138. package/ts/src/artifact-gate.ts +82 -2
  139. package/ts/src/benchmark-agent-conformance.ts +54 -15
  140. package/ts/src/benchmark-environment-bridge.ts +234 -46
  141. package/ts/src/bookable-facts.ts +109 -5
  142. package/ts/src/booking-saga.ts +1 -1
  143. package/ts/src/booking-surface/{availability-policy-v2.ts → availability-policy.ts} +124 -125
  144. package/ts/src/booking-surface/canonical-schema.js +8 -22
  145. package/ts/src/booking-surface/contracts.ts +278 -239
  146. package/ts/src/booking-surface/dsh-planner.ts +333 -194
  147. package/ts/src/booking-surface/dsh-plugin.js +3 -3
  148. package/ts/src/booking-surface/index.ts +1 -5
  149. package/ts/src/booking-surface/profile.ts +11 -11
  150. package/ts/src/booking-surface/runtime.ts +1351 -351
  151. package/ts/src/booking-surface/server.ts +282 -175
  152. package/ts/src/booking-surface/startup.ts +36 -48
  153. package/ts/src/booking-surface/validation.ts +194 -442
  154. package/ts/src/contracts.ts +1 -1
  155. package/ts/src/index.ts +492 -172
  156. package/ts/src/loop.ts +1 -1
  157. package/ts/src/state-ledger.ts +1 -1
  158. package/ts/src/turn-deadline.ts +365 -0
  159. package/ts/src/turn-policy.ts +154 -0
  160. package/ts/src/wish-pool.ts +17 -4
  161. package/dist/scripts/agent-planning-budget-e2e.js +0 -227
  162. package/dist/scripts/agent-planning-budget-tests.js +0 -173
  163. package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +0 -3935
  164. package/dist/scripts/booking-surface-v2-contract-proof-tests.js +0 -1174
  165. package/dist/src/booking-surface/contracts-v2.js +0 -89
  166. package/dist/src/booking-surface/runtime-v2.js +0 -1771
  167. package/dist/src/booking-surface/server-v2.js +0 -334
  168. package/dist/src/booking-surface/validation-v2.js +0 -319
  169. package/dist/src/tool-budget.js +0 -136
  170. package/schemas/booking.surface.v1.schema.json +0 -927
  171. package/schemas/booking.surface.v2.schema.json +0 -61
  172. package/ts/src/booking-surface/contracts-v2.ts +0 -118
  173. package/ts/src/booking-surface/runtime-v2.ts +0 -1466
  174. package/ts/src/booking-surface/server-v2.ts +0 -247
  175. package/ts/src/booking-surface/validation-v2.ts +0 -205
  176. package/ts/src/tool-budget.ts +0 -165
@@ -1,7 +1,17 @@
1
1
  import assert from 'node:assert/strict';
2
- import { DSH_EMBEDDED_BOOKING_TOOL_NAMES, buildDshPlannerEnvironment, createDshEmbeddedBookingPlanner, createDshEmbeddedBookingPlannerV2 } from '../src/booking-surface/dsh-planner.js';
2
+ import { DSH_EMBEDDED_BOOKING_TOOL_NAMES, buildDshPlannerEnvironment, createDshEmbeddedBookingPlanner } from '../src/booking-surface/dsh-planner.js';
3
+ const availability = {
4
+ initialized: true,
5
+ recoveryStarted: false,
6
+ availabilityPhase: 'need_offers',
7
+ activeHotelOrdinal: 0,
8
+ hotelRefs: [],
9
+ hotels: {},
10
+ attempts: [],
11
+ queryReservations: []
12
+ };
3
13
  const task = {
4
- schemaVersion: 'booking.surface.v1',
14
+ schemaVersion: 'booking.surface',
5
15
  taskId: 'task-dsh-1',
6
16
  contextRef: 'ctx-dsh-1',
7
17
  surface: 'tenant',
@@ -11,12 +21,14 @@ const task = {
11
21
  'search.run'
12
22
  ],
13
23
  userTurnCount: 1,
14
- lastUserTurnDigest: 'request-digest',
24
+ lastTurnId: 'dsh-turn-1',
25
+ operationCount: 0,
15
26
  phase: 'planning',
16
- lastSequence: 0
27
+ lastSequence: 0,
28
+ availability
17
29
  };
18
30
  const workspace = {
19
- schemaVersion: 'booking.surface.v1',
31
+ schemaVersion: 'booking.surface',
20
32
  contextRef: task.contextRef,
21
33
  surface: 'tenant',
22
34
  revision: 0,
@@ -38,7 +50,7 @@ const workspace = {
38
50
  }
39
51
  };
40
52
  const searchRun = {
41
- schemaVersion: 'booking.surface.v1',
53
+ schemaVersion: 'booking.surface',
42
54
  kind: 'search.run',
43
55
  actionId: 'action-dsh-1',
44
56
  contextRef: task.contextRef,
@@ -133,9 +145,10 @@ const session = adapter.plannerFactory(task);
133
145
  const first = await session.next({
134
146
  task,
135
147
  turn: {
136
- schemaVersion: 'booking.surface.v1',
148
+ schemaVersion: 'booking.surface',
137
149
  kind: 'user.turn',
138
150
  taskId: task.taskId,
151
+ turnId: 'dsh-turn-1',
139
152
  workspace: {
140
153
  ...workspace,
141
154
  capabilities: {
@@ -157,7 +170,7 @@ assert.deepEqual(first, [
157
170
  }
158
171
  ], 'typed dsh tool call becomes one operation');
159
172
  const receipt = {
160
- schemaVersion: 'booking.surface.v1',
173
+ schemaVersion: 'booking.surface',
161
174
  kind: 'action.receipt',
162
175
  actionId: searchRun.actionId,
163
176
  contextRef: task.contextRef,
@@ -172,7 +185,9 @@ const receipt = {
172
185
  outcome: 'complete',
173
186
  hardCriteriaMet: true,
174
187
  factRefs: [],
175
- gapCodes: []
188
+ gapCodes: [],
189
+ blockers: [],
190
+ relaxationsApplied: []
176
191
  }
177
192
  };
178
193
  const continuedTask = {
@@ -183,7 +198,7 @@ const continuedTask = {
183
198
  const second = await session.next({
184
199
  task: continuedTask,
185
200
  turn: {
186
- schemaVersion: 'booking.surface.v1',
201
+ schemaVersion: 'booking.surface',
187
202
  kind: 'action.receipt.continuation',
188
203
  taskId: task.taskId,
189
204
  workspace: {
@@ -224,9 +239,10 @@ const paymentSession = adapter.plannerFactory(paymentTask);
224
239
  const selected = await paymentSession.next({
225
240
  task: paymentTask,
226
241
  turn: {
227
- schemaVersion: 'booking.surface.v1',
242
+ schemaVersion: 'booking.surface',
228
243
  kind: 'user.turn',
229
244
  taskId: paymentTask.taskId,
245
+ turnId: 'payment-turn-1',
230
246
  workspace: {
231
247
  ...workspace,
232
248
  surface: 'payment_link',
@@ -271,7 +287,7 @@ assert.equal(childEnv.DEEPSEEK_BASE_URL, 'http://model.invalid/v1');
271
287
  assert.equal(childEnv.PORTAL_TOKEN, undefined);
272
288
  assert.equal(childEnv.HOTELBYTE_TOKEN, undefined);
273
289
  assert.equal(childEnv.GOTRY_BOOKING_COPILOT_API_KEY, undefined);
274
- const proseOnlyPort = {
290
+ const textChannelPort = {
275
291
  async run () {
276
292
  return {
277
293
  finalResponse: JSON.stringify({
@@ -283,15 +299,16 @@ const proseOnlyPort = {
283
299
  },
284
300
  async close () {}
285
301
  };
286
- const proseOnly = await createDshEmbeddedBookingPlanner({
287
- runPort: proseOnlyPort
302
+ const textChannel = await createDshEmbeddedBookingPlanner({
303
+ runPort: textChannelPort
288
304
  });
289
- const proseDecisions = await proseOnly.plannerFactory(task).next({
305
+ const textDecisions = await textChannel.plannerFactory(task).next({
290
306
  task,
291
307
  turn: {
292
- schemaVersion: 'booking.surface.v1',
308
+ schemaVersion: 'booking.surface',
293
309
  kind: 'user.turn',
294
310
  taskId: task.taskId,
311
+ turnId: 'dsh-turn-3',
295
312
  workspace: {
296
313
  ...workspace,
297
314
  capabilities: {
@@ -306,7 +323,292 @@ const proseDecisions = await proseOnly.plannerFactory(task).next({
306
323
  }
307
324
  }
308
325
  });
309
- assert.equal(proseDecisions[0]?.kind, 'error', 'JSON-looking assistant prose is never executable');
326
+ assert.equal(textDecisions[0]?.kind, 'operation', 'text-channel typed decisions execute through the same authority path');
327
+ assert.deepEqual(textDecisions[0].action, {
328
+ ...searchRun,
329
+ expectedRevision: 0
330
+ });
331
+ const sanitizedRefPort = {
332
+ async run () {
333
+ return {
334
+ finalResponse: '',
335
+ events: [
336
+ {
337
+ type: 'tool/call',
338
+ data: {
339
+ name: 'booking_search_hotels',
340
+ arguments: JSON.stringify({
341
+ decision: {
342
+ kind: 'operation',
343
+ action: {
344
+ ...searchRun,
345
+ factRefs: [
346
+ 'draft:destination=Dubai'
347
+ ]
348
+ }
349
+ }
350
+ })
351
+ }
352
+ }
353
+ ]
354
+ };
355
+ },
356
+ async close () {}
357
+ };
358
+ const sanitizedRef = await createDshEmbeddedBookingPlanner({
359
+ runPort: sanitizedRefPort
360
+ });
361
+ const sanitizedDecisions = await sanitizedRef.plannerFactory(task).next({
362
+ task,
363
+ turn: {
364
+ schemaVersion: 'booking.surface',
365
+ kind: 'user.turn',
366
+ taskId: task.taskId,
367
+ turnId: 'dsh-turn-6b',
368
+ workspace,
369
+ request: {
370
+ text: 'Find hotels'
371
+ }
372
+ }
373
+ });
374
+ assert.equal(sanitizedDecisions[0]?.kind, 'operation', 'sanitizer maps off-charset characters deterministically');
375
+ assert.deepEqual(sanitizedDecisions[0].action?.factRefs, [
376
+ 'draft:destination.Dubai'
377
+ ]);
378
+ await sanitizedRef.close();
379
+ const unauthorisedPort = {
380
+ async run () {
381
+ return {
382
+ finalResponse: JSON.stringify({
383
+ kind: 'operation',
384
+ action: hotelSelect
385
+ }),
386
+ events: []
387
+ };
388
+ },
389
+ async close () {}
390
+ };
391
+ const unauthorised = await createDshEmbeddedBookingPlanner({
392
+ runPort: unauthorisedPort
393
+ });
394
+ const unauthorisedDecisions = await unauthorised.plannerFactory(task).next({
395
+ task,
396
+ turn: {
397
+ schemaVersion: 'booking.surface',
398
+ kind: 'user.turn',
399
+ taskId: task.taskId,
400
+ turnId: 'dsh-turn-4',
401
+ workspace: {
402
+ ...workspace,
403
+ capabilities: {
404
+ ...workspace.capabilities,
405
+ allowedActions: [
406
+ ...workspace.capabilities.allowedActions
407
+ ]
408
+ }
409
+ },
410
+ request: {
411
+ text: 'Select a hotel'
412
+ }
413
+ }
414
+ });
415
+ assert.equal(unauthorisedDecisions[0]?.kind, 'error', 'text-channel decisions outside allowedActions stay non-executable');
416
+ const fragmentRefPort = {
417
+ async run () {
418
+ return {
419
+ finalResponse: '',
420
+ events: [
421
+ {
422
+ type: 'tool/call',
423
+ data: {
424
+ name: 'booking_search_hotels',
425
+ arguments: JSON.stringify({
426
+ decision: {
427
+ kind: 'operation',
428
+ action: {
429
+ ...searchRun,
430
+ factRefs: [
431
+ `fact://turn_${task.lastTurnId}/request`
432
+ ]
433
+ }
434
+ }
435
+ })
436
+ }
437
+ }
438
+ ]
439
+ };
440
+ },
441
+ async close () {}
442
+ };
443
+ const fragmentRef = await createDshEmbeddedBookingPlanner({
444
+ runPort: fragmentRefPort
445
+ });
446
+ const fragmentDecisions = await fragmentRef.plannerFactory(task).next({
447
+ task,
448
+ turn: {
449
+ schemaVersion: 'booking.surface',
450
+ kind: 'user.turn',
451
+ taskId: task.taskId,
452
+ turnId: 'dsh-turn-7',
453
+ workspace,
454
+ request: {
455
+ text: 'Find hotels'
456
+ }
457
+ }
458
+ });
459
+ assert.equal(fragmentDecisions[0]?.kind, 'operation', 'JSON-pointer fragment factRefs repair into the safe charset');
460
+ assert.deepEqual(fragmentDecisions[0].action?.factRefs, [
461
+ `fact:..turn_${task.lastTurnId}.request`
462
+ ]);
463
+ await fragmentRef.close();
464
+ const truncatedPort = {
465
+ async run () {
466
+ const truncated = JSON.stringify({
467
+ decision: {
468
+ action: {
469
+ ...searchRun,
470
+ factRefs: [
471
+ 'turn_cap-request'
472
+ ]
473
+ },
474
+ kind: 'operation'
475
+ }
476
+ }).replace(/}+$/, '');
477
+ return {
478
+ finalResponse: truncated,
479
+ events: []
480
+ };
481
+ },
482
+ async close () {}
483
+ };
484
+ const truncatedRecovery = await createDshEmbeddedBookingPlanner({
485
+ runPort: truncatedPort
486
+ });
487
+ const truncatedDecisions = await truncatedRecovery.plannerFactory(task).next({
488
+ task,
489
+ turn: {
490
+ schemaVersion: 'booking.surface',
491
+ kind: 'user.turn',
492
+ taskId: task.taskId,
493
+ turnId: 'dsh-turn-8',
494
+ workspace,
495
+ request: {
496
+ text: 'Find hotels'
497
+ }
498
+ }
499
+ });
500
+ assert.equal(truncatedDecisions[0]?.kind, 'operation', 'truncated-but-reconstructable finalResponse recovers through the authority path');
501
+ await truncatedRecovery.close();
502
+ const unsafeRefPort = {
503
+ async run () {
504
+ return {
505
+ finalResponse: '',
506
+ events: [
507
+ {
508
+ type: 'tool/call',
509
+ data: {
510
+ name: 'booking_search_hotels',
511
+ arguments: JSON.stringify({
512
+ decision: {
513
+ kind: 'operation',
514
+ action: {
515
+ ...searchRun,
516
+ factRefs: [
517
+ 42
518
+ ]
519
+ }
520
+ }
521
+ })
522
+ }
523
+ }
524
+ ]
525
+ };
526
+ },
527
+ async close () {}
528
+ };
529
+ const unsafeRef = await createDshEmbeddedBookingPlanner({
530
+ runPort: unsafeRefPort
531
+ });
532
+ await assert.rejects(unsafeRef.plannerFactory(task).next({
533
+ task,
534
+ turn: {
535
+ schemaVersion: 'booking.surface',
536
+ kind: 'user.turn',
537
+ taskId: task.taskId,
538
+ turnId: 'dsh-turn-6',
539
+ workspace,
540
+ request: {
541
+ text: 'Find hotels'
542
+ }
543
+ }
544
+ }), /planner_invalid_action/, 'non-string factRef entries retry as parse-class failures, not ledger-boundary crashes');
545
+ await unsafeRef.close();
546
+ const foreignOfferWorkspace = {
547
+ ...workspace,
548
+ loadedOffers: [
549
+ {
550
+ offerRef: "offer-ui-1",
551
+ offerVersionRef: "offerv-ui-1",
552
+ hotelRef: "hotel-ui-9",
553
+ evidenceLevel: "rate_loaded",
554
+ factRefs: []
555
+ }
556
+ ]
557
+ };
558
+ const uiOffersPort = {
559
+ async run (prompt) {
560
+ assert.ok(prompt.includes("hotel-ui-9"), "workspace loadedOffers reach the planner payload");
561
+ return {
562
+ finalResponse: "",
563
+ events: []
564
+ };
565
+ },
566
+ async close () {}
567
+ };
568
+ const uiOffers = await createDshEmbeddedBookingPlanner({
569
+ runPort: uiOffersPort
570
+ });
571
+ const uiOffersDecisions = await uiOffers.plannerFactory(task).next({
572
+ task,
573
+ turn: {
574
+ schemaVersion: "booking.surface",
575
+ kind: "user.turn",
576
+ taskId: task.taskId,
577
+ turnId: "dsh-turn-ui",
578
+ workspace: foreignOfferWorkspace,
579
+ request: {
580
+ text: "Prepare the loaded offer"
581
+ }
582
+ }
583
+ });
584
+ assert.equal(uiOffersDecisions[0]?.kind, "error", "foreign loadedOffers reach the payload without crashing the projection");
585
+ await uiOffers.close();
586
+ const plainProsePort = {
587
+ async run () {
588
+ return {
589
+ finalResponse: 'I would search hotels in Dubai for you.',
590
+ events: []
591
+ };
592
+ },
593
+ async close () {}
594
+ };
595
+ const plainProse = await createDshEmbeddedBookingPlanner({
596
+ runPort: plainProsePort
597
+ });
598
+ const plainProseDecisions = await plainProse.plannerFactory(task).next({
599
+ task,
600
+ turn: {
601
+ schemaVersion: 'booking.surface',
602
+ kind: 'user.turn',
603
+ taskId: task.taskId,
604
+ turnId: 'dsh-turn-5',
605
+ workspace,
606
+ request: {
607
+ text: 'Find hotels'
608
+ }
609
+ }
610
+ });
611
+ assert.equal(plainProseDecisions[0]?.kind, 'error', 'prose without a typed decision envelope is never executable');
310
612
  const forbiddenPort = {
311
613
  async run () {
312
614
  return {
@@ -338,9 +640,10 @@ const forbidden = await createDshEmbeddedBookingPlanner({
338
640
  await assert.rejects(forbidden.plannerFactory(task).next({
339
641
  task,
340
642
  turn: {
341
- schemaVersion: 'booking.surface.v1',
643
+ schemaVersion: 'booking.surface',
342
644
  kind: 'user.turn',
343
645
  taskId: task.taskId,
646
+ turnId: 'dsh-turn-4',
344
647
  workspace: {
345
648
  ...workspace,
346
649
  capabilities: {
@@ -355,10 +658,10 @@ await assert.rejects(forbidden.plannerFactory(task).next({
355
658
  }
356
659
  }
357
660
  }), /planner_forbidden_tool/);
358
- const v2Task = {
359
- schemaVersion: 'booking.surface.v2',
360
- taskId: 'task-dsh-v2',
361
- contextRef: 'ctx-dsh-v2',
661
+ const terminalTask = {
662
+ schemaVersion: 'booking.surface',
663
+ taskId: 'task-dsh-terminal',
664
+ contextRef: 'ctx-dsh-terminal',
362
665
  surface: 'tenant',
363
666
  revision: 0,
364
667
  allowedActions: [
@@ -385,9 +688,9 @@ const v2Task = {
385
688
  }
386
689
  }
387
690
  };
388
- const v2Workspace = {
389
- schemaVersion: 'booking.surface.v2',
390
- contextRef: v2Task.contextRef,
691
+ const terminalWorkspace = {
692
+ schemaVersion: 'booking.surface',
693
+ contextRef: terminalTask.contextRef,
391
694
  surface: 'tenant',
392
695
  revision: 0,
393
696
  locale: 'en-US',
@@ -406,11 +709,11 @@ const v2Workspace = {
406
709
  ]
407
710
  }
408
711
  };
409
- let v2Runs = 0;
410
- const v2Port = {
712
+ let terminalRuns = 0;
713
+ const terminalPort = {
411
714
  async run () {
412
- v2Runs++;
413
- return v2Runs === 1 ? {
715
+ terminalRuns++;
716
+ return terminalRuns === 1 ? {
414
717
  finalResponse: '',
415
718
  events: [
416
719
  {
@@ -422,9 +725,9 @@ const v2Port = {
422
725
  kind: 'operation',
423
726
  action: {
424
727
  ...searchRun,
425
- schemaVersion: 'booking.surface.v2',
426
- contextRef: v2Task.contextRef,
427
- actionId: 'action-dsh-v2'
728
+ schemaVersion: 'booking.surface',
729
+ contextRef: terminalTask.contextRef,
730
+ actionId: 'action-dsh-terminal'
428
731
  }
429
732
  }
430
733
  })
@@ -455,37 +758,37 @@ const v2Port = {
455
758
  },
456
759
  async close () {}
457
760
  };
458
- const v2Adapter = await createDshEmbeddedBookingPlannerV2({
459
- runPort: v2Port
761
+ const terminalAdapter = await createDshEmbeddedBookingPlanner({
762
+ runPort: terminalPort
460
763
  });
461
- const v2Decisions = await v2Adapter.plannerFactory(v2Task).next({
462
- task: v2Task,
764
+ const terminalDecisions = await terminalAdapter.plannerFactory(terminalTask).next({
765
+ task: terminalTask,
463
766
  turn: {
464
- schemaVersion: 'booking.surface.v2',
767
+ schemaVersion: 'booking.surface',
465
768
  kind: 'user.turn',
466
- taskId: v2Task.taskId,
467
- turnId: 'dsh-v2-turn-1',
468
- workspace: v2Workspace,
769
+ taskId: terminalTask.taskId,
770
+ turnId: 'dsh-terminal-turn-1',
771
+ workspace: terminalWorkspace,
469
772
  request: {
470
773
  text: 'find hotels'
471
774
  }
472
775
  }
473
776
  });
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',
777
+ assert.equal(terminalDecisions[0]?.kind, 'operation', 'real DSH adapter accepts the canonical typed action');
778
+ assert.equal(terminalDecisions[0]?.kind === 'operation' ? terminalDecisions[0].action.schemaVersion : '', 'booking.surface');
779
+ const terminalContinuation = {
780
+ schemaVersion: 'booking.surface',
478
781
  kind: 'action.receipt.continuation',
479
- taskId: v2Task.taskId,
782
+ taskId: terminalTask.taskId,
480
783
  workspace: {
481
- ...v2Workspace,
784
+ ...terminalWorkspace,
482
785
  revision: 1
483
786
  },
484
787
  receipt: {
485
- schemaVersion: 'booking.surface.v2',
788
+ schemaVersion: 'booking.surface',
486
789
  kind: 'action.receipt',
487
- actionId: 'action-dsh-v2',
488
- contextRef: v2Task.contextRef,
790
+ actionId: 'action-dsh-terminal',
791
+ contextRef: terminalTask.contextRef,
489
792
  status: 'applied',
490
793
  revision: 1,
491
794
  observation: {
@@ -502,15 +805,15 @@ const v2Continuation = {
502
805
  }
503
806
  }
504
807
  };
505
- const v2ContinuationDecision = await v2Adapter.plannerFactory(v2Task).next({
808
+ const terminalContinuationDecision = await terminalAdapter.plannerFactory(terminalTask).next({
506
809
  task: {
507
- ...v2Task,
810
+ ...terminalTask,
508
811
  revision: 1,
509
- lastReceipt: v2Continuation.receipt
812
+ lastReceipt: terminalContinuation.receipt
510
813
  },
511
- turn: v2Continuation
814
+ turn: terminalContinuation
512
815
  });
513
- assert.deepEqual(v2ContinuationDecision, [
816
+ assert.deepEqual(terminalContinuationDecision, [
514
817
  {
515
818
  kind: 'terminal',
516
819
  terminal: {
@@ -519,16 +822,16 @@ assert.deepEqual(v2ContinuationDecision, [
519
822
  factRefs: []
520
823
  }
521
824
  }
522
- ], 'real DSH v2 planner handles receipt continuation through the typed seam');
523
- await assert.rejects(v2Adapter.plannerFactory(v2Task).next({
524
- task: v2Task,
825
+ ], 'real DSH planner handles receipt continuation through the typed seam');
826
+ await assert.rejects(terminalAdapter.plannerFactory(terminalTask).next({
827
+ task: terminalTask,
525
828
  turn: {
526
- schemaVersion: 'booking.surface.v2',
829
+ schemaVersion: 'booking.surface',
527
830
  kind: 'user.turn.ingress',
528
831
  requestKey: 'browser-request',
529
832
  surfaceHint: 'tenant',
530
833
  workspace: {
531
- schemaVersion: 'booking.surface.v2',
834
+ schemaVersion: 'booking.surface',
532
835
  revision: 0,
533
836
  locale: 'en-US',
534
837
  currency: 'AED',
@@ -547,9 +850,15 @@ await assert.rejects(v2Adapter.plannerFactory(v2Task).next({
547
850
  }), /planner_identity_required/);
548
851
  await Promise.all([
549
852
  adapter.close(),
550
- proseOnly.close(),
853
+ textChannel.close(),
854
+ unauthorised.close(),
855
+ fragmentRef.close(),
856
+ truncatedRecovery.close(),
857
+ sanitizedRef.close(),
858
+ unsafeRef.close(),
859
+ uiOffers.close(),
551
860
  forbidden.close(),
552
- v2Adapter.close()
861
+ terminalAdapter.close()
553
862
  ]);
554
863
  console.log('BOOKING COPILOT DSH PLANNER PROOF: task session/typed tool decisions/no Book/no prose parser/no portal token OK');
555
864
 
@@ -38,7 +38,7 @@ const validSearchDecision = {
38
38
  decision: {
39
39
  kind: 'operation',
40
40
  action: {
41
- schemaVersion: 'booking.surface.v1',
41
+ schemaVersion: 'booking.surface',
42
42
  kind: 'search.patch',
43
43
  actionId: 'action-model-1',
44
44
  contextRef: 'ctx-model-1',
@@ -67,7 +67,7 @@ assert.equal(validateSearchTool({
67
67
  decision: {
68
68
  kind: 'operation',
69
69
  action: {
70
- schemaVersion: 'booking.surface.v2',
70
+ schemaVersion: 'booking.surface',
71
71
  kind: 'search.run',
72
72
  actionId: 'action-model-v2',
73
73
  contextRef: 'ctx-model-1',
@@ -8,7 +8,7 @@ import { ensureLedger } from '../src/state-ledger.js';
8
8
  import { BookingCopilotTaskRuntime } from '../src/booking-surface/runtime.js';
9
9
  const taskId = 'task-event-sequence-atomicity';
10
10
  const workspace = {
11
- schemaVersion: 'booking.surface.v1',
11
+ schemaVersion: 'booking.surface',
12
12
  contextRef: 'ctx-event-sequence-atomicity',
13
13
  surface: 'tenant',
14
14
  revision: 0,
@@ -29,9 +29,10 @@ const workspace = {
29
29
  }
30
30
  };
31
31
  const turn = {
32
- schemaVersion: 'booking.surface.v1',
32
+ schemaVersion: 'booking.surface',
33
33
  kind: 'user.turn',
34
34
  taskId,
35
+ turnId: 'seq-anchor-turn',
35
36
  workspace,
36
37
  request: {
37
38
  text: 'opaque user turn'
@@ -121,7 +122,10 @@ if (child) {
121
122
  return state;
122
123
  };
123
124
  try {
124
- if (mode === 'user-turn') runtime.startTask(turn);
125
+ if (mode === 'user-turn') runtime.startTask({
126
+ ...turn,
127
+ turnId: `seq-${variant}-turn`
128
+ });
125
129
  const event = runtime.emitEvent(taskId, {
126
130
  kind: 'status',
127
131
  status: 'working'