Skip to content

fix: restore Demo moderation and image creation - #485

Merged
nezhyborets merged 11 commits into
MacPaw:mainfrom
mvanhorn:fix/478-demo-moderation-image-creation
Nov 10, 2026
Merged

nezhyborets merged 11 commits into
MacPaw:mainfrom
mvanhorn:fix/478-demo-moderation-image-creation

Conversation

@mvanhorn

@mvanhorn mvanhorn commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

What

Moderation Chat rejects messages with an invalid-model error. Creating an image silently fails, leaving the user without an image, progress feedback, or an explanation. Moderation requests use the rejected text-moderation-latest model, while image creation omits the required model parameter. Image failures are only printed, and the view only handles URL responses, so it cannot display base64 image results.

Moderation now uses omni-moderation-latest, and ImageStore constructs image requests with gpt-image-1 and size options supported by that model. The image view displays progress, request errors, and decoded base64 images while retaining URL support. Starting a request cancels the previous subscription and clears stale results and errors; cancellation ends progress without displaying an error. The diff adds tests for request parameters, moderation success and failure, image errors, retries, base64 results, and cancellation.

Ran xcodebuild test -scheme DemoChat for MiscStoreTests and ImageStoreTests on an iPhone 17 simulator (iOS 26.4): 3 tests (11 test cases) pass with this change.
The moderation half has a runtime regression test: with the source changes reverted, MiscStoreTests compiles and fails because the request sends text-moderation-latest instead of omni-moderation-latest.
The image half is covered by ImageStoreTests, which call the new images(prompt:n:size:) entry point and read imagesQueryError. Those APIs do not exist on main, so these tests cannot run against the old code.

Refs #478

Why

The October 27 Demo release check (#478) found that Moderation Chat fails on every message and that image creation appears to do nothing. This covers those two items; the other observations in that report are left for follow-up.

Affected Areas

Demo app only: MiscStore.swift, ImageStore.swift and ImageCreationView.swift, plus the new MiscStoreTests.swift and ImageStoreTests.swift. No library code changes.

Moderation now uses omni-moderation-latest, and ImageStore constructs
image requests with gpt-image-1 and size options supported by that
model. The image view displays progress, request errors, and decoded
base64 images while retaining URL support. Starting a request cancels
the previous subscription and clears stale results and errors;
cancellation ends progress without displaying an error. The diff adds
tests for request parameters, moderation success and failure, image
errors, retries, base64 results, and cancellation.

Refs MacPaw#478

@nezhyborets nezhyborets left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thanks for the contribution! Please see the comments.

Also, could you add a Demo: entry under Unreleased → Fixed in CHANGELOG.md, like the other Demo fixes there?

Comment thread Demo/DemoChat/Sources/ImageStore.swift Resolved

@nezhyborets nezhyborets left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few more comments

Comment thread Demo/DemoChat/Sources/ImageStore.swift Resolved
Comment thread Demo/DemoChat/Sources/MiscStore.swift Resolved
@nezhyborets

Copy link
Copy Markdown
Collaborator

I've also created a few related issues that were found during review #488 #489, I just don't want to bloat this PR with all the stuff. But if you think you want to do that in this PR it's ok.

The API no longer lists gpt-image-1 for new keys, so the release check's
image creation case failed. Add Model.gpt_image_1_5 and use it in
ImageStore.
ImageCreationView decoded each b64_json and built a UIImage on every body
evaluation, including every keystroke in the prompt. ImageStore now
decodes them off the main thread in its pipeline and publishes
decodedImages, which the view reads.
The map closure in images(prompt:n:size:) inherited its main actor
isolation and crashed the isolation check when it ran on the URL
session queue. Use a static function instead.
Each behavior gets its own test, so a failure names the one that broke,
and the handler that never answers says so.
The API reference has no description of the model to copy, and the
doc comment was not taken from it.
ImageURLProtocol and ModerationURLProtocol were nearly identical, and so
were the body capture and client setup around them. MockURL in its own
file replaces both: it is configured through its respond property and
exposes the last request body and the request count.
Comment thread Demo/DemoChat/Sources/ImageStore.swift Resolved
The store now decodes b64_json to a CGImage with ImageIO off the main
thread and holds one GeneratedImage array, so it needs no UIKit
branches.

@nezhyborets nezhyborets left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job 👍

@nezhyborets
nezhyborets merged commit f5d1815 into MacPaw:main Nov 10, 2026
11 checks passed
@mvanhorn

Copy link
Copy Markdown
Contributor Author

Much appreciated @nezhyborets, with omni-moderation-latest and gpt-image-1 the Demo's moderation chat and image creation should work again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants