@subcortex-ai/sdk 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @subcortex-ai/sdk
2
2
 
3
- TypeScript SDK for the [SubCortex cognitive engine](https://github.com/tommyboy145/cortex) — persistent memory, identity, signals, and knowledge graph for AI agents.
3
+ TypeScript SDK for the [SubCortex cognitive engine](https://subcortex.ai) — persistent memory, identity, signals, and knowledge graph for AI agents.
4
4
 
5
5
  ## Install
6
6
 
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,12 @@ __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,
45
49
  SIGNAL_DECAY_CONFIG: () => SIGNAL_DECAY_CONFIG,
46
50
  SYSTEM_SIGNAL_TYPES: () => SYSTEM_SIGNAL_TYPES,
51
+ SearchNamespace: () => SearchNamespace,
47
52
  SignalsNamespace: () => SignalsNamespace,
48
53
  SubCortexAuthenticationError: () => SubCortexAuthenticationError,
49
54
  SubCortexAuthorizationError: () => SubCortexAuthorizationError,
@@ -57,6 +62,7 @@ __export(index_exports, {
57
62
  SubCortexTimeoutError: () => SubCortexTimeoutError,
58
63
  SubCortexValidationError: () => SubCortexValidationError,
59
64
  SubjectPrefix: () => SubjectPrefix,
65
+ TemporalNamespace: () => TemporalNamespace,
60
66
  UsersNamespace: () => UsersNamespace,
61
67
  WorkPredicate: () => WorkPredicate,
62
68
  confidenceToScore: () => confidenceToScore,
@@ -976,49 +982,10 @@ ${connectedPeople.map((p) => {
976
982
  let assertionsCreated = 0;
977
983
  let relationshipsCreated = 0;
978
984
  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++;
985
+ const candidates = [];
986
+ candidates.push({ subject: personSubject, predicate: "name", value: input.name, source_confidence: conf, provenance: "agent" });
987
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++;
988
+ candidates.push({ subject: personSubject, predicate: "role", value: input.role, source_confidence: conf, provenance: "agent" });
1022
989
  try {
1023
990
  const allAssertions = await this.http.get(
1024
991
  `/api/v1/assertions/list/${enc2(this.tenantId)}`
@@ -1035,6 +1002,35 @@ ${connectedPeople.map((p) => {
1035
1002
  }
1036
1003
  } catch {
1037
1004
  }
1005
+ }
1006
+ if (input.details) {
1007
+ candidates.push({ subject: personSubject, predicate: "details", value: input.details, source_confidence: conf, provenance: "agent" });
1008
+ }
1009
+ candidates.push({
1010
+ subject: personSubject,
1011
+ predicate: "status",
1012
+ value: input.relationship === "candidate" ? "candidate" : "active",
1013
+ source_confidence: conf,
1014
+ provenance: "agent"
1015
+ });
1016
+ const correlationId = `register_person_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
1017
+ const intakeResult = await this.http.post("/api/v1/intake/submit", {
1018
+ correlation_id: correlationId,
1019
+ agent_id: "sdk",
1020
+ tenant_id: this.tenantId,
1021
+ candidates,
1022
+ context: input.sessionId ? { sessionId: input.sessionId } : void 0
1023
+ });
1024
+ assertionsCreated = intakeResult.accepted + intakeResult.reinforced;
1025
+ if (intakeResult.conflicts > 0) {
1026
+ const conflictItems = (intakeResult.items || []).filter(
1027
+ (i) => i.status === "conflict_detected"
1028
+ );
1029
+ for (const item of conflictItems) {
1030
+ warnings.push(item.surfacingHint || "A conflict was detected with existing data.");
1031
+ }
1032
+ }
1033
+ if (input.role) {
1038
1034
  const roleSubject = subject("role" /* ROLE */, input.role);
1039
1035
  await this.http.post("/api/v1/assertions", {
1040
1036
  tenant_id: this.tenantId,
@@ -1050,34 +1046,13 @@ ${connectedPeople.map((p) => {
1050
1046
  relationship_type: "holds_role" /* HOLDS_ROLE */,
1051
1047
  confidence: conf
1052
1048
  });
1053
- assertionsCreated++;
1054
1049
  relationshipsCreated++;
1055
1050
  }
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
1051
  const FORWARD_MAP = {
1075
1052
  "direct_report": "manages" /* MANAGES */,
1076
1053
  "team_member": "has_member" /* HAS_MEMBER */,
1077
1054
  "candidate": "manages" /* MANAGES */,
1078
- // user manages the hiring
1079
1055
  "manager": "reports_to" /* REPORTS_TO */,
1080
- // user reports to this person
1081
1056
  "stakeholder": "stakeholder_in" /* STAKEHOLDER_IN */,
1082
1057
  "collaborator": "collaborates_with" /* COLLABORATES_WITH */,
1083
1058
  "mentor": "mentors" /* MENTORS */
@@ -1118,31 +1093,26 @@ ${connectedPeople.map((p) => {
1118
1093
  async recordRapport(input) {
1119
1094
  const userSubject = subject("user" /* USER */, input.userId);
1120
1095
  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
- });
1096
+ const candidates = [
1097
+ { subject: userSubject, predicate: input.type, value: input.value, source_confidence: conf, provenance: "agent" }
1098
+ ];
1128
1099
  if (input.aboutPerson) {
1129
1100
  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
- }
1101
+ candidates.push({
1102
+ subject: personSubject,
1103
+ predicate: "timeline",
1104
+ value: input.value,
1105
+ source_confidence: conf,
1106
+ provenance: "agent"
1107
+ });
1145
1108
  }
1109
+ const correlationId = `rapport_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
1110
+ await this.http.post("/api/v1/intake/submit", {
1111
+ correlation_id: correlationId,
1112
+ agent_id: "sdk",
1113
+ tenant_id: this.tenantId,
1114
+ candidates
1115
+ });
1146
1116
  return { success: true };
1147
1117
  }
1148
1118
  /**
@@ -1431,11 +1401,247 @@ var IntakeNamespace = class {
1431
1401
  return this.http.get(`/api/v1/intake/stats/${enc3(agentId)}`);
1432
1402
  }
1433
1403
  };
1404
+ var ExperiencesNamespace = class {
1405
+ constructor(http, tenantId) {
1406
+ this.http = http;
1407
+ this.tenantId = tenantId;
1408
+ }
1409
+ /** List experiences, optionally filtered by subject. */
1410
+ async list(input) {
1411
+ const tenantId = input?.tenantId || this.tenantId;
1412
+ const params = new URLSearchParams();
1413
+ if (input?.subject) params.set("subject", input.subject);
1414
+ if (input?.limit) params.set("limit", String(input.limit));
1415
+ const qs = params.toString();
1416
+ return this.http.get(
1417
+ `/api/v1/experiences/${enc3(tenantId)}${qs ? `?${qs}` : ""}`
1418
+ );
1419
+ }
1420
+ /** Get a single experience by ID. */
1421
+ async get(experienceId, options) {
1422
+ const tenantId = options?.tenantId || this.tenantId;
1423
+ return this.http.get(
1424
+ `/api/v1/experiences/${enc3(tenantId)}/${enc3(experienceId)}`
1425
+ );
1426
+ }
1427
+ };
1428
+ var RecallNamespace = class {
1429
+ constructor(http, tenantId) {
1430
+ this.http = http;
1431
+ this.tenantId = tenantId;
1432
+ }
1433
+ /** BM25 full-text search across assertions. */
1434
+ async search(input) {
1435
+ const tenantId = input.tenantId || this.tenantId;
1436
+ const params = new URLSearchParams({ q: input.query });
1437
+ if (input.limit) params.set("limit", String(input.limit));
1438
+ return this.http.get(
1439
+ `/api/v1/recall/${enc3(tenantId)}?${params.toString()}`
1440
+ );
1441
+ }
1442
+ };
1443
+ var GraphNamespace = class {
1444
+ constructor(http, tenantId) {
1445
+ this.http = http;
1446
+ this.tenantId = tenantId;
1447
+ }
1448
+ /** Find paths between two subjects. */
1449
+ async findPaths(input) {
1450
+ const tenantId = input.tenantId || this.tenantId;
1451
+ return this.http.post(
1452
+ `/api/v1/graph/${enc3(tenantId)}/paths`,
1453
+ {
1454
+ from: input.from,
1455
+ to: input.to,
1456
+ max_depth: input.maxDepth,
1457
+ min_confidence: input.minConfidence,
1458
+ strategy: input.strategy
1459
+ }
1460
+ );
1461
+ }
1462
+ /** BFS traversal from a starting subject. */
1463
+ async traverse(input) {
1464
+ const tenantId = input.tenantId || this.tenantId;
1465
+ return this.http.post(
1466
+ `/api/v1/graph/${enc3(tenantId)}/traverse`,
1467
+ {
1468
+ start_subject: input.startSubject,
1469
+ max_depth: input.maxDepth,
1470
+ relationship_types: input.relationshipTypes,
1471
+ min_confidence: input.minConfidence,
1472
+ max_nodes: input.maxNodes
1473
+ }
1474
+ );
1475
+ }
1476
+ };
1477
+ var TemporalNamespace = class {
1478
+ constructor(http, tenantId) {
1479
+ this.http = http;
1480
+ this.tenantId = tenantId;
1481
+ }
1482
+ /** Get assertions valid at a specific point in time. */
1483
+ async at(subject2, point, options) {
1484
+ const tenantId = options?.tenantId || this.tenantId;
1485
+ const pointStr = point instanceof Date ? point.toISOString() : point;
1486
+ return this.http.get(
1487
+ `/api/v1/temporal/${enc3(tenantId)}/${enc3(subject2)}/at?point=${enc3(pointStr)}`
1488
+ );
1489
+ }
1490
+ /** Get assertions within a date range. */
1491
+ async range(subject2, start, end, options) {
1492
+ const tenantId = options?.tenantId || this.tenantId;
1493
+ const startStr = start instanceof Date ? start.toISOString() : start;
1494
+ const endStr = end instanceof Date ? end.toISOString() : end;
1495
+ return this.http.get(
1496
+ `/api/v1/temporal/${enc3(tenantId)}/${enc3(subject2)}/range?start=${enc3(startStr)}&end=${enc3(endStr)}`
1497
+ );
1498
+ }
1499
+ };
1500
+ var SearchNamespace = class {
1501
+ constructor(http, tenantId) {
1502
+ this.http = http;
1503
+ this.tenantId = tenantId;
1504
+ }
1505
+ /** Semantic nearest-neighbor search over assertion embeddings. */
1506
+ async semantic(input) {
1507
+ const tenantId = input.tenantId || this.tenantId;
1508
+ return this.http.post(
1509
+ `/api/v1/search/${enc3(tenantId)}/semantic`,
1510
+ {
1511
+ embedding: input.embedding,
1512
+ top_k: input.topK
1513
+ }
1514
+ );
1515
+ }
1516
+ };
1434
1517
  var DEFAULT_RETRY = {
1435
1518
  maxRetries: 3,
1436
1519
  baseDelayMs: 500,
1437
1520
  maxDelayMs: 1e4
1438
1521
  };
1522
+ var EntitiesNamespace = class {
1523
+ constructor(http, tenantId) {
1524
+ this.http = http;
1525
+ this.tenantId = tenantId;
1526
+ }
1527
+ /** Create an entity with optional description and type. */
1528
+ async create(input) {
1529
+ const tenantId = input.tenantId || this.tenantId;
1530
+ const subject2 = `entity:${input.name.toLowerCase().replace(/\s+/g, "-")}`;
1531
+ const typeAssertion = await this.http.post(
1532
+ `/api/v1/assertions`,
1533
+ {
1534
+ tenant_id: tenantId,
1535
+ subject: subject2,
1536
+ predicate: "type",
1537
+ value: input.type || "model",
1538
+ confidence: 1
1539
+ }
1540
+ );
1541
+ if (input.description) {
1542
+ await this.http.post(
1543
+ `/api/v1/assertions`,
1544
+ {
1545
+ tenant_id: tenantId,
1546
+ subject: subject2,
1547
+ predicate: "description",
1548
+ value: input.description,
1549
+ confidence: 1
1550
+ }
1551
+ );
1552
+ }
1553
+ return typeAssertion;
1554
+ }
1555
+ /** Add a property to an entity. */
1556
+ async addProperty(input) {
1557
+ const tenantId = input.tenantId || this.tenantId;
1558
+ const entitySubject = `entity:${input.entityName.toLowerCase().replace(/\s+/g, "-")}`;
1559
+ const propertySubject = `property:${input.entityName.toLowerCase().replace(/\s+/g, "-")}.${input.name.toLowerCase().replace(/\s+/g, "-")}`;
1560
+ const assertion = await this.http.post(
1561
+ `/api/v1/assertions`,
1562
+ {
1563
+ tenant_id: tenantId,
1564
+ subject: propertySubject,
1565
+ predicate: "field_type",
1566
+ value: input.fieldType,
1567
+ confidence: 1
1568
+ }
1569
+ );
1570
+ const relationship = await this.http.post(
1571
+ `/api/v1/relationships`,
1572
+ {
1573
+ tenant_id: tenantId,
1574
+ from_subject: entitySubject,
1575
+ to_subject: propertySubject,
1576
+ relationship_type: "has_property",
1577
+ confidence: 1
1578
+ }
1579
+ );
1580
+ if (input.required) {
1581
+ await this.http.post(
1582
+ `/api/v1/assertions`,
1583
+ {
1584
+ tenant_id: tenantId,
1585
+ subject: propertySubject,
1586
+ predicate: "required",
1587
+ value: true,
1588
+ confidence: 1
1589
+ }
1590
+ );
1591
+ }
1592
+ return { assertion, relationship };
1593
+ }
1594
+ /** Describe an entity by reconstructing its properties and relationships from assertions. */
1595
+ async describe(entityName, options) {
1596
+ const tenantId = options?.tenantId || this.tenantId;
1597
+ const subject2 = `entity:${entityName.toLowerCase().replace(/\s+/g, "-")}`;
1598
+ const assertions = await this.http.get(
1599
+ `/api/v1/assertions/query/${enc3(tenantId)}/${enc3(subject2)}`
1600
+ );
1601
+ const relationships = await this.http.get(
1602
+ `/api/v1/relationships/query/${enc3(tenantId)}/${enc3(subject2)}`
1603
+ );
1604
+ const typeAssertion = assertions.find((a) => a.predicate === "type" && !a.isSuperseded);
1605
+ const descAssertion = assertions.find((a) => a.predicate === "description" && !a.isSuperseded);
1606
+ const propertyRels = relationships.filter((r) => r.relationshipType === "has_property");
1607
+ const properties = await Promise.all(
1608
+ propertyRels.map(async (rel) => {
1609
+ const propAssertions = await this.http.get(
1610
+ `/api/v1/assertions/query/${enc3(tenantId)}/${enc3(rel.toSubject)}`
1611
+ );
1612
+ const fieldType = propAssertions.find((a) => a.predicate === "field_type" && !a.isSuperseded);
1613
+ const required = propAssertions.find((a) => a.predicate === "required" && !a.isSuperseded);
1614
+ const name = rel.toSubject.replace(/^property:[^.]+\./, "");
1615
+ return {
1616
+ name,
1617
+ fieldType: fieldType ? String(fieldType.value) : null,
1618
+ required: required ? Boolean(required.value) : false
1619
+ };
1620
+ })
1621
+ );
1622
+ const otherRels = relationships.filter((r) => r.relationshipType !== "has_property").map((r) => ({
1623
+ type: r.relationshipType,
1624
+ target: r.toSubject,
1625
+ confidence: r.confidence
1626
+ }));
1627
+ return {
1628
+ subject: subject2,
1629
+ name: entityName,
1630
+ type: typeAssertion ? String(typeAssertion.value) : null,
1631
+ description: descAssertion ? String(descAssertion.value) : null,
1632
+ properties,
1633
+ relationships: otherRels
1634
+ };
1635
+ }
1636
+ /** List all entities for a tenant (subjects with entity: prefix that have a type predicate). */
1637
+ async list(options) {
1638
+ const tenantId = options?.tenantId || this.tenantId;
1639
+ const all = await this.http.get(
1640
+ `/api/v1/assertions/list/${enc3(tenantId)}`
1641
+ );
1642
+ return all.filter((a) => a.subject.startsWith("entity:") && a.predicate === "type" && !a.isSuperseded);
1643
+ }
1644
+ };
1439
1645
  var SubCortexClient = class {
1440
1646
  /** Assertion operations (low-level knowledge primitives) */
1441
1647
  assertions;
@@ -1451,6 +1657,18 @@ var SubCortexClient = class {
1451
1657
  users;
1452
1658
  /** Emotional signals — record, query, and resolve */
1453
1659
  signals;
1660
+ /** Graph queries — pathfinding and traversal */
1661
+ graph;
1662
+ /** Temporal queries — point-in-time snapshots and range queries */
1663
+ temporal;
1664
+ /** Semantic search over assertion embeddings */
1665
+ search;
1666
+ /** BM25 full-text recall search */
1667
+ recall;
1668
+ /** Episodic memory — experiences grouped by session */
1669
+ experiences;
1670
+ /** Entity schema management — create, describe, and manage data models */
1671
+ entities;
1454
1672
  http;
1455
1673
  constructor(options) {
1456
1674
  if (!options.apiKey && !options.token) {
@@ -1474,6 +1692,12 @@ var SubCortexClient = class {
1474
1692
  this.intake = new IntakeNamespace(this.http, options.tenantId);
1475
1693
  this.users = new UsersNamespace(this.http, options.tenantId);
1476
1694
  this.signals = new SignalsNamespace(this.http, options.tenantId);
1695
+ this.graph = new GraphNamespace(this.http, options.tenantId);
1696
+ this.temporal = new TemporalNamespace(this.http, options.tenantId);
1697
+ this.search = new SearchNamespace(this.http, options.tenantId);
1698
+ this.recall = new RecallNamespace(this.http, options.tenantId);
1699
+ this.experiences = new ExperiencesNamespace(this.http, options.tenantId);
1700
+ this.entities = new EntitiesNamespace(this.http, options.tenantId);
1477
1701
  }
1478
1702
  /** Check SubCortex server health. */
1479
1703
  async health() {
@@ -1649,9 +1873,12 @@ function esc(s) {
1649
1873
  CONTEXT_SCHEMA_VERSION,
1650
1874
  ConfidenceLevel,
1651
1875
  ConfidenceScores,
1876
+ EntitiesNamespace,
1652
1877
  EntityPredicate,
1653
1878
  EntityRelationship,
1654
1879
  EventPredicate,
1880
+ ExperiencesNamespace,
1881
+ GraphNamespace,
1655
1882
  IdentityPredicate,
1656
1883
  IntakeNamespace,
1657
1884
  MULTI_VALUE_PREDICATES,
@@ -1664,10 +1891,12 @@ function esc(s) {
1664
1891
  RELATIONSHIP_LABELS,
1665
1892
  REVERSE_RELATIONSHIPS,
1666
1893
  RapportPredicate,
1894
+ RecallNamespace,
1667
1895
  RelationshipTypes,
1668
1896
  RelationshipsNamespace,
1669
1897
  SIGNAL_DECAY_CONFIG,
1670
1898
  SYSTEM_SIGNAL_TYPES,
1899
+ SearchNamespace,
1671
1900
  SignalsNamespace,
1672
1901
  SubCortexAuthenticationError,
1673
1902
  SubCortexAuthorizationError,
@@ -1681,6 +1910,7 @@ function esc(s) {
1681
1910
  SubCortexTimeoutError,
1682
1911
  SubCortexValidationError,
1683
1912
  SubjectPrefix,
1913
+ TemporalNamespace,
1684
1914
  UsersNamespace,
1685
1915
  WorkPredicate,
1686
1916
  confidenceToScore,