diff --git a/.github/workflows/labrinth-build.yml b/.github/workflows/labrinth-build.yml index 950a1337bd..dd19280d2d 100644 --- a/.github/workflows/labrinth-build.yml +++ b/.github/workflows/labrinth-build.yml @@ -86,7 +86,7 @@ jobs: GIT_HASH: ${{ github.sha }} SCCACHE_CACHE_SIZE: ${{ needs.skip-if-clean.outputs.internal == 'true' && '20G' || '' }} RUSTC_WRAPPER: ${{ needs.skip-if-clean.outputs.internal == 'true' && 'sccache' || '' }} - RUST_MIN_STACK: '16777216' + RUST_MIN_STACK: '268435456' steps: - name: Check out code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 diff --git a/apps/docs/public/openapi.yaml b/apps/docs/public/openapi.yaml index 9407d9ac28..a424e7ef4a 100644 --- a/apps/docs/public/openapi.yaml +++ b/apps/docs/public/openapi.yaml @@ -436,7 +436,7 @@ components: - ai_content_code - ai_content_assets - ai_content_text - - ai_content_functionality + - ai_functionality - advertisements - epilepsy_triggers - system_interactions @@ -2202,7 +2202,7 @@ paths: - `ai_content_code` - `ai_content_assets` - `ai_content_text` - - `ai_content_functionality` + - `ai_functionality` - `advertisements` - `epilepsy_triggers` - `system_interactions` diff --git a/apps/frontend/src/components/ui/project-settings/disclosures/AiDisclosureCard.vue b/apps/frontend/src/components/ui/project-settings/disclosures/AiDisclosureCard.vue index e0280d303b..b1883fb6ce 100644 --- a/apps/frontend/src/components/ui/project-settings/disclosures/AiDisclosureCard.vue +++ b/apps/frontend/src/components/ui/project-settings/disclosures/AiDisclosureCard.vue @@ -25,7 +25,7 @@ const emit = defineEmits<{ const { formatMessage } = useVIntl() -const AI_USES: AiUsage[] = ['code', 'assets', 'text', 'functionality'] +const AI_USES: AiUsage[] = ['code', 'assets', 'text'] const messages = defineMessages({ title: { @@ -35,9 +35,8 @@ const messages = defineMessages({ description: { id: 'project.settings.disclosures.ai.description', defaultMessage: `You must enable this if this project contains a substantial amount of AI-generated code, any - assets that are substantially AI-generated, the project's functionality relies on the use of - generative AI, or if any element of your project's page such as description or publishing - relies on generative AI.`, + assets that are substantially AI-generated, or if any element of your project's page such as + description or publishing relies on generative AI.`, }, contentRules: { id: 'project.settings.disclosures.ai.content-rules', diff --git a/apps/frontend/src/components/ui/project-settings/disclosures/AiFunctionalityDisclosureCard.vue b/apps/frontend/src/components/ui/project-settings/disclosures/AiFunctionalityDisclosureCard.vue new file mode 100644 index 0000000000..529c179291 --- /dev/null +++ b/apps/frontend/src/components/ui/project-settings/disclosures/AiFunctionalityDisclosureCard.vue @@ -0,0 +1,67 @@ + + + diff --git a/apps/frontend/src/components/ui/project-settings/disclosures/form.ts b/apps/frontend/src/components/ui/project-settings/disclosures/form.ts index d6cedf831a..5e1ba8e419 100644 --- a/apps/frontend/src/components/ui/project-settings/disclosures/form.ts +++ b/apps/frontend/src/components/ui/project-settings/disclosures/form.ts @@ -22,7 +22,7 @@ function findDisclosure( return disclosures.find((disclosure): disclosure is DisclosureOf => disclosure.type === type) } -type NoteDisclosureType = 'advertisements' | 'epilepsy_triggers' | 'archived' +type NoteDisclosureType = 'ai_functionality' | 'advertisements' | 'epilepsy_triggers' | 'archived' function createNoteModel( disclosures: ProjectDisclosureData[], @@ -66,6 +66,7 @@ export function disclosuresToForm(disclosures: ProjectDisclosureData[]): Disclos uses: ai ? [...(ai.uses ?? [])] : [], note: ai?.note ?? '', }, + aiFunctionality: createNoteModel(disclosures, 'ai_functionality'), advertising: createNoteModel(disclosures, 'advertisements'), paidFeatures: { enabled: isActiveDisclosure(paidFeatures), @@ -110,6 +111,8 @@ export function formToDisclosure( uses: [...form.ai.uses], note: form.ai.note.trim() || null, } + case 'ai_functionality': + return { type: 'ai_functionality', note: form.aiFunctionality.note.trim() || null } case 'advertisements': return { type: 'advertisements', note: form.advertising.note.trim() || null } case 'paid_features': @@ -151,6 +154,9 @@ export function formToDisclosures(form: DisclosureFormState): ProjectDisclosure[ if (form.ai.enabled) { set.push(formToDisclosure(form, 'ai_content')) } + if (form.aiFunctionality.enabled) { + set.push(formToDisclosure(form, 'ai_functionality')) + } if (form.advertising.enabled) { set.push(formToDisclosure(form, 'advertisements')) } diff --git a/apps/frontend/src/components/ui/project-settings/disclosures/index.ts b/apps/frontend/src/components/ui/project-settings/disclosures/index.ts index 085bf22204..3c49f28e9a 100644 --- a/apps/frontend/src/components/ui/project-settings/disclosures/index.ts +++ b/apps/frontend/src/components/ui/project-settings/disclosures/index.ts @@ -1,5 +1,6 @@ export { default as AdvertisingDisclosureCard } from './AdvertisingDisclosureCard.vue' export { default as AiDisclosureCard } from './AiDisclosureCard.vue' +export { default as AiFunctionalityDisclosureCard } from './AiFunctionalityDisclosureCard.vue' export { default as ArchivedDisclosureCard } from './ArchivedDisclosureCard.vue' export { default as DerivativeDisclosureCard } from './DerivativeDisclosureCard.vue' export { default as DisclosureToggleCard } from './DisclosureToggleCard.vue' diff --git a/apps/frontend/src/components/ui/project-settings/disclosures/types.ts b/apps/frontend/src/components/ui/project-settings/disclosures/types.ts index 6983314a98..acf811d467 100644 --- a/apps/frontend/src/components/ui/project-settings/disclosures/types.ts +++ b/apps/frontend/src/components/ui/project-settings/disclosures/types.ts @@ -44,6 +44,7 @@ export type DerivativeDisclosure = { export type DisclosureFormState = { ai: AiDisclosure + aiFunctionality: NoteDisclosure advertising: NoteDisclosure paidFeatures: PaidFeaturesDisclosure telemetry: TelemetryDisclosure diff --git a/apps/frontend/src/locales/en-US/index.json b/apps/frontend/src/locales/en-US/index.json index 38ef534d84..862d471098 100644 --- a/apps/frontend/src/locales/en-US/index.json +++ b/apps/frontend/src/locales/en-US/index.json @@ -3839,11 +3839,20 @@ "project.settings.disclosures.advertising.title": { "message": "Contains advertisements" }, + "project.settings.disclosures.ai-functionality.description": { + "message": "Placeholder" + }, + "project.settings.disclosures.ai-functionality.note-placeholder": { + "message": "e.g. The in-game assistant uses generative AI to generate dialogue." + }, + "project.settings.disclosures.ai-functionality.title": { + "message": "Contains generative AI functionality" + }, "project.settings.disclosures.ai.content-rules": { "message": "Please refer to Section 6 of Modrinth's Content Rules for more information." }, "project.settings.disclosures.ai.description": { - "message": "You must enable this if this project contains a substantial amount of AI-generated code, any\n\t\t\t\tassets that are substantially AI-generated, the project's functionality relies on the use of\n\t\t\t\tgenerative AI, or if any element of your project's page such as description or publishing\n\t\t\t\trelies on generative AI." + "message": "You must enable this if this project contains a substantial amount of AI-generated code, any\n\t\t\t\tassets that are substantially AI-generated, or if any element of your project's page such as\n\t\t\t\tdescription or publishing relies on generative AI." }, "project.settings.disclosures.ai.note-placeholder": { "message": "e.g. The Chinese and Arabic translations are AI-generated." diff --git a/apps/frontend/src/pages/[type]/[project]/settings/disclosures.vue b/apps/frontend/src/pages/[type]/[project]/settings/disclosures.vue index 0d79f28ca8..dd9bc55b39 100644 --- a/apps/frontend/src/pages/[type]/[project]/settings/disclosures.vue +++ b/apps/frontend/src/pages/[type]/[project]/settings/disclosures.vue @@ -22,6 +22,7 @@ import { computed, watch } from 'vue' import { AdvertisingDisclosureCard, AiDisclosureCard, + AiFunctionalityDisclosureCard, ArchivedDisclosureCard, DerivativeDisclosureCard, type DisclosureFormIssue, @@ -293,6 +294,14 @@ const { confirmLeaveModal } = usePageLeaveSafety(hasChanges) (status: DisclosureLockStatus) => setDisclosureLockStatus('ai_content', status) " /> + 'uses' ? 'functionality' +ON CONFLICT (project_id, type) DO NOTHING; + +DELETE FROM project_disclosures +WHERE type = 'ai_content' + AND metadata -> 'uses' ? 'functionality' + AND jsonb_array_length(metadata -> 'uses') = 1; + +UPDATE project_disclosures +SET metadata = jsonb_set(metadata, '{uses}', (metadata -> 'uses') - 'functionality') +WHERE type = 'ai_content' + AND metadata -> 'uses' ? 'functionality'; diff --git a/apps/labrinth/src/models/v3/disclosures.rs b/apps/labrinth/src/models/v3/disclosures.rs index 2c7e7b2a45..48da86e906 100644 --- a/apps/labrinth/src/models/v3/disclosures.rs +++ b/apps/labrinth/src/models/v3/disclosures.rs @@ -18,6 +18,9 @@ pub enum ProjectDisclosure { note: Option, uses: BTreeSet, }, + AiFunctionality { + note: Option, + }, Advertisements { note: Option, }, @@ -161,7 +164,6 @@ pub enum AiUsages { Code, Assets, Text, - Functionality, } #[derive(Debug, Clone, Serialize, Deserialize, ToSchema, IntoStaticStr)] diff --git a/packages/api-client/src/modules/labrinth/types.ts b/packages/api-client/src/modules/labrinth/types.ts index 0c7f1b48ce..e6e512e1bc 100644 --- a/packages/api-client/src/modules/labrinth/types.ts +++ b/packages/api-client/src/modules/labrinth/types.ts @@ -1304,7 +1304,7 @@ export namespace Labrinth { export type TelemetryConsent = 'opt_in' | 'opt_out' | 'always_active' - export type AiUsage = 'code' | 'assets' | 'text' | 'functionality' + export type AiUsage = 'code' | 'assets' | 'text' export type DisclosureLockStatus = 'unlocked' | 'cannot_disable' | 'fully_locked' @@ -1320,6 +1320,10 @@ export namespace Labrinth { uses: AiUsage[] note?: string | null } + | { + type: 'ai_functionality' + note?: string | null + } | { type: 'advertisements' note?: string | null diff --git a/packages/assets/generated-icons.ts b/packages/assets/generated-icons.ts index b92e881e3a..5cf5029c49 100644 --- a/packages/assets/generated-icons.ts +++ b/packages/assets/generated-icons.ts @@ -61,6 +61,7 @@ import _BoxIcon from './icons/box.svg?component' import _BoxImportIcon from './icons/box-import.svg?component' import _BoxesIcon from './icons/boxes.svg?component' import _BracesIcon from './icons/braces.svg?component' +import _BrainCircuitIcon from './icons/brain-circuit.svg?component' import _BrushCleaningIcon from './icons/brush-cleaning.svg?component' import _BugIcon from './icons/bug.svg?component' import _CalendarIcon from './icons/calendar.svg?component' @@ -505,6 +506,7 @@ export const BoxIcon = _BoxIcon export const BoxImportIcon = _BoxImportIcon export const BoxesIcon = _BoxesIcon export const BracesIcon = _BracesIcon +export const BrainCircuitIcon = _BrainCircuitIcon export const BrushCleaningIcon = _BrushCleaningIcon export const BugIcon = _BugIcon export const CalendarIcon = _CalendarIcon diff --git a/packages/assets/icons/brain-circuit.svg b/packages/assets/icons/brain-circuit.svg new file mode 100644 index 0000000000..dc4bfb7700 --- /dev/null +++ b/packages/assets/icons/brain-circuit.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + diff --git a/packages/ui/src/components/project/ProjectSidebarDetails.vue b/packages/ui/src/components/project/ProjectSidebarDetails.vue index 8be4b125e9..99399cfb12 100644 --- a/packages/ui/src/components/project/ProjectSidebarDetails.vue +++ b/packages/ui/src/components/project/ProjectSidebarDetails.vue @@ -38,6 +38,17 @@ +
+