mirror of
https://github.com/coder/coder.git
synced 2026-09-23 05:43:53 +08:00
Follow-up to #26862 ("remove direct chat routing"), which collapsed the routing discriminated union into a single `aiGatewayModelRoute` but left a one-path dispatch shim behind in `model_routing.go`. Removes `resolveModelRouteForConfig`/`resolveModelRouteForProviderType`/`newModel` wrapper functions that did nothing but call their `*AIGateway*` counterparts, and renames the `*AIGateway*` targets to take over those names directly. Also collapses a redundant if/else in `title_override.go` where both branches called the same function with the same effective argument, and has `chatutil.NormalizedStringPointer` delegate to the existing `coderd/util/strings.EmptyToNil` instead of reimplementing empty-string-to-nil logic. No behavior change. <details> <summary>Investigation notes / decision log</summary> Two independent read-only investigations were run over `coderd/x/chatd` looking for cleanup opportunities following #26862: one focused on residue from that PR specifically, one a general over-engineering pass on the whole package. Both independently converged on the `model_routing.go` shim as the top finding (verified zero divergent call sites). Other candidates considered and explicitly deferred/rejected for this PR: - Renaming away the vestigial `AIGateway` prefix package-wide: cosmetic-only, touches many call sites, skipped. - Inlining the `chatcost` subpackage into `chatd`: unrelated to #26862, skipped. - Deleting the deprecated `AIGatewayRoutingEnabled` deployment flag: confirmed dead/no-op, but intentionally kept as a back-compat shim per #26862; removal should follow the same deprecation cadence as other deprecated deployment options, as a separate, differently-timed change. - Folding `chatutil` entirely into `chatprovider`/`chatopenai`: `NormalizedStringPointer` overlapped with `coderd/util/strings.EmptyToNil` (now reused), but `NormalizedEnumValue` has no equivalent elsewhere in the repo and still has 2 real call sites, so the package stays. </details> --- Generated by Coder Agents on behalf of @johnstcn.
87 lines
2.2 KiB
Go
87 lines
2.2 KiB
Go
package chatd
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"charm.land/fantasy"
|
|
"github.com/google/uuid"
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/coder/coder/v2/coderd/aibridge"
|
|
"github.com/coder/coder/v2/coderd/database"
|
|
"github.com/coder/coder/v2/coderd/x/chatd/chatprovider"
|
|
)
|
|
|
|
type modelClientRequest struct {
|
|
Chat database.Chat
|
|
ModelName string
|
|
UserAgent string
|
|
ExtraHeaders map[string]string
|
|
}
|
|
|
|
type modelBuildOptions struct {
|
|
ActiveAPIKeyID string
|
|
RecordHTTP bool
|
|
}
|
|
|
|
func modelBuildOptionsFromMessages(messages []database.ChatMessage) modelBuildOptions {
|
|
apiKeyID, _ := activeTurnAPIKeyIDFromMessages(messages)
|
|
return modelBuildOptions{ActiveAPIKeyID: apiKeyID}
|
|
}
|
|
|
|
// withActiveTurnAPIKeyID augments ctx with the active turn's delegated API
|
|
// key ID when one is known. AI Gateway routing and subagent tool callbacks
|
|
// read this value from the context to attribute requests to the correct
|
|
// turn. When no key is known, ctx is returned unchanged.
|
|
func withActiveTurnAPIKeyID(ctx context.Context, opts modelBuildOptions) context.Context {
|
|
if opts.ActiveAPIKeyID == "" {
|
|
return ctx
|
|
}
|
|
return aibridge.WithDelegatedAPIKeyID(ctx, opts.ActiveAPIKeyID)
|
|
}
|
|
|
|
func (p *Server) enabledAIProviderByID(ctx context.Context, providerID uuid.UUID) (database.AIProvider, error) {
|
|
provider, err := p.db.GetAIProviderByID(ctx, providerID)
|
|
if err != nil {
|
|
return database.AIProvider{}, xerrors.Errorf("get AI provider: %w", err)
|
|
}
|
|
if !provider.Enabled {
|
|
return database.AIProvider{}, xerrors.Errorf("AI provider %s is disabled", provider.ID)
|
|
}
|
|
return provider, nil
|
|
}
|
|
|
|
func newLanguageModel(
|
|
providerHint string,
|
|
modelName string,
|
|
providerKeys chatprovider.ProviderAPIKeys,
|
|
userAgent string,
|
|
extraHeaders map[string]string,
|
|
httpClient *http.Client,
|
|
) (fantasy.LanguageModel, error) {
|
|
model, err := chatprovider.ModelFromConfig(
|
|
providerHint,
|
|
modelName,
|
|
providerKeys,
|
|
userAgent,
|
|
extraHeaders,
|
|
httpClient,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if model == nil {
|
|
provider, resolvedModel, resolveErr := chatprovider.ResolveModelWithProviderHint(modelName, providerHint)
|
|
if resolveErr != nil {
|
|
return nil, resolveErr
|
|
}
|
|
return nil, xerrors.Errorf(
|
|
"create model for %s/%s returned nil",
|
|
provider,
|
|
resolvedModel,
|
|
)
|
|
}
|
|
return model, nil
|
|
}
|