Skip to content

Responsible gaming ​

Watching a player's deposits for signs of harm, where rules, a model and your responsible gaming team decide together and every step is on the record: deposit and sign-up events, the net loss and verified age your platform keeps on the player, what the player last wrote to your support team, read by a model, and a responsible gaming case when a rule warns or the model is not sure the player shows no sign of harm. Pack: examples/policies/responsible-gaming/.

A pattern for expressing a gaming and betting policy, not regulatory guidance: the ages, thresholds, questions and fields are placeholders chosen to make the example run; a real policy comes from the business's own rules and the markets it serves. Its read step calls one model app install, chatgpt (The model step).

The decision it automates ​

Whether to take no action (approve), open a responsible gaming case, or block (reject), when your platform starts the run after a deposit. Only the age rule blocks: the model can open a case, but never blocks and never closes one the rules open.

Data expected ​

  • The player as a subject (kind user) with age, netLoss30d and deviceId, written by your platform, and lastContact (channel, text): the player's last message to your support team, when there is one. A player who never wrote is never sent to the model, and the rules decide alone.
  • deposit.made events with an amount, and account.created events with the promoted deviceId key, posted through POST /events.

Steps and rules ​

StepTypeWhy
rulesevaluate_rulesThe responsible-gaming rule set under max_severity; nothing is collected.
routebranchrules.outcome == reject (an age under 21) blocks at once; a player with a lastContact.text goes to read; otherwise manual_review opens a case and the rest closes with no action.
readcall_appchatgpt's decide: two questions about the player's message, answered under ai (The model step).
triagebranchrules.outcome == manual_review opens a case; ai.answers.no_harm_signs.probability >= 0.8 closes with no action; the default (a model that reads signs of harm, or is unsure) opens a case.
reviewcreate_caseresponsible_gaming, priority medium, 4-hour SLA.
decideemit_decisionFrom the rules, or the reviewer's decision.

The rule set responsible-gaming (useCase: monitoring) uses max_severity: a failed block rule rejects, a failed warn rule sends the run to review, and the weights add up to the score.

RuleTypeSeverity, weightFails when
play_age_verifiedcomparisonblock, 100age is under 21, or missing
play_deposit_velocityvelocitywarn, 30deposits sum to more than 1,000 in 24 hours
play_loss_thresholdscore thresholdwarn, 30netLoss30d is above 3,000
play_linked_accountsvelocitywarn, 20more than two account.created events on the device in 30 days

The model step ​

read asks the model two questions about the player's last message. Its state is the step's variables as one JSON object, mapped from subject.lastContact: channel and text.

QuestionTypeAsksUsed by
no_harm_signsyes or no, threshold 0.8Is the message free of signs that gambling is harming the player: chasing losses, borrowed money or money meant for bills, distress, or asking to lift a limit, end a cooling-off period or reverse a withdrawal to keep playing?triage: 0.8 or more closes, with no action, a run every rule passed
markerone of chasing_losses, borrowing, distress, limit_change, noneWhich sign of harm does the message show most clearly?the reviewer, in the run context

The model can open a case the rules would not, never close one they open, and never blocks: an age under 21 blocks before the model is asked. Its answers are a reading of what the player wrote, for your team to act on; they diagnose nothing.

What the vendor sees ​

read sends OpenAI, through the chatgpt install, the two questions (their instructions, criteria and options) and the state: the player's last message to your support team and the channel it came through, and nothing else of the run: not the player's name, age, deposits or losses. What a player writes can speak of their health, their family or their debts, so the step sends the last message alone. It is text the model reads: an instruction written into it at worst closes a run with no action where the rules alone would have closed it (Prompt injection). OpenAI's own terms say what it keeps; the console's preset calls its Responses API with storing off, decisions included (Data protection).

The chatgpt install ​

The pack declares the install it calls, "installs": { "chatgpt": "chatgpt" }; installs are never part of a pack. The admin console's import result installs chatgpt in one click: ChatGPT (OpenAI API) on OpenAI's Responses API, with a sample key in place of yours. Replace the key with your OpenAI API key on the install's page (Connect › Apps › ChatGPT (OpenAI API) › chatgpt, under Keys) or through POST /app-installs/chatgpt/secrets/openaiApiKey.

Until then, the run of a player who wrote to you reaches read, fails there and opens no case; so does a run whose model call fails for another reason, such as an outage that outlasts the retries, an exhausted quota or a refusal. The vendor's answer shows in the invocation record and under the run's app calls. Once the key is in, Replay from step on the run's page runs it again from read (Admin console: Runs). The runs of players who never wrote, and of players under 21, never reach read: the rules decide those whatever the key.

pnpm policy:import reports the install as missing in a workspace without one, where a run that reaches read fails with unknown_install: create it as Installing a model app shows, named chatgpt. Every model app takes the same input and answers in the same shape, so read can call an install of claude or gemini instead, declared in installs with its app, or keep chatgpt with a fallback on a second install that answers while OpenAI is down (Falling back to another install).

What a reviewer sees ​

A responsible_gaming case with the rule results, the player's deposits on the timeline and, when the player wrote to you, the model's answers under ai in the run context: whether it read signs of harm, and which (marker). What follows (a call, a deposit limit) is recorded as the decision's reasons; case.decided tells your platform.

How to adapt it ​

Set the ages and thresholds your markets require, add a call_app step that sends the player a responsible gaming message through an http-api install for your messaging service (Adding a vendor step), and backtest new thresholds over past deposits before publishing. Map more of what the player wrote, such as the last few messages as one text, into text, and move the 0.8 in triage once a backtest shows where your team and the model disagree.

Run it ​

bash
pnpm policy:import examples/policies/responsible-gaming --publish

pnpm policies:check runs three fixtures. The model stub (scripts/ai-stub.mjs) answers for OpenAI, following the cue word in each player's message ([[stub:low]], [[stub:high]]); the pack carries none.

  • expect.json: deposits of $600 and $850 within two hours for a player with a net loss of $900, who asked live chat to lift their deposit limit to win back what they lost this week. The deposit velocity rule fails, the model answers no_harm_signs at 0.05 and marker chasing_losses, and a responsible_gaming case opens. The check closes it with no action (approve) and the run completes with a manual approve.
  • expect-signs-of-harm.json: a player every rule passes, who wrote that they lost the rent money and asked to reverse a withdrawal to keep playing. The model reads signs of harm (0.05), so a case opens that the rules alone would not have opened.
  • expect-no-signs.json: a player every rule passes, asking about a late withdrawal. The model reads no sign of harm (0.95), and the run closes with no action: an automated approve.

Released under the Apache-2.0 License.