@shipfox/api-agent 6.0.0 → 8.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.
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 50 files with swc (536.61ms)
2
+ Successfully compiled: 51 files with swc (494.7ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @shipfox/api-agent
2
2
 
3
+ ## 8.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - de559bb: Moves Agent validation policy behind a versioned inter-module catalog and injects it into Definitions normalization.
8
+ - Updated dependencies [de559bb]
9
+ - @shipfox/api-agent-dto@8.0.0
10
+
11
+ ## 7.1.0
12
+
13
+ ### Patch Changes
14
+
15
+ - ac42c96: Adds boundary-owned reporting for unexpected API runtime failures while preserving expected client and provider outcomes.
16
+ - Updated dependencies [ac42c96]
17
+ - Updated dependencies [6ce08c0]
18
+ - @shipfox/node-error-monitoring@0.2.0
19
+ - @shipfox/node-fastify@0.3.0
20
+ - @shipfox/node-module@0.5.0
21
+ - @shipfox/node-opentelemetry@0.6.0
22
+ - @shipfox/api-auth-context@7.1.0
23
+
3
24
  ## 6.0.0
4
25
 
5
26
  ### Minor Changes
@@ -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;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
+ {"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,5 +1,7 @@
1
1
  import { DEFAULT_AGENT_THINKING } from '@shipfox/api-agent-dto';
2
2
  import { assertEgressAllowed } from '@shipfox/node-egress-guard';
3
+ import { reportError } from '@shipfox/node-error-monitoring';
4
+ import { logger } from '@shipfox/node-opentelemetry';
3
5
  import { deleteModelProviderConfig, getModelProviderConfig, insertCustomModelProviderConfig, upsertModelProviderConfig } from '#db/index.js';
4
6
  import { agentSystemNamespace, customCredentialsToStoreValues, customCredentialToStoreKey, storeValuesToCustomRuntimeCredentials } from './credential-fingerprints.js';
5
7
  import { normalizeCustomProviderBaseUrl } from './custom-provider-url.js';
@@ -165,7 +167,21 @@ export async function updateCustomModelProviderConfig(params, options = {}) {
165
167
  namespace,
166
168
  existingSecrets,
167
169
  attemptedSecrets: newSecretCredentials
168
- }).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
+ });
169
185
  throw error;
170
186
  }
