Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# CODEOWNERS file for managing repository permissions
# Format: path-pattern @username @org/team-name

# Maintainers: Default owners for all files
* @roostorg/roosters

8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Example [COOP](https://github.com/roostorg/coop) integration plugin. Reference r

- **Integration:** `COOP_INTEGRATION_EXAMPLE`
- **Signal 1 – Random Signal Selection** (`RANDOM_SIGNAL_SELECTION`): Returns `true` or `false` at random. The probability (0–100%) comes from the org’s integration config (“True percentage”). Set e.g. `70` in Org settings → Integrations; the signal returns `true` about 70% of the time. Use this to test config saving and boolean conditions.
- **Signal 2 – Random Score** (`RANDOM_SCORE`): Returns a random number between 0 and 1. No integration config needed. In the rule builder you set a **threshold** (e.g. `0.5`) and choose **above** or **below**. Use this to test numeric score conditions (e.g. “score ≥ 0.5” or “score < 0.3”).
- **Signal 2 – Random Score** (`RANDOM_SCORE`): Returns a random number from **0 up to (but not including) 100**—the same 0–100 style as “True percentage,” so thresholds feel consistent. No integration config needed. In the rule builder set a **threshold** (e.g. `50`) and choose **above** or **below**. Use this to test numeric score conditions (e.g. “score ≥ 50” or “score < 30”).

## Install

Expand Down Expand Up @@ -61,17 +61,17 @@ Restart the COOP server so it loads the plugin.
1. **Org settings → Integrations** – you should see “COOP Integration Example”. Open it and set **True percentage (0–100)** (e.g. `70`) for Random Signal Selection. Save.
2. **Rules (routing or enforcement)** – when adding a condition:
- **Random Signal Selection**: Pick that signal; the condition uses your configured percentage (true/false).
- **Random Score**: Pick “Random Score”, then set a **threshold** (e.g. `0.5`) and choose **above** or **below**. The rule compares the random score to your threshold.
- **Random Score**: Pick “Random Score”, then set a **threshold** on the 0–100 scale (e.g. `50`) and choose **above** or **below**. The rule compares the random score to your threshold.

## Contract

This package implements the COOP plugin contract from `@roostorg/types`:

- **Default export:** `CoopIntegrationPlugin` with `manifest` and `createSignals(context)`.
- **Manifest:** `id`, `name`, `version`, `requiresConfig`, `configurationFields`, `signalTypeIds`, `modelCard` (with required sections `modelDetails` and `technicalIntegration`).
- **Manifest:** `id`, `name`, `version`, `requiresConfig`, `configurationFields`, `signalTypeIds`, `modelCard` (must include every section id in `REQUIRED_MODEL_CARD_SECTION_IDS` from `@roostorg/types`; call `assertModelCardHasRequiredSections(modelCard)` when registering).
- **createSignals:** Returns two descriptors:
- `RANDOM_SIGNAL_SELECTION`: `run(input)` uses `context.getCredential(orgId)` for true percentage; returns `{ outputType: { scalarType: 'BOOLEAN' }, score: boolean }`.
- `RANDOM_SCORE`: `run()` returns `{ outputType: { scalarType: 'NUMBER' }, score: number }` in [0, 1]; no config. Threshold is set in the rule (above/below).
- `RANDOM_SCORE`: `run()` returns `{ outputType: { scalarType: 'NUMBER' }, score: number }` in **[0, 100)** (`Math.random() * 100`); no config. Threshold is set in the rule on the same scale (above/below).

## Publishing

Expand Down
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@roostorg/coop-integration-example",
"version": "1.0.0",
"version": "2.0.0",
"description": "Example package to show how a custom integration and signal can be used in COOP this is meant to be a reference repository and provide basic determination",
"type": "module",
"main": "dist/index.js",
Expand All @@ -23,7 +23,7 @@
"example"
],
"author": "Roostorg",
"license": "apache-2.0",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/roostorg/coop-integration-example.git"
Expand All @@ -33,10 +33,10 @@
},
"homepage": "https://github.com/roostorg/coop-integration-example#readme",
"peerDependencies": {
"@roostorg/types": ">=1.0.0"
"@roostorg/types": ">=2.0.0"
},
"devDependencies": {
"@roostorg/types": "^1.1.1",
"@roostorg/types": "^2.0.0",
"typescript": "^5.0.0"
},
"engines": {
Expand Down
118 changes: 90 additions & 28 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
/**
* Example COOP integration plugin with two signal types:
* 1. Random Signal Selection – boolean, probability from org config (tests config saving).
* 2. Random Score – numeric [0, 1], threshold set in the rule (tests score vs threshold).
* 2. Random Score – numeric 0–100, threshold set in the rule (tests score vs threshold).
*/

import type {
CoopIntegrationPlugin,
IntegrationManifest,
ModelCard,
PluginSignalContext,
PluginSignalDescriptor,
import {
assertModelCardHasRequiredSections,
type CoopIntegrationPlugin,
type IntegrationManifest,
type ModelCard,
type PluginSignalContext,
type PluginSignalDescriptor,
} from '@roostorg/types';

const SIGNAL_TYPE_RANDOM_SELECTION = 'RANDOM_SIGNAL_SELECTION';
Expand All @@ -19,49 +20,111 @@ const DEFAULT_TRUE_PERCENTAGE = 50;

const modelCard: ModelCard = {
modelName: 'COOP Integration Example',
version: '1.0.0',
releaseDate: '2026',
version: '2.0.0',
releaseDate: 'March 2026',
sections: [
{
id: 'modelDetails',
title: 'Model Details',
id: 'trainingData',
title: 'Training Data',
fields: [
{ label: 'Model Name', value: 'COOP Integration Example' },
{
label: 'Purpose',
label: 'Overview',
value:
'Example plugin with two signals: one uses org config (boolean), one returns a numeric score so you can set a threshold in the rule (over/under).',
'This reference integration does not use a trained model. Outputs are randomly generated for demonstration and testing of COOP rules, configuration, and UI only.',
},
],
},
{
id: 'policyAndTaxonomy',
title: 'Policy and Taxonomy',
fields: [
{
label: 'Scope',
value:
'Not a content policy engine. Signals are placeholders: boolean “coin flip” with configurable probability and a numeric random score for threshold exercises in rules.',
},
],
},
{
id: 'annotationMethodology',
title: 'Annotation Methodology',
fields: [
{
label: 'Method',
value:
'No human or automated labeling pipeline. Values are produced with Math.random() (or equivalent logic) at evaluation time.',
},
],
},
{
id: 'performanceBenchmarks',
title: 'Performance and Benchmarks',
fields: [
{
label: 'Benchmarks',
value:
'No precision, recall, or latency benchmarks apply. Do not use performance claims from this package in production decisions.',
},
],
},
{
id: 'biasAndLimitations',
title: 'Bias and Limitations',
fields: [
{
label: 'Limitations',
value:
'Outputs are uncorrelated with input content. Unsuitable for safety, compliance, or moderation decisions. For integration testing and developer learning only.',
},
],
},
{
id: 'implementationGuidance',
title: 'Implementation Guidance',
fields: [
{
label: 'Signals',
value: `${SIGNAL_TYPE_RANDOM_SELECTION} (boolean, config-driven) and ${SIGNAL_TYPE_RANDOM_SCORE} (number 0–1, threshold in rule).`,
value: `${SIGNAL_TYPE_RANDOM_SELECTION} (boolean; org config truePercentage 0–100). ${SIGNAL_TYPE_RANDOM_SCORE} (number 0–100; set threshold and above/below in the rule).`,
},
{
label: 'Configuration',
value:
'Random Signal Selection requires org integration config (true percentage). Random Score requires no integration config.',
},
{
label: 'Versioning',
value:
'modelCard.version and manifest.version identify this integration plugin release. They are independent of the @roostorg/types dependency major version (e.g. 2.x).',
},
],
},
{
id: 'technicalIntegration',
title: 'Technical Integration',
id: 'relevantLinks',
title: 'Relevant Links',
fields: [
{
label: 'Signal types',
value: `${SIGNAL_TYPE_RANDOM_SELECTION}, ${SIGNAL_TYPE_RANDOM_SCORE}`,
label: 'Repository',
value: 'https://github.com/roostorg/coop-integration-example',
},
{
label: 'Config',
value: 'truePercentage (0–100) for Random Signal Selection only; Random Score needs no config.',
label: 'Documentation',
value: 'https://roostorg.github.io/coop/INTEGRATIONS_PLUGIN.html',
},
],
},
],
};

assertModelCardHasRequiredSections(modelCard);

const manifest: IntegrationManifest = {
id: INTEGRATION_ID,
name: 'COOP Integration Example',
version: '1.0.0',
/** Same semver as modelCard.version: this plugin’s release, not @roostorg/types. */
version: '2.0.0',
description:
'Example plugin with two signals: config-driven boolean and a numeric score you compare with a threshold in the rule.',
docsUrl: 'https://github.com/roostorg/coop/tree/main/coop-integration-example',
docsUrl: 'https://roostorg.github.io/coop/INTEGRATIONS_PLUGIN.html',
requiresConfig: true,
configurationFields: [
{
Expand Down Expand Up @@ -158,11 +221,11 @@ function createRandomScoreDescriptor(
id: { type: SIGNAL_TYPE_RANDOM_SCORE },
displayName: 'Random Score',
description:
'Returns a random number between 0 and 1. Set a threshold in the rule (e.g. 0.5) and choose "above" or "below" to test numeric conditions.',
'Returns a random number from 0 up to (but not including) 100. Set a threshold in the rule (e.g. 50) and choose "above" or "below" to test numeric conditions.',
docsUrl: null,
recommendedThresholds: {
highPrecisionThreshold: 0.5,
highRecallThreshold: 0.5,
highPrecisionThreshold: 50,
highRecallThreshold: 50,
},
supportedLanguages: 'ALL',
pricingStructure: { type: 'FREE' },
Expand All @@ -178,8 +241,7 @@ function createRandomScoreDescriptor(
async run(
_input: unknown,
): Promise<{ outputType: typeof outputType; score: number }> {
// Returns a random number between 0 and 100.
// Because outputType is { scalarType: 'NUMBER' }, Coop can take the score and compare it to a threshold in the rule.
// [0, 100) — same scale as percentages elsewhere in this plugin (e.g. truePercentage).
const score = Math.random() * 100;
return { outputType, score };
},
Expand Down
Loading