@shipfox/api-agent 8.0.0 → 9.0.1

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 (67) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +47 -0
  3. package/dist/config.js +2 -1
  4. package/dist/config.js.map +1 -1
  5. package/dist/core/credential-fingerprints.js +1 -1
  6. package/dist/core/credential-fingerprints.js.map +1 -1
  7. package/dist/core/index.d.ts +1 -0
  8. package/dist/core/index.d.ts.map +1 -1
  9. package/dist/core/index.js +1 -0
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/core/model-provider-config-service.d.ts.map +1 -1
  12. package/dist/core/model-provider-config-service.js +2 -1
  13. package/dist/core/model-provider-config-service.js.map +1 -1
  14. package/dist/core/model-provider-policy.d.ts +7 -0
  15. package/dist/core/model-provider-policy.d.ts.map +1 -0
  16. package/dist/core/model-provider-policy.js +23 -0
  17. package/dist/core/model-provider-policy.js.map +1 -0
  18. package/dist/core/model-provider-validation.d.ts +1 -1
  19. package/dist/core/model-provider-validation.d.ts.map +1 -1
  20. package/dist/core/model-provider-validation.js +1 -1
  21. package/dist/core/model-provider-validation.js.map +1 -1
  22. package/dist/core/resolve-agent-config.d.ts.map +1 -1
  23. package/dist/core/resolve-agent-config.js +2 -1
  24. package/dist/core/resolve-agent-config.js.map +1 -1
  25. package/dist/core/resolve-runtime-credentials.d.ts +1 -1
  26. package/dist/core/resolve-runtime-credentials.d.ts.map +1 -1
  27. package/dist/core/resolve-runtime-credentials.js +1 -1
  28. package/dist/core/resolve-runtime-credentials.js.map +1 -1
  29. package/dist/core/validation-catalog.d.ts.map +1 -1
  30. package/dist/core/validation-catalog.js +2 -1
  31. package/dist/core/validation-catalog.js.map +1 -1
  32. package/dist/db/schema/model-provider-configs.d.ts.map +1 -1
  33. package/dist/db/schema/model-provider-configs.js +5 -4
  34. package/dist/db/schema/model-provider-configs.js.map +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +3 -2
  38. package/dist/index.js.map +1 -1
  39. package/dist/presentation/e2eRoutes/create-model-provider.d.ts.map +1 -1
  40. package/dist/presentation/e2eRoutes/create-model-provider.js +2 -1
  41. package/dist/presentation/e2eRoutes/create-model-provider.js.map +1 -1
  42. package/dist/presentation/routes/errors.js +1 -1
  43. package/dist/presentation/routes/errors.js.map +1 -1
  44. package/dist/presentation/routes/set-default-model-provider.js +2 -1
  45. package/dist/presentation/routes/set-default-model-provider.js.map +1 -1
  46. package/dist/tsconfig.test.tsbuildinfo +1 -1
  47. package/drizzle/0000_daffy_leopardon.sql +5 -5
  48. package/drizzle/meta/0000_snapshot.json +10 -10
  49. package/drizzle/meta/0001_snapshot.json +10 -10
  50. package/package.json +17 -18
  51. package/src/config.ts +1 -1
  52. package/src/core/catalog-registry.test.ts +8 -1
  53. package/src/core/credential-fingerprints.ts +1 -1
  54. package/src/core/index.ts +7 -0
  55. package/src/core/model-provider-config-service.ts +1 -2
  56. package/src/core/model-provider-policy.ts +35 -0
  57. package/src/core/model-provider-validation.ts +6 -6
  58. package/src/core/resolve-agent-config.ts +1 -1
  59. package/src/core/resolve-runtime-credentials.ts +7 -8
  60. package/src/core/validation-catalog.ts +1 -1
  61. package/src/db/schema/model-provider-configs.ts +4 -4
  62. package/src/index.ts +6 -1
  63. package/src/presentation/e2eRoutes/create-model-provider.ts +2 -1
  64. package/src/presentation/routes/errors.ts +1 -1
  65. package/src/presentation/routes/set-default-model-provider.ts +1 -1
  66. package/test/globalSetup.ts +1 -1
  67. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 51 files with swc (494.7ms)
