@memberjunction/server 2.47.0 → 2.49.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/apolloServer/TransactionPlugin.js +7 -7
- package/dist/apolloServer/TransactionPlugin.js.map +1 -1
- package/dist/auth/index.d.ts +3 -3
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/newUsers.d.ts.map +1 -1
- package/dist/auth/newUsers.js +2 -13
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/context.d.ts +3 -3
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js.map +1 -1
- package/dist/generated/generated.d.ts +686 -329
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +5786 -3286
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +17 -17
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +7 -5
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +12 -4
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -14
- package/dist/index.js.map +1 -1
- package/dist/orm.d.ts +3 -3
- package/dist/orm.d.ts.map +1 -1
- package/dist/orm.js +14 -15
- package/dist/orm.js.map +1 -1
- package/dist/resolvers/AskSkipResolver.d.ts +19 -19
- package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
- package/dist/resolvers/AskSkipResolver.js +17 -12
- package/dist/resolvers/AskSkipResolver.js.map +1 -1
- package/dist/resolvers/EntityResolver.d.ts +2 -1
- package/dist/resolvers/EntityResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityResolver.js +6 -3
- package/dist/resolvers/EntityResolver.js.map +1 -1
- package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
- package/dist/resolvers/FileCategoryResolver.js +10 -2
- package/dist/resolvers/FileCategoryResolver.js.map +1 -1
- package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
- package/dist/resolvers/GetDataResolver.js +4 -2
- package/dist/resolvers/GetDataResolver.js.map +1 -1
- package/dist/resolvers/ReportResolver.d.ts.map +1 -1
- package/dist/resolvers/ReportResolver.js +5 -3
- package/dist/resolvers/ReportResolver.js.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.d.ts +19 -0
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -0
- package/dist/resolvers/RunAIAgentResolver.js +194 -0
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -0
- package/dist/resolvers/UserFavoriteResolver.d.ts +2 -2
- package/dist/resolvers/UserViewResolver.d.ts +4 -4
- package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
- package/dist/resolvers/UserViewResolver.js.map +1 -1
- package/dist/types.d.ts +6 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +10 -3
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +22 -3
- package/dist/util.js.map +1 -1
- package/package.json +24 -25
- package/src/apolloServer/TransactionPlugin.ts +8 -8
- package/src/auth/index.ts +4 -4
- package/src/auth/newUsers.ts +0 -1
- package/src/context.ts +2 -2
- package/src/generated/generated.ts +4759 -3021
- package/src/generic/ResolverBase.ts +23 -22
- package/src/generic/RunViewResolver.ts +12 -4
- package/src/index.ts +18 -15
- package/src/orm.ts +18 -17
- package/src/resolvers/AskSkipResolver.ts +36 -32
- package/src/resolvers/EntityResolver.ts +5 -2
- package/src/resolvers/FileCategoryResolver.ts +9 -2
- package/src/resolvers/GetDataResolver.ts +4 -2
- package/src/resolvers/ReportResolver.ts +5 -3
- package/src/resolvers/RunAIAgentResolver.ts +174 -0
- package/src/resolvers/UserViewResolver.ts +0 -1
- package/src/types.ts +8 -8
- package/src/util.ts +31 -6
|
@@ -6,6 +6,7 @@ import { SkipAPIAnalysisCompleteResponse } from '@memberjunction/skip-types';
|
|
|
6
6
|
import { DataContext } from '@memberjunction/data-context';
|
|
7
7
|
import { UserCache } from '@memberjunction/sqlserver-dataprovider';
|
|
8
8
|
import { z } from 'zod';
|
|
9
|
+
import mssql from 'mssql';
|
|
9
10
|
|
|
10
11
|
@ObjectType()
|
|
11
12
|
export class RunReportResultType {
|
|
@@ -90,9 +91,10 @@ export class ReportResolverExtended {
|
|
|
90
91
|
WHERE
|
|
91
92
|
cd.ID='${ConversationDetailID}'`;
|
|
92
93
|
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
const request = new mssql.Request(dataSource);
|
|
95
|
+
const result = await request.query(sql);
|
|
96
|
+
if (!result || !result.recordset || result.recordset.length === 0) throw new Error('Unable to retrieve converation details');
|
|
97
|
+
const skipData = <SkipAPIAnalysisCompleteResponse>JSON.parse(result.recordset[0].Message);
|
|
96
98
|
|
|
97
99
|
const report = await md.GetEntityObject<ReportEntity>('Reports', u);
|
|
98
100
|
report.NewRecord();
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { Resolver, Mutation, Arg, Ctx, ObjectType, Field } from 'type-graphql';
|
|
2
|
+
import { UserPayload } from '../types.js';
|
|
3
|
+
import { LogError, LogStatus, Metadata } from '@memberjunction/core';
|
|
4
|
+
import { AIAgentEntity } from '@memberjunction/core-entities';
|
|
5
|
+
import { AgentRunner } from '@memberjunction/ai-agents';
|
|
6
|
+
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
7
|
+
|
|
8
|
+
@ObjectType()
|
|
9
|
+
export class AIAgentRunResult {
|
|
10
|
+
@Field()
|
|
11
|
+
success: boolean;
|
|
12
|
+
|
|
13
|
+
@Field({ nullable: true })
|
|
14
|
+
output?: string;
|
|
15
|
+
|
|
16
|
+
@Field({ nullable: true })
|
|
17
|
+
parsedResult?: string;
|
|
18
|
+
|
|
19
|
+
@Field({ nullable: true })
|
|
20
|
+
error?: string;
|
|
21
|
+
|
|
22
|
+
@Field({ nullable: true })
|
|
23
|
+
executionTimeMs?: number;
|
|
24
|
+
|
|
25
|
+
@Field({ nullable: true })
|
|
26
|
+
tokensUsed?: number;
|
|
27
|
+
|
|
28
|
+
@Field({ nullable: true })
|
|
29
|
+
agentRunId?: string;
|
|
30
|
+
|
|
31
|
+
@Field({ nullable: true })
|
|
32
|
+
rawResult?: string;
|
|
33
|
+
|
|
34
|
+
@Field({ nullable: true })
|
|
35
|
+
nextStep?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Resolver()
|
|
39
|
+
export class RunAIAgentResolver extends ResolverBase {
|
|
40
|
+
@Mutation(() => AIAgentRunResult)
|
|
41
|
+
async RunAIAgent(
|
|
42
|
+
@Arg('agentId') agentId: string,
|
|
43
|
+
@Ctx() { userPayload }: { userPayload: UserPayload },
|
|
44
|
+
@Arg('messages') messagesJson: string,
|
|
45
|
+
@Arg('data', { nullable: true }) data?: string,
|
|
46
|
+
@Arg('templateData', { nullable: true }) templateData?: string
|
|
47
|
+
): Promise<AIAgentRunResult> {
|
|
48
|
+
const startTime = Date.now();
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
LogStatus(`=== RUNNING AI AGENT FOR ID: ${agentId} ===`);
|
|
52
|
+
|
|
53
|
+
// Parse messages (required)
|
|
54
|
+
let parsedMessages;
|
|
55
|
+
try {
|
|
56
|
+
parsedMessages = JSON.parse(messagesJson);
|
|
57
|
+
if (!Array.isArray(parsedMessages)) {
|
|
58
|
+
throw new Error('Messages must be an array');
|
|
59
|
+
}
|
|
60
|
+
} catch (parseError) {
|
|
61
|
+
return {
|
|
62
|
+
success: false,
|
|
63
|
+
error: `Invalid JSON in messages: ${(parseError as Error).message}`,
|
|
64
|
+
executionTimeMs: Date.now() - startTime
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Parse data contexts (JSON strings)
|
|
69
|
+
let parsedData = {};
|
|
70
|
+
let parsedTemplateData = {};
|
|
71
|
+
|
|
72
|
+
if (data) {
|
|
73
|
+
try {
|
|
74
|
+
parsedData = JSON.parse(data);
|
|
75
|
+
} catch (parseError) {
|
|
76
|
+
return {
|
|
77
|
+
success: false,
|
|
78
|
+
error: `Invalid JSON in data: ${(parseError as Error).message}`,
|
|
79
|
+
executionTimeMs: Date.now() - startTime
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (templateData) {
|
|
85
|
+
try {
|
|
86
|
+
parsedTemplateData = JSON.parse(templateData);
|
|
87
|
+
} catch (parseError) {
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
error: `Invalid JSON in template data: ${(parseError as Error).message}`,
|
|
91
|
+
executionTimeMs: Date.now() - startTime
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Get current user from payload
|
|
97
|
+
const currentUser = this.GetUserFromPayload(userPayload);
|
|
98
|
+
if (!currentUser) {
|
|
99
|
+
return {
|
|
100
|
+
success: false,
|
|
101
|
+
error: 'Unable to determine current user',
|
|
102
|
+
executionTimeMs: Date.now() - startTime
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const md = new Metadata();
|
|
107
|
+
|
|
108
|
+
// Load the AI agent entity
|
|
109
|
+
const agentEntity = await md.GetEntityObject<AIAgentEntity>('AI Agents', currentUser);
|
|
110
|
+
await agentEntity.Load(agentId);
|
|
111
|
+
|
|
112
|
+
if (!agentEntity.IsSaved) {
|
|
113
|
+
return {
|
|
114
|
+
success: false,
|
|
115
|
+
error: `AI Agent with ID ${agentId} not found`,
|
|
116
|
+
executionTimeMs: Date.now() - startTime
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Check if agent is active
|
|
121
|
+
if (agentEntity.Status !== 'Active') {
|
|
122
|
+
return {
|
|
123
|
+
success: false,
|
|
124
|
+
error: `AI Agent "${agentEntity.Name}" is not active (Status: ${agentEntity.Status})`,
|
|
125
|
+
executionTimeMs: Date.now() - startTime
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Create AI agent runner and execute
|
|
130
|
+
const agentRunner = new AgentRunner();
|
|
131
|
+
|
|
132
|
+
// Execute the agent with the parsed messages and optional data
|
|
133
|
+
const result = await agentRunner.RunAgent({
|
|
134
|
+
agent: agentEntity,
|
|
135
|
+
conversationMessages: parsedMessages,
|
|
136
|
+
contextUser: currentUser,
|
|
137
|
+
...(Object.keys(parsedData).length > 0 && { data: parsedData }),
|
|
138
|
+
...(Object.keys(parsedTemplateData).length > 0 && { templateData: parsedTemplateData })
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const executionTime = Date.now() - startTime;
|
|
142
|
+
|
|
143
|
+
if (result.nextStep !== 'failed') {
|
|
144
|
+
LogStatus(`=== AI AGENT RUN COMPLETED FOR: ${agentEntity.Name} (${executionTime}ms) ===`);
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
success: true,
|
|
148
|
+
output: result.rawResult,
|
|
149
|
+
parsedResult: typeof result.returnValue === 'string' ? result.returnValue : JSON.stringify(result.returnValue),
|
|
150
|
+
rawResult: result.rawResult,
|
|
151
|
+
executionTimeMs: executionTime,
|
|
152
|
+
nextStep: result.nextStep
|
|
153
|
+
};
|
|
154
|
+
} else {
|
|
155
|
+
LogError(`AI Agent run failed for ${agentEntity.Name}: ${result.errorMessage}`);
|
|
156
|
+
return {
|
|
157
|
+
success: false,
|
|
158
|
+
error: result.errorMessage,
|
|
159
|
+
executionTimeMs: executionTime,
|
|
160
|
+
nextStep: result.nextStep
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
} catch (error) {
|
|
165
|
+
const executionTime = Date.now() - startTime;
|
|
166
|
+
LogError(`AI Agent run failed:`, undefined, error);
|
|
167
|
+
return {
|
|
168
|
+
success: false,
|
|
169
|
+
error: (error as Error).message || 'Unknown error occurred',
|
|
170
|
+
executionTimeMs: executionTime
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { Metadata } from '@memberjunction/core';
|
|
3
3
|
import { AppContext, Arg, Ctx, Int, Query, Resolver, UserPayload } from '@memberjunction/server';
|
|
4
|
-
import { DataSource } from 'typeorm';
|
|
5
4
|
import { UserView_, UserViewResolverBase } from '../generated/generated.js';
|
|
6
5
|
import { UserResolver } from './UserResolver.js';
|
|
7
6
|
import { UserViewEntity, UserViewEntityExtended } from '@memberjunction/core-entities';
|
package/src/types.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { UserInfo } from '@memberjunction/core';
|
|
|
2
2
|
import { UserViewEntity } from '@memberjunction/core-entities';
|
|
3
3
|
import { GraphQLSchema } from 'graphql';
|
|
4
4
|
import { PubSubEngine } from 'type-graphql';
|
|
5
|
-
import
|
|
5
|
+
import sql from 'mssql';
|
|
6
6
|
import { getSystemUser } from './auth/index.js';
|
|
7
7
|
import { MJEvent, MJEventType, MJGlobal } from '@memberjunction/global';
|
|
8
8
|
|
|
@@ -19,19 +19,19 @@ export type UserPayload = {
|
|
|
19
19
|
*/
|
|
20
20
|
export type AppContext = {
|
|
21
21
|
/**
|
|
22
|
-
* The default and backwards compatible
|
|
22
|
+
* The default and backwards compatible connection pool.
|
|
23
23
|
*/
|
|
24
|
-
dataSource:
|
|
24
|
+
dataSource: sql.ConnectionPool;
|
|
25
25
|
userPayload: UserPayload;
|
|
26
|
-
queryRunner?:
|
|
26
|
+
queryRunner?: sql.Request;
|
|
27
27
|
/**
|
|
28
|
-
* Array of
|
|
28
|
+
* Array of connection pools that have additional information about their intended use e.g. Admin, Read-Write, Read-Only.
|
|
29
29
|
*/
|
|
30
30
|
dataSources: DataSourceInfo[];
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
export class DataSourceInfo {
|
|
34
|
-
dataSource:
|
|
34
|
+
dataSource: sql.ConnectionPool;
|
|
35
35
|
host: string;
|
|
36
36
|
port: number;
|
|
37
37
|
instance?: string;
|
|
@@ -39,7 +39,7 @@ export class DataSourceInfo {
|
|
|
39
39
|
userName: string;
|
|
40
40
|
type: "Admin" | "Read-Write" | "Read-Only" | "Other";
|
|
41
41
|
|
|
42
|
-
constructor(init: {dataSource:
|
|
42
|
+
constructor(init: {dataSource: sql.ConnectionPool, type: "Admin" | "Read-Write" | "Read-Only" | "Other", host: string, port: number, database: string, userName: string} ) {
|
|
43
43
|
this.dataSource = init.dataSource;
|
|
44
44
|
this.host = init.host;
|
|
45
45
|
this.port = init.port;
|
|
@@ -56,7 +56,7 @@ export type DirectiveBuilder = {
|
|
|
56
56
|
|
|
57
57
|
export type RunViewGenericParams = {
|
|
58
58
|
viewInfo: UserViewEntity;
|
|
59
|
-
dataSource:
|
|
59
|
+
dataSource: sql.ConnectionPool;
|
|
60
60
|
extraFilter: string;
|
|
61
61
|
orderBy: string;
|
|
62
62
|
userSearchString: string;
|
package/src/util.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { promisify } from 'util';
|
|
|
5
5
|
import { URL } from 'url';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import { DataSourceInfo } from './types';
|
|
8
|
-
import
|
|
8
|
+
import sql from 'mssql';
|
|
9
9
|
|
|
10
10
|
const gzip = promisify(gzipCallback);
|
|
11
11
|
|
|
@@ -120,17 +120,17 @@ export async function sendPostRequest(url: string, payload: any, useCompression:
|
|
|
120
120
|
* @param options
|
|
121
121
|
* @returns
|
|
122
122
|
*/
|
|
123
|
-
export function GetReadOnlyDataSource(dataSources: DataSourceInfo[], options?: {allowFallbackToReadWrite: boolean}):
|
|
123
|
+
export function GetReadOnlyDataSource(dataSources: DataSourceInfo[], options?: {allowFallbackToReadWrite: boolean}): sql.ConnectionPool & { query: (sql: string, params?: any) => Promise<any[]> } {
|
|
124
124
|
const readOnlyDataSource = dataSources.find((ds) => ds.type === 'Read-Only');
|
|
125
125
|
if (readOnlyDataSource) {
|
|
126
|
-
return readOnlyDataSource.dataSource;
|
|
126
|
+
return extendConnectionPoolWithQuery(readOnlyDataSource.dataSource);
|
|
127
127
|
}
|
|
128
128
|
else if (!options || options.allowFallbackToReadWrite) {
|
|
129
129
|
// default behavior for backward compatibility prior to MJ 2.22.3 where we introduced this functionality was to have a single
|
|
130
130
|
// connection, so for back-compatability, if we don't have a read-only data source, we'll fall back to the read-write data source
|
|
131
131
|
const readWriteDataSource = dataSources.find((ds) => ds.type === 'Read-Write');
|
|
132
132
|
if (readWriteDataSource) {
|
|
133
|
-
return readWriteDataSource.dataSource;
|
|
133
|
+
return extendConnectionPoolWithQuery(readWriteDataSource.dataSource);
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
throw new Error('No suitable data source found');
|
|
@@ -141,10 +141,35 @@ export async function sendPostRequest(url: string, payload: any, useCompression:
|
|
|
141
141
|
* @param dataSources
|
|
142
142
|
* @returns
|
|
143
143
|
*/
|
|
144
|
-
export function GetReadWriteDataSource(dataSources: DataSourceInfo[]):
|
|
144
|
+
export function GetReadWriteDataSource(dataSources: DataSourceInfo[]): sql.ConnectionPool & { query: (sql: string, params?: any) => Promise<any[]> } {
|
|
145
145
|
const readWriteDataSource = dataSources.find((ds) => ds.type === 'Read-Write');
|
|
146
146
|
if (readWriteDataSource) {
|
|
147
|
-
return readWriteDataSource.dataSource;
|
|
147
|
+
return extendConnectionPoolWithQuery(readWriteDataSource.dataSource);
|
|
148
148
|
}
|
|
149
149
|
throw new Error('No suitable read-write data source found');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Extends a ConnectionPool with a query method that returns results in the format expected by generated code
|
|
154
|
+
* This provides backwards compatibility with code that expects TypeORM-style query results
|
|
155
|
+
*/
|
|
156
|
+
export function extendConnectionPoolWithQuery(pool: sql.ConnectionPool): sql.ConnectionPool & { query: (sql: string, params?: any) => Promise<any[]> } {
|
|
157
|
+
const extendedPool = pool as any;
|
|
158
|
+
extendedPool.query = async (sqlQuery: string, parameters?: any): Promise<any[]> => {
|
|
159
|
+
const request = new sql.Request(pool);
|
|
160
|
+
// Add parameters if provided
|
|
161
|
+
if (parameters) {
|
|
162
|
+
if (Array.isArray(parameters)) {
|
|
163
|
+
parameters.forEach((value, index) => {
|
|
164
|
+
request.input(`p${index}`, value);
|
|
165
|
+
});
|
|
166
|
+
// Replace ? with @p0, @p1, etc. in the query
|
|
167
|
+
let paramIndex = 0;
|
|
168
|
+
sqlQuery = sqlQuery.replace(/\?/g, () => `@p${paramIndex++}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const result = await request.query(sqlQuery);
|
|
172
|
+
return result.recordset || [];
|
|
173
|
+
};
|
|
174
|
+
return extendedPool;
|
|
150
175
|
}
|