@honua/mcp-server 0.1.1-beta.0 → 0.1.4-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/LICENSE +201 -0
- package/README.md +202 -7
- package/dist/src/certification/census-fixture-client.d.ts.map +1 -1
- package/dist/src/certification/census-fixture-client.js +5 -0
- package/dist/src/certification/certifier.d.ts +1 -1
- package/dist/src/certification/certifier.d.ts.map +1 -1
- package/dist/src/certification/certifier.js +28 -20
- package/dist/src/certification/cli.js +1 -1
- package/dist/src/certification/cql2.d.ts +24 -0
- package/dist/src/certification/cql2.d.ts.map +1 -0
- package/dist/src/certification/cql2.js +354 -0
- package/dist/src/certification/fixtures.d.ts +8 -0
- package/dist/src/certification/fixtures.d.ts.map +1 -1
- package/dist/src/certification/fixtures.js +26 -10
- package/dist/src/certification/ogc-data.d.ts +30 -0
- package/dist/src/certification/ogc-data.d.ts.map +1 -0
- package/dist/src/certification/ogc-data.js +726 -0
- package/dist/src/certification/ogc-fixture-client.d.ts +4 -0
- package/dist/src/certification/ogc-fixture-client.d.ts.map +1 -0
- package/dist/src/certification/ogc-fixture-client.js +190 -0
- package/dist/src/certification/target.d.ts +10 -1
- package/dist/src/certification/target.d.ts.map +1 -1
- package/dist/src/certification/target.js +45 -2
- package/dist/src/eval/cli.js +6 -3
- package/dist/src/eval/corpus.d.ts +7 -0
- package/dist/src/eval/corpus.d.ts.map +1 -1
- package/dist/src/eval/corpus.js +12 -0
- package/dist/src/eval/ogc-corpus.d.ts +3 -0
- package/dist/src/eval/ogc-corpus.d.ts.map +1 -0
- package/dist/src/eval/ogc-corpus.js +437 -0
- package/dist/src/eval/runner.d.ts +6 -0
- package/dist/src/eval/runner.d.ts.map +1 -1
- package/dist/src/eval/runner.js +21 -7
- package/dist/src/helpers.d.ts +8 -13
- package/dist/src/helpers.d.ts.map +1 -1
- package/dist/src/helpers.js +7 -35
- package/dist/src/index.d.ts +14 -7
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +24 -15
- package/dist/src/neutral/errors.d.ts +73 -0
- package/dist/src/neutral/errors.d.ts.map +1 -0
- package/dist/src/neutral/errors.js +112 -0
- package/dist/src/neutral/filter.d.ts +108 -0
- package/dist/src/neutral/filter.d.ts.map +1 -0
- package/dist/src/neutral/filter.js +271 -0
- package/dist/src/neutral/query.d.ts +101 -0
- package/dist/src/neutral/query.d.ts.map +1 -0
- package/dist/src/neutral/query.js +180 -0
- package/dist/src/neutral/result.d.ts +33 -0
- package/dist/src/neutral/result.d.ts.map +1 -0
- package/dist/src/neutral/result.js +38 -0
- package/dist/src/neutral/source-ref.d.ts +126 -0
- package/dist/src/neutral/source-ref.d.ts.map +1 -0
- package/dist/src/neutral/source-ref.js +267 -0
- package/dist/src/nl-map-control.d.ts.map +1 -1
- package/dist/src/tools/count-features.d.ts +85 -11
- package/dist/src/tools/count-features.d.ts.map +1 -1
- package/dist/src/tools/count-features.js +49 -31
- package/dist/src/tools/describe-layer.d.ts +30 -6
- package/dist/src/tools/describe-layer.d.ts.map +1 -1
- package/dist/src/tools/describe-layer.js +99 -8
- package/dist/src/tools/get-extent.d.ts +69 -11
- package/dist/src/tools/get-extent.d.ts.map +1 -1
- package/dist/src/tools/get-extent.js +28 -46
- package/dist/src/tools/list-services.d.ts +7 -0
- package/dist/src/tools/list-services.d.ts.map +1 -1
- package/dist/src/tools/list-services.js +8 -1
- package/dist/src/tools/list-sources.d.ts +44 -0
- package/dist/src/tools/list-sources.d.ts.map +1 -0
- package/dist/src/tools/list-sources.js +138 -0
- package/dist/src/tools/query-features.d.ts +99 -19
- package/dist/src/tools/query-features.d.ts.map +1 -1
- package/dist/src/tools/query-features.js +38 -45
- package/dist/src/tools/statistics.d.ts +80 -12
- package/dist/src/tools/statistics.d.ts.map +1 -1
- package/dist/src/tools/statistics.js +56 -23
- package/package.json +31 -7
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NON-GeoServices (OGC API Features) eval corpus — issue #1005.
|
|
3
|
+
*
|
|
4
|
+
* The standalone corpus proves the surface works against a plain Esri
|
|
5
|
+
* FeatureServer. That is only half the vendor-neutrality claim: a tool contract
|
|
6
|
+
* can pass every GeoServices scenario and still be Esri-shaped. This corpus runs
|
|
7
|
+
* the same catalog against a plain **OGC API Features** endpoint — recorded from
|
|
8
|
+
* the public pygeoapi demo (`src/certification/ogc-data.ts`), the pinned
|
|
9
|
+
* `ogc-features` target in `config/live-conformance-endpoints.v1.json` — where
|
|
10
|
+
* nothing Esri exists: no `/rest/services`, no `serviceId`, no `layerId`.
|
|
11
|
+
*
|
|
12
|
+
* Every scenario addresses data with the protocol-neutral
|
|
13
|
+
* `ogc-features:<collectionId>` reference and filters with the typed semantic
|
|
14
|
+
* filter, a `bbox`, or a canonical temporal predicate. Grading is SEMANTIC, on
|
|
15
|
+
* anchors verified against the recorded data:
|
|
16
|
+
*
|
|
17
|
+
* obs (5 observations): avg(value)=96.14 max=103.5 stn_id=2147 => 2 rows
|
|
18
|
+
* value>95 => 2 2001-01-01..2004-01-01 => 3 rows
|
|
19
|
+
* bbox(-80,42,-78,44) => 2 rows
|
|
20
|
+
* utah_city_locations (31 cities): sum(POP_2000)=354212 max=105166 (Provo)
|
|
21
|
+
* CO_SEAT='yes' => 1 POP_2000>100000 => 1
|
|
22
|
+
*
|
|
23
|
+
* Two scenarios grade HONESTY rather than data: OGC API Features has no
|
|
24
|
+
* server-side aggregation and no server-side extent operation, so those answers
|
|
25
|
+
* must arrive carrying an explicit degradation reason; and a CQL2 spatial
|
|
26
|
+
* predicate the endpoint does not publish must come back as a structured
|
|
27
|
+
* capability refusal, never as an empty feature list.
|
|
28
|
+
*
|
|
29
|
+
* Selected via `HONUA_EVAL_CORPUS=ogc` / `--corpus ogc`; the runner swaps in the
|
|
30
|
+
* OGC fixture client for this corpus (see `runner.ts`).
|
|
31
|
+
*/
|
|
32
|
+
const OBS = "ogc-features:obs";
|
|
33
|
+
const CITIES = "ogc-features:utah_city_locations";
|
|
34
|
+
export const OGC_CORPUS = [
|
|
35
|
+
// ── Protocol-neutral discovery ───────────────────────────────────────────
|
|
36
|
+
{
|
|
37
|
+
id: "ogc-discover-sources",
|
|
38
|
+
title: "Discover sources on an endpoint with no GeoServices catalog",
|
|
39
|
+
category: "discovery",
|
|
40
|
+
prompt: "What data can I query at this endpoint? List the sources and how I address them.",
|
|
41
|
+
criteria: {
|
|
42
|
+
requiredTools: ["honua_list_sources"],
|
|
43
|
+
answerMustInclude: ["ogc-features:obs", "ogc-features:utah_city_locations"],
|
|
44
|
+
},
|
|
45
|
+
script: [{ tool: "honua_list_sources", args: {} }],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "ogc-discover-geoservices-absent",
|
|
49
|
+
title: "The GeoServices family is reported absent, not as 'no data'",
|
|
50
|
+
category: "degradation",
|
|
51
|
+
prompt: "Does this endpoint publish any Esri feature services? Be honest if it does not.",
|
|
52
|
+
criteria: {
|
|
53
|
+
requiredTools: ["honua_list_sources"],
|
|
54
|
+
answerMustInclude: ["geoservices", "ogc-features:obs"],
|
|
55
|
+
answerMustMatch: ['"available":\\s*false'],
|
|
56
|
+
},
|
|
57
|
+
script: [{ tool: "honua_list_sources", args: {} }],
|
|
58
|
+
},
|
|
59
|
+
// ── Schema grounding ─────────────────────────────────────────────────────
|
|
60
|
+
{
|
|
61
|
+
id: "ogc-describe-collection",
|
|
62
|
+
title: "Inspect an OGC collection's schema before querying",
|
|
63
|
+
category: "grounding",
|
|
64
|
+
prompt: "Show me the fields on the observations collection before I query it.",
|
|
65
|
+
criteria: {
|
|
66
|
+
requiredTools: ["honua_describe_layer"],
|
|
67
|
+
answerMustInclude: ["stn_id", "value", "ogc-features"],
|
|
68
|
+
},
|
|
69
|
+
script: [{ tool: "honua_describe_layer", args: { source: OBS } }],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: "ogc-describe-capabilities",
|
|
73
|
+
title: "Report the capabilities the protocol actually advertises",
|
|
74
|
+
category: "grounding",
|
|
75
|
+
prompt: "What can I actually do with the observations collection — can I aggregate on the server?",
|
|
76
|
+
criteria: {
|
|
77
|
+
requiredTools: ["honua_describe_layer"],
|
|
78
|
+
answerMustInclude: ["capabilities", "query"],
|
|
79
|
+
answerMustNotInclude: ['"queryAggregate"'],
|
|
80
|
+
},
|
|
81
|
+
script: [{ tool: "honua_describe_layer", args: { source: OBS } }],
|
|
82
|
+
},
|
|
83
|
+
// ── Counting through numberMatched ───────────────────────────────────────
|
|
84
|
+
{
|
|
85
|
+
id: "ogc-count-all",
|
|
86
|
+
title: "Count every record in an OGC collection",
|
|
87
|
+
category: "count",
|
|
88
|
+
prompt: "How many observations are there? Just the number.",
|
|
89
|
+
criteria: {
|
|
90
|
+
requiredTools: ["honua_count_features"],
|
|
91
|
+
forbiddenTools: ["honua_query_features"],
|
|
92
|
+
answerMustMatch: ['"count":\\s*5'],
|
|
93
|
+
},
|
|
94
|
+
script: [{ tool: "honua_count_features", args: { source: OBS } }],
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: "ogc-count-typed-filter",
|
|
98
|
+
title: "Count with the typed semantic filter (compiled to CQL2)",
|
|
99
|
+
category: "count",
|
|
100
|
+
prompt: "How many observations came from station 2147?",
|
|
101
|
+
criteria: {
|
|
102
|
+
requiredTools: ["honua_count_features"],
|
|
103
|
+
answerMustMatch: ['"count":\\s*2'],
|
|
104
|
+
},
|
|
105
|
+
script: [
|
|
106
|
+
{
|
|
107
|
+
tool: "honua_count_features",
|
|
108
|
+
args: { source: OBS, filter: { op: "eq", field: "stn_id", value: 2147 } },
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: "ogc-count-county-seat",
|
|
114
|
+
title: "Count with a string equality filter",
|
|
115
|
+
category: "count",
|
|
116
|
+
prompt: "How many of these Utah cities are county seats?",
|
|
117
|
+
criteria: {
|
|
118
|
+
requiredTools: ["honua_count_features"],
|
|
119
|
+
answerMustMatch: ['"count":\\s*1'],
|
|
120
|
+
},
|
|
121
|
+
script: [
|
|
122
|
+
{
|
|
123
|
+
tool: "honua_count_features",
|
|
124
|
+
args: { source: CITIES, filter: { op: "eq", field: "CO_SEAT", value: "yes" } },
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
// ── Typed filter + ordering ──────────────────────────────────────────────
|
|
129
|
+
{
|
|
130
|
+
id: "ogc-filter-and-sort",
|
|
131
|
+
title: "Filter and sort with the protocol-neutral vocabulary",
|
|
132
|
+
category: "query",
|
|
133
|
+
prompt: "Show me the observations with a value above 95, highest first.",
|
|
134
|
+
criteria: {
|
|
135
|
+
requiredTools: ["honua_query_features"],
|
|
136
|
+
answerMustMatch: ["103.5", '"returnedCount":\\s*2'],
|
|
137
|
+
},
|
|
138
|
+
script: [
|
|
139
|
+
{
|
|
140
|
+
tool: "honua_query_features",
|
|
141
|
+
args: {
|
|
142
|
+
source: OBS,
|
|
143
|
+
filter: { op: "gt", field: "value", value: 95 },
|
|
144
|
+
orderBy: [{ field: "value", direction: "desc" }],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: "ogc-filter-compound",
|
|
151
|
+
title: "Compound AND filter over an OGC collection",
|
|
152
|
+
category: "query",
|
|
153
|
+
prompt: "Which observations from station 2147 have a value under 100?",
|
|
154
|
+
criteria: {
|
|
155
|
+
requiredTools: ["honua_query_features"],
|
|
156
|
+
answerMustMatch: ["93.5", '"returnedCount":\\s*1'],
|
|
157
|
+
answerMustNotInclude: ["103.5"],
|
|
158
|
+
},
|
|
159
|
+
script: [
|
|
160
|
+
{
|
|
161
|
+
tool: "honua_query_features",
|
|
162
|
+
args: {
|
|
163
|
+
source: OBS,
|
|
164
|
+
filter: {
|
|
165
|
+
op: "and",
|
|
166
|
+
args: [
|
|
167
|
+
{ op: "eq", field: "stn_id", value: 2147 },
|
|
168
|
+
{ op: "lt", field: "value", value: 100 },
|
|
169
|
+
],
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
id: "ogc-filter-largest-city",
|
|
177
|
+
title: "Find the largest city with a typed filter",
|
|
178
|
+
category: "reasoning",
|
|
179
|
+
prompt: "Which of these Utah cities had more than 100,000 people in 2000?",
|
|
180
|
+
criteria: {
|
|
181
|
+
requiredTools: ["honua_query_features"],
|
|
182
|
+
answerMustMatch: ["105166", '"returnedCount":\\s*1'],
|
|
183
|
+
},
|
|
184
|
+
script: [
|
|
185
|
+
{
|
|
186
|
+
tool: "honua_query_features",
|
|
187
|
+
args: { source: CITIES, filter: { op: "gt", field: "POP_2000", value: 100000 } },
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
},
|
|
191
|
+
// ── Canonical geometry + temporal predicates ─────────────────────────────
|
|
192
|
+
{
|
|
193
|
+
id: "ogc-bbox-filter",
|
|
194
|
+
title: "Spatial filter through the canonical bbox",
|
|
195
|
+
category: "query",
|
|
196
|
+
prompt: "Which observations fall inside the box from -80,42 to -78,44? Include their geometry.",
|
|
197
|
+
criteria: {
|
|
198
|
+
requiredTools: ["honua_query_features"],
|
|
199
|
+
answerMustMatch: ['"returnedCount":\\s*2', '"geometryFormat":\\s*"geojson"'],
|
|
200
|
+
answerMustInclude: ["Point"],
|
|
201
|
+
},
|
|
202
|
+
script: [
|
|
203
|
+
{
|
|
204
|
+
tool: "honua_query_features",
|
|
205
|
+
args: { source: OBS, bbox: [-80, 42, -78, 44], returnGeometry: true },
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
id: "ogc-temporal-interval",
|
|
211
|
+
title: "Canonical temporal interval on the collection time dimension",
|
|
212
|
+
category: "query",
|
|
213
|
+
prompt: "How many observations were recorded between 2001 and the start of 2004?",
|
|
214
|
+
criteria: {
|
|
215
|
+
requiredTools: ["honua_count_features"],
|
|
216
|
+
answerMustMatch: ['"count":\\s*3'],
|
|
217
|
+
},
|
|
218
|
+
script: [
|
|
219
|
+
{
|
|
220
|
+
tool: "honua_count_features",
|
|
221
|
+
args: { source: OBS, temporal: { start: "2001-01-01T00:00:00Z", end: "2004-01-01T00:00:00Z" } },
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
id: "ogc-temporal-field",
|
|
227
|
+
title: "Canonical temporal predicate bound to an explicit field",
|
|
228
|
+
category: "query",
|
|
229
|
+
prompt: "Count the observations whose datetime column falls in 2001 through 2003.",
|
|
230
|
+
criteria: {
|
|
231
|
+
requiredTools: ["honua_count_features"],
|
|
232
|
+
answerMustMatch: ['"count":\\s*3'],
|
|
233
|
+
},
|
|
234
|
+
script: [
|
|
235
|
+
{
|
|
236
|
+
tool: "honua_count_features",
|
|
237
|
+
args: {
|
|
238
|
+
source: OBS,
|
|
239
|
+
temporal: { start: "2001-01-01T00:00:00Z", end: "2004-01-01T00:00:00Z", field: "datetime" },
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
// ── Aggregation with honest degradation ──────────────────────────────────
|
|
245
|
+
{
|
|
246
|
+
id: "ogc-aggregate-sum",
|
|
247
|
+
title: "Aggregate over a protocol with no server-side aggregation",
|
|
248
|
+
category: "analysis",
|
|
249
|
+
prompt: "What is the total 2000 population across these Utah cities?",
|
|
250
|
+
criteria: {
|
|
251
|
+
requiredTools: ["honua_statistics"],
|
|
252
|
+
answerMustInclude: ["sum_POP_2000"],
|
|
253
|
+
answerMustMatch: ["354212"],
|
|
254
|
+
},
|
|
255
|
+
script: [{ tool: "honua_statistics", args: { source: CITIES, statisticType: "sum", onField: "POP_2000" } }],
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
id: "ogc-aggregate-degradation-reported",
|
|
259
|
+
title: "Client-side aggregation is reported, not passed off as server-side",
|
|
260
|
+
category: "degradation",
|
|
261
|
+
prompt: "Average the observation values, and tell me whether the server computed that or you did.",
|
|
262
|
+
criteria: {
|
|
263
|
+
requiredTools: ["honua_statistics"],
|
|
264
|
+
answerMustInclude: ["degraded", "queryAggregate", "client-side"],
|
|
265
|
+
answerMustMatch: ["96.14"],
|
|
266
|
+
},
|
|
267
|
+
script: [{ tool: "honua_statistics", args: { source: OBS, statisticType: "avg", onField: "value" } }],
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
id: "ogc-aggregate-grouped",
|
|
271
|
+
title: "Grouped aggregation across an OGC collection",
|
|
272
|
+
category: "analysis",
|
|
273
|
+
prompt: "Break the Utah cities down by whether they are county seats and count each group.",
|
|
274
|
+
criteria: {
|
|
275
|
+
requiredTools: ["honua_statistics"],
|
|
276
|
+
answerMustInclude: ["CO_SEAT"],
|
|
277
|
+
answerMustMatch: ['"count_POP_2000":\\s*30', '"count_POP_2000":\\s*1'],
|
|
278
|
+
},
|
|
279
|
+
script: [
|
|
280
|
+
{
|
|
281
|
+
tool: "honua_statistics",
|
|
282
|
+
args: { source: CITIES, statisticType: "count", onField: "POP_2000", groupBy: ["CO_SEAT"] },
|
|
283
|
+
},
|
|
284
|
+
],
|
|
285
|
+
},
|
|
286
|
+
// ── Extent with honest provenance ────────────────────────────────────────
|
|
287
|
+
{
|
|
288
|
+
id: "ogc-extent-declared",
|
|
289
|
+
title: "Extent comes from the declared collection extent, and says so",
|
|
290
|
+
category: "degradation",
|
|
291
|
+
prompt: "What area do these Utah cities cover?",
|
|
292
|
+
criteria: {
|
|
293
|
+
requiredTools: ["honua_get_extent"],
|
|
294
|
+
answerMustInclude: ["declared-extent"],
|
|
295
|
+
answerMustMatch: ["-112.108489"],
|
|
296
|
+
},
|
|
297
|
+
script: [{ tool: "honua_get_extent", args: { source: CITIES } }],
|
|
298
|
+
},
|
|
299
|
+
// ── Capability honesty ───────────────────────────────────────────────────
|
|
300
|
+
{
|
|
301
|
+
id: "ogc-spatial-predicate-refused",
|
|
302
|
+
title: "An inexpressible spatial predicate refuses instead of returning nothing",
|
|
303
|
+
category: "degradation",
|
|
304
|
+
prompt: "Find the observations strictly within this polygon. If this endpoint cannot do that, say so — do not tell me there are none.",
|
|
305
|
+
criteria: {
|
|
306
|
+
requiredTools: ["honua_query_features"],
|
|
307
|
+
answerMustInclude: ["Part 3"],
|
|
308
|
+
answerMustNotInclude: ['"returnedCount": 0'],
|
|
309
|
+
},
|
|
310
|
+
script: [
|
|
311
|
+
{
|
|
312
|
+
tool: "honua_query_features",
|
|
313
|
+
args: {
|
|
314
|
+
source: OBS,
|
|
315
|
+
filter: {
|
|
316
|
+
op: "within",
|
|
317
|
+
geometry: {
|
|
318
|
+
type: "Polygon",
|
|
319
|
+
coordinates: [
|
|
320
|
+
[
|
|
321
|
+
[-80, 42],
|
|
322
|
+
[-78, 42],
|
|
323
|
+
[-78, 44],
|
|
324
|
+
[-80, 44],
|
|
325
|
+
[-80, 42],
|
|
326
|
+
],
|
|
327
|
+
],
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
],
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
id: "ogc-bad-source-reference",
|
|
336
|
+
title: "A malformed source reference is refused with the accepted forms",
|
|
337
|
+
category: "grounding",
|
|
338
|
+
prompt: "Query the collection called 'observations-2024' on this server.",
|
|
339
|
+
criteria: {
|
|
340
|
+
requiredTools: ["honua_query_features"],
|
|
341
|
+
answerMustInclude: ["invalid_source_reference", "ogc-features:<collectionId>"],
|
|
342
|
+
},
|
|
343
|
+
script: [{ tool: "honua_query_features", args: { source: "observations-2024" } }],
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
id: "ogc-style-unavailable",
|
|
347
|
+
title: "Styling degrades honestly on an OGC endpoint too",
|
|
348
|
+
category: "degradation",
|
|
349
|
+
prompt: "List the map styles this endpoint publishes.",
|
|
350
|
+
criteria: {
|
|
351
|
+
requiredTools: ["honua_get_style"],
|
|
352
|
+
answerMustInclude: ["OGC API - Styles"],
|
|
353
|
+
answerMustMatch: ['"available":\\s*false'],
|
|
354
|
+
},
|
|
355
|
+
script: [{ tool: "honua_get_style", args: {} }],
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
id: "ogc-capability-gap-explained",
|
|
359
|
+
title: "Explain the aggregation gap for the OGC protocol",
|
|
360
|
+
category: "grounding",
|
|
361
|
+
prompt: "Can OGC API Features aggregate on the server? If not, what should I do instead?",
|
|
362
|
+
criteria: {
|
|
363
|
+
requiredTools: ["honua_explain_capability_gap"],
|
|
364
|
+
answerMustInclude: ["explanation"],
|
|
365
|
+
},
|
|
366
|
+
script: [
|
|
367
|
+
{
|
|
368
|
+
tool: "honua_explain_capability_gap",
|
|
369
|
+
args: { capability: "queryAggregate", protocol: "ogc-features" },
|
|
370
|
+
},
|
|
371
|
+
],
|
|
372
|
+
},
|
|
373
|
+
// ── Multi-step workflows ─────────────────────────────────────────────────
|
|
374
|
+
{
|
|
375
|
+
id: "ogc-discover-describe-query",
|
|
376
|
+
title: "Discover → describe → query, end to end, with zero Esri vocabulary",
|
|
377
|
+
category: "multi-step",
|
|
378
|
+
prompt: "I don't know this endpoint. Find a source, inspect its schema, then show me its highest-value observation.",
|
|
379
|
+
criteria: {
|
|
380
|
+
requiredTools: ["honua_list_sources", "honua_describe_layer", "honua_query_features"],
|
|
381
|
+
expectedToolSequence: ["honua_list_sources", "honua_describe_layer", "honua_query_features"],
|
|
382
|
+
answerMustMatch: ["103.5"],
|
|
383
|
+
},
|
|
384
|
+
script: [
|
|
385
|
+
{ tool: "honua_list_sources", args: {} },
|
|
386
|
+
{ tool: "honua_describe_layer", args: { source: OBS } },
|
|
387
|
+
{
|
|
388
|
+
tool: "honua_query_features",
|
|
389
|
+
args: { source: OBS, orderBy: [{ field: "value", direction: "desc" }], limit: 1 },
|
|
390
|
+
},
|
|
391
|
+
],
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
id: "ogc-count-then-list",
|
|
395
|
+
title: "Check cardinality, then fetch the matching records",
|
|
396
|
+
category: "multi-step",
|
|
397
|
+
prompt: "How many observations exceed 95, and which are they?",
|
|
398
|
+
criteria: {
|
|
399
|
+
requiredTools: ["honua_count_features", "honua_query_features"],
|
|
400
|
+
expectedToolSequence: ["honua_count_features", "honua_query_features"],
|
|
401
|
+
answerMustMatch: ['"count":\\s*2', "99.9"],
|
|
402
|
+
},
|
|
403
|
+
script: [
|
|
404
|
+
{
|
|
405
|
+
tool: "honua_count_features",
|
|
406
|
+
args: { source: OBS, filter: { op: "gt", field: "value", value: 95 } },
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
tool: "honua_query_features",
|
|
410
|
+
args: { source: OBS, filter: { op: "gt", field: "value", value: 95 } },
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
},
|
|
414
|
+
// ── Ambiguity / refusal ──────────────────────────────────────────────────
|
|
415
|
+
{
|
|
416
|
+
id: "ogc-clarify-which-collection",
|
|
417
|
+
title: "Ambiguous 'the data' → clarify which collection",
|
|
418
|
+
category: "clarification",
|
|
419
|
+
prompt: "Show me the data from this server.",
|
|
420
|
+
criteria: { requiredTools: [], expectClarification: true },
|
|
421
|
+
script: [],
|
|
422
|
+
clarify: {
|
|
423
|
+
question: "Which collection would you like — the observations (ogc-features:obs) or the Utah city locations (ogc-features:utah_city_locations)?",
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
id: "ogc-refuse-write",
|
|
428
|
+
title: "Read-only endpoint → refuse an edit",
|
|
429
|
+
category: "clarification",
|
|
430
|
+
prompt: "Set every observation value to 100 and save it.",
|
|
431
|
+
criteria: { requiredTools: [], expectClarification: true },
|
|
432
|
+
script: [],
|
|
433
|
+
clarify: {
|
|
434
|
+
question: "This MCP surface is read-only, so I can't write features to this OGC API Features endpoint. Would you like me to query or aggregate the observations instead?",
|
|
435
|
+
},
|
|
436
|
+
},
|
|
437
|
+
];
|
|
@@ -23,6 +23,12 @@ export interface RunEvalOptions {
|
|
|
23
23
|
* Defaults to true when `HONUA_EVAL_CORPUS=standalone`.
|
|
24
24
|
*/
|
|
25
25
|
forceStandaloneSurface?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Use the NON-GeoServices fixture surface (a plain OGC API Features endpoint,
|
|
28
|
+
* recorded pygeoapi collections) instead of either Honua/Esri fixture. Implies
|
|
29
|
+
* offline. Defaults to true when `HONUA_EVAL_CORPUS=ogc` (issue #1005).
|
|
30
|
+
*/
|
|
31
|
+
forceOgcSurface?: boolean;
|
|
26
32
|
}
|
|
27
33
|
export declare function runEval(options?: RunEvalOptions): Promise<EvalReport>;
|
|
28
34
|
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/eval/runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/eval/runner.ts"],"names":[],"mappings":"AAWA,OAAO,EAAiB,KAAK,UAAU,EAAkB,MAAM,aAAa,CAAC;AAC7E,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAmC,MAAM,YAAY,CAAC;AAEzF;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA4GD,wBAAsB,OAAO,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAkD/E"}
|
package/dist/src/eval/runner.js
CHANGED
|
@@ -2,10 +2,11 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
|
2
2
|
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
3
3
|
import { createStandaloneFixtureClient } from "../certification/census-fixture-client.js";
|
|
4
4
|
import { createFixtureClient } from "../certification/fixture-client.js";
|
|
5
|
+
import { createOgcFixtureClient } from "../certification/ogc-fixture-client.js";
|
|
5
6
|
import { createServer } from "../index.js";
|
|
6
7
|
import { readNegotiatedProtocolVersion, resolveSuiteGitSha } from "../provenance.js";
|
|
7
8
|
import { connectUpstream, resolveProxyOptions } from "../proxy.js";
|
|
8
|
-
import { isStandaloneCorpus, resolveCorpus } from "./corpus.js";
|
|
9
|
+
import { isOgcCorpus, isStandaloneCorpus, resolveCorpus } from "./corpus.js";
|
|
9
10
|
import { resolveDrivers } from "./drivers/index.js";
|
|
10
11
|
import { grade } from "./grade.js";
|
|
11
12
|
import { assembleReport } from "./report.js";
|
|
@@ -17,8 +18,12 @@ function isTruthy(value) {
|
|
|
17
18
|
const v = value.trim().toLowerCase();
|
|
18
19
|
return v.length > 0 && v !== "0" && v !== "false" && v !== "no" && v !== "off";
|
|
19
20
|
}
|
|
20
|
-
async function connectSurface(env, forceOffline, standalone) {
|
|
21
|
-
const live = !forceOffline &&
|
|
21
|
+
async function connectSurface(env, forceOffline, standalone, ogc) {
|
|
22
|
+
const live = !forceOffline &&
|
|
23
|
+
!standalone &&
|
|
24
|
+
!ogc &&
|
|
25
|
+
typeof env.HONUA_MCP_REMOTE_URL === "string" &&
|
|
26
|
+
env.HONUA_MCP_REMOTE_URL.length > 0;
|
|
22
27
|
if (live) {
|
|
23
28
|
const options = resolveProxyOptions(env);
|
|
24
29
|
// The live lane authenticates via the proxy's real credential headers — no
|
|
@@ -41,7 +46,11 @@ async function connectSurface(env, forceOffline, standalone) {
|
|
|
41
46
|
},
|
|
42
47
|
};
|
|
43
48
|
}
|
|
44
|
-
const fixtureClient =
|
|
49
|
+
const fixtureClient = ogc
|
|
50
|
+
? createOgcFixtureClient()
|
|
51
|
+
: standalone
|
|
52
|
+
? createStandaloneFixtureClient()
|
|
53
|
+
: createFixtureClient();
|
|
45
54
|
const server = createServer(fixtureClient);
|
|
46
55
|
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
47
56
|
const client = new Client({ name: "honua-mcp-eval", version: "1.0.0" });
|
|
@@ -50,7 +59,11 @@ async function connectSurface(env, forceOffline, standalone) {
|
|
|
50
59
|
return {
|
|
51
60
|
client,
|
|
52
61
|
backend: "fixture",
|
|
53
|
-
mcpTransport:
|
|
62
|
+
mcpTransport: ogc
|
|
63
|
+
? "in-memory (standalone OGC API Features fixture)"
|
|
64
|
+
: standalone
|
|
65
|
+
? "in-memory (standalone FeatureServer fixture)"
|
|
66
|
+
: "in-memory",
|
|
54
67
|
auth: "none",
|
|
55
68
|
close: async () => {
|
|
56
69
|
await client.close().catch(() => { });
|
|
@@ -86,8 +99,9 @@ export async function runEval(options = {}) {
|
|
|
86
99
|
const corpus = options.corpus ?? resolveCorpus(env);
|
|
87
100
|
const drivers = options.drivers ?? resolveDrivers({ env });
|
|
88
101
|
const standalone = options.forceStandaloneSurface ?? isStandaloneCorpus(env);
|
|
89
|
-
const
|
|
90
|
-
const
|
|
102
|
+
const ogc = options.forceOgcSurface ?? isOgcCorpus(env);
|
|
103
|
+
const forceOffline = options.forceOffline ?? (standalone || ogc);
|
|
104
|
+
const surface = await connectSurface(env, forceOffline, standalone, ogc);
|
|
91
105
|
try {
|
|
92
106
|
const listed = await surface.client.listTools();
|
|
93
107
|
const tools = listed.tools.map((t) => ({
|
package/dist/src/helpers.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import type { EsriGeometryType
|
|
1
|
+
import type { EsriGeometryType } from "@honua/sdk-js/honua";
|
|
2
|
+
/**
|
|
3
|
+
* Esri geometry-type tags.
|
|
4
|
+
*
|
|
5
|
+
* These are the SDK's canonical geometry-operand tags, not part of the tool
|
|
6
|
+
* contract: the tool surface takes GeoJSON (see `neutral/filter.ts`) and only
|
|
7
|
+
* accepts these to disambiguate Esri-JSON geometry sent by legacy clients.
|
|
8
|
+
*/
|
|
2
9
|
export declare const GEOMETRY_TYPES: readonly ["esriGeometryPoint", "esriGeometryPolyline", "esriGeometryPolygon", "esriGeometryEnvelope", "esriGeometryMultipoint"];
|
|
3
|
-
export declare function mapSpatialRel(rel: string | undefined): EsriSpatialRel | undefined;
|
|
4
10
|
export declare function clampLimit(limit: number | undefined): number;
|
|
5
11
|
export declare function resolveGeometryType(geometry: Record<string, unknown> | undefined, geometryType: EsriGeometryType | undefined): EsriGeometryType | undefined;
|
|
6
12
|
export declare function jsonText(result: unknown): {
|
|
@@ -10,17 +16,6 @@ export declare function jsonText(result: unknown): {
|
|
|
10
16
|
}>;
|
|
11
17
|
};
|
|
12
18
|
export declare function metadataErrorText(): string;
|
|
13
|
-
/**
|
|
14
|
-
* Coerce a feature `count` from a query response into a usable value.
|
|
15
|
-
*
|
|
16
|
-
* The default `grpc-web` transport returns counts via `toSafeNumberOrString`,
|
|
17
|
-
* which yields a **string** when the proto count exceeds
|
|
18
|
-
* `Number.MAX_SAFE_INTEGER` (chosen specifically to avoid precision loss). Both
|
|
19
|
-
* a finite `number` and a numeric `string` are valid counts; anything else
|
|
20
|
-
* (non-finite numbers, non-numeric strings, missing values) returns
|
|
21
|
-
* `undefined`.
|
|
22
|
-
*/
|
|
23
|
-
export declare function coerceCount(value: unknown): number | string | undefined;
|
|
24
19
|
export declare function encodeServiceId(serviceId: string): string;
|
|
25
20
|
export declare function decodeServiceId(encoded: string): string;
|
|
26
21
|
export declare function parseLayerId(value: string): number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAM5D;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,iIAMjB,CAAC;AAEX,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAG5D;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC7C,YAAY,EAAE,gBAAgB,GAAG,SAAS,GACzC,gBAAgB,GAAG,SAAS,CA8B9B;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAE5F;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAC3C,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GACzC,OAAO,CAAC,CAAC,EAAE,CAAC,CAqBd"}
|
package/dist/src/helpers.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
const MAX_LIMIT = 2000;
|
|
2
2
|
const DEFAULT_LIMIT = 100;
|
|
3
3
|
const METADATA_ERROR_MESSAGE = "Failed to fetch service metadata.";
|
|
4
|
+
/**
|
|
5
|
+
* Esri geometry-type tags.
|
|
6
|
+
*
|
|
7
|
+
* These are the SDK's canonical geometry-operand tags, not part of the tool
|
|
8
|
+
* contract: the tool surface takes GeoJSON (see `neutral/filter.ts`) and only
|
|
9
|
+
* accepts these to disambiguate Esri-JSON geometry sent by legacy clients.
|
|
10
|
+
*/
|
|
4
11
|
export const GEOMETRY_TYPES = [
|
|
5
12
|
"esriGeometryPoint",
|
|
6
13
|
"esriGeometryPolyline",
|
|
@@ -8,19 +15,6 @@ export const GEOMETRY_TYPES = [
|
|
|
8
15
|
"esriGeometryEnvelope",
|
|
9
16
|
"esriGeometryMultipoint",
|
|
10
17
|
];
|
|
11
|
-
const SPATIAL_REL_MAP = {
|
|
12
|
-
intersects: "esriSpatialRelIntersects",
|
|
13
|
-
contains: "esriSpatialRelContains",
|
|
14
|
-
within: "esriSpatialRelWithin",
|
|
15
|
-
};
|
|
16
|
-
export function mapSpatialRel(rel) {
|
|
17
|
-
if (!rel)
|
|
18
|
-
return undefined;
|
|
19
|
-
const mapped = SPATIAL_REL_MAP[rel];
|
|
20
|
-
if (!mapped)
|
|
21
|
-
throw new Error(`Unknown spatialRel "${rel}". Expected: intersects, contains, within`);
|
|
22
|
-
return mapped;
|
|
23
|
-
}
|
|
24
18
|
export function clampLimit(limit) {
|
|
25
19
|
const n = limit ?? DEFAULT_LIMIT;
|
|
26
20
|
return Math.min(Math.max(1, n), MAX_LIMIT);
|
|
@@ -55,28 +49,6 @@ export function jsonText(result) {
|
|
|
55
49
|
export function metadataErrorText() {
|
|
56
50
|
return METADATA_ERROR_MESSAGE;
|
|
57
51
|
}
|
|
58
|
-
/**
|
|
59
|
-
* Coerce a feature `count` from a query response into a usable value.
|
|
60
|
-
*
|
|
61
|
-
* The default `grpc-web` transport returns counts via `toSafeNumberOrString`,
|
|
62
|
-
* which yields a **string** when the proto count exceeds
|
|
63
|
-
* `Number.MAX_SAFE_INTEGER` (chosen specifically to avoid precision loss). Both
|
|
64
|
-
* a finite `number` and a numeric `string` are valid counts; anything else
|
|
65
|
-
* (non-finite numbers, non-numeric strings, missing values) returns
|
|
66
|
-
* `undefined`.
|
|
67
|
-
*/
|
|
68
|
-
export function coerceCount(value) {
|
|
69
|
-
if (typeof value === "number") {
|
|
70
|
-
return Number.isFinite(value) ? value : undefined;
|
|
71
|
-
}
|
|
72
|
-
if (typeof value === "string") {
|
|
73
|
-
// Accept canonical base-10 integer strings (optionally signed). These are
|
|
74
|
-
// the large-count representation the grpc adapter emits to preserve
|
|
75
|
-
// precision beyond Number.MAX_SAFE_INTEGER.
|
|
76
|
-
return /^-?\d+$/.test(value.trim()) ? value.trim() : undefined;
|
|
77
|
-
}
|
|
78
|
-
return undefined;
|
|
79
|
-
}
|
|
80
52
|
export function encodeServiceId(serviceId) {
|
|
81
53
|
return encodeURIComponent(serviceId);
|
|
82
54
|
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -22,13 +22,20 @@ export declare function createClientFromEnv(env?: NodeJS.ProcessEnv): HonuaClien
|
|
|
22
22
|
/**
|
|
23
23
|
* The PLATFORM-FREE standalone MCP surface (issue #369).
|
|
24
24
|
*
|
|
25
|
-
* This is the direct-SDK operator surface:
|
|
26
|
-
* straight onto `@honua/sdk-js
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
25
|
+
* This is the direct-SDK operator surface: ten read-only geospatial tools wired
|
|
26
|
+
* straight onto `@honua/sdk-js`. Point it at ANY public FeatureServer / OGC API /
|
|
27
|
+
* STAC / WFS / OData endpoint with ZERO Honua-server assumptions — no admin API,
|
|
28
|
+
* no `/healthz`, no `/mcp` catalog. This is what the `honua-mcp` bin runs (see
|
|
29
|
+
* {@link runStandalone}), and what the platform-free certification lanes + eval
|
|
30
|
+
* corpora exercise.
|
|
31
|
+
*
|
|
32
|
+
* The tool contract is PROTOCOL-NEUTRAL (issue #1005): sources are addressed by
|
|
33
|
+
* a `<protocol>:<address>` reference (`honua_list_sources` emits them), filters
|
|
34
|
+
* are the SDK's typed semantic filter, geometry is GeoJSON, and execution goes
|
|
35
|
+
* through the canonical `Dataset`/`Source`/`Query`/`Result` contract so one call
|
|
36
|
+
* means the same thing on every protocol. The GeoServices `serviceId`/`layerId`
|
|
37
|
+
* pair is still accepted as a deprecated compatibility input; no tool schema
|
|
38
|
+
* requires an Esri-only field.
|
|
32
39
|
*
|
|
33
40
|
* Tools that need a Honua-only surface (server-side styling via OGC API – Styles,
|
|
34
41
|
* a `/rest/services` catalog) degrade gracefully on a plain target: they return a
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,SAAS,EAAoB,MAAM,yCAAyC,CAAC;AAGtF,OAAO,EAAE,KAAK,mBAAmB,EAAgC,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,SAAS,EAAoB,MAAM,yCAAyC,CAAC;AAGtF,OAAO,EAAE,KAAK,mBAAmB,EAAgC,MAAM,qBAAqB,CAAC;AAe7F,OAAO,EACL,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,gCAAgC,EAChC,yBAAyB,EACzB,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,6BAA6B,GAC9B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,SAAS,EAAE,cAAc,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,gFAAgF;IAChF,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;CAC7C;AAMD,eAAO,MAAM,cAAc,QAAyB,CAAC;AA2DrD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,cAAc,CAgD5E;AAED,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,WAAW,CASrF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,mBAAwB,aAsGlF;AAMD;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAKvF"}
|