@totalreclaw/totalreclaw 3.3.12-rc.2 → 3.3.12-rc.21
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/CHANGELOG.md +26 -0
- package/SKILL.md +34 -249
- package/api-client.ts +17 -9
- package/batch-gate.ts +42 -0
- package/billing-cache.ts +25 -20
- package/claims-helper.ts +7 -1
- package/config.ts +54 -12
- package/consolidation.ts +6 -13
- package/contradiction-sync.ts +19 -14
- package/credential-provider.ts +184 -0
- package/crypto.ts +27 -160
- package/dist/api-client.js +17 -9
- package/dist/batch-gate.js +40 -0
- package/dist/billing-cache.js +19 -21
- package/dist/claims-helper.js +7 -1
- package/dist/config.js +54 -12
- package/dist/consolidation.js +6 -15
- package/dist/contradiction-sync.js +15 -15
- package/dist/credential-provider.js +145 -0
- package/dist/crypto.js +17 -137
- package/dist/download-ux.js +11 -7
- package/dist/embedder-loader.js +266 -0
- package/dist/embedding.js +36 -3
- package/dist/entry.js +123 -0
- package/dist/extractor.js +134 -0
- package/dist/fs-helpers.js +116 -241
- package/dist/import-adapters/chatgpt-adapter.js +14 -0
- package/dist/import-adapters/claude-adapter.js +14 -0
- package/dist/import-adapters/gemini-adapter.js +43 -159
- package/dist/import-adapters/mcp-memory-adapter.js +14 -0
- package/dist/import-state-manager.js +100 -0
- package/dist/index.js +1130 -2520
- package/dist/llm-client.js +69 -1
- package/dist/memory-runtime.js +459 -0
- package/dist/native-memory.js +123 -0
- package/dist/onboarding-cli.js +3 -2
- package/dist/pair-cli.js +1 -1
- package/dist/pair-crypto.js +16 -358
- package/dist/pair-http.js +147 -4
- package/dist/relay.js +140 -0
- package/dist/reranker.js +13 -8
- package/dist/semantic-dedup.js +5 -7
- package/dist/skill-register.js +97 -0
- package/dist/subgraph-search.js +3 -1
- package/dist/subgraph-store.js +315 -282
- package/dist/tool-gating.js +39 -26
- package/dist/tools.js +367 -0
- package/dist/tr-cli-export-helper.js +103 -0
- package/dist/tr-cli.js +220 -127
- package/dist/trajectory-poller.js +155 -9
- package/dist/vault-crypto.js +551 -0
- package/download-ux.ts +12 -6
- package/embedder-loader.ts +293 -1
- package/embedding.ts +43 -3
- package/entry.ts +132 -0
- package/extractor.ts +167 -0
- package/fs-helpers.ts +166 -292
- package/import-adapters/chatgpt-adapter.ts +18 -0
- package/import-adapters/claude-adapter.ts +18 -0
- package/import-adapters/gemini-adapter.ts +56 -183
- package/import-adapters/mcp-memory-adapter.ts +18 -0
- package/import-adapters/types.ts +1 -1
- package/import-state-manager.ts +139 -0
- package/index.ts +1432 -3002
- package/llm-client.ts +74 -1
- package/memory-runtime.ts +723 -0
- package/native-memory.ts +196 -0
- package/onboarding-cli.ts +3 -2
- package/openclaw.plugin.json +5 -17
- package/package.json +7 -4
- package/pair-cli.ts +1 -1
- package/pair-crypto.ts +41 -483
- package/pair-http.ts +194 -5
- package/postinstall.mjs +138 -0
- package/relay.ts +172 -0
- package/reranker.ts +13 -8
- package/semantic-dedup.ts +5 -6
- package/skill-register.ts +146 -0
- package/skill.json +1 -1
- package/subgraph-search.ts +3 -1
- package/subgraph-store.ts +334 -299
- package/tool-gating.ts +39 -26
- package/tools.ts +499 -0
- package/tr-cli-export-helper.ts +138 -0
- package/tr-cli.ts +263 -133
- package/trajectory-poller.ts +162 -10
- package/vault-crypto.ts +705 -0
package/extractor.ts
CHANGED
|
@@ -199,6 +199,24 @@ export interface ExtractedFact {
|
|
|
199
199
|
* is skipped (facts.length < 5), by the `defaultVolatility` heuristic.
|
|
200
200
|
*/
|
|
201
201
|
volatility?: MemoryVolatility;
|
|
202
|
+
/**
|
|
203
|
+
* am-1: Crystal-shaped debrief structured metadata. When present,
|
|
204
|
+
* re-attached as `metadata` on the v1 blob after core validation.
|
|
205
|
+
* Only set on Crystal debrief facts (type='summary', source='derived').
|
|
206
|
+
*/
|
|
207
|
+
crystalMetadata?: CrystalMetadata;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Structured metadata for a Crystal-shaped session summary (am-1). */
|
|
211
|
+
export interface CrystalMetadata {
|
|
212
|
+
subtype: 'session_crystal';
|
|
213
|
+
key_outcomes: string[];
|
|
214
|
+
open_threads: string[];
|
|
215
|
+
lessons: string[];
|
|
216
|
+
session_id?: string;
|
|
217
|
+
source_message_ids?: string[];
|
|
218
|
+
files_affected?: string[]; // coding hosts (OpenClaw, MCP)
|
|
219
|
+
topics_discussed?: string[]; // chat hosts (Hermes, NanoClaw)
|
|
202
220
|
}
|
|
203
221
|
|
|
204
222
|
const ALLOWED_ENTITY_TYPES: ReadonlySet<EntityType> = new Set([
|
|
@@ -925,6 +943,155 @@ export async function extractDebrief(
|
|
|
925
943
|
}
|
|
926
944
|
}
|
|
927
945
|
|
|
946
|
+
// ---------------------------------------------------------------------------
|
|
947
|
+
// Crystal-shaped debrief (am-1) — one structured summary per session
|
|
948
|
+
// ---------------------------------------------------------------------------
|
|
949
|
+
|
|
950
|
+
const _CRYSTAL_COMMON_FIELDS = `Return a JSON object (no markdown, no code fences):
|
|
951
|
+
{
|
|
952
|
+
"narrative": "1-2 sentence summary of what happened this session",
|
|
953
|
+
"key_outcomes": ["outcome or decision 1", "outcome or decision 2"],
|
|
954
|
+
"open_threads": ["unfinished item 1"],
|
|
955
|
+
"lessons": ["lesson or gotcha 1"],
|
|
956
|
+
"importance": 8
|
|
957
|
+
}`;
|
|
958
|
+
|
|
959
|
+
export const CRYSTAL_SYSTEM_PROMPT_CHAT = `You are crystallising a finished conversation into one structured session summary.
|
|
960
|
+
|
|
961
|
+
The following facts were already extracted and stored during this conversation:
|
|
962
|
+
{already_stored_facts}
|
|
963
|
+
|
|
964
|
+
Write ONE Crystal that captures what turn-by-turn extraction missed. Include:
|
|
965
|
+
- narrative: 1-2 sentences describing the conversation overall
|
|
966
|
+
- key_outcomes: decisions made, problems solved, conclusions reached
|
|
967
|
+
- open_threads: things left unfinished or needing follow-up
|
|
968
|
+
- lessons: patterns, gotchas, or insights worth remembering
|
|
969
|
+
- topics_discussed: the main subjects covered
|
|
970
|
+
- importance: 7-10 (8 default)
|
|
971
|
+
|
|
972
|
+
Do NOT repeat facts already stored. Return null for trivial or very short conversations.
|
|
973
|
+
|
|
974
|
+
${_CRYSTAL_COMMON_FIELDS}
|
|
975
|
+
|
|
976
|
+
Also include "topics_discussed": ["topic 1", "topic 2"] in the object.
|
|
977
|
+
Return null (not an object) for trivial or very short conversations.`;
|
|
978
|
+
|
|
979
|
+
export const CRYSTAL_SYSTEM_PROMPT_CODING = `You are crystallising a finished coding session into one structured session summary.
|
|
980
|
+
|
|
981
|
+
The following facts were already extracted and stored during this conversation:
|
|
982
|
+
{already_stored_facts}
|
|
983
|
+
|
|
984
|
+
Write ONE Crystal that captures what turn-by-turn extraction missed. Include:
|
|
985
|
+
- narrative: 1-2 sentences describing the session overall
|
|
986
|
+
- key_outcomes: decisions made, bugs fixed, features built
|
|
987
|
+
- open_threads: things left unfinished or needing follow-up
|
|
988
|
+
- lessons: patterns, gotchas, or insights worth remembering
|
|
989
|
+
- files_affected: file paths mentioned or worked on (extract from assistant messages)
|
|
990
|
+
- importance: 7-10 (8 default)
|
|
991
|
+
|
|
992
|
+
Do NOT repeat facts already stored. Return null for trivial or very short sessions.
|
|
993
|
+
|
|
994
|
+
${_CRYSTAL_COMMON_FIELDS}
|
|
995
|
+
|
|
996
|
+
Also include "files_affected": ["/path/to/file.ts", ...] in the object (may be []).
|
|
997
|
+
Return null (not an object) for trivial or very short sessions.`;
|
|
998
|
+
|
|
999
|
+
/** Parse an LLM Crystal response into a CrystalMetadata + narrative pair. */
|
|
1000
|
+
export function parseCrystalResponse(
|
|
1001
|
+
response: string,
|
|
1002
|
+
hostType: 'chat' | 'coding' = 'chat',
|
|
1003
|
+
): { narrative: string; importance: number; metadata: CrystalMetadata } | null {
|
|
1004
|
+
let cleaned = response.trim();
|
|
1005
|
+
if (cleaned.startsWith('```')) {
|
|
1006
|
+
cleaned = cleaned.replace(/^```(?:json)?\n?/, '').replace(/\n?```$/, '').trim();
|
|
1007
|
+
}
|
|
1008
|
+
if (cleaned.toLowerCase() === 'null' || cleaned === '') return null;
|
|
1009
|
+
|
|
1010
|
+
let parsed: unknown;
|
|
1011
|
+
try {
|
|
1012
|
+
parsed = JSON.parse(cleaned);
|
|
1013
|
+
} catch {
|
|
1014
|
+
return null;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
if (parsed === null) return null;
|
|
1018
|
+
if (typeof parsed !== 'object' || Array.isArray(parsed)) return null;
|
|
1019
|
+
|
|
1020
|
+
const d = parsed as Record<string, unknown>;
|
|
1021
|
+
const narrative = typeof d.narrative === 'string' ? d.narrative.trim().slice(0, 512) : '';
|
|
1022
|
+
if (narrative.length < 10) return null;
|
|
1023
|
+
|
|
1024
|
+
const strList = (key: string): string[] => {
|
|
1025
|
+
const raw = d[key];
|
|
1026
|
+
if (!Array.isArray(raw)) return [];
|
|
1027
|
+
return raw.map((x) => String(x).trim()).filter((x) => x.length > 0).slice(0, 10);
|
|
1028
|
+
};
|
|
1029
|
+
|
|
1030
|
+
let importance = typeof d.importance === 'number' ? d.importance : 8;
|
|
1031
|
+
importance = Math.max(1, Math.min(10, Math.round(importance)));
|
|
1032
|
+
|
|
1033
|
+
const metadata: CrystalMetadata = {
|
|
1034
|
+
subtype: 'session_crystal',
|
|
1035
|
+
key_outcomes: strList('key_outcomes'),
|
|
1036
|
+
open_threads: strList('open_threads'),
|
|
1037
|
+
lessons: strList('lessons'),
|
|
1038
|
+
};
|
|
1039
|
+
if (hostType === 'coding') {
|
|
1040
|
+
metadata.files_affected = strList('files_affected');
|
|
1041
|
+
} else {
|
|
1042
|
+
metadata.topics_discussed = strList('topics_discussed');
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
return { narrative, importance, metadata };
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Extract a Crystal session summary using LLM.
|
|
1050
|
+
*
|
|
1051
|
+
* Returns null if LLM unavailable, session too short, or LLM returns null.
|
|
1052
|
+
*/
|
|
1053
|
+
export async function extractCrystal(
|
|
1054
|
+
rawMessages: unknown[],
|
|
1055
|
+
storedFactTexts: string[],
|
|
1056
|
+
hostType: 'chat' | 'coding' = 'coding',
|
|
1057
|
+
): Promise<{ narrative: string; importance: number; metadata: CrystalMetadata } | null> {
|
|
1058
|
+
const config = resolveLLMConfig();
|
|
1059
|
+
if (!config) return null;
|
|
1060
|
+
|
|
1061
|
+
const parsed = rawMessages
|
|
1062
|
+
.map(messageToText)
|
|
1063
|
+
.filter((m): m is { role: string; content: string } => m !== null);
|
|
1064
|
+
|
|
1065
|
+
if (parsed.length < 8) return null;
|
|
1066
|
+
|
|
1067
|
+
const conversationText = truncateMessages(parsed, 12_000);
|
|
1068
|
+
if (conversationText.length < 20) return null;
|
|
1069
|
+
|
|
1070
|
+
const alreadyStored = storedFactTexts.length > 0
|
|
1071
|
+
? storedFactTexts.map((t) => `- ${t}`).join('\n')
|
|
1072
|
+
: '(none)';
|
|
1073
|
+
|
|
1074
|
+
const promptTemplate = hostType === 'coding'
|
|
1075
|
+
? CRYSTAL_SYSTEM_PROMPT_CODING
|
|
1076
|
+
: CRYSTAL_SYSTEM_PROMPT_CHAT;
|
|
1077
|
+
const systemPrompt = promptTemplate.replace('{already_stored_facts}', alreadyStored);
|
|
1078
|
+
|
|
1079
|
+
try {
|
|
1080
|
+
const response = await chatCompletion(config, [
|
|
1081
|
+
{ role: 'system', content: systemPrompt },
|
|
1082
|
+
{ role: 'user', content: `Crystallise this session:\n\n${conversationText}` },
|
|
1083
|
+
], {
|
|
1084
|
+
retry: { attempts: 3, baseDelayMs: 1000 },
|
|
1085
|
+
timeoutMs: 30_000,
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
if (!response) return null;
|
|
1089
|
+
return parseCrystalResponse(response, hostType);
|
|
1090
|
+
} catch {
|
|
1091
|
+
return null;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
928
1095
|
// ---------------------------------------------------------------------------
|
|
929
1096
|
// v1 Taxonomy Extraction Pipeline (default as of plugin v3.0.0)
|
|
930
1097
|
//
|