171
187
  await pruneStaleCustomHeaderSecrets(secrets, {
@@ -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 {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
+ {"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 +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;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
+ {"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,4 +1,6 @@
1
1
  import { DEFAULT_AGENT_THINKING, getModelProviderEntry, modelProviderCredentialKeysMatch } from '@shipfox/api-agent-dto';
2
+ import { reportError } from '@shipfox/node-error-monitoring';
3
+ import { logger } from '@shipfox/node-opentelemetry';
2
4
  import { deleteModelProviderConfig as deleteModelProviderConfigRow, getModelProviderConfig, updateModelProviderDefaultModel, upsertModelProviderConfig } from '#db/index.js';
3
5
  import { agentSystemNamespace, credentialsToStoreValues } from './credential-fingerprints.js';
4
6
  import { InvalidAgentModelError, InvalidCredentialFieldsError, ModelProviderConfigNotFoundError, UnsupportedModelProviderError } from './errors.js';
@@ -56,7 +58,21 @@ export async function testAndSaveModelProviderConfig(params, options = {}) {
56
58
  workspaceId: params.workspaceId,
57
59
  namespace,
58
60
  expectedKeys: Object.keys(values)
59
- }).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
+ });
60
76
  return config;
61
77
  }
62
78
  export async function updateModelProviderConfigDefaultModel(params) {
@@ -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 {\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":"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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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"}
@@ -0,0 +1,4 @@
1
+ import type { AgentValidationCatalog } from '@shipfox/api-agent-dto/inter-module';
2
+ /** Produces the versioned, JSON-safe policy snapshot consumed by Definitions. */
3
+ export declare function getAgentValidationCatalog(): AgentValidationCatalog;
4
+ //# sourceMappingURL=validation-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation-catalog.d.ts","sourceRoot":"","sources":["../../src/core/validation-catalog.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,qCAAqC,CAAC;AAGhF,iFAAiF;AACjF,wBAAgB,yBAAyB,IAAI,sBAAsB,CAgBlE"}
@@ -0,0 +1,23 @@
1
+ import { getModelProviderEntry, listEnabledHarnessTools, listHarnessDescriptors, MODEL_PROVIDER_IDS } from '@shipfox/api-agent-dto';
2
+ import { harnessToolDeploymentConfig } from '#config.js';
3
+ /** Produces the versioned, JSON-safe policy snapshot consumed by Definitions. */ export function getAgentValidationCatalog() {
4
+ return {
5
+ version: 1,
6
+ providers: MODEL_PROVIDER_IDS.map((id)=>({
7
+ id,
8
+ support_status: getModelProviderEntry(id)?.support_status ?? 'unsupported'
9
+ })),
10
+ harnesses: listHarnessDescriptors().map((harness)=>({
11
+ id: harness.id,
12
+ supported_provider_ids: [
13
+ ...harness.supportedProviderIds
14
+ ],
15
+ thinking_levels: [
16
+ ...harness.thinkingLevels
17
+ ],
18
+ effective_tools: listEnabledHarnessTools(harness.id, harnessToolDeploymentConfig).map((tool)=>tool.name)
19
+ }))
20
+ };
21
+ }
22
+
23
+ //# sourceMappingURL=validation-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/validation-catalog.ts"],"sourcesContent":["import {\n getModelProviderEntry,\n listEnabledHarnessTools,\n listHarnessDescriptors,\n MODEL_PROVIDER_IDS,\n} from '@shipfox/api-agent-dto';\nimport type {AgentValidationCatalog} from '@shipfox/api-agent-dto/inter-module';\nimport {harnessToolDeploymentConfig} from '#config.js';\n\n/** Produces the versioned, JSON-safe policy snapshot consumed by Definitions. */\nexport function getAgentValidationCatalog(): AgentValidationCatalog {\n return {\n version: 1,\n providers: MODEL_PROVIDER_IDS.map((id) => ({\n id,\n support_status: getModelProviderEntry(id)?.support_status ?? 'unsupported',\n })),\n harnesses: listHarnessDescriptors().map((harness) => ({\n id: harness.id,\n supported_provider_ids: [...harness.supportedProviderIds],\n thinking_levels: [...harness.thinkingLevels],\n effective_tools: listEnabledHarnessTools(harness.id, harnessToolDeploymentConfig).map(\n (tool) => tool.name,\n ),\n })),\n };\n}\n"],"names":["getModelProviderEntry","listEnabledHarnessTools","listHarnessDescriptors","MODEL_PROVIDER_IDS","harnessToolDeploymentConfig","getAgentValidationCatalog","version","providers","map","id","support_status","harnesses","harness","supported_provider_ids","supportedProviderIds","thinking_levels","thinkingLevels","effective_tools","tool","name"],"mappings":"AAAA,SACEA,qBAAqB,EACrBC,uBAAuB,EACvBC,sBAAsB,EACtBC,kBAAkB,QACb,yBAAyB;AAEhC,SAAQC,2BAA2B,QAAO,aAAa;AAEvD,+EAA+E,GAC/E,OAAO,SAASC;IACd,OAAO;QACLC,SAAS;QACTC,WAAWJ,mBAAmBK,GAAG,CAAC,CAACC,KAAQ,CAAA;gBACzCA;gBACAC,gBAAgBV,sBAAsBS,KAAKC,kBAAkB;YAC/D,CAAA;QACAC,WAAWT,yBAAyBM,GAAG,CAAC,CAACI,UAAa,CAAA;gBACpDH,IAAIG,QAAQH,EAAE;gBACdI,wBAAwB;uBAAID,QAAQE,oBAAoB;iBAAC;gBACzDC,iBAAiB;uBAAIH,QAAQI,cAAc;iBAAC;gBAC5CC,iBAAiBhB,wBAAwBW,QAAQH,EAAE,EAAEL,6BAA6BI,GAAG,CACnF,CAACU,OAASA,KAAKC,IAAI;YAEvB,CAAA;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"inter-module.d.ts","sourceRoot":"","sources":["../../src/presentation/inter-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,wBAAwB,EAAC,MAAM,qCAAqC,CAAC;AAE7E,OAAO,EAGL,KAAK,uBAAuB,EAE7B,MAAM,uBAAuB,CAAC;AAU/B,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,yBAAyB,CAAC;AAGhE,wBAAgB,kCAAkC,CAAC,MAAM,EAAE;IACzD,OAAO,EAAE,kBAAkB,CAAC;CAC7B,GAAG,uBAAuB,CAAC,OAAO,wBAAwB,CAAC,CAqB3D"}
1
+ {"version":3,"file":"inter-module.d.ts","sourceRoot":"","sources":["../../src/presentation/inter-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,wBAAwB,EAAC,MAAM,qCAAqC,CAAC;AAE7E,OAAO,EAGL,KAAK,uBAAuB,EAE7B,MAAM,uBAAuB,CAAC;AAU/B,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,yBAAyB,CAAC;AAIhE,wBAAgB,kCAAkC,CAAC,MAAM,EAAE;IACzD,OAAO,EAAE,kBAAkB,CAAC;CAC7B,GAAG,uBAAuB,CAAC,OAAO,wBAAwB,CAAC,CAsB3D"}
@@ -4,9 +4,11 @@ import { createInterModuleKnownError, defineInterModulePresentation, isInterModu
4
4
  import { InvalidAgentModelError, ModelProviderConfigNotFoundError, UnsupportedHarnessProviderError, UnsupportedHarnessThinkingError, UnsupportedModelProviderError } from '#core/errors.js';
5
5
  import { resolveAgentConfig } from '#core/resolve-agent-config.js';
6
6
  import { resolveRuntimeCredentials } from '#core/resolve-runtime-credentials.js';
7
+ import { getAgentValidationCatalog } from '#core/validation-catalog.js';
7
8
  import { createWorkspaceAgentDefaultsResolver } from '#core/workspace-agent-defaults-resolver.js';
8
9
  export function createAgentInterModulePresentation(params) {
9
10
  return defineInterModulePresentation(agentInterModuleContract, {
11
+ getValidationCatalog: ()=>getAgentValidationCatalog(),
10
12
  resolveAgentConfig: async ({ workspaceId, config })=>{
11
13
  try {
12
14
  const resolve = workspaceId === null ? resolveAgentConfig : await createWorkspaceAgentDefaultsResolver(workspaceId);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/presentation/inter-module.ts"],"sourcesContent":["import {agentInterModuleContract} from '@shipfox/api-agent-dto/inter-module';\nimport {secretsInterModuleContract} from '@shipfox/api-secrets-dto/inter-module';\nimport {\n createInterModuleKnownError,\n defineInterModulePresentation,\n type InterModulePresentation,\n isInterModuleKnownError,\n} from '@shipfox/inter-module';\nimport {\n InvalidAgentModelError,\n ModelProviderConfigNotFoundError,\n UnsupportedHarnessProviderError,\n UnsupportedHarnessThinkingError,\n UnsupportedModelProviderError,\n} from '#core/errors.js';\nimport {resolveAgentConfig} from '#core/resolve-agent-config.js';\nimport {resolveRuntimeCredentials} from '#core/resolve-runtime-credentials.js';\nimport type {AgentSecretsClient} from '#core/secrets-client.js';\nimport {createWorkspaceAgentDefaultsResolver} from '#core/workspace-agent-defaults-resolver.js';\n\nexport function createAgentInterModulePresentation(params: {\n secrets: AgentSecretsClient;\n}): InterModulePresentation<typeof agentInterModuleContract> {\n return defineInterModulePresentation(agentInterModuleContract, {\n resolveAgentConfig: async ({workspaceId, config}) => {\n try {\n const resolve =\n workspaceId === null\n ? resolveAgentConfig\n : await createWorkspaceAgentDefaultsResolver(workspaceId);\n return await resolve(config);\n } catch (error) {\n throw toResolveAgentConfigKnownError(error);\n }\n },\n resolveRuntimeCredentials: async (input) => {\n try {\n return await resolveRuntimeCredentials(input, {secrets: params.secrets});\n } catch (error) {\n throw toResolveRuntimeCredentialsKnownError(error);\n }\n },\n });\n}\n\nfunction toResolveAgentConfigKnownError(error: unknown): unknown {\n if (\n error instanceof InvalidAgentModelError ||\n error instanceof UnsupportedHarnessProviderError ||\n error instanceof UnsupportedHarnessThinkingError ||\n error instanceof UnsupportedModelProviderError\n ) {\n return createInterModuleKnownError(\n agentInterModuleContract.methods.resolveAgentConfig,\n 'agent-config-invalid',\n {},\n );\n }\n return error;\n}\n\nfunction toResolveRuntimeCredentialsKnownError(error: unknown): unknown {\n if (error instanceof ModelProviderConfigNotFoundError) {\n return createInterModuleKnownError(\n agentInterModuleContract.methods.resolveRuntimeCredentials,\n 'model-provider-not-configured',\n {},\n );\n }\n if (isInterModuleKnownError(secretsInterModuleContract.methods.getSecretsByNamespace, error)) {\n return createInterModuleKnownError(\n agentInterModuleContract.methods.resolveRuntimeCredentials,\n 'model-provider-credentials-invalid',\n {},\n );\n }\n return error;\n}\n"],"names":["agentInterModuleContract","secretsInterModuleContract","createInterModuleKnownError","defineInterModulePresentation","isInterModuleKnownError","InvalidAgentModelError","ModelProviderConfigNotFoundError","UnsupportedHarnessProviderError","UnsupportedHarnessThinkingError","UnsupportedModelProviderError","resolveAgentConfig","resolveRuntimeCredentials","createWorkspaceAgentDefaultsResolver","createAgentInterModulePresentation","params","workspaceId","config","resolve","error","toResolveAgentConfigKnownError","input","secrets","toResolveRuntimeCredentialsKnownError","methods","getSecretsByNamespace"],"mappings":"AAAA,SAAQA,wBAAwB,QAAO,sCAAsC;AAC7E,SAAQC,0BAA0B,QAAO,wCAAwC;AACjF,SACEC,2BAA2B,EAC3BC,6BAA6B,EAE7BC,uBAAuB,QAClB,wBAAwB;AAC/B,SACEC,sBAAsB,EACtBC,gCAAgC,EAChCC,+BAA+B,EAC/BC,+BAA+B,EAC/BC,6BAA6B,QACxB,kBAAkB;AACzB,SAAQC,kBAAkB,QAAO,gCAAgC;AACjE,SAAQC,yBAAyB,QAAO,uCAAuC;AAE/E,SAAQC,oCAAoC,QAAO,6CAA6C;AAEhG,OAAO,SAASC,mCAAmCC,MAElD;IACC,OAAOX,8BAA8BH,0BAA0B;QAC7DU,oBAAoB,OAAO,EAACK,WAAW,EAAEC,MAAM,EAAC;YAC9C,IAAI;gBACF,MAAMC,UACJF,gBAAgB,OACZL,qBACA,MAAME,qCAAqCG;gBACjD,OAAO,MAAME,QAAQD;YACvB,EAAE,OAAOE,OAAO;gBACd,MAAMC,+BAA+BD;YACvC;QACF;QACAP,2BAA2B,OAAOS;YAChC,IAAI;gBACF,OAAO,MAAMT,0BAA0BS,OAAO;oBAACC,SAASP,OAAOO,OAAO;gBAAA;YACxE,EAAE,OAAOH,OAAO;gBACd,MAAMI,sCAAsCJ;YAC9C;QACF;IACF;AACF;AAEA,SAASC,+BAA+BD,KAAc;IACpD,IACEA,iBAAiBb,0BACjBa,iBAAiBX,mCACjBW,iBAAiBV,mCACjBU,iBAAiBT,+BACjB;QACA,OAAOP,4BACLF,yBAAyBuB,OAAO,CAACb,kBAAkB,EACnD,wBACA,CAAC;IAEL;IACA,OAAOQ;AACT;AAEA,SAASI,sCAAsCJ,KAAc;IAC3D,IAAIA,iBAAiBZ,kCAAkC;QACrD,OAAOJ,4BACLF,yBAAyBuB,OAAO,CAACZ,yBAAyB,EAC1D,iCACA,CAAC;IAEL;IACA,IAAIP,wBAAwBH,2BAA2BsB,OAAO,CAACC,qBAAqB,EAAEN,QAAQ;QAC5F,OAAOhB,4BACLF,yBAAyBuB,OAAO,CAACZ,yBAAyB,EAC1D,sCACA,CAAC;IAEL;IACA,OAAOO;AACT"}
1
+ {"version":3,"sources":["../../src/presentation/inter-module.ts"],"sourcesContent":["import {agentInterModuleContract} from '@shipfox/api-agent-dto/inter-module';\nimport {secretsInterModuleContract} from '@shipfox/api-secrets-dto/inter-module';\nimport {\n createInterModuleKnownError,\n defineInterModulePresentation,\n type InterModulePresentation,\n isInterModuleKnownError,\n} from '@shipfox/inter-module';\nimport {\n InvalidAgentModelError,\n ModelProviderConfigNotFoundError,\n UnsupportedHarnessProviderError,\n UnsupportedHarnessThinkingError,\n UnsupportedModelProviderError,\n} from '#core/errors.js';\nimport {resolveAgentConfig} from '#core/resolve-agent-config.js';\nimport {resolveRuntimeCredentials} from '#core/resolve-runtime-credentials.js';\nimport type {AgentSecretsClient} from '#core/secrets-client.js';\nimport {getAgentValidationCatalog} from '#core/validation-catalog.js';\nimport {createWorkspaceAgentDefaultsResolver} from '#core/workspace-agent-defaults-resolver.js';\n\nexport function createAgentInterModulePresentation(params: {\n secrets: AgentSecretsClient;\n}): InterModulePresentation<typeof agentInterModuleContract> {\n return defineInterModulePresentation(agentInterModuleContract, {\n getValidationCatalog: () => getAgentValidationCatalog(),\n resolveAgentConfig: async ({workspaceId, config}) => {\n try {\n const resolve =\n workspaceId === null\n ? resolveAgentConfig\n : await createWorkspaceAgentDefaultsResolver(workspaceId);\n return await resolve(config);\n } catch (error) {\n throw toResolveAgentConfigKnownError(error);\n }\n },\n resolveRuntimeCredentials: async (input) => {\n try {\n return await resolveRuntimeCredentials(input, {secrets: params.secrets});\n } catch (error) {\n throw toResolveRuntimeCredentialsKnownError(error);\n }\n },\n });\n}\n\nfunction toResolveAgentConfigKnownError(error: unknown): unknown {\n if (\n error instanceof InvalidAgentModelError ||\n error instanceof UnsupportedHarnessProviderError ||\n error instanceof UnsupportedHarnessThinkingError ||\n error instanceof UnsupportedModelProviderError\n ) {\n return createInterModuleKnownError(\n agentInterModuleContract.methods.resolveAgentConfig,\n 'agent-config-invalid',\n {},\n );\n }\n return error;\n}\n\nfunction toResolveRuntimeCredentialsKnownError(error: unknown): unknown {\n if (error instanceof ModelProviderConfigNotFoundError) {\n return createInterModuleKnownError(\n agentInterModuleContract.methods.resolveRuntimeCredentials,\n 'model-provider-not-configured',\n {},\n );\n }\n if (isInterModuleKnownError(secretsInterModuleContract.methods.getSecretsByNamespace, error)) {\n return createInterModuleKnownError(\n agentInterModuleContract.methods.resolveRuntimeCredentials,\n 'model-provider-credentials-invalid',\n {},\n );\n }\n return error;\n}\n"],"names":["agentInterModuleContract","secretsInterModuleContract","createInterModuleKnownError","defineInterModulePresentation","isInterModuleKnownError","InvalidAgentModelError","ModelProviderConfigNotFoundError","UnsupportedHarnessProviderError","UnsupportedHarnessThinkingError","UnsupportedModelProviderError","resolveAgentConfig","resolveRuntimeCredentials","getAgentValidationCatalog","createWorkspaceAgentDefaultsResolver","createAgentInterModulePresentation","params","getValidationCatalog","workspaceId","config","resolve","error","toResolveAgentConfigKnownError","input","secrets","toResolveRuntimeCredentialsKnownError","methods","getSecretsByNamespace"],"mappings":"AAAA,SAAQA,wBAAwB,QAAO,sCAAsC;AAC7E,SAAQC,0BAA0B,QAAO,wCAAwC;AACjF,SACEC,2BAA2B,EAC3BC,6BAA6B,EAE7BC,uBAAuB,QAClB,wBAAwB;AAC/B,SACEC,sBAAsB,EACtBC,gCAAgC,EAChCC,+BAA+B,EAC/BC,+BAA+B,EAC/BC,6BAA6B,QACxB,kBAAkB;AACzB,SAAQC,kBAAkB,QAAO,gCAAgC;AACjE,SAAQC,yBAAyB,QAAO,uCAAuC;AAE/E,SAAQC,yBAAyB,QAAO,8BAA8B;AACtE,SAAQC,oCAAoC,QAAO,6CAA6C;AAEhG,OAAO,SAASC,mCAAmCC,MAElD;IACC,OAAOZ,8BAA8BH,0BAA0B;QAC7DgB,sBAAsB,IAAMJ;QAC5BF,oBAAoB,OAAO,EAACO,WAAW,EAAEC,MAAM,EAAC;YAC9C,IAAI;gBACF,MAAMC,UACJF,gBAAgB,OACZP,qBACA,MAAMG,qCAAqCI;gBACjD,OAAO,MAAME,QAAQD;YACvB,EAAE,OAAOE,OAAO;gBACd,MAAMC,+BAA+BD;YACvC;QACF;QACAT,2BAA2B,OAAOW;YAChC,IAAI;gBACF,OAAO,MAAMX,0BAA0BW,OAAO;oBAACC,SAASR,OAAOQ,OAAO;gBAAA;YACxE,EAAE,OAAOH,OAAO;gBACd,MAAMI,sCAAsCJ;YAC9C;QACF;IACF;AACF;AAEA,SAASC,+BAA+BD,KAAc;IACpD,IACEA,iBAAiBf,0BACjBe,iBAAiBb,mCACjBa,iBAAiBZ,mCACjBY,iBAAiBX,+BACjB;QACA,OAAOP,4BACLF,yBAAyByB,OAAO,CAACf,kBAAkB,EACnD,wBACA,CAAC;IAEL;IACA,OAAOU;AACT;AAEA,SAASI,sCAAsCJ,KAAc;IAC3D,IAAIA,iBAAiBd,kCAAkC;QACrD,OAAOJ,4BACLF,yBAAyByB,OAAO,CAACd,yBAAyB,EAC1D,iCACA,CAAC;IAEL;IACA,IAAIP,wBAAwBH,2BAA2BwB,OAAO,CAACC,qBAAqB,EAAEN,QAAQ;QAC5F,OAAOlB,4BACLF,yBAAyByB,OAAO,CAACd,yBAAyB,EAC1D,sCACA,CAAC;IAEL;IACA,OAAOS;AACT"}