@shipfox/api-agent 5.0.0 → 6.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +30 -0
- package/dist/core/custom-model-provider-config-service.d.ts +4 -0
- package/dist/core/custom-model-provider-config-service.d.ts.map +1 -1
- package/dist/core/custom-model-provider-config-service.js +19 -16
- package/dist/core/custom-model-provider-config-service.js.map +1 -1
- package/dist/core/model-provider-config-service.d.ts +4 -0
- package/dist/core/model-provider-config-service.d.ts.map +1 -1
- package/dist/core/model-provider-config-service.js +10 -8
- package/dist/core/model-provider-config-service.js.map +1 -1
- package/dist/core/resolve-runtime-credentials.d.ts +6 -2
- package/dist/core/resolve-runtime-credentials.d.ts.map +1 -1
- package/dist/core/resolve-runtime-credentials.js +10 -5
- package/dist/core/resolve-runtime-credentials.js.map +1 -1
- package/dist/core/secrets-client.d.ts +4 -0
- package/dist/core/secrets-client.d.ts.map +1 -0
- package/dist/core/secrets-client.js +6 -0
- package/dist/core/secrets-client.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -13
- package/dist/index.js.map +1 -1
- package/dist/presentation/e2eRoutes/create-model-provider.d.ts +2 -1
- package/dist/presentation/e2eRoutes/create-model-provider.d.ts.map +1 -1
- package/dist/presentation/e2eRoutes/create-model-provider.js +46 -45
- package/dist/presentation/e2eRoutes/create-model-provider.js.map +1 -1
- package/dist/presentation/e2eRoutes/index.d.ts +2 -0
- package/dist/presentation/e2eRoutes/index.d.ts.map +1 -1
- package/dist/presentation/e2eRoutes/index.js +9 -6
- package/dist/presentation/e2eRoutes/index.js.map +1 -1
- package/dist/presentation/index.d.ts +1 -1
- package/dist/presentation/index.d.ts.map +1 -1
- package/dist/presentation/index.js +1 -1
- package/dist/presentation/index.js.map +1 -1
- package/dist/presentation/inter-module.d.ts +7 -0
- package/dist/presentation/inter-module.d.ts.map +1 -0
- package/dist/presentation/inter-module.js +45 -0
- package/dist/presentation/inter-module.js.map +1 -0
- package/dist/presentation/routes/create-custom-model-provider.d.ts +2 -1
- package/dist/presentation/routes/create-custom-model-provider.d.ts.map +1 -1
- package/dist/presentation/routes/create-custom-model-provider.js +39 -35
- package/dist/presentation/routes/create-custom-model-provider.js.map +1 -1
- package/dist/presentation/routes/delete-model-provider-config.d.ts +2 -1
- package/dist/presentation/routes/delete-model-provider-config.d.ts.map +1 -1
- package/dist/presentation/routes/delete-model-provider-config.js +33 -29
- package/dist/presentation/routes/delete-model-provider-config.js.map +1 -1
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.d.ts +2 -1
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.d.ts.map +1 -1
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.js +32 -28
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.js.map +1 -1
- package/dist/presentation/routes/errors.d.ts.map +1 -1
- package/dist/presentation/routes/errors.js +13 -12
- package/dist/presentation/routes/errors.js.map +1 -1
- package/dist/presentation/routes/index.d.ts +2 -0
- package/dist/presentation/routes/index.d.ts.map +1 -1
- package/dist/presentation/routes/index.js +32 -29
- package/dist/presentation/routes/index.js.map +1 -1
- package/dist/presentation/routes/update-custom-model-provider.d.ts +2 -1
- package/dist/presentation/routes/update-custom-model-provider.d.ts.map +1 -1
- package/dist/presentation/routes/update-custom-model-provider.js +41 -37
- package/dist/presentation/routes/update-custom-model-provider.js.map +1 -1
- package/dist/presentation/routes/upsert-model-provider-config.d.ts +2 -1
- package/dist/presentation/routes/upsert-model-provider-config.d.ts.map +1 -1
- package/dist/presentation/routes/upsert-model-provider-config.js +46 -42
- package/dist/presentation/routes/upsert-model-provider-config.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +11 -8
- package/src/core/custom-model-provider-config-service.ts +50 -34
- package/src/core/model-provider-config-service.test.ts +1 -3
- package/src/core/model-provider-config-service.ts +18 -15
- package/src/core/resolve-runtime-credentials.test.ts +3 -3
- package/src/core/resolve-runtime-credentials.ts +22 -8
- package/src/core/secrets-client.ts +13 -0
- package/src/index.ts +13 -8
- package/src/presentation/e2eRoutes/create-model-provider.ts +41 -39
- package/src/presentation/e2eRoutes/index.ts +6 -4
- package/src/presentation/index.ts +1 -1
- package/src/presentation/inter-module.ts +78 -0
- package/src/presentation/routes/create-custom-model-provider.ts +36 -30
- package/src/presentation/routes/delete-model-provider-config.ts +25 -22
- package/src/presentation/routes/discover-custom-model-provider-models-by-slug.ts +31 -25
- package/src/presentation/routes/errors.ts +11 -11
- package/src/presentation/routes/index.ts +32 -27
- package/src/presentation/routes/model-provider-config.test.ts +1 -1
- package/src/presentation/routes/update-custom-model-provider.ts +40 -34
- package/src/presentation/routes/upsert-model-provider-config.ts +43 -37
- package/test/fixtures/secrets-client.ts +80 -0
- package/test/globalSetup.ts +0 -9
- package/test/setup.ts +8 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
$ shipfox-swc
|
|
2
|
-
Successfully compiled:
|
|
2
|
+
Successfully compiled: 50 files with swc (536.61ms)
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @shipfox/api-agent
|
|
2
2
|
|
|
3
|
+
## 6.0.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- a42b575: Exposes Secrets through its inter-module contract and migrates Agent, integrations, and Workflows consumers.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 0bb82a4: Adds the Agent and Integrations inter-module APIs, moving Workflows agent configuration, runtime credential resolution, and integration consumers behind producer-owned clients.
|
|
12
|
+
- f73da5d: Enforces bounded API context imports and routes inter-module consumers through producer contracts.
|
|
13
|
+
- Updated dependencies [0bb82a4]
|
|
14
|
+
- Updated dependencies [54ce48b]
|
|
15
|
+
- Updated dependencies [c0162b0]
|
|
16
|
+
- Updated dependencies [7ac43a4]
|
|
17
|
+
- Updated dependencies [a01e917]
|
|
18
|
+
- Updated dependencies [a42b575]
|
|
19
|
+
- Updated dependencies [8bdc149]
|
|
20
|
+
- Updated dependencies [3810996]
|
|
21
|
+
- Updated dependencies [b00ed29]
|
|
22
|
+
- Updated dependencies [8aa7cd3]
|
|
23
|
+
- Updated dependencies [81f9544]
|
|
24
|
+
- @shipfox/api-agent-dto@6.0.0
|
|
25
|
+
- @shipfox/node-module@0.4.0
|
|
26
|
+
- @shipfox/node-drizzle@0.3.2
|
|
27
|
+
- @shipfox/redact@0.2.3
|
|
28
|
+
- @shipfox/api-secrets-dto@6.0.0
|
|
29
|
+
- @shipfox/api-auth-context@6.0.0
|
|
30
|
+
- @shipfox/node-fastify@0.2.4
|
|
31
|
+
- @shipfox/inter-module@0.2.0
|
|
32
|
+
|
|
3
33
|
## 5.0.0
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type CreateCustomModelProviderBodyDto, type DiscoverCustomModelProviderModelsBodyDto, type DiscoverCustomModelProviderModelsBySlugBodyDto, type ModelProviderRef, type UpdateCustomModelProviderBodyDto } from '@shipfox/api-agent-dto';
|
|
2
2
|
import type { ModelProviderConfig } from './entities/model-provider-config.js';
|
|
3
3
|
import { probeCustomModelProviderCredentials } from './model-provider-validation.js';
|
|
4
|
+
import { type AgentSecretsClient } from './secrets-client.js';
|
|
4
5
|
export interface CreateCustomModelProviderConfigParams {
|
|
5
6
|
workspaceId: string;
|
|
6
7
|
body: CreateCustomModelProviderBodyDto;
|
|
@@ -15,6 +16,7 @@ export interface UpdateCustomModelProviderConfigParams {
|
|
|
15
16
|
}
|
|
16
17
|
export interface CustomModelProviderConfigServiceOptions {
|
|
17
18
|
probe?: typeof probeCustomModelProviderCredentials | undefined;
|
|
19
|
+
secrets?: AgentSecretsClient | undefined;
|
|
18
20
|
}
|
|
19
21
|
export declare function createCustomModelProviderConfig(params: CreateCustomModelProviderConfigParams, options?: CustomModelProviderConfigServiceOptions): Promise<ModelProviderConfig>;
|
|
20
22
|
export declare function updateCustomModelProviderConfig(params: UpdateCustomModelProviderConfigParams, options?: CustomModelProviderConfigServiceOptions): Promise<ModelProviderConfig>;
|
|
@@ -22,5 +24,7 @@ export declare function resolveCustomModelProviderDiscoveryParams(params: {
|
|
|
22
24
|
workspaceId: string;
|
|
23
25
|
providerId: ModelProviderRef;
|
|
24
26
|
body: DiscoverCustomModelProviderModelsBySlugBodyDto;
|
|
27
|
+
}, options?: {
|
|
28
|
+
secrets?: AgentSecretsClient | undefined;
|
|
25
29
|
}): Promise<DiscoverCustomModelProviderModelsBodyDto>;
|
|
26
30
|
//# sourceMappingURL=custom-model-provider-config-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-model-provider-config-service.d.ts","sourceRoot":"","sources":["../../src/core/custom-model-provider-config-service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gCAAgC,EAKrC,KAAK,wCAAwC,EAC7C,KAAK,8CAA8C,EACnD,KAAK,gBAAgB,EACrB,KAAK,gCAAgC,EAEtC,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"custom-model-provider-config-service.d.ts","sourceRoot":"","sources":["../../src/core/custom-model-provider-config-service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gCAAgC,EAKrC,KAAK,wCAAwC,EAC7C,KAAK,8CAA8C,EACnD,KAAK,gBAAgB,EACrB,KAAK,gCAAgC,EAEtC,MAAM,wBAAwB,CAAC;AAehC,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,qCAAqC,CAAC;AAQ7E,OAAO,EAEL,mCAAmC,EAEpC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAC,KAAK,kBAAkB,EAA4B,MAAM,qBAAqB,CAAC;AAEvF,MAAM,WAAW,qCAAqC;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,gCAAgC,CAAC;IACvC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,qCAAqC;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,IAAI,EAAE,gCAAgC,CAAC;IACvC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,uCAAuC;IACtD,KAAK,CAAC,EAAE,OAAO,mCAAmC,GAAG,SAAS,CAAC;IAC/D,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;CAC1C;AASD,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,qCAAqC,EAC7C,OAAO,GAAE,uCAA4C,GACpD,OAAO,CAAC,mBAAmB,CAAC,CA0E9B;AAED,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,qCAAqC,EAC7C,OAAO,GAAE,uCAA4C,GACpD,OAAO,CAAC,mBAAmB,CAAC,CAqG9B;AAED,wBAAsB,yCAAyC,CAC7D,MAAM,EAAE;IACN,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,IAAI,EAAE,8CAA8C,CAAC;CACtD,EACD,OAAO,GAAE;IAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAA;CAAM,GACvD,OAAO,CAAC,wCAAwC,CAAC,CA4BnD"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { DEFAULT_AGENT_THINKING } from '@shipfox/api-agent-dto';
|
|
2
|
-
import { deleteSecrets, getSecretsByNamespace, setSecrets } from '@shipfox/api-secrets';
|
|
3
2
|
import { assertEgressAllowed } from '@shipfox/node-egress-guard';
|
|
4
3
|
import { deleteModelProviderConfig, getModelProviderConfig, insertCustomModelProviderConfig, upsertModelProviderConfig } from '#db/index.js';
|
|
5
4
|
import { agentSystemNamespace, customCredentialsToStoreValues, customCredentialToStoreKey, storeValuesToCustomRuntimeCredentials } from './credential-fingerprints.js';
|
|
6
5
|
import { normalizeCustomProviderBaseUrl } from './custom-provider-url.js';
|
|
7
6
|
import { CustomModelProviderConfigNotFoundError, CustomModelProviderSlugCollisionError, CustomModelProviderStoredSecretBaseUrlChangeError, InvalidAgentModelError, InvalidCustomModelProviderHeaderKeepError } from './errors.js';
|
|
8
7
|
import { egressPolicy, probeCustomModelProviderCredentials, runProviderProbe } from './model-provider-validation.js';
|
|
8
|
+
import { requireAgentSecretsClient } from './secrets-client.js';
|
|
9
9
|
export async function createCustomModelProviderConfig(params, options = {}) {
|
|
10
10
|
const probe = options.probe ?? probeCustomModelProviderCredentials;
|
|
11
|
+
const secrets = requireAgentSecretsClient(options.secrets);
|
|
11
12
|
const existing = await getModelProviderConfig({
|
|
12
13
|
workspaceId: params.workspaceId,
|
|
13
14
|
providerId: params.body.slug
|
|
@@ -61,7 +62,7 @@ export async function createCustomModelProviderConfig(params, options = {}) {
|
|
|
61
62
|
throw new CustomModelProviderSlugCollisionError(params.workspaceId, params.body.slug);
|
|
62
63
|
}
|
|
63
64
|
try {
|
|
64
|
-
await setSecrets({
|
|
65
|
+
await secrets.setSecrets({
|
|
65
66
|
workspaceId: params.workspaceId,
|
|
66
67
|
namespace: agentSystemNamespace(params.body.slug),
|
|
67
68
|
values: customCredentialsToStoreValues(secretCredentials)
|
|
@@ -72,7 +73,7 @@ export async function createCustomModelProviderConfig(params, options = {}) {
|
|
|
72
73
|
workspaceId: params.workspaceId,
|
|
73
74
|
providerId: params.body.slug
|
|
74
75
|
});
|
|
75
|
-
await deleteSecrets({
|
|
76
|
+
await secrets.deleteSecrets({
|
|
76
77
|
workspaceId: params.workspaceId,
|
|
77
78
|
namespace: agentSystemNamespace(params.body.slug)
|
|
78
79
|
});
|
|
@@ -81,8 +82,9 @@ export async function createCustomModelProviderConfig(params, options = {}) {
|
|
|
81
82
|
}
|
|
82
83
|
export async function updateCustomModelProviderConfig(params, options = {}) {
|
|
83
84
|
const probe = options.probe ?? probeCustomModelProviderCredentials;
|
|
85
|
+
const secrets = requireAgentSecretsClient(options.secrets);
|
|
84
86
|
const existing = await getExistingCustomConfig(params.workspaceId, params.providerId);
|
|
85
|
-
const existingSecrets = await getCustomProviderSecrets({
|
|
87
|
+
const existingSecrets = await getCustomProviderSecrets(secrets, {
|
|
86
88
|
workspaceId: params.workspaceId,
|
|
87
89
|
providerId: params.providerId
|
|
88
90
|
});
|
|
@@ -136,7 +138,7 @@ export async function updateCustomModelProviderConfig(params, options = {}) {
|
|
|
136
138
|
signal: params.signal
|
|
137
139
|
});
|
|
138
140
|
const namespace = agentSystemNamespace(params.providerId);
|
|
139
|
-
await setSecrets({
|
|
141
|
+
await secrets.setSecrets({
|
|
140
142
|
workspaceId: params.workspaceId,
|
|
141
143
|
namespace,
|
|
142
144
|
values: customCredentialsToStoreValues(newSecretCredentials)
|
|
@@ -158,7 +160,7 @@ export async function updateCustomModelProviderConfig(params, options = {}) {
|
|
|
158
160
|
defaultThinking: existing.defaultThinking
|
|
159
161
|
});
|
|
160
162
|
} catch (error) {
|
|
161
|
-
await rollbackCustomProviderSecretUpdate({
|
|
163
|
+
await rollbackCustomProviderSecretUpdate(secrets, {
|
|
162
164
|
workspaceId: params.workspaceId,
|
|
163
165
|
namespace,
|
|
164
166
|
existingSecrets,
|
|
@@ -166,7 +168,7 @@ export async function updateCustomModelProviderConfig(params, options = {}) {
|
|
|
166
168
|
}).catch(()=>undefined);
|
|
167
169
|
throw error;
|
|
168
170
|
}
|
|
169
|
-
await pruneStaleCustomHeaderSecrets({
|
|
171
|
+
await pruneStaleCustomHeaderSecrets(secrets, {
|
|
170
172
|
workspaceId: params.workspaceId,
|
|
171
173
|
providerId: params.providerId,
|
|
172
174
|
existingSecrets,
|
|
@@ -175,9 +177,10 @@ export async function updateCustomModelProviderConfig(params, options = {}) {
|
|
|
175
177
|
});
|
|
176
178
|
return updated;
|
|
177
179
|
}
|
|
178
|
-
export async function resolveCustomModelProviderDiscoveryParams(params) {
|
|
180
|
+
export async function resolveCustomModelProviderDiscoveryParams(params, options = {}) {
|
|
181
|
+
const secrets = requireAgentSecretsClient(options.secrets);
|
|
179
182
|
const existing = await getExistingCustomConfig(params.workspaceId, params.providerId);
|
|
180
|
-
const existingSecrets = await getCustomProviderSecrets({
|
|
183
|
+
const existingSecrets = await getCustomProviderSecrets(secrets, {
|
|
181
184
|
workspaceId: params.workspaceId,
|
|
182
185
|
providerId: params.providerId
|
|
183
186
|
});
|
|
@@ -325,8 +328,8 @@ function selectProbeModel(models, defaultModel) {
|
|
|
325
328
|
if (!model) throw new Error('Custom model provider must include at least one model.');
|
|
326
329
|
return model;
|
|
327
330
|
}
|
|
328
|
-
async function getCustomProviderSecrets(params) {
|
|
329
|
-
const values = await getSecretsByNamespace({
|
|
331
|
+
async function getCustomProviderSecrets(secrets, params) {
|
|
332
|
+
const { values } = await secrets.getSecretsByNamespace({
|
|
330
333
|
workspaceId: params.workspaceId,
|
|
331
334
|
namespace: agentSystemNamespace(params.providerId)
|
|
332
335
|
});
|
|
@@ -345,7 +348,7 @@ function assertStoredSecretsNotReusedAfterBaseUrlChange(params) {
|
|
|
345
348
|
function normalizedUrl(value) {
|
|
346
349
|
return normalizeCustomProviderBaseUrl(value);
|
|
347
350
|
}
|
|
348
|
-
async function rollbackCustomProviderSecretUpdate(params) {
|
|
351
|
+
async function rollbackCustomProviderSecretUpdate(secrets, params) {
|
|
349
352
|
const attemptedKeys = Object.keys(params.attemptedSecrets);
|
|
350
353
|
if (attemptedKeys.length === 0) return;
|
|
351
354
|
const secretsToRestore = Object.fromEntries(attemptedKeys.flatMap((key)=>{
|
|
@@ -358,7 +361,7 @@ async function rollbackCustomProviderSecretUpdate(params) {
|
|
|
358
361
|
];
|
|
359
362
|
}));
|
|
360
363
|
if (Object.keys(secretsToRestore).length > 0) {
|
|
361
|
-
await setSecrets({
|
|
364
|
+
await secrets.setSecrets({
|
|
362
365
|
workspaceId: params.workspaceId,
|
|
363
366
|
namespace: params.namespace,
|
|
364
367
|
values: customCredentialsToStoreValues(secretsToRestore)
|
|
@@ -366,18 +369,18 @@ async function rollbackCustomProviderSecretUpdate(params) {
|
|
|
366
369
|
}
|
|
367
370
|
const newKeys = attemptedKeys.filter((key)=>params.existingSecrets[key] === undefined);
|
|
368
371
|
if (newKeys.length === 0) return;
|
|
369
|
-
await deleteSecrets({
|
|
372
|
+
await secrets.deleteSecrets({
|
|
370
373
|
workspaceId: params.workspaceId,
|
|
371
374
|
namespace: params.namespace,
|
|
372
375
|
keys: newKeys.map(customCredentialToStoreKey)
|
|
373
376
|
});
|
|
374
377
|
}
|
|
375
|
-
async function pruneStaleCustomHeaderSecrets(params) {
|
|
378
|
+
async function pruneStaleCustomHeaderSecrets(secrets, params) {
|
|
376
379
|
if (!params.replaceHeaders) return;
|
|
377
380
|
const nextKeys = new Set(Object.keys(params.newSecrets));
|
|
378
381
|
const staleKeys = Object.keys(params.existingSecrets).filter((key)=>key.startsWith('header:') && !nextKeys.has(key));
|
|
379
382
|
if (staleKeys.length === 0) return;
|
|
380
|
-
await deleteSecrets({
|
|
383
|
+
await secrets.deleteSecrets({
|
|
381
384
|
workspaceId: params.workspaceId,
|
|
382
385
|
namespace: agentSystemNamespace(params.providerId),
|
|
383
386
|
keys: staleKeys.map(customCredentialToStoreKey)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/custom-model-provider-config-service.ts"],"sourcesContent":["import {\n type CreateCustomModelProviderBodyDto,\n type CustomAgentModelDto,\n type CustomModelProviderHeaderDto,\n type CustomModelProviderHeaderRequestDto,\n DEFAULT_AGENT_THINKING,\n type DiscoverCustomModelProviderModelsBodyDto,\n type DiscoverCustomModelProviderModelsBySlugBodyDto,\n type ModelProviderRef,\n type UpdateCustomModelProviderBodyDto,\n type UpdateCustomModelProviderHeaderRequestDto,\n} from '@shipfox/api-agent-dto';\nimport {deleteSecrets, getSecretsByNamespace, setSecrets} from '@shipfox/api-secrets';\nimport {assertEgressAllowed} from '@shipfox/node-egress-guard';\nimport {\n deleteModelProviderConfig,\n getModelProviderConfig,\n insertCustomModelProviderConfig,\n upsertModelProviderConfig,\n} from '#db/index.js';\nimport {\n agentSystemNamespace,\n customCredentialsToStoreValues,\n customCredentialToStoreKey,\n storeValuesToCustomRuntimeCredentials,\n} from './credential-fingerprints.js';\nimport {normalizeCustomProviderBaseUrl} from './custom-provider-url.js';\nimport type {ModelProviderConfig} from './entities/model-provider-config.js';\nimport {\n CustomModelProviderConfigNotFoundError,\n CustomModelProviderSlugCollisionError,\n CustomModelProviderStoredSecretBaseUrlChangeError,\n InvalidAgentModelError,\n InvalidCustomModelProviderHeaderKeepError,\n} from './errors.js';\nimport {\n egressPolicy,\n probeCustomModelProviderCredentials,\n runProviderProbe,\n} from './model-provider-validation.js';\n\nexport interface CreateCustomModelProviderConfigParams {\n workspaceId: string;\n body: CreateCustomModelProviderBodyDto;\n setAsDefault?: boolean | undefined;\n signal?: AbortSignal | undefined;\n}\n\nexport interface UpdateCustomModelProviderConfigParams {\n workspaceId: string;\n providerId: ModelProviderRef;\n body: UpdateCustomModelProviderBodyDto;\n signal?: AbortSignal | undefined;\n}\n\nexport interface CustomModelProviderConfigServiceOptions {\n probe?: typeof probeCustomModelProviderCredentials | undefined;\n}\n\ninterface SplitHeaders {\n plaintextHeaders: CustomModelProviderHeaderDto[];\n secretHeaderNames: string[];\n secretCredentials: Record<string, string>;\n runtimeHeaders: Record<string, string>;\n}\n\nexport async function createCustomModelProviderConfig(\n params: CreateCustomModelProviderConfigParams,\n options: CustomModelProviderConfigServiceOptions = {},\n): Promise<ModelProviderConfig> {\n const probe = options.probe ?? probeCustomModelProviderCredentials;\n\n const existing = await getModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.body.slug,\n });\n if (existing !== undefined) {\n throw new CustomModelProviderSlugCollisionError(params.workspaceId, params.body.slug);\n }\n\n const splitHeaders = splitCustomHeaders(params.body.headers ?? []);\n const secretCredentials = {\n ...(params.body.api_key ? {api_key: params.body.api_key} : {}),\n ...splitHeaders.secretCredentials,\n };\n const probeModel = selectProbeModel(params.body.models, params.body.default_model ?? null);\n\n await assertEgressAllowed(params.body.base_url, egressPolicy());\n await runProviderProbe({\n probe,\n args: {\n providerId: params.body.slug,\n api: params.body.api,\n baseUrl: params.body.base_url,\n model: probeModel,\n apiKey: params.body.api_key,\n headers: splitHeaders.runtimeHeaders,\n ...(params.signal ? {signal: params.signal} : {}),\n },\n metricLabel: 'custom',\n providerId: params.body.slug,\n secrets: Object.values(secretCredentials),\n signal: params.signal,\n });\n\n const config = await insertCustomModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.body.slug,\n kind: 'custom',\n displayName: params.body.display_name,\n api: params.body.api,\n baseUrl: params.body.base_url,\n headers: splitHeaders.plaintextHeaders,\n secretHeaderNames: splitHeaders.secretHeaderNames,\n models: params.body.models,\n requiresApiKey: params.body.api_key !== undefined,\n defaultModel: params.body.default_model ?? null,\n defaultThinking: DEFAULT_AGENT_THINKING,\n setAsDefault: params.setAsDefault,\n });\n if (!config) {\n throw new CustomModelProviderSlugCollisionError(params.workspaceId, params.body.slug);\n }\n\n try {\n await setSecrets({\n workspaceId: params.workspaceId,\n namespace: agentSystemNamespace(params.body.slug),\n values: customCredentialsToStoreValues(secretCredentials),\n });\n return config;\n } catch (error) {\n await deleteModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.body.slug,\n });\n await deleteSecrets({\n workspaceId: params.workspaceId,\n namespace: agentSystemNamespace(params.body.slug),\n });\n throw error;\n }\n}\n\nexport async function updateCustomModelProviderConfig(\n params: UpdateCustomModelProviderConfigParams,\n options: CustomModelProviderConfigServiceOptions = {},\n): Promise<ModelProviderConfig> {\n const probe = options.probe ?? probeCustomModelProviderCredentials;\n\n const existing = await getExistingCustomConfig(params.workspaceId, params.providerId);\n const existingSecrets = await getCustomProviderSecrets({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n });\n const nextModels = params.body.models ?? existing.models ?? [];\n const nextDefaultModel = resolveNextDefaultModel(\n params.providerId,\n existing.defaultModel,\n nextModels,\n params.body,\n );\n const nextApi = params.body.api ?? existing.api ?? 'openai-responses';\n const nextBaseUrl = params.body.base_url ?? existing.baseUrl ?? '';\n const nextDisplayName = params.body.display_name ?? existing.displayName ?? params.providerId;\n assertStoredSecretsNotReusedAfterBaseUrlChange({\n body: params.body,\n existing,\n existingSecrets,\n providerId: params.providerId,\n });\n const nextHeaders = resolveNextHeaders({\n requestHeaders: params.body.headers,\n existing,\n existingSecrets,\n providerId: params.providerId,\n });\n const nextApiKey = params.body.api_key ?? existingSecrets.api_key;\n const newSecretCredentials = {\n ...(params.body.api_key ? {api_key: params.body.api_key} : {}),\n ...nextHeaders.newSecretCredentials,\n };\n const probeSecretCredentials = {\n ...(nextApiKey ? {api_key: nextApiKey} : {}),\n ...nextHeaders.probeSecretCredentials,\n };\n\n await assertEgressAllowed(nextBaseUrl, egressPolicy());\n await runProviderProbe({\n probe,\n args: {\n providerId: params.providerId,\n api: nextApi,\n baseUrl: nextBaseUrl,\n model: selectProbeModel(nextModels, nextDefaultModel),\n apiKey: nextApiKey,\n headers: nextHeaders.runtimeHeaders,\n ...(params.signal ? {signal: params.signal} : {}),\n },\n metricLabel: 'custom',\n providerId: params.providerId,\n secrets: Object.values(probeSecretCredentials),\n signal: params.signal,\n });\n\n const namespace = agentSystemNamespace(params.providerId);\n await setSecrets({\n workspaceId: params.workspaceId,\n namespace,\n values: customCredentialsToStoreValues(newSecretCredentials),\n });\n\n let updated: ModelProviderConfig;\n try {\n updated = await upsertModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n kind: 'custom',\n displayName: nextDisplayName,\n api: nextApi,\n baseUrl: nextBaseUrl,\n headers: nextHeaders.plaintextHeaders,\n secretHeaderNames: nextHeaders.secretHeaderNames,\n models: nextModels,\n requiresApiKey: existing.requiresApiKey || params.body.api_key !== undefined,\n defaultModel: nextDefaultModel,\n defaultThinking: existing.defaultThinking,\n });\n } catch (error) {\n await rollbackCustomProviderSecretUpdate({\n workspaceId: params.workspaceId,\n namespace,\n existingSecrets,\n attemptedSecrets: newSecretCredentials,\n }).catch(() => undefined);\n throw error;\n }\n\n await pruneStaleCustomHeaderSecrets({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n existingSecrets,\n newSecrets: newSecretCredentials,\n replaceHeaders: params.body.headers !== undefined,\n });\n\n return updated;\n}\n\nexport async function resolveCustomModelProviderDiscoveryParams(params: {\n workspaceId: string;\n providerId: ModelProviderRef;\n body: DiscoverCustomModelProviderModelsBySlugBodyDto;\n}): Promise<DiscoverCustomModelProviderModelsBodyDto> {\n const existing = await getExistingCustomConfig(params.workspaceId, params.providerId);\n const existingSecrets = await getCustomProviderSecrets({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n });\n assertStoredSecretsNotReusedAfterBaseUrlChange({\n body: params.body,\n existing,\n existingSecrets,\n providerId: params.providerId,\n });\n const headers = resolveNextHeaders({\n requestHeaders: params.body.headers,\n existing,\n existingSecrets,\n providerId: params.providerId,\n });\n\n return {\n api: params.body.api ?? existing.api ?? 'openai-responses',\n base_url: params.body.base_url ?? existing.baseUrl ?? '',\n ...((params.body.api_key ?? existingSecrets.api_key)\n ? {api_key: params.body.api_key ?? existingSecrets.api_key}\n : {}),\n headers: Object.entries(headers.runtimeHeaders).map(([name, value]) => ({name, value})),\n };\n}\n\nasync function getExistingCustomConfig(\n workspaceId: string,\n providerId: ModelProviderRef,\n): Promise<ModelProviderConfig> {\n const existing = await getModelProviderConfig({workspaceId, providerId});\n if (existing?.kind !== 'custom') {\n throw new CustomModelProviderConfigNotFoundError(workspaceId, providerId);\n }\n return existing;\n}\n\nfunction splitCustomHeaders(headers: CustomModelProviderHeaderRequestDto[]): SplitHeaders {\n const plaintextHeaders: CustomModelProviderHeaderDto[] = [];\n const secretHeaderNames: string[] = [];\n const secretCredentials: Record<string, string> = {};\n const runtimeHeaders: Record<string, string> = {};\n\n for (const header of headers) {\n runtimeHeaders[header.name] = header.value;\n if (header.secret) {\n secretHeaderNames.push(header.name);\n secretCredentials[`header:${header.name}`] = header.value;\n } else {\n plaintextHeaders.push({name: header.name, value: header.value});\n }\n }\n\n return {plaintextHeaders, secretHeaderNames, secretCredentials, runtimeHeaders};\n}\n\nfunction resolveNextHeaders(params: {\n requestHeaders: UpdateCustomModelProviderHeaderRequestDto[] | undefined;\n existing: ModelProviderConfig;\n existingSecrets: Record<string, string>;\n providerId: ModelProviderRef;\n}): {\n plaintextHeaders: CustomModelProviderHeaderDto[];\n secretHeaderNames: string[];\n runtimeHeaders: Record<string, string>;\n probeSecretCredentials: Record<string, string>;\n newSecretCredentials: Record<string, string>;\n} {\n if (params.requestHeaders !== undefined) {\n return splitUpdateHeaders({\n requestHeaders: params.requestHeaders,\n existingSecrets: params.existingSecrets,\n providerId: params.providerId,\n });\n }\n\n const runtimeHeaders: Record<string, string> = {};\n for (const header of params.existing.headers ?? []) {\n runtimeHeaders[header.name] = header.value;\n }\n\n const probeSecretCredentials: Record<string, string> = {};\n for (const [key, value] of Object.entries(params.existingSecrets)) {\n if (!key.startsWith('header:')) continue;\n const name = key.slice('header:'.length);\n runtimeHeaders[name] = value;\n probeSecretCredentials[key] = value;\n }\n\n return {\n plaintextHeaders: params.existing.headers ?? [],\n secretHeaderNames:\n params.existing.secretHeaderNames ?? secretHeaderNamesFromCredentials(params.existingSecrets),\n runtimeHeaders,\n probeSecretCredentials,\n newSecretCredentials: {},\n };\n}\n\nfunction splitUpdateHeaders(params: {\n requestHeaders: UpdateCustomModelProviderHeaderRequestDto[];\n existingSecrets: Record<string, string>;\n providerId: ModelProviderRef;\n}): {\n plaintextHeaders: CustomModelProviderHeaderDto[];\n secretHeaderNames: string[];\n runtimeHeaders: Record<string, string>;\n probeSecretCredentials: Record<string, string>;\n newSecretCredentials: Record<string, string>;\n} {\n const plaintextHeaders: CustomModelProviderHeaderDto[] = [];\n const secretHeaderNames: string[] = [];\n const runtimeHeaders: Record<string, string> = {};\n const probeSecretCredentials: Record<string, string> = {};\n const newSecretCredentials: Record<string, string> = {};\n\n for (const header of params.requestHeaders) {\n if (header.keep === true) {\n const key = `header:${header.name}`;\n const value = params.existingSecrets[key];\n if (value === undefined) {\n throw new InvalidCustomModelProviderHeaderKeepError(params.providerId, header.name);\n }\n runtimeHeaders[header.name] = value;\n secretHeaderNames.push(header.name);\n probeSecretCredentials[key] = value;\n newSecretCredentials[key] = value;\n continue;\n }\n\n const value = header.value;\n if (value === undefined) {\n throw new InvalidCustomModelProviderHeaderKeepError(params.providerId, header.name);\n }\n runtimeHeaders[header.name] = value;\n if (header.secret) {\n const key = `header:${header.name}`;\n secretHeaderNames.push(header.name);\n probeSecretCredentials[key] = value;\n newSecretCredentials[key] = value;\n } else {\n plaintextHeaders.push({name: header.name, value});\n }\n }\n\n return {\n plaintextHeaders,\n secretHeaderNames,\n runtimeHeaders,\n probeSecretCredentials,\n newSecretCredentials,\n };\n}\n\nfunction resolveNextDefaultModel(\n providerId: ModelProviderRef,\n existingDefaultModel: string | null,\n models: CustomAgentModelDto[],\n body: UpdateCustomModelProviderBodyDto,\n): string | null {\n if (!('default_model' in body)) {\n if (existingDefaultModel === null) return null;\n return models.some((model) => model.id === existingDefaultModel) ? existingDefaultModel : null;\n }\n\n const requestedDefaultModel = body.default_model ?? null;\n if (requestedDefaultModel === null) return null;\n if (models.some((model) => model.id === requestedDefaultModel)) return requestedDefaultModel;\n throw new InvalidAgentModelError('pi', providerId, requestedDefaultModel);\n}\n\nfunction selectProbeModel(\n models: CustomAgentModelDto[],\n defaultModel: string | null,\n): CustomAgentModelDto {\n const model = models.find((candidate) => candidate.id === defaultModel) ?? models[0];\n if (!model) throw new Error('Custom model provider must include at least one model.');\n return model;\n}\n\nasync function getCustomProviderSecrets(params: {\n workspaceId: string;\n providerId: ModelProviderRef;\n}): Promise<Record<string, string>> {\n const values = await getSecretsByNamespace({\n workspaceId: params.workspaceId,\n namespace: agentSystemNamespace(params.providerId),\n });\n return storeValuesToCustomRuntimeCredentials(values);\n}\n\nfunction assertStoredSecretsNotReusedAfterBaseUrlChange(params: {\n body: UpdateCustomModelProviderBodyDto | DiscoverCustomModelProviderModelsBySlugBodyDto;\n existing: ModelProviderConfig;\n existingSecrets: Record<string, string>;\n providerId: ModelProviderRef;\n}): void {\n if (\n params.body.base_url === undefined ||\n normalizedUrl(params.body.base_url) === normalizedUrl(params.existing.baseUrl ?? '')\n ) {\n return;\n }\n\n const reusesStoredApiKey =\n params.existingSecrets.api_key !== undefined && params.body.api_key === undefined;\n const reusesStoredSecretHeader =\n params.body.headers === undefined\n ? Object.keys(params.existingSecrets).some((key) => key.startsWith('header:'))\n : params.body.headers.some((header) => header.keep === true);\n\n if (reusesStoredApiKey || reusesStoredSecretHeader) {\n throw new CustomModelProviderStoredSecretBaseUrlChangeError(params.providerId);\n }\n}\n\nfunction normalizedUrl(value: string): string {\n return normalizeCustomProviderBaseUrl(value);\n}\n\nasync function rollbackCustomProviderSecretUpdate(params: {\n workspaceId: string;\n namespace: string;\n existingSecrets: Record<string, string>;\n attemptedSecrets: Record<string, string>;\n}): Promise<void> {\n const attemptedKeys = Object.keys(params.attemptedSecrets);\n if (attemptedKeys.length === 0) return;\n\n const secretsToRestore = Object.fromEntries(\n attemptedKeys.flatMap((key) => {\n const value = params.existingSecrets[key];\n return value === undefined ? [] : [[key, value]];\n }),\n );\n if (Object.keys(secretsToRestore).length > 0) {\n await setSecrets({\n workspaceId: params.workspaceId,\n namespace: params.namespace,\n values: customCredentialsToStoreValues(secretsToRestore),\n });\n }\n\n const newKeys = attemptedKeys.filter((key) => params.existingSecrets[key] === undefined);\n if (newKeys.length === 0) return;\n\n await deleteSecrets({\n workspaceId: params.workspaceId,\n namespace: params.namespace,\n keys: newKeys.map(customCredentialToStoreKey),\n });\n}\n\nasync function pruneStaleCustomHeaderSecrets(params: {\n workspaceId: string;\n providerId: ModelProviderRef;\n existingSecrets: Record<string, string>;\n newSecrets: Record<string, string>;\n replaceHeaders: boolean;\n}): Promise<void> {\n if (!params.replaceHeaders) return;\n\n const nextKeys = new Set(Object.keys(params.newSecrets));\n const staleKeys = Object.keys(params.existingSecrets).filter(\n (key) => key.startsWith('header:') && !nextKeys.has(key),\n );\n if (staleKeys.length === 0) return;\n\n await deleteSecrets({\n workspaceId: params.workspaceId,\n namespace: agentSystemNamespace(params.providerId),\n keys: staleKeys.map(customCredentialToStoreKey),\n });\n}\n\nfunction secretHeaderNamesFromCredentials(credentials: Record<string, string>): string[] {\n return Object.keys(credentials)\n .filter((key) => key.startsWith('header:'))\n .map((key) => key.slice('header:'.length))\n .sort();\n}\n"],"names":["DEFAULT_AGENT_THINKING","deleteSecrets","getSecretsByNamespace","setSecrets","assertEgressAllowed","deleteModelProviderConfig","getModelProviderConfig","insertCustomModelProviderConfig","upsertModelProviderConfig","agentSystemNamespace","customCredentialsToStoreValues","customCredentialToStoreKey","storeValuesToCustomRuntimeCredentials","normalizeCustomProviderBaseUrl","CustomModelProviderConfigNotFoundError","CustomModelProviderSlugCollisionError","CustomModelProviderStoredSecretBaseUrlChangeError","InvalidAgentModelError","InvalidCustomModelProviderHeaderKeepError","egressPolicy","probeCustomModelProviderCredentials","runProviderProbe","createCustomModelProviderConfig","params","options","probe","existing","workspaceId","providerId","body","slug","undefined","splitHeaders","splitCustomHeaders","headers","secretCredentials","api_key","probeModel","selectProbeModel","models","default_model","base_url","args","api","baseUrl","model","apiKey","runtimeHeaders","signal","metricLabel","secrets","Object","values","config","kind","displayName","display_name","plaintextHeaders","secretHeaderNames","requiresApiKey","defaultModel","defaultThinking","setAsDefault","namespace","error","updateCustomModelProviderConfig","getExistingCustomConfig","existingSecrets","getCustomProviderSecrets","nextModels","nextDefaultModel","resolveNextDefaultModel","nextApi","nextBaseUrl","nextDisplayName","assertStoredSecretsNotReusedAfterBaseUrlChange","nextHeaders","resolveNextHeaders","requestHeaders","nextApiKey","newSecretCredentials","probeSecretCredentials","updated","rollbackCustomProviderSecretUpdate","attemptedSecrets","catch","pruneStaleCustomHeaderSecrets","newSecrets","replaceHeaders","resolveCustomModelProviderDiscoveryParams","entries","map","name","value","header","secret","push","splitUpdateHeaders","key","startsWith","slice","length","secretHeaderNamesFromCredentials","keep","existingDefaultModel","some","id","requestedDefaultModel","find","candidate","Error","normalizedUrl","reusesStoredApiKey","reusesStoredSecretHeader","keys","attemptedKeys","secretsToRestore","fromEntries","flatMap","newKeys","filter","nextKeys","Set","staleKeys","has","credentials","sort"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/custom-model-provider-config-service.ts"],"sourcesContent":["import {\n type CreateCustomModelProviderBodyDto,\n type CustomAgentModelDto,\n type CustomModelProviderHeaderDto,\n type CustomModelProviderHeaderRequestDto,\n DEFAULT_AGENT_THINKING,\n type DiscoverCustomModelProviderModelsBodyDto,\n type DiscoverCustomModelProviderModelsBySlugBodyDto,\n type ModelProviderRef,\n type UpdateCustomModelProviderBodyDto,\n type UpdateCustomModelProviderHeaderRequestDto,\n} from '@shipfox/api-agent-dto';\nimport {assertEgressAllowed} from '@shipfox/node-egress-guard';\nimport {\n deleteModelProviderConfig,\n getModelProviderConfig,\n insertCustomModelProviderConfig,\n upsertModelProviderConfig,\n} from '#db/index.js';\nimport {\n agentSystemNamespace,\n customCredentialsToStoreValues,\n customCredentialToStoreKey,\n storeValuesToCustomRuntimeCredentials,\n} from './credential-fingerprints.js';\nimport {normalizeCustomProviderBaseUrl} from './custom-provider-url.js';\nimport type {ModelProviderConfig} from './entities/model-provider-config.js';\nimport {\n CustomModelProviderConfigNotFoundError,\n CustomModelProviderSlugCollisionError,\n CustomModelProviderStoredSecretBaseUrlChangeError,\n InvalidAgentModelError,\n InvalidCustomModelProviderHeaderKeepError,\n} from './errors.js';\nimport {\n egressPolicy,\n probeCustomModelProviderCredentials,\n runProviderProbe,\n} from './model-provider-validation.js';\nimport {type AgentSecretsClient, requireAgentSecretsClient} from './secrets-client.js';\n\nexport interface CreateCustomModelProviderConfigParams {\n workspaceId: string;\n body: CreateCustomModelProviderBodyDto;\n setAsDefault?: boolean | undefined;\n signal?: AbortSignal | undefined;\n}\n\nexport interface UpdateCustomModelProviderConfigParams {\n workspaceId: string;\n providerId: ModelProviderRef;\n body: UpdateCustomModelProviderBodyDto;\n signal?: AbortSignal | undefined;\n}\n\nexport interface CustomModelProviderConfigServiceOptions {\n probe?: typeof probeCustomModelProviderCredentials | undefined;\n secrets?: AgentSecretsClient | undefined;\n}\n\ninterface SplitHeaders {\n plaintextHeaders: CustomModelProviderHeaderDto[];\n secretHeaderNames: string[];\n secretCredentials: Record<string, string>;\n runtimeHeaders: Record<string, string>;\n}\n\nexport async function createCustomModelProviderConfig(\n params: CreateCustomModelProviderConfigParams,\n options: CustomModelProviderConfigServiceOptions = {},\n): Promise<ModelProviderConfig> {\n const probe = options.probe ?? probeCustomModelProviderCredentials;\n const secrets = requireAgentSecretsClient(options.secrets);\n\n const existing = await getModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.body.slug,\n });\n if (existing !== undefined) {\n throw new CustomModelProviderSlugCollisionError(params.workspaceId, params.body.slug);\n }\n\n const splitHeaders = splitCustomHeaders(params.body.headers ?? []);\n const secretCredentials = {\n ...(params.body.api_key ? {api_key: params.body.api_key} : {}),\n ...splitHeaders.secretCredentials,\n };\n const probeModel = selectProbeModel(params.body.models, params.body.default_model ?? null);\n\n await assertEgressAllowed(params.body.base_url, egressPolicy());\n await runProviderProbe({\n probe,\n args: {\n providerId: params.body.slug,\n api: params.body.api,\n baseUrl: params.body.base_url,\n model: probeModel,\n apiKey: params.body.api_key,\n headers: splitHeaders.runtimeHeaders,\n ...(params.signal ? {signal: params.signal} : {}),\n },\n metricLabel: 'custom',\n providerId: params.body.slug,\n secrets: Object.values(secretCredentials),\n signal: params.signal,\n });\n\n const config = await insertCustomModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.body.slug,\n kind: 'custom',\n displayName: params.body.display_name,\n api: params.body.api,\n baseUrl: params.body.base_url,\n headers: splitHeaders.plaintextHeaders,\n secretHeaderNames: splitHeaders.secretHeaderNames,\n models: params.body.models,\n requiresApiKey: params.body.api_key !== undefined,\n defaultModel: params.body.default_model ?? null,\n defaultThinking: DEFAULT_AGENT_THINKING,\n setAsDefault: params.setAsDefault,\n });\n if (!config) {\n throw new CustomModelProviderSlugCollisionError(params.workspaceId, params.body.slug);\n }\n\n try {\n await secrets.setSecrets({\n workspaceId: params.workspaceId,\n namespace: agentSystemNamespace(params.body.slug),\n values: customCredentialsToStoreValues(secretCredentials),\n });\n return config;\n } catch (error) {\n await deleteModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.body.slug,\n });\n await secrets.deleteSecrets({\n workspaceId: params.workspaceId,\n namespace: agentSystemNamespace(params.body.slug),\n });\n throw error;\n }\n}\n\nexport async function updateCustomModelProviderConfig(\n params: UpdateCustomModelProviderConfigParams,\n options: CustomModelProviderConfigServiceOptions = {},\n): Promise<ModelProviderConfig> {\n const probe = options.probe ?? probeCustomModelProviderCredentials;\n const secrets = requireAgentSecretsClient(options.secrets);\n\n const existing = await getExistingCustomConfig(params.workspaceId, params.providerId);\n const existingSecrets = await getCustomProviderSecrets(secrets, {\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n });\n const nextModels = params.body.models ?? existing.models ?? [];\n const nextDefaultModel = resolveNextDefaultModel(\n params.providerId,\n existing.defaultModel,\n nextModels,\n params.body,\n );\n const nextApi = params.body.api ?? existing.api ?? 'openai-responses';\n const nextBaseUrl = params.body.base_url ?? existing.baseUrl ?? '';\n const nextDisplayName = params.body.display_name ?? existing.displayName ?? params.providerId;\n assertStoredSecretsNotReusedAfterBaseUrlChange({\n body: params.body,\n existing,\n existingSecrets,\n providerId: params.providerId,\n });\n const nextHeaders = resolveNextHeaders({\n requestHeaders: params.body.headers,\n existing,\n existingSecrets,\n providerId: params.providerId,\n });\n const nextApiKey = params.body.api_key ?? existingSecrets.api_key;\n const newSecretCredentials = {\n ...(params.body.api_key ? {api_key: params.body.api_key} : {}),\n ...nextHeaders.newSecretCredentials,\n };\n const probeSecretCredentials = {\n ...(nextApiKey ? {api_key: nextApiKey} : {}),\n ...nextHeaders.probeSecretCredentials,\n };\n\n await assertEgressAllowed(nextBaseUrl, egressPolicy());\n await runProviderProbe({\n probe,\n args: {\n providerId: params.providerId,\n api: nextApi,\n baseUrl: nextBaseUrl,\n model: selectProbeModel(nextModels, nextDefaultModel),\n apiKey: nextApiKey,\n headers: nextHeaders.runtimeHeaders,\n ...(params.signal ? {signal: params.signal} : {}),\n },\n metricLabel: 'custom',\n providerId: params.providerId,\n secrets: Object.values(probeSecretCredentials),\n signal: params.signal,\n });\n\n const namespace = agentSystemNamespace(params.providerId);\n await secrets.setSecrets({\n workspaceId: params.workspaceId,\n namespace,\n values: customCredentialsToStoreValues(newSecretCredentials),\n });\n\n let updated: ModelProviderConfig;\n try {\n updated = await upsertModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n kind: 'custom',\n displayName: nextDisplayName,\n api: nextApi,\n baseUrl: nextBaseUrl,\n headers: nextHeaders.plaintextHeaders,\n secretHeaderNames: nextHeaders.secretHeaderNames,\n models: nextModels,\n requiresApiKey: existing.requiresApiKey || params.body.api_key !== undefined,\n defaultModel: nextDefaultModel,\n defaultThinking: existing.defaultThinking,\n });\n } catch (error) {\n await rollbackCustomProviderSecretUpdate(secrets, {\n workspaceId: params.workspaceId,\n namespace,\n existingSecrets,\n attemptedSecrets: newSecretCredentials,\n }).catch(() => undefined);\n throw error;\n }\n\n await pruneStaleCustomHeaderSecrets(secrets, {\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n existingSecrets,\n newSecrets: newSecretCredentials,\n replaceHeaders: params.body.headers !== undefined,\n });\n\n return updated;\n}\n\nexport async function resolveCustomModelProviderDiscoveryParams(\n params: {\n workspaceId: string;\n providerId: ModelProviderRef;\n body: DiscoverCustomModelProviderModelsBySlugBodyDto;\n },\n options: {secrets?: AgentSecretsClient | undefined} = {},\n): Promise<DiscoverCustomModelProviderModelsBodyDto> {\n const secrets = requireAgentSecretsClient(options.secrets);\n const existing = await getExistingCustomConfig(params.workspaceId, params.providerId);\n const existingSecrets = await getCustomProviderSecrets(secrets, {\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n });\n assertStoredSecretsNotReusedAfterBaseUrlChange({\n body: params.body,\n existing,\n existingSecrets,\n providerId: params.providerId,\n });\n const headers = resolveNextHeaders({\n requestHeaders: params.body.headers,\n existing,\n existingSecrets,\n providerId: params.providerId,\n });\n\n return {\n api: params.body.api ?? existing.api ?? 'openai-responses',\n base_url: params.body.base_url ?? existing.baseUrl ?? '',\n ...((params.body.api_key ?? existingSecrets.api_key)\n ? {api_key: params.body.api_key ?? existingSecrets.api_key}\n : {}),\n headers: Object.entries(headers.runtimeHeaders).map(([name, value]) => ({name, value})),\n };\n}\n\nasync function getExistingCustomConfig(\n workspaceId: string,\n providerId: ModelProviderRef,\n): Promise<ModelProviderConfig> {\n const existing = await getModelProviderConfig({workspaceId, providerId});\n if (existing?.kind !== 'custom') {\n throw new CustomModelProviderConfigNotFoundError(workspaceId, providerId);\n }\n return existing;\n}\n\nfunction splitCustomHeaders(headers: CustomModelProviderHeaderRequestDto[]): SplitHeaders {\n const plaintextHeaders: CustomModelProviderHeaderDto[] = [];\n const secretHeaderNames: string[] = [];\n const secretCredentials: Record<string, string> = {};\n const runtimeHeaders: Record<string, string> = {};\n\n for (const header of headers) {\n runtimeHeaders[header.name] = header.value;\n if (header.secret) {\n secretHeaderNames.push(header.name);\n secretCredentials[`header:${header.name}`] = header.value;\n } else {\n plaintextHeaders.push({name: header.name, value: header.value});\n }\n }\n\n return {plaintextHeaders, secretHeaderNames, secretCredentials, runtimeHeaders};\n}\n\nfunction resolveNextHeaders(params: {\n requestHeaders: UpdateCustomModelProviderHeaderRequestDto[] | undefined;\n existing: ModelProviderConfig;\n existingSecrets: Record<string, string>;\n providerId: ModelProviderRef;\n}): {\n plaintextHeaders: CustomModelProviderHeaderDto[];\n secretHeaderNames: string[];\n runtimeHeaders: Record<string, string>;\n probeSecretCredentials: Record<string, string>;\n newSecretCredentials: Record<string, string>;\n} {\n if (params.requestHeaders !== undefined) {\n return splitUpdateHeaders({\n requestHeaders: params.requestHeaders,\n existingSecrets: params.existingSecrets,\n providerId: params.providerId,\n });\n }\n\n const runtimeHeaders: Record<string, string> = {};\n for (const header of params.existing.headers ?? []) {\n runtimeHeaders[header.name] = header.value;\n }\n\n const probeSecretCredentials: Record<string, string> = {};\n for (const [key, value] of Object.entries(params.existingSecrets)) {\n if (!key.startsWith('header:')) continue;\n const name = key.slice('header:'.length);\n runtimeHeaders[name] = value;\n probeSecretCredentials[key] = value;\n }\n\n return {\n plaintextHeaders: params.existing.headers ?? [],\n secretHeaderNames:\n params.existing.secretHeaderNames ?? secretHeaderNamesFromCredentials(params.existingSecrets),\n runtimeHeaders,\n probeSecretCredentials,\n newSecretCredentials: {},\n };\n}\n\nfunction splitUpdateHeaders(params: {\n requestHeaders: UpdateCustomModelProviderHeaderRequestDto[];\n existingSecrets: Record<string, string>;\n providerId: ModelProviderRef;\n}): {\n plaintextHeaders: CustomModelProviderHeaderDto[];\n secretHeaderNames: string[];\n runtimeHeaders: Record<string, string>;\n probeSecretCredentials: Record<string, string>;\n newSecretCredentials: Record<string, string>;\n} {\n const plaintextHeaders: CustomModelProviderHeaderDto[] = [];\n const secretHeaderNames: string[] = [];\n const runtimeHeaders: Record<string, string> = {};\n const probeSecretCredentials: Record<string, string> = {};\n const newSecretCredentials: Record<string, string> = {};\n\n for (const header of params.requestHeaders) {\n if (header.keep === true) {\n const key = `header:${header.name}`;\n const value = params.existingSecrets[key];\n if (value === undefined) {\n throw new InvalidCustomModelProviderHeaderKeepError(params.providerId, header.name);\n }\n runtimeHeaders[header.name] = value;\n secretHeaderNames.push(header.name);\n probeSecretCredentials[key] = value;\n newSecretCredentials[key] = value;\n continue;\n }\n\n const value = header.value;\n if (value === undefined) {\n throw new InvalidCustomModelProviderHeaderKeepError(params.providerId, header.name);\n }\n runtimeHeaders[header.name] = value;\n if (header.secret) {\n const key = `header:${header.name}`;\n secretHeaderNames.push(header.name);\n probeSecretCredentials[key] = value;\n newSecretCredentials[key] = value;\n } else {\n plaintextHeaders.push({name: header.name, value});\n }\n }\n\n return {\n plaintextHeaders,\n secretHeaderNames,\n runtimeHeaders,\n probeSecretCredentials,\n newSecretCredentials,\n };\n}\n\nfunction resolveNextDefaultModel(\n providerId: ModelProviderRef,\n existingDefaultModel: string | null,\n models: CustomAgentModelDto[],\n body: UpdateCustomModelProviderBodyDto,\n): string | null {\n if (!('default_model' in body)) {\n if (existingDefaultModel === null) return null;\n return models.some((model) => model.id === existingDefaultModel) ? existingDefaultModel : null;\n }\n\n const requestedDefaultModel = body.default_model ?? null;\n if (requestedDefaultModel === null) return null;\n if (models.some((model) => model.id === requestedDefaultModel)) return requestedDefaultModel;\n throw new InvalidAgentModelError('pi', providerId, requestedDefaultModel);\n}\n\nfunction selectProbeModel(\n models: CustomAgentModelDto[],\n defaultModel: string | null,\n): CustomAgentModelDto {\n const model = models.find((candidate) => candidate.id === defaultModel) ?? models[0];\n if (!model) throw new Error('Custom model provider must include at least one model.');\n return model;\n}\n\nasync function getCustomProviderSecrets(\n secrets: AgentSecretsClient,\n params: {\n workspaceId: string;\n providerId: ModelProviderRef;\n },\n): Promise<Record<string, string>> {\n const {values} = await secrets.getSecretsByNamespace({\n workspaceId: params.workspaceId,\n namespace: agentSystemNamespace(params.providerId),\n });\n return storeValuesToCustomRuntimeCredentials(values);\n}\n\nfunction assertStoredSecretsNotReusedAfterBaseUrlChange(params: {\n body: UpdateCustomModelProviderBodyDto | DiscoverCustomModelProviderModelsBySlugBodyDto;\n existing: ModelProviderConfig;\n existingSecrets: Record<string, string>;\n providerId: ModelProviderRef;\n}): void {\n if (\n params.body.base_url === undefined ||\n normalizedUrl(params.body.base_url) === normalizedUrl(params.existing.baseUrl ?? '')\n ) {\n return;\n }\n\n const reusesStoredApiKey =\n params.existingSecrets.api_key !== undefined && params.body.api_key === undefined;\n const reusesStoredSecretHeader =\n params.body.headers === undefined\n ? Object.keys(params.existingSecrets).some((key) => key.startsWith('header:'))\n : params.body.headers.some((header) => header.keep === true);\n\n if (reusesStoredApiKey || reusesStoredSecretHeader) {\n throw new CustomModelProviderStoredSecretBaseUrlChangeError(params.providerId);\n }\n}\n\nfunction normalizedUrl(value: string): string {\n return normalizeCustomProviderBaseUrl(value);\n}\n\nasync function rollbackCustomProviderSecretUpdate(\n secrets: AgentSecretsClient,\n params: {\n workspaceId: string;\n namespace: string;\n existingSecrets: Record<string, string>;\n attemptedSecrets: Record<string, string>;\n },\n): Promise<void> {\n const attemptedKeys = Object.keys(params.attemptedSecrets);\n if (attemptedKeys.length === 0) return;\n\n const secretsToRestore = Object.fromEntries(\n attemptedKeys.flatMap((key) => {\n const value = params.existingSecrets[key];\n return value === undefined ? [] : [[key, value]];\n }),\n );\n if (Object.keys(secretsToRestore).length > 0) {\n await secrets.setSecrets({\n workspaceId: params.workspaceId,\n namespace: params.namespace,\n values: customCredentialsToStoreValues(secretsToRestore),\n });\n }\n\n const newKeys = attemptedKeys.filter((key) => params.existingSecrets[key] === undefined);\n if (newKeys.length === 0) return;\n\n await secrets.deleteSecrets({\n workspaceId: params.workspaceId,\n namespace: params.namespace,\n keys: newKeys.map(customCredentialToStoreKey),\n });\n}\n\nasync function pruneStaleCustomHeaderSecrets(\n secrets: AgentSecretsClient,\n params: {\n workspaceId: string;\n providerId: ModelProviderRef;\n existingSecrets: Record<string, string>;\n newSecrets: Record<string, string>;\n replaceHeaders: boolean;\n },\n): Promise<void> {\n if (!params.replaceHeaders) return;\n\n const nextKeys = new Set(Object.keys(params.newSecrets));\n const staleKeys = Object.keys(params.existingSecrets).filter(\n (key) => key.startsWith('header:') && !nextKeys.has(key),\n );\n if (staleKeys.length === 0) return;\n\n await secrets.deleteSecrets({\n workspaceId: params.workspaceId,\n namespace: agentSystemNamespace(params.providerId),\n keys: staleKeys.map(customCredentialToStoreKey),\n });\n}\n\nfunction secretHeaderNamesFromCredentials(credentials: Record<string, string>): string[] {\n return Object.keys(credentials)\n .filter((key) => key.startsWith('header:'))\n .map((key) => key.slice('header:'.length))\n .sort();\n}\n"],"names":["DEFAULT_AGENT_THINKING","assertEgressAllowed","deleteModelProviderConfig","getModelProviderConfig","insertCustomModelProviderConfig","upsertModelProviderConfig","agentSystemNamespace","customCredentialsToStoreValues","customCredentialToStoreKey","storeValuesToCustomRuntimeCredentials","normalizeCustomProviderBaseUrl","CustomModelProviderConfigNotFoundError","CustomModelProviderSlugCollisionError","CustomModelProviderStoredSecretBaseUrlChangeError","InvalidAgentModelError","InvalidCustomModelProviderHeaderKeepError","egressPolicy","probeCustomModelProviderCredentials","runProviderProbe","requireAgentSecretsClient","createCustomModelProviderConfig","params","options","probe","secrets","existing","workspaceId","providerId","body","slug","undefined","splitHeaders","splitCustomHeaders","headers","secretCredentials","api_key","probeModel","selectProbeModel","models","default_model","base_url","args","api","baseUrl","model","apiKey","runtimeHeaders","signal","metricLabel","Object","values","config","kind","displayName","display_name","plaintextHeaders","secretHeaderNames","requiresApiKey","defaultModel","defaultThinking","setAsDefault","setSecrets","namespace","error","deleteSecrets","updateCustomModelProviderConfig","getExistingCustomConfig","existingSecrets","getCustomProviderSecrets","nextModels","nextDefaultModel","resolveNextDefaultModel","nextApi","nextBaseUrl","nextDisplayName","assertStoredSecretsNotReusedAfterBaseUrlChange","nextHeaders","resolveNextHeaders","requestHeaders","nextApiKey","newSecretCredentials","probeSecretCredentials","updated","rollbackCustomProviderSecretUpdate","attemptedSecrets","catch","pruneStaleCustomHeaderSecrets","newSecrets","replaceHeaders","resolveCustomModelProviderDiscoveryParams","entries","map","name","value","header","secret","push","splitUpdateHeaders","key","startsWith","slice","length","secretHeaderNamesFromCredentials","keep","existingDefaultModel","some","id","requestedDefaultModel","find","candidate","Error","getSecretsByNamespace","normalizedUrl","reusesStoredApiKey","reusesStoredSecretHeader","keys","attemptedKeys","secretsToRestore","fromEntries","flatMap","newKeys","filter","nextKeys","Set","staleKeys","has","credentials","sort"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ModelProviderRef, type SupportedModelProviderId } from '@shipfox/api-agent-dto';
|
|
2
2
|
import type { ModelProviderConfig } from './entities/model-provider-config.js';
|
|
3
3
|
import { probeModelProviderCredentials } from './model-provider-validation.js';
|
|
4
|
+
import { type AgentSecretsClient } from './secrets-client.js';
|
|
4
5
|
export interface TestAndSaveModelProviderConfigParams {
|
|
5
6
|
workspaceId: string;
|
|
6
7
|
providerId: SupportedModelProviderId;
|
|
@@ -12,6 +13,7 @@ export interface TestAndSaveModelProviderConfigParams {
|
|
|
12
13
|
}
|
|
13
14
|
export interface TestAndSaveModelProviderConfigOptions {
|
|
14
15
|
probe?: typeof probeModelProviderCredentials;
|
|
16
|
+
secrets?: AgentSecretsClient | undefined;
|
|
15
17
|
pruneStaleSecrets?: ((params: {
|
|
16
18
|
workspaceId: string;
|
|
17
19
|
namespace: string;
|
|
@@ -28,5 +30,7 @@ export declare function updateModelProviderConfigDefaultModel(params: UpdateMode
|
|
|
28
30
|
export declare function deleteModelProviderConfig(params: {
|
|
29
31
|
workspaceId: string;
|
|
30
32
|
providerId: ModelProviderRef;
|
|
33
|
+
}, options?: {
|
|
34
|
+
secrets?: AgentSecretsClient | undefined;
|
|
31
35
|
}): Promise<boolean>;
|
|
32
36
|
//# sourceMappingURL=model-provider-config-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-provider-config-service.d.ts","sourceRoot":"","sources":["../../src/core/model-provider-config-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gBAAgB,EAErB,KAAK,wBAAwB,EAC9B,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"model-provider-config-service.d.ts","sourceRoot":"","sources":["../../src/core/model-provider-config-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gBAAgB,EAErB,KAAK,wBAAwB,EAC9B,MAAM,wBAAwB,CAAC;AAQhC,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,qCAAqC,CAAC;AAQ7E,OAAO,EAAC,6BAA6B,EAAmB,MAAM,gCAAgC,CAAC;AAC/F,OAAO,EAAC,KAAK,kBAAkB,EAA4B,MAAM,qBAAqB,CAAC;AAEvF,MAAM,WAAW,oCAAoC;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,wBAAwB,CAAC;IACrC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACrC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,qCAAqC;IACpD,KAAK,CAAC,EAAE,OAAO,6BAA6B,CAAC;IAC7C,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACzC,iBAAiB,CAAC,EACd,CAAC,CAAC,MAAM,EAAE;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,EAAE,CAAA;KAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GAC7F,SAAS,CAAC;CACf;AAED,MAAM,WAAW,2CAA2C;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,oCAAoC,EAC5C,OAAO,GAAE,qCAA0C,GAClD,OAAO,CAAC,mBAAmB,CAAC,CA6D9B;AAED,wBAAsB,qCAAqC,CACzD,MAAM,EAAE,2CAA2C,GAClD,OAAO,CAAC,mBAAmB,CAAC,CAwC9B;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,gBAAgB,CAAA;CAAC,EAC3D,OAAO,GAAE;IAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAA;CAAM,GACvD,OAAO,CAAC,OAAO,CAAC,CAQlB"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { DEFAULT_AGENT_THINKING, getModelProviderEntry, modelProviderCredentialKeysMatch } from '@shipfox/api-agent-dto';
|
|
2
|
-
import { deleteSecrets, getSecretsByNamespace, setSecrets } from '@shipfox/api-secrets';
|
|
3
2
|
import { deleteModelProviderConfig as deleteModelProviderConfigRow, getModelProviderConfig, updateModelProviderDefaultModel, upsertModelProviderConfig } from '#db/index.js';
|
|
4
3
|
import { agentSystemNamespace, credentialsToStoreValues } from './credential-fingerprints.js';
|
|
5
4
|
import { InvalidAgentModelError, InvalidCredentialFieldsError, ModelProviderConfigNotFoundError, UnsupportedModelProviderError } from './errors.js';
|
|
6
5
|
import { buildModelProviderCatalog } from './model-provider-catalog.js';
|
|
7
6
|
import { probeModelProviderCredentials, runProviderProbe } from './model-provider-validation.js';
|
|
7
|
+
import { requireAgentSecretsClient } from './secrets-client.js';
|
|
8
8
|
export async function testAndSaveModelProviderConfig(params, options = {}) {
|
|
9
9
|
const probe = options.probe ?? probeModelProviderCredentials;
|
|
10
|
+
const secrets = requireAgentSecretsClient(options.secrets);
|
|
10
11
|
const entry = getModelProviderEntry(params.providerId);
|
|
11
12
|
if (entry === undefined || entry.support_status !== 'supported') {
|
|
12
13
|
throw new UnsupportedModelProviderError(params.providerId);
|
|
@@ -35,10 +36,10 @@ export async function testAndSaveModelProviderConfig(params, options = {}) {
|
|
|
35
36
|
secrets: Object.values(params.credentials),
|
|
36
37
|
signal: params.signal
|
|
37
38
|
});
|
|
38
|
-
const pruneStaleSecrets = options.pruneStaleSecrets ?? pruneStaleProviderCredentialSecrets;
|
|
39
|
+
const pruneStaleSecrets = options.pruneStaleSecrets ?? ((input)=>pruneStaleProviderCredentialSecrets(secrets, input));
|
|
39
40
|
const namespace = agentSystemNamespace(params.providerId);
|
|
40
41
|
const values = credentialsToStoreValues(params.providerId, params.credentials);
|
|
41
|
-
await setSecrets({
|
|
42
|
+
await secrets.setSecrets({
|
|
42
43
|
workspaceId: params.workspaceId,
|
|
43
44
|
namespace,
|
|
44
45
|
values,
|
|
@@ -93,9 +94,10 @@ export async function updateModelProviderConfigDefaultModel(params) {
|
|
|
93
94
|
if (!config) throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);
|
|
94
95
|
return config;
|
|
95
96
|
}
|
|
96
|
-
export async function deleteModelProviderConfig(params) {
|
|
97
|
+
export async function deleteModelProviderConfig(params, options = {}) {
|
|
98
|
+
const secrets = requireAgentSecretsClient(options.secrets);
|
|
97
99
|
const deleted = await deleteModelProviderConfigRow(params);
|
|
98
|
-
await deleteSecrets({
|
|
100
|
+
await secrets.deleteSecrets({
|
|
99
101
|
workspaceId: params.workspaceId,
|
|
100
102
|
namespace: agentSystemNamespace(params.providerId)
|
|
101
103
|
});
|
|
@@ -115,15 +117,15 @@ function resolveDefaultModel(providerId, requestedModel) {
|
|
|
115
117
|
storedModel: requestedModel ?? null
|
|
116
118
|
};
|
|
117
119
|
}
|
|
118
|
-
async function pruneStaleProviderCredentialSecrets(params) {
|
|
119
|
-
const stored = await getSecretsByNamespace({
|
|
120
|
+
async function pruneStaleProviderCredentialSecrets(secrets, params) {
|
|
121
|
+
const { values: stored } = await secrets.getSecretsByNamespace({
|
|
120
122
|
workspaceId: params.workspaceId,
|
|
121
123
|
namespace: params.namespace
|
|
122
124
|
});
|
|
123
125
|
const expected = new Set(params.expectedKeys);
|
|
124
126
|
const staleKeys = Object.keys(stored).filter((key)=>!expected.has(key));
|
|
125
127
|
if (staleKeys.length === 0) return;
|
|
126
|
-
await deleteSecrets({
|
|
128
|
+
await secrets.deleteSecrets({
|
|
127
129
|
workspaceId: params.workspaceId,
|
|
128
130
|
namespace: params.namespace,
|
|
129
131
|
keys: staleKeys
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/model-provider-config-service.ts"],"sourcesContent":["import {\n DEFAULT_AGENT_THINKING,\n getModelProviderEntry,\n type ModelProviderRef,\n modelProviderCredentialKeysMatch,\n type SupportedModelProviderId,\n} from '@shipfox/api-agent-dto';\nimport {deleteSecrets, getSecretsByNamespace, setSecrets} from '@shipfox/api-secrets';\nimport {\n deleteModelProviderConfig as deleteModelProviderConfigRow,\n getModelProviderConfig,\n updateModelProviderDefaultModel,\n upsertModelProviderConfig,\n} from '#db/index.js';\nimport {agentSystemNamespace, credentialsToStoreValues} from './credential-fingerprints.js';\nimport type {ModelProviderConfig} from './entities/model-provider-config.js';\nimport {\n InvalidAgentModelError,\n InvalidCredentialFieldsError,\n ModelProviderConfigNotFoundError,\n UnsupportedModelProviderError,\n} from './errors.js';\nimport {buildModelProviderCatalog} from './model-provider-catalog.js';\nimport {probeModelProviderCredentials, runProviderProbe} from './model-provider-validation.js';\n\nexport interface TestAndSaveModelProviderConfigParams {\n workspaceId: string;\n providerId: SupportedModelProviderId;\n defaultModel?: string | null | undefined;\n credentials: Record<string, string>;\n editedBy?: string | null | undefined;\n setAsDefault?: boolean | undefined;\n signal?: AbortSignal | undefined;\n}\n\nexport interface TestAndSaveModelProviderConfigOptions {\n probe?: typeof probeModelProviderCredentials;\n pruneStaleSecrets?:\n | ((params: {workspaceId: string; namespace: string; expectedKeys: string[]}) => Promise<void>)\n | undefined;\n}\n\nexport interface UpdateModelProviderConfigDefaultModelParams {\n workspaceId: string;\n providerId: ModelProviderRef;\n defaultModel: string | null;\n}\n\nexport async function testAndSaveModelProviderConfig(\n params: TestAndSaveModelProviderConfigParams,\n options: TestAndSaveModelProviderConfigOptions = {},\n): Promise<ModelProviderConfig> {\n const probe = options.probe ?? probeModelProviderCredentials;\n const entry = getModelProviderEntry(params.providerId);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(params.providerId);\n }\n if (entry.default_model === null) throw new UnsupportedModelProviderError(params.providerId);\n\n if (!modelProviderCredentialKeysMatch(params.providerId, params.credentials)) {\n throw new InvalidCredentialFieldsError(params.providerId);\n }\n\n const existingConfig = await getModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n });\n const modelSelection = resolveDefaultModel(\n params.providerId,\n params.defaultModel !== undefined ? params.defaultModel : existingConfig?.defaultModel,\n );\n\n await runProviderProbe({\n probe,\n args: {\n providerId: params.providerId,\n model: modelSelection.probeModel,\n credentials: params.credentials,\n ...(params.signal ? {signal: params.signal} : {}),\n },\n metricLabel: params.providerId,\n providerId: params.providerId,\n secrets: Object.values(params.credentials),\n signal: params.signal,\n });\n const pruneStaleSecrets = options.pruneStaleSecrets ?? pruneStaleProviderCredentialSecrets;\n const namespace = agentSystemNamespace(params.providerId);\n const values = credentialsToStoreValues(params.providerId, params.credentials);\n await setSecrets({\n workspaceId: params.workspaceId,\n namespace,\n values,\n editedBy: params.editedBy,\n });\n\n const config = await upsertModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n defaultModel: modelSelection.storedModel,\n defaultThinking: DEFAULT_AGENT_THINKING,\n setAsDefault: params.setAsDefault,\n });\n\n await pruneStaleSecrets({\n workspaceId: params.workspaceId,\n namespace,\n expectedKeys: Object.keys(values),\n }).catch(() => undefined);\n\n return config;\n}\n\nexport async function updateModelProviderConfigDefaultModel(\n params: UpdateModelProviderConfigDefaultModelParams,\n): Promise<ModelProviderConfig> {\n const existingConfig = await getModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n });\n if (!existingConfig) {\n throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);\n }\n if (existingConfig.kind === 'custom') {\n if (\n params.defaultModel !== null &&\n !existingConfig.models?.some((model) => model.id === params.defaultModel)\n ) {\n throw new InvalidAgentModelError('pi', params.providerId, params.defaultModel);\n }\n\n const config = await updateModelProviderDefaultModel({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n defaultModel: params.defaultModel,\n });\n if (!config) throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);\n return config;\n }\n\n const providerId = params.providerId as SupportedModelProviderId;\n const entry = getModelProviderEntry(providerId);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(params.providerId);\n }\n if (entry.default_model === null) throw new UnsupportedModelProviderError(params.providerId);\n\n const modelSelection = resolveDefaultModel(providerId, params.defaultModel);\n const config = await updateModelProviderDefaultModel({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n defaultModel: modelSelection.storedModel,\n });\n if (!config) throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);\n return config;\n}\n\nexport async function deleteModelProviderConfig(params: {\n workspaceId: string;\n providerId: ModelProviderRef;\n}): Promise<boolean> {\n const deleted = await deleteModelProviderConfigRow(params);\n await deleteSecrets({\n workspaceId: params.workspaceId,\n namespace: agentSystemNamespace(params.providerId),\n });\n return deleted;\n}\n\nfunction resolveDefaultModel(\n providerId: SupportedModelProviderId,\n requestedModel: string | null | undefined,\n): {probeModel: string; storedModel: string | null} {\n const catalogEntry = buildModelProviderCatalog().find((entry) => entry.id === providerId);\n if (\n catalogEntry === undefined ||\n catalogEntry.support_status !== 'supported' ||\n catalogEntry.default_model === null\n ) {\n throw new UnsupportedModelProviderError(providerId);\n }\n\n const model = requestedModel ?? catalogEntry.default_model;\n if (!catalogEntry.models.some((candidate) => candidate.id === model)) {\n throw new InvalidAgentModelError('pi', providerId, model);\n }\n return {probeModel: model, storedModel: requestedModel ?? null};\n}\n\nasync function pruneStaleProviderCredentialSecrets(params: {\n workspaceId: string;\n namespace: string;\n expectedKeys: string[];\n}): Promise<void> {\n const stored = await getSecretsByNamespace({\n workspaceId: params.workspaceId,\n namespace: params.namespace,\n });\n const expected = new Set(params.expectedKeys);\n const staleKeys = Object.keys(stored).filter((key) => !expected.has(key));\n if (staleKeys.length === 0) return;\n\n await deleteSecrets({\n workspaceId: params.workspaceId,\n namespace: params.namespace,\n keys: staleKeys,\n });\n}\n"],"names":["DEFAULT_AGENT_THINKING","getModelProviderEntry","modelProviderCredentialKeysMatch","deleteSecrets","getSecretsByNamespace","setSecrets","deleteModelProviderConfig","deleteModelProviderConfigRow","getModelProviderConfig","updateModelProviderDefaultModel","upsertModelProviderConfig","agentSystemNamespace","credentialsToStoreValues","InvalidAgentModelError","InvalidCredentialFieldsError","ModelProviderConfigNotFoundError","UnsupportedModelProviderError","buildModelProviderCatalog","probeModelProviderCredentials","runProviderProbe","testAndSaveModelProviderConfig","params","options","probe","entry","providerId","undefined","support_status","default_model","credentials","existingConfig","workspaceId","modelSelection","resolveDefaultModel","defaultModel","args","model","probeModel","signal","metricLabel","secrets","Object","values","pruneStaleSecrets","pruneStaleProviderCredentialSecrets","namespace","editedBy","config","storedModel","defaultThinking","setAsDefault","expectedKeys","keys","catch","updateModelProviderConfigDefaultModel","kind","models","some","id","deleted","requestedModel","catalogEntry","find","candidate","stored","expected","Set","staleKeys","filter","key","has","length"],"mappings":"AAAA,SACEA,sBAAsB,EACtBC,qBAAqB,EAErBC,gCAAgC,QAE3B,yBAAyB;AAChC,SAAQC,aAAa,EAAEC,qBAAqB,EAAEC,UAAU,QAAO,uBAAuB;AACtF,SACEC,6BAA6BC,4BAA4B,EACzDC,sBAAsB,EACtBC,+BAA+B,EAC/BC,yBAAyB,QACpB,eAAe;AACtB,SAAQC,oBAAoB,EAAEC,wBAAwB,QAAO,+BAA+B;AAE5F,SACEC,sBAAsB,EACtBC,4BAA4B,EAC5BC,gCAAgC,EAChCC,6BAA6B,QACxB,cAAc;AACrB,SAAQC,yBAAyB,QAAO,8BAA8B;AACtE,SAAQC,6BAA6B,EAAEC,gBAAgB,QAAO,iCAAiC;AAyB/F,OAAO,eAAeC,+BACpBC,MAA4C,EAC5CC,UAAiD,CAAC,CAAC;IAEnD,MAAMC,QAAQD,QAAQC,KAAK,IAAIL;IAC/B,MAAMM,QAAQvB,sBAAsBoB,OAAOI,UAAU;IACrD,IAAID,UAAUE,aAAaF,MAAMG,cAAc,KAAK,aAAa;QAC/D,MAAM,IAAIX,8BAA8BK,OAAOI,UAAU;IAC3D;IACA,IAAID,MAAMI,aAAa,KAAK,MAAM,MAAM,IAAIZ,8BAA8BK,OAAOI,UAAU;IAE3F,IAAI,CAACvB,iCAAiCmB,OAAOI,UAAU,EAAEJ,OAAOQ,WAAW,GAAG;QAC5E,MAAM,IAAIf,6BAA6BO,OAAOI,UAAU;IAC1D;IAEA,MAAMK,iBAAiB,MAAMtB,uBAAuB;QAClDuB,aAAaV,OAAOU,WAAW;QAC/BN,YAAYJ,OAAOI,UAAU;IAC/B;IACA,MAAMO,iBAAiBC,oBACrBZ,OAAOI,UAAU,EACjBJ,OAAOa,YAAY,KAAKR,YAAYL,OAAOa,YAAY,GAAGJ,gBAAgBI;IAG5E,MAAMf,iBAAiB;QACrBI;QACAY,MAAM;YACJV,YAAYJ,OAAOI,UAAU;YAC7BW,OAAOJ,eAAeK,UAAU;YAChCR,aAAaR,OAAOQ,WAAW;YAC/B,GAAIR,OAAOiB,MAAM,GAAG;gBAACA,QAAQjB,OAAOiB,MAAM;YAAA,IAAI,CAAC,CAAC;QAClD;QACAC,aAAalB,OAAOI,UAAU;QAC9BA,YAAYJ,OAAOI,UAAU;QAC7Be,SAASC,OAAOC,MAAM,CAACrB,OAAOQ,WAAW;QACzCS,QAAQjB,OAAOiB,MAAM;IACvB;IACA,MAAMK,oBAAoBrB,QAAQqB,iBAAiB,IAAIC;IACvD,MAAMC,YAAYlC,qBAAqBU,OAAOI,UAAU;IACxD,MAAMiB,SAAS9B,yBAAyBS,OAAOI,UAAU,EAAEJ,OAAOQ,WAAW;IAC7E,MAAMxB,WAAW;QACf0B,aAAaV,OAAOU,WAAW;QAC/Bc;QACAH;QACAI,UAAUzB,OAAOyB,QAAQ;IAC3B;IAEA,MAAMC,SAAS,MAAMrC,0BAA0B;QAC7CqB,aAAaV,OAAOU,WAAW;QAC/BN,YAAYJ,OAAOI,UAAU;QAC7BS,cAAcF,eAAegB,WAAW;QACxCC,iBAAiBjD;QACjBkD,cAAc7B,OAAO6B,YAAY;IACnC;IAEA,MAAMP,kBAAkB;QACtBZ,aAAaV,OAAOU,WAAW;QAC/Bc;QACAM,cAAcV,OAAOW,IAAI,CAACV;IAC5B,GAAGW,KAAK,CAAC,IAAM3B;IAEf,OAAOqB;AACT;AAEA,OAAO,eAAeO,sCACpBjC,MAAmD;IAEnD,MAAMS,iBAAiB,MAAMtB,uBAAuB;QAClDuB,aAAaV,OAAOU,WAAW;QAC/BN,YAAYJ,OAAOI,UAAU;IAC/B;IACA,IAAI,CAACK,gBAAgB;QACnB,MAAM,IAAIf,iCAAiCM,OAAOU,WAAW,EAAEV,OAAOI,UAAU;IAClF;IACA,IAAIK,eAAeyB,IAAI,KAAK,UAAU;QACpC,IACElC,OAAOa,YAAY,KAAK,QACxB,CAACJ,eAAe0B,MAAM,EAAEC,KAAK,CAACrB,QAAUA,MAAMsB,EAAE,KAAKrC,OAAOa,YAAY,GACxE;YACA,MAAM,IAAIrB,uBAAuB,MAAMQ,OAAOI,UAAU,EAAEJ,OAAOa,YAAY;QAC/E;QAEA,MAAMa,SAAS,MAAMtC,gCAAgC;YACnDsB,aAAaV,OAAOU,WAAW;YAC/BN,YAAYJ,OAAOI,UAAU;YAC7BS,cAAcb,OAAOa,YAAY;QACnC;QACA,IAAI,CAACa,QAAQ,MAAM,IAAIhC,iCAAiCM,OAAOU,WAAW,EAAEV,OAAOI,UAAU;QAC7F,OAAOsB;IACT;IAEA,MAAMtB,aAAaJ,OAAOI,UAAU;IACpC,MAAMD,QAAQvB,sBAAsBwB;IACpC,IAAID,UAAUE,aAAaF,MAAMG,cAAc,KAAK,aAAa;QAC/D,MAAM,IAAIX,8BAA8BK,OAAOI,UAAU;IAC3D;IACA,IAAID,MAAMI,aAAa,KAAK,MAAM,MAAM,IAAIZ,8BAA8BK,OAAOI,UAAU;IAE3F,MAAMO,iBAAiBC,oBAAoBR,YAAYJ,OAAOa,YAAY;IAC1E,MAAMa,SAAS,MAAMtC,gCAAgC;QACnDsB,aAAaV,OAAOU,WAAW;QAC/BN,YAAYJ,OAAOI,UAAU;QAC7BS,cAAcF,eAAegB,WAAW;IAC1C;IACA,IAAI,CAACD,QAAQ,MAAM,IAAIhC,iCAAiCM,OAAOU,WAAW,EAAEV,OAAOI,UAAU;IAC7F,OAAOsB;AACT;AAEA,OAAO,eAAezC,0BAA0Be,MAG/C;IACC,MAAMsC,UAAU,MAAMpD,6BAA6Bc;IACnD,MAAMlB,cAAc;QAClB4B,aAAaV,OAAOU,WAAW;QAC/Bc,WAAWlC,qBAAqBU,OAAOI,UAAU;IACnD;IACA,OAAOkC;AACT;AAEA,SAAS1B,oBACPR,UAAoC,EACpCmC,cAAyC;IAEzC,MAAMC,eAAe5C,4BAA4B6C,IAAI,CAAC,CAACtC,QAAUA,MAAMkC,EAAE,KAAKjC;IAC9E,IACEoC,iBAAiBnC,aACjBmC,aAAalC,cAAc,KAAK,eAChCkC,aAAajC,aAAa,KAAK,MAC/B;QACA,MAAM,IAAIZ,8BAA8BS;IAC1C;IAEA,MAAMW,QAAQwB,kBAAkBC,aAAajC,aAAa;IAC1D,IAAI,CAACiC,aAAaL,MAAM,CAACC,IAAI,CAAC,CAACM,YAAcA,UAAUL,EAAE,KAAKtB,QAAQ;QACpE,MAAM,IAAIvB,uBAAuB,MAAMY,YAAYW;IACrD;IACA,OAAO;QAACC,YAAYD;QAAOY,aAAaY,kBAAkB;IAAI;AAChE;AAEA,eAAehB,oCAAoCvB,MAIlD;IACC,MAAM2C,SAAS,MAAM5D,sBAAsB;QACzC2B,aAAaV,OAAOU,WAAW;QAC/Bc,WAAWxB,OAAOwB,SAAS;IAC7B;IACA,MAAMoB,WAAW,IAAIC,IAAI7C,OAAO8B,YAAY;IAC5C,MAAMgB,YAAY1B,OAAOW,IAAI,CAACY,QAAQI,MAAM,CAAC,CAACC,MAAQ,CAACJ,SAASK,GAAG,CAACD;IACpE,IAAIF,UAAUI,MAAM,KAAK,GAAG;IAE5B,MAAMpE,cAAc;QAClB4B,aAAaV,OAAOU,WAAW;QAC/Bc,WAAWxB,OAAOwB,SAAS;QAC3BO,MAAMe;IACR;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/model-provider-config-service.ts"],"sourcesContent":["import {\n DEFAULT_AGENT_THINKING,\n getModelProviderEntry,\n type ModelProviderRef,\n modelProviderCredentialKeysMatch,\n type SupportedModelProviderId,\n} from '@shipfox/api-agent-dto';\nimport {\n deleteModelProviderConfig as deleteModelProviderConfigRow,\n getModelProviderConfig,\n updateModelProviderDefaultModel,\n upsertModelProviderConfig,\n} from '#db/index.js';\nimport {agentSystemNamespace, credentialsToStoreValues} from './credential-fingerprints.js';\nimport type {ModelProviderConfig} from './entities/model-provider-config.js';\nimport {\n InvalidAgentModelError,\n InvalidCredentialFieldsError,\n ModelProviderConfigNotFoundError,\n UnsupportedModelProviderError,\n} from './errors.js';\nimport {buildModelProviderCatalog} from './model-provider-catalog.js';\nimport {probeModelProviderCredentials, runProviderProbe} from './model-provider-validation.js';\nimport {type AgentSecretsClient, requireAgentSecretsClient} from './secrets-client.js';\n\nexport interface TestAndSaveModelProviderConfigParams {\n workspaceId: string;\n providerId: SupportedModelProviderId;\n defaultModel?: string | null | undefined;\n credentials: Record<string, string>;\n editedBy?: string | null | undefined;\n setAsDefault?: boolean | undefined;\n signal?: AbortSignal | undefined;\n}\n\nexport interface TestAndSaveModelProviderConfigOptions {\n probe?: typeof probeModelProviderCredentials;\n secrets?: AgentSecretsClient | undefined;\n pruneStaleSecrets?:\n | ((params: {workspaceId: string; namespace: string; expectedKeys: string[]}) => Promise<void>)\n | undefined;\n}\n\nexport interface UpdateModelProviderConfigDefaultModelParams {\n workspaceId: string;\n providerId: ModelProviderRef;\n defaultModel: string | null;\n}\n\nexport async function testAndSaveModelProviderConfig(\n params: TestAndSaveModelProviderConfigParams,\n options: TestAndSaveModelProviderConfigOptions = {},\n): Promise<ModelProviderConfig> {\n const probe = options.probe ?? probeModelProviderCredentials;\n const secrets = requireAgentSecretsClient(options.secrets);\n const entry = getModelProviderEntry(params.providerId);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(params.providerId);\n }\n if (entry.default_model === null) throw new UnsupportedModelProviderError(params.providerId);\n\n if (!modelProviderCredentialKeysMatch(params.providerId, params.credentials)) {\n throw new InvalidCredentialFieldsError(params.providerId);\n }\n\n const existingConfig = await getModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n });\n const modelSelection = resolveDefaultModel(\n params.providerId,\n params.defaultModel !== undefined ? params.defaultModel : existingConfig?.defaultModel,\n );\n\n await runProviderProbe({\n probe,\n args: {\n providerId: params.providerId,\n model: modelSelection.probeModel,\n credentials: params.credentials,\n ...(params.signal ? {signal: params.signal} : {}),\n },\n metricLabel: params.providerId,\n providerId: params.providerId,\n secrets: Object.values(params.credentials),\n signal: params.signal,\n });\n const pruneStaleSecrets =\n options.pruneStaleSecrets ?? ((input) => pruneStaleProviderCredentialSecrets(secrets, input));\n const namespace = agentSystemNamespace(params.providerId);\n const values = credentialsToStoreValues(params.providerId, params.credentials);\n await secrets.setSecrets({\n workspaceId: params.workspaceId,\n namespace,\n values,\n editedBy: params.editedBy,\n });\n\n const config = await upsertModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n defaultModel: modelSelection.storedModel,\n defaultThinking: DEFAULT_AGENT_THINKING,\n setAsDefault: params.setAsDefault,\n });\n\n await pruneStaleSecrets({\n workspaceId: params.workspaceId,\n namespace,\n expectedKeys: Object.keys(values),\n }).catch(() => undefined);\n\n return config;\n}\n\nexport async function updateModelProviderConfigDefaultModel(\n params: UpdateModelProviderConfigDefaultModelParams,\n): Promise<ModelProviderConfig> {\n const existingConfig = await getModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n });\n if (!existingConfig) {\n throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);\n }\n if (existingConfig.kind === 'custom') {\n if (\n params.defaultModel !== null &&\n !existingConfig.models?.some((model) => model.id === params.defaultModel)\n ) {\n throw new InvalidAgentModelError('pi', params.providerId, params.defaultModel);\n }\n\n const config = await updateModelProviderDefaultModel({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n defaultModel: params.defaultModel,\n });\n if (!config) throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);\n return config;\n }\n\n const providerId = params.providerId as SupportedModelProviderId;\n const entry = getModelProviderEntry(providerId);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(params.providerId);\n }\n if (entry.default_model === null) throw new UnsupportedModelProviderError(params.providerId);\n\n const modelSelection = resolveDefaultModel(providerId, params.defaultModel);\n const config = await updateModelProviderDefaultModel({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n defaultModel: modelSelection.storedModel,\n });\n if (!config) throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);\n return config;\n}\n\nexport async function deleteModelProviderConfig(\n params: {workspaceId: string; providerId: ModelProviderRef},\n options: {secrets?: AgentSecretsClient | undefined} = {},\n): Promise<boolean> {\n const secrets = requireAgentSecretsClient(options.secrets);\n const deleted = await deleteModelProviderConfigRow(params);\n await secrets.deleteSecrets({\n workspaceId: params.workspaceId,\n namespace: agentSystemNamespace(params.providerId),\n });\n return deleted;\n}\n\nfunction resolveDefaultModel(\n providerId: SupportedModelProviderId,\n requestedModel: string | null | undefined,\n): {probeModel: string; storedModel: string | null} {\n const catalogEntry = buildModelProviderCatalog().find((entry) => entry.id === providerId);\n if (\n catalogEntry === undefined ||\n catalogEntry.support_status !== 'supported' ||\n catalogEntry.default_model === null\n ) {\n throw new UnsupportedModelProviderError(providerId);\n }\n\n const model = requestedModel ?? catalogEntry.default_model;\n if (!catalogEntry.models.some((candidate) => candidate.id === model)) {\n throw new InvalidAgentModelError('pi', providerId, model);\n }\n return {probeModel: model, storedModel: requestedModel ?? null};\n}\n\nasync function pruneStaleProviderCredentialSecrets(\n secrets: AgentSecretsClient,\n params: {workspaceId: string; namespace: string; expectedKeys: string[]},\n): Promise<void> {\n const {values: stored} = await secrets.getSecretsByNamespace({\n workspaceId: params.workspaceId,\n namespace: params.namespace,\n });\n const expected = new Set(params.expectedKeys);\n const staleKeys = Object.keys(stored).filter((key) => !expected.has(key));\n if (staleKeys.length === 0) return;\n\n await secrets.deleteSecrets({\n workspaceId: params.workspaceId,\n namespace: params.namespace,\n keys: staleKeys,\n });\n}\n"],"names":["DEFAULT_AGENT_THINKING","getModelProviderEntry","modelProviderCredentialKeysMatch","deleteModelProviderConfig","deleteModelProviderConfigRow","getModelProviderConfig","updateModelProviderDefaultModel","upsertModelProviderConfig","agentSystemNamespace","credentialsToStoreValues","InvalidAgentModelError","InvalidCredentialFieldsError","ModelProviderConfigNotFoundError","UnsupportedModelProviderError","buildModelProviderCatalog","probeModelProviderCredentials","runProviderProbe","requireAgentSecretsClient","testAndSaveModelProviderConfig","params","options","probe","secrets","entry","providerId","undefined","support_status","default_model","credentials","existingConfig","workspaceId","modelSelection","resolveDefaultModel","defaultModel","args","model","probeModel","signal","metricLabel","Object","values","pruneStaleSecrets","input","pruneStaleProviderCredentialSecrets","namespace","setSecrets","editedBy","config","storedModel","defaultThinking","setAsDefault","expectedKeys","keys","catch","updateModelProviderConfigDefaultModel","kind","models","some","id","deleted","deleteSecrets","requestedModel","catalogEntry","find","candidate","stored","getSecretsByNamespace","expected","Set","staleKeys","filter","key","has","length"],"mappings":"AAAA,SACEA,sBAAsB,EACtBC,qBAAqB,EAErBC,gCAAgC,QAE3B,yBAAyB;AAChC,SACEC,6BAA6BC,4BAA4B,EACzDC,sBAAsB,EACtBC,+BAA+B,EAC/BC,yBAAyB,QACpB,eAAe;AACtB,SAAQC,oBAAoB,EAAEC,wBAAwB,QAAO,+BAA+B;AAE5F,SACEC,sBAAsB,EACtBC,4BAA4B,EAC5BC,gCAAgC,EAChCC,6BAA6B,QACxB,cAAc;AACrB,SAAQC,yBAAyB,QAAO,8BAA8B;AACtE,SAAQC,6BAA6B,EAAEC,gBAAgB,QAAO,iCAAiC;AAC/F,SAAiCC,yBAAyB,QAAO,sBAAsB;AA0BvF,OAAO,eAAeC,+BACpBC,MAA4C,EAC5CC,UAAiD,CAAC,CAAC;IAEnD,MAAMC,QAAQD,QAAQC,KAAK,IAAIN;IAC/B,MAAMO,UAAUL,0BAA0BG,QAAQE,OAAO;IACzD,MAAMC,QAAQtB,sBAAsBkB,OAAOK,UAAU;IACrD,IAAID,UAAUE,aAAaF,MAAMG,cAAc,KAAK,aAAa;QAC/D,MAAM,IAAIb,8BAA8BM,OAAOK,UAAU;IAC3D;IACA,IAAID,MAAMI,aAAa,KAAK,MAAM,MAAM,IAAId,8BAA8BM,OAAOK,UAAU;IAE3F,IAAI,CAACtB,iCAAiCiB,OAAOK,UAAU,EAAEL,OAAOS,WAAW,GAAG;QAC5E,MAAM,IAAIjB,6BAA6BQ,OAAOK,UAAU;IAC1D;IAEA,MAAMK,iBAAiB,MAAMxB,uBAAuB;QAClDyB,aAAaX,OAAOW,WAAW;QAC/BN,YAAYL,OAAOK,UAAU;IAC/B;IACA,MAAMO,iBAAiBC,oBACrBb,OAAOK,UAAU,EACjBL,OAAOc,YAAY,KAAKR,YAAYN,OAAOc,YAAY,GAAGJ,gBAAgBI;IAG5E,MAAMjB,iBAAiB;QACrBK;QACAa,MAAM;YACJV,YAAYL,OAAOK,UAAU;YAC7BW,OAAOJ,eAAeK,UAAU;YAChCR,aAAaT,OAAOS,WAAW;YAC/B,GAAIT,OAAOkB,MAAM,GAAG;gBAACA,QAAQlB,OAAOkB,MAAM;YAAA,IAAI,CAAC,CAAC;QAClD;QACAC,aAAanB,OAAOK,UAAU;QAC9BA,YAAYL,OAAOK,UAAU;QAC7BF,SAASiB,OAAOC,MAAM,CAACrB,OAAOS,WAAW;QACzCS,QAAQlB,OAAOkB,MAAM;IACvB;IACA,MAAMI,oBACJrB,QAAQqB,iBAAiB,IAAK,CAAA,CAACC,QAAUC,oCAAoCrB,SAASoB,MAAK;IAC7F,MAAME,YAAYpC,qBAAqBW,OAAOK,UAAU;IACxD,MAAMgB,SAAS/B,yBAAyBU,OAAOK,UAAU,EAAEL,OAAOS,WAAW;IAC7E,MAAMN,QAAQuB,UAAU,CAAC;QACvBf,aAAaX,OAAOW,WAAW;QAC/Bc;QACAJ;QACAM,UAAU3B,OAAO2B,QAAQ;IAC3B;IAEA,MAAMC,SAAS,MAAMxC,0BAA0B;QAC7CuB,aAAaX,OAAOW,WAAW;QAC/BN,YAAYL,OAAOK,UAAU;QAC7BS,cAAcF,eAAeiB,WAAW;QACxCC,iBAAiBjD;QACjBkD,cAAc/B,OAAO+B,YAAY;IACnC;IAEA,MAAMT,kBAAkB;QACtBX,aAAaX,OAAOW,WAAW;QAC/Bc;QACAO,cAAcZ,OAAOa,IAAI,CAACZ;IAC5B,GAAGa,KAAK,CAAC,IAAM5B;IAEf,OAAOsB;AACT;AAEA,OAAO,eAAeO,sCACpBnC,MAAmD;IAEnD,MAAMU,iBAAiB,MAAMxB,uBAAuB;QAClDyB,aAAaX,OAAOW,WAAW;QAC/BN,YAAYL,OAAOK,UAAU;IAC/B;IACA,IAAI,CAACK,gBAAgB;QACnB,MAAM,IAAIjB,iCAAiCO,OAAOW,WAAW,EAAEX,OAAOK,UAAU;IAClF;IACA,IAAIK,eAAe0B,IAAI,KAAK,UAAU;QACpC,IACEpC,OAAOc,YAAY,KAAK,QACxB,CAACJ,eAAe2B,MAAM,EAAEC,KAAK,CAACtB,QAAUA,MAAMuB,EAAE,KAAKvC,OAAOc,YAAY,GACxE;YACA,MAAM,IAAIvB,uBAAuB,MAAMS,OAAOK,UAAU,EAAEL,OAAOc,YAAY;QAC/E;QAEA,MAAMc,SAAS,MAAMzC,gCAAgC;YACnDwB,aAAaX,OAAOW,WAAW;YAC/BN,YAAYL,OAAOK,UAAU;YAC7BS,cAAcd,OAAOc,YAAY;QACnC;QACA,IAAI,CAACc,QAAQ,MAAM,IAAInC,iCAAiCO,OAAOW,WAAW,EAAEX,OAAOK,UAAU;QAC7F,OAAOuB;IACT;IAEA,MAAMvB,aAAaL,OAAOK,UAAU;IACpC,MAAMD,QAAQtB,sBAAsBuB;IACpC,IAAID,UAAUE,aAAaF,MAAMG,cAAc,KAAK,aAAa;QAC/D,MAAM,IAAIb,8BAA8BM,OAAOK,UAAU;IAC3D;IACA,IAAID,MAAMI,aAAa,KAAK,MAAM,MAAM,IAAId,8BAA8BM,OAAOK,UAAU;IAE3F,MAAMO,iBAAiBC,oBAAoBR,YAAYL,OAAOc,YAAY;IAC1E,MAAMc,SAAS,MAAMzC,gCAAgC;QACnDwB,aAAaX,OAAOW,WAAW;QAC/BN,YAAYL,OAAOK,UAAU;QAC7BS,cAAcF,eAAeiB,WAAW;IAC1C;IACA,IAAI,CAACD,QAAQ,MAAM,IAAInC,iCAAiCO,OAAOW,WAAW,EAAEX,OAAOK,UAAU;IAC7F,OAAOuB;AACT;AAEA,OAAO,eAAe5C,0BACpBgB,MAA2D,EAC3DC,UAAsD,CAAC,CAAC;IAExD,MAAME,UAAUL,0BAA0BG,QAAQE,OAAO;IACzD,MAAMqC,UAAU,MAAMvD,6BAA6Be;IACnD,MAAMG,QAAQsC,aAAa,CAAC;QAC1B9B,aAAaX,OAAOW,WAAW;QAC/Bc,WAAWpC,qBAAqBW,OAAOK,UAAU;IACnD;IACA,OAAOmC;AACT;AAEA,SAAS3B,oBACPR,UAAoC,EACpCqC,cAAyC;IAEzC,MAAMC,eAAehD,4BAA4BiD,IAAI,CAAC,CAACxC,QAAUA,MAAMmC,EAAE,KAAKlC;IAC9E,IACEsC,iBAAiBrC,aACjBqC,aAAapC,cAAc,KAAK,eAChCoC,aAAanC,aAAa,KAAK,MAC/B;QACA,MAAM,IAAId,8BAA8BW;IAC1C;IAEA,MAAMW,QAAQ0B,kBAAkBC,aAAanC,aAAa;IAC1D,IAAI,CAACmC,aAAaN,MAAM,CAACC,IAAI,CAAC,CAACO,YAAcA,UAAUN,EAAE,KAAKvB,QAAQ;QACpE,MAAM,IAAIzB,uBAAuB,MAAMc,YAAYW;IACrD;IACA,OAAO;QAACC,YAAYD;QAAOa,aAAaa,kBAAkB;IAAI;AAChE;AAEA,eAAelB,oCACbrB,OAA2B,EAC3BH,MAAwE;IAExE,MAAM,EAACqB,QAAQyB,MAAM,EAAC,GAAG,MAAM3C,QAAQ4C,qBAAqB,CAAC;QAC3DpC,aAAaX,OAAOW,WAAW;QAC/Bc,WAAWzB,OAAOyB,SAAS;IAC7B;IACA,MAAMuB,WAAW,IAAIC,IAAIjD,OAAOgC,YAAY;IAC5C,MAAMkB,YAAY9B,OAAOa,IAAI,CAACa,QAAQK,MAAM,CAAC,CAACC,MAAQ,CAACJ,SAASK,GAAG,CAACD;IACpE,IAAIF,UAAUI,MAAM,KAAK,GAAG;IAE5B,MAAMnD,QAAQsC,aAAa,CAAC;QAC1B9B,aAAaX,OAAOW,WAAW;QAC/Bc,WAAWzB,OAAOyB,SAAS;QAC3BQ,MAAMiB;IACR;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AgentRuntimeCredentialsResponseDto, type AgentThinking, type Harness, type ModelProviderRef, type SupportedModelProviderId } from '@shipfox/api-agent-dto';
|
|
2
|
-
import {
|
|
2
|
+
import { type AgentSecretsClient } from './secrets-client.js';
|
|
3
3
|
export interface ResolveRuntimeCredentialsParams {
|
|
4
4
|
workspaceId: string;
|
|
5
5
|
harness: Harness;
|
|
@@ -13,7 +13,11 @@ interface RuntimeCredentialsConfig {
|
|
|
13
13
|
}
|
|
14
14
|
interface ResolveRuntimeCredentialsOptions {
|
|
15
15
|
runtimeConfig?: RuntimeCredentialsConfig | undefined;
|
|
16
|
-
|
|
16
|
+
secrets?: AgentSecretsClient | undefined;
|
|
17
|
+
getCredentialBag?: ((params: {
|
|
18
|
+
workspaceId: string;
|
|
19
|
+
namespace: string;
|
|
20
|
+
}) => Promise<Record<string, string>>) | undefined;
|
|
17
21
|
}
|
|
18
22
|
export declare function resolveRuntimeCredentials(params: ResolveRuntimeCredentialsParams, options?: ResolveRuntimeCredentialsOptions): Promise<AgentRuntimeCredentialsResponseDto>;
|
|
19
23
|
export declare function getInstanceDefaultModelProviderApiKeyField(providerId: ModelProviderRef): 'api_key' | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-runtime-credentials.d.ts","sourceRoot":"","sources":["../../src/core/resolve-runtime-credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kCAAkC,EACvC,KAAK,aAAa,EAElB,KAAK,OAAO,EACZ,KAAK,gBAAgB,EAErB,KAAK,wBAAwB,EAC9B,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"resolve-runtime-credentials.d.ts","sourceRoot":"","sources":["../../src/core/resolve-runtime-credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kCAAkC,EACvC,KAAK,aAAa,EAElB,KAAK,OAAO,EACZ,KAAK,gBAAgB,EAErB,KAAK,wBAAwB,EAC9B,MAAM,wBAAwB,CAAC;AAahC,OAAO,EAAC,KAAK,kBAAkB,EAA4B,MAAM,qBAAqB,CAAC;AAEvF,MAAM,WAAW,+BAA+B;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;CACzB;AAED,UAAU,wBAAwB;IAChC,sBAAsB,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAC9D,8BAA8B,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrD;AAED,UAAU,gCAAgC;IACxC,aAAa,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IACrD,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACzC,gBAAgB,CAAC,EACb,CAAC,CAAC,MAAM,EAAE;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GACvF,SAAS,CAAC;CACf;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,+BAA+B,EACvC,OAAO,CAAC,EAAE,gCAAgC,GACzC,OAAO,CAAC,kCAAkC,CAAC,CA0D7C;AAED,wBAAgB,0CAA0C,CACxD,UAAU,EAAE,gBAAgB,GAC3B,SAAS,GAAG,SAAS,CAQvB"}
|
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import { getModelProviderEntry, modelProviderCredentialKeysMatch } from '@shipfox/api-agent-dto';
|
|
2
|
-
import {
|
|
2
|
+
import { secretsInterModuleContract } from '@shipfox/api-secrets-dto/inter-module';
|
|
3
|
+
import { isInterModuleKnownError } from '@shipfox/inter-module';
|
|
3
4
|
import { config } from '#config.js';
|
|
4
5
|
import { getModelProviderConfig } from '#db/index.js';
|
|
5
6
|
import { agentRuntimeConfigResolvedCount } from '#metrics/index.js';
|
|
6
7
|
import { agentSystemNamespace, storeValuesToCustomRuntimeCredentials, storeValuesToRuntimeCredentials } from './credential-fingerprints.js';
|
|
7
8
|
import { ModelProviderConfigNotFoundError } from './errors.js';
|
|
9
|
+
import { requireAgentSecretsClient } from './secrets-client.js';
|
|
8
10
|
export async function resolveRuntimeCredentials(params, options) {
|
|
9
11
|
const runtimeConfig = options?.runtimeConfig ?? config;
|
|
10
|
-
const
|
|
12
|
+
const secrets = options?.secrets;
|
|
11
13
|
const providerConfig = await getModelProviderConfig({
|
|
12
14
|
workspaceId: params.workspaceId,
|
|
13
15
|
providerId: params.provider
|
|
14
16
|
});
|
|
15
17
|
if (providerConfig) {
|
|
16
18
|
try {
|
|
17
|
-
const values = await getCredentialBag({
|
|
19
|
+
const values = options?.getCredentialBag ? await options.getCredentialBag({
|
|
18
20
|
workspaceId: params.workspaceId,
|
|
19
21
|
namespace: agentSystemNamespace(params.provider)
|
|
20
|
-
})
|
|
22
|
+
}) : (await requireAgentSecretsClient(secrets).getSecretsByNamespace({
|
|
23
|
+
workspaceId: params.workspaceId,
|
|
24
|
+
namespace: agentSystemNamespace(params.provider)
|
|
25
|
+
})).values;
|
|
21
26
|
if (providerConfig.kind === 'custom') {
|
|
22
27
|
const credentials = storeValuesToCustomRuntimeCredentials(values);
|
|
23
28
|
agentRuntimeConfigResolvedCount.add(1, {
|
|
@@ -37,7 +42,7 @@ export async function resolveRuntimeCredentials(params, options) {
|
|
|
37
42
|
});
|
|
38
43
|
return toResponse(params, credentials, providerConfig);
|
|
39
44
|
} catch (error) {
|
|
40
|
-
if (error
|
|
45
|
+
if (isInterModuleKnownError(secretsInterModuleContract.methods.getSecretsByNamespace, error)) {
|
|
41
46
|
agentRuntimeConfigResolvedCount.add(1, {
|
|
42
47
|
source: 'workspace',
|
|
43
48
|
outcome: 'decryption_failed'
|