@skaile/forge-settings 1.1.0 → 1.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.0
4
+
5
+ - `@skaile/forge-settings/ai-sdk`: `resolveRegistryLanguageModel(selector, { …, registry? })` takes an already merged registry (e.g. one routed through the Workspaces transform proxy). When set, `projectDir` is not read for providers (so no `registry_invalid` from disk), the selector and the credential policy are checked against that registry, and it is forwarded to Workspaces' `resolveLanguageModel({ registry })`.
6
+ - Needs `@skaile/workspaces` ^7.8.0 (the `registry` option of `resolveLanguageModel`); the 6.x range is dropped.
7
+
8
+ ## 1.1.1
9
+
10
+ - Accepts `@skaile/workspaces` 7: dependency range `^6.14.0 || ^7.0.0` (checked against 7.1.0; nothing this package imports changed). No code change.
11
+
3
12
  ## 1.1.0
4
13
 
5
14
  - `@skaile/forge-settings/server`: `HarnessRow` carries `detection: HarnessDetection` (installed / version / login, from `@skaile/workspaces` `detectHarnesses()`). `buildHarnessRows(harnesses, settings, detections?)` takes the host's detections as an optional third argument; a harness it does not mention, or every harness when it is omitted, reports `{ id, status: "unknown" }`.
