@subcortex-ai/sdk 0.1.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/LICENSE +191 -0
- package/README.md +259 -0
- package/dist/index.cjs +1694 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1447 -0
- package/dist/index.d.ts +1447 -0
- package/dist/index.js +1622 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1694 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AgentsNamespace: () => AgentsNamespace,
|
|
24
|
+
AssertionsNamespace: () => AssertionsNamespace,
|
|
25
|
+
CONTEXT_SCHEMA_VERSION: () => CONTEXT_SCHEMA_VERSION,
|
|
26
|
+
ConfidenceLevel: () => ConfidenceLevel,
|
|
27
|
+
ConfidenceScores: () => ConfidenceScores,
|
|
28
|
+
EntityPredicate: () => EntityPredicate,
|
|
29
|
+
EntityRelationship: () => EntityRelationship,
|
|
30
|
+
EventPredicate: () => EventPredicate,
|
|
31
|
+
IdentityPredicate: () => IdentityPredicate,
|
|
32
|
+
IntakeNamespace: () => IntakeNamespace,
|
|
33
|
+
MULTI_VALUE_PREDICATES: () => MULTI_VALUE_PREDICATES,
|
|
34
|
+
MemoryNamespace: () => MemoryNamespace,
|
|
35
|
+
MemoryPredicate: () => MemoryPredicate,
|
|
36
|
+
NEGATIVE_SIGNALS: () => NEGATIVE_SIGNALS,
|
|
37
|
+
OrgRelationship: () => OrgRelationship,
|
|
38
|
+
POSITIVE_SIGNALS: () => POSITIVE_SIGNALS,
|
|
39
|
+
Predicates: () => Predicates,
|
|
40
|
+
RELATIONSHIP_LABELS: () => RELATIONSHIP_LABELS,
|
|
41
|
+
REVERSE_RELATIONSHIPS: () => REVERSE_RELATIONSHIPS,
|
|
42
|
+
RapportPredicate: () => RapportPredicate,
|
|
43
|
+
RelationshipTypes: () => RelationshipTypes,
|
|
44
|
+
RelationshipsNamespace: () => RelationshipsNamespace,
|
|
45
|
+
SIGNAL_DECAY_CONFIG: () => SIGNAL_DECAY_CONFIG,
|
|
46
|
+
SYSTEM_SIGNAL_TYPES: () => SYSTEM_SIGNAL_TYPES,
|
|
47
|
+
SignalsNamespace: () => SignalsNamespace,
|
|
48
|
+
SubCortexAuthenticationError: () => SubCortexAuthenticationError,
|
|
49
|
+
SubCortexAuthorizationError: () => SubCortexAuthorizationError,
|
|
50
|
+
SubCortexClient: () => SubCortexClient,
|
|
51
|
+
SubCortexConflictError: () => SubCortexConflictError,
|
|
52
|
+
SubCortexError: () => SubCortexError,
|
|
53
|
+
SubCortexNetworkError: () => SubCortexNetworkError,
|
|
54
|
+
SubCortexNotFoundError: () => SubCortexNotFoundError,
|
|
55
|
+
SubCortexRateLimitError: () => SubCortexRateLimitError,
|
|
56
|
+
SubCortexServerError: () => SubCortexServerError,
|
|
57
|
+
SubCortexTimeoutError: () => SubCortexTimeoutError,
|
|
58
|
+
SubCortexValidationError: () => SubCortexValidationError,
|
|
59
|
+
SubjectPrefix: () => SubjectPrefix,
|
|
60
|
+
UsersNamespace: () => UsersNamespace,
|
|
61
|
+
WorkPredicate: () => WorkPredicate,
|
|
62
|
+
confidenceToScore: () => confidenceToScore,
|
|
63
|
+
formatContext: () => formatContext,
|
|
64
|
+
getDecayHalfLife: () => getDecayHalfLife,
|
|
65
|
+
isValidSignalType: () => isValidSignalType,
|
|
66
|
+
scoreToConfidence: () => scoreToConfidence,
|
|
67
|
+
subject: () => subject,
|
|
68
|
+
toContextXml: () => toContextXml
|
|
69
|
+
});
|
|
70
|
+
module.exports = __toCommonJS(index_exports);
|
|
71
|
+
|
|
72
|
+
// src/errors.ts
|
|
73
|
+
var SubCortexError = class extends Error {
|
|
74
|
+
/** HTTP status code (0 for network errors) */
|
|
75
|
+
statusCode;
|
|
76
|
+
/** Server-assigned request ID for debugging */
|
|
77
|
+
requestId;
|
|
78
|
+
/** Whether the request can be retried */
|
|
79
|
+
retryable;
|
|
80
|
+
/** Raw response body */
|
|
81
|
+
body;
|
|
82
|
+
constructor(message, statusCode, options) {
|
|
83
|
+
super(message);
|
|
84
|
+
this.name = "SubCortexError";
|
|
85
|
+
this.statusCode = statusCode;
|
|
86
|
+
this.requestId = options?.requestId;
|
|
87
|
+
this.retryable = options?.retryable ?? false;
|
|
88
|
+
this.body = options?.body;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
var SubCortexValidationError = class extends SubCortexError {
|
|
92
|
+
/** Field-level validation errors if available */
|
|
93
|
+
details;
|
|
94
|
+
constructor(message, options) {
|
|
95
|
+
super(message, 400, { ...options, retryable: false });
|
|
96
|
+
this.name = "SubCortexValidationError";
|
|
97
|
+
this.details = options?.details;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
var SubCortexAuthenticationError = class extends SubCortexError {
|
|
101
|
+
constructor(message, options) {
|
|
102
|
+
super(message, 401, { ...options, retryable: false });
|
|
103
|
+
this.name = "SubCortexAuthenticationError";
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var SubCortexAuthorizationError = class extends SubCortexError {
|
|
107
|
+
constructor(message, options) {
|
|
108
|
+
super(message, 403, { ...options, retryable: false });
|
|
109
|
+
this.name = "SubCortexAuthorizationError";
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
var SubCortexNotFoundError = class extends SubCortexError {
|
|
113
|
+
constructor(message, options) {
|
|
114
|
+
super(message, 404, { ...options, retryable: false });
|
|
115
|
+
this.name = "SubCortexNotFoundError";
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
var SubCortexConflictError = class extends SubCortexError {
|
|
119
|
+
constructor(message, options) {
|
|
120
|
+
super(message, 409, { ...options, retryable: false });
|
|
121
|
+
this.name = "SubCortexConflictError";
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
var SubCortexRateLimitError = class extends SubCortexError {
|
|
125
|
+
/** Seconds to wait before retrying */
|
|
126
|
+
retryAfter;
|
|
127
|
+
constructor(message, options) {
|
|
128
|
+
super(message, 429, { ...options, retryable: true });
|
|
129
|
+
this.name = "SubCortexRateLimitError";
|
|
130
|
+
this.retryAfter = options?.retryAfter;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
var SubCortexServerError = class extends SubCortexError {
|
|
134
|
+
constructor(message, statusCode, options) {
|
|
135
|
+
super(message, statusCode, { ...options, retryable: true });
|
|
136
|
+
this.name = "SubCortexServerError";
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
var SubCortexNetworkError = class extends SubCortexError {
|
|
140
|
+
cause;
|
|
141
|
+
constructor(message, options) {
|
|
142
|
+
super(message, 0, { retryable: true });
|
|
143
|
+
this.name = "SubCortexNetworkError";
|
|
144
|
+
this.cause = options?.cause;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
var SubCortexTimeoutError = class extends SubCortexNetworkError {
|
|
148
|
+
constructor(timeoutMs) {
|
|
149
|
+
super(`Request timed out after ${timeoutMs}ms`);
|
|
150
|
+
this.name = "SubCortexTimeoutError";
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
function classifyError(statusCode, body, requestId, retryAfterHint) {
|
|
154
|
+
let errorCode = "";
|
|
155
|
+
let message = "";
|
|
156
|
+
let details;
|
|
157
|
+
try {
|
|
158
|
+
const parsed = JSON.parse(body);
|
|
159
|
+
if (parsed.error) {
|
|
160
|
+
errorCode = parsed.error.code || "";
|
|
161
|
+
message = parsed.error.message || "";
|
|
162
|
+
if (parsed.error.details) {
|
|
163
|
+
details = parsed.error.details;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
} catch {
|
|
167
|
+
}
|
|
168
|
+
if (!message) {
|
|
169
|
+
message = body || `HTTP ${statusCode}`;
|
|
170
|
+
}
|
|
171
|
+
const opts = { requestId, body };
|
|
172
|
+
switch (statusCode) {
|
|
173
|
+
case 400:
|
|
174
|
+
return new SubCortexValidationError(message, { ...opts, details });
|
|
175
|
+
case 401:
|
|
176
|
+
return new SubCortexAuthenticationError(message, opts);
|
|
177
|
+
case 403:
|
|
178
|
+
return new SubCortexAuthorizationError(message, opts);
|
|
179
|
+
case 404:
|
|
180
|
+
return new SubCortexNotFoundError(message, opts);
|
|
181
|
+
case 409:
|
|
182
|
+
return new SubCortexConflictError(message, opts);
|
|
183
|
+
case 429: {
|
|
184
|
+
let retryAfter = retryAfterHint;
|
|
185
|
+
if (retryAfter === void 0) {
|
|
186
|
+
try {
|
|
187
|
+
const parsed = JSON.parse(body);
|
|
188
|
+
retryAfter = parsed.retryAfter ?? parsed.retry_after;
|
|
189
|
+
} catch {
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return new SubCortexRateLimitError(message, { ...opts, retryAfter });
|
|
193
|
+
}
|
|
194
|
+
default:
|
|
195
|
+
if (statusCode >= 500) {
|
|
196
|
+
return new SubCortexServerError(message, statusCode, opts);
|
|
197
|
+
}
|
|
198
|
+
return new SubCortexError(message, statusCode, opts);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// src/http.ts
|
|
203
|
+
function snakeToCamel(s) {
|
|
204
|
+
return s.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
205
|
+
}
|
|
206
|
+
function camelToSnake(s) {
|
|
207
|
+
return s.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
|
|
208
|
+
}
|
|
209
|
+
function mapKeys(obj, mapper) {
|
|
210
|
+
if (obj === null || obj === void 0) return obj;
|
|
211
|
+
if (Array.isArray(obj)) return obj.map((item) => mapKeys(item, mapper));
|
|
212
|
+
if (typeof obj === "object") {
|
|
213
|
+
const mapped = {};
|
|
214
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
215
|
+
mapped[mapper(key)] = mapKeys(value, mapper);
|
|
216
|
+
}
|
|
217
|
+
return mapped;
|
|
218
|
+
}
|
|
219
|
+
return obj;
|
|
220
|
+
}
|
|
221
|
+
function fromWire(data) {
|
|
222
|
+
return mapKeys(data, snakeToCamel);
|
|
223
|
+
}
|
|
224
|
+
function toWire(data) {
|
|
225
|
+
return mapKeys(data, camelToSnake);
|
|
226
|
+
}
|
|
227
|
+
var counter = 0;
|
|
228
|
+
function generateRequestId() {
|
|
229
|
+
const ts = Date.now().toString(36);
|
|
230
|
+
const seq = (counter++).toString(36);
|
|
231
|
+
const rand = Math.random().toString(36).slice(2, 6);
|
|
232
|
+
return `scx-${ts}-${seq}-${rand}`;
|
|
233
|
+
}
|
|
234
|
+
function sleep(ms) {
|
|
235
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
236
|
+
}
|
|
237
|
+
function computeDelay(attempt, config) {
|
|
238
|
+
const exponential = config.baseDelayMs * Math.pow(2, attempt);
|
|
239
|
+
const capped = Math.min(exponential, config.maxDelayMs);
|
|
240
|
+
const jitter = capped * (0.5 + Math.random());
|
|
241
|
+
return Math.round(jitter);
|
|
242
|
+
}
|
|
243
|
+
function isRetryable(status) {
|
|
244
|
+
return status === 429 || status >= 500;
|
|
245
|
+
}
|
|
246
|
+
var HttpTransport = class {
|
|
247
|
+
opts;
|
|
248
|
+
constructor(options) {
|
|
249
|
+
this.opts = {
|
|
250
|
+
...options,
|
|
251
|
+
baseUrl: options.baseUrl.replace(/\/$/, "")
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
/** GET request with retry and typed response. */
|
|
255
|
+
async get(path, tenantId) {
|
|
256
|
+
return this.request("GET", path, void 0, tenantId);
|
|
257
|
+
}
|
|
258
|
+
/** POST request with retry and typed response. */
|
|
259
|
+
async post(path, body, tenantId) {
|
|
260
|
+
return this.request("POST", path, body, tenantId);
|
|
261
|
+
}
|
|
262
|
+
/** PUT request with retry and typed response. */
|
|
263
|
+
async put(path, body, tenantId) {
|
|
264
|
+
return this.request("PUT", path, body, tenantId);
|
|
265
|
+
}
|
|
266
|
+
/** DELETE request with retry and typed response. */
|
|
267
|
+
async delete(path, tenantId) {
|
|
268
|
+
return this.request("DELETE", path, void 0, tenantId);
|
|
269
|
+
}
|
|
270
|
+
/** Core request method with retry loop. */
|
|
271
|
+
async request(method, path, body, tenantIdOverride) {
|
|
272
|
+
const url = `${this.opts.baseUrl}${path}`;
|
|
273
|
+
const requestId = generateRequestId();
|
|
274
|
+
const tenantId = tenantIdOverride || this.opts.tenantId;
|
|
275
|
+
const headers = {
|
|
276
|
+
Accept: "application/json",
|
|
277
|
+
"X-Request-ID": requestId,
|
|
278
|
+
"X-Tenant-ID": tenantId,
|
|
279
|
+
...this.opts.headers
|
|
280
|
+
};
|
|
281
|
+
if (body !== void 0) {
|
|
282
|
+
headers["Content-Type"] = "application/json";
|
|
283
|
+
}
|
|
284
|
+
if (this.opts.apiKey) {
|
|
285
|
+
headers["Authorization"] = `Bearer ${this.opts.apiKey}`;
|
|
286
|
+
} else if (this.opts.token) {
|
|
287
|
+
headers["Authorization"] = `Bearer ${this.opts.token}`;
|
|
288
|
+
}
|
|
289
|
+
const fetchOpts = {
|
|
290
|
+
method,
|
|
291
|
+
headers,
|
|
292
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
293
|
+
};
|
|
294
|
+
let lastError;
|
|
295
|
+
for (let attempt = 0; attempt <= this.opts.retry.maxRetries; attempt++) {
|
|
296
|
+
try {
|
|
297
|
+
const response = await this.fetchWithTimeout(url, fetchOpts);
|
|
298
|
+
if (response.ok) {
|
|
299
|
+
const text = await response.text();
|
|
300
|
+
if (!text) return void 0;
|
|
301
|
+
const parsed = JSON.parse(text);
|
|
302
|
+
return fromWire(parsed);
|
|
303
|
+
}
|
|
304
|
+
const responseBody = await response.text();
|
|
305
|
+
if (response.status === 429) {
|
|
306
|
+
const retryAfterRaw = response.headers.get("Retry-After");
|
|
307
|
+
const retryAfterSecs = retryAfterRaw ? parseInt(retryAfterRaw, 10) : 0;
|
|
308
|
+
if (attempt < this.opts.retry.maxRetries) {
|
|
309
|
+
const delay = retryAfterSecs > 0 ? retryAfterSecs * 1e3 : computeDelay(attempt, this.opts.retry);
|
|
310
|
+
await sleep(delay);
|
|
311
|
+
lastError = classifyError(response.status, responseBody, requestId, retryAfterSecs || void 0);
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
throw classifyError(response.status, responseBody, requestId, retryAfterSecs || void 0);
|
|
315
|
+
}
|
|
316
|
+
if (isRetryable(response.status) && attempt < this.opts.retry.maxRetries) {
|
|
317
|
+
lastError = classifyError(response.status, responseBody, requestId);
|
|
318
|
+
await sleep(computeDelay(attempt, this.opts.retry));
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
throw classifyError(response.status, responseBody, requestId);
|
|
322
|
+
} catch (error) {
|
|
323
|
+
if (error instanceof Error && error.name.startsWith("SubCortex")) {
|
|
324
|
+
if (!error.retryable || attempt >= this.opts.retry.maxRetries) {
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
327
|
+
lastError = error;
|
|
328
|
+
await sleep(computeDelay(attempt, this.opts.retry));
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if (error instanceof TypeError || error instanceof DOMException) {
|
|
332
|
+
lastError = new SubCortexNetworkError(
|
|
333
|
+
`Network error: ${error.message}`,
|
|
334
|
+
{ cause: error }
|
|
335
|
+
);
|
|
336
|
+
if (attempt < this.opts.retry.maxRetries) {
|
|
337
|
+
await sleep(computeDelay(attempt, this.opts.retry));
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
throw lastError;
|
|
341
|
+
}
|
|
342
|
+
throw error;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
throw lastError || new SubCortexNetworkError("Request failed after all retries");
|
|
346
|
+
}
|
|
347
|
+
/** Fetch with AbortController timeout. */
|
|
348
|
+
async fetchWithTimeout(url, init) {
|
|
349
|
+
const controller = new AbortController();
|
|
350
|
+
const timeoutId = setTimeout(
|
|
351
|
+
() => controller.abort(),
|
|
352
|
+
this.opts.timeoutMs
|
|
353
|
+
);
|
|
354
|
+
if (this.opts.signal) {
|
|
355
|
+
this.opts.signal.addEventListener("abort", () => controller.abort());
|
|
356
|
+
}
|
|
357
|
+
try {
|
|
358
|
+
return await this.opts.fetchImpl(url, {
|
|
359
|
+
...init,
|
|
360
|
+
signal: controller.signal
|
|
361
|
+
});
|
|
362
|
+
} catch (error) {
|
|
363
|
+
if (error instanceof DOMException && error.name === "AbortError" && !this.opts.signal?.aborted) {
|
|
364
|
+
throw new SubCortexTimeoutError(this.opts.timeoutMs);
|
|
365
|
+
}
|
|
366
|
+
throw error;
|
|
367
|
+
} finally {
|
|
368
|
+
clearTimeout(timeoutId);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
// src/types/schema.ts
|
|
374
|
+
var SubjectPrefix = /* @__PURE__ */ ((SubjectPrefix2) => {
|
|
375
|
+
SubjectPrefix2["USER"] = "user";
|
|
376
|
+
SubjectPrefix2["PERSON"] = "person";
|
|
377
|
+
SubjectPrefix2["ROLE"] = "role";
|
|
378
|
+
SubjectPrefix2["ENTITY"] = "entity";
|
|
379
|
+
SubjectPrefix2["PROPERTY"] = "property";
|
|
380
|
+
SubjectPrefix2["PROJECT"] = "project";
|
|
381
|
+
SubjectPrefix2["EVENT"] = "event";
|
|
382
|
+
SubjectPrefix2["AGENT"] = "agent";
|
|
383
|
+
return SubjectPrefix2;
|
|
384
|
+
})(SubjectPrefix || {});
|
|
385
|
+
var TITLE_NORMALIZATIONS = [
|
|
386
|
+
[/\bvp\b/gi, "Vice President"],
|
|
387
|
+
[/\bsvp\b/gi, "Senior Vice President"],
|
|
388
|
+
[/\bevp\b/gi, "Executive Vice President"],
|
|
389
|
+
[/\bcto\b/gi, "Chief Technology Officer"],
|
|
390
|
+
[/\bceo\b/gi, "Chief Executive Officer"],
|
|
391
|
+
[/\bcfo\b/gi, "Chief Financial Officer"],
|
|
392
|
+
[/\bcoo\b/gi, "Chief Operating Officer"],
|
|
393
|
+
[/\bcmo\b/gi, "Chief Marketing Officer"],
|
|
394
|
+
[/\bcpo\b/gi, "Chief Product Officer"],
|
|
395
|
+
[/\bcio\b/gi, "Chief Information Officer"],
|
|
396
|
+
[/\bea\b/gi, "Executive Assistant"],
|
|
397
|
+
[/\bpm\b/gi, "Project Manager"],
|
|
398
|
+
[/\bdir\b/gi, "Director"],
|
|
399
|
+
[/\bsr\b/gi, "Senior"],
|
|
400
|
+
[/\bjr\b/gi, "Junior"]
|
|
401
|
+
];
|
|
402
|
+
function subject(prefix, identifier) {
|
|
403
|
+
let expanded = identifier;
|
|
404
|
+
if (prefix === "role" /* ROLE */ || prefix === "role") {
|
|
405
|
+
for (const [pattern, replacement] of TITLE_NORMALIZATIONS) {
|
|
406
|
+
expanded = expanded.replace(pattern, replacement);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
const normalized = expanded.toLowerCase().replace(/\s+/g, "-");
|
|
410
|
+
return `${prefix}:${normalized}`;
|
|
411
|
+
}
|
|
412
|
+
var IdentityPredicate = /* @__PURE__ */ ((IdentityPredicate2) => {
|
|
413
|
+
IdentityPredicate2["NAME"] = "name";
|
|
414
|
+
IdentityPredicate2["FULL_NAME"] = "full_name";
|
|
415
|
+
IdentityPredicate2["ROLE"] = "role";
|
|
416
|
+
IdentityPredicate2["TITLE"] = "title";
|
|
417
|
+
IdentityPredicate2["DEPARTMENT"] = "department";
|
|
418
|
+
IdentityPredicate2["TEAM"] = "team";
|
|
419
|
+
IdentityPredicate2["START_DATE"] = "start_date";
|
|
420
|
+
IdentityPredicate2["EMAIL"] = "email";
|
|
421
|
+
return IdentityPredicate2;
|
|
422
|
+
})(IdentityPredicate || {});
|
|
423
|
+
var WorkPredicate = /* @__PURE__ */ ((WorkPredicate2) => {
|
|
424
|
+
WorkPredicate2["EXPERTISE"] = "expertise";
|
|
425
|
+
WorkPredicate2["CURRENT_PROJECT"] = "current_project";
|
|
426
|
+
WorkPredicate2["PAIN_POINT"] = "pain_point";
|
|
427
|
+
return WorkPredicate2;
|
|
428
|
+
})(WorkPredicate || {});
|
|
429
|
+
var EventPredicate = /* @__PURE__ */ ((EventPredicate2) => {
|
|
430
|
+
EventPredicate2["STATUS"] = "status";
|
|
431
|
+
EventPredicate2["STATUS_CHANGE"] = "status_change";
|
|
432
|
+
EventPredicate2["EVENT"] = "event";
|
|
433
|
+
EventPredicate2["DECISION"] = "decision";
|
|
434
|
+
EventPredicate2["OUTCOME"] = "outcome";
|
|
435
|
+
return EventPredicate2;
|
|
436
|
+
})(EventPredicate || {});
|
|
437
|
+
var RapportPredicate = /* @__PURE__ */ ((RapportPredicate2) => {
|
|
438
|
+
RapportPredicate2["SENTIMENT"] = "sentiment";
|
|
439
|
+
RapportPredicate2["FRUSTRATION"] = "frustration";
|
|
440
|
+
RapportPredicate2["EXCITEMENT"] = "excitement";
|
|
441
|
+
RapportPredicate2["CONCERN"] = "concern";
|
|
442
|
+
RapportPredicate2["GOAL"] = "goal";
|
|
443
|
+
RapportPredicate2["ASPIRATION"] = "aspiration";
|
|
444
|
+
RapportPredicate2["PREFERENCE"] = "preference";
|
|
445
|
+
RapportPredicate2["PAIN_POINT"] = "pain_point";
|
|
446
|
+
RapportPredicate2["INTEREST"] = "interest";
|
|
447
|
+
RapportPredicate2["COMMUNICATION_STYLE"] = "communication_style";
|
|
448
|
+
return RapportPredicate2;
|
|
449
|
+
})(RapportPredicate || {});
|
|
450
|
+
var MemoryPredicate = /* @__PURE__ */ ((MemoryPredicate2) => {
|
|
451
|
+
MemoryPredicate2["REMINDER"] = "reminder";
|
|
452
|
+
MemoryPredicate2["CONTEXT"] = "context";
|
|
453
|
+
MemoryPredicate2["CONTEXT_TASK"] = "context:task";
|
|
454
|
+
MemoryPredicate2["CURRENT_PROJECT"] = "current_project";
|
|
455
|
+
return MemoryPredicate2;
|
|
456
|
+
})(MemoryPredicate || {});
|
|
457
|
+
var EntityPredicate = /* @__PURE__ */ ((EntityPredicate2) => {
|
|
458
|
+
EntityPredicate2["TYPE"] = "type";
|
|
459
|
+
EntityPredicate2["DESCRIPTION"] = "description";
|
|
460
|
+
EntityPredicate2["FIELD_TYPE"] = "field_type";
|
|
461
|
+
EntityPredicate2["REQUIRED"] = "required";
|
|
462
|
+
EntityPredicate2["WORKFLOW"] = "workflow";
|
|
463
|
+
return EntityPredicate2;
|
|
464
|
+
})(EntityPredicate || {});
|
|
465
|
+
var Predicates = {
|
|
466
|
+
...IdentityPredicate,
|
|
467
|
+
...WorkPredicate,
|
|
468
|
+
...EventPredicate,
|
|
469
|
+
...RapportPredicate,
|
|
470
|
+
...MemoryPredicate,
|
|
471
|
+
...EntityPredicate
|
|
472
|
+
};
|
|
473
|
+
var OrgRelationship = /* @__PURE__ */ ((OrgRelationship2) => {
|
|
474
|
+
OrgRelationship2["REPORTS_TO"] = "reports_to";
|
|
475
|
+
OrgRelationship2["MANAGES"] = "manages";
|
|
476
|
+
OrgRelationship2["MEMBER_OF"] = "member_of";
|
|
477
|
+
OrgRelationship2["HAS_MEMBER"] = "has_member";
|
|
478
|
+
OrgRelationship2["HOLDS_ROLE"] = "holds_role";
|
|
479
|
+
OrgRelationship2["CANDIDATE_FOR"] = "candidate_for";
|
|
480
|
+
OrgRelationship2["COLLABORATES_WITH"] = "collaborates_with";
|
|
481
|
+
OrgRelationship2["MENTORS"] = "mentors";
|
|
482
|
+
OrgRelationship2["MENTORED_BY"] = "mentored_by";
|
|
483
|
+
OrgRelationship2["STAKEHOLDER_IN"] = "stakeholder_in";
|
|
484
|
+
return OrgRelationship2;
|
|
485
|
+
})(OrgRelationship || {});
|
|
486
|
+
var EntityRelationship = /* @__PURE__ */ ((EntityRelationship2) => {
|
|
487
|
+
EntityRelationship2["HAS_PROPERTY"] = "has_property";
|
|
488
|
+
EntityRelationship2["BELONGS_TO"] = "belongs_to";
|
|
489
|
+
EntityRelationship2["HAS_MANY"] = "has_many";
|
|
490
|
+
EntityRelationship2["MANY_TO_MANY"] = "many_to_many";
|
|
491
|
+
EntityRelationship2["DEPENDS_ON"] = "depends_on";
|
|
492
|
+
return EntityRelationship2;
|
|
493
|
+
})(EntityRelationship || {});
|
|
494
|
+
var RelationshipTypes = {
|
|
495
|
+
...OrgRelationship,
|
|
496
|
+
...EntityRelationship
|
|
497
|
+
};
|
|
498
|
+
var ConfidenceLevel = /* @__PURE__ */ ((ConfidenceLevel2) => {
|
|
499
|
+
ConfidenceLevel2["CONFIRMED"] = "confirmed";
|
|
500
|
+
ConfidenceLevel2["HIGH"] = "high";
|
|
501
|
+
ConfidenceLevel2["MODERATE"] = "moderate";
|
|
502
|
+
ConfidenceLevel2["LOW"] = "low";
|
|
503
|
+
return ConfidenceLevel2;
|
|
504
|
+
})(ConfidenceLevel || {});
|
|
505
|
+
var ConfidenceScores = {
|
|
506
|
+
["confirmed" /* CONFIRMED */]: 0.99,
|
|
507
|
+
["high" /* HIGH */]: 0.85,
|
|
508
|
+
["moderate" /* MODERATE */]: 0.65,
|
|
509
|
+
["low" /* LOW */]: 0.4
|
|
510
|
+
};
|
|
511
|
+
function confidenceToScore(level) {
|
|
512
|
+
return ConfidenceScores[level] ?? 0.7;
|
|
513
|
+
}
|
|
514
|
+
function scoreToConfidence(score) {
|
|
515
|
+
if (score >= 0.95) return "confirmed" /* CONFIRMED */;
|
|
516
|
+
if (score >= 0.8) return "high" /* HIGH */;
|
|
517
|
+
if (score >= 0.6) return "moderate" /* MODERATE */;
|
|
518
|
+
return "low" /* LOW */;
|
|
519
|
+
}
|
|
520
|
+
var MULTI_VALUE_PREDICATES = /* @__PURE__ */ new Set([
|
|
521
|
+
// Events — multiple things happen over time
|
|
522
|
+
"status_change" /* STATUS_CHANGE */,
|
|
523
|
+
"event" /* EVENT */,
|
|
524
|
+
"decision" /* DECISION */,
|
|
525
|
+
"outcome" /* OUTCOME */,
|
|
526
|
+
// Emotional — multiple sentiments about different things
|
|
527
|
+
"sentiment" /* SENTIMENT */,
|
|
528
|
+
"frustration" /* FRUSTRATION */,
|
|
529
|
+
"excitement" /* EXCITEMENT */,
|
|
530
|
+
"concern" /* CONCERN */,
|
|
531
|
+
"goal" /* GOAL */,
|
|
532
|
+
"interest" /* INTEREST */,
|
|
533
|
+
// Memory — multiple reminders, contexts, projects
|
|
534
|
+
"reminder" /* REMINDER */,
|
|
535
|
+
"context:task" /* CONTEXT_TASK */,
|
|
536
|
+
"current_project" /* CURRENT_PROJECT */,
|
|
537
|
+
// Timeline
|
|
538
|
+
"timeline"
|
|
539
|
+
]);
|
|
540
|
+
var REVERSE_RELATIONSHIPS = {
|
|
541
|
+
// Proper OrgRelationship values
|
|
542
|
+
["reports_to" /* REPORTS_TO */]: "manages" /* MANAGES */,
|
|
543
|
+
["manages" /* MANAGES */]: "reports_to" /* REPORTS_TO */,
|
|
544
|
+
["member_of" /* MEMBER_OF */]: "has_member" /* HAS_MEMBER */,
|
|
545
|
+
["has_member" /* HAS_MEMBER */]: "member_of" /* MEMBER_OF */,
|
|
546
|
+
["mentors" /* MENTORS */]: "mentored_by" /* MENTORED_BY */,
|
|
547
|
+
["mentored_by" /* MENTORED_BY */]: "mentors" /* MENTORS */,
|
|
548
|
+
["collaborates_with" /* COLLABORATES_WITH */]: "collaborates_with" /* COLLABORATES_WITH */,
|
|
549
|
+
["candidate_for" /* CANDIDATE_FOR */]: "candidate_for" /* CANDIDATE_FOR */,
|
|
550
|
+
["stakeholder_in" /* STAKEHOLDER_IN */]: "stakeholder_in" /* STAKEHOLDER_IN */,
|
|
551
|
+
// Agent-facing predicate names → proper relationship types
|
|
552
|
+
// The model sends 'direct_report' as predicate, SDK maps to proper relationships
|
|
553
|
+
"direct_report": "reports_to" /* REPORTS_TO */,
|
|
554
|
+
"team_member": "member_of" /* MEMBER_OF */,
|
|
555
|
+
"candidate": "candidate_for" /* CANDIDATE_FOR */,
|
|
556
|
+
"manager": "manages" /* MANAGES */,
|
|
557
|
+
"stakeholder": "stakeholder_in" /* STAKEHOLDER_IN */,
|
|
558
|
+
"collaborator": "collaborates_with" /* COLLABORATES_WITH */,
|
|
559
|
+
"mentor": "mentored_by" /* MENTORED_BY */
|
|
560
|
+
};
|
|
561
|
+
var RELATIONSHIP_LABELS = {
|
|
562
|
+
["reports_to" /* REPORTS_TO */]: "reports to (person is a direct report)",
|
|
563
|
+
["manages" /* MANAGES */]: "manages (user is the manager)",
|
|
564
|
+
["member_of" /* MEMBER_OF */]: "is a member of (team, project)",
|
|
565
|
+
["holds_role" /* HOLDS_ROLE */]: "holds a role/position",
|
|
566
|
+
["candidate_for" /* CANDIDATE_FOR */]: "is a candidate for a role",
|
|
567
|
+
["collaborates_with" /* COLLABORATES_WITH */]: "collaborates with",
|
|
568
|
+
["mentors" /* MENTORS */]: "mentors",
|
|
569
|
+
["stakeholder_in" /* STAKEHOLDER_IN */]: "is a stakeholder in"
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
// src/types/signals.ts
|
|
573
|
+
var SYSTEM_SIGNAL_TYPES = [
|
|
574
|
+
"frustration",
|
|
575
|
+
"excitement",
|
|
576
|
+
"concern",
|
|
577
|
+
"satisfaction",
|
|
578
|
+
"confusion",
|
|
579
|
+
"gratitude",
|
|
580
|
+
"tension",
|
|
581
|
+
"sentiment"
|
|
582
|
+
];
|
|
583
|
+
function isValidSignalType(type) {
|
|
584
|
+
if (SYSTEM_SIGNAL_TYPES.includes(type)) return true;
|
|
585
|
+
if (type.startsWith("custom:")) return true;
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
588
|
+
var SIGNAL_DECAY_CONFIG = {
|
|
589
|
+
frustration: 24,
|
|
590
|
+
excitement: 24,
|
|
591
|
+
concern: 24,
|
|
592
|
+
satisfaction: 24,
|
|
593
|
+
confusion: 24,
|
|
594
|
+
gratitude: 24,
|
|
595
|
+
tension: 24,
|
|
596
|
+
sentiment: 24,
|
|
597
|
+
_default: 24
|
|
598
|
+
};
|
|
599
|
+
function getDecayHalfLife(signalType) {
|
|
600
|
+
return SIGNAL_DECAY_CONFIG[signalType] ?? SIGNAL_DECAY_CONFIG._default;
|
|
601
|
+
}
|
|
602
|
+
var POSITIVE_SIGNALS = /* @__PURE__ */ new Set([
|
|
603
|
+
"satisfaction",
|
|
604
|
+
"excitement",
|
|
605
|
+
"gratitude"
|
|
606
|
+
]);
|
|
607
|
+
var NEGATIVE_SIGNALS = /* @__PURE__ */ new Set([
|
|
608
|
+
"frustration",
|
|
609
|
+
"concern",
|
|
610
|
+
"tension",
|
|
611
|
+
"confusion"
|
|
612
|
+
]);
|
|
613
|
+
|
|
614
|
+
// src/signals.ts
|
|
615
|
+
var LEGACY_SIGNAL_PREDICATES = /* @__PURE__ */ new Set([
|
|
616
|
+
"sentiment",
|
|
617
|
+
"frustration",
|
|
618
|
+
"excitement",
|
|
619
|
+
"concern",
|
|
620
|
+
"goal",
|
|
621
|
+
"aspiration",
|
|
622
|
+
"preference",
|
|
623
|
+
"interest"
|
|
624
|
+
]);
|
|
625
|
+
var SignalsNamespace = class {
|
|
626
|
+
constructor(http, tenantId) {
|
|
627
|
+
this.http = http;
|
|
628
|
+
this.tenantId = tenantId;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Record an emotional signal about a user.
|
|
632
|
+
*
|
|
633
|
+
* @example
|
|
634
|
+
* ```typescript
|
|
635
|
+
* await brain.signals.record({
|
|
636
|
+
* userId: 'cmk123',
|
|
637
|
+
* type: 'frustration',
|
|
638
|
+
* content: 'Frustrated about the hiring timeline',
|
|
639
|
+
* intensity: 0.85,
|
|
640
|
+
* aboutSubject: 'context:hiring-ea',
|
|
641
|
+
* })
|
|
642
|
+
* ```
|
|
643
|
+
*/
|
|
644
|
+
async record(input) {
|
|
645
|
+
if (!isValidSignalType(input.type)) {
|
|
646
|
+
throw new Error(`Invalid signal type: ${input.type}. Use one of: ${SYSTEM_SIGNAL_TYPES.join(", ")} or custom:{tenant}:{type}`);
|
|
647
|
+
}
|
|
648
|
+
const userSubject = subject("user" /* USER */, input.userId);
|
|
649
|
+
const predicate = `signal:${input.type}`;
|
|
650
|
+
const value = {
|
|
651
|
+
content: input.content,
|
|
652
|
+
intensity: input.intensity ?? 0.7,
|
|
653
|
+
about_subject: input.aboutSubject || null,
|
|
654
|
+
session_id: input.sessionId || null
|
|
655
|
+
};
|
|
656
|
+
const result = await this.http.post("/api/v1/assertions", {
|
|
657
|
+
tenant_id: this.tenantId,
|
|
658
|
+
subject: userSubject,
|
|
659
|
+
predicate,
|
|
660
|
+
value,
|
|
661
|
+
confidence: input.intensity ?? 0.7
|
|
662
|
+
});
|
|
663
|
+
let resolved = 0;
|
|
664
|
+
if (input.resolveConflicting && POSITIVE_SIGNALS.has(input.type)) {
|
|
665
|
+
try {
|
|
666
|
+
const snapshot = await this.query(userSubject, { windowHours: 72 });
|
|
667
|
+
for (const sig of snapshot.signals) {
|
|
668
|
+
if (!NEGATIVE_SIGNALS.has(sig.type)) continue;
|
|
669
|
+
if (sig.resolvedBy) continue;
|
|
670
|
+
const sameContext = input.aboutSubject ? sig.aboutSubject === input.aboutSubject : !sig.aboutSubject;
|
|
671
|
+
if (sameContext) {
|
|
672
|
+
await this.resolve({ signalId: sig.id, resolvedBySignalId: result.id });
|
|
673
|
+
resolved++;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
} catch {
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
return { id: result.id, ...resolved > 0 && { resolved } };
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Query signals for a user with computed decay and trajectory.
|
|
683
|
+
* Delegates to the engine's signal query endpoint for server-side computation.
|
|
684
|
+
*
|
|
685
|
+
* @example
|
|
686
|
+
* ```typescript
|
|
687
|
+
* const snapshot = await brain.signals.query('user:cmk123', {
|
|
688
|
+
* windowHours: 72,
|
|
689
|
+
* type: 'frustration',
|
|
690
|
+
* })
|
|
691
|
+
* ```
|
|
692
|
+
*/
|
|
693
|
+
async query(userSubject, options = {}) {
|
|
694
|
+
const windowHours = options.windowHours ?? 72;
|
|
695
|
+
const query = { window: String(windowHours) };
|
|
696
|
+
if (options.type) query.type = options.type;
|
|
697
|
+
const qs = new URLSearchParams(query).toString();
|
|
698
|
+
const response = await this.http.get(
|
|
699
|
+
`/api/v1/signals/${enc(this.tenantId)}/${enc(userSubject)}?${qs}`
|
|
700
|
+
);
|
|
701
|
+
const signals = response.signals.map((s) => ({
|
|
702
|
+
id: s.assertion_id,
|
|
703
|
+
type: s.signal_type,
|
|
704
|
+
content: s.content,
|
|
705
|
+
intensity: s.intensity,
|
|
706
|
+
decayedIntensity: s.decayed_intensity,
|
|
707
|
+
ageHours: Math.round(s.age_hours * 10) / 10,
|
|
708
|
+
aboutSubject: s.about_subject || void 0,
|
|
709
|
+
resolvedBy: s.resolved_by || void 0,
|
|
710
|
+
timestamp: s.timestamp
|
|
711
|
+
}));
|
|
712
|
+
return {
|
|
713
|
+
signals,
|
|
714
|
+
trajectory: response.trajectory,
|
|
715
|
+
aggregateIntensity: response.aggregate_intensity
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Resolve a signal — mark it as resolved by a subsequent positive interaction.
|
|
720
|
+
* The resolved signal's effective intensity drops faster.
|
|
721
|
+
*
|
|
722
|
+
* @example
|
|
723
|
+
* ```typescript
|
|
724
|
+
* await brain.signals.resolve({
|
|
725
|
+
* signalId: 'abc123',
|
|
726
|
+
* resolvedBySignalId: 'def456',
|
|
727
|
+
* })
|
|
728
|
+
* ```
|
|
729
|
+
*/
|
|
730
|
+
async resolve(input) {
|
|
731
|
+
const original = await this.http.get(
|
|
732
|
+
`/api/v1/assertions/${enc(this.tenantId)}/${enc(input.signalId)}`
|
|
733
|
+
).catch(() => null);
|
|
734
|
+
if (!original) return { success: false };
|
|
735
|
+
const value = typeof original.value === "object" && original.value !== null ? { ...original.value, resolved_by: input.resolvedBySignalId } : { content: String(original.value), resolved_by: input.resolvedBySignalId };
|
|
736
|
+
await this.http.post("/api/v1/assertions/supersede", {
|
|
737
|
+
tenant_id: this.tenantId,
|
|
738
|
+
original_assertion_id: input.signalId,
|
|
739
|
+
subject: original.subject,
|
|
740
|
+
predicate: original.predicate,
|
|
741
|
+
value,
|
|
742
|
+
confidence: original.confidence
|
|
743
|
+
});
|
|
744
|
+
return { success: true };
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
function computeDecay(intensity, ageHours, halfLifeHours, isResolved = false) {
|
|
748
|
+
const effectiveHalfLife = isResolved ? halfLifeHours / 4 : halfLifeHours;
|
|
749
|
+
const decayed = intensity * Math.pow(2, -ageHours / effectiveHalfLife);
|
|
750
|
+
return Math.round(decayed * 100) / 100;
|
|
751
|
+
}
|
|
752
|
+
function extractSignals(assertions, windowHours = 72) {
|
|
753
|
+
const now = Date.now();
|
|
754
|
+
const windowMs = windowHours * 60 * 60 * 1e3;
|
|
755
|
+
const entries = [];
|
|
756
|
+
for (const a of assertions) {
|
|
757
|
+
if (a.isSuperseded) continue;
|
|
758
|
+
const isSignal = a.predicate.startsWith("signal:");
|
|
759
|
+
const isLegacy = LEGACY_SIGNAL_PREDICATES.has(a.predicate);
|
|
760
|
+
if (!isSignal && !isLegacy) continue;
|
|
761
|
+
const timestamp = a.validFrom;
|
|
762
|
+
const ageMs = now - new Date(timestamp).getTime();
|
|
763
|
+
if (ageMs > windowMs) continue;
|
|
764
|
+
const ageHours = ageMs / (60 * 60 * 1e3);
|
|
765
|
+
const type = isSignal ? a.predicate.slice(7) : a.predicate;
|
|
766
|
+
const halfLife = getDecayHalfLife(type);
|
|
767
|
+
let content = "";
|
|
768
|
+
let intensity = a.confidence ?? 0.7;
|
|
769
|
+
let aboutSubject;
|
|
770
|
+
let resolvedBy;
|
|
771
|
+
if (typeof a.value === "object" && a.value !== null) {
|
|
772
|
+
const v = a.value;
|
|
773
|
+
content = v.content || "";
|
|
774
|
+
intensity = v.intensity ?? intensity;
|
|
775
|
+
aboutSubject = v.about_subject || void 0;
|
|
776
|
+
resolvedBy = v.resolved_by || void 0;
|
|
777
|
+
} else {
|
|
778
|
+
content = String(a.value);
|
|
779
|
+
}
|
|
780
|
+
entries.push({
|
|
781
|
+
id: a.id,
|
|
782
|
+
type,
|
|
783
|
+
content,
|
|
784
|
+
intensity,
|
|
785
|
+
decayedIntensity: computeDecay(intensity, ageHours, halfLife, !!resolvedBy),
|
|
786
|
+
ageHours: Math.round(ageHours * 10) / 10,
|
|
787
|
+
aboutSubject,
|
|
788
|
+
resolvedBy,
|
|
789
|
+
timestamp
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
entries.sort((a, b) => a.ageHours - b.ageHours);
|
|
793
|
+
return entries;
|
|
794
|
+
}
|
|
795
|
+
function enc(s) {
|
|
796
|
+
return encodeURIComponent(s);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// src/users.ts
|
|
800
|
+
var UsersNamespace = class {
|
|
801
|
+
constructor(http, tenantId) {
|
|
802
|
+
this.http = http;
|
|
803
|
+
this.tenantId = tenantId;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Identify a user and retrieve their full context.
|
|
807
|
+
*
|
|
808
|
+
* This is the FIRST thing an agent should call at session start.
|
|
809
|
+
* Returns whether the user is known, their memories, connected
|
|
810
|
+
* people, reminders, conflicts, and a summary.
|
|
811
|
+
*
|
|
812
|
+
* @example
|
|
813
|
+
* ```typescript
|
|
814
|
+
* const user = await brain.users.identify({
|
|
815
|
+
* userId: 'cmk123...',
|
|
816
|
+
* displayName: 'Tom Santos',
|
|
817
|
+
* })
|
|
818
|
+
*
|
|
819
|
+
* if (!user.isKnown) {
|
|
820
|
+
* // First encounter — get to know them
|
|
821
|
+
* } else {
|
|
822
|
+
* // Returning user — reference what you know
|
|
823
|
+
* // user.reminders — bring these up
|
|
824
|
+
* // user.conflicts — address these
|
|
825
|
+
* // user.connectedPeople — context about their org
|
|
826
|
+
* }
|
|
827
|
+
* ```
|
|
828
|
+
*/
|
|
829
|
+
async identify(input) {
|
|
830
|
+
const userSubject = subject("user" /* USER */, input.userId);
|
|
831
|
+
const assertions = await this.http.get(
|
|
832
|
+
`/api/v1/assertions/query/${enc2(this.tenantId)}/${enc2(userSubject)}`
|
|
833
|
+
);
|
|
834
|
+
const active = assertions.filter((a) => !a.isSuperseded);
|
|
835
|
+
const isKnown = active.length > 0;
|
|
836
|
+
if (input.displayName && !active.some((a) => a.predicate === "name" || a.predicate === "full_name")) {
|
|
837
|
+
try {
|
|
838
|
+
await this.http.post("/api/v1/assertions", {
|
|
839
|
+
tenant_id: this.tenantId,
|
|
840
|
+
subject: userSubject,
|
|
841
|
+
predicate: "name",
|
|
842
|
+
value: input.displayName,
|
|
843
|
+
confidence: 1
|
|
844
|
+
});
|
|
845
|
+
} catch {
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
const nameAssertion = active.find((a) => a.predicate === "name" || a.predicate === "full_name");
|
|
849
|
+
const name = nameAssertion?.value || input.displayName || null;
|
|
850
|
+
const reminders = active.filter((a) => a.predicate === "reminder").map((a) => ({ id: a.id, predicate: a.predicate, value: a.value, confidence: a.confidence, createdAt: a.validFrom }));
|
|
851
|
+
for (const reminder of reminders) {
|
|
852
|
+
try {
|
|
853
|
+
await this.http.post(
|
|
854
|
+
`/api/v1/assertions/retract/${enc2(this.tenantId)}/${enc2(reminder.id)}`,
|
|
855
|
+
{}
|
|
856
|
+
);
|
|
857
|
+
} catch {
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
const contexts = active.filter((a) => a.predicate === "context" || a.predicate === "context:task").map((a) => ({ id: a.id, predicate: a.predicate, value: a.value, confidence: a.confidence, createdAt: a.validFrom }));
|
|
861
|
+
const signals = extractSignals(assertions);
|
|
862
|
+
const signalIds = new Set(signals.map((s) => s.id));
|
|
863
|
+
let rapportTrajectory = "neutral";
|
|
864
|
+
try {
|
|
865
|
+
const qs = new URLSearchParams({ window: "72" }).toString();
|
|
866
|
+
const snapshot = await this.http.get(
|
|
867
|
+
`/api/v1/signals/${enc2(this.tenantId)}/${enc2(userSubject)}?${qs}`
|
|
868
|
+
);
|
|
869
|
+
rapportTrajectory = snapshot.trajectory;
|
|
870
|
+
} catch {
|
|
871
|
+
}
|
|
872
|
+
const memories = active.filter(
|
|
873
|
+
(a) => a.predicate !== "reminder" && a.predicate !== "context" && a.predicate !== "context:task" && !signalIds.has(a.id)
|
|
874
|
+
// exclude signals from memories
|
|
875
|
+
).map((a) => ({ id: a.id, predicate: a.predicate, value: a.value, confidence: a.confidence, createdAt: a.validFrom }));
|
|
876
|
+
const connectedPeople = [];
|
|
877
|
+
try {
|
|
878
|
+
const relationships = await this.http.get(`/api/v1/relationships/${enc2(this.tenantId)}/${enc2(userSubject)}`);
|
|
879
|
+
const visited = /* @__PURE__ */ new Set();
|
|
880
|
+
for (const rel of relationships) {
|
|
881
|
+
const other = rel.fromSubject === userSubject ? rel.toSubject : rel.fromSubject;
|
|
882
|
+
if (!other || other === userSubject || visited.has(other)) continue;
|
|
883
|
+
visited.add(other);
|
|
884
|
+
const personAssertions = await this.http.get(
|
|
885
|
+
`/api/v1/assertions/query/${enc2(this.tenantId)}/${enc2(other)}`
|
|
886
|
+
);
|
|
887
|
+
const personActive = personAssertions.filter((a) => !a.isSuperseded);
|
|
888
|
+
const personName = personActive.find((a) => a.predicate === "name");
|
|
889
|
+
const facts = personActive.filter((a) => a.predicate !== "name").map((a) => ({ predicate: a.predicate, value: a.value }));
|
|
890
|
+
connectedPeople.push({
|
|
891
|
+
subject: other,
|
|
892
|
+
name: personName?.value || other,
|
|
893
|
+
relationship: rel.relationshipType,
|
|
894
|
+
facts
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
} catch {
|
|
898
|
+
}
|
|
899
|
+
const conflicts = [];
|
|
900
|
+
try {
|
|
901
|
+
if (!input.agentId) throw new Error("agentId is required on IdentifyUserInput to fetch conflicts");
|
|
902
|
+
const pending = await this.http.get(`/api/v1/intake/pending/${enc2(input.agentId)}?status=conflict_detected`);
|
|
903
|
+
for (const item of pending) {
|
|
904
|
+
if (item.acknowledged) continue;
|
|
905
|
+
const hint = item.surfacingHint || "";
|
|
906
|
+
const involvesUser = hint.includes(userSubject) || (item.persistedAssertionIds || []).some((id) => {
|
|
907
|
+
const a = assertions.find((a2) => a2.id === id);
|
|
908
|
+
return a?.subject === userSubject;
|
|
909
|
+
});
|
|
910
|
+
if (!involvesUser) continue;
|
|
911
|
+
let resolvedHint = hint || "A conflict was detected.";
|
|
912
|
+
if (name) {
|
|
913
|
+
resolvedHint = resolvedHint.replace(
|
|
914
|
+
new RegExp(userSubject.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"),
|
|
915
|
+
name
|
|
916
|
+
);
|
|
917
|
+
}
|
|
918
|
+
conflicts.push({ id: item.id, hint: resolvedHint });
|
|
919
|
+
}
|
|
920
|
+
} catch {
|
|
921
|
+
}
|
|
922
|
+
const parts = [];
|
|
923
|
+
if (conflicts.length > 0) {
|
|
924
|
+
parts.push(`ATTENTION: ${conflicts.length} knowledge conflict(s) \u2014 MUST address: ${conflicts.map((c) => c.hint).join(" | ")}`);
|
|
925
|
+
}
|
|
926
|
+
if (reminders.length > 0) {
|
|
927
|
+
parts.push(`REMINDERS (${reminders.length}): ${reminders.map((r) => `"${r.value}"`).join(", ")}. Dismiss each after surfacing.`);
|
|
928
|
+
}
|
|
929
|
+
if (connectedPeople.length > 0) {
|
|
930
|
+
parts.push(`Connected people:
|
|
931
|
+
${connectedPeople.map((p) => {
|
|
932
|
+
const factsStr = p.facts.map((f) => `${f.predicate}: ${f.value}`).join(", ");
|
|
933
|
+
return `- ${p.name} (${p.relationship})${factsStr ? ": " + factsStr : ""}`;
|
|
934
|
+
}).join("\n")}`);
|
|
935
|
+
}
|
|
936
|
+
if (memories.length > 0 && parts.length === 0) {
|
|
937
|
+
parts.push(`You know ${memories.length} things about this user.`);
|
|
938
|
+
}
|
|
939
|
+
if (parts.length === 0) {
|
|
940
|
+
parts.push("This is a new user \u2014 no memories yet. Get to know them.");
|
|
941
|
+
}
|
|
942
|
+
return {
|
|
943
|
+
subject: userSubject,
|
|
944
|
+
isKnown,
|
|
945
|
+
name,
|
|
946
|
+
memories,
|
|
947
|
+
connectedPeople,
|
|
948
|
+
reminders,
|
|
949
|
+
contexts,
|
|
950
|
+
conflicts,
|
|
951
|
+
signals,
|
|
952
|
+
rapportTrajectory,
|
|
953
|
+
summary: parts.join("\n")
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* Register a person that the user mentioned.
|
|
958
|
+
*
|
|
959
|
+
* Creates the person node, their role, and bidirectional
|
|
960
|
+
* relationships to the user. One call does everything.
|
|
961
|
+
*
|
|
962
|
+
* @example
|
|
963
|
+
* ```typescript
|
|
964
|
+
* const result = await brain.users.registerPerson({
|
|
965
|
+
* name: 'John Smith',
|
|
966
|
+
* userId: 'cmk123...',
|
|
967
|
+
* relationship: 'direct_report',
|
|
968
|
+
* role: 'VP of Engineering',
|
|
969
|
+
* })
|
|
970
|
+
* ```
|
|
971
|
+
*/
|
|
972
|
+
async registerPerson(input) {
|
|
973
|
+
const userSubject = subject("user" /* USER */, input.userId);
|
|
974
|
+
const personSubject = subject("person" /* PERSON */, input.name);
|
|
975
|
+
const conf = typeof input.confidence === "number" ? input.confidence : confidenceToScore(input.confidence || "confirmed" /* CONFIRMED */);
|
|
976
|
+
let assertionsCreated = 0;
|
|
977
|
+
let relationshipsCreated = 0;
|
|
978
|
+
const warnings = [];
|
|
979
|
+
await this.http.post("/api/v1/assertions", {
|
|
980
|
+
tenant_id: this.tenantId,
|
|
981
|
+
subject: personSubject,
|
|
982
|
+
predicate: "name",
|
|
983
|
+
value: input.name,
|
|
984
|
+
confidence: conf
|
|
985
|
+
});
|
|
986
|
+
assertionsCreated++;
|
|
987
|
+
if (input.role) {
|
|
988
|
+
try {
|
|
989
|
+
const existing = await this.http.get(
|
|
990
|
+
`/api/v1/assertions/query/${enc2(this.tenantId)}/${enc2(personSubject)}`
|
|
991
|
+
);
|
|
992
|
+
const existingRole = existing.find((a) => a.predicate === "role" && !a.isSuperseded);
|
|
993
|
+
if (existingRole && existingRole.value !== input.role) {
|
|
994
|
+
warnings.push(`${input.name} was previously "${existingRole.value}" \u2014 now being set as "${input.role}". Role change or mistake?`);
|
|
995
|
+
await this.http.post("/api/v1/assertions/supersede", {
|
|
996
|
+
tenant_id: this.tenantId,
|
|
997
|
+
original_assertion_id: existingRole.id,
|
|
998
|
+
subject: personSubject,
|
|
999
|
+
predicate: "role",
|
|
1000
|
+
value: input.role,
|
|
1001
|
+
confidence: conf
|
|
1002
|
+
});
|
|
1003
|
+
} else if (!existingRole) {
|
|
1004
|
+
await this.http.post("/api/v1/assertions", {
|
|
1005
|
+
tenant_id: this.tenantId,
|
|
1006
|
+
subject: personSubject,
|
|
1007
|
+
predicate: "role",
|
|
1008
|
+
value: input.role,
|
|
1009
|
+
confidence: conf
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
} catch {
|
|
1013
|
+
await this.http.post("/api/v1/assertions", {
|
|
1014
|
+
tenant_id: this.tenantId,
|
|
1015
|
+
subject: personSubject,
|
|
1016
|
+
predicate: "role",
|
|
1017
|
+
value: input.role,
|
|
1018
|
+
confidence: conf
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
assertionsCreated++;
|
|
1022
|
+
try {
|
|
1023
|
+
const allAssertions = await this.http.get(
|
|
1024
|
+
`/api/v1/assertions/list/${enc2(this.tenantId)}`
|
|
1025
|
+
);
|
|
1026
|
+
const sameRole = allAssertions.filter(
|
|
1027
|
+
(a) => a.subject.startsWith("person:") && a.subject !== personSubject && a.predicate === "role" && a.value === input.role && !a.isSuperseded
|
|
1028
|
+
);
|
|
1029
|
+
if (sameRole.length > 0) {
|
|
1030
|
+
const otherAssertions = await this.http.get(
|
|
1031
|
+
`/api/v1/assertions/query/${enc2(this.tenantId)}/${enc2(sameRole[0].subject)}`
|
|
1032
|
+
);
|
|
1033
|
+
const otherName = otherAssertions.find((a) => a.predicate === "name")?.value || sameRole[0].subject;
|
|
1034
|
+
warnings.push(`"${input.role}" is already held by ${otherName}. Is ${otherName} no longer in this role?`);
|
|
1035
|
+
}
|
|
1036
|
+
} catch {
|
|
1037
|
+
}
|
|
1038
|
+
const roleSubject = subject("role" /* ROLE */, input.role);
|
|
1039
|
+
await this.http.post("/api/v1/assertions", {
|
|
1040
|
+
tenant_id: this.tenantId,
|
|
1041
|
+
subject: roleSubject,
|
|
1042
|
+
predicate: "name",
|
|
1043
|
+
value: input.role,
|
|
1044
|
+
confidence: conf
|
|
1045
|
+
});
|
|
1046
|
+
await this.http.post("/api/v1/relationships", {
|
|
1047
|
+
tenant_id: this.tenantId,
|
|
1048
|
+
from_subject: personSubject,
|
|
1049
|
+
to_subject: roleSubject,
|
|
1050
|
+
relationship_type: "holds_role" /* HOLDS_ROLE */,
|
|
1051
|
+
confidence: conf
|
|
1052
|
+
});
|
|
1053
|
+
assertionsCreated++;
|
|
1054
|
+
relationshipsCreated++;
|
|
1055
|
+
}
|
|
1056
|
+
if (input.details) {
|
|
1057
|
+
await this.http.post("/api/v1/assertions", {
|
|
1058
|
+
tenant_id: this.tenantId,
|
|
1059
|
+
subject: personSubject,
|
|
1060
|
+
predicate: "details",
|
|
1061
|
+
value: input.details,
|
|
1062
|
+
confidence: conf
|
|
1063
|
+
});
|
|
1064
|
+
assertionsCreated++;
|
|
1065
|
+
}
|
|
1066
|
+
await this.http.post("/api/v1/assertions", {
|
|
1067
|
+
tenant_id: this.tenantId,
|
|
1068
|
+
subject: personSubject,
|
|
1069
|
+
predicate: "status",
|
|
1070
|
+
value: input.relationship === "candidate" ? "candidate" : "active",
|
|
1071
|
+
confidence: conf
|
|
1072
|
+
});
|
|
1073
|
+
assertionsCreated++;
|
|
1074
|
+
const FORWARD_MAP = {
|
|
1075
|
+
"direct_report": "manages" /* MANAGES */,
|
|
1076
|
+
"team_member": "has_member" /* HAS_MEMBER */,
|
|
1077
|
+
"candidate": "manages" /* MANAGES */,
|
|
1078
|
+
// user manages the hiring
|
|
1079
|
+
"manager": "reports_to" /* REPORTS_TO */,
|
|
1080
|
+
// user reports to this person
|
|
1081
|
+
"stakeholder": "stakeholder_in" /* STAKEHOLDER_IN */,
|
|
1082
|
+
"collaborator": "collaborates_with" /* COLLABORATES_WITH */,
|
|
1083
|
+
"mentor": "mentors" /* MENTORS */
|
|
1084
|
+
};
|
|
1085
|
+
const forwardType = FORWARD_MAP[input.relationship] || input.relationship;
|
|
1086
|
+
const reverseType = REVERSE_RELATIONSHIPS[input.relationship] || REVERSE_RELATIONSHIPS[forwardType] || input.relationship;
|
|
1087
|
+
await this.http.post("/api/v1/relationships", {
|
|
1088
|
+
tenant_id: this.tenantId,
|
|
1089
|
+
from_subject: userSubject,
|
|
1090
|
+
to_subject: personSubject,
|
|
1091
|
+
relationship_type: forwardType,
|
|
1092
|
+
confidence: conf
|
|
1093
|
+
});
|
|
1094
|
+
relationshipsCreated++;
|
|
1095
|
+
await this.http.post("/api/v1/relationships", {
|
|
1096
|
+
tenant_id: this.tenantId,
|
|
1097
|
+
from_subject: personSubject,
|
|
1098
|
+
to_subject: userSubject,
|
|
1099
|
+
relationship_type: reverseType,
|
|
1100
|
+
confidence: conf
|
|
1101
|
+
});
|
|
1102
|
+
relationshipsCreated++;
|
|
1103
|
+
return { personSubject, assertionsCreated, relationshipsCreated, warnings };
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Record an emotional state or rapport signal about the user.
|
|
1107
|
+
*
|
|
1108
|
+
* @example
|
|
1109
|
+
* ```typescript
|
|
1110
|
+
* await brain.users.recordRapport({
|
|
1111
|
+
* userId: 'cmk123...',
|
|
1112
|
+
* type: 'frustration',
|
|
1113
|
+
* value: 'Frustrated about losing the EA candidate',
|
|
1114
|
+
* aboutPerson: 'Sarah Johnson',
|
|
1115
|
+
* })
|
|
1116
|
+
* ```
|
|
1117
|
+
*/
|
|
1118
|
+
async recordRapport(input) {
|
|
1119
|
+
const userSubject = subject("user" /* USER */, input.userId);
|
|
1120
|
+
const conf = typeof input.confidence === "number" ? input.confidence : confidenceToScore(input.confidence || "high" /* HIGH */);
|
|
1121
|
+
await this.http.post("/api/v1/assertions", {
|
|
1122
|
+
tenant_id: this.tenantId,
|
|
1123
|
+
subject: userSubject,
|
|
1124
|
+
predicate: input.type,
|
|
1125
|
+
value: input.value,
|
|
1126
|
+
confidence: conf
|
|
1127
|
+
});
|
|
1128
|
+
if (input.aboutPerson) {
|
|
1129
|
+
const personSubject = subject("person" /* PERSON */, input.aboutPerson);
|
|
1130
|
+
try {
|
|
1131
|
+
const personAssertions = await this.http.get(
|
|
1132
|
+
`/api/v1/assertions/query/${enc2(this.tenantId)}/${enc2(personSubject)}`
|
|
1133
|
+
);
|
|
1134
|
+
if (personAssertions.length > 0) {
|
|
1135
|
+
await this.http.post("/api/v1/assertions", {
|
|
1136
|
+
tenant_id: this.tenantId,
|
|
1137
|
+
subject: personSubject,
|
|
1138
|
+
predicate: "timeline",
|
|
1139
|
+
value: input.value,
|
|
1140
|
+
confidence: conf
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
} catch {
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
return { success: true };
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Dismiss a reminder after the agent has surfaced it.
|
|
1150
|
+
*/
|
|
1151
|
+
async dismissReminder(userId, reminderContent) {
|
|
1152
|
+
const userSubject = subject("user" /* USER */, userId);
|
|
1153
|
+
const assertions = await this.http.get(
|
|
1154
|
+
`/api/v1/assertions/query/${enc2(this.tenantId)}/${enc2(userSubject)}`
|
|
1155
|
+
);
|
|
1156
|
+
const reminder = assertions.find(
|
|
1157
|
+
(a) => a.predicate === "reminder" && !a.isSuperseded && a.value.toLowerCase().includes(reminderContent.toLowerCase())
|
|
1158
|
+
);
|
|
1159
|
+
if (reminder) {
|
|
1160
|
+
await this.http.post(`/api/v1/assertions/retract/${enc2(this.tenantId)}/${enc2(reminder.id)}`, {});
|
|
1161
|
+
return { success: true };
|
|
1162
|
+
}
|
|
1163
|
+
return { success: false };
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
function enc2(s) {
|
|
1167
|
+
return encodeURIComponent(s);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// src/client.ts
|
|
1171
|
+
var AssertionsNamespace = class {
|
|
1172
|
+
constructor(http, tenantId) {
|
|
1173
|
+
this.http = http;
|
|
1174
|
+
this.tenantId = tenantId;
|
|
1175
|
+
}
|
|
1176
|
+
/** Create an assertion in the knowledge graph. */
|
|
1177
|
+
async create(input) {
|
|
1178
|
+
const tenantId = input.tenantId || this.tenantId;
|
|
1179
|
+
return this.http.post("/api/v1/assertions", {
|
|
1180
|
+
tenant_id: tenantId,
|
|
1181
|
+
subject: input.subject,
|
|
1182
|
+
predicate: input.predicate,
|
|
1183
|
+
value: input.value,
|
|
1184
|
+
confidence: input.confidence
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
/** Get an assertion by its content-addressable ID. */
|
|
1188
|
+
async get(assertionId, options) {
|
|
1189
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1190
|
+
return this.http.get(
|
|
1191
|
+
`/api/v1/assertions/${enc3(tenantId)}/${enc3(assertionId)}`
|
|
1192
|
+
);
|
|
1193
|
+
}
|
|
1194
|
+
/** Query assertions by subject. */
|
|
1195
|
+
async query(subject2, options) {
|
|
1196
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1197
|
+
return this.http.get(
|
|
1198
|
+
`/api/v1/assertions/query/${enc3(tenantId)}/${enc3(subject2)}`
|
|
1199
|
+
);
|
|
1200
|
+
}
|
|
1201
|
+
/** List all active assertions for the tenant. */
|
|
1202
|
+
async list(options) {
|
|
1203
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1204
|
+
return this.http.get(
|
|
1205
|
+
`/api/v1/assertions/list/${enc3(tenantId)}`
|
|
1206
|
+
);
|
|
1207
|
+
}
|
|
1208
|
+
/** Supersede an existing assertion with updated values. */
|
|
1209
|
+
async supersede(input) {
|
|
1210
|
+
const tenantId = input.tenantId || this.tenantId;
|
|
1211
|
+
return this.http.post("/api/v1/assertions/supersede", {
|
|
1212
|
+
tenant_id: tenantId,
|
|
1213
|
+
original_assertion_id: input.originalAssertionId,
|
|
1214
|
+
subject: input.subject,
|
|
1215
|
+
predicate: input.predicate,
|
|
1216
|
+
value: input.value,
|
|
1217
|
+
confidence: input.confidence
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
/** Retract an assertion by closing its temporal bounds. */
|
|
1221
|
+
async retract(assertionId, options) {
|
|
1222
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1223
|
+
return this.http.post(
|
|
1224
|
+
`/api/v1/assertions/retract/${enc3(tenantId)}/${enc3(assertionId)}`,
|
|
1225
|
+
{}
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1228
|
+
};
|
|
1229
|
+
var RelationshipsNamespace = class {
|
|
1230
|
+
constructor(http, tenantId) {
|
|
1231
|
+
this.http = http;
|
|
1232
|
+
this.tenantId = tenantId;
|
|
1233
|
+
}
|
|
1234
|
+
/** Create a relationship between two subjects. */
|
|
1235
|
+
async create(input) {
|
|
1236
|
+
const tenantId = input.tenantId || this.tenantId;
|
|
1237
|
+
return this.http.post("/api/v1/relationships", {
|
|
1238
|
+
tenant_id: tenantId,
|
|
1239
|
+
from_subject: input.fromSubject,
|
|
1240
|
+
to_subject: input.toSubject,
|
|
1241
|
+
relationship_type: input.relationshipType,
|
|
1242
|
+
confidence: input.confidence,
|
|
1243
|
+
weight: input.weight,
|
|
1244
|
+
properties: input.properties
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
/** Get relationships for a subject. */
|
|
1248
|
+
async query(subject2, options) {
|
|
1249
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1250
|
+
return this.http.get(
|
|
1251
|
+
`/api/v1/relationships/${enc3(tenantId)}/${enc3(subject2)}`
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
/** List all relationships for the tenant. */
|
|
1255
|
+
async list(options) {
|
|
1256
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1257
|
+
return this.http.get(
|
|
1258
|
+
`/api/v1/relationships/list/${enc3(tenantId)}`
|
|
1259
|
+
);
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
var AgentsNamespace = class {
|
|
1263
|
+
constructor(http, tenantId) {
|
|
1264
|
+
this.http = http;
|
|
1265
|
+
this.tenantId = tenantId;
|
|
1266
|
+
}
|
|
1267
|
+
/** Create a new agent. */
|
|
1268
|
+
async create(input) {
|
|
1269
|
+
const tenantId = input.tenantId || this.tenantId;
|
|
1270
|
+
return this.http.post("/api/v1/agents", {
|
|
1271
|
+
tenant_id: tenantId,
|
|
1272
|
+
name: input.name,
|
|
1273
|
+
description: input.description,
|
|
1274
|
+
personality: input.personality,
|
|
1275
|
+
instructions: input.instructions ? toWire(input.instructions) : void 0,
|
|
1276
|
+
model: input.model ? toWire(input.model) : void 0,
|
|
1277
|
+
capabilities: input.capabilities,
|
|
1278
|
+
memory_policy: input.memoryPolicy ? toWire(input.memoryPolicy) : void 0
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
/** Get an agent by ID. */
|
|
1282
|
+
async get(agentId, options) {
|
|
1283
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1284
|
+
return this.http.get(
|
|
1285
|
+
`/api/v1/agents/${enc3(tenantId)}/${enc3(agentId)}`
|
|
1286
|
+
);
|
|
1287
|
+
}
|
|
1288
|
+
/** Update an agent. */
|
|
1289
|
+
async update(agentId, input, options) {
|
|
1290
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1291
|
+
return this.http.put(
|
|
1292
|
+
`/api/v1/agents/${enc3(tenantId)}/${enc3(agentId)}`,
|
|
1293
|
+
{
|
|
1294
|
+
tenant_id: tenantId,
|
|
1295
|
+
name: input.name,
|
|
1296
|
+
description: input.description,
|
|
1297
|
+
personality: input.personality,
|
|
1298
|
+
instructions: input.instructions ? toWire(input.instructions) : void 0,
|
|
1299
|
+
model: input.model ? toWire(input.model) : void 0,
|
|
1300
|
+
capabilities: input.capabilities,
|
|
1301
|
+
memory_policy: input.memoryPolicy ? toWire(input.memoryPolicy) : void 0,
|
|
1302
|
+
is_active: input.isActive
|
|
1303
|
+
}
|
|
1304
|
+
);
|
|
1305
|
+
}
|
|
1306
|
+
/** Delete an agent. */
|
|
1307
|
+
async delete(agentId, options) {
|
|
1308
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1309
|
+
await this.http.delete(`/api/v1/agents/${enc3(tenantId)}/${enc3(agentId)}`);
|
|
1310
|
+
}
|
|
1311
|
+
/** List all agents for the tenant. */
|
|
1312
|
+
async list(options) {
|
|
1313
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1314
|
+
return this.http.get(
|
|
1315
|
+
`/api/v1/agents/list/${enc3(tenantId)}`
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
1318
|
+
/** Get composed system instructions for an agent. */
|
|
1319
|
+
async getInstructions(agentId, options) {
|
|
1320
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1321
|
+
return this.http.get(
|
|
1322
|
+
`/api/v1/agents/${enc3(tenantId)}/${enc3(agentId)}/instructions`
|
|
1323
|
+
);
|
|
1324
|
+
}
|
|
1325
|
+
};
|
|
1326
|
+
var MemoryNamespace = class {
|
|
1327
|
+
constructor(http, tenantId) {
|
|
1328
|
+
this.http = http;
|
|
1329
|
+
this.tenantId = tenantId;
|
|
1330
|
+
}
|
|
1331
|
+
/**
|
|
1332
|
+
* Store a fact in the agent's memory.
|
|
1333
|
+
*
|
|
1334
|
+
* Routes through the Thalamus by default. The Thalamus will:
|
|
1335
|
+
* - Classify the signal (reject noise)
|
|
1336
|
+
* - Check for contradictions with existing assertions
|
|
1337
|
+
* - Detect duplicates and reinforce instead of creating new
|
|
1338
|
+
*
|
|
1339
|
+
* Pass `raw: true` to bypass Thalamus for system operations.
|
|
1340
|
+
*/
|
|
1341
|
+
async store(input) {
|
|
1342
|
+
const tenantId = input.tenantId || this.tenantId;
|
|
1343
|
+
if (input.raw) {
|
|
1344
|
+
return this.http.post("/api/v1/assertions", {
|
|
1345
|
+
tenant_id: tenantId,
|
|
1346
|
+
subject: input.subject,
|
|
1347
|
+
predicate: input.predicate,
|
|
1348
|
+
value: input.value,
|
|
1349
|
+
confidence: input.confidence
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
const correlationId = `mem_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
|
|
1353
|
+
return this.http.post("/api/v1/intake/submit", {
|
|
1354
|
+
correlation_id: correlationId,
|
|
1355
|
+
agent_id: input.agentId,
|
|
1356
|
+
tenant_id: tenantId,
|
|
1357
|
+
candidates: [{
|
|
1358
|
+
subject: input.subject,
|
|
1359
|
+
predicate: input.predicate,
|
|
1360
|
+
value: input.value,
|
|
1361
|
+
source_confidence: input.confidence ?? 0.95,
|
|
1362
|
+
provenance: "agent",
|
|
1363
|
+
person_name: input.personName
|
|
1364
|
+
}],
|
|
1365
|
+
context: input.context
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
/** Recall all memories for a subject. */
|
|
1369
|
+
async recall(subject2, options) {
|
|
1370
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1371
|
+
return this.http.get(
|
|
1372
|
+
`/api/v1/assertions/query/${enc3(tenantId)}/${enc3(subject2)}`
|
|
1373
|
+
);
|
|
1374
|
+
}
|
|
1375
|
+
/** Forget a specific memory (retract the assertion). */
|
|
1376
|
+
async forget(assertionId, options) {
|
|
1377
|
+
const tenantId = options?.tenantId || this.tenantId;
|
|
1378
|
+
return this.http.post(
|
|
1379
|
+
`/api/v1/assertions/retract/${enc3(tenantId)}/${enc3(assertionId)}`,
|
|
1380
|
+
{}
|
|
1381
|
+
);
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
var IntakeNamespace = class {
|
|
1385
|
+
constructor(http, tenantId) {
|
|
1386
|
+
this.http = http;
|
|
1387
|
+
this.tenantId = tenantId;
|
|
1388
|
+
}
|
|
1389
|
+
/** Submit candidate assertions for Thalamus processing. */
|
|
1390
|
+
async submit(input) {
|
|
1391
|
+
const tenantId = input.tenantId || this.tenantId;
|
|
1392
|
+
return this.http.post("/api/v1/intake/submit", {
|
|
1393
|
+
correlation_id: input.correlationId,
|
|
1394
|
+
agent_id: input.agentId,
|
|
1395
|
+
tenant_id: tenantId,
|
|
1396
|
+
candidates: input.candidates.map((c) => ({
|
|
1397
|
+
subject: c.subject,
|
|
1398
|
+
predicate: c.predicate,
|
|
1399
|
+
value: c.value,
|
|
1400
|
+
source_confidence: c.sourceConfidence,
|
|
1401
|
+
valid_from: c.validFrom,
|
|
1402
|
+
valid_until: c.validUntil,
|
|
1403
|
+
provenance: c.provenance,
|
|
1404
|
+
person_name: c.personName
|
|
1405
|
+
})),
|
|
1406
|
+
context: input.context
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
/** Get pending intake results for an agent. */
|
|
1410
|
+
async pending(agentId, options) {
|
|
1411
|
+
let path = `/api/v1/intake/pending/${enc3(agentId)}`;
|
|
1412
|
+
const params = [];
|
|
1413
|
+
if (options?.status) params.push(`status=${options.status.join(",")}`);
|
|
1414
|
+
if (options?.limit) params.push(`limit=${options.limit}`);
|
|
1415
|
+
if (params.length) path += `?${params.join("&")}`;
|
|
1416
|
+
return this.http.get(path);
|
|
1417
|
+
}
|
|
1418
|
+
/** Acknowledge an intake result (mark as consumed). */
|
|
1419
|
+
async acknowledge(itemId) {
|
|
1420
|
+
await this.http.post(`/api/v1/intake/acknowledge/${enc3(itemId)}`, {});
|
|
1421
|
+
}
|
|
1422
|
+
/** Acknowledge all pending items for an agent. */
|
|
1423
|
+
async acknowledgeAll(agentId) {
|
|
1424
|
+
return this.http.post(
|
|
1425
|
+
`/api/v1/intake/acknowledge-all/${enc3(agentId)}`,
|
|
1426
|
+
{}
|
|
1427
|
+
);
|
|
1428
|
+
}
|
|
1429
|
+
/** Get intake processing stats for an agent. */
|
|
1430
|
+
async stats(agentId) {
|
|
1431
|
+
return this.http.get(`/api/v1/intake/stats/${enc3(agentId)}`);
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
var DEFAULT_RETRY = {
|
|
1435
|
+
maxRetries: 3,
|
|
1436
|
+
baseDelayMs: 500,
|
|
1437
|
+
maxDelayMs: 1e4
|
|
1438
|
+
};
|
|
1439
|
+
var SubCortexClient = class {
|
|
1440
|
+
/** Assertion operations (low-level knowledge primitives) */
|
|
1441
|
+
assertions;
|
|
1442
|
+
/** Relationship operations */
|
|
1443
|
+
relationships;
|
|
1444
|
+
/** Agent identity & configuration */
|
|
1445
|
+
agents;
|
|
1446
|
+
/** Agent memory (semantic wrapper over assertions) */
|
|
1447
|
+
memory;
|
|
1448
|
+
/** Thalamus cognitive intake pipeline */
|
|
1449
|
+
intake;
|
|
1450
|
+
/** User rapport building operations */
|
|
1451
|
+
users;
|
|
1452
|
+
/** Emotional signals — record, query, and resolve */
|
|
1453
|
+
signals;
|
|
1454
|
+
http;
|
|
1455
|
+
constructor(options) {
|
|
1456
|
+
if (!options.apiKey && !options.token) {
|
|
1457
|
+
console.warn("[SubCortex] No apiKey or token provided \u2014 requests will be unauthenticated.");
|
|
1458
|
+
}
|
|
1459
|
+
this.http = new HttpTransport({
|
|
1460
|
+
baseUrl: options.endpoint,
|
|
1461
|
+
tenantId: options.tenantId,
|
|
1462
|
+
apiKey: options.apiKey,
|
|
1463
|
+
token: options.token,
|
|
1464
|
+
retry: { ...DEFAULT_RETRY, ...options.retry },
|
|
1465
|
+
timeoutMs: options.timeoutMs ?? 3e4,
|
|
1466
|
+
fetchImpl: options.fetch ?? globalThis.fetch,
|
|
1467
|
+
headers: options.headers ?? {},
|
|
1468
|
+
signal: options.signal
|
|
1469
|
+
});
|
|
1470
|
+
this.assertions = new AssertionsNamespace(this.http, options.tenantId);
|
|
1471
|
+
this.relationships = new RelationshipsNamespace(this.http, options.tenantId);
|
|
1472
|
+
this.agents = new AgentsNamespace(this.http, options.tenantId);
|
|
1473
|
+
this.memory = new MemoryNamespace(this.http, options.tenantId);
|
|
1474
|
+
this.intake = new IntakeNamespace(this.http, options.tenantId);
|
|
1475
|
+
this.users = new UsersNamespace(this.http, options.tenantId);
|
|
1476
|
+
this.signals = new SignalsNamespace(this.http, options.tenantId);
|
|
1477
|
+
}
|
|
1478
|
+
/** Check SubCortex server health. */
|
|
1479
|
+
async health() {
|
|
1480
|
+
return this.http.get("/health");
|
|
1481
|
+
}
|
|
1482
|
+
};
|
|
1483
|
+
function enc3(s) {
|
|
1484
|
+
return encodeURIComponent(s);
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
// src/context.ts
|
|
1488
|
+
var CONTEXT_SCHEMA_VERSION = "1.0";
|
|
1489
|
+
function formatContext(user, options = {}) {
|
|
1490
|
+
const format = options.format ?? "xml";
|
|
1491
|
+
switch (format) {
|
|
1492
|
+
case "xml":
|
|
1493
|
+
return toContextXml(user, options);
|
|
1494
|
+
case "json":
|
|
1495
|
+
return JSON.stringify(user, null, 2);
|
|
1496
|
+
case "summary":
|
|
1497
|
+
return user.summary;
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
function toContextXml(user, options = {}) {
|
|
1501
|
+
const {
|
|
1502
|
+
includeMemories = true,
|
|
1503
|
+
includeRelationships = true,
|
|
1504
|
+
includeReminders = true,
|
|
1505
|
+
includeConflicts = true,
|
|
1506
|
+
includeContexts = true,
|
|
1507
|
+
includeSignals = true,
|
|
1508
|
+
minConfidence = 0
|
|
1509
|
+
} = options;
|
|
1510
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
1511
|
+
const lines = [];
|
|
1512
|
+
const signalsByAbout = /* @__PURE__ */ new Map();
|
|
1513
|
+
const unattachedSignals = [];
|
|
1514
|
+
if (includeSignals && user.signals) {
|
|
1515
|
+
for (const sig of user.signals) {
|
|
1516
|
+
if (sig.aboutSubject) {
|
|
1517
|
+
const existing = signalsByAbout.get(sig.aboutSubject) || [];
|
|
1518
|
+
existing.push(sig);
|
|
1519
|
+
signalsByAbout.set(sig.aboutSubject, existing);
|
|
1520
|
+
} else {
|
|
1521
|
+
unattachedSignals.push(sig);
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
lines.push(`<subcortex_context version="${CONTEXT_SCHEMA_VERSION}" subject="${esc(user.subject)}" known="${user.isKnown}" ts="${ts}">`);
|
|
1526
|
+
if (includeConflicts && user.conflicts.length > 0) {
|
|
1527
|
+
lines.push(` <conflicts count="${user.conflicts.length}" priority="critical">`);
|
|
1528
|
+
for (const conflict of user.conflicts) {
|
|
1529
|
+
lines.push(` <conflict id="${esc(conflict.id)}">${esc(conflict.hint)}</conflict>`);
|
|
1530
|
+
}
|
|
1531
|
+
lines.push(` </conflicts>`);
|
|
1532
|
+
}
|
|
1533
|
+
if (includeReminders && user.reminders.length > 0) {
|
|
1534
|
+
lines.push(` <reminders count="${user.reminders.length}" priority="high">`);
|
|
1535
|
+
for (const reminder of user.reminders) {
|
|
1536
|
+
lines.push(` <reminder id="${esc(reminder.id)}" confidence="${fmtConf(reminder.confidence)}">${esc(String(reminder.value))}</reminder>`);
|
|
1537
|
+
}
|
|
1538
|
+
lines.push(` </reminders>`);
|
|
1539
|
+
}
|
|
1540
|
+
if (includeContexts && user.contexts.length > 0) {
|
|
1541
|
+
lines.push(` <active_contexts count="${user.contexts.length}">`);
|
|
1542
|
+
for (const ctx of user.contexts) {
|
|
1543
|
+
const ctxSignals = findSignalsForFact(ctx, signalsByAbout);
|
|
1544
|
+
if (ctxSignals.length > 0) {
|
|
1545
|
+
lines.push(` <context predicate="${esc(ctx.predicate)}" confidence="${fmtConf(ctx.confidence)}">`);
|
|
1546
|
+
lines.push(` ${esc(String(ctx.value))}`);
|
|
1547
|
+
for (const sig of ctxSignals) {
|
|
1548
|
+
lines.push(` ${renderSignal(sig)}`);
|
|
1549
|
+
}
|
|
1550
|
+
lines.push(` </context>`);
|
|
1551
|
+
} else {
|
|
1552
|
+
lines.push(` <context predicate="${esc(ctx.predicate)}" confidence="${fmtConf(ctx.confidence)}">${esc(String(ctx.value))}</context>`);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
lines.push(` </active_contexts>`);
|
|
1556
|
+
}
|
|
1557
|
+
if (user.name) {
|
|
1558
|
+
const trajectoryAttr = user.rapportTrajectory ? ` rapport_trajectory="${user.rapportTrajectory}"` : "";
|
|
1559
|
+
lines.push(` <identity name="${esc(String(user.name))}" subject="${esc(user.subject)}"${trajectoryAttr}>`);
|
|
1560
|
+
const identityPredicates = /* @__PURE__ */ new Set(["name", "full_name", "role", "title", "department", "team", "email", "start_date", "communication_style"]);
|
|
1561
|
+
const identityFacts = user.memories.filter((m) => identityPredicates.has(m.predicate) && m.confidence >= minConfidence);
|
|
1562
|
+
for (const fact of identityFacts) {
|
|
1563
|
+
const factSignals = findSignalsForFact(fact, signalsByAbout);
|
|
1564
|
+
if (factSignals.length > 0) {
|
|
1565
|
+
lines.push(` <fact predicate="${esc(fact.predicate)}" confidence="${fmtConf(fact.confidence)}">`);
|
|
1566
|
+
lines.push(` ${esc(String(fact.value))}`);
|
|
1567
|
+
for (const sig of factSignals) {
|
|
1568
|
+
lines.push(` ${renderSignal(sig)}`);
|
|
1569
|
+
}
|
|
1570
|
+
lines.push(` </fact>`);
|
|
1571
|
+
} else {
|
|
1572
|
+
lines.push(` <fact predicate="${esc(fact.predicate)}" confidence="${fmtConf(fact.confidence)}">${esc(String(fact.value))}</fact>`);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
for (const sig of unattachedSignals) {
|
|
1576
|
+
lines.push(` ${renderSignal(sig)}`);
|
|
1577
|
+
}
|
|
1578
|
+
lines.push(` </identity>`);
|
|
1579
|
+
}
|
|
1580
|
+
if (includeMemories) {
|
|
1581
|
+
const identityPredicates = /* @__PURE__ */ new Set(["name", "full_name", "role", "title", "department", "team", "email", "start_date", "communication_style"]);
|
|
1582
|
+
const knowledge = user.memories.filter(
|
|
1583
|
+
(m) => !identityPredicates.has(m.predicate) && m.confidence >= minConfidence
|
|
1584
|
+
);
|
|
1585
|
+
if (knowledge.length > 0) {
|
|
1586
|
+
lines.push(` <knowledge count="${knowledge.length}">`);
|
|
1587
|
+
for (const mem of knowledge) {
|
|
1588
|
+
const memSignals = findSignalsForFact(mem, signalsByAbout);
|
|
1589
|
+
if (memSignals.length > 0) {
|
|
1590
|
+
lines.push(` <fact predicate="${esc(mem.predicate)}" confidence="${fmtConf(mem.confidence)}">`);
|
|
1591
|
+
lines.push(` ${esc(String(mem.value))}`);
|
|
1592
|
+
for (const sig of memSignals) {
|
|
1593
|
+
lines.push(` ${renderSignal(sig)}`);
|
|
1594
|
+
}
|
|
1595
|
+
lines.push(` </fact>`);
|
|
1596
|
+
} else {
|
|
1597
|
+
lines.push(` <fact predicate="${esc(mem.predicate)}" confidence="${fmtConf(mem.confidence)}">${esc(String(mem.value))}</fact>`);
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
lines.push(` </knowledge>`);
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
if (includeRelationships && user.connectedPeople.length > 0) {
|
|
1604
|
+
lines.push(` <relationships count="${user.connectedPeople.length}">`);
|
|
1605
|
+
for (const person of user.connectedPeople) {
|
|
1606
|
+
const personSignals = signalsByAbout.get(person.subject) || [];
|
|
1607
|
+
const hasContent = person.facts.length > 0 || personSignals.length > 0;
|
|
1608
|
+
if (!hasContent) {
|
|
1609
|
+
lines.push(` <person name="${esc(person.name)}" relationship="${esc(person.relationship)}" />`);
|
|
1610
|
+
} else {
|
|
1611
|
+
lines.push(` <person name="${esc(person.name)}" relationship="${esc(person.relationship)}">`);
|
|
1612
|
+
for (const fact of person.facts) {
|
|
1613
|
+
lines.push(` <fact predicate="${esc(fact.predicate)}">${esc(String(fact.value))}</fact>`);
|
|
1614
|
+
}
|
|
1615
|
+
for (const sig of personSignals) {
|
|
1616
|
+
lines.push(` ${renderSignal(sig)}`);
|
|
1617
|
+
}
|
|
1618
|
+
lines.push(` </person>`);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
lines.push(` </relationships>`);
|
|
1622
|
+
}
|
|
1623
|
+
lines.push(`</subcortex_context>`);
|
|
1624
|
+
return lines.join("\n");
|
|
1625
|
+
}
|
|
1626
|
+
function renderSignal(sig) {
|
|
1627
|
+
const aboutAttr = sig.aboutSubject ? ` about="${esc(sig.aboutSubject)}"` : "";
|
|
1628
|
+
return `<signal type="${esc(sig.type)}" intensity="${fmtConf(sig.intensity)}" decayed="${fmtConf(sig.decayedIntensity)}" age_hours="${sig.ageHours}"${aboutAttr}>${esc(sig.content)}</signal>`;
|
|
1629
|
+
}
|
|
1630
|
+
function findSignalsForFact(fact, signalsByAbout) {
|
|
1631
|
+
const results = [];
|
|
1632
|
+
for (const [aboutSubject, signals] of signalsByAbout) {
|
|
1633
|
+
if (aboutSubject.includes(fact.predicate) || aboutSubject.includes(String(fact.value).toLowerCase().replace(/\s+/g, "-").slice(0, 30))) {
|
|
1634
|
+
results.push(...signals);
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
return results;
|
|
1638
|
+
}
|
|
1639
|
+
function fmtConf(n) {
|
|
1640
|
+
return n.toFixed(2);
|
|
1641
|
+
}
|
|
1642
|
+
function esc(s) {
|
|
1643
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1644
|
+
}
|
|
1645
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1646
|
+
0 && (module.exports = {
|
|
1647
|
+
AgentsNamespace,
|
|
1648
|
+
AssertionsNamespace,
|
|
1649
|
+
CONTEXT_SCHEMA_VERSION,
|
|
1650
|
+
ConfidenceLevel,
|
|
1651
|
+
ConfidenceScores,
|
|
1652
|
+
EntityPredicate,
|
|
1653
|
+
EntityRelationship,
|
|
1654
|
+
EventPredicate,
|
|
1655
|
+
IdentityPredicate,
|
|
1656
|
+
IntakeNamespace,
|
|
1657
|
+
MULTI_VALUE_PREDICATES,
|
|
1658
|
+
MemoryNamespace,
|
|
1659
|
+
MemoryPredicate,
|
|
1660
|
+
NEGATIVE_SIGNALS,
|
|
1661
|
+
OrgRelationship,
|
|
1662
|
+
POSITIVE_SIGNALS,
|
|
1663
|
+
Predicates,
|
|
1664
|
+
RELATIONSHIP_LABELS,
|
|
1665
|
+
REVERSE_RELATIONSHIPS,
|
|
1666
|
+
RapportPredicate,
|
|
1667
|
+
RelationshipTypes,
|
|
1668
|
+
RelationshipsNamespace,
|
|
1669
|
+
SIGNAL_DECAY_CONFIG,
|
|
1670
|
+
SYSTEM_SIGNAL_TYPES,
|
|
1671
|
+
SignalsNamespace,
|
|
1672
|
+
SubCortexAuthenticationError,
|
|
1673
|
+
SubCortexAuthorizationError,
|
|
1674
|
+
SubCortexClient,
|
|
1675
|
+
SubCortexConflictError,
|
|
1676
|
+
SubCortexError,
|
|
1677
|
+
SubCortexNetworkError,
|
|
1678
|
+
SubCortexNotFoundError,
|
|
1679
|
+
SubCortexRateLimitError,
|
|
1680
|
+
SubCortexServerError,
|
|
1681
|
+
SubCortexTimeoutError,
|
|
1682
|
+
SubCortexValidationError,
|
|
1683
|
+
SubjectPrefix,
|
|
1684
|
+
UsersNamespace,
|
|
1685
|
+
WorkPredicate,
|
|
1686
|
+
confidenceToScore,
|
|
1687
|
+
formatContext,
|
|
1688
|
+
getDecayHalfLife,
|
|
1689
|
+
isValidSignalType,
|
|
1690
|
+
scoreToConfidence,
|
|
1691
|
+
subject,
|
|
1692
|
+
toContextXml
|
|
1693
|
+
});
|
|
1694
|
+
//# sourceMappingURL=index.cjs.map
|