@crowdin/app-project-module 0.55.0 → 0.56.1

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/out/index.js CHANGED
@@ -62,6 +62,7 @@ const customMTApp = __importStar(require("./modules/custom-mt"));
62
62
  const spellCheckApp = __importStar(require("./modules/custom-spell-check"));
63
63
  const aiProvider = __importStar(require("./modules/ai-provider"));
64
64
  const aiPromptProvider = __importStar(require("./modules/ai-prompt-provider"));
65
+ const aiToolCalls = __importStar(require("./modules/ai-tools"));
65
66
  const editorRightPanelApp = __importStar(require("./modules/editor-right-panel"));
66
67
  const editorThemesApp = __importStar(require("./modules/editor-themes"));
67
68
  const fileProcessingApps = __importStar(require("./modules/file-processing"));
@@ -167,6 +168,8 @@ function addCrowdinEndpoints(app, clientConfig) {
167
168
  apiApp.register({ config, app });
168
169
  aiProvider.register({ config, app });
169
170
  aiPromptProvider.register({ config, app });
171
+ aiToolCalls.registerAiToolCalls({ config, app });
172
+ aiToolCalls.registerAiToolCallWidgets({ config, app });
170
173
  addFormSchema({ config, app });
171
174
  return Object.assign(Object.assign({}, exports.metadataStore), { establishCrowdinConnection: (authRequest) => {
172
175
  let jwtToken = '';
@@ -0,0 +1,5 @@
1
+ /// <reference types="qs" />
2
+ import { Response } from 'express';
3
+ import { CrowdinClientRequest } from '../../../types';
4
+ import { AiToolCall } from '../types';
5
+ export default function handle(aiToolCall: AiToolCall): (req: CrowdinClientRequest | import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const util_1 = require("../../../util");
13
+ const logger_1 = require("../../../util/logger");
14
+ function handle(aiToolCall) {
15
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
16
+ try {
17
+ const { crowdinApiClient: client, crowdinContext: context, body: payload } = req;
18
+ const { function: { arguments: stringArgs = '' }, } = payload;
19
+ const { jwtPayload: { context: { project_id: projectId }, }, } = context;
20
+ let args = null;
21
+ try {
22
+ args = JSON.parse(stringArgs);
23
+ }
24
+ catch (e) { }
25
+ const { content, error: message } = yield aiToolCall.handle({
26
+ client,
27
+ args,
28
+ projectId,
29
+ payload,
30
+ context,
31
+ req,
32
+ });
33
+ res.send({
34
+ data: {
35
+ content: typeof content === 'string' ? content : JSON.stringify(content),
36
+ error: message ? { message } : undefined,
37
+ },
38
+ });
39
+ }
40
+ catch (e) {
41
+ if (req.logError) {
42
+ req.logError(e);
43
+ }
44
+ res.send({ error: { message: (0, logger_1.getErrorMessage)(e) } });
45
+ }
46
+ }));
47
+ }
48
+ exports.default = handle;
@@ -0,0 +1,10 @@
1
+ import { Express } from 'express';
2
+ import { Config } from '../../types';
3
+ export declare function registerAiToolCalls({ config, app }: {
4
+ config: Config;
5
+ app: Express;
6
+ }): void;
7
+ export declare function registerAiToolCallWidgets({ config, app }: {
8
+ config: Config;
9
+ app: Express;
10
+ }): void;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerAiToolCallWidgets = exports.registerAiToolCalls = void 0;
7
+ const json_response_1 = __importDefault(require("../../middlewares/json-response"));
8
+ const tool_calls_1 = __importDefault(require("./handlers/tool-calls"));
9
+ const ui_module_1 = __importDefault(require("../../middlewares/ui-module"));
10
+ const render_ui_module_1 = __importDefault(require("../../middlewares/render-ui-module"));
11
+ const crowdin_client_1 = __importDefault(require("../../middlewares/crowdin-client"));
12
+ function getToolKey(tool) {
13
+ return tool.function.name;
14
+ }
15
+ function registerAiToolCalls({ config, app }) {
16
+ if (config.aiToolCalls) {
17
+ const tools = Array.isArray(config.aiToolCalls) ? config.aiToolCalls : [config.aiToolCalls];
18
+ for (const tool of tools) {
19
+ app.post(`/ai-tool-calls/${getToolKey(tool)}`, json_response_1.default, (0, crowdin_client_1.default)(config), (0, tool_calls_1.default)(tool));
20
+ }
21
+ }
22
+ }
23
+ exports.registerAiToolCalls = registerAiToolCalls;
24
+ function registerAiToolCallWidgets({ config, app }) {
25
+ if (config.aiToolCallWidgets) {
26
+ const tools = Array.isArray(config.aiToolCallWidgets) ? config.aiToolCallWidgets : [config.aiToolCallWidgets];
27
+ for (const tool of tools) {
28
+ app.use(`/ai-tool-call-widgets/${getToolKey(tool)}`, (0, ui_module_1.default)(config), (0, render_ui_module_1.default)(tool));
29
+ }
30
+ }
31
+ }
32
+ exports.registerAiToolCallWidgets = registerAiToolCallWidgets;
@@ -0,0 +1,63 @@
1
+ import { CrowdinClientRequest, CrowdinContextInfo, Environments, UiModule } from '../../types';
2
+ import Crowdin from '@crowdin/crowdin-api-client';
3
+ export interface AiToolCallWidget extends AiTool, UiModule {
4
+ }
5
+ export interface AiToolCall extends AiTool {
6
+ /**
7
+ * function to handle requests
8
+ */
9
+ handle: (options: AiToolCallArguments) => Promise<AiToolCallResponse>;
10
+ }
11
+ interface AiTool extends Environments {
12
+ /**
13
+ * Tool type, default is 'function'
14
+ */
15
+ toolType: string;
16
+ /**
17
+ * describe function object
18
+ */
19
+ function: AiToolCallFunction;
20
+ }
21
+ interface AiToolCallFunction {
22
+ /**
23
+ * The name of the function to be called. Must be a-z, A-Z, 0-9, or contain underscores and dashes.
24
+ */
25
+ name: string;
26
+ /**
27
+ * A description of what the function does, used by the AI model to choose when and how to call the function.
28
+ */
29
+ description: string;
30
+ /**
31
+ * Describe as a JSON Schema object
32
+ */
33
+ parameters?: {
34
+ type: string;
35
+ properties: object;
36
+ required?: string[];
37
+ };
38
+ }
39
+ interface AiToolCallArguments {
40
+ client: Crowdin;
41
+ args: object | null;
42
+ projectId: number;
43
+ payload: AiToolCallPayload;
44
+ context: CrowdinContextInfo;
45
+ req: CrowdinClientRequest;
46
+ }
47
+ interface AiToolCallPayload {
48
+ function: {
49
+ name: string;
50
+ arguments: string;
51
+ };
52
+ organization: {
53
+ [key: string]: unknown;
54
+ };
55
+ project: {
56
+ [key: string]: unknown;
57
+ };
58
+ }
59
+ interface AiToolCallResponse {
60
+ content: string | object;
61
+ error?: string;
62
+ }
63
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -86,6 +86,7 @@ function filesCron({ config, integration, period, }) {
86
86
  (0, logger_1.log)(`Starting files cron job with period [${period}]`);
87
87
  const syncSettingsList = yield (0, storage_1.getStorage)().getAllSyncSettingsByType('schedule');
88
88
  for (const syncSettings of syncSettingsList) {
89
+ let projectData;
89
90
  let files = JSON.parse(syncSettings.files);
90
91
  let newFiles = [];
91
92
  const crowdinCredentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(syncSettings.crowdinId);
@@ -131,8 +132,14 @@ function filesCron({ config, integration, period, }) {
131
132
  (0, logger_1.log)(`Subscription expired. Skipping job [${period}] for organization ${crowdinCredentials.id}`);
132
133
  continue;
133
134
  }
134
- const projectData = (yield crowdinClient.projectsGroupsApi.getProject(projectId))
135
- .data;
135
+ try {
136
+ projectData = (yield crowdinClient.projectsGroupsApi.getProject(projectId))
137
+ .data;
138
+ }
139
+ catch (e) {
140
+ (0, logger_1.logError)(e);
141
+ continue;
142
+ }
136
143
  // eslint-disable-next-line @typescript-eslint/camelcase
137
144
  context.jwtPayload.context.project_identifier = projectData.identifier;
138
145
  const rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, crowdinClient, projectId);
@@ -188,6 +188,26 @@ function handle(config) {
188
188
  : {})),
189
189
  ];
190
190
  }
