@danceiny/gotry 0.0.1-rc.19 → 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 +1 -1
- package/README.zh-CN.md +1 -1
- package/bin/gotry-bootstrap.js +83 -37
- package/bin/gotry-inner.js +11 -6
- package/cordis.gotry-patch.yml +7 -3
- package/dist/capabilities/anything.js +62 -29
- package/dist/capabilities/doctor.js +25 -3
- package/dist/capabilities/hbcli.js +28 -2
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +2 -1
- package/dist/scripts/anything-tests.js +70 -21
- package/dist/scripts/benchmark-environment-bridge-e2e.js +136 -29
- package/dist/scripts/benchmark-environment-bridge-tests.js +1056 -269
- package/dist/scripts/bootstrap-tests.js +28 -2
- package/dist/scripts/doctor-tests.js +55 -1
- package/dist/scripts/hbcli-tests.js +38 -1
- package/dist/src/benchmark-agent-conformance.js +32 -12
- package/dist/src/benchmark-environment-bridge.js +317 -114
- package/dist/src/index.js +5 -2
- package/extension/manifest.json +2 -2
- package/package.json +2 -1
- package/ts/capabilities/anything.ts +89 -38
- package/ts/capabilities/hbcli.ts +53 -4
- 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 -1
- package/ts/src/benchmark-agent-conformance.ts +40 -9
- package/ts/src/benchmark-environment-bridge.ts +235 -66
- package/ts/src/index.ts +4 -2
- package/ts/src/turn-deadline.ts +4 -0
|
@@ -1,12 +1,19 @@
|
|
|
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 {
|
|
4
|
+
import { assertSupportedJsonSchema, validateJsonSchemaValue, ToolArgsError } from '@deepseek-ai/dsh-tools';
|
|
5
5
|
import { validateTerminalOutputConfig } from './benchmark-agent-conformance.js';
|
|
6
|
-
const SCHEMA_VERSION = '
|
|
6
|
+
const SCHEMA_VERSION = 'gotry_benchmark_environment_bridge_v3';
|
|
7
|
+
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
|
+
];
|
|
7
14
|
const IDENTIFIER = /^[A-Za-z][A-Za-z0-9_.-]*$/;
|
|
15
|
+
const RECOVERIES = new Set(BENCHMARK_DOMAIN_RECOVERIES);
|
|
8
16
|
const CONFIG_KEYS = [
|
|
9
|
-
'allowed_tools',
|
|
10
17
|
'argv_prefix',
|
|
11
18
|
'cwd',
|
|
12
19
|
'enabled',
|
|
@@ -15,14 +22,87 @@ const CONFIG_KEYS = [
|
|
|
15
22
|
'max_output_bytes',
|
|
16
23
|
'schema_version',
|
|
17
24
|
'terminal_output',
|
|
18
|
-
'timeout_ms'
|
|
19
|
-
|
|
20
|
-
const OPTIONAL_CONFIG_KEYS = [
|
|
21
|
-
'allowed_output_keys'
|
|
25
|
+
'timeout_ms',
|
|
26
|
+
'tools'
|
|
22
27
|
];
|
|
28
|
+
const INPUT_SCHEMA_MAX_BYTES = 16 * 1024;
|
|
29
|
+
const INPUT_SCHEMA_MAX_DEPTH = 8;
|
|
30
|
+
const INPUT_SCHEMA_MAX_NODES = 256;
|
|
31
|
+
const INPUT_SCHEMA_MAX_PROPERTIES = 256;
|
|
32
|
+
const INPUT_SCHEMA_MAX_ENUM_VALUES = 256;
|
|
33
|
+
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
|
+
]);
|
|
43
|
+
function descriptorSchema(tools) {
|
|
44
|
+
return {
|
|
45
|
+
oneOf: [
|
|
46
|
+
{
|
|
47
|
+
type: 'object',
|
|
48
|
+
description: 'List the frozen benchmark tool descriptors.',
|
|
49
|
+
properties: {
|
|
50
|
+
action: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
const: 'tools'
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
required: [
|
|
56
|
+
'action'
|
|
57
|
+
],
|
|
58
|
+
additionalProperties: false
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: 'object',
|
|
62
|
+
description: 'List the frozen bridge error contract.',
|
|
63
|
+
properties: {
|
|
64
|
+
action: {
|
|
65
|
+
type: 'string',
|
|
66
|
+
const: 'errors'
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
required: [
|
|
70
|
+
'action'
|
|
71
|
+
],
|
|
72
|
+
additionalProperties: false
|
|
73
|
+
},
|
|
74
|
+
...tools.map((tool)=>({
|
|
75
|
+
type: 'object',
|
|
76
|
+
description: tool.description,
|
|
77
|
+
properties: {
|
|
78
|
+
action: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
const: 'call'
|
|
81
|
+
},
|
|
82
|
+
tool: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
const: tool.name
|
|
85
|
+
},
|
|
86
|
+
arguments: tool.input_schema
|
|
87
|
+
},
|
|
88
|
+
required: [
|
|
89
|
+
'action',
|
|
90
|
+
'tool',
|
|
91
|
+
'arguments'
|
|
92
|
+
],
|
|
93
|
+
additionalProperties: false
|
|
94
|
+
}))
|
|
95
|
+
]
|
|
96
|
+
};
|
|
97
|
+
}
|
|
23
98
|
function plainObject(value) {
|
|
24
99
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
25
100
|
}
|
|
101
|
+
function deepFreezeJson(value) {
|
|
102
|
+
if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value;
|
|
103
|
+
for (const child of Object.values(value))deepFreezeJson(child);
|
|
104
|
+
return Object.freeze(value);
|
|
105
|
+
}
|
|
26
106
|
function existingExecutable(value) {
|
|
27
107
|
if (typeof value !== 'string' || !isAbsolute(value)) return false;
|
|
28
108
|
try {
|
|
@@ -41,13 +121,121 @@ function existingDirectory(value) {
|
|
|
41
121
|
return false;
|
|
42
122
|
}
|
|
43
123
|
}
|
|
44
|
-
function identifiers(value) {
|
|
45
|
-
return Array.isArray(value) && value.length > 0 && value.length <= 64 && new Set(value).size === value.length && value.every((item)=>typeof item === 'string' && item.length > 0 && IDENTIFIER.test(item));
|
|
124
|
+
function identifiers(value, allowEmpty = false) {
|
|
125
|
+
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));
|
|
126
|
+
}
|
|
127
|
+
function exactKeys(value, allowed) {
|
|
128
|
+
return Object.keys(value).every((key)=>allowed.includes(key));
|
|
129
|
+
}
|
|
130
|
+
function validDescription(value, required = false) {
|
|
131
|
+
if (value === undefined) return !required;
|
|
132
|
+
return typeof value === 'string' && (!required || value.trim().length > 0) && value.length <= INPUT_SCHEMA_MAX_DESCRIPTION_LENGTH && !/[\u0000-\u001f\u007f]/.test(value);
|
|
46
133
|
}
|
|
47
|
-
function
|
|
134
|
+
function scalarMatches(type, value) {
|
|
135
|
+
if (type === 'string') return typeof value === 'string' && value.length <= 512;
|
|
136
|
+
if (type === 'number') return typeof value === 'number' && Number.isFinite(value);
|
|
137
|
+
if (type === 'integer') return typeof value === 'number' && Number.isSafeInteger(value);
|
|
138
|
+
if (type === 'boolean') return typeof value === 'boolean';
|
|
139
|
+
return type === 'null' && value === null;
|
|
140
|
+
}
|
|
141
|
+
function validInputSchema(value) {
|
|
48
142
|
if (!plainObject(value)) return false;
|
|
49
|
-
|
|
50
|
-
|
|
143
|
+
let serialized;
|
|
144
|
+
try {
|
|
145
|
+
serialized = JSON.stringify(value);
|
|
146
|
+
} catch {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
if (Buffer.byteLength(serialized, 'utf8') > INPUT_SCHEMA_MAX_BYTES) return false;
|
|
150
|
+
const pending = [
|
|
151
|
+
{
|
|
152
|
+
node: value,
|
|
153
|
+
depth: 0
|
|
154
|
+
}
|
|
155
|
+
];
|
|
156
|
+
const seen = new Set();
|
|
157
|
+
let nodes = 0;
|
|
158
|
+
let properties = 0;
|
|
159
|
+
let enumValues = 0;
|
|
160
|
+
while(pending.length > 0){
|
|
161
|
+
const { node, depth } = pending.pop();
|
|
162
|
+
if (seen.has(node) || ++nodes > INPUT_SCHEMA_MAX_NODES || depth > INPUT_SCHEMA_MAX_DEPTH) return false;
|
|
163
|
+
seen.add(node);
|
|
164
|
+
if (!INPUT_SCHEMA_TYPES.has(String(node.type)) || !validDescription(node.description)) return false;
|
|
165
|
+
if (node.type === 'object') {
|
|
166
|
+
if (!exactKeys(node, [
|
|
167
|
+
'type',
|
|
168
|
+
'description',
|
|
169
|
+
'properties',
|
|
170
|
+
'required',
|
|
171
|
+
'additionalProperties'
|
|
172
|
+
]) || !plainObject(node.properties) || !Array.isArray(node.required) || node.additionalProperties !== false) return false;
|
|
173
|
+
const propertyEntries = Object.entries(node.properties);
|
|
174
|
+
properties += propertyEntries.length;
|
|
175
|
+
if (properties > INPUT_SCHEMA_MAX_PROPERTIES || propertyEntries.some(([key, child])=>!IDENTIFIER.test(key) || !plainObject(child))) return false;
|
|
176
|
+
const required = node.required;
|
|
177
|
+
if (required.length > propertyEntries.length || new Set(required).size !== required.length || required.some((key)=>typeof key !== 'string' || !Object.hasOwn(node.properties, key))) return false;
|
|
178
|
+
for (const [, child] of propertyEntries)pending.push({
|
|
179
|
+
node: child,
|
|
180
|
+
depth: depth + 1
|
|
181
|
+
});
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (node.type === 'array') {
|
|
185
|
+
if (!exactKeys(node, [
|
|
186
|
+
'type',
|
|
187
|
+
'description',
|
|
188
|
+
'items'
|
|
189
|
+
]) || !plainObject(node.items)) return false;
|
|
190
|
+
pending.push({
|
|
191
|
+
node: node.items,
|
|
192
|
+
depth: depth + 1
|
|
193
|
+
});
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (!exactKeys(node, [
|
|
197
|
+
'type',
|
|
198
|
+
'description',
|
|
199
|
+
'enum',
|
|
200
|
+
'const'
|
|
201
|
+
]) || Object.hasOwn(node, 'enum') && Object.hasOwn(node, 'const')) return false;
|
|
202
|
+
if (Object.hasOwn(node, 'const') && !scalarMatches(String(node.type), node.const)) return false;
|
|
203
|
+
if (Object.hasOwn(node, 'enum')) {
|
|
204
|
+
if (!Array.isArray(node.enum) || node.enum.length === 0 || node.enum.length > 64) return false;
|
|
205
|
+
enumValues += node.enum.length;
|
|
206
|
+
if (enumValues > INPUT_SCHEMA_MAX_ENUM_VALUES || new Set(node.enum).size !== node.enum.length || node.enum.some((item)=>!scalarMatches(String(node.type), item))) return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return value.type === 'object';
|
|
210
|
+
}
|
|
211
|
+
function toolDescriptors(value) {
|
|
212
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > 64) return false;
|
|
213
|
+
const names = new Set();
|
|
214
|
+
return value.every((item)=>{
|
|
215
|
+
if (!plainObject(item)) return false;
|
|
216
|
+
const keys = Object.keys(item).sort();
|
|
217
|
+
const required = [
|
|
218
|
+
'description',
|
|
219
|
+
'domain_outcomes',
|
|
220
|
+
'input_schema',
|
|
221
|
+
'name'
|
|
222
|
+
];
|
|
223
|
+
if (JSON.stringify(keys) !== JSON.stringify([
|
|
224
|
+
...required,
|
|
225
|
+
'output_keys'
|
|
226
|
+
].sort())) return false;
|
|
227
|
+
if (typeof item.name !== 'string' || !IDENTIFIER.test(item.name) || names.has(item.name)) return false;
|
|
228
|
+
names.add(item.name);
|
|
229
|
+
if (!validDescription(item.description, true) || !validInputSchema(item.input_schema)) return false;
|
|
230
|
+
if (!Array.isArray(item.domain_outcomes) || item.domain_outcomes.length > 64) return false;
|
|
231
|
+
const outcomeKeys = new Set();
|
|
232
|
+
if (!item.domain_outcomes.every((outcome)=>plainObject(outcome) && JSON.stringify(Object.keys(outcome).sort()) === JSON.stringify([
|
|
233
|
+
'code',
|
|
234
|
+
'recovery',
|
|
235
|
+
'status'
|
|
236
|
+
]) && (outcome.status === 'miss' || outcome.status === 'error') && typeof outcome.code === 'string' && IDENTIFIER.test(outcome.code) && typeof outcome.recovery === 'string' && RECOVERIES.has(outcome.recovery) && !outcomeKeys.has(outcome.code) && (outcomeKeys.add(outcome.code), true))) return false;
|
|
237
|
+
return identifiers(item.output_keys);
|
|
238
|
+
});
|
|
51
239
|
}
|
|
52
240
|
function argvPrefix(value) {
|
|
53
241
|
return Array.isArray(value) && value.length > 0 && value.length <= 32 && value.every((item)=>typeof item === 'string' && item.length > 0 && item.length <= 256 && !item.includes('\0') && !item.includes('\r') && !item.includes('\n'));
|
|
@@ -69,14 +257,7 @@ function validate(value) {
|
|
|
69
257
|
const baseKeys = [
|
|
70
258
|
...CONFIG_KEYS
|
|
71
259
|
].sort();
|
|
72
|
-
|
|
73
|
-
...CONFIG_KEYS,
|
|
74
|
-
...OPTIONAL_CONFIG_KEYS
|
|
75
|
-
].sort();
|
|
76
|
-
if (!plainObject(value) || ![
|
|
77
|
-
baseKeys,
|
|
78
|
-
extendedKeys
|
|
79
|
-
].some((keys)=>JSON.stringify(configKeys) === JSON.stringify(keys)) || value.schema_version !== SCHEMA_VERSION || value.enabled !== true || !existingExecutable(value.executable) || !existingDirectory(value.cwd) || !argvPrefix(value.argv_prefix) || !identifiers(value.allowed_tools) || !validBound(value.timeout_ms, 120_000) || !validBound(value.max_output_bytes, 10 * 1024 * 1024) || !validateTerminalOutputConfig(value.terminal_output) || !exactIsolation(value.isolation) || Object.hasOwn(value, 'allowed_output_keys') && !allowedOutputKeys(value.allowed_output_keys, value.allowed_tools)) return false;
|
|
260
|
+
if (!plainObject(value) || JSON.stringify(configKeys) !== JSON.stringify(baseKeys) || value.schema_version !== SCHEMA_VERSION || value.enabled !== true || !existingExecutable(value.executable) || !existingDirectory(value.cwd) || !argvPrefix(value.argv_prefix) || !toolDescriptors(value.tools) || !validBound(value.timeout_ms, 120_000) || !validBound(value.max_output_bytes, 10 * 1024 * 1024) || !validateTerminalOutputConfig(value.terminal_output) || !exactIsolation(value.isolation)) return false;
|
|
80
261
|
return true;
|
|
81
262
|
}
|
|
82
263
|
export function loadBenchmarkEnvironmentConfig(path) {
|
|
@@ -87,7 +268,7 @@ export function loadBenchmarkEnvironmentConfig(path) {
|
|
|
87
268
|
if (typeof getuid !== 'function' || metadata.uid !== getuid()) return null;
|
|
88
269
|
if ((metadata.mode & 0o022) !== 0) return null;
|
|
89
270
|
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
90
|
-
return validate(parsed) ? parsed : null;
|
|
271
|
+
return validate(parsed) ? deepFreezeJson(parsed) : null;
|
|
91
272
|
} catch {
|
|
92
273
|
return null;
|
|
93
274
|
}
|
|
@@ -116,6 +297,48 @@ const FORBIDDEN_OUTPUT_KEY_FRAGMENTS = [
|
|
|
116
297
|
'reward',
|
|
117
298
|
'score'
|
|
118
299
|
];
|
|
300
|
+
export const BRIDGE_ERROR_CONTRACT = Object.freeze({
|
|
301
|
+
invalid_action: {
|
|
302
|
+
recoverable: true,
|
|
303
|
+
remedy: 'action 只允许 tools、call 或 errors'
|
|
304
|
+
},
|
|
305
|
+
disallowed_tool: {
|
|
306
|
+
recoverable: true,
|
|
307
|
+
remedy: '先 action=tools 列出 allowed_tools 清单,再从清单内选工具'
|
|
308
|
+
},
|
|
309
|
+
invalid_arguments: {
|
|
310
|
+
recoverable: true,
|
|
311
|
+
remedy: 'arguments 必须是可序列化 JSON 对象(≤64KB、深度≤12);收窄后重试'
|
|
312
|
+
},
|
|
313
|
+
timed_out: {
|
|
314
|
+
recoverable: true,
|
|
315
|
+
remedy: '上游超时;可原样重试一次或换其他工具'
|
|
316
|
+
},
|
|
317
|
+
output_truncated: {
|
|
318
|
+
recoverable: true,
|
|
319
|
+
remedy: '输出超出上限;让被调工具收窄查询范围后重试'
|
|
320
|
+
},
|
|
321
|
+
invalid_json: {
|
|
322
|
+
recoverable: true,
|
|
323
|
+
remedy: '上游输出不是合法 JSON;重试一次或换工具'
|
|
324
|
+
},
|
|
325
|
+
invalid_output: {
|
|
326
|
+
recoverable: true,
|
|
327
|
+
remedy: '上游输出结构不符;重试或换工具'
|
|
328
|
+
},
|
|
329
|
+
runner_failed: {
|
|
330
|
+
recoverable: true,
|
|
331
|
+
remedy: '上游进程非零退出;可重试一次,持续失败换工具'
|
|
332
|
+
},
|
|
333
|
+
spawn_failed: {
|
|
334
|
+
recoverable: false,
|
|
335
|
+
remedy: '可执行文件不可用——环境问题,调用方不可恢复'
|
|
336
|
+
},
|
|
337
|
+
forbidden_output: {
|
|
338
|
+
recoverable: false,
|
|
339
|
+
remedy: '输出含未授权键(策略边界)——不可恢复,换工具或放弃'
|
|
340
|
+
}
|
|
341
|
+
});
|
|
119
342
|
function inspectOutput(value) {
|
|
120
343
|
const pending = [
|
|
121
344
|
{
|
|
@@ -152,7 +375,8 @@ function inspectAllowedOutput(value, allowedKeys) {
|
|
|
152
375
|
const pending = [
|
|
153
376
|
{
|
|
154
377
|
value,
|
|
155
|
-
depth: 0
|
|
378
|
+
depth: 0,
|
|
379
|
+
coveredByDeclaredKey: false
|
|
156
380
|
}
|
|
157
381
|
];
|
|
158
382
|
let nodes = 0;
|
|
@@ -162,16 +386,21 @@ function inspectAllowedOutput(value, allowedKeys) {
|
|
|
162
386
|
if (Array.isArray(current.value)) {
|
|
163
387
|
for (const child of current.value)pending.push({
|
|
164
388
|
value: child,
|
|
165
|
-
depth: current.depth + 1
|
|
389
|
+
depth: current.depth + 1,
|
|
390
|
+
coveredByDeclaredKey: current.coveredByDeclaredKey
|
|
166
391
|
});
|
|
167
392
|
continue;
|
|
168
393
|
}
|
|
169
|
-
if (!plainObject(current.value))
|
|
394
|
+
if (!plainObject(current.value)) {
|
|
395
|
+
if (!current.coveredByDeclaredKey) return false;
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
170
398
|
for (const [key, child] of Object.entries(current.value)){
|
|
171
399
|
if (!allowed.has(key)) return false;
|
|
172
400
|
pending.push({
|
|
173
401
|
value: child,
|
|
174
|
-
depth: current.depth + 1
|
|
402
|
+
depth: current.depth + 1,
|
|
403
|
+
coveredByDeclaredKey: true
|
|
175
404
|
});
|
|
176
405
|
}
|
|
177
406
|
}
|
|
@@ -211,80 +440,20 @@ function serializedArguments(value) {
|
|
|
211
440
|
};
|
|
212
441
|
}
|
|
213
442
|
}
|
|
214
|
-
export const BRIDGE_ERROR_CONTRACT = Object.freeze({
|
|
215
|
-
invalid_action: {
|
|
216
|
-
recoverable: true,
|
|
217
|
-
remedy: 'action 只允许 tools 或 call'
|
|
218
|
-
},
|
|
219
|
-
disallowed_tool: {
|
|
220
|
-
recoverable: true,
|
|
221
|
-
remedy: '先 action=tools 列出 allowed_tools 清单,再从清单内选工具'
|
|
222
|
-
},
|
|
223
|
-
invalid_arguments: {
|
|
224
|
-
recoverable: true,
|
|
225
|
-
remedy: 'arguments 必须是可序列化 JSON 对象(≤64KB、深度≤12);收窄后重试'
|
|
226
|
-
},
|
|
227
|
-
timed_out: {
|
|
228
|
-
recoverable: true,
|
|
229
|
-
remedy: '上游超时;可原样重试一次或换其他工具'
|
|
230
|
-
},
|
|
231
|
-
output_truncated: {
|
|
232
|
-
recoverable: true,
|
|
233
|
-
remedy: '输出超出上限;让被调工具收窄查询范围后重试'
|
|
234
|
-
},
|
|
235
|
-
invalid_json: {
|
|
236
|
-
recoverable: true,
|
|
237
|
-
remedy: '上游输出不是合法 JSON;重试一次或换工具'
|
|
238
|
-
},
|
|
239
|
-
invalid_output: {
|
|
240
|
-
recoverable: true,
|
|
241
|
-
remedy: '上游输出结构不符(如原始字符串);重试或换工具'
|
|
242
|
-
},
|
|
243
|
-
runner_failed: {
|
|
244
|
-
recoverable: true,
|
|
245
|
-
remedy: '上游进程非零退出;可重试一次,持续失败换工具'
|
|
246
|
-
},
|
|
247
|
-
spawn_failed: {
|
|
248
|
-
recoverable: false,
|
|
249
|
-
remedy: '可执行文件不可用——环境问题,调用方不可恢复'
|
|
250
|
-
},
|
|
251
|
-
forbidden_output: {
|
|
252
|
-
recoverable: false,
|
|
253
|
-
remedy: '输出含未授权键(策略边界)——不可恢复,换工具或放弃'
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
443
|
export function registerBenchmarkEnvironmentBridge(path, register, subprocess) {
|
|
257
444
|
const bridge = loadBenchmarkEnvironmentConfig(path);
|
|
258
445
|
if (!bridge) throw new Error('benchmark environment bridge configuration unavailable');
|
|
259
446
|
if (!subprocess) throw new Error('benchmark environment bridge subprocess unavailable');
|
|
260
|
-
|
|
447
|
+
const parameters = deepFreezeJson({
|
|
448
|
+
oneOf: descriptorSchema(bridge.tools).oneOf
|
|
449
|
+
});
|
|
450
|
+
assertSupportedJsonSchema(parameters);
|
|
451
|
+
const definition = {
|
|
261
452
|
name: 'gotry_benchmark_environment',
|
|
262
|
-
description: 'When a prompt asks to run agent_env.cli, use action=call here with the mapped tool; arbitrary shell is not exposed.
|
|
263
|
-
parameters
|
|
264
|
-
action: {
|
|
265
|
-
type: 'string',
|
|
266
|
-
enum: [
|
|
267
|
-
'tools',
|
|
268
|
-
'call',
|
|
269
|
-
'errors'
|
|
270
|
-
],
|
|
271
|
-
required: true,
|
|
272
|
-
description: 'tools=列出可调工具;call=执行被映射工具;errors=拉取可恢复错误契约表'
|
|
273
|
-
},
|
|
274
|
-
tool: {
|
|
275
|
-
type: 'string',
|
|
276
|
-
description: '被调工具名(必须在 allowed_tools 清单内;action=call 时必填)'
|
|
277
|
-
},
|
|
278
|
-
arguments: {
|
|
279
|
-
type: 'object',
|
|
280
|
-
additionalProperties: true,
|
|
281
|
-
description: '传给被调工具的参数对象(action=call 时可选;≤64KB、深度≤12)'
|
|
282
|
-
}
|
|
283
|
-
},
|
|
453
|
+
description: 'When a prompt asks to run agent_env.cli, use action=call here with the mapped tool; arbitrary shell is not exposed.',
|
|
454
|
+
parameters,
|
|
284
455
|
output: {
|
|
285
|
-
schema: {
|
|
286
|
-
type: 'json'
|
|
287
|
-
},
|
|
456
|
+
schema: {},
|
|
288
457
|
render: (_args, value)=>[
|
|
289
458
|
{
|
|
290
459
|
type: 'text',
|
|
@@ -293,33 +462,45 @@ export function registerBenchmarkEnvironmentBridge(path, register, subprocess) {
|
|
|
293
462
|
]
|
|
294
463
|
},
|
|
295
464
|
async execute (args) {
|
|
296
|
-
const
|
|
297
|
-
if (
|
|
465
|
+
const violations = validateJsonSchemaValue(parameters, args, 'arguments');
|
|
466
|
+
if (violations.length > 0) throw new ToolArgsError(violations);
|
|
467
|
+
const query = args;
|
|
468
|
+
const tool = query.tool;
|
|
469
|
+
const descriptor = bridge.tools.find((item)=>item.name === tool);
|
|
470
|
+
if (query.action === 'tools') return jsonObject({
|
|
298
471
|
ok: true,
|
|
299
|
-
|
|
472
|
+
tools: bridge.tools
|
|
300
473
|
});
|
|
301
|
-
if (action === '
|
|
474
|
+
if (query.action === 'errors') return jsonObject({
|
|
302
475
|
ok: true,
|
|
303
|
-
|
|
304
|
-
});
|
|
305
|
-
if (action !== 'call') return jsonObject({
|
|
306
|
-
ok: false,
|
|
307
|
-
error: 'invalid_action'
|
|
476
|
+
errors: BRIDGE_ERROR_CONTRACT
|
|
308
477
|
});
|
|
309
|
-
|
|
310
|
-
|
|
478
|
+
if (query.action !== 'call') {
|
|
479
|
+
return jsonObject({
|
|
480
|
+
ok: false,
|
|
481
|
+
error: 'invalid_action'
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
if (typeof tool !== 'string' || !descriptor) {
|
|
311
485
|
return jsonObject({
|
|
312
486
|
ok: false,
|
|
313
487
|
error: 'disallowed_tool'
|
|
314
488
|
});
|
|
315
489
|
}
|
|
316
|
-
if (
|
|
490
|
+
if (!plainObject(query.arguments)) {
|
|
491
|
+
return jsonObject({
|
|
492
|
+
ok: false,
|
|
493
|
+
error: 'invalid_arguments'
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
const callArguments = query.arguments;
|
|
497
|
+
const argumentViolations = validateJsonSchemaValue(descriptor.input_schema, callArguments, 'arguments');
|
|
498
|
+
if (argumentViolations.length > 0) {
|
|
317
499
|
return jsonObject({
|
|
318
500
|
ok: false,
|
|
319
501
|
error: 'invalid_arguments'
|
|
320
502
|
});
|
|
321
503
|
}
|
|
322
|
-
const callArguments = query.arguments === undefined ? {} : query.arguments;
|
|
323
504
|
const serialized = serializedArguments(callArguments);
|
|
324
505
|
if (serialized.reason) return jsonObject({
|
|
325
506
|
ok: false,
|
|
@@ -352,7 +533,7 @@ export function registerBenchmarkEnvironmentBridge(path, register, subprocess) {
|
|
|
352
533
|
bridge.executable,
|
|
353
534
|
...bridge.argv_prefix,
|
|
354
535
|
'call',
|
|
355
|
-
|
|
536
|
+
tool,
|
|
356
537
|
serialized.json
|
|
357
538
|
],
|
|
358
539
|
cwd: bridge.cwd,
|
|
@@ -402,13 +583,36 @@ export function registerBenchmarkEnvironmentBridge(path, register, subprocess) {
|
|
|
402
583
|
ok: false,
|
|
403
584
|
error: 'invalid_output'
|
|
404
585
|
});
|
|
405
|
-
|
|
586
|
+
if (parsed.schema_version !== BENCHMARK_TOOL_RESULT_SCHEMA_VERSION || typeof parsed.status !== 'string') {
|
|
587
|
+
return jsonObject({
|
|
588
|
+
ok: false,
|
|
589
|
+
error: 'invalid_output'
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
if (parsed.status === 'miss' || parsed.status === 'error') {
|
|
593
|
+
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)) return jsonObject({
|
|
594
|
+
ok: false,
|
|
595
|
+
error: 'invalid_output'
|
|
596
|
+
});
|
|
597
|
+
if (Object.keys(parsed).sort().join(',') !== 'code,recovery,schema_version,status') return jsonObject({
|
|
598
|
+
ok: false,
|
|
599
|
+
error: 'invalid_output'
|
|
600
|
+
});
|
|
601
|
+
return jsonObject({
|
|
602
|
+
ok: true,
|
|
603
|
+
outcome: parsed
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
if (parsed.status !== 'ok' || !Object.hasOwn(parsed, 'result') || Object.keys(parsed).sort().join(',') !== 'result,schema_version,status') return jsonObject({
|
|
607
|
+
ok: false,
|
|
608
|
+
error: 'invalid_output'
|
|
609
|
+
});
|
|
610
|
+
const visibleResult = parsed.result;
|
|
406
611
|
if (!plainObject(visibleResult) && !Array.isArray(visibleResult)) return jsonObject({
|
|
407
612
|
ok: false,
|
|
408
613
|
error: 'invalid_output'
|
|
409
614
|
});
|
|
410
|
-
|
|
411
|
-
if (outputKeys && !inspectAllowedOutput(visibleResult, outputKeys)) return jsonObject({
|
|
615
|
+
if (!inspectAllowedOutput(visibleResult, descriptor.output_keys)) return jsonObject({
|
|
412
616
|
ok: false,
|
|
413
617
|
error: 'forbidden_output'
|
|
414
618
|
});
|
|
@@ -429,12 +633,11 @@ export function registerBenchmarkEnvironmentBridge(path, register, subprocess) {
|
|
|
429
633
|
clearTimeout(timer);
|
|
430
634
|
}
|
|
431
635
|
}
|
|
432
|
-
}
|
|
636
|
+
};
|
|
637
|
+
register(definition);
|
|
433
638
|
return Object.freeze({
|
|
434
639
|
toolName: 'gotry_benchmark_environment',
|
|
435
|
-
allowedTools: Object.freeze(
|
|
436
|
-
...bridge.allowed_tools
|
|
437
|
-
]),
|
|
640
|
+
allowedTools: Object.freeze(bridge.tools.map((item)=>item.name)),
|
|
438
641
|
terminal: Object.freeze({
|
|
439
642
|
...bridge.terminal_output
|
|
440
643
|
})
|
package/dist/src/index.js
CHANGED
|
@@ -1599,14 +1599,17 @@ export function apply(ctx, config) {
|
|
|
1599
1599
|
}
|
|
1600
1600
|
const itpA = await interpretEffect({
|
|
1601
1601
|
effect: 'ANYTHING_SEARCH',
|
|
1602
|
-
params:
|
|
1602
|
+
params: {
|
|
1603
|
+
...q,
|
|
1604
|
+
hbcliBin: config.hbcliBin
|
|
1605
|
+
}
|
|
1603
1606
|
});
|
|
1604
1607
|
if (!itpA.result) return declinedObservation('ANYTHING_SEARCH', itpA.trace);
|
|
1605
1608
|
const r = itpA.result;
|
|
1606
1609
|
const dir = await ensureStateDir(config.stateRoot);
|
|
1607
1610
|
await recordLatency(join(dir, 'bridge-latency.jsonl'), Date.now() - started, `anything:${r.via}`).catch(()=>{});
|
|
1608
1611
|
const top5 = (r.hits ?? []).slice(0, 5);
|
|
1609
|
-
const summary = r.verdict === 'hit' ? `${q.keyword} → hit (${r.hits?.length ?? 0} 候选项)\n${top5.map((h, i)=>` ${i + 1}. [${h.type}] ${h.name}${h.latitude !== undefined && h.longitude !== undefined ? ` @ (${h.latitude.toFixed(3)},${h.longitude.toFixed(3)})` : ''}`).join('\n')}\n${r.evidence}` : r.verdict === 'miss' ? `${q.keyword} → miss (酒店-be 一切正常但无候选)\n${r.evidence}` : `${q.keyword} → unavailable (${r.error})\n${r.evidence}`;
|
|
1612
|
+
const summary = r.verdict === 'hit' ? `${q.keyword} → hit (${r.hits?.length ?? 0} 候选项)\n${top5.map((h, i)=>` ${i + 1}. [${h.type}] ${h.name}${h.star ? ` ${h.star}★` : ''}${h.latitude !== undefined && h.longitude !== undefined ? ` @ (${h.latitude.toFixed(3)},${h.longitude.toFixed(3)})` : ''}${h.hotelId ? ` hotelId=${h.hotelId}` : h.destinationId ? ` destinationId=${h.destinationId}` : ''}`).join('\n')}\n${r.evidence}` : r.verdict === 'miss' ? `${q.keyword} → miss (酒店-be 一切正常但无候选)\n${r.evidence}` : `${q.keyword} → unavailable (${r.error})\n${r.evidence}`;
|
|
1610
1613
|
return JSON.parse(JSON.stringify({
|
|
1611
1614
|
ok: r.ok,
|
|
1612
1615
|
verdict: r.verdict,
|
package/extension/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "GoTry Session Bridge",
|
|
4
|
-
"version": "0.0.1.
|
|
4
|
+
"version": "0.0.1.20",
|
|
5
5
|
"description": "GoTry 会话检索桥(issue #21):在你自己的登录态里只读嗅探检索回包(机票/酒店/火车)与登录票据 cookie 名;零凭证经手,登录在官网由你完成,检索只读不写。",
|
|
6
6
|
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnuzBX8rT8+RZKEUip5VRA0cY056pExy9PNdN9YCiuY3dgglRbcIBhjuFJoR6EX3/MaUv82vJVyItRVrowXLTwDk4WZof0vwFgKL0zBK304PC46pUaAKTSu1PgXeL1+j5KTAGz/9a9+RnPdbj7jND5rM/MOmBHNPVPpp1NlwxRGIgF9OxHSOfXORcH4Iyte1aJSFUJbFtNS/DaE5D+KjyupPLyIqVN/dCiKnNsTCEHQB9ngeli665PFp76hkccHQQZ4sVuMLS4zBPcazUsp1kcnW+xsQoUATkODTCY+Pzk3zUVF1QOESTjRCVnbNi8tkO43RMRs2q63gX/3inFivcEwIDAQAB",
|
|
7
7
|
"permissions": [
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"run_at": "document_start"
|
|
47
47
|
}
|
|
48
48
|
],
|
|
49
|
-
"version_name": "0.0.1-rc.
|
|
49
|
+
"version_name": "0.0.1-rc.20"
|
|
50
50
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danceiny/gotry",
|
|
3
|
-
"version": "0.0.1-rc.
|
|
3
|
+
"version": "0.0.1-rc.20",
|
|
4
4
|
"description": "GoTry — 从出发到下一次出发的 AI 旅行 Agent(dsh 插件)。npm/源码入口共用锁定的 dsh runtime + README 安装路径。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "ts/src/index.ts",
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
"ts/capabilities/session/",
|
|
90
90
|
"extension/",
|
|
91
91
|
"ts/package.json",
|
|
92
|
+
"ts/dsh-runtime/vendor/dsh-map-tools",
|
|
92
93
|
"cordis.gotry-patch.yml",
|
|
93
94
|
"README.md",
|
|
94
95
|
"README.zh-CN.md",
|