@shipfox/client-agent 22.0.2 → 22.0.3

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 (73) hide show
  1. package/.storybook/preview.tsx +2 -2
  2. package/.turbo/turbo-build.log +1 -1
  3. package/CHANGELOG.md +19 -0
  4. package/dist/components/form-errors.d.ts.map +1 -1
  5. package/dist/components/form-errors.js +3 -0
  6. package/dist/components/form-errors.js.map +1 -1
  7. package/dist/components/harness-availability.d.ts +2 -2
  8. package/dist/components/harness-availability.d.ts.map +1 -1
  9. package/dist/components/harness-availability.js +4 -3
  10. package/dist/components/harness-availability.js.map +1 -1
  11. package/dist/components/harnesses-section.d.ts.map +1 -1
  12. package/dist/components/harnesses-section.js +4 -2
  13. package/dist/components/harnesses-section.js.map +1 -1
  14. package/dist/components/model-provider-usage-modal.d.ts.map +1 -1
  15. package/dist/components/model-provider-usage-modal.js +23 -5
  16. package/dist/components/model-provider-usage-modal.js.map +1 -1
  17. package/dist/components/model-provider-usage-target.d.ts +6 -6
  18. package/dist/components/model-provider-usage-target.d.ts.map +1 -1
  19. package/dist/components/model-provider-usage-target.js +3 -1
  20. package/dist/components/model-provider-usage-target.js.map +1 -1
  21. package/dist/components/model-providers-section.d.ts.map +1 -1
  22. package/dist/components/model-providers-section.js +277 -170
  23. package/dist/components/model-providers-section.js.map +1 -1
  24. package/dist/components/model-providers-section.stories.d.ts +2 -1
  25. package/dist/components/model-providers-section.stories.d.ts.map +1 -1
  26. package/dist/components/model-providers-section.stories.js +45 -1
  27. package/dist/components/model-providers-section.stories.js.map +1 -1
  28. package/dist/core/harness-policy.d.ts +5 -2
  29. package/dist/core/harness-policy.d.ts.map +1 -1
  30. package/dist/core/harness-policy.js +7 -1
  31. package/dist/core/harness-policy.js.map +1 -1
  32. package/dist/core/models.d.ts +3 -0
  33. package/dist/core/models.d.ts.map +1 -1
  34. package/dist/core/models.js.map +1 -1
  35. package/dist/core/provider-policy.d.ts +3 -1
  36. package/dist/core/provider-policy.d.ts.map +1 -1
  37. package/dist/core/provider-policy.js +7 -0
  38. package/dist/core/provider-policy.js.map +1 -1
  39. package/dist/hooks/api/model-provider-mapper.d.ts.map +1 -1
  40. package/dist/hooks/api/model-provider-mapper.js +5 -1
  41. package/dist/hooks/api/model-provider-mapper.js.map +1 -1
  42. package/dist/pages/model-provider-onboarding-page.d.ts +1 -1
  43. package/dist/pages/model-provider-onboarding-page.d.ts.map +1 -1
  44. package/dist/pages/model-provider-onboarding-page.js +58 -44
  45. package/dist/pages/model-provider-onboarding-page.js.map +1 -1
  46. package/dist/pages/model-provider-onboarding-page.stories.d.ts.map +1 -1
  47. package/dist/pages/model-provider-onboarding-page.stories.js +5 -17
  48. package/dist/pages/model-provider-onboarding-page.stories.js.map +1 -1
  49. package/dist/tsconfig.test.tsbuildinfo +1 -1
  50. package/package.json +5 -5
  51. package/src/components/form-errors.test.ts +9 -0
  52. package/src/components/form-errors.ts +3 -0
  53. package/src/components/harness-availability.test.ts +49 -2
  54. package/src/components/harness-availability.ts +18 -3
  55. package/src/components/harnesses-section.test.tsx +51 -9
  56. package/src/components/harnesses-section.tsx +4 -1
  57. package/src/components/model-provider-usage-modal.test.tsx +23 -0
  58. package/src/components/model-provider-usage-modal.tsx +32 -6
  59. package/src/components/model-provider-usage-target.ts +9 -3
  60. package/src/components/model-providers-section.stories.tsx +33 -1
  61. package/src/components/model-providers-section.test.tsx +41 -0
  62. package/src/components/model-providers-section.tsx +264 -155
  63. package/src/core/harness-policy.ts +21 -1
  64. package/src/core/models.ts +3 -0
  65. package/src/core/provider-policy.ts +12 -0
  66. package/src/hooks/api/model-provider-mapper.test.ts +18 -0
  67. package/src/hooks/api/model-provider-mapper.ts +6 -1
  68. package/src/hooks/api/model-providers.test.ts +11 -0
  69. package/src/pages/model-provider-onboarding-page.stories.tsx +10 -14
  70. package/src/pages/model-provider-onboarding-page.test.tsx +133 -24
  71. package/src/pages/model-provider-onboarding-page.tsx +47 -34
  72. package/test/fixtures/model-providers.ts +22 -1
  73. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/provider-policy.ts"],"sourcesContent":["import type {\n HarnessDescriptor,\n ProviderCatalogEntry,\n ProviderConfig,\n SupportedProvider,\n} from './models.js';\n\nexport function isSupportedProvider(entry: ProviderCatalogEntry): entry is SupportedProvider {\n return entry.kind === 'supported';\n}\n\nexport function supportsProvider(harness: HarnessDescriptor, providerId: string): boolean {\n return harness.supportedProviderIds.includes(providerId);\n}\n\nexport function availableProviders(\n catalog: readonly ProviderCatalogEntry[],\n configs: readonly ProviderConfig[],\n): SupportedProvider[] {\n const configuredIds = new Set(configs.map((config) => config.providerId));\n return catalog.filter(isSupportedProvider).filter((provider) => !configuredIds.has(provider.id));\n}\n\nexport function providerMatchesSearch(entry: SupportedProvider, query: string): boolean {\n const needle = query.trim().toLocaleLowerCase();\n if (!needle) return true;\n const terms = [\n entry.id,\n entry.label,\n ...entry.models.flatMap((model) => [model.id, model.label]),\n ];\n return terms.some((term) => term.toLocaleLowerCase().includes(needle));\n}\n\nexport function customProviderCardMatchesSearch(query: string): boolean {\n const needle = query.trim().toLocaleLowerCase();\n if (!needle) return true;\n return 'custom provider openai anthropic google endpoint https public'.includes(needle);\n}\n\nexport function deriveProviderSlug(displayName: string): string {\n return displayName\n .trim()\n .toLocaleLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nconst PROVIDER_SLUG_RE = /^[a-z][a-z0-9-]{1,62}$/;\n\nexport function isProviderSlugValid(slug: string): boolean {\n return PROVIDER_SLUG_RE.test(slug);\n}\n"],"names":["isSupportedProvider","entry","kind","supportsProvider","harness","providerId","supportedProviderIds","includes","availableProviders","catalog","configs","configuredIds","Set","map","config","filter","provider","has","id","providerMatchesSearch","query","needle","trim","toLocaleLowerCase","terms","label","models","flatMap","model","some","term","customProviderCardMatchesSearch","deriveProviderSlug","displayName","replace","PROVIDER_SLUG_RE","isProviderSlugValid","slug","test"],"mappings":"AAOA,OAAO,SAASA,oBAAoBC,KAA2B;IAC7D,OAAOA,MAAMC,IAAI,KAAK;AACxB;AAEA,OAAO,SAASC,iBAAiBC,OAA0B,EAAEC,UAAkB;IAC7E,OAAOD,QAAQE,oBAAoB,CAACC,QAAQ,CAACF;AAC/C;AAEA,OAAO,SAASG,mBACdC,OAAwC,EACxCC,OAAkC;IAElC,MAAMC,gBAAgB,IAAIC,IAAIF,QAAQG,GAAG,CAAC,CAACC,SAAWA,OAAOT,UAAU;IACvE,OAAOI,QAAQM,MAAM,CAACf,qBAAqBe,MAAM,CAAC,CAACC,WAAa,CAACL,cAAcM,GAAG,CAACD,SAASE,EAAE;AAChG;AAEA,OAAO,SAASC,sBAAsBlB,KAAwB,EAAEmB,KAAa;IAC3E,MAAMC,SAASD,MAAME,IAAI,GAAGC,iBAAiB;IAC7C,IAAI,CAACF,QAAQ,OAAO;IACpB,MAAMG,QAAQ;QACZvB,MAAMiB,EAAE;QACRjB,MAAMwB,KAAK;WACRxB,MAAMyB,MAAM,CAACC,OAAO,CAAC,CAACC,QAAU;gBAACA,MAAMV,EAAE;gBAAEU,MAAMH,KAAK;aAAC;KAC3D;IACD,OAAOD,MAAMK,IAAI,CAAC,CAACC,OAASA,KAAKP,iBAAiB,GAAGhB,QAAQ,CAACc;AAChE;AAEA,OAAO,SAASU,gCAAgCX,KAAa;IAC3D,MAAMC,SAASD,MAAME,IAAI,GAAGC,iBAAiB;IAC7C,IAAI,CAACF,QAAQ,OAAO;IACpB,OAAO,gEAAgEd,QAAQ,CAACc;AAClF;AAEA,OAAO,SAASW,mBAAmBC,WAAmB;IACpD,OAAOA,YACJX,IAAI,GACJC,iBAAiB,GACjBW,OAAO,CAAC,eAAe,KACvBA,OAAO,CAAC,YAAY;AACzB;AAEA,MAAMC,mBAAmB;AAEzB,OAAO,SAASC,oBAAoBC,IAAY;IAC9C,OAAOF,iBAAiBG,IAAI,CAACD;AAC/B"}
1
+ {"version":3,"sources":["../../src/core/provider-policy.ts"],"sourcesContent":["import type {\n HarnessDescriptor,\n ProviderCatalog,\n ProviderCatalogEntry,\n ProviderConfig,\n SupportedProvider,\n} from './models.js';\n\nexport function isSupportedProvider(entry: ProviderCatalogEntry): entry is SupportedProvider {\n return entry.kind === 'supported';\n}\n\nexport function supportsProvider(harness: HarnessDescriptor, providerId: string): boolean {\n return harness.supportedProviderIds.includes(providerId);\n}\n\nexport function isManagedOnlyCatalog(catalog: ProviderCatalog | undefined): boolean {\n return catalog?.workspaceProviders === 'disabled';\n}\n\nexport function managedProviderFromCatalog(\n catalog: ProviderCatalog | undefined,\n): SupportedProvider | undefined {\n if (!isManagedOnlyCatalog(catalog)) return undefined;\n return catalog?.providers.find(isSupportedProvider);\n}\n\nexport function availableProviders(\n catalog: readonly ProviderCatalogEntry[],\n configs: readonly ProviderConfig[],\n): SupportedProvider[] {\n const configuredIds = new Set(configs.map((config) => config.providerId));\n return catalog.filter(isSupportedProvider).filter((provider) => !configuredIds.has(provider.id));\n}\n\nexport function providerMatchesSearch(entry: SupportedProvider, query: string): boolean {\n const needle = query.trim().toLocaleLowerCase();\n if (!needle) return true;\n const terms = [\n entry.id,\n entry.label,\n ...entry.models.flatMap((model) => [model.id, model.label]),\n ];\n return terms.some((term) => term.toLocaleLowerCase().includes(needle));\n}\n\nexport function customProviderCardMatchesSearch(query: string): boolean {\n const needle = query.trim().toLocaleLowerCase();\n if (!needle) return true;\n return 'custom provider openai anthropic google endpoint https public'.includes(needle);\n}\n\nexport function deriveProviderSlug(displayName: string): string {\n return displayName\n .trim()\n .toLocaleLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nconst PROVIDER_SLUG_RE = /^[a-z][a-z0-9-]{1,62}$/;\n\nexport function isProviderSlugValid(slug: string): boolean {\n return PROVIDER_SLUG_RE.test(slug);\n}\n"],"names":["isSupportedProvider","entry","kind","supportsProvider","harness","providerId","supportedProviderIds","includes","isManagedOnlyCatalog","catalog","workspaceProviders","managedProviderFromCatalog","undefined","providers","find","availableProviders","configs","configuredIds","Set","map","config","filter","provider","has","id","providerMatchesSearch","query","needle","trim","toLocaleLowerCase","terms","label","models","flatMap","model","some","term","customProviderCardMatchesSearch","deriveProviderSlug","displayName","replace","PROVIDER_SLUG_RE","isProviderSlugValid","slug","test"],"mappings":"AAQA,OAAO,SAASA,oBAAoBC,KAA2B;IAC7D,OAAOA,MAAMC,IAAI,KAAK;AACxB;AAEA,OAAO,SAASC,iBAAiBC,OAA0B,EAAEC,UAAkB;IAC7E,OAAOD,QAAQE,oBAAoB,CAACC,QAAQ,CAACF;AAC/C;AAEA,OAAO,SAASG,qBAAqBC,OAAoC;IACvE,OAAOA,SAASC,uBAAuB;AACzC;AAEA,OAAO,SAASC,2BACdF,OAAoC;IAEpC,IAAI,CAACD,qBAAqBC,UAAU,OAAOG;IAC3C,OAAOH,SAASI,UAAUC,KAAKd;AACjC;AAEA,OAAO,SAASe,mBACdN,OAAwC,EACxCO,OAAkC;IAElC,MAAMC,gBAAgB,IAAIC,IAAIF,QAAQG,GAAG,CAAC,CAACC,SAAWA,OAAOf,UAAU;IACvE,OAAOI,QAAQY,MAAM,CAACrB,qBAAqBqB,MAAM,CAAC,CAACC,WAAa,CAACL,cAAcM,GAAG,CAACD,SAASE,EAAE;AAChG;AAEA,OAAO,SAASC,sBAAsBxB,KAAwB,EAAEyB,KAAa;IAC3E,MAAMC,SAASD,MAAME,IAAI,GAAGC,iBAAiB;IAC7C,IAAI,CAACF,QAAQ,OAAO;IACpB,MAAMG,QAAQ;QACZ7B,MAAMuB,EAAE;QACRvB,MAAM8B,KAAK;WACR9B,MAAM+B,MAAM,CAACC,OAAO,CAAC,CAACC,QAAU;gBAACA,MAAMV,EAAE;gBAAEU,MAAMH,KAAK;aAAC;KAC3D;IACD,OAAOD,MAAMK,IAAI,CAAC,CAACC,OAASA,KAAKP,iBAAiB,GAAGtB,QAAQ,CAACoB;AAChE;AAEA,OAAO,SAASU,gCAAgCX,KAAa;IAC3D,MAAMC,SAASD,MAAME,IAAI,GAAGC,iBAAiB;IAC7C,IAAI,CAACF,QAAQ,OAAO;IACpB,OAAO,gEAAgEpB,QAAQ,CAACoB;AAClF;AAEA,OAAO,SAASW,mBAAmBC,WAAmB;IACpD,OAAOA,YACJX,IAAI,GACJC,iBAAiB,GACjBW,OAAO,CAAC,eAAe,KACvBA,OAAO,CAAC,YAAY;AACzB;AAEA,MAAMC,mBAAmB;AAEzB,OAAO,SAASC,oBAAoBC,IAAY;IAC9C,OAAOF,iBAAiBG,IAAI,CAACD;AAC/B"}
@@ -1 +1 @@
1
- {"version":3,"file":"model-provider-mapper.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/model-provider-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,4BAA4B,EAC5B,mCAAmC,EACnC,4BAA4B,EAC5B,+BAA+B,EAC/B,sBAAsB,EACtB,8BAA8B,EAC9B,4BAA4B,EAC5B,kCAAkC,EACnC,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAEV,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,6BAA6B,EAC7B,eAAe,EACf,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACtB,MAAM,iBAAiB,CAAC;AAEzB,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,+BAA+B,GAAG,eAAe,CAE5F;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,4BAA4B,GAAG,oBAAoB,CAqBhG;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,mCAAmC,GAC5C,qBAAqB,CAMvB;AAED,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,kCAAkC,GAC3C,6BAA6B,CAE/B;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,4BAA4B,GACrC,uBAAuB,CAEzB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,8BAA8B,GAAG,cAAc,CAIvF;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,sBAAsB,GAAG,qBAAqB,CAQ7F;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,4BAA4B,GAAG,oBAAoB,CAcjG"}
1
+ {"version":3,"file":"model-provider-mapper.d.ts","sourceRoot":"","sources":["../../../src/hooks/api/model-provider-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,4BAA4B,EAC5B,mCAAmC,EACnC,4BAA4B,EAC5B,+BAA+B,EAC/B,sBAAsB,EACtB,8BAA8B,EAC9B,4BAA4B,EAC5B,kCAAkC,EACnC,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAEV,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,6BAA6B,EAC7B,eAAe,EACf,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACtB,MAAM,iBAAiB,CAAC;AAEzB,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,+BAA+B,GAAG,eAAe,CAK5F;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,4BAA4B,GAAG,oBAAoB,CAqBhG;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,mCAAmC,GAC5C,qBAAqB,CAMvB;AAED,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,kCAAkC,GAC3C,6BAA6B,CAE/B;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,4BAA4B,GACrC,uBAAuB,CAEzB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,8BAA8B,GAAG,cAAc,CAIvF;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,sBAAsB,GAAG,qBAAqB,CAQ7F;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,4BAA4B,GAAG,oBAAoB,CAcjG"}
@@ -1,6 +1,7 @@
1
1
  export function toProviderCatalog(response) {
2
2
  return {
3
- providers: response.providers.map(toProviderCatalogEntry)
3
+ providers: response.providers.map(toProviderCatalogEntry),
4
+ workspaceProviders: response.workspace_providers ?? 'enabled'
4
5
  };
5
6
  }
6
7
  export function toProviderCatalogEntry(entry) {
@@ -76,6 +77,9 @@ function toAgentModel(model) {
76
77
  return {
77
78
  id: model.id,
78
79
  label: model.label,
80
+ ...model.api === undefined ? {} : {
81
+ api: model.api
82
+ },
79
83
  ...model.context_window === undefined ? {} : {
80
84
  contextWindow: model.context_window
81
85
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/hooks/api/model-provider-mapper.ts"],"sourcesContent":["import type {\n CustomModelProviderConfigDto,\n ListModelProviderConfigsResponseDto,\n ModelProviderCatalogEntryDto,\n ModelProviderCatalogResponseDto,\n ModelProviderConfigDto,\n ModelProviderConfigResponseDto,\n SetDefaultHarnessResponseDto,\n SetDefaultModelProviderResponseDto,\n} from '@shipfox/api-agent-dto';\nimport type {\n AgentModel,\n BuiltinProviderConfig,\n CustomProviderConfig,\n DefaultHarnessSelection,\n DefaultModelProviderSelection,\n ProviderCatalog,\n ProviderCatalogEntry,\n ProviderConfig,\n ProviderConfiguration,\n} from '#core/models.js';\n\nexport function toProviderCatalog(response: ModelProviderCatalogResponseDto): ProviderCatalog {\n return {providers: response.providers.map(toProviderCatalogEntry)};\n}\n\nexport function toProviderCatalogEntry(entry: ModelProviderCatalogEntryDto): ProviderCatalogEntry {\n if (entry.support_status === 'unsupported') {\n return {\n kind: 'unsupported',\n id: entry.id,\n label: entry.label,\n unsupportedReason: entry.unsupported_reason ?? 'Unsupported provider',\n };\n }\n return {\n kind: 'supported',\n id: entry.id,\n label: entry.label,\n defaultModel: entry.default_model,\n credentialFields: entry.credential_fields.map((field) => ({\n key: field.key,\n label: field.label,\n secret: field.secret,\n })),\n models: entry.models.map(toAgentModel),\n };\n}\n\nexport function toProviderConfiguration(\n response: ListModelProviderConfigsResponseDto,\n): ProviderConfiguration {\n return {\n configs: response.configs.map(toProviderConfig),\n defaultHarnessId: response.default_harness_id,\n defaultProviderId: response.default_provider_id,\n };\n}\n\nexport function toDefaultModelProviderSelection(\n response: SetDefaultModelProviderResponseDto,\n): DefaultModelProviderSelection {\n return {defaultProviderId: response.default_provider_id};\n}\n\nexport function toDefaultHarnessSelection(\n response: SetDefaultHarnessResponseDto,\n): DefaultHarnessSelection {\n return {defaultHarnessId: response.default_harness_id};\n}\n\nexport function toProviderConfig(config: ModelProviderConfigResponseDto): ProviderConfig {\n return config.kind === 'builtin'\n ? toBuiltinProviderConfig(config)\n : toCustomProviderConfig(config);\n}\n\nexport function toBuiltinProviderConfig(config: ModelProviderConfigDto): BuiltinProviderConfig {\n return {\n kind: 'builtin',\n providerId: config.provider_id,\n defaultModel: config.default_model,\n createdAt: config.created_at,\n updatedAt: config.updated_at,\n };\n}\n\nexport function toCustomProviderConfig(config: CustomModelProviderConfigDto): CustomProviderConfig {\n return {\n kind: 'custom',\n providerId: config.provider_id,\n displayName: config.display_name,\n api: config.api,\n baseUrl: config.base_url,\n headers: config.headers.map((header) => ({name: header.name, value: header.value})),\n secretHeaderNames: config.secret_header_names,\n models: config.models.map(toAgentModel),\n defaultModel: config.default_model,\n createdAt: config.created_at,\n updatedAt: config.updated_at,\n };\n}\n\nfunction toAgentModel(model: {\n id: string;\n label: string;\n context_window?: number | undefined;\n max_output_tokens?: number | undefined;\n input_image?: boolean | undefined;\n reasoning?: boolean | undefined;\n}): AgentModel {\n return {\n id: model.id,\n label: model.label,\n ...(model.context_window === undefined ? {} : {contextWindow: model.context_window}),\n ...(model.max_output_tokens === undefined ? {} : {maxOutputTokens: model.max_output_tokens}),\n ...(model.input_image === undefined ? {} : {inputImage: model.input_image}),\n ...(model.reasoning === undefined ? {} : {reasoning: model.reasoning}),\n };\n}\n"],"names":["toProviderCatalog","response","providers","map","toProviderCatalogEntry","entry","support_status","kind","id","label","unsupportedReason","unsupported_reason","defaultModel","default_model","credentialFields","credential_fields","field","key","secret","models","toAgentModel","toProviderConfiguration","configs","toProviderConfig","defaultHarnessId","default_harness_id","defaultProviderId","default_provider_id","toDefaultModelProviderSelection","toDefaultHarnessSelection","config","toBuiltinProviderConfig","toCustomProviderConfig","providerId","provider_id","createdAt","created_at","updatedAt","updated_at","displayName","display_name","api","baseUrl","base_url","headers","header","name","value","secretHeaderNames","secret_header_names","model","context_window","undefined","contextWindow","max_output_tokens","maxOutputTokens","input_image","inputImage","reasoning"],"mappings":"AAsBA,OAAO,SAASA,kBAAkBC,QAAyC;IACzE,OAAO;QAACC,WAAWD,SAASC,SAAS,CAACC,GAAG,CAACC;IAAuB;AACnE;AAEA,OAAO,SAASA,uBAAuBC,KAAmC;IACxE,IAAIA,MAAMC,cAAc,KAAK,eAAe;QAC1C,OAAO;YACLC,MAAM;YACNC,IAAIH,MAAMG,EAAE;YACZC,OAAOJ,MAAMI,KAAK;YAClBC,mBAAmBL,MAAMM,kBAAkB,IAAI;QACjD;IACF;IACA,OAAO;QACLJ,MAAM;QACNC,IAAIH,MAAMG,EAAE;QACZC,OAAOJ,MAAMI,KAAK;QAClBG,cAAcP,MAAMQ,aAAa;QACjCC,kBAAkBT,MAAMU,iBAAiB,CAACZ,GAAG,CAAC,CAACa,QAAW,CAAA;gBACxDC,KAAKD,MAAMC,GAAG;gBACdR,OAAOO,MAAMP,KAAK;gBAClBS,QAAQF,MAAME,MAAM;YACtB,CAAA;QACAC,QAAQd,MAAMc,MAAM,CAAChB,GAAG,CAACiB;IAC3B;AACF;AAEA,OAAO,SAASC,wBACdpB,QAA6C;IAE7C,OAAO;QACLqB,SAASrB,SAASqB,OAAO,CAACnB,GAAG,CAACoB;QAC9BC,kBAAkBvB,SAASwB,kBAAkB;QAC7CC,mBAAmBzB,SAAS0B,mBAAmB;IACjD;AACF;AAEA,OAAO,SAASC,gCACd3B,QAA4C;IAE5C,OAAO;QAACyB,mBAAmBzB,SAAS0B,mBAAmB;IAAA;AACzD;AAEA,OAAO,SAASE,0BACd5B,QAAsC;IAEtC,OAAO;QAACuB,kBAAkBvB,SAASwB,kBAAkB;IAAA;AACvD;AAEA,OAAO,SAASF,iBAAiBO,MAAsC;IACrE,OAAOA,OAAOvB,IAAI,KAAK,YACnBwB,wBAAwBD,UACxBE,uBAAuBF;AAC7B;AAEA,OAAO,SAASC,wBAAwBD,MAA8B;IACpE,OAAO;QACLvB,MAAM;QACN0B,YAAYH,OAAOI,WAAW;QAC9BtB,cAAckB,OAAOjB,aAAa;QAClCsB,WAAWL,OAAOM,UAAU;QAC5BC,WAAWP,OAAOQ,UAAU;IAC9B;AACF;AAEA,OAAO,SAASN,uBAAuBF,MAAoC;IACzE,OAAO;QACLvB,MAAM;QACN0B,YAAYH,OAAOI,WAAW;QAC9BK,aAAaT,OAAOU,YAAY;QAChCC,KAAKX,OAAOW,GAAG;QACfC,SAASZ,OAAOa,QAAQ;QACxBC,SAASd,OAAOc,OAAO,CAACzC,GAAG,CAAC,CAAC0C,SAAY,CAAA;gBAACC,MAAMD,OAAOC,IAAI;gBAAEC,OAAOF,OAAOE,KAAK;YAAA,CAAA;QAChFC,mBAAmBlB,OAAOmB,mBAAmB;QAC7C9B,QAAQW,OAAOX,MAAM,CAAChB,GAAG,CAACiB;QAC1BR,cAAckB,OAAOjB,aAAa;QAClCsB,WAAWL,OAAOM,UAAU;QAC5BC,WAAWP,OAAOQ,UAAU;IAC9B;AACF;AAEA,SAASlB,aAAa8B,KAOrB;IACC,OAAO;QACL1C,IAAI0C,MAAM1C,EAAE;QACZC,OAAOyC,MAAMzC,KAAK;QAClB,GAAIyC,MAAMC,cAAc,KAAKC,YAAY,CAAC,IAAI;YAACC,eAAeH,MAAMC,cAAc;QAAA,CAAC;QACnF,GAAID,MAAMI,iBAAiB,KAAKF,YAAY,CAAC,IAAI;YAACG,iBAAiBL,MAAMI,iBAAiB;QAAA,CAAC;QAC3F,GAAIJ,MAAMM,WAAW,KAAKJ,YAAY,CAAC,IAAI;YAACK,YAAYP,MAAMM,WAAW;QAAA,CAAC;QAC1E,GAAIN,MAAMQ,SAAS,KAAKN,YAAY,CAAC,IAAI;YAACM,WAAWR,MAAMQ,SAAS;QAAA,CAAC;IACvE;AACF"}
1
+ {"version":3,"sources":["../../../src/hooks/api/model-provider-mapper.ts"],"sourcesContent":["import type {\n CustomModelProviderConfigDto,\n ListModelProviderConfigsResponseDto,\n ModelProviderCatalogEntryDto,\n ModelProviderCatalogResponseDto,\n ModelProviderConfigDto,\n ModelProviderConfigResponseDto,\n SetDefaultHarnessResponseDto,\n SetDefaultModelProviderResponseDto,\n} from '@shipfox/api-agent-dto';\nimport type {\n AgentModel,\n BuiltinProviderConfig,\n CustomProviderConfig,\n DefaultHarnessSelection,\n DefaultModelProviderSelection,\n ProviderCatalog,\n ProviderCatalogEntry,\n ProviderConfig,\n ProviderConfiguration,\n} from '#core/models.js';\n\nexport function toProviderCatalog(response: ModelProviderCatalogResponseDto): ProviderCatalog {\n return {\n providers: response.providers.map(toProviderCatalogEntry),\n workspaceProviders: response.workspace_providers ?? 'enabled',\n };\n}\n\nexport function toProviderCatalogEntry(entry: ModelProviderCatalogEntryDto): ProviderCatalogEntry {\n if (entry.support_status === 'unsupported') {\n return {\n kind: 'unsupported',\n id: entry.id,\n label: entry.label,\n unsupportedReason: entry.unsupported_reason ?? 'Unsupported provider',\n };\n }\n return {\n kind: 'supported',\n id: entry.id,\n label: entry.label,\n defaultModel: entry.default_model,\n credentialFields: entry.credential_fields.map((field) => ({\n key: field.key,\n label: field.label,\n secret: field.secret,\n })),\n models: entry.models.map(toAgentModel),\n };\n}\n\nexport function toProviderConfiguration(\n response: ListModelProviderConfigsResponseDto,\n): ProviderConfiguration {\n return {\n configs: response.configs.map(toProviderConfig),\n defaultHarnessId: response.default_harness_id,\n defaultProviderId: response.default_provider_id,\n };\n}\n\nexport function toDefaultModelProviderSelection(\n response: SetDefaultModelProviderResponseDto,\n): DefaultModelProviderSelection {\n return {defaultProviderId: response.default_provider_id};\n}\n\nexport function toDefaultHarnessSelection(\n response: SetDefaultHarnessResponseDto,\n): DefaultHarnessSelection {\n return {defaultHarnessId: response.default_harness_id};\n}\n\nexport function toProviderConfig(config: ModelProviderConfigResponseDto): ProviderConfig {\n return config.kind === 'builtin'\n ? toBuiltinProviderConfig(config)\n : toCustomProviderConfig(config);\n}\n\nexport function toBuiltinProviderConfig(config: ModelProviderConfigDto): BuiltinProviderConfig {\n return {\n kind: 'builtin',\n providerId: config.provider_id,\n defaultModel: config.default_model,\n createdAt: config.created_at,\n updatedAt: config.updated_at,\n };\n}\n\nexport function toCustomProviderConfig(config: CustomModelProviderConfigDto): CustomProviderConfig {\n return {\n kind: 'custom',\n providerId: config.provider_id,\n displayName: config.display_name,\n api: config.api,\n baseUrl: config.base_url,\n headers: config.headers.map((header) => ({name: header.name, value: header.value})),\n secretHeaderNames: config.secret_header_names,\n models: config.models.map(toAgentModel),\n defaultModel: config.default_model,\n createdAt: config.created_at,\n updatedAt: config.updated_at,\n };\n}\n\nfunction toAgentModel(model: {\n id: string;\n label: string;\n api?: AgentModel['api'];\n context_window?: number | undefined;\n max_output_tokens?: number | undefined;\n input_image?: boolean | undefined;\n reasoning?: boolean | undefined;\n}): AgentModel {\n return {\n id: model.id,\n label: model.label,\n ...(model.api === undefined ? {} : {api: model.api}),\n ...(model.context_window === undefined ? {} : {contextWindow: model.context_window}),\n ...(model.max_output_tokens === undefined ? {} : {maxOutputTokens: model.max_output_tokens}),\n ...(model.input_image === undefined ? {} : {inputImage: model.input_image}),\n ...(model.reasoning === undefined ? {} : {reasoning: model.reasoning}),\n };\n}\n"],"names":["toProviderCatalog","response","providers","map","toProviderCatalogEntry","workspaceProviders","workspace_providers","entry","support_status","kind","id","label","unsupportedReason","unsupported_reason","defaultModel","default_model","credentialFields","credential_fields","field","key","secret","models","toAgentModel","toProviderConfiguration","configs","toProviderConfig","defaultHarnessId","default_harness_id","defaultProviderId","default_provider_id","toDefaultModelProviderSelection","toDefaultHarnessSelection","config","toBuiltinProviderConfig","toCustomProviderConfig","providerId","provider_id","createdAt","created_at","updatedAt","updated_at","displayName","display_name","api","baseUrl","base_url","headers","header","name","value","secretHeaderNames","secret_header_names","model","undefined","context_window","contextWindow","max_output_tokens","maxOutputTokens","input_image","inputImage","reasoning"],"mappings":"AAsBA,OAAO,SAASA,kBAAkBC,QAAyC;IACzE,OAAO;QACLC,WAAWD,SAASC,SAAS,CAACC,GAAG,CAACC;QAClCC,oBAAoBJ,SAASK,mBAAmB,IAAI;IACtD;AACF;AAEA,OAAO,SAASF,uBAAuBG,KAAmC;IACxE,IAAIA,MAAMC,cAAc,KAAK,eAAe;QAC1C,OAAO;YACLC,MAAM;YACNC,IAAIH,MAAMG,EAAE;YACZC,OAAOJ,MAAMI,KAAK;YAClBC,mBAAmBL,MAAMM,kBAAkB,IAAI;QACjD;IACF;IACA,OAAO;QACLJ,MAAM;QACNC,IAAIH,MAAMG,EAAE;QACZC,OAAOJ,MAAMI,KAAK;QAClBG,cAAcP,MAAMQ,aAAa;QACjCC,kBAAkBT,MAAMU,iBAAiB,CAACd,GAAG,CAAC,CAACe,QAAW,CAAA;gBACxDC,KAAKD,MAAMC,GAAG;gBACdR,OAAOO,MAAMP,KAAK;gBAClBS,QAAQF,MAAME,MAAM;YACtB,CAAA;QACAC,QAAQd,MAAMc,MAAM,CAAClB,GAAG,CAACmB;IAC3B;AACF;AAEA,OAAO,SAASC,wBACdtB,QAA6C;IAE7C,OAAO;QACLuB,SAASvB,SAASuB,OAAO,CAACrB,GAAG,CAACsB;QAC9BC,kBAAkBzB,SAAS0B,kBAAkB;QAC7CC,mBAAmB3B,SAAS4B,mBAAmB;IACjD;AACF;AAEA,OAAO,SAASC,gCACd7B,QAA4C;IAE5C,OAAO;QAAC2B,mBAAmB3B,SAAS4B,mBAAmB;IAAA;AACzD;AAEA,OAAO,SAASE,0BACd9B,QAAsC;IAEtC,OAAO;QAACyB,kBAAkBzB,SAAS0B,kBAAkB;IAAA;AACvD;AAEA,OAAO,SAASF,iBAAiBO,MAAsC;IACrE,OAAOA,OAAOvB,IAAI,KAAK,YACnBwB,wBAAwBD,UACxBE,uBAAuBF;AAC7B;AAEA,OAAO,SAASC,wBAAwBD,MAA8B;IACpE,OAAO;QACLvB,MAAM;QACN0B,YAAYH,OAAOI,WAAW;QAC9BtB,cAAckB,OAAOjB,aAAa;QAClCsB,WAAWL,OAAOM,UAAU;QAC5BC,WAAWP,OAAOQ,UAAU;IAC9B;AACF;AAEA,OAAO,SAASN,uBAAuBF,MAAoC;IACzE,OAAO;QACLvB,MAAM;QACN0B,YAAYH,OAAOI,WAAW;QAC9BK,aAAaT,OAAOU,YAAY;QAChCC,KAAKX,OAAOW,GAAG;QACfC,SAASZ,OAAOa,QAAQ;QACxBC,SAASd,OAAOc,OAAO,CAAC3C,GAAG,CAAC,CAAC4C,SAAY,CAAA;gBAACC,MAAMD,OAAOC,IAAI;gBAAEC,OAAOF,OAAOE,KAAK;YAAA,CAAA;QAChFC,mBAAmBlB,OAAOmB,mBAAmB;QAC7C9B,QAAQW,OAAOX,MAAM,CAAClB,GAAG,CAACmB;QAC1BR,cAAckB,OAAOjB,aAAa;QAClCsB,WAAWL,OAAOM,UAAU;QAC5BC,WAAWP,OAAOQ,UAAU;IAC9B;AACF;AAEA,SAASlB,aAAa8B,KAQrB;IACC,OAAO;QACL1C,IAAI0C,MAAM1C,EAAE;QACZC,OAAOyC,MAAMzC,KAAK;QAClB,GAAIyC,MAAMT,GAAG,KAAKU,YAAY,CAAC,IAAI;YAACV,KAAKS,MAAMT,GAAG;QAAA,CAAC;QACnD,GAAIS,MAAME,cAAc,KAAKD,YAAY,CAAC,IAAI;YAACE,eAAeH,MAAME,cAAc;QAAA,CAAC;QACnF,GAAIF,MAAMI,iBAAiB,KAAKH,YAAY,CAAC,IAAI;YAACI,iBAAiBL,MAAMI,iBAAiB;QAAA,CAAC;QAC3F,GAAIJ,MAAMM,WAAW,KAAKL,YAAY,CAAC,IAAI;YAACM,YAAYP,MAAMM,WAAW;QAAA,CAAC;QAC1E,GAAIN,MAAMQ,SAAS,KAAKP,YAAY,CAAC,IAAI;YAACO,WAAWR,MAAMQ,SAAS;QAAA,CAAC;IACvE;AACF"}
@@ -2,5 +2,5 @@ export declare function ModelProviderOnboardingPage({ workspaceId, onSkip, onCon
2
2
  workspaceId: string;
3
3
  onSkip: () => void;
4
4
  onConfigured: () => void;
5
- }): import("react").JSX.Element;
5
+ }): import("react").JSX.Element | null;
6
6
  //# sourceMappingURL=model-provider-onboarding-page.d.ts.map
@@ -1 +1 @@
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"}
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,sCA0MA"}
@@ -7,14 +7,14 @@ import { Modal, ModalContent, ModalHeader, ModalTitle } from '@shipfox/react-ui/
7
7
  import { Panel, PanelBody, PanelCell, PanelCellAction, PanelGrid } from '@shipfox/react-ui/panel';
8
8
  import { toast } from '@shipfox/react-ui/toast';
9
9
  import { Header, Text } from '@shipfox/react-ui/typography';
10
- import { useEffect, useMemo, useReducer } from 'react';
10
+ import { useEffect, useMemo, useReducer, useRef } from 'react';
11
11
  import { AvailableProvidersGrid } from '#components/available-providers-grid.js';
12
12
  import { modelProviderConfigErrorToFormError } from '#components/form-errors.js';
13
13
  import { ModelProviderGridSkeleton } from '#components/model-provider-grid-skeleton.js';
14
14
  import { ModelProviderTestAndSaveForm } from '#components/test-and-save-form.js';
15
15
  import { DEFAULT_HARNESS, harnessSupportsProvider, listHarnesses } from '#core/harness-policy.js';
16
16
  import { initialOnboardingState, onboardingReducer } from '#core/onboarding-reducer.js';
17
- import { isSupportedProvider } from '#core/provider-policy.js';
17
+ import { isManagedOnlyCatalog, isSupportedProvider } from '#core/provider-policy.js';
18
18
  import { useModelProviderCatalogQuery, useSetDefaultHarnessMutation } from '#hooks/api/model-providers.js';
19
19
  import { dismissModelProviderOnboarding } from '#state/model-provider-onboarding.js';
20
20
  export function ModelProviderOnboardingPage({ workspaceId, onSkip, onConfigured }) {
@@ -22,6 +22,11 @@ export function ModelProviderOnboardingPage({ workspaceId, onSkip, onConfigured
22
22
  const setDefaultHarness = useSetDefaultHarnessMutation();
23
23
  const [onboarding, dispatch] = useReducer(onboardingReducer, initialOnboardingState);
24
24
  const supportedProviders = catalogQuery.data?.providers.filter(isSupportedProvider) ?? [];
25
+ const catalogLoaded = catalogQuery.data !== undefined;
26
+ const catalogLoading = catalogQuery.isPending;
27
+ const catalogLoadError = catalogQuery.isError && catalogQuery.data === undefined;
28
+ const managedOnly = isManagedOnlyCatalog(catalogQuery.data);
29
+ const managedOnlyForwarded = useRef(false);
25
30
  const filteredProviders = useMemo(()=>{
26
31
  if (onboarding.step === 'choose-harness') return [];
27
32
  return supportedProviders.filter((provider)=>harnessSupportsProvider(onboarding.harnessId, provider.id));
@@ -30,10 +35,22 @@ export function ModelProviderOnboardingPage({ workspaceId, onSkip, onConfigured
30
35
  supportedProviders
31
36
  ]);
32
37
  useEffect(()=>{
38
+ if (!managedOnly || managedOnlyForwarded.current) return;
39
+ managedOnlyForwarded.current = true;
40
+ onConfigured();
41
+ }, [
42
+ managedOnly,
43
+ onConfigured
44
+ ]);
45
+ useEffect(()=>{
46
+ if (managedOnly || !catalogLoaded) return;
33
47
  document.getElementById(onboarding.step === 'choose-harness' ? 'model-provider-harness-step' : 'model-provider-provider-step')?.focus();
34
48
  }, [
49
+ catalogLoaded,
50
+ managedOnly,
35
51
  onboarding.step
36
52
  ]);
53
+ if (managedOnly) return null;
37
54
  function handleSkip() {
38
55
  try {
39
56
  dismissModelProviderOnboarding(workspaceId);
@@ -108,38 +125,46 @@ export function ModelProviderOnboardingPage({ workspaceId, onSkip, onConfigured
108
125
  })
109
126
  ]
110
127
  }),
111
- /*#__PURE__*/ _jsx("section", {
128
+ /*#__PURE__*/ _jsxs("section", {
112
129
  "aria-labelledby": headingId,
113
130
  className: "flex flex-col gap-group",
114
- children: onboarding.step === 'choose-harness' ? /*#__PURE__*/ _jsx(HarnessPicker, {
115
- onSelect: (harnessId)=>dispatch({
116
- type: 'harness-selected',
117
- harnessId
118
- })
119
- }) : /*#__PURE__*/ _jsxs(_Fragment, {
120
- children: [
121
- /*#__PURE__*/ _jsx("div", {
122
- children: /*#__PURE__*/ _jsx(Button, {
123
- type: "button",
124
- variant: "transparent",
125
- onClick: ()=>dispatch({
126
- type: 'back'
127
- }),
128
- children: "Back"
131
+ children: [
132
+ catalogLoading ? /*#__PURE__*/ _jsx(ModelProviderGridSkeleton, {
133
+ label: "Loading model providers"
134
+ }) : null,
135
+ catalogLoadError ? /*#__PURE__*/ _jsx(QueryLoadError, {
136
+ query: catalogQuery,
137
+ subject: "model provider catalog"
138
+ }) : null,
139
+ !catalogLoading && !catalogLoadError ? onboarding.step === 'choose-harness' ? /*#__PURE__*/ _jsx(HarnessPicker, {
140
+ onSelect: (harnessId)=>dispatch({
141
+ type: 'harness-selected',
142
+ harnessId
129
143
  })
130
- }),
131
- /*#__PURE__*/ _jsx(ModelProviderPicker, {
132
- catalogQuery: catalogQuery,
133
- supportedProviders: filteredProviders,
134
- onSelect: (entry)=>{
135
- dispatch({
136
- type: 'provider-selected',
137
- provider: entry
138
- });
139
- }
140
- }, onboarding.harnessId)
141
- ]
142
- })
144
+ }) : /*#__PURE__*/ _jsxs(_Fragment, {
145
+ children: [
146
+ /*#__PURE__*/ _jsx("div", {
147
+ children: /*#__PURE__*/ _jsx(Button, {
148
+ type: "button",
149
+ variant: "transparent",
150
+ onClick: ()=>dispatch({
151
+ type: 'back'
152
+ }),
153
+ children: "Back"
154
+ })
155
+ }),
156
+ /*#__PURE__*/ _jsx(ModelProviderPicker, {
157
+ supportedProviders: filteredProviders,
158
+ onSelect: (entry)=>{
159
+ dispatch({
160
+ type: 'provider-selected',
161
+ provider: entry
162
+ });
163
+ }
164
+ }, onboarding.harnessId)
165
+ ]
166
+ }) : null
167
+ ]
143
168
  }),
144
169
  /*#__PURE__*/ _jsx(Modal, {
145
170
  open: onboarding.step === 'configure-provider' || onboarding.step === 'saving-default-harness',
@@ -255,19 +280,8 @@ function HarnessCard({ harness, onChoose }) {
255
280
  })
256
281
  });
257
282
  }
258
- function ModelProviderPicker({ catalogQuery, supportedProviders, onSelect }) {
259
- if (catalogQuery.isPending) {
260
- return /*#__PURE__*/ _jsx(ModelProviderGridSkeleton, {
261
- label: "Loading model providers"
262
- });
263
- }
264
- if (catalogQuery.isError && catalogQuery.data === undefined) {
265
- return /*#__PURE__*/ _jsx(QueryLoadError, {
266
- query: catalogQuery,
267
- subject: "model provider catalog"
268
- });
269
- }
270
- if (catalogQuery.data !== undefined && supportedProviders.length === 0) {
283
+ function ModelProviderPicker({ supportedProviders, onSelect }) {
284
+ if (supportedProviders.length === 0) {
271
285
  return /*#__PURE__*/ _jsx(EmptyState, {
272
286
  icon: "componentLine",
273
287
  title: "No providers available to configure",
@@ -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 {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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"}
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, useRef} 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 {isManagedOnlyCatalog, 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 catalogLoaded = catalogQuery.data !== undefined;\n const catalogLoading = catalogQuery.isPending;\n const catalogLoadError = catalogQuery.isError && catalogQuery.data === undefined;\n const managedOnly = isManagedOnlyCatalog(catalogQuery.data);\n const managedOnlyForwarded = useRef(false);\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 if (!managedOnly || managedOnlyForwarded.current) return;\n managedOnlyForwarded.current = true;\n onConfigured();\n }, [managedOnly, onConfigured]);\n\n useEffect(() => {\n if (managedOnly || !catalogLoaded) return;\n document\n .getElementById(\n onboarding.step === 'choose-harness'\n ? 'model-provider-harness-step'\n : 'model-provider-provider-step',\n )\n ?.focus();\n }, [catalogLoaded, managedOnly, onboarding.step]);\n\n if (managedOnly) return null;\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 {catalogLoading ? <ModelProviderGridSkeleton label=\"Loading model providers\" /> : null}\n {catalogLoadError ? (\n <QueryLoadError query={catalogQuery} subject=\"model provider catalog\" />\n ) : null}\n {!catalogLoading && !catalogLoadError ? (\n onboarding.step === 'choose-harness' ? (\n <HarnessPicker\n onSelect={(harnessId) => dispatch({type: 'harness-selected', harnessId})}\n />\n ) : (\n <>\n <div>\n <Button\n type=\"button\"\n variant=\"transparent\"\n onClick={() => dispatch({type: 'back'})}\n >\n Back\n </Button>\n </div>\n <ModelProviderPicker\n key={onboarding.harnessId}\n supportedProviders={filteredProviders}\n onSelect={(entry) => {\n dispatch({type: 'provider-selected', provider: entry});\n }}\n />\n </>\n )\n ) : null}\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 supportedProviders,\n onSelect,\n}: {\n supportedProviders: SupportedProvider[];\n onSelect: (entry: SupportedProvider) => void;\n}) {\n if (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","useRef","AvailableProvidersGrid","modelProviderConfigErrorToFormError","ModelProviderGridSkeleton","ModelProviderTestAndSaveForm","DEFAULT_HARNESS","harnessSupportsProvider","listHarnesses","initialOnboardingState","onboardingReducer","isManagedOnlyCatalog","isSupportedProvider","useModelProviderCatalogQuery","useSetDefaultHarnessMutation","dismissModelProviderOnboarding","ModelProviderOnboardingPage","workspaceId","onSkip","onConfigured","catalogQuery","setDefaultHarness","onboarding","dispatch","supportedProviders","data","providers","filter","catalogLoaded","undefined","catalogLoading","isPending","catalogLoadError","isError","managedOnly","managedOnlyForwarded","filteredProviders","step","provider","harnessId","id","current","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","query","subject","HarnessPicker","onSelect","ModelProviderPicker","entry","open","onOpenChange","aria-describedby","aria-hidden","role","bold","setAsDefaultOnSave","onSaved","aria-label","map","HarnessCard","onChoose","action","span","as","description","length","icon","title","entries"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"model-provider-onboarding-page.stories.d.ts","sourceRoot":"","sources":["../../src/pages/model-provider-onboarding-page.stories.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAO,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAQrD,KAAK,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,eAAe,GAAG,cAAc,GAAG,YAAY,CAAC;AAE1F,UAAU,iCAAiC;IACzC,QAAQ,EAAE,QAAQ,CAAC;CACpB;AA+ED,iBAAS,4BAA4B,CAAC,EAAC,QAAQ,EAAC,EAAE,iCAAiC,+BAuBlF;AAED,QAAA,MAAM,IAAI;;;;QAGK,MAAM;;;;;CAEgC,CAAC;eAEvC,IAAI;AACnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,UAAU,EAAE,KAAU,CAAC;AAEpC,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,KAMlC,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,KAW/B,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,KAWjC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,KAQhC,CAAC"}
1
+ {"version":3,"file":"model-provider-onboarding-page.stories.d.ts","sourceRoot":"","sources":["../../src/pages/model-provider-onboarding-page.stories.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAO,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAQrD,KAAK,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,eAAe,GAAG,cAAc,GAAG,YAAY,CAAC;AAE1F,UAAU,iCAAiC;IACzC,QAAQ,EAAE,QAAQ,CAAC;CACpB;AA+ED,iBAAS,4BAA4B,CAAC,EAAC,QAAQ,EAAC,EAAE,iCAAiC,+BAuBlF;AAED,QAAA,MAAM,IAAI;;;;QAGK,MAAM;;;;;CAEgC,CAAC;eAEvC,IAAI;AACnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,UAAU,EAAE,KAAU,CAAC;AAEpC,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAE1B,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,KAMlC,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,KAW/B,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,KAWjC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,KAQhC,CAAC"}
@@ -176,23 +176,11 @@ export const Playground = {};
176
176
  export const Loading = {
177
177
  args: {
178
178
  scenario: 'loading'
179
- },
180
- play: async ({ canvasElement })=>{
181
- const canvas = within(canvasElement);
182
- await userEvent.click(canvas.getByRole('button', {
183
- name: 'Choose pi'
184
- }));
185
179
  }
186
180
  };
187
181
  export const CatalogError = {
188
182
  args: {
189
183
  scenario: 'catalog-error'
190
- },
191
- play: async ({ canvasElement })=>{
192
- const canvas = within(canvasElement);
193
- await userEvent.click(canvas.getByRole('button', {
194
- name: 'Choose pi'
195
- }));
196
184
  }
197
185
  };
198
186
  export const NoProvidersAvailable = {
@@ -201,7 +189,7 @@ export const NoProvidersAvailable = {
201
189
  },
202
190
  play: async ({ canvasElement })=>{
203
191
  const canvas = within(canvasElement);
204
- await userEvent.click(canvas.getByRole('button', {
192
+ await userEvent.click(await canvas.findByRole('button', {
205
193
  name: 'Choose pi'
206
194
  }));
207
195
  }
@@ -212,7 +200,7 @@ export const LongNames = {
212
200
  },
213
201
  play: async ({ canvasElement })=>{
214
202
  const canvas = within(canvasElement);
215
- await userEvent.click(canvas.getByRole('button', {
203
+ await userEvent.click(await canvas.findByRole('button', {
216
204
  name: 'Choose pi'
217
205
  }));
218
206
  }
@@ -223,7 +211,7 @@ export const FilteredProviders = {
223
211
  },
224
212
  play: async ({ canvasElement })=>{
225
213
  const canvas = within(canvasElement);
226
- await userEvent.click(canvas.getByRole('button', {
214
+ await userEvent.click(await canvas.findByRole('button', {
227
215
  name: 'Choose pi'
228
216
  }));
229
217
  await userEvent.type(await canvas.findByRole('searchbox', {
@@ -240,7 +228,7 @@ export const NoMatchingProviders = {
240
228
  },
241
229
  play: async ({ canvasElement })=>{
242
230
  const canvas = within(canvasElement);
243
- await userEvent.click(canvas.getByRole('button', {
231
+ await userEvent.click(await canvas.findByRole('button', {
244
232
  name: 'Choose pi'
245
233
  }));
246
234
  await userEvent.type(await canvas.findByRole('searchbox', {
@@ -257,7 +245,7 @@ export const ConfigureModalOpen = {
257
245
  },
258
246
  play: async ({ canvasElement })=>{
259
247
  const canvas = within(canvasElement);
260
- await userEvent.click(canvas.getByRole('button', {
248
+ await userEvent.click(await canvas.findByRole('button', {
261
249
  name: 'Choose pi'
262
250
  }));
263
251
  await userEvent.click(await canvas.findByRole('button', {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/model-provider-onboarding-page.stories.tsx"],"sourcesContent":["import type {ModelProviderCatalogEntryDto, ModelProviderConfigDto} 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 {ModelProviderOnboardingPage} from './model-provider-onboarding-page.js';\n\nconst WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';\n\ntype Scenario = 'available' | 'loading' | 'catalog-error' | 'no-providers' | 'long-names';\n\ninterface ModelProviderOnboardingStoryProps {\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 ModelProviderOnboardingStory({scenario}: ModelProviderOnboardingStoryProps) {\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=\"bg-background-subtle-base px-24 py-32\">\n <ModelProviderOnboardingPage\n workspaceId={WORKSPACE_ID}\n onSkip={() => undefined}\n onConfigured={() => undefined}\n />\n </div>\n <Toaster />\n </QueryClientProvider>\n );\n}\n\nconst meta = {\n title: 'Agent/ProviderOnboarding',\n component: ModelProviderOnboardingStory,\n parameters: {layout: 'fullscreen'},\n args: {scenario: 'available'},\n} satisfies Meta<typeof ModelProviderOnboardingStory>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Playground: Story = {};\n\nexport const Loading: Story = {\n args: {scenario: 'loading'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\n },\n};\n\nexport const CatalogError: Story = {\n args: {scenario: 'catalog-error'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\n },\n};\n\nexport const NoProvidersAvailable: Story = {\n args: {scenario: 'no-providers'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\n },\n};\n\nexport const LongNames: Story = {\n args: {scenario: 'long-names'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\n },\n};\n\nexport const FilteredProviders: Story = {\n args: {scenario: 'available'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\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 NoMatchingProviders: Story = {\n args: {scenario: 'available'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\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: 'available'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(canvas.getByRole('button', {name: 'Choose pi'}));\n await userEvent.click(await canvas.findByRole('button', {name: 'Configure Anthropic'}));\n await screen.findByLabelText('API key');\n },\n};\n\nfunction fetchForScenario(scenario: Scenario): typeof fetch {\n return (input) => {\n const url = requestUrl(input);\n const request = input instanceof Request ? input : undefined;\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 (request?.method === 'PUT' && url.pathname.includes('/agent/model-providers/')) {\n return Promise.resolve(\n jsonResponse(\n providerConfig({\n provider_id: url.pathname.endsWith('/openai') ? 'openai' : 'anthropic',\n }),\n ),\n );\n }\n return Promise.resolve(jsonResponse({}, {status: 404}));\n };\n}\n\nfunction catalogForScenario(scenario: Scenario): ModelProviderCatalogEntryDto[] {\n if (scenario === 'no-providers') return [];\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 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","ModelProviderOnboardingPage","WORKSPACE_ID","CATALOG","providerEntry","id","label","default_model","models","support_status","credential_fields","unsupported_reason","ModelProviderOnboardingStory","scenario","baseUrl","fetchImpl","fetchForScenario","queryClient","defaultOptions","queries","retry","client","div","className","workspaceId","onSkip","undefined","onConfigured","meta","title","component","parameters","layout","args","Playground","Loading","play","canvasElement","canvas","click","getByRole","name","CatalogError","NoProvidersAvailable","LongNames","FilteredProviders","type","findByRole","NoMatchingProviders","ConfigureModalOpen","findByLabelText","input","url","requestUrl","request","Request","Promise","pathname","endsWith","resolve","errorResponse","jsonResponse","providers","catalogForScenario","method","includes","providerConfig","provider_id","status","overrides","key","secret","kind","created_at","updated_at","URL","body","init","Response","JSON","stringify","headers","code","statusText"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/pages/model-provider-onboarding-page.stories.tsx"],"sourcesContent":["import type {ModelProviderCatalogEntryDto, ModelProviderConfigDto} 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 {ModelProviderOnboardingPage} from './model-provider-onboarding-page.js';\n\nconst WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';\n\ntype Scenario = 'available' | 'loading' | 'catalog-error' | 'no-providers' | 'long-names';\n\ninterface ModelProviderOnboardingStoryProps {\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 ModelProviderOnboardingStory({scenario}: ModelProviderOnboardingStoryProps) {\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=\"bg-background-subtle-base px-24 py-32\">\n <ModelProviderOnboardingPage\n workspaceId={WORKSPACE_ID}\n onSkip={() => undefined}\n onConfigured={() => undefined}\n />\n </div>\n <Toaster />\n </QueryClientProvider>\n );\n}\n\nconst meta = {\n title: 'Agent/ProviderOnboarding',\n component: ModelProviderOnboardingStory,\n parameters: {layout: 'fullscreen'},\n args: {scenario: 'available'},\n} satisfies Meta<typeof ModelProviderOnboardingStory>;\n\nexport default meta;\ntype Story = StoryObj<typeof meta>;\n\nexport const Playground: Story = {};\n\nexport const Loading: Story = {\n args: {scenario: 'loading'},\n};\n\nexport const CatalogError: Story = {\n args: {scenario: 'catalog-error'},\n};\n\nexport const NoProvidersAvailable: Story = {\n args: {scenario: 'no-providers'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Choose pi'}));\n },\n};\n\nexport const LongNames: Story = {\n args: {scenario: 'long-names'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Choose pi'}));\n },\n};\n\nexport const FilteredProviders: Story = {\n args: {scenario: 'available'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Choose pi'}));\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 NoMatchingProviders: Story = {\n args: {scenario: 'available'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Choose pi'}));\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: 'available'},\n play: async ({canvasElement}) => {\n const canvas = within(canvasElement);\n await userEvent.click(await canvas.findByRole('button', {name: 'Choose pi'}));\n await userEvent.click(await canvas.findByRole('button', {name: 'Configure Anthropic'}));\n await screen.findByLabelText('API key');\n },\n};\n\nfunction fetchForScenario(scenario: Scenario): typeof fetch {\n return (input) => {\n const url = requestUrl(input);\n const request = input instanceof Request ? input : undefined;\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(\n jsonResponse({\n providers: catalogForScenario(scenario),\n }),\n );\n }\n if (request?.method === 'PUT' && url.pathname.includes('/agent/model-providers/')) {\n return Promise.resolve(\n jsonResponse(\n providerConfig({\n provider_id: url.pathname.endsWith('/openai') ? 'openai' : 'anthropic',\n }),\n ),\n );\n }\n return Promise.resolve(jsonResponse({}, {status: 404}));\n };\n}\n\nfunction catalogForScenario(scenario: Scenario): ModelProviderCatalogEntryDto[] {\n if (scenario === 'no-providers') return [];\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 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","ModelProviderOnboardingPage","WORKSPACE_ID","CATALOG","providerEntry","id","label","default_model","models","support_status","credential_fields","unsupported_reason","ModelProviderOnboardingStory","scenario","baseUrl","fetchImpl","fetchForScenario","queryClient","defaultOptions","queries","retry","client","div","className","workspaceId","onSkip","undefined","onConfigured","meta","title","component","parameters","layout","args","Playground","Loading","CatalogError","NoProvidersAvailable","play","canvasElement","canvas","click","findByRole","name","LongNames","FilteredProviders","type","NoMatchingProviders","ConfigureModalOpen","findByLabelText","input","url","requestUrl","request","Request","Promise","pathname","endsWith","resolve","errorResponse","jsonResponse","providers","catalogForScenario","method","includes","providerConfig","provider_id","status","overrides","key","secret","kind","created_at","updated_at","URL","body","init","Response","JSON","stringify","headers","code","statusText"],"mappings":"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"}