diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 213533889fa..166ae772cf0 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -6203,10 +6203,7 @@ const docTemplate = `{ { "CoderSessionToken": [] } - ], - "x-apidocgen": { - "skip": true - } + ] }, "post": { "consumes": [ @@ -6250,10 +6247,7 @@ const docTemplate = `{ { "CoderSessionToken": [] } - ], - "x-apidocgen": { - "skip": true - } + ] } }, "/api/v2/organizations/{organization}/chats/models/{model}": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index e61e55c2b33..77554932c3e 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -5478,10 +5478,7 @@ { "CoderSessionToken": [] } - ], - "x-apidocgen": { - "skip": true - } + ] }, "post": { "consumes": ["application/json"], @@ -5519,10 +5516,7 @@ { "CoderSessionToken": [] } - ], - "x-apidocgen": { - "skip": true - } + ] } }, "/api/v2/organizations/{organization}/chats/models/{model}": { diff --git a/coderd/chat_routes.go b/coderd/chat_routes.go index 72e068c5f7f..a29067ea7ba 100644 --- a/coderd/chat_routes.go +++ b/coderd/chat_routes.go @@ -31,15 +31,6 @@ const ( chatAPIPrefixExperimental ) -// injectDefaultOrganizationParam lets the legacy default-organization -// routes reuse the organization-scoped handlers. -func injectDefaultOrganizationParam(next http.Handler) http.Handler { - return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - chi.RouteContext(req.Context()).URLParams.Add("organization", codersdk.DefaultOrganization) - next.ServeHTTP(rw, req) - }) -} - // registerChatAPIRoutes mounts the chat API surface on r, the root router // of an API prefix. /api/v2 and /api/experimental serve the same promoted // routes during the CODAGT-921 compatibility window. The experimental @@ -56,30 +47,18 @@ func (api *API) registerChatAPIRoutes(r chi.Router, apiKeyMiddleware func(http.H r.Use(api.chatFilesRateLimitMW()) r.Get("/chats/files/{file}/download", api.downloadChatFile) }) - if experimental { - // Superseded by the organization-scoped models collection and - // deliberately not promoted. Keep until the frontend uses the - // organization-scoped routes. - r.Route("/chats/model-configs", func(r chi.Router) { - r.Use( - apiKeyMiddleware, - injectDefaultOrganizationParam, - httpmw.ExtractOrganizationParam(api.Database), - ) - r.Get("/", api.listDefaultOrganizationChatModelConfigs) - r.Post("/", api.createChatModelConfig) - }) - } r.Route("/chats", func(r chi.Router) { r.Use(apiKeyMiddleware) if experimental { - // Superseded by the organization-scoped models route and - // deliberately not promoted. Keep until the frontend uses - // the organization-scoped routes. - r.With( - injectDefaultOrganizationParam, - httpmw.ExtractOrganizationParam(api.Database), - ).Get("/models", api.listChatModelConfigsByOrganization) + // Reserve removed collection paths so they return 404 instead of + // falling into the {chat} wildcard and failing UUID parsing. + for _, segment := range []string{"/models", "/model-configs"} { + r.Route(segment, func(r chi.Router) { + r.NotFound(func(rw http.ResponseWriter, _ *http.Request) { + httpapi.RouteNotFound(rw) + }) + }) + } // TODO(cian): place under /api/experimental/chats/config r.Route("/providers", func(r chi.Router) { r.Get("/", api.listChatProviders) @@ -97,13 +76,14 @@ func (api *API) registerChatAPIRoutes(r chi.Router, apiKeyMiddleware func(http.H }) }) } else { - // These segments exist only under /api/experimental. Reserve - // them with empty subrouters so they return 404 instead of + // Reserve unmounted segments so they return 404 instead of // falling into the {chat} wildcard and failing UUID parsing // with a 400. - // TODO(CODAGT-922): drop the reservations with the + segments := []string{"/model-configs"} + // TODO(CODAGT-922): drop the provider reservations with the // experimental mounts. - for _, segment := range []string{"/models", "/model-configs", "/providers", "/user-provider-configs"} { + segments = append(segments, "/providers", "/user-provider-configs") + for _, segment := range segments { r.Route(segment, func(r chi.Router) { r.NotFound(func(rw http.ResponseWriter, _ *http.Request) { httpapi.RouteNotFound(rw) diff --git a/coderd/chat_routes_test.go b/coderd/chat_routes_test.go index 764e3850303..93004072a91 100644 --- a/coderd/chat_routes_test.go +++ b/coderd/chat_routes_test.go @@ -31,7 +31,6 @@ func TestChatRoutesCompatibility(t *testing.T) { for _, route := range []string{ "/api/experimental/chats", "/api/experimental/chats/config/system-prompt", - "/api/experimental/chats/models", "/api/v2/chats", "/api/v2/chats/config/system-prompt", } { @@ -45,7 +44,9 @@ func TestChatRoutesCompatibility(t *testing.T) { method string path string }{ - {http.MethodGet, "/api/v2/chats/models"}, + {http.MethodGet, "/api/experimental/chats/models"}, + {http.MethodGet, "/api/experimental/chats/model-configs"}, + {http.MethodPost, "/api/experimental/chats/model-configs"}, {http.MethodGet, "/api/v2/chats/model-configs"}, {http.MethodPost, "/api/v2/chats/model-configs"}, {http.MethodGet, "/api/v2/chats/providers"}, diff --git a/coderd/exp_chats.go b/coderd/exp_chats.go index 76ea2f92c71..1da17501d2e 100644 --- a/coderd/exp_chats.go +++ b/coderd/exp_chats.go @@ -6898,32 +6898,6 @@ func (*API) deleteUserChatProviderKey(rw http.ResponseWriter, r *http.Request) { writeLegacyChatProviderGone(rw, r) } -func (api *API) listDefaultOrganizationChatModelConfigs(rw http.ResponseWriter, r *http.Request) { - ctx := r.Context() - organization := httpmw.OrganizationParam(r) - apiKey := httpmw.APIKey(r) - - if !chatModelConfigReadScope(apiKey.Scopes) { - httpapi.Forbidden(rw) - return - } - - configs, err := api.Database.GetChatModelConfigs(ctx, organization.ID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Failed to list chat model configs.", - Detail: err.Error(), - }) - return - } - - resp := make([]codersdk.ChatModel, 0, len(configs)) - for _, config := range configs { - resp = append(resp, convertChatModelConfig(config)) - } - httpapi.Write(ctx, rw, http.StatusOK, resp) -} - // @Summary List AI models and provider descriptors in an organization // @ID list-ai-models-and-provider-descriptors-in-an-organization // @Security CoderSessionToken @@ -6932,7 +6906,6 @@ func (api *API) listDefaultOrganizationChatModelConfigs(rw http.ResponseWriter, // @Param organization path string true "Organization name or ID" // @Success 200 {object} codersdk.OrganizationChatModelsResponse // @Router /api/v2/organizations/{organization}/chats/models [get] -// @x-apidocgen {"skip": true} func (api *API) listChatModelConfigsByOrganization(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() organization := httpmw.OrganizationParam(r) @@ -7017,8 +6990,7 @@ func chatModelConfigReadScope(scopes database.APIKeyScopes) bool { // read gate; providers are deployment-scoped and an org admin cannot read // them directly, so the fetch runs under a narrow AsChatd context scoped to // exactly these two reads and the result is projected to the fixed redacted -// fields (no key material, base URLs, or headers). Disclosure matches what -// /api/experimental/chats/models already shows any authenticated caller. +// fields, which exclude key material, base URLs, and headers. func (api *API) chatModelProviderDescriptors( ctx context.Context, userID uuid.UUID, @@ -7196,7 +7168,6 @@ func (api *API) auditChatModelConfigTransitions( // @Param request body codersdk.CreateChatModelRequest true "Model" // @Success 201 {object} codersdk.ChatModel // @Router /api/v2/organizations/{organization}/chats/models [post] -// @x-apidocgen {"skip": true} func (api *API) createChatModelConfig(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() apiKey := httpmw.APIKey(r) diff --git a/coderd/exp_chats_test.go b/coderd/exp_chats_test.go index 0bc424ec338..93183ba2955 100644 --- a/coderd/exp_chats_test.go +++ b/coderd/exp_chats_test.go @@ -4719,49 +4719,6 @@ func TestListChatModelConfigs(t *testing.T) { require.True(t, found) }) - t.Run("CompatibilityCollectionRoutesUseDefaultOrganization", func(t *testing.T) { - t.Parallel() - - ctx := testutil.Context(t, testutil.WaitLong) - client := newChatClient(t) - _ = coderdtest.CreateFirstUser(t, client.Client) - modelConfig := createChatModel(t, client) - - res, err := client.Request(ctx, http.MethodGet, "/api/experimental/chats/model-configs", nil) - require.NoError(t, err) - defer res.Body.Close() - require.Equal(t, http.StatusOK, res.StatusCode) - var configs []codersdk.ChatModel - require.NoError(t, codersdk.ReadBodyAsJSON(res, &configs)) - require.Contains(t, configs, modelConfig) - - collectionRes, err := client.Request(ctx, http.MethodGet, "/api/experimental/chats/models", nil) - require.NoError(t, err) - defer collectionRes.Body.Close() - require.Equal(t, http.StatusOK, collectionRes.StatusCode) - var collection codersdk.OrganizationChatModelsResponse - require.NoError(t, codersdk.ReadBodyAsJSON(collectionRes, &collection)) - require.Contains(t, collection.Models, modelConfig) - - contextLimit := int64(8192) - createdRes, err := client.Request(ctx, http.MethodPost, "/api/experimental/chats/model-configs", codersdk.CreateChatModelRequest{ - AIProviderID: &modelConfig.AIProviderID, - Model: "compatibility-model", - ContextLimit: &contextLimit, - }) - require.NoError(t, err) - defer createdRes.Body.Close() - require.Equal(t, http.StatusCreated, createdRes.StatusCode) - var created codersdk.ChatModel - require.NoError(t, codersdk.ReadBodyAsJSON(createdRes, &created)) - - got, err := client.ChatModel(ctx, created.OrganizationID, created.ID) - require.NoError(t, err) - require.Equal(t, created.ID, got.ID) - - require.NoError(t, client.DeleteChatModel(ctx, created.OrganizationID, created.ID)) - }) - t.Run("CollectionIncludesDisabledModelConfigs", func(t *testing.T) { t.Parallel() diff --git a/codersdk/chats.go b/codersdk/chats.go index fc960dbadc5..a6a0b0adb3d 100644 --- a/codersdk/chats.go +++ b/codersdk/chats.go @@ -2301,8 +2301,8 @@ func (c *Client) DeleteChatModel(ctx context.Context, organizationID, modelID uu // ChatModelProviderDescriptor is the redacted view of an AI provider carried // on the org model collection response. It carries only the capability // metadata the Models UI needs; key material, base URLs, and headers are -// never exposed. The fields mirror what /api/experimental/chats/models -// already discloses to any authenticated caller. +// never exposed. The fields mirror the provider descriptors returned by the +// organization-scoped chat models collection. type ChatModelProviderDescriptor struct { ID uuid.UUID `json:"id" format:"uuid"` Type string `json:"type"` diff --git a/docs/ai-coder/agents/models.md b/docs/ai-coder/agents/models.md index bdc7114c03f..a06cf74451c 100644 --- a/docs/ai-coder/agents/models.md +++ b/docs/ai-coder/agents/models.md @@ -167,6 +167,20 @@ An unavailable provider can remain visible while its models are omitted from the Model APIs identify each configured model with a UUID. The provider's model identifier, such as `gpt-5.3-codex`, doesn't replace this model UUID. +### Migrate model API clients + +Model collection APIs require an organization name or ID in the path. +Update clients that use the removed default-organization routes as follows: + +| Removed route | Replacement | Response change | +|----------------------------------------------|----------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------| +| `GET /api/experimental/chats/models` | `GET /api/v2/organizations/{organization}/chats/models` | The response remains an `OrganizationChatModelsResponse`. | +| `GET /api/experimental/chats/model-configs` | `GET /api/v2/organizations/{organization}/chats/models` | The response changes from a `ChatModel` array to an `OrganizationChatModelsResponse`. Read configured models from `models`. | +| `POST /api/experimental/chats/model-configs` | `POST /api/v2/organizations/{organization}/chats/models` | The request and `ChatModel` response shapes remain the same. | + +Replace `{organization}` with the organization name or ID that owns the models. +The collection response also includes provider descriptors and unsupported provider details. + ### Add a model 1. Navigate to **Admin settings** > **AI** > **Models**. diff --git a/docs/reference/api/chats.md b/docs/reference/api/chats.md index 7b331c5db9c..d0ff0e39ba9 100644 --- a/docs/reference/api/chats.md +++ b/docs/reference/api/chats.md @@ -3873,6 +3873,606 @@ curl -X POST http://coder-server:8080/api/v2/chats/{chat}/tool-results \ To perform this operation, you must be authenticated. [Learn more](authentication.md). +## List AI models and provider descriptors in an organization + +### Code samples + +```sh +# Example request using curl +curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/chats/models \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`GET /api/v2/organizations/{organization}/chats/models` + +### Parameters + +| Name | In | Type | Required | Description | +|----------------|------|--------|----------|-------------------------| +| `organization` | path | string | true | Organization name or ID | + +### Example responses + +> 200 Response + +```json +{ + "models": [ + { + "ai_provider_id": "5a3b8ff9-20e7-4c37-ba1a-5b433e355819", + "compression_threshold": 0, + "context_limit": 0, + "created_at": "2019-08-24T14:15:22Z", + "display_name": "string", + "enabled": true, + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "is_default": true, + "model": "string", + "model_config": { + "frequency_penalty": 0, + "max_output_tokens": 0, + "openai_config": { + "use_responses_api": true + }, + "presence_penalty": 0, + "provider_options": { + "anthropic": { + "allowed_domains": [ + "string" + ], + "blocked_domains": [ + "string" + ], + "context_1m_enabled": true, + "disable_parallel_tool_use": true, + "send_reasoning": true, + "thinking": { + "budget_tokens": 0 + }, + "thinking_display": "string", + "web_search_enabled": true + }, + "google": { + "cached_content": "string", + "safety_settings": [ + { + "category": "string", + "threshold": "string" + } + ], + "thinking_config": { + "include_thoughts": true, + "thinking_budget": 0, + "thinking_level": "string" + }, + "threshold": "string", + "web_search_enabled": true + }, + "openai": { + "allowed_domains": [ + "string" + ], + "include": [ + "string" + ], + "instructions": "string", + "log_probs": true, + "logit_bias": { + "property1": 0, + "property2": 0 + }, + "max_completion_tokens": 0, + "max_tool_calls": 0, + "metadata": { + "property1": null, + "property2": null + }, + "parallel_tool_calls": true, + "prediction": { + "property1": null, + "property2": null + }, + "prompt_cache_key": "string", + "reasoning_summary": "string", + "safety_identifier": "string", + "search_context_size": "string", + "service_tier": "string", + "store": true, + "strict_json_schema": true, + "structured_outputs": true, + "text_verbosity": "string", + "top_log_probs": 0, + "user": "string", + "web_search_enabled": true + }, + "openaicompat": { + "user": "string" + }, + "openrouter": { + "extra_body": { + "property1": null, + "property2": null + }, + "include_usage": true, + "log_probs": true, + "logit_bias": { + "property1": 0, + "property2": 0 + }, + "parallel_tool_calls": true, + "provider": { + "allow_fallbacks": true, + "data_collection": "string", + "ignore": [ + "string" + ], + "only": [ + "string" + ], + "order": [ + "string" + ], + "quantizations": [ + "string" + ], + "require_parameters": true, + "sort": "string" + }, + "reasoning": { + "enabled": true, + "exclude": true, + "max_tokens": 0 + }, + "user": "string" + }, + "vercel": { + "extra_body": { + "property1": null, + "property2": null + }, + "logit_bias": { + "property1": 0, + "property2": 0 + }, + "logprobs": true, + "parallel_tool_calls": true, + "providerOptions": { + "models": [ + "string" + ], + "order": [ + "string" + ] + }, + "reasoning": { + "enabled": true, + "exclude": true, + "max_tokens": 0 + }, + "top_logprobs": 0, + "user": "string" + } + }, + "reasoning_effort": { + "default": "string", + "max": "string" + }, + "temperature": 0, + "top_k": 0, + "top_p": 0 + }, + "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6", + "reasoning_efforts": [ + "string" + ], + "updated_at": "2019-08-24T14:15:22Z" + } + ], + "providers": [ + { + "allow_user_api_key": true, + "available": true, + "display_name": "string", + "enabled": true, + "has_api_key": true, + "has_effective_api_key": true, + "has_user_api_key": true, + "icon": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "type": "string", + "unavailable_reason": "missing_api_key" + } + ], + "unsupported_providers": [ + { + "display_name": "string", + "provider": "string" + } + ] +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +|--------|---------------------------------------------------------|-------------|----------------------------------------------------------------------------------------------| +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.OrganizationChatModelsResponse](schemas.md#codersdkorganizationchatmodelsresponse) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + +## Create an AI model in an organization + +### Code samples + +```sh +# Example request using curl +curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/chats/models \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`POST /api/v2/organizations/{organization}/chats/models` + +> Body parameter + +```json +{ + "ai_provider_id": "5a3b8ff9-20e7-4c37-ba1a-5b433e355819", + "compression_threshold": 0, + "context_limit": 0, + "display_name": "string", + "enabled": true, + "is_default": true, + "model": "string", + "model_config": { + "frequency_penalty": 0, + "max_output_tokens": 0, + "openai_config": { + "use_responses_api": true + }, + "presence_penalty": 0, + "provider_options": { + "anthropic": { + "allowed_domains": [ + "string" + ], + "blocked_domains": [ + "string" + ], + "context_1m_enabled": true, + "disable_parallel_tool_use": true, + "send_reasoning": true, + "thinking": { + "budget_tokens": 0 + }, + "thinking_display": "string", + "web_search_enabled": true + }, + "google": { + "cached_content": "string", + "safety_settings": [ + { + "category": "string", + "threshold": "string" + } + ], + "thinking_config": { + "include_thoughts": true, + "thinking_budget": 0, + "thinking_level": "string" + }, + "threshold": "string", + "web_search_enabled": true + }, + "openai": { + "allowed_domains": [ + "string" + ], + "include": [ + "string" + ], + "instructions": "string", + "log_probs": true, + "logit_bias": { + "property1": 0, + "property2": 0 + }, + "max_completion_tokens": 0, + "max_tool_calls": 0, + "metadata": { + "property1": null, + "property2": null + }, + "parallel_tool_calls": true, + "prediction": { + "property1": null, + "property2": null + }, + "prompt_cache_key": "string", + "reasoning_summary": "string", + "safety_identifier": "string", + "search_context_size": "string", + "service_tier": "string", + "store": true, + "strict_json_schema": true, + "structured_outputs": true, + "text_verbosity": "string", + "top_log_probs": 0, + "user": "string", + "web_search_enabled": true + }, + "openaicompat": { + "user": "string" + }, + "openrouter": { + "extra_body": { + "property1": null, + "property2": null + }, + "include_usage": true, + "log_probs": true, + "logit_bias": { + "property1": 0, + "property2": 0 + }, + "parallel_tool_calls": true, + "provider": { + "allow_fallbacks": true, + "data_collection": "string", + "ignore": [ + "string" + ], + "only": [ + "string" + ], + "order": [ + "string" + ], + "quantizations": [ + "string" + ], + "require_parameters": true, + "sort": "string" + }, + "reasoning": { + "enabled": true, + "exclude": true, + "max_tokens": 0 + }, + "user": "string" + }, + "vercel": { + "extra_body": { + "property1": null, + "property2": null + }, + "logit_bias": { + "property1": 0, + "property2": 0 + }, + "logprobs": true, + "parallel_tool_calls": true, + "providerOptions": { + "models": [ + "string" + ], + "order": [ + "string" + ] + }, + "reasoning": { + "enabled": true, + "exclude": true, + "max_tokens": 0 + }, + "top_logprobs": 0, + "user": "string" + } + }, + "reasoning_effort": { + "default": "string", + "max": "string" + }, + "temperature": 0, + "top_k": 0, + "top_p": 0 + } +} +``` + +### Parameters + +| Name | In | Type | Required | Description | +|----------------|------|------------------------------------------------------------------------------|----------|-------------------------| +| `organization` | path | string | true | Organization name or ID | +| `body` | body | [codersdk.CreateChatModelRequest](schemas.md#codersdkcreatechatmodelrequest) | true | Model | + +### Example responses + +> 201 Response + +```json +{ + "ai_provider_id": "5a3b8ff9-20e7-4c37-ba1a-5b433e355819", + "compression_threshold": 0, + "context_limit": 0, + "created_at": "2019-08-24T14:15:22Z", + "display_name": "string", + "enabled": true, + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "is_default": true, + "model": "string", + "model_config": { + "frequency_penalty": 0, + "max_output_tokens": 0, + "openai_config": { + "use_responses_api": true + }, + "presence_penalty": 0, + "provider_options": { + "anthropic": { + "allowed_domains": [ + "string" + ], + "blocked_domains": [ + "string" + ], + "context_1m_enabled": true, + "disable_parallel_tool_use": true, + "send_reasoning": true, + "thinking": { + "budget_tokens": 0 + }, + "thinking_display": "string", + "web_search_enabled": true + }, + "google": { + "cached_content": "string", + "safety_settings": [ + { + "category": "string", + "threshold": "string" + } + ], + "thinking_config": { + "include_thoughts": true, + "thinking_budget": 0, + "thinking_level": "string" + }, + "threshold": "string", + "web_search_enabled": true + }, + "openai": { + "allowed_domains": [ + "string" + ], + "include": [ + "string" + ], + "instructions": "string", + "log_probs": true, + "logit_bias": { + "property1": 0, + "property2": 0 + }, + "max_completion_tokens": 0, + "max_tool_calls": 0, + "metadata": { + "property1": null, + "property2": null + }, + "parallel_tool_calls": true, + "prediction": { + "property1": null, + "property2": null + }, + "prompt_cache_key": "string", + "reasoning_summary": "string", + "safety_identifier": "string", + "search_context_size": "string", + "service_tier": "string", + "store": true, + "strict_json_schema": true, + "structured_outputs": true, + "text_verbosity": "string", + "top_log_probs": 0, + "user": "string", + "web_search_enabled": true + }, + "openaicompat": { + "user": "string" + }, + "openrouter": { + "extra_body": { + "property1": null, + "property2": null + }, + "include_usage": true, + "log_probs": true, + "logit_bias": { + "property1": 0, + "property2": 0 + }, + "parallel_tool_calls": true, + "provider": { + "allow_fallbacks": true, + "data_collection": "string", + "ignore": [ + "string" + ], + "only": [ + "string" + ], + "order": [ + "string" + ], + "quantizations": [ + "string" + ], + "require_parameters": true, + "sort": "string" + }, + "reasoning": { + "enabled": true, + "exclude": true, + "max_tokens": 0 + }, + "user": "string" + }, + "vercel": { + "extra_body": { + "property1": null, + "property2": null + }, + "logit_bias": { + "property1": 0, + "property2": 0 + }, + "logprobs": true, + "parallel_tool_calls": true, + "providerOptions": { + "models": [ + "string" + ], + "order": [ + "string" + ] + }, + "reasoning": { + "enabled": true, + "exclude": true, + "max_tokens": 0 + }, + "top_logprobs": 0, + "user": "string" + } + }, + "reasoning_effort": { + "default": "string", + "max": "string" + }, + "temperature": 0, + "top_k": 0, + "top_p": 0 + }, + "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6", + "reasoning_efforts": [ + "string" + ], + "updated_at": "2019-08-24T14:15:22Z" +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +|--------|--------------------------------------------------------------|-------------|----------------------------------------------------| +| 201 | [Created](https://tools.ietf.org/html/rfc7231#section-6.3.2) | Created | [codersdk.ChatModel](schemas.md#codersdkchatmodel) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + ## List user AI provider key configurations ### Code samples diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 4f26df5168e..6cc9ab53faf 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -3051,8 +3051,8 @@ export interface ChatModelOverridesResponse { * ChatModelProviderDescriptor is the redacted view of an AI provider carried * on the org model collection response. It carries only the capability * metadata the Models UI needs; key material, base URLs, and headers are - * never exposed. The fields mirror what /api/experimental/chats/models - * already discloses to any authenticated caller. + * never exposed. The fields mirror the provider descriptors returned by the + * organization-scoped chat models collection. */ export interface ChatModelProviderDescriptor { readonly id: string;