@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.
Files changed (327) hide show
  1. package/README.md +102 -194
  2. package/README.zh-CN.md +115 -210
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-bootstrap.js +466 -35
  5. package/bin/gotry-inner.js +255 -36
  6. package/bin/gotry-process-liveness.d.ts +27 -0
  7. package/bin/gotry-process-liveness.js +97 -0
  8. package/bin/gotry-runtime-resolution.d.ts +1 -1
  9. package/bin/gotry-runtime-resolution.js +2 -2
  10. package/client/client.js +174 -0
  11. package/cordis.gotry-patch.yml +70 -93
  12. package/dist/capabilities/agent-reach-deep.js +45 -122
  13. package/dist/capabilities/agent-reach.js +63 -148
  14. package/dist/capabilities/anything.js +89 -75
  15. package/dist/capabilities/artifacts.js +123 -104
  16. package/dist/capabilities/channel-health.js +65 -45
  17. package/dist/capabilities/channel-registry.js +108 -87
  18. package/dist/capabilities/doctor.js +357 -235
  19. package/dist/capabilities/effect.js +223 -309
  20. package/dist/capabilities/fact-log.js +28 -14
  21. package/dist/capabilities/flyai.js +245 -156
  22. package/dist/capabilities/ground-transfer.js +509 -0
  23. package/dist/capabilities/hbcli.js +144 -148
  24. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  25. package/dist/capabilities/incident-log.js +131 -61
  26. package/dist/capabilities/model-override.js +30 -10
  27. package/dist/capabilities/opensky.js +54 -43
  28. package/dist/capabilities/resilience.js +50 -32
  29. package/dist/capabilities/session/action-cache.js +50 -44
  30. package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
  31. package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
  32. package/dist/capabilities/session/adapters/dida-portal.js +206 -0
  33. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  34. package/dist/capabilities/session/adapters/rail-12306.js +169 -112
  35. package/dist/capabilities/session/benchmark.js +85 -149
  36. package/dist/capabilities/session/extension-bridge.js +320 -259
  37. package/dist/capabilities/session/extension-channel.js +57 -76
  38. package/dist/capabilities/session/extension-distribution.js +115 -119
  39. package/dist/capabilities/session/extract.js +31 -21
  40. package/dist/capabilities/session/golden-score.js +55 -33
  41. package/dist/capabilities/session/health-watch.js +146 -154
  42. package/dist/capabilities/session/read-guard.js +55 -47
  43. package/dist/capabilities/session/static-flight-golden.js +49 -36
  44. package/dist/capabilities/session/transport.js +54 -61
  45. package/dist/capabilities/session/wizard.js +63 -93
  46. package/dist/capabilities/session-consent.js +143 -47
  47. package/dist/capabilities/session-login.js +95 -126
  48. package/dist/capabilities/session-search.js +391 -253
  49. package/dist/capabilities/sponsor-plugin.js +341 -0
  50. package/dist/capabilities/visa-policy.js +87 -73
  51. package/dist/capabilities/weather.js +163 -235
  52. package/dist/scripts/action-cache-tests.js +24 -59
  53. package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
  54. package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
  55. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  56. package/dist/scripts/agent-reach-tests.js +26 -18
  57. package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
  58. package/dist/scripts/anything-tests.js +58 -62
  59. package/dist/scripts/artifact-client-contract-tests.js +69 -0
  60. package/dist/scripts/artifacts-capability-tests.js +235 -0
  61. package/dist/scripts/async-collect.js +26 -15
  62. package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
  63. package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
  64. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
  65. package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
  66. package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
  67. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
  68. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
  69. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
  70. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
  71. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
  72. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
  73. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
  74. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
  75. package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
  76. package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
  77. package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
  78. package/dist/scripts/booking-executor-tests.js +80 -0
  79. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  80. package/dist/scripts/booking-saga-tests.js +61 -123
  81. package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
  82. package/dist/scripts/bootstrap-tests.js +1383 -128
  83. package/dist/scripts/build-changelog.js +89 -130
  84. package/dist/scripts/build-metrics-report.js +135 -143
  85. package/dist/scripts/changelog-tests.js +35 -82
  86. package/dist/scripts/channel-probe-tests.js +44 -116
  87. package/dist/scripts/channel-probe.js +84 -167
  88. package/dist/scripts/channel-registry-tests.js +97 -185
  89. package/dist/scripts/companion-tests.js +25 -70
  90. package/dist/scripts/dida-cookie-probe.js +87 -0
  91. package/dist/scripts/dida-sw-probe.js +114 -0
  92. package/dist/scripts/diff-test.js +17 -12
  93. package/dist/scripts/doctor-tests.js +428 -120
  94. package/dist/scripts/dsh-artifact-e2e.js +150 -0
  95. package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
  96. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  97. package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
  98. package/dist/scripts/dsh-runtime-closure.js +75 -63
  99. package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
  100. package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
  101. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  102. package/dist/scripts/effect-tests.js +165 -552
  103. package/dist/scripts/engine-run.js +1 -3
  104. package/dist/scripts/engine-tests.js +16 -10
  105. package/dist/scripts/evaluation-cadence-tests.js +69 -242
  106. package/dist/scripts/evaluation-contract-tests.js +193 -499
  107. package/dist/scripts/extension-distribution-cli.js +19 -15
  108. package/dist/scripts/extension-distribution-tests.js +98 -211
  109. package/dist/scripts/extension-tests.js +366 -389
  110. package/dist/scripts/fact-gate-tests.js +725 -263
  111. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  112. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  113. package/dist/scripts/flight-malformed-tests.js +159 -0
  114. package/dist/scripts/flyai-tests.js +325 -68
  115. package/dist/scripts/g5-guard-tests.js +131 -0
  116. package/dist/scripts/g5-guard.js +189 -0
  117. package/dist/scripts/gen-lunar-anchors.js +106 -0
  118. package/dist/scripts/gotry-backend-kernel-tests.js +79 -0
  119. package/dist/scripts/ground-transfer-tests.js +956 -0
  120. package/dist/scripts/hbcli-e2e-tests.js +71 -90
  121. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  122. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  123. package/dist/scripts/hbcli-tests.js +41 -115
  124. package/dist/scripts/health-watch-cli.js +42 -28
  125. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  126. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  127. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  128. package/dist/scripts/i18n-tests.js +16 -9
  129. package/dist/scripts/incident-tests.js +281 -87
  130. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  131. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  132. package/dist/scripts/issue-271-liveness-tests.js +547 -0
  133. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  134. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  135. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  136. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  137. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  138. package/dist/scripts/journey-tests.js +22 -27
  139. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  140. package/dist/scripts/kernel-manifest-gate.js +126 -0
  141. package/dist/scripts/kernel-manifest-tests.js +212 -0
  142. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  143. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  144. package/dist/scripts/kernel-manifest.js +369 -0
  145. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  146. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  147. package/dist/scripts/ledger-tests.js +325 -340
  148. package/dist/scripts/ledger-workflow-crash.js +10 -20
  149. package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
  150. package/dist/scripts/memory-capture-tests.js +242 -61
  151. package/dist/scripts/memory-decay-tests.js +18 -52
  152. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  153. package/dist/scripts/memory-lifecycle.js +196 -0
  154. package/dist/scripts/memory-metrics.js +24 -12
  155. package/dist/scripts/memory-value-report.js +474 -222
  156. package/dist/scripts/memory-value-tests.js +328 -0
  157. package/dist/scripts/metrics-report-tests.js +62 -199
  158. package/dist/scripts/model-override-e2e.js +66 -105
  159. package/dist/scripts/nightly-evidence-tests.js +64 -89
  160. package/dist/scripts/nightly-evidence.js +108 -111
  161. package/dist/scripts/nudge-digest.js +39 -28
  162. package/dist/scripts/onboarding-tests.js +63 -88
  163. package/dist/scripts/opensky-check.js +18 -13
  164. package/dist/scripts/opensky-tests.js +28 -28
  165. package/dist/scripts/persona-surface-guard-tests.js +37 -12
  166. package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
  167. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  168. package/dist/scripts/price-drift-tests.js +126 -227
  169. package/dist/scripts/price-drift-watch.js +209 -253
  170. package/dist/scripts/probe-poi-tests.js +52 -45
  171. package/dist/scripts/product-metrics.js +187 -273
  172. package/dist/scripts/publish-preverify.js +47 -41
  173. package/dist/scripts/realtime-pricing-tests.js +37 -76
  174. package/dist/scripts/replay-async.js +20 -18
  175. package/dist/scripts/replay-real.js +16 -18
  176. package/dist/scripts/replay.js +52 -82
  177. package/dist/scripts/session-attach-diagnose.js +16 -12
  178. package/dist/scripts/session-attach-poc.js +34 -37
  179. package/dist/scripts/session-benchmark.js +66 -147
  180. package/dist/scripts/session-dida-live-e2e.js +151 -0
  181. package/dist/scripts/session-extract-tests.js +14 -35
  182. package/dist/scripts/session-login.js +14 -13
  183. package/dist/scripts/session-tests.js +545 -583
  184. package/dist/scripts/sf-live-benchmark.js +92 -110
  185. package/dist/scripts/sf-live-cli-tests.js +2 -9
  186. package/dist/scripts/sf-soft-score-tests.js +19 -60
  187. package/dist/scripts/sf-summary-tests.js +149 -0
  188. package/dist/scripts/sf-summary.js +466 -84
  189. package/dist/scripts/skeleton-check.js +16 -14
  190. package/dist/scripts/skeleton-integration-test.js +11 -10
  191. package/dist/scripts/skills-contract-tests.js +51 -46
  192. package/dist/scripts/smoke-session-gate-tests.js +12 -20
  193. package/dist/scripts/smoke.js +541 -422
  194. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  195. package/dist/scripts/state-cli-tests.js +226 -101
  196. package/dist/scripts/state-cli.js +549 -212
  197. package/dist/scripts/static-golden-tests.js +46 -180
  198. package/dist/scripts/time-eval-tests.js +210 -192
  199. package/dist/scripts/travel-timeline-tests.js +29 -93
  200. package/dist/scripts/turn-handoff-collect-tests.js +46 -93
  201. package/dist/scripts/turn-handoff-collect.js +71 -99
  202. package/dist/scripts/turn-policy-tests.js +28 -29
  203. package/dist/scripts/typed-contract-canary.js +77 -162
  204. package/dist/scripts/tz-resolver-sanity.js +50 -0
  205. package/dist/scripts/tz-resolver-tests.js +584 -0
  206. package/dist/scripts/unified-tests.js +23 -19
  207. package/dist/scripts/visa-policy-tests.js +31 -44
  208. package/dist/scripts/weather-tests.js +121 -543
  209. package/dist/scripts/wish-channel-gate-tests.js +29 -86
  210. package/dist/scripts/write-gate-tests.js +522 -0
  211. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  212. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  213. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  214. package/dist/scripts/z3-race-tests.js +18 -12
  215. package/dist/src/artifact-gate.js +652 -221
  216. package/dist/src/backend/kernel.js +91 -0
  217. package/dist/src/backend/modules/booking-copilot.js +55 -0
  218. package/dist/src/backend/modules/booking-executor.js +124 -0
  219. package/dist/src/backend/modules/session-search.js +194 -0
  220. package/dist/src/benchmark-agent-conformance.js +296 -262
  221. package/dist/src/benchmark-environment-bridge.js +298 -413
  222. package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
  223. package/dist/src/benchmark-tool-isolation.js +94 -67
  224. package/dist/src/bookable-facts.js +299 -174
  225. package/dist/src/booking-saga.js +64 -120
  226. package/dist/src/booking-surface/availability-policy.js +443 -576
  227. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  228. package/dist/src/booking-surface/contracts.js +24 -80
  229. package/dist/src/booking-surface/dsh-planner.js +510 -281
  230. package/dist/src/booking-surface/dsh-plugin.js +17 -1
  231. package/dist/src/booking-surface/error-codes.js +82 -10
  232. package/dist/src/booking-surface/index.js +0 -3
  233. package/dist/src/booking-surface/profile.js +10 -54
  234. package/dist/src/booking-surface/recovery-chain.js +367 -0
  235. package/dist/src/booking-surface/runtime.js +765 -891
  236. package/dist/src/booking-surface/server.js +200 -251
  237. package/dist/src/booking-surface/startup.js +58 -54
  238. package/dist/src/booking-surface/validation.js +150 -218
  239. package/dist/src/bridge.js +20 -13
  240. package/dist/src/companions.js +48 -74
  241. package/dist/src/contracts.js +21 -43
  242. package/dist/src/dsh-llm.js +82 -120
  243. package/dist/src/engine.js +253 -239
  244. package/dist/src/evaluation-cadence.js +72 -209
  245. package/dist/src/evaluation-contracts.js +220 -843
  246. package/dist/src/flight-pack-adapter.js +54 -0
  247. package/dist/src/flight-pack-contract.js +2 -0
  248. package/dist/src/gotry-backend.js +70 -0
  249. package/dist/src/hotel-date-gate.js +118 -0
  250. package/dist/src/i18n.js +18 -7
  251. package/dist/src/index.js +1425 -1629
  252. package/dist/src/journey.js +132 -81
  253. package/dist/src/ledger-repair-apply.js +538 -0
  254. package/dist/src/ledger-repair-plan.js +463 -0
  255. package/dist/src/loop.js +257 -166
  256. package/dist/src/memory-capture.js +180 -32
  257. package/dist/src/memory-decay.js +30 -14
  258. package/dist/src/memory-lifecycle.js +1310 -0
  259. package/dist/src/memory-utility.js +27 -40
  260. package/dist/src/mock-llm.js +36 -61
  261. package/dist/src/model.js +81 -36
  262. package/dist/src/realtime-pricing.js +63 -72
  263. package/dist/src/slot-spec.js +84 -106
  264. package/dist/src/state-ledger.js +310 -471
  265. package/dist/src/subagent-job-id-guard.js +58 -0
  266. package/dist/src/time-anchor.js +231 -33
  267. package/dist/src/tool-packet.js +20 -8
  268. package/dist/src/travel-slots.js +58 -35
  269. package/dist/src/travel-timeline.js +44 -63
  270. package/dist/src/turn-deadline.js +121 -127
  271. package/dist/src/turn-policy.js +61 -89
  272. package/dist/src/tz-resolver.js +143 -0
  273. package/dist/src/unified.js +504 -381
  274. package/dist/src/wish-pool.js +39 -14
  275. package/dist/src/write-gate.js +495 -0
  276. package/dist/src/z3-shared.js +273 -7
  277. package/extension/README.md +4 -3
  278. package/extension/background.js +125 -14
  279. package/extension/content-bridge.js +23 -1
  280. package/extension/content-main.js +15 -4
  281. package/extension/manifest.json +16 -8
  282. package/package.json +251 -220
  283. package/ts/capabilities/agent-reach.ts +4 -4
  284. package/ts/capabilities/anything.ts +1 -1
  285. package/ts/capabilities/artifacts.ts +46 -9
  286. package/ts/capabilities/flyai.ts +156 -37
  287. package/ts/capabilities/hbcli.ts +1 -1
  288. package/ts/capabilities/incident-log.ts +88 -59
  289. package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
  290. package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
  291. package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
  292. package/ts/capabilities/session/extension-bridge.ts +226 -101
  293. package/ts/capabilities/session/extension-channel.ts +22 -9
  294. package/ts/capabilities/session/wizard.ts +2 -2
  295. package/ts/capabilities/session-consent.ts +98 -14
  296. package/ts/capabilities/session-login.ts +1 -0
  297. package/ts/capabilities/session-search.ts +315 -31
  298. package/ts/dsh-runtime/vendor/README.md +8 -4
  299. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
  300. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
  301. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
  302. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
  303. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
  304. package/ts/package.json +236 -16
  305. package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
  306. package/ts/scripts/state-cli.ts +418 -51
  307. package/ts/src/artifact-gate.ts +561 -15
  308. package/ts/src/benchmark-environment-bridge.ts +37 -20
  309. package/ts/src/bookable-facts.ts +183 -7
  310. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  311. package/ts/src/booking-surface/dsh-planner.ts +240 -32
  312. package/ts/src/booking-surface/dsh-plugin.js +17 -1
  313. package/ts/src/booking-surface/error-codes.ts +75 -0
  314. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  315. package/ts/src/booking-surface/server.ts +84 -51
  316. package/ts/src/booking-surface/validation.ts +2 -0
  317. package/ts/src/contracts.ts +12 -2
  318. package/ts/src/dsh-llm.ts +4 -8
  319. package/ts/src/index.ts +609 -90
  320. package/ts/src/loop.ts +116 -7
  321. package/ts/src/memory-capture.ts +227 -3
  322. package/ts/src/mock-llm.ts +4 -8
  323. package/ts/src/model.ts +88 -2
  324. package/ts/src/state-ledger.ts +47 -29
  325. package/ts/src/subagent-job-id-guard.ts +72 -0
  326. package/ts/src/time-anchor.ts +217 -13
  327. package/ts/src/unified.ts +316 -54
