Mirror of https://github.com/roostorg/coop github.com/roostorg/coop
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[Model Cards] Update required fields and mark current as TBD (#130)

* [Model Cards] Update required fields and mark current as TBD

* update package version

authored by

Juan Mrad and committed by
GitHub
3855d1fa 9a40fa6c

+163 -161
+15 -9
client/src/webpages/dashboard/integrations/IntegrationConfigApiCredentialsSection.tsx
··· 12 12 name: string; 13 13 setApiCredential: (cred: GQLIntegrationApiCredential) => void; 14 14 apiCredential: GQLIntegrationApiCredential; 15 + compact?: boolean; 15 16 }) { 16 - const { setApiCredential, apiCredential } = props; 17 + const { setApiCredential, apiCredential, compact } = props; 18 + const inputWidthClass = compact ? 'w-full' : 'w-1/2'; 17 19 18 20 const renderGoogleContentSafetyApiCredential = ( 19 21 apiCredential: GQLGoogleContentSafetyApiIntegrationApiCredential, 20 22 ) => { 21 23 return ( 22 - <div className="flex flex-col w-1/2"> 24 + <div className={`flex flex-col ${inputWidthClass}`}> 23 25 <div className="mb-1">API Key</div> 24 26 <Input 25 27 value={apiCredential.apiKey} ··· 38 40 apiCredential: GQLOpenAiIntegrationApiCredential, 39 41 ) => { 40 42 return ( 41 - <div className="flex flex-col w-1/2"> 43 + <div className={`flex flex-col ${inputWidthClass}`}> 42 44 <div className="mb-1">API Key</div> 43 45 <Input 44 46 value={apiCredential.apiKey} ··· 88 90 89 91 return ( 90 92 <div className="flex flex-col gap-4"> 91 - <div className="flex flex-col w-1/2"> 93 + <div className={`flex flex-col ${inputWidthClass}`}> 92 94 <div className="mb-1">API Key</div> 93 95 <Input 94 96 value={apiCredential.apiKey} ··· 100 102 } 101 103 /> 102 104 </div> 103 - <div className="flex flex-col w-1/2"> 105 + <div className={`flex flex-col ${inputWidthClass}`}> 104 106 <div className="mb-2 font-semibold">Labeler Versions</div> 105 107 {labelerVersions.map((version, index) => ( 106 - <div key={index} className="flex items-center gap-2 mb-2"> 108 + <div 109 + key={index} 110 + className={`flex gap-2 mb-2 ${compact ? 'flex-col' : 'flex-row items-center'}`} 111 + > 107 112 <Input 108 113 placeholder="Version ID" 109 114 value={version.id} ··· 125 130 icon={<Trash2 size={14} />} 126 131 onClick={() => removeLabelerVersion(index)} 127 132 danger 133 + className={compact ? 'self-end' : ''} 128 134 /> 129 135 </div> 130 136 ))} 131 137 <Button 132 138 type="dashed" 133 - icon={<Plus size={14} />} 139 + icon={<Plus size={14} className="inline-block" />} 134 140 onClick={addLabelerVersion} 135 - className="w-fit" 141 + className={compact ? 'w-full' : 'w-fit'} 136 142 > 137 143 Add Labeler Version 138 144 </Button> ··· 159 165 return ( 160 166 <div className="flex flex-col gap-4"> 161 167 {fieldsToShow.map(([key, value]) => ( 162 - <div key={key} className="flex flex-col w-1/2"> 168 + <div key={key} className={`flex flex-col ${inputWidthClass}`}> 163 169 <div className="mb-1"> 164 170 {PLUGIN_FIELD_LABELS[key] ?? key} 165 171 </div>
+5 -4
client/src/webpages/dashboard/integrations/IntegrationConfigForm.tsx
··· 457 457 </div> 458 458 459 459 {hasModelCard && apiModelCard ? ( 460 - <div className="flex flex-col lg:flex-row gap-8 w-full max-w-5xl"> 460 + <div className="flex flex-col lg:flex-row gap-8 w-full max-w-7xl"> 461 461 <div className="flex-1 min-w-0"> 462 462 <ModelCardView card={apiModelCard} /> 463 463 </div> 464 - <div className="flex flex-col lg:w-80 shrink-0"> 464 + <div className="flex flex-col lg:w-96 shrink-0"> 465 465 {apiModelCardLearnMoreUrl != null && ( 466 466 <a 467 467 href={apiModelCardLearnMoreUrl} ··· 473 473 <span>Learn more about how to read model cards</span> 474 474 </a> 475 475 )} 476 - <div className="font-semibold text-zinc-800 mb-2">Credentials</div> 476 + <div className="font-semibold text-zinc-800 mb-2">Configuration</div> 477 477 <div className="text-sm text-zinc-600 mb-3"> 478 - Configure your credentials below. 478 + Configure your integration settings below. 479 479 </div> 480 480 <IntegrationConfigApiCredentialsSection 481 481 name={integrationName} ··· 483 483 setApiCredential={(cred: GQLIntegrationApiCredential) => 484 484 setApiCredential(cred) 485 485 } 486 + compact 486 487 /> 487 488 {saveButton} 488 489 </div>
+119 -128
server/services/integrationRegistry/integrationManifests.ts
··· 4 4 * Lives in the registry (not graphql) so transport-agnostic code can import it. 5 5 */ 6 6 7 - const REQUIRED_SECTION_IDS = ['modelDetails', 'technicalIntegration'] as const; 7 + const REQUIRED_SECTION_IDS = [ 8 + 'trainingData', 9 + 'policyAndTaxonomy', 10 + 'annotationMethodology', 11 + 'performanceBenchmarks', 12 + 'biasAndLimitations', 13 + 'implementationGuidance', 14 + 'relevantLinks', 15 + ] as const; 8 16 9 17 export type ModelCardField = Readonly<{ label: string; value: string }>; 10 18 export type ModelCardSubsection = Readonly<{ ··· 41 49 42 50 function assertModelCardHasRequiredSections(card: ModelCard): void { 43 51 const sectionIds = new Set((card.sections ?? []).map((s) => s.id)); 44 - for (const requiredId of REQUIRED_SECTION_IDS) { 45 - if (!sectionIds.has(requiredId)) { 46 - throw new Error( 47 - `Model card must include a section with id "${requiredId}".`, 48 - ); 49 - } 52 + const missing = REQUIRED_SECTION_IDS.filter((id) => !sectionIds.has(id)); 53 + if (missing.length > 0) { 54 + throw new Error( 55 + `Model card is missing required section(s): ${missing.map((id) => `"${id}"`).join(', ')}.`, 56 + ); 50 57 } 51 58 } 52 59 ··· 57 64 releaseDate: 'Ongoing', 58 65 sections: [ 59 66 { 60 - id: 'modelDetails', 61 - title: 'Model Details', 62 - subsections: [ 63 - { 64 - title: 'Basic Information', 65 - fields: [ 66 - { label: 'Model Name', value: 'Content Safety API' }, 67 - { label: 'Developed By', value: 'Google' }, 68 - { 69 - label: 'Documentation URL', 70 - value: 'https://protectingchildren.google/tools-for-partners/', 71 - }, 72 - ], 73 - }, 74 - { 75 - title: 'Intended Use', 76 - fields: [ 77 - { 78 - label: 'Primary Use Case', 79 - value: 80 - 'Child safety prioritization recommendations on user-generated content.', 81 - }, 82 - { 83 - label: 'Target Users', 84 - value: 'Platforms and partners conducting content moderation.', 85 - }, 86 - { 87 - label: 'Important Note', 88 - value: 89 - 'Users must conduct their own manual review and comply with applicable reporting laws. The API does not replace human judgment.', 90 - }, 91 - ], 92 - }, 93 - ], 67 + id: 'trainingData', 68 + title: 'Training Data Sources', 69 + fields: [{ label: 'Data Sources', value: 'TBD' }], 94 70 }, 95 71 { 96 - id: 'technicalIntegration', 97 - title: 'Technical Integration', 72 + id: 'policyAndTaxonomy', 73 + title: 'Policy & Taxonomy Definitions', 74 + fields: [{ label: 'Policies', value: 'TBD' }], 75 + }, 76 + { 77 + id: 'annotationMethodology', 78 + title: 'Annotation Methodology', 79 + fields: [{ label: 'Methodology', value: 'TBD' }], 80 + }, 81 + { 82 + id: 'performanceBenchmarks', 83 + title: 'Performance Benchmarks', 84 + fields: [{ label: 'Benchmarks', value: 'TBD' }], 85 + }, 86 + { 87 + id: 'biasAndLimitations', 88 + title: 'Bias Documentation & Known Limits', 89 + fields: [{ label: 'Known Limitations', value: 'TBD' }], 90 + }, 91 + { 92 + id: 'implementationGuidance', 93 + title: 'Implementation Guidance', 98 94 fields: [ 99 95 { 100 96 label: 'Authentication', ··· 107 103 }, 108 104 ], 109 105 }, 106 + { 107 + id: 'relevantLinks', 108 + title: 'Relevant Links', 109 + fields: [ 110 + { 111 + label: 'Documentation', 112 + value: 'https://protectingchildren.google/tools-for-partners/', 113 + }, 114 + { 115 + label: 'Model Cards', 116 + value: 'https://modelcards.withgoogle.com/', 117 + }, 118 + ], 119 + }, 110 120 ], 111 121 }, 112 122 modelCardLearnMoreUrl: 'https://modelcards.withgoogle.com/', ··· 122 132 releaseDate: 'January 2026', 123 133 sections: [ 124 134 { 125 - id: 'modelDetails', 126 - title: 'Model Details', 127 - subsections: [ 128 - { 129 - title: 'Basic Information', 130 - fields: [ 131 - { label: 'Model Name', value: 'OpenAI' }, 132 - { label: 'Version', value: 'v0.0' }, 133 - { label: 'Release Date', value: 'January 2026' }, 134 - { label: 'License Type', value: 'API Access Only' }, 135 - { 136 - label: 'Documentation URL', 137 - value: 'https://platform.openai.com/docs', 138 - }, 139 - ], 140 - }, 141 - { 142 - title: 'Model Architecture', 143 - fields: [ 144 - { label: 'Base Architecture', value: 'Transformer-based' }, 145 - { 146 - label: 'Input/output specifications', 147 - value: 148 - 'API-dependent; see OpenAI documentation for the specific model in use.', 149 - }, 150 - ], 151 - }, 152 - { 153 - title: 'Intended Use', 154 - fields: [ 155 - { 156 - label: 'Primary Use Case', 157 - value: 158 - 'Content moderation and safety-related classification via OpenAI APIs.', 159 - }, 160 - { 161 - label: 'Target Users', 162 - value: 'Platforms using Coop for moderation.', 163 - }, 164 - { 165 - label: 'Deployment Context', 166 - value: 'Used within Coop to call OpenAI APIs with your API key.', 167 - }, 168 - ], 169 - }, 170 - ], 135 + id: 'trainingData', 136 + title: 'Training Data Sources', 137 + fields: [{ label: 'Data Sources', value: 'TBD' }], 138 + }, 139 + { 140 + id: 'policyAndTaxonomy', 141 + title: 'Policy & Taxonomy Definitions', 142 + fields: [{ label: 'Policies', value: 'TBD' }], 143 + }, 144 + { 145 + id: 'annotationMethodology', 146 + title: 'Annotation Methodology', 147 + fields: [{ label: 'Methodology', value: 'TBD' }], 148 + }, 149 + { 150 + id: 'performanceBenchmarks', 151 + title: 'Performance Benchmarks', 152 + fields: [{ label: 'Benchmarks', value: 'TBD' }], 153 + }, 154 + { 155 + id: 'biasAndLimitations', 156 + title: 'Bias Documentation & Known Limits', 157 + fields: [{ label: 'Known Limitations', value: 'TBD' }], 171 158 }, 172 159 { 173 - id: 'technicalIntegration', 174 - title: 'Technical Integration', 160 + id: 'implementationGuidance', 161 + title: 'Implementation Guidance', 175 162 fields: [ 176 163 { 177 164 label: 'Credentials', 178 165 value: 'This integration requires one API Key.', 179 166 }, 167 + ], 168 + }, 169 + { 170 + id: 'relevantLinks', 171 + title: 'Relevant Links', 172 + fields: [ 180 173 { 181 174 label: 'Documentation', 182 175 value: 'https://platform.openai.com/docs', ··· 198 191 releaseDate: 'Ongoing', 199 192 sections: [ 200 193 { 201 - id: 'modelDetails', 202 - title: 'Model Details', 203 - subsections: [ 194 + id: 'trainingData', 195 + title: 'Training Data Sources', 196 + fields: [{ label: 'Data Sources', value: 'TBD' }], 197 + }, 198 + { 199 + id: 'policyAndTaxonomy', 200 + title: 'Policy & Taxonomy Definitions', 201 + fields: [{ label: 'Policies', value: 'TBD' }], 202 + }, 203 + { 204 + id: 'annotationMethodology', 205 + title: 'Annotation Methodology', 206 + fields: [{ label: 'Methodology', value: 'TBD' }], 207 + }, 208 + { 209 + id: 'performanceBenchmarks', 210 + title: 'Performance Benchmarks', 211 + fields: [{ label: 'Benchmarks', value: 'TBD' }], 212 + }, 213 + { 214 + id: 'biasAndLimitations', 215 + title: 'Bias Documentation & Known Limits', 216 + fields: [{ label: 'Known Limitations', value: 'TBD' }], 217 + }, 218 + { 219 + id: 'implementationGuidance', 220 + title: 'Implementation Guidance', 221 + fields: [ 204 222 { 205 - title: 'Basic Information', 206 - fields: [ 207 - { label: 'Model Name', value: 'Zentropi' }, 208 - { label: 'Developed By', value: 'Zentropi' }, 209 - { 210 - label: 'Documentation URL', 211 - value: 'https://docs.zentropi.ai', 212 - }, 213 - ], 214 - }, 215 - { 216 - title: 'Intended Use', 217 - fields: [ 218 - { 219 - label: 'Primary Use Case', 220 - value: 221 - 'Content labeling and moderation via configurable labeler versions.', 222 - }, 223 - { 224 - label: 'Target Users', 225 - value: 'Platforms using Coop with Zentropi labelers.', 226 - }, 227 - { 228 - label: 'Integration Points', 229 - value: 230 - 'API key plus optional labeler versions (id and label) for each model you use.', 231 - }, 232 - ], 223 + label: 'Credentials', 224 + value: 225 + 'API Key plus optional Labeler Versions (id and label per version).', 233 226 }, 234 227 ], 235 228 }, 236 229 { 237 - id: 'technicalIntegration', 238 - title: 'Technical Integration', 230 + id: 'relevantLinks', 231 + title: 'Relevant Links', 239 232 fields: [ 240 233 { 241 - label: 'Credentials', 242 - value: 243 - 'API Key plus optional Labeler Versions (id and label per version).', 234 + label: 'Documentation', 235 + value: 'https://docs.zentropi.ai', 244 236 }, 245 - { label: 'Documentation', value: 'https://docs.zentropi.ai' }, 246 237 ], 247 238 }, 248 239 ],
+1 -2
server/services/integrationRegistry/loadPlugins.ts
··· 178 178 logoUrl, 179 179 logoWithBackgroundUrl, 180 180 }; 181 - // Plugin manifest may omit modelCard; we require it for display. 182 181 if ((serverEntry as { modelCard?: ModelCard }).modelCard == null) { 183 182 throw new Error( 184 - `Integration "${id}" (${packageSpec}) must provide a modelCard with at least "modelDetails" and "technicalIntegration" sections.`, 183 + `Integration "${id}" (${packageSpec}) must provide a modelCard with all required sections (see REQUIRED_MODEL_CARD_SECTION_IDS).`, 185 184 ); 186 185 } 187 186 map.set(id, serverEntry);
+20 -15
types/integration.ts
··· 39 39 * Either subsections (with bold sub-headings) or top-level fields, or both. 40 40 */ 41 41 export type ModelCardSection = Readonly<{ 42 - /** Stable id for the section (e.g. "modelDetails", "trainingData"). */ 42 + /** Stable id for the section (e.g. "trainingData", "biasAndLimitations"). */ 43 43 id: string; 44 44 /** Display title (e.g. "Model Details"). */ 45 45 title: string; ··· 73 73 * Use assertModelCardHasRequiredSections() to validate at runtime. 74 74 */ 75 75 export const REQUIRED_MODEL_CARD_SECTION_IDS = [ 76 - 'modelDetails', 77 - 'technicalIntegration', 76 + 'trainingData', 77 + 'policyAndTaxonomy', 78 + 'annotationMethodology', 79 + 'performanceBenchmarks', 80 + 'biasAndLimitations', 81 + 'implementationGuidance', 82 + 'relevantLinks', 78 83 ] as const; 79 84 80 85 /** 81 - * Asserts that a model card has at least the required sections (basic information 82 - * and technical integration). Call when registering integration manifests. 86 + * Asserts that a model card has at least the required sections. 87 + * Call when registering integration manifests. 83 88 * @throws Error if any required section id is missing 84 89 */ 85 90 export function assertModelCardHasRequiredSections(card: ModelCard): void { 86 91 const sectionIds = new Set((card.sections ?? []).map((s) => s.id)); 87 - for (const requiredId of REQUIRED_MODEL_CARD_SECTION_IDS) { 88 - if (!sectionIds.has(requiredId)) { 89 - throw new Error( 90 - `Model card must include a section with id "${requiredId}" (e.g. Basic Information / Model Details and Technical Integration).`, 91 - ); 92 - } 92 + const missing = REQUIRED_MODEL_CARD_SECTION_IDS.filter( 93 + (id) => !sectionIds.has(id), 94 + ); 95 + if (missing.length > 0) { 96 + throw new Error( 97 + `Model card is missing required section(s): ${missing.map((id) => `"${id}"`).join(', ')}.`, 98 + ); 93 99 } 94 100 } 95 101 ··· 141 147 signalTypeIds?: readonly string[]; 142 148 /** 143 149 * Model card: structured metadata (model name, version, sections) for the UI. 144 - * When present, the integration detail page renders it. Built-in integrations 145 - * should always provide a model card with at least sections "modelDetails" and 146 - * "technicalIntegration"; use assertModelCardHasRequiredSections() when 147 - * registering. 150 + * When present, the integration detail page renders it. Integrations must 151 + * include all sections listed in REQUIRED_MODEL_CARD_SECTION_IDS; use 152 + * assertModelCardHasRequiredSections() when registering. 148 153 */ 149 154 modelCard?: ModelCard; 150 155 /**
+2 -2
types/package-lock.json
··· 1 1 { 2 2 "name": "@roostorg/types", 3 - "version": "1.1.1", 3 + "version": "2.0.0", 4 4 "lockfileVersion": 2, 5 5 "requires": true, 6 6 "packages": { 7 7 "": { 8 8 "name": "@roostorg/types", 9 - "version": "1.1.1", 9 + "version": "2.0.0", 10 10 "license": "ISC", 11 11 "dependencies": { 12 12 "date-fns": "^2.29.3",
+1 -1
types/package.json
··· 1 1 { 2 2 "name": "@roostorg/types", 3 3 "type": "module", 4 - "version": "1.1.1", 4 + "version": "2.0.0", 5 5 "description": "Shared types across Coop services", 6 6 "module": "transpiled/index.js", 7 7 "typings": "./transpiled/index.d.ts",