Skip to content

Add self-harm/intent + self-harm/instructions OpenAI signals - #535

Merged
julietshen merged 5 commits into
mainfrom
julietshen/mod-api-self-harm-subcategories
Aug 5, 2026
Merged

Add self-harm/intent + self-harm/instructions OpenAI signals#535
julietshen merged 5 commits into
mainfrom
julietshen/mod-api-self-harm-subcategories

Conversation

@julietshen

@julietshen julietshen commented May 21, 2026

Copy link
Copy Markdown
Member

Stacked on #534. Adds the two omni self-harm subcategories on both modalities so coverage is symmetric and matches OpenAI's spec.

Why this is separate

PR #534 resolves #518 by adding image moderation for the four omni categories that already had text counterparts (violence, violence/graphic, self-harm, sexual). It deliberately stops there to keep the diff focused.

But OpenAI's omni model also scores self-harm/intent and self-harm/instructions for both text and images — and we had neither modality for those subcategories. Image-only would be lopsided; this PR adds the missing four classes so both modalities cover the full self-harm trio in OpenAI's spec.

What's in

Four new signal classes following the existing pattern:

  • OpenAiSelfHarmIntentTextSignal
  • OpenAiSelfHarmIntentImageSignal
  • OpenAiSelfHarmInstructionsTextSignal
  • OpenAiSelfHarmInstructionsImageSignal

Plus the matching plumbing: two new category names in OpenAiModelName and OpenAiImageModelName, four new SignalType enum values, four entries each in SignalArgsByType / RuntimeSignalArgsByType, four cases in integrationForSignalType, and four IoC registrations in instantiateBuiltInSignals.

Tests

The existing openAIModerationUtils.test.ts from #534 still passes — no new test surface added, since these signals are pure delegations to the lib that PR #534 already tests.

(cd server && npx tsc --noEmit)
(cd server && npm run lint -- services/signalsService/)

Reviewer checks:

(Optional) Rollout Plan

No schema change, no GraphQL change, no client change. Server starts registering 4 additional built-in signal types alongside the ones added in #534.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added OpenAI moderation signals for detecting self-harm instructions and intent in both text and images.
    • Added confidence scoring and signal support for these categories across moderation workflows.
  • Bug Fixes
    • Improved registration and integration handling for the new moderation signals.
  • Refactor
    • Consolidated shared moderation behavior for more consistent text and image signal processing.

@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds OpenAI self-harm instruction and intent signals for text and image inputs. It updates signal contracts, moderation factories, built-in registrations, GraphQL definitions, and client integration routing.

Changes

OpenAI Self-Harm Moderation Signal Support

Layer / File(s) Summary
Signal type and model contracts
client/src/graphql/generated.ts, server/graphql/..., server/services/signalsService/types/..., server/services/signalsService/signals/third_party_signals/open_ai/moderation/openAIModerationUtils.ts
Adds four self-harm signal types, model categories, GraphQL entries, integration mappings, and argument mappings.
Shared moderation factory migration
server/services/signalsService/signals/third_party_signals/open_ai/moderation/openAiModerationSignalFactory.ts, openAIModerationUtils.ts, OpenAi*ImageSignal.ts
Adds shared image and text moderation factories and redirects existing image signals to the new factory module.
Self-harm signal implementations
server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSelfHarm*Signal.ts
Adds image and text signals for self-harm/instructions and self-harm/intent.
Built-in registration and client routing
server/services/signalsService/helpers/instantiateBuiltInSignals.ts, client/src/models/signal.ts
Registers the four signals with OpenAI credentials and score retrieval. Client routing maps them to the OpenAI integration.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BuiltInSignalFactory
  participant OpenAiSelfHarmSignal
  participant getOpenAiScores
  participant OpenAI moderation API
  BuiltInSignalFactory->>OpenAiSelfHarmSignal: instantiate configured signal
  OpenAiSelfHarmSignal->>getOpenAiScores: submit text or image input
  getOpenAiScores->>OpenAI moderation API: request moderation score
  OpenAI moderation API-->>getOpenAiScores: return category score
  getOpenAiScores-->>OpenAiSelfHarmSignal: return numeric result
Loading

Possibly related PRs

  • roostorg/coop#534: Adds the OpenAI multimodal moderation plumbing extended by these signal types.

