@danceiny/gotry 0.0.1-rc.18 → 0.0.1-rc.20

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 (176) hide show
  1. package/README.md +42 -16
  2. package/README.zh-CN.md +37 -15
  3. package/bin/gotry-bootstrap.js +309 -30
  4. package/bin/gotry-inner.js +74 -23
  5. package/bin/gotry-runtime-resolution.d.ts +1 -1
  6. package/bin/gotry-runtime-resolution.js +7 -8
  7. package/cordis.gotry-patch.yml +22 -8
  8. package/data/stations-12306-verify.json +524 -0
  9. package/dist/capabilities/agent-reach.js +4 -4
  10. package/dist/capabilities/anything.js +62 -29
  11. package/dist/capabilities/channel-health.js +103 -0
  12. package/dist/capabilities/channel-registry.js +213 -0
  13. package/dist/capabilities/doctor.js +307 -0
  14. package/dist/capabilities/effect.js +178 -5
  15. package/dist/capabilities/flyai.js +13 -0
  16. package/dist/capabilities/hbcli.js +28 -2
  17. package/dist/capabilities/session/adapters/ctrip-hotel.js +207 -0
  18. package/dist/capabilities/session/adapters/rail-12306.js +285 -0
  19. package/dist/capabilities/session/extension-bridge.js +14 -1
  20. package/dist/capabilities/session/extension-channel.js +4 -2
  21. package/dist/capabilities/session/extension-distribution.js +1 -1
  22. package/dist/capabilities/session-search.js +311 -0
  23. package/dist/capabilities/visa-policy.js +126 -0
  24. package/dist/scripts/agent-planning-turn-deadline-e2e.js +305 -0
  25. package/dist/scripts/agent-planning-turn-deadline-tests.js +281 -0
  26. package/dist/scripts/anything-tests.js +70 -21
  27. package/dist/scripts/benchmark-environment-bridge-e2e.js +139 -37
  28. package/dist/scripts/benchmark-environment-bridge-tests.js +1099 -306
  29. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +26 -26
  30. package/dist/scripts/{booking-copilot-availability-policy-v2-tests.js → booking-copilot-availability-policy-tests.js} +115 -115
  31. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +41 -1
  32. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +75 -120
  33. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +370 -61
  34. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +2 -2
  35. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +7 -3
  36. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +15 -9
  37. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +19 -11
  38. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +16 -52
  39. package/dist/scripts/booking-copilot-runtime-proof-tests.js +3953 -155
  40. package/dist/scripts/booking-copilot-server-proof-tests.js +58 -23
  41. package/dist/scripts/booking-copilot-startup-proof-tests.js +10 -119
  42. package/dist/scripts/booking-surface-contract-proof-tests.js +1154 -326
  43. package/dist/scripts/bootstrap-tests.js +113 -2
  44. package/dist/scripts/build-metrics-report.js +339 -0
  45. package/dist/scripts/channel-probe-tests.js +148 -0
  46. package/dist/scripts/channel-probe.js +252 -0
  47. package/dist/scripts/channel-registry-tests.js +262 -0
  48. package/dist/scripts/doctor-tests.js +175 -0
  49. package/dist/scripts/effect-tests.js +274 -1
  50. package/dist/scripts/extension-tests.js +129 -11
  51. package/dist/scripts/fact-gate-tests.js +91 -2
  52. package/dist/scripts/flyai-tests.js +17 -1
  53. package/dist/scripts/hbcli-e2e-tests.js +1 -3
  54. package/dist/scripts/hbcli-tests.js +38 -1
  55. package/dist/scripts/metrics-report-tests.js +288 -0
  56. package/dist/scripts/persona-surface-guard-tests.js +19 -0
  57. package/dist/scripts/session-tests.js +401 -1
  58. package/dist/scripts/smoke.js +100 -83
  59. package/dist/scripts/turn-handoff-collect-tests.js +216 -0
  60. package/dist/scripts/turn-handoff-collect.js +189 -0
  61. package/dist/scripts/turn-policy-tests.js +56 -0
  62. package/dist/scripts/typed-contract-canary.js +261 -0
  63. package/dist/scripts/visa-policy-tests.js +75 -0
  64. package/dist/scripts/wish-channel-gate-tests.js +111 -0
  65. package/dist/src/artifact-gate.js +91 -3
  66. package/dist/src/benchmark-agent-conformance.js +39 -16
  67. package/dist/src/benchmark-environment-bridge.js +316 -52
  68. package/dist/src/bookable-facts.js +62 -3
  69. package/dist/src/booking-surface/{availability-policy-v2.js → availability-policy.js} +89 -89
  70. package/dist/src/booking-surface/canonical-schema.js +8 -22
  71. package/dist/src/booking-surface/contracts.js +70 -19
  72. package/dist/src/booking-surface/dsh-planner.js +310 -177
  73. package/dist/src/booking-surface/dsh-plugin.js +3 -3
  74. package/dist/src/booking-surface/index.js +1 -5
  75. package/dist/src/booking-surface/profile.js +1 -1
  76. package/dist/src/booking-surface/runtime.js +1682 -247
  77. package/dist/src/booking-surface/server.js +371 -185
  78. package/dist/src/booking-surface/startup.js +17 -27
  79. package/dist/src/booking-surface/validation.js +270 -760
  80. package/dist/src/index.js +739 -150
  81. package/dist/src/turn-deadline.js +292 -0
  82. package/dist/src/turn-policy.js +146 -0
  83. package/dist/src/wish-pool.js +5 -0
  84. package/extension/background.js +23 -4
  85. package/extension/content-main.js +47 -9
  86. package/extension/manifest.json +27 -9
  87. package/package.json +7 -26
  88. package/schemas/booking.surface.schema.json +2593 -0
  89. package/ts/capabilities/agent-reach.ts +4 -4
  90. package/ts/capabilities/anything.ts +89 -38
  91. package/ts/capabilities/flyai.ts +21 -3
  92. package/ts/capabilities/hbcli.ts +53 -4
  93. package/ts/capabilities/session/action-cache.ts +1 -1
  94. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  95. package/ts/capabilities/session/adapters/rail-12306.ts +293 -0
  96. package/ts/capabilities/session/extension-bridge.ts +32 -2
  97. package/ts/capabilities/session/extension-channel.ts +9 -8
  98. package/ts/capabilities/session/extension-distribution.ts +3 -1
  99. package/ts/capabilities/session/health-watch.ts +1 -1
  100. package/ts/capabilities/session/read-guard.ts +1 -1
  101. package/ts/capabilities/session/wizard.ts +1 -1
  102. package/ts/capabilities/session-search.ts +323 -1
  103. package/ts/dsh-runtime/vendor/README.md +60 -0
  104. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  105. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +200 -0
  106. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +202 -0
  107. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +216 -0
  108. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  109. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +371 -0
  110. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  111. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +56 -0
  112. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  113. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  114. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +126 -0
  115. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  116. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +109 -0
  117. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +27 -0
  118. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  119. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  120. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +170 -0
  121. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +53 -0
  122. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  123. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  124. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  125. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  126. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +20 -0
  127. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  128. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  129. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  130. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  131. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  132. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +16 -0
  133. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +55 -0
  134. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  135. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +91 -0
  136. package/ts/package.json +9 -0
  137. package/ts/scripts/turn-handoff-collect.ts +178 -0
  138. package/ts/src/artifact-gate.ts +82 -2
  139. package/ts/src/benchmark-agent-conformance.ts +54 -15
  140. package/ts/src/benchmark-environment-bridge.ts +234 -46
  141. package/ts/src/bookable-facts.ts +109 -5
  142. package/ts/src/booking-saga.ts +1 -1
  143. package/ts/src/booking-surface/{availability-policy-v2.ts → availability-policy.ts} +124 -125
  144. package/ts/src/booking-surface/canonical-schema.js +8 -22
  145. package/ts/src/booking-surface/contracts.ts +278 -239
  146. package/ts/src/booking-surface/dsh-planner.ts +333 -194
  147. package/ts/src/booking-surface/dsh-plugin.js +3 -3
  148. package/ts/src/booking-surface/index.ts +1 -5
  149. package/ts/src/booking-surface/profile.ts +11 -11
  150. package/ts/src/booking-surface/runtime.ts +1351 -351
  151. package/ts/src/booking-surface/server.ts +282 -175
  152. package/ts/src/booking-surface/startup.ts +36 -48
  153. package/ts/src/booking-surface/validation.ts +194 -442
  154. package/ts/src/contracts.ts +1 -1
  155. package/ts/src/index.ts +492 -172
  156. package/ts/src/loop.ts +1 -1
  157. package/ts/src/state-ledger.ts +1 -1
  158. package/ts/src/turn-deadline.ts +365 -0
  159. package/ts/src/turn-policy.ts +154 -0
  160. package/ts/src/wish-pool.ts +17 -4
  161. package/dist/scripts/agent-planning-budget-e2e.js +0 -227
  162. package/dist/scripts/agent-planning-budget-tests.js +0 -173
  163. package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +0 -3935
  164. package/dist/scripts/booking-surface-v2-contract-proof-tests.js +0 -1174
  165. package/dist/src/booking-surface/contracts-v2.js +0 -89
  166. package/dist/src/booking-surface/runtime-v2.js +0 -1771
  167. package/dist/src/booking-surface/server-v2.js +0 -334
  168. package/dist/src/booking-surface/validation-v2.js +0 -319
  169. package/dist/src/tool-budget.js +0 -136
  170. package/schemas/booking.surface.v1.schema.json +0 -927
  171. package/schemas/booking.surface.v2.schema.json +0 -61
  172. package/ts/src/booking-surface/contracts-v2.ts +0 -118
  173. package/ts/src/booking-surface/runtime-v2.ts +0 -1466
  174. package/ts/src/booking-surface/server-v2.ts +0 -247
  175. package/ts/src/booking-surface/validation-v2.ts +0 -205
  176. package/ts/src/tool-budget.ts +0 -165
