@shipfox/client-agent 17.0.0 → 22.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.
Files changed (58) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +34 -0
  3. package/dist/components/add-custom-provider-card.d.ts.map +1 -1
  4. package/dist/components/add-custom-provider-card.js +11 -31
  5. package/dist/components/add-custom-provider-card.js.map +1 -1
  6. package/dist/components/available-provider-card.d.ts.map +1 -1
  7. package/dist/components/available-provider-card.js +11 -31
  8. package/dist/components/available-provider-card.js.map +1 -1
  9. package/dist/components/available-providers-grid.d.ts +0 -1
  10. package/dist/components/available-providers-grid.d.ts.map +1 -1
  11. package/dist/components/available-providers-grid.js +33 -27
  12. package/dist/components/available-providers-grid.js.map +1 -1
  13. package/dist/components/custom-model-provider-form.stories.js +1 -1
  14. package/dist/components/custom-model-provider-form.stories.js.map +1 -1
  15. package/dist/components/harnesses-section.d.ts.map +1 -1
  16. package/dist/components/harnesses-section.js +147 -134
  17. package/dist/components/harnesses-section.js.map +1 -1
  18. package/dist/components/harnesses-section.stories.js +1 -1
  19. package/dist/components/harnesses-section.stories.js.map +1 -1
  20. package/dist/components/model-provider-grid-skeleton.d.ts +4 -0
  21. package/dist/components/model-provider-grid-skeleton.d.ts.map +1 -0
  22. package/dist/components/model-provider-grid-skeleton.js +34 -0
  23. package/dist/components/model-provider-grid-skeleton.js.map +1 -0
  24. package/dist/components/model-provider-usage-modal.stories.js +1 -1
  25. package/dist/components/model-provider-usage-modal.stories.js.map +1 -1
  26. package/dist/components/model-providers-section.d.ts.map +1 -1
  27. package/dist/components/model-providers-section.js +253 -245
  28. package/dist/components/model-providers-section.js.map +1 -1
  29. package/dist/components/model-providers-section.stories.js +1 -1
  30. package/dist/components/model-providers-section.stories.js.map +1 -1
  31. package/dist/pages/model-provider-onboarding-page.d.ts.map +1 -1
  32. package/dist/pages/model-provider-onboarding-page.js +32 -64
  33. package/dist/pages/model-provider-onboarding-page.js.map +1 -1
  34. package/dist/pages/model-provider-onboarding-page.stories.js +1 -1
  35. package/dist/pages/model-provider-onboarding-page.stories.js.map +1 -1
  36. package/dist/routes/agents-settings.d.ts +3 -0
  37. package/dist/routes/agents-settings.js +3 -0
  38. package/dist/routes/agents-settings.js.map +1 -1
  39. package/dist/routes/model-provider.d.ts +3 -0
  40. package/dist/routes/model-provider.js +3 -0
  41. package/dist/routes/model-provider.js.map +1 -1
  42. package/dist/tsconfig.test.tsbuildinfo +1 -1
  43. package/package.json +4 -4
  44. package/src/components/add-custom-provider-card.tsx +9 -23
  45. package/src/components/available-provider-card.tsx +9 -23
  46. package/src/components/available-providers-grid.tsx +36 -29
  47. package/src/components/custom-model-provider-form.stories.tsx +1 -1
  48. package/src/components/harnesses-section.stories.tsx +1 -1
  49. package/src/components/harnesses-section.tsx +116 -106
  50. package/src/components/model-provider-grid-skeleton.tsx +21 -0
  51. package/src/components/model-provider-usage-modal.stories.tsx +1 -1
  52. package/src/components/model-providers-section.stories.tsx +1 -1
  53. package/src/components/model-providers-section.tsx +208 -191
  54. package/src/pages/model-provider-onboarding-page.stories.tsx +1 -1
  55. package/src/pages/model-provider-onboarding-page.tsx +26 -54
  56. package/src/routes/agents-settings.tsx +1 -0
  57. package/src/routes/model-provider.tsx +1 -0
  58. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1 +1 @@
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-region\">\n <section\n ref={configuredProvidersRegionRef}\n className=\"flex flex-col gap-group outline-none\"\n aria-label=\"Configured providers\"\n tabIndex={-1}\n >\n <div className=\"flex flex-col gap-tight\">\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-row')}>\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-row')}>\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-group\" aria-label=\"Available providers\">\n <div className=\"flex flex-col gap-tight\">\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-row')}>\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-group\" aria-label=\"Unsupported providers\">\n <div className=\"flex flex-col gap-tight\">\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-cluster px-row py-row opacity-70\">\n <Icon\n name=\"forbid2Line\"\n className=\"mt-[2px] size-18 shrink-0 text-foreground-neutral-muted\"\n aria-hidden\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-tight\">\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-tight\">\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-inline px-row py-row transition-colors hover:bg-background-components-hover\">\n <div className=\"flex items-center justify-between gap-cluster\">\n <div className=\"flex min-w-0 items-center gap-inline\">\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-group\">\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-cluster px-row py-row\">\n <Skeleton className=\"size-32 shrink-0\" />\n <div className=\"flex min-w-0 flex-1 flex-col gap-inline\">\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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"}
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 {Panel, PanelBody, PanelRow} from '@shipfox/react-ui/panel';\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 {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} 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 {ModelProviderGridSkeleton} from './model-provider-grid-skeleton.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\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-region\">\n <section\n ref={configuredProvidersRegionRef}\n className=\"flex flex-col gap-group outline-none\"\n aria-label=\"Configured providers\"\n tabIndex={-1}\n >\n <div className=\"flex flex-col gap-tight\">\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 <Panel>\n <QueryLoadError query={configsQuery} subject=\"model provider configs\" variant=\"panel\" />\n </Panel>\n ) : null}\n\n {configsQuery.data !== undefined && configs.length === 0 ? (\n <Panel>\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 variant=\"panel\"\n />\n </Panel>\n ) : null}\n\n {configs.length > 0 ? (\n <Panel>\n <PanelBody asChild>\n <ul>\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({\n type: 'edit-builtin',\n provider: entry,\n config: builtinConfig,\n });\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 </PanelBody>\n </Panel>\n ) : null}\n </section>\n\n <section className=\"flex flex-col gap-group\" aria-label=\"Available providers\">\n <div className=\"flex flex-col gap-tight\">\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 ? (\n <ModelProviderGridSkeleton label=\"Loading available providers\" />\n ) : null}\n\n {catalogQuery.isError && catalogQuery.data === undefined ? (\n <Panel>\n <QueryLoadError query={catalogQuery} subject=\"model provider catalog\" variant=\"panel\" />\n </Panel>\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-group\" aria-label=\"Unsupported providers\">\n <div className=\"flex flex-col gap-tight\">\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 <Panel>\n <PanelBody asChild>\n <ul>\n {unsupportedProviders.map((entry) => (\n <PanelRow\n asChild\n className=\"items-start justify-start gap-cluster opacity-70 hover:bg-background-neutral-base\"\n key={entry.id}\n >\n <li>\n <Icon\n name=\"forbid2Line\"\n className=\"mt-[2px] size-18 shrink-0 text-foreground-neutral-muted\"\n aria-hidden\n />\n <div className=\"flex min-w-0 flex-1 flex-col gap-tight\">\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 </PanelRow>\n ))}\n </ul>\n </PanelBody>\n </Panel>\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-tight\">\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 <PanelRow asChild className=\"flex-col items-stretch gap-inline\">\n <li>\n <div className=\"flex items-center justify-between gap-cluster\">\n <div className=\"flex min-w-0 items-center gap-inline\">\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 </PanelRow>\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-group\">\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 <Panel>\n <PanelBody asChild>\n <ul role=\"status\" aria-label={label}>\n {[0, 1, 2].map((row) => (\n <PanelRow\n asChild\n className=\"justify-start gap-cluster hover:bg-background-neutral-base\"\n key={row}\n >\n <li>\n <Skeleton className=\"size-32 shrink-0\" />\n <div className=\"flex min-w-0 flex-1 flex-col gap-inline\">\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 </PanelRow>\n ))}\n </ul>\n </PanelBody>\n </Panel>\n );\n}\n"],"names":["QueryLoadError","Button","IconButton","Callout","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","EmptyState","Icon","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","Panel","PanelBody","PanelRow","Skeleton","toast","Tooltip","TooltipContent","TooltipTrigger","Header","Text","useEffect","useMemo","useReducer","useRef","useState","managementModalReducer","customProviderCardMatchesSearch","isSupportedProvider","availableProviders","selectAvailableProviders","useDeleteModelProviderConfigMutation","useModelProviderCatalogQuery","useModelProviderConfigsQuery","useSetDefaultModelProviderMutation","AddCustomProviderCard","AvailableProvidersGrid","ChangeDefaultModelForm","CustomModelProviderForm","modelProviderConfigErrorToFormError","ModelProviderGridSkeleton","ModelProviderUsageModal","usageTargetFromCatalogEntry","usageTargetFromCustomConfig","ModelProviderTestAndSaveForm","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","asChild","ul","catalogEntry","builtinConfig","isBuiltinModelProviderConfig","customConfig","isCustomModelProviderConfig","ConfiguredProviderRow","isDefault","onEdit","onChangeDefaultModel","onShowUsage","defaultModel","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","span","align","disabled","role","DeleteModelProviderDialog","errorMessage","isLoading","onDelete","onClick","row"],"mappings":"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"}
@@ -150,7 +150,7 @@ function ModelProvidersStory({ scenario }) {
150
150
  client: queryClient,
151
151
  children: [
152
152
  /*#__PURE__*/ _jsx("div", {
153
- className: "mx-auto w-full max-w-[760px] bg-background-neutral-background p-24",
153
+ className: "mx-auto w-full max-w-[760px] bg-background-subtle-base p-24",
154
154
  children: /*#__PURE__*/ _jsx(WorkspaceModelProvidersSection, {
155
155
  workspaceId: WORKSPACE_ID
156
156
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/model-providers-section.stories.tsx"],"sourcesContent":["import type {\n CustomModelProviderConfigDto,\n ModelProviderCatalogEntryDto,\n ModelProviderConfigDto,\n SupportedModelProviderId,\n} from '@shipfox/api-agent-dto';\nimport {configureApiClient} from '@shipfox/client-api';\nimport {Toaster} from '@shipfox/react-ui/toast';\nimport type {Meta, StoryObj} from '@storybook/react';\nimport {QueryClient, QueryClientProvider} from '@tanstack/react-query';\nimport {useMemo} from 'react';\nimport {screen, userEvent, within} from 'storybook/test';\nimport {WorkspaceModelProvidersSection} from './model-providers-section.js';\n\nconst WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';\n\ntype Scenario =\n | 'mixed'\n | 'empty-configured'\n | 'all-configured'\n | 'custom-configured'\n | 'loading'\n | 'configs-error'\n | 'catalog-error'\n | 'long-names';\n\ninterface ModelProvidersStoryProps {\n scenario: Scenario;\n}\n\nconst CATALOG: ModelProviderCatalogEntryDto[] = [\n providerEntry({\n id: 'anthropic',\n label: 'Anthropic',\n default_model: 'claude-opus-4-8',\n models: [\n {id: 'claude-opus-4-8', label: 'Claude Opus 4.8'},\n {id: 'claude-haiku-4-5', label: 'Claude Haiku 4.5'},\n ],\n }),\n providerEntry({\n id: 'openai',\n label: 'OpenAI',\n default_model: 'gpt-5.5-pro',\n models: [\n {id: 'gpt-5.5-pro', label: 'GPT-5.5 Pro'},\n {id: 'gpt-5-mini', label: 'GPT-5 Mini'},\n ],\n }),\n providerEntry({\n id: 'xai',\n label: 'xAI',\n default_model: 'grok-code-fast-1',\n models: [{id: 'grok-code-fast-1', label: 'Grok Code Fast 1'}],\n }),\n providerEntry({\n id: 'openrouter',\n label: 'OpenRouter',\n default_model: 'openrouter/auto',\n models: [{id: 'openrouter/auto', label: 'OpenRouter Auto'}],\n }),\n providerEntry({\n id: 'google',\n label: 'Google Gemini',\n default_model: 'gemini-3-pro',\n models: [{id: 'gemini-3-pro', label: 'Gemini 3 Pro'}],\n }),\n providerEntry({\n id: 'mistral',\n label: 'Mistral AI',\n default_model: 'codestral-latest',\n models: [{id: 'codestral-latest', label: 'Codestral Latest'}],\n }),\n providerEntry({\n id: 'groq',\n label: 'Groq',\n default_model: 'llama-4-fast',\n models: [{id: 'llama-4-fast', label: 'Llama 4 Fast'}],\n }),\n providerEntry({\n id: 'deepseek',\n label: 'DeepSeek',\n default_model: 'deepseek-coder',\n models: [{id: 'deepseek-coder', label: 'DeepSeek Coder'}],\n }),\n providerEntry({\n id: 'moonshotai',\n label: 'Moonshot AI',\n default_model: 'kimi-k2',\n models: [{id: 'kimi-k2', label: 'Kimi K2'}],\n }),\n providerEntry({\n id: 'azure-openai-responses',\n label: 'Azure OpenAI Responses',\n default_model: 'gpt-5.5-pro',\n models: [{id: 'gpt-5.5-pro', label: 'GPT-5.5 Pro'}],\n }),\n providerEntry({\n id: 'amazon-bedrock',\n label: 'Amazon Bedrock',\n support_status: 'unsupported',\n credential_fields: [],\n unsupported_reason: 'AWS cloud credentials are not supported yet.',\n models: [],\n }),\n];\n\nfunction ModelProvidersStory({scenario}: ModelProvidersStoryProps) {\n configureApiClient({\n baseUrl: 'https://api.example.test',\n fetchImpl: fetchForScenario(scenario),\n });\n\n const queryClient = useMemo(\n () => new QueryClient({defaultOptions: {queries: {retry: false}}}),\n [],\n );\n\n return (\n <QueryClientProvider client={queryClient}>\n <div className=\"mx-auto w-full max-w-[760px] bg-background-neutral-background p-24\">\n <WorkspaceModelProvidersSection workspaceId={WORKSPACE_ID} />\n </div>\n <Toaster />\n </QueryClientProvider>\n );\n}\n\nconst meta = {\n title: 'Agent/ProviderSettings',\n component: ModelProvidersStory,\n parameters: {layout: 'fullscreen'},\n args: {scenario: 'mixed'},\n} satisfies Meta<typeof ModelProvidersStory>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Playground: Story = {};\n\nexport const EmptyConfigured: Story = {\n args: {scenario: 'empty-configured'},\n};\n\nexport const AllConfigured: Story = {\n args: {scenario: 'all-configured'},\n};\n\nexport const CustomConfigured: Story = {\n args: {scenario: 'custom-configured'},\n};\n\nexport const Loading: Story = {\n args: {scenario: 'loading'},\n};\n\nexport const ConfigsError: Story = {\n args: {scenario: 'configs-error'},\n};\n\nexport const CatalogError: Story = {\n args: {scenario: 'catalog-error'},\n};\n\nexport const LongNames: Story = {\n args: {scenario: 'long-names'},\n};\n\nexport const FilteredAvailableProviders: Story = {\n args: {scenario: 'empty-configured'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.type(\n await canvas.findByRole('searchbox', {name: 'Search providers'}),\n 'openrouter',\n );\n await canvas.findByRole('button', {name: 'Configure OpenRouter'});\n },\n};\n\nexport const NoMatchingAvailableProviders: Story = {\n args: {scenario: 'empty-configured'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.type(\n await canvas.findByRole('searchbox', {name: 'Search providers'}),\n 'not-a-provider',\n );\n await canvas.findByRole('button', {name: 'Clear search'});\n },\n};\n\nexport const ConfigureModalOpen: Story = {\n args: {scenario: 'empty-configured'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Configure Anthropic'}));\n await screen.findByLabelText('API key');\n },\n};\n\nexport const CustomProviderModalOpen: Story = {\n args: {scenario: 'empty-configured'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Configure custom provider'}));\n await screen.findByRole('dialog', {name: 'Add custom provider'});\n },\n};\n\nexport const WorkflowExampleModalOpen: Story = {\n args: {scenario: 'mixed'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(\n await canvas.findByRole('button', {name: 'Open Anthropic provider actions'}),\n );\n await userEvent.click(await screen.findByRole('menuitem', {name: 'View workflow example'}));\n await screen.findByRole('dialog', {name: 'Use Anthropic in a workflow'});\n },\n};\n\nfunction fetchForScenario(scenario: Scenario): typeof fetch {\n return (input) => {\n const url = requestUrl(input);\n if (scenario === 'loading') return new Promise<Response>(() => undefined);\n if (url.pathname.endsWith('/agent/model-provider-catalog')) {\n if (scenario === 'catalog-error') return Promise.resolve(errorResponse());\n return Promise.resolve(jsonResponse({providers: catalogForScenario(scenario)}));\n }\n if (url.pathname.endsWith('/agent/model-providers')) {\n if (scenario === 'configs-error') return Promise.resolve(errorResponse());\n return Promise.resolve(jsonResponse(configsForScenario(scenario)));\n }\n return Promise.resolve(jsonResponse({}, {status: 404}));\n };\n}\n\nfunction catalogForScenario(scenario: Scenario): ModelProviderCatalogEntryDto[] {\n if (scenario !== 'long-names') return CATALOG;\n return [\n providerEntry({\n id: 'anthropic',\n label: 'Anthropic Enterprise Production Claude Provider With Long Label',\n default_model: 'claude-opus-4-8',\n }),\n providerEntry({\n id: 'openai',\n label: 'OpenAI Platform Shared Workspace Credentials With Long Label',\n default_model: 'gpt-5.5-pro',\n models: [{id: 'gpt-5.5-pro', label: 'GPT-5.5 Pro'}],\n }),\n ];\n}\n\nfunction configsForScenario(scenario: Scenario) {\n if (scenario === 'empty-configured' || scenario === 'configs-error') {\n return {configs: [], default_provider_id: null, default_harness_id: null};\n }\n if (scenario === 'all-configured') {\n return {\n configs: CATALOG.filter((entry) => entry.support_status === 'supported').map((entry) =>\n providerConfig({\n provider_id: entry.id as SupportedModelProviderId,\n }),\n ),\n default_provider_id: 'anthropic',\n default_harness_id: null,\n };\n }\n if (scenario === 'custom-configured') {\n return {\n configs: [providerConfig({provider_id: 'anthropic'}), customProviderConfig()],\n default_provider_id: 'local-vllm',\n default_harness_id: null,\n };\n }\n return {\n configs: [providerConfig({provider_id: 'anthropic'})],\n default_provider_id: 'anthropic',\n default_harness_id: null,\n };\n}\n\nfunction customProviderConfig(): CustomModelProviderConfigDto {\n return {\n kind: 'custom',\n provider_id: 'local-vllm',\n display_name: 'Local vLLM',\n api: 'openai-completions',\n base_url: 'http://localhost:8000/v1',\n headers: [{name: 'x-region', value: 'us'}],\n secret_header_names: ['authorization'],\n models: [\n {id: 'llama-3.1', label: 'Llama 3.1'},\n {id: 'qwen-coder', label: 'Qwen Coder'},\n ],\n default_model: 'llama-3.1',\n created_at: '2026-05-08T00:00:00.000Z',\n updated_at: '2026-05-08T00:00:00.000Z',\n };\n}\n\nfunction providerEntry(\n overrides: Partial<ModelProviderCatalogEntryDto> = {},\n): ModelProviderCatalogEntryDto {\n return {\n id: 'anthropic',\n label: 'Anthropic',\n support_status: 'supported',\n default_model: null,\n credential_fields: [{key: 'api_key', label: 'API key', secret: true}],\n unsupported_reason: null,\n models: [{id: 'claude-opus-4-8', label: 'Claude Opus 4.8'}],\n ...overrides,\n };\n}\n\nfunction providerConfig(\n overrides: Partial<Omit<ModelProviderConfigDto, 'kind'>> = {},\n): ModelProviderConfigDto {\n return {\n kind: 'builtin',\n provider_id: 'anthropic',\n default_model: null,\n created_at: '2026-05-08T00:00:00.000Z',\n updated_at: '2026-05-08T00:00:00.000Z',\n ...overrides,\n };\n}\n\nfunction requestUrl(input: RequestInfo | URL): URL {\n if (typeof input === 'string') return new URL(input);\n if (input instanceof URL) return input;\n return new URL(input.url);\n}\n\nfunction jsonResponse(body: unknown, init: ResponseInit = {}) {\n return new Response(JSON.stringify(body), {\n status: 200,\n headers: {'content-type': 'application/json'},\n ...init,\n });\n}\n\nfunction errorResponse() {\n return jsonResponse({code: 'server-error'}, {status: 500, statusText: 'Server error'});\n}\n"],"names":["configureApiClient","Toaster","QueryClient","QueryClientProvider","useMemo","screen","userEvent","within","WorkspaceModelProvidersSection","WORKSPACE_ID","CATALOG","providerEntry","id","label","default_model","models","support_status","credential_fields","unsupported_reason","ModelProvidersStory","scenario","baseUrl","fetchImpl","fetchForScenario","queryClient","defaultOptions","queries","retry","client","div","className","workspaceId","meta","title","component","parameters","layout","args","Playground","EmptyConfigured","AllConfigured","CustomConfigured","Loading","ConfigsError","CatalogError","LongNames","FilteredAvailableProviders","play","canvasElement","canvas","type","findByRole","name","NoMatchingAvailableProviders","ConfigureModalOpen","click","findByLabelText","CustomProviderModalOpen","WorkflowExampleModalOpen","input","url","requestUrl","Promise","undefined","pathname","endsWith","resolve","errorResponse","jsonResponse","providers","catalogForScenario","configsForScenario","status","configs","default_provider_id","default_harness_id","filter","entry","map","providerConfig","provider_id","customProviderConfig","kind","display_name","api","base_url","headers","value","secret_header_names","created_at","updated_at","overrides","key","secret","URL","body","init","Response","JSON","stringify","code","statusText"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/model-providers-section.stories.tsx"],"sourcesContent":["import type {\n CustomModelProviderConfigDto,\n ModelProviderCatalogEntryDto,\n ModelProviderConfigDto,\n SupportedModelProviderId,\n} from '@shipfox/api-agent-dto';\nimport {configureApiClient} from '@shipfox/client-api';\nimport {Toaster} from '@shipfox/react-ui/toast';\nimport type {Meta, StoryObj} from '@storybook/react';\nimport {QueryClient, QueryClientProvider} from '@tanstack/react-query';\nimport {useMemo} from 'react';\nimport {screen, userEvent, within} from 'storybook/test';\nimport {WorkspaceModelProvidersSection} from './model-providers-section.js';\n\nconst WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';\n\ntype Scenario =\n | 'mixed'\n | 'empty-configured'\n | 'all-configured'\n | 'custom-configured'\n | 'loading'\n | 'configs-error'\n | 'catalog-error'\n | 'long-names';\n\ninterface ModelProvidersStoryProps {\n scenario: Scenario;\n}\n\nconst CATALOG: ModelProviderCatalogEntryDto[] = [\n providerEntry({\n id: 'anthropic',\n label: 'Anthropic',\n default_model: 'claude-opus-4-8',\n models: [\n {id: 'claude-opus-4-8', label: 'Claude Opus 4.8'},\n {id: 'claude-haiku-4-5', label: 'Claude Haiku 4.5'},\n ],\n }),\n providerEntry({\n id: 'openai',\n label: 'OpenAI',\n default_model: 'gpt-5.5-pro',\n models: [\n {id: 'gpt-5.5-pro', label: 'GPT-5.5 Pro'},\n {id: 'gpt-5-mini', label: 'GPT-5 Mini'},\n ],\n }),\n providerEntry({\n id: 'xai',\n label: 'xAI',\n default_model: 'grok-code-fast-1',\n models: [{id: 'grok-code-fast-1', label: 'Grok Code Fast 1'}],\n }),\n providerEntry({\n id: 'openrouter',\n label: 'OpenRouter',\n default_model: 'openrouter/auto',\n models: [{id: 'openrouter/auto', label: 'OpenRouter Auto'}],\n }),\n providerEntry({\n id: 'google',\n label: 'Google Gemini',\n default_model: 'gemini-3-pro',\n models: [{id: 'gemini-3-pro', label: 'Gemini 3 Pro'}],\n }),\n providerEntry({\n id: 'mistral',\n label: 'Mistral AI',\n default_model: 'codestral-latest',\n models: [{id: 'codestral-latest', label: 'Codestral Latest'}],\n }),\n providerEntry({\n id: 'groq',\n label: 'Groq',\n default_model: 'llama-4-fast',\n models: [{id: 'llama-4-fast', label: 'Llama 4 Fast'}],\n }),\n providerEntry({\n id: 'deepseek',\n label: 'DeepSeek',\n default_model: 'deepseek-coder',\n models: [{id: 'deepseek-coder', label: 'DeepSeek Coder'}],\n }),\n providerEntry({\n id: 'moonshotai',\n label: 'Moonshot AI',\n default_model: 'kimi-k2',\n models: [{id: 'kimi-k2', label: 'Kimi K2'}],\n }),\n providerEntry({\n id: 'azure-openai-responses',\n label: 'Azure OpenAI Responses',\n default_model: 'gpt-5.5-pro',\n models: [{id: 'gpt-5.5-pro', label: 'GPT-5.5 Pro'}],\n }),\n providerEntry({\n id: 'amazon-bedrock',\n label: 'Amazon Bedrock',\n support_status: 'unsupported',\n credential_fields: [],\n unsupported_reason: 'AWS cloud credentials are not supported yet.',\n models: [],\n }),\n];\n\nfunction ModelProvidersStory({scenario}: ModelProvidersStoryProps) {\n configureApiClient({\n baseUrl: 'https://api.example.test',\n fetchImpl: fetchForScenario(scenario),\n });\n\n const queryClient = useMemo(\n () => new QueryClient({defaultOptions: {queries: {retry: false}}}),\n [],\n );\n\n return (\n <QueryClientProvider client={queryClient}>\n <div className=\"mx-auto w-full max-w-[760px] bg-background-subtle-base p-24\">\n <WorkspaceModelProvidersSection workspaceId={WORKSPACE_ID} />\n </div>\n <Toaster />\n </QueryClientProvider>\n );\n}\n\nconst meta = {\n title: 'Agent/ProviderSettings',\n component: ModelProvidersStory,\n parameters: {layout: 'fullscreen'},\n args: {scenario: 'mixed'},\n} satisfies Meta<typeof ModelProvidersStory>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Playground: Story = {};\n\nexport const EmptyConfigured: Story = {\n args: {scenario: 'empty-configured'},\n};\n\nexport const AllConfigured: Story = {\n args: {scenario: 'all-configured'},\n};\n\nexport const CustomConfigured: Story = {\n args: {scenario: 'custom-configured'},\n};\n\nexport const Loading: Story = {\n args: {scenario: 'loading'},\n};\n\nexport const ConfigsError: Story = {\n args: {scenario: 'configs-error'},\n};\n\nexport const CatalogError: Story = {\n args: {scenario: 'catalog-error'},\n};\n\nexport const LongNames: Story = {\n args: {scenario: 'long-names'},\n};\n\nexport const FilteredAvailableProviders: Story = {\n args: {scenario: 'empty-configured'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.type(\n await canvas.findByRole('searchbox', {name: 'Search providers'}),\n 'openrouter',\n );\n await canvas.findByRole('button', {name: 'Configure OpenRouter'});\n },\n};\n\nexport const NoMatchingAvailableProviders: Story = {\n args: {scenario: 'empty-configured'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.type(\n await canvas.findByRole('searchbox', {name: 'Search providers'}),\n 'not-a-provider',\n );\n await canvas.findByRole('button', {name: 'Clear search'});\n },\n};\n\nexport const ConfigureModalOpen: Story = {\n args: {scenario: 'empty-configured'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Configure Anthropic'}));\n await screen.findByLabelText('API key');\n },\n};\n\nexport const CustomProviderModalOpen: Story = {\n args: {scenario: 'empty-configured'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Configure custom provider'}));\n await screen.findByRole('dialog', {name: 'Add custom provider'});\n },\n};\n\nexport const WorkflowExampleModalOpen: Story = {\n args: {scenario: 'mixed'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(\n await canvas.findByRole('button', {name: 'Open Anthropic provider actions'}),\n );\n await userEvent.click(await screen.findByRole('menuitem', {name: 'View workflow example'}));\n await screen.findByRole('dialog', {name: 'Use Anthropic in a workflow'});\n },\n};\n\nfunction fetchForScenario(scenario: Scenario): typeof fetch {\n return (input) => {\n const url = requestUrl(input);\n if (scenario === 'loading') return new Promise<Response>(() => undefined);\n if (url.pathname.endsWith('/agent/model-provider-catalog')) {\n if (scenario === 'catalog-error') return Promise.resolve(errorResponse());\n return Promise.resolve(jsonResponse({providers: catalogForScenario(scenario)}));\n }\n if (url.pathname.endsWith('/agent/model-providers')) {\n if (scenario === 'configs-error') return Promise.resolve(errorResponse());\n return Promise.resolve(jsonResponse(configsForScenario(scenario)));\n }\n return Promise.resolve(jsonResponse({}, {status: 404}));\n };\n}\n\nfunction catalogForScenario(scenario: Scenario): ModelProviderCatalogEntryDto[] {\n if (scenario !== 'long-names') return CATALOG;\n return [\n providerEntry({\n id: 'anthropic',\n label: 'Anthropic Enterprise Production Claude Provider With Long Label',\n default_model: 'claude-opus-4-8',\n }),\n providerEntry({\n id: 'openai',\n label: 'OpenAI Platform Shared Workspace Credentials With Long Label',\n default_model: 'gpt-5.5-pro',\n models: [{id: 'gpt-5.5-pro', label: 'GPT-5.5 Pro'}],\n }),\n ];\n}\n\nfunction configsForScenario(scenario: Scenario) {\n if (scenario === 'empty-configured' || scenario === 'configs-error') {\n return {configs: [], default_provider_id: null, default_harness_id: null};\n }\n if (scenario === 'all-configured') {\n return {\n configs: CATALOG.filter((entry) => entry.support_status === 'supported').map((entry) =>\n providerConfig({\n provider_id: entry.id as SupportedModelProviderId,\n }),\n ),\n default_provider_id: 'anthropic',\n default_harness_id: null,\n };\n }\n if (scenario === 'custom-configured') {\n return {\n configs: [providerConfig({provider_id: 'anthropic'}), customProviderConfig()],\n default_provider_id: 'local-vllm',\n default_harness_id: null,\n };\n }\n return {\n configs: [providerConfig({provider_id: 'anthropic'})],\n default_provider_id: 'anthropic',\n default_harness_id: null,\n };\n}\n\nfunction customProviderConfig(): CustomModelProviderConfigDto {\n return {\n kind: 'custom',\n provider_id: 'local-vllm',\n display_name: 'Local vLLM',\n api: 'openai-completions',\n base_url: 'http://localhost:8000/v1',\n headers: [{name: 'x-region', value: 'us'}],\n secret_header_names: ['authorization'],\n models: [\n {id: 'llama-3.1', label: 'Llama 3.1'},\n {id: 'qwen-coder', label: 'Qwen Coder'},\n ],\n default_model: 'llama-3.1',\n created_at: '2026-05-08T00:00:00.000Z',\n updated_at: '2026-05-08T00:00:00.000Z',\n };\n}\n\nfunction providerEntry(\n overrides: Partial<ModelProviderCatalogEntryDto> = {},\n): ModelProviderCatalogEntryDto {\n return {\n id: 'anthropic',\n label: 'Anthropic',\n support_status: 'supported',\n default_model: null,\n credential_fields: [{key: 'api_key', label: 'API key', secret: true}],\n unsupported_reason: null,\n models: [{id: 'claude-opus-4-8', label: 'Claude Opus 4.8'}],\n ...overrides,\n };\n}\n\nfunction providerConfig(\n overrides: Partial<Omit<ModelProviderConfigDto, 'kind'>> = {},\n): ModelProviderConfigDto {\n return {\n kind: 'builtin',\n provider_id: 'anthropic',\n default_model: null,\n created_at: '2026-05-08T00:00:00.000Z',\n updated_at: '2026-05-08T00:00:00.000Z',\n ...overrides,\n };\n}\n\nfunction requestUrl(input: RequestInfo | URL): URL {\n if (typeof input === 'string') return new URL(input);\n if (input instanceof URL) return input;\n return new URL(input.url);\n}\n\nfunction jsonResponse(body: unknown, init: ResponseInit = {}) {\n return new Response(JSON.stringify(body), {\n status: 200,\n headers: {'content-type': 'application/json'},\n ...init,\n });\n}\n\nfunction errorResponse() {\n return jsonResponse({code: 'server-error'}, {status: 500, statusText: 'Server error'});\n}\n"],"names":["configureApiClient","Toaster","QueryClient","QueryClientProvider","useMemo","screen","userEvent","within","WorkspaceModelProvidersSection","WORKSPACE_ID","CATALOG","providerEntry","id","label","default_model","models","support_status","credential_fields","unsupported_reason","ModelProvidersStory","scenario","baseUrl","fetchImpl","fetchForScenario","queryClient","defaultOptions","queries","retry","client","div","className","workspaceId","meta","title","component","parameters","layout","args","Playground","EmptyConfigured","AllConfigured","CustomConfigured","Loading","ConfigsError","CatalogError","LongNames","FilteredAvailableProviders","play","canvasElement","canvas","type","findByRole","name","NoMatchingAvailableProviders","ConfigureModalOpen","click","findByLabelText","CustomProviderModalOpen","WorkflowExampleModalOpen","input","url","requestUrl","Promise","undefined","pathname","endsWith","resolve","errorResponse","jsonResponse","providers","catalogForScenario","configsForScenario","status","configs","default_provider_id","default_harness_id","filter","entry","map","providerConfig","provider_id","customProviderConfig","kind","display_name","api","base_url","headers","value","secret_header_names","created_at","updated_at","overrides","key","secret","URL","body","init","Response","JSON","stringify","code","statusText"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"model-provider-onboarding-page.d.ts","sourceRoot":"","sources":["../../src/pages/model-provider-onboarding-page.tsx"],"names":[],"mappings":"AA2BA,wBAAgB,2BAA2B,CAAC,EAC1C,WAAW,EACX,MAAM,EACN,YAAY,GACb,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,+BAmLA"}
1
+ {"version":3,"file":"model-provider-onboarding-page.d.ts","sourceRoot":"","sources":["../../src/pages/model-provider-onboarding-page.tsx"],"names":[],"mappings":"AAuBA,wBAAgB,2BAA2B,CAAC,EAC1C,WAAW,EACX,MAAM,EACN,YAAY,GACb,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,+BAmLA"}
@@ -3,22 +3,20 @@ import { QueryLoadError } from '@shipfox/client-ui';
3
3
  import { Button } from '@shipfox/react-ui/button';
4
4
  import { Callout } from '@shipfox/react-ui/callout';
5
5
  import { EmptyState } from '@shipfox/react-ui/empty-state';
6
- import { Icon } from '@shipfox/react-ui/icon';
7
6
  import { Modal, ModalContent, ModalHeader, ModalTitle } from '@shipfox/react-ui/modal';
8
- import { Skeleton } from '@shipfox/react-ui/skeleton';
7
+ import { Panel, PanelBody, PanelCell, PanelCellAction, PanelGrid } from '@shipfox/react-ui/panel';
9
8
  import { toast } from '@shipfox/react-ui/toast';
10
9
  import { Header, Text } from '@shipfox/react-ui/typography';
11
- import { cn } from '@shipfox/react-ui/utils';
12
10
  import { useEffect, useMemo, useReducer } from 'react';
13
- import { AvailableProvidersGrid, PROVIDER_GRID_CLASS } from '#components/available-providers-grid.js';
11
+ import { AvailableProvidersGrid } from '#components/available-providers-grid.js';
14
12
  import { modelProviderConfigErrorToFormError } from '#components/form-errors.js';
13
+ import { ModelProviderGridSkeleton } from '#components/model-provider-grid-skeleton.js';
15
14
  import { ModelProviderTestAndSaveForm } from '#components/test-and-save-form.js';
16
15
  import { DEFAULT_HARNESS, harnessSupportsProvider, listHarnesses } from '#core/harness-policy.js';
17
16
  import { initialOnboardingState, onboardingReducer } from '#core/onboarding-reducer.js';
18
17
  import { isSupportedProvider } from '#core/provider-policy.js';
19
18
  import { useModelProviderCatalogQuery, useSetDefaultHarnessMutation } from '#hooks/api/model-providers.js';
20
19
  import { dismissModelProviderOnboarding } from '#state/model-provider-onboarding.js';
21
- const SURFACE_CLASS = 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';
22
20
  export function ModelProviderOnboardingPage({ workspaceId, onSkip, onConfigured }) {
23
21
  const catalogQuery = useModelProviderCatalogQuery();
24
22
  const setDefaultHarness = useSetDefaultHarnessMutation();
@@ -79,7 +77,7 @@ export function ModelProviderOnboardingPage({ workspaceId, onSkip, onConfigured
79
77
  const selectedHarnessDescriptor = onboarding.step === 'choose-harness' ? null : listHarnesses().find((harness)=>harness.id === onboarding.harnessId);
80
78
  const headingId = onboarding.step === 'choose-harness' ? 'model-provider-harness-step' : 'model-provider-provider-step';
81
79
  return /*#__PURE__*/ _jsxs("div", {
82
- className: "mx-auto flex w-full max-w-[640px] flex-col gap-section",
80
+ className: "flex w-full flex-col gap-section",
83
81
  children: [
84
82
  /*#__PURE__*/ _jsxs("header", {
85
83
  className: "flex flex-col gap-cluster",
@@ -218,53 +216,39 @@ export function ModelProviderOnboardingPage({ workspaceId, onSkip, onConfigured
218
216
  });
219
217
  }
220
218
  function HarnessPicker({ onSelect }) {
221
- return /*#__PURE__*/ _jsx("ul", {
222
- className: PROVIDER_GRID_CLASS,
223
- "aria-label": "Agent harnesses",
224
- children: listHarnesses().map((harness)=>/*#__PURE__*/ _jsx(HarnessCard, {
225
- harness: harness,
226
- onChoose: ()=>onSelect(harness.id)
227
- }, harness.id))
219
+ return /*#__PURE__*/ _jsx(Panel, {
220
+ children: /*#__PURE__*/ _jsx(PanelBody, {
221
+ children: /*#__PURE__*/ _jsx(PanelGrid, {
222
+ "aria-label": "Agent harnesses",
223
+ children: listHarnesses().map((harness)=>/*#__PURE__*/ _jsx(HarnessCard, {
224
+ harness: harness,
225
+ onChoose: ()=>onSelect(harness.id)
226
+ }, harness.id))
227
+ })
228
+ })
228
229
  });
229
230
  }
230
231
  function HarnessCard({ harness, onChoose }) {
231
- return /*#__PURE__*/ _jsx("li", {
232
- children: /*#__PURE__*/ _jsx("button", {
233
- type: "button",
234
- className: cn('group block w-full cursor-pointer p-panel-compact text-left outline-none transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus', SURFACE_CLASS),
232
+ return /*#__PURE__*/ _jsx(PanelCell, {
233
+ children: /*#__PURE__*/ _jsx(PanelCellAction, {
234
+ action: "Choose",
235
235
  "aria-label": `Choose ${harness.label}`,
236
236
  onClick: onChoose,
237
- children: /*#__PURE__*/ _jsxs("div", {
238
- className: "flex min-w-0 items-center justify-between gap-cluster",
237
+ children: /*#__PURE__*/ _jsxs("span", {
238
+ className: "flex min-w-0 flex-col gap-tight",
239
239
  children: [
240
- /*#__PURE__*/ _jsxs("div", {
241
- className: "flex min-w-0 flex-col gap-tight",
242
- children: [
243
- /*#__PURE__*/ _jsx(Text, {
244
- size: "md",
245
- bold: true,
246
- className: "min-w-0 truncate",
247
- children: harness.label
248
- }),
249
- /*#__PURE__*/ _jsx(Text, {
250
- size: "sm",
251
- className: "text-foreground-neutral-muted",
252
- children: harness.description
253
- })
254
- ]
240
+ /*#__PURE__*/ _jsx(Text, {
241
+ as: "span",
242
+ size: "md",
243
+ bold: true,
244
+ className: "min-w-0 truncate",
245
+ children: harness.label
255
246
  }),
256
- /*#__PURE__*/ _jsxs("div", {
257
- className: "flex shrink-0 items-center gap-tight text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive",
258
- children: [
259
- /*#__PURE__*/ _jsx(Text, {
260
- size: "sm",
261
- children: "Choose"
262
- }),
263
- /*#__PURE__*/ _jsx(Icon, {
264
- name: "chevronRight",
265
- className: "size-16"
266
- })
267
- ]
247
+ /*#__PURE__*/ _jsx(Text, {
248
+ as: "span",
249
+ size: "sm",
250
+ className: "text-foreground-neutral-muted",
251
+ children: harness.description
268
252
  })
269
253
  ]
270
254
  })
@@ -273,11 +257,8 @@ function HarnessCard({ harness, onChoose }) {
273
257
  }
274
258
  function ModelProviderPicker({ catalogQuery, supportedProviders, onSelect }) {
275
259
  if (catalogQuery.isPending) {
276
- return /*#__PURE__*/ _jsx("div", {
277
- role: "status",
278
- "aria-busy": "true",
279
- "aria-label": "Loading model providers",
280
- children: /*#__PURE__*/ _jsx(ModelProviderGridSkeleton, {})
260
+ return /*#__PURE__*/ _jsx(ModelProviderGridSkeleton, {
261
+ label: "Loading model providers"
281
262
  });
282
263
  }
283
264
  if (catalogQuery.isError && catalogQuery.data === undefined) {
@@ -298,18 +279,5 @@ function ModelProviderPicker({ catalogQuery, supportedProviders, onSelect }) {
298
279
  onSelect: onSelect
299
280
  });
300
281
  }
301
- function ModelProviderGridSkeleton() {
302
- return /*#__PURE__*/ _jsx("div", {
303
- className: PROVIDER_GRID_CLASS,
304
- children: [
305
- 0,
306
- 1,
307
- 2,
308
- 3
309
- ].map((card)=>/*#__PURE__*/ _jsx(Skeleton, {
310
- className: "h-136 w-full"
311
- }, card))
312
- });
313
- }
314
282
 
315
283
  //# sourceMappingURL=model-provider-onboarding-page.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/model-provider-onboarding-page.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {Modal, ModalContent, ModalHeader, ModalTitle} from '@shipfox/react-ui/modal';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {useEffect, useMemo, useReducer} from 'react';\nimport {AvailableProvidersGrid, PROVIDER_GRID_CLASS} from '#components/available-providers-grid.js';\nimport {modelProviderConfigErrorToFormError} from '#components/form-errors.js';\nimport {ModelProviderTestAndSaveForm} from '#components/test-and-save-form.js';\nimport {DEFAULT_HARNESS, harnessSupportsProvider, listHarnesses} from '#core/harness-policy.js';\nimport type {HarnessDescriptor, HarnessId, SupportedProvider} from '#core/models.js';\nimport {initialOnboardingState, onboardingReducer} from '#core/onboarding-reducer.js';\nimport {isSupportedProvider} from '#core/provider-policy.js';\nimport {\n useModelProviderCatalogQuery,\n useSetDefaultHarnessMutation,\n} from '#hooks/api/model-providers.js';\nimport {dismissModelProviderOnboarding} from '#state/model-provider-onboarding.js';\n\nconst SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\nexport function ModelProviderOnboardingPage({\n workspaceId,\n onSkip,\n onConfigured,\n}: {\n workspaceId: string;\n onSkip: () => void;\n onConfigured: () => void;\n}) {\n const catalogQuery = useModelProviderCatalogQuery();\n const setDefaultHarness = useSetDefaultHarnessMutation();\n const [onboarding, dispatch] = useReducer(onboardingReducer, initialOnboardingState);\n const supportedProviders = catalogQuery.data?.providers.filter(isSupportedProvider) ?? [];\n const filteredProviders = useMemo(() => {\n if (onboarding.step === 'choose-harness') return [];\n return supportedProviders.filter((provider) =>\n harnessSupportsProvider(onboarding.harnessId, provider.id),\n );\n }, [onboarding, supportedProviders]);\n\n useEffect(() => {\n document\n .getElementById(\n onboarding.step === 'choose-harness'\n ? 'model-provider-harness-step'\n : 'model-provider-provider-step',\n )\n ?.focus();\n }, [onboarding.step]);\n\n function handleSkip() {\n try {\n dismissModelProviderOnboarding(workspaceId);\n } catch {\n // Skip is best-effort persistence; access to the product must not depend on storage.\n }\n onSkip();\n }\n\n async function handleProviderSaved() {\n if (onboarding.step !== 'configure-provider' && onboarding.step !== 'saving-default-harness')\n return;\n\n const provider = onboarding.provider;\n if (onboarding.step === 'configure-provider') dispatch({type: 'provider-saved'});\n if (onboarding.harnessId === DEFAULT_HARNESS) {\n toast.success(`${provider.label} saved`);\n dispatch({type: 'default-harness-saved'});\n onConfigured();\n return;\n }\n\n try {\n await setDefaultHarness.mutateAsync({\n workspaceId,\n harnessId: onboarding.harnessId,\n });\n toast.success(`${provider.label} saved`);\n dispatch({type: 'default-harness-saved'});\n onConfigured();\n } catch (error) {\n const mapped = modelProviderConfigErrorToFormError(error);\n dispatch({\n type: 'default-harness-failed',\n message: mapped.message || 'Could not save default harness. Try again.',\n });\n }\n }\n\n const selectedHarnessDescriptor =\n onboarding.step === 'choose-harness'\n ? null\n : listHarnesses().find((harness) => harness.id === onboarding.harnessId);\n const headingId =\n onboarding.step === 'choose-harness'\n ? 'model-provider-harness-step'\n : 'model-provider-provider-step';\n\n return (\n <div className=\"mx-auto flex w-full max-w-[640px] flex-col gap-section\">\n <header className=\"flex flex-col gap-cluster\">\n <div className=\"flex items-start justify-between gap-group max-[520px]:flex-col max-[520px]:gap-inline\">\n <Header id={headingId} variant=\"h1\" tabIndex={-1} className=\"outline-none\">\n {selectedHarnessDescriptor\n ? `Configure ${selectedHarnessDescriptor.label}`\n : 'Choose agent harness'}\n </Header>\n <Button type=\"button\" variant=\"secondary\" onClick={handleSkip} className=\"shrink-0\">\n Skip for now\n </Button>\n </div>\n <Text size=\"md\" className=\"text-foreground-neutral-muted\">\n {selectedHarnessDescriptor\n ? `${selectedHarnessDescriptor.label} needs a compatible model provider. Add your own API key, or go back to choose a different harness.`\n : 'A harness runs agent steps. Choose the engine you want first, then connect a compatible model provider.'}\n </Text>\n </header>\n\n <section aria-labelledby={headingId} className=\"flex flex-col gap-group\">\n {onboarding.step === 'choose-harness' ? (\n <HarnessPicker\n onSelect={(harnessId) => dispatch({type: 'harness-selected', harnessId})}\n />\n ) : (\n <>\n <div>\n <Button type=\"button\" variant=\"transparent\" onClick={() => dispatch({type: 'back'})}>\n Back\n </Button>\n </div>\n <ModelProviderPicker\n key={onboarding.harnessId}\n catalogQuery={catalogQuery}\n supportedProviders={filteredProviders}\n onSelect={(entry) => {\n dispatch({type: 'provider-selected', provider: entry});\n }}\n />\n </>\n )}\n </section>\n\n <Modal\n open={\n onboarding.step === 'configure-provider' || onboarding.step === 'saving-default-harness'\n }\n onOpenChange={(open) => {\n if (!open && onboarding.step === 'configure-provider') dispatch({type: 'back'});\n }}\n >\n <ModalContent aria-describedby={undefined}>\n <ModalTitle className=\"sr-only\">\n {onboarding.step === 'configure-provider' ||\n onboarding.step === 'saving-default-harness'\n ? `Configure ${onboarding.provider.label}`\n : ''}\n </ModalTitle>\n <ModalHeader>\n <Text\n size=\"lg\"\n aria-hidden=\"true\"\n className=\"overflow-ellipsis overflow-hidden whitespace-nowrap\"\n >\n {onboarding.step === 'configure-provider' ||\n onboarding.step === 'saving-default-harness'\n ? `Configure ${onboarding.provider.label}`\n : ''}\n </Text>\n </ModalHeader>\n {onboarding.step === 'configure-provider' ||\n onboarding.step === 'saving-default-harness' ? (\n <div className=\"flex min-h-0 flex-1 flex-col gap-inline\">\n {onboarding.step === 'saving-default-harness' ? (\n <div role=\"status\" className=\"px-row\">\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Saving harness default...\n </Text>\n </div>\n ) : null}\n {onboarding.step === 'saving-default-harness' && onboarding.error ? (\n <div className=\"px-row\">\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-inline\">\n <Text size=\"sm\" bold>\n Could not save default harness\n </Text>\n <Text size=\"sm\">{onboarding.error}</Text>\n </div>\n </Callout>\n </div>\n ) : null}\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <ModelProviderTestAndSaveForm\n workspaceId={workspaceId}\n entry={onboarding.provider}\n setAsDefaultOnSave\n onSaved={() => {\n void handleProviderSaved();\n }}\n />\n </div>\n </div>\n ) : null}\n </ModalContent>\n </Modal>\n </div>\n );\n}\n\nfunction HarnessPicker({onSelect}: {onSelect: (harness: HarnessId) => void}) {\n return (\n <ul className={PROVIDER_GRID_CLASS} aria-label=\"Agent harnesses\">\n {listHarnesses().map((harness) => (\n <HarnessCard key={harness.id} harness={harness} onChoose={() => onSelect(harness.id)} />\n ))}\n </ul>\n );\n}\n\nfunction HarnessCard({harness, onChoose}: {harness: HarnessDescriptor; onChoose: () => void}) {\n return (\n <li>\n <button\n type=\"button\"\n className={cn(\n 'group block w-full cursor-pointer p-panel-compact text-left outline-none transition-colors hover:bg-background-components-hover focus-visible:shadow-button-neutral-focus',\n SURFACE_CLASS,\n )}\n aria-label={`Choose ${harness.label}`}\n onClick={onChoose}\n >\n <div className=\"flex min-w-0 items-center justify-between gap-cluster\">\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <Text size=\"md\" bold className=\"min-w-0 truncate\">\n {harness.label}\n </Text>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n {harness.description}\n </Text>\n </div>\n <div className=\"flex shrink-0 items-center gap-tight text-foreground-neutral-muted transition-colors group-hover:text-foreground-highlight-interactive\">\n <Text size=\"sm\">Choose</Text>\n <Icon name=\"chevronRight\" className=\"size-16\" />\n </div>\n </div>\n </button>\n </li>\n );\n}\n\nfunction ModelProviderPicker({\n catalogQuery,\n supportedProviders,\n onSelect,\n}: {\n catalogQuery: ReturnType<typeof useModelProviderCatalogQuery>;\n supportedProviders: SupportedProvider[];\n onSelect: (entry: SupportedProvider) => void;\n}) {\n if (catalogQuery.isPending) {\n return (\n <div role=\"status\" aria-busy=\"true\" aria-label=\"Loading model providers\">\n <ModelProviderGridSkeleton />\n </div>\n );\n }\n\n if (catalogQuery.isError && catalogQuery.data === undefined) {\n return <QueryLoadError query={catalogQuery} subject=\"model provider catalog\" />;\n }\n\n if (catalogQuery.data !== undefined && supportedProviders.length === 0) {\n return (\n <EmptyState\n icon=\"componentLine\"\n title=\"No providers available to configure\"\n description=\"Skip for now and add one later from workspace settings.\"\n />\n );\n }\n\n return <AvailableProvidersGrid entries={supportedProviders} onSelect={onSelect} />;\n}\n\nfunction ModelProviderGridSkeleton() {\n return (\n <div 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","Callout","EmptyState","Icon","Modal","ModalContent","ModalHeader","ModalTitle","Skeleton","toast","Header","Text","cn","useEffect","useMemo","useReducer","AvailableProvidersGrid","PROVIDER_GRID_CLASS","modelProviderConfigErrorToFormError","ModelProviderTestAndSaveForm","DEFAULT_HARNESS","harnessSupportsProvider","listHarnesses","initialOnboardingState","onboardingReducer","isSupportedProvider","useModelProviderCatalogQuery","useSetDefaultHarnessMutation","dismissModelProviderOnboarding","SURFACE_CLASS","ModelProviderOnboardingPage","workspaceId","onSkip","onConfigured","catalogQuery","setDefaultHarness","onboarding","dispatch","supportedProviders","data","providers","filter","filteredProviders","step","provider","harnessId","id","document","getElementById","focus","handleSkip","handleProviderSaved","type","success","label","mutateAsync","error","mapped","message","selectedHarnessDescriptor","find","harness","headingId","div","className","header","variant","tabIndex","onClick","size","section","aria-labelledby","HarnessPicker","onSelect","ModelProviderPicker","entry","open","onOpenChange","aria-describedby","undefined","aria-hidden","role","bold","setAsDefaultOnSave","onSaved","ul","aria-label","map","HarnessCard","onChoose","li","button","description","name","isPending","aria-busy","ModelProviderGridSkeleton","isError","query","subject","length","icon","title","entries","card"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/pages/model-provider-onboarding-page.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Modal, ModalContent, ModalHeader, ModalTitle} from '@shipfox/react-ui/modal';\nimport {Panel, PanelBody, PanelCell, PanelCellAction, PanelGrid} from '@shipfox/react-ui/panel';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useEffect, useMemo, useReducer} from 'react';\nimport {AvailableProvidersGrid} from '#components/available-providers-grid.js';\nimport {modelProviderConfigErrorToFormError} from '#components/form-errors.js';\nimport {ModelProviderGridSkeleton} from '#components/model-provider-grid-skeleton.js';\nimport {ModelProviderTestAndSaveForm} from '#components/test-and-save-form.js';\nimport {DEFAULT_HARNESS, harnessSupportsProvider, listHarnesses} from '#core/harness-policy.js';\nimport type {HarnessDescriptor, HarnessId, SupportedProvider} from '#core/models.js';\nimport {initialOnboardingState, onboardingReducer} from '#core/onboarding-reducer.js';\nimport {isSupportedProvider} from '#core/provider-policy.js';\nimport {\n useModelProviderCatalogQuery,\n useSetDefaultHarnessMutation,\n} from '#hooks/api/model-providers.js';\nimport {dismissModelProviderOnboarding} from '#state/model-provider-onboarding.js';\n\nexport function ModelProviderOnboardingPage({\n workspaceId,\n onSkip,\n onConfigured,\n}: {\n workspaceId: string;\n onSkip: () => void;\n onConfigured: () => void;\n}) {\n const catalogQuery = useModelProviderCatalogQuery();\n const setDefaultHarness = useSetDefaultHarnessMutation();\n const [onboarding, dispatch] = useReducer(onboardingReducer, initialOnboardingState);\n const supportedProviders = catalogQuery.data?.providers.filter(isSupportedProvider) ?? [];\n const filteredProviders = useMemo(() => {\n if (onboarding.step === 'choose-harness') return [];\n return supportedProviders.filter((provider) =>\n harnessSupportsProvider(onboarding.harnessId, provider.id),\n );\n }, [onboarding, supportedProviders]);\n\n useEffect(() => {\n document\n .getElementById(\n onboarding.step === 'choose-harness'\n ? 'model-provider-harness-step'\n : 'model-provider-provider-step',\n )\n ?.focus();\n }, [onboarding.step]);\n\n function handleSkip() {\n try {\n dismissModelProviderOnboarding(workspaceId);\n } catch {\n // Skip is best-effort persistence; access to the product must not depend on storage.\n }\n onSkip();\n }\n\n async function handleProviderSaved() {\n if (onboarding.step !== 'configure-provider' && onboarding.step !== 'saving-default-harness')\n return;\n\n const provider = onboarding.provider;\n if (onboarding.step === 'configure-provider') dispatch({type: 'provider-saved'});\n if (onboarding.harnessId === DEFAULT_HARNESS) {\n toast.success(`${provider.label} saved`);\n dispatch({type: 'default-harness-saved'});\n onConfigured();\n return;\n }\n\n try {\n await setDefaultHarness.mutateAsync({\n workspaceId,\n harnessId: onboarding.harnessId,\n });\n toast.success(`${provider.label} saved`);\n dispatch({type: 'default-harness-saved'});\n onConfigured();\n } catch (error) {\n const mapped = modelProviderConfigErrorToFormError(error);\n dispatch({\n type: 'default-harness-failed',\n message: mapped.message || 'Could not save default harness. Try again.',\n });\n }\n }\n\n const selectedHarnessDescriptor =\n onboarding.step === 'choose-harness'\n ? null\n : listHarnesses().find((harness) => harness.id === onboarding.harnessId);\n const headingId =\n onboarding.step === 'choose-harness'\n ? 'model-provider-harness-step'\n : 'model-provider-provider-step';\n\n return (\n <div className=\"flex w-full flex-col gap-section\">\n <header className=\"flex flex-col gap-cluster\">\n <div className=\"flex items-start justify-between gap-group max-[520px]:flex-col max-[520px]:gap-inline\">\n <Header id={headingId} variant=\"h1\" tabIndex={-1} className=\"outline-none\">\n {selectedHarnessDescriptor\n ? `Configure ${selectedHarnessDescriptor.label}`\n : 'Choose agent harness'}\n </Header>\n <Button type=\"button\" variant=\"secondary\" onClick={handleSkip} className=\"shrink-0\">\n Skip for now\n </Button>\n </div>\n <Text size=\"md\" className=\"text-foreground-neutral-muted\">\n {selectedHarnessDescriptor\n ? `${selectedHarnessDescriptor.label} needs a compatible model provider. Add your own API key, or go back to choose a different harness.`\n : 'A harness runs agent steps. Choose the engine you want first, then connect a compatible model provider.'}\n </Text>\n </header>\n\n <section aria-labelledby={headingId} className=\"flex flex-col gap-group\">\n {onboarding.step === 'choose-harness' ? (\n <HarnessPicker\n onSelect={(harnessId) => dispatch({type: 'harness-selected', harnessId})}\n />\n ) : (\n <>\n <div>\n <Button type=\"button\" variant=\"transparent\" onClick={() => dispatch({type: 'back'})}>\n Back\n </Button>\n </div>\n <ModelProviderPicker\n key={onboarding.harnessId}\n catalogQuery={catalogQuery}\n supportedProviders={filteredProviders}\n onSelect={(entry) => {\n dispatch({type: 'provider-selected', provider: entry});\n }}\n />\n </>\n )}\n </section>\n\n <Modal\n open={\n onboarding.step === 'configure-provider' || onboarding.step === 'saving-default-harness'\n }\n onOpenChange={(open) => {\n if (!open && onboarding.step === 'configure-provider') dispatch({type: 'back'});\n }}\n >\n <ModalContent aria-describedby={undefined}>\n <ModalTitle className=\"sr-only\">\n {onboarding.step === 'configure-provider' ||\n onboarding.step === 'saving-default-harness'\n ? `Configure ${onboarding.provider.label}`\n : ''}\n </ModalTitle>\n <ModalHeader>\n <Text\n size=\"lg\"\n aria-hidden=\"true\"\n className=\"overflow-ellipsis overflow-hidden whitespace-nowrap\"\n >\n {onboarding.step === 'configure-provider' ||\n onboarding.step === 'saving-default-harness'\n ? `Configure ${onboarding.provider.label}`\n : ''}\n </Text>\n </ModalHeader>\n {onboarding.step === 'configure-provider' ||\n onboarding.step === 'saving-default-harness' ? (\n <div className=\"flex min-h-0 flex-1 flex-col gap-inline\">\n {onboarding.step === 'saving-default-harness' ? (\n <div role=\"status\" className=\"px-row\">\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Saving harness default...\n </Text>\n </div>\n ) : null}\n {onboarding.step === 'saving-default-harness' && onboarding.error ? (\n <div className=\"px-row\">\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-inline\">\n <Text size=\"sm\" bold>\n Could not save default harness\n </Text>\n <Text size=\"sm\">{onboarding.error}</Text>\n </div>\n </Callout>\n </div>\n ) : null}\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <ModelProviderTestAndSaveForm\n workspaceId={workspaceId}\n entry={onboarding.provider}\n setAsDefaultOnSave\n onSaved={() => {\n void handleProviderSaved();\n }}\n />\n </div>\n </div>\n ) : null}\n </ModalContent>\n </Modal>\n </div>\n );\n}\n\nfunction HarnessPicker({onSelect}: {onSelect: (harness: HarnessId) => void}) {\n return (\n <Panel>\n <PanelBody>\n <PanelGrid aria-label=\"Agent harnesses\">\n {listHarnesses().map((harness) => (\n <HarnessCard key={harness.id} harness={harness} onChoose={() => onSelect(harness.id)} />\n ))}\n </PanelGrid>\n </PanelBody>\n </Panel>\n );\n}\n\nfunction HarnessCard({harness, onChoose}: {harness: HarnessDescriptor; onChoose: () => void}) {\n return (\n <PanelCell>\n <PanelCellAction action=\"Choose\" aria-label={`Choose ${harness.label}`} onClick={onChoose}>\n <span className=\"flex min-w-0 flex-col gap-tight\">\n <Text as=\"span\" size=\"md\" bold className=\"min-w-0 truncate\">\n {harness.label}\n </Text>\n <Text as=\"span\" size=\"sm\" className=\"text-foreground-neutral-muted\">\n {harness.description}\n </Text>\n </span>\n </PanelCellAction>\n </PanelCell>\n );\n}\n\nfunction ModelProviderPicker({\n catalogQuery,\n supportedProviders,\n onSelect,\n}: {\n catalogQuery: ReturnType<typeof useModelProviderCatalogQuery>;\n supportedProviders: SupportedProvider[];\n onSelect: (entry: SupportedProvider) => void;\n}) {\n if (catalogQuery.isPending) {\n return <ModelProviderGridSkeleton label=\"Loading model providers\" />;\n }\n\n if (catalogQuery.isError && catalogQuery.data === undefined) {\n return <QueryLoadError query={catalogQuery} subject=\"model provider catalog\" />;\n }\n\n if (catalogQuery.data !== undefined && supportedProviders.length === 0) {\n return (\n <EmptyState\n icon=\"componentLine\"\n title=\"No providers available to configure\"\n description=\"Skip for now and add one later from workspace settings.\"\n />\n );\n }\n\n return <AvailableProvidersGrid entries={supportedProviders} onSelect={onSelect} />;\n}\n"],"names":["QueryLoadError","Button","Callout","EmptyState","Modal","ModalContent","ModalHeader","ModalTitle","Panel","PanelBody","PanelCell","PanelCellAction","PanelGrid","toast","Header","Text","useEffect","useMemo","useReducer","AvailableProvidersGrid","modelProviderConfigErrorToFormError","ModelProviderGridSkeleton","ModelProviderTestAndSaveForm","DEFAULT_HARNESS","harnessSupportsProvider","listHarnesses","initialOnboardingState","onboardingReducer","isSupportedProvider","useModelProviderCatalogQuery","useSetDefaultHarnessMutation","dismissModelProviderOnboarding","ModelProviderOnboardingPage","workspaceId","onSkip","onConfigured","catalogQuery","setDefaultHarness","onboarding","dispatch","supportedProviders","data","providers","filter","filteredProviders","step","provider","harnessId","id","document","getElementById","focus","handleSkip","handleProviderSaved","type","success","label","mutateAsync","error","mapped","message","selectedHarnessDescriptor","find","harness","headingId","div","className","header","variant","tabIndex","onClick","size","section","aria-labelledby","HarnessPicker","onSelect","ModelProviderPicker","entry","open","onOpenChange","aria-describedby","undefined","aria-hidden","role","bold","setAsDefaultOnSave","onSaved","aria-label","map","HarnessCard","onChoose","action","span","as","description","isPending","isError","query","subject","length","icon","title","entries"],"mappings":"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"}
@@ -150,7 +150,7 @@ function ModelProviderOnboardingStory({ scenario }) {
150
150
  client: queryClient,
151
151
  children: [
152
152
  /*#__PURE__*/ _jsx("div", {
153
- className: "bg-background-neutral-background px-24 py-32",
153
+ className: "bg-background-subtle-base px-24 py-32",
154
154
  children: /*#__PURE__*/ _jsx(ModelProviderOnboardingPage, {
155
155
  workspaceId: WORKSPACE_ID,
156
156
  onSkip: ()=>undefined,