@danceiny/gotry 0.0.1-rc.21 → 0.0.1-rc.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -194
- package/README.zh-CN.md +115 -210
- package/bin/gotry-backend.js +53 -0
- package/bin/gotry-bootstrap.js +466 -35
- package/bin/gotry-inner.js +255 -36
- package/bin/gotry-process-liveness.d.ts +27 -0
- package/bin/gotry-process-liveness.js +97 -0
- package/bin/gotry-runtime-resolution.d.ts +1 -1
- package/bin/gotry-runtime-resolution.js +2 -2
- package/client/client.js +174 -0
- package/cordis.gotry-patch.yml +70 -93
- package/dist/capabilities/agent-reach-deep.js +45 -122
- package/dist/capabilities/agent-reach.js +63 -148
- package/dist/capabilities/anything.js +89 -75
- package/dist/capabilities/artifacts.js +123 -104
- package/dist/capabilities/channel-health.js +65 -45
- package/dist/capabilities/channel-registry.js +108 -87
- package/dist/capabilities/doctor.js +357 -235
- package/dist/capabilities/effect.js +223 -309
- package/dist/capabilities/fact-log.js +28 -14
- package/dist/capabilities/flyai.js +245 -156
- package/dist/capabilities/ground-transfer.js +509 -0
- package/dist/capabilities/hbcli.js +144 -148
- package/dist/capabilities/hotelbyte-transaction.js +194 -0
- package/dist/capabilities/incident-log.js +131 -61
- package/dist/capabilities/model-override.js +30 -10
- package/dist/capabilities/opensky.js +54 -43
- package/dist/capabilities/resilience.js +50 -32
- package/dist/capabilities/session/action-cache.js +50 -44
- package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
- package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
- package/dist/capabilities/session/adapters/dida-portal.js +206 -0
- package/dist/capabilities/session/adapters/meituan-local.js +35 -54
- package/dist/capabilities/session/adapters/rail-12306.js +169 -112
- package/dist/capabilities/session/benchmark.js +85 -149
- package/dist/capabilities/session/extension-bridge.js +320 -259
- package/dist/capabilities/session/extension-channel.js +57 -76
- package/dist/capabilities/session/extension-distribution.js +115 -119
- package/dist/capabilities/session/extract.js +31 -21
- package/dist/capabilities/session/golden-score.js +55 -33
- package/dist/capabilities/session/health-watch.js +146 -154
- package/dist/capabilities/session/read-guard.js +55 -47
- package/dist/capabilities/session/static-flight-golden.js +49 -36
- package/dist/capabilities/session/transport.js +54 -61
- package/dist/capabilities/session/wizard.js +63 -93
- package/dist/capabilities/session-consent.js +143 -47
- package/dist/capabilities/session-login.js +95 -126
- package/dist/capabilities/session-search.js +391 -253
- package/dist/capabilities/sponsor-plugin.js +341 -0
- package/dist/capabilities/visa-policy.js +87 -73
- package/dist/capabilities/weather.js +163 -235
- package/dist/scripts/action-cache-tests.js +24 -59
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
- package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
- package/dist/scripts/agent-reach-deep-tests.js +30 -40
- package/dist/scripts/agent-reach-tests.js +26 -18
- package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
- package/dist/scripts/anything-tests.js +58 -62
- package/dist/scripts/artifact-client-contract-tests.js +69 -0
- package/dist/scripts/artifacts-capability-tests.js +235 -0
- package/dist/scripts/async-collect.js +26 -15
- package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
- package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
- package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
- package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
- package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
- package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
- package/dist/scripts/booking-executor-tests.js +80 -0
- package/dist/scripts/booking-recovery-chain-tests.js +182 -0
- package/dist/scripts/booking-saga-tests.js +61 -123
- package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
- package/dist/scripts/bootstrap-tests.js +1383 -128
- package/dist/scripts/build-changelog.js +89 -130
- package/dist/scripts/build-metrics-report.js +135 -143
- package/dist/scripts/changelog-tests.js +35 -82
- package/dist/scripts/channel-probe-tests.js +44 -116
- package/dist/scripts/channel-probe.js +84 -167
- package/dist/scripts/channel-registry-tests.js +97 -185
- package/dist/scripts/companion-tests.js +25 -70
- package/dist/scripts/dida-cookie-probe.js +87 -0
- package/dist/scripts/dida-sw-probe.js +114 -0
- package/dist/scripts/diff-test.js +17 -12
- package/dist/scripts/doctor-tests.js +428 -120
- package/dist/scripts/dsh-artifact-e2e.js +150 -0
- package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
- package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
- package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
- package/dist/scripts/dsh-runtime-closure.js +75 -63
- package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
- package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
- package/dist/scripts/dsh-target-closure-proof.js +178 -0
- package/dist/scripts/effect-tests.js +165 -552
- package/dist/scripts/engine-run.js +1 -3
- package/dist/scripts/engine-tests.js +16 -10
- package/dist/scripts/evaluation-cadence-tests.js +69 -242
- package/dist/scripts/evaluation-contract-tests.js +193 -499
- package/dist/scripts/extension-distribution-cli.js +19 -15
- package/dist/scripts/extension-distribution-tests.js +98 -211
- package/dist/scripts/extension-tests.js +366 -389
- package/dist/scripts/fact-gate-tests.js +725 -263
- package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
- package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
- package/dist/scripts/flight-malformed-tests.js +159 -0
- package/dist/scripts/flyai-tests.js +325 -68
- package/dist/scripts/g5-guard-tests.js +131 -0
- package/dist/scripts/g5-guard.js +189 -0
- package/dist/scripts/gen-lunar-anchors.js +106 -0
- package/dist/scripts/gotry-backend-kernel-tests.js +79 -0
- package/dist/scripts/ground-transfer-tests.js +956 -0
- package/dist/scripts/hbcli-e2e-tests.js +71 -90
- package/dist/scripts/hbcli-live-optin-tests.js +96 -0
- package/dist/scripts/hbcli-release-contract-tests.js +122 -0
- package/dist/scripts/hbcli-tests.js +41 -115
- package/dist/scripts/health-watch-cli.js +42 -28
- package/dist/scripts/hotel-date-gate-tests.js +496 -0
- package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
- package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
- package/dist/scripts/i18n-tests.js +16 -9
- package/dist/scripts/incident-tests.js +281 -87
- package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
- package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
- package/dist/scripts/issue-271-liveness-tests.js +547 -0
- package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
- package/dist/scripts/issue-289-model-retry-tests.js +441 -0
- package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
- package/dist/scripts/issue-338-home-city-e2e.js +577 -0
- package/dist/scripts/issue343-real-entry-e2e.js +160 -0
- package/dist/scripts/journey-tests.js +22 -27
- package/dist/scripts/kernel-manifest-evidence.js +109 -0
- package/dist/scripts/kernel-manifest-gate.js +126 -0
- package/dist/scripts/kernel-manifest-tests.js +212 -0
- package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
- package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
- package/dist/scripts/kernel-manifest.js +369 -0
- package/dist/scripts/ledger-repair-apply-tests.js +316 -0
- package/dist/scripts/ledger-repair-plan-tests.js +375 -0
- package/dist/scripts/ledger-tests.js +325 -340
- package/dist/scripts/ledger-workflow-crash.js +10 -20
- package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
- package/dist/scripts/memory-capture-tests.js +242 -61
- package/dist/scripts/memory-decay-tests.js +18 -52
- package/dist/scripts/memory-lifecycle-tests.js +657 -0
- package/dist/scripts/memory-lifecycle.js +196 -0
- package/dist/scripts/memory-metrics.js +24 -12
- package/dist/scripts/memory-value-report.js +474 -222
- package/dist/scripts/memory-value-tests.js +328 -0
- package/dist/scripts/metrics-report-tests.js +62 -199
- package/dist/scripts/model-override-e2e.js +66 -105
- package/dist/scripts/nightly-evidence-tests.js +64 -89
- package/dist/scripts/nightly-evidence.js +108 -111
- package/dist/scripts/nudge-digest.js +39 -28
- package/dist/scripts/onboarding-tests.js +63 -88
- package/dist/scripts/opensky-check.js +18 -13
- package/dist/scripts/opensky-tests.js +28 -28
- package/dist/scripts/persona-surface-guard-tests.js +37 -12
- package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
- package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
- package/dist/scripts/price-drift-tests.js +126 -227
- package/dist/scripts/price-drift-watch.js +209 -253
- package/dist/scripts/probe-poi-tests.js +52 -45
- package/dist/scripts/product-metrics.js +187 -273
- package/dist/scripts/publish-preverify.js +47 -41
- package/dist/scripts/realtime-pricing-tests.js +37 -76
- package/dist/scripts/replay-async.js +20 -18
- package/dist/scripts/replay-real.js +16 -18
- package/dist/scripts/replay.js +52 -82
- package/dist/scripts/session-attach-diagnose.js +16 -12
- package/dist/scripts/session-attach-poc.js +34 -37
- package/dist/scripts/session-benchmark.js +66 -147
- package/dist/scripts/session-dida-live-e2e.js +151 -0
- package/dist/scripts/session-extract-tests.js +14 -35
- package/dist/scripts/session-login.js +14 -13
- package/dist/scripts/session-tests.js +545 -583
- package/dist/scripts/sf-live-benchmark.js +92 -110
- package/dist/scripts/sf-live-cli-tests.js +2 -9
- package/dist/scripts/sf-soft-score-tests.js +19 -60
- package/dist/scripts/sf-summary-tests.js +149 -0
- package/dist/scripts/sf-summary.js +466 -84
- package/dist/scripts/skeleton-check.js +16 -14
- package/dist/scripts/skeleton-integration-test.js +11 -10
- package/dist/scripts/skills-contract-tests.js +51 -46
- package/dist/scripts/smoke-session-gate-tests.js +12 -20
- package/dist/scripts/smoke.js +541 -422
- package/dist/scripts/sponsor-reuse-tests.js +262 -0
- package/dist/scripts/state-cli-tests.js +226 -101
- package/dist/scripts/state-cli.js +549 -212
- package/dist/scripts/static-golden-tests.js +46 -180
- package/dist/scripts/time-eval-tests.js +210 -192
- package/dist/scripts/travel-timeline-tests.js +29 -93
- package/dist/scripts/turn-handoff-collect-tests.js +46 -93
- package/dist/scripts/turn-handoff-collect.js +71 -99
- package/dist/scripts/turn-policy-tests.js +28 -29
- package/dist/scripts/typed-contract-canary.js +77 -162
- package/dist/scripts/tz-resolver-sanity.js +50 -0
- package/dist/scripts/tz-resolver-tests.js +584 -0
- package/dist/scripts/unified-tests.js +23 -19
- package/dist/scripts/visa-policy-tests.js +31 -44
- package/dist/scripts/weather-tests.js +121 -543
- package/dist/scripts/wish-channel-gate-tests.js +29 -86
- package/dist/scripts/write-gate-tests.js +522 -0
- package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
- package/dist/scripts/z3-lifecycle-tests.js +170 -0
- package/dist/scripts/z3-race-repeat-tests.js +39 -0
- package/dist/scripts/z3-race-tests.js +18 -12
- package/dist/src/artifact-gate.js +652 -221
- package/dist/src/backend/kernel.js +91 -0
- package/dist/src/backend/modules/booking-copilot.js +55 -0
- package/dist/src/backend/modules/booking-executor.js +124 -0
- package/dist/src/backend/modules/session-search.js +194 -0
- package/dist/src/benchmark-agent-conformance.js +296 -262
- package/dist/src/benchmark-environment-bridge.js +298 -413
- package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
- package/dist/src/benchmark-tool-isolation.js +94 -67
- package/dist/src/bookable-facts.js +299 -174
- package/dist/src/booking-saga.js +64 -120
- package/dist/src/booking-surface/availability-policy.js +443 -576
- package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
- package/dist/src/booking-surface/contracts.js +24 -80
- package/dist/src/booking-surface/dsh-planner.js +510 -281
- package/dist/src/booking-surface/dsh-plugin.js +17 -1
- package/dist/src/booking-surface/error-codes.js +82 -10
- package/dist/src/booking-surface/index.js +0 -3
- package/dist/src/booking-surface/profile.js +10 -54
- package/dist/src/booking-surface/recovery-chain.js +367 -0
- package/dist/src/booking-surface/runtime.js +765 -891
- package/dist/src/booking-surface/server.js +200 -251
- package/dist/src/booking-surface/startup.js +58 -54
- package/dist/src/booking-surface/validation.js +150 -218
- package/dist/src/bridge.js +20 -13
- package/dist/src/companions.js +48 -74
- package/dist/src/contracts.js +21 -43
- package/dist/src/dsh-llm.js +82 -120
- package/dist/src/engine.js +253 -239
- package/dist/src/evaluation-cadence.js +72 -209
- package/dist/src/evaluation-contracts.js +220 -843
- package/dist/src/flight-pack-adapter.js +54 -0
- package/dist/src/flight-pack-contract.js +2 -0
- package/dist/src/gotry-backend.js +70 -0
- package/dist/src/hotel-date-gate.js +118 -0
- package/dist/src/i18n.js +18 -7
- package/dist/src/index.js +1425 -1629
- package/dist/src/journey.js +132 -81
- package/dist/src/ledger-repair-apply.js +538 -0
- package/dist/src/ledger-repair-plan.js +463 -0
- package/dist/src/loop.js +257 -166
- package/dist/src/memory-capture.js +180 -32
- package/dist/src/memory-decay.js +30 -14
- package/dist/src/memory-lifecycle.js +1310 -0
- package/dist/src/memory-utility.js +27 -40
- package/dist/src/mock-llm.js +36 -61
- package/dist/src/model.js +81 -36
- package/dist/src/realtime-pricing.js +63 -72
- package/dist/src/slot-spec.js +84 -106
- package/dist/src/state-ledger.js +310 -471
- package/dist/src/subagent-job-id-guard.js +58 -0
- package/dist/src/time-anchor.js +231 -33
- package/dist/src/tool-packet.js +20 -8
- package/dist/src/travel-slots.js +58 -35
- package/dist/src/travel-timeline.js +44 -63
- package/dist/src/turn-deadline.js +121 -127
- package/dist/src/turn-policy.js +61 -89
- package/dist/src/tz-resolver.js +143 -0
- package/dist/src/unified.js +504 -381
- package/dist/src/wish-pool.js +39 -14
- package/dist/src/write-gate.js +495 -0
- package/dist/src/z3-shared.js +273 -7
- package/extension/README.md +4 -3
- package/extension/background.js +125 -14
- package/extension/content-bridge.js +23 -1
- package/extension/content-main.js +15 -4
- package/extension/manifest.json +16 -8
- package/package.json +251 -220
- package/ts/capabilities/agent-reach.ts +4 -4
- package/ts/capabilities/anything.ts +1 -1
- package/ts/capabilities/artifacts.ts +46 -9
- package/ts/capabilities/flyai.ts +156 -37
- package/ts/capabilities/hbcli.ts +1 -1
- package/ts/capabilities/incident-log.ts +88 -59
- package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
- package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
- package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
- package/ts/capabilities/session/extension-bridge.ts +226 -101
- package/ts/capabilities/session/extension-channel.ts +22 -9
- package/ts/capabilities/session/wizard.ts +2 -2
- package/ts/capabilities/session-consent.ts +98 -14
- package/ts/capabilities/session-login.ts +1 -0
- package/ts/capabilities/session-search.ts +315 -31
- package/ts/dsh-runtime/vendor/README.md +8 -4
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
- package/ts/package.json +236 -16
- package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
- package/ts/scripts/state-cli.ts +418 -51
- package/ts/src/artifact-gate.ts +561 -15
- package/ts/src/benchmark-environment-bridge.ts +37 -20
- package/ts/src/bookable-facts.ts +183 -7
- package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
- package/ts/src/booking-surface/dsh-planner.ts +240 -32
- package/ts/src/booking-surface/dsh-plugin.js +17 -1
- package/ts/src/booking-surface/error-codes.ts +75 -0
- package/ts/src/booking-surface/recovery-chain.ts +409 -0
- package/ts/src/booking-surface/server.ts +84 -51
- package/ts/src/booking-surface/validation.ts +2 -0
- package/ts/src/contracts.ts +12 -2
- package/ts/src/dsh-llm.ts +4 -8
- package/ts/src/index.ts +609 -90
- package/ts/src/loop.ts +116 -7
- package/ts/src/memory-capture.ts +227 -3
- package/ts/src/mock-llm.ts +4 -8
- package/ts/src/model.ts +88 -2
- package/ts/src/state-ledger.ts +47 -29
- package/ts/src/subagent-job-id-guard.ts +72 -0
- package/ts/src/time-anchor.ts +217 -13
- package/ts/src/unified.ts +316 -54
|
@@ -1,220 +1,233 @@
|
|
|
1
1
|
import { accessSync, constants, lstatSync, readFileSync, statSync } from 'node:fs';
|
|
2
2
|
import { getuid } from 'node:process';
|
|
3
3
|
import { isAbsolute } from 'node:path';
|
|
4
|
-
import { assertSupportedJsonSchema, validateJsonSchemaValue, ToolArgsError } from '@deepseek-ai/dsh-tools';
|
|
5
|
-
import { validateTerminalOutputConfig } from './benchmark-agent-conformance.js';
|
|
4
|
+
import { assertSupportedJsonSchema, validateJsonSchemaValue, ToolArgsError, } from '@deepseek-ai/dsh-tools';
|
|
5
|
+
import { validateTerminalOutputConfig, } from './benchmark-agent-conformance.js';
|
|
6
|
+
// v4(#215 Round 12):terminal_output 携带 closed body schema(结构关键字白名单,
|
|
7
|
+
// 禁数据值注解面);v3 及更早配置缺该面,按契约不兼容 fail-closed。
|
|
6
8
|
const SCHEMA_VERSION = 'gotry_benchmark_environment_bridge_v4';
|
|
7
9
|
export const BENCHMARK_TOOL_RESULT_SCHEMA_VERSION = 'gotry_benchmark_tool_result_v1';
|
|
8
|
-
export const BENCHMARK_DOMAIN_RECOVERIES = [
|
|
9
|
-
'none',
|
|
10
|
-
'retry_same',
|
|
11
|
-
'revise_arguments',
|
|
12
|
-
'choose_alternative'
|
|
13
|
-
];
|
|
10
|
+
export const BENCHMARK_DOMAIN_RECOVERIES = ['none', 'retry_same', 'revise_arguments', 'choose_alternative'];
|
|
14
11
|
const IDENTIFIER = /^[A-Za-z][A-Za-z0-9_.-]*$/;
|
|
15
12
|
const RECOVERIES = new Set(BENCHMARK_DOMAIN_RECOVERIES);
|
|
16
|
-
const CONFIG_KEYS = [
|
|
17
|
-
'argv_prefix',
|
|
18
|
-
'cwd',
|
|
19
|
-
'enabled',
|
|
20
|
-
'executable',
|
|
21
|
-
'isolation',
|
|
22
|
-
'max_output_bytes',
|
|
23
|
-
'schema_version',
|
|
24
|
-
'terminal_output',
|
|
25
|
-
'timeout_ms',
|
|
26
|
-
'tools'
|
|
27
|
-
];
|
|
13
|
+
const CONFIG_KEYS = ['argv_prefix', 'cwd', 'enabled', 'executable', 'isolation', 'max_output_bytes', 'schema_version', 'terminal_output', 'timeout_ms', 'tools'];
|
|
28
14
|
const INPUT_SCHEMA_MAX_BYTES = 16 * 1024;
|
|
29
15
|
const INPUT_SCHEMA_MAX_DEPTH = 8;
|
|
30
16
|
const INPUT_SCHEMA_MAX_NODES = 256;
|
|
31
17
|
const INPUT_SCHEMA_MAX_PROPERTIES = 256;
|
|
32
18
|
const INPUT_SCHEMA_MAX_ENUM_VALUES = 256;
|
|
33
19
|
const INPUT_SCHEMA_MAX_DESCRIPTION_LENGTH = 512;
|
|
34
|
-
const INPUT_SCHEMA_TYPES = new Set([
|
|
35
|
-
'string',
|
|
36
|
-
'number',
|
|
37
|
-
'integer',
|
|
38
|
-
'boolean',
|
|
39
|
-
'null',
|
|
40
|
-
'array',
|
|
41
|
-
'object'
|
|
42
|
-
]);
|
|
20
|
+
const INPUT_SCHEMA_TYPES = new Set(['string', 'number', 'integer', 'boolean', 'null', 'array', 'object']);
|
|
43
21
|
function plainObject(value) {
|
|
44
22
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
45
23
|
}
|
|
46
24
|
function deepFreezeJson(value) {
|
|
47
|
-
if (!value || typeof value !== 'object' || Object.isFrozen(value))
|
|
48
|
-
|
|
25
|
+
if (!value || typeof value !== 'object' || Object.isFrozen(value))
|
|
26
|
+
return value;
|
|
27
|
+
for (const child of Object.values(value))
|
|
28
|
+
deepFreezeJson(child);
|
|
49
29
|
return Object.freeze(value);
|
|
50
30
|
}
|
|
51
31
|
function existingExecutable(value) {
|
|
52
|
-
if (typeof value !== 'string' || !isAbsolute(value))
|
|
32
|
+
if (typeof value !== 'string' || !isAbsolute(value))
|
|
33
|
+
return false;
|
|
53
34
|
try {
|
|
54
35
|
const stat = statSync(value);
|
|
55
36
|
accessSync(value, constants.X_OK);
|
|
56
37
|
return stat.isFile();
|
|
57
|
-
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
58
40
|
return false;
|
|
59
41
|
}
|
|
60
42
|
}
|
|
61
43
|
function existingDirectory(value) {
|
|
62
|
-
if (typeof value !== 'string' || !isAbsolute(value))
|
|
44
|
+
if (typeof value !== 'string' || !isAbsolute(value))
|
|
45
|
+
return false;
|
|
63
46
|
try {
|
|
64
47
|
return statSync(value).isDirectory();
|
|
65
|
-
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
66
50
|
return false;
|
|
67
51
|
}
|
|
68
52
|
}
|
|
69
53
|
function identifiers(value, allowEmpty = false) {
|
|
70
|
-
return Array.isArray(value) && (allowEmpty || value.length > 0) && value.length <= 64 && new Set(value).size === value.length && value.every(
|
|
54
|
+
return Array.isArray(value) && (allowEmpty || value.length > 0) && value.length <= 64 && new Set(value).size === value.length && value.every(item => typeof item === 'string' && item.length > 0 && IDENTIFIER.test(item));
|
|
71
55
|
}
|
|
72
56
|
function exactKeys(value, allowed) {
|
|
73
|
-
return Object.keys(value).every(
|
|
57
|
+
return Object.keys(value).every(key => allowed.includes(key));
|
|
74
58
|
}
|
|
75
59
|
function validDescription(value, required = false) {
|
|
76
|
-
if (value === undefined)
|
|
77
|
-
|
|
60
|
+
if (value === undefined)
|
|
61
|
+
return !required;
|
|
62
|
+
return typeof value === 'string'
|
|
63
|
+
&& (!required || value.trim().length > 0)
|
|
64
|
+
&& value.length <= INPUT_SCHEMA_MAX_DESCRIPTION_LENGTH
|
|
65
|
+
&& !/[\u0000-\u001f\u007f]/.test(value);
|
|
78
66
|
}
|
|
79
67
|
function scalarMatches(type, value) {
|
|
80
|
-
if (type === 'string')
|
|
81
|
-
|
|
82
|
-
if (type === '
|
|
83
|
-
|
|
68
|
+
if (type === 'string')
|
|
69
|
+
return typeof value === 'string' && value.length <= 512;
|
|
70
|
+
if (type === 'number')
|
|
71
|
+
return typeof value === 'number' && Number.isFinite(value);
|
|
72
|
+
if (type === 'integer')
|
|
73
|
+
return typeof value === 'number' && Number.isSafeInteger(value);
|
|
74
|
+
if (type === 'boolean')
|
|
75
|
+
return typeof value === 'boolean';
|
|
84
76
|
return type === 'null' && value === null;
|
|
85
77
|
}
|
|
86
78
|
function validInputSchema(value) {
|
|
87
|
-
if (!plainObject(value))
|
|
79
|
+
if (!plainObject(value))
|
|
80
|
+
return false;
|
|
88
81
|
let serialized;
|
|
89
82
|
try {
|
|
90
83
|
serialized = JSON.stringify(value);
|
|
91
|
-
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
92
86
|
return false;
|
|
93
87
|
}
|
|
94
|
-
if (Buffer.byteLength(serialized, 'utf8') > INPUT_SCHEMA_MAX_BYTES)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
node: value,
|
|
98
|
-
depth: 0
|
|
99
|
-
}
|
|
100
|
-
];
|
|
88
|
+
if (Buffer.byteLength(serialized, 'utf8') > INPUT_SCHEMA_MAX_BYTES)
|
|
89
|
+
return false;
|
|
90
|
+
const pending = [{ node: value, depth: 0 }];
|
|
101
91
|
const seen = new Set();
|
|
102
92
|
let nodes = 0;
|
|
103
93
|
let properties = 0;
|
|
104
94
|
let enumValues = 0;
|
|
105
|
-
while(pending.length > 0){
|
|
95
|
+
while (pending.length > 0) {
|
|
106
96
|
const { node, depth } = pending.pop();
|
|
107
|
-
if (seen.has(node) || ++nodes > INPUT_SCHEMA_MAX_NODES || depth > INPUT_SCHEMA_MAX_DEPTH)
|
|
97
|
+
if (seen.has(node) || ++nodes > INPUT_SCHEMA_MAX_NODES || depth > INPUT_SCHEMA_MAX_DEPTH)
|
|
98
|
+
return false;
|
|
108
99
|
seen.add(node);
|
|
109
|
-
if (!INPUT_SCHEMA_TYPES.has(String(node.type)) || !validDescription(node.description))
|
|
100
|
+
if (!INPUT_SCHEMA_TYPES.has(String(node.type)) || !validDescription(node.description))
|
|
101
|
+
return false;
|
|
110
102
|
if (node.type === 'object') {
|
|
111
|
-
if (!exactKeys(node, [
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
'additionalProperties'
|
|
117
|
-
]) || !plainObject(node.properties) || !Array.isArray(node.required) || node.additionalProperties !== false) return false;
|
|
103
|
+
if (!exactKeys(node, ['type', 'description', 'properties', 'required', 'additionalProperties'])
|
|
104
|
+
|| !plainObject(node.properties)
|
|
105
|
+
|| !Array.isArray(node.required)
|
|
106
|
+
|| node.additionalProperties !== false)
|
|
107
|
+
return false;
|
|
118
108
|
const propertyEntries = Object.entries(node.properties);
|
|
119
109
|
properties += propertyEntries.length;
|
|
120
|
-
if (properties > INPUT_SCHEMA_MAX_PROPERTIES || propertyEntries.some(([key, child])
|
|
110
|
+
if (properties > INPUT_SCHEMA_MAX_PROPERTIES || propertyEntries.some(([key, child]) => !IDENTIFIER.test(key) || !plainObject(child)))
|
|
111
|
+
return false;
|
|
121
112
|
const required = node.required;
|
|
122
|
-
if (required.length > propertyEntries.length
|
|
123
|
-
|
|
124
|
-
node
|
|
125
|
-
|
|
126
|
-
|
|
113
|
+
if (required.length > propertyEntries.length
|
|
114
|
+
|| new Set(required).size !== required.length
|
|
115
|
+
|| required.some(key => typeof key !== 'string' || !Object.hasOwn(node.properties, key)))
|
|
116
|
+
return false;
|
|
117
|
+
for (const [, child] of propertyEntries)
|
|
118
|
+
pending.push({ node: child, depth: depth + 1 });
|
|
127
119
|
continue;
|
|
128
120
|
}
|
|
129
121
|
if (node.type === 'array') {
|
|
130
|
-
if (!exactKeys(node, [
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
'items'
|
|
134
|
-
]) || !plainObject(node.items)) return false;
|
|
135
|
-
pending.push({
|
|
136
|
-
node: node.items,
|
|
137
|
-
depth: depth + 1
|
|
138
|
-
});
|
|
122
|
+
if (!exactKeys(node, ['type', 'description', 'items']) || !plainObject(node.items))
|
|
123
|
+
return false;
|
|
124
|
+
pending.push({ node: node.items, depth: depth + 1 });
|
|
139
125
|
continue;
|
|
140
126
|
}
|
|
141
|
-
if (!exactKeys(node, [
|
|
142
|
-
'
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
]) || Object.hasOwn(node, 'enum') && Object.hasOwn(node, 'const')) return false;
|
|
147
|
-
if (Object.hasOwn(node, 'const') && !scalarMatches(String(node.type), node.const)) return false;
|
|
127
|
+
if (!exactKeys(node, ['type', 'description', 'enum', 'const'])
|
|
128
|
+
|| (Object.hasOwn(node, 'enum') && Object.hasOwn(node, 'const')))
|
|
129
|
+
return false;
|
|
130
|
+
if (Object.hasOwn(node, 'const') && !scalarMatches(String(node.type), node.const))
|
|
131
|
+
return false;
|
|
148
132
|
if (Object.hasOwn(node, 'enum')) {
|
|
149
|
-
if (!Array.isArray(node.enum) || node.enum.length === 0 || node.enum.length > 64)
|
|
133
|
+
if (!Array.isArray(node.enum) || node.enum.length === 0 || node.enum.length > 64)
|
|
134
|
+
return false;
|
|
150
135
|
enumValues += node.enum.length;
|
|
151
|
-
if (enumValues > INPUT_SCHEMA_MAX_ENUM_VALUES
|
|
136
|
+
if (enumValues > INPUT_SCHEMA_MAX_ENUM_VALUES
|
|
137
|
+
|| new Set(node.enum).size !== node.enum.length
|
|
138
|
+
|| node.enum.some(item => !scalarMatches(String(node.type), item)))
|
|
139
|
+
return false;
|
|
152
140
|
}
|
|
153
141
|
}
|
|
154
142
|
return value.type === 'object';
|
|
155
143
|
}
|
|
156
144
|
function toolDescriptors(value) {
|
|
157
|
-
if (!Array.isArray(value) || value.length === 0 || value.length > 64)
|
|
145
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > 64)
|
|
146
|
+
return false;
|
|
158
147
|
const names = new Set();
|
|
159
|
-
return value.every(
|
|
160
|
-
if (!plainObject(item))
|
|
148
|
+
return value.every(item => {
|
|
149
|
+
if (!plainObject(item))
|
|
150
|
+
return false;
|
|
161
151
|
const keys = Object.keys(item).sort();
|
|
162
|
-
const required = [
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
];
|
|
168
|
-
if (JSON.stringify(keys) !== JSON.stringify([
|
|
169
|
-
...required,
|
|
170
|
-
'output_keys'
|
|
171
|
-
].sort())) return false;
|
|
172
|
-
if (typeof item.name !== 'string' || !IDENTIFIER.test(item.name) || names.has(item.name)) return false;
|
|
152
|
+
const required = ['description', 'domain_outcomes', 'input_schema', 'name'];
|
|
153
|
+
if (JSON.stringify(keys) !== JSON.stringify([...required, 'output_keys'].sort()))
|
|
154
|
+
return false;
|
|
155
|
+
if (typeof item.name !== 'string' || !IDENTIFIER.test(item.name) || names.has(item.name))
|
|
156
|
+
return false;
|
|
173
157
|
names.add(item.name);
|
|
174
|
-
if (!validDescription(item.description, true) || !validInputSchema(item.input_schema))
|
|
175
|
-
|
|
158
|
+
if (!validDescription(item.description, true) || !validInputSchema(item.input_schema))
|
|
159
|
+
return false;
|
|
160
|
+
if (!Array.isArray(item.domain_outcomes) || item.domain_outcomes.length > 64)
|
|
161
|
+
return false;
|
|
176
162
|
const outcomeKeys = new Set();
|
|
177
|
-
if (!item.domain_outcomes.every(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
163
|
+
if (!item.domain_outcomes.every(outcome => plainObject(outcome)
|
|
164
|
+
&& JSON.stringify(Object.keys(outcome).sort()) === JSON.stringify(['code', 'recovery', 'status'])
|
|
165
|
+
&& (outcome.status === 'miss' || outcome.status === 'error')
|
|
166
|
+
&& typeof outcome.code === 'string' && IDENTIFIER.test(outcome.code)
|
|
167
|
+
&& typeof outcome.recovery === 'string' && RECOVERIES.has(outcome.recovery)
|
|
168
|
+
&& !outcomeKeys.has(outcome.code)
|
|
169
|
+
&& (outcomeKeys.add(outcome.code), true)))
|
|
170
|
+
return false;
|
|
182
171
|
return identifiers(item.output_keys);
|
|
183
172
|
});
|
|
184
173
|
}
|
|
174
|
+
// These are passed as direct argv entries (never through a shell), so options
|
|
175
|
+
// such as "-m" and dotted module names are valid. Keep the prefix bounded and
|
|
176
|
+
// reject line/control separators that could make diagnostics ambiguous.
|
|
185
177
|
function argvPrefix(value) {
|
|
186
|
-
return Array.isArray(value) && value.length > 0 && value.length <= 32 && value.every(
|
|
178
|
+
return Array.isArray(value) && value.length > 0 && value.length <= 32 && value.every(item => typeof item === 'string'
|
|
179
|
+
&& item.length > 0
|
|
180
|
+
&& item.length <= 256
|
|
181
|
+
&& !item.includes('\0')
|
|
182
|
+
&& !item.includes('\r')
|
|
183
|
+
&& !item.includes('\n'));
|
|
187
184
|
}
|
|
188
185
|
function exactIsolation(value) {
|
|
189
|
-
if (!plainObject(value))
|
|
186
|
+
if (!plainObject(value))
|
|
187
|
+
return false;
|
|
190
188
|
const keys = Object.keys(value).sort();
|
|
191
|
-
return JSON.stringify(keys) === JSON.stringify([
|
|
192
|
-
|
|
193
|
-
'
|
|
194
|
-
'
|
|
195
|
-
]) && value.mode === 'host-enforced' && value.writes === 'forbidden' && value.network === 'denied';
|
|
189
|
+
return JSON.stringify(keys) === JSON.stringify(['mode', 'network', 'writes'])
|
|
190
|
+
&& value.mode === 'host-enforced'
|
|
191
|
+
&& value.writes === 'forbidden'
|
|
192
|
+
&& value.network === 'denied';
|
|
196
193
|
}
|
|
197
194
|
function validBound(value, maximum) {
|
|
198
195
|
return typeof value === 'number' && Number.isInteger(value) && value >= 1 && value <= maximum;
|
|
199
196
|
}
|
|
200
197
|
function validate(value) {
|
|
201
198
|
const configKeys = plainObject(value) ? Object.keys(value).sort() : [];
|
|
202
|
-
const baseKeys = [
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
199
|
+
const baseKeys = [...CONFIG_KEYS].sort();
|
|
200
|
+
if (!plainObject(value)
|
|
201
|
+
|| JSON.stringify(configKeys) !== JSON.stringify(baseKeys)
|
|
202
|
+
|| value.schema_version !== SCHEMA_VERSION
|
|
203
|
+
|| value.enabled !== true
|
|
204
|
+
|| !existingExecutable(value.executable)
|
|
205
|
+
|| !existingDirectory(value.cwd)
|
|
206
|
+
|| !argvPrefix(value.argv_prefix)
|
|
207
|
+
|| !toolDescriptors(value.tools)
|
|
208
|
+
|| !validBound(value.timeout_ms, 120_000)
|
|
209
|
+
|| !validBound(value.max_output_bytes, 10 * 1024 * 1024)
|
|
210
|
+
|| !validateTerminalOutputConfig(value.terminal_output)
|
|
211
|
+
|| !exactIsolation(value.isolation))
|
|
212
|
+
return false;
|
|
206
213
|
return true;
|
|
207
214
|
}
|
|
215
|
+
/** Read and validate an owner-local bridge config without exposing its contents. */
|
|
208
216
|
export function loadBenchmarkEnvironmentConfig(path) {
|
|
209
217
|
try {
|
|
210
|
-
if (!isAbsolute(path))
|
|
218
|
+
if (!isAbsolute(path))
|
|
219
|
+
return null;
|
|
211
220
|
const metadata = lstatSync(path);
|
|
212
|
-
if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size > 64 * 1024)
|
|
213
|
-
|
|
214
|
-
if (
|
|
221
|
+
if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size > 64 * 1024)
|
|
222
|
+
return null;
|
|
223
|
+
if (typeof getuid !== 'function' || metadata.uid !== getuid())
|
|
224
|
+
return null;
|
|
225
|
+
if ((metadata.mode & 0o022) !== 0)
|
|
226
|
+
return null;
|
|
215
227
|
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
216
228
|
return validate(parsed) ? deepFreezeJson(parsed) : null;
|
|
217
|
-
}
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
218
231
|
return null;
|
|
219
232
|
}
|
|
220
233
|
}
|
|
@@ -222,7 +235,8 @@ function structuredObject(text) {
|
|
|
222
235
|
try {
|
|
223
236
|
const parsed = JSON.parse(text.trim());
|
|
224
237
|
return plainObject(parsed) ? parsed : null;
|
|
225
|
-
}
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
226
240
|
return null;
|
|
227
241
|
}
|
|
228
242
|
}
|
|
@@ -230,123 +244,68 @@ function jsonObject(value) {
|
|
|
230
244
|
return JSON.parse(JSON.stringify(value));
|
|
231
245
|
}
|
|
232
246
|
const FORBIDDEN_OUTPUT_KEY_FRAGMENTS = [
|
|
233
|
-
'answer',
|
|
234
|
-
'
|
|
235
|
-
'gold',
|
|
236
|
-
'groundtruth',
|
|
237
|
-
'hiddenquery',
|
|
238
|
-
'label',
|
|
239
|
-
'loadermetadata',
|
|
240
|
-
'oracle',
|
|
241
|
-
'reference',
|
|
242
|
-
'reward',
|
|
243
|
-
'score'
|
|
247
|
+
'answer', 'expected', 'gold', 'groundtruth', 'hiddenquery', 'label',
|
|
248
|
+
'loadermetadata', 'oracle', 'reference', 'reward', 'score',
|
|
244
249
|
];
|
|
245
250
|
export const BRIDGE_ERROR_CONTRACT = Object.freeze({
|
|
246
|
-
invalid_action: {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
},
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
},
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
remedy: 'arguments 必须是可序列化 JSON 对象(≤64KB、深度≤12);收窄后重试'
|
|
257
|
-
},
|
|
258
|
-
timed_out: {
|
|
259
|
-
recoverable: true,
|
|
260
|
-
remedy: '上游超时;可原样重试一次或换其他工具'
|
|
261
|
-
},
|
|
262
|
-
output_truncated: {
|
|
263
|
-
recoverable: true,
|
|
264
|
-
remedy: '输出超出上限;让被调工具收窄查询范围后重试'
|
|
265
|
-
},
|
|
266
|
-
invalid_json: {
|
|
267
|
-
recoverable: true,
|
|
268
|
-
remedy: '上游输出不是合法 JSON;重试一次或换工具'
|
|
269
|
-
},
|
|
270
|
-
invalid_output: {
|
|
271
|
-
recoverable: true,
|
|
272
|
-
remedy: '上游输出结构不符;重试或换工具'
|
|
273
|
-
},
|
|
274
|
-
runner_failed: {
|
|
275
|
-
recoverable: true,
|
|
276
|
-
remedy: '上游进程非零退出;可重试一次,持续失败换工具'
|
|
277
|
-
},
|
|
278
|
-
spawn_failed: {
|
|
279
|
-
recoverable: false,
|
|
280
|
-
remedy: '可执行文件不可用——环境问题,调用方不可恢复'
|
|
281
|
-
},
|
|
282
|
-
forbidden_output: {
|
|
283
|
-
recoverable: false,
|
|
284
|
-
remedy: '输出含未授权键(策略边界)——不可恢复,换工具或放弃'
|
|
285
|
-
}
|
|
251
|
+
invalid_action: { recoverable: true, remedy: 'action 只允许 tools、call 或 errors' },
|
|
252
|
+
disallowed_tool: { recoverable: true, remedy: '先 action=tools 列出 allowed_tools 清单,再从清单内选工具' },
|
|
253
|
+
invalid_arguments: { recoverable: true, remedy: 'arguments 必须是可序列化 JSON 对象(≤64KB、深度≤12);收窄后重试' },
|
|
254
|
+
timed_out: { recoverable: true, remedy: '上游超时;可原样重试一次或换其他工具' },
|
|
255
|
+
output_truncated: { recoverable: true, remedy: '输出超出上限;让被调工具收窄查询范围后重试' },
|
|
256
|
+
invalid_json: { recoverable: true, remedy: '上游输出不是合法 JSON;重试一次或换工具' },
|
|
257
|
+
invalid_output: { recoverable: true, remedy: '上游输出结构不符;重试或换工具' },
|
|
258
|
+
runner_failed: { recoverable: true, remedy: '上游进程非零退出;可重试一次,持续失败换工具' },
|
|
259
|
+
spawn_failed: { recoverable: false, remedy: '可执行文件不可用——环境问题,调用方不可恢复' },
|
|
260
|
+
forbidden_output: { recoverable: false, remedy: '输出含未授权键(策略边界)——不可恢复,换工具或放弃' },
|
|
286
261
|
});
|
|
287
262
|
function inspectOutput(value) {
|
|
288
|
-
const pending = [
|
|
289
|
-
{
|
|
290
|
-
value,
|
|
291
|
-
depth: 0
|
|
292
|
-
}
|
|
293
|
-
];
|
|
263
|
+
const pending = [{ value, depth: 0 }];
|
|
294
264
|
let nodes = 0;
|
|
295
|
-
while(pending.length > 0){
|
|
265
|
+
while (pending.length > 0) {
|
|
296
266
|
const current = pending.pop();
|
|
297
|
-
if (++nodes > 10_000 || current.depth > 24)
|
|
267
|
+
if (++nodes > 10_000 || current.depth > 24)
|
|
268
|
+
return 'structure_limit';
|
|
298
269
|
if (Array.isArray(current.value)) {
|
|
299
|
-
for (const child of current.value)
|
|
300
|
-
value: child,
|
|
301
|
-
depth: current.depth + 1
|
|
302
|
-
});
|
|
270
|
+
for (const child of current.value)
|
|
271
|
+
pending.push({ value: child, depth: current.depth + 1 });
|
|
303
272
|
continue;
|
|
304
273
|
}
|
|
305
|
-
if (!plainObject(current.value))
|
|
306
|
-
|
|
307
|
-
|
|
274
|
+
if (!plainObject(current.value))
|
|
275
|
+
continue;
|
|
276
|
+
for (const [key, child] of Object.entries(current.value)) {
|
|
277
|
+
if (!/^[\x20-\x7E]+$/.test(key))
|
|
278
|
+
return 'forbidden_key';
|
|
308
279
|
const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
309
|
-
if (FORBIDDEN_OUTPUT_KEY_FRAGMENTS.some(
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
depth: current.depth + 1
|
|
313
|
-
});
|
|
280
|
+
if (FORBIDDEN_OUTPUT_KEY_FRAGMENTS.some(fragment => normalized.includes(fragment)))
|
|
281
|
+
return 'forbidden_key';
|
|
282
|
+
pending.push({ value: child, depth: current.depth + 1 });
|
|
314
283
|
}
|
|
315
284
|
}
|
|
316
285
|
return 'ok';
|
|
317
286
|
}
|
|
318
287
|
function inspectAllowedOutput(value, allowedKeys) {
|
|
319
288
|
const allowed = new Set(allowedKeys);
|
|
320
|
-
const pending = [
|
|
321
|
-
{
|
|
322
|
-
value,
|
|
323
|
-
depth: 0,
|
|
324
|
-
coveredByDeclaredKey: false
|
|
325
|
-
}
|
|
326
|
-
];
|
|
289
|
+
const pending = [{ value, depth: 0, coveredByDeclaredKey: false }];
|
|
327
290
|
let nodes = 0;
|
|
328
|
-
while(pending.length > 0){
|
|
291
|
+
while (pending.length > 0) {
|
|
329
292
|
const current = pending.pop();
|
|
330
|
-
if (++nodes > 10_000 || current.depth > 24)
|
|
293
|
+
if (++nodes > 10_000 || current.depth > 24)
|
|
294
|
+
return false;
|
|
331
295
|
if (Array.isArray(current.value)) {
|
|
332
|
-
for (const child of current.value)
|
|
333
|
-
value: child,
|
|
334
|
-
depth: current.depth + 1,
|
|
335
|
-
coveredByDeclaredKey: current.coveredByDeclaredKey
|
|
336
|
-
});
|
|
296
|
+
for (const child of current.value)
|
|
297
|
+
pending.push({ value: child, depth: current.depth + 1, coveredByDeclaredKey: current.coveredByDeclaredKey });
|
|
337
298
|
continue;
|
|
338
299
|
}
|
|
339
300
|
if (!plainObject(current.value)) {
|
|
340
|
-
if (!current.coveredByDeclaredKey)
|
|
301
|
+
if (!current.coveredByDeclaredKey)
|
|
302
|
+
return false;
|
|
341
303
|
continue;
|
|
342
304
|
}
|
|
343
|
-
for (const [key, child] of Object.entries(current.value)){
|
|
344
|
-
if (!allowed.has(key))
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
depth: current.depth + 1,
|
|
348
|
-
coveredByDeclaredKey: true
|
|
349
|
-
});
|
|
305
|
+
for (const [key, child] of Object.entries(current.value)) {
|
|
306
|
+
if (!allowed.has(key))
|
|
307
|
+
return false;
|
|
308
|
+
pending.push({ value: child, depth: current.depth + 1, coveredByDeclaredKey: true });
|
|
350
309
|
}
|
|
351
310
|
}
|
|
352
311
|
return true;
|
|
@@ -355,68 +314,52 @@ function serializedArguments(value) {
|
|
|
355
314
|
const seen = new Set();
|
|
356
315
|
let nodes = 0;
|
|
357
316
|
let keys = 0;
|
|
358
|
-
const inspect = (current, depth)=>{
|
|
359
|
-
if (++nodes > 10_000 || depth > 12)
|
|
317
|
+
const inspect = (current, depth) => {
|
|
318
|
+
if (++nodes > 10_000 || depth > 12)
|
|
319
|
+
return false;
|
|
360
320
|
if (current && typeof current === 'object') {
|
|
361
|
-
if (seen.has(current))
|
|
321
|
+
if (seen.has(current))
|
|
322
|
+
return false;
|
|
362
323
|
seen.add(current);
|
|
363
|
-
if (Array.isArray(current))
|
|
364
|
-
|
|
365
|
-
|
|
324
|
+
if (Array.isArray(current))
|
|
325
|
+
return current.every(item => inspect(item, depth + 1));
|
|
326
|
+
return Object.entries(current).every(([key, child]) => {
|
|
327
|
+
if (++keys > 10_000)
|
|
328
|
+
return false;
|
|
366
329
|
return inspect(key, depth + 1) && inspect(child, depth + 1);
|
|
367
330
|
});
|
|
368
331
|
}
|
|
369
332
|
return true;
|
|
370
333
|
};
|
|
371
|
-
if (!inspect(value, 0))
|
|
372
|
-
reason: 'serialization_limit'
|
|
373
|
-
};
|
|
334
|
+
if (!inspect(value, 0))
|
|
335
|
+
return { reason: 'serialization_limit' };
|
|
374
336
|
try {
|
|
375
337
|
const json = JSON.stringify(value);
|
|
376
|
-
if (typeof json !== 'string' || Buffer.byteLength(json, 'utf8') > 65_536)
|
|
377
|
-
reason: 'serialization_limit'
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
};
|
|
382
|
-
} catch {
|
|
383
|
-
return {
|
|
384
|
-
reason: 'serialization_limit'
|
|
385
|
-
};
|
|
338
|
+
if (typeof json !== 'string' || Buffer.byteLength(json, 'utf8') > 65_536)
|
|
339
|
+
return { reason: 'serialization_limit' };
|
|
340
|
+
return { json };
|
|
341
|
+
}
|
|
342
|
+
catch {
|
|
343
|
+
return { reason: 'serialization_limit' };
|
|
386
344
|
}
|
|
387
345
|
}
|
|
346
|
+
/** Register the opt-in model-facing bridge. */
|
|
388
347
|
export function registerBenchmarkEnvironmentBridge(path, register, subprocess) {
|
|
389
348
|
const bridge = loadBenchmarkEnvironmentConfig(path);
|
|
390
|
-
if (!bridge)
|
|
391
|
-
|
|
349
|
+
if (!bridge)
|
|
350
|
+
throw new Error('benchmark environment bridge configuration unavailable');
|
|
351
|
+
if (!subprocess)
|
|
352
|
+
throw new Error('benchmark environment bridge subprocess unavailable');
|
|
392
353
|
const parameters = deepFreezeJson({
|
|
393
354
|
type: 'object',
|
|
394
355
|
description: 'Flat benchmark bridge wire: choose an action, then provide the mapped tool and its arguments.',
|
|
395
356
|
properties: {
|
|
396
|
-
action: {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
'tools',
|
|
400
|
-
'call',
|
|
401
|
-
'errors'
|
|
402
|
-
],
|
|
403
|
-
description: 'tools=列出可调工具;call=执行工具;errors=拉取错误契约'
|
|
404
|
-
},
|
|
405
|
-
tool: {
|
|
406
|
-
type: 'string',
|
|
407
|
-
enum: bridge.tools.map((item)=>item.name),
|
|
408
|
-
description: 'action=call 时选择的冻结工具名'
|
|
409
|
-
},
|
|
410
|
-
arguments: {
|
|
411
|
-
type: 'object',
|
|
412
|
-
additionalProperties: true,
|
|
413
|
-
description: 'action=call 时传给工具的参数对象'
|
|
414
|
-
}
|
|
357
|
+
action: { type: 'string', enum: ['tools', 'call', 'errors'], description: 'tools=列出可调工具;call=执行工具;errors=拉取错误契约' },
|
|
358
|
+
tool: { type: 'string', enum: bridge.tools.map(item => item.name), description: 'action=call 时选择的冻结工具名' },
|
|
359
|
+
arguments: { type: 'object', additionalProperties: true, description: 'action=call 时传给工具的参数对象' },
|
|
415
360
|
},
|
|
416
|
-
required: [
|
|
417
|
-
|
|
418
|
-
],
|
|
419
|
-
additionalProperties: false
|
|
361
|
+
required: ['action'],
|
|
362
|
+
additionalProperties: false,
|
|
420
363
|
});
|
|
421
364
|
assertSupportedJsonSchema(parameters);
|
|
422
365
|
const definition = {
|
|
@@ -425,206 +368,148 @@ export function registerBenchmarkEnvironmentBridge(path, register, subprocess) {
|
|
|
425
368
|
parameters,
|
|
426
369
|
output: {
|
|
427
370
|
schema: {},
|
|
428
|
-
render: (_args, value)=>[
|
|
429
|
-
{
|
|
430
|
-
type: 'text',
|
|
431
|
-
text: JSON.stringify(value)
|
|
432
|
-
}
|
|
433
|
-
]
|
|
371
|
+
render: (_args, value) => [{ type: 'text', text: JSON.stringify(value) }],
|
|
434
372
|
},
|
|
435
|
-
async execute
|
|
373
|
+
async execute(args) {
|
|
436
374
|
const violations = validateJsonSchemaValue(parameters, args, 'arguments');
|
|
437
|
-
if (violations.length > 0)
|
|
375
|
+
if (violations.length > 0)
|
|
376
|
+
throw new ToolArgsError(violations);
|
|
438
377
|
const query = args;
|
|
439
378
|
const tool = query.tool;
|
|
440
|
-
const descriptor = bridge.tools.find(
|
|
379
|
+
const descriptor = bridge.tools.find(item => item.name === tool);
|
|
441
380
|
const keys = Object.keys(query);
|
|
442
381
|
if (query.action === 'tools') {
|
|
443
|
-
if (keys.length !== 1)
|
|
444
|
-
'arguments: tools action accepts no tool or arguments'
|
|
445
|
-
|
|
446
|
-
return jsonObject({
|
|
447
|
-
ok: true,
|
|
448
|
-
tools: bridge.tools
|
|
449
|
-
});
|
|
382
|
+
if (keys.length !== 1)
|
|
383
|
+
throw new ToolArgsError(['arguments: tools action accepts no tool or arguments']);
|
|
384
|
+
return jsonObject({ ok: true, tools: bridge.tools });
|
|
450
385
|
}
|
|
451
386
|
if (query.action === 'errors') {
|
|
452
|
-
if (keys.length !== 1)
|
|
453
|
-
'arguments: errors action accepts no tool or arguments'
|
|
454
|
-
|
|
455
|
-
return jsonObject({
|
|
456
|
-
ok: true,
|
|
457
|
-
errors: BRIDGE_ERROR_CONTRACT
|
|
458
|
-
});
|
|
387
|
+
if (keys.length !== 1)
|
|
388
|
+
throw new ToolArgsError(['arguments: errors action accepts no tool or arguments']);
|
|
389
|
+
return jsonObject({ ok: true, errors: BRIDGE_ERROR_CONTRACT });
|
|
459
390
|
}
|
|
460
391
|
if (query.action !== 'call') {
|
|
461
|
-
return jsonObject({
|
|
462
|
-
ok: false,
|
|
463
|
-
error: 'invalid_action'
|
|
464
|
-
});
|
|
392
|
+
return jsonObject({ ok: false, error: 'invalid_action' });
|
|
465
393
|
}
|
|
466
394
|
if (keys.length !== 3 || !Object.hasOwn(query, 'tool') || !Object.hasOwn(query, 'arguments')) {
|
|
467
|
-
throw new ToolArgsError([
|
|
468
|
-
'arguments: call action requires exactly tool and arguments'
|
|
469
|
-
]);
|
|
395
|
+
throw new ToolArgsError(['arguments: call action requires exactly tool and arguments']);
|
|
470
396
|
}
|
|
471
397
|
if (typeof tool !== 'string' || !descriptor) {
|
|
472
|
-
return jsonObject({
|
|
473
|
-
ok: false,
|
|
474
|
-
error: 'disallowed_tool'
|
|
475
|
-
});
|
|
398
|
+
return jsonObject({ ok: false, error: 'disallowed_tool' });
|
|
476
399
|
}
|
|
477
400
|
if (!plainObject(query.arguments)) {
|
|
478
|
-
return jsonObject({
|
|
479
|
-
ok: false,
|
|
480
|
-
error: 'invalid_arguments'
|
|
481
|
-
});
|
|
401
|
+
return jsonObject({ ok: false, error: 'invalid_arguments' });
|
|
482
402
|
}
|
|
483
403
|
const callArguments = query.arguments;
|
|
484
404
|
const argumentViolations = validateJsonSchemaValue(descriptor.input_schema, callArguments, 'arguments');
|
|
485
|
-
if (argumentViolations.length > 0)
|
|
405
|
+
if (argumentViolations.length > 0)
|
|
406
|
+
throw new ToolArgsError(argumentViolations);
|
|
486
407
|
const serialized = serializedArguments(callArguments);
|
|
487
|
-
if (serialized.reason)
|
|
488
|
-
ok: false,
|
|
489
|
-
error: 'invalid_arguments',
|
|
490
|
-
reason: serialized.reason
|
|
491
|
-
});
|
|
408
|
+
if (serialized.reason)
|
|
409
|
+
return jsonObject({ ok: false, error: 'invalid_arguments', reason: serialized.reason });
|
|
492
410
|
const controller = new AbortController();
|
|
493
|
-
const timer = setTimeout(()=>{
|
|
411
|
+
const timer = setTimeout(() => {
|
|
494
412
|
controller.abort();
|
|
495
413
|
}, bridge.timeout_ms);
|
|
496
414
|
let handle;
|
|
497
415
|
try {
|
|
498
|
-
const env = Object.fromEntries(Object.keys(process.env).map(
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
for (const key of [
|
|
503
|
-
'PATH',
|
|
504
|
-
'LANG',
|
|
505
|
-
'LC_ALL',
|
|
506
|
-
'LC_CTYPE',
|
|
507
|
-
'TZ'
|
|
508
|
-
]){
|
|
509
|
-
if (process.env[key] !== undefined) env[key] = process.env[key];
|
|
416
|
+
const env = Object.fromEntries(Object.keys(process.env).map(key => [key, undefined]));
|
|
417
|
+
for (const key of ['PATH', 'LANG', 'LC_ALL', 'LC_CTYPE', 'TZ']) {
|
|
418
|
+
if (process.env[key] !== undefined)
|
|
419
|
+
env[key] = process.env[key];
|
|
510
420
|
}
|
|
511
421
|
env.PYTHONDONTWRITEBYTECODE = '1';
|
|
512
422
|
env.PYTHONNOUSERSITE = '1';
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
bridge.executable,
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
cwd: bridge.cwd,
|
|
522
|
-
stdio: {
|
|
523
|
-
stdin: 'ignore',
|
|
524
|
-
stdout: {
|
|
525
|
-
maxBytes: bridge.max_output_bytes
|
|
423
|
+
try {
|
|
424
|
+
handle = subprocess.spawn({
|
|
425
|
+
argv: [bridge.executable, ...bridge.argv_prefix, 'call', tool, serialized.json],
|
|
426
|
+
cwd: bridge.cwd,
|
|
427
|
+
stdio: {
|
|
428
|
+
stdin: 'ignore',
|
|
429
|
+
stdout: { maxBytes: bridge.max_output_bytes },
|
|
430
|
+
stderr: { maxBytes: bridge.max_output_bytes },
|
|
526
431
|
},
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
error: '
|
|
545
|
-
}
|
|
432
|
+
graceMs: Math.min(1_000, bridge.timeout_ms),
|
|
433
|
+
env,
|
|
434
|
+
signal: controller.signal,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
if (controller.signal.aborted)
|
|
439
|
+
return jsonObject({ ok: false, error: 'timed_out' });
|
|
440
|
+
return jsonObject({ ok: false, error: 'spawn_failed' });
|
|
441
|
+
}
|
|
442
|
+
let status;
|
|
443
|
+
try {
|
|
444
|
+
status = await handle.done;
|
|
445
|
+
}
|
|
446
|
+
catch {
|
|
447
|
+
if (controller.signal.aborted)
|
|
448
|
+
return jsonObject({ ok: false, error: 'timed_out' });
|
|
449
|
+
return jsonObject({ ok: false, error: 'spawn_failed' });
|
|
450
|
+
}
|
|
451
|
+
if (controller.signal.aborted)
|
|
452
|
+
return jsonObject({ ok: false, error: 'timed_out' });
|
|
453
|
+
let stdout;
|
|
454
|
+
let stderr;
|
|
455
|
+
try {
|
|
456
|
+
stdout = handle.collected.stdout.readFrom(0);
|
|
457
|
+
stderr = handle.collected.stderr.readFrom(0);
|
|
458
|
+
}
|
|
459
|
+
catch {
|
|
460
|
+
return jsonObject({
|
|
461
|
+
ok: false,
|
|
462
|
+
error: 'runner_failed',
|
|
463
|
+
exit_code: status.exitCode,
|
|
464
|
+
signal: status.signal ?? null,
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
if (stdout.lossy || stderr.lossy)
|
|
468
|
+
return jsonObject({ ok: false, error: 'output_truncated' });
|
|
546
469
|
if (status.exitCode !== 0) {
|
|
547
470
|
return jsonObject({
|
|
548
471
|
ok: false,
|
|
549
472
|
error: 'runner_failed',
|
|
550
473
|
exit_code: status.exitCode,
|
|
551
|
-
signal: status.signal ?? null
|
|
474
|
+
signal: status.signal ?? null,
|
|
552
475
|
});
|
|
553
476
|
}
|
|
554
477
|
const parsed = structuredObject(stdout.text);
|
|
555
|
-
if (!parsed)
|
|
556
|
-
ok: false,
|
|
557
|
-
error: 'invalid_json'
|
|
558
|
-
});
|
|
478
|
+
if (!parsed)
|
|
479
|
+
return jsonObject({ ok: false, error: 'invalid_json' });
|
|
559
480
|
const outputInspection = inspectOutput(parsed);
|
|
560
|
-
if (outputInspection === 'forbidden_key')
|
|
561
|
-
ok: false,
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
if (outputInspection === 'structure_limit') return jsonObject({
|
|
565
|
-
ok: false,
|
|
566
|
-
error: 'invalid_output'
|
|
567
|
-
});
|
|
481
|
+
if (outputInspection === 'forbidden_key')
|
|
482
|
+
return jsonObject({ ok: false, error: 'forbidden_output' });
|
|
483
|
+
if (outputInspection === 'structure_limit')
|
|
484
|
+
return jsonObject({ ok: false, error: 'invalid_output' });
|
|
568
485
|
if (parsed.schema_version !== BENCHMARK_TOOL_RESULT_SCHEMA_VERSION || typeof parsed.status !== 'string') {
|
|
569
|
-
return jsonObject({
|
|
570
|
-
ok: false,
|
|
571
|
-
error: 'invalid_output'
|
|
572
|
-
});
|
|
486
|
+
return jsonObject({ ok: false, error: 'invalid_output' });
|
|
573
487
|
}
|
|
574
488
|
if (parsed.status === 'miss' || parsed.status === 'error') {
|
|
575
|
-
if (typeof parsed.code !== 'string' || typeof parsed.recovery !== 'string' || !descriptor.domain_outcomes.some(
|
|
576
|
-
ok: false,
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
ok: false,
|
|
581
|
-
error: 'invalid_output'
|
|
582
|
-
});
|
|
583
|
-
return jsonObject({
|
|
584
|
-
ok: true,
|
|
585
|
-
outcome: parsed
|
|
586
|
-
});
|
|
489
|
+
if (typeof parsed.code !== 'string' || typeof parsed.recovery !== 'string' || !descriptor.domain_outcomes.some(outcome => outcome.status === parsed.status && outcome.code === parsed.code && outcome.recovery === parsed.recovery))
|
|
490
|
+
return jsonObject({ ok: false, error: 'invalid_output' });
|
|
491
|
+
if (Object.keys(parsed).sort().join(',') !== 'code,recovery,schema_version,status')
|
|
492
|
+
return jsonObject({ ok: false, error: 'invalid_output' });
|
|
493
|
+
return jsonObject({ ok: true, outcome: parsed });
|
|
587
494
|
}
|
|
588
|
-
if (parsed.status !== 'ok' || !Object.hasOwn(parsed, 'result') || Object.keys(parsed).sort().join(',') !== 'result,schema_version,status')
|
|
589
|
-
ok: false,
|
|
590
|
-
error: 'invalid_output'
|
|
591
|
-
});
|
|
495
|
+
if (parsed.status !== 'ok' || !Object.hasOwn(parsed, 'result') || Object.keys(parsed).sort().join(',') !== 'result,schema_version,status')
|
|
496
|
+
return jsonObject({ ok: false, error: 'invalid_output' });
|
|
592
497
|
const visibleResult = parsed.result;
|
|
593
|
-
if (!plainObject(visibleResult) && !Array.isArray(visibleResult))
|
|
594
|
-
ok: false,
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
});
|
|
601
|
-
return jsonObject({
|
|
602
|
-
ok: true,
|
|
603
|
-
result: visibleResult
|
|
604
|
-
});
|
|
605
|
-
} catch {
|
|
606
|
-
if (controller.signal.aborted) return jsonObject({
|
|
607
|
-
ok: false,
|
|
608
|
-
error: 'timed_out'
|
|
609
|
-
});
|
|
610
|
-
return jsonObject({
|
|
611
|
-
ok: false,
|
|
612
|
-
error: !handle || handle.pid === -1 ? 'spawn_failed' : 'runner_failed'
|
|
613
|
-
});
|
|
614
|
-
} finally{
|
|
498
|
+
if (!plainObject(visibleResult) && !Array.isArray(visibleResult))
|
|
499
|
+
return jsonObject({ ok: false, error: 'invalid_output' });
|
|
500
|
+
if (!inspectAllowedOutput(visibleResult, descriptor.output_keys))
|
|
501
|
+
return jsonObject({ ok: false, error: 'forbidden_output' });
|
|
502
|
+
return jsonObject({ ok: true, result: visibleResult });
|
|
503
|
+
}
|
|
504
|
+
finally {
|
|
615
505
|
clearTimeout(timer);
|
|
616
506
|
}
|
|
617
|
-
}
|
|
507
|
+
},
|
|
618
508
|
};
|
|
619
509
|
register(definition);
|
|
620
510
|
return Object.freeze({
|
|
621
511
|
toolName: 'gotry_benchmark_environment',
|
|
622
|
-
allowedTools: Object.freeze(bridge.tools.map(
|
|
623
|
-
terminal: Object.freeze({
|
|
624
|
-
...bridge.terminal_output
|
|
625
|
-
})
|
|
512
|
+
allowedTools: Object.freeze(bridge.tools.map(item => item.name)),
|
|
513
|
+
terminal: Object.freeze({ ...bridge.terminal_output }),
|
|
626
514
|
});
|
|
627
515
|
}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
//# sourceURL=ts/src/benchmark-environment-bridge.ts
|