@happyvertical/smrt-inference 0.0.0-stage → 0.60.16

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 (112) hide show
  1. package/AGENTS.md +206 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +73 -2
  5. package/agents/fusions.md +105 -0
  6. package/agents/hosted.md +161 -0
  7. package/agents/resolver.md +65 -0
  8. package/agents/settings.md +107 -0
  9. package/dist/__smrt-register__.d.ts +2 -0
  10. package/dist/__smrt-register__.d.ts.map +1 -0
  11. package/dist/chunks/InferenceOverrideCollection-Dat4TrK5.js +423 -0
  12. package/dist/chunks/InferenceOverrideCollection-Dat4TrK5.js.map +1 -0
  13. package/dist/chunks/provider-config-BSpIQRVM.js +1873 -0
  14. package/dist/chunks/provider-config-BSpIQRVM.js.map +1 -0
  15. package/dist/classify.d.ts +32 -0
  16. package/dist/classify.d.ts.map +1 -0
  17. package/dist/config.d.ts +89 -0
  18. package/dist/config.d.ts.map +1 -0
  19. package/dist/errors.d.ts +51 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/executor.d.ts +45 -0
  22. package/dist/executor.d.ts.map +1 -0
  23. package/dist/fusion-store.d.ts +16 -0
  24. package/dist/fusion-store.d.ts.map +1 -0
  25. package/dist/fusion.d.ts +155 -0
  26. package/dist/fusion.d.ts.map +1 -0
  27. package/dist/gate.d.ts +143 -0
  28. package/dist/gate.d.ts.map +1 -0
  29. package/dist/gate.js +94 -0
  30. package/dist/gate.js.map +1 -0
  31. package/dist/hosted.d.ts +461 -0
  32. package/dist/hosted.d.ts.map +1 -0
  33. package/dist/index.d.ts +9 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +8 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/manifest.json +453 -0
  38. package/dist/models/InferenceOverride.d.ts +38 -0
  39. package/dist/models/InferenceOverride.d.ts.map +1 -0
  40. package/dist/models/InferenceOverrideCollection.d.ts +35 -0
  41. package/dist/models/InferenceOverrideCollection.d.ts.map +1 -0
  42. package/dist/models.d.ts +11 -0
  43. package/dist/models.d.ts.map +1 -0
  44. package/dist/models.js +2 -0
  45. package/dist/node.d.ts +110 -0
  46. package/dist/node.d.ts.map +1 -0
  47. package/dist/node.js +1414 -0
  48. package/dist/node.js.map +1 -0
  49. package/dist/provider-config.d.ts +113 -0
  50. package/dist/provider-config.d.ts.map +1 -0
  51. package/dist/register.d.ts +30 -0
  52. package/dist/register.d.ts.map +1 -0
  53. package/dist/resolver.d.ts +166 -0
  54. package/dist/resolver.d.ts.map +1 -0
  55. package/dist/resolver.js +291 -0
  56. package/dist/resolver.js.map +1 -0
  57. package/dist/server.d.ts +25 -0
  58. package/dist/server.d.ts.map +1 -0
  59. package/dist/server.js +1138 -0
  60. package/dist/server.js.map +1 -0
  61. package/dist/settings/cache.d.ts +5 -0
  62. package/dist/settings/cache.d.ts.map +1 -0
  63. package/dist/settings/keys.d.ts +70 -0
  64. package/dist/settings/keys.d.ts.map +1 -0
  65. package/dist/settings/layers.d.ts +68 -0
  66. package/dist/settings/layers.d.ts.map +1 -0
  67. package/dist/settings/override-service.d.ts +119 -0
  68. package/dist/settings/override-service.d.ts.map +1 -0
  69. package/dist/settings/preferences.d.ts +137 -0
  70. package/dist/settings/preferences.d.ts.map +1 -0
  71. package/dist/settings/resolver.d.ts +41 -0
  72. package/dist/settings/resolver.d.ts.map +1 -0
  73. package/dist/settings/settings-service.d.ts +355 -0
  74. package/dist/settings/settings-service.d.ts.map +1 -0
  75. package/dist/settings/targets.d.ts +112 -0
  76. package/dist/settings/targets.d.ts.map +1 -0
  77. package/dist/settings/transcripts.d.ts +33 -0
  78. package/dist/settings/transcripts.d.ts.map +1 -0
  79. package/dist/smrt-knowledge.json +341 -0
  80. package/dist/smrt-knowledge.okf.md +80 -0
  81. package/dist/svelte/components/InferenceAliasEditor.svelte +210 -0
  82. package/dist/svelte/components/InferenceAliasEditor.svelte.d.ts +13 -0
  83. package/dist/svelte/components/InferenceAliasEditor.svelte.d.ts.map +1 -0
  84. package/dist/svelte/components/InferenceDefaultView.svelte +330 -0
  85. package/dist/svelte/components/InferenceDefaultView.svelte.d.ts +15 -0
  86. package/dist/svelte/components/InferenceDefaultView.svelte.d.ts.map +1 -0
  87. package/dist/svelte/components/InferenceFusionList.svelte +141 -0
  88. package/dist/svelte/components/InferenceFusionList.svelte.d.ts +16 -0
  89. package/dist/svelte/components/InferenceFusionList.svelte.d.ts.map +1 -0
  90. package/dist/svelte/components/InferenceSettingsPanel.svelte +392 -0
  91. package/dist/svelte/components/InferenceSettingsPanel.svelte.d.ts +84 -0
  92. package/dist/svelte/components/InferenceSettingsPanel.svelte.d.ts.map +1 -0
  93. package/dist/svelte/components/InferenceTierRow.svelte +199 -0
  94. package/dist/svelte/components/InferenceTierRow.svelte.d.ts +14 -0
  95. package/dist/svelte/components/InferenceTierRow.svelte.d.ts.map +1 -0
  96. package/dist/svelte/components/InferenceTranscriptSettings.svelte +165 -0
  97. package/dist/svelte/components/InferenceTranscriptSettings.svelte.d.ts +18 -0
  98. package/dist/svelte/components/InferenceTranscriptSettings.svelte.d.ts.map +1 -0
  99. package/dist/svelte/components/InferenceUsageTable.svelte +177 -0
  100. package/dist/svelte/components/InferenceUsageTable.svelte.d.ts +21 -0
  101. package/dist/svelte/components/InferenceUsageTable.svelte.d.ts.map +1 -0
  102. package/dist/svelte/index.d.ts +17 -0
  103. package/dist/svelte/index.d.ts.map +1 -0
  104. package/dist/svelte/index.js +14 -0
  105. package/dist/svelte/types.d.ts +262 -0
  106. package/dist/svelte/types.d.ts.map +1 -0
  107. package/dist/svelte/types.js +124 -0
  108. package/dist/types.d.ts +47 -0
  109. package/dist/types.d.ts.map +1 -0
  110. package/dist/types.js +13 -0
  111. package/dist/types.js.map +1 -0
  112. package/package.json +105 -3
