@danceiny/gotry 0.0.1-rc.9 → 0.2.0-rc.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +172 -219
- package/README.zh-CN.md +222 -0
- package/bin/gotry-backend.js +53 -0
- package/bin/gotry-booking-copilot.js +53 -0
- package/bin/gotry-bootstrap.js +1788 -0
- package/bin/gotry-inner.js +733 -83
- package/bin/gotry-process-liveness.d.ts +27 -0
- package/bin/gotry-process-liveness.js +97 -0
- package/bin/gotry-runtime-resolution.d.ts +27 -0
- package/bin/gotry-runtime-resolution.js +49 -0
- package/bin/gotry.js +1 -1
- package/client/client.js +203 -0
- package/cordis.gotry-patch.yml +80 -56
- package/data/airline-airports.json +39 -0
- package/data/stations-12306-verify.json +524 -0
- package/dist/capabilities/agent-reach-deep.js +45 -122
- package/dist/capabilities/agent-reach.js +101 -146
- package/dist/capabilities/anything.js +161 -94
- package/dist/capabilities/artifacts.js +370 -0
- package/dist/capabilities/channel-health.js +131 -0
- package/dist/capabilities/channel-registry.js +256 -0
- package/dist/capabilities/doctor.js +553 -0
- package/dist/capabilities/effect.js +394 -0
- package/dist/capabilities/external-event.js +149 -0
- package/dist/capabilities/fact-log.js +55 -0
- package/dist/capabilities/flyai-config.js +337 -0
- package/dist/capabilities/flyai.js +947 -110
- package/dist/capabilities/fx-contract.js +293 -0
- package/dist/capabilities/geo-atlas.js +246 -0
- package/dist/capabilities/ground-transfer.js +676 -0
- package/dist/capabilities/hbcli.js +260 -123
- package/dist/capabilities/hotelbyte-transaction.js +194 -0
- package/dist/capabilities/incident-log.js +131 -61
- package/dist/capabilities/itinerary-artifact.js +190 -0
- package/dist/capabilities/itinerary-deck-artifact.js +194 -0
- package/dist/capabilities/itinerary-deck-export.js +339 -0
- package/dist/capabilities/lavish-local.js +924 -0
- package/dist/capabilities/model-override.js +38 -0
- package/dist/capabilities/opensky.js +54 -43
- package/dist/capabilities/provider-detail-sanitize.js +64 -0
- package/dist/capabilities/resilience.js +191 -0
- package/dist/capabilities/route-provider-conformance.js +341 -0
- package/dist/capabilities/session/action-cache.js +50 -44
- package/dist/capabilities/session/adapters/ctrip-flight.js +120 -62
- package/dist/capabilities/session/adapters/ctrip-hotel.js +222 -0
- package/dist/capabilities/session/adapters/dida-portal.js +274 -0
- package/dist/capabilities/session/adapters/meituan-local.js +35 -54
- package/dist/capabilities/session/adapters/rail-12306.js +342 -0
- package/dist/capabilities/session/benchmark.js +189 -0
- package/dist/capabilities/session/bridge-ledger.js +224 -0
- package/dist/capabilities/session/extension-bridge.js +636 -0
- package/dist/capabilities/session/extension-channel.js +109 -0
- package/dist/capabilities/session/extension-distribution.js +230 -0
- package/dist/capabilities/session/extract.js +31 -21
- package/dist/capabilities/session/golden-score.js +114 -0
- package/dist/capabilities/session/health-watch.js +215 -0
- package/dist/capabilities/session/read-guard.js +75 -24
- package/dist/capabilities/session/static-flight-golden.js +150 -0
- package/dist/capabilities/session/transport.js +97 -83
- package/dist/capabilities/session/wizard.js +117 -0
- package/dist/capabilities/session-consent.js +178 -0
- package/dist/capabilities/session-login.js +170 -0
- package/dist/capabilities/session-search.js +635 -44
- package/dist/capabilities/spawn-bounded.js +203 -0
- package/dist/capabilities/sponsor-plugin.js +341 -0
- package/dist/capabilities/visa-policy.js +140 -0
- package/dist/capabilities/weather.js +243 -138
- package/dist/data/session-golden-20.json +25 -0
- package/dist/data/sf-golden-manifest.json +103 -0
- package/dist/data/sf-static-routes.json +91 -0
- package/dist/scripts/action-cache-tests.js +24 -59
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +242 -0
- package/dist/scripts/agent-planning-turn-deadline-tests.js +185 -0
- package/dist/scripts/agent-reach-deep-tests.js +30 -40
- package/dist/scripts/agent-reach-error-tests.js +354 -0
- package/dist/scripts/agent-reach-tests.js +26 -18
- package/dist/scripts/agent-reach-wrapper-tests.js +50 -50
- package/dist/scripts/anything-path-measure-tests.js +133 -0
- package/dist/scripts/anything-path-measure.js +150 -0
- package/dist/scripts/anything-tests.js +250 -60
- package/dist/scripts/artifact-client-contract-tests.js +220 -0
- package/dist/scripts/artifacts-capability-tests.js +727 -0
- package/dist/scripts/async-collect.js +50 -11
- package/dist/scripts/benchmark-environment-bridge-e2e.js +741 -0
- package/dist/scripts/benchmark-environment-bridge-tests.js +1452 -0
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +126 -0
- package/dist/scripts/booking-copilot-availability-policy-tests.js +265 -0
- package/dist/scripts/booking-copilot-bin-proof-tests.js +66 -0
- package/dist/scripts/booking-copilot-cleanup-proof-helper.js +76 -0
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +144 -0
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +424 -0
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +2839 -0
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +309 -0
- package/dist/scripts/booking-copilot-dsh-readiness-proof.js +238 -0
- package/dist/scripts/booking-copilot-dsh-warmer-proof.js +126 -0
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +156 -0
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +70 -0
- package/dist/scripts/booking-copilot-intent-proof-tests.js +422 -0
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +184 -0
- package/dist/scripts/booking-copilot-planner-live-probe.js +95 -0
- package/dist/scripts/booking-copilot-proof-runtime.js +42 -0
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +210 -0
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +2349 -0
- package/dist/scripts/booking-copilot-server-proof-tests.js +784 -0
- package/dist/scripts/booking-copilot-startup-proof-tests.js +94 -0
- package/dist/scripts/booking-executor-tests.js +80 -0
- package/dist/scripts/booking-recovery-chain-tests.js +182 -0
- package/dist/scripts/booking-saga-tests.js +125 -0
- package/dist/scripts/booking-surface-contract-proof-tests.js +212 -0
- package/dist/scripts/bootstrap-tests.js +1549 -0
- package/dist/scripts/bridge-events-tests.js +239 -0
- package/dist/scripts/bridge-ledger-tests.js +428 -0
- package/dist/scripts/build-changelog.js +238 -0
- package/dist/scripts/build-metrics-report.js +331 -0
- package/dist/scripts/changelog-tests.js +118 -0
- package/dist/scripts/channel-probe-tests.js +103 -0
- package/dist/scripts/channel-probe.js +169 -0
- package/dist/scripts/channel-registry-tests.js +208 -0
- package/dist/scripts/city-scenario-tier-tests.js +234 -0
- package/dist/scripts/companion-tests.js +25 -70
- package/dist/scripts/dida-cookie-probe.js +87 -0
- package/dist/scripts/dida-runner-stop-tests.js +311 -0
- package/dist/scripts/dida-sw-probe.js +114 -0
- package/dist/scripts/diff-test.js +17 -12
- package/dist/scripts/doctor-tests.js +600 -0
- package/dist/scripts/drill-multiuser-ledger-tests.js +1076 -0
- package/dist/scripts/drill-sdk-descendant-cleanup-tests.js +606 -0
- package/dist/scripts/drill-w2a-sensor-tests.js +788 -0
- package/dist/scripts/dsh-artifact-e2e.js +279 -0
- package/dist/scripts/dsh-artifact-web-e2e.js +675 -0
- package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
- package/dist/scripts/dsh-llm-tests.js +437 -0
- package/dist/scripts/dsh-runtime-closure-tests.js +182 -0
- package/dist/scripts/dsh-runtime-closure.js +162 -0
- package/dist/scripts/dsh-session-v3-migration-proof.js +109 -0
- package/dist/scripts/dsh-subprocess-local-proof.js +150 -0
- package/dist/scripts/dsh-target-closure-proof.js +178 -0
- package/dist/scripts/effect-tests.js +539 -0
- package/dist/scripts/engine-run.js +1 -3
- package/dist/scripts/engine-tests.js +16 -10
- package/dist/scripts/evaluation-cadence-tests.js +174 -0
- package/dist/scripts/evaluation-contract-tests.js +268 -0
- package/dist/scripts/extension-distribution-cli.js +39 -0
- package/dist/scripts/extension-distribution-tests.js +443 -0
- package/dist/scripts/extension-tests.js +988 -0
- package/dist/scripts/external-event-tests.js +350 -0
- package/dist/scripts/fact-gate-tests.js +869 -0
- package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
- package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
- package/dist/scripts/flight-malformed-tests.js +159 -0
- package/dist/scripts/flyai-setup-tests.js +228 -0
- package/dist/scripts/flyai-setup-tool-tests.js +54 -0
- package/dist/scripts/flyai-tests.js +692 -0
- package/dist/scripts/flyai-tool-registration-contract-tests.js +91 -0
- package/dist/scripts/fx-contract-tests.js +201 -0
- package/dist/scripts/g5-guard-tests.js +150 -0
- package/dist/scripts/g5-guard.js +193 -0
- package/dist/scripts/gen-lunar-anchors.js +106 -0
- package/dist/scripts/geo-atlas-tests.js +283 -0
- package/dist/scripts/gotry-backend-kernel-tests.js +206 -0
- package/dist/scripts/gotry-try-demo-tests.js +79 -0
- package/dist/scripts/gotry-try-demo.js +49 -0
- package/dist/scripts/ground-transfer-tests.js +956 -0
- package/dist/scripts/hbcli-e2e-tests.js +159 -0
- package/dist/scripts/hbcli-live-optin-tests.js +96 -0
- package/dist/scripts/hbcli-release-contract-tests.js +122 -0
- package/dist/scripts/hbcli-tests.js +121 -69
- package/dist/scripts/health-watch-cli.js +73 -0
- package/dist/scripts/hotel-date-gate-tests.js +496 -0
- package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
- package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
- package/dist/scripts/i18n-tests.js +41 -0
- package/dist/scripts/incident-tests.js +281 -87
- package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
- package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
- package/dist/scripts/issue-271-liveness-tests.js +569 -0
- package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
- package/dist/scripts/issue-289-model-retry-tests.js +441 -0
- package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
- package/dist/scripts/issue-338-home-city-e2e.js +577 -0
- package/dist/scripts/issue343-real-entry-e2e.js +160 -0
- package/dist/scripts/issue436-persisted-routing-e2e.js +247 -0
- package/dist/scripts/itinerary-artifact-tests.js +368 -0
- package/dist/scripts/itinerary-deck-artifact-tests.js +416 -0
- package/dist/scripts/itinerary-deck-export-tests.js +552 -0
- package/dist/scripts/itinerary-deck-tests.js +435 -0
- package/dist/scripts/itinerary-html-tests.js +426 -0
- package/dist/scripts/journey-tests.js +22 -27
- package/dist/scripts/kernel-manifest-evidence.js +109 -0
- package/dist/scripts/kernel-manifest-gate.js +126 -0
- package/dist/scripts/kernel-manifest-tests.js +212 -0
- package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
- package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
- package/dist/scripts/kernel-manifest.js +369 -0
- package/dist/scripts/lavish-local-tests.js +1226 -0
- package/dist/scripts/lavish-product-tools-tests.js +537 -0
- package/dist/scripts/ledger-repair-apply-tests.js +316 -0
- package/dist/scripts/ledger-repair-plan-tests.js +375 -0
- package/dist/scripts/ledger-tests.js +382 -246
- package/dist/scripts/ledger-workflow-crash.js +10 -20
- package/dist/scripts/m3-cohort-tests.js +714 -0
- package/dist/scripts/m3-cohort.js +310 -0
- package/dist/scripts/managed-dsh-cleanup-diagnostic-proof.js +184 -0
- package/dist/scripts/managed-dsh-close-failure-proof.js +172 -0
- package/dist/scripts/managed-dsh-run-port-proof.js +153 -0
- package/dist/scripts/managed-dsh-terminal-proof.js +252 -0
- package/dist/scripts/map-tools-vendor-package-proof.js +365 -0
- package/dist/scripts/memory-capture-tests.js +242 -61
- package/dist/scripts/memory-decay-tests.js +18 -52
- package/dist/scripts/memory-lifecycle-tests.js +657 -0
- package/dist/scripts/memory-lifecycle.js +196 -0
- package/dist/scripts/memory-metrics.js +24 -12
- package/dist/scripts/memory-value-report.js +631 -0
- package/dist/scripts/memory-value-tests.js +328 -0
- package/dist/scripts/metrics-report-tests.js +151 -0
- package/dist/scripts/model-override-e2e.js +137 -0
- package/dist/scripts/nightly-evidence-tests.js +203 -0
- package/dist/scripts/nightly-evidence.js +303 -0
- package/dist/scripts/nudge-digest.js +39 -28
- package/dist/scripts/observability-tests.js +381 -0
- package/dist/scripts/onboarding-tests.js +161 -0
- package/dist/scripts/opensky-check.js +18 -13
- package/dist/scripts/opensky-tests.js +28 -28
- package/dist/scripts/outcome-projection-tests.js +427 -0
- package/dist/scripts/persona-sim-tests.js +603 -0
- package/dist/scripts/persona-sim.js +1081 -0
- package/dist/scripts/persona-surface-guard-tests.js +49 -0
- package/dist/scripts/pnpm-dsh-closure-proof.js +17 -0
- package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
- package/dist/scripts/price-drift-tests.js +340 -0
- package/dist/scripts/price-drift-watch.js +447 -0
- package/dist/scripts/probe-poi-tests.js +53 -45
- package/dist/scripts/product-metrics.js +483 -0
- package/dist/scripts/publish-preverify.js +110 -0
- package/dist/scripts/realtime-pricing-tests.js +76 -0
- package/dist/scripts/recall-tests.js +513 -0
- package/dist/scripts/replay-async.js +22 -18
- package/dist/scripts/replay-real.js +18 -18
- package/dist/scripts/replay.js +54 -82
- package/dist/scripts/route-provider-conformance-tests.js +391 -0
- package/dist/scripts/session-attach-diagnose.js +20 -20
- package/dist/scripts/session-attach-poc.js +34 -37
- package/dist/scripts/session-benchmark.js +180 -0
- package/dist/scripts/session-dida-live-e2e.js +199 -0
- package/dist/scripts/session-extract-tests.js +14 -35
- package/dist/scripts/session-link-tests.js +478 -0
- package/dist/scripts/session-login.js +27 -46
- package/dist/scripts/session-tests.js +796 -96
- package/dist/scripts/session-zone-crash.js +49 -0
- package/dist/scripts/session-zone-ledger-tests.js +432 -0
- package/dist/scripts/session-zone-observation-tests.js +492 -0
- package/dist/scripts/session-zone-observe.js +135 -0
- package/dist/scripts/session-zone-wiring-tests.js +566 -0
- package/dist/scripts/session-zones-tests.js +374 -0
- package/dist/scripts/sf-live-benchmark.js +367 -0
- package/dist/scripts/sf-live-challenge-stop-tests.js +453 -0
- package/dist/scripts/sf-live-cli-tests.js +92 -0
- package/dist/scripts/sf-live-options.js +46 -0
- package/dist/scripts/sf-manifest-tests.js +30 -0
- package/dist/scripts/sf-manifest.js +33 -0
- package/dist/scripts/sf-soft-score-tests.js +67 -0
- package/dist/scripts/sf-summary-tests.js +324 -0
- package/dist/scripts/sf-summary.js +525 -0
- package/dist/scripts/share-tests.js +432 -0
- package/dist/scripts/skeleton-check.js +16 -14
- package/dist/scripts/skeleton-integration-test.js +28 -11
- package/dist/scripts/skills-contract-tests.js +51 -46
- package/dist/scripts/smoke-session-gate-tests.js +21 -0
- package/dist/scripts/smoke.js +690 -246
- package/dist/scripts/spawn-bounded-abort-tests.js +244 -0
- package/dist/scripts/sponsor-reuse-tests.js +262 -0
- package/dist/scripts/state-cli-tests.js +226 -101
- package/dist/scripts/state-cli.js +565 -198
- package/dist/scripts/state-repair-cli.js +66 -0
- package/dist/scripts/state-repair-tests.js +140 -0
- package/dist/scripts/static-golden-tests.js +165 -0
- package/dist/scripts/time-eval-tests.js +212 -192
- package/dist/scripts/travel-timeline-tests.js +29 -93
- package/dist/scripts/turn-handoff-collect-tests.js +169 -0
- package/dist/scripts/turn-handoff-collect.js +161 -0
- package/dist/scripts/turn-policy-tests.js +55 -0
- package/dist/scripts/typed-contract-canary.js +176 -0
- package/dist/scripts/tz-resolver-sanity.js +50 -0
- package/dist/scripts/tz-resolver-tests.js +584 -0
- package/dist/scripts/unified-tests.js +60 -20
- package/dist/scripts/visa-policy-tests.js +62 -0
- package/dist/scripts/weather-tests.js +276 -41
- package/dist/scripts/wish-channel-gate-tests.js +54 -0
- package/dist/scripts/write-gate-tests.js +522 -0
- package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
- package/dist/scripts/z3-lifecycle-tests.js +170 -0
- package/dist/scripts/z3-race-repeat-tests.js +39 -0
- package/dist/scripts/z3-race-tests.js +46 -0
- package/dist/src/artifact-gate.js +829 -0
- package/dist/src/backend/kernel.js +91 -0
- package/dist/src/backend/modules/booking-copilot.js +92 -0
- package/dist/src/backend/modules/booking-executor.js +124 -0
- package/dist/src/backend/modules/session-search.js +551 -0
- package/dist/src/benchmark-agent-conformance.js +578 -0
- package/dist/src/benchmark-environment-bridge.js +515 -0
- package/dist/src/benchmark-headless-child-diagnostics.js +166 -0
- package/dist/src/benchmark-tool-isolation.js +151 -0
- package/dist/src/bookable-facts.js +533 -0
- package/dist/src/booking-saga.js +97 -0
- package/dist/src/booking-surface/availability-policy.js +697 -0
- package/dist/src/booking-surface/booking-intent.js +43 -0
- package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
- package/dist/src/booking-surface/canonical-schema.js +116 -0
- package/dist/src/booking-surface/contracts.js +75 -0
- package/dist/src/booking-surface/dsh-planner.js +1854 -0
- package/dist/src/booking-surface/dsh-plugin.js +378 -0
- package/dist/src/booking-surface/dsh-worker.js +98 -0
- package/dist/src/booking-surface/error-codes.js +231 -0
- package/dist/src/booking-surface/index.js +9 -0
- package/dist/src/booking-surface/managed-dsh-cleanup-diagnostic.js +97 -0
- package/dist/src/booking-surface/managed-dsh-run-port.js +244 -0
- package/dist/src/booking-surface/profile.js +24 -0
- package/dist/src/booking-surface/recovery-chain.js +367 -0
- package/dist/src/booking-surface/runtime.js +1968 -0
- package/dist/src/booking-surface/server.js +674 -0
- package/dist/src/booking-surface/startup.js +168 -0
- package/dist/src/booking-surface/validation.js +261 -0
- package/dist/src/bridge.js +20 -13
- package/dist/src/city-scenario-tier.js +378 -0
- package/dist/src/companions.js +48 -74
- package/dist/src/contracts.js +21 -43
- package/dist/src/dsh-llm.js +171 -115
- package/dist/src/engine.js +276 -193
- package/dist/src/evaluation-cadence.js +97 -0
- package/dist/src/evaluation-contracts.js +283 -0
- package/dist/src/flight-pack-adapter.js +54 -0
- package/dist/src/flight-pack-contract.js +2 -0
- package/dist/src/flyai-setup-tool.js +70 -0
- package/dist/src/gotry-backend.js +125 -0
- package/dist/src/hotel-date-gate.js +118 -0
- package/dist/src/i18n.js +88 -0
- package/dist/src/index.js +2385 -881
- package/dist/src/itinerary-deck.js +139 -0
- package/dist/src/itinerary-doc-shared.js +661 -0
- package/dist/src/itinerary-html.js +131 -0
- package/dist/src/journey.js +155 -108
- package/dist/src/lavish-tools.js +400 -0
- package/dist/src/ledger-repair-apply.js +538 -0
- package/dist/src/ledger-repair-plan.js +463 -0
- package/dist/src/loop.js +331 -161
- package/dist/src/m3-cohort.js +1577 -0
- package/dist/src/memory-capture.js +180 -32
- package/dist/src/memory-decay.js +30 -14
- package/dist/src/memory-lifecycle.js +1310 -0
- package/dist/src/memory-utility.js +27 -40
- package/dist/src/mock-llm.js +36 -61
- package/dist/src/model.js +81 -36
- package/dist/src/outcome-projection.js +746 -0
- package/dist/src/realtime-pricing.js +103 -0
- package/dist/src/recall/card.js +74 -0
- package/dist/src/recall/evaluator.js +140 -0
- package/dist/src/recall/integration.js +17 -0
- package/dist/src/recall/tick.js +166 -0
- package/dist/src/session-link/plan-it-action.js +48 -0
- package/dist/src/session-link/session-link.js +248 -0
- package/dist/src/session-zone-ledger.js +312 -0
- package/dist/src/session-zone-observation.js +354 -0
- package/dist/src/session-zone-wiring.js +658 -0
- package/dist/src/session-zones.js +510 -0
- package/dist/src/share/adapters.js +51 -0
- package/dist/src/share/share-consent.js +76 -0
- package/dist/src/share/share-deck.js +58 -0
- package/dist/src/share/share-token.js +146 -0
- package/dist/src/slot-spec.js +84 -106
- package/dist/src/state-ledger.js +696 -524
- package/dist/src/state-repair.js +299 -0
- package/dist/src/subagent-job-id-guard.js +58 -0
- package/dist/src/time-anchor.js +231 -33
- package/dist/src/tool-packet.js +20 -8
- package/dist/src/travel-slots.js +58 -35
- package/dist/src/travel-timeline.js +44 -63
- package/dist/src/turn-deadline.js +287 -0
- package/dist/src/turn-policy.js +118 -0
- package/dist/src/tz-resolver.js +143 -0
- package/dist/src/unified.js +600 -360
- package/dist/src/wish-pool.js +42 -12
- package/dist/src/write-gate.js +495 -0
- package/dist/src/z3-shared.js +284 -0
- package/extension/README.md +21 -0
- package/extension/README.zh-CN.md +21 -0
- package/extension/background.js +463 -0
- package/extension/content-bridge.js +270 -0
- package/extension/content-main.js +111 -0
- package/extension/manifest.json +60 -0
- package/package.json +407 -14
- package/schemas/booking.intent.schema.json +193 -0
- package/schemas/booking.surface.schema.json +2622 -0
- package/ts/capabilities/agent-reach-deep.ts +114 -0
- package/ts/capabilities/agent-reach.ts +198 -0
- package/ts/capabilities/anything.ts +282 -0
- package/ts/capabilities/artifacts.ts +428 -0
- package/ts/capabilities/fact-log.ts +54 -0
- package/ts/capabilities/flyai-config.ts +388 -0
- package/ts/capabilities/flyai.ts +1274 -0
- package/ts/capabilities/hbcli.ts +253 -71
- package/ts/capabilities/incident-log.ts +88 -59
- package/ts/capabilities/itinerary-artifact.ts +214 -0
- package/ts/capabilities/itinerary-deck-artifact.ts +218 -0
- package/ts/capabilities/itinerary-deck-export.ts +378 -0
- package/ts/capabilities/opensky.ts +121 -0
- package/ts/capabilities/session/action-cache.ts +148 -0
- package/ts/capabilities/session/adapters/ctrip-flight.ts +181 -0
- package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
- package/ts/capabilities/session/adapters/dida-portal.ts +338 -0
- package/ts/capabilities/session/adapters/meituan-local.ts +70 -0
- package/ts/capabilities/session/adapters/rail-12306.ts +392 -0
- package/ts/capabilities/session/benchmark.ts +276 -0
- package/ts/capabilities/session/bridge-ledger.ts +333 -0
- package/ts/capabilities/session/extension-bridge.ts +794 -0
- package/ts/capabilities/session/extension-channel.ts +144 -0
- package/ts/capabilities/session/extension-distribution.ts +266 -0
- package/ts/capabilities/session/extract.ts +54 -0
- package/ts/capabilities/session/golden-score.ts +139 -0
- package/ts/capabilities/session/health-watch.ts +264 -0
- package/ts/capabilities/session/read-guard.ts +141 -0
- package/ts/capabilities/session/static-flight-golden.ts +209 -0
- package/ts/capabilities/session/transport.ts +146 -0
- package/ts/capabilities/session/wizard.ts +140 -0
- package/ts/capabilities/session-consent.ts +211 -0
- package/ts/capabilities/session-login.ts +208 -0
- package/ts/capabilities/session-search.ts +893 -0
- package/ts/capabilities/weather.ts +330 -0
- package/ts/dsh-runtime/vendor/README.md +68 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +405 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +404 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +1584 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/icon.svg +5 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +595 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +58 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +131 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/geo.js +232 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +120 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +40 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/staticmap-route.js +115 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +267 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +90 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +23 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/geo.d.ts +61 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/staticmap-route.d.ts +31 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +75 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +68 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +97 -0
- package/ts/package.json +293 -3
- package/ts/scripts/async-collect.ts +91 -0
- package/ts/scripts/map-tools-vendor-package-proof.ts +404 -0
- package/ts/scripts/skeleton-check.ts +1 -1
- package/ts/scripts/skeleton-integration-test.ts +23 -1
- package/ts/scripts/state-cli.ts +586 -0
- package/ts/scripts/turn-handoff-collect.ts +178 -0
- package/ts/src/artifact-gate.ts +991 -0
- package/ts/src/benchmark-agent-conformance.ts +619 -0
- package/ts/src/benchmark-environment-bridge.ts +538 -0
- package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
- package/ts/src/benchmark-tool-isolation.ts +166 -0
- package/ts/src/bookable-facts.ts +837 -0
- package/ts/src/booking-saga.ts +133 -0
- package/ts/src/booking-surface/availability-policy.ts +522 -0
- package/ts/src/booking-surface/booking-intent.ts +86 -0
- package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
- package/ts/src/booking-surface/canonical-schema.js +116 -0
- package/ts/src/booking-surface/contracts.ts +475 -0
- package/ts/src/booking-surface/dsh-planner.ts +1949 -0
- package/ts/src/booking-surface/dsh-plugin.js +378 -0
- package/ts/src/booking-surface/dsh-worker.ts +110 -0
- package/ts/src/booking-surface/error-codes.ts +241 -0
- package/ts/src/booking-surface/index.ts +9 -0
- package/ts/src/booking-surface/managed-dsh-cleanup-diagnostic.ts +151 -0
- package/ts/src/booking-surface/managed-dsh-run-port.ts +273 -0
- package/ts/src/booking-surface/profile.ts +42 -0
- package/ts/src/booking-surface/recovery-chain.ts +409 -0
- package/ts/src/booking-surface/runtime.ts +1793 -0
- package/ts/src/booking-surface/server.ts +733 -0
- package/ts/src/booking-surface/startup.ts +201 -0
- package/ts/src/booking-surface/validation.ts +217 -0
- package/ts/src/companions.ts +113 -0
- package/ts/src/contracts.ts +17 -3
- package/ts/src/dsh-llm.ts +152 -17
- package/ts/src/flyai-setup-tool.ts +77 -0
- package/ts/src/index.ts +2123 -200
- package/ts/src/itinerary-deck.ts +189 -0
- package/ts/src/itinerary-doc-shared.ts +741 -0
- package/ts/src/itinerary-html.ts +171 -0
- package/ts/src/loop.ts +234 -26
- package/ts/src/memory-capture.ts +283 -0
- package/ts/src/memory-decay.ts +55 -0
- package/ts/src/memory-utility.ts +70 -0
- package/ts/src/mock-llm.ts +4 -8
- package/ts/src/model.ts +88 -2
- package/ts/src/recall/card.ts +106 -0
- package/ts/src/recall/evaluator.ts +170 -0
- package/ts/src/recall/integration.ts +35 -0
- package/ts/src/recall/tick.ts +213 -0
- package/ts/src/session-link/plan-it-action.ts +78 -0
- package/ts/src/session-link/session-link.ts +275 -0
- package/ts/src/share/adapters.ts +93 -0
- package/ts/src/share/share-consent.ts +105 -0
- package/ts/src/share/share-deck.ts +85 -0
- package/ts/src/share/share-token.ts +166 -0
- package/ts/src/slot-spec.ts +172 -0
- package/ts/src/state-ledger.ts +1166 -0
- package/ts/src/subagent-job-id-guard.ts +72 -0
- package/ts/src/time-anchor.ts +338 -0
- package/ts/src/tool-packet.ts +32 -0
- package/ts/src/travel-slots.ts +219 -0
- package/ts/src/travel-timeline.ts +83 -0
- package/ts/src/turn-deadline.ts +366 -0
- package/ts/src/turn-policy.ts +154 -0
- package/ts/src/unified.ts +444 -105
- package/ts/src/wish-pool.ts +79 -0
- package/dist/scripts/session-attach-wait.js +0 -41
|
@@ -1,38 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent-reach web 读取(readUrl 薄壳)测试:
|
|
3
|
+
* readUrl = URL 校验 + 委托上游 WebChannel.read(反射桥) + Title 提取,自身无网络实现。
|
|
4
|
+
* 上游真读已在 §15 wrapper 测试覆盖;本套只测薄壳行为:
|
|
5
|
+
* 1. 非法 URL(不带 http) → 拒绝,不抛错,降级返回(离线确定性)
|
|
6
|
+
* 2. 1ms 超时 → 桥被杀,降级 error(离线确定性)
|
|
7
|
+
* 3. live 读 example.com → 成功时断言 Title/证据链;网络边界允许降级(不抛错)
|
|
8
|
+
*
|
|
9
|
+
* 运行: cd ts && npx tsx scripts/agent-reach-tests.ts
|
|
10
|
+
*/
|
|
1
11
|
import assert from 'node:assert/strict';
|
|
2
12
|
import { readUrl } from '../capabilities/agent-reach.js';
|
|
13
|
+
// 1. 非法 URL(不带 scheme)
|
|
3
14
|
{
|
|
4
|
-
const r = await readUrl({
|
|
5
|
-
url: 'example.com'
|
|
6
|
-
});
|
|
15
|
+
const r = await readUrl({ url: 'example.com' });
|
|
7
16
|
assert.equal(r.ok, false);
|
|
8
17
|
assert.equal(r.via, 'r.jina.ai-error');
|
|
9
18
|
assert.ok(r.evidence.includes('error'), 'evidence 带 error');
|
|
10
19
|
console.log('1. 非法 URL 拒绝 OK');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
});
|
|
20
|
+
}
|
|
21
|
+
// 2. 超时(1ms 杀掉反射桥进程)
|
|
22
|
+
{
|
|
23
|
+
const r = await readUrl({ url: 'https://example.com', timeoutMs: 1 });
|
|
16
24
|
assert.equal(r.ok, false);
|
|
17
25
|
assert.equal(r.via, 'r.jina.ai-error');
|
|
18
26
|
assert.ok(r.latencyMs >= 0, '永不抛错');
|
|
19
27
|
console.log('2. 超时降级 OK');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
28
|
+
}
|
|
29
|
+
// 3. live 读 example.com(上游 Jina Reader;网络边界允许降级)
|
|
30
|
+
{
|
|
31
|
+
const r = await readUrl({ url: 'https://example.com', timeoutMs: 30_000 });
|
|
25
32
|
if (r.ok) {
|
|
26
33
|
assert.ok(r.evidence.includes('[agent-reach:web.read@'), '证据链');
|
|
27
34
|
assert.match(r.evidence, /\[agent-reach:web\.read@2\d{3}-\d{2}-\d{2}T/, '证据链带 ISO 时间戳');
|
|
28
35
|
assert.ok(typeof r.content === 'string' && r.content.length > 0, 'content 非空');
|
|
36
|
+
// live 内容会漂移(example.com 经 Jina 的 Title 曾从 Example Domain 变 Test Document),
|
|
37
|
+
// 断言结构(非空标题被提取)而非精确文案
|
|
29
38
|
assert.ok(typeof r.title === 'string' && r.title.length > 0, `Title 提取,实际 ${r.title}`);
|
|
30
39
|
console.log(`3. readUrl example.com → ok (title=${r.title}) OK`);
|
|
31
|
-
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
32
42
|
assert.equal(r.via, 'r.jina.ai-error');
|
|
33
43
|
console.log(`3. readUrl example.com → 降级(${r.error?.slice(0, 60)})(网络边界,合法) OK`);
|
|
34
44
|
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
//# sourceURL=/Users/bytedance/work/gotry/ts/scripts/agent-reach-tests.ts
|
|
45
|
+
}
|
|
46
|
+
console.log('\nAGENT-REACH TESTS: 3/3 OK(readUrl 薄壳;上游真读见 wrapper 套)');
|
|
@@ -1,79 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent-reach wrapper 测试(零渠道知识,全部走反射桥):
|
|
3
|
+
* 1. status: 真 agent-reach doctor 透传(via=agent-reach-cli)
|
|
4
|
+
* 2. web.read: 真读 example.com(上游 Jina Reader 后端)
|
|
5
|
+
* 3. v2ex.get_hot_topics: 上游 python 方法真调(网络边界允许降级)
|
|
6
|
+
* 4. xueqiu.get_stock_quote: 无 cookie → needs-setup 且 setup=上游 check() 原话
|
|
7
|
+
* 5. 未知渠道 → 自描述错误带回上游渠道清单
|
|
8
|
+
* 6. 未知方法 → 自描述错误带回上游方法签名清单
|
|
9
|
+
* 7. 永不抛错: 空 channel/method 降级
|
|
10
|
+
*
|
|
11
|
+
* 运行: cd ts && npx tsx scripts/agent-reach-wrapper-tests.ts
|
|
12
|
+
*/
|
|
1
13
|
import assert from 'node:assert/strict';
|
|
2
14
|
import { reach, reachStatus } from '../capabilities/agent-reach.js';
|
|
15
|
+
// 1. status(真 doctor 原样透传;agent-reach 未装时结构化 SKIP——真集成面设备绑定,
|
|
16
|
+
// 与 §17 skills-contract「有凭证真校验,离线 SKIP」同构;CI 装了则全跑 7 断言)
|
|
3
17
|
{
|
|
4
18
|
const st = await reachStatus(90_000);
|
|
19
|
+
if (!st.ok) {
|
|
20
|
+
console.log(`SKIP: agent-reach doctor 未就绪(未安装/needs-setup),7 断言整体跳过 — via=${st.via} output=${String(st.output).slice(0, 120)}`);
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
5
23
|
assert.equal(st.ok, true);
|
|
6
24
|
assert.equal(st.via, 'agent-reach-cli');
|
|
7
25
|
assert.ok(st.output.length > 50, 'doctor 输出非空(上游原样)');
|
|
8
26
|
console.log(`1. status → doctor 透传 (${st.latencyMs}ms) OK`);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
args: [
|
|
14
|
-
'https://example.com'
|
|
15
|
-
],
|
|
16
|
-
timeoutMs: 30_000
|
|
17
|
-
});
|
|
27
|
+
}
|
|
28
|
+
// 2. web.read(上游 WebChannel.read → Jina Reader)
|
|
29
|
+
{
|
|
30
|
+
const r = await reach({ channel: 'web', method: 'read', args: ['https://example.com'], timeoutMs: 30_000 });
|
|
18
31
|
assert.equal(r.verdict, 'found');
|
|
19
32
|
assert.ok(r.evidence.includes('[agent-reach:web.read@'), '证据链 [agent-reach:web.read@ts]');
|
|
33
|
+
// live 内容会漂移(同 §13),断言非空 markdown 而非精确文案
|
|
20
34
|
assert.ok(typeof r.data === 'string' && r.data.length > 200, 'content 非空 markdown');
|
|
21
35
|
console.log(`2. web.read example.com → found (${r.latencyMs}ms) OK`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
timeoutMs: 30_000
|
|
27
|
-
});
|
|
36
|
+
}
|
|
37
|
+
// 3. v2ex.get_hot_topics(上游 python 方法;网络边界允许降级不抛错)
|
|
38
|
+
{
|
|
39
|
+
const r = await reach({ channel: 'v2ex', method: 'get_hot_topics', timeoutMs: 30_000 });
|
|
28
40
|
if (r.ok) {
|
|
29
41
|
assert.ok(Array.isArray(r.data), 'hot topics 是数组');
|
|
30
42
|
console.log(`3. v2ex.get_hot_topics → found (${r.data.length} topics) OK`);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
'needs-setup'
|
|
35
|
-
].includes(r.verdict), '降级合法');
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
assert.ok(['error', 'needs-setup'].includes(r.verdict), '降级合法');
|
|
36
46
|
console.log(`3. v2ex.get_hot_topics → ${r.verdict}(网络边界,降级合法) OK`);
|
|
37
47
|
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
args: [
|
|
43
|
-
'SH600519'
|
|
44
|
-
],
|
|
45
|
-
timeoutMs: 30_000
|
|
46
|
-
});
|
|
48
|
+
}
|
|
49
|
+
// 4. xueqiu.get_stock_quote(无 cookie → needs-setup 且 setup 是上游 check() 原话)
|
|
50
|
+
{
|
|
51
|
+
const r = await reach({ channel: 'xueqiu', method: 'get_stock_quote', args: ['SH600519'], timeoutMs: 30_000 });
|
|
47
52
|
assert.equal(r.verdict, 'needs-setup', `实际 verdict=${r.verdict} error=${r.error}`);
|
|
48
53
|
assert.ok((r.setup ?? '').includes('configure'), 'setup 透传上游 configure 指引(不转述)');
|
|
49
54
|
console.log('4. xueqiu.get_stock_quote → needs-setup(上游原话指引) OK');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
});
|
|
55
|
+
}
|
|
56
|
+
// 5. 未知渠道 → 自描述,带回上游渠道清单
|
|
57
|
+
{
|
|
58
|
+
const r = await reach({ channel: 'nosuch', method: 'foo' });
|
|
55
59
|
assert.equal(r.ok, false);
|
|
56
|
-
const channels = r.inventory?.channels ?? {};
|
|
60
|
+
const channels = (r.inventory?.channels ?? {});
|
|
57
61
|
assert.ok(channels.web && channels.xueqiu && channels['exa_search'], 'inventory 带回上游注册表(含 exa_search 真名)');
|
|
58
62
|
console.log(`5. 未知渠道 → 自描述清单(${Object.keys(channels).length} 渠道) OK`);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
63
|
+
}
|
|
64
|
+
// 6. 未知方法 → 自描述,带回上游方法签名清单
|
|
65
|
+
{
|
|
66
|
+
const r = await reach({ channel: 'web', method: 'nosuch' });
|
|
64
67
|
assert.equal(r.ok, false);
|
|
65
|
-
const methods = r.inventory?.methods ?? {};
|
|
68
|
+
const methods = (r.inventory?.methods ?? {});
|
|
66
69
|
assert.ok(methods.read, 'inventory.methods 带 read 签名');
|
|
67
70
|
console.log(`6. 未知方法 → 自描述清单(${Object.keys(methods).length} 方法) OK`);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
});
|
|
71
|
+
}
|
|
72
|
+
// 7. 永不抛错: 空 channel/method
|
|
73
|
+
{
|
|
74
|
+
const r = await reach({ channel: '', method: '' });
|
|
73
75
|
assert.equal(r.ok, false);
|
|
74
76
|
assert.equal(r.verdict, 'error');
|
|
75
77
|
console.log('7. 空 channel/method 降级 OK');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
//# sourceURL=/Users/bytedance/work/gotry/ts/scripts/agent-reach-wrapper-tests.ts
|
|
78
|
+
}
|
|
79
|
+
console.log('\nAGENT-REACH WRAPPER TESTS: 7/7 OK(反射桥 + doctor 透传 + 自描述错误)');
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offline tests for the Anything-path measurement probe (issue #276 / #345 evidence probe).
|
|
3
|
+
*
|
|
4
|
+
* Run: cd ts && npx tsx scripts/anything-path-measure-tests.ts
|
|
5
|
+
*
|
|
6
|
+
* Fully offline: the real hbcli runner is never used; a scripted fake runner stands in. The opt-in
|
|
7
|
+
* claim is executed, not asserted: with the environment flag missing, the fake runner must be
|
|
8
|
+
* called exactly zero times.
|
|
9
|
+
*/
|
|
10
|
+
import assert from 'node:assert/strict';
|
|
11
|
+
import { CONCURRENCY, OPT_IN_ENV, fieldPresence, latencyStats, measure, measureIfOptedIn, percentile, scrub, } from './anything-path-measure.js';
|
|
12
|
+
const tests = [];
|
|
13
|
+
const test = (name, run) => tests.push({ name, run });
|
|
14
|
+
const hotel = (extra = {}) => ({ type: 'hotel', hotel: { name: 'H', star: 4, address: 'a', ...extra } });
|
|
15
|
+
const city = () => ({ type: 'city', region: { name: 'C', countryCode: 'CN', extra: '' } });
|
|
16
|
+
/** A scripted runner: results come from a queue per call; also tracks max in-flight calls. */
|
|
17
|
+
function scripted(script) {
|
|
18
|
+
let calls = 0;
|
|
19
|
+
let inFlight = 0;
|
|
20
|
+
let maxInFlight = 0;
|
|
21
|
+
const runner = async (args) => {
|
|
22
|
+
const index = calls++;
|
|
23
|
+
inFlight++;
|
|
24
|
+
maxInFlight = Math.max(maxInFlight, inFlight);
|
|
25
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
26
|
+
inFlight--;
|
|
27
|
+
return script(args, index);
|
|
28
|
+
};
|
|
29
|
+
return { runner, stats: () => ({ calls, maxInFlight }) };
|
|
30
|
+
}
|
|
31
|
+
test('opt-in gate: without the env flag nothing is spawned and nothing is measured', async () => {
|
|
32
|
+
const fake = scripted(() => ({ ok: true, ms: 1, candidates: [] }));
|
|
33
|
+
const result = await measureIfOptedIn({}, fake.runner);
|
|
34
|
+
assert.equal(result.state, 'waiting_external_evidence');
|
|
35
|
+
assert.equal(fake.stats().calls, 0, 'runner must not be called without opt-in');
|
|
36
|
+
const wrong = await measureIfOptedIn({ [OPT_IN_ENV]: 'true' }, fake.runner);
|
|
37
|
+
assert.equal(wrong.state, 'waiting_external_evidence', 'only the exact value 1 opts in');
|
|
38
|
+
assert.equal(fake.stats().calls, 0);
|
|
39
|
+
});
|
|
40
|
+
test('opt-in gate: GOTRY_UAT_READONLY=1 runs the whole measurement', async () => {
|
|
41
|
+
const fake = scripted(() => ({ ok: true, ms: 5, candidates: [city()] }));
|
|
42
|
+
const result = await measureIfOptedIn({ [OPT_IN_ENV]: '1' }, fake.runner);
|
|
43
|
+
assert.equal(result.state, 'measured');
|
|
44
|
+
assert.ok(fake.stats().calls > 0);
|
|
45
|
+
});
|
|
46
|
+
test('percentile: nearest-rank, empty sample is null, single sample is itself', () => {
|
|
47
|
+
assert.equal(percentile([], 50), null);
|
|
48
|
+
assert.equal(percentile([7], 95), 7);
|
|
49
|
+
const sample = Array.from({ length: 20 }, (_, i) => (i + 1) * 10);
|
|
50
|
+
assert.equal(percentile(sample, 50), 100);
|
|
51
|
+
assert.equal(percentile(sample, 95), 190);
|
|
52
|
+
assert.equal(percentile([30, 10, 20], 50), 20, 'input order must not matter');
|
|
53
|
+
});
|
|
54
|
+
test('latencyStats counts failures by reason and keeps their timings in the sample', () => {
|
|
55
|
+
const stats = latencyStats([
|
|
56
|
+
{ ok: true, ms: 100, candidates: [] },
|
|
57
|
+
{ ok: false, ms: 900, reason: 'exit_1', detail: '' },
|
|
58
|
+
{ ok: false, ms: 50, reason: 'exit_1', detail: '' },
|
|
59
|
+
{ ok: false, ms: 60_000, reason: 'timeout', detail: '' },
|
|
60
|
+
]);
|
|
61
|
+
assert.equal(stats.calls, 4);
|
|
62
|
+
assert.equal(stats.errors, 3);
|
|
63
|
+
assert.deepEqual(stats.error_reasons, { exit_1: 2, timeout: 1 });
|
|
64
|
+
assert.equal(stats.max_ms, 60_000);
|
|
65
|
+
});
|
|
66
|
+
test('fieldPresence: empty strings, empty arrays and empty objects do not count as present', () => {
|
|
67
|
+
const presence = fieldPresence([
|
|
68
|
+
{ name: 'a', rating: 4.5, photos: [], hours: {}, note: '' },
|
|
69
|
+
{ name: 'b', rating: null },
|
|
70
|
+
undefined,
|
|
71
|
+
]);
|
|
72
|
+
assert.equal(presence.n, 2, 'undefined entries are not objects');
|
|
73
|
+
assert.deepEqual(presence.fields, { hours: '0/2', name: '2/2', note: '0/2', photos: '0/2', rating: '1/2' });
|
|
74
|
+
});
|
|
75
|
+
test('scrub: credential-looking material is redacted and the text is bounded', () => {
|
|
76
|
+
const scrubbed = scrub('401 Unauthorized: Bearer abc.def.ghi ticket=ST:12345 token: zzz api_key=k123 password hunter2');
|
|
77
|
+
assert.ok(!/abc\.def|12345|zzz|k123|hunter2/.test(scrubbed), `secret material survived: ${scrubbed}`);
|
|
78
|
+
assert.ok(scrubbed.length <= 160);
|
|
79
|
+
assert.ok(scrub('x'.repeat(1000)).length <= 160);
|
|
80
|
+
});
|
|
81
|
+
test('measure: aggregates a scripted run (types, place emptiness, presence, failures) deterministically', async () => {
|
|
82
|
+
const keywords = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
|
|
83
|
+
let n = 0;
|
|
84
|
+
const fake = scripted((args) => {
|
|
85
|
+
n++;
|
|
86
|
+
const placeOnly = args.includes('place');
|
|
87
|
+
if (placeOnly)
|
|
88
|
+
return { ok: true, ms: 10, candidates: [] };
|
|
89
|
+
if (n === 2)
|
|
90
|
+
return { ok: false, ms: 40, reason: 'exit_1', detail: 'boom' };
|
|
91
|
+
return { ok: true, ms: 20 + n, candidates: [city(), hotel(), hotel({ rating: 4.2 })] };
|
|
92
|
+
});
|
|
93
|
+
const fixedClock = () => new Date('2026-10-04T00:00:00.000Z');
|
|
94
|
+
const result = await measure(fake.runner, keywords, fixedClock);
|
|
95
|
+
assert.equal(result.measured_at, '2026-10-04T00:00:00.000Z');
|
|
96
|
+
assert.equal(result.sequential_mixed.calls, 7);
|
|
97
|
+
assert.equal(result.sequential_mixed.errors, 1);
|
|
98
|
+
assert.deepEqual(result.sequential_mixed.error_reasons, { exit_1: 1 });
|
|
99
|
+
assert.equal(result.sequential_place_only.errors, 0);
|
|
100
|
+
assert.equal(result.place_only_total_candidates, 0);
|
|
101
|
+
assert.equal(result.keywords_with_zero_place_results, '7/7');
|
|
102
|
+
assert.equal(result.place_object_field_presence.n, 0);
|
|
103
|
+
assert.deepEqual(Object.keys(result.mixed_candidates_by_type).sort(), ['city', 'hotel']);
|
|
104
|
+
assert.equal(result.mixed_candidates_by_type['city'], 6, 'one of seven mixed calls failed');
|
|
105
|
+
assert.equal(result.hotel_object_field_presence.fields['rating'], '6/12', 'half of the 12 hotel candidates carry a rating');
|
|
106
|
+
assert.equal(result.concurrent_mixed.concurrency, CONCURRENCY);
|
|
107
|
+
assert.equal(result.concurrent_mixed.calls, 7);
|
|
108
|
+
});
|
|
109
|
+
test('measure: the burst phase never exceeds the declared concurrency', async () => {
|
|
110
|
+
const keywords = Array.from({ length: 23 }, (_, i) => `k${i}`);
|
|
111
|
+
const fake = scripted(() => ({ ok: true, ms: 1, candidates: [] }));
|
|
112
|
+
await measure(fake.runner, keywords);
|
|
113
|
+
assert.ok(fake.stats().maxInFlight <= CONCURRENCY, `in-flight ${fake.stats().maxInFlight} exceeded ${CONCURRENCY}`);
|
|
114
|
+
assert.ok(fake.stats().maxInFlight > 1, 'burst phase must actually run concurrently');
|
|
115
|
+
assert.equal(fake.stats().calls, keywords.length * 3, 'mixed + place-only + burst');
|
|
116
|
+
});
|
|
117
|
+
let failed = 0;
|
|
118
|
+
for (const { name, run } of tests) {
|
|
119
|
+
try {
|
|
120
|
+
await run();
|
|
121
|
+
console.log(` ok ${name}`);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
failed++;
|
|
125
|
+
console.error(` FAIL ${name}`);
|
|
126
|
+
console.error(error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (failed > 0) {
|
|
130
|
+
console.error(`${failed} anything-path-measure test(s) failed`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
console.log(`anything-path-measure tests: ${tests.length} passed, 0 failed (offline: real hbcli runner never used)`);
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Read-only measurement of the external Anything path
|
|
4
|
+
* (hbcli -> hotel-be /api/search/anything), the evidence probe for two trigger trackers:
|
|
5
|
+
* #276 does the external path show a material latency/reliability bottleneck at scale?
|
|
6
|
+
* #345 what fields does Anything actually return for place-like queries (rating/photos/hours)?
|
|
7
|
+
*
|
|
8
|
+
* Discipline:
|
|
9
|
+
* - Opt-in only: without GOTRY_UAT_READONLY=1 it exits 0 with `waiting_external_evidence` and spawns nothing
|
|
10
|
+
* (CI-safe; same no-spend discipline as nightly-evidence.ts).
|
|
11
|
+
* - Read-only `search anything` calls against the environment hbcli is already authenticated for
|
|
12
|
+
* (flags fixed to `--json --env=uat`). It never reads, prints or persists credentials.
|
|
13
|
+
* - Prints aggregates only (latency percentiles, error counts, candidate-type counts, field-presence
|
|
14
|
+
* ratios). Raw responses are not persisted; failure details are scrubbed and truncated.
|
|
15
|
+
* - This MEASURES the real path. It does not satisfy either tracker's trigger: both need real M4
|
|
16
|
+
* usage evidence (and, for #345, founder approval of per-call billing).
|
|
17
|
+
*/
|
|
18
|
+
import { execFile } from 'node:child_process';
|
|
19
|
+
import { pathToFileURL } from 'node:url';
|
|
20
|
+
export const DEFAULT_KEYWORDS = [
|
|
21
|
+
'Dali', '大理', '洱海', 'Erhai', 'Lijiang', '丽江', 'Phuket', '普吉', 'Rawai', 'Krabi', '甲米',
|
|
22
|
+
'Shenzhen', '深圳', 'Hong Kong', '香港', 'Dubai', '迪拜', 'Kunming', '昆明', 'Bangkok', '曼谷',
|
|
23
|
+
'Tokyo', 'Paris', 'Hilton', 'Marriott', 'Old Town', 'Airport', 'Beach',
|
|
24
|
+
];
|
|
25
|
+
export const OPT_IN_ENV = 'GOTRY_UAT_READONLY';
|
|
26
|
+
export const CALL_TIMEOUT_MS = 60_000;
|
|
27
|
+
export const CONCURRENCY = 5;
|
|
28
|
+
/** Redact credential-looking material and bound the length of anything we keep from a failed call. */
|
|
29
|
+
export function scrub(text) {
|
|
30
|
+
return text
|
|
31
|
+
.replace(/(bearer|ticket|token|authorization|secret|api[-_ ]?key|password)\s*[:=]?\s*[^\s"',}]+/gi, '$1=<redacted>')
|
|
32
|
+
.replace(/\s+/g, ' ')
|
|
33
|
+
.trim()
|
|
34
|
+
.slice(0, 160);
|
|
35
|
+
}
|
|
36
|
+
/** Nearest-rank percentile; null for an empty sample. */
|
|
37
|
+
export function percentile(values, p) {
|
|
38
|
+
if (values.length === 0)
|
|
39
|
+
return null;
|
|
40
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
41
|
+
return sorted[Math.min(sorted.length - 1, Math.ceil((p / 100) * sorted.length) - 1)] ?? null;
|
|
42
|
+
}
|
|
43
|
+
export function latencyStats(results) {
|
|
44
|
+
const reasons = {};
|
|
45
|
+
for (const r of results)
|
|
46
|
+
if (!r.ok)
|
|
47
|
+
reasons[r.reason] = (reasons[r.reason] ?? 0) + 1;
|
|
48
|
+
const times = results.map((r) => r.ms);
|
|
49
|
+
return {
|
|
50
|
+
calls: results.length,
|
|
51
|
+
errors: results.filter((r) => !r.ok).length,
|
|
52
|
+
error_reasons: reasons,
|
|
53
|
+
p50_ms: percentile(times, 50),
|
|
54
|
+
p95_ms: percentile(times, 95),
|
|
55
|
+
max_ms: times.length ? Math.max(...times) : null,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function isPresent(value) {
|
|
59
|
+
if (value === null || value === undefined || value === '')
|
|
60
|
+
return false;
|
|
61
|
+
if (Array.isArray(value))
|
|
62
|
+
return value.length > 0;
|
|
63
|
+
if (typeof value === 'object')
|
|
64
|
+
return Object.keys(value).length > 0;
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
/** For each key seen on any object: how many of the n objects carry a non-empty value (`"52/55"`). */
|
|
68
|
+
export function fieldPresence(objects) {
|
|
69
|
+
const present = {};
|
|
70
|
+
const real = objects.filter((o) => o !== undefined && o !== null);
|
|
71
|
+
for (const o of real)
|
|
72
|
+
for (const [k, v] of Object.entries(o))
|
|
73
|
+
present[k] = (present[k] ?? 0) + (isPresent(v) ? 1 : 0);
|
|
74
|
+
const fields = {};
|
|
75
|
+
for (const k of Object.keys(present).sort())
|
|
76
|
+
fields[k] = `${present[k]}/${real.length}`;
|
|
77
|
+
return { n: real.length, fields };
|
|
78
|
+
}
|
|
79
|
+
/** Real runner: one hbcli call, classified, bounded, scrubbed. Never throws. */
|
|
80
|
+
export const hbcliRunner = (args) => new Promise((resolve) => {
|
|
81
|
+
const started = performance.now();
|
|
82
|
+
execFile('hbcli', ['--json', '--env=uat', 'search', 'anything', ...args], { timeout: CALL_TIMEOUT_MS, maxBuffer: 8 << 20 }, (error, stdout, stderr) => {
|
|
83
|
+
const ms = Math.round(performance.now() - started);
|
|
84
|
+
if (error) {
|
|
85
|
+
const killed = error.killed === true;
|
|
86
|
+
const code = error.code;
|
|
87
|
+
const reason = killed ? 'timeout' : typeof code === 'number' ? `exit_${code}` : 'spawn_error';
|
|
88
|
+
resolve({ ok: false, ms, reason, detail: scrub(String(stderr || stdout || error.message)) });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const parsed = JSON.parse(String(stdout));
|
|
93
|
+
resolve({ ok: true, ms, candidates: Array.isArray(parsed.candidates) ? parsed.candidates : [] });
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
resolve({ ok: false, ms, reason: 'non_json', detail: scrub(String(stdout)) });
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
async function sequential(run, keywords, extra) {
|
|
101
|
+
const out = [];
|
|
102
|
+
for (const kw of keywords)
|
|
103
|
+
out.push(await run([kw, ...extra]));
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
async function concurrent(run, keywords, width) {
|
|
107
|
+
const out = [];
|
|
108
|
+
for (let i = 0; i < keywords.length; i += width) {
|
|
109
|
+
out.push(...await Promise.all(keywords.slice(i, i + width).map((kw) => run([kw]))));
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
/** Pure given a runner and a clock: the whole measurement, no environment access. */
|
|
114
|
+
export async function measure(run, keywords = DEFAULT_KEYWORDS, now = () => new Date()) {
|
|
115
|
+
const mixed = await sequential(run, keywords, []);
|
|
116
|
+
const placeOnly = await sequential(run, keywords, ['--content-type', 'place']);
|
|
117
|
+
const burst = await concurrent(run, keywords, CONCURRENCY);
|
|
118
|
+
const mixedCandidates = mixed.flatMap((r) => (r.ok ? r.candidates : []));
|
|
119
|
+
const placeCandidates = placeOnly.flatMap((r) => (r.ok ? r.candidates : []));
|
|
120
|
+
const byType = {};
|
|
121
|
+
for (const c of mixedCandidates)
|
|
122
|
+
byType[c.type ?? 'unknown'] = (byType[c.type ?? 'unknown'] ?? 0) + 1;
|
|
123
|
+
const zeroPlace = placeOnly.filter((r) => r.ok && r.candidates.length === 0).length;
|
|
124
|
+
return {
|
|
125
|
+
state: 'measured',
|
|
126
|
+
measured_at: now().toISOString(),
|
|
127
|
+
hbcli_json_flags: '--json --env=uat',
|
|
128
|
+
sequential_mixed: latencyStats(mixed),
|
|
129
|
+
sequential_place_only: latencyStats(placeOnly),
|
|
130
|
+
concurrent_mixed: { ...latencyStats(burst), concurrency: CONCURRENCY },
|
|
131
|
+
mixed_candidates_by_type: byType,
|
|
132
|
+
place_only_total_candidates: placeCandidates.length,
|
|
133
|
+
keywords_with_zero_place_results: `${zeroPlace}/${keywords.length}`,
|
|
134
|
+
hotel_object_field_presence: fieldPresence(mixedCandidates.filter((c) => c.type === 'hotel').map((c) => c.hotel)),
|
|
135
|
+
city_region_field_presence: fieldPresence(mixedCandidates.filter((c) => c.type === 'city').map((c) => c.region)),
|
|
136
|
+
place_object_field_presence: fieldPresence(placeCandidates.map((c) => c.place)),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/** The opt-in gate: nothing is spawned unless the environment explicitly asks for it. */
|
|
140
|
+
export async function measureIfOptedIn(env, run) {
|
|
141
|
+
if (env[OPT_IN_ENV] !== '1') {
|
|
142
|
+
return { state: 'waiting_external_evidence', reason: `${OPT_IN_ENV}=1 not set; no hbcli process was spawned, nothing was measured` };
|
|
143
|
+
}
|
|
144
|
+
return measure(run);
|
|
145
|
+
}
|
|
146
|
+
if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
147
|
+
measureIfOptedIn(process.env, hbcliRunner).then((result) => {
|
|
148
|
+
console.log(JSON.stringify(result, null, 2));
|
|
149
|
+
});
|
|
150
|
+
}
|