@skaile/forge-settings 1.4.0 → 2.0.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 (75) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +34 -11
  3. package/dist/module.json +1 -1
  4. package/dist/runtime/ai-sdk/index.d.ts +33 -26
  5. package/dist/runtime/ai-sdk/index.js +34 -16
  6. package/dist/runtime/components/ForgeProvidersPanel.d.vue.ts +2 -2
  7. package/dist/runtime/components/ForgeProvidersPanel.vue.d.ts +2 -2
  8. package/dist/runtime/editor/index.d.ts +55 -16
  9. package/dist/runtime/editor/index.js +82 -40
  10. package/dist/runtime/model/selector.d.ts +16 -0
  11. package/dist/runtime/model/selector.js +12 -0
  12. package/dist/runtime/server/credential-store.d.ts +16 -4
  13. package/dist/runtime/server/credential-store.js +3 -4
  14. package/dist/runtime/server/env-layers.d.ts +1 -1
  15. package/dist/runtime/server/env-layers.js +3 -3
  16. package/dist/runtime/server/index.d.ts +7 -8
  17. package/dist/runtime/server/index.js +1 -3
  18. package/dist/runtime/server/provider-discovery.d.ts +28 -8
  19. package/dist/runtime/server/provider-discovery.js +57 -33
  20. package/dist/runtime/server/provider-layers.d.ts +1 -1
  21. package/dist/runtime/server/provider-layers.js +3 -5
  22. package/dist/runtime/server/provider-service.d.ts +2 -2
  23. package/dist/runtime/server/provider-write.d.ts +1 -1
  24. package/dist/runtime/server/provider-write.js +3 -3
  25. package/dist/runtime/server/voice-provider.d.ts +61 -0
  26. package/dist/runtime/server/voice-provider.js +31 -0
  27. package/dist/runtime/shared/data-zone.d.ts +28 -26
  28. package/dist/runtime/shared/data-zone.js +4 -4
  29. package/dist/runtime/shared/harness-providers.d.ts +7 -7
  30. package/dist/runtime/shared/provider-accounts.d.ts +1 -1
  31. package/dist/runtime/shared/provider-registry.d.ts +19 -220
  32. package/dist/runtime/shared/provider-registry.js +25 -81
  33. package/dist/runtime/vue/providers-panel-model.d.ts +4 -4
  34. package/dist/runtime/{server → workspaces}/harness-settings.d.ts +3 -3
  35. package/dist/runtime/workspaces/index.d.ts +16 -0
  36. package/dist/runtime/workspaces/index.js +5 -0
  37. package/dist/runtime/workspaces/language-model.d.ts +45 -0
  38. package/dist/runtime/workspaces/language-model.js +26 -0
  39. package/dist/runtime/workspaces/model-endpoint.d.ts +38 -0
  40. package/dist/runtime/workspaces/model-endpoint.js +54 -0
  41. package/dist/runtime/workspaces/provider-settings.d.ts +35 -0
  42. package/dist/runtime/{server → workspaces}/provider-settings.js +0 -31
  43. package/dist/runtime/{server → workspaces}/settings-defaults.d.ts +1 -1
  44. package/dist/runtime/{shared → workspaces}/settings-types.d.ts +4 -4
  45. package/package.json +13 -4
  46. package/src/runtime/ai-sdk/index.ts +88 -47
  47. package/src/runtime/components/ForgeProvidersPanel.vue +2 -2
  48. package/src/runtime/editor/index.ts +158 -63
  49. package/src/runtime/model/selector.ts +31 -0
  50. package/src/runtime/server/credential-store.ts +20 -10
  51. package/src/runtime/server/env-layers.ts +4 -4
  52. package/src/runtime/server/index.ts +7 -8
  53. package/src/runtime/server/provider-discovery.ts +114 -48
  54. package/src/runtime/server/provider-layers.ts +6 -6
  55. package/src/runtime/server/provider-service.ts +2 -2
  56. package/src/runtime/server/provider-write.ts +3 -3
  57. package/src/runtime/server/voice-provider.ts +110 -0
  58. package/src/runtime/shared/data-zone.ts +40 -33
  59. package/src/runtime/shared/harness-providers.ts +7 -7
  60. package/src/runtime/shared/provider-accounts.ts +1 -1
  61. package/src/runtime/shared/provider-registry.ts +82 -314
  62. package/src/runtime/vue/providers-panel-model.ts +5 -5
  63. package/src/runtime/vue/useProvidersPanel.ts +5 -2
  64. package/src/runtime/{server → workspaces}/harness-settings.ts +3 -3
  65. package/src/runtime/workspaces/index.ts +17 -0
  66. package/src/runtime/workspaces/language-model.ts +82 -0
  67. package/src/runtime/workspaces/model-endpoint.ts +100 -0
  68. package/src/runtime/workspaces/provider-settings.ts +96 -0
  69. package/src/runtime/{server → workspaces}/settings-defaults.ts +1 -1
  70. package/src/runtime/{shared → workspaces}/settings-types.ts +4 -4
  71. package/dist/runtime/server/provider-settings.d.ts +0 -78
  72. package/src/runtime/server/provider-settings.ts +0 -192
  73. /package/dist/runtime/{server → workspaces}/harness-settings.js +0 -0
  74. /package/dist/runtime/{server → workspaces}/settings-defaults.js +0 -0
  75. /package/dist/runtime/{shared → workspaces}/settings-types.js +0 -0
