@shipfox/api-agent 4.0.0 → 6.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 +1 -1
- package/CHANGELOG.md +48 -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 +19 -16
- 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 +10 -8
- 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 +30 -61
- package/src/core/custom-model-provider-config-service.ts +50 -34
- package/src/core/model-provider-config-service.test.ts +1 -3
- package/src/core/model-provider-config-service.ts +18 -15
- 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
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {DEFAULT_AGENT_THINKING, getModelProviderEntry} from '@shipfox/api-agent-dto';
|
|
2
|
-
import {setSecrets} from '@shipfox/api-secrets';
|
|
3
2
|
import {ClientError, defineRoute} from '@shipfox/node-fastify';
|
|
4
3
|
import {z} from 'zod';
|
|
5
4
|
import {agentSystemNamespace} from '#core/credential-fingerprints.js';
|
|
6
5
|
import {listHarnessProviderModels} from '#core/harness/registry.js';
|
|
6
|
+
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
7
7
|
import {upsertModelProviderConfig} from '#db/index.js';
|
|
8
8
|
|
|
9
9
|
const createE2eModelProviderBodySchema = z.object({
|
|
@@ -18,44 +18,46 @@ const createE2eModelProviderResponseSchema = z.object({
|
|
|
18
18
|
provider_id: z.literal('anthropic'),
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
export function createE2eModelProviderRoute(secrets: AgentSecretsClient) {
|
|
22
|
+
return defineRoute({
|
|
23
|
+
method: 'POST',
|
|
24
|
+
path: '/model-provider',
|
|
25
|
+
description: 'Create an Anthropic model provider config for E2E tests.',
|
|
26
|
+
schema: {
|
|
27
|
+
body: createE2eModelProviderBodySchema,
|
|
28
|
+
response: {201: createE2eModelProviderResponseSchema},
|
|
29
|
+
},
|
|
30
|
+
handler: async (request, reply) => {
|
|
31
|
+
const entry = getModelProviderEntry(request.body.provider_id);
|
|
32
|
+
if (entry === undefined || entry.default_model === null) {
|
|
33
|
+
throw new ClientError('Unsupported E2E model provider', 'unsupported-model-provider', {
|
|
34
|
+
status: 400,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const defaultModel = request.body.default_model ?? entry.default_model;
|
|
38
|
+
const supportedModels = listHarnessProviderModels('claude', request.body.provider_id);
|
|
39
|
+
if (!supportedModels.some((model) => model.id === defaultModel)) {
|
|
40
|
+
throw new ClientError('Unsupported Anthropic default model', 'unsupported-model', {
|
|
41
|
+
status: 400,
|
|
42
|
+
details: {default_model: defaultModel},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await secrets.setSecrets({
|
|
47
|
+
workspaceId: request.body.workspace_id,
|
|
48
|
+
namespace: agentSystemNamespace(request.body.provider_id),
|
|
49
|
+
values: {API_KEY: request.body.api_key},
|
|
34
50
|
});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
details: {default_model: defaultModel},
|
|
51
|
+
await upsertModelProviderConfig({
|
|
52
|
+
workspaceId: request.body.workspace_id,
|
|
53
|
+
providerId: request.body.provider_id,
|
|
54
|
+
defaultModel,
|
|
55
|
+
defaultThinking: DEFAULT_AGENT_THINKING,
|
|
56
|
+
setAsDefault: request.body.set_as_default,
|
|
42
57
|
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
await setSecrets({
|
|
46
|
-
workspaceId: request.body.workspace_id,
|
|
47
|
-
namespace: agentSystemNamespace(request.body.provider_id),
|
|
48
|
-
values: {API_KEY: request.body.api_key},
|
|
49
|
-
});
|
|
50
|
-
await upsertModelProviderConfig({
|
|
51
|
-
workspaceId: request.body.workspace_id,
|
|
52
|
-
providerId: request.body.provider_id,
|
|
53
|
-
defaultModel,
|
|
54
|
-
defaultThinking: DEFAULT_AGENT_THINKING,
|
|
55
|
-
setAsDefault: request.body.set_as_default,
|
|
56
|
-
});
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
});
|
|
59
|
+
reply.code(201);
|
|
60
|
+
return {provider_id: request.body.provider_id};
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type {RouteGroup} from '@shipfox/node-fastify';
|
|
2
|
+
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
2
3
|
import {createE2eModelProviderRoute} from './create-model-provider.js';
|
|
3
4
|
|
|
4
|
-
export
|
|
5
|
-
prefix: '/agent',
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
export function createAgentE2eRoutes(secrets: AgentSecretsClient): RouteGroup {
|
|
6
|
+
return {prefix: '/agent', routes: [createE2eModelProviderRoute(secrets)]};
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const agentE2eRoutes = createAgentE2eRoutes(undefined as unknown as AgentSecretsClient);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {agentRoutes as routes} from './routes/index.js';
|
|
1
|
+
export {agentRoutes as routes, createAgentRoutes} from './routes/index.js';
|
|
@@ -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
|
+
}
|