@danceiny/gotry 0.0.1-rc.9 → 0.2.0-rc.28
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 +172 -219
- package/README.zh-CN.md +222 -0
- package/bin/gotry-backend.js +53 -0
- package/bin/gotry-booking-copilot.js +53 -0
- package/bin/gotry-bootstrap.js +1788 -0
- package/bin/gotry-inner.js +733 -83
- package/bin/gotry-process-liveness.d.ts +27 -0
- package/bin/gotry-process-liveness.js +97 -0
- package/bin/gotry-runtime-resolution.d.ts +27 -0
- package/bin/gotry-runtime-resolution.js +49 -0
- package/bin/gotry.js +1 -1
- package/client/client.js +203 -0
- package/cordis.gotry-patch.yml +80 -56
- package/data/airline-airports.json +39 -0
- package/data/stations-12306-verify.json +524 -0
- package/dist/capabilities/agent-reach-deep.js +45 -122
- package/dist/capabilities/agent-reach.js +101 -146
- package/dist/capabilities/anything.js +161 -94
- package/dist/capabilities/artifacts.js +370 -0
- package/dist/capabilities/channel-health.js +131 -0
- package/dist/capabilities/channel-registry.js +256 -0
- package/dist/capabilities/doctor.js +553 -0
- package/dist/capabilities/effect.js +394 -0
- package/dist/capabilities/external-event.js +149 -0
- package/dist/capabilities/fact-log.js +55 -0
- package/dist/capabilities/flyai-config.js +337 -0
- package/dist/capabilities/flyai.js +947 -110
- package/dist/capabilities/fx-contract.js +293 -0
- package/dist/capabilities/geo-atlas.js +246 -0
- package/dist/capabilities/ground-transfer.js +676 -0
- package/dist/capabilities/hbcli.js +260 -123
- package/dist/capabilities/hotelbyte-transaction.js +194 -0
- package/dist/capabilities/incident-log.js +131 -61
- package/dist/capabilities/itinerary-artifact.js +190 -0
- package/dist/capabilities/itinerary-deck-artifact.js +194 -0
- package/dist/capabilities/itinerary-deck-export.js +339 -0
- package/dist/capabilities/lavish-local.js +924 -0
- package/dist/capabilities/model-override.js +38 -0
- package/dist/capabilities/opensky.js +54 -43
- package/dist/capabilities/provider-detail-sanitize.js +64 -0
- package/dist/capabilities/resilience.js +191 -0
- package/dist/capabilities/route-provider-conformance.js +341 -0
- package/dist/capabilities/session/action-cache.js +50 -44
- package/dist/capabilities/session/adapters/ctrip-flight.js +120 -62
- package/dist/capabilities/session/adapters/ctrip-hotel.js +222 -0
- package/dist/capabilities/session/adapters/dida-portal.js +274 -0
- package/dist/capabilities/session/adapters/meituan-local.js +35 -54
- package/dist/capabilities/session/adapters/rail-12306.js +342 -0
- package/dist/capabilities/session/benchmark.js +189 -0
- package/dist/capabilities/session/bridge-ledger.js +224 -0
- package/dist/capabilities/session/extension-bridge.js +636 -0
- package/dist/capabilities/session/extension-channel.js +109 -0
- package/dist/capabilities/session/extension-distribution.js +230 -0
- package/dist/capabilities/session/extract.js +31 -21
- package/dist/capabilities/session/golden-score.js +114 -0
- package/dist/capabilities/session/health-watch.js +215 -0
- package/dist/capabilities/session/read-guard.js +75 -24
- package/dist/capabilities/session/static-flight-golden.js +150 -0
- package/dist/capabilities/session/transport.js +97 -83
- package/dist/capabilities/session/wizard.js +117 -0
- package/dist/capabilities/session-consent.js +178 -0
- package/dist/capabilities/session-login.js +170 -0
- package/dist/capabilities/session-search.js +635 -44
- package/dist/capabilities/spawn-bounded.js +203 -0
- package/dist/capabilities/sponsor-plugin.js +341 -0
- package/dist/capabilities/visa-policy.js +140 -0
- package/dist/capabilities/weather.js +243 -138
- package/dist/data/session-golden-20.json +25 -0
- package/dist/data/sf-golden-manifest.json +103 -0
- package/dist/data/sf-static-routes.json +91 -0
- package/dist/scripts/action-cache-tests.js +24 -59
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +242 -0
- package/dist/scripts/agent-planning-turn-deadline-tests.js +185 -0
- package/dist/scripts/agent-reach-deep-tests.js +30 -40
- package/dist/scripts/agent-reach-error-tests.js +354 -0
- package/dist/scripts/agent-reach-tests.js +26 -18
- package/dist/scripts/agent-reach-wrapper-tests.js +50 -50
- package/dist/scripts/anything-path-measure-tests.js +133 -0
- package/dist/scripts/anything-path-measure.js +150 -0
- package/dist/scripts/anything-tests.js +250 -60
- package/dist/scripts/artifact-client-contract-tests.js +220 -0
- package/dist/scripts/artifacts-capability-tests.js +727 -0
- package/dist/scripts/async-collect.js +50 -11
- package/dist/scripts/benchmark-environment-bridge-e2e.js +741 -0
- package/dist/scripts/benchmark-environment-bridge-tests.js +1452 -0
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +126 -0
- package/dist/scripts/booking-copilot-availability-policy-tests.js +265 -0
- package/dist/scripts/booking-copilot-bin-proof-tests.js +66 -0
- package/dist/scripts/booking-copilot-cleanup-proof-helper.js +76 -0
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +144 -0
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +424 -0
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +2839 -0
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +309 -0
- package/dist/scripts/booking-copilot-dsh-readiness-proof.js +238 -0
- package/dist/scripts/booking-copilot-dsh-warmer-proof.js +126 -0
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +156 -0
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +70 -0
- package/dist/scripts/booking-copilot-intent-proof-tests.js +422 -0
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +184 -0
- package/dist/scripts/booking-copilot-planner-live-probe.js +95 -0
- package/dist/scripts/booking-copilot-proof-runtime.js +42 -0
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +210 -0
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +2349 -0
- package/dist/scripts/booking-copilot-server-proof-tests.js +784 -0
- package/dist/scripts/booking-copilot-startup-proof-tests.js +94 -0
- package/dist/scripts/booking-executor-tests.js +80 -0
- package/dist/scripts/booking-recovery-chain-tests.js +182 -0
- package/dist/scripts/booking-saga-tests.js +125 -0
- package/dist/scripts/booking-surface-contract-proof-tests.js +212 -0
- package/dist/scripts/bootstrap-tests.js +1549 -0
- package/dist/scripts/bridge-events-tests.js +239 -0
- package/dist/scripts/bridge-ledger-tests.js +428 -0
- package/dist/scripts/build-changelog.js +238 -0
- package/dist/scripts/build-metrics-report.js +331 -0
- package/dist/scripts/changelog-tests.js +118 -0
- package/dist/scripts/channel-probe-tests.js +103 -0
- package/dist/scripts/channel-probe.js +169 -0
- package/dist/scripts/channel-registry-tests.js +208 -0
- package/dist/scripts/city-scenario-tier-tests.js +234 -0
- package/dist/scripts/companion-tests.js +25 -70
- package/dist/scripts/dida-cookie-probe.js +87 -0
- package/dist/scripts/dida-runner-stop-tests.js +311 -0
- package/dist/scripts/dida-sw-probe.js +114 -0
- package/dist/scripts/diff-test.js +17 -12
- package/dist/scripts/doctor-tests.js +600 -0
- package/dist/scripts/drill-multiuser-ledger-tests.js +1076 -0
- package/dist/scripts/drill-sdk-descendant-cleanup-tests.js +606 -0
- package/dist/scripts/drill-w2a-sensor-tests.js +788 -0
- package/dist/scripts/dsh-artifact-e2e.js +279 -0
- package/dist/scripts/dsh-artifact-web-e2e.js +675 -0
- package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
- package/dist/scripts/dsh-llm-tests.js +437 -0
- package/dist/scripts/dsh-runtime-closure-tests.js +182 -0
- package/dist/scripts/dsh-runtime-closure.js +162 -0
- package/dist/scripts/dsh-session-v3-migration-proof.js +109 -0
- package/dist/scripts/dsh-subprocess-local-proof.js +150 -0
- package/dist/scripts/dsh-target-closure-proof.js +178 -0
- package/dist/scripts/effect-tests.js +539 -0
- package/dist/scripts/engine-run.js +1 -3
- package/dist/scripts/engine-tests.js +16 -10
- package/dist/scripts/evaluation-cadence-tests.js +174 -0
- package/dist/scripts/evaluation-contract-tests.js +268 -0
- package/dist/scripts/extension-distribution-cli.js +39 -0
- package/dist/scripts/extension-distribution-tests.js +443 -0
- package/dist/scripts/extension-tests.js +988 -0
- package/dist/scripts/external-event-tests.js +350 -0
- package/dist/scripts/fact-gate-tests.js +869 -0
- package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
- package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
- package/dist/scripts/flight-malformed-tests.js +159 -0
- package/dist/scripts/flyai-setup-tests.js +228 -0
- package/dist/scripts/flyai-setup-tool-tests.js +54 -0
- package/dist/scripts/flyai-tests.js +692 -0
- package/dist/scripts/flyai-tool-registration-contract-tests.js +91 -0
- package/dist/scripts/fx-contract-tests.js +201 -0
- package/dist/scripts/g5-guard-tests.js +150 -0
- package/dist/scripts/g5-guard.js +193 -0
- package/dist/scripts/gen-lunar-anchors.js +106 -0
- package/dist/scripts/geo-atlas-tests.js +283 -0
- package/dist/scripts/gotry-backend-kernel-tests.js +206 -0
- package/dist/scripts/gotry-try-demo-tests.js +79 -0
- package/dist/scripts/gotry-try-demo.js +49 -0
- package/dist/scripts/ground-transfer-tests.js +956 -0
- package/dist/scripts/hbcli-e2e-tests.js +159 -0
- package/dist/scripts/hbcli-live-optin-tests.js +96 -0
- package/dist/scripts/hbcli-release-contract-tests.js +122 -0
- package/dist/scripts/hbcli-tests.js +121 -69
- package/dist/scripts/health-watch-cli.js +73 -0
- package/dist/scripts/hotel-date-gate-tests.js +496 -0
- package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
- package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
- package/dist/scripts/i18n-tests.js +41 -0
- package/dist/scripts/incident-tests.js +281 -87
- package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
- package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
- package/dist/scripts/issue-271-liveness-tests.js +569 -0
- package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
- package/dist/scripts/issue-289-model-retry-tests.js +441 -0
- package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
- package/dist/scripts/issue-338-home-city-e2e.js +577 -0
- package/dist/scripts/issue343-real-entry-e2e.js +160 -0
- package/dist/scripts/issue436-persisted-routing-e2e.js +247 -0
- package/dist/scripts/itinerary-artifact-tests.js +368 -0
- package/dist/scripts/itinerary-deck-artifact-tests.js +416 -0
- package/dist/scripts/itinerary-deck-export-tests.js +552 -0
- package/dist/scripts/itinerary-deck-tests.js +435 -0
- package/dist/scripts/itinerary-html-tests.js +426 -0
- package/dist/scripts/journey-tests.js +22 -27
- package/dist/scripts/kernel-manifest-evidence.js +109 -0
- package/dist/scripts/kernel-manifest-gate.js +126 -0
- package/dist/scripts/kernel-manifest-tests.js +212 -0
- package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
- package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
- package/dist/scripts/kernel-manifest.js +369 -0
- package/dist/scripts/lavish-local-tests.js +1226 -0
- package/dist/scripts/lavish-product-tools-tests.js +537 -0
- package/dist/scripts/ledger-repair-apply-tests.js +316 -0
- package/dist/scripts/ledger-repair-plan-tests.js +375 -0
- package/dist/scripts/ledger-tests.js +382 -246
- package/dist/scripts/ledger-workflow-crash.js +10 -20
- package/dist/scripts/m3-cohort-tests.js +714 -0
- package/dist/scripts/m3-cohort.js +310 -0
- package/dist/scripts/managed-dsh-cleanup-diagnostic-proof.js +184 -0
- package/dist/scripts/managed-dsh-close-failure-proof.js +172 -0
- package/dist/scripts/managed-dsh-run-port-proof.js +153 -0
- package/dist/scripts/managed-dsh-terminal-proof.js +252 -0
- package/dist/scripts/map-tools-vendor-package-proof.js +365 -0
- package/dist/scripts/memory-capture-tests.js +242 -61
- package/dist/scripts/memory-decay-tests.js +18 -52
- package/dist/scripts/memory-lifecycle-tests.js +657 -0
- package/dist/scripts/memory-lifecycle.js +196 -0
- package/dist/scripts/memory-metrics.js +24 -12
- package/dist/scripts/memory-value-report.js +631 -0
- package/dist/scripts/memory-value-tests.js +328 -0
- package/dist/scripts/metrics-report-tests.js +151 -0
- package/dist/scripts/model-override-e2e.js +137 -0
- package/dist/scripts/nightly-evidence-tests.js +203 -0
- package/dist/scripts/nightly-evidence.js +303 -0
- package/dist/scripts/nudge-digest.js +39 -28
- package/dist/scripts/observability-tests.js +381 -0
- package/dist/scripts/onboarding-tests.js +161 -0
- package/dist/scripts/opensky-check.js +18 -13
- package/dist/scripts/opensky-tests.js +28 -28
- package/dist/scripts/outcome-projection-tests.js +427 -0
- package/dist/scripts/persona-sim-tests.js +603 -0
- package/dist/scripts/persona-sim.js +1081 -0
- package/dist/scripts/persona-surface-guard-tests.js +49 -0
- package/dist/scripts/pnpm-dsh-closure-proof.js +17 -0
- package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
- package/dist/scripts/price-drift-tests.js +340 -0
- package/dist/scripts/price-drift-watch.js +447 -0
- package/dist/scripts/probe-poi-tests.js +53 -45
- package/dist/scripts/product-metrics.js +483 -0
- package/dist/scripts/publish-preverify.js +110 -0
- package/dist/scripts/realtime-pricing-tests.js +76 -0
- package/dist/scripts/recall-tests.js +513 -0
- package/dist/scripts/replay-async.js +22 -18
- package/dist/scripts/replay-real.js +18 -18
- package/dist/scripts/replay.js +54 -82
- package/dist/scripts/route-provider-conformance-tests.js +391 -0
- package/dist/scripts/session-attach-diagnose.js +20 -20
- package/dist/scripts/session-attach-poc.js +34 -37
- package/dist/scripts/session-benchmark.js +180 -0
- package/dist/scripts/session-dida-live-e2e.js +199 -0
- package/dist/scripts/session-extract-tests.js +14 -35
- package/dist/scripts/session-link-tests.js +478 -0
- package/dist/scripts/session-login.js +27 -46
- package/dist/scripts/session-tests.js +796 -96
- package/dist/scripts/session-zone-crash.js +49 -0
- package/dist/scripts/session-zone-ledger-tests.js +432 -0
- package/dist/scripts/session-zone-observation-tests.js +492 -0
- package/dist/scripts/session-zone-observe.js +135 -0
- package/dist/scripts/session-zone-wiring-tests.js +566 -0
- package/dist/scripts/session-zones-tests.js +374 -0
- package/dist/scripts/sf-live-benchmark.js +367 -0
- package/dist/scripts/sf-live-challenge-stop-tests.js +453 -0
- package/dist/scripts/sf-live-cli-tests.js +92 -0
- package/dist/scripts/sf-live-options.js +46 -0
- package/dist/scripts/sf-manifest-tests.js +30 -0
- package/dist/scripts/sf-manifest.js +33 -0
- package/dist/scripts/sf-soft-score-tests.js +67 -0
- package/dist/scripts/sf-summary-tests.js +324 -0
- package/dist/scripts/sf-summary.js +525 -0
- package/dist/scripts/share-tests.js +432 -0
- package/dist/scripts/skeleton-check.js +16 -14
- package/dist/scripts/skeleton-integration-test.js +28 -11
- package/dist/scripts/skills-contract-tests.js +51 -46
- package/dist/scripts/smoke-session-gate-tests.js +21 -0
- package/dist/scripts/smoke.js +690 -246
- package/dist/scripts/spawn-bounded-abort-tests.js +244 -0
- package/dist/scripts/sponsor-reuse-tests.js +262 -0
- package/dist/scripts/state-cli-tests.js +226 -101
- package/dist/scripts/state-cli.js +565 -198
- package/dist/scripts/state-repair-cli.js +66 -0
- package/dist/scripts/state-repair-tests.js +140 -0
- package/dist/scripts/static-golden-tests.js +165 -0
- package/dist/scripts/time-eval-tests.js +212 -192
- package/dist/scripts/travel-timeline-tests.js +29 -93
- package/dist/scripts/turn-handoff-collect-tests.js +169 -0
- package/dist/scripts/turn-handoff-collect.js +161 -0
- package/dist/scripts/turn-policy-tests.js +55 -0
- package/dist/scripts/typed-contract-canary.js +176 -0
- package/dist/scripts/tz-resolver-sanity.js +50 -0
- package/dist/scripts/tz-resolver-tests.js +584 -0
- package/dist/scripts/unified-tests.js +60 -20
- package/dist/scripts/visa-policy-tests.js +62 -0
- package/dist/scripts/weather-tests.js +276 -41
- package/dist/scripts/wish-channel-gate-tests.js +54 -0
- package/dist/scripts/write-gate-tests.js +522 -0
- package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
- package/dist/scripts/z3-lifecycle-tests.js +170 -0
- package/dist/scripts/z3-race-repeat-tests.js +39 -0
- package/dist/scripts/z3-race-tests.js +46 -0
- package/dist/src/artifact-gate.js +829 -0
- package/dist/src/backend/kernel.js +91 -0
- package/dist/src/backend/modules/booking-copilot.js +92 -0
- package/dist/src/backend/modules/booking-executor.js +124 -0
- package/dist/src/backend/modules/session-search.js +551 -0
- package/dist/src/benchmark-agent-conformance.js +578 -0
- package/dist/src/benchmark-environment-bridge.js +515 -0
- package/dist/src/benchmark-headless-child-diagnostics.js +166 -0
- package/dist/src/benchmark-tool-isolation.js +151 -0
- package/dist/src/bookable-facts.js +533 -0
- package/dist/src/booking-saga.js +97 -0
- package/dist/src/booking-surface/availability-policy.js +697 -0
- package/dist/src/booking-surface/booking-intent.js +43 -0
- package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
- package/dist/src/booking-surface/canonical-schema.js +116 -0
- package/dist/src/booking-surface/contracts.js +75 -0
- package/dist/src/booking-surface/dsh-planner.js +1854 -0
- package/dist/src/booking-surface/dsh-plugin.js +378 -0
- package/dist/src/booking-surface/dsh-worker.js +98 -0
- package/dist/src/booking-surface/error-codes.js +231 -0
- package/dist/src/booking-surface/index.js +9 -0
- package/dist/src/booking-surface/managed-dsh-cleanup-diagnostic.js +97 -0
- package/dist/src/booking-surface/managed-dsh-run-port.js +244 -0
- package/dist/src/booking-surface/profile.js +24 -0
- package/dist/src/booking-surface/recovery-chain.js +367 -0
- package/dist/src/booking-surface/runtime.js +1968 -0
- package/dist/src/booking-surface/server.js +674 -0
- package/dist/src/booking-surface/startup.js +168 -0
- package/dist/src/booking-surface/validation.js +261 -0
- package/dist/src/bridge.js +20 -13
- package/dist/src/city-scenario-tier.js +378 -0
- package/dist/src/companions.js +48 -74
- package/dist/src/contracts.js +21 -43
- package/dist/src/dsh-llm.js +171 -115
- package/dist/src/engine.js +276 -193
- package/dist/src/evaluation-cadence.js +97 -0
- package/dist/src/evaluation-contracts.js +283 -0
- package/dist/src/flight-pack-adapter.js +54 -0
- package/dist/src/flight-pack-contract.js +2 -0
- package/dist/src/flyai-setup-tool.js +70 -0
- package/dist/src/gotry-backend.js +125 -0
- package/dist/src/hotel-date-gate.js +118 -0
- package/dist/src/i18n.js +88 -0
- package/dist/src/index.js +2385 -881
- package/dist/src/itinerary-deck.js +139 -0
- package/dist/src/itinerary-doc-shared.js +661 -0
- package/dist/src/itinerary-html.js +131 -0
- package/dist/src/journey.js +155 -108
- package/dist/src/lavish-tools.js +400 -0
- package/dist/src/ledger-repair-apply.js +538 -0
- package/dist/src/ledger-repair-plan.js +463 -0
- package/dist/src/loop.js +331 -161
- package/dist/src/m3-cohort.js +1577 -0
- package/dist/src/memory-capture.js +180 -32
- package/dist/src/memory-decay.js +30 -14
- package/dist/src/memory-lifecycle.js +1310 -0
- package/dist/src/memory-utility.js +27 -40
- package/dist/src/mock-llm.js +36 -61
- package/dist/src/model.js +81 -36
- package/dist/src/outcome-projection.js +746 -0
- package/dist/src/realtime-pricing.js +103 -0
- package/dist/src/recall/card.js +74 -0
- package/dist/src/recall/evaluator.js +140 -0
- package/dist/src/recall/integration.js +17 -0
- package/dist/src/recall/tick.js +166 -0
- package/dist/src/session-link/plan-it-action.js +48 -0
- package/dist/src/session-link/session-link.js +248 -0
- package/dist/src/session-zone-ledger.js +312 -0
- package/dist/src/session-zone-observation.js +354 -0
- package/dist/src/session-zone-wiring.js +658 -0
- package/dist/src/session-zones.js +510 -0
- package/dist/src/share/adapters.js +51 -0
- package/dist/src/share/share-consent.js +76 -0
- package/dist/src/share/share-deck.js +58 -0
- package/dist/src/share/share-token.js +146 -0
- package/dist/src/slot-spec.js +84 -106
- package/dist/src/state-ledger.js +696 -524
- package/dist/src/state-repair.js +299 -0
- package/dist/src/subagent-job-id-guard.js +58 -0
- package/dist/src/time-anchor.js +231 -33
- package/dist/src/tool-packet.js +20 -8
- package/dist/src/travel-slots.js +58 -35
- package/dist/src/travel-timeline.js +44 -63
- package/dist/src/turn-deadline.js +287 -0
- package/dist/src/turn-policy.js +118 -0
- package/dist/src/tz-resolver.js +143 -0
- package/dist/src/unified.js +600 -360
- package/dist/src/wish-pool.js +42 -12
- package/dist/src/write-gate.js +495 -0
- package/dist/src/z3-shared.js +284 -0
- package/extension/README.md +21 -0
- package/extension/README.zh-CN.md +21 -0
- package/extension/background.js +463 -0
- package/extension/content-bridge.js +270 -0
- package/extension/content-main.js +111 -0
- package/extension/manifest.json +60 -0
- package/package.json +407 -14
- package/schemas/booking.intent.schema.json +193 -0
- package/schemas/booking.surface.schema.json +2622 -0
- package/ts/capabilities/agent-reach-deep.ts +114 -0
- package/ts/capabilities/agent-reach.ts +198 -0
- package/ts/capabilities/anything.ts +282 -0
- package/ts/capabilities/artifacts.ts +428 -0
- package/ts/capabilities/fact-log.ts +54 -0
- package/ts/capabilities/flyai-config.ts +388 -0
- package/ts/capabilities/flyai.ts +1274 -0
- package/ts/capabilities/hbcli.ts +253 -71
- package/ts/capabilities/incident-log.ts +88 -59
- package/ts/capabilities/itinerary-artifact.ts +214 -0
- package/ts/capabilities/itinerary-deck-artifact.ts +218 -0
- package/ts/capabilities/itinerary-deck-export.ts +378 -0
- package/ts/capabilities/opensky.ts +121 -0
- package/ts/capabilities/session/action-cache.ts +148 -0
- package/ts/capabilities/session/adapters/ctrip-flight.ts +181 -0
- package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
- package/ts/capabilities/session/adapters/dida-portal.ts +338 -0
- package/ts/capabilities/session/adapters/meituan-local.ts +70 -0
- package/ts/capabilities/session/adapters/rail-12306.ts +392 -0
- package/ts/capabilities/session/benchmark.ts +276 -0
- package/ts/capabilities/session/bridge-ledger.ts +333 -0
- package/ts/capabilities/session/extension-bridge.ts +794 -0
- package/ts/capabilities/session/extension-channel.ts +144 -0
- package/ts/capabilities/session/extension-distribution.ts +266 -0
- package/ts/capabilities/session/extract.ts +54 -0
- package/ts/capabilities/session/golden-score.ts +139 -0
- package/ts/capabilities/session/health-watch.ts +264 -0
- package/ts/capabilities/session/read-guard.ts +141 -0
- package/ts/capabilities/session/static-flight-golden.ts +209 -0
- package/ts/capabilities/session/transport.ts +146 -0
- package/ts/capabilities/session/wizard.ts +140 -0
- package/ts/capabilities/session-consent.ts +211 -0
- package/ts/capabilities/session-login.ts +208 -0
- package/ts/capabilities/session-search.ts +893 -0
- package/ts/capabilities/weather.ts +330 -0
- package/ts/dsh-runtime/vendor/README.md +68 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +405 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +404 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +1584 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/icon.svg +5 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +595 -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 +58 -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 +131 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/geo.js +232 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +120 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +40 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/staticmap-route.js +115 -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 +267 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +90 -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 +23 -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/geo.d.ts +61 -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/staticmap-route.d.ts +31 -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 +75 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +68 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +97 -0
- package/ts/package.json +293 -3
- package/ts/scripts/async-collect.ts +91 -0
- package/ts/scripts/map-tools-vendor-package-proof.ts +404 -0
- package/ts/scripts/skeleton-check.ts +1 -1
- package/ts/scripts/skeleton-integration-test.ts +23 -1
- package/ts/scripts/state-cli.ts +586 -0
- package/ts/scripts/turn-handoff-collect.ts +178 -0
- package/ts/src/artifact-gate.ts +991 -0
- package/ts/src/benchmark-agent-conformance.ts +619 -0
- package/ts/src/benchmark-environment-bridge.ts +538 -0
- package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
- package/ts/src/benchmark-tool-isolation.ts +166 -0
- package/ts/src/bookable-facts.ts +837 -0
- package/ts/src/booking-saga.ts +133 -0
- package/ts/src/booking-surface/availability-policy.ts +522 -0
- package/ts/src/booking-surface/booking-intent.ts +86 -0
- package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
- package/ts/src/booking-surface/canonical-schema.js +116 -0
- package/ts/src/booking-surface/contracts.ts +475 -0
- package/ts/src/booking-surface/dsh-planner.ts +1949 -0
- package/ts/src/booking-surface/dsh-plugin.js +378 -0
- package/ts/src/booking-surface/dsh-worker.ts +110 -0
- package/ts/src/booking-surface/error-codes.ts +241 -0
- package/ts/src/booking-surface/index.ts +9 -0
- package/ts/src/booking-surface/managed-dsh-cleanup-diagnostic.ts +151 -0
- package/ts/src/booking-surface/managed-dsh-run-port.ts +273 -0
- package/ts/src/booking-surface/profile.ts +42 -0
- package/ts/src/booking-surface/recovery-chain.ts +409 -0
- package/ts/src/booking-surface/runtime.ts +1793 -0
- package/ts/src/booking-surface/server.ts +733 -0
- package/ts/src/booking-surface/startup.ts +201 -0
- package/ts/src/booking-surface/validation.ts +217 -0
- package/ts/src/companions.ts +113 -0
- package/ts/src/contracts.ts +17 -3
- package/ts/src/dsh-llm.ts +152 -17
- package/ts/src/flyai-setup-tool.ts +77 -0
- package/ts/src/index.ts +2123 -200
- package/ts/src/itinerary-deck.ts +189 -0
- package/ts/src/itinerary-doc-shared.ts +741 -0
- package/ts/src/itinerary-html.ts +171 -0
- package/ts/src/loop.ts +234 -26
- package/ts/src/memory-capture.ts +283 -0
- package/ts/src/memory-decay.ts +55 -0
- package/ts/src/memory-utility.ts +70 -0
- package/ts/src/mock-llm.ts +4 -8
- package/ts/src/model.ts +88 -2
- package/ts/src/recall/card.ts +106 -0
- package/ts/src/recall/evaluator.ts +170 -0
- package/ts/src/recall/integration.ts +35 -0
- package/ts/src/recall/tick.ts +213 -0
- package/ts/src/session-link/plan-it-action.ts +78 -0
- package/ts/src/session-link/session-link.ts +275 -0
- package/ts/src/share/adapters.ts +93 -0
- package/ts/src/share/share-consent.ts +105 -0
- package/ts/src/share/share-deck.ts +85 -0
- package/ts/src/share/share-token.ts +166 -0
- package/ts/src/slot-spec.ts +172 -0
- package/ts/src/state-ledger.ts +1166 -0
- package/ts/src/subagent-job-id-guard.ts +72 -0
- package/ts/src/time-anchor.ts +338 -0
- package/ts/src/tool-packet.ts +32 -0
- package/ts/src/travel-slots.ts +219 -0
- package/ts/src/travel-timeline.ts +83 -0
- package/ts/src/turn-deadline.ts +366 -0
- package/ts/src/turn-policy.ts +154 -0
- package/ts/src/unified.ts +444 -105
- package/ts/src/wish-pool.ts +79 -0
- package/dist/scripts/session-attach-wait.js +0 -41
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded ground-transfer seam for explicit airport/station coordinates.
|
|
3
|
+
*
|
|
4
|
+
* This capability owns only the boundary between a public
|
|
5
|
+
* `map_driving_route` result and the deterministic candidate input. It never
|
|
6
|
+
* calls a map client directly, never writes shared state, and never supplies
|
|
7
|
+
* a price: the selected candidate transfer keeps its static `priceCny`.
|
|
8
|
+
*
|
|
9
|
+
* Each `ground_transfer` request resolves two deterministic directions —
|
|
10
|
+
* outbound (origin → destination) and return (destination → origin) — and
|
|
11
|
+
* binds the resulting route minutes to the candidate transfer as
|
|
12
|
+
* `minutesOut` / `minutesRet` overrides consumed by the solver / arithmetic
|
|
13
|
+
* layer. Cache, freshness, and fallback are isolated per direction so a
|
|
14
|
+
* miss / error / stale / mismatch in one direction never borrows the
|
|
15
|
+
* dynamic value of the other.
|
|
16
|
+
*
|
|
17
|
+
* A provider's OWN claims about its answer — declared `mode`, resolved
|
|
18
|
+
* origin/destination — are verified against the request whenever the provider
|
|
19
|
+
* makes them: a contradiction is refused with the conformance vocabulary
|
|
20
|
+
* (`mode_mismatch` / `direction_mismatch`) and falls back to the static estimate,
|
|
21
|
+
* so a transit duration is never bound as driving and a route between two other
|
|
22
|
+
* places is never bound as the airport transfer (issue #429 GAP-429-1/2). All
|
|
23
|
+
* three fields are OPTIONAL and absent means unverifiable: see
|
|
24
|
+
* `PublicMapDrivingRouteResult` for why absent is still accepted today.
|
|
25
|
+
*
|
|
26
|
+
* A provider failure becomes a `fallbackReason`, and `exposeGroundTransferEvidence`
|
|
27
|
+
* carries that text into the tool result and each matching verdict's
|
|
28
|
+
* `transfer_evidence`. It is therefore an EXPOSED surface: every provider-authored
|
|
29
|
+
* failure string passes through the shared `sanitizeFaultDetail` first, so markup,
|
|
30
|
+
* credential assignments and URLs from a provider response body can never reach it
|
|
31
|
+
* (issue #429 GAP-429-3). The historical 400-character bound and the historical
|
|
32
|
+
* empty-case wording are preserved, so existing `GROUND_TRANSFER_*` /
|
|
33
|
+
* `map_driving_route` reason strings are unchanged byte for byte.
|
|
34
|
+
*/
|
|
35
|
+
import { ToolCallId } from '@deepseek-ai/dsh-llm';
|
|
36
|
+
import { sanitizeFaultDetail } from './provider-detail-sanitize.js';
|
|
37
|
+
export const GROUND_TRANSFER_MODE = 'driving';
|
|
38
|
+
export const GROUND_TRANSFER_POSITION = 'destination';
|
|
39
|
+
export const GROUND_TRANSFER_STATIC_MODE = 'taxi';
|
|
40
|
+
export const GROUND_TRANSFER_STATIC_MODE_MISMATCH = 'ground_transfer_static_mode_mismatch';
|
|
41
|
+
export const GROUND_TRANSFER_STATIC_PRICE_EVIDENCE = '[静态包:估算]';
|
|
42
|
+
export const GROUND_TRANSFER_DEFAULT_MAX_AGE_S = 15 * 60;
|
|
43
|
+
/**
|
|
44
|
+
* Refusal classifications for a provider that contradicts its own request. The
|
|
45
|
+
* two names are the #429 conformance gate's vocabulary verbatim
|
|
46
|
+
* (`RouteErrorCode`), reused here as the `<code>:<direction>:<detail>` reason
|
|
47
|
+
* prefix this module already uses for `map_driving_route_provider_error` and
|
|
48
|
+
* `stale_route_requery_error`. They are duplicated as literals on purpose: the
|
|
49
|
+
* gate must stay free of product callers, so nothing here imports it.
|
|
50
|
+
*/
|
|
51
|
+
export const GROUND_TRANSFER_ROUTE_MODE_MISMATCH = 'mode_mismatch';
|
|
52
|
+
export const GROUND_TRANSFER_ROUTE_DIRECTION_MISMATCH = 'direction_mismatch';
|
|
53
|
+
/**
|
|
54
|
+
* Tolerance for verifying a provider's echoed endpoint against the requested
|
|
55
|
+
* one: 1e-4 degrees ≈ 11 m of latitude. A provider legitimately snaps a
|
|
56
|
+
* coordinate to the nearest routable road node, so an exact string match would
|
|
57
|
+
* refuse honest answers; anything beyond this bound is a different place, not a
|
|
58
|
+
* snap. Deliberately tight — refusing falls back to the static estimate, which
|
|
59
|
+
* is the safe direction.
|
|
60
|
+
*/
|
|
61
|
+
export const GROUND_TRANSFER_ECHO_TOLERANCE_DEG = 1e-4;
|
|
62
|
+
const GROUND_TRANSFER_CACHE_LIMIT = 32;
|
|
63
|
+
function asRecord(value) {
|
|
64
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
65
|
+
? value
|
|
66
|
+
: null;
|
|
67
|
+
}
|
|
68
|
+
function coordinate(value) {
|
|
69
|
+
const record = asRecord(value);
|
|
70
|
+
const longitude = record?.['longitude'];
|
|
71
|
+
const latitude = record?.['latitude'];
|
|
72
|
+
if (typeof longitude !== 'number' || !Number.isFinite(longitude) || longitude < -180 || longitude > 180
|
|
73
|
+
|| typeof latitude !== 'number' || !Number.isFinite(latitude) || latitude < -90 || latitude > 90)
|
|
74
|
+
return null;
|
|
75
|
+
return { longitude, latitude };
|
|
76
|
+
}
|
|
77
|
+
function coordinatePair(value) {
|
|
78
|
+
const record = asRecord(value);
|
|
79
|
+
if (!record)
|
|
80
|
+
return null;
|
|
81
|
+
const origin = coordinate(record['origin']);
|
|
82
|
+
const destination = coordinate(record['destination']);
|
|
83
|
+
if (origin === null || destination === null)
|
|
84
|
+
return null;
|
|
85
|
+
return { origin, destination };
|
|
86
|
+
}
|
|
87
|
+
function coordinateText(value) {
|
|
88
|
+
return `${String(value.longitude)},${String(value.latitude)}`;
|
|
89
|
+
}
|
|
90
|
+
/** Parse a canonical `"lon,lat"` text back into a validated coordinate. */
|
|
91
|
+
function coordinateFromText(value) {
|
|
92
|
+
const parts = value.split(',');
|
|
93
|
+
if (parts.length !== 2)
|
|
94
|
+
return null;
|
|
95
|
+
const [longitudeText, latitudeText] = parts;
|
|
96
|
+
if (longitudeText.trim() === '' || latitudeText.trim() === '')
|
|
97
|
+
return null;
|
|
98
|
+
return coordinate({ longitude: Number(longitudeText), latitude: Number(latitudeText) });
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Does a provider's echoed endpoint name the place that was requested?
|
|
102
|
+
*
|
|
103
|
+
* Compared within `GROUND_TRANSFER_ECHO_TOLERANCE_DEG` so a road-node snap still
|
|
104
|
+
* matches. An echo that cannot be parsed is NOT a match: present-but-unverifiable
|
|
105
|
+
* fails closed rather than being accepted as the requested pair.
|
|
106
|
+
*/
|
|
107
|
+
function sameEndpoint(echoed, requested) {
|
|
108
|
+
const left = coordinateFromText(echoed);
|
|
109
|
+
const right = coordinateFromText(requested);
|
|
110
|
+
if (left === null || right === null)
|
|
111
|
+
return false;
|
|
112
|
+
return Math.abs(left.longitude - right.longitude) <= GROUND_TRANSFER_ECHO_TOLERANCE_DEG
|
|
113
|
+
&& Math.abs(left.latitude - right.latitude) <= GROUND_TRANSFER_ECHO_TOLERANCE_DEG;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Normalize one of the provider's OWN optional claims into a comparable string.
|
|
117
|
+
*
|
|
118
|
+
* Absent (`undefined` / `null`) stays absent — that is the wired driving tool and
|
|
119
|
+
* its behaviour is unchanged. A present-but-unusable value is NOT dropped: it is
|
|
120
|
+
* carried as a non-empty string so the enforcement below can refuse it, because
|
|
121
|
+
* silently dropping a contradicting claim is exactly the relabel this seam
|
|
122
|
+
* forbids. A `{ longitude, latitude }` object is accepted as the canonical text.
|
|
123
|
+
*/
|
|
124
|
+
function declaredClaim(value) {
|
|
125
|
+
if (value === undefined || value === null)
|
|
126
|
+
return undefined;
|
|
127
|
+
if (typeof value === 'string')
|
|
128
|
+
return value.trim() === '' ? '(blank)' : value.trim();
|
|
129
|
+
const asCoordinate = coordinate(value);
|
|
130
|
+
if (asCoordinate !== null)
|
|
131
|
+
return coordinateText(asCoordinate);
|
|
132
|
+
return typeof value === 'object' ? JSON.stringify(value) : String(value);
|
|
133
|
+
}
|
|
134
|
+
function cacheKey(direction) {
|
|
135
|
+
return JSON.stringify({
|
|
136
|
+
mode: GROUND_TRANSFER_MODE,
|
|
137
|
+
direction: direction.direction,
|
|
138
|
+
origin: direction.origin,
|
|
139
|
+
destination: direction.destination,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function nowMs(clock) {
|
|
143
|
+
const value = clock().getTime();
|
|
144
|
+
if (!Number.isFinite(value))
|
|
145
|
+
throw new Error('ground-transfer clock returned an invalid date');
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
148
|
+
function asOf(clock) {
|
|
149
|
+
return new Date(nowMs(clock)).toISOString();
|
|
150
|
+
}
|
|
151
|
+
/** Historical bound for an exposed provider failure string (unchanged). */
|
|
152
|
+
const GROUND_TRANSFER_FAULT_DETAIL_MAX_CHARS = 400;
|
|
153
|
+
/**
|
|
154
|
+
* Normalize a provider failure into an exposable label. The text reaches the tool
|
|
155
|
+
* result via `exposeGroundTransferEvidence`, so it is scrubbed of markup,
|
|
156
|
+
* credential assignments and URLs before anything else (#429 GAP-429-3); the
|
|
157
|
+
* historical length bound and empty-case wording are preserved.
|
|
158
|
+
*/
|
|
159
|
+
function safeErrorMessage(value) {
|
|
160
|
+
const message = value instanceof Error ? value.message : String(value);
|
|
161
|
+
return sanitizeFaultDetail(message, {
|
|
162
|
+
maxChars: GROUND_TRANSFER_FAULT_DETAIL_MAX_CHARS,
|
|
163
|
+
emptyPlaceholder: 'unknown provider error',
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
/** Bound for a provider-authored claim quoted inside a refusal reason. */
|
|
167
|
+
const GROUND_TRANSFER_CLAIM_DETAIL_MAX_CHARS = 120;
|
|
168
|
+
/**
|
|
169
|
+
* A provider's own claim (mode / echoed endpoint / provider id) is provider-authored
|
|
170
|
+
* text, and a refusal reason reaches the tool result via
|
|
171
|
+
* `exposeGroundTransferEvidence`. Quote it only through the shared sanitizer.
|
|
172
|
+
*/
|
|
173
|
+
function safeClaim(value) {
|
|
174
|
+
return sanitizeFaultDetail(value, {
|
|
175
|
+
maxChars: GROUND_TRANSFER_CLAIM_DETAIL_MAX_CHARS,
|
|
176
|
+
emptyPlaceholder: '(absent)',
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
function staticCache(status = 'bypass') {
|
|
180
|
+
return { status, ageS: null, asOf: null };
|
|
181
|
+
}
|
|
182
|
+
function notAppliedBase(parts) {
|
|
183
|
+
return {
|
|
184
|
+
requestedMode: parts.requestedMode,
|
|
185
|
+
requestedPosition: parts.requestedPosition,
|
|
186
|
+
provenance: 'none',
|
|
187
|
+
asOf: null,
|
|
188
|
+
freshness: 'not_attempted',
|
|
189
|
+
cache: staticCache('bypass'),
|
|
190
|
+
evidenceClass: 'none',
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function staticDirectionResolution(direction, staticMinutes, reason) {
|
|
194
|
+
return {
|
|
195
|
+
applied: false,
|
|
196
|
+
direction,
|
|
197
|
+
staticMinutes,
|
|
198
|
+
provenance: 'static-transfer-pack',
|
|
199
|
+
asOf: null,
|
|
200
|
+
freshness: 'fallback',
|
|
201
|
+
cache: staticCache('bypass'),
|
|
202
|
+
evidenceClass: 'static_transfer_estimate',
|
|
203
|
+
fallbackReason: reason,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function parseRequest(value) {
|
|
207
|
+
const record = asRecord(value);
|
|
208
|
+
if (!record) {
|
|
209
|
+
return {
|
|
210
|
+
candidateId: null,
|
|
211
|
+
transferIndex: null,
|
|
212
|
+
requestedMode: null,
|
|
213
|
+
requestedPosition: null,
|
|
214
|
+
outbound: null,
|
|
215
|
+
ret: null,
|
|
216
|
+
invalidReason: 'ground_transfer_request_invalid:expected an object',
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
const candidateId = typeof record['candidate_id'] === 'string' && record['candidate_id'].trim()
|
|
220
|
+
? record['candidate_id']
|
|
221
|
+
: null;
|
|
222
|
+
const transferIndex = Number.isInteger(record['transfer_index']) && Number(record['transfer_index']) >= 0
|
|
223
|
+
? Number(record['transfer_index'])
|
|
224
|
+
: null;
|
|
225
|
+
const requestedMode = typeof record['mode'] === 'string' && record['mode'].trim()
|
|
226
|
+
? record['mode']
|
|
227
|
+
: null;
|
|
228
|
+
const requestedPosition = typeof record['position'] === 'string' && record['position'].trim()
|
|
229
|
+
? record['position']
|
|
230
|
+
: null;
|
|
231
|
+
let outbound = null;
|
|
232
|
+
let ret = null;
|
|
233
|
+
if (record['outbound'] !== undefined || record['return'] !== undefined) {
|
|
234
|
+
outbound = coordinatePair(record['outbound']);
|
|
235
|
+
ret = coordinatePair(record['return']);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
// Legacy single-pair shape: outbound = origin/destination; return = the
|
|
239
|
+
// swapped pair. Keeps pre-#364 payloads behavior-compatible.
|
|
240
|
+
const legacyOrigin = coordinate(record['origin']);
|
|
241
|
+
const legacyDestination = coordinate(record['destination']);
|
|
242
|
+
if (legacyOrigin && legacyDestination) {
|
|
243
|
+
outbound = { origin: legacyOrigin, destination: legacyDestination };
|
|
244
|
+
ret = { origin: legacyDestination, destination: legacyOrigin };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
let invalidReason;
|
|
248
|
+
if (candidateId === null)
|
|
249
|
+
invalidReason = 'ground_transfer_binding_invalid:candidate_id is required';
|
|
250
|
+
else if (transferIndex === null)
|
|
251
|
+
invalidReason = 'ground_transfer_binding_invalid:transfer_index must be a non-negative integer';
|
|
252
|
+
else if (requestedPosition !== GROUND_TRANSFER_POSITION)
|
|
253
|
+
invalidReason = `unsupported_ground_transfer_position:${requestedPosition ?? 'unknown'}`;
|
|
254
|
+
else if (requestedMode !== GROUND_TRANSFER_MODE)
|
|
255
|
+
invalidReason = `unsupported_ground_transfer_mode:${requestedMode ?? 'unknown'}`;
|
|
256
|
+
else if (outbound === null || ret === null)
|
|
257
|
+
invalidReason = 'invalid_ground_transfer_coordinates:longitude/latitude must be finite and in range';
|
|
258
|
+
return {
|
|
259
|
+
candidateId,
|
|
260
|
+
transferIndex,
|
|
261
|
+
requestedMode,
|
|
262
|
+
requestedPosition,
|
|
263
|
+
outbound,
|
|
264
|
+
ret,
|
|
265
|
+
invalidReason,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function completeRequest(parts) {
|
|
269
|
+
if (parts.invalidReason || parts.candidateId === null || parts.transferIndex === null
|
|
270
|
+
|| parts.requestedMode !== GROUND_TRANSFER_MODE || parts.requestedPosition !== GROUND_TRANSFER_POSITION
|
|
271
|
+
|| parts.outbound === null || parts.ret === null)
|
|
272
|
+
return null;
|
|
273
|
+
return {
|
|
274
|
+
candidateId: parts.candidateId,
|
|
275
|
+
transferIndex: parts.transferIndex,
|
|
276
|
+
mode: GROUND_TRANSFER_MODE,
|
|
277
|
+
position: GROUND_TRANSFER_POSITION,
|
|
278
|
+
outbound: { direction: 'outbound', origin: parts.outbound.origin, destination: parts.outbound.destination },
|
|
279
|
+
ret: { direction: 'return', origin: parts.ret.origin, destination: parts.ret.destination },
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
function parseRouteResult(value) {
|
|
283
|
+
const record = asRecord(value);
|
|
284
|
+
if (!record)
|
|
285
|
+
throw new Error('map_driving_route returned an invalid public result');
|
|
286
|
+
const provider = record?.['provider'];
|
|
287
|
+
const distanceM = record?.['distanceM'];
|
|
288
|
+
const durationS = record?.['durationS'];
|
|
289
|
+
if (typeof provider !== 'string' || provider.trim() === ''
|
|
290
|
+
|| typeof distanceM !== 'number' || !Number.isFinite(distanceM) || distanceM < 0
|
|
291
|
+
|| typeof durationS !== 'number' || !Number.isFinite(durationS) || durationS < 0
|
|
292
|
+
// A positive distance cannot be covered in zero time: such a response is
|
|
293
|
+
// a self-contradictory route fact, not a credible provider hit. It falls
|
|
294
|
+
// into the explicit provider-miss fallback instead of silently binding
|
|
295
|
+
// zero minutes into the solver.
|
|
296
|
+
|| (distanceM > 0 && durationS === 0))
|
|
297
|
+
throw new Error('map_driving_route returned an invalid public result');
|
|
298
|
+
// The provider's own claims are CARRIED, never dropped: `routeClaimRefusal`
|
|
299
|
+
// below checks them when they exist. Absent stays absent (the wired driving
|
|
300
|
+
// tool sends none of the three), and re-parsing an already-parsed result is
|
|
301
|
+
// idempotent because the carried values are already canonical.
|
|
302
|
+
const declaredMode = declaredClaim(record['mode']);
|
|
303
|
+
const resolvedOrigin = declaredClaim(record['resolvedOrigin']);
|
|
304
|
+
const resolvedDestination = declaredClaim(record['resolvedDestination']);
|
|
305
|
+
return {
|
|
306
|
+
provider,
|
|
307
|
+
distanceM,
|
|
308
|
+
durationS,
|
|
309
|
+
...(typeof record['polyline'] === 'string' ? { polyline: record['polyline'] } : {}),
|
|
310
|
+
...(Array.isArray(record['steps']) ? { steps: record['steps'] } : {}),
|
|
311
|
+
...(declaredMode !== undefined ? { mode: declaredMode } : {}),
|
|
312
|
+
...(resolvedOrigin !== undefined ? { resolvedOrigin } : {}),
|
|
313
|
+
...(resolvedDestination !== undefined ? { resolvedDestination } : {}),
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Verify the provider's OWN claims against the request for this direction, and
|
|
318
|
+
* return a typed refusal when one contradicts it (#429 GAP-429-1/2).
|
|
319
|
+
*
|
|
320
|
+
* ABSENT = UNVERIFIABLE, and absent is ACCEPTED — not because an unverified
|
|
321
|
+
* answer is as good as a verified one, but because the only wired provider (the
|
|
322
|
+
* registered `map_driving_route` tool) is driving by construction and echoes no
|
|
323
|
+
* origin/destination, so for it nothing changes byte for byte. Any future
|
|
324
|
+
* non-driving or address-resolving adapter must supply these fields; the #429
|
|
325
|
+
* conformance gate already refuses an adapter that does not.
|
|
326
|
+
*
|
|
327
|
+
* PRESENT and contradicting = REFUSAL. The caller falls back to the static
|
|
328
|
+
* transfer estimate with its original price label, so a mislabelled or
|
|
329
|
+
* misrouted answer never reaches the solver.
|
|
330
|
+
*/
|
|
331
|
+
function routeClaimRefusal(direction, request, route) {
|
|
332
|
+
if (route.mode !== undefined && route.mode !== GROUND_TRANSFER_MODE) {
|
|
333
|
+
return {
|
|
334
|
+
code: GROUND_TRANSFER_ROUTE_MODE_MISMATCH,
|
|
335
|
+
detail: `provider ${safeClaim(route.provider)} returned mode '${safeClaim(route.mode)}' for a '${GROUND_TRANSFER_MODE}' request; a declared mode is never relabelled as ${GROUND_TRANSFER_MODE}; static transfer preserved`,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
const { resolvedOrigin, resolvedDestination } = route;
|
|
339
|
+
if (resolvedOrigin === undefined && resolvedDestination === undefined)
|
|
340
|
+
return null;
|
|
341
|
+
if ((resolvedOrigin !== undefined && !sameEndpoint(resolvedOrigin, request.origin))
|
|
342
|
+
|| (resolvedDestination !== undefined && !sameEndpoint(resolvedDestination, request.destination))) {
|
|
343
|
+
return {
|
|
344
|
+
code: GROUND_TRANSFER_ROUTE_DIRECTION_MISMATCH,
|
|
345
|
+
detail: `provider ${safeClaim(route.provider)} resolved ${safeClaim(resolvedOrigin ?? '(absent)')}>${safeClaim(resolvedDestination ?? '(absent)')} but the ${direction.direction} request was ${request.origin}>${request.destination}; direction binding is verified against the response, not assumed from the request; static transfer preserved`,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
function buildRouteFact(direction, route, clock, cache) {
|
|
351
|
+
return {
|
|
352
|
+
direction: direction.direction,
|
|
353
|
+
origin: direction.origin,
|
|
354
|
+
destination: direction.destination,
|
|
355
|
+
mode: GROUND_TRANSFER_MODE,
|
|
356
|
+
provider: route.provider,
|
|
357
|
+
distanceM: route.distanceM,
|
|
358
|
+
durationS: route.durationS,
|
|
359
|
+
durationMin: Math.round(route.durationS / 60),
|
|
360
|
+
asOf: asOf(clock),
|
|
361
|
+
provenance: 'map_driving_route',
|
|
362
|
+
freshness: cache.status === 'hit' ? 'cache_hit' : 'fresh',
|
|
363
|
+
cache,
|
|
364
|
+
evidenceClass: 'public_map_route_estimate',
|
|
365
|
+
trafficStatus: 'not-live-route-estimate',
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function selectionFor(candidates, parts) {
|
|
369
|
+
if (parts.candidateId === null || parts.transferIndex === null)
|
|
370
|
+
return null;
|
|
371
|
+
const matching = candidates
|
|
372
|
+
.map((candidate, index) => ({ candidate, index }))
|
|
373
|
+
.filter(({ candidate }) => candidate.id === parts.candidateId);
|
|
374
|
+
if (matching.length !== 1)
|
|
375
|
+
return null;
|
|
376
|
+
const match = matching[0];
|
|
377
|
+
const transfer = match.candidate.destTransfers[parts.transferIndex];
|
|
378
|
+
if (!transfer || typeof transfer.mode !== 'string' || !Number.isFinite(transfer.minutes) || transfer.minutes < 0 || !Number.isFinite(transfer.priceCny) || transfer.priceCny < 0)
|
|
379
|
+
return null;
|
|
380
|
+
return {
|
|
381
|
+
candidateIndex: match.index,
|
|
382
|
+
selection: {
|
|
383
|
+
candidateId: parts.candidateId,
|
|
384
|
+
transferIndex: parts.transferIndex,
|
|
385
|
+
staticMode: transfer.mode,
|
|
386
|
+
staticMinutes: transfer.minutes,
|
|
387
|
+
staticPriceCny: transfer.priceCny,
|
|
388
|
+
},
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
async function resolveDirection(direction, staticMinutes, provider, clock, cache, maxEntries, context) {
|
|
392
|
+
const key = cacheKey(direction);
|
|
393
|
+
const currentMs = nowMs(clock);
|
|
394
|
+
const cached = cache.get(key);
|
|
395
|
+
if (cached) {
|
|
396
|
+
const ageS = Math.max(0, currentMs - cached.storedAtMs) / 1000;
|
|
397
|
+
if (ageS <= GROUND_TRANSFER_DEFAULT_MAX_AGE_S) {
|
|
398
|
+
const hitCache = { status: 'hit', ageS, asOf: cached.fact.asOf };
|
|
399
|
+
const hitFact = { ...cached.fact, freshness: 'cache_hit', cache: hitCache };
|
|
400
|
+
return {
|
|
401
|
+
applied: true,
|
|
402
|
+
direction: direction.direction,
|
|
403
|
+
minutes: hitFact.durationMin,
|
|
404
|
+
staticMinutes,
|
|
405
|
+
provenance: 'map_driving_route',
|
|
406
|
+
asOf: hitFact.asOf,
|
|
407
|
+
freshness: 'cache_hit',
|
|
408
|
+
cache: hitCache,
|
|
409
|
+
evidenceClass: 'public_map_route_estimate',
|
|
410
|
+
routeFact: hitFact,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
const requestForProvider = {
|
|
415
|
+
origin: coordinateText(direction.origin),
|
|
416
|
+
destination: coordinateText(direction.destination),
|
|
417
|
+
mode: GROUND_TRANSFER_MODE,
|
|
418
|
+
};
|
|
419
|
+
try {
|
|
420
|
+
const raw = await provider(requestForProvider, {
|
|
421
|
+
signal: context.signal ?? new AbortController().signal,
|
|
422
|
+
execution: context.execution,
|
|
423
|
+
});
|
|
424
|
+
const route = parseRouteResult(raw);
|
|
425
|
+
const refusal = routeClaimRefusal(direction, requestForProvider, route);
|
|
426
|
+
if (refusal !== null) {
|
|
427
|
+
// Fail closed: no fact is built and nothing is written to the cache, so a
|
|
428
|
+
// refused answer can never be served later as a cache hit. The static
|
|
429
|
+
// minutes, price and `[静态包:估算]` label are left untouched.
|
|
430
|
+
return {
|
|
431
|
+
applied: false,
|
|
432
|
+
direction: direction.direction,
|
|
433
|
+
staticMinutes,
|
|
434
|
+
provenance: 'static-transfer-pack',
|
|
435
|
+
asOf: null,
|
|
436
|
+
freshness: 'fallback',
|
|
437
|
+
cache: staticCache(cached ? 'stale' : 'bypass'),
|
|
438
|
+
evidenceClass: 'static_transfer_estimate',
|
|
439
|
+
fallbackReason: `${refusal.code}:${direction.direction}:${refusal.detail}`,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
const cacheInfo = {
|
|
443
|
+
status: cached ? 'requery' : 'miss',
|
|
444
|
+
ageS: 0,
|
|
445
|
+
asOf: null,
|
|
446
|
+
};
|
|
447
|
+
const fact = buildRouteFact(direction, route, clock, cacheInfo);
|
|
448
|
+
cacheInfo.asOf = fact.asOf;
|
|
449
|
+
const entry = { fact, storedAtMs: currentMs };
|
|
450
|
+
if (cache.size >= maxEntries && !cache.has(key)) {
|
|
451
|
+
const oldest = cache.keys().next().value;
|
|
452
|
+
if (typeof oldest === 'string')
|
|
453
|
+
cache.delete(oldest);
|
|
454
|
+
}
|
|
455
|
+
cache.set(key, entry);
|
|
456
|
+
return {
|
|
457
|
+
applied: true,
|
|
458
|
+
direction: direction.direction,
|
|
459
|
+
minutes: fact.durationMin,
|
|
460
|
+
staticMinutes,
|
|
461
|
+
provenance: 'map_driving_route',
|
|
462
|
+
asOf: fact.asOf,
|
|
463
|
+
freshness: 'fresh',
|
|
464
|
+
cache: cacheInfo,
|
|
465
|
+
evidenceClass: 'public_map_route_estimate',
|
|
466
|
+
routeFact: fact,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
catch (error) {
|
|
470
|
+
const detail = safeErrorMessage(error);
|
|
471
|
+
return {
|
|
472
|
+
applied: false,
|
|
473
|
+
direction: direction.direction,
|
|
474
|
+
staticMinutes,
|
|
475
|
+
provenance: 'static-transfer-pack',
|
|
476
|
+
asOf: null,
|
|
477
|
+
freshness: 'fallback',
|
|
478
|
+
cache: staticCache(cached ? 'stale' : 'bypass'),
|
|
479
|
+
evidenceClass: 'static_transfer_estimate',
|
|
480
|
+
fallbackReason: cached
|
|
481
|
+
? `stale_route_requery_error:${direction.direction}:${detail}`
|
|
482
|
+
: `map_driving_route_provider_error:${direction.direction}:${detail}`,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
export function createGroundTransferResolver(options) {
|
|
487
|
+
const clock = options.clock ?? (() => new Date());
|
|
488
|
+
const maxEntries = Number.isInteger(options.maxEntries) && Number(options.maxEntries) > 0
|
|
489
|
+
? Number(options.maxEntries)
|
|
490
|
+
: GROUND_TRANSFER_CACHE_LIMIT;
|
|
491
|
+
const cache = new Map();
|
|
492
|
+
return {
|
|
493
|
+
async resolve(request, selection, context = {}) {
|
|
494
|
+
const [outbound, ret] = await Promise.all([
|
|
495
|
+
resolveDirection(request.outbound, selection.staticMinutes, options.provider, clock, cache, maxEntries, context),
|
|
496
|
+
resolveDirection(request.ret, selection.staticMinutes, options.provider, clock, cache, maxEntries, context),
|
|
497
|
+
]);
|
|
498
|
+
const applied = outbound.applied || ret.applied;
|
|
499
|
+
// Aggregate fields are a summary only: per-direction objects above are
|
|
500
|
+
// the authoritative per-direction record. A full cache hit keeps the
|
|
501
|
+
// legacy aggregate semantics ('cache_hit'), a re-query keeps 'requery'.
|
|
502
|
+
const aggregateProvenance = applied ? 'map_driving_route' : 'static-transfer-pack';
|
|
503
|
+
const aggregateEvidenceClass = applied ? 'public_map_route_estimate' : 'static_transfer_estimate';
|
|
504
|
+
const aggregateFreshness = !applied
|
|
505
|
+
? 'fallback'
|
|
506
|
+
: outbound.freshness === 'fresh' || ret.freshness === 'fresh'
|
|
507
|
+
? 'fresh'
|
|
508
|
+
: 'cache_hit';
|
|
509
|
+
const statuses = [outbound.cache.status, ret.cache.status];
|
|
510
|
+
const aggregateCache = !applied
|
|
511
|
+
? staticCache('bypass')
|
|
512
|
+
: {
|
|
513
|
+
status: statuses.includes('hit') ? 'hit' : statuses.includes('requery') ? 'requery' : 'miss',
|
|
514
|
+
ageS: 0,
|
|
515
|
+
asOf: null,
|
|
516
|
+
};
|
|
517
|
+
const aggregateAsOf = applied ? (outbound.asOf ?? ret.asOf) : null;
|
|
518
|
+
const resolution = {
|
|
519
|
+
applied,
|
|
520
|
+
candidateId: selection.candidateId,
|
|
521
|
+
transferIndex: selection.transferIndex,
|
|
522
|
+
requestedMode: request.mode,
|
|
523
|
+
requestedPosition: request.position,
|
|
524
|
+
staticMode: selection.staticMode,
|
|
525
|
+
staticMinutes: selection.staticMinutes,
|
|
526
|
+
priceCny: selection.staticPriceCny,
|
|
527
|
+
priceEvidence: GROUND_TRANSFER_STATIC_PRICE_EVIDENCE,
|
|
528
|
+
provenance: aggregateProvenance,
|
|
529
|
+
asOf: aggregateAsOf,
|
|
530
|
+
freshness: aggregateFreshness,
|
|
531
|
+
cache: aggregateCache,
|
|
532
|
+
evidenceClass: aggregateEvidenceClass,
|
|
533
|
+
outbound,
|
|
534
|
+
return: ret,
|
|
535
|
+
};
|
|
536
|
+
if (outbound.applied)
|
|
537
|
+
resolution.outboundMinutes = outbound.minutes;
|
|
538
|
+
if (ret.applied)
|
|
539
|
+
resolution.returnMinutes = ret.minutes;
|
|
540
|
+
if (!applied) {
|
|
541
|
+
resolution.fallbackReason = `both_directions_failed:${outbound.fallbackReason ?? 'unknown'};${ret.fallbackReason ?? 'unknown'}`;
|
|
542
|
+
}
|
|
543
|
+
return resolution;
|
|
544
|
+
},
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Delegate through the registered public map tool. The dsh-tools types expose
|
|
549
|
+
* nested execution explicitly, so the current root/agent/signal are carried
|
|
550
|
+
* into the sub-dispatch instead of calling a private map client.
|
|
551
|
+
*/
|
|
552
|
+
export function createPublicMapDrivingRouteProvider(ctx) {
|
|
553
|
+
return async (request, context) => {
|
|
554
|
+
const execution = context.execution;
|
|
555
|
+
if (!execution)
|
|
556
|
+
throw new Error('GROUND_TRANSFER_NESTED_EXECUTION_UNSUPPORTED: current tool execution context is unavailable');
|
|
557
|
+
const tools = ctx.tools;
|
|
558
|
+
if (typeof tools?.execute !== 'function' || typeof tools?.get !== 'function') {
|
|
559
|
+
throw new Error('GROUND_TRANSFER_NESTED_EXECUTION_UNSUPPORTED: host must expose dsh-tools ToolRuntime.execute/get');
|
|
560
|
+
}
|
|
561
|
+
if (!tools.get('map_driving_route', execution.agent)) {
|
|
562
|
+
throw new Error('GROUND_TRANSFER_PUBLIC_MAP_TOOL_UNAVAILABLE: map_driving_route is not registered in the current tool scope');
|
|
563
|
+
}
|
|
564
|
+
const nested = {
|
|
565
|
+
callId: ToolCallId(`${String(execution.callId)}:ground-transfer`),
|
|
566
|
+
rootCallId: execution.rootCallId,
|
|
567
|
+
name: 'map_driving_route',
|
|
568
|
+
arguments: { origin: request.origin, destination: request.destination },
|
|
569
|
+
...(execution.agent !== undefined ? { agent: execution.agent } : {}),
|
|
570
|
+
parent: execution.token,
|
|
571
|
+
signal: execution.signal,
|
|
572
|
+
};
|
|
573
|
+
const result = await tools.execute(nested);
|
|
574
|
+
if (result.isError)
|
|
575
|
+
throw new Error(`map_driving_route failed: ${result.error.message}`);
|
|
576
|
+
return parseRouteResult(result.value);
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
/** Resolve and patch exactly one named transfer position before solver entry. */
|
|
580
|
+
export async function resolveGroundTransferPayload(rawRequest, candidates, resolver, context) {
|
|
581
|
+
const parts = parseRequest(rawRequest);
|
|
582
|
+
const bound = selectionFor(candidates, parts);
|
|
583
|
+
if (!bound) {
|
|
584
|
+
const base = notAppliedBase(parts);
|
|
585
|
+
return {
|
|
586
|
+
candidates: [...candidates],
|
|
587
|
+
resolution: {
|
|
588
|
+
...base,
|
|
589
|
+
applied: false,
|
|
590
|
+
...(parts.candidateId !== null ? { candidateId: parts.candidateId } : {}),
|
|
591
|
+
...(parts.transferIndex !== null ? { transferIndex: parts.transferIndex } : {}),
|
|
592
|
+
outbound: staticDirectionResolution('outbound', Number.NaN, 'ground_transfer_binding_mismatch'),
|
|
593
|
+
return: staticDirectionResolution('return', Number.NaN, 'ground_transfer_binding_mismatch'),
|
|
594
|
+
fallbackReason: 'ground_transfer_binding_mismatch: candidate_id and transfer_index must identify exactly one valid static transfer',
|
|
595
|
+
},
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
const complete = completeRequest(parts);
|
|
599
|
+
if (!complete) {
|
|
600
|
+
return {
|
|
601
|
+
candidates: [...candidates],
|
|
602
|
+
resolution: {
|
|
603
|
+
applied: false,
|
|
604
|
+
candidateId: bound.selection.candidateId,
|
|
605
|
+
transferIndex: bound.selection.transferIndex,
|
|
606
|
+
requestedMode: parts.requestedMode,
|
|
607
|
+
requestedPosition: parts.requestedPosition,
|
|
608
|
+
staticMode: bound.selection.staticMode,
|
|
609
|
+
staticMinutes: bound.selection.staticMinutes,
|
|
610
|
+
priceCny: bound.selection.staticPriceCny,
|
|
611
|
+
priceEvidence: GROUND_TRANSFER_STATIC_PRICE_EVIDENCE,
|
|
612
|
+
provenance: 'static-transfer-pack',
|
|
613
|
+
asOf: null,
|
|
614
|
+
freshness: 'fallback',
|
|
615
|
+
cache: staticCache('bypass'),
|
|
616
|
+
evidenceClass: 'static_transfer_estimate',
|
|
617
|
+
outbound: staticDirectionResolution('outbound', bound.selection.staticMinutes, parts.invalidReason ?? 'ground_transfer_request_invalid'),
|
|
618
|
+
return: staticDirectionResolution('return', bound.selection.staticMinutes, parts.invalidReason ?? 'ground_transfer_request_invalid'),
|
|
619
|
+
fallbackReason: `${parts.invalidReason ?? 'ground_transfer_request_invalid'}; static transfer minutes and price preserved`,
|
|
620
|
+
},
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
if (bound.selection.staticMode !== GROUND_TRANSFER_STATIC_MODE) {
|
|
624
|
+
const reason = `${GROUND_TRANSFER_STATIC_MODE_MISMATCH}: mode=${bound.selection.staticMode}; only taxi accepts a driving route; static transfer preserved`;
|
|
625
|
+
return {
|
|
626
|
+
candidates: [...candidates],
|
|
627
|
+
resolution: {
|
|
628
|
+
applied: false,
|
|
629
|
+
candidateId: bound.selection.candidateId,
|
|
630
|
+
transferIndex: bound.selection.transferIndex,
|
|
631
|
+
requestedMode: parts.requestedMode,
|
|
632
|
+
requestedPosition: parts.requestedPosition,
|
|
633
|
+
staticMode: bound.selection.staticMode,
|
|
634
|
+
staticMinutes: bound.selection.staticMinutes,
|
|
635
|
+
priceCny: bound.selection.staticPriceCny,
|
|
636
|
+
priceEvidence: GROUND_TRANSFER_STATIC_PRICE_EVIDENCE,
|
|
637
|
+
provenance: 'static-transfer-pack',
|
|
638
|
+
asOf: null,
|
|
639
|
+
freshness: 'not_attempted',
|
|
640
|
+
cache: staticCache('bypass'),
|
|
641
|
+
evidenceClass: 'static_transfer_estimate',
|
|
642
|
+
outbound: staticDirectionResolution('outbound', bound.selection.staticMinutes, reason),
|
|
643
|
+
return: staticDirectionResolution('return', bound.selection.staticMinutes, reason),
|
|
644
|
+
fallbackReason: reason,
|
|
645
|
+
},
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
const resolution = await resolver.resolve(complete, bound.selection, context);
|
|
649
|
+
if (!resolution.applied) {
|
|
650
|
+
return { candidates: [...candidates], resolution };
|
|
651
|
+
}
|
|
652
|
+
const patched = candidates.map((candidate, candidateIndex) => {
|
|
653
|
+
if (candidateIndex !== bound.candidateIndex)
|
|
654
|
+
return candidate;
|
|
655
|
+
const destTransfers = candidate.destTransfers.map((transfer, transferIndex) => {
|
|
656
|
+
if (transferIndex !== bound.selection.transferIndex)
|
|
657
|
+
return transfer;
|
|
658
|
+
const next = { ...transfer };
|
|
659
|
+
if (resolution.outboundMinutes !== undefined)
|
|
660
|
+
next['minutesOut'] = resolution.outboundMinutes;
|
|
661
|
+
if (resolution.returnMinutes !== undefined)
|
|
662
|
+
next['minutesRet'] = resolution.returnMinutes;
|
|
663
|
+
return next;
|
|
664
|
+
});
|
|
665
|
+
return { ...candidate, destTransfers };
|
|
666
|
+
});
|
|
667
|
+
return { candidates: patched, resolution };
|
|
668
|
+
}
|
|
669
|
+
export function exposeGroundTransferEvidence(result, resolution) {
|
|
670
|
+
const verdicts = Array.isArray(result['verdicts'])
|
|
671
|
+
? result['verdicts'].map(verdict => resolution.candidateId !== undefined && verdict['candidate_id'] === resolution.candidateId
|
|
672
|
+
? { ...verdict, transfer_evidence: resolution }
|
|
673
|
+
: verdict)
|
|
674
|
+
: result['verdicts'];
|
|
675
|
+
return { ...result, verdicts, ground_transfer: resolution };
|
|
676
|
+
}
|