@shipfox/client-agent 5.0.0 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +45 -0
- package/dist/components/available-provider-card.d.ts +2 -2
- package/dist/components/available-provider-card.d.ts.map +1 -1
- package/dist/components/available-provider-card.js.map +1 -1
- package/dist/components/available-providers-grid.d.ts +2 -2
- package/dist/components/available-providers-grid.d.ts.map +1 -1
- package/dist/components/available-providers-grid.js +1 -1
- package/dist/components/available-providers-grid.js.map +1 -1
- package/dist/components/change-default-model-form.d.ts +3 -4
- package/dist/components/change-default-model-form.d.ts.map +1 -1
- package/dist/components/change-default-model-form.js +2 -4
- package/dist/components/change-default-model-form.js.map +1 -1
- package/dist/components/custom-model-provider-api-options.d.ts +3 -3
- package/dist/components/custom-model-provider-api-options.d.ts.map +1 -1
- package/dist/components/custom-model-provider-api-options.js.map +1 -1
- package/dist/components/custom-model-provider-form.d.ts +2 -2
- package/dist/components/custom-model-provider-form.d.ts.map +1 -1
- package/dist/components/custom-model-provider-form.js +12 -10
- package/dist/components/custom-model-provider-form.js.map +1 -1
- package/dist/components/custom-model-provider-form.stories.d.ts.map +1 -1
- package/dist/components/custom-model-provider-form.stories.js +11 -11
- package/dist/components/custom-model-provider-form.stories.js.map +1 -1
- package/dist/components/custom-model-provider-payload.d.ts +9 -9
- package/dist/components/custom-model-provider-payload.d.ts.map +1 -1
- package/dist/components/custom-model-provider-payload.js +42 -26
- package/dist/components/custom-model-provider-payload.js.map +1 -1
- package/dist/components/custom-model-provider-slug.d.ts +1 -1
- package/dist/components/custom-model-provider-slug.d.ts.map +1 -1
- package/dist/components/custom-model-provider-slug.js +3 -3
- package/dist/components/custom-model-provider-slug.js.map +1 -1
- package/dist/components/default-model-field.d.ts +2 -2
- package/dist/components/default-model-field.d.ts.map +1 -1
- package/dist/components/default-model-field.js +1 -1
- package/dist/components/default-model-field.js.map +1 -1
- package/dist/components/harness-availability.d.ts +4 -7
- package/dist/components/harness-availability.d.ts.map +1 -1
- package/dist/components/harness-availability.js +2 -11
- package/dist/components/harness-availability.js.map +1 -1
- package/dist/components/harnesses-section.d.ts.map +1 -1
- package/dist/components/harnesses-section.js +4 -6
- package/dist/components/harnesses-section.js.map +1 -1
- package/dist/components/model-provider-usage-modal.d.ts +2 -2
- package/dist/components/model-provider-usage-modal.d.ts.map +1 -1
- package/dist/components/model-provider-usage-modal.js +4 -4
- package/dist/components/model-provider-usage-modal.js.map +1 -1
- package/dist/components/model-provider-usage-modal.stories.d.ts.map +1 -1
- package/dist/components/model-provider-usage-modal.stories.js +14 -16
- package/dist/components/model-provider-usage-modal.stories.js.map +1 -1
- package/dist/components/model-provider-usage-target.d.ts +5 -5
- package/dist/components/model-provider-usage-target.d.ts.map +1 -1
- package/dist/components/model-provider-usage-target.js +10 -8
- package/dist/components/model-provider-usage-target.js.map +1 -1
- package/dist/components/model-providers-section.d.ts.map +1 -1
- package/dist/components/model-providers-section.js +112 -94
- package/dist/components/model-providers-section.js.map +1 -1
- package/dist/components/model-providers-section.stories.js +8 -4
- package/dist/components/model-providers-section.stories.js.map +1 -1
- package/dist/components/test-and-save-form.d.ts +3 -3
- package/dist/components/test-and-save-form.d.ts.map +1 -1
- package/dist/components/test-and-save-form.js +7 -7
- package/dist/components/test-and-save-form.js.map +1 -1
- package/dist/core/harness-policy.d.ts +11 -0
- package/dist/core/harness-policy.d.ts.map +1 -0
- package/dist/core/harness-policy.js +71 -0
- package/dist/core/harness-policy.js.map +1 -0
- package/dist/core/model-provider-management-reducer.d.ts +51 -0
- package/dist/core/model-provider-management-reducer.d.ts.map +1 -0
- package/dist/core/model-provider-management-reducer.js +43 -0
- package/dist/core/model-provider-management-reducer.js.map +1 -0
- package/dist/core/models.d.ts +120 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +3 -0
- package/dist/core/models.js.map +1 -0
- package/dist/core/onboarding-reducer.d.ts +36 -0
- package/dist/core/onboarding-reducer.d.ts.map +1 -0
- package/dist/core/onboarding-reducer.js +54 -0
- package/dist/core/onboarding-reducer.js.map +1 -0
- package/dist/core/provider-policy.d.ts +9 -0
- package/dist/core/provider-policy.d.ts.map +1 -0
- package/dist/core/provider-policy.js +37 -0
- package/dist/core/provider-policy.js.map +1 -0
- package/dist/feature.d.ts +7 -0
- package/dist/feature.d.ts.map +1 -1
- package/dist/feature.js +10 -9
- package/dist/feature.js.map +1 -1
- package/dist/hooks/api/model-provider-command-mapper.d.ts +11 -0
- package/dist/hooks/api/model-provider-command-mapper.d.ts.map +1 -0
- package/dist/hooks/api/model-provider-command-mapper.js +144 -0
- package/dist/hooks/api/model-provider-command-mapper.js.map +1 -0
- package/dist/hooks/api/model-provider-mapper.d.ts +11 -0
- package/dist/hooks/api/model-provider-mapper.d.ts.map +1 -0
- package/dist/hooks/api/model-provider-mapper.js +94 -0
- package/dist/hooks/api/model-provider-mapper.js.map +1 -0
- package/dist/hooks/api/model-providers.d.ts +60 -295
- package/dist/hooks/api/model-providers.d.ts.map +1 -1
- package/dist/hooks/api/model-providers.js +51 -37
- package/dist/hooks/api/model-providers.js.map +1 -1
- package/dist/pages/model-provider-onboarding-page.d.ts.map +1 -1
- package/dist/pages/model-provider-onboarding-page.js +57 -45
- package/dist/pages/model-provider-onboarding-page.js.map +1 -1
- package/dist/routes/inputs.d.ts +4 -0
- package/dist/routes/inputs.d.ts.map +1 -0
- package/dist/routes/inputs.js +12 -0
- package/dist/routes/inputs.js.map +1 -0
- package/dist/routes/model-provider.d.ts.map +1 -1
- package/dist/routes/model-provider.js +4 -5
- package/dist/routes/model-provider.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +9 -10
- package/src/components/available-provider-card.tsx +2 -2
- package/src/components/available-providers-grid.tsx +3 -3
- package/src/components/change-default-model-form.tsx +5 -6
- package/src/components/custom-model-provider-api-options.ts +3 -3
- package/src/components/custom-model-provider-form.stories.tsx +13 -13
- package/src/components/custom-model-provider-form.tsx +19 -12
- package/src/components/custom-model-provider-payload.test.ts +22 -22
- package/src/components/custom-model-provider-payload.ts +69 -54
- package/src/components/custom-model-provider-slug.test.ts +1 -1
- package/src/components/custom-model-provider-slug.ts +6 -3
- package/src/components/default-model-field.tsx +5 -5
- package/src/components/harness-availability.test.ts +13 -10
- package/src/components/harness-availability.ts +4 -28
- package/src/components/harnesses-section.tsx +7 -11
- package/src/components/model-provider-usage-modal.stories.tsx +18 -23
- package/src/components/model-provider-usage-modal.test.tsx +35 -7
- package/src/components/model-provider-usage-modal.tsx +12 -16
- package/src/components/model-provider-usage-target.ts +15 -18
- package/src/components/model-providers-section.stories.tsx +4 -1
- package/src/components/model-providers-section.tsx +112 -125
- package/src/components/test-and-save-form.tsx +13 -17
- package/src/core/harness-policy.test.ts +15 -0
- package/src/core/harness-policy.ts +83 -0
- package/src/core/model-provider-management-reducer.test.ts +59 -0
- package/src/core/model-provider-management-reducer.ts +72 -0
- package/src/core/models.ts +143 -0
- package/src/core/onboarding-reducer.test.ts +44 -0
- package/src/core/onboarding-reducer.ts +64 -0
- package/src/core/provider-policy.ts +53 -0
- package/src/feature.ts +12 -10
- package/src/hooks/api/model-provider-command-mapper.ts +122 -0
- package/src/hooks/api/model-provider-mapper.test.ts +27 -0
- package/src/hooks/api/model-provider-mapper.ts +120 -0
- package/src/hooks/api/model-providers.test.ts +15 -15
- package/src/hooks/api/model-providers.ts +146 -81
- package/src/pages/model-provider-onboarding-page.tsx +62 -56
- package/src/routes/inputs.test.ts +11 -0
- package/src/routes/inputs.ts +9 -0
- package/src/routes/model-provider.tsx +4 -3
- package/test/fixtures/model-providers.ts +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/vercel.json +5 -0
- package/dist/components/provider-search.d.ts +0 -4
- package/dist/components/provider-search.d.ts.map +0 -1
- package/dist/components/provider-search.js +0 -13
- package/dist/components/provider-search.js.map +0 -1
- package/dist/components/supported-model-provider-catalog-entry.d.ts +0 -8
- package/dist/components/supported-model-provider-catalog-entry.d.ts.map +0 -1
- package/dist/components/supported-model-provider-catalog-entry.js +0 -9
- package/dist/components/supported-model-provider-catalog-entry.js.map +0 -1
- package/src/components/provider-search.test.ts +0 -45
- package/src/components/provider-search.ts +0 -18
- package/src/components/supported-model-provider-catalog-entry.ts +0 -19
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/harnesses-section.tsx"],"sourcesContent":["import {\n DEFAULT_HARNESS,\n type Harness,\n type HarnessDescriptor,\n listHarnessDescriptors,\n} from '@shipfox/api-agent-dto';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {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 {Icon} from '@shipfox/react-ui/icon';\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 {useRef, useState} from 'react';\nimport {\n useModelProviderConfigsQuery,\n useSetDefaultHarnessMutation,\n} from '#hooks/api/model-providers.js';\nimport {modelProviderConfigErrorToFormError} from './form-errors.js';\nimport {isHarnessAvailable} from './harness-availability.js';\n\nconst SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\nexport function WorkspaceHarnessesSection({workspaceId}: {workspaceId: string}) {\n const configsQuery = useModelProviderConfigsQuery(workspaceId);\n const setDefaultHarness = useSetDefaultHarnessMutation();\n const activeWorkspaceIdRef = useRef(workspaceId);\n const defaultRequestSeqRef = useRef(0);\n const activeDefaultRequestRef = useRef<{workspaceId: string; id: number} | null>(null);\n const [pendingDefaultHarness, setPendingDefaultHarness] = useState<{\n workspaceId: string;\n harnessId: Harness;\n } | null>(null);\n const [defaultError, setDefaultError] = useState<\n {workspaceId: string; harnessId: Harness; message: string} | undefined\n >();\n const configs = configsQuery.data?.configs ?? [];\n const defaultHarnessId = configsQuery.data?.default_harness_id ?? DEFAULT_HARNESS;\n activeWorkspaceIdRef.current = workspaceId;\n\n function isActiveDefaultRequest(request: {workspaceId: string; id: number}) {\n const activeRequest = activeDefaultRequestRef.current;\n return (\n activeWorkspaceIdRef.current === request.workspaceId &&\n activeRequest?.workspaceId === request.workspaceId &&\n activeRequest.id === request.id\n );\n }\n\n async function handleSetDefault(harness: HarnessDescriptor) {\n if (activeDefaultRequestRef.current?.workspaceId === workspaceId) return;\n\n const request = {workspaceId, id: defaultRequestSeqRef.current + 1};\n defaultRequestSeqRef.current = request.id;\n activeDefaultRequestRef.current = request;\n setPendingDefaultHarness({workspaceId, harnessId: harness.id});\n setDefaultError(undefined);\n try {\n await setDefaultHarness.mutateAsync({\n workspaceId,\n body: {harness_id: harness.id},\n });\n if (!isActiveDefaultRequest(request)) return;\n toast.success(`${harness.label} is now the default harness`);\n } catch (error) {\n if (!isActiveDefaultRequest(request)) return;\n const mapped = modelProviderConfigErrorToFormError(error);\n setDefaultError({\n workspaceId,\n harnessId: harness.id,\n message: mapped.message || 'Could not save default harness. Try again.',\n });\n } finally {\n if (isActiveDefaultRequest(request)) {\n activeDefaultRequestRef.current = null;\n setPendingDefaultHarness(null);\n }\n }\n }\n\n return (\n <section className=\"flex flex-col gap-16\" aria-label=\"Harnesses\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Harnesses</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Harnesses available to run agent steps in this workspace.\n </Text>\n </div>\n\n {configsQuery.isPending ? <HarnessRowsSkeleton /> : null}\n\n {configsQuery.isError && configsQuery.data === undefined ? (\n <div className={cn(SURFACE_CLASS, 'px-16')}>\n <QueryLoadError query={configsQuery} subject=\"harnesses\" />\n </div>\n ) : null}\n\n {configsQuery.data !== undefined ? (\n <ul className={cn('divide-y divide-border-neutral-base', SURFACE_CLASS)}>\n {listHarnessDescriptors().map((harness) => (\n <HarnessRow\n key={harness.id}\n harness={harness}\n isDefault={harness.id === defaultHarnessId}\n isAvailable={isHarnessAvailable(harness, configs)}\n isSettingDefault={pendingDefaultHarness?.workspaceId === workspaceId}\n defaultError={\n defaultError?.workspaceId === workspaceId && defaultError.harnessId === harness.id\n ? defaultError.message\n : undefined\n }\n onSetDefault={handleSetDefault}\n />\n ))}\n </ul>\n ) : null}\n </section>\n );\n}\n\nfunction HarnessRow({\n harness,\n isDefault,\n isAvailable,\n isSettingDefault,\n defaultError,\n onSetDefault,\n}: {\n harness: HarnessDescriptor;\n isDefault: boolean;\n isAvailable: boolean;\n isSettingDefault: boolean;\n defaultError: string | undefined;\n onSetDefault: (harness: HarnessDescriptor) => void;\n}) {\n const unavailableCopy = harnessUnavailableCopy(isDefault);\n\n return (\n <li className=\"flex flex-col gap-10 px-16 py-12 transition-colors hover:bg-background-components-hover\">\n <div className=\"flex items-center justify-between gap-12\">\n <div className=\"flex min-w-0 items-center gap-8\">\n {isDefault ? (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex size-16 shrink-0 items-center justify-center\">\n <Icon\n name=\"starLine\"\n className=\"size-16 text-foreground-neutral-muted\"\n aria-hidden\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>Default harness</TooltipContent>\n </Tooltip>\n <span className=\"sr-only\">Default harness</span>\n </>\n ) : null}\n <Text size=\"md\" bold className=\"truncate\">\n {harness.label}\n </Text>\n {!isAvailable ? (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex size-16 shrink-0 items-center justify-center\">\n <Icon\n name=\"errorWarningLine\"\n className=\"size-16 text-foreground-warning-base\"\n aria-hidden\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{unavailableCopy}</TooltipContent>\n </Tooltip>\n <span className=\"sr-only\">{unavailableCopy}</span>\n </>\n ) : null}\n </div>\n {!isDefault ? (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n disabled={isSettingDefault}\n aria-label={`Open ${harness.label} harness actions`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n icon=\"starLine\"\n disabled={isSettingDefault || !isAvailable}\n onSelect={() => {\n onSetDefault(harness);\n }}\n >\n Set as default\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n ) : null}\n </div>\n {defaultError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{defaultError}</Text>\n </Callout>\n ) : null}\n </li>\n );\n}\n\nfunction harnessUnavailableCopy(isDefault: boolean): string {\n const base = 'Configure a compatible model provider to use this harness.';\n if (!isDefault) return base;\n return `${base} The stored default harness cannot currently run in this workspace.`;\n}\n\nfunction HarnessRowsSkeleton() {\n return (\n <ul\n role=\"status\"\n aria-label=\"Loading harnesses\"\n className={cn('divide-y divide-border-neutral-base', SURFACE_CLASS)}\n >\n {[0, 1].map((row) => (\n <li key={row} className=\"flex items-center gap-12 px-16 py-12\">\n <Skeleton className=\"size-16 shrink-0\" />\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"ml-auto size-28 shrink-0\" />\n </li>\n ))}\n </ul>\n );\n}\n"],"names":["DEFAULT_HARNESS","listHarnessDescriptors","QueryLoadError","IconButton","Callout","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","Icon","Skeleton","toast","Tooltip","TooltipContent","TooltipTrigger","Header","Text","cn","useRef","useState","useModelProviderConfigsQuery","useSetDefaultHarnessMutation","modelProviderConfigErrorToFormError","isHarnessAvailable","SURFACE_CLASS","WorkspaceHarnessesSection","workspaceId","configsQuery","setDefaultHarness","activeWorkspaceIdRef","defaultRequestSeqRef","activeDefaultRequestRef","pendingDefaultHarness","setPendingDefaultHarness","defaultError","setDefaultError","configs","data","defaultHarnessId","default_harness_id","current","isActiveDefaultRequest","request","activeRequest","id","handleSetDefault","harness","harnessId","undefined","mutateAsync","body","harness_id","success","label","error","mapped","message","section","className","aria-label","div","variant","size","isPending","HarnessRowsSkeleton","isError","query","subject","ul","map","HarnessRow","isDefault","isAvailable","isSettingDefault","onSetDefault","unavailableCopy","harnessUnavailableCopy","li","asChild","span","name","aria-hidden","bold","icon","disabled","align","onSelect","role","type","base","row"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/components/harnesses-section.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {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 {Icon} from '@shipfox/react-ui/icon';\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 {useRef, useState} from 'react';\nimport {DEFAULT_HARNESS, listHarnesses} from '#core/harness-policy.js';\nimport type {HarnessDescriptor, HarnessId} from '#core/models.js';\nimport {\n useModelProviderConfigsQuery,\n useSetDefaultHarnessMutation,\n} from '#hooks/api/model-providers.js';\nimport {modelProviderConfigErrorToFormError} from './form-errors.js';\nimport {isHarnessAvailable} from './harness-availability.js';\n\nconst SURFACE_CLASS =\n 'overflow-hidden rounded-8 border border-border-neutral-base bg-background-neutral-base';\n\nexport function WorkspaceHarnessesSection({workspaceId}: {workspaceId: string}) {\n const configsQuery = useModelProviderConfigsQuery(workspaceId);\n const setDefaultHarness = useSetDefaultHarnessMutation();\n const activeWorkspaceIdRef = useRef(workspaceId);\n const defaultRequestSeqRef = useRef(0);\n const activeDefaultRequestRef = useRef<{workspaceId: string; id: number} | null>(null);\n const [pendingDefaultHarness, setPendingDefaultHarness] = useState<{\n workspaceId: string;\n harnessId: HarnessId;\n } | null>(null);\n const [defaultError, setDefaultError] = useState<\n {workspaceId: string; harnessId: HarnessId; message: string} | undefined\n >();\n const configs = configsQuery.data?.configs ?? [];\n const defaultHarnessId = configsQuery.data?.defaultHarnessId ?? DEFAULT_HARNESS;\n activeWorkspaceIdRef.current = workspaceId;\n\n function isActiveDefaultRequest(request: {workspaceId: string; id: number}) {\n const activeRequest = activeDefaultRequestRef.current;\n return (\n activeWorkspaceIdRef.current === request.workspaceId &&\n activeRequest?.workspaceId === request.workspaceId &&\n activeRequest.id === request.id\n );\n }\n\n async function handleSetDefault(harness: HarnessDescriptor) {\n if (activeDefaultRequestRef.current?.workspaceId === workspaceId) return;\n\n const request = {workspaceId, id: defaultRequestSeqRef.current + 1};\n defaultRequestSeqRef.current = request.id;\n activeDefaultRequestRef.current = request;\n setPendingDefaultHarness({workspaceId, harnessId: harness.id});\n setDefaultError(undefined);\n try {\n await setDefaultHarness.mutateAsync({\n workspaceId,\n harnessId: harness.id,\n });\n if (!isActiveDefaultRequest(request)) return;\n toast.success(`${harness.label} is now the default harness`);\n } catch (error) {\n if (!isActiveDefaultRequest(request)) return;\n const mapped = modelProviderConfigErrorToFormError(error);\n setDefaultError({\n workspaceId,\n harnessId: harness.id,\n message: mapped.message || 'Could not save default harness. Try again.',\n });\n } finally {\n if (isActiveDefaultRequest(request)) {\n activeDefaultRequestRef.current = null;\n setPendingDefaultHarness(null);\n }\n }\n }\n\n return (\n <section className=\"flex flex-col gap-16\" aria-label=\"Harnesses\">\n <div className=\"flex flex-col gap-4\">\n <Header variant=\"h3\">Harnesses</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Harnesses available to run agent steps in this workspace.\n </Text>\n </div>\n\n {configsQuery.isPending ? <HarnessRowsSkeleton /> : null}\n\n {configsQuery.isError && configsQuery.data === undefined ? (\n <div className={cn(SURFACE_CLASS, 'px-16')}>\n <QueryLoadError query={configsQuery} subject=\"harnesses\" />\n </div>\n ) : null}\n\n {configsQuery.data !== undefined ? (\n <ul className={cn('divide-y divide-border-neutral-base', SURFACE_CLASS)}>\n {listHarnesses().map((harness) => (\n <HarnessRow\n key={harness.id}\n harness={harness}\n isDefault={harness.id === defaultHarnessId}\n isAvailable={isHarnessAvailable(harness, configs)}\n isSettingDefault={pendingDefaultHarness?.workspaceId === workspaceId}\n defaultError={\n defaultError?.workspaceId === workspaceId && defaultError.harnessId === harness.id\n ? defaultError.message\n : undefined\n }\n onSetDefault={handleSetDefault}\n />\n ))}\n </ul>\n ) : null}\n </section>\n );\n}\n\nfunction HarnessRow({\n harness,\n isDefault,\n isAvailable,\n isSettingDefault,\n defaultError,\n onSetDefault,\n}: {\n harness: HarnessDescriptor;\n isDefault: boolean;\n isAvailable: boolean;\n isSettingDefault: boolean;\n defaultError: string | undefined;\n onSetDefault: (harness: HarnessDescriptor) => void;\n}) {\n const unavailableCopy = harnessUnavailableCopy(isDefault);\n\n return (\n <li className=\"flex flex-col gap-10 px-16 py-12 transition-colors hover:bg-background-components-hover\">\n <div className=\"flex items-center justify-between gap-12\">\n <div className=\"flex min-w-0 items-center gap-8\">\n {isDefault ? (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex size-16 shrink-0 items-center justify-center\">\n <Icon\n name=\"starLine\"\n className=\"size-16 text-foreground-neutral-muted\"\n aria-hidden\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>Default harness</TooltipContent>\n </Tooltip>\n <span className=\"sr-only\">Default harness</span>\n </>\n ) : null}\n <Text size=\"md\" bold className=\"truncate\">\n {harness.label}\n </Text>\n {!isAvailable ? (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex size-16 shrink-0 items-center justify-center\">\n <Icon\n name=\"errorWarningLine\"\n className=\"size-16 text-foreground-warning-base\"\n aria-hidden\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{unavailableCopy}</TooltipContent>\n </Tooltip>\n <span className=\"sr-only\">{unavailableCopy}</span>\n </>\n ) : null}\n </div>\n {!isDefault ? (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n size=\"sm\"\n variant=\"transparent\"\n icon=\"more2Line\"\n disabled={isSettingDefault}\n aria-label={`Open ${harness.label} harness actions`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n icon=\"starLine\"\n disabled={isSettingDefault || !isAvailable}\n onSelect={() => {\n onSetDefault(harness);\n }}\n >\n Set as default\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n ) : null}\n </div>\n {defaultError ? (\n <Callout role=\"alert\" type=\"error\">\n <Text size=\"sm\">{defaultError}</Text>\n </Callout>\n ) : null}\n </li>\n );\n}\n\nfunction harnessUnavailableCopy(isDefault: boolean): string {\n const base = 'Configure a compatible model provider to use this harness.';\n if (!isDefault) return base;\n return `${base} The stored default harness cannot currently run in this workspace.`;\n}\n\nfunction HarnessRowsSkeleton() {\n return (\n <ul\n role=\"status\"\n aria-label=\"Loading harnesses\"\n className={cn('divide-y divide-border-neutral-base', SURFACE_CLASS)}\n >\n {[0, 1].map((row) => (\n <li key={row} className=\"flex items-center gap-12 px-16 py-12\">\n <Skeleton className=\"size-16 shrink-0\" />\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"ml-auto size-28 shrink-0\" />\n </li>\n ))}\n </ul>\n );\n}\n"],"names":["QueryLoadError","IconButton","Callout","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","Icon","Skeleton","toast","Tooltip","TooltipContent","TooltipTrigger","Header","Text","cn","useRef","useState","DEFAULT_HARNESS","listHarnesses","useModelProviderConfigsQuery","useSetDefaultHarnessMutation","modelProviderConfigErrorToFormError","isHarnessAvailable","SURFACE_CLASS","WorkspaceHarnessesSection","workspaceId","configsQuery","setDefaultHarness","activeWorkspaceIdRef","defaultRequestSeqRef","activeDefaultRequestRef","pendingDefaultHarness","setPendingDefaultHarness","defaultError","setDefaultError","configs","data","defaultHarnessId","current","isActiveDefaultRequest","request","activeRequest","id","handleSetDefault","harness","harnessId","undefined","mutateAsync","success","label","error","mapped","message","section","className","aria-label","div","variant","size","isPending","HarnessRowsSkeleton","isError","query","subject","ul","map","HarnessRow","isDefault","isAvailable","isSettingDefault","onSetDefault","unavailableCopy","harnessUnavailableCopy","li","asChild","span","name","aria-hidden","bold","icon","disabled","align","onSelect","role","type","base","row"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { HarnessId } from '#core/models.js';
|
|
2
2
|
import type { ModelProviderUsageTarget } from './model-provider-usage-target.js';
|
|
3
3
|
export declare function ModelProviderUsageModal({ target, initialModel, open, onOpenChange, closeFocusTarget, workspaceDefaultHarnessId, }: {
|
|
4
4
|
target: ModelProviderUsageTarget | null;
|
|
@@ -6,6 +6,6 @@ export declare function ModelProviderUsageModal({ target, initialModel, open, on
|
|
|
6
6
|
open: boolean;
|
|
7
7
|
onOpenChange: (open: boolean) => void;
|
|
8
8
|
closeFocusTarget?: HTMLElement | null | undefined;
|
|
9
|
-
workspaceDefaultHarnessId?:
|
|
9
|
+
workspaceDefaultHarnessId?: HarnessId | null | undefined;
|
|
10
10
|
}): import("react").JSX.Element;
|
|
11
11
|
//# sourceMappingURL=model-provider-usage-modal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-provider-usage-modal.d.ts","sourceRoot":"","sources":["../../src/components/model-provider-usage-modal.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"model-provider-usage-modal.d.ts","sourceRoot":"","sources":["../../src/components/model-provider-usage-modal.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAG/C,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,kCAAkC,CAAC;AAM/E,wBAAgB,uBAAuB,CAAC,EACtC,MAAM,EACN,YAAY,EACZ,IAAI,EACJ,YAAY,EACZ,gBAAgB,EAChB,yBAAyB,GAC1B,EAAE;IACD,MAAM,EAAE,wBAAwB,GAAG,IAAI,CAAC;IACxC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,gBAAgB,CAAC,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD,yBAAyB,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;CAC1D,+BA0LA"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { DEFAULT_HARNESS, getHarnessDescriptor, listHarnessDescriptors } from '@shipfox/api-agent-dto';
|
|
3
2
|
import { Button } from '@shipfox/react-ui/button';
|
|
4
3
|
import { CodeBlock, CodeBlockBody, CodeBlockContent, CodeBlockCopyButton, CodeBlockFilename, CodeBlockFiles, CodeBlockHeader, CodeBlockItem } from '@shipfox/react-ui/code-block';
|
|
5
4
|
import { Combobox } from '@shipfox/react-ui/combobox';
|
|
@@ -8,6 +7,7 @@ import { Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, ModalTitle }
|
|
|
8
7
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/tooltip';
|
|
9
8
|
import { Code, Text } from '@shipfox/react-ui/typography';
|
|
10
9
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
10
|
+
import { DEFAULT_HARNESS, getHarness, listHarnesses } from '#core/harness-policy.js';
|
|
11
11
|
import { buildAgentWorkflowExample } from './agent-workflow-example.js';
|
|
12
12
|
import { compatibleHarnessIds } from './harness-availability.js';
|
|
13
13
|
const WORKFLOW_EXAMPLE_FILENAME = '.shipfox/workflows/agent.yml';
|
|
@@ -16,7 +16,7 @@ export function ModelProviderUsageModal({ target, initialModel, open, onOpenChan
|
|
|
16
16
|
const [selectedHarness, setSelectedHarness] = useState(DEFAULT_HARNESS);
|
|
17
17
|
useEffect(()=>{
|
|
18
18
|
if (!target) return;
|
|
19
|
-
setSelectedModel(initialModel ?? target.
|
|
19
|
+
setSelectedModel(initialModel ?? target.defaultModel ?? target.models[0]?.id ?? '');
|
|
20
20
|
}, [
|
|
21
21
|
target,
|
|
22
22
|
initialModel
|
|
@@ -40,7 +40,7 @@ export function ModelProviderUsageModal({ target, initialModel, open, onOpenChan
|
|
|
40
40
|
]);
|
|
41
41
|
const harnessOptions = useMemo(()=>compatibleIds.map((harnessId)=>({
|
|
42
42
|
value: harnessId,
|
|
43
|
-
label:
|
|
43
|
+
label: getHarness(harnessId).label
|
|
44
44
|
})), [
|
|
45
45
|
compatibleIds
|
|
46
46
|
]);
|
|
@@ -257,7 +257,7 @@ function selectInitialHarness(compatibleIds, workspaceDefaultHarnessId) {
|
|
|
257
257
|
return compatibleIds[0] ?? DEFAULT_HARNESS;
|
|
258
258
|
}
|
|
259
259
|
function isHarness(value) {
|
|
260
|
-
return
|
|
260
|
+
return listHarnesses().some((descriptor)=>descriptor.id === value);
|
|
261
261
|
}
|
|
262
262
|
function ModelProviderModelRow({ label, id }) {
|
|
263
263
|
const [copyState, setCopyState] = useState('idle');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/model-provider-usage-modal.tsx"],"sourcesContent":["import {\n DEFAULT_HARNESS,\n getHarnessDescriptor,\n type Harness,\n listHarnessDescriptors,\n} from '@shipfox/api-agent-dto';\nimport {Button} from '@shipfox/react-ui/button';\nimport {\n CodeBlock,\n CodeBlockBody,\n CodeBlockContent,\n CodeBlockCopyButton,\n CodeBlockFilename,\n CodeBlockFiles,\n CodeBlockHeader,\n CodeBlockItem,\n} from '@shipfox/react-ui/code-block';\nimport {Combobox} from '@shipfox/react-ui/combobox';\nimport {useCopyToClipboard} from '@shipfox/react-ui/hooks';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n} from '@shipfox/react-ui/modal';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {useEffect, useMemo, useRef, useState} from 'react';\nimport {buildAgentWorkflowExample} from './agent-workflow-example.js';\nimport {compatibleHarnessIds} from './harness-availability.js';\nimport type {ModelProviderUsageTarget} from './model-provider-usage-target.js';\n\ntype CopyState = 'idle' | 'copied' | 'failed';\n\nconst WORKFLOW_EXAMPLE_FILENAME = '.shipfox/workflows/agent.yml';\n\nexport function ModelProviderUsageModal({\n target,\n initialModel,\n open,\n onOpenChange,\n closeFocusTarget,\n workspaceDefaultHarnessId,\n}: {\n target: ModelProviderUsageTarget | null;\n initialModel?: string | null | undefined;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n closeFocusTarget?: HTMLElement | null | undefined;\n workspaceDefaultHarnessId?: Harness | null | undefined;\n}) {\n const [selectedModel, setSelectedModel] = useState('');\n const [selectedHarness, setSelectedHarness] = useState<Harness>(DEFAULT_HARNESS);\n\n useEffect(() => {\n if (!target) return;\n setSelectedModel(initialModel ?? target.default_model ?? target.models[0]?.id ?? '');\n }, [target, initialModel]);\n\n useEffect(() => {\n if (!target) return;\n const nextCompatibleHarnessIds = compatibleHarnessIds({\n isCustom: target.isCustom,\n providerId: target.id,\n });\n setSelectedHarness(selectInitialHarness(nextCompatibleHarnessIds, workspaceDefaultHarnessId));\n }, [target, workspaceDefaultHarnessId]);\n\n const compatibleIds = useMemo(\n () =>\n target\n ? compatibleHarnessIds({isCustom: target.isCustom, providerId: target.id})\n : ([] as Harness[]),\n [target],\n );\n const harnessOptions = useMemo(\n () =>\n compatibleIds.map((harnessId) => ({\n value: harnessId,\n label: getHarnessDescriptor(harnessId).label,\n })),\n [compatibleIds],\n );\n const modelOptions = useMemo(\n () => target?.models.map((model) => ({value: model.id, label: model.label})) ?? [],\n [target],\n );\n const example = target\n ? buildAgentWorkflowExample({\n harness: selectedHarness,\n providerId: target.id,\n model: selectedModel,\n })\n : null;\n const data =\n example === null\n ? []\n : [{language: 'yaml', filename: WORKFLOW_EXAMPLE_FILENAME, code: example.code}];\n\n function handleOpenChange(nextOpen: boolean) {\n onOpenChange(nextOpen);\n if (!nextOpen && closeFocusTarget) {\n window.setTimeout(() => closeFocusTarget.focus(), 0);\n }\n }\n\n return (\n <Modal open={open && target !== null} onOpenChange={handleOpenChange}>\n <ModalContent aria-describedby={undefined} className=\"max-h-[calc(100vh-32px)] max-w-[640px]\">\n <ModalTitle className=\"sr-only\">\n {target ? `Use ${target.label} in a workflow` : 'Use provider in a workflow'}\n </ModalTitle>\n <ModalHeader>\n <div className=\"flex min-w-0 flex-col gap-2\">\n <Text size=\"lg\" aria-hidden=\"true\" className=\"truncate\">\n {target ? `Use ${target.label} in a workflow` : 'Use provider in a workflow'}\n </Text>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Reference this provider from a workflow agent step.\n </Text>\n </div>\n </ModalHeader>\n {target && example ? (\n <>\n <ModalBody className=\"min-h-0 flex-1 gap-0 overflow-y-auto overflow-x-clip scrollbar\">\n <div className=\"flex w-full flex-col gap-20\">\n {compatibleIds.length === 1 ? (\n <div className=\"flex flex-col gap-12\">\n <div className=\"flex min-h-40 items-center justify-between gap-12 rounded-8 border border-border-neutral-base px-12 py-8\">\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Harness\n </Text>\n <Code as=\"span\" variant=\"label\">\n {compatibleIds[0]}\n </Code>\n </div>\n <Combobox\n aria-label=\"Model\"\n options={modelOptions}\n value={selectedModel}\n onValueChange={(value) => {\n if (value) setSelectedModel(value);\n }}\n placeholder=\"Select model...\"\n searchPlaceholder=\"Search models...\"\n emptyState=\"No model found.\"\n className=\"w-full\"\n />\n </div>\n ) : (\n <div className=\"flex flex-col gap-12 sm:flex-row sm:gap-12\">\n <Combobox\n aria-label=\"Harness\"\n options={harnessOptions}\n value={selectedHarness}\n onValueChange={(value) => {\n if (isHarness(value)) setSelectedHarness(value);\n }}\n placeholder=\"Select harness...\"\n searchPlaceholder=\"Search harnesses...\"\n emptyState=\"No harness found.\"\n className=\"w-full sm:flex-1\"\n />\n <Combobox\n aria-label=\"Model\"\n options={modelOptions}\n value={selectedModel}\n onValueChange={(value) => {\n if (value) setSelectedModel(value);\n }}\n placeholder=\"Select model...\"\n searchPlaceholder=\"Search models...\"\n emptyState=\"No model found.\"\n className=\"w-full sm:flex-1\"\n />\n </div>\n )}\n\n <div className=\"flex flex-col gap-8\">\n <CodeBlock data={data} className=\"h-auto min-h-0 rounded-8\">\n <CodeBlockHeader>\n <CodeBlockFiles>\n {(item) => (\n <CodeBlockFilename value={item.filename}>\n {item.filename}\n </CodeBlockFilename>\n )}\n </CodeBlockFiles>\n <CodeBlockCopyButton />\n </CodeBlockHeader>\n <CodeBlockBody>\n {(item) => (\n <CodeBlockItem value={item.filename}>\n <CodeBlockContent\n language=\"yaml\"\n syntaxHighlighting\n highlightedLineRange={example.highlightedLineRange}\n >\n {item.code}\n </CodeBlockContent>\n </CodeBlockItem>\n )}\n </CodeBlockBody>\n </CodeBlock>\n\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Add this to a workflow file under{' '}\n <Code as=\"span\" variant=\"label\">\n .shipfox/workflows/\n </Code>{' '}\n in your repository to run it.\n </Text>\n </div>\n\n <div className=\"flex flex-col gap-8\">\n <Text size=\"sm\" bold>\n Available models ({target.models.length})\n </Text>\n <ul className=\"rounded-8 border border-border-neutral-base\">\n {target.models.map((model) => (\n <ModelProviderModelRow key={model.id} label={model.label} id={model.id} />\n ))}\n </ul>\n </div>\n </div>\n </ModalBody>\n <ModalFooter>\n <Button type=\"button\" onClick={() => handleOpenChange(false)}>\n Done\n </Button>\n </ModalFooter>\n </>\n ) : null}\n </ModalContent>\n </Modal>\n );\n}\n\nfunction selectInitialHarness(\n compatibleIds: Harness[],\n workspaceDefaultHarnessId: Harness | null | undefined,\n): Harness {\n if (workspaceDefaultHarnessId && compatibleIds.includes(workspaceDefaultHarnessId)) {\n return workspaceDefaultHarnessId;\n }\n if (compatibleIds.includes(DEFAULT_HARNESS)) return DEFAULT_HARNESS;\n return compatibleIds[0] ?? DEFAULT_HARNESS;\n}\n\nfunction isHarness(value: string): value is Harness {\n return listHarnessDescriptors().some((descriptor) => descriptor.id === value);\n}\n\nfunction ModelProviderModelRow({label, id}: {label: string; id: string}) {\n const [copyState, setCopyState] = useState<CopyState>('idle');\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const {copy} = useCopyToClipboard({\n text: id,\n onCopy: () => {\n setTemporaryCopyState('copied');\n },\n });\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n };\n }, []);\n\n function setTemporaryCopyState(state: Exclude<CopyState, 'idle'>) {\n setCopyState(state);\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(() => setCopyState('idle'), 2500);\n }\n\n async function handleCopy() {\n try {\n await copy();\n } catch {\n setTemporaryCopyState('failed');\n }\n }\n\n return (\n <li className=\"border-b border-border-neutral-base last:border-b-0\">\n <Tooltip open={copyState === 'copied'}>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={`Copy ${label} model id ${id}`}\n className=\"flex min-h-40 w-full min-w-0 flex-col items-start gap-2 px-12 py-8 text-left transition-colors hover:bg-background-components-hover focus-visible:shadow-border-interactive-with-active focus-visible:outline-none sm:flex-row sm:items-center sm:gap-8\"\n onClick={() => {\n void handleCopy();\n }}\n >\n <Text as=\"span\" size=\"sm\" bold className=\"max-w-full shrink-0 truncate sm:max-w-[48%]\">\n {label}\n </Text>\n <Code\n as=\"span\"\n variant=\"label\"\n className=\"min-w-0 max-w-full truncate text-left text-foreground-neutral-muted sm:flex-1 sm:text-right\"\n >\n {id}\n </Code>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"top\" align=\"center\">\n Copied\n </TooltipContent>\n </Tooltip>\n {copyState === 'copied' ? (\n <span className=\"sr-only\" role=\"status\">\n Copied {label} id\n </span>\n ) : null}\n {copyState === 'failed' ? (\n <span className=\"sr-only\" role=\"status\">\n Could not copy {label} id\n </span>\n ) : null}\n </li>\n );\n}\n"],"names":["DEFAULT_HARNESS","getHarnessDescriptor","listHarnessDescriptors","Button","CodeBlock","CodeBlockBody","CodeBlockContent","CodeBlockCopyButton","CodeBlockFilename","CodeBlockFiles","CodeBlockHeader","CodeBlockItem","Combobox","useCopyToClipboard","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","Tooltip","TooltipContent","TooltipTrigger","Code","Text","useEffect","useMemo","useRef","useState","buildAgentWorkflowExample","compatibleHarnessIds","WORKFLOW_EXAMPLE_FILENAME","ModelProviderUsageModal","target","initialModel","open","onOpenChange","closeFocusTarget","workspaceDefaultHarnessId","selectedModel","setSelectedModel","selectedHarness","setSelectedHarness","default_model","models","id","nextCompatibleHarnessIds","isCustom","providerId","selectInitialHarness","compatibleIds","harnessOptions","map","harnessId","value","label","modelOptions","model","example","harness","data","language","filename","code","handleOpenChange","nextOpen","window","setTimeout","focus","aria-describedby","undefined","className","div","size","aria-hidden","length","as","variant","aria-label","options","onValueChange","placeholder","searchPlaceholder","emptyState","isHarness","item","syntaxHighlighting","highlightedLineRange","bold","ul","ModelProviderModelRow","type","onClick","includes","some","descriptor","copyState","setCopyState","timeoutRef","copy","text","onCopy","setTemporaryCopyState","current","clearTimeout","state","handleCopy","li","asChild","button","side","align","span","role"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/components/model-provider-usage-modal.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {\n CodeBlock,\n CodeBlockBody,\n CodeBlockContent,\n CodeBlockCopyButton,\n CodeBlockFilename,\n CodeBlockFiles,\n CodeBlockHeader,\n CodeBlockItem,\n} from '@shipfox/react-ui/code-block';\nimport {Combobox} from '@shipfox/react-ui/combobox';\nimport {useCopyToClipboard} from '@shipfox/react-ui/hooks';\nimport {\n Modal,\n ModalBody,\n ModalContent,\n ModalFooter,\n ModalHeader,\n ModalTitle,\n} from '@shipfox/react-ui/modal';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {useEffect, useMemo, useRef, useState} from 'react';\nimport {DEFAULT_HARNESS, getHarness, listHarnesses} from '#core/harness-policy.js';\nimport type {HarnessId} from '#core/models.js';\nimport {buildAgentWorkflowExample} from './agent-workflow-example.js';\nimport {compatibleHarnessIds} from './harness-availability.js';\nimport type {ModelProviderUsageTarget} from './model-provider-usage-target.js';\n\ntype CopyState = 'idle' | 'copied' | 'failed';\n\nconst WORKFLOW_EXAMPLE_FILENAME = '.shipfox/workflows/agent.yml';\n\nexport function ModelProviderUsageModal({\n target,\n initialModel,\n open,\n onOpenChange,\n closeFocusTarget,\n workspaceDefaultHarnessId,\n}: {\n target: ModelProviderUsageTarget | null;\n initialModel?: string | null | undefined;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n closeFocusTarget?: HTMLElement | null | undefined;\n workspaceDefaultHarnessId?: HarnessId | null | undefined;\n}) {\n const [selectedModel, setSelectedModel] = useState('');\n const [selectedHarness, setSelectedHarness] = useState<HarnessId>(DEFAULT_HARNESS);\n\n useEffect(() => {\n if (!target) return;\n setSelectedModel(initialModel ?? target.defaultModel ?? target.models[0]?.id ?? '');\n }, [target, initialModel]);\n\n useEffect(() => {\n if (!target) return;\n const nextCompatibleHarnessIds = compatibleHarnessIds({\n isCustom: target.isCustom,\n providerId: target.id,\n });\n setSelectedHarness(selectInitialHarness(nextCompatibleHarnessIds, workspaceDefaultHarnessId));\n }, [target, workspaceDefaultHarnessId]);\n\n const compatibleIds = useMemo(\n () =>\n target\n ? compatibleHarnessIds({isCustom: target.isCustom, providerId: target.id})\n : ([] as HarnessId[]),\n [target],\n );\n const harnessOptions = useMemo(\n () =>\n compatibleIds.map((harnessId) => ({\n value: harnessId,\n label: getHarness(harnessId).label,\n })),\n [compatibleIds],\n );\n const modelOptions = useMemo(\n () => target?.models.map((model) => ({value: model.id, label: model.label})) ?? [],\n [target],\n );\n const example = target\n ? buildAgentWorkflowExample({\n harness: selectedHarness,\n providerId: target.id,\n model: selectedModel,\n })\n : null;\n const data =\n example === null\n ? []\n : [{language: 'yaml', filename: WORKFLOW_EXAMPLE_FILENAME, code: example.code}];\n\n function handleOpenChange(nextOpen: boolean) {\n onOpenChange(nextOpen);\n if (!nextOpen && closeFocusTarget) {\n window.setTimeout(() => closeFocusTarget.focus(), 0);\n }\n }\n\n return (\n <Modal open={open && target !== null} onOpenChange={handleOpenChange}>\n <ModalContent aria-describedby={undefined} className=\"max-h-[calc(100vh-32px)] max-w-[640px]\">\n <ModalTitle className=\"sr-only\">\n {target ? `Use ${target.label} in a workflow` : 'Use provider in a workflow'}\n </ModalTitle>\n <ModalHeader>\n <div className=\"flex min-w-0 flex-col gap-2\">\n <Text size=\"lg\" aria-hidden=\"true\" className=\"truncate\">\n {target ? `Use ${target.label} in a workflow` : 'Use provider in a workflow'}\n </Text>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Reference this provider from a workflow agent step.\n </Text>\n </div>\n </ModalHeader>\n {target && example ? (\n <>\n <ModalBody className=\"min-h-0 flex-1 gap-0 overflow-y-auto overflow-x-clip scrollbar\">\n <div className=\"flex w-full flex-col gap-20\">\n {compatibleIds.length === 1 ? (\n <div className=\"flex flex-col gap-12\">\n <div className=\"flex min-h-40 items-center justify-between gap-12 rounded-8 border border-border-neutral-base px-12 py-8\">\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Harness\n </Text>\n <Code as=\"span\" variant=\"label\">\n {compatibleIds[0]}\n </Code>\n </div>\n <Combobox\n aria-label=\"Model\"\n options={modelOptions}\n value={selectedModel}\n onValueChange={(value) => {\n if (value) setSelectedModel(value);\n }}\n placeholder=\"Select model...\"\n searchPlaceholder=\"Search models...\"\n emptyState=\"No model found.\"\n className=\"w-full\"\n />\n </div>\n ) : (\n <div className=\"flex flex-col gap-12 sm:flex-row sm:gap-12\">\n <Combobox\n aria-label=\"Harness\"\n options={harnessOptions}\n value={selectedHarness}\n onValueChange={(value) => {\n if (isHarness(value)) setSelectedHarness(value);\n }}\n placeholder=\"Select harness...\"\n searchPlaceholder=\"Search harnesses...\"\n emptyState=\"No harness found.\"\n className=\"w-full sm:flex-1\"\n />\n <Combobox\n aria-label=\"Model\"\n options={modelOptions}\n value={selectedModel}\n onValueChange={(value) => {\n if (value) setSelectedModel(value);\n }}\n placeholder=\"Select model...\"\n searchPlaceholder=\"Search models...\"\n emptyState=\"No model found.\"\n className=\"w-full sm:flex-1\"\n />\n </div>\n )}\n\n <div className=\"flex flex-col gap-8\">\n <CodeBlock data={data} className=\"h-auto min-h-0 rounded-8\">\n <CodeBlockHeader>\n <CodeBlockFiles>\n {(item) => (\n <CodeBlockFilename value={item.filename}>\n {item.filename}\n </CodeBlockFilename>\n )}\n </CodeBlockFiles>\n <CodeBlockCopyButton />\n </CodeBlockHeader>\n <CodeBlockBody>\n {(item) => (\n <CodeBlockItem value={item.filename}>\n <CodeBlockContent\n language=\"yaml\"\n syntaxHighlighting\n highlightedLineRange={example.highlightedLineRange}\n >\n {item.code}\n </CodeBlockContent>\n </CodeBlockItem>\n )}\n </CodeBlockBody>\n </CodeBlock>\n\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Add this to a workflow file under{' '}\n <Code as=\"span\" variant=\"label\">\n .shipfox/workflows/\n </Code>{' '}\n in your repository to run it.\n </Text>\n </div>\n\n <div className=\"flex flex-col gap-8\">\n <Text size=\"sm\" bold>\n Available models ({target.models.length})\n </Text>\n <ul className=\"rounded-8 border border-border-neutral-base\">\n {target.models.map((model) => (\n <ModelProviderModelRow key={model.id} label={model.label} id={model.id} />\n ))}\n </ul>\n </div>\n </div>\n </ModalBody>\n <ModalFooter>\n <Button type=\"button\" onClick={() => handleOpenChange(false)}>\n Done\n </Button>\n </ModalFooter>\n </>\n ) : null}\n </ModalContent>\n </Modal>\n );\n}\n\nfunction selectInitialHarness(\n compatibleIds: HarnessId[],\n workspaceDefaultHarnessId: HarnessId | null | undefined,\n): HarnessId {\n if (workspaceDefaultHarnessId && compatibleIds.includes(workspaceDefaultHarnessId)) {\n return workspaceDefaultHarnessId;\n }\n if (compatibleIds.includes(DEFAULT_HARNESS)) return DEFAULT_HARNESS;\n return compatibleIds[0] ?? DEFAULT_HARNESS;\n}\n\nfunction isHarness(value: string): value is HarnessId {\n return listHarnesses().some((descriptor) => descriptor.id === value);\n}\n\nfunction ModelProviderModelRow({label, id}: {label: string; id: string}) {\n const [copyState, setCopyState] = useState<CopyState>('idle');\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const {copy} = useCopyToClipboard({\n text: id,\n onCopy: () => {\n setTemporaryCopyState('copied');\n },\n });\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n };\n }, []);\n\n function setTemporaryCopyState(state: Exclude<CopyState, 'idle'>) {\n setCopyState(state);\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(() => setCopyState('idle'), 2500);\n }\n\n async function handleCopy() {\n try {\n await copy();\n } catch {\n setTemporaryCopyState('failed');\n }\n }\n\n return (\n <li className=\"border-b border-border-neutral-base last:border-b-0\">\n <Tooltip open={copyState === 'copied'}>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={`Copy ${label} model id ${id}`}\n className=\"flex min-h-40 w-full min-w-0 flex-col items-start gap-2 px-12 py-8 text-left transition-colors hover:bg-background-components-hover focus-visible:shadow-border-interactive-with-active focus-visible:outline-none sm:flex-row sm:items-center sm:gap-8\"\n onClick={() => {\n void handleCopy();\n }}\n >\n <Text as=\"span\" size=\"sm\" bold className=\"max-w-full shrink-0 truncate sm:max-w-[48%]\">\n {label}\n </Text>\n <Code\n as=\"span\"\n variant=\"label\"\n className=\"min-w-0 max-w-full truncate text-left text-foreground-neutral-muted sm:flex-1 sm:text-right\"\n >\n {id}\n </Code>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"top\" align=\"center\">\n Copied\n </TooltipContent>\n </Tooltip>\n {copyState === 'copied' ? (\n <span className=\"sr-only\" role=\"status\">\n Copied {label} id\n </span>\n ) : null}\n {copyState === 'failed' ? (\n <span className=\"sr-only\" role=\"status\">\n Could not copy {label} id\n </span>\n ) : null}\n </li>\n );\n}\n"],"names":["Button","CodeBlock","CodeBlockBody","CodeBlockContent","CodeBlockCopyButton","CodeBlockFilename","CodeBlockFiles","CodeBlockHeader","CodeBlockItem","Combobox","useCopyToClipboard","Modal","ModalBody","ModalContent","ModalFooter","ModalHeader","ModalTitle","Tooltip","TooltipContent","TooltipTrigger","Code","Text","useEffect","useMemo","useRef","useState","DEFAULT_HARNESS","getHarness","listHarnesses","buildAgentWorkflowExample","compatibleHarnessIds","WORKFLOW_EXAMPLE_FILENAME","ModelProviderUsageModal","target","initialModel","open","onOpenChange","closeFocusTarget","workspaceDefaultHarnessId","selectedModel","setSelectedModel","selectedHarness","setSelectedHarness","defaultModel","models","id","nextCompatibleHarnessIds","isCustom","providerId","selectInitialHarness","compatibleIds","harnessOptions","map","harnessId","value","label","modelOptions","model","example","harness","data","language","filename","code","handleOpenChange","nextOpen","window","setTimeout","focus","aria-describedby","undefined","className","div","size","aria-hidden","length","as","variant","aria-label","options","onValueChange","placeholder","searchPlaceholder","emptyState","isHarness","item","syntaxHighlighting","highlightedLineRange","bold","ul","ModelProviderModelRow","type","onClick","includes","some","descriptor","copyState","setCopyState","timeoutRef","copy","text","onCopy","setTemporaryCopyState","current","clearTimeout","state","handleCopy","li","asChild","button","side","align","span","role"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-provider-usage-modal.stories.d.ts","sourceRoot":"","sources":["../../src/components/model-provider-usage-modal.stories.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"model-provider-usage-modal.stories.d.ts","sourceRoot":"","sources":["../../src/components/model-provider-usage-modal.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAO,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AASrD,UAAU,iCAAiC;IACzC,OAAO,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;CAC/C;AAED,iBAAS,4BAA4B,CAAC,EAAC,OAAO,EAAC,EAAE,iCAAiC,+BAmBjF;AAED,QAAA,MAAM,IAAI;;;;;;;;;CAK2C,CAAC;AAEtD,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,UAAU,EAAE,KAAU,CAAC;AAEpC,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAC"}
|
|
@@ -10,7 +10,7 @@ function ModelProviderUsageModalStory({ variant }) {
|
|
|
10
10
|
className: "min-h-screen bg-background-neutral-background p-24",
|
|
11
11
|
children: /*#__PURE__*/ _jsx(ModelProviderUsageModal, {
|
|
12
12
|
target: target,
|
|
13
|
-
initialModel: target.
|
|
13
|
+
initialModel: target.defaultModel,
|
|
14
14
|
workspaceDefaultHarnessId: "claude",
|
|
15
15
|
open: open,
|
|
16
16
|
onOpenChange: setOpen
|
|
@@ -41,18 +41,17 @@ export const CustomProvider = {
|
|
|
41
41
|
};
|
|
42
42
|
function anthropicEntry() {
|
|
43
43
|
return {
|
|
44
|
+
kind: 'supported',
|
|
44
45
|
id: 'anthropic',
|
|
45
46
|
label: 'Anthropic',
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
credential_fields: [
|
|
47
|
+
defaultModel: 'claude-opus-4-8',
|
|
48
|
+
credentialFields: [
|
|
49
49
|
{
|
|
50
50
|
key: 'api_key',
|
|
51
51
|
label: 'API key',
|
|
52
52
|
secret: true
|
|
53
53
|
}
|
|
54
54
|
],
|
|
55
|
-
unsupported_reason: null,
|
|
56
55
|
models: [
|
|
57
56
|
{
|
|
58
57
|
id: 'claude-opus-4-8',
|
|
@@ -71,18 +70,17 @@ function anthropicEntry() {
|
|
|
71
70
|
}
|
|
72
71
|
function longListEntry() {
|
|
73
72
|
return {
|
|
73
|
+
kind: 'supported',
|
|
74
74
|
id: 'cloudflare-workers-ai',
|
|
75
75
|
label: 'Cloudflare Workers AI',
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
credential_fields: [
|
|
76
|
+
defaultModel: '@cf/moonshotai/kimi-k2.7-code',
|
|
77
|
+
credentialFields: [
|
|
79
78
|
{
|
|
80
79
|
key: 'api_token',
|
|
81
80
|
label: 'API token',
|
|
82
81
|
secret: true
|
|
83
82
|
}
|
|
84
83
|
],
|
|
85
|
-
unsupported_reason: null,
|
|
86
84
|
models: Array.from({
|
|
87
85
|
length: 56
|
|
88
86
|
}, (_, index)=>({
|
|
@@ -94,21 +92,21 @@ function longListEntry() {
|
|
|
94
92
|
function customProviderConfig() {
|
|
95
93
|
return {
|
|
96
94
|
kind: 'custom',
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
providerId: 'local-vllm',
|
|
96
|
+
displayName: 'Local vLLM',
|
|
99
97
|
api: 'openai-completions',
|
|
100
|
-
|
|
98
|
+
baseUrl: 'http://localhost:8000/v1',
|
|
101
99
|
headers: [],
|
|
102
|
-
|
|
100
|
+
secretHeaderNames: [],
|
|
103
101
|
models: [
|
|
104
102
|
{
|
|
105
103
|
id: 'llama-3.1',
|
|
106
104
|
label: 'Llama 3.1'
|
|
107
105
|
}
|
|
108
106
|
],
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
defaultModel: 'llama-3.1',
|
|
108
|
+
createdAt: '2026-05-08T00:00:00.000Z',
|
|
109
|
+
updatedAt: '2026-05-08T00:00:00.000Z'
|
|
112
110
|
};
|
|
113
111
|
}
|
|
114
112
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/model-provider-usage-modal.stories.tsx"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"sources":["../../src/components/model-provider-usage-modal.stories.tsx"],"sourcesContent":["import type {Meta, StoryObj} from '@storybook/react';\nimport {useState} from 'react';\nimport type {CustomProviderConfig, SupportedProvider} from '#core/models.js';\nimport {ModelProviderUsageModal} from './model-provider-usage-modal.js';\nimport {\n usageTargetFromCatalogEntry,\n usageTargetFromCustomConfig,\n} from './model-provider-usage-target.js';\n\ninterface ModelProviderUsageModalStoryProps {\n variant: 'anthropic' | 'custom' | 'long-list';\n}\n\nfunction ModelProviderUsageModalStory({variant}: ModelProviderUsageModalStoryProps) {\n const [open, setOpen] = useState(true);\n const entry = variant === 'long-list' ? longListEntry() : anthropicEntry();\n const target =\n variant === 'custom'\n ? usageTargetFromCustomConfig(customProviderConfig())\n : usageTargetFromCatalogEntry(entry);\n\n return (\n <div className=\"min-h-screen bg-background-neutral-background p-24\">\n <ModelProviderUsageModal\n target={target}\n initialModel={target.defaultModel}\n workspaceDefaultHarnessId=\"claude\"\n open={open}\n onOpenChange={setOpen}\n />\n </div>\n );\n}\n\nconst meta = {\n title: 'Agent/ProviderUsageModal',\n component: ModelProviderUsageModalStory,\n parameters: {layout: 'fullscreen'},\n args: {variant: 'anthropic'},\n} satisfies Meta<typeof ModelProviderUsageModalStory>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Playground: Story = {};\n\nexport const LongModelList: Story = {\n args: {variant: 'long-list'},\n};\n\nexport const CustomProvider: Story = {\n args: {variant: 'custom'},\n};\n\nfunction anthropicEntry(): SupportedProvider {\n return {\n kind: 'supported',\n id: 'anthropic',\n label: 'Anthropic',\n defaultModel: 'claude-opus-4-8',\n credentialFields: [{key: 'api_key', label: 'API key', secret: true}],\n models: [\n {id: 'claude-opus-4-8', label: 'Claude Opus 4.8'},\n {id: 'claude-sonnet-4-8', label: 'Claude Sonnet 4.8'},\n {id: 'claude-haiku-4-5', label: 'Claude Haiku 4.5'},\n ],\n };\n}\n\nfunction longListEntry(): SupportedProvider {\n return {\n kind: 'supported',\n id: 'cloudflare-workers-ai',\n label: 'Cloudflare Workers AI',\n defaultModel: '@cf/moonshotai/kimi-k2.7-code',\n credentialFields: [{key: 'api_token', label: 'API token', secret: true}],\n models: Array.from({length: 56}, (_, index) => ({\n id:\n index === 0\n ? '@cf/moonshotai/kimi-k2.7-code'\n : `provider/research-lab/model-family-${String(index).padStart(2, '0')}-large-context`,\n label: index === 0 ? 'Kimi K2.7 Code' : `Research Model ${index}`,\n })),\n };\n}\n\nfunction customProviderConfig(): CustomProviderConfig {\n return {\n kind: 'custom',\n providerId: 'local-vllm',\n displayName: 'Local vLLM',\n api: 'openai-completions',\n baseUrl: 'http://localhost:8000/v1',\n headers: [],\n secretHeaderNames: [],\n models: [{id: 'llama-3.1', label: 'Llama 3.1'}],\n defaultModel: 'llama-3.1',\n createdAt: '2026-05-08T00:00:00.000Z',\n updatedAt: '2026-05-08T00:00:00.000Z',\n };\n}\n"],"names":["useState","ModelProviderUsageModal","usageTargetFromCatalogEntry","usageTargetFromCustomConfig","ModelProviderUsageModalStory","variant","open","setOpen","entry","longListEntry","anthropicEntry","target","customProviderConfig","div","className","initialModel","defaultModel","workspaceDefaultHarnessId","onOpenChange","meta","title","component","parameters","layout","args","Playground","LongModelList","CustomProvider","kind","id","label","credentialFields","key","secret","models","Array","from","length","_","index","String","padStart","providerId","displayName","api","baseUrl","headers","secretHeaderNames","createdAt","updatedAt"],"mappings":";AACA,SAAQA,QAAQ,QAAO,QAAQ;AAE/B,SAAQC,uBAAuB,QAAO,kCAAkC;AACxE,SACEC,2BAA2B,EAC3BC,2BAA2B,QACtB,mCAAmC;AAM1C,SAASC,6BAA6B,EAACC,OAAO,EAAoC;IAChF,MAAM,CAACC,MAAMC,QAAQ,GAAGP,SAAS;IACjC,MAAMQ,QAAQH,YAAY,cAAcI,kBAAkBC;IAC1D,MAAMC,SACJN,YAAY,WACRF,4BAA4BS,0BAC5BV,4BAA4BM;IAElC,qBACE,KAACK;QAAIC,WAAU;kBACb,cAAA,KAACb;YACCU,QAAQA;YACRI,cAAcJ,OAAOK,YAAY;YACjCC,2BAA0B;YAC1BX,MAAMA;YACNY,cAAcX;;;AAItB;AAEA,MAAMY,OAAO;IACXC,OAAO;IACPC,WAAWjB;IACXkB,YAAY;QAACC,QAAQ;IAAY;IACjCC,MAAM;QAACnB,SAAS;IAAW;AAC7B;AAEA,eAAec,KAAK;AAGpB,OAAO,MAAMM,aAAoB,CAAC,EAAE;AAEpC,OAAO,MAAMC,gBAAuB;IAClCF,MAAM;QAACnB,SAAS;IAAW;AAC7B,EAAE;AAEF,OAAO,MAAMsB,iBAAwB;IACnCH,MAAM;QAACnB,SAAS;IAAQ;AAC1B,EAAE;AAEF,SAASK;IACP,OAAO;QACLkB,MAAM;QACNC,IAAI;QACJC,OAAO;QACPd,cAAc;QACde,kBAAkB;YAAC;gBAACC,KAAK;gBAAWF,OAAO;gBAAWG,QAAQ;YAAI;SAAE;QACpEC,QAAQ;YACN;gBAACL,IAAI;gBAAmBC,OAAO;YAAiB;YAChD;gBAACD,IAAI;gBAAqBC,OAAO;YAAmB;YACpD;gBAACD,IAAI;gBAAoBC,OAAO;YAAkB;SACnD;IACH;AACF;AAEA,SAASrB;IACP,OAAO;QACLmB,MAAM;QACNC,IAAI;QACJC,OAAO;QACPd,cAAc;QACde,kBAAkB;YAAC;gBAACC,KAAK;gBAAaF,OAAO;gBAAaG,QAAQ;YAAI;SAAE;QACxEC,QAAQC,MAAMC,IAAI,CAAC;YAACC,QAAQ;QAAE,GAAG,CAACC,GAAGC,QAAW,CAAA;gBAC9CV,IACEU,UAAU,IACN,kCACA,CAAC,mCAAmC,EAAEC,OAAOD,OAAOE,QAAQ,CAAC,GAAG,KAAK,cAAc,CAAC;gBAC1FX,OAAOS,UAAU,IAAI,mBAAmB,CAAC,eAAe,EAAEA,OAAO;YACnE,CAAA;IACF;AACF;AAEA,SAAS3B;IACP,OAAO;QACLgB,MAAM;QACNc,YAAY;QACZC,aAAa;QACbC,KAAK;QACLC,SAAS;QACTC,SAAS,EAAE;QACXC,mBAAmB,EAAE;QACrBb,QAAQ;YAAC;gBAACL,IAAI;gBAAaC,OAAO;YAAW;SAAE;QAC/Cd,cAAc;QACdgC,WAAW;QACXC,WAAW;IACb;AACF"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CustomProviderConfig, SupportedProvider } from '#core/models.js';
|
|
2
2
|
export interface ModelProviderUsageTarget {
|
|
3
3
|
id: string;
|
|
4
4
|
label: string;
|
|
5
5
|
isCustom: boolean;
|
|
6
|
-
models:
|
|
6
|
+
models: ReadonlyArray<{
|
|
7
7
|
id: string;
|
|
8
8
|
label: string;
|
|
9
9
|
}>;
|
|
10
|
-
|
|
10
|
+
defaultModel: string | null;
|
|
11
11
|
}
|
|
12
|
-
export declare function usageTargetFromCatalogEntry(entry:
|
|
13
|
-
export declare function usageTargetFromCustomConfig(config:
|
|
12
|
+
export declare function usageTargetFromCatalogEntry(entry: SupportedProvider): ModelProviderUsageTarget;
|
|
13
|
+
export declare function usageTargetFromCustomConfig(config: CustomProviderConfig): ModelProviderUsageTarget;
|
|
14
14
|
//# sourceMappingURL=model-provider-usage-target.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-provider-usage-target.d.ts","sourceRoot":"","sources":["../../src/components/model-provider-usage-target.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"model-provider-usage-target.d.ts","sourceRoot":"","sources":["../../src/components/model-provider-usage-target.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,oBAAoB,EAAE,iBAAiB,EAAC,MAAM,iBAAiB,CAAC;AAE7E,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IACnD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,iBAAiB,GAAG,wBAAwB,CAS9F;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,oBAAoB,GAC3B,wBAAwB,CAS1B"}
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
export function usageTargetFromCatalogEntry(entry) {
|
|
2
|
+
const provider = entry;
|
|
2
3
|
return {
|
|
3
|
-
id:
|
|
4
|
-
label:
|
|
4
|
+
id: provider.id,
|
|
5
|
+
label: provider.label,
|
|
5
6
|
isCustom: false,
|
|
6
|
-
models:
|
|
7
|
-
|
|
7
|
+
models: provider.models,
|
|
8
|
+
defaultModel: provider.defaultModel
|
|
8
9
|
};
|
|
9
10
|
}
|
|
10
11
|
export function usageTargetFromCustomConfig(config) {
|
|
12
|
+
const provider = config;
|
|
11
13
|
return {
|
|
12
|
-
id:
|
|
13
|
-
label:
|
|
14
|
+
id: provider.providerId,
|
|
15
|
+
label: provider.displayName,
|
|
14
16
|
isCustom: true,
|
|
15
|
-
models:
|
|
16
|
-
|
|
17
|
+
models: provider.models,
|
|
18
|
+
defaultModel: provider.defaultModel
|
|
17
19
|
};
|
|
18
20
|
}
|
|
19
21
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/model-provider-usage-target.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"sources":["../../src/components/model-provider-usage-target.ts"],"sourcesContent":["import type {CustomProviderConfig, SupportedProvider} from '#core/models.js';\n\nexport interface ModelProviderUsageTarget {\n id: string;\n label: string;\n isCustom: boolean;\n models: ReadonlyArray<{id: string; label: string}>;\n defaultModel: string | null;\n}\n\nexport function usageTargetFromCatalogEntry(entry: SupportedProvider): ModelProviderUsageTarget {\n const provider = entry;\n return {\n id: provider.id,\n label: provider.label,\n isCustom: false,\n models: provider.models,\n defaultModel: provider.defaultModel,\n };\n}\n\nexport function usageTargetFromCustomConfig(\n config: CustomProviderConfig,\n): ModelProviderUsageTarget {\n const provider = config;\n return {\n id: provider.providerId,\n label: provider.displayName,\n isCustom: true,\n models: provider.models,\n defaultModel: provider.defaultModel,\n };\n}\n"],"names":["usageTargetFromCatalogEntry","entry","provider","id","label","isCustom","models","defaultModel","usageTargetFromCustomConfig","config","providerId","displayName"],"mappings":"AAUA,OAAO,SAASA,4BAA4BC,KAAwB;IAClE,MAAMC,WAAWD;IACjB,OAAO;QACLE,IAAID,SAASC,EAAE;QACfC,OAAOF,SAASE,KAAK;QACrBC,UAAU;QACVC,QAAQJ,SAASI,MAAM;QACvBC,cAAcL,SAASK,YAAY;IACrC;AACF;AAEA,OAAO,SAASC,4BACdC,MAA4B;IAE5B,MAAMP,WAAWO;IACjB,OAAO;QACLN,IAAID,SAASQ,UAAU;QACvBN,OAAOF,SAASS,WAAW;QAC3BN,UAAU;QACVC,QAAQJ,SAASI,MAAM;QACvBC,cAAcL,SAASK,YAAY;IACrC;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-providers-section.d.ts","sourceRoot":"","sources":["../../src/components/model-providers-section.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"model-providers-section.d.ts","sourceRoot":"","sources":["../../src/components/model-providers-section.tsx"],"names":[],"mappings":"AAuEA,wBAAgB,8BAA8B,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,+BA2TlF"}
|