@@ -2,221 +2,137 @@ import assert from 'node:assert/strict';
2
2
  import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync } from 'node:fs';
3
3
  import { tmpdir } from 'node:os';
4
4
  import { join } from 'node:path';
5
- import { installTurnDeadline, TURN_DEADLINE_EXHAUSTED, TURN_DEADLINE_HANDOFF, TURN_HANDOFF_SCHEMA, writeTurnHandoffTicket } from '../src/turn-deadline.js';
6
- const success = ()=>({
7
- isError: false,
8
- value: null,
9
- content: []
10
- });
5
+ import { installTurnDeadline, TURN_DEADLINE_EXHAUSTED, TURN_DEADLINE_HANDOFF, TURN_HANDOFF_SCHEMA, writeTurnHandoffTicket, } from '../src/turn-deadline.js';
6
+ const success = () => ({ isError: false, value: null, content: [] });
11
7
  const handlers = new Map();
12
8
  const restricted = [];
13
9
  const lifted = [];
14
- const makeAgent = (id)=>({
15
- id,
16
- ctx: {
17
- tools: {
18
- restrict (filter) {
19
- restricted.push({
20
- agentId: id,
21
- deny: [
22
- ...filter.deny
23
- ]
24
- });
25
- return ()=>lifted.push(id);
26
- }
27
- }
28
- }
29
- });
10
+ const makeAgent = (id) => ({
11
+ id,
12
+ ctx: {
13
+ tools: {
14
+ restrict(filter) {
15
+ restricted.push({ agentId: id, deny: [...filter.deny] });
16
+ return () => lifted.push(id);
17
+ },
18
+ },
19
+ },
20
+ });
30
21
  const ctx = {
31
22
  tools: {
32
- schemas: ()=>[
33
- {
34
- name: 'gotry_alpha'
35
- },
36
- {
37
- name: 'gotry_beta'
38
- }
39
- ]
23
+ schemas: () => [{ name: 'gotry_alpha' }, { name: 'gotry_beta' }],
40
24
  },
41
- on (event, listener) {
25
+ on(event, listener) {
42
26
  const bucket = handlers.get(event) ?? [];
43
27
  bucket.push(listener);
44
28
  handlers.set(event, bucket);
45
- return ()=>{};
46
- }
29
+ return () => { };
30
+ },
47
31
  };
