@resolveio/server-lib 20.14.28 → 20.14.30

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.
@@ -18,5 +18,25 @@ export type AiAssistantMongoReadInput = {
18
18
  readonly?: boolean;
19
19
  };
20
20
  };
21
+ export type AiAssistantMongoAggregateInput = {
22
+ database?: string;
23
+ collection?: string;
24
+ query?: Record<string, any>;
25
+ pipeline?: Array<Record<string, any>>;
26
+ options?: {
27
+ allowDiskUse?: boolean;
28
+ maxTimeMS?: number;
29
+ limit?: number;
30
+ };
31
+ permissionView?: string;
32
+ id_client?: string;
33
+ mongo?: {
34
+ database?: string;
35
+ databases?: string[];
36
+ access?: string;
37
+ readonly?: boolean;
38
+ };
39
+ };
21
40
  export declare function loadAiTerminalMethods(methodManager: any): void;
22
41
  export declare function executeAiAssistantMongoRead(payload: AiAssistantMongoReadInput, context: any): Promise<any>;
42
+ export declare function executeAiAssistantMongoAggregate(payload: AiAssistantMongoAggregateInput, context: any): Promise<any>;
@@ -14,6 +14,17 @@ var __extends = (this && this.__extends) || (function () {
14
14
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
15
  };
16
16
  })();
17
+ var __assign = (this && this.__assign) || function () {
18
+ __assign = Object.assign || function(t) {
19
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
20
+ s = arguments[i];
21
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
22
+ t[p] = s[p];
23
+ }
24
+ return t;
25
+ };
26
+ return __assign.apply(this, arguments);
27
+ };
17
28
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
29
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
30
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -50,17 +61,6 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
50
61
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
62
  }
52
63
  };
53
- var __values = (this && this.__values) || function(o) {
54
- var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
55
- if (m) return m.call(o);
56
- if (o && typeof o.length === "number") return {
57
- next: function () {
58
- if (o && i >= o.length) o = void 0;
59
- return { value: o && o[i++], done: !o };
60
- }
61
- };
62
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
63
- };
64
64
  var __read = (this && this.__read) || function (o, n) {
65
65
  var m = typeof Symbol === "function" && o[Symbol.iterator];
66
66
  if (!m) return o;
@@ -77,9 +77,30 @@ var __read = (this && this.__read) || function (o, n) {
77
77
  }
78
78
  return ar;
79
79
  };
80
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
81
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
82
+ if (ar || !(i in from)) {
83
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
84
+ ar[i] = from[i];
85
+ }
86
+ }
87
+ return to.concat(ar || Array.prototype.slice.call(from));
88
+ };
89
+ var __values = (this && this.__values) || function(o) {
90
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
91
+ if (m) return m.call(o);
92
+ if (o && typeof o.length === "number") return {
93
+ next: function () {
94
+ if (o && i >= o.length) o = void 0;
95
+ return { value: o && o[i++], done: !o };
96
+ }
97
+ };
98
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
99
+ };
80
100
  Object.defineProperty(exports, "__esModule", { value: true });
81
101
  exports.loadAiTerminalMethods = loadAiTerminalMethods;
82
102
  exports.executeAiAssistantMongoRead = executeAiAssistantMongoRead;
103
+ exports.executeAiAssistantMongoAggregate = executeAiAssistantMongoAggregate;
83
104
  var fs_1 = require("fs");
84
105
  var events_1 = require("events");
85
106
  var os = require("os");
@@ -104,6 +125,10 @@ var DEFAULT_CODEX_MODEL = 'gpt-5.2-codex';
104
125
  var DEFAULT_CODEX_TIMEOUT_MS = 180000;
105
126
  var AI_ASSISTANT_MONGO_DEFAULT_LIMIT = 20;
106
127
  var AI_ASSISTANT_MONGO_MAX_LIMIT = 200;
