Rejects oversize images on capped providers before any upstream request is issued. Gotcha: a historical oversize image bricks the chat on a capped provider until the user switches providers back, starts a new chat, or edits a message above the offending one (which truncates the prompt forward). A f
(provider string)
| 5847 | // user-facing warning, but that requires altering the FileResolver |
| 5848 | // contract. |
| 5849 | func (p *Server) chatFileResolver(provider string) chatprompt.FileResolver { |
| 5850 | return func(ctx context.Context, ids []uuid.UUID) (map[uuid.UUID]chatprompt.FileData, error) { |
| 5851 | files, err := p.db.GetChatFilesByIDs(ctx, ids) |
| 5852 | if err != nil { |
| 5853 | return nil, err |
| 5854 | } |
| 5855 | imageCap, hasImageCap := chatprovider.InlineImageCapBytes(provider) |
| 5856 | normalizedProvider := chatprovider.NormalizeProvider(provider) |
| 5857 | result := make(map[uuid.UUID]chatprompt.FileData, len(files)) |
| 5858 | for _, f := range files { |
| 5859 | if hasImageCap && |
| 5860 | strings.HasPrefix(f.Mimetype, "image/") && |
| 5861 | len(f.Data) >= imageCap { |
| 5862 | err := xerrors.Errorf( |
| 5863 | "image attachment %q is %d bytes; %s inline image limit is %d bytes", |
| 5864 | f.Name, len(f.Data), |
| 5865 | chatprovider.ProviderDisplayName(normalizedProvider), |
| 5866 | imageCap, |
| 5867 | ) |
| 5868 | // User-facing message stays client-agnostic since |
| 5869 | // older web clients and direct API callers don't |
| 5870 | // auto-resize; the wrapped error above keeps the |
| 5871 | // exact byte count for operator logs. |
| 5872 | return nil, chaterror.WithClassification(err, chaterror.ClassifiedError{ |
| 5873 | Kind: codersdk.ChatErrorKindConfig, |
| 5874 | Provider: normalizedProvider, |
| 5875 | Message: fmt.Sprintf( |
| 5876 | "Image attachment exceeds %s's %s inline image limit. Replace it with a smaller image.", |
| 5877 | chatprovider.ProviderDisplayName(normalizedProvider), |
| 5878 | //nolint:gosec // imageCap is a small positive constant defined in chatprovider. |
| 5879 | humanize.IBytes(uint64(imageCap)), |
| 5880 | ), |
| 5881 | Retryable: false, |
| 5882 | }) |
| 5883 | } |
| 5884 | result[f.ID] = chatprompt.FileData{ |
| 5885 | Name: f.Name, |
| 5886 | Data: f.Data, |
| 5887 | MediaType: f.Mimetype, |
| 5888 | } |
| 5889 | } |
| 5890 | return result, nil |
| 5891 | } |
| 5892 | } |
| 5893 | |
| 5894 | // tryAutoPromoteQueuedMessage pops the next queued message and converts it |
| 5895 | // into a pending user message inside the caller's transaction. Queued |