package/README.md CHANGED
@@ -66,6 +66,8 @@ const { model } = await resolveRegistryLanguageModel('assistant-default/some-mod
66
66
 
67
67
  Role-to-selector mapping belongs to the host's settings document; there is no global model locator. Failures are `ModelResolutionError` with a `code`; messages never carry a secret.
68
68
 
69
+ Pass `registry` (an already merged registry, e.g. one routed through the Workspaces transform proxy) to resolve against it instead of the providers on disk; the policy check runs on it and Workspaces receives it unchanged.
70
+
69
71
  ## Providers panel
70
72
 
71
73
  ```ts
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@skaile/forge-settings",
3
3
  "configKey": "forgeSettings",
4
- "version": "1.1.0",
4
+ "version": "1.2.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.3",
7
7
  "unbuild": "3.6.1"
@@ -13,6 +13,7 @@
13
13
  * `@ai-sdk/openai-compatible`) are optional peers of Workspaces: install the
14
14
  * one the selected surface needs.
15
15
  */
16
+ import { type MergedAIProviderRegistry } from "@skaile/workspaces/core";
16
17
  import { type ResolvedLanguageModel } from "@skaile/workspaces/ai-sdk";
17
18
  import type { CredentialPolicy } from "../server/credential-policy.js";
18
19
  export { ModelResolutionError } from "../model/errors.js";
@@ -34,13 +35,21 @@ export interface ResolveRegistryLanguageModelOptions {
34
35
  * before anything is read; a refused one is a `policy_refused` failure.
35
36
  */
36
37
  policy?: CredentialPolicy;
38
+ /**
39
+ * An already merged (e.g. transform-proxy-routed) registry. When set,
40
+ * `projectDir` is not read for providers, the policy check runs on this
41
+ * registry, and it is handed to Workspaces as the registry to resolve against.
42
+ */
43
+ registry?: MergedAIProviderRegistry;
37
44
  }
38
45
  /**
39
46
  * The AI SDK model for `selector` (`<providerId>/<modelId>`, a bare model id or
40
- * `@role`), resolved by Workspaces against the registry on disk.
47
+ * `@role`), resolved by Workspaces against the registry on disk, or the given
48
+ * `registry`.
41
49
  *
42
- * @throws {ModelResolutionError} `registry_invalid` · `unknown_selector` ·
43
- * `policy_refused` · `unresolved` (credential, endpoint or provider SDK; the
44
- * message is fixed and never carries Workspaces' text, which stays on `cause`).
50
+ * @throws {ModelResolutionError} `registry_invalid` (only when read from disk) ·
51
+ * `unknown_selector` · `policy_refused` · `unresolved` (credential, endpoint or
52
+ * provider SDK; the message is fixed and never carries Workspaces' text, which
53
+ * stays on `cause`).
45
54
  */
46
55
  export declare function resolveRegistryLanguageModel(selector: string, options: ResolveRegistryLanguageModelOptions): Promise<ResolvedLanguageModel>;
@@ -4,11 +4,7 @@ import { loadMergedProviderRegistry } from "@skaile/workspaces/sdk/bridge";
4
4
  import { ModelResolutionError, assertEntryAllowed } from "../model/errors.js";
5
5
  export { ModelResolutionError } from "../model/errors.js";
6
6
  export async function resolveRegistryLanguageModel(selector, options) {
7
- const { merged, diagnostics } = loadMergedProviderRegistry({ projectDir: options.projectDir });
8
- const errors = diagnostics.filter((d) => d.severity === "error").map((d) => d.path ? `${d.path}: ${d.message}` : d.message);
9
- if (errors.length > 0) {
10
- throw new ModelResolutionError("registry_invalid", `providers registry: ${errors.join("; ")}`);
11
- }
7
+ const merged = options.registry ?? loadRegistry(options.projectDir);
12
8
  const ref = parseModelRef(selector, merged, options.roles);
13
9
  if (!ref) {
14
10
  throw new ModelResolutionError("unknown_selector", `no provider serves '${selector}'`);
@@ -19,7 +15,8 @@ export async function resolveRegistryLanguageModel(selector, options) {
19
15
  return await resolveLanguageModel(selector, {
20
16
  projectDir: options.projectDir,
21
17
  env: options.env,
22
- ...options.roles ? { roles: options.roles } : {}
18
+ ...options.roles ? { roles: options.roles } : {},
19
+ ...options.registry ? { registry: options.registry } : {}
23
20
  });
24
21
  } catch (cause) {
25
22
  throw new ModelResolutionError(
@@ -29,3 +26,11 @@ export async function resolveRegistryLanguageModel(selector, options) {
29
26
  );
30
27
  }
31
28
  }
29
+ function loadRegistry(projectDir) {
30
+ const { merged, diagnostics } = loadMergedProviderRegistry({ projectDir });
31
+ const errors = diagnostics.filter((d) => d.severity === "error").map((d) => d.path ? `${d.path}: ${d.message}` : d.message);
32
+ if (errors.length > 0) {
33
+ throw new ModelResolutionError("registry_invalid", `providers registry: ${errors.join("; ")}`);
34
+ }
35
+ return merged;
36
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skaile/forge-settings",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Provider and settings operations for Skaile forge apps: provider registry layers, credential store, env layers, model discovery, the providers panel, and editor / AI SDK model adapters.",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.3.9",
@@ -55,7 +55,7 @@
55
55
  },
56
56
  "dependencies": {
57
57
  "@nuxt/kit": "^4.0.0",
58
- "@skaile/workspaces": "^6.14.0",
58
+ "@skaile/workspaces": "^7.8.0",
59
59
  "ofetch": "^1.4.0",
60
60
  "yaml": "^2.9.0"
61
61
  },
@@ -14,7 +14,7 @@
14
14
  * one the selected surface needs.
15
15
  */
16
16
 
17
- import { parseModelRef } from "@skaile/workspaces/core";
17
+ import { type MergedAIProviderRegistry, parseModelRef } from "@skaile/workspaces/core";
18
18
  import { type ResolvedLanguageModel, resolveLanguageModel } from "@skaile/workspaces/ai-sdk";
19
19
  import { loadMergedProviderRegistry } from "@skaile/workspaces/sdk/bridge";
20
20
  import type { CredentialPolicy } from "../server/credential-policy";
@@ -40,27 +40,29 @@ export interface ResolveRegistryLanguageModelOptions {
40
40
  * before anything is read; a refused one is a `policy_refused` failure.
41
41
  */
42
42
  policy?: CredentialPolicy;
43
+ /**
44
+ * An already merged (e.g. transform-proxy-routed) registry. When set,
45
+ * `projectDir` is not read for providers, the policy check runs on this
46
+ * registry, and it is handed to Workspaces as the registry to resolve against.
47
+ */
48
+ registry?: MergedAIProviderRegistry;
43
49
  }
44
50
 
45
51
  /**
46
52
  * The AI SDK model for `selector` (`<providerId>/<modelId>`, a bare model id or
47
- * `@role`), resolved by Workspaces against the registry on disk.
53
+ * `@role`), resolved by Workspaces against the registry on disk, or the given
54
+ * `registry`.
48
55
  *
49
- * @throws {ModelResolutionError} `registry_invalid` · `unknown_selector` ·
50
- * `policy_refused` · `unresolved` (credential, endpoint or provider SDK; the
51
- * message is fixed and never carries Workspaces' text, which stays on `cause`).
56
+ * @throws {ModelResolutionError} `registry_invalid` (only when read from disk) ·
57
+ * `unknown_selector` · `policy_refused` · `unresolved` (credential, endpoint or
58
+ * provider SDK; the message is fixed and never carries Workspaces' text, which
59
+ * stays on `cause`).
52
60
  */
53
61
  export async function resolveRegistryLanguageModel(
54
62
  selector: string,
55
63
  options: ResolveRegistryLanguageModelOptions,
56
64
  ): Promise<ResolvedLanguageModel> {
57
- const { merged, diagnostics } = loadMergedProviderRegistry({ projectDir: options.projectDir });
58
- const errors = diagnostics
59
- .filter((d) => d.severity === "error")
60
- .map((d) => (d.path ? `${d.path}: ${d.message}` : d.message));
61
- if (errors.length > 0) {
62
- throw new ModelResolutionError("registry_invalid", `providers registry: ${errors.join("; ")}`);
63
- }
65
+ const merged = options.registry ?? loadRegistry(options.projectDir);
64
66
 
65
67
  const ref = parseModelRef(selector, merged, options.roles);
66
68
  if (!ref) {
@@ -74,6 +76,7 @@ export async function resolveRegistryLanguageModel(
74
76
  projectDir: options.projectDir,
75
77
  env: options.env,
76
78
  ...(options.roles ? { roles: options.roles } : {}),
79
+ ...(options.registry ? { registry: options.registry } : {}),
77
80
  });
78
81
  } catch (cause) {
79
82
  // Workspaces' message is not ours to vouch for: it can echo a resolved
@@ -86,3 +89,15 @@ export async function resolveRegistryLanguageModel(
86
89
  );
87
90
  }
88
91
  }
92
+
93
+ /** The merged registry of `projectDir`; `registry_invalid` on any error diagnostic. */
94
+ function loadRegistry(projectDir: string): MergedAIProviderRegistry {
95
+ const { merged, diagnostics } = loadMergedProviderRegistry({ projectDir });
96
+ const errors = diagnostics
97
+ .filter((d) => d.severity === "error")
98
+ .map((d) => (d.path ? `${d.path}: ${d.message}` : d.message));
99
+ if (errors.length > 0) {
100
+ throw new ModelResolutionError("registry_invalid", `providers registry: ${errors.join("; ")}`);
101
+ }
102
+ return merged;
103
+ }