@shipfox/api-agent 12.2.0 → 14.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 +30 -0
- package/dist/config.d.ts +5 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +75 -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 +60 -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 +196 -4
- package/src/config.ts +100 -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 +289 -1
- package/src/core/resolve-runtime-credentials.ts +69 -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
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
HarnessDescriptor,
|
|
3
|
+
ManagedModelProvider,
|
|
4
|
+
WorkspaceProvidersPolicy,
|
|
5
|
+
} from '@shipfox/api-agent-dto';
|
|
1
6
|
import {
|
|
2
7
|
listEnabledHarnessTools,
|
|
3
8
|
listHarnessDescriptors,
|
|
@@ -8,27 +13,127 @@ import {harnessToolDeploymentConfig} from '#config.js';
|
|
|
8
13
|
import {listHarnessProviderModels} from './harness/index.js';
|
|
9
14
|
import {getModelProviderEntry} from './model-provider-policy.js';
|
|
10
15
|
|
|
16
|
+
type HarnessValidationCatalog = AgentValidationCatalog['harnesses'][number];
|
|
17
|
+
|
|
11
18
|
/** Produces the versioned, JSON-safe policy snapshot consumed by Definitions. */
|
|
12
|
-
export function getAgentValidationCatalog(
|
|
19
|
+
export function getAgentValidationCatalog(
|
|
20
|
+
managedProvider?: ManagedModelProvider | undefined,
|
|
21
|
+
workspaceProviders: WorkspaceProvidersPolicy = 'enabled',
|
|
22
|
+
): AgentValidationCatalog {
|
|
23
|
+
const managedOnly = workspaceProviders === 'disabled';
|
|
24
|
+
|
|
13
25
|
return {
|
|
14
26
|
version: 1,
|
|
15
|
-
providers:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
providers: buildValidationProviders(managedProvider, managedOnly),
|
|
28
|
+
harnesses: listHarnessDescriptors().map((harness) =>
|
|
29
|
+
buildHarnessValidationCatalog(harness, managedProvider, managedOnly),
|
|
30
|
+
),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function buildValidationProviders(
|
|
35
|
+
managedProvider: ManagedModelProvider | undefined,
|
|
36
|
+
managedOnly: boolean,
|
|
37
|
+
): AgentValidationCatalog['providers'] {
|
|
38
|
+
const providers: AgentValidationCatalog['providers'] = [];
|
|
39
|
+
|
|
40
|
+
if (!managedOnly) {
|
|
41
|
+
providers.push(
|
|
42
|
+
...MODEL_PROVIDER_IDS.map((id) => ({
|
|
43
|
+
id,
|
|
44
|
+
support_status: getModelProviderEntry(id)?.support_status ?? 'unsupported',
|
|
45
|
+
})),
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (managedProvider !== undefined) {
|
|
50
|
+
providers.push({id: managedProvider.id, support_status: 'supported'});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return providers;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function buildHarnessValidationCatalog(
|
|
57
|
+
harness: HarnessDescriptor,
|
|
58
|
+
managedProvider: ManagedModelProvider | undefined,
|
|
59
|
+
managedOnly: boolean,
|
|
60
|
+
): HarnessValidationCatalog {
|
|
61
|
+
const managedModels = getManagedModelsForHarness(harness, managedProvider);
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
id: harness.id,
|
|
65
|
+
supported_provider_ids: buildSupportedProviderIds(
|
|
66
|
+
harness,
|
|
67
|
+
managedProvider,
|
|
68
|
+
managedModels,
|
|
69
|
+
managedOnly,
|
|
70
|
+
),
|
|
71
|
+
model_ids_by_provider: buildModelIdsByProvider(
|
|
72
|
+
harness,
|
|
73
|
+
managedProvider,
|
|
74
|
+
managedModels,
|
|
75
|
+
managedOnly,
|
|
76
|
+
),
|
|
77
|
+
thinking_levels: [...harness.thinkingLevels],
|
|
78
|
+
effective_tools: listEnabledHarnessTools(harness.id, harnessToolDeploymentConfig).map(
|
|
79
|
+
(tool) => tool.name,
|
|
80
|
+
),
|
|
33
81
|
};
|
|
34
82
|
}
|
|
83
|
+
|
|
84
|
+
function buildSupportedProviderIds(
|
|
85
|
+
harness: HarnessDescriptor,
|
|
86
|
+
managedProvider: ManagedModelProvider | undefined,
|
|
87
|
+
managedModels: ManagedModelProvider['models'],
|
|
88
|
+
managedOnly: boolean,
|
|
89
|
+
): string[] {
|
|
90
|
+
if (managedOnly) {
|
|
91
|
+
if (managedProvider === undefined || managedModels.length === 0) return [];
|
|
92
|
+
return [managedProvider.id];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const providerIds = [...harness.supportedProviderIds];
|
|
96
|
+
if (managedProvider !== undefined && managedModels.length > 0) {
|
|
97
|
+
providerIds.push(managedProvider.id);
|
|
98
|
+
}
|
|
99
|
+
return providerIds;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function buildModelIdsByProvider(
|
|
103
|
+
harness: HarnessDescriptor,
|
|
104
|
+
managedProvider: ManagedModelProvider | undefined,
|
|
105
|
+
managedModels: ManagedModelProvider['models'],
|
|
106
|
+
managedOnly: boolean,
|
|
107
|
+
): Record<string, string[]> {
|
|
108
|
+
const modelIdsByProvider: Record<string, string[]> = {};
|
|
109
|
+
|
|
110
|
+
if (!managedOnly) {
|
|
111
|
+
for (const providerId of harness.supportedProviderIds) {
|
|
112
|
+
modelIdsByProvider[providerId] = listHarnessProviderModels(harness.id, providerId).map(
|
|
113
|
+
(model) => model.id,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (managedProvider !== undefined) {
|
|
119
|
+
modelIdsByProvider[managedProvider.id] = managedModels.map((model) => model.id);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return modelIdsByProvider;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getManagedModelsForHarness(
|
|
126
|
+
harness: HarnessDescriptor,
|
|
127
|
+
managedProvider: ManagedModelProvider | undefined,
|
|
128
|
+
): ManagedModelProvider['models'] {
|
|
129
|
+
if (managedProvider === undefined) return [];
|
|
130
|
+
return managedModelsForHarness(harness.id, managedProvider);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function managedModelsForHarness(
|
|
134
|
+
harness: 'pi' | 'claude',
|
|
135
|
+
managedProvider: ManagedModelProvider,
|
|
136
|
+
): ManagedModelProvider['models'] {
|
|
137
|
+
if (harness === 'pi') return managedProvider.models;
|
|
138
|
+
return managedProvider.models.filter((model) => model.api === 'anthropic-messages');
|
|
139
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AgentThinking,
|
|
3
|
+
ManagedModelProvider,
|
|
3
4
|
ModelProviderRef,
|
|
4
|
-
|
|
5
|
+
WorkspaceProvidersPolicy,
|
|
5
6
|
} from '@shipfox/api-agent-dto';
|
|
6
7
|
import {config} from '#config.js';
|
|
7
8
|
import {getAgentWorkspaceDefaultsSnapshot} from '#db/index.js';
|
|
@@ -10,6 +11,8 @@ import {resolveAgentConfig} from './resolve-agent-config.js';
|
|
|
10
11
|
|
|
11
12
|
export async function createWorkspaceAgentDefaultsResolver(
|
|
12
13
|
workspaceId: string,
|
|
14
|
+
managedProvider?: ManagedModelProvider | undefined,
|
|
15
|
+
workspaceProviders?: WorkspaceProvidersPolicy | undefined,
|
|
13
16
|
): Promise<AgentDefaultsResolver> {
|
|
14
17
|
const snapshot = await getAgentWorkspaceDefaultsSnapshot(workspaceId);
|
|
15
18
|
const workspaceProviderConfigs = new Map<
|
|
@@ -33,9 +36,11 @@ export async function createWorkspaceAgentDefaultsResolver(
|
|
|
33
36
|
workspaceDefaultHarnessId: snapshot.defaultHarnessId ?? null,
|
|
34
37
|
workspaceDefaultProviderId: snapshot.defaultProviderId ?? null,
|
|
35
38
|
workspaceProviderConfigs,
|
|
36
|
-
instanceDefaultProvider: config.AGENT_DEFAULT_PROVIDER
|
|
39
|
+
instanceDefaultProvider: config.AGENT_DEFAULT_PROVIDER,
|
|
37
40
|
instanceDefaultModel: config.AGENT_DEFAULT_PROVIDER_MODEL,
|
|
38
41
|
instanceDefaultThinking: config.AGENT_DEFAULT_PROVIDER_THINKING as AgentThinking | undefined,
|
|
42
|
+
managedProvider,
|
|
43
|
+
workspaceProviders,
|
|
39
44
|
};
|
|
40
45
|
|
|
41
46
|
return (step) => resolveAgentConfig(step, ctx);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type {WorkspaceProvidersPolicy} from '@shipfox/api-agent-dto';
|
|
2
|
+
import {WorkspaceProvidersDisabledError} from './errors.js';
|
|
3
|
+
|
|
4
|
+
export interface WorkspaceProviderPolicyOptions {
|
|
5
|
+
readonly workspaceProviders: WorkspaceProvidersPolicy;
|
|
6
|
+
readonly managedProviderId?: string | undefined;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function assertWorkspaceProviderConfigurationEnabled(
|
|
10
|
+
options: WorkspaceProviderPolicyOptions,
|
|
11
|
+
): void {
|
|
12
|
+
if (options.workspaceProviders !== 'disabled') return;
|
|
13
|
+
if (options.managedProviderId === undefined) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
'workspace provider configuration is disabled but no managed provider is registered',
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
throw new WorkspaceProvidersDisabledError(options.managedProviderId);
|
|
19
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type {ManagedModelProvider} from '@shipfox/api-agent-dto';
|
|
1
2
|
import type {ShipfoxModule} from '@shipfox/node-module';
|
|
3
|
+
import {assertAgentConfig, workspaceProvidersPolicy} from '#config.js';
|
|
2
4
|
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
3
5
|
import {db, migrationsPath} from '#db/index.js';
|
|
4
6
|
import {createAgentE2eRoutes} from '#presentation/e2eRoutes/index.js';
|
|
@@ -33,6 +35,7 @@ export {
|
|
|
33
35
|
testAndSaveModelProviderConfig,
|
|
34
36
|
UnsupportedModelProviderError,
|
|
35
37
|
updateCustomModelProviderConfig,
|
|
38
|
+
WorkspaceProvidersDisabledError,
|
|
36
39
|
} from '#core/index.js';
|
|
37
40
|
export {
|
|
38
41
|
getAgentWorkspaceSettings,
|
|
@@ -42,12 +45,30 @@ export {
|
|
|
42
45
|
upsertModelProviderConfig,
|
|
43
46
|
} from '#db/index.js';
|
|
44
47
|
|
|
45
|
-
export function createAgentModule(params: {
|
|
48
|
+
export function createAgentModule(params: {
|
|
49
|
+
secrets: AgentSecretsClient;
|
|
50
|
+
managedProvider?: ManagedModelProvider | undefined;
|
|
51
|
+
}): ShipfoxModule {
|
|
52
|
+
assertAgentConfig(params.managedProvider);
|
|
53
|
+
|
|
46
54
|
return {
|
|
47
55
|
name: 'agent',
|
|
48
56
|
database: {db, migrationsPath, databaseNamespace: 'agent'},
|
|
49
|
-
routes: createAgentRoutes(params.secrets
|
|
50
|
-
|
|
51
|
-
|
|
57
|
+
routes: createAgentRoutes(params.secrets, {
|
|
58
|
+
managedProvider: params.managedProvider,
|
|
59
|
+
workspaceProviders: workspaceProvidersPolicy,
|
|
60
|
+
}),
|
|
61
|
+
e2eRoutes: [
|
|
62
|
+
createAgentE2eRoutes(params.secrets, {
|
|
63
|
+
managedProviderId: params.managedProvider?.id,
|
|
64
|
+
workspaceProviders: workspaceProvidersPolicy,
|
|
65
|
+
}),
|
|
66
|
+
],
|
|
67
|
+
interModulePresentations: [
|
|
68
|
+
createAgentInterModulePresentation({
|
|
69
|
+
...params,
|
|
70
|
+
workspaceProviders: workspaceProvidersPolicy,
|
|
71
|
+
}),
|
|
72
|
+
],
|
|
52
73
|
};
|
|
53
74
|
}
|
|
@@ -3,9 +3,14 @@ import {ClientError, defineRoute} from '@shipfox/node-fastify';
|
|
|
3
3
|
import {z} from 'zod';
|
|
4
4
|
import {agentSystemNamespace} from '#core/credential-fingerprints.js';
|
|
5
5
|
import {listHarnessProviderModels} from '#core/harness/registry.js';
|
|
6
|
+
import {
|
|
7
|
+
assertWorkspaceProviderConfigurationEnabled,
|
|
8
|
+
type WorkspaceProviderPolicyOptions,
|
|
9
|
+
} from '#core/index.js';
|
|
6
10
|
import {getModelProviderEntry} from '#core/model-provider-policy.js';
|
|
7
11
|
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
8
12
|
import {upsertModelProviderConfig} from '#db/index.js';
|
|
13
|
+
import {translateModelProviderRouteError} from '#presentation/routes/errors.js';
|
|
9
14
|
|
|
10
15
|
const createE2eModelProviderBodySchema = z.object({
|
|
11
16
|
workspace_id: z.string().uuid(),
|
|
@@ -19,7 +24,10 @@ const createE2eModelProviderResponseSchema = z.object({
|
|
|
19
24
|
provider_id: z.literal('anthropic'),
|
|
20
25
|
});
|
|
21
26
|
|
|
22
|
-
export function createE2eModelProviderRoute(
|
|
27
|
+
export function createE2eModelProviderRoute(
|
|
28
|
+
secrets: AgentSecretsClient,
|
|
29
|
+
workspaceProviderPolicy: WorkspaceProviderPolicyOptions = {workspaceProviders: 'enabled'},
|
|
30
|
+
) {
|
|
23
31
|
return defineRoute({
|
|
24
32
|
method: 'POST',
|
|
25
33
|
path: '/model-provider',
|
|
@@ -28,7 +36,9 @@ export function createE2eModelProviderRoute(secrets: AgentSecretsClient) {
|
|
|
28
36
|
body: createE2eModelProviderBodySchema,
|
|
29
37
|
response: {201: createE2eModelProviderResponseSchema},
|
|
30
38
|
},
|
|
39
|
+
errorHandler: translateModelProviderRouteError,
|
|
31
40
|
handler: async (request, reply) => {
|
|
41
|
+
assertWorkspaceProviderConfigurationEnabled(workspaceProviderPolicy);
|
|
32
42
|
const entry = getModelProviderEntry(request.body.provider_id);
|
|
33
43
|
if (entry === undefined || entry.default_model === null) {
|
|
34
44
|
throw new ClientError('Unsupported E2E model provider', 'unsupported-model-provider', {
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import type {RouteGroup} from '@shipfox/node-fastify';
|
|
2
2
|
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
3
|
+
import type {WorkspaceProviderPolicyOptions} from '#core/workspace-provider-policy.js';
|
|
3
4
|
import {createE2eModelProviderRoute} from './create-model-provider.js';
|
|
4
5
|
|
|
5
|
-
export function createAgentE2eRoutes(
|
|
6
|
-
|
|
6
|
+
export function createAgentE2eRoutes(
|
|
7
|
+
secrets: AgentSecretsClient,
|
|
8
|
+
workspaceProviderPolicy: WorkspaceProviderPolicyOptions = {workspaceProviders: 'enabled'},
|
|
9
|
+
): RouteGroup {
|
|
10
|
+
return {
|
|
11
|
+
prefix: '/agent',
|
|
12
|
+
routes: [createE2eModelProviderRoute(secrets, workspaceProviderPolicy)],
|
|
13
|
+
};
|
|
7
14
|
}
|
|
8
15
|
|
|
9
16
|
export const agentE2eRoutes = createAgentE2eRoutes(undefined as unknown as AgentSecretsClient);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type {ManagedModelProvider} from '@shipfox/api-agent-dto';
|
|
2
|
+
import {agentInterModuleContract} from '@shipfox/api-agent-dto/inter-module';
|
|
3
|
+
import {isInterModuleKnownError} from '@shipfox/inter-module';
|
|
4
|
+
import {agentTestSecretsClient} from '#test/fixtures/secrets-client.js';
|
|
5
|
+
import {createAgentInterModulePresentation} from './inter-module.js';
|
|
6
|
+
|
|
7
|
+
describe('agent inter-module presentation', () => {
|
|
8
|
+
test('preserves managed provider policy details for runtime credentials', async () => {
|
|
9
|
+
const managedProvider: ManagedModelProvider = {
|
|
10
|
+
id: 'shipfox',
|
|
11
|
+
label: 'Shipfox',
|
|
12
|
+
models: [{id: 'managed-model', label: 'Managed model', api: 'openai-responses'}],
|
|
13
|
+
defaultModel: 'managed-model',
|
|
14
|
+
resolveCredentials: vi.fn(),
|
|
15
|
+
};
|
|
16
|
+
const presentation = createAgentInterModulePresentation({
|
|
17
|
+
secrets: agentTestSecretsClient,
|
|
18
|
+
managedProvider,
|
|
19
|
+
workspaceProviders: 'disabled',
|
|
20
|
+
});
|
|
21
|
+
const input = {
|
|
22
|
+
workspaceId: crypto.randomUUID(),
|
|
23
|
+
runId: crypto.randomUUID(),
|
|
24
|
+
stepAttemptId: crypto.randomUUID(),
|
|
25
|
+
harness: 'pi' as const,
|
|
26
|
+
provider: 'anthropic' as const,
|
|
27
|
+
model: 'claude-opus-4-8',
|
|
28
|
+
thinking: 'high' as const,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const result = await Promise.resolve(
|
|
32
|
+
presentation.handlers.resolveRuntimeCredentials(input, {
|
|
33
|
+
signal: new AbortController().signal,
|
|
34
|
+
}),
|
|
35
|
+
).catch((error: unknown) => error);
|
|
36
|
+
|
|
37
|
+
expect(
|
|
38
|
+
isInterModuleKnownError(agentInterModuleContract.methods.resolveRuntimeCredentials, result),
|
|
39
|
+
).toBe(true);
|
|
40
|
+
if (
|
|
41
|
+
!isInterModuleKnownError(agentInterModuleContract.methods.resolveRuntimeCredentials, result)
|
|
42
|
+
) {
|
|
43
|
+
throw new Error('Expected a managed provider policy error');
|
|
44
|
+
}
|
|
45
|
+
expect(result.code).toBe('workspace-providers-disabled');
|
|
46
|
+
expect(result.details).toEqual({
|
|
47
|
+
message: 'This instance only supports provider `shipfox`.',
|
|
48
|
+
managed_provider_id: 'shipfox',
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type {ManagedModelProvider, WorkspaceProvidersPolicy} from '@shipfox/api-agent-dto';
|
|
1
2
|
import {agentInterModuleContract} from '@shipfox/api-agent-dto/inter-module';
|
|
2
3
|
import {secretsInterModuleContract} from '@shipfox/api-secrets-dto/inter-module';
|
|
3
4
|
import {
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
UnsupportedHarnessProviderError,
|
|
13
14
|
UnsupportedHarnessThinkingError,
|
|
14
15
|
UnsupportedModelProviderError,
|
|
16
|
+
WorkspaceProvidersDisabledError,
|
|
15
17
|
} from '#core/errors.js';
|
|
16
18
|
import {resolveAgentConfig} from '#core/resolve-agent-config.js';
|
|
17
19
|
import {resolveRuntimeCredentials} from '#core/resolve-runtime-credentials.js';
|
|
@@ -21,15 +23,26 @@ import {createWorkspaceAgentDefaultsResolver} from '#core/workspace-agent-defaul
|
|
|
21
23
|
|
|
22
24
|
export function createAgentInterModulePresentation(params: {
|
|
23
25
|
secrets: AgentSecretsClient;
|
|
26
|
+
managedProvider?: ManagedModelProvider | undefined;
|
|
27
|
+
workspaceProviders?: WorkspaceProvidersPolicy | undefined;
|
|
24
28
|
}): InterModulePresentation<typeof agentInterModuleContract> {
|
|
25
29
|
return defineInterModulePresentation(agentInterModuleContract, {
|
|
26
|
-
getValidationCatalog: () =>
|
|
30
|
+
getValidationCatalog: () =>
|
|
31
|
+
getAgentValidationCatalog(params.managedProvider, params.workspaceProviders),
|
|
27
32
|
resolveAgentConfig: async ({workspaceId, config}) => {
|
|
28
33
|
try {
|
|
29
34
|
const resolve =
|
|
30
35
|
workspaceId === null
|
|
31
|
-
? resolveAgentConfig
|
|
32
|
-
|
|
36
|
+
? (step: Parameters<typeof resolveAgentConfig>[0]) =>
|
|
37
|
+
resolveAgentConfig(step, {
|
|
38
|
+
managedProvider: params.managedProvider,
|
|
39
|
+
workspaceProviders: params.workspaceProviders,
|
|
40
|
+
})
|
|
41
|
+
: await createWorkspaceAgentDefaultsResolver(
|
|
42
|
+
workspaceId,
|
|
43
|
+
params.managedProvider,
|
|
44
|
+
params.workspaceProviders,
|
|
45
|
+
);
|
|
33
46
|
return await resolve(config);
|
|
34
47
|
} catch (error) {
|
|
35
48
|
throw toResolveAgentConfigKnownError(error);
|
|
@@ -37,7 +50,11 @@ export function createAgentInterModulePresentation(params: {
|
|
|
37
50
|
},
|
|
38
51
|
resolveRuntimeCredentials: async (input) => {
|
|
39
52
|
try {
|
|
40
|
-
return await resolveRuntimeCredentials(input, {
|
|
53
|
+
return await resolveRuntimeCredentials(input, {
|
|
54
|
+
managedProvider: params.managedProvider,
|
|
55
|
+
secrets: params.secrets,
|
|
56
|
+
workspaceProviders: params.workspaceProviders,
|
|
57
|
+
});
|
|
41
58
|
} catch (error) {
|
|
42
59
|
throw toResolveRuntimeCredentialsKnownError(error);
|
|
43
60
|
}
|
|
@@ -50,18 +67,33 @@ function toResolveAgentConfigKnownError(error: unknown): unknown {
|
|
|
50
67
|
error instanceof InvalidAgentModelError ||
|
|
51
68
|
error instanceof UnsupportedHarnessProviderError ||
|
|
52
69
|
error instanceof UnsupportedHarnessThinkingError ||
|
|
53
|
-
error instanceof UnsupportedModelProviderError
|
|
70
|
+
error instanceof UnsupportedModelProviderError ||
|
|
71
|
+
error instanceof WorkspaceProvidersDisabledError
|
|
54
72
|
) {
|
|
55
73
|
return createInterModuleKnownError(
|
|
56
74
|
agentInterModuleContract.methods.resolveAgentConfig,
|
|
57
75
|
'agent-config-invalid',
|
|
58
|
-
{
|
|
76
|
+
{
|
|
77
|
+
...(error instanceof WorkspaceProvidersDisabledError
|
|
78
|
+
? {message: error.message, managed_provider_id: error.managedProviderId}
|
|
79
|
+
: {}),
|
|
80
|
+
},
|
|
59
81
|
);
|
|
60
82
|
}
|
|
61
83
|
return error;
|
|
62
84
|
}
|
|
63
85
|
|
|
64
86
|
function toResolveRuntimeCredentialsKnownError(error: unknown): unknown {
|
|
87
|
+
if (error instanceof WorkspaceProvidersDisabledError) {
|
|
88
|
+
return createInterModuleKnownError(
|
|
89
|
+
agentInterModuleContract.methods.resolveRuntimeCredentials,
|
|
90
|
+
'workspace-providers-disabled',
|
|
91
|
+
{
|
|
92
|
+
message: error.message,
|
|
93
|
+
managed_provider_id: error.managedProviderId,
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
}
|
|
65
97
|
if (error instanceof ModelProviderConfigNotFoundError) {
|
|
66
98
|
return createInterModuleKnownError(
|
|
67
99
|
agentInterModuleContract.methods.resolveRuntimeCredentials,
|
|
@@ -5,12 +5,19 @@ 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
|
+
createCustomModelProviderConfig,
|
|
11
|
+
} from '#core/index.js';
|
|
9
12
|
import type {AgentSecretsClient} from '#core/secrets-client.js';
|
|
13
|
+
import type {WorkspaceProviderPolicyOptions} from '#core/workspace-provider-policy.js';
|
|
10
14
|
import {toCustomModelProviderConfigDto} from '#presentation/dto/index.js';
|
|
11
15
|
import {translateModelProviderRouteError} from './errors.js';
|
|
12
16
|
|
|
13
|
-
export function createCustomModelProviderRoute(
|
|
17
|
+
export function createCustomModelProviderRoute(
|
|
18
|
+
secrets: AgentSecretsClient,
|
|
19
|
+
workspaceProviderPolicy: WorkspaceProviderPolicyOptions = {workspaceProviders: 'enabled'},
|
|
20
|
+
) {
|
|
14
21
|
return defineRoute({
|
|
15
22
|
method: 'POST',
|
|
16
23
|
path: '/custom-model-providers',
|
|
@@ -35,6 +42,7 @@ export function createCustomModelProviderRoute(secrets: AgentSecretsClient) {
|
|
|
35
42
|
});
|
|
36
43
|
|
|
37
44
|
requireWorkspaceAccess({request, workspaceId});
|
|
45
|
+
assertWorkspaceProviderConfigurationEnabled(workspaceProviderPolicy);
|
|
38
46
|
|
|
39
47
|
const config = await createCustomModelProviderConfig(
|
|
40
48
|
{
|
|
@@ -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,
|