@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.
Files changed (60) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/bin/gotry-bootstrap.js +83 -37
  4. package/bin/gotry-inner.js +11 -6
  5. package/cordis.gotry-patch.yml +7 -3
  6. package/dist/capabilities/anything.js +62 -29
  7. package/dist/capabilities/doctor.js +25 -3
  8. package/dist/capabilities/hbcli.js +28 -2
  9. package/dist/scripts/agent-planning-turn-deadline-e2e.js +2 -1
  10. package/dist/scripts/anything-tests.js +70 -21
  11. package/dist/scripts/benchmark-environment-bridge-e2e.js +136 -29
  12. package/dist/scripts/benchmark-environment-bridge-tests.js +1056 -269
  13. package/dist/scripts/bootstrap-tests.js +28 -2
  14. package/dist/scripts/doctor-tests.js +55 -1
  15. package/dist/scripts/hbcli-tests.js +38 -1
  16. package/dist/src/benchmark-agent-conformance.js +32 -12
  17. package/dist/src/benchmark-environment-bridge.js +317 -114
  18. package/dist/src/index.js +5 -2
  19. package/extension/manifest.json +2 -2
  20. package/package.json +2 -1
  21. package/ts/capabilities/anything.ts +89 -38
  22. package/ts/capabilities/hbcli.ts +53 -4
  23. package/ts/dsh-runtime/vendor/README.md +60 -0
  24. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  25. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +200 -0
  26. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +202 -0
  27. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +216 -0
  28. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  29. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +371 -0
  30. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  31. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +56 -0
  32. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  33. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  34. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +126 -0
  35. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  36. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +109 -0
  37. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +27 -0
  38. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  39. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  40. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +170 -0
  41. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +53 -0
  42. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  43. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  44. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  45. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  46. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +20 -0
  47. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  48. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  49. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  50. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  51. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  52. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +16 -0
  53. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +55 -0
  54. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  55. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +91 -0
  56. package/ts/package.json +9 -1
  57. package/ts/src/benchmark-agent-conformance.ts +40 -9
  58. package/ts/src/benchmark-environment-bridge.ts +235 -66
  59. package/ts/src/index.ts +4 -2
  60. package/ts/src/turn-deadline.ts +4 -0
