@intlayer/ai 8.0.4 → 8.0.5

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.
@@ -0,0 +1,41 @@
1
+ You are an expert AI localization engine specialized in software internationalization (i18n). Your task is to translate and adapt content from a source locale to a specific target locale.
2
+
3
+ **CRITICAL INSTRUCTION:**
4
+
5
+ - **Source Language:** {{entryLocale}}
6
+ - **Target Language:** {{outputLocale}}
7
+ - **Strict Compliance:** You must translate the content **ONLY** into {{outputLocale}}. Never use any other language.
8
+
9
+ **Translation Guidelines:**
10
+
11
+ 1. **Preserve Structure:** The output TOON structure (keys, nesting, array lengths) must exactly match the input structure.
12
+ 2. **Key Integrity:** Do not translate, rename, or remove object keys.
13
+ 3. **Data Types:** Respect specific data types. If the source is a string, return a string. If it is a boolean or number, preserve it.
14
+ 4. **Formatting:**
15
+ - Escape special characters if necessary for valid TOON.
16
+ - Do not add markdown formatting (like `toon ... `) in the final output; return pure data matching the schema.
17
+ 5. **Node Types:** Do not translate values containing technical metadata such as `{ 'nodeType': 'XXX' }`.
18
+
19
+ **Localization Logic:**
20
+
21
+ - **Missing Content:** If a key is missing in the preset output, translate the entry content into the target language.
22
+ - **Dialect Handling:** Adapt the translation to the specific variant (e.g., `en-GB` vs `en-US`, `es-ES` vs `es-MX`).
23
+ - **Context Awareness:** Use the provided Dictionary Description and Application Context to inform tone and terminology.
24
+
25
+ **Mode Instruction:**
26
+ {{modeInstructions}}
27
+
28
+ **Tags Context:**
29
+ {{tagsInstructions}}
30
+
31
+ **Application Context:**
32
+ {{applicationContext}}
33
+
34
+ **Dictionary Description:**
35
+ {{dictionaryDescription}}
36
+
37
+ **Preset Output Content (Current State):**
38
+ {{presetOutputContent}}
39
+
40
+ **Final Goal:**
41
+ Return the fully translated/updated TOON object for the Target Language ({{outputLocale}}).
@@ -1,3 +1,4 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1
2
  let _ai_sdk_anthropic = require("@ai-sdk/anthropic");
2
3
  let _ai_sdk_deepseek = require("@ai-sdk/deepseek");
3
4
  let _ai_sdk_google = require("@ai-sdk/google");
@@ -91,7 +92,8 @@ const getAIConfig = async (options, isAuthenticated = false) => {
91
92
  if (!apiKey && aiOptions.provider !== AIProvider.OLLAMA) throw new Error(`API key for ${aiOptions.provider} is missing`);
92
93
  return {
93
94
  model: getLanguageModel(aiOptions, apiKey, defaultOptions?.model),
94
- temperature: aiOptions.temperature
95
+ temperature: aiOptions.temperature,
96
+ dataSerialization: aiOptions.dataSerialization
95
97
  };
96
98
  };
97
99
 
@@ -1 +1 @@
1
- {"version":3,"file":"aiSdk.cjs","names":[],"sources":["../../src/aiSdk.ts"],"sourcesContent":["import { type anthropic, createAnthropic } from '@ai-sdk/anthropic';\nimport { createDeepSeek, type deepseek } from '@ai-sdk/deepseek';\nimport { createGoogleGenerativeAI, type google } from '@ai-sdk/google';\nimport { createMistral, type mistral } from '@ai-sdk/mistral';\nimport { createOpenAI, type openai } from '@ai-sdk/openai';\nimport type {\n AssistantModelMessage,\n generateText,\n SystemModelMessage,\n ToolModelMessage,\n UserModelMessage,\n} from 'ai';\n\ntype AnthropicModel = Parameters<typeof anthropic>[0];\ntype DeepSeekModel = Parameters<typeof deepseek>[0];\ntype MistralModel = Parameters<typeof mistral>[0];\ntype OpenAIModel = Parameters<typeof openai>[0];\ntype GoogleModel = Parameters<typeof google>[0];\n\nexport type Messages = (\n | SystemModelMessage\n | UserModelMessage\n | AssistantModelMessage\n | ToolModelMessage\n)[];\n\n/**\n * Supported AI models\n */\nexport type Model =\n | AnthropicModel\n | DeepSeekModel\n | MistralModel\n | OpenAIModel\n | GoogleModel\n | (string & {});\n\n/**\n * Supported AI SDK providers\n */\nexport enum AIProvider {\n OPENAI = 'openai',\n ANTHROPIC = 'anthropic',\n MISTRAL = 'mistral',\n DEEPSEEK = 'deepseek',\n GEMINI = 'gemini',\n OLLAMA = 'ollama',\n}\n\nexport type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high' | 'none';\n\n/**\n * Common options for all AI providers\n */\nexport type AIOptions = {\n provider?: AIProvider;\n model?: Model;\n temperature?: number;\n baseURL?: string;\n apiKey?: string;\n applicationContext?: string;\n};\n\n// Define the structure of messages used in chat completions\nexport type ChatCompletionRequestMessage = {\n role: 'system' | 'user' | 'assistant'; // The role of the message sender\n content: string; // The text content of the message\n timestamp?: Date; // The timestamp of the message\n};\n\ntype AccessType = 'apiKey' | 'registered_user' | 'premium_user' | 'public';\n\nconst getAPIKey = (\n accessType: AccessType[],\n aiOptions?: AIOptions,\n isAuthenticated: boolean = false\n) => {\n const defaultApiKey = process.env.OPENAI_API_KEY;\n\n if (accessType.includes('public')) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n if (accessType.includes('apiKey') && aiOptions?.apiKey) {\n return aiOptions?.apiKey;\n }\n\n if (accessType.includes('registered_user') && isAuthenticated) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n // TODO: Implement premium user access\n if (accessType.includes('premium_user') && isAuthenticated) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n return undefined;\n};\n\nconst getModelName = (\n provider: AIProvider,\n userApiKey: string | undefined,\n userModel?: Model,\n defaultModel: Model = 'gpt-5-mini'\n): Model => {\n // If the user uses their own API key, allow custom model selection\n if (userApiKey || provider === AIProvider.OLLAMA) {\n if (provider === AIProvider.OPENAI) {\n return userModel ?? defaultModel;\n }\n\n if (userModel) {\n return userModel;\n }\n\n switch (provider) {\n case AIProvider.ANTHROPIC:\n return 'claude-sonnet-4-5-20250929';\n case AIProvider.MISTRAL:\n return 'mistral-large-latest';\n case AIProvider.DEEPSEEK:\n return 'deepseek-coder';\n case AIProvider.GEMINI:\n return 'gemini-2.5-flash';\n case AIProvider.OLLAMA:\n return '';\n default:\n return defaultModel;\n }\n }\n\n // Guard: Prevent custom model usage without a user API key\n if (userModel || provider) {\n throw new Error(\n 'The user should use his own API key to use a custom model'\n );\n }\n\n return defaultModel;\n};\n\nconst getLanguageModel = (\n aiOptions: AIOptions,\n apiKey: string | undefined,\n defaultModel?: Model\n) => {\n const selectedModel = getModelName(\n aiOptions.provider as AIProvider,\n apiKey,\n aiOptions.model,\n defaultModel\n );\n\n const baseURL = aiOptions.baseURL;\n\n switch (aiOptions.provider) {\n case AIProvider.OPENAI: {\n return createOpenAI({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.ANTHROPIC: {\n return createAnthropic({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.MISTRAL: {\n return createMistral({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.DEEPSEEK: {\n return createDeepSeek({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.GEMINI: {\n return createGoogleGenerativeAI({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.OLLAMA: {\n // Ollama compatible mode:\n const ollama = createOpenAI({\n baseURL: baseURL ?? 'http://localhost:11434/v1',\n apiKey: apiKey ?? 'ollama', // Required but unused by Ollama\n });\n\n return ollama.chat(selectedModel);\n }\n\n default: {\n throw new Error(`Provider ${aiOptions.provider} not supported`);\n }\n }\n};\n\nexport type AIConfig = Omit<Parameters<typeof generateText>[0], 'prompt'> & {\n reasoningEffort?: ReasoningEffort;\n textVerbosity?: 'low' | 'medium' | 'high';\n};\n\nconst DEFAULT_PROVIDER: AIProvider = AIProvider.OPENAI as AIProvider;\n\nexport type AIConfigOptions = {\n userOptions?: AIOptions;\n projectOptions?: AIOptions;\n defaultOptions?: AIOptions;\n accessType?: AccessType[];\n};\n\n/**\n * Get AI model configuration based on the selected provider and options\n * This function handles the configuration for different AI providers\n *\n * @param options Configuration options including provider, API keys, models and temperature\n * @returns Configured AI model ready to use with generateText\n */\nexport const getAIConfig = async (\n options: AIConfigOptions,\n isAuthenticated: boolean = false\n): Promise<AIConfig> => {\n const {\n userOptions,\n projectOptions,\n defaultOptions,\n accessType = ['registered_user'],\n } = options;\n\n const aiOptions = {\n provider: DEFAULT_PROVIDER,\n ...defaultOptions,\n ...projectOptions,\n ...userOptions,\n } satisfies AIOptions;\n\n const apiKey = getAPIKey(accessType, aiOptions, isAuthenticated);\n\n // Check if API key is provided\n if (!apiKey && aiOptions.provider !== AIProvider.OLLAMA) {\n throw new Error(`API key for ${aiOptions.provider} is missing`);\n }\n\n const languageModel = getLanguageModel(\n aiOptions,\n apiKey,\n defaultOptions?.model\n );\n\n return {\n model: languageModel,\n temperature: aiOptions.temperature,\n };\n};\n"],"mappings":";;;;;;;;;;AAwCA,IAAY,kDAAL;AACL;AACA;AACA;AACA;AACA;AACA;;;AA0BF,MAAM,aACJ,YACA,WACA,kBAA2B,UACxB;CACH,MAAM,gBAAgB,QAAQ,IAAI;AAElC,KAAI,WAAW,SAAS,SAAS,CAC/B,QAAO,WAAW,UAAU;AAG9B,KAAI,WAAW,SAAS,SAAS,IAAI,WAAW,OAC9C,QAAO,WAAW;AAGpB,KAAI,WAAW,SAAS,kBAAkB,IAAI,gBAC5C,QAAO,WAAW,UAAU;AAI9B,KAAI,WAAW,SAAS,eAAe,IAAI,gBACzC,QAAO,WAAW,UAAU;;AAMhC,MAAM,gBACJ,UACA,YACA,WACA,eAAsB,iBACZ;AAEV,KAAI,cAAc,aAAa,WAAW,QAAQ;AAChD,MAAI,aAAa,WAAW,OAC1B,QAAO,aAAa;AAGtB,MAAI,UACF,QAAO;AAGT,UAAQ,UAAR;GACE,KAAK,WAAW,UACd,QAAO;GACT,KAAK,WAAW,QACd,QAAO;GACT,KAAK,WAAW,SACd,QAAO;GACT,KAAK,WAAW,OACd,QAAO;GACT,KAAK,WAAW,OACd,QAAO;GACT,QACE,QAAO;;;AAKb,KAAI,aAAa,SACf,OAAM,IAAI,MACR,4DACD;AAGH,QAAO;;AAGT,MAAM,oBACJ,WACA,QACA,iBACG;CACH,MAAM,gBAAgB,aACpB,UAAU,UACV,QACA,UAAU,OACV,aACD;CAED,MAAM,UAAU,UAAU;AAE1B,SAAQ,UAAU,UAAlB;EACE,KAAK,WAAW,OACd,yCAAoB;GAClB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,UACd,+CAAuB;GACrB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,QACd,2CAAqB;GACnB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,SACd,6CAAsB;GACpB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,OACd,qDAAgC;GAC9B;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,OAOd,yCAL4B;GAC1B,SAAS,WAAW;GACpB,QAAQ,UAAU;GACnB,CAAC,CAEY,KAAK,cAAc;EAGnC,QACE,OAAM,IAAI,MAAM,YAAY,UAAU,SAAS,gBAAgB;;;AAUrE,MAAM,mBAA+B,WAAW;;;;;;;;AAgBhD,MAAa,cAAc,OACzB,SACA,kBAA2B,UACL;CACtB,MAAM,EACJ,aACA,gBACA,gBACA,aAAa,CAAC,kBAAkB,KAC9B;CAEJ,MAAM,YAAY;EAChB,UAAU;EACV,GAAG;EACH,GAAG;EACH,GAAG;EACJ;CAED,MAAM,SAAS,UAAU,YAAY,WAAW,gBAAgB;AAGhE,KAAI,CAAC,UAAU,UAAU,aAAa,WAAW,OAC/C,OAAM,IAAI,MAAM,eAAe,UAAU,SAAS,aAAa;AASjE,QAAO;EACL,OAPoB,iBACpB,WACA,QACA,gBAAgB,MACjB;EAIC,aAAa,UAAU;EACxB"}
1
+ {"version":3,"file":"aiSdk.cjs","names":[],"sources":["../../src/aiSdk.ts"],"sourcesContent":["import { type anthropic, createAnthropic } from '@ai-sdk/anthropic';\nimport { createDeepSeek, type deepseek } from '@ai-sdk/deepseek';\nimport { createGoogleGenerativeAI, type google } from '@ai-sdk/google';\nimport { createMistral, type mistral } from '@ai-sdk/mistral';\nimport { createOpenAI, type openai } from '@ai-sdk/openai';\nimport type {\n AssistantModelMessage,\n generateText,\n SystemModelMessage,\n ToolModelMessage,\n UserModelMessage,\n} from 'ai';\n\ntype AnthropicModel = Parameters<typeof anthropic>[0];\ntype DeepSeekModel = Parameters<typeof deepseek>[0];\ntype MistralModel = Parameters<typeof mistral>[0];\ntype OpenAIModel = Parameters<typeof openai>[0];\ntype GoogleModel = Parameters<typeof google>[0];\n\nexport type Messages = (\n | SystemModelMessage\n | UserModelMessage\n | AssistantModelMessage\n | ToolModelMessage\n)[];\n\n/**\n * Supported AI models\n */\nexport type Model =\n | AnthropicModel\n | DeepSeekModel\n | MistralModel\n | OpenAIModel\n | GoogleModel\n | (string & {});\n\n/**\n * Supported AI SDK providers\n */\nexport enum AIProvider {\n OPENAI = 'openai',\n ANTHROPIC = 'anthropic',\n MISTRAL = 'mistral',\n DEEPSEEK = 'deepseek',\n GEMINI = 'gemini',\n OLLAMA = 'ollama',\n}\n\nexport type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high' | 'none';\n\n/**\n * Common options for all AI providers\n */\nexport type AIOptions = {\n provider?: AIProvider;\n model?: Model;\n temperature?: number;\n baseURL?: string;\n apiKey?: string;\n applicationContext?: string;\n dataSerialization?: 'json' | 'toon';\n};\n\n// Define the structure of messages used in chat completions\nexport type ChatCompletionRequestMessage = {\n role: 'system' | 'user' | 'assistant'; // The role of the message sender\n content: string; // The text content of the message\n timestamp?: Date; // The timestamp of the message\n};\n\ntype AccessType = 'apiKey' | 'registered_user' | 'premium_user' | 'public';\n\nconst getAPIKey = (\n accessType: AccessType[],\n aiOptions?: AIOptions,\n isAuthenticated: boolean = false\n) => {\n const defaultApiKey = process.env.OPENAI_API_KEY;\n\n if (accessType.includes('public')) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n if (accessType.includes('apiKey') && aiOptions?.apiKey) {\n return aiOptions?.apiKey;\n }\n\n if (accessType.includes('registered_user') && isAuthenticated) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n // TODO: Implement premium user access\n if (accessType.includes('premium_user') && isAuthenticated) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n return undefined;\n};\n\nconst getModelName = (\n provider: AIProvider,\n userApiKey: string | undefined,\n userModel?: Model,\n defaultModel: Model = 'gpt-5-mini'\n): Model => {\n // If the user uses their own API key, allow custom model selection\n if (userApiKey || provider === AIProvider.OLLAMA) {\n if (provider === AIProvider.OPENAI) {\n return userModel ?? defaultModel;\n }\n\n if (userModel) {\n return userModel;\n }\n\n switch (provider) {\n case AIProvider.ANTHROPIC:\n return 'claude-sonnet-4-5-20250929';\n case AIProvider.MISTRAL:\n return 'mistral-large-latest';\n case AIProvider.DEEPSEEK:\n return 'deepseek-coder';\n case AIProvider.GEMINI:\n return 'gemini-2.5-flash';\n case AIProvider.OLLAMA:\n return '';\n default:\n return defaultModel;\n }\n }\n\n // Guard: Prevent custom model usage without a user API key\n if (userModel || provider) {\n throw new Error(\n 'The user should use his own API key to use a custom model'\n );\n }\n\n return defaultModel;\n};\n\nconst getLanguageModel = (\n aiOptions: AIOptions,\n apiKey: string | undefined,\n defaultModel?: Model\n) => {\n const selectedModel = getModelName(\n aiOptions.provider as AIProvider,\n apiKey,\n aiOptions.model,\n defaultModel\n );\n\n const baseURL = aiOptions.baseURL;\n\n switch (aiOptions.provider) {\n case AIProvider.OPENAI: {\n return createOpenAI({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.ANTHROPIC: {\n return createAnthropic({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.MISTRAL: {\n return createMistral({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.DEEPSEEK: {\n return createDeepSeek({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.GEMINI: {\n return createGoogleGenerativeAI({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.OLLAMA: {\n // Ollama compatible mode:\n const ollama = createOpenAI({\n baseURL: baseURL ?? 'http://localhost:11434/v1',\n apiKey: apiKey ?? 'ollama', // Required but unused by Ollama\n });\n\n return ollama.chat(selectedModel);\n }\n\n default: {\n throw new Error(`Provider ${aiOptions.provider} not supported`);\n }\n }\n};\n\nexport type AIConfig = Omit<Parameters<typeof generateText>[0], 'prompt'> & {\n reasoningEffort?: ReasoningEffort;\n textVerbosity?: 'low' | 'medium' | 'high';\n dataSerialization?: 'json' | 'toon';\n};\n\nconst DEFAULT_PROVIDER: AIProvider = AIProvider.OPENAI as AIProvider;\n\nexport type AIConfigOptions = {\n userOptions?: AIOptions;\n projectOptions?: AIOptions;\n defaultOptions?: AIOptions;\n accessType?: AccessType[];\n};\n\n/**\n * Get AI model configuration based on the selected provider and options\n * This function handles the configuration for different AI providers\n *\n * @param options Configuration options including provider, API keys, models and temperature\n * @returns Configured AI model ready to use with generateText\n */\nexport const getAIConfig = async (\n options: AIConfigOptions,\n isAuthenticated: boolean = false\n): Promise<AIConfig> => {\n const {\n userOptions,\n projectOptions,\n defaultOptions,\n accessType = ['registered_user'],\n } = options;\n\n const aiOptions = {\n provider: DEFAULT_PROVIDER,\n ...defaultOptions,\n ...projectOptions,\n ...userOptions,\n } satisfies AIOptions;\n\n const apiKey = getAPIKey(accessType, aiOptions, isAuthenticated);\n\n // Check if API key is provided\n if (!apiKey && aiOptions.provider !== AIProvider.OLLAMA) {\n throw new Error(`API key for ${aiOptions.provider} is missing`);\n }\n\n const languageModel = getLanguageModel(\n aiOptions,\n apiKey,\n defaultOptions?.model\n );\n\n return {\n model: languageModel,\n temperature: aiOptions.temperature,\n dataSerialization: aiOptions.dataSerialization,\n };\n};\n"],"mappings":";;;;;;;;;;;AAwCA,IAAY,kDAAL;AACL;AACA;AACA;AACA;AACA;AACA;;;AA2BF,MAAM,aACJ,YACA,WACA,kBAA2B,UACxB;CACH,MAAM,gBAAgB,QAAQ,IAAI;AAElC,KAAI,WAAW,SAAS,SAAS,CAC/B,QAAO,WAAW,UAAU;AAG9B,KAAI,WAAW,SAAS,SAAS,IAAI,WAAW,OAC9C,QAAO,WAAW;AAGpB,KAAI,WAAW,SAAS,kBAAkB,IAAI,gBAC5C,QAAO,WAAW,UAAU;AAI9B,KAAI,WAAW,SAAS,eAAe,IAAI,gBACzC,QAAO,WAAW,UAAU;;AAMhC,MAAM,gBACJ,UACA,YACA,WACA,eAAsB,iBACZ;AAEV,KAAI,cAAc,aAAa,WAAW,QAAQ;AAChD,MAAI,aAAa,WAAW,OAC1B,QAAO,aAAa;AAGtB,MAAI,UACF,QAAO;AAGT,UAAQ,UAAR;GACE,KAAK,WAAW,UACd,QAAO;GACT,KAAK,WAAW,QACd,QAAO;GACT,KAAK,WAAW,SACd,QAAO;GACT,KAAK,WAAW,OACd,QAAO;GACT,KAAK,WAAW,OACd,QAAO;GACT,QACE,QAAO;;;AAKb,KAAI,aAAa,SACf,OAAM,IAAI,MACR,4DACD;AAGH,QAAO;;AAGT,MAAM,oBACJ,WACA,QACA,iBACG;CACH,MAAM,gBAAgB,aACpB,UAAU,UACV,QACA,UAAU,OACV,aACD;CAED,MAAM,UAAU,UAAU;AAE1B,SAAQ,UAAU,UAAlB;EACE,KAAK,WAAW,OACd,yCAAoB;GAClB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,UACd,+CAAuB;GACrB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,QACd,2CAAqB;GACnB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,SACd,6CAAsB;GACpB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,OACd,qDAAgC;GAC9B;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,OAOd,yCAL4B;GAC1B,SAAS,WAAW;GACpB,QAAQ,UAAU;GACnB,CAAC,CAEY,KAAK,cAAc;EAGnC,QACE,OAAM,IAAI,MAAM,YAAY,UAAU,SAAS,gBAAgB;;;AAWrE,MAAM,mBAA+B,WAAW;;;;;;;;AAgBhD,MAAa,cAAc,OACzB,SACA,kBAA2B,UACL;CACtB,MAAM,EACJ,aACA,gBACA,gBACA,aAAa,CAAC,kBAAkB,KAC9B;CAEJ,MAAM,YAAY;EAChB,UAAU;EACV,GAAG;EACH,GAAG;EACH,GAAG;EACJ;CAED,MAAM,SAAS,UAAU,YAAY,WAAW,gBAAgB;AAGhE,KAAI,CAAC,UAAU,UAAU,aAAa,WAAW,OAC/C,OAAM,IAAI,MAAM,eAAe,UAAU,SAAS,aAAa;AASjE,QAAO;EACL,OAPoB,iBACpB,WACA,QACA,gBAAgB,MACjB;EAIC,aAAa,UAAU;EACvB,mBAAmB,UAAU;EAC9B"}
@@ -1,3 +1,4 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1
2
  const require__utils_asset = require('../_virtual/_utils_asset.cjs');
