maplibre-gl-geoagent 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +12 -3
  2. package/dist/{GeoAgentControl-CkSzEkxK.js → GeoAgentControl-BWSkl9b-.js} +107 -64
  3. package/dist/{GeoAgentControl-CkSzEkxK.js.map → GeoAgentControl-BWSkl9b-.js.map} +1 -1
  4. package/dist/{GeoAgentControl-BuRXouXc.cjs → GeoAgentControl-J26MMwe5.cjs} +107 -64
  5. package/dist/{GeoAgentControl-BuRXouXc.cjs.map → GeoAgentControl-J26MMwe5.cjs.map} +1 -1
  6. package/dist/{anthropic-AqviskG5.cjs → anthropic-D2xJ9IO4.cjs} +2 -2
  7. package/dist/{anthropic-AqviskG5.cjs.map → anthropic-D2xJ9IO4.cjs.map} +1 -1
  8. package/dist/{anthropic-BmkKDa_y.js → anthropic-DqtWmJMG.js} +2 -2
  9. package/dist/{anthropic-BmkKDa_y.js.map → anthropic-DqtWmJMG.js.map} +1 -1
  10. package/dist/{browser-DMUMiiD6.js → browser-DTYbc3Sp.js} +2 -2
  11. package/dist/{browser-DMUMiiD6.js.map → browser-DTYbc3Sp.js.map} +1 -1
  12. package/dist/{browser-CoAUAizZ.cjs → browser-ZyWGgIdV.cjs} +2 -2
  13. package/dist/{browser-CoAUAizZ.cjs.map → browser-ZyWGgIdV.cjs.map} +1 -1
  14. package/dist/{index-BGu0d4ba.js → index-CRfykVWh.js} +2 -2
  15. package/dist/{index-BGu0d4ba.js.map → index-CRfykVWh.js.map} +1 -1
  16. package/dist/{index-CymPxtlg.cjs → index-D7y77wpc.cjs} +2 -2
  17. package/dist/{index-CymPxtlg.cjs.map → index-D7y77wpc.cjs.map} +1 -1
  18. package/dist/{index-CAzjc-N5.cjs → index-DHGV30Mr.cjs} +2 -2
  19. package/dist/{index-CAzjc-N5.cjs.map → index-DHGV30Mr.cjs.map} +1 -1
  20. package/dist/{index-DmwfExZ4.js → index-DnnohXIw.js} +2 -2
  21. package/dist/{index-DmwfExZ4.js.map → index-DnnohXIw.js.map} +1 -1
  22. package/dist/{index-DNdtYpS0.cjs → index-cO0gccGg.cjs} +2 -2
  23. package/dist/{index-DNdtYpS0.cjs.map → index-cO0gccGg.cjs.map} +1 -1
  24. package/dist/{index-BlVNkKFu.js → index-oSbeAq6a.js} +2 -2
  25. package/dist/{index-BlVNkKFu.js.map → index-oSbeAq6a.js.map} +1 -1
  26. package/dist/index.cjs +1 -1
  27. package/dist/index.mjs +1 -1
  28. package/dist/maplibre-gl-geoagent.css +16 -9
  29. package/dist/react.cjs +1 -1
  30. package/dist/react.mjs +1 -1
  31. package/dist/types/lib/core/GeoAgentControl.d.ts +11 -0
  32. package/dist/types/lib/core/GeoAgentControl.d.ts.map +1 -1
  33. package/package.json +1 -1
package/README.md CHANGED
@@ -14,7 +14,7 @@ inspect and operate on the live map through dedicated browser tools.
14
14
  - Collapsible MapLibre control with a floating chat panel
15
15
  - Browser provider UI for OpenAI Responses, OpenAI Chat, Anthropic, Google Gemini, Amazon Bedrock, and any OpenAI-compatible/custom endpoint
16
16
  - API keys are saved on commit (Enter or blur) with an inline confirmation, then checked against the provider: an invalid key keeps the chat locked, while a verified key (or one that could not be reached for verification) unlocks it
17
- - One-click "Load models" lists the provider's available models into a dropdown
17
+ - Provider, key, and model settings live in one collapsible section that folds away once configured; the model field is a combobox that accepts a typed value or a one-click "Load models" list of the provider's available models
18
18
  - Map tools for camera movement, projection, basemaps, markers, GeoJSON, XYZ tiles, layer visibility, opacity, feature queries, screenshots, and layer cleanup
19
19
  - Optional Google Earth Engine tools for catalog search, OAuth initialization, dataset tile layers, normalized difference indexes, visualization updates, snippets, and bounded statistics
20
20
  - Optional MapLibre JavaScript execution tool, disabled by default