@@ -15,6 +15,7 @@
15
15
 
16
16
  import {
17
17
  flightClaimVerdict,
18
+ hotelClaimVerdict,
18
19
  itineraryInvariants,
19
20
  latestFactsForRouteDate,
20
21
  type BookableFact,
@@ -62,12 +63,24 @@ export interface ExtractedAirportClaim {
62
63
  city: string
63
64
  }
64
65
 
66
+ /** 酒店 claim(D-26):断言「有房/可订/已核验」的行——目的地与档期缺失时 fail-closed */
67
+ export interface ExtractedHotelClaim {
68
+ line: number
69
+ text: string
70
+ destination?: string
71
+ check_in?: string
72
+ check_out?: string
73
+ }
74
+
65
75
  export interface ExtractedClaims {
66
76
  flights: ExtractedFlightClaim[]
67
77
  policies: ExtractedPolicyClaim[]
68
78
  airports: ExtractedAirportClaim[]
69
79
  /** 含「直飞」断言且可解析航线的行(通用直飞规则:该日无任何在架直飞即违例) */
70
80
  direct_lines: Array<{ line: number; text: string; origin?: string; destination?: string; date?: string }>
81
+ hotels: ExtractedHotelClaim[]
82
+ /** 渲染原语锚点(fact:<id>):命中行只走确定性回溯,启发式让位 */
83
+ anchors: Map<number, string>
71
84
  }
72
85
 
73
86
  /** 航班号:2 位承运码 + 3-4 位数字(UO784/EK328/MF1538/CZ8582/9C8781/FD597) */
@@ -94,6 +107,14 @@ function hasDirectAssertion(line: string): boolean {
94
107
 
95
108
  interface SectionCtx { origin?: string; destination?: string; date?: string }
96
109
 
110
+ /** 行内第一个命中词表的城市中文名(酒店 claim 的目的地键;无命中=undefined) */
111
+ function occ1(line: string, map: AirlineAirportMap): string | undefined {
112
+ for (const city of Object.keys(map.city_alias)) {
113
+ if (line.includes(city)) return city
114
+ }
115
+ return undefined
116
+ }
117
+
97
118
  /** 从文本(小节标题或行)解析航线上下文:箭头紧邻城市对(方向最可靠)优先,否则按出现位置取前两个;日期 M.D 或 MM-DD */
98
119
  function routeCtxOf(text: string, map: AirlineAirportMap, defaultYear?: number): SectionCtx {
99
120
  const occ: Array<{ city: string; iata: string; pos: number }> = []
@@ -140,12 +161,19 @@ function routeCtxOf(text: string, map: AirlineAirportMap, defaultYear?: number):
140
161
  * 行内自带上下文优先。默认年份由 trip window 提供(远期行程的年份不含糊)。
141
162
  */
142
163
  export function extractClaims(markdown: string, map: AirlineAirportMap, opts?: { trip_year?: number }): ExtractedClaims {
143
- const claims: ExtractedClaims = { flights: [], policies: [], airports: [], direct_lines: [] }
164
+ const claims: ExtractedClaims = { flights: [], policies: [], airports: [], direct_lines: [], hotels: [], anchors: new Map() }
144
165
  const lines = markdown.split('\n')
145
166
  let section: SectionCtx = {}
167
+ // 渲染原语锚点(单向生成):带 fact:<id> 的行只走锚点确定性回溯,启发式抽取让位
168
+ const ANCHOR = /fact:([0-9a-f]{16})/
146
169
  for (let i = 0; i < lines.length; i++) {
147
170
  const line = lines[i]!
148
171
  const lineNo = i + 1
172
+ const anchorMatch = line.match(ANCHOR)
173
+ if (anchorMatch) {
174
+ claims.anchors.set(lineNo, anchorMatch[1]!.toLowerCase())
175
+ continue
176
+ }
149
177
  if (/^#{1,4}\s/.test(line)) {
150
178
  const ctx = routeCtxOf(line, map, opts?.trip_year)
151
179
  section = { origin: ctx.origin, destination: ctx.destination, date: ctx.date ?? section.date }
@@ -179,6 +207,19 @@ export function extractClaims(markdown: string, map: AirlineAirportMap, opts?: {
179
207
  if (POLICY_WORD.test(line)) {
180
208
  claims.policies.push({ line: lineNo, text: line.trim().slice(0, 160), has_as_of: AS_OF_WORD.test(line) })
181
209
  }
210
+ // 酒店 claim(D-26):断言可住性(有房/可订/已核验/✓)的行——目的地与档期缺失时 fail-closed
211
+ const HOTEL_ASSERT = /酒店|住宿|客栈|民宿/
212
+ const HOTEL_BOOKABLE = /有房|可订|在架|已核验|已验证|可住|✓|✅/
213
+ if (HOTEL_ASSERT.test(line) && HOTEL_BOOKABLE.test(line)) {
214
+ const stays = [...line.matchAll(/(?<!\d)(\d{4}-\d{2}-\d{2})(?!\d)/g)].map(m => m[1]!)
215
+ claims.hotels.push({
216
+ line: lineNo,
217
+ text: line.trim().slice(0, 160),
218
+ destination: occ1(line, map),
219
+ check_in: stays[0],
220
+ check_out: stays[1],
221
+ })
222
+ }
182
223
  // 航司→机场映射 claim:同一行出现承运码 + 机场码,且该城是双机场映射面
183
224
  for (const [city, carriers] of Object.entries(map.carrier_airport)) {
184
225
  const airports = [...new Set(Object.values(carriers))]
@@ -207,6 +248,8 @@ export type GateViolationKind =
207
248
  | 'legs_inconsistent' // flight O&D 段与 legs 口径不一致
208
249
  | 'budget_floor_inconsistent' // 预算下限话术低于分项最低合计
209
250
  | 'date_order' // 住宿/段日期越窗或倒挂
251
+ | 'unverifiable_hotel_claim' // 酒店可住断言无 exact-date 事实回溯(D-26)
252
+ | 'fact_anchor_unknown' // 渲染锚点 fact:<id> 在注册表不存在(锚点被手改/伪造)
210
253
 
211
254
  export interface GateViolation {
212
255
  kind: GateViolationKind
@@ -242,6 +285,43 @@ export function gateArtifact(
242
285
  const violations: GateViolation[] = []
243
286
  let traceable = 0
244
287
 
288
+ // 渲染锚点优先(issue #118 单向生成):带 fact:<id> 的行确定性回溯注册表——
289
+ // 锚点在=按事实 bookability 判;锚点不存在=手改/伪造,直接违例。启发式对锚点行让位。
290
+ for (const [lineNo, factId] of claims.anchors) {
291
+ const f = facts.find(x => x.fact_id === factId)
292
+ if (!f) {
293
+ violations.push({ kind: 'fact_anchor_unknown', line: lineNo, detail: `渲染锚点 fact:${factId} 不在事实注册表——锚点被手改或伪造,产物不可信` })
294
+ continue
295
+ }
296
+ if (f.kind !== 'policy' && f.bookability === 'unavailable_exact_date') {
297
+ violations.push({ kind: 'not_in_source', line: lineNo, detail: `锚点事实为 exact-date 负事实(${(f as { fetched_at?: string }).fetched_at ?? ''})——负事实对应的可住/可订断言不得出现` })
298
+ continue
299
+ }
300
+ traceable++
301
+ }
302
+
303
+ // 酒店 claim(D-26):目的地+档期回溯酒店事实;无事实 fail-closed
304
+ for (const c of claims.hotels) {
305
+ if (claims.anchors.has(c.line)) continue
306
+ if (!c.destination) {
307
+ violations.push({ kind: 'unverifiable_hotel_claim', line: c.line, detail: `酒店可住断言缺目的地上下文,无法回溯 exact-date 事实——fail closed 按未核验处理` })
308
+ continue
309
+ }
310
+ const r = hotelClaimVerdict(facts, { destination: c.destination, check_in: c.check_in, check_out: c.check_out })
311
+ if (r.verdict === 'traceable') {
312
+ traceable++
313
+ continue
314
+ }
315
+ if (r.verdict === 'unverified') {
316
+ violations.push({ kind: 'unverifiable_hotel_claim', line: c.line, detail: r.reason })
317
+ } else {
318
+ violations.push({ kind: 'not_in_source', line: c.line, detail: r.reason })
319
+ }
320
+ if (CHECK_MARK.test(c.text)) {
321
+ violations.push({ kind: 'unconditional_check', line: c.line, detail: '对未核验酒店使用无条件 ✓/✅——只有 bookable_exact_date 才允许确定性标记' })
322
+ }
323
+ }
324
+
245
325
  for (const c of claims.flights) {
246
326
  if (c.carrier_only) {
247
327
  // 承运级直飞断言:注册表该 route+date 须存在该承运的 bookable 直飞
@@ -334,7 +414,7 @@ export function gateArtifact(
334
414
  if (!line.includes('联程')) return
335
415
  const nos = [...line.matchAll(FLIGHT_NO)].map(m => m[1]!.toUpperCase())
336
416
  const matched = facts.filter((f): f is Extract<BookableFact, { kind: 'flight' | 'train' }> =>
337
- f.kind !== 'policy' && nos.includes(f.flight_no.toUpperCase()))
417
+ (f.kind === 'flight' || f.kind === 'train') && nos.includes(f.flight_no.toUpperCase()))
338
418
  const allProtected = nos.length > 0
339
419
  && matched.length === nos.length
340
420
  && matched.every(f => f.protected_connection === true)
@@ -22,6 +22,8 @@ export const BENCHMARK_CONFORMANCE_STATE_UNAVAILABLE = 'BENCHMARK_CONFORMANCE_ST
22
22
 
23
23
  const IDENTIFIER = /^[A-Za-z][A-Za-z0-9_.-]*$/
24
24
  const MAX_TERMINAL_BYTES = 1024 * 1024
25
+ const BENCHMARK_TOOL_RESULT_SCHEMA_VERSION = 'gotry_benchmark_tool_result_v1'
26
+ const BENCHMARK_DOMAIN_RECOVERIES = new Set(['none', 'retry_same', 'revise_arguments', 'choose_alternative'])
25
27
 
26
28
  export interface TerminalOutputConfig {
27
29
  tag: string
@@ -46,6 +48,8 @@ interface TurnState {
46
48
  retryCount: number
47
49
  retryMode: RetryMode
48
50
  successfulResultStep?: number
51
+ domainOutcomeStep?: number
52
+ lastBridgeResponseStep?: number
49
53
  bridgeCallFailed: boolean
50
54
  bridgeFailureCode?: string
51
55
  retryRedispatchAttempted: boolean
@@ -89,12 +93,19 @@ function invalidTerminal(): TerminalOutputValue {
89
93
  return { ok: false, error: 'invalid_terminal_output' }
90
94
  }
91
95
 
96
+ /** 剥离推理模型的思考标签对(如 MiniMax/DeepSeek 的 <think>…</think>):当代模型
97
+ * 即便被明令「只回终态包」也会以思考块前缀输出——不剥则严格终态门对推理模型
98
+ * 结构性失效(Round 9 治理面实测)。只剥配对的推理标签本体,其余前后缀仍 fail-closed。 */
99
+ function stripReasoningBlocks(raw: string): string {
100
+ return raw.replace(/<think>[\s\S]*?<\/think>\s*/gi, '')
101
+ }
102
+
92
103
  /** Parse exactly one configured tag pair containing one JSON object. */
93
104
  export function parseBenchmarkTerminal(raw: string, config: TerminalOutputConfig): TerminalOutputValue {
94
105
  if (!validateTerminalOutputConfig(config)) return invalidTerminal()
95
106
  if (Buffer.byteLength(raw, 'utf8') > config.max_bytes) return invalidTerminal()
96
107
 
97
- const trimmed = raw.trim()
108
+ const trimmed = stripReasoningBlocks(raw).trim()
98
109
  const opening = `<${config.tag}>`
99
110
  const closing = `</${config.tag}>`
100
111
  if (!trimmed.startsWith(opening) || !trimmed.endsWith(closing)) return invalidTerminal()
@@ -143,7 +154,9 @@ function assistantText(data: Record<string, unknown>): { text: string; interrupt
143
154
  return { text, interrupted: data.interrupted === true }
144
155
  }
145
156
 
146
- function bridgeResultStatus(data: Record<string, unknown>, callId: string): { ok: true } | { ok: false; code: string } | undefined {
157
+ type BridgeResultStatus = { kind: 'result' } | { kind: 'domain' } | { kind: 'failure'; code: string }
158
+
159
+ function bridgeResultStatus(data: Record<string, unknown>, callId: string): BridgeResultStatus | undefined {
147
160
  if (!plainObject(data.message) || !plainObject(data.message.source)) return undefined
148
161
  if (data.message.source.callId !== callId || !Array.isArray(data.message.content)) return undefined
149
162
  const block = data.message.content.find(candidate => plainObject(candidate)
@@ -157,8 +170,28 @@ function bridgeResultStatus(data: Record<string, unknown>, callId: string): { ok
157
170
  try {
158
171
  const parsed: unknown = JSON.parse(text)
159
172
  if (!plainObject(parsed)) return undefined
160
- if (parsed.ok === true) return { ok: true }
173
+ const keys = Object.keys(parsed).sort().join(',')
174
+ if (parsed.ok === true && keys === 'ok,result' && (plainObject(parsed.result) || Array.isArray(parsed.result))) return { kind: 'result' }
175
+ if (parsed.ok === true && keys === 'ok,outcome' && plainObject(parsed.outcome)) {
176
+ const outcomeKeys = Object.keys(parsed.outcome).sort().join(',')
177
+ if (outcomeKeys === 'code,recovery,schema_version,status'
178
+ && parsed.outcome.schema_version === BENCHMARK_TOOL_RESULT_SCHEMA_VERSION
179
+ && (parsed.outcome.status === 'miss' || parsed.outcome.status === 'error')
180
+ && typeof parsed.outcome.code === 'string'
181
+ && IDENTIFIER.test(parsed.outcome.code)
182
+ && typeof parsed.outcome.recovery === 'string'
183
+ && BENCHMARK_DOMAIN_RECOVERIES.has(parsed.outcome.recovery)) return { kind: 'domain' }
184
+ return undefined
185
+ }
161
186
  if (parsed.ok === false && typeof parsed.error === 'string') {
187
+ const exactFailure = parsed.error === 'runner_failed'
188
+ ? (keys === 'error,ok' || (keys === 'error,exit_code,ok,signal'
189
+ && (parsed.exit_code === null || (typeof parsed.exit_code === 'number' && Number.isInteger(parsed.exit_code)))
190
+ && (parsed.signal === null || typeof parsed.signal === 'string')))
191
+ : parsed.error === 'invalid_arguments'
192
+ ? keys === 'error,ok,reason' && typeof parsed.reason === 'string'
193
+ : keys === 'error,ok'
194
+ if (!exactFailure) return undefined
162
195
  const code = parsed.error === 'timed_out'
163
196
  ? BENCHMARK_BRIDGE_TIMED_OUT
164
197
  : parsed.error === 'runner_failed'
@@ -168,7 +201,7 @@ function bridgeResultStatus(data: Record<string, unknown>, callId: string): { ok
168
201
  : parsed.error === 'output_truncated'
169
202
  ? BENCHMARK_BRIDGE_OUTPUT_TRUNCATED
170
203
  : BENCHMARK_BRIDGE_CALL_FAILED
171
- return { ok: false, code }
204
+ return { kind: 'failure', code }
172
205
  }
173
206
  return undefined
174
207
  } catch {
@@ -227,10 +260,11 @@ export function createBenchmarkAgentConformance(projection: BenchmarkBridgeProje
227
260
  }
228
261
  if (typeof event.data.callId !== 'string') return
229
262
  const args = parseToolArguments(event.data.arguments)
230
- const query = args && plainObject(args.query) ? args.query : undefined
231
- if (query?.action === 'call'
232
- && typeof query.tool === 'string'
233
- && projection.allowedTools.includes(query.tool)) {
263
+ // Round 8(issue #100/#102):bridge 工具 typed 泛化后,模型出参为平铺形态
264
+ const flat = args && plainObject(args) ? args : undefined
265
+ if (flat?.action === 'call'
266
+ && typeof flat.tool === 'string'
267
+ && projection.allowedTools.includes(flat.tool)) {
234
268
  state.validCallIds.add(event.data.callId)
235
269
  }
236
270
  return
@@ -241,10 +275,15 @@ export function createBenchmarkAgentConformance(projection: BenchmarkBridgeProje
241
275
  const callId = event.data.message.source.callId
242
276
  if (typeof callId !== 'string' || !state.validCallIds.has(callId)) return
243
277
  const resultStatus = bridgeResultStatus(event.data, callId)
244
- if (resultStatus?.ok === true) {
278
+ if (typeof event.data.step === 'number') state.lastBridgeResponseStep = event.data.step
279
+ if (resultStatus?.kind === 'result') {
245
280
  state.successfulResultStep = typeof event.data.step === 'number'
246
281
  ? event.data.step
247
282
  : state.successfulResultStep
283
+ } else if (resultStatus?.kind === 'domain') {
284
+ state.domainOutcomeStep = typeof event.data.step === 'number'
285
+ ? event.data.step
286
+ : state.domainOutcomeStep
248
287
  } else {
249
288
  state.bridgeCallFailed = true
250
289
  state.bridgeFailureCode = resultStatus?.code ?? BENCHMARK_BRIDGE_CALL_FAILED
@@ -266,10 +305,10 @@ export function createBenchmarkAgentConformance(projection: BenchmarkBridgeProje
266
305
  if (state.retryRedispatchAttempted) {
267
306
  return { kind: 'reject', code: BENCHMARK_BRIDGE_RETRY_CALL_NOT_ALLOWED }
268
307
  }
269
- if (state.successfulResultStep === undefined) {
270
- if (state.bridgeCallFailed) {
271
- return { kind: 'reject', code: state.bridgeFailureCode ?? BENCHMARK_BRIDGE_CALL_FAILED }
272
- }
308
+ if (state.bridgeCallFailed && state.successfulResultStep === undefined) {
309
+ return { kind: 'reject', code: state.bridgeFailureCode ?? BENCHMARK_BRIDGE_CALL_FAILED }
310
+ }
311
+ if (state.successfulResultStep === undefined && state.domainOutcomeStep === undefined) {
273
312
  if (state.retryCount >= MAX_CONFORMANCE_RETRIES) {
274
313
  return { kind: 'reject', code: BENCHMARK_BRIDGE_CALL_REQUIRED }
275
314
  }
@@ -281,7 +320,7 @@ export function createBenchmarkAgentConformance(projection: BenchmarkBridgeProje
281
320
  const terminal = state.lastAssistant
282
321
  const terminalIsValid = terminal !== undefined
283
322
  && !terminal.interrupted
284
- && terminal.step > state.successfulResultStep
323
+ && terminal.step > state.lastBridgeResponseStep!
285
324
  && parseBenchmarkTerminal(terminal.text, projection.terminal).ok
286
325
  if (terminalIsValid) return { kind: 'accept' }
287
326
  if (state.retryCount >= MAX_CONFORMANCE_RETRIES) {
@@ -338,7 +377,7 @@ function systemSection(projection: BenchmarkBridgeProjection): { name: string; t
338
377
  text: [
339
378
  'Benchmark execution contract:',
340
379
  `- Translate every task instruction to use a CLI, shell, Python, or agent_env.cli into the native tool ${projection.toolName}; do not merely describe the intended command.`,
341
- `- Call it with exactly {"query":{"action":"call","tool":"<one of: ${allowed}>","arguments":{...}}}.`,
380
+ `- Call it with exactly {"action":"call","tool":"<one of: ${allowed}>","arguments":{...}}.`,
342
381
  '- action:"tools" is discovery only and does not satisfy the required environment call.',
343
382
  `- After a successful tool result, reply only <${projection.terminal.tag}>{...one JSON object...}</${projection.terminal.tag}> with no prose or code fence.`,
344
383
  '- If a terminal-format correction arrives, reuse the existing result and do not call the tool again.',