@ai-stack/payloadcms 3.76.0-beta.2 → 3.76.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/core/media/image/handlers/multimodal.js +2 -2
- package/dist/ai/core/media/image/handlers/multimodal.js.map +1 -1
- package/dist/ai/providers/blocks/anthropic.js +2 -2
- package/dist/ai/providers/blocks/anthropic.js.map +1 -1
- package/dist/ai/providers/blocks/elevenlabs.js +3 -3
- package/dist/ai/providers/blocks/elevenlabs.js.map +1 -1
- package/dist/ai/providers/blocks/fal.js +2 -2
- package/dist/ai/providers/blocks/fal.js.map +1 -1
- package/dist/ai/providers/blocks/google.js +4 -3
- package/dist/ai/providers/blocks/google.js.map +1 -1
- package/dist/ai/providers/blocks/openai-compatible.js +2 -2
- package/dist/ai/providers/blocks/openai-compatible.js.map +1 -1
- package/dist/ai/providers/blocks/openai.js +2 -2
- package/dist/ai/providers/blocks/openai.js.map +1 -1
- package/dist/ai/providers/blocks/xai.js +2 -2
- package/dist/ai/providers/blocks/xai.js.map +1 -1
- package/dist/ai/utilities/nodeToSchemaMap.js +6 -6
- package/dist/ai/utilities/nodeToSchemaMap.js.map +1 -1
- package/dist/collections/AIProviders.js +13 -13
- package/dist/collections/AIProviders.js.map +1 -1
- package/dist/collections/Instructions.js +6 -6
- package/dist/collections/Instructions.js.map +1 -1
- package/dist/endpoints/index.js +1 -1
- package/dist/endpoints/index.js.map +1 -1
- package/dist/fields/LexicalEditor/feature.server.js +1 -1
- package/dist/fields/LexicalEditor/feature.server.js.map +1 -1
- package/dist/fields/PromptEditorField/feature.client.js.map +1 -1
- package/dist/fields/PromptEditorField/feature.server.js +1 -1
- package/dist/fields/PromptEditorField/feature.server.js.map +1 -1
- package/dist/plugin.js +1 -1
- package/dist/plugin.js.map +1 -1
- package/dist/providers/FieldProvider/FieldProvider.js +1 -1
- package/dist/providers/FieldProvider/FieldProvider.js.map +1 -1
- package/dist/providers/FieldProvider/FieldProvider.jsx +2 -2
- package/dist/providers/InstructionsProvider/InstructionsProvider.js +1 -1
- package/dist/providers/InstructionsProvider/InstructionsProvider.js.map +1 -1
- package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +2 -2
- package/dist/types.d.ts +10 -0
- package/dist/types.js.map +1 -1
- package/dist/ui/Compose/Compose.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/Item.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/TranslateMenu.js +12 -4
- package/dist/ui/Compose/hooks/menu/TranslateMenu.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/TranslateMenu.jsx +8 -4
- package/dist/ui/Compose/hooks/useHistory.js +1 -1
- package/dist/ui/Compose/hooks/useHistory.js.map +1 -1
- package/dist/ui/DynamicModelSelect/index.js +1 -1
- package/dist/ui/DynamicModelSelect/index.js.map +1 -1
- package/dist/ui/DynamicModelSelect/index.jsx +1 -1
- package/dist/ui/DynamicProviderSelect/index.js +1 -1
- package/dist/ui/DynamicProviderSelect/index.js.map +1 -1
- package/dist/ui/DynamicProviderSelect/index.jsx +1 -1
- package/dist/ui/DynamicVoiceSelect/index.js +1 -1
- package/dist/ui/DynamicVoiceSelect/index.js.map +1 -1
- package/dist/ui/DynamicVoiceSelect/index.jsx +1 -1
- package/dist/ui/InstructionProviderOptions/ProviderOptionsTree.js.map +1 -1
- package/dist/ui/hooks/useAISettings.js.map +1 -1
- package/dist/ui/providerOptions/updateProviderOptionsValue.d.ts +1 -1
- package/dist/ui/providerOptions/updateProviderOptionsValue.js.map +1 -1
- package/dist/utilities/ai/resolveEffectiveInstructionSettings.js.map +1 -1
- package/dist/utilities/fields/updateFieldsConfig.js +1 -1
- package/dist/utilities/fields/updateFieldsConfig.js.map +1 -1
- package/dist/utilities/lexical/lexicalToPromptTemplate.d.ts +1 -1
- package/dist/utilities/lexical/lexicalToPromptTemplate.js +1 -1
- package/dist/utilities/lexical/lexicalToPromptTemplate.js.map +1 -1
- package/dist/utilities/lexical/stringToLexicalJSON.js +1 -1
- package/dist/utilities/lexical/stringToLexicalJSON.js.map +1 -1
- package/dist/utilities/seedProperties.js +19 -2
- package/dist/utilities/seedProperties.js.map +1 -1
- package/package.json +35 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/DynamicModelSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField, useFormFields } from '@payloadcms/ui'\nimport React, { useMemo } from 'react'\n\nimport { allProviderBlocks } from '../../ai/providers/blocks/index.js'\nimport { handleSelectChange } from '../shared/handleSelectChange.js'\nimport { useAISettings } from '../hooks/useAISettings.js'\n\ntype Props = {\n name: string\n path: string\n}\n\n/**\n * Find a field by name within a block's fields, searching through tabs\n */\nfunction findFieldInBlock(block: any, fieldName: string): any | undefined {\n const searchFields = (fields: any[]): any | undefined => {\n for (const field of fields) {\n if ('name' in field && field.name === fieldName) {\n return field\n }\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n const found = searchFields(tab.fields)\n if (found) {\n return found\n }\n }\n }\n if (field.type === 'group' && 'fields' in field) {\n const found = searchFields(field.fields)\n if (found) {\n return found\n }\n }\n }\n return undefined\n }\n \n return searchFields(block.fields)\n}\n\n/**\n * Infer use case from field path\n * Handles both:\n * - AISettings paths: 'defaults.text.model', 'defaults.image.model'\n * - Instructions paths: 'text-settings.model', 'image-settings.model'\n */\nfunction inferUseCase(path: string): string {\n const pathParts = path.split('.')\n const parentName = pathParts[pathParts.length - 2]\n \n // AISettings: 'defaults.text.model' -> parentName is 'text'\n // Direct use case names\n if (['image', 'text', 'tts', 'video'].includes(parentName)) {\n return parentName\n }\n \n // Instructions: 'text-settings.model' -> parentName is 'text-settings'\n if (parentName === 'image-settings') {\n return 'image'\n }\n if (parentName === 'tts-settings') {\n return 'tts'\n }\n if (parentName === 'text-settings' || parentName === 'richtext-settings') {\n return 'text'\n }\n if (parentName === 'video-settings') {\n return 'video'\n }\n \n // Default to text\n return 'text'\n}\n\nexport const DynamicModelSelect: React.FC<Props> = (props) => {\n const { name, path } = props\n\n // Getting the 'provider' sibling field value\n const parentPath = path.split('.').slice(0, -1).join('.')\n const providerPath = `${parentPath}.provider`\n\n const providerField = useFormFields(([fields]) => fields[providerPath])\n const providerValue = providerField?.value as string\n\n // Get all form fields to search for live provider configuration (for AISettings context)\n // We filter to only 'providers' fields to avoid unnecessary re-renders, \n // but note that the selector runs on every change.\n const formProviders = useFormFields(([fields]) => {\n const providers: Record<string, any> = {}\n if (fields && typeof fields === 'object') {\n Object.keys(fields).forEach((key) => {\n if (key.startsWith('providers.')) {\n providers[key] = fields[key]\n }\n })\n }\n return providers\n })\n\n const { setValue, value } = useField<string>({ path })\n\n const { data: aiSettings } = useAISettings()\n const providersData = aiSettings?.providers ?? []\n\n const inferredUseCase = useMemo(() => inferUseCase(path), [path])\n\n const options = useMemo(() => {\n if (!providerValue) {\n return []\n }\n\n const optionsList: { label: string; value: string }[] = []\n\n // Strategy:\n // 1. Try to find provider in LIVE form state (if editing AISettings)\n // 2. If not found, try to find in FETCHED API data (if editing Instructions or saved AISettings)\n // 3. Fall back to static defaults from block definitions\n\n let foundInForm = false\n let foundInAPI = false\n\n // --- 1. Live Form Search ---\n // Iterate through form fields to find the matching provider block\n // We assume standard block structure: providers.0.blockType, etc.\n // We search up to 20 providers to be safe (unlikely to have more)\n for (let i = 0; i < 20; i++) {\n const typeKey = `providers.${i}.blockType`\n const typeField = formProviders[typeKey]\n \n if (!typeField) {break} // Stop if no more blocks (or gap)\n \n if (typeof typeField === 'object' && 'value' in typeField && typeField.value === providerValue) {\n foundInForm = true\n // Found the provider! Now iterate its models\n // Models path: providers.0.models.0.id\n for (let j = 0; j < 50; j++) {\n const idKey = `providers.${i}.models.${j}.id`\n const nameKey = `providers.${i}.models.${j}.name`\n const useCaseKey = `providers.${i}.models.${j}.useCase`\n const enabledKey = `providers.${i}.models.${j}.enabled`\n \n const idField = formProviders[idKey]\n if (!idField) {break} // Stop if no more models\n \n const modelId = (idField).value as string\n const modelName = (formProviders[nameKey])?.value as string\n const modelUseCase = (formProviders[useCaseKey])?.value as string\n const modelEnabled = (formProviders[enabledKey])?.value\n \n // Check use case and enabled status (default to enabled if undefined)\n if (modelUseCase === inferredUseCase && modelEnabled !== false) {\n optionsList.push({\n label: modelName || modelId,\n value: modelId,\n })\n }\n }\n break // Stop searching providers\n }\n }\n\n // --- 2. API Data Search (if not found in form) ---\n if (!foundInForm) {\n const userProviderBlock = providersData.find((p: any) => p.blockType === providerValue)\n\n if (userProviderBlock && userProviderBlock.models) {\n foundInAPI = true\n userProviderBlock.models.forEach((m: any) => {\n if (m.useCase === inferredUseCase && m.enabled !== false) {\n // Avoid duplicates\n if (!optionsList.some((opt) => opt.value === m.id)) {\n optionsList.push({\n label: m.name,\n value: m.id,\n })\n }\n }\n })\n }\n }\n\n // --- 3. Static Defaults (if not found in form OR API) ---\n // Note: We only fall back to static if we didn't find ANY configuration for this provider.\n // If we found the provider but it had no models for this use case, we show empty list (correct).\n if (!foundInForm && !foundInAPI) {\n const staticBlock = allProviderBlocks.find((b) => b.slug === providerValue)\n\n if (staticBlock) {\n // Search through tabs to find models field\n const modelsField = findFieldInBlock(staticBlock, 'models')\n const defaultModels =\n modelsField && 'defaultValue' in modelsField ? (modelsField.defaultValue as any[]) : []\n\n defaultModels.forEach((m) => {\n if (m.useCase === inferredUseCase && m.enabled !== false) {\n optionsList.push({\n label: m.name,\n value: m.id,\n })\n }\n })\n }\n }\n\n return optionsList\n }, [providerValue, providersData, inferredUseCase, formProviders])\n\n return (\n <div className=\"field-type select\">\n <label className=\"field-label\" htmlFor={path}>\n Model\n </label>\n <SelectInput\n name={name}\n onChange={(option) => handleSelectChange(setValue, option)}\n options={options as any}\n path={path}\n value={value}\n />\n </div>\n )\n}\n\n"],"names":["SelectInput","useField","useFormFields","React","useMemo","allProviderBlocks","handleSelectChange","useAISettings","findFieldInBlock","block","fieldName","searchFields","fields","field","name","type","tab","tabs","found","undefined","inferUseCase","path","pathParts","split","parentName","length","includes","DynamicModelSelect","props","parentPath","slice","join","providerPath","providerField","providerValue","value","formProviders","providers","Object","keys","forEach","key","startsWith","setValue","data","aiSettings","providersData","inferredUseCase","options","optionsList","foundInForm","foundInAPI","i","typeKey","typeField","j","idKey","nameKey","useCaseKey","enabledKey","idField","modelId","modelName","modelUseCase","modelEnabled","push","label","userProviderBlock","find","p","blockType","models","m","useCase","enabled","some","opt","id","staticBlock","b","slug","modelsField","defaultModels","defaultValue","div","className","htmlFor","onChange","option"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/DynamicModelSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField, useFormFields } from '@payloadcms/ui'\nimport React, { useMemo } from 'react'\n\nimport { allProviderBlocks } from '../../ai/providers/blocks/index.js'\nimport { useAISettings } from '../hooks/useAISettings.js'\nimport { handleSelectChange } from '../shared/handleSelectChange.js'\n\ntype Props = {\n name: string\n path: string\n}\n\n/**\n * Find a field by name within a block's fields, searching through tabs\n */\nfunction findFieldInBlock(block: any, fieldName: string): any | undefined {\n const searchFields = (fields: any[]): any | undefined => {\n for (const field of fields) {\n if ('name' in field && field.name === fieldName) {\n return field\n }\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n const found = searchFields(tab.fields)\n if (found) {\n return found\n }\n }\n }\n if (field.type === 'group' && 'fields' in field) {\n const found = searchFields(field.fields)\n if (found) {\n return found\n }\n }\n }\n return undefined\n }\n \n return searchFields(block.fields)\n}\n\n/**\n * Infer use case from field path\n * Handles both:\n * - AISettings paths: 'defaults.text.model', 'defaults.image.model'\n * - Instructions paths: 'text-settings.model', 'image-settings.model'\n */\nfunction inferUseCase(path: string): string {\n const pathParts = path.split('.')\n const parentName = pathParts[pathParts.length - 2]\n \n // AISettings: 'defaults.text.model' -> parentName is 'text'\n // Direct use case names\n if (['image', 'text', 'tts', 'video'].includes(parentName)) {\n return parentName\n }\n \n // Instructions: 'text-settings.model' -> parentName is 'text-settings'\n if (parentName === 'image-settings') {\n return 'image'\n }\n if (parentName === 'tts-settings') {\n return 'tts'\n }\n if (parentName === 'text-settings' || parentName === 'richtext-settings') {\n return 'text'\n }\n if (parentName === 'video-settings') {\n return 'video'\n }\n \n // Default to text\n return 'text'\n}\n\nexport const DynamicModelSelect: React.FC<Props> = (props) => {\n const { name, path } = props\n\n // Getting the 'provider' sibling field value\n const parentPath = path.split('.').slice(0, -1).join('.')\n const providerPath = `${parentPath}.provider`\n\n const providerField = useFormFields(([fields]) => fields[providerPath])\n const providerValue = providerField?.value as string\n\n // Get all form fields to search for live provider configuration (for AISettings context)\n // We filter to only 'providers' fields to avoid unnecessary re-renders, \n // but note that the selector runs on every change.\n const formProviders = useFormFields(([fields]) => {\n const providers: Record<string, any> = {}\n if (fields && typeof fields === 'object') {\n Object.keys(fields).forEach((key) => {\n if (key.startsWith('providers.')) {\n providers[key] = fields[key]\n }\n })\n }\n return providers\n })\n\n const { setValue, value } = useField<string>({ path })\n\n const { data: aiSettings } = useAISettings()\n const providersData = aiSettings?.providers ?? []\n\n const inferredUseCase = useMemo(() => inferUseCase(path), [path])\n\n const options = useMemo(() => {\n if (!providerValue) {\n return []\n }\n\n const optionsList: { label: string; value: string }[] = []\n\n // Strategy:\n // 1. Try to find provider in LIVE form state (if editing AISettings)\n // 2. If not found, try to find in FETCHED API data (if editing Instructions or saved AISettings)\n // 3. Fall back to static defaults from block definitions\n\n let foundInForm = false\n let foundInAPI = false\n\n // --- 1. Live Form Search ---\n // Iterate through form fields to find the matching provider block\n // We assume standard block structure: providers.0.blockType, etc.\n // We search up to 20 providers to be safe (unlikely to have more)\n for (let i = 0; i < 20; i++) {\n const typeKey = `providers.${i}.blockType`\n const typeField = formProviders[typeKey]\n \n if (!typeField) {break} // Stop if no more blocks (or gap)\n \n if (typeof typeField === 'object' && 'value' in typeField && typeField.value === providerValue) {\n foundInForm = true\n // Found the provider! Now iterate its models\n // Models path: providers.0.models.0.id\n for (let j = 0; j < 50; j++) {\n const idKey = `providers.${i}.models.${j}.id`\n const nameKey = `providers.${i}.models.${j}.name`\n const useCaseKey = `providers.${i}.models.${j}.useCase`\n const enabledKey = `providers.${i}.models.${j}.enabled`\n \n const idField = formProviders[idKey]\n if (!idField) {break} // Stop if no more models\n \n const modelId = (idField).value as string\n const modelName = (formProviders[nameKey])?.value as string\n const modelUseCase = (formProviders[useCaseKey])?.value as string\n const modelEnabled = (formProviders[enabledKey])?.value\n \n // Check use case and enabled status (default to enabled if undefined)\n if (modelUseCase === inferredUseCase && modelEnabled !== false) {\n optionsList.push({\n label: modelName || modelId,\n value: modelId,\n })\n }\n }\n break // Stop searching providers\n }\n }\n\n // --- 2. API Data Search (if not found in form) ---\n if (!foundInForm) {\n const userProviderBlock = providersData.find((p: any) => p.blockType === providerValue)\n\n if (userProviderBlock && userProviderBlock.models) {\n foundInAPI = true\n userProviderBlock.models.forEach((m: any) => {\n if (m.useCase === inferredUseCase && m.enabled !== false) {\n // Avoid duplicates\n if (!optionsList.some((opt) => opt.value === m.id)) {\n optionsList.push({\n label: m.name,\n value: m.id,\n })\n }\n }\n })\n }\n }\n\n // --- 3. Static Defaults (if not found in form OR API) ---\n // Note: We only fall back to static if we didn't find ANY configuration for this provider.\n // If we found the provider but it had no models for this use case, we show empty list (correct).\n if (!foundInForm && !foundInAPI) {\n const staticBlock = allProviderBlocks.find((b) => b.slug === providerValue)\n\n if (staticBlock) {\n // Search through tabs to find models field\n const modelsField = findFieldInBlock(staticBlock, 'models')\n const defaultModels =\n modelsField && 'defaultValue' in modelsField ? (modelsField.defaultValue as any[]) : []\n\n defaultModels.forEach((m) => {\n if (m.useCase === inferredUseCase && m.enabled !== false) {\n optionsList.push({\n label: m.name,\n value: m.id,\n })\n }\n })\n }\n }\n\n return optionsList\n }, [providerValue, providersData, inferredUseCase, formProviders])\n\n return (\n <div className=\"field-type select\">\n <label className=\"field-label\" htmlFor={path}>\n Model\n </label>\n <SelectInput\n name={name}\n onChange={(option) => handleSelectChange(setValue, option)}\n options={options as any}\n path={path}\n value={value}\n />\n </div>\n )\n}\n\n"],"names":["SelectInput","useField","useFormFields","React","useMemo","allProviderBlocks","useAISettings","handleSelectChange","findFieldInBlock","block","fieldName","searchFields","fields","field","name","type","tab","tabs","found","undefined","inferUseCase","path","pathParts","split","parentName","length","includes","DynamicModelSelect","props","parentPath","slice","join","providerPath","providerField","providerValue","value","formProviders","providers","Object","keys","forEach","key","startsWith","setValue","data","aiSettings","providersData","inferredUseCase","options","optionsList","foundInForm","foundInAPI","i","typeKey","typeField","j","idKey","nameKey","useCaseKey","enabledKey","idField","modelId","modelName","modelUseCase","modelEnabled","push","label","userProviderBlock","find","p","blockType","models","m","useCase","enabled","some","opt","id","staticBlock","b","slug","modelsField","defaultModels","defaultValue","div","className","htmlFor","onChange","option"],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { SelectInput, useField, useFormFields } from '@payloadcms/ui';
|
|
3
3
|
import React, { useMemo } from 'react';
|
|
4
4
|
import { allProviderBlocks } from '../../ai/providers/blocks/index.js';
|
|
5
|
-
import { handleSelectChange } from '../shared/handleSelectChange.js';
|
|
6
5
|
import { useAISettings } from '../hooks/useAISettings.js';
|
|
6
|
+
import { handleSelectChange } from '../shared/handleSelectChange.js';
|
|
7
7
|
/**
|
|
8
8
|
* Find a field by name within a block's fields, searching through tabs
|
|
9
9
|
*/
|
|
@@ -3,8 +3,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { SelectInput, useField } from '@payloadcms/ui';
|
|
4
4
|
import React, { useMemo } from 'react';
|
|
5
5
|
import { allProviderBlocks } from '../../ai/providers/blocks/index.js';
|
|
6
|
-
import { handleSelectChange } from '../shared/handleSelectChange.js';
|
|
7
6
|
import { useAISettings } from '../hooks/useAISettings.js';
|
|
7
|
+
import { handleSelectChange } from '../shared/handleSelectChange.js';
|
|
8
8
|
export const DynamicProviderSelect = (props)=>{
|
|
9
9
|
const { name, path } = props;
|
|
10
10
|
const { setValue, value } = useField({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/DynamicProviderSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField } from '@payloadcms/ui'\nimport React, { useMemo } from 'react'\n\nimport { allProviderBlocks } from '../../ai/providers/blocks/index.js'\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/DynamicProviderSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField } from '@payloadcms/ui'\nimport React, { useMemo } from 'react'\n\nimport { allProviderBlocks } from '../../ai/providers/blocks/index.js'\nimport { useAISettings } from '../hooks/useAISettings.js'\nimport { handleSelectChange } from '../shared/handleSelectChange.js'\n\ntype Props = {\n name: string\n path: string\n}\n\nexport const DynamicProviderSelect: React.FC<Props> = (props) => {\n const { name, path } = props\n\n const { setValue, value } = useField<string>({ path })\n\n const { data: aiSettings } = useAISettings()\n const providersData = aiSettings?.providers ?? []\n\n const options = useMemo(() => {\n const optionsList: { label: string; value: string }[] = []\n const processedProviders = new Set<string>()\n\n // Iterate through fetched providers to find custom names\n providersData.forEach((provider: any) => {\n if (!provider.enabled) {\n return\n }\n\n const blockType = provider.blockType\n const customName = provider.providerName\n\n // Get static label as fallback\n const staticBlock = allProviderBlocks.find((b) => b.slug === blockType)\n const staticLabel = staticBlock?.labels?.singular\n ? typeof staticBlock.labels.singular === 'string'\n ? staticBlock.labels.singular\n : blockType\n : blockType\n\n const label = customName || staticLabel\n\n if (!processedProviders.has(blockType)) {\n optionsList.push({\n label,\n value: blockType,\n })\n processedProviders.add(blockType)\n } else if (customName) {\n // Update existing label if custom name is available\n const existingOpt = optionsList.find((o) => o.value === blockType)\n if (existingOpt && existingOpt.label === staticLabel) {\n existingOpt.label = customName\n }\n }\n })\n\n // Add any other available providers from blocks that might not be configured yet?\n // Usually we only want to show configured providers in the selection list.\n // But for standard providers (OpenAI, Google), they might not need much config other than API key.\n // If they are not in the list, user can't select them.\n // However, if they are not enabled in settings, maybe we shouldn't show them?\n // Let's stick to showing all available blocks, but prioritizing configured ones with custom names.\n\n allProviderBlocks.forEach((block) => {\n if (!processedProviders.has(block.slug)) {\n optionsList.push({\n label: typeof block.labels?.singular === 'string' ? block.labels.singular : block.slug,\n value: block.slug,\n })\n }\n })\n\n return optionsList\n }, [providersData])\n\n return (\n <div className=\"field-type select\">\n <label className=\"field-label\" htmlFor={path}>\n Provider\n </label>\n <SelectInput\n name={name}\n onChange={(option) => handleSelectChange(setValue, option)}\n options={options as any}\n path={path}\n value={value}\n />\n </div>\n )\n}\n"],"names":["SelectInput","useField","React","useMemo","allProviderBlocks","useAISettings","handleSelectChange","DynamicProviderSelect","props","name","path","setValue","value","data","aiSettings","providersData","providers","options","optionsList","processedProviders","Set","forEach","provider","enabled","blockType","customName","providerName","staticBlock","find","b","slug","staticLabel","labels","singular","label","has","push","add","existingOpt","o","block","div","className","htmlFor","onChange","option"],"mappings":"AAAA;;AAEA,SAASA,WAAW,EAAEC,QAAQ,QAAQ,iBAAgB;AACtD,OAAOC,SAASC,OAAO,QAAQ,QAAO;AAEtC,SAASC,iBAAiB,QAAQ,qCAAoC;AACtE,SAASC,aAAa,QAAQ,4BAA2B;AACzD,SAASC,kBAAkB,QAAQ,kCAAiC;AAOpE,OAAO,MAAMC,wBAAyC,CAACC;IACrD,MAAM,EAAEC,IAAI,EAAEC,IAAI,EAAE,GAAGF;IAEvB,MAAM,EAAEG,QAAQ,EAAEC,KAAK,EAAE,GAAGX,SAAiB;QAAES;IAAK;IAEpD,MAAM,EAAEG,MAAMC,UAAU,EAAE,GAAGT;IAC7B,MAAMU,gBAAgBD,YAAYE,aAAa,EAAE;IAEjD,MAAMC,UAAUd,QAAQ;QACtB,MAAMe,cAAkD,EAAE;QAC1D,MAAMC,qBAAqB,IAAIC;QAE/B,yDAAyD;QACzDL,cAAcM,OAAO,CAAC,CAACC;YACrB,IAAI,CAACA,SAASC,OAAO,EAAE;gBACrB;YACF;YAEA,MAAMC,YAAYF,SAASE,SAAS;YACpC,MAAMC,aAAaH,SAASI,YAAY;YAExC,+BAA+B;YAC/B,MAAMC,cAAcvB,kBAAkBwB,IAAI,CAAC,CAACC,IAAMA,EAAEC,IAAI,KAAKN;YAC7D,MAAMO,cAAcJ,aAAaK,QAAQC,WACrC,OAAON,YAAYK,MAAM,CAACC,QAAQ,KAAK,WACrCN,YAAYK,MAAM,CAACC,QAAQ,GAC3BT,YACFA;YAEJ,MAAMU,QAAQT,cAAcM;YAE5B,IAAI,CAACZ,mBAAmBgB,GAAG,CAACX,YAAY;gBACtCN,YAAYkB,IAAI,CAAC;oBACfF;oBACAtB,OAAOY;gBACT;gBACAL,mBAAmBkB,GAAG,CAACb;YACzB,OAAO,IAAIC,YAAY;gBACrB,oDAAoD;gBACpD,MAAMa,cAAcpB,YAAYU,IAAI,CAAC,CAACW,IAAMA,EAAE3B,KAAK,KAAKY;gBACxD,IAAIc,eAAeA,YAAYJ,KAAK,KAAKH,aAAa;oBACpDO,YAAYJ,KAAK,GAAGT;gBACtB;YACF;QACF;QAEA,kFAAkF;QAClF,2EAA2E;QAC3E,mGAAmG;QACnG,uDAAuD;QACvD,8EAA8E;QAC9E,mGAAmG;QAEnGrB,kBAAkBiB,OAAO,CAAC,CAACmB;YACzB,IAAI,CAACrB,mBAAmBgB,GAAG,CAACK,MAAMV,IAAI,GAAG;gBACvCZ,YAAYkB,IAAI,CAAC;oBACfF,OAAO,OAAOM,MAAMR,MAAM,EAAEC,aAAa,WAAWO,MAAMR,MAAM,CAACC,QAAQ,GAAGO,MAAMV,IAAI;oBACtFlB,OAAO4B,MAAMV,IAAI;gBACnB;YACF;QACF;QAEA,OAAOZ;IACT,GAAG;QAACH;KAAc;IAElB,qBACE,MAAC0B;QAAIC,WAAU;;0BACb,KAACR;gBAAMQ,WAAU;gBAAcC,SAASjC;0BAAM;;0BAG9C,KAACV;gBACCS,MAAMA;gBACNmC,UAAU,CAACC,SAAWvC,mBAAmBK,UAAUkC;gBACnD5B,SAASA;gBACTP,MAAMA;gBACNE,OAAOA;;;;AAIf,EAAC"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { SelectInput, useField } from '@payloadcms/ui';
|
|
3
3
|
import React, { useMemo } from 'react';
|
|
4
4
|
import { allProviderBlocks } from '../../ai/providers/blocks/index.js';
|
|
5
|
-
import { handleSelectChange } from '../shared/handleSelectChange.js';
|
|
6
5
|
import { useAISettings } from '../hooks/useAISettings.js';
|
|
6
|
+
import { handleSelectChange } from '../shared/handleSelectChange.js';
|
|
7
7
|
export const DynamicProviderSelect = (props) => {
|
|
8
8
|
const { name, path } = props;
|
|
9
9
|
const { setValue, value } = useField({ path });
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { SelectInput, useField, useFormFields } from '@payloadcms/ui';
|
|
4
4
|
import React, { useEffect, useMemo } from 'react';
|
|
5
|
-
import { handleSelectChange } from '../shared/handleSelectChange.js';
|
|
6
5
|
import { useAISettings } from '../hooks/useAISettings.js';
|
|
6
|
+
import { handleSelectChange } from '../shared/handleSelectChange.js';
|
|
7
7
|
const StatusMessage = ({ label, message, path })=>/*#__PURE__*/ _jsxs("div", {
|
|
8
8
|
className: "field-type text",
|
|
9
9
|
children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/DynamicVoiceSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField, useFormFields } from '@payloadcms/ui'\nimport React, { useEffect, useMemo } from 'react'\n\nimport type { Voice } from '../shared/types.js'\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/DynamicVoiceSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField, useFormFields } from '@payloadcms/ui'\nimport React, { useEffect, useMemo } from 'react'\n\nimport type { Voice } from '../shared/types.js'\n\nimport { useAISettings } from '../hooks/useAISettings.js'\nimport { handleSelectChange } from '../shared/handleSelectChange.js'\n\ntype Props = {\n name: string\n path: string\n}\n\ninterface ProviderBlock {\n blockType: string\n enabled?: boolean\n voices?: Voice[]\n}\n\nconst StatusMessage: React.FC<{ label: string; message: string; path: string }> = ({ label, message, path }) => (\n <div className=\"field-type text\">\n <label className=\"field-label\" htmlFor={path}>\n {label}\n </label>\n <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px' }}>\n {message}\n </p>\n </div>\n)\n\nexport const DynamicVoiceSelect: React.FC<Props> = (props) => {\n const { name, path } = props\n\n // Get provider from siblings\n const parentPath = path.split('.').slice(0, -1).join('.')\n const providerPath = `${parentPath}.provider`\n\n // Use useFormFields to get the provider field value - this will re-render when provider changes\n const providerField = useFormFields(([fields]) => fields[providerPath])\n const provider = (providerField?.value as string) || ''\n\n const { setValue, value } = useField<string>({ path })\n const { data: aiSettings, isLoading } = useAISettings()\n\n const voices = useMemo(() => {\n if (!provider || !aiSettings?.providers) {\n return []\n }\n\n // Find the provider block matching the selected provider\n const providerBlock = aiSettings.providers.find(\n (p: ProviderBlock) => p.blockType === provider && p.enabled !== false,\n ) as ProviderBlock | undefined\n\n if (!providerBlock?.voices) {\n return []\n }\n\n // Get enabled voices from provider block\n return providerBlock.voices\n .filter((v: Voice) => v.enabled !== false)\n .map((v: Voice) => ({\n label: v.name || v.id,\n value: v.id,\n }))\n }, [provider, aiSettings])\n\n // Clear voice selection when provider changes and current voice is not available\n useEffect(() => {\n if (value && voices.length > 0) {\n const voiceExists = voices.some((v) => v.value === value)\n if (!voiceExists) {\n setValue('')\n }\n }\n }, [voices, value, setValue])\n\n if (!provider) {\n return <StatusMessage label=\"Voice\" message=\"Please select a provider first.\" path={path} />\n }\n\n if (isLoading) {\n return <StatusMessage label=\"Voice\" message=\"Loading voices...\" path={path} />\n }\n\n if (voices.length === 0) {\n return (\n <StatusMessage\n label=\"Voice\"\n message={`No voices available. Please configure voices in AI Settings for ${provider}.`}\n path={path}\n />\n )\n }\n\n return (\n <div className=\"field-type select\">\n <label className=\"field-label\" htmlFor={path}>\n Voice\n </label>\n <SelectInput\n name={name}\n onChange={(option) => handleSelectChange(setValue, option)}\n options={voices}\n path={path}\n value={value}\n />\n </div>\n )\n}\n\n"],"names":["SelectInput","useField","useFormFields","React","useEffect","useMemo","useAISettings","handleSelectChange","StatusMessage","label","message","path","div","className","htmlFor","p","style","color","fontSize","DynamicVoiceSelect","props","name","parentPath","split","slice","join","providerPath","providerField","fields","provider","value","setValue","data","aiSettings","isLoading","voices","providers","providerBlock","find","blockType","enabled","filter","v","map","id","length","voiceExists","some","onChange","option","options"],"mappings":"AAAA;;AAEA,SAASA,WAAW,EAAEC,QAAQ,EAAEC,aAAa,QAAQ,iBAAgB;AACrE,OAAOC,SAASC,SAAS,EAAEC,OAAO,QAAQ,QAAO;AAIjD,SAASC,aAAa,QAAQ,4BAA2B;AACzD,SAASC,kBAAkB,QAAQ,kCAAiC;AAapE,MAAMC,gBAA4E,CAAC,EAAEC,KAAK,EAAEC,OAAO,EAAEC,IAAI,EAAE,iBACzG,MAACC;QAAIC,WAAU;;0BACb,KAACJ;gBAAMI,WAAU;gBAAcC,SAASH;0BACrCF;;0BAEH,KAACM;gBAAEC,OAAO;oBAAEC,OAAO;oBAA8BC,UAAU;gBAAO;0BAC/DR;;;;AAKP,OAAO,MAAMS,qBAAsC,CAACC;IAClD,MAAM,EAAEC,IAAI,EAAEV,IAAI,EAAE,GAAGS;IAEvB,6BAA6B;IAC7B,MAAME,aAAaX,KAAKY,KAAK,CAAC,KAAKC,KAAK,CAAC,GAAG,CAAC,GAAGC,IAAI,CAAC;IACrD,MAAMC,eAAe,CAAC,EAAEJ,WAAW,SAAS,CAAC;IAE7C,gGAAgG;IAChG,MAAMK,gBAAgBzB,cAAc,CAAC,CAAC0B,OAAO,GAAKA,MAAM,CAACF,aAAa;IACtE,MAAMG,WAAW,AAACF,eAAeG,SAAoB;IAErD,MAAM,EAAEC,QAAQ,EAAED,KAAK,EAAE,GAAG7B,SAAiB;QAAEU;IAAK;IACpD,MAAM,EAAEqB,MAAMC,UAAU,EAAEC,SAAS,EAAE,GAAG5B;IAExC,MAAM6B,SAAS9B,QAAQ;QACrB,IAAI,CAACwB,YAAY,CAACI,YAAYG,WAAW;YACvC,OAAO,EAAE;QACX;QAEA,yDAAyD;QACzD,MAAMC,gBAAgBJ,WAAWG,SAAS,CAACE,IAAI,CAC7C,CAACvB,IAAqBA,EAAEwB,SAAS,KAAKV,YAAYd,EAAEyB,OAAO,KAAK;QAGlE,IAAI,CAACH,eAAeF,QAAQ;YAC1B,OAAO,EAAE;QACX;QAEA,yCAAyC;QACzC,OAAOE,cAAcF,MAAM,CACxBM,MAAM,CAAC,CAACC,IAAaA,EAAEF,OAAO,KAAK,OACnCG,GAAG,CAAC,CAACD,IAAc,CAAA;gBAClBjC,OAAOiC,EAAErB,IAAI,IAAIqB,EAAEE,EAAE;gBACrBd,OAAOY,EAAEE,EAAE;YACb,CAAA;IACJ,GAAG;QAACf;QAAUI;KAAW;IAEzB,iFAAiF;IACjF7B,UAAU;QACR,IAAI0B,SAASK,OAAOU,MAAM,GAAG,GAAG;YAC9B,MAAMC,cAAcX,OAAOY,IAAI,CAAC,CAACL,IAAMA,EAAEZ,KAAK,KAAKA;YACnD,IAAI,CAACgB,aAAa;gBAChBf,SAAS;YACX;QACF;IACF,GAAG;QAACI;QAAQL;QAAOC;KAAS;IAE5B,IAAI,CAACF,UAAU;QACb,qBAAO,KAACrB;YAAcC,OAAM;YAAQC,SAAQ;YAAkCC,MAAMA;;IACtF;IAEA,IAAIuB,WAAW;QACb,qBAAO,KAAC1B;YAAcC,OAAM;YAAQC,SAAQ;YAAoBC,MAAMA;;IACxE;IAEA,IAAIwB,OAAOU,MAAM,KAAK,GAAG;QACvB,qBACE,KAACrC;YACCC,OAAM;YACNC,SAAS,CAAC,gEAAgE,EAAEmB,SAAS,CAAC,CAAC;YACvFlB,MAAMA;;IAGZ;IAEA,qBACE,MAACC;QAAIC,WAAU;;0BACb,KAACJ;gBAAMI,WAAU;gBAAcC,SAASH;0BAAM;;0BAG9C,KAACX;gBACCqB,MAAMA;gBACN2B,UAAU,CAACC,SAAW1C,mBAAmBwB,UAAUkB;gBACnDC,SAASf;gBACTxB,MAAMA;gBACNmB,OAAOA;;;;AAIf,EAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { SelectInput, useField, useFormFields } from '@payloadcms/ui';
|
|
3
3
|
import React, { useEffect, useMemo } from 'react';
|
|
4
|
-
import { handleSelectChange } from '../shared/handleSelectChange.js';
|
|
5
4
|
import { useAISettings } from '../hooks/useAISettings.js';
|
|
5
|
+
import { handleSelectChange } from '../shared/handleSelectChange.js';
|
|
6
6
|
const StatusMessage = ({ label, message, path }) => (<div className="field-type text">
|
|
7
7
|
<label className="field-label" htmlFor={path}>
|
|
8
8
|
{label}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/InstructionProviderOptions/ProviderOptionsTree.tsx"],"sourcesContent":["'use client'\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/InstructionProviderOptions/ProviderOptionsTree.tsx"],"sourcesContent":["'use client'\n\nimport type { OptionObject } from 'payload'\n\nimport { SelectInput } from '@payloadcms/ui'\nimport React from 'react'\n\ntype Primitive = boolean | null | number | string | undefined\ntype PrimitiveArray = number[] | string[]\n\ntype ProviderOptionTreeNodeProps = {\n disabled?: boolean\n onChange: (path: string[], value: any) => void\n path: string[]\n schemaValue: Primitive | PrimitiveArray | Record<string, any>\n selectedValue: any\n}\n\nexport const ProviderOptionsTree: React.FC<ProviderOptionTreeNodeProps> = ({\n disabled,\n onChange,\n path,\n schemaValue,\n selectedValue,\n}) => {\n const nodeKey = path.length > 0 ? path[path.length - 1] : 'root'\n const inputId = `po-${path.join('-')}`\n\n // Ensure path is properly passed when nested deeper than 1 level\n if (schemaValue && typeof schemaValue === 'object' && !Array.isArray(schemaValue)) {\n return (\n <div className=\"provider-options-group\" style={{ \n borderLeft: path.length > 0 ? '1px solid var(--theme-elevation-150)' : 'none', \n display: 'grid', \n gap: '1rem', \n marginLeft: path.length > 0 ? '1rem' : '0', \n paddingLeft: path.length > 0 ? '1rem' : '0' \n }}>\n {path.length > 0 && <div className=\"field-label\" style={{ fontWeight: 600, marginBottom: '-0.5rem' }}>{nodeKey}</div>}\n {Object.entries(schemaValue).map(([key, childSchema]) => (\n <ProviderOptionsTree\n disabled={disabled}\n key={key}\n onChange={onChange}\n path={[...path, key]}\n schemaValue={childSchema}\n selectedValue={selectedValue?.[key]}\n />\n ))}\n </div>\n )\n }\n\n // Handle Array as Select Menu options\n if (Array.isArray(schemaValue)) {\n const options: OptionObject[] = schemaValue.map((item) => ({\n label: String(item),\n value: String(item),\n }))\n\n return (\n <div className=\"field-type select\">\n <label className=\"field-label\" htmlFor={inputId}>\n {nodeKey}\n </label>\n <SelectInput\n isClearable\n name={inputId}\n onChange={(selected) => {\n if (selected && typeof selected === 'object' && 'value' in selected) {\n onChange(path, (selected as OptionObject).value)\n return\n }\n onChange(path, undefined)\n }}\n options={options}\n path={inputId}\n readOnly={disabled}\n value={selectedValue !== undefined ? String(selectedValue) : undefined}\n />\n </div>\n )\n }\n\n // Handle Boolean as Select Menu True/False\n if (typeof schemaValue === 'boolean') {\n const booleanOptions: OptionObject[] = [\n { label: 'True', value: 'true' },\n { label: 'False', value: 'false' },\n ]\n const stringVal = selectedValue === true ? 'true' : selectedValue === false ? 'false' : undefined\n\n return (\n <div className=\"field-type select\">\n <label className=\"field-label\" htmlFor={inputId}>\n {nodeKey}\n </label>\n <SelectInput\n isClearable\n name={inputId}\n onChange={(selected) => {\n if (selected && typeof selected === 'object' && 'value' in selected) {\n onChange(path, (selected as OptionObject).value === 'true')\n return\n }\n onChange(path, undefined)\n }}\n options={booleanOptions}\n path={inputId}\n readOnly={disabled}\n value={stringVal}\n />\n </div>\n )\n }\n\n // Handle Number Input\n if (typeof schemaValue === 'number') {\n return (\n <div className=\"field-type number\">\n <label className=\"field-label\" htmlFor={inputId}>\n {nodeKey}\n </label>\n <input\n disabled={disabled}\n id={inputId}\n name={inputId}\n onChange={(e) => {\n const val = e.target.value\n onChange(path, val === '' ? undefined : Number(val))\n }}\n style={{ width: '100%' }}\n type=\"number\"\n value={\n typeof selectedValue === 'number' && !Number.isNaN(selectedValue)\n ? Number(selectedValue)\n : ''\n }\n />\n </div>\n )\n }\n\n // Handle Text Input\n return (\n <div className=\"field-type text\">\n <label className=\"field-label\" htmlFor={inputId}>\n {nodeKey}\n </label>\n <input\n disabled={disabled}\n id={inputId}\n name={inputId}\n onChange={(e) => {\n const val = e.target.value\n onChange(path, val.trim() === '' ? undefined : val)\n }}\n style={{ width: '100%' }}\n type=\"text\"\n value={typeof selectedValue === 'string' ? selectedValue : ''}\n />\n </div>\n )\n}\n"],"names":["SelectInput","React","ProviderOptionsTree","disabled","onChange","path","schemaValue","selectedValue","nodeKey","length","inputId","join","Array","isArray","div","className","style","borderLeft","display","gap","marginLeft","paddingLeft","fontWeight","marginBottom","Object","entries","map","key","childSchema","options","item","label","String","value","htmlFor","isClearable","name","selected","undefined","readOnly","booleanOptions","stringVal","input","id","e","val","target","Number","width","type","isNaN","trim"],"mappings":"AAAA;;AAIA,SAASA,WAAW,QAAQ,iBAAgB;AAC5C,OAAOC,WAAW,QAAO;AAazB,OAAO,MAAMC,sBAA6D,CAAC,EACzEC,QAAQ,EACRC,QAAQ,EACRC,IAAI,EACJC,WAAW,EACXC,aAAa,EACd;IACC,MAAMC,UAAUH,KAAKI,MAAM,GAAG,IAAIJ,IAAI,CAACA,KAAKI,MAAM,GAAG,EAAE,GAAG;IAC1D,MAAMC,UAAU,CAAC,GAAG,EAAEL,KAAKM,IAAI,CAAC,KAAK,CAAC;IAEtC,iEAAiE;IACjE,IAAIL,eAAe,OAAOA,gBAAgB,YAAY,CAACM,MAAMC,OAAO,CAACP,cAAc;QACjF,qBACE,MAACQ;YAAIC,WAAU;YAAyBC,OAAO;gBAC7CC,YAAYZ,KAAKI,MAAM,GAAG,IAAI,yCAAyC;gBACvES,SAAS;gBACTC,KAAK;gBACLC,YAAYf,KAAKI,MAAM,GAAG,IAAI,SAAS;gBACvCY,aAAahB,KAAKI,MAAM,GAAG,IAAI,SAAS;YAC1C;;gBACGJ,KAAKI,MAAM,GAAG,mBAAK,KAACK;oBAAIC,WAAU;oBAAcC,OAAO;wBAAEM,YAAY;wBAAKC,cAAc;oBAAU;8BAAIf;;gBACtGgB,OAAOC,OAAO,CAACnB,aAAaoB,GAAG,CAAC,CAAC,CAACC,KAAKC,YAAY,iBAClD,KAAC1B;wBACCC,UAAUA;wBAEVC,UAAUA;wBACVC,MAAM;+BAAIA;4BAAMsB;yBAAI;wBACpBrB,aAAasB;wBACbrB,eAAeA,eAAe,CAACoB,IAAI;uBAJ9BA;;;IASf;IAEA,sCAAsC;IACtC,IAAIf,MAAMC,OAAO,CAACP,cAAc;QAC9B,MAAMuB,UAA0BvB,YAAYoB,GAAG,CAAC,CAACI,OAAU,CAAA;gBACzDC,OAAOC,OAAOF;gBACdG,OAAOD,OAAOF;YAChB,CAAA;QAEA,qBACE,MAAChB;YAAIC,WAAU;;8BACb,KAACgB;oBAAMhB,WAAU;oBAAcmB,SAASxB;8BACrCF;;8BAEH,KAACR;oBACCmC,WAAW;oBACXC,MAAM1B;oBACNN,UAAU,CAACiC;wBACT,IAAIA,YAAY,OAAOA,aAAa,YAAY,WAAWA,UAAU;4BACnEjC,SAASC,MAAM,AAACgC,SAA0BJ,KAAK;4BAC/C;wBACF;wBACA7B,SAASC,MAAMiC;oBACjB;oBACAT,SAASA;oBACTxB,MAAMK;oBACN6B,UAAUpC;oBACV8B,OAAO1B,kBAAkB+B,YAAYN,OAAOzB,iBAAiB+B;;;;IAIrE;IAEA,2CAA2C;IAC3C,IAAI,OAAOhC,gBAAgB,WAAW;QACpC,MAAMkC,iBAAiC;YACrC;gBAAET,OAAO;gBAAQE,OAAO;YAAO;YAC/B;gBAAEF,OAAO;gBAASE,OAAO;YAAQ;SAClC;QACD,MAAMQ,YAAYlC,kBAAkB,OAAO,SAASA,kBAAkB,QAAQ,UAAU+B;QAExF,qBACE,MAACxB;YAAIC,WAAU;;8BACb,KAACgB;oBAAMhB,WAAU;oBAAcmB,SAASxB;8BACrCF;;8BAEH,KAACR;oBACCmC,WAAW;oBACXC,MAAM1B;oBACNN,UAAU,CAACiC;wBACT,IAAIA,YAAY,OAAOA,aAAa,YAAY,WAAWA,UAAU;4BACnEjC,SAASC,MAAM,AAACgC,SAA0BJ,KAAK,KAAK;4BACpD;wBACF;wBACA7B,SAASC,MAAMiC;oBACjB;oBACAT,SAASW;oBACTnC,MAAMK;oBACN6B,UAAUpC;oBACV8B,OAAOQ;;;;IAIf;IAEA,sBAAsB;IACtB,IAAI,OAAOnC,gBAAgB,UAAU;QACnC,qBACE,MAACQ;YAAIC,WAAU;;8BACb,KAACgB;oBAAMhB,WAAU;oBAAcmB,SAASxB;8BACrCF;;8BAEH,KAACkC;oBACCvC,UAAUA;oBACVwC,IAAIjC;oBACJ0B,MAAM1B;oBACNN,UAAU,CAACwC;wBACT,MAAMC,MAAMD,EAAEE,MAAM,CAACb,KAAK;wBAC1B7B,SAASC,MAAMwC,QAAQ,KAAKP,YAAYS,OAAOF;oBACjD;oBACA7B,OAAO;wBAAEgC,OAAO;oBAAO;oBACvBC,MAAK;oBACLhB,OACE,OAAO1B,kBAAkB,YAAY,CAACwC,OAAOG,KAAK,CAAC3C,iBAC/CwC,OAAOxC,iBACP;;;;IAKd;IAEA,oBAAoB;IACpB,qBACE,MAACO;QAAIC,WAAU;;0BACb,KAACgB;gBAAMhB,WAAU;gBAAcmB,SAASxB;0BACrCF;;0BAEH,KAACkC;gBACCvC,UAAUA;gBACVwC,IAAIjC;gBACJ0B,MAAM1B;gBACNN,UAAU,CAACwC;oBACT,MAAMC,MAAMD,EAAEE,MAAM,CAACb,KAAK;oBAC1B7B,SAASC,MAAMwC,IAAIM,IAAI,OAAO,KAAKb,YAAYO;gBACjD;gBACA7B,OAAO;oBAAEgC,OAAO;gBAAO;gBACvBC,MAAK;gBACLhB,OAAO,OAAO1B,kBAAkB,WAAWA,gBAAgB;;;;AAInE,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/hooks/useAISettings.ts"],"sourcesContent":["'use client'\n\nimport
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/hooks/useAISettings.ts"],"sourcesContent":["'use client'\n\nimport { useEffect, useState } from 'react'\n\nimport type { AISettingsData } from '../../ai/providers/types.js'\n\n/**\n * Cached AI settings per depth.\n * We still cache to avoid duplicate requests during a single render/mount cycle,\n * but we always revalidate on mount so changes made in AI Providers appear in Instructions.\n */\nconst cachedDataByDepth = new Map<number, AISettingsData | null>()\nconst fetchPromiseByDepth = new Map<number, Promise<AISettingsData | null>>()\n\n/**\n * Shared hook for fetching AI settings from `/api/globals/ai-providers`.\n *\n * Features:\n * - Module-level cache to prevent redundant fetches across components\n * - Deduplicates in-flight requests (if 3 components mount at once, only 1 fetch fires)\n * - Optional `depth` parameter for controlling response depth\n *\n * @example\n * ```ts\n * const { data, isLoading } = useAISettings()\n * const providers = data?.providers ?? []\n * ```\n */\nexport function useAISettings(options?: { depth?: number }) {\n const depth = options?.depth ?? 1\n const initialCached = cachedDataByDepth.get(depth) ?? null\n const [data, setData] = useState<AISettingsData | null>(initialCached)\n const [isLoading, setIsLoading] = useState(!initialCached)\n\n useEffect(() => {\n const cached = cachedDataByDepth.get(depth) ?? null\n if (cached) {\n setData(cached)\n setIsLoading(false)\n } else {\n setIsLoading(true)\n }\n\n // Deduplicate in-flight requests per depth and always revalidate on mount.\n let fetchPromise = fetchPromiseByDepth.get(depth) ?? null\n if (!fetchPromise) {\n fetchPromise = fetch(`/api/globals/ai-providers?depth=${depth}`, {\n cache: 'no-store',\n credentials: 'include',\n })\n .then(async (res) => {\n if (res.ok) {\n const json = await res.json()\n cachedDataByDepth.set(depth, json as AISettingsData)\n return json as AISettingsData\n }\n return null\n })\n .catch(() => null)\n .finally(() => {\n fetchPromiseByDepth.delete(depth)\n })\n\n fetchPromiseByDepth.set(depth, fetchPromise)\n }\n\n void fetchPromise.then((result) => {\n setData(result)\n setIsLoading(false)\n })\n }, [depth])\n\n return { data, isLoading }\n}\n\n/**\n * Invalidate the cached AI settings, forcing the next `useAISettings` call to re-fetch.\n * Useful after saving settings.\n */\nexport function invalidateAISettings(): void {\n cachedDataByDepth.clear()\n fetchPromiseByDepth.clear()\n}\n"],"names":["useEffect","useState","cachedDataByDepth","Map","fetchPromiseByDepth","useAISettings","options","depth","initialCached","get","data","setData","isLoading","setIsLoading","cached","fetchPromise","fetch","cache","credentials","then","res","ok","json","set","catch","finally","delete","result","invalidateAISettings","clear"],"mappings":"AAAA;AAEA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAI3C;;;;CAIC,GACD,MAAMC,oBAAoB,IAAIC;AAC9B,MAAMC,sBAAsB,IAAID;AAEhC;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASE,cAAcC,OAA4B;IACxD,MAAMC,QAAQD,SAASC,SAAS;IAChC,MAAMC,gBAAgBN,kBAAkBO,GAAG,CAACF,UAAU;IACtD,MAAM,CAACG,MAAMC,QAAQ,GAAGV,SAAgCO;IACxD,MAAM,CAACI,WAAWC,aAAa,GAAGZ,SAAS,CAACO;IAE5CR,UAAU;QACR,MAAMc,SAASZ,kBAAkBO,GAAG,CAACF,UAAU;QAC/C,IAAIO,QAAQ;YACVH,QAAQG;YACRD,aAAa;QACf,OAAO;YACLA,aAAa;QACf;QAEA,2EAA2E;QAC3E,IAAIE,eAAeX,oBAAoBK,GAAG,CAACF,UAAU;QACrD,IAAI,CAACQ,cAAc;YACjBA,eAAeC,MAAM,CAAC,gCAAgC,EAAET,MAAM,CAAC,EAAE;gBAC/DU,OAAO;gBACPC,aAAa;YACf,GACGC,IAAI,CAAC,OAAOC;gBACX,IAAIA,IAAIC,EAAE,EAAE;oBACV,MAAMC,OAAO,MAAMF,IAAIE,IAAI;oBAC3BpB,kBAAkBqB,GAAG,CAAChB,OAAOe;oBAC7B,OAAOA;gBACT;gBACA,OAAO;YACT,GACCE,KAAK,CAAC,IAAM,MACZC,OAAO,CAAC;gBACPrB,oBAAoBsB,MAAM,CAACnB;YAC7B;YAEFH,oBAAoBmB,GAAG,CAAChB,OAAOQ;QACjC;QAEA,KAAKA,aAAaI,IAAI,CAAC,CAACQ;YACtBhB,QAAQgB;YACRd,aAAa;QACf;IACF,GAAG;QAACN;KAAM;IAEV,OAAO;QAAEG;QAAME;IAAU;AAC3B;AAEA;;;CAGC,GACD,OAAO,SAASgB;IACd1B,kBAAkB2B,KAAK;IACvBzB,oBAAoByB,KAAK;AAC3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/providerOptions/updateProviderOptionsValue.ts"],"sourcesContent":["function isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction cloneRecord(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) {\n return {}\n }\n\n return JSON.parse(JSON.stringify(value)) as Record<string, unknown>\n}\n\nfunction pruneEmptyObjects(node: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(node)) {\n if (!isRecord(value)) {\n continue\n }\n\n pruneEmptyObjects(value)\n if (Object.keys(value).length === 0) {\n delete node[key]\n }\n }\n}\n\nexport function updateProviderOptionsValue({\n currentValue,\n keyPath,\n provider,\n targetValue,\n}: {\n currentValue: unknown\n keyPath: string[]\n provider?: string\n targetValue: unknown\n}): Record<string, unknown>
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/providerOptions/updateProviderOptionsValue.ts"],"sourcesContent":["function isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction cloneRecord(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) {\n return {}\n }\n\n return JSON.parse(JSON.stringify(value)) as Record<string, unknown>\n}\n\nfunction pruneEmptyObjects(node: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(node)) {\n if (!isRecord(value)) {\n continue\n }\n\n pruneEmptyObjects(value)\n if (Object.keys(value).length === 0) {\n delete node[key]\n }\n }\n}\n\nexport function updateProviderOptionsValue({\n currentValue,\n keyPath,\n provider,\n targetValue,\n}: {\n currentValue: unknown\n keyPath: string[]\n provider?: string\n targetValue: unknown\n}): null | Record<string, unknown> {\n if (!provider || keyPath.length === 0) {\n return isRecord(currentValue) ? cloneRecord(currentValue) : null\n }\n\n const nextProviderOptions = cloneRecord(currentValue)\n const currentProviderOptions = isRecord(nextProviderOptions[provider])\n ? cloneRecord(nextProviderOptions[provider])\n : {}\n\n let targetNode = currentProviderOptions\n for (let i = 0; i < keyPath.length - 1; i++) {\n const segment = keyPath[i]\n if (!isRecord(targetNode[segment])) {\n targetNode[segment] = {}\n }\n targetNode = targetNode[segment] as Record<string, unknown>\n }\n\n const finalKey = keyPath[keyPath.length - 1]\n if (targetValue === undefined) {\n delete targetNode[finalKey]\n } else {\n targetNode[finalKey] = targetValue\n }\n\n pruneEmptyObjects(currentProviderOptions)\n\n if (Object.keys(currentProviderOptions).length === 0) {\n delete nextProviderOptions[provider]\n } else {\n nextProviderOptions[provider] = currentProviderOptions\n }\n\n return Object.keys(nextProviderOptions).length > 0 ? nextProviderOptions : null\n}\n"],"names":["isRecord","value","Array","isArray","cloneRecord","JSON","parse","stringify","pruneEmptyObjects","node","key","Object","entries","keys","length","updateProviderOptionsValue","currentValue","keyPath","provider","targetValue","nextProviderOptions","currentProviderOptions","targetNode","i","segment","finalKey","undefined"],"mappings":"AAAA,SAASA,SAASC,KAAc;IAC9B,OAAO,CAAC,CAACA,SAAS,OAAOA,UAAU,YAAY,CAACC,MAAMC,OAAO,CAACF;AAChE;AAEA,SAASG,YAAYH,KAAc;IACjC,IAAI,CAACD,SAASC,QAAQ;QACpB,OAAO,CAAC;IACV;IAEA,OAAOI,KAAKC,KAAK,CAACD,KAAKE,SAAS,CAACN;AACnC;AAEA,SAASO,kBAAkBC,IAA6B;IACtD,KAAK,MAAM,CAACC,KAAKT,MAAM,IAAIU,OAAOC,OAAO,CAACH,MAAO;QAC/C,IAAI,CAACT,SAASC,QAAQ;YACpB;QACF;QAEAO,kBAAkBP;QAClB,IAAIU,OAAOE,IAAI,CAACZ,OAAOa,MAAM,KAAK,GAAG;YACnC,OAAOL,IAAI,CAACC,IAAI;QAClB;IACF;AACF;AAEA,OAAO,SAASK,2BAA2B,EACzCC,YAAY,EACZC,OAAO,EACPC,QAAQ,EACRC,WAAW,EAMZ;IACC,IAAI,CAACD,YAAYD,QAAQH,MAAM,KAAK,GAAG;QACrC,OAAOd,SAASgB,gBAAgBZ,YAAYY,gBAAgB;IAC9D;IAEA,MAAMI,sBAAsBhB,YAAYY;IACxC,MAAMK,yBAAyBrB,SAASoB,mBAAmB,CAACF,SAAS,IACjEd,YAAYgB,mBAAmB,CAACF,SAAS,IACzC,CAAC;IAEL,IAAII,aAAaD;IACjB,IAAK,IAAIE,IAAI,GAAGA,IAAIN,QAAQH,MAAM,GAAG,GAAGS,IAAK;QAC3C,MAAMC,UAAUP,OAAO,CAACM,EAAE;QAC1B,IAAI,CAACvB,SAASsB,UAAU,CAACE,QAAQ,GAAG;YAClCF,UAAU,CAACE,QAAQ,GAAG,CAAC;QACzB;QACAF,aAAaA,UAAU,CAACE,QAAQ;IAClC;IAEA,MAAMC,WAAWR,OAAO,CAACA,QAAQH,MAAM,GAAG,EAAE;IAC5C,IAAIK,gBAAgBO,WAAW;QAC7B,OAAOJ,UAAU,CAACG,SAAS;IAC7B,OAAO;QACLH,UAAU,CAACG,SAAS,GAAGN;IACzB;IAEAX,kBAAkBa;IAElB,IAAIV,OAAOE,IAAI,CAACQ,wBAAwBP,MAAM,KAAK,GAAG;QACpD,OAAOM,mBAAmB,CAACF,SAAS;IACtC,OAAO;QACLE,mBAAmB,CAACF,SAAS,GAAGG;IAClC;IAEA,OAAOV,OAAOE,IAAI,CAACO,qBAAqBN,MAAM,GAAG,IAAIM,sBAAsB;AAC7E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utilities/ai/resolveEffectiveInstructionSettings.ts"],"sourcesContent":["export type InstructionUseCase = 'image' | 'text' | 'tts' | 'video'\n\nconst hasMeaningfulValue = (value: unknown): boolean => {\n if (value === null || value === undefined) {\n return false\n }\n\n if (typeof value === 'string') {\n return value.trim() !== ''\n }\n\n return true\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction deepMergeRecords(\n base: Record<string, unknown>,\n override: Record<string, unknown>,\n): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...base }\n\n for (const [key, value] of Object.entries(override)) {\n const current = merged[key]\n if (isRecord(current) && isRecord(value)) {\n merged[key] = deepMergeRecords(current, value)\n continue\n }\n merged[key] = value\n }\n\n return merged\n}\n\nexport function getInstructionSettingsName(modelId: unknown): string | undefined {\n if (modelId === 'text') {\n return 'text-settings'\n }\n if (modelId === 'richtext') {\n return 'richtext-settings'\n }\n if (modelId === 'array') {\n return 'array-settings'\n }\n if (modelId === 'image') {\n return 'image-settings'\n }\n if (modelId === 'tts') {\n return 'tts-settings'\n }\n if (modelId === 'video') {\n return 'video-settings'\n }\n\n return undefined\n}\n\nexport function getInstructionUseCase(modelId: unknown): InstructionUseCase | undefined {\n if (modelId === 'text' || modelId === 'richtext' || modelId === 'array') {\n return 'text'\n }\n if (modelId === 'image') {\n return 'image'\n }\n if (modelId === 'tts') {\n return 'tts'\n }\n if (modelId === 'video') {\n return 'video'\n }\n\n return undefined\n}\nexport function resolveEffectiveInstructionSettings({\n defaults,\n instructions,\n}: {\n defaults?: Record<string, any>\n instructions: Record<string, any>\n}): {\n effectiveSettings: Record<string, unknown>\n settingsName?: string\n useCase?: InstructionUseCase\n} {\n const modelId = instructions['model-id']\n const settingsName = getInstructionSettingsName(modelId)\n const useCase = getInstructionUseCase(modelId)\n\n if (!settingsName || !useCase) {\n return { effectiveSettings: {}, settingsName, useCase }\n }\n\n const defaultsForUseCase = (defaults?.[useCase] || {}) as Record<string, unknown>\n const instructionSettings = (instructions[settingsName] || {}) as Record<string, unknown>\n const effectiveSettings: Record<string, unknown> = {\n ...defaultsForUseCase,\n }\n\n for (const [key, value] of Object.entries(instructionSettings)) {\n if (key === 'providerOptions') {\n const selectedProvider =\n typeof instructionSettings.provider === 'string'\n ? instructionSettings.provider\n : typeof defaultsForUseCase.provider === 'string'\n ? defaultsForUseCase.provider\n : undefined\n\n if (selectedProvider && isRecord(value) && isRecord(value[selectedProvider])) {\n const existingOpts = isRecord(effectiveSettings.providerOptions)\n ? effectiveSettings.providerOptions\n : {}\n const existingProviderOpts = isRecord(existingOpts[selectedProvider])\n ? existingOpts[selectedProvider]\n : {}\n const incomingProviderOpts = value[selectedProvider]
|
|
1
|
+
{"version":3,"sources":["../../../src/utilities/ai/resolveEffectiveInstructionSettings.ts"],"sourcesContent":["export type InstructionUseCase = 'image' | 'text' | 'tts' | 'video'\n\nconst hasMeaningfulValue = (value: unknown): boolean => {\n if (value === null || value === undefined) {\n return false\n }\n\n if (typeof value === 'string') {\n return value.trim() !== ''\n }\n\n return true\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction deepMergeRecords(\n base: Record<string, unknown>,\n override: Record<string, unknown>,\n): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...base }\n\n for (const [key, value] of Object.entries(override)) {\n const current = merged[key]\n if (isRecord(current) && isRecord(value)) {\n merged[key] = deepMergeRecords(current, value)\n continue\n }\n merged[key] = value\n }\n\n return merged\n}\n\nexport function getInstructionSettingsName(modelId: unknown): string | undefined {\n if (modelId === 'text') {\n return 'text-settings'\n }\n if (modelId === 'richtext') {\n return 'richtext-settings'\n }\n if (modelId === 'array') {\n return 'array-settings'\n }\n if (modelId === 'image') {\n return 'image-settings'\n }\n if (modelId === 'tts') {\n return 'tts-settings'\n }\n if (modelId === 'video') {\n return 'video-settings'\n }\n\n return undefined\n}\n\nexport function getInstructionUseCase(modelId: unknown): InstructionUseCase | undefined {\n if (modelId === 'text' || modelId === 'richtext' || modelId === 'array') {\n return 'text'\n }\n if (modelId === 'image') {\n return 'image'\n }\n if (modelId === 'tts') {\n return 'tts'\n }\n if (modelId === 'video') {\n return 'video'\n }\n\n return undefined\n}\nexport function resolveEffectiveInstructionSettings({\n defaults,\n instructions,\n}: {\n defaults?: Record<string, any>\n instructions: Record<string, any>\n}): {\n effectiveSettings: Record<string, unknown>\n settingsName?: string\n useCase?: InstructionUseCase\n} {\n const modelId = instructions['model-id']\n const settingsName = getInstructionSettingsName(modelId)\n const useCase = getInstructionUseCase(modelId)\n\n if (!settingsName || !useCase) {\n return { effectiveSettings: {}, settingsName, useCase }\n }\n\n const defaultsForUseCase = (defaults?.[useCase] || {}) as Record<string, unknown>\n const instructionSettings = (instructions[settingsName] || {}) as Record<string, unknown>\n const effectiveSettings: Record<string, unknown> = {\n ...defaultsForUseCase,\n }\n\n for (const [key, value] of Object.entries(instructionSettings)) {\n if (key === 'providerOptions') {\n const selectedProvider =\n typeof instructionSettings.provider === 'string'\n ? instructionSettings.provider\n : typeof defaultsForUseCase.provider === 'string'\n ? defaultsForUseCase.provider\n : undefined\n\n if (selectedProvider && isRecord(value) && isRecord(value[selectedProvider])) {\n const existingOpts = isRecord(effectiveSettings.providerOptions)\n ? effectiveSettings.providerOptions\n : {}\n const existingProviderOpts = isRecord(existingOpts[selectedProvider])\n ? existingOpts[selectedProvider]\n : {}\n const incomingProviderOpts = value[selectedProvider]\n\n effectiveSettings.providerOptions = {\n ...existingOpts,\n [selectedProvider]: {\n ...deepMergeRecords(existingProviderOpts, incomingProviderOpts),\n },\n }\n }\n continue\n }\n\n if (hasMeaningfulValue(value)) {\n effectiveSettings[key] = value\n }\n }\n\n return {\n effectiveSettings,\n settingsName,\n useCase,\n }\n}\n\nexport function applyInstructionDefaultsForDisplay({\n defaults,\n instructions,\n}: {\n defaults?: Record<string, any>\n instructions: Record<string, any>\n}): Record<string, any> {\n const { settingsName, useCase } = resolveEffectiveInstructionSettings({ defaults, instructions })\n\n if (!settingsName || !useCase) {\n return instructions\n }\n\n const defaultsForUseCase = (defaults?.[useCase] || {}) as Record<string, unknown>\n const group = ((instructions[settingsName] || {}) as Record<string, unknown>)\n const updatedGroup: Record<string, unknown> = {\n ...group,\n }\n\n if (!hasMeaningfulValue(updatedGroup.provider) && hasMeaningfulValue(defaultsForUseCase.provider)) {\n updatedGroup.provider = defaultsForUseCase.provider\n }\n\n if (!hasMeaningfulValue(updatedGroup.model) && hasMeaningfulValue(defaultsForUseCase.model)) {\n updatedGroup.model = defaultsForUseCase.model\n }\n\n if (useCase === 'tts' && !hasMeaningfulValue(updatedGroup.voice) && hasMeaningfulValue(defaultsForUseCase.voice)) {\n updatedGroup.voice = defaultsForUseCase.voice\n }\n\n if (JSON.stringify(group) === JSON.stringify(updatedGroup)) {\n return instructions\n }\n\n return {\n ...instructions,\n [settingsName]: updatedGroup,\n }\n}\n"],"names":["hasMeaningfulValue","value","undefined","trim","isRecord","Array","isArray","deepMergeRecords","base","override","merged","key","Object","entries","current","getInstructionSettingsName","modelId","getInstructionUseCase","resolveEffectiveInstructionSettings","defaults","instructions","settingsName","useCase","effectiveSettings","defaultsForUseCase","instructionSettings","selectedProvider","provider","existingOpts","providerOptions","existingProviderOpts","incomingProviderOpts","applyInstructionDefaultsForDisplay","group","updatedGroup","model","voice","JSON","stringify"],"mappings":"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"}
|
|
@@ -49,7 +49,7 @@ export const updateFieldsConfig = (collectionConfig)=>{
|
|
|
49
49
|
}
|
|
50
50
|
// Array fields use ArrayComposeField (always visible) since they don't have focus events
|
|
51
51
|
// Other fields use ComposeField with focus-dependent visibility
|
|
52
|
-
const componentPath = field.type === 'array' ? '@ai-stack/payloadcms/fields#ArrayComposeField' : '@ai-stack/payloadcms/fields#ComposeField';
|
|
52
|
+
const componentPath = field.type === 'array' ? '@ai-stack/payloadcms/fields/ArrayComposeField/ArrayComposeField.js#ArrayComposeField' : '@ai-stack/payloadcms/fields/ComposeField/ComposeField.js#ComposeField';
|
|
53
53
|
return {
|
|
54
54
|
...field,
|
|
55
55
|
admin: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utilities/fields/updateFieldsConfig.ts"],"sourcesContent":["import type { CollectionConfig, GlobalConfig } from 'payload'\n\ninterface UpdateFieldsConfig {\n schemaPathMap: Record<string, any>\n updatedCollectionConfig: CollectionConfig | GlobalConfig\n}\n\nexport const updateFieldsConfig = (collectionConfig: CollectionConfig | GlobalConfig): UpdateFieldsConfig => {\n let schemaPathMap = {}\n\n function updateField(field: any, parentPath = ''): any {\n const currentPath = field.name\n ? parentPath\n ? `${parentPath}.${field.name}`\n : field.name\n : parentPath\n const currentSchemaPath = `${collectionConfig.slug}.${currentPath}`\n\n // Disabled fields/ field types\n if (\n field.admin?.disabled ||\n field.admin?.readOnly ||\n field.admin?.hidden ||\n field.type === 'row'\n ) {\n return field\n }\n\n // Developer opt-out: custom.ai.enabled === false skips compose injection entirely\n const aiConfig = field.custom?.ai\n const isAiDisabledByDev = aiConfig?.enabled === false\n\n // Map field path for global fieldInstructionsMap to load related instructions\n // This is done due to save extra API call to get instructions when Field components are loaded in admin\n // Doing is will only call instructions data when user clicks on settings\n if (['array', 'richText', 'text', 'textarea', 'upload'].includes(field.type) && !isAiDisabledByDev) {\n schemaPathMap = {\n ...schemaPathMap,\n [currentSchemaPath]: {\n type: field.type,\n custom: field.custom,\n hasMany: field.hasMany === true,\n label: field.label || field.name,\n relationTo: field.relationTo,\n },\n }\n }\n\n // Inject AI actions, richText is not included here as it has to be explicitly defined by user\n // Array fields also get AI injection for bulk generation\n if (['array', 'text', 'textarea', 'upload'].includes(field.type) && !isAiDisabledByDev) {\n let customField = {}\n\n // Custom fields don't fully adhere to the Payload schema, making it difficult to\n // determine which components support injecting ComposeField as a Description.\n if (field.admin?.components?.Field || field.admin?.components?.Description) {\n // TODO: If a field already provides its own Description, we still inject our ComposeField\n // by overriding Description. If you need both, consider composing your own wrapper.\n customField = {}\n }\n\n // Array fields use ArrayComposeField (always visible) since they don't have focus events\n // Other fields use ComposeField with focus-dependent visibility\n const componentPath = field.type === 'array'\n ? '@ai-stack/payloadcms/fields#ArrayComposeField'\n : '@ai-stack/payloadcms/fields#ComposeField'\n\n return {\n ...field,\n admin: {\n ...field.admin,\n components: {\n ...(field.admin?.components || {}),\n Description: {\n clientProps: {\n alwaysShow: !!aiConfig?.alwaysShow,\n schemaPath: currentSchemaPath,\n },\n path: componentPath,\n },\n ...customField,\n },\n },\n }\n }\n\n if (field.fields) {\n return {\n ...field,\n fields: field.fields.map((subField: any) => updateField(subField, currentPath)),\n }\n }\n\n if (field.tabs) {\n return {\n ...field,\n tabs: field.tabs.map((tab: any) => {\n return {\n ...tab,\n // Tabs are a UI construct and should not add to the schema path\n fields: (tab.fields || []).map((subField: any) => updateField(subField, parentPath)),\n }\n }),\n }\n }\n\n if (field.blocks) {\n return {\n ...field,\n blocks: field.blocks.map((block: any) => ({\n ...block,\n fields: block.fields.map((subField: any) =>\n updateField(subField, `${currentPath}.${block.slug}`),\n ),\n })),\n }\n }\n\n return field\n }\n\n const updatedCollectionConfig = {\n ...collectionConfig,\n fields: collectionConfig.fields.map((field) => updateField(field)),\n }\n\n return {\n schemaPathMap,\n updatedCollectionConfig,\n }\n}\n"],"names":["updateFieldsConfig","collectionConfig","schemaPathMap","updateField","field","parentPath","currentPath","name","currentSchemaPath","slug","admin","disabled","readOnly","hidden","type","aiConfig","custom","ai","isAiDisabledByDev","enabled","includes","hasMany","label","relationTo","customField","components","Field","Description","componentPath","clientProps","alwaysShow","schemaPath","path","fields","map","subField","tabs","tab","blocks","block","updatedCollectionConfig"],"mappings":"AAOA,OAAO,MAAMA,qBAAqB,CAACC;IACjC,IAAIC,gBAAgB,CAAC;IAErB,SAASC,YAAYC,KAAU,EAAEC,aAAa,EAAE;QAC9C,MAAMC,cAAcF,MAAMG,IAAI,GAC1BF,aACE,CAAC,EAAEA,WAAW,CAAC,EAAED,MAAMG,IAAI,CAAC,CAAC,GAC7BH,MAAMG,IAAI,GACZF;QACJ,MAAMG,oBAAoB,CAAC,EAAEP,iBAAiBQ,IAAI,CAAC,CAAC,EAAEH,YAAY,CAAC;QAEnE,+BAA+B;QAC/B,IACEF,MAAMM,KAAK,EAAEC,YACbP,MAAMM,KAAK,EAAEE,YACbR,MAAMM,KAAK,EAAEG,UACbT,MAAMU,IAAI,KAAK,OACf;YACA,OAAOV;QACT;QAEA,kFAAkF;QAClF,MAAMW,WAAWX,MAAMY,MAAM,EAAEC;QAC/B,MAAMC,oBAAoBH,UAAUI,YAAY;QAEhD,8EAA8E;QAC9E,wGAAwG;QACxG,yEAAyE;QACzE,IAAI;YAAC;YAAS;YAAY;YAAQ;YAAY;SAAS,CAACC,QAAQ,CAAChB,MAAMU,IAAI,KAAK,CAACI,mBAAmB;YAClGhB,gBAAgB;gBACd,GAAGA,aAAa;gBAChB,CAACM,kBAAkB,EAAE;oBACnBM,MAAMV,MAAMU,IAAI;oBAChBE,QAAQZ,MAAMY,MAAM;oBACpBK,SAASjB,MAAMiB,OAAO,KAAK;oBAC3BC,OAAOlB,MAAMkB,KAAK,IAAIlB,MAAMG,IAAI;oBAChCgB,YAAYnB,MAAMmB,UAAU;gBAC9B;YACF;QACF;QAEA,8FAA8F;QAC9F,yDAAyD;QACzD,IAAI;YAAC;YAAS;YAAQ;YAAY;SAAS,CAACH,QAAQ,CAAChB,MAAMU,IAAI,KAAK,CAACI,mBAAmB;YACtF,IAAIM,cAAc,CAAC;YAEnB,iFAAiF;YACjF,8EAA8E;YAC9E,IAAIpB,MAAMM,KAAK,EAAEe,YAAYC,SAAStB,MAAMM,KAAK,EAAEe,YAAYE,aAAa;gBAC1E,0FAA0F;gBAC1F,oFAAoF;gBACpFH,cAAc,CAAC;YACjB;YAEA,yFAAyF;YACzF,gEAAgE;YAChE,MAAMI,gBAAgBxB,MAAMU,IAAI,KAAK,UACjC,
|
|
1
|
+
{"version":3,"sources":["../../../src/utilities/fields/updateFieldsConfig.ts"],"sourcesContent":["import type { CollectionConfig, GlobalConfig } from 'payload'\n\ninterface UpdateFieldsConfig {\n schemaPathMap: Record<string, any>\n updatedCollectionConfig: CollectionConfig | GlobalConfig\n}\n\nexport const updateFieldsConfig = (collectionConfig: CollectionConfig | GlobalConfig): UpdateFieldsConfig => {\n let schemaPathMap = {}\n\n function updateField(field: any, parentPath = ''): any {\n const currentPath = field.name\n ? parentPath\n ? `${parentPath}.${field.name}`\n : field.name\n : parentPath\n const currentSchemaPath = `${collectionConfig.slug}.${currentPath}`\n\n // Disabled fields/ field types\n if (\n field.admin?.disabled ||\n field.admin?.readOnly ||\n field.admin?.hidden ||\n field.type === 'row'\n ) {\n return field\n }\n\n // Developer opt-out: custom.ai.enabled === false skips compose injection entirely\n const aiConfig = field.custom?.ai\n const isAiDisabledByDev = aiConfig?.enabled === false\n\n // Map field path for global fieldInstructionsMap to load related instructions\n // This is done due to save extra API call to get instructions when Field components are loaded in admin\n // Doing is will only call instructions data when user clicks on settings\n if (['array', 'richText', 'text', 'textarea', 'upload'].includes(field.type) && !isAiDisabledByDev) {\n schemaPathMap = {\n ...schemaPathMap,\n [currentSchemaPath]: {\n type: field.type,\n custom: field.custom,\n hasMany: field.hasMany === true,\n label: field.label || field.name,\n relationTo: field.relationTo,\n },\n }\n }\n\n // Inject AI actions, richText is not included here as it has to be explicitly defined by user\n // Array fields also get AI injection for bulk generation\n if (['array', 'text', 'textarea', 'upload'].includes(field.type) && !isAiDisabledByDev) {\n let customField = {}\n\n // Custom fields don't fully adhere to the Payload schema, making it difficult to\n // determine which components support injecting ComposeField as a Description.\n if (field.admin?.components?.Field || field.admin?.components?.Description) {\n // TODO: If a field already provides its own Description, we still inject our ComposeField\n // by overriding Description. If you need both, consider composing your own wrapper.\n customField = {}\n }\n\n // Array fields use ArrayComposeField (always visible) since they don't have focus events\n // Other fields use ComposeField with focus-dependent visibility\n const componentPath = field.type === 'array'\n ? '@ai-stack/payloadcms/fields/ArrayComposeField/ArrayComposeField.js#ArrayComposeField'\n : '@ai-stack/payloadcms/fields/ComposeField/ComposeField.js#ComposeField'\n\n return {\n ...field,\n admin: {\n ...field.admin,\n components: {\n ...(field.admin?.components || {}),\n Description: {\n clientProps: {\n alwaysShow: !!aiConfig?.alwaysShow,\n schemaPath: currentSchemaPath,\n },\n path: componentPath,\n },\n ...customField,\n },\n },\n }\n }\n\n if (field.fields) {\n return {\n ...field,\n fields: field.fields.map((subField: any) => updateField(subField, currentPath)),\n }\n }\n\n if (field.tabs) {\n return {\n ...field,\n tabs: field.tabs.map((tab: any) => {\n return {\n ...tab,\n // Tabs are a UI construct and should not add to the schema path\n fields: (tab.fields || []).map((subField: any) => updateField(subField, parentPath)),\n }\n }),\n }\n }\n\n if (field.blocks) {\n return {\n ...field,\n blocks: field.blocks.map((block: any) => ({\n ...block,\n fields: block.fields.map((subField: any) =>\n updateField(subField, `${currentPath}.${block.slug}`),\n ),\n })),\n }\n }\n\n return field\n }\n\n const updatedCollectionConfig = {\n ...collectionConfig,\n fields: collectionConfig.fields.map((field) => updateField(field)),\n }\n\n return {\n schemaPathMap,\n updatedCollectionConfig,\n }\n}\n"],"names":["updateFieldsConfig","collectionConfig","schemaPathMap","updateField","field","parentPath","currentPath","name","currentSchemaPath","slug","admin","disabled","readOnly","hidden","type","aiConfig","custom","ai","isAiDisabledByDev","enabled","includes","hasMany","label","relationTo","customField","components","Field","Description","componentPath","clientProps","alwaysShow","schemaPath","path","fields","map","subField","tabs","tab","blocks","block","updatedCollectionConfig"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { SerializedEditorState } from 'lexical';
|
|
2
|
-
export declare const lexicalToPromptTemplate: (editorState:
|
|
2
|
+
export declare const lexicalToPromptTemplate: (editorState: any | SerializedEditorState) => string;
|
|
@@ -44,7 +44,7 @@ export const lexicalToPromptTemplate = (editorState)=>{
|
|
|
44
44
|
// If the user typed `{{toHTML `, then inserted `#content`, then typed `}}`, the raw string is `{{toHTML {{content}}}}`.
|
|
45
45
|
// We can just replace `{{` and `}}` if they are surrounded by an outer bracket context.
|
|
46
46
|
// For safety, let's just fix the specific pattern of nested brackets for mentions.
|
|
47
|
-
return rawTemplate.replace(/({{[^{}]
|
|
47
|
+
return rawTemplate.replace(/(\{\{[^{}]*)\{\{([^}]+)\}\}(.*?\}\})/g, '$1$2$3');
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
//# sourceMappingURL=lexicalToPromptTemplate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utilities/lexical/lexicalToPromptTemplate.ts"],"sourcesContent":["import type { SerializedEditorState, SerializedLexicalNode } from 'lexical'\n\ninterface BeautifulMentionNode extends SerializedLexicalNode {\n trigger: string\n value: string\n
|
|
1
|
+
{"version":3,"sources":["../../../src/utilities/lexical/lexicalToPromptTemplate.ts"],"sourcesContent":["import type { SerializedEditorState, SerializedLexicalNode } from 'lexical'\n\ninterface BeautifulMentionNode extends SerializedLexicalNode {\n data?: Record<string, unknown>\n trigger: string\n value: string\n}\n\nexport const lexicalToPromptTemplate = (editorState: any | SerializedEditorState): string => {\n if (!editorState || !editorState.root) {\n return ''\n }\n\n const traverse = (node: SerializedLexicalNode): string => {\n if (node.type === 'text') {\n return (node as any).text || ''\n }\n\n if (node.type === 'beautifulMention') {\n const mentionNode = node as BeautifulMentionNode\n // Handle # (Field) -> {{value}}\n if (mentionNode.trigger === '#') {\n // If the value contains spaces or special chars, it might need brackets,\n // but usually for Handlebars variable replacement we expect {{field_name}}\n // The value from our endpoint is the full path e.g. \"array.0.field\"\n // We assume the value is ready for handlebars.\n return `{{${mentionNode.value}}}`\n }\n // Handle @ (Image) -> @value\n if (mentionNode.trigger === '@') {\n return `@${mentionNode.value}`\n }\n return mentionNode.value\n }\n\n if (node.type === 'paragraph') {\n const childrenContent = (node as any).children?.map(traverse).join('') || ''\n return childrenContent + '\\n'\n }\n\n if ((node as any).children) {\n return (node as any).children.map(traverse).join('')\n }\n\n return ''\n }\n\n const rawTemplate = (editorState.root.children || []).map(traverse).join('').trim()\n \n // Post-process the template to fix nested handlebars syntax\n // Example 1: `{{toHTML {{content}}}}` -> `{{toHTML content}}`\n // Example 2: `{{#each {{array}}}}` -> `{{#each array}}`\n // Matches any handlebar opening `{{` or `{{#` or `{{/` followed by anything, followed by `{{value}}`, followed by `}}`\n // Actually, a simpler regex: replace `{{(` with `{{` is wrong.\n // We want to replace `{{... {{value}} ...}}` with `{{... value ...}}`\n // Regex to find `{{` inside another `{{` `}}` block is tricky.\n // Instead, let's just globally replace `{{` and `}}` that are immediately inside another tag.\n // Let's use a simpler heuristic: if a mention trigger `#` was used, it returned `{{value}}`.\n // If the user typed `{{toHTML `, then inserted `#content`, then typed `}}`, the raw string is `{{toHTML {{content}}}}`.\n // We can just replace `{{` and `}}` if they are surrounded by an outer bracket context.\n // For safety, let's just fix the specific pattern of nested brackets for mentions.\n return rawTemplate.replace(/(\\{\\{[^{}]*)\\{\\{([^}]+)\\}\\}(.*?\\}\\})/g, '$1$2$3')\n}\n"],"names":["lexicalToPromptTemplate","editorState","root","traverse","node","type","text","mentionNode","trigger","value","childrenContent","children","map","join","rawTemplate","trim","replace"],"mappings":"AAQA,OAAO,MAAMA,0BAA0B,CAACC;IACtC,IAAI,CAACA,eAAe,CAACA,YAAYC,IAAI,EAAE;QACrC,OAAO;IACT;IAEA,MAAMC,WAAW,CAACC;QAChB,IAAIA,KAAKC,IAAI,KAAK,QAAQ;YACxB,OAAO,AAACD,KAAaE,IAAI,IAAI;QAC/B;QAEA,IAAIF,KAAKC,IAAI,KAAK,oBAAoB;YACpC,MAAME,cAAcH;YACpB,gCAAgC;YAChC,IAAIG,YAAYC,OAAO,KAAK,KAAK;gBAC7B,yEAAyE;gBACzE,2EAA2E;gBAC3E,oEAAoE;gBACpE,+CAA+C;gBAC/C,OAAO,CAAC,EAAE,EAAED,YAAYE,KAAK,CAAC,EAAE,CAAC;YACrC;YACA,6BAA6B;YAC7B,IAAIF,YAAYC,OAAO,KAAK,KAAK;gBAC7B,OAAO,CAAC,CAAC,EAAED,YAAYE,KAAK,CAAC,CAAC;YAClC;YACA,OAAOF,YAAYE,KAAK;QAC1B;QAEA,IAAIL,KAAKC,IAAI,KAAK,aAAa;YAC7B,MAAMK,kBAAkB,AAACN,KAAaO,QAAQ,EAAEC,IAAIT,UAAUU,KAAK,OAAO;YAC1E,OAAOH,kBAAkB;QAC3B;QAEA,IAAI,AAACN,KAAaO,QAAQ,EAAE;YAC1B,OAAO,AAACP,KAAaO,QAAQ,CAACC,GAAG,CAACT,UAAUU,IAAI,CAAC;QACnD;QAEA,OAAO;IACT;IAEA,MAAMC,cAAc,AAACb,CAAAA,YAAYC,IAAI,CAACS,QAAQ,IAAI,EAAE,AAAD,EAAGC,GAAG,CAACT,UAAUU,IAAI,CAAC,IAAIE,IAAI;IAEjF,4DAA4D;IAC5D,8DAA8D;IAC9D,wDAAwD;IACxD,uHAAuH;IACvH,+DAA+D;IAC/D,sEAAsE;IACtE,+DAA+D;IAC/D,8FAA8F;IAC9F,6FAA6F;IAC7F,wHAAwH;IACxH,wFAAwF;IACxF,mFAAmF;IACnF,OAAOD,YAAYE,OAAO,CAAC,yCAAyC;AACtE,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utilities/lexical/stringToLexicalJSON.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../../src/utilities/lexical/stringToLexicalJSON.ts"],"sourcesContent":["/* eslint-disable */\nimport type { SerializedEditorState, SerializedParagraphNode, SerializedTextNode } from 'lexical'\n\nexport const stringToLexicalJSON = (text: string): SerializedEditorState => {\n const rootChildren: SerializedParagraphNode[] = []\n\n const lines = text.split('\\n')\n\n for (const line of lines) {\n const children: SerializedTextNode[] = []\n if (line.length > 0) {\n children.push({\n detail: 0,\n format: 0,\n mode: 'normal',\n style: '',\n text: line,\n type: 'text',\n version: 1,\n })\n }\n\n rootChildren.push({\n children,\n direction: 'ltr',\n format: '',\n indent: 0,\n type: 'paragraph',\n version: 1,\n textFormat: 0, \n } as any)\n }\n\n return {\n root: {\n children: rootChildren,\n direction: 'ltr',\n format: '',\n indent: 0,\n type: 'root',\n version: 1,\n },\n }\n}\n"],"names":["stringToLexicalJSON","text","rootChildren","lines","split","line","children","length","push","detail","format","mode","style","type","version","direction","indent","textFormat","root"],"mappings":"AAAA,kBAAkB,GAGlB,OAAO,MAAMA,sBAAsB,CAACC;IAClC,MAAMC,eAA0C,EAAE;IAElD,MAAMC,QAAQF,KAAKG,KAAK,CAAC;IAEzB,KAAK,MAAMC,QAAQF,MAAO;QACxB,MAAMG,WAAiC,EAAE;QACzC,IAAID,KAAKE,MAAM,GAAG,GAAG;YACnBD,SAASE,IAAI,CAAC;gBACZC,QAAQ;gBACRC,QAAQ;gBACRC,MAAM;gBACNC,OAAO;gBACPX,MAAMI;gBACNQ,MAAM;gBACNC,SAAS;YACX;QACF;QAEAZ,aAAaM,IAAI,CAAC;YAChBF;YACAS,WAAW;YACXL,QAAQ;YACRM,QAAQ;YACRH,MAAM;YACNC,SAAS;YACTG,YAAY;QACd;IACF;IAEA,OAAO;QACLC,MAAM;YACJZ,UAAUJ;YACVa,WAAW;YACXL,QAAQ;YACRM,QAAQ;YACRH,MAAM;YACNC,SAAS;QACX;IACF;AACF,EAAC"}
|
|
@@ -44,9 +44,14 @@ export const seedProperties = async ({ enabledCollections, req })=>{
|
|
|
44
44
|
updateData.hasMany = !!hasMany;
|
|
45
45
|
needsUpdate = true;
|
|
46
46
|
}
|
|
47
|
+
if (!hasMany && !!doc.appendGenerated) {
|
|
48
|
+
// Keep legacy records consistent when field is no longer hasMany.
|
|
49
|
+
updateData.appendGenerated = false;
|
|
50
|
+
needsUpdate = true;
|
|
51
|
+
}
|
|
47
52
|
// If developer has provided custom prompts in the schema, update the existing record
|
|
48
53
|
// but only if the values have actually changed.
|
|
49
|
-
if (custom?.ai?.prompt || custom?.ai?.system || custom?.ai?.alwaysShow !== undefined) {
|
|
54
|
+
if (custom?.ai?.prompt || custom?.ai?.system || custom?.ai?.alwaysShow !== undefined || custom?.ai?.appendGenerated !== undefined || custom?.ai?.disabled !== undefined) {
|
|
50
55
|
if (custom?.ai?.prompt && custom.ai.prompt !== currentPrompt) {
|
|
51
56
|
updateData.prompt = stringToLexicalJSON(custom.ai.prompt);
|
|
52
57
|
needsUpdate = true;
|
|
@@ -59,6 +64,17 @@ export const seedProperties = async ({ enabledCollections, req })=>{
|
|
|
59
64
|
updateData.alwaysShow = !!custom.ai.alwaysShow;
|
|
60
65
|
needsUpdate = true;
|
|
61
66
|
}
|
|
67
|
+
if (custom?.ai?.disabled !== undefined && custom.ai.disabled !== doc.disabled) {
|
|
68
|
+
updateData.disabled = !!custom.ai.disabled;
|
|
69
|
+
needsUpdate = true;
|
|
70
|
+
}
|
|
71
|
+
if (custom?.ai?.appendGenerated !== undefined) {
|
|
72
|
+
const nextAppendGenerated = !!hasMany && !!custom.ai.appendGenerated;
|
|
73
|
+
if (nextAppendGenerated !== !!doc.appendGenerated) {
|
|
74
|
+
updateData.appendGenerated = nextAppendGenerated;
|
|
75
|
+
needsUpdate = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
62
78
|
}
|
|
63
79
|
if (needsUpdate) {
|
|
64
80
|
try {
|
|
@@ -94,7 +110,8 @@ export const seedProperties = async ({ enabledCollections, req })=>{
|
|
|
94
110
|
collection: PLUGIN_INSTRUCTIONS_TABLE,
|
|
95
111
|
data: {
|
|
96
112
|
alwaysShow: !!custom?.ai?.alwaysShow,
|
|
97
|
-
|
|
113
|
+
appendGenerated: !!hasMany && !!custom?.ai?.appendGenerated,
|
|
114
|
+
disabled: !!custom?.ai?.disabled,
|
|
98
115
|
'field-type': type,
|
|
99
116
|
hasMany: !!hasMany,
|
|
100
117
|
'model-id': modelId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/seedProperties.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { PLUGIN_INSTRUCTIONS_TABLE } from '../defaults.js'\nimport { updateFieldsConfig } from './fields/updateFieldsConfig.js'\nimport { stringToLexicalJSON } from './lexical/stringToLexicalJSON.js'\ninterface SeedPropertiesArgs {\n enabledCollections: string[]\n req: PayloadRequest\n}\n\ninterface SchemaPathFieldInfo {\n custom?: {
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/seedProperties.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { PLUGIN_INSTRUCTIONS_TABLE } from '../defaults.js'\nimport { updateFieldsConfig } from './fields/updateFieldsConfig.js'\nimport { stringToLexicalJSON } from './lexical/stringToLexicalJSON.js'\ninterface SeedPropertiesArgs {\n enabledCollections: string[]\n req: PayloadRequest\n}\n\ninterface SchemaPathFieldInfo {\n custom?: {\n ai?: {\n alwaysShow?: boolean\n appendGenerated?: boolean\n disabled?: boolean\n prompt?: string\n system?: string\n }\n }\n hasMany?: boolean\n relationTo?: string\n type: string\n}\n\nexport const seedProperties = async ({ enabledCollections, req }: SeedPropertiesArgs): Promise<void> => {\n const { payload } = req\n\n if (!enabledCollections || enabledCollections.length === 0) {\n return\n }\n\n // Get all collections from payload config\n const allCollections = payload.config.collections\n\n for (const collectionSlug of enabledCollections) {\n const collectionConfig = allCollections.find((c) => c.slug === collectionSlug)\n if (!collectionConfig) {\n continue\n }\n\n // Traverse the collection config effectively using updateFieldsConfig\n // Use the side-effect of getting schemaPathMap from it\n const { schemaPathMap } = updateFieldsConfig(collectionConfig)\n\n for (const [schemaPath, fieldInfo] of Object.entries(schemaPathMap)) {\n const typedFieldInfo = fieldInfo as SchemaPathFieldInfo\n const custom = typedFieldInfo.custom\n const hasMany = typedFieldInfo.hasMany\n const relationTo = typedFieldInfo.relationTo\n const type = typedFieldInfo.type\n\n // Check if instruction already exists\n const existingInstruction = await payload.find({\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n depth: 0,\n limit: 1,\n overrideAccess: true,\n where: {\n 'schema-path': {\n equals: schemaPath,\n },\n },\n })\n\n if (existingInstruction.totalDocs > 0) {\n const doc = existingInstruction.docs[0] as any\n const currentPrompt = doc.prompt\n const currentSystem = doc.system\n\n let needsUpdate = false\n const updateData: any = {}\n\n if (!!doc.hasMany !== !!hasMany) {\n updateData.hasMany = !!hasMany\n needsUpdate = true\n }\n if (!hasMany && !!doc.appendGenerated) {\n // Keep legacy records consistent when field is no longer hasMany.\n updateData.appendGenerated = false\n needsUpdate = true\n }\n\n // If developer has provided custom prompts in the schema, update the existing record\n // but only if the values have actually changed.\n if (\n custom?.ai?.prompt ||\n custom?.ai?.system ||\n custom?.ai?.alwaysShow !== undefined ||\n custom?.ai?.appendGenerated !== undefined ||\n custom?.ai?.disabled !== undefined\n ) {\n if (custom?.ai?.prompt && custom.ai.prompt !== currentPrompt) {\n updateData.prompt = stringToLexicalJSON(custom.ai.prompt)\n needsUpdate = true\n }\n if (custom?.ai?.system && custom.ai.system !== currentSystem) {\n updateData.system = custom.ai.system\n needsUpdate = true\n }\n if (custom?.ai?.alwaysShow !== undefined && custom.ai.alwaysShow !== doc.alwaysShow) {\n updateData.alwaysShow = !!custom.ai.alwaysShow\n needsUpdate = true\n }\n if (custom?.ai?.disabled !== undefined && custom.ai.disabled !== doc.disabled) {\n updateData.disabled = !!custom.ai.disabled\n needsUpdate = true\n }\n if (custom?.ai?.appendGenerated !== undefined) {\n const nextAppendGenerated = !!hasMany && !!custom.ai.appendGenerated\n if (nextAppendGenerated !== !!doc.appendGenerated) {\n updateData.appendGenerated = nextAppendGenerated\n needsUpdate = true\n }\n }\n }\n\n if (needsUpdate) {\n try {\n await payload.update({\n id: doc.id,\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n data: updateData,\n overrideAccess: true,\n })\n } catch (error) {\n payload.logger.error(`— AI Plugin: Failed to update instruction for ${schemaPath}: ${error}`)\n }\n }\n continue\n }\n\n // Use custom prompts if provided, otherwise leave empty\n const prompt = custom?.ai?.prompt ? stringToLexicalJSON(custom.ai.prompt) : undefined\n const system = custom?.ai?.system || ''\n\n // Determine model-id based on field type\n let modelId = 'text'\n if (type === 'richText') {\n modelId = 'richtext'\n }\n if (type === 'upload') {\n modelId = 'image'\n } // defaulting to image generation for uploads\n if (type === 'array') {\n modelId = 'array'\n }\n\n // Create new instruction\n try {\n await payload.create({\n collection: PLUGIN_INSTRUCTIONS_TABLE,\n data: {\n alwaysShow: !!custom?.ai?.alwaysShow,\n appendGenerated: !!hasMany && !!custom?.ai?.appendGenerated,\n disabled: !!custom?.ai?.disabled,\n 'field-type': type,\n hasMany: !!hasMany,\n 'model-id': modelId,\n prompt,\n 'relation-to': relationTo,\n 'schema-path': schemaPath,\n system,\n },\n overrideAccess: true,\n })\n } catch (error) {\n payload.logger.error(`— AI Plugin: Failed to seed instruction for ${schemaPath}: ${error}`)\n }\n }\n }\n}\n"],"names":["PLUGIN_INSTRUCTIONS_TABLE","updateFieldsConfig","stringToLexicalJSON","seedProperties","enabledCollections","req","payload","length","allCollections","config","collections","collectionSlug","collectionConfig","find","c","slug","schemaPathMap","schemaPath","fieldInfo","Object","entries","typedFieldInfo","custom","hasMany","relationTo","type","existingInstruction","collection","depth","limit","overrideAccess","where","equals","totalDocs","doc","docs","currentPrompt","prompt","currentSystem","system","needsUpdate","updateData","appendGenerated","ai","alwaysShow","undefined","disabled","nextAppendGenerated","update","id","data","error","logger","modelId","create"],"mappings":"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"}
|