@memberjunction/server 5.22.0 → 5.24.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/README.md +35 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -1
- package/dist/generated/generated.d.ts +610 -4
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +17333 -13889
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/resolvers/AutotagPipelineResolver.d.ts +30 -0
- package/dist/resolvers/AutotagPipelineResolver.d.ts.map +1 -0
- package/dist/resolvers/AutotagPipelineResolver.js +231 -0
- package/dist/resolvers/AutotagPipelineResolver.js.map +1 -0
- package/dist/resolvers/ClientToolRequestResolver.d.ts +43 -0
- package/dist/resolvers/ClientToolRequestResolver.d.ts.map +1 -0
- package/dist/resolvers/ClientToolRequestResolver.js +161 -0
- package/dist/resolvers/ClientToolRequestResolver.js.map +1 -0
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts +29 -0
- package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -0
- package/dist/resolvers/FetchEntityVectorsResolver.js +222 -0
- package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -0
- package/dist/resolvers/RunAIAgentResolver.d.ts +21 -0
- package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
- package/dist/resolvers/RunAIAgentResolver.js +75 -33
- package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
- package/dist/resolvers/SearchKnowledgeResolver.d.ts +42 -1
- package/dist/resolvers/SearchKnowledgeResolver.d.ts.map +1 -1
- package/dist/resolvers/SearchKnowledgeResolver.js +239 -13
- package/dist/resolvers/SearchKnowledgeResolver.js.map +1 -1
- package/package.json +63 -63
- package/src/__tests__/search-knowledge-tags.test.ts +415 -0
- package/src/config.ts +11 -0
- package/src/generated/generated.ts +2373 -7
- package/src/generic/RunViewResolver.ts +1 -0
- package/src/index.ts +10 -0
- package/src/resolvers/AutotagPipelineResolver.ts +235 -0
- package/src/resolvers/ClientToolRequestResolver.ts +128 -0
- package/src/resolvers/FetchEntityVectorsResolver.ts +238 -0
- package/src/resolvers/RunAIAgentResolver.ts +97 -56
- package/src/resolvers/SearchKnowledgeResolver.ts +270 -13
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { Resolver, Query, Arg, Ctx, ObjectType, Field, Float, Int } from 'type-graphql';
|
|
14
|
+
import { LogError, LogStatus, RunView } from '@memberjunction/core';
|
|
15
|
+
import { ResolverBase } from '../generic/ResolverBase.js';
|
|
16
|
+
import { GetAIAPIKey } from '@memberjunction/ai';
|
|
17
|
+
import { VectorDBBase } from '@memberjunction/ai-vectordb';
|
|
18
|
+
import { MJGlobal, UUIDsEqual } from '@memberjunction/global';
|
|
19
|
+
/* ───── GraphQL types ───── */
|
|
20
|
+
let EntityVectorItem = class EntityVectorItem {
|
|
21
|
+
};
|
|
22
|
+
__decorate([
|
|
23
|
+
Field(),
|
|
24
|
+
__metadata("design:type", String)
|
|
25
|
+
], EntityVectorItem.prototype, "ID", void 0);
|
|
26
|
+
__decorate([
|
|
27
|
+
Field(() => [Float]),
|
|
28
|
+
__metadata("design:type", Array)
|
|
29
|
+
], EntityVectorItem.prototype, "Values", void 0);
|
|
30
|
+
__decorate([
|
|
31
|
+
Field(() => String),
|
|
32
|
+
__metadata("design:type", String)
|
|
33
|
+
], EntityVectorItem.prototype, "Metadata", void 0);
|
|
34
|
+
EntityVectorItem = __decorate([
|
|
35
|
+
ObjectType()
|
|
36
|
+
], EntityVectorItem);
|
|
37
|
+
export { EntityVectorItem };
|
|
38
|
+
let FetchEntityVectorsResult = class FetchEntityVectorsResult {
|
|
39
|
+
};
|
|
40
|
+
__decorate([
|
|
41
|
+
Field(),
|
|
42
|
+
__metadata("design:type", Boolean)
|
|
43
|
+
], FetchEntityVectorsResult.prototype, "Success", void 0);
|
|
44
|
+
__decorate([
|
|
45
|
+
Field(() => [EntityVectorItem]),
|
|
46
|
+
__metadata("design:type", Array)
|
|
47
|
+
], FetchEntityVectorsResult.prototype, "Results", void 0);
|
|
48
|
+
__decorate([
|
|
49
|
+
Field(),
|
|
50
|
+
__metadata("design:type", Number)
|
|
51
|
+
], FetchEntityVectorsResult.prototype, "TotalCount", void 0);
|
|
52
|
+
__decorate([
|
|
53
|
+
Field(),
|
|
54
|
+
__metadata("design:type", Number)
|
|
55
|
+
], FetchEntityVectorsResult.prototype, "ElapsedMs", void 0);
|
|
56
|
+
__decorate([
|
|
57
|
+
Field({ nullable: true }),
|
|
58
|
+
__metadata("design:type", String)
|
|
59
|
+
], FetchEntityVectorsResult.prototype, "ErrorMessage", void 0);
|
|
60
|
+
FetchEntityVectorsResult = __decorate([
|
|
61
|
+
ObjectType()
|
|
62
|
+
], FetchEntityVectorsResult);
|
|
63
|
+
export { FetchEntityVectorsResult };
|
|
64
|
+
/* ───── Resolver ───── */
|
|
65
|
+
let FetchEntityVectorsResolver = class FetchEntityVectorsResolver extends ResolverBase {
|
|
66
|
+
async FetchEntityVectors(entityDocumentID, maxRecords, filter, { userPayload } = {}) {
|
|
67
|
+
const startTime = Date.now();
|
|
68
|
+
try {
|
|
69
|
+
const currentUser = this.GetUserFromPayload(userPayload);
|
|
70
|
+
if (!currentUser) {
|
|
71
|
+
return this.errorResult('Unable to determine current user', startTime);
|
|
72
|
+
}
|
|
73
|
+
const limit = maxRecords ?? 1000;
|
|
74
|
+
// Step 1: Load the EntityDocument
|
|
75
|
+
const entityDoc = await this.loadEntityDocument(entityDocumentID, currentUser);
|
|
76
|
+
if (!entityDoc) {
|
|
77
|
+
return this.errorResult(`EntityDocument not found: ${entityDocumentID}`, startTime);
|
|
78
|
+
}
|
|
79
|
+
// Step 2: Resolve the VectorIndex
|
|
80
|
+
const vectorIndex = await this.resolveVectorIndex(entityDoc, currentUser);
|
|
81
|
+
if (!vectorIndex) {
|
|
82
|
+
return this.errorResult(`Could not resolve VectorIndex for EntityDocument "${entityDoc.Name}"`, startTime);
|
|
83
|
+
}
|
|
84
|
+
// Step 3: Create VectorDB provider instance
|
|
85
|
+
const vectorDBInstance = await this.createVectorDBInstance(vectorIndex, currentUser);
|
|
86
|
+
if (!vectorDBInstance) {
|
|
87
|
+
return this.errorResult(`Could not create VectorDB provider for index "${vectorIndex.Name}"`, startTime);
|
|
88
|
+
}
|
|
89
|
+
// Step 4: Query with zero vector + Entity metadata filter.
|
|
90
|
+
// Pinecone's list API doesn't support metadata filtering, but query does.
|
|
91
|
+
// A zero vector returns results in arbitrary order (similarity is meaningless),
|
|
92
|
+
// but the metadata filter ensures we only get vectors for this entity.
|
|
93
|
+
const entityName = entityDoc.Entity;
|
|
94
|
+
const dimensions = vectorIndex.Dimensions || 1536; // fall back to common embedding size
|
|
95
|
+
// Use a tiny uniform vector instead of zero — cosine similarity is undefined
|
|
96
|
+
// for a zero vector (division by zero), causing Pinecone to return 0 matches.
|
|
97
|
+
// A uniform vector has equal similarity to all vectors, giving us an unbiased
|
|
98
|
+
// listing that respects the metadata filter.
|
|
99
|
+
const uniformVector = new Array(dimensions).fill(1.0 / Math.sqrt(dimensions));
|
|
100
|
+
const metadataFilter = { Entity: { $eq: entityName } };
|
|
101
|
+
const queryResponse = await vectorDBInstance.QueryIndex({
|
|
102
|
+
id: vectorIndex.Name, // index name (stripped before Pinecone query)
|
|
103
|
+
vector: uniformVector,
|
|
104
|
+
topK: limit,
|
|
105
|
+
includeMetadata: true,
|
|
106
|
+
includeValues: true,
|
|
107
|
+
filter: metadataFilter,
|
|
108
|
+
});
|
|
109
|
+
if (!queryResponse.success || !queryResponse.data) {
|
|
110
|
+
return this.errorResult(`Vector query failed for entity "${entityName}" in index "${vectorIndex.Name}"`, startTime);
|
|
111
|
+
}
|
|
112
|
+
// Step 5: Convert query matches to result format
|
|
113
|
+
const matches = queryResponse.data.matches ?? [];
|
|
114
|
+
const results = matches.map(match => ({
|
|
115
|
+
ID: match.id,
|
|
116
|
+
Values: match.values ?? [],
|
|
117
|
+
Metadata: JSON.stringify(match.metadata ?? {}),
|
|
118
|
+
}));
|
|
119
|
+
LogStatus(`FetchEntityVectors: Queried ${results.length} vectors for entity "${entityName}" in ${Date.now() - startTime}ms`);
|
|
120
|
+
return {
|
|
121
|
+
Success: true,
|
|
122
|
+
Results: results,
|
|
123
|
+
TotalCount: results.length,
|
|
124
|
+
ElapsedMs: Date.now() - startTime,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
129
|
+
LogError(`FetchEntityVectors query failed: ${msg}`);
|
|
130
|
+
return this.errorResult(msg, startTime);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Load EntityDocument by ID */
|
|
134
|
+
async loadEntityDocument(entityDocumentID, contextUser) {
|
|
135
|
+
const rv = new RunView();
|
|
136
|
+
const result = await rv.RunView({
|
|
137
|
+
EntityName: 'MJ: Entity Documents',
|
|
138
|
+
ExtraFilter: `ID='${entityDocumentID}'`,
|
|
139
|
+
ResultType: 'entity_object',
|
|
140
|
+
}, contextUser);
|
|
141
|
+
if (!result.Success || result.Results.length === 0) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
return result.Results[0];
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Resolve the VectorIndex for an EntityDocument.
|
|
148
|
+
* Prefers the explicit VectorIndexID on the EntityDocument; falls back to
|
|
149
|
+
* finding a VectorIndex by matching VectorDatabaseID + EmbeddingModelID.
|
|
150
|
+
*/
|
|
151
|
+
async resolveVectorIndex(entityDoc, contextUser) {
|
|
152
|
+
const rv = new RunView();
|
|
153
|
+
// If the EntityDocument has an explicit VectorIndexID, use it directly
|
|
154
|
+
if (entityDoc.VectorIndexID) {
|
|
155
|
+
const result = await rv.RunView({
|
|
156
|
+
EntityName: 'MJ: Vector Indexes',
|
|
157
|
+
ExtraFilter: `ID='${entityDoc.VectorIndexID}'`,
|
|
158
|
+
ResultType: 'entity_object',
|
|
159
|
+
}, contextUser);
|
|
160
|
+
if (result.Success && result.Results.length > 0) {
|
|
161
|
+
return result.Results[0];
|
|
162
|
+
}
|
|
163
|
+
LogError(`FetchEntityVectors: VectorIndex ${entityDoc.VectorIndexID} referenced by EntityDocument not found`);
|
|
164
|
+
}
|
|
165
|
+
// Fallback: find a VectorIndex by VectorDatabaseID + matching AIModelID as EmbeddingModelID
|
|
166
|
+
const indexResult = await rv.RunView({
|
|
167
|
+
EntityName: 'MJ: Vector Indexes',
|
|
168
|
+
ExtraFilter: `VectorDatabaseID='${entityDoc.VectorDatabaseID}'`,
|
|
169
|
+
ResultType: 'entity_object',
|
|
170
|
+
}, contextUser);
|
|
171
|
+
if (!indexResult.Success || indexResult.Results.length === 0) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
// Match on EmbeddingModelID = EntityDocument.AIModelID
|
|
175
|
+
const match = indexResult.Results.find(idx => UUIDsEqual(idx.EmbeddingModelID, entityDoc.AIModelID));
|
|
176
|
+
return match ?? indexResult.Results[0];
|
|
177
|
+
}
|
|
178
|
+
/** Create a VectorDBBase provider instance for a given VectorIndex */
|
|
179
|
+
async createVectorDBInstance(vectorIndex, contextUser) {
|
|
180
|
+
const rv = new RunView();
|
|
181
|
+
const dbResult = await rv.RunView({
|
|
182
|
+
EntityName: 'MJ: Vector Databases',
|
|
183
|
+
ExtraFilter: `ID='${vectorIndex.VectorDatabaseID}'`,
|
|
184
|
+
ResultType: 'entity_object',
|
|
185
|
+
}, contextUser);
|
|
186
|
+
if (!dbResult.Success || dbResult.Results.length === 0) {
|
|
187
|
+
LogError(`FetchEntityVectors: VectorDatabase not found for index "${vectorIndex.Name}"`);
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
const vectorDB = dbResult.Results[0];
|
|
191
|
+
const apiKey = GetAIAPIKey(vectorDB.ClassKey);
|
|
192
|
+
const instance = MJGlobal.Instance.ClassFactory.CreateInstance(VectorDBBase, vectorDB.ClassKey, apiKey);
|
|
193
|
+
if (!instance) {
|
|
194
|
+
LogError(`FetchEntityVectors: Failed to create VectorDB instance for ClassKey "${vectorDB.ClassKey}"`);
|
|
195
|
+
}
|
|
196
|
+
return instance;
|
|
197
|
+
}
|
|
198
|
+
errorResult(message, startTime) {
|
|
199
|
+
return {
|
|
200
|
+
Success: false,
|
|
201
|
+
Results: [],
|
|
202
|
+
TotalCount: 0,
|
|
203
|
+
ElapsedMs: Date.now() - startTime,
|
|
204
|
+
ErrorMessage: message,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
__decorate([
|
|
209
|
+
Query(() => FetchEntityVectorsResult),
|
|
210
|
+
__param(0, Arg('entityDocumentID')),
|
|
211
|
+
__param(1, Arg('maxRecords', () => Int, { nullable: true })),
|
|
212
|
+
__param(2, Arg('filter', { nullable: true })),
|
|
213
|
+
__param(3, Ctx()),
|
|
214
|
+
__metadata("design:type", Function),
|
|
215
|
+
__metadata("design:paramtypes", [String, Number, String, Object]),
|
|
216
|
+
__metadata("design:returntype", Promise)
|
|
217
|
+
], FetchEntityVectorsResolver.prototype, "FetchEntityVectors", null);
|
|
218
|
+
FetchEntityVectorsResolver = __decorate([
|
|
219
|
+
Resolver()
|
|
220
|
+
], FetchEntityVectorsResolver);
|
|
221
|
+
export { FetchEntityVectorsResolver };
|
|
222
|
+
//# sourceMappingURL=FetchEntityVectorsResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FetchEntityVectorsResolver.js","sourceRoot":"","sources":["../../src/resolvers/FetchEntityVectorsResolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -102,6 +102,13 @@ export declare class RunAIAgentResolver extends ResolverBase {
|
|
|
102
102
|
* Create a user notification for agent completion with artifact
|
|
103
103
|
* Notification includes navigation link back to the conversation
|
|
104
104
|
*/
|
|
105
|
+
/**
|
|
106
|
+
* LATENCY OPTIMIZATION (Opt #2): Now accepts conversationId directly instead of
|
|
107
|
+
* conversationDetailId. Previously this method loaded a ConversationDetail entity
|
|
108
|
+
* from the DB solely to extract its ConversationID field for building a URL — a
|
|
109
|
+
* redundant ~50ms DB round-trip since the caller already resolved conversationId
|
|
110
|
+
* when loading conversation history.
|
|
111
|
+
*/
|
|
105
112
|
private createCompletionNotification;
|
|
106
113
|
/**
|
|
107
114
|
* When a continuation run completes (lastRunId was provided), sync the corresponding
|
|
@@ -146,6 +153,20 @@ export declare class RunAIAgentResolver extends ResolverBase {
|
|
|
146
153
|
/**
|
|
147
154
|
* Load conversation history with attachments from database.
|
|
148
155
|
* Builds ChatMessage[] with multimodal content blocks for attachments.
|
|
156
|
+
*
|
|
157
|
+
* LATENCY OPTIMIZATIONS (plans/agent-latency-optimization.md — Opts #3 and #8):
|
|
158
|
+
*
|
|
159
|
+
* Opt #3: This method now accepts conversationId directly instead of conversationDetailId.
|
|
160
|
+
* Previously it loaded a ConversationDetail entity object just to extract its ConversationID
|
|
161
|
+
* field — a redundant DB round-trip (~40ms) since the caller already has this information.
|
|
162
|
+
* The caller (RunAIAgentFromConversationDetail) now loads the ConversationDetail once and
|
|
163
|
+
* passes conversationId down.
|
|
164
|
+
*
|
|
165
|
+
* Opt #8: Switched from ResultType 'entity_object' to 'simple' with explicit Fields.
|
|
166
|
+
* The history query only needs ID, Role, and Message from each ConversationDetail record.
|
|
167
|
+
* Using 'entity_object' created full BaseEntity instances with getters/setters, dirty tracking,
|
|
168
|
+
* and validation — none of which are needed for read-only history assembly. The 'simple' result
|
|
169
|
+
* type returns plain JS objects, reducing per-record overhead (~30ms total savings).
|
|
149
170
|
*/
|
|
150
171
|
private loadConversationHistoryWithAttachments;
|
|
151
172
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RunAIAgentResolver.d.ts","sourceRoot":"","sources":["../../src/resolvers/RunAIAgentResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkE,YAAY,EAAmD,MAAM,cAAc,CAAC;AAC7J,OAAO,EAAE,UAAU,EAAe,MAAM,aAAa,CAAC;AAOtD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAQ1D,qBACa,gBAAgB;IAEzB,OAAO,EAAE,OAAO,CAAC;IAGjB,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,eAAe,CAAC,EAAE,MAAM,CAAC;IAGzB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,qBACa,sBAAsB;IAE/B,WAAW,EAAE,MAAM,CAAC;IAGpB,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,OAAO,EAAE,MAAM,CAAC;IAGhB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,qBACa,qBAAqB;IAE9B,OAAO,EAAE,MAAM,CAAC;IAGhB,SAAS,EAAE,OAAO,CAAC;IAGnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBACa,yBAAyB;IAElC,MAAM,EAAE,MAAM,CAAC;IAGf,QAAQ,EAAE,MAAM,CAAC;IAGjB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,SAAS,EAAE,IAAI,CAAC;IAGhB,OAAO,CAAC,EAAE,IAAI,CAAC;IAGf,MAAM,EAAE,MAAM,CAAC;IAGf,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBACa,kBAAkB;IAE3B,WAAW,EAAE,MAAM,CAAC;IAGpB,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,qBACa,2BAA2B;IAEpC,SAAS,EAAE,MAAM,CAAC;IAGlB,UAAU,EAAE,MAAM,CAAC;IAGnB,IAAI,EAAE,UAAU,GAAG,WAAW,GAAG,gBAAgB,GAAG,UAAU,CAAC;IAG/D,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAGlC,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAGlC,aAAa,CAAC,EAAE,kBAAkB,CAAC;IAGnC,SAAS,EAAE,IAAI,CAAC;IAGhB,QAAQ,CAAC,EAAE,GAAG,CAAC;IAGf,oBAAoB,CAAC,EAAE,MAAM,CAAC;CACjC;AAMD,qBACa,kBAAmB,SAAQ,YAAY;IAChD;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA4B3B;;OAEG;IACH,OAAO,CAAC,cAAc;IAUtB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;OAEG;YACW,aAAa;IAmB3B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA6C9B,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,sBAAsB;IAY9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAmC/B;;;;OAIG;YACW,cAAc;
|
|
1
|
+
{"version":3,"file":"RunAIAgentResolver.d.ts","sourceRoot":"","sources":["../../src/resolvers/RunAIAgentResolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -368,7 +368,9 @@ let RunAIAgentResolver = class RunAIAgentResolver extends ResolverBase {
|
|
|
368
368
|
* This method is called by both the regular and system user resolvers.
|
|
369
369
|
* @private
|
|
370
370
|
*/
|
|
371
|
-
async executeAIAgent(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, templateData, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts = false, createNotification = false, sourceArtifactId, sourceArtifactVersionId
|
|
371
|
+
async executeAIAgent(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, templateData, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts = false, createNotification = false, sourceArtifactId, sourceArtifactVersionId,
|
|
372
|
+
/** LATENCY OPT #2: Pre-resolved conversationId avoids redundant DB load in AgentRunner */
|
|
373
|
+
conversationId) {
|
|
372
374
|
const startTime = Date.now();
|
|
373
375
|
try {
|
|
374
376
|
LogStatus(`=== RUNNING AI AGENT FOR ID: ${agentId} ===`);
|
|
@@ -402,6 +404,7 @@ let RunAIAgentResolver = class RunAIAgentResolver extends ResolverBase {
|
|
|
402
404
|
conversationMessages: parsedMessages,
|
|
403
405
|
payload: payload ? SafeJSONParse(payload) : undefined,
|
|
404
406
|
contextUser: currentUser,
|
|
407
|
+
sessionID: sessionId,
|
|
405
408
|
onProgress: this.createProgressCallback(pubSub, sessionId, userPayload, agentRunRef),
|
|
406
409
|
onStreaming: this.createStreamingCallback(pubSub, sessionId, userPayload, agentRunRef),
|
|
407
410
|
lastRunId: lastRunId,
|
|
@@ -413,6 +416,7 @@ let RunAIAgentResolver = class RunAIAgentResolver extends ResolverBase {
|
|
|
413
416
|
}
|
|
414
417
|
}, {
|
|
415
418
|
conversationDetailId: conversationDetailId, // Use existing if provided
|
|
419
|
+
conversationId: conversationId, // LATENCY OPT #2: pre-resolved to skip redundant load in AgentRunner
|
|
416
420
|
userMessage: userMessage, // Provide user message when conversationDetailId not provided
|
|
417
421
|
createArtifacts: createArtifacts || false,
|
|
418
422
|
sourceArtifactId: sourceArtifactId
|
|
@@ -426,21 +430,33 @@ let RunAIAgentResolver = class RunAIAgentResolver extends ResolverBase {
|
|
|
426
430
|
agentRunRef.current = result.agentRun;
|
|
427
431
|
}
|
|
428
432
|
const executionTime = Date.now() - startTime;
|
|
429
|
-
//
|
|
433
|
+
// LATENCY OPTIMIZATION (Opt #6): These three post-execution operations are independent
|
|
434
|
+
// of each other — none reads the output of another. Previously they ran sequentially,
|
|
435
|
+
// adding their latencies together (~50ms total). Now they run in parallel via Promise.all,
|
|
436
|
+
// so we only pay the cost of the slowest one.
|
|
437
|
+
//
|
|
438
|
+
// 1. syncFeedbackRequestFromConversation — links a prior Chat-step feedback request to
|
|
439
|
+
// the new agent run so the conversation thread stays coherent.
|
|
440
|
+
// 2. sendFeedbackRequestNotification — sends an in-app/email/SMS notification when the
|
|
441
|
+
// agent paused for human input (Chat step).
|
|
442
|
+
// 3. createCompletionNotification — sends an in-app/email/SMS notification that the
|
|
443
|
+
// agent finished and created an artifact.
|
|
444
|
+
const postExecutionOps = [];
|
|
430
445
|
if (lastRunId && result.agentRun?.ID) {
|
|
431
|
-
|
|
446
|
+
postExecutionOps.push(this.syncFeedbackRequestFromConversation(lastRunId, result.agentRun.ID, userMessage, currentUser));
|
|
432
447
|
}
|
|
433
|
-
// Send notification if agent created a feedback request (Chat step)
|
|
434
448
|
if (result.feedbackRequestId) {
|
|
435
|
-
|
|
449
|
+
postExecutionOps.push(this.sendFeedbackRequestNotification(result, currentUser, pubSub, userPayload));
|
|
436
450
|
}
|
|
437
|
-
// Create notification if enabled and artifact was created successfully
|
|
438
451
|
if (createNotification && result.success && artifactInfo && artifactInfo.artifactId && artifactInfo.versionId && artifactInfo.versionNumber) {
|
|
439
|
-
|
|
452
|
+
postExecutionOps.push(this.createCompletionNotification(result.agentRun, {
|
|
440
453
|
artifactId: artifactInfo.artifactId,
|
|
441
454
|
versionId: artifactInfo.versionId,
|
|
442
455
|
versionNumber: artifactInfo.versionNumber
|
|
443
|
-
}, finalConversationDetailId, currentUser, pubSub, userPayload);
|
|
456
|
+
}, conversationResult.conversationId, finalConversationDetailId, currentUser, pubSub, userPayload));
|
|
457
|
+
}
|
|
458
|
+
if (postExecutionOps.length > 0) {
|
|
459
|
+
await Promise.all(postExecutionOps);
|
|
444
460
|
}
|
|
445
461
|
// Create sanitized payload for JSON serialization
|
|
446
462
|
const sanitizedResult = this.sanitizeAgentResult(result);
|
|
@@ -553,21 +569,22 @@ let RunAIAgentResolver = class RunAIAgentResolver extends ResolverBase {
|
|
|
553
569
|
* Create a user notification for agent completion with artifact
|
|
554
570
|
* Notification includes navigation link back to the conversation
|
|
555
571
|
*/
|
|
556
|
-
|
|
572
|
+
/**
|
|
573
|
+
* LATENCY OPTIMIZATION (Opt #2): Now accepts conversationId directly instead of
|
|
574
|
+
* conversationDetailId. Previously this method loaded a ConversationDetail entity
|
|
575
|
+
* from the DB solely to extract its ConversationID field for building a URL — a
|
|
576
|
+
* redundant ~50ms DB round-trip since the caller already resolved conversationId
|
|
577
|
+
* when loading conversation history.
|
|
578
|
+
*/
|
|
579
|
+
async createCompletionNotification(agentRun, artifactInfo, conversationId, conversationDetailId, contextUser, pubSub, userPayload) {
|
|
557
580
|
try {
|
|
558
|
-
const md = new Metadata();
|
|
559
581
|
// Get agent info for notification message
|
|
560
582
|
await AIEngine.Instance.Config(false, contextUser);
|
|
561
583
|
const agent = AIEngine.Instance.Agents.find(a => UUIDsEqual(a.ID, agentRun.AgentID));
|
|
562
584
|
const agentName = agent?.Name || 'Agent';
|
|
563
|
-
// Load conversation detail to get conversation info
|
|
564
|
-
const detail = await md.GetEntityObject('MJ: Conversation Details', contextUser);
|
|
565
|
-
if (!(await detail.Load(conversationDetailId))) {
|
|
566
|
-
throw new Error(`Failed to load conversation detail ${conversationDetailId}`);
|
|
567
|
-
}
|
|
568
585
|
// Build conversation URL for email/SMS templates
|
|
569
586
|
const baseUrl = process.env.APP_BASE_URL || 'http://localhost:4201';
|
|
570
|
-
const conversationUrl = `${baseUrl}/conversations/${
|
|
587
|
+
const conversationUrl = `${baseUrl}/conversations/${conversationId}?artifact=${artifactInfo.artifactId}`;
|
|
571
588
|
// Craft message based on versioning
|
|
572
589
|
const message = artifactInfo.versionNumber > 1
|
|
573
590
|
? `${agentName} has finished processing and created version ${artifactInfo.versionNumber}`
|
|
@@ -582,7 +599,7 @@ let RunAIAgentResolver = class RunAIAgentResolver extends ResolverBase {
|
|
|
582
599
|
message: message,
|
|
583
600
|
resourceConfiguration: {
|
|
584
601
|
type: 'conversation',
|
|
585
|
-
conversationId:
|
|
602
|
+
conversationId: conversationId,
|
|
586
603
|
messageId: conversationDetailId,
|
|
587
604
|
artifactId: artifactInfo.artifactId,
|
|
588
605
|
versionId: artifactInfo.versionId,
|
|
@@ -613,7 +630,8 @@ let RunAIAgentResolver = class RunAIAgentResolver extends ResolverBase {
|
|
|
613
630
|
notificationId: result.inAppNotificationId,
|
|
614
631
|
action: 'create',
|
|
615
632
|
title: `${agentName} completed your request`,
|
|
616
|
-
message: message
|
|
633
|
+
message: message,
|
|
634
|
+
conversationId: conversationId
|
|
617
635
|
})
|
|
618
636
|
});
|
|
619
637
|
LogStatus(`📡 Published notification event to client`);
|
|
@@ -738,14 +756,25 @@ let RunAIAgentResolver = class RunAIAgentResolver extends ResolverBase {
|
|
|
738
756
|
};
|
|
739
757
|
}
|
|
740
758
|
try {
|
|
759
|
+
// LATENCY OPTIMIZATION (Opt #2 + #3): Load ConversationDetail once here to extract
|
|
760
|
+
// conversationId, then pass it downstream. Previously this record was loaded multiple
|
|
761
|
+
// times: once in loadConversationHistoryWithAttachments (just to get conversationId),
|
|
762
|
+
// once in AgentRunner (same reason), and once in createCompletionNotification. Now we
|
|
763
|
+
// load it a single time and thread conversationId through the call chain.
|
|
764
|
+
const md = new Metadata();
|
|
765
|
+
const currentDetail = await md.GetEntityObject('MJ: Conversation Details', currentUser);
|
|
766
|
+
if (!await currentDetail.Load(conversationDetailId)) {
|
|
767
|
+
throw new Error(`Conversation detail ${conversationDetailId} not found`);
|
|
768
|
+
}
|
|
769
|
+
const conversationId = currentDetail.ConversationID;
|
|
741
770
|
// Load conversation history with attachments from DB
|
|
742
|
-
const messages = await this.loadConversationHistoryWithAttachments(
|
|
771
|
+
const messages = await this.loadConversationHistoryWithAttachments(conversationId, currentUser, maxHistoryMessages || 20);
|
|
743
772
|
// Convert to JSON string for the existing executeAIAgent method
|
|
744
773
|
const messagesJson = JSON.stringify(messages);
|
|
745
774
|
if (fireAndForget) {
|
|
746
775
|
// Fire-and-forget mode: start execution in background, return immediately.
|
|
747
776
|
// The client will receive the result via WebSocket PubSub completion event.
|
|
748
|
-
this.executeAgentInBackground(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts || false, createNotification || false, sourceArtifactId, sourceArtifactVersionId);
|
|
777
|
+
this.executeAgentInBackground(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts || false, createNotification || false, sourceArtifactId, sourceArtifactVersionId, conversationId);
|
|
749
778
|
LogStatus(`🔥 Fire-and-forget: Agent ${agentId} execution started in background for session ${sessionId}`);
|
|
750
779
|
return {
|
|
751
780
|
success: true,
|
|
@@ -754,7 +783,8 @@ let RunAIAgentResolver = class RunAIAgentResolver extends ResolverBase {
|
|
|
754
783
|
}
|
|
755
784
|
// Synchronous mode (default): wait for execution to complete
|
|
756
785
|
return this.executeAIAgent(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, undefined, // templateData
|
|
757
|
-
lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts || false, createNotification || false, sourceArtifactId, sourceArtifactVersionId
|
|
786
|
+
lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts || false, createNotification || false, sourceArtifactId, sourceArtifactVersionId, conversationId // LATENCY OPT #2: pass pre-resolved conversationId
|
|
787
|
+
);
|
|
758
788
|
}
|
|
759
789
|
catch (error) {
|
|
760
790
|
const errorMessage = error.message || 'Unknown error loading conversation history';
|
|
@@ -914,9 +944,11 @@ let RunAIAgentResolver = class RunAIAgentResolver extends ResolverBase {
|
|
|
914
944
|
* so the client receives them via WebSocket even though the HTTP response
|
|
915
945
|
* has already been sent.
|
|
916
946
|
*/
|
|
917
|
-
executeAgentInBackground(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts = false, createNotification = false, sourceArtifactId, sourceArtifactVersionId
|
|
947
|
+
executeAgentInBackground(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts = false, createNotification = false, sourceArtifactId, sourceArtifactVersionId,
|
|
948
|
+
/** LATENCY OPT #2: Pre-resolved conversationId avoids redundant DB load in AgentRunner */
|
|
949
|
+
conversationId) {
|
|
918
950
|
// Execute in background - errors are handled within, not propagated
|
|
919
|
-
this.executeAIAgent(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, undefined, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts, createNotification, sourceArtifactId, sourceArtifactVersionId).catch((error) => {
|
|
951
|
+
this.executeAIAgent(p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub, data, payload, undefined, lastRunId, autoPopulateLastRunPayload, configurationId, conversationDetailId, createArtifacts, createNotification, sourceArtifactId, sourceArtifactVersionId, conversationId).catch((error) => {
|
|
920
952
|
// Background execution failed unexpectedly (executeAIAgent has its own try-catch,
|
|
921
953
|
// so this would only fire for truly unexpected errors).
|
|
922
954
|
const errorMessage = (error instanceof Error) ? error.message : 'Unknown background execution error';
|
|
@@ -938,24 +970,34 @@ let RunAIAgentResolver = class RunAIAgentResolver extends ResolverBase {
|
|
|
938
970
|
/**
|
|
939
971
|
* Load conversation history with attachments from database.
|
|
940
972
|
* Builds ChatMessage[] with multimodal content blocks for attachments.
|
|
973
|
+
*
|
|
974
|
+
* LATENCY OPTIMIZATIONS (plans/agent-latency-optimization.md — Opts #3 and #8):
|
|
975
|
+
*
|
|
976
|
+
* Opt #3: This method now accepts conversationId directly instead of conversationDetailId.
|
|
977
|
+
* Previously it loaded a ConversationDetail entity object just to extract its ConversationID
|
|
978
|
+
* field — a redundant DB round-trip (~40ms) since the caller already has this information.
|
|
979
|
+
* The caller (RunAIAgentFromConversationDetail) now loads the ConversationDetail once and
|
|
980
|
+
* passes conversationId down.
|
|
981
|
+
*
|
|
982
|
+
* Opt #8: Switched from ResultType 'entity_object' to 'simple' with explicit Fields.
|
|
983
|
+
* The history query only needs ID, Role, and Message from each ConversationDetail record.
|
|
984
|
+
* Using 'entity_object' created full BaseEntity instances with getters/setters, dirty tracking,
|
|
985
|
+
* and validation — none of which are needed for read-only history assembly. The 'simple' result
|
|
986
|
+
* type returns plain JS objects, reducing per-record overhead (~30ms total savings).
|
|
941
987
|
*/
|
|
942
|
-
async loadConversationHistoryWithAttachments(
|
|
943
|
-
const md = new Metadata();
|
|
988
|
+
async loadConversationHistoryWithAttachments(conversationId, contextUser, maxMessages) {
|
|
944
989
|
const rv = new RunView();
|
|
945
990
|
const attachmentService = getAttachmentService();
|
|
946
|
-
// Load
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
throw new Error(`Conversation detail ${conversationDetailId} not found`);
|
|
950
|
-
}
|
|
951
|
-
const conversationId = currentDetail.ConversationID;
|
|
952
|
-
// Load recent conversation details (messages) for this conversation
|
|
991
|
+
// Load recent conversation details (messages) for this conversation.
|
|
992
|
+
// Only fetch the three fields we actually use — ID for attachment lookups,
|
|
993
|
+
// Role for message routing, Message for content.
|
|
953
994
|
const detailsResult = await rv.RunView({
|
|
954
995
|
EntityName: 'MJ: Conversation Details',
|
|
955
996
|
ExtraFilter: `ConversationID='${conversationId}'`,
|
|
956
997
|
OrderBy: '__mj_CreatedAt DESC',
|
|
957
998
|
MaxRows: maxMessages,
|
|
958
|
-
|
|
999
|
+
Fields: ['ID', 'Role', 'Message'],
|
|
1000
|
+
ResultType: 'simple'
|
|
959
1001
|
}, contextUser);
|
|
960
1002
|
if (!detailsResult.Success || !detailsResult.Results) {
|
|
961
1003
|
throw new Error('Failed to load conversation history');
|