stratagate-dsh 0.2.30 → 0.2.31

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.js CHANGED
@@ -132,14 +132,14 @@ function resultSummary(value) {
132
132
  }
133
133
  if (typeof value === "number" || typeof value === "boolean") return String(value);
134
134
  if (!value || typeof value !== "object") return "";
135
- const record = value;
136
- if (typeof record.error === "string") return `failed: ${record.error.replace(/\s+/g, " ").slice(0, 140)}`;
137
- if (typeof record.summary === "string") return record.summary.replace(/\s+/g, " ").slice(0, 160);
138
- if (typeof record.message === "string") return record.message.replace(/\s+/g, " ").slice(0, 160);
139
- const counts = Object.entries(record).filter(([key, item]) => !["arguments", "params", "input", "request"].includes(key) && Array.isArray(item)).map(([key, item]) => `${key}: ${item.length}`);
135
+ const record2 = value;
136
+ if (typeof record2.error === "string") return `failed: ${record2.error.replace(/\s+/g, " ").slice(0, 140)}`;
137
+ if (typeof record2.summary === "string") return record2.summary.replace(/\s+/g, " ").slice(0, 160);
138
+ if (typeof record2.message === "string") return record2.message.replace(/\s+/g, " ").slice(0, 160);
139
+ const counts = Object.entries(record2).filter(([key, item]) => !["arguments", "params", "input", "request"].includes(key) && Array.isArray(item)).map(([key, item]) => `${key}: ${item.length}`);
140
140
  if (counts.length > 0) return counts.join(", ").slice(0, 160);
141
- if (record.ok === true) return "completed";
142
- if (record.ok === false) return "not completed";
141
+ if (record2.ok === true) return "completed";
142
+ if (record2.ok === false) return "not completed";
143
143
  return "structured result returned";
144
144
  }
