@shipfox/client-agent 3.0.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shipfox/client-agent",
3
3
  "license": "MIT",
4
- "version": "3.0.1",
4
+ "version": "5.0.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ShipfoxHQ/shipfox.git",
@@ -32,10 +32,10 @@
32
32
  "@swc/helpers": "^0.5.17",
33
33
  "@tanstack/react-form": "^1.32.0",
34
34
  "@tanstack/react-query": "^5.101.0",
35
- "@shipfox/api-agent-dto": "6.0.0",
36
- "@shipfox/client-api": "1.0.0",
37
- "@shipfox/client-shell": "3.0.1",
38
- "@shipfox/client-ui": "3.0.1",
35
+ "@shipfox/api-agent-dto": "8.0.0",
36
+ "@shipfox/client-shell": "5.0.0",
37
+ "@shipfox/client-api": "4.0.0",
38
+ "@shipfox/client-ui": "4.0.0",
39
39
  "@shipfox/react-ui": "0.3.5"
40
40
  },
41
41
  "peerDependencies": {
@@ -44,39 +44,6 @@
44
44
  "react": "^19.0.0",
45
45
  "react-dom": "^19.0.0"
46
46
  },
47
- "devDependencies": {
48
- "@argos-ci/cli": "^5.0.0",
49
- "@argos-ci/storybook": "^6.0.0",
50
- "@storybook/addon-vitest": "^10.3.6",
51
- "@storybook/react": "^10.0.0",
52
- "@storybook/react-vite": "^10.0.0",
53
- "@tailwindcss/vite": "^4.1.13",
54
- "@testing-library/jest-dom": "^6.6.3",
55
- "@testing-library/react": "^16.3.2",
56
- "@testing-library/user-event": "^14.6.1",
57
- "@types/react": "^19.1.11",
58
- "@types/react-dom": "^19.1.7",
59
- "@tanstack/react-query": "^5.101.0",
60
- "@vitejs/plugin-react": "^6.0.0",
61
- "@vitest/browser-playwright": "^4.1.5",
62
- "happy-dom": "^20.8.3",
63
- "jsdom": "^29.0.0",
64
- "react": "^19.1.1",
65
- "react-dom": "^19.1.1",
66
- "storybook": "^10.0.0",
67
- "storybook-addon-pseudo-states": "^10.0.0",
68
- "tailwindcss": "^4.1.13",
69
- "vite": "^8.0.3",
70
- "vitest": "^4.1.5",
71
- "yaml": "^2.8.3",
72
- "@shipfox/biome": "1.8.2",
73
- "@shipfox/client-test-setup": "0.0.3",
74
- "@shipfox/swc": "1.2.6",
75
- "@shipfox/ts-config": "1.3.8",
76
- "@shipfox/typescript": "1.1.7",
77
- "@shipfox/vitest": "1.2.3",
78
- "@shipfox/workflow-document": "2.1.1"
79
- },
80
47
  "scripts": {
81
48
  "build": "shipfox-swc",
82
49
  "check": "shipfox-biome-check",
package/src/feature.ts CHANGED
@@ -8,5 +8,19 @@ export const agentFeature = defineClientFeature({
8
8
  parent: 'workspaceLayout',
9
9
  impl: '@shipfox/client-agent/routes/model-provider',
10
10
  },
11
+ {
12
+ path: '/workspaces/$wid/settings/agents',
13
+ parent: 'workspaceSettings',
14
+ impl: '@shipfox/client-agent/routes/agents-settings',
15
+ },
16
+ ],
17
+ settingsSections: [
18
+ {
19
+ id: 'settings.agents',
20
+ pathSegment: 'agents',
21
+ label: 'Agents',
22
+ icon: 'robot2Line',
23
+ order: 400,
24
+ },
11
25
  ],
12
26
  });
@@ -18,7 +18,13 @@ import type {
18
18
  UpdateModelProviderDefaultModelBodyDto,
19
19
  } from '@shipfox/api-agent-dto';
20
20
  import {apiRequest} from '@shipfox/client-api';
21
- import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
21
+ import {
22
+ type FetchQueryOptions,
23
+ queryOptions,
24
+ useMutation,
25
+ useQuery,
26
+ useQueryClient,
27
+ } from '@tanstack/react-query';
22
28
 
