@pyxmate/memory 0.37.0 → 0.38.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.
@@ -100,6 +100,7 @@ var MemoryClient = class {
100
100
  if (params.type) searchParams.set("type", params.type);
101
101
  if (params.agentId) searchParams.set("agentId", params.agentId);
102
102
  if (params.strategy) searchParams.set("strategy", params.strategy);
103
+ if (params.effort) searchParams.set("effort", params.effort);
103
104
  if (params.eventTimeRange) {
104
105
  searchParams.set("eventTimeStart", params.eventTimeRange[0]);
105
106
  searchParams.set("eventTimeEnd", params.eventTimeRange[1]);
@@ -628,6 +629,27 @@ var MemoryClient = class {
628
629
  );
629
630
  return result.entries;
630
631
  }
632
+ async lineage(params) {
633
+ const searchParams = new URLSearchParams();
634
+ if (params.subject) searchParams.set("subject", params.subject);
635
+ if (params.relation) searchParams.set("relation", params.relation);
636
+ if (params.entryId) searchParams.set("entryId", params.entryId);
637
+ if (params.asOf) searchParams.set("asOf", params.asOf);
638
+ if (params.beforeValue) searchParams.set("beforeValue", params.beforeValue);
639
+ if (params.limit !== void 0) searchParams.set("limit", String(params.limit));
640
+ if (params.eventTimeRange) {
641
+ searchParams.set("eventTimeStart", params.eventTimeRange[0]);
642
+ searchParams.set("eventTimeEnd", params.eventTimeRange[1]);
643
+ }
644
+ const qs = searchParams.toString();
645
+ return this.fetchApi(`/api/memory/lineage${qs ? `?${qs}` : ""}`);
646
+ }
647
+ async reinforce(params) {
648
+ return this.fetchApi("/api/memory/reinforce", {
649
+ method: "POST",
650
+ body: JSON.stringify(params)
651
+ });
652
+ }
631
653
  async log(filters = {}) {
632
654
  const params = new URLSearchParams();
633
655
  if (filters.since) params.set("since", filters.since);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  MemoryClient
3
- } from "./chunk-EXUSQ2GR.mjs";
3
+ } from "./chunk-CK7VUON3.mjs";
4
4
 
5
5
  // ../dashboard/src/aggregations/consolidation-analytics.ts