@@ -0,0 +1,53 @@
1
+ /** Amap (高德) Web Service API client. */
2
+ import type { GeocodeResult, LngLat, PoiResult, RouteResult } from '../types.js';
3
+ /** 配额类错误(QPS 或日配额超限)。retryable=true 时短期内重试可能成功
4
+ * (QPS 超限),false 表示重试无意义(日配额已用尽)。 */
5
+ export declare class AmapQuotaError extends Error {
6
+ readonly infocode: string;
7
+ readonly retryable: boolean;
8
+ constructor(infocode: string, message: string, retryable: boolean);
9
+ }
10
+ export interface AmapClientOptions {
11
+ key: string;
12
+ timeoutMs: number;
13
+ /** 每秒最大高德请求数(默认 2,低于高德常见 3 QPS 上限,留余量防 10021)。 */
14
+ maxQps?: number;
15
+ }
16
+ export declare class AmapClient {
17
+ private readonly opts;
18
+ private readonly limiter;
19
+ private readonly geoCache;
20
+ private readonly routeCache;
21
+ private readonly poiCache;
22
+ constructor(opts: AmapClientOptions);
23
+ /**
24
+ * 带配额保护的统一请求入口:限速排队 → 缓存命中 → 请求 → 可重试错误退避
25
+ * 重试 → 写入缓存。
26
+ */
27
+ private request;
28
+ /** 裸 GET:拼 URL、带 key、超时 + abort、错误分类。 */
29
+ private rawGet;
30
+ /**
31
+ * Plan a route. `mode` maps to the Amap endpoint.
32
+ * Transit requires city1/city2 (origin/destination city names).
33
+ */
34
+ route(origin: LngLat, destination: LngLat, mode: 'driving' | 'transit' | 'walking' | 'bicycling', opts: {
35
+ city1?: string;
36
+ city2?: string;
37
+ } | undefined, signal: AbortSignal): Promise<RouteResult>;
38
+ private transitRoute;
39
+ /** Forward geocode: address → coordinates. */
40
+ geocode(address: string, signal: AbortSignal): Promise<GeocodeResult>;
41
+ /** Reverse geocode: coordinates → address. */
42
+ reverseGeocode(location: LngLat, signal: AbortSignal): Promise<GeocodeResult>;
43
+ /** POI text search. */
44
+ poiSearch(keywords: string, opts: {
45
+ region?: string;
46
+ cityLimit?: boolean;
47
+ }, signal: AbortSignal): Promise<PoiResult[]>;
48
+ /** POI around search (nearest first by default). */
49
+ poiAround(location: LngLat, keywords: string, opts: {
50
+ radiusM?: number;
51
+ types?: string;
52
+ }, signal: AbortSignal): Promise<PoiResult[]>;
53
+ }
@@ -0,0 +1,17 @@
1
+ /** Nominatim (OpenStreetMap) geocoding client — free fallback, 1 QPS policy. */
2
+ import type { GeocodeResult, LngLat } from '../types.js';
3
+ export interface NominatimClientOptions {
4
+ timeoutMs: number;
5
+ baseUrl?: string;
6
+ /** User-Agent identifying the client (required by Nominatim usage policy). */
7
+ userAgent: string;
8
+ }
9
+ export declare class NominatimClient {
10
+ private readonly opts;
11
+ constructor(opts: NominatimClientOptions);
12
+ private get;
13
+ /** Forward geocode. */
14
+ geocode(query: string, signal: AbortSignal): Promise<GeocodeResult>;
15
+ /** Reverse geocode. */
16
+ reverseGeocode(location: LngLat, signal: AbortSignal): Promise<GeocodeResult>;
17
+ }
@@ -0,0 +1,15 @@
1
+ /** OSRM public server client — free route fallback (no API key). */
2
+ import type { LngLat, RouteResult } from '../types.js';
3
+ export interface OsrmClientOptions {
4
+ timeoutMs: number;
5
+ baseUrl?: string;
6
+ }
7
+ export declare class OsrmClient {
8
+ private readonly opts;
9
+ constructor(opts: OsrmClientOptions);
10
+ /**
11
+ * Plan a route. `profile` maps to OSRM profiles: driving | walking | cycling.
12
+ * OSRM has no transit profile — callers must not request transit here.
13
+ */
14
+ route(origin: LngLat, destination: LngLat, profile: 'driving' | 'walking' | 'cycling', signal: AbortSignal): Promise<RouteResult>;
15
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Photon (photon.komoot.io) geocoding client — free, keyless, reachable on CN
3
+ * networks (unlike nominatim.openstreetmap.org). Backed by OpenStreetMap data.
4
+ *
5
+ * Usage policy: free public service; be reasonable with request rate. Add a
6
+ * `lang` parameter (default zh) for localized results.
7
+ */
8
+ import type { GeocodeResult, LngLat } from '../types.js';
9
+ export interface PhotonClientOptions {
10
+ timeoutMs: number;
11
+ baseUrl?: string;
12
+ lang?: 'zh' | 'en';
13
+ }
14
+ export declare class PhotonClient {
15
+ private readonly opts;
16
+ constructor(opts: PhotonClientOptions);
17
+ private get;
18
+ /** Forward geocode. */
19
+ geocode(query: string, signal: AbortSignal): Promise<GeocodeResult>;
20
+ /** Reverse geocode. */
21
+ reverseGeocode(location: LngLat, signal: AbortSignal): Promise<GeocodeResult>;
22
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * dsh-map-tools persisted config file (~/.dsh-map-tools/config.json).
3
+ *
4
+ * Follows the modlens pattern: the plugin's API keys and provider choice live
5
+ * in its own file (shared across profiles, never in the DSH settings
6
+ * document), and the settings card reads/writes it through a loopback route.
7
+ */
8
+ /** The file the plugin's settings card reads and writes. Overridable for tests. */
9
+ export declare function configPath(): string;
10
+ /** What the plugin persists and serves to the settings card. */
11
+ export interface MapToolsFileConfig {
12
+ provider?: 'amap' | 'osm';
13
+ amapKey?: string;
14
+ timeoutMs?: number;
15
+ maxQps?: number;
16
+ }
17
+ /**
18
+ * Read the shared config, or a thrown error. Only a missing file reads as
19
+ * empty: an existing-but-unparsable file is somebody's configuration, and a
20
+ * card that treated it as empty would overwrite it on the next save.
21
+ */
22
+ export declare function readConfig(): MapToolsFileConfig;
23
+ /** Persist a patch onto the config file, then return the new whole. */
24
+ export declare function applyConfig(patch: Partial<MapToolsFileConfig>): MapToolsFileConfig;
25
+ /** Whether the config file exists (the card can offer "open config file"). */
26
+ export declare function configFileExists(): boolean;
27
+ /** Non-secret summary served to the settings card (keys are never echoed). */
28
+ export declare function configSummary(): {
29
+ provider: MapToolsFileConfig['provider'];
30
+ timeoutMs?: number;
31
+ maxQps?: number;
32
+ hasAmapKey: boolean;
33
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Loopback settings-card route for dsh-map-tools.
3
+ *
4
+ * GET /dsh-map-tools/config → non-secret summary (has-amap-key, …)
5
+ * GET /dsh-map-tools/config?open=true → open the config file in the editor
6
+ * POST /dsh-map-tools/config → apply a provider/key/timeout patch
7
+ *
8
+ * Same-origin loopback only (mirrors dsh's own /api fence and the modlens
9
+ * pattern); the two halves of the card read/write a real file.
10
+ */
11
+ import type { Context } from '@deepseek-ai/cordis';
12
+ /**
13
+ * Register the settings-card route under the web server, when one exists.
14
+ *
15
+ * @param ctx - plugin context.
16
+ * @param reload - rebuild the tools after the card saves (the file write alone
17
+ * never reaches the registered tool instances; without this the new provider
18
+ * or key only takes effect on the next plugin reload).
19
+ */
20
+ export declare function installConfigRoute(ctx: Context, reload?: () => void): void;
@@ -0,0 +1,23 @@
1
+ /** Plugin configuration schema. */
2
+ import Schema from '@deepseek-ai/schemastery';
3
+ export interface Config {
4
+ /**
5
+ * Provider selection:
6
+ * - 'amap': 高德地图(Web 服务 API key,免费申请,推荐)
7
+ * - 'osm': 免费 OSM/OSRM 兜底(无 key,能力有限)
8
+ */
9
+ provider: 'amap' | 'osm';
10
+ /** Amap (高德) Web Service API key. */
11
+ amapKey?: string;
12
+ /** Per-request timeout in milliseconds. */
13
+ timeoutMs: number;
14
+ /** Amap requests per second cap (高德个人 key QPS 上限低,默认 2 留余量). */
15
+ maxQps: number;
16
+ /** Default route mode when a generic route is requested. */
17
+ defaultMode: 'driving' | 'transit' | 'walking' | 'bicycling';
18
+ /** Language hint for providers that support it. */
19
+ language: 'zh' | 'en';
20
+ }
21
+ /** Amap apply URL (shown as a clickable link in the settings card). */
22
+ export declare const AMAP_APPLY_URL = "https://console.amap.com/dev/key/app";
23
+ export declare const Config: Schema<Config>;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * dsh-map-tools — map & routing tools for DeepSeek Harness.
3
+ *
4
+ * Registers 7 native tools:
5
+ * map_driving_route / map_transit_route / map_walking_route / map_bicycling_route
6
+ * map_geocode / map_reverse_geocode / map_poi_search
7
+ *
8
+ * Data sources: OSM/OSRM/Nominatim free fallback by default (zero-key); when
9
+ * amapKey is configured (or provider='amap'), Amap (高德) is used for best
10
+ * CN data quality (transit + POI require Amap).
11
+ */
12
+ import type { Context } from '@deepseek-ai/cordis';
13
+ import { Config } from './config.js';
14
+ import type { Config as ConfigType } from './config.js';
15
+ export declare const name = "dsh-map-tools";
16
+ export declare const inject: string[];
17
+ export { Config };
18
+ export declare function apply(ctx: Context, config: ConfigType): void;
@@ -0,0 +1,14 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ import type { Config as ConfigType } from './config.js';
3
+ /** Namespace the settings page keys this plugin's card to (plain string since DSH 0.1.2-rc.1). */
4
+ export declare const MAP_TOOLS_NS = "dsh-map-tools";
5
+ /**
6
+ * Wire the settings section so the card renders. The values live in the
7
+ * config file; the section carries only the composition entry as its base so
8
+ * the page has something to dispatch on.
9
+ *
10
+ * @param ctx - plugin context.
11
+ * @param entry - the composition entry config (schema defaults).
12
+ * @param reload - rebuild tools after a settings change.
13
+ */
14
+ export declare function installSettingsNamespace(ctx: Context, entry: ConfigType, reload: () => void): void;
@@ -0,0 +1,11 @@
1
+ /** Geocoding tools: address → coordinates, and reverse. */
2
+ import type { Context } from '@deepseek-ai/cordis';
3
+ import type { AmapClient } from '../clients/amap.js';
4
+ import type { NominatimClient } from '../clients/nominatim.js';
5
+ import type { PhotonClient } from '../clients/photon.js';
6
+ export interface GeocodeClients {
7
+ amap?: AmapClient;
8
+ nominatim?: NominatimClient;
9
+ photon?: PhotonClient;
10
+ }
11
+ export declare function registerGeocodeTools(ctx: Context, clients: GeocodeClients, disposers?: Array<() => void>): void;
@@ -0,0 +1,9 @@
1
+ /** POI search tool. */
2
+ import type { Context } from '@deepseek-ai/cordis';
3
+ import type { AmapClient } from '../clients/amap.js';
4
+ export interface PoiClients {
5
+ amap?: AmapClient;
6
+ /** Resolve an address (or `lng,lat`) to coordinates; throws with a helpful message. */
7
+ resolve: (text: string, signal: AbortSignal) => Promise<[number, number]>;
8
+ }
9
+ export declare function registerPoiTool(ctx: Context, clients: PoiClients, disposers?: Array<() => void>): void;
@@ -0,0 +1,16 @@
1
+ /** Route planning tools: driving / transit / walking / bicycling. */
2
+ import type { Context } from '@deepseek-ai/cordis';
3
+ import { type AmapClient } from '../clients/amap.js';
4
+ import type { OsrmClient } from '../clients/osrm.js';
5
+ import type { LngLat } from '../types.js';
6
+ /** Shared runtime handle handed to every tool (built by the plugin entry). */
7
+ export interface MapClients {
8
+ amap?: AmapClient;
9
+ osrm?: OsrmClient;
10
+ /** Resolve an address (or `lng,lat`) to coordinates; throws with a helpful message. */
11
+ resolve: (text: string, signal: AbortSignal) => Promise<LngLat>;
12
+ /** Resolve the city name for a point (transit queries need city1/city2). */
13
+ resolveCity: (text: string, signal: AbortSignal) => Promise<string>;
14
+ defaultMode: 'driving' | 'transit' | 'walking' | 'bicycling';
15
+ }
16
+ export declare function registerRouteTools(ctx: Context, clients: MapClients, disposers?: Array<() => void>): void;
@@ -0,0 +1,55 @@
1
+ /** Shared types for dsh-map-tools. */
2
+ /** A normalized geo point: [longitude, latitude]. */
3
+ export type LngLat = [number, number];
4
+ /** One route leg/step instruction, normalized across providers. */
5
+ export interface RouteStep {
6
+ /** Human-readable instruction, e.g. "沿北京路向西行驶 300 米". */
7
+ instruction: string;
8
+ /** Distance in meters. */
9
+ distanceM: number;
10
+ /** Duration in seconds. */
11
+ durationS: number;
12
+ }
13
+ /** Normalized route result, provider-agnostic. */
14
+ export interface RouteResult {
15
+ /** Provider that produced this result: 'amap' | 'osrm'. */
16
+ provider: 'amap' | 'osrm';
17
+ /** Total distance in meters. */
18
+ distanceM: number;
19
+ /** Total duration in seconds. */
20
+ durationS: number;
21
+ /** Compact polyline string (Amap format) or GeoJSON line, depending on provider. */
22
+ polyline: string;
23
+ /** Waypoint coordinates [lng, lat] along the route (sampled). */
24
+ points: LngLat[];
25
+ /** Step-by-step instructions. */
26
+ steps: RouteStep[];
27
+ }
28
+ /** Normalized geocode result. */
29
+ export interface GeocodeResult {
30
+ /** Provider: 'amap' | 'nominatim' | 'photon'. */
31
+ provider: 'amap' | 'nominatim' | 'photon';
32
+ /** Matched display name. */
33
+ formatted: string;
34
+ /** Normalized [lng, lat]. */
35
+ location: LngLat;
36
+ /** Optional structured fields. */
37
+ city?: string;
38
+ district?: string;
39
+ adcode?: string;
40
+ }
41
+ /** Normalized POI search result. */
42
+ export interface PoiResult {
43
+ name: string;
44
+ location: LngLat;
45
+ /** POI category/type label. */
46
+ type?: string;
47
+ address?: string;
48
+ tel?: string;
49
+ /** Distance in meters from the query location (around-search only). */
50
+ distanceM?: number;
51
+ }
52
+ /** One coordinate pair from a `lng,lat` or `lat,lng` string. */
53
+ export declare function parseLngLat(text: string): LngLat | null;
54
+ /** Format a pair as `lng,lat`. */
55
+ export declare function formatLngLat([lng, lat]: LngLat): string;
@@ -0,0 +1,16 @@
1
+ /** Shared types for dsh-map-tools. */
2
+ /** One coordinate pair from a `lng,lat` or `lat,lng` string. */
3
+ export function parseLngLat(text) {
4
+ const m = /^\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*$/.exec(text);
5
+ if (!m)
6
+ return null;
7
+ const lng = Number(m[1]);
8
+ const lat = Number(m[2]);
9
+ if (lng < -180 || lng > 180 || lat < -90 || lat > 90)
10
+ return null;
11
+ return [lng, lat];
12
+ }
13
+ /** Format a pair as `lng,lat`. */
14
+ export function formatLngLat([lng, lat]) {
15
+ return `${lng},${lat}`;
16
+ }
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "dsh-map-tools",
3
+ "description": "Map & routing tools for DeepSeek Harness: driving/transit/walking/bicycling route planning, geocoding, reverse geocoding and POI search via Amap (高德) or free OSM/OSRM.",
4
+ "version": "0.5.1",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "types": "lib/types/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/types/index.d.ts",
11
+ "default": "./lib/index.js"
12
+ },
13
+ "./client": "./client/client.js",
14
+ "./cordis.patch.yml": "./cordis.patch.yml",
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "lib",
19
+ "client",
20
+ "cordis.patch.yml",
21
+ "LICENSE"
22
+ ],
23
+ "keywords": [
24
+ "deepseek",
25
+ "harness",
26
+ "dsh",
27
+ "dsh-plugin",
28
+ "map",
29
+ "routing",
30
+ "path-planning",
31
+ "geocoding",
32
+ "amap",
33
+ "gaode",
34
+ "osm",
35
+ "osrm"
36
+ ],
37
+ "license": "MIT",
38
+ "author": "HorusJiang",
39
+ "engines": {
40
+ "node": ">=20"
41
+ },
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/HorusJiang/dsh-map-tools.git"
45
+ },
46
+ "bugs": {
47
+ "url": "https://github.com/HorusJiang/dsh-map-tools/issues"
48
+ },
49
+ "homepage": "https://github.com/HorusJiang/dsh-map-tools#readme",
50
+ "peerDependencies": {
51
+ "@deepseek-ai/cordis": "^4.0.2",
52
+ "@deepseek-ai/dsh-settings": ">=0.1.2-rc.1",
53
+ "@deepseek-ai/dsh-tools": ">=0.1.2-rc.1"
54
+ },
55
+ "dependencies": {
56
+ "@deepseek-ai/schemastery": "^3.18.2"
57
+ },
58
+ "devDependencies": {
59
+ "@deepseek-ai/cordis": "^4.0.2",
60
+ "@deepseek-ai/dsh-settings": ">=0.1.2-rc.1",
61
+ "@deepseek-ai/dsh-tools": ">=0.1.2-rc.1",
62
+ "@deepseek-ai/schemastery": "^3.18.2",
63
+ "@types/node": "^22.0.0",
64
+ "typescript": "^5.6.0",
65
+ "vitest": "^4.1.10"
66
+ },
67
+ "publishConfig": {
68
+ "registry": "https://registry.npmjs.org/"
69
+ },
70
+ "dsh": {
71
+ "bundle": {
72
+ "patch": "./cordis.patch.yml"
73
+ },
74
+ "client": {
75
+ "platform": "web"
76
+ },
77
+ "compatibility": {
78
+ "dshReleases": {
79
+ "0.1.2-rc.1": "compatible",
80
+ "0.1.3-alpha.1": "compatible"
81
+ }
82
+ }
83
+ },
84
+ "scripts": {
85
+ "build": "tsc -p tsconfig.json",
86
+ "test": "vitest run",
87
+ "prepack": "npm run build",
88
+ "hooks": "node scripts/install-hooks.mjs",
89
+ "check:secrets": "node scripts/check-secrets.mjs"
90
+ }
91
+ }
package/ts/package.json CHANGED
@@ -11,11 +11,11 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@deepseek-ai/cordis": "4.0.2",
14
+ "@deepseek-ai/dsh-session": "0.1.2-alpha.3",
14
15
  "@deepseek-ai/dsh-tools": "0.1.2-alpha.3",
