@shipfox/api-agent 5.0.0 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +43 -0
  3. package/dist/core/custom-model-provider-config-service.d.ts +4 -0
  4. package/dist/core/custom-model-provider-config-service.d.ts.map +1 -1
  5. package/dist/core/custom-model-provider-config-service.js +36 -17
  6. package/dist/core/custom-model-provider-config-service.js.map +1 -1
  7. package/dist/core/model-provider-config-service.d.ts +4 -0
  8. package/dist/core/model-provider-config-service.d.ts.map +1 -1
  9. package/dist/core/model-provider-config-service.js +27 -9
  10. package/dist/core/model-provider-config-service.js.map +1 -1
  11. package/dist/core/resolve-runtime-credentials.d.ts +6 -2
  12. package/dist/core/resolve-runtime-credentials.d.ts.map +1 -1
  13. package/dist/core/resolve-runtime-credentials.js +10 -5
  14. package/dist/core/resolve-runtime-credentials.js.map +1 -1
  15. package/dist/core/secrets-client.d.ts +4 -0
  16. package/dist/core/secrets-client.d.ts.map +1 -0
  17. package/dist/core/secrets-client.js +6 -0
  18. package/dist/core/secrets-client.js.map +1 -0
  19. package/dist/index.d.ts +4 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +19 -13
  22. package/dist/index.js.map +1 -1
  23. package/dist/presentation/e2eRoutes/create-model-provider.d.ts +2 -1
  24. package/dist/presentation/e2eRoutes/create-model-provider.d.ts.map +1 -1
  25. package/dist/presentation/e2eRoutes/create-model-provider.js +46 -45
  26. package/dist/presentation/e2eRoutes/create-model-provider.js.map +1 -1
  27. package/dist/presentation/e2eRoutes/index.d.ts +2 -0
  28. package/dist/presentation/e2eRoutes/index.d.ts.map +1 -1
  29. package/dist/presentation/e2eRoutes/index.js +9 -6
  30. package/dist/presentation/e2eRoutes/index.js.map +1 -1
  31. package/dist/presentation/index.d.ts +1 -1
  32. package/dist/presentation/index.d.ts.map +1 -1
  33. package/dist/presentation/index.js +1 -1
  34. package/dist/presentation/index.js.map +1 -1
  35. package/dist/presentation/inter-module.d.ts +7 -0
  36. package/dist/presentation/inter-module.d.ts.map +1 -0
  37. package/dist/presentation/inter-module.js +45 -0
  38. package/dist/presentation/inter-module.js.map +1 -0
  39. package/dist/presentation/routes/create-custom-model-provider.d.ts +2 -1
  40. package/dist/presentation/routes/create-custom-model-provider.d.ts.map +1 -1
  41. package/dist/presentation/routes/create-custom-model-provider.js +39 -35
  42. package/dist/presentation/routes/create-custom-model-provider.js.map +1 -1
  43. package/dist/presentation/routes/delete-model-provider-config.d.ts +2 -1
  44. package/dist/presentation/routes/delete-model-provider-config.d.ts.map +1 -1
  45. package/dist/presentation/routes/delete-model-provider-config.js +33 -29
  46. package/dist/presentation/routes/delete-model-provider-config.js.map +1 -1
  47. package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.d.ts +2 -1
  48. package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.d.ts.map +1 -1
  49. package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.js +32 -28
  50. package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.js.map +1 -1
  51. package/dist/presentation/routes/errors.d.ts.map +1 -1
  52. package/dist/presentation/routes/errors.js +13 -12
  53. package/dist/presentation/routes/errors.js.map +1 -1
  54. package/dist/presentation/routes/index.d.ts +2 -0
  55. package/dist/presentation/routes/index.d.ts.map +1 -1
  56. package/dist/presentation/routes/index.js +32 -29
  57. package/dist/presentation/routes/index.js.map +1 -1
  58. package/dist/presentation/routes/update-custom-model-provider.d.ts +2 -1
  59. package/dist/presentation/routes/update-custom-model-provider.d.ts.map +1 -1
  60. package/dist/presentation/routes/update-custom-model-provider.js +41 -37
  61. package/dist/presentation/routes/update-custom-model-provider.js.map +1 -1
  62. package/dist/presentation/routes/upsert-model-provider-config.d.ts +2 -1
  63. package/dist/presentation/routes/upsert-model-provider-config.d.ts.map +1 -1
  64. package/dist/presentation/routes/upsert-model-provider-config.js +46 -42
  65. package/dist/presentation/routes/upsert-model-provider-config.js.map +1 -1
  66. package/dist/tsconfig.test.tsbuildinfo +1 -1
  67. package/package.json +12 -18
  68. package/src/core/custom-model-provider-config-service.ts +63 -35
  69. package/src/core/model-provider-config-service.test.ts +1 -3
  70. package/src/core/model-provider-config-service.ts +31 -16
  71. package/src/core/resolve-runtime-credentials.test.ts +3 -3
  72. package/src/core/resolve-runtime-credentials.ts +22 -8
  73. package/src/core/secrets-client.ts +13 -0
  74. package/src/index.ts +13 -8
  75. package/src/presentation/e2eRoutes/create-model-provider.ts +41 -39
  76. package/src/presentation/e2eRoutes/index.ts +6 -4
  77. package/src/presentation/index.ts +1 -1
  78. package/src/presentation/inter-module.ts +78 -0
  79. package/src/presentation/routes/create-custom-model-provider.ts +36 -30
  80. package/src/presentation/routes/delete-model-provider-config.ts +25 -22
  81. package/src/presentation/routes/discover-custom-model-provider-models-by-slug.ts +31 -25
  82. package/src/presentation/routes/errors.ts +11 -11
  83. package/src/presentation/routes/index.ts +32 -27
  84. package/src/presentation/routes/model-provider-config.test.ts +1 -1
  85. package/src/presentation/routes/update-custom-model-provider.ts +40 -34
  86. package/src/presentation/routes/upsert-model-provider-config.ts +43 -37
  87. package/test/fixtures/secrets-client.ts +80 -0
  88. package/test/globalSetup.ts +0 -9
  89. package/test/setup.ts +8 -0
  90. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 48 files with swc (101.45ms)
