openclaw-penfield 1.1.2 → 2.0.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 +48 -7
- package/dist/index.js +2 -2
- package/dist/src/api-client.d.ts.map +1 -1
- package/dist/src/api-client.js +3 -0
- package/dist/src/response-compact.d.ts +91 -0
- package/dist/src/response-compact.d.ts.map +1 -0
- package/dist/src/response-compact.js +152 -0
- package/dist/src/tools/disconnect.d.ts +7 -0
- package/dist/src/tools/disconnect.d.ts.map +1 -0
- package/dist/src/tools/disconnect.js +38 -0
- package/dist/src/tools/explore.d.ts.map +1 -1
- package/dist/src/tools/explore.js +3 -1
- package/dist/src/tools/index.d.ts.map +1 -1
- package/dist/src/tools/index.js +3 -1
- package/dist/src/tools/recall.d.ts +4 -0
- package/dist/src/tools/recall.d.ts.map +1 -1
- package/dist/src/tools/recall.js +14 -3
- package/dist/src/tools/reflect.d.ts.map +1 -1
- package/dist/src/tools/reflect.js +4 -1
- package/dist/src/tools/search.d.ts +4 -0
- package/dist/src/tools/search.d.ts.map +1 -1
- package/dist/src/tools/search.js +14 -3
- package/dist/src/types/typebox.d.ts +4 -0
- package/dist/src/types/typebox.d.ts.map +1 -1
- package/dist/src/types/typebox.js +20 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ Penfield is in **free beta**. Sign up for access:
|
|
|
38
38
|
|
|
39
39
|
Native OpenClaw plugin providing direct integration with Penfield's memory and knowledge graph API. This plugin offers 4-5x performance improvement over the MCP server approach by eliminating the mcporter → MCP → Penfield stack.
|
|
40
40
|
|
|
41
|
-
- **
|
|
41
|
+
- **17 Memory Tools**
|
|
42
42
|
- **OAuth 2.1 Device Code Flow**: Secure authentication following RFC 8628
|
|
43
43
|
- **Hybrid Search**: BM25 + vector + graph search capabilities
|
|
44
44
|
- **Knowledge Graph**: Build and traverse relationships between memories
|
|
@@ -66,6 +66,20 @@ openclaw plugins install -l .
|
|
|
66
66
|
|
|
67
67
|
The plugin is **auto-enabled when loaded**. No configuration required for basic use.
|
|
68
68
|
|
|
69
|
+
### Plugin Allowlist
|
|
70
|
+
|
|
71
|
+
OpenClaw recommends explicitly trusting non-bundled plugins. If you see `plugins.allow is empty` warnings on startup, add the plugin to your allowlist in `openclaw.json`:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"plugins": {
|
|
76
|
+
"allow": ["openclaw-penfield"]
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Once the `allow` array exists, future `openclaw plugins install` and `openclaw plugins enable` commands will automatically append to it.
|
|
82
|
+
|
|
69
83
|
### Plugin Config
|
|
70
84
|
|
|
71
85
|
In `openclaw.json` under `plugins.entries`:
|
|
@@ -175,7 +189,7 @@ Store a new memory in Penfield.
|
|
|
175
189
|
```
|
|
176
190
|
|
|
177
191
|
#### `penfield_recall`
|
|
178
|
-
Hybrid search using BM25 + vector + graph.
|
|
192
|
+
Hybrid search using BM25 + vector + graph. Returns compact responses (essential fields only).
|
|
179
193
|
|
|
180
194
|
**Parameters:**
|
|
181
195
|
- `query` (required): Search query (1-4,000 chars)
|
|
@@ -186,6 +200,10 @@ Hybrid search using BM25 + vector + graph.
|
|
|
186
200
|
- `memory_types` (optional): Filter by types
|
|
187
201
|
- `importance_threshold` (optional): Minimum importance
|
|
188
202
|
- `enable_graph_expansion` (optional): Enable traversal (default: true)
|
|
203
|
+
- `start_date` (optional): Filter memories created on or after this date (ISO 8601, e.g. "2025-01-01")
|
|
204
|
+
- `end_date` (optional): Filter memories created on or before this date (ISO 8601, e.g. "2025-12-31")
|
|
205
|
+
- `sort` (optional): Sort order — "relevance" (default), "created_desc", or "created_asc"
|
|
206
|
+
- `max_content_length` (optional): Truncate content to N characters (50-10,000). Full content available via `penfield_fetch`.
|
|
189
207
|
|
|
190
208
|
**Example:**
|
|
191
209
|
```typescript
|
|
@@ -194,18 +212,23 @@ Hybrid search using BM25 + vector + graph.
|
|
|
194
212
|
"limit": 10,
|
|
195
213
|
"vector_weight": 0.5,
|
|
196
214
|
"bm25_weight": 0.3,
|
|
197
|
-
"graph_weight": 0.2
|
|
215
|
+
"graph_weight": 0.2,
|
|
216
|
+
"start_date": "2025-06-01"
|
|
198
217
|
}
|
|
199
218
|
```
|
|
200
219
|
|
|
201
220
|
#### `penfield_search`
|
|
202
|
-
Semantic search variant (higher vector weight).
|
|
221
|
+
Semantic search variant (higher vector weight). Returns compact responses (essential fields only).
|
|
203
222
|
|
|
204
223
|
**Parameters:**
|
|
205
|
-
- `query` (required): Search query
|
|
206
|
-
- `limit` (optional): Max results
|
|
224
|
+
- `query` (required): Search query (1-4,000 chars)
|
|
225
|
+
- `limit` (optional): Max results (default: 20, max: 100)
|
|
207
226
|
- `memory_types` (optional): Filter by types
|
|
208
227
|
- `importance_threshold` (optional): Minimum importance
|
|
228
|
+
- `start_date` (optional): Filter memories created on or after this date (ISO 8601)
|
|
229
|
+
- `end_date` (optional): Filter memories created on or before this date (ISO 8601)
|
|
230
|
+
- `sort` (optional): Sort order — "relevance" (default), "created_desc", or "created_asc"
|
|
231
|
+
- `max_content_length` (optional): Truncate content to N characters (50-10,000)
|
|
209
232
|
|
|
210
233
|
#### `penfield_fetch`
|
|
211
234
|
Get a specific memory by ID.
|
|
@@ -253,6 +276,21 @@ Create a relationship between two memories.
|
|
|
253
276
|
}
|
|
254
277
|
```
|
|
255
278
|
|
|
279
|
+
#### `penfield_disconnect`
|
|
280
|
+
Remove a relationship between two memories.
|
|
281
|
+
|
|
282
|
+
**Parameters:**
|
|
283
|
+
- `from_memory_id` (required): Source memory ID (UUID format)
|
|
284
|
+
- `to_memory_id` (required): Target memory ID (UUID format)
|
|
285
|
+
|
|
286
|
+
**Example:**
|
|
287
|
+
```typescript
|
|
288
|
+
{
|
|
289
|
+
"from_memory_id": "22618318-8d82-49c9-8bb8-1cf3a61b3c75",
|
|
290
|
+
"to_memory_id": "20413926-2446-4f88-bfd6-749b37969f34"
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
256
294
|
#### `penfield_explore`
|
|
257
295
|
Traverse the knowledge graph from a starting memory.
|
|
258
296
|
|
|
@@ -478,18 +516,20 @@ src/
|
|
|
478
516
|
├── hooks.ts # Lifecycle hooks (auto-awaken, auto-orient, flush config check)
|
|
479
517
|
├── auth-service.ts # Background OAuth token refresh service
|
|
480
518
|
├── api-client.ts # HTTP client wrapper
|
|
519
|
+
├── response-compact.ts # Response compaction (mirrors MCP field-stripping)
|
|
481
520
|
├── runtime.ts # Runtime factory (receives authService from index.ts)
|
|
482
521
|
├── store.ts # Credential file I/O with TOKEN_EXPIRY_BUFFER_MS
|
|
483
522
|
├── cli.ts # CLI command registration (penfield login)
|
|
484
523
|
├── device-flow.ts # RFC 8628 Device Code Flow implementation
|
|
485
524
|
└── tools/
|
|
486
|
-
├── index.ts # Tool registry (
|
|
525
|
+
├── index.ts # Tool registry (17 tools)
|
|
487
526
|
├── store.ts # penfield_store
|
|
488
527
|
├── recall.ts # penfield_recall
|
|
489
528
|
├── search.ts # penfield_search
|
|
490
529
|
├── fetch.ts # penfield_fetch
|
|
491
530
|
├── update-memory.ts # penfield_update_memory
|
|
492
531
|
├── connect.ts # penfield_connect
|
|
532
|
+
├── disconnect.ts # penfield_disconnect
|
|
493
533
|
├── explore.ts # penfield_explore
|
|
494
534
|
├── save-context.ts # penfield_save_context
|
|
495
535
|
├── restore-context.ts # penfield_restore_context
|
|
@@ -525,6 +565,7 @@ The plugin uses two services and one hook registered with OpenClaw:
|
|
|
525
565
|
|------|--------|----------|
|
|
526
566
|
| awaken | GET | /api/v2/personality/awakening |
|
|
527
567
|
| connect | POST | /api/v2/relationships |
|
|
568
|
+
| disconnect | DELETE | /api/v2/relationships/between |
|
|
528
569
|
| delete_artifact | DELETE | /api/v2/artifacts |
|
|
529
570
|
| explore | POST | /api/v2/relationships/traverse |
|
|
530
571
|
| fetch | GET | /api/v2/memories/{id} |
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { createAuthService } from "./src/auth-service.js";
|
|
|
7
7
|
const penfieldPlugin = {
|
|
8
8
|
id: "openclaw-penfield",
|
|
9
9
|
name: "Penfield Memory",
|
|
10
|
-
description: "Native Penfield memory integration with
|
|
10
|
+
description: "Native Penfield memory integration with 17 tools for knowledge management",
|
|
11
11
|
configSchema: {
|
|
12
12
|
parse(value) {
|
|
13
13
|
return PenfieldConfigSchema.parse(value ?? {});
|
|
@@ -79,7 +79,7 @@ const penfieldPlugin = {
|
|
|
79
79
|
logger.info("[penfield-auth] Service stopped");
|
|
80
80
|
},
|
|
81
81
|
});
|
|
82
|
-
// Register all
|
|
82
|
+
// Register all 17 tools
|
|
83
83
|
registerPenfieldTools(api, ensureRuntime);
|
|
84
84
|
// Register lifecycle hooks (auto-awaken + auto-orient, injected every turn)
|
|
85
85
|
registerPenfieldHooks({ api, config: cfg, ensureRuntime, logger });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../src/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM,CAAC;gBAFP,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,YAAY,YAAA;IAGzB,OAAO,CAAC,CAAC,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,OAAO,EACd,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,OAAO,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../src/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM,CAAC;gBAFP,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,YAAY,YAAA;IAGzB,OAAO,CAAC,CAAC,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,OAAO,EACd,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,OAAO,CAAC,CAAC,CAAC;IA2DP,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAI1E,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIrD,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIpD,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAGpF"}
|
package/dist/src/api-client.js
CHANGED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response compaction utilities.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the MCP server's field-stripping patterns so models receive only
|
|
5
|
+
* the fields they need, saving context tokens and reducing noise.
|
|
6
|
+
*/
|
|
7
|
+
/** Minimum relevance score — results below this are dropped (matches MCP) */
|
|
8
|
+
export declare const RELEVANCE_THRESHOLD = 0.05;
|
|
9
|
+
interface CompactMemory {
|
|
10
|
+
id: string | undefined;
|
|
11
|
+
content: string | undefined;
|
|
12
|
+
type: string;
|
|
13
|
+
relevance: number;
|
|
14
|
+
created: string | undefined;
|
|
15
|
+
tags: string[];
|
|
16
|
+
source_type?: string;
|
|
17
|
+
filename?: string;
|
|
18
|
+
document_title?: string;
|
|
19
|
+
document_id?: string;
|
|
20
|
+
content_with_context?: string;
|
|
21
|
+
chunk_index?: number;
|
|
22
|
+
total_chunks?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface CompactRecallResponse {
|
|
25
|
+
query: string;
|
|
26
|
+
found: number;
|
|
27
|
+
memories: CompactMemory[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Compact a hybrid search response to essential fields.
|
|
31
|
+
*
|
|
32
|
+
* Strips: score_breakdown, search_metadata, knowledge_cloud, analyzed_query,
|
|
33
|
+
* raw metadata objects. Filters results below RELEVANCE_THRESHOLD.
|
|
34
|
+
*
|
|
35
|
+
* Optionally sorts by created date and truncates content.
|
|
36
|
+
*/
|
|
37
|
+
export declare function compactRecallResponse(response: any, query: string, options?: {
|
|
38
|
+
sort?: string;
|
|
39
|
+
maxContentLength?: number;
|
|
40
|
+
}): CompactRecallResponse;
|
|
41
|
+
interface CompactReflectMemory {
|
|
42
|
+
content: string | undefined;
|
|
43
|
+
type: string;
|
|
44
|
+
importance: number | undefined;
|
|
45
|
+
score: number | undefined;
|
|
46
|
+
}
|
|
47
|
+
export interface CompactReflectResponse {
|
|
48
|
+
time_window: string;
|
|
49
|
+
memories_analyzed: number;
|
|
50
|
+
active_topics: unknown[];
|
|
51
|
+
top_memories: CompactReflectMemory[];
|
|
52
|
+
patterns: unknown[];
|
|
53
|
+
insights: unknown[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Compact a reflect response to essential fields.
|
|
57
|
+
*
|
|
58
|
+
* Strips full statistics object. Slices memories to top 5, topics to top 10.
|
|
59
|
+
*/
|
|
60
|
+
export declare function compactReflectResponse(response: any, timeWindow: string): CompactReflectResponse;
|
|
61
|
+
interface CompactNode {
|
|
62
|
+
id: string;
|
|
63
|
+
preview?: string;
|
|
64
|
+
type?: string;
|
|
65
|
+
tags?: string[];
|
|
66
|
+
}
|
|
67
|
+
interface CompactRelationship {
|
|
68
|
+
id: string;
|
|
69
|
+
type?: string;
|
|
70
|
+
strength?: number;
|
|
71
|
+
}
|
|
72
|
+
interface CompactPath {
|
|
73
|
+
nodes: CompactNode[];
|
|
74
|
+
relationships: CompactRelationship[];
|
|
75
|
+
depth: number;
|
|
76
|
+
}
|
|
77
|
+
export interface CompactExploreResponse {
|
|
78
|
+
start_memory: string;
|
|
79
|
+
paths_found: number;
|
|
80
|
+
max_depth_reached: number;
|
|
81
|
+
paths: CompactPath[];
|
|
82
|
+
message?: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Compact a graph traversal response.
|
|
86
|
+
*
|
|
87
|
+
* Enriches nodes/relationships with selective fields from detail lookups.
|
|
88
|
+
*/
|
|
89
|
+
export declare function compactExploreResponse(response: any, startMemoryId: string): CompactExploreResponse;
|
|
90
|
+
export {};
|
|
91
|
+
//# sourceMappingURL=response-compact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-compact.d.ts","sourceRoot":"","sources":["../../src/response-compact.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAyBxC,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAEnC,QAAQ,EAAE,GAAG,EACb,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GACrD,qBAAqB,CA0DvB;AAMD,UAAU,oBAAoB;IAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,OAAO,EAAE,CAAC;IACzB,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAEpC,QAAQ,EAAE,GAAG,EACb,UAAU,EAAE,MAAM,GACjB,sBAAsB,CAmBxB;AAMD,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,UAAU,mBAAmB;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,WAAW;IACnB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,aAAa,EAAE,mBAAmB,EAAE,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAEpC,QAAQ,EAAE,GAAG,EACb,aAAa,EAAE,MAAM,GACpB,sBAAsB,CAiDxB"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response compaction utilities.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the MCP server's field-stripping patterns so models receive only
|
|
5
|
+
* the fields they need, saving context tokens and reducing noise.
|
|
6
|
+
*/
|
|
7
|
+
/** Minimum relevance score — results below this are dropped (matches MCP) */
|
|
8
|
+
export const RELEVANCE_THRESHOLD = 0.05;
|
|
9
|
+
/** Maximum memories returned in reflect compaction */
|
|
10
|
+
const MAX_REFLECT_MEMORIES = 5;
|
|
11
|
+
/** Maximum active topics returned in reflect compaction */
|
|
12
|
+
const MAX_REFLECT_TOPICS = 10;
|
|
13
|
+
/**
|
|
14
|
+
* Compact a hybrid search response to essential fields.
|
|
15
|
+
*
|
|
16
|
+
* Strips: score_breakdown, search_metadata, knowledge_cloud, analyzed_query,
|
|
17
|
+
* raw metadata objects. Filters results below RELEVANCE_THRESHOLD.
|
|
18
|
+
*
|
|
19
|
+
* Optionally sorts by created date and truncates content.
|
|
20
|
+
*/
|
|
21
|
+
export function compactRecallResponse(
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- raw API shape
|
|
23
|
+
response, query, options) {
|
|
24
|
+
const items = response?.items ?? [];
|
|
25
|
+
const memories = [];
|
|
26
|
+
for (const result of items) {
|
|
27
|
+
const score = result.score ?? 0;
|
|
28
|
+
if (score < RELEVANCE_THRESHOLD)
|
|
29
|
+
continue;
|
|
30
|
+
const metadata = result.metadata ?? {};
|
|
31
|
+
const memoryType = metadata.memory_type ?? "unknown";
|
|
32
|
+
const sourceType = result.source_type ?? metadata.source_type;
|
|
33
|
+
const entry = {
|
|
34
|
+
id: result.id,
|
|
35
|
+
content: result.content,
|
|
36
|
+
type: memoryType,
|
|
37
|
+
relevance: score,
|
|
38
|
+
created: result.created_at,
|
|
39
|
+
tags: result.tags ?? [],
|
|
40
|
+
};
|
|
41
|
+
// Include document metadata when applicable
|
|
42
|
+
if (sourceType === "document_upload") {
|
|
43
|
+
entry.source_type = "document";
|
|
44
|
+
if (metadata.filename)
|
|
45
|
+
entry.filename = metadata.filename;
|
|
46
|
+
if (metadata.document_title)
|
|
47
|
+
entry.document_title = metadata.document_title;
|
|
48
|
+
if (metadata.document_id)
|
|
49
|
+
entry.document_id = metadata.document_id;
|
|
50
|
+
}
|
|
51
|
+
// Include chunk context when present
|
|
52
|
+
if (result.content_with_context) {
|
|
53
|
+
entry.content_with_context = result.content_with_context;
|
|
54
|
+
entry.chunk_index = result.chunk_index;
|
|
55
|
+
entry.total_chunks = result.total_chunks;
|
|
56
|
+
}
|
|
57
|
+
memories.push(entry);
|
|
58
|
+
}
|
|
59
|
+
// Client-side sort
|
|
60
|
+
if (options?.sort === "created_desc") {
|
|
61
|
+
memories.sort((a, b) => (b.created ?? "").localeCompare(a.created ?? ""));
|
|
62
|
+
}
|
|
63
|
+
else if (options?.sort === "created_asc") {
|
|
64
|
+
memories.sort((a, b) => (a.created ?? "").localeCompare(b.created ?? ""));
|
|
65
|
+
}
|
|
66
|
+
// default "relevance" — already sorted by API
|
|
67
|
+
// Content truncation
|
|
68
|
+
if (options?.maxContentLength != null && options.maxContentLength > 0) {
|
|
69
|
+
const max = options.maxContentLength;
|
|
70
|
+
for (const m of memories) {
|
|
71
|
+
if (m.content && m.content.length > max) {
|
|
72
|
+
m.content = m.content.slice(0, max) + "... [truncated, use penfield_fetch for full content]";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return { query, found: memories.length, memories };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Compact a reflect response to essential fields.
|
|
80
|
+
*
|
|
81
|
+
* Strips full statistics object. Slices memories to top 5, topics to top 10.
|
|
82
|
+
*/
|
|
83
|
+
export function compactReflectResponse(
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- raw API shape
|
|
85
|
+
response, timeWindow) {
|
|
86
|
+
const rawMemories = response?.memories ?? [];
|
|
87
|
+
const topMemories = rawMemories.slice(0, MAX_REFLECT_MEMORIES).map((m) => ({
|
|
88
|
+
content: m.content,
|
|
89
|
+
type: m.memory_type ?? "unknown",
|
|
90
|
+
importance: m.importance,
|
|
91
|
+
score: m.score,
|
|
92
|
+
}));
|
|
93
|
+
const activeTopics = (response?.active_topics ?? []).slice(0, MAX_REFLECT_TOPICS);
|
|
94
|
+
return {
|
|
95
|
+
time_window: timeWindow,
|
|
96
|
+
memories_analyzed: response?.statistics?.total_memories_analyzed ?? 0,
|
|
97
|
+
active_topics: activeTopics,
|
|
98
|
+
top_memories: topMemories,
|
|
99
|
+
patterns: response?.emerging_patterns ?? [],
|
|
100
|
+
insights: response?.relationship_insights ?? [],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Compact a graph traversal response.
|
|
105
|
+
*
|
|
106
|
+
* Enriches nodes/relationships with selective fields from detail lookups.
|
|
107
|
+
*/
|
|
108
|
+
export function compactExploreResponse(
|
|
109
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- raw API shape
|
|
110
|
+
response, startMemoryId) {
|
|
111
|
+
const nodeDetails = response?.node_details ?? {};
|
|
112
|
+
const relDetails = response?.relationship_details ?? {};
|
|
113
|
+
const rawPaths = response?.paths ?? [];
|
|
114
|
+
const paths = rawPaths.map((path) => {
|
|
115
|
+
const rawNodes = path.nodes ?? [];
|
|
116
|
+
const rawRels = path.relationships ?? [];
|
|
117
|
+
const nodes = rawNodes.map((nid) => {
|
|
118
|
+
const detail = nodeDetails[nid];
|
|
119
|
+
if (detail) {
|
|
120
|
+
return {
|
|
121
|
+
id: nid,
|
|
122
|
+
preview: detail.preview,
|
|
123
|
+
type: detail.type,
|
|
124
|
+
tags: detail.tags ?? [],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return { id: nid };
|
|
128
|
+
});
|
|
129
|
+
const relationships = rawRels.map((rid) => {
|
|
130
|
+
const detail = relDetails[rid];
|
|
131
|
+
if (detail) {
|
|
132
|
+
return {
|
|
133
|
+
id: rid,
|
|
134
|
+
type: detail.type,
|
|
135
|
+
strength: detail.strength,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return { id: rid };
|
|
139
|
+
});
|
|
140
|
+
return { nodes, relationships, depth: rawNodes.length - 1 };
|
|
141
|
+
});
|
|
142
|
+
const result = {
|
|
143
|
+
start_memory: startMemoryId,
|
|
144
|
+
paths_found: paths.length,
|
|
145
|
+
max_depth_reached: response?.max_depth_reached ?? 0,
|
|
146
|
+
paths,
|
|
147
|
+
};
|
|
148
|
+
if (paths.length === 0) {
|
|
149
|
+
result.message = "No connections found from this memory";
|
|
150
|
+
}
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PenfieldApiClient } from "../api-client.js";
|
|
2
|
+
export declare const DisconnectToolSchema: import("@sinclair/typebox").TObject<{
|
|
3
|
+
from_memory_id: import("@sinclair/typebox").TString;
|
|
4
|
+
to_memory_id: import("@sinclair/typebox").TString;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function executeDisconnectTool(apiClient: PenfieldApiClient, params: any): Promise<any>;
|
|
7
|
+
//# sourceMappingURL=disconnect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disconnect.d.ts","sourceRoot":"","sources":["../../../src/tools/disconnect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,eAAO,MAAM,oBAAoB;;;EASE,CAAC;AAEpC,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,GAAG,GACV,OAAO,CAAC,GAAG,CAAC,CA4Bd"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Type } from "../types/typebox.js";
|
|
2
|
+
import { validateUuid } from "../validation.js";
|
|
3
|
+
export const DisconnectToolSchema = Type.Object({
|
|
4
|
+
from_memory_id: Type.String({
|
|
5
|
+
description: "Source memory ID (UUID format)",
|
|
6
|
+
examples: ["22618318-8d82-49c9-8bb8-1cf3a61b3c75"],
|
|
7
|
+
}),
|
|
8
|
+
to_memory_id: Type.String({
|
|
9
|
+
description: "Target memory ID (UUID format)",
|
|
10
|
+
examples: ["20413926-2446-4f88-bfd6-749b37969f34"],
|
|
11
|
+
}),
|
|
12
|
+
}, { additionalProperties: false });
|
|
13
|
+
export async function executeDisconnectTool(apiClient, params // eslint-disable-line @typescript-eslint/no-explicit-any -- validated by TypeBox schema
|
|
14
|
+
) {
|
|
15
|
+
validateUuid(params.from_memory_id, 'from_memory_id');
|
|
16
|
+
validateUuid(params.to_memory_id, 'to_memory_id');
|
|
17
|
+
// Map user-friendly field names to API field names
|
|
18
|
+
const queryParams = {
|
|
19
|
+
from_id: params.from_memory_id,
|
|
20
|
+
to_id: params.to_memory_id,
|
|
21
|
+
};
|
|
22
|
+
await apiClient.delete("/api/v2/relationships/between", queryParams);
|
|
23
|
+
const result = {
|
|
24
|
+
success: true,
|
|
25
|
+
from_id: params.from_memory_id,
|
|
26
|
+
to_id: params.to_memory_id,
|
|
27
|
+
message: "Relationship removed",
|
|
28
|
+
};
|
|
29
|
+
return {
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: "text",
|
|
33
|
+
text: JSON.stringify(result, null, 2),
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
details: result,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explore.d.ts","sourceRoot":"","sources":["../../../src/tools/explore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"explore.d.ts","sourceRoot":"","sources":["../../../src/tools/explore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAI1D,eAAO,MAAM,iBAAiB;;;;;EAwBK,CAAC;AAEpC,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,GAAG,CAAC,CAgBd"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Type, RelationshipTypeSchema } from "../types/typebox.js";
|
|
2
2
|
import { validateUuid } from "../validation.js";
|
|
3
|
+
import { compactExploreResponse } from "../response-compact.js";
|
|
3
4
|
export const ExploreToolSchema = Type.Object({
|
|
4
5
|
start_memory_id: Type.String({
|
|
5
6
|
description: "Starting memory ID for graph traversal (UUID format)",
|
|
@@ -23,11 +24,12 @@ export async function executeExploreTool(apiClient, params) {
|
|
|
23
24
|
const { start_memory_id } = params;
|
|
24
25
|
validateUuid(start_memory_id, 'start_memory_id');
|
|
25
26
|
const response = await apiClient.post("/api/v2/relationships/traverse", params);
|
|
27
|
+
const compact = compactExploreResponse(response, start_memory_id);
|
|
26
28
|
return {
|
|
27
29
|
content: [
|
|
28
30
|
{
|
|
29
31
|
type: "text",
|
|
30
|
-
text: JSON.stringify(
|
|
32
|
+
text: JSON.stringify(compact, null, 2),
|
|
31
33
|
},
|
|
32
34
|
],
|
|
33
35
|
details: response,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA8BrD,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,iBAAiB,EACtB,aAAa,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,QAwK9C"}
|
package/dist/src/tools/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { SearchToolSchema, executeSearchTool } from "./search.js";
|
|
|
4
4
|
import { FetchToolSchema, executeFetchTool } from "./fetch.js";
|
|
5
5
|
import { UpdateMemoryToolSchema, executeUpdateMemoryTool } from "./update-memory.js";
|
|
6
6
|
import { ConnectToolSchema, executeConnectTool } from "./connect.js";
|
|
7
|
+
import { DisconnectToolSchema, executeDisconnectTool } from "./disconnect.js";
|
|
7
8
|
import { ExploreToolSchema, executeExploreTool } from "./explore.js";
|
|
8
9
|
import { SaveContextToolSchema, executeSaveContextTool } from "./save-context.js";
|
|
9
10
|
import { RestoreContextToolSchema, executeRestoreContextTool, } from "./restore-context.js";
|
|
@@ -38,13 +39,14 @@ export function registerPenfieldTools(api, ensureRuntime) {
|
|
|
38
39
|
},
|
|
39
40
|
});
|
|
40
41
|
};
|
|
41
|
-
// Register all
|
|
42
|
+
// Register all 17 tools
|
|
42
43
|
registerTool("penfield_store", "Store Memory", "Store a new memory in Penfield", StoreToolSchema, executeStoreTool);
|
|
43
44
|
registerTool("penfield_recall", "Recall Memories", "Search memories using hybrid BM25 + vector + graph search", RecallToolSchema, executeRecallTool);
|
|
44
45
|
registerTool("penfield_search", "Search Memories", "Semantic search for memories", SearchToolSchema, executeSearchTool);
|
|
45
46
|
registerTool("penfield_fetch", "Fetch Memory", "Get a specific memory by ID", FetchToolSchema, executeFetchTool);
|
|
46
47
|
registerTool("penfield_update_memory", "Update Memory", "Update an existing memory", UpdateMemoryToolSchema, executeUpdateMemoryTool);
|
|
47
48
|
registerTool("penfield_connect", "Connect Memories", "Create a relationship between two memories", ConnectToolSchema, executeConnectTool);
|
|
49
|
+
registerTool("penfield_disconnect", "Disconnect Memories", "Remove a relationship between two memories", DisconnectToolSchema, executeDisconnectTool);
|
|
48
50
|
registerTool("penfield_explore", "Explore Graph", "Traverse the knowledge graph from a starting memory", ExploreToolSchema, executeExploreTool);
|
|
49
51
|
registerTool("penfield_save_context", "Save Context", "Save a cognitive state checkpoint with name and description for handoff to another agent or future session", SaveContextToolSchema, executeSaveContextTool);
|
|
50
52
|
registerTool("penfield_restore_context", "Restore Context", "Restore a previously saved context checkpoint by name, UUID, or 'awakening' for personality briefing", RestoreContextToolSchema, executeRestoreContextTool);
|
|
@@ -8,6 +8,10 @@ export declare const RecallToolSchema: import("@sinclair/typebox").TObject<{
|
|
|
8
8
|
memory_types: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"fact">, import("@sinclair/typebox").TLiteral<"insight">, import("@sinclair/typebox").TLiteral<"conversation">, import("@sinclair/typebox").TLiteral<"correction">, import("@sinclair/typebox").TLiteral<"reference">, import("@sinclair/typebox").TLiteral<"task">, import("@sinclair/typebox").TLiteral<"checkpoint">, import("@sinclair/typebox").TLiteral<"identity_core">, import("@sinclair/typebox").TLiteral<"personality_trait">, import("@sinclair/typebox").TLiteral<"relationship">, import("@sinclair/typebox").TLiteral<"strategy">]>>>;
|
|
9
9
|
importance_threshold: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
10
10
|
enable_graph_expansion: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
11
|
+
start_date: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
12
|
+
end_date: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
13
|
+
sort: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"relevance">, import("@sinclair/typebox").TLiteral<"created_desc">, import("@sinclair/typebox").TLiteral<"created_asc">]>>;
|
|
14
|
+
max_content_length: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
11
15
|
}>;
|
|
12
16
|
export declare function executeRecallTool(apiClient: PenfieldApiClient, params: any): Promise<any>;
|
|
13
17
|
//# sourceMappingURL=recall.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../../src/tools/recall.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../../src/tools/recall.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;EA2DM,CAAC;AAEpC,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,GAAG,GACV,OAAO,CAAC,GAAG,CAAC,CA6Bd"}
|
package/dist/src/tools/recall.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Type, MemoryTypeSchema, ImportanceScoreSchema } from "../types/typebox.js";
|
|
1
|
+
import { Type, MemoryTypeSchema, ImportanceScoreSchema, StartDateSchema, EndDateSchema, SortOrderSchema, MaxContentLengthSchema } from "../types/typebox.js";
|
|
2
|
+
import { compactRecallResponse } from "../response-compact.js";
|
|
2
3
|
export const RecallToolSchema = Type.Object({
|
|
3
4
|
query: Type.String({
|
|
4
5
|
description: "Search query (1-4,000 chars)",
|
|
@@ -40,6 +41,10 @@ export const RecallToolSchema = Type.Object({
|
|
|
40
41
|
description: "Enable graph traversal (default: true)",
|
|
41
42
|
default: true,
|
|
42
43
|
})),
|
|
44
|
+
start_date: Type.Optional(StartDateSchema),
|
|
45
|
+
end_date: Type.Optional(EndDateSchema),
|
|
46
|
+
sort: Type.Optional(SortOrderSchema),
|
|
47
|
+
max_content_length: Type.Optional(MaxContentLengthSchema),
|
|
43
48
|
}, { additionalProperties: false });
|
|
44
49
|
export async function executeRecallTool(apiClient, params // eslint-disable-line @typescript-eslint/no-explicit-any -- validated by TypeBox schema
|
|
45
50
|
) {
|
|
@@ -51,12 +56,18 @@ export async function executeRecallTool(apiClient, params // eslint-disable-line
|
|
|
51
56
|
if (Math.abs(sum - 1.0) > 0.01) {
|
|
52
57
|
throw new Error(`Weights must sum to 1.0 (got ${sum})`);
|
|
53
58
|
}
|
|
54
|
-
|
|
59
|
+
// Separate plugin-only params from API params
|
|
60
|
+
const { sort, max_content_length, ...apiParams } = params;
|
|
61
|
+
const response = await apiClient.post("/api/v2/search/hybrid", apiParams);
|
|
62
|
+
const compact = compactRecallResponse(response, params.query, {
|
|
63
|
+
sort,
|
|
64
|
+
maxContentLength: max_content_length,
|
|
65
|
+
});
|
|
55
66
|
return {
|
|
56
67
|
content: [
|
|
57
68
|
{
|
|
58
69
|
type: "text",
|
|
59
|
-
text: JSON.stringify(
|
|
70
|
+
text: JSON.stringify(compact, null, 2),
|
|
60
71
|
},
|
|
61
72
|
],
|
|
62
73
|
details: response,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reflect.d.ts","sourceRoot":"","sources":["../../../src/tools/reflect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"reflect.d.ts","sourceRoot":"","sources":["../../../src/tools/reflect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,eAAO,MAAM,iBAAiB;;;;;EAwCK,CAAC;AASpC,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,GAAG,CAAC,CA8Bd"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "../types/typebox.js";
|
|
2
|
+
import { compactReflectResponse } from "../response-compact.js";
|
|
2
3
|
export const ReflectToolSchema = Type.Object({
|
|
3
4
|
time_window: Type.Optional(Type.Union([
|
|
4
5
|
Type.Literal("recent"),
|
|
@@ -34,6 +35,7 @@ const TIME_WINDOW_ALIASES = {
|
|
|
34
35
|
export async function executeReflectTool(apiClient, params) {
|
|
35
36
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- params validated by schema
|
|
36
37
|
const p = { ...params };
|
|
38
|
+
const originalTimeWindow = p.time_window ?? "recent";
|
|
37
39
|
if (p.time_window === "90d") {
|
|
38
40
|
// API has no 90d window — convert to explicit date range (matches MCP behavior)
|
|
39
41
|
if (!p.start_date) {
|
|
@@ -47,11 +49,12 @@ export async function executeReflectTool(apiClient, params) {
|
|
|
47
49
|
p.time_window = TIME_WINDOW_ALIASES[p.time_window];
|
|
48
50
|
}
|
|
49
51
|
const response = await apiClient.post("/api/v2/analysis/reflect", p);
|
|
52
|
+
const compact = compactReflectResponse(response, originalTimeWindow);
|
|
50
53
|
return {
|
|
51
54
|
content: [
|
|
52
55
|
{
|
|
53
56
|
type: "text",
|
|
54
|
-
text: JSON.stringify(
|
|
57
|
+
text: JSON.stringify(compact, null, 2),
|
|
55
58
|
},
|
|
56
59
|
],
|
|
57
60
|
details: response,
|
|
@@ -4,6 +4,10 @@ export declare const SearchToolSchema: import("@sinclair/typebox").TObject<{
|
|
|
4
4
|
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
5
5
|
memory_types: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"fact">, import("@sinclair/typebox").TLiteral<"insight">, import("@sinclair/typebox").TLiteral<"conversation">, import("@sinclair/typebox").TLiteral<"correction">, import("@sinclair/typebox").TLiteral<"reference">, import("@sinclair/typebox").TLiteral<"task">, import("@sinclair/typebox").TLiteral<"checkpoint">, import("@sinclair/typebox").TLiteral<"identity_core">, import("@sinclair/typebox").TLiteral<"personality_trait">, import("@sinclair/typebox").TLiteral<"relationship">, import("@sinclair/typebox").TLiteral<"strategy">]>>>;
|
|
6
6
|
importance_threshold: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
7
|
+
start_date: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
8
|
+
end_date: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
9
|
+
sort: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"relevance">, import("@sinclair/typebox").TLiteral<"created_desc">, import("@sinclair/typebox").TLiteral<"created_asc">]>>;
|
|
10
|
+
max_content_length: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
7
11
|
}>;
|
|
8
12
|
export declare function executeSearchTool(apiClient: PenfieldApiClient, params: any): Promise<any>;
|
|
9
13
|
//# sourceMappingURL=search.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/tools/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/tools/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,eAAO,MAAM,gBAAgB;;;;;;;;;EA6BM,CAAC;AAEpC,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,GAAG,GACV,OAAO,CAAC,GAAG,CAAC,CA2Bd"}
|
package/dist/src/tools/search.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Type, MemoryTypeSchema, ImportanceScoreSchema } from "../types/typebox.js";
|
|
1
|
+
import { Type, MemoryTypeSchema, ImportanceScoreSchema, StartDateSchema, EndDateSchema, SortOrderSchema, MaxContentLengthSchema } from "../types/typebox.js";
|
|
2
|
+
import { compactRecallResponse } from "../response-compact.js";
|
|
2
3
|
export const SearchToolSchema = Type.Object({
|
|
3
4
|
query: Type.String({
|
|
4
5
|
description: "Search query (1-4,000 chars)",
|
|
@@ -18,22 +19,32 @@ export const SearchToolSchema = Type.Object({
|
|
|
18
19
|
...ImportanceScoreSchema,
|
|
19
20
|
description: "Minimum importance (0-1)",
|
|
20
21
|
})),
|
|
22
|
+
start_date: Type.Optional(StartDateSchema),
|
|
23
|
+
end_date: Type.Optional(EndDateSchema),
|
|
24
|
+
sort: Type.Optional(SortOrderSchema),
|
|
25
|
+
max_content_length: Type.Optional(MaxContentLengthSchema),
|
|
21
26
|
}, { additionalProperties: false });
|
|
22
27
|
export async function executeSearchTool(apiClient, params // eslint-disable-line @typescript-eslint/no-explicit-any -- validated by TypeBox schema
|
|
23
28
|
) {
|
|
29
|
+
// Separate plugin-only params from API params
|
|
30
|
+
const { sort, max_content_length, ...userParams } = params;
|
|
24
31
|
// Search is a variant of hybrid search with higher vector weight
|
|
25
32
|
const searchParams = {
|
|
26
|
-
...
|
|
33
|
+
...userParams,
|
|
27
34
|
vector_weight: 0.6,
|
|
28
35
|
bm25_weight: 0.3,
|
|
29
36
|
graph_weight: 0.1,
|
|
30
37
|
};
|
|
31
38
|
const response = await apiClient.post("/api/v2/search/hybrid", searchParams);
|
|
39
|
+
const compact = compactRecallResponse(response, params.query, {
|
|
40
|
+
sort,
|
|
41
|
+
maxContentLength: max_content_length,
|
|
42
|
+
});
|
|
32
43
|
return {
|
|
33
44
|
content: [
|
|
34
45
|
{
|
|
35
46
|
type: "text",
|
|
36
|
-
text: JSON.stringify(
|
|
47
|
+
text: JSON.stringify(compact, null, 2),
|
|
37
48
|
},
|
|
38
49
|
],
|
|
39
50
|
details: response,
|
|
@@ -15,5 +15,9 @@ export declare const ImportanceScoreSchema: import("@sinclair/typebox").TNumber;
|
|
|
15
15
|
export declare const ConfidenceScoreSchema: import("@sinclair/typebox").TNumber;
|
|
16
16
|
export declare const TagsSchema: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
17
17
|
export declare const MemoryTypeSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"fact">, import("@sinclair/typebox").TLiteral<"insight">, import("@sinclair/typebox").TLiteral<"conversation">, import("@sinclair/typebox").TLiteral<"correction">, import("@sinclair/typebox").TLiteral<"reference">, import("@sinclair/typebox").TLiteral<"task">, import("@sinclair/typebox").TLiteral<"checkpoint">, import("@sinclair/typebox").TLiteral<"identity_core">, import("@sinclair/typebox").TLiteral<"personality_trait">, import("@sinclair/typebox").TLiteral<"relationship">, import("@sinclair/typebox").TLiteral<"strategy">]>;
|
|
18
|
+
export declare const StartDateSchema: import("@sinclair/typebox").TString;
|
|
19
|
+
export declare const EndDateSchema: import("@sinclair/typebox").TString;
|
|
20
|
+
export declare const SortOrderSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"relevance">, import("@sinclair/typebox").TLiteral<"created_desc">, import("@sinclair/typebox").TLiteral<"created_asc">]>;
|
|
21
|
+
export declare const MaxContentLengthSchema: import("@sinclair/typebox").TNumber;
|
|
18
22
|
export declare const RelationshipTypeSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"supersedes">, import("@sinclair/typebox").TLiteral<"updates">, import("@sinclair/typebox").TLiteral<"evolution_of">, import("@sinclair/typebox").TLiteral<"supports">, import("@sinclair/typebox").TLiteral<"contradicts">, import("@sinclair/typebox").TLiteral<"disputes">, import("@sinclair/typebox").TLiteral<"parent_of">, import("@sinclair/typebox").TLiteral<"child_of">, import("@sinclair/typebox").TLiteral<"sibling_of">, import("@sinclair/typebox").TLiteral<"causes">, import("@sinclair/typebox").TLiteral<"influenced_by">, import("@sinclair/typebox").TLiteral<"prerequisite_for">, import("@sinclair/typebox").TLiteral<"implements">, import("@sinclair/typebox").TLiteral<"documents">, import("@sinclair/typebox").TLiteral<"example_of">, import("@sinclair/typebox").TLiteral<"tests">, import("@sinclair/typebox").TLiteral<"responds_to">, import("@sinclair/typebox").TLiteral<"references">, import("@sinclair/typebox").TLiteral<"inspired_by">, import("@sinclair/typebox").TLiteral<"follows">, import("@sinclair/typebox").TLiteral<"precedes">, import("@sinclair/typebox").TLiteral<"depends_on">, import("@sinclair/typebox").TLiteral<"composed_of">, import("@sinclair/typebox").TLiteral<"part_of">]>;
|
|
19
23
|
//# sourceMappingURL=typebox.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typebox.d.ts","sourceRoot":"","sources":["../../../src/types/typebox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;AAG9B,eAAO,MAAM,UAAU,qCAGrB,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;EAY3B,CAAC;AAEH,eAAO,MAAM,qBAAqB,qCAIhC,CAAC;AAEH,eAAO,MAAM,qBAAqB,qCAIhC,CAAC;AAEH,eAAO,MAAM,UAAU,yEAGrB,CAAC;AAEH,eAAO,MAAM,gBAAgB,8lBAYQ,CAAC;
|
|
1
|
+
{"version":3,"file":"typebox.d.ts","sourceRoot":"","sources":["../../../src/types/typebox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;AAG9B,eAAO,MAAM,UAAU,qCAGrB,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;EAY3B,CAAC;AAEH,eAAO,MAAM,qBAAqB,qCAIhC,CAAC;AAEH,eAAO,MAAM,qBAAqB,qCAIhC,CAAC;AAEH,eAAO,MAAM,UAAU,yEAGrB,CAAC;AAEH,eAAO,MAAM,gBAAgB,8lBAYQ,CAAC;AAGtC,eAAO,MAAM,eAAe,qCAE1B,CAAC;AAEH,eAAO,MAAM,aAAa,qCAExB,CAAC;AAEH,eAAO,MAAM,eAAe,oMAU3B,CAAC;AAEF,eAAO,MAAM,sBAAsB,qCAIjC,CAAC;AAEH,eAAO,MAAM,sBAAsB,yvCAoCjC,CAAC"}
|
|
@@ -52,6 +52,26 @@ export const MemoryTypeSchema = Type.Union([
|
|
|
52
52
|
Type.Literal("relationship"),
|
|
53
53
|
Type.Literal("strategy"),
|
|
54
54
|
], { description: "Type of memory" });
|
|
55
|
+
// Shared search parameter schemas (used by recall + search)
|
|
56
|
+
export const StartDateSchema = Type.String({
|
|
57
|
+
description: "Filter memories created on or after this date (ISO 8601, e.g. '2025-01-01')",
|
|
58
|
+
});
|
|
59
|
+
export const EndDateSchema = Type.String({
|
|
60
|
+
description: "Filter memories created on or before this date (ISO 8601, e.g. '2025-12-31')",
|
|
61
|
+
});
|
|
62
|
+
export const SortOrderSchema = Type.Union([
|
|
63
|
+
Type.Literal("relevance"),
|
|
64
|
+
Type.Literal("created_desc"),
|
|
65
|
+
Type.Literal("created_asc"),
|
|
66
|
+
], {
|
|
67
|
+
description: 'Sort order: "relevance" (default), "created_desc", or "created_asc"',
|
|
68
|
+
default: "relevance",
|
|
69
|
+
});
|
|
70
|
+
export const MaxContentLengthSchema = Type.Number({
|
|
71
|
+
description: "Truncate memory content to this many characters. Full content available via penfield_fetch.",
|
|
72
|
+
minimum: 50,
|
|
73
|
+
maximum: 10000,
|
|
74
|
+
});
|
|
55
75
|
export const RelationshipTypeSchema = Type.Union([
|
|
56
76
|
// Knowledge Evolution
|
|
57
77
|
Type.Literal("supersedes"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-penfield",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Native OpenClaw plugin for Penfield memory integration",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"memory",
|
|
16
16
|
"knowledge-graph"
|
|
17
17
|
],
|
|
18
|
-
"author": "
|
|
18
|
+
"author": "Penfield",
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|