@honua/mcp-server 0.0.9-alpha.0 → 0.0.20-alpha.0
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 +167 -0
- package/certification/geospatial-mcp-schemas/PROVENANCE.md +33 -0
- package/certification/geospatial-mcp-schemas/README.md +90 -0
- package/certification/geospatial-mcp-schemas/common/geoprocessing-error.schema.json +45 -0
- package/certification/geospatial-mcp-schemas/conformance/manifest.schema.json +73 -0
- package/certification/geospatial-mcp-schemas/index.json +311 -0
- package/certification/geospatial-mcp-schemas/resources/app-package.schema.json +20 -0
- package/certification/geospatial-mcp-schemas/resources/app-template.schema.json +15 -0
- package/certification/geospatial-mcp-schemas/resources/artifact.schema.json +69 -0
- package/certification/geospatial-mcp-schemas/resources/deployment.schema.json +27 -0
- package/certification/geospatial-mcp-schemas/resources/map-package.schema.json +21 -0
- package/certification/geospatial-mcp-schemas/resources/map-template.schema.json +15 -0
- package/certification/geospatial-mcp-schemas/resources/provenance.schema.json +50 -0
- package/certification/geospatial-mcp-schemas/resources/published-service.schema.json +21 -0
- package/certification/geospatial-mcp-schemas/resources/result-package.schema.json +64 -0
- package/certification/geospatial-mcp-schemas/resources/style.schema.json +12 -0
- package/certification/geospatial-mcp-schemas/resources/theme.schema.json +12 -0
- package/certification/geospatial-mcp-schemas/resources/workspace.schema.json +63 -0
- package/certification/geospatial-mcp-schemas/tools/apply_style_preset.schema.json +23 -0
- package/certification/geospatial-mcp-schemas/tools/cancel_job.schema.json +15 -0
- package/certification/geospatial-mcp-schemas/tools/clarify_intent.schema.json +69 -0
- package/certification/geospatial-mcp-schemas/tools/compose_mixed_protocol_map.schema.json +21 -0
- package/certification/geospatial-mcp-schemas/tools/create_app_package.schema.json +33 -0
- package/certification/geospatial-mcp-schemas/tools/create_map_package.schema.json +41 -0
- package/certification/geospatial-mcp-schemas/tools/execute_plan.schema.json +64 -0
- package/certification/geospatial-mcp-schemas/tools/geocode_address.schema.json +36 -0
- package/certification/geospatial-mcp-schemas/tools/get_style.schema.json +30 -0
- package/certification/geospatial-mcp-schemas/tools/ground_candidates.schema.json +66 -0
- package/certification/geospatial-mcp-schemas/tools/list_capabilities.schema.json +21 -0
- package/certification/geospatial-mcp-schemas/tools/list_layers.schema.json +14 -0
- package/certification/geospatial-mcp-schemas/tools/plan_analysis.schema.json +19 -0
- package/certification/geospatial-mcp-schemas/tools/preview_app_package.schema.json +15 -0
- package/certification/geospatial-mcp-schemas/tools/preview_map_package.schema.json +17 -0
- package/certification/geospatial-mcp-schemas/tools/preview_package.schema.json +40 -0
- package/certification/geospatial-mcp-schemas/tools/propose_operation.schema.json +28 -0
- package/certification/geospatial-mcp-schemas/tools/publish_result.schema.json +29 -0
- package/certification/geospatial-mcp-schemas/tools/publish_service.schema.json +59 -0
- package/certification/geospatial-mcp-schemas/tools/query_features.schema.json +54 -0
- package/certification/geospatial-mcp-schemas/tools/refine_map_package.schema.json +22 -0
- package/certification/geospatial-mcp-schemas/tools/render_map.schema.json +55 -0
- package/certification/geospatial-mcp-schemas/tools/resolve_entity.schema.json +30 -0
- package/certification/geospatial-mcp-schemas/tools/solve_route.schema.json +39 -0
- package/certification/geospatial-mcp-schemas/tools/validate_package.schema.json +35 -0
- package/certification/geospatial-mcp-schemas/tools/validate_plan.schema.json +61 -0
- package/dist/src/certification/certifier.d.ts +119 -0
- package/dist/src/certification/certifier.d.ts.map +1 -0
- package/dist/src/certification/certifier.js +410 -0
- package/dist/src/certification/cli.d.ts +3 -0
- package/dist/src/certification/cli.d.ts.map +1 -0
- package/dist/src/certification/cli.js +48 -0
- package/dist/src/certification/contracts.d.ts +62 -0
- package/dist/src/certification/contracts.d.ts.map +1 -0
- package/dist/src/certification/contracts.js +174 -0
- package/dist/src/certification/fixture-client.d.ts +4 -0
- package/dist/src/certification/fixture-client.d.ts.map +1 -0
- package/dist/src/certification/fixture-client.js +113 -0
- package/dist/src/certification/fixtures.d.ts +32 -0
- package/dist/src/certification/fixtures.d.ts.map +1 -0
- package/dist/src/certification/fixtures.js +64 -0
- package/dist/src/certification/json-schema.d.ts +49 -0
- package/dist/src/certification/json-schema.d.ts.map +1 -0
- package/dist/src/certification/json-schema.js +164 -0
- package/dist/src/certification/mock-upstream.d.ts +29 -0
- package/dist/src/certification/mock-upstream.d.ts.map +1 -0
- package/dist/src/certification/mock-upstream.js +96 -0
- package/dist/src/certification/operator-catalog.d.ts +82 -0
- package/dist/src/certification/operator-catalog.d.ts.map +1 -0
- package/dist/src/certification/operator-catalog.js +466 -0
- package/dist/src/certification/report.d.ts +4 -0
- package/dist/src/certification/report.d.ts.map +1 -0
- package/dist/src/certification/report.js +90 -0
- package/dist/src/certification/run.d.ts +28 -0
- package/dist/src/certification/run.d.ts.map +1 -0
- package/dist/src/certification/run.js +31 -0
- package/dist/src/certification/schema-index.d.ts +69 -0
- package/dist/src/certification/schema-index.d.ts.map +1 -0
- package/dist/src/certification/schema-index.js +82 -0
- package/dist/src/certification/target.d.ts +40 -0
- package/dist/src/certification/target.d.ts.map +1 -0
- package/dist/src/certification/target.js +167 -0
- package/dist/src/eval/cli.d.ts +3 -0
- package/dist/src/eval/cli.d.ts.map +1 -0
- package/dist/src/eval/cli.js +116 -0
- package/dist/src/eval/corpus.d.ts +27 -0
- package/dist/src/eval/corpus.d.ts.map +1 -0
- package/dist/src/eval/corpus.js +134 -0
- package/dist/src/eval/drivers/anthropic.d.ts +14 -0
- package/dist/src/eval/drivers/anthropic.d.ts.map +1 -0
- package/dist/src/eval/drivers/anthropic.js +120 -0
- package/dist/src/eval/drivers/bedrock.d.ts +54 -0
- package/dist/src/eval/drivers/bedrock.d.ts.map +1 -0
- package/dist/src/eval/drivers/bedrock.js +178 -0
- package/dist/src/eval/drivers/deterministic.d.ts +17 -0
- package/dist/src/eval/drivers/deterministic.d.ts.map +1 -0
- package/dist/src/eval/drivers/deterministic.js +51 -0
- package/dist/src/eval/drivers/index.d.ts +34 -0
- package/dist/src/eval/drivers/index.d.ts.map +1 -0
- package/dist/src/eval/drivers/index.js +74 -0
- package/dist/src/eval/drivers/openai.d.ts +14 -0
- package/dist/src/eval/drivers/openai.d.ts.map +1 -0
- package/dist/src/eval/drivers/openai.js +136 -0
- package/dist/src/eval/grade.d.ts +14 -0
- package/dist/src/eval/grade.d.ts.map +1 -0
- package/dist/src/eval/grade.js +56 -0
- package/dist/src/eval/northstar-corpus.d.ts +3 -0
- package/dist/src/eval/northstar-corpus.d.ts.map +1 -0
- package/dist/src/eval/northstar-corpus.js +194 -0
- package/dist/src/eval/operator-corpus.d.ts +3 -0
- package/dist/src/eval/operator-corpus.d.ts.map +1 -0
- package/dist/src/eval/operator-corpus.js +193 -0
- package/dist/src/eval/report.d.ts +104 -0
- package/dist/src/eval/report.d.ts.map +1 -0
- package/dist/src/eval/report.js +130 -0
- package/dist/src/eval/runner.d.ts +22 -0
- package/dist/src/eval/runner.d.ts.map +1 -0
- package/dist/src/eval/runner.js +116 -0
- package/dist/src/eval/types.d.ts +93 -0
- package/dist/src/eval/types.d.ts.map +1 -0
- package/dist/src/eval/types.js +10 -0
- package/dist/src/helpers.d.ts +11 -0
- package/dist/src/helpers.d.ts.map +1 -1
- package/dist/src/helpers.js +22 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +30 -4
- package/dist/src/proxy.d.ts +46 -0
- package/dist/src/proxy.d.ts.map +1 -0
- package/dist/src/proxy.js +124 -0
- package/dist/src/resources/styles.d.ts +29 -0
- package/dist/src/resources/styles.d.ts.map +1 -0
- package/dist/src/resources/styles.js +43 -0
- package/dist/src/styles.d.ts +110 -0
- package/dist/src/styles.d.ts.map +1 -0
- package/dist/src/styles.js +118 -0
- package/dist/src/tools/apply-style-preset.d.ts +27 -0
- package/dist/src/tools/apply-style-preset.d.ts.map +1 -0
- package/dist/src/tools/apply-style-preset.js +29 -0
- package/dist/src/tools/count-features.d.ts.map +1 -1
- package/dist/src/tools/count-features.js +5 -4
- package/dist/src/tools/get-extent.d.ts.map +1 -1
- package/dist/src/tools/get-extent.js +6 -4
- package/dist/src/tools/get-style.d.ts +24 -0
- package/dist/src/tools/get-style.d.ts.map +1 -0
- package/dist/src/tools/get-style.js +28 -0
- package/dist/src/tools/query-features.d.ts.map +1 -1
- package/dist/src/tools/query-features.js +4 -1
- package/package.json +19 -4
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Scenario } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Held-out corpus of GIS workflows for the cross-model eval (honua-server #1956).
|
|
4
|
+
*
|
|
5
|
+
* Each scenario is a natural-language GIS task plus declarative success criteria.
|
|
6
|
+
* The `script` is the "ideal client" tool trajectory the deterministic offline
|
|
7
|
+
* driver follows; live LLM drivers (Claude, GPT) plan their own calls from the
|
|
8
|
+
* prompt and the advertised tool catalog. Criteria are graded identically across
|
|
9
|
+
* all drivers, so the same corpus measures any client against any workflow.
|
|
10
|
+
*
|
|
11
|
+
* Tool/argument shapes target the canonical honua MCP catalog and resolve
|
|
12
|
+
* against the offline fixture backend (service "Parks", layer 0).
|
|
13
|
+
*/
|
|
14
|
+
export declare const CORPUS: Scenario[];
|
|
15
|
+
/**
|
|
16
|
+
* Select the corpus to run from the environment (honua-server #1956).
|
|
17
|
+
*
|
|
18
|
+
* The default `analyst` corpus targets the in-process SDK fixture surface and is
|
|
19
|
+
* the CI control. `operator` selects {@link OPERATOR_CORPUS} for live runs against
|
|
20
|
+
* the honua-server operator MCP surface; `northstar` selects {@link NORTHSTAR_CORPUS},
|
|
21
|
+
* the three P1-gate workflows (also live-gated); `all` runs every corpus
|
|
22
|
+
* back-to-back. Selection is case-insensitive and falls back to the analyst corpus
|
|
23
|
+
* for any unset/unknown value so CI behavior is unchanged unless `HONUA_EVAL_CORPUS`
|
|
24
|
+
* is set explicitly.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveCorpus(env?: NodeJS.ProcessEnv): Scenario[];
|
|
27
|
+
//# sourceMappingURL=corpus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"corpus.d.ts","sourceRoot":"","sources":["../../../src/eval/corpus.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,MAAM,EAAE,QAAQ,EAkG5B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,QAAQ,EAAE,CAW9E"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { NORTHSTAR_CORPUS } from "./northstar-corpus.js";
|
|
2
|
+
import { OPERATOR_CORPUS } from "./operator-corpus.js";
|
|
3
|
+
/**
|
|
4
|
+
* Held-out corpus of GIS workflows for the cross-model eval (honua-server #1956).
|
|
5
|
+
*
|
|
6
|
+
* Each scenario is a natural-language GIS task plus declarative success criteria.
|
|
7
|
+
* The `script` is the "ideal client" tool trajectory the deterministic offline
|
|
8
|
+
* driver follows; live LLM drivers (Claude, GPT) plan their own calls from the
|
|
9
|
+
* prompt and the advertised tool catalog. Criteria are graded identically across
|
|
10
|
+
* all drivers, so the same corpus measures any client against any workflow.
|
|
11
|
+
*
|
|
12
|
+
* Tool/argument shapes target the canonical honua MCP catalog and resolve
|
|
13
|
+
* against the offline fixture backend (service "Parks", layer 0).
|
|
14
|
+
*/
|
|
15
|
+
export const CORPUS = [
|
|
16
|
+
{
|
|
17
|
+
id: "discover-services",
|
|
18
|
+
title: "Discover available feature services",
|
|
19
|
+
category: "discovery",
|
|
20
|
+
prompt: "I'm new to this server. What feature services are available to query? Just list them.",
|
|
21
|
+
criteria: {
|
|
22
|
+
requiredTools: ["honua_list_services"],
|
|
23
|
+
answerMustInclude: ["Parks"],
|
|
24
|
+
},
|
|
25
|
+
script: [{ tool: "honua_list_services", args: {} }],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "inspect-layer-schema",
|
|
29
|
+
title: "Inspect a layer's schema before querying",
|
|
30
|
+
category: "grounding",
|
|
31
|
+
prompt: "Before I query the Parks service, show me the schema of its first layer (layer 0) — the fields and geometry type.",
|
|
32
|
+
criteria: {
|
|
33
|
+
requiredTools: ["honua_describe_layer"],
|
|
34
|
+
answerMustInclude: ["OBJECTID"],
|
|
35
|
+
},
|
|
36
|
+
script: [{ tool: "honua_describe_layer", args: { serviceId: "Parks", layerId: 0 } }],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "count-then-query",
|
|
40
|
+
title: "Check cardinality, then fetch a sample",
|
|
41
|
+
category: "query",
|
|
42
|
+
prompt: "How many features are in the Parks service layer 0? Then show me a couple of them.",
|
|
43
|
+
criteria: {
|
|
44
|
+
requiredTools: ["honua_count_features", "honua_query_features"],
|
|
45
|
+
expectedToolSequence: ["honua_count_features", "honua_query_features"],
|
|
46
|
+
answerMustInclude: ["Park A"],
|
|
47
|
+
},
|
|
48
|
+
script: [
|
|
49
|
+
{ tool: "honua_count_features", args: { serviceId: "Parks", layerId: 0 } },
|
|
50
|
+
{ tool: "honua_query_features", args: { serviceId: "Parks", layerId: 0, limit: 2 } },
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "discover-then-query",
|
|
55
|
+
title: "End-to-end discover → query",
|
|
56
|
+
category: "multi-step",
|
|
57
|
+
prompt: "I don't know what's on this server. Find a feature service and show me a few features from one of its layers.",
|
|
58
|
+
criteria: {
|
|
59
|
+
requiredTools: ["honua_list_services", "honua_query_features"],
|
|
60
|
+
expectedToolSequence: ["honua_list_services", "honua_query_features"],
|
|
61
|
+
answerMustInclude: ["Park"],
|
|
62
|
+
},
|
|
63
|
+
script: [
|
|
64
|
+
{ tool: "honua_list_services", args: {} },
|
|
65
|
+
{ tool: "honua_query_features", args: { serviceId: "Parks", layerId: 0, limit: 2 } },
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: "aggregate-statistic",
|
|
70
|
+
title: "Compute an aggregate statistic",
|
|
71
|
+
category: "analysis",
|
|
72
|
+
prompt: "What is the average of the VALUE field for the Parks service, layer 0?",
|
|
73
|
+
criteria: {
|
|
74
|
+
requiredTools: ["honua_statistics"],
|
|
75
|
+
answerMustInclude: ["statistics"],
|
|
76
|
+
},
|
|
77
|
+
script: [
|
|
78
|
+
{
|
|
79
|
+
tool: "honua_statistics",
|
|
80
|
+
args: { serviceId: "Parks", layerId: 0, statisticType: "avg", onField: "VALUE" },
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: "spatial-extent",
|
|
86
|
+
title: "Get the spatial extent of a layer",
|
|
87
|
+
category: "query",
|
|
88
|
+
prompt: "What is the bounding box / spatial extent of the Parks service, layer 0?",
|
|
89
|
+
criteria: {
|
|
90
|
+
requiredTools: ["honua_get_extent"],
|
|
91
|
+
answerMustInclude: ["extent"],
|
|
92
|
+
},
|
|
93
|
+
script: [{ tool: "honua_get_extent", args: { serviceId: "Parks", layerId: 0 } }],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: "capability-gap",
|
|
97
|
+
title: "Explain a capability gap honestly",
|
|
98
|
+
category: "grounding",
|
|
99
|
+
prompt: "Can I run an attribute query against a WMTS source on this platform? If not, what should I do instead?",
|
|
100
|
+
criteria: {
|
|
101
|
+
requiredTools: ["honua_explain_capability_gap"],
|
|
102
|
+
answerMustInclude: ["explanation"],
|
|
103
|
+
},
|
|
104
|
+
script: [
|
|
105
|
+
{
|
|
106
|
+
tool: "honua_explain_capability_gap",
|
|
107
|
+
args: { capability: "query", protocol: "wmts" },
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
];
|
|
112
|
+
/**
|
|
113
|
+
* Select the corpus to run from the environment (honua-server #1956).
|
|
114
|
+
*
|
|
115
|
+
* The default `analyst` corpus targets the in-process SDK fixture surface and is
|
|
116
|
+
* the CI control. `operator` selects {@link OPERATOR_CORPUS} for live runs against
|
|
117
|
+
* the honua-server operator MCP surface; `northstar` selects {@link NORTHSTAR_CORPUS},
|
|
118
|
+
* the three P1-gate workflows (also live-gated); `all` runs every corpus
|
|
119
|
+
* back-to-back. Selection is case-insensitive and falls back to the analyst corpus
|
|
120
|
+
* for any unset/unknown value so CI behavior is unchanged unless `HONUA_EVAL_CORPUS`
|
|
121
|
+
* is set explicitly.
|
|
122
|
+
*/
|
|
123
|
+
export function resolveCorpus(env = process.env) {
|
|
124
|
+
switch ((env.HONUA_EVAL_CORPUS ?? "").trim().toLowerCase()) {
|
|
125
|
+
case "operator":
|
|
126
|
+
return OPERATOR_CORPUS;
|
|
127
|
+
case "northstar":
|
|
128
|
+
return NORTHSTAR_CORPUS;
|
|
129
|
+
case "all":
|
|
130
|
+
return [...CORPUS, ...OPERATOR_CORPUS, ...NORTHSTAR_CORPUS];
|
|
131
|
+
default:
|
|
132
|
+
return CORPUS;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ModelDriver, Scenario, WorkflowContext, WorkflowTranscript } from "../types.js";
|
|
2
|
+
export interface AnthropicDriverOptions {
|
|
3
|
+
apiKey?: string | undefined;
|
|
4
|
+
model?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class AnthropicDriver implements ModelDriver {
|
|
7
|
+
readonly vendor: "anthropic";
|
|
8
|
+
readonly id: string;
|
|
9
|
+
private readonly apiKey;
|
|
10
|
+
constructor(options?: AnthropicDriverOptions);
|
|
11
|
+
isAvailable(): boolean;
|
|
12
|
+
runWorkflow(scenario: Scenario, ctx: WorkflowContext): Promise<WorkflowTranscript>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../../src/eval/drivers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAkB,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAoC9G,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,eAAgB,YAAW,WAAW;IACjD,QAAQ,CAAC,MAAM,EAAG,WAAW,CAAU;IACvC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;gBAEhC,OAAO,GAAE,sBAA2B;IAKhD,WAAW,IAAI,OAAO;IAIhB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAoFzF"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude client driver for the cross-model eval (honua-server #1956).
|
|
3
|
+
*
|
|
4
|
+
* Gated behind ANTHROPIC_API_KEY and a dynamically-imported `@anthropic-ai/sdk`
|
|
5
|
+
* — neither is a dependency of this package, so the offline CI path never needs
|
|
6
|
+
* them. Live runs use the latest Opus model (claude-opus-4-8) with a manual
|
|
7
|
+
* tool-use loop over the advertised MCP catalog. A synthetic `ask_user` tool
|
|
8
|
+
* lets the model signal that it needs clarification, which the harness records
|
|
9
|
+
* separately from success/failure.
|
|
10
|
+
*
|
|
11
|
+
* Live cross-model runs are tracked under honua-io/honua-server#1956.
|
|
12
|
+
*/
|
|
13
|
+
const ASK_USER_TOOL = {
|
|
14
|
+
name: "ask_user",
|
|
15
|
+
description: "Call this ONLY if the request is too ambiguous to proceed. Provide the clarifying question you would ask.",
|
|
16
|
+
input_schema: {
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: { question: { type: "string" } },
|
|
19
|
+
required: ["question"],
|
|
20
|
+
additionalProperties: false,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const SYSTEM_PROMPT = "You are a GIS analyst working through the Honua MCP tools. Complete the user's task by calling the available tools. " +
|
|
24
|
+
"Ground every step in real tool results — do not invent service names, layers, or fields. " +
|
|
25
|
+
"If, and only if, the request is genuinely ambiguous and you cannot proceed, call ask_user. " +
|
|
26
|
+
"When finished, give a concise final answer that references what the tools returned.";
|
|
27
|
+
const MAX_ITERATIONS = 8;
|
|
28
|
+
const DEFAULT_MODEL = "claude-opus-4-8";
|
|
29
|
+
export class AnthropicDriver {
|
|
30
|
+
vendor = "anthropic";
|
|
31
|
+
id;
|
|
32
|
+
apiKey;
|
|
33
|
+
constructor(options = {}) {
|
|
34
|
+
this.id = options.model ?? DEFAULT_MODEL;
|
|
35
|
+
this.apiKey = options.apiKey ?? process.env.ANTHROPIC_API_KEY;
|
|
36
|
+
}
|
|
37
|
+
isAvailable() {
|
|
38
|
+
return typeof this.apiKey === "string" && this.apiKey.length > 0;
|
|
39
|
+
}
|
|
40
|
+
async runWorkflow(scenario, ctx) {
|
|
41
|
+
const steps = [];
|
|
42
|
+
const transcript = {
|
|
43
|
+
scenarioId: scenario.id,
|
|
44
|
+
modelId: this.id,
|
|
45
|
+
steps,
|
|
46
|
+
finalAnswer: "",
|
|
47
|
+
clarificationRequested: false,
|
|
48
|
+
errorCount: 0,
|
|
49
|
+
};
|
|
50
|
+
let Anthropic;
|
|
51
|
+
try {
|
|
52
|
+
// Variable specifier → not statically resolved; keeps @anthropic-ai/sdk
|
|
53
|
+
// an optional, non-bundled dependency for live runs only.
|
|
54
|
+
const specifier = "@anthropic-ai/sdk";
|
|
55
|
+
const mod = (await import(specifier));
|
|
56
|
+
Anthropic = mod.default;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
transcript.driverError = "@anthropic-ai/sdk is not installed (required for live Claude eval runs)";
|
|
60
|
+
return transcript;
|
|
61
|
+
}
|
|
62
|
+
if (!this.apiKey) {
|
|
63
|
+
transcript.driverError = "ANTHROPIC_API_KEY is not set";
|
|
64
|
+
return transcript;
|
|
65
|
+
}
|
|
66
|
+
const client = new Anthropic({ apiKey: this.apiKey });
|
|
67
|
+
const tools = [
|
|
68
|
+
...ctx.tools.map((t) => ({ name: t.name, description: t.description, input_schema: t.inputSchema })),
|
|
69
|
+
ASK_USER_TOOL,
|
|
70
|
+
];
|
|
71
|
+
const messages = [{ role: "user", content: scenario.prompt }];
|
|
72
|
+
try {
|
|
73
|
+
for (let i = 0; i < MAX_ITERATIONS; i++) {
|
|
74
|
+
const response = await client.messages.create({
|
|
75
|
+
model: this.id,
|
|
76
|
+
max_tokens: 4096,
|
|
77
|
+
system: SYSTEM_PROMPT,
|
|
78
|
+
tools,
|
|
79
|
+
messages,
|
|
80
|
+
});
|
|
81
|
+
const toolUses = response.content.filter((b) => b.type === "tool_use");
|
|
82
|
+
const text = response.content
|
|
83
|
+
.filter((b) => b.type === "text")
|
|
84
|
+
.map((b) => b.text)
|
|
85
|
+
.join("\n");
|
|
86
|
+
if (response.stop_reason !== "tool_use" || toolUses.length === 0) {
|
|
87
|
+
transcript.finalAnswer = text;
|
|
88
|
+
return transcript;
|
|
89
|
+
}
|
|
90
|
+
messages.push({ role: "assistant", content: response.content });
|
|
91
|
+
const toolResults = [];
|
|
92
|
+
for (const use of toolUses) {
|
|
93
|
+
if (use.name === ASK_USER_TOOL.name) {
|
|
94
|
+
transcript.clarificationRequested = true;
|
|
95
|
+
transcript.finalAnswer = text;
|
|
96
|
+
return transcript;
|
|
97
|
+
}
|
|
98
|
+
const result = await ctx.callTool(use.name, (use.input ?? {}));
|
|
99
|
+
steps.push({ tool: use.name, args: (use.input ?? {}), isError: result.isError });
|
|
100
|
+
if (result.isError) {
|
|
101
|
+
transcript.errorCount++;
|
|
102
|
+
}
|
|
103
|
+
toolResults.push({
|
|
104
|
+
type: "tool_result",
|
|
105
|
+
tool_use_id: use.id,
|
|
106
|
+
content: result.text,
|
|
107
|
+
is_error: result.isError,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
messages.push({ role: "user", content: toolResults });
|
|
111
|
+
}
|
|
112
|
+
transcript.driverError = `exceeded ${MAX_ITERATIONS} tool-use iterations without finishing`;
|
|
113
|
+
return transcript;
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
transcript.driverError = err instanceof Error ? err.message : String(err);
|
|
117
|
+
return transcript;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ModelDriver, Scenario, ToolDescriptor, WorkflowContext, WorkflowTranscript } from "../types.js";
|
|
2
|
+
export interface BedrockDriverOptions {
|
|
3
|
+
/** Bedrock model id or inference-profile id. Defaults to Sonnet 4.5. */
|
|
4
|
+
model?: string | undefined;
|
|
5
|
+
/** AWS region. Defaults to AWS_REGION, then us-west-2. */
|
|
6
|
+
region?: string | undefined;
|
|
7
|
+
/** Opt-in flag value (defaults to process.env.HONUA_EVAL_BEDROCK). */
|
|
8
|
+
enabled?: string | undefined;
|
|
9
|
+
}
|
|
10
|
+
export declare class BedrockDriver implements ModelDriver {
|
|
11
|
+
readonly vendor: "bedrock";
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly region: string;
|
|
14
|
+
private readonly enabled;
|
|
15
|
+
constructor(options?: BedrockDriverOptions);
|
|
16
|
+
isAvailable(): boolean;
|
|
17
|
+
runWorkflow(scenario: Scenario, ctx: WorkflowContext): Promise<WorkflowTranscript>;
|
|
18
|
+
}
|
|
19
|
+
/** Map MCP tool descriptors to Bedrock Converse `toolSpec` entries. */
|
|
20
|
+
export declare function toBedrockTools(tools: ToolDescriptor[]): BedrockTool[];
|
|
21
|
+
/** Pull tool-use blocks out of a Converse content array. */
|
|
22
|
+
export declare function extractToolUses(content: BedrockContentBlock[]): BedrockToolUse[];
|
|
23
|
+
/** Concatenate text blocks of a Converse content array. */
|
|
24
|
+
export declare function extractText(content: BedrockContentBlock[]): string;
|
|
25
|
+
/** Build a Converse `toolResult` content block to feed back to the model. */
|
|
26
|
+
export declare function toToolResultBlock(toolUseId: string, text: string, isError: boolean): BedrockContentBlock;
|
|
27
|
+
interface BedrockToolUse {
|
|
28
|
+
toolUseId: string;
|
|
29
|
+
name: string;
|
|
30
|
+
input?: unknown;
|
|
31
|
+
}
|
|
32
|
+
interface BedrockToolResult {
|
|
33
|
+
toolUseId: string;
|
|
34
|
+
content: {
|
|
35
|
+
text: string;
|
|
36
|
+
}[];
|
|
37
|
+
status: "error" | "success";
|
|
38
|
+
}
|
|
39
|
+
interface BedrockContentBlock {
|
|
40
|
+
text?: string;
|
|
41
|
+
toolUse?: BedrockToolUse;
|
|
42
|
+
toolResult?: BedrockToolResult;
|
|
43
|
+
}
|
|
44
|
+
interface BedrockTool {
|
|
45
|
+
toolSpec: {
|
|
46
|
+
name: string;
|
|
47
|
+
description: string;
|
|
48
|
+
inputSchema: {
|
|
49
|
+
json: Record<string, unknown>;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=bedrock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bedrock.d.ts","sourceRoot":"","sources":["../../../../src/eval/drivers/bedrock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EACR,cAAc,EAEd,eAAe,EACf,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAgErB,MAAM,WAAW,oBAAoB;IACnC,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B;AAED,qBAAa,aAAc,YAAW,WAAW;IAC/C,QAAQ,CAAC,MAAM,EAAG,SAAS,CAAU;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;gBAEtB,OAAO,GAAE,oBAAyB;IAO9C,WAAW,IAAI,OAAO;IAIhB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAyEzF;AAUD,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,WAAW,EAAE,CAQrE;AAED,4DAA4D;AAC5D,wBAAgB,eAAe,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,cAAc,EAAE,CAIhF;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,MAAM,CAKlE;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,mBAAmB,CAQxG;AAID,UAAU,cAAc;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AACD,UAAU,iBAAiB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5B,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;CAC7B;AACD,UAAU,mBAAmB;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAKD,UAAU,WAAW;IACnB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAE,CAAC;KAChD,CAAC;CACH"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude-via-Amazon-Bedrock driver for the cross-model eval (honua-server #1956).
|
|
3
|
+
*
|
|
4
|
+
* This is the "any client LLM" counterpart to the direct-Anthropic driver, but it
|
|
5
|
+
* reaches Claude through Amazon Bedrock's Converse API instead of the Anthropic
|
|
6
|
+
* API. It exists so the AI proof can run on infrastructure that has AWS Bedrock
|
|
7
|
+
* access (default `~/.aws` credential chain) but no ANTHROPIC_API_KEY — exactly
|
|
8
|
+
* the situation on the build host. The SAME corpus and grading are driven over
|
|
9
|
+
* the identical MCP catalog, so the artifact compares success / clarification /
|
|
10
|
+
* edit rates across vendors and transports.
|
|
11
|
+
*
|
|
12
|
+
* Auth uses the standard AWS SDK credential provider chain (env vars, shared
|
|
13
|
+
* config/credentials files, SSO, instance/role credentials) — no key is ever
|
|
14
|
+
* hardcoded. Because that chain is resolved asynchronously and cannot be sniffed
|
|
15
|
+
* synchronously, the driver opts in via the `HONUA_EVAL_BEDROCK` env flag (set by
|
|
16
|
+
* `resolveDrivers`) or by explicit selection (`--driver bedrock`).
|
|
17
|
+
*
|
|
18
|
+
* Model id: defaults to `anthropic.claude-sonnet-4-5-20250929-v1:0`, overridable
|
|
19
|
+
* via `HONUA_EVAL_BEDROCK_MODEL`. NOTE: most current Anthropic models on Bedrock
|
|
20
|
+
* are not enabled for on-demand throughput by the bare id and must be invoked
|
|
21
|
+
* through a cross-region inference profile — i.e. the `us.`-prefixed form
|
|
22
|
+
* `us.anthropic.claude-sonnet-4-5-20250929-v1:0` in us.* regions. Set
|
|
23
|
+
* `HONUA_EVAL_BEDROCK_MODEL` accordingly for live runs.
|
|
24
|
+
*
|
|
25
|
+
* Region: `AWS_REGION` if set, else `us-west-2`.
|
|
26
|
+
*
|
|
27
|
+
* `@aws-sdk/client-bedrock-runtime` is a declared dependency but is imported
|
|
28
|
+
* dynamically (variable specifier) so the offline CI path — which only runs the
|
|
29
|
+
* deterministic control — never needs to load it, and a graceful `driverError`
|
|
30
|
+
* is recorded if it is somehow absent.
|
|
31
|
+
*
|
|
32
|
+
* Live cross-model runs are tracked under honua-io/honua-server#1956.
|
|
33
|
+
*/
|
|
34
|
+
const ASK_USER_TOOL_NAME = "ask_user";
|
|
35
|
+
const ASK_USER_TOOL = {
|
|
36
|
+
toolSpec: {
|
|
37
|
+
name: ASK_USER_TOOL_NAME,
|
|
38
|
+
description: "Call this ONLY if the request is too ambiguous to proceed. Provide the clarifying question you would ask.",
|
|
39
|
+
inputSchema: {
|
|
40
|
+
json: {
|
|
41
|
+
type: "object",
|
|
42
|
+
properties: { question: { type: "string" } },
|
|
43
|
+
required: ["question"],
|
|
44
|
+
additionalProperties: false,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
const SYSTEM_PROMPT = "You are a GIS analyst working through the Honua MCP tools. Complete the user's task by calling the available tools. " +
|
|
50
|
+
"Ground every step in real tool results — do not invent service names, layers, or fields. " +
|
|
51
|
+
"If, and only if, the request is genuinely ambiguous and you cannot proceed, call ask_user. " +
|
|
52
|
+
"When finished, give a concise final answer that references what the tools returned.";
|
|
53
|
+
const MAX_ITERATIONS = 8;
|
|
54
|
+
const MAX_TOKENS = 4096;
|
|
55
|
+
const DEFAULT_MODEL = "anthropic.claude-sonnet-4-5-20250929-v1:0";
|
|
56
|
+
const DEFAULT_REGION = "us-west-2";
|
|
57
|
+
export class BedrockDriver {
|
|
58
|
+
vendor = "bedrock";
|
|
59
|
+
id;
|
|
60
|
+
region;
|
|
61
|
+
enabled;
|
|
62
|
+
constructor(options = {}) {
|
|
63
|
+
this.id = options.model ?? DEFAULT_MODEL;
|
|
64
|
+
this.region = options.region ?? DEFAULT_REGION;
|
|
65
|
+
const flag = options.enabled ?? process.env.HONUA_EVAL_BEDROCK;
|
|
66
|
+
this.enabled = isTruthy(flag);
|
|
67
|
+
}
|
|
68
|
+
isAvailable() {
|
|
69
|
+
return this.enabled;
|
|
70
|
+
}
|
|
71
|
+
async runWorkflow(scenario, ctx) {
|
|
72
|
+
const steps = [];
|
|
73
|
+
const transcript = {
|
|
74
|
+
scenarioId: scenario.id,
|
|
75
|
+
modelId: this.id,
|
|
76
|
+
steps,
|
|
77
|
+
finalAnswer: "",
|
|
78
|
+
clarificationRequested: false,
|
|
79
|
+
errorCount: 0,
|
|
80
|
+
};
|
|
81
|
+
let runtime;
|
|
82
|
+
try {
|
|
83
|
+
// Variable specifier → not statically resolved; keeps the AWS SDK an
|
|
84
|
+
// optional load for live runs only and the build independent of it.
|
|
85
|
+
const specifier = "@aws-sdk/client-bedrock-runtime";
|
|
86
|
+
runtime = (await import(specifier));
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
transcript.driverError = "@aws-sdk/client-bedrock-runtime is not installed (required for live Bedrock eval runs)";
|
|
90
|
+
return transcript;
|
|
91
|
+
}
|
|
92
|
+
const { BedrockRuntimeClient, ConverseCommand } = runtime;
|
|
93
|
+
const client = new BedrockRuntimeClient({ region: this.region });
|
|
94
|
+
const toolConfig = { tools: [...toBedrockTools(ctx.tools), ASK_USER_TOOL] };
|
|
95
|
+
const messages = [{ role: "user", content: [{ text: scenario.prompt }] }];
|
|
96
|
+
try {
|
|
97
|
+
for (let i = 0; i < MAX_ITERATIONS; i++) {
|
|
98
|
+
const response = await client.send(new ConverseCommand({
|
|
99
|
+
modelId: this.id,
|
|
100
|
+
system: [{ text: SYSTEM_PROMPT }],
|
|
101
|
+
messages,
|
|
102
|
+
toolConfig,
|
|
103
|
+
inferenceConfig: { maxTokens: MAX_TOKENS },
|
|
104
|
+
}));
|
|
105
|
+
const content = response.output?.message?.content ?? [];
|
|
106
|
+
const toolUses = extractToolUses(content);
|
|
107
|
+
const text = extractText(content);
|
|
108
|
+
if (response.stopReason !== "tool_use" || toolUses.length === 0) {
|
|
109
|
+
transcript.finalAnswer = text;
|
|
110
|
+
return transcript;
|
|
111
|
+
}
|
|
112
|
+
messages.push({ role: "assistant", content });
|
|
113
|
+
const toolResults = [];
|
|
114
|
+
for (const use of toolUses) {
|
|
115
|
+
if (use.name === ASK_USER_TOOL_NAME) {
|
|
116
|
+
transcript.clarificationRequested = true;
|
|
117
|
+
transcript.finalAnswer = text;
|
|
118
|
+
return transcript;
|
|
119
|
+
}
|
|
120
|
+
const args = (use.input ?? {});
|
|
121
|
+
const result = await ctx.callTool(use.name, args);
|
|
122
|
+
steps.push({ tool: use.name, args, isError: result.isError });
|
|
123
|
+
if (result.isError) {
|
|
124
|
+
transcript.errorCount++;
|
|
125
|
+
}
|
|
126
|
+
toolResults.push(toToolResultBlock(use.toolUseId, result.text, result.isError));
|
|
127
|
+
}
|
|
128
|
+
messages.push({ role: "user", content: toolResults });
|
|
129
|
+
}
|
|
130
|
+
transcript.driverError = `exceeded ${MAX_ITERATIONS} tool-use iterations without finishing`;
|
|
131
|
+
return transcript;
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
transcript.driverError = err instanceof Error ? err.message : String(err);
|
|
135
|
+
return transcript;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function isTruthy(value) {
|
|
140
|
+
if (typeof value !== "string") {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
const v = value.trim().toLowerCase();
|
|
144
|
+
return v.length > 0 && v !== "0" && v !== "false" && v !== "no" && v !== "off";
|
|
145
|
+
}
|
|
146
|
+
/** Map MCP tool descriptors to Bedrock Converse `toolSpec` entries. */
|
|
147
|
+
export function toBedrockTools(tools) {
|
|
148
|
+
return tools.map((t) => ({
|
|
149
|
+
toolSpec: {
|
|
150
|
+
name: t.name,
|
|
151
|
+
description: t.description,
|
|
152
|
+
inputSchema: { json: (t.inputSchema ?? { type: "object" }) },
|
|
153
|
+
},
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
/** Pull tool-use blocks out of a Converse content array. */
|
|
157
|
+
export function extractToolUses(content) {
|
|
158
|
+
return content
|
|
159
|
+
.map((b) => b.toolUse)
|
|
160
|
+
.filter((u) => typeof u === "object" && u !== null && typeof u.name === "string");
|
|
161
|
+
}
|
|
162
|
+
/** Concatenate text blocks of a Converse content array. */
|
|
163
|
+
export function extractText(content) {
|
|
164
|
+
return content
|
|
165
|
+
.map((b) => b.text)
|
|
166
|
+
.filter((t) => typeof t === "string")
|
|
167
|
+
.join("\n");
|
|
168
|
+
}
|
|
169
|
+
/** Build a Converse `toolResult` content block to feed back to the model. */
|
|
170
|
+
export function toToolResultBlock(toolUseId, text, isError) {
|
|
171
|
+
return {
|
|
172
|
+
toolResult: {
|
|
173
|
+
toolUseId,
|
|
174
|
+
content: [{ text }],
|
|
175
|
+
status: isError ? "error" : "success",
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ModelDriver, Scenario, WorkflowContext, WorkflowTranscript } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic offline driver — the CI control for the cross-model eval.
|
|
4
|
+
*
|
|
5
|
+
* It does not call any model. Instead it executes the scenario's scripted "ideal
|
|
6
|
+
* client" tool trajectory against the REAL MCP surface (the same `tools/call`
|
|
7
|
+
* round-trips a live LLM would make), then synthesizes a final answer from the
|
|
8
|
+
* concatenated tool results. This makes the offline eval a genuine end-to-end
|
|
9
|
+
* exercise of the MCP surface — not a stub — while staying fully reproducible.
|
|
10
|
+
*/
|
|
11
|
+
export declare class DeterministicDriver implements ModelDriver {
|
|
12
|
+
readonly id = "deterministic";
|
|
13
|
+
readonly vendor: "deterministic";
|
|
14
|
+
isAvailable(): boolean;
|
|
15
|
+
runWorkflow(scenario: Scenario, ctx: WorkflowContext): Promise<WorkflowTranscript>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=deterministic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deterministic.d.ts","sourceRoot":"","sources":["../../../../src/eval/drivers/deterministic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAkB,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAE9G;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,YAAW,WAAW;IACrD,QAAQ,CAAC,EAAE,mBAAmB;IAC9B,QAAQ,CAAC,MAAM,EAAG,eAAe,CAAU;IAE3C,WAAW,IAAI,OAAO;IAIhB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAsCzF"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic offline driver — the CI control for the cross-model eval.
|
|
3
|
+
*
|
|
4
|
+
* It does not call any model. Instead it executes the scenario's scripted "ideal
|
|
5
|
+
* client" tool trajectory against the REAL MCP surface (the same `tools/call`
|
|
6
|
+
* round-trips a live LLM would make), then synthesizes a final answer from the
|
|
7
|
+
* concatenated tool results. This makes the offline eval a genuine end-to-end
|
|
8
|
+
* exercise of the MCP surface — not a stub — while staying fully reproducible.
|
|
9
|
+
*/
|
|
10
|
+
export class DeterministicDriver {
|
|
11
|
+
id = "deterministic";
|
|
12
|
+
vendor = "deterministic";
|
|
13
|
+
isAvailable() {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
async runWorkflow(scenario, ctx) {
|
|
17
|
+
const advertised = new Set(ctx.tools.map((t) => t.name));
|
|
18
|
+
const steps = [];
|
|
19
|
+
const answerParts = [];
|
|
20
|
+
let errorCount = 0;
|
|
21
|
+
for (const planned of scenario.script) {
|
|
22
|
+
if (!advertised.has(planned.tool)) {
|
|
23
|
+
// The scripted tool is not on the surface — record a driver-visible error
|
|
24
|
+
// (a real catalog regression would surface here, not silently pass).
|
|
25
|
+
return {
|
|
26
|
+
scenarioId: scenario.id,
|
|
27
|
+
modelId: this.id,
|
|
28
|
+
steps,
|
|
29
|
+
finalAnswer: answerParts.join("\n"),
|
|
30
|
+
clarificationRequested: false,
|
|
31
|
+
errorCount,
|
|
32
|
+
driverError: `scripted tool not advertised by the MCP surface: ${planned.tool}`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const result = await ctx.callTool(planned.tool, planned.args);
|
|
36
|
+
steps.push({ tool: planned.tool, args: planned.args, isError: result.isError });
|
|
37
|
+
if (result.isError) {
|
|
38
|
+
errorCount++;
|
|
39
|
+
}
|
|
40
|
+
answerParts.push(result.text);
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
scenarioId: scenario.id,
|
|
44
|
+
modelId: this.id,
|
|
45
|
+
steps,
|
|
46
|
+
finalAnswer: answerParts.join("\n"),
|
|
47
|
+
clarificationRequested: false,
|
|
48
|
+
errorCount,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ModelDriver } from "../types.js";
|
|
2
|
+
import { AnthropicDriver } from "./anthropic.js";
|
|
3
|
+
import { BedrockDriver } from "./bedrock.js";
|
|
4
|
+
import { DeterministicDriver } from "./deterministic.js";
|
|
5
|
+
import { OpenAiDriver } from "./openai.js";
|
|
6
|
+
export { AnthropicDriver, BedrockDriver, DeterministicDriver, OpenAiDriver };
|
|
7
|
+
/** Names accepted by `selectDrivers` / the CLI `--driver` flag. */
|
|
8
|
+
export type DriverName = "deterministic" | "anthropic" | "openai" | "bedrock";
|
|
9
|
+
export interface ResolveDriversOptions {
|
|
10
|
+
env?: NodeJS.ProcessEnv;
|
|
11
|
+
/** Include live drivers even if their key/opt-in is absent (they record driverError). */
|
|
12
|
+
includeUnavailable?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the set of model drivers to run.
|
|
16
|
+
*
|
|
17
|
+
* The deterministic control is always included. Claude (Anthropic API) and GPT
|
|
18
|
+
* drivers are added when their API keys are present; the Claude-via-Bedrock driver
|
|
19
|
+
* is added when `HONUA_EVAL_BEDROCK` is set (its auth comes from the AWS credential
|
|
20
|
+
* chain, which can't be sniffed from a single env var). This gates live runs behind
|
|
21
|
+
* env without hardcoding any credentials. CI runs the deterministic driver only —
|
|
22
|
+
* a green, reproducible artifact with no model/API calls.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveDrivers(options?: ResolveDriversOptions): ModelDriver[];
|
|
25
|
+
/**
|
|
26
|
+
* Build the driver set for an explicit `--driver` selection. The deterministic
|
|
27
|
+
* control is always included (it is the CI gate). Named live drivers are always
|
|
28
|
+
* constructed and run — even if their key/opt-in is absent — so an explicit
|
|
29
|
+
* request surfaces an honest `driverError` rather than being silently dropped.
|
|
30
|
+
*/
|
|
31
|
+
export declare function selectDrivers(names: DriverName[], options?: ResolveDriversOptions): ModelDriver[];
|
|
32
|
+
/** Parse/validate a `--driver` value into a known driver name. */
|
|
33
|
+
export declare function parseDriverName(value: string): DriverName;
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/eval/drivers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,mBAAmB,EAAE,YAAY,EAAE,CAAC;AAE7E,mEAAmE;AACnE,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE9E,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,WAAW,EAAE,CAwBjF;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,OAAO,GAAE,qBAA0B,GAAG,WAAW,EAAE,CAuBrG;AAED,kEAAkE;AAClE,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAMzD"}
|