@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.
- package/README.md +42 -16
- package/README.zh-CN.md +37 -15
- package/bin/gotry-bootstrap.js +309 -30
- package/bin/gotry-inner.js +74 -23
- package/bin/gotry-runtime-resolution.d.ts +1 -1
- package/bin/gotry-runtime-resolution.js +7 -8
- package/cordis.gotry-patch.yml +22 -8
- package/data/stations-12306-verify.json +524 -0
- package/dist/capabilities/agent-reach.js +4 -4
- package/dist/capabilities/anything.js +62 -29
- package/dist/capabilities/channel-health.js +103 -0
- package/dist/capabilities/channel-registry.js +213 -0
- package/dist/capabilities/doctor.js +307 -0
- package/dist/capabilities/effect.js +178 -5
- package/dist/capabilities/flyai.js +13 -0
- package/dist/capabilities/hbcli.js +28 -2
- package/dist/capabilities/session/adapters/ctrip-hotel.js +207 -0
- package/dist/capabilities/session/adapters/rail-12306.js +285 -0
- package/dist/capabilities/session/extension-bridge.js +14 -1
- package/dist/capabilities/session/extension-channel.js +4 -2
- package/dist/capabilities/session/extension-distribution.js +1 -1
- package/dist/capabilities/session-search.js +311 -0
- package/dist/capabilities/visa-policy.js +126 -0
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +305 -0
- package/dist/scripts/agent-planning-turn-deadline-tests.js +281 -0
- package/dist/scripts/anything-tests.js +70 -21
- package/dist/scripts/benchmark-environment-bridge-e2e.js +139 -37
- package/dist/scripts/benchmark-environment-bridge-tests.js +1099 -306
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +26 -26
- package/dist/scripts/{booking-copilot-availability-policy-v2-tests.js → booking-copilot-availability-policy-tests.js} +115 -115
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +41 -1
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +75 -120
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +370 -61
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +2 -2
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +7 -3
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +15 -9
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +19 -11
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +16 -52
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +3953 -155
- package/dist/scripts/booking-copilot-server-proof-tests.js +58 -23
- package/dist/scripts/booking-copilot-startup-proof-tests.js +10 -119
- package/dist/scripts/booking-surface-contract-proof-tests.js +1154 -326
- package/dist/scripts/bootstrap-tests.js +113 -2
- package/dist/scripts/build-metrics-report.js +339 -0
- package/dist/scripts/channel-probe-tests.js +148 -0
- package/dist/scripts/channel-probe.js +252 -0
- package/dist/scripts/channel-registry-tests.js +262 -0
- package/dist/scripts/doctor-tests.js +175 -0
- package/dist/scripts/effect-tests.js +274 -1
- package/dist/scripts/extension-tests.js +129 -11
- package/dist/scripts/fact-gate-tests.js +91 -2
- package/dist/scripts/flyai-tests.js +17 -1
- package/dist/scripts/hbcli-e2e-tests.js +1 -3
- package/dist/scripts/hbcli-tests.js +38 -1
- package/dist/scripts/metrics-report-tests.js +288 -0
- package/dist/scripts/persona-surface-guard-tests.js +19 -0
- package/dist/scripts/session-tests.js +401 -1
- package/dist/scripts/smoke.js +100 -83
- package/dist/scripts/turn-handoff-collect-tests.js +216 -0
- package/dist/scripts/turn-handoff-collect.js +189 -0
- package/dist/scripts/turn-policy-tests.js +56 -0
- package/dist/scripts/typed-contract-canary.js +261 -0
- package/dist/scripts/visa-policy-tests.js +75 -0
- package/dist/scripts/wish-channel-gate-tests.js +111 -0
- package/dist/src/artifact-gate.js +91 -3
- package/dist/src/benchmark-agent-conformance.js +39 -16
- package/dist/src/benchmark-environment-bridge.js +316 -52
- package/dist/src/bookable-facts.js +62 -3
- package/dist/src/booking-surface/{availability-policy-v2.js → availability-policy.js} +89 -89
- package/dist/src/booking-surface/canonical-schema.js +8 -22
- package/dist/src/booking-surface/contracts.js +70 -19
- package/dist/src/booking-surface/dsh-planner.js +310 -177
- package/dist/src/booking-surface/dsh-plugin.js +3 -3
- package/dist/src/booking-surface/index.js +1 -5
- package/dist/src/booking-surface/profile.js +1 -1
- package/dist/src/booking-surface/runtime.js +1682 -247
- package/dist/src/booking-surface/server.js +371 -185
- package/dist/src/booking-surface/startup.js +17 -27
- package/dist/src/booking-surface/validation.js +270 -760
- package/dist/src/index.js +739 -150
- package/dist/src/turn-deadline.js +292 -0
- package/dist/src/turn-policy.js +146 -0
- package/dist/src/wish-pool.js +5 -0
- package/extension/background.js +23 -4
- package/extension/content-main.js +47 -9
- package/extension/manifest.json +27 -9
- package/package.json +7 -26
- package/schemas/booking.surface.schema.json +2593 -0
- package/ts/capabilities/agent-reach.ts +4 -4
- package/ts/capabilities/anything.ts +89 -38
- package/ts/capabilities/flyai.ts +21 -3
- package/ts/capabilities/hbcli.ts +53 -4
- package/ts/capabilities/session/action-cache.ts +1 -1
- package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
- package/ts/capabilities/session/adapters/rail-12306.ts +293 -0
- package/ts/capabilities/session/extension-bridge.ts +32 -2
- package/ts/capabilities/session/extension-channel.ts +9 -8
- package/ts/capabilities/session/extension-distribution.ts +3 -1
- package/ts/capabilities/session/health-watch.ts +1 -1
- package/ts/capabilities/session/read-guard.ts +1 -1
- package/ts/capabilities/session/wizard.ts +1 -1
- package/ts/capabilities/session-search.ts +323 -1
- package/ts/dsh-runtime/vendor/README.md +60 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +200 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +202 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +216 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +371 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +56 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +126 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +109 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +27 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +170 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +53 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +20 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +55 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +91 -0
- package/ts/package.json +9 -0
- package/ts/scripts/turn-handoff-collect.ts +178 -0
- package/ts/src/artifact-gate.ts +82 -2
- package/ts/src/benchmark-agent-conformance.ts +54 -15
- package/ts/src/benchmark-environment-bridge.ts +234 -46
- package/ts/src/bookable-facts.ts +109 -5
- package/ts/src/booking-saga.ts +1 -1
- package/ts/src/booking-surface/{availability-policy-v2.ts → availability-policy.ts} +124 -125
- package/ts/src/booking-surface/canonical-schema.js +8 -22
- package/ts/src/booking-surface/contracts.ts +278 -239
- package/ts/src/booking-surface/dsh-planner.ts +333 -194
- package/ts/src/booking-surface/dsh-plugin.js +3 -3
- package/ts/src/booking-surface/index.ts +1 -5
- package/ts/src/booking-surface/profile.ts +11 -11
- package/ts/src/booking-surface/runtime.ts +1351 -351
- package/ts/src/booking-surface/server.ts +282 -175
- package/ts/src/booking-surface/startup.ts +36 -48
- package/ts/src/booking-surface/validation.ts +194 -442
- package/ts/src/contracts.ts +1 -1
- package/ts/src/index.ts +492 -172
- package/ts/src/loop.ts +1 -1
- package/ts/src/state-ledger.ts +1 -1
- package/ts/src/turn-deadline.ts +365 -0
- package/ts/src/turn-policy.ts +154 -0
- package/ts/src/wish-pool.ts +17 -4
- package/dist/scripts/agent-planning-budget-e2e.js +0 -227
- package/dist/scripts/agent-planning-budget-tests.js +0 -173
- package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +0 -3935
- package/dist/scripts/booking-surface-v2-contract-proof-tests.js +0 -1174
- package/dist/src/booking-surface/contracts-v2.js +0 -89
- package/dist/src/booking-surface/runtime-v2.js +0 -1771
- package/dist/src/booking-surface/server-v2.js +0 -334
- package/dist/src/booking-surface/validation-v2.js +0 -319
- package/dist/src/tool-budget.js +0 -136
- package/schemas/booking.surface.v1.schema.json +0 -927
- package/schemas/booking.surface.v2.schema.json +0 -61
- package/ts/src/booking-surface/contracts-v2.ts +0 -118
- package/ts/src/booking-surface/runtime-v2.ts +0 -1466
- package/ts/src/booking-surface/server-v2.ts +0 -247
- package/ts/src/booking-surface/validation-v2.ts +0 -205
- package/ts/src/tool-budget.ts +0 -165
package/ts/src/artifact-gate.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
&&
|
|
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 (
|
|
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
|
-
|
|
271
|
-
|
|
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.
|
|
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 {"
|
|
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.',
|