@usecortex_ai/openclaw-cortex-ai 0.0.1 → 0.1.1
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/.github/workflows/publish.yaml +40 -0
- package/README.md +47 -27
- package/client.ts +11 -3
- package/commands/cli.ts +4 -0
- package/commands/onboarding.ts +442 -0
- package/commands/slash.ts +4 -4
- package/config.ts +8 -1
- package/hooks/capture.ts +76 -60
- package/hooks/recall.ts +6 -0
- package/index.ts +30 -9
- package/log.ts +27 -4
- package/messages.ts +88 -0
- package/openclaw.plugin.json +6 -0
- package/package.json +1 -1
- package/session.ts +10 -2
- package/tools/delete.ts +54 -0
- package/tools/get.ts +57 -0
- package/tools/list.ts +56 -0
- package/tools/search.ts +1 -1
- package/tools/store.ts +68 -14
- package/types/cortex.ts +2 -0
package/tools/store.ts
CHANGED
|
@@ -3,23 +3,32 @@ import type { OpenClawPluginApi } from "openclaw/plugin-sdk"
|
|
|
3
3
|
import type { CortexClient } from "../client.ts"
|
|
4
4
|
import type { CortexPluginConfig } from "../config.ts"
|
|
5
5
|
import { log } from "../log.ts"
|
|
6
|
-
import {
|
|
6
|
+
import { extractAllTurns, filterIgnoredTurns } from "../messages.ts"
|
|
7
|
+
import { toToolSourceId } from "../session.ts"
|
|
8
|
+
import type { ConversationTurn } from "../types/cortex.ts"
|
|
9
|
+
|
|
10
|
+
const MAX_STORE_TURNS = 10
|
|
11
|
+
|
|
12
|
+
function removeInjectedBlocks(text: string): string {
|
|
13
|
+
return text.replace(/<cortex-context>[\s\S]*?<\/cortex-context>\s*/g, "").trim()
|
|
14
|
+
}
|
|
7
15
|
|
|
8
16
|
export function registerStoreTool(
|
|
9
17
|
api: OpenClawPluginApi,
|
|
10
18
|
client: CortexClient,
|
|
11
|
-
|
|
12
|
-
|
|
19
|
+
cfg: CortexPluginConfig,
|
|
20
|
+
getSessionId: () => string | undefined,
|
|
21
|
+
getMessages: () => unknown[],
|
|
13
22
|
): void {
|
|
14
23
|
api.registerTool(
|
|
15
24
|
{
|
|
16
25
|
name: "cortex_store",
|
|
17
26
|
label: "Cortex Store",
|
|
18
27
|
description:
|
|
19
|
-
"Save
|
|
28
|
+
"Save the full conversation history to Cortex AI memory. Use this to persist facts, preferences, or decisions the user wants remembered. The complete chat history will be sent for context-rich storage.",
|
|
20
29
|
parameters: Type.Object({
|
|
21
30
|
text: Type.String({
|
|
22
|
-
description: "
|
|
31
|
+
description: "A brief summary or note about what is being saved",
|
|
23
32
|
}),
|
|
24
33
|
title: Type.Optional(
|
|
25
34
|
Type.String({
|
|
@@ -31,10 +40,60 @@ export function registerStoreTool(
|
|
|
31
40
|
_toolCallId: string,
|
|
32
41
|
params: { text: string; title?: string },
|
|
33
42
|
) {
|
|
34
|
-
const
|
|
35
|
-
const sourceId =
|
|
43
|
+
const sid = getSessionId()
|
|
44
|
+
const sourceId = sid ? toToolSourceId(sid) : undefined
|
|
45
|
+
const messages = getMessages()
|
|
46
|
+
|
|
47
|
+
log.debug(`[store] tool called — sid=${sid ?? "none"} msgs=${messages.length} text="${params.text.slice(0, 50)}"`)
|
|
48
|
+
|
|
49
|
+
const rawTurns = extractAllTurns(messages)
|
|
50
|
+
const filteredTurns = filterIgnoredTurns(rawTurns, cfg.ignoreTerm)
|
|
51
|
+
const recentTurns = filteredTurns.slice(-MAX_STORE_TURNS)
|
|
52
|
+
const turns: ConversationTurn[] = recentTurns.map((t) => ({
|
|
53
|
+
user: removeInjectedBlocks(t.user),
|
|
54
|
+
assistant: removeInjectedBlocks(t.assistant),
|
|
55
|
+
}))
|
|
56
|
+
|
|
57
|
+
log.debug(`[store] extracted ${rawTurns.length} total turns, ${rawTurns.length - filteredTurns.length} ignored, using last ${turns.length} (MAX_STORE_TURNS=${MAX_STORE_TURNS})`)
|
|
58
|
+
|
|
59
|
+
if (turns.length > 0 && sourceId) {
|
|
60
|
+
const now = new Date()
|
|
61
|
+
const readableTime = now.toLocaleString("en-US", {
|
|
62
|
+
weekday: "short",
|
|
63
|
+
year: "numeric",
|
|
64
|
+
month: "short",
|
|
65
|
+
day: "numeric",
|
|
66
|
+
hour: "2-digit",
|
|
67
|
+
minute: "2-digit",
|
|
68
|
+
timeZoneName: "short",
|
|
69
|
+
})
|
|
36
70
|
|
|
37
|
-
|
|
71
|
+
const annotatedTurns = turns.map((t, i) => ({
|
|
72
|
+
user: i === 0 ? `[Temporal details: ${readableTime}]\n\n${t.user}` : t.user,
|
|
73
|
+
assistant: t.assistant,
|
|
74
|
+
}))
|
|
75
|
+
|
|
76
|
+
log.debug(`[store] ingesting ${annotatedTurns.length} conversation turns -> ${sourceId}`)
|
|
77
|
+
|
|
78
|
+
await client.ingestConversation(annotatedTurns, sourceId, {
|
|
79
|
+
metadata: {
|
|
80
|
+
captured_at: now.toISOString(),
|
|
81
|
+
source: "openclaw_tool",
|
|
82
|
+
note: params.text,
|
|
83
|
+
},
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
content: [
|
|
88
|
+
{
|
|
89
|
+
type: "text" as const,
|
|
90
|
+
text: `Saved ${annotatedTurns.length} conversation turns to Cortex (${sourceId}). Note: "${params.text.length > 80 ? `${params.text.slice(0, 80)}…` : params.text}"`,
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
log.debug("[store] no conversation turns found, falling back to text ingestion")
|
|
38
97
|
|
|
39
98
|
await client.ingestText(params.text, {
|
|
40
99
|
sourceId,
|
|
@@ -42,16 +101,11 @@ export function registerStoreTool(
|
|
|
42
101
|
infer: true,
|
|
43
102
|
})
|
|
44
103
|
|
|
45
|
-
const preview =
|
|
46
|
-
params.text.length > 80
|
|
47
|
-
? `${params.text.slice(0, 80)}…`
|
|
48
|
-
: params.text
|
|
49
|
-
|
|
50
104
|
return {
|
|
51
105
|
content: [
|
|
52
106
|
{
|
|
53
107
|
type: "text" as const,
|
|
54
|
-
text: `Saved to Cortex: "${
|
|
108
|
+
text: `Saved to Cortex: "${params.text.length > 80 ? `${params.text.slice(0, 80)}…` : params.text}"`,
|
|
55
109
|
},
|
|
56
110
|
],
|
|
57
111
|
}
|