@@ -131,8 +131,9 @@ The API key is written to `sessionStorage` only when you commit it (press Enter
131
131
  or move focus out of the field), so a half-typed key never flips the status
132
132
  badge to "Ready". After a key is committed the control calls the provider's
133
133
  model-list endpoint to verify it: a success marks the connection ready and
134
- populates the model dropdown, an authentication error marks the key invalid and
135
- keeps the prompt locked, and a network/CORS failure leaves the key usable but
134
+ fills the model field's suggestion list, an authentication error marks the key
135
+ invalid and keeps the prompt locked, and a network/CORS failure leaves the key
136
+ usable but
136
137
  unverified so a provider that does not allow browser model listing never blocks
137
138
  you. Use the "Load models" button to re-run this check at any time.
138
139
 
@@ -142,6 +143,14 @@ URL must already be a valid `http(s)` URL when you commit the key; otherwise
142
143
  finish entering the base URL first, then press "Load models" to verify and load
143
144
  the model list.
144
145
 
146
+ The loaded list is filtered to text chat models: embeddings, speech/audio,
147
+ image, moderation, and (for first-party OpenAI) legacy completion models such as
148
+ `davinci` and `*-instruct` are removed. These `/models` endpoints expose no
149
+ "deprecated" flag, so deprecated chat snapshots cannot be detected and are left
150
+ in. Aggregator endpoints such as OpenRouter legitimately list hundreds of chat
151
+ models from many providers; the model field is a combobox, so type to narrow the
152
+ suggestions.
153
+
145
154
  ## Options
146
155
 
147
156
  | Option | Type | Default |
@@ -3518,7 +3518,7 @@ class HttpProtocol extends SerdeContext {
3518
3518
  });
3519
3519
  }