23
29
  export const modelProviderQueryKeys = {
24
30
  all: ['model-providers'] as const,
@@ -27,6 +33,17 @@ export const modelProviderQueryKeys = {
27
33
  [...modelProviderQueryKeys.all, 'configs', workspaceId] as const,
28
34
  };
29
35
 
36
+ type ModelProviderConfigsQueryKey =
37
+ | ReturnType<typeof modelProviderQueryKeys.configs>
38
+ | readonly ['model-providers', 'configs'];
39
+
40
+ type ModelProviderConfigsQueryOptions = FetchQueryOptions<
41
+ ListModelProviderConfigsResponseDto,
42
+ Error,
43
+ ListModelProviderConfigsResponseDto,
44
+ ModelProviderConfigsQueryKey
45
+ >;
46
+
30
47
  export async function getModelProviderCatalog({signal}: {signal?: AbortSignal} = {}) {
31
48
  return await apiRequest<ModelProviderCatalogResponseDto>('/agent/model-provider-catalog', {
32
49
  signal,
@@ -46,6 +63,18 @@ export async function listModelProviderConfigs({
46
63
  );
47
64
  }
48
65
 
66
+ export function modelProviderConfigsQueryOptions(
67
+ workspaceId: string | undefined,
68
+ ): ModelProviderConfigsQueryOptions {
69
+ return queryOptions({
70
+ queryKey: workspaceId
71
+ ? modelProviderQueryKeys.configs(workspaceId)
72
+ : ([...modelProviderQueryKeys.all, 'configs'] as const),
73
+ enabled: Boolean(workspaceId),
74
+ queryFn: ({signal}) => listModelProviderConfigs({workspaceId: workspaceId ?? '', signal}),
75
+ });
76
+ }
77
+
49
78
  export async function upsertModelProviderConfig({
50
79
  workspaceId,
51
80
  providerId,
@@ -179,13 +208,7 @@ export function useModelProviderCatalogQuery() {
179
208
  }
180
209
 
181
210
  export function useModelProviderConfigsQuery(workspaceId: string | undefined) {
182
- return useQuery({
183
- queryKey: workspaceId
184
- ? modelProviderQueryKeys.configs(workspaceId)
185
- : [...modelProviderQueryKeys.all, 'configs'],
186
- enabled: Boolean(workspaceId),
187
- queryFn: ({signal}) => listModelProviderConfigs({workspaceId: workspaceId ?? '', signal}),
188
- });
211
+ return useQuery(modelProviderConfigsQueryOptions(workspaceId));
189
212
  }
190
213
 
191
214
  export function useUpsertModelProviderConfigMutation() {
@@ -0,0 +1,14 @@
1
+ import {defineRoute, useActiveWorkspace} from '@shipfox/client-shell/runtime';
2
+ import {WorkspaceHarnessesSection, WorkspaceModelProvidersSection} from '#index.js';
3
+
4
+ export default defineRoute({
5
+ component: () => {
6
+ const workspace = useActiveWorkspace();
7
+ return (
8
+ <div className="flex flex-col gap-32">
9
+ <WorkspaceHarnessesSection workspaceId={workspace.id} />
10
+ <WorkspaceModelProvidersSection workspaceId={workspace.id} />
11
+ </div>
12
+ );
13
+ },
14
+ });
@@ -1,31 +1,34 @@
1
- const MODEL_PROVIDER_ONBOARDING_STORAGE_KEY = 'shipfox.modelProviderOnboardingDismissed';
1
+ import {createTypedBrowserStorage, localStorageOrUndefined} from '@shipfox/client-ui';
2
2
 
3
3
  type DismissedMap = Record<string, true>;
4
4
 
5
+ const dismissedStorage = createTypedBrowserStorage(localStorageOrUndefined, {
6
+ key: 'shipfox.modelProviderOnboardingDismissed',
7
+ lifetime: 'persistent',
8
+ principalScope: 'workspace',
9
+ serialize: (dismissed: DismissedMap) => JSON.stringify(dismissed),
10
+ parse: (raw) => {
11
+ try {
12
+ const parsed: unknown = JSON.parse(raw);
13
+ return isDismissedMap(parsed) ? parsed : undefined;
14
+ } catch {
15
+ return undefined;
16
+ }
17
+ },
18
+ });
19
+
5
20
  export function isModelProviderOnboardingDismissed(workspaceId: string): boolean {
6
21
  return Boolean(readDismissedMap()[workspaceId]);
7
22
  }
8
23
 
9
24
  export function dismissModelProviderOnboarding(workspaceId: string): void {
10
- if (typeof window === 'undefined') return;
11
-
12
25
  const dismissed = readDismissedMap();
13
26
  dismissed[workspaceId] = true;
14
- window.localStorage.setItem(MODEL_PROVIDER_ONBOARDING_STORAGE_KEY, JSON.stringify(dismissed));
27
+ dismissedStorage.write(dismissed);
15
28
  }
16
29
 
17
30
  function readDismissedMap(): DismissedMap {
18
- if (typeof window === 'undefined') return {};
19
-
20
- try {
21
- const raw = window.localStorage.getItem(MODEL_PROVIDER_ONBOARDING_STORAGE_KEY);
22
- if (!raw) return {};
23
- const parsed: unknown = JSON.parse(raw);
24
- if (!isDismissedMap(parsed)) return {};
25
- return parsed;
26
- } catch {
27
- return {};
28
- }
31
+ return dismissedStorage.read() ?? {};
29
32
  }
30
33
 
31
34
  function isDismissedMap(value: unknown): value is DismissedMap {