@skaile/forge-settings 1.3.3 → 2.0.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +52 -9
  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 +13 -0
  7. package/dist/runtime/components/ForgeProvidersPanel.vue +461 -78
  8. package/dist/runtime/components/ForgeProvidersPanel.vue.d.ts +13 -0
  9. package/dist/runtime/editor/index.d.ts +55 -16
  10. package/dist/runtime/editor/index.js +82 -40
  11. package/dist/runtime/model/selector.d.ts +16 -0
  12. package/dist/runtime/model/selector.js +12 -0
  13. package/dist/runtime/server/credential-store.d.ts +16 -4
  14. package/dist/runtime/server/credential-store.js +3 -4
  15. package/dist/runtime/server/env-layers.d.ts +1 -1
  16. package/dist/runtime/server/env-layers.js +3 -3
  17. package/dist/runtime/server/index.d.ts +9 -8
  18. package/dist/runtime/server/index.js +3 -3
  19. package/dist/runtime/server/provider-discovery.d.ts +28 -8
  20. package/dist/runtime/server/provider-discovery.js +57 -33
  21. package/dist/runtime/server/provider-layers.d.ts +1 -1
  22. package/dist/runtime/server/provider-layers.js +3 -5
  23. package/dist/runtime/server/provider-service.d.ts +26 -2
  24. package/dist/runtime/server/provider-service.js +16 -1
  25. package/dist/runtime/server/provider-write.d.ts +26 -10
  26. package/dist/runtime/server/provider-write.js +75 -7
  27. package/dist/runtime/server/voice-provider.d.ts +61 -0
  28. package/dist/runtime/server/voice-provider.js +31 -0
  29. package/dist/runtime/shared/data-zone.d.ts +68 -0
  30. package/dist/runtime/shared/data-zone.js +79 -0
  31. package/dist/runtime/shared/harness-providers.d.ts +42 -3
  32. package/dist/runtime/shared/harness-providers.js +31 -8
  33. package/dist/runtime/shared/harnesses.d.ts +7 -0
  34. package/dist/runtime/shared/harnesses.js +18 -0
  35. package/dist/runtime/shared/provider-accounts.d.ts +215 -0
  36. package/dist/runtime/shared/provider-accounts.js +255 -0
  37. package/dist/runtime/shared/provider-registry.d.ts +19 -182
  38. package/dist/runtime/shared/provider-registry.js +25 -65
  39. package/dist/runtime/vue/index.d.ts +2 -0
  40. package/dist/runtime/vue/index.js +2 -0
  41. package/dist/runtime/vue/providers-panel-model.d.ts +98 -5
  42. package/dist/runtime/vue/providers-panel-model.js +13 -1
  43. package/dist/runtime/vue/useProvidersPanel.d.ts +66 -5
  44. package/dist/runtime/vue/useProvidersPanel.js +417 -29
  45. package/dist/runtime/{server → workspaces}/harness-settings.d.ts +51 -13
  46. package/dist/runtime/{server → workspaces}/harness-settings.js +93 -9
  47. package/dist/runtime/workspaces/index.d.ts +16 -0
  48. package/dist/runtime/workspaces/index.js +5 -0
  49. package/dist/runtime/workspaces/language-model.d.ts +45 -0
  50. package/dist/runtime/workspaces/language-model.js +26 -0
  51. package/dist/runtime/workspaces/model-endpoint.d.ts +38 -0
  52. package/dist/runtime/workspaces/model-endpoint.js +54 -0
  53. package/dist/runtime/workspaces/provider-settings.d.ts +35 -0
  54. package/dist/runtime/{server → workspaces}/provider-settings.js +0 -31
  55. package/dist/runtime/{server → workspaces}/settings-defaults.d.ts +1 -1
  56. package/dist/runtime/{shared → workspaces}/settings-types.d.ts +11 -4
  57. package/package.json +11 -2
  58. package/src/runtime/ai-sdk/index.ts +88 -47
  59. package/src/runtime/components/ForgeProvidersPanel.vue +477 -78
  60. package/src/runtime/editor/index.ts +158 -63
  61. package/src/runtime/model/selector.ts +31 -0
  62. package/src/runtime/server/credential-store.ts +20 -10
  63. package/src/runtime/server/env-layers.ts +4 -4
  64. package/src/runtime/server/index.ts +9 -8
  65. package/src/runtime/server/provider-discovery.ts +114 -48
  66. package/src/runtime/server/provider-layers.ts +6 -6
  67. package/src/runtime/server/provider-service.ts +53 -1
  68. package/src/runtime/server/provider-write.ts +132 -18
  69. package/src/runtime/server/voice-provider.ts +110 -0
  70. package/src/runtime/shared/data-zone.ts +179 -0
  71. package/src/runtime/shared/harness-providers.ts +78 -7
  72. package/src/runtime/shared/harnesses.ts +25 -0
  73. package/src/runtime/shared/provider-accounts.ts +526 -0
  74. package/src/runtime/shared/provider-registry.ts +82 -256
  75. package/src/runtime/vue/index.ts +2 -0
  76. package/src/runtime/vue/providers-panel-model.ts +123 -5
  77. package/src/runtime/vue/useProvidersPanel.ts +589 -37
  78. package/src/runtime/{server → workspaces}/harness-settings.ts +166 -22
  79. package/src/runtime/workspaces/index.ts +17 -0
  80. package/src/runtime/workspaces/language-model.ts +82 -0
  81. package/src/runtime/workspaces/model-endpoint.ts +100 -0
  82. package/src/runtime/workspaces/provider-settings.ts +96 -0
  83. package/src/runtime/{server → workspaces}/settings-defaults.ts +1 -1
  84. package/src/runtime/{shared → workspaces}/settings-types.ts +11 -4
  85. package/dist/runtime/server/provider-settings.d.ts +0 -78
  86. package/src/runtime/server/provider-settings.ts +0 -192
  87. /package/dist/runtime/{server → workspaces}/settings-defaults.js +0 -0
  88. /package/dist/runtime/{shared → workspaces}/settings-types.js +0 -0