145
145
  function summarizeToolTrace(trace) {
@@ -157,14 +157,14 @@ function summarizeToolJson(value) {
157
157
  item.forEach(visit);
158
158
  return;
159
159
  }
160
- const record = item;
161
- if (typeof record.name === "string" && ("arguments" in record || "parameters" in record)) names.add(record.name);
162
- if (typeof record.tool === "string") names.add(record.tool);
163
- if (record.function && typeof record.function === "object") {
164
- const name2 = record.function.name;
160
+ const record2 = item;
161
+ if (typeof record2.name === "string" && ("arguments" in record2 || "parameters" in record2)) names.add(record2.name);
162
+ if (typeof record2.tool === "string") names.add(record2.tool);
163
+ if (record2.function && typeof record2.function === "object") {
164
+ const name2 = record2.function.name;
165
165
  if (typeof name2 === "string") names.add(name2);
166
166
  }
167
- Object.values(record).forEach(visit);
167
+ Object.values(record2).forEach(visit);
168
168
  };
169
169
  visit(parsed);
170
170
  if (names.size === 0) return null;
@@ -505,6 +505,235 @@ function normalizeStandardEventType(value) {
505
505
  return aliases[normalized] ?? "other";
506
506
  }
507
507
 
508
+ // ../../src/external-memory.ts
509
+ var EXTERNAL_MEMORY_EXPORT_SCHEMA = "stratagate.external-memory.v2";
510
+ var EXTERNAL_MEMORY_DECIDER_PROMPT_ZH_CN = `
511
+ \u4F60\u662F StrataGate \u7684\u5916\u90E8\u8BB0\u5FC6\u5408\u5E76\u88C1\u51B3\u5668\u3002\u8F93\u5165\u5305\u542B\u4E00\u4E2A\u5916\u90E8 candidate Event\uFF0C\u4EE5\u53CA\u672C\u5730\u68C0\u7D22\u5F97\u5230\u7684 Top-K existing Events\u3002\u53EA\u80FD\u4F9D\u636E candidate \u548C existing Events \u5224\u65AD\uFF0C\u4E0D\u5F97\u5F15\u5165\u5217\u8868\u4E4B\u5916\u7684\u672C\u5730\u4E8B\u4EF6\uFF0C\u4E5F\u4E0D\u5F97\u51ED\u5E38\u8BC6\u8865\u5168\u65F6\u95F4\u3002
512
+
513
+ action \u53EA\u80FD\u662F\uFF1A
514
+ - ADD\uFF1A\u6CA1\u6709\u8DB3\u591F\u76F8\u540C\u6216\u53EF\u66F4\u65B0\u7684\u672C\u5730\u4E8B\u4EF6\u3002
515
+ - MERGE\uFF1Acandidate \u4E0E\u4E00\u4E2A\u6216\u591A\u4E2A existing Events \u8868\u8FBE\u540C\u4E00\u4E8B\u5B9E\u7684\u8865\u5145\u6216\u6574\u5408\uFF1B\u8FD4\u56DE\u4E00\u6761\u66F4\u5B8C\u6574\u7684 mergedCandidate\uFF0C\u5E76\u5F15\u7528\u8981\u88AB\u65B0\u4E8B\u5B9E\u53D6\u4EE3\u7684 existingEventIds\u3002
516
+ - SUPERSEDE\uFF1Acandidate \u660E\u786E\u662F\u540C\u4E00\u4E8B\u5B9E\u7684\u8F83\u65B0\u7248\u672C\u3001\u7EA0\u6B63\u6216\u72B6\u6001\u66F4\u65B0\uFF1B\u5F15\u7528\u88AB\u53D6\u4EE3\u7684 existingEventIds\u3002
517
+ - CONFLICT\uFF1A\u4E24\u6761\u9648\u8FF0\u90FD\u5E94\u4FDD\u7559\uFF0C\u4F46\u5185\u5BB9\u65E0\u6CD5\u540C\u65F6\u6210\u7ACB\uFF1B\u5F15\u7528\u51B2\u7A81\u7684 existingEventIds\u3002
518
+ - IGNORE\uFF1A\u91CD\u590D\u3001\u4E34\u65F6\u3001\u65E0\u957F\u671F\u4EF7\u503C\u3001\u8BC1\u636E\u4E0D\u8DB3\uFF0C\u6216\u65E0\u6CD5\u5B89\u5168\u5224\u65AD\u3002
519
+
520
+ \u65F6\u95F4\u88C1\u51B3\uFF1A\u5916\u90E8 candidate \u7684\u65F6\u95F4\u5B57\u6BB5\u53EA\u5728\u5176\u81EA\u8EAB\u6709\u660E\u786E\u4F9D\u636E\u65F6\u4FDD\u7559\u3002\u4E0D\u8981\u56E0\u4E3A candidate \u8F83\u65B0\u5C31\u5047\u8BBE\u5B83\u53D1\u751F\u5728\u5BFC\u5165\u65F6\u95F4\uFF1B\u4E0D\u786E\u5B9A\u5C31\u4FDD\u7559 originalText \u5E76\u8BA9 precision/basis \u4E3A unknown\u3002MERGE/SUPERSEDE \u4E0D\u5E94\u62B9\u6389\u65E7\u4E8B\u4EF6\u7684\u6765\u6E90\u3002
521
+
522
+ \u53EA\u8F93\u51FA JSON\uFF1A{"action":"ADD|MERGE|SUPERSEDE|CONFLICT|IGNORE","existingEventIds":["\u53EA\u80FD\u6765\u81EA Top-K \u7684 id"],"mergedCandidate":{...\u53EF\u9009...},"reason":"\u4E0D\u8D85\u8FC7 200 \u5B57\u7684\u5BA2\u89C2\u7406\u7531"}\u3002
523
+ `.trim();
524
+ var LEGACY_EXTERNAL_MEMORY_EXPORT_PROMPT_ZH_CN = `
525
+ \u8BF7\u4E3A\u6211\u5BFC\u51FA\u4E00\u4EFD\u53EF\u8FC1\u79FB\u5230 StrataGate \u7684\u957F\u671F\u8BB0\u5FC6\u3002\u4EC5\u4F7F\u7528\u4F60\u5F53\u524D\u786E\u5B9E\u80FD\u591F\u8BBF\u95EE\u5230\u7684\u3001\u4E0E\u6211\u6709\u5173\u7684\u957F\u671F\u8BB0\u5FC6\u548C\u672C\u6B21\u4F1A\u8BDD\u4E0A\u4E0B\u6587\uFF1B\u4E0D\u8981\u8865\u5145\u5E38\u8BC6\u63A8\u6D4B\uFF0C\u4E0D\u8981\u628A\u52A9\u624B\u81EA\u5DF1\u7684\u5EFA\u8BAE\u5199\u6210\u6211\u7684\u4E8B\u5B9E\u3002
526
+
527
+ \u62BD\u53D6\u8303\u56F4
528
+ 1. \u6307\u4EE4\uFF1A\u6211\u660E\u786E\u8981\u6C42\u957F\u671F\u9075\u5FAA\u7684\u89C4\u5219\u3001\u683C\u5F0F\u3001\u8BED\u6C14\u3001\u7981\u5FCC\u548C\u5BF9\u52A9\u624B\u884C\u4E3A\u7684\u7EA0\u6B63\u3002\u5C3D\u91CF\u4FDD\u7559\u6211\u7684\u539F\u8BDD\u3002
529
+ 2. \u8EAB\u4EFD\uFF1A\u6211\u4E3B\u52A8\u5206\u4EAB\u7684\u975E\u654F\u611F\u8EAB\u4EFD\u3001\u80CC\u666F\u3001\u5173\u7CFB\u3001\u8BED\u8A00\u548C\u5174\u8DA3\u3002\u4E0D\u8981\u8F93\u51FA\u8BC1\u4EF6\u53F7\u3001\u8054\u7CFB\u65B9\u5F0F\u3001\u8D26\u53F7\u3001\u5BC6\u7801\u3001\u7CBE\u786E\u4F4F\u5740\u7B49\u654F\u611F\u6570\u636E\u3002
530
+ 3. \u804C\u4E1A\uFF1A\u660E\u786E\u63D0\u5230\u7684\u5F53\u524D\u6216\u8FC7\u5F80\u804C\u4F4D\u3001\u516C\u53F8\u3001\u804C\u8D23\u548C\u6280\u80FD\u3002
531
+ 4. \u9879\u76EE\uFF1A\u6211\u5B9E\u9645\u53C2\u4E0E\u6216\u6295\u5165\u7CBE\u529B\u7684\u9879\u76EE\u3001\u72B6\u6001\u3001\u51B3\u5B9A\u3001\u53D8\u66F4\u548C\u7ED3\u679C\u3002
532
+ 5. \u504F\u597D\uFF1A\u80FD\u591F\u8DE8\u4F1A\u8BDD\u590D\u7528\u7684\u89C2\u70B9\u3001\u54C1\u5473\u4E0E\u5DE5\u4F5C\u65B9\u5F0F\u3002\u4E00\u6B21\u6027\u7684\u4E34\u65F6\u8981\u6C42\u4E0D\u8981\u63D0\u5347\u4E3A\u957F\u671F\u504F\u597D\u3002
533
+
534
+ \u4E8B\u4EF6\u62C6\u5206
535
+ - \u6BCF\u4E2A candidate \u53EA\u8868\u8FBE\u4E00\u4E2A\u53EF\u72EC\u7ACB\u66F4\u65B0\u3001\u5408\u5E76\u6216\u51B2\u7A81\u5224\u65AD\u7684\u4E8B\u5B9E/\u4E8B\u4EF6\uFF1B\u4E0D\u8981\u628A\u591A\u4E2A\u9879\u76EE\u6216\u591A\u4E2A\u65F6\u95F4\u70B9\u585E\u8FDB\u4E00\u6761\u3002
536
+ - \u540C\u4E00\u4E8B\u5B9E\u7684\u66F4\u65B0\u53EF\u4EE5\u5206\u522B\u8F93\u51FA\uFF1B\u4E92\u76F8\u77DB\u76FE\u4E14\u65E0\u6CD5\u786E\u8BA4\u54EA\u6761\u66F4\u65B0\u65F6\uFF0C\u4E5F\u5206\u522B\u8F93\u51FA\uFF0C\u4E0D\u8981\u64C5\u81EA\u9009\u8FB9\u3002
537
+ - \u5BD2\u6684\u3001\u91CD\u590D\u5185\u5BB9\u3001\u52A9\u624B\u63A8\u6D4B\u3001\u6CA1\u6709\u957F\u671F\u4EF7\u503C\u7684\u4E34\u65F6\u5185\u5BB9\u4E0D\u8981\u8F93\u51FA\u3002
538
+
539
+ \u65F6\u95F4\u89C4\u5219\uFF08\u5FC5\u987B\u4E25\u683C\u9075\u5B88\uFF09
540
+ - mentionedAt \u662F\u8FD9\u6761\u4FE1\u606F\u88AB\u6211\u8BF4\u51FA\u6216\u8BB0\u5F55\u7684\u65F6\u95F4\uFF1BhappenedStart/happenedEnd \u662F\u4E8B\u60C5\u5B9E\u9645\u53D1\u751F\u6216\u9884\u8BA1\u53D1\u751F\u7684\u65F6\u95F4\uFF0C\u4E8C\u8005\u4E0D\u80FD\u6DF7\u7528\u3002
541
+ - \u53EA\u6709\u6765\u6E90\u660E\u786E\u7ED9\u51FA\u65F6\u95F4\uFF0C\u6216\u76F8\u5BF9\u65F6\u95F4\u80FD\u4F9D\u636E\u5DF2\u77E5\u6D88\u606F\u65F6\u95F4\u552F\u4E00\u6362\u7B97\u65F6\uFF0C\u624D\u586B\u5199\u65F6\u95F4\u5B57\u6BB5\u3002
542
+ - \u4E0D\u5F97\u628A\u4ECA\u5929\u3001\u5BFC\u51FA\u65F6\u95F4\u3001\u804A\u5929\u6392\u5E8F\u3001\u6A21\u578B\u77E5\u8BC6\u622A\u6B62\u65F6\u95F4\u5F53\u4F5C\u4E8B\u4EF6\u53D1\u751F\u65F6\u95F4\u3002
543
+ - \u201C\u4E0A\u5468\u3001\u6700\u8FD1\u3001\u4EE5\u524D\u3001\u660E\u5E74\u201D\u7B49\u8868\u8FBE\u82E5\u7F3A\u5C11\u53EF\u6838\u5BF9\u7684\u53C2\u7167\u65F6\u95F4\uFF1A\u4FDD\u7559\u5728 temporal.originalText \u4E2D\uFF0Cbasis \u5199 unknown\uFF0Cprecision \u5199 unknown\uFF0C\u5E76\u7701\u7565 happenedStart/happenedEnd\u3002
544
+ - \u82E5\u80FD\u53EF\u9760\u6362\u7B97\u76F8\u5BF9\u65F6\u95F4\uFF1Abasis \u5199 relative\uFF0CoriginalText \u4FDD\u7559\u539F\u8868\u8FBE\uFF0C\u5E76\u6309\u5B9E\u9645\u7CBE\u5EA6\u586B\u5199 precision\u3002\u4E0D\u80FD\u628A\u201C2024 \u5E74\u201D\u4F2A\u88C5\u6210\u67D0\u4E00\u5929\uFF0C\u4E0D\u80FD\u628A\u201C3 \u6708\u201D\u4F2A\u88C5\u6210\u67D0\u4E2A\u65F6\u523B\u3002
545
+ - \u65F6\u95F4\u7CBE\u5EA6\u53EA\u80FD\u662F instant/day/month/year/range/unknown\u3002\u5DF2\u77E5\u5E74\u4EFD\u5199 YYYY\uFF1B\u5DF2\u77E5\u6708\u4EFD\u5199 YYYY-MM\uFF1B\u5DF2\u77E5\u65E5\u671F\u5199 YYYY-MM-DD\uFF1B\u53EA\u6709\u786E\u77E5\u65F6\u523B\u548C\u65F6\u533A\u624D\u5199 RFC 3339 \u65F6\u95F4\u3002
546
+ - \u65F6\u95F4\u4E0D\u786E\u5B9A\u65F6\u5B81\u53EF\u7701\u7565\uFF0C\u4E0D\u731C\u6D4B\u3002\u4E0D\u8981\u8F93\u51FA null\uFF1B\u672A\u77E5\u7684\u53EF\u9009\u5B57\u6BB5\u76F4\u63A5\u7701\u7565\u3002
547
+
548
+ \u5B57\u6BB5\u89C4\u5219
549
+ - category: instruction/identity/career/project/preference \u4E4B\u4E00\u3002
550
+ - eventType: decision/release/task_completed/plan/change/cancellation/incident/meeting/collaboration/migration/other \u4E4B\u4E00\u3002
551
+ - status: occurred/planned/cancelled/ongoing/unknown \u4E4B\u4E00\u3002
552
+ - scope: user/project/session \u4E4B\u4E00\uFF1B\u901A\u5E38\u4F7F\u7528 user\uFF0C\u660E\u786E\u53EA\u5C5E\u4E8E\u67D0\u9879\u76EE\u65F6\u4F7F\u7528 project\u3002
553
+ - criticality: routine/preference/identity/safety \u4E4B\u4E00\u3002
554
+ - confidence \u662F 0 \u5230 1\u3002\u53EA\u6709\u76F4\u63A5\u3001\u6E05\u695A\u3001\u53EF\u5F52\u56E0\u4E8E\u6211\u7684\u9648\u8FF0\u624D\u53EF\u9AD8\u4E8E 0.85\uFF1B\u542B\u7CCA\u6216\u95F4\u63A5\u4FE1\u606F\u5E94\u964D\u4F4E\u7F6E\u4FE1\u5EA6\u3002
555
+ - quotes \u53EA\u653E\u6211\u786E\u5B9E\u8BF4\u8FC7\u4E14\u503C\u5F97\u4FDD\u7559\u7684\u77ED\u539F\u8BDD\uFF1B\u65E0\u6CD5\u9010\u5B57\u786E\u8BA4\u65F6\u7559\u7A7A\uFF0C\u4E0D\u8981\u4F2A\u9020\u5F15\u53F7\u3002
556
+ - tags \u5FC5\u987B\u5305\u542B category\uFF0C\u5E76\u53EF\u6DFB\u52A0\u5C11\u91CF\u4FBF\u4E8E\u68C0\u7D22\u7684\u4E3B\u9898\u6807\u7B7E\u3002
557
+
558
+ \u53EA\u8F93\u51FA\u4E00\u4E2A\u5408\u6CD5 JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981\u4F7F\u7528 Markdown \u4EE3\u7801\u5757\uFF0C\u4E0D\u8981\u5728 JSON \u524D\u540E\u89E3\u91CA\u3002\u683C\u5F0F\u5982\u4E0B\uFF1A
559
+ {
560
+ "schemaVersion": "stratagate.external-memory.v1",
561
+ "candidates": [
562
+ {
563
+ "category": "project",
564
+ "title": "\u7B80\u77ED\u3001\u53EF\u68C0\u7D22\u7684\u6807\u9898",
565
+ "summary": "\u72EC\u7ACB\u3001\u5BA2\u89C2\u3001\u53EF\u957F\u671F\u4FDD\u5B58\u7684\u4E00\u6761\u4E8B\u5B9E",
566
+ "narrative": "\u5FC5\u8981\u65F6\u8865\u5145\u4E0A\u4E0B\u6587\uFF1B\u6CA1\u6709\u5219\u4E0E summary \u76F8\u540C",
567
+ "tags": ["project", "\u4E3B\u9898\u6807\u7B7E"],
568
+ "quotes": ["\u53EF\u786E\u8BA4\u7684\u7528\u6237\u539F\u8BDD"],
569
+ "temporal": {
570
+ "mentionedAt": "2026-08-26T10:30:00+08:00",
571
+ "happenedStart": "2026-08",
572
+ "originalText": "2026 \u5E74 8 \u6708",
573
+ "precision": "month",
574
+ "basis": "explicit",
575
+ "status": "occurred",
576
+ "participants": ["\u76F8\u5173\u7684\u4EBA\u3001\u9879\u76EE\u6216\u7EC4\u7EC7"],
577
+ "eventType": "change"
578
+ },
579
+ "scope": "project",
580
+ "criticality": "routine",
581
+ "confidence": 0.95
582
+ }
583
+ ],
584
+ "coverage": "\u662F\u5426\u5DF2\u8986\u76D6\u5F53\u524D\u53EF\u8BBF\u95EE\u7684\u5168\u90E8\u76F8\u5173\u957F\u671F\u4FE1\u606F",
585
+ "uncertainItems": ["\u672A\u7EB3\u5165\u3001\u9700\u7528\u6237\u786E\u8BA4\u7684\u5185\u5BB9\u53CA\u539F\u56E0"]
586
+ }
587
+
588
+ \u5982\u679C\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u957F\u671F\u8BB0\u5FC6\uFF0C\u4ECD\u8F93\u51FA\u8BE5 JSON \u7ED3\u6784\uFF0C\u5E76\u4EE4 candidates \u4E3A\u7A7A\u6570\u7EC4\u3002
589
+ `.trim();
590
+ var EXTERNAL_MEMORY_EXPORT_PROMPT_ZH_CN = `
591
+ \u8BF7\u4E3A\u6211\u5BFC\u51FA\u4E00\u4EFD\u53EF\u4EE5\u8FC1\u79FB\u5230\u53E6\u4E00\u4E2A AI \u7CFB\u7EDF\u7684\u957F\u671F\u8BB0\u5FC6\u3002
592
+
593
+ \u4F60\u7684\u4EFB\u52A1\u4E0D\u662F\u5199\u603B\u7ED3\u6587\u7AE0\uFF0C\u800C\u662F\u4ECE\u4F60\u5F53\u524D\u80FD\u591F\u8BBF\u95EE\u5230\u7684\u3001\u4E0E\u6211\u6709\u5173\u7684\u957F\u671F\u4FE1\u606F\u548C\u672C\u6B21\u4F1A\u8BDD\u4E0A\u4E0B\u6587\u4E2D\uFF0C\u63D0\u53D6\u53EF\u4EE5\u957F\u671F\u590D\u7528\u7684\u4E8B\u5B9E\u3001\u504F\u597D\u3001\u89C4\u5219\u3001\u9879\u76EE\u72B6\u6001\u548C\u5386\u53F2\u4E8B\u4EF6\u3002\u53EA\u8BB0\u5F55\u6709\u660E\u786E\u4F9D\u636E\u7684\u5185\u5BB9\uFF1B\u4E0D\u8981\u628A\u4F60\u7684\u63A8\u6D4B\u3001\u5EFA\u8BAE\u3001\u5E38\u8BC6\u3001\u81C6\u6D4B\u6216\u52A9\u624B\u81EA\u5DF1\u7684\u89C2\u70B9\u5199\u6210\u6211\u7684\u4E8B\u5B9E\u3002
594
+
595
+ \u6BCF\u6761 candidate \u5FC5\u987B\u5305\u542B memoryKind \u548C category\u3002memoryKind \u53EA\u80FD\u662F instruction\u3001preference\u3001fact\u3001event\uFF1Ainstruction \u662F\u957F\u671F\u884C\u4E3A\u89C4\u5219\uFF0Cpreference \u662F\u7A33\u5B9A\u504F\u597D\uFF0Cfact \u662F\u76F8\u5BF9\u7A33\u5B9A\u7684\u4E8B\u5B9E\uFF0Cevent \u662F\u53D1\u751F\u3001\u53D8\u5316\u3001\u51B3\u7B56\u6216\u65F6\u95F4\u8FC7\u7A0B\u3002category \u53EA\u80FD\u662F instruction\u3001identity\u3001career\u3001project\u3001preference\uFF1BmemoryKind \u4E0E category \u662F\u4E0D\u540C\u6982\u5FF5\uFF08\u4F8B\u5982\u201C\u7528\u6237\u53D1\u5E03\u9879\u76EE\u7248\u672C\u201D\u662F event + project\uFF09\u3002
596
+
597
+ \u6309 instruction\u3001identity\u3001career\u3001project\u3001preference \u7684\u987A\u5E8F\u63D0\u53D6\u3002\u6BCF\u4E2A candidate \u53EA\u8868\u8FBE\u4E00\u6761\u53EF\u72EC\u7ACB\u5224\u65AD\u3001\u5408\u5E76\u6216\u51B2\u7A81\u5904\u7406\u7684\u8BB0\u5FC6\uFF1B\u4E0D\u8981\u5408\u5E76\u591A\u4E2A\u9879\u76EE\u3001\u51B3\u5B9A\u6216\u65F6\u95F4\u70B9\u3002\u77DB\u76FE\u5185\u5BB9\u65E0\u6CD5\u5224\u65AD\u65F6\u5206\u522B\u8F93\u51FA\uFF0C\u4E0D\u8981\u66FF\u7528\u6237\u9009\u62E9\u3002\u4E0D\u8981\u8F93\u51FA\u5BD2\u6684\u3001\u91CD\u590D\u5185\u5BB9\u3001\u4E34\u65F6\u4E0A\u4E0B\u6587\u3001\u52A9\u624B\u63A8\u6D4B\u6216\u654F\u611F\u9690\u79C1\uFF08\u8BC1\u4EF6\u53F7\u3001\u624B\u673A\u53F7\u3001\u90AE\u7BB1\u3001\u5BC6\u7801\u3001API Key\u3001\u7CBE\u786E\u4F4F\u5740\u3001\u8D26\u53F7\u51ED\u8BC1\u7B49\uFF09\u3002
598
+
599
+ \u65F6\u95F4\u5FC5\u987B\u5B81\u7F3A\u6BCB\u6EE5\uFF1AmentionedAt \u662F\u88AB\u63D0\u53CA/\u8BB0\u5F55/\u786E\u8BA4\u7684\u65F6\u95F4\uFF0ChappenedStart/happenedEnd \u662F\u5B9E\u9645\u53D1\u751F\u3001\u5F00\u59CB\u3001\u7ED3\u675F\u6216\u8BA1\u5212\u53D1\u751F\u7684\u65F6\u95F4\uFF0C\u4E0D\u80FD\u6DF7\u7528\u3002\u53EA\u6709\u6765\u6E90\u660E\u786E\u7ED9\u51FA\uFF0C\u6216\u76F8\u5BF9\u65F6\u95F4\u80FD\u4F9D\u636E\u5DF2\u77E5\u53C2\u7167\u65E5\u671F\u552F\u4E00\u6362\u7B97\u65F6\uFF0C\u624D\u586B\u5199\u65F6\u95F4\u3002\u4E0D\u8981\u628A\u5F53\u524D\u65E5\u671F\u3001\u5BFC\u51FA\u65F6\u95F4\u3001\u804A\u5929\u6392\u5E8F\u6216\u6A21\u578B\u77E5\u8BC6\u622A\u6B62\u65F6\u95F4\u5F53\u4F5C\u4E8B\u4EF6\u65F6\u95F4\u3002\u201C\u4E0A\u5468\u3001\u6700\u8FD1\u3001\u4EE5\u524D\u3001\u660E\u5E74\u201D\u7B49\u7F3A\u5C11\u53EF\u9760\u53C2\u7167\u65F6\uFF0C\u4FDD\u7559 temporal.originalText\uFF0Cprecision \u548C basis \u90FD\u5199 unknown\uFF0C\u5E76\u7701\u7565 happenedStart/happenedEnd\u3002\u4E0D\u8981\u628A\u201C2024 \u5E74\u201D\u53D8\u6210\u67D0\u4E00\u5929\uFF1B\u65F6\u95F4\u7CBE\u5EA6\u53EA\u80FD\u662F instant\u3001day\u3001month\u3001year\u3001range\u3001unknown\u3002\u672A\u77E5\u5B57\u6BB5\u76F4\u63A5\u7701\u7565\uFF0C\u4E0D\u8981\u8F93\u51FA null\u3002
600
+
601
+ \u53EA\u6709 memoryKind=event \u4E14\u5B58\u5728\u660E\u786E\u4E8B\u4EF6\u8BED\u4E49\u65F6\u624D\u586B\u5199 eventType\uFF1BeventType \u53EA\u80FD\u662F decision\u3001release\u3001task_completed\u3001plan\u3001change\u3001cancellation\u3001incident\u3001meeting\u3001collaboration\u3001migration\u3001other\u3002temporal.status \u53EA\u80FD\u662F occurred\u3001planned\u3001cancelled\u3001ongoing\u3001unknown\u3002scope \u53EA\u80FD\u662F user\u3001project\u3001session\uFF1Bcriticality \u53EA\u80FD\u662F routine\u3001preference\u3001identity\u3001safety\u3002confidence \u4E3A 0 \u5230 1\uFF1Bquotes \u53EA\u80FD\u662F\u53EF\u786E\u8BA4\u7684\u7528\u6237\u539F\u8BDD\uFF1Btags \u81F3\u5C11\u5305\u542B category\u3002
602
+
603
+ \u8FD9\u662F\u4E00\u6B21\u5916\u90E8 AI \u8BB0\u5FC6\u5BFC\u51FA\u3002\u9876\u5C42\u8F93\u51FA sourceType\uFF08\u56FA\u5B9A\u4E3A external_ai_memory_export\uFF09\u3001sourceSystem\uFF08\u5F53\u524D AI \u540D\u79F0\uFF0C\u4E0D\u786E\u5B9A\u5199 unknown\uFF09\u3001\u53EF\u53EF\u9760\u83B7\u5F97\u65F6\u624D\u8F93\u51FA exportedAt\uFF1Bcoverage \u53EA\u80FD\u662F full\u3001partial\u3001limited\uFF0C\u5E76\u53EF\u9644 coverageNote \u548C uncertainItems\u3002
604
+
605
+ \u53EA\u8F93\u51FA\u4E00\u4E2A\u5408\u6CD5 JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981\u8F93\u51FA Markdown \u4EE3\u7801\u5757\u3001\u89E3\u91CA\u6216\u5206\u6790\u8FC7\u7A0B\uFF1A
606
+ {
607
+ "schemaVersion": "stratagate.external-memory.v2",
608
+ "sourceType": "external_ai_memory_export",
609
+ "sourceSystem": "unknown",
610
+ "exportedAt": "\u53EA\u6709\u53EF\u9760\u77E5\u9053\u5F53\u524D\u65F6\u95F4\u65F6\u586B\u5199",
611
+ "candidates": [
612
+ {
613
+ "memoryKind": "event",
614
+ "category": "project",
615
+ "title": "\u7B80\u77ED\u3001\u660E\u786E\u3001\u65B9\u4FBF\u68C0\u7D22\u7684\u6807\u9898",
616
+ "summary": "\u4E00\u6761\u72EC\u7ACB\u3001\u5BA2\u89C2\u3001\u53EF\u4EE5\u957F\u671F\u4FDD\u5B58\u7684\u8BB0\u5FC6",
617
+ "narrative": "\u5FC5\u8981\u7684\u4E0A\u4E0B\u6587",
618
+ "tags": ["project", "\u4E3B\u9898\u6807\u7B7E"],
619
+ "quotes": ["\u80FD\u591F\u786E\u8BA4\u7684\u7528\u6237\u539F\u8BDD"],
620
+ "temporal": {
621
+ "mentionedAt": "\u53EA\u6709\u660E\u786E\u77E5\u9053\u65F6\u586B\u5199",
622
+ "happenedStart": "\u53EA\u6709\u53EF\u9760\u786E\u5B9A\u65F6\u586B\u5199",
623
+ "happenedEnd": "\u53EA\u6709\u53EF\u9760\u786E\u5B9A\u65F6\u586B\u5199",
624
+ "originalText": "\u539F\u59CB\u65F6\u95F4\u8868\u8FBE",
625
+ "precision": "day",
626
+ "basis": "explicit",
627
+ "status": "occurred",
628
+ "participants": ["\u76F8\u5173\u4EBA\u7269\u3001\u9879\u76EE\u3001\u7EC4\u7EC7\u3001\u5DE5\u5177\u6216\u5730\u70B9"],
629
+ "eventType": "decision"
630
+ },
631
+ "scope": "project",
632
+ "criticality": "routine",
633
+ "confidence": 0.95
634
+ }
635
+ ],
636
+ "coverage": "full",
637
+ "coverageNote": "\u5FC5\u8981\u65F6\u7B80\u77ED\u8BF4\u660E\u8986\u76D6\u8303\u56F4",
638
+ "uncertainItems": ["\u6CA1\u6709\u5BFC\u51FA\u7684\u5185\u5BB9\u4EE5\u53CA\u5177\u4F53\u539F\u56E0"]
639
+ }
640
+
641
+ \u5982\u679C\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u957F\u671F\u8BB0\u5FC6\uFF0C\u4ECD\u8F93\u51FA\u5408\u6CD5 JSON\uFF0C\u4EE4 candidates \u4E3A\u7A7A\u6570\u7EC4\uFF0Ccoverage \u4E3A limited\uFF0C\u5E76\u8BF4\u660E\u539F\u56E0\u3002
642
+ `.trim();
643
+ function record(value) {
644
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
645
+ }
646
+ function optionalString(value, maxLength = 2e3) {
647
+ return typeof value === "string" && value.trim() ? value.trim().slice(0, maxLength) : void 0;
648
+ }
649
+ function stringArray(value, limit, maxLength = 200) {
650
+ return Array.isArray(value) ? [...new Set(value.flatMap((item) => optionalString(item, maxLength) ?? []).slice(0, limit))] : [];
651
+ }
652
+ function oneOf(value, allowed) {
653
+ return typeof value === "string" && allowed.includes(value) ? value : void 0;
654
+ }
655
+ function parseTemporal(value) {
656
+ const raw = record(value);
657
+ if (!raw) return void 0;
658
+ const temporal = {};
659
+ for (const key of ["mentionedAt", "happenedStart", "happenedEnd", "originalText"]) {
660
+ const parsed = optionalString(raw[key], 200);
661
+ if (parsed) temporal[key] = parsed;
662
+ }
663
+ const precision = oneOf(raw.precision, ["instant", "day", "month", "year", "range", "unknown"]);
664
+ const basis = oneOf(raw.basis, ["explicit", "relative", "inferred", "unknown"]);
665
+ const status = oneOf(raw.status, ["occurred", "planned", "cancelled", "ongoing", "unknown"]);
666
+ const eventType = optionalString(raw.eventType, 80);
667
+ const participants = stringArray(raw.participants, 24);
668
+ if (precision) temporal.precision = precision;
669
+ if (basis) temporal.basis = basis;
670
+ if (status) temporal.status = status;
671
+ if (eventType) temporal.eventType = eventType;
672
+ if (participants.length > 0) temporal.participants = participants;
673
+ if (precision === "unknown" || basis === "unknown") {
674
+ delete temporal.happenedStart;
675
+ delete temporal.happenedEnd;
676
+ }
677
+ return temporal;
678
+ }
679
+ function parseCandidate(value) {
680
+ const raw = record(value);
681
+ if (!raw) return null;
682
+ const title = optionalString(raw.title, 160);
683
+ const summary = optionalString(raw.summary, 2e3);
684
+ if (!title || !summary) return null;
685
+ const category = oneOf(raw.category, ["instruction", "identity", "career", "project", "preference"]);
686
+ const memoryKind = oneOf(raw.memoryKind, ["instruction", "preference", "fact", "event"]);
687
+ const tags = stringArray(raw.tags, 12);
688
+ const candidate = {
689
+ title,
690
+ summary,
691
+ ...memoryKind ? { memoryKind } : {},
692
+ ...category ? { category } : {},
693
+ tags: [.../* @__PURE__ */ new Set([...category ? [category] : [], ...tags])].slice(0, 12),
694
+ quotes: stringArray(raw.quotes, 12, 500)
695
+ };
696
+ const narrative = optionalString(raw.narrative, 8e3);
697
+ const temporal = parseTemporal(raw.temporal);
698
+ const scope = oneOf(raw.scope, ["user", "project", "session"]);
699
+ const criticality = oneOf(raw.criticality, ["routine", "preference", "identity", "safety"]);
700
+ if (narrative) candidate.narrative = narrative;
701
+ if (temporal) candidate.temporal = temporal;
702
+ if (scope) candidate.scope = scope;
703
+ if (criticality) candidate.criticality = criticality;
704
+ if (typeof raw.confidence === "number" && Number.isFinite(raw.confidence)) {
705
+ candidate.confidence = Math.max(0, Math.min(1, raw.confidence));
706
+ }
707
+ return candidate;
708
+ }
709
+ function unwrapJson(text3) {
710
+ const trimmed = text3.trim();
711
+ const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/iu);
712
+ return fenced?.[1]?.trim() ?? trimmed;
713
+ }
714
+ function parseExternalMemoryExport(text3) {
715
+ let parsed;
716
+ try {
717
+ parsed = JSON.parse(unwrapJson(text3));
718
+ } catch (error) {
719
+ throw new TypeError(`Invalid external memory JSON: ${error instanceof Error ? error.message : String(error)}`);
720
+ }
721
+ const root = record(parsed);
722
+ if (!root) throw new TypeError("Invalid external memory JSON: expected an object");
723
+ const schemaVersion = optionalString(root.schemaVersion, 80);
724
+ if (schemaVersion && schemaVersion !== "stratagate.external-memory.v1" && schemaVersion !== EXTERNAL_MEMORY_EXPORT_SCHEMA) {
725
+ throw new TypeError(`Unsupported external memory schema: ${schemaVersion}`);
726
+ }
727
+ const sourceType = optionalString(root.sourceType, 80);
728
+ if (sourceType && sourceType !== "external_ai_memory_export") {
729
+ throw new TypeError(`Invalid external memory sourceType: ${sourceType}`);
730
+ }
731
+ const rawCandidates = Array.isArray(root.candidates) ? root.candidates : Array.isArray(root.events) ? root.events : [];
732
+ const candidates = rawCandidates.flatMap((value) => parseCandidate(value) ?? []).slice(0, 200);
733
+ return { candidates, reason: `Parsed ${candidates.length} candidate events from external memory export.` };
734
+ }
735
+ var externalMemoryJsonExtractor = async ({ text: text3 }) => parseExternalMemoryExport(text3);
736
+
508
737
  // ../../src/retrieval.ts