15
16
  "@deepseek-ai/schemastery": "^3.18.2",
16
17
  "@types/better-sqlite3": "^9.6.0",
17
18
  "better-sqlite3": "^13.0.3",
18
- "dsh-map-tools": "0.5.1",
19
19
  "z3-solver": "^5.2.0"
20
20
  },
21
21
  "devDependencies": {
@@ -24,5 +24,13 @@
24
24
  "puppeteer-core": "^25.9.0",
25
25
  "tsx": "^4.19.0",
26
26
  "typescript": "^5.6.0"
27
+ },
28
+ "overrides": {
29
+ "@deepseek-ai/dsh-brand": "0.1.2-alpha.3",
30
+ "@deepseek-ai/dsh-llm": "0.1.2-alpha.3",
31
+ "@deepseek-ai/dsh-timeout": "0.1.2-alpha.3",
32
+ "@deepseek-ai/dsh-typert-protocol": "0.1.2-alpha.3",
33
+ "@deepseek-ai/dsh-util-crypto": "0.1.2-alpha.3",
34
+ "@deepseek-ai/dsh-util-values": "0.1.2-alpha.3"
27
35
  }
28
36
  }
@@ -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
@@ -150,7 +154,9 @@ function assistantText(data: Record<string, unknown>): { text: string; interrupt
150
154
  return { text, interrupted: data.interrupted === true }
151
155
  }
