@yunsoft/yuncms-api 0.1.20 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yunsoft/yuncms-api",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
4
4
  "description": "Express API runtime and bundled Studio server for YunCMS.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,7 +35,7 @@
35
35
  "@modelcontextprotocol/node": "2.0.0",
36
36
  "@modelcontextprotocol/server": "2.0.0",
37
37
  "@node-saml/node-saml": "5.1.0",
38
- "@yunsoft/yuncms-core": "0.1.20",
38
+ "@yunsoft/yuncms-core": "0.1.21",
39
39
  "express": "5.2.1",
40
40
  "ldapts": "9.0.0",
41
41
  "openid-client": "6.8.7",
package/src/ai/service.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { canonicalStudioLocale, STUDIO_LOCALE_CODES } from '@yunsoft/yuncms-core';
2
+
1
3
  import {
2
4
  aiToolDefinitions,
3
5
  executeAiTool,
@@ -7,7 +9,21 @@ import {
7
9
  } from './tools.js';
8
10
 
9
11
  const PROVIDER_RESPONSE_LIMIT = 2_000_000;
10
- const SUPPORTED_LOCALES = new Set(['tr', 'en']);
12
+ export const AI_REPLY_LANGUAGE_BY_LOCALE = Object.freeze({
13
+ en: 'English',
14
+ tr: 'Turkish',
15
+ es: 'Spanish',
16
+ de: 'German',
17
+ fr: 'French',
18
+ 'pt-BR': 'Brazilian Portuguese',
19
+ ja: 'Japanese',
20
+ 'zh-CN': 'Simplified Chinese',
21
+ });
22
+
23
+ if (Object.keys(AI_REPLY_LANGUAGE_BY_LOCALE).length !== STUDIO_LOCALE_CODES.length
24
+ || STUDIO_LOCALE_CODES.some((locale) => !AI_REPLY_LANGUAGE_BY_LOCALE[locale])) {
25
+ throw new Error('AI reply languages must cover every supported Studio locale');
26
+ }
11
27
 
12
28
  function aiError(code, message) {
13
29
  const error = new Error(message);
@@ -77,9 +93,10 @@ export function normalizeAiConversation(messages, config) {
77
93
  }
78
94
 
79
95
  function systemPrompt({ locale, writesEnabled, deletesEnabled }) {
80
- const language = locale === 'en' ? 'English' : 'Turkish';
96
+ const normalizedLocale = canonicalStudioLocale(locale) ?? 'en';
97
+ const language = AI_REPLY_LANGUAGE_BY_LOCALE[normalizedLocale];
81
98
  return [
82
- 'You are YunCMS Yapay Zeka, the assistant embedded inside YunCMS Studio.',
99
+ 'You are the AI assistant embedded inside YunCMS Studio.',
83
100
  `Reply in ${language} unless the user explicitly asks for another language.`,
84
101
  'Use the provided tools whenever an answer depends on YunCMS schema or records. Never invent collection names, fields, records, counts or permissions.',
85
102
  'The tools already enforce the signed-in user\'s YunCMS permissions. If a tool says access is forbidden, explain that the current account does not have that access instead of trying to bypass it.',
@@ -184,20 +201,20 @@ export class AiAssistantService {
184
201
 
185
202
  async chat(req, {
186
203
  messages,
187
- locale = 'tr',
204
+ locale = 'en',
188
205
  allowWrites = false,
189
206
  allowDeletes = false,
190
207
  } = {}) {
191
208
  const config = await this.settings();
192
209
  if (!config.enabled || !config.apiKey || !config.model) {
193
- throw aiError('AI_NOT_CONFIGURED', 'Yapay Zeka is not configured on this YunCMS server');
210
+ throw aiError('AI_NOT_CONFIGURED', 'The AI assistant is not configured on this YunCMS server');
194
211
  }
195
212
  if (req?.authMethod === 'public' || !req?.accountability?.user) {
196
- throw aiError('UNAUTHORIZED', 'Yapay Zeka requires an authenticated YunCMS account');
213
+ throw aiError('UNAUTHORIZED', 'The AI assistant requires an authenticated YunCMS account');
197
214
  }
198
215
 
199
216
  const conversation = normalizeAiConversation(messages, config);
200
- const normalizedLocale = SUPPORTED_LOCALES.has(locale) ? locale : 'tr';
217
+ const normalizedLocale = canonicalStudioLocale(locale) ?? 'en';
201
218
  const writesEnabled = config.writesEnabled === true && allowWrites === true;
202
219
  const deletesEnabled = writesEnabled && allowDeletes === true;
203
220
  const tools = aiToolDefinitions({ writesEnabled, deletesEnabled, maxItems: 100 });
@@ -229,7 +246,7 @@ export class AiAssistantService {
229
246
  }
230
247
 
231
248
  if (round >= config.maxToolRounds) {
232
- throw aiError('AI_TOOL_ROUND_LIMIT', 'Yapay Zeka reached the tool-call safety limit');
249
+ throw aiError('AI_TOOL_ROUND_LIMIT', 'The AI assistant reached the tool-call safety limit');
233
250
  }
234
251
 
235
252
  providerMessages.push(providerAssistantMessage(assistantMessage, toolCalls));
@@ -261,7 +278,7 @@ export class AiAssistantService {
261
278
  }
262
279
  }
263
280
 
264
- throw aiError('AI_TOOL_ROUND_LIMIT', 'Yapay Zeka reached the tool-call safety limit');
281
+ throw aiError('AI_TOOL_ROUND_LIMIT', 'The AI assistant reached the tool-call safety limit');
265
282
  }
266
283
  }
267
284
 
@@ -119,10 +119,10 @@ export class AiSettingsStore {
119
119
  const effectiveModel = Object.hasOwn(normalized, 'model') ? normalized.model : current.model;
120
120
  const effectiveEnabled = Object.hasOwn(normalized, 'enabled') ? normalized.enabled : Boolean(current.enabled);
121
121
  if (effectiveEnabled && !effectiveHasKey) {
122
- throw settingsError('INVALID_AI_CONFIG', 'Save an API key before enabling Yapay Zeka');
122
+ throw settingsError('INVALID_AI_CONFIG', 'Save an API key before enabling the AI assistant');
123
123
  }
124
124
  if (effectiveEnabled && !effectiveModel) {
125
- throw settingsError('INVALID_AI_CONFIG', 'Choose a model before enabling Yapay Zeka');
125
+ throw settingsError('INVALID_AI_CONFIG', 'Choose a model before enabling the AI assistant');
126
126
  }
127
127
 
128
128
  params.push(1);
package/src/routes/ai.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import express from 'express';
2
2
 
3
3
  function authError() {
4
- const error = new Error('Yapay Zeka requires an authenticated YunCMS account');
4
+ const error = new Error('AI assistant requires an authenticated YunCMS account');
5
5
  error.code = 'UNAUTHORIZED';
6
6
  return error;
7
7
  }
@@ -13,7 +13,7 @@ function requireAuthenticated(req) {
13
13
  function requireAdministrator(req) {
14
14
  requireAuthenticated(req);
15
15
  if (req.accountability?.admin === true || req.accountability?.system === true) return;
16
- const error = new Error('Yapay Zeka settings require administrator access');
16
+ const error = new Error('AI assistant settings require administrator access');
17
17
  error.code = 'FORBIDDEN';
18
18
  throw error;
19
19
  }