@shipfox/client-agent 4.0.0 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +59 -0
  3. package/dist/components/available-provider-card.d.ts +2 -2
  4. package/dist/components/available-provider-card.d.ts.map +1 -1
  5. package/dist/components/available-provider-card.js.map +1 -1
  6. package/dist/components/available-providers-grid.d.ts +2 -2
  7. package/dist/components/available-providers-grid.d.ts.map +1 -1
  8. package/dist/components/available-providers-grid.js +1 -1
  9. package/dist/components/available-providers-grid.js.map +1 -1
  10. package/dist/components/change-default-model-form.d.ts +3 -4
  11. package/dist/components/change-default-model-form.d.ts.map +1 -1
  12. package/dist/components/change-default-model-form.js +2 -4
  13. package/dist/components/change-default-model-form.js.map +1 -1
  14. package/dist/components/custom-model-provider-api-options.d.ts +3 -3
  15. package/dist/components/custom-model-provider-api-options.d.ts.map +1 -1
  16. package/dist/components/custom-model-provider-api-options.js.map +1 -1
  17. package/dist/components/custom-model-provider-form.d.ts +2 -2
  18. package/dist/components/custom-model-provider-form.d.ts.map +1 -1
  19. package/dist/components/custom-model-provider-form.js +12 -10
  20. package/dist/components/custom-model-provider-form.js.map +1 -1
  21. package/dist/components/custom-model-provider-form.stories.d.ts.map +1 -1
  22. package/dist/components/custom-model-provider-form.stories.js +11 -11
  23. package/dist/components/custom-model-provider-form.stories.js.map +1 -1
  24. package/dist/components/custom-model-provider-payload.d.ts +9 -9
  25. package/dist/components/custom-model-provider-payload.d.ts.map +1 -1
  26. package/dist/components/custom-model-provider-payload.js +42 -26
  27. package/dist/components/custom-model-provider-payload.js.map +1 -1
  28. package/dist/components/custom-model-provider-slug.d.ts +1 -1
  29. package/dist/components/custom-model-provider-slug.d.ts.map +1 -1
  30. package/dist/components/custom-model-provider-slug.js +3 -3
  31. package/dist/components/custom-model-provider-slug.js.map +1 -1
  32. package/dist/components/default-model-field.d.ts +2 -2
  33. package/dist/components/default-model-field.d.ts.map +1 -1
  34. package/dist/components/default-model-field.js +1 -1
  35. package/dist/components/default-model-field.js.map +1 -1
  36. package/dist/components/harness-availability.d.ts +4 -7
  37. package/dist/components/harness-availability.d.ts.map +1 -1
  38. package/dist/components/harness-availability.js +2 -11
  39. package/dist/components/harness-availability.js.map +1 -1
  40. package/dist/components/harnesses-section.d.ts.map +1 -1
  41. package/dist/components/harnesses-section.js +4 -6
  42. package/dist/components/harnesses-section.js.map +1 -1
  43. package/dist/components/model-provider-usage-modal.d.ts +2 -2
  44. package/dist/components/model-provider-usage-modal.d.ts.map +1 -1
  45. package/dist/components/model-provider-usage-modal.js +4 -4
  46. package/dist/components/model-provider-usage-modal.js.map +1 -1
  47. package/dist/components/model-provider-usage-modal.stories.d.ts.map +1 -1
  48. package/dist/components/model-provider-usage-modal.stories.js +14 -16
  49. package/dist/components/model-provider-usage-modal.stories.js.map +1 -1
  50. package/dist/components/model-provider-usage-target.d.ts +5 -5
  51. package/dist/components/model-provider-usage-target.d.ts.map +1 -1
  52. package/dist/components/model-provider-usage-target.js +10 -8
  53. package/dist/components/model-provider-usage-target.js.map +1 -1
  54. package/dist/components/model-providers-section.d.ts.map +1 -1
  55. package/dist/components/model-providers-section.js +112 -94
  56. package/dist/components/model-providers-section.js.map +1 -1
  57. package/dist/components/model-providers-section.stories.js +8 -4
  58. package/dist/components/model-providers-section.stories.js.map +1 -1
  59. package/dist/components/test-and-save-form.d.ts +3 -3
  60. package/dist/components/test-and-save-form.d.ts.map +1 -1
  61. package/dist/components/test-and-save-form.js +7 -7
  62. package/dist/components/test-and-save-form.js.map +1 -1
  63. package/dist/core/harness-policy.d.ts +11 -0
  64. package/dist/core/harness-policy.d.ts.map +1 -0
  65. package/dist/core/harness-policy.js +71 -0
  66. package/dist/core/harness-policy.js.map +1 -0
  67. package/dist/core/model-provider-management-reducer.d.ts +51 -0
  68. package/dist/core/model-provider-management-reducer.d.ts.map +1 -0
  69. package/dist/core/model-provider-management-reducer.js +43 -0
  70. package/dist/core/model-provider-management-reducer.js.map +1 -0
  71. package/dist/core/models.d.ts +120 -0
  72. package/dist/core/models.d.ts.map +1 -0
  73. package/dist/core/models.js +3 -0
  74. package/dist/core/models.js.map +1 -0
  75. package/dist/core/onboarding-reducer.d.ts +36 -0
  76. package/dist/core/onboarding-reducer.d.ts.map +1 -0
  77. package/dist/core/onboarding-reducer.js +54 -0
  78. package/dist/core/onboarding-reducer.js.map +1 -0
  79. package/dist/core/provider-policy.d.ts +9 -0
  80. package/dist/core/provider-policy.d.ts.map +1 -0
  81. package/dist/core/provider-policy.js +37 -0
  82. package/dist/core/provider-policy.js.map +1 -0
  83. package/dist/feature.d.ts +18 -0
  84. package/dist/feature.d.ts.map +1 -1
  85. package/dist/feature.js +16 -1
  86. package/dist/feature.js.map +1 -1
  87. package/dist/hooks/api/model-provider-command-mapper.d.ts +11 -0
  88. package/dist/hooks/api/model-provider-command-mapper.d.ts.map +1 -0
  89. package/dist/hooks/api/model-provider-command-mapper.js +144 -0
  90. package/dist/hooks/api/model-provider-command-mapper.js.map +1 -0
  91. package/dist/hooks/api/model-provider-mapper.d.ts +11 -0
  92. package/dist/hooks/api/model-provider-mapper.d.ts.map +1 -0
  93. package/dist/hooks/api/model-provider-mapper.js +94 -0
  94. package/dist/hooks/api/model-provider-mapper.js.map +1 -0
  95. package/dist/hooks/api/model-providers.d.ts +64 -294
  96. package/dist/hooks/api/model-providers.d.ts.map +1 -1
  97. package/dist/hooks/api/model-providers.js +65 -48
  98. package/dist/hooks/api/model-providers.js.map +1 -1
  99. package/dist/pages/model-provider-onboarding-page.d.ts.map +1 -1
  100. package/dist/pages/model-provider-onboarding-page.js +57 -45
  101. package/dist/pages/model-provider-onboarding-page.js.map +1 -1
  102. package/dist/routes/agents-settings.d.ts +5 -0
  103. package/dist/routes/agents-settings.d.ts.map +1 -0
  104. package/dist/routes/agents-settings.js +21 -0
  105. package/dist/routes/agents-settings.js.map +1 -0
  106. package/dist/routes/inputs.d.ts +4 -0
  107. package/dist/routes/inputs.d.ts.map +1 -0
  108. package/dist/routes/inputs.js +12 -0
  109. package/dist/routes/inputs.js.map +1 -0
  110. package/dist/routes/model-provider.d.ts.map +1 -1
  111. package/dist/routes/model-provider.js +4 -5
  112. package/dist/routes/model-provider.js.map +1 -1
  113. package/dist/tsconfig.test.tsbuildinfo +1 -1
  114. package/package.json +9 -10
  115. package/src/components/available-provider-card.tsx +2 -2
  116. package/src/components/available-providers-grid.tsx +3 -3
  117. package/src/components/change-default-model-form.tsx +5 -6
  118. package/src/components/custom-model-provider-api-options.ts +3 -3
  119. package/src/components/custom-model-provider-form.stories.tsx +13 -13
  120. package/src/components/custom-model-provider-form.tsx +19 -12
  121. package/src/components/custom-model-provider-payload.test.ts +22 -22
  122. package/src/components/custom-model-provider-payload.ts +69 -54
  123. package/src/components/custom-model-provider-slug.test.ts +1 -1
  124. package/src/components/custom-model-provider-slug.ts +6 -3
  125. package/src/components/default-model-field.tsx +5 -5
  126. package/src/components/harness-availability.test.ts +13 -10
  127. package/src/components/harness-availability.ts +4 -28
  128. package/src/components/harnesses-section.tsx +7 -11
  129. package/src/components/model-provider-usage-modal.stories.tsx +18 -23
  130. package/src/components/model-provider-usage-modal.test.tsx +35 -7
  131. package/src/components/model-provider-usage-modal.tsx +12 -16
  132. package/src/components/model-provider-usage-target.ts +15 -18
  133. package/src/components/model-providers-section.stories.tsx +4 -1
  134. package/src/components/model-providers-section.tsx +112 -125
  135. package/src/components/test-and-save-form.tsx +13 -17
  136. package/src/core/harness-policy.test.ts +15 -0
  137. package/src/core/harness-policy.ts +83 -0
  138. package/src/core/model-provider-management-reducer.test.ts +59 -0
  139. package/src/core/model-provider-management-reducer.ts +72 -0
  140. package/src/core/models.ts +143 -0
  141. package/src/core/onboarding-reducer.test.ts +44 -0
  142. package/src/core/onboarding-reducer.ts +64 -0
  143. package/src/core/provider-policy.ts +53 -0
  144. package/src/feature.ts +17 -1
  145. package/src/hooks/api/model-provider-command-mapper.ts +122 -0
  146. package/src/hooks/api/model-provider-mapper.test.ts +27 -0
  147. package/src/hooks/api/model-provider-mapper.ts +120 -0
  148. package/src/hooks/api/model-providers.test.ts +15 -15
  149. package/src/hooks/api/model-providers.ts +175 -87
  150. package/src/pages/model-provider-onboarding-page.tsx +62 -56
  151. package/src/routes/agents-settings.tsx +14 -0
  152. package/src/routes/inputs.test.ts +11 -0
  153. package/src/routes/inputs.ts +9 -0
  154. package/src/routes/model-provider.tsx +4 -3
  155. package/test/fixtures/model-providers.ts +1 -1
  156. package/tsconfig.build.tsbuildinfo +1 -1
  157. package/vercel.json +5 -0
  158. package/dist/components/provider-search.d.ts +0 -4
  159. package/dist/components/provider-search.d.ts.map +0 -1
  160. package/dist/components/provider-search.js +0 -13
  161. package/dist/components/provider-search.js.map +0 -1
  162. package/dist/components/supported-model-provider-catalog-entry.d.ts +0 -8
  163. package/dist/components/supported-model-provider-catalog-entry.d.ts.map +0 -1
  164. package/dist/components/supported-model-provider-catalog-entry.js +0 -9
  165. package/dist/components/supported-model-provider-catalog-entry.js.map +0 -1
  166. package/src/components/provider-search.test.ts +0 -45
  167. package/src/components/provider-search.ts +0 -18
  168. package/src/components/supported-model-provider-catalog-entry.ts +0 -19