Suggested reviewers: cassidyjames, dom-notion, vinaysrao1

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the addition of OpenAI self-harm intent and instructions signals.
Description check ✅ Passed The description covers context, scope, testing commands, rollout impact, and reviewer checks.
Linked Issues check ✅ Passed The changes add image and text self-harm subcategory signals and the required integration plumbing for issue #518.
Out of Scope Changes check ✅ Passed The changed files support the stated OpenAI moderation signal expansion and contain no unrelated functionality.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch julietshen/mod-api-self-harm-subcategories

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@julietshen
julietshen force-pushed the julietshen/mod-api-self-harm-subcategories branch 2 times, most recently from da6a4ab to e0e76a7 Compare May 21, 2026 12:13
@cassidyjames cassidyjames added the integration Deals with a built-in integration label May 21, 2026
@julietshen
julietshen force-pushed the julietshen/mod-api-self-harm-subcategories branch from e0e76a7 to 345af20 Compare May 26, 2026 17:49
@julietshen
julietshen deleted the branch main May 29, 2026 00:11
@julietshen julietshen closed this May 29, 2026
@julietshen julietshen reopened this May 29, 2026
@julietshen
julietshen changed the base branch from julietshen/mod-api to main May 29, 2026 00:13
julietshen and others added 4 commits May 29, 2026 18:46
Round out the omni-moderation self-harm coverage that the prior commit
left lopsided. OpenAI scores both subcategories for text *and* image
inputs; we had neither.

New signal classes (4):
- OpenAiSelfHarmIntentTextSignal / OpenAiSelfHarmIntentImageSignal
- OpenAiSelfHarmInstructionsTextSignal / OpenAiSelfHarmInstructionsImageSignal

Plus matching SignalType enum entries, integrationForSignalType cases,
SignalArgsByType / RuntimeSignalArgsByType entries, IoC registration,
and the two new category names in OpenAiModelName +
OpenAiImageModelName.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same shape as the previous fix on PR #534: the four new self-harm
subcategory signal types need to round-trip through both
hand-maintained mirrors or the dashboard can't see them.

- server/graphql/modules/signal.ts: add the four
  OPEN_AI_SELF_HARM_{INTENT,INSTRUCTIONS}_{TEXT,IMAGE}_MODEL types to
  the SDL enum.
- client/src/models/signal.ts: add the same four to the OpenAi case
  in integrationForSignalType.
- Regenerate codegen.

The coverage test added in PR #534 catches this regression class on
new SignalType additions; it now exercises 33 enum values (was 29).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Matches the docstring style applied to the base PR's image signals.
Raises this PR's docstring coverage above CodeRabbit's 80% pre-merge
threshold by documenting each of the four new signal classes
(self-harm/intent text+image, self-harm/instructions text+image) and
their run() methods.

No behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the cleanup from PR #534: the 4 self-harm subcategory signal
classes (2 text + 2 image) collapse to ~20-line factory calls instead
of ~110-line class definitions each.

- Adds `makeOpenAiTextModerationSignal` alongside the existing image
  factory introduced in #534.
