@danceiny/gotry 0.0.1-rc.9 → 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 -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 +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 -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 +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 +947 -110
- 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 +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-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 +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 +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 +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 +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 +382 -246
- package/dist/scripts/ledger-workflow-crash.js +10 -20
- 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 +161 -0
- package/dist/scripts/nightly-evidence.js +286 -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/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 +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-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 +690 -246
- 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 +226 -101
- package/dist/scripts/state-cli.js +550 -199
- 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 +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 +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 +48 -74
- 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 +2227 -882
- 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 +319 -160
- 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/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 +435 -516
- 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 +535 -359
- 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 +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 +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 +1948 -198
- 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 +223 -25
- 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 +354 -88
- package/ts/src/wish-pool.ts +79 -0
- package/dist/scripts/session-attach-wait.js +0 -41
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prevent a continuable subagent durable id from entering the jobs tool family.
|
|
3
|
+
*
|
|
4
|
+
* dsh deliberately keeps continuable children out of the jobs registry. The
|
|
5
|
+
* jobs tools therefore cannot distinguish a mistaken durable child id from any
|
|
6
|
+
* other unknown id once their body runs. GoTry owns the surrounding plugin and
|
|
7
|
+
* can use dsh's typed pre-execute waterfall to give the model a recoverable,
|
|
8
|
+
* actionable error before the jobs registry is consulted.
|
|
9
|
+
*/
|
|
10
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
11
|
+
import type { Agent } from '@deepseek-ai/dsh-agent'
|
|
12
|
+
import type { SessionId } from '@deepseek-ai/dsh-session'
|
|
13
|
+
import type { PreToolDecision, ToolExecution } from '@deepseek-ai/dsh-tools'
|
|
14
|
+
import type { SubagentCatalogEntry, SubagentRuntime } from '@deepseek-ai/dsh-subagent'
|
|
15
|
+
|
|
16
|
+
const JOB_TOOLS = new Set(['job_output', 'job_kill'])
|
|
17
|
+
|
|
18
|
+
function subagentsOf(ctx: Context): SubagentRuntime | undefined {
|
|
19
|
+
try {
|
|
20
|
+
return (ctx as Context & { subagents?: SubagentRuntime }).subagents
|
|
21
|
+
} catch {
|
|
22
|
+
// Minimal hosts and benchmark contexts may not mount the optional service.
|
|
23
|
+
return undefined
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function jobIdOf(exec: ToolExecution): string | undefined {
|
|
28
|
+
if (!exec.arguments || typeof exec.arguments !== 'object') return undefined
|
|
29
|
+
const jobId = (exec.arguments as Record<string, unknown>).job_id
|
|
30
|
+
return typeof jobId === 'string' && jobId.length > 0 ? jobId : undefined
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isContinuableChild(entry: SubagentCatalogEntry, jobId: string): boolean {
|
|
34
|
+
return entry.mode === 'continuable' && entry.id === jobId
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function recoveryReason(toolName: string, jobId: string): string {
|
|
38
|
+
const stopHint = toolName === 'job_kill'
|
|
39
|
+
? '; use interrupt_agent to stop its current turn.'
|
|
40
|
+
: '.'
|
|
41
|
+
return [
|
|
42
|
+
`SUBAGENT_ID_IS_NOT_JOB_ID: ${JSON.stringify(jobId)} is a continuable subagent durable id, not a background job id.`,
|
|
43
|
+
'Its completion arrives as a completion notice; use list_agents to inspect it and send_message to continue it',
|
|
44
|
+
stopHint,
|
|
45
|
+
].join(' ')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Install the GoTry-owned safety net around dsh's jobs tools. */
|
|
49
|
+
export function installSubagentJobIdGuard(ctx: Context): void {
|
|
50
|
+
const ctxOn = (ctx as unknown as { on?: typeof ctx.on }).on
|
|
51
|
+
if (typeof ctxOn !== 'function') return
|
|
52
|
+
ctx.on('tools/pre-execute', async (exec, next): Promise<PreToolDecision> => {
|
|
53
|
+
if (!JOB_TOOLS.has(exec.name)) return next()
|
|
54
|
+
const jobId = jobIdOf(exec)
|
|
55
|
+
const agent = exec.agent as Agent | undefined
|
|
56
|
+
const subagents = subagentsOf(ctx)
|
|
57
|
+
if (!jobId || !agent || !subagents) return next()
|
|
58
|
+
|
|
59
|
+
let children: SubagentCatalogEntry[]
|
|
60
|
+
try {
|
|
61
|
+
children = await subagents.listChildren(agent.id as SessionId, exec.signal)
|
|
62
|
+
} catch (error) {
|
|
63
|
+
// The guard is diagnostic, not an alternate ownership or availability
|
|
64
|
+
// path. Preserve cancellation; otherwise retain dsh's native job error.
|
|
65
|
+
if (exec.signal.aborted) throw error
|
|
66
|
+
return next()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!children.some(entry => isContinuableChild(entry, jobId))) return next()
|
|
70
|
+
return { kind: 'deny', reason: recoveryReason(exec.name, jobId) }
|
|
71
|
+
}, { prepend: true })
|
|
72
|
+
}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 时间锚点层(确定性纯函数,零依赖):「今天是哪天、相对日期怎么换算」的算术全部在这里,
|
|
3
|
+
* LLM 只查锚点卡不自算(仓规:算术只在代码层;tool-owned dates 的执行面)。
|
|
4
|
+
*
|
|
5
|
+
* 消费面:
|
|
6
|
+
* - dsh 成品路径:index.ts 注册 {{time_anchor_card}} 变量,系统时钟;
|
|
7
|
+
* - legacy 抽取路径:dsh-llm.ts 注入 FACTS/SKELETON/槽位抽取 prompt;
|
|
8
|
+
* - 评测:time-eval-tests.ts 用固定 now(2026-08-27)保证确定性。
|
|
9
|
+
*
|
|
10
|
+
* 节日锚点表 SPRING_FESTIVAL:由构建期生成器机械生成(issue #274 清偿 D-9 手抄债务,覆盖 2026-2099);
|
|
11
|
+
* 扩表/换库 = 重跑 ts/scripts/gen-lunar-anchors.ts(--check 为漂移闸,run-all §58)。
|
|
12
|
+
* 到期即红守卫 springFestivalHorizonOk:最晚锚点年份 < 当前年+3 时测试红;表耗尽后锚点卡
|
|
13
|
+
* 显式告警(不再静默省略)——「换个日子的同款债务」的静默耗尽模式已消灭。
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export interface TimeAnchor {
|
|
17
|
+
/** 今天 YYYY-MM-DD(宿主机本地时区) */
|
|
18
|
+
today: string
|
|
19
|
+
/** 今天星期几,如「周四」 */
|
|
20
|
+
todayWeekdayZh: string
|
|
21
|
+
/** 时区标注,固定为 UTC±HH:MM,如 UTC+08:00 / UTC+05:30 */
|
|
22
|
+
tzLabel: string
|
|
23
|
+
/** 注入 prompt 的多行锚点卡文本 */
|
|
24
|
+
card: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type PlanningDateIntent = 'future' | 'historical'
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Named-year planning context. It is derived per turn from the current
|
|
31
|
+
* TimeAnchor; it is deliberately not part of TripState so a later turn cannot
|
|
32
|
+
* inherit a stale planning reference date.
|
|
33
|
+
*/
|
|
34
|
+
export interface PlanningWindow {
|
|
35
|
+
referenceDate: string
|
|
36
|
+
requestedYear: number
|
|
37
|
+
intent: PlanningDateIntent
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface PlanningWindowBounds {
|
|
41
|
+
start: string
|
|
42
|
+
end: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const WEEKDAYS_ZH = ['日', '一', '二', '三', '四', '五', '六'] as const
|
|
46
|
+
|
|
47
|
+
export function ymd(d: Date): string {
|
|
48
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function addDays(d: Date, n: number): Date {
|
|
52
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate() + n)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** ISO 周周一:getDay() 周日=0 归到上周一(-6) */
|
|
56
|
+
function weekMonday(d: Date): Date {
|
|
57
|
+
return addDays(d, -((d.getDay() + 6) % 7))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 春节锚点表(正月初一;仅此节日漂移大,故表驱动;元旦/国庆固定月日按「下一次发生」算)。
|
|
62
|
+
* 本块由构建期生成器机械生成,禁止手改(issue #274:手抄常量表=换个日子的同款债务,已否决)。
|
|
63
|
+
* provenance:lunar-typescript@1.8.6(MIT,零传递依赖,devDependency 不进 runtime)· 生成时间 2026-09-11T17:19:45.752Z
|
|
64
|
+
* 命令:cd ts && npx tsx scripts/gen-lunar-anchors.ts(扩表/换库=重跑;--check=漂移闸,run-all §58)
|
|
65
|
+
* 交叉验证:2026-2031 旧表 6 条 + 港天文台 2032-2040 核实 9 条逐条一致(time-eval §7 双 oracle)。
|
|
66
|
+
* 到期守卫:springFestivalHorizonOk——最晚锚点年份 < 当前年+3 测试即红(临近耗尽先红于静默缺失)。
|
|
67
|
+
*/
|
|
68
|
+
// [gen:lunar-anchors:begin] 生成块起点——手改会被下次生成覆盖
|
|
69
|
+
export const SPRING_FESTIVAL: Record<number, string> = {
|
|
70
|
+
2026: '2026-02-17',
|
|
71
|
+
2027: '2027-02-06',
|
|
72
|
+
2028: '2028-01-26',
|
|
73
|
+
2029: '2029-02-13',
|
|
74
|
+
2030: '2030-02-03',
|
|
75
|
+
2031: '2031-01-23',
|
|
76
|
+
2032: '2032-02-11',
|
|
77
|
+
2033: '2033-01-31',
|
|
78
|
+
2034: '2034-02-19',
|
|
79
|
+
2035: '2035-02-08',
|
|
80
|
+
2036: '2036-01-28',
|
|
81
|
+
2037: '2037-02-15',
|
|
82
|
+
2038: '2038-02-04',
|
|
83
|
+
2039: '2039-01-24',
|
|
84
|
+
2040: '2040-02-12',
|
|
85
|
+
2041: '2041-02-01',
|
|
86
|
+
2042: '2042-01-22',
|
|
87
|
+
2043: '2043-02-10',
|
|
88
|
+
2044: '2044-01-30',
|
|
89
|
+
2045: '2045-02-17',
|
|
90
|
+
2046: '2046-02-06',
|
|
91
|
+
2047: '2047-01-26',
|
|
92
|
+
2048: '2048-02-14',
|
|
93
|
+
2049: '2049-02-02',
|
|
94
|
+
2050: '2050-01-23',
|
|
95
|
+
2051: '2051-02-11',
|
|
96
|
+
2052: '2052-02-01',
|
|
97
|
+
2053: '2053-02-19',
|
|
98
|
+
2054: '2054-02-08',
|
|
99
|
+
2055: '2055-01-28',
|
|
100
|
+
2056: '2056-02-15',
|
|
101
|
+
2057: '2057-02-04',
|
|
102
|
+
2058: '2058-01-24',
|
|
103
|
+
2059: '2059-02-12',
|
|
104
|
+
2060: '2060-02-02',
|
|
105
|
+
2061: '2061-01-21',
|
|
106
|
+
2062: '2062-02-09',
|
|
107
|
+
2063: '2063-01-29',
|
|
108
|
+
2064: '2064-02-17',
|
|
109
|
+
2065: '2065-02-05',
|
|
110
|
+
2066: '2066-01-26',
|
|
111
|
+
2067: '2067-02-14',
|
|
112
|
+
2068: '2068-02-03',
|
|
113
|
+
2069: '2069-01-23',
|
|
114
|
+
2070: '2070-02-11',
|
|
115
|
+
2071: '2071-01-31',
|
|
116
|
+
2072: '2072-02-19',
|
|
117
|
+
2073: '2073-02-07',
|
|
118
|
+
2074: '2074-01-27',
|
|
119
|
+
2075: '2075-02-15',
|
|
120
|
+
2076: '2076-02-05',
|
|
121
|
+
2077: '2077-01-24',
|
|
122
|
+
2078: '2078-02-12',
|
|
123
|
+
2079: '2079-02-02',
|
|
124
|
+
2080: '2080-01-22',
|
|
125
|
+
2081: '2081-02-09',
|
|
126
|
+
2082: '2082-01-29',
|
|
127
|
+
2083: '2083-02-17',
|
|
128
|
+
2084: '2084-02-06',
|
|
129
|
+
2085: '2085-01-26',
|
|
130
|
+
2086: '2086-02-14',
|
|
131
|
+
2087: '2087-02-03',
|
|
132
|
+
2088: '2088-01-24',
|
|
133
|
+
2089: '2089-02-10',
|
|
134
|
+
2090: '2090-01-30',
|
|
135
|
+
2091: '2091-02-18',
|
|
136
|
+
2092: '2092-02-07',
|
|
137
|
+
2093: '2093-01-27',
|
|
138
|
+
2094: '2094-02-15',
|
|
139
|
+
2095: '2095-02-05',
|
|
140
|
+
2096: '2096-01-25',
|
|
141
|
+
2097: '2097-02-12',
|
|
142
|
+
2098: '2098-02-01',
|
|
143
|
+
2099: '2099-01-21',
|
|
144
|
+
}
|
|
145
|
+
// [gen:lunar-anchors:end]
|
|
146
|
+
|
|
147
|
+
/** 到期即红守卫阈值(issue #274):最晚春节锚点年份必须 ≥ 当前年+3——临近耗尽先红于静默缺失。 */
|
|
148
|
+
export const SPRING_FESTIVAL_HORIZON_MIN_YEARS = 3
|
|
149
|
+
|
|
150
|
+
/** 表内最晚锚点年份距 now 的年数(守卫与 time-eval §7 共用;旧表「牙齿证明」传表参)。 */
|
|
151
|
+
export function springFestivalHorizonYears(table: Record<number, string>, now: Date = new Date()): number {
|
|
152
|
+
return Math.max(...Object.keys(table).map(Number)) - now.getFullYear()
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** D-9 到期即红守卫:最晚锚点年份 < 当前年+3 → 测试红(而非春节锚点静默缺失)。 */
|
|
156
|
+
export function springFestivalHorizonOk(now: Date = new Date()): boolean {
|
|
157
|
+
return springFestivalHorizonYears(SPRING_FESTIVAL, now) >= SPRING_FESTIVAL_HORIZON_MIN_YEARS
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function formatUtcOffsetLabel(utcOffsetMinutes: number): string {
|
|
161
|
+
const sign = utcOffsetMinutes >= 0 ? '+' : '-'
|
|
162
|
+
const abs = Math.abs(utcOffsetMinutes)
|
|
163
|
+
const h = Math.floor(abs / 60)
|
|
164
|
+
const m = abs % 60
|
|
165
|
+
return `UTC${sign}${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function tzLabelOf(d: Date): string {
|
|
169
|
+
return formatUtcOffsetLabel(-d.getTimezoneOffset())
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function weekdayOf(d: Date): string {
|
|
173
|
+
return `周${WEEKDAYS_ZH[d.getDay()]}`
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** 一周七天的渲染:周一 2026-08-31|周二 …|周日 … */
|
|
177
|
+
function weekRow(label: string, monday: Date): string {
|
|
178
|
+
const days = Array.from({ length: 7 }, (_, i) => {
|
|
179
|
+
const d = addDays(monday, i)
|
|
180
|
+
return `${weekdayOf(d)} ${ymd(d)}`
|
|
181
|
+
})
|
|
182
|
+
return `${label}:${days.join('|')}`
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** 固定月日节日的下一次发生(已过则取明年) */
|
|
186
|
+
function nextOccurrence(todayYmd: string, year: number, monthDay: string): string {
|
|
187
|
+
const thisYear = `${year}-${monthDay}`
|
|
188
|
+
return thisYear >= todayYmd ? thisYear : `${year + 1}-${monthDay}`
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function buildTimeAnchor(now: Date = new Date()): TimeAnchor {
|
|
192
|
+
const today = ymd(now)
|
|
193
|
+
const year = now.getFullYear()
|
|
194
|
+
const monday = weekMonday(now)
|
|
195
|
+
|
|
196
|
+
const tomorrow = addDays(now, 1)
|
|
197
|
+
const dayAfter = addDays(now, 2)
|
|
198
|
+
const inThreeDays = addDays(now, 3)
|
|
199
|
+
|
|
200
|
+
// 下个月:初(1-10)/中旬(11-20)/下旬(21-月末)
|
|
201
|
+
const nm = new Date(year, now.getMonth() + 1, 1)
|
|
202
|
+
const nmYear = nm.getFullYear()
|
|
203
|
+
const nmMonth = nm.getMonth()
|
|
204
|
+
const nmLastDay = new Date(nmYear, nmMonth + 1, 0).getDate()
|
|
205
|
+
const mm = String(nmMonth + 1).padStart(2, '0')
|
|
206
|
+
|
|
207
|
+
// 下个季度初
|
|
208
|
+
const nextQuarterMonth0 = Math.floor(now.getMonth() / 3) * 3 + 3
|
|
209
|
+
const nq = new Date(nextQuarterMonth0 >= 12 ? year + 1 : year, nextQuarterMonth0 % 12, 1)
|
|
210
|
+
|
|
211
|
+
const festivals: string[] = [
|
|
212
|
+
`国庆 ${nextOccurrence(today, year, '10-01')}`,
|
|
213
|
+
`元旦 ${nextOccurrence(today, year, '01-01')}`,
|
|
214
|
+
]
|
|
215
|
+
const spring = Object.values(SPRING_FESTIVAL).filter(d => d >= today).sort()[0]
|
|
216
|
+
if (spring) festivals.push(`春节 ${spring}`)
|
|
217
|
+
else festivals.push('春节(锚点表已到期:重跑 ts/scripts/gen-lunar-anchors.ts 扩表,勿静默省略)')
|
|
218
|
+
|
|
219
|
+
const card = [
|
|
220
|
+
`今天 ${today} ${weekdayOf(now)}(时区 ${tzLabelOf(now)})`,
|
|
221
|
+
`明天 ${ymd(tomorrow)} ${weekdayOf(tomorrow)}|后天 ${ymd(dayAfter)} ${weekdayOf(dayAfter)}|大后天 ${ymd(inThreeDays)} ${weekdayOf(inThreeDays)}`,
|
|
222
|
+
weekRow('本周', monday),
|
|
223
|
+
weekRow('下周', addDays(monday, 7)),
|
|
224
|
+
weekRow('下下周', addDays(monday, 14)),
|
|
225
|
+
`下个月 ${nmYear}-${mm}:初 ${mm}-01~${mm}-10|中旬 ${mm}-11~${mm}-20|下旬 ${mm}-21~${mm}-${nmLastDay}`,
|
|
226
|
+
`下个季度初:${ymd(nq)} 起`,
|
|
227
|
+
`节日锚点:${festivals.join('|')}(「国庆前」= 该日之前,以此类推)`,
|
|
228
|
+
].join('\n')
|
|
229
|
+
|
|
230
|
+
return { today, todayWeekdayZh: weekdayOf(now), tzLabel: tzLabelOf(now), card }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Extract the smallest named-year intent needed by the planning guard.
|
|
235
|
+
* Relative future years (今年/明年/后年/年内) resolve against the current
|
|
236
|
+
* TimeAnchor, so a future-tense phrase without a four-digit year still yields
|
|
237
|
+
* a named-year window. Historical bypass is intentionally narrow: a negated
|
|
238
|
+
* warning about past dates is not historical lookup, and multiple eligible
|
|
239
|
+
* years are ambiguous. Same-year restatements (「今年年内」「2026 年内」) are
|
|
240
|
+
* one window, not a conflict.
|
|
241
|
+
*/
|
|
242
|
+
export function parsePlanningWindow(text: string, anchor: TimeAnchor): PlanningWindow | null {
|
|
243
|
+
const historical = /(?:回测|复盘|backtest|historical)|(?:历史|过去).{0,8}(?:查询|查|检索|回看|回测|复盘)|(?:查询|查|检索|回看).{0,8}(?:历史|过去)/i.test(text)
|
|
244
|
+
const anchorYear = Number(anchor.today.slice(0, 4))
|
|
245
|
+
const relativeYear = (token: string): number =>
|
|
246
|
+
token === '今年' ? anchorYear : token === '明年' ? anchorYear + 1 : anchorYear + 2
|
|
247
|
+
const matches: Array<{ year: number; start: number; end: number }> = []
|
|
248
|
+
for (const m of text.matchAll(/(?<!\d)(\d{4})\s*年/g)) {
|
|
249
|
+
const start = m.index ?? 0
|
|
250
|
+
matches.push({ year: Number(m[1]), start, end: start + m[0].length })
|
|
251
|
+
}
|
|
252
|
+
for (const m of text.matchAll(/\b(?:in|within|by)\s+(\d{4})\b/gi)) {
|
|
253
|
+
const start = m.index ?? 0
|
|
254
|
+
matches.push({ year: Number(m[1]), start, end: start + m[0].length })
|
|
255
|
+
}
|
|
256
|
+
for (const m of text.matchAll(/今年|明年|后年/g)) {
|
|
257
|
+
const start = m.index ?? 0
|
|
258
|
+
matches.push({ year: relativeYear(m[0]), start, end: start + m[0].length })
|
|
259
|
+
}
|
|
260
|
+
for (const m of text.matchAll(/年内/g)) {
|
|
261
|
+
const start = m.index ?? 0
|
|
262
|
+
// 「明年年内」「2025 年内」继承紧邻前缀的年份(「年」可已被年份 token 消费);裸「年内」= 锚点当前年
|
|
263
|
+
const adjacent = text.slice(0, start).match(/(今年|明年|后年|\d{4})\s*年?\s*$/)
|
|
264
|
+
matches.push({ year: adjacent ? (/^\d{4}$/.test(adjacent[1]!) ? Number(adjacent[1]) : relativeYear(adjacent[1]!)) : anchorYear, start, end: start + m[0].length })
|
|
265
|
+
}
|
|
266
|
+
if (matches.some(m => !Number.isInteger(m.year) || m.year < 1_000 || m.year > 9_999)) return null
|
|
267
|
+
const distinct = [...new Map(matches.map(m => [m.year, m])).values()]
|
|
268
|
+
if (historical && distinct.length !== 1) return null
|
|
269
|
+
|
|
270
|
+
const planningCue = /计划|规划|安排|打算|希望|想在|要在|完成|出行|旅行|预订|预定/i
|
|
271
|
+
const eligibleYears = new Set(
|
|
272
|
+
matches
|
|
273
|
+
.filter(m => {
|
|
274
|
+
const before = text.slice(Math.max(0, m.start - 24), m.start)
|
|
275
|
+
const after = text.slice(m.end, m.end + 24)
|
|
276
|
+
return planningCue.test(before) || /^\s*(?:内|以内|完成|出行|旅行|预订|预定)/i.test(after)
|
|
277
|
+
})
|
|
278
|
+
.map(m => m.year),
|
|
279
|
+
)
|
|
280
|
+
const selectedYear = eligibleYears.size === 1 ? [...eligibleYears][0]!
|
|
281
|
+
: (historical && distinct.length === 1 ? distinct[0]!.year : null)
|
|
282
|
+
if (selectedYear === null) return null
|
|
283
|
+
return { referenceDate: anchor.today, requestedYear: selectedYear, intent: historical ? 'historical' : 'future' }
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export function planningWindowBounds(window: PlanningWindow, anchor: TimeAnchor): PlanningWindowBounds | null {
|
|
287
|
+
if (window.intent === 'historical') return null
|
|
288
|
+
const currentYear = Number(anchor.today.slice(0, 4))
|
|
289
|
+
if (window.requestedYear < currentYear) return null
|
|
290
|
+
const year = String(window.requestedYear).padStart(4, '0')
|
|
291
|
+
return {
|
|
292
|
+
start: window.requestedYear === currentYear ? anchor.today : `${year}-01-01`,
|
|
293
|
+
end: `${year}-12-31`,
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** 严格 ISO 校验:YYYY-MM-DD 必须落在真实日历(2026-02-30/2026-13-01 一律拒)。
|
|
298
|
+
* 复用 Date 月末自动进位:同年/月/day 还原回同一串 = 真日历;否则越界。
|
|
299
|
+
* 同时拒掉非有限值(NaN/Infinity)与越界月日(1-12/1-31)。
|
|
300
|
+
* 供 parseAbsoluteDate 词表口径 + hotel-date-gate 终消费层 复用。 */
|
|
301
|
+
export function isRealIsoDate(y: number, m: number, d: number): boolean {
|
|
302
|
+
if (!Number.isFinite(y) || !Number.isFinite(m) || !Number.isFinite(d)) return false
|
|
303
|
+
if (m < 1 || m > 12) return false
|
|
304
|
+
if (d < 1 || d > 31) return false
|
|
305
|
+
const dt = new Date(y, m - 1, d)
|
|
306
|
+
return dt.getFullYear() === y && dt.getMonth() === m - 1 && dt.getDate() === d
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* 绝对月日表达 → YYYY-MM-DD(年缺省时按锚点年)。只识别**绝对**表达:
|
|
311
|
+
* ISO(2026-08-01)、数字点分(8.1 / 9.10)、中文(8月5日 / 8月5号)。
|
|
312
|
+
* 严格校验真日历存在性:2026-02-30 / 2026-13-01 / 2025-02-29 等一律返回 null——
|
|
313
|
+
* 词表外不一致日期不冒充合法,闸会归 unresolved 拒绝发供应商查询(issue #283 红线)。
|
|
314
|
+
* 相对/模糊表达(下周一/明天/本周三/下个月中旬/近期/Aug-5 英文月名)一律返回 null——
|
|
315
|
+
* 逐字保留给下游,本层不做换算也不做过期判定(与评测 golden 对齐:英文月日不判过期)。
|
|
316
|
+
*/
|
|
317
|
+
export function parseAbsoluteDate(expr: string, anchorYear: number): string | null {
|
|
318
|
+
const t = expr.trim()
|
|
319
|
+
let m = t.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/)
|
|
320
|
+
if (m) {
|
|
321
|
+
const y = Number(m[1]); const mo = Number(m[2]); const d = Number(m[3])
|
|
322
|
+
if (!isRealIsoDate(y, mo, d)) return null
|
|
323
|
+
return `${m[1]}-${m[2].padStart(2, '0')}-${m[3].padStart(2, '0')}`
|
|
324
|
+
}
|
|
325
|
+
m = t.match(/^(\d{1,2})[./](\d{1,2})(?:日|号)?$/)
|
|
326
|
+
if (m) {
|
|
327
|
+
const mo = Number(m[1]); const d = Number(m[2])
|
|
328
|
+
if (!isRealIsoDate(anchorYear, mo, d)) return null
|
|
329
|
+
return `${anchorYear}-${m[1].padStart(2, '0')}-${m[2].padStart(2, '0')}`
|
|
330
|
+
}
|
|
331
|
+
m = t.match(/^(\d{1,2})月(\d{1,2})[日号]?$/)
|
|
332
|
+
if (m) {
|
|
333
|
+
const mo = Number(m[1]); const d = Number(m[2])
|
|
334
|
+
if (!isRealIsoDate(anchorYear, mo, d)) return null
|
|
335
|
+
return `${anchorYear}-${m[1].padStart(2, '0')}-${m[2].padStart(2, '0')}`
|
|
336
|
+
}
|
|
337
|
+
return null
|
|
338
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 工具调用 packet 纪律(RFC S1,loopx agent-loop-effect-interpreter 映射):
|
|
3
|
+
* 每次工具交互 = effect_request(args) → interpretation(interpretArgs)→ observation(返回值)。
|
|
4
|
+
*
|
|
5
|
+
* envelope 是**平铺**的(house style,与 guardToolExecute 兜底同形):
|
|
6
|
+
* - 成功:{ ok: true, ...payload } —— 渲染/调用方按字段读,不受扰;
|
|
7
|
+
* - 失败:{ ok: false, summary, evidence? } —— guard 异常降级天然就是这一支。
|
|
8
|
+
* Handler 是数据不是 callable:observation 必须可 JSON 序列化(跨 dsh/cordis 边界)。
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** 失败分支(guardToolExecute 兜底与工具显式失败共用此形状) */
|
|
12
|
+
export interface ToolFailure {
|
|
13
|
+
ok: false
|
|
14
|
+
summary: string
|
|
15
|
+
evidence?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** 成功分支:业务载荷平铺 + ok:true 标记 */
|
|
19
|
+
export type GotryObservation<T extends object> = (T & { ok: true }) | ToolFailure
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 参数归一(interpretation 层):dsh 模型侧对 query 包装参数的三种形态——
|
|
23
|
+
* ① 包装对象 { query: {...} } ② 裸对象(平铺字段) ③ 字符串(按主键收)。
|
|
24
|
+
* 唯一归一入口;工具面不再各自猜形状。
|
|
25
|
+
*/
|
|
26
|
+
export function interpretArgs<T extends Record<string, unknown>>(args: { query?: unknown } & Record<string, unknown>, stringKey?: string): T {
|
|
27
|
+
if (args.query && typeof args.query === 'object') return args.query as T
|
|
28
|
+
const { query, ...rest } = args as Record<string, unknown>
|
|
29
|
+
if (Object.keys(rest).length > 0) return rest as T
|
|
30
|
+
if (typeof query === 'string' && stringKey) return { [stringKey]: query } as T
|
|
31
|
+
return {} as T
|
|
32
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 槽位抽取层(travel_slot_extraction.v1):面向差旅 intake 的槽位 schema + 确定性过期校验 + 评分器。
|
|
3
|
+
*
|
|
4
|
+
* 设计约定(与评测 golden 逐条对齐):
|
|
5
|
+
* - 时间表达**逐字保留**(「下周一」就写「下周一」),换算归下游工具——tool-owned dates;
|
|
6
|
+
* - 过期判定在代码层(flagExpiredSlots),LLM 只负责逐字抽取;
|
|
7
|
+
* - 过期只判**主日期字段**(requisition.start_date / flight.departure_date / hotel.check_in_date),
|
|
8
|
+
* 且槽位原值保留,仅往 missing_slots 追加 "<domain>.<field> (date is expired)";
|
|
9
|
+
* - 相对/模糊表达永不判过期(「本周三」即使已过也逐字传递,由人裁决语义)。
|
|
10
|
+
*
|
|
11
|
+
* slot→spec 求解桥接不在本期(architecture §10 债务)。
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { parseAbsoluteDate, type TimeAnchor } from './time-anchor.ts'
|
|
15
|
+
|
|
16
|
+
export type SlotDomain = 'requisition' | 'flight' | 'hotel'
|
|
17
|
+
|
|
18
|
+
export interface RequisitionSlots {
|
|
19
|
+
mode?: 'create' | string
|
|
20
|
+
destination?: string | string[]
|
|
21
|
+
start_date?: string
|
|
22
|
+
end_date?: string
|
|
23
|
+
duration_days?: number
|
|
24
|
+
trip_type?: 'one_way' | 'round_trip' | string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface FlightSlots {
|
|
28
|
+
action?: 'search' | string
|
|
29
|
+
origin?: string
|
|
30
|
+
destination?: string | string[]
|
|
31
|
+
departure_date?: string
|
|
32
|
+
return_date?: string
|
|
33
|
+
departure_time_pref?: string
|
|
34
|
+
sort_name?: string
|
|
35
|
+
sort_type?: string
|
|
36
|
+
multi_destination?: boolean
|
|
37
|
+
trip_type?: 'one_way' | 'round_trip' | string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface HotelSlots {
|
|
41
|
+
action?: 'search' | string
|
|
42
|
+
city?: string
|
|
43
|
+
check_in_date?: string
|
|
44
|
+
check_out_date?: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface TravelSlotExtraction {
|
|
48
|
+
schema_version: 'travel_slot_extraction.v1'
|
|
49
|
+
language: 'zh' | 'en' | 'mixed'
|
|
50
|
+
domains: SlotDomain[]
|
|
51
|
+
slots: {
|
|
52
|
+
requisition?: RequisitionSlots
|
|
53
|
+
flight?: FlightSlots
|
|
54
|
+
hotel?: HotelSlots
|
|
55
|
+
}
|
|
56
|
+
missing_slots: string[]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** 各域的主日期字段——过期校验只判它(对齐 golden:8.1-8.10 仅 start_date 进 missing_slots) */
|
|
60
|
+
const PRIMARY_DATE_FIELD: Record<SlotDomain, string> = {
|
|
61
|
+
requisition: 'start_date',
|
|
62
|
+
flight: 'departure_date',
|
|
63
|
+
hotel: 'check_in_date',
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 确定性过期校验(纯函数,不改入参):主日期字段是**绝对**月日表达且早于锚点今天,
|
|
68
|
+
* 往 missing_slots 追加 "<domain>.<field> (date is expired)"(幂等去重);槽位原值不动。
|
|
69
|
+
*/
|
|
70
|
+
export function flagExpiredSlots(ext: TravelSlotExtraction, anchor: TimeAnchor): TravelSlotExtraction {
|
|
71
|
+
const anchorYear = Number(anchor.today.slice(0, 4))
|
|
72
|
+
const missing = [...ext.missing_slots]
|
|
73
|
+
for (const domain of ext.domains) {
|
|
74
|
+
const slots = ext.slots[domain] as Record<string, unknown> | undefined
|
|
75
|
+
const field = PRIMARY_DATE_FIELD[domain]
|
|
76
|
+
const value = slots?.[field]
|
|
77
|
+
if (typeof value !== 'string') continue
|
|
78
|
+
const resolved = parseAbsoluteDate(value, anchorYear)
|
|
79
|
+
if (resolved && resolved < anchor.today) {
|
|
80
|
+
const flag = `${domain}.${field} (date is expired)`
|
|
81
|
+
if (!missing.includes(flag)) missing.push(flag)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return { ...ext, missing_slots: missing }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** 槽位抽取 system prompt:锚点卡注入 + 逐字保留铁律(LLM 不做算术、不判过期) */
|
|
88
|
+
export function buildSlotSystem(anchor: TimeAnchor): string {
|
|
89
|
+
return `你是差旅需求的槽位抽取器。从用户原话抽取槽位,只输出 JSON:
|
|
90
|
+
{"schema_version":"travel_slot_extraction.v1","language":"zh|en|mixed","domains":["requisition"|"flight"|"hotel",...],"slots":{...},"missing_slots":[...]}
|
|
91
|
+
|
|
92
|
+
## 时间锚点卡
|
|
93
|
+
${anchor.card}
|
|
94
|
+
相对日期(明天/下周X/下个月中旬/国庆前…)对应的绝对日期都查锚点卡,不要自己心算。
|
|
95
|
+
|
|
96
|
+
## 铁律
|
|
97
|
+
1. 时间表达逐字保留、不翻译:用户说「下周一」就写「下周一」,说「next Thursday」就写 "next Thursday"——绝不换算成绝对日期、绝不切换语言(换算归下游工具)。模糊时间词(过几天/近期/下周初/隔周/下个月)同样是合法槽位值,逐字保留,**不算缺失**。
|
|
98
|
+
2. language 指**用户原话**的语言(与槽位值用什么语言无关):全中文 zh;全英文 en;中英混排 mixed。即使槽位值按规则 10 含中文城市名,只要原话全英文,language 仍为 en。
|
|
99
|
+
3. 域判定——看用户的**动作动词**,一句话可落多个域:
|
|
100
|
+
- 安排行程/行程推荐/帮我安排 → requisition:{"mode":"create","destination","start_date","end_date"?,"trip_type"}
|
|
101
|
+
- 看/查/订机票、航班、票价 → flight:{"action":"search","origin"?,"destination","departure_date","return_date"?,"trip_type"}
|
|
102
|
+
- 看/订酒店、入住、订房 → hotel:{"action":"search","city","check_in_date","check_out_date"?};「待/住 N 天」只是时长语义,不单独构成 hotel 域
|
|
103
|
+
- 「出差/去 X」本身不构成 requisition;没有上述动词的单城出行意图按回程形态分流:
|
|
104
|
+
「去 X,当天往返」→ 仅 requisition(round_trip);「去 X,周日回/X 号回」跨天回程 → 仅 flight(round_trip)。
|
|
105
|
+
4. trip_type 必填(requisition 与 flight;hotel 不要):出现「往返/回程/当天往返/X 号回」→ "round_trip";否则显式 "one_way"。
|
|
106
|
+
5. 停留天数:「出差/待/住 N 天」→ requisition 用 "duration_days":N;hotel 用 "check_out_date":"<入住表达>+N" 原样拼接。
|
|
107
|
+
6. 回程机票(「住 N 天回 X」「待到周日回 X」):flight.origin=旅行城市, flight.destination=X, flight.departure_date="<入住/到达表达>+N" 或逐字回程表达,只有回程时 trip_type="one_way"。
|
|
108
|
+
7. 价格**排序**偏好只在找低价时加(「哪天便宜/比较便宜/最便宜」→ flight "sort_name":"PRICE","sort_type":"ASC");单纯「看价格/多少钱」不加。
|
|
109
|
+
8. 出发时段偏好(「早上七点后出发」)→ flight 加 "departure_time_pref":"07:00后"(HH:MM后 格式)。
|
|
110
|
+
9. 多目的地:
|
|
111
|
+
- 国内多城链路(≥3 城):requisition.destination 与 flight.destination 都写**全程城市数组**(含首站),flight 不写 origin,departure_date=首段出发表达,加 "multi_destination":true;不为链路每段单独建 hotel/子段。
|
|
112
|
+
- 国际开口程(open-jaw):flight.origin=首站(单值), flight.destination=后续链路数组, 加 "multi_destination":true。
|
|
113
|
+
10. 城市名:纯国内行程用中文标准名(北京/上海/广州/深圳…,即使原文是拼音);国际或跨国多城链路的城市名保留用户原文。
|
|
114
|
+
11. 关键槽位缺失(如有机票意图但无目的地)→ missing_slots 加 "<domain>.<field>";不缺则空数组。
|
|
115
|
+
12. 过期判定不归你:绝对日期是否已过由下游确定性层处理,你只管逐字抽取。
|
|
116
|
+
|
|
117
|
+
## 示例(学习约定,勿照抄内容)
|
|
118
|
+
用户:下周五入住上海,住三天回杭州
|
|
119
|
+
输出:{"schema_version":"travel_slot_extraction.v1","language":"zh","domains":["hotel","flight"],"slots":{"hotel":{"action":"search","city":"上海","check_in_date":"下周五","check_out_date":"下周五+3"},"flight":{"action":"search","origin":"上海","destination":"杭州","departure_date":"下周五+3","trip_type":"one_way"}},"missing_slots":[]}
|
|
120
|
+
|
|
121
|
+
用户:next Monday 去上海,订酒店
|
|
122
|
+
输出:{"schema_version":"travel_slot_extraction.v1","language":"mixed","domains":["hotel"],"slots":{"hotel":{"action":"search","city":"上海","check_in_date":"next Monday"}},"missing_slots":[]}
|
|
123
|
+
|
|
124
|
+
用户:这阵子想去广州,帮我看下深圳到广州的机票
|
|
125
|
+
输出:{"schema_version":"travel_slot_extraction.v1","language":"zh","domains":["flight"],"slots":{"flight":{"action":"search","origin":"深圳","destination":"广州","departure_date":"这阵子","trip_type":"one_way"}},"missing_slots":[]}
|
|
126
|
+
|
|
127
|
+
用户:8.20 日去杭州,当天往返
|
|
128
|
+
输出:{"schema_version":"travel_slot_extraction.v1","language":"zh","domains":["requisition"],"slots":{"requisition":{"mode":"create","destination":"杭州","start_date":"8.20","trip_type":"round_trip"}},"missing_slots":[]}
|
|
129
|
+
|
|
130
|
+
用户:下周三去杭州,周六回
|
|
131
|
+
输出:{"schema_version":"travel_slot_extraction.v1","language":"zh","domains":["flight"],"slots":{"flight":{"action":"search","destination":"杭州","departure_date":"下周三","return_date":"周六","trip_type":"round_trip"}},"missing_slots":[]}
|
|
132
|
+
|
|
133
|
+
用户:下周三去成都,待到周六,周六去西安待一天然后回杭州
|
|
134
|
+
输出:{"schema_version":"travel_slot_extraction.v1","language":"zh","domains":["requisition","flight"],"slots":{"requisition":{"mode":"create","destination":["成都","西安","杭州"],"start_date":"下周三","trip_type":"round_trip"},"flight":{"action":"search","destination":["成都","西安","杭州"],"departure_date":"下周三","multi_destination":true,"trip_type":"round_trip"}},"missing_slots":[]}
|
|
135
|
+
|
|
136
|
+
用户:open-jaw please: Shanghai to Tokyo next Monday, back from Osaka to Shanghai next Friday
|
|
137
|
+
输出:{"schema_version":"travel_slot_extraction.v1","language":"en","domains":["flight"],"slots":{"flight":{"action":"search","origin":"Shanghai","destination":["Tokyo","Osaka","Shanghai"],"departure_date":"next Monday","return_date":"next Friday","multi_destination":true,"trip_type":"round_trip"}},"missing_slots":[]}
|
|
138
|
+
|
|
139
|
+
只输出 JSON,不要多余文本。`
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* language 的确定性判定(判定归代码层,不信模型):只看用户原话——
|
|
144
|
+
* 含中文且含拉丁字母 → mixed;仅中文 → zh;仅拉丁 → en。
|
|
145
|
+
* (对齐 golden:「next Thursday 去北京」=mixed;全英文带中文槽位值仍=en)
|
|
146
|
+
*/
|
|
147
|
+
export function detectLanguage(utterance: string): 'zh' | 'en' | 'mixed' {
|
|
148
|
+
const hasCjk = /[一-鿿]/.test(utterance)
|
|
149
|
+
const hasLatin = /[A-Za-z]/.test(utterance)
|
|
150
|
+
if (hasCjk && hasLatin) return 'mixed'
|
|
151
|
+
if (hasLatin) return 'en'
|
|
152
|
+
return 'zh'
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** 模型原始 JSON → 规范化 v1 抽取结果(缺省补齐,域外键容忍;language 由 detectLanguage 覆写) */
|
|
156
|
+
export function normalizeExtraction(obj: Record<string, unknown>, utterance?: string): TravelSlotExtraction | null {
|
|
157
|
+
const domains = obj['domains']
|
|
158
|
+
if (!Array.isArray(domains) || domains.length === 0) return null
|
|
159
|
+
const valid = domains.filter((d): d is SlotDomain => d === 'requisition' || d === 'flight' || d === 'hotel')
|
|
160
|
+
if (valid.length === 0) return null
|
|
161
|
+
const lang = obj['language']
|
|
162
|
+
const slots = (obj['slots'] ?? {}) as TravelSlotExtraction['slots']
|
|
163
|
+
const missing = obj['missing_slots']
|
|
164
|
+
return {
|
|
165
|
+
schema_version: 'travel_slot_extraction.v1',
|
|
166
|
+
language: utterance !== undefined ? detectLanguage(utterance) : (lang === 'en' || lang === 'mixed' ? lang : 'zh'),
|
|
167
|
+
domains: valid,
|
|
168
|
+
slots,
|
|
169
|
+
missing_slots: Array.isArray(missing) ? missing.map(String) : [],
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface ScoreResult {
|
|
174
|
+
pass: boolean
|
|
175
|
+
/** 致命差异(导致 fail) */
|
|
176
|
+
diffs: string[]
|
|
177
|
+
/** 非致命提示(actual 多出 expected 没有的槽位键等) */
|
|
178
|
+
warnings: string[]
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const sortedSet = (xs: string[]) => [...xs].sort()
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* 评分器:case pass 的口径 = language 一致 + domains 集合一致 +
|
|
185
|
+
* expected 的每个槽位键值在 actual 中精确命中(actual 多出的键只记 warning)+
|
|
186
|
+
* missing_slots 集合一致。逐字保留语义下,值比较就是字符串精确比较。
|
|
187
|
+
*/
|
|
188
|
+
export function scoreExtraction(expected: TravelSlotExtraction, actual: TravelSlotExtraction): ScoreResult {
|
|
189
|
+
const diffs: string[] = []
|
|
190
|
+
const warnings: string[] = []
|
|
191
|
+
|
|
192
|
+
if (expected.language !== actual.language) {
|
|
193
|
+
diffs.push(`language: 期望 ${expected.language},实际 ${actual.language}`)
|
|
194
|
+
}
|
|
195
|
+
if (JSON.stringify(sortedSet(expected.domains)) !== JSON.stringify(sortedSet(actual.domains))) {
|
|
196
|
+
diffs.push(`domains: 期望 [${sortedSet(expected.domains)}],实际 [${sortedSet(actual.domains)}]`)
|
|
197
|
+
}
|
|
198
|
+
for (const domain of expected.domains) {
|
|
199
|
+
const exp = expected.slots[domain] as Record<string, unknown> | undefined
|
|
200
|
+
const act = actual.slots[domain] as Record<string, unknown> | undefined
|
|
201
|
+
if (!exp) continue
|
|
202
|
+
if (!act) {
|
|
203
|
+
diffs.push(`slots.${domain}: 实际缺失整个域`)
|
|
204
|
+
continue
|
|
205
|
+
}
|
|
206
|
+
for (const [k, v] of Object.entries(exp)) {
|
|
207
|
+
if (JSON.stringify(act[k]) !== JSON.stringify(v)) {
|
|
208
|
+
diffs.push(`slots.${domain}.${k}: 期望 ${JSON.stringify(v)},实际 ${JSON.stringify(act[k])}`)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
for (const k of Object.keys(act)) {
|
|
212
|
+
if (!(k in exp)) warnings.push(`slots.${domain}.${k}: 实际多出键 ${JSON.stringify(act[k])}`)
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (JSON.stringify(sortedSet(expected.missing_slots)) !== JSON.stringify(sortedSet(actual.missing_slots))) {
|
|
216
|
+
diffs.push(`missing_slots: 期望 [${expected.missing_slots}],实际 [${actual.missing_slots}]`)
|
|
217
|
+
}
|
|
218
|
+
return { pass: diffs.length === 0, diffs, warnings }
|
|
219
|
+
}
|