@shipfox/api-agent 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -0
- package/.turbo/turbo-type$colon$emit.log +1 -0
- package/.turbo/turbo-type.log +1 -0
- package/CHANGELOG.md +105 -0
- package/LICENSE +21 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +60 -0
- package/dist/config.js.map +1 -0
- package/dist/core/credential-fingerprints.d.ts +10 -0
- package/dist/core/credential-fingerprints.d.ts.map +1 -0
- package/dist/core/credential-fingerprints.js +65 -0
- package/dist/core/credential-fingerprints.js.map +1 -0
- package/dist/core/custom-model-provider-config-service.d.ts +26 -0
- package/dist/core/custom-model-provider-config-service.d.ts.map +1 -0
- package/dist/core/custom-model-provider-config-service.js +390 -0
- package/dist/core/custom-model-provider-config-service.js.map +1 -0
- package/dist/core/custom-provider-url.d.ts +4 -0
- package/dist/core/custom-provider-url.d.ts.map +1 -0
- package/dist/core/custom-provider-url.js +23 -0
- package/dist/core/custom-provider-url.js.map +1 -0
- package/dist/core/discover-custom-model-provider-models.d.ts +3 -0
- package/dist/core/discover-custom-model-provider-models.d.ts.map +1 -0
- package/dist/core/discover-custom-model-provider-models.js +122 -0
- package/dist/core/discover-custom-model-provider-models.js.map +1 -0
- package/dist/core/entities/agent-workspace-settings.d.ts +9 -0
- package/dist/core/entities/agent-workspace-settings.d.ts.map +1 -0
- package/dist/core/entities/agent-workspace-settings.js +3 -0
- package/dist/core/entities/agent-workspace-settings.js.map +1 -0
- package/dist/core/entities/model-provider-config.d.ts +19 -0
- package/dist/core/entities/model-provider-config.d.ts.map +1 -0
- package/dist/core/entities/model-provider-config.js +3 -0
- package/dist/core/entities/model-provider-config.js.map +1 -0
- package/dist/core/errors.d.ts +62 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +80 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/harness/claude.d.ts +6 -0
- package/dist/core/harness/claude.d.ts.map +1 -0
- package/dist/core/harness/claude.js +104 -0
- package/dist/core/harness/claude.js.map +1 -0
- package/dist/core/harness/index.d.ts +4 -0
- package/dist/core/harness/index.d.ts.map +1 -0
- package/dist/core/harness/index.js +5 -0
- package/dist/core/harness/index.js.map +1 -0
- package/dist/core/harness/pi.d.ts +6 -0
- package/dist/core/harness/pi.d.ts.map +1 -0
- package/dist/core/harness/pi.js +16 -0
- package/dist/core/harness/pi.js.map +1 -0
- package/dist/core/harness/registry.d.ts +22 -0
- package/dist/core/harness/registry.d.ts.map +1 -0
- package/dist/core/harness/registry.js +46 -0
- package/dist/core/harness/registry.js.map +1 -0
- package/dist/core/index.d.ts +12 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +11 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/model-provider-catalog.d.ts +3 -0
- package/dist/core/model-provider-catalog.d.ts.map +1 -0
- package/dist/core/model-provider-catalog.js +25 -0
- package/dist/core/model-provider-catalog.js.map +1 -0
- package/dist/core/model-provider-config-service.d.ts +32 -0
- package/dist/core/model-provider-config-service.d.ts.map +1 -0
- package/dist/core/model-provider-config-service.js +133 -0
- package/dist/core/model-provider-config-service.js.map +1 -0
- package/dist/core/model-provider-validation.d.ts +31 -0
- package/dist/core/model-provider-validation.d.ts.map +1 -0
- package/dist/core/model-provider-validation.js +220 -0
- package/dist/core/model-provider-validation.js.map +1 -0
- package/dist/core/resolve-agent-config.d.ts +32 -0
- package/dist/core/resolve-agent-config.d.ts.map +1 -0
- package/dist/core/resolve-agent-config.js +143 -0
- package/dist/core/resolve-agent-config.js.map +1 -0
- package/dist/core/resolve-runtime-credentials.d.ts +21 -0
- package/dist/core/resolve-runtime-credentials.d.ts.map +1 -0
- package/dist/core/resolve-runtime-credentials.js +101 -0
- package/dist/core/resolve-runtime-credentials.js.map +1 -0
- package/dist/core/workspace-agent-defaults-resolver.d.ts +3 -0
- package/dist/core/workspace-agent-defaults-resolver.d.ts.map +1 -0
- package/dist/core/workspace-agent-defaults-resolver.js +26 -0
- package/dist/core/workspace-agent-defaults-resolver.js.map +1 -0
- package/dist/db/agent-defaults-snapshot.d.ts +9 -0
- package/dist/db/agent-defaults-snapshot.d.ts.map +1 -0
- package/dist/db/agent-defaults-snapshot.js +24 -0
- package/dist/db/agent-defaults-snapshot.js.map +1 -0
- package/dist/db/agent-workspace-settings.d.ts +12 -0
- package/dist/db/agent-workspace-settings.d.ts.map +1 -0
- package/dist/db/agent-workspace-settings.js +53 -0
- package/dist/db/agent-workspace-settings.js.map +1 -0
- package/dist/db/db.d.ts +771 -0
- package/dist/db/db.d.ts.map +1 -0
- package/dist/db/db.js +20 -0
- package/dist/db/db.js.map +1 -0
- package/dist/db/index.d.ts +9 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +11 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/model-provider-configs.d.ts +38 -0
- package/dist/db/model-provider-configs.d.ts.map +1 -0
- package/dist/db/model-provider-configs.js +159 -0
- package/dist/db/model-provider-configs.js.map +1 -0
- package/dist/db/schema/agent-workspace-settings.d.ts +97 -0
- package/dist/db/schema/agent-workspace-settings.d.ts.map +1 -0
- package/dist/db/schema/agent-workspace-settings.js +26 -0
- package/dist/db/schema/agent-workspace-settings.js.map +1 -0
- package/dist/db/schema/common.d.ts +2 -0
- package/dist/db/schema/common.d.ts.map +1 -0
- package/dist/db/schema/common.js +4 -0
- package/dist/db/schema/common.js.map +1 -0
- package/dist/db/schema/model-provider-configs.d.ts +296 -0
- package/dist/db/schema/model-provider-configs.d.ts.map +1 -0
- package/dist/db/schema/model-provider-configs.js +52 -0
- package/dist/db/schema/model-provider-configs.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics/index.d.ts +2 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +3 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/instance.d.ts +10 -0
- package/dist/metrics/instance.d.ts.map +1 -0
- package/dist/metrics/instance.js +10 -0
- package/dist/metrics/instance.js.map +1 -0
- package/dist/presentation/dto/index.d.ts +2 -0
- package/dist/presentation/dto/index.d.ts.map +1 -0
- package/dist/presentation/dto/index.js +3 -0
- package/dist/presentation/dto/index.js.map +1 -0
- package/dist/presentation/dto/model-provider-config.d.ts +6 -0
- package/dist/presentation/dto/model-provider-config.d.ts.map +1 -0
- package/dist/presentation/dto/model-provider-config.js +32 -0
- package/dist/presentation/dto/model-provider-config.js.map +1 -0
- package/dist/presentation/e2eRoutes/create-model-provider.d.ts +2 -0
- package/dist/presentation/e2eRoutes/create-model-provider.d.ts.map +1 -0
- package/dist/presentation/e2eRoutes/create-model-provider.js +66 -0
- package/dist/presentation/e2eRoutes/create-model-provider.js.map +1 -0
- package/dist/presentation/e2eRoutes/index.d.ts +3 -0
- package/dist/presentation/e2eRoutes/index.d.ts.map +1 -0
- package/dist/presentation/e2eRoutes/index.js +9 -0
- package/dist/presentation/e2eRoutes/index.js.map +1 -0
- package/dist/presentation/index.d.ts +2 -0
- package/dist/presentation/index.d.ts.map +1 -0
- package/dist/presentation/index.js +3 -0
- package/dist/presentation/index.js.map +1 -0
- package/dist/presentation/routes/create-custom-model-provider.d.ts +2 -0
- package/dist/presentation/routes/create-custom-model-provider.d.ts.map +1 -0
- package/dist/presentation/routes/create-custom-model-provider.js +45 -0
- package/dist/presentation/routes/create-custom-model-provider.js.map +1 -0
- package/dist/presentation/routes/delete-model-provider-config.d.ts +2 -0
- package/dist/presentation/routes/delete-model-provider-config.d.ts.map +1 -0
- package/dist/presentation/routes/delete-model-provider-config.js +38 -0
- package/dist/presentation/routes/delete-model-provider-config.js.map +1 -0
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.d.ts +2 -0
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.d.ts.map +1 -0
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.js +37 -0
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.js.map +1 -0
- package/dist/presentation/routes/discover-custom-model-provider-models.d.ts +2 -0
- package/dist/presentation/routes/discover-custom-model-provider-models.d.ts.map +1 -0
- package/dist/presentation/routes/discover-custom-model-provider-models.js +31 -0
- package/dist/presentation/routes/discover-custom-model-provider-models.js.map +1 -0
- package/dist/presentation/routes/errors.d.ts +2 -0
- package/dist/presentation/routes/errors.d.ts.map +1 -0
- package/dist/presentation/routes/errors.js +112 -0
- package/dist/presentation/routes/errors.js.map +1 -0
- package/dist/presentation/routes/index.d.ts +3 -0
- package/dist/presentation/routes/index.d.ts.map +1 -0
- package/dist/presentation/routes/index.js +39 -0
- package/dist/presentation/routes/index.js.map +1 -0
- package/dist/presentation/routes/list-model-provider-catalog.d.ts +2 -0
- package/dist/presentation/routes/list-model-provider-catalog.d.ts.map +1 -0
- package/dist/presentation/routes/list-model-provider-catalog.js +18 -0
- package/dist/presentation/routes/list-model-provider-catalog.js.map +1 -0
- package/dist/presentation/routes/list-model-provider-configs.d.ts +2 -0
- package/dist/presentation/routes/list-model-provider-configs.d.ts.map +1 -0
- package/dist/presentation/routes/list-model-provider-configs.js +37 -0
- package/dist/presentation/routes/list-model-provider-configs.js.map +1 -0
- package/dist/presentation/routes/set-default-harness.d.ts +2 -0
- package/dist/presentation/routes/set-default-harness.d.ts.map +1 -0
- package/dist/presentation/routes/set-default-harness.js +38 -0
- package/dist/presentation/routes/set-default-harness.js.map +1 -0
- package/dist/presentation/routes/set-default-model-provider.d.ts +2 -0
- package/dist/presentation/routes/set-default-model-provider.d.ts.map +1 -0
- package/dist/presentation/routes/set-default-model-provider.js +48 -0
- package/dist/presentation/routes/set-default-model-provider.js.map +1 -0
- package/dist/presentation/routes/update-custom-model-provider.d.ts +2 -0
- package/dist/presentation/routes/update-custom-model-provider.d.ts.map +1 -0
- package/dist/presentation/routes/update-custom-model-provider.js +47 -0
- package/dist/presentation/routes/update-custom-model-provider.js.map +1 -0
- package/dist/presentation/routes/update-model-provider-default-model.d.ts +2 -0
- package/dist/presentation/routes/update-model-provider-default-model.d.ts.map +1 -0
- package/dist/presentation/routes/update-model-provider-default-model.js +38 -0
- package/dist/presentation/routes/update-model-provider-default-model.js.map +1 -0
- package/dist/presentation/routes/upsert-model-provider-config.d.ts +2 -0
- package/dist/presentation/routes/upsert-model-provider-config.d.ts.map +1 -0
- package/dist/presentation/routes/upsert-model-provider-config.js +52 -0
- package/dist/presentation/routes/upsert-model-provider-config.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -0
- package/drizzle/0000_daffy_leopardon.sql +28 -0
- package/drizzle/0001_default_harness.sql +1 -0
- package/drizzle/meta/0000_snapshot.json +199 -0
- package/drizzle/meta/0001_snapshot.json +205 -0
- package/drizzle/meta/_journal.json +20 -0
- package/drizzle.config.ts +7 -0
- package/package.json +109 -0
- package/src/config.test.ts +118 -0
- package/src/config.ts +75 -0
- package/src/core/catalog-registry.test.ts +48 -0
- package/src/core/credential-fingerprints.test.ts +34 -0
- package/src/core/credential-fingerprints.ts +84 -0
- package/src/core/custom-model-provider-config-service.ts +537 -0
- package/src/core/custom-provider-url.ts +24 -0
- package/src/core/discover-custom-model-provider-models.ts +147 -0
- package/src/core/entities/agent-workspace-settings.ts +9 -0
- package/src/core/entities/model-provider-config.ts +25 -0
- package/src/core/errors.ts +139 -0
- package/src/core/harness/claude.ts +75 -0
- package/src/core/harness/index.ts +19 -0
- package/src/core/harness/pi.ts +18 -0
- package/src/core/harness/registry.test.ts +281 -0
- package/src/core/harness/registry.ts +108 -0
- package/src/core/index.ts +56 -0
- package/src/core/model-provider-catalog.ts +33 -0
- package/src/core/model-provider-config-service.test.ts +940 -0
- package/src/core/model-provider-config-service.ts +207 -0
- package/src/core/model-provider-validation.test.ts +354 -0
- package/src/core/model-provider-validation.ts +276 -0
- package/src/core/resolve-agent-config.test.ts +441 -0
- package/src/core/resolve-agent-config.ts +272 -0
- package/src/core/resolve-runtime-credentials.test.ts +316 -0
- package/src/core/resolve-runtime-credentials.ts +147 -0
- package/src/core/workspace-agent-defaults-resolver.ts +42 -0
- package/src/db/agent-defaults-snapshot.ts +49 -0
- package/src/db/agent-workspace-settings.test.ts +111 -0
- package/src/db/agent-workspace-settings.ts +92 -0
- package/src/db/db.ts +20 -0
- package/src/db/index.ts +29 -0
- package/src/db/model-provider-configs.test.ts +281 -0
- package/src/db/model-provider-configs.ts +230 -0
- package/src/db/schema/agent-workspace-settings.ts +27 -0
- package/src/db/schema/common.ts +3 -0
- package/src/db/schema/model-provider-configs.ts +80 -0
- package/src/index.ts +43 -0
- package/src/metrics/index.ts +1 -0
- package/src/metrics/instance.ts +18 -0
- package/src/presentation/dto/index.ts +5 -0
- package/src/presentation/dto/model-provider-config.ts +41 -0
- package/src/presentation/e2eRoutes/create-model-provider.test.ts +47 -0
- package/src/presentation/e2eRoutes/create-model-provider.ts +61 -0
- package/src/presentation/e2eRoutes/index.ts +7 -0
- package/src/presentation/index.ts +1 -0
- package/src/presentation/routes/create-custom-model-provider.ts +45 -0
- package/src/presentation/routes/delete-model-provider-config.ts +31 -0
- package/src/presentation/routes/discover-custom-model-provider-models-by-slug.ts +42 -0
- package/src/presentation/routes/discover-custom-model-provider-models.ts +29 -0
- package/src/presentation/routes/errors.ts +122 -0
- package/src/presentation/routes/index.ts +37 -0
- package/src/presentation/routes/list-model-provider-catalog.ts +15 -0
- package/src/presentation/routes/list-model-provider-configs.ts +33 -0
- package/src/presentation/routes/model-provider-catalog.test.ts +73 -0
- package/src/presentation/routes/model-provider-config.test.ts +807 -0
- package/src/presentation/routes/set-default-harness.ts +33 -0
- package/src/presentation/routes/set-default-model-provider.ts +47 -0
- package/src/presentation/routes/update-custom-model-provider.ts +50 -0
- package/src/presentation/routes/update-model-provider-default-model.ts +40 -0
- package/src/presentation/routes/upsert-model-provider-config.ts +53 -0
- package/test/env.ts +8 -0
- package/test/globalSetup.ts +25 -0
- package/test/setup.ts +17 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +3 -0
- package/tsconfig.test.json +8 -0
- package/vitest.config.ts +11 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ModelProviderRef, type SupportedModelProviderId } from '@shipfox/api-agent-dto';
|
|
2
|
+
import type { ModelProviderConfig } from './entities/model-provider-config.js';
|
|
3
|
+
import { probeModelProviderCredentials } from './model-provider-validation.js';
|
|
4
|
+
export interface TestAndSaveModelProviderConfigParams {
|
|
5
|
+
workspaceId: string;
|
|
6
|
+
providerId: SupportedModelProviderId;
|
|
7
|
+
defaultModel?: string | null | undefined;
|
|
8
|
+
credentials: Record<string, string>;
|
|
9
|
+
editedBy?: string | null | undefined;
|
|
10
|
+
setAsDefault?: boolean | undefined;
|
|
11
|
+
signal?: AbortSignal | undefined;
|
|
12
|
+
}
|
|
13
|
+
export interface TestAndSaveModelProviderConfigOptions {
|
|
14
|
+
probe?: typeof probeModelProviderCredentials;
|
|
15
|
+
pruneStaleSecrets?: ((params: {
|
|
16
|
+
workspaceId: string;
|
|
17
|
+
namespace: string;
|
|
18
|
+
expectedKeys: string[];
|
|
19
|
+
}) => Promise<void>) | undefined;
|
|
20
|
+
}
|
|
21
|
+
export interface UpdateModelProviderConfigDefaultModelParams {
|
|
22
|
+
workspaceId: string;
|
|
23
|
+
providerId: ModelProviderRef;
|
|
24
|
+
defaultModel: string | null;
|
|
25
|
+
}
|
|
26
|
+
export declare function testAndSaveModelProviderConfig(params: TestAndSaveModelProviderConfigParams, options?: TestAndSaveModelProviderConfigOptions): Promise<ModelProviderConfig>;
|
|
27
|
+
export declare function updateModelProviderConfigDefaultModel(params: UpdateModelProviderConfigDefaultModelParams): Promise<ModelProviderConfig>;
|
|
28
|
+
export declare function deleteModelProviderConfig(params: {
|
|
29
|
+
workspaceId: string;
|
|
30
|
+
providerId: ModelProviderRef;
|
|
31
|
+
}): Promise<boolean>;
|
|
32
|
+
//# sourceMappingURL=model-provider-config-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-provider-config-service.d.ts","sourceRoot":"","sources":["../../src/core/model-provider-config-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gBAAgB,EAErB,KAAK,wBAAwB,EAC9B,MAAM,wBAAwB,CAAC;AAShC,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,qCAAqC,CAAC;AAQ7E,OAAO,EAAC,6BAA6B,EAAmB,MAAM,gCAAgC,CAAC;AAE/F,MAAM,WAAW,oCAAoC;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,wBAAwB,CAAC;IACrC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACrC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,qCAAqC;IACpD,KAAK,CAAC,EAAE,OAAO,6BAA6B,CAAC;IAC7C,iBAAiB,CAAC,EACd,CAAC,CAAC,MAAM,EAAE;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,EAAE,CAAA;KAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GAC7F,SAAS,CAAC;CACf;AAED,MAAM,WAAW,2CAA2C;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,oCAAoC,EAC5C,OAAO,GAAE,qCAA0C,GAClD,OAAO,CAAC,mBAAmB,CAAC,CA2D9B;AAED,wBAAsB,qCAAqC,CACzD,MAAM,EAAE,2CAA2C,GAClD,OAAO,CAAC,mBAAmB,CAAC,CAwC9B;AAED,wBAAsB,yBAAyB,CAAC,MAAM,EAAE;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,gBAAgB,CAAC;CAC9B,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnB"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { DEFAULT_AGENT_THINKING, getModelProviderEntry, modelProviderCredentialKeysMatch } from '@shipfox/api-agent-dto';
|
|
2
|
+
import { deleteSecrets, getSecretsByNamespace, setSecrets } from '@shipfox/api-secrets';
|
|
3
|
+
import { deleteModelProviderConfig as deleteModelProviderConfigRow, getModelProviderConfig, updateModelProviderDefaultModel, upsertModelProviderConfig } from '#db/index.js';
|
|
4
|
+
import { agentSystemNamespace, credentialsToStoreValues } from './credential-fingerprints.js';
|
|
5
|
+
import { InvalidAgentModelError, InvalidCredentialFieldsError, ModelProviderConfigNotFoundError, UnsupportedModelProviderError } from './errors.js';
|
|
6
|
+
import { buildModelProviderCatalog } from './model-provider-catalog.js';
|
|
7
|
+
import { probeModelProviderCredentials, runProviderProbe } from './model-provider-validation.js';
|
|
8
|
+
export async function testAndSaveModelProviderConfig(params, options = {}) {
|
|
9
|
+
const probe = options.probe ?? probeModelProviderCredentials;
|
|
10
|
+
const entry = getModelProviderEntry(params.providerId);
|
|
11
|
+
if (entry === undefined || entry.support_status !== 'supported') {
|
|
12
|
+
throw new UnsupportedModelProviderError(params.providerId);
|
|
13
|
+
}
|
|
14
|
+
if (entry.default_model === null) throw new UnsupportedModelProviderError(params.providerId);
|
|
15
|
+
if (!modelProviderCredentialKeysMatch(params.providerId, params.credentials)) {
|
|
16
|
+
throw new InvalidCredentialFieldsError(params.providerId);
|
|
17
|
+
}
|
|
18
|
+
const existingConfig = await getModelProviderConfig({
|
|
19
|
+
workspaceId: params.workspaceId,
|
|
20
|
+
providerId: params.providerId
|
|
21
|
+
});
|
|
22
|
+
const modelSelection = resolveDefaultModel(params.providerId, params.defaultModel !== undefined ? params.defaultModel : existingConfig?.defaultModel);
|
|
23
|
+
await runProviderProbe({
|
|
24
|
+
probe,
|
|
25
|
+
args: {
|
|
26
|
+
providerId: params.providerId,
|
|
27
|
+
model: modelSelection.probeModel,
|
|
28
|
+
credentials: params.credentials,
|
|
29
|
+
...params.signal ? {
|
|
30
|
+
signal: params.signal
|
|
31
|
+
} : {}
|
|
32
|
+
},
|
|
33
|
+
metricLabel: params.providerId,
|
|
34
|
+
providerId: params.providerId,
|
|
35
|
+
secrets: Object.values(params.credentials),
|
|
36
|
+
signal: params.signal
|
|
37
|
+
});
|
|
38
|
+
const pruneStaleSecrets = options.pruneStaleSecrets ?? pruneStaleProviderCredentialSecrets;
|
|
39
|
+
const namespace = agentSystemNamespace(params.providerId);
|
|
40
|
+
const values = credentialsToStoreValues(params.providerId, params.credentials);
|
|
41
|
+
await setSecrets({
|
|
42
|
+
workspaceId: params.workspaceId,
|
|
43
|
+
namespace,
|
|
44
|
+
values,
|
|
45
|
+
editedBy: params.editedBy
|
|
46
|
+
});
|
|
47
|
+
const config = await upsertModelProviderConfig({
|
|
48
|
+
workspaceId: params.workspaceId,
|
|
49
|
+
providerId: params.providerId,
|
|
50
|
+
defaultModel: modelSelection.storedModel,
|
|
51
|
+
defaultThinking: DEFAULT_AGENT_THINKING,
|
|
52
|
+
setAsDefault: params.setAsDefault
|
|
53
|
+
});
|
|
54
|
+
await pruneStaleSecrets({
|
|
55
|
+
workspaceId: params.workspaceId,
|
|
56
|
+
namespace,
|
|
57
|
+
expectedKeys: Object.keys(values)
|
|
58
|
+
}).catch(()=>undefined);
|
|
59
|
+
return config;
|
|
60
|
+
}
|
|
61
|
+
export async function updateModelProviderConfigDefaultModel(params) {
|
|
62
|
+
const existingConfig = await getModelProviderConfig({
|
|
63
|
+
workspaceId: params.workspaceId,
|
|
64
|
+
providerId: params.providerId
|
|
65
|
+
});
|
|
66
|
+
if (!existingConfig) {
|
|
67
|
+
throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);
|
|
68
|
+
}
|
|
69
|
+
if (existingConfig.kind === 'custom') {
|
|
70
|
+
if (params.defaultModel !== null && !existingConfig.models?.some((model)=>model.id === params.defaultModel)) {
|
|
71
|
+
throw new InvalidAgentModelError('pi', params.providerId, params.defaultModel);
|
|
72
|
+
}
|
|
73
|
+
const config = await updateModelProviderDefaultModel({
|
|
74
|
+
workspaceId: params.workspaceId,
|
|
75
|
+
providerId: params.providerId,
|
|
76
|
+
defaultModel: params.defaultModel
|
|
77
|
+
});
|
|
78
|
+
if (!config) throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);
|
|
79
|
+
return config;
|
|
80
|
+
}
|
|
81
|
+
const providerId = params.providerId;
|
|
82
|
+
const entry = getModelProviderEntry(providerId);
|
|
83
|
+
if (entry === undefined || entry.support_status !== 'supported') {
|
|
84
|
+
throw new UnsupportedModelProviderError(params.providerId);
|
|
85
|
+
}
|
|
86
|
+
if (entry.default_model === null) throw new UnsupportedModelProviderError(params.providerId);
|
|
87
|
+
const modelSelection = resolveDefaultModel(providerId, params.defaultModel);
|
|
88
|
+
const config = await updateModelProviderDefaultModel({
|
|
89
|
+
workspaceId: params.workspaceId,
|
|
90
|
+
providerId: params.providerId,
|
|
91
|
+
defaultModel: modelSelection.storedModel
|
|
92
|
+
});
|
|
93
|
+
if (!config) throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);
|
|
94
|
+
return config;
|
|
95
|
+
}
|
|
96
|
+
export async function deleteModelProviderConfig(params) {
|
|
97
|
+
const deleted = await deleteModelProviderConfigRow(params);
|
|
98
|
+
await deleteSecrets({
|
|
99
|
+
workspaceId: params.workspaceId,
|
|
100
|
+
namespace: agentSystemNamespace(params.providerId)
|
|
101
|
+
});
|
|
102
|
+
return deleted;
|
|
103
|
+
}
|
|
104
|
+
function resolveDefaultModel(providerId, requestedModel) {
|
|
105
|
+
const catalogEntry = buildModelProviderCatalog().find((entry)=>entry.id === providerId);
|
|
106
|
+
if (catalogEntry === undefined || catalogEntry.support_status !== 'supported' || catalogEntry.default_model === null) {
|
|
107
|
+
throw new UnsupportedModelProviderError(providerId);
|
|
108
|
+
}
|
|
109
|
+
const model = requestedModel ?? catalogEntry.default_model;
|
|
110
|
+
if (!catalogEntry.models.some((candidate)=>candidate.id === model)) {
|
|
111
|
+
throw new InvalidAgentModelError('pi', providerId, model);
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
probeModel: model,
|
|
115
|
+
storedModel: requestedModel ?? null
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
async function pruneStaleProviderCredentialSecrets(params) {
|
|
119
|
+
const stored = await getSecretsByNamespace({
|
|
120
|
+
workspaceId: params.workspaceId,
|
|
121
|
+
namespace: params.namespace
|
|
122
|
+
});
|
|
123
|
+
const expected = new Set(params.expectedKeys);
|
|
124
|
+
const staleKeys = Object.keys(stored).filter((key)=>!expected.has(key));
|
|
125
|
+
if (staleKeys.length === 0) return;
|
|
126
|
+
await deleteSecrets({
|
|
127
|
+
workspaceId: params.workspaceId,
|
|
128
|
+
namespace: params.namespace,
|
|
129
|
+
keys: staleKeys
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//# sourceMappingURL=model-provider-config-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/model-provider-config-service.ts"],"sourcesContent":["import {\n DEFAULT_AGENT_THINKING,\n getModelProviderEntry,\n type ModelProviderRef,\n modelProviderCredentialKeysMatch,\n type SupportedModelProviderId,\n} from '@shipfox/api-agent-dto';\nimport {deleteSecrets, getSecretsByNamespace, setSecrets} from '@shipfox/api-secrets';\nimport {\n deleteModelProviderConfig as deleteModelProviderConfigRow,\n getModelProviderConfig,\n updateModelProviderDefaultModel,\n upsertModelProviderConfig,\n} from '#db/index.js';\nimport {agentSystemNamespace, credentialsToStoreValues} from './credential-fingerprints.js';\nimport type {ModelProviderConfig} from './entities/model-provider-config.js';\nimport {\n InvalidAgentModelError,\n InvalidCredentialFieldsError,\n ModelProviderConfigNotFoundError,\n UnsupportedModelProviderError,\n} from './errors.js';\nimport {buildModelProviderCatalog} from './model-provider-catalog.js';\nimport {probeModelProviderCredentials, runProviderProbe} from './model-provider-validation.js';\n\nexport interface TestAndSaveModelProviderConfigParams {\n workspaceId: string;\n providerId: SupportedModelProviderId;\n defaultModel?: string | null | undefined;\n credentials: Record<string, string>;\n editedBy?: string | null | undefined;\n setAsDefault?: boolean | undefined;\n signal?: AbortSignal | undefined;\n}\n\nexport interface TestAndSaveModelProviderConfigOptions {\n probe?: typeof probeModelProviderCredentials;\n pruneStaleSecrets?:\n | ((params: {workspaceId: string; namespace: string; expectedKeys: string[]}) => Promise<void>)\n | undefined;\n}\n\nexport interface UpdateModelProviderConfigDefaultModelParams {\n workspaceId: string;\n providerId: ModelProviderRef;\n defaultModel: string | null;\n}\n\nexport async function testAndSaveModelProviderConfig(\n params: TestAndSaveModelProviderConfigParams,\n options: TestAndSaveModelProviderConfigOptions = {},\n): Promise<ModelProviderConfig> {\n const probe = options.probe ?? probeModelProviderCredentials;\n const entry = getModelProviderEntry(params.providerId);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(params.providerId);\n }\n if (entry.default_model === null) throw new UnsupportedModelProviderError(params.providerId);\n\n if (!modelProviderCredentialKeysMatch(params.providerId, params.credentials)) {\n throw new InvalidCredentialFieldsError(params.providerId);\n }\n\n const existingConfig = await getModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n });\n const modelSelection = resolveDefaultModel(\n params.providerId,\n params.defaultModel !== undefined ? params.defaultModel : existingConfig?.defaultModel,\n );\n\n await runProviderProbe({\n probe,\n args: {\n providerId: params.providerId,\n model: modelSelection.probeModel,\n credentials: params.credentials,\n ...(params.signal ? {signal: params.signal} : {}),\n },\n metricLabel: params.providerId,\n providerId: params.providerId,\n secrets: Object.values(params.credentials),\n signal: params.signal,\n });\n const pruneStaleSecrets = options.pruneStaleSecrets ?? pruneStaleProviderCredentialSecrets;\n const namespace = agentSystemNamespace(params.providerId);\n const values = credentialsToStoreValues(params.providerId, params.credentials);\n await setSecrets({\n workspaceId: params.workspaceId,\n namespace,\n values,\n editedBy: params.editedBy,\n });\n\n const config = await upsertModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n defaultModel: modelSelection.storedModel,\n defaultThinking: DEFAULT_AGENT_THINKING,\n setAsDefault: params.setAsDefault,\n });\n\n await pruneStaleSecrets({\n workspaceId: params.workspaceId,\n namespace,\n expectedKeys: Object.keys(values),\n }).catch(() => undefined);\n\n return config;\n}\n\nexport async function updateModelProviderConfigDefaultModel(\n params: UpdateModelProviderConfigDefaultModelParams,\n): Promise<ModelProviderConfig> {\n const existingConfig = await getModelProviderConfig({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n });\n if (!existingConfig) {\n throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);\n }\n if (existingConfig.kind === 'custom') {\n if (\n params.defaultModel !== null &&\n !existingConfig.models?.some((model) => model.id === params.defaultModel)\n ) {\n throw new InvalidAgentModelError('pi', params.providerId, params.defaultModel);\n }\n\n const config = await updateModelProviderDefaultModel({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n defaultModel: params.defaultModel,\n });\n if (!config) throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);\n return config;\n }\n\n const providerId = params.providerId as SupportedModelProviderId;\n const entry = getModelProviderEntry(providerId);\n if (entry === undefined || entry.support_status !== 'supported') {\n throw new UnsupportedModelProviderError(params.providerId);\n }\n if (entry.default_model === null) throw new UnsupportedModelProviderError(params.providerId);\n\n const modelSelection = resolveDefaultModel(providerId, params.defaultModel);\n const config = await updateModelProviderDefaultModel({\n workspaceId: params.workspaceId,\n providerId: params.providerId,\n defaultModel: modelSelection.storedModel,\n });\n if (!config) throw new ModelProviderConfigNotFoundError(params.workspaceId, params.providerId);\n return config;\n}\n\nexport async function deleteModelProviderConfig(params: {\n workspaceId: string;\n providerId: ModelProviderRef;\n}): Promise<boolean> {\n const deleted = await deleteModelProviderConfigRow(params);\n await deleteSecrets({\n workspaceId: params.workspaceId,\n namespace: agentSystemNamespace(params.providerId),\n });\n return deleted;\n}\n\nfunction resolveDefaultModel(\n providerId: SupportedModelProviderId,\n requestedModel: string | null | undefined,\n): {probeModel: string; storedModel: string | null} {\n const catalogEntry = buildModelProviderCatalog().find((entry) => entry.id === providerId);\n if (\n catalogEntry === undefined ||\n catalogEntry.support_status !== 'supported' ||\n catalogEntry.default_model === null\n ) {\n throw new UnsupportedModelProviderError(providerId);\n }\n\n const model = requestedModel ?? catalogEntry.default_model;\n if (!catalogEntry.models.some((candidate) => candidate.id === model)) {\n throw new InvalidAgentModelError('pi', providerId, model);\n }\n return {probeModel: model, storedModel: requestedModel ?? null};\n}\n\nasync function pruneStaleProviderCredentialSecrets(params: {\n workspaceId: string;\n namespace: string;\n expectedKeys: string[];\n}): Promise<void> {\n const stored = await getSecretsByNamespace({\n workspaceId: params.workspaceId,\n namespace: params.namespace,\n });\n const expected = new Set(params.expectedKeys);\n const staleKeys = Object.keys(stored).filter((key) => !expected.has(key));\n if (staleKeys.length === 0) return;\n\n await deleteSecrets({\n workspaceId: params.workspaceId,\n namespace: params.namespace,\n keys: staleKeys,\n });\n}\n"],"names":["DEFAULT_AGENT_THINKING","getModelProviderEntry","modelProviderCredentialKeysMatch","deleteSecrets","getSecretsByNamespace","setSecrets","deleteModelProviderConfig","deleteModelProviderConfigRow","getModelProviderConfig","updateModelProviderDefaultModel","upsertModelProviderConfig","agentSystemNamespace","credentialsToStoreValues","InvalidAgentModelError","InvalidCredentialFieldsError","ModelProviderConfigNotFoundError","UnsupportedModelProviderError","buildModelProviderCatalog","probeModelProviderCredentials","runProviderProbe","testAndSaveModelProviderConfig","params","options","probe","entry","providerId","undefined","support_status","default_model","credentials","existingConfig","workspaceId","modelSelection","resolveDefaultModel","defaultModel","args","model","probeModel","signal","metricLabel","secrets","Object","values","pruneStaleSecrets","pruneStaleProviderCredentialSecrets","namespace","editedBy","config","storedModel","defaultThinking","setAsDefault","expectedKeys","keys","catch","updateModelProviderConfigDefaultModel","kind","models","some","id","deleted","requestedModel","catalogEntry","find","candidate","stored","expected","Set","staleKeys","filter","key","has","length"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type CustomAgentModelDto, type ModelProviderApi, type ModelProviderRef, type SupportedModelProviderId } from '@shipfox/api-agent-dto';
|
|
2
|
+
import { type EgressPolicy } from '@shipfox/node-egress-guard';
|
|
3
|
+
export interface ProbeModelProviderCredentialsParams {
|
|
4
|
+
providerId: SupportedModelProviderId;
|
|
5
|
+
model: string;
|
|
6
|
+
credentials: Record<string, string>;
|
|
7
|
+
signal?: AbortSignal | undefined;
|
|
8
|
+
}
|
|
9
|
+
export interface ProbeCustomModelProviderCredentialsParams {
|
|
10
|
+
providerId: ModelProviderRef;
|
|
11
|
+
api: ModelProviderApi;
|
|
12
|
+
baseUrl: string;
|
|
13
|
+
model: CustomAgentModelDto;
|
|
14
|
+
apiKey?: string | undefined;
|
|
15
|
+
headers?: Record<string, string> | undefined;
|
|
16
|
+
signal?: AbortSignal | undefined;
|
|
17
|
+
}
|
|
18
|
+
export interface RunProviderProbeParams<TArgs> {
|
|
19
|
+
probe: (args: TArgs) => Promise<void>;
|
|
20
|
+
args: TArgs;
|
|
21
|
+
metricLabel: SupportedModelProviderId | 'custom';
|
|
22
|
+
providerId: ModelProviderRef;
|
|
23
|
+
secrets: string[];
|
|
24
|
+
signal?: AbortSignal | undefined;
|
|
25
|
+
}
|
|
26
|
+
export declare function runProviderProbe<TArgs>(params: RunProviderProbeParams<TArgs>): Promise<void>;
|
|
27
|
+
export declare function probeModelProviderCredentials(params: ProbeModelProviderCredentialsParams): Promise<void>;
|
|
28
|
+
export declare function probeCustomModelProviderCredentials(params: ProbeCustomModelProviderCredentialsParams): Promise<void>;
|
|
29
|
+
export declare function sanitizeModelProviderError(error: unknown, secrets: string[]): string;
|
|
30
|
+
export declare function egressPolicy(): EgressPolicy;
|
|
31
|
+
//# sourceMappingURL=model-provider-validation.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { complete, getModels } from '@earendil-works/pi-ai';
|
|
2
|
+
import { getModelProviderEntry } from '@shipfox/api-agent-dto';
|
|
3
|
+
import { parseEgressHostDenylist } from '@shipfox/node-egress-guard';
|
|
4
|
+
import { redactSecrets, secretWireForms } from '@shipfox/redact';
|
|
5
|
+
import { config } from '#config.js';
|
|
6
|
+
import { modelProviderValidationCount } from '#metrics/index.js';
|
|
7
|
+
import { appendCustomProviderPath } from './custom-provider-url.js';
|
|
8
|
+
import { InvalidAgentModelError, InvalidCredentialFieldsError, ModelProviderValidationError, ModelProviderValidationUnavailableError, UnsupportedModelProviderError } from './errors.js';
|
|
9
|
+
const PROBE_MAX_TOKENS = 64;
|
|
10
|
+
const MAX_SANITIZED_ERROR_LENGTH = 500;
|
|
11
|
+
const CUSTOM_PROBE_PROMPT = 'Reply with OK.';
|
|
12
|
+
export async function runProviderProbe(params) {
|
|
13
|
+
try {
|
|
14
|
+
await params.probe(params.args);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (params.signal?.aborted) throw error;
|
|
17
|
+
modelProviderValidationCount.add(1, {
|
|
18
|
+
model_provider: params.metricLabel,
|
|
19
|
+
outcome: 'failed'
|
|
20
|
+
});
|
|
21
|
+
if (error instanceof InvalidAgentModelError) throw error;
|
|
22
|
+
const sanitizedMessage = sanitizeModelProviderError(error, params.secrets);
|
|
23
|
+
throw new ModelProviderValidationError(params.providerId, sanitizedMessage);
|
|
24
|
+
}
|
|
25
|
+
modelProviderValidationCount.add(1, {
|
|
26
|
+
model_provider: params.metricLabel,
|
|
27
|
+
outcome: 'succeeded'
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export async function probeModelProviderCredentials(params) {
|
|
31
|
+
const entry = getModelProviderEntry(params.providerId);
|
|
32
|
+
if (entry === undefined || entry.support_status !== 'supported') {
|
|
33
|
+
throw new UnsupportedModelProviderError(params.providerId);
|
|
34
|
+
}
|
|
35
|
+
const model = getModels(params.providerId).find((candidate)=>candidate.id === params.model);
|
|
36
|
+
if (!model) throw new InvalidAgentModelError('pi', params.providerId, params.model);
|
|
37
|
+
const secretField = entry.credential_fields.find((field)=>field.secret);
|
|
38
|
+
if (!secretField) throw new ModelProviderValidationUnavailableError(params.providerId);
|
|
39
|
+
const apiKey = credentialValue(params, secretField.key);
|
|
40
|
+
const context = {
|
|
41
|
+
messages: [
|
|
42
|
+
{
|
|
43
|
+
role: 'user',
|
|
44
|
+
content: 'Reply with OK.',
|
|
45
|
+
timestamp: Date.now()
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
};
|
|
49
|
+
const options = {
|
|
50
|
+
apiKey,
|
|
51
|
+
maxTokens: PROBE_MAX_TOKENS,
|
|
52
|
+
maxRetries: 0,
|
|
53
|
+
timeoutMs: config.AGENT_PROVIDER_VALIDATION_TIMEOUT_MS,
|
|
54
|
+
...modelProviderCredentialOptions(params),
|
|
55
|
+
...params.signal ? {
|
|
56
|
+
signal: params.signal
|
|
57
|
+
} : {}
|
|
58
|
+
};
|
|
59
|
+
const result = await complete(model, context, options);
|
|
60
|
+
rejectModelProviderErrorResult(result);
|
|
61
|
+
}
|
|
62
|
+
export async function probeCustomModelProviderCredentials(params) {
|
|
63
|
+
const response = await fetch(customProbeUrl(params), {
|
|
64
|
+
method: 'POST',
|
|
65
|
+
headers: customProbeHeaders(params),
|
|
66
|
+
body: JSON.stringify(customProbeBody(params)),
|
|
67
|
+
redirect: 'error',
|
|
68
|
+
signal: timeoutSignal(params.signal, config.AGENT_PROVIDER_VALIDATION_TIMEOUT_MS)
|
|
69
|
+
});
|
|
70
|
+
try {
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
throw new Error(`Provider returned HTTP ${response.status}.`);
|
|
73
|
+
}
|
|
74
|
+
} finally{
|
|
75
|
+
await response.body?.cancel();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export function sanitizeModelProviderError(error, secrets) {
|
|
79
|
+
const message = error instanceof Error && error.message.length > 0 ? error.message : 'Provider validation failed.';
|
|
80
|
+
const secretForms = secrets.flatMap((secret)=>secretWireForms(secret));
|
|
81
|
+
const redacted = redactSecrets(message, secretForms);
|
|
82
|
+
return redacted.slice(0, MAX_SANITIZED_ERROR_LENGTH);
|
|
83
|
+
}
|
|
84
|
+
export function egressPolicy() {
|
|
85
|
+
return {
|
|
86
|
+
allowPrivateNetworks: config.AGENT_CUSTOM_PROVIDER_ALLOW_PRIVATE_NETWORKS,
|
|
87
|
+
hostDenylist: parseEgressHostDenylist(config.AGENT_CUSTOM_PROVIDER_HOST_DENYLIST)
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function customProbeUrl(params) {
|
|
91
|
+
switch(params.api){
|
|
92
|
+
case 'anthropic-messages':
|
|
93
|
+
return appendCustomProviderPath(params.baseUrl, 'messages').toString();
|
|
94
|
+
case 'google-generative-ai':
|
|
95
|
+
return appendCustomProviderPath(params.baseUrl, `models/${encodeURIComponent(params.model.id)}:generateContent`).toString();
|
|
96
|
+
case 'openai-completions':
|
|
97
|
+
return appendCustomProviderPath(params.baseUrl, 'chat/completions').toString();
|
|
98
|
+
case 'openai-responses':
|
|
99
|
+
return appendCustomProviderPath(params.baseUrl, 'responses').toString();
|
|
100
|
+
default:
|
|
101
|
+
return assertNever(params.api);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function customProbeHeaders(params) {
|
|
105
|
+
const headers = new Headers(params.headers);
|
|
106
|
+
headers.set('content-type', 'application/json');
|
|
107
|
+
if (!params.apiKey) return headers;
|
|
108
|
+
switch(params.api){
|
|
109
|
+
case 'anthropic-messages':
|
|
110
|
+
headers.set('x-api-key', params.apiKey);
|
|
111
|
+
headers.set('anthropic-version', '2023-06-01');
|
|
112
|
+
break;
|
|
113
|
+
case 'google-generative-ai':
|
|
114
|
+
headers.set('x-goog-api-key', params.apiKey);
|
|
115
|
+
break;
|
|
116
|
+
case 'openai-completions':
|
|
117
|
+
case 'openai-responses':
|
|
118
|
+
headers.set('authorization', `Bearer ${params.apiKey}`);
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
assertNever(params.api);
|
|
122
|
+
}
|
|
123
|
+
return headers;
|
|
124
|
+
}
|
|
125
|
+
function customProbeBody(params) {
|
|
126
|
+
switch(params.api){
|
|
127
|
+
case 'anthropic-messages':
|
|
128
|
+
return {
|
|
129
|
+
model: params.model.id,
|
|
130
|
+
max_tokens: PROBE_MAX_TOKENS,
|
|
131
|
+
messages: [
|
|
132
|
+
{
|
|
133
|
+
role: 'user',
|
|
134
|
+
content: CUSTOM_PROBE_PROMPT
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
};
|
|
138
|
+
case 'google-generative-ai':
|
|
139
|
+
return {
|
|
140
|
+
contents: [
|
|
141
|
+
{
|
|
142
|
+
role: 'user',
|
|
143
|
+
parts: [
|
|
144
|
+
{
|
|
145
|
+
text: CUSTOM_PROBE_PROMPT
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
],
|
|
150
|
+
generationConfig: {
|
|
151
|
+
maxOutputTokens: PROBE_MAX_TOKENS
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
case 'openai-completions':
|
|
155
|
+
return {
|
|
156
|
+
model: params.model.id,
|
|
157
|
+
messages: [
|
|
158
|
+
{
|
|
159
|
+
role: 'user',
|
|
160
|
+
content: CUSTOM_PROBE_PROMPT
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
max_tokens: PROBE_MAX_TOKENS,
|
|
164
|
+
stream: false
|
|
165
|
+
};
|
|
166
|
+
case 'openai-responses':
|
|
167
|
+
return {
|
|
168
|
+
model: params.model.id,
|
|
169
|
+
input: CUSTOM_PROBE_PROMPT,
|
|
170
|
+
max_output_tokens: PROBE_MAX_TOKENS,
|
|
171
|
+
stream: false,
|
|
172
|
+
store: false
|
|
173
|
+
};
|
|
174
|
+
default:
|
|
175
|
+
return assertNever(params.api);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function assertNever(value) {
|
|
179
|
+
throw new Error(`Unsupported custom model provider API: ${value}`);
|
|
180
|
+
}
|
|
181
|
+
function timeoutSignal(signal, timeoutMs) {
|
|
182
|
+
return signal === undefined ? AbortSignal.timeout(timeoutMs) : AbortSignal.any([
|
|
183
|
+
signal,
|
|
184
|
+
AbortSignal.timeout(timeoutMs)
|
|
185
|
+
]);
|
|
186
|
+
}
|
|
187
|
+
function modelProviderCredentialOptions(params) {
|
|
188
|
+
switch(params.providerId){
|
|
189
|
+
case 'azure-openai-responses':
|
|
190
|
+
return {
|
|
191
|
+
azureBaseUrl: credentialValue(params, 'endpoint')
|
|
192
|
+
};
|
|
193
|
+
case 'cloudflare-ai-gateway':
|
|
194
|
+
return {
|
|
195
|
+
env: {
|
|
196
|
+
CLOUDFLARE_ACCOUNT_ID: credentialValue(params, 'account_id'),
|
|
197
|
+
CLOUDFLARE_GATEWAY_ID: credentialValue(params, 'gateway_id')
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
case 'cloudflare-workers-ai':
|
|
201
|
+
return {
|
|
202
|
+
env: {
|
|
203
|
+
CLOUDFLARE_ACCOUNT_ID: credentialValue(params, 'account_id')
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
default:
|
|
207
|
+
return {};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function credentialValue(params, key) {
|
|
211
|
+
const value = params.credentials[key];
|
|
212
|
+
if (value === undefined) throw new InvalidCredentialFieldsError(params.providerId);
|
|
213
|
+
return value;
|
|
214
|
+
}
|
|
215
|
+
function rejectModelProviderErrorResult(result) {
|
|
216
|
+
if (result.stopReason !== 'error' && result.stopReason !== 'aborted') return;
|
|
217
|
+
throw new Error(result.errorMessage ?? 'Provider validation failed.');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
//# sourceMappingURL=model-provider-validation.js.map
|
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type AgentThinking, type CustomAgentModelDto, type Harness, type ModelProviderRef, type SupportedModelProviderId } from '@shipfox/api-agent-dto';
|
|
2
|
+
export interface ContextualAgentConfig {
|
|
3
|
+
readonly harness?: Harness | undefined;
|
|
4
|
+
readonly provider?: string | undefined;
|
|
5
|
+
readonly model?: string | undefined;
|
|
6
|
+
readonly thinking?: AgentThinking | undefined;
|
|
7
|
+
}
|
|
8
|
+
export interface ResolvedAgentConfig {
|
|
9
|
+
readonly harness: Harness;
|
|
10
|
+
readonly provider: ModelProviderRef;
|
|
11
|
+
readonly model: string;
|
|
12
|
+
readonly thinking: AgentThinking;
|
|
13
|
+
}
|
|
14
|
+
export type AgentDefaultsResolver = (step: ContextualAgentConfig) => ResolvedAgentConfig;
|
|
15
|
+
export interface AgentConfigResolutionContext {
|
|
16
|
+
readonly workspaceDefaultHarnessId?: Harness | null | undefined;
|
|
17
|
+
readonly workspaceDefaultProviderId?: ModelProviderRef | null | undefined;
|
|
18
|
+
readonly workspaceProviderConfigs?: ReadonlyMap<ModelProviderRef, WorkspaceProviderDefaults>;
|
|
19
|
+
readonly instanceDefaultProvider?: SupportedModelProviderId | undefined;
|
|
20
|
+
readonly instanceDefaultModel?: string | undefined;
|
|
21
|
+
readonly instanceDefaultThinking?: AgentThinking | undefined;
|
|
22
|
+
}
|
|
23
|
+
interface WorkspaceProviderDefaults {
|
|
24
|
+
readonly kind?: 'builtin' | 'custom' | undefined;
|
|
25
|
+
readonly defaultModel: string | null;
|
|
26
|
+
readonly defaultThinking: AgentThinking;
|
|
27
|
+
readonly models?: readonly CustomAgentModelDto[] | null | undefined;
|
|
28
|
+
}
|
|
29
|
+
export declare function resolveAgentConfig(step: ContextualAgentConfig, ctx?: AgentConfigResolutionContext): ResolvedAgentConfig;
|
|
30
|
+
export declare const catalogDefaultAgentResolver: AgentDefaultsResolver;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=resolve-agent-config.d.ts.map
|
|
@@ -0,0 +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"}
|