Strip the :N suffix on SAM3's single-prompt path (#15811) - #15840
Strip the :N suffix on SAM3's single-prompt path (#15811)#15840ntdat812 wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📜 Recent review details🧰 Additional context used📓 Path-based instructions (6)**/*📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.py📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{py,json}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{py,md,txt,json}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**⚙️ CodeRabbit configuration file
Files:
comfy/**⚙️ CodeRabbit configuration file
Files:
🔇 Additional comments (2)
📝 WalkthroughWalkthrough
Merge Risk: ⚪ Minimal · up to The change makes single prompts such as "person:1" and "(person)" reach the encoder in their intended normalized form without changing multi-prompt behavior; no actionable merge-blocking risk remains after normal checks and review. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
`:N` sets max_detections per category and defaults to 1, so `person:1` is by definition the same detection prompt as `person`. `_parse_prompts()` strips the suffix, but the fast path in `SAM3TokenizerWrapper.tokenize_with_weights()` forwarded the raw text — and that branch is taken for exactly the `foo:1` shape, so the encoder grounded on the literal "person:1". Forward the parsed phrase instead, falling back to the raw text when nothing parses (empty prompt). This also makes the fast path agree with the multi-prompt path on parentheses, which `_parse_prompts()` already strips.
Fixes #15811.
The bug
:Nsetsmax_detectionsfor a category and defaults to1, soperson:1is by definition the same detection prompt asperson._parse_prompts()strips the suffix correctly — the fast path did not:That branch is taken for exactly two shapes:
foo(nothing to strip) andfoo:1(everything to strip). So the only case it can affect is the broken one, and the encoder grounded on the literal"person:1".The change
Forward
parsed[0][0]instead oftext, falling back totextwhen nothing parses so an empty prompt still reaches the tokenizer unchanged rather than becomingNone.One knock-on effect worth naming:
_parse_prompts()also strips parentheses (SAM3 setsdisable_weights = True), so(person)now tokenizes aspersonon this path too. That is what the multi-prompt path has always done — the two paths now agree instead of disagreeing on the same input.Tests
tests-unit/comfy_test/sam3_prompt_parse_test.py— 10 tests asserting which string the inner tokenizer is actually handed.They load
sam3_clip.pywithcomfy.sd1_clipstubbed by a recording tokenizer, so the forwarding contract is checked without torch, transformers or model weights. The stub is scoped to the load and restored afterwards — it never enterssys.modulesunder the real module name, so nothing else in the session sees it.Against
masterwith onlycomfy/text_encoders/sam3_clip.pyreverted:The four that pass on both are the ones pinning what must not change: the bare
personprompt, the empty-prompt fallback, the multi-prompt path (person:2, car→ still two batches with[2, 1]), and_parse_prompts()itself.With the fix: 10 passed.
ruff checkclean on both files.