@subcortex-ai/sdk 0.1.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -25,9 +25,12 @@ __export(index_exports, {
25
25
  CONTEXT_SCHEMA_VERSION: () => CONTEXT_SCHEMA_VERSION,
26
26
  ConfidenceLevel: () => ConfidenceLevel,
27
27
  ConfidenceScores: () => ConfidenceScores,
28
+ EntitiesNamespace: () => EntitiesNamespace,
28
29
  EntityPredicate: () => EntityPredicate,
29
30
  EntityRelationship: () => EntityRelationship,
30
31
  EventPredicate: () => EventPredicate,
32
+ ExperiencesNamespace: () => ExperiencesNamespace,
33
+ GraphNamespace: () => GraphNamespace,
31
34
  IdentityPredicate: () => IdentityPredicate,
32
35
  IntakeNamespace: () => IntakeNamespace,
33
36
  MULTI_VALUE_PREDICATES: () => MULTI_VALUE_PREDICATES,
@@ -40,10 +43,14 @@ __export(index_exports, {
40
43
  RELATIONSHIP_LABELS: () => RELATIONSHIP_LABELS,
41
44
  REVERSE_RELATIONSHIPS: () => REVERSE_RELATIONSHIPS,
42
45
  RapportPredicate: () => RapportPredicate,
46
+ RecallNamespace: () => RecallNamespace,
43
47
  RelationshipTypes: () => RelationshipTypes,
44
48
  RelationshipsNamespace: () => RelationshipsNamespace,
49
+ RulePredicates: () => RulePredicates,
50
+ RulesNamespace: () => RulesNamespace,
45
51
  SIGNAL_DECAY_CONFIG: () => SIGNAL_DECAY_CONFIG,
46
52
  SYSTEM_SIGNAL_TYPES: () => SYSTEM_SIGNAL_TYPES,
53
+ SearchNamespace: () => SearchNamespace,
47
54
  SignalsNamespace: () => SignalsNamespace,
48
55
  SubCortexAuthenticationError: () => SubCortexAuthenticationError,
49
56
  SubCortexAuthorizationError: () => SubCortexAuthorizationError,
@@ -57,6 +64,7 @@ __export(index_exports, {
57
64
  SubCortexTimeoutError: () => SubCortexTimeoutError,
58
65
  SubCortexValidationError: () => SubCortexValidationError,
59
66
  SubjectPrefix: () => SubjectPrefix,
67
+ TemporalNamespace: () => TemporalNamespace,
60
68
  UsersNamespace: () => UsersNamespace,
61
69
  WorkPredicate: () => WorkPredicate,
62
70
  confidenceToScore: () => confidenceToScore,
@@ -976,49 +984,10 @@ ${connectedPeople.map((p) => {
976
984
  let assertionsCreated = 0;
977
985
  let relationshipsCreated = 0;
978
986
  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
+ const candidates = [];
988
+ candidates.push({ subject: personSubject, predicate: "name", value: input.name, source_confidence: conf, provenance: "agent" });
987
989
  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++;
990
+ candidates.push({ subject: personSubject, predicate: "role", value: input.role, source_confidence: conf, provenance: "agent" });
1022
991
  try {
1023
992
  const allAssertions = await this.http.get(
1024
993
  `/api/v1/assertions/list/${enc2(this.tenantId)}`
@@ -1035,6 +1004,35 @@ ${connectedPeople.map((p) => {
1035
1004
  }
1036
1005
  } catch {
1037
1006
  }
1007
+ }
1008
+ if (input.details) {
1009
+ candidates.push({ subject: personSubject, predicate: "details", value: input.details, source_confidence: conf, provenance: "agent" });
1010
+ }
1011
+ candidates.push({
1012
+ subject: personSubject,
1013
+ predicate: "status",
1014
+ value: input.relationship === "candidate" ? "candidate" : "active",
1015
+ source_confidence: conf,
1016
+ provenance: "agent"
1017
+ });
1018
+ const correlationId = `register_person_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
1019
+ const intakeResult = await this.http.post("/api/v1/intake/submit", {
1020
+ correlation_id: correlationId,
1021
+ agent_id: "sdk",
1022
+ tenant_id: this.tenantId,
1023
+ candidates,
1024
+ context: input.sessionId ? { sessionId: input.sessionId } : void 0
1025
+ });
1026
+ assertionsCreated = intakeResult.accepted + intakeResult.reinforced;
1027
+ if (intakeResult.conflicts > 0) {
1028
+ const conflictItems = (intakeResult.items || []).filter(
1029
+ (i) => i.status === "conflict_detected"
1030
+ );
1031
+ for (const item of conflictItems) {
1032
+ warnings.push(item.surfacingHint || "A conflict was detected with existing data.");
1033
+ }
1034
+ }
1035
+ if (input.role) {
1038
1036
  const roleSubject = subject("role" /* ROLE */, input.role);
1039
1037
  await this.http.post("/api/v1/assertions", {
1040
1038
  tenant_id: this.tenantId,
@@ -1050,34 +1048,13 @@ ${connectedPeople.map((p) => {
1050
1048
  relationship_type: "holds_role" /* HOLDS_ROLE */,
1051
1049
  confidence: conf
1052
1050
  });
1053
- assertionsCreated++;
1054
1051
  relationshipsCreated++;
1055
1052
  }
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
1053
  const FORWARD_MAP = {
1075
1054
  "direct_report": "manages" /* MANAGES */,
1076
1055
  "team_member": "has_member" /* HAS_MEMBER */,
1077
1056
  "candidate": "manages" /* MANAGES */,
1078
- // user manages the hiring
1079
1057
  "manager": "reports_to" /* REPORTS_TO */,
1080
- // user reports to this person
1081
1058
  "stakeholder": "stakeholder_in" /* STAKEHOLDER_IN */,
1082
1059
  "collaborator": "collaborates_with" /* COLLABORATES_WITH */,
1083
1060
  "mentor": "mentors" /* MENTORS */
@@ -1118,31 +1095,26 @@ ${connectedPeople.map((p) => {
1118
1095
  async recordRapport(input) {
1119
1096
  const userSubject = subject("user" /* USER */, input.userId);
1120
1097
  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
- });
1098
+ const candidates = [
1099
+ { subject: userSubject, predicate: input.type, value: input.value, source_confidence: conf, provenance: "agent" }
1100
+ ];
1128
1101
  if (input.aboutPerson) {
1129
1102
  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
- }
1103
+ candidates.push({
1104
+ subject: personSubject,
1105
+ predicate: "timeline",
1106
+ value: input.value,
1107
+ source_confidence: conf,
1108
+ provenance: "agent"
1109
+ });
1145
1110
  }
1111
+ const correlationId = `rapport_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
1112
+ await this.http.post("/api/v1/intake/submit", {
1113
+ correlation_id: correlationId,
1114
+ agent_id: "sdk",
1115
+ tenant_id: this.tenantId,
1116
+ candidates
1117
+ });
1146
1118
  return { success: true };
1147
1119
  }
1148
1120
  /**
@@ -1167,6 +1139,242 @@ function enc2(s) {
1167
1139
  return encodeURIComponent(s);
1168
1140
  }
1169
1141
 
1142
+ // src/types/rules.ts
1143
+ var RulePredicates = {
1144
+ BANNED_PATTERN: "rule:banned_pattern",
1145
+ REQUIRED_PATTERN: "rule:required_pattern",
1146
+ FILE_CONSTRAINT: "rule:file_constraint",
1147
+ REQUIRES_PROPAGATION: "rule:requires_propagation"
1148
+ };
1149
+
1150
+ // src/rules.ts
1151
+ var RULE_PREDICATE_PREFIX = "rule:";
1152
+ var TYPE_TO_PREDICATE = {
1153
+ banned_pattern: RulePredicates.BANNED_PATTERN,
1154
+ required_pattern: RulePredicates.REQUIRED_PATTERN,
1155
+ file_constraint: RulePredicates.FILE_CONSTRAINT,
1156
+ requires_propagation: RulePredicates.REQUIRES_PROPAGATION
1157
+ };
1158
+ function defaultSeverity(confidence) {
1159
+ if (confidence >= 1) return "block";
1160
+ if (confidence >= 0.7) return "warn";
1161
+ return "info";
1162
+ }
1163
+ var RulesNamespace = class {
1164
+ http;
1165
+ tenantId;
1166
+ constructor(http, tenantId) {
1167
+ this.http = http;
1168
+ this.tenantId = tenantId;
1169
+ }
1170
+ /**
1171
+ * Create a new rule.
1172
+ *
1173
+ * Stores an assertion with a `rule:*` predicate and a typed value.
1174
+ * Defaults to confidence 1.0 (enforcement) if not specified.
1175
+ *
1176
+ * @example
1177
+ * ```typescript
1178
+ * await subcortex.rules.create({
1179
+ * subject: 'project:my-project',
1180
+ * type: 'banned_pattern',
1181
+ * pattern: 'as any',
1182
+ * description: 'No any casts — use proper types',
1183
+ * })
1184
+ * ```
1185
+ */
1186
+ async create(input) {
1187
+ const confidence = input.confidence ?? 1;
1188
+ const severity = input.severity ?? defaultSeverity(confidence);
1189
+ const ruleValue = {
1190
+ description: input.description,
1191
+ pattern: input.pattern,
1192
+ fileScope: input.fileScope,
1193
+ propagatesTo: input.propagatesTo
1194
+ };
1195
+ const assertion = await this.http.post(
1196
+ `/api/v1/assertions`,
1197
+ {
1198
+ subject: input.subject,
1199
+ predicate: TYPE_TO_PREDICATE[input.type],
1200
+ value: { ...ruleValue, severity },
1201
+ confidence,
1202
+ tenant_id: input.tenantId ?? this.tenantId
1203
+ },
1204
+ input.tenantId ?? this.tenantId
1205
+ );
1206
+ return parseRule(assertion);
1207
+ }
1208
+ /**
1209
+ * Get a rule by its assertion ID.
1210
+ */
1211
+ async get(ruleId, options) {
1212
+ const tenant = options?.tenantId ?? this.tenantId;
1213
+ const assertion = await this.http.get(
1214
+ `/api/v1/assertions/${enc3(tenant)}/${enc3(ruleId)}`
1215
+ );
1216
+ return parseRule(assertion);
1217
+ }
1218
+ /**
1219
+ * List all rules for this project, optionally filtered by type or severity.
1220
+ */
1221
+ async list(options) {
1222
+ const tenant = options?.tenantId ?? this.tenantId;
1223
+ const assertions = await this.http.get(
1224
+ `/api/v1/assertions/list/${enc3(tenant)}`
1225
+ );
1226
+ return assertions.filter((a) => isRuleAssertion(a)).filter((a) => options?.includeSuperseded || !a.isSuperseded).map(parseRule).filter((r) => !options?.type || r.type === options.type).filter((r) => !options?.severity || r.severity === options.severity);
1227
+ }
1228
+ /**
1229
+ * Get all rules whose fileScope matches the given file path.
1230
+ *
1231
+ * This is the primary query for the PreToolUse hook — "what rules apply
1232
+ * to the file I'm about to modify?"
1233
+ *
1234
+ * @example
1235
+ * ```typescript
1236
+ * const rules = await subcortex.rules.forFile('app/api/users/route.ts')
1237
+ * // Returns banned_pattern and required_pattern rules whose fileScope
1238
+ * // matches the path, plus any project-wide rules without a fileScope.
1239
+ * ```
1240
+ */
1241
+ async forFile(filePath, options) {
1242
+ const allRules = await this.list(options);
1243
+ return allRules.filter((rule) => {
1244
+ if (!rule.value.fileScope) return true;
1245
+ try {
1246
+ const regex = new RegExp(rule.value.fileScope);
1247
+ return regex.test(filePath);
1248
+ } catch {
1249
+ return false;
1250
+ }
1251
+ });
1252
+ }
1253
+ /**
1254
+ * Get all rules scoped to a specific intent subject.
1255
+ *
1256
+ * @example
1257
+ * ```typescript
1258
+ * const apiRules = await subcortex.rules.forIntent('api')
1259
+ * // Queries subject "intent:api" for all rule assertions
1260
+ * ```
1261
+ */
1262
+ async forIntent(intent, options) {
1263
+ const tenant = options?.tenantId ?? this.tenantId;
1264
+ const subject2 = intent.startsWith("intent:") ? intent : `intent:${intent}`;
1265
+ const assertions = await this.http.get(
1266
+ `/api/v1/assertions/query/${enc3(tenant)}/${enc3(subject2)}`
1267
+ );
1268
+ return assertions.filter((a) => isRuleAssertion(a)).filter((a) => options?.includeSuperseded || !a.isSuperseded).map(parseRule).filter((r) => !options?.type || r.type === options.type).filter((r) => !options?.severity || r.severity === options.severity);
1269
+ }
1270
+ /**
1271
+ * Get all rules scoped to a specific subject (project, file, intent, etc.).
1272
+ */
1273
+ async forSubject(subject2, options) {
1274
+ const tenant = options?.tenantId ?? this.tenantId;
1275
+ const assertions = await this.http.get(
1276
+ `/api/v1/assertions/query/${enc3(tenant)}/${enc3(subject2)}`
1277
+ );
1278
+ return assertions.filter((a) => isRuleAssertion(a)).filter((a) => options?.includeSuperseded || !a.isSuperseded).map(parseRule).filter((r) => !options?.type || r.type === options.type).filter((r) => !options?.severity || r.severity === options.severity);
1279
+ }
1280
+ /**
1281
+ * Update a rule by superseding it.
1282
+ *
1283
+ * The old rule is marked as superseded, a new one is created.
1284
+ * Full assertion history is preserved.
1285
+ */
1286
+ async update(input) {
1287
+ const tenant = input.tenantId ?? this.tenantId;
1288
+ const existing = await this.get(input.ruleId, { tenantId: tenant });
1289
+ const confidence = input.confidence ?? existing.confidence;
1290
+ const severity = input.severity ?? existing.severity;
1291
+ const ruleValue = {
1292
+ description: input.description ?? existing.value.description,
1293
+ pattern: input.pattern ?? existing.value.pattern,
1294
+ fileScope: input.fileScope ?? existing.value.fileScope,
1295
+ propagatesTo: input.propagatesTo ?? existing.value.propagatesTo
1296
+ };
1297
+ const assertion = await this.http.post(
1298
+ `/api/v1/assertions/supersede`,
1299
+ {
1300
+ original_assertion_id: input.ruleId,
1301
+ subject: existing.subject,
1302
+ predicate: existing.predicate,
1303
+ value: { ...ruleValue, severity },
1304
+ confidence,
1305
+ tenant_id: tenant
1306
+ },
1307
+ tenant
1308
+ );
1309
+ return parseRule(assertion);
1310
+ }
1311
+ /**
1312
+ * Retract (deactivate) a rule.
1313
+ *
1314
+ * The assertion's temporal bounds are closed. The rule stops matching
1315
+ * in future queries but its history is preserved.
1316
+ */
1317
+ async retract(ruleId, options) {
1318
+ const tenant = options?.tenantId ?? this.tenantId;
1319
+ await this.http.post(
1320
+ `/api/v1/assertions/retract/${enc3(tenant)}/${enc3(ruleId)}`,
1321
+ {},
1322
+ tenant
1323
+ );
1324
+ }
1325
+ };
1326
+ function isRuleAssertion(assertion) {
1327
+ return assertion.predicate?.startsWith(RULE_PREDICATE_PREFIX) ?? false;
1328
+ }
1329
+ function parseRule(assertion) {
1330
+ const predicate = assertion.predicate;
1331
+ const type = predicate.replace(RULE_PREDICATE_PREFIX, "");
1332
+ let ruleValue;
1333
+ let severity;
1334
+ if (typeof assertion.value === "object" && assertion.value !== null) {
1335
+ const val = assertion.value;
1336
+ ruleValue = {
1337
+ description: String(val.description ?? ""),
1338
+ pattern: val.pattern != null ? String(val.pattern) : void 0,
1339
+ fileScope: val.fileScope != null ? String(val.fileScope) : void 0,
1340
+ propagatesTo: Array.isArray(val.propagatesTo) ? val.propagatesTo.map(String) : void 0
1341
+ };
1342
+ severity = val.severity ?? defaultSeverity(assertion.confidence);
1343
+ } else if (typeof assertion.value === "string") {
1344
+ try {
1345
+ const parsed = JSON.parse(assertion.value);
1346
+ ruleValue = {
1347
+ description: String(parsed.description ?? ""),
1348
+ pattern: parsed.pattern != null ? String(parsed.pattern) : void 0,
1349
+ fileScope: parsed.filePattern != null ? String(parsed.filePattern) : void 0,
1350
+ propagatesTo: Array.isArray(parsed.propagatesTo) ? parsed.propagatesTo.map(String) : void 0
1351
+ };
1352
+ severity = parsed.severity ?? defaultSeverity(assertion.confidence);
1353
+ } catch {
1354
+ ruleValue = { description: String(assertion.value) };
1355
+ severity = defaultSeverity(assertion.confidence);
1356
+ }
1357
+ } else {
1358
+ ruleValue = { description: "" };
1359
+ severity = defaultSeverity(assertion.confidence);
1360
+ }
1361
+ return {
1362
+ id: assertion.id,
1363
+ tenantId: assertion.tenantId,
1364
+ subject: assertion.subject,
1365
+ type,
1366
+ predicate,
1367
+ value: ruleValue,
1368
+ severity,
1369
+ confidence: assertion.confidence,
1370
+ validFrom: assertion.validFrom,
1371
+ isSuperseded: assertion.isSuperseded
1372
+ };
1373
+ }
1374
+ function enc3(s) {
1375
+ return encodeURIComponent(s);
1376
+ }
1377
+
1170
1378
  // src/client.ts
1171
1379
  var AssertionsNamespace = class {
1172
1380
  constructor(http, tenantId) {
@@ -1188,21 +1396,21 @@ var AssertionsNamespace = class {
1188
1396
  async get(assertionId, options) {
1189
1397
  const tenantId = options?.tenantId || this.tenantId;
1190
1398
  return this.http.get(
1191
- `/api/v1/assertions/${enc3(tenantId)}/${enc3(assertionId)}`
1399
+ `/api/v1/assertions/${enc4(tenantId)}/${enc4(assertionId)}`
1192
1400
  );
1193
1401
  }
1194
1402
  /** Query assertions by subject. */
1195
1403
  async query(subject2, options) {
1196
1404
  const tenantId = options?.tenantId || this.tenantId;
1197
1405
  return this.http.get(
1198
- `/api/v1/assertions/query/${enc3(tenantId)}/${enc3(subject2)}`
1406
+ `/api/v1/assertions/query/${enc4(tenantId)}/${enc4(subject2)}`
1199
1407
  );
1200
1408
  }
1201
1409
  /** List all active assertions for the tenant. */
1202
1410
  async list(options) {
1203
1411
  const tenantId = options?.tenantId || this.tenantId;
1204
1412
  return this.http.get(
1205
- `/api/v1/assertions/list/${enc3(tenantId)}`
1413
+ `/api/v1/assertions/list/${enc4(tenantId)}`
1206
1414
  );
1207
1415
  }
1208
1416
  /** Supersede an existing assertion with updated values. */
@@ -1221,7 +1429,7 @@ var AssertionsNamespace = class {
1221
1429
  async retract(assertionId, options) {
1222
1430
  const tenantId = options?.tenantId || this.tenantId;
1223
1431
  return this.http.post(
1224
- `/api/v1/assertions/retract/${enc3(tenantId)}/${enc3(assertionId)}`,
1432
+ `/api/v1/assertions/retract/${enc4(tenantId)}/${enc4(assertionId)}`,
1225
1433
  {}
1226
1434
  );
1227
1435
  }
@@ -1248,14 +1456,14 @@ var RelationshipsNamespace = class {
1248
1456
  async query(subject2, options) {
1249
1457
  const tenantId = options?.tenantId || this.tenantId;
1250
1458
  return this.http.get(
1251
- `/api/v1/relationships/${enc3(tenantId)}/${enc3(subject2)}`
1459
+ `/api/v1/relationships/${enc4(tenantId)}/${enc4(subject2)}`
1252
1460
  );
1253
1461
  }
1254
1462
  /** List all relationships for the tenant. */
1255
1463
  async list(options) {
1256
1464
  const tenantId = options?.tenantId || this.tenantId;
1257
1465
  return this.http.get(
1258
- `/api/v1/relationships/list/${enc3(tenantId)}`
1466
+ `/api/v1/relationships/list/${enc4(tenantId)}`
1259
1467
  );
1260
1468
  }
1261
1469
  };
@@ -1282,14 +1490,14 @@ var AgentsNamespace = class {
1282
1490
  async get(agentId, options) {
1283
1491
  const tenantId = options?.tenantId || this.tenantId;
1284
1492
  return this.http.get(
1285
- `/api/v1/agents/${enc3(tenantId)}/${enc3(agentId)}`
1493
+ `/api/v1/agents/${enc4(tenantId)}/${enc4(agentId)}`
1286
1494
  );
1287
1495
  }
1288
1496
  /** Update an agent. */
1289
1497
  async update(agentId, input, options) {
1290
1498
  const tenantId = options?.tenantId || this.tenantId;
1291
1499
  return this.http.put(
1292
- `/api/v1/agents/${enc3(tenantId)}/${enc3(agentId)}`,
1500
+ `/api/v1/agents/${enc4(tenantId)}/${enc4(agentId)}`,
1293
1501
  {
1294
1502
  tenant_id: tenantId,
1295
1503
  name: input.name,
@@ -1306,20 +1514,20 @@ var AgentsNamespace = class {
1306
1514
  /** Delete an agent. */
1307
1515
  async delete(agentId, options) {
1308
1516
  const tenantId = options?.tenantId || this.tenantId;
1309
- await this.http.delete(`/api/v1/agents/${enc3(tenantId)}/${enc3(agentId)}`);
1517
+ await this.http.delete(`/api/v1/agents/${enc4(tenantId)}/${enc4(agentId)}`);
1310
1518
  }
1311
1519
  /** List all agents for the tenant. */
1312
1520
  async list(options) {
1313
1521
  const tenantId = options?.tenantId || this.tenantId;
1314
1522
  return this.http.get(
1315
- `/api/v1/agents/list/${enc3(tenantId)}`
1523
+ `/api/v1/agents/list/${enc4(tenantId)}`
1316
1524
  );
1317
1525
  }
1318
1526
  /** Get composed system instructions for an agent. */
1319
1527
  async getInstructions(agentId, options) {
1320
1528
  const tenantId = options?.tenantId || this.tenantId;
1321
1529
  return this.http.get(
1322
- `/api/v1/agents/${enc3(tenantId)}/${enc3(agentId)}/instructions`
1530
+ `/api/v1/agents/${enc4(tenantId)}/${enc4(agentId)}/instructions`
1323
1531
  );
1324
1532
  }
1325
1533
  };
@@ -1369,14 +1577,14 @@ var MemoryNamespace = class {
1369
1577
  async recall(subject2, options) {
1370
1578
  const tenantId = options?.tenantId || this.tenantId;
1371
1579
  return this.http.get(
1372
- `/api/v1/assertions/query/${enc3(tenantId)}/${enc3(subject2)}`
1580
+ `/api/v1/assertions/query/${enc4(tenantId)}/${enc4(subject2)}`
1373
1581
  );
1374
1582
  }
1375
1583
  /** Forget a specific memory (retract the assertion). */
1376
1584
  async forget(assertionId, options) {
1377
1585
  const tenantId = options?.tenantId || this.tenantId;
1378
1586
  return this.http.post(
1379
- `/api/v1/assertions/retract/${enc3(tenantId)}/${enc3(assertionId)}`,
1587
+ `/api/v1/assertions/retract/${enc4(tenantId)}/${enc4(assertionId)}`,
1380
1588
  {}
1381
1589
  );
1382
1590
  }
@@ -1408,7 +1616,7 @@ var IntakeNamespace = class {
1408
1616
  }
1409
1617
  /** Get pending intake results for an agent. */
1410
1618
  async pending(agentId, options) {
1411
- let path = `/api/v1/intake/pending/${enc3(agentId)}`;
1619
+ let path = `/api/v1/intake/pending/${enc4(agentId)}`;
1412
1620
  const params = [];
1413
1621
  if (options?.status) params.push(`status=${options.status.join(",")}`);
1414
1622
  if (options?.limit) params.push(`limit=${options.limit}`);
@@ -1417,18 +1625,131 @@ var IntakeNamespace = class {
1417
1625
  }
1418
1626
  /** Acknowledge an intake result (mark as consumed). */
1419
1627
  async acknowledge(itemId) {
1420
- await this.http.post(`/api/v1/intake/acknowledge/${enc3(itemId)}`, {});
1628
+ await this.http.post(`/api/v1/intake/acknowledge/${enc4(itemId)}`, {});
1421
1629
  }
1422
1630
  /** Acknowledge all pending items for an agent. */
1423
1631
  async acknowledgeAll(agentId) {
1424
1632
  return this.http.post(
1425
- `/api/v1/intake/acknowledge-all/${enc3(agentId)}`,
1633
+ `/api/v1/intake/acknowledge-all/${enc4(agentId)}`,
1426
1634
  {}
1427
1635
  );
1428
1636
  }
1429
1637
  /** Get intake processing stats for an agent. */
1430
1638
  async stats(agentId) {
1431
- return this.http.get(`/api/v1/intake/stats/${enc3(agentId)}`);
1639
+ return this.http.get(`/api/v1/intake/stats/${enc4(agentId)}`);
1640
+ }
1641
+ };
1642
+ var ExperiencesNamespace = class {
1643
+ constructor(http, tenantId) {
1644
+ this.http = http;
1645
+ this.tenantId = tenantId;
1646
+ }
1647
+ /** List experiences, optionally filtered by subject. */
1648
+ async list(input) {
1649
+ const tenantId = input?.tenantId || this.tenantId;
1650
+ const params = new URLSearchParams();
1651
+ if (input?.subject) params.set("subject", input.subject);
1652
+ if (input?.limit) params.set("limit", String(input.limit));
1653
+ const qs = params.toString();
1654
+ return this.http.get(
1655
+ `/api/v1/experiences/${enc4(tenantId)}${qs ? `?${qs}` : ""}`
1656
+ );
1657
+ }
1658
+ /** Get a single experience by ID. */
1659
+ async get(experienceId, options) {
1660
+ const tenantId = options?.tenantId || this.tenantId;
1661
+ return this.http.get(
1662
+ `/api/v1/experiences/${enc4(tenantId)}/${enc4(experienceId)}`
1663
+ );
1664
+ }
1665
+ };
1666
+ var RecallNamespace = class {
1667
+ constructor(http, tenantId) {
1668
+ this.http = http;
1669
+ this.tenantId = tenantId;
1670
+ }
1671
+ /** BM25 full-text search across assertions. */
1672
+ async search(input) {
1673
+ const tenantId = input.tenantId || this.tenantId;
1674
+ const params = new URLSearchParams({ q: input.query });
1675
+ if (input.limit) params.set("limit", String(input.limit));
1676
+ return this.http.get(
1677
+ `/api/v1/recall/${enc4(tenantId)}?${params.toString()}`
1678
+ );
1679
+ }
1680
+ };
1681
+ var GraphNamespace = class {
1682
+ constructor(http, tenantId) {
1683
+ this.http = http;
1684
+ this.tenantId = tenantId;
1685
+ }
1686
+ /** Find paths between two subjects. */
1687
+ async findPaths(input) {
1688
+ const tenantId = input.tenantId || this.tenantId;
1689
+ return this.http.post(
1690
+ `/api/v1/graph/${enc4(tenantId)}/paths`,
1691
+ {
1692
+ from: input.from,
1693
+ to: input.to,
1694
+ max_depth: input.maxDepth,
1695
+ min_confidence: input.minConfidence,
1696
+ strategy: input.strategy
1697
+ }
1698
+ );
1699
+ }
1700
+ /** BFS traversal from a starting subject. */
1701
+ async traverse(input) {
1702
+ const tenantId = input.tenantId || this.tenantId;
1703
+ return this.http.post(
1704
+ `/api/v1/graph/${enc4(tenantId)}/traverse`,
1705
+ {
1706
+ start_subject: input.startSubject,
1707
+ max_depth: input.maxDepth,
1708
+ relationship_types: input.relationshipTypes,
1709
+ min_confidence: input.minConfidence,
1710
+ max_nodes: input.maxNodes
1711
+ }
1712
+ );
1713
+ }
1714
+ };
1715
+ var TemporalNamespace = class {
1716
+ constructor(http, tenantId) {
1717
+ this.http = http;
1718
+ this.tenantId = tenantId;
1719
+ }
1720
+ /** Get assertions valid at a specific point in time. */
1721
+ async at(subject2, point, options) {
1722
+ const tenantId = options?.tenantId || this.tenantId;
1723
+ const pointStr = point instanceof Date ? point.toISOString() : point;
1724
+ return this.http.get(
1725
+ `/api/v1/temporal/${enc4(tenantId)}/${enc4(subject2)}/at?point=${enc4(pointStr)}`
1726
+ );
1727
+ }
1728
+ /** Get assertions within a date range. */
1729
+ async range(subject2, start, end, options) {
1730
+ const tenantId = options?.tenantId || this.tenantId;
1731
+ const startStr = start instanceof Date ? start.toISOString() : start;
1732
+ const endStr = end instanceof Date ? end.toISOString() : end;
1733
+ return this.http.get(
1734
+ `/api/v1/temporal/${enc4(tenantId)}/${enc4(subject2)}/range?start=${enc4(startStr)}&end=${enc4(endStr)}`
1735
+ );
1736
+ }
1737
+ };
1738
+ var SearchNamespace = class {
1739
+ constructor(http, tenantId) {
1740
+ this.http = http;
1741
+ this.tenantId = tenantId;
1742
+ }
1743
+ /** Semantic nearest-neighbor search over assertion embeddings. */
1744
+ async semantic(input) {
1745
+ const tenantId = input.tenantId || this.tenantId;
1746
+ return this.http.post(
1747
+ `/api/v1/search/${enc4(tenantId)}/semantic`,
1748
+ {
1749
+ embedding: input.embedding,
1750
+ top_k: input.topK
1751
+ }
1752
+ );
1432
1753
  }
1433
1754
  };
1434
1755
  var DEFAULT_RETRY = {
@@ -1436,6 +1757,129 @@ var DEFAULT_RETRY = {
1436
1757
  baseDelayMs: 500,
1437
1758
  maxDelayMs: 1e4
1438
1759
  };
1760
+ var EntitiesNamespace = class {
1761
+ constructor(http, tenantId) {
1762
+ this.http = http;
1763
+ this.tenantId = tenantId;
1764
+ }
1765
+ /** Create an entity with optional description and type. */
1766
+ async create(input) {
1767
+ const tenantId = input.tenantId || this.tenantId;
1768
+ const subject2 = `entity:${input.name.toLowerCase().replace(/\s+/g, "-")}`;
1769
+ const typeAssertion = await this.http.post(
1770
+ `/api/v1/assertions`,
1771
+ {
1772
+ tenant_id: tenantId,
1773
+ subject: subject2,
1774
+ predicate: "type",
1775
+ value: input.type || "model",
1776
+ confidence: 1
1777
+ }
1778
+ );
1779
+ if (input.description) {
1780
+ await this.http.post(
1781
+ `/api/v1/assertions`,
1782
+ {
1783
+ tenant_id: tenantId,
1784
+ subject: subject2,
1785
+ predicate: "description",
1786
+ value: input.description,
1787
+ confidence: 1
1788
+ }
1789
+ );
1790
+ }
1791
+ return typeAssertion;
1792
+ }
1793
+ /** Add a property to an entity. */
1794
+ async addProperty(input) {
1795
+ const tenantId = input.tenantId || this.tenantId;
1796
+ const entitySubject = `entity:${input.entityName.toLowerCase().replace(/\s+/g, "-")}`;
1797
+ const propertySubject = `property:${input.entityName.toLowerCase().replace(/\s+/g, "-")}.${input.name.toLowerCase().replace(/\s+/g, "-")}`;
1798
+ const assertion = await this.http.post(
1799
+ `/api/v1/assertions`,
1800
+ {
1801
+ tenant_id: tenantId,
1802
+ subject: propertySubject,
1803
+ predicate: "field_type",
1804
+ value: input.fieldType,
1805
+ confidence: 1
1806
+ }
1807
+ );
1808
+ const relationship = await this.http.post(
1809
+ `/api/v1/relationships`,
1810
+ {
1811
+ tenant_id: tenantId,
1812
+ from_subject: entitySubject,
1813
+ to_subject: propertySubject,
1814
+ relationship_type: "has_property",
1815
+ confidence: 1
1816
+ }
1817
+ );
1818
+ if (input.required) {
1819
+ await this.http.post(
1820
+ `/api/v1/assertions`,
1821
+ {
1822
+ tenant_id: tenantId,
1823
+ subject: propertySubject,
1824
+ predicate: "required",
1825
+ value: true,
1826
+ confidence: 1
1827
+ }
1828
+ );
1829
+ }
1830
+ return { assertion, relationship };
1831
+ }
1832
+ /** Describe an entity by reconstructing its properties and relationships from assertions. */
1833
+ async describe(entityName, options) {
1834
+ const tenantId = options?.tenantId || this.tenantId;
1835
+ const subject2 = `entity:${entityName.toLowerCase().replace(/\s+/g, "-")}`;
1836
+ const assertions = await this.http.get(
1837
+ `/api/v1/assertions/query/${enc4(tenantId)}/${enc4(subject2)}`
1838
+ );
1839
+ const relationships = await this.http.get(
1840
+ `/api/v1/relationships/query/${enc4(tenantId)}/${enc4(subject2)}`
1841
+ );
1842
+ const typeAssertion = assertions.find((a) => a.predicate === "type" && !a.isSuperseded);
1843
+ const descAssertion = assertions.find((a) => a.predicate === "description" && !a.isSuperseded);
1844
+ const propertyRels = relationships.filter((r) => r.relationshipType === "has_property");
1845
+ const properties = await Promise.all(
1846
+ propertyRels.map(async (rel) => {
1847
+ const propAssertions = await this.http.get(
1848
+ `/api/v1/assertions/query/${enc4(tenantId)}/${enc4(rel.toSubject)}`
1849
+ );
1850
+ const fieldType = propAssertions.find((a) => a.predicate === "field_type" && !a.isSuperseded);
1851
+ const required = propAssertions.find((a) => a.predicate === "required" && !a.isSuperseded);
1852
+ const name = rel.toSubject.replace(/^property:[^.]+\./, "");
1853
+ return {
1854
+ name,
1855
+ fieldType: fieldType ? String(fieldType.value) : null,
1856
+ required: required ? Boolean(required.value) : false
1857
+ };
1858
+ })
1859
+ );
1860
+ const otherRels = relationships.filter((r) => r.relationshipType !== "has_property").map((r) => ({
1861
+ type: r.relationshipType,
1862
+ target: r.toSubject,
1863
+ confidence: r.confidence
1864
+ }));
1865
+ return {
1866
+ subject: subject2,
1867
+ name: entityName,
1868
+ type: typeAssertion ? String(typeAssertion.value) : null,
1869
+ description: descAssertion ? String(descAssertion.value) : null,
1870
+ properties,
1871
+ relationships: otherRels
1872
+ };
1873
+ }
1874
+ /** List all entities for a tenant (subjects with entity: prefix that have a type predicate). */
1875
+ async list(options) {
1876
+ const tenantId = options?.tenantId || this.tenantId;
1877
+ const all = await this.http.get(
1878
+ `/api/v1/assertions/list/${enc4(tenantId)}`
1879
+ );
1880
+ return all.filter((a) => a.subject.startsWith("entity:") && a.predicate === "type" && !a.isSuperseded);
1881
+ }
1882
+ };
1439
1883
  var SubCortexClient = class {
1440
1884
  /** Assertion operations (low-level knowledge primitives) */
1441
1885
  assertions;
@@ -1451,6 +1895,20 @@ var SubCortexClient = class {
1451
1895
  users;
1452
1896
  /** Emotional signals — record, query, and resolve */
1453
1897
  signals;
1898
+ /** Graph queries — pathfinding and traversal */
1899
+ graph;
1900
+ /** Temporal queries — point-in-time snapshots and range queries */
1901
+ temporal;
1902
+ /** Semantic search over assertion embeddings */
1903
+ search;
1904
+ /** BM25 full-text recall search */
1905
+ recall;
1906
+ /** Episodic memory — experiences grouped by session */
1907
+ experiences;
1908
+ /** Entity schema management — create, describe, and manage data models */
1909
+ entities;
1910
+ /** Code guardrails — typed rules stored as assertions with file-scope matching */
1911
+ rules;
1454
1912
  http;
1455
1913
  constructor(options) {
1456
1914
  if (!options.apiKey && !options.token) {
@@ -1474,13 +1932,20 @@ var SubCortexClient = class {
1474
1932
  this.intake = new IntakeNamespace(this.http, options.tenantId);
1475
1933
  this.users = new UsersNamespace(this.http, options.tenantId);
1476
1934
  this.signals = new SignalsNamespace(this.http, options.tenantId);
1935
+ this.graph = new GraphNamespace(this.http, options.tenantId);
1936
+ this.temporal = new TemporalNamespace(this.http, options.tenantId);
1937
+ this.search = new SearchNamespace(this.http, options.tenantId);
1938
+ this.recall = new RecallNamespace(this.http, options.tenantId);
1939
+ this.experiences = new ExperiencesNamespace(this.http, options.tenantId);
1940
+ this.entities = new EntitiesNamespace(this.http, options.tenantId);
1941
+ this.rules = new RulesNamespace(this.http, options.tenantId);
1477
1942
  }
1478
1943
  /** Check SubCortex server health. */
1479
1944
  async health() {
1480
1945
  return this.http.get("/health");
1481
1946
  }
1482
1947
  };
1483
- function enc3(s) {
1948
+ function enc4(s) {
1484
1949
  return encodeURIComponent(s);
1485
1950
  }
1486
1951
 
@@ -1649,9 +2114,12 @@ function esc(s) {
1649
2114
  CONTEXT_SCHEMA_VERSION,
1650
2115
  ConfidenceLevel,
1651
2116
  ConfidenceScores,
2117
+ EntitiesNamespace,
1652
2118
  EntityPredicate,
1653
2119
  EntityRelationship,
1654
2120
  EventPredicate,
2121
+ ExperiencesNamespace,
2122
+ GraphNamespace,
1655
2123
  IdentityPredicate,
1656
2124
  IntakeNamespace,
1657
2125
  MULTI_VALUE_PREDICATES,
@@ -1664,10 +2132,14 @@ function esc(s) {
1664
2132
  RELATIONSHIP_LABELS,
1665
2133
  REVERSE_RELATIONSHIPS,
1666
2134
  RapportPredicate,
2135
+ RecallNamespace,
1667
2136
  RelationshipTypes,
1668
2137
  RelationshipsNamespace,
2138
+ RulePredicates,
2139
+ RulesNamespace,
1669
2140
  SIGNAL_DECAY_CONFIG,
1670
2141
  SYSTEM_SIGNAL_TYPES,
2142
+ SearchNamespace,
1671
2143
  SignalsNamespace,
1672
2144
  SubCortexAuthenticationError,
1673
2145
  SubCortexAuthorizationError,
@@ -1681,6 +2153,7 @@ function esc(s) {
1681
2153
  SubCortexTimeoutError,
1682
2154
  SubCortexValidationError,
1683
2155
  SubjectPrefix,
2156
+ TemporalNamespace,
1684
2157
  UsersNamespace,
1685
2158
  WorkPredicate,
1686
2159
  confidenceToScore,