@subcortex-ai/sdk 0.3.8 → 0.3.10

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
@@ -242,6 +242,27 @@ const subcortex = new SubCortexClient({
242
242
  })
243
243
  ```
244
244
 
245
+ ## Framework Integration
246
+
247
+ ### Next.js (App Router)
248
+
249
+ Next.js patches `globalThis.fetch` with aggressive caching. GET requests — including assertion queries, user identification, and signal snapshots — will return stale data unless you bypass the cache. **This is critical for cognitive data that changes between sessions.**
250
+
251
+ ```typescript
252
+ // app/api/my-agent/route.ts
253
+ const noCacheFetch: typeof fetch = (input, init) =>
254
+ fetch(input, { ...init, cache: 'no-store' })
255
+
256
+ const subcortex = new SubCortexClient({
257
+ endpoint: process.env.SUBCORTEX_ENDPOINT!,
258
+ tenantId: process.env.SUBCORTEX_TENANT_ID!,
259
+ apiKey: process.env.SUBCORTEX_API_KEY,
260
+ fetch: noCacheFetch, // ← Required in Next.js
261
+ })
262
+ ```
263
+
264
+ Without this, `users.identify()`, `assertions.query()`, and `signals.query()` may return cached results — meaning new assertions added between sessions (by other agents, users, or the SubCortex console) will be invisible until a hard page refresh.
265
+
245
266
  ## What is SubCortex?
246
267
 
247
268
  SubCortex is a purpose-built cognitive engine for AI agents — persistent memory, identity, emotional signals, and knowledge graph in one system.
package/dist/index.cjs CHANGED
@@ -485,6 +485,7 @@ var OrgRelationship = /* @__PURE__ */ ((OrgRelationship2) => {
485
485
  OrgRelationship2["HAS_MEMBER"] = "has_member";
486
486
  OrgRelationship2["HOLDS_ROLE"] = "holds_role";
487
487
  OrgRelationship2["CANDIDATE_FOR"] = "candidate_for";
488
+ OrgRelationship2["CONSIDERING"] = "considering";
488
489
  OrgRelationship2["COLLABORATES_WITH"] = "collaborates_with";
489
490
  OrgRelationship2["MENTORS"] = "mentors";
490
491
  OrgRelationship2["MENTORED_BY"] = "mentored_by";
@@ -554,7 +555,8 @@ var REVERSE_RELATIONSHIPS = {
554
555
  ["mentors" /* MENTORS */]: "mentored_by" /* MENTORED_BY */,
555
556
  ["mentored_by" /* MENTORED_BY */]: "mentors" /* MENTORS */,
556
557
  ["collaborates_with" /* COLLABORATES_WITH */]: "collaborates_with" /* COLLABORATES_WITH */,
557
- ["candidate_for" /* CANDIDATE_FOR */]: "candidate_for" /* CANDIDATE_FOR */,
558
+ ["candidate_for" /* CANDIDATE_FOR */]: "considering" /* CONSIDERING */,
559
+ ["considering" /* CONSIDERING */]: "candidate_for" /* CANDIDATE_FOR */,
558
560
  ["stakeholder_in" /* STAKEHOLDER_IN */]: "stakeholder_in" /* STAKEHOLDER_IN */,
559
561
  // Agent-facing predicate names → proper relationship types
560
562
  // The model sends 'direct_report' as predicate, SDK maps to proper relationships
@@ -856,13 +858,15 @@ var UsersNamespace = class {
856
858
  const nameAssertion = active.find((a) => a.predicate === "name" || a.predicate === "full_name");
857
859
  const name = nameAssertion?.value || input.displayName || null;
858
860
  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 }));
859
- for (const reminder of reminders) {
860
- try {
861
- await this.http.post(
862
- `/api/v1/assertions/retract/${enc2(this.tenantId)}/${enc2(reminder.id)}`,
863
- {}
864
- );
865
- } catch {
861
+ if (input.dismissReminders !== false) {
862
+ for (const reminder of reminders) {
863
+ try {
864
+ await this.http.post(
865
+ `/api/v1/assertions/retract/${enc2(this.tenantId)}/${enc2(reminder.id)}`,
866
+ {}
867
+ );
868
+ } catch {
869
+ }
866
870
  }
867
871
  }
868
872
  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 }));
@@ -1053,7 +1057,7 @@ ${connectedPeople.map((p) => {
1053
1057
  const FORWARD_MAP = {
1054
1058
  "direct_report": "manages" /* MANAGES */,
1055
1059
  "team_member": "has_member" /* HAS_MEMBER */,
1056
- "candidate": "manages" /* MANAGES */,
1060
+ "candidate": "considering" /* CONSIDERING */,
1057
1061
  "manager": "reports_to" /* REPORTS_TO */,
1058
1062
  "stakeholder": "stakeholder_in" /* STAKEHOLDER_IN */,
1059
1063
  "collaborator": "collaborates_with" /* COLLABORATES_WITH */,
@@ -1845,7 +1849,7 @@ var EntitiesNamespace = class {
1845
1849
  `/api/v1/assertions/query/${enc4(tenantId)}/${enc4(subject2)}`
1846
1850
  );
1847
1851
  const relationships = await this.http.get(
1848
- `/api/v1/relationships/query/${enc4(tenantId)}/${enc4(subject2)}`
1852
+ `/api/v1/relationships/${enc4(tenantId)}/${enc4(subject2)}`
1849
1853
  );
1850
1854
  const typeAssertion = assertions.find((a) => a.predicate === "type" && !a.isSuperseded);
1851
1855
  const descAssertion = assertions.find((a) => a.predicate === "description" && !a.isSuperseded);
@@ -2058,16 +2062,25 @@ function toContextXml(user, options = {}) {
2058
2062
  if (knowledge.length > 0) {
2059
2063
  lines.push(` <knowledge count="${knowledge.length}">`);
2060
2064
  for (const mem of knowledge) {
2065
+ if (mem.predicate.startsWith("signal:")) {
2066
+ const sigType = mem.predicate.slice(7);
2067
+ const val = mem.value;
2068
+ const content = typeof val === "object" && val?.content ? String(val.content) : formatValue(mem.value);
2069
+ const intensity = typeof val === "object" && val?.intensity ? Number(val.intensity) : mem.confidence;
2070
+ const about = typeof val === "object" && val?.aboutSubject ? ` about="${esc(String(val.aboutSubject))}"` : "";
2071
+ lines.push(` <signal type="${esc(sigType)}" intensity="${fmtConf(intensity)}"${about}>${esc(content)}</signal>`);
2072
+ continue;
2073
+ }
2061
2074
  const memSignals = findSignalsForFact(mem, signalsByAbout);
2062
2075
  if (memSignals.length > 0) {
2063
2076
  lines.push(` <fact predicate="${esc(mem.predicate)}" confidence="${fmtConf(mem.confidence)}">`);
2064
- lines.push(` ${esc(String(mem.value))}`);
2077
+ lines.push(` ${esc(formatValue(mem.value))}`);
2065
2078
  for (const sig of memSignals) {
2066
2079
  lines.push(` ${renderSignal(sig)}`);
2067
2080
  }
2068
2081
  lines.push(` </fact>`);
2069
2082
  } else {
2070
- lines.push(` <fact predicate="${esc(mem.predicate)}" confidence="${fmtConf(mem.confidence)}">${esc(String(mem.value))}</fact>`);
2083
+ lines.push(` <fact predicate="${esc(mem.predicate)}" confidence="${fmtConf(mem.confidence)}">${esc(formatValue(mem.value))}</fact>`);
2071
2084
  }
2072
2085
  }
2073
2086
  lines.push(` </knowledge>`);
@@ -2109,6 +2122,12 @@ function findSignalsForFact(fact, signalsByAbout) {
2109
2122
  }
2110
2123
  return results;
2111
2124
  }
2125
+ function formatValue(v) {
2126
+ if (v === null || v === void 0) return "";
2127
+ if (typeof v === "string") return v;
2128
+ if (typeof v === "object" && "content" in v) return String(v.content);
2129
+ return JSON.stringify(v);
2130
+ }
2112
2131
  function fmtConf(n) {
2113
2132
  return n.toFixed(2);
2114
2133
  }