@hyperspell/openclaw-hyperspell 0.8.1 → 0.10.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.
- package/client.ts +271 -59
- package/commands/setup.ts +1 -0
- package/commands/slash.ts +15 -7
- package/config.ts +55 -0
- package/graph/ops.ts +34 -28
- package/graph/tools.ts +1 -1
- package/hooks/auto-context.ts +163 -10
- package/hooks/auto-trace.ts +12 -2
- package/hooks/emotional-state.ts +97 -0
- package/hooks/memory-sync.ts +5 -3
- package/index.ts +19 -6
- package/lib/sender.ts +76 -0
- package/openclaw.plugin.json +17 -0
- package/package.json +1 -1
- package/sync/markdown.ts +4 -1
- package/tools/remember.ts +56 -48
- package/tools/search.ts +86 -82
- package/types/openclaw.d.ts +16 -0
package/tools/remember.ts
CHANGED
|
@@ -1,60 +1,68 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox"
|
|
2
|
-
import type { OpenClawPluginApi } from "openclaw/plugin-sdk"
|
|
3
2
|
import type { HyperspellClient } from "../client.ts"
|
|
4
3
|
import type { HyperspellConfig } from "../config.ts"
|
|
4
|
+
import { resolveUser } from "../lib/sender.ts"
|
|
5
5
|
import { log } from "../logger.ts"
|
|
6
6
|
|
|
7
|
-
export function
|
|
8
|
-
api: OpenClawPluginApi,
|
|
7
|
+
export function createRememberToolFactory(
|
|
9
8
|
client: HyperspellClient,
|
|
10
|
-
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
)
|
|
30
|
-
|
|
9
|
+
cfg: HyperspellConfig,
|
|
10
|
+
) {
|
|
11
|
+
return (ctx: Record<string, unknown>) => ({
|
|
12
|
+
name: "hyperspell_remember",
|
|
13
|
+
label: "Memory Store",
|
|
14
|
+
description: "Save important information to the user's memory.",
|
|
15
|
+
parameters: Type.Object({
|
|
16
|
+
text: Type.String({ description: "Information to remember" }),
|
|
17
|
+
title: Type.Optional(
|
|
18
|
+
Type.String({ description: "Optional title for the memory" }),
|
|
19
|
+
),
|
|
20
|
+
date: Type.Optional(
|
|
21
|
+
Type.String({ description: "Date of the memory (ISO 8601 or YYYY-MM-DD). Helps ranking and enables date-range filtering. Defaults to now if omitted." }),
|
|
22
|
+
),
|
|
23
|
+
userId: Type.Optional(
|
|
24
|
+
Type.String({
|
|
25
|
+
description:
|
|
26
|
+
"Store for a specific user or 'shared' for everyone. Omit to store for current sender.",
|
|
27
|
+
}),
|
|
28
|
+
),
|
|
29
|
+
}),
|
|
30
|
+
async execute(
|
|
31
|
+
_toolCallId: string,
|
|
32
|
+
params: { text: string; title?: string; date?: string; userId?: string },
|
|
33
|
+
) {
|
|
34
|
+
// Resolve userId: explicit param > sender resolution > config default
|
|
35
|
+
const resolved = resolveUser(ctx, cfg)
|
|
36
|
+
const userId = params.userId ?? resolved?.userId
|
|
37
|
+
log.debug(
|
|
38
|
+
`remember tool: "${params.text.slice(0, 50)}..." date=${params.date ?? "now"} userId=${userId}`,
|
|
39
|
+
)
|
|
31
40
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
try {
|
|
42
|
+
await client.addMemory(params.text, {
|
|
43
|
+
title: params.title,
|
|
44
|
+
date: params.date,
|
|
45
|
+
metadata: { source: "openclaw_tool" },
|
|
46
|
+
userId,
|
|
47
|
+
})
|
|
38
48
|
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
const preview =
|
|
50
|
+
params.text.length > 80 ? `${params.text.slice(0, 80)}…` : params.text
|
|
41
51
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
} catch (err) {
|
|
46
|
-
log.error("remember tool failed", err)
|
|
47
|
-
return {
|
|
48
|
-
content: [
|
|
49
|
-
{
|
|
50
|
-
type: "text" as const,
|
|
51
|
-
text: `Failed to store memory: ${err instanceof Error ? err.message : String(err)}`,
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
}
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: "text" as const, text: `Stored: "${preview}"` }],
|
|
55
54
|
}
|
|
56
|
-
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
log.error("remember tool failed", err)
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: "text" as const,
|
|
61
|
+
text: `Failed to store memory: ${err instanceof Error ? err.message : String(err)}`,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
}
|
|
65
|
+
}
|
|
57
66
|
},
|
|
58
|
-
|
|
59
|
-
)
|
|
67
|
+
})
|
|
60
68
|
}
|
package/tools/search.ts
CHANGED
|
@@ -1,98 +1,102 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox"
|
|
2
|
-
import type { OpenClawPluginApi } from "openclaw/plugin-sdk"
|
|
3
2
|
import type { HyperspellClient } from "../client.ts"
|
|
4
3
|
import type { HyperspellConfig } from "../config.ts"
|
|
4
|
+
import { resolveUser } from "../lib/sender.ts"
|
|
5
5
|
import { log } from "../logger.ts"
|
|
6
6
|
|
|
7
|
-
export function
|
|
8
|
-
api: OpenClawPluginApi,
|
|
7
|
+
export function createSearchToolFactory(
|
|
9
8
|
client: HyperspellClient,
|
|
10
|
-
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
|
|
9
|
+
cfg: HyperspellConfig,
|
|
10
|
+
) {
|
|
11
|
+
return (ctx: Record<string, unknown>) => ({
|
|
12
|
+
name: "hyperspell_search",
|
|
13
|
+
label: "Memory Search",
|
|
14
|
+
description:
|
|
15
|
+
"Search through the user's connected sources (Notion, Slack, Gmail, Google Drive, etc.) for relevant information.",
|
|
16
|
+
parameters: Type.Object({
|
|
17
|
+
query: Type.String({ description: "Search query" }),
|
|
18
|
+
limit: Type.Optional(
|
|
19
|
+
Type.Number({ description: "Max results (default: 5)" }),
|
|
20
|
+
),
|
|
21
|
+
after: Type.Optional(
|
|
22
|
+
Type.String({ description: "Only return memories created on or after this date (ISO 8601 or YYYY-MM-DD)" }),
|
|
23
|
+
),
|
|
24
|
+
before: Type.Optional(
|
|
25
|
+
Type.String({ description: "Only return memories created before this date (ISO 8601 or YYYY-MM-DD)" }),
|
|
26
|
+
),
|
|
27
|
+
userId: Type.Optional(
|
|
28
|
+
Type.String({
|
|
29
|
+
description:
|
|
30
|
+
"Search as a specific user (e.g. 'ben', 'shared'). Omit to search as current sender.",
|
|
31
|
+
}),
|
|
32
|
+
),
|
|
33
|
+
}),
|
|
34
|
+
async execute(
|
|
35
|
+
_toolCallId: string,
|
|
36
|
+
params: { query: string; limit?: number; after?: string; before?: string; userId?: string },
|
|
37
|
+
) {
|
|
38
|
+
const limit = params.limit ?? 5
|
|
39
|
+
// Resolve userId: explicit param > sender resolution > config default
|
|
40
|
+
const resolved = resolveUser(ctx, cfg)
|
|
41
|
+
const userId = params.userId ?? resolved?.userId
|
|
42
|
+
log.debug(
|
|
43
|
+
`search tool: query="${params.query}" limit=${limit} after=${params.after ?? "none"} before=${params.before ?? "none"} userId=${userId}`,
|
|
44
|
+
)
|
|
36
45
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
try {
|
|
47
|
+
const response = await client.searchRaw(params.query, {
|
|
48
|
+
limit,
|
|
49
|
+
after: params.after,
|
|
50
|
+
before: params.before,
|
|
51
|
+
userId,
|
|
52
|
+
})
|
|
53
|
+
const documents = (response.documents ?? []) as Array<{
|
|
54
|
+
source: string
|
|
55
|
+
resource_id: string
|
|
56
|
+
score?: number
|
|
57
|
+
summary?: string
|
|
58
|
+
title?: string
|
|
59
|
+
metadata?: Record<string, unknown>
|
|
60
|
+
highlights?: Array<{ text: string }>
|
|
61
|
+
data?: Array<{ text: string }>
|
|
62
|
+
}>
|
|
49
63
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
64
|
+
if (documents.length === 0) {
|
|
65
|
+
return {
|
|
66
|
+
content: [
|
|
67
|
+
{ type: "text" as const, text: "No relevant memories found." },
|
|
68
|
+
],
|
|
56
69
|
}
|
|
70
|
+
}
|
|
57
71
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
const formattedDocs = documents
|
|
73
|
+
.map((doc, i) => {
|
|
74
|
+
const relevance = doc.score
|
|
75
|
+
? `${Math.round(doc.score * 100)}%`
|
|
76
|
+
: "N/A"
|
|
77
|
+
const title = doc.title || "(untitled)"
|
|
78
|
+
const summary = doc.summary || "(no summary)"
|
|
79
|
+
return `${i + 1}. Source: ${doc.source}\n Title: ${title}\n Summary: ${summary}\n Relevance: ${relevance}`
|
|
80
|
+
})
|
|
81
|
+
.join("\n\n")
|
|
68
82
|
|
|
69
|
-
|
|
83
|
+
const text = `Found ${documents.length} memories:\n\n${formattedDocs}`
|
|
70
84
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
return {
|
|
86
|
+
content: [{ type: "text" as const, text }],
|
|
87
|
+
details: { count: documents.length, documents },
|
|
88
|
+
}
|
|
89
|
+
} catch (err) {
|
|
90
|
+
log.error("search tool failed", err)
|
|
91
|
+
return {
|
|
92
|
+
content: [
|
|
93
|
+
{
|
|
94
|
+
type: "text" as const,
|
|
95
|
+
text: `Search failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
81
96
|
},
|
|
82
|
-
|
|
83
|
-
} catch (err) {
|
|
84
|
-
log.error("search tool failed", err)
|
|
85
|
-
return {
|
|
86
|
-
content: [
|
|
87
|
-
{
|
|
88
|
-
type: "text" as const,
|
|
89
|
-
text: `Search failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
90
|
-
},
|
|
91
|
-
],
|
|
92
|
-
}
|
|
97
|
+
],
|
|
93
98
|
}
|
|
94
|
-
}
|
|
99
|
+
}
|
|
95
100
|
},
|
|
96
|
-
|
|
97
|
-
)
|
|
101
|
+
})
|
|
98
102
|
}
|
package/types/openclaw.d.ts
CHANGED
|
@@ -48,6 +48,22 @@ declare module "openclaw/plugin-sdk" {
|
|
|
48
48
|
},
|
|
49
49
|
meta: { name: string },
|
|
50
50
|
): void
|
|
51
|
+
registerTool<T = unknown>(
|
|
52
|
+
factory: (ctx: Record<string, unknown>) => {
|
|
53
|
+
name: string
|
|
54
|
+
label: string
|
|
55
|
+
description: string
|
|
56
|
+
parameters: unknown
|
|
57
|
+
execute: (
|
|
58
|
+
toolCallId: string,
|
|
59
|
+
params: T,
|
|
60
|
+
) => Promise<{
|
|
61
|
+
content: Array<{ type: "text"; text: string }>
|
|
62
|
+
details?: Record<string, unknown>
|
|
63
|
+
}>
|
|
64
|
+
},
|
|
65
|
+
meta: { name: string },
|
|
66
|
+
): void
|
|
51
67
|
on(event: string, handler: (event: Record<string, unknown>, ctx?: Record<string, unknown>) => Promise<{ prependContext?: string } | void> | void): void
|
|
52
68
|
registerService(options: {
|
|
53
69
|
id: string
|