@@ -0,0 +1,120 @@
1
+ import type {
2
+ CustomModelProviderConfigDto,
3
+ ListModelProviderConfigsResponseDto,
4
+ ModelProviderCatalogEntryDto,
5
+ ModelProviderCatalogResponseDto,
6
+ ModelProviderConfigDto,
7
+ ModelProviderConfigResponseDto,
8
+ SetDefaultHarnessResponseDto,
9
+ SetDefaultModelProviderResponseDto,
10
+ } from '@shipfox/api-agent-dto';
11
+ import type {
12
+ AgentModel,
13
+ BuiltinProviderConfig,
14
+ CustomProviderConfig,
15
+ DefaultHarnessSelection,
16
+ DefaultModelProviderSelection,
17
+ ProviderCatalog,
18
+ ProviderCatalogEntry,
19
+ ProviderConfig,
20
+ ProviderConfiguration,
21
+ } from '#core/models.js';
22
+
23
+ export function toProviderCatalog(response: ModelProviderCatalogResponseDto): ProviderCatalog {
24
+ return {providers: response.providers.map(toProviderCatalogEntry)};
25
+ }
26
+
27
+ export function toProviderCatalogEntry(entry: ModelProviderCatalogEntryDto): ProviderCatalogEntry {
28
+ if (entry.support_status === 'unsupported') {
29
+ return {
30
+ kind: 'unsupported',
31
+ id: entry.id,
32
+ label: entry.label,
33
+ unsupportedReason: entry.unsupported_reason ?? 'Unsupported provider',
34
+ };
35
+ }
36
+ return {
37
+ kind: 'supported',
38
+ id: entry.id,
39
+ label: entry.label,
40
+ defaultModel: entry.default_model,
41
+ credentialFields: entry.credential_fields.map((field) => ({
42
+ key: field.key,
43
+ label: field.label,
44
+ secret: field.secret,
45
+ })),
46
+ models: entry.models.map(toAgentModel),
47
+ };
48
+ }
49
+
50
+ export function toProviderConfiguration(
51
+ response: ListModelProviderConfigsResponseDto,
52
+ ): ProviderConfiguration {
53
+ return {
54
+ configs: response.configs.map(toProviderConfig),
55
+ defaultHarnessId: response.default_harness_id,
56
+ defaultProviderId: response.default_provider_id,
57
+ };
58
+ }
59
+
60
+ export function toDefaultModelProviderSelection(
61
+ response: SetDefaultModelProviderResponseDto,
62
+ ): DefaultModelProviderSelection {
63
+ return {defaultProviderId: response.default_provider_id};
64
+ }
65
+
66
+ export function toDefaultHarnessSelection(
67
+ response: SetDefaultHarnessResponseDto,
68
+ ): DefaultHarnessSelection {
69
+ return {defaultHarnessId: response.default_harness_id};
70
+ }
71
+
72
+ export function toProviderConfig(config: ModelProviderConfigResponseDto): ProviderConfig {
73
+ return config.kind === 'builtin'
74
+ ? toBuiltinProviderConfig(config)
75
+ : toCustomProviderConfig(config);
76
+ }
77
+
78
+ export function toBuiltinProviderConfig(config: ModelProviderConfigDto): BuiltinProviderConfig {
79
+ return {
80
+ kind: 'builtin',
81
+ providerId: config.provider_id,
82
+ defaultModel: config.default_model,
83
+ createdAt: config.created_at,
84
+ updatedAt: config.updated_at,
85
+ };
86
+ }
87
+
88
+ export function toCustomProviderConfig(config: CustomModelProviderConfigDto): CustomProviderConfig {
89
+ return {
90
+ kind: 'custom',
91
+ providerId: config.provider_id,
92
+ displayName: config.display_name,
93
+ api: config.api,
94
+ baseUrl: config.base_url,
95
+ headers: config.headers.map((header) => ({name: header.name, value: header.value})),
96
+ secretHeaderNames: config.secret_header_names,
97
+ models: config.models.map(toAgentModel),
98
+ defaultModel: config.default_model,
99
+ createdAt: config.created_at,
100
+ updatedAt: config.updated_at,
101
+ };
102
+ }
103
+
104
+ function toAgentModel(model: {
105
+ id: string;
106
+ label: string;
107
+ context_window?: number | undefined;
108
+ max_output_tokens?: number | undefined;
109
+ input_image?: boolean | undefined;
110
+ reasoning?: boolean | undefined;
111
+ }): AgentModel {
112
+ return {
113
+ id: model.id,
114
+ label: model.label,
115
+ ...(model.context_window === undefined ? {} : {contextWindow: model.context_window}),
116
+ ...(model.max_output_tokens === undefined ? {} : {maxOutputTokens: model.max_output_tokens}),
117
+ ...(model.input_image === undefined ? {} : {inputImage: model.input_image}),
118
+ ...(model.reasoning === undefined ? {} : {reasoning: model.reasoning}),
119
+ };
120
+ }
@@ -47,7 +47,7 @@ describe('model provider transport', () => {
47
47
  const result = await listModelProviderConfigs({workspaceId: AGENT_TEST_WORKSPACE_ID});
48
48
 
49
49
  const request = fetchImpl.mock.calls[0]?.[0] as Request;
50
- expect(result.default_provider_id).toBe('anthropic');
50
+ expect(result.defaultProviderId).toBe('anthropic');
51
51
  expect(request.url).toBe(
52
52
  `https://api.example.test/workspaces/${AGENT_TEST_WORKSPACE_ID}/agent/model-providers`,
53
53
  );
@@ -66,11 +66,11 @@ describe('model provider transport', () => {
66
66
  const result = await upsertModelProviderConfig({
67
67
  workspaceId: AGENT_TEST_WORKSPACE_ID,
68
68
  providerId: 'anthropic',
69
- body,
69
+ command: {defaultModel: 'claude-haiku-4-5', credentials: {api_key: 'sk-ant-secret'}},
70
70
  });
71
71
 
72
72
  const request = fetchImpl.mock.calls[0]?.[0] as Request;
73
- expect(result.provider_id).toBe('anthropic');
73
+ expect(result.providerId).toBe('anthropic');
74
74
  expect(request.url).toBe(
75
75
  `https://api.example.test/workspaces/${AGENT_TEST_WORKSPACE_ID}/agent/model-providers/anthropic`,
76
76
  );
@@ -102,21 +102,21 @@ describe('model provider transport', () => {
102
102
  return jsonResponse(modelProviderConfig({default_model: null}));
103
103
  });
104
104
  configureApiClient({fetchImpl});
105
- const body = {default_model: null};
105
+ const defaultModel: string | null = null;
106
106
 
107
107
  const result = await updateModelProviderDefaultModel({
108
108
  workspaceId: AGENT_TEST_WORKSPACE_ID,
109
109
  providerId: 'anthropic',
110
- body,
110
+ defaultModel,
111
111
  });
112
112
 
113
113
  const request = fetchImpl.mock.calls[0]?.[0] as Request;
114
- expect(result.default_model).toBeNull();
114
+ expect(result.defaultModel).toBeNull();
115
115
  expect(request.url).toBe(
116
116
  `https://api.example.test/workspaces/${AGENT_TEST_WORKSPACE_ID}/agent/model-providers/anthropic/default-model`,
117
117
  );
118
118
  expect(request.method).toBe('PUT');
119
- expect(requestBody).toEqual(body);
119
+ expect(requestBody).toEqual({default_model: defaultModel});
120
120
  });
121
121
 
122
122
  test('sets the default model provider', async () => {
@@ -126,20 +126,20 @@ describe('model provider transport', () => {
126
126
  return jsonResponse({default_provider_id: 'anthropic'});
127
127
  });
128
128
  configureApiClient({fetchImpl});
129
- const body = {provider_id: 'anthropic'} as const;
129
+ const providerId = 'anthropic';
130
130
 
131
131
  const result = await setDefaultModelProvider({
132
132
  workspaceId: AGENT_TEST_WORKSPACE_ID,
133
- body,
133
+ providerId,
134
134
  });
135
135
 
136
136
  const request = fetchImpl.mock.calls[0]?.[0] as Request;
137
- expect(result.default_provider_id).toBe('anthropic');
137
+ expect(result.defaultProviderId).toBe('anthropic');
138
138
  expect(request.url).toBe(
139
139
  `https://api.example.test/workspaces/${AGENT_TEST_WORKSPACE_ID}/agent/default-model-provider`,
140
140
  );
141
141
  expect(request.method).toBe('PUT');
142
- expect(requestBody).toEqual(body);
142
+ expect(requestBody).toEqual({provider_id: providerId});
143
143
  });
144
144
 
145
145
  test('sets the default harness', async () => {
@@ -149,19 +149,19 @@ describe('model provider transport', () => {
149
149
  return jsonResponse({default_harness_id: 'claude'});
150
150
  });
151
151
  configureApiClient({fetchImpl});
152
- const body = {harness_id: 'claude'} as const;
152
+ const harnessId = 'claude' as const;
153
153
 
154
154
  const result = await setDefaultHarness({
155
155
  workspaceId: AGENT_TEST_WORKSPACE_ID,
156
- body,
156
+ harnessId,
157
157
  });
158
158
 
159
159
  const request = fetchImpl.mock.calls[0]?.[0] as Request;
160
- expect(result.default_harness_id).toBe('claude');
160
+ expect(result.defaultHarnessId).toBe('claude');
161
161
  expect(request.url).toBe(
162
162
  `https://api.example.test/workspaces/${AGENT_TEST_WORKSPACE_ID}/agent/default-harness`,
163
163
  );
164
164
  expect(request.method).toBe('PUT');
165
- expect(requestBody).toEqual(body);
165
+ expect(requestBody).toEqual({harness_id: harnessId});
166
166
  });
167
167
  });
