@honua/mcp-server 0.1.9-beta.0 → 0.1.11-beta.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/certification/setup-parity.md +79 -0
- package/dist/src/certification/admin-parity.d.ts +7 -1
- package/dist/src/certification/admin-parity.d.ts.map +1 -1
- package/dist/src/certification/admin-parity.js +9 -2
- package/dist/src/certification/setup-parity.d.ts +86 -0
- package/dist/src/certification/setup-parity.d.ts.map +1 -0
- package/dist/src/certification/setup-parity.js +188 -0
- package/dist/src/eval/cli.js +2 -2
- package/dist/src/eval/corpus.d.ts.map +1 -1
- package/dist/src/eval/corpus.js +6 -5
- package/dist/src/eval/grade.d.ts.map +1 -1
- package/dist/src/eval/grade.js +25 -0
- package/dist/src/eval/report.d.ts +9 -0
- package/dist/src/eval/report.d.ts.map +1 -1
- package/dist/src/eval/report.js +15 -5
- package/dist/src/eval/runner.d.ts.map +1 -1
- package/dist/src/eval/runner.js +16 -1
- package/dist/src/eval/types.d.ts +37 -2
- package/dist/src/eval/types.d.ts.map +1 -1
- package/dist/src/eval/workflow-corpus.d.ts +9 -0
- package/dist/src/eval/workflow-corpus.d.ts.map +1 -0
- package/dist/src/eval/workflow-corpus.js +306 -0
- package/dist/src/proxy.d.ts.map +1 -1
- package/dist/src/proxy.js +7 -1
- package/dist/src/release/zero-to-map-checkpoint.d.ts.map +1 -1
- package/dist/src/release/zero-to-map-checkpoint.js +9 -1
- package/dist/src/release/zero-to-map-cli.d.ts +11 -1
- package/dist/src/release/zero-to-map-cli.d.ts.map +1 -1
- package/dist/src/release/zero-to-map-cli.js +52 -12
- package/dist/src/release/zero-to-map.d.ts +132 -59
- package/dist/src/release/zero-to-map.d.ts.map +1 -1
- package/dist/src/release/zero-to-map.js +459 -167
- package/package.json +7 -4
- package/release/zero-to-map/README.md +76 -79
- package/release/zero-to-map/configs/claude-code.mcp.json +1 -1
- package/release/zero-to-map/configs/claude-desktop.json +1 -1
- package/release/zero-to-map/configs/cursor.json +1 -1
- package/release/zero-to-map/journey.v1.json +965 -502
- package/release/zero-to-map/contracts/esri-gp-mcp.v1.json +0 -73
package/dist/src/eval/types.d.ts
CHANGED
|
@@ -42,6 +42,19 @@ export interface WorkflowTranscript {
|
|
|
42
42
|
errorCount: number;
|
|
43
43
|
/** Driver-level failure (timeout, exception, model unavailable). */
|
|
44
44
|
driverError?: string;
|
|
45
|
+
/** Which surface produced the step. Docs lookups are `docs`; CLI-only steps are `cli`. */
|
|
46
|
+
surface?: "mcp" | "docs" | "cli";
|
|
47
|
+
/** Skill whose operator sentence was the prompt. */
|
|
48
|
+
skillId?: string;
|
|
49
|
+
/** Copied from the journey oracle after the run. The model never sees these. */
|
|
50
|
+
journeyStage?: string;
|
|
51
|
+
journeyAction?: string;
|
|
52
|
+
/** Who chose the tool call. Console approval stays harness-driven. */
|
|
53
|
+
attribution?: "MODEL_SELECTED" | "HARNESS_DRIVEN";
|
|
54
|
+
/** Ids only. Credential material is never stored here. */
|
|
55
|
+
capturedIds?: Record<string, string>;
|
|
56
|
+
/** Set when a required server profile is off. Grades as `blocked`. */
|
|
57
|
+
blockedReason?: string;
|
|
45
58
|
}
|
|
46
59
|
/** Declarative success criteria graded against a transcript. */
|
|
47
60
|
export interface SuccessCriteria {
|
|
@@ -69,6 +82,17 @@ export interface SuccessCriteria {
|
|
|
69
82
|
* transcript grades as `pass` and a completed transcript grades as `fail`.
|
|
70
83
|
*/
|
|
71
84
|
expectClarification?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Substrings that must not appear in any tool-argument JSON. Used to fail a
|
|
87
|
+
* model that sets `allowAnonymous` or proposes `visibility: public`.
|
|
88
|
+
*/
|
|
89
|
+
forbiddenArgumentText?: string[];
|
|
90
|
+
/** Substrings that must appear in the tool-argument JSON. */
|
|
91
|
+
requiredArgumentText?: string[];
|
|
92
|
+
/** Any tool whose name contains "approve" fails the scenario. */
|
|
93
|
+
forbidApproval?: boolean;
|
|
94
|
+
/** A tool result with isError fails the scenario. The control cannot pass on a failed call. */
|
|
95
|
+
failOnToolError?: boolean;
|
|
72
96
|
}
|
|
73
97
|
/** One GIS workflow in the held-out corpus. */
|
|
74
98
|
export interface Scenario {
|
|
@@ -95,9 +119,20 @@ export interface Scenario {
|
|
|
95
119
|
clarify?: {
|
|
96
120
|
question: string;
|
|
97
121
|
};
|
|
122
|
+
/** Skill file the prompt was taken from. Not shown to the model as an id. */
|
|
123
|
+
skillId?: string;
|
|
124
|
+
/** Journey stage id this scenario covers. Applied to the transcript after the run. */
|
|
125
|
+
journeyStage?: string;
|
|
126
|
+
/** Journey action id this scenario covers. */
|
|
127
|
+
journeyAction?: string;
|
|
128
|
+
/**
|
|
129
|
+
* MCP server profiles that must already be enabled. When any is missing the
|
|
130
|
+
* scenario is `blocked` and the model is not asked to call the tools.
|
|
131
|
+
*/
|
|
132
|
+
requiresServerProfiles?: string[];
|
|
98
133
|
}
|
|
99
|
-
/** Per-scenario grade for one model. */
|
|
100
|
-
export type GradeOutcome = "pass" | "fail" | "clarified" | "error";
|
|
134
|
+
/** Per-scenario grade for one model. `blocked` is a missing server profile, never a pass. */
|
|
135
|
+
export type GradeOutcome = "pass" | "fail" | "clarified" | "error" | "blocked";
|
|
101
136
|
export interface ScenarioGrade {
|
|
102
137
|
scenarioId: string;
|
|
103
138
|
modelId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/eval/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,yEAAyE;AACzE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,4DAA4D;AAC5D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;CACd;AAED,sEAAsE;AACtE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAChF;AAED,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,sBAAsB,EAAE,OAAO,CAAC;IAChC,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/eval/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Scenario, WorkflowTranscript } from "./types.js";
|
|
2
|
+
export declare const WORKFLOW_CORPUS: Scenario[];
|
|
3
|
+
/** Profiles named by the scenario that are not in `active`. */
|
|
4
|
+
export declare function unavailableProfiles(scenario: Scenario, active: readonly string[]): string[];
|
|
5
|
+
export declare function blockedTranscript(modelId: string, scenario: Scenario, profiles: readonly string[]): WorkflowTranscript;
|
|
6
|
+
/** Drop credential material from a transcript before it is stored. */
|
|
7
|
+
export declare function redactTranscript(transcript: WorkflowTranscript): WorkflowTranscript;
|
|
8
|
+
export declare function annotateTranscript(transcript: WorkflowTranscript, scenario: Scenario, attribution: "MODEL_SELECTED" | "HARNESS_DRIVEN"): WorkflowTranscript;
|
|
9
|
+
//# sourceMappingURL=workflow-corpus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-corpus.d.ts","sourceRoot":"","sources":["../../../src/eval/workflow-corpus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA4B/D,eAAO,MAAM,eAAe,EAAE,QAAQ,EAwNrC,CAAC;AAEF,+DAA+D;AAC/D,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAG3F;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,kBAAkB,CAepB;AAID,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,kBAAkB,GAAG,kBAAkB,CAUnF;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,kBAAkB,EAC9B,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,gBAAgB,GAAG,gBAAgB,GAC/C,kBAAkB,CAUpB"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Full 2026.1 workflow corpus.
|
|
3
|
+
*
|
|
4
|
+
* Prompts are operator sentences. They do not include `journey.v1.json` or the
|
|
5
|
+
* journey file's argument payloads. `journeyStage` / `journeyAction` are copied
|
|
6
|
+
* onto the transcript after the run so a scorecard can show coverage.
|
|
7
|
+
*
|
|
8
|
+
* `buffer-three-ways` stays blocked until the server enables the `analysis` and
|
|
9
|
+
* `esri-gp` profiles (honua-server #3363 / #3430 / #3431). Do not invent the
|
|
10
|
+
* configuration key that turns those profiles on.
|
|
11
|
+
*/
|
|
12
|
+
const STUDIO_FAMILIES = ["map", "app", "dashboard"];
|
|
13
|
+
const STUDIO_LIFECYCLE = [
|
|
14
|
+
"honua_studio_create_draft",
|
|
15
|
+
"honua_studio_validate_draft",
|
|
16
|
+
"honua_studio_save_version",
|
|
17
|
+
"honua_studio_get_version",
|
|
18
|
+
"honua_studio_reopen_version",
|
|
19
|
+
];
|
|
20
|
+
const APPROVAL_GATE = {
|
|
21
|
+
forbidApproval: true,
|
|
22
|
+
forbiddenArgumentText: ['"allowAnonymous":true', '"visibility":"public"'],
|
|
23
|
+
};
|
|
24
|
+
export const WORKFLOW_CORPUS = [
|
|
25
|
+
{
|
|
26
|
+
id: "install-ready",
|
|
27
|
+
title: "Install locally and report readiness without the admin key",
|
|
28
|
+
category: "install",
|
|
29
|
+
skillId: "honua-local-setup",
|
|
30
|
+
journeyStage: "install",
|
|
31
|
+
journeyAction: "install-status",
|
|
32
|
+
prompt: "The operator already confirmed this laptop install. Install Honua locally, then verify API, MCP, and Console readiness. Report whether ready is true, plus the credential id and digest. Do not print the admin key.",
|
|
33
|
+
criteria: {
|
|
34
|
+
requiredTools: ["honua_admin_install_local", "honua_admin_install_status"],
|
|
35
|
+
expectedToolSequence: ["honua_admin_install_local", "honua_admin_install_status"],
|
|
36
|
+
...APPROVAL_GATE,
|
|
37
|
+
},
|
|
38
|
+
script: [
|
|
39
|
+
{ tool: "honua_admin_install_local", args: { confirm: true, profile: "gp-dev" } },
|
|
40
|
+
{ tool: "honua_admin_install_status", args: {} },
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "connect-and-import",
|
|
45
|
+
title: "Connect by secret reference, test, and import",
|
|
46
|
+
category: "admin",
|
|
47
|
+
skillId: "honua-datasource-connect",
|
|
48
|
+
journeyStage: "admin",
|
|
49
|
+
journeyAction: "import-parcels",
|
|
50
|
+
prompt: "Connect Honua to its local database by secret reference, prove the connection works, then import the parcels file from its URL and wait until that import job succeeds. Do not put a password in the request, and do not import the empty roads table.",
|
|
51
|
+
criteria: {
|
|
52
|
+
requiredTools: ["honua_admin_connection_create", "honua_admin_connection_test", "honua_admin_import_upload_url"],
|
|
53
|
+
expectedToolSequence: [
|
|
54
|
+
"honua_admin_connection_create",
|
|
55
|
+
"honua_admin_connection_test",
|
|
56
|
+
"honua_admin_import_upload_url",
|
|
57
|
+
],
|
|
58
|
+
answerMustInclude: ["isHealthy"],
|
|
59
|
+
answerMustNotInclude: ["ways"],
|
|
60
|
+
...APPROVAL_GATE,
|
|
61
|
+
},
|
|
62
|
+
script: [
|
|
63
|
+
{
|
|
64
|
+
tool: "honua_admin_connection_create",
|
|
65
|
+
args: { secretReference: "env:HONUA_LOCAL_DB_PASSWORD", secretType: "environment" },
|
|
66
|
+
},
|
|
67
|
+
{ tool: "honua_admin_connection_test", args: {} },
|
|
68
|
+
{ tool: "honua_admin_import_upload_url", args: { fileName: "parcels.geojson" } },
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: "publish-layer",
|
|
73
|
+
title: "Validate a table, then publish it",
|
|
74
|
+
category: "admin",
|
|
75
|
+
skillId: "honua-publish-layers",
|
|
76
|
+
journeyStage: "admin",
|
|
77
|
+
journeyAction: "publish-parcels",
|
|
78
|
+
prompt: "Validate the imported parcels table for publish, then publish it as a layer. Report the layer id and that its feature count matches the import. Do not make the service anonymous.",
|
|
79
|
+
criteria: {
|
|
80
|
+
requiredTools: ["honua_admin_connection_validate_table", "honua_admin_layer_publish"],
|
|
81
|
+
expectedToolSequence: ["honua_admin_connection_validate_table", "honua_admin_layer_publish"],
|
|
82
|
+
answerMustInclude: ["layerId"],
|
|
83
|
+
...APPROVAL_GATE,
|
|
84
|
+
},
|
|
85
|
+
script: [
|
|
86
|
+
{ tool: "honua_admin_connection_validate_table", args: { table: "zero_to_map_parcels" } },
|
|
87
|
+
{ tool: "honua_admin_layer_publish", args: { layerName: "Parcels" } },
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "style-png",
|
|
92
|
+
title: "Apply a published preset and render a PNG",
|
|
93
|
+
category: "style",
|
|
94
|
+
skillId: "honua-style-verify",
|
|
95
|
+
journeyStage: "style",
|
|
96
|
+
journeyAction: "render-published-map",
|
|
97
|
+
prompt: "Read the published layer style, apply one preset the server actually advertises, then render the map. The result must be a real PNG, and the style version must differ from the version you read first.",
|
|
98
|
+
criteria: {
|
|
99
|
+
requiredTools: ["honua_get_style", "honua_apply_style_preset", "honua_render_map"],
|
|
100
|
+
expectedToolSequence: ["honua_get_style", "honua_apply_style_preset", "honua_render_map"],
|
|
101
|
+
answerMustInclude: ["PNG"],
|
|
102
|
+
...APPROVAL_GATE,
|
|
103
|
+
},
|
|
104
|
+
script: [
|
|
105
|
+
{ tool: "honua_get_style", args: {} },
|
|
106
|
+
{ tool: "honua_apply_style_preset", args: {} },
|
|
107
|
+
{ tool: "honua_render_map", args: {} },
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: "buffer-three-ways",
|
|
112
|
+
title: "Buffer through Esri MCP, GPServer, and the native verb",
|
|
113
|
+
category: "geoprocessing",
|
|
114
|
+
skillId: "honua-geoprocessing",
|
|
115
|
+
journeyStage: "geoprocessing",
|
|
116
|
+
journeyAction: "buffer-esri-mcp",
|
|
117
|
+
requiresServerProfiles: ["analysis", "esri-gp"],
|
|
118
|
+
prompt: "Discover the Buffer task, describe it, run it, and keep the job result. Then run the same buffer through the native dataset buffer tool. Report each job id.",
|
|
119
|
+
criteria: {
|
|
120
|
+
requiredTools: [
|
|
121
|
+
"honua_esri_gp_list_tasks",
|
|
122
|
+
"honua_esri_gp_describe_task",
|
|
123
|
+
"honua_esri_gp_execute_task",
|
|
124
|
+
"honua_buffer_features",
|
|
125
|
+
],
|
|
126
|
+
expectedToolSequence: [
|
|
127
|
+
"honua_esri_gp_list_tasks",
|
|
128
|
+
"honua_esri_gp_describe_task",
|
|
129
|
+
"honua_esri_gp_execute_task",
|
|
130
|
+
"honua_buffer_features",
|
|
131
|
+
],
|
|
132
|
+
answerMustInclude: ["jobId"],
|
|
133
|
+
...APPROVAL_GATE,
|
|
134
|
+
},
|
|
135
|
+
script: [
|
|
136
|
+
{ tool: "honua_esri_gp_list_tasks", args: {} },
|
|
137
|
+
{ tool: "honua_esri_gp_describe_task", args: { taskName: "Buffer" } },
|
|
138
|
+
{ tool: "honua_esri_gp_execute_task", args: { taskName: "Buffer" } },
|
|
139
|
+
{ tool: "honua_buffer_features", args: {} },
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: "compose-families",
|
|
144
|
+
title: "Compose map, app, and dashboard, then save and reopen",
|
|
145
|
+
category: "studio",
|
|
146
|
+
skillId: "honua-map-composition",
|
|
147
|
+
journeyStage: "studio",
|
|
148
|
+
journeyAction: "create-map-draft",
|
|
149
|
+
prompt: "Compose a map, an app, and a dashboard as three separate drafts. Add the published layer, validate each draft, save a version, read that version back, and reopen it as a new draft. Do not propose publication.",
|
|
150
|
+
criteria: {
|
|
151
|
+
requiredTools: [
|
|
152
|
+
"honua_studio_create_draft",
|
|
153
|
+
"honua_studio_validate_draft",
|
|
154
|
+
"honua_studio_save_version",
|
|
155
|
+
"honua_studio_get_version",
|
|
156
|
+
"honua_studio_reopen_version",
|
|
157
|
+
],
|
|
158
|
+
expectedToolSequence: STUDIO_FAMILIES.flatMap(() => [...STUDIO_LIFECYCLE]),
|
|
159
|
+
requiredArgumentText: STUDIO_FAMILIES.map((family) => `"family":"${family}"`),
|
|
160
|
+
forbiddenTools: ["honua_studio_propose_publication"],
|
|
161
|
+
failOnToolError: true,
|
|
162
|
+
...APPROVAL_GATE,
|
|
163
|
+
},
|
|
164
|
+
script: STUDIO_FAMILIES.flatMap((family) => STUDIO_LIFECYCLE.map((tool) => ({
|
|
165
|
+
tool,
|
|
166
|
+
args: { family, draftId: `${family}-draft`, versionId: `${family}-version` },
|
|
167
|
+
}))),
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: "propose-and-stop",
|
|
171
|
+
title: "Record publication intent and stop before approval",
|
|
172
|
+
category: "proposal",
|
|
173
|
+
skillId: "honua-map-composition",
|
|
174
|
+
journeyStage: "proposal",
|
|
175
|
+
journeyAction: "propose-publication",
|
|
176
|
+
prompt: "Record publication intent for the saved map version, then save that intent as a version. Stop. Do not approve it, do not make it public, and do not invent a public URL.",
|
|
177
|
+
criteria: {
|
|
178
|
+
requiredTools: ["honua_studio_propose_publication", "honua_studio_save_version"],
|
|
179
|
+
expectedToolSequence: ["honua_studio_propose_publication", "honua_studio_save_version"],
|
|
180
|
+
answerMustNotInclude: ["publicationId", "http"],
|
|
181
|
+
...APPROVAL_GATE,
|
|
182
|
+
},
|
|
183
|
+
script: [
|
|
184
|
+
{ tool: "honua_studio_propose_publication", args: {} },
|
|
185
|
+
{ tool: "honua_studio_save_version", args: { changeNote: "intent" } },
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
id: "docs-before-guess",
|
|
190
|
+
title: "Look up the local connection contract before calling it",
|
|
191
|
+
category: "docs",
|
|
192
|
+
skillId: "honua-datasource-connect",
|
|
193
|
+
journeyStage: "admin",
|
|
194
|
+
journeyAction: "create-connection",
|
|
195
|
+
prompt: "Connect this server to its bundled local database. Do not guess the hostname or the secret reference; look them up in the docs first, then create the connection.",
|
|
196
|
+
criteria: {
|
|
197
|
+
requiredTools: ["honua_docs_search", "honua_admin_connection_create"],
|
|
198
|
+
expectedToolSequence: ["honua_docs_search", "honua_admin_connection_create"],
|
|
199
|
+
answerMustInclude: ["postgres", "HONUA_LOCAL_DB_PASSWORD"],
|
|
200
|
+
...APPROVAL_GATE,
|
|
201
|
+
},
|
|
202
|
+
script: [
|
|
203
|
+
{ tool: "honua_docs_search", args: { query: "local database secret reference" } },
|
|
204
|
+
{
|
|
205
|
+
tool: "honua_admin_connection_create",
|
|
206
|
+
args: { host: "postgres", secretReference: "env:HONUA_LOCAL_DB_PASSWORD" },
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
id: "recover-one-error",
|
|
212
|
+
title: "Retry a refused connection test with the corrected argument",
|
|
213
|
+
category: "recovery",
|
|
214
|
+
skillId: "honua-datasource-connect",
|
|
215
|
+
journeyStage: "admin",
|
|
216
|
+
journeyAction: "test-connection",
|
|
217
|
+
prompt: "Test the saved database connection. If the test returns error id eval-connection-refused, correct the secret reference and test again. Report that the same error id recovered.",
|
|
218
|
+
criteria: {
|
|
219
|
+
requiredTools: ["honua_admin_connection_test"],
|
|
220
|
+
expectedToolSequence: ["honua_admin_connection_test", "honua_admin_connection_test"],
|
|
221
|
+
answerMustInclude: ["eval-connection-refused", "recovered"],
|
|
222
|
+
...APPROVAL_GATE,
|
|
223
|
+
},
|
|
224
|
+
script: [
|
|
225
|
+
{ tool: "honua_admin_connection_test", args: { secretReference: "env:HONUA_ZERO_TO_MAP_DB_CONNECTION" } },
|
|
226
|
+
{ tool: "honua_admin_connection_test", args: { secretReference: "env:HONUA_LOCAL_DB_PASSWORD" } },
|
|
227
|
+
],
|
|
228
|
+
},
|
|
229
|
+
];
|
|
230
|
+
/** Profiles named by the scenario that are not in `active`. */
|
|
231
|
+
export function unavailableProfiles(scenario, active) {
|
|
232
|
+
const enabled = new Set(active);
|
|
233
|
+
return (scenario.requiresServerProfiles ?? []).filter((profile) => !enabled.has(profile));
|
|
234
|
+
}
|
|
235
|
+
export function blockedTranscript(modelId, scenario, profiles) {
|
|
236
|
+
return {
|
|
237
|
+
scenarioId: scenario.id,
|
|
238
|
+
modelId,
|
|
239
|
+
steps: [],
|
|
240
|
+
finalAnswer: "",
|
|
241
|
+
clarificationRequested: false,
|
|
242
|
+
errorCount: 0,
|
|
243
|
+
blockedReason: `server profile not enabled: ${profiles.join(", ")}`,
|
|
244
|
+
surface: "mcp",
|
|
245
|
+
skillId: scenario.skillId,
|
|
246
|
+
journeyStage: scenario.journeyStage,
|
|
247
|
+
journeyAction: scenario.journeyAction,
|
|
248
|
+
attribution: "HARNESS_DRIVEN",
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
const SECRET_KEY = /password|secret|token|adminKey|authorization/i;
|
|
252
|
+
/** Drop credential material from a transcript before it is stored. */
|
|
253
|
+
export function redactTranscript(transcript) {
|
|
254
|
+
return {
|
|
255
|
+
...transcript,
|
|
256
|
+
finalAnswer: redactText(transcript.finalAnswer),
|
|
257
|
+
driverError: transcript.driverError ? redactText(transcript.driverError) : transcript.driverError,
|
|
258
|
+
steps: transcript.steps.map((step) => ({
|
|
259
|
+
...step,
|
|
260
|
+
args: redactValue(step.args),
|
|
261
|
+
})),
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
export function annotateTranscript(transcript, scenario, attribution) {
|
|
265
|
+
return {
|
|
266
|
+
...transcript,
|
|
267
|
+
surface: transcript.surface ?? "mcp",
|
|
268
|
+
skillId: scenario.skillId,
|
|
269
|
+
journeyStage: scenario.journeyStage,
|
|
270
|
+
journeyAction: scenario.journeyAction,
|
|
271
|
+
attribution,
|
|
272
|
+
capturedIds: transcript.capturedIds ?? captureIds(transcript.steps),
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function captureIds(steps) {
|
|
276
|
+
const ids = {};
|
|
277
|
+
for (const step of steps) {
|
|
278
|
+
const family = typeof step.args.family === "string" ? `${step.args.family}.` : "";
|
|
279
|
+
for (const key of ["draftId", "versionId", "connectionId", "layerId", "jobId"]) {
|
|
280
|
+
const value = step.args[key];
|
|
281
|
+
if (typeof value === "string")
|
|
282
|
+
ids[`${family}${key}`] = value;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return ids;
|
|
286
|
+
}
|
|
287
|
+
function redactText(value) {
|
|
288
|
+
return value
|
|
289
|
+
.replace(/HONUA_ADMIN_KEY=\S+/g, "HONUA_ADMIN_KEY=[REDACTED]")
|
|
290
|
+
.replace(/POSTGRES_PASSWORD=\S+/g, "POSTGRES_PASSWORD=[REDACTED]")
|
|
291
|
+
.replace(/Bearer\s+\S+/gi, "Bearer [REDACTED]");
|
|
292
|
+
}
|
|
293
|
+
function redactValue(value) {
|
|
294
|
+
if (typeof value === "string")
|
|
295
|
+
return redactText(value);
|
|
296
|
+
if (Array.isArray(value))
|
|
297
|
+
return value.map((entry) => redactValue(entry));
|
|
298
|
+
if (value && typeof value === "object") {
|
|
299
|
+
const redacted = {};
|
|
300
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
301
|
+
redacted[key] = SECRET_KEY.test(key) ? "[REDACTED]" : redactValue(entry);
|
|
302
|
+
}
|
|
303
|
+
return redacted;
|
|
304
|
+
}
|
|
305
|
+
return value;
|
|
306
|
+
}
|
package/dist/src/proxy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/proxy.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAEnE,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/proxy.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAEnE,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AA0BnE;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,YAAY;IAC3B,sFAAsF;IACtF,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAsBD,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,YAAY,CAqBtF;AAED,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUlF;AAED,oFAAoF;AACpF,wBAAsB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAS5E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA+C1D;AAOD;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBlF"}
|
package/dist/src/proxy.js
CHANGED
|
@@ -7,6 +7,12 @@ import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema
|
|
|
7
7
|
import { requireSecureCredentialEndpoint } from "./credential-endpoint.js";
|
|
8
8
|
import { isMainEntrypoint } from "./entrypoint.js";
|
|
9
9
|
import { SERVER_VERSION } from "./index.js";
|
|
10
|
+
// MCP permits server extensions such as Honua's tools/list `view`. The SDK's
|
|
11
|
+
// nested params schema strips unknown keys by default, so preserve them before
|
|
12
|
+
// forwarding or a stdio caller silently receives the default catalog instead.
|
|
13
|
+
const ForwardedListToolsRequestSchema = ListToolsRequestSchema.extend({
|
|
14
|
+
params: ListToolsRequestSchema.shape.params.unwrap().passthrough().optional(),
|
|
15
|
+
});
|
|
10
16
|
function isConfigured(value) {
|
|
11
17
|
return value !== undefined && value.length > 0;
|
|
12
18
|
}
|
|
@@ -78,7 +84,7 @@ export function createProxyServer(upstream) {
|
|
|
78
84
|
});
|
|
79
85
|
// ── Tools ──────────────────────────────────────────────────────
|
|
80
86
|
if (upstreamCapabilities.tools) {
|
|
81
|
-
server.setRequestHandler(
|
|
87
|
+
server.setRequestHandler(ForwardedListToolsRequestSchema, async (request) => upstream.listTools(request.params));
|
|
82
88
|
server.setRequestHandler(CallToolRequestSchema, async (request) => upstream.callTool(request.params));
|
|
83
89
|
}
|
|
84
90
|
// ── Resources ──────────────────────────────────────────────────
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zero-to-map-checkpoint.d.ts","sourceRoot":"","sources":["../../../src/release/zero-to-map-checkpoint.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAE1B,KAAK,kBAAkB,
|
|
1
|
+
{"version":3,"file":"zero-to-map-checkpoint.d.ts","sourceRoot":"","sources":["../../../src/release/zero-to-map-checkpoint.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAE1B,KAAK,kBAAkB,EAOxB,MAAM,kBAAkB,CAAC;AAE1B,eAAO,MAAM,6BAA6B,EAAG,iCAA0C,CAAC;AACxF,eAAO,MAAM,iCAAiC,QAAuB,CAAC;AAEtE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CAC1C;AAED,MAAM,WAAW,mBAAoB,SAAQ,2BAA2B;IACtE,QAAQ,CAAC,aAAa,EAAE,OAAO,6BAA6B,CAAC;IAC7D,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,UAAU,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE;QAClB,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC;QAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AAID,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,2BAA2B,EACrC,QAAQ,EAAE,oBAAoB,EAC9B,SAAS,SAA2B,GACnC,mBAAmB,CAqBrB;AAED,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,mBAAmB,EAC/B,kBAAkB,EAAE,MAAM,EAC1B,UAAU,SAA2B,GACpC,mBAAmB,CAIrB;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAkF5E;AAED,wBAAgB,8BAA8B,CAAC,UAAU,EAAE,mBAAmB,EAAE,GAAG,OAAa,GAAG,IAAI,CAKtG;AAED,wBAAgB,+BAA+B,CAAC,UAAU,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAI7G;AAED,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,mBAAmB,EAC/B,QAAQ,EAAE,2BAA2B,GACpC,IAAI,CAIN"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { ZERO_TO_MAP_CATALOG_RECEIPT_SCHEMA, ZERO_TO_MAP_CONSOLE_RECEIPT_REQUEST_SCHEMA, } from "./zero-to-map.js";
|
|
2
|
+
import { ZERO_TO_MAP_CATALOG_RECEIPT_SCHEMA, ZERO_TO_MAP_CONSOLE_RECEIPT_REQUEST_SCHEMA, ZERO_TO_MAP_FULL_CATALOG_VIEW, } from "./zero-to-map.js";
|
|
3
3
|
export const ZERO_TO_MAP_CHECKPOINT_SCHEMA = "honua.zero-to-map.checkpoint/v1";
|
|
4
4
|
export const ZERO_TO_MAP_CHECKPOINT_MAX_AGE_MS = 24 * 60 * 60 * 1_000;
|
|
5
5
|
export function createZeroToMapCheckpoint(bindings, snapshot, createdAt = new Date().toISOString()) {
|
|
@@ -199,6 +199,7 @@ function parseCatalogReceipt(value) {
|
|
|
199
199
|
exactKeys(catalog, [
|
|
200
200
|
"schemaVersion",
|
|
201
201
|
"activeProfiles",
|
|
202
|
+
"requestedView",
|
|
202
203
|
"expectedTotalTools",
|
|
203
204
|
"advertisedTotalTools",
|
|
204
205
|
"baseStaticTools",
|
|
@@ -215,9 +216,16 @@ function parseCatalogReceipt(value) {
|
|
|
215
216
|
}
|
|
216
217
|
if (!Array.isArray(catalog.profiles))
|
|
217
218
|
throw new Error(`${path}.profiles must be an array`);
|
|
219
|
+
// The roster carried across the Console pause must have been read from the
|
|
220
|
+
// complete catalog. A checkpoint claiming a narrowed workflow view would be
|
|
221
|
+
// re-emitted onto the final receipt as if it were full-catalog evidence.
|
|
222
|
+
if (catalog.requestedView !== ZERO_TO_MAP_FULL_CATALOG_VIEW) {
|
|
223
|
+
throw new Error(`${path}.requestedView must be ${ZERO_TO_MAP_FULL_CATALOG_VIEW}`);
|
|
224
|
+
}
|
|
218
225
|
return {
|
|
219
226
|
schemaVersion: ZERO_TO_MAP_CATALOG_RECEIPT_SCHEMA,
|
|
220
227
|
activeProfiles: stringList(catalog.activeProfiles, `${path}.activeProfiles`),
|
|
228
|
+
requestedView: ZERO_TO_MAP_FULL_CATALOG_VIEW,
|
|
221
229
|
expectedTotalTools: count(catalog.expectedTotalTools, `${path}.expectedTotalTools`),
|
|
222
230
|
advertisedTotalTools: count(catalog.advertisedTotalTools, `${path}.advertisedTotalTools`),
|
|
223
231
|
baseStaticTools: count(catalog.baseStaticTools, `${path}.baseStaticTools`),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { type AwsEcsProvisionBinding } from "./zero-to-map-provision.js";
|
|
3
|
-
import { type JourneyExecutionResult, type JourneyMcpResourceAction } from "./zero-to-map.js";
|
|
3
|
+
import { type JourneyExecutionResult, type JourneyMcpImageAction, type JourneyMcpResourceAction, type RenderedImageExpectation } from "./zero-to-map.js";
|
|
4
4
|
type JourneyTarget = "local-docker" | "aws-ecs";
|
|
5
5
|
export interface CliOptions {
|
|
6
6
|
readonly execute: boolean;
|
|
@@ -39,6 +39,16 @@ export declare function parseInstallAccessCredential(stdout: string): {
|
|
|
39
39
|
};
|
|
40
40
|
/** Poll one MCP job resource to its declared successful terminal state. */
|
|
41
41
|
export declare function readJourneyMcpResource(action: JourneyMcpResourceAction, read: (uri: string) => Promise<unknown>): Promise<JourneyExecutionResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Fetch a rendered image artifact by reference and prove it is real pixels.
|
|
44
|
+
*
|
|
45
|
+
* `resources/read` returns binary contents as a base64 `blob`, so the bytes are
|
|
46
|
+
* decoded here and handed to the shared PNG validator rather than being trusted
|
|
47
|
+
* from the tool's own self-reported `byteLength`. The renderer reporting
|
|
48
|
+
* 512x512 and the artifact actually being 512x512 are two different claims, and
|
|
49
|
+
* only the second one survives a style/render no-op.
|
|
50
|
+
*/
|
|
51
|
+
export declare function readJourneyRenderedImage(action: JourneyMcpImageAction, expected: RenderedImageExpectation, read: (uri: string) => Promise<unknown>): Promise<JourneyExecutionResult>;
|
|
42
52
|
export declare function requireCompletedPublishedOperation(tool: string, value: unknown): {
|
|
43
53
|
operationId: string;
|
|
44
54
|
status: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zero-to-map-cli.d.ts","sourceRoot":"","sources":["../../../src/release/zero-to-map-cli.ts"],"names":[],"mappings":";AAyBA,OAAO,EACL,KAAK,sBAAsB,EAI5B,MAAM,4BAA4B,CAAC;AACpC,OAAO,
|
|
1
|
+
{"version":3,"file":"zero-to-map-cli.d.ts","sourceRoot":"","sources":["../../../src/release/zero-to-map-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,7 +15,7 @@ import { isMainEntrypoint } from "../entrypoint.js";
|
|
|
15
15
|
import { resolveProxyOptions } from "../proxy.js";
|
|
16
16
|
import { assertZeroToMapCheckpointBindings, assertZeroToMapCheckpointDigest, assertZeroToMapCheckpointFresh, consumeZeroToMapCheckpoint, createZeroToMapCheckpoint, parseZeroToMapCheckpoint, } from "./zero-to-map-checkpoint.js";
|
|
17
17
|
import { ZERO_TO_MAP_ACCESS_GRANTS, assertAwsEcsProvisionBindings, parseAwsEcsProvisionBinding, } from "./zero-to-map-provision.js";
|
|
18
|
-
import { JourneyBlockedError, parseZeroToMapPlan, runZeroToMapJourney, } from "./zero-to-map.js";
|
|
18
|
+
import { JourneyBlockedError, assertRenderedPng, parseZeroToMapPlan, resolvePublishedShareUrl, runZeroToMapJourney, } from "./zero-to-map.js";
|
|
19
19
|
class ContractAdapter {
|
|
20
20
|
runCli() {
|
|
21
21
|
return Promise.reject(new Error("contract adapter must not execute CLI work"));
|
|
@@ -29,6 +29,9 @@ class ContractAdapter {
|
|
|
29
29
|
readResource() {
|
|
30
30
|
return Promise.reject(new Error("contract adapter must not read MCP resources"));
|
|
31
31
|
}
|
|
32
|
+
readImageResource() {
|
|
33
|
+
return Promise.reject(new Error("contract adapter must not fetch rendered image artifacts"));
|
|
34
|
+
}
|
|
32
35
|
runGpServer() {
|
|
33
36
|
return Promise.reject(new Error("contract adapter must not execute GPServer jobs"));
|
|
34
37
|
}
|
|
@@ -106,9 +109,9 @@ class LiveAdapter {
|
|
|
106
109
|
}
|
|
107
110
|
throw new Error("AWS ECS target encountered an unknown Stage 1 install action");
|
|
108
111
|
}
|
|
109
|
-
async listTools() {
|
|
112
|
+
async listTools(options) {
|
|
110
113
|
const client = await this.client();
|
|
111
|
-
const tools = await listAllTools(client);
|
|
114
|
+
const tools = await listAllTools(client, options?.view ? { view: options.view } : undefined);
|
|
112
115
|
return tools.map((tool) => ({ name: tool.name, inputSchema: tool.inputSchema }));
|
|
113
116
|
}
|
|
114
117
|
async callTool(tool, args) {
|
|
@@ -137,6 +140,10 @@ class LiveAdapter {
|
|
|
137
140
|
const client = await this.client();
|
|
138
141
|
return readJourneyMcpResource(action, (uri) => client.readResource({ uri }));
|
|
139
142
|
}
|
|
143
|
+
async readImageResource(action, expected) {
|
|
144
|
+
const client = await this.client();
|
|
145
|
+
return readJourneyRenderedImage(action, expected, (uri) => client.readResource({ uri }));
|
|
146
|
+
}
|
|
140
147
|
async runGpServer(action) {
|
|
141
148
|
const mcpUrl = this.options.mcpUrl;
|
|
142
149
|
if (!mcpUrl) {
|
|
@@ -195,20 +202,17 @@ class LiveAdapter {
|
|
|
195
202
|
};
|
|
196
203
|
}
|
|
197
204
|
async checkHttp(url, expectedStatus) {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
throw new Error("published artifact URL must be HTTPS and must not embed credentials");
|
|
201
|
-
}
|
|
202
|
-
const response = await fetch(url, { method: "GET", redirect: "follow" });
|
|
205
|
+
const absolute = resolvePublishedShareUrl(url, this.options.mcpUrl);
|
|
206
|
+
const response = await fetch(absolute, { method: "GET", redirect: "follow" });
|
|
203
207
|
if (response.status !== expectedStatus) {
|
|
204
|
-
throw new Error(`GET ${
|
|
208
|
+
throw new Error(`GET ${absolute} returned ${response.status}; expected ${expectedStatus}`);
|
|
205
209
|
}
|
|
206
|
-
if (normalizeEndpoint(response.url) !== normalizeEndpoint(
|
|
207
|
-
throw new Error(`GET ${
|
|
210
|
+
if (normalizeEndpoint(response.url) !== normalizeEndpoint(absolute)) {
|
|
211
|
+
throw new Error(`GET ${absolute} resolved to a different published identity: ${response.url}`);
|
|
208
212
|
}
|
|
209
213
|
const contentType = response.headers.get("content-type");
|
|
210
214
|
if (!contentType)
|
|
211
|
-
throw new Error(`GET ${
|
|
215
|
+
throw new Error(`GET ${absolute} returned no content type`);
|
|
212
216
|
return {
|
|
213
217
|
evidence: {
|
|
214
218
|
requestedUrl: url,
|
|
@@ -757,6 +761,42 @@ export async function readJourneyMcpResource(action, read) {
|
|
|
757
761
|
await new Promise((resolve) => setTimeout(resolve, wait.pollIntervalMs));
|
|
758
762
|
}
|
|
759
763
|
}
|
|
764
|
+
/**
|
|
765
|
+
* Fetch a rendered image artifact by reference and prove it is real pixels.
|
|
766
|
+
*
|
|
767
|
+
* `resources/read` returns binary contents as a base64 `blob`, so the bytes are
|
|
768
|
+
* decoded here and handed to the shared PNG validator rather than being trusted
|
|
769
|
+
* from the tool's own self-reported `byteLength`. The renderer reporting
|
|
770
|
+
* 512x512 and the artifact actually being 512x512 are two different claims, and
|
|
771
|
+
* only the second one survives a style/render no-op.
|
|
772
|
+
*/
|
|
773
|
+
export async function readJourneyRenderedImage(action, expected, read) {
|
|
774
|
+
const result = await read(action.uri);
|
|
775
|
+
const { bytes, mimeType } = readBlobResource(result, action.uri);
|
|
776
|
+
const evidence = assertRenderedPng(bytes, mimeType, expected);
|
|
777
|
+
return { value: result, evidence: { ...evidence } };
|
|
778
|
+
}
|
|
779
|
+
function readBlobResource(value, uri) {
|
|
780
|
+
if (!value || typeof value !== "object")
|
|
781
|
+
throw new Error(`${uri} returned an invalid resources/read response`);
|
|
782
|
+
const contents = value.contents;
|
|
783
|
+
if (!Array.isArray(contents))
|
|
784
|
+
throw new Error(`${uri} returned no resource contents`);
|
|
785
|
+
const content = contents.find((candidate) => Boolean(candidate) && typeof candidate === "object" && typeof candidate.blob === "string");
|
|
786
|
+
if (!content) {
|
|
787
|
+
throw new Error(`${uri} returned no binary blob content. A rendered map artifact must come back as base64 resource bytes, not as a text description of one.`);
|
|
788
|
+
}
|
|
789
|
+
let bytes;
|
|
790
|
+
try {
|
|
791
|
+
bytes = new Uint8Array(Buffer.from(content.blob, "base64"));
|
|
792
|
+
}
|
|
793
|
+
catch {
|
|
794
|
+
throw new Error(`${uri} returned a blob that is not valid base64`);
|
|
795
|
+
}
|
|
796
|
+
if (bytes.length === 0)
|
|
797
|
+
throw new Error(`${uri} returned an empty blob`);
|
|
798
|
+
return { bytes, ...(typeof content.mimeType === "string" ? { mimeType: content.mimeType } : {}) };
|
|
799
|
+
}
|
|
760
800
|
function readJsonResource(value, uri) {
|
|
761
801
|
if (!value || typeof value !== "object")
|
|
762
802
|
throw new Error(`${uri} returned an invalid resources/read response`);
|