2
+ Successfully compiled: 50 files with swc (541.72ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # @shipfox/api-agent
2
2
 
3
+ ## 7.1.0
4
+
5
+ ### Patch Changes
6
+
7
+ - ac42c96: Adds boundary-owned reporting for unexpected API runtime failures while preserving expected client and provider outcomes.
8
+ - Updated dependencies [ac42c96]
9
+ - Updated dependencies [6ce08c0]
10
+ - @shipfox/node-error-monitoring@0.2.0
11
+ - @shipfox/node-fastify@0.3.0
12
+ - @shipfox/node-module@0.5.0
13
+ - @shipfox/node-opentelemetry@0.6.0
14
+ - @shipfox/api-auth-context@7.1.0
15
+
16
+ ## 6.0.0
17
+
18
+ ### Minor Changes
19
+
20
+ - a42b575: Exposes Secrets through its inter-module contract and migrates Agent, integrations, and Workflows consumers.
21
+
22
+ ### Patch Changes
23
+
24
+ - 0bb82a4: Adds the Agent and Integrations inter-module APIs, moving Workflows agent configuration, runtime credential resolution, and integration consumers behind producer-owned clients.
25
+ - f73da5d: Enforces bounded API context imports and routes inter-module consumers through producer contracts.
26
+ - Updated dependencies [0bb82a4]
27
+ - Updated dependencies [54ce48b]
28
+ - Updated dependencies [c0162b0]
29
+ - Updated dependencies [7ac43a4]
30
+ - Updated dependencies [a01e917]
31
+ - Updated dependencies [a42b575]
32
+ - Updated dependencies [8bdc149]
33
+ - Updated dependencies [3810996]
34
+ - Updated dependencies [b00ed29]
35
+ - Updated dependencies [8aa7cd3]
36
+ - Updated dependencies [81f9544]
37
+ - @shipfox/api-agent-dto@6.0.0
38
+ - @shipfox/node-module@0.4.0
39
+ - @shipfox/node-drizzle@0.3.2
40
+ - @shipfox/redact@0.2.3
41
+ - @shipfox/api-secrets-dto@6.0.0
42
+ - @shipfox/api-auth-context@6.0.0
43
+ - @shipfox/node-fastify@0.2.4
44
+ - @shipfox/inter-module@0.2.0
45
+
3
46
  ## 5.0.0
4
47
 
5
48
  ### 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;AAgBhC,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,qCAAqC,CAAC;AAQ7E,OAAO,EAEL,mCAAmC,EAEpC,MAAM,gCAAgC,CAAC;AAExC,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;CAChE;AASD,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,qCAAqC,EAC7C,OAAO,GAAE,uCAA4C,GACpD,OAAO,CAAC,mBAAmB,CAAC,CAyE9B;AAED,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,qCAAqC,EAC7C,OAAO,GAAE,uCAA4C,GACpD,OAAO,CAAC,mBAAmB,CAAC,CAoG9B;AAED,wBAAsB,yCAAyC,CAAC,MAAM,EAAE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,IAAI,EAAE,8CAA8C,CAAC;CACtD,GAAG,OAAO,CAAC,wCAAwC,CAAC,CA2BpD"}
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;AAiBhC,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,CA+G9B;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,16 @@
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';
3
+ import { reportError } from '@shipfox/node-error-monitoring';
4
+ import { logger } from '@shipfox/node-opentelemetry';
4
5
  import { deleteModelProviderConfig, getModelProviderConfig, insertCustomModelProviderConfig, upsertModelProviderConfig } from '#db/index.js';
5
6
  import { agentSystemNamespace, customCredentialsToStoreValues, customCredentialToStoreKey, storeValuesToCustomRuntimeCredentials } from './credential-fingerprints.js';
6
7
  import { normalizeCustomProviderBaseUrl } from './custom-provider-url.js';
7
8
  import { CustomModelProviderConfigNotFoundError, CustomModelProviderSlugCollisionError, CustomModelProviderStoredSecretBaseUrlChangeError, InvalidAgentModelError, InvalidCustomModelProviderHeaderKeepError } from './errors.js';
8
9
  import { egressPolicy, probeCustomModelProviderCredentials, runProviderProbe } from './model-provider-validation.js';
10
+ import { requireAgentSecretsClient } from './secrets-client.js';
9
11
  export async function createCustomModelProviderConfig(params, options = {}) {
10
12
  const probe = options.probe ?? probeCustomModelProviderCredentials;
13
+ const secrets = requireAgentSecretsClient(options.secrets);
11
14
  const existing = await getModelProviderConfig({
12
15
  workspaceId: params.workspaceId,
13
16
  providerId: params.body.slug
@@ -61,7 +64,7 @@ export async function createCustomModelProviderConfig(params, options = {}) {
61
64
  throw new CustomModelProviderSlugCollisionError(params.workspaceId, params.body.slug);
62
65
  }
63
66
  try {
64
- await setSecrets({
67
+ await secrets.setSecrets({
65
68
  workspaceId: params.workspaceId,
66
69
  namespace: agentSystemNamespace(params.body.slug),
67
70
  values: customCredentialsToStoreValues(secretCredentials)
@@ -72,7 +75,7 @@ export async function createCustomModelProviderConfig(params, options = {}) {
72
75
  workspaceId: params.workspaceId,
73
76
  providerId: params.body.slug
74
77
  });
75
- await deleteSecrets({
78
+ await secrets.deleteSecrets({
76
79
  workspaceId: params.workspaceId,
77
80
  namespace: agentSystemNamespace(params.body.slug)
78
81
  });
@@ -81,8 +84,9 @@ export async function createCustomModelProviderConfig(params, options = {}) {
81
84
  }
82
85
  export async function updateCustomModelProviderConfig(params, options = {}) {
83
86
  const probe = options.probe ?? probeCustomModelProviderCredentials;
87
+ const secrets = requireAgentSecretsClient(options.secrets);
84
88
  const existing = await getExistingCustomConfig(params.workspaceId, params.providerId);
85
- const existingSecrets = await getCustomProviderSecrets({
89
+ const existingSecrets = await getCustomProviderSecrets(secrets, {
86
90
  workspaceId: params.workspaceId,
87
91
  providerId: params.providerId
88
92
  });
@@ -136,7 +140,7 @@ export async function updateCustomModelProviderConfig(params, options = {}) {
136
140
  signal: params.signal
137
141
  });
138
142
  const namespace = agentSystemNamespace(params.providerId);
139
- await setSecrets({
143
+ await secrets.setSecrets({
140
144
  workspaceId: params.workspaceId,
141
145
  namespace,
142
146
  values: customCredentialsToStoreValues(newSecretCredentials)
@@ -158,15 +162,29 @@ export async function updateCustomModelProviderConfig(params, options = {}) {
158
162
  defaultThinking: existing.defaultThinking
159
163
  });
160
164
  } catch (error) {
161
- await rollbackCustomProviderSecretUpdate({
165
+ await rollbackCustomProviderSecretUpdate(secrets, {
162
166
  workspaceId: params.workspaceId,
163
167
  namespace,
164
168
  existingSecrets,
165
169
  attemptedSecrets: newSecretCredentials
166
- }).catch(()=>undefined);
170
+ }).catch((rollbackError)=>{
171
+ logger().error({
172
+ err: rollbackError,
173
+ workspaceId: params.workspaceId,
174
+ providerId: params.providerId
175
+ }, 'Failed to roll back custom model provider secrets');
176
+ reportError(rollbackError, {
177
+ boundary: 'agent.cleanup',
178
+ operation: 'rollback-secret-update',
179
+ extra: {
180
+ workspaceId: params.workspaceId,
181
+ providerId: params.providerId
182
+ }
183
+ });
184
+ });
167
185
  throw error;
168
186
  }
169
- await pruneStaleCustomHeaderSecrets({
187
+ await pruneStaleCustomHeaderSecrets(secrets, {
170
188
  workspaceId: params.workspaceId,
171
189
  providerId: params.providerId,
172
190
  existingSecrets,
@@ -175,9 +193,10 @@ export async function updateCustomModelProviderConfig(params, options = {}) {
175
193
  });
176
194
  return updated;
177
195
  }
178
- export async function resolveCustomModelProviderDiscoveryParams(params) {
196
+ export async function resolveCustomModelProviderDiscoveryParams(params, options = {}) {
197
+ const secrets = requireAgentSecretsClient(options.secrets);
179
198
  const existing = await getExistingCustomConfig(params.workspaceId, params.providerId);
180
- const existingSecrets = await getCustomProviderSecrets({
199
+ const existingSecrets = await getCustomProviderSecrets(secrets, {
181
200
  workspaceId: params.workspaceId,
182
201
  providerId: params.providerId
183
202
  });
@@ -325,8 +344,8 @@ function selectProbeModel(models, defaultModel) {
325
344
  if (!model) throw new Error('Custom model provider must include at least one model.');
326
345
  return model;
327
346
  }
328
- async function getCustomProviderSecrets(params) {
329
- const values = await getSecretsByNamespace({
347
+ async function getCustomProviderSecrets(secrets, params) {
348
+ const { values } = await secrets.getSecretsByNamespace({
330
349
  workspaceId: params.workspaceId,
331
350
  namespace: agentSystemNamespace(params.providerId)
332
351
  });
@@ -345,7 +364,7 @@ function assertStoredSecretsNotReusedAfterBaseUrlChange(params) {
345
364
  function normalizedUrl(value) {
346
365
  return normalizeCustomProviderBaseUrl(value);
347
366
  }
348
- async function rollbackCustomProviderSecretUpdate(params) {
367
+ async function rollbackCustomProviderSecretUpdate(secrets, params) {
349
368
  const attemptedKeys = Object.keys(params.attemptedSecrets);
350
369
  if (attemptedKeys.length === 0) return;
351
370
  const secretsToRestore = Object.fromEntries(attemptedKeys.flatMap((key)=>{
@@ -358,7 +377,7 @@ async function rollbackCustomProviderSecretUpdate(params) {
358
377
  ];
359
378
  }));
360
379
  if (Object.keys(secretsToRestore).length > 0) {
361
- await setSecrets({
380
+ await secrets.setSecrets({
362
381
  workspaceId: params.workspaceId,
363
382
  namespace: params.namespace,
364
383
  values: customCredentialsToStoreValues(secretsToRestore)
@@ -366,18 +385,18 @@ async function rollbackCustomProviderSecretUpdate(params) {
366
385
  }
367
386
  const newKeys = attemptedKeys.filter((key)=>params.existingSecrets[key] === undefined);
368
387
  if (newKeys.length === 0) return;
369
- await deleteSecrets({
388
+ await secrets.deleteSecrets({
370
389
  workspaceId: params.workspaceId,
371
390
  namespace: params.namespace,
372
391
  keys: newKeys.map(customCredentialToStoreKey)
373
392
  });
374
393
  }
375
- async function pruneStaleCustomHeaderSecrets(params) {
394
+ async function pruneStaleCustomHeaderSecrets(secrets, params) {
376
395
  if (!params.replaceHeaders) return;
377
396
  const nextKeys = new Set(Object.keys(params.newSecrets));
378
397
  const staleKeys = Object.keys(params.existingSecrets).filter((key)=>key.startsWith('header:') && !nextKeys.has(key));
379
398
  if (staleKeys.length === 0) return;
380
- await deleteSecrets({
399
+ await secrets.deleteSecrets({
381
400
  workspaceId: params.workspaceId,
382
401
  namespace: agentSystemNamespace(params.providerId),
383
402
  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 {reportError} from '@shipfox/node-error-monitoring';\nimport {logger} from '@shipfox/node-opentelemetry';\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((rollbackError) => {\n logger().error(\n {err: rollbackError, workspaceId: params.workspaceId, providerId: params.providerId},\n 'Failed to roll back custom model provider secrets',\n );\n reportError(rollbackError, {\n boundary: 'agent.cleanup',\n operation: 'rollback-secret-update',\n extra: {workspaceId: params.workspaceId, providerId: params.providerId},\n });\n });\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","reportError","logger","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","rollbackError","err","boundary","operation","extra","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;AAShC,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,qCAAqC,CAAC;AAQ7E,OAAO,EAAC,6BAA6B,EAAmB,MAAM,gCAAgC,CAAC;AAE/F,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,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,CA2D9B;AAED,wBAAsB,qCAAqC,CACzD,MAAM,EAAE,2CAA2C,GAClD,OAAO,CAAC,mBAAmB,CAAC,CAwC9B;AAED,wBAAsB,yBAAyB,CAAC,MAAM,EAAE;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,gBAAgB,CAAC;CAC9B,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnB"}
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;AAUhC,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,CAuE9B;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,15 @@
1
1
  import { DEFAULT_AGENT_THINKING, getModelProviderEntry, modelProviderCredentialKeysMatch } from '@shipfox/api-agent-dto';
2
- import { deleteSecrets, getSecretsByNamespace, setSecrets } from '@shipfox/api-secrets';
2
+ import { reportError } from '@shipfox/node-error-monitoring';
3
+ import { logger } from '@shipfox/node-opentelemetry';
3
4
  import { deleteModelProviderConfig as deleteModelProviderConfigRow, getModelProviderConfig, updateModelProviderDefaultModel, upsertModelProviderConfig } from '#db/index.js';
4
5
  import { agentSystemNamespace, credentialsToStoreValues } from './credential-fingerprints.js';
5
6
  import { InvalidAgentModelError, InvalidCredentialFieldsError, ModelProviderConfigNotFoundError, UnsupportedModelProviderError } from './errors.js';
6
7
  import { buildModelProviderCatalog } from './model-provider-catalog.js';
7
8
  import { probeModelProviderCredentials, runProviderProbe } from './model-provider-validation.js';
9
+ import { requireAgentSecretsClient } from './secrets-client.js';
8
10
  export async function testAndSaveModelProviderConfig(params, options = {}) {
9
11
  const probe = options.probe ?? probeModelProviderCredentials;
12
+ const secrets = requireAgentSecretsClient(options.secrets);
10
13
  const entry = getModelProviderEntry(params.providerId);
11
14
  if (entry === undefined || entry.support_status !== 'supported') {
12
15
  throw new UnsupportedModelProviderError(params.providerId);
@@ -35,10 +38,10 @@ export async function testAndSaveModelProviderConfig(params, options = {}) {
35
38
  secrets: Object.values(params.credentials),
36
39
  signal: params.signal
37
40
  });
38
- const pruneStaleSecrets = options.pruneStaleSecrets ?? pruneStaleProviderCredentialSecrets;
41
+ const pruneStaleSecrets = options.pruneStaleSecrets ?? ((input)=>pruneStaleProviderCredentialSecrets(secrets, input));
39
42
  const namespace = agentSystemNamespace(params.providerId);
40
43
  const values = credentialsToStoreValues(params.providerId, params.credentials);
41
- await setSecrets({
44
+ await secrets.setSecrets({
42
45
  workspaceId: params.workspaceId,
43
46
  namespace,
44
47
  values,
@@ -55,7 +58,21 @@ export async function testAndSaveModelProviderConfig(params, options = {}) {
55
58
  workspaceId: params.workspaceId,
56
59
  namespace,
57
60
  expectedKeys: Object.keys(values)
58
- }).catch(()=>undefined);
61
+ }).catch((error)=>{
62
+ logger().error({
63
+ err: error,
64
+ workspaceId: params.workspaceId,
65
+ providerId: params.providerId
66
+ }, 'Failed to prune stale model provider secrets');
67
+ reportError(error, {
68
+ boundary: 'agent.cleanup',
69
+ operation: 'prune-stale-secrets',
70
+ extra: {
71
+ workspaceId: params.workspaceId,
72
+ providerId: params.providerId
73
+ }
74
+ });
75
+ });
59
76
  return config;
60
77
  }
61
78
  export async function updateModelProviderConfigDefaultModel(params) {
@@ -93,9 +110,10 @@ export async function updateModelProviderConfigDefaultModel(params) {
93
110
  if (!config) throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);
94
111
  return config;
95
112
  }
96
- export async function deleteModelProviderConfig(params) {
113
+ export async function deleteModelProviderConfig(params, options = {}) {
114
+ const secrets = requireAgentSecretsClient(options.secrets);
97
115
  const deleted = await deleteModelProviderConfigRow(params);
98
- await deleteSecrets({
116
+ await secrets.deleteSecrets({
99
117
  workspaceId: params.workspaceId,
100
118
  namespace: agentSystemNamespace(params.providerId)
101
119
  });
@@ -115,15 +133,15 @@ function resolveDefaultModel(providerId, requestedModel) {
115
133
  storedModel: requestedModel ?? null
116
134
  };
117
135
  }
118
- async function pruneStaleProviderCredentialSecrets(params) {
119
- const stored = await getSecretsByNamespace({
136
+ async function pruneStaleProviderCredentialSecrets(secrets, params) {
137
+ const { values: stored } = await secrets.getSecretsByNamespace({
120
138
  workspaceId: params.workspaceId,
121
139
  namespace: params.namespace
122
140
  });
123
141
  const expected = new Set(params.expectedKeys);
124
142
  const staleKeys = Object.keys(stored).filter((key)=>!expected.has(key));
125
143
  if (staleKeys.length === 0) return;
126
- await deleteSecrets({
144
+ await secrets.deleteSecrets({
127
145
  workspaceId: params.workspaceId,
128
146
  namespace: params.namespace,
129
147
  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":"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"}
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 {reportError} from '@shipfox/node-error-monitoring';\nimport {logger} from '@shipfox/node-opentelemetry';\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((error) => {\n logger().error(\n {err: error, workspaceId: params.workspaceId, providerId: params.providerId},\n 'Failed to prune stale model provider secrets',\n );\n reportError(error, {\n boundary: 'agent.cleanup',\n operation: 'prune-stale-secrets',\n extra: {workspaceId: params.workspaceId, providerId: params.providerId},\n });\n });\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","reportError","logger","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","error","err","boundary","operation","extra","updateModelProviderConfigDefaultModel","kind","models","some","id","deleted","deleteSecrets","requestedModel","catalogEntry","find","candidate","stored","getSecretsByNamespace","expected","Set","staleKeys","filter","key","has","length"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { type AgentRuntimeCredentialsResponseDto, type AgentThinking, type Harness, type ModelProviderRef, type SupportedModelProviderId } from '@shipfox/api-agent-dto';
2
- import { getSecretsByNamespace } from '@shipfox/api-secrets';
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
- getCredentialBag?: typeof getSecretsByNamespace | undefined;
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;AAChC,OAAO,EAAC,qBAAqB,EAAwB,MAAM,sBAAsB,CAAC;AAYlF,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,gBAAgB,CAAC,EAAE,OAAO,qBAAqB,GAAG,SAAS,CAAC;CAC7D;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,+BAA+B,EACvC,OAAO,CAAC,EAAE,gCAAgC,GACzC,OAAO,CAAC,kCAAkC,CAAC,CAiD7C;AAED,wBAAgB,0CAA0C,CACxD,UAAU,EAAE,gBAAgB,GAC3B,SAAS,GAAG,SAAS,CAQvB"}
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"}