@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
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM_MODEL 会话面覆盖(issue #77)。
|
|
3
|
+
*
|
|
4
|
+
* dsh settings 分层:schema 默认 < composition 配置(cordis patch)< 用户层
|
|
5
|
+
*(~/.dsh/settings.yaml)。bin/gotry-inner.js 已把 LLM_MODEL 注入 composition
|
|
6
|
+
* 层(agent-default-model 默认模型 + llm-deepseek 目录),但用户在 dsh web UI
|
|
7
|
+
* 选过模型时,用户层压过 composition 层——单靠 patch,.env 承诺仍落空。
|
|
8
|
+
*
|
|
9
|
+
* 这里在 agent/request 瀑布(dsh-agent-loop 每次发起 LLM 请求前解析
|
|
10
|
+
* provider/model 的闸口,dsh-agent installModelSelection 也在此处施加选择)挂
|
|
11
|
+
* 监听,post-next 覆盖 provider/model:本插件随 cordis patch 在根组装载,先于
|
|
12
|
+
* 任何 agent 创建;瀑布按注册序嵌套(先注册 = 最外层,post-next 最后生效),
|
|
13
|
+
* 因此显式 .env 意图压过一切持久层选择。内存态零持久化,进程退即散,不改写
|
|
14
|
+
* 用户 ~/.dsh 设置。
|
|
15
|
+
*
|
|
16
|
+
* GOTRY_LLM_MODEL 未设置时不挂监听:默认路径(组合配置或用户 web 设置)面不变。
|
|
17
|
+
*
|
|
18
|
+
* @module gotry/capabilities/model-override
|
|
19
|
+
*/
|
|
20
|
+
export const MODEL_OVERRIDE_ENV = 'GOTRY_LLM_MODEL';
|
|
21
|
+
/**
|
|
22
|
+
* 挂载模型覆盖;返回是否实际挂载(未设环境变量或 ctx 无事件总线时为 false)。
|
|
23
|
+
* provider 固定 deepseek-official:llm-deepseek 是 gotry 组合里唯一持有
|
|
24
|
+
* DEEPSEEK_API_KEY/DEEPSEEK_BASE_URL 映射凭证的 provider 路由。
|
|
25
|
+
*/
|
|
26
|
+
export function installModelOverride(ctx, env = process.env) {
|
|
27
|
+
const model = env[MODEL_OVERRIDE_ENV];
|
|
28
|
+
if (!model || typeof ctx.on !== 'function')
|
|
29
|
+
return false;
|
|
30
|
+
ctx.on('agent/request', async (_payload, next) => {
|
|
31
|
+
const resolved = await next();
|
|
32
|
+
// 与 installModelSelection 同语义:选中项无 effort 时清掉继承值,回落
|
|
33
|
+
// provider 默认推理档——不把上一个模型的 effort 错配到被覆盖的模型上
|
|
34
|
+
const { reasoningEffort: _inherited, ...rest } = resolved;
|
|
35
|
+
return { ...rest, provider: 'deepseek-official', model };
|
|
36
|
+
});
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
@@ -1,33 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenSky 实时观测桥(免费匿名,~400 credits/天,~4 req/s burst):
|
|
3
|
+
* 查某 callsign 的飞机是否在 ADS-B 网络的当前观测里——航线层的实时印证。
|
|
4
|
+
*
|
|
5
|
+
* 契约(与 weather.ts / hbcli.ts 同构):
|
|
6
|
+
* - 永不抛错:网络失败/超时/解析失败一律降级返回;
|
|
7
|
+
* - 三值语义:命中=强肯定;查空≠证伪(ADS-B 覆盖有限,降权不排除);服务不可用=无结论;
|
|
8
|
+
* - 证据链:成功 [实时API:opensky@ts];失败 [实时API:opensky@error@ts]。
|
|
9
|
+
*
|
|
10
|
+
* 接口面(2026-08 实际可达,匿名路径):
|
|
11
|
+
* GET /api/states/all — 当前全球 ADS-B 状态,~10000 架
|
|
12
|
+
* GET /api/states/all?icao24=<hex> — 单飞机
|
|
13
|
+
* /api/flights/airport 历史查 = 需鉴权(匿名 403)
|
|
14
|
+
*
|
|
15
|
+
* 数据意义:与 OpenFlights 骨架(通航性)+ 静态班次包(班期时刻) 三值互补——
|
|
16
|
+
* OpenFlights = 历史上是否通航过(offline)
|
|
17
|
+
* flights_2026.json = 调研估算的班次时刻
|
|
18
|
+
* OpenSky = 该 callsign 的飞机「现在」是否在观测网络里(实时刻正飞)
|
|
19
|
+
*
|
|
20
|
+
* v0.0.1-rc.3 +: 之前是 scripts/opensky-check.ts 一次性 CLI(M2 时设计为 7 天窗
|
|
21
|
+
* 历史校验,但匿名路径实际不可达),现升级为能力层封装 + dsh 插件工具。
|
|
22
|
+
*/
|
|
1
23
|
const BASE = 'https://opensky-network.org/api';
|
|
2
24
|
async function fetchOpenSky(url, timeoutMs) {
|
|
3
25
|
const ctrl = new AbortController();
|
|
4
|
-
const timer = setTimeout(()=>ctrl.abort(), timeoutMs);
|
|
26
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
5
27
|
try {
|
|
6
28
|
const res = await fetch(url, {
|
|
7
29
|
signal: ctrl.signal,
|
|
8
|
-
headers: {
|
|
9
|
-
Accept: 'application/json',
|
|
10
|
-
'User-Agent': 'gotry/0.0.1-rc.3 (+https://github.com/Danceiny/gotry)'
|
|
11
|
-
}
|
|
30
|
+
headers: { Accept: 'application/json', 'User-Agent': 'gotry/0.0.1-rc.3 (+https://github.com/Danceiny/gotry)' },
|
|
12
31
|
});
|
|
13
|
-
if (!res.ok)
|
|
14
|
-
ok: false,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
} catch (e) {
|
|
22
|
-
return {
|
|
23
|
-
ok: false,
|
|
24
|
-
error: e.message.slice(0, 200)
|
|
25
|
-
};
|
|
26
|
-
} finally{
|
|
32
|
+
if (!res.ok)
|
|
33
|
+
return { ok: false, error: `opensky HTTP ${res.status}${res.status === 429 ? ' (rate limited, 400 credits/day anonymous)' : ''}` };
|
|
34
|
+
return { ok: true, data: await res.json() };
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
return { ok: false, error: e.message.slice(0, 200) };
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
27
40
|
clearTimeout(timer);
|
|
28
41
|
}
|
|
29
42
|
}
|
|
30
|
-
const upper = (s)=>s.trim().toUpperCase();
|
|
43
|
+
const upper = (s) => s.trim().toUpperCase();
|
|
31
44
|
export async function verifyFlight(query) {
|
|
32
45
|
const started = Date.now();
|
|
33
46
|
const ts = new Date().toISOString();
|
|
@@ -38,37 +51,35 @@ export async function verifyFlight(query) {
|
|
|
38
51
|
if (!r.ok) {
|
|
39
52
|
return {
|
|
40
53
|
verdict: 'unavailable',
|
|
41
|
-
callsign: cs,
|
|
42
|
-
|
|
43
|
-
sampleSize: 0,
|
|
44
|
-
hits: [],
|
|
54
|
+
callsign: cs, airport,
|
|
55
|
+
sampleSize: 0, hits: [],
|
|
45
56
|
evidence: `[实时API:opensky@error@${ts}] ${r.error}`,
|
|
46
57
|
via: 'opensky-error',
|
|
47
|
-
latencyMs,
|
|
48
|
-
error: r.error
|
|
58
|
+
latencyMs, error: r.error,
|
|
49
59
|
};
|
|
50
60
|
}
|
|
61
|
+
// /api/states/all → { time, states: Array<17 元素数组> }
|
|
62
|
+
// [0 icao24, 1 callsign, 2 origin_country, 3 time_position, 4 last_contact,
|
|
63
|
+
// 5 lon, 6 lat, 7 baro_altitude, 8 on_ground, ...]
|
|
51
64
|
const rawStates = (r.data ?? {}).states ?? [];
|
|
52
|
-
const observed = rawStates
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
65
|
+
const observed = rawStates
|
|
66
|
+
.filter(row => (row[1] ?? '').trim().toUpperCase().includes(cs))
|
|
67
|
+
.map(row => ({
|
|
68
|
+
icao24: String(row[0] ?? ''),
|
|
69
|
+
callsign: (row[1] ?? '').trim() || null,
|
|
70
|
+
lastSeen: Number(row[4] ?? 0),
|
|
71
|
+
firstSeen: Number(row[4] ?? 0),
|
|
72
|
+
estArrivalAirport: airport,
|
|
73
|
+
}));
|
|
59
74
|
const verdict = observed.length > 0 ? 'observed' : 'not_observed';
|
|
60
|
-
const evidence = observed.length > 0
|
|
75
|
+
const evidence = observed.length > 0
|
|
76
|
+
? `[实时API:opensky@${ts}] ✅ 全球 ADS-B 当前观测命中 ${cs} (${observed.length} 架)`
|
|
77
|
+
: `[实时API:opensky@${ts}] ○ 当前 ADS-B 全球观测列表未见 ${cs}(ADS-B 覆盖有限,不作否定结论)`;
|
|
61
78
|
return {
|
|
62
|
-
verdict,
|
|
63
|
-
callsign: cs,
|
|
64
|
-
airport,
|
|
79
|
+
verdict, callsign: cs, airport,
|
|
65
80
|
sampleSize: rawStates.length,
|
|
66
|
-
hits: observed,
|
|
67
|
-
evidence,
|
|
81
|
+
hits: observed, evidence,
|
|
68
82
|
via: 'opensky',
|
|
69
|
-
latencyMs
|
|
83
|
+
latencyMs,
|
|
70
84
|
};
|
|
71
85
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
//# sourceURL=/Users/bytedance/work/gotry/ts/capabilities/opensky.ts
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部依赖韧性原语(issue #16 采纳,ADR-18):effect_interpreter.v1 解译器层的横切面。
|
|
3
|
+
*
|
|
4
|
+
* 对外通道的三类故障形态在此归一一处,能力层 handler(永不抛错契约)零改写:
|
|
5
|
+
* - 指数退避重试 withRetry:只对「瞬时类失败」按策略重试,不改变单次失败语义;
|
|
6
|
+
* - 断路器 CircuitBreaker:closed→open→half-open,连续失败达阈值即熔断,
|
|
7
|
+
* 冷却后放行单探测——保护配额与上游,拒绝也是显式结构化观察(不抛错);
|
|
8
|
+
*
|
|
9
|
+
* 策略边界(issue #16 三个解译器主张在本仓的保守落法,详见 docs/design/effect-interpreter.md):
|
|
10
|
+
* - 重试只属于被判定「值得重试」的瞬时失败;风控/挑战/限流类上游明确说「不」的
|
|
11
|
+
* 失败(如 FlyAI Sentinel)永不重试——重试是放大器,不是修复器;
|
|
12
|
+
* - 断路器状态是进程内瞬态(同 session-search 节律闸的先例),重启即重置;
|
|
13
|
+
* 不把瞬态熔断写盘成持久资产。
|
|
14
|
+
*/
|
|
15
|
+
/** 第 failedAttempt 次失败后的等待时长(纯函数,单测锁定 500→1000→2000 封顶链) */
|
|
16
|
+
export function backoffDelayMs(policy, failedAttempt) {
|
|
17
|
+
const raw = policy.baseDelayMs * 2 ** (Math.max(1, failedAttempt) - 1);
|
|
18
|
+
return Math.min(raw, policy.maxDelayMs);
|
|
19
|
+
}
|
|
20
|
+
const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
21
|
+
/**
|
|
22
|
+
* 带指数退避的受控重试:handler 本身永不抛错(能力层契约),这里兼容抛错的
|
|
23
|
+
* 「裸调用方」——异常按 isRetryable(result=null, error) 判定后并入同一计数。
|
|
24
|
+
* 重试只针对瞬时失败;上限到点即返回最后结果,永不向上抛。
|
|
25
|
+
*/
|
|
26
|
+
export async function withRetry(fn, policy, onBackoff) {
|
|
27
|
+
const sleep = policy.sleep ?? defaultSleep;
|
|
28
|
+
const maxAttempts = Math.max(1, policy.maxAttempts);
|
|
29
|
+
let attempts = 0;
|
|
30
|
+
let backoffMs = 0;
|
|
31
|
+
const abortableSleep = (ms) => {
|
|
32
|
+
const signal = policy.signal;
|
|
33
|
+
if (signal?.aborted)
|
|
34
|
+
return Promise.resolve('aborted');
|
|
35
|
+
// The injected sleep is part of the retry contract. Keep its rejection
|
|
36
|
+
// visible to callers, while making an abort win the race and consuming a
|
|
37
|
+
// later rejection so cancellation cannot create an unhandled rejection.
|
|
38
|
+
if (!signal)
|
|
39
|
+
return sleep(ms).then(() => 'slept');
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
let settled = false;
|
|
42
|
+
let timer;
|
|
43
|
+
const cleanup = () => signal.removeEventListener('abort', onAbort);
|
|
44
|
+
const finish = (outcome) => {
|
|
45
|
+
if (settled)
|
|
46
|
+
return;
|
|
47
|
+
settled = true;
|
|
48
|
+
if (timer !== undefined)
|
|
49
|
+
clearTimeout(timer);
|
|
50
|
+
cleanup();
|
|
51
|
+
resolve(outcome);
|
|
52
|
+
};
|
|
53
|
+
const onAbort = () => finish('aborted');
|
|
54
|
+
const onSleepResolved = () => finish('slept');
|
|
55
|
+
const onSleepRejected = (error) => {
|
|
56
|
+
if (settled)
|
|
57
|
+
return;
|
|
58
|
+
settled = true;
|
|
59
|
+
cleanup();
|
|
60
|
+
reject(error);
|
|
61
|
+
};
|
|
62
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
63
|
+
if (policy.sleep) {
|
|
64
|
+
void Promise.resolve().then(() => policy.sleep(ms)).then(onSleepResolved, onSleepRejected);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
timer = setTimeout(onSleepResolved, ms);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
for (;;) {
|
|
72
|
+
if (policy.signal?.aborted) {
|
|
73
|
+
return { result: null, error: null, attempts, backoffMs, aborted: true };
|
|
74
|
+
}
|
|
75
|
+
attempts += 1;
|
|
76
|
+
let result = null;
|
|
77
|
+
let error = null;
|
|
78
|
+
try {
|
|
79
|
+
result = await fn();
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
error = e;
|
|
83
|
+
}
|
|
84
|
+
if (policy.signal?.aborted) {
|
|
85
|
+
return { result: null, error, attempts, backoffMs, aborted: true };
|
|
86
|
+
}
|
|
87
|
+
const retryable = policy.isRetryable?.(result, error)
|
|
88
|
+
?? (error != null || result?.ok === false);
|
|
89
|
+
if (attempts < maxAttempts && retryable) {
|
|
90
|
+
const delay = backoffDelayMs(policy, attempts);
|
|
91
|
+
onBackoff?.(attempts, delay);
|
|
92
|
+
backoffMs += delay;
|
|
93
|
+
if (await abortableSleep(delay) === 'aborted') {
|
|
94
|
+
return { result: null, error, attempts, backoffMs, aborted: true };
|
|
95
|
+
}
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
return { result, error, attempts, backoffMs, aborted: false };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 断路器(每效应一个实例):
|
|
103
|
+
* closed 常态放行;连续失败达 failureThreshold → open;
|
|
104
|
+
* open 拒绝(new attempts=0,.fail-fast 保护上游/配额);冷却满 openMs → half-open;
|
|
105
|
+
* half-open 仅放行单个探测:onSuccess → closed 清零;onFailure → 重新 open(冷却重启)。
|
|
106
|
+
* 「失败」按效应的 isFailure 语义计数(一次调用一次计数,重试耗尽才计,非每 attempt)。
|
|
107
|
+
*/
|
|
108
|
+
export class CircuitBreaker {
|
|
109
|
+
o;
|
|
110
|
+
consecutiveFailures = 0;
|
|
111
|
+
openedAt = 0;
|
|
112
|
+
generation = 0;
|
|
113
|
+
nextTokenId = 0;
|
|
114
|
+
probeToken = null;
|
|
115
|
+
constructor(o) {
|
|
116
|
+
this.o = o;
|
|
117
|
+
}
|
|
118
|
+
threshold() {
|
|
119
|
+
return Math.max(1, this.o.failureThreshold);
|
|
120
|
+
}
|
|
121
|
+
now() {
|
|
122
|
+
return (this.o.now ?? Date.now)();
|
|
123
|
+
}
|
|
124
|
+
state() {
|
|
125
|
+
if (this.openedAt > 0 && this.now() - this.openedAt >= this.o.openMs)
|
|
126
|
+
return 'half-open';
|
|
127
|
+
if (this.openedAt > 0)
|
|
128
|
+
return 'open';
|
|
129
|
+
return 'closed';
|
|
130
|
+
}
|
|
131
|
+
/** 发起一次调用前问闸:open 回 {allowed:false}(调用方须返回显式降级观察,不重试) */
|
|
132
|
+
canAttempt() {
|
|
133
|
+
const s = this.state();
|
|
134
|
+
if (s === 'closed')
|
|
135
|
+
return { allowed: true, state: s, token: this.makeToken(false) };
|
|
136
|
+
if (s === 'open')
|
|
137
|
+
return { allowed: false, state: s };
|
|
138
|
+
// half-open:单探测语义——已有探测在途拒其余并发
|
|
139
|
+
if (this.probeToken)
|
|
140
|
+
return { allowed: false, state: s };
|
|
141
|
+
this.generation += 1;
|
|
142
|
+
const token = this.makeToken(true);
|
|
143
|
+
this.probeToken = token;
|
|
144
|
+
return { allowed: true, state: s, token };
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* half-open 探测被取消:仅令牌持有者释放所有权,不把 probe 永久卡死,
|
|
148
|
+
* 也不让旧 closed 调用或旧 generation 释放新探测。
|
|
149
|
+
*/
|
|
150
|
+
releaseProbe(token) {
|
|
151
|
+
if (token?.probe !== true || this.probeToken !== token || this.state() !== 'half-open')
|
|
152
|
+
return;
|
|
153
|
+
this.probeToken = null;
|
|
154
|
+
this.generation += 1;
|
|
155
|
+
}
|
|
156
|
+
/** 一次解译调用成功(非 isFailure)——清零;half-open 探测成功即回 closed */
|
|
157
|
+
onSuccess(token) {
|
|
158
|
+
if (!this.owns(token))
|
|
159
|
+
return;
|
|
160
|
+
this.consecutiveFailures = 0;
|
|
161
|
+
this.openedAt = 0;
|
|
162
|
+
if (token?.probe === true || (!token && this.probeToken !== null)) {
|
|
163
|
+
this.probeToken = null;
|
|
164
|
+
this.generation += 1;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/** 一次解译调用失败(含重试耗尽)——半开探测失败 = 重新开闸 */
|
|
168
|
+
onFailure(token) {
|
|
169
|
+
if (!this.owns(token))
|
|
170
|
+
return;
|
|
171
|
+
if (token?.probe === true || (!token && this.probeToken !== null))
|
|
172
|
+
this.probeToken = null;
|
|
173
|
+
this.consecutiveFailures += 1;
|
|
174
|
+
if (this.openedAt > 0 || this.consecutiveFailures >= this.threshold()) {
|
|
175
|
+
this.openedAt = this.now();
|
|
176
|
+
this.generation += 1;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
makeToken(probe) {
|
|
180
|
+
return Object.freeze({ generation: this.generation, probe, id: ++this.nextTokenId });
|
|
181
|
+
}
|
|
182
|
+
owns(token) {
|
|
183
|
+
// Keep the direct CircuitBreaker API backwards-compatible for callers
|
|
184
|
+
// that settle the currently active call without retaining its token.
|
|
185
|
+
if (!token)
|
|
186
|
+
return true;
|
|
187
|
+
if (token.probe)
|
|
188
|
+
return this.probeToken === token && this.state() === 'half-open';
|
|
189
|
+
return token.generation === this.generation && this.probeToken === null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* action-cache 本地自愈层(RFC docs/rfc/user-session-data-rfc.md §3.2 / §2.3;Stagehand 云端缓存的本地化):
|
|
3
|
+
*
|
|
4
|
+
* 目的:会话检索的查询模式高度重复(同站点同类型搜索),首跑用 LLM/规则定位,后续走
|
|
5
|
+
* 缓存的确定性载荷零成本重放;站点改版 → DOM 指纹失配 → miss → 重新定位并回写。
|
|
6
|
+
*
|
|
7
|
+
* 设计原则(Stagehand「错误的缓存点击比慢更糟」的被动失效):
|
|
8
|
+
* - key = site + action + 参数模板(%from%/%to%/%date% 变量化,同型查询共享条目);
|
|
9
|
+
* - 每条目绑 domFingerprint(快照/接口形状的 sha256 指纹);lookup 时现场指纹与条目不符 = miss(即使 key 命中);
|
|
10
|
+
* - miss 即回写(记录新定位),过期(默认 48h)与容量(每 site 默认 50 条,LRU)被动淘汰;
|
|
11
|
+
* - 纯函数 + JSON 文件持久化(隔离 stateRoot;损坏文件按空缓存处理,永不抛错)。
|
|
12
|
+
*
|
|
13
|
+
* P2 切片:模块+确定性测试先行;消费方(P2 美团适配器/a11y 兜底)下一切片接线。
|
|
14
|
+
*/
|
|
15
|
+
import { createHash } from 'node:crypto';
|
|
16
|
+
import { mkdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
17
|
+
import { dirname, join } from 'node:path';
|
|
18
|
+
/** 把具体查询参数变量化为模板 key:日期→%date%,from/to 语义序在前,其余参数按字典序尾随 */
|
|
19
|
+
export function templateKey(site, action, params) {
|
|
20
|
+
const val = (k) => (k === 'date' ? '%date%' : (params[k] ?? '').trim());
|
|
21
|
+
const head = ['from', 'to', 'date'].filter((k) => k in params).map(val);
|
|
22
|
+
const tail = Object.keys(params).filter((k) => !['from', 'to', 'date'].includes(k)).sort().map(val);
|
|
23
|
+
return `${site}:${action}:${[...head, ...tail].join('|')}`;
|
|
24
|
+
}
|
|
25
|
+
/** 指纹:快照/接口形状文本 → sha256 前 16 位(微改版即失配——宁可 miss 不可错点) */
|
|
26
|
+
export function fingerprint(shapeText) {
|
|
27
|
+
return createHash('sha256').update(shapeText).digest('hex').slice(0, 16);
|
|
28
|
+
}
|
|
29
|
+
export class ActionCache {
|
|
30
|
+
filePath;
|
|
31
|
+
entries = new Map();
|
|
32
|
+
loaded = false;
|
|
33
|
+
ttlMs;
|
|
34
|
+
maxPerSite;
|
|
35
|
+
now;
|
|
36
|
+
constructor(filePath, opts = {}) {
|
|
37
|
+
this.filePath = filePath;
|
|
38
|
+
this.ttlMs = opts.ttlMs ?? 48 * 3600_000;
|
|
39
|
+
this.maxPerSite = opts.maxEntriesPerSite ?? 50;
|
|
40
|
+
this.now = opts.now ?? (() => new Date());
|
|
41
|
+
}
|
|
42
|
+
load() {
|
|
43
|
+
if (this.loaded)
|
|
44
|
+
return;
|
|
45
|
+
this.loaded = true;
|
|
46
|
+
try {
|
|
47
|
+
if (existsSync(this.filePath)) {
|
|
48
|
+
const raw = JSON.parse(readFileSync(this.filePath, 'utf8'));
|
|
49
|
+
for (const e of raw) {
|
|
50
|
+
if (e?.key && e.domFingerprint && e.locator)
|
|
51
|
+
this.entries.set(e.key, e);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch { /* 损坏文件按空缓存处理 */ }
|
|
56
|
+
}
|
|
57
|
+
persist() {
|
|
58
|
+
try {
|
|
59
|
+
mkdirSync(dirname(this.filePath), { recursive: true });
|
|
60
|
+
const tmp = this.filePath + '.tmp';
|
|
61
|
+
writeFileSync(tmp, JSON.stringify([...this.entries.values()], null, 0), 'utf8');
|
|
62
|
+
writeFileSync(this.filePath, readFileSync(tmp, 'utf8'), 'utf8');
|
|
63
|
+
try {
|
|
64
|
+
require('node:fs').rmSync(tmp);
|
|
65
|
+
}
|
|
66
|
+
catch { /* best effort */ }
|
|
67
|
+
}
|
|
68
|
+
catch { /* 持久化失败不阻塞内存路径 */ }
|
|
69
|
+
}
|
|
70
|
+
/** 站点前缀条目数(LRU 淘汰用) */
|
|
71
|
+
siteEntries(site) {
|
|
72
|
+
return [...this.entries.values()].filter((e) => e.key.startsWith(site + ':'));
|
|
73
|
+
}
|
|
74
|
+
/** 命中三条件:key 存在 + 未过期 + 指纹一致;命中计 hits 并惰性落盘 */
|
|
75
|
+
lookup(key, domFingerprint, site) {
|
|
76
|
+
this.load();
|
|
77
|
+
const e = this.entries.get(key);
|
|
78
|
+
if (!e)
|
|
79
|
+
return null;
|
|
80
|
+
if (this.now().getTime() - Date.parse(e.lastHitAt || e.createdAt) > this.ttlMs) {
|
|
81
|
+
this.entries.delete(key);
|
|
82
|
+
this.persist();
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
if (e.domFingerprint !== domFingerprint)
|
|
86
|
+
return null; // 改版:被动失效,等 record 回写
|
|
87
|
+
e.hits += 1;
|
|
88
|
+
e.lastHitAt = this.now().toISOString();
|
|
89
|
+
this.persist();
|
|
90
|
+
void site;
|
|
91
|
+
return e;
|
|
92
|
+
}
|
|
93
|
+
/** miss 后回写(重新定位的产物);同 key 覆盖;超容 LRU 淘汰最旧 */
|
|
94
|
+
record(key, domFingerprint, locator, site) {
|
|
95
|
+
this.load();
|
|
96
|
+
const ts = this.now().toISOString();
|
|
97
|
+
const prev = this.entries.get(key);
|
|
98
|
+
this.entries.set(key, {
|
|
99
|
+
key, domFingerprint, locator,
|
|
100
|
+
createdAt: prev?.createdAt ?? ts,
|
|
101
|
+
lastHitAt: ts,
|
|
102
|
+
hits: prev?.hits ?? 0,
|
|
103
|
+
});
|
|
104
|
+
const siteList = this.siteEntries(site);
|
|
105
|
+
if (siteList.length > this.maxPerSite) {
|
|
106
|
+
const victim = siteList.sort((a, b) => Date.parse(a.lastHitAt) - Date.parse(b.lastHitAt))[0];
|
|
107
|
+
if (victim)
|
|
108
|
+
this.entries.delete(victim.key);
|
|
109
|
+
}
|
|
110
|
+
this.persist();
|
|
111
|
+
return this.entries.get(key);
|
|
112
|
+
}
|
|
113
|
+
invalidate(key) {
|
|
114
|
+
this.load();
|
|
115
|
+
this.entries.delete(key);
|
|
116
|
+
this.persist();
|
|
117
|
+
}
|
|
118
|
+
size(site) {
|
|
119
|
+
this.load();
|
|
120
|
+
return site ? this.siteEntries(site).length : this.entries.size;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/** 便捷入口:隔离 stateRoot 下的缓存文件路径 */
|
|
124
|
+
export function actionCachePath(stateRoot) {
|
|
125
|
+
return join(stateRoot, 'session-action-cache.json');
|
|
126
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 携程机票站点适配器(RFC §3.2 首个适配器;PoC 已识别接口面,data-sources.md §8):
|
|
3
|
+
* - entry:URL 参数直开(https://flights.ctrip.com/online/list/oneway-{from}-{to}?depdate=YYYY-MM-DD)
|
|
4
|
+
* - networkHints:主搜索接口 search/api/search/batchSearch(POST,~550KB,国内票同走)
|
|
5
|
+
* - 解析:flightItineraryList[].flightSegments[0].flightList[0] + priceList 最小 adultPrice
|
|
6
|
+
* (schema 实测 2026-08-28,见 data-sources.md §8)
|
|
7
|
+
* 只读:适配器不含任何提交/预订语义;URL 直开即零 DOM 交互。
|
|
8
|
+
*/
|
|
9
|
+
/** 城市三字码表(小起步集;词表外 unresolved 逐字保留,不做开放式猜测——ADR-12 同款边界) */
|
|
10
|
+
const CITY_CODES = {
|
|
11
|
+
上海: 'sha', 北京: 'bjs', 广州: 'can', 深圳: 'szx', 成都: 'ctu', 昆明: 'kmg',
|
|
12
|
+
大理: 'dlu', 丽江: 'ljg', 西安: 'sia', 杭州: 'hgh', 三亚: 'syx', 厦门: 'xmn',
|
|
13
|
+
重庆: 'cqg', 青岛: 'taa', 长沙: 'csx', 武汉: 'wuh', 南京: 'nkg', 郑州: 'cgo',
|
|
14
|
+
贵阳: 'kwe', 桂林: 'kwl', 西双版纳: 'jhg', 香格里拉: 'dig',
|
|
15
|
+
};
|
|
16
|
+
export function buildEntryUrl(from, to, depDate) {
|
|
17
|
+
const unresolved = [];
|
|
18
|
+
const fromCode = CITY_CODES[from];
|
|
19
|
+
const toCode = CITY_CODES[to];
|
|
20
|
+
if (!fromCode)
|
|
21
|
+
unresolved.push(from);
|
|
22
|
+
if (!toCode)
|
|
23
|
+
unresolved.push(to);
|
|
24
|
+
if (unresolved.length > 0 || !/^\d{4}-\d{2}-\d{2}$/.test(depDate)) {
|
|
25
|
+
return { ok: false, unresolved: unresolved.length > 0 ? unresolved : [depDate] };
|
|
26
|
+
}
|
|
27
|
+
return { ok: true, url: `https://flights.ctrip.com/online/list/oneway-${fromCode}-${toCode}?depdate=${depDate}` };
|
|
28
|
+
}
|
|
29
|
+
/** networkHints:响应 URL 命中即视为搜索回包(对 UI 改版免疫,只怕接口改版) */
|
|
30
|
+
export const NETWORK_HINTS = [/search\/api\/search\/batchSearch/];
|
|
31
|
+
/**
|
|
32
|
+
* 登录态检测(用户自己的账号,不是匿名实例——founder 2026-08-28 纠偏):
|
|
33
|
+
* 任一登录票据 cookie 存在即视为已登录;名单基于公开常识,首个真登录后校准(D-13)。
|
|
34
|
+
*/
|
|
35
|
+
export const LOGIN_COOKIE_NAMES = ['cticket', 'uid', 'uname', 'passport'];
|
|
36
|
+
export const SITE_DOMAIN = '.ctrip.com';
|
|
37
|
+
/** 安全取字符串字段(任意来源字段都可能是 null/undefined/数字/对象) */
|
|
38
|
+
function asString(v) {
|
|
39
|
+
return typeof v === 'string' ? v : '';
|
|
40
|
+
}
|
|
41
|
+
/** 安全取正数(无法解析按 0 返,绝不伪造价格) */
|
|
42
|
+
function asPositiveNumber(v) {
|
|
43
|
+
return typeof v === 'number' && Number.isFinite(v) && v > 0 ? v : 0;
|
|
44
|
+
}
|
|
45
|
+
/** 解析 batchSearch 响应(纯函数,fixture 测试锚点);malformed 一律返空,不抛错 */
|
|
46
|
+
export function parseBatchSearch(body) {
|
|
47
|
+
return parseBatchSearchResult(body).options;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 结构化解析(issue #279):返回选项 + 三态判语。
|
|
51
|
+
* - `hit` = 已识别合法结构 + 至少一个有效行程
|
|
52
|
+
* - `miss` = 已识别合法空(data.flightItineraryList 是空数组)
|
|
53
|
+
* - `error`= 形状未识别(JSON 解析失败 / 非对象根 / data 缺失或非对象 /
|
|
54
|
+
* flightItineraryList 不是数组 / 非空数组没有可用行程)——未知响应
|
|
55
|
+
* 不可静默收敛为 miss
|
|
56
|
+
* 绝不发明价格、航班号、机场、时刻;混合数组保留有效项,全畸形数组报 error。
|
|
57
|
+
*/
|
|
58
|
+
export function parseBatchSearchResult(body) {
|
|
59
|
+
let raw;
|
|
60
|
+
try {
|
|
61
|
+
raw = JSON.parse(body);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return { options: [], verdict: 'error', shape: 'invalid_json' };
|
|
65
|
+
}
|
|
66
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
67
|
+
return { options: [], verdict: 'error', shape: 'root_not_object' };
|
|
68
|
+
}
|
|
69
|
+
const data = raw.data;
|
|
70
|
+
if (data === null || typeof data !== 'object' || Array.isArray(data)) {
|
|
71
|
+
return { options: [], verdict: 'error', shape: 'data_not_object' };
|
|
72
|
+
}
|
|
73
|
+
const list = raw.data.flightItineraryList;
|
|
74
|
+
if (!Array.isArray(list)) {
|
|
75
|
+
return { options: [], verdict: 'error', shape: 'itinerary_list_not_array' };
|
|
76
|
+
}
|
|
77
|
+
const out = [];
|
|
78
|
+
for (const it of list) {
|
|
79
|
+
if (it === null || typeof it !== 'object' || Array.isArray(it))
|
|
80
|
+
continue;
|
|
81
|
+
const item = it;
|
|
82
|
+
const segs = item.flightSegments;
|
|
83
|
+
if (!Array.isArray(segs) || segs.length === 0)
|
|
84
|
+
continue;
|
|
85
|
+
const seg = segs[0];
|
|
86
|
+
if (seg === null || typeof seg !== 'object' || Array.isArray(seg))
|
|
87
|
+
continue;
|
|
88
|
+
const segObj = seg;
|
|
89
|
+
const fl = segObj.flightList;
|
|
90
|
+
if (!Array.isArray(fl) || fl.length === 0)
|
|
91
|
+
continue;
|
|
92
|
+
const flight = fl[0];
|
|
93
|
+
if (flight === null || typeof flight !== 'object' || Array.isArray(flight))
|
|
94
|
+
continue;
|
|
95
|
+
const f = flight;
|
|
96
|
+
if (typeof f.flightNo !== 'string' || !f.flightNo)
|
|
97
|
+
continue;
|
|
98
|
+
if (typeof f.departureDateTime !== 'string' || !f.departureDateTime)
|
|
99
|
+
continue;
|
|
100
|
+
// 缺 priceList 延续旧合同为「有航班、价格未知」;显式非数组与畸形价项
|
|
101
|
+
// 属未知响应,整项跳过。若响应里没有其他有效项,最终判 error 而非 miss。
|
|
102
|
+
if (item.priceList !== undefined && !Array.isArray(item.priceList))
|
|
103
|
+
continue;
|
|
104
|
+
const priceList = item.priceList ?? [];
|
|
105
|
+
const prices = [];
|
|
106
|
+
let malformedPrice = false;
|
|
107
|
+
for (const p of priceList) {
|
|
108
|
+
if (p === null || typeof p !== 'object' || Array.isArray(p)) {
|
|
109
|
+
malformedPrice = true;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
const adultPrice = p.adultPrice;
|
|
113
|
+
if (adultPrice === undefined)
|
|
114
|
+
continue;
|
|
115
|
+
if (typeof adultPrice !== 'number' || !Number.isFinite(adultPrice)) {
|
|
116
|
+
malformedPrice = true;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
if (adultPrice > 0)
|
|
120
|
+
prices.push(adultPrice);
|
|
121
|
+
}
|
|
122
|
+
if (malformedPrice)
|
|
123
|
+
continue;
|
|
124
|
+
out.push({
|
|
125
|
+
flightNo: f.flightNo,
|
|
126
|
+
airline: asString(segObj.airlineName),
|
|
127
|
+
depDateTime: asString(f.departureDateTime),
|
|
128
|
+
arrDateTime: asString(f.arrivalDateTime),
|
|
129
|
+
depAirport: asString(f.departureAirportName),
|
|
130
|
+
arrAirport: asString(f.arrivalAirportName),
|
|
131
|
+
durationMin: asPositiveNumber(segObj.duration),
|
|
132
|
+
price: prices.length > 0 ? Math.min(...prices) : 0,
|
|
133
|
+
aircraft: typeof f.aircraftName === 'string' ? f.aircraftName : undefined,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
options: out,
|
|
138
|
+
verdict: out.length > 0 ? 'hit' : list.length === 0 ? 'miss' : 'error',
|
|
139
|
+
shape: out.length > 0 ? 'itinerary_rows_usable' : list.length === 0 ? 'itinerary_list_empty' : 'itinerary_rows_unusable',
|
|
140
|
+
};
|
|
141
|
+
}
|