@hyperspell/openclaw-hyperspell 0.1.1 → 0.3.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/README.md CHANGED
@@ -10,9 +10,23 @@ OpenClaw plugin for [Hyperspell](https://hyperspell.com) - Context and memory fo
10
10
  openclaw plugins install @hyperspell/openclaw-hyperspell
11
11
  ```
12
12
 
13
- ## Configuration
13
+ ## Quick Start
14
14
 
15
- Add to your `openclaw.json`:
15
+ Run the interactive setup wizard:
16
+
17
+ ```bash
18
+ openclaw openclaw-hyperspell setup
19
+ ```
20
+
21
+ The setup wizard will guide you through:
22
+ 1. Creating a Hyperspell account (if you don't have one)
23
+ 2. Configuring your API key
24
+ 3. Setting up your User ID for multi-tenant memory
25
+ 4. Connecting your apps (Notion, Slack, Google Drive, etc.)
26
+
27
+ ## Manual Configuration
28
+
29
+ Alternatively, add to your `openclaw.json`:
16
30
 
17
31
  ```json
18
32
  {
@@ -22,6 +36,7 @@ Add to your `openclaw.json`:
22
36
  "enabled": true,
23
37
  "config": {
24
38
  "apiKey": "${HYPERSPELL_API_KEY}",
39
+ "userId": "your-email",
25
40
  "autoContext": true
26
41
  }
27
42
  }
@@ -37,12 +52,26 @@ Or set the environment variable:
37
52
  export HYPERSPELL_API_KEY=hs_...
38
53
  ```
39
54
 
55
+ ## CLI Commands
56
+
57
+ ### `openclaw openclaw-hyperspell setup`
58
+
59
+ Interactive setup wizard that walks you through configuration.
60
+
61
+ ### `openclaw openclaw-hyperspell status`
62
+
63
+ Check your current configuration and connection status.
64
+
65
+ ### `openclaw openclaw-hyperspell connect`
66
+
67
+ Open the Hyperspell connect page to link your accounts (Notion, Slack, Google Drive, etc.)
68
+
40
69
  ### Options
41
70
 
42
71
  | Option | Type | Default | Description |
43
72
  |--------|------|---------|-------------|
44
73
  | `apiKey` | string | `${HYPERSPELL_API_KEY}` | Hyperspell API key |
45
- | `userId` | string | - | User ID to scope searches (for non-JWT API keys) |
74
+ | `userId` | string | - | User ID (can be your email) |
46
75
  | `autoContext` | boolean | `true` | Auto-inject relevant memories before each AI turn |
47
76
  | `sources` | string | - | Comma-separated sources to search (e.g., `notion,slack`) |
48
77
  | `maxResults` | number | `10` | Maximum memories per context injection |
@@ -58,16 +87,6 @@ Search your memories for relevant context.
58
87
  /getcontext Q1 budget planning
59
88
  ```
60
89
 
61
- ### `/connect <source>`
62
-
63
- Connect an account to Hyperspell. Opens the OAuth flow in your browser.
64
-
65
- ```
66
- /connect notion
67
- /connect slack
68
- /connect google_drive
69
- ```
70
-
71
90
  ### `/remember <text>`
72
91
 
73
92
  Save something to memory.
@@ -95,12 +114,11 @@ This ensures the AI always has access to relevant information from your connecte
95
114
 
96
115
  ## Available Sources
97
116
 
98
- - `collections` - User-created collections
117
+ - `vault` - User-created memories
99
118
  - `notion` - Notion pages and databases
100
119
  - `slack` - Slack messages
101
120
  - `google_calendar` - Google Calendar events
102
121
  - `google_mail` - Gmail messages
103
122
  - `google_drive` - Google Drive files
104
123
  - `box` - Box files
105
- - `vault` - Vault documents
106
124
  - `web_crawler` - Crawled web pages
package/client.ts CHANGED
@@ -11,6 +11,11 @@ export type SearchResult = {
11
11
  createdAt: string | null
12
12
  }
13
13
 
14
+ export type SearchWithAnswerResult = {
15
+ answer: string | null
16
+ documents: SearchResult[]
17
+ }
18
+
14
19
  export type Integration = {
15
20
  id: string
16
21
  name: string
@@ -18,6 +23,13 @@ export type Integration = {
18
23
  icon: string
19
24
  }
20
25
 
26
+ export type Connection = {
27
+ id: string
28
+ integrationId: string
29
+ label: string | null
30
+ provider: HyperspellSource
31
+ }
32
+
21
33
  export class HyperspellClient {
22
34
  private client: Hyperspell
23
35
  private config: HyperspellConfig
@@ -26,8 +38,9 @@ export class HyperspellClient {
26
38
  this.config = config
27
39
  this.client = new Hyperspell({
28
40
  apiKey: config.apiKey,
41
+ userID: config.userId,
29
42
  })
30
- log.info("client initialized")
43
+ log.info(`client initialized${config.userId ? ` for user ${config.userId}` : ""}`)
31
44
  }
32
45
 
33
46
  async search(
@@ -61,18 +74,89 @@ export class HyperspellClient {
61
74
  return results
62
75
  }
63
76
 
77
+ async searchRaw(
78
+ query: string,
79
+ options?: { limit?: number; sources?: HyperspellSource[] },
80
+ ): Promise<Record<string, unknown>> {
81
+ const limit = options?.limit ?? this.config.maxResults
82
+ const sources =
83
+ options?.sources ?? (this.config.sources.length > 0 ? this.config.sources : undefined)
84
+
85
+ log.debugRequest("memories.search (raw)", { query, limit, sources })
86
+
87
+ const response = await this.client.memories.search({
88
+ query,
89
+ sources,
90
+ options: {
91
+ max_results: limit,
92
+ },
93
+ })
94
+
95
+ log.debugResponse("memories.search (raw)", { count: response.documents.length })
96
+
97
+ return response as unknown as Record<string, unknown>
98
+ }
99
+
100
+ async searchWithAnswer(
101
+ query: string,
102
+ options?: { limit?: number; sources?: HyperspellSource[] },
103
+ ): Promise<SearchWithAnswerResult> {
104
+ const limit = options?.limit ?? this.config.maxResults
105
+ const sources =
106
+ options?.sources ?? (this.config.sources.length > 0 ? this.config.sources : undefined)
107
+
108
+ log.debugRequest("memories.search (with answer)", { query, limit, sources })
109
+
110
+ const response = await this.client.memories.search({
111
+ query,
112
+ sources,
113
+ answer: true,
114
+ options: {
115
+ max_results: limit,
116
+ },
117
+ })
118
+
119
+ const documents: SearchResult[] = response.documents.map((doc) => ({
120
+ resourceId: doc.resource_id,
121
+ title: doc.title ?? null,
122
+ source: doc.source as HyperspellSource,
123
+ score: doc.score ?? null,
124
+ url: doc.metadata?.url as string | null ?? null,
125
+ createdAt: doc.metadata?.created_at as string | null ?? null,
126
+ }))
127
+
128
+ log.debugResponse("memories.search (with answer)", {
129
+ count: documents.length,
130
+ hasAnswer: !!response.answer,
131
+ })
132
+
133
+ return {
134
+ answer: response.answer ?? null,
135
+ documents,
136
+ }
137
+ }
138
+
64
139
  async addMemory(
65
140
  text: string,
66
- options?: { title?: string; metadata?: Record<string, string | number | boolean> },
141
+ options?: {
142
+ title?: string
143
+ resourceId?: string
144
+ collection?: string
145
+ metadata?: Record<string, string | number | boolean>
146
+ },
67
147
  ): Promise<{ resourceId: string }> {
68
148
  log.debugRequest("memories.add", {
69
149
  textLength: text.length,
70
150
  title: options?.title,
151
+ resourceId: options?.resourceId,
152
+ collection: options?.collection,
71
153
  })
72
154
 
73
155
  const result = await this.client.memories.add({
74
156
  text,
75
157
  title: options?.title,
158
+ resource_id: options?.resourceId,
159
+ collection: options?.collection,
76
160
  metadata: {
77
161
  ...options?.metadata,
78
162
  openclaw_source: "command",
@@ -110,4 +194,20 @@ export class HyperspellClient {
110
194
  expiresAt: response.expires_at,
111
195
  }
112
196
  }
197
+
198
+ async listConnections(): Promise<Connection[]> {
199
+ log.debugRequest("connections.list", {})
200
+
201
+ const response = await this.client.connections.list()
202
+
203
+ const connections: Connection[] = response.connections.map((conn) => ({
204
+ id: conn.id,
205
+ integrationId: conn.integration_id,
206
+ label: conn.label,
207
+ provider: conn.provider as HyperspellSource,
208
+ }))
209
+
210
+ log.debugResponse("connections.list", { count: connections.length })
211
+ return connections
212
+ }
113
213
  }