2
+ Successfully compiled: 52 files with swc (414.1ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # @shipfox/api-agent
2
2
 
3
+ ## 9.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 067d309: Prefixes Agent database objects in the migration baseline.
8
+ - 475ce59: Republishes all public packages after restoring release authorization.
9
+ - Updated dependencies [8436596]
10
+ - Updated dependencies [475ce59]
11
+ - Updated dependencies [154e03f]
12
+ - @shipfox/api-secrets-dto@9.0.1
13
+ - @shipfox/redact@0.2.4
14
+ - @shipfox/api-agent-dto@9.0.1
15
+ - @shipfox/api-auth-context@9.0.1
16
+ - @shipfox/config@1.2.3
17
+ - @shipfox/inter-module@0.2.1
18
+ - @shipfox/node-drizzle@0.3.3
19
+ - @shipfox/node-egress-guard@0.1.2
20
+ - @shipfox/node-error-monitoring@0.2.1
21
+ - @shipfox/node-fastify@0.3.1
22
+ - @shipfox/node-module@1.0.0
23
+ - @shipfox/node-opentelemetry@0.6.1
24
+ - @shipfox/node-postgres@0.4.3
25
+
26
+ ## 9.0.0
27
+
28
+ ### Minor Changes
29
+
30
+ - 46aa52f: Closes remaining API package-boundary exceptions and moves model-provider policy behind the Agent implementation boundary.
31
+
32
+ ### Patch Changes
33
+
34
+ - Updated dependencies [46aa52f]
35
+ - Updated dependencies [02974d6]
36
+ - @shipfox/api-agent-dto@9.0.0
37
+ - @shipfox/api-secrets-dto@9.0.0
38
+ - @shipfox/api-auth-context@9.0.0
39
+ - @shipfox/config@1.2.2
40
+ - @shipfox/inter-module@0.2.0
41
+ - @shipfox/redact@0.2.3
42
+ - @shipfox/node-drizzle@0.3.2
43
+ - @shipfox/node-egress-guard@0.1.1
44
+ - @shipfox/node-error-monitoring@0.2.0
45
+ - @shipfox/node-fastify@0.3.0
46
+ - @shipfox/node-module@0.5.0
47
+ - @shipfox/node-opentelemetry@0.6.0
48
+ - @shipfox/node-postgres@0.4.2
49
+
3
50
  ## 8.0.0
4
51
 
5
52
  ### Patch Changes
package/dist/config.js CHANGED
@@ -1,5 +1,6 @@
1
- import { agentThinkingSchema, buildHarnessToolDeploymentConfig, getModelProviderEntry, SUPPORTED_MODEL_PROVIDER_IDS } from '@shipfox/api-agent-dto';
1
+ import { agentThinkingSchema, buildHarnessToolDeploymentConfig, SUPPORTED_MODEL_PROVIDER_IDS } from '@shipfox/api-agent-dto';
2
2
  import { bool, createConfig, num, str } from '@shipfox/config';
3
+ import { getModelProviderEntry } from '#core/model-provider-policy.js';
3
4
  const AGENT_THINKING_CHOICES = agentThinkingSchema.options;
4
5
  export const config = createConfig({
5
6
  AGENT_DEFAULT_PROVIDER: str({
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts"],"sourcesContent":["import {\n agentThinkingSchema,\n buildHarnessToolDeploymentConfig,\n getModelProviderEntry,\n SUPPORTED_MODEL_PROVIDER_IDS,\n type SupportedModelProviderId,\n} from '@shipfox/api-agent-dto';\nimport {bool, createConfig, num, str} from '@shipfox/config';\n\nconst AGENT_THINKING_CHOICES = agentThinkingSchema.options;\n\nexport const config = createConfig({\n AGENT_DEFAULT_PROVIDER: str({\n desc: 'Instance-wide default model provider ID used when a workflow and workspace do not choose one. Optional. Use one of the supported model provider IDs from the model provider catalog.',\n choices: SUPPORTED_MODEL_PROVIDER_IDS,\n default: undefined,\n }),\n AGENT_DEFAULT_PROVIDER_MODEL: str({\n desc: 'Instance-wide default model ID used when the resolved provider matches AGENT_DEFAULT_PROVIDER and no workflow or workspace model is set. Optional. Use a model ID supported by that provider.',\n default: undefined,\n }),\n AGENT_DEFAULT_PROVIDER_THINKING: str({\n desc: 'Instance-wide default thinking effort used when the resolved provider matches AGENT_DEFAULT_PROVIDER and no workflow or workspace thinking effort is set. Optional. Accepted values are off, minimal, low, medium, high, and xhigh.',\n choices: AGENT_THINKING_CHOICES,\n default: undefined,\n }),\n AGENT_DEFAULT_PROVIDER_API_KEY: str({\n desc: 'API key for the instance default provider. Optional. Must belong to AGENT_DEFAULT_PROVIDER. If you change the default provider, change this key too. Instance defaults support API-key-only providers.',\n default: undefined,\n }),\n AGENT_PROVIDER_VALIDATION_TIMEOUT_MS: num({\n desc: 'Maximum time in milliseconds to wait for the live provider test request when saving credentials.',\n default: 10000,\n }),\n AGENT_CUSTOM_PROVIDER_ALLOW_PRIVATE_NETWORKS: bool({\n desc: 'Allows custom model providers to use private, loopback, link-local, metadata, and .internal network targets. Keep this true for local development and self-hosted private networks. Set it to false on cloud instances.',\n default: true,\n }),\n AGENT_CUSTOM_PROVIDER_HOST_DENYLIST: str({\n desc: 'Comma-separated hosts and IP ranges that custom model providers may not call. Accepts exact hosts, suffix patterns such as .internal.example or *.internal.example, IP literals, and CIDR blocks such as 10.0.0.0/8.',\n default: '',\n }),\n AGENT_PI_ENABLED_TOOL_PACKAGES: str({\n desc: 'Comma-separated optional Pi tool packages enabled for this deployment. Defaults to pi-web-access so Pi web access is available. Set it to an empty value to enable only Pi built-in tools. Accepted values: pi-web-access.',\n default: 'pi-web-access',\n }),\n AGENT_PI_WEB_SEARCH_ENABLED: bool({\n desc: 'Enables Pi web search tools when pi-web-access is enabled. Set it to false to disable web_search and get_search_content while keeping fetch_content available.',\n default: true,\n }),\n});\n\nassertInstanceDefaultModelProviderApiKeyConfig();\n\nexport const harnessToolDeploymentConfig = buildHarnessToolDeploymentConfig({\n piEnabledToolPackages: config.AGENT_PI_ENABLED_TOOL_PACKAGES,\n piWebSearchEnabled: config.AGENT_PI_WEB_SEARCH_ENABLED,\n});\n\nfunction assertInstanceDefaultModelProviderApiKeyConfig(): void {\n if (!config.AGENT_DEFAULT_PROVIDER_API_KEY) return;\n if (!config.AGENT_DEFAULT_PROVIDER) {\n throw new Error('AGENT_DEFAULT_PROVIDER_API_KEY requires AGENT_DEFAULT_PROVIDER to be set.');\n }\n\n const credentialFields =\n getModelProviderEntry(config.AGENT_DEFAULT_PROVIDER as SupportedModelProviderId)\n ?.credential_fields ?? [];\n const field = credentialFields[0];\n if (credentialFields.length === 1 && field?.key === 'api_key' && field.secret) return;\n\n throw new Error(\n 'AGENT_DEFAULT_PROVIDER_API_KEY requires AGENT_DEFAULT_PROVIDER to use exactly one secret api_key credential field.',\n );\n}\n"],"names":["agentThinkingSchema","buildHarnessToolDeploymentConfig","getModelProviderEntry","SUPPORTED_MODEL_PROVIDER_IDS","bool","createConfig","num","str","AGENT_THINKING_CHOICES","options","config","AGENT_DEFAULT_PROVIDER","desc","choices","default","undefined","AGENT_DEFAULT_PROVIDER_MODEL","AGENT_DEFAULT_PROVIDER_THINKING","AGENT_DEFAULT_PROVIDER_API_KEY","AGENT_PROVIDER_VALIDATION_TIMEOUT_MS","AGENT_CUSTOM_PROVIDER_ALLOW_PRIVATE_NETWORKS","AGENT_CUSTOM_PROVIDER_HOST_DENYLIST","AGENT_PI_ENABLED_TOOL_PACKAGES","AGENT_PI_WEB_SEARCH_ENABLED","assertInstanceDefaultModelProviderApiKeyConfig","harnessToolDeploymentConfig","piEnabledToolPackages","piWebSearchEnabled","Error","credentialFields","credential_fields","field","length","key","secret"],"mappings":"AAAA,SACEA,mBAAmB,EACnBC,gCAAgC,EAChCC,qBAAqB,EACrBC,4BAA4B,QAEvB,yBAAyB;AAChC,SAAQC,IAAI,EAAEC,YAAY,EAAEC,GAAG,EAAEC,GAAG,QAAO,kBAAkB;AAE7D,MAAMC,yBAAyBR,oBAAoBS,OAAO;AAE1D,OAAO,MAAMC,SAASL,aAAa;IACjCM,wBAAwBJ,IAAI;QAC1BK,MAAM;QACNC,SAASV;QACTW,SAASC;IACX;IACAC,8BAA8BT,IAAI;QAChCK,MAAM;QACNE,SAASC;IACX;IACAE,iCAAiCV,IAAI;QACnCK,MAAM;QACNC,SAASL;QACTM,SAASC;IACX;IACAG,gCAAgCX,IAAI;QAClCK,MAAM;QACNE,SAASC;IACX;IACAI,sCAAsCb,IAAI;QACxCM,MAAM;QACNE,SAAS;IACX;IACAM,8CAA8ChB,KAAK;QACjDQ,MAAM;QACNE,SAAS;IACX;IACAO,qCAAqCd,IAAI;QACvCK,MAAM;QACNE,SAAS;IACX;IACAQ,gCAAgCf,IAAI;QAClCK,MAAM;QACNE,SAAS;IACX;IACAS,6BAA6BnB,KAAK;QAChCQ,MAAM;QACNE,SAAS;IACX;AACF,GAAG;AAEHU;AAEA,OAAO,MAAMC,8BAA8BxB,iCAAiC;IAC1EyB,uBAAuBhB,OAAOY,8BAA8B;IAC5DK,oBAAoBjB,OAAOa,2BAA2B;AACxD,GAAG;AAEH,SAASC;IACP,IAAI,CAACd,OAAOQ,8BAA8B,EAAE;IAC5C,IAAI,CAACR,OAAOC,sBAAsB,EAAE;QAClC,MAAM,IAAIiB,MAAM;IAClB;IAEA,MAAMC,mBACJ3B,sBAAsBQ,OAAOC,sBAAsB,GAC/CmB,qBAAqB,EAAE;IAC7B,MAAMC,QAAQF,gBAAgB,CAAC,EAAE;IACjC,IAAIA,iBAAiBG,MAAM,KAAK,KAAKD,OAAOE,QAAQ,aAAaF,MAAMG,MAAM,EAAE;IAE/E,MAAM,IAAIN,MACR;AAEJ"}
1
+ {"version":3,"sources":["../src/config.ts"],"sourcesContent":["import {\n agentThinkingSchema,\n buildHarnessToolDeploymentConfig,\n SUPPORTED_MODEL_PROVIDER_IDS,\n type SupportedModelProviderId,\n} from '@shipfox/api-agent-dto';\nimport {bool, createConfig, num, str} from '@shipfox/config';\nimport {getModelProviderEntry} from '#core/model-provider-policy.js';\n\nconst AGENT_THINKING_CHOICES = agentThinkingSchema.options;\n\nexport const config = createConfig({\n AGENT_DEFAULT_PROVIDER: str({\n desc: 'Instance-wide default model provider ID used when a workflow and workspace do not choose one. Optional. Use one of the supported model provider IDs from the model provider catalog.',\n choices: SUPPORTED_MODEL_PROVIDER_IDS,\n default: undefined,\n }),\n AGENT_DEFAULT_PROVIDER_MODEL: str({\n desc: 'Instance-wide default model ID used when the resolved provider matches AGENT_DEFAULT_PROVIDER and no workflow or workspace model is set. Optional. Use a model ID supported by that provider.',\n default: undefined,\n }),\n AGENT_DEFAULT_PROVIDER_THINKING: str({\n desc: 'Instance-wide default thinking effort used when the resolved provider matches AGENT_DEFAULT_PROVIDER and no workflow or workspace thinking effort is set. Optional. Accepted values are off, minimal, low, medium, high, and xhigh.',\n choices: AGENT_THINKING_CHOICES,\n default: undefined,\n }),\n AGENT_DEFAULT_PROVIDER_API_KEY: str({\n desc: 'API key for the instance default provider. Optional. Must belong to AGENT_DEFAULT_PROVIDER. If you change the default provider, change this key too. Instance defaults support API-key-only providers.',\n default: undefined,\n }),\n AGENT_PROVIDER_VALIDATION_TIMEOUT_MS: num({\n desc: 'Maximum time in milliseconds to wait for the live provider test request when saving credentials.',\n default: 10000,\n }),\n AGENT_CUSTOM_PROVIDER_ALLOW_PRIVATE_NETWORKS: bool({\n desc: 'Allows custom model providers to use private, loopback, link-local, metadata, and .internal network targets. Keep this true for local development and self-hosted private networks. Set it to false on cloud instances.',\n default: true,\n }),\n AGENT_CUSTOM_PROVIDER_HOST_DENYLIST: str({\n desc: 'Comma-separated hosts and IP ranges that custom model providers may not call. Accepts exact hosts, suffix patterns such as .internal.example or *.internal.example, IP literals, and CIDR blocks such as 10.0.0.0/8.',\n default: '',\n }),\n AGENT_PI_ENABLED_TOOL_PACKAGES: str({\n desc: 'Comma-separated optional Pi tool packages enabled for this deployment. Defaults to pi-web-access so Pi web access is available. Set it to an empty value to enable only Pi built-in tools. Accepted values: pi-web-access.',\n default: 'pi-web-access',\n }),\n AGENT_PI_WEB_SEARCH_ENABLED: bool({\n desc: 'Enables Pi web search tools when pi-web-access is enabled. Set it to false to disable web_search and get_search_content while keeping fetch_content available.',\n default: true,\n }),\n});\n\nassertInstanceDefaultModelProviderApiKeyConfig();\n\nexport const harnessToolDeploymentConfig = buildHarnessToolDeploymentConfig({\n piEnabledToolPackages: config.AGENT_PI_ENABLED_TOOL_PACKAGES,\n piWebSearchEnabled: config.AGENT_PI_WEB_SEARCH_ENABLED,\n});\n\nfunction assertInstanceDefaultModelProviderApiKeyConfig(): void {\n if (!config.AGENT_DEFAULT_PROVIDER_API_KEY) return;\n if (!config.AGENT_DEFAULT_PROVIDER) {\n throw new Error('AGENT_DEFAULT_PROVIDER_API_KEY requires AGENT_DEFAULT_PROVIDER to be set.');\n }\n\n const credentialFields =\n getModelProviderEntry(config.AGENT_DEFAULT_PROVIDER as SupportedModelProviderId)\n ?.credential_fields ?? [];\n const field = credentialFields[0];\n if (credentialFields.length === 1 && field?.key === 'api_key' && field.secret) return;\n\n throw new Error(\n 'AGENT_DEFAULT_PROVIDER_API_KEY requires AGENT_DEFAULT_PROVIDER to use exactly one secret api_key credential field.',\n );\n}\n"],"names":["agentThinkingSchema","buildHarnessToolDeploymentConfig","SUPPORTED_MODEL_PROVIDER_IDS","bool","createConfig","num","str","getModelProviderEntry","AGENT_THINKING_CHOICES","options","config","AGENT_DEFAULT_PROVIDER","desc","choices","default","undefined","AGENT_DEFAULT_PROVIDER_MODEL","AGENT_DEFAULT_PROVIDER_THINKING","AGENT_DEFAULT_PROVIDER_API_KEY","AGENT_PROVIDER_VALIDATION_TIMEOUT_MS","AGENT_CUSTOM_PROVIDER_ALLOW_PRIVATE_NETWORKS","AGENT_CUSTOM_PROVIDER_HOST_DENYLIST","AGENT_PI_ENABLED_TOOL_PACKAGES","AGENT_PI_WEB_SEARCH_ENABLED","assertInstanceDefaultModelProviderApiKeyConfig","harnessToolDeploymentConfig","piEnabledToolPackages","piWebSearchEnabled","Error","credentialFields","credential_fields","field","length","key","secret"],"mappings":"AAAA,SACEA,mBAAmB,EACnBC,gCAAgC,EAChCC,4BAA4B,QAEvB,yBAAyB;AAChC,SAAQC,IAAI,EAAEC,YAAY,EAAEC,GAAG,EAAEC,GAAG,QAAO,kBAAkB;AAC7D,SAAQC,qBAAqB,QAAO,iCAAiC;AAErE,MAAMC,yBAAyBR,oBAAoBS,OAAO;AAE1D,OAAO,MAAMC,SAASN,aAAa;IACjCO,wBAAwBL,IAAI;QAC1BM,MAAM;QACNC,SAASX;QACTY,SAASC;IACX;IACAC,8BAA8BV,IAAI;QAChCM,MAAM;QACNE,SAASC;IACX;IACAE,iCAAiCX,IAAI;QACnCM,MAAM;QACNC,SAASL;QACTM,SAASC;IACX;IACAG,gCAAgCZ,IAAI;QAClCM,MAAM;QACNE,SAASC;IACX;IACAI,sCAAsCd,IAAI;QACxCO,MAAM;QACNE,SAAS;IACX;IACAM,8CAA8CjB,KAAK;QACjDS,MAAM;QACNE,SAAS;IACX;IACAO,qCAAqCf,IAAI;QACvCM,MAAM;QACNE,SAAS;IACX;IACAQ,gCAAgChB,IAAI;QAClCM,MAAM;QACNE,SAAS;IACX;IACAS,6BAA6BpB,KAAK;QAChCS,MAAM;QACNE,SAAS;IACX;AACF,GAAG;AAEHU;AAEA,OAAO,MAAMC,8BAA8BxB,iCAAiC;IAC1EyB,uBAAuBhB,OAAOY,8BAA8B;IAC5DK,oBAAoBjB,OAAOa,2BAA2B;AACxD,GAAG;AAEH,SAASC;IACP,IAAI,CAACd,OAAOQ,8BAA8B,EAAE;IAC5C,IAAI,CAACR,OAAOC,sBAAsB,EAAE;QAClC,MAAM,IAAIiB,MAAM;IAClB;IAEA,MAAMC,mBACJtB,sBAAsBG,OAAOC,sBAAsB,GAC/CmB,qBAAqB,EAAE;IAC7B,MAAMC,QAAQF,gBAAgB,CAAC,EAAE;IACjC,IAAIA,iBAAiBG,MAAM,KAAK,KAAKD,OAAOE,QAAQ,aAAaF,MAAMG,MAAM,EAAE;IAE/E,MAAM,IAAIN,MACR;AAEJ"}
@@ -1,5 +1,5 @@
1
- import { getModelProviderEntry } from '@shipfox/api-agent-dto';
2
1
  import { UnsupportedModelProviderError } from './errors.js';
2
+ import { getModelProviderEntry } from './model-provider-policy.js';
3
3
  export function agentSystemNamespace(providerId) {
4
4
  return `system/agent/model-provider/${providerId}`;
5
5
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/credential-fingerprints.ts"],"sourcesContent":["import type {SupportedModelProviderId} from '@shipfox/api-agent-dto';\nimport {getModelProviderEntry} from '@shipfox/api-agent-dto';\nimport {UnsupportedModelProviderError} from './errors.js';\n\nexport function agentSystemNamespace(providerId: string): string {\n return `system/agent/model-provider/${providerId}`;\n}\n\nexport function toStoreKey(fieldKey: string): string {\n return fieldKey.toUpperCase();\n}\n\nexport function customCredentialToStoreKey(fieldKey: string): string {\n if (fieldKey === 'api_key') return 'API_KEY';\n if (fieldKey.startsWith('header:'))\n return `HEADER_${encodeStoreKey(fieldKey.slice('header:'.length))}`;\n return `CREDENTIAL_${encodeStoreKey(fieldKey)}`;\n}\n\nexport function customStoreKeyToRuntimeKey(storeKey: string): string {\n if (storeKey === 'API_KEY') return 'api_key';\n if (storeKey.startsWith('HEADER_'))\n return `header:${decodeStoreKey(storeKey.slice('HEADER_'.length))}`;\n if (storeKey.startsWith('CREDENTIAL_'))\n return decodeStoreKey(storeKey.slice('CREDENTIAL_'.length));\n return storeKey.toLowerCase();\n}\n\nexport function customCredentialsToStoreValues(\n credentials: Record<string, string>,\n): Record<string, string> {\n return Object.fromEntries(\n Object.entries(credentials).map(([key, value]) => [customCredentialToStoreKey(key), value]),\n );\n}\n\nexport function storeValuesToCustomRuntimeCredentials(\n values: Record<string, string>,\n): Record<string, string> {\n return Object.fromEntries(\n Object.entries(values).map(([key, value]) => [customStoreKeyToRuntimeKey(key), value]),\n );\n}\n\nexport function credentialsToStoreValues(\n providerId: SupportedModelProviderId,\n credentials: Record<string, string>,\n): Record<string, string> {\n const entry = getSupportedModelProviderEntry(providerId);\n\n return Object.fromEntries(\n entry.credential_fields.map((field) => [toStoreKey(field.key), credentials[field.key] ?? '']),\n );\n}\n\nexport function storeValuesToRuntimeCredentials(\n providerId: SupportedModelProviderId,\n values: Record<string, string>,\n): Record<string, string> {\n const entry = getSupportedModelProviderEntry(providerId);\n\n return Object.fromEntries(\n entry.credential_fields.flatMap((field) => {\n const value = values[toStoreKey(field.key)];\n return value === undefined ? [] : [[field.key, value]];\n }),\n );\n}\n\nfunction getSupportedModelProviderEntry(providerId: SupportedModelProviderId) {\n const entry = getModelProviderEntry(providerId);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(providerId);\n }\n return entry;\n}\n\nfunction encodeStoreKey(value: string): string {\n return Buffer.from(value, 'utf8').toString('hex').toUpperCase();\n}\n\nfunction decodeStoreKey(value: string): string {\n return Buffer.from(value, 'hex').toString('utf8');\n}\n"],"names":["getModelProviderEntry","UnsupportedModelProviderError","agentSystemNamespace","providerId","toStoreKey","fieldKey","toUpperCase","customCredentialToStoreKey","startsWith","encodeStoreKey","slice","length","customStoreKeyToRuntimeKey","storeKey","decodeStoreKey","toLowerCase","customCredentialsToStoreValues","credentials","Object","fromEntries","entries","map","key","value","storeValuesToCustomRuntimeCredentials","values","credentialsToStoreValues","entry","getSupportedModelProviderEntry","credential_fields","field","storeValuesToRuntimeCredentials","flatMap","undefined","support_status","Buffer","from","toString"],"mappings":"AACA,SAAQA,qBAAqB,QAAO,yBAAyB;AAC7D,SAAQC,6BAA6B,QAAO,cAAc;AAE1D,OAAO,SAASC,qBAAqBC,UAAkB;IACrD,OAAO,CAAC,4BAA4B,EAAEA,YAAY;AACpD;AAEA,OAAO,SAASC,WAAWC,QAAgB;IACzC,OAAOA,SAASC,WAAW;AAC7B;AAEA,OAAO,SAASC,2BAA2BF,QAAgB;IACzD,IAAIA,aAAa,WAAW,OAAO;IACnC,IAAIA,SAASG,UAAU,CAAC,YACtB,OAAO,CAAC,OAAO,EAAEC,eAAeJ,SAASK,KAAK,CAAC,UAAUC,MAAM,IAAI;IACrE,OAAO,CAAC,WAAW,EAAEF,eAAeJ,WAAW;AACjD;AAEA,OAAO,SAASO,2BAA2BC,QAAgB;IACzD,IAAIA,aAAa,WAAW,OAAO;IACnC,IAAIA,SAASL,UAAU,CAAC,YACtB,OAAO,CAAC,OAAO,EAAEM,eAAeD,SAASH,KAAK,CAAC,UAAUC,MAAM,IAAI;IACrE,IAAIE,SAASL,UAAU,CAAC,gBACtB,OAAOM,eAAeD,SAASH,KAAK,CAAC,cAAcC,MAAM;IAC3D,OAAOE,SAASE,WAAW;AAC7B;AAEA,OAAO,SAASC,+BACdC,WAAmC;IAEnC,OAAOC,OAAOC,WAAW,CACvBD,OAAOE,OAAO,CAACH,aAAaI,GAAG,CAAC,CAAC,CAACC,KAAKC,MAAM,GAAK;YAAChB,2BAA2Be;YAAMC;SAAM;AAE9F;AAEA,OAAO,SAASC,sCACdC,MAA8B;IAE9B,OAAOP,OAAOC,WAAW,CACvBD,OAAOE,OAAO,CAACK,QAAQJ,GAAG,CAAC,CAAC,CAACC,KAAKC,MAAM,GAAK;YAACX,2BAA2BU;YAAMC;SAAM;AAEzF;AAEA,OAAO,SAASG,yBACdvB,UAAoC,EACpCc,WAAmC;IAEnC,MAAMU,QAAQC,+BAA+BzB;IAE7C,OAAOe,OAAOC,WAAW,CACvBQ,MAAME,iBAAiB,CAACR,GAAG,CAAC,CAACS,QAAU;YAAC1B,WAAW0B,MAAMR,GAAG;YAAGL,WAAW,CAACa,MAAMR,GAAG,CAAC,IAAI;SAAG;AAEhG;AAEA,OAAO,SAASS,gCACd5B,UAAoC,EACpCsB,MAA8B;IAE9B,MAAME,QAAQC,+BAA+BzB;IAE7C,OAAOe,OAAOC,WAAW,CACvBQ,MAAME,iBAAiB,CAACG,OAAO,CAAC,CAACF;QAC/B,MAAMP,QAAQE,MAAM,CAACrB,WAAW0B,MAAMR,GAAG,EAAE;QAC3C,OAAOC,UAAUU,YAAY,EAAE,GAAG;YAAC;gBAACH,MAAMR,GAAG;gBAAEC;aAAM;SAAC;IACxD;AAEJ;AAEA,SAASK,+BAA+BzB,UAAoC;IAC1E,MAAMwB,QAAQ3B,sBAAsBG;IACpC,IAAIwB,UAAUM,aAAaN,MAAMO,cAAc,KAAK,aAAa;QAC/D,MAAM,IAAIjC,8BAA8BE;IAC1C;IACA,OAAOwB;AACT;AAEA,SAASlB,eAAec,KAAa;IACnC,OAAOY,OAAOC,IAAI,CAACb,OAAO,QAAQc,QAAQ,CAAC,OAAO/B,WAAW;AAC/D;AAEA,SAASQ,eAAeS,KAAa;IACnC,OAAOY,OAAOC,IAAI,CAACb,OAAO,OAAOc,QAAQ,CAAC;AAC5C"}
1
+ {"version":3,"sources":["../../src/core/credential-fingerprints.ts"],"sourcesContent":["import type {SupportedModelProviderId} from '@shipfox/api-agent-dto';\nimport {UnsupportedModelProviderError} from './errors.js';\nimport {getModelProviderEntry} from './model-provider-policy.js';\n\nexport function agentSystemNamespace(providerId: string): string {\n return `system/agent/model-provider/${providerId}`;\n}\n\nexport function toStoreKey(fieldKey: string): string {\n return fieldKey.toUpperCase();\n}\n\nexport function customCredentialToStoreKey(fieldKey: string): string {\n if (fieldKey === 'api_key') return 'API_KEY';\n if (fieldKey.startsWith('header:'))\n return `HEADER_${encodeStoreKey(fieldKey.slice('header:'.length))}`;\n return `CREDENTIAL_${encodeStoreKey(fieldKey)}`;\n}\n\nexport function customStoreKeyToRuntimeKey(storeKey: string): string {\n if (storeKey === 'API_KEY') return 'api_key';\n if (storeKey.startsWith('HEADER_'))\n return `header:${decodeStoreKey(storeKey.slice('HEADER_'.length))}`;\n if (storeKey.startsWith('CREDENTIAL_'))\n return decodeStoreKey(storeKey.slice('CREDENTIAL_'.length));\n return storeKey.toLowerCase();\n}\n\nexport function customCredentialsToStoreValues(\n credentials: Record<string, string>,\n): Record<string, string> {\n return Object.fromEntries(\n Object.entries(credentials).map(([key, value]) => [customCredentialToStoreKey(key), value]),\n );\n}\n\nexport function storeValuesToCustomRuntimeCredentials(\n values: Record<string, string>,\n): Record<string, string> {\n return Object.fromEntries(\n Object.entries(values).map(([key, value]) => [customStoreKeyToRuntimeKey(key), value]),\n );\n}\n\nexport function credentialsToStoreValues(\n providerId: SupportedModelProviderId,\n credentials: Record<string, string>,\n): Record<string, string> {\n const entry = getSupportedModelProviderEntry(providerId);\n\n return Object.fromEntries(\n entry.credential_fields.map((field) => [toStoreKey(field.key), credentials[field.key] ?? '']),\n );\n}\n\nexport function storeValuesToRuntimeCredentials(\n providerId: SupportedModelProviderId,\n values: Record<string, string>,\n): Record<string, string> {\n const entry = getSupportedModelProviderEntry(providerId);\n\n return Object.fromEntries(\n entry.credential_fields.flatMap((field) => {\n const value = values[toStoreKey(field.key)];\n return value === undefined ? [] : [[field.key, value]];\n }),\n );\n}\n\nfunction getSupportedModelProviderEntry(providerId: SupportedModelProviderId) {\n const entry = getModelProviderEntry(providerId);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(providerId);\n }\n return entry;\n}\n\nfunction encodeStoreKey(value: string): string {\n return Buffer.from(value, 'utf8').toString('hex').toUpperCase();\n}\n\nfunction decodeStoreKey(value: string): string {\n return Buffer.from(value, 'hex').toString('utf8');\n}\n"],"names":["UnsupportedModelProviderError","getModelProviderEntry","agentSystemNamespace","providerId","toStoreKey","fieldKey","toUpperCase","customCredentialToStoreKey","startsWith","encodeStoreKey","slice","length","customStoreKeyToRuntimeKey","storeKey","decodeStoreKey","toLowerCase","customCredentialsToStoreValues","credentials","Object","fromEntries","entries","map","key","value","storeValuesToCustomRuntimeCredentials","values","credentialsToStoreValues","entry","getSupportedModelProviderEntry","credential_fields","field","storeValuesToRuntimeCredentials","flatMap","undefined","support_status","Buffer","from","toString"],"mappings":"AACA,SAAQA,6BAA6B,QAAO,cAAc;AAC1D,SAAQC,qBAAqB,QAAO,6BAA6B;AAEjE,OAAO,SAASC,qBAAqBC,UAAkB;IACrD,OAAO,CAAC,4BAA4B,EAAEA,YAAY;AACpD;AAEA,OAAO,SAASC,WAAWC,QAAgB;IACzC,OAAOA,SAASC,WAAW;AAC7B;AAEA,OAAO,SAASC,2BAA2BF,QAAgB;IACzD,IAAIA,aAAa,WAAW,OAAO;IACnC,IAAIA,SAASG,UAAU,CAAC,YACtB,OAAO,CAAC,OAAO,EAAEC,eAAeJ,SAASK,KAAK,CAAC,UAAUC,MAAM,IAAI;IACrE,OAAO,CAAC,WAAW,EAAEF,eAAeJ,WAAW;AACjD;AAEA,OAAO,SAASO,2BAA2BC,QAAgB;IACzD,IAAIA,aAAa,WAAW,OAAO;IACnC,IAAIA,SAASL,UAAU,CAAC,YACtB,OAAO,CAAC,OAAO,EAAEM,eAAeD,SAASH,KAAK,CAAC,UAAUC,MAAM,IAAI;IACrE,IAAIE,SAASL,UAAU,CAAC,gBACtB,OAAOM,eAAeD,SAASH,KAAK,CAAC,cAAcC,MAAM;IAC3D,OAAOE,SAASE,WAAW;AAC7B;AAEA,OAAO,SAASC,+BACdC,WAAmC;IAEnC,OAAOC,OAAOC,WAAW,CACvBD,OAAOE,OAAO,CAACH,aAAaI,GAAG,CAAC,CAAC,CAACC,KAAKC,MAAM,GAAK;YAAChB,2BAA2Be;YAAMC;SAAM;AAE9F;AAEA,OAAO,SAASC,sCACdC,MAA8B;IAE9B,OAAOP,OAAOC,WAAW,CACvBD,OAAOE,OAAO,CAACK,QAAQJ,GAAG,CAAC,CAAC,CAACC,KAAKC,MAAM,GAAK;YAACX,2BAA2BU;YAAMC;SAAM;AAEzF;AAEA,OAAO,SAASG,yBACdvB,UAAoC,EACpCc,WAAmC;IAEnC,MAAMU,QAAQC,+BAA+BzB;IAE7C,OAAOe,OAAOC,WAAW,CACvBQ,MAAME,iBAAiB,CAACR,GAAG,CAAC,CAACS,QAAU;YAAC1B,WAAW0B,MAAMR,GAAG;YAAGL,WAAW,CAACa,MAAMR,GAAG,CAAC,IAAI;SAAG;AAEhG;AAEA,OAAO,SAASS,gCACd5B,UAAoC,EACpCsB,MAA8B;IAE9B,MAAME,QAAQC,+BAA+BzB;IAE7C,OAAOe,OAAOC,WAAW,CACvBQ,MAAME,iBAAiB,CAACG,OAAO,CAAC,CAACF;QAC/B,MAAMP,QAAQE,MAAM,CAACrB,WAAW0B,MAAMR,GAAG,EAAE;QAC3C,OAAOC,UAAUU,YAAY,EAAE,GAAG;YAAC;gBAACH,MAAMR,GAAG;gBAAEC;aAAM;SAAC;IACxD;AAEJ;AAEA,SAASK,+BAA+BzB,UAAoC;IAC1E,MAAMwB,QAAQ1B,sBAAsBE;IACpC,IAAIwB,UAAUM,aAAaN,MAAMO,cAAc,KAAK,aAAa;QAC/D,MAAM,IAAIlC,8BAA8BG;IAC1C;IACA,OAAOwB;AACT;AAEA,SAASlB,eAAec,KAAa;IACnC,OAAOY,OAAOC,IAAI,CAACb,OAAO,QAAQc,QAAQ,CAAC,OAAO/B,WAAW;AAC/D;AAEA,SAASQ,eAAeS,KAAa;IACnC,OAAOY,OAAOC,IAAI,CAACb,OAAO,OAAOc,QAAQ,CAAC;AAC5C"}
@@ -6,6 +6,7 @@ export { CustomModelProviderConfigNotFoundError, CustomModelProviderSlugCollisio
6
6
  export { getHarnessDescriptor, getHarnessToolDescriptor, type HarnessDescriptor, type HarnessToolDeploymentConfig, type HarnessToolDescriptor, type HarnessToolPackageName, harnessSupportsProvider, harnessSupportsTool, listEnabledHarnessTools, listHarnessDescriptors, listHarnessProviderModels, listHarnessTools, probeHarnessProviderCredentials, } from './harness/index.js';
7
7
  export { buildModelProviderCatalog } from './model-provider-catalog.js';
8
8
  export { deleteModelProviderConfig, testAndSaveModelProviderConfig, updateModelProviderConfigDefaultModel, } from './model-provider-config-service.js';
9
+ export { getModelProviderCredentialKeys, getModelProviderEntry, isReservedModelProviderId, listSupportedModelProviders, modelProviderCredentialKeysMatch, } from './model-provider-policy.js';
9
10
  export { type AgentConfigResolutionContext, type AgentDefaultsResolver, type ContextualAgentConfig, catalogDefaultAgentResolver, type ResolvedAgentConfig, resolveAgentConfig, } from './resolve-agent-config.js';
10
11
  export { type ResolveRuntimeCredentialsParams, resolveRuntimeCredentials, } from './resolve-runtime-credentials.js';
11
12
  export { createWorkspaceAgentDefaultsResolver } from './workspace-agent-defaults-resolver.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,+BAA+B,EAC/B,yCAAyC,EACzC,+BAA+B,GAChC,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAC,iCAAiC,EAAC,MAAM,4CAA4C,CAAC;AAC7F,YAAY,EAAC,sBAAsB,EAAC,MAAM,wCAAwC,CAAC;AACnF,YAAY,EAAC,mBAAmB,EAAC,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EACL,sCAAsC,EACtC,qCAAqC,EACrC,iDAAiD,EACjD,sBAAsB,EACtB,4BAA4B,EAC5B,yCAAyC,EACzC,gCAAgC,EAChC,4BAA4B,EAC5B,uCAAuC,EACvC,+BAA+B,EAC/B,+BAA+B,EAC/B,6BAA6B,GAC9B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EAChC,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,uBAAuB,EACvB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,gBAAgB,EAChB,+BAA+B,GAChC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,yBAAyB,EAAC,MAAM,6BAA6B,CAAC;AACtE,OAAO,EACL,yBAAyB,EACzB,8BAA8B,EAC9B,qCAAqC,GACtC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,2BAA2B,EAC3B,KAAK,mBAAmB,EACxB,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,KAAK,+BAA+B,EACpC,yBAAyB,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAC,oCAAoC,EAAC,MAAM,wCAAwC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,+BAA+B,EAC/B,yCAAyC,EACzC,+BAA+B,GAChC,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAC,iCAAiC,EAAC,MAAM,4CAA4C,CAAC;AAC7F,YAAY,EAAC,sBAAsB,EAAC,MAAM,wCAAwC,CAAC;AACnF,YAAY,EAAC,mBAAmB,EAAC,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EACL,sCAAsC,EACtC,qCAAqC,EACrC,iDAAiD,EACjD,sBAAsB,EACtB,4BAA4B,EAC5B,yCAAyC,EACzC,gCAAgC,EAChC,4BAA4B,EAC5B,uCAAuC,EACvC,+BAA+B,EAC/B,+BAA+B,EAC/B,6BAA6B,GAC9B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EAChC,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,uBAAuB,EACvB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,EACzB,gBAAgB,EAChB,+BAA+B,GAChC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,yBAAyB,EAAC,MAAM,6BAA6B,CAAC;AACtE,OAAO,EACL,yBAAyB,EACzB,8BAA8B,EAC9B,qCAAqC,GACtC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,8BAA8B,EAC9B,qBAAqB,EACrB,yBAAyB,EACzB,2BAA2B,EAC3B,gCAAgC,GACjC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,2BAA2B,EAC3B,KAAK,mBAAmB,EACxB,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,KAAK,+BAA+B,EACpC,yBAAyB,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAC,oCAAoC,EAAC,MAAM,wCAAwC,CAAC"}
@@ -4,6 +4,7 @@ export { CustomModelProviderConfigNotFoundError, CustomModelProviderSlugCollisio
4
4
  export { getHarnessDescriptor, getHarnessToolDescriptor, harnessSupportsProvider, harnessSupportsTool, listEnabledHarnessTools, listHarnessDescriptors, listHarnessProviderModels, listHarnessTools, probeHarnessProviderCredentials } from './harness/index.js';
5
5
  export { buildModelProviderCatalog } from './model-provider-catalog.js';
6
6
  export { deleteModelProviderConfig, testAndSaveModelProviderConfig, updateModelProviderConfigDefaultModel } from './model-provider-config-service.js';
7
+ export { getModelProviderCredentialKeys, getModelProviderEntry, isReservedModelProviderId, listSupportedModelProviders, modelProviderCredentialKeysMatch } from './model-provider-policy.js';
7
8
  export { catalogDefaultAgentResolver, resolveAgentConfig } from './resolve-agent-config.js';
8
9
  export { resolveRuntimeCredentials } from './resolve-runtime-credentials.js';
9
10
  export { createWorkspaceAgentDefaultsResolver } from './workspace-agent-defaults-resolver.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/index.ts"],"sourcesContent":["export {\n createCustomModelProviderConfig,\n resolveCustomModelProviderDiscoveryParams,\n updateCustomModelProviderConfig,\n} from './custom-model-provider-config-service.js';\nexport {discoverCustomModelProviderModels} from './discover-custom-model-provider-models.js';\nexport type {AgentWorkspaceSettings} from './entities/agent-workspace-settings.js';\nexport type {ModelProviderConfig} from './entities/model-provider-config.js';\nexport {\n CustomModelProviderConfigNotFoundError,\n CustomModelProviderSlugCollisionError,\n CustomModelProviderStoredSecretBaseUrlChangeError,\n InvalidAgentModelError,\n InvalidCredentialFieldsError,\n InvalidCustomModelProviderHeaderKeepError,\n ModelProviderConfigNotFoundError,\n ModelProviderValidationError,\n ModelProviderValidationUnavailableError,\n UnsupportedHarnessProviderError,\n UnsupportedHarnessThinkingError,\n UnsupportedModelProviderError,\n} from './errors.js';\nexport {\n getHarnessDescriptor,\n getHarnessToolDescriptor,\n type HarnessDescriptor,\n type HarnessToolDeploymentConfig,\n type HarnessToolDescriptor,\n type HarnessToolPackageName,\n harnessSupportsProvider,\n harnessSupportsTool,\n listEnabledHarnessTools,\n listHarnessDescriptors,\n listHarnessProviderModels,\n listHarnessTools,\n probeHarnessProviderCredentials,\n} from './harness/index.js';\nexport {buildModelProviderCatalog} from './model-provider-catalog.js';\nexport {\n deleteModelProviderConfig,\n testAndSaveModelProviderConfig,\n updateModelProviderConfigDefaultModel,\n} from './model-provider-config-service.js';\nexport {\n type AgentConfigResolutionContext,\n type AgentDefaultsResolver,\n type ContextualAgentConfig,\n catalogDefaultAgentResolver,\n type ResolvedAgentConfig,\n resolveAgentConfig,\n} from './resolve-agent-config.js';\nexport {\n type ResolveRuntimeCredentialsParams,\n resolveRuntimeCredentials,\n} from './resolve-runtime-credentials.js';\nexport {createWorkspaceAgentDefaultsResolver} from './workspace-agent-defaults-resolver.js';\n"],"names":["createCustomModelProviderConfig","resolveCustomModelProviderDiscoveryParams","updateCustomModelProviderConfig","discoverCustomModelProviderModels","CustomModelProviderConfigNotFoundError","CustomModelProviderSlugCollisionError","CustomModelProviderStoredSecretBaseUrlChangeError","InvalidAgentModelError","InvalidCredentialFieldsError","InvalidCustomModelProviderHeaderKeepError","ModelProviderConfigNotFoundError","ModelProviderValidationError","ModelProviderValidationUnavailableError","UnsupportedHarnessProviderError","UnsupportedHarnessThinkingError","UnsupportedModelProviderError","getHarnessDescriptor","getHarnessToolDescriptor","harnessSupportsProvider","harnessSupportsTool","listEnabledHarnessTools","listHarnessDescriptors","listHarnessProviderModels","listHarnessTools","probeHarnessProviderCredentials","buildModelProviderCatalog","deleteModelProviderConfig","testAndSaveModelProviderConfig","updateModelProviderConfigDefaultModel","catalogDefaultAgentResolver","resolveAgentConfig","resolveRuntimeCredentials","createWorkspaceAgentDefaultsResolver"],"mappings":"AAAA,SACEA,+BAA+B,EAC/BC,yCAAyC,EACzCC,+BAA+B,QAC1B,4CAA4C;AACnD,SAAQC,iCAAiC,QAAO,6CAA6C;AAG7F,SACEC,sCAAsC,EACtCC,qCAAqC,EACrCC,iDAAiD,EACjDC,sBAAsB,EACtBC,4BAA4B,EAC5BC,yCAAyC,EACzCC,gCAAgC,EAChCC,4BAA4B,EAC5BC,uCAAuC,EACvCC,+BAA+B,EAC/BC,+BAA+B,EAC/BC,6BAA6B,QACxB,cAAc;AACrB,SACEC,oBAAoB,EACpBC,wBAAwB,EAKxBC,uBAAuB,EACvBC,mBAAmB,EACnBC,uBAAuB,EACvBC,sBAAsB,EACtBC,yBAAyB,EACzBC,gBAAgB,EAChBC,+BAA+B,QAC1B,qBAAqB;AAC5B,SAAQC,yBAAyB,QAAO,8BAA8B;AACtE,SACEC,yBAAyB,EACzBC,8BAA8B,EAC9BC,qCAAqC,QAChC,qCAAqC;AAC5C,SAIEC,2BAA2B,EAE3BC,kBAAkB,QACb,4BAA4B;AACnC,SAEEC,yBAAyB,QACpB,mCAAmC;AAC1C,SAAQC,oCAAoC,QAAO,yCAAyC"}
1
+ {"version":3,"sources":["../../src/core/index.ts"],"sourcesContent":["export {\n createCustomModelProviderConfig,\n resolveCustomModelProviderDiscoveryParams,\n updateCustomModelProviderConfig,\n} from './custom-model-provider-config-service.js';\nexport {discoverCustomModelProviderModels} from './discover-custom-model-provider-models.js';\nexport type {AgentWorkspaceSettings} from './entities/agent-workspace-settings.js';\nexport type {ModelProviderConfig} from './entities/model-provider-config.js';\nexport {\n CustomModelProviderConfigNotFoundError,\n CustomModelProviderSlugCollisionError,\n CustomModelProviderStoredSecretBaseUrlChangeError,\n InvalidAgentModelError,\n InvalidCredentialFieldsError,\n InvalidCustomModelProviderHeaderKeepError,\n ModelProviderConfigNotFoundError,\n ModelProviderValidationError,\n ModelProviderValidationUnavailableError,\n UnsupportedHarnessProviderError,\n UnsupportedHarnessThinkingError,\n UnsupportedModelProviderError,\n} from './errors.js';\nexport {\n getHarnessDescriptor,\n getHarnessToolDescriptor,\n type HarnessDescriptor,\n type HarnessToolDeploymentConfig,\n type HarnessToolDescriptor,\n type HarnessToolPackageName,\n harnessSupportsProvider,\n harnessSupportsTool,\n listEnabledHarnessTools,\n listHarnessDescriptors,\n listHarnessProviderModels,\n listHarnessTools,\n probeHarnessProviderCredentials,\n} from './harness/index.js';\nexport {buildModelProviderCatalog} from './model-provider-catalog.js';\nexport {\n deleteModelProviderConfig,\n testAndSaveModelProviderConfig,\n updateModelProviderConfigDefaultModel,\n} from './model-provider-config-service.js';\nexport {\n getModelProviderCredentialKeys,\n getModelProviderEntry,\n isReservedModelProviderId,\n listSupportedModelProviders,\n modelProviderCredentialKeysMatch,\n} from './model-provider-policy.js';\nexport {\n type AgentConfigResolutionContext,\n type AgentDefaultsResolver,\n type ContextualAgentConfig,\n catalogDefaultAgentResolver,\n type ResolvedAgentConfig,\n resolveAgentConfig,\n} from './resolve-agent-config.js';\nexport {\n type ResolveRuntimeCredentialsParams,\n resolveRuntimeCredentials,\n} from './resolve-runtime-credentials.js';\nexport {createWorkspaceAgentDefaultsResolver} from './workspace-agent-defaults-resolver.js';\n"],"names":["createCustomModelProviderConfig","resolveCustomModelProviderDiscoveryParams","updateCustomModelProviderConfig","discoverCustomModelProviderModels","CustomModelProviderConfigNotFoundError","CustomModelProviderSlugCollisionError","CustomModelProviderStoredSecretBaseUrlChangeError","InvalidAgentModelError","InvalidCredentialFieldsError","InvalidCustomModelProviderHeaderKeepError","ModelProviderConfigNotFoundError","ModelProviderValidationError","ModelProviderValidationUnavailableError","UnsupportedHarnessProviderError","UnsupportedHarnessThinkingError","UnsupportedModelProviderError","getHarnessDescriptor","getHarnessToolDescriptor","harnessSupportsProvider","harnessSupportsTool","listEnabledHarnessTools","listHarnessDescriptors","listHarnessProviderModels","listHarnessTools","probeHarnessProviderCredentials","buildModelProviderCatalog","deleteModelProviderConfig","testAndSaveModelProviderConfig","updateModelProviderConfigDefaultModel","getModelProviderCredentialKeys","getModelProviderEntry","isReservedModelProviderId","listSupportedModelProviders","modelProviderCredentialKeysMatch","catalogDefaultAgentResolver","resolveAgentConfig","resolveRuntimeCredentials","createWorkspaceAgentDefaultsResolver"],"mappings":"AAAA,SACEA,+BAA+B,EAC/BC,yCAAyC,EACzCC,+BAA+B,QAC1B,4CAA4C;AACnD,SAAQC,iCAAiC,QAAO,6CAA6C;AAG7F,SACEC,sCAAsC,EACtCC,qCAAqC,EACrCC,iDAAiD,EACjDC,sBAAsB,EACtBC,4BAA4B,EAC5BC,yCAAyC,EACzCC,gCAAgC,EAChCC,4BAA4B,EAC5BC,uCAAuC,EACvCC,+BAA+B,EAC/BC,+BAA+B,EAC/BC,6BAA6B,QACxB,cAAc;AACrB,SACEC,oBAAoB,EACpBC,wBAAwB,EAKxBC,uBAAuB,EACvBC,mBAAmB,EACnBC,uBAAuB,EACvBC,sBAAsB,EACtBC,yBAAyB,EACzBC,gBAAgB,EAChBC,+BAA+B,QAC1B,qBAAqB;AAC5B,SAAQC,yBAAyB,QAAO,8BAA8B;AACtE,SACEC,yBAAyB,EACzBC,8BAA8B,EAC9BC,qCAAqC,QAChC,qCAAqC;AAC5C,SACEC,8BAA8B,EAC9BC,qBAAqB,EACrBC,yBAAyB,EACzBC,2BAA2B,EAC3BC,gCAAgC,QAC3B,6BAA6B;AACpC,SAIEC,2BAA2B,EAE3BC,kBAAkB,QACb,4BAA4B;AACnC,SAEEC,yBAAyB,QACpB,mCAAmC;AAC1C,SAAQC,oCAAoC,QAAO,yCAAyC"}
@@ -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;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
+ {"version":3,"file":"model-provider-config-service.d.ts","sourceRoot":"","sources":["../../src/core/model-provider-config-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC9B,MAAM,wBAAwB,CAAC;AAUhC,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,qCAAqC,CAAC;AAS7E,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,10 +1,11 @@
1
- import { DEFAULT_AGENT_THINKING, getModelProviderEntry, modelProviderCredentialKeysMatch } from '@shipfox/api-agent-dto';
1
+ import { DEFAULT_AGENT_THINKING } from '@shipfox/api-agent-dto';
2
2
  import { reportError } from '@shipfox/node-error-monitoring';
3
3
  import { logger } from '@shipfox/node-opentelemetry';
4
4
  import { deleteModelProviderConfig as deleteModelProviderConfigRow, getModelProviderConfig, updateModelProviderDefaultModel, upsertModelProviderConfig } from '#db/index.js';
5
5
  import { agentSystemNamespace, credentialsToStoreValues } from './credential-fingerprints.js';
6
6
  import { InvalidAgentModelError, InvalidCredentialFieldsError, ModelProviderConfigNotFoundError, UnsupportedModelProviderError } from './errors.js';
7
7
  import { buildModelProviderCatalog } from './model-provider-catalog.js';
8
+ import { getModelProviderEntry, modelProviderCredentialKeysMatch } from './model-provider-policy.js';
8
9
  import { probeModelProviderCredentials, runProviderProbe } from './model-provider-validation.js';
9
10
  import { requireAgentSecretsClient } from './secrets-client.js';
10
11
  export async function testAndSaveModelProviderConfig(params, options = {}) {
@@ -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 {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
+ {"version":3,"sources":["../../src/core/model-provider-config-service.ts"],"sourcesContent":["import {\n DEFAULT_AGENT_THINKING,\n type ModelProviderRef,\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 {getModelProviderEntry, modelProviderCredentialKeysMatch} from './model-provider-policy.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","reportError","logger","deleteModelProviderConfig","deleteModelProviderConfigRow","getModelProviderConfig","updateModelProviderDefaultModel","upsertModelProviderConfig","agentSystemNamespace","credentialsToStoreValues","InvalidAgentModelError","InvalidCredentialFieldsError","ModelProviderConfigNotFoundError","UnsupportedModelProviderError","buildModelProviderCatalog","getModelProviderEntry","modelProviderCredentialKeysMatch","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,7 @@
1
+ import type { ModelProviderCatalogSeedDto, SupportedModelProviderId } from '@shipfox/api-agent-dto';
2
+ export declare function getModelProviderEntry(id: string): ModelProviderCatalogSeedDto | undefined;
3
+ export declare function getModelProviderCredentialKeys(providerId: SupportedModelProviderId): string[] | undefined;
4
+ export declare function modelProviderCredentialKeysMatch(providerId: SupportedModelProviderId, credentials: Record<string, string>): boolean;
5
+ export declare function listSupportedModelProviders(): readonly ModelProviderCatalogSeedDto[];
6
+ export declare function isReservedModelProviderId(value: string): boolean;
7
+ //# sourceMappingURL=model-provider-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-provider-policy.d.ts","sourceRoot":"","sources":["../../src/core/model-provider-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,2BAA2B,EAAE,wBAAwB,EAAC,MAAM,wBAAwB,CAAC;AAGlG,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,2BAA2B,GAAG,SAAS,CAEzF;AAED,wBAAgB,8BAA8B,CAC5C,UAAU,EAAE,wBAAwB,GACnC,MAAM,EAAE,GAAG,SAAS,CAItB;AAED,wBAAgB,gCAAgC,CAC9C,UAAU,EAAE,wBAAwB,EACpC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,OAAO,CAQT;AAED,wBAAgB,2BAA2B,IAAI,SAAS,2BAA2B,EAAE,CAEpF;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEhE"}
@@ -0,0 +1,23 @@
1
+ import { MODEL_PROVIDER_CATALOG_SEED, MODEL_PROVIDER_IDS } from '@shipfox/api-agent-dto';
2
+ export function getModelProviderEntry(id) {
3
+ return MODEL_PROVIDER_CATALOG_SEED.find((entry)=>entry.id === id);
4
+ }
5
+ export function getModelProviderCredentialKeys(providerId) {
6
+ const entry = getModelProviderEntry(providerId);
7
+ if (entry === undefined || entry.support_status !== 'supported') return undefined;
8
+ return entry.credential_fields.map((field)=>field.key).sort();
9
+ }
10
+ export function modelProviderCredentialKeysMatch(providerId, credentials) {
11
+ const expectedKeys = getModelProviderCredentialKeys(providerId);
12
+ if (expectedKeys === undefined) return false;
13
+ const actualKeys = Object.keys(credentials).sort();
14
+ return actualKeys.length === expectedKeys.length && actualKeys.every((key, index)=>key === expectedKeys[index]);
15
+ }
16
+ export function listSupportedModelProviders() {
17
+ return MODEL_PROVIDER_CATALOG_SEED.filter((entry)=>entry.support_status === 'supported');
18
+ }
19
+ export function isReservedModelProviderId(value) {
20
+ return MODEL_PROVIDER_IDS.includes(value);
21
+ }
22
+
23
+ //# sourceMappingURL=model-provider-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/model-provider-policy.ts"],"sourcesContent":["import type {ModelProviderCatalogSeedDto, SupportedModelProviderId} from '@shipfox/api-agent-dto';\nimport {MODEL_PROVIDER_CATALOG_SEED, MODEL_PROVIDER_IDS} from '@shipfox/api-agent-dto';\n\nexport function getModelProviderEntry(id: string): ModelProviderCatalogSeedDto | undefined {\n return MODEL_PROVIDER_CATALOG_SEED.find((entry) => entry.id === id);\n}\n\nexport function getModelProviderCredentialKeys(\n providerId: SupportedModelProviderId,\n): string[] | undefined {\n const entry = getModelProviderEntry(providerId);\n if (entry === undefined || entry.support_status !== 'supported') return undefined;\n return entry.credential_fields.map((field) => field.key).sort();\n}\n\nexport function modelProviderCredentialKeysMatch(\n providerId: SupportedModelProviderId,\n credentials: Record<string, string>,\n): boolean {\n const expectedKeys = getModelProviderCredentialKeys(providerId);\n if (expectedKeys === undefined) return false;\n const actualKeys = Object.keys(credentials).sort();\n return (\n actualKeys.length === expectedKeys.length &&\n actualKeys.every((key, index) => key === expectedKeys[index])\n );\n}\n\nexport function listSupportedModelProviders(): readonly ModelProviderCatalogSeedDto[] {\n return MODEL_PROVIDER_CATALOG_SEED.filter((entry) => entry.support_status === 'supported');\n}\n\nexport function isReservedModelProviderId(value: string): boolean {\n return (MODEL_PROVIDER_IDS as readonly string[]).includes(value);\n}\n"],"names":["MODEL_PROVIDER_CATALOG_SEED","MODEL_PROVIDER_IDS","getModelProviderEntry","id","find","entry","getModelProviderCredentialKeys","providerId","undefined","support_status","credential_fields","map","field","key","sort","modelProviderCredentialKeysMatch","credentials","expectedKeys","actualKeys","Object","keys","length","every","index","listSupportedModelProviders","filter","isReservedModelProviderId","value","includes"],"mappings":"AACA,SAAQA,2BAA2B,EAAEC,kBAAkB,QAAO,yBAAyB;AAEvF,OAAO,SAASC,sBAAsBC,EAAU;IAC9C,OAAOH,4BAA4BI,IAAI,CAAC,CAACC,QAAUA,MAAMF,EAAE,KAAKA;AAClE;AAEA,OAAO,SAASG,+BACdC,UAAoC;IAEpC,MAAMF,QAAQH,sBAAsBK;IACpC,IAAIF,UAAUG,aAAaH,MAAMI,cAAc,KAAK,aAAa,OAAOD;IACxE,OAAOH,MAAMK,iBAAiB,CAACC,GAAG,CAAC,CAACC,QAAUA,MAAMC,GAAG,EAAEC,IAAI;AAC/D;AAEA,OAAO,SAASC,iCACdR,UAAoC,EACpCS,WAAmC;IAEnC,MAAMC,eAAeX,+BAA+BC;IACpD,IAAIU,iBAAiBT,WAAW,OAAO;IACvC,MAAMU,aAAaC,OAAOC,IAAI,CAACJ,aAAaF,IAAI;IAChD,OACEI,WAAWG,MAAM,KAAKJ,aAAaI,MAAM,IACzCH,WAAWI,KAAK,CAAC,CAACT,KAAKU,QAAUV,QAAQI,YAAY,CAACM,MAAM;AAEhE;AAEA,OAAO,SAASC;IACd,OAAOxB,4BAA4ByB,MAAM,CAAC,CAACpB,QAAUA,MAAMI,cAAc,KAAK;AAChF;AAEA,OAAO,SAASiB,0BAA0BC,KAAa;IACrD,OAAO,AAAC1B,mBAAyC2B,QAAQ,CAACD;AAC5D"}
@@ -1,4 +1,4 @@
1
- import { type CustomAgentModelDto, type ModelProviderApi, type ModelProviderRef, type SupportedModelProviderId } from '@shipfox/api-agent-dto';
1
+ import type { CustomAgentModelDto, ModelProviderApi, ModelProviderRef, SupportedModelProviderId } from '@shipfox/api-agent-dto';
2
2
  import { type EgressPolicy } from '@shipfox/node-egress-guard';
3
3
  export interface ProbeModelProviderCredentialsParams {
4
4
  providerId: SupportedModelProviderId;
@@ -1 +1 @@
1
- {"version":3,"file":"model-provider-validation.d.ts","sourceRoot":"","sources":["../../src/core/model-provider-validation.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,mBAAmB,EAExB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC9B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAC,KAAK,YAAY,EAA0B,MAAM,4BAA4B,CAAC;AAiBtF,MAAM,WAAW,mCAAmC;IAClD,UAAU,EAAE,wBAAwB,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,yCAAyC;IACxD,UAAU,EAAE,gBAAgB,CAAC;IAC7B,GAAG,EAAE,gBAAgB,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC7C,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,sBAAsB,CAAC,KAAK;IAC3C,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,EAAE,KAAK,CAAC;IACZ,WAAW,EAAE,wBAAwB,GAAG,QAAQ,CAAC;IACjD,UAAU,EAAE,gBAAgB,CAAC;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAC1C,MAAM,EAAE,sBAAsB,CAAC,KAAK,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,mCAAmC,GAC1C,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED,wBAAsB,mCAAmC,CACvD,MAAM,EAAE,yCAAyC,GAChD,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAQpF;AAED,wBAAgB,YAAY,IAAI,YAAY,CAK3C"}
1
+ {"version":3,"file":"model-provider-validation.d.ts","sourceRoot":"","sources":["../../src/core/model-provider-validation.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAC,KAAK,YAAY,EAA0B,MAAM,4BAA4B,CAAC;AAkBtF,MAAM,WAAW,mCAAmC;IAClD,UAAU,EAAE,wBAAwB,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,yCAAyC;IACxD,UAAU,EAAE,gBAAgB,CAAC;IAC7B,GAAG,EAAE,gBAAgB,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC7C,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,sBAAsB,CAAC,KAAK;IAC3C,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,EAAE,KAAK,CAAC;IACZ,WAAW,EAAE,wBAAwB,GAAG,QAAQ,CAAC;IACjD,UAAU,EAAE,gBAAgB,CAAC;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAC1C,MAAM,EAAE,sBAAsB,CAAC,KAAK,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,mCAAmC,GAC1C,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED,wBAAsB,mCAAmC,CACvD,MAAM,EAAE,yCAAyC,GAChD,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAQpF;AAED,wBAAgB,YAAY,IAAI,YAAY,CAK3C"}
@@ -1,11 +1,11 @@
1
1
  import { complete, getModels } from '@earendil-works/pi-ai';
2
- import { getModelProviderEntry } from '@shipfox/api-agent-dto';
3
2
  import { parseEgressHostDenylist } from '@shipfox/node-egress-guard';
4
3
  import { redactSecrets, secretWireForms } from '@shipfox/redact';
5
4
  import { config } from '#config.js';
6
5
  import { modelProviderValidationCount } from '#metrics/index.js';
7
6
  import { appendCustomProviderPath } from './custom-provider-url.js';
8
7
  import { InvalidAgentModelError, InvalidCredentialFieldsError, ModelProviderValidationError, ModelProviderValidationUnavailableError, UnsupportedModelProviderError } from './errors.js';
8
+ import { getModelProviderEntry } from './model-provider-policy.js';
9
9
  const PROBE_MAX_TOKENS = 64;
10
10
  const MAX_SANITIZED_ERROR_LENGTH = 500;
11
11
  const CUSTOM_PROBE_PROMPT = 'Reply with OK.';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/model-provider-validation.ts"],"sourcesContent":["import {\n type AssistantMessage,\n type Context,\n complete,\n getModels,\n type ProviderStreamOptions,\n} from '@earendil-works/pi-ai';\nimport {\n type CustomAgentModelDto,\n getModelProviderEntry,\n type ModelProviderApi,\n type ModelProviderRef,\n type SupportedModelProviderId,\n} from '@shipfox/api-agent-dto';\nimport {type EgressPolicy, parseEgressHostDenylist} from '@shipfox/node-egress-guard';\nimport {redactSecrets, secretWireForms} from '@shipfox/redact';\nimport {config} from '#config.js';\nimport {modelProviderValidationCount} from '#metrics/index.js';\nimport {appendCustomProviderPath} from './custom-provider-url.js';\nimport {\n InvalidAgentModelError,\n InvalidCredentialFieldsError,\n ModelProviderValidationError,\n ModelProviderValidationUnavailableError,\n UnsupportedModelProviderError,\n} from './errors.js';\n\nconst PROBE_MAX_TOKENS = 64;\nconst MAX_SANITIZED_ERROR_LENGTH = 500;\nconst CUSTOM_PROBE_PROMPT = 'Reply with OK.';\n\nexport interface ProbeModelProviderCredentialsParams {\n providerId: SupportedModelProviderId;\n model: string;\n credentials: Record<string, string>;\n signal?: AbortSignal | undefined;\n}\n\nexport interface ProbeCustomModelProviderCredentialsParams {\n providerId: ModelProviderRef;\n api: ModelProviderApi;\n baseUrl: string;\n model: CustomAgentModelDto;\n apiKey?: string | undefined;\n headers?: Record<string, string> | undefined;\n signal?: AbortSignal | undefined;\n}\n\nexport interface RunProviderProbeParams<TArgs> {\n probe: (args: TArgs) => Promise<void>;\n args: TArgs;\n metricLabel: SupportedModelProviderId | 'custom';\n providerId: ModelProviderRef;\n secrets: string[];\n signal?: AbortSignal | undefined;\n}\n\nexport async function runProviderProbe<TArgs>(\n params: RunProviderProbeParams<TArgs>,\n): Promise<void> {\n try {\n await params.probe(params.args);\n } catch (error) {\n if (params.signal?.aborted) throw error;\n modelProviderValidationCount.add(1, {\n model_provider: params.metricLabel,\n outcome: 'failed',\n });\n if (error instanceof InvalidAgentModelError) throw error;\n\n const sanitizedMessage = sanitizeModelProviderError(error, params.secrets);\n throw new ModelProviderValidationError(params.providerId, sanitizedMessage);\n }\n\n modelProviderValidationCount.add(1, {\n model_provider: params.metricLabel,\n outcome: 'succeeded',\n });\n}\n\nexport async function probeModelProviderCredentials(\n params: ProbeModelProviderCredentialsParams,\n): Promise<void> {\n const entry = getModelProviderEntry(params.providerId);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(params.providerId);\n }\n\n const model = getModels(params.providerId).find((candidate) => candidate.id === params.model);\n if (!model) throw new InvalidAgentModelError('pi', params.providerId, params.model);\n\n const secretField = entry.credential_fields.find((field) => field.secret);\n if (!secretField) throw new ModelProviderValidationUnavailableError(params.providerId);\n const apiKey = credentialValue(params, secretField.key);\n\n const context: Context = {\n messages: [\n {\n role: 'user',\n content: 'Reply with OK.',\n timestamp: Date.now(),\n },\n ],\n };\n const options: ProviderStreamOptions = {\n apiKey,\n maxTokens: PROBE_MAX_TOKENS,\n maxRetries: 0,\n timeoutMs: config.AGENT_PROVIDER_VALIDATION_TIMEOUT_MS,\n ...modelProviderCredentialOptions(params),\n ...(params.signal ? {signal: params.signal} : {}),\n };\n\n const result = await complete(model, context, options);\n rejectModelProviderErrorResult(result);\n}\n\nexport async function probeCustomModelProviderCredentials(\n params: ProbeCustomModelProviderCredentialsParams,\n): Promise<void> {\n const response = await fetch(customProbeUrl(params), {\n method: 'POST',\n headers: customProbeHeaders(params),\n body: JSON.stringify(customProbeBody(params)),\n redirect: 'error',\n signal: timeoutSignal(params.signal, config.AGENT_PROVIDER_VALIDATION_TIMEOUT_MS),\n });\n\n try {\n if (!response.ok) {\n throw new Error(`Provider returned HTTP ${response.status}.`);\n }\n } finally {\n await response.body?.cancel();\n }\n}\n\nexport function sanitizeModelProviderError(error: unknown, secrets: string[]): string {\n const message =\n error instanceof Error && error.message.length > 0\n ? error.message\n : 'Provider validation failed.';\n const secretForms = secrets.flatMap((secret) => secretWireForms(secret));\n const redacted = redactSecrets(message, secretForms);\n return redacted.slice(0, MAX_SANITIZED_ERROR_LENGTH);\n}\n\nexport function egressPolicy(): EgressPolicy {\n return {\n allowPrivateNetworks: config.AGENT_CUSTOM_PROVIDER_ALLOW_PRIVATE_NETWORKS,\n hostDenylist: parseEgressHostDenylist(config.AGENT_CUSTOM_PROVIDER_HOST_DENYLIST),\n };\n}\n\nfunction customProbeUrl(params: ProbeCustomModelProviderCredentialsParams): string {\n switch (params.api) {\n case 'anthropic-messages':\n return appendCustomProviderPath(params.baseUrl, 'messages').toString();\n case 'google-generative-ai':\n return appendCustomProviderPath(\n params.baseUrl,\n `models/${encodeURIComponent(params.model.id)}:generateContent`,\n ).toString();\n case 'openai-completions':\n return appendCustomProviderPath(params.baseUrl, 'chat/completions').toString();\n case 'openai-responses':\n return appendCustomProviderPath(params.baseUrl, 'responses').toString();\n default:\n return assertNever(params.api);\n }\n}\n\nfunction customProbeHeaders(params: ProbeCustomModelProviderCredentialsParams): Headers {\n const headers = new Headers(params.headers);\n headers.set('content-type', 'application/json');\n if (!params.apiKey) return headers;\n\n switch (params.api) {\n case 'anthropic-messages':\n headers.set('x-api-key', params.apiKey);\n headers.set('anthropic-version', '2023-06-01');\n break;\n case 'google-generative-ai':\n headers.set('x-goog-api-key', params.apiKey);\n break;\n case 'openai-completions':\n case 'openai-responses':\n headers.set('authorization', `Bearer ${params.apiKey}`);\n break;\n default:\n assertNever(params.api);\n }\n\n return headers;\n}\n\nfunction customProbeBody(params: ProbeCustomModelProviderCredentialsParams): unknown {\n switch (params.api) {\n case 'anthropic-messages':\n return {\n model: params.model.id,\n max_tokens: PROBE_MAX_TOKENS,\n messages: [{role: 'user', content: CUSTOM_PROBE_PROMPT}],\n };\n case 'google-generative-ai':\n return {\n contents: [{role: 'user', parts: [{text: CUSTOM_PROBE_PROMPT}]}],\n generationConfig: {maxOutputTokens: PROBE_MAX_TOKENS},\n };\n case 'openai-completions':\n return {\n model: params.model.id,\n messages: [{role: 'user', content: CUSTOM_PROBE_PROMPT}],\n max_tokens: PROBE_MAX_TOKENS,\n stream: false,\n };\n case 'openai-responses':\n return {\n model: params.model.id,\n input: CUSTOM_PROBE_PROMPT,\n max_output_tokens: PROBE_MAX_TOKENS,\n stream: false,\n store: false,\n };\n default:\n return assertNever(params.api);\n }\n}\n\nfunction assertNever(value: never): never {\n throw new Error(`Unsupported custom model provider API: ${value}`);\n}\n\nfunction timeoutSignal(signal: AbortSignal | undefined, timeoutMs: number): AbortSignal {\n return signal === undefined\n ? AbortSignal.timeout(timeoutMs)\n : AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]);\n}\n\nfunction modelProviderCredentialOptions(\n params: Pick<ProbeModelProviderCredentialsParams, 'providerId' | 'credentials'>,\n): ProviderStreamOptions {\n switch (params.providerId) {\n case 'azure-openai-responses':\n return {azureBaseUrl: credentialValue(params, 'endpoint')};\n case 'cloudflare-ai-gateway':\n return {\n env: {\n CLOUDFLARE_ACCOUNT_ID: credentialValue(params, 'account_id'),\n CLOUDFLARE_GATEWAY_ID: credentialValue(params, 'gateway_id'),\n },\n };\n case 'cloudflare-workers-ai':\n return {\n env: {\n CLOUDFLARE_ACCOUNT_ID: credentialValue(params, 'account_id'),\n },\n };\n default:\n return {};\n }\n}\n\nfunction credentialValue(\n params: Pick<ProbeModelProviderCredentialsParams, 'providerId' | 'credentials'>,\n key: string,\n): string {\n const value = params.credentials[key];\n if (value === undefined) throw new InvalidCredentialFieldsError(params.providerId);\n return value;\n}\n\nfunction rejectModelProviderErrorResult(result: AssistantMessage): void {\n if (result.stopReason !== 'error' && result.stopReason !== 'aborted') return;\n throw new Error(result.errorMessage ?? 'Provider validation failed.');\n}\n"],"names":["complete","getModels","getModelProviderEntry","parseEgressHostDenylist","redactSecrets","secretWireForms","config","modelProviderValidationCount","appendCustomProviderPath","InvalidAgentModelError","InvalidCredentialFieldsError","ModelProviderValidationError","ModelProviderValidationUnavailableError","UnsupportedModelProviderError","PROBE_MAX_TOKENS","MAX_SANITIZED_ERROR_LENGTH","CUSTOM_PROBE_PROMPT","runProviderProbe","params","probe","args","error","signal","aborted","add","model_provider","metricLabel","outcome","sanitizedMessage","sanitizeModelProviderError","secrets","providerId","probeModelProviderCredentials","entry","undefined","support_status","model","find","candidate","id","secretField","credential_fields","field","secret","apiKey","credentialValue","key","context","messages","role","content","timestamp","Date","now","options","maxTokens","maxRetries","timeoutMs","AGENT_PROVIDER_VALIDATION_TIMEOUT_MS","modelProviderCredentialOptions","result","rejectModelProviderErrorResult","probeCustomModelProviderCredentials","response","fetch","customProbeUrl","method","headers","customProbeHeaders","body","JSON","stringify","customProbeBody","redirect","timeoutSignal","ok","Error","status","cancel","message","length","secretForms","flatMap","redacted","slice","egressPolicy","allowPrivateNetworks","AGENT_CUSTOM_PROVIDER_ALLOW_PRIVATE_NETWORKS","hostDenylist","AGENT_CUSTOM_PROVIDER_HOST_DENYLIST","api","baseUrl","toString","encodeURIComponent","assertNever","Headers","set","max_tokens","contents","parts","text","generationConfig","maxOutputTokens","stream","input","max_output_tokens","store","value","AbortSignal","timeout","any","azureBaseUrl","env","CLOUDFLARE_ACCOUNT_ID","CLOUDFLARE_GATEWAY_ID","credentials","stopReason","errorMessage"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/core/model-provider-validation.ts"],"sourcesContent":["import {\n type AssistantMessage,\n type Context,\n complete,\n getModels,\n type ProviderStreamOptions,\n} from '@earendil-works/pi-ai';\nimport type {\n CustomAgentModelDto,\n ModelProviderApi,\n ModelProviderRef,\n SupportedModelProviderId,\n} from '@shipfox/api-agent-dto';\nimport {type EgressPolicy, parseEgressHostDenylist} from '@shipfox/node-egress-guard';\nimport {redactSecrets, secretWireForms} from '@shipfox/redact';\nimport {config} from '#config.js';\nimport {modelProviderValidationCount} from '#metrics/index.js';\nimport {appendCustomProviderPath} from './custom-provider-url.js';\nimport {\n InvalidAgentModelError,\n InvalidCredentialFieldsError,\n ModelProviderValidationError,\n ModelProviderValidationUnavailableError,\n UnsupportedModelProviderError,\n} from './errors.js';\nimport {getModelProviderEntry} from './model-provider-policy.js';\n\nconst PROBE_MAX_TOKENS = 64;\nconst MAX_SANITIZED_ERROR_LENGTH = 500;\nconst CUSTOM_PROBE_PROMPT = 'Reply with OK.';\n\nexport interface ProbeModelProviderCredentialsParams {\n providerId: SupportedModelProviderId;\n model: string;\n credentials: Record<string, string>;\n signal?: AbortSignal | undefined;\n}\n\nexport interface ProbeCustomModelProviderCredentialsParams {\n providerId: ModelProviderRef;\n api: ModelProviderApi;\n baseUrl: string;\n model: CustomAgentModelDto;\n apiKey?: string | undefined;\n headers?: Record<string, string> | undefined;\n signal?: AbortSignal | undefined;\n}\n\nexport interface RunProviderProbeParams<TArgs> {\n probe: (args: TArgs) => Promise<void>;\n args: TArgs;\n metricLabel: SupportedModelProviderId | 'custom';\n providerId: ModelProviderRef;\n secrets: string[];\n signal?: AbortSignal | undefined;\n}\n\nexport async function runProviderProbe<TArgs>(\n params: RunProviderProbeParams<TArgs>,\n): Promise<void> {\n try {\n await params.probe(params.args);\n } catch (error) {\n if (params.signal?.aborted) throw error;\n modelProviderValidationCount.add(1, {\n model_provider: params.metricLabel,\n outcome: 'failed',\n });\n if (error instanceof InvalidAgentModelError) throw error;\n\n const sanitizedMessage = sanitizeModelProviderError(error, params.secrets);\n throw new ModelProviderValidationError(params.providerId, sanitizedMessage);\n }\n\n modelProviderValidationCount.add(1, {\n model_provider: params.metricLabel,\n outcome: 'succeeded',\n });\n}\n\nexport async function probeModelProviderCredentials(\n params: ProbeModelProviderCredentialsParams,\n): Promise<void> {\n const entry = getModelProviderEntry(params.providerId);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(params.providerId);\n }\n\n const model = getModels(params.providerId).find((candidate) => candidate.id === params.model);\n if (!model) throw new InvalidAgentModelError('pi', params.providerId, params.model);\n\n const secretField = entry.credential_fields.find((field) => field.secret);\n if (!secretField) throw new ModelProviderValidationUnavailableError(params.providerId);\n const apiKey = credentialValue(params, secretField.key);\n\n const context: Context = {\n messages: [\n {\n role: 'user',\n content: 'Reply with OK.',\n timestamp: Date.now(),\n },\n ],\n };\n const options: ProviderStreamOptions = {\n apiKey,\n maxTokens: PROBE_MAX_TOKENS,\n maxRetries: 0,\n timeoutMs: config.AGENT_PROVIDER_VALIDATION_TIMEOUT_MS,\n ...modelProviderCredentialOptions(params),\n ...(params.signal ? {signal: params.signal} : {}),\n };\n\n const result = await complete(model, context, options);\n rejectModelProviderErrorResult(result);\n}\n\nexport async function probeCustomModelProviderCredentials(\n params: ProbeCustomModelProviderCredentialsParams,\n): Promise<void> {\n const response = await fetch(customProbeUrl(params), {\n method: 'POST',\n headers: customProbeHeaders(params),\n body: JSON.stringify(customProbeBody(params)),\n redirect: 'error',\n signal: timeoutSignal(params.signal, config.AGENT_PROVIDER_VALIDATION_TIMEOUT_MS),\n });\n\n try {\n if (!response.ok) {\n throw new Error(`Provider returned HTTP ${response.status}.`);\n }\n } finally {\n await response.body?.cancel();\n }\n}\n\nexport function sanitizeModelProviderError(error: unknown, secrets: string[]): string {\n const message =\n error instanceof Error && error.message.length > 0\n ? error.message\n : 'Provider validation failed.';\n const secretForms = secrets.flatMap((secret) => secretWireForms(secret));\n const redacted = redactSecrets(message, secretForms);\n return redacted.slice(0, MAX_SANITIZED_ERROR_LENGTH);\n}\n\nexport function egressPolicy(): EgressPolicy {\n return {\n allowPrivateNetworks: config.AGENT_CUSTOM_PROVIDER_ALLOW_PRIVATE_NETWORKS,\n hostDenylist: parseEgressHostDenylist(config.AGENT_CUSTOM_PROVIDER_HOST_DENYLIST),\n };\n}\n\nfunction customProbeUrl(params: ProbeCustomModelProviderCredentialsParams): string {\n switch (params.api) {\n case 'anthropic-messages':\n return appendCustomProviderPath(params.baseUrl, 'messages').toString();\n case 'google-generative-ai':\n return appendCustomProviderPath(\n params.baseUrl,\n `models/${encodeURIComponent(params.model.id)}:generateContent`,\n ).toString();\n case 'openai-completions':\n return appendCustomProviderPath(params.baseUrl, 'chat/completions').toString();\n case 'openai-responses':\n return appendCustomProviderPath(params.baseUrl, 'responses').toString();\n default:\n return assertNever(params.api);\n }\n}\n\nfunction customProbeHeaders(params: ProbeCustomModelProviderCredentialsParams): Headers {\n const headers = new Headers(params.headers);\n headers.set('content-type', 'application/json');\n if (!params.apiKey) return headers;\n\n switch (params.api) {\n case 'anthropic-messages':\n headers.set('x-api-key', params.apiKey);\n headers.set('anthropic-version', '2023-06-01');\n break;\n case 'google-generative-ai':\n headers.set('x-goog-api-key', params.apiKey);\n break;\n case 'openai-completions':\n case 'openai-responses':\n headers.set('authorization', `Bearer ${params.apiKey}`);\n break;\n default:\n assertNever(params.api);\n }\n\n return headers;\n}\n\nfunction customProbeBody(params: ProbeCustomModelProviderCredentialsParams): unknown {\n switch (params.api) {\n case 'anthropic-messages':\n return {\n model: params.model.id,\n max_tokens: PROBE_MAX_TOKENS,\n messages: [{role: 'user', content: CUSTOM_PROBE_PROMPT}],\n };\n case 'google-generative-ai':\n return {\n contents: [{role: 'user', parts: [{text: CUSTOM_PROBE_PROMPT}]}],\n generationConfig: {maxOutputTokens: PROBE_MAX_TOKENS},\n };\n case 'openai-completions':\n return {\n model: params.model.id,\n messages: [{role: 'user', content: CUSTOM_PROBE_PROMPT}],\n max_tokens: PROBE_MAX_TOKENS,\n stream: false,\n };\n case 'openai-responses':\n return {\n model: params.model.id,\n input: CUSTOM_PROBE_PROMPT,\n max_output_tokens: PROBE_MAX_TOKENS,\n stream: false,\n store: false,\n };\n default:\n return assertNever(params.api);\n }\n}\n\nfunction assertNever(value: never): never {\n throw new Error(`Unsupported custom model provider API: ${value}`);\n}\n\nfunction timeoutSignal(signal: AbortSignal | undefined, timeoutMs: number): AbortSignal {\n return signal === undefined\n ? AbortSignal.timeout(timeoutMs)\n : AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]);\n}\n\nfunction modelProviderCredentialOptions(\n params: Pick<ProbeModelProviderCredentialsParams, 'providerId' | 'credentials'>,\n): ProviderStreamOptions {\n switch (params.providerId) {\n case 'azure-openai-responses':\n return {azureBaseUrl: credentialValue(params, 'endpoint')};\n case 'cloudflare-ai-gateway':\n return {\n env: {\n CLOUDFLARE_ACCOUNT_ID: credentialValue(params, 'account_id'),\n CLOUDFLARE_GATEWAY_ID: credentialValue(params, 'gateway_id'),\n },\n };\n case 'cloudflare-workers-ai':\n return {\n env: {\n CLOUDFLARE_ACCOUNT_ID: credentialValue(params, 'account_id'),\n },\n };\n default:\n return {};\n }\n}\n\nfunction credentialValue(\n params: Pick<ProbeModelProviderCredentialsParams, 'providerId' | 'credentials'>,\n key: string,\n): string {\n const value = params.credentials[key];\n if (value === undefined) throw new InvalidCredentialFieldsError(params.providerId);\n return value;\n}\n\nfunction rejectModelProviderErrorResult(result: AssistantMessage): void {\n if (result.stopReason !== 'error' && result.stopReason !== 'aborted') return;\n throw new Error(result.errorMessage ?? 'Provider validation failed.');\n}\n"],"names":["complete","getModels","parseEgressHostDenylist","redactSecrets","secretWireForms","config","modelProviderValidationCount","appendCustomProviderPath","InvalidAgentModelError","InvalidCredentialFieldsError","ModelProviderValidationError","ModelProviderValidationUnavailableError","UnsupportedModelProviderError","getModelProviderEntry","PROBE_MAX_TOKENS","MAX_SANITIZED_ERROR_LENGTH","CUSTOM_PROBE_PROMPT","runProviderProbe","params","probe","args","error","signal","aborted","add","model_provider","metricLabel","outcome","sanitizedMessage","sanitizeModelProviderError","secrets","providerId","probeModelProviderCredentials","entry","undefined","support_status","model","find","candidate","id","secretField","credential_fields","field","secret","apiKey","credentialValue","key","context","messages","role","content","timestamp","Date","now","options","maxTokens","maxRetries","timeoutMs","AGENT_PROVIDER_VALIDATION_TIMEOUT_MS","modelProviderCredentialOptions","result","rejectModelProviderErrorResult","probeCustomModelProviderCredentials","response","fetch","customProbeUrl","method","headers","customProbeHeaders","body","JSON","stringify","customProbeBody","redirect","timeoutSignal","ok","Error","status","cancel","message","length","secretForms","flatMap","redacted","slice","egressPolicy","allowPrivateNetworks","AGENT_CUSTOM_PROVIDER_ALLOW_PRIVATE_NETWORKS","hostDenylist","AGENT_CUSTOM_PROVIDER_HOST_DENYLIST","api","baseUrl","toString","encodeURIComponent","assertNever","Headers","set","max_tokens","contents","parts","text","generationConfig","maxOutputTokens","stream","input","max_output_tokens","store","value","AbortSignal","timeout","any","azureBaseUrl","env","CLOUDFLARE_ACCOUNT_ID","CLOUDFLARE_GATEWAY_ID","credentials","stopReason","errorMessage"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-agent-config.d.ts","sourceRoot":"","sources":["../../src/core/resolve-agent-config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,mBAAmB,EAIxB,KAAK,OAAO,EACZ,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC9B,MAAM,wBAAwB,CAAC;AAShC,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;CAClC;AAED,MAAM,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,qBAAqB,KAAK,mBAAmB,CAAC;AAEzF,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;IAChE,QAAQ,CAAC,0BAA0B,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,CAAC;IAC1E,QAAQ,CAAC,wBAAwB,CAAC,EAAE,WAAW,CAAC,gBAAgB,EAAE,yBAAyB,CAAC,CAAC;IAC7F,QAAQ,CAAC,uBAAuB,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IACxE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnD,QAAQ,CAAC,uBAAuB,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CAC9D;AAED,UAAU,yBAAyB;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,mBAAmB,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;CACrE;AAID,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,qBAAqB,EAC3B,GAAG,GAAE,4BAAiC,GACrC,mBAAmB,CAcrB;AAED,eAAO,MAAM,2BAA2B,EAAE,qBAChB,CAAC"}
1
+ {"version":3,"file":"resolve-agent-config.d.ts","sourceRoot":"","sources":["../../src/core/resolve-agent-config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,mBAAmB,EAGxB,KAAK,OAAO,EACZ,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC9B,MAAM,wBAAwB,CAAC;AAUhC,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;CAClC;AAED,MAAM,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,qBAAqB,KAAK,mBAAmB,CAAC;AAEzF,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;IAChE,QAAQ,CAAC,0BAA0B,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,CAAC;IAC1E,QAAQ,CAAC,wBAAwB,CAAC,EAAE,WAAW,CAAC,gBAAgB,EAAE,yBAAyB,CAAC,CAAC;IAC7F,QAAQ,CAAC,uBAAuB,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IACxE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnD,QAAQ,CAAC,uBAAuB,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CAC9D;AAED,UAAU,yBAAyB;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,mBAAmB,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;CACrE;AAID,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,qBAAqB,EAC3B,GAAG,GAAE,4BAAiC,GACrC,mBAAmB,CAcrB;AAED,eAAO,MAAM,2BAA2B,EAAE,qBAChB,CAAC"}
@@ -1,6 +1,7 @@
1
- import { agentThinkingByHarness, DEFAULT_HARNESS, getHarnessDescriptor, getModelProviderEntry } from '@shipfox/api-agent-dto';
1
+ import { agentThinkingByHarness, DEFAULT_HARNESS, getHarnessDescriptor } from '@shipfox/api-agent-dto';
2
2
  import { InvalidAgentModelError, UnsupportedHarnessProviderError, UnsupportedHarnessThinkingError, UnsupportedModelProviderError } from './errors.js';
3
3
  import { listHarnessProviderModels } from './harness/index.js';
4
+ import { getModelProviderEntry } from './model-provider-policy.js';
4
5
  export function resolveAgentConfig(step, ctx = {}) {
5
6
  const harness = step.harness ?? ctx.workspaceDefaultHarnessId ?? DEFAULT_HARNESS;
6
7
  const provider = resolveProvider(step, ctx, harness);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/resolve-agent-config.ts"],"sourcesContent":["import {\n type AgentThinking,\n agentThinkingByHarness,\n type CustomAgentModelDto,\n DEFAULT_HARNESS,\n getHarnessDescriptor,\n getModelProviderEntry,\n type Harness,\n type ModelProviderRef,\n type SupportedModelProviderId,\n} from '@shipfox/api-agent-dto';\nimport {\n InvalidAgentModelError,\n UnsupportedHarnessProviderError,\n UnsupportedHarnessThinkingError,\n UnsupportedModelProviderError,\n} from './errors.js';\nimport {listHarnessProviderModels} from './harness/index.js';\n\nexport interface ContextualAgentConfig {\n readonly harness?: Harness | undefined;\n readonly provider?: string | undefined;\n readonly model?: string | undefined;\n readonly thinking?: AgentThinking | undefined;\n}\n\nexport interface ResolvedAgentConfig {\n readonly harness: Harness;\n readonly provider: ModelProviderRef;\n readonly model: string;\n readonly thinking: AgentThinking;\n}\n\nexport type AgentDefaultsResolver = (step: ContextualAgentConfig) => ResolvedAgentConfig;\n\nexport interface AgentConfigResolutionContext {\n readonly workspaceDefaultHarnessId?: Harness | null | undefined;\n readonly workspaceDefaultProviderId?: ModelProviderRef | null | undefined;\n readonly workspaceProviderConfigs?: ReadonlyMap<ModelProviderRef, WorkspaceProviderDefaults>;\n readonly instanceDefaultProvider?: SupportedModelProviderId | undefined;\n readonly instanceDefaultModel?: string | undefined;\n readonly instanceDefaultThinking?: AgentThinking | undefined;\n}\n\ninterface WorkspaceProviderDefaults {\n readonly kind?: 'builtin' | 'custom' | undefined;\n readonly defaultModel: string | null;\n readonly defaultThinking: AgentThinking;\n readonly models?: readonly CustomAgentModelDto[] | null | undefined;\n}\n\ntype ModelCandidateResolver = () => string | null | undefined;\n\nexport function resolveAgentConfig(\n step: ContextualAgentConfig,\n ctx: AgentConfigResolutionContext = {},\n): ResolvedAgentConfig {\n const harness = step.harness ?? ctx.workspaceDefaultHarnessId ?? DEFAULT_HARNESS;\n const provider = resolveProvider(step, ctx, harness);\n const workspaceProviderConfig = ctx.workspaceProviderConfigs?.get(provider);\n const model = resolveModel({\n step,\n ctx,\n harness,\n provider,\n workspaceProviderConfig,\n });\n const thinking = resolveThinking({step, ctx, harness, provider, workspaceProviderConfig});\n\n return {harness, provider, model, thinking};\n}\n\nexport const catalogDefaultAgentResolver: AgentDefaultsResolver = (step) =>\n resolveAgentConfig(step);\n\nfunction resolveProvider(\n step: ContextualAgentConfig,\n ctx: AgentConfigResolutionContext,\n harness: Harness,\n): ModelProviderRef {\n const descriptor = getHarnessDescriptor(harness);\n if (step.provider !== undefined) {\n const provider = resolveSupportedProvider(step.provider, ctx);\n if (!isHarnessCompatible(harness, provider, ctx.workspaceProviderConfigs?.get(provider))) {\n throw new UnsupportedHarnessProviderError(\n harness,\n step.provider,\n descriptor.supportedProviderIds,\n );\n }\n return provider;\n }\n\n const candidates = [\n ctx.workspaceDefaultProviderId,\n ctx.instanceDefaultProvider,\n descriptor.defaultProviderId,\n ];\n for (const candidate of candidates) {\n if (candidate === undefined || candidate === null) continue;\n\n const workspaceProviderConfig = ctx.workspaceProviderConfigs?.get(candidate);\n if (!isHarnessCompatible(harness, candidate, workspaceProviderConfig)) continue;\n\n return resolveSupportedProvider(candidate, ctx);\n }\n\n return descriptor.defaultProviderId;\n}\n\nfunction resolveSupportedProvider(\n provider: string,\n ctx: AgentConfigResolutionContext,\n): ModelProviderRef {\n const workspaceProviderConfig = ctx.workspaceProviderConfigs?.get(provider);\n if (workspaceProviderConfig?.kind === 'custom') return provider;\n\n const entry = getModelProviderEntry(provider);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(provider);\n }\n return provider as SupportedModelProviderId;\n}\n\nfunction resolveModel(params: {\n step: ContextualAgentConfig;\n ctx: AgentConfigResolutionContext;\n harness: Harness;\n provider: ModelProviderRef;\n workspaceProviderConfig: WorkspaceProviderDefaults | undefined;\n}): string {\n if (params.step.model !== undefined) {\n validateModel(\n params.harness,\n params.provider,\n params.step.model,\n params.workspaceProviderConfig,\n );\n return params.step.model;\n }\n\n const candidates: ModelCandidateResolver[] = [() => params.workspaceProviderConfig?.defaultModel];\n if (params.workspaceProviderConfig?.kind === 'custom') {\n candidates.push(() => customDefaultModel(params.workspaceProviderConfig));\n } else {\n candidates.push(\n () => instanceDefaultModel(params.provider, params.ctx),\n () => catalogDefaultModel(params.harness, params.provider),\n );\n }\n\n for (const resolveCandidate of candidates) {\n const candidate = resolveCandidate();\n if (candidate === undefined || candidate === null) continue;\n if (\n modelIsAvailable(params.harness, params.provider, candidate, params.workspaceProviderConfig)\n ) {\n return candidate;\n }\n }\n\n throw new InvalidAgentModelError(params.harness, params.provider, '');\n}\n\nfunction catalogDefaultModel(harness: Harness, provider: ModelProviderRef): string {\n const catalogModels = listProviderModels(harness, provider);\n const entry = getModelProviderEntry(provider);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(provider);\n }\n if (\n entry.default_model !== null &&\n catalogModels.some((candidate) => candidate.id === entry.default_model)\n ) {\n return entry.default_model;\n }\n\n const firstModel = catalogModels[0];\n if (firstModel === undefined) throw new InvalidAgentModelError(harness, provider, '');\n return firstModel.id;\n}\n\nfunction instanceDefaultModel(\n provider: ModelProviderRef,\n ctx: AgentConfigResolutionContext,\n): string | undefined {\n return provider === ctx.instanceDefaultProvider ? ctx.instanceDefaultModel : undefined;\n}\n\nfunction instanceDefaultThinking(\n provider: ModelProviderRef,\n ctx: AgentConfigResolutionContext,\n): AgentThinking | undefined {\n return provider === ctx.instanceDefaultProvider ? ctx.instanceDefaultThinking : undefined;\n}\n\nfunction customDefaultModel(\n workspaceProviderConfig: WorkspaceProviderDefaults | undefined,\n): string | undefined {\n if (workspaceProviderConfig?.kind !== 'custom') return undefined;\n return workspaceProviderConfig.models?.[0]?.id;\n}\n\nfunction validateModel(\n harness: Harness,\n provider: ModelProviderRef,\n model: string,\n workspaceProviderConfig: WorkspaceProviderDefaults | undefined,\n): void {\n if (modelIsAvailable(harness, provider, model, workspaceProviderConfig)) return;\n throw new InvalidAgentModelError(harness, provider, model);\n}\n\nfunction modelIsAvailable(\n harness: Harness,\n provider: ModelProviderRef,\n model: string,\n workspaceProviderConfig: WorkspaceProviderDefaults | undefined,\n): boolean {\n if (workspaceProviderConfig?.kind === 'custom') {\n return workspaceProviderConfig.models?.some((candidate) => candidate.id === model) ?? false;\n }\n\n return listProviderModels(harness, provider).some((candidate) => candidate.id === model);\n}\n\nfunction listProviderModels(harness: Harness, provider: ModelProviderRef): readonly {id: string}[] {\n return listHarnessProviderModels(harness, provider);\n}\n\nfunction isHarnessCompatible(\n harness: Harness,\n provider: ModelProviderRef,\n workspaceProviderConfig: WorkspaceProviderDefaults | undefined,\n): boolean {\n if (workspaceProviderConfig?.kind === 'custom') return harness === 'pi';\n\n return getHarnessDescriptor(harness).supportedProviderIds.includes(provider);\n}\n\nfunction resolveThinking(params: {\n step: ContextualAgentConfig;\n ctx: AgentConfigResolutionContext;\n harness: Harness;\n provider: ModelProviderRef;\n workspaceProviderConfig: WorkspaceProviderDefaults | undefined;\n}): AgentThinking {\n const thinkingSchema = agentThinkingByHarness[params.harness];\n const descriptor = getHarnessDescriptor(params.harness);\n\n if (params.step.thinking !== undefined) {\n if (!thinkingSchema.safeParse(params.step.thinking).success) {\n throw new UnsupportedHarnessThinkingError(\n params.harness,\n params.step.thinking,\n descriptor.thinkingLevels,\n );\n }\n return params.step.thinking;\n }\n\n const candidates = [\n params.workspaceProviderConfig?.defaultThinking,\n instanceDefaultThinking(params.provider, params.ctx),\n descriptor.defaultThinking,\n ];\n for (const candidate of candidates) {\n if (candidate !== undefined && thinkingSchema.safeParse(candidate).success) return candidate;\n }\n\n return descriptor.defaultThinking;\n}\n"],"names":["agentThinkingByHarness","DEFAULT_HARNESS","getHarnessDescriptor","getModelProviderEntry","InvalidAgentModelError","UnsupportedHarnessProviderError","UnsupportedHarnessThinkingError","UnsupportedModelProviderError","listHarnessProviderModels","resolveAgentConfig","step","ctx","harness","workspaceDefaultHarnessId","provider","resolveProvider","workspaceProviderConfig","workspaceProviderConfigs","get","model","resolveModel","thinking","resolveThinking","catalogDefaultAgentResolver","descriptor","undefined","resolveSupportedProvider","isHarnessCompatible","supportedProviderIds","candidates","workspaceDefaultProviderId","instanceDefaultProvider","defaultProviderId","candidate","kind","entry","support_status","params","validateModel","defaultModel","push","customDefaultModel","instanceDefaultModel","catalogDefaultModel","resolveCandidate","modelIsAvailable","catalogModels","listProviderModels","default_model","some","id","firstModel","instanceDefaultThinking","models","includes","thinkingSchema","safeParse","success","thinkingLevels","defaultThinking"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/core/resolve-agent-config.ts"],"sourcesContent":["import {\n type AgentThinking,\n agentThinkingByHarness,\n type CustomAgentModelDto,\n DEFAULT_HARNESS,\n getHarnessDescriptor,\n type Harness,\n type ModelProviderRef,\n type SupportedModelProviderId,\n} from '@shipfox/api-agent-dto';\nimport {\n InvalidAgentModelError,\n UnsupportedHarnessProviderError,\n UnsupportedHarnessThinkingError,\n UnsupportedModelProviderError,\n} from './errors.js';\nimport {listHarnessProviderModels} from './harness/index.js';\nimport {getModelProviderEntry} from './model-provider-policy.js';\n\nexport interface ContextualAgentConfig {\n readonly harness?: Harness | undefined;\n readonly provider?: string | undefined;\n readonly model?: string | undefined;\n readonly thinking?: AgentThinking | undefined;\n}\n\nexport interface ResolvedAgentConfig {\n readonly harness: Harness;\n readonly provider: ModelProviderRef;\n readonly model: string;\n readonly thinking: AgentThinking;\n}\n\nexport type AgentDefaultsResolver = (step: ContextualAgentConfig) => ResolvedAgentConfig;\n\nexport interface AgentConfigResolutionContext {\n readonly workspaceDefaultHarnessId?: Harness | null | undefined;\n readonly workspaceDefaultProviderId?: ModelProviderRef | null | undefined;\n readonly workspaceProviderConfigs?: ReadonlyMap<ModelProviderRef, WorkspaceProviderDefaults>;\n readonly instanceDefaultProvider?: SupportedModelProviderId | undefined;\n readonly instanceDefaultModel?: string | undefined;\n readonly instanceDefaultThinking?: AgentThinking | undefined;\n}\n\ninterface WorkspaceProviderDefaults {\n readonly kind?: 'builtin' | 'custom' | undefined;\n readonly defaultModel: string | null;\n readonly defaultThinking: AgentThinking;\n readonly models?: readonly CustomAgentModelDto[] | null | undefined;\n}\n\ntype ModelCandidateResolver = () => string | null | undefined;\n\nexport function resolveAgentConfig(\n step: ContextualAgentConfig,\n ctx: AgentConfigResolutionContext = {},\n): ResolvedAgentConfig {\n const harness = step.harness ?? ctx.workspaceDefaultHarnessId ?? DEFAULT_HARNESS;\n const provider = resolveProvider(step, ctx, harness);\n const workspaceProviderConfig = ctx.workspaceProviderConfigs?.get(provider);\n const model = resolveModel({\n step,\n ctx,\n harness,\n provider,\n workspaceProviderConfig,\n });\n const thinking = resolveThinking({step, ctx, harness, provider, workspaceProviderConfig});\n\n return {harness, provider, model, thinking};\n}\n\nexport const catalogDefaultAgentResolver: AgentDefaultsResolver = (step) =>\n resolveAgentConfig(step);\n\nfunction resolveProvider(\n step: ContextualAgentConfig,\n ctx: AgentConfigResolutionContext,\n harness: Harness,\n): ModelProviderRef {\n const descriptor = getHarnessDescriptor(harness);\n if (step.provider !== undefined) {\n const provider = resolveSupportedProvider(step.provider, ctx);\n if (!isHarnessCompatible(harness, provider, ctx.workspaceProviderConfigs?.get(provider))) {\n throw new UnsupportedHarnessProviderError(\n harness,\n step.provider,\n descriptor.supportedProviderIds,\n );\n }\n return provider;\n }\n\n const candidates = [\n ctx.workspaceDefaultProviderId,\n ctx.instanceDefaultProvider,\n descriptor.defaultProviderId,\n ];\n for (const candidate of candidates) {\n if (candidate === undefined || candidate === null) continue;\n\n const workspaceProviderConfig = ctx.workspaceProviderConfigs?.get(candidate);\n if (!isHarnessCompatible(harness, candidate, workspaceProviderConfig)) continue;\n\n return resolveSupportedProvider(candidate, ctx);\n }\n\n return descriptor.defaultProviderId;\n}\n\nfunction resolveSupportedProvider(\n provider: string,\n ctx: AgentConfigResolutionContext,\n): ModelProviderRef {\n const workspaceProviderConfig = ctx.workspaceProviderConfigs?.get(provider);\n if (workspaceProviderConfig?.kind === 'custom') return provider;\n\n const entry = getModelProviderEntry(provider);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(provider);\n }\n return provider as SupportedModelProviderId;\n}\n\nfunction resolveModel(params: {\n step: ContextualAgentConfig;\n ctx: AgentConfigResolutionContext;\n harness: Harness;\n provider: ModelProviderRef;\n workspaceProviderConfig: WorkspaceProviderDefaults | undefined;\n}): string {\n if (params.step.model !== undefined) {\n validateModel(\n params.harness,\n params.provider,\n params.step.model,\n params.workspaceProviderConfig,\n );\n return params.step.model;\n }\n\n const candidates: ModelCandidateResolver[] = [() => params.workspaceProviderConfig?.defaultModel];\n if (params.workspaceProviderConfig?.kind === 'custom') {\n candidates.push(() => customDefaultModel(params.workspaceProviderConfig));\n } else {\n candidates.push(\n () => instanceDefaultModel(params.provider, params.ctx),\n () => catalogDefaultModel(params.harness, params.provider),\n );\n }\n\n for (const resolveCandidate of candidates) {\n const candidate = resolveCandidate();\n if (candidate === undefined || candidate === null) continue;\n if (\n modelIsAvailable(params.harness, params.provider, candidate, params.workspaceProviderConfig)\n ) {\n return candidate;\n }\n }\n\n throw new InvalidAgentModelError(params.harness, params.provider, '');\n}\n\nfunction catalogDefaultModel(harness: Harness, provider: ModelProviderRef): string {\n const catalogModels = listProviderModels(harness, provider);\n const entry = getModelProviderEntry(provider);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(provider);\n }\n if (\n entry.default_model !== null &&\n catalogModels.some((candidate) => candidate.id === entry.default_model)\n ) {\n return entry.default_model;\n }\n\n const firstModel = catalogModels[0];\n if (firstModel === undefined) throw new InvalidAgentModelError(harness, provider, '');\n return firstModel.id;\n}\n\nfunction instanceDefaultModel(\n provider: ModelProviderRef,\n ctx: AgentConfigResolutionContext,\n): string | undefined {\n return provider === ctx.instanceDefaultProvider ? ctx.instanceDefaultModel : undefined;\n}\n\nfunction instanceDefaultThinking(\n provider: ModelProviderRef,\n ctx: AgentConfigResolutionContext,\n): AgentThinking | undefined {\n return provider === ctx.instanceDefaultProvider ? ctx.instanceDefaultThinking : undefined;\n}\n\nfunction customDefaultModel(\n workspaceProviderConfig: WorkspaceProviderDefaults | undefined,\n): string | undefined {\n if (workspaceProviderConfig?.kind !== 'custom') return undefined;\n return workspaceProviderConfig.models?.[0]?.id;\n}\n\nfunction validateModel(\n harness: Harness,\n provider: ModelProviderRef,\n model: string,\n workspaceProviderConfig: WorkspaceProviderDefaults | undefined,\n): void {\n if (modelIsAvailable(harness, provider, model, workspaceProviderConfig)) return;\n throw new InvalidAgentModelError(harness, provider, model);\n}\n\nfunction modelIsAvailable(\n harness: Harness,\n provider: ModelProviderRef,\n model: string,\n workspaceProviderConfig: WorkspaceProviderDefaults | undefined,\n): boolean {\n if (workspaceProviderConfig?.kind === 'custom') {\n return workspaceProviderConfig.models?.some((candidate) => candidate.id === model) ?? false;\n }\n\n return listProviderModels(harness, provider).some((candidate) => candidate.id === model);\n}\n\nfunction listProviderModels(harness: Harness, provider: ModelProviderRef): readonly {id: string}[] {\n return listHarnessProviderModels(harness, provider);\n}\n\nfunction isHarnessCompatible(\n harness: Harness,\n provider: ModelProviderRef,\n workspaceProviderConfig: WorkspaceProviderDefaults | undefined,\n): boolean {\n if (workspaceProviderConfig?.kind === 'custom') return harness === 'pi';\n\n return getHarnessDescriptor(harness).supportedProviderIds.includes(provider);\n}\n\nfunction resolveThinking(params: {\n step: ContextualAgentConfig;\n ctx: AgentConfigResolutionContext;\n harness: Harness;\n provider: ModelProviderRef;\n workspaceProviderConfig: WorkspaceProviderDefaults | undefined;\n}): AgentThinking {\n const thinkingSchema = agentThinkingByHarness[params.harness];\n const descriptor = getHarnessDescriptor(params.harness);\n\n if (params.step.thinking !== undefined) {\n if (!thinkingSchema.safeParse(params.step.thinking).success) {\n throw new UnsupportedHarnessThinkingError(\n params.harness,\n params.step.thinking,\n descriptor.thinkingLevels,\n );\n }\n return params.step.thinking;\n }\n\n const candidates = [\n params.workspaceProviderConfig?.defaultThinking,\n instanceDefaultThinking(params.provider, params.ctx),\n descriptor.defaultThinking,\n ];\n for (const candidate of candidates) {\n if (candidate !== undefined && thinkingSchema.safeParse(candidate).success) return candidate;\n }\n\n return descriptor.defaultThinking;\n}\n"],"names":["agentThinkingByHarness","DEFAULT_HARNESS","getHarnessDescriptor","InvalidAgentModelError","UnsupportedHarnessProviderError","UnsupportedHarnessThinkingError","UnsupportedModelProviderError","listHarnessProviderModels","getModelProviderEntry","resolveAgentConfig","step","ctx","harness","workspaceDefaultHarnessId","provider","resolveProvider","workspaceProviderConfig","workspaceProviderConfigs","get","model","resolveModel","thinking","resolveThinking","catalogDefaultAgentResolver","descriptor","undefined","resolveSupportedProvider","isHarnessCompatible","supportedProviderIds","candidates","workspaceDefaultProviderId","instanceDefaultProvider","defaultProviderId","candidate","kind","entry","support_status","params","validateModel","defaultModel","push","customDefaultModel","instanceDefaultModel","catalogDefaultModel","resolveCandidate","modelIsAvailable","catalogModels","listProviderModels","default_model","some","id","firstModel","instanceDefaultThinking","models","includes","thinkingSchema","safeParse","success","thinkingLevels","defaultThinking"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { type AgentRuntimeCredentialsResponseDto, type AgentThinking, type Harness, type ModelProviderRef, type SupportedModelProviderId } from '@shipfox/api-agent-dto';
1
+ import type { AgentRuntimeCredentialsResponseDto, AgentThinking, Harness, ModelProviderRef, SupportedModelProviderId } from '@shipfox/api-agent-dto';
2
2
  import { type AgentSecretsClient } from './secrets-client.js';
3
3
  export interface ResolveRuntimeCredentialsParams {
4
4
  workspaceId: string;
@@ -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;AAahC,OAAO,EAAC,KAAK,kBAAkB,EAA4B,MAAM,qBAAqB,CAAC;AAEvF,MAAM,WAAW,+BAA+B;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;CACzB;AAED,UAAU,wBAAwB;IAChC,sBAAsB,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAC9D,8BAA8B,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrD;AAED,UAAU,gCAAgC;IACxC,aAAa,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IACrD,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACzC,gBAAgB,CAAC,EACb,CAAC,CAAC,MAAM,EAAE;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GACvF,SAAS,CAAC;CACf;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,+BAA+B,EACvC,OAAO,CAAC,EAAE,gCAAgC,GACzC,OAAO,CAAC,kCAAkC,CAAC,CA0D7C;AAED,wBAAgB,0CAA0C,CACxD,UAAU,EAAE,gBAAgB,GAC3B,SAAS,GAAG,SAAS,CAQvB"}
1
+ {"version":3,"file":"resolve-runtime-credentials.d.ts","sourceRoot":"","sources":["../../src/core/resolve-runtime-credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kCAAkC,EAClC,aAAa,EACb,OAAO,EACP,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,wBAAwB,CAAC;AAchC,OAAO,EAAC,KAAK,kBAAkB,EAA4B,MAAM,qBAAqB,CAAC;AAEvF,MAAM,WAAW,+BAA+B;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;CACzB;AAED,UAAU,wBAAwB;IAChC,sBAAsB,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAC9D,8BAA8B,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrD;AAED,UAAU,gCAAgC;IACxC,aAAa,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IACrD,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACzC,gBAAgB,CAAC,EACb,CAAC,CAAC,MAAM,EAAE;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GACvF,SAAS,CAAC;CACf;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,+BAA+B,EACvC,OAAO,CAAC,EAAE,gCAAgC,GACzC,OAAO,CAAC,kCAAkC,CAAC,CA0D7C;AAED,wBAAgB,0CAA0C,CACxD,UAAU,EAAE,gBAAgB,GAC3B,SAAS,GAAG,SAAS,CAQvB"}
@@ -1,4 +1,3 @@
1
- import { getModelProviderEntry, modelProviderCredentialKeysMatch } from '@shipfox/api-agent-dto';
2
1
  import { secretsInterModuleContract } from '@shipfox/api-secrets-dto/inter-module';
3
2
  import { isInterModuleKnownError } from '@shipfox/inter-module';
4
3
  import { config } from '#config.js';
@@ -6,6 +5,7 @@ import { getModelProviderConfig } from '#db/index.js';
6
5
  import { agentRuntimeConfigResolvedCount } from '#metrics/index.js';
7
6
  import { agentSystemNamespace, storeValuesToCustomRuntimeCredentials, storeValuesToRuntimeCredentials } from './credential-fingerprints.js';
8
7
  import { ModelProviderConfigNotFoundError } from './errors.js';
8
+ import { getModelProviderEntry, modelProviderCredentialKeysMatch } from './model-provider-policy.js';
9
9
  import { requireAgentSecretsClient } from './secrets-client.js';
10
10
  export async function resolveRuntimeCredentials(params, options) {
11
11
  const runtimeConfig = options?.runtimeConfig ?? config;