@memberjunction/server 5.24.0 → 5.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/skip-sdk.d.ts +12 -0
- package/dist/agents/skip-sdk.d.ts.map +1 -1
- package/dist/agents/skip-sdk.js +70 -1
- package/dist/agents/skip-sdk.js.map +1 -1
- package/dist/generated/generated.d.ts +492 -0
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +2731 -0
- package/dist/generated/generated.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/resolvers/ArtifactFileResolver.d.ts +15 -0
- package/dist/resolvers/ArtifactFileResolver.d.ts.map +1 -0
- package/dist/resolvers/ArtifactFileResolver.js +74 -0
- package/dist/resolvers/ArtifactFileResolver.js.map +1 -0
- package/dist/resolvers/AutotagPipelineResolver.d.ts +13 -0
- package/dist/resolvers/AutotagPipelineResolver.d.ts.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.js +103 -3
- package/dist/resolvers/AutotagPipelineResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +12 -32
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/GeoResolver.d.ts +58 -0
- package/dist/resolvers/GeoResolver.d.ts.map +1 -0
- package/dist/resolvers/GeoResolver.js +302 -0
- package/dist/resolvers/GeoResolver.js.map +1 -0
- package/dist/resolvers/RunAIAgentResolver.d.ts +13 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +115 -20
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeResolver.d.ts +21 -80
- package/dist/resolvers/SearchKnowledgeResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchKnowledgeResolver.js +129 -604
- package/dist/resolvers/SearchKnowledgeResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.d.ts +19 -0
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.d.ts.map +1 -0
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.js +149 -0
- package/dist/resolvers/SearchKnowledgeSystemUserResolver.js.map +1 -0
- package/package.json +63 -63
- package/src/__tests__/search-knowledge-tags.test.ts +177 -337
- package/src/__tests__/skip-sdk-organic-keys.test.ts +274 -0
- package/src/agents/skip-sdk.ts +83 -2
- package/src/generated/generated.ts +1884 -1
- package/src/index.ts +2 -0
- package/src/resolvers/ArtifactFileResolver.ts +71 -0
- package/src/resolvers/AutotagPipelineResolver.ts +118 -4
- package/src/resolvers/FileResolver.ts +12 -41
- package/src/resolvers/GeoResolver.ts +258 -0
- package/src/resolvers/RunAIAgentResolver.ts +137 -23
- package/src/resolvers/SearchKnowledgeResolver.ts +114 -715
- package/src/resolvers/SearchKnowledgeSystemUserResolver.ts +138 -0
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, PubSub, PubSubEngine, Subscription, Root, ResolverFilterData, ID, Int } from 'type-graphql';
|
|
2
2
|
import { AppContext, UserPayload } from '../types.js';
|
|
3
|
-
import { DatabaseProviderBase, LogError, LogStatus, Metadata, RunView, UserInfo } from '@memberjunction/core';
|
|
4
|
-
import { MJConversationDetailEntity, MJConversationDetailAttachmentEntity, MJAIAgentRequestEntity } from '@memberjunction/core-entities';
|
|
3
|
+
import { DatabaseProviderBase, LogError, LogStatus, Metadata, RunView, UserInfo, IMetadataProvider } from '@memberjunction/core';
|
|
4
|
+
import { MJConversationDetailEntity, MJConversationDetailAttachmentEntity, MJConversationDetailArtifactEntity, MJArtifactVersionEntity, MJAIAgentRequestEntity } from '@memberjunction/core-entities';
|
|
5
5
|
import { AgentRunner } from '@memberjunction/ai-agents';
|
|
6
6
|
import { MJAIAgentEntityExtended, MJAIAgentRunEntityExtended, ExecuteAgentResult, ConversationUtility, AttachmentData } from '@memberjunction/ai-core-plus';
|
|
7
7
|
import { AIEngine } from '@memberjunction/aiengine';
|
|
8
|
-
import { ChatMessage } from '@memberjunction/ai';
|
|
8
|
+
import { ChatMessage, ChatMessageContent } from '@memberjunction/ai';
|
|
9
9
|
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
10
10
|
import { PUSH_STATUS_UPDATES_TOPIC } from '../generic/PushStatusResolver.js';
|
|
11
11
|
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
|
|
12
12
|
import { GetReadWriteProvider } from '../util.js';
|
|
13
13
|
import { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
|
|
14
|
-
import {
|
|
14
|
+
import { GetAttachmentService } from '@memberjunction/aiengine';
|
|
15
15
|
import { NotificationEngine } from '@memberjunction/notifications';
|
|
16
16
|
|
|
17
17
|
@ObjectType()
|
|
@@ -453,7 +453,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
453
453
|
|
|
454
454
|
if (lastRunId && result.agentRun?.ID) {
|
|
455
455
|
postExecutionOps.push(
|
|
456
|
-
this.syncFeedbackRequestFromConversation(lastRunId, result.agentRun.ID, userMessage, currentUser)
|
|
456
|
+
this.syncFeedbackRequestFromConversation(lastRunId, result.agentRun.ID, userMessage, currentUser, p)
|
|
457
457
|
);
|
|
458
458
|
}
|
|
459
459
|
|
|
@@ -797,10 +797,11 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
797
797
|
lastRunId: string,
|
|
798
798
|
newRunId: string,
|
|
799
799
|
userMessage: string | undefined,
|
|
800
|
-
contextUser: UserInfo
|
|
800
|
+
contextUser: UserInfo,
|
|
801
|
+
provider: IMetadataProvider
|
|
801
802
|
): Promise<void> {
|
|
802
803
|
try {
|
|
803
|
-
const rv =
|
|
804
|
+
const rv = RunView.FromMetadataProvider(provider);
|
|
804
805
|
const result = await rv.RunView<MJAIAgentRequestEntity>({
|
|
805
806
|
EntityName: 'MJ: AI Agent Requests',
|
|
806
807
|
ExtraFilter: `OriginatingAgentRunID='${lastRunId}' AND Status='Requested'`,
|
|
@@ -939,8 +940,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
939
940
|
// times: once in loadConversationHistoryWithAttachments (just to get conversationId),
|
|
940
941
|
// once in AgentRunner (same reason), and once in createCompletionNotification. Now we
|
|
941
942
|
// load it a single time and thread conversationId through the call chain.
|
|
942
|
-
const
|
|
943
|
-
const currentDetail = await md.GetEntityObject<MJConversationDetailEntity>(
|
|
943
|
+
const currentDetail = await p.GetEntityObject<MJConversationDetailEntity>(
|
|
944
944
|
'MJ: Conversation Details',
|
|
945
945
|
currentUser
|
|
946
946
|
);
|
|
@@ -953,7 +953,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
953
953
|
const messages = await this.loadConversationHistoryWithAttachments(
|
|
954
954
|
conversationId,
|
|
955
955
|
currentUser,
|
|
956
|
-
maxHistoryMessages || 20
|
|
956
|
+
maxHistoryMessages || 20,
|
|
957
|
+
p
|
|
957
958
|
);
|
|
958
959
|
|
|
959
960
|
// Convert to JSON string for the existing executeAIAgent method
|
|
@@ -1031,8 +1032,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1031
1032
|
throw new Error('Unable to determine current user');
|
|
1032
1033
|
}
|
|
1033
1034
|
|
|
1034
|
-
const
|
|
1035
|
-
const request = await
|
|
1035
|
+
const p = GetReadWriteProvider(providers);
|
|
1036
|
+
const request = await p.GetEntityObject<MJAIAgentRequestEntity>(
|
|
1036
1037
|
'MJ: AI Agent Requests',
|
|
1037
1038
|
currentUser
|
|
1038
1039
|
);
|
|
@@ -1096,7 +1097,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1096
1097
|
async ReassignAgentRequest(
|
|
1097
1098
|
@Arg('requestId') requestId: string,
|
|
1098
1099
|
@Arg('newUserID') newUserID: string,
|
|
1099
|
-
@Ctx() { userPayload }: AppContext,
|
|
1100
|
+
@Ctx() { userPayload, providers }: AppContext,
|
|
1100
1101
|
@Arg('note', { nullable: true }) note?: string
|
|
1101
1102
|
): Promise<AIAgentRunResult> {
|
|
1102
1103
|
const startTime = Date.now();
|
|
@@ -1106,8 +1107,8 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1106
1107
|
throw new Error('Unable to determine current user');
|
|
1107
1108
|
}
|
|
1108
1109
|
|
|
1109
|
-
const
|
|
1110
|
-
const request = await
|
|
1110
|
+
const p = GetReadWriteProvider(providers);
|
|
1111
|
+
const request = await p.GetEntityObject<MJAIAgentRequestEntity>(
|
|
1111
1112
|
'MJ: AI Agent Requests',
|
|
1112
1113
|
currentUser
|
|
1113
1114
|
);
|
|
@@ -1262,10 +1263,11 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1262
1263
|
private async loadConversationHistoryWithAttachments(
|
|
1263
1264
|
conversationId: string,
|
|
1264
1265
|
contextUser: UserInfo,
|
|
1265
|
-
maxMessages: number
|
|
1266
|
+
maxMessages: number,
|
|
1267
|
+
provider: IMetadataProvider
|
|
1266
1268
|
): Promise<ChatMessage[]> {
|
|
1267
|
-
const rv =
|
|
1268
|
-
const attachmentService =
|
|
1269
|
+
const rv = RunView.FromMetadataProvider(provider);
|
|
1270
|
+
const attachmentService = GetAttachmentService();
|
|
1269
1271
|
|
|
1270
1272
|
// Load recent conversation details (messages) for this conversation.
|
|
1271
1273
|
// Only fetch the three fields we actually use — ID for attachment lookups,
|
|
@@ -1290,9 +1292,12 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1290
1292
|
const messageIds = details.map(d => d.ID);
|
|
1291
1293
|
|
|
1292
1294
|
// Batch load all attachments for these messages
|
|
1293
|
-
const attachmentsByDetailId = await attachmentService.
|
|
1295
|
+
const attachmentsByDetailId = await attachmentService.GetAttachmentsBatch(messageIds, contextUser, provider);
|
|
1296
|
+
|
|
1297
|
+
// Batch load input artifacts for these messages
|
|
1298
|
+
const inputArtifactsByDetailId = await this.loadInputArtifactsBatch(messageIds, contextUser, provider);
|
|
1294
1299
|
|
|
1295
|
-
// Build ChatMessage array with attachments
|
|
1300
|
+
// Build ChatMessage array with attachments and input artifacts
|
|
1296
1301
|
const messages: ChatMessage[] = [];
|
|
1297
1302
|
|
|
1298
1303
|
for (const detail of details) {
|
|
@@ -1301,7 +1306,7 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1301
1306
|
|
|
1302
1307
|
// Get attachment data with content URLs (handles both inline and FileID storage)
|
|
1303
1308
|
const attachmentDataPromises = attachments.map(att =>
|
|
1304
|
-
attachmentService.
|
|
1309
|
+
attachmentService.GetAttachmentData(att, contextUser, provider)
|
|
1305
1310
|
);
|
|
1306
1311
|
const attachmentDataResults = await Promise.all(attachmentDataPromises);
|
|
1307
1312
|
|
|
@@ -1319,12 +1324,38 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1319
1324
|
content: result.contentUrl
|
|
1320
1325
|
}));
|
|
1321
1326
|
|
|
1327
|
+
// Get input artifacts for this message and convert to AttachmentData
|
|
1328
|
+
const inputArtifacts = inputArtifactsByDetailId.get(detail.ID) || [];
|
|
1329
|
+
for (const artifactVersion of inputArtifacts) {
|
|
1330
|
+
if (artifactVersion.ContentMode === 'File' && artifactVersion.FileID) {
|
|
1331
|
+
// File-backed artifact — download content and treat like a document attachment
|
|
1332
|
+
const fileContent = await this.downloadArtifactFileContent(artifactVersion, contextUser, provider);
|
|
1333
|
+
if (fileContent) {
|
|
1334
|
+
validAttachments.push({
|
|
1335
|
+
type: ConversationUtility.GetAttachmentTypeFromMime(artifactVersion.MimeType || ''),
|
|
1336
|
+
mimeType: artifactVersion.MimeType || 'application/octet-stream',
|
|
1337
|
+
fileName: artifactVersion.FileName || artifactVersion.Name || undefined,
|
|
1338
|
+
sizeBytes: artifactVersion.ContentSizeBytes || undefined,
|
|
1339
|
+
content: fileContent
|
|
1340
|
+
});
|
|
1341
|
+
}
|
|
1342
|
+
} else if (artifactVersion.Content) {
|
|
1343
|
+
// Text artifact — include content directly as a text attachment
|
|
1344
|
+
validAttachments.push({
|
|
1345
|
+
type: 'Document' as AttachmentData['type'],
|
|
1346
|
+
mimeType: 'text/plain',
|
|
1347
|
+
fileName: artifactVersion.Name || 'artifact.txt',
|
|
1348
|
+
content: `[Artifact: ${artifactVersion.Name || 'Untitled'}]\n\n${artifactVersion.Content}`
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1322
1353
|
// Build message content (with or without attachments)
|
|
1323
|
-
let content:
|
|
1354
|
+
let content: ChatMessageContent;
|
|
1324
1355
|
|
|
1325
1356
|
if (validAttachments.length > 0) {
|
|
1326
1357
|
// Use ConversationUtility to build multimodal content blocks
|
|
1327
|
-
content = ConversationUtility.BuildChatMessageContent(
|
|
1358
|
+
content = await ConversationUtility.BuildChatMessageContent(
|
|
1328
1359
|
detail.Message || '',
|
|
1329
1360
|
validAttachments
|
|
1330
1361
|
);
|
|
@@ -1352,4 +1383,87 @@ export class RunAIAgentResolver extends ResolverBase {
|
|
|
1352
1383
|
return 'user'; // Default to user
|
|
1353
1384
|
}
|
|
1354
1385
|
|
|
1386
|
+
/**
|
|
1387
|
+
* Batch load input artifact versions for conversation details.
|
|
1388
|
+
* Returns a map of ConversationDetailID -> ArtifactVersion[]
|
|
1389
|
+
*/
|
|
1390
|
+
private async loadInputArtifactsBatch(
|
|
1391
|
+
conversationDetailIds: string[],
|
|
1392
|
+
contextUser: UserInfo,
|
|
1393
|
+
provider: IMetadataProvider
|
|
1394
|
+
): Promise<Map<string, MJArtifactVersionEntity[]>> {
|
|
1395
|
+
const map = new Map<string, MJArtifactVersionEntity[]>();
|
|
1396
|
+
if (conversationDetailIds.length === 0) return map;
|
|
1397
|
+
|
|
1398
|
+
const rv = RunView.FromMetadataProvider(provider);
|
|
1399
|
+
const idList = conversationDetailIds.map(id => `'${id}'`).join(',');
|
|
1400
|
+
|
|
1401
|
+
// Load ConversationDetailArtifact links with Direction='Input'
|
|
1402
|
+
const linksResult = await rv.RunView<MJConversationDetailArtifactEntity>({
|
|
1403
|
+
EntityName: 'MJ: Conversation Detail Artifacts',
|
|
1404
|
+
ExtraFilter: `ConversationDetailID IN (${idList}) AND Direction = 'Input'`,
|
|
1405
|
+
ResultType: 'entity_object'
|
|
1406
|
+
}, contextUser);
|
|
1407
|
+
|
|
1408
|
+
if (!linksResult.Success || !linksResult.Results || linksResult.Results.length === 0) {
|
|
1409
|
+
return map;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
// Load the referenced artifact versions
|
|
1413
|
+
const versionIds = linksResult.Results.map(l => `'${l.ArtifactVersionID}'`).join(',');
|
|
1414
|
+
const versionsResult = await rv.RunView<MJArtifactVersionEntity>({
|
|
1415
|
+
EntityName: 'MJ: Artifact Versions',
|
|
1416
|
+
ExtraFilter: `ID IN (${versionIds})`,
|
|
1417
|
+
ResultType: 'entity_object'
|
|
1418
|
+
}, contextUser);
|
|
1419
|
+
|
|
1420
|
+
if (!versionsResult.Success || !versionsResult.Results) return map;
|
|
1421
|
+
|
|
1422
|
+
// Build a lookup of version ID -> version entity
|
|
1423
|
+
const versionMap = new Map<string, MJArtifactVersionEntity>();
|
|
1424
|
+
for (const v of versionsResult.Results) {
|
|
1425
|
+
versionMap.set(v.ID, v);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// Group by conversation detail ID
|
|
1429
|
+
for (const link of linksResult.Results) {
|
|
1430
|
+
const version = versionMap.get(link.ArtifactVersionID);
|
|
1431
|
+
if (version) {
|
|
1432
|
+
const existing = map.get(link.ConversationDetailID) || [];
|
|
1433
|
+
existing.push(version);
|
|
1434
|
+
map.set(link.ConversationDetailID, existing);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
return map;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
/**
|
|
1442
|
+
* Download file content from an artifact version's FileID.
|
|
1443
|
+
* Returns base64 data URL for extraction pipeline compatibility.
|
|
1444
|
+
* Uses the same downloadFileContent path as ConversationAttachmentService
|
|
1445
|
+
* to avoid Box driver path resolution issues.
|
|
1446
|
+
*/
|
|
1447
|
+
private async downloadArtifactFileContent(
|
|
1448
|
+
artifactVersion: MJArtifactVersionEntity,
|
|
1449
|
+
contextUser: UserInfo,
|
|
1450
|
+
provider: IMetadataProvider
|
|
1451
|
+
): Promise<string | null> {
|
|
1452
|
+
if (!artifactVersion.FileID) return null;
|
|
1453
|
+
|
|
1454
|
+
try {
|
|
1455
|
+
// Use the attachment service's downloadFileContent which uses GetObject directly
|
|
1456
|
+
const attachmentService = GetAttachmentService();
|
|
1457
|
+
const buffer = await attachmentService.DownloadFileContent(artifactVersion.FileID, contextUser, provider);
|
|
1458
|
+
if (!buffer) return null;
|
|
1459
|
+
|
|
1460
|
+
const base64 = buffer.toString('base64');
|
|
1461
|
+
const mimeType = artifactVersion.MimeType || 'application/octet-stream';
|
|
1462
|
+
return `data:${mimeType};base64,${base64}`;
|
|
1463
|
+
} catch (err) {
|
|
1464
|
+
LogError(`Failed to download artifact file ${artifactVersion.FileID}: ${err}`);
|
|
1465
|
+
return null;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1355
1469
|
}
|