@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,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 行程 HTML 渲染器(issue #442,父 #438;共享契约层抽取见 issue #564)。
|
|
3
|
+
*
|
|
4
|
+
* 纯有界渲染器:拒绝畸形输入,产出单文件自包含 HTML。本模块不执行 IO、
|
|
5
|
+
* 不启动服务、不解析 Markdown、不做夜数/预算/时间运算——只把显式行程结构
|
|
6
|
+
* 与已注册事实投影成可导航、可展开的安全文档。
|
|
7
|
+
*
|
|
8
|
+
* 输入校验、事实归一化与证据卡渲染的单一事实源在 `itinerary-doc-shared.ts`
|
|
9
|
+
* (两个文档投影共用,防第二实现漂移);本模块只保留单页文档的排版与组装。
|
|
10
|
+
*
|
|
11
|
+
* 两条永不合流的证据面:
|
|
12
|
+
* 1. 计划面(planner:trip_start/trip_end/stays/od_segments)——用户排期意图;
|
|
13
|
+
* 2. 证据面(facts:调用方从注册表选出的 BookableFact)——exact-date 查询结论,
|
|
14
|
+
* 逐条保留 tier/bookability/source/query_id/fetched_at/as_of。
|
|
15
|
+
* 目的地级酒店库存绝不宣称「某家酒店有房/可订」;无任何整体 verified 徽章。
|
|
16
|
+
*
|
|
17
|
+
* 渲染闸锚点纪律:本模块不嵌入 `<!-- fact:<id> -->` 锚点(那属 Markdown 产物闸),
|
|
18
|
+
* 事实 id 只作为可见文本展示,避免整篇 HTML 被当作锚点行解析。
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
DOC_BASE_CSS,
|
|
23
|
+
DOC_NARROW_CSS,
|
|
24
|
+
EVIDENCE_BOUNDARY_NOTICE,
|
|
25
|
+
MODE_LABEL,
|
|
26
|
+
TWO_PLANE_STATEMENT,
|
|
27
|
+
buildDateIndex,
|
|
28
|
+
docBytesError,
|
|
29
|
+
escapeHtml,
|
|
30
|
+
factIdSlug,
|
|
31
|
+
hotelFactsForStay,
|
|
32
|
+
leftoverFacts,
|
|
33
|
+
normalizeDocInput,
|
|
34
|
+
renderDateList,
|
|
35
|
+
renderFact,
|
|
36
|
+
renderFactCountsLine,
|
|
37
|
+
renderHotelEvidenceSection,
|
|
38
|
+
renderHotelNote,
|
|
39
|
+
renderLeftoverBlock,
|
|
40
|
+
renderPlannedStay,
|
|
41
|
+
renderPolicyNote,
|
|
42
|
+
renderSegment,
|
|
43
|
+
routeFactsFor,
|
|
44
|
+
timeEl,
|
|
45
|
+
type ItineraryDocResult,
|
|
46
|
+
type NormalizedFact,
|
|
47
|
+
type NormalizedFlight,
|
|
48
|
+
type NormalizedHotel,
|
|
49
|
+
type NormalizedItinerary,
|
|
50
|
+
type NormalizedPolicy,
|
|
51
|
+
} from './itinerary-doc-shared.ts'
|
|
52
|
+
|
|
53
|
+
// API 面稳定性:既有消费方(itinerary-artifact.ts / 测试)继续从本模块导入
|
|
54
|
+
export { ITINERARY_DOC_LIMITS as ITINERARY_HTML_LIMITS } from './itinerary-doc-shared.ts'
|
|
55
|
+
export type { ItineraryDocInput as ItineraryHtmlInput, ItineraryDocResult as ItineraryHtmlResult } from './itinerary-doc-shared.ts'
|
|
56
|
+
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// 单页文档排版(组装共享层的内容原语;CSS 为本形态私有)
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
const CSS = DOC_BASE_CSS + `
|
|
62
|
+
.wrap{max-width:64rem;margin:0 auto;padding:1rem}
|
|
63
|
+
header.doc{border-bottom:1px solid var(--line);padding-bottom:.75rem}
|
|
64
|
+
nav.toc{border:1px solid var(--line);border-radius:6px;padding:.6rem .8rem;margin:1rem 0;background:var(--card)}
|
|
65
|
+
nav.toc h2{font-size:1rem}
|
|
66
|
+
nav.toc ul{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.35rem .9rem}
|
|
67
|
+
nav.toc ul ul{margin-left:.9rem;font-size:.92rem;display:block}
|
|
68
|
+
section{margin:1.75rem 0}
|
|
69
|
+
` + DOC_NARROW_CSS + `
|
|
70
|
+
@media (max-width:480px){
|
|
71
|
+
.wrap{padding:.6rem}
|
|
72
|
+
}`
|
|
73
|
+
|
|
74
|
+
function render(input: { title: string; itinerary: NormalizedItinerary; facts: NormalizedFact[] }): string {
|
|
75
|
+
const { title, itinerary, facts } = input
|
|
76
|
+
const stays = itinerary.stays
|
|
77
|
+
const segs = itinerary.od_segments
|
|
78
|
+
const hotelFacts = facts.filter((f): f is NormalizedHotel => f.kind === 'hotel')
|
|
79
|
+
const policyFacts = facts.filter((f): f is NormalizedPolicy => f.kind === 'policy')
|
|
80
|
+
const flightFacts = facts.filter((f): f is NormalizedFlight => f.kind === 'flight' || f.kind === 'train')
|
|
81
|
+
|
|
82
|
+
const stayBlocks = stays.map((stay, i) => renderPlannedStay(stay, `stay-${i + 1}`, hotelFactsForStay(hotelFacts, stay)))
|
|
83
|
+
const segBlocks = segs.map((seg, i) => renderSegment(seg, `seg-${i + 1}`, routeFactsFor(facts, seg), itinerary.trip_start))
|
|
84
|
+
|
|
85
|
+
const stayDateItems = stays.filter((s, i) => stays.findIndex(x => x.check_in === s.check_in) === i)
|
|
86
|
+
.map(s => `<li>${timeEl(s.check_in)} — <a href="#stay-${stays.indexOf(s) + 1}">计划住宿 ${escapeHtml(s.place)}</a></li>`)
|
|
87
|
+
.join('')
|
|
88
|
+
const segDateItems = [...new Set(segs.map(s => s.date))].sort()
|
|
89
|
+
.map(d => `<li>${timeEl(d)} — <a href="#segments">交通段</a></li>`)
|
|
90
|
+
.join('')
|
|
91
|
+
|
|
92
|
+
const dateList = renderDateList(buildDateIndex(itinerary))
|
|
93
|
+
const leftovers = leftoverFacts(facts, itinerary)
|
|
94
|
+
const leftoverBlock = renderLeftoverBlock(leftovers, itinerary.trip_start)
|
|
95
|
+
const hotelNote = renderHotelNote(hotelFacts)
|
|
96
|
+
const policyNote = renderPolicyNote(policyFacts)
|
|
97
|
+
|
|
98
|
+
return `<!DOCTYPE html>
|
|
99
|
+
<html lang="zh-CN">
|
|
100
|
+
<head>
|
|
101
|
+
<meta charset="utf-8">
|
|
102
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
103
|
+
<meta name="referrer" content="no-referrer">
|
|
104
|
+
<title>${escapeHtml(title)}</title>
|
|
105
|
+
<style>${CSS}</style>
|
|
106
|
+
</head>
|
|
107
|
+
<body>
|
|
108
|
+
<a class="skip" href="#main">跳到主要内容</a>
|
|
109
|
+
<div class="wrap">
|
|
110
|
+
<header class="doc">
|
|
111
|
+
<h1>${escapeHtml(title)}</h1>
|
|
112
|
+
<p>行程 ${timeEl(itinerary.trip_start)} → ${timeEl(itinerary.trip_end)}</p>
|
|
113
|
+
${TWO_PLANE_STATEMENT}
|
|
114
|
+
</header>
|
|
115
|
+
<main id="main">
|
|
116
|
+
${EVIDENCE_BOUNDARY_NOTICE}
|
|
117
|
+
<nav class="toc" aria-label="行程导航">
|
|
118
|
+
<h2>导航</h2>
|
|
119
|
+
<ul>
|
|
120
|
+
<li><a href="#dates">按日期</a><ul>${dateList.startsWith('<p') ? '<li class="muted">无</li>' : ''}</ul></li>
|
|
121
|
+
<li><a href="#segments">航班/交通段</a><ul>${segDateItems || '<li class="muted">无</li>'}</ul></li>
|
|
122
|
+
<li><a href="#stays">住宿</a><ul>${stayDateItems || '<li class="muted">无</li>'}</ul></li>
|
|
123
|
+
<li><a href="#facts">事实与证据</a></li>
|
|
124
|
+
</ul>
|
|
125
|
+
</nav>
|
|
126
|
+
<section id="dates"><h2>按日期行程</h2>
|
|
127
|
+
${dateList}
|
|
128
|
+
</section>
|
|
129
|
+
<section id="segments"><h2>航班/交通段</h2>
|
|
130
|
+
<p class="muted">下列条目是计划段(用户排期意图);每段内另列可回溯到该 route + date 的已注册事实。计划段不因存在事实而变成可下单。</p>
|
|
131
|
+
${segBlocks.join('') || '<p class="muted missing">没有显式交通段。</p>'}
|
|
132
|
+
</section>
|
|
133
|
+
<section id="stays"><h2>住宿</h2>
|
|
134
|
+
${hotelNote}
|
|
135
|
+
${stayBlocks.join('') || '<p class="muted missing">没有显式住宿段。</p>'}
|
|
136
|
+
${renderHotelEvidenceSection(hotelFacts, itinerary.trip_start)}
|
|
137
|
+
</section>
|
|
138
|
+
<section id="facts"><h2>事实与证据</h2>
|
|
139
|
+
${renderFactCountsLine(facts)}
|
|
140
|
+
${policyFacts.map(f => renderFact(f, `policy-${factIdSlug(f.fact.fact_id)}`, itinerary.trip_start)).join('')}
|
|
141
|
+
${policyNote}
|
|
142
|
+
${leftoverBlock}
|
|
143
|
+
<h3>全部航班/车次事实(含负事实与冲突)</h3>
|
|
144
|
+
${flightFacts.map(f => renderFact(f, `flight-${factIdSlug(f.fact.fact_id)}`, itinerary.trip_start)).join('') || '<p class="muted missing">本次输入没有航班/车次事实。</p>'}
|
|
145
|
+
</section>
|
|
146
|
+
</main>
|
|
147
|
+
</div>
|
|
148
|
+
</body>
|
|
149
|
+
</html>
|
|
150
|
+
`
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
// 入口
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 纯渲染入口。`input` 是任意运行时数据:结构、枚举、真实日历日期、有限数值、
|
|
159
|
+
* 容量与文档大小全部现场校验;任何一项不合法即返回 `ok:false` + 结构化 errors,
|
|
160
|
+
* 绝不静默丢弃核心行程后仍返回「成功」。校验与归一化的单一事实源在
|
|
161
|
+
* `itinerary-doc-shared.ts`,与 deck 投影共用同一拒绝语义。
|
|
162
|
+
*/
|
|
163
|
+
export function renderItineraryHtml(input: unknown): ItineraryDocResult {
|
|
164
|
+
const normalized = normalizeDocInput(input)
|
|
165
|
+
if (!normalized.ok) return normalized
|
|
166
|
+
const html = render(normalized)
|
|
167
|
+
// 输出大小硬上限:超限即整体失败(检查实现于共享层)
|
|
168
|
+
const bytesError = docBytesError(html)
|
|
169
|
+
if (bytesError !== undefined) return { ok: false, errors: bytesError }
|
|
170
|
+
return { ok: true, html }
|
|
171
|
+
}
|
package/ts/src/loop.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Stage 1 对话循环(S2 段1,docs/stage1-top-down-design.md §2.3)。
|
|
2
|
+
* Stage 1 对话循环(S2 段1,docs/design/stage1-top-down-design.md §2.3)。
|
|
3
3
|
*
|
|
4
4
|
* 自顶向下:循环只依赖两个端口——LlmPort(mock/真)与确定性工具(interview_next)。
|
|
5
5
|
* 求解/渲染接线是 S2 后续段;本段验收:重放用户开场白,系统一轮内完成
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { InterviewQuestion, TripState, TravelerProfile, Turn, CalendarState, SolveResult } from './contracts.ts'
|
|
10
10
|
import type { JourneySpecTS } from './unified.ts'
|
|
11
|
+
import { buildTimeAnchor, isRealIsoDate, planningWindowBounds, parsePlanningWindow, type PlanningWindow, type TimeAnchor } from './time-anchor.ts'
|
|
11
12
|
import type { TravelSlotExtraction } from './travel-slots.ts'
|
|
12
13
|
import { anythingSearch } from '../capabilities/anything.ts'
|
|
13
14
|
|
|
@@ -95,6 +96,98 @@ export function validateSpec(spec: JourneySpecTS): string | null {
|
|
|
95
96
|
return null
|
|
96
97
|
}
|
|
97
98
|
|
|
99
|
+
export interface PlanningWindowRejection {
|
|
100
|
+
segmentId: string
|
|
101
|
+
optionId: string
|
|
102
|
+
date: string
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface PlanningWindowCheck {
|
|
106
|
+
spec: JourneySpecTS
|
|
107
|
+
rejected: PlanningWindowRejection[]
|
|
108
|
+
error?: string
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface PlanningWindowOptions {
|
|
112
|
+
/** Registered feasibility tool opts into the dated-candidate default future floor. */
|
|
113
|
+
defaultDatedFuture?: boolean
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function isoDateInBounds(date: string, bounds: { start: string; end: string }): boolean {
|
|
117
|
+
const m = date.match(/^(\d{4})-(\d{2})-(\d{2})$/)
|
|
118
|
+
if (!m || !isRealIsoDate(Number(m[1]), Number(m[2]), Number(m[3]))) return false
|
|
119
|
+
return date >= bounds.start && date <= bounds.end
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function hasDatedCandidates(spec: JourneySpecTS): boolean {
|
|
123
|
+
return spec.segments.some(segment => segment.date !== undefined || segment.options.some(option => option.date !== undefined))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Enforce a named-year future window at the planner boundary. Historical
|
|
128
|
+
* lookup/backtesting remains an explicit bypass; an expired named year fails
|
|
129
|
+
* instead of being silently rolled into a different year.
|
|
130
|
+
*/
|
|
131
|
+
export function applyPlanningWindow(
|
|
132
|
+
spec: JourneySpecTS,
|
|
133
|
+
window: PlanningWindow | null,
|
|
134
|
+
anchor: TimeAnchor,
|
|
135
|
+
options: PlanningWindowOptions = {},
|
|
136
|
+
): PlanningWindowCheck {
|
|
137
|
+
// Dated recommendations are future-oriented even without optional named-year context.
|
|
138
|
+
// Fully dateless legacy calculations remain untouched; historical bypass is explicit.
|
|
139
|
+
if (window?.intent === 'historical') return { spec, rejected: [] }
|
|
140
|
+
const implicitFutureFloor = !window && options.defaultDatedFuture === true && hasDatedCandidates(spec)
|
|
141
|
+
if (!window && !implicitFutureFloor) return { spec, rejected: [] }
|
|
142
|
+
|
|
143
|
+
const currentYear = Number(anchor.today.slice(0, 4))
|
|
144
|
+
if (window && window.requestedYear < currentYear) {
|
|
145
|
+
return {
|
|
146
|
+
spec,
|
|
147
|
+
rejected: [],
|
|
148
|
+
error: `${window.requestedYear} 年已结束(当前规划参考日 ${anchor.today}),不会自动改用其他年份;如需历史查询请明确说明“历史/回测”。`,
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const bounds = window
|
|
153
|
+
? planningWindowBounds(window, anchor)
|
|
154
|
+
: { start: anchor.today, end: '9999-12-31' }
|
|
155
|
+
if (!bounds) return { spec, rejected: [], error: `无法建立 ${window!.requestedYear} 年的未来规划窗口。` }
|
|
156
|
+
|
|
157
|
+
const rejected: PlanningWindowRejection[] = []
|
|
158
|
+
const guardedSegments = spec.segments.map(segment => ({
|
|
159
|
+
...segment,
|
|
160
|
+
options: segment.options.filter(option => {
|
|
161
|
+
const date = option.date ?? segment.date
|
|
162
|
+
if (date && isoDateInBounds(date, bounds)) return true
|
|
163
|
+
rejected.push({ segmentId: segment.id, optionId: option.id, date: date ?? '未提供明确日期' })
|
|
164
|
+
return false
|
|
165
|
+
}),
|
|
166
|
+
}))
|
|
167
|
+
|
|
168
|
+
if (guardedSegments.some(segment => segment.options.length === 0)) {
|
|
169
|
+
return {
|
|
170
|
+
spec: { ...spec, segments: guardedSegments },
|
|
171
|
+
rejected,
|
|
172
|
+
error: implicitFutureFloor
|
|
173
|
+
? `带日期的未来推荐必须不早于当前规划参考日 ${bounds.start};没有带明确日期且在未来窗口内的可接受方案。`
|
|
174
|
+
: `${window!.requestedYear} 年未来规划窗口为 ${bounds.start} 至 ${bounds.end};没有带明确日期且落在窗口内的可接受方案。`,
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return { spec: { ...spec, segments: guardedSegments }, rejected }
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function latestPlanningWindow(history: Turn[], userMsg: string, anchor: TimeAnchor): PlanningWindow | null {
|
|
181
|
+
const turns = [...history, { role: 'user' as const, text: userMsg }]
|
|
182
|
+
for (let i = turns.length - 1; i >= 0; i--) {
|
|
183
|
+
const turn = turns[i]
|
|
184
|
+
if (turn?.role !== 'user') continue
|
|
185
|
+
const parsed = parsePlanningWindow(turn.text, anchor)
|
|
186
|
+
if (parsed) return parsed
|
|
187
|
+
}
|
|
188
|
+
return null
|
|
189
|
+
}
|
|
190
|
+
|
|
98
191
|
/** 求解端口:S3 起由 unified 求解器实现;循环只认此签名(确定性责任)。 */
|
|
99
192
|
export type SolvePort = (spec: JourneySpecTS) => Promise<SolveResult>
|
|
100
193
|
|
|
@@ -110,6 +203,56 @@ export interface AsyncTicket {
|
|
|
110
203
|
etaLabel: string
|
|
111
204
|
}
|
|
112
205
|
|
|
206
|
+
export const ASYNC_TERMINAL_SCHEMA = 'gotry_async_terminal.v1' as const
|
|
207
|
+
|
|
208
|
+
export interface AsyncTerminalOutcome {
|
|
209
|
+
schema: typeof ASYNC_TERMINAL_SCHEMA
|
|
210
|
+
ticket_id: string
|
|
211
|
+
status: 'succeeded' | 'failed'
|
|
212
|
+
passed: number
|
|
213
|
+
total: 4
|
|
214
|
+
checks: Record<string, boolean>
|
|
215
|
+
failed_checks: string[]
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function asyncTerminalOutcome(ticketId: string, checks: Record<string, boolean>): AsyncTerminalOutcome {
|
|
219
|
+
const failedChecks = Object.entries(checks).filter(([, passed]) => !passed).map(([name]) => name)
|
|
220
|
+
return {
|
|
221
|
+
schema: ASYNC_TERMINAL_SCHEMA,
|
|
222
|
+
ticket_id: ticketId,
|
|
223
|
+
status: failedChecks.length === 0 ? 'succeeded' : 'failed',
|
|
224
|
+
passed: Object.values(checks).filter(Boolean).length,
|
|
225
|
+
total: 4,
|
|
226
|
+
checks,
|
|
227
|
+
failed_checks: failedChecks,
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function terminalOutcomeFromState(ticketId: string, state: TripState): AsyncTerminalOutcome {
|
|
232
|
+
if (!state.spec || !state.solve) {
|
|
233
|
+
return asyncTerminalOutcome(ticketId, {
|
|
234
|
+
'1_承诺时间后必有明确产物': false,
|
|
235
|
+
'2_产物通过自检清单': false,
|
|
236
|
+
'3_待决问题全部是简单选择题': false,
|
|
237
|
+
'4_做不到的诚实说': false,
|
|
238
|
+
})
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// issue #620:求解器自身失败时既没有产物也没有判定——2 条不成立;但「做不到诚实说」
|
|
242
|
+
// 恰恰成立(我们明说了是引擎故障而非不可行),不靠 unsat_core 冒充自检通过。
|
|
243
|
+
const solverFailed = Boolean(state.solve.solver_error)
|
|
244
|
+
return asyncTerminalOutcome(ticketId, {
|
|
245
|
+
'1_承诺时间后必有明确产物': Boolean(state.solve.legs?.length || state.solve.verdicts?.length),
|
|
246
|
+
'2_产物通过自检清单': solverFailed
|
|
247
|
+
? false
|
|
248
|
+
: state.solve.feasible
|
|
249
|
+
? (state.solve.legs?.every(l => (l as Record<string, unknown>)['energy_pct'] !== undefined) ?? false)
|
|
250
|
+
: Boolean(state.solve.unsat_core?.length),
|
|
251
|
+
'3_待决问题全部是简单选择题': state.gates.every(g => g.id === 'budget' || g.options.length >= 2),
|
|
252
|
+
'4_做不到的诚实说': solverFailed || state.solve.feasible || Boolean(state.solve.suggestions?.length),
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
|
|
113
256
|
export function isComplex(state: TripState): boolean {
|
|
114
257
|
/** 复杂度判据(架构占位,后续可细化):多段或多约束即深规划 */
|
|
115
258
|
const p = state.profile
|
|
@@ -134,21 +277,19 @@ export async function collectDeepPlanning(
|
|
|
134
277
|
state: TripState,
|
|
135
278
|
ticket: AsyncTicket,
|
|
136
279
|
solve: SolvePort,
|
|
137
|
-
): Promise<{ reply: string; state: TripState }> {
|
|
280
|
+
): Promise<{ reply: string; state: TripState; outcome: AsyncTerminalOutcome }> {
|
|
138
281
|
const spec = state.spec
|
|
139
|
-
if (!spec)
|
|
282
|
+
if (!spec) {
|
|
283
|
+
const outcome = terminalOutcomeFromState(ticket.id, state)
|
|
284
|
+
return { reply: '(内部状态缺失 spec——深度规划未就绪,这是不应发生的路径)', state, outcome }
|
|
285
|
+
}
|
|
140
286
|
state.solve = await solve(spec)
|
|
141
287
|
state.gates = state.gates.filter(g => !g.id.startsWith('async-'))
|
|
142
288
|
|
|
143
289
|
// 不失望四条自检(交付物自带,总纲 3.6)
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
'3_待决问题全部是简单选择题': state.gates.every(g => g.id === 'budget' || g.options.length >= 2),
|
|
148
|
-
'4_做不到的诚实说': state.solve.feasible || Boolean(state.solve.suggestions?.length),
|
|
149
|
-
}
|
|
150
|
-
const head = `# 回访交付:${ticket.objective}\n(工单 ${ticket.id},不失望四条:${Object.values(checks).every(Boolean) ? '4/4 ✅' : '有未达项 ❌'})`
|
|
151
|
-
return { reply: `${head}\n\n${renderSolve(state)}`, state }
|
|
290
|
+
const outcome = terminalOutcomeFromState(ticket.id, state)
|
|
291
|
+
const head = `# 回访交付:${ticket.objective}\n(工单 ${ticket.id},不失望四条:${outcome.status === 'succeeded' ? '4/4 ✅' : '有未达项 ❌'})`
|
|
292
|
+
return { reply: `${head}\n\n${renderSolve(state)}`, state, outcome }
|
|
152
293
|
}
|
|
153
294
|
|
|
154
295
|
/** 求解结果 → 人话(模板;S4 可由 LLM 润色,数字与判定不可改) */
|
|
@@ -156,15 +297,27 @@ export function renderSolve(state: TripState): string {
|
|
|
156
297
|
const s = state.solve
|
|
157
298
|
if (!s) return '(无求解结果)'
|
|
158
299
|
const lines: string[] = []
|
|
159
|
-
if (s.
|
|
300
|
+
if (s.solver_error) {
|
|
301
|
+
// issue #620:求解器自己失败 ≠ 行程不可行。这里**不**说「不可行」、不列「冲突」,
|
|
302
|
+
// 也不把机器 token(solver_error.code)渲染给用户——它只在日志/证据里。
|
|
303
|
+
lines.push('**这轮没算出结论——求解器自身出错了,不是你的行程不可行**')
|
|
304
|
+
lines.push('- 我不把引擎故障说成「不可行」:这条已记录,修好或换候选形态(枚举)后重算')
|
|
305
|
+
} else if (s.feasible) {
|
|
160
306
|
lines.push(`**方案可行,机票合计 ¥${s.money_cny}**`)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
307
|
+
// §7-1 issue #559 卡点 4:从 s.skeleton_notes 字符串编码里推断 unscaffolded 的 seg.id,
|
|
308
|
+
// 不动 unified.ts/journey.ts(内核冻结面 #234),用户面给 ⚠ 前缀与「枢纽对未在骨架覆盖」补充。
|
|
309
|
+
// skeleton_notes 单条形态:`<seg.id>: [骨架:openflights] ❌ ...` 或 `<seg.id>: [骨架:openflights] ✅ ...`
|
|
310
|
+
const unscaffoldedSegIds = new Set<string>()
|
|
311
|
+
for (const n of s.skeleton_notes ?? []) {
|
|
312
|
+
const m = /^([^:]+):\s*\[骨架:openflights\]\s*❌/.exec(n)
|
|
313
|
+
if (m) unscaffoldedSegIds.add(m[1])
|
|
165
314
|
}
|
|
166
|
-
for (const
|
|
167
|
-
|
|
315
|
+
for (const lg of s.legs ?? []) {
|
|
316
|
+
const l = lg as Record<string, string | number | boolean>
|
|
317
|
+
const unscaffoldedFlag = unscaffoldedSegIds.has(String(l['leg'])) ? '⚠ ' : ''
|
|
318
|
+
const unscaffoldedNote = unscaffoldedSegIds.has(String(l['leg'])) ? '(枢纽对未在骨架覆盖,实时源以新航线为准)' : ''
|
|
319
|
+
lines.push(`- ${unscaffoldedFlag}${l['leg']} ${l['service']}:${l['dep']} 起飞,${l['wake']} 出发,${l['arrive_stay']} 到,`
|
|
320
|
+
+ `门到门 ${l['door_to_door']},落地精力 ${l['energy_pct']}%,¥${l['price_cny']}${unscaffoldedNote ? ` ${unscaffoldedNote}` : ''}`)
|
|
168
321
|
}
|
|
169
322
|
for (const n of s.skeleton_notes ?? []) lines.push(`- ${n}`)
|
|
170
323
|
for (const f of s.red_flags ?? []) lines.push(`- ⚠️ ${f}`)
|
|
@@ -172,6 +325,9 @@ export function renderSolve(state: TripState): string {
|
|
|
172
325
|
lines.push(`**当前约束下不可行——冲突:${(s.unsat_core ?? []).join('、')}`)
|
|
173
326
|
for (const sg of s.suggestions ?? []) lines.push(`- 放宽「${sg.relax}」可解(约 ¥${sg.money_cny})`)
|
|
174
327
|
}
|
|
328
|
+
for (const e of s.work_window_exclusions ?? []) {
|
|
329
|
+
lines.push(`- 已排除 ${e.option}(工作窗口):${e.reason}`)
|
|
330
|
+
}
|
|
175
331
|
if (state.gates.length) {
|
|
176
332
|
lines.push('', '**待你决定(选择题)**')
|
|
177
333
|
for (const g of state.gates) {
|
|
@@ -188,7 +344,9 @@ export async function runTurn(
|
|
|
188
344
|
llm: LlmPort,
|
|
189
345
|
history: Turn[] = [],
|
|
190
346
|
solve: SolvePort | null = null,
|
|
347
|
+
now: Date = new Date(),
|
|
191
348
|
): Promise<{ reply: string; state: TripState }> {
|
|
349
|
+
const anchor = buildTimeAnchor(now)
|
|
192
350
|
const facts = await llm.extractFacts([...history, { role: 'user', text: userMsg }], state)
|
|
193
351
|
|
|
194
352
|
const conflicts: string[] = []
|
|
@@ -236,7 +394,10 @@ export async function runTurn(
|
|
|
236
394
|
} else if (ar.verdict === 'miss') {
|
|
237
395
|
parts.push(`**${poiProbe} → miss** (酒店-be Anything 一切正常但无候选)\n${ar.evidence}`)
|
|
238
396
|
} else {
|
|
239
|
-
|
|
397
|
+
// 用户面只给人话原因 + 来源 tag:evidence 里的上游原话是溯源契约(能力层测试锁),
|
|
398
|
+
// 其中的进程噪音(如 `(exit null)`)不该渲染进回复。
|
|
399
|
+
const sourceTag = ar.evidence.match(/^\[[^\]]+\]/)?.[0]
|
|
400
|
+
parts.push(`**${poiProbe} → 实时查询不可用**(${ar.error ?? 'hbcli 不可达'})——这条不阻塞本轮规划,只影响实时数据源,其余结论照常带来源标注${sourceTag ? `\n${sourceTag}` : ''}`)
|
|
240
401
|
}
|
|
241
402
|
}
|
|
242
403
|
|
|
@@ -244,7 +405,22 @@ export async function runTurn(
|
|
|
244
405
|
|
|
245
406
|
// 约束齐备(无阻塞问题)→ 翻译 spec → **校验闸 + 日期一致性闸** → 求解 → 渲染
|
|
246
407
|
if (blocking.length === 0 && solve) {
|
|
247
|
-
const
|
|
408
|
+
const extractedSpec = await llm.extractSpec([...history, { role: 'user', text: userMsg }], state)
|
|
409
|
+
const planning = latestPlanningWindow(history, userMsg, anchor)
|
|
410
|
+
const planningCheck = extractedSpec ? applyPlanningWindow(extractedSpec, planning, anchor) : null
|
|
411
|
+
if (planningCheck?.error) {
|
|
412
|
+
state.spec = undefined
|
|
413
|
+
state.solve = undefined
|
|
414
|
+
parts.push(`⚠️ ${planningCheck.error}`)
|
|
415
|
+
return { reply: parts.join('\n\n'), state }
|
|
416
|
+
}
|
|
417
|
+
if (planningCheck?.rejected.length) {
|
|
418
|
+
const rejected = planningCheck.rejected
|
|
419
|
+
.map(r => `${r.segmentId}/${r.optionId}(${r.date})`)
|
|
420
|
+
.join('、')
|
|
421
|
+
parts.push(`已排除规划窗口外的候选:${rejected}`)
|
|
422
|
+
}
|
|
423
|
+
const spec = planningCheck?.spec ?? extractedSpec
|
|
248
424
|
// 场景路由:erhai 候选标记 → 候选求解(洱海金标准的引擎判定)——纯 TS unify 路径
|
|
249
425
|
if (spec && (spec as unknown as { note?: string }).note === 'erhai-candidates') {
|
|
250
426
|
const { readFile } = await import('node:fs/promises')
|
|
@@ -268,11 +444,10 @@ export async function runTurn(
|
|
|
268
444
|
// D-10 切片 C:spec↔槽位日期一致性闸(ADR-10 翻译≠造数的执行点)。
|
|
269
445
|
// LLM 翻译的 spec 日期与代码层换算的槽位日期分歧时不求解、不猜,追问确认——
|
|
270
446
|
// 日期是求解关键输入,错日期 = 错判决。槽位缺失/unresolved 不参与(不造假阳性)。
|
|
271
|
-
const ext = await llm.extractSlots([...history, { role: 'user', text: userMsg }])
|
|
447
|
+
const ext = await llm.extractSlots([...history, { role: 'user', text: userMsg }], now)
|
|
272
448
|
if (ext) {
|
|
273
449
|
const { resolveSlots, specDateMismatches } = await import('./slot-spec.ts')
|
|
274
|
-
const
|
|
275
|
-
const mismatches = specDateMismatches(spec, resolveSlots(ext, buildTimeAnchor()))
|
|
450
|
+
const mismatches = specDateMismatches(spec, resolveSlots(ext, anchor))
|
|
276
451
|
if (mismatches.length > 0) {
|
|
277
452
|
const lines = mismatches.map(m => `- ${m.specAt}:翻译说 ${m.specDate},你的原话换算是 ${m.slotDate}(${m.field})`)
|
|
278
453
|
parts.push(`⚠️ 日期分歧,确认后我再算(以你为准):\n${lines.join('\n')}`)
|
|
@@ -341,14 +516,44 @@ export async function loadAsyncTicket(ticketId: string, stateRoot = '.'): Promis
|
|
|
341
516
|
}
|
|
342
517
|
}
|
|
343
518
|
|
|
344
|
-
export async function settleAsyncTicket(
|
|
345
|
-
|
|
519
|
+
export async function settleAsyncTicket(
|
|
520
|
+
ticketId: string,
|
|
521
|
+
reply: string,
|
|
522
|
+
stateRoot = '.',
|
|
523
|
+
outcome?: AsyncTerminalOutcome,
|
|
524
|
+
): Promise<string> {
|
|
525
|
+
const ledger = openLedgerIfExists(stateRoot)
|
|
526
|
+
const terminalOutcome = outcome ?? recoverAsyncTerminalOutcome(ledger, ticketId)
|
|
527
|
+
if (ledger && !terminalOutcome) {
|
|
528
|
+
throw new Error(`workflow ${ticketId} 缺少可恢复的 ${ASYNC_TERMINAL_SCHEMA},拒绝误结算`)
|
|
529
|
+
}
|
|
530
|
+
if (terminalOutcome?.status === 'failed') ledger?.failWorkflowRun(ticketId, reply, terminalOutcome)
|
|
531
|
+
else ledger?.settleWorkflowRun(ticketId, reply, terminalOutcome)
|
|
346
532
|
const dir = await asyncDir(stateRoot)
|
|
347
533
|
const p = join(dir, `${ticketId}.deliverable.md`)
|
|
348
534
|
await atomicWrite(p, reply)
|
|
349
535
|
return p
|
|
350
536
|
}
|
|
351
537
|
|
|
538
|
+
function recoverAsyncTerminalOutcome(ledger: StateLedger | null, ticketId: string): AsyncTerminalOutcome | undefined {
|
|
539
|
+
if (!ledger) return undefined
|
|
540
|
+
const run = ledger.getWorkflowRun(ticketId)
|
|
541
|
+
if (!run) return undefined
|
|
542
|
+
|
|
543
|
+
try {
|
|
544
|
+
const state = JSON.parse(run.state_json) as TripState
|
|
545
|
+
if (!state.spec) return terminalOutcomeFromState(ticketId, state)
|
|
546
|
+
|
|
547
|
+
const solveStep = ledger.getWorkflowStep(ticketId, 'solve')
|
|
548
|
+
if (solveStep?.status !== 'done' || !solveStep.result) return undefined
|
|
549
|
+
state.solve = JSON.parse(solveStep.result) as SolveResult
|
|
550
|
+
state.gates = state.gates.filter(g => !g.id.startsWith('async-'))
|
|
551
|
+
return terminalOutcomeFromState(ticketId, state)
|
|
552
|
+
} catch {
|
|
553
|
+
return undefined
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
352
557
|
/**
|
|
353
558
|
* 可日志化 solve 端口(ADR-15 步骤日志,intent-before-execute):
|
|
354
559
|
* 先记 intent 再执行,done 后结果落账本——任意进程恢复时 done 的步骤直接复用
|
|
@@ -380,6 +585,9 @@ export function makeJournaledSolvePort(ledger: StateLedger, runId: string, solve
|
|
|
380
585
|
* 2026-08-28 巡检收紧:旧版 ≤24 直通把访谈答案整句当关键词,垃圾 hbcli 调用+证据噪音)。
|
|
381
586
|
* 不是意图(改求解器),只是 datasources 编排层的"提早调 anything"提示。
|
|
382
587
|
*/
|
|
588
|
+
/** 住宿名称段上界:路径 2 已要求含拉丁/数字且被标点截断,旧 24 字会把
|
|
589
|
+
* 「The Title East Wing Rawai」这类真实酒店名截残后回显给用户(2026-09-22)。 */
|
|
590
|
+
const POI_NAME_MAX = 48
|
|
383
591
|
export function probePoi(msg: string): string | null {
|
|
384
592
|
const trimmed = msg.trim()
|
|
385
593
|
if (!trimmed) return null
|
|
@@ -395,7 +603,7 @@ export function probePoi(msg: string): string | null {
|
|
|
395
603
|
if (/(酒店|民宿|客栈|饭店)/.test(trimmed)) {
|
|
396
604
|
const parts = trimmed.split(/(酒店|民宿|客栈|饭店)/)
|
|
397
605
|
const after = cutAtPunct((parts[2] ?? '').replace(/^[的::\s]+/, ''))
|
|
398
|
-
if (after.length >= 2 && /[A-Za-z0-9]/.test(after)) return after.slice(0,
|
|
606
|
+
if (after.length >= 2 && /[A-Za-z0-9]/.test(after)) return after.length > POI_NAME_MAX ? `${after.slice(0, POI_NAME_MAX - 1)}…` : after
|
|
399
607
|
const nounAt = trimmed.search(/(酒店|民宿|客栈|饭店)/)
|
|
400
608
|
const pre = trimmed.slice(Math.max(0, nounAt - 6), nounAt).match(/[一-龥]{2,6}$/)
|
|
401
609
|
if (pre && !/(机票|车票|和|做|订|的)$/.test(pre[0])) return pre[0]
|