dsh-github-copilot 0.4.0-alpha.22 → 0.4.0-alpha.24

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/lib/client.js CHANGED
@@ -5399,7 +5399,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5399
5399
  expectedRevision: revision
5400
5400
  }).strict();
5401
5401
  const DualModelCreateResultSchema = object({ sessionId: id }).strict();
5402
- const contribution$1 = {
5402
+ const contribution$2 = {
5403
5403
  package: "dsh-github-copilot",
5404
5404
  descriptors: [
5405
5405
  {
@@ -5462,6 +5462,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5462
5462
  ]
5463
5463
  };
5464
5464
  //#endregion
5465
+ //#region lib/types/search-routing-remote.js
5466
+ const SearchProviderCatalogSchema = object({
5467
+ supported: boolean(),
5468
+ providers: array(object({ id: string().min(1).max(512) }).strict()).max(512)
5469
+ }).strict();
5470
+ const contribution$1 = {
5471
+ package: "dsh-github-copilot",
5472
+ descriptors: [{
5473
+ id: "dsh-github-copilot:githubCopilotSearchRouting.providers",
5474
+ namespace: "githubCopilotSearchRouting",
5475
+ service: "githubCopilotSearchRouting",
5476
+ method: "providers",
5477
+ invocation: { kind: "direct" },
5478
+ parameters: [],
5479
+ result: {
5480
+ mode: "strict",
5481
+ typeSymbol: "dsh-github-copilot#SearchProviderCatalog",
5482
+ schema: SearchProviderCatalogSchema
5483
+ }
5484
+ }]
5485
+ };
5486
+ //#endregion
5465
5487
  //#region lib/types/remote.js
5466
5488
  /**
5467
5489
  * Client-safe Remote contribution for the plugin-owned authorization bridge.
@@ -5622,6 +5644,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5622
5644
  schema: GitHubCopilotMigrationStatusSchema
5623
5645
  }
5624
5646
  },
5647
+ ...contribution$2.descriptors,
5625
5648
  ...contribution$1.descriptors
5626
5649
  ]
5627
5650
  };
@@ -5880,29 +5903,43 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5880
5903
  };
5881
5904
  }
5882
5905
  //#endregion
5906
+ //#region lib/types/search-routing-policy.js
5907
+ /** Resolve old and new settings without guessing registered providers or dropping unknown ids. */
5908
+ function normalizeWebSearchRouting(config) {
5909
+ const defaultProvider = config.defaultSearchProvider?.trim() || "deepseek-official";
5910
+ const legacy = config.searchProvider === void 0;
5911
+ return {
5912
+ primaryProvider: legacy ? config.searchMode === "fixed" ? defaultProvider : "auto" : config.searchProvider?.trim() || "auto",
5913
+ defaultProvider,
5914
+ legacy
5915
+ };
5916
+ }
5917
+ //#endregion
5883
5918
  //#region lib/types/web-search-routing-card.js
5884
5919
  const GITHUB_COPILOT_SETTINGS_NAMESPACE = "github-copilot";
5885
5920
  const WEB_SEARCH_ROUTING_SETTINGS_NAMESPACE = "github-copilot-search-routing";
5886
5921
  const NO_DEFAULT_SEARCH_PROVIDER = "none";
5887
5922
  const GITHUB_COPILOT_SEARCH_PROVIDER = "github-copilot-hosted";
5888
5923
  const DEEPSEEK_SEARCH_PROVIDER = "deepseek-official";
5889
- const EXA_SEARCH_PROVIDER = "exa";
5890
- const PERPLEXITY_SEARCH_PROVIDER = "perplexity";
5891
5924
  const cardStyle$1 = {
5892
5925
  display: "grid",
5893
5926
  gap: "14px",
5894
5927
  padding: "18px",
5895
5928
  marginTop: "16px",
5929
+ minWidth: 0,
5896
5930
  border: "1px solid color-mix(in srgb, currentColor 20%, transparent)",
5897
5931
  borderRadius: "14px",
5898
5932
  background: "color-mix(in srgb, currentColor 4%, transparent)"
5899
5933
  };
5900
5934
  const fieldStyle$1 = {
5901
5935
  display: "grid",
5902
- gap: "6px"
5936
+ gap: "6px",
5937
+ minWidth: 0
5903
5938
  };
5904
5939
  const controlStyle$1 = {
5905
5940
  width: "100%",
5941
+ minWidth: 0,
5942
+ boxSizing: "border-box",
5906
5943
  padding: "9px 11px",
5907
5944
  borderRadius: "9px",
5908
5945
  color: "inherit",
@@ -5920,20 +5957,29 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5920
5957
  color: "inherit",
5921
5958
  font: "inherit"
5922
5959
  };
5960
+ const hintStyle = {
5961
+ opacity: .8,
5962
+ fontSize: "12px",
5963
+ lineHeight: 1.5,
5964
+ overflowWrap: "anywhere"
5965
+ };
5923
5966
  function record(value) {
5924
5967
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
5925
5968
  }
5926
5969
  function revisionOf(value) {
5927
5970
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
5928
5971
  }
5929
- /** Models-page card for plugin-owned cross-provider search routing. */
5972
+ /** Provider-level primary and final fallback; model choice stays with each provider. */
5930
5973
  function WebSearchRoutingCard(props) {
5931
5974
  const [draft, setDraft] = (0, react.useState)({
5932
- mode: "auto",
5975
+ primary: "auto",
5933
5976
  provider: DEEPSEEK_SEARCH_PROVIDER,
5934
- model: ""
5977
+ model: "",
5978
+ legacy: true
5935
5979
  });
5936
5980
  const [models, setModels] = (0, react.useState)([]);
5981
+ const [providers, setProviders] = (0, react.useState)([]);
5982
+ const [catalogReady, setCatalogReady] = (0, react.useState)(false);
5937
5983
  const [loading, setLoading] = (0, react.useState)(true);
5938
5984
  const [saving, setSaving] = (0, react.useState)(false);
5939
5985
  const [writable, setWritable] = (0, react.useState)(false);
@@ -5953,8 +5999,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5953
5999
  setLoading(true);
5954
6000
  setSaving(false);
5955
6001
  setWritable(false);
6002
+ setCatalogReady(false);
5956
6003
  setMessage("");
5957
6004
  setModels([]);
6005
+ setProviders([]);
5958
6006
  setModelNotice("");
5959
6007
  const loadModels = async () => {
5960
6008
  try {
@@ -5973,7 +6021,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5973
6021
  };
5974
6022
  loadModels();
5975
6023
  try {
5976
- const result = await props.settings.describe();
6024
+ const [result, catalog] = await Promise.all([props.settings.describe(), Promise.resolve().then(() => props.routing.providers()).catch(() => void 0)]);
5977
6025
  if (!current()) return;
5978
6026
  if (!result.ok) {
5979
6027
  setMessage("Could not load search settings. Reload settings to retry.");
@@ -5981,27 +6029,47 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5981
6029
  }
5982
6030
  const routing = result.value.namespaces.find((entry) => entry.ns === WEB_SEARCH_ROUTING_SETTINGS_NAMESPACE);
5983
6031
  const copilot = result.value.namespaces.find((entry) => entry.ns === GITHUB_COPILOT_SETTINGS_NAMESPACE);
5984
- const routingValue = record(routing?.value);
5985
- const copilotValue = record(copilot?.value);
6032
+ const routingValue = record(routing?.value), copilotValue = record(copilot?.value);
6033
+ const normalized = normalizeWebSearchRouting({
6034
+ searchProvider: typeof routingValue.searchProvider === "string" ? routingValue.searchProvider : void 0,
6035
+ searchMode: routingValue.searchMode === "fixed" ? "fixed" : "auto",
6036
+ defaultSearchProvider: typeof routingValue.defaultSearchProvider === "string" ? routingValue.defaultSearchProvider : void 0
6037
+ });
5986
6038
  setDraft({
5987
- mode: routingValue.searchMode === "fixed" ? "fixed" : "auto",
5988
- provider: typeof routingValue.defaultSearchProvider === "string" ? routingValue.defaultSearchProvider : DEEPSEEK_SEARCH_PROVIDER,
6039
+ primary: normalized.primaryProvider,
6040
+ provider: normalized.defaultProvider,
6041
+ legacy: normalized.legacy,
5989
6042
  model: typeof copilotValue.searchModel === "string" ? copilotValue.searchModel : "",
5990
6043
  routingRevision: revisionOf(routing?.revision),
5991
6044
  copilotRevision: revisionOf(copilot?.revision)
5992
6045
  });
6046
+ const parsed = catalog?.ok ? SearchProviderCatalogSchema.safeParse(catalog.value) : void 0;
6047
+ const ids = parsed?.success ? parsed.data.providers.map((entry) => entry.id) : [];
6048
+ if (!parsed?.success || !parsed.data.supported || new Set(ids).size !== ids.length || ids.includes("auto") || ids.includes("none")) {
6049
+ setMessage("Search provider list is unavailable. Reload after the routed search service is active.");
6050
+ return;
6051
+ }
6052
+ setProviders(ids.toSorted());
6053
+ setCatalogReady(true);
5993
6054
  setWritable(result.value.writable === true);
5994
6055
  if (!routing || revisionOf(routing.revision) === void 0) setMessage("Web search routing settings are unavailable. Reload after the routing namespace is registered.");
5995
6056
  else if (!result.value.writable) setMessage("Search settings are read-only in this deployment.");
5996
6057
  } catch {
5997
- if (current()) setMessage("Could not load search settings. Reload settings to retry.");
6058
+ setMessageIfCurrent("Could not load search settings. Reload settings to retry.");
5998
6059
  } finally {
5999
6060
  if (current()) {
6000
6061
  owner.busy = false;
6001
6062
  setLoading(false);
6002
6063
  }
6003
6064
  }
6004
- }, [props.copilot, props.settings]);
6065
+ function setMessageIfCurrent(value) {
6066
+ if (current()) setMessage(value);
6067
+ }
6068
+ }, [
6069
+ props.copilot,
6070
+ props.settings,
6071
+ props.routing
6072
+ ]);
6005
6073
  (0, react.useEffect)(() => {
6006
6074
  const owner = lifecycle.current;
6007
6075
  owner.active = true;
@@ -6012,27 +6080,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6012
6080
  owner.busy = false;
6013
6081
  };
6014
6082
  }, [load]);
