@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.
- package/README.md +42 -16
- package/README.zh-CN.md +37 -15
- package/bin/gotry-bootstrap.js +309 -30
- package/bin/gotry-inner.js +74 -23
- package/bin/gotry-runtime-resolution.d.ts +1 -1
- package/bin/gotry-runtime-resolution.js +7 -8
- package/cordis.gotry-patch.yml +22 -8
- package/data/stations-12306-verify.json +524 -0
- package/dist/capabilities/agent-reach.js +4 -4
- package/dist/capabilities/anything.js +62 -29
- package/dist/capabilities/channel-health.js +103 -0
- package/dist/capabilities/channel-registry.js +213 -0
- package/dist/capabilities/doctor.js +307 -0
- package/dist/capabilities/effect.js +178 -5
- package/dist/capabilities/flyai.js +13 -0
- package/dist/capabilities/hbcli.js +28 -2
- package/dist/capabilities/session/adapters/ctrip-hotel.js +207 -0
- package/dist/capabilities/session/adapters/rail-12306.js +285 -0
- package/dist/capabilities/session/extension-bridge.js +14 -1
- package/dist/capabilities/session/extension-channel.js +4 -2
- package/dist/capabilities/session/extension-distribution.js +1 -1
- package/dist/capabilities/session-search.js +311 -0
- package/dist/capabilities/visa-policy.js +126 -0
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +305 -0
- package/dist/scripts/agent-planning-turn-deadline-tests.js +281 -0
- package/dist/scripts/anything-tests.js +70 -21
- package/dist/scripts/benchmark-environment-bridge-e2e.js +139 -37
- package/dist/scripts/benchmark-environment-bridge-tests.js +1099 -306
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +26 -26
- package/dist/scripts/{booking-copilot-availability-policy-v2-tests.js → booking-copilot-availability-policy-tests.js} +115 -115
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +41 -1
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +75 -120
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +370 -61
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +2 -2
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +7 -3
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +15 -9
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +19 -11
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +16 -52
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +3953 -155
- package/dist/scripts/booking-copilot-server-proof-tests.js +58 -23
- package/dist/scripts/booking-copilot-startup-proof-tests.js +10 -119
- package/dist/scripts/booking-surface-contract-proof-tests.js +1154 -326
- package/dist/scripts/bootstrap-tests.js +113 -2
- package/dist/scripts/build-metrics-report.js +339 -0
- package/dist/scripts/channel-probe-tests.js +148 -0
- package/dist/scripts/channel-probe.js +252 -0
- package/dist/scripts/channel-registry-tests.js +262 -0
- package/dist/scripts/doctor-tests.js +175 -0
- package/dist/scripts/effect-tests.js +274 -1
- package/dist/scripts/extension-tests.js +129 -11
- package/dist/scripts/fact-gate-tests.js +91 -2
- package/dist/scripts/flyai-tests.js +17 -1
- package/dist/scripts/hbcli-e2e-tests.js +1 -3
- package/dist/scripts/hbcli-tests.js +38 -1
- package/dist/scripts/metrics-report-tests.js +288 -0
- package/dist/scripts/persona-surface-guard-tests.js +19 -0
- package/dist/scripts/session-tests.js +401 -1
- package/dist/scripts/smoke.js +100 -83
- package/dist/scripts/turn-handoff-collect-tests.js +216 -0
- package/dist/scripts/turn-handoff-collect.js +189 -0
- package/dist/scripts/turn-policy-tests.js +56 -0
- package/dist/scripts/typed-contract-canary.js +261 -0
- package/dist/scripts/visa-policy-tests.js +75 -0
- package/dist/scripts/wish-channel-gate-tests.js +111 -0
- package/dist/src/artifact-gate.js +91 -3
- package/dist/src/benchmark-agent-conformance.js +39 -16
- package/dist/src/benchmark-environment-bridge.js +316 -52
- package/dist/src/bookable-facts.js +62 -3
- package/dist/src/booking-surface/{availability-policy-v2.js → availability-policy.js} +89 -89
- package/dist/src/booking-surface/canonical-schema.js +8 -22
- package/dist/src/booking-surface/contracts.js +70 -19
- package/dist/src/booking-surface/dsh-planner.js +310 -177
- package/dist/src/booking-surface/dsh-plugin.js +3 -3
- package/dist/src/booking-surface/index.js +1 -5
- package/dist/src/booking-surface/profile.js +1 -1
- package/dist/src/booking-surface/runtime.js +1682 -247
- package/dist/src/booking-surface/server.js +371 -185
- package/dist/src/booking-surface/startup.js +17 -27
- package/dist/src/booking-surface/validation.js +270 -760
- package/dist/src/index.js +739 -150
- package/dist/src/turn-deadline.js +292 -0
- package/dist/src/turn-policy.js +146 -0
- package/dist/src/wish-pool.js +5 -0
- package/extension/background.js +23 -4
- package/extension/content-main.js +47 -9
- package/extension/manifest.json +27 -9
- package/package.json +7 -26
- package/schemas/booking.surface.schema.json +2593 -0
- package/ts/capabilities/agent-reach.ts +4 -4
- package/ts/capabilities/anything.ts +89 -38
- package/ts/capabilities/flyai.ts +21 -3
- package/ts/capabilities/hbcli.ts +53 -4
- package/ts/capabilities/session/action-cache.ts +1 -1
- package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
- package/ts/capabilities/session/adapters/rail-12306.ts +293 -0
- package/ts/capabilities/session/extension-bridge.ts +32 -2
- package/ts/capabilities/session/extension-channel.ts +9 -8
- package/ts/capabilities/session/extension-distribution.ts +3 -1
- package/ts/capabilities/session/health-watch.ts +1 -1
- package/ts/capabilities/session/read-guard.ts +1 -1
- package/ts/capabilities/session/wizard.ts +1 -1
- package/ts/capabilities/session-search.ts +323 -1
- package/ts/dsh-runtime/vendor/README.md +60 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +200 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +202 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +216 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +371 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +56 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +126 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +109 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +27 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +170 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +53 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +20 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +55 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +91 -0
- package/ts/package.json +9 -0
- package/ts/scripts/turn-handoff-collect.ts +178 -0
- package/ts/src/artifact-gate.ts +82 -2
- package/ts/src/benchmark-agent-conformance.ts +54 -15
- package/ts/src/benchmark-environment-bridge.ts +234 -46
- package/ts/src/bookable-facts.ts +109 -5
- package/ts/src/booking-saga.ts +1 -1
- package/ts/src/booking-surface/{availability-policy-v2.ts → availability-policy.ts} +124 -125
- package/ts/src/booking-surface/canonical-schema.js +8 -22
- package/ts/src/booking-surface/contracts.ts +278 -239
- package/ts/src/booking-surface/dsh-planner.ts +333 -194
- package/ts/src/booking-surface/dsh-plugin.js +3 -3
- package/ts/src/booking-surface/index.ts +1 -5
- package/ts/src/booking-surface/profile.ts +11 -11
- package/ts/src/booking-surface/runtime.ts +1351 -351
- package/ts/src/booking-surface/server.ts +282 -175
- package/ts/src/booking-surface/startup.ts +36 -48
- package/ts/src/booking-surface/validation.ts +194 -442
- package/ts/src/contracts.ts +1 -1
- package/ts/src/index.ts +492 -172
- package/ts/src/loop.ts +1 -1
- package/ts/src/state-ledger.ts +1 -1
- package/ts/src/turn-deadline.ts +365 -0
- package/ts/src/turn-policy.ts +154 -0
- package/ts/src/wish-pool.ts +17 -4
- package/dist/scripts/agent-planning-budget-e2e.js +0 -227
- package/dist/scripts/agent-planning-budget-tests.js +0 -173
- package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +0 -3935
- package/dist/scripts/booking-surface-v2-contract-proof-tests.js +0 -1174
- package/dist/src/booking-surface/contracts-v2.js +0 -89
- package/dist/src/booking-surface/runtime-v2.js +0 -1771
- package/dist/src/booking-surface/server-v2.js +0 -334
- package/dist/src/booking-surface/validation-v2.js +0 -319
- package/dist/src/tool-budget.js +0 -136
- package/schemas/booking.surface.v1.schema.json +0 -927
- package/schemas/booking.surface.v2.schema.json +0 -61
- package/ts/src/booking-surface/contracts-v2.ts +0 -118
- package/ts/src/booking-surface/runtime-v2.ts +0 -1466
- package/ts/src/booking-surface/server-v2.ts +0 -247
- package/ts/src/booking-surface/validation-v2.ts +0 -205
- 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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
287
|
-
runPort:
|
|
302
|
+
const textChannel = await createDshEmbeddedBookingPlanner({
|
|
303
|
+
runPort: textChannelPort
|
|
288
304
|
});
|
|
289
|
-
const
|
|
305
|
+
const textDecisions = await textChannel.plannerFactory(task).next({
|
|
290
306
|
task,
|
|
291
307
|
turn: {
|
|
292
|
-
schemaVersion: 'booking.surface
|
|
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(
|
|
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
|
|
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
|
|
359
|
-
schemaVersion: 'booking.surface
|
|
360
|
-
taskId: 'task-dsh-
|
|
361
|
-
contextRef: 'ctx-dsh-
|
|
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
|
|
389
|
-
schemaVersion: 'booking.surface
|
|
390
|
-
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
|
|
410
|
-
const
|
|
712
|
+
let terminalRuns = 0;
|
|
713
|
+
const terminalPort = {
|
|
411
714
|
async run () {
|
|
412
|
-
|
|
413
|
-
return
|
|
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
|
|
426
|
-
contextRef:
|
|
427
|
-
actionId: 'action-dsh-
|
|
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
|
|
459
|
-
runPort:
|
|
761
|
+
const terminalAdapter = await createDshEmbeddedBookingPlanner({
|
|
762
|
+
runPort: terminalPort
|
|
460
763
|
});
|
|
461
|
-
const
|
|
462
|
-
task:
|
|
764
|
+
const terminalDecisions = await terminalAdapter.plannerFactory(terminalTask).next({
|
|
765
|
+
task: terminalTask,
|
|
463
766
|
turn: {
|
|
464
|
-
schemaVersion: 'booking.surface
|
|
767
|
+
schemaVersion: 'booking.surface',
|
|
465
768
|
kind: 'user.turn',
|
|
466
|
-
taskId:
|
|
467
|
-
turnId: 'dsh-
|
|
468
|
-
workspace:
|
|
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(
|
|
475
|
-
assert.equal(
|
|
476
|
-
const
|
|
477
|
-
schemaVersion: 'booking.surface
|
|
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:
|
|
782
|
+
taskId: terminalTask.taskId,
|
|
480
783
|
workspace: {
|
|
481
|
-
...
|
|
784
|
+
...terminalWorkspace,
|
|
482
785
|
revision: 1
|
|
483
786
|
},
|
|
484
787
|
receipt: {
|
|
485
|
-
schemaVersion: 'booking.surface
|
|
788
|
+
schemaVersion: 'booking.surface',
|
|
486
789
|
kind: 'action.receipt',
|
|
487
|
-
actionId: 'action-dsh-
|
|
488
|
-
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
|
|
808
|
+
const terminalContinuationDecision = await terminalAdapter.plannerFactory(terminalTask).next({
|
|
506
809
|
task: {
|
|
507
|
-
...
|
|
810
|
+
...terminalTask,
|
|
508
811
|
revision: 1,
|
|
509
|
-
lastReceipt:
|
|
812
|
+
lastReceipt: terminalContinuation.receipt
|
|
510
813
|
},
|
|
511
|
-
turn:
|
|
814
|
+
turn: terminalContinuation
|
|
512
815
|
});
|
|
513
|
-
assert.deepEqual(
|
|
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
|
|
523
|
-
await assert.rejects(
|
|
524
|
-
task:
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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'
|