509
738
  var RETRIEVAL_STRATEGIES = [
510
739
  "answer",
@@ -2185,6 +2414,95 @@ var StrataGate = class _StrataGate {
2185
2414
  return event;
2186
2415
  });
2187
2416
  }
2417
+ /**
2418
+ * Import a memory summary produced by another AI.
2419
+ *
2420
+ * The extractor turns prose into candidate Events. Each candidate is then
2421
+ * matched against the local Event index (bounded by topK) and passed to the
2422
+ * decider. Only ADD/MERGE/SUPERSEDE/CONFLICT decisions write Events; IGNORE
2423
+ * is recorded in the returned audit result. Existing Events are never
2424
+ * overwritten: MERGE and SUPERSEDE create a new canonical Event that points
2425
+ * back to the older Events.
2426
+ */
2427
+ async importExternalMemory(options) {
2428
+ const text3 = options.text.trim();
2429
+ if (!text3) throw new TypeError("External memory text must not be empty");
2430
+ if (typeof options.decider !== "function") {
2431
+ throw new TypeError("External memory decider is required");
2432
+ }
2433
+ const importedAt = toUtc8Iso(options.importedAt ?? this.now());
2434
+ const extractor = options.extractor ?? externalMemoryJsonExtractor;
2435
+ const extracted = await extractor({ text: text3, importedAt });
2436
+ const candidates = Array.isArray(extracted?.candidates) ? extracted.candidates.slice(0, 200) : [];
2437
+ const topK = Math.max(1, Math.min(20, Math.floor(options.topK ?? 5)));
2438
+ const source = await this.commitMutation(() => this.createExternalSourceBlock(text3, importedAt));
2439
+ const prepared = [];
2440
+ for (const candidate of candidates) {
2441
+ if (!candidate || typeof candidate.title !== "string" || typeof candidate.summary !== "string") continue;
2442
+ const query = `${candidate.title} ${candidate.summary} ${(candidate.tags ?? []).join(" ")}`.trim();
2443
+ const matches = await this.searchEvents(query, { limit: topK });
2444
+ const decision = await options.decider({ candidate, matches });
2445
+ const allowed = new Set(matches.map(({ event }) => event.id));
2446
+ const existingEventIds = [...new Set((decision.existingEventIds ?? []).filter((id) => allowed.has(id)))];
2447
+ prepared.push({ candidate, decision, existingEventIds });
2448
+ }
2449
+ return this.commitMutation(() => {
2450
+ const addedEvents = [];
2451
+ const changedEventIds = /* @__PURE__ */ new Set();
2452
+ const decisions = [];
2453
+ for (const item of prepared) {
2454
+ const action = this.normalizeExternalAction(item.decision.action);
2455
+ const targets = item.existingEventIds;
2456
+ const reason = typeof item.decision.reason === "string" ? item.decision.reason.trim().slice(0, 500) : void 0;
2457
+ let createdEvent;
2458
+ const proposed = item.decision.mergedCandidate;
2459
+ const candidate = proposed && typeof proposed.title === "string" && typeof proposed.summary === "string" ? proposed : item.candidate;
2460
+ if ((action === "ADD" || action === "MERGE" || action === "SUPERSEDE" || action === "CONFLICT") && (action === "ADD" || targets.length > 0)) {
2461
+ const temporal = {
2462
+ ...candidate.temporal ?? {},
2463
+ ...action === "MERGE" || action === "SUPERSEDE" ? { supersedesEventIds: targets } : {},
2464
+ ...action === "CONFLICT" ? { conflictsWithEventIds: targets } : {}
2465
+ };
2466
+ createdEvent = this.addEventInMemory({
2467
+ ...candidate,
2468
+ sourceBlockId: source.id,
2469
+ sourceMessageIds: [source.l5Raw[0].id],
2470
+ temporal
2471
+ });
2472
+ addedEvents.push(createdEvent);
2473
+ changedEventIds.add(createdEvent.id);
2474
+ if (action === "CONFLICT") {
2475
+ for (const id of targets) {
2476
+ const existing = this.events.find((event) => event.id === id);
2477
+ if (!existing) continue;
2478
+ existing.temporal.conflictsWithEventIds = [.../* @__PURE__ */ new Set([...existing.temporal.conflictsWithEventIds ?? [], createdEvent.id])];
2479
+ existing.updatedAt = importedAt;
2480
+ changedEventIds.add(existing.id);
2481
+ }
2482
+ }
2483
+ }
2484
+ const audit2 = {
2485
+ candidate: structuredClone(item.candidate),
2486
+ action,
2487
+ existingEventIds: targets,
2488
+ ...createdEvent ? { createdEventId: createdEvent.id } : {},
2489
+ ...reason ? { reason } : {}
2490
+ };
2491
+ decisions.push(audit2);
2492
+ }
2493
+ if (addedEvents.length > 0) {
2494
+ const ids = addedEvents.map(({ id }) => id);
2495
+ this.queueElementProjection(ids);
2496
+ this.queueGraphProjection(ids, 2e3);
2497
+ }
2498
+ return {
2499
+ sourceBlockId: source.id,
2500
+ decisions,
2501
+ addedEvents,
2502
+ changedEventIds: [...changedEventIds]
2503
+ };
2504
+ });
2505
+ }
2188
2506
  async searchEvents(query, options = {}) {
2189
2507
  const limit = Math.max(1, Math.min(20, options.limit ?? 6));
2190
2508
  const participants = (options.participants ?? []).map(normalizeSearchText).filter(Boolean);
@@ -2564,6 +2882,43 @@ var StrataGate = class _StrataGate {
2564
2882
  async close() {
2565
2883
  await this.storage?.close?.();
2566
2884
  }
2885
+ normalizeExternalAction(value) {
2886
+ const action = typeof value === "string" ? value.trim().toUpperCase() : "";
2887
+ return action === "ADD" || action === "MERGE" || action === "SUPERSEDE" || action === "CONFLICT" || action === "IGNORE" ? action : "IGNORE";
2888
+ }
2889
+ createExternalSourceBlock(text3, importedAt) {
2890
+ const blockId = this.idFactory("blk");
2891
+ const threadId = `external-import:${blockId}`;
2892
+ const message = {
2893
+ id: this.idFactory("msg"),
2894
+ role: "user",
2895
+ content: text3,
2896
+ createdAt: importedAt,
2897
+ threadId
2898
+ };
2899
+ const firstLine = text3.split(/\r?\n/u).map((line) => line.trim()).find(Boolean) ?? "External AI memory import";
2900
+ const block = {
2901
+ id: blockId,
2902
+ threadId,
2903
+ sequence: this.blocks.length + 1,
2904
+ startTurn: 1,
2905
+ endTurn: 1,
2906
+ createdAt: importedAt,
2907
+ l0Title: firstLine.slice(0, 80),
2908
+ l0Tags: ["external-memory-import"],
2909
+ l1Summary: text3.replace(/\s+/gu, " ").trim().slice(0, 500),
2910
+ l2Keypoints: text3.split(/\r?\n/u).map((line) => line.trim()).filter(Boolean).slice(0, 8),
2911
+ shouldExtract: false,
2912
+ ...deterministicBlockLayers([message]),
2913
+ pointerCurrentLevel: 5,
2914
+ pointerAnchorLevel: 5,
2915
+ pointerAnchorBlockPosition: 1,
2916
+ lastLiftedAt: null,
2917
+ lastLiftedBy: null
2918
+ };
2919
+ this.blocks.push(block);
2920
+ return block;
2921
+ }
2567
2922
  addEventInMemory(input) {
2568
2923
  const sourceBlock = this.blocks.find((block) => block.id === input.sourceBlockId);
2569
2924
  if (!sourceBlock) throw new Error(`Unknown source block: ${input.sourceBlockId}`);
@@ -4152,6 +4507,45 @@ var StrataGateRuntime = class {
4152
4507
  await storage.close();
4153
4508
  }
4154
4509
  }
4510
+ /** Import a v2 external-AI export from the admin UI. */
4511
+ async adminImportExternalMemory(namespace, text3) {
4512
+ const key = namespace.trim();
4513
+ if (!key) throw new TypeError("StrataGate admin namespace must not be empty");
4514
+ await this.flush();
4515
+ const active = this.spaces.get(key);
4516
+ let memory;
4517
+ let owned = false;
4518
+ if (active) {
4519
+ memory = await active;
4520
+ } else {
4521
+ if (this.config.database === ":memory:" || !existsSync(this.config.database)) {
4522
+ throw new Error(`Unknown StrataGate namespace: ${key}`);
4523
+ }
4524
+ memory = await StrataGate.open({
4525
+ database: this.config.database,
4526
+ namespace: key,
4527
+ blockTurnSize: this.config.blockTurnSize,
4528
+ blockDecayLambda: this.blockDecayLambda,
4529
+ graphProjector: this.models.graphProjector,
4530
+ disableElementProjection: true
4531
+ });
4532
+ owned = true;
4533
+ }
4534
+ try {
4535
+ const result = await memory.importExternalMemory({
4536
+ text: text3,
4537
+ decider: async () => ({ action: "ADD" })
4538
+ });
4539
+ return {
4540
+ sourceBlockId: result.sourceBlockId,
4541
+ decisions: result.decisions,
4542
+ importedCount: result.addedEvents.length,
4543
+ changedEventIds: result.changedEventIds
4544
+ };
4545
+ } finally {
4546
+ if (owned) await memory.close();
4547
+ }
4548
+ }
4155
4549
  adminWorkspaceName(namespace) {
4156
4550
  const remembered = this.workspaceNames.get(namespace);
4157
4551
  if (remembered) return remembered;
@@ -4837,7 +5231,7 @@ function clusterKnowledgeGraph(rawNodes, rawEdges) {
4837
5231
  }
4838
5232
 
4839
5233
  // src/web.ts
4840
- var STRATAGATE_DSH_VERSION = "0.2.30";
5234
+ var STRATAGATE_DSH_VERSION = "0.2.31";
4841
5235
  var LEGACY_THREAD_ID = "__legacy__";
4842
5236
  var nodeRequire = createRequire(import.meta.url);
4843
5237
  function installedPackageVersion(names) {
@@ -5033,6 +5427,25 @@ async function updateSettings(runtime, url) {
5033
5427
  }
5034
5428
  return { blockDecayLambda: await runtime.adminSetBlockDecayLambda(value) };
5035
5429
  }
5430
+ async function importExternalMemory(runtime, req) {
5431
+ let body;
5432
+ if (typeof req.body === "string") {
5433
+ try {
5434
+ body = JSON.parse(req.body);
5435
+ } catch {
5436
+ throw new AdminHttpError(400, "\u5BFC\u5165\u6570\u636E\u5FC5\u987B\u662F\u5408\u6CD5 JSON");
5437
+ }
5438
+ } else if (req.body && typeof req.body === "object" && !Array.isArray(req.body)) {
5439
+ body = req.body;
5440
+ } else {
5441
+ throw new AdminHttpError(400, "\u5BFC\u5165\u8BF7\u6C42\u7F3A\u5C11 JSON body");
5442
+ }
5443
+ const namespace = typeof body.namespace === "string" ? body.namespace.trim() : "";
5444
+ const text3 = typeof body.text === "string" ? body.text.trim() : "";
5445
+ if (!namespace) throw new AdminHttpError(400, "namespace is required");
5446
+ if (!text3) throw new AdminHttpError(400, "text is required");
5447
+ return runtime.adminImportExternalMemory(namespace, text3);
5448
+ }
5036
5449
  function receiptThreadId(id) {
5037
5450
  const match = /^dsh:(.+):turn:\d+$/.exec(id);
5038
5451
  return match?.[1]?.trim() || null;
@@ -5387,6 +5800,9 @@ async function handleAdminRequest(runtime, req, res) {
5387
5800
  } else if (path === "/api/stratagate/blocks/expand") {
5388
5801
  if (req.method !== "PATCH") throw new AdminHttpError(405, "StrataGate Block expansion requires PATCH");
5389
5802
  sendJson(res, 200, await expandBlock(runtime, url));
5803
+ } else if (path === "/api/stratagate/import") {
5804
+ if (req.method !== "POST") throw new AdminHttpError(405, "External memory import requires POST");
5805
+ sendJson(res, 200, await importExternalMemory(runtime, req));
5390
5806
  } else if (req.method !== "GET") throw new AdminHttpError(405, "StrataGate memory data is read-only");
5391
5807
  else if (path === "/api/stratagate/overview") sendJson(res, 200, await overview(runtime));
5392
5808
  else if (path === "/api/stratagate/memories") sendJson(res, 200, await memories(runtime, url));