@@ -0,0 +1,166 @@
1
+ /**
2
+ * `@happyvertical/smrt-inference/resolver` — per-user and per-tenant
3
+ * inference bindings over smrt-secrets (#4756). Node-only: it reads secrets
4
+ * and the ambient principal, so it stays off the browser-safe root entry.
5
+ *
6
+ * Precedence for each tier, highest first:
7
+ * 1. the current user's stored `inference.provider-config` (tier binding,
8
+ * then the user's default binding);
9
+ * 2. the tenant's stored config (same order);
10
+ * 3. `fallback` (another resolver), else the app's `inference` block;
11
+ * 4. unbound: the configured client (`SMRT_AI_*` / the process `ai` block).
12
+ * Every resolution carries `target.source` (`byo | local | hosted | app`),
13
+ * which core records as the `source` usage tag.
14
+ *
15
+ * Inference mode (#4757): a stored config may carry `mode`. The user's mode,
16
+ * else the tenant's, applies: `off` answers every tier (and untiered calls,
17
+ * through `mode()`) as unavailable; `byo` / `local` / `hosted` bind only a
18
+ * stored binding of that source (user, then tenant) and report
19
+ * `unconfigured` when there is none, never falling through to app config.
20
+ */
21
+ import { type InferenceMode, type InferenceModeRequest, type InferenceModeState, type InferenceResolver, type InferenceTarget, type InferenceTier } from '@happyvertical/smrt-core';
22
+ import { SecretService } from '@happyvertical/smrt-secrets';
23
+ import type { DatabaseInterface } from '@happyvertical/sql';
24
+ import { type InferenceProviderConfig, type RedactedInferenceProviderConfig } from './provider-config.js';
25
+ export * from './provider-config.js';
26
+ /**
27
+ * Drop cached configs in every user resolver this process created (all, one
28
+ * tenant, or one user). Writers outside a resolver (hosted provisioning,
29
+ * #4759) call this after storing a config; other processes see the change
30
+ * when their cache entry expires (`ttlMs`, 30 s by default).
31
+ */
32
+ export declare function invalidateUserInferenceResolvers(scope?: {
33
+ tenantId?: string;
34
+ userId?: string;
35
+ }): void;
36
+ /** Default cache lifetime of decrypted configs, per `(tenantId, userId)`. */
37
+ export declare const USER_INFERENCE_CACHE_TTL_MS = 30000;
38
+ /**
39
+ * The subset of `SecretService` the resolver uses. Reads go through
40
+ * `retrieve()` (audited, access-counted); writes through `store()`.
41
+ */
42
+ export interface InferenceSecretStore {
43
+ retrieve(name: string): Promise<{
44
+ value: string;
45
+ }>;
46
+ store(name: string, value: string, options?: {
47
+ category?: string;
48
+ description?: string;
49
+ }): Promise<unknown>;
50
+ delete(name: string): Promise<boolean>;
51
+ }
52
+ /** Who a resolution acts for. */
53
+ export interface InferencePrincipal {
54
+ tenantId: string;
55
+ /** Absent for service principals and background jobs: no user layer. */
56
+ userId?: string;
57
+ }
58
+ /** Options for {@link createUserInferenceResolver}. */
59
+ export interface UserInferenceResolverOptions {
60
+ /** Database for a `SecretService` built on first use (when no `secrets`). */
61
+ db?: DatabaseInterface;
62
+ /** The secret store; defaults to `SecretService.create({ db })`. */
63
+ secrets?: InferenceSecretStore | SecretService;
64
+ /**
65
+ * Resolver for tiers neither the user nor the tenant binds. Default: the
66
+ * app's `inference` block through core's built-in resolution.
67
+ */
68
+ fallback?: InferenceResolver;
69
+ /** Cache lifetime in ms (default {@link USER_INFERENCE_CACHE_TTL_MS}). */
70
+ ttlMs?: number;
71
+ /** Clock seam for tests. */
72
+ now?: () => number;
73
+ /**
74
+ * Principal seam for tests and hosts with their own identity. Default:
75
+ * the ambient principal, read the way smrt-preferences reads it.
76
+ */
77
+ principal?: () => InferencePrincipal | undefined;
78
+ /**
79
+ * Let a request for another tenant than the principal's (an object of
80
+ * tenant B used by a principal of tenant A) read tenant B's stored config.
81
+ * Default `false`: such a request skips the stored layers and falls through
82
+ * to the app config, because reading B's key for A's action is a
83
+ * cross-tenant read. Principal-less contexts (jobs) always use the
84
+ * request's tenant.
85
+ */
86
+ allowCrossTenant?: boolean;
87
+ }
88
+ /** One tier of {@link InferenceBindingMap}. */
89
+ export type InferenceBindingEntry = (InferenceTarget | (Omit<InferenceTarget, 'apiKey'> & {
90
+ hasApiKey: boolean;
91
+ })) & {
92
+ layer: 'user' | 'tenant';
93
+ };
94
+ /** What {@link UserInferenceResolver.resolveBindings} returns. */
95
+ export interface InferenceBindingMap {
96
+ tenantId?: string;
97
+ userId?: string;
98
+ /** Per tier: the stored binding that answers it (absent: app config). */
99
+ tiers: Partial<Record<InferenceTier, InferenceBindingEntry>>;
100
+ /** The stored configs themselves, redacted unless `redact: false`. */
101
+ user?: InferenceProviderConfig | RedactedInferenceProviderConfig;
102
+ tenant?: InferenceProviderConfig | RedactedInferenceProviderConfig;
103
+ /** The explicit mode that applies (#4757) and the layer that set it. */
104
+ mode?: {
105
+ mode: InferenceMode;
106
+ layer: 'user' | 'tenant';
107
+ };
108
+ }
109
+ /** The scope a config is written to. */
110
+ export type InferenceConfigLevel = 'user' | 'tenant';
111
+ /** A resolver plus the read/write helpers the settings panel uses. */
112
+ export interface UserInferenceResolver extends InferenceResolver {
113
+ /**
114
+ * The tier → target map for the ambient principal (never a caller-chosen
115
+ * tenant or user), without
116
+ * keys unless `redact: false` (server-only; never send that to a client).
117
+ */
118
+ resolveBindings(options?: {
119
+ redact?: boolean;
120
+ }): Promise<InferenceBindingMap>;
121
+ /**
122
+ * Validate and store a config for the current principal through
123
+ * `SecretService.store()`, then invalidate the cache. `user` needs a
124
+ * principal with a user id. Authorization (who may write the tenant
125
+ * config) is the host's server action's job.
126
+ */
127
+ write(level: InferenceConfigLevel, config: unknown): Promise<void>;
128
+ /** Delete the stored config at `level` for the current principal. */
129
+ remove(level: InferenceConfigLevel): Promise<boolean>;
130
+ /**
131
+ * Set (or with `null` clear) the stored mode at `level` (#4757), keeping
132
+ * the stored binding. Works without a key: a mode-only config is valid.
133
+ * A config left with neither binding nor mode is deleted. Invalidates the
134
+ * cache, so the next call sees it.
135
+ */
136
+ setMode(level: InferenceConfigLevel, mode: InferenceMode | null): Promise<void>;
137
+ /** The explicit stored mode for untiered calls (core's `mode()` hook). */
138
+ mode(request: InferenceModeRequest): Promise<InferenceModeState | undefined>;
139
+ /**
140
+ * Drop cached configs: all, one tenant's (every user), or one
141
+ * `(tenantId, userId)`. Call after writing a config elsewhere.
142
+ */
143
+ invalidate(scope?: {
144
+ tenantId?: string;
145
+ userId?: string;
146
+ }): void;
147
+ }
148
+ /**
149
+ * The ambient principal: the tenancy context first, then the users session
150
+ * permission context (smrt-preferences' order). Never guessed.
151
+ */
152
+ export declare function getAmbientInferencePrincipal(): InferencePrincipal | undefined;
153
+ /**
154
+ * Create the per-user / per-tenant {@link InferenceResolver}. Register it
155
+ * with {@link registerUserInferenceResolver} (keeps #4752's validation in
156
+ * front) or `setInferenceResolver()`.
157
+ */
158
+ export declare function createUserInferenceResolver(options?: UserInferenceResolverOptions): UserInferenceResolver;
159
+ /**
160
+ * Register `resolver` behind smrt-inference's validating resolver (#4752):
161
+ * chain config is validated first, then the per-user resolver binds, then
162
+ * its `fallback` / the app config. Safe in either import order: a later
163
+ * `registerInference()` keeps this registration.
164
+ */
165
+ export declare function registerUserInferenceResolver(resolver: UserInferenceResolver): UserInferenceResolver;
166
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,291 @@
1
+ import { a as inferenceProviderBindingFor, c as inferenceProviderTargets, d as redactInferenceTarget, f as createInferenceResolver, i as InferenceProviderConfigError, l as parseInferenceProviderConfig, n as INFERENCE_PROVIDER_CONFIG_SOURCES, o as inferenceProviderConfigSecretName, r as INFERENCE_PROVIDER_PARAM_KEYS, s as inferenceProviderSource, t as INFERENCE_PROVIDER_CONFIG_SECRET_TYPE, u as redactInferenceProviderConfig } from "./chunks/provider-config-BSpIQRVM.js";
2
+ import { isInferenceTargetSource, resolveAutoTier, setInferenceResolver } from "@happyvertical/smrt-core";
3
+ import { SecretService } from "@happyvertical/smrt-secrets";
4
+ import { getCurrentTenant, withTenant } from "@happyvertical/smrt-tenancy";
5
+ import { getCurrentSessionPermissionContext } from "@happyvertical/smrt-users";
6
+ //#region src/resolver.ts
7
+ var liveResolvers = /* @__PURE__ */ new Set();
8
+ function invalidateUserInferenceResolvers(scope) {
9
+ for (const ref of [...liveResolvers]) {
10
+ const invalidate = ref.deref();
11
+ if (invalidate) invalidate(scope);
12
+ else liveResolvers.delete(ref);
13
+ }
14
+ }
15
+ var USER_INFERENCE_CACHE_TTL_MS = 3e4;
16
+ function explicitMode(layers) {
17
+ if (layers.user?.mode) return {
18
+ mode: layers.user.mode,
19
+ layer: "user"
20
+ };
21
+ if (layers.tenant?.mode) return {
22
+ mode: layers.tenant.mode,
23
+ layer: "tenant"
24
+ };
25
+ }
26
+ function text(value) {
27
+ return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
28
+ }
29
+ function getAmbientInferencePrincipal() {
30
+ const tenant = getCurrentTenant();
31
+ const tenantId = text(tenant?.tenantId);
32
+ if (tenantId) {
33
+ const userId2 = text(tenant?.userId);
34
+ return userId2 ? {
35
+ tenantId,
36
+ userId: userId2
37
+ } : { tenantId };
38
+ }
39
+ const session = getCurrentSessionPermissionContext();
40
+ const sessionTenant = text(session?.tenantId);
41
+ if (!sessionTenant) return void 0;
42
+ const userId = text(session?.userId);
43
+ return userId ? {
44
+ tenantId: sessionTenant,
45
+ userId
46
+ } : { tenantId: sessionTenant };
47
+ }
48
+ function isAbsentSecretError(error, name) {
49
+ if (!(error instanceof Error)) return false;
50
+ return error.message === `Secret '${name}' not found` || error.message === "Secret not found" || error.message === "Secret disabled" || error.message === "Secret expired";
51
+ }
52
+ var cacheKey = (tenantId, userId) => `${tenantId}\0${userId ?? ""}`;
53
+ function createUserInferenceResolver(options = {}) {
54
+ const ttlMs = options.ttlMs ?? 3e4;
55
+ const now = options.now ?? Date.now;
56
+ const principalOf = options.principal ?? getAmbientInferencePrincipal;
57
+ const cache = /* @__PURE__ */ new Map();
58
+ let secretsPromise;
59
+ const getSecrets = () => {
60
+ if (options.secrets) return Promise.resolve(options.secrets);
61
+ if (!options.db) return Promise.reject(/* @__PURE__ */ new Error("createUserInferenceResolver needs `secrets` or `db` to read stored inference configs."));
62
+ secretsPromise ??= SecretService.create({ db: options.db }).catch((error) => {
63
+ secretsPromise = void 0;
64
+ throw error;
65
+ });
66
+ return secretsPromise;
67
+ };
68
+ const inTenant = (principal, fn) => {
69
+ const current = getCurrentTenant();
70
+ if (text(current?.tenantId) === principal.tenantId && text(current?.userId) === principal.userId) return fn();
71
+ return withTenant({
72
+ tenantId: principal.tenantId,
73
+ ...principal.userId ? { userId: principal.userId } : {}
74
+ }, fn);
75
+ };
76
+ const readConfig = async (secrets, name) => {
77
+ let value;
78
+ try {
79
+ value = (await secrets.retrieve(name)).value;
80
+ } catch (error) {
81
+ if (isAbsentSecretError(error, name)) return void 0;
82
+ throw error;
83
+ }
84
+ return parseInferenceProviderConfig(value);
85
+ };
86
+ const loadLayers = async (tenantId, userId) => {
87
+ const secrets = await getSecrets();
88
+ return inTenant({
89
+ tenantId,
90
+ ...userId ? { userId } : {}
91
+ }, async () => {
92
+ const layers = {};
93
+ if (userId) layers.user = await readConfig(secrets, inferenceProviderConfigSecretName({ userId }));
94
+ layers.tenant = await readConfig(secrets, inferenceProviderConfigSecretName({}));
95
+ return layers;
96
+ });
97
+ };
98
+ const getLayers = (tenantId, userId) => {
99
+ const key = cacheKey(tenantId, userId);
100
+ const hit = cache.get(key);
101
+ if (hit && hit.expires > now()) return hit.value;
102
+ const value = loadLayers(tenantId, userId);
103
+ const entry = {
104
+ expires: now() + ttlMs,
105
+ value
106
+ };
107
+ cache.set(key, entry);
108
+ value.catch(() => {
109
+ if (cache.get(key) === entry) cache.delete(key);
110
+ });
111
+ return value;
112
+ };
113
+ const identityFor = (request) => {
114
+ const principal = principalOf();
115
+ const requested = text(request.tenantId);
116
+ if (!principal) return requested ? { tenantId: requested } : {};
117
+ if (requested && requested !== principal.tenantId) return options.allowCrossTenant ? { tenantId: requested } : {};
118
+ const tenantId = principal.tenantId;
119
+ const userId = request.userId === null ? void 0 : text(principal.userId);
120
+ return userId ? {
121
+ tenantId,
122
+ userId
123
+ } : { tenantId };
124
+ };
125
+ const invalidate = (scope) => {
126
+ if (!scope?.tenantId) {
127
+ cache.clear();
128
+ return;
129
+ }
130
+ if (scope.userId) {
131
+ cache.delete(cacheKey(scope.tenantId, scope.userId));
132
+ return;
133
+ }
134
+ const prefix = `${scope.tenantId}\0`;
135
+ for (const key of [...cache.keys()]) if (key.startsWith(prefix)) cache.delete(key);
136
+ };
137
+ const writeScope = (level) => {
138
+ const principal = principalOf();
139
+ if (!principal?.tenantId) throw new Error("Writing an inference provider config needs an authenticated tenant context.");
140
+ if (level === "user" && !principal.userId) throw new Error("Writing a user inference provider config needs a principal with a user id.");
141
+ return principal;
142
+ };
143
+ liveResolvers.add(new WeakRef(invalidate));
144
+ return {
145
+ async resolve(request, context) {
146
+ const tierResolved = request.tier === "auto" ? resolveAutoTier(context.config) : request.tier;
147
+ const { tenantId, userId } = identityFor(request);
148
+ if (tenantId) {
149
+ const layers = await getLayers(tenantId, userId);
150
+ const chosen = explicitMode(layers);
151
+ if (chosen?.mode === "off") return {
152
+ tierResolved,
153
+ target: {},
154
+ via: "resolver",
155
+ mode: "off",
156
+ unavailable: "off"
157
+ };
158
+ const candidates = [inferenceProviderTargets(layers.user)[tierResolved], inferenceProviderTargets(layers.tenant)[tierResolved]];
159
+ if (chosen) {
160
+ const target2 = candidates.find((entry) => entry?.source === chosen.mode);
161
+ if (target2) return {
162
+ tierResolved,
163
+ target: target2,
164
+ via: "resolver",
165
+ mode: chosen.mode
166
+ };
167
+ return {
168
+ tierResolved,
169
+ target: {},
170
+ via: "resolver",
171
+ mode: "off",
172
+ unavailable: "unconfigured"
173
+ };
174
+ }
175
+ const target = candidates.find(Boolean);
176
+ if (target) {
177
+ const source2 = target.source;
178
+ return {
179
+ tierResolved,
180
+ target,
181
+ via: "resolver",
182
+ ...source2 === "byo" || source2 === "local" || source2 === "hosted" ? { mode: source2 } : {}
183
+ };
184
+ }
185
+ }
186
+ const fallen = await options.fallback?.resolve(request, context) ?? context.resolveFromConfig(request);
187
+ const source = fallen.target?.source;
188
+ return {
189
+ ...fallen,
190
+ target: {
191
+ ...fallen.target,
192
+ source: isInferenceTargetSource(source) ? source : "app"
193
+ }
194
+ };
195
+ },
196
+ async mode(request) {
197
+ const { tenantId, userId } = identityFor(request);
198
+ if (!tenantId) return void 0;
199
+ const chosen = explicitMode(await getLayers(tenantId, userId));
200
+ if (!chosen) return void 0;
201
+ return chosen.mode === "off" ? {
202
+ mode: "off",
203
+ unavailable: "off"
204
+ } : { mode: chosen.mode };
205
+ },
206
+ async lookupFusion(key, request, context) {
207
+ return options.fallback?.lookupFusion?.(key, request, context);
208
+ },
209
+ async resolveBindings(bindingOptions = {}) {
210
+ const redact = bindingOptions.redact !== false;
211
+ const { tenantId, userId } = identityFor({});
212
+ if (!tenantId) return { tiers: {} };
213
+ const layers = await getLayers(tenantId, userId);
214
+ const map = {
215
+ tenantId,
216
+ ...userId ? { userId } : {},
217
+ tiers: {}
218
+ };
219
+ for (const layer of ["tenant", "user"]) {
220
+ const config = layers[layer];
221
+ if (!config) continue;
222
+ map[layer] = redact ? redactInferenceProviderConfig(config) : config;
223
+ for (const [tier, target] of Object.entries(inferenceProviderTargets(config))) map.tiers[tier] = {
224
+ ...redact ? redactInferenceTarget(target) : target,
225
+ layer
226
+ };
227
+ }
228
+ const chosen = explicitMode(layers);
229
+ if (chosen) map.mode = chosen;
230
+ return map;
231
+ },
232
+ async write(level, config) {
233
+ const principal = writeScope(level);
234
+ const parsed = parseInferenceProviderConfig(config);
235
+ const secrets = await getSecrets();
236
+ const name = inferenceProviderConfigSecretName(level === "user" ? { userId: principal.userId } : {});
237
+ await inTenant(principal, () => secrets.store(name, JSON.stringify(parsed), {
238
+ category: INFERENCE_PROVIDER_CONFIG_SECRET_TYPE,
239
+ description: `Inference provider config (${level})`
240
+ }));
241
+ invalidate(level === "user" ? {
242
+ tenantId: principal.tenantId,
243
+ userId: principal.userId
244
+ } : { tenantId: principal.tenantId });
245
+ },
246
+ async remove(level) {
247
+ const principal = writeScope(level);
248
+ const secrets = await getSecrets();
249
+ const name = inferenceProviderConfigSecretName(level === "user" ? { userId: principal.userId } : {});
250
+ const removed = await inTenant(principal, () => secrets.delete(name));
251
+ invalidate(level === "user" ? {
252
+ tenantId: principal.tenantId,
253
+ userId: principal.userId
254
+ } : { tenantId: principal.tenantId });
255
+ return removed;
256
+ },
257
+ async setMode(level, mode) {
258
+ const principal = writeScope(level);
259
+ const secrets = await getSecrets();
260
+ const name = inferenceProviderConfigSecretName(level === "user" ? { userId: principal.userId } : {});
261
+ const current = await inTenant(principal, () => readConfig(secrets, name));
262
+ const next = { ...current ?? {} };
263
+ if (mode === null) delete next.mode;
264
+ else next.mode = parseInferenceProviderConfig({ mode }).mode;
265
+ const empty = Object.keys(next).every((key) => key === "version" || key === "source" || key === "gatewayKeyAlias");
266
+ await inTenant(principal, async () => {
267
+ if (empty) {
268
+ if (current) await secrets.delete(name);
269
+ return;
270
+ }
271
+ await secrets.store(name, JSON.stringify(parseInferenceProviderConfig(next)), {
272
+ category: INFERENCE_PROVIDER_CONFIG_SECRET_TYPE,
273
+ description: `Inference provider config (${level})`
274
+ });
275
+ });
276
+ invalidate(level === "user" ? {
277
+ tenantId: principal.tenantId,
278
+ userId: principal.userId
279
+ } : { tenantId: principal.tenantId });
280
+ },
281
+ invalidate
282
+ };
283
+ }
284
+ function registerUserInferenceResolver(resolver) {
285
+ setInferenceResolver(createInferenceResolver(resolver));
286
+ return resolver;
287
+ }
288
+ //#endregion
289
+ export { INFERENCE_PROVIDER_CONFIG_SECRET_TYPE, INFERENCE_PROVIDER_CONFIG_SOURCES, INFERENCE_PROVIDER_PARAM_KEYS, InferenceProviderConfigError, USER_INFERENCE_CACHE_TTL_MS, createUserInferenceResolver, getAmbientInferencePrincipal, inferenceProviderBindingFor, inferenceProviderConfigSecretName, inferenceProviderSource, inferenceProviderTargets, invalidateUserInferenceResolvers, parseInferenceProviderConfig, redactInferenceProviderConfig, redactInferenceTarget, registerUserInferenceResolver };
290
+
291
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","names":["userId","target","source"],"sources":["../src/resolver.ts"],"sourcesContent":["/**\n * `@happyvertical/smrt-inference/resolver` — per-user and per-tenant\n * inference bindings over smrt-secrets (#4756). Node-only: it reads secrets\n * and the ambient principal, so it stays off the browser-safe root entry.\n *\n * Precedence for each tier, highest first:\n * 1. the current user's stored `inference.provider-config` (tier binding,\n * then the user's default binding);\n * 2. the tenant's stored config (same order);\n * 3. `fallback` (another resolver), else the app's `inference` block;\n * 4. unbound: the configured client (`SMRT_AI_*` / the process `ai` block).\n * Every resolution carries `target.source` (`byo | local | hosted | app`),\n * which core records as the `source` usage tag.\n *\n * Inference mode (#4757): a stored config may carry `mode`. The user's mode,\n * else the tenant's, applies: `off` answers every tier (and untiered calls,\n * through `mode()`) as unavailable; `byo` / `local` / `hosted` bind only a\n * stored binding of that source (user, then tenant) and report\n * `unconfigured` when there is none, never falling through to app config.\n */\nimport {\n type InferenceMode,\n type InferenceModeRequest,\n type InferenceModeState,\n type InferenceRequest,\n type InferenceResolution,\n type InferenceResolver,\n type InferenceResolverContext,\n type InferenceTarget,\n type InferenceTier,\n isInferenceTargetSource,\n resolveAutoTier,\n setInferenceResolver,\n} from '@happyvertical/smrt-core';\nimport { SecretService } from '@happyvertical/smrt-secrets';\nimport { getCurrentTenant, withTenant } from '@happyvertical/smrt-tenancy';\nimport { getCurrentSessionPermissionContext } from '@happyvertical/smrt-users';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport {\n INFERENCE_PROVIDER_CONFIG_SECRET_TYPE,\n type InferenceProviderConfig,\n inferenceProviderConfigSecretName,\n inferenceProviderTargets,\n parseInferenceProviderConfig,\n type RedactedInferenceProviderConfig,\n redactInferenceProviderConfig,\n redactInferenceTarget,\n} from './provider-config.js';\nimport { createInferenceResolver } from './register.js';\n\nexport * from './provider-config.js';\n\n/** `invalidate()` of every live resolver this process created. */\nconst liveResolvers = new Set<WeakRef<UserInferenceResolver['invalidate']>>();\n\n/**\n * Drop cached configs in every user resolver this process created (all, one\n * tenant, or one user). Writers outside a resolver (hosted provisioning,\n * #4759) call this after storing a config; other processes see the change\n * when their cache entry expires (`ttlMs`, 30 s by default).\n */\nexport function invalidateUserInferenceResolvers(scope?: {\n tenantId?: string;\n userId?: string;\n}): void {\n for (const ref of [...liveResolvers]) {\n const invalidate = ref.deref();\n if (invalidate) invalidate(scope);\n else liveResolvers.delete(ref);\n }\n}\n\n/** Default cache lifetime of decrypted configs, per `(tenantId, userId)`. */\nexport const USER_INFERENCE_CACHE_TTL_MS = 30_000;\n\n/**\n * The subset of `SecretService` the resolver uses. Reads go through\n * `retrieve()` (audited, access-counted); writes through `store()`.\n */\nexport interface InferenceSecretStore {\n retrieve(name: string): Promise<{ value: string }>;\n store(\n name: string,\n value: string,\n options?: { category?: string; description?: string },\n ): Promise<unknown>;\n delete(name: string): Promise<boolean>;\n}\n\n/** Who a resolution acts for. */\nexport interface InferencePrincipal {\n tenantId: string;\n /** Absent for service principals and background jobs: no user layer. */\n userId?: string;\n}\n\n/** Options for {@link createUserInferenceResolver}. */\nexport interface UserInferenceResolverOptions {\n /** Database for a `SecretService` built on first use (when no `secrets`). */\n db?: DatabaseInterface;\n /** The secret store; defaults to `SecretService.create({ db })`. */\n secrets?: InferenceSecretStore | SecretService;\n /**\n * Resolver for tiers neither the user nor the tenant binds. Default: the\n * app's `inference` block through core's built-in resolution.\n */\n fallback?: InferenceResolver;\n /** Cache lifetime in ms (default {@link USER_INFERENCE_CACHE_TTL_MS}). */\n ttlMs?: number;\n /** Clock seam for tests. */\n now?: () => number;\n /**\n * Principal seam for tests and hosts with their own identity. Default:\n * the ambient principal, read the way smrt-preferences reads it.\n */\n principal?: () => InferencePrincipal | undefined;\n /**\n * Let a request for another tenant than the principal's (an object of\n * tenant B used by a principal of tenant A) read tenant B's stored config.\n * Default `false`: such a request skips the stored layers and falls through\n * to the app config, because reading B's key for A's action is a\n * cross-tenant read. Principal-less contexts (jobs) always use the\n * request's tenant.\n */\n allowCrossTenant?: boolean;\n}\n\n/** The stored layers for one `(tenantId, userId)`. */\ninterface Layers {\n user?: InferenceProviderConfig;\n tenant?: InferenceProviderConfig;\n}\n\n/** The explicit mode that applies: the user's, else the tenant's. */\nfunction explicitMode(\n layers: Layers,\n): { mode: InferenceMode; layer: 'user' | 'tenant' } | undefined {\n if (layers.user?.mode) return { mode: layers.user.mode, layer: 'user' };\n if (layers.tenant?.mode) return { mode: layers.tenant.mode, layer: 'tenant' };\n return undefined;\n}\n\n/** One tier of {@link InferenceBindingMap}. */\nexport type InferenceBindingEntry = (\n | InferenceTarget\n | (Omit<InferenceTarget, 'apiKey'> & { hasApiKey: boolean })\n) & { layer: 'user' | 'tenant' };\n\n/** What {@link UserInferenceResolver.resolveBindings} returns. */\nexport interface InferenceBindingMap {\n tenantId?: string;\n userId?: string;\n /** Per tier: the stored binding that answers it (absent: app config). */\n tiers: Partial<Record<InferenceTier, InferenceBindingEntry>>;\n /** The stored configs themselves, redacted unless `redact: false`. */\n user?: InferenceProviderConfig | RedactedInferenceProviderConfig;\n tenant?: InferenceProviderConfig | RedactedInferenceProviderConfig;\n /** The explicit mode that applies (#4757) and the layer that set it. */\n mode?: { mode: InferenceMode; layer: 'user' | 'tenant' };\n}\n\n/** The scope a config is written to. */\nexport type InferenceConfigLevel = 'user' | 'tenant';\n\n/** A resolver plus the read/write helpers the settings panel uses. */\nexport interface UserInferenceResolver extends InferenceResolver {\n /**\n * The tier → target map for the ambient principal (never a caller-chosen\n * tenant or user), without\n * keys unless `redact: false` (server-only; never send that to a client).\n */\n resolveBindings(options?: { redact?: boolean }): Promise<InferenceBindingMap>;\n /**\n * Validate and store a config for the current principal through\n * `SecretService.store()`, then invalidate the cache. `user` needs a\n * principal with a user id. Authorization (who may write the tenant\n * config) is the host's server action's job.\n */\n write(level: InferenceConfigLevel, config: unknown): Promise<void>;\n /** Delete the stored config at `level` for the current principal. */\n remove(level: InferenceConfigLevel): Promise<boolean>;\n /**\n * Set (or with `null` clear) the stored mode at `level` (#4757), keeping\n * the stored binding. Works without a key: a mode-only config is valid.\n * A config left with neither binding nor mode is deleted. Invalidates the\n * cache, so the next call sees it.\n */\n setMode(\n level: InferenceConfigLevel,\n mode: InferenceMode | null,\n ): Promise<void>;\n /** The explicit stored mode for untiered calls (core's `mode()` hook). */\n mode(request: InferenceModeRequest): Promise<InferenceModeState | undefined>;\n /**\n * Drop cached configs: all, one tenant's (every user), or one\n * `(tenantId, userId)`. Call after writing a config elsewhere.\n */\n invalidate(scope?: { tenantId?: string; userId?: string }): void;\n}\n\nfunction text(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() !== ''\n ? value.trim()\n : undefined;\n}\n\n/**\n * The ambient principal: the tenancy context first, then the users session\n * permission context (smrt-preferences' order). Never guessed.\n */\nexport function getAmbientInferencePrincipal(): InferencePrincipal | undefined {\n const tenant = getCurrentTenant();\n const tenantId = text(tenant?.tenantId);\n if (tenantId) {\n const userId = text(tenant?.userId);\n return userId ? { tenantId, userId } : { tenantId };\n }\n const session = getCurrentSessionPermissionContext();\n const sessionTenant = text(session?.tenantId);\n if (!sessionTenant) return undefined;\n const userId = text(session?.userId);\n return userId\n ? { tenantId: sessionTenant, userId }\n : { tenantId: sessionTenant };\n}\n\nfunction isAbsentSecretError(error: unknown, name: string): boolean {\n if (!(error instanceof Error)) return false;\n return (\n error.message === `Secret '${name}' not found` ||\n error.message === 'Secret not found' ||\n error.message === 'Secret disabled' ||\n error.message === 'Secret expired'\n );\n}\n\nconst cacheKey = (tenantId: string, userId: string | undefined) =>\n `${tenantId}\\u0000${userId ?? ''}`;\n\n/**\n * Create the per-user / per-tenant {@link InferenceResolver}. Register it\n * with {@link registerUserInferenceResolver} (keeps #4752's validation in\n * front) or `setInferenceResolver()`.\n */\nexport function createUserInferenceResolver(\n options: UserInferenceResolverOptions = {},\n): UserInferenceResolver {\n const ttlMs = options.ttlMs ?? USER_INFERENCE_CACHE_TTL_MS;\n const now = options.now ?? Date.now;\n const principalOf = options.principal ?? getAmbientInferencePrincipal;\n const cache = new Map<string, { expires: number; value: Promise<Layers> }>();\n let secretsPromise: Promise<InferenceSecretStore> | undefined;\n\n const getSecrets = (): Promise<InferenceSecretStore> => {\n if (options.secrets) return Promise.resolve(options.secrets);\n if (!options.db) {\n return Promise.reject(\n new Error(\n 'createUserInferenceResolver needs `secrets` or `db` to read stored inference configs.',\n ),\n );\n }\n secretsPromise ??= SecretService.create({ db: options.db }).catch(\n (error: unknown) => {\n secretsPromise = undefined;\n throw error;\n },\n );\n return secretsPromise;\n };\n\n /** Run `fn` in a tenancy context for `principal` (audit keeps the user). */\n const inTenant = <T>(\n principal: InferencePrincipal,\n fn: () => Promise<T>,\n ): Promise<T> => {\n const current = getCurrentTenant();\n if (\n text(current?.tenantId) === principal.tenantId &&\n text(current?.userId) === principal.userId\n ) {\n return fn();\n }\n return withTenant(\n {\n tenantId: principal.tenantId,\n ...(principal.userId ? { userId: principal.userId } : {}),\n },\n fn,\n );\n };\n\n const readConfig = async (\n secrets: InferenceSecretStore,\n name: string,\n ): Promise<InferenceProviderConfig | undefined> => {\n let value: string;\n try {\n value = (await secrets.retrieve(name)).value;\n } catch (error) {\n if (isAbsentSecretError(error, name)) return undefined;\n throw error;\n }\n return parseInferenceProviderConfig(value);\n };\n\n const loadLayers = async (\n tenantId: string,\n userId: string | undefined,\n ): Promise<Layers> => {\n const secrets = await getSecrets();\n return inTenant({ tenantId, ...(userId ? { userId } : {}) }, async () => {\n const layers: Layers = {};\n if (userId) {\n layers.user = await readConfig(\n secrets,\n inferenceProviderConfigSecretName({ userId }),\n );\n }\n layers.tenant = await readConfig(\n secrets,\n inferenceProviderConfigSecretName({}),\n );\n return layers;\n });\n };\n\n const getLayers = (\n tenantId: string,\n userId: string | undefined,\n ): Promise<Layers> => {\n const key = cacheKey(tenantId, userId);\n const hit = cache.get(key);\n if (hit && hit.expires > now()) return hit.value;\n const value = loadLayers(tenantId, userId);\n const entry = { expires: now() + ttlMs, value };\n cache.set(key, entry);\n value.catch(() => {\n if (cache.get(key) === entry) cache.delete(key);\n });\n return value;\n };\n\n /**\n * Whose stored layers answer this request. With a principal: its tenant\n * (or the request's when they match), its user unless the request says\n * `userId: null` (a client shared beyond one user, e.g. a long-lived\n * agent). A request for another tenant reads nothing stored unless\n * `allowCrossTenant`. Without a principal: the request's tenant, no user.\n */\n const identityFor = (\n request: Pick<InferenceRequest, 'tenantId' | 'userId'>,\n ): { tenantId?: string; userId?: string } => {\n const principal = principalOf();\n const requested = text(request.tenantId);\n if (!principal) return requested ? { tenantId: requested } : {};\n if (requested && requested !== principal.tenantId) {\n return options.allowCrossTenant ? { tenantId: requested } : {};\n }\n const tenantId = principal.tenantId;\n const userId = request.userId === null ? undefined : text(principal.userId);\n return userId ? { tenantId, userId } : { tenantId };\n };\n\n const invalidate: UserInferenceResolver['invalidate'] = (scope) => {\n if (!scope?.tenantId) {\n cache.clear();\n return;\n }\n if (scope.userId) {\n cache.delete(cacheKey(scope.tenantId, scope.userId));\n return;\n }\n const prefix = `${scope.tenantId}\\u0000`;\n for (const key of [...cache.keys()]) {\n if (key.startsWith(prefix)) cache.delete(key);\n }\n };\n\n const writeScope = (level: InferenceConfigLevel): InferencePrincipal => {\n const principal = principalOf();\n if (!principal?.tenantId) {\n throw new Error(\n 'Writing an inference provider config needs an authenticated tenant context.',\n );\n }\n if (level === 'user' && !principal.userId) {\n throw new Error(\n 'Writing a user inference provider config needs a principal with a user id.',\n );\n }\n return principal;\n };\n\n liveResolvers.add(new WeakRef(invalidate));\n\n return {\n async resolve(\n request: InferenceRequest,\n context: InferenceResolverContext,\n ): Promise<InferenceResolution | undefined> {\n const tierResolved =\n request.tier === 'auto'\n ? resolveAutoTier(context.config)\n : request.tier;\n const { tenantId, userId } = identityFor(request);\n if (tenantId) {\n const layers = await getLayers(tenantId, userId);\n const chosen = explicitMode(layers);\n if (chosen?.mode === 'off') {\n return {\n tierResolved,\n target: {},\n via: 'resolver',\n mode: 'off',\n unavailable: 'off',\n };\n }\n const candidates = [\n inferenceProviderTargets(layers.user)[tierResolved],\n inferenceProviderTargets(layers.tenant)[tierResolved],\n ];\n if (chosen) {\n // An explicit mode binds only its own kind of stored binding.\n const target = candidates.find(\n (entry) => entry?.source === chosen.mode,\n );\n if (target) {\n return { tierResolved, target, via: 'resolver', mode: chosen.mode };\n }\n return {\n tierResolved,\n target: {},\n via: 'resolver',\n mode: 'off',\n unavailable: 'unconfigured',\n };\n }\n const target = candidates.find(Boolean);\n if (target) {\n const source = target.source;\n return {\n tierResolved,\n target,\n via: 'resolver',\n ...(source === 'byo' || source === 'local' || source === 'hosted'\n ? { mode: source }\n : {}),\n };\n }\n }\n const fallen =\n (await options.fallback?.resolve(request, context)) ??\n context.resolveFromConfig(request);\n const source = fallen.target?.source;\n return {\n ...fallen,\n target: {\n ...fallen.target,\n source: isInferenceTargetSource(source) ? source : 'app',\n },\n };\n },\n\n async mode(request) {\n const { tenantId, userId } = identityFor(request);\n if (!tenantId) return undefined;\n const chosen = explicitMode(await getLayers(tenantId, userId));\n if (!chosen) return undefined;\n return chosen.mode === 'off'\n ? { mode: 'off', unavailable: 'off' }\n : { mode: chosen.mode };\n },\n\n // Fusions are app-scope only (#4753): stored user and tenant configs\n // never define one, so the lookup is the fallback's (override rows,\n // #4800) or none (core then reads `inference.fusions`).\n async lookupFusion(key, request, context) {\n return options.fallback?.lookupFusion?.(key, request, context);\n },\n\n async resolveBindings(bindingOptions = {}) {\n const redact = bindingOptions.redact !== false;\n // Identity is ambient only: no caller-chosen tenant or user.\n const { tenantId, userId } = identityFor({});\n if (!tenantId) return { tiers: {} };\n const layers = await getLayers(tenantId, userId);\n const map: InferenceBindingMap = {\n tenantId,\n ...(userId ? { userId } : {}),\n tiers: {},\n };\n for (const layer of ['tenant', 'user'] as const) {\n const config = layers[layer];\n if (!config) continue;\n map[layer] = redact ? redactInferenceProviderConfig(config) : config;\n for (const [tier, target] of Object.entries(\n inferenceProviderTargets(config),\n )) {\n map.tiers[tier as InferenceTier] = {\n ...(redact ? redactInferenceTarget(target) : target),\n layer,\n };\n }\n }\n const chosen = explicitMode(layers);\n if (chosen) map.mode = chosen;\n return map;\n },\n\n async write(level, config) {\n const principal = writeScope(level);\n const parsed = parseInferenceProviderConfig(config);\n const secrets = await getSecrets();\n const name = inferenceProviderConfigSecretName(\n level === 'user' ? { userId: principal.userId } : {},\n );\n await inTenant(principal, () =>\n secrets.store(name, JSON.stringify(parsed), {\n category: INFERENCE_PROVIDER_CONFIG_SECRET_TYPE,\n description: `Inference provider config (${level})`,\n }),\n );\n invalidate(\n level === 'user'\n ? { tenantId: principal.tenantId, userId: principal.userId }\n : { tenantId: principal.tenantId },\n );\n },\n\n async remove(level) {\n const principal = writeScope(level);\n const secrets = await getSecrets();\n const name = inferenceProviderConfigSecretName(\n level === 'user' ? { userId: principal.userId } : {},\n );\n const removed = await inTenant(principal, () => secrets.delete(name));\n invalidate(\n level === 'user'\n ? { tenantId: principal.tenantId, userId: principal.userId }\n : { tenantId: principal.tenantId },\n );\n return removed;\n },\n\n async setMode(level, mode) {\n const principal = writeScope(level);\n const secrets = await getSecrets();\n const name = inferenceProviderConfigSecretName(\n level === 'user' ? { userId: principal.userId } : {},\n );\n // Read fresh (not the cache) so a concurrent binding write is kept.\n const current = await inTenant(principal, () =>\n readConfig(secrets, name),\n );\n const next: InferenceProviderConfig = { ...(current ?? {}) };\n if (mode === null) delete next.mode;\n else next.mode = parseInferenceProviderConfig({ mode }).mode;\n const empty = Object.keys(next).every(\n (key) =>\n key === 'version' || key === 'source' || key === 'gatewayKeyAlias',\n );\n await inTenant(principal, async () => {\n if (empty) {\n if (current) await secrets.delete(name);\n return;\n }\n await secrets.store(\n name,\n JSON.stringify(parseInferenceProviderConfig(next)),\n {\n category: INFERENCE_PROVIDER_CONFIG_SECRET_TYPE,\n description: `Inference provider config (${level})`,\n },\n );\n });\n invalidate(\n level === 'user'\n ? { tenantId: principal.tenantId, userId: principal.userId }\n : { tenantId: principal.tenantId },\n );\n },\n\n invalidate,\n };\n}\n\n/**\n * Register `resolver` behind smrt-inference's validating resolver (#4752):\n * chain config is validated first, then the per-user resolver binds, then\n * its `fallback` / the app config. Safe in either import order: a later\n * `registerInference()` keeps this registration.\n */\nexport function registerUserInferenceResolver(\n resolver: UserInferenceResolver,\n): UserInferenceResolver {\n setInferenceResolver(createInferenceResolver(resolver));\n return resolver;\n}\n"],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @happyvertical/smrt-inference/server — server half of the inference
3
+ * settings screen (#4754). Node-only (it reuses the `./node` doctor and the
4
+ * AI SDK provider list).
5
+ *
6
+ * - `InferenceSettingsService`: rows for `InferenceSettingsPanel`, writes
7
+ * through the authorizer-gated `InferenceOverrideService`, test
8
+ * connection, doctor, usage, local discovery and provider options.
9
+ * - `createInferenceOverrideResolver()`: applies stored bindings at call time.
10
+ * - The origin-bound key rule (`bindInferenceKey`, `inferenceKeyFor`); keys
11
+ * are stored by the host through smrt-secrets, never here.
12
+ * - The smrt-preferences kind `inference` for user choices.
13
+ */
14
+ import './__smrt-register__.js';
15
+ export { APP_INFERENCE_SCOPE_ID, InferenceOverride, type InferenceOverrideOptions, } from './models/InferenceOverride.js';
16
+ export { InferenceOverrideCollection, type InferenceOverrideScopeType, } from './models/InferenceOverrideCollection.js';
17
+ export { bindInferenceKey, InferenceKeyOriginError, type InferenceKeyRecord, inferenceKeyFor, inferenceKeyOrigin, inferenceProviderConfigFromKey, REDACTED_KEY, redactInferenceSecret, } from './settings/keys.js';
18
+ export { buildInferenceOverrideLayers, type InferenceOverrideLayers, type InferenceOverrideRows, type InferenceSettingsConfig, loadInferenceOverrideLayers, mergeSettingsConfigs, readInferenceOverrideRows, } from './settings/layers.js';
19
+ export { assertValidInferenceScope, InferenceOverrideAuthorizationError, type InferenceOverrideAuthorizer, InferenceOverrideService, type InferenceOverrideServiceOptions, type InferenceOverrideWriteRequest, InferenceTenantTargetNotAllowedError, type InferenceTenantTargetPolicy, type InferenceTenantTargetRequest, InvalidInferenceScopeError, } from './settings/override-service.js';
20
+ export { CUSTOMIZE_INFERENCE_PERMISSION, createInferencePreferences, INFERENCE_PERMISSION_DEFINITIONS, INFERENCE_PREFERENCE_KIND, INFERENCE_PREFERENCE_SURFACE, type InferencePreferenceIssue, type InferencePreferenceRead, type InferencePreferenceStoreLike, type InferencePreferences, type InferencePreferencesApi, inferencePreferenceKind, PERSONALIZE_INFERENCE_PERMISSION, validateInferencePreferences, } from './settings/preferences.js';
21
+ export { createInferenceOverrideResolver, type InferenceOverrideResolverOptions, } from './settings/resolver.js';
22
+ export { type InferenceAliasSetting, InferenceBindingInUseError, type InferenceConnectionInput, type InferenceConnectionResult, type InferenceDefaultTierSetting, type InferenceFusionSetting, type InferenceProviderOption, InferenceSettingsConfigError, type InferenceSettingsLevel, InferenceSettingsService, type InferenceSettingsServiceOptions, type InferenceTierSettingsRow, type InferenceTranscriptSettings, type InferenceUsageReportDimension, type RegisteredFusionLike, } from './settings/settings-service.js';
23
+ export { DEFAULT_TIER_BINDING, describeInferenceTarget, INFERENCE_MODES, type InferenceBindingId, InferenceBindingValueError, type InferenceMode, type InferenceTranscriptSettingsValue, inferenceTargetRef, isAllowedByList, matchesAllowPattern, normalizeTranscriptSettings, parseInferenceBinding, stripKeyMembers, TRANSCRIPTS_BINDING, tierBinding, } from './settings/targets.js';
24
+ export { applyStoredTranscriptSettings, loadInferenceTranscriptSettings, storedTranscriptSettings, } from './settings/transcripts.js';
25
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,wBAAwB,CAAC;AAEhC,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,KAAK,wBAAwB,GAC9B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,2BAA2B,EAC3B,KAAK,0BAA0B,GAChC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,kBAAkB,EACvB,eAAe,EACf,kBAAkB,EAClB,8BAA8B,EAC9B,YAAY,EACZ,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,4BAA4B,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,2BAA2B,EAC3B,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,yBAAyB,EACzB,mCAAmC,EACnC,KAAK,2BAA2B,EAChC,wBAAwB,EACxB,KAAK,+BAA+B,EACpC,KAAK,6BAA6B,EAClC,oCAAoC,EACpC,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,0BAA0B,GAC3B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,8BAA8B,EAC9B,0BAA0B,EAC1B,gCAAgC,EAChC,yBAAyB,EACzB,4BAA4B,EAC5B,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,4BAA4B,EACjC,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,uBAAuB,EACvB,gCAAgC,EAChC,4BAA4B,GAC7B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,+BAA+B,EAC/B,KAAK,gCAAgC,GACtC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,qBAAqB,EAC1B,0BAA0B,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,4BAA4B,EAC5B,KAAK,sBAAsB,EAC3B,wBAAwB,EACxB,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,EAC7B,KAAK,2BAA2B,EAChC,KAAK,6BAA6B,EAClC,KAAK,oBAAoB,GAC1B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,EACf,KAAK,kBAAkB,EACvB,0BAA0B,EAC1B,KAAK,aAAa,EAClB,KAAK,gCAAgC,EACrC,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,2BAA2B,EAC3B,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACnB,WAAW,GACZ,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,6BAA6B,EAC7B,+BAA+B,EAC/B,wBAAwB,GACzB,MAAM,2BAA2B,CAAC"}