@shipfox/client-agent 22.0.1 → 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 +28 -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
@@ -4,8 +4,8 @@ import type {Decorator, Preview} from '@storybook/react';
4
4
 
5
5
  if (typeof document !== 'undefined' && document.fonts) {
6
6
  void Promise.all([
7
- document.fonts.load("16px 'Inter'"),
8
- document.fonts.load("italic 16px 'Inter'"),
7
+ document.fonts.load("16px 'IBM Plex Sans'"),
8
+ document.fonts.load("italic 16px 'IBM Plex Sans'"),
9
9
  document.fonts.load("16px 'Commit Mono'"),
10
10
  document.fonts.load("bold 16px 'Commit Mono'"),
11
11
  ]);
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 38 files with swc (215.49ms)
2
+ Successfully compiled: 38 files with swc (564.33ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @shipfox/client-agent
2
2
 
3
+ ## 22.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 0d3c2e3: Updates @shipfox/client-agent, @shipfox/client-onboarding, and @shipfox/client-workflows to show
8
+ managed inference providers without exposing workspace credential setup, keep workflow examples
9
+ limited to supported models, and explain managed-provider failures in workflow runs.
10
+ - b734450: Agent provider onboarding now waits for the model provider catalog before showing provider and harness selection, with a loading state and a retryable error state when the catalog cannot be loaded.
11
+ - Updated dependencies [a7fb52d]
12
+ - Updated dependencies [0d3c2e3]
13
+ - Updated dependencies [5c100d6]
14
+ - Updated dependencies [ca91dc3]
15
+ - Updated dependencies [ddcc546]
16
+ - Updated dependencies [67aab38]
17
+ - @shipfox/react-ui@2.2.0
18
+ - @shipfox/api-agent-dto@13.1.0
19
+ - @shipfox/client-shell@22.0.3
20
+ - @shipfox/client-ui@22.0.3
21
+
22
+ ## 22.0.2
23
+
24
+ ### Patch Changes
25
+
26
+ - Updated dependencies [87d9bd8]
27
+ - @shipfox/react-ui@2.1.1
28
+ - @shipfox/client-shell@22.0.2
29
+ - @shipfox/client-ui@22.0.2
30
+
3
31
  ## 22.0.1
4
32
 
5
33
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"form-errors.d.ts","sourceRoot":"","sources":["../../src/components/form-errors.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mCAAmC,GAC3C;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,GAC/B;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAC;AAYnF,wBAAgB,mCAAmC,CACjD,KAAK,EAAE,OAAO,GACb,mCAAmC,CAQrC;AAuDD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,mCAAmC,CAUjG"}
1
+ {"version":3,"file":"form-errors.d.ts","sourceRoot":"","sources":["../../src/components/form-errors.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mCAAmC,GAC3C;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,GAC/B;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAC;AAYnF,wBAAgB,mCAAmC,CACjD,KAAK,EAAE,OAAO,GACb,mCAAmC,CAQrC;AA0DD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,mCAAmC,CAUjG"}
@@ -62,6 +62,9 @@ function apiErrorMessage(error) {
62
62
  if (error.code === 'provider-not-configured') {
63
63
  return 'Configure this provider before setting it as the default.';
64
64
  }
65
+ if (error.code === 'workspace-providers-disabled') {
66
+ return typeof details.message === 'string' ? details.message : error.message;
67
+ }
65
68
  return error.message;
66
69
  }
67
70
  export function modelProviderConfigErrorField(error) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/form-errors.ts"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\n\nexport type ModelProviderConfigFormErrorMapping =\n | {kind: 'form'; message: string}\n | {kind: 'field'; field: 'slug' | 'base_url' | 'default_model'; message: string};\n\ntype ModelProviderErrorDetails = {\n message?: unknown;\n provider_id?: unknown;\n expected_keys?: unknown;\n reason?: unknown;\n target?: unknown;\n cap?: unknown;\n details?: unknown;\n};\n\nexport function modelProviderConfigErrorToFormError(\n error: unknown,\n): ModelProviderConfigFormErrorMapping {\n if (error instanceof ApiError) {\n return {kind: 'form', message: apiErrorMessage(error)};\n }\n if (error instanceof Error) {\n return {kind: 'form', message: error.message};\n }\n return {kind: 'form', message: 'Something went wrong. Try again.'};\n}\n\nfunction apiErrorMessage(error: ApiError): string {\n const details = modelProviderErrorDetails(error.details);\n\n if (error.code === 'provider-validation-failed') {\n return typeof details.message === 'string' ? details.message : error.message;\n }\n if (error.code === 'invalid-credential-fields') {\n const expectedKeys = Array.isArray(details.expected_keys)\n ? details.expected_keys.filter((key): key is string => typeof key === 'string')\n : [];\n if (expectedKeys.length > 0) {\n return `Credentials must include exactly these fields: ${expectedKeys.join(', ')}.`;\n }\n return 'Credentials do not match the fields required by this provider.';\n }\n if (error.code === 'invalid-agent-model') {\n return 'Choose a model from the models list.';\n }\n if (error.code === 'slug-collision') {\n return 'A provider with this id already exists in this workspace.';\n }\n if (error.code === 'egress-denied') {\n const target = typeof details.target === 'string' ? details.target : undefined;\n const reason = typeof details.reason === 'string' ? details.reason : undefined;\n const prefix = target && reason ? `Requests to ${target} are blocked (${reason}). ` : '';\n return `${prefix}On Shipfox Cloud the endpoint must be reachable from the internet. Use a public HTTPS URL for hosted providers.`;\n }\n if (error.code === 'invalid-header-keep') {\n return 'A kept secret header no longer exists - re-enter its value.';\n }\n if (error.code === 'stored-secret-base-url-changed') {\n return 'Re-enter stored secret values before testing against a different base URL.';\n }\n if (error.code === 'not-found') {\n return 'This custom provider no longer exists. Refresh and try again.';\n }\n if (error.code === 'workspace-secret-cap-exceeded') {\n return typeof details.cap === 'number'\n ? `This workspace has reached its secrets limit of ${details.cap}.`\n : 'This workspace has reached its secrets limit.';\n }\n if (error.code === 'value-too-large') {\n return 'A key or header value is too large to store.';\n }\n if (error.code === 'provider-unsupported') {\n return 'This provider is not supported for workspace-managed credentials.';\n }\n if (error.code === 'provider-not-configured') {\n return 'Configure this provider before setting it as the default.';\n }\n return error.message;\n}\n\nexport function modelProviderConfigErrorField(error: unknown): ModelProviderConfigFormErrorMapping {\n const mapping = modelProviderConfigErrorToFormError(error);\n if (!(error instanceof ApiError)) return mapping;\n if (error.code === 'slug-collision') return {...mapping, kind: 'field', field: 'slug'};\n if (error.code === 'egress-denied') return {...mapping, kind: 'field', field: 'base_url'};\n if (error.code === 'invalid-agent-model')\n return {...mapping, kind: 'field', field: 'default_model'};\n if (error.code === 'stored-secret-base-url-changed')\n return {...mapping, kind: 'field', field: 'base_url'};\n return mapping;\n}\n\nfunction modelProviderErrorDetails(rawDetails: unknown): ModelProviderErrorDetails {\n if (typeof rawDetails !== 'object' || rawDetails === null) return {};\n\n const payload = rawDetails as ModelProviderErrorDetails;\n if (typeof payload.details === 'object' && payload.details !== null) {\n return payload.details as ModelProviderErrorDetails;\n }\n return payload;\n}\n"],"names":["ApiError","modelProviderConfigErrorToFormError","error","kind","message","apiErrorMessage","Error","details","modelProviderErrorDetails","code","expectedKeys","Array","isArray","expected_keys","filter","key","length","join","target","undefined","reason","prefix","cap","modelProviderConfigErrorField","mapping","field","rawDetails","payload"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/components/form-errors.ts"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\n\nexport type ModelProviderConfigFormErrorMapping =\n | {kind: 'form'; message: string}\n | {kind: 'field'; field: 'slug' | 'base_url' | 'default_model'; message: string};\n\ntype ModelProviderErrorDetails = {\n message?: unknown;\n provider_id?: unknown;\n expected_keys?: unknown;\n reason?: unknown;\n target?: unknown;\n cap?: unknown;\n details?: unknown;\n};\n\nexport function modelProviderConfigErrorToFormError(\n error: unknown,\n): ModelProviderConfigFormErrorMapping {\n if (error instanceof ApiError) {\n return {kind: 'form', message: apiErrorMessage(error)};\n }\n if (error instanceof Error) {\n return {kind: 'form', message: error.message};\n }\n return {kind: 'form', message: 'Something went wrong. Try again.'};\n}\n\nfunction apiErrorMessage(error: ApiError): string {\n const details = modelProviderErrorDetails(error.details);\n\n if (error.code === 'provider-validation-failed') {\n return typeof details.message === 'string' ? details.message : error.message;\n }\n if (error.code === 'invalid-credential-fields') {\n const expectedKeys = Array.isArray(details.expected_keys)\n ? details.expected_keys.filter((key): key is string => typeof key === 'string')\n : [];\n if (expectedKeys.length > 0) {\n return `Credentials must include exactly these fields: ${expectedKeys.join(', ')}.`;\n }\n return 'Credentials do not match the fields required by this provider.';\n }\n if (error.code === 'invalid-agent-model') {\n return 'Choose a model from the models list.';\n }\n if (error.code === 'slug-collision') {\n return 'A provider with this id already exists in this workspace.';\n }\n if (error.code === 'egress-denied') {\n const target = typeof details.target === 'string' ? details.target : undefined;\n const reason = typeof details.reason === 'string' ? details.reason : undefined;\n const prefix = target && reason ? `Requests to ${target} are blocked (${reason}). ` : '';\n return `${prefix}On Shipfox Cloud the endpoint must be reachable from the internet. Use a public HTTPS URL for hosted providers.`;\n }\n if (error.code === 'invalid-header-keep') {\n return 'A kept secret header no longer exists - re-enter its value.';\n }\n if (error.code === 'stored-secret-base-url-changed') {\n return 'Re-enter stored secret values before testing against a different base URL.';\n }\n if (error.code === 'not-found') {\n return 'This custom provider no longer exists. Refresh and try again.';\n }\n if (error.code === 'workspace-secret-cap-exceeded') {\n return typeof details.cap === 'number'\n ? `This workspace has reached its secrets limit of ${details.cap}.`\n : 'This workspace has reached its secrets limit.';\n }\n if (error.code === 'value-too-large') {\n return 'A key or header value is too large to store.';\n }\n if (error.code === 'provider-unsupported') {\n return 'This provider is not supported for workspace-managed credentials.';\n }\n if (error.code === 'provider-not-configured') {\n return 'Configure this provider before setting it as the default.';\n }\n if (error.code === 'workspace-providers-disabled') {\n return typeof details.message === 'string' ? details.message : error.message;\n }\n return error.message;\n}\n\nexport function modelProviderConfigErrorField(error: unknown): ModelProviderConfigFormErrorMapping {\n const mapping = modelProviderConfigErrorToFormError(error);\n if (!(error instanceof ApiError)) return mapping;\n if (error.code === 'slug-collision') return {...mapping, kind: 'field', field: 'slug'};\n if (error.code === 'egress-denied') return {...mapping, kind: 'field', field: 'base_url'};\n if (error.code === 'invalid-agent-model')\n return {...mapping, kind: 'field', field: 'default_model'};\n if (error.code === 'stored-secret-base-url-changed')\n return {...mapping, kind: 'field', field: 'base_url'};\n return mapping;\n}\n\nfunction modelProviderErrorDetails(rawDetails: unknown): ModelProviderErrorDetails {\n if (typeof rawDetails !== 'object' || rawDetails === null) return {};\n\n const payload = rawDetails as ModelProviderErrorDetails;\n if (typeof payload.details === 'object' && payload.details !== null) {\n return payload.details as ModelProviderErrorDetails;\n }\n return payload;\n}\n"],"names":["ApiError","modelProviderConfigErrorToFormError","error","kind","message","apiErrorMessage","Error","details","modelProviderErrorDetails","code","expectedKeys","Array","isArray","expected_keys","filter","key","length","join","target","undefined","reason","prefix","cap","modelProviderConfigErrorField","mapping","field","rawDetails","payload"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { compatibleHarnessIds } from '#core/harness-policy.js';
2
- import type { HarnessDescriptor, ProviderConfig } from '#core/models.js';
3
- export declare function isHarnessAvailable(descriptor: HarnessDescriptor, configs: readonly ProviderConfig[]): boolean;
2
+ import type { HarnessDescriptor, ProviderCatalog, ProviderConfig } from '#core/models.js';
3
+ export declare function isHarnessAvailable(descriptor: HarnessDescriptor, configs: readonly ProviderConfig[], catalog?: ProviderCatalog): boolean;
4
4
  export { compatibleHarnessIds };
5
5
  //# sourceMappingURL=harness-availability.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"harness-availability.d.ts","sourceRoot":"","sources":["../../src/components/harness-availability.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,oBAAoB,EAAwB,MAAM,yBAAyB,CAAC;AACpF,OAAO,KAAK,EAAC,iBAAiB,EAAE,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAEvE,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,iBAAiB,EAC7B,OAAO,EAAE,SAAS,cAAc,EAAE,GACjC,OAAO,CAET;AAED,OAAO,EAAC,oBAAoB,EAAC,CAAC"}
1
+ {"version":3,"file":"harness-availability.d.ts","sourceRoot":"","sources":["../../src/components/harness-availability.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EAGrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAC,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAGxF,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,iBAAiB,EAC7B,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAWT;AAED,OAAO,EAAC,oBAAoB,EAAC,CAAC"}
@@ -1,6 +1,7 @@
1
- import { compatibleHarnessIds, configSupportsHarness } from '#core/harness-policy.js';
2
- export function isHarnessAvailable(descriptor, configs) {
3
- return configs.some((config)=>configSupportsHarness(config, descriptor));
1
+ import { compatibleHarnessIds, configSupportsHarness, managedModelSupportsHarness } from '#core/harness-policy.js';
2
+ import { isManagedOnlyCatalog, isSupportedProvider } from '#core/provider-policy.js';
3
+ export function isHarnessAvailable(descriptor, configs, catalog) {
4
+ return configs.some((config)=>configSupportsHarness(config, descriptor)) || isManagedOnlyCatalog(catalog) && (catalog?.providers.some((provider)=>isSupportedProvider(provider) && provider.models.some((model)=>managedModelSupportsHarness(descriptor.id, model))) ?? false);
4
5
  }
5
6
  export { compatibleHarnessIds };
6
7
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/harness-availability.ts"],"sourcesContent":["import {compatibleHarnessIds, configSupportsHarness} from '#core/harness-policy.js';\nimport type {HarnessDescriptor, ProviderConfig} from '#core/models.js';\n\nexport function isHarnessAvailable(\n descriptor: HarnessDescriptor,\n configs: readonly ProviderConfig[],\n): boolean {\n return configs.some((config) => configSupportsHarness(config, descriptor));\n}\n\nexport {compatibleHarnessIds};\n"],"names":["compatibleHarnessIds","configSupportsHarness","isHarnessAvailable","descriptor","configs","some","config"],"mappings":"AAAA,SAAQA,oBAAoB,EAAEC,qBAAqB,QAAO,0BAA0B;AAGpF,OAAO,SAASC,mBACdC,UAA6B,EAC7BC,OAAkC;IAElC,OAAOA,QAAQC,IAAI,CAAC,CAACC,SAAWL,sBAAsBK,QAAQH;AAChE;AAEA,SAAQH,oBAAoB,GAAE"}
1
+ {"version":3,"sources":["../../src/components/harness-availability.ts"],"sourcesContent":["import {\n compatibleHarnessIds,\n configSupportsHarness,\n managedModelSupportsHarness,\n} from '#core/harness-policy.js';\nimport type {HarnessDescriptor, ProviderCatalog, ProviderConfig} from '#core/models.js';\nimport {isManagedOnlyCatalog, isSupportedProvider} from '#core/provider-policy.js';\n\nexport function isHarnessAvailable(\n descriptor: HarnessDescriptor,\n configs: readonly ProviderConfig[],\n catalog?: ProviderCatalog,\n): boolean {\n return (\n configs.some((config) => configSupportsHarness(config, descriptor)) ||\n (isManagedOnlyCatalog(catalog) &&\n (catalog?.providers.some(\n (provider) =>\n isSupportedProvider(provider) &&\n provider.models.some((model) => managedModelSupportsHarness(descriptor.id, model)),\n ) ??\n false))\n );\n}\n\nexport {compatibleHarnessIds};\n"],"names":["compatibleHarnessIds","configSupportsHarness","managedModelSupportsHarness","isManagedOnlyCatalog","isSupportedProvider","isHarnessAvailable","descriptor","configs","catalog","some","config","providers","provider","models","model","id"],"mappings":"AAAA,SACEA,oBAAoB,EACpBC,qBAAqB,EACrBC,2BAA2B,QACtB,0BAA0B;AAEjC,SAAQC,oBAAoB,EAAEC,mBAAmB,QAAO,2BAA2B;AAEnF,OAAO,SAASC,mBACdC,UAA6B,EAC7BC,OAAkC,EAClCC,OAAyB;IAEzB,OACED,QAAQE,IAAI,CAAC,CAACC,SAAWT,sBAAsBS,QAAQJ,gBACtDH,qBAAqBK,YACnBA,CAAAA,SAASG,UAAUF,KAClB,CAACG,WACCR,oBAAoBQ,aACpBA,SAASC,MAAM,CAACJ,IAAI,CAAC,CAACK,QAAUZ,4BAA4BI,WAAWS,EAAE,EAAED,YAE7E,KAAI;AAEZ;AAEA,SAAQd,oBAAoB,GAAE"}
@@ -1 +1 @@
1
- {"version":3,"file":"harnesses-section.d.ts","sourceRoot":"","sources":["../../src/components/harnesses-section.tsx"],"names":[],"mappings":"AAyBA,wBAAgB,yBAAyB,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,+BAiG7E"}
1
+ {"version":3,"file":"harnesses-section.d.ts","sourceRoot":"","sources":["../../src/components/harnesses-section.tsx"],"names":[],"mappings":"AA0BA,wBAAgB,yBAAyB,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,+BAmG7E"}
@@ -11,10 +11,11 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/toolt
11
11
  import { Header, Text } from '@shipfox/react-ui/typography';
12
12
  import { useRef, useState } from 'react';
13
13
  import { DEFAULT_HARNESS, listHarnesses } from '#core/harness-policy.js';
14
- import { useModelProviderConfigsQuery, useSetDefaultHarnessMutation } from '#hooks/api/model-providers.js';
14
+ import { useModelProviderCatalogQuery, useModelProviderConfigsQuery, useSetDefaultHarnessMutation } from '#hooks/api/model-providers.js';
15
15
  import { modelProviderConfigErrorToFormError } from './form-errors.js';
16
16
  import { isHarnessAvailable } from './harness-availability.js';
17
17
  export function WorkspaceHarnessesSection({ workspaceId }) {
18
+ const catalogQuery = useModelProviderCatalogQuery();
18
19
  const configsQuery = useModelProviderConfigsQuery(workspaceId);
19
20
  const setDefaultHarness = useSetDefaultHarnessMutation();
20
21
  const activeWorkspaceIdRef = useRef(workspaceId);
@@ -23,6 +24,7 @@ export function WorkspaceHarnessesSection({ workspaceId }) {
23
24
  const [pendingDefaultHarness, setPendingDefaultHarness] = useState(null);
24
25
  const [defaultError, setDefaultError] = useState();
25
26
  const configs = configsQuery.data?.configs ?? [];
27
+ const catalog = catalogQuery.data;
26
28
  const defaultHarnessId = configsQuery.data?.defaultHarnessId ?? DEFAULT_HARNESS;
27
29
  activeWorkspaceIdRef.current = workspaceId;
28
30
  function isActiveDefaultRequest(request) {
@@ -90,7 +92,7 @@ export function WorkspaceHarnessesSection({ workspaceId }) {
90
92
  children: listHarnesses().map((harness)=>/*#__PURE__*/ _jsx(HarnessRow, {
91
93
  harness: harness,
92
94
  isDefault: harness.id === defaultHarnessId,
93
- isAvailable: isHarnessAvailable(harness, configs),
95
+ isAvailable: isHarnessAvailable(harness, configs, catalog),
94
96
  isSettingDefault: pendingDefaultHarness?.workspaceId === workspaceId,
95
97
  defaultError: defaultError?.workspaceId === workspaceId && defaultError.harnessId === harness.id ? defaultError.message : undefined,
96
98
  onSetDefault: handleSetDefault
@@ -1 +1 @@
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 {Panel, PanelBody, PanelRow} from '@shipfox/react-ui/panel';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {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\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-group\" aria-label=\"Harnesses\">\n <div className=\"flex flex-col gap-tight\">\n <Header variant=\"h3\">Harnesses</Header>\n </div>\n\n {configsQuery.isPending ? <HarnessRowsSkeleton /> : null}\n\n {configsQuery.isError && configsQuery.data === undefined ? (\n <Panel>\n <QueryLoadError query={configsQuery} subject=\"harnesses\" variant=\"panel\" />\n </Panel>\n ) : null}\n\n {configsQuery.data !== undefined ? (\n <Panel>\n <PanelBody asChild>\n <ul>\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 &&\n defaultError.harnessId === harness.id\n ? defaultError.message\n : undefined\n }\n onSetDefault={handleSetDefault}\n />\n ))}\n </ul>\n </PanelBody>\n </Panel>\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 <PanelRow asChild className=\"flex-col items-stretch gap-inline\">\n <li>\n <div className=\"flex items-center justify-between gap-cluster\">\n <div className=\"flex min-w-0 items-center gap-inline\">\n {isDefault ? (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex size-16 shrink-0 items-center justify-center\">\n <Icon\n name=\"starLine\"\n className=\"size-16 text-foreground-neutral-muted\"\n aria-hidden\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>Default 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 </PanelRow>\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 <Panel>\n <PanelBody asChild>\n <ul role=\"status\" aria-label=\"Loading harnesses\">\n {[0, 1].map((row) => (\n <PanelRow\n asChild\n className=\"justify-start gap-cluster hover:bg-background-neutral-base\"\n key={row}\n >\n <li>\n <Skeleton className=\"size-16 shrink-0\" />\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"ml-auto size-28 shrink-0\" />\n </li>\n </PanelRow>\n ))}\n </ul>\n </PanelBody>\n </Panel>\n );\n}\n"],"names":["QueryLoadError","IconButton","Callout","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","Icon","Panel","PanelBody","PanelRow","Skeleton","toast","Tooltip","TooltipContent","TooltipTrigger","Header","Text","useRef","useState","DEFAULT_HARNESS","listHarnesses","useModelProviderConfigsQuery","useSetDefaultHarnessMutation","modelProviderConfigErrorToFormError","isHarnessAvailable","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","isPending","HarnessRowsSkeleton","isError","query","subject","asChild","ul","map","HarnessRow","isDefault","isAvailable","isSettingDefault","onSetDefault","unavailableCopy","harnessUnavailableCopy","li","span","name","aria-hidden","size","bold","icon","disabled","align","onSelect","role","type","base","row"],"mappings":";AAAA,SAAQA,cAAc,QAAO,qBAAqB;AAClD,SAAQC,UAAU,QAAO,2BAA2B;AACpD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SACEC,YAAY,EACZC,mBAAmB,EACnBC,gBAAgB,EAChBC,mBAAmB,QACd,kCAAkC;AACzC,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,KAAK,EAAEC,SAAS,EAAEC,QAAQ,QAAO,0BAA0B;AACnE,SAAQC,QAAQ,QAAO,6BAA6B;AACpD,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,MAAM,EAAEC,IAAI,QAAO,+BAA+B;AAC1D,SAAQC,MAAM,EAAEC,QAAQ,QAAO,QAAQ;AACvC,SAAQC,eAAe,EAAEC,aAAa,QAAO,0BAA0B;AAEvE,SACEC,4BAA4B,EAC5BC,4BAA4B,QACvB,gCAAgC;AACvC,SAAQC,mCAAmC,QAAO,mBAAmB;AACrE,SAAQC,kBAAkB,QAAO,4BAA4B;AAE7D,OAAO,SAASC,0BAA0B,EAACC,WAAW,EAAwB;IAC5E,MAAMC,eAAeN,6BAA6BK;IAClD,MAAME,oBAAoBN;IAC1B,MAAMO,uBAAuBZ,OAAOS;IACpC,MAAMI,uBAAuBb,OAAO;IACpC,MAAMc,0BAA0Bd,OAAiD;IACjF,MAAM,CAACe,uBAAuBC,yBAAyB,GAAGf,SAGhD;IACV,MAAM,CAACgB,cAAcC,gBAAgB,GAAGjB;IAGxC,MAAMkB,UAAUT,aAAaU,IAAI,EAAED,WAAW,EAAE;IAChD,MAAME,mBAAmBX,aAAaU,IAAI,EAAEC,oBAAoBnB;IAChEU,qBAAqBU,OAAO,GAAGb;IAE/B,SAASc,uBAAuBC,OAA0C;QACxE,MAAMC,gBAAgBX,wBAAwBQ,OAAO;QACrD,OACEV,qBAAqBU,OAAO,KAAKE,QAAQf,WAAW,IACpDgB,eAAehB,gBAAgBe,QAAQf,WAAW,IAClDgB,cAAcC,EAAE,KAAKF,QAAQE,EAAE;IAEnC;IAEA,eAAeC,iBAAiBC,OAA0B;QACxD,IAAId,wBAAwBQ,OAAO,EAAEb,gBAAgBA,aAAa;QAElE,MAAMe,UAAU;YAACf;YAAaiB,IAAIb,qBAAqBS,OAAO,GAAG;QAAC;QAClET,qBAAqBS,OAAO,GAAGE,QAAQE,EAAE;QACzCZ,wBAAwBQ,OAAO,GAAGE;QAClCR,yBAAyB;YAACP;YAAaoB,WAAWD,QAAQF,EAAE;QAAA;QAC5DR,gBAAgBY;QAChB,IAAI;YACF,MAAMnB,kBAAkBoB,WAAW,CAAC;gBAClCtB;gBACAoB,WAAWD,QAAQF,EAAE;YACvB;YACA,IAAI,CAACH,uBAAuBC,UAAU;YACtC9B,MAAMsC,OAAO,CAAC,GAAGJ,QAAQK,KAAK,CAAC,2BAA2B,CAAC;QAC7D,EAAE,OAAOC,OAAO;YACd,IAAI,CAACX,uBAAuBC,UAAU;YACtC,MAAMW,SAAS7B,oCAAoC4B;YACnDhB,gBAAgB;gBACdT;gBACAoB,WAAWD,QAAQF,EAAE;gBACrBU,SAASD,OAAOC,OAAO,IAAI;YAC7B;QACF,SAAU;YACR,IAAIb,uBAAuBC,UAAU;gBACnCV,wBAAwBQ,OAAO,GAAG;gBAClCN,yBAAyB;YAC3B;QACF;IACF;IAEA,qBACE,MAACqB;QAAQC,WAAU;QAA0BC,cAAW;;0BACtD,KAACC;gBAAIF,WAAU;0BACb,cAAA,KAACxC;oBAAO2C,SAAQ;8BAAK;;;YAGtB/B,aAAagC,SAAS,iBAAG,KAACC,2BAAyB;YAEnDjC,aAAakC,OAAO,IAAIlC,aAAaU,IAAI,KAAKU,0BAC7C,KAACxC;0BACC,cAAA,KAACR;oBAAe+D,OAAOnC;oBAAcoC,SAAQ;oBAAYL,SAAQ;;iBAEjE;YAEH/B,aAAaU,IAAI,KAAKU,0BACrB,KAACxC;0BACC,cAAA,KAACC;oBAAUwD,OAAO;8BAChB,cAAA,KAACC;kCACE7C,gBAAgB8C,GAAG,CAAC,CAACrB,wBACpB,KAACsB;gCAECtB,SAASA;gCACTuB,WAAWvB,QAAQF,EAAE,KAAKL;gCAC1B+B,aAAa7C,mBAAmBqB,SAAST;gCACzCkC,kBAAkBtC,uBAAuBN,gBAAgBA;gCACzDQ,cACEA,cAAcR,gBAAgBA,eAC9BQ,aAAaY,SAAS,KAAKD,QAAQF,EAAE,GACjCT,aAAamB,OAAO,GACpBN;gCAENwB,cAAc3B;+BAXTC,QAAQF,EAAE;;;iBAiBvB;;;AAGV;AAEA,SAASwB,WAAW,EAClBtB,OAAO,EACPuB,SAAS,EACTC,WAAW,EACXC,gBAAgB,EAChBpC,YAAY,EACZqC,YAAY,EAQb;IACC,MAAMC,kBAAkBC,uBAAuBL;IAE/C,qBACE,KAAC3D;QAASuD,OAAO;QAACT,WAAU;kBAC1B,cAAA,MAACmB;;8BACC,MAACjB;oBAAIF,WAAU;;sCACb,MAACE;4BAAIF,WAAU;;gCACZa,0BACC;;sDACE,MAACxD;;8DACC,KAACE;oDAAekD,OAAO;8DACrB,cAAA,KAACW;wDAAKpB,WAAU;kEACd,cAAA,KAACjD;4DACCsE,MAAK;4DACLrB,WAAU;4DACVsB,aAAW;;;;8DAIjB,KAAChE;8DAAe;;;;sDAElB,KAAC8D;4CAAKpB,WAAU;sDAAU;;;qCAE1B;8CACJ,KAACvC;oCAAK8D,MAAK;oCAAKC,IAAI;oCAACxB,WAAU;8CAC5BV,QAAQK,KAAK;;gCAEf,CAACmB,4BACA;;sDACE,MAACzD;;8DACC,KAACE;oDAAekD,OAAO;8DACrB,cAAA,KAACW;wDAAKpB,WAAU;kEACd,cAAA,KAACjD;4DACCsE,MAAK;4DACLrB,WAAU;4DACVsB,aAAW;;;;8DAIjB,KAAChE;8DAAgB2D;;;;sDAEnB,KAACG;4CAAKpB,WAAU;sDAAWiB;;;qCAE3B;;;wBAEL,CAACJ,0BACA,MAAClE;;8CACC,KAACG;oCAAoB2D,OAAO;8CAC1B,cAAA,KAAChE;wCACC8E,MAAK;wCACLpB,SAAQ;wCACRsB,MAAK;wCACLC,UAAUX;wCACVd,cAAY,CAAC,KAAK,EAAEX,QAAQK,KAAK,CAAC,gBAAgB,CAAC;;;8CAGvD,KAAC/C;oCAAoB+E,OAAM;8CACzB,cAAA,KAAC9E;wCACC4E,MAAK;wCACLC,UAAUX,oBAAoB,CAACD;wCAC/Bc,UAAU;4CACRZ,aAAa1B;wCACf;kDACD;;;;6BAKH;;;gBAELX,6BACC,KAACjC;oBAAQmF,MAAK;oBAAQC,MAAK;8BACzB,cAAA,KAACrE;wBAAK8D,MAAK;kCAAM5C;;qBAEjB;;;;AAIZ;AAEA,SAASuC,uBAAuBL,SAAkB;IAChD,MAAMkB,OAAO;IACb,IAAI,CAAClB,WAAW,OAAOkB;IACvB,OAAO,GAAGA,KAAK,mEAAmE,CAAC;AACrF;AAEA,SAAS1B;IACP,qBACE,KAACrD;kBACC,cAAA,KAACC;YAAUwD,OAAO;sBAChB,cAAA,KAACC;gBAAGmB,MAAK;gBAAS5B,cAAW;0BAC1B;oBAAC;oBAAG;iBAAE,CAACU,GAAG,CAAC,CAACqB,oBACX,KAAC9E;wBACCuD,OAAO;wBACPT,WAAU;kCAGV,cAAA,MAACmB;;8CACC,KAAChE;oCAAS6C,WAAU;;8CACpB,KAAC7C;oCAAS6C,WAAU;;8CACpB,KAAC7C;oCAAS6C,WAAU;;;;uBALjBgC;;;;AAanB"}
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 {Panel, PanelBody, PanelRow} from '@shipfox/react-ui/panel';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport {useRef, useState} from 'react';\nimport {DEFAULT_HARNESS, listHarnesses} from '#core/harness-policy.js';\nimport type {HarnessDescriptor, HarnessId} from '#core/models.js';\nimport {\n useModelProviderCatalogQuery,\n useModelProviderConfigsQuery,\n useSetDefaultHarnessMutation,\n} from '#hooks/api/model-providers.js';\nimport {modelProviderConfigErrorToFormError} from './form-errors.js';\nimport {isHarnessAvailable} from './harness-availability.js';\n\nexport function WorkspaceHarnessesSection({workspaceId}: {workspaceId: string}) {\n const catalogQuery = useModelProviderCatalogQuery();\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 catalog = catalogQuery.data;\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-group\" aria-label=\"Harnesses\">\n <div className=\"flex flex-col gap-tight\">\n <Header variant=\"h3\">Harnesses</Header>\n </div>\n\n {configsQuery.isPending ? <HarnessRowsSkeleton /> : null}\n\n {configsQuery.isError && configsQuery.data === undefined ? (\n <Panel>\n <QueryLoadError query={configsQuery} subject=\"harnesses\" variant=\"panel\" />\n </Panel>\n ) : null}\n\n {configsQuery.data !== undefined ? (\n <Panel>\n <PanelBody asChild>\n <ul>\n {listHarnesses().map((harness) => (\n <HarnessRow\n key={harness.id}\n harness={harness}\n isDefault={harness.id === defaultHarnessId}\n isAvailable={isHarnessAvailable(harness, configs, catalog)}\n isSettingDefault={pendingDefaultHarness?.workspaceId === workspaceId}\n defaultError={\n defaultError?.workspaceId === workspaceId &&\n defaultError.harnessId === harness.id\n ? defaultError.message\n : undefined\n }\n onSetDefault={handleSetDefault}\n />\n ))}\n </ul>\n </PanelBody>\n </Panel>\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 <PanelRow asChild className=\"flex-col items-stretch gap-inline\">\n <li>\n <div className=\"flex items-center justify-between gap-cluster\">\n <div className=\"flex min-w-0 items-center gap-inline\">\n {isDefault ? (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"inline-flex size-16 shrink-0 items-center justify-center\">\n <Icon\n name=\"starLine\"\n className=\"size-16 text-foreground-neutral-muted\"\n aria-hidden\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>Default 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 </PanelRow>\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 <Panel>\n <PanelBody asChild>\n <ul role=\"status\" aria-label=\"Loading harnesses\">\n {[0, 1].map((row) => (\n <PanelRow\n asChild\n className=\"justify-start gap-cluster hover:bg-background-neutral-base\"\n key={row}\n >\n <li>\n <Skeleton className=\"size-16 shrink-0\" />\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"ml-auto size-28 shrink-0\" />\n </li>\n </PanelRow>\n ))}\n </ul>\n </PanelBody>\n </Panel>\n );\n}\n"],"names":["QueryLoadError","IconButton","Callout","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","Icon","Panel","PanelBody","PanelRow","Skeleton","toast","Tooltip","TooltipContent","TooltipTrigger","Header","Text","useRef","useState","DEFAULT_HARNESS","listHarnesses","useModelProviderCatalogQuery","useModelProviderConfigsQuery","useSetDefaultHarnessMutation","modelProviderConfigErrorToFormError","isHarnessAvailable","WorkspaceHarnessesSection","workspaceId","catalogQuery","configsQuery","setDefaultHarness","activeWorkspaceIdRef","defaultRequestSeqRef","activeDefaultRequestRef","pendingDefaultHarness","setPendingDefaultHarness","defaultError","setDefaultError","configs","data","catalog","defaultHarnessId","current","isActiveDefaultRequest","request","activeRequest","id","handleSetDefault","harness","harnessId","undefined","mutateAsync","success","label","error","mapped","message","section","className","aria-label","div","variant","isPending","HarnessRowsSkeleton","isError","query","subject","asChild","ul","map","HarnessRow","isDefault","isAvailable","isSettingDefault","onSetDefault","unavailableCopy","harnessUnavailableCopy","li","span","name","aria-hidden","size","bold","icon","disabled","align","onSelect","role","type","base","row"],"mappings":";AAAA,SAAQA,cAAc,QAAO,qBAAqB;AAClD,SAAQC,UAAU,QAAO,2BAA2B;AACpD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SACEC,YAAY,EACZC,mBAAmB,EACnBC,gBAAgB,EAChBC,mBAAmB,QACd,kCAAkC;AACzC,SAAQC,IAAI,QAAO,yBAAyB;AAC5C,SAAQC,KAAK,EAAEC,SAAS,EAAEC,QAAQ,QAAO,0BAA0B;AACnE,SAAQC,QAAQ,QAAO,6BAA6B;AACpD,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,OAAO,EAAEC,cAAc,EAAEC,cAAc,QAAO,4BAA4B;AAClF,SAAQC,MAAM,EAAEC,IAAI,QAAO,+BAA+B;AAC1D,SAAQC,MAAM,EAAEC,QAAQ,QAAO,QAAQ;AACvC,SAAQC,eAAe,EAAEC,aAAa,QAAO,0BAA0B;AAEvE,SACEC,4BAA4B,EAC5BC,4BAA4B,EAC5BC,4BAA4B,QACvB,gCAAgC;AACvC,SAAQC,mCAAmC,QAAO,mBAAmB;AACrE,SAAQC,kBAAkB,QAAO,4BAA4B;AAE7D,OAAO,SAASC,0BAA0B,EAACC,WAAW,EAAwB;IAC5E,MAAMC,eAAeP;IACrB,MAAMQ,eAAeP,6BAA6BK;IAClD,MAAMG,oBAAoBP;IAC1B,MAAMQ,uBAAuBd,OAAOU;IACpC,MAAMK,uBAAuBf,OAAO;IACpC,MAAMgB,0BAA0BhB,OAAiD;IACjF,MAAM,CAACiB,uBAAuBC,yBAAyB,GAAGjB,SAGhD;IACV,MAAM,CAACkB,cAAcC,gBAAgB,GAAGnB;IAGxC,MAAMoB,UAAUT,aAAaU,IAAI,EAAED,WAAW,EAAE;IAChD,MAAME,UAAUZ,aAAaW,IAAI;IACjC,MAAME,mBAAmBZ,aAAaU,IAAI,EAAEE,oBAAoBtB;IAChEY,qBAAqBW,OAAO,GAAGf;IAE/B,SAASgB,uBAAuBC,OAA0C;QACxE,MAAMC,gBAAgBZ,wBAAwBS,OAAO;QACrD,OACEX,qBAAqBW,OAAO,KAAKE,QAAQjB,WAAW,IACpDkB,eAAelB,gBAAgBiB,QAAQjB,WAAW,IAClDkB,cAAcC,EAAE,KAAKF,QAAQE,EAAE;IAEnC;IAEA,eAAeC,iBAAiBC,OAA0B;QACxD,IAAIf,wBAAwBS,OAAO,EAAEf,gBAAgBA,aAAa;QAElE,MAAMiB,UAAU;YAACjB;YAAamB,IAAId,qBAAqBU,OAAO,GAAG;QAAC;QAClEV,qBAAqBU,OAAO,GAAGE,QAAQE,EAAE;QACzCb,wBAAwBS,OAAO,GAAGE;QAClCT,yBAAyB;YAACR;YAAasB,WAAWD,QAAQF,EAAE;QAAA;QAC5DT,gBAAgBa;QAChB,IAAI;YACF,MAAMpB,kBAAkBqB,WAAW,CAAC;gBAClCxB;gBACAsB,WAAWD,QAAQF,EAAE;YACvB;YACA,IAAI,CAACH,uBAAuBC,UAAU;YACtCjC,MAAMyC,OAAO,CAAC,GAAGJ,QAAQK,KAAK,CAAC,2BAA2B,CAAC;QAC7D,EAAE,OAAOC,OAAO;YACd,IAAI,CAACX,uBAAuBC,UAAU;YACtC,MAAMW,SAAS/B,oCAAoC8B;YACnDjB,gBAAgB;gBACdV;gBACAsB,WAAWD,QAAQF,EAAE;gBACrBU,SAASD,OAAOC,OAAO,IAAI;YAC7B;QACF,SAAU;YACR,IAAIb,uBAAuBC,UAAU;gBACnCX,wBAAwBS,OAAO,GAAG;gBAClCP,yBAAyB;YAC3B;QACF;IACF;IAEA,qBACE,MAACsB;QAAQC,WAAU;QAA0BC,cAAW;;0BACtD,KAACC;gBAAIF,WAAU;0BACb,cAAA,KAAC3C;oBAAO8C,SAAQ;8BAAK;;;YAGtBhC,aAAaiC,SAAS,iBAAG,KAACC,2BAAyB;YAEnDlC,aAAamC,OAAO,IAAInC,aAAaU,IAAI,KAAKW,0BAC7C,KAAC3C;0BACC,cAAA,KAACR;oBAAekE,OAAOpC;oBAAcqC,SAAQ;oBAAYL,SAAQ;;iBAEjE;YAEHhC,aAAaU,IAAI,KAAKW,0BACrB,KAAC3C;0BACC,cAAA,KAACC;oBAAU2D,OAAO;8BAChB,cAAA,KAACC;kCACEhD,gBAAgBiD,GAAG,CAAC,CAACrB,wBACpB,KAACsB;gCAECtB,SAASA;gCACTuB,WAAWvB,QAAQF,EAAE,KAAKL;gCAC1B+B,aAAa/C,mBAAmBuB,SAASV,SAASE;gCAClDiC,kBAAkBvC,uBAAuBP,gBAAgBA;gCACzDS,cACEA,cAAcT,gBAAgBA,eAC9BS,aAAaa,SAAS,KAAKD,QAAQF,EAAE,GACjCV,aAAaoB,OAAO,GACpBN;gCAENwB,cAAc3B;+BAXTC,QAAQF,EAAE;;;iBAiBvB;;;AAGV;AAEA,SAASwB,WAAW,EAClBtB,OAAO,EACPuB,SAAS,EACTC,WAAW,EACXC,gBAAgB,EAChBrC,YAAY,EACZsC,YAAY,EAQb;IACC,MAAMC,kBAAkBC,uBAAuBL;IAE/C,qBACE,KAAC9D;QAAS0D,OAAO;QAACT,WAAU;kBAC1B,cAAA,MAACmB;;8BACC,MAACjB;oBAAIF,WAAU;;sCACb,MAACE;4BAAIF,WAAU;;gCACZa,0BACC;;sDACE,MAAC3D;;8DACC,KAACE;oDAAeqD,OAAO;8DACrB,cAAA,KAACW;wDAAKpB,WAAU;kEACd,cAAA,KAACpD;4DACCyE,MAAK;4DACLrB,WAAU;4DACVsB,aAAW;;;;8DAIjB,KAACnE;8DAAe;;;;sDAElB,KAACiE;4CAAKpB,WAAU;sDAAU;;;qCAE1B;8CACJ,KAAC1C;oCAAKiE,MAAK;oCAAKC,IAAI;oCAACxB,WAAU;8CAC5BV,QAAQK,KAAK;;gCAEf,CAACmB,4BACA;;sDACE,MAAC5D;;8DACC,KAACE;oDAAeqD,OAAO;8DACrB,cAAA,KAACW;wDAAKpB,WAAU;kEACd,cAAA,KAACpD;4DACCyE,MAAK;4DACLrB,WAAU;4DACVsB,aAAW;;;;8DAIjB,KAACnE;8DAAgB8D;;;;sDAEnB,KAACG;4CAAKpB,WAAU;sDAAWiB;;;qCAE3B;;;wBAEL,CAACJ,0BACA,MAACrE;;8CACC,KAACG;oCAAoB8D,OAAO;8CAC1B,cAAA,KAACnE;wCACCiF,MAAK;wCACLpB,SAAQ;wCACRsB,MAAK;wCACLC,UAAUX;wCACVd,cAAY,CAAC,KAAK,EAAEX,QAAQK,KAAK,CAAC,gBAAgB,CAAC;;;8CAGvD,KAAClD;oCAAoBkF,OAAM;8CACzB,cAAA,KAACjF;wCACC+E,MAAK;wCACLC,UAAUX,oBAAoB,CAACD;wCAC/Bc,UAAU;4CACRZ,aAAa1B;wCACf;kDACD;;;;6BAKH;;;gBAELZ,6BACC,KAACnC;oBAAQsF,MAAK;oBAAQC,MAAK;8BACzB,cAAA,KAACxE;wBAAKiE,MAAK;kCAAM7C;;qBAEjB;;;;AAIZ;AAEA,SAASwC,uBAAuBL,SAAkB;IAChD,MAAMkB,OAAO;IACb,IAAI,CAAClB,WAAW,OAAOkB;IACvB,OAAO,GAAGA,KAAK,mEAAmE,CAAC;AACrF;AAEA,SAAS1B;IACP,qBACE,KAACxD;kBACC,cAAA,KAACC;YAAU2D,OAAO;sBAChB,cAAA,KAACC;gBAAGmB,MAAK;gBAAS5B,cAAW;0BAC1B;oBAAC;oBAAG;iBAAE,CAACU,GAAG,CAAC,CAACqB,oBACX,KAACjF;wBACC0D,OAAO;wBACPT,WAAU;kCAGV,cAAA,MAACmB;;8CACC,KAACnE;oCAASgD,WAAU;;8CACpB,KAAChD;oCAASgD,WAAU;;8CACpB,KAAChD;oCAASgD,WAAU;;;;uBALjBgC;;;;AAanB"}
@@ -1 +1 @@
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
+ {"version":3,"file":"model-provider-usage-modal.d.ts","sourceRoot":"","sources":["../../src/components/model-provider-usage-modal.tsx"],"names":[],"mappings":"AA8BA,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,+BA+MA"}
@@ -7,7 +7,7 @@ import { Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, ModalTitle }
7
7
  import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/tooltip';
8
8
  import { Code, Text } from '@shipfox/react-ui/typography';
9
9
  import { useEffect, useMemo, useRef, useState } from 'react';
10
- import { DEFAULT_HARNESS, getHarness, listHarnesses } from '#core/harness-policy.js';
10
+ import { DEFAULT_HARNESS, getHarness, listHarnesses, managedModelSupportsHarness } 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';
@@ -25,6 +25,8 @@ export function ModelProviderUsageModal({ target, initialModel, open, onOpenChan
25
25
  if (!target) return;
26
26
  const nextCompatibleHarnessIds = compatibleHarnessIds({
27
27
  isCustom: target.isCustom,
28
+ isManaged: target.isManaged,
29
+ models: target.models,
28
30
  providerId: target.id
29
31
  });
30
32
  setSelectedHarness(selectInitialHarness(nextCompatibleHarnessIds, workspaceDefaultHarnessId));
@@ -34,6 +36,8 @@ export function ModelProviderUsageModal({ target, initialModel, open, onOpenChan
34
36
  ]);
35
37
  const compatibleIds = useMemo(()=>target ? compatibleHarnessIds({
36
38
  isCustom: target.isCustom,
39
+ isManaged: target.isManaged,
40
+ models: target.models,
37
41
  providerId: target.id
38
42
  }) : [], [
39
43
  target
@@ -44,10 +48,24 @@ export function ModelProviderUsageModal({ target, initialModel, open, onOpenChan
44
48
  })), [
45
49
  compatibleIds
46
50
  ]);
47
- const modelOptions = useMemo(()=>target?.models.map((model)=>({
51
+ const compatibleModels = useMemo(()=>{
52
+ if (!target) return [];
53
+ return target.isManaged ? target.models.filter((model)=>managedModelSupportsHarness(selectedHarness, model)) : target.models;
54
+ }, [
55
+ selectedHarness,
56
+ target
57
+ ]);
58
+ const modelOptions = useMemo(()=>compatibleModels.map((model)=>({
48
59
  value: model.id,
49
60
  label: model.label
50
- })) ?? [], [
61
+ })), [
62
+ compatibleModels
63
+ ]);
64
+ useEffect(()=>{
65
+ if (!target || compatibleModels.length === 0) return;
66
+ setSelectedModel((current)=>compatibleModels.some((model)=>model.id === current) ? current : compatibleModels[0]?.id ?? '');
67
+ }, [
68
+ compatibleModels,
51
69
  target
52
70
  ]);
53
71
  const example = target ? buildAgentWorkflowExample({
@@ -220,13 +238,13 @@ export function ModelProviderUsageModal({ target, initialModel, open, onOpenChan
220
238
  bold: true,
221
239
  children: [
222
240
  "Available models (",
223
- target.models.length,
241
+ compatibleModels.length,
224
242
  ")"
225
243
  ]
226
244
  }),
227
245
  /*#__PURE__*/ _jsx("ul", {
228
246
  className: "rounded-8 border border-border-neutral-base",
229
- children: target.models.map((model)=>/*#__PURE__*/ _jsx(ModelProviderModelRow, {
247
+ children: compatibleModels.map((model)=>/*#__PURE__*/ _jsx(ModelProviderModelRow, {
230
248
  label: model.label,
231
249
  id: model.id
232
250
  }, model.id))
@@ -1 +1 @@
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-tight\">\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-section\">\n {compatibleIds.length === 1 ? (\n <div className=\"flex flex-col gap-cluster\">\n <div className=\"flex min-h-40 items-center justify-between gap-cluster rounded-8 border border-border-neutral-base px-row py-row\">\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-cluster sm:flex-row sm:gap-cluster\">\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-inline\">\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-inline\">\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-tight px-row py-row 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-inline\"\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
+ {"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 {\n DEFAULT_HARNESS,\n getHarness,\n listHarnesses,\n managedModelSupportsHarness,\n} 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 isManaged: target.isManaged,\n models: target.models,\n providerId: target.id,\n });\n setSelectedHarness(selectInitialHarness(nextCompatibleHarnessIds, workspaceDefaultHarnessId));\n }, [target, workspaceDefaultHarnessId]);\n\n const compatibleIds = useMemo(\n () =>\n target\n ? compatibleHarnessIds({\n isCustom: target.isCustom,\n isManaged: target.isManaged,\n models: target.models,\n providerId: target.id,\n })\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 compatibleModels = useMemo(() => {\n if (!target) return [];\n return target.isManaged\n ? target.models.filter((model) => managedModelSupportsHarness(selectedHarness, model))\n : target.models;\n }, [selectedHarness, target]);\n const modelOptions = useMemo(\n () => compatibleModels.map((model) => ({value: model.id, label: model.label})),\n [compatibleModels],\n );\n useEffect(() => {\n if (!target || compatibleModels.length === 0) return;\n setSelectedModel((current) =>\n compatibleModels.some((model) => model.id === current)\n ? current\n : (compatibleModels[0]?.id ?? ''),\n );\n }, [compatibleModels, target]);\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-tight\">\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-section\">\n {compatibleIds.length === 1 ? (\n <div className=\"flex flex-col gap-cluster\">\n <div className=\"flex min-h-40 items-center justify-between gap-cluster rounded-8 border border-border-neutral-base px-row py-row\">\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-cluster sm:flex-row sm:gap-cluster\">\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-inline\">\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-inline\">\n <Text size=\"sm\" bold>\n Available models ({compatibleModels.length})\n </Text>\n <ul className=\"rounded-8 border border-border-neutral-base\">\n {compatibleModels.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-tight px-row py-row 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-inline\"\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","managedModelSupportsHarness","buildAgentWorkflowExample","compatibleHarnessIds","WORKFLOW_EXAMPLE_FILENAME","ModelProviderUsageModal","target","initialModel","open","onOpenChange","closeFocusTarget","workspaceDefaultHarnessId","selectedModel","setSelectedModel","selectedHarness","setSelectedHarness","defaultModel","models","id","nextCompatibleHarnessIds","isCustom","isManaged","providerId","selectInitialHarness","compatibleIds","harnessOptions","map","harnessId","value","label","compatibleModels","filter","model","modelOptions","length","current","some","example","harness","data","language","filename","code","handleOpenChange","nextOpen","window","setTimeout","focus","aria-describedby","undefined","className","div","size","aria-hidden","as","variant","aria-label","options","onValueChange","placeholder","searchPlaceholder","emptyState","isHarness","item","syntaxHighlighting","highlightedLineRange","bold","ul","ModelProviderModelRow","type","onClick","includes","descriptor","copyState","setCopyState","timeoutRef","copy","text","onCopy","setTemporaryCopyState","clearTimeout","state","handleCopy","li","asChild","button","side","align","span","role"],"mappings":"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"}
@@ -1,14 +1,14 @@
1
- import type { CustomProviderConfig, SupportedProvider } from '#core/models.js';
1
+ import type { AgentModel, 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: ReadonlyArray<{
7
- id: string;
8
- label: string;
9
- }>;
6
+ isManaged: boolean;
7
+ models: ReadonlyArray<AgentModel>;
10
8
  defaultModel: string | null;
11
9
  }
12
- export declare function usageTargetFromCatalogEntry(entry: SupportedProvider): ModelProviderUsageTarget;
10
+ export declare function usageTargetFromCatalogEntry(entry: SupportedProvider, options?: {
11
+ isManaged?: boolean;
12
+ }): ModelProviderUsageTarget;
13
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,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
+ {"version":3,"file":"model-provider-usage-target.d.ts","sourceRoot":"","sources":["../../src/components/model-provider-usage-target.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAE,oBAAoB,EAAE,iBAAiB,EAAC,MAAM,iBAAiB,CAAC;AAEzF,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,iBAAiB,EACxB,OAAO,GAAE;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAM,GAClC,wBAAwB,CAU1B;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,oBAAoB,GAC3B,wBAAwB,CAU1B"}
@@ -1,9 +1,10 @@
1
- export function usageTargetFromCatalogEntry(entry) {
1
+ export function usageTargetFromCatalogEntry(entry, options = {}) {
2
2
  const provider = entry;
3
3
  return {
4
4
  id: provider.id,
5
5
  label: provider.label,
6
6
  isCustom: false,
7
+ isManaged: options.isManaged ?? false,
7
8
  models: provider.models,
8
9
  defaultModel: provider.defaultModel
9
10
  };
@@ -14,6 +15,7 @@ export function usageTargetFromCustomConfig(config) {
14
15
  id: provider.providerId,
15
16
  label: provider.displayName,
16
17
  isCustom: true,
18
+ isManaged: false,
17
19
  models: provider.models,
18
20
  defaultModel: provider.defaultModel
19
21
  };
@@ -1 +1 @@
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
+ {"version":3,"sources":["../../src/components/model-provider-usage-target.ts"],"sourcesContent":["import type {AgentModel, CustomProviderConfig, SupportedProvider} from '#core/models.js';\n\nexport interface ModelProviderUsageTarget {\n id: string;\n label: string;\n isCustom: boolean;\n isManaged: boolean;\n models: ReadonlyArray<AgentModel>;\n defaultModel: string | null;\n}\n\nexport function usageTargetFromCatalogEntry(\n entry: SupportedProvider,\n options: {isManaged?: boolean} = {},\n): ModelProviderUsageTarget {\n const provider = entry;\n return {\n id: provider.id,\n label: provider.label,\n isCustom: false,\n isManaged: options.isManaged ?? 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 isManaged: false,\n models: provider.models,\n defaultModel: provider.defaultModel,\n };\n}\n"],"names":["usageTargetFromCatalogEntry","entry","options","provider","id","label","isCustom","isManaged","models","defaultModel","usageTargetFromCustomConfig","config","providerId","displayName"],"mappings":"AAWA,OAAO,SAASA,4BACdC,KAAwB,EACxBC,UAAiC,CAAC,CAAC;IAEnC,MAAMC,WAAWF;IACjB,OAAO;QACLG,IAAID,SAASC,EAAE;QACfC,OAAOF,SAASE,KAAK;QACrBC,UAAU;QACVC,WAAWL,QAAQK,SAAS,IAAI;QAChCC,QAAQL,SAASK,MAAM;QACvBC,cAAcN,SAASM,YAAY;IACrC;AACF;AAEA,OAAO,SAASC,4BACdC,MAA4B;IAE5B,MAAMR,WAAWQ;IACjB,OAAO;QACLP,IAAID,SAASS,UAAU;QACvBP,OAAOF,SAASU,WAAW;QAC3BP,UAAU;QACVC,WAAW;QACXC,QAAQL,SAASK,MAAM;QACvBC,cAAcN,SAASM,YAAY;IACrC;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"model-providers-section.d.ts","sourceRoot":"","sources":["../../src/components/model-providers-section.tsx"],"names":[],"mappings":"AAqEA,wBAAgB,8BAA8B,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,+BAuUlF"}
1
+ {"version":3,"file":"model-providers-section.d.ts","sourceRoot":"","sources":["../../src/components/model-providers-section.tsx"],"names":[],"mappings":"AA+IA,wBAAgB,8BAA8B,CAAC,EAAC,WAAW,EAAC,EAAE;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,+BA0WlF"}