@danceiny/gotry 0.0.1-rc.8 → 0.2.0-rc.27
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 -217
- 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 +1744 -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 -49
- 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 +135 -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 +546 -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 +968 -0
- package/dist/capabilities/fx-contract.js +293 -0
- package/dist/capabilities/geo-atlas.js +246 -0
- package/dist/capabilities/ground-transfer.js +509 -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/resilience.js +191 -0
- package/dist/capabilities/session/action-cache.js +126 -0
- package/dist/capabilities/session/adapters/ctrip-flight.js +141 -0
- 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 +54 -0
- 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 +50 -0
- 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 +107 -0
- package/dist/capabilities/session/static-flight-golden.js +150 -0
- package/dist/capabilities/session/transport.js +109 -0
- 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 +686 -0
- 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 +72 -0
- 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-tests.js +116 -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 +68 -10
- 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 +123 -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 +1479 -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/companion-tests.js +67 -0
- 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 +564 -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-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 +131 -0
- package/dist/scripts/g5-guard.js +189 -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 +480 -0
- package/dist/scripts/ledger-workflow-crash.js +32 -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 +49 -0
- package/dist/scripts/memory-lifecycle-tests.js +657 -0
- package/dist/scripts/memory-lifecycle.js +196 -0
- package/dist/scripts/memory-metrics.js +29 -31
- 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 +161 -0
- package/dist/scripts/nightly-evidence.js +286 -0
- package/dist/scripts/nudge-digest.js +43 -42
- 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/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 +20 -18
- package/dist/scripts/replay-real.js +18 -18
- package/dist/scripts/replay.js +52 -82
- package/dist/scripts/session-attach-diagnose.js +31 -0
- package/dist/scripts/session-attach-poc.js +62 -0
- 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 +60 -0
- package/dist/scripts/session-link-tests.js +478 -0
- package/dist/scripts/session-login.js +29 -0
- package/dist/scripts/session-tests.js +862 -0
- package/dist/scripts/session-zones-tests.js +358 -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 +703 -219
- package/dist/scripts/spawn-bounded-abort-tests.js +241 -0
- package/dist/scripts/sponsor-reuse-tests.js +262 -0
- package/dist/scripts/state-cli-tests.js +261 -0
- package/dist/scripts/state-cli.js +585 -0
- 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 +210 -192
- package/dist/scripts/travel-timeline-tests.js +59 -0
- 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 +23 -19
- 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 +41 -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/companions.js +86 -0
- package/dist/src/contracts.js +21 -43
- package/dist/src/dsh-llm.js +97 -111
- 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 +2305 -731
- 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 +358 -162
- package/dist/src/memory-capture.js +180 -32
- package/dist/src/memory-decay.js +47 -0
- 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/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-zones.js +507 -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 +767 -0
- 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 +59 -0
- 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 +538 -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 +255 -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 +296 -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 +568 -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 +13 -3
- package/ts/src/dsh-llm.ts +44 -11
- package/ts/src/flyai-setup-tool.ts +77 -0
- package/ts/src/index.ts +2107 -224
- 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 +278 -40
- 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 +912 -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 +360 -89
- package/ts/src/wish-pool.ts +79 -0
package/dist/src/loop.js
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage 1 对话循环(S2 段1,docs/design/stage1-top-down-design.md §2.3)。
|
|
3
|
+
*
|
|
4
|
+
* 自顶向下:循环只依赖两个端口——LlmPort(mock/真)与确定性工具(interview_next)。
|
|
5
|
+
* 求解/渲染接线是 S2 后续段;本段验收:重放用户开场白,系统一轮内完成
|
|
6
|
+
* 日历断言 + 访谈补全启动(问出工作窗口与已订资源——Kimi 第 6 轮才问的事)。
|
|
7
|
+
*/
|
|
8
|
+
import { buildTimeAnchor, isRealIsoDate, planningWindowBounds, parsePlanningWindow } from './time-anchor.js';
|
|
1
9
|
import { anythingSearch } from '../capabilities/anything.js';
|
|
2
10
|
export function newState(year = 2026) {
|
|
3
11
|
return {
|
|
4
|
-
calendar: {
|
|
5
|
-
year,
|
|
6
|
-
assertedWeekdays: {}
|
|
7
|
-
},
|
|
12
|
+
calendar: { year, assertedWeekdays: {} },
|
|
8
13
|
profile: {},
|
|
9
14
|
gates: [],
|
|
10
|
-
wishes: []
|
|
15
|
+
wishes: [],
|
|
11
16
|
};
|
|
12
17
|
}
|
|
18
|
+
/** ADR-9:访谈由缺失字段驱动(确定性,无 LLM 即兴) */
|
|
13
19
|
export function interviewNext(state) {
|
|
14
20
|
const p = state.profile;
|
|
15
21
|
const questions = [];
|
|
@@ -18,14 +24,14 @@ export function interviewNext(state) {
|
|
|
18
24
|
questions.push({
|
|
19
25
|
key: 'workWindow',
|
|
20
26
|
text: '你这两周要远程办公——工作时间是几点到几点、按哪个时区?这决定每天的可玩时段。',
|
|
21
|
-
why: '工作窗口直接决定每日节奏(普吉 13:00-22:00 与 9:00-18:00 是两种人生)'
|
|
27
|
+
why: '工作窗口直接决定每日节奏(普吉 13:00-22:00 与 9:00-18:00 是两种人生)',
|
|
22
28
|
});
|
|
23
29
|
}
|
|
24
30
|
if (!p.bookedResources) {
|
|
25
31
|
questions.push({
|
|
26
32
|
key: 'bookedResources',
|
|
27
33
|
text: '已经有订好的航班或酒店吗?(哪怕只是意向)——已订资源是硬锚点,先告诉我再规划。',
|
|
28
|
-
why: '已订资源决定哪些段不可动,Kimi 式规划会绕开它们重排'
|
|
34
|
+
why: '已订资源决定哪些段不可动,Kimi 式规划会绕开它们重排',
|
|
29
35
|
});
|
|
30
36
|
}
|
|
31
37
|
if (!p.budgetTier) {
|
|
@@ -34,35 +40,28 @@ export function interviewNext(state) {
|
|
|
34
40
|
text: '预算档位:经济(¥12.6k 级)/ 舒适(¥16.3k 级)/ 便利优先?',
|
|
35
41
|
why: '分层预算决定班次与住宿的选型口径',
|
|
36
42
|
options: [
|
|
37
|
-
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
label: '舒适',
|
|
43
|
-
tradeOff: 'workation 办公质量优先'
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
label: '便利优先',
|
|
47
|
-
tradeOff: '时间最省'
|
|
48
|
-
}
|
|
49
|
-
]
|
|
43
|
+
{ label: '经济', tradeOff: '省钱,接驳多走路' },
|
|
44
|
+
{ label: '舒适', tradeOff: 'workation 办公质量优先' },
|
|
45
|
+
{ label: '便利优先', tradeOff: '时间最省' },
|
|
46
|
+
],
|
|
50
47
|
});
|
|
51
48
|
}
|
|
52
|
-
return {
|
|
53
|
-
questions,
|
|
54
|
-
missing: questions.map((q)=>q.key)
|
|
55
|
-
};
|
|
49
|
+
return { questions, missing: questions.map(q => q.key) };
|
|
56
50
|
}
|
|
51
|
+
/** spec 校验闸:LLM 翻译产物进求解器前的确定性形状检查(责任边界的执行点)。 */
|
|
57
52
|
export function validateSpec(spec) {
|
|
58
|
-
if (!Array.isArray(spec.segments) || spec.segments.length === 0)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (!
|
|
62
|
-
|
|
53
|
+
if (!Array.isArray(spec.segments) || spec.segments.length === 0)
|
|
54
|
+
return '没有段(segments)';
|
|
55
|
+
for (const seg of spec.segments) {
|
|
56
|
+
if (!seg.id)
|
|
57
|
+
return '存在缺少 id 的段';
|
|
58
|
+
if (!Array.isArray(seg.options) || seg.options.length === 0)
|
|
59
|
+
return `段 ${seg.id} 没有可选方案`;
|
|
60
|
+
for (const opt of seg.options) {
|
|
63
61
|
const svcs = opt.move?.services;
|
|
64
|
-
if (!Array.isArray(svcs) || svcs.length === 0)
|
|
65
|
-
|
|
62
|
+
if (!Array.isArray(svcs) || svcs.length === 0)
|
|
63
|
+
return `段 ${seg.id} 的方案 ${opt.id} 缺少班次(services)`;
|
|
64
|
+
for (const s of svcs) {
|
|
66
65
|
if (typeof s.depMin !== 'number' || typeof s.arrMin !== 'number') {
|
|
67
66
|
return `段 ${seg.id}/${opt.id} 的班次 ${s.id ?? '?'} 缺少时刻(depMin/arrMin)`;
|
|
68
67
|
}
|
|
@@ -71,7 +70,108 @@ export function validateSpec(spec) {
|
|
|
71
70
|
}
|
|
72
71
|
return null;
|
|
73
72
|
}
|
|
73
|
+
function isoDateInBounds(date, bounds) {
|
|
74
|
+
const m = date.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
75
|
+
if (!m || !isRealIsoDate(Number(m[1]), Number(m[2]), Number(m[3])))
|
|
76
|
+
return false;
|
|
77
|
+
return date >= bounds.start && date <= bounds.end;
|
|
78
|
+
}
|
|
79
|
+
function hasDatedCandidates(spec) {
|
|
80
|
+
return spec.segments.some(segment => segment.date !== undefined || segment.options.some(option => option.date !== undefined));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Enforce a named-year future window at the planner boundary. Historical
|
|
84
|
+
* lookup/backtesting remains an explicit bypass; an expired named year fails
|
|
85
|
+
* instead of being silently rolled into a different year.
|
|
86
|
+
*/
|
|
87
|
+
export function applyPlanningWindow(spec, window, anchor, options = {}) {
|
|
88
|
+
// Dated recommendations are future-oriented even without optional named-year context.
|
|
89
|
+
// Fully dateless legacy calculations remain untouched; historical bypass is explicit.
|
|
90
|
+
if (window?.intent === 'historical')
|
|
91
|
+
return { spec, rejected: [] };
|
|
92
|
+
const implicitFutureFloor = !window && options.defaultDatedFuture === true && hasDatedCandidates(spec);
|
|
93
|
+
if (!window && !implicitFutureFloor)
|
|
94
|
+
return { spec, rejected: [] };
|
|
95
|
+
const currentYear = Number(anchor.today.slice(0, 4));
|
|
96
|
+
if (window && window.requestedYear < currentYear) {
|
|
97
|
+
return {
|
|
98
|
+
spec,
|
|
99
|
+
rejected: [],
|
|
100
|
+
error: `${window.requestedYear} 年已结束(当前规划参考日 ${anchor.today}),不会自动改用其他年份;如需历史查询请明确说明“历史/回测”。`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const bounds = window
|
|
104
|
+
? planningWindowBounds(window, anchor)
|
|
105
|
+
: { start: anchor.today, end: '9999-12-31' };
|
|
106
|
+
if (!bounds)
|
|
107
|
+
return { spec, rejected: [], error: `无法建立 ${window.requestedYear} 年的未来规划窗口。` };
|
|
108
|
+
const rejected = [];
|
|
109
|
+
const guardedSegments = spec.segments.map(segment => ({
|
|
110
|
+
...segment,
|
|
111
|
+
options: segment.options.filter(option => {
|
|
112
|
+
const date = option.date ?? segment.date;
|
|
113
|
+
if (date && isoDateInBounds(date, bounds))
|
|
114
|
+
return true;
|
|
115
|
+
rejected.push({ segmentId: segment.id, optionId: option.id, date: date ?? '未提供明确日期' });
|
|
116
|
+
return false;
|
|
117
|
+
}),
|
|
118
|
+
}));
|
|
119
|
+
if (guardedSegments.some(segment => segment.options.length === 0)) {
|
|
120
|
+
return {
|
|
121
|
+
spec: { ...spec, segments: guardedSegments },
|
|
122
|
+
rejected,
|
|
123
|
+
error: implicitFutureFloor
|
|
124
|
+
? `带日期的未来推荐必须不早于当前规划参考日 ${bounds.start};没有带明确日期且在未来窗口内的可接受方案。`
|
|
125
|
+
: `${window.requestedYear} 年未来规划窗口为 ${bounds.start} 至 ${bounds.end};没有带明确日期且落在窗口内的可接受方案。`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return { spec: { ...spec, segments: guardedSegments }, rejected };
|
|
129
|
+
}
|
|
130
|
+
function latestPlanningWindow(history, userMsg, anchor) {
|
|
131
|
+
const turns = [...history, { role: 'user', text: userMsg }];
|
|
132
|
+
for (let i = turns.length - 1; i >= 0; i--) {
|
|
133
|
+
const turn = turns[i];
|
|
134
|
+
if (turn?.role !== 'user')
|
|
135
|
+
continue;
|
|
136
|
+
const parsed = parsePlanningWindow(turn.text, anchor);
|
|
137
|
+
if (parsed)
|
|
138
|
+
return parsed;
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
export const ASYNC_TERMINAL_SCHEMA = 'gotry_async_terminal.v1';
|
|
143
|
+
function asyncTerminalOutcome(ticketId, checks) {
|
|
144
|
+
const failedChecks = Object.entries(checks).filter(([, passed]) => !passed).map(([name]) => name);
|
|
145
|
+
return {
|
|
146
|
+
schema: ASYNC_TERMINAL_SCHEMA,
|
|
147
|
+
ticket_id: ticketId,
|
|
148
|
+
status: failedChecks.length === 0 ? 'succeeded' : 'failed',
|
|
149
|
+
passed: Object.values(checks).filter(Boolean).length,
|
|
150
|
+
total: 4,
|
|
151
|
+
checks,
|
|
152
|
+
failed_checks: failedChecks,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function terminalOutcomeFromState(ticketId, state) {
|
|
156
|
+
if (!state.spec || !state.solve) {
|
|
157
|
+
return asyncTerminalOutcome(ticketId, {
|
|
158
|
+
'1_承诺时间后必有明确产物': false,
|
|
159
|
+
'2_产物通过自检清单': false,
|
|
160
|
+
'3_待决问题全部是简单选择题': false,
|
|
161
|
+
'4_做不到的诚实说': false,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return asyncTerminalOutcome(ticketId, {
|
|
165
|
+
'1_承诺时间后必有明确产物': Boolean(state.solve.legs?.length || state.solve.verdicts?.length),
|
|
166
|
+
'2_产物通过自检清单': state.solve.feasible
|
|
167
|
+
? (state.solve.legs?.every(l => l['energy_pct'] !== undefined) ?? false)
|
|
168
|
+
: Boolean(state.solve.unsat_core?.length),
|
|
169
|
+
'3_待决问题全部是简单选择题': state.gates.every(g => g.id === 'budget' || g.options.length >= 2),
|
|
170
|
+
'4_做不到的诚实说': state.solve.feasible || Boolean(state.solve.suggestions?.length),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
74
173
|
export function isComplex(state) {
|
|
174
|
+
/** 复杂度判据(架构占位,后续可细化):多段或多约束即深规划 */
|
|
75
175
|
const p = state.profile;
|
|
76
176
|
return Boolean(p.workWindow && p.bookedResources) && (state.gates.length > 0 || Boolean(state.spec));
|
|
77
177
|
}
|
|
@@ -80,135 +180,149 @@ export async function requestDeepPlanning(state) {
|
|
|
80
180
|
id: `dp-${Date.now().toString(36)}`,
|
|
81
181
|
objective: '生成已验证的行程方案:全成本核算 + 动机/约束匹配 + 不失望四条',
|
|
82
182
|
requestedAt: new Date().toISOString(),
|
|
83
|
-
etaLabel: '约 1 小时(mock 期:秒级)'
|
|
84
|
-
};
|
|
85
|
-
state.gates.push({
|
|
86
|
-
id: `async-${ticket.id}`,
|
|
87
|
-
question: `深度规划已启动(${ticket.etaLabel})`,
|
|
88
|
-
options: []
|
|
89
|
-
});
|
|
90
|
-
const reply = '这趟行程跨度大(两周 workation + 三城 + 红眼返程),我切到**深度规划模式**:后台做多轮校验' + '(锚点/工作窗口/全成本/负例排查),做好后通知你。**先留一道选择题给你**,回来直接定:' + '\n1. 预算档位?(经济/舒适/便利优先)';
|
|
91
|
-
return {
|
|
92
|
-
reply,
|
|
93
|
-
ticket
|
|
183
|
+
etaLabel: '约 1 小时(mock 期:秒级)',
|
|
94
184
|
};
|
|
185
|
+
state.gates.push({ id: `async-${ticket.id}`, question: `深度规划已启动(${ticket.etaLabel})`, options: [] });
|
|
186
|
+
const reply = '这趟行程跨度大(两周 workation + 三城 + 红眼返程),我切到**深度规划模式**:后台做多轮校验'
|
|
187
|
+
+ '(锚点/工作窗口/全成本/负例排查),做好后通知你。**先留一道选择题给你**,回来直接定:'
|
|
188
|
+
+ '\n1. 预算档位?(经济/舒适/便利优先)';
|
|
189
|
+
return { reply, ticket };
|
|
95
190
|
}
|
|
96
191
|
export async function collectDeepPlanning(state, ticket, solve) {
|
|
97
192
|
const spec = state.spec;
|
|
98
|
-
if (!spec)
|
|
99
|
-
|
|
100
|
-
state
|
|
101
|
-
}
|
|
193
|
+
if (!spec) {
|
|
194
|
+
const outcome = terminalOutcomeFromState(ticket.id, state);
|
|
195
|
+
return { reply: '(内部状态缺失 spec——深度规划未就绪,这是不应发生的路径)', state, outcome };
|
|
196
|
+
}
|
|
102
197
|
state.solve = await solve(spec);
|
|
103
|
-
state.gates = state.gates.filter(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
'4_做不到的诚实说': state.solve.feasible || Boolean(state.solve.suggestions?.length)
|
|
109
|
-
};
|
|
110
|
-
const head = `# 回访交付:${ticket.objective}\n(工单 ${ticket.id},不失望四条:${Object.values(checks).every(Boolean) ? '4/4 ✅' : '有未达项 ❌'})`;
|
|
111
|
-
return {
|
|
112
|
-
reply: `${head}\n\n${renderSolve(state)}`,
|
|
113
|
-
state
|
|
114
|
-
};
|
|
198
|
+
state.gates = state.gates.filter(g => !g.id.startsWith('async-'));
|
|
199
|
+
// 不失望四条自检(交付物自带,总纲 3.6)
|
|
200
|
+
const outcome = terminalOutcomeFromState(ticket.id, state);
|
|
201
|
+
const head = `# 回访交付:${ticket.objective}\n(工单 ${ticket.id},不失望四条:${outcome.status === 'succeeded' ? '4/4 ✅' : '有未达项 ❌'})`;
|
|
202
|
+
return { reply: `${head}\n\n${renderSolve(state)}`, state, outcome };
|
|
115
203
|
}
|
|
204
|
+
/** 求解结果 → 人话(模板;S4 可由 LLM 润色,数字与判定不可改) */
|
|
116
205
|
export function renderSolve(state) {
|
|
117
206
|
const s = state.solve;
|
|
118
|
-
if (!s)
|
|
207
|
+
if (!s)
|
|
208
|
+
return '(无求解结果)';
|
|
119
209
|
const lines = [];
|
|
120
210
|
if (s.feasible) {
|
|
121
211
|
lines.push(`**方案可行,机票合计 ¥${s.money_cny}**`);
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
212
|
+
// §7-1 issue #559 卡点 4:从 s.skeleton_notes 字符串编码里推断 unscaffolded 的 seg.id,
|
|
213
|
+
// 不动 unified.ts/journey.ts(内核冻结面 #234),用户面给 ⚠ 前缀与「枢纽对未在骨架覆盖」补充。
|
|
214
|
+
// skeleton_notes 单条形态:`<seg.id>: [骨架:openflights] ❌ ...` 或 `<seg.id>: [骨架:openflights] ✅ ...`
|
|
215
|
+
const unscaffoldedSegIds = new Set();
|
|
216
|
+
for (const n of s.skeleton_notes ?? []) {
|
|
217
|
+
const m = /^([^:]+):\s*\[骨架:openflights\]\s*❌/.exec(n);
|
|
218
|
+
if (m)
|
|
219
|
+
unscaffoldedSegIds.add(m[1]);
|
|
125
220
|
}
|
|
126
|
-
for (const
|
|
127
|
-
|
|
221
|
+
for (const lg of s.legs ?? []) {
|
|
222
|
+
const l = lg;
|
|
223
|
+
const unscaffoldedFlag = unscaffoldedSegIds.has(String(l['leg'])) ? '⚠ ' : '';
|
|
224
|
+
const unscaffoldedNote = unscaffoldedSegIds.has(String(l['leg'])) ? '(枢纽对未在骨架覆盖,实时源以新航线为准)' : '';
|
|
225
|
+
lines.push(`- ${unscaffoldedFlag}${l['leg']} ${l['service']}:${l['dep']} 起飞,${l['wake']} 出发,${l['arrive_stay']} 到,`
|
|
226
|
+
+ `门到门 ${l['door_to_door']},落地精力 ${l['energy_pct']}%,¥${l['price_cny']}${unscaffoldedNote ? ` ${unscaffoldedNote}` : ''}`);
|
|
128
227
|
}
|
|
129
|
-
for (const n of s.skeleton_notes ?? [])
|
|
130
|
-
|
|
131
|
-
|
|
228
|
+
for (const n of s.skeleton_notes ?? [])
|
|
229
|
+
lines.push(`- ${n}`);
|
|
230
|
+
for (const f of s.red_flags ?? [])
|
|
231
|
+
lines.push(`- ⚠️ ${f}`);
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
132
234
|
lines.push(`**当前约束下不可行——冲突:${(s.unsat_core ?? []).join('、')}`);
|
|
133
|
-
for (const sg of s.suggestions ?? [])
|
|
235
|
+
for (const sg of s.suggestions ?? [])
|
|
236
|
+
lines.push(`- 放宽「${sg.relax}」可解(约 ¥${sg.money_cny})`);
|
|
237
|
+
}
|
|
238
|
+
for (const e of s.work_window_exclusions ?? []) {
|
|
239
|
+
lines.push(`- 已排除 ${e.option}(工作窗口):${e.reason}`);
|
|
134
240
|
}
|
|
135
241
|
if (state.gates.length) {
|
|
136
242
|
lines.push('', '**待你决定(选择题)**');
|
|
137
|
-
for (const g of state.gates){
|
|
138
|
-
lines.push(`- ${g.question} → ${g.options.map(
|
|
243
|
+
for (const g of state.gates) {
|
|
244
|
+
lines.push(`- ${g.question} → ${g.options.map(o => o.label + (o.tradeOff ? `(${o.tradeOff})` : '')).join(' / ')}`);
|
|
139
245
|
}
|
|
140
246
|
}
|
|
141
247
|
return lines.join('\n');
|
|
142
248
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
role: 'user',
|
|
148
|
-
text: userMsg
|
|
149
|
-
}
|
|
150
|
-
], state);
|
|
249
|
+
/** 一次对话回合:抽取事实(冲突即指出)→ 增量访谈 → 约束齐备则求解+渲染。 */
|
|
250
|
+
export async function runTurn(state, userMsg, llm, history = [], solve = null, now = new Date()) {
|
|
251
|
+
const anchor = buildTimeAnchor(now);
|
|
252
|
+
const facts = await llm.extractFacts([...history, { role: 'user', text: userMsg }], state);
|
|
151
253
|
const conflicts = [];
|
|
152
254
|
if (facts.calendar?.assertedWeekdays) {
|
|
153
|
-
for (const [date, wd] of Object.entries(facts.calendar.assertedWeekdays)){
|
|
255
|
+
for (const [date, wd] of Object.entries(facts.calendar.assertedWeekdays)) {
|
|
154
256
|
const prev = state.calendar.assertedWeekdays[date];
|
|
155
257
|
if (prev && prev !== wd) {
|
|
156
258
|
conflicts.push(`${date}:已有断言 ${prev},新说法 ${wd}——以先断言为准,如需改请明确说`);
|
|
157
|
-
}
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
158
261
|
state.calendar.assertedWeekdays[date] = wd;
|
|
159
262
|
}
|
|
160
263
|
}
|
|
161
264
|
}
|
|
162
265
|
Object.assign(state.profile, facts.profile ?? {});
|
|
266
|
+
// 访谈:workWindow/bookedResources 是求解前置;budgetTier 转为 gate(不阻塞规划)
|
|
163
267
|
const { questions } = interviewNext(state);
|
|
164
|
-
const blocking = questions.filter(
|
|
165
|
-
const budgetQ = questions.find(
|
|
166
|
-
if (budgetQ && !state.gates.some(
|
|
268
|
+
const blocking = questions.filter(q => q.key !== 'budgetTier');
|
|
269
|
+
const budgetQ = questions.find(q => q.key === 'budgetTier');
|
|
270
|
+
if (budgetQ && !state.gates.some(g => g.id === 'budget')) {
|
|
167
271
|
state.gates.push({
|
|
168
272
|
id: 'budget',
|
|
169
273
|
question: budgetQ.text,
|
|
170
|
-
options: budgetQ.options ?? [
|
|
171
|
-
{
|
|
172
|
-
label: '经济'
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
label: '舒适'
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
label: '便利优先'
|
|
179
|
-
}
|
|
180
|
-
]
|
|
274
|
+
options: budgetQ.options ?? [{ label: '经济' }, { label: '舒适' }, { label: '便利优先' }],
|
|
181
275
|
});
|
|
182
276
|
}
|
|
183
277
|
const parts = [];
|
|
184
|
-
if (conflicts.length)
|
|
278
|
+
if (conflicts.length)
|
|
279
|
+
parts.push(`⚠️ 日历冲突:\n${conflicts.map(c => `- ${c}`).join('\n')}`);
|
|
280
|
+
// D-7a 例外: blocking>0 时,用户消息含"查+地名/酒店/天气"信号时,直接调 anything_search
|
|
281
|
+
// 走 PoI 真相(datasources 层主动调,不动 polling 状态机,不改求解器)
|
|
185
282
|
const poiProbe = probePoi(userMsg);
|
|
186
283
|
if (poiProbe) {
|
|
187
|
-
const ar = await anythingSearch({
|
|
188
|
-
keyword: poiProbe
|
|
189
|
-
});
|
|
284
|
+
const ar = await anythingSearch({ keyword: poiProbe });
|
|
190
285
|
if (ar.verdict === 'hit' && ar.hits && ar.hits.length > 0) {
|
|
191
286
|
const top = ar.hits.slice(0, 5);
|
|
192
|
-
const lines = top.map((h, i)=>{
|
|
193
|
-
const latlng = h.latitude !== undefined && h.longitude !== undefined
|
|
287
|
+
const lines = top.map((h, i) => {
|
|
288
|
+
const latlng = h.latitude !== undefined && h.longitude !== undefined
|
|
289
|
+
? ` @ (${h.latitude.toFixed(3)},${h.longitude.toFixed(3)})`
|
|
290
|
+
: '';
|
|
194
291
|
return ` ${i + 1}. [${h.type}] ${h.name}${latlng}`;
|
|
195
292
|
}).join('\n');
|
|
196
293
|
parts.push(`**${poiProbe} → hit (${ar.hits.length} 候选项)**\n${lines}\n${ar.evidence}`);
|
|
197
|
-
}
|
|
294
|
+
}
|
|
295
|
+
else if (ar.verdict === 'miss') {
|
|
198
296
|
parts.push(`**${poiProbe} → miss** (酒店-be Anything 一切正常但无候选)\n${ar.evidence}`);
|
|
199
|
-
}
|
|
200
|
-
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
// 用户面只给人话原因 + 来源 tag:evidence 里的上游原话是溯源契约(能力层测试锁),
|
|
300
|
+
// 其中的进程噪音(如 `(exit null)`)不该渲染进回复。
|
|
301
|
+
const sourceTag = ar.evidence.match(/^\[[^\]]+\]/)?.[0];
|
|
302
|
+
parts.push(`**${poiProbe} → 实时查询不可用**(${ar.error ?? 'hbcli 不可达'})——这条不阻塞本轮规划,只影响实时数据源,其余结论照常带来源标注${sourceTag ? `\n${sourceTag}` : ''}`);
|
|
201
303
|
}
|
|
202
304
|
}
|
|
203
|
-
for (const q of blocking)
|
|
305
|
+
for (const q of blocking)
|
|
306
|
+
parts.push(await llm.polishQuestion(q));
|
|
307
|
+
// 约束齐备(无阻塞问题)→ 翻译 spec → **校验闸 + 日期一致性闸** → 求解 → 渲染
|
|
204
308
|
if (blocking.length === 0 && solve) {
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
309
|
+
const extractedSpec = await llm.extractSpec([...history, { role: 'user', text: userMsg }], state);
|
|
310
|
+
const planning = latestPlanningWindow(history, userMsg, anchor);
|
|
311
|
+
const planningCheck = extractedSpec ? applyPlanningWindow(extractedSpec, planning, anchor) : null;
|
|
312
|
+
if (planningCheck?.error) {
|
|
313
|
+
state.spec = undefined;
|
|
314
|
+
state.solve = undefined;
|
|
315
|
+
parts.push(`⚠️ ${planningCheck.error}`);
|
|
316
|
+
return { reply: parts.join('\n\n'), state };
|
|
317
|
+
}
|
|
318
|
+
if (planningCheck?.rejected.length) {
|
|
319
|
+
const rejected = planningCheck.rejected
|
|
320
|
+
.map(r => `${r.segmentId}/${r.optionId}(${r.date})`)
|
|
321
|
+
.join('、');
|
|
322
|
+
parts.push(`已排除规划窗口外的候选:${rejected}`);
|
|
323
|
+
}
|
|
324
|
+
const spec = planningCheck?.spec ?? extractedSpec;
|
|
325
|
+
// 场景路由:erhai 候选标记 → 候选求解(洱海金标准的引擎判定)——纯 TS unify 路径
|
|
212
326
|
if (spec && spec.note === 'erhai-candidates') {
|
|
213
327
|
const { readFile } = await import('node:fs/promises');
|
|
214
328
|
const { join } = await import('node:path');
|
|
@@ -222,102 +336,184 @@ export async function runTurn(state, userMsg, llm, history = [], solve = null) {
|
|
|
222
336
|
const result = solveChoiceSegment(erhaiSpec, req);
|
|
223
337
|
state.solve = result;
|
|
224
338
|
parts.push(result.answer_md ?? '(候选求解完成)');
|
|
225
|
-
}
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
226
341
|
parts.push('(洱海候选求解暂不可用——退回访谈)');
|
|
227
342
|
}
|
|
228
|
-
}
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
229
345
|
const invalid = spec ? validateSpec(spec) : '翻译器未产出 spec';
|
|
230
346
|
if (spec && !invalid) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
text: userMsg
|
|
236
|
-
}
|
|
237
|
-
]);
|
|
347
|
+
// D-10 切片 C:spec↔槽位日期一致性闸(ADR-10 翻译≠造数的执行点)。
|
|
348
|
+
// LLM 翻译的 spec 日期与代码层换算的槽位日期分歧时不求解、不猜,追问确认——
|
|
349
|
+
// 日期是求解关键输入,错日期 = 错判决。槽位缺失/unresolved 不参与(不造假阳性)。
|
|
350
|
+
const ext = await llm.extractSlots([...history, { role: 'user', text: userMsg }], now);
|
|
238
351
|
if (ext) {
|
|
239
352
|
const { resolveSlots, specDateMismatches } = await import('./slot-spec.js');
|
|
240
|
-
const
|
|
241
|
-
const mismatches = specDateMismatches(spec, resolveSlots(ext, buildTimeAnchor()));
|
|
353
|
+
const mismatches = specDateMismatches(spec, resolveSlots(ext, anchor));
|
|
242
354
|
if (mismatches.length > 0) {
|
|
243
|
-
const lines = mismatches.map(
|
|
355
|
+
const lines = mismatches.map(m => `- ${m.specAt}:翻译说 ${m.specDate},你的原话换算是 ${m.slotDate}(${m.field})`);
|
|
244
356
|
parts.push(`⚠️ 日期分歧,确认后我再算(以你为准):\n${lines.join('\n')}`);
|
|
245
|
-
return {
|
|
246
|
-
reply: parts.join('\n\n'),
|
|
247
|
-
state
|
|
248
|
-
};
|
|
357
|
+
return { reply: parts.join('\n\n'), state };
|
|
249
358
|
}
|
|
250
359
|
}
|
|
251
360
|
state.spec = spec;
|
|
252
361
|
state.solve = await solve(spec);
|
|
253
362
|
parts.push(llm.render ? await llm.render(state) : renderSolve(state));
|
|
254
|
-
}
|
|
363
|
+
}
|
|
364
|
+
else if (blocking.length === 0 && invalid) {
|
|
255
365
|
parts.push(`(行程骨架还不完整:${invalid}——请补充对应信息,我不猜)`);
|
|
256
366
|
}
|
|
257
367
|
}
|
|
258
|
-
}
|
|
368
|
+
}
|
|
369
|
+
else if (blocking.length === 0) {
|
|
259
370
|
parts.push('(约束齐备——进入规划,S3 接线后此处产出方案与选择题)');
|
|
260
371
|
}
|
|
261
|
-
return {
|
|
262
|
-
reply: parts.join('\n\n'),
|
|
263
|
-
state
|
|
264
|
-
};
|
|
372
|
+
return { reply: parts.join('\n\n'), state };
|
|
265
373
|
}
|
|
374
|
+
// ---- 异步工单持久化(S5 编排半段 → ADR-15 durable 工单):真正的「一小时后」必须跨进程存续 ----
|
|
375
|
+
// 权威 = 账本 workflow_runs/workflow_steps(单事务;崩溃后 done 步骤不重执行);
|
|
376
|
+
// {id}.json / {id}.deliverable.md 降级为视图(AGENTS.md 清扫合同 + 人工检视),
|
|
377
|
+
// tmp+rename 原子写——此前裸 writeFile 的非原子缺口(RFC §1.1)就此关闭。
|
|
266
378
|
import { join } from 'node:path';
|
|
267
|
-
import { mkdir } from 'node:fs/promises';
|
|
268
|
-
import {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
379
|
+
import { mkdir, rename, writeFile, readFile } from 'node:fs/promises';
|
|
380
|
+
import { ensureLedger, openLedgerIfExists } from './state-ledger.js';
|
|
381
|
+
async function asyncDir(stateRoot) {
|
|
382
|
+
const root = stateRoot === '.' ? process.cwd() : stateRoot;
|
|
383
|
+
const dir = join(root, 'gotry-state', 'async');
|
|
384
|
+
await mkdir(dir, { recursive: true });
|
|
385
|
+
return dir;
|
|
386
|
+
}
|
|
387
|
+
async function atomicWrite(path, text) {
|
|
388
|
+
const tmp = `${path}.tmp`;
|
|
389
|
+
await writeFile(tmp, text, 'utf-8');
|
|
390
|
+
await rename(tmp, path);
|
|
275
391
|
}
|
|
276
|
-
export async function persistAsyncTicket(ticket, state) {
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}, null, 2)
|
|
392
|
+
export async function persistAsyncTicket(ticket, state, stateRoot = '.') {
|
|
393
|
+
const ledger = ensureLedger(stateRoot);
|
|
394
|
+
ledger.createWorkflowRun({ id: ticket.id, goal: ticket.objective, ticket, state });
|
|
395
|
+
const dir = await asyncDir(stateRoot);
|
|
396
|
+
const p = join(dir, `${ticket.id}.json`);
|
|
397
|
+
await atomicWrite(p, JSON.stringify({ ticket, state }, null, 2));
|
|
282
398
|
return p;
|
|
283
399
|
}
|
|
284
|
-
export async function loadAsyncTicket(ticketId) {
|
|
400
|
+
export async function loadAsyncTicket(ticketId, stateRoot = '.') {
|
|
401
|
+
// 账本优先;无账本的 root 回退旧 json 文件(只读,兼容存量已交付工单)
|
|
402
|
+
const ledger = openLedgerIfExists(stateRoot);
|
|
403
|
+
const run = ledger?.getWorkflowRun(ticketId);
|
|
404
|
+
if (run) {
|
|
405
|
+
return {
|
|
406
|
+
ticket: JSON.parse(run.ticket_json),
|
|
407
|
+
state: JSON.parse(run.state_json),
|
|
408
|
+
};
|
|
409
|
+
}
|
|
285
410
|
try {
|
|
286
|
-
const p = await
|
|
411
|
+
const p = join(await asyncDir(stateRoot), `${ticketId}.json`);
|
|
287
412
|
return JSON.parse(await readFile(p, 'utf-8'));
|
|
288
|
-
}
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
289
415
|
return null;
|
|
290
416
|
}
|
|
291
417
|
}
|
|
292
|
-
export async function settleAsyncTicket(ticketId, reply) {
|
|
293
|
-
const
|
|
294
|
-
|
|
418
|
+
export async function settleAsyncTicket(ticketId, reply, stateRoot = '.', outcome) {
|
|
419
|
+
const ledger = openLedgerIfExists(stateRoot);
|
|
420
|
+
const terminalOutcome = outcome ?? recoverAsyncTerminalOutcome(ledger, ticketId);
|
|
421
|
+
if (ledger && !terminalOutcome) {
|
|
422
|
+
throw new Error(`workflow ${ticketId} 缺少可恢复的 ${ASYNC_TERMINAL_SCHEMA},拒绝误结算`);
|
|
423
|
+
}
|
|
424
|
+
if (terminalOutcome?.status === 'failed')
|
|
425
|
+
ledger?.failWorkflowRun(ticketId, reply, terminalOutcome);
|
|
426
|
+
else
|
|
427
|
+
ledger?.settleWorkflowRun(ticketId, reply, terminalOutcome);
|
|
428
|
+
const dir = await asyncDir(stateRoot);
|
|
429
|
+
const p = join(dir, `${ticketId}.deliverable.md`);
|
|
430
|
+
await atomicWrite(p, reply);
|
|
295
431
|
return p;
|
|
296
432
|
}
|
|
433
|
+
function recoverAsyncTerminalOutcome(ledger, ticketId) {
|
|
434
|
+
if (!ledger)
|
|
435
|
+
return undefined;
|
|
436
|
+
const run = ledger.getWorkflowRun(ticketId);
|
|
437
|
+
if (!run)
|
|
438
|
+
return undefined;
|
|
439
|
+
try {
|
|
440
|
+
const state = JSON.parse(run.state_json);
|
|
441
|
+
if (!state.spec)
|
|
442
|
+
return terminalOutcomeFromState(ticketId, state);
|
|
443
|
+
const solveStep = ledger.getWorkflowStep(ticketId, 'solve');
|
|
444
|
+
if (solveStep?.status !== 'done' || !solveStep.result)
|
|
445
|
+
return undefined;
|
|
446
|
+
state.solve = JSON.parse(solveStep.result);
|
|
447
|
+
state.gates = state.gates.filter(g => !g.id.startsWith('async-'));
|
|
448
|
+
return terminalOutcomeFromState(ticketId, state);
|
|
449
|
+
}
|
|
450
|
+
catch {
|
|
451
|
+
return undefined;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* 可日志化 solve 端口(ADR-15 步骤日志,intent-before-execute):
|
|
456
|
+
* 先记 intent 再执行,done 后结果落账本——任意进程恢复时 done 的步骤直接复用
|
|
457
|
+
* 结果不重执行(exactly-once:LLM/求解调用不重复花钱),intent 悬挂的重试。
|
|
458
|
+
*/
|
|
459
|
+
export function makeJournaledSolvePort(ledger, runId, solve, opts) {
|
|
460
|
+
return async (spec) => {
|
|
461
|
+
const step = ledger.getWorkflowStep(runId, 'solve');
|
|
462
|
+
if (step?.status === 'done' && step.result) {
|
|
463
|
+
return JSON.parse(step.result);
|
|
464
|
+
}
|
|
465
|
+
ledger.markStepIntent(runId, 'solve');
|
|
466
|
+
opts?.onRealSolve?.();
|
|
467
|
+
const r = await solve(spec);
|
|
468
|
+
ledger.markStepDone(runId, 'solve', r);
|
|
469
|
+
return r;
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* probePoi:从 user msg 探测"查 POI/酒店" 信号,返回关键词。
|
|
474
|
+
* 触发的不是关键词,是**结构**;关键词抓取有方向性——
|
|
475
|
+
* 1) 显式搜索动词(查/搜/找/看看/推荐/告诉我/检索)+ 宾语在动词后;
|
|
476
|
+
* 2) 住宿名词(酒店/民宿/客栈/饭店):优先取名词**之后**的名称段(须含拉丁/数字,
|
|
477
|
+
* 「我订了酒店:The Title…」→ The Title…);退路是名词前 2-6 字紧邻地名
|
|
478
|
+
* (「大理酒店」→ 大理;「机票和」类垃圾后缀拒);
|
|
479
|
+
* 3) 开放问(有什么/玩什么/有哪些):取名词前的地名;
|
|
480
|
+
* 4) 短裸地名:≤12 字、无标点、无陈述动词(「大理」✓;「明天有空」「我的工作时间是…」✗——
|
|
481
|
+
* 2026-08-28 巡检收紧:旧版 ≤24 直通把访谈答案整句当关键词,垃圾 hbcli 调用+证据噪音)。
|
|
482
|
+
* 不是意图(改求解器),只是 datasources 编排层的"提早调 anything"提示。
|
|
483
|
+
*/
|
|
484
|
+
/** 住宿名称段上界:路径 2 已要求含拉丁/数字且被标点截断,旧 24 字会把
|
|
485
|
+
* 「The Title East Wing Rawai」这类真实酒店名截残后回显给用户(2026-09-22)。 */
|
|
486
|
+
const POI_NAME_MAX = 48;
|
|
297
487
|
export function probePoi(msg) {
|
|
298
488
|
const trimmed = msg.trim();
|
|
299
|
-
if (!trimmed)
|
|
300
|
-
|
|
489
|
+
if (!trimmed)
|
|
490
|
+
return null;
|
|
491
|
+
const cutAtPunct = (s) => s.split(/[,,。.;;!!??]/)[0]?.trim() ?? '';
|
|
492
|
+
// 1) 显式搜索动词 + 宾语
|
|
301
493
|
const m = trimmed.match(/(查一下|查|搜|找|看看|推荐|告诉我|检索)\s*(.{2,24})/);
|
|
302
494
|
if (m?.[2]) {
|
|
303
495
|
const obj = cutAtPunct(m[2]);
|
|
304
|
-
if (obj.length >= 2)
|
|
496
|
+
if (obj.length >= 2)
|
|
497
|
+
return obj.slice(0, 24);
|
|
305
498
|
}
|
|
499
|
+
// 2) 住宿名词:名称段在名词后
|
|
306
500
|
if (/(酒店|民宿|客栈|饭店)/.test(trimmed)) {
|
|
307
501
|
const parts = trimmed.split(/(酒店|民宿|客栈|饭店)/);
|
|
308
502
|
const after = cutAtPunct((parts[2] ?? '').replace(/^[的::\s]+/, ''));
|
|
309
|
-
if (after.length >= 2 && /[A-Za-z0-9]/.test(after))
|
|
503
|
+
if (after.length >= 2 && /[A-Za-z0-9]/.test(after))
|
|
504
|
+
return after.length > POI_NAME_MAX ? `${after.slice(0, POI_NAME_MAX - 1)}…` : after;
|
|
310
505
|
const nounAt = trimmed.search(/(酒店|民宿|客栈|饭店)/);
|
|
311
506
|
const pre = trimmed.slice(Math.max(0, nounAt - 6), nounAt).match(/[一-龥]{2,6}$/);
|
|
312
|
-
if (pre && !/(机票|车票|和|做|订|的)$/.test(pre[0]))
|
|
507
|
+
if (pre && !/(机票|车票|和|做|订|的)$/.test(pre[0]))
|
|
508
|
+
return pre[0];
|
|
313
509
|
}
|
|
510
|
+
// 3) 开放问:地名在疑问词前
|
|
314
511
|
const q = trimmed.match(/([一-龥a-zA-Z]{2,12})\s*(?:有什么|玩什么|有哪些)/);
|
|
315
|
-
if (q?.[1])
|
|
512
|
+
if (q?.[1])
|
|
513
|
+
return q[1];
|
|
514
|
+
// 4) 短裸地名(≤12 字,无标点,无陈述动词)
|
|
316
515
|
if (trimmed.length <= 12 && !/[,,。.;;!!??::]/.test(trimmed) && !/[是有在要想得到说订吧呢]/.test(trimmed)) {
|
|
317
516
|
return trimmed.slice(0, 24);
|
|
318
517
|
}
|
|
319
518
|
return null;
|
|
320
519
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
//# sourceURL=/Users/bytedance/work/gotry/ts/src/loop.ts
|