@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.
- package/CHANGELOG.md +40 -0
- package/README.md +52 -9
- package/dist/module.json +1 -1
- package/dist/runtime/ai-sdk/index.d.ts +33 -26
- package/dist/runtime/ai-sdk/index.js +34 -16
- package/dist/runtime/components/ForgeProvidersPanel.d.vue.ts +13 -0
- package/dist/runtime/components/ForgeProvidersPanel.vue +461 -78
- package/dist/runtime/components/ForgeProvidersPanel.vue.d.ts +13 -0
- package/dist/runtime/editor/index.d.ts +55 -16
- package/dist/runtime/editor/index.js +82 -40
- package/dist/runtime/model/selector.d.ts +16 -0
- package/dist/runtime/model/selector.js +12 -0
- package/dist/runtime/server/credential-store.d.ts +16 -4
- package/dist/runtime/server/credential-store.js +3 -4
- package/dist/runtime/server/env-layers.d.ts +1 -1
- package/dist/runtime/server/env-layers.js +3 -3
- package/dist/runtime/server/index.d.ts +9 -8
- package/dist/runtime/server/index.js +3 -3
- package/dist/runtime/server/provider-discovery.d.ts +28 -8
- package/dist/runtime/server/provider-discovery.js +57 -33
- package/dist/runtime/server/provider-layers.d.ts +1 -1
- package/dist/runtime/server/provider-layers.js +3 -5
- package/dist/runtime/server/provider-service.d.ts +26 -2
- package/dist/runtime/server/provider-service.js +16 -1
- package/dist/runtime/server/provider-write.d.ts +26 -10
- package/dist/runtime/server/provider-write.js +75 -7
- package/dist/runtime/server/voice-provider.d.ts +61 -0
- package/dist/runtime/server/voice-provider.js +31 -0
- package/dist/runtime/shared/data-zone.d.ts +68 -0
- package/dist/runtime/shared/data-zone.js +79 -0
- package/dist/runtime/shared/harness-providers.d.ts +42 -3
- package/dist/runtime/shared/harness-providers.js +31 -8
- package/dist/runtime/shared/harnesses.d.ts +7 -0
- package/dist/runtime/shared/harnesses.js +18 -0
- package/dist/runtime/shared/provider-accounts.d.ts +215 -0
- package/dist/runtime/shared/provider-accounts.js +255 -0
- package/dist/runtime/shared/provider-registry.d.ts +19 -182
- package/dist/runtime/shared/provider-registry.js +25 -65
- package/dist/runtime/vue/index.d.ts +2 -0
- package/dist/runtime/vue/index.js +2 -0
- package/dist/runtime/vue/providers-panel-model.d.ts +98 -5
- package/dist/runtime/vue/providers-panel-model.js +13 -1
- package/dist/runtime/vue/useProvidersPanel.d.ts +66 -5
- package/dist/runtime/vue/useProvidersPanel.js +417 -29
- package/dist/runtime/{server → workspaces}/harness-settings.d.ts +51 -13
- package/dist/runtime/{server → workspaces}/harness-settings.js +93 -9
- package/dist/runtime/workspaces/index.d.ts +16 -0
- package/dist/runtime/workspaces/index.js +5 -0
- package/dist/runtime/workspaces/language-model.d.ts +45 -0
- package/dist/runtime/workspaces/language-model.js +26 -0
- package/dist/runtime/workspaces/model-endpoint.d.ts +38 -0
- package/dist/runtime/workspaces/model-endpoint.js +54 -0
- package/dist/runtime/workspaces/provider-settings.d.ts +35 -0
- package/dist/runtime/{server → workspaces}/provider-settings.js +0 -31
- package/dist/runtime/{server → workspaces}/settings-defaults.d.ts +1 -1
- package/dist/runtime/{shared → workspaces}/settings-types.d.ts +11 -4
- package/package.json +11 -2
- package/src/runtime/ai-sdk/index.ts +88 -47
- package/src/runtime/components/ForgeProvidersPanel.vue +477 -78
- package/src/runtime/editor/index.ts +158 -63
- package/src/runtime/model/selector.ts +31 -0
- package/src/runtime/server/credential-store.ts +20 -10
- package/src/runtime/server/env-layers.ts +4 -4
- package/src/runtime/server/index.ts +9 -8
- package/src/runtime/server/provider-discovery.ts +114 -48
- package/src/runtime/server/provider-layers.ts +6 -6
- package/src/runtime/server/provider-service.ts +53 -1
- package/src/runtime/server/provider-write.ts +132 -18
- package/src/runtime/server/voice-provider.ts +110 -0
- package/src/runtime/shared/data-zone.ts +179 -0
- package/src/runtime/shared/harness-providers.ts +78 -7
- package/src/runtime/shared/harnesses.ts +25 -0
- package/src/runtime/shared/provider-accounts.ts +526 -0
- package/src/runtime/shared/provider-registry.ts +82 -256
- package/src/runtime/vue/index.ts +2 -0
- package/src/runtime/vue/providers-panel-model.ts +123 -5
- package/src/runtime/vue/useProvidersPanel.ts +589 -37
- package/src/runtime/{server → workspaces}/harness-settings.ts +166 -22
- package/src/runtime/workspaces/index.ts +17 -0
- package/src/runtime/workspaces/language-model.ts +82 -0
- package/src/runtime/workspaces/model-endpoint.ts +100 -0
- package/src/runtime/workspaces/provider-settings.ts +96 -0
- package/src/runtime/{server → workspaces}/settings-defaults.ts +1 -1
- package/src/runtime/{shared → workspaces}/settings-types.ts +11 -4
- package/dist/runtime/server/provider-settings.d.ts +0 -78
- package/src/runtime/server/provider-settings.ts +0 -192
- /package/dist/runtime/{server → workspaces}/settings-defaults.js +0 -0
- /package/dist/runtime/{shared → workspaces}/settings-types.js +0 -0
|
@@ -1,33 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@skaile/forge-settings/ai-sdk` — the AI SDK language model of a registry
|
|
3
|
-
* selector,
|
|
4
|
-
* credential
|
|
3
|
+
* selector, built by `@skaile/provider-registry/ai-sdk` against one registry
|
|
4
|
+
* snapshot the host passes, with the credential resolved under the host's
|
|
5
|
+
* policy.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
* this module
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* The shared constructor owns endpoint, header and SDK wiring for every
|
|
8
|
+
* surface it supports; this module decides *whether* an entry may be resolved
|
|
9
|
+
* and supplies its credential — through the same policy-checked resolver model
|
|
10
|
+
* discovery uses, so a model that lists is a model that calls with the same
|
|
11
|
+
* key. It is not a service locator: the caller passes the selector
|
|
12
|
+
* (role-to-selector mapping belongs to the host's settings document), the
|
|
13
|
+
* registry and the environment explicitly. Nothing is read from disk here;
|
|
14
|
+
* a Skaile Workspaces host that resolves against a project's registry uses
|
|
15
|
+
* `resolveWorkspaceLanguageModel` from `@skaile/forge-settings/workspaces`.
|
|
11
16
|
*
|
|
12
17
|
* Provider SDKs (`@ai-sdk/anthropic`, `@ai-sdk/openai`,
|
|
13
|
-
* `@ai-sdk/openai-compatible`) are optional peers
|
|
14
|
-
*
|
|
18
|
+
* `@ai-sdk/openai-compatible`) are optional peers: install the one the
|
|
19
|
+
* selected surface needs.
|
|
15
20
|
*/
|
|
16
21
|
|
|
17
|
-
import { type MergedAIProviderRegistry, parseModelRef } from "@skaile/
|
|
18
|
-
import {
|
|
19
|
-
|
|
22
|
+
import { type MergedAIProviderRegistry, parseModelRef } from "@skaile/provider-registry";
|
|
23
|
+
import {
|
|
24
|
+
type EntryCredentialResolver,
|
|
25
|
+
type ResolvedLanguageModel,
|
|
26
|
+
resolveLanguageModel,
|
|
27
|
+
} from "@skaile/provider-registry/ai-sdk";
|
|
28
|
+
import { assertEntryAllowed, ModelResolutionError } from "../model/errors";
|
|
29
|
+
import { credentialStoreOptions, selectorProviderId } from "../model/selector";
|
|
20
30
|
import type { CredentialPolicy } from "../server/credential-policy";
|
|
21
|
-
import {
|
|
31
|
+
import { resolveEntryCredential } from "../server/credential-store";
|
|
22
32
|
|
|
23
|
-
export { ModelResolutionError } from "../model/errors";
|
|
24
33
|
export type { ModelResolutionCode } from "../model/errors";
|
|
34
|
+
export { ModelResolutionError } from "../model/errors";
|
|
25
35
|
export type { ResolvedLanguageModel };
|
|
26
36
|
|
|
27
37
|
/** Options for {@link resolveRegistryLanguageModel}. */
|
|
28
38
|
export interface ResolveRegistryLanguageModelOptions {
|
|
29
|
-
/**
|
|
30
|
-
|
|
39
|
+
/** The one merged registry snapshot the selector resolves against. */
|
|
40
|
+
registry: MergedAIProviderRegistry;
|
|
31
41
|
/**
|
|
32
42
|
* The environment `env:` credential references are read from. Required, so a
|
|
33
43
|
* host never reads the ambient process by accident.
|
|
@@ -40,48 +50,91 @@ export interface ResolveRegistryLanguageModelOptions {
|
|
|
40
50
|
* before anything is read; a refused one is a `policy_refused` failure.
|
|
41
51
|
*/
|
|
42
52
|
policy?: CredentialPolicy;
|
|
43
|
-
/**
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
/** Local encrypted store for `keyring:` references; else `FORGE_CREDENTIAL_STORE` of `env`. */
|
|
54
|
+
path?: string;
|
|
55
|
+
/** 64-char hex key of the local store; else `FORGE_CREDENTIAL_KEY` of `env`. */
|
|
56
|
+
key?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The credential resolver discovery and invocation share: the policy refuses
|
|
61
|
+
* an entry before any reference is read, then the reference resolves from
|
|
62
|
+
* `env` or the local store. Secret-free errors only.
|
|
63
|
+
*/
|
|
64
|
+
function policyCredentialResolver(
|
|
65
|
+
options: Pick<ResolveRegistryLanguageModelOptions, "env" | "policy" | "path" | "key">,
|
|
66
|
+
): EntryCredentialResolver {
|
|
67
|
+
return (entry, providerId) => {
|
|
68
|
+
assertEntryAllowed(entry, providerId, options.policy);
|
|
69
|
+
const resolved = resolveEntryCredential(entry, credentialStoreOptions(options.env, options));
|
|
70
|
+
return resolved.error && !resolved.value
|
|
71
|
+
? { error: resolved.error }
|
|
72
|
+
: { ...(resolved.value !== undefined ? { value: resolved.value } : {}) };
|
|
73
|
+
};
|
|
49
74
|
}
|
|
50
75
|
|
|
51
76
|
/**
|
|
52
77
|
* The AI SDK model for `selector` (`<providerId>/<modelId>`, a bare model id or
|
|
53
|
-
* `@role`), resolved
|
|
54
|
-
* `registry`.
|
|
78
|
+
* `@role`), resolved against `options.registry` only.
|
|
55
79
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
80
|
+
* Strict: a selector naming a provider that is missing from the registry's
|
|
81
|
+
* enabled `llm` entries (and that no entry maps as a model id), disabled, or an
|
|
82
|
+
* unassigned `@role` fails — nothing is rerouted to another endpoint and
|
|
83
|
+
* nothing is sent. A bare model id without `/` resolves as the registry orders it.
|
|
84
|
+
*
|
|
85
|
+
* @throws {ModelResolutionError} `unknown_selector` (no enabled entry serves the
|
|
86
|
+
* selector, or the named entry is disabled / not an `llm` entry) ·
|
|
87
|
+
* `policy_refused` · `unresolved` (credential, endpoint or provider SDK; the
|
|
88
|
+
* message is fixed, the underlying error stays on `cause`).
|
|
60
89
|
*/
|
|
61
90
|
export async function resolveRegistryLanguageModel(
|
|
62
91
|
selector: string,
|
|
63
92
|
options: ResolveRegistryLanguageModelOptions,
|
|
64
93
|
): Promise<ResolvedLanguageModel> {
|
|
65
|
-
const merged = options.registry
|
|
94
|
+
const merged = options.registry;
|
|
95
|
+
|
|
96
|
+
const head = selectorProviderId(selector);
|
|
97
|
+
const named = head === undefined ? undefined : merged.providers[head];
|
|
98
|
+
if (
|
|
99
|
+
head !== undefined &&
|
|
100
|
+
named !== undefined &&
|
|
101
|
+
(named.kind !== "llm" || named.enabled === false)
|
|
102
|
+
) {
|
|
103
|
+
throw new ModelResolutionError(
|
|
104
|
+
"unknown_selector",
|
|
105
|
+
`provider '${head}' is ${named.kind !== "llm" ? "not an llm entry" : "disabled"}`,
|
|
106
|
+
{ providerId: head },
|
|
107
|
+
);
|
|
108
|
+
}
|
|
66
109
|
|
|
67
110
|
const ref = parseModelRef(selector, merged, options.roles);
|
|
68
|
-
|
|
111
|
+
// `<head>/<model>` that no entry is named by or maps: the general resolver would
|
|
112
|
+
// hand it to the first entry in registry order, i.e. send it (and that entry's
|
|
113
|
+
// credential) to an endpoint the caller did not name.
|
|
114
|
+
if (!ref || (head !== undefined && named === undefined && ref.fallback === true)) {
|
|
69
115
|
throw new ModelResolutionError("unknown_selector", `no provider serves '${selector}'`);
|
|
70
116
|
}
|
|
117
|
+
if (ref.role !== undefined && !options.roles?.[ref.role]) {
|
|
118
|
+
throw new ModelResolutionError(
|
|
119
|
+
"unknown_selector",
|
|
120
|
+
`role '@${ref.role}' is not assigned to a model`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
71
123
|
const entry = merged.providers[ref.providerId];
|
|
72
124
|
if (entry) assertEntryAllowed(entry, ref.providerId, options.policy);
|
|
73
125
|
|
|
74
126
|
try {
|
|
75
127
|
return await resolveLanguageModel(selector, {
|
|
76
|
-
|
|
128
|
+
registry: merged,
|
|
77
129
|
env: options.env,
|
|
78
130
|
...(options.roles ? { roles: options.roles } : {}),
|
|
79
|
-
|
|
131
|
+
resolveCredential: policyCredentialResolver(options),
|
|
80
132
|
});
|
|
81
133
|
} catch (cause) {
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
//
|
|
134
|
+
if (cause instanceof ModelResolutionError) throw cause;
|
|
135
|
+
// The constructor's message is not ours to vouch for: an SDK error can echo
|
|
136
|
+
// an endpoint with a key in its query. The message is fixed; the original
|
|
137
|
+
// error stays on `cause` for a host that logs it server-side.
|
|
85
138
|
throw new ModelResolutionError(
|
|
86
139
|
"unresolved",
|
|
87
140
|
`provider '${ref.providerId}': credential, endpoint or provider SDK could not be resolved`,
|
|
@@ -89,15 +142,3 @@ export async function resolveRegistryLanguageModel(
|
|
|
89
142
|
);
|
|
90
143
|
}
|
|
91
144
|
}
|
|
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
|
-
}
|