@@ -8,11 +8,16 @@
8
8
  * Eligibility is by wire surface, never by vendor name: an entry is eligible
9
9
  * for a harness when it is an enabled `llm` entry whose `surface` the harness
10
10
  * declares. A harness that declares no surfaces accepts every `llm` entry.
11
+ * A host's data-zone rule then keeps out the entries outside it: such an
12
+ * entry is reported as `blocked-by-rule`, never eligible and never chosen.
11
13
  *
12
14
  * Browser-safe on purpose — no `node:` imports.
13
15
  */
14
16
 
15
- /** How many registry entries a harness can run at once (`@skaile/workspaces` `HarnessInfo.providerPlurality`). */
17
+ import { DATA_ZONE_RULE_LABELS, dataZoneRefusal, presetDataZone } from "./data-zone";
18
+ import type { AIProviderDataZone, AIProviderDataZoneRule } from "./provider-registry";
19
+
20
+ /** How many registry entries a harness can run at once (`HarnessInfo.providerPlurality` of a Workspaces harness). */
16
21
  export type HarnessProviderPlurality = "registry" | "credentials-n" | "single";
17
22
 
18
23
  /** The slice of a harness the rule reads. `GET /api/agents` rows satisfy it. */
@@ -33,6 +38,35 @@ export interface HarnessProviderCandidate {
33
38
  surface?: string;
34
39
  /** Absent means enabled. */
35
40
  enabled?: boolean;
41
+ /** Catalog preset; gives the zone when {@link dataZone} is absent. */
42
+ preset?: string;
43
+ /** Effective data zone (`GET /api/providers` rows carry it). Absent: the preset's, else `transfer`. */
44
+ dataZone?: AIProviderDataZone;
45
+ /** The account's EU-processing setting is on. */
46
+ euProcessing?: boolean;
47
+ }
48
+
49
+ /** Why an entry on a surface the harness speaks still cannot be used. */
50
+ export type HarnessProviderBlockReason = "blocked-by-rule";
51
+
52
+ /** One entry the harness could speak to that the host's rule keeps out. */
53
+ export interface HarnessProviderBlock {
54
+ id: string;
55
+ reason: HarnessProviderBlockReason;
56
+ /** The rule in force. */
57
+ rule: AIProviderDataZoneRule;
58
+ /** The rule's label ("EU only"). */
59
+ ruleLabel: string;
60
+ /** The entry's effective zone. */
61
+ zone: AIProviderDataZone;
62
+ /** What a settings table shows on the box it cannot tick. Secret-free. */
63
+ message: string;
64
+ }
65
+
66
+ /** What {@link resolveHarnessProviders} applies beyond the surface rule. */
67
+ export interface HarnessProviderOptions {
68
+ /** The host's data-zone rule. Absent: `any`. */
69
+ dataZoneRule?: AIProviderDataZoneRule;
36
70
  }
37
71
 
38
72
  /**
@@ -55,8 +89,10 @@ export interface HarnessProviderResolution<
55
89
  state: HarnessProviderState;
56
90
  /** The harness can run several providers at once. */
57
91
  multiple: boolean;
58
- /** Stored pick ids that are no longer eligible, deduplicated, in stored order. */
92
+ /** Stored pick ids that are no longer eligible (blocked ones included), deduplicated, in stored order. */
59
93
  stale: string[];
94
+ /** Candidates on a surface the harness speaks that the data-zone rule keeps out, in registry order. */
95
+ blocked: HarnessProviderBlock[];
60
96
  }
61
97
 
62
98
  /** Whether `candidate` is an enabled `llm` entry on a surface `harness` speaks. */
@@ -70,22 +106,55 @@ export function isProviderEligibleForHarness(
70
106
  return candidate.surface !== undefined && harness.surfaces.includes(candidate.surface);
71
107
  }
72
108
 
