@shipfox/client-agent 5.0.0 → 6.0.2
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 +57 -0
- package/dist/components/available-provider-card.d.ts +2 -2
- package/dist/components/available-provider-card.d.ts.map +1 -1
- package/dist/components/available-provider-card.js.map +1 -1
- package/dist/components/available-providers-grid.d.ts +2 -2
- package/dist/components/available-providers-grid.d.ts.map +1 -1
- package/dist/components/available-providers-grid.js +1 -1
- package/dist/components/available-providers-grid.js.map +1 -1
- package/dist/components/change-default-model-form.d.ts +3 -4
- package/dist/components/change-default-model-form.d.ts.map +1 -1
- package/dist/components/change-default-model-form.js +2 -4
- package/dist/components/change-default-model-form.js.map +1 -1
- package/dist/components/custom-model-provider-api-options.d.ts +3 -3
- package/dist/components/custom-model-provider-api-options.d.ts.map +1 -1
- package/dist/components/custom-model-provider-api-options.js.map +1 -1
- package/dist/components/custom-model-provider-form.d.ts +2 -2
- package/dist/components/custom-model-provider-form.d.ts.map +1 -1
- package/dist/components/custom-model-provider-form.js +12 -10
- package/dist/components/custom-model-provider-form.js.map +1 -1
- package/dist/components/custom-model-provider-form.stories.d.ts.map +1 -1
- package/dist/components/custom-model-provider-form.stories.js +11 -11
- package/dist/components/custom-model-provider-form.stories.js.map +1 -1
- package/dist/components/custom-model-provider-payload.d.ts +9 -9
- package/dist/components/custom-model-provider-payload.d.ts.map +1 -1
- package/dist/components/custom-model-provider-payload.js +42 -26
- package/dist/components/custom-model-provider-payload.js.map +1 -1
- package/dist/components/custom-model-provider-slug.d.ts +1 -1
- package/dist/components/custom-model-provider-slug.d.ts.map +1 -1
- package/dist/components/custom-model-provider-slug.js +3 -3
- package/dist/components/custom-model-provider-slug.js.map +1 -1
- package/dist/components/default-model-field.d.ts +2 -2
- package/dist/components/default-model-field.d.ts.map +1 -1
- package/dist/components/default-model-field.js +1 -1
- package/dist/components/default-model-field.js.map +1 -1
- package/dist/components/harness-availability.d.ts +4 -7
- package/dist/components/harness-availability.d.ts.map +1 -1
- package/dist/components/harness-availability.js +2 -11
- package/dist/components/harness-availability.js.map +1 -1
- package/dist/components/harnesses-section.d.ts.map +1 -1
- package/dist/components/harnesses-section.js +4 -6
- package/dist/components/harnesses-section.js.map +1 -1
- package/dist/components/model-provider-usage-modal.d.ts +2 -2
- package/dist/components/model-provider-usage-modal.d.ts.map +1 -1
- package/dist/components/model-provider-usage-modal.js +4 -4
- package/dist/components/model-provider-usage-modal.js.map +1 -1
- package/dist/components/model-provider-usage-modal.stories.d.ts.map +1 -1
- package/dist/components/model-provider-usage-modal.stories.js +14 -16
- package/dist/components/model-provider-usage-modal.stories.js.map +1 -1
- package/dist/components/model-provider-usage-target.d.ts +5 -5
- package/dist/components/model-provider-usage-target.d.ts.map +1 -1
- package/dist/components/model-provider-usage-target.js +10 -8
- package/dist/components/model-provider-usage-target.js.map +1 -1
- package/dist/components/model-providers-section.d.ts.map +1 -1
- package/dist/components/model-providers-section.js +112 -94
- package/dist/components/model-providers-section.js.map +1 -1
- package/dist/components/model-providers-section.stories.js +8 -4
- package/dist/components/model-providers-section.stories.js.map +1 -1
- package/dist/components/test-and-save-form.d.ts +3 -3
- package/dist/components/test-and-save-form.d.ts.map +1 -1
- package/dist/components/test-and-save-form.js +7 -7
- package/dist/components/test-and-save-form.js.map +1 -1
- package/dist/core/harness-policy.d.ts +11 -0
- package/dist/core/harness-policy.d.ts.map +1 -0
- package/dist/core/harness-policy.js +71 -0
- package/dist/core/harness-policy.js.map +1 -0
- package/dist/core/model-provider-management-reducer.d.ts +51 -0
- package/dist/core/model-provider-management-reducer.d.ts.map +1 -0
- package/dist/core/model-provider-management-reducer.js +43 -0
- package/dist/core/model-provider-management-reducer.js.map +1 -0
- package/dist/core/models.d.ts +120 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +3 -0
- package/dist/core/models.js.map +1 -0
- package/dist/core/onboarding-reducer.d.ts +36 -0
- package/dist/core/onboarding-reducer.d.ts.map +1 -0
- package/dist/core/onboarding-reducer.js +54 -0
- package/dist/core/onboarding-reducer.js.map +1 -0
- package/dist/core/provider-policy.d.ts +9 -0
- package/dist/core/provider-policy.d.ts.map +1 -0
- package/dist/core/provider-policy.js +37 -0
- package/dist/core/provider-policy.js.map +1 -0
- package/dist/feature.d.ts +7 -0
- package/dist/feature.d.ts.map +1 -1
- package/dist/feature.js +10 -9
- package/dist/feature.js.map +1 -1
- package/dist/hooks/api/model-provider-command-mapper.d.ts +11 -0
- package/dist/hooks/api/model-provider-command-mapper.d.ts.map +1 -0
- package/dist/hooks/api/model-provider-command-mapper.js +144 -0
- package/dist/hooks/api/model-provider-command-mapper.js.map +1 -0
- package/dist/hooks/api/model-provider-mapper.d.ts +11 -0
- package/dist/hooks/api/model-provider-mapper.d.ts.map +1 -0
- package/dist/hooks/api/model-provider-mapper.js +94 -0
- package/dist/hooks/api/model-provider-mapper.js.map +1 -0
- package/dist/hooks/api/model-providers.d.ts +60 -295
- package/dist/hooks/api/model-providers.d.ts.map +1 -1
- package/dist/hooks/api/model-providers.js +51 -37
- package/dist/hooks/api/model-providers.js.map +1 -1
- package/dist/pages/model-provider-onboarding-page.d.ts.map +1 -1
- package/dist/pages/model-provider-onboarding-page.js +57 -45
- package/dist/pages/model-provider-onboarding-page.js.map +1 -1
- package/dist/routes/inputs.d.ts +4 -0
- package/dist/routes/inputs.d.ts.map +1 -0
- package/dist/routes/inputs.js +12 -0
- package/dist/routes/inputs.js.map +1 -0
- package/dist/routes/model-provider.d.ts.map +1 -1
- package/dist/routes/model-provider.js +4 -5
- package/dist/routes/model-provider.js.map +1 -1
- package/dist/state/model-provider-onboarding.d.ts.map +1 -1
- package/dist/state/model-provider-onboarding.js +9 -18
- package/dist/state/model-provider-onboarding.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +9 -10
- package/src/components/available-provider-card.tsx +2 -2
- package/src/components/available-providers-grid.tsx +3 -3
- package/src/components/change-default-model-form.tsx +5 -6
- package/src/components/custom-model-provider-api-options.ts +3 -3
- package/src/components/custom-model-provider-form.stories.tsx +13 -13
- package/src/components/custom-model-provider-form.tsx +19 -12
- package/src/components/custom-model-provider-payload.test.ts +22 -22
- package/src/components/custom-model-provider-payload.ts +69 -54
- package/src/components/custom-model-provider-slug.test.ts +1 -1
- package/src/components/custom-model-provider-slug.ts +6 -3
- package/src/components/default-model-field.tsx +5 -5
- package/src/components/harness-availability.test.ts +13 -10
- package/src/components/harness-availability.ts +4 -28
- package/src/components/harnesses-section.tsx +7 -11
- package/src/components/model-provider-usage-modal.stories.tsx +18 -23
- package/src/components/model-provider-usage-modal.test.tsx +35 -7
- package/src/components/model-provider-usage-modal.tsx +12 -16
- package/src/components/model-provider-usage-target.ts +15 -18
- package/src/components/model-providers-section.stories.tsx +4 -1
- package/src/components/model-providers-section.tsx +112 -125
- package/src/components/test-and-save-form.tsx +13 -17
- package/src/core/harness-policy.test.ts +15 -0
- package/src/core/harness-policy.ts +83 -0
- package/src/core/model-provider-management-reducer.test.ts +59 -0
- package/src/core/model-provider-management-reducer.ts +72 -0
- package/src/core/models.ts +143 -0
- package/src/core/onboarding-reducer.test.ts +44 -0
- package/src/core/onboarding-reducer.ts +64 -0
- package/src/core/provider-policy.ts +53 -0
- package/src/feature.ts +12 -10
- package/src/hooks/api/model-provider-command-mapper.ts +122 -0
- package/src/hooks/api/model-provider-mapper.test.ts +27 -0
- package/src/hooks/api/model-provider-mapper.ts +120 -0
- package/src/hooks/api/model-providers.test.ts +15 -15
- package/src/hooks/api/model-providers.ts +146 -81
- package/src/pages/model-provider-onboarding-page.tsx +62 -56
- package/src/routes/inputs.test.ts +11 -0
- package/src/routes/inputs.ts +9 -0
- package/src/routes/model-provider.tsx +4 -3
- package/src/state/model-provider-onboarding.test.ts +4 -4
- package/src/state/model-provider-onboarding.ts +13 -23
- package/test/fixtures/model-providers.ts +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/vercel.json +5 -0
- package/dist/components/provider-search.d.ts +0 -4
- package/dist/components/provider-search.d.ts.map +0 -1
- package/dist/components/provider-search.js +0 -13
- package/dist/components/provider-search.js.map +0 -1
- package/dist/components/supported-model-provider-catalog-entry.d.ts +0 -8
- package/dist/components/supported-model-provider-catalog-entry.d.ts.map +0 -1
- package/dist/components/supported-model-provider-catalog-entry.js +0 -9
- package/dist/components/supported-model-provider-catalog-entry.js.map +0 -1
- package/src/components/provider-search.test.ts +0 -45
- package/src/components/provider-search.ts +0 -18
- package/src/components/supported-model-provider-catalog-entry.ts +0 -19
|
@@ -11,7 +11,9 @@ import { toast } from '@shipfox/react-ui/toast';
|
|
|
11
11
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/tooltip';
|
|
12
12
|
import { Header, Text } from '@shipfox/react-ui/typography';
|
|
13
13
|
import { cn } from '@shipfox/react-ui/utils';
|
|
14
|
-
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
14
|
+
import { useEffect, useMemo, useReducer, useRef, useState } from 'react';
|
|
15
|
+
import { managementModalReducer } from '#core/model-provider-management-reducer.js';
|
|
16
|
+
import { customProviderCardMatchesSearch, isSupportedProvider, availableProviders as selectAvailableProviders } from '#core/provider-policy.js';
|
|
15
17
|
import { useDeleteModelProviderConfigMutation, useModelProviderCatalogQuery, useModelProviderConfigsQuery, useSetDefaultModelProviderMutation } from '#hooks/api/model-providers.js';
|
|
16
18
|
import { AddCustomProviderCard } from './add-custom-provider-card.js';
|
|
17
19
|
import { AvailableProvidersGrid, PROVIDER_GRID_CLASS } from './available-providers-grid.js';
|
|
@@ -20,56 +22,56 @@ import { CustomModelProviderForm } from './custom-model-provider-form.js';
|
|
|
20
22
|
import { modelProviderConfigErrorToFormError } from './form-errors.js';
|
|
21
23
|
import { ModelProviderUsageModal } from './model-provider-usage-modal.js';
|
|
22
24
|
import { usageTargetFromCatalogEntry, usageTargetFromCustomConfig } from './model-provider-usage-target.js';
|
|
23
|
-
import { customProviderCardMatchesSearch } from './provider-search.js';
|
|
24
|
-
import { isSupportedCatalogEntry, toSupportedCatalogEntry } from './supported-model-provider-catalog-entry.js';
|
|
25
25
|
import { ModelProviderTestAndSaveForm } from './test-and-save-form.js';
|
|
26
26
|
const SURFACE_CLASS = 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';
|
|
27
27
|
const USAGE_MODAL_OPEN_DELAY_MS = 250;
|
|
28
28
|
export function WorkspaceModelProvidersSection({ workspaceId }) {
|
|
29
29
|
const catalogQuery = useModelProviderCatalogQuery();
|
|
30
30
|
const configsQuery = useModelProviderConfigsQuery(workspaceId);
|
|
31
|
-
const [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const [usageTarget, setUsageTarget] = useState(null);
|
|
31
|
+
const [modal, dispatchModal] = useReducer(managementModalReducer, {
|
|
32
|
+
kind: 'closed'
|
|
33
|
+
});
|
|
35
34
|
const [pendingUsageTarget, setPendingUsageTarget] = useState(null);
|
|
36
35
|
const configuredProvidersRegionRef = useRef(null);
|
|
37
36
|
const providers = catalogQuery.data?.providers ?? [];
|
|
38
37
|
const configs = configsQuery.data?.configs ?? [];
|
|
39
38
|
const configsLoaded = configsQuery.data !== undefined;
|
|
40
|
-
const defaultProviderId = configsQuery.data?.
|
|
39
|
+
const defaultProviderId = configsQuery.data?.defaultProviderId ?? null;
|
|
41
40
|
const providerById = useMemo(()=>new Map(providers.map((provider)=>[
|
|
42
41
|
provider.id,
|
|
43
42
|
provider
|
|
44
43
|
])), [
|
|
45
44
|
providers
|
|
46
45
|
]);
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
]);
|
|
50
|
-
const availableProviders = configsLoaded ? providers.filter((provider)=>isSupportedCatalogEntry(provider) && !configuredIds.has(provider.id)) : [];
|
|
51
|
-
const unsupportedProviders = providers.filter((provider)=>provider.support_status === 'unsupported');
|
|
52
|
-
function closeForm() {
|
|
53
|
-
setFormState(null);
|
|
54
|
-
}
|
|
55
|
-
function closeModelForm() {
|
|
56
|
-
setModelFormState(null);
|
|
57
|
-
}
|
|
58
|
-
function closeCustomForm() {
|
|
59
|
-
setCustomFormState(null);
|
|
60
|
-
}
|
|
46
|
+
const availableProviders = configsLoaded ? selectAvailableProviders(providers, configs) : [];
|
|
47
|
+
const unsupportedProviders = providers.filter((provider)=>!isSupportedProvider(provider));
|
|
61
48
|
useEffect(()=>{
|
|
62
|
-
if (pendingUsageTarget === null ||
|
|
49
|
+
if (pendingUsageTarget === null || modal.kind !== 'closed') return undefined;
|
|
63
50
|
const timer = window.setTimeout(()=>{
|
|
64
|
-
|
|
51
|
+
dispatchModal({
|
|
52
|
+
type: 'show-usage',
|
|
53
|
+
providerId: pendingUsageTarget.target.id,
|
|
54
|
+
initialModel: pendingUsageTarget.initialModel,
|
|
55
|
+
restoreFocusToConfiguredProviders: pendingUsageTarget.restoreFocusToConfiguredProviders
|
|
56
|
+
});
|
|
65
57
|
setPendingUsageTarget(null);
|
|
66
58
|
}, USAGE_MODAL_OPEN_DELAY_MS);
|
|
67
59
|
return ()=>window.clearTimeout(timer);
|
|
68
60
|
}, [
|
|
69
|
-
|
|
70
|
-
formState,
|
|
61
|
+
modal.kind,
|
|
71
62
|
pendingUsageTarget
|
|
72
63
|
]);
|
|
64
|
+
const usageTarget = useMemo(()=>{
|
|
65
|
+
if (modal.kind !== 'show-usage') return null;
|
|
66
|
+
const config = configs.find((item)=>item.providerId === modal.providerId);
|
|
67
|
+
if (config?.kind === 'custom') return usageTargetFromCustomConfig(config);
|
|
68
|
+
const entry = providerById.get(modal.providerId);
|
|
69
|
+
return entry && isSupportedProvider(entry) ? usageTargetFromCatalogEntry(entry) : null;
|
|
70
|
+
}, [
|
|
71
|
+
configs,
|
|
72
|
+
modal,
|
|
73
|
+
providerById
|
|
74
|
+
]);
|
|
73
75
|
return /*#__PURE__*/ _jsxs("div", {
|
|
74
76
|
className: "flex min-w-0 flex-col gap-32",
|
|
75
77
|
children: [
|
|
@@ -114,52 +116,56 @@ export function WorkspaceModelProvidersSection({ workspaceId }) {
|
|
|
114
116
|
configs.length > 0 ? /*#__PURE__*/ _jsx("ul", {
|
|
115
117
|
className: cn('divide-y divide-border-neutral-base', SURFACE_CLASS),
|
|
116
118
|
children: configs.map((config)=>{
|
|
117
|
-
const
|
|
119
|
+
const catalogEntry = providerById.get(config.providerId);
|
|
120
|
+
const entry = catalogEntry && isSupportedProvider(catalogEntry) ? catalogEntry : undefined;
|
|
118
121
|
const builtinConfig = isBuiltinModelProviderConfig(config) ? config : undefined;
|
|
119
122
|
const customConfig = isCustomModelProviderConfig(config) ? config : undefined;
|
|
120
123
|
return /*#__PURE__*/ _jsx(ConfiguredProviderRow, {
|
|
121
124
|
workspaceId: workspaceId,
|
|
122
125
|
config: config,
|
|
123
126
|
entry: entry,
|
|
124
|
-
isDefault: config.
|
|
127
|
+
isDefault: config.providerId === defaultProviderId,
|
|
125
128
|
onEdit: ()=>{
|
|
126
129
|
if (entry && builtinConfig) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
entry,
|
|
130
|
+
dispatchModal({
|
|
131
|
+
type: 'edit-builtin',
|
|
132
|
+
provider: entry,
|
|
130
133
|
config: builtinConfig
|
|
131
134
|
});
|
|
132
135
|
} else if (customConfig) {
|
|
133
|
-
|
|
134
|
-
|
|
136
|
+
dispatchModal({
|
|
137
|
+
type: 'edit-custom',
|
|
135
138
|
config: customConfig
|
|
136
139
|
});
|
|
137
140
|
}
|
|
138
141
|
},
|
|
139
142
|
onChangeDefaultModel: ()=>{
|
|
140
|
-
if (entry && builtinConfig)
|
|
141
|
-
|
|
143
|
+
if (entry && builtinConfig) dispatchModal({
|
|
144
|
+
type: 'change-default-model',
|
|
145
|
+
provider: entry,
|
|
142
146
|
config: builtinConfig
|
|
143
147
|
});
|
|
144
148
|
},
|
|
145
149
|
onShowUsage: ()=>{
|
|
146
150
|
if (entry && builtinConfig) {
|
|
147
151
|
setPendingUsageTarget(null);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
dispatchModal({
|
|
153
|
+
type: 'show-usage',
|
|
154
|
+
providerId: entry.id,
|
|
155
|
+
initialModel: builtinConfig.defaultModel,
|
|
151
156
|
restoreFocusToConfiguredProviders: false
|
|
152
157
|
});
|
|
153
158
|
} else if (customConfig) {
|
|
154
159
|
setPendingUsageTarget(null);
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
160
|
+
dispatchModal({
|
|
161
|
+
type: 'show-usage',
|
|
162
|
+
providerId: customConfig.providerId,
|
|
163
|
+
initialModel: customConfig.defaultModel,
|
|
158
164
|
restoreFocusToConfiguredProviders: false
|
|
159
165
|
});
|
|
160
166
|
}
|
|
161
167
|
}
|
|
162
|
-
}, config.
|
|
168
|
+
}, config.providerId);
|
|
163
169
|
})
|
|
164
170
|
}) : null
|
|
165
171
|
]
|
|
@@ -192,13 +198,13 @@ export function WorkspaceModelProvidersSection({ workspaceId }) {
|
|
|
192
198
|
}) : null,
|
|
193
199
|
configsLoaded ? /*#__PURE__*/ _jsx(AvailableProvidersGrid, {
|
|
194
200
|
entries: availableProviders,
|
|
195
|
-
onSelect: (entry)=>
|
|
196
|
-
|
|
197
|
-
entry
|
|
201
|
+
onSelect: (entry)=>dispatchModal({
|
|
202
|
+
type: 'configure-builtin',
|
|
203
|
+
provider: entry
|
|
198
204
|
}),
|
|
199
205
|
trailingCard: /*#__PURE__*/ _jsx(AddCustomProviderCard, {
|
|
200
|
-
onConfigure: ()=>
|
|
201
|
-
|
|
206
|
+
onConfigure: ()=>dispatchModal({
|
|
207
|
+
type: 'create-custom'
|
|
202
208
|
})
|
|
203
209
|
}),
|
|
204
210
|
trailingCardMatchesSearch: customProviderCardMatchesSearch
|
|
@@ -248,7 +254,7 @@ export function WorkspaceModelProvidersSection({ workspaceId }) {
|
|
|
248
254
|
/*#__PURE__*/ _jsx(Text, {
|
|
249
255
|
size: "sm",
|
|
250
256
|
className: "text-foreground-neutral-muted",
|
|
251
|
-
children: entry.
|
|
257
|
+
children: entry.unsupportedReason
|
|
252
258
|
})
|
|
253
259
|
]
|
|
254
260
|
})
|
|
@@ -258,45 +264,51 @@ export function WorkspaceModelProvidersSection({ workspaceId }) {
|
|
|
258
264
|
]
|
|
259
265
|
}),
|
|
260
266
|
/*#__PURE__*/ _jsx(Modal, {
|
|
261
|
-
open:
|
|
262
|
-
onOpenChange: (open)=>open ? undefined :
|
|
267
|
+
open: modal.kind === 'configure-builtin' || modal.kind === 'edit-builtin',
|
|
268
|
+
onOpenChange: (open)=>open ? undefined : dispatchModal({
|
|
269
|
+
type: 'close'
|
|
270
|
+
}),
|
|
263
271
|
children: /*#__PURE__*/ _jsxs(ModalContent, {
|
|
264
272
|
"aria-describedby": undefined,
|
|
265
273
|
children: [
|
|
266
274
|
/*#__PURE__*/ _jsx(ModalTitle, {
|
|
267
275
|
className: "sr-only",
|
|
268
|
-
children: modelProviderFormTitle(
|
|
276
|
+
children: modelProviderFormTitle(modal)
|
|
269
277
|
}),
|
|
270
278
|
/*#__PURE__*/ _jsx(ModalHeader, {
|
|
271
279
|
children: /*#__PURE__*/ _jsx(Text, {
|
|
272
280
|
size: "lg",
|
|
273
281
|
"aria-hidden": "true",
|
|
274
282
|
className: "overflow-ellipsis overflow-hidden whitespace-nowrap",
|
|
275
|
-
children: modelProviderFormTitle(
|
|
283
|
+
children: modelProviderFormTitle(modal)
|
|
276
284
|
})
|
|
277
285
|
}),
|
|
278
|
-
|
|
286
|
+
modal.kind === 'configure-builtin' || modal.kind === 'edit-builtin' ? /*#__PURE__*/ _jsx(ModelProviderTestAndSaveForm, {
|
|
279
287
|
workspaceId: workspaceId,
|
|
280
|
-
entry:
|
|
281
|
-
existingConfig:
|
|
288
|
+
entry: modal.provider,
|
|
289
|
+
existingConfig: modal.kind === 'edit-builtin' ? modal.config : undefined,
|
|
282
290
|
onSaved: (savedDefaultModel)=>{
|
|
283
|
-
toast.success(`${
|
|
284
|
-
if (
|
|
291
|
+
toast.success(`${modal.provider.label} saved`);
|
|
292
|
+
if (modal.kind === 'configure-builtin' && configs.length === 0) {
|
|
285
293
|
setPendingUsageTarget({
|
|
286
|
-
target: usageTargetFromCatalogEntry(
|
|
294
|
+
target: usageTargetFromCatalogEntry(modal.provider),
|
|
287
295
|
initialModel: savedDefaultModel,
|
|
288
296
|
restoreFocusToConfiguredProviders: true
|
|
289
297
|
});
|
|
290
298
|
}
|
|
291
|
-
|
|
299
|
+
dispatchModal({
|
|
300
|
+
type: 'close'
|
|
301
|
+
});
|
|
292
302
|
}
|
|
293
303
|
}) : null
|
|
294
304
|
]
|
|
295
305
|
})
|
|
296
306
|
}),
|
|
297
307
|
/*#__PURE__*/ _jsx(Modal, {
|
|
298
|
-
open:
|
|
299
|
-
onOpenChange: (open)=>open ? undefined :
|
|
308
|
+
open: modal.kind === 'change-default-model',
|
|
309
|
+
onOpenChange: (open)=>open ? undefined : dispatchModal({
|
|
310
|
+
type: 'close'
|
|
311
|
+
}),
|
|
300
312
|
children: /*#__PURE__*/ _jsxs(ModalContent, {
|
|
301
313
|
"aria-describedby": undefined,
|
|
302
314
|
children: [
|
|
@@ -310,43 +322,50 @@ export function WorkspaceModelProvidersSection({ workspaceId }) {
|
|
|
310
322
|
"aria-hidden": "true",
|
|
311
323
|
className: "overflow-ellipsis overflow-hidden whitespace-nowrap",
|
|
312
324
|
children: [
|
|
313
|
-
"Change default model for
|
|
314
|
-
|
|
325
|
+
"Change default model for",
|
|
326
|
+
' ',
|
|
327
|
+
modal.kind === 'change-default-model' ? modal.provider.label : ''
|
|
315
328
|
]
|
|
316
329
|
})
|
|
317
330
|
}),
|
|
318
|
-
|
|
331
|
+
modal.kind === 'change-default-model' ? /*#__PURE__*/ _jsx(ChangeDefaultModelForm, {
|
|
319
332
|
workspaceId: workspaceId,
|
|
320
|
-
entry:
|
|
321
|
-
config:
|
|
333
|
+
entry: modal.provider,
|
|
334
|
+
config: modal.config,
|
|
322
335
|
onSaved: ()=>{
|
|
323
|
-
toast.success(`${
|
|
324
|
-
|
|
336
|
+
toast.success(`${modal.provider.label} default model saved`);
|
|
337
|
+
dispatchModal({
|
|
338
|
+
type: 'close'
|
|
339
|
+
});
|
|
325
340
|
}
|
|
326
341
|
}) : null
|
|
327
342
|
]
|
|
328
343
|
})
|
|
329
344
|
}),
|
|
330
345
|
/*#__PURE__*/ _jsx(ModelProviderUsageModal, {
|
|
331
|
-
target: usageTarget
|
|
332
|
-
initialModel:
|
|
333
|
-
workspaceDefaultHarnessId: configsQuery.data?.
|
|
334
|
-
open:
|
|
335
|
-
closeFocusTarget:
|
|
346
|
+
target: usageTarget,
|
|
347
|
+
initialModel: modal.kind === 'show-usage' ? modal.initialModel : null,
|
|
348
|
+
workspaceDefaultHarnessId: configsQuery.data?.defaultHarnessId ?? null,
|
|
349
|
+
open: modal.kind === 'show-usage',
|
|
350
|
+
closeFocusTarget: modal.kind === 'show-usage' && modal.restoreFocusToConfiguredProviders ? configuredProvidersRegionRef.current : null,
|
|
336
351
|
onOpenChange: (open)=>{
|
|
337
|
-
if (!open)
|
|
352
|
+
if (!open) dispatchModal({
|
|
353
|
+
type: 'close'
|
|
354
|
+
});
|
|
338
355
|
}
|
|
339
356
|
}),
|
|
340
357
|
/*#__PURE__*/ _jsx(Modal, {
|
|
341
|
-
open:
|
|
342
|
-
onOpenChange: (open)=>open ? undefined :
|
|
358
|
+
open: modal.kind === 'create-custom' || modal.kind === 'edit-custom',
|
|
359
|
+
onOpenChange: (open)=>open ? undefined : dispatchModal({
|
|
360
|
+
type: 'close'
|
|
361
|
+
}),
|
|
343
362
|
children: /*#__PURE__*/ _jsxs(ModalContent, {
|
|
344
363
|
"aria-describedby": undefined,
|
|
345
364
|
className: "max-h-[calc(100vh-32px)] max-w-[760px]",
|
|
346
365
|
children: [
|
|
347
366
|
/*#__PURE__*/ _jsx(ModalTitle, {
|
|
348
367
|
className: "sr-only",
|
|
349
|
-
children: customModelProviderFormTitle(
|
|
368
|
+
children: customModelProviderFormTitle(modal)
|
|
350
369
|
}),
|
|
351
370
|
/*#__PURE__*/ _jsx(ModalHeader, {
|
|
352
371
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
@@ -356,7 +375,7 @@ export function WorkspaceModelProvidersSection({ workspaceId }) {
|
|
|
356
375
|
size: "lg",
|
|
357
376
|
"aria-hidden": "true",
|
|
358
377
|
className: "truncate",
|
|
359
|
-
children: customModelProviderFormTitle(
|
|
378
|
+
children: customModelProviderFormTitle(modal)
|
|
360
379
|
}),
|
|
361
380
|
/*#__PURE__*/ _jsx(Text, {
|
|
362
381
|
size: "sm",
|
|
@@ -366,12 +385,14 @@ export function WorkspaceModelProvidersSection({ workspaceId }) {
|
|
|
366
385
|
]
|
|
367
386
|
})
|
|
368
387
|
}),
|
|
369
|
-
|
|
388
|
+
modal.kind === 'create-custom' || modal.kind === 'edit-custom' ? /*#__PURE__*/ _jsx(CustomModelProviderForm, {
|
|
370
389
|
workspaceId: workspaceId,
|
|
371
|
-
existingConfig:
|
|
390
|
+
existingConfig: modal.kind === 'edit-custom' ? modal.config : undefined,
|
|
372
391
|
onSaved: ()=>{
|
|
373
|
-
toast.success(
|
|
374
|
-
|
|
392
|
+
toast.success(modal.kind === 'edit-custom' ? `${modal.config.displayName} saved` : 'Custom provider saved');
|
|
393
|
+
dispatchModal({
|
|
394
|
+
type: 'close'
|
|
395
|
+
});
|
|
375
396
|
}
|
|
376
397
|
}) : null
|
|
377
398
|
]
|
|
@@ -380,14 +401,13 @@ export function WorkspaceModelProvidersSection({ workspaceId }) {
|
|
|
380
401
|
]
|
|
381
402
|
});
|
|
382
403
|
}
|
|
383
|
-
function modelProviderFormTitle(
|
|
384
|
-
if (
|
|
385
|
-
if (
|
|
386
|
-
return
|
|
404
|
+
function modelProviderFormTitle(modal) {
|
|
405
|
+
if (modal.kind === 'edit-builtin') return `Edit credentials for ${modal.provider.label}`;
|
|
406
|
+
if (modal.kind === 'configure-builtin') return `Configure ${modal.provider.label}`;
|
|
407
|
+
return '';
|
|
387
408
|
}
|
|
388
|
-
function customModelProviderFormTitle(
|
|
389
|
-
if (
|
|
390
|
-
if (formState.mode === 'edit') return `Edit ${formState.config.display_name}`;
|
|
409
|
+
function customModelProviderFormTitle(modal) {
|
|
410
|
+
if (modal.kind === 'edit-custom') return `Edit ${modal.config.displayName}`;
|
|
391
411
|
return 'Add custom provider';
|
|
392
412
|
}
|
|
393
413
|
function isBuiltinModelProviderConfig(config) {
|
|
@@ -403,7 +423,7 @@ function ConfiguredProviderRow({ workspaceId, config, entry, isDefault, onEdit,
|
|
|
403
423
|
const [deleteOpen, setDeleteOpen] = useState(false);
|
|
404
424
|
const [deleteError, setDeleteError] = useState();
|
|
405
425
|
const customConfig = isCustomModelProviderConfig(config) ? config : undefined;
|
|
406
|
-
const label = customConfig?.
|
|
426
|
+
const label = customConfig?.displayName ?? entry?.label ?? config.providerId;
|
|
407
427
|
const canUse = entry !== undefined || customConfig !== undefined;
|
|
408
428
|
const canEdit = entry !== undefined || customConfig !== undefined;
|
|
409
429
|
const isBuiltinConfig = isBuiltinModelProviderConfig(config);
|
|
@@ -412,9 +432,7 @@ function ConfiguredProviderRow({ workspaceId, config, entry, isDefault, onEdit,
|
|
|
412
432
|
try {
|
|
413
433
|
await setDefault.mutateAsync({
|
|
414
434
|
workspaceId,
|
|
415
|
-
|
|
416
|
-
provider_id: config.provider_id
|
|
417
|
-
}
|
|
435
|
+
providerId: config.providerId
|
|
418
436
|
});
|
|
419
437
|
toast.success(`${label} is now the default provider`);
|
|
420
438
|
} catch (error) {
|
|
@@ -427,7 +445,7 @@ function ConfiguredProviderRow({ workspaceId, config, entry, isDefault, onEdit,
|
|
|
427
445
|
try {
|
|
428
446
|
await deleteConfig.mutateAsync({
|
|
429
447
|
workspaceId,
|
|
430
|
-
providerId: config.
|
|
448
|
+
providerId: config.providerId
|
|
431
449
|
});
|
|
432
450
|
toast.success(`${label} deleted`);
|
|
433
451
|
setDeleteOpen(false);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/model-providers-section.tsx"],"sourcesContent":["import type {\n CustomModelProviderConfigDto,\n ModelProviderCatalogEntryDto,\n ModelProviderConfigDto,\n ModelProviderConfigResponseDto,\n} from '@shipfox/api-agent-dto';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {Button, IconButton} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n} from '@shipfox/react-ui/modal';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {useEffect, useMemo, useRef, useState} from 'react';\nimport {\n useDeleteModelProviderConfigMutation,\n useModelProviderCatalogQuery,\n useModelProviderConfigsQuery,\n useSetDefaultModelProviderMutation,\n} from '#hooks/api/model-providers.js';\nimport {AddCustomProviderCard} from './add-custom-provider-card.js';\nimport {AvailableProvidersGrid, PROVIDER_GRID_CLASS} from './available-providers-grid.js';\nimport {ChangeDefaultModelForm} from './change-default-model-form.js';\nimport {CustomModelProviderForm} from './custom-model-provider-form.js';\nimport {modelProviderConfigErrorToFormError} from './form-errors.js';\nimport {ModelProviderUsageModal} from './model-provider-usage-modal.js';\nimport {\n type ModelProviderUsageTarget,\n usageTargetFromCatalogEntry,\n usageTargetFromCustomConfig,\n} from './model-provider-usage-target.js';\nimport {customProviderCardMatchesSearch} from './provider-search.js';\nimport {\n isSupportedCatalogEntry,\n type SupportedModelProviderCatalogEntry,\n toSupportedCatalogEntry,\n} from './supported-model-provider-catalog-entry.js';\nimport {ModelProviderTestAndSaveForm} from './test-and-save-form.js';\n\nconst SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\ntype ModelProviderFormState =\n | {mode: 'configure'; entry: SupportedModelProviderCatalogEntry; config?: undefined}\n | {mode: 'edit'; entry: SupportedModelProviderCatalogEntry; config: ModelProviderConfigDto};\ntype CustomModelProviderFormState =\n | {mode: 'create'}\n | {mode: 'edit'; config: CustomModelProviderConfigDto};\ntype ModelFormState = {entry: SupportedModelProviderCatalogEntry; config: ModelProviderConfigDto};\ntype UsageTarget = {\n target: ModelProviderUsageTarget;\n initialModel: string | null;\n restoreFocusToConfiguredProviders: boolean;\n};\n\nconst USAGE_MODAL_OPEN_DELAY_MS = 250;\n\nexport function WorkspaceModelProvidersSection({workspaceId}: {workspaceId: string}) {\n const catalogQuery = useModelProviderCatalogQuery();\n const configsQuery = useModelProviderConfigsQuery(workspaceId);\n const [formState, setFormState] = useState<ModelProviderFormState | null>(null);\n const [customFormState, setCustomFormState] = useState<CustomModelProviderFormState | null>(null);\n const [modelFormState, setModelFormState] = useState<ModelFormState | null>(null);\n const [usageTarget, setUsageTarget] = useState<UsageTarget | null>(null);\n const [pendingUsageTarget, setPendingUsageTarget] = useState<UsageTarget | null>(null);\n const configuredProvidersRegionRef = useRef<HTMLElement | null>(null);\n\n const providers = catalogQuery.data?.providers ?? [];\n const configs = configsQuery.data?.configs ?? [];\n const configsLoaded = configsQuery.data !== undefined;\n const defaultProviderId = configsQuery.data?.default_provider_id ?? null;\n const providerById = useMemo(\n () =>\n new Map<string, ModelProviderCatalogEntryDto>(\n providers.map((provider) => [provider.id, provider]),\n ),\n [providers],\n );\n const configuredIds = useMemo(\n () => new Set<string>(configs.map((config) => config.provider_id)),\n [configs],\n );\n const availableProviders = configsLoaded\n ? providers.filter(\n (provider): provider is SupportedModelProviderCatalogEntry =>\n isSupportedCatalogEntry(provider) && !configuredIds.has(provider.id),\n )\n : [];\n const unsupportedProviders = providers.filter(\n (provider) => provider.support_status === 'unsupported',\n );\n\n function closeForm() {\n setFormState(null);\n }\n\n function closeModelForm() {\n setModelFormState(null);\n }\n\n function closeCustomForm() {\n setCustomFormState(null);\n }\n\n useEffect(() => {\n if (pendingUsageTarget === null || formState !== null || customFormState !== null)\n return undefined;\n\n const timer = window.setTimeout(() => {\n setUsageTarget(pendingUsageTarget);\n setPendingUsageTarget(null);\n }, USAGE_MODAL_OPEN_DELAY_MS);\n\n return () => window.clearTimeout(timer);\n }, [customFormState, formState, pendingUsageTarget]);\n\n return (\n <div className=\"flex min-w-0 flex-col gap-32\">\n <section\n ref={configuredProvidersRegionRef}\n className=\"flex flex-col gap-16 outline-none\"\n aria-label=\"Configured providers\"\n tabIndex={-1}\n >\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Configured providers</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Workspace credentials available to agent steps.\n </Text>\n </div>\n\n {configsQuery.isPending ? (\n <ModelProviderRowsSkeleton label=\"Loading configured providers\" />\n ) : null}\n\n {configsQuery.isError && configsQuery.data === undefined ? (\n <div className={cn(SURFACE_CLASS, 'px-16')}>\n <QueryLoadError query={configsQuery} subject=\"model provider configs\" />\n </div>\n ) : null}\n\n {configsQuery.data !== undefined && configs.length === 0 ? (\n <div className={cn(SURFACE_CLASS, 'px-16')}>\n <EmptyState\n icon=\"key2Line\"\n title=\"No providers configured\"\n description=\"Configure a provider below to run agent steps with workspace-managed credentials.\"\n />\n </div>\n ) : null}\n\n {configs.length > 0 ? (\n <ul className={cn('divide-y divide-border-neutral-base', SURFACE_CLASS)}>\n {configs.map((config) => {\n const entry = toSupportedCatalogEntry(providerById.get(config.provider_id));\n const builtinConfig = isBuiltinModelProviderConfig(config) ? config : undefined;\n const customConfig = isCustomModelProviderConfig(config) ? config : undefined;\n return (\n <ConfiguredProviderRow\n key={config.provider_id}\n workspaceId={workspaceId}\n config={config}\n entry={entry}\n isDefault={config.provider_id === defaultProviderId}\n onEdit={() => {\n if (entry && builtinConfig) {\n setFormState({mode: 'edit', entry, config: builtinConfig});\n } else if (customConfig) {\n setCustomFormState({mode: 'edit', config: customConfig});\n }\n }}\n onChangeDefaultModel={() => {\n if (entry && builtinConfig) setModelFormState({entry, config: builtinConfig});\n }}\n onShowUsage={() => {\n if (entry && builtinConfig) {\n setPendingUsageTarget(null);\n setUsageTarget({\n target: usageTargetFromCatalogEntry(entry),\n initialModel: builtinConfig.default_model,\n restoreFocusToConfiguredProviders: false,\n });\n } else if (customConfig) {\n setPendingUsageTarget(null);\n setUsageTarget({\n target: usageTargetFromCustomConfig(customConfig),\n initialModel: customConfig.default_model,\n restoreFocusToConfiguredProviders: false,\n });\n }\n }}\n />\n );\n })}\n </ul>\n ) : null}\n </section>\n\n <section className=\"flex flex-col gap-16\" aria-label=\"Available providers\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Available providers</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Providers that can be configured for agent steps in this workspace.\n </Text>\n </div>\n\n {catalogQuery.isPending || configsQuery.isPending ? <ModelProviderGridSkeleton /> : null}\n\n {catalogQuery.isError && catalogQuery.data === undefined ? (\n <div className={cn(SURFACE_CLASS, 'px-16')}>\n <QueryLoadError query={catalogQuery} subject=\"model provider catalog\" />\n </div>\n ) : null}\n\n {configsLoaded ? (\n <AvailableProvidersGrid\n entries={availableProviders}\n onSelect={(entry) => setFormState({mode: 'configure', entry})}\n trailingCard={\n <AddCustomProviderCard onConfigure={() => setCustomFormState({mode: 'create'})} />\n }\n trailingCardMatchesSearch={customProviderCardMatchesSearch}\n />\n ) : null}\n </section>\n\n <section className=\"flex flex-col gap-16\" aria-label=\"Unsupported providers\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Unsupported providers</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Providers that cannot be configured in this workspace yet.\n </Text>\n </div>\n\n {catalogQuery.isPending ? (\n <ModelProviderRowsSkeleton label=\"Loading unsupported providers\" />\n ) : null}\n\n {unsupportedProviders.length > 0 ? (\n <ul className={cn('divide-y divide-border-neutral-base', SURFACE_CLASS)}>\n {unsupportedProviders.map((entry) => (\n <li key={entry.id} className=\"flex items-start gap-12 px-16 py-12 opacity-70\">\n <Icon\n name=\"forbid2Line\"\n className=\"mt-2 size-18 shrink-0 text-foreground-neutral-muted\"\n aria-hidden\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n <Text size=\"md\" bold className=\"truncate\">\n {entry.label}\n </Text>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {entry.unsupported_reason}\n </Text>\n </div>\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n\n <Modal open={formState !== null} onOpenChange={(open) => (open ? undefined : closeForm())}>\n <ModalContent aria-describedby={undefined}>\n <ModalTitle className=\"sr-only\">{modelProviderFormTitle(formState)}</ModalTitle>\n <ModalHeader>\n <Text\n size=\"lg\"\n aria-hidden=\"true\"\n className=\"overflow-ellipsis overflow-hidden whitespace-nowrap\"\n >\n {modelProviderFormTitle(formState)}\n </Text>\n </ModalHeader>\n {formState ? (\n <ModelProviderTestAndSaveForm\n workspaceId={workspaceId}\n entry={formState.entry}\n existingConfig={formState.config}\n onSaved={(savedDefaultModel) => {\n toast.success(`${formState.entry.label} saved`);\n if (formState.mode === 'configure' && configs.length === 0) {\n setPendingUsageTarget({\n target: usageTargetFromCatalogEntry(formState.entry),\n initialModel: savedDefaultModel,\n restoreFocusToConfiguredProviders: true,\n });\n }\n closeForm();\n }}\n />\n ) : null}\n </ModalContent>\n </Modal>\n\n <Modal\n open={modelFormState !== null}\n onOpenChange={(open) => (open ? undefined : closeModelForm())}\n >\n <ModalContent aria-describedby={undefined}>\n <ModalTitle className=\"sr-only\">Change default model</ModalTitle>\n <ModalHeader>\n <Text\n size=\"lg\"\n aria-hidden=\"true\"\n className=\"overflow-ellipsis overflow-hidden whitespace-nowrap\"\n >\n Change default model for {modelFormState?.entry.label}\n </Text>\n </ModalHeader>\n {modelFormState ? (\n <ChangeDefaultModelForm\n workspaceId={workspaceId}\n entry={modelFormState.entry}\n config={modelFormState.config}\n onSaved={() => {\n toast.success(`${modelFormState.entry.label} default model saved`);\n closeModelForm();\n }}\n />\n ) : null}\n </ModalContent>\n </Modal>\n\n <ModelProviderUsageModal\n target={usageTarget?.target ?? null}\n initialModel={usageTarget?.initialModel ?? null}\n workspaceDefaultHarnessId={configsQuery.data?.default_harness_id ?? null}\n open={usageTarget !== null}\n closeFocusTarget={\n usageTarget?.restoreFocusToConfiguredProviders\n ? configuredProvidersRegionRef.current\n : null\n }\n onOpenChange={(open) => {\n if (!open) setUsageTarget(null);\n }}\n />\n\n <Modal\n open={customFormState !== null}\n onOpenChange={(open) => (open ? undefined : closeCustomForm())}\n >\n <ModalContent\n aria-describedby={undefined}\n className=\"max-h-[calc(100vh-32px)] max-w-[760px]\"\n >\n <ModalTitle className=\"sr-only\">\n {customModelProviderFormTitle(customFormState)}\n </ModalTitle>\n <ModalHeader>\n <div className=\"flex min-w-0 flex-col gap-2\">\n <Text size=\"lg\" aria-hidden=\"true\" className=\"truncate\">\n {customModelProviderFormTitle(customFormState)}\n </Text>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Connect an OpenAI-, Anthropic-, or Gemini-compatible endpoint.\n </Text>\n </div>\n </ModalHeader>\n {customFormState ? (\n <CustomModelProviderForm\n workspaceId={workspaceId}\n existingConfig={customFormState.mode === 'edit' ? customFormState.config : undefined}\n onSaved={() => {\n toast.success(\n customFormState.mode === 'edit'\n ? `${customFormState.config.display_name} saved`\n : 'Custom provider saved',\n );\n closeCustomForm();\n }}\n />\n ) : null}\n </ModalContent>\n </Modal>\n </div>\n );\n}\n\nfunction modelProviderFormTitle(formState: ModelProviderFormState | null): string {\n if (formState === null) return '';\n if (formState.mode === 'edit') return `Edit credentials for ${formState.entry.label}`;\n return `Configure ${formState.entry.label}`;\n}\n\nfunction customModelProviderFormTitle(formState: CustomModelProviderFormState | null): string {\n if (formState === null) return '';\n if (formState.mode === 'edit') return `Edit ${formState.config.display_name}`;\n return 'Add custom provider';\n}\n\nfunction isBuiltinModelProviderConfig(\n config: ModelProviderConfigResponseDto,\n): config is ModelProviderConfigDto {\n return config.kind === 'builtin';\n}\n\nfunction isCustomModelProviderConfig(\n config: ModelProviderConfigResponseDto,\n): config is CustomModelProviderConfigDto {\n return config.kind === 'custom';\n}\n\nfunction ConfiguredProviderRow({\n workspaceId,\n config,\n entry,\n isDefault,\n onEdit,\n onChangeDefaultModel,\n onShowUsage,\n}: {\n workspaceId: string;\n config: ModelProviderConfigResponseDto;\n entry: SupportedModelProviderCatalogEntry | undefined;\n isDefault: boolean;\n onEdit: () => void;\n onChangeDefaultModel: () => void;\n onShowUsage: () => void;\n}) {\n const setDefault = useSetDefaultModelProviderMutation();\n const deleteConfig = useDeleteModelProviderConfigMutation();\n const [defaultError, setDefaultError] = useState<string | undefined>();\n const [deleteOpen, setDeleteOpen] = useState(false);\n const [deleteError, setDeleteError] = useState<string | undefined>();\n const customConfig = isCustomModelProviderConfig(config) ? config : undefined;\n const label = customConfig?.display_name ?? entry?.label ?? config.provider_id;\n const canUse = entry !== undefined || customConfig !== undefined;\n const canEdit = entry !== undefined || customConfig !== undefined;\n const isBuiltinConfig = isBuiltinModelProviderConfig(config);\n\n async function handleSetDefault() {\n setDefaultError(undefined);\n try {\n await setDefault.mutateAsync({\n workspaceId,\n body: {provider_id: config.provider_id},\n });\n toast.success(`${label} is now the default provider`);\n } catch (error) {\n const mapped = modelProviderConfigErrorToFormError(error);\n setDefaultError(mapped.message);\n }\n }\n\n async function handleDelete() {\n setDeleteError(undefined);\n try {\n await deleteConfig.mutateAsync({workspaceId, providerId: config.provider_id});\n toast.success(`${label} deleted`);\n setDeleteOpen(false);\n } catch (error) {\n const mapped = modelProviderConfigErrorToFormError(error);\n setDeleteError(mapped.message);\n }\n }\n\n function handleDeleteOpenChange(nextOpen: boolean) {\n setDeleteOpen(nextOpen);\n if (nextOpen) {\n setDeleteError(undefined);\n deleteConfig.reset();\n }\n }\n\n return (\n <li className=\"flex flex-col gap-10 px-16 py-12 transition-colors hover:bg-background-components-hover\">\n <div className=\"flex items-center justify-between gap-12\">\n <div className=\"flex min-w-0 items-center gap-8\">\n {isDefault ? (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex size-16 shrink-0 items-center justify-center\">\n <Icon\n name=\"starLine\"\n className=\"size-16 text-foreground-neutral-muted\"\n aria-hidden\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>Default provider</TooltipContent>\n </Tooltip>\n <span className=\"sr-only\">Default provider</span>\n </>\n ) : null}\n <Text size=\"md\" bold className=\"truncate\">\n {label}\n </Text>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n aria-label={`Open ${label} provider actions`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {!isDefault ? (\n <DropdownMenuItem\n icon=\"starLine\"\n disabled={setDefault.isPending || (!entry && !customConfig)}\n onSelect={() => {\n void handleSetDefault();\n }}\n >\n Set as default\n </DropdownMenuItem>\n ) : null}\n {isBuiltinConfig ? (\n <DropdownMenuItem\n icon=\"settings3Line\"\n disabled={!entry}\n onSelect={onChangeDefaultModel}\n >\n Change default model\n </DropdownMenuItem>\n ) : null}\n <DropdownMenuItem icon=\"bookOpenLine\" disabled={!canUse} onSelect={onShowUsage}>\n View workflow example\n </DropdownMenuItem>\n <DropdownMenuItem icon=\"editLine\" disabled={!canEdit} onSelect={onEdit}>\n {customConfig ? 'Edit' : 'Edit credentials'}\n </DropdownMenuItem>\n <DropdownMenuItem\n icon=\"deleteBinLine\"\n onSelect={() => {\n setDeleteOpen(true);\n }}\n >\n Delete\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n {defaultError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{defaultError}</Text>\n </Callout>\n ) : null}\n <DeleteModelProviderDialog\n open={deleteOpen}\n onOpenChange={handleDeleteOpenChange}\n label={label}\n errorMessage={deleteError}\n isLoading={deleteConfig.isPending}\n onDelete={handleDelete}\n />\n </li>\n );\n}\n\nfunction DeleteModelProviderDialog({\n open,\n onOpenChange,\n label,\n errorMessage,\n isLoading,\n onDelete,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n label: string;\n errorMessage: string | undefined;\n isLoading: boolean;\n onDelete: () => void;\n}) {\n return (\n <Modal open={open} onOpenChange={onOpenChange}>\n <ModalContent aria-describedby={undefined} className=\"max-w-[420px]\">\n <ModalTitle className=\"sr-only\">Delete model provider</ModalTitle>\n <ModalHeader title=\"Delete model provider\" />\n <ModalBody className=\"gap-16\">\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Delete {label} credentials from this workspace? Agent jobs cannot use this provider\n until it is configured again.\n </Text>\n {errorMessage ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{errorMessage}</Text>\n </Callout>\n ) : null}\n </ModalBody>\n <ModalFooter>\n <Button size=\"sm\" variant=\"secondary\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button size=\"sm\" variant=\"danger\" isLoading={isLoading} onClick={onDelete}>\n Delete\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n );\n}\n\nfunction ModelProviderRowsSkeleton({label}: {label: string}) {\n return (\n <ul\n role=\"status\"\n aria-label={label}\n className={cn('divide-y divide-border-neutral-base', SURFACE_CLASS)}\n >\n {[0, 1, 2].map((row) => (\n <li key={row} className=\"flex items-center gap-12 px-16 py-12\">\n <Skeleton className=\"size-32 shrink-0\" />\n <div className=\"flex min-w-0 flex-1 flex-col gap-6\">\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"h-14 w-180\" />\n </div>\n <Skeleton className=\"h-28 w-96 shrink-0\" />\n </li>\n ))}\n </ul>\n );\n}\n\nfunction ModelProviderGridSkeleton() {\n return (\n <div role=\"status\" aria-label=\"Loading available providers\" className={PROVIDER_GRID_CLASS}>\n {[0, 1, 2, 3].map((card) => (\n <Skeleton key={card} className=\"h-136 w-full\" />\n ))}\n </div>\n );\n}\n"],"names":["QueryLoadError","Button","IconButton","Callout","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","EmptyState","Icon","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","Skeleton","toast","Tooltip","TooltipContent","TooltipTrigger","Header","Text","cn","useEffect","useMemo","useRef","useState","useDeleteModelProviderConfigMutation","useModelProviderCatalogQuery","useModelProviderConfigsQuery","useSetDefaultModelProviderMutation","AddCustomProviderCard","AvailableProvidersGrid","PROVIDER_GRID_CLASS","ChangeDefaultModelForm","CustomModelProviderForm","modelProviderConfigErrorToFormError","ModelProviderUsageModal","usageTargetFromCatalogEntry","usageTargetFromCustomConfig","customProviderCardMatchesSearch","isSupportedCatalogEntry","toSupportedCatalogEntry","ModelProviderTestAndSaveForm","SURFACE_CLASS","USAGE_MODAL_OPEN_DELAY_MS","WorkspaceModelProvidersSection","workspaceId","catalogQuery","configsQuery","formState","setFormState","customFormState","setCustomFormState","modelFormState","setModelFormState","usageTarget","setUsageTarget","pendingUsageTarget","setPendingUsageTarget","configuredProvidersRegionRef","providers","data","configs","configsLoaded","undefined","defaultProviderId","default_provider_id","providerById","Map","map","provider","id","configuredIds","Set","config","provider_id","availableProviders","filter","has","unsupportedProviders","support_status","closeForm","closeModelForm","closeCustomForm","timer","window","setTimeout","clearTimeout","div","className","section","ref","aria-label","tabIndex","variant","size","isPending","ModelProviderRowsSkeleton","label","isError","query","subject","length","icon","title","description","ul","entry","get","builtinConfig","isBuiltinModelProviderConfig","customConfig","isCustomModelProviderConfig","ConfiguredProviderRow","isDefault","onEdit","mode","onChangeDefaultModel","onShowUsage","target","initialModel","default_model","restoreFocusToConfiguredProviders","ModelProviderGridSkeleton","entries","onSelect","trailingCard","onConfigure","trailingCardMatchesSearch","li","name","aria-hidden","bold","unsupported_reason","open","onOpenChange","aria-describedby","modelProviderFormTitle","existingConfig","onSaved","savedDefaultModel","success","workspaceDefaultHarnessId","default_harness_id","closeFocusTarget","current","customModelProviderFormTitle","display_name","kind","setDefault","deleteConfig","defaultError","setDefaultError","deleteOpen","setDeleteOpen","deleteError","setDeleteError","canUse","canEdit","isBuiltinConfig","handleSetDefault","mutateAsync","body","error","mapped","message","handleDelete","providerId","handleDeleteOpenChange","nextOpen","reset","asChild","span","align","disabled","role","type","DeleteModelProviderDialog","errorMessage","isLoading","onDelete","onClick","row","card"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/components/model-providers-section.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {Button, IconButton} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n} from '@shipfox/react-ui/modal';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {useEffect, useMemo, useReducer, useRef, useState} from 'react';\nimport {\n type ManagementModal,\n managementModalReducer,\n} from '#core/model-provider-management-reducer.js';\nimport type {\n BuiltinProviderConfig,\n CustomProviderConfig,\n ProviderCatalogEntry,\n ProviderConfig,\n SupportedProvider,\n} from '#core/models.js';\nimport {\n customProviderCardMatchesSearch,\n isSupportedProvider,\n availableProviders as selectAvailableProviders,\n} from '#core/provider-policy.js';\nimport {\n useDeleteModelProviderConfigMutation,\n useModelProviderCatalogQuery,\n useModelProviderConfigsQuery,\n useSetDefaultModelProviderMutation,\n} from '#hooks/api/model-providers.js';\nimport {AddCustomProviderCard} from './add-custom-provider-card.js';\nimport {AvailableProvidersGrid, PROVIDER_GRID_CLASS} from './available-providers-grid.js';\nimport {ChangeDefaultModelForm} from './change-default-model-form.js';\nimport {CustomModelProviderForm} from './custom-model-provider-form.js';\nimport {modelProviderConfigErrorToFormError} from './form-errors.js';\nimport {ModelProviderUsageModal} from './model-provider-usage-modal.js';\nimport {\n type ModelProviderUsageTarget,\n usageTargetFromCatalogEntry,\n usageTargetFromCustomConfig,\n} from './model-provider-usage-target.js';\nimport {ModelProviderTestAndSaveForm} from './test-and-save-form.js';\n\nconst SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\ntype UsageTarget = {\n target: ModelProviderUsageTarget;\n initialModel: string | null;\n restoreFocusToConfiguredProviders: boolean;\n};\n\nconst USAGE_MODAL_OPEN_DELAY_MS = 250;\n\nexport function WorkspaceModelProvidersSection({workspaceId}: {workspaceId: string}) {\n const catalogQuery = useModelProviderCatalogQuery();\n const configsQuery = useModelProviderConfigsQuery(workspaceId);\n const [modal, dispatchModal] = useReducer(managementModalReducer, {kind: 'closed'});\n const [pendingUsageTarget, setPendingUsageTarget] = useState<UsageTarget | null>(null);\n const configuredProvidersRegionRef = useRef<HTMLElement | null>(null);\n\n const providers = catalogQuery.data?.providers ?? [];\n const configs = configsQuery.data?.configs ?? [];\n const configsLoaded = configsQuery.data !== undefined;\n const defaultProviderId = configsQuery.data?.defaultProviderId ?? null;\n const providerById = useMemo(\n () =>\n new Map<string, ProviderCatalogEntry>(providers.map((provider) => [provider.id, provider])),\n [providers],\n );\n const availableProviders = configsLoaded ? selectAvailableProviders(providers, configs) : [];\n const unsupportedProviders = providers.filter((provider) => !isSupportedProvider(provider));\n\n useEffect(() => {\n if (pendingUsageTarget === null || modal.kind !== 'closed') return undefined;\n\n const timer = window.setTimeout(() => {\n dispatchModal({\n type: 'show-usage',\n providerId: pendingUsageTarget.target.id,\n initialModel: pendingUsageTarget.initialModel,\n restoreFocusToConfiguredProviders: pendingUsageTarget.restoreFocusToConfiguredProviders,\n });\n setPendingUsageTarget(null);\n }, USAGE_MODAL_OPEN_DELAY_MS);\n\n return () => window.clearTimeout(timer);\n }, [modal.kind, pendingUsageTarget]);\n\n const usageTarget = useMemo(() => {\n if (modal.kind !== 'show-usage') return null;\n const config = configs.find((item) => item.providerId === modal.providerId);\n if (config?.kind === 'custom') return usageTargetFromCustomConfig(config);\n const entry = providerById.get(modal.providerId);\n return entry && isSupportedProvider(entry) ? usageTargetFromCatalogEntry(entry) : null;\n }, [configs, modal, providerById]);\n\n return (\n <div className=\"flex min-w-0 flex-col gap-32\">\n <section\n ref={configuredProvidersRegionRef}\n className=\"flex flex-col gap-16 outline-none\"\n aria-label=\"Configured providers\"\n tabIndex={-1}\n >\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Configured providers</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Workspace credentials available to agent steps.\n </Text>\n </div>\n\n {configsQuery.isPending ? (\n <ModelProviderRowsSkeleton label=\"Loading configured providers\" />\n ) : null}\n\n {configsQuery.isError && configsQuery.data === undefined ? (\n <div className={cn(SURFACE_CLASS, 'px-16')}>\n <QueryLoadError query={configsQuery} subject=\"model provider configs\" />\n </div>\n ) : null}\n\n {configsQuery.data !== undefined && configs.length === 0 ? (\n <div className={cn(SURFACE_CLASS, 'px-16')}>\n <EmptyState\n icon=\"key2Line\"\n title=\"No providers configured\"\n description=\"Configure a provider below to run agent steps with workspace-managed credentials.\"\n />\n </div>\n ) : null}\n\n {configs.length > 0 ? (\n <ul className={cn('divide-y divide-border-neutral-base', SURFACE_CLASS)}>\n {configs.map((config) => {\n const catalogEntry = providerById.get(config.providerId);\n const entry =\n catalogEntry && isSupportedProvider(catalogEntry) ? catalogEntry : undefined;\n const builtinConfig = isBuiltinModelProviderConfig(config) ? config : undefined;\n const customConfig = isCustomModelProviderConfig(config) ? config : undefined;\n return (\n <ConfiguredProviderRow\n key={config.providerId}\n workspaceId={workspaceId}\n config={config}\n entry={entry}\n isDefault={config.providerId === defaultProviderId}\n onEdit={() => {\n if (entry && builtinConfig) {\n dispatchModal({type: 'edit-builtin', provider: entry, config: builtinConfig});\n } else if (customConfig) {\n dispatchModal({type: 'edit-custom', config: customConfig});\n }\n }}\n onChangeDefaultModel={() => {\n if (entry && builtinConfig)\n dispatchModal({\n type: 'change-default-model',\n provider: entry,\n config: builtinConfig,\n });\n }}\n onShowUsage={() => {\n if (entry && builtinConfig) {\n setPendingUsageTarget(null);\n dispatchModal({\n type: 'show-usage',\n providerId: entry.id,\n initialModel: builtinConfig.defaultModel,\n restoreFocusToConfiguredProviders: false,\n });\n } else if (customConfig) {\n setPendingUsageTarget(null);\n dispatchModal({\n type: 'show-usage',\n providerId: customConfig.providerId,\n initialModel: customConfig.defaultModel,\n restoreFocusToConfiguredProviders: false,\n });\n }\n }}\n />\n );\n })}\n </ul>\n ) : null}\n </section>\n\n <section className=\"flex flex-col gap-16\" aria-label=\"Available providers\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Available providers</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Providers that can be configured for agent steps in this workspace.\n </Text>\n </div>\n\n {catalogQuery.isPending || configsQuery.isPending ? <ModelProviderGridSkeleton /> : null}\n\n {catalogQuery.isError && catalogQuery.data === undefined ? (\n <div className={cn(SURFACE_CLASS, 'px-16')}>\n <QueryLoadError query={catalogQuery} subject=\"model provider catalog\" />\n </div>\n ) : null}\n\n {configsLoaded ? (\n <AvailableProvidersGrid\n entries={availableProviders}\n onSelect={(entry) => dispatchModal({type: 'configure-builtin', provider: entry})}\n trailingCard={\n <AddCustomProviderCard onConfigure={() => dispatchModal({type: 'create-custom'})} />\n }\n trailingCardMatchesSearch={customProviderCardMatchesSearch}\n />\n ) : null}\n </section>\n\n <section className=\"flex flex-col gap-16\" aria-label=\"Unsupported providers\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Unsupported providers</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Providers that cannot be configured in this workspace yet.\n </Text>\n </div>\n\n {catalogQuery.isPending ? (\n <ModelProviderRowsSkeleton label=\"Loading unsupported providers\" />\n ) : null}\n\n {unsupportedProviders.length > 0 ? (\n <ul className={cn('divide-y divide-border-neutral-base', SURFACE_CLASS)}>\n {unsupportedProviders.map((entry) => (\n <li key={entry.id} className=\"flex items-start gap-12 px-16 py-12 opacity-70\">\n <Icon\n name=\"forbid2Line\"\n className=\"mt-2 size-18 shrink-0 text-foreground-neutral-muted\"\n aria-hidden\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n <Text size=\"md\" bold className=\"truncate\">\n {entry.label}\n </Text>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {entry.unsupportedReason}\n </Text>\n </div>\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n\n <Modal\n open={modal.kind === 'configure-builtin' || modal.kind === 'edit-builtin'}\n onOpenChange={(open) => (open ? undefined : dispatchModal({type: 'close'}))}\n >\n <ModalContent aria-describedby={undefined}>\n <ModalTitle className=\"sr-only\">{modelProviderFormTitle(modal)}</ModalTitle>\n <ModalHeader>\n <Text\n size=\"lg\"\n aria-hidden=\"true\"\n className=\"overflow-ellipsis overflow-hidden whitespace-nowrap\"\n >\n {modelProviderFormTitle(modal)}\n </Text>\n </ModalHeader>\n {modal.kind === 'configure-builtin' || modal.kind === 'edit-builtin' ? (\n <ModelProviderTestAndSaveForm\n workspaceId={workspaceId}\n entry={modal.provider}\n existingConfig={modal.kind === 'edit-builtin' ? modal.config : undefined}\n onSaved={(savedDefaultModel) => {\n toast.success(`${modal.provider.label} saved`);\n if (modal.kind === 'configure-builtin' && configs.length === 0) {\n setPendingUsageTarget({\n target: usageTargetFromCatalogEntry(modal.provider),\n initialModel: savedDefaultModel,\n restoreFocusToConfiguredProviders: true,\n });\n }\n dispatchModal({type: 'close'});\n }}\n />\n ) : null}\n </ModalContent>\n </Modal>\n\n <Modal\n open={modal.kind === 'change-default-model'}\n onOpenChange={(open) => (open ? undefined : dispatchModal({type: 'close'}))}\n >\n <ModalContent aria-describedby={undefined}>\n <ModalTitle className=\"sr-only\">Change default model</ModalTitle>\n <ModalHeader>\n <Text\n size=\"lg\"\n aria-hidden=\"true\"\n className=\"overflow-ellipsis overflow-hidden whitespace-nowrap\"\n >\n Change default model for{' '}\n {modal.kind === 'change-default-model' ? modal.provider.label : ''}\n </Text>\n </ModalHeader>\n {modal.kind === 'change-default-model' ? (\n <ChangeDefaultModelForm\n workspaceId={workspaceId}\n entry={modal.provider}\n config={modal.config}\n onSaved={() => {\n toast.success(`${modal.provider.label} default model saved`);\n dispatchModal({type: 'close'});\n }}\n />\n ) : null}\n </ModalContent>\n </Modal>\n\n <ModelProviderUsageModal\n target={usageTarget}\n initialModel={modal.kind === 'show-usage' ? modal.initialModel : null}\n workspaceDefaultHarnessId={configsQuery.data?.defaultHarnessId ?? null}\n open={modal.kind === 'show-usage'}\n closeFocusTarget={\n modal.kind === 'show-usage' && modal.restoreFocusToConfiguredProviders\n ? configuredProvidersRegionRef.current\n : null\n }\n onOpenChange={(open) => {\n if (!open) dispatchModal({type: 'close'});\n }}\n />\n\n <Modal\n open={modal.kind === 'create-custom' || modal.kind === 'edit-custom'}\n onOpenChange={(open) => (open ? undefined : dispatchModal({type: 'close'}))}\n >\n <ModalContent\n aria-describedby={undefined}\n className=\"max-h-[calc(100vh-32px)] max-w-[760px]\"\n >\n <ModalTitle className=\"sr-only\">{customModelProviderFormTitle(modal)}</ModalTitle>\n <ModalHeader>\n <div className=\"flex min-w-0 flex-col gap-2\">\n <Text size=\"lg\" aria-hidden=\"true\" className=\"truncate\">\n {customModelProviderFormTitle(modal)}\n </Text>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Connect an OpenAI-, Anthropic-, or Gemini-compatible endpoint.\n </Text>\n </div>\n </ModalHeader>\n {modal.kind === 'create-custom' || modal.kind === 'edit-custom' ? (\n <CustomModelProviderForm\n workspaceId={workspaceId}\n existingConfig={modal.kind === 'edit-custom' ? modal.config : undefined}\n onSaved={() => {\n toast.success(\n modal.kind === 'edit-custom'\n ? `${modal.config.displayName} saved`\n : 'Custom provider saved',\n );\n dispatchModal({type: 'close'});\n }}\n />\n ) : null}\n </ModalContent>\n </Modal>\n </div>\n );\n}\n\nfunction modelProviderFormTitle(modal: ManagementModal): string {\n if (modal.kind === 'edit-builtin') return `Edit credentials for ${modal.provider.label}`;\n if (modal.kind === 'configure-builtin') return `Configure ${modal.provider.label}`;\n return '';\n}\n\nfunction customModelProviderFormTitle(modal: ManagementModal): string {\n if (modal.kind === 'edit-custom') return `Edit ${modal.config.displayName}`;\n return 'Add custom provider';\n}\n\nfunction isBuiltinModelProviderConfig(config: ProviderConfig): config is BuiltinProviderConfig {\n return config.kind === 'builtin';\n}\n\nfunction isCustomModelProviderConfig(config: ProviderConfig): config is CustomProviderConfig {\n return config.kind === 'custom';\n}\n\nfunction ConfiguredProviderRow({\n workspaceId,\n config,\n entry,\n isDefault,\n onEdit,\n onChangeDefaultModel,\n onShowUsage,\n}: {\n workspaceId: string;\n config: ProviderConfig;\n entry: SupportedProvider | undefined;\n isDefault: boolean;\n onEdit: () => void;\n onChangeDefaultModel: () => void;\n onShowUsage: () => void;\n}) {\n const setDefault = useSetDefaultModelProviderMutation();\n const deleteConfig = useDeleteModelProviderConfigMutation();\n const [defaultError, setDefaultError] = useState<string | undefined>();\n const [deleteOpen, setDeleteOpen] = useState(false);\n const [deleteError, setDeleteError] = useState<string | undefined>();\n const customConfig = isCustomModelProviderConfig(config) ? config : undefined;\n const label = customConfig?.displayName ?? entry?.label ?? config.providerId;\n const canUse = entry !== undefined || customConfig !== undefined;\n const canEdit = entry !== undefined || customConfig !== undefined;\n const isBuiltinConfig = isBuiltinModelProviderConfig(config);\n\n async function handleSetDefault() {\n setDefaultError(undefined);\n try {\n await setDefault.mutateAsync({\n workspaceId,\n providerId: config.providerId,\n });\n toast.success(`${label} is now the default provider`);\n } catch (error) {\n const mapped = modelProviderConfigErrorToFormError(error);\n setDefaultError(mapped.message);\n }\n }\n\n async function handleDelete() {\n setDeleteError(undefined);\n try {\n await deleteConfig.mutateAsync({workspaceId, providerId: config.providerId});\n toast.success(`${label} deleted`);\n setDeleteOpen(false);\n } catch (error) {\n const mapped = modelProviderConfigErrorToFormError(error);\n setDeleteError(mapped.message);\n }\n }\n\n function handleDeleteOpenChange(nextOpen: boolean) {\n setDeleteOpen(nextOpen);\n if (nextOpen) {\n setDeleteError(undefined);\n deleteConfig.reset();\n }\n }\n\n return (\n <li className=\"flex flex-col gap-10 px-16 py-12 transition-colors hover:bg-background-components-hover\">\n <div className=\"flex items-center justify-between gap-12\">\n <div className=\"flex min-w-0 items-center gap-8\">\n {isDefault ? (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex size-16 shrink-0 items-center justify-center\">\n <Icon\n name=\"starLine\"\n className=\"size-16 text-foreground-neutral-muted\"\n aria-hidden\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>Default provider</TooltipContent>\n </Tooltip>\n <span className=\"sr-only\">Default provider</span>\n </>\n ) : null}\n <Text size=\"md\" bold className=\"truncate\">\n {label}\n </Text>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n aria-label={`Open ${label} provider actions`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {!isDefault ? (\n <DropdownMenuItem\n icon=\"starLine\"\n disabled={setDefault.isPending || (!entry && !customConfig)}\n onSelect={() => {\n void handleSetDefault();\n }}\n >\n Set as default\n </DropdownMenuItem>\n ) : null}\n {isBuiltinConfig ? (\n <DropdownMenuItem\n icon=\"settings3Line\"\n disabled={!entry}\n onSelect={onChangeDefaultModel}\n >\n Change default model\n </DropdownMenuItem>\n ) : null}\n <DropdownMenuItem icon=\"bookOpenLine\" disabled={!canUse} onSelect={onShowUsage}>\n View workflow example\n </DropdownMenuItem>\n <DropdownMenuItem icon=\"editLine\" disabled={!canEdit} onSelect={onEdit}>\n {customConfig ? 'Edit' : 'Edit credentials'}\n </DropdownMenuItem>\n <DropdownMenuItem\n icon=\"deleteBinLine\"\n onSelect={() => {\n setDeleteOpen(true);\n }}\n >\n Delete\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n {defaultError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{defaultError}</Text>\n </Callout>\n ) : null}\n <DeleteModelProviderDialog\n open={deleteOpen}\n onOpenChange={handleDeleteOpenChange}\n label={label}\n errorMessage={deleteError}\n isLoading={deleteConfig.isPending}\n onDelete={handleDelete}\n />\n </li>\n );\n}\n\nfunction DeleteModelProviderDialog({\n open,\n onOpenChange,\n label,\n errorMessage,\n isLoading,\n onDelete,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n label: string;\n errorMessage: string | undefined;\n isLoading: boolean;\n onDelete: () => void;\n}) {\n return (\n <Modal open={open} onOpenChange={onOpenChange}>\n <ModalContent aria-describedby={undefined} className=\"max-w-[420px]\">\n <ModalTitle className=\"sr-only\">Delete model provider</ModalTitle>\n <ModalHeader title=\"Delete model provider\" />\n <ModalBody className=\"gap-16\">\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Delete {label} credentials from this workspace? Agent jobs cannot use this provider\n until it is configured again.\n </Text>\n {errorMessage ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{errorMessage}</Text>\n </Callout>\n ) : null}\n </ModalBody>\n <ModalFooter>\n <Button size=\"sm\" variant=\"secondary\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button size=\"sm\" variant=\"danger\" isLoading={isLoading} onClick={onDelete}>\n Delete\n </Button>\n </ModalFooter>\n </ModalContent>\n </Modal>\n );\n}\n\nfunction ModelProviderRowsSkeleton({label}: {label: string}) {\n return (\n <ul\n role=\"status\"\n aria-label={label}\n className={cn('divide-y divide-border-neutral-base', SURFACE_CLASS)}\n >\n {[0, 1, 2].map((row) => (\n <li key={row} className=\"flex items-center gap-12 px-16 py-12\">\n <Skeleton className=\"size-32 shrink-0\" />\n <div className=\"flex min-w-0 flex-1 flex-col gap-6\">\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"h-14 w-180\" />\n </div>\n <Skeleton className=\"h-28 w-96 shrink-0\" />\n </li>\n ))}\n </ul>\n );\n}\n\nfunction ModelProviderGridSkeleton() {\n return (\n <div role=\"status\" aria-label=\"Loading available providers\" className={PROVIDER_GRID_CLASS}>\n {[0, 1, 2, 3].map((card) => (\n <Skeleton key={card} className=\"h-136 w-full\" />\n ))}\n </div>\n );\n}\n"],"names":["QueryLoadError","Button","IconButton","Callout","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","EmptyState","Icon","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","Skeleton","toast","Tooltip","TooltipContent","TooltipTrigger","Header","Text","cn","useEffect","useMemo","useReducer","useRef","useState","managementModalReducer","customProviderCardMatchesSearch","isSupportedProvider","availableProviders","selectAvailableProviders","useDeleteModelProviderConfigMutation","useModelProviderCatalogQuery","useModelProviderConfigsQuery","useSetDefaultModelProviderMutation","AddCustomProviderCard","AvailableProvidersGrid","PROVIDER_GRID_CLASS","ChangeDefaultModelForm","CustomModelProviderForm","modelProviderConfigErrorToFormError","ModelProviderUsageModal","usageTargetFromCatalogEntry","usageTargetFromCustomConfig","ModelProviderTestAndSaveForm","SURFACE_CLASS","USAGE_MODAL_OPEN_DELAY_MS","WorkspaceModelProvidersSection","workspaceId","catalogQuery","configsQuery","modal","dispatchModal","kind","pendingUsageTarget","setPendingUsageTarget","configuredProvidersRegionRef","providers","data","configs","configsLoaded","undefined","defaultProviderId","providerById","Map","map","provider","id","unsupportedProviders","filter","timer","window","setTimeout","type","providerId","target","initialModel","restoreFocusToConfiguredProviders","clearTimeout","usageTarget","config","find","item","entry","get","div","className","section","ref","aria-label","tabIndex","variant","size","isPending","ModelProviderRowsSkeleton","label","isError","query","subject","length","icon","title","description","ul","catalogEntry","builtinConfig","isBuiltinModelProviderConfig","customConfig","isCustomModelProviderConfig","ConfiguredProviderRow","isDefault","onEdit","onChangeDefaultModel","onShowUsage","defaultModel","ModelProviderGridSkeleton","entries","onSelect","trailingCard","onConfigure","trailingCardMatchesSearch","li","name","aria-hidden","bold","unsupportedReason","open","onOpenChange","aria-describedby","modelProviderFormTitle","existingConfig","onSaved","savedDefaultModel","success","workspaceDefaultHarnessId","defaultHarnessId","closeFocusTarget","current","customModelProviderFormTitle","displayName","setDefault","deleteConfig","defaultError","setDefaultError","deleteOpen","setDeleteOpen","deleteError","setDeleteError","canUse","canEdit","isBuiltinConfig","handleSetDefault","mutateAsync","error","mapped","message","handleDelete","handleDeleteOpenChange","nextOpen","reset","asChild","span","align","disabled","role","DeleteModelProviderDialog","errorMessage","isLoading","onDelete","onClick","row","card"],"mappings":"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"}
|