@@ -9,15 +9,15 @@
9
9
  */
10
10
 
11
11
  import { existsSync, readFileSync } from "node:fs";
12
- import {
13
- type AIProviderRegistryPatch,
14
- PROVIDERS_FILENAME,
15
- saveProviderRegistryFile,
16
- } from "@skaile/workspaces/core";
17
- import { AI_PROVIDER_PRESETS, type AIProviderPreset } from "@skaile/workspaces/sdk/bridge";
12
+ import type { AIProviderRegistryPatch } from "@skaile/provider-registry";
13
+ import { AI_PROVIDER_PRESETS, type AIProviderPreset } from "@skaile/provider-registry/catalog";
14
+ import { saveProviderRegistryFile } from "@skaile/provider-registry/files";
18
15
  import { parse as parseYaml } from "yaml";
19
16
  import { isPlainObject } from "../shared/guards";
20
17
 
18
+ /** A layer document's file name, as every registry host spells it. */
19
+ const PROVIDERS_FILENAME = "providers.yml";
20
+
21
21
  /** The `.yaml` spelling of {@link PROVIDERS_FILENAME}. */
22
22
  const PROVIDERS_FILENAME_ALIAS = "providers.yaml";
23
23
 
@@ -23,12 +23,12 @@ import { entryDataZone } from "../shared/data-zone";
23
23
  import type {
24
24
  AIProviderCapabilities,
25
25
  AIProviderCredentialKind,
26
+ AIProviderDataZone,
26
27
  AIProviderKind,
27
28
  AIProviderRegistryView,
28
29
  AIProviderSurface,
29
30
  AIProviderTransport,
30
31
  AIProviderVoiceParams,
31
- DataZone,
32
32
  } from "../shared/provider-registry";