- Both factories now share a single internal `makeOpenAiModerationSignal`
  parameterized by input scalar + run impl, so the class body lives in
  one place (was duplicated twice in #534's first cut).
- Factories moved into `openAiModerationSignalFactory.ts` — keeps
  `openAIModerationUtils.ts` under the 500-line lint limit (the second
  factory pushed it to 510) and organizes the file boundary cleanly:
  utils = lib functions, factory = class generator.

The 4 self-harm subcategory signal files (text + image variants for
`self-harm/intent` and `self-harm/instructions`) now just import the
appropriate factory and pass a config object.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@julietshen
julietshen force-pushed the julietshen/mod-api-self-harm-subcategories branch from 345af20 to cce7cbf Compare May 29, 2026 22:49
@github-actions

Copy link
Copy Markdown
Contributor

Checklist:

  • If you're creating a new signal, did you check all the potential error cases, and classify, for each one, whether it should be thrown as a permanent error (not subject to retry) or just a normal error (which will lead the signal to being retried and the error value not cached)? NOTE: in our data model, any case in which the signal can not determine the score for the provided input should result in a SignalPermanentError. (server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSelfHarmInstructionsImageSignal.ts, server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSelfHarmInstructionsTextSignal.ts, server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSelfHarmIntentImageSignal.ts, server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSelfHarmIntentTextSignal.ts, server/services/signalsService/signals/third_party_signals/open_ai/moderation/openAIModerationUtils.ts, server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiGraphicViolenceImageSignal.ts, server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSelfHarmImageSignal.ts, server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSexualImageSignal.ts, server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiViolenceImageSignal.ts, server/services/signalsService/signals/third_party_signals/open_ai/moderation/openAiModerationSignalFactory.ts)

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
server/services/signalsService/signals/third_party_signals/open_ai/moderation/openAiModerationSignalFactory.ts (1)

183-191: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Migrate the remaining OpenAI text moderation signals to the new factory.

The existing text subclasses still declare the shared moderation base getters by hand, while image signals and only the new self-harm text signals use makeOpenAiImageModerationSignal / makeOpenAiTextModerationSignal. Use the wrappers for the remaining text signals to keep the moderation boilerplate in one place.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@server/services/signalsService/signals/third_party_signals/open_ai/moderation/openAiModerationSignalFactory.ts`
around lines 183 - 191, Update the remaining OpenAI text moderation signal
subclasses to use makeOpenAiTextModerationSignal, removing their duplicated
shared moderation base getters while preserving each signal’s specific
configuration and behavior. Follow the existing implementation of
makeOpenAiTextModerationSignal and the migrated self-harm text signals as the
pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@server/services/signalsService/signals/third_party_signals/open_ai/moderation/openAiModerationSignalFactory.ts`:
- Around line 1-12: Add unit tests for both makeOpenAiImageModerationSignal and
makeOpenAiTextModerationSignal, covering their expected eligibleInputs values,
id.type matching the configured SignalType, and run forwarding modelName plus
the injected credential getter to the correct implementation. Use mocks or spies
for the underlying moderation implementations and verify each wrapper routes to
its corresponding implementation.

---

Nitpick comments:
In
`@server/services/signalsService/signals/third_party_signals/open_ai/moderation/openAiModerationSignalFactory.ts`:
- Around line 183-191: Update the remaining OpenAI text moderation signal
subclasses to use makeOpenAiTextModerationSignal, removing their duplicated
shared moderation base getters while preserving each signal’s specific
configuration and behavior. Follow the existing implementation of
makeOpenAiTextModerationSignal and the migrated self-harm text signals as the
pattern.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7843d854-41df-42e5-9ed0-8d580e561fa8

📥 Commits

Reviewing files that changed from the base of the PR and between b98d11b and 85ccfed.

⛔ Files ignored due to path filters (2)
  • client/src/graphql/generated.ts is excluded by !**/generated.ts
  • server/graphql/generated.ts is excluded by !**/generated.ts
📒 Files selected for processing (15)
  • client/src/models/signal.ts
  • server/graphql/modules/signal.ts
  • server/services/signalsService/helpers/instantiateBuiltInSignals.ts
  • server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiGraphicViolenceImageSignal.ts
  • server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSelfHarmImageSignal.ts
  • server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSelfHarmInstructionsImageSignal.ts
  • server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSelfHarmInstructionsTextSignal.ts
  • server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSelfHarmIntentImageSignal.ts
  • server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSelfHarmIntentTextSignal.ts
  • server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiSexualImageSignal.ts
  • server/services/signalsService/signals/third_party_signals/open_ai/moderation/OpenAiViolenceImageSignal.ts
  • server/services/signalsService/signals/third_party_signals/open_ai/moderation/openAIModerationUtils.ts
  • server/services/signalsService/signals/third_party_signals/open_ai/moderation/openAiModerationSignalFactory.ts
  • server/services/signalsService/types/SignalArgsByType.ts
  • server/services/signalsService/types/SignalType.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • server/services/signalsService/types/SignalType.ts
  • client/src/models/signal.ts
  • server/graphql/modules/signal.ts
  • server/services/signalsService/helpers/instantiateBuiltInSignals.ts
  • server/services/signalsService/types/SignalArgsByType.ts

Comment on lines +1 to +12
/**
* Factories for OpenAI moderation signals. Collapses the boilerplate that
* was duplicated across every per-category signal class — id, displayName,
* description, integration, pricing, languages, cost, etc. The two public
* exports (`makeOpenAiImageModerationSignal`,
* `makeOpenAiTextModerationSignal`) are thin wrappers around the private
* `makeOpenAiModerationSignal` so the class body lives in one place.
*
* The IoC container instantiates the returned class with
* `(credentials, scores)` like any other signal, preserving the existing
* registration pattern in `instantiateBuiltInSignals.ts`.
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add tests for the shared factory.

This module is now the single construction point for every OpenAI moderation signal. A regression in eligibleInputs, outputType, id, or runImpl routing would affect all of them at once. The PR adds no tests.

Add a unit test that asserts, for both wrappers:

  • eligibleInputs returns [ScalarTypes.IMAGE] for makeOpenAiImageModerationSignal and [ScalarTypes.STRING] for makeOpenAiTextModerationSignal.
  • run forwards the configured modelName and the injected credential getter to the correct implementation.
  • id.type equals the configured SignalType.

Do you want me to generate that test file?

Based on learnings, and as per coding guidelines: "New behavior requires a test, and bug fixes require a regression test."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@server/services/signalsService/signals/third_party_signals/open_ai/moderation/openAiModerationSignalFactory.ts`
around lines 1 - 12, Add unit tests for both makeOpenAiImageModerationSignal and
makeOpenAiTextModerationSignal, covering their expected eligibleInputs values,
id.type matching the configured SignalType, and run forwarding modelName plus
the injected credential getter to the correct implementation. Use mocks or spies
for the underlying moderation implementations and verify each wrapper routes to
its corresponding implementation.

Source: Coding guidelines

@julietshen
julietshen merged commit 0aeb7eb into main Aug 5, 2026
17 checks passed
@julietshen
julietshen deleted the julietshen/mod-api-self-harm-subcategories branch August 5, 2026 13:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integration Deals with a built-in integration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[OpenAI] Moderation api is missing image/media inputs

3 participants