@ixo/common 1.1.2 → 1.1.4
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/.turbo/turbo-build.log +1 -1
- package/dist/ai/models/openai.d.ts +16 -0
- package/dist/ai/models/openai.d.ts.map +1 -1
- package/dist/ai/models/openai.js +26 -0
- package/dist/ai/models/openai.js.map +1 -1
- package/dist/ai/nodes/generic-chat/generic-chat.node.d.ts +1 -1
- package/dist/ai/nodes/index.d.ts +0 -1
- package/dist/ai/nodes/index.d.ts.map +1 -1
- package/dist/ai/nodes/index.js +0 -1
- package/dist/ai/nodes/index.js.map +1 -1
- package/dist/ai/semantic-router-factory/create-semantic-router.d.ts +1 -2
- package/dist/ai/semantic-router-factory/create-semantic-router.d.ts.map +1 -1
- package/dist/ai/semantic-router-factory/create-semantic-router.js +2 -3
- package/dist/ai/semantic-router-factory/create-semantic-router.js.map +1 -1
- package/dist/ai/tools/ask-ixo-guru/ask-ixo-guru.d.ts +1 -1
- package/dist/ai/tools/ask-ixo-guru/ask-ixo-guru.d.ts.map +1 -1
- package/dist/ai/tools/index.d.ts +0 -1
- package/dist/ai/tools/index.d.ts.map +1 -1
- package/dist/ai/tools/index.js +0 -1
- package/dist/ai/tools/index.js.map +1 -1
- package/dist/ai/tools/parser-action-tool.d.ts +1 -1
- package/dist/ai/tools/parser-action-tool.d.ts.map +1 -1
- package/dist/ai/tools/parser-action-tool.js +10 -3
- package/dist/ai/tools/parser-action-tool.js.map +1 -1
- package/dist/ai/tools/parser-browser-tool.d.ts +1 -1
- package/dist/ai/tools/parser-browser-tool.d.ts.map +1 -1
- package/dist/ai/tools/scrape-web-page.d.ts +1 -1
- package/dist/ai/tools/scrape-web-page.d.ts.map +1 -1
- package/dist/ai/tools/web-search-tool.d.ts +1 -1
- package/dist/ai/tools/web-search-tool.d.ts.map +1 -1
- package/dist/ai/utils/load-file.d.ts +1 -0
- package/dist/ai/utils/load-file.d.ts.map +1 -1
- package/dist/ai/utils/load-file.js +8 -0
- package/dist/ai/utils/load-file.js.map +1 -1
- package/dist/ai/utils/transformGraphStateMessageToListMessageResponse.d.ts +10 -0
- package/dist/ai/utils/transformGraphStateMessageToListMessageResponse.d.ts.map +1 -1
- package/dist/ai/utils/transformGraphStateMessageToListMessageResponse.js +4 -1
- package/dist/ai/utils/transformGraphStateMessageToListMessageResponse.js.map +1 -1
- package/dist/ai/utils/verify-matrix-openId-token.js +2 -2
- package/dist/ai/utils/verify-matrix-openId-token.js.map +1 -1
- package/dist/services/env/env.service.js.map +1 -1
- package/dist/services/memory-engine/memory-engine.service.d.ts +22 -16
- package/dist/services/memory-engine/memory-engine.service.d.ts.map +1 -1
- package/dist/services/memory-engine/memory-engine.service.js +136 -111
- package/dist/services/memory-engine/memory-engine.service.js.map +1 -1
- package/dist/services/memory-engine/types.d.ts +16 -0
- package/dist/services/memory-engine/types.d.ts.map +1 -1
- package/dist/services/memory-engine/types.js +4 -1
- package/dist/services/memory-engine/types.js.map +1 -1
- package/dist/services/session-manager/dto.d.ts +7 -0
- package/dist/services/session-manager/dto.d.ts.map +1 -1
- package/dist/services/session-manager/dto.js +42 -0
- package/dist/services/session-manager/dto.js.map +1 -1
- package/dist/services/session-manager/session-manager.service.d.ts +2 -2
- package/dist/services/session-manager/session-manager.service.d.ts.map +1 -1
- package/dist/services/session-manager/session-manager.service.js +81 -36
- package/dist/services/session-manager/session-manager.service.js.map +1 -1
- package/dist/utils/get-user-subscription.d.ts +2 -1
- package/dist/utils/get-user-subscription.d.ts.map +1 -1
- package/dist/utils/get-user-subscription.js +11 -7
- package/dist/utils/get-user-subscription.js.map +1 -1
- package/package.json +24 -25
- package/src/ai/models/openai.ts +31 -0
- package/src/ai/nodes/index.ts +0 -1
- package/src/ai/semantic-router-factory/create-semantic-router.test.ts +0 -3
- package/src/ai/semantic-router-factory/create-semantic-router.ts +2 -7
- package/src/ai/tools/index.ts +0 -1
- package/src/ai/tools/parser-action-tool.ts +19 -3
- package/src/ai/utils/load-file.ts +17 -0
- package/src/ai/utils/transformGraphStateMessageToListMessageResponse.ts +18 -1
- package/src/ai/utils/verify-matrix-openId-token.ts +2 -2
- package/src/services/env/env.service.ts +1 -1
- package/src/services/memory-engine/memory-engine.service.ts +228 -240
- package/src/services/memory-engine/types.ts +34 -0
- package/src/services/session-manager/dto.ts +30 -0
- package/src/services/session-manager/session-manager.service.ts +98 -38
- package/src/utils/get-user-subscription.ts +13 -6
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/ai/nodes/find-docs/find-docs.prompt.d.ts +0 -3
- package/dist/ai/nodes/find-docs/find-docs.prompt.d.ts.map +0 -1
- package/dist/ai/nodes/find-docs/find-docs.prompt.js +0 -61
- package/dist/ai/nodes/find-docs/find-docs.prompt.js.map +0 -1
- package/dist/ai/nodes/find-docs/index.d.ts +0 -3
- package/dist/ai/nodes/find-docs/index.d.ts.map +0 -1
- package/dist/ai/nodes/find-docs/index.js +0 -3
- package/dist/ai/nodes/find-docs/index.js.map +0 -1
- package/dist/ai/nodes/find-docs/node.d.ts +0 -17
- package/dist/ai/nodes/find-docs/node.d.ts.map +0 -1
- package/dist/ai/nodes/find-docs/node.js +0 -46
- package/dist/ai/nodes/find-docs/node.js.map +0 -1
- package/dist/ai/tools/retriever-tool/index.d.ts +0 -2
- package/dist/ai/tools/retriever-tool/index.d.ts.map +0 -1
- package/dist/ai/tools/retriever-tool/index.js +0 -2
- package/dist/ai/tools/retriever-tool/index.js.map +0 -1
- package/dist/ai/tools/retriever-tool/retriever-tool.d.ts +0 -18
- package/dist/ai/tools/retriever-tool/retriever-tool.d.ts.map +0 -1
- package/dist/ai/tools/retriever-tool/retriever-tool.js +0 -62
- package/dist/ai/tools/retriever-tool/retriever-tool.js.map +0 -1
- package/src/ai/nodes/find-docs/find-docs.prompt.ts +0 -61
- package/src/ai/nodes/find-docs/index.ts +0 -2
- package/src/ai/nodes/find-docs/node.ts +0 -83
- package/src/ai/tools/retriever-tool/index.ts +0 -1
- package/src/ai/tools/retriever-tool/retriever-tool.test.ts +0 -163
- package/src/ai/tools/retriever-tool/retriever-tool.ts +0 -107
|
@@ -1,32 +1,52 @@
|
|
|
1
1
|
import { Logger } from '@ixo/logger';
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import {
|
|
3
|
+
isBatchErrorSlot,
|
|
4
|
+
type SearchEnhancedBatchRequest,
|
|
5
|
+
type SearchEnhancedBatchResponse,
|
|
6
|
+
type SearchEnhancedRequest,
|
|
7
|
+
type SearchEnhancedResponse,
|
|
8
|
+
type UserContextData,
|
|
6
9
|
} from './types.js';
|
|
7
10
|
|
|
11
|
+
interface MemoryEngineAuthHeaders {
|
|
12
|
+
oracleToken: string;
|
|
13
|
+
userToken: string;
|
|
14
|
+
oracleHomeServer: string;
|
|
15
|
+
userHomeServer: string;
|
|
16
|
+
/** When set, uses UCAN auth instead of Matrix tokens */
|
|
17
|
+
ucanInvocation?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
8
20
|
export class MemoryEngineService {
|
|
9
|
-
|
|
21
|
+
// Batch covers 6 queries running in parallel server-side. Bound by the
|
|
22
|
+
// slowest query, not 6× — but we leave headroom for cold caches.
|
|
23
|
+
private readonly BATCH_TIMEOUT_MS = 15000;
|
|
10
24
|
|
|
11
|
-
constructor(
|
|
12
|
-
private readonly memoryEngineUrl: string,
|
|
13
|
-
private readonly memoryServiceApiKey: string,
|
|
14
|
-
) {}
|
|
25
|
+
constructor(private readonly memoryEngineUrl: string) {}
|
|
15
26
|
|
|
16
27
|
/**
|
|
17
|
-
*
|
|
28
|
+
* Build HTTP headers for memory engine requests (UCAN or Matrix)
|
|
18
29
|
*/
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
private buildHeaders(
|
|
31
|
+
auth: MemoryEngineAuthHeaders,
|
|
32
|
+
roomId: string,
|
|
33
|
+
): Record<string, string> {
|
|
34
|
+
if (auth.ucanInvocation) {
|
|
35
|
+
return {
|
|
36
|
+
Authorization: `Bearer ${auth.ucanInvocation}`,
|
|
37
|
+
'X-Auth-Type': 'ucan',
|
|
38
|
+
'x-room-id': roomId,
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
'x-oracle-token': auth.oracleToken,
|
|
44
|
+
'x-user-token': auth.userToken,
|
|
45
|
+
'x-oracle-matrix-homeserver': auth.oracleHomeServer,
|
|
46
|
+
'x-user-matrix-homeserver': auth.userHomeServer,
|
|
47
|
+
'x-room-id': roomId,
|
|
48
|
+
'Content-Type': 'application/json',
|
|
49
|
+
};
|
|
30
50
|
}
|
|
31
51
|
|
|
32
52
|
/**
|
|
@@ -34,101 +54,175 @@ export class MemoryEngineService {
|
|
|
34
54
|
*/
|
|
35
55
|
async gatherUserContext(params: {
|
|
36
56
|
oracleDid: string;
|
|
37
|
-
userDid: string;
|
|
38
57
|
roomId: string;
|
|
58
|
+
oracleToken: string;
|
|
59
|
+
userToken: string;
|
|
60
|
+
oracleHomeServer: string;
|
|
61
|
+
userHomeServer: string;
|
|
62
|
+
/** When set, uses UCAN auth instead of Matrix tokens */
|
|
63
|
+
ucanInvocation?: string;
|
|
39
64
|
}): Promise<UserContextData> {
|
|
40
|
-
const {
|
|
65
|
+
const {
|
|
66
|
+
oracleDid,
|
|
67
|
+
roomId,
|
|
68
|
+
oracleToken,
|
|
69
|
+
userToken,
|
|
70
|
+
oracleHomeServer,
|
|
71
|
+
userHomeServer,
|
|
72
|
+
ucanInvocation,
|
|
73
|
+
} = params;
|
|
41
74
|
|
|
42
75
|
Logger.info(
|
|
43
76
|
`[MemoryEngineService] Gathering user context for oracle: ${oracleDid}, room: ${roomId}`,
|
|
44
77
|
);
|
|
45
78
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
results[3].status === 'fulfilled' ? results[3].value : undefined;
|
|
90
|
-
const relationships =
|
|
91
|
-
results[4].status === 'fulfilled' ? results[4].value : undefined;
|
|
92
|
-
const recent =
|
|
93
|
-
results[5].status === 'fulfilled' ? results[5].value : undefined;
|
|
94
|
-
|
|
95
|
-
// Log any failures
|
|
96
|
-
results.forEach((result, index) => {
|
|
97
|
-
if (result.status === 'rejected') {
|
|
79
|
+
const authHeaders: MemoryEngineAuthHeaders = {
|
|
80
|
+
oracleToken,
|
|
81
|
+
userToken,
|
|
82
|
+
oracleHomeServer,
|
|
83
|
+
userHomeServer,
|
|
84
|
+
ucanInvocation,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// The 6 queries that make up userContext. Order matters: it determines
|
|
88
|
+
// how we map batch result slots back to UserContextData fields.
|
|
89
|
+
const labels = [
|
|
90
|
+
'identity',
|
|
91
|
+
'work',
|
|
92
|
+
'goals',
|
|
93
|
+
'interests',
|
|
94
|
+
'relationships',
|
|
95
|
+
'recent',
|
|
96
|
+
] as const;
|
|
97
|
+
const requests: SearchEnhancedRequest[] = [
|
|
98
|
+
this.buildIdentityRequest(oracleDid),
|
|
99
|
+
this.buildWorkRequest(oracleDid),
|
|
100
|
+
this.buildGoalsRequest(oracleDid),
|
|
101
|
+
this.buildInterestsRequest(oracleDid),
|
|
102
|
+
this.buildRelationshipsRequest(oracleDid),
|
|
103
|
+
this.buildRecentRequest(oracleDid),
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
const gatherStart = Date.now();
|
|
107
|
+
const batch = await this.executeBatch(requests, roomId, authHeaders);
|
|
108
|
+
const gatherElapsed = Date.now() - gatherStart;
|
|
109
|
+
|
|
110
|
+
if (!batch) {
|
|
111
|
+
Logger.error(
|
|
112
|
+
`[MemoryEngineService] gatherUserContext failed after ${gatherElapsed}ms — returning empty context`,
|
|
113
|
+
);
|
|
114
|
+
return {};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Map each slot back to the labelled field. Error slots become undefined.
|
|
118
|
+
const fields: (SearchEnhancedResponse | undefined)[] = batch.results.map(
|
|
119
|
+
(slot, index) => {
|
|
120
|
+
const label = labels[index];
|
|
121
|
+
if (isBatchErrorSlot(slot)) {
|
|
98
122
|
Logger.warn(
|
|
99
|
-
`[MemoryEngineService]
|
|
100
|
-
result.reason,
|
|
123
|
+
`[MemoryEngineService] Batch slot "${label}" failed (${slot.error.status_code}): ${slot.error.detail}`,
|
|
101
124
|
);
|
|
125
|
+
return undefined;
|
|
102
126
|
}
|
|
103
|
-
|
|
127
|
+
return slot;
|
|
128
|
+
},
|
|
129
|
+
);
|
|
104
130
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
goals,
|
|
109
|
-
interests,
|
|
110
|
-
relationships,
|
|
111
|
-
recent,
|
|
112
|
-
};
|
|
113
|
-
} catch (error) {
|
|
114
|
-
Logger.error(
|
|
115
|
-
'[MemoryEngineService] Failed to gather user context:',
|
|
116
|
-
error,
|
|
131
|
+
if (batch.results.length !== labels.length) {
|
|
132
|
+
Logger.warn(
|
|
133
|
+
`[MemoryEngineService] Batch length mismatch: expected ${labels.length}, got ${batch.results.length}`,
|
|
117
134
|
);
|
|
118
|
-
// Return empty context on error
|
|
119
|
-
return {};
|
|
120
135
|
}
|
|
136
|
+
|
|
137
|
+
const summary = labels.map((label, index) => {
|
|
138
|
+
const value = fields[index];
|
|
139
|
+
if (value === undefined) return `${label}=missing`;
|
|
140
|
+
return `${label}=ok(f${value.total_results.facts}/e${value.total_results.entities})`;
|
|
141
|
+
});
|
|
142
|
+
Logger.info(
|
|
143
|
+
`[MemoryEngineService] gatherUserContext completed in ${gatherElapsed}ms (batch) — ${summary.join(', ')}`,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
identity: fields[0],
|
|
148
|
+
work: fields[1],
|
|
149
|
+
goals: fields[2],
|
|
150
|
+
interests: fields[3],
|
|
151
|
+
relationships: fields[4],
|
|
152
|
+
recent: fields[5],
|
|
153
|
+
};
|
|
121
154
|
}
|
|
122
155
|
|
|
123
156
|
/**
|
|
124
|
-
*
|
|
157
|
+
* POST /search-enhanced-batch — single round-trip for N parallel queries.
|
|
158
|
+
* Returns undefined on transport/HTTP failure; a partially-failed batch
|
|
159
|
+
* still resolves with per-slot error markers (handled by caller via
|
|
160
|
+
* `isBatchErrorSlot`).
|
|
125
161
|
*/
|
|
126
|
-
private async
|
|
127
|
-
|
|
128
|
-
userDid: string,
|
|
162
|
+
private async executeBatch(
|
|
163
|
+
queries: SearchEnhancedRequest[],
|
|
129
164
|
roomId: string,
|
|
130
|
-
|
|
131
|
-
|
|
165
|
+
auth: MemoryEngineAuthHeaders,
|
|
166
|
+
): Promise<SearchEnhancedBatchResponse | undefined> {
|
|
167
|
+
if (!roomId) {
|
|
168
|
+
Logger.warn(
|
|
169
|
+
`[MemoryEngineService] No room id provided, skipping batch search`,
|
|
170
|
+
);
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
if (!auth.ucanInvocation && (!auth.oracleToken || !auth.userToken)) {
|
|
174
|
+
Logger.warn(
|
|
175
|
+
`[MemoryEngineService] Missing auth (no UCAN and no Matrix tokens), skipping batch search`,
|
|
176
|
+
);
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const body: SearchEnhancedBatchRequest = { queries };
|
|
181
|
+
|
|
182
|
+
const controller = new AbortController();
|
|
183
|
+
const timer = setTimeout(() => controller.abort(), this.BATCH_TIMEOUT_MS);
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
const response = await fetch(
|
|
187
|
+
`${this.memoryEngineUrl}/search-enhanced-batch`,
|
|
188
|
+
{
|
|
189
|
+
method: 'POST',
|
|
190
|
+
headers: this.buildHeaders(auth, roomId),
|
|
191
|
+
body: JSON.stringify(body),
|
|
192
|
+
signal: controller.signal,
|
|
193
|
+
},
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
if (!response.ok) {
|
|
197
|
+
const errorText = await response.text();
|
|
198
|
+
Logger.warn(
|
|
199
|
+
`[MemoryEngineService] Batch search failed (${response.status}): ${errorText}`,
|
|
200
|
+
);
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return (await response.json()) as SearchEnhancedBatchResponse;
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if ((error as Error).name === 'AbortError') {
|
|
207
|
+
Logger.warn(
|
|
208
|
+
`[MemoryEngineService] Batch search aborted after ${this.BATCH_TIMEOUT_MS}ms`,
|
|
209
|
+
);
|
|
210
|
+
} else {
|
|
211
|
+
Logger.error(`[MemoryEngineService] Batch search threw:`, error);
|
|
212
|
+
}
|
|
213
|
+
return undefined;
|
|
214
|
+
} finally {
|
|
215
|
+
clearTimeout(timer);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ── Per-query request builders ────────────────────────────────────────────
|
|
220
|
+
// These produce SearchEnhancedRequest payloads consumed by gatherUserContext
|
|
221
|
+
// via the batch endpoint. Order matches the labels array in
|
|
222
|
+
// gatherUserContext — keep the two in sync.
|
|
223
|
+
|
|
224
|
+
private buildIdentityRequest(oracleDid: string): SearchEnhancedRequest {
|
|
225
|
+
return {
|
|
132
226
|
oracle_dids: [oracleDid],
|
|
133
227
|
query:
|
|
134
228
|
'username and nickname and age user identity traits values personality characteristics communication style beliefs preferences',
|
|
@@ -152,19 +246,10 @@ export class MemoryEngineService {
|
|
|
152
246
|
invalid_at: [[{ date: null, comparison_operator: 'IS NULL' }]],
|
|
153
247
|
},
|
|
154
248
|
};
|
|
155
|
-
|
|
156
|
-
return this.executeQuery(request, userDid, oracleDid, roomId);
|
|
157
249
|
}
|
|
158
250
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
*/
|
|
162
|
-
private async queryWork(
|
|
163
|
-
oracleDid: string,
|
|
164
|
-
userDid: string,
|
|
165
|
-
roomId: string,
|
|
166
|
-
): Promise<SearchEnhancedResponse | undefined> {
|
|
167
|
-
const request: SearchEnhancedRequest = {
|
|
251
|
+
private buildWorkRequest(oracleDid: string): SearchEnhancedRequest {
|
|
252
|
+
return {
|
|
168
253
|
oracle_dids: [oracleDid],
|
|
169
254
|
query:
|
|
170
255
|
'work job career projects skills organization employment role responsibilities expertise',
|
|
@@ -195,19 +280,10 @@ export class MemoryEngineService {
|
|
|
195
280
|
invalid_at: [[{ date: null, comparison_operator: 'IS NULL' }]],
|
|
196
281
|
},
|
|
197
282
|
};
|
|
198
|
-
|
|
199
|
-
return this.executeQuery(request, userDid, oracleDid, roomId);
|
|
200
283
|
}
|
|
201
284
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
*/
|
|
205
|
-
private async queryGoals(
|
|
206
|
-
oracleDid: string,
|
|
207
|
-
userDid: string,
|
|
208
|
-
roomId: string,
|
|
209
|
-
): Promise<SearchEnhancedResponse | undefined> {
|
|
210
|
-
const request: SearchEnhancedRequest = {
|
|
285
|
+
private buildGoalsRequest(oracleDid: string): SearchEnhancedRequest {
|
|
286
|
+
return {
|
|
211
287
|
oracle_dids: [oracleDid],
|
|
212
288
|
query:
|
|
213
289
|
'goals aspirations objectives milestones habits routines patterns achievements progress',
|
|
@@ -230,19 +306,10 @@ export class MemoryEngineService {
|
|
|
230
306
|
invalid_at: [[{ date: null, comparison_operator: 'IS NULL' }]],
|
|
231
307
|
},
|
|
232
308
|
};
|
|
233
|
-
|
|
234
|
-
return this.executeQuery(request, userDid, oracleDid, roomId);
|
|
235
309
|
}
|
|
236
310
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
*/
|
|
240
|
-
private async queryInterests(
|
|
241
|
-
oracleDid: string,
|
|
242
|
-
userDid: string,
|
|
243
|
-
roomId: string,
|
|
244
|
-
): Promise<SearchEnhancedResponse | undefined> {
|
|
245
|
-
const request: SearchEnhancedRequest = {
|
|
311
|
+
private buildInterestsRequest(oracleDid: string): SearchEnhancedRequest {
|
|
312
|
+
return {
|
|
246
313
|
oracle_dids: [oracleDid],
|
|
247
314
|
query:
|
|
248
315
|
'interests hobbies passions preferences likes dislikes expertise topics content',
|
|
@@ -272,19 +339,10 @@ export class MemoryEngineService {
|
|
|
272
339
|
invalid_at: [[{ date: null, comparison_operator: 'IS NULL' }]],
|
|
273
340
|
},
|
|
274
341
|
};
|
|
275
|
-
|
|
276
|
-
return this.executeQuery(request, userDid, oracleDid, roomId);
|
|
277
342
|
}
|
|
278
343
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
*/
|
|
282
|
-
private async queryRelationships(
|
|
283
|
-
oracleDid: string,
|
|
284
|
-
userDid: string,
|
|
285
|
-
roomId: string,
|
|
286
|
-
): Promise<SearchEnhancedResponse | undefined> {
|
|
287
|
-
const request: SearchEnhancedRequest = {
|
|
344
|
+
private buildRelationshipsRequest(oracleDid: string): SearchEnhancedRequest {
|
|
345
|
+
return {
|
|
288
346
|
oracle_dids: [oracleDid],
|
|
289
347
|
query:
|
|
290
348
|
'relationships people connections social network colleagues friends family contacts',
|
|
@@ -307,24 +365,17 @@ export class MemoryEngineService {
|
|
|
307
365
|
invalid_at: [[{ date: null, comparison_operator: 'IS NULL' }]],
|
|
308
366
|
},
|
|
309
367
|
};
|
|
310
|
-
|
|
311
|
-
return this.executeQuery(request, userDid, oracleDid, roomId);
|
|
312
368
|
}
|
|
313
369
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
oracleDid: string,
|
|
319
|
-
userDid: string,
|
|
320
|
-
roomId: string,
|
|
321
|
-
): Promise<SearchEnhancedResponse | undefined> {
|
|
322
|
-
// Calculate date 90 days ago for recent context
|
|
370
|
+
private buildRecentRequest(oracleDid: string): SearchEnhancedRequest {
|
|
371
|
+
// Server-side `recent_memory` strategy auto-injects a created_at >= now-90d
|
|
372
|
+
// filter. We still pass it explicitly as defense-in-depth — the server's
|
|
373
|
+
// merge logic respects an existing lower bound and won't double-apply.
|
|
323
374
|
const ninetyDaysAgo = new Date();
|
|
324
375
|
ninetyDaysAgo.setDate(ninetyDaysAgo.getDate() - 90);
|
|
325
376
|
const dateString = ninetyDaysAgo.toISOString();
|
|
326
377
|
|
|
327
|
-
|
|
378
|
+
return {
|
|
328
379
|
oracle_dids: [oracleDid],
|
|
329
380
|
query:
|
|
330
381
|
'recent conversations messages discussions activities updates interactions',
|
|
@@ -338,8 +389,6 @@ export class MemoryEngineService {
|
|
|
338
389
|
created_at: [[{ date: dateString, comparison_operator: '>=' }]],
|
|
339
390
|
},
|
|
340
391
|
};
|
|
341
|
-
|
|
342
|
-
return this.executeQuery(request, userDid, oracleDid, roomId);
|
|
343
392
|
}
|
|
344
393
|
|
|
345
394
|
/**
|
|
@@ -347,9 +396,12 @@ export class MemoryEngineService {
|
|
|
347
396
|
*/
|
|
348
397
|
async processConversationHistory({
|
|
349
398
|
messages,
|
|
350
|
-
userDid,
|
|
351
|
-
oracleDid,
|
|
352
399
|
roomId,
|
|
400
|
+
oracleToken,
|
|
401
|
+
userToken,
|
|
402
|
+
oracleHomeServer,
|
|
403
|
+
userHomeServer,
|
|
404
|
+
ucanInvocation,
|
|
353
405
|
}: {
|
|
354
406
|
messages: Array<{
|
|
355
407
|
content: string;
|
|
@@ -358,25 +410,23 @@ export class MemoryEngineService {
|
|
|
358
410
|
name?: string;
|
|
359
411
|
source_description?: string;
|
|
360
412
|
}>;
|
|
361
|
-
userDid: string;
|
|
362
|
-
oracleDid: string;
|
|
363
413
|
roomId: string;
|
|
414
|
+
oracleToken: string;
|
|
415
|
+
userToken: string;
|
|
416
|
+
oracleHomeServer: string;
|
|
417
|
+
userHomeServer: string;
|
|
418
|
+
/** When set, uses UCAN auth instead of Matrix tokens */
|
|
419
|
+
ucanInvocation?: string;
|
|
364
420
|
}): Promise<{ success: boolean }> {
|
|
365
|
-
if (!
|
|
366
|
-
Logger.warn(
|
|
367
|
-
`[MemoryEngineService] No user DID provided, skipping conversation processing`,
|
|
368
|
-
);
|
|
369
|
-
return { success: false };
|
|
370
|
-
}
|
|
371
|
-
if (!oracleDid) {
|
|
421
|
+
if (!roomId) {
|
|
372
422
|
Logger.warn(
|
|
373
|
-
`[MemoryEngineService] No
|
|
423
|
+
`[MemoryEngineService] No room id provided, skipping conversation processing`,
|
|
374
424
|
);
|
|
375
425
|
return { success: false };
|
|
376
426
|
}
|
|
377
|
-
if (!
|
|
427
|
+
if (!ucanInvocation && (!oracleToken || !userToken)) {
|
|
378
428
|
Logger.warn(
|
|
379
|
-
`[MemoryEngineService]
|
|
429
|
+
`[MemoryEngineService] Missing auth (no UCAN and no Matrix tokens), skipping conversation processing`,
|
|
380
430
|
);
|
|
381
431
|
return { success: false };
|
|
382
432
|
}
|
|
@@ -388,15 +438,16 @@ export class MemoryEngineService {
|
|
|
388
438
|
}
|
|
389
439
|
|
|
390
440
|
try {
|
|
441
|
+
const auth: MemoryEngineAuthHeaders = {
|
|
442
|
+
oracleToken,
|
|
443
|
+
userToken,
|
|
444
|
+
oracleHomeServer,
|
|
445
|
+
userHomeServer,
|
|
446
|
+
ucanInvocation,
|
|
447
|
+
};
|
|
391
448
|
const response = await fetch(`${this.memoryEngineUrl}/messages`, {
|
|
392
449
|
method: 'POST',
|
|
393
|
-
headers:
|
|
394
|
-
'x-user-did': userDid,
|
|
395
|
-
'x-oracle-did': oracleDid,
|
|
396
|
-
'x-room-id': roomId,
|
|
397
|
-
'x-service-api-key': this.memoryServiceApiKey,
|
|
398
|
-
'Content-Type': 'application/json',
|
|
399
|
-
},
|
|
450
|
+
headers: this.buildHeaders(auth, roomId),
|
|
400
451
|
body: JSON.stringify({ messages }),
|
|
401
452
|
});
|
|
402
453
|
|
|
@@ -420,67 +471,4 @@ export class MemoryEngineService {
|
|
|
420
471
|
return { success: false };
|
|
421
472
|
}
|
|
422
473
|
}
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Execute a search query against the Memory Engine API
|
|
426
|
-
*/
|
|
427
|
-
private async executeQuery(
|
|
428
|
-
request: SearchEnhancedRequest,
|
|
429
|
-
userDid: string,
|
|
430
|
-
oracleDid: string,
|
|
431
|
-
roomId: string,
|
|
432
|
-
): Promise<SearchEnhancedResponse | undefined> {
|
|
433
|
-
if (!userDid) {
|
|
434
|
-
Logger.warn(
|
|
435
|
-
`[MemoryEngineService] No user DID provided, skipping query "${request.query}"`,
|
|
436
|
-
);
|
|
437
|
-
return undefined;
|
|
438
|
-
}
|
|
439
|
-
if (!oracleDid) {
|
|
440
|
-
Logger.warn(
|
|
441
|
-
`[MemoryEngineService] No oracle did provided, skipping query "${request.query}"`,
|
|
442
|
-
);
|
|
443
|
-
return undefined;
|
|
444
|
-
}
|
|
445
|
-
if (!roomId) {
|
|
446
|
-
Logger.warn(
|
|
447
|
-
`[MemoryEngineService] No room id provided, skipping query "${request.query}"`,
|
|
448
|
-
);
|
|
449
|
-
return undefined;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
try {
|
|
453
|
-
const response = await fetch(`${this.memoryEngineUrl}/search-enhanced`, {
|
|
454
|
-
method: 'POST',
|
|
455
|
-
headers: {
|
|
456
|
-
'x-user-did': userDid,
|
|
457
|
-
'x-oracle-did': oracleDid,
|
|
458
|
-
'x-room-id': roomId,
|
|
459
|
-
'x-service-api-key': this.memoryServiceApiKey,
|
|
460
|
-
'Content-Type': 'application/json',
|
|
461
|
-
},
|
|
462
|
-
body: JSON.stringify(request),
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
if (!response.ok) {
|
|
466
|
-
const errorText = await response.text();
|
|
467
|
-
Logger.warn(
|
|
468
|
-
`[MemoryEngineService] Memory Engine query failed (${response.status}): ${errorText}`,
|
|
469
|
-
);
|
|
470
|
-
return undefined;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
const result = (await response.json()) as SearchEnhancedResponse;
|
|
474
|
-
Logger.info(
|
|
475
|
-
`[MemoryEngineService] Query "${request.query}" returned ${result.total_results.facts} facts, ${result.total_results.entities} entities`,
|
|
476
|
-
);
|
|
477
|
-
return result;
|
|
478
|
-
} catch (error) {
|
|
479
|
-
Logger.error(
|
|
480
|
-
`[MemoryEngineService] Failed to execute query "${request.query}":`,
|
|
481
|
-
error,
|
|
482
|
-
);
|
|
483
|
-
return undefined;
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
474
|
}
|
|
@@ -206,3 +206,37 @@ export interface UserContextData {
|
|
|
206
206
|
relationships?: SearchEnhancedResponse;
|
|
207
207
|
recent?: SearchEnhancedResponse;
|
|
208
208
|
}
|
|
209
|
+
|
|
210
|
+
// Batch search types — backend endpoint POST /search-enhanced-batch
|
|
211
|
+
export interface SearchEnhancedBatchRequest {
|
|
212
|
+
queries: SearchEnhancedRequest[];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// A failed slot in the batch response. The server returns this in place of
|
|
216
|
+
// SearchEnhancedResponse when a single query fails — the rest of the batch
|
|
217
|
+
// still completes.
|
|
218
|
+
export interface SearchEnhancedBatchErrorSlot {
|
|
219
|
+
error: {
|
|
220
|
+
status_code: number;
|
|
221
|
+
detail: string;
|
|
222
|
+
};
|
|
223
|
+
query: string;
|
|
224
|
+
strategy_used: string;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export type SearchEnhancedBatchSlot =
|
|
228
|
+
| SearchEnhancedResponse
|
|
229
|
+
| SearchEnhancedBatchErrorSlot;
|
|
230
|
+
|
|
231
|
+
export interface SearchEnhancedBatchResponse {
|
|
232
|
+
results: SearchEnhancedBatchSlot[];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function isBatchErrorSlot(
|
|
236
|
+
slot: SearchEnhancedBatchSlot,
|
|
237
|
+
): slot is SearchEnhancedBatchErrorSlot {
|
|
238
|
+
return (
|
|
239
|
+
typeof (slot as SearchEnhancedBatchErrorSlot).error === 'object' &&
|
|
240
|
+
(slot as SearchEnhancedBatchErrorSlot).error !== null
|
|
241
|
+
);
|
|
242
|
+
}
|
|
@@ -32,6 +32,11 @@ export class ListChatSessionsDto extends UserAuthDto {
|
|
|
32
32
|
@IsOptional()
|
|
33
33
|
@Min(0)
|
|
34
34
|
offset?: number;
|
|
35
|
+
|
|
36
|
+
/** Filter sessions by roomId. When set, only sessions in this room are returned. */
|
|
37
|
+
@IsString()
|
|
38
|
+
@IsOptional()
|
|
39
|
+
roomId?: string;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
export class CreateChatSessionDto extends UserAuthDto {
|
|
@@ -50,6 +55,31 @@ export class CreateChatSessionDto extends UserAuthDto {
|
|
|
50
55
|
@IsString()
|
|
51
56
|
@IsOptional()
|
|
52
57
|
slackThreadTs?: string;
|
|
58
|
+
|
|
59
|
+
@IsString()
|
|
60
|
+
@IsOptional()
|
|
61
|
+
oracleToken?: string;
|
|
62
|
+
|
|
63
|
+
@IsString()
|
|
64
|
+
@IsOptional()
|
|
65
|
+
userToken?: string;
|
|
66
|
+
|
|
67
|
+
@IsString()
|
|
68
|
+
@IsOptional()
|
|
69
|
+
oracleHomeServer?: string;
|
|
70
|
+
|
|
71
|
+
@IsString()
|
|
72
|
+
@IsOptional()
|
|
73
|
+
userHomeServer?: string;
|
|
74
|
+
|
|
75
|
+
@IsString()
|
|
76
|
+
@IsOptional()
|
|
77
|
+
ucanInvocation?: string;
|
|
78
|
+
|
|
79
|
+
/** Override the roomId stored on the session (e.g. task-specific room). */
|
|
80
|
+
@IsString()
|
|
81
|
+
@IsOptional()
|
|
82
|
+
roomId?: string;
|
|
53
83
|
}
|
|
54
84
|
|
|
55
85
|
export class DeleteChatSessionDto extends UserAuthDto {
|