128
+ var AI_ASSISTANT_DATE_FALLBACKS = {
129
+ date_created: 'createdAt',
130
+ createdAt: 'date_created'
131
+ };
107
132
  var AI_ASSISTANT_BLOCKED_COLLECTIONS = new Set([
108
133
  'user-groups',
109
134
  'logged-in-users',
@@ -157,17 +182,22 @@ var AI_ASSISTANT_SYSTEM_PROMPT = [
157
182
  '- If the user explicitly asks to create/open/file a support ticket, end your response with a single line exactly in this format:',
158
183
  '- SUPPORT_TICKET_CREATE: <one-line summary>',
159
184
  '- Only include that line when the user clearly wants a ticket created. Do not claim a ticket is created unless you include that line.',
185
+ '- Do not end responses with tentative phrasing like "I could" or "I’m going to." Complete the request or state what is required to proceed.',
186
+ '- Use the codebase context to choose correct collections/fields/workflows and use MONGO_READ/MONGO_AGG to answer with real data when needed.',
160
187
  '- For direct questions, answer first. Ask a single follow-up only if required to run a query or resolve missing details.',
161
188
  '- If you need database data to answer, end your response with a single line exactly in this format:',
162
189
  '- MONGO_READ: {"collection":"<name>","query":{...},"options":{"projection":{...},"sort":{...},"limit":20},"permissionView":"</route>"}',
190
+ '- If you need grouped/aggregated data (totals by user, rankings, trends), end your response with a single line exactly in this format:',
191
+ '- MONGO_AGG: {"collection":"<name>","pipeline":[...],"options":{"allowDiskUse":true,"limit":20},"permissionView":"</route>"}',
163
192
  '- For invoice data, set permissionView to an invoice route (ex: /invoice/list or /report/invoice).',
164
193
  '- Keep queries minimal, read-only, and avoid user/credential data unless the user is a super admin.',
165
194
  '- Assume you are not a super admin unless explicitly told otherwise.',
166
195
  '- Only request data when the user has permission for that module; invoice data requires invoice view access.',
167
196
  '- If the user lacks permission, answer without data and explain how to view it in the app or request access.',
168
- '- For counts, totals, or time-range metrics, always use MONGO_READ. Do not guess or return 0 without data.',
169
- '- Before issuing MONGO_READ, verify the collection name and key fields by checking collection/model definitions in the current app (look for "collectionName:" and date fields like date_created/date_completed/createdAt). Do not invent collection names.',
170
- '- Use MONGO_READ only to produce summaries/snapshots/health checks (not raw dumps) when permitted.',
197
+ '- For simple counts or time-range totals, use MONGO_READ (includeTotal). For breakdowns, rankings, or sums grouped by a field, use MONGO_AGG.',
198
+ '- Before issuing MONGO_READ or MONGO_AGG, verify the collection name and key fields by checking collection/model definitions in the current app (look for "collectionName:" and date fields like date_created/date_completed/createdAt). Do not invent collection names.',
199
+ '- For creation-date questions when both date_created and createdAt exist, match both with $or so results are not missed.',
200
+ '- Use MONGO_READ/MONGO_AGG only to produce summaries/snapshots/health checks (not raw dumps) when permitted.',
171
201
  '- When referencing data, summarize it in bullets and avoid raw JSON or dumps.',
172
202
  '- Keep responses concise and use low reasoning effort.'
173
203
  ].join('\n');
@@ -198,7 +228,7 @@ function loadAiTerminalMethods(methodManager) {
198
228
  case 0:
199
229
  now = new Date();
200
230
  doc = {
201
- id_client: normalizeOptionalString(payload.id_client),
231
+ id_client: resolveClientIdFromConfig(payload.id_client),
202
232
  id_app: normalizeOptionalString(payload.id_app),
203
233
  title: normalizeOptionalString(payload.title) || 'New Conversation',
204
234
  mode: normalizeConversationMode(payload.mode),
@@ -452,6 +482,24 @@ function loadAiTerminalMethods(methodManager) {
452
482
  });
453
483
  }
454
484
  },
485
+ aiAssistantMongoAggregate: {
486
+ check: new simpl_schema_1.default({
487
+ payload: {
488
+ type: Object,
489
+ blackbox: true
490
+ }
491
+ }),
492
+ function: function (payload) {
493
+ return __awaiter(this, void 0, void 0, function () {
494
+ return __generator(this, function (_a) {
495
+ switch (_a.label) {
496
+ case 0: return [4 /*yield*/, executeAiAssistantMongoAggregate(payload, this)];
497
+ case 1: return [2 /*return*/, _a.sent()];
498
+ }
499
+ });
500
+ });
501
+ }
502
+ },
455
503
  aiCoderTerminalDeployTest: {
456
504
  check: new simpl_schema_1.default({
457
505
  id_conversation: {
@@ -655,7 +703,7 @@ function executeAiFormPatch(payload, context) {
655
703
  case 1:
656
704
  response = _b.sent();
657
705
  usage = response.usage || estimateUsage(messages, response.content, response.model || openaiSettings.model);
658
- idClient = normalizeOptionalString(input.id_client);
706
+ idClient = resolveClientIdFromConfig(input.id_client);
659
707
  if (!idClient) return [3 /*break*/, 3];
660
708
  return [4 /*yield*/, (0, openai_usage_ledger_manager_1.recordOpenAIUsage)({
661
709
  id_client: idClient,
@@ -903,6 +951,89 @@ function executeAiAssistantMongoRead(payload, context) {
903
951
  });
904
952
  });
905
953
  }
954
+ function executeAiAssistantMongoAggregate(payload, context) {
955
+ return __awaiter(this, void 0, void 0, function () {
956
+ var input, collection, _a, user, isSuperAdmin, customerId, dbName, db, baseQuery, userId, normalizedClient, shouldScopeByClient, _b, clientScopedQuery, scopedQuery, normalizedPipeline, pipelineWithScope, normalizedOptions, limitedPipeline, documents, fallback, fallbackPipeline, fallbackDocs, sanitizedDocuments;
957
+ var _c;
958
+ return __generator(this, function (_d) {
959
+ switch (_d.label) {
960
+ case 0:
961
+ input = payload || {};
962
+ collection = normalizeOptionalString(input.collection);
963
+ if (!collection) {
964
+ throw new Error('AI assistant mongo aggregate: Collection is required.');
965
+ }
966
+ return [4 /*yield*/, ensureAssistantReadAccess(context, input.permissionView, collection)];
967
+ case 1:
968
+ _a = _d.sent(), user = _a.user, isSuperAdmin = _a.isSuperAdmin;
969
+ if (!isSuperAdmin && AI_ASSISTANT_BLOCKED_COLLECTIONS.has(collection)) {
970
+ throw new Error('AI assistant mongo aggregate: Access denied.');
971
+ }
972
+ customerId = normalizeOptionalString((_c = user === null || user === void 0 ? void 0 : user.other) === null || _c === void 0 ? void 0 : _c.id_customer);
973
+ dbName = resolveAssistantDatabaseName(input.database, input.mongo);
974
+ db = resolveio_server_app_1.ResolveIOServer.getMongoConnection().db(dbName);
975
+ baseQuery = normalizeMongoQuery(input.query);
976
+ if (!isSuperAdmin && (collection === 'users' || collection === 'user-versions')) {
977
+ userId = normalizeOptionalString(user === null || user === void 0 ? void 0 : user._id);
978
+ if (!userId) {
979
+ throw new Error('AI assistant mongo aggregate: Access denied.');
980
+ }
981
+ baseQuery = {
982
+ $and: [baseQuery, { _id: userId }]
983
+ };
984
+ }
985
+ normalizedClient = normalizeOptionalString(input.id_client);
986
+ if (!(!isSuperAdmin && normalizedClient)) return [3 /*break*/, 3];
987
+ return [4 /*yield*/, collectionHasClientIndex(db, dbName, collection)];
988
+ case 2:
989
+ _b = _d.sent();
990
+ return [3 /*break*/, 4];
991
+ case 3:
992
+ _b = false;
993
+ _d.label = 4;
994
+ case 4:
995
+ shouldScopeByClient = _b;
996
+ clientScopedQuery = shouldScopeByClient
997
+ ? applyClientScopeFilter(baseQuery, normalizedClient, isSuperAdmin)
998
+ : baseQuery;
999
+ scopedQuery = applyCustomerScopeFilter(clientScopedQuery, collection, customerId, isSuperAdmin);
1000
+ normalizedPipeline = normalizeAssistantAggregatePipeline(input.pipeline);
1001
+ pipelineWithScope = buildAssistantAggregatePipeline(scopedQuery, normalizedPipeline);
1002
+ normalizedOptions = normalizeAssistantAggregateOptions(input.options);
1003
+ limitedPipeline = applyAssistantAggregateLimit(pipelineWithScope, normalizedOptions.limit);
1004
+ if (containsForbiddenMongoOperators(limitedPipeline)) {
1005
+ throw new Error('AI assistant mongo aggregate: Pipeline contains restricted operators.');
1006
+ }
1007
+ return [4 /*yield*/, db.collection(collection)
1008
+ .aggregate(limitedPipeline, normalizedOptions.aggregateOptions)
1009
+ .toArray()];
1010
+ case 5:
1011
+ documents = _d.sent();
1012
+ if (!!documents.length) return [3 /*break*/, 7];
1013
+ fallback = resolveAggregateDateFieldFallback(limitedPipeline);
1014
+ if (!fallback) return [3 /*break*/, 7];
1015
+ fallbackPipeline = replaceAggregateDateField(limitedPipeline, fallback.from, fallback.to);
1016
+ if (!!containsForbiddenMongoOperators(fallbackPipeline)) return [3 /*break*/, 7];
1017
+ return [4 /*yield*/, db.collection(collection)
1018
+ .aggregate(fallbackPipeline, normalizedOptions.aggregateOptions)
1019
+ .toArray()];
1020
+ case 6:
1021
+ fallbackDocs = _d.sent();
1022
+ if (fallbackDocs.length) {
1023
+ documents = fallbackDocs;
1024
+ }
1025
+ _d.label = 7;
1026
+ case 7:
1027
+ sanitizedDocuments = isSuperAdmin
1028
+ ? documents
1029
+ : documents.map(function (doc) { return redactSensitiveFields((0, common_1.deepCopy)(doc)); });
1030
+ return [2 /*return*/, {
1031
+ documents: sanitizedDocuments
1032
+ }];
1033
+ }
1034
+ });
1035
+ });
1036
+ }
906
1037
  function ensureAssistantReadAccess(context, permissionView, collection) {
907
1038
  return __awaiter(this, void 0, void 0, function () {
908
1039
  var idUser, user, isSuperAdmin, normalizedPermission, normalizedCollection;
@@ -979,6 +1110,162 @@ function normalizeAssistantFindOptions(options) {
979
1110
  includeTotal: normalized.includeTotal === true
980
1111
  };
981
1112
  }
1113
+ function normalizeAssistantAggregatePipeline(pipeline) {
1114
+ if (!Array.isArray(pipeline)) {
1115
+ return [];
1116
+ }
1117
+ return pipeline.filter(function (stage) { return stage && typeof stage === 'object' && !Array.isArray(stage); });
1118
+ }
1119
+ function buildAssistantAggregatePipeline(query, pipeline) {
1120
+ var _a;
1121
+ var scopedPipeline = Array.isArray(pipeline) ? __spreadArray([], __read(pipeline), false) : [];
1122
+ if (!query || !Object.keys(query).length) {
1123
+ return scopedPipeline;
1124
+ }
1125
+ if (scopedPipeline.length && ((_a = scopedPipeline[0]) === null || _a === void 0 ? void 0 : _a.$geoNear) && typeof scopedPipeline[0].$geoNear === 'object') {
1126
+ var geoNearStage = __assign({}, scopedPipeline[0].$geoNear);
1127
+ var existingQuery = geoNearStage.query && typeof geoNearStage.query === 'object' ? geoNearStage.query : {};
1128
+ geoNearStage.query = { $and: [existingQuery, query] };
1129
+ return __spreadArray([{ $geoNear: geoNearStage }], __read(scopedPipeline.slice(1)), false);
1130
+ }
1131
+ return __spreadArray([{ $match: query }], __read(scopedPipeline), false);
1132
+ }
1133
+ function normalizeAssistantAggregateOptions(options) {
1134
+ var normalized = options || {};
1135
+ var allowDiskUse = normalized.allowDiskUse === true ? true : undefined;
1136
+ var maxTimeMS = typeof normalized.maxTimeMS === 'number' && normalized.maxTimeMS > 0
1137
+ ? (0, common_1.round)(normalized.maxTimeMS)
1138
+ : undefined;
1139
+ var limit = typeof normalized.limit === 'number'
1140
+ ? Math.min(Math.max((0, common_1.round)(normalized.limit), 0), AI_ASSISTANT_MONGO_MAX_LIMIT)
1141
+ : undefined;
1142
+ var aggregateOptions = {};
1143
+ if (allowDiskUse !== undefined) {
1144
+ aggregateOptions.allowDiskUse = allowDiskUse;
1145
+ }
1146
+ if (maxTimeMS !== undefined) {
1147
+ aggregateOptions.maxTimeMS = maxTimeMS;
1148
+ }
1149
+ return {
1150
+ aggregateOptions: aggregateOptions,
1151
+ limit: limit
1152
+ };
1153
+ }
1154
+ function findAggregateLimit(pipeline) {
1155
+ for (var i = 0; i < pipeline.length; i += 1) {
1156
+ var stage = pipeline[i];
1157
+ if (!stage || typeof stage !== 'object') {
1158
+ continue;
1159
+ }
1160
+ var limit = stage.$limit;
1161
+ if (typeof limit === 'number' && Number.isFinite(limit)) {
1162
+ return limit;
1163
+ }
1164
+ }
1165
+ return null;
1166
+ }
1167
+ function applyAssistantAggregateLimit(pipeline, limit) {
1168
+ var normalizedPipeline = Array.isArray(pipeline) ? __spreadArray([], __read(pipeline), false) : [];
1169
+ var maxLimit = AI_ASSISTANT_MONGO_MAX_LIMIT;
1170
+ var requestedLimit = typeof limit === 'number' && limit > 0
1171
+ ? Math.min(limit, maxLimit)
1172
+ : AI_ASSISTANT_MONGO_DEFAULT_LIMIT;
1173
+ var existingLimit = findAggregateLimit(normalizedPipeline);
1174
+ if (existingLimit === null) {
1175
+ normalizedPipeline.push({ $limit: requestedLimit });
1176
+ return normalizedPipeline;
1177
+ }
1178
+ if (existingLimit > maxLimit) {
1179
+ normalizedPipeline.push({ $limit: maxLimit });
1180
+ }
1181
+ return normalizedPipeline;
1182
+ }
1183
+ function resolveAggregateDateFieldFallback(pipeline) {
1184
+ var dateField = findAggregateDateField(pipeline);
1185
+ if (!dateField) {
1186
+ return null;
1187
+ }
1188
+ var fallback = AI_ASSISTANT_DATE_FALLBACKS[dateField];
1189
+ if (!fallback) {
1190
+ return null;
1191
+ }
1192
+ return { from: dateField, to: fallback };
1193
+ }
1194
+ function findAggregateDateField(pipeline) {
1195
+ var fields = new Set();
1196
+ (pipeline || []).forEach(function (stage) {
1197
+ if (!stage || typeof stage !== 'object') {
1198
+ return;
1199
+ }
1200
+ if (stage.$match && typeof stage.$match === 'object') {
1201
+ collectDateFieldsFromMatch(stage.$match, fields);
1202
+ }
1203
+ });
1204
+ if (fields.size !== 1) {
1205
+ return null;
1206
+ }
1207
+ return Array.from(fields)[0];
1208
+ }
1209
+ function collectDateFieldsFromMatch(value, fields) {
1210
+ if (!value || typeof value !== 'object') {
1211
+ return;
1212
+ }
1213
+ if (Array.isArray(value)) {
1214
+ value.forEach(function (entry) { return collectDateFieldsFromMatch(entry, fields); });
1215
+ return;
1216
+ }
1217
+ Object.keys(value).forEach(function (key) {
1218
+ var entry = value[key];
1219
+ if (Object.prototype.hasOwnProperty.call(AI_ASSISTANT_DATE_FALLBACKS, key)) {
1220
+ if (hasDateRangeOperators(entry) || entry instanceof Date) {
1221
+ fields.add(key);
1222
+ }
1223
+ return;
1224
+ }
1225
+ if (key.startsWith('$')) {
1226
+ collectDateFieldsFromMatch(entry, fields);
1227
+ return;
1228
+ }
1229
+ if (entry && typeof entry === 'object') {
1230
+ collectDateFieldsFromMatch(entry, fields);
1231
+ }
1232
+ });
1233
+ }
1234
+ function hasDateRangeOperators(value) {
1235
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
1236
+ return false;
1237
+ }
1238
+ return Object.prototype.hasOwnProperty.call(value, '$gte')
1239
+ || Object.prototype.hasOwnProperty.call(value, '$gt')
1240
+ || Object.prototype.hasOwnProperty.call(value, '$lte')
1241
+ || Object.prototype.hasOwnProperty.call(value, '$lt');
1242
+ }
1243
+ function replaceAggregateDateField(pipeline, fromField, toField) {
1244
+ var replacer = function (value) {
1245
+ if (Array.isArray(value)) {
1246
+ return value.map(function (entry) { return replacer(entry); });
1247
+ }
1248
+ if (value instanceof Date) {
1249
+ return value;
1250
+ }
1251
+ if (value && typeof value === 'object') {
1252
+ var next_1 = {};
1253
+ Object.keys(value).forEach(function (key) {
1254
+ var nextKey = key === fromField ? toField : key;
1255
+ next_1[nextKey] = replacer(value[key]);
1256
+ });
1257
+ return next_1;
1258
+ }
1259
+ if (typeof value === 'string') {
1260
+ if (value.startsWith("$".concat(fromField))) {
1261
+ return "$".concat(toField).concat(value.slice(fromField.length + 1));
1262
+ }
1263
+ return value;
1264
+ }
1265
+ return value;
1266
+ };
1267
+ return replacer(pipeline);
1268
+ }
982
1269
  function normalizeMongoQuery(query) {
983
1270
  var normalized = query && typeof query === 'object' ? query : {};
984
1271
  if (containsForbiddenMongoOperators(normalized)) {
@@ -1640,6 +1927,10 @@ function sanitizeAssistantResponse(value) {
1640
1927
  }
1641
1928
  var withoutBlocks = raw.replace(/```[\\s\\S]*?```/g, '').replace(/`([^`]+)`/g, '$1').trim();
1642
1929
  var stripEstimated = function (line) { return line.replace(/\bEstimated (human )?hours:\s*.*$/i, '').trimEnd(); };
1930
+ var isTentativeQueryLine = function (line) {
1931
+ var normalized = line.trim().replace(/^[-*•]+\s*/, '');
1932
+ return /^i\s+(can|will|['’]ll|am going to|['’]m going to)\s+(pull|run|query|get|fetch|look up|retrieve|grab)\b/i.test(normalized);
1933
+ };
1643
1934
  var cleanedLines = [];
1644
1935
  withoutBlocks.split('\n').forEach(function (line) {
1645
1936
  var trimmed = line.trim();
@@ -1647,6 +1938,9 @@ function sanitizeAssistantResponse(value) {
1647
1938
  cleanedLines.push(line);
1648
1939
  return;
1649
1940
  }
1941
+ if (isTentativeQueryLine(line)) {
1942
+ return;
1943
+ }
1650
1944
  if (/^work ticket summary:/i.test(trimmed)) {
1651
1945
  return;
1652
1946
  }
@@ -2025,6 +2319,12 @@ function sanitizeConfig(source) {
2025
2319
  max_tokens: normalizeOptionalNumber(source === null || source === void 0 ? void 0 : source.max_tokens)
2026
2320
  };
2027
2321
  }
2322
+ function resolveClientIdFromConfig(explicit) {
2323
+ var _a;
2324
+ var config = ((_a = resolveio_server_app_1.ResolveIOServer.getServerConfig) === null || _a === void 0 ? void 0 : _a.call(resolveio_server_app_1.ResolveIOServer)) || {};
2325
+ return normalizeOptionalString(explicit)
2326
+ || normalizeOptionalString(config['CLIENT_ID'] || config['client_id'] || process.env.CLIENT_ID || '');
2327
+ }
2028
2328
  function ensureConversation(input, mode) {
2029
2329
  return __awaiter(this, void 0, void 0, function () {
2030
2330
  var idConversation, existing, now, doc, result;
@@ -2043,7 +2343,7 @@ function ensureConversation(input, mode) {
2043
2343
  case 2:
2044
2344
  now = new Date();
2045
2345
  doc = {
2046
- id_client: normalizeOptionalString(input.id_client),
2346
+ id_client: resolveClientIdFromConfig(input.id_client),
2047
2347
  id_app: normalizeOptionalString(input.id_app),
2048
2348
  title: 'New Conversation',
2049
2349
  mode: mode,
@@ -2129,7 +2429,9 @@ function normalizeHistoryLimit(value) {
2129
2429
  return Math.min(Math.max((0, common_1.round)(parsed), 0), 30);
2130
2430
  }
2131
2431
  function resolveClientId(conversation, inputClientId) {
2132
- return normalizeOptionalString(inputClientId) || normalizeOptionalString(conversation === null || conversation === void 0 ? void 0 : conversation.id_client);
2432
+ return normalizeOptionalString(inputClientId)
2433
+ || normalizeOptionalString(conversation === null || conversation === void 0 ? void 0 : conversation.id_client)
2434
+ || resolveClientIdFromConfig();
2133
2435
  }
2134
2436
  function estimateUsage(messages, responseText, model) {
2135
2437
  var inputTokens = (0, tokenizer_1.countChatTokens)(messages, model);