6
6
  function analyzeConsolidationLog(entries) {
@@ -555,7 +555,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
555
555
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
556
556
 
557
557
  // src/mcp/instructions.ts
558
- var PYX_MEMORY_INSTRUCTIONS = `Use pyx-memory to search durable project/user memory before assuming prior decisions, and to store concise facts after corrections, bug fixes, design decisions, integration discoveries, gotchas, explicit preferences, or "remember this" requests. Store decisions, not deliberation. Include topic and project. Pass eventTime (ISO-8601, when the fact happened or took effect) for any fact that can change or go stale \u2014 job/status changes, decisions that supersede earlier ones, dated events; recency ordering, dated ("as of") queries, and stale-vs-current conflict resolution all key off it. When a question names a time \u2014 explicit or relative ("last year", "\uB450 \uB2EC \uC804") \u2014 resolve it to an absolute ISO-8601 timestamp yourself and pass it as search anchorTime: results then rank by proximity to that time instead of now, without excluding anything. When content names people, organizations, tools, places, events, or key concepts, you (the caller) must extract and pass both entities and relationships \u2014 the server does not auto-extract them. Edges matter as much as nodes: without relationships the graph cannot connect related memories. Use file ingest for documents/images worth persisting; images require a description.`;
558
+ var PYX_MEMORY_INSTRUCTIONS = `Use pyx-memory to search durable project/user memory before assuming prior decisions, and to store concise facts after corrections, bug fixes, design decisions, integration discoveries, gotchas, explicit preferences, or "remember this" requests. Store decisions, not deliberation. Include topic and project. Pass eventTime (ISO-8601, when the fact happened or took effect) for any fact that can change or go stale \u2014 job/status changes, decisions that supersede earlier ones, dated events; recency ordering, dated ("as of") queries, and stale-vs-current conflict resolution all key off it. Search effort is retrieval depth: quick=strongest, deep=everything including archived/superseded. Use reinforce after memories were actually used, so they surface in quick/medium effort tiers. Use lineage for the history of how a fact changed; pass subject+relation for graph lineage or entryId for a superseded chain. When a question names a time \u2014 explicit or relative ("last year", "\uB450 \uB2EC \uC804") \u2014 resolve it to an absolute ISO-8601 timestamp yourself and pass it as search anchorTime: results then rank by proximity to this time instead of now, without excluding anything. When content names people, organizations, tools, places, events, or key concepts, you (the caller) must extract and pass both entities and relationships \u2014 the server does not auto-extract them. Edges matter as much as nodes: without relationships the graph cannot connect related memories. Use file ingest for documents/images worth persisting; images require a description.`;
559
559
 
560
560
  // src/mcp/sampling.ts
561
561
  function createSamplingClient(server) {
@@ -910,17 +910,62 @@ var ingestMemoryFileTool = {
910
910
  }
911
911
  };
912
912
 
913
- // src/mcp/tools/list.ts
913
+ // src/mcp/tools/lineage.ts
914
914
  import { z as z6 } from "zod";
915
915
  var inputShape4 = {
916
- mode: z6.enum(["entries", "log"]).optional().describe(
916
+ subject: z6.string().optional().describe("Graph subject to trace, used with relation for graph lineage."),
917
+ relation: z6.string().optional().describe("Graph relation to trace for the subject."),
918
+ entryId: z6.string().optional().describe("Memory entry id to trace through its supersededBy chain."),
919
+ asOf: z6.string().optional().describe("Only include lineage versions ingested by this ISO-8601 time."),
920
+ eventTimeStart: z6.string().optional().describe("Inclusive event-time start (ISO-8601)."),
921
+ eventTimeEnd: z6.string().optional().describe("Inclusive event-time end (ISO-8601)."),
922
+ beforeValue: z6.string().optional().describe("Stop before the lineage version with this value."),
923
+ limit: z6.number().int().positive().optional().describe("Maximum lineage versions to return."),
924
+ ...scopeShape
925
+ };
926
+ var lineageTool = {
927
+ name: "lineage",
928
+ config: {
929
+ title: "Trace pyx-memory fact lineage",
930
+ description: "Return the time-ordered history of how a fact evolved: subject+relation traces graph lineage, entryId traces a supersededBy chain. Use for questions like what did X use before Y or how did this fact evolve.",
931
+ inputSchema: inputShape4,
932
+ annotations: { readOnlyHint: true, openWorldHint: true }
933
+ },
934
+ handler: (deps) => async (raw) => {
935
+ const args = raw;
936
+ const creds = await deps.readCredentials();
937
+ if (!creds.ok) return creds.result;
938
+ const http = createHttpClient(creds.credentials, deps.fetchImpl);
939
+ const res = await http.requestJson({
940
+ method: "GET",
941
+ path: "/api/memory/lineage",
942
+ query: {
943
+ subject: args.subject,
944
+ relation: args.relation,
945
+ entryId: args.entryId,
946
+ asOf: args.asOf,
947
+ eventTimeStart: args.eventTimeStart,
948
+ eventTimeEnd: args.eventTimeEnd,
949
+ beforeValue: args.beforeValue,
950
+ limit: args.limit
951
+ },
952
+ scope: args
953
+ });
954
+ return res.ok ? mcpJson(res.data) : res.result;
955
+ }
956
+ };
957
+
958
+ // src/mcp/tools/list.ts
959
+ import { z as z7 } from "zod";
960
+ var inputShape5 = {
961
+ mode: z7.enum(["entries", "log"]).optional().describe(
917
962
  "Listing mode. `entries` (default) returns paginated entries by filter; `log` returns the chronological memory log."
918
963
  ),
919
- page: z6.number().int().min(1).optional().describe("1-based page index for entries mode."),
920
- limit: z6.number().int().min(1).max(200).optional().describe("Page size; server clamps."),
921
- type: z6.enum(["short-term", "long-term", "working", "episodic", "summary"]).optional().describe("Filter by memory type."),
922
- agentId: z6.string().optional().describe("Filter to memories from this agentId."),
923
- since: z6.string().optional().describe("ISO-8601 lower bound for log mode."),
964
+ page: z7.number().int().min(1).optional().describe("1-based page index for entries mode."),
965
+ limit: z7.number().int().min(1).max(200).optional().describe("Page size; server clamps."),
966
+ type: z7.enum(["short-term", "long-term", "working", "episodic", "summary"]).optional().describe("Filter by memory type."),
967
+ agentId: z7.string().optional().describe("Filter to memories from this agentId."),
968
+ since: z7.string().optional().describe("ISO-8601 lower bound for log mode."),
924
969
  ...scopeShape
925
970
  };
926
971
  var listMemoriesTool = {
@@ -928,7 +973,7 @@ var listMemoriesTool = {
928
973
  config: {
929
974
  title: "List pyx-memory",
930
975
  description: "List recent memory entries or a chronological memory log. Same tool for both reads \u2014 `mode` controls which.",
931
- inputSchema: inputShape4,
976
+ inputSchema: inputShape5,
932
977
  annotations: { readOnlyHint: true, openWorldHint: true }
933
978
  },
934
979
  handler: (deps) => async (raw) => {
@@ -955,9 +1000,9 @@ var listMemoriesTool = {
955
1000
  };
956
1001
 
957
1002
  // src/mcp/tools/profile.ts
958
- import { z as z7 } from "zod";
1003
+ import { z as z8 } from "zod";
959
1004
  var getInputShape = {
960
- namespaceId: z7.string().min(1).describe("Namespace id whose user-profile to fetch."),
1005
+ namespaceId: z8.string().min(1).describe("Namespace id whose user-profile to fetch."),
961
1006
  ...scopeShape
962
1007
  };
963
1008
  var getUserProfileTool = {
@@ -983,8 +1028,8 @@ var getUserProfileTool = {
983
1028
  }
984
1029
  };
985
1030
  var upsertInputShape = {
986
- namespaceId: z7.string().min(1).describe("Namespace id to upsert the user-profile into."),
987
- content: z7.string().min(1).describe("Full freeform profile content (UTF-8, \u22648192 bytes; server enforces the cap)."),
1031
+ namespaceId: z8.string().min(1).describe("Namespace id to upsert the user-profile into."),
1032
+ content: z8.string().min(1).describe("Full freeform profile content (UTF-8, \u22648192 bytes; server enforces the cap)."),
988
1033
  ...scopeShape
989
1034
  };
990
1035
  var upsertUserProfileTool = {
@@ -1010,21 +1055,57 @@ var upsertUserProfileTool = {
1010
1055
  }
1011
1056
  };
1012
1057
 
1058
+ // src/mcp/tools/reinforce.ts
1059
+ import { z as z9 } from "zod";
1060
+ var inputShape6 = {
1061
+ entryIds: z9.array(z9.string().min(1)).min(1).describe("Memory entry ids that were actually used."),
1062
+ signal: z9.enum(["context_included", "cited", "explicit_positive"]).describe("Reinforcement signal: context_included < cited < explicit_positive."),
1063
+ at: z9.union([z9.string(), z9.number()]).optional().describe("Recall time as epoch-ms or full ISO-8601 timestamp with timezone."),
1064
+ ...scopeShape
1065
+ };
1066
+ var reinforceTool = {
1067
+ name: "reinforce",
1068
+ config: {
1069
+ title: "Reinforce used pyx-memory entries",
1070
+ description: "Reinforce memories the agent actually USED (recall reinforces \u2014 raises strength so they surface in quick/medium effort tiers). signal: context_included < cited < explicit_positive.",
1071
+ inputSchema: inputShape6,
1072
+ annotations: { readOnlyHint: false, openWorldHint: true }
1073
+ },
1074
+ handler: (deps) => async (raw) => {
1075
+ const args = raw;
1076
+ const creds = await deps.readCredentials();
1077
+ if (!creds.ok) return creds.result;
1078
+ const http = createHttpClient(creds.credentials, deps.fetchImpl);
1079
+ const res = await http.requestJson({
1080
+ method: "POST",
1081
+ path: "/api/memory/reinforce",
1082
+ body: { entryIds: args.entryIds, signal: args.signal, at: args.at },
1083
+ scope: args
1084
+ });
1085
+ return res.ok ? mcpJson(res.data) : res.result;
1086
+ }
1087
+ };
1088
+
1013
1089
  // src/mcp/tools/search.ts
1014
- import { z as z8 } from "zod";
1015
- var inputShape5 = {
1016
- query: z8.string().min(1).describe("Required natural-language search text."),
1017
- limit: z8.number().int().min(1).max(100).optional().describe("Maximum results; server clamps to 1\u2013100. Default 10."),
1018
- strategy: z8.enum(["naive", "graph", "hybrid"]).optional().describe(
1090
+ import { z as z10 } from "zod";
1091
+ var inputShape7 = {
1092
+ query: z10.string().min(1).describe("Required natural-language search text."),
1093
+ limit: z10.number().int().min(1).max(100).optional().describe(
1094
+ 'Target result count; server clamps to 1\u2013100. Default 10. The hybrid strategy may widen enumeration/count queries ("how many \u2026", "list all/every \u2026") up to 30 for set-completeness recall.'
1095
+ ),
1096
+ strategy: z10.enum(["naive", "graph", "hybrid"]).optional().describe(
1019
1097
  "RAG strategy. Defaults to `hybrid` (cross-encoder reranking, multi-entity decomposition, confidence scoring) and is sent explicitly when omitted; pass `naive` for a lighter vector-only search or `graph` for graph-augmented retrieval."
1020
1098
  ),
1021
- type: z8.enum(["short-term", "long-term", "working", "episodic", "summary"]).optional().describe("Filter by memory type."),
1022
- agentId: z8.string().optional().describe("Filter to memories stored for this agentId."),
1023
- abstentionThreshold: z8.number().min(0).max(1).optional().describe("Enable confidence scoring; abstain when confidence falls below this value (0\u20131)."),
1024
- eventTimeStart: z8.string().optional().describe("Inclusive event-time start (ISO-8601); must be paired with eventTimeEnd."),
1025
- eventTimeEnd: z8.string().optional().describe("Inclusive event-time end (ISO-8601); must be paired with eventTimeStart."),
1026
- asOf: z8.string().optional().describe("Only include memories ingested before this ISO-8601 timestamp."),
1027
- anchorTime: z8.string().optional().describe(
1099
+ effort: z10.enum(["quick", "medium", "deep"]).optional().describe(
1100
+ "Retrieval depth: quick=strongest, medium=default-depth, deep=everything including archived/superseded."
1101
+ ),
1102
+ type: z10.enum(["short-term", "long-term", "working", "episodic", "summary"]).optional().describe("Filter by memory type."),
1103
+ agentId: z10.string().optional().describe("Filter to memories stored for this agentId."),
1104
+ abstentionThreshold: z10.number().min(0).max(1).optional().describe("Enable confidence scoring; abstain when confidence falls below this value (0\u20131)."),
1105
+ eventTimeStart: z10.string().optional().describe("Inclusive event-time start (ISO-8601); must be paired with eventTimeEnd."),
1106
+ eventTimeEnd: z10.string().optional().describe("Inclusive event-time end (ISO-8601); must be paired with eventTimeStart."),
1107
+ asOf: z10.string().optional().describe("Only include memories ingested before this ISO-8601 timestamp."),
1108
+ anchorTime: z10.string().optional().describe(
1028
1109
  'Soft recency ANCHOR (ISO-8601) \u2014 ranks results by proximity to this time instead of now; never excludes anything. When the question names a relative time ("two months ago", "last year", "3\uB144 \uC804"), resolve it against the current date yourself and pass the absolute timestamp here; prefer this over eventTimeStart/End unless a strict window is required, because hard filters drop last-known-before facts.'
1029
1110
  ),
1030
1111
  ...scopeShape
@@ -1034,7 +1115,7 @@ var searchMemoriesTool = {
1034
1115
  config: {
1035
1116
  title: "Search pyx-memory",
1036
1117
  description: "Search durable pyx-memory entries with hybrid/vector/keyword/graph strategy, tenant scope, sensitivity access, and optional confidence/abstention.",
1037
- inputSchema: inputShape5,
1118
+ inputSchema: inputShape7,
1038
1119
  annotations: { readOnlyHint: true, openWorldHint: true }
1039
1120
  },
1040
1121
  handler: (deps) => async (raw) => {
@@ -1053,6 +1134,7 @@ var searchMemoriesTool = {
1053
1134
  // `naive` (1–2 results vs hybrid's 15–20) — sending it explicitly makes
1054
1135
  // recall deterministic regardless of the instance version.
1055
1136
  strategy: args.strategy ?? "hybrid",
1137
+ effort: args.effort,
1056
1138
  type: args.type,
1057
1139
  agentId: args.agentId,
1058
1140
  abstentionThreshold: args.abstentionThreshold,
@@ -1068,13 +1150,13 @@ var searchMemoriesTool = {
1068
1150
  };
1069
1151
 
1070
1152
  // src/mcp/tools/status.ts
1071
- var inputShape6 = {};
1153
+ var inputShape8 = {};
1072
1154
  var statusTool = {
1073
1155
  name: "status",
1074
1156
  config: {
1075
1157
  title: "Get pyx-memory topology",
1076
1158
  description: "Fetch the running pyx-memory server topology from GET /status when available. Hosted gateways that expose /health but not /status return an explicit topologyUnavailable result with the health payload.",
1077
- inputSchema: inputShape6,
1159
+ inputSchema: inputShape8,
1078
1160
  annotations: { readOnlyHint: true, openWorldHint: true }
1079
1161
  },
1080
1162
  handler: (deps) => async () => {
@@ -1097,10 +1179,10 @@ var statusTool = {
1097
1179
  };
1098
1180
 
1099
1181
  // src/mcp/tools/store.ts
1100
- import { z as z10 } from "zod";
1182
+ import { z as z12 } from "zod";
1101
1183
 
1102
1184
  // src/mcp/extraction-prompt.ts
1103
- import { z as z9 } from "zod";
1185
+ import { z as z11 } from "zod";
1104
1186
  var ENTITY_TYPES = ["PERSON", "ORGANIZATION", "CONCEPT", "TOOL", "LOCATION", "EVENT"];
1105
1187
  var RELATION_TYPES = [
1106
1188
  "USES",
@@ -1113,18 +1195,18 @@ var RELATION_TYPES = [
1113
1195
  "WORKS_AT",
1114
1196
  "LOCATED_IN"
1115
1197
  ];
1116
- var ExtractionSchema = z9.object({
1117
- entities: z9.array(
1118
- z9.object({
1119
- name: z9.string().min(1),
1120
- type: z9.string().min(1).transform((value) => normalizeGraphLabel(value, "CONCEPT"))
1198
+ var ExtractionSchema = z11.object({
1199
+ entities: z11.array(
1200
+ z11.object({
1201
+ name: z11.string().min(1),
1202
+ type: z11.string().min(1).transform((value) => normalizeGraphLabel(value, "CONCEPT"))
1121
1203
  })
1122
1204
  ),
1123
- relations: z9.array(
1124
- z9.object({
1125
- source: z9.string().min(1),
1126
- target: z9.string().min(1),
1127
- type: z9.string().min(1).transform((value) => normalizeGraphLabel(value, "RELATED_TO"))
1205
+ relations: z11.array(
1206
+ z11.object({
1207
+ source: z11.string().min(1),
1208
+ target: z11.string().min(1),
1209
+ type: z11.string().min(1).transform((value) => normalizeGraphLabel(value, "RELATED_TO"))
1128
1210
  })
1129
1211
  )
1130
1212
  });
@@ -1170,40 +1252,40 @@ var relationshipTypes = [
1170
1252
  "LOCATED_IN"
1171
1253
  ];
1172
1254
  var storeTargets = ["sqlite", "vector", "graph"];
1173
- var inputShape7 = {
1174
- content: z10.string().min(1).describe("Concise factual statement to persist; decision, not deliberation."),
1175
- topic: z10.string().min(1).describe("Required metadata.topic for retrieval grouping."),
1176
- project: z10.string().min(1).describe("Required metadata.project namespace."),
1177
- type: z10.enum(["short-term", "long-term", "working", "episodic", "summary"]).optional().describe("Memory type. Default long-term."),
1178
- targets: z10.array(z10.enum(storeTargets)).optional().describe(
1255
+ var inputShape9 = {
1256
+ content: z12.string().min(1).describe("Concise factual statement to persist; decision, not deliberation."),
1257
+ topic: z12.string().min(1).describe("Required metadata.topic for retrieval grouping."),
1258
+ project: z12.string().min(1).describe("Required metadata.project namespace."),
1259
+ type: z12.enum(["short-term", "long-term", "working", "episodic", "summary"]).optional().describe("Memory type. Default long-term."),
1260
+ targets: z12.array(z12.enum(storeTargets)).optional().describe(
1179
1261
  "Storage targets. Include 'graph' when you provide entities/relationships or want zero graph write counts reported."
1180
1262
  ),
1181
- importance: z10.number().int().min(1).max(10).optional().describe("Importance 1\u201310."),
1182
- eventTime: z10.string().optional().describe(
1263
+ importance: z12.number().int().min(1).max(10).optional().describe("Importance 1\u201310."),
1264
+ eventTime: z12.string().optional().describe(
1183
1265
  'ISO-8601 time the fact happened or took effect (bi-temporal). Pass for any fact that can change or go stale \u2014 recency ordering, dated ("as of") queries, and stale-vs-current conflict resolution key off it.'
1184
1266
  ),
1185
- source: z10.string().optional().describe("Free-form origin (filename, URL, conversation id)."),
1186
- agentId: z10.string().optional().describe("Agent identifier stored alongside the entry."),
1187
- sessionId: z10.string().optional().describe("Session identifier for grouping."),
1188
- parentId: z10.string().optional().describe("Parent memory entry id (hierarchical)."),
1189
- entities: z10.array(
1190
- z10.object({
1191
- name: z10.string().min(1).describe("Entity name as referenced in content."),
1192
- type: z10.enum(entityTypes).describe("Entity type.")
1267
+ source: z12.string().optional().describe("Free-form origin (filename, URL, conversation id)."),
1268
+ agentId: z12.string().optional().describe("Agent identifier stored alongside the entry."),
1269
+ sessionId: z12.string().optional().describe("Session identifier for grouping."),
1270
+ parentId: z12.string().optional().describe("Parent memory entry id (hierarchical)."),
1271
+ entities: z12.array(
1272
+ z12.object({
1273
+ name: z12.string().min(1).describe("Entity name as referenced in content."),
1274
+ type: z12.enum(entityTypes).describe("Entity type.")
1193
1275
  })
1194
1276
  ).optional().describe(
1195
1277
  "Named entities mentioned by the content. The caller LLM must extract and pass these when the content names people, organizations, tools, places, events, or key concepts; the server does not auto-extract them."
1196
1278
  ),
1197
- relationships: z10.array(
1198
- z10.object({
1199
- source: z10.string().min(1).describe("Source entity name (must appear in entities array)."),
1200
- target: z10.string().min(1).describe("Target entity name (must appear in entities array)."),
1201
- type: z10.enum(relationshipTypes).describe("Relationship type.")
1279
+ relationships: z12.array(
1280
+ z12.object({
1281
+ source: z12.string().min(1).describe("Source entity name (must appear in entities array)."),
1282
+ target: z12.string().min(1).describe("Target entity name (must appear in entities array)."),
1283
+ type: z12.enum(relationshipTypes).describe("Relationship type.")
1202
1284
  })
1203
1285
  ).optional().describe(
1204
1286
  "Edges between entities; source and target must be entity names from this request. Relationships matter as much as entities because graph traversal needs edges to connect related memories."
1205
1287
  ),
1206
- extractEntities: z10.boolean().optional().describe(
1288
+ extractEntities: z12.boolean().optional().describe(
1207
1289
  "Override extraction: false skips caller-side extraction; true requires caller entities or MCP sampling and errors loudly if neither is available."
1208
1290
  ),
1209
1291
  ...scopeShape
@@ -1213,7 +1295,7 @@ var storeMemoryTool = {
1213
1295
  config: {
1214
1296
  title: "Store pyx-memory entry",
1215
1297
  description: "Store one concise factual memory with required topic and project metadata. When content names people, organizations, tools, places, events, or key concepts, the caller LLM must extract and pass entities and relationships; the server does not auto-extract them. Relationships (edges) matter as much as entities because graph traversal needs edges to connect related memories. Entity-free memories are valid; omit graph data or set extractEntities:false when there are no graph facts.",
1216
- inputSchema: inputShape7,
1298
+ inputSchema: inputShape9,
1217
1299
  annotations: { readOnlyHint: false, idempotentHint: false, openWorldHint: true }
1218
1300
  },
1219
1301
  handler: (deps) => async (raw, ctx) => {
@@ -1273,13 +1355,13 @@ var storeMemoryTool = {
1273
1355
  };
1274
1356
 
1275
1357
  // src/mcp/tools/summarize.ts
1276
- import { z as z11 } from "zod";
1277
- var inputShape8 = {
1278
- entityName: z11.string().min(1).describe(
1358
+ import { z as z13 } from "zod";
1359
+ var inputShape10 = {
1360
+ entityName: z13.string().min(1).describe(
1279
1361
  "Entity name to synthesize a profile for (PERSON, ORG, CONCEPT, TOOL, LOCATION, EVENT)."
1280
1362
  ),
1281
- entityType: z11.enum(["PERSON", "ORGANIZATION", "CONCEPT", "TOOL", "LOCATION", "EVENT"]).optional().describe("Optional explicit entity type when the same name spans multiple categories."),
1282
- refresh: z11.boolean().optional().describe(
1363
+ entityType: z13.enum(["PERSON", "ORGANIZATION", "CONCEPT", "TOOL", "LOCATION", "EVENT"]).optional().describe("Optional explicit entity type when the same name spans multiple categories."),
1364
+ refresh: z13.boolean().optional().describe(
1283
1365
  "Default false: fetch the existing synthesis. true: rebuild the synthesis from current memory (POST)."
1284
1366
  ),
1285
1367
  ...scopeShape
@@ -1289,7 +1371,7 @@ var summarizeMemoryEntityTool = {
1289
1371
  config: {
1290
1372
  title: "Synthesize pyx-memory entity",
1291
1373
  description: "Fetch or refresh a reusable synthesis/profile for an entity (person, customer, project, tool, organization). Default fetches existing; set refresh:true to rebuild.",
1292
- inputSchema: inputShape8,
1374
+ inputSchema: inputShape10,
1293
1375
  annotations: { readOnlyHint: false, idempotentHint: true, openWorldHint: true }
1294
1376
  },
1295
1377
  handler: (deps) => async (raw) => {
@@ -1321,6 +1403,8 @@ var ALL_TOOLS = [
1321
1403
  searchMemoriesTool,
1322
1404
  storeMemoryTool,
1323
1405
  getMemoryTool,
1406
+ lineageTool,
1407
+ reinforceTool,
1324
1408
  listMemoriesTool,
1325
1409
  deleteMemoryTool,
1326
1410
  ingestMemoryFileTool,
@@ -1336,7 +1420,7 @@ var ALL_TOOL_NAMES = ALL_TOOLS.map((t) => t.name);
1336
1420
  // src/mcp/server.ts
1337
1421
  async function runMcpServer(opts) {
1338
1422
  const fetchImpl = opts.fetchImpl ?? fetch;
1339
- const version = opts.version ?? (true ? "0.37.0" : "0.0.0-dev");
1423
+ const version = opts.version ?? (true ? "0.38.0" : "0.0.0-dev");
1340
1424
  const server = new McpServer(
1341
1425
  { name: "pyx-memory", version },
1342
1426
  { instructions: PYX_MEMORY_INSTRUCTIONS, capabilities: { tools: {} } }
@@ -11,8 +11,8 @@ import {
11
11
  toGraphologyFormat,
12
12
  transformGraphData,
13
13
  unreachableHealth
14
- } from "./chunk-DEMDFWI4.mjs";
15
- import "./chunk-EXUSQ2GR.mjs";
14
+ } from "./chunk-TDPGRIJW.mjs";
15
+ import "./chunk-CK7VUON3.mjs";
16
16
  import "./chunk-KSTI4M52.mjs";
17
17
  export {
18
18
  DashboardClient,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { StoreInput as StoreInput$1, MemoryEntry as MemoryEntry$1, MemorySearchParams as MemorySearchParams$1, MemorySearchResult as MemorySearchResult$1, MemoryType as MemoryType$1, PrincipalContext as PrincipalContext$1, MemoryStats as MemoryStats$1, WikiLintReport as WikiLintReport$1, GraphRepairResult as GraphRepairResult$1, ExtractedImageMeta as ExtractedImageMeta$1, IngestEntity as IngestEntity$1, IngestRelationship as IngestRelationship$1, EntityExtractionResult as EntityExtractionResult$1, Topology as Topology$1, IngestEvent as IngestEvent$1, GraphNode as GraphNode$1, GraphTraversalResult as GraphTraversalResult$1, CorrectionRecord as CorrectionRecord$1 } from '@pyx-memory/shared';
1
+ import { StoreInput as StoreInput$1, MemoryEntry as MemoryEntry$1, MemorySearchParams as MemorySearchParams$1, MemorySearchResult as MemorySearchResult$1, MemoryType as MemoryType$1, PrincipalContext as PrincipalContext$1, MemoryStats as MemoryStats$1, LineageParams as LineageParams$1, LineageResult as LineageResult$1, ReinforceParams as ReinforceParams$1, ReinforceResult as ReinforceResult$1, WikiLintReport as WikiLintReport$1, GraphRepairResult as GraphRepairResult$1, ExtractedImageMeta as ExtractedImageMeta$1, IngestEntity as IngestEntity$1, IngestRelationship as IngestRelationship$1, EntityExtractionResult as EntityExtractionResult$1, Topology as Topology$1, IngestEvent as IngestEvent$1, GraphNode as GraphNode$1, GraphTraversalResult as GraphTraversalResult$1, CorrectionRecord as CorrectionRecord$1 } from '@pyx-memory/shared';
2
2
 
3
3
  /** Parameters for paginated entry listing. */
4
4
  interface MemoryListParams {
@@ -83,6 +83,10 @@ interface MemoryInterface {
83
83
  stats(options?: TenantScopeOptions): Promise<MemoryStats$1>;
84
84
  /** Query entries as they existed at a point in time (by ingest time). */
85
85
  queryAsOf(asOfDate: string, filters?: TemporalQueryFilters): Promise<MemoryEntry$1[]>;
86
+ /** Read the time-ordered lineage of a graph fact or superseded entry chain. */
87
+ lineage(params: LineageParams$1): Promise<LineageResult$1>;
88
+ /** Reinforce memories that were actually used by the caller. */
89
+ reinforce(params: ReinforceParams$1): Promise<ReinforceResult$1>;
86
90
  /** Query entries by event time range (when things actually happened). */
87
91
  queryByEventTime(startTime: string, endTime: string, filters?: TemporalQueryFilters): Promise<MemoryEntry$1[]>;
88
92
  shutdown(): Promise<void>;
@@ -354,6 +358,8 @@ declare class MemoryClient implements ExtendedMemoryInterface {
354
358
  dryRun: boolean;
355
359
  }>;
356
360
  queryAsOf(asOfDate: string, filters?: TemporalQueryFilters): Promise<MemoryEntry$1[]>;
361
+ lineage(params: LineageParams$1): Promise<LineageResult$1>;
362
+ reinforce(params: ReinforceParams$1): Promise<ReinforceResult$1>;
357
363
  log(filters?: MemoryLogFilters): Promise<MemoryEntry$1[]>;
358
364
  queryByEventTime(startTime: string, endTime: string, filters?: TemporalQueryFilters): Promise<MemoryEntry$1[]>;
359
365
  summarizeEntity(name: string): Promise<MemoryEntry$1>;
@@ -543,6 +549,22 @@ interface MemoryEntry {
543
549
  * file-catalog row pointed at by another service's foreign key).
544
550
  */
545
551
  pinned?: boolean;
552
+ /**
553
+ * Lifecycle status (H8). `'active'` (or absent — back-compat default) is a
554
+ * normal retrievable entry. `'superseded'` means a newer near-duplicate
555
+ * UPDATE replaced this one during consolidation. `'archived'` (1b) means decay
556
+ * retired it (no successor) — kept, strength 0, `deep`-tier only. All three
557
+ * are kept (history / lineage / deep recall) but `superseded`/`archived` are
558
+ * excluded from default/quick/medium search. Only `forget()` and exact-byte-
559
+ * duplicate collapse hard-delete. See `docs/H8-MEMORY-MODEL-DESIGN.md`.
560
+ */
561
+ status?: 'active' | 'superseded' | 'archived';
562
+ /**
563
+ * When `status==='superseded'`, the id of the newer entry that replaced this
564
+ * one — the backward link used by `Memory.lineage()` chain traversal. Cleared
565
+ * to NULL (never resurrected to active) if the successor is later forgotten.
566
+ */
567
+ supersededByEntryId?: string;
546
568
  }
547
569
  interface MemorySearchParams {
548
570
  query: string;
@@ -601,6 +623,16 @@ interface MemorySearchParams {
601
623
  * index drift. Default true (access tracking is the product's usage signal).
602
624
  */
603
625
  trackAccess?: boolean;
626
+ /**
627
+ * Retrieval EFFORT tier (H8 slice 1b) — admits candidates by activation
628
+ * strength BEFORE RRF fusion (like LLM thinking-mode depth): `quick` = the
629
+ * strongest (sharpest top), `medium` = strong+mid, `deep` = everything
630
+ * including cold + superseded + archived rows. **Omitted ⇒ byte-identical to
631
+ * pre-1b behavior** (no activation lookup; all rows admitted, superseded/
632
+ * archived hidden as in 1a). Strength rises only via `Memory.reinforce` (recall
633
+ * reinforces); idle alone never revives. See `docs/H8-MEMORY-MODEL-DESIGN.md`.
634
+ */
635
+ effort?: 'quick' | 'medium' | 'deep';
604
636
  /** Maximum sensitivity level to include in results. Entries above this level are excluded or redacted. */
605
637
  maxSensitivity?: SensitivityLevel;
606
638
  /** Tenant ID for multi-tenant isolation. */
@@ -663,6 +695,65 @@ interface MemorySearchResult {
663
695
  };
664
696
  };
665
697
  }
698
+ /** One version in a fact's history, as returned by {@link LineageResult}. */
699
+ interface LineageVersion {
700
+ entryId: string;
701
+ /** The entry content carrying this version's value. */
702
+ value: string;
703
+ eventTime?: string;
704
+ ingestTime?: string;
705
+ status: 'active' | 'superseded' | 'archived';
706
+ /** Set when this version was superseded by a newer entry. */
707
+ supersededByEntryId?: string;
708
+ }
709
+ /**
710
+ * Query for the evolution of a fact (H8 `Memory.lineage`). Provide either a
711
+ * `subject` (+ optional `relation`) for graph-backed subject/relation lineage,
712
+ * OR an `entryId` to walk the `supersededBy` chain (the only mode available
713
+ * without a graph store).
714
+ */
715
+ interface LineageParams {
716
+ subject?: string;
717
+ relation?: string;
718
+ entryId?: string;
719
+ /** Current version as of this time (newest version with eventTime ≤ asOf). */
720
+ asOf?: string;
721
+ eventTimeRange?: [string, string];
722
+ /** Return only versions strictly older than the version holding this value. */
723
+ beforeValue?: string;
724
+ limit?: number;
725
+ }
726
+ interface LineageResult {
727
+ subject?: string;
728
+ relation?: string;
729
+ /** Event-time ascending (oldest → newest). */
730
+ versions: LineageVersion[];
731
+ /** Which path answered — honest provenance (graph conflict-group vs supersededBy chain). */
732
+ source: 'graph' | 'chain';
733
+ }
734
+ /**
735
+ * Explicit recall-usefulness signal for {@link MemorySearchParams} `reinforce`.
736
+ * `context_included` = surfaced into the working context (small η); `cited` =
737
+ * the agent actually used it in its answer (medium η); `explicit_positive` =
738
+ * user/agent marked it useful (large η). Mere top-k return is NOT a signal
739
+ * (determinism + "returned ≠ used") — only an explicit `reinforce()` call moves
740
+ * strength.
741
+ */
742
+ type ReinforceSignal = 'context_included' | 'cited' | 'explicit_positive';
743
+ interface ReinforceParams {
744
+ entryIds: string[];
745
+ signal: ReinforceSignal;
746
+ /** When the recall happened — epoch-ms, or full ISO-8601 WITH timezone. Date-only / tz-free is rejected. Defaults to the activation clock. */
747
+ at?: string | number;
748
+ }
749
+ interface ReinforceResult {
750
+ /** Per-entry post-reinforce activation. Entries absent from the store are omitted. */
751
+ updated: Array<{
752
+ entryId: string;
753
+ strength: number;
754
+ tier: 'quick' | 'medium' | 'deep';
755
+ }>;
756
+ }
666
757
  interface SourceEvidence {
667
758
  /** Memory entry that produced this graph fact. */
668
759
  memoryEntryId: string;
@@ -1254,4 +1345,4 @@ interface PrincipalContext {
1254
1345
  /** Sentinel tenant ID used in single-tenant deployments. */
1255
1346
  declare const SINGLE_TENANT_ID = "_single";
1256
1347
 
1257
- export { type AgentId, type ApiResponse, type ConsolidationRunResult, type CorrectionInput, type CorrectionRecord, DEFAULTS, DEPRECATED_RAG_STRATEGIES, EmbeddingProviderName, type EnrichmentCallbacks, type EntityExtractionResult, type ExtendedMemoryInterface, type FetchCorrectionsInput, type GraphFailureMode, type GraphNode, type GraphRelationship, type GraphRepairResult, type GraphTraversalResult, type IngestEntity, type IngestErrorEvent, type IngestEvent, type IngestFileOptions, type IngestHeartbeatEvent, type IngestProgressEvent, type IngestRelationship, type IngestResultEvent, type IngestStage, type IngestionResult, MemoryClient, type MemoryClientOptions, type MemoryEntry, type MemoryIngestRequest, type MemoryInterface, type MemoryListParams, type MemoryListResult, type MemoryLogFilters, type MemorySearchParams, type MemorySearchResult, MemoryServerError, type MemoryStats, MemoryType, type MoveEntriesFilter, MoveFailureReason, type MoveResult, type MoveTarget, NamespaceIsolation, type PrincipalContext, RAGStrategy, SINGLE_TENANT_ID, SensitivityLevel, type SourceEvidence, type StoreInput, StoreTarget, type TemporalQueryFilters, type TenantScopeOptions, type Timestamp, type Topology, type TopologyServiceVariant, VectorProvider, type WikiLintReport, mergeExtractedEntities, normalizeGraphLabel };
1348
+ export { type AgentId, type ApiResponse, type ConsolidationRunResult, type CorrectionInput, type CorrectionRecord, DEFAULTS, DEPRECATED_RAG_STRATEGIES, EmbeddingProviderName, type EnrichmentCallbacks, type EntityExtractionResult, type ExtendedMemoryInterface, type FetchCorrectionsInput, type GraphFailureMode, type GraphNode, type GraphRelationship, type GraphRepairResult, type GraphTraversalResult, type IngestEntity, type IngestErrorEvent, type IngestEvent, type IngestFileOptions, type IngestHeartbeatEvent, type IngestProgressEvent, type IngestRelationship, type IngestResultEvent, type IngestStage, type IngestionResult, type LineageParams, type LineageResult, type LineageVersion, MemoryClient, type MemoryClientOptions, type MemoryEntry, type MemoryIngestRequest, type MemoryInterface, type MemoryListParams, type MemoryListResult, type MemoryLogFilters, type MemorySearchParams, type MemorySearchResult, MemoryServerError, type MemoryStats, MemoryType, type MoveEntriesFilter, MoveFailureReason, type MoveResult, type MoveTarget, NamespaceIsolation, type PrincipalContext, RAGStrategy, type ReinforceParams, type ReinforceResult, type ReinforceSignal, SINGLE_TENANT_ID, SensitivityLevel, type SourceEvidence, type StoreInput, StoreTarget, type TemporalQueryFilters, type TenantScopeOptions, type Timestamp, type Topology, type TopologyServiceVariant, VectorProvider, type WikiLintReport, mergeExtractedEntities, normalizeGraphLabel };
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  MemoryClient,
3
3
  MemoryServerError
4
- } from "./chunk-EXUSQ2GR.mjs";
4
+ } from "./chunk-CK7VUON3.mjs";
5
5
  import {
6
6
  DEFAULTS,
7
7
  DEPRECATED_RAG_STRATEGIES,
package/dist/react.mjs CHANGED
@@ -11,8 +11,8 @@ import {
11
11
  toGraphologyFormat,
12
12
  transformGraphData,
13
13
  unreachableHealth
14
- } from "./chunk-DEMDFWI4.mjs";
15
- import "./chunk-EXUSQ2GR.mjs";
14
+ } from "./chunk-TDPGRIJW.mjs";
15
+ import "./chunk-CK7VUON3.mjs";
16
16
  import "./chunk-KSTI4M52.mjs";
17
17
 
18
18
  // ../dashboard/src/hooks/use-consolidation-log.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyxmate/memory",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "type": "module",
5
5
  "description": "SDK for pyx-memory — Memory as a Service for AI agents",
6
6
  "license": "MIT",