191
+ if (config.aiToolCalls) {
192
+ const tools = Array.isArray(config.aiToolCalls) ? config.aiToolCalls : [config.aiToolCalls];
193
+ modules['ai-tool-calls'] = [];
194
+ for (const tool of tools) {
195
+ const key = tool.function.name;
196
+ modules['ai-tool-calls'].push(Object.assign({ key, toolType: 'function', function: tool.function, url: `/ai-tool-calls/${key}` }, (!!tool.environments && {
197
+ environments: normalizeEnvironments(tool.environments),
198
+ })));
199
+ }
200
+ }
201
+ if (config.aiToolCallWidgets) {
202
+ const tools = Array.isArray(config.aiToolCallWidgets) ? config.aiToolCallWidgets : [config.aiToolCallWidgets];
203
+ modules['ai-tool-call-widgets'] = [];
204
+ for (const tool of tools) {
205
+ const key = tool.function.name;
206
+ modules['ai-tool-call-widgets'].push(Object.assign({ key, toolType: 'function', function: tool.function, url: `/ai-tool-call-widgets/${key}/${tool.fileName || 'index.html'}` }, (!!tool.environments && {
207
+ environments: normalizeEnvironments(tool.environments),
208
+ })));
209
+ }
210
+ }
191
211
  const events = {
192
212
  installed: '/installed',
193
213
  uninstall: '/uninstall',
package/out/types.d.ts CHANGED
@@ -14,6 +14,7 @@ import { ApiModule } from './modules/api/types';
14
14
  import { LogErrorFunction, LogFunction } from './util/logger';
15
15
  import { AiProviderModule } from './modules/ai-provider/types';
16
16
  import { AiPromptProviderModule } from './modules/ai-prompt-provider/types';
17
+ import { AiToolCall, AiToolCallWidget } from './modules/ai-tools/types';
17
18
  export interface ClientConfig extends ImagePath {
18
19
  /**
19
20
  * Authentication Crowdin App type: "authorization_code", "crowdin_app". Default: "crowdin_app"
@@ -185,6 +186,14 @@ export interface ClientConfig extends ImagePath {
185
186
  * ai prompt provider module
186
187
  */
187
188
  aiPromptProvider?: AiPromptProviderModule & ImagePath;
189
+ /**
190
+ * AI tool_calls modules
191
+ */
192
+ aiToolCalls?: AiToolCall | AiToolCall[];
193
+ /**
194
+ * AI tool_calls modules with UI widgets
195
+ */
196
+ aiToolCallWidgets?: AiToolCallWidget | AiToolCallWidget[];
188
197
  }
189
198
  export interface Environments {
190
199
  environments?: Environment | Environment[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.55.0",
3
+ "version": "0.56.1",
4
4
  "description": "Module that generates for you all common endpoints for serving standalone Crowdin App",
5
5
  "main": "out/index.js",
6
6
  "types": "out/index.d.ts",