Skip to main content

Composable safety primitives

Tuteliq isn’t a set of independent detectors — it’s a platform where detectors enrich each other. The detect_vulnerability_exploitation endpoint returns two fields, cross_endpoint_modifier and vulnerability_profile, that agents use to amplify risk verdicts from sibling detectors and route to vulnerability-appropriate intervention workflows. This page explains the primitive and shows how to compose with it.

Why this matters

Most safety APIs return per-call classifications: is this content X? That’s enough if every harm is independent. But real harm rarely is. A grooming pattern targeting an emotionally vulnerable minor is structurally different from the same pattern targeting an emotionally stable adult — and an effective safety system has to weight signals by who the target is, not just what the content says. Tuteliq exposes that weighting as a primitive your agents compose, rather than burying it inside opaque score adjustments.

The fields

cross_endpoint_modifier

A numeric multiplier (typical range 1.0–2.0) you apply to another endpoint’s risk_score when both endpoints detect a pattern in the same content. A modifier of 1.6 means: “the vulnerability signals here amplify any concurrent grooming, scam, or coercion signal by 60%.”

vulnerability_profile

A four-dimensional decomposition of the target’s vulnerability, each scored 0.0–1.0: Agents route differently based on which dimension is highest — a high emotional_vulnerability plus a romance_scam signal calls for a slower, gentler intervention; a high situational_vulnerability plus a financial_grooming signal might trigger an immediate transaction hold.

Example response

Composing with another detector

The intended pattern is: run detect_vulnerability_exploitation in parallel with the harm-specific detector for the same content, then combine.
In Python:

When to use this primitive

  • You’re building an agent that takes graduated actions based on combined risk, not single-detector verdicts.
  • You’re moderating populations where target vulnerability is highly variable — mixed-age platforms, fintech, dating apps, AI companion products.
  • You want intervention workflows that adapt to the user, not just the content.

When not to use it

  • You’re running a fixed-threshold per-message classifier and only need a single binary verdict — recommended_action from each endpoint is enough.
  • You’re moderating content at the corpus level (e.g. AI training data) rather than per-user signals — vulnerability doesn’t apply.

Notes on safe composition

  • Cap the compound risk at 1.0 (Math.min(scam.risk_score * modifier, 1.0)) so amplification never produces an out-of-band value downstream consumers don’t expect.
  • The modifier is only meaningful when both endpoints actually detect — if vuln.detected === false, treat the modifier as 1.0.
  • Cache the profile per-conversation, not per-message — a vulnerability read stays roughly stable across a single conversation, so re-running it on every message adds latency without changing the answer. This is guidance about your caching layer, not a Tuteliq-side store — see Privacy and data handling below. Refresh periodically or on context changes (e.g. a major life event surfaced in subsequent messages), and apply your own retention limits.
  • Don’t expose the raw modifier to end users. It’s an integrator-level signal designed for routing logic, not for display. Surface the resulting route and the human-readable rationale instead.

Privacy and data handling

detect_vulnerability_exploitation, like every Tuteliq detection endpoint, is stateless and server-to-server:
  • No persistent identifier. No request or response field in this API — or anywhere in Tuteliq’s detection surface — asks for or returns a user_id, device_id, or other end-user identifier. vulnerability_profile is computed fresh from the content (and optional conversation_history) submitted in that one call; it is not looked up against, or written to, a stored profile of any individual.
  • No server-side profiling. Tuteliq does not build, persist, or accumulate a vulnerability profile per user across calls. Each response reflects only what was in that request. If you want profile continuity across a conversation, that’s the client-side caching described above — a decision (and a data-retention obligation) that belongs to you as the integrator, not something Tuteliq does on your behalf.
  • Server-to-server only. Detection runs on Tuteliq’s infrastructure. SDK calls (tuteliq.safety.vulnerabilityExploitation(...)) are thin clients that call the hosted API — nothing in this composition pattern, or in any Tuteliq SDK, runs inference on the end user’s device.
  • The age_group / age fields elsewhere in the API are optional inputs, not requirements. Detectors that accept an age or age-bracket field (e.g. detect_grooming’s context.child_age) work without it; supplying it sharpens the analysis but is never mandatory.
If your own integration persists vulnerability_profile results (per the caching guidance above), that data lives in your systems under your own privacy and retention policies — Tuteliq’s involvement ends at the response of each stateless call.

Carrying a signal forward

Some findings are about a person rather than a message, and stay true on that person’s next request. Tuteliq does not keep such a finding against the user between calls (see Stateless by Design), so the platform carries the signal forward itself. The clearest case is minor_disclosure: a speaker on an adult platform who says they are under 18. The pattern:
  1. Store the suggestion on your side. When a response carries minor_disclosure, save minor_disclosure.suggested_age_group against that user in your own records.
  2. Send it back as the declared age. On that user’s later requests, pass the stored value as context.age_group. It is always a minor band (under 18, under 13, 13-15 or 16-17), so the detectors apply a minor’s protections.
  3. A declared child beats an adult setting. With conversation_type dating, adult_community or workplace, a declared minor age group means the adult audience is not used for that request. You do not need to change your platform-wide setting.
Things to know:
  • The check does not repeat. Once a request declares a minor, it no longer declares an adult, so minor_disclosure_check does not run and minor_on_adult_platform_raised is not returned again. The declared age group is now the signal, and the account decision (asking the user to verify their age again, for example) belongs to your own process.
  • On /safety/grooming, which takes ages rather than an age group, declare the user’s messages with a child sender_role, or pass their age, instead of age_group.
  • Decide how long to keep it. The stored value is your data, in your systems, under your own retention and review rules. Tuteliq’s involvement ends with each response.
  • Let a person decide. A finding is a reason to review an account, not proof of age. Route it to a person before you restrict anyone.