Skip to main content

Ocular Beta

Behavioral risk assessment for human–AI conversations. Returns a continuous salience score, eight user-side axes (signals.user), four AI-side axes (signals.ai), fiction strength, authenticity, and optional per-turn trajectory.

Beta endpoint. Response shape may evolve. Rate-limited under the standard /v1/* limiter. See dashboard.nope.net/ocular for per-call analytics.

What Ocular is

Ocular is a probe-based behavioral classifier. Instead of producing a single severity rating like Evaluate, it returns axis-level signals so you can route differently for, say, harm to others vs self-neglect, or for AI-side concerns like manipulation or safeguarding failure.

Ocular is fiction-aware. A roleplay scene that mentions self-harm without genuine distress will score high fiction and a correspondingly low salience. Use it on the full conversation (assistant + user turns) rather than single messages — the trajectory and AI-concern signals require both sides.

Quickstart

curl -X POST https://api.nope.net/v1/ocular \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {"role": "user", "content": "I feel really hopeless lately"},
      {"role": "assistant", "content": "I hear you. That sounds really painful."}
    ]
  }'

Response

salience is the headline signal — a continuous score in [0, 1], and the field to key your flag / escalation decision off. Pick the cutoff that fits your use case (NOPE publishes 0.30 / 0.60 as reference watch / danger thresholds). The per-axis signals.user.<axis>.level and signals.ai.<axis>.level tell you which concern is driving a score — use them to route to the right resource or reviewer, not as a separate escalation gate. NOPE's fiction- and register-aware adjustments are already reflected in salience, so the flag decision belongs on salience.

{
  "salience": 0.41,
  "subject": "self",
  "imminence": { "level": "moderate", "score": 0.42 },
  "fiction": 0.08,
  "authenticity": 0.81,
  "signals": {
    "user": {
      "suicide":          { "level": "moderate", "score": 0.55 },
      "self_harm":        { "level": "low",      "score": 0.21 },
      "harm_to_others":   { "level": "minimal",  "score": 0.02 },
      "abuse":            { "level": "minimal",  "score": 0.01 },
      "sexual_violence":  { "level": "minimal",  "score": 0.00 },
      "exploitation":     { "level": "minimal",  "score": 0.00 },
      "stalking":         { "level": "minimal",  "score": 0.00 },
      "self_neglect":     { "level": "low",      "score": 0.18 }
    },
    "ai": {
      "harm_provision":       { "level": "minimal", "score": 0.03 },
      "emotional_failure":    { "level": "minimal", "score": 0.07 },
      "manipulation":         { "level": "minimal", "score": 0.01 },
      "safeguarding_failure": { "level": "minimal", "score": 0.05 }
    }
  },
  "thoroughness": "auto",
  "confidence": 0.87,
  "stability": null,
  "meta": {
    "version": "0.3.5",
    "inference_ms": 175,
    "windowed": false,
    "windows": 1
  }
}

Fields

FieldDescription
salience0..1 — the continuous top-line signal. Key off this field for routing logic; 0.30 / 0.60 are published reference watch / danger thresholds.
subjectself (speaker themselves) | other (third party) | unknown.
imminence{ level, score } — how imminent the concern is. level uses the shared ladder (minimal … critical).
fiction0..1 — how strongly the message reads as fiction / roleplay. High fiction modulates salience downward.
authenticity0..1 — how strongly the message reads as genuine first-person disclosure.
signals.userEight user-side axes, each { level, score }: suicide, self_harm, harm_to_others, abuse, sexual_violence, exploitation, stalking, self_neglect.
signals.aiFour AI-side axes, each { level, score }: harm_provision, emotional_failure, manipulation, safeguarding_failure.
thoroughnessEchoes the requested mode ("fast", "auto", or "thorough"). "auto" is the default — single-pass on long inputs, auto-escalates to a small parallel ensemble on short inputs that benefit from disambiguation.
confidenceSingle scalar in [0, 1] derived from variant agreement (high = robust call; low = borderline). null when thoroughness="fast".
stabilityPer-axis robustness breakdown feeding confidence. null when thoroughness="fast".
trajectorySampled array [{role, turn, salience, signals_by_axis}] when per_turn=true is requested. The default stride is 3, sampled backward from the final message. Set trajectory_stride=1 to request every message. turn values are 0-based positions in the messages array.
meta{ version, inference_ms, windowed, windows }. windowed / windows report whether a long input was scored in multiple windows (and how many). The model version is opaque — pin or alert on changes if your scoring is calibrated to a specific release.

Trajectory indexing and axis keys

The returned trajectory can contain fewer entries than the input has messages. The onsets values in trajectory_shape are 0-based message positions. Its phases and slopes align to the sampled trajectory entries, and peak_turn is an index into the returned trajectory array. A shape can be absent when only one trajectory entry was scored.

The per-entry signals_by_axis vocabulary uses user-axis names such as suicide, AI-axis names prefixed with ai_ such as ai_manipulation, and the context scalars fiction and genuine.

Level values

Both signals.user and signals.ai axes draw their level from a fixed ladder: minimal, low, moderate, high, critical. When you do route on an axis, prefer its level over the raw score. The level mapping has been tuned against curated and red-team fixtures.

Axis levels are independently calibrated from the overall salience bands. A critical axis level can therefore appear with a score or overall salience below 0.5. Do not convert an individual axis score using the salience thresholds.

Identity fields (optional)

Three opaque string fields let you tie calls back to your own analytics in the dashboard:

  • user_id — your identifier for the end-user
  • session_id — your identifier for the conversation
  • agent_id — your identifier for the AI agent / persona

Each is optional, 1–256 characters. We do not parse, hash, or interpret these values — they're stored alongside the call metadata so the dashboard can show per-user and per-agent breakdowns.

Privacy: identity values stay on the NOPE side. They are not forwarded to the underlying classifier model and are never shared between customers. To rotate, change the identifier — old rows retain the prior value.

Pricing

$0.0001 per call. Deducted from prepaid balance like every other /v1/* endpoint. The X-Cost and X-Balance response headers report the cost and remaining balance.

What Ocular is not

  • Not predictive or diagnostic. Ocular surfaces behavioral signals, not a clinical tool. Scores indicate signal, not prognosis.
  • Not a moderation pipeline. Use Ocular signals to decide which conversations deserve human attention, not as automated takedowns.
  • Not a replacement for Evaluate. Evaluate returns severity bands and a structured feature set; Ocular returns axis signals from a behavioral embedding classifier. They're complementary.

Next steps