152
156
 
153
- function bridgeResultStatus(data: Record<string, unknown>, callId: string): { ok: true } | { ok: false; code: string } | undefined {
157
+ type BridgeResultStatus = { kind: 'result' } | { kind: 'domain' } | { kind: 'failure'; code: string }
158
+
159
+ function bridgeResultStatus(data: Record<string, unknown>, callId: string): BridgeResultStatus | undefined {
154
160
  if (!plainObject(data.message) || !plainObject(data.message.source)) return undefined
155
161
  if (data.message.source.callId !== callId || !Array.isArray(data.message.content)) return undefined
156
162
  const block = data.message.content.find(candidate => plainObject(candidate)
@@ -164,8 +170,28 @@ function bridgeResultStatus(data: Record<string, unknown>, callId: string): { ok
164
170
  try {
165
171
  const parsed: unknown = JSON.parse(text)
166
172
  if (!plainObject(parsed)) return undefined
167
- if (parsed.ok === true) return { ok: true }
173
+ const keys = Object.keys(parsed).sort().join(',')
174
+ if (parsed.ok === true && keys === 'ok,result' && (plainObject(parsed.result) || Array.isArray(parsed.result))) return { kind: 'result' }
175
+ if (parsed.ok === true && keys === 'ok,outcome' && plainObject(parsed.outcome)) {
176
+ const outcomeKeys = Object.keys(parsed.outcome).sort().join(',')
177
+ if (outcomeKeys === 'code,recovery,schema_version,status'
178
+ && parsed.outcome.schema_version === BENCHMARK_TOOL_RESULT_SCHEMA_VERSION
179
+ && (parsed.outcome.status === 'miss' || parsed.outcome.status === 'error')
180
+ && typeof parsed.outcome.code === 'string'
181
+ && IDENTIFIER.test(parsed.outcome.code)
182
+ && typeof parsed.outcome.recovery === 'string'
183
+ && BENCHMARK_DOMAIN_RECOVERIES.has(parsed.outcome.recovery)) return { kind: 'domain' }
184
+ return undefined
185
+ }
168
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
169
195
  const code = parsed.error === 'timed_out'
170
196
  ? BENCHMARK_BRIDGE_TIMED_OUT
171
197
  : parsed.error === 'runner_failed'
@@ -175,7 +201,7 @@ function bridgeResultStatus(data: Record<string, unknown>, callId: string): { ok
175
201
  : parsed.error === 'output_truncated'
176
202
  ? BENCHMARK_BRIDGE_OUTPUT_TRUNCATED
177
203
  : BENCHMARK_BRIDGE_CALL_FAILED
178
- return { ok: false, code }
204
+ return { kind: 'failure', code }
179
205
  }
180
206
  return undefined
181
207
  } catch {
@@ -249,10 +275,15 @@ export function createBenchmarkAgentConformance(projection: BenchmarkBridgeProje
249
275
  const callId = event.data.message.source.callId
250
276
  if (typeof callId !== 'string' || !state.validCallIds.has(callId)) return
251
277
  const resultStatus = bridgeResultStatus(event.data, callId)
252
- if (resultStatus?.ok === true) {
278
+ if (typeof event.data.step === 'number') state.lastBridgeResponseStep = event.data.step
279
+ if (resultStatus?.kind === 'result') {
253
280
  state.successfulResultStep = typeof event.data.step === 'number'
254
281
  ? event.data.step
255
282
  : state.successfulResultStep
283
+ } else if (resultStatus?.kind === 'domain') {
284
+ state.domainOutcomeStep = typeof event.data.step === 'number'
285
+ ? event.data.step
286
+ : state.domainOutcomeStep
256
287
  } else {
257
288
  state.bridgeCallFailed = true
258
289
  state.bridgeFailureCode = resultStatus?.code ?? BENCHMARK_BRIDGE_CALL_FAILED
@@ -274,10 +305,10 @@ export function createBenchmarkAgentConformance(projection: BenchmarkBridgeProje
274
305
  if (state.retryRedispatchAttempted) {
275
306
  return { kind: 'reject', code: BENCHMARK_BRIDGE_RETRY_CALL_NOT_ALLOWED }
276
307
  }
277
- if (state.successfulResultStep === undefined) {
278
- if (state.bridgeCallFailed) {
279
- return { kind: 'reject', code: state.bridgeFailureCode ?? BENCHMARK_BRIDGE_CALL_FAILED }
280
- }
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) {
281
312
  if (state.retryCount >= MAX_CONFORMANCE_RETRIES) {
282
313
  return { kind: 'reject', code: BENCHMARK_BRIDGE_CALL_REQUIRED }
283
314
  }
@@ -289,7 +320,7 @@ export function createBenchmarkAgentConformance(projection: BenchmarkBridgeProje
289
320
  const terminal = state.lastAssistant
290
321
  const terminalIsValid = terminal !== undefined
291
322
  && !terminal.interrupted
292
- && terminal.step > state.successfulResultStep
323
+ && terminal.step > state.lastBridgeResponseStep!
293
324
  && parseBenchmarkTerminal(terminal.text, projection.terminal).ok
294
325
  if (terminalIsValid) return { kind: 'accept' }
295
326
  if (state.retryCount >= MAX_CONFORMANCE_RETRIES) {