6015
- const usesCopilot = draft.provider.trim() === GITHUB_COPILOT_SEARCH_PROVIDER;
6016
- const disabled = loading || saving || !writable || draft.routingRevision === void 0;
6083
+ const usesCopilot = draft.primary === GITHUB_COPILOT_SEARCH_PROVIDER || draft.provider === GITHUB_COPILOT_SEARCH_PROVIDER;
6084
+ const disabled = loading || saving || !writable || draft.routingRevision === void 0 || !catalogReady;
6017
6085
  const missingCopilot = usesCopilot && draft.copilotRevision === void 0;
6018
- const providerOptions = [
6019
- DEEPSEEK_SEARCH_PROVIDER,
6020
- GITHUB_COPILOT_SEARCH_PROVIDER,
6021
- EXA_SEARCH_PROVIDER,
6022
- PERPLEXITY_SEARCH_PROVIDER,
6023
- NO_DEFAULT_SEARCH_PROVIDER
6024
- ];
6086
+ const primaryKnown = draft.primary === "auto" || draft.primary === "none" || providers.includes(draft.primary);
6087
+ const fallbackKnown = draft.provider === "none" || providers.includes(draft.provider);
6088
+ const missingProvider = !primaryKnown || !fallbackKnown;
6025
6089
  const save = (0, react.useCallback)(async () => {
6026
6090
  const owner = lifecycle.current;
6027
6091
  if (!owner.active || owner.busy || disabled || missingCopilot) return;
6028
- const generation = owner.generation;
6029
- const current = () => owner.active && owner.generation === generation;
6030
- const provider = draft.provider.trim();
6031
- const model = draft.model.trim();
6032
- if (provider.length === 0) {
6033
- setMessage("Enter a registered search provider id, or use none.");
6092
+ if (missingProvider) {
6093
+ setMessage("Choose a registered search provider, or disable the fallback with None.");
6034
6094
  return;
6035
6095
  }
6096
+ const generation = owner.generation;
6097
+ const current = () => owner.active && owner.generation === generation;
6098
+ const provider = draft.provider, primary = draft.primary, model = draft.model.trim();
6036
6099
  if (usesCopilot && model.length === 0) {
6037
6100
  setMessage("Enter a Copilot Responses model before using GitHub Copilot search.");
6038
6101
  return;
@@ -6068,8 +6131,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6068
6131
  }
6069
6132
  const routingWrite = await props.settings.mutate(WEB_SEARCH_ROUTING_SETTINGS_NAMESPACE, [{
6070
6133
  op: "set",
6071
- path: ["searchMode"],
6072
- value: draft.mode
6134
+ path: ["searchProvider"],
6135
+ value: primary
6073
6136
  }, {
6074
6137
  op: "set",
6075
6138
  path: ["defaultSearchProvider"],
@@ -6083,8 +6146,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6083
6146
  const revision = revisionOf(routingWrite.value.revision);
6084
6147
  setDraft((value) => current() ? {
6085
6148
  ...value,
6149
+ primary,
6086
6150
  provider,
6087
- routingRevision: revision
6151
+ routingRevision: revision,
6152
+ legacy: false
6088
6153
  } : value);
6089
6154
  setMessage(revision === void 0 ? "Save returned no revision. Reload settings before editing again." : "Saved. New searches use this routing immediately.");
6090
6155
  } catch {
@@ -6099,9 +6164,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6099
6164
  disabled,
6100
6165
  draft,
6101
6166
  missingCopilot,
6167
+ missingProvider,
6102
6168
  props.settings,
6103
6169
  usesCopilot
6104
6170
  ]);
6171
+ const providerOptions = () => providers.map((id) => (0, react.createElement)("option", {
6172
+ key: id,
6173
+ value: id
6174
+ }, id));
6175
+ const unavailableOption = (id, known) => known ? null : (0, react.createElement)("option", {
6176
+ value: id,
6177
+ disabled: true
6178
+ }, `${id || "(empty)"} — unavailable`);
6105
6179
  return (0, react.createElement)("section", {
6106
6180
  style: cardStyle$1,
6107
6181
  "data-dsh-web-search-routing": true
@@ -6110,33 +6184,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6110
6184
  fontSize: "16px"
6111
6185
  } }, "Web search"), (0, react.createElement)("p", { style: {
6112
6186
  margin: "5px 0 0",
6113
- opacity: .72,
6187
+ opacity: .8,
6114
6188
  fontSize: "13px",
6115
6189
  lineHeight: 1.5
6116
- } }, "Auto tries native search for the initiating Copilot model, then the default provider when unavailable. Other model providers use the default directly. Fixed always uses the default. Chat remains available when search is unavailable.")), (0, react.createElement)("label", { style: fieldStyle$1 }, (0, react.createElement)("span", { style: {
6190
+ } }, "Auto follows the Chat provider when a matching search provider exists. Choose a provider to keep search fixed, independently of Chat.")), (0, react.createElement)("label", { style: fieldStyle$1 }, (0, react.createElement)("span", { style: {
6117
6191
  fontSize: "13px",
6118
6192
  fontWeight: 600
6119
- } }, "Search mode"), (0, react.createElement)("select", {
6193
+ } }, "Search provider"), (0, react.createElement)("select", {
6120
6194
  style: controlStyle$1,
6121
6195
  disabled,
6122
- value: draft.mode,
6196
+ value: draft.primary,
6123
6197
  "data-dsh-web-search-mode": true,
6124
6198
  onChange: (event) => {
6125
- const mode = event.currentTarget.value === "fixed" ? "fixed" : "auto";
6199
+ const primary = event.currentTarget.value;
6126
6200
  setDraft((current) => ({
6127
6201
  ...current,
6128
- mode
6202
+ primary
6129
6203
  }));
6130
6204
  }
6131
- }, (0, react.createElement)("option", { value: "auto" }, "Auto — native Copilot search first, then default provider"), (0, react.createElement)("option", { value: "fixed" }, "Fixedalways use the default provider"))), (0, react.createElement)("label", { style: fieldStyle$1 }, (0, react.createElement)("span", { style: {
6205
+ }, (0, react.createElement)("option", { value: "auto" }, "Auto — follow Chat"), draft.primary === "none" ? (0, react.createElement)("option", { value: "none" }, "Disabledsaved configuration") : null, ...providerOptions(), unavailableOption(draft.primary, primaryKnown))), (0, react.createElement)("label", { style: fieldStyle$1 }, (0, react.createElement)("span", { style: {
6132
6206
  fontSize: "13px",
6133
6207
  fontWeight: 600
6134
- } }, "Default search provider"), (0, react.createElement)("input", {
6208
+ } }, "Default search provider"), (0, react.createElement)("select", {
6135
6209
  style: controlStyle$1,
6136
- list: "dsh-search-provider-options",
6137
6210
  disabled,
6138
6211
  value: draft.provider,
6139
- placeholder: "registered provider id",
6140
6212
  "data-dsh-web-search-provider": true,
6141
6213
  onChange: (event) => {
6142
6214
  const provider = event.currentTarget.value;
@@ -6145,14 +6217,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6145
6217
  provider
6146
6218
  }));
6147
6219
  }
6148
- }), (0, react.createElement)("datalist", { id: "dsh-search-provider-options" }, ...providerOptions.map((id) => (0, react.createElement)("option", {
6149
- key: id,
6150
- value: id,
6151
- label: id === NO_DEFAULT_SEARCH_PROVIDER ? "None no default search provider" : `${id} (suggestion)`
6152
- }))), (0, react.createElement)("span", { style: {
6153
- opacity: .66,
6154
- fontSize: "12px"
6155
- } }, "Suggestions are examples, not installed-provider or capability checks. Enter any registered search provider id, or none; unavailable providers fail without affecting chat.")), !usesCopilot ? null : (0, react.createElement)("label", { style: fieldStyle$1 }, (0, react.createElement)("span", { style: {
6220
+ }, (0, react.createElement)("option", { value: NO_DEFAULT_SEARCH_PROVIDER }, "None — no fallback"), ...providerOptions(), unavailableOption(draft.provider, fallbackKnown)), (0, react.createElement)("span", { style: hintStyle }, "Final fallback only: used when Auto has no matching provider or the primary search fails. The same provider is never retried as its own fallback.")), catalogReady && providers.length === 0 ? (0, react.createElement)("p", {
6221
+ role: "status",
6222
+ style: hintStyle
6223
+ }, "No search providers are registered. Enable a search provider, then reload settings.") : null, catalogReady && missingProvider ? (0, react.createElement)("p", {
6224
+ role: "status",
6225
+ style: hintStyle
6226
+ }, "A saved provider is no longer registered. Choose an available entry; it has not been replaced automatically.") : null, draft.legacy && catalogReady ? (0, react.createElement)("p", { style: hintStyle }, "Your existing choices are preserved. Saving adopts the selected Default as the final fallback, which may incur that provider’s API charges. Cancellation and captured account-proof invalidation never trigger fallback.") : null, !usesCopilot ? null : (0, react.createElement)("label", { style: fieldStyle$1 }, (0, react.createElement)("span", { style: {
6156
6227
  fontSize: "13px",
6157
6228
  fontWeight: 600
6158
6229
  } }, "Copilot search model"), (0, react.createElement)("input", {
@@ -6172,12 +6243,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6172
6243
  }), (0, react.createElement)("datalist", { id: "dsh-copilot-search-models" }, ...models.map((id) => (0, react.createElement)("option", {
6173
6244
  key: id,
6174
6245
  value: id
6175
- }))), (0, react.createElement)("span", { style: {
6176
- opacity: .66,
6177
- fontSize: "12px"
6178
- } }, "Account Responses models are suggestions, not hosted-search capability proof. The model must be account-authorized and pass the configured search checks. It does not change the chat model."), missingCopilot ? (0, react.createElement)("span", { role: "status" }, "Copilot search settings are unavailable. Reload after the github-copilot namespace is registered, or choose another provider.") : null, modelNotice ? (0, react.createElement)("span", {
6246
+ }))), (0, react.createElement)("span", { style: hintStyle }, "Used when Copilot is selected explicitly or as the fallback. Account Responses models are suggestions, not hosted-search capability proof. This does not change the Chat model."), missingCopilot ? (0, react.createElement)("span", { role: "status" }, "Copilot search settings are unavailable. Reload after the github-copilot namespace is registered, or choose another provider.") : null, modelNotice ? (0, react.createElement)("span", {
6179
6247
  role: "status",
6180
- style: { fontSize: "12px" }
6248
+ style: hintStyle
6181
6249
  }, modelNotice) : null), (0, react.createElement)("div", { style: {
6182
6250
  display: "flex",
6183
6251
  alignItems: "center",
@@ -6186,7 +6254,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6186
6254
  } }, (0, react.createElement)("button", {
6187
6255
  type: "button",
6188
6256
  style: buttonStyle$1,
6189
- disabled: disabled || missingCopilot,
6257
+ disabled: disabled || missingCopilot || missingProvider,
6190
6258
  "data-dsh-web-search-save": true,
6191
6259
  onClick: () => {
6192
6260
  save();
@@ -6202,10 +6270,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6202
6270
  }
6203
6271
  }, "Reload settings"), message.length === 0 ? null : (0, react.createElement)("span", {
6204
6272
  role: "status",
6205
- style: {
6206
- fontSize: "13px",
6207
- opacity: .8
6208
- }
6273
+ style: hintStyle
6209
6274
  }, message)));
6210
6275
  }
6211
6276
  //#endregion
@@ -7713,7 +7778,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7713
7778
  let fallback;
7714
7779
  const render = () => (0, react.createElement)(WebSearchRoutingCard, {
7715
7780
  settings: ctx.remote.settings,
7716
- copilot: ctx.remote.githubCopilot
7781
+ copilot: ctx.remote.githubCopilot,
7782
+ routing: ctx.remote.githubCopilotSearchRouting
7717
7783
  });
7718
7784
  const syncFallback = () => {
7719
7785
  if (active && sectionActive && !footerActive) fallback ??= ctx.slots.register({
@@ -7786,6 +7852,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7786
7852
  const searchUi = ctx.inject([
7787
7853
  "remote.githubCopilot",
7788
7854
  "remote.settings",
7855
+ "remote.githubCopilotSearchRouting",
7789
7856
  "slots"
7790
7857
  ], registerSearchUi);
7791
7858
  const dualModelUi = ctx.inject(["remote.githubCopilotDualModel", "slots"], registerDualModelUi);