109
+ /**
110
+ * Why the data-zone rule keeps `candidate` out of `harness`, or `undefined`
111
+ * when it does not: the candidate must be otherwise eligible
112
+ * ({@link isProviderEligibleForHarness}) and outside `rule`.
113
+ */
114
+ export function harnessProviderBlock(
115
+ harness: HarnessProviderInfo,
116
+ candidate: HarnessProviderCandidate,
117
+ rule: AIProviderDataZoneRule | undefined,
118
+ ): HarnessProviderBlock | undefined {
119
+ if (!rule || rule === "any" || !isProviderEligibleForHarness(harness, candidate)) {
120
+ return undefined;
121
+ }
122
+ const zone = candidate.dataZone ?? presetDataZone(candidate.preset) ?? "transfer";
123
+ const message = dataZoneRefusal(rule, zone, candidate.euProcessing);
124
+ if (!message) return undefined;
125
+ return {
126
+ id: candidate.id,
127
+ reason: "blocked-by-rule",
128
+ rule,
129
+ ruleLabel: DATA_ZONE_RULE_LABELS[rule],
130
+ zone,
131
+ message,
132
+ };
133
+ }
134
+
73
135
  /**
74
136
  * Resolve the providers a harness runs against.
75
137
  *
76
138
  * @param candidates Registry entries in registry order.
77
139
  * @param selection The stored per-harness pick (`SkaileSettings.harnessProviders[harness.id]`).
140
+ * @param options.dataZoneRule The host's data-zone rule: entries outside it are
141
+ * `blocked`, never eligible, never auto-chosen; a stored pick of one is `stale`.
78
142
  */
79
143
  export function resolveHarnessProviders<C extends HarnessProviderCandidate>(
80
144
  harness: HarnessProviderInfo,
81
145
  candidates: readonly C[],
82
146
  selection: readonly string[] | undefined,
147
+ options: HarnessProviderOptions = {},
83
148
  ): HarnessProviderResolution<C> {
84
149
  const multiple =
85
150
  harness.providerPlurality === "registry" || harness.providerPlurality === "credentials-n";
86
- const eligible = candidates.filter((candidate) =>
87
- isProviderEligibleForHarness(harness, candidate),
88
- );
151
+ const blocked: HarnessProviderBlock[] = [];
152
+ const eligible = candidates.filter((candidate) => {
153
+ if (!isProviderEligibleForHarness(harness, candidate)) return false;
154
+ const block = harnessProviderBlock(harness, candidate, options.dataZoneRule);
155
+ if (block) blocked.push(block);
156
+ return !block;
157
+ });
89
158
  const eligibleIds = new Set(eligible.map((candidate) => candidate.id));
90
159
  const picked = new Set(selection ?? []);
91
160
  const stale = [...picked].filter((id) => !eligibleIds.has(id));
@@ -100,10 +169,11 @@ export function resolveHarnessProviders<C extends HarnessProviderCandidate>(
100
169
  state: "chosen",
101
170
  multiple,
102
171
  stale,
172
+ blocked,
103
173
  };
104
174
  }
105
175
  if (eligible.length === 0) {
106
- return { eligible, selected: [], state: "none-eligible", multiple, stale };
176
+ return { eligible, selected: [], state: "none-eligible", multiple, stale, blocked };
107
177
  }
108
178
  if (eligible.length === 1 || multiple) {
109
179
  return {
@@ -112,7 +182,8 @@ export function resolveHarnessProviders<C extends HarnessProviderCandidate>(
112
182
  state: "auto",
113
183
  multiple,
114
184
  stale,
185
+ blocked,
115
186
  };
116
187
  }
117
- return { eligible, selected: [], state: "needs-choice", multiple, stale };
188
+ return { eligible, selected: [], state: "needs-choice", multiple, stale, blocked };
118
189
  }
@@ -32,3 +32,28 @@ export const DEFAULT_ENABLED_HARNESSES = ["omp", "claude-sdk", "codex"] as const
32
32
  export function isExperimentalHarness(id: string): boolean {
33
33
  return !(DEFAULT_ENABLED_HARNESSES as readonly string[]).includes(id);
34
34
  }
35
+
36
+ /**
37
+ * The model roles ("models per task") each multi-model harness renders, keyed by
38
+ * harness id. A harness absent here runs one model and takes no roles.
39
+ */
40
+ export const HARNESS_ROLES: Readonly<Record<string, readonly string[]>> = {
41
+ omp: [
42
+ "default",
43
+ "smol",
44
+ "slow",
45
+ "vision",
46
+ "plan",
47
+ "designer",
48
+ "commit",
49
+ "tiny",
50
+ "task",
51
+ "advisor",
52
+ ],
53
+ continue: ["chat", "edit", "apply", "autocomplete", "embed", "rerank", "summarize"],
54
+ };
55
+
56
+ /** The role ids `harnessId` supports ({@link HARNESS_ROLES}); empty for a one-model harness. */
57
+ export function harnessRoleIds(harnessId: string): string[] {
58
+ return [...(HARNESS_ROLES[harnessId] ?? [])];
59
+ }