33
33
  import {
34
34
  entriesOfKind,
@@ -100,7 +100,7 @@ export interface ProviderInfo {
100
100
  /** Frozen by the control plane: a lower layer cannot change or disable it. */
101
101
  locked: boolean;
102
102
  /** Where the entry processes data: its `data_zone`, else its preset's, else `transfer`. */
103
- dataZone: DataZone;
103
+ dataZone: AIProviderDataZone;
104
104
  /** The entry's `eu_processing` switch (an `eu_option` entry counts as EU only with it on). */
105
105
  euProcessing: boolean;
106
106
  /**
@@ -28,17 +28,17 @@ import {
28
28
  type AIProviderRegistryLayer,
29
29
  type AIProviderRegistryPatch,
30
30
  isSafeProviderId,
31
- loadProviderRegistryFile,
32
31
  mergeRegistries,
33
32
  parseCredentialRef,
34
33
  validateMergedRegistry,
35
34
  validateRegistry,
36
- } from "@skaile/workspaces/core";
35
+ } from "@skaile/provider-registry";
37
36
  import {
38
37
  AI_PROVIDER_PRESETS,
39
38
  type AIProviderPreset,
40
39
  expandPreset,
41
- } from "@skaile/workspaces/sdk/bridge";
40
+ } from "@skaile/provider-registry/catalog";
41
+ import { loadProviderRegistryFile } from "@skaile/provider-registry/files";
42
42
  import { isDataZone } from "../shared/data-zone";
43
43
  import { isPlainObject } from "../shared/guards";
44
44
  import { missingRequiredParams } from "../shared/provider-accounts";
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Voice selection: which `kind: stt|tts` registry entry serves a request and
3
+ * with which parameters.
4
+ *
5
+ * `sttProvider`/`ttsProvider` are registry ids of `kind: stt|tts` entries; the
6
+ * endpoint and the voice parameters live on the entry, and
7
+ * `sttLanguage`/`ttsVoice` are per-request overrides of two of those
8
+ * parameters. Resolving all of that used to be three apps' worth of hardcoded
9
+ * endpoints and voice ids.
10
+ */
11
+
12
+ import type {
13
+ AIProviderRegistryView,
14
+ AIProviderVoiceEntry,
15
+ AIProviderVoiceKind,
16
+ AIProviderVoiceParams,
17
+ } from "../shared/provider-registry";
18
+ import {
19
+ entriesOfKind,
20
+ selectVoiceEntryId,
21
+ VOICE_OVERRIDE_PARAM,
22
+ } from "../shared/provider-registry";
23
+
24
+ /**
25
+ * Settings fields that name a voice entry and override its parameters — the
26
+ * same field names as the Workspaces `settings.json` document, so a
27
+ * `SkaileSettings` (`@skaile/forge-settings/workspaces`) can be passed as is.
28
+ */
29
+ export interface VoiceSettings {
30
+ /** Registry id of the `kind: stt` entry. */
31
+ sttProvider?: string;
32
+ /** Registry id of the `kind: tts` entry. */
33
+ ttsProvider?: string;
34
+ /** Overrides the stt entry's `language` parameter. */
35
+ sttLanguage?: string;
36
+ /** Overrides the tts entry's `voice_id` parameter. */
37
+ ttsVoice?: string;
38
+ }
39
+
40
+ /** The `kind: stt|tts` entry a request runs against, with its parameters resolved. */
41
+ export interface VoiceProviderSelection {
42
+ /** Registry id of the entry. */
43
+ providerId: string;
44
+ entry: AIProviderVoiceEntry;
45
+ /** Endpoint from the entry; absent when the entry inherits its preset's default. */
46
+ baseUrl?: string;
47
+ /**
48
+ * The entry's `params` with overrides applied — Deepgram `{model, language}`,
49
+ * ElevenLabs `{voice_id, output_format}`. This is the only place a forge app
50
+ * should read voice defaults from.
51
+ */
52
+ params: AIProviderVoiceParams;
53
+ /** True when settings named no usable entry and registry order decided. */
54
+ fallback: boolean;
55
+ /** Non-fatal notes, e.g. settings naming an entry the registry does not have. */
56
+ warnings: string[];
57
+ }
58
+
59
+ /**
60
+ * Resolve which registry entry serves speech-to-text or text-to-speech.
61
+ *
62
+ * Selection is `settings.sttProvider`/`settings.ttsProvider`, falling back to
63
+ * the first enabled entry of that kind in registry order when the setting is
64
+ * absent or names an entry that is gone — a missing setting must not silence an
65
+ * app that has a perfectly good entry configured.
66
+ *
67
+ * Parameter precedence, lowest first: the entry's `params`, then the settings
68
+ * overrides (`sttLanguage` → `language`, `ttsVoice` → `voice_id`), then
69
+ * `overrides` from the request. The per-request override is the contract
70
+ * forge-concept already honoured and the other apps silently dropped.
71
+ *
72
+ * @returns The selection, or `undefined` when the registry has no enabled entry
73
+ * of that kind.
74
+ */
75
+ export function resolveVoiceProvider(
76
+ registry: AIProviderRegistryView,
77
+ kind: AIProviderVoiceKind,
78
+ settings: VoiceSettings = {},
79
+ overrides: AIProviderVoiceParams = {},
80
+ ): VoiceProviderSelection | undefined {
81
+ const candidates = entriesOfKind(registry, kind);
82
+ if (candidates.length === 0) return undefined;
83
+
84
+ const warnings: string[] = [];
85
+ const wanted = (kind === "stt" ? settings.sttProvider : settings.ttsProvider)?.trim();
86
+ const ids = candidates.map(([id]) => id);
87
+ // `candidates` is non-empty, so the shared rule always names one of these ids.
88
+ const providerId = selectVoiceEntryId(ids, wanted) as string;
89
+ const entry = candidates[ids.indexOf(providerId)][1];
90
+ if (wanted && wanted !== providerId) {
91
+ warnings.push(
92
+ `settings name '${wanted}' for ${kind}, which is not an enabled ${kind} entry — ` +
93
+ `using '${providerId}' instead`,
94
+ );
95
+ }
96
+ const fallback = wanted !== providerId;
97
+
98
+ const settingsOverride: AIProviderVoiceParams = {};
99
+ const override = (kind === "stt" ? settings.sttLanguage : settings.ttsVoice)?.trim();
100
+ if (override) settingsOverride[VOICE_OVERRIDE_PARAM[kind]] = override;
101
+
102
+ return {
103
+ providerId,
104
+ entry,
105
+ ...(entry.base_url ? { baseUrl: entry.base_url } : {}),
106
+ params: { ...entry.params, ...settingsOverride, ...overrides },
107
+ fallback,
108
+ warnings,
109
+ };
110
+ }
@@ -2,34 +2,36 @@
2
2
  * Data zones: where a provider entry processes data, and which entries a
3
3
  * host's data-zone rule ("Where may AI process data?") keeps.
4
4
  *
5
- * `@skaile/workspaces` 9.1 owns this (`entryDataZone`,
6
- * `entryAllowedByDataZone`, `filterRegistryByDataZone` in
7
- * `bridge/src/provider-catalog.ts`, the `data_zone` of each catalog preset).
8
- * forge-settings mirrors it here so the settings panel and a host on an older
9
- * SDK apply the same rule in the browser and on the server. Semantics match
10
- * upstream exactly; {@link PRESET_DATA_ZONES} is a copy of the catalog's
11
- * column, and the SDK catalog is its source.
5
+ * `@skaile/provider-registry` owns the vocabulary (`AI_PROVIDER_DATA_ZONES`,
6
+ * `AI_PROVIDER_DATA_ZONE_RULES`, re-exported by `./provider-registry`) and the
7
+ * catalog's `data_zone` column with `entryDataZone`, `entryAllowedByDataZone`
8
+ * and `filterRegistryByDataZone` in its `/catalog` entry. forge-settings keeps
9
+ * the browser-side view here so the settings panel does not ship the catalog
10
+ * (and its generated model table) to the browser: the same semantics, plus
11
+ * labels, refusal wording and a filter that keeps a merged registry merged.
12
+ * {@link PRESET_DATA_ZONES} is a copy of the catalog's column; a test holds it
13
+ * equal to `@skaile/provider-registry/catalog`.
12
14
  *
13
15
  * Browser-safe on purpose — no `node:` imports.
14
16
  */
15
17
 
16
18
  import {
19
+ AI_PROVIDER_DATA_ZONE_RULES,
20
+ AI_PROVIDER_DATA_ZONES,
21
+ type AIProviderDataZone,
22
+ type AIProviderDataZoneRule,
17
23
  type AIProviderRegistry,
18
24
  type AIProviderRegistryView,
19
- DATA_ZONE_RULES,
20
- DATA_ZONES,
21
- type DataZone,
22
- type DataZoneRule,
23
25
  isMergedRegistry,
24
26
  type MergedAIProviderRegistry,
25
27
  } from "./provider-registry";
26
28
 
27
29
  /**
28
30
  * The `data_zone` of each catalog preset, by preset id. Copied from
29
- * `@skaile/workspaces/bridge`'s `AI_PROVIDER_PRESETS` (9.1); change it there
31
+ * `@skaile/provider-registry/catalog`'s `AI_PROVIDER_PRESETS`; change it there
30
32
  * first. A preset this table does not name is `transfer`.
31
33
  */
32
- export const PRESET_DATA_ZONES: Readonly<Record<string, DataZone>> = {
34
+ export const PRESET_DATA_ZONES: Readonly<Record<string, AIProviderDataZone>> = {
33
35
  anthropic: "transfer",
34
36
  openai: "transfer",
35
37
  google: "transfer",
@@ -53,7 +55,7 @@ export const PRESET_DATA_ZONES: Readonly<Record<string, DataZone>> = {
53
55
  };
54
56
 
55
57
  /** What a provider row's zone chip says. */
56
- export const DATA_ZONE_LABELS: Readonly<Record<DataZone, string>> = {
58
+ export const DATA_ZONE_LABELS: Readonly<Record<AIProviderDataZone, string>> = {
57
59
  eu: "EU",
58
60
  eu_option: "EU option",
59
61
  transfer: "Transfer",
@@ -61,24 +63,26 @@ export const DATA_ZONE_LABELS: Readonly<Record<DataZone, string>> = {
61
63
  };
62
64
 
63
65
  /** What a host calls each rule when it names the rule that keeps an entry out. */
64
- export const DATA_ZONE_RULE_LABELS: Readonly<Record<DataZoneRule, string>> = {
66
+ export const DATA_ZONE_RULE_LABELS: Readonly<Record<AIProviderDataZoneRule, string>> = {
65
67
  any: "Anywhere",
66
68
  eu_options: "EU, or EU option with EU processing on",
67
69
  eu: "EU only",
68
70
  };
69
71
 
70
- /** Whether `value` is one of {@link DATA_ZONES}. */
71
- export function isDataZone(value: unknown): value is DataZone {
72
- return typeof value === "string" && (DATA_ZONES as readonly string[]).includes(value);
72
+ /** Whether `value` is one of `AI_PROVIDER_DATA_ZONES`. */
73
+ export function isDataZone(value: unknown): value is AIProviderDataZone {
74
+ return typeof value === "string" && (AI_PROVIDER_DATA_ZONES as readonly string[]).includes(value);
73
75
  }
74
76
 
75
- /** Whether `value` is one of {@link DATA_ZONE_RULES}. */
76
- export function isDataZoneRule(value: unknown): value is DataZoneRule {
77
- return typeof value === "string" && (DATA_ZONE_RULES as readonly string[]).includes(value);
77
+ /** Whether `value` is one of `AI_PROVIDER_DATA_ZONE_RULES`. */
78
+ export function isDataZoneRule(value: unknown): value is AIProviderDataZoneRule {
79
+ return (
80
+ typeof value === "string" && (AI_PROVIDER_DATA_ZONE_RULES as readonly string[]).includes(value)
81
+ );
78
82
  }
79
83
 
80
84
  /** The zone of catalog preset `presetId`, or `undefined` for an id the catalog does not name. */
81
- export function presetDataZone(presetId: string | undefined): DataZone | undefined {
85
+ export function presetDataZone(presetId: string | undefined): AIProviderDataZone | undefined {
82
86
  return presetId !== undefined && Object.hasOwn(PRESET_DATA_ZONES, presetId)
83
87
  ? PRESET_DATA_ZONES[presetId]
84
88
  : undefined;
@@ -89,7 +93,10 @@ export function presetDataZone(presetId: string | undefined): DataZone | undefin
89
93
  * catalog preset it names, else `transfer` (an unknown endpoint is assumed to
90
94
  * leave the EU).
91
95
  */
92
- export function entryDataZone(entry: { data_zone?: DataZone; preset?: string }): DataZone {
96
+ export function entryDataZone(entry: {
97
+ data_zone?: AIProviderDataZone;
98
+ preset?: string;
99
+ }): AIProviderDataZone {
93
100
  return entry.data_zone ?? presetDataZone(entry.preset) ?? "transfer";
94
101
  }
95
102
 
@@ -99,8 +106,8 @@ export function entryDataZone(entry: { data_zone?: DataZone; preset?: string }):
99
106
  * `euProcessing` is `true`.
100
107
  */
101
108
  export function dataZoneAllows(
102
- rule: DataZoneRule,
103
- zone: DataZone,
109
+ rule: AIProviderDataZoneRule,
110
+ zone: AIProviderDataZone,
104
111
  euProcessing: boolean | undefined,
105
112
  ): boolean {
106
113
  if (rule === "any") return true;
@@ -110,8 +117,8 @@ export function dataZoneAllows(
110
117
 
111
118
  /** Whether `rule` allows `entry` ({@link dataZoneAllows} over {@link entryDataZone}). */
112
119
  export function entryAllowedByDataZone(
113
- entry: { data_zone?: DataZone; preset?: string; eu_processing?: boolean },
114
- rule: DataZoneRule,
120
+ entry: { data_zone?: AIProviderDataZone; preset?: string; eu_processing?: boolean },
121
+ rule: AIProviderDataZoneRule,
115
122
  ): boolean {
116
123
  return dataZoneAllows(rule, entryDataZone(entry), entry.eu_processing);
117
124
  }
@@ -121,8 +128,8 @@ export function entryAllowedByDataZone(
121
128
  * when the rule allows it. Secret-free, safe to render.
122
129
  */
123
130
  export function dataZoneRefusal(
124
- rule: DataZoneRule,
125
- zone: DataZone,
131
+ rule: AIProviderDataZoneRule,
132
+ zone: AIProviderDataZone,
126
133
  euProcessing: boolean | undefined,
127
134
  ): string | undefined {
128
135
  if (dataZoneAllows(rule, zone, euProcessing)) return undefined;
@@ -141,19 +148,19 @@ export function dataZoneRefusal(
141
148
  */
142
149
  export function filterRegistryByDataZone(
143
150
  registry: AIProviderRegistry,
144
- rule: DataZoneRule,
151
+ rule: AIProviderDataZoneRule,
145
152
  ): AIProviderRegistry;
146
153
  export function filterRegistryByDataZone(
147
154
  registry: MergedAIProviderRegistry,
148
- rule: DataZoneRule,
155
+ rule: AIProviderDataZoneRule,
149
156
  ): MergedAIProviderRegistry;
150
157
  export function filterRegistryByDataZone(
151
158
  registry: AIProviderRegistryView,
152
- rule: DataZoneRule,
159
+ rule: AIProviderDataZoneRule,
153
160
  ): AIProviderRegistryView;
154
161
  export function filterRegistryByDataZone(
155
162
  registry: AIProviderRegistryView,
156
- rule: DataZoneRule,
163
+ rule: AIProviderDataZoneRule,
157
164
  ): AIProviderRegistryView {
158
165
  const entries = isMergedRegistry(registry) ? registry.providers : registry;
159
166
  const providers: AIProviderRegistry = {};
@@ -15,9 +15,9 @@
15
15
  */
16
16
 
17
17
  import { DATA_ZONE_RULE_LABELS, dataZoneRefusal, presetDataZone } from "./data-zone";
18
- import type { DataZone, DataZoneRule } from "./provider-registry";
18
+ import type { AIProviderDataZone, AIProviderDataZoneRule } from "./provider-registry";
19
19
 
20
- /** How many registry entries a harness can run at once (`@skaile/workspaces` `HarnessInfo.providerPlurality`). */
20
+ /** How many registry entries a harness can run at once (`HarnessInfo.providerPlurality` of a Workspaces harness). */
21
21
  export type HarnessProviderPlurality = "registry" | "credentials-n" | "single";
22
22
 
23
23
  /** The slice of a harness the rule reads. `GET /api/agents` rows satisfy it. */
@@ -41,7 +41,7 @@ export interface HarnessProviderCandidate {
41
41
  /** Catalog preset; gives the zone when {@link dataZone} is absent. */
42
42
  preset?: string;
43
43
  /** Effective data zone (`GET /api/providers` rows carry it). Absent: the preset's, else `transfer`. */
44
- dataZone?: DataZone;
44
+ dataZone?: AIProviderDataZone;
45
45
  /** The account's EU-processing setting is on. */
46
46
  euProcessing?: boolean;
47
47
  }
@@ -54,11 +54,11 @@ export interface HarnessProviderBlock {
54
54
  id: string;
55
55
  reason: HarnessProviderBlockReason;
56
56
  /** The rule in force. */
57
- rule: DataZoneRule;
57
+ rule: AIProviderDataZoneRule;
58
58
  /** The rule's label ("EU only"). */
59
59
  ruleLabel: string;
60
60
  /** The entry's effective zone. */
61
- zone: DataZone;
61
+ zone: AIProviderDataZone;
62
62
  /** What a settings table shows on the box it cannot tick. Secret-free. */
63
63
  message: string;
64
64
  }
@@ -66,7 +66,7 @@ export interface HarnessProviderBlock {
66
66
  /** What {@link resolveHarnessProviders} applies beyond the surface rule. */
67
67
  export interface HarnessProviderOptions {
68
68
  /** The host's data-zone rule. Absent: `any`. */
69
- dataZoneRule?: DataZoneRule;
69
+ dataZoneRule?: AIProviderDataZoneRule;
70
70
  }
71
71
 
72
72
  /**
@@ -114,7 +114,7 @@ export function isProviderEligibleForHarness(
114
114
  export function harnessProviderBlock(
115
115
  harness: HarnessProviderInfo,
116
116
  candidate: HarnessProviderCandidate,
117
- rule: DataZoneRule | undefined,
117
+ rule: AIProviderDataZoneRule | undefined,
118
118
  ): HarnessProviderBlock | undefined {
119
119
  if (!rule || rule === "any" || !isProviderEligibleForHarness(harness, candidate)) {
120
120
  return undefined;
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * Pure and browser-safe: the settings panel and the server's write gate read
8
8
  * the same rules. The facts come from the catalog preset
9
- * (`@skaile/workspaces`' `AIProviderPreset`): its `credential.kind`, its
9
+ * (`@skaile/provider-registry/catalog`'s `AIProviderPreset`): its `credential.kind`, its
10
10
  * `transport`, its default `params` and its `required_params`. The catalog
11
11
  * names no list of accepted sign-in kinds, so they are derived here from those
12
12
  * facts.