32
+ // Product-path opt-out: `enabled: false` must install nothing.
48
33
  const productCtx = {
49
- tools: {
50
- schemas: ()=>[]
51
- },
52
- on (event) {
34
+ tools: { schemas: () => [] },
35
+ on(event) {
53
36
  throw new Error(`opt-out path must not subscribe to ${event}`);
54
- }
37
+ },
55
38
  };
56
- installTurnDeadline(productCtx, {
57
- enabled: false
58
- });
59
- const clock = (()=>{
39
+ installTurnDeadline(productCtx, { enabled: false });
40
+ const clock = (() => {
60
41
  let t = 1_000_000;
61
- return {
62
- now: ()=>t,
63
- advance: (ms)=>{
64
- t += ms;
65
- }
66
- };
42
+ return { now: () => t, advance: (ms) => { t += ms; } };
67
43
  })();
68
44
  const handoffRoot = mkdtempSync(join(tmpdir(), 'gotry-turn-handoff-tests-'));
69
- installTurnDeadline(ctx, {
70
- stateRoot: handoffRoot,
71
- now: clock.now
72
- });
45
+ installTurnDeadline(ctx, { stateRoot: handoffRoot, now: clock.now });
73
46
  const execute = handlers.get('tools/execute')?.[0];
74
47
  const postExecute = handlers.get('tools/post-execute')?.[0];
75
48
  const sessionEvent = handlers.get('session/event')?.[0];
76
49
  const sessionDisposed = handlers.get('session/disposed')?.[0];
77
50
  assert.ok(execute && postExecute && sessionEvent && sessionDisposed, 'all Cordis boundary hooks register');
78
- const userMessage = (id, text, kind = 'user')=>sessionEvent({
79
- id
80
- }, {
81
- type: 'user/message',
82
- data: {
83
- source: {
84
- kind
85
- },
86
- content: [
87
- {
88
- type: 'text',
89
- text
90
- }
91
- ]
92
- }
93
- });
94
- const turnEvent = (id, type)=>sessionEvent({
95
- id
96
- }, {
97
- type
98
- });
51
+ // dsh 事件载荷在 event.data 下( benchmark-agent-conformance 同型)
52
+ const userMessage = (id, text, kind = 'user') => sessionEvent({ id }, { type: 'user/message', data: { source: { kind }, content: [{ type: 'text', text }] } });
53
+ const turnEvent = (id, type) => sessionEvent({ id }, { type });
54
+ // Agent-less calls are programmatic control-plane calls, not planner spend.
99
55
  {
100
56
  let directBodies = 0;
101
- for(let i = 0; i < 5; i++){
102
- const result = await execute({
103
- token: Symbol(`direct-${i}`)
104
- }, async ()=>{
105
- directBodies++;
106
- return success();
107
- });
57
+ for (let i = 0; i < 5; i++) {
58
+ const result = await execute({ token: Symbol(`direct-${i}`) }, async () => { directBodies++; return success(); });
108
59
  assert.equal(result.isError, false);
109
60
  }
110
61
  assert.equal(directBodies, 5);
111
- }{
62
+ }
63
+ // ---- converge 路径:sync-planning 消息,软提示 + 硬阈结构化拒绝 ----------------
64
+ {
112
65
  const agent = makeAgent('agent-converge');
113
66
  turnEvent(agent.id, 'turn/start');
114
67
  userMessage(agent.id, '帮我看看10.1去杭州的高铁票');
115
68
  {
116
- const exec = {
117
- token: Symbol('conv-1'),
118
- agent
119
- };
120
- const result = await execute(exec, async ()=>success());
121
- const post = await postExecute(exec, result, async ()=>({
122
- kind: 'accept'
123
- }));
69
+ const exec = { token: Symbol('conv-1'), agent };
70
+ const result = await execute(exec, async () => success());
71
+ const post = await postExecute(exec, result, async () => ({ kind: 'accept' }));
124
72
  assert.equal(result.isError, false);
125
73
  assert.equal((post.additionalContexts ?? []).length, 0, 'no convergence context before soft');
126
74
  assert.equal(restricted.length, 0);
127
75
  }
76
+ // 推进超过软阈(sync-planning 300s):post-execute 注入 TURN_DEADLINE_SOFT
128
77
  clock.advance(300_001);
129
78
  {
130
- const exec = {
131
- token: Symbol('conv-2'),
132
- agent
133
- };
134
- const result = await execute(exec, async ()=>success());
135
- const post = await postExecute(exec, result, async ()=>({
136
- kind: 'accept'
137
- }));
138
- const contextText = post.additionalContexts?.flatMap((item)=>item.content ?? []).map((item)=>item.text ?? '').join('\n') ?? '';
79
+ const exec = { token: Symbol('conv-2'), agent };
80
+ const result = await execute(exec, async () => success());
81
+ const post = await postExecute(exec, result, async () => ({ kind: 'accept' }));
82
+ const contextText = post.additionalContexts?.flatMap(item => item.content ?? []).map(item => item.text ?? '').join('\n') ?? '';
139
83
  assert.ok(contextText.includes('TURN_DEADLINE_SOFT'), 'soft context after crossing softMs');
140
84
  assert.ok(contextText.includes('final answer'), 'converge soft text asks for a final answer');
141
85
  }
86
+ // 推进超过硬阈(600s):结构化拒绝 + 同步抑制 schema,不落任何工单
142
87
  clock.advance(300_000);
143
88
  {
144
- const exec = {
145
- token: Symbol('conv-3'),
146
- agent
147
- };
89
+ const exec = { token: Symbol('conv-3'), agent };
148
90
  let bodyRan = false;
149
- const result = await execute(exec, async ()=>{
150
- bodyRan = true;
151
- return success();
152
- });
91
+ const result = await execute(exec, async () => { bodyRan = true; return success(); });
153
92
  assert.equal(bodyRan, false);
154
93
  assert.equal(result.isError, true);
155
- assert.deepEqual(result.error?.info, {
156
- name: 'TurnDeadlineError',
157
- code: TURN_DEADLINE_EXHAUSTED
158
- });
94
+ assert.deepEqual(result.error?.info, { name: 'TurnDeadlineError', code: TURN_DEADLINE_EXHAUSTED });
159
95
  assert.match(result.content[0]?.text ?? '', /TURN_DEADLINE_EXHAUSTED/);
160
96
  }
161
- assert.deepEqual(restricted.at(-1), {
162
- agentId: agent.id,
163
- deny: [
164
- 'gotry_alpha',
165
- 'gotry_beta'
166
- ]
167
- });
97
+ assert.deepEqual(restricted.at(-1), { agentId: agent.id, deny: ['gotry_alpha', 'gotry_beta'] });
168
98
  const convergeTicketDir = join(handoffRoot, 'gotry-state', 'turn-handoffs');
169
99
  assert.equal(existsSync(convergeTicketDir) ? readdirSync(convergeTicketDir).length : 0, 0, 'converge writes no ticket');
170
100
  turnEvent(agent.id, 'turn/end');
171
101
  assert.equal(lifted.at(-1), agent.id);
172
- }{
102
+ }
103
+ // ---- handoff 路径:deep-planning 消息(失败轨迹原文)→ 落单转后台 -----------
104
+ {
173
105
  const agent = makeAgent('agent-handoff');
174
106
  turnEvent(agent.id, 'turn/start');
175
- const deepMessage = '2026年我还有6天IRW额度 ,我准备再请几天假,在国内待个十几天。' + '其中10.3要去湖南衡阳参加同学婚礼。其他我没有特别的要求,请根据我的实际情况,偏好,外部环境等因素,给我安排行程';
107
+ const deepMessage = '2026年我还有6天IRW额度 ,我准备再请几天假,在国内待个十几天。'
108
+ + '其中10.3要去湖南衡阳参加同学婚礼。其他我没有特别的要求,请根据我的实际情况,偏好,外部环境等因素,给我安排行程';
176
109
  userMessage(agent.id, deepMessage);
110
+ // 软阈(deep 120s):提示语义是「收尾摸底、即将转后台」
177
111
  clock.advance(120_001);
178
112
  {
179
- const exec = {
180
- token: Symbol('hand-1'),
181
- agent
182
- };
183
- const result = await execute(exec, async ()=>success());
184
- const post = await postExecute(exec, result, async ()=>({
185
- kind: 'accept'
186
- }));
187
- const contextText = post.additionalContexts?.flatMap((item)=>item.content ?? []).map((item)=>item.text ?? '').join('\n') ?? '';
113
+ const exec = { token: Symbol('hand-1'), agent };
114
+ const result = await execute(exec, async () => success());
115
+ const post = await postExecute(exec, result, async () => ({ kind: 'accept' }));
116
+ const contextText = post.additionalContexts?.flatMap(item => item.content ?? []).map(item => item.text ?? '').join('\n') ?? '';
188
117
  assert.ok(contextText.includes('background planning'), 'handoff soft text announces the handoff');
189
118
  assert.equal(result.isError, false);
190
119
  }
120
+ // 硬阈(240s):TURN_DEADLINE_HANDOFF 结构化结果 + 工单落盘
191
121
  clock.advance(120_000);
192
122
  {
193
- const exec = {
194
- token: Symbol('hand-2'),
195
- agent
196
- };
123
+ const exec = { token: Symbol('hand-2'), agent };
197
124
  let bodyRan = false;
198
- const result = await execute(exec, async ()=>{
199
- bodyRan = true;
200
- return success();
201
- });
125
+ const result = await execute(exec, async () => { bodyRan = true; return success(); });
202
126
  assert.equal(bodyRan, false);
203
127
  assert.equal(result.isError, true);
204
- assert.deepEqual(result.error?.info, {
205
- name: 'TurnDeadlineHandoff',
206
- code: TURN_DEADLINE_HANDOFF
207
- });
128
+ assert.deepEqual(result.error?.info, { name: 'TurnDeadlineHandoff', code: TURN_DEADLINE_HANDOFF });
208
129
  const text = result.content[0]?.text ?? '';
209
130
  assert.match(text, /TURN_DEADLINE_HANDOFF/);
210
131
  assert.match(text, /th-/, 'result names the persisted ticket id');
211
132
  assert.match(text, /约 1 小时/, 'ETA label mirrors the S5 promise');
212
133
  }
213
- assert.deepEqual(restricted.at(-1), {
214
- agentId: agent.id,
215
- deny: [
216
- 'gotry_alpha',
217
- 'gotry_beta'
218
- ]
219
- });
134
+ // 同步抑制已生效
135
+ assert.deepEqual(restricted.at(-1), { agentId: agent.id, deny: ['gotry_alpha', 'gotry_beta'] });
220
136
  const tickets = readdirSync(join(handoffRoot, 'gotry-state', 'turn-handoffs'));
221
137
  assert.equal(tickets.length, 1, 'exactly one handoff ticket');
222
138
  const ticket = JSON.parse(readFileSync(join(handoffRoot, 'gotry-state', 'turn-handoffs', tickets[0]), 'utf8'));
@@ -225,38 +141,36 @@ const turnEvent = (id, type)=>sessionEvent({
225
141
  assert.equal(ticket.userMessage, deepMessage, 'ticket carries the verbatim user ask');
226
142
  assert.ok(ticket.requestedAt);
227
143
  assert.equal(ticket.etaLabel, '约 1 小时');
144
+ // 新 user 消息 = 新预算:同 agent 下一轮 quick 消息恢复放行
228
145
  turnEvent(agent.id, 'turn/end');
229
146
  userMessage(agent.id, '你好');
230
147
  {
231
- const result = await execute({
232
- token: Symbol('hand-3'),
233
- agent
234
- }, async ()=>success());
148
+ const result = await execute({ token: Symbol('hand-3'), agent }, async () => success());
235
149
  assert.equal(result.isError, false);
236
150
  }
237
151
  turnEvent(agent.id, 'turn/end');
238
152
  assert.equal(readdirSync(join(handoffRoot, 'gotry-state', 'turn-handoffs')).length, 1, 'no extra tickets');
239
- }{
153
+ }
154
+ // ---- 路由输入纪律:plugin 注入的 user/message 不参与路由 --------------------
155
+ {
240
156
  const agent = makeAgent('agent-plugin-msg');
241
157
  turnEvent(agent.id, 'turn/start');
242
158
  userMessage(agent.id, '你好');
159
+ // plugin 注入的深规划文本不得翻转预算
243
160
  userMessage(agent.id, deepPlanningNoise(), 'plugin');
244
161
  clock.advance(1_000_000);
245
162
  {
246
- const exec = {
247
- token: Symbol('plug-1'),
248
- agent
249
- };
250
- const result = await execute(exec, async ()=>success());
251
- assert.deepEqual(result.error?.info, {
252
- name: 'TurnDeadlineError',
253
- code: TURN_DEADLINE_EXHAUSTED
254
- });
163
+ const exec = { token: Symbol('plug-1'), agent };
164
+ const result = await execute(exec, async () => success());
165
+ // quick 硬阈 180s 已被跨过 → converge 拒绝(而非 handoff):证明路由未被 plugin 消息改写
166
+ assert.deepEqual(result.error?.info, { name: 'TurnDeadlineError', code: TURN_DEADLINE_EXHAUSTED });
255
167
  }
256
168
  turnEvent(agent.id, 'turn/end');
257
- }function deepPlanningNoise() {
169
+ }
170
+ function deepPlanningNoise() {
258
171
  return '系统提醒样例:10.3 婚礼 IRW 请假 十几天 安排行程——这是插件注入,不该参与路由';
259
172
  }
173
+ // ---- 工单写入器(独立契约:原子写 + 目录形态) ------------------------------
260
174
  {
261
175
  const root = mkdtempSync(join(tmpdir(), 'gotry-turn-handoff-writer-'));
262
176
  const ticket = await writeTurnHandoffTicket(root, '短消息');
@@ -264,18 +178,8 @@ const turnEvent = (id, type)=>sessionEvent({
264
178
  assert.equal(readdirSync(dir).length, 1);
265
179
  const loaded = JSON.parse(readFileSync(join(dir, `${ticket.id}.json`), 'utf8'));
266
180
  assert.equal(loaded.userMessage, '短消息');
267
- rmSync(root, {
268
- recursive: true,
269
- force: true
270
- });
271
- }sessionDisposed({
272
- id: 'agent-handoff'
273
- });
274
- rmSync(handoffRoot, {
275
- recursive: true,
276
- force: true
277
- });
181
+ rmSync(root, { recursive: true, force: true });
182
+ }
183
+ sessionDisposed({ id: 'agent-handoff' });
184
+ rmSync(handoffRoot, { recursive: true, force: true });
278
185
  console.log('agent turn deadline tests: OK (routing→converge/handoff exits, ticket persistence, plugin-message discipline, lifecycle)');
279
-
280
-
281
- //# sourceURL=ts/scripts/agent-planning-turn-deadline-tests.ts
@@ -1,54 +1,44 @@
1
+ /**
2
+ * agent-reach 深度能力层测试(yt-dlp + gh,系统装了就调,没装降级):
3
+ * 1. yt-dlp:无论装没装,三值之一(found/not-installed/error)且不抛错
4
+ * 2. gh 搜索:gh 已装的环境真实搜 agent-reach;未装环境走 not-installed
5
+ * 3. 证据链标注含 [agent-reach:<bin>@
6
+ * 4. 超时降级
7
+ *
8
+ * 运行: cd ts && npx tsx scripts/agent-reach-deep-tests.ts
9
+ */
1
10
  import assert from 'node:assert/strict';
2
11
  import { videoSubtitle, githubSearch } from '../capabilities/agent-reach-deep.js';
12
+ // 1. yt-dlp 三值
3
13
  {
4
- const r = await videoSubtitle({
5
- url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
6
- timeoutMs: 15_000
7
- });
8
- assert.ok([
9
- 'found',
10
- 'not-installed',
11
- 'error',
12
- 'timeout'
13
- ].includes(r.verdict), `verdict 三值之一: ${r.verdict}`);
14
+ const r = await videoSubtitle({ url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', timeoutMs: 15_000 });
15
+ assert.ok(['found', 'not-installed', 'error', 'timeout'].includes(r.verdict), `verdict 三值之一: ${r.verdict}`);
14
16
  assert.ok(r.evidence.includes('[agent-reach:yt-dlp@'), '证据链前缀');
15
17
  console.log(`1. yt-dlp → ${r.verdict} (${r.latencyMs}ms) OK`);
16
- }{
17
- const r = await githubSearch({
18
- query: 'agent-reach',
19
- limit: 3
20
- });
21
- assert.ok([
22
- 'found',
23
- 'not-installed',
24
- 'error',
25
- 'timeout'
26
- ].includes(r.verdict));
18
+ }
19
+ // 2. gh 搜索(装了就真实搜,没装走 not-installed)
20
+ {
21
+ const r = await githubSearch({ query: 'agent-reach', limit: 3 });
22
+ assert.ok(['found', 'not-installed', 'error', 'timeout'].includes(r.verdict));
27
23
  if (r.verdict === 'found') {
28
24
  assert.ok((r.repos?.length ?? 0) > 0, 'found 应有 repos');
29
25
  const top = r.repos[0];
30
26
  console.log(`2. gh search → found (top: ${top.name} ★${top.stars}) OK`);
31
- } else {
27
+ }
28
+ else {
32
29
  console.log(`2. gh search → ${r.verdict} (${r.stderr?.slice(0, 60)}) OK`);
33
30
  }
34
- }{
35
- const r = await githubSearch({
36
- query: 'hello'
37
- });
31
+ }
32
+ // 3. 证据链格式
33
+ {
34
+ const r = await githubSearch({ query: 'hello' });
38
35
  assert.match(r.evidence, /\[agent-reach:gh@/, 'gh 证据链');
39
36
  console.log('3. 证据链格式 OK');
40
- }{
41
- const r = await githubSearch({
42
- query: 'hello',
43
- timeoutMs: 1
44
- });
45
- assert.ok([
46
- 'timeout',
47
- 'error',
48
- 'not-installed'
49
- ].includes(r.verdict));
37
+ }
38
+ // 4. 超时降级(1ms timeout)
39
+ {
40
+ const r = await githubSearch({ query: 'hello', timeoutMs: 1 });
41
+ assert.ok(['timeout', 'error', 'not-installed'].includes(r.verdict));
50
42
  console.log(`4. 超时 → ${r.verdict} OK`);
51
- }console.log('\nAGENT-REACH DEEP TESTS: 4/4 OK(yt-dlp/gh 可选工具,不装则降级)');
52
-
53
-
54
- //# sourceURL=ts/scripts/agent-reach-deep-tests.ts
43
+ }
44
+ console.log('\nAGENT-REACH DEEP TESTS: 4/4 OK(yt-dlp/gh 可选工具,不装则降级)');
@@ -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
- const r = await readUrl({
13
- url: 'https://example.com',
14
- timeoutMs: 1
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
- const r = await readUrl({
22
- url: 'https://example.com',
23
- timeoutMs: 30_000
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
- } else {
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
- }console.log('\nAGENT-REACH TESTS: 3/3 OK(readUrl 薄壳;上游真读见 wrapper 套)');
36
-
37
-
38
- //# sourceURL=ts/scripts/agent-reach-tests.ts
45
+ }
46
+ console.log('\nAGENT-REACH TESTS: 3/3 OK(readUrl 薄壳;上游真读见 wrapper 套)');
@@ -1,5 +1,19 @@
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);
5
19
  if (!st.ok) {
@@ -10,74 +24,56 @@ import { reach, reachStatus } from '../capabilities/agent-reach.js';
10
24
  assert.equal(st.via, 'agent-reach-cli');
11
25
  assert.ok(st.output.length > 50, 'doctor 输出非空(上游原样)');
12
26
  console.log(`1. status → doctor 透传 (${st.latencyMs}ms) OK`);
13
- }{
14
- const r = await reach({
15
- channel: 'web',
16
- method: 'read',
17
- args: [
18
- 'https://example.com'
19
- ],
20
- timeoutMs: 30_000
21
- });
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 });
22
31
  assert.equal(r.verdict, 'found');
23
32
  assert.ok(r.evidence.includes('[agent-reach:web.read@'), '证据链 [agent-reach:web.read@ts]');
33
+ // live 内容会漂移(同 §13),断言非空 markdown 而非精确文案
24
34
  assert.ok(typeof r.data === 'string' && r.data.length > 200, 'content 非空 markdown');
25
35
  console.log(`2. web.read example.com → found (${r.latencyMs}ms) OK`);
26
- }{
27
- const r = await reach({
28
- channel: 'v2ex',
29
- method: 'get_hot_topics',
30
- timeoutMs: 30_000
31
- });
36
+ }
37
+ // 3. v2ex.get_hot_topics(上游 python 方法;网络边界允许降级不抛错)
38
+ {
39
+ const r = await reach({ channel: 'v2ex', method: 'get_hot_topics', timeoutMs: 30_000 });
32
40
  if (r.ok) {
33
41
  assert.ok(Array.isArray(r.data), 'hot topics 是数组');
34
42
  console.log(`3. v2ex.get_hot_topics → found (${r.data.length} topics) OK`);
35
- } else {
36
- assert.ok([
37
- 'error',
38
- 'needs-setup'
39
- ].includes(r.verdict), '降级合法');
43
+ }
44
+ else {
45
+ assert.ok(['error', 'needs-setup'].includes(r.verdict), '降级合法');
40
46
  console.log(`3. v2ex.get_hot_topics → ${r.verdict}(网络边界,降级合法) OK`);
41
47
  }
42
- }{
43
- const r = await reach({
44
- channel: 'xueqiu',
45
- method: 'get_stock_quote',
46
- args: [
47
- 'SH600519'
48
- ],
49
- timeoutMs: 30_000
50
- });
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 });
51
52
  assert.equal(r.verdict, 'needs-setup', `实际 verdict=${r.verdict} error=${r.error}`);
52
53
  assert.ok((r.setup ?? '').includes('configure'), 'setup 透传上游 configure 指引(不转述)');
53
54
  console.log('4. xueqiu.get_stock_quote → needs-setup(上游原话指引) OK');
54
- }{
55
- const r = await reach({
56
- channel: 'nosuch',
57
- method: 'foo'
58
- });
55
+ }
56
+ // 5. 未知渠道 自描述,带回上游渠道清单
57
+ {
58
+ const r = await reach({ channel: 'nosuch', method: 'foo' });
59
59
  assert.equal(r.ok, false);
60
- const channels = r.inventory?.channels ?? {};
60
+ const channels = (r.inventory?.channels ?? {});
61
61
  assert.ok(channels.web && channels.xueqiu && channels['exa_search'], 'inventory 带回上游注册表(含 exa_search 真名)');
62
62
  console.log(`5. 未知渠道 → 自描述清单(${Object.keys(channels).length} 渠道) OK`);
63
- }{
64
- const r = await reach({
65
- channel: 'web',
66
- method: 'nosuch'
67
- });
63
+ }
64
+ // 6. 未知方法 自描述,带回上游方法签名清单
65
+ {
66
+ const r = await reach({ channel: 'web', method: 'nosuch' });
68
67
  assert.equal(r.ok, false);
69
- const methods = r.inventory?.methods ?? {};
68
+ const methods = (r.inventory?.methods ?? {});
70
69
  assert.ok(methods.read, 'inventory.methods 带 read 签名');
71
70
  console.log(`6. 未知方法 → 自描述清单(${Object.keys(methods).length} 方法) OK`);
72
- }{
73
- const r = await reach({
74
- channel: '',
75
- method: ''
76
- });
71
+ }
72
+ // 7. 永不抛错: channel/method
73
+ {
74
+ const r = await reach({ channel: '', method: '' });
77
75
  assert.equal(r.ok, false);
78
76
  assert.equal(r.verdict, 'error');
79
77
  console.log('7. 空 channel/method 降级 OK');
80
- }console.log('\nAGENT-REACH WRAPPER TESTS: 7/7 OK(反射桥 + doctor 透传 + 自描述错误)');
81
-
82
-
83
- //# sourceURL=ts/scripts/agent-reach-wrapper-tests.ts
78
+ }
79
+ console.log('\nAGENT-REACH WRAPPER TESTS: 7/7 OK(反射桥 + doctor 透传 + 自描述错误)');