2
3
  let ai = require("ai");
3
4
  let zod = require("zod");
@@ -14,13 +15,15 @@ const auditDictionaryMetadata = async ({ fileContent, tags, aiConfig, applicatio
14
15
  const EXAMPLE_REQUEST = require__utils_asset.readAsset("./EXAMPLE_REQUEST.md");
15
16
  const EXAMPLE_RESPONSE = require__utils_asset.readAsset("./EXAMPLE_RESPONSE.md");
16
17
  const prompt = CHAT_GPT_PROMPT.replace("{{applicationContext}}", applicationContext ?? "").replace("{{tags}}", tags ? JSON.stringify(tags.map(({ key, description }) => `- ${key}: ${description}`).join("\n\n"), null, 2) : "");
17
- const { object, usage } = await (0, ai.generateObject)({
18
- ...aiConfig,
19
- schema: zod.z.object({
18
+ const { dataSerialization, ...restAiConfig } = aiConfig;
19
+ const { output: _unusedOutput, ...validAiConfig } = restAiConfig;
20
+ const { output, usage } = await (0, ai.generateText)({
21
+ ...validAiConfig,
22
+ output: ai.Output.object({ schema: zod.z.object({
20
23
  title: zod.z.string(),
21
24
  description: zod.z.string(),
22
25
  tags: zod.z.array(zod.z.string())
23
- }),
26
+ }) }),
24
27
  messages: [
25
28
  {
26
29
  role: "system",
@@ -41,7 +44,7 @@ const auditDictionaryMetadata = async ({ fileContent, tags, aiConfig, applicatio
41
44
  ]
42
45
  });
43
46
  return {
44
- fileContent: object,
47
+ fileContent: output,
45
48
  tokenUsed: usage?.totalTokens ?? 0
46
49
  };
47
50
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["readAsset","z"],"sources":["../../../src/auditDictionaryMetadata/index.ts"],"sourcesContent":["import { readAsset } from 'utils:asset';\nimport { generateObject } from 'ai';\nimport { z } from 'zod';\nimport type { AIConfig, AIOptions } from '../aiSdk';\n\ntype Tag = {\n key: string;\n description?: string;\n};\n\nexport type AuditDictionaryMetadataOptions = {\n fileContent: string;\n tags?: Tag[];\n aiConfig: AIConfig;\n applicationContext?: string;\n};\n\nexport type AuditFileResultData = {\n fileContent: {\n title: string;\n description: string;\n tags: string[];\n };\n tokenUsed: number;\n};\n\nexport const aiDefaultOptions: AIOptions = {\n // Keep default options\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionaryMetadata = async ({\n fileContent,\n tags,\n aiConfig,\n applicationContext,\n}: AuditDictionaryMetadataOptions): Promise<\n AuditFileResultData | undefined\n> => {\n const CHAT_GPT_PROMPT = readAsset('./PROMPT.md');\n const EXAMPLE_REQUEST = readAsset('./EXAMPLE_REQUEST.md');\n const EXAMPLE_RESPONSE = readAsset('./EXAMPLE_RESPONSE.md');\n\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{applicationContext}}',\n applicationContext ?? ''\n ).replace(\n '{{tags}}',\n tags\n ? JSON.stringify(\n tags\n .map(({ key, description }) => `- ${key}: ${description}`)\n .join('\\n\\n'),\n null,\n 2\n )\n : ''\n );\n\n // Use the AI SDK to generate the completion\n const { object, usage } = await generateObject({\n ...aiConfig,\n schema: z.object({\n title: z.string(),\n description: z.string(),\n tags: z.array(z.string()),\n }),\n messages: [\n { role: 'system', content: prompt },\n { role: 'user', content: EXAMPLE_REQUEST },\n { role: 'assistant', content: EXAMPLE_RESPONSE },\n {\n role: 'user',\n content: fileContent,\n },\n ],\n });\n\n return {\n fileContent: object,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;AA0BA,MAAa,mBAA8B,EAE1C;;;;;;AAOD,MAAa,0BAA0B,OAAO,EAC5C,aACA,MACA,UACA,yBAGG;CACH,MAAM,kBAAkBA,+BAAU,cAAc;CAChD,MAAM,kBAAkBA,+BAAU,uBAAuB;CACzD,MAAM,mBAAmBA,+BAAU,wBAAwB;CAG3D,MAAM,SAAS,gBAAgB,QAC7B,0BACA,sBAAsB,GACvB,CAAC,QACA,YACA,OACI,KAAK,UACH,KACG,KAAK,EAAE,KAAK,kBAAkB,KAAK,IAAI,IAAI,cAAc,CACzD,KAAK,OAAO,EACf,MACA,EACD,GACD,GACL;CAGD,MAAM,EAAE,QAAQ,UAAU,6BAAqB;EAC7C,GAAG;EACH,QAAQC,MAAE,OAAO;GACf,OAAOA,MAAE,QAAQ;GACjB,aAAaA,MAAE,QAAQ;GACvB,MAAMA,MAAE,MAAMA,MAAE,QAAQ,CAAC;GAC1B,CAAC;EACF,UAAU;GACR;IAAE,MAAM;IAAU,SAAS;IAAQ;GACnC;IAAE,MAAM;IAAQ,SAAS;IAAiB;GAC1C;IAAE,MAAM;IAAa,SAAS;IAAkB;GAChD;IACE,MAAM;IACN,SAAS;IACV;GACF;EACF,CAAC;AAEF,QAAO;EACL,aAAa;EACb,WAAW,OAAO,eAAe;EAClC"}
1
+ {"version":3,"file":"index.cjs","names":["readAsset","Output","z"],"sources":["../../../src/auditDictionaryMetadata/index.ts"],"sourcesContent":["import { readAsset } from 'utils:asset';\nimport { generateText, Output } from 'ai';\nimport { z } from 'zod';\nimport type { AIConfig, AIOptions } from '../aiSdk';\n\ntype Tag = {\n key: string;\n description?: string;\n};\n\nexport type AuditDictionaryMetadataOptions = {\n fileContent: string;\n tags?: Tag[];\n aiConfig: AIConfig;\n applicationContext?: string;\n};\n\nexport type AuditFileResultData = {\n fileContent: {\n title: string;\n description: string;\n tags: string[];\n };\n tokenUsed: number;\n};\n\nexport const aiDefaultOptions: AIOptions = {\n // Keep default options\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionaryMetadata = async ({\n fileContent,\n tags,\n aiConfig,\n applicationContext,\n}: AuditDictionaryMetadataOptions): Promise<\n AuditFileResultData | undefined\n> => {\n const CHAT_GPT_PROMPT = readAsset('./PROMPT.md');\n const EXAMPLE_REQUEST = readAsset('./EXAMPLE_REQUEST.md');\n const EXAMPLE_RESPONSE = readAsset('./EXAMPLE_RESPONSE.md');\n\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{applicationContext}}',\n applicationContext ?? ''\n ).replace(\n '{{tags}}',\n tags\n ? JSON.stringify(\n tags\n .map(({ key, description }) => `- ${key}: ${description}`)\n .join('\\n\\n'),\n null,\n 2\n )\n : ''\n );\n\n const { dataSerialization, ...restAiConfig } = aiConfig;\n const { output: _unusedOutput, ...validAiConfig } = restAiConfig;\n\n // Use the AI SDK to generate the completion\n const { output, usage } = await generateText({\n ...validAiConfig,\n output: Output.object({\n schema: z.object({\n title: z.string(),\n description: z.string(),\n tags: z.array(z.string()),\n }),\n }),\n messages: [\n { role: 'system', content: prompt },\n { role: 'user', content: EXAMPLE_REQUEST },\n { role: 'assistant', content: EXAMPLE_RESPONSE },\n {\n role: 'user',\n content: fileContent,\n },\n ],\n });\n\n return {\n fileContent: output,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;AA0BA,MAAa,mBAA8B,EAE1C;;;;;;AAOD,MAAa,0BAA0B,OAAO,EAC5C,aACA,MACA,UACA,yBAGG;CACH,MAAM,kBAAkBA,+BAAU,cAAc;CAChD,MAAM,kBAAkBA,+BAAU,uBAAuB;CACzD,MAAM,mBAAmBA,+BAAU,wBAAwB;CAG3D,MAAM,SAAS,gBAAgB,QAC7B,0BACA,sBAAsB,GACvB,CAAC,QACA,YACA,OACI,KAAK,UACH,KACG,KAAK,EAAE,KAAK,kBAAkB,KAAK,IAAI,IAAI,cAAc,CACzD,KAAK,OAAO,EACf,MACA,EACD,GACD,GACL;CAED,MAAM,EAAE,mBAAmB,GAAG,iBAAiB;CAC/C,MAAM,EAAE,QAAQ,eAAe,GAAG,kBAAkB;CAGpD,MAAM,EAAE,QAAQ,UAAU,2BAAmB;EAC3C,GAAG;EACH,QAAQC,UAAO,OAAO,EACpB,QAAQC,MAAE,OAAO;GACf,OAAOA,MAAE,QAAQ;GACjB,aAAaA,MAAE,QAAQ;GACvB,MAAMA,MAAE,MAAMA,MAAE,QAAQ,CAAC;GAC1B,CAAC,EACH,CAAC;EACF,UAAU;GACR;IAAE,MAAM;IAAU,SAAS;IAAQ;GACnC;IAAE,MAAM;IAAQ,SAAS;IAAiB;GAC1C;IAAE,MAAM;IAAa,SAAS;IAAkB;GAChD;IACE,MAAM;IACN,SAAS;IACV;GACF;EACF,CAAC;AAEF,QAAO;EACL,aAAa;EACb,WAAW,OAAO,eAAe;EAClC"}
@@ -1,3 +1,4 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1
2
  let ai = require("ai");
2
3
 
3
4
  //#region src/customQuery.ts
@@ -1 +1 @@
1
- {"version":3,"file":"customQuery.cjs","names":[],"sources":["../../src/customQuery.ts"],"sourcesContent":["import { generateText } from 'ai';\nimport type { AIConfig, AIOptions, Messages } from './aiSdk';\n\nexport type CustomQueryOptions = {\n messages: Messages;\n aiConfig: AIConfig;\n};\n\nexport type CustomQueryResultData = {\n fileContent: string;\n tokenUsed: number;\n};\n\nexport const aiDefaultOptions: AIOptions = {\n model: 'gpt-4o-mini',\n // Keep default options\n};\n\n/**\n * CustomQuery a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const customQuery = async ({\n messages,\n aiConfig,\n}: CustomQueryOptions): Promise<CustomQueryResultData | undefined> => {\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n ...aiConfig,\n messages,\n });\n\n return {\n fileContent: newContent,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;AAaA,MAAa,mBAA8B,EACzC,OAAO,eAER;;;;;;AAOD,MAAa,cAAc,OAAO,EAChC,UACA,eACoE;CAEpE,MAAM,EAAE,MAAM,YAAY,UAAU,2BAAmB;EACrD,GAAG;EACH;EACD,CAAC;AAEF,QAAO;EACL,aAAa;EACb,WAAW,OAAO,eAAe;EAClC"}
1
+ {"version":3,"file":"customQuery.cjs","names":[],"sources":["../../src/customQuery.ts"],"sourcesContent":["import { generateText } from 'ai';\nimport type { AIConfig, AIOptions, Messages } from './aiSdk';\n\nexport type CustomQueryOptions = {\n messages: Messages;\n aiConfig: AIConfig;\n};\n\nexport type CustomQueryResultData = {\n fileContent: string;\n tokenUsed: number;\n};\n\nexport const aiDefaultOptions: AIOptions = {\n model: 'gpt-4o-mini',\n // Keep default options\n};\n\n/**\n * CustomQuery a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const customQuery = async ({\n messages,\n aiConfig,\n}: CustomQueryOptions): Promise<CustomQueryResultData | undefined> => {\n // Use the AI SDK to generate the completion\n const { text: newContent, usage } = await generateText({\n ...aiConfig,\n messages,\n });\n\n return {\n fileContent: newContent,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;AAaA,MAAa,mBAA8B,EACzC,OAAO,eAER;;;;;;AAOD,MAAa,cAAc,OAAO,EAChC,UACA,eACoE;CAEpE,MAAM,EAAE,MAAM,YAAY,UAAU,2BAAmB;EACrD,GAAG;EACH;EACD,CAAC;AAEF,QAAO;EACL,aAAa;EACb,WAAW,OAAO,eAAe;EAClC"}
@@ -1,3 +1,4 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1
2
  const require_aiSdk = require('./aiSdk.cjs');
2
3
  const require_customQuery = require('./customQuery.cjs');
3
4
  const require_auditDictionaryMetadata_index = require('./auditDictionaryMetadata/index.cjs');
@@ -1,9 +1,11 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1
2
  const require_aiSdk = require('../aiSdk.cjs');
2
3
  const require__utils_asset = require('../_virtual/_utils_asset.cjs');
3
4
  let ai = require("ai");
4
5
  let zod = require("zod");
5
6
  let _intlayer_core = require("@intlayer/core");
6
7
  let _intlayer_types = require("@intlayer/types");
8
+ let _toon_format_toon = require("@toon-format/toon");
7
9
 
8
10
  //#region src/translateJSON/index.ts
9
11
  const aiDefaultOptions = {
@@ -55,13 +57,42 @@ const jsonToZod = (content) => {
55
57
  * and requests for identifying issues or inconsistencies.
56
58
  */
57
59
  const translateJSON = async ({ entryFileContent, presetOutputContent, dictionaryDescription, aiConfig, entryLocale, outputLocale, tags, mode, applicationContext }) => {
58
- const promptFile = require__utils_asset.readAsset("./PROMPT.md");
60
+ const { dataSerialization, ...restAiConfig } = aiConfig;
61
+ const { output: _unusedOutput, ...validAiConfig } = restAiConfig;
59
62
  const formattedEntryLocale = formatLocaleWithName(entryLocale);
60
63
  const formattedOutputLocale = formatLocaleWithName(outputLocale);
61
- const prompt = promptFile.replace("{{entryLocale}}", formattedEntryLocale).replace("{{outputLocale}}", formattedOutputLocale).replace("{{presetOutputContent}}", JSON.stringify(presetOutputContent)).replace("{{dictionaryDescription}}", dictionaryDescription ?? "").replace("{{applicationContext}}", applicationContext ?? "").replace("{{tagsInstructions}}", formatTagInstructions(tags ?? [])).replace("{{modeInstructions}}", getModeInstructions(mode));
62
- const { object, usage } = await (0, ai.generateObject)({
63
- ...aiConfig,
64
- schema: jsonToZod(entryFileContent),
64
+ const isToon = dataSerialization === "toon";
65
+ const promptFile = require__utils_asset.readAsset(isToon ? "./PROMPT_TOON.md" : "./PROMPT_JSON.md");
66
+ const entryContentStr = isToon ? (0, _toon_format_toon.encode)(entryFileContent) : JSON.stringify(entryFileContent);
67
+ const presetContentStr = isToon ? (0, _toon_format_toon.encode)(presetOutputContent) : JSON.stringify(presetOutputContent);
68
+ const prompt = promptFile.replace("{{entryLocale}}", formattedEntryLocale).replace("{{outputLocale}}", formattedOutputLocale).replace("{{presetOutputContent}}", presetContentStr).replace("{{dictionaryDescription}}", dictionaryDescription ?? "").replace("{{applicationContext}}", applicationContext ?? "").replace("{{tagsInstructions}}", formatTagInstructions(tags ?? [])).replace("{{modeInstructions}}", getModeInstructions(mode));
69
+ if (isToon) {
70
+ const { text, usage } = await (0, ai.generateText)({
71
+ ...aiConfig,
72
+ messages: [{
73
+ role: "system",
74
+ content: prompt
75
+ }, {
76
+ role: "user",
77
+ content: [
78
+ `# Translation Request`,
79
+ `Please translate the following TOON content.`,
80
+ `- **From:** ${formattedEntryLocale}`,
81
+ `- **To:** ${formattedOutputLocale}`,
82
+ ``,
83
+ `## Entry Content:`,
84
+ entryContentStr
85
+ ].join("\n")
86
+ }]
87
+ });
88
+ return {
89
+ fileContent: (0, _toon_format_toon.decode)(text.replace(/^```(?:toon)?\n([\s\S]*?)\n```$/gm, "$1").trim()),
90
+ tokenUsed: usage?.totalTokens ?? 0
91
+ };
92
+ }
93
+ const { output, usage } = await (0, ai.generateText)({
94
+ ...validAiConfig,
95
+ output: ai.Output.object({ schema: jsonToZod(entryFileContent) }),
65
96
  messages: [{
66
97
  role: "system",
67
98
  content: prompt
@@ -74,12 +105,12 @@ const translateJSON = async ({ entryFileContent, presetOutputContent, dictionary
74
105
  `- **To:** ${formattedOutputLocale}`,
75
106
  ``,
76
107
  `## Entry Content:`,
77
- JSON.stringify(entryFileContent)
108
+ entryContentStr
78
109
  ].join("\n")
79
110
  }]
80
111
  });
81
112
  return {
82
- fileContent: object,
113
+ fileContent: output,
83
114
  tokenUsed: usage?.totalTokens ?? 0
84
115
  };
85
116
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["AIProvider","Locales","z","readAsset"],"sources":["../../../src/translateJSON/index.ts"],"sourcesContent":["import { readAsset } from 'utils:asset';\nimport { getLocaleName } from '@intlayer/core';\nimport { type Locale, Locales } from '@intlayer/types';\nimport { generateObject } from 'ai';\nimport { z } from 'zod';\nimport { type AIConfig, type AIOptions, AIProvider } from '../aiSdk';\n\ntype Tag = {\n key: string;\n description?: string;\n};\n\nexport type TranslateJSONOptions<T = JSON> = {\n entryFileContent: T;\n presetOutputContent: Partial<T>;\n dictionaryDescription?: string;\n entryLocale: Locale;\n outputLocale: Locale;\n tags?: Tag[];\n aiConfig: AIConfig;\n mode: 'complete' | 'review';\n applicationContext?: string;\n};\n\nexport type TranslateJSONResultData<T = JSON> = {\n fileContent: T;\n tokenUsed: number;\n};\n\nexport const aiDefaultOptions: AIOptions = {\n provider: AIProvider.OPENAI,\n model: 'gpt-5-mini',\n};\n\n/**\n * Format a locale with its name.\n *\n * @param locale - The locale to format.\n * @returns A string in the format \"locale: name\", e.g. \"en: English\".\n */\nconst formatLocaleWithName = (locale: Locale): string =>\n `${locale}: ${getLocaleName(locale, Locales.ENGLISH)}`;\n\n/**\n * Formats tag instructions for the AI prompt.\n * Creates a string with all available tags and their descriptions.\n *\n * @param tags - The list of tags to format.\n * @returns A formatted string with tag instructions.\n */\nconst formatTagInstructions = (tags: Tag[]): string => {\n if (!tags || tags.length === 0) {\n return '';\n }\n\n // Prepare the tag instructions.\n return `Based on the dictionary content, identify specific tags from the list below that would be relevant:\n \n${tags.map(({ key, description }) => `- ${key}: ${description}`).join('\\n\\n')}`;\n};\n\nconst getModeInstructions = (mode: 'complete' | 'review'): string => {\n if (mode === 'complete') {\n return 'Mode: \"Complete\" - Enrich the preset content with the missing keys and values in the output locale. Do not update existing keys. Everything should be returned in the output.';\n }\n\n return 'Mode: \"Review\" - Fill missing content and review existing keys from the preset content. If a key from the entry is missing in the output, it must be translated to the target language and added. If you detect misspelled content, or content that should be reformulated, correct it. If a translation is not coherent with the desired language, translate it.';\n};\n\nconst jsonToZod = (content: any): z.ZodTypeAny => {\n // Base case: content is a string (the translation target)\n if (typeof content === 'string') {\n return z.string();\n }\n\n // Base cases: primitives often preserved in i18n files (e.g. strict numbers/booleans)\n if (typeof content === 'number') {\n return z.number();\n }\n if (typeof content === 'boolean') {\n return z.boolean();\n }\n\n // Recursive case: Array\n if (Array.isArray(content)) {\n // If array is empty, we assume array of strings as default for i18n\n if (content.length === 0) {\n return z.array(z.string());\n }\n // We assume all items in the array share the structure of the first item\n return z.array(jsonToZod(content[0]));\n }\n\n // Recursive case: Object\n if (typeof content === 'object' && content !== null) {\n const shape: Record<string, z.ZodTypeAny> = {};\n for (const key in content) {\n shape[key] = jsonToZod(content[key]);\n }\n return z.object(shape);\n }\n\n // Fallback\n return z.any();\n};\n\n/**\n * TranslateJSONs a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const translateJSON = async <T>({\n entryFileContent,\n presetOutputContent,\n dictionaryDescription,\n aiConfig,\n entryLocale,\n outputLocale,\n tags,\n mode,\n applicationContext,\n}: TranslateJSONOptions<T>): Promise<\n TranslateJSONResultData<T> | undefined\n> => {\n const promptFile = readAsset('./PROMPT.md');\n\n const formattedEntryLocale = formatLocaleWithName(entryLocale);\n const formattedOutputLocale = formatLocaleWithName(outputLocale);\n\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = promptFile\n .replace('{{entryLocale}}', formattedEntryLocale)\n .replace('{{outputLocale}}', formattedOutputLocale)\n .replace('{{presetOutputContent}}', JSON.stringify(presetOutputContent))\n .replace('{{dictionaryDescription}}', dictionaryDescription ?? '')\n .replace('{{applicationContext}}', applicationContext ?? '')\n .replace('{{tagsInstructions}}', formatTagInstructions(tags ?? []))\n .replace('{{modeInstructions}}', getModeInstructions(mode));\n\n // Use the AI SDK to generate the completion\n const { object, usage } = await generateObject({\n ...aiConfig,\n schema: jsonToZod(entryFileContent),\n messages: [\n { role: 'system', content: prompt },\n {\n role: 'user',\n // KEY CHANGE: Explicitly repeating instructions in the user message\n content: [\n `# Translation Request`,\n `Please translate the following JSON content.`,\n `- **From:** ${formattedEntryLocale}`,\n `- **To:** ${formattedOutputLocale}`,\n ``,\n `## Entry Content:`,\n JSON.stringify(entryFileContent),\n ].join('\\n'),\n },\n ],\n });\n\n return {\n fileContent: object as T,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;;;AA6BA,MAAa,mBAA8B;CACzC,UAAUA,yBAAW;CACrB,OAAO;CACR;;;;;;;AAQD,MAAM,wBAAwB,WAC5B,GAAG,OAAO,sCAAkB,QAAQC,wBAAQ,QAAQ;;;;;;;;AAStD,MAAM,yBAAyB,SAAwB;AACrD,KAAI,CAAC,QAAQ,KAAK,WAAW,EAC3B,QAAO;AAIT,QAAO;;EAEP,KAAK,KAAK,EAAE,KAAK,kBAAkB,KAAK,IAAI,IAAI,cAAc,CAAC,KAAK,OAAO;;AAG7E,MAAM,uBAAuB,SAAwC;AACnE,KAAI,SAAS,WACX,QAAO;AAGT,QAAO;;AAGT,MAAM,aAAa,YAA+B;AAEhD,KAAI,OAAO,YAAY,SACrB,QAAOC,MAAE,QAAQ;AAInB,KAAI,OAAO,YAAY,SACrB,QAAOA,MAAE,QAAQ;AAEnB,KAAI,OAAO,YAAY,UACrB,QAAOA,MAAE,SAAS;AAIpB,KAAI,MAAM,QAAQ,QAAQ,EAAE;AAE1B,MAAI,QAAQ,WAAW,EACrB,QAAOA,MAAE,MAAMA,MAAE,QAAQ,CAAC;AAG5B,SAAOA,MAAE,MAAM,UAAU,QAAQ,GAAG,CAAC;;AAIvC,KAAI,OAAO,YAAY,YAAY,YAAY,MAAM;EACnD,MAAM,QAAsC,EAAE;AAC9C,OAAK,MAAM,OAAO,QAChB,OAAM,OAAO,UAAU,QAAQ,KAAK;AAEtC,SAAOA,MAAE,OAAO,MAAM;;AAIxB,QAAOA,MAAE,KAAK;;;;;;;AAQhB,MAAa,gBAAgB,OAAU,EACrC,kBACA,qBACA,uBACA,UACA,aACA,cACA,MACA,MACA,yBAGG;CACH,MAAM,aAAaC,+BAAU,cAAc;CAE3C,MAAM,uBAAuB,qBAAqB,YAAY;CAC9D,MAAM,wBAAwB,qBAAqB,aAAa;CAGhE,MAAM,SAAS,WACZ,QAAQ,mBAAmB,qBAAqB,CAChD,QAAQ,oBAAoB,sBAAsB,CAClD,QAAQ,2BAA2B,KAAK,UAAU,oBAAoB,CAAC,CACvE,QAAQ,6BAA6B,yBAAyB,GAAG,CACjE,QAAQ,0BAA0B,sBAAsB,GAAG,CAC3D,QAAQ,wBAAwB,sBAAsB,QAAQ,EAAE,CAAC,CAAC,CAClE,QAAQ,wBAAwB,oBAAoB,KAAK,CAAC;CAG7D,MAAM,EAAE,QAAQ,UAAU,6BAAqB;EAC7C,GAAG;EACH,QAAQ,UAAU,iBAAiB;EACnC,UAAU,CACR;GAAE,MAAM;GAAU,SAAS;GAAQ,EACnC;GACE,MAAM;GAEN,SAAS;IACP;IACA;IACA,eAAe;IACf,aAAa;IACb;IACA;IACA,KAAK,UAAU,iBAAiB;IACjC,CAAC,KAAK,KAAK;GACb,CACF;EACF,CAAC;AAEF,QAAO;EACL,aAAa;EACb,WAAW,OAAO,eAAe;EAClC"}
1
+ {"version":3,"file":"index.cjs","names":["AIProvider","Locales","z","readAsset","Output"],"sources":["../../../src/translateJSON/index.ts"],"sourcesContent":["import { readAsset } from 'utils:asset';\nimport { getLocaleName } from '@intlayer/core';\nimport { type Locale, Locales } from '@intlayer/types';\nimport { decode, encode } from '@toon-format/toon';\nimport { generateText, Output } from 'ai';\nimport { z } from 'zod';\nimport { type AIConfig, type AIOptions, AIProvider } from '../aiSdk';\n\ntype Tag = {\n key: string;\n description?: string;\n};\n\nexport type TranslateJSONOptions<T = JSON> = {\n entryFileContent: T;\n presetOutputContent: Partial<T>;\n dictionaryDescription?: string;\n entryLocale: Locale;\n outputLocale: Locale;\n tags?: Tag[];\n aiConfig: AIConfig;\n mode: 'complete' | 'review';\n applicationContext?: string;\n};\n\nexport type TranslateJSONResultData<T = JSON> = {\n fileContent: T;\n tokenUsed: number;\n};\n\nexport const aiDefaultOptions: AIOptions = {\n provider: AIProvider.OPENAI,\n model: 'gpt-5-mini',\n};\n\n/**\n * Format a locale with its name.\n *\n * @param locale - The locale to format.\n * @returns A string in the format \"locale: name\", e.g. \"en: English\".\n */\nconst formatLocaleWithName = (locale: Locale): string =>\n `${locale}: ${getLocaleName(locale, Locales.ENGLISH)}`;\n\n/**\n * Formats tag instructions for the AI prompt.\n * Creates a string with all available tags and their descriptions.\n *\n * @param tags - The list of tags to format.\n * @returns A formatted string with tag instructions.\n */\nconst formatTagInstructions = (tags: Tag[]): string => {\n if (!tags || tags.length === 0) {\n return '';\n }\n\n // Prepare the tag instructions.\n return `Based on the dictionary content, identify specific tags from the list below that would be relevant:\n \n${tags.map(({ key, description }) => `- ${key}: ${description}`).join('\\n\\n')}`;\n};\n\nconst getModeInstructions = (mode: 'complete' | 'review'): string => {\n if (mode === 'complete') {\n return 'Mode: \"Complete\" - Enrich the preset content with the missing keys and values in the output locale. Do not update existing keys. Everything should be returned in the output.';\n }\n\n return 'Mode: \"Review\" - Fill missing content and review existing keys from the preset content. If a key from the entry is missing in the output, it must be translated to the target language and added. If you detect misspelled content, or content that should be reformulated, correct it. If a translation is not coherent with the desired language, translate it.';\n};\n\nconst jsonToZod = (content: any): z.ZodTypeAny => {\n // Base case: content is a string (the translation target)\n if (typeof content === 'string') {\n return z.string();\n }\n\n // Base cases: primitives often preserved in i18n files (e.g. strict numbers/booleans)\n if (typeof content === 'number') {\n return z.number();\n }\n if (typeof content === 'boolean') {\n return z.boolean();\n }\n\n // Recursive case: Array\n if (Array.isArray(content)) {\n // If array is empty, we assume array of strings as default for i18n\n if (content.length === 0) {\n return z.array(z.string());\n }\n // We assume all items in the array share the structure of the first item\n return z.array(jsonToZod(content[0]));\n }\n\n // Recursive case: Object\n if (typeof content === 'object' && content !== null) {\n const shape: Record<string, z.ZodTypeAny> = {};\n for (const key in content) {\n shape[key] = jsonToZod(content[key]);\n }\n return z.object(shape);\n }\n\n // Fallback\n return z.any();\n};\n\n/**\n * TranslateJSONs a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const translateJSON = async <T>({\n entryFileContent,\n presetOutputContent,\n dictionaryDescription,\n aiConfig,\n entryLocale,\n outputLocale,\n tags,\n mode,\n applicationContext,\n}: TranslateJSONOptions<T>): Promise<\n TranslateJSONResultData<T> | undefined\n> => {\n const { dataSerialization, ...restAiConfig } = aiConfig;\n // @ts-ignore\n const { output: _unusedOutput, ...validAiConfig } = restAiConfig;\n\n const formattedEntryLocale = formatLocaleWithName(entryLocale);\n const formattedOutputLocale = formatLocaleWithName(outputLocale);\n\n const isToon = dataSerialization === 'toon';\n const promptFile = readAsset(\n isToon ? './PROMPT_TOON.md' : './PROMPT_JSON.md'\n );\n const entryContentStr = isToon\n ? encode(entryFileContent)\n : JSON.stringify(entryFileContent);\n const presetContentStr = isToon\n ? encode(presetOutputContent)\n : JSON.stringify(presetOutputContent);\n\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = promptFile\n .replace('{{entryLocale}}', formattedEntryLocale)\n .replace('{{outputLocale}}', formattedOutputLocale)\n .replace('{{presetOutputContent}}', presetContentStr)\n .replace('{{dictionaryDescription}}', dictionaryDescription ?? '')\n .replace('{{applicationContext}}', applicationContext ?? '')\n .replace('{{tagsInstructions}}', formatTagInstructions(tags ?? []))\n .replace('{{modeInstructions}}', getModeInstructions(mode));\n\n if (isToon) {\n const { text, usage } = await generateText({\n ...aiConfig,\n messages: [\n { role: 'system', content: prompt },\n {\n role: 'user',\n content: [\n `# Translation Request`,\n `Please translate the following TOON content.`,\n `- **From:** ${formattedEntryLocale}`,\n `- **To:** ${formattedOutputLocale}`,\n ``,\n `## Entry Content:`,\n entryContentStr,\n ].join('\\n'),\n },\n ],\n });\n\n // Strip markdown code blocks if present\n const cleanedText = text\n .replace(/^```(?:toon)?\\n([\\s\\S]*?)\\n```$/gm, '$1')\n .trim();\n\n return {\n fileContent: decode(cleanedText) as T,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n }\n\n // Use the AI SDK to generate the completion\n const { output, usage } = await generateText({\n ...validAiConfig,\n output: Output.object({\n schema: jsonToZod(entryFileContent),\n }),\n messages: [\n { role: 'system', content: prompt },\n {\n role: 'user',\n // KEY CHANGE: Explicitly repeating instructions in the user message\n content: [\n `# Translation Request`,\n `Please translate the following JSON content.`,\n `- **From:** ${formattedEntryLocale}`,\n `- **To:** ${formattedOutputLocale}`,\n ``,\n `## Entry Content:`,\n entryContentStr,\n ].join('\\n'),\n },\n ],\n });\n\n return {\n fileContent: output as T,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;;;;;AA8BA,MAAa,mBAA8B;CACzC,UAAUA,yBAAW;CACrB,OAAO;CACR;;;;;;;AAQD,MAAM,wBAAwB,WAC5B,GAAG,OAAO,sCAAkB,QAAQC,wBAAQ,QAAQ;;;;;;;;AAStD,MAAM,yBAAyB,SAAwB;AACrD,KAAI,CAAC,QAAQ,KAAK,WAAW,EAC3B,QAAO;AAIT,QAAO;;EAEP,KAAK,KAAK,EAAE,KAAK,kBAAkB,KAAK,IAAI,IAAI,cAAc,CAAC,KAAK,OAAO;;AAG7E,MAAM,uBAAuB,SAAwC;AACnE,KAAI,SAAS,WACX,QAAO;AAGT,QAAO;;AAGT,MAAM,aAAa,YAA+B;AAEhD,KAAI,OAAO,YAAY,SACrB,QAAOC,MAAE,QAAQ;AAInB,KAAI,OAAO,YAAY,SACrB,QAAOA,MAAE,QAAQ;AAEnB,KAAI,OAAO,YAAY,UACrB,QAAOA,MAAE,SAAS;AAIpB,KAAI,MAAM,QAAQ,QAAQ,EAAE;AAE1B,MAAI,QAAQ,WAAW,EACrB,QAAOA,MAAE,MAAMA,MAAE,QAAQ,CAAC;AAG5B,SAAOA,MAAE,MAAM,UAAU,QAAQ,GAAG,CAAC;;AAIvC,KAAI,OAAO,YAAY,YAAY,YAAY,MAAM;EACnD,MAAM,QAAsC,EAAE;AAC9C,OAAK,MAAM,OAAO,QAChB,OAAM,OAAO,UAAU,QAAQ,KAAK;AAEtC,SAAOA,MAAE,OAAO,MAAM;;AAIxB,QAAOA,MAAE,KAAK;;;;;;;AAQhB,MAAa,gBAAgB,OAAU,EACrC,kBACA,qBACA,uBACA,UACA,aACA,cACA,MACA,MACA,yBAGG;CACH,MAAM,EAAE,mBAAmB,GAAG,iBAAiB;CAE/C,MAAM,EAAE,QAAQ,eAAe,GAAG,kBAAkB;CAEpD,MAAM,uBAAuB,qBAAqB,YAAY;CAC9D,MAAM,wBAAwB,qBAAqB,aAAa;CAEhE,MAAM,SAAS,sBAAsB;CACrC,MAAM,aAAaC,+BACjB,SAAS,qBAAqB,mBAC/B;CACD,MAAM,kBAAkB,uCACb,iBAAiB,GACxB,KAAK,UAAU,iBAAiB;CACpC,MAAM,mBAAmB,uCACd,oBAAoB,GAC3B,KAAK,UAAU,oBAAoB;CAGvC,MAAM,SAAS,WACZ,QAAQ,mBAAmB,qBAAqB,CAChD,QAAQ,oBAAoB,sBAAsB,CAClD,QAAQ,2BAA2B,iBAAiB,CACpD,QAAQ,6BAA6B,yBAAyB,GAAG,CACjE,QAAQ,0BAA0B,sBAAsB,GAAG,CAC3D,QAAQ,wBAAwB,sBAAsB,QAAQ,EAAE,CAAC,CAAC,CAClE,QAAQ,wBAAwB,oBAAoB,KAAK,CAAC;AAE7D,KAAI,QAAQ;EACV,MAAM,EAAE,MAAM,UAAU,2BAAmB;GACzC,GAAG;GACH,UAAU,CACR;IAAE,MAAM;IAAU,SAAS;IAAQ,EACnC;IACE,MAAM;IACN,SAAS;KACP;KACA;KACA,eAAe;KACf,aAAa;KACb;KACA;KACA;KACD,CAAC,KAAK,KAAK;IACb,CACF;GACF,CAAC;AAOF,SAAO;GACL,2CALkB,KACjB,QAAQ,qCAAqC,KAAK,CAClD,MAAM,CAGyB;GAChC,WAAW,OAAO,eAAe;GAClC;;CAIH,MAAM,EAAE,QAAQ,UAAU,2BAAmB;EAC3C,GAAG;EACH,QAAQC,UAAO,OAAO,EACpB,QAAQ,UAAU,iBAAiB,EACpC,CAAC;EACF,UAAU,CACR;GAAE,MAAM;GAAU,SAAS;GAAQ,EACnC;GACE,MAAM;GAEN,SAAS;IACP;IACA;IACA,eAAe;IACf,aAAa;IACb;IACA;IACA;IACD,CAAC,KAAK,KAAK;GACb,CACF;EACF,CAAC;AAEF,QAAO;EACL,aAAa;EACb,WAAW,OAAO,eAAe;EAClC"}
@@ -1,3 +1,4 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1
2
 
2
3
  //#region src/utils/extractJSON.ts
3
4
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"extractJSON.cjs","names":[],"sources":["../../../src/utils/extractJSON.ts"],"sourcesContent":["/**\n * Extracts and parses the first valid JSON value (object or array) from a string containing arbitrary text.\n * This is used to safely extract JSON from LLM responses that may contain additional text or markdown.\n *\n * @example\n * // Extracts JSON object from markdown response:\n * ```json\n * {\n * \"title\": \"Test content declarations\",\n * \"description\": \"A comprehensive test dictionary...\",\n * \"tags\": [\"test tag\"]\n * }\n * ```\n *\n * @example\n * // Extracts JSON array:\n * ```json\n * [\"item1\", \"item2\", \"item3\"]\n * ```\n *\n * @example\n * // Extracts JSON from markdown:\n * Here is the response:\n * ```json\n * {\"key\": \"value\"}\n * ```\n * End of response.\n *\n * @throws {Error} If no valid JSON object/array is found or if parsing fails\n * @returns {T} The parsed JSON value cast to type T\n */\nexport const extractJson = <T = any>(input: string): T => {\n const opening = input.match(/[{[]/);\n if (!opening) throw new Error('No JSON start character ({ or [) found.');\n\n const startIdx = opening.index!;\n const openChar = input[startIdx];\n const closeChar = openChar === '{' ? '}' : ']';\n let depth = 0;\n\n for (let i = startIdx; i < input.length; i++) {\n const char = input[i];\n if (char === openChar) depth++;\n else if (char === closeChar) {\n depth--;\n if (depth === 0) {\n const jsonSubstring = input.slice(startIdx, i + 1);\n try {\n return JSON.parse(jsonSubstring) as T;\n } catch (err) {\n throw new Error(`Failed to parse JSON: ${(err as Error).message}`);\n }\n }\n }\n }\n\n throw new Error('Reached end of input without closing JSON bracket.');\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,MAAa,eAAwB,UAAqB;CACxD,MAAM,UAAU,MAAM,MAAM,OAAO;AACnC,KAAI,CAAC,QAAS,OAAM,IAAI,MAAM,0CAA0C;CAExE,MAAM,WAAW,QAAQ;CACzB,MAAM,WAAW,MAAM;CACvB,MAAM,YAAY,aAAa,MAAM,MAAM;CAC3C,IAAI,QAAQ;AAEZ,MAAK,IAAI,IAAI,UAAU,IAAI,MAAM,QAAQ,KAAK;EAC5C,MAAM,OAAO,MAAM;AACnB,MAAI,SAAS,SAAU;WACd,SAAS,WAAW;AAC3B;AACA,OAAI,UAAU,GAAG;IACf,MAAM,gBAAgB,MAAM,MAAM,UAAU,IAAI,EAAE;AAClD,QAAI;AACF,YAAO,KAAK,MAAM,cAAc;aACzB,KAAK;AACZ,WAAM,IAAI,MAAM,yBAA0B,IAAc,UAAU;;;;;AAM1E,OAAM,IAAI,MAAM,qDAAqD"}
1
+ {"version":3,"file":"extractJSON.cjs","names":[],"sources":["../../../src/utils/extractJSON.ts"],"sourcesContent":["/**\n * Extracts and parses the first valid JSON value (object or array) from a string containing arbitrary text.\n * This is used to safely extract JSON from LLM responses that may contain additional text or markdown.\n *\n * @example\n * // Extracts JSON object from markdown response:\n * ```json\n * {\n * \"title\": \"Test content declarations\",\n * \"description\": \"A comprehensive test dictionary...\",\n * \"tags\": [\"test tag\"]\n * }\n * ```\n *\n * @example\n * // Extracts JSON array:\n * ```json\n * [\"item1\", \"item2\", \"item3\"]\n * ```\n *\n * @example\n * // Extracts JSON from markdown:\n * Here is the response:\n * ```json\n * {\"key\": \"value\"}\n * ```\n * End of response.\n *\n * @throws {Error} If no valid JSON object/array is found or if parsing fails\n * @returns {T} The parsed JSON value cast to type T\n */\nexport const extractJson = <T = any>(input: string): T => {\n const opening = input.match(/[{[]/);\n if (!opening) throw new Error('No JSON start character ({ or [) found.');\n\n const startIdx = opening.index!;\n const openChar = input[startIdx];\n const closeChar = openChar === '{' ? '}' : ']';\n let depth = 0;\n\n for (let i = startIdx; i < input.length; i++) {\n const char = input[i];\n if (char === openChar) depth++;\n else if (char === closeChar) {\n depth--;\n if (depth === 0) {\n const jsonSubstring = input.slice(startIdx, i + 1);\n try {\n return JSON.parse(jsonSubstring) as T;\n } catch (err) {\n throw new Error(`Failed to parse JSON: ${(err as Error).message}`);\n }\n }\n }\n }\n\n throw new Error('Reached end of input without closing JSON bracket.');\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,MAAa,eAAwB,UAAqB;CACxD,MAAM,UAAU,MAAM,MAAM,OAAO;AACnC,KAAI,CAAC,QAAS,OAAM,IAAI,MAAM,0CAA0C;CAExE,MAAM,WAAW,QAAQ;CACzB,MAAM,WAAW,MAAM;CACvB,MAAM,YAAY,aAAa,MAAM,MAAM;CAC3C,IAAI,QAAQ;AAEZ,MAAK,IAAI,IAAI,UAAU,IAAI,MAAM,QAAQ,KAAK;EAC5C,MAAM,OAAO,MAAM;AACnB,MAAI,SAAS,SAAU;WACd,SAAS,WAAW;AAC3B;AACA,OAAI,UAAU,GAAG;IACf,MAAM,gBAAgB,MAAM,MAAM,UAAU,IAAI,EAAE;AAClD,QAAI;AACF,YAAO,KAAK,MAAM,cAAc;aACzB,KAAK;AACZ,WAAM,IAAI,MAAM,yBAA0B,IAAc,UAAU;;;;;AAM1E,OAAM,IAAI,MAAM,qDAAqD"}
@@ -91,7 +91,8 @@ const getAIConfig = async (options, isAuthenticated = false) => {
91
91
  if (!apiKey && aiOptions.provider !== AIProvider.OLLAMA) throw new Error(`API key for ${aiOptions.provider} is missing`);
92
92
  return {
93
93
  model: getLanguageModel(aiOptions, apiKey, defaultOptions?.model),
94
- temperature: aiOptions.temperature
94
+ temperature: aiOptions.temperature,
95
+ dataSerialization: aiOptions.dataSerialization
95
96
  };
96
97
  };
97
98
 
@@ -1 +1 @@
1
- {"version":3,"file":"aiSdk.mjs","names":[],"sources":["../../src/aiSdk.ts"],"sourcesContent":["import { type anthropic, createAnthropic } from '@ai-sdk/anthropic';\nimport { createDeepSeek, type deepseek } from '@ai-sdk/deepseek';\nimport { createGoogleGenerativeAI, type google } from '@ai-sdk/google';\nimport { createMistral, type mistral } from '@ai-sdk/mistral';\nimport { createOpenAI, type openai } from '@ai-sdk/openai';\nimport type {\n AssistantModelMessage,\n generateText,\n SystemModelMessage,\n ToolModelMessage,\n UserModelMessage,\n} from 'ai';\n\ntype AnthropicModel = Parameters<typeof anthropic>[0];\ntype DeepSeekModel = Parameters<typeof deepseek>[0];\ntype MistralModel = Parameters<typeof mistral>[0];\ntype OpenAIModel = Parameters<typeof openai>[0];\ntype GoogleModel = Parameters<typeof google>[0];\n\nexport type Messages = (\n | SystemModelMessage\n | UserModelMessage\n | AssistantModelMessage\n | ToolModelMessage\n)[];\n\n/**\n * Supported AI models\n */\nexport type Model =\n | AnthropicModel\n | DeepSeekModel\n | MistralModel\n | OpenAIModel\n | GoogleModel\n | (string & {});\n\n/**\n * Supported AI SDK providers\n */\nexport enum AIProvider {\n OPENAI = 'openai',\n ANTHROPIC = 'anthropic',\n MISTRAL = 'mistral',\n DEEPSEEK = 'deepseek',\n GEMINI = 'gemini',\n OLLAMA = 'ollama',\n}\n\nexport type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high' | 'none';\n\n/**\n * Common options for all AI providers\n */\nexport type AIOptions = {\n provider?: AIProvider;\n model?: Model;\n temperature?: number;\n baseURL?: string;\n apiKey?: string;\n applicationContext?: string;\n};\n\n// Define the structure of messages used in chat completions\nexport type ChatCompletionRequestMessage = {\n role: 'system' | 'user' | 'assistant'; // The role of the message sender\n content: string; // The text content of the message\n timestamp?: Date; // The timestamp of the message\n};\n\ntype AccessType = 'apiKey' | 'registered_user' | 'premium_user' | 'public';\n\nconst getAPIKey = (\n accessType: AccessType[],\n aiOptions?: AIOptions,\n isAuthenticated: boolean = false\n) => {\n const defaultApiKey = process.env.OPENAI_API_KEY;\n\n if (accessType.includes('public')) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n if (accessType.includes('apiKey') && aiOptions?.apiKey) {\n return aiOptions?.apiKey;\n }\n\n if (accessType.includes('registered_user') && isAuthenticated) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n // TODO: Implement premium user access\n if (accessType.includes('premium_user') && isAuthenticated) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n return undefined;\n};\n\nconst getModelName = (\n provider: AIProvider,\n userApiKey: string | undefined,\n userModel?: Model,\n defaultModel: Model = 'gpt-5-mini'\n): Model => {\n // If the user uses their own API key, allow custom model selection\n if (userApiKey || provider === AIProvider.OLLAMA) {\n if (provider === AIProvider.OPENAI) {\n return userModel ?? defaultModel;\n }\n\n if (userModel) {\n return userModel;\n }\n\n switch (provider) {\n case AIProvider.ANTHROPIC:\n return 'claude-sonnet-4-5-20250929';\n case AIProvider.MISTRAL:\n return 'mistral-large-latest';\n case AIProvider.DEEPSEEK:\n return 'deepseek-coder';\n case AIProvider.GEMINI:\n return 'gemini-2.5-flash';\n case AIProvider.OLLAMA:\n return '';\n default:\n return defaultModel;\n }\n }\n\n // Guard: Prevent custom model usage without a user API key\n if (userModel || provider) {\n throw new Error(\n 'The user should use his own API key to use a custom model'\n );\n }\n\n return defaultModel;\n};\n\nconst getLanguageModel = (\n aiOptions: AIOptions,\n apiKey: string | undefined,\n defaultModel?: Model\n) => {\n const selectedModel = getModelName(\n aiOptions.provider as AIProvider,\n apiKey,\n aiOptions.model,\n defaultModel\n );\n\n const baseURL = aiOptions.baseURL;\n\n switch (aiOptions.provider) {\n case AIProvider.OPENAI: {\n return createOpenAI({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.ANTHROPIC: {\n return createAnthropic({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.MISTRAL: {\n return createMistral({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.DEEPSEEK: {\n return createDeepSeek({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.GEMINI: {\n return createGoogleGenerativeAI({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.OLLAMA: {\n // Ollama compatible mode:\n const ollama = createOpenAI({\n baseURL: baseURL ?? 'http://localhost:11434/v1',\n apiKey: apiKey ?? 'ollama', // Required but unused by Ollama\n });\n\n return ollama.chat(selectedModel);\n }\n\n default: {\n throw new Error(`Provider ${aiOptions.provider} not supported`);\n }\n }\n};\n\nexport type AIConfig = Omit<Parameters<typeof generateText>[0], 'prompt'> & {\n reasoningEffort?: ReasoningEffort;\n textVerbosity?: 'low' | 'medium' | 'high';\n};\n\nconst DEFAULT_PROVIDER: AIProvider = AIProvider.OPENAI as AIProvider;\n\nexport type AIConfigOptions = {\n userOptions?: AIOptions;\n projectOptions?: AIOptions;\n defaultOptions?: AIOptions;\n accessType?: AccessType[];\n};\n\n/**\n * Get AI model configuration based on the selected provider and options\n * This function handles the configuration for different AI providers\n *\n * @param options Configuration options including provider, API keys, models and temperature\n * @returns Configured AI model ready to use with generateText\n */\nexport const getAIConfig = async (\n options: AIConfigOptions,\n isAuthenticated: boolean = false\n): Promise<AIConfig> => {\n const {\n userOptions,\n projectOptions,\n defaultOptions,\n accessType = ['registered_user'],\n } = options;\n\n const aiOptions = {\n provider: DEFAULT_PROVIDER,\n ...defaultOptions,\n ...projectOptions,\n ...userOptions,\n } satisfies AIOptions;\n\n const apiKey = getAPIKey(accessType, aiOptions, isAuthenticated);\n\n // Check if API key is provided\n if (!apiKey && aiOptions.provider !== AIProvider.OLLAMA) {\n throw new Error(`API key for ${aiOptions.provider} is missing`);\n }\n\n const languageModel = getLanguageModel(\n aiOptions,\n apiKey,\n defaultOptions?.model\n );\n\n return {\n model: languageModel,\n temperature: aiOptions.temperature,\n };\n};\n"],"mappings":";;;;;;;;;;AAwCA,IAAY,kDAAL;AACL;AACA;AACA;AACA;AACA;AACA;;;AA0BF,MAAM,aACJ,YACA,WACA,kBAA2B,UACxB;CACH,MAAM,gBAAgB,QAAQ,IAAI;AAElC,KAAI,WAAW,SAAS,SAAS,CAC/B,QAAO,WAAW,UAAU;AAG9B,KAAI,WAAW,SAAS,SAAS,IAAI,WAAW,OAC9C,QAAO,WAAW;AAGpB,KAAI,WAAW,SAAS,kBAAkB,IAAI,gBAC5C,QAAO,WAAW,UAAU;AAI9B,KAAI,WAAW,SAAS,eAAe,IAAI,gBACzC,QAAO,WAAW,UAAU;;AAMhC,MAAM,gBACJ,UACA,YACA,WACA,eAAsB,iBACZ;AAEV,KAAI,cAAc,aAAa,WAAW,QAAQ;AAChD,MAAI,aAAa,WAAW,OAC1B,QAAO,aAAa;AAGtB,MAAI,UACF,QAAO;AAGT,UAAQ,UAAR;GACE,KAAK,WAAW,UACd,QAAO;GACT,KAAK,WAAW,QACd,QAAO;GACT,KAAK,WAAW,SACd,QAAO;GACT,KAAK,WAAW,OACd,QAAO;GACT,KAAK,WAAW,OACd,QAAO;GACT,QACE,QAAO;;;AAKb,KAAI,aAAa,SACf,OAAM,IAAI,MACR,4DACD;AAGH,QAAO;;AAGT,MAAM,oBACJ,WACA,QACA,iBACG;CACH,MAAM,gBAAgB,aACpB,UAAU,UACV,QACA,UAAU,OACV,aACD;CAED,MAAM,UAAU,UAAU;AAE1B,SAAQ,UAAU,UAAlB;EACE,KAAK,WAAW,OACd,QAAO,aAAa;GAClB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,UACd,QAAO,gBAAgB;GACrB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,QACd,QAAO,cAAc;GACnB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,SACd,QAAO,eAAe;GACpB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,OACd,QAAO,yBAAyB;GAC9B;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,OAOd,QALe,aAAa;GAC1B,SAAS,WAAW;GACpB,QAAQ,UAAU;GACnB,CAAC,CAEY,KAAK,cAAc;EAGnC,QACE,OAAM,IAAI,MAAM,YAAY,UAAU,SAAS,gBAAgB;;;AAUrE,MAAM,mBAA+B,WAAW;;;;;;;;AAgBhD,MAAa,cAAc,OACzB,SACA,kBAA2B,UACL;CACtB,MAAM,EACJ,aACA,gBACA,gBACA,aAAa,CAAC,kBAAkB,KAC9B;CAEJ,MAAM,YAAY;EAChB,UAAU;EACV,GAAG;EACH,GAAG;EACH,GAAG;EACJ;CAED,MAAM,SAAS,UAAU,YAAY,WAAW,gBAAgB;AAGhE,KAAI,CAAC,UAAU,UAAU,aAAa,WAAW,OAC/C,OAAM,IAAI,MAAM,eAAe,UAAU,SAAS,aAAa;AASjE,QAAO;EACL,OAPoB,iBACpB,WACA,QACA,gBAAgB,MACjB;EAIC,aAAa,UAAU;EACxB"}
1
+ {"version":3,"file":"aiSdk.mjs","names":[],"sources":["../../src/aiSdk.ts"],"sourcesContent":["import { type anthropic, createAnthropic } from '@ai-sdk/anthropic';\nimport { createDeepSeek, type deepseek } from '@ai-sdk/deepseek';\nimport { createGoogleGenerativeAI, type google } from '@ai-sdk/google';\nimport { createMistral, type mistral } from '@ai-sdk/mistral';\nimport { createOpenAI, type openai } from '@ai-sdk/openai';\nimport type {\n AssistantModelMessage,\n generateText,\n SystemModelMessage,\n ToolModelMessage,\n UserModelMessage,\n} from 'ai';\n\ntype AnthropicModel = Parameters<typeof anthropic>[0];\ntype DeepSeekModel = Parameters<typeof deepseek>[0];\ntype MistralModel = Parameters<typeof mistral>[0];\ntype OpenAIModel = Parameters<typeof openai>[0];\ntype GoogleModel = Parameters<typeof google>[0];\n\nexport type Messages = (\n | SystemModelMessage\n | UserModelMessage\n | AssistantModelMessage\n | ToolModelMessage\n)[];\n\n/**\n * Supported AI models\n */\nexport type Model =\n | AnthropicModel\n | DeepSeekModel\n | MistralModel\n | OpenAIModel\n | GoogleModel\n | (string & {});\n\n/**\n * Supported AI SDK providers\n */\nexport enum AIProvider {\n OPENAI = 'openai',\n ANTHROPIC = 'anthropic',\n MISTRAL = 'mistral',\n DEEPSEEK = 'deepseek',\n GEMINI = 'gemini',\n OLLAMA = 'ollama',\n}\n\nexport type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high' | 'none';\n\n/**\n * Common options for all AI providers\n */\nexport type AIOptions = {\n provider?: AIProvider;\n model?: Model;\n temperature?: number;\n baseURL?: string;\n apiKey?: string;\n applicationContext?: string;\n dataSerialization?: 'json' | 'toon';\n};\n\n// Define the structure of messages used in chat completions\nexport type ChatCompletionRequestMessage = {\n role: 'system' | 'user' | 'assistant'; // The role of the message sender\n content: string; // The text content of the message\n timestamp?: Date; // The timestamp of the message\n};\n\ntype AccessType = 'apiKey' | 'registered_user' | 'premium_user' | 'public';\n\nconst getAPIKey = (\n accessType: AccessType[],\n aiOptions?: AIOptions,\n isAuthenticated: boolean = false\n) => {\n const defaultApiKey = process.env.OPENAI_API_KEY;\n\n if (accessType.includes('public')) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n if (accessType.includes('apiKey') && aiOptions?.apiKey) {\n return aiOptions?.apiKey;\n }\n\n if (accessType.includes('registered_user') && isAuthenticated) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n // TODO: Implement premium user access\n if (accessType.includes('premium_user') && isAuthenticated) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n return undefined;\n};\n\nconst getModelName = (\n provider: AIProvider,\n userApiKey: string | undefined,\n userModel?: Model,\n defaultModel: Model = 'gpt-5-mini'\n): Model => {\n // If the user uses their own API key, allow custom model selection\n if (userApiKey || provider === AIProvider.OLLAMA) {\n if (provider === AIProvider.OPENAI) {\n return userModel ?? defaultModel;\n }\n\n if (userModel) {\n return userModel;\n }\n\n switch (provider) {\n case AIProvider.ANTHROPIC:\n return 'claude-sonnet-4-5-20250929';\n case AIProvider.MISTRAL:\n return 'mistral-large-latest';\n case AIProvider.DEEPSEEK:\n return 'deepseek-coder';\n case AIProvider.GEMINI:\n return 'gemini-2.5-flash';\n case AIProvider.OLLAMA:\n return '';\n default:\n return defaultModel;\n }\n }\n\n // Guard: Prevent custom model usage without a user API key\n if (userModel || provider) {\n throw new Error(\n 'The user should use his own API key to use a custom model'\n );\n }\n\n return defaultModel;\n};\n\nconst getLanguageModel = (\n aiOptions: AIOptions,\n apiKey: string | undefined,\n defaultModel?: Model\n) => {\n const selectedModel = getModelName(\n aiOptions.provider as AIProvider,\n apiKey,\n aiOptions.model,\n defaultModel\n );\n\n const baseURL = aiOptions.baseURL;\n\n switch (aiOptions.provider) {\n case AIProvider.OPENAI: {\n return createOpenAI({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.ANTHROPIC: {\n return createAnthropic({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.MISTRAL: {\n return createMistral({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.DEEPSEEK: {\n return createDeepSeek({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.GEMINI: {\n return createGoogleGenerativeAI({\n apiKey,\n baseURL,\n })(selectedModel);\n }\n\n case AIProvider.OLLAMA: {\n // Ollama compatible mode:\n const ollama = createOpenAI({\n baseURL: baseURL ?? 'http://localhost:11434/v1',\n apiKey: apiKey ?? 'ollama', // Required but unused by Ollama\n });\n\n return ollama.chat(selectedModel);\n }\n\n default: {\n throw new Error(`Provider ${aiOptions.provider} not supported`);\n }\n }\n};\n\nexport type AIConfig = Omit<Parameters<typeof generateText>[0], 'prompt'> & {\n reasoningEffort?: ReasoningEffort;\n textVerbosity?: 'low' | 'medium' | 'high';\n dataSerialization?: 'json' | 'toon';\n};\n\nconst DEFAULT_PROVIDER: AIProvider = AIProvider.OPENAI as AIProvider;\n\nexport type AIConfigOptions = {\n userOptions?: AIOptions;\n projectOptions?: AIOptions;\n defaultOptions?: AIOptions;\n accessType?: AccessType[];\n};\n\n/**\n * Get AI model configuration based on the selected provider and options\n * This function handles the configuration for different AI providers\n *\n * @param options Configuration options including provider, API keys, models and temperature\n * @returns Configured AI model ready to use with generateText\n */\nexport const getAIConfig = async (\n options: AIConfigOptions,\n isAuthenticated: boolean = false\n): Promise<AIConfig> => {\n const {\n userOptions,\n projectOptions,\n defaultOptions,\n accessType = ['registered_user'],\n } = options;\n\n const aiOptions = {\n provider: DEFAULT_PROVIDER,\n ...defaultOptions,\n ...projectOptions,\n ...userOptions,\n } satisfies AIOptions;\n\n const apiKey = getAPIKey(accessType, aiOptions, isAuthenticated);\n\n // Check if API key is provided\n if (!apiKey && aiOptions.provider !== AIProvider.OLLAMA) {\n throw new Error(`API key for ${aiOptions.provider} is missing`);\n }\n\n const languageModel = getLanguageModel(\n aiOptions,\n apiKey,\n defaultOptions?.model\n );\n\n return {\n model: languageModel,\n temperature: aiOptions.temperature,\n dataSerialization: aiOptions.dataSerialization,\n };\n};\n"],"mappings":";;;;;;;;;;AAwCA,IAAY,kDAAL;AACL;AACA;AACA;AACA;AACA;AACA;;;AA2BF,MAAM,aACJ,YACA,WACA,kBAA2B,UACxB;CACH,MAAM,gBAAgB,QAAQ,IAAI;AAElC,KAAI,WAAW,SAAS,SAAS,CAC/B,QAAO,WAAW,UAAU;AAG9B,KAAI,WAAW,SAAS,SAAS,IAAI,WAAW,OAC9C,QAAO,WAAW;AAGpB,KAAI,WAAW,SAAS,kBAAkB,IAAI,gBAC5C,QAAO,WAAW,UAAU;AAI9B,KAAI,WAAW,SAAS,eAAe,IAAI,gBACzC,QAAO,WAAW,UAAU;;AAMhC,MAAM,gBACJ,UACA,YACA,WACA,eAAsB,iBACZ;AAEV,KAAI,cAAc,aAAa,WAAW,QAAQ;AAChD,MAAI,aAAa,WAAW,OAC1B,QAAO,aAAa;AAGtB,MAAI,UACF,QAAO;AAGT,UAAQ,UAAR;GACE,KAAK,WAAW,UACd,QAAO;GACT,KAAK,WAAW,QACd,QAAO;GACT,KAAK,WAAW,SACd,QAAO;GACT,KAAK,WAAW,OACd,QAAO;GACT,KAAK,WAAW,OACd,QAAO;GACT,QACE,QAAO;;;AAKb,KAAI,aAAa,SACf,OAAM,IAAI,MACR,4DACD;AAGH,QAAO;;AAGT,MAAM,oBACJ,WACA,QACA,iBACG;CACH,MAAM,gBAAgB,aACpB,UAAU,UACV,QACA,UAAU,OACV,aACD;CAED,MAAM,UAAU,UAAU;AAE1B,SAAQ,UAAU,UAAlB;EACE,KAAK,WAAW,OACd,QAAO,aAAa;GAClB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,UACd,QAAO,gBAAgB;GACrB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,QACd,QAAO,cAAc;GACnB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,SACd,QAAO,eAAe;GACpB;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,OACd,QAAO,yBAAyB;GAC9B;GACA;GACD,CAAC,CAAC,cAAc;EAGnB,KAAK,WAAW,OAOd,QALe,aAAa;GAC1B,SAAS,WAAW;GACpB,QAAQ,UAAU;GACnB,CAAC,CAEY,KAAK,cAAc;EAGnC,QACE,OAAM,IAAI,MAAM,YAAY,UAAU,SAAS,gBAAgB;;;AAWrE,MAAM,mBAA+B,WAAW;;;;;;;;AAgBhD,MAAa,cAAc,OACzB,SACA,kBAA2B,UACL;CACtB,MAAM,EACJ,aACA,gBACA,gBACA,aAAa,CAAC,kBAAkB,KAC9B;CAEJ,MAAM,YAAY;EAChB,UAAU;EACV,GAAG;EACH,GAAG;EACH,GAAG;EACJ;CAED,MAAM,SAAS,UAAU,YAAY,WAAW,gBAAgB;AAGhE,KAAI,CAAC,UAAU,UAAU,aAAa,WAAW,OAC/C,OAAM,IAAI,MAAM,eAAe,UAAU,SAAS,aAAa;AASjE,QAAO;EACL,OAPoB,iBACpB,WACA,QACA,gBAAgB,MACjB;EAIC,aAAa,UAAU;EACvB,mBAAmB,UAAU;EAC9B"}
@@ -1,5 +1,5 @@
1
1
  import { readAsset } from "../_virtual/_utils_asset.mjs";
2
- import { generateObject } from "ai";
2
+ import { Output, generateText } from "ai";
3
3
  import { z } from "zod";
4
4
 
5
5
  //#region src/auditDictionaryMetadata/index.ts
@@ -14,13 +14,15 @@ const auditDictionaryMetadata = async ({ fileContent, tags, aiConfig, applicatio
14
14
  const EXAMPLE_REQUEST = readAsset("./EXAMPLE_REQUEST.md");
15
15
  const EXAMPLE_RESPONSE = readAsset("./EXAMPLE_RESPONSE.md");
16
16
  const prompt = CHAT_GPT_PROMPT.replace("{{applicationContext}}", applicationContext ?? "").replace("{{tags}}", tags ? JSON.stringify(tags.map(({ key, description }) => `- ${key}: ${description}`).join("\n\n"), null, 2) : "");
17
- const { object, usage } = await generateObject({
18
- ...aiConfig,
19
- schema: z.object({
17
+ const { dataSerialization, ...restAiConfig } = aiConfig;
18
+ const { output: _unusedOutput, ...validAiConfig } = restAiConfig;
19
+ const { output, usage } = await generateText({
20
+ ...validAiConfig,
21
+ output: Output.object({ schema: z.object({
20
22
  title: z.string(),
21
23
  description: z.string(),
22
24
  tags: z.array(z.string())
23
- }),
25
+ }) }),
24
26
  messages: [
25
27
  {
26
28
  role: "system",
@@ -41,7 +43,7 @@ const auditDictionaryMetadata = async ({ fileContent, tags, aiConfig, applicatio
41
43
  ]
42
44
  });
43
45
  return {
44
- fileContent: object,
46
+ fileContent: output,
45
47
  tokenUsed: usage?.totalTokens ?? 0
46
48
  };
47
49
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/auditDictionaryMetadata/index.ts"],"sourcesContent":["import { readAsset } from 'utils:asset';\nimport { generateObject } from 'ai';\nimport { z } from 'zod';\nimport type { AIConfig, AIOptions } from '../aiSdk';\n\ntype Tag = {\n key: string;\n description?: string;\n};\n\nexport type AuditDictionaryMetadataOptions = {\n fileContent: string;\n tags?: Tag[];\n aiConfig: AIConfig;\n applicationContext?: string;\n};\n\nexport type AuditFileResultData = {\n fileContent: {\n title: string;\n description: string;\n tags: string[];\n };\n tokenUsed: number;\n};\n\nexport const aiDefaultOptions: AIOptions = {\n // Keep default options\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionaryMetadata = async ({\n fileContent,\n tags,\n aiConfig,\n applicationContext,\n}: AuditDictionaryMetadataOptions): Promise<\n AuditFileResultData | undefined\n> => {\n const CHAT_GPT_PROMPT = readAsset('./PROMPT.md');\n const EXAMPLE_REQUEST = readAsset('./EXAMPLE_REQUEST.md');\n const EXAMPLE_RESPONSE = readAsset('./EXAMPLE_RESPONSE.md');\n\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{applicationContext}}',\n applicationContext ?? ''\n ).replace(\n '{{tags}}',\n tags\n ? JSON.stringify(\n tags\n .map(({ key, description }) => `- ${key}: ${description}`)\n .join('\\n\\n'),\n null,\n 2\n )\n : ''\n );\n\n // Use the AI SDK to generate the completion\n const { object, usage } = await generateObject({\n ...aiConfig,\n schema: z.object({\n title: z.string(),\n description: z.string(),\n tags: z.array(z.string()),\n }),\n messages: [\n { role: 'system', content: prompt },\n { role: 'user', content: EXAMPLE_REQUEST },\n { role: 'assistant', content: EXAMPLE_RESPONSE },\n {\n role: 'user',\n content: fileContent,\n },\n ],\n });\n\n return {\n fileContent: object,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;AA0BA,MAAa,mBAA8B,EAE1C;;;;;;AAOD,MAAa,0BAA0B,OAAO,EAC5C,aACA,MACA,UACA,yBAGG;CACH,MAAM,kBAAkB,UAAU,cAAc;CAChD,MAAM,kBAAkB,UAAU,uBAAuB;CACzD,MAAM,mBAAmB,UAAU,wBAAwB;CAG3D,MAAM,SAAS,gBAAgB,QAC7B,0BACA,sBAAsB,GACvB,CAAC,QACA,YACA,OACI,KAAK,UACH,KACG,KAAK,EAAE,KAAK,kBAAkB,KAAK,IAAI,IAAI,cAAc,CACzD,KAAK,OAAO,EACf,MACA,EACD,GACD,GACL;CAGD,MAAM,EAAE,QAAQ,UAAU,MAAM,eAAe;EAC7C,GAAG;EACH,QAAQ,EAAE,OAAO;GACf,OAAO,EAAE,QAAQ;GACjB,aAAa,EAAE,QAAQ;GACvB,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;GAC1B,CAAC;EACF,UAAU;GACR;IAAE,MAAM;IAAU,SAAS;IAAQ;GACnC;IAAE,MAAM;IAAQ,SAAS;IAAiB;GAC1C;IAAE,MAAM;IAAa,SAAS;IAAkB;GAChD;IACE,MAAM;IACN,SAAS;IACV;GACF;EACF,CAAC;AAEF,QAAO;EACL,aAAa;EACb,WAAW,OAAO,eAAe;EAClC"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/auditDictionaryMetadata/index.ts"],"sourcesContent":["import { readAsset } from 'utils:asset';\nimport { generateText, Output } from 'ai';\nimport { z } from 'zod';\nimport type { AIConfig, AIOptions } from '../aiSdk';\n\ntype Tag = {\n key: string;\n description?: string;\n};\n\nexport type AuditDictionaryMetadataOptions = {\n fileContent: string;\n tags?: Tag[];\n aiConfig: AIConfig;\n applicationContext?: string;\n};\n\nexport type AuditFileResultData = {\n fileContent: {\n title: string;\n description: string;\n tags: string[];\n };\n tokenUsed: number;\n};\n\nexport const aiDefaultOptions: AIOptions = {\n // Keep default options\n};\n\n/**\n * Audits a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const auditDictionaryMetadata = async ({\n fileContent,\n tags,\n aiConfig,\n applicationContext,\n}: AuditDictionaryMetadataOptions): Promise<\n AuditFileResultData | undefined\n> => {\n const CHAT_GPT_PROMPT = readAsset('./PROMPT.md');\n const EXAMPLE_REQUEST = readAsset('./EXAMPLE_REQUEST.md');\n const EXAMPLE_RESPONSE = readAsset('./EXAMPLE_RESPONSE.md');\n\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = CHAT_GPT_PROMPT.replace(\n '{{applicationContext}}',\n applicationContext ?? ''\n ).replace(\n '{{tags}}',\n tags\n ? JSON.stringify(\n tags\n .map(({ key, description }) => `- ${key}: ${description}`)\n .join('\\n\\n'),\n null,\n 2\n )\n : ''\n );\n\n const { dataSerialization, ...restAiConfig } = aiConfig;\n const { output: _unusedOutput, ...validAiConfig } = restAiConfig;\n\n // Use the AI SDK to generate the completion\n const { output, usage } = await generateText({\n ...validAiConfig,\n output: Output.object({\n schema: z.object({\n title: z.string(),\n description: z.string(),\n tags: z.array(z.string()),\n }),\n }),\n messages: [\n { role: 'system', content: prompt },\n { role: 'user', content: EXAMPLE_REQUEST },\n { role: 'assistant', content: EXAMPLE_RESPONSE },\n {\n role: 'user',\n content: fileContent,\n },\n ],\n });\n\n return {\n fileContent: output,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;AA0BA,MAAa,mBAA8B,EAE1C;;;;;;AAOD,MAAa,0BAA0B,OAAO,EAC5C,aACA,MACA,UACA,yBAGG;CACH,MAAM,kBAAkB,UAAU,cAAc;CAChD,MAAM,kBAAkB,UAAU,uBAAuB;CACzD,MAAM,mBAAmB,UAAU,wBAAwB;CAG3D,MAAM,SAAS,gBAAgB,QAC7B,0BACA,sBAAsB,GACvB,CAAC,QACA,YACA,OACI,KAAK,UACH,KACG,KAAK,EAAE,KAAK,kBAAkB,KAAK,IAAI,IAAI,cAAc,CACzD,KAAK,OAAO,EACf,MACA,EACD,GACD,GACL;CAED,MAAM,EAAE,mBAAmB,GAAG,iBAAiB;CAC/C,MAAM,EAAE,QAAQ,eAAe,GAAG,kBAAkB;CAGpD,MAAM,EAAE,QAAQ,UAAU,MAAM,aAAa;EAC3C,GAAG;EACH,QAAQ,OAAO,OAAO,EACpB,QAAQ,EAAE,OAAO;GACf,OAAO,EAAE,QAAQ;GACjB,aAAa,EAAE,QAAQ;GACvB,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;GAC1B,CAAC,EACH,CAAC;EACF,UAAU;GACR;IAAE,MAAM;IAAU,SAAS;IAAQ;GACnC;IAAE,MAAM;IAAQ,SAAS;IAAiB;GAC1C;IAAE,MAAM;IAAa,SAAS;IAAkB;GAChD;IACE,MAAM;IACN,SAAS;IACV;GACF;EACF,CAAC;AAEF,QAAO;EACL,aAAa;EACb,WAAW,OAAO,eAAe;EAClC"}
@@ -1,9 +1,10 @@
1
1
  import { AIProvider } from "../aiSdk.mjs";
2
2
  import { readAsset } from "../_virtual/_utils_asset.mjs";
3
- import { generateObject } from "ai";
3
+ import { Output, generateText } from "ai";
4
4
  import { z } from "zod";
5
5
  import { getLocaleName } from "@intlayer/core";
6
6
  import { Locales } from "@intlayer/types";
7
+ import { decode, encode } from "@toon-format/toon";
7
8
 
8
9
  //#region src/translateJSON/index.ts
9
10
  const aiDefaultOptions = {
@@ -55,13 +56,42 @@ const jsonToZod = (content) => {
55
56
  * and requests for identifying issues or inconsistencies.
56
57
  */
57
58
  const translateJSON = async ({ entryFileContent, presetOutputContent, dictionaryDescription, aiConfig, entryLocale, outputLocale, tags, mode, applicationContext }) => {
58
- const promptFile = readAsset("./PROMPT.md");
59
+ const { dataSerialization, ...restAiConfig } = aiConfig;
60
+ const { output: _unusedOutput, ...validAiConfig } = restAiConfig;
59
61
  const formattedEntryLocale = formatLocaleWithName(entryLocale);
60
62
  const formattedOutputLocale = formatLocaleWithName(outputLocale);
61
- const prompt = promptFile.replace("{{entryLocale}}", formattedEntryLocale).replace("{{outputLocale}}", formattedOutputLocale).replace("{{presetOutputContent}}", JSON.stringify(presetOutputContent)).replace("{{dictionaryDescription}}", dictionaryDescription ?? "").replace("{{applicationContext}}", applicationContext ?? "").replace("{{tagsInstructions}}", formatTagInstructions(tags ?? [])).replace("{{modeInstructions}}", getModeInstructions(mode));
62
- const { object, usage } = await generateObject({
63
- ...aiConfig,
64
- schema: jsonToZod(entryFileContent),
63
+ const isToon = dataSerialization === "toon";
64
+ const promptFile = readAsset(isToon ? "./PROMPT_TOON.md" : "./PROMPT_JSON.md");
65
+ const entryContentStr = isToon ? encode(entryFileContent) : JSON.stringify(entryFileContent);
66
+ const presetContentStr = isToon ? encode(presetOutputContent) : JSON.stringify(presetOutputContent);
67
+ const prompt = promptFile.replace("{{entryLocale}}", formattedEntryLocale).replace("{{outputLocale}}", formattedOutputLocale).replace("{{presetOutputContent}}", presetContentStr).replace("{{dictionaryDescription}}", dictionaryDescription ?? "").replace("{{applicationContext}}", applicationContext ?? "").replace("{{tagsInstructions}}", formatTagInstructions(tags ?? [])).replace("{{modeInstructions}}", getModeInstructions(mode));
68
+ if (isToon) {
69
+ const { text, usage } = await generateText({
70
+ ...aiConfig,
71
+ messages: [{
72
+ role: "system",
73
+ content: prompt
74
+ }, {
75
+ role: "user",
76
+ content: [
77
+ `# Translation Request`,
78
+ `Please translate the following TOON content.`,
79
+ `- **From:** ${formattedEntryLocale}`,
80
+ `- **To:** ${formattedOutputLocale}`,
81
+ ``,
82
+ `## Entry Content:`,
83
+ entryContentStr
84
+ ].join("\n")
85
+ }]
86
+ });
87
+ return {
88
+ fileContent: decode(text.replace(/^```(?:toon)?\n([\s\S]*?)\n```$/gm, "$1").trim()),
89
+ tokenUsed: usage?.totalTokens ?? 0
90
+ };
91
+ }
92
+ const { output, usage } = await generateText({
93
+ ...validAiConfig,
94
+ output: Output.object({ schema: jsonToZod(entryFileContent) }),
65
95
  messages: [{
66
96
  role: "system",
67
97
  content: prompt
@@ -74,12 +104,12 @@ const translateJSON = async ({ entryFileContent, presetOutputContent, dictionary
74
104
  `- **To:** ${formattedOutputLocale}`,
75
105
  ``,
76
106
  `## Entry Content:`,
77
- JSON.stringify(entryFileContent)
107
+ entryContentStr
78
108
  ].join("\n")
79
109
  }]
80
110
  });
81
111
  return {
82
- fileContent: object,
112
+ fileContent: output,
83
113
  tokenUsed: usage?.totalTokens ?? 0
84
114
  };
85
115
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/translateJSON/index.ts"],"sourcesContent":["import { readAsset } from 'utils:asset';\nimport { getLocaleName } from '@intlayer/core';\nimport { type Locale, Locales } from '@intlayer/types';\nimport { generateObject } from 'ai';\nimport { z } from 'zod';\nimport { type AIConfig, type AIOptions, AIProvider } from '../aiSdk';\n\ntype Tag = {\n key: string;\n description?: string;\n};\n\nexport type TranslateJSONOptions<T = JSON> = {\n entryFileContent: T;\n presetOutputContent: Partial<T>;\n dictionaryDescription?: string;\n entryLocale: Locale;\n outputLocale: Locale;\n tags?: Tag[];\n aiConfig: AIConfig;\n mode: 'complete' | 'review';\n applicationContext?: string;\n};\n\nexport type TranslateJSONResultData<T = JSON> = {\n fileContent: T;\n tokenUsed: number;\n};\n\nexport const aiDefaultOptions: AIOptions = {\n provider: AIProvider.OPENAI,\n model: 'gpt-5-mini',\n};\n\n/**\n * Format a locale with its name.\n *\n * @param locale - The locale to format.\n * @returns A string in the format \"locale: name\", e.g. \"en: English\".\n */\nconst formatLocaleWithName = (locale: Locale): string =>\n `${locale}: ${getLocaleName(locale, Locales.ENGLISH)}`;\n\n/**\n * Formats tag instructions for the AI prompt.\n * Creates a string with all available tags and their descriptions.\n *\n * @param tags - The list of tags to format.\n * @returns A formatted string with tag instructions.\n */\nconst formatTagInstructions = (tags: Tag[]): string => {\n if (!tags || tags.length === 0) {\n return '';\n }\n\n // Prepare the tag instructions.\n return `Based on the dictionary content, identify specific tags from the list below that would be relevant:\n \n${tags.map(({ key, description }) => `- ${key}: ${description}`).join('\\n\\n')}`;\n};\n\nconst getModeInstructions = (mode: 'complete' | 'review'): string => {\n if (mode === 'complete') {\n return 'Mode: \"Complete\" - Enrich the preset content with the missing keys and values in the output locale. Do not update existing keys. Everything should be returned in the output.';\n }\n\n return 'Mode: \"Review\" - Fill missing content and review existing keys from the preset content. If a key from the entry is missing in the output, it must be translated to the target language and added. If you detect misspelled content, or content that should be reformulated, correct it. If a translation is not coherent with the desired language, translate it.';\n};\n\nconst jsonToZod = (content: any): z.ZodTypeAny => {\n // Base case: content is a string (the translation target)\n if (typeof content === 'string') {\n return z.string();\n }\n\n // Base cases: primitives often preserved in i18n files (e.g. strict numbers/booleans)\n if (typeof content === 'number') {\n return z.number();\n }\n if (typeof content === 'boolean') {\n return z.boolean();\n }\n\n // Recursive case: Array\n if (Array.isArray(content)) {\n // If array is empty, we assume array of strings as default for i18n\n if (content.length === 0) {\n return z.array(z.string());\n }\n // We assume all items in the array share the structure of the first item\n return z.array(jsonToZod(content[0]));\n }\n\n // Recursive case: Object\n if (typeof content === 'object' && content !== null) {\n const shape: Record<string, z.ZodTypeAny> = {};\n for (const key in content) {\n shape[key] = jsonToZod(content[key]);\n }\n return z.object(shape);\n }\n\n // Fallback\n return z.any();\n};\n\n/**\n * TranslateJSONs a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const translateJSON = async <T>({\n entryFileContent,\n presetOutputContent,\n dictionaryDescription,\n aiConfig,\n entryLocale,\n outputLocale,\n tags,\n mode,\n applicationContext,\n}: TranslateJSONOptions<T>): Promise<\n TranslateJSONResultData<T> | undefined\n> => {\n const promptFile = readAsset('./PROMPT.md');\n\n const formattedEntryLocale = formatLocaleWithName(entryLocale);\n const formattedOutputLocale = formatLocaleWithName(outputLocale);\n\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = promptFile\n .replace('{{entryLocale}}', formattedEntryLocale)\n .replace('{{outputLocale}}', formattedOutputLocale)\n .replace('{{presetOutputContent}}', JSON.stringify(presetOutputContent))\n .replace('{{dictionaryDescription}}', dictionaryDescription ?? '')\n .replace('{{applicationContext}}', applicationContext ?? '')\n .replace('{{tagsInstructions}}', formatTagInstructions(tags ?? []))\n .replace('{{modeInstructions}}', getModeInstructions(mode));\n\n // Use the AI SDK to generate the completion\n const { object, usage } = await generateObject({\n ...aiConfig,\n schema: jsonToZod(entryFileContent),\n messages: [\n { role: 'system', content: prompt },\n {\n role: 'user',\n // KEY CHANGE: Explicitly repeating instructions in the user message\n content: [\n `# Translation Request`,\n `Please translate the following JSON content.`,\n `- **From:** ${formattedEntryLocale}`,\n `- **To:** ${formattedOutputLocale}`,\n ``,\n `## Entry Content:`,\n JSON.stringify(entryFileContent),\n ].join('\\n'),\n },\n ],\n });\n\n return {\n fileContent: object as T,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;;;AA6BA,MAAa,mBAA8B;CACzC,UAAU,WAAW;CACrB,OAAO;CACR;;;;;;;AAQD,MAAM,wBAAwB,WAC5B,GAAG,OAAO,IAAI,cAAc,QAAQ,QAAQ,QAAQ;;;;;;;;AAStD,MAAM,yBAAyB,SAAwB;AACrD,KAAI,CAAC,QAAQ,KAAK,WAAW,EAC3B,QAAO;AAIT,QAAO;;EAEP,KAAK,KAAK,EAAE,KAAK,kBAAkB,KAAK,IAAI,IAAI,cAAc,CAAC,KAAK,OAAO;;AAG7E,MAAM,uBAAuB,SAAwC;AACnE,KAAI,SAAS,WACX,QAAO;AAGT,QAAO;;AAGT,MAAM,aAAa,YAA+B;AAEhD,KAAI,OAAO,YAAY,SACrB,QAAO,EAAE,QAAQ;AAInB,KAAI,OAAO,YAAY,SACrB,QAAO,EAAE,QAAQ;AAEnB,KAAI,OAAO,YAAY,UACrB,QAAO,EAAE,SAAS;AAIpB,KAAI,MAAM,QAAQ,QAAQ,EAAE;AAE1B,MAAI,QAAQ,WAAW,EACrB,QAAO,EAAE,MAAM,EAAE,QAAQ,CAAC;AAG5B,SAAO,EAAE,MAAM,UAAU,QAAQ,GAAG,CAAC;;AAIvC,KAAI,OAAO,YAAY,YAAY,YAAY,MAAM;EACnD,MAAM,QAAsC,EAAE;AAC9C,OAAK,MAAM,OAAO,QAChB,OAAM,OAAO,UAAU,QAAQ,KAAK;AAEtC,SAAO,EAAE,OAAO,MAAM;;AAIxB,QAAO,EAAE,KAAK;;;;;;;AAQhB,MAAa,gBAAgB,OAAU,EACrC,kBACA,qBACA,uBACA,UACA,aACA,cACA,MACA,MACA,yBAGG;CACH,MAAM,aAAa,UAAU,cAAc;CAE3C,MAAM,uBAAuB,qBAAqB,YAAY;CAC9D,MAAM,wBAAwB,qBAAqB,aAAa;CAGhE,MAAM,SAAS,WACZ,QAAQ,mBAAmB,qBAAqB,CAChD,QAAQ,oBAAoB,sBAAsB,CAClD,QAAQ,2BAA2B,KAAK,UAAU,oBAAoB,CAAC,CACvE,QAAQ,6BAA6B,yBAAyB,GAAG,CACjE,QAAQ,0BAA0B,sBAAsB,GAAG,CAC3D,QAAQ,wBAAwB,sBAAsB,QAAQ,EAAE,CAAC,CAAC,CAClE,QAAQ,wBAAwB,oBAAoB,KAAK,CAAC;CAG7D,MAAM,EAAE,QAAQ,UAAU,MAAM,eAAe;EAC7C,GAAG;EACH,QAAQ,UAAU,iBAAiB;EACnC,UAAU,CACR;GAAE,MAAM;GAAU,SAAS;GAAQ,EACnC;GACE,MAAM;GAEN,SAAS;IACP;IACA;IACA,eAAe;IACf,aAAa;IACb;IACA;IACA,KAAK,UAAU,iBAAiB;IACjC,CAAC,KAAK,KAAK;GACb,CACF;EACF,CAAC;AAEF,QAAO;EACL,aAAa;EACb,WAAW,OAAO,eAAe;EAClC"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/translateJSON/index.ts"],"sourcesContent":["import { readAsset } from 'utils:asset';\nimport { getLocaleName } from '@intlayer/core';\nimport { type Locale, Locales } from '@intlayer/types';\nimport { decode, encode } from '@toon-format/toon';\nimport { generateText, Output } from 'ai';\nimport { z } from 'zod';\nimport { type AIConfig, type AIOptions, AIProvider } from '../aiSdk';\n\ntype Tag = {\n key: string;\n description?: string;\n};\n\nexport type TranslateJSONOptions<T = JSON> = {\n entryFileContent: T;\n presetOutputContent: Partial<T>;\n dictionaryDescription?: string;\n entryLocale: Locale;\n outputLocale: Locale;\n tags?: Tag[];\n aiConfig: AIConfig;\n mode: 'complete' | 'review';\n applicationContext?: string;\n};\n\nexport type TranslateJSONResultData<T = JSON> = {\n fileContent: T;\n tokenUsed: number;\n};\n\nexport const aiDefaultOptions: AIOptions = {\n provider: AIProvider.OPENAI,\n model: 'gpt-5-mini',\n};\n\n/**\n * Format a locale with its name.\n *\n * @param locale - The locale to format.\n * @returns A string in the format \"locale: name\", e.g. \"en: English\".\n */\nconst formatLocaleWithName = (locale: Locale): string =>\n `${locale}: ${getLocaleName(locale, Locales.ENGLISH)}`;\n\n/**\n * Formats tag instructions for the AI prompt.\n * Creates a string with all available tags and their descriptions.\n *\n * @param tags - The list of tags to format.\n * @returns A formatted string with tag instructions.\n */\nconst formatTagInstructions = (tags: Tag[]): string => {\n if (!tags || tags.length === 0) {\n return '';\n }\n\n // Prepare the tag instructions.\n return `Based on the dictionary content, identify specific tags from the list below that would be relevant:\n \n${tags.map(({ key, description }) => `- ${key}: ${description}`).join('\\n\\n')}`;\n};\n\nconst getModeInstructions = (mode: 'complete' | 'review'): string => {\n if (mode === 'complete') {\n return 'Mode: \"Complete\" - Enrich the preset content with the missing keys and values in the output locale. Do not update existing keys. Everything should be returned in the output.';\n }\n\n return 'Mode: \"Review\" - Fill missing content and review existing keys from the preset content. If a key from the entry is missing in the output, it must be translated to the target language and added. If you detect misspelled content, or content that should be reformulated, correct it. If a translation is not coherent with the desired language, translate it.';\n};\n\nconst jsonToZod = (content: any): z.ZodTypeAny => {\n // Base case: content is a string (the translation target)\n if (typeof content === 'string') {\n return z.string();\n }\n\n // Base cases: primitives often preserved in i18n files (e.g. strict numbers/booleans)\n if (typeof content === 'number') {\n return z.number();\n }\n if (typeof content === 'boolean') {\n return z.boolean();\n }\n\n // Recursive case: Array\n if (Array.isArray(content)) {\n // If array is empty, we assume array of strings as default for i18n\n if (content.length === 0) {\n return z.array(z.string());\n }\n // We assume all items in the array share the structure of the first item\n return z.array(jsonToZod(content[0]));\n }\n\n // Recursive case: Object\n if (typeof content === 'object' && content !== null) {\n const shape: Record<string, z.ZodTypeAny> = {};\n for (const key in content) {\n shape[key] = jsonToZod(content[key]);\n }\n return z.object(shape);\n }\n\n // Fallback\n return z.any();\n};\n\n/**\n * TranslateJSONs a content declaration file by constructing a prompt for AI models.\n * The prompt includes details about the project's locales, file paths of content declarations,\n * and requests for identifying issues or inconsistencies.\n */\nexport const translateJSON = async <T>({\n entryFileContent,\n presetOutputContent,\n dictionaryDescription,\n aiConfig,\n entryLocale,\n outputLocale,\n tags,\n mode,\n applicationContext,\n}: TranslateJSONOptions<T>): Promise<\n TranslateJSONResultData<T> | undefined\n> => {\n const { dataSerialization, ...restAiConfig } = aiConfig;\n // @ts-ignore\n const { output: _unusedOutput, ...validAiConfig } = restAiConfig;\n\n const formattedEntryLocale = formatLocaleWithName(entryLocale);\n const formattedOutputLocale = formatLocaleWithName(outputLocale);\n\n const isToon = dataSerialization === 'toon';\n const promptFile = readAsset(\n isToon ? './PROMPT_TOON.md' : './PROMPT_JSON.md'\n );\n const entryContentStr = isToon\n ? encode(entryFileContent)\n : JSON.stringify(entryFileContent);\n const presetContentStr = isToon\n ? encode(presetOutputContent)\n : JSON.stringify(presetOutputContent);\n\n // Prepare the prompt for AI by replacing placeholders with actual values.\n const prompt = promptFile\n .replace('{{entryLocale}}', formattedEntryLocale)\n .replace('{{outputLocale}}', formattedOutputLocale)\n .replace('{{presetOutputContent}}', presetContentStr)\n .replace('{{dictionaryDescription}}', dictionaryDescription ?? '')\n .replace('{{applicationContext}}', applicationContext ?? '')\n .replace('{{tagsInstructions}}', formatTagInstructions(tags ?? []))\n .replace('{{modeInstructions}}', getModeInstructions(mode));\n\n if (isToon) {\n const { text, usage } = await generateText({\n ...aiConfig,\n messages: [\n { role: 'system', content: prompt },\n {\n role: 'user',\n content: [\n `# Translation Request`,\n `Please translate the following TOON content.`,\n `- **From:** ${formattedEntryLocale}`,\n `- **To:** ${formattedOutputLocale}`,\n ``,\n `## Entry Content:`,\n entryContentStr,\n ].join('\\n'),\n },\n ],\n });\n\n // Strip markdown code blocks if present\n const cleanedText = text\n .replace(/^```(?:toon)?\\n([\\s\\S]*?)\\n```$/gm, '$1')\n .trim();\n\n return {\n fileContent: decode(cleanedText) as T,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n }\n\n // Use the AI SDK to generate the completion\n const { output, usage } = await generateText({\n ...validAiConfig,\n output: Output.object({\n schema: jsonToZod(entryFileContent),\n }),\n messages: [\n { role: 'system', content: prompt },\n {\n role: 'user',\n // KEY CHANGE: Explicitly repeating instructions in the user message\n content: [\n `# Translation Request`,\n `Please translate the following JSON content.`,\n `- **From:** ${formattedEntryLocale}`,\n `- **To:** ${formattedOutputLocale}`,\n ``,\n `## Entry Content:`,\n entryContentStr,\n ].join('\\n'),\n },\n ],\n });\n\n return {\n fileContent: output as T,\n tokenUsed: usage?.totalTokens ?? 0,\n };\n};\n"],"mappings":";;;;;;;;;AA8BA,MAAa,mBAA8B;CACzC,UAAU,WAAW;CACrB,OAAO;CACR;;;;;;;AAQD,MAAM,wBAAwB,WAC5B,GAAG,OAAO,IAAI,cAAc,QAAQ,QAAQ,QAAQ;;;;;;;;AAStD,MAAM,yBAAyB,SAAwB;AACrD,KAAI,CAAC,QAAQ,KAAK,WAAW,EAC3B,QAAO;AAIT,QAAO;;EAEP,KAAK,KAAK,EAAE,KAAK,kBAAkB,KAAK,IAAI,IAAI,cAAc,CAAC,KAAK,OAAO;;AAG7E,MAAM,uBAAuB,SAAwC;AACnE,KAAI,SAAS,WACX,QAAO;AAGT,QAAO;;AAGT,MAAM,aAAa,YAA+B;AAEhD,KAAI,OAAO,YAAY,SACrB,QAAO,EAAE,QAAQ;AAInB,KAAI,OAAO,YAAY,SACrB,QAAO,EAAE,QAAQ;AAEnB,KAAI,OAAO,YAAY,UACrB,QAAO,EAAE,SAAS;AAIpB,KAAI,MAAM,QAAQ,QAAQ,EAAE;AAE1B,MAAI,QAAQ,WAAW,EACrB,QAAO,EAAE,MAAM,EAAE,QAAQ,CAAC;AAG5B,SAAO,EAAE,MAAM,UAAU,QAAQ,GAAG,CAAC;;AAIvC,KAAI,OAAO,YAAY,YAAY,YAAY,MAAM;EACnD,MAAM,QAAsC,EAAE;AAC9C,OAAK,MAAM,OAAO,QAChB,OAAM,OAAO,UAAU,QAAQ,KAAK;AAEtC,SAAO,EAAE,OAAO,MAAM;;AAIxB,QAAO,EAAE,KAAK;;;;;;;AAQhB,MAAa,gBAAgB,OAAU,EACrC,kBACA,qBACA,uBACA,UACA,aACA,cACA,MACA,MACA,yBAGG;CACH,MAAM,EAAE,mBAAmB,GAAG,iBAAiB;CAE/C,MAAM,EAAE,QAAQ,eAAe,GAAG,kBAAkB;CAEpD,MAAM,uBAAuB,qBAAqB,YAAY;CAC9D,MAAM,wBAAwB,qBAAqB,aAAa;CAEhE,MAAM,SAAS,sBAAsB;CACrC,MAAM,aAAa,UACjB,SAAS,qBAAqB,mBAC/B;CACD,MAAM,kBAAkB,SACpB,OAAO,iBAAiB,GACxB,KAAK,UAAU,iBAAiB;CACpC,MAAM,mBAAmB,SACrB,OAAO,oBAAoB,GAC3B,KAAK,UAAU,oBAAoB;CAGvC,MAAM,SAAS,WACZ,QAAQ,mBAAmB,qBAAqB,CAChD,QAAQ,oBAAoB,sBAAsB,CAClD,QAAQ,2BAA2B,iBAAiB,CACpD,QAAQ,6BAA6B,yBAAyB,GAAG,CACjE,QAAQ,0BAA0B,sBAAsB,GAAG,CAC3D,QAAQ,wBAAwB,sBAAsB,QAAQ,EAAE,CAAC,CAAC,CAClE,QAAQ,wBAAwB,oBAAoB,KAAK,CAAC;AAE7D,KAAI,QAAQ;EACV,MAAM,EAAE,MAAM,UAAU,MAAM,aAAa;GACzC,GAAG;GACH,UAAU,CACR;IAAE,MAAM;IAAU,SAAS;IAAQ,EACnC;IACE,MAAM;IACN,SAAS;KACP;KACA;KACA,eAAe;KACf,aAAa;KACb;KACA;KACA;KACD,CAAC,KAAK,KAAK;IACb,CACF;GACF,CAAC;AAOF,SAAO;GACL,aAAa,OALK,KACjB,QAAQ,qCAAqC,KAAK,CAClD,MAAM,CAGyB;GAChC,WAAW,OAAO,eAAe;GAClC;;CAIH,MAAM,EAAE,QAAQ,UAAU,MAAM,aAAa;EAC3C,GAAG;EACH,QAAQ,OAAO,OAAO,EACpB,QAAQ,UAAU,iBAAiB,EACpC,CAAC;EACF,UAAU,CACR;GAAE,MAAM;GAAU,SAAS;GAAQ,EACnC;GACE,MAAM;GAEN,SAAS;IACP;IACA;IACA,eAAe;IACf,aAAa;IACb;IACA;IACA;IACD,CAAC,KAAK,KAAK;GACb,CACF;EACF,CAAC;AAEF,QAAO;EACL,aAAa;EACb,WAAW,OAAO,eAAe;EAClC"}
@@ -38,6 +38,7 @@ type AIOptions = {
38
38
  baseURL?: string;
39
39
  apiKey?: string;
40
40
  applicationContext?: string;
41
+ dataSerialization?: 'json' | 'toon';
41
42
  };
42
43
  type ChatCompletionRequestMessage = {
43
44
  role: 'system' | 'user' | 'assistant';
@@ -48,6 +49,7 @@ type AccessType = 'apiKey' | 'registered_user' | 'premium_user' | 'public';
48
49
  type AIConfig = Omit<Parameters<typeof generateText>[0], 'prompt'> & {
49
50
  reasoningEffort?: ReasoningEffort;
50
51
  textVerbosity?: 'low' | 'medium' | 'high';
52
+ dataSerialization?: 'json' | 'toon';
51
53
  };
52
54
  type AIConfigOptions = {
53
55
  userOptions?: AIOptions;
@@ -1 +1 @@
1
- {"version":3,"file":"aiSdk.d.ts","names":[],"sources":["../../src/aiSdk.ts"],"mappings":";;;;;;;;KAaK,cAAA,GAAiB,UAAA,QAAkB,SAAA;AAAA,KACnC,aAAA,GAAgB,UAAA,QAAkB,QAAA;AAAA,KAClC,YAAA,GAAe,UAAA,QAAkB,OAAA;AAAA,KACjC,WAAA,GAAc,UAAA,QAAkB,MAAA;AAAA,KAChC,WAAA,GAAc,UAAA,QAAkB,MAAA;AAAA,KAEzB,QAAA,IACR,kBAAA,GACA,gBAAA,GACA,qBAAA,GACA,gBAAA;;AAV6C;;KAgBrC,KAAA,GACR,cAAA,GACA,aAAA,GACA,YAAA,GACA,WAAA,GACA,WAAA;;;AApB2C;aA0BnC,UAAA;EACV,MAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,MAAA;EACA,MAAA;AAAA;AAAA,KAGU,eAAA;AAjC+B;;;AAAA,KAsC/B,SAAA;EACV,QAAA,GAAW,UAAA;EACX,KAAA,GAAQ,KAAA;EACR,WAAA;EACA,OAAA;EACA,MAAA;EACA,kBAAA;AAAA;AAAA,KAIU,4BAAA;EACV,IAAA;EACA,OAAA;EACA,SAAA,GAAY,IAAA;AAAA;AAAA,KAGT,UAAA;AAAA,KAyIO,QAAA,GAAW,IAAA,CAAK,UAAA,QAAkB,YAAA;EAC5C,eAAA,GAAkB,eAAA;EAClB,aAAA;AAAA;AAAA,KAKU,eAAA;EACV,WAAA,GAAc,SAAA;EACd,cAAA,GAAiB,SAAA;EACjB,cAAA,GAAiB,SAAA;EACjB,UAAA,GAAa,UAAA;AAAA;;;;;;;;cAUF,WAAA,GACX,OAAA,EAAS,eAAA,EACT,eAAA,eACC,OAAA,CAAQ,QAAA"}
1
+ {"version":3,"file":"aiSdk.d.ts","names":[],"sources":["../../src/aiSdk.ts"],"mappings":";;;;;;;;KAaK,cAAA,GAAiB,UAAA,QAAkB,SAAA;AAAA,KACnC,aAAA,GAAgB,UAAA,QAAkB,QAAA;AAAA,KAClC,YAAA,GAAe,UAAA,QAAkB,OAAA;AAAA,KACjC,WAAA,GAAc,UAAA,QAAkB,MAAA;AAAA,KAChC,WAAA,GAAc,UAAA,QAAkB,MAAA;AAAA,KAEzB,QAAA,IACR,kBAAA,GACA,gBAAA,GACA,qBAAA,GACA,gBAAA;;AAV6C;;KAgBrC,KAAA,GACR,cAAA,GACA,aAAA,GACA,YAAA,GACA,WAAA,GACA,WAAA;;;AApB2C;aA0BnC,UAAA;EACV,MAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,MAAA;EACA,MAAA;AAAA;AAAA,KAGU,eAAA;AAjC+B;;;AAAA,KAsC/B,SAAA;EACV,QAAA,GAAW,UAAA;EACX,KAAA,GAAQ,KAAA;EACR,WAAA;EACA,OAAA;EACA,MAAA;EACA,kBAAA;EACA,iBAAA;AAAA;AAAA,KAIU,4BAAA;EACV,IAAA;EACA,OAAA;EACA,SAAA,GAAY,IAAA;AAAA;AAAA,KAGT,UAAA;AAAA,KAyIO,QAAA,GAAW,IAAA,CAAK,UAAA,QAAkB,YAAA;EAC5C,eAAA,GAAkB,eAAA;EAClB,aAAA;EACA,iBAAA;AAAA;AAAA,KAKU,eAAA;EACV,WAAA,GAAc,SAAA;EACd,cAAA,GAAiB,SAAA;EACjB,cAAA,GAAiB,SAAA;EACjB,UAAA,GAAa,UAAA;AAAA;;;;;;;;cAUF,WAAA,GACX,OAAA,EAAS,eAAA,EACT,eAAA,eACC,OAAA,CAAQ,QAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/translateJSON/index.ts"],"mappings":";;;;KAOK,GAAA;EACH,GAAA;EACA,WAAA;AAAA;AAAA,KAGU,oBAAA,KAAyB,IAAA;EACnC,gBAAA,EAAkB,CAAA;EAClB,mBAAA,EAAqB,OAAA,CAAQ,CAAA;EAC7B,qBAAA;EACA,WAAA,EAAa,MAAA;EACb,YAAA,EAAc,MAAA;EACd,IAAA,GAAO,GAAA;EACP,QAAA,EAAU,QAAA;EACV,IAAA;EACA,kBAAA;AAAA;AAAA,KAGU,uBAAA,KAA4B,IAAA;EACtC,WAAA,EAAa,CAAA;EACb,SAAA;AAAA;AAAA,cAGW,gBAAA,EAAkB,SAAA;;;;;;cAkFlB,aAAA;EAA0B,gBAAA;EAAA,mBAAA;EAAA,qBAAA;EAAA,QAAA;EAAA,WAAA;EAAA,YAAA;EAAA,IAAA;EAAA,IAAA;EAAA;AAAA,GAUpC,oBAAA,CAAqB,CAAA,MAAK,OAAA,CAC3B,uBAAA,CAAwB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/translateJSON/index.ts"],"mappings":";;;;KAQK,GAAA;EACH,GAAA;EACA,WAAA;AAAA;AAAA,KAGU,oBAAA,KAAyB,IAAA;EACnC,gBAAA,EAAkB,CAAA;EAClB,mBAAA,EAAqB,OAAA,CAAQ,CAAA;EAC7B,qBAAA;EACA,WAAA,EAAa,MAAA;EACb,YAAA,EAAc,MAAA;EACd,IAAA,GAAO,GAAA;EACP,QAAA,EAAU,QAAA;EACV,IAAA;EACA,kBAAA;AAAA;AAAA,KAGU,uBAAA,KAA4B,IAAA;EACtC,WAAA,EAAa,CAAA;EACb,SAAA;AAAA;AAAA,cAGW,gBAAA,EAAkB,SAAA;;;;;;cAkFlB,aAAA;EAA0B,gBAAA;EAAA,mBAAA;EAAA,qBAAA;EAAA,QAAA;EAAA,WAAA;EAAA,YAAA;EAAA,IAAA;EAAA,IAAA;EAAA;AAAA,GAUpC,oBAAA,CAAqB,CAAA,MAAK,OAAA,CAC3B,uBAAA,CAAwB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/ai",
3
- "version": "8.0.4",
3
+ "version": "8.0.5",
4
4
  "private": false,
5
5
  "description": "SDK that provides AI capabilities for Intlayer applications",
6
6
  "keywords": [
@@ -78,20 +78,21 @@
78
78
  "@ai-sdk/google": "3.0.7",
79
79
  "@ai-sdk/mistral": "3.0.6",
80
80
  "@ai-sdk/openai": "3.0.9",
81
- "@intlayer/api": "8.0.4",
82
- "@intlayer/config": "8.0.4",
83
- "@intlayer/core": "8.0.4",
84
- "@intlayer/types": "8.0.4",
81
+ "@intlayer/api": "8.0.5",
82
+ "@intlayer/config": "8.0.5",
83
+ "@intlayer/core": "8.0.5",
84
+ "@intlayer/types": "8.0.5",
85
+ "@toon-format/toon": "^2.1.0",
85
86
  "ai": "6.0.31",
86
87
  "zod": "4.3.6"
87
88
  },
88
89
  "devDependencies": {
89
- "@types/node": "25.0.10",
90
+ "@types/node": "25.2.2",
90
91
  "@utils/ts-config": "1.0.4",
91
92
  "@utils/ts-config-types": "1.0.4",
92
93
  "@utils/tsdown-config": "1.0.4",
93
94
  "rimraf": "6.1.2",
94
- "tsdown": "0.20.1",
95
+ "tsdown": "0.20.3",
95
96
  "typescript": "5.9.3",
96
97
  "vitest": "4.0.18"
97
98
  },