@danceiny/gotry 0.0.1-rc.21 → 0.0.1-rc.24
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 +102 -194
- package/README.zh-CN.md +115 -210
- package/bin/gotry-backend.js +53 -0
- package/bin/gotry-bootstrap.js +466 -35
- package/bin/gotry-inner.js +255 -36
- package/bin/gotry-process-liveness.d.ts +27 -0
- package/bin/gotry-process-liveness.js +97 -0
- package/bin/gotry-runtime-resolution.d.ts +1 -1
- package/bin/gotry-runtime-resolution.js +2 -2
- package/client/client.js +174 -0
- package/cordis.gotry-patch.yml +70 -93
- package/dist/capabilities/agent-reach-deep.js +45 -122
- package/dist/capabilities/agent-reach.js +63 -148
- package/dist/capabilities/anything.js +89 -75
- package/dist/capabilities/artifacts.js +123 -104
- package/dist/capabilities/channel-health.js +65 -45
- package/dist/capabilities/channel-registry.js +108 -87
- package/dist/capabilities/doctor.js +357 -235
- package/dist/capabilities/effect.js +223 -309
- package/dist/capabilities/fact-log.js +28 -14
- package/dist/capabilities/flyai.js +245 -156
- package/dist/capabilities/ground-transfer.js +509 -0
- package/dist/capabilities/hbcli.js +144 -148
- package/dist/capabilities/hotelbyte-transaction.js +194 -0
- package/dist/capabilities/incident-log.js +131 -61
- package/dist/capabilities/model-override.js +30 -10
- package/dist/capabilities/opensky.js +54 -43
- package/dist/capabilities/resilience.js +50 -32
- package/dist/capabilities/session/action-cache.js +50 -44
- package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
- package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
- package/dist/capabilities/session/adapters/dida-portal.js +206 -0
- package/dist/capabilities/session/adapters/meituan-local.js +35 -54
- package/dist/capabilities/session/adapters/rail-12306.js +169 -112
- package/dist/capabilities/session/benchmark.js +85 -149
- package/dist/capabilities/session/extension-bridge.js +320 -259
- package/dist/capabilities/session/extension-channel.js +57 -76
- package/dist/capabilities/session/extension-distribution.js +115 -119
- package/dist/capabilities/session/extract.js +31 -21
- package/dist/capabilities/session/golden-score.js +55 -33
- package/dist/capabilities/session/health-watch.js +146 -154
- package/dist/capabilities/session/read-guard.js +55 -47
- package/dist/capabilities/session/static-flight-golden.js +49 -36
- package/dist/capabilities/session/transport.js +54 -61
- package/dist/capabilities/session/wizard.js +63 -93
- package/dist/capabilities/session-consent.js +143 -47
- package/dist/capabilities/session-login.js +95 -126
- package/dist/capabilities/session-search.js +391 -253
- package/dist/capabilities/sponsor-plugin.js +341 -0
- package/dist/capabilities/visa-policy.js +87 -73
- package/dist/capabilities/weather.js +163 -235
- package/dist/scripts/action-cache-tests.js +24 -59
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
- package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
- package/dist/scripts/agent-reach-deep-tests.js +30 -40
- package/dist/scripts/agent-reach-tests.js +26 -18
- package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
- package/dist/scripts/anything-tests.js +58 -62
- package/dist/scripts/artifact-client-contract-tests.js +69 -0
- package/dist/scripts/artifacts-capability-tests.js +235 -0
- package/dist/scripts/async-collect.js +26 -15
- package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
- package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
- package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
- package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
- package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
- package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
- 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 +61 -123
- package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
- package/dist/scripts/bootstrap-tests.js +1383 -128
- package/dist/scripts/build-changelog.js +89 -130
- package/dist/scripts/build-metrics-report.js +135 -143
- package/dist/scripts/changelog-tests.js +35 -82
- package/dist/scripts/channel-probe-tests.js +44 -116
- package/dist/scripts/channel-probe.js +84 -167
- package/dist/scripts/channel-registry-tests.js +97 -185
- package/dist/scripts/companion-tests.js +25 -70
- package/dist/scripts/dida-cookie-probe.js +87 -0
- package/dist/scripts/dida-sw-probe.js +114 -0
- package/dist/scripts/diff-test.js +17 -12
- package/dist/scripts/doctor-tests.js +428 -120
- package/dist/scripts/dsh-artifact-e2e.js +150 -0
- package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
- package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
- package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
- package/dist/scripts/dsh-runtime-closure.js +75 -63
- package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
- package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
- package/dist/scripts/dsh-target-closure-proof.js +178 -0
- package/dist/scripts/effect-tests.js +165 -552
- package/dist/scripts/engine-run.js +1 -3
- package/dist/scripts/engine-tests.js +16 -10
- package/dist/scripts/evaluation-cadence-tests.js +69 -242
- package/dist/scripts/evaluation-contract-tests.js +193 -499
- package/dist/scripts/extension-distribution-cli.js +19 -15
- package/dist/scripts/extension-distribution-tests.js +98 -211
- package/dist/scripts/extension-tests.js +366 -389
- package/dist/scripts/fact-gate-tests.js +725 -263
- 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-tests.js +325 -68
- 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/gotry-backend-kernel-tests.js +79 -0
- package/dist/scripts/ground-transfer-tests.js +956 -0
- package/dist/scripts/hbcli-e2e-tests.js +71 -90
- 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 +41 -115
- package/dist/scripts/health-watch-cli.js +42 -28
- 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 +16 -9
- 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 +547 -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/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/ledger-repair-apply-tests.js +316 -0
- package/dist/scripts/ledger-repair-plan-tests.js +375 -0
- package/dist/scripts/ledger-tests.js +325 -340
- package/dist/scripts/ledger-workflow-crash.js +10 -20
- package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
- 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 +474 -222
- package/dist/scripts/memory-value-tests.js +328 -0
- package/dist/scripts/metrics-report-tests.js +62 -199
- package/dist/scripts/model-override-e2e.js +66 -105
- package/dist/scripts/nightly-evidence-tests.js +64 -89
- package/dist/scripts/nightly-evidence.js +108 -111
- package/dist/scripts/nudge-digest.js +39 -28
- package/dist/scripts/onboarding-tests.js +63 -88
- package/dist/scripts/opensky-check.js +18 -13
- package/dist/scripts/opensky-tests.js +28 -28
- package/dist/scripts/persona-surface-guard-tests.js +37 -12
- package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
- package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
- package/dist/scripts/price-drift-tests.js +126 -227
- package/dist/scripts/price-drift-watch.js +209 -253
- package/dist/scripts/probe-poi-tests.js +52 -45
- package/dist/scripts/product-metrics.js +187 -273
- package/dist/scripts/publish-preverify.js +47 -41
- package/dist/scripts/realtime-pricing-tests.js +37 -76
- package/dist/scripts/replay-async.js +20 -18
- package/dist/scripts/replay-real.js +16 -18
- package/dist/scripts/replay.js +52 -82
- package/dist/scripts/session-attach-diagnose.js +16 -12
- package/dist/scripts/session-attach-poc.js +34 -37
- package/dist/scripts/session-benchmark.js +66 -147
- package/dist/scripts/session-dida-live-e2e.js +151 -0
- package/dist/scripts/session-extract-tests.js +14 -35
- package/dist/scripts/session-login.js +14 -13
- package/dist/scripts/session-tests.js +545 -583
- package/dist/scripts/sf-live-benchmark.js +92 -110
- package/dist/scripts/sf-live-cli-tests.js +2 -9
- package/dist/scripts/sf-soft-score-tests.js +19 -60
- package/dist/scripts/sf-summary-tests.js +149 -0
- package/dist/scripts/sf-summary.js +466 -84
- package/dist/scripts/skeleton-check.js +16 -14
- package/dist/scripts/skeleton-integration-test.js +11 -10
- package/dist/scripts/skills-contract-tests.js +51 -46
- package/dist/scripts/smoke-session-gate-tests.js +12 -20
- package/dist/scripts/smoke.js +541 -422
- package/dist/scripts/sponsor-reuse-tests.js +262 -0
- package/dist/scripts/state-cli-tests.js +226 -101
- package/dist/scripts/state-cli.js +549 -212
- package/dist/scripts/static-golden-tests.js +46 -180
- package/dist/scripts/time-eval-tests.js +210 -192
- package/dist/scripts/travel-timeline-tests.js +29 -93
- package/dist/scripts/turn-handoff-collect-tests.js +46 -93
- package/dist/scripts/turn-handoff-collect.js +71 -99
- package/dist/scripts/turn-policy-tests.js +28 -29
- package/dist/scripts/typed-contract-canary.js +77 -162
- 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 +31 -44
- package/dist/scripts/weather-tests.js +121 -543
- package/dist/scripts/wish-channel-gate-tests.js +29 -86
- 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 +18 -12
- package/dist/src/artifact-gate.js +652 -221
- package/dist/src/backend/kernel.js +91 -0
- package/dist/src/backend/modules/booking-copilot.js +55 -0
- package/dist/src/backend/modules/booking-executor.js +124 -0
- package/dist/src/backend/modules/session-search.js +194 -0
- package/dist/src/benchmark-agent-conformance.js +296 -262
- package/dist/src/benchmark-environment-bridge.js +298 -413
- package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
- package/dist/src/benchmark-tool-isolation.js +94 -67
- package/dist/src/bookable-facts.js +299 -174
- package/dist/src/booking-saga.js +64 -120
- package/dist/src/booking-surface/availability-policy.js +443 -576
- package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
- package/dist/src/booking-surface/contracts.js +24 -80
- package/dist/src/booking-surface/dsh-planner.js +510 -281
- package/dist/src/booking-surface/dsh-plugin.js +17 -1
- package/dist/src/booking-surface/error-codes.js +82 -10
- package/dist/src/booking-surface/index.js +0 -3
- package/dist/src/booking-surface/profile.js +10 -54
- package/dist/src/booking-surface/recovery-chain.js +367 -0
- package/dist/src/booking-surface/runtime.js +765 -891
- package/dist/src/booking-surface/server.js +200 -251
- package/dist/src/booking-surface/startup.js +58 -54
- package/dist/src/booking-surface/validation.js +150 -218
- package/dist/src/bridge.js +20 -13
- package/dist/src/companions.js +48 -74
- package/dist/src/contracts.js +21 -43
- package/dist/src/dsh-llm.js +82 -120
- package/dist/src/engine.js +253 -239
- package/dist/src/evaluation-cadence.js +72 -209
- package/dist/src/evaluation-contracts.js +220 -843
- package/dist/src/flight-pack-adapter.js +54 -0
- package/dist/src/flight-pack-contract.js +2 -0
- package/dist/src/gotry-backend.js +70 -0
- package/dist/src/hotel-date-gate.js +118 -0
- package/dist/src/i18n.js +18 -7
- package/dist/src/index.js +1425 -1629
- package/dist/src/journey.js +132 -81
- package/dist/src/ledger-repair-apply.js +538 -0
- package/dist/src/ledger-repair-plan.js +463 -0
- package/dist/src/loop.js +257 -166
- package/dist/src/memory-capture.js +180 -32
- package/dist/src/memory-decay.js +30 -14
- package/dist/src/memory-lifecycle.js +1310 -0
- package/dist/src/memory-utility.js +27 -40
- package/dist/src/mock-llm.js +36 -61
- package/dist/src/model.js +81 -36
- package/dist/src/realtime-pricing.js +63 -72
- package/dist/src/slot-spec.js +84 -106
- package/dist/src/state-ledger.js +310 -471
- 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 +121 -127
- package/dist/src/turn-policy.js +61 -89
- package/dist/src/tz-resolver.js +143 -0
- package/dist/src/unified.js +504 -381
- package/dist/src/wish-pool.js +39 -14
- package/dist/src/write-gate.js +495 -0
- package/dist/src/z3-shared.js +273 -7
- package/extension/README.md +4 -3
- package/extension/background.js +125 -14
- package/extension/content-bridge.js +23 -1
- package/extension/content-main.js +15 -4
- package/extension/manifest.json +16 -8
- package/package.json +251 -220
- package/ts/capabilities/agent-reach.ts +4 -4
- package/ts/capabilities/anything.ts +1 -1
- package/ts/capabilities/artifacts.ts +46 -9
- package/ts/capabilities/flyai.ts +156 -37
- package/ts/capabilities/hbcli.ts +1 -1
- package/ts/capabilities/incident-log.ts +88 -59
- package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
- package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
- package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
- package/ts/capabilities/session/extension-bridge.ts +226 -101
- package/ts/capabilities/session/extension-channel.ts +22 -9
- package/ts/capabilities/session/wizard.ts +2 -2
- package/ts/capabilities/session-consent.ts +98 -14
- package/ts/capabilities/session-login.ts +1 -0
- package/ts/capabilities/session-search.ts +315 -31
- package/ts/dsh-runtime/vendor/README.md +8 -4
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
- package/ts/package.json +236 -16
- package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
- package/ts/scripts/state-cli.ts +418 -51
- package/ts/src/artifact-gate.ts +561 -15
- package/ts/src/benchmark-environment-bridge.ts +37 -20
- package/ts/src/bookable-facts.ts +183 -7
- package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
- package/ts/src/booking-surface/dsh-planner.ts +240 -32
- package/ts/src/booking-surface/dsh-plugin.js +17 -1
- package/ts/src/booking-surface/error-codes.ts +75 -0
- package/ts/src/booking-surface/recovery-chain.ts +409 -0
- package/ts/src/booking-surface/server.ts +84 -51
- package/ts/src/booking-surface/validation.ts +2 -0
- package/ts/src/contracts.ts +12 -2
- package/ts/src/dsh-llm.ts +4 -8
- package/ts/src/index.ts +609 -90
- package/ts/src/loop.ts +116 -7
- package/ts/src/memory-capture.ts +227 -3
- package/ts/src/mock-llm.ts +4 -8
- package/ts/src/model.ts +88 -2
- package/ts/src/state-ledger.ts +47 -29
- package/ts/src/subagent-job-id-guard.ts +72 -0
- package/ts/src/time-anchor.ts +217 -13
- package/ts/src/unified.ts +316 -54
|
@@ -260,8 +260,6 @@ interface CollectedText {
|
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
interface SubprocessHandle {
|
|
263
|
-
/** DSH reports -1 when process creation itself failed. */
|
|
264
|
-
readonly pid: number
|
|
265
263
|
collected: { stdout: CollectedText; stderr: CollectedText }
|
|
266
264
|
done: Promise<{ exitCode: number | null; signal?: string | null }>
|
|
267
265
|
terminate?: () => void
|
|
@@ -461,22 +459,44 @@ export function registerBenchmarkEnvironmentBridge(
|
|
|
461
459
|
}
|
|
462
460
|
env.PYTHONDONTWRITEBYTECODE = '1'
|
|
463
461
|
env.PYTHONNOUSERSITE = '1'
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
462
|
+
try {
|
|
463
|
+
handle = subprocess.spawn({
|
|
464
|
+
argv: [bridge.executable, ...bridge.argv_prefix, 'call', tool, serialized.json!],
|
|
465
|
+
cwd: bridge.cwd,
|
|
466
|
+
stdio: {
|
|
467
|
+
stdin: 'ignore',
|
|
468
|
+
stdout: { maxBytes: bridge.max_output_bytes },
|
|
469
|
+
stderr: { maxBytes: bridge.max_output_bytes },
|
|
470
|
+
},
|
|
471
|
+
graceMs: Math.min(1_000, bridge.timeout_ms),
|
|
472
|
+
env,
|
|
473
|
+
signal: controller.signal,
|
|
474
|
+
})
|
|
475
|
+
} catch {
|
|
476
|
+
if (controller.signal.aborted) return jsonObject({ ok: false, error: 'timed_out' })
|
|
477
|
+
return jsonObject({ ok: false, error: 'spawn_failed' })
|
|
478
|
+
}
|
|
479
|
+
let status: { exitCode: number | null; signal?: string | null }
|
|
480
|
+
try {
|
|
481
|
+
status = await handle!.done
|
|
482
|
+
} catch {
|
|
483
|
+
if (controller.signal.aborted) return jsonObject({ ok: false, error: 'timed_out' })
|
|
484
|
+
return jsonObject({ ok: false, error: 'spawn_failed' })
|
|
485
|
+
}
|
|
477
486
|
if (controller.signal.aborted) return jsonObject({ ok: false, error: 'timed_out' })
|
|
478
|
-
|
|
479
|
-
|
|
487
|
+
let stdout: { text: string; lossy?: boolean }
|
|
488
|
+
let stderr: { text: string; lossy?: boolean }
|
|
489
|
+
try {
|
|
490
|
+
stdout = handle!.collected.stdout.readFrom(0)
|
|
491
|
+
stderr = handle!.collected.stderr.readFrom(0)
|
|
492
|
+
} catch {
|
|
493
|
+
return jsonObject({
|
|
494
|
+
ok: false,
|
|
495
|
+
error: 'runner_failed',
|
|
496
|
+
exit_code: status.exitCode,
|
|
497
|
+
signal: status.signal ?? null,
|
|
498
|
+
})
|
|
499
|
+
}
|
|
480
500
|
if (stdout.lossy || stderr.lossy) return jsonObject({ ok: false, error: 'output_truncated' })
|
|
481
501
|
if (status.exitCode !== 0) {
|
|
482
502
|
return jsonObject({
|
|
@@ -504,9 +524,6 @@ export function registerBenchmarkEnvironmentBridge(
|
|
|
504
524
|
if (!plainObject(visibleResult) && !Array.isArray(visibleResult)) return jsonObject({ ok: false, error: 'invalid_output' })
|
|
505
525
|
if (!inspectAllowedOutput(visibleResult, descriptor.output_keys)) return jsonObject({ ok: false, error: 'forbidden_output' })
|
|
506
526
|
return jsonObject({ ok: true, result: visibleResult })
|
|
507
|
-
} catch {
|
|
508
|
-
if (controller.signal.aborted) return jsonObject({ ok: false, error: 'timed_out' })
|
|
509
|
-
return jsonObject({ ok: false, error: !handle || handle.pid === -1 ? 'spawn_failed' : 'runner_failed' })
|
|
510
527
|
} finally {
|
|
511
528
|
clearTimeout(timer)
|
|
512
529
|
}
|
package/ts/src/bookable-facts.ts
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import { createHash } from 'node:crypto'
|
|
23
|
+
import { hasRecognizedAvailableSeat, validateTrainQueryResponseUrl, type SessionTrainOption } from '../capabilities/session/adapters/rail-12306.ts'
|
|
23
24
|
|
|
24
25
|
export const BOOKABLE_FACT_SCHEMA = 'gotry_bookable_fact.v1' as const
|
|
25
26
|
|
|
@@ -182,6 +183,25 @@ export interface SessionLikeResult {
|
|
|
182
183
|
options?: SessionLikeOption[]
|
|
183
184
|
}
|
|
184
185
|
|
|
186
|
+
/** 12306 exact-date fact freshness rule: capture must be non-future and <=15 minutes old. */
|
|
187
|
+
export const TRAIN_FACT_FRESHNESS_RULE = 'captured_at_non_future_and_max_age_15m' as const
|
|
188
|
+
export const TRAIN_FACT_MAX_AGE_MS = 15 * 60 * 1000
|
|
189
|
+
|
|
190
|
+
export interface SessionTrainFactResult {
|
|
191
|
+
outcome: {
|
|
192
|
+
kind: 'recognized-nonempty' | 'recognized-empty' | 'malformed' | 'transport-runtime-error'
|
|
193
|
+
trains?: SessionTrainOption[]
|
|
194
|
+
}
|
|
195
|
+
collection?: {
|
|
196
|
+
requested: { from: string; to: string; date: string }
|
|
197
|
+
request: { fromStationTelecode: string; toStationTelecode: string; date: string }
|
|
198
|
+
response: { url: string; fromStationTelecode: string; toStationTelecode: string; date: string }
|
|
199
|
+
batchId: string
|
|
200
|
+
queryId: string
|
|
201
|
+
fetchedAt: string
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
185
205
|
const YMD = /^\d{4}-\d{2}-\d{2}$/
|
|
186
206
|
|
|
187
207
|
function hmOf(dateTime: string | undefined): string | undefined {
|
|
@@ -289,6 +309,67 @@ export function factsFromSession(q: { origin: string; destination: string; date:
|
|
|
289
309
|
return facts
|
|
290
310
|
}
|
|
291
311
|
|
|
312
|
+
function trainCollectionIsFresh(
|
|
313
|
+
q: { from: string; to: string; date: string },
|
|
314
|
+
r: SessionTrainFactResult,
|
|
315
|
+
now: Date,
|
|
316
|
+
): r is SessionTrainFactResult & { collection: NonNullable<SessionTrainFactResult['collection']> } {
|
|
317
|
+
const c = r.collection
|
|
318
|
+
if (!c || !c.batchId.trim() || !c.queryId.trim() || c.queryId !== `session:12306-train:${c.batchId}`) return false
|
|
319
|
+
if (c.requested.from !== q.from || c.requested.to !== q.to || c.requested.date !== q.date) return false
|
|
320
|
+
if (!c.request || !c.response
|
|
321
|
+
|| c.request.date !== c.requested.date
|
|
322
|
+
|| c.response.fromStationTelecode !== c.request.fromStationTelecode
|
|
323
|
+
|| c.response.toStationTelecode !== c.request.toStationTelecode
|
|
324
|
+
|| c.response.date !== c.request.date
|
|
325
|
+
|| !validateTrainQueryResponseUrl(c.response.url, c.request).ok) return false
|
|
326
|
+
const fetchedMs = Date.parse(c.fetchedAt)
|
|
327
|
+
const nowMs = now.getTime()
|
|
328
|
+
if (!Number.isFinite(fetchedMs) || !Number.isFinite(nowMs)) return false
|
|
329
|
+
return fetchedMs <= nowMs && nowMs - fetchedMs <= TRAIN_FACT_MAX_AGE_MS
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** 12306 typed outcome → exact-date train facts.
|
|
333
|
+
* The converter never invents collection identity or timestamps: both must come
|
|
334
|
+
* from the session invocation binding. Only recognized-empty can create a
|
|
335
|
+
* negative fact. A recognized row needs Y plus a closed-set available seat token.
|
|
336
|
+
*/
|
|
337
|
+
export function factsFromSessionTrain(
|
|
338
|
+
q: { from: string; to: string; date: string },
|
|
339
|
+
r: SessionTrainFactResult,
|
|
340
|
+
now: Date = new Date(),
|
|
341
|
+
): FlightFact[] {
|
|
342
|
+
if (!trainCollectionIsFresh(q, r, now)) return []
|
|
343
|
+
const c = r.collection
|
|
344
|
+
const source = 'session:12306-train'
|
|
345
|
+
const fetchedAt = c.fetchedAt
|
|
346
|
+
if (r.outcome.kind === 'recognized-empty') {
|
|
347
|
+
return [negativeFact(c.queryId, 'train', q.from, q.to, q.date, source, fetchedAt)]
|
|
348
|
+
}
|
|
349
|
+
if (r.outcome.kind !== 'recognized-nonempty') return []
|
|
350
|
+
const facts: FlightFact[] = []
|
|
351
|
+
for (const o of r.outcome.trains ?? []) {
|
|
352
|
+
if (o.canWebBuy !== 'Y' || !hasRecognizedAvailableSeat(o)) continue
|
|
353
|
+
facts.push({
|
|
354
|
+
schema: BOOKABLE_FACT_SCHEMA,
|
|
355
|
+
fact_id: makeFactId(['train', q.from, q.to, q.date, o.trainCode, c.queryId]),
|
|
356
|
+
kind: 'train',
|
|
357
|
+
route: { origin: q.from, destination: q.to },
|
|
358
|
+
date: q.date,
|
|
359
|
+
flight_no: o.trainCode,
|
|
360
|
+
dep_local: o.depTime,
|
|
361
|
+
arr_local: o.arrTime,
|
|
362
|
+
tier: 'live_inventory',
|
|
363
|
+
bookability: 'bookable_exact_date',
|
|
364
|
+
source,
|
|
365
|
+
query_id: c.queryId,
|
|
366
|
+
fetched_at: fetchedAt,
|
|
367
|
+
as_of: fetchedAt.slice(0, 10),
|
|
368
|
+
})
|
|
369
|
+
}
|
|
370
|
+
return facts
|
|
371
|
+
}
|
|
372
|
+
|
|
292
373
|
// ---------------------------------------------------------------------------
|
|
293
374
|
// 注册表(纯函数视图;持久化在 capabilities/fact-log.ts)
|
|
294
375
|
// ---------------------------------------------------------------------------
|
|
@@ -304,9 +385,13 @@ export function dedupeFacts<T extends BookableFact>(facts: T[]): T[] {
|
|
|
304
385
|
}
|
|
305
386
|
|
|
306
387
|
/** route+date 的最新查询结论(同日多次查询:最新一次为准,避免「昨天 miss 今天 hit」陈旧否定) */
|
|
307
|
-
export function latestFactsForRouteDate(
|
|
388
|
+
export function latestFactsForRouteDate(
|
|
389
|
+
facts: BookableFact[], origin: string, destination: string, date: string,
|
|
390
|
+
kind?: 'flight' | 'train',
|
|
391
|
+
): FlightFact[] {
|
|
308
392
|
const hits = facts.filter((f): f is FlightFact =>
|
|
309
393
|
(f.kind === 'flight' || f.kind === 'train')
|
|
394
|
+
&& (!kind || f.kind === kind)
|
|
310
395
|
&& f.route.origin === origin && f.route.destination === destination && f.date === date)
|
|
311
396
|
const latestQueryTs = new Map<string, string>()
|
|
312
397
|
for (const f of hits) {
|
|
@@ -319,7 +404,7 @@ export function latestFactsForRouteDate(facts: BookableFact[], origin: string, d
|
|
|
319
404
|
}
|
|
320
405
|
|
|
321
406
|
// ---------------------------------------------------------------------------
|
|
322
|
-
// 判定原语①:航班 claim 可述性(fail closed)
|
|
407
|
+
// 判定原语①:航班 claim 可述性(fail closed,flight-only)
|
|
323
408
|
// ---------------------------------------------------------------------------
|
|
324
409
|
|
|
325
410
|
export type FlightClaimVerdict =
|
|
@@ -335,10 +420,16 @@ export interface FlightClaim {
|
|
|
335
420
|
date?: string
|
|
336
421
|
}
|
|
337
422
|
|
|
423
|
+
/**
|
|
424
|
+
* 航班 claim 裁决(flight-only):注册表只接受 `kind:'flight'` 的同号事实
|
|
425
|
+
* ——train 事实走 `railClaimVerdict` 独立裁决,不得混入航班 not_in_source
|
|
426
|
+
* 路径(issue #299)。中文高铁/动车/城际/直达代码(G/D/C/Z + 3–4 位)在
|
|
427
|
+
* 闸侧 `extractClaims` 已分流到 `trains` claim,本函数无需再做扩展。
|
|
428
|
+
*/
|
|
338
429
|
export function flightClaimVerdict(facts: BookableFact[], claim: FlightClaim): { verdict: FlightClaimVerdict; fact?: FlightFact; reason: string } {
|
|
339
430
|
const no = claim.flight_no.toUpperCase().replace(/\s+/g, '')
|
|
340
431
|
const sameNo = facts.filter((f): f is FlightFact =>
|
|
341
|
-
|
|
432
|
+
f.kind === 'flight' && f.flight_no.toUpperCase() === no && f.bookability === 'bookable_exact_date')
|
|
342
433
|
const routeMatched = sameNo.filter(f =>
|
|
343
434
|
(!claim.origin || f.route.origin === claim.origin || f.route.origin_airport === claim.origin)
|
|
344
435
|
&& (!claim.destination || f.route.destination === claim.destination || f.route.dest_airport === claim.destination)
|
|
@@ -346,7 +437,7 @@ export function flightClaimVerdict(facts: BookableFact[], claim: FlightClaim): {
|
|
|
346
437
|
if (routeMatched.length > 0) return { verdict: 'traceable', fact: routeMatched[0], reason: `回溯 ${routeMatched[0]!.query_id}` }
|
|
347
438
|
// 无同号可下单事实:该 route+date 是否查过?
|
|
348
439
|
if (claim.origin && claim.destination && claim.date) {
|
|
349
|
-
const scoped = latestFactsForRouteDate(facts, claim.origin, claim.destination, claim.date)
|
|
440
|
+
const scoped = latestFactsForRouteDate(facts, claim.origin, claim.destination, claim.date, 'flight')
|
|
350
441
|
if (scoped.length > 0) {
|
|
351
442
|
return {
|
|
352
443
|
verdict: 'not_in_source',
|
|
@@ -360,6 +451,63 @@ export function flightClaimVerdict(facts: BookableFact[], claim: FlightClaim): {
|
|
|
360
451
|
return { verdict: 'route_unqueried', reason: `航班 ${no} 无可回溯的 exact-date 事实(缺 route/date 上下文)` }
|
|
361
452
|
}
|
|
362
453
|
|
|
454
|
+
// ---------------------------------------------------------------------------
|
|
455
|
+
// 判定原语①b:车次 claim 可述性(rail-only,fail closed;issue #299)
|
|
456
|
+
// 闸侧 `extractClaims` 已把 G/D/C/Z + 3–4 位 token 收集为 train claim;
|
|
457
|
+
// 本裁决只在 train 事实里查同号 bookable_exact_date,缺事实/缺上下文/
|
|
458
|
+
// 路线未查均 fail-closed。支持的事实生产端是 `factsFromFlyai kind:'train'`
|
|
459
|
+
// 与 `factsFromSessionTrain`,两者均经真实工具路径追加到事实日志; session
|
|
460
|
+
// 结果必须先通过 typed parser outcome + seat availability/freshness contract。
|
|
461
|
+
// 不得用历史班期或 static-schedule 凑合格回溯。
|
|
462
|
+
// ---------------------------------------------------------------------------
|
|
463
|
+
|
|
464
|
+
export type RailClaimVerdict =
|
|
465
|
+
| 'traceable' // 注册表内有 bookable_exact_date 的该 train 事实(同号+同 route+同 date)
|
|
466
|
+
| 'not_in_source' // 该 route+date 查过 exact-date,结果里没有它——最强违例
|
|
467
|
+
| 'route_unqueried' // 该 route+date 从未查过 exact-date——无证据断言
|
|
468
|
+
| 'rail_claim_unverified' // 缺 route/date 上下文,或缺同号事实且 route/date 无 exact-date 证据
|
|
469
|
+
|
|
470
|
+
export interface RailClaim {
|
|
471
|
+
flight_no: string
|
|
472
|
+
origin?: string
|
|
473
|
+
destination?: string
|
|
474
|
+
date?: string
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const TRAIN_FACT_SOURCES = new Set(['flyai', 'session:12306-train'])
|
|
478
|
+
|
|
479
|
+
function isStructuredTrainFact(f: BookableFact): f is FlightFact {
|
|
480
|
+
return f.kind === 'train'
|
|
481
|
+
&& f.schema === BOOKABLE_FACT_SCHEMA
|
|
482
|
+
&& TRAIN_FACT_SOURCES.has(f.source)
|
|
483
|
+
&& f.query_id.trim().length > 0
|
|
484
|
+
&& f.tier === 'live_inventory'
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export function railClaimVerdict(facts: BookableFact[], claim: RailClaim): { verdict: RailClaimVerdict; fact?: FlightFact; reason: string } {
|
|
488
|
+
const no = claim.flight_no.toUpperCase().replace(/\s+/g, '')
|
|
489
|
+
if (!claim.origin || !claim.destination || !claim.date) {
|
|
490
|
+
return { verdict: 'rail_claim_unverified', reason: `车次 ${no} 无可回溯的 exact-date 事实(缺完整 route/date 上下文)` }
|
|
491
|
+
}
|
|
492
|
+
// 先按 train kind 选择该 route+date 的最新查询批次,再在该批次匹配车次。
|
|
493
|
+
// 这样旧 hit 不会越过更新的 miss/unavailable,flight 批次也不能遮蔽 train 批次。
|
|
494
|
+
const scoped = latestFactsForRouteDate(facts, claim.origin, claim.destination, claim.date, 'train')
|
|
495
|
+
.filter(isStructuredTrainFact)
|
|
496
|
+
const sameNo = scoped.filter(f =>
|
|
497
|
+
f.flight_no.toUpperCase() === no
|
|
498
|
+
&& f.bookability === 'bookable_exact_date')
|
|
499
|
+
if (sameNo.length > 0) return { verdict: 'traceable', fact: sameNo[0], reason: `回溯 ${sameNo[0]!.query_id}` }
|
|
500
|
+
if (scoped.length > 0) {
|
|
501
|
+
return {
|
|
502
|
+
verdict: 'not_in_source',
|
|
503
|
+
reason: scoped.some(f => f.bookability === 'unavailable_exact_date')
|
|
504
|
+
? `${claim.origin}→${claim.destination} ${claim.date} train exact-date 源返回 0 条(${scoped[0]!.query_id})——不得用历史班期/相邻日期填充`
|
|
505
|
+
: `${claim.origin}→${claim.destination} ${claim.date} train exact-date 源在架 ${scoped.filter(f => f.bookability === 'bookable_exact_date').map(f => f.flight_no).join('/')}——无 ${no}`,
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return { verdict: 'route_unqueried', reason: `${claim.origin}→${claim.destination} ${claim.date} train 路线从未经 exact-date 源核验` }
|
|
509
|
+
}
|
|
510
|
+
|
|
363
511
|
// ---------------------------------------------------------------------------
|
|
364
512
|
// 判定原语②:同日衔接硬约束(办事结束 → 门到机场 → 值机截止 → 起飞)
|
|
365
513
|
// ---------------------------------------------------------------------------
|
|
@@ -405,7 +553,7 @@ export function checkSameDayDeparture(
|
|
|
405
553
|
c: SameDayDepartureConstraint,
|
|
406
554
|
): SameDayDepartureVerdict {
|
|
407
555
|
const earliest = hmToMin(c.errand_end_local) + c.airport_transit_min + c.checkin_deadline_min
|
|
408
|
-
const scoped = latestFactsForRouteDate(facts, q.origin, q.destination, q.date)
|
|
556
|
+
const scoped = latestFactsForRouteDate(facts, q.origin, q.destination, q.date, 'flight')
|
|
409
557
|
const nonstopBookable = scoped.filter(f => f.bookability === 'bookable_exact_date' && f.nonstop !== false)
|
|
410
558
|
const feasible: FlightFact[] = []
|
|
411
559
|
const excluded: Array<{ flight_no: string; reason: string }> = []
|
|
@@ -526,8 +674,9 @@ export function defaultReviewBy(tripDate: string): string {
|
|
|
526
674
|
}
|
|
527
675
|
|
|
528
676
|
/**
|
|
529
|
-
*
|
|
530
|
-
*
|
|
677
|
+
* 航班/车次事实行。bookable_exact_date 才允许完整班次行;其余一律 fail-closed 措辞。
|
|
678
|
+
* train 复用此 canonical renderer 但只输出车次语义,不输出直飞或价格;永不输出无条件 ✓;
|
|
679
|
+
* 证据链(source/query_id/fetched_at)随行必达。
|
|
531
680
|
*/
|
|
532
681
|
export function renderFlightFact(f: FlightFact): string {
|
|
533
682
|
return renderFlightFactInner(f) + ` <!-- fact:${f.fact_id} -->`
|
|
@@ -538,6 +687,13 @@ function renderFlightFactInner(f: FlightFact): string {
|
|
|
538
687
|
const anchor = ` <!-- fact:${f.fact_id} -->`
|
|
539
688
|
const route = `${f.route.origin}→${f.route.destination}`
|
|
540
689
|
const evidence = `[${f.source}@${f.fetched_at} #${f.query_id}]`
|
|
690
|
+
if (f.kind === 'train' && f.bookability === 'unavailable_exact_date') {
|
|
691
|
+
const review = f.review_by ?? defaultReviewBy(f.date)
|
|
692
|
+
return `- ${route} ${f.date} 车次${f.flight_no ? ` ${f.flight_no}` : ''}:**未确认/当前不可售**——exact-date 源 ${f.source} 于 ${f.fetched_at.slice(0, 10)} 返回 0 条;到 ${review} 复核,不得用历史班期/相邻日期填充 ${evidence}`
|
|
693
|
+
}
|
|
694
|
+
if (f.kind === 'train' && f.bookability !== 'bookable_exact_date') {
|
|
695
|
+
return `- ${route} ${f.date} 车次${f.flight_no ? ` ${f.flight_no}` : ''}:**未核验**(${f.bookability})——仅作参考,不得作为可下单方案呈现 ${evidence}`
|
|
696
|
+
}
|
|
541
697
|
if (f.bookability === 'unavailable_exact_date') {
|
|
542
698
|
const review = f.review_by ?? defaultReviewBy(f.date)
|
|
543
699
|
return `- ${route} ${f.date}:**未确认/当前不可售**——exact-date 源 ${f.source} 于 ${f.fetched_at.slice(0, 10)} 返回 0 条;到 ${review} 复核,不得用历史班期/相邻日期填充 ${evidence}`
|
|
@@ -545,6 +701,10 @@ function renderFlightFactInner(f: FlightFact): string {
|
|
|
545
701
|
if (f.bookability !== 'bookable_exact_date') {
|
|
546
702
|
return `- ${route} ${f.date} ${f.flight_no || ''}:**未核验**(${f.bookability})——仅作参考,不得作为可下单方案呈现 ${evidence}`
|
|
547
703
|
}
|
|
704
|
+
if (f.kind === 'train') {
|
|
705
|
+
const times = f.dep_local && f.arr_local ? ` ${f.dep_local}→${f.arr_local}` : ''
|
|
706
|
+
return `- ${route} ${f.date} 车次 ${f.flight_no}${times} ${evidence}`
|
|
707
|
+
}
|
|
548
708
|
const carrier = f.operating_carrier && f.operating_carrier !== f.marketing_carrier
|
|
549
709
|
? `营销 ${f.marketing_carrier ?? '?'} / 实际承运 ${f.operating_carrier}`
|
|
550
710
|
: (f.marketing_carrier ?? '')
|
|
@@ -574,8 +734,24 @@ export function renderConnection(legA: FlightFact, legB: FlightFact): string {
|
|
|
574
734
|
/**
|
|
575
735
|
* 政策事实行:恒为「截至 as_of 的现行政策」表述 + 复核 gate,永不用无条件 ✓。
|
|
576
736
|
* 远期(出发日晚于 as_of)必须附 review_by(默认 D-30)。
|
|
737
|
+
*
|
|
738
|
+
* 行尾内嵌 `<!-- fact:<fact_id> -->` 锚点(issue #273,ADR-19 typed-anchor 单向生成):
|
|
739
|
+
* 产物经渲染原语生成即自带溯源锚,闸侧锚点确定性回溯;手改/伪造锚点 = fact_anchor_unknown。
|
|
740
|
+
* 与 renderFlightFact / renderHotelFact 同源:启发式 POLICY_WORD 仅覆盖手写/历史产物。
|
|
577
741
|
*/
|
|
578
742
|
export function renderPolicyFact(p: PolicyFact, tripStart?: string): string {
|
|
743
|
+
return `${policyCanonicalBody(p, tripStart)} <!-- fact:${p.fact_id} -->`
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* 政策行 canonical body(不含锚点;issue #359,D-26 残余收口):
|
|
748
|
+
* 闸侧锚点回溯用同一原文,subject/statement/source/fetched_at/query_id 任意一项
|
|
749
|
+
* 改动 → 行文本不再等于 canonical body → fact_anchor_unknown fail-closed。
|
|
750
|
+
* 不走宽松 substring/subset 匹配,避免锚点行被改写 subject/statement 后仍 pass。
|
|
751
|
+
* 复核提醒(review_by 或 tripStart 派生的 defaultReviewBy)是合法的可选段——
|
|
752
|
+
* `tripStart` 与 renderPolicyFact 同一传入,产物与闸两侧语义一致。
|
|
753
|
+
*/
|
|
754
|
+
export function policyCanonicalBody(p: PolicyFact, tripStart?: string): string {
|
|
579
755
|
const review = p.review_by ?? (tripStart ? defaultReviewBy(tripStart) : undefined)
|
|
580
756
|
const reviewNote = review ? `;远期政策须复核——到 ${review} 再核验一次` : ''
|
|
581
757
|
return `- ${p.subject}:截至 ${p.as_of} 的现行政策——${p.statement}${reviewNote} [${p.source}@${p.fetched_at} #${p.query_id}]`
|