@@ -1,24 +1,51 @@
1
- import type {
2
- CreateCustomModelProviderBodyDto,
3
- CustomModelProviderConfigDto,
4
- DiscoverCustomModelProviderModelsBodyDto,
5
- DiscoverCustomModelProviderModelsBySlugBodyDto,
6
- DiscoverCustomModelProviderModelsResponseDto,
7
- ListModelProviderConfigsResponseDto,
8
- ModelProviderCatalogResponseDto,
9
- ModelProviderConfigDto,
10
- ModelProviderRef,
11
- SetDefaultHarnessBodyDto,
12
- SetDefaultHarnessResponseDto,
13
- SetDefaultModelProviderBodyDto,
14
- SetDefaultModelProviderResponseDto,
15
- SupportedModelProviderId,
16
- UpdateCustomModelProviderBodyDto,
17
- UpdateModelProviderConfigBodyDto,
18
- UpdateModelProviderDefaultModelBodyDto,
1
+ import {
2
+ customModelProviderConfigDtoSchema,
3
+ discoverCustomModelProviderModelsResponseSchema,
4
+ listModelProviderConfigsResponseSchema,
5
+ type ModelProviderRef,
6
+ modelProviderCatalogResponseSchema,
7
+ modelProviderConfigDtoSchema,
8
+ setDefaultHarnessResponseSchema,
9
+ setDefaultModelProviderResponseSchema,
19
10
  } from '@shipfox/api-agent-dto';
20
- import {apiRequest} from '@shipfox/client-api';
21
- import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
11
+ import {checkedApiRequest, emptyResponseSchema} from '@shipfox/client-api';
12
+ import {
13
+ type FetchQueryOptions,
14
+ queryOptions,
15
+ useMutation,
16
+ useQuery,
17
+ useQueryClient,
18
+ } from '@tanstack/react-query';
19
+ import type {
20
+ AgentModel,
21
+ CreateCustomProviderCommand,
22
+ DefaultHarnessSelection,
23
+ DefaultModelProviderSelection,
24
+ DiscoverProviderModelsCommand,
25
+ HarnessId,
26
+ ProviderCatalog,
27
+ ProviderConfig,
28
+ ProviderConfiguration,
29
+ ProviderCredentialsCommand,
30
+ UpdateCustomProviderCommand,
31
+ } from '#core/models.js';
32
+ import {
33
+ toCreateCustomProviderBody,
34
+ toDefaultHarnessBody,
35
+ toDefaultModelBody,
36
+ toDefaultProviderBody,
37
+ toDiscoverModelsBody,
38
+ toDiscoverModelsBySlugBody,
39
+ toProviderCredentialsBody,
40
+ toUpdateCustomProviderBody,
41
+ } from './model-provider-command-mapper.js';
42
+ import {
43
+ toDefaultHarnessSelection,
44
+ toDefaultModelProviderSelection,
45
+ toProviderCatalog,
46
+ toProviderConfig,
47
+ toProviderConfiguration,
48
+ } from './model-provider-mapper.js';
22
49
 
23
50
  export const modelProviderQueryKeys = {
24
51
  all: ['model-providers'] as const,
@@ -27,10 +54,34 @@ export const modelProviderQueryKeys = {
27
54
  [...modelProviderQueryKeys.all, 'configs', workspaceId] as const,
28
55
  };
29
56
 
30
- export async function getModelProviderCatalog({signal}: {signal?: AbortSignal} = {}) {
31
- return await apiRequest<ModelProviderCatalogResponseDto>('/agent/model-provider-catalog', {
32
- signal,
33
- });
57
+ type ModelProviderConfigsQueryKey =
58
+ | ReturnType<typeof modelProviderQueryKeys.configs>
59
+ | readonly ['model-providers', 'configs'];
60
+
61
+ type ModelProviderConfigsQueryOptions = FetchQueryOptions<
62
+ ProviderConfiguration,
63
+ Error,
64
+ ProviderConfiguration,
65
+ ModelProviderConfigsQueryKey
66
+ >;
67
+
68
+ type ModelProviderCatalogQueryOptions = FetchQueryOptions<
69
+ ProviderCatalog,
70
+ Error,
71
+ ProviderCatalog,
72
+ ReturnType<typeof modelProviderQueryKeys.catalog>
73
+ >;
74
+
75
+ export async function getModelProviderCatalog({
76
+ signal,
77
+ }: {
78
+ signal?: AbortSignal;
79
+ } = {}): Promise<ProviderCatalog> {
80
+ return toProviderCatalog(
81
+ await checkedApiRequest(modelProviderCatalogResponseSchema, '/agent/model-provider-catalog', {
82
+ signal,
83
+ }),
84
+ );
34
85
  }
35
86
 
36
87
  export async function listModelProviderConfigs({
@@ -39,82 +90,110 @@ export async function listModelProviderConfigs({
39
90
  }: {
40
91
  workspaceId: string;
41
92
  signal?: AbortSignal;
42
- }) {
43
- return await apiRequest<ListModelProviderConfigsResponseDto>(
44
- `/workspaces/${workspaceId}/agent/model-providers`,
45
- {signal},
93
+ }): Promise<ProviderConfiguration> {
94
+ return toProviderConfiguration(
95
+ await checkedApiRequest(
96
+ listModelProviderConfigsResponseSchema,
97
+ `/workspaces/${workspaceId}/agent/model-providers`,
98
+ {signal},
99
+ ),
46
100
  );
47
101
  }
48
102
 
103
+ export function modelProviderConfigsQueryOptions(
104
+ workspaceId: string | undefined,
105
+ ): ModelProviderConfigsQueryOptions {
106
+ return queryOptions({
107
+ queryKey: workspaceId
108
+ ? modelProviderQueryKeys.configs(workspaceId)
109
+ : ([...modelProviderQueryKeys.all, 'configs'] as const),
110
+ enabled: Boolean(workspaceId),
111
+ queryFn: ({signal}) => listModelProviderConfigs({workspaceId: workspaceId ?? '', signal}),
112
+ });
113
+ }
114
+
49
115
  export async function upsertModelProviderConfig({
50
116
  workspaceId,
51
117
  providerId,
52
- body,
118
+ command,
53
119
  }: {
54
120
  workspaceId: string;
55
- providerId: SupportedModelProviderId;
56
- body: UpdateModelProviderConfigBodyDto;
57
- }) {
58
- return await apiRequest<ModelProviderConfigDto>(
59
- `/workspaces/${workspaceId}/agent/model-providers/${providerId}`,
60
- {method: 'PUT', body},
121
+ providerId: string;
122
+ command: ProviderCredentialsCommand;
123
+ }): Promise<ProviderConfig> {
124
+ return toProviderConfig(
125
+ await checkedApiRequest(
126
+ modelProviderConfigDtoSchema,
127
+ `/workspaces/${workspaceId}/agent/model-providers/${providerId}`,
128
+ {method: 'PUT', body: toProviderCredentialsBody(command)},
129
+ ),
61
130
  );
62
131
  }
63
132
 
64
133
  export async function createCustomModelProviderConfig({
65
134
  workspaceId,
66
- body,
135
+ command,
67
136
  }: {
68
137
  workspaceId: string;
69
- body: CreateCustomModelProviderBodyDto;
70
- }) {
71
- return await apiRequest<CustomModelProviderConfigDto>(
72
- `/workspaces/${workspaceId}/agent/custom-model-providers`,
73
- {method: 'POST', body},
138
+ command: CreateCustomProviderCommand;
139
+ }): Promise<ProviderConfig> {
140
+ return toProviderConfig(
141
+ await checkedApiRequest(
142
+ customModelProviderConfigDtoSchema,
143
+ `/workspaces/${workspaceId}/agent/custom-model-providers`,
144
+ {method: 'POST', body: toCreateCustomProviderBody(command)},
145
+ ),
74
146
  );
75
147
  }
76
148
 
77
149
  export async function updateCustomModelProviderConfig({
78
150
  workspaceId,
79
151
  providerId,
80
- body,
152
+ command,
81
153
  }: {
82
154
  workspaceId: string;
83
155
  providerId: ModelProviderRef;
84
- body: UpdateCustomModelProviderBodyDto;
85
- }) {
86
- return await apiRequest<CustomModelProviderConfigDto>(
87
- `/workspaces/${workspaceId}/agent/custom-model-providers/${providerId}`,
88
- {method: 'PUT', body},
156
+ command: UpdateCustomProviderCommand;
157
+ }): Promise<ProviderConfig> {
158
+ return toProviderConfig(
159
+ await checkedApiRequest(
160
+ customModelProviderConfigDtoSchema,
161
+ `/workspaces/${workspaceId}/agent/custom-model-providers/${providerId}`,
162
+ {method: 'PUT', body: toUpdateCustomProviderBody(command)},
163
+ ),
89
164
  );
90
165
  }
91
166
 
92
167
  export async function discoverCustomModelProviderModels({
93
168
  workspaceId,
94
- body,
169
+ command,
95
170
  }: {
96
171
  workspaceId: string;
97
- body: DiscoverCustomModelProviderModelsBodyDto;
98
- }) {
99
- return await apiRequest<DiscoverCustomModelProviderModelsResponseDto>(
172
+ command: DiscoverProviderModelsCommand;
173
+ }): Promise<readonly AgentModel[]> {
174
+ const response = await checkedApiRequest(
175
+ discoverCustomModelProviderModelsResponseSchema,
100
176
  `/workspaces/${workspaceId}/agent/custom-model-providers/discover-models`,
101
- {method: 'POST', body},
177
+ {method: 'POST', body: toDiscoverModelsBody(command)},
102
178
  );
179
+ return response.models.map((model) => ({id: model.id, label: model.label}));
103
180
  }
104
181
 
105
182
  export async function discoverCustomModelProviderModelsBySlug({
106
183
  workspaceId,
107
184
  providerId,
108
- body,
185
+ command,
109
186
  }: {
110
187
  workspaceId: string;
111
188
  providerId: ModelProviderRef;
112
- body: DiscoverCustomModelProviderModelsBySlugBodyDto;
113
- }) {
114
- return await apiRequest<DiscoverCustomModelProviderModelsResponseDto>(
189
+ command: DiscoverProviderModelsCommand;
190
+ }): Promise<readonly AgentModel[]> {
191
+ const response = await checkedApiRequest(
192
+ discoverCustomModelProviderModelsResponseSchema,
115
193
  `/workspaces/${workspaceId}/agent/custom-model-providers/${providerId}/discover-models`,
116
- {method: 'POST', body},
194
+ {method: 'POST', body: toDiscoverModelsBySlugBody(command)},
117
195
  );
196
+ return response.models.map((model) => ({id: model.id, label: model.label}));
118
197
  }
119
198
 
120
199
  export async function deleteModelProviderConfig({
@@ -124,54 +203,69 @@ export async function deleteModelProviderConfig({
124
203
  workspaceId: string;
125
204
  providerId: ModelProviderRef;
126
205
  }) {
127
- return await apiRequest<void>(`/workspaces/${workspaceId}/agent/model-providers/${providerId}`, {
128
- method: 'DELETE',
129
- });
206
+ return await checkedApiRequest(
207
+ emptyResponseSchema,
208
+ `/workspaces/${workspaceId}/agent/model-providers/${providerId}`,
209
+ {method: 'DELETE'},
210
+ );
130
211
  }
131
212
 
132
213
  export async function updateModelProviderDefaultModel({
133
214
  workspaceId,
134
215
  providerId,
135
- body,
216
+ defaultModel,
136
217
  }: {
137
218
  workspaceId: string;
138
- providerId: SupportedModelProviderId;
139
- body: UpdateModelProviderDefaultModelBodyDto;
140
- }) {
141
- return await apiRequest<ModelProviderConfigDto>(
142
- `/workspaces/${workspaceId}/agent/model-providers/${providerId}/default-model`,
143
- {method: 'PUT', body},
219
+ providerId: string;
220
+ defaultModel: string | null;
221
+ }): Promise<ProviderConfig> {
222
+ return toProviderConfig(
223
+ await checkedApiRequest(
224
+ modelProviderConfigDtoSchema,
225
+ `/workspaces/${workspaceId}/agent/model-providers/${providerId}/default-model`,
226
+ {method: 'PUT', body: toDefaultModelBody(defaultModel)},
227
+ ),
144
228
  );
145
229
  }
146
230
 
147
231
  export async function setDefaultModelProvider({
148
232
  workspaceId,
149
- body,
233
+ providerId,
150
234
  }: {
151
235
  workspaceId: string;
152
- body: SetDefaultModelProviderBodyDto;
153
- }) {
154
- return await apiRequest<SetDefaultModelProviderResponseDto>(
155
- `/workspaces/${workspaceId}/agent/default-model-provider`,
156
- {method: 'PUT', body},
236
+ providerId: string;
237
+ }): Promise<DefaultModelProviderSelection> {
238
+ return toDefaultModelProviderSelection(
239
+ await checkedApiRequest(
240
+ setDefaultModelProviderResponseSchema,
241
+ `/workspaces/${workspaceId}/agent/default-model-provider`,
242
+ {method: 'PUT', body: toDefaultProviderBody(providerId)},
243
+ ),
157
244
  );
158
245
  }
159
246
 
160
247
  export async function setDefaultHarness({
161
248
  workspaceId,
162
- body,
249
+ harnessId,
163
250
  }: {
164
251
  workspaceId: string;
165
- body: SetDefaultHarnessBodyDto;
166
- }) {
167
- return await apiRequest<SetDefaultHarnessResponseDto>(
168
- `/workspaces/${workspaceId}/agent/default-harness`,
169
- {method: 'PUT', body},
252
+ harnessId: HarnessId;
253
+ }): Promise<DefaultHarnessSelection> {
254
+ return toDefaultHarnessSelection(
255
+ await checkedApiRequest(
256
+ setDefaultHarnessResponseSchema,
257
+ `/workspaces/${workspaceId}/agent/default-harness`,
258
+ {method: 'PUT', body: toDefaultHarnessBody(harnessId)},
259
+ ),
170
260
  );
171
261
  }
172
262
 
173
263
  export function useModelProviderCatalogQuery() {
174
- return useQuery({
264
+ return useQuery(modelProviderCatalogQueryOptions());
265
+ }
266
+
267
+ export function modelProviderCatalogQueryOptions(): ModelProviderCatalogQueryOptions {
268
+ return queryOptions({
175
269
  queryKey: modelProviderQueryKeys.catalog(),
176
270
  queryFn: ({signal}) => getModelProviderCatalog({signal}),
177
271
  staleTime: 1000 * 60 * 60,
@@ -179,13 +273,7 @@ export function useModelProviderCatalogQuery() {
179
273
  }
180
274
 
181
275
  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
- });
276
+ return useQuery(modelProviderConfigsQueryOptions(workspaceId));
189
277
  }
190
278
 
191
279
  export function useUpsertModelProviderConfigMutation() {