@shipfox/api-agent 12.2.0 → 13.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +19 -0
- package/dist/config.d.ts +5 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +72 -7
- package/dist/config.js.map +1 -1
- package/dist/core/errors.d.ts +4 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +6 -0
- package/dist/core/errors.js.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/model-provider-catalog.d.ts +5 -2
- package/dist/core/model-provider-catalog.d.ts.map +1 -1
- package/dist/core/model-provider-catalog.js +33 -1
- package/dist/core/model-provider-catalog.js.map +1 -1
- package/dist/core/resolve-agent-config.d.ts +4 -2
- package/dist/core/resolve-agent-config.d.ts.map +1 -1
- package/dist/core/resolve-agent-config.js +86 -31
- package/dist/core/resolve-agent-config.js.map +1 -1
- package/dist/core/resolve-runtime-credentials.d.ts +6 -2
- package/dist/core/resolve-runtime-credentials.d.ts.map +1 -1
- package/dist/core/resolve-runtime-credentials.js +59 -3
- package/dist/core/resolve-runtime-credentials.js.map +1 -1
- package/dist/core/validation-catalog.d.ts +2 -1
- package/dist/core/validation-catalog.d.ts.map +1 -1
- package/dist/core/validation-catalog.js +65 -17
- package/dist/core/validation-catalog.js.map +1 -1
- package/dist/core/workspace-agent-defaults-resolver.d.ts +2 -1
- package/dist/core/workspace-agent-defaults-resolver.d.ts.map +1 -1
- package/dist/core/workspace-agent-defaults-resolver.js +4 -2
- package/dist/core/workspace-agent-defaults-resolver.js.map +1 -1
- package/dist/core/workspace-provider-policy.d.ts +7 -0
- package/dist/core/workspace-provider-policy.d.ts.map +1 -0
- package/dist/core/workspace-provider-policy.js +10 -0
- package/dist/core/workspace-provider-policy.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -4
- package/dist/index.js.map +1 -1
- package/dist/presentation/e2eRoutes/create-model-provider.d.ts +2 -1
- package/dist/presentation/e2eRoutes/create-model-provider.d.ts.map +1 -1
- package/dist/presentation/e2eRoutes/create-model-provider.js +7 -1
- package/dist/presentation/e2eRoutes/create-model-provider.js.map +1 -1
- package/dist/presentation/e2eRoutes/index.d.ts +2 -1
- package/dist/presentation/e2eRoutes/index.d.ts.map +1 -1
- package/dist/presentation/e2eRoutes/index.js +4 -2
- package/dist/presentation/e2eRoutes/index.js.map +1 -1
- package/dist/presentation/inter-module.d.ts +3 -0
- package/dist/presentation/inter-module.d.ts.map +1 -1
- package/dist/presentation/inter-module.js +22 -6
- package/dist/presentation/inter-module.js.map +1 -1
- package/dist/presentation/routes/create-custom-model-provider.d.ts +2 -1
- package/dist/presentation/routes/create-custom-model-provider.d.ts.map +1 -1
- package/dist/presentation/routes/create-custom-model-provider.js +5 -2
- package/dist/presentation/routes/create-custom-model-provider.js.map +1 -1
- package/dist/presentation/routes/delete-model-provider-config.d.ts +2 -1
- package/dist/presentation/routes/delete-model-provider-config.d.ts.map +1 -1
- package/dist/presentation/routes/delete-model-provider-config.js +7 -2
- package/dist/presentation/routes/delete-model-provider-config.js.map +1 -1
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.d.ts +2 -1
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.d.ts.map +1 -1
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.js +5 -2
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.js.map +1 -1
- 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 -1
- package/dist/presentation/routes/discover-custom-model-provider-models.js +29 -23
- package/dist/presentation/routes/discover-custom-model-provider-models.js.map +1 -1
- package/dist/presentation/routes/errors.d.ts.map +1 -1
- package/dist/presentation/routes/errors.js +10 -1
- package/dist/presentation/routes/errors.js.map +1 -1
- package/dist/presentation/routes/index.d.ts +5 -1
- package/dist/presentation/routes/index.d.ts.map +1 -1
- package/dist/presentation/routes/index.js +21 -14
- package/dist/presentation/routes/index.js.map +1 -1
- package/dist/presentation/routes/list-model-provider-catalog.d.ts +5 -0
- package/dist/presentation/routes/list-model-provider-catalog.d.ts.map +1 -1
- package/dist/presentation/routes/list-model-provider-catalog.js +21 -13
- package/dist/presentation/routes/list-model-provider-catalog.js.map +1 -1
- package/dist/presentation/routes/set-default-model-provider.d.ts +2 -0
- package/dist/presentation/routes/set-default-model-provider.d.ts.map +1 -1
- package/dist/presentation/routes/set-default-model-provider.js +44 -38
- package/dist/presentation/routes/set-default-model-provider.js.map +1 -1
- package/dist/presentation/routes/update-custom-model-provider.d.ts +2 -1
- package/dist/presentation/routes/update-custom-model-provider.d.ts.map +1 -1
- package/dist/presentation/routes/update-custom-model-provider.js +5 -2
- package/dist/presentation/routes/update-custom-model-provider.js.map +1 -1
- 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 -1
- package/dist/presentation/routes/update-model-provider-default-model.js +35 -29
- package/dist/presentation/routes/update-model-provider-default-model.js.map +1 -1
- package/dist/presentation/routes/upsert-model-provider-config.d.ts +2 -1
- package/dist/presentation/routes/upsert-model-provider-config.d.ts.map +1 -1
- package/dist/presentation/routes/upsert-model-provider-config.js +5 -2
- package/dist/presentation/routes/upsert-model-provider-config.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/config.test.ts +165 -4
- package/src/config.ts +94 -9
- package/src/core/errors.ts +7 -0
- package/src/core/index.ts +5 -0
- package/src/core/model-provider-catalog.test.ts +30 -0
- package/src/core/model-provider-catalog.ts +41 -1
- package/src/core/resolve-agent-config.test.ts +92 -0
- package/src/core/resolve-agent-config.ts +152 -43
- package/src/core/resolve-runtime-credentials.test.ts +169 -1
- package/src/core/resolve-runtime-credentials.ts +68 -3
- package/src/core/validation-catalog.test.ts +54 -0
- package/src/core/validation-catalog.ts +124 -19
- package/src/core/workspace-agent-defaults-resolver.ts +7 -2
- package/src/core/workspace-provider-policy.ts +19 -0
- package/src/index.ts +25 -4
- package/src/presentation/e2eRoutes/create-model-provider.ts +11 -1
- package/src/presentation/e2eRoutes/index.ts +9 -2
- package/src/presentation/inter-module.test.ts +51 -0
- package/src/presentation/inter-module.ts +38 -6
- package/src/presentation/routes/create-custom-model-provider.ts +10 -2
- package/src/presentation/routes/delete-model-provider-config.ts +12 -2
- package/src/presentation/routes/discover-custom-model-provider-models-by-slug.ts +7 -1
- package/src/presentation/routes/discover-custom-model-provider-models.ts +30 -18
- package/src/presentation/routes/errors.ts +11 -0
- package/src/presentation/routes/index.ts +32 -14
- package/src/presentation/routes/list-model-provider-catalog.ts +32 -11
- package/src/presentation/routes/model-provider-catalog.test.ts +49 -1
- package/src/presentation/routes/model-provider-config.test.ts +62 -1
- package/src/presentation/routes/set-default-model-provider.ts +42 -31
- package/src/presentation/routes/update-custom-model-provider.ts +10 -2
- package/src/presentation/routes/update-model-provider-default-model.ts +37 -26
- package/src/presentation/routes/upsert-model-provider-config.ts +10 -2
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -2,10 +2,18 @@ import {modelProviderRefSchema} from '@shipfox/api-agent-dto';
|
|
|
2
2
|
import {requireWorkspaceAccess} from '@shipfox/api-auth-context';
|
|
3
3
|
import {ClientError, defineRoute} from '@shipfox/node-fastify';
|
|
4
4
|
import {z} from 'zod';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
assertWorkspaceProviderConfigurationEnabled,
|
|
7
|
+
deleteModelProviderConfig,
|
|
8
|
+
} from '#core/index.js';
|
|
6
9
|
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
10
|
+
import type {WorkspaceProviderPolicyOptions} from '#core/workspace-provider-policy.js';
|
|
11
|
+
import {translateModelProviderRouteError} from './errors.js';
|
|
7
12
|
|
|
8
|
-
export function createDeleteModelProviderConfigRoute(
|
|
13
|
+
export function createDeleteModelProviderConfigRoute(
|
|
14
|
+
secrets: AgentSecretsClient,
|
|
15
|
+
workspaceProviderPolicy: WorkspaceProviderPolicyOptions = {workspaceProviders: 'enabled'},
|
|
16
|
+
) {
|
|
9
17
|
return defineRoute({
|
|
10
18
|
method: 'DELETE',
|
|
11
19
|
path: '/model-providers/:providerId',
|
|
@@ -19,9 +27,11 @@ export function createDeleteModelProviderConfigRoute(secrets: AgentSecretsClient
|
|
|
19
27
|
204: z.void(),
|
|
20
28
|
},
|
|
21
29
|
},
|
|
30
|
+
errorHandler: translateModelProviderRouteError,
|
|
22
31
|
handler: async (request, reply) => {
|
|
23
32
|
const {workspaceId, providerId} = request.params;
|
|
24
33
|
requireWorkspaceAccess({request, workspaceId});
|
|
34
|
+
assertWorkspaceProviderConfigurationEnabled(workspaceProviderPolicy);
|
|
25
35
|
|
|
26
36
|
const deleted = await deleteModelProviderConfig({workspaceId, providerId}, {secrets});
|
|
27
37
|
if (!deleted) {
|
|
@@ -7,13 +7,18 @@ import {requireWorkspaceAccess} from '@shipfox/api-auth-context';
|
|
|
7
7
|
import {defineRoute} from '@shipfox/node-fastify';
|
|
8
8
|
import {z} from 'zod';
|
|
9
9
|
import {
|
|
10
|
+
assertWorkspaceProviderConfigurationEnabled,
|
|
10
11
|
discoverCustomModelProviderModels,
|
|
11
12
|
resolveCustomModelProviderDiscoveryParams,
|
|
12
13
|
} from '#core/index.js';
|
|
13
14
|
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
15
|
+
import type {WorkspaceProviderPolicyOptions} from '#core/workspace-provider-policy.js';
|
|
14
16
|
import {translateModelProviderRouteError} from './errors.js';
|
|
15
17
|
|
|
16
|
-
export function createDiscoverCustomModelProviderModelsBySlugRoute(
|
|
18
|
+
export function createDiscoverCustomModelProviderModelsBySlugRoute(
|
|
19
|
+
secrets: AgentSecretsClient,
|
|
20
|
+
workspaceProviderPolicy: WorkspaceProviderPolicyOptions = {workspaceProviders: 'enabled'},
|
|
21
|
+
) {
|
|
17
22
|
return defineRoute({
|
|
18
23
|
method: 'POST',
|
|
19
24
|
path: '/custom-model-providers/:slug/discover-models',
|
|
@@ -32,6 +37,7 @@ export function createDiscoverCustomModelProviderModelsBySlugRoute(secrets: Agen
|
|
|
32
37
|
handler: async (request) => {
|
|
33
38
|
const {workspaceId, slug} = request.params;
|
|
34
39
|
requireWorkspaceAccess({request, workspaceId});
|
|
40
|
+
assertWorkspaceProviderConfigurationEnabled(workspaceProviderPolicy);
|
|
35
41
|
|
|
36
42
|
const discoveryParams = await resolveCustomModelProviderDiscoveryParams(
|
|
37
43
|
{
|
|
@@ -5,25 +5,37 @@ import {
|
|
|
5
5
|
import {requireWorkspaceAccess} from '@shipfox/api-auth-context';
|
|
6
6
|
import {defineRoute} from '@shipfox/node-fastify';
|
|
7
7
|
import {z} from 'zod';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
assertWorkspaceProviderConfigurationEnabled,
|
|
10
|
+
discoverCustomModelProviderModels,
|
|
11
|
+
} from '#core/index.js';
|
|
12
|
+
import type {WorkspaceProviderPolicyOptions} from '#core/workspace-provider-policy.js';
|
|
9
13
|
import {translateModelProviderRouteError} from './errors.js';
|
|
10
14
|
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
export function createDiscoverCustomModelProviderModelsRoute(
|
|
16
|
+
workspaceProviderPolicy: WorkspaceProviderPolicyOptions = {workspaceProviders: 'enabled'},
|
|
17
|
+
) {
|
|
18
|
+
return defineRoute({
|
|
19
|
+
method: 'POST',
|
|
20
|
+
path: '/custom-model-providers/discover-models',
|
|
21
|
+
description: 'Discover models exposed by a custom model provider endpoint',
|
|
22
|
+
schema: {
|
|
23
|
+
params: z.object({workspaceId: z.string().uuid()}),
|
|
24
|
+
body: discoverCustomModelProviderModelsBodySchema,
|
|
25
|
+
response: {
|
|
26
|
+
200: discoverCustomModelProviderModelsResponseSchema,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
errorHandler: translateModelProviderRouteError,
|
|
30
|
+
handler: async (request) => {
|
|
31
|
+
const {workspaceId} = request.params;
|
|
32
|
+
requireWorkspaceAccess({request, workspaceId});
|
|
33
|
+
assertWorkspaceProviderConfigurationEnabled(workspaceProviderPolicy);
|
|
34
|
+
|
|
35
|
+
return await discoverCustomModelProviderModels(request.body);
|
|
20
36
|
},
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
handler: async (request) => {
|
|
24
|
-
const {workspaceId} = request.params;
|
|
25
|
-
requireWorkspaceAccess({request, workspaceId});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
26
39
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
40
|
+
export const discoverCustomModelProviderModelsRoute =
|
|
41
|
+
createDiscoverCustomModelProviderModelsRoute();
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
ModelProviderConfigNotFoundError,
|
|
13
13
|
ModelProviderValidationError,
|
|
14
14
|
UnsupportedModelProviderError,
|
|
15
|
+
WorkspaceProvidersDisabledError,
|
|
15
16
|
} from '#core/index.js';
|
|
16
17
|
import {getModelProviderCredentialKeys} from '#core/model-provider-policy.js';
|
|
17
18
|
|
|
@@ -96,6 +97,16 @@ export function translateModelProviderRouteError(error: unknown): never {
|
|
|
96
97
|
});
|
|
97
98
|
}
|
|
98
99
|
|
|
100
|
+
if (error instanceof WorkspaceProvidersDisabledError) {
|
|
101
|
+
throw new ClientError(error.message, 'workspace-providers-disabled', {
|
|
102
|
+
status: 422,
|
|
103
|
+
details: {
|
|
104
|
+
managed_provider_id: error.managedProviderId,
|
|
105
|
+
message: error.message,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
99
110
|
if (error instanceof ModelProviderConfigNotFoundError) {
|
|
100
111
|
throw new ClientError('Provider is not configured', 'provider-not-configured', {
|
|
101
112
|
status: 422,
|
|
@@ -1,40 +1,58 @@
|
|
|
1
|
+
import type {ManagedModelProvider, WorkspaceProvidersPolicy} from '@shipfox/api-agent-dto';
|
|
1
2
|
import {AUTH_USER} from '@shipfox/api-auth-context';
|
|
2
3
|
import type {RouteGroup} from '@shipfox/node-fastify';
|
|
3
4
|
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
5
|
+
import type {WorkspaceProviderPolicyOptions} from '#core/workspace-provider-policy.js';
|
|
4
6
|
import {createCustomModelProviderRoute} from './create-custom-model-provider.js';
|
|
5
7
|
import {createDeleteModelProviderConfigRoute} from './delete-model-provider-config.js';
|
|
6
|
-
import {
|
|
8
|
+
import {createDiscoverCustomModelProviderModelsRoute} from './discover-custom-model-provider-models.js';
|
|
7
9
|
import {createDiscoverCustomModelProviderModelsBySlugRoute} from './discover-custom-model-provider-models-by-slug.js';
|
|
8
|
-
import {
|
|
10
|
+
import {createListModelProviderCatalogRoute} from './list-model-provider-catalog.js';
|
|
9
11
|
import {listModelProviderConfigsRoute} from './list-model-provider-configs.js';
|
|
10
12
|
import {setDefaultHarnessRoute} from './set-default-harness.js';
|
|
11
|
-
import {
|
|
13
|
+
import {createSetDefaultModelProviderRoute} from './set-default-model-provider.js';
|
|
12
14
|
import {createUpdateCustomModelProviderRoute} from './update-custom-model-provider.js';
|
|
13
|
-
import {
|
|
15
|
+
import {createUpdateModelProviderDefaultModelRoute} from './update-model-provider-default-model.js';
|
|
14
16
|
import {createUpsertModelProviderConfigRoute} from './upsert-model-provider-config.js';
|
|
15
17
|
|
|
16
|
-
export function createAgentRoutes(
|
|
18
|
+
export function createAgentRoutes(
|
|
19
|
+
secrets: AgentSecretsClient,
|
|
20
|
+
options: {
|
|
21
|
+
managedProvider?: ManagedModelProvider | undefined;
|
|
22
|
+
workspaceProviders?: WorkspaceProvidersPolicy | undefined;
|
|
23
|
+
} = {},
|
|
24
|
+
): RouteGroup[] {
|
|
25
|
+
const workspaceProviderPolicy: WorkspaceProviderPolicyOptions = {
|
|
26
|
+
workspaceProviders: options.workspaceProviders ?? 'enabled',
|
|
27
|
+
managedProviderId: options.managedProvider?.id,
|
|
28
|
+
};
|
|
29
|
+
|
|
17
30
|
return [
|
|
18
31
|
{
|
|
19
32
|
prefix: '/workspaces/:workspaceId/agent',
|
|
20
33
|
auth: AUTH_USER,
|
|
21
34
|
routes: [
|
|
22
35
|
listModelProviderConfigsRoute,
|
|
23
|
-
createCustomModelProviderRoute(secrets),
|
|
24
|
-
|
|
25
|
-
createDiscoverCustomModelProviderModelsBySlugRoute(secrets),
|
|
26
|
-
createUpdateCustomModelProviderRoute(secrets),
|
|
27
|
-
createUpsertModelProviderConfigRoute(secrets),
|
|
28
|
-
|
|
29
|
-
createDeleteModelProviderConfigRoute(secrets),
|
|
36
|
+
createCustomModelProviderRoute(secrets, workspaceProviderPolicy),
|
|
37
|
+
createDiscoverCustomModelProviderModelsRoute(workspaceProviderPolicy),
|
|
38
|
+
createDiscoverCustomModelProviderModelsBySlugRoute(secrets, workspaceProviderPolicy),
|
|
39
|
+
createUpdateCustomModelProviderRoute(secrets, workspaceProviderPolicy),
|
|
40
|
+
createUpsertModelProviderConfigRoute(secrets, workspaceProviderPolicy),
|
|
41
|
+
createUpdateModelProviderDefaultModelRoute(workspaceProviderPolicy),
|
|
42
|
+
createDeleteModelProviderConfigRoute(secrets, workspaceProviderPolicy),
|
|
30
43
|
setDefaultHarnessRoute,
|
|
31
|
-
|
|
44
|
+
createSetDefaultModelProviderRoute(workspaceProviderPolicy),
|
|
32
45
|
],
|
|
33
46
|
},
|
|
34
47
|
{
|
|
35
48
|
prefix: '/agent',
|
|
36
49
|
auth: AUTH_USER,
|
|
37
|
-
routes: [
|
|
50
|
+
routes: [
|
|
51
|
+
createListModelProviderCatalogRoute({
|
|
52
|
+
managedProvider: options.managedProvider,
|
|
53
|
+
workspaceProviders: options.workspaceProviders,
|
|
54
|
+
}),
|
|
55
|
+
],
|
|
38
56
|
},
|
|
39
57
|
];
|
|
40
58
|
}
|
|
@@ -1,15 +1,36 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ManagedModelProvider,
|
|
3
|
+
modelProviderCatalogResponseSchema,
|
|
4
|
+
type WorkspaceProvidersPolicy,
|
|
5
|
+
} from '@shipfox/api-agent-dto';
|
|
2
6
|
import {defineRoute} from '@shipfox/node-fastify';
|
|
3
7
|
import {buildModelProviderCatalog} from '#core/index.js';
|
|
4
8
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
export function createListModelProviderCatalogRoute(
|
|
10
|
+
options: {
|
|
11
|
+
managedProvider?: ManagedModelProvider | undefined;
|
|
12
|
+
workspaceProviders?: WorkspaceProvidersPolicy | undefined;
|
|
13
|
+
} = {},
|
|
14
|
+
) {
|
|
15
|
+
const workspaceProviders = options.workspaceProviders ?? 'enabled';
|
|
16
|
+
|
|
17
|
+
return defineRoute({
|
|
18
|
+
method: 'GET',
|
|
19
|
+
path: '/model-provider-catalog',
|
|
20
|
+
description: 'List available model providers and models',
|
|
21
|
+
schema: {
|
|
22
|
+
response: {
|
|
23
|
+
200: modelProviderCatalogResponseSchema,
|
|
24
|
+
},
|
|
12
25
|
},
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
26
|
+
handler: () => ({
|
|
27
|
+
providers: buildModelProviderCatalog({
|
|
28
|
+
managedProvider: options.managedProvider,
|
|
29
|
+
workspaceProviders,
|
|
30
|
+
}),
|
|
31
|
+
workspace_providers: workspaceProviders,
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const listModelProviderCatalogRoute = createListModelProviderCatalogRoute();
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type {ManagedModelProvider} from '@shipfox/api-agent-dto';
|
|
1
2
|
import {AUTH_USER, buildUserContext, setUserContext} from '@shipfox/api-auth-context';
|
|
2
3
|
import type {AuthMethod, FastifyRequest} from '@shipfox/node-fastify';
|
|
3
4
|
import {ClientError, closeApp, createApp} from '@shipfox/node-fastify';
|
|
4
|
-
import {agentRoutes} from './index.js';
|
|
5
|
+
import {agentRoutes, createAgentRoutes} from './index.js';
|
|
5
6
|
|
|
6
7
|
const fakeUserAuth: AuthMethod = {
|
|
7
8
|
name: AUTH_USER,
|
|
@@ -69,5 +70,52 @@ describe('model provider catalog route', () => {
|
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
});
|
|
73
|
+
|
|
74
|
+
it('returns only the managed provider and the disabled policy when configured', async () => {
|
|
75
|
+
await closeApp();
|
|
76
|
+
app = await createApp({
|
|
77
|
+
auth: [fakeUserAuth],
|
|
78
|
+
routes: createAgentRoutes(undefined as never, {
|
|
79
|
+
managedProvider: managedProvider(),
|
|
80
|
+
workspaceProviders: 'disabled',
|
|
81
|
+
}),
|
|
82
|
+
swagger: false,
|
|
83
|
+
});
|
|
84
|
+
await app.ready();
|
|
85
|
+
|
|
86
|
+
const res = await app.inject({
|
|
87
|
+
method: 'GET',
|
|
88
|
+
url: '/agent/model-provider-catalog',
|
|
89
|
+
headers: {authorization: 'Bearer user'},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
expect(res.statusCode, res.body).toBe(200);
|
|
93
|
+
expect(res.json()).toMatchObject({
|
|
94
|
+
workspace_providers: 'disabled',
|
|
95
|
+
providers: [
|
|
96
|
+
expect.objectContaining({
|
|
97
|
+
id: 'shipfox',
|
|
98
|
+
support_status: 'supported',
|
|
99
|
+
default_model: 'managed-claude',
|
|
100
|
+
credential_fields: [],
|
|
101
|
+
models: [{id: 'managed-claude', label: 'Managed Claude', api: 'anthropic-messages'}],
|
|
102
|
+
}),
|
|
103
|
+
],
|
|
104
|
+
});
|
|
105
|
+
});
|
|
72
106
|
});
|
|
73
107
|
});
|
|
108
|
+
|
|
109
|
+
function managedProvider(): ManagedModelProvider {
|
|
110
|
+
return {
|
|
111
|
+
id: 'shipfox',
|
|
112
|
+
label: 'Shipfox',
|
|
113
|
+
models: [{id: 'managed-claude', label: 'Managed Claude', api: 'anthropic-messages'}],
|
|
114
|
+
defaultModel: 'managed-claude',
|
|
115
|
+
resolveCredentials: async () => ({
|
|
116
|
+
api: 'anthropic-messages',
|
|
117
|
+
baseUrl: 'https://gateway.example.com',
|
|
118
|
+
credentials: {api_key: 'token'},
|
|
119
|
+
}),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from '#db/index.js';
|
|
21
21
|
import {modelProviderConfigs} from '#db/schema/model-provider-configs.js';
|
|
22
22
|
import {getSecretsByNamespace, setSecrets} from '#test/fixtures/secrets-client.js';
|
|
23
|
-
import {agentRoutes} from './index.js';
|
|
23
|
+
import {agentRoutes, createAgentRoutes} from './index.js';
|
|
24
24
|
|
|
25
25
|
vi.mock('@earendil-works/pi-ai/compat', async (importOriginal) => {
|
|
26
26
|
const actual = await importOriginal<typeof import('@earendil-works/pi-ai/compat')>();
|
|
@@ -391,6 +391,53 @@ describe('model provider config routes', () => {
|
|
|
391
391
|
|
|
392
392
|
expect(res.statusCode).toBe(400);
|
|
393
393
|
});
|
|
394
|
+
|
|
395
|
+
it('rejects catalog and custom provider writes when workspace providers are disabled', async () => {
|
|
396
|
+
await closeApp();
|
|
397
|
+
app = await createApp({
|
|
398
|
+
auth: [fakeUserAuth],
|
|
399
|
+
routes: createAgentRoutes(undefined as never, {
|
|
400
|
+
managedProvider: managedProvider(),
|
|
401
|
+
workspaceProviders: 'disabled',
|
|
402
|
+
}),
|
|
403
|
+
swagger: false,
|
|
404
|
+
});
|
|
405
|
+
await app.ready();
|
|
406
|
+
|
|
407
|
+
const catalogWrite = await app.inject({
|
|
408
|
+
method: 'PUT',
|
|
409
|
+
url: `/workspaces/${workspaceId}/agent/model-providers/anthropic`,
|
|
410
|
+
headers: {authorization: 'Bearer user'},
|
|
411
|
+
payload: {credentials: {api_key: 'sk-secret'}},
|
|
412
|
+
});
|
|
413
|
+
const customWrite = await app.inject({
|
|
414
|
+
method: 'POST',
|
|
415
|
+
url: `/workspaces/${workspaceId}/agent/custom-model-providers`,
|
|
416
|
+
headers: {authorization: 'Bearer user'},
|
|
417
|
+
payload: {
|
|
418
|
+
slug: 'local-vllm',
|
|
419
|
+
display_name: 'Local vLLM',
|
|
420
|
+
api: 'openai-responses',
|
|
421
|
+
base_url: 'http://127.0.0.1:11434/v1',
|
|
422
|
+
models: [{id: 'llama-3.1', label: 'Llama 3.1'}],
|
|
423
|
+
},
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
expect(catalogWrite.statusCode).toBe(422);
|
|
427
|
+
expect(customWrite.statusCode).toBe(422);
|
|
428
|
+
expect(catalogWrite.json()).toMatchObject({
|
|
429
|
+
code: 'workspace-providers-disabled',
|
|
430
|
+
details: {
|
|
431
|
+
message: 'This instance only supports provider `shipfox`.',
|
|
432
|
+
},
|
|
433
|
+
});
|
|
434
|
+
expect(customWrite.json()).toMatchObject({
|
|
435
|
+
code: 'workspace-providers-disabled',
|
|
436
|
+
details: {
|
|
437
|
+
message: 'This instance only supports provider `shipfox`.',
|
|
438
|
+
},
|
|
439
|
+
});
|
|
440
|
+
});
|
|
394
441
|
});
|
|
395
442
|
|
|
396
443
|
describe('DELETE /workspaces/:workspaceId/agent/model-providers/:providerId', () => {
|
|
@@ -804,4 +851,18 @@ describe('model provider config routes', () => {
|
|
|
804
851
|
});
|
|
805
852
|
expect(rows).toHaveLength(1);
|
|
806
853
|
}
|
|
854
|
+
|
|
855
|
+
function managedProvider() {
|
|
856
|
+
return {
|
|
857
|
+
id: 'shipfox',
|
|
858
|
+
label: 'Shipfox',
|
|
859
|
+
models: [{id: 'managed-claude', label: 'Managed Claude', api: 'anthropic-messages' as const}],
|
|
860
|
+
defaultModel: 'managed-claude',
|
|
861
|
+
resolveCredentials: async () => ({
|
|
862
|
+
api: 'anthropic-messages' as const,
|
|
863
|
+
baseUrl: 'https://gateway.example.com',
|
|
864
|
+
credentials: {api_key: 'token'},
|
|
865
|
+
}),
|
|
866
|
+
};
|
|
867
|
+
}
|
|
807
868
|
});
|
|
@@ -5,43 +5,54 @@ import {
|
|
|
5
5
|
import {requireWorkspaceAccess} from '@shipfox/api-auth-context';
|
|
6
6
|
import {defineRoute} from '@shipfox/node-fastify';
|
|
7
7
|
import {z} from 'zod';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
assertWorkspaceProviderConfigurationEnabled,
|
|
10
|
+
UnsupportedModelProviderError,
|
|
11
|
+
} from '#core/index.js';
|
|
9
12
|
import {getModelProviderEntry} from '#core/model-provider-policy.js';
|
|
13
|
+
import type {WorkspaceProviderPolicyOptions} from '#core/workspace-provider-policy.js';
|
|
10
14
|
import {getModelProviderConfig, setDefaultModelProvider} from '#db/index.js';
|
|
11
15
|
import {translateModelProviderRouteError} from './errors.js';
|
|
12
16
|
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
export function createSetDefaultModelProviderRoute(
|
|
18
|
+
workspaceProviderPolicy: WorkspaceProviderPolicyOptions = {workspaceProviders: 'enabled'},
|
|
19
|
+
) {
|
|
20
|
+
return defineRoute({
|
|
21
|
+
method: 'PUT',
|
|
22
|
+
path: '/default-model-provider',
|
|
23
|
+
description: 'Set the default model provider for a workspace',
|
|
24
|
+
schema: {
|
|
25
|
+
params: z.object({workspaceId: z.string().uuid()}),
|
|
26
|
+
body: setDefaultModelProviderBodySchema,
|
|
27
|
+
response: {
|
|
28
|
+
200: setDefaultModelProviderResponseSchema,
|
|
29
|
+
},
|
|
22
30
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
errorHandler: translateModelProviderRouteError,
|
|
32
|
+
handler: async (request) => {
|
|
33
|
+
const {workspaceId} = request.params;
|
|
34
|
+
requireWorkspaceAccess({request, workspaceId});
|
|
35
|
+
assertWorkspaceProviderConfigurationEnabled(workspaceProviderPolicy);
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
const existingConfig = await getModelProviderConfig({
|
|
38
|
+
workspaceId,
|
|
39
|
+
providerId: request.body.provider_id,
|
|
40
|
+
});
|
|
41
|
+
if (existingConfig?.kind !== 'custom') {
|
|
42
|
+
const entry = getModelProviderEntry(request.body.provider_id);
|
|
43
|
+
if (entry === undefined || entry.support_status !== 'supported') {
|
|
44
|
+
throw new UnsupportedModelProviderError(request.body.provider_id);
|
|
45
|
+
}
|
|
37
46
|
}
|
|
38
|
-
}
|
|
39
47
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
const settings = await setDefaultModelProvider({
|
|
49
|
+
workspaceId,
|
|
50
|
+
providerId: request.body.provider_id,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return {default_provider_id: settings.defaultProviderId};
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
},
|
|
47
|
-
});
|
|
58
|
+
export const setDefaultModelProviderRoute = createSetDefaultModelProviderRoute();
|
|
@@ -6,12 +6,19 @@ import {
|
|
|
6
6
|
import {requireWorkspaceAccess} from '@shipfox/api-auth-context';
|
|
7
7
|
import {defineRoute} from '@shipfox/node-fastify';
|
|
8
8
|
import {z} from 'zod';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
assertWorkspaceProviderConfigurationEnabled,
|
|
11
|
+
updateCustomModelProviderConfig,
|
|
12
|
+
} from '#core/index.js';
|
|
10
13
|
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
14
|
+
import type {WorkspaceProviderPolicyOptions} from '#core/workspace-provider-policy.js';
|
|
11
15
|
import {toCustomModelProviderConfigDto} from '#presentation/dto/index.js';
|
|
12
16
|
import {translateModelProviderRouteError} from './errors.js';
|
|
13
17
|
|
|
14
|
-
export function createUpdateCustomModelProviderRoute(
|
|
18
|
+
export function createUpdateCustomModelProviderRoute(
|
|
19
|
+
secrets: AgentSecretsClient,
|
|
20
|
+
workspaceProviderPolicy: WorkspaceProviderPolicyOptions = {workspaceProviders: 'enabled'},
|
|
21
|
+
) {
|
|
15
22
|
return defineRoute({
|
|
16
23
|
method: 'PUT',
|
|
17
24
|
path: '/custom-model-providers/:slug',
|
|
@@ -39,6 +46,7 @@ export function createUpdateCustomModelProviderRoute(secrets: AgentSecretsClient
|
|
|
39
46
|
});
|
|
40
47
|
|
|
41
48
|
requireWorkspaceAccess({request, workspaceId});
|
|
49
|
+
assertWorkspaceProviderConfigurationEnabled(workspaceProviderPolicy);
|
|
42
50
|
|
|
43
51
|
const config = await updateCustomModelProviderConfig(
|
|
44
52
|
{
|
|
@@ -6,35 +6,46 @@ import {
|
|
|
6
6
|
import {requireWorkspaceAccess} from '@shipfox/api-auth-context';
|
|
7
7
|
import {defineRoute} from '@shipfox/node-fastify';
|
|
8
8
|
import {z} from 'zod';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
assertWorkspaceProviderConfigurationEnabled,
|
|
11
|
+
updateModelProviderConfigDefaultModel,
|
|
12
|
+
} from '#core/index.js';
|
|
13
|
+
import type {WorkspaceProviderPolicyOptions} from '#core/workspace-provider-policy.js';
|
|
10
14
|
import {toModelProviderConfigResponseDto} from '#presentation/dto/index.js';
|
|
11
15
|
import {translateModelProviderRouteError} from './errors.js';
|
|
12
16
|
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
export function createUpdateModelProviderDefaultModelRoute(
|
|
18
|
+
workspaceProviderPolicy: WorkspaceProviderPolicyOptions = {workspaceProviders: 'enabled'},
|
|
19
|
+
) {
|
|
20
|
+
return defineRoute({
|
|
21
|
+
method: 'PUT',
|
|
22
|
+
path: '/model-providers/:providerId/default-model',
|
|
23
|
+
description: 'Update the default model for an existing model provider configuration',
|
|
24
|
+
schema: {
|
|
25
|
+
params: z.object({
|
|
26
|
+
workspaceId: z.string().uuid(),
|
|
27
|
+
providerId: modelProviderRefSchema,
|
|
28
|
+
}),
|
|
29
|
+
body: updateModelProviderDefaultModelBodySchema,
|
|
30
|
+
response: {
|
|
31
|
+
200: modelProviderConfigResponseSchema,
|
|
32
|
+
},
|
|
25
33
|
},
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
errorHandler: translateModelProviderRouteError,
|
|
35
|
+
handler: async (request) => {
|
|
36
|
+
const {workspaceId, providerId} = request.params;
|
|
37
|
+
requireWorkspaceAccess({request, workspaceId});
|
|
38
|
+
assertWorkspaceProviderConfigurationEnabled(workspaceProviderPolicy);
|
|
39
|
+
|
|
40
|
+
const config = await updateModelProviderConfigDefaultModel({
|
|
41
|
+
workspaceId,
|
|
42
|
+
providerId,
|
|
43
|
+
defaultModel: request.body.default_model,
|
|
44
|
+
});
|
|
31
45
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
46
|
+
return toModelProviderConfigResponseDto(config);
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
},
|
|
40
|
-
});
|
|
51
|
+
export const updateModelProviderDefaultModelRoute = createUpdateModelProviderDefaultModelRoute();
|
|
@@ -6,12 +6,19 @@ import {
|
|
|
6
6
|
import {requireWorkspaceAccess} from '@shipfox/api-auth-context';
|
|
7
7
|
import {defineRoute} from '@shipfox/node-fastify';
|
|
8
8
|
import {z} from 'zod';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
assertWorkspaceProviderConfigurationEnabled,
|
|
11
|
+
testAndSaveModelProviderConfig,
|
|
12
|
+
} from '#core/index.js';
|
|
10
13
|
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
14
|
+
import type {WorkspaceProviderPolicyOptions} from '#core/workspace-provider-policy.js';
|
|
11
15
|
import {toModelProviderConfigDto} from '#presentation/dto/index.js';
|
|
12
16
|
import {translateModelProviderRouteError} from './errors.js';
|
|
13
17
|
|
|
14
|
-
export function createUpsertModelProviderConfigRoute(
|
|
18
|
+
export function createUpsertModelProviderConfigRoute(
|
|
19
|
+
secrets: AgentSecretsClient,
|
|
20
|
+
workspaceProviderPolicy: WorkspaceProviderPolicyOptions = {workspaceProviders: 'enabled'},
|
|
21
|
+
) {
|
|
15
22
|
return defineRoute({
|
|
16
23
|
method: 'PUT',
|
|
17
24
|
path: '/model-providers/:providerId',
|
|
@@ -39,6 +46,7 @@ export function createUpsertModelProviderConfigRoute(secrets: AgentSecretsClient
|
|
|
39
46
|
});
|
|
40
47
|
|
|
41
48
|
const membership = requireWorkspaceAccess({request, workspaceId});
|
|
49
|
+
assertWorkspaceProviderConfigurationEnabled(workspaceProviderPolicy);
|
|
42
50
|
|
|
43
51
|
const config = await testAndSaveModelProviderConfig(
|
|
44
52
|
{
|