@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.
- package/.storybook/preview.tsx +2 -2
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +28 -0
- package/dist/components/form-errors.d.ts.map +1 -1
- package/dist/components/form-errors.js +3 -0
- package/dist/components/form-errors.js.map +1 -1
- package/dist/components/harness-availability.d.ts +2 -2
- package/dist/components/harness-availability.d.ts.map +1 -1
- package/dist/components/harness-availability.js +4 -3
- package/dist/components/harness-availability.js.map +1 -1
- package/dist/components/harnesses-section.d.ts.map +1 -1
- package/dist/components/harnesses-section.js +4 -2
- package/dist/components/harnesses-section.js.map +1 -1
- package/dist/components/model-provider-usage-modal.d.ts.map +1 -1
- package/dist/components/model-provider-usage-modal.js +23 -5
- package/dist/components/model-provider-usage-modal.js.map +1 -1
- package/dist/components/model-provider-usage-target.d.ts +6 -6
- package/dist/components/model-provider-usage-target.d.ts.map +1 -1
- package/dist/components/model-provider-usage-target.js +3 -1
- package/dist/components/model-provider-usage-target.js.map +1 -1
- package/dist/components/model-providers-section.d.ts.map +1 -1
- package/dist/components/model-providers-section.js +277 -170
- package/dist/components/model-providers-section.js.map +1 -1
- package/dist/components/model-providers-section.stories.d.ts +2 -1
- package/dist/components/model-providers-section.stories.d.ts.map +1 -1
- package/dist/components/model-providers-section.stories.js +45 -1
- package/dist/components/model-providers-section.stories.js.map +1 -1
- package/dist/core/harness-policy.d.ts +5 -2
- package/dist/core/harness-policy.d.ts.map +1 -1
- package/dist/core/harness-policy.js +7 -1
- package/dist/core/harness-policy.js.map +1 -1
- package/dist/core/models.d.ts +3 -0
- package/dist/core/models.d.ts.map +1 -1
- package/dist/core/models.js.map +1 -1
- package/dist/core/provider-policy.d.ts +3 -1
- package/dist/core/provider-policy.d.ts.map +1 -1
- package/dist/core/provider-policy.js +7 -0
- package/dist/core/provider-policy.js.map +1 -1
- package/dist/hooks/api/model-provider-mapper.d.ts.map +1 -1
- package/dist/hooks/api/model-provider-mapper.js +5 -1
- package/dist/hooks/api/model-provider-mapper.js.map +1 -1
- package/dist/pages/model-provider-onboarding-page.d.ts +1 -1
- package/dist/pages/model-provider-onboarding-page.d.ts.map +1 -1
- package/dist/pages/model-provider-onboarding-page.js +58 -44
- package/dist/pages/model-provider-onboarding-page.js.map +1 -1
- package/dist/pages/model-provider-onboarding-page.stories.d.ts.map +1 -1
- package/dist/pages/model-provider-onboarding-page.stories.js +5 -17
- package/dist/pages/model-provider-onboarding-page.stories.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/components/form-errors.test.ts +9 -0
- package/src/components/form-errors.ts +3 -0
- package/src/components/harness-availability.test.ts +49 -2
- package/src/components/harness-availability.ts +18 -3
- package/src/components/harnesses-section.test.tsx +51 -9
- package/src/components/harnesses-section.tsx +4 -1
- package/src/components/model-provider-usage-modal.test.tsx +23 -0
- package/src/components/model-provider-usage-modal.tsx +32 -6
- package/src/components/model-provider-usage-target.ts +9 -3
- package/src/components/model-providers-section.stories.tsx +33 -1
- package/src/components/model-providers-section.test.tsx +41 -0
- package/src/components/model-providers-section.tsx +264 -155
- package/src/core/harness-policy.ts +21 -1
- package/src/core/models.ts +3 -0
- package/src/core/provider-policy.ts +12 -0
- package/src/hooks/api/model-provider-mapper.test.ts +18 -0
- package/src/hooks/api/model-provider-mapper.ts +6 -1
- package/src/hooks/api/model-providers.test.ts +11 -0
- package/src/pages/model-provider-onboarding-page.stories.tsx +10 -14
- package/src/pages/model-provider-onboarding-page.test.tsx +133 -24
- package/src/pages/model-provider-onboarding-page.tsx +47 -34
- package/test/fixtures/model-providers.ts +22 -1
- package/tsconfig.build.tsbuildinfo +1 -1
package/.storybook/preview.tsx
CHANGED
|
@@ -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 '
|
|
8
|
-
document.fonts.load("italic 16px '
|
|
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
|
]);
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
$ shipfox-swc
|
|
2
|
-
Successfully compiled: 38 files with swc (
|
|
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;
|
|
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":"AAAA,SAAQA,QAAQ,QAAO,sBAAsB;AAgB7C,OAAO,SAASC,oCACdC,KAAc;IAEd,IAAIA,iBAAiBF,UAAU;QAC7B,OAAO;YAACG,MAAM;YAAQC,SAASC,gBAAgBH;QAAM;IACvD;IACA,IAAIA,iBAAiBI,OAAO;QAC1B,OAAO;YAACH,MAAM;YAAQC,SAASF,MAAME,OAAO;QAAA;IAC9C;IACA,OAAO;QAACD,MAAM;QAAQC,SAAS;IAAkC;AACnE;AAEA,SAASC,gBAAgBH,KAAe;IACtC,MAAMK,UAAUC,0BAA0BN,MAAMK,OAAO;IAEvD,IAAIL,MAAMO,IAAI,KAAK,8BAA8B;QAC/C,OAAO,OAAOF,QAAQH,OAAO,KAAK,WAAWG,QAAQH,OAAO,GAAGF,MAAME,OAAO;IAC9E;IACA,IAAIF,MAAMO,IAAI,KAAK,6BAA6B;QAC9C,MAAMC,eAAeC,MAAMC,OAAO,CAACL,QAAQM,aAAa,IACpDN,QAAQM,aAAa,CAACC,MAAM,CAAC,CAACC,MAAuB,OAAOA,QAAQ,YACpE,EAAE;QACN,IAAIL,aAAaM,MAAM,GAAG,GAAG;YAC3B,OAAO,CAAC,+CAA+C,EAAEN,aAAaO,IAAI,CAAC,MAAM,CAAC,CAAC;QACrF;QACA,OAAO;IACT;IACA,IAAIf,MAAMO,IAAI,KAAK,uBAAuB;QACxC,OAAO;IACT;IACA,IAAIP,MAAMO,IAAI,KAAK,kBAAkB;QACnC,OAAO;IACT;IACA,IAAIP,MAAMO,IAAI,KAAK,iBAAiB;QAClC,MAAMS,SAAS,OAAOX,QAAQW,MAAM,KAAK,WAAWX,QAAQW,MAAM,GAAGC;QACrE,MAAMC,SAAS,OAAOb,QAAQa,MAAM,KAAK,WAAWb,QAAQa,MAAM,GAAGD;QACrE,MAAME,SAASH,UAAUE,SAAS,CAAC,YAAY,EAAEF,OAAO,cAAc,EAAEE,OAAO,GAAG,CAAC,GAAG;QACtF,OAAO,GAAGC,OAAO,+GAA+G,CAAC;IACnI;IACA,IAAInB,MAAMO,IAAI,KAAK,uBAAuB;QACxC,OAAO;IACT;IACA,IAAIP,MAAMO,IAAI,KAAK,kCAAkC;QACnD,OAAO;IACT;IACA,IAAIP,MAAMO,IAAI,KAAK,aAAa;QAC9B,OAAO;IACT;IACA,IAAIP,MAAMO,IAAI,KAAK,iCAAiC;QAClD,OAAO,OAAOF,QAAQe,GAAG,KAAK,WAC1B,CAAC,gDAAgD,EAAEf,QAAQe,GAAG,CAAC,CAAC,CAAC,GACjE;IACN;IACA,IAAIpB,MAAMO,IAAI,KAAK,mBAAmB;QACpC,OAAO;IACT;IACA,IAAIP,MAAMO,IAAI,KAAK,wBAAwB;QACzC,OAAO;IACT;IACA,IAAIP,MAAMO,IAAI,KAAK,2BAA2B;QAC5C,OAAO;IACT;IACA,
|
|
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,
|
|
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
|
-
|
|
3
|
-
|
|
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
|
|
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":"
|
|
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":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/components/harnesses-section.tsx"],"sourcesContent":["import {QueryLoadError} from '@shipfox/client-ui';\nimport {IconButton} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {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":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-provider-usage-modal.d.ts","sourceRoot":"","sources":["../../src/components/model-provider-usage-modal.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"model-provider-usage-modal.d.ts","sourceRoot":"","sources":["../../src/components/model-provider-usage-modal.tsx"],"names":[],"mappings":"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
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
7
|
-
|
|
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
|
|
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;
|
|
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<
|
|
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":"
|
|
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"}
|