@shipfox/api-agent 5.0.0 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +43 -0
- package/dist/core/custom-model-provider-config-service.d.ts +4 -0
- package/dist/core/custom-model-provider-config-service.d.ts.map +1 -1
- package/dist/core/custom-model-provider-config-service.js +36 -17
- package/dist/core/custom-model-provider-config-service.js.map +1 -1
- package/dist/core/model-provider-config-service.d.ts +4 -0
- package/dist/core/model-provider-config-service.d.ts.map +1 -1
- package/dist/core/model-provider-config-service.js +27 -9
- package/dist/core/model-provider-config-service.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 +10 -5
- package/dist/core/resolve-runtime-credentials.js.map +1 -1
- package/dist/core/secrets-client.d.ts +4 -0
- package/dist/core/secrets-client.d.ts.map +1 -0
- package/dist/core/secrets-client.js +6 -0
- package/dist/core/secrets-client.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -13
- 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 +46 -45
- package/dist/presentation/e2eRoutes/create-model-provider.js.map +1 -1
- package/dist/presentation/e2eRoutes/index.d.ts +2 -0
- package/dist/presentation/e2eRoutes/index.d.ts.map +1 -1
- package/dist/presentation/e2eRoutes/index.js +9 -6
- package/dist/presentation/e2eRoutes/index.js.map +1 -1
- package/dist/presentation/index.d.ts +1 -1
- package/dist/presentation/index.d.ts.map +1 -1
- package/dist/presentation/index.js +1 -1
- package/dist/presentation/index.js.map +1 -1
- package/dist/presentation/inter-module.d.ts +7 -0
- package/dist/presentation/inter-module.d.ts.map +1 -0
- package/dist/presentation/inter-module.js +45 -0
- package/dist/presentation/inter-module.js.map +1 -0
- 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 +39 -35
- 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 +33 -29
- 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 +32 -28
- package/dist/presentation/routes/discover-custom-model-provider-models-by-slug.js.map +1 -1
- package/dist/presentation/routes/errors.d.ts.map +1 -1
- package/dist/presentation/routes/errors.js +13 -12
- package/dist/presentation/routes/errors.js.map +1 -1
- package/dist/presentation/routes/index.d.ts +2 -0
- package/dist/presentation/routes/index.d.ts.map +1 -1
- package/dist/presentation/routes/index.js +32 -29
- package/dist/presentation/routes/index.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 +41 -37
- package/dist/presentation/routes/update-custom-model-provider.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 +46 -42
- package/dist/presentation/routes/upsert-model-provider-config.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +12 -18
- package/src/core/custom-model-provider-config-service.ts +63 -35
- package/src/core/model-provider-config-service.test.ts +1 -3
- package/src/core/model-provider-config-service.ts +31 -16
- package/src/core/resolve-runtime-credentials.test.ts +3 -3
- package/src/core/resolve-runtime-credentials.ts +22 -8
- package/src/core/secrets-client.ts +13 -0
- package/src/index.ts +13 -8
- package/src/presentation/e2eRoutes/create-model-provider.ts +41 -39
- package/src/presentation/e2eRoutes/index.ts +6 -4
- package/src/presentation/index.ts +1 -1
- package/src/presentation/inter-module.ts +78 -0
- package/src/presentation/routes/create-custom-model-provider.ts +36 -30
- package/src/presentation/routes/delete-model-provider-config.ts +25 -22
- package/src/presentation/routes/discover-custom-model-provider-models-by-slug.ts +31 -25
- package/src/presentation/routes/errors.ts +11 -11
- package/src/presentation/routes/index.ts +32 -27
- package/src/presentation/routes/model-provider-config.test.ts +1 -1
- package/src/presentation/routes/update-custom-model-provider.ts +40 -34
- package/src/presentation/routes/upsert-model-provider-config.ts +43 -37
- package/test/fixtures/secrets-client.ts +80 -0
- package/test/globalSetup.ts +0 -9
- package/test/setup.ts +8 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {agentInterModuleContract} from '@shipfox/api-agent-dto/inter-module';
|
|
2
|
+
import {secretsInterModuleContract} from '@shipfox/api-secrets-dto/inter-module';
|
|
3
|
+
import {
|
|
4
|
+
createInterModuleKnownError,
|
|
5
|
+
defineInterModulePresentation,
|
|
6
|
+
type InterModulePresentation,
|
|
7
|
+
isInterModuleKnownError,
|
|
8
|
+
} from '@shipfox/inter-module';
|
|
9
|
+
import {
|
|
10
|
+
InvalidAgentModelError,
|
|
11
|
+
ModelProviderConfigNotFoundError,
|
|
12
|
+
UnsupportedHarnessProviderError,
|
|
13
|
+
UnsupportedHarnessThinkingError,
|
|
14
|
+
UnsupportedModelProviderError,
|
|
15
|
+
} from '#core/errors.js';
|
|
16
|
+
import {resolveAgentConfig} from '#core/resolve-agent-config.js';
|
|
17
|
+
import {resolveRuntimeCredentials} from '#core/resolve-runtime-credentials.js';
|
|
18
|
+
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
19
|
+
import {createWorkspaceAgentDefaultsResolver} from '#core/workspace-agent-defaults-resolver.js';
|
|
20
|
+
|
|
21
|
+
export function createAgentInterModulePresentation(params: {
|
|
22
|
+
secrets: AgentSecretsClient;
|
|
23
|
+
}): InterModulePresentation<typeof agentInterModuleContract> {
|
|
24
|
+
return defineInterModulePresentation(agentInterModuleContract, {
|
|
25
|
+
resolveAgentConfig: async ({workspaceId, config}) => {
|
|
26
|
+
try {
|
|
27
|
+
const resolve =
|
|
28
|
+
workspaceId === null
|
|
29
|
+
? resolveAgentConfig
|
|
30
|
+
: await createWorkspaceAgentDefaultsResolver(workspaceId);
|
|
31
|
+
return await resolve(config);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
throw toResolveAgentConfigKnownError(error);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
resolveRuntimeCredentials: async (input) => {
|
|
37
|
+
try {
|
|
38
|
+
return await resolveRuntimeCredentials(input, {secrets: params.secrets});
|
|
39
|
+
} catch (error) {
|
|
40
|
+
throw toResolveRuntimeCredentialsKnownError(error);
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function toResolveAgentConfigKnownError(error: unknown): unknown {
|
|
47
|
+
if (
|
|
48
|
+
error instanceof InvalidAgentModelError ||
|
|
49
|
+
error instanceof UnsupportedHarnessProviderError ||
|
|
50
|
+
error instanceof UnsupportedHarnessThinkingError ||
|
|
51
|
+
error instanceof UnsupportedModelProviderError
|
|
52
|
+
) {
|
|
53
|
+
return createInterModuleKnownError(
|
|
54
|
+
agentInterModuleContract.methods.resolveAgentConfig,
|
|
55
|
+
'agent-config-invalid',
|
|
56
|
+
{},
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return error;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function toResolveRuntimeCredentialsKnownError(error: unknown): unknown {
|
|
63
|
+
if (error instanceof ModelProviderConfigNotFoundError) {
|
|
64
|
+
return createInterModuleKnownError(
|
|
65
|
+
agentInterModuleContract.methods.resolveRuntimeCredentials,
|
|
66
|
+
'model-provider-not-configured',
|
|
67
|
+
{},
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
if (isInterModuleKnownError(secretsInterModuleContract.methods.getSecretsByNamespace, error)) {
|
|
71
|
+
return createInterModuleKnownError(
|
|
72
|
+
agentInterModuleContract.methods.resolveRuntimeCredentials,
|
|
73
|
+
'model-provider-credentials-invalid',
|
|
74
|
+
{},
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
return error;
|
|
78
|
+
}
|
|
@@ -6,40 +6,46 @@ import {requireWorkspaceAccess} from '@shipfox/api-auth-context';
|
|
|
6
6
|
import {defineRoute} from '@shipfox/node-fastify';
|
|
7
7
|
import {z} from 'zod';
|
|
8
8
|
import {createCustomModelProviderConfig} from '#core/index.js';
|
|
9
|
+
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
9
10
|
import {toCustomModelProviderConfigDto} from '#presentation/dto/index.js';
|
|
10
11
|
import {translateModelProviderRouteError} from './errors.js';
|
|
11
12
|
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
export function createCustomModelProviderRoute(secrets: AgentSecretsClient) {
|
|
14
|
+
return defineRoute({
|
|
15
|
+
method: 'POST',
|
|
16
|
+
path: '/custom-model-providers',
|
|
17
|
+
description: 'Create a custom model provider configuration for a workspace',
|
|
18
|
+
schema: {
|
|
19
|
+
params: z.object({workspaceId: z.string().uuid()}),
|
|
20
|
+
body: createCustomModelProviderBodySchema,
|
|
21
|
+
response: {
|
|
22
|
+
200: customModelProviderConfigDtoSchema,
|
|
23
|
+
},
|
|
21
24
|
},
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
});
|
|
25
|
+
errorHandler: translateModelProviderRouteError,
|
|
26
|
+
handler: async (request, reply) => {
|
|
27
|
+
const {workspaceId} = request.params;
|
|
28
|
+
const abortController = new AbortController();
|
|
29
|
+
let responseFinished = false;
|
|
30
|
+
reply.raw.on('finish', () => {
|
|
31
|
+
responseFinished = true;
|
|
32
|
+
});
|
|
33
|
+
reply.raw.on('close', () => {
|
|
34
|
+
if (!responseFinished) abortController.abort();
|
|
35
|
+
});
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
requireWorkspaceAccess({request, workspaceId});
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
const config = await createCustomModelProviderConfig(
|
|
40
|
+
{
|
|
41
|
+
workspaceId,
|
|
42
|
+
body: request.body,
|
|
43
|
+
signal: abortController.signal,
|
|
44
|
+
},
|
|
45
|
+
{secrets},
|
|
46
|
+
);
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
});
|
|
48
|
+
return toCustomModelProviderConfigDto(config);
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -3,29 +3,32 @@ import {requireWorkspaceAccess} from '@shipfox/api-auth-context';
|
|
|
3
3
|
import {ClientError, defineRoute} from '@shipfox/node-fastify';
|
|
4
4
|
import {z} from 'zod';
|
|
5
5
|
import {deleteModelProviderConfig} from '#core/index.js';
|
|
6
|
+
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
6
7
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
export function createDeleteModelProviderConfigRoute(secrets: AgentSecretsClient) {
|
|
9
|
+
return defineRoute({
|
|
10
|
+
method: 'DELETE',
|
|
11
|
+
path: '/model-providers/:providerId',
|
|
12
|
+
description: 'Delete a model provider configuration for a workspace',
|
|
13
|
+
schema: {
|
|
14
|
+
params: z.object({
|
|
15
|
+
workspaceId: z.string().uuid(),
|
|
16
|
+
providerId: modelProviderRefSchema,
|
|
17
|
+
}),
|
|
18
|
+
response: {
|
|
19
|
+
204: z.void(),
|
|
20
|
+
},
|
|
18
21
|
},
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
requireWorkspaceAccess({request, workspaceId});
|
|
22
|
+
handler: async (request, reply) => {
|
|
23
|
+
const {workspaceId, providerId} = request.params;
|
|
24
|
+
requireWorkspaceAccess({request, workspaceId});
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
const deleted = await deleteModelProviderConfig({workspaceId, providerId}, {secrets});
|
|
27
|
+
if (!deleted) {
|
|
28
|
+
throw new ClientError('Model provider configuration not found', 'not-found', {status: 404});
|
|
29
|
+
}
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
});
|
|
31
|
+
reply.code(204);
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -10,33 +10,39 @@ import {
|
|
|
10
10
|
discoverCustomModelProviderModels,
|
|
11
11
|
resolveCustomModelProviderDiscoveryParams,
|
|
12
12
|
} from '#core/index.js';
|
|
13
|
+
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
13
14
|
import {translateModelProviderRouteError} from './errors.js';
|
|
14
15
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
export function createDiscoverCustomModelProviderModelsBySlugRoute(secrets: AgentSecretsClient) {
|
|
17
|
+
return defineRoute({
|
|
18
|
+
method: 'POST',
|
|
19
|
+
path: '/custom-model-providers/:slug/discover-models',
|
|
20
|
+
description: 'Discover models for a stored custom model provider configuration',
|
|
21
|
+
schema: {
|
|
22
|
+
params: z.object({
|
|
23
|
+
workspaceId: z.string().uuid(),
|
|
24
|
+
slug: modelProviderRefSchema,
|
|
25
|
+
}),
|
|
26
|
+
body: discoverCustomModelProviderModelsBySlugBodySchema,
|
|
27
|
+
response: {
|
|
28
|
+
200: discoverCustomModelProviderModelsResponseSchema,
|
|
29
|
+
},
|
|
27
30
|
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
requireWorkspaceAccess({request, workspaceId});
|
|
31
|
+
errorHandler: translateModelProviderRouteError,
|
|
32
|
+
handler: async (request) => {
|
|
33
|
+
const {workspaceId, slug} = request.params;
|
|
34
|
+
requireWorkspaceAccess({request, workspaceId});
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
const discoveryParams = await resolveCustomModelProviderDiscoveryParams(
|
|
37
|
+
{
|
|
38
|
+
workspaceId,
|
|
39
|
+
providerId: slug,
|
|
40
|
+
body: request.body ?? {},
|
|
41
|
+
},
|
|
42
|
+
{secrets},
|
|
43
|
+
);
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
});
|
|
45
|
+
return await discoverCustomModelProviderModels(discoveryParams);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {getModelProviderCredentialKeys} from '@shipfox/api-agent-dto';
|
|
2
|
-
import {
|
|
2
|
+
import {secretsInterModuleContract} from '@shipfox/api-secrets-dto/inter-module';
|
|
3
|
+
import {isInterModuleKnownError} from '@shipfox/inter-module';
|
|
3
4
|
import {EgressDeniedError} from '@shipfox/node-egress-guard';
|
|
4
5
|
import {ClientError} from '@shipfox/node-fastify';
|
|
5
6
|
import {
|
|
@@ -104,17 +105,16 @@ export function translateModelProviderRouteError(error: unknown): never {
|
|
|
104
105
|
});
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
if (error
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
throw new ClientError(error.message, 'value-too-large', {
|
|
108
|
+
if (isInterModuleKnownError(secretsInterModuleContract.methods.setSecrets, error)) {
|
|
109
|
+
if (error.code === 'workspace-secret-cap-exceeded') {
|
|
110
|
+
throw new ClientError('Workspace secret cap exceeded', 'workspace-secret-cap-exceeded', {
|
|
111
|
+
status: 409,
|
|
112
|
+
details: {cap: error.details.cap},
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
throw new ClientError('Secret value is too large', 'value-too-large', {
|
|
116
116
|
status: 400,
|
|
117
|
-
details: {max_bytes: error.maxBytes},
|
|
117
|
+
details: {max_bytes: error.details.maxBytes},
|
|
118
118
|
});
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -1,37 +1,42 @@
|
|
|
1
1
|
import {AUTH_USER} from '@shipfox/api-auth-context';
|
|
2
2
|
import type {RouteGroup} from '@shipfox/node-fastify';
|
|
3
|
+
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
3
4
|
import {createCustomModelProviderRoute} from './create-custom-model-provider.js';
|
|
4
|
-
import {
|
|
5
|
+
import {createDeleteModelProviderConfigRoute} from './delete-model-provider-config.js';
|
|
5
6
|
import {discoverCustomModelProviderModelsRoute} from './discover-custom-model-provider-models.js';
|
|
6
|
-
import {
|
|
7
|
+
import {createDiscoverCustomModelProviderModelsBySlugRoute} from './discover-custom-model-provider-models-by-slug.js';
|
|
7
8
|
import {listModelProviderCatalogRoute} from './list-model-provider-catalog.js';
|
|
8
9
|
import {listModelProviderConfigsRoute} from './list-model-provider-configs.js';
|
|
9
10
|
import {setDefaultHarnessRoute} from './set-default-harness.js';
|
|
10
11
|
import {setDefaultModelProviderRoute} from './set-default-model-provider.js';
|
|
11
|
-
import {
|
|
12
|
+
import {createUpdateCustomModelProviderRoute} from './update-custom-model-provider.js';
|
|
12
13
|
import {updateModelProviderDefaultModelRoute} from './update-model-provider-default-model.js';
|
|
13
|
-
import {
|
|
14
|
+
import {createUpsertModelProviderConfigRoute} from './upsert-model-provider-config.js';
|
|
14
15
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
16
|
+
export function createAgentRoutes(secrets: AgentSecretsClient): RouteGroup[] {
|
|
17
|
+
return [
|
|
18
|
+
{
|
|
19
|
+
prefix: '/workspaces/:workspaceId/agent',
|
|
20
|
+
auth: AUTH_USER,
|
|
21
|
+
routes: [
|
|
22
|
+
listModelProviderConfigsRoute,
|
|
23
|
+
createCustomModelProviderRoute(secrets),
|
|
24
|
+
discoverCustomModelProviderModelsRoute,
|
|
25
|
+
createDiscoverCustomModelProviderModelsBySlugRoute(secrets),
|
|
26
|
+
createUpdateCustomModelProviderRoute(secrets),
|
|
27
|
+
createUpsertModelProviderConfigRoute(secrets),
|
|
28
|
+
updateModelProviderDefaultModelRoute,
|
|
29
|
+
createDeleteModelProviderConfigRoute(secrets),
|
|
30
|
+
setDefaultHarnessRoute,
|
|
31
|
+
setDefaultModelProviderRoute,
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
prefix: '/agent',
|
|
36
|
+
auth: AUTH_USER,
|
|
37
|
+
routes: [listModelProviderCatalogRoute],
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const agentRoutes = createAgentRoutes(undefined as unknown as AgentSecretsClient);
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
setUserContext,
|
|
7
7
|
type UserContextMembership,
|
|
8
8
|
} from '@shipfox/api-auth-context';
|
|
9
|
-
import {getSecretsByNamespace, setSecrets} from '@shipfox/api-secrets';
|
|
10
9
|
import type {AuthMethod, FastifyRequest} from '@shipfox/node-fastify';
|
|
11
10
|
import {ClientError, closeApp, createApp} from '@shipfox/node-fastify';
|
|
12
11
|
import {eq} from 'drizzle-orm';
|
|
@@ -20,6 +19,7 @@ import {
|
|
|
20
19
|
upsertModelProviderConfig,
|
|
21
20
|
} from '#db/index.js';
|
|
22
21
|
import {modelProviderConfigs} from '#db/schema/model-provider-configs.js';
|
|
22
|
+
import {getSecretsByNamespace, setSecrets} from '#test/fixtures/secrets-client.js';
|
|
23
23
|
import {agentRoutes} from './index.js';
|
|
24
24
|
|
|
25
25
|
vi.mock('@earendil-works/pi-ai', async (importOriginal) => {
|
|
@@ -7,44 +7,50 @@ import {requireWorkspaceAccess} from '@shipfox/api-auth-context';
|
|
|
7
7
|
import {defineRoute} from '@shipfox/node-fastify';
|
|
8
8
|
import {z} from 'zod';
|
|
9
9
|
import {updateCustomModelProviderConfig} from '#core/index.js';
|
|
10
|
+
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
10
11
|
import {toCustomModelProviderConfigDto} from '#presentation/dto/index.js';
|
|
11
12
|
import {translateModelProviderRouteError} from './errors.js';
|
|
12
13
|
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
export function createUpdateCustomModelProviderRoute(secrets: AgentSecretsClient) {
|
|
15
|
+
return defineRoute({
|
|
16
|
+
method: 'PUT',
|
|
17
|
+
path: '/custom-model-providers/:slug',
|
|
18
|
+
description: 'Update a custom model provider configuration for a workspace',
|
|
19
|
+
schema: {
|
|
20
|
+
params: z.object({
|
|
21
|
+
workspaceId: z.string().uuid(),
|
|
22
|
+
slug: modelProviderRefSchema,
|
|
23
|
+
}),
|
|
24
|
+
body: updateCustomModelProviderBodySchema,
|
|
25
|
+
response: {
|
|
26
|
+
200: customModelProviderConfigDtoSchema,
|
|
27
|
+
},
|
|
25
28
|
},
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
29
|
+
errorHandler: translateModelProviderRouteError,
|
|
30
|
+
handler: async (request, reply) => {
|
|
31
|
+
const {workspaceId, slug} = request.params;
|
|
32
|
+
const abortController = new AbortController();
|
|
33
|
+
let responseFinished = false;
|
|
34
|
+
reply.raw.on('finish', () => {
|
|
35
|
+
responseFinished = true;
|
|
36
|
+
});
|
|
37
|
+
reply.raw.on('close', () => {
|
|
38
|
+
if (!responseFinished) abortController.abort();
|
|
39
|
+
});
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
requireWorkspaceAccess({request, workspaceId});
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const config = await updateCustomModelProviderConfig(
|
|
44
|
+
{
|
|
45
|
+
workspaceId,
|
|
46
|
+
providerId: slug,
|
|
47
|
+
body: request.body,
|
|
48
|
+
signal: abortController.signal,
|
|
49
|
+
},
|
|
50
|
+
{secrets},
|
|
51
|
+
);
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
});
|
|
53
|
+
return toCustomModelProviderConfigDto(config);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
@@ -7,47 +7,53 @@ import {requireWorkspaceAccess} from '@shipfox/api-auth-context';
|
|
|
7
7
|
import {defineRoute} from '@shipfox/node-fastify';
|
|
8
8
|
import {z} from 'zod';
|
|
9
9
|
import {testAndSaveModelProviderConfig} from '#core/index.js';
|
|
10
|
+
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
10
11
|
import {toModelProviderConfigDto} from '#presentation/dto/index.js';
|
|
11
12
|
import {translateModelProviderRouteError} from './errors.js';
|
|
12
13
|
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
export function createUpsertModelProviderConfigRoute(secrets: AgentSecretsClient) {
|
|
15
|
+
return defineRoute({
|
|
16
|
+
method: 'PUT',
|
|
17
|
+
path: '/model-providers/:providerId',
|
|
18
|
+
description: 'Test and save a model provider configuration for a workspace',
|
|
19
|
+
schema: {
|
|
20
|
+
params: z.object({
|
|
21
|
+
workspaceId: z.string().uuid(),
|
|
22
|
+
providerId: supportedModelProviderIdSchema,
|
|
23
|
+
}),
|
|
24
|
+
body: updateModelProviderConfigBodySchema,
|
|
25
|
+
response: {
|
|
26
|
+
200: modelProviderConfigDtoSchema,
|
|
27
|
+
},
|
|
25
28
|
},
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
29
|
+
errorHandler: translateModelProviderRouteError,
|
|
30
|
+
handler: async (request, reply) => {
|
|
31
|
+
const {workspaceId, providerId} = request.params;
|
|
32
|
+
const abortController = new AbortController();
|
|
33
|
+
let responseFinished = false;
|
|
34
|
+
reply.raw.on('finish', () => {
|
|
35
|
+
responseFinished = true;
|
|
36
|
+
});
|
|
37
|
+
reply.raw.on('close', () => {
|
|
38
|
+
if (!responseFinished) abortController.abort();
|
|
39
|
+
});
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
const membership = requireWorkspaceAccess({request, workspaceId});
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
const config = await testAndSaveModelProviderConfig(
|
|
44
|
+
{
|
|
45
|
+
workspaceId,
|
|
46
|
+
providerId,
|
|
47
|
+
...('default_model' in request.body ? {defaultModel: request.body.default_model} : {}),
|
|
48
|
+
credentials: request.body.credentials,
|
|
49
|
+
editedBy: membership.userId,
|
|
50
|
+
setAsDefault: request.body.set_as_default,
|
|
51
|
+
signal: abortController.signal,
|
|
52
|
+
},
|
|
53
|
+
{secrets},
|
|
54
|
+
);
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
});
|
|
56
|
+
return toModelProviderConfigDto(config);
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|