3520
3520
  async loadEventStreamCapability() {
3521
- const { EventStreamSerde } = await import("./index-BlVNkKFu.js");
3521
+ const { EventStreamSerde } = await import("./index-oSbeAq6a.js");
3522
3522
  return new EventStreamSerde({
3523
3523
  marshaller: this.getEventStreamMarshaller(),
3524
3524
  serializer: this.serializer,
@@ -42664,7 +42664,7 @@ class EarthEngineService {
42664
42664
  }
42665
42665
  async loadEe() {
42666
42666
  if (!this.eePromise) {
42667
- this.eePromise = import("./browser-DMUMiiD6.js").then((n) => n.b).then((module) => {
42667
+ this.eePromise = import("./browser-DTYbc3Sp.js").then((n) => n.b).then((module) => {
42668
42668
  const imported = "default" in module ? module.default : module;
42669
42669
  const ee = imported;
42670
42670
  const scope2 = globalThis;
@@ -45927,6 +45927,20 @@ const STATUS_INVALID = "Invalid API key";
45927
45927
  const IDLE_STATUS_LABELS = /* @__PURE__ */ new Set([STATUS_READY, STATUS_SETUP]);
45928
45928
  class ProviderAuthError extends Error {
45929
45929
  }
45930
+ const NON_CHAT_MODEL_MARKERS = [
45931
+ "embed",
45932
+ "whisper",
45933
+ "tts",
45934
+ "text-to-speech",
45935
+ "transcribe",
45936
+ "realtime",
45937
+ "moderation",
45938
+ "dall-e",
45939
+ "gpt-image",
45940
+ "rerank",
45941
+ "guard"
45942
+ ];
45943
+ const OPENAI_LEGACY_MODEL_MARKERS = ["davinci", "babbage", "curie"];
45930
45944
  const BASE_PROVIDER_CONFIGS = {
45931
45945
  "openai-responses": {
45932
45946
  id: "openai-responses",
@@ -46024,7 +46038,7 @@ function defaultModelFor(providerId, defaultModel) {
46024
46038
  function markdownHeading(role) {
46025
46039
  return role.charAt(0).toUpperCase() + role.slice(1).toLowerCase();
46026
46040
  }
46027
- class GeoAgentControl {
46041
+ const _GeoAgentControl = class _GeoAgentControl {
46028
46042
  constructor(options = {}) {
46029
46043
  __publicField(this, "options");
46030
46044
  __publicField(this, "map");
@@ -46057,6 +46071,10 @@ class GeoAgentControl {
46057
46071
  // result over a newer key/provider.
46058
46072
  __publicField(this, "verifyToken", 0);
46059
46073
  __publicField(this, "configNoteTimer", null);
46074
+ __publicField(this, "modelListId", `geoagent-model-list-${_GeoAgentControl.instanceCount += 1}`);
46075
+ // Whether the agent was configured at the last control refresh, used to fold
46076
+ // the settings section away the first time setup completes.
46077
+ __publicField(this, "wasConfigured", false);
46060
46078
  this.options = {
46061
46079
  collapsed: options.collapsed ?? true,
46062
46080
  position: options.position ?? "top-right",
@@ -46112,6 +46130,10 @@ class GeoAgentControl {
46112
46130
  });
46113
46131
  this.setupEventListeners();
46114
46132
  this.loadProviderSettings();
46133
+ if (this.ui) {
46134
+ this.wasConfigured = this.isConfigured();
46135
+ this.ui.settingsDetails.open = !this.wasConfigured;
46136
+ }
46115
46137
  this.applyIdleStatus(true);
46116
46138
  this.appendLog("system", this.readyLogMessage());
46117
46139
  this.updateControls();
@@ -46342,33 +46364,36 @@ class GeoAgentControl {
46342
46364
  const content = document.createElement("div");
46343
46365
  content.className = "geoagent-panel-content";
46344
46366
  content.innerHTML = `
46345
- <div class="geoagent-settings-grid">
46346
- <label>
46347
- Provider
46348
- <select class="geoagent-provider"></select>
46349
- </label>
46350
- <label>
46351
- <span class="geoagent-api-key-label">API Key</span>
46352
- <input class="geoagent-api-key" type="password" autocomplete="off" placeholder="sk-..." />
46353
- </label>
46354
- <label class="geoagent-base-url-row" hidden>
46355
- API Base URL
46356
- <input class="geoagent-base-url" autocomplete="off" placeholder="https://host/v1" />
46357
- </label>
46358
- <label class="geoagent-bedrock-region-row" hidden>
46359
- Region
46360
- <input class="geoagent-bedrock-region" autocomplete="off" placeholder="us-west-2" />
46361
- </label>
46362
- <label class="geoagent-model-cell">
46363
- Model
46364
- <div class="geoagent-model-row">
46365
- <input class="geoagent-model-id" />
46366
- <button class="geoagent-load-models secondary" type="button">Load models</button>
46367
- </div>
46368
- <select class="geoagent-model-select" aria-label="Available models" hidden></select>
46369
- </label>
46370
- <div class="geoagent-config-note" aria-live="polite" hidden></div>
46371
- </div>
46367
+ <details class="geoagent-settings">
46368
+ <summary>Provider &amp; model</summary>
46369
+ <div class="geoagent-settings-grid">
46370
+ <label>
46371
+ Provider
46372
+ <select class="geoagent-provider"></select>
46373
+ </label>
46374
+ <label>
46375
+ <span class="geoagent-api-key-label">API Key</span>
46376
+ <input class="geoagent-api-key" type="password" autocomplete="off" placeholder="sk-..." />
46377
+ </label>
46378
+ <label class="geoagent-base-url-row" hidden>
46379
+ API Base URL
46380
+ <input class="geoagent-base-url" autocomplete="off" placeholder="https://host/v1" />
46381
+ </label>
46382
+ <label class="geoagent-bedrock-region-row" hidden>
46383
+ Region
46384
+ <input class="geoagent-bedrock-region" autocomplete="off" placeholder="us-west-2" />
46385
+ </label>
46386
+ <label class="geoagent-model-cell">
46387
+ Model
46388
+ <div class="geoagent-model-row">
46389
+ <input class="geoagent-model-id" list="${this.modelListId}" autocomplete="off" />
46390
+ <button class="geoagent-load-models secondary" type="button">Load models</button>
46391
+ </div>
46392
+ <datalist class="geoagent-model-list" id="${this.modelListId}"></datalist>
46393
+ </label>
46394
+ <div class="geoagent-config-note" aria-live="polite" hidden></div>
46395
+ </div>
46396
+ </details>
46372
46397
 
46373
46398
  <details class="geoagent-earth-engine">
46374
46399
  <summary>Earth Engine</summary>
@@ -46413,13 +46438,14 @@ class GeoAgentControl {
46413
46438
  panel.append(header, content, resizeHandleLeft, resizeHandleRight);
46414
46439
  this.ui = {
46415
46440
  status,
46441
+ settingsDetails: this.requiredElement(content, ".geoagent-settings"),
46416
46442
  providerSelect: this.requiredElement(content, ".geoagent-provider"),
46417
46443
  apiKeyLabel: this.requiredElement(content, ".geoagent-api-key-label"),
46418
46444
  apiKeyInput: this.requiredElement(content, ".geoagent-api-key"),
46419
46445
  baseUrlLabel: this.requiredElement(content, ".geoagent-base-url-row"),
46420
46446
  baseUrlInput: this.requiredElement(content, ".geoagent-base-url"),
46421
46447
  modelIdInput: this.requiredElement(content, ".geoagent-model-id"),
46422
- modelSelect: this.requiredElement(content, ".geoagent-model-select"),
46448
+ modelList: this.requiredElement(content, ".geoagent-model-list"),
46423
46449
  loadModelsButton: this.requiredElement(content, ".geoagent-load-models"),
46424
46450
  configNote: this.requiredElement(content, ".geoagent-config-note"),
46425
46451
  bedrockRegionLabel: this.requiredElement(content, ".geoagent-bedrock-region-row"),
@@ -46577,14 +46603,6 @@ class GeoAgentControl {
46577
46603
  ui.loadModelsButton.addEventListener("click", () => {
46578
46604
  void this.verifyAndLoadModels();
46579
46605
  });
46580
- ui.modelSelect.addEventListener("change", () => {
46581
- const modelId = ui.modelSelect.value;
46582
- if (!modelId) {
46583
- return;
46584
- }
46585
- ui.modelIdInput.value = modelId;
46586
- ui.modelIdInput.dispatchEvent(new Event("input", { bubbles: true }));
46587
- });
46588
46606
  ui.modelIdInput.addEventListener("input", () => {
46589
46607
  const modelId = ui.modelIdInput.value.trim();
46590
46608
  this.state.modelId = modelId;
@@ -47036,6 +47054,10 @@ ${markdown.trim()}`;
47036
47054
  this.ui.cancelButton.disabled = !this.state.busy || this.cancelRequested;
47037
47055
  this.ui.clearButton.disabled = this.state.busy;
47038
47056
  this.ui.copyButton.disabled = this.ui.log.childElementCount === 0;
47057
+ if (configured && !this.wasConfigured) {
47058
+ this.ui.settingsDetails.open = false;
47059
+ }
47060
+ this.wasConfigured = configured;
47039
47061
  this.applyIdleStatus();
47040
47062
  }
47041
47063
  /** Placeholder hint shown in the prompt field while it is locked. */
@@ -47211,25 +47233,13 @@ ${markdown.trim()}`;
47211
47233
  if (!this.ui) {
47212
47234
  return;
47213
47235
  }
47214
- const select = this.ui.modelSelect;
47215
- select.replaceChildren();
47216
- if (!models.length) {
47217
- select.hidden = true;
47218
- return;
47219
- }
47220
- const placeholder = document.createElement("option");
47221
- placeholder.value = "";
47222
- placeholder.textContent = `Select a model (${models.length} available)`;
47223
- select.appendChild(placeholder);
47236
+ const list = this.ui.modelList;
47237
+ list.replaceChildren();
47224
47238
  for (const model of models) {
47225
47239
  const option = document.createElement("option");
47226
47240
  option.value = model;
47227
- option.textContent = model;
47228
- select.appendChild(option);
47241
+ list.appendChild(option);
47229
47242
  }
47230
- const current = this.ui.modelIdInput.value.trim();
47231
- select.value = models.includes(current) ? current : "";
47232
- select.hidden = false;
47233
47243
  }
47234
47244
  normalizeBaseUrl(baseUrl) {
47235
47245
  return baseUrl.trim().replace(/\/+$/, "");
@@ -47255,9 +47265,13 @@ ${markdown.trim()}`;
47255
47265
  switch (provider.id) {
47256
47266
  case "openai-responses":
47257
47267
  case "openai-chat":
47258
- return this.fetchOpenAiModels("https://api.openai.com/v1", apiKey);
47268
+ return this.fetchOpenAiModels("https://api.openai.com/v1", apiKey, true);
47259
47269
  case "openai-compatible":
47260
- return this.fetchOpenAiModels(this.normalizeBaseUrl(baseUrl), apiKey);
47270
+ return this.fetchOpenAiModels(
47271
+ this.normalizeBaseUrl(baseUrl),
47272
+ apiKey,
47273
+ false
47274
+ );
47261
47275
  case "anthropic":
47262
47276
  return this.fetchAnthropicModels(apiKey);
47263
47277
  case "google":
@@ -47284,11 +47298,36 @@ ${markdown.trim()}`;
47284
47298
  clearTimeout(timer);
47285
47299
  }
47286
47300
  }
47287
- async fetchOpenAiModels(baseUrl, apiKey) {
47301
+ async fetchOpenAiModels(baseUrl, apiKey, firstPartyOpenAi) {
47288
47302
  const json = await this.fetchModelJson(`${baseUrl}/models`, {
47289
47303
  headers: { Authorization: `Bearer ${apiKey}` }
47290
47304
  });
47291
- return (json.data ?? []).map((entry) => entry.id).filter((id2) => typeof id2 === "string" && id2.length > 0).sort();
47305
+ const ids = (json.data ?? []).map((entry) => entry.id).filter((id2) => typeof id2 === "string" && id2.length > 0);
47306
+ return this.filterChatModels(ids, firstPartyOpenAi).sort();
47307
+ }
47308
+ /**
47309
+ * Drop entries that are clearly not text chat models (embeddings, audio,
47310
+ * image, moderation) so the picker only offers models the agent can run. For
47311
+ * first-party OpenAI, also drop legacy completion families the chat/responses
47312
+ * API cannot drive. Custom endpoints keep their own naming, so the legacy
47313
+ * filter is not applied to them.
47314
+ */
47315
+ filterChatModels(ids, firstPartyOpenAi) {
47316
+ return ids.filter((id2) => {
47317
+ const lower = id2.toLowerCase();
47318
+ if (NON_CHAT_MODEL_MARKERS.some((marker) => lower.includes(marker))) {
47319
+ return false;
47320
+ }
47321
+ if (firstPartyOpenAi) {
47322
+ if (lower.endsWith("-instruct")) {
47323
+ return false;
47324
+ }
47325
+ if (OPENAI_LEGACY_MODEL_MARKERS.some((marker) => lower.includes(marker))) {
47326
+ return false;
47327
+ }
47328
+ }
47329
+ return true;
47330
+ });
47292
47331
  }
47293
47332
  async fetchAnthropicModels(apiKey) {
47294
47333
  const json = await this.fetchModelJson(
@@ -47337,7 +47376,7 @@ ${markdown.trim()}`;
47337
47376
  }
47338
47377
  async createProviderModel(providerId, modelId, apiKey, bedrockRegion, baseUrl) {
47339
47378
  if (providerId === "openai-responses" || providerId === "openai-chat") {
47340
- const { OpenAIModel } = await import("./index-BGu0d4ba.js");
47379
+ const { OpenAIModel } = await import("./index-CRfykVWh.js");
47341
47380
  return new OpenAIModel({
47342
47381
  api: providerId === "openai-responses" ? "responses" : "chat",
47343
47382
  modelId,
@@ -47348,7 +47387,7 @@ ${markdown.trim()}`;
47348
47387
  });
47349
47388
  }
47350
47389
  if (providerId === "openai-compatible") {
47351
- const { OpenAIModel } = await import("./index-BGu0d4ba.js");
47390
+ const { OpenAIModel } = await import("./index-CRfykVWh.js");
47352
47391
  return new OpenAIModel({
47353
47392
  api: "chat",
47354
47393
  modelId,
@@ -47360,7 +47399,7 @@ ${markdown.trim()}`;
47360
47399
  });
47361
47400
  }
47362
47401
  if (providerId === "anthropic") {
47363
- const { AnthropicModel } = await import("./anthropic-BmkKDa_y.js");
47402
+ const { AnthropicModel } = await import("./anthropic-DqtWmJMG.js");
47364
47403
  return new AnthropicModel({
47365
47404
  modelId,
47366
47405
  apiKey,
@@ -47370,7 +47409,7 @@ ${markdown.trim()}`;
47370
47409
  });
47371
47410
  }
47372
47411
  if (providerId === "google") {
47373
- const { GoogleModel } = await import("./index-DmwfExZ4.js");
47412
+ const { GoogleModel } = await import("./index-DnnohXIw.js");
47374
47413
  return new GoogleModel({
47375
47414
  modelId,
47376
47415
  apiKey
@@ -47578,7 +47617,11 @@ ${BROWSER_MAPLIBRE_CODE_SYSTEM_PROMPT}` : BROWSER_MAPLIBRE_SYSTEM_PROMPT;
47578
47617
  break;
47579
47618
  }
47580
47619
  }
47581
- }
47620
+ };
47621
+ // Unique per control instance so the model <input list> and its <datalist>
47622
+ // pair up even when several controls share a page.
47623
+ __publicField(_GeoAgentControl, "instanceCount", 0);
47624
+ let GeoAgentControl = _GeoAgentControl;
47582
47625
  export {
47583
47626
  ContextWindowOverflowError as C,
47584
47627
  DEFAULT_BASEMAPS as D,
@@ -47607,4 +47650,4 @@ export {
47607
47650
  toJsonValue as t,
47608
47651
  warnOnce as w
47609
47652
  };
47610
- //# sourceMappingURL=GeoAgentControl-CkSzEkxK.js.map
47653
+ //# sourceMappingURL=GeoAgentControl-BWSkl9b-.js.map