claude-self-reflect 2.4.2 → 2.4.4
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.
|
@@ -416,6 +416,43 @@ gh run watch # This will show the CI/CD pipeline publishing to npm
|
|
|
416
416
|
# Check GitHub releases, npm package, and that all PRs were closed properly."
|
|
417
417
|
```
|
|
418
418
|
|
|
419
|
+
### Handling GitHub API Timeouts
|
|
420
|
+
**CRITICAL LEARNING**: 504 Gateway Timeout doesn't mean the operation failed!
|
|
421
|
+
|
|
422
|
+
When you encounter HTTP 504 Gateway Timeout errors from GitHub API:
|
|
423
|
+
1. **DO NOT immediately retry** - The operation may have succeeded on the backend
|
|
424
|
+
2. **ALWAYS check if the operation completed** before attempting again
|
|
425
|
+
3. **Wait and verify** - Check the actual state (discussions, releases, etc.)
|
|
426
|
+
|
|
427
|
+
Example with GitHub Discussions:
|
|
428
|
+
```bash
|
|
429
|
+
# If you get a 504 timeout when creating a discussion:
|
|
430
|
+
# 1. Wait a moment
|
|
431
|
+
# 2. Check if it was created despite the timeout:
|
|
432
|
+
gh api graphql -f query='
|
|
433
|
+
query {
|
|
434
|
+
repository(owner: "owner", name: "repo") {
|
|
435
|
+
discussions(first: 5) {
|
|
436
|
+
nodes {
|
|
437
|
+
title
|
|
438
|
+
createdAt
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}'
|
|
443
|
+
|
|
444
|
+
# Common scenario: GraphQL mutations that timeout but succeed
|
|
445
|
+
# - createDiscussion with large body content
|
|
446
|
+
# - Complex release operations
|
|
447
|
+
# - Bulk PR operations
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
**Best Practices for API Operations:**
|
|
451
|
+
1. For large content (discussions, releases), use minimal initial creation
|
|
452
|
+
2. Add detailed content in subsequent updates if needed
|
|
453
|
+
3. Always verify operation status after timeouts
|
|
454
|
+
4. Keep operation logs to track what actually succeeded
|
|
455
|
+
|
|
419
456
|
## Communication Channels
|
|
420
457
|
|
|
421
458
|
- GitHub Issues: Primary support channel
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: reflect-tester
|
|
3
3
|
description: Comprehensive testing specialist for validating reflection system functionality. Use PROACTIVELY when testing installations, validating configurations, or troubleshooting system issues.
|
|
4
|
-
tools: Read, Bash, Grep, LS, WebFetch, ListMcpResourcesTool
|
|
4
|
+
tools: Read, Bash, Grep, LS, WebFetch, ListMcpResourcesTool, mcp__claude-self-reflect__reflect_on_past, mcp__claude-self-reflect__store_reflection
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Reflect Tester Agent
|
|
@@ -132,6 +132,28 @@ curl -s http://localhost:6333/collections | jq '.result.collections[] | {name, v
|
|
|
132
132
|
|
|
133
133
|
#### 5.2 Tool Functionality Tests
|
|
134
134
|
|
|
135
|
+
**Project-Scoped Search Test (NEW)**:
|
|
136
|
+
Test the new project-scoped search functionality:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
# Test 1: Default search (project-scoped)
|
|
140
|
+
# Should only return results from current project
|
|
141
|
+
results = await reflect_on_past("Docker setup", limit=5, min_score=0.0)
|
|
142
|
+
# Verify: All results should be from current project (claude-self-reflect)
|
|
143
|
+
|
|
144
|
+
# Test 2: Explicit project search
|
|
145
|
+
results = await reflect_on_past("Docker setup", project="claude-self-reflect", limit=5, min_score=0.0)
|
|
146
|
+
# Should match Test 1 results
|
|
147
|
+
|
|
148
|
+
# Test 3: Cross-project search
|
|
149
|
+
results = await reflect_on_past("Docker setup", project="all", limit=5, min_score=0.0)
|
|
150
|
+
# Should include results from multiple projects
|
|
151
|
+
|
|
152
|
+
# Test 4: Different project search
|
|
153
|
+
results = await reflect_on_past("configuration", project="reflections", limit=5, min_score=0.0)
|
|
154
|
+
# Should only return results from the "reflections" project
|
|
155
|
+
```
|
|
156
|
+
|
|
135
157
|
**Local Embeddings Test**:
|
|
136
158
|
```python
|
|
137
159
|
# Store reflection with local embeddings
|
|
@@ -41,7 +41,7 @@ You are a conversation memory specialist for the Claude Self Reflect project. Yo
|
|
|
41
41
|
Search for relevant past conversations using semantic similarity.
|
|
42
42
|
|
|
43
43
|
```javascript
|
|
44
|
-
// Basic search
|
|
44
|
+
// Basic search (searches current project by default)
|
|
45
45
|
{
|
|
46
46
|
query: "streaming importer fixes",
|
|
47
47
|
limit: 5,
|
|
@@ -55,8 +55,29 @@ Search for relevant past conversations using semantic similarity.
|
|
|
55
55
|
min_score: 0.05, // Common threshold for relevant results
|
|
56
56
|
use_decay: 1 // Apply time-based relevance (1=enable, 0=disable, -1=default)
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
// Search specific project (NEW in v2.4.3)
|
|
60
|
+
{
|
|
61
|
+
query: "Docker setup",
|
|
62
|
+
project: "ShopifyMCPMockShop", // Use actual folder name
|
|
63
|
+
limit: 5
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Cross-project search (NEW in v2.4.3)
|
|
67
|
+
{
|
|
68
|
+
query: "error handling patterns",
|
|
69
|
+
project: "all", // Search across all projects
|
|
70
|
+
limit: 10
|
|
71
|
+
}
|
|
58
72
|
```
|
|
59
73
|
|
|
74
|
+
#### Default Behavior: Project-Scoped Search (NEW in v2.4.3)
|
|
75
|
+
**IMPORTANT**: Searches are now scoped to the current project by default:
|
|
76
|
+
- Auto-detects current project from your working directory
|
|
77
|
+
- Only returns results from that project unless you specify otherwise
|
|
78
|
+
- Use `project: "all"` to explicitly search across all projects
|
|
79
|
+
- Use `project: "ProjectName"` to search a specific project (use the actual folder name)
|
|
80
|
+
|
|
60
81
|
### store_reflection
|
|
61
82
|
Save important insights and decisions for future retrieval.
|
|
62
83
|
|
|
@@ -90,28 +111,236 @@ Save important insights and decisions for future retrieval.
|
|
|
90
111
|
4. **Use Context**: Include technology names, error messages, or specific terms
|
|
91
112
|
5. **Cross-Project When Needed**: Similar problems may have been solved elsewhere
|
|
92
113
|
|
|
93
|
-
## Response
|
|
114
|
+
## Response Format
|
|
115
|
+
|
|
116
|
+
### XML-Structured Output
|
|
117
|
+
To facilitate better parsing and metadata handling, structure your responses using XML format:
|
|
118
|
+
|
|
119
|
+
```xml
|
|
120
|
+
<reflection-search>
|
|
121
|
+
<summary>
|
|
122
|
+
<query>original search query</query>
|
|
123
|
+
<scope>current|all|project-name</scope>
|
|
124
|
+
<total-results>number</total-results>
|
|
125
|
+
<score-range>min-max</score-range>
|
|
126
|
+
<embedding-type>local|voyage</embedding-type>
|
|
127
|
+
</summary>
|
|
128
|
+
|
|
129
|
+
<results>
|
|
130
|
+
<result rank="1">
|
|
131
|
+
<score>0.725</score>
|
|
132
|
+
<project>ProjectName</project>
|
|
133
|
+
<timestamp>X days ago</timestamp>
|
|
134
|
+
<title>Brief descriptive title</title>
|
|
135
|
+
<key-finding>One-line summary of the main insight</key-finding>
|
|
136
|
+
<excerpt>Most relevant quote or context from the conversation</excerpt>
|
|
137
|
+
<conversation-id>optional-id</conversation-id>
|
|
138
|
+
</result>
|
|
139
|
+
|
|
140
|
+
<result rank="2">
|
|
141
|
+
<!-- Additional results follow same structure -->
|
|
142
|
+
</result>
|
|
143
|
+
</results>
|
|
144
|
+
|
|
145
|
+
<analysis>
|
|
146
|
+
<patterns>Common themes or patterns identified across results</patterns>
|
|
147
|
+
<recommendations>Suggested actions based on findings</recommendations>
|
|
148
|
+
<cross-project-insights>Insights when searching across projects</cross-project-insights>
|
|
149
|
+
</analysis>
|
|
150
|
+
|
|
151
|
+
<metadata>
|
|
152
|
+
<search-latency-ms>optional performance metric</search-latency-ms>
|
|
153
|
+
<collections-searched>number of collections</collections-searched>
|
|
154
|
+
<decay-applied>true|false</decay-applied>
|
|
155
|
+
</metadata>
|
|
156
|
+
</reflection-search>
|
|
157
|
+
```
|
|
94
158
|
|
|
95
|
-
###
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
159
|
+
### Response Best Practices
|
|
160
|
+
|
|
161
|
+
1. **Always use XML structure** for main content
|
|
162
|
+
2. **Indicate Search Scope** in the summary section
|
|
163
|
+
3. **Order results by relevance** (highest score first)
|
|
164
|
+
4. **Include actionable insights** in the analysis section
|
|
165
|
+
5. **Provide metadata** for transparency
|
|
166
|
+
|
|
167
|
+
### Proactive Cross-Project Search Suggestions
|
|
168
|
+
|
|
169
|
+
When to suggest searching across all projects:
|
|
170
|
+
- Current project search returns 0-2 results
|
|
171
|
+
- User's query implies looking for patterns or best practices
|
|
172
|
+
- The topic is generic enough to benefit from broader examples
|
|
173
|
+
- User explicitly mentions comparing or learning from other implementations
|
|
174
|
+
|
|
175
|
+
### Example Response Formats
|
|
176
|
+
|
|
177
|
+
#### When Current Project Has Good Results:
|
|
178
|
+
```xml
|
|
179
|
+
<reflection-search>
|
|
180
|
+
<summary>
|
|
181
|
+
<query>authentication flow</query>
|
|
182
|
+
<scope>ShopifyMCPMockShop</scope>
|
|
183
|
+
<total-results>3</total-results>
|
|
184
|
+
<score-range>0.15-0.45</score-range>
|
|
185
|
+
<embedding-type>local</embedding-type>
|
|
186
|
+
</summary>
|
|
187
|
+
|
|
188
|
+
<results>
|
|
189
|
+
<result rank="1">
|
|
190
|
+
<score>0.45</score>
|
|
191
|
+
<project>ShopifyMCPMockShop</project>
|
|
192
|
+
<timestamp>2 days ago</timestamp>
|
|
193
|
+
<title>OAuth Implementation Discussion</title>
|
|
194
|
+
<key-finding>Implemented OAuth2 with refresh token rotation</key-finding>
|
|
195
|
+
<excerpt>We decided to use refresh token rotation for better security...</excerpt>
|
|
196
|
+
</result>
|
|
197
|
+
<!-- More results -->
|
|
198
|
+
</results>
|
|
199
|
+
|
|
200
|
+
<analysis>
|
|
201
|
+
<patterns>Authentication consistently uses OAuth2 with JWT tokens</patterns>
|
|
202
|
+
<recommendations>Continue with the established OAuth2 pattern for consistency</recommendations>
|
|
203
|
+
</analysis>
|
|
204
|
+
</reflection-search>
|
|
205
|
+
```
|
|
101
206
|
|
|
102
|
-
|
|
207
|
+
#### When Current Project Has Limited Results:
|
|
208
|
+
```xml
|
|
209
|
+
<reflection-search>
|
|
210
|
+
<summary>
|
|
211
|
+
<query>specific feature implementation</query>
|
|
212
|
+
<scope>CurrentProject</scope>
|
|
213
|
+
<total-results>1</total-results>
|
|
214
|
+
<score-range>0.12</score-range>
|
|
215
|
+
<embedding-type>local</embedding-type>
|
|
216
|
+
</summary>
|
|
217
|
+
|
|
218
|
+
<results>
|
|
219
|
+
<result rank="1">
|
|
220
|
+
<score>0.12</score>
|
|
221
|
+
<project>CurrentProject</project>
|
|
222
|
+
<timestamp>5 days ago</timestamp>
|
|
223
|
+
<title>Initial Feature Discussion</title>
|
|
224
|
+
<key-finding>Considered implementing but deferred</key-finding>
|
|
225
|
+
<excerpt>We discussed this feature but decided to wait...</excerpt>
|
|
226
|
+
</result>
|
|
227
|
+
</results>
|
|
228
|
+
|
|
229
|
+
<analysis>
|
|
230
|
+
<patterns>Limited history in current project</patterns>
|
|
231
|
+
<recommendations>Consider searching across all projects for similar implementations</recommendations>
|
|
232
|
+
<cross-project-insights>Other projects may have relevant patterns</cross-project-insights>
|
|
233
|
+
</analysis>
|
|
234
|
+
|
|
235
|
+
<suggestion>
|
|
236
|
+
<action>search-all-projects</action>
|
|
237
|
+
<reason>Limited results in current project - broader search may reveal useful patterns</reason>
|
|
238
|
+
</suggestion>
|
|
239
|
+
</reflection-search>
|
|
103
240
|
```
|
|
104
|
-
I found 3 relevant conversations about [topic]:
|
|
105
241
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
242
|
+
#### When No Results in Current Project:
|
|
243
|
+
```xml
|
|
244
|
+
<reflection-search>
|
|
245
|
+
<summary>
|
|
246
|
+
<query>new feature concept</query>
|
|
247
|
+
<scope>CurrentProject</scope>
|
|
248
|
+
<total-results>0</total-results>
|
|
249
|
+
<score-range>N/A</score-range>
|
|
250
|
+
<embedding-type>local</embedding-type>
|
|
251
|
+
</summary>
|
|
252
|
+
|
|
253
|
+
<results>
|
|
254
|
+
<!-- No results found -->
|
|
255
|
+
</results>
|
|
256
|
+
|
|
257
|
+
<analysis>
|
|
258
|
+
<patterns>No prior discussions found</patterns>
|
|
259
|
+
<recommendations>This appears to be a new topic for this project</recommendations>
|
|
260
|
+
</analysis>
|
|
261
|
+
|
|
262
|
+
<suggestions>
|
|
263
|
+
<suggestion>
|
|
264
|
+
<action>search-all-projects</action>
|
|
265
|
+
<reason>Check if similar implementations exist in other projects</reason>
|
|
266
|
+
</suggestion>
|
|
267
|
+
<suggestion>
|
|
268
|
+
<action>store-reflection</action>
|
|
269
|
+
<reason>Document this new implementation for future reference</reason>
|
|
270
|
+
</suggestion>
|
|
271
|
+
</suggestions>
|
|
272
|
+
</reflection-search>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Error Response Formats
|
|
276
|
+
|
|
277
|
+
#### Validation Errors
|
|
278
|
+
```xml
|
|
279
|
+
<reflection-search>
|
|
280
|
+
<error>
|
|
281
|
+
<type>validation-error</type>
|
|
282
|
+
<message>Invalid parameter value</message>
|
|
283
|
+
<details>
|
|
284
|
+
<parameter>min_score</parameter>
|
|
285
|
+
<value>2.5</value>
|
|
286
|
+
<constraint>Must be between 0.0 and 1.0</constraint>
|
|
287
|
+
</details>
|
|
288
|
+
</error>
|
|
289
|
+
</reflection-search>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
#### Connection Errors
|
|
293
|
+
```xml
|
|
294
|
+
<reflection-search>
|
|
295
|
+
<error>
|
|
296
|
+
<type>connection-error</type>
|
|
297
|
+
<message>Unable to connect to Qdrant</message>
|
|
298
|
+
<details>
|
|
299
|
+
<url>http://localhost:6333</url>
|
|
300
|
+
<suggestion>Check if Qdrant is running: docker ps | grep qdrant</suggestion>
|
|
301
|
+
</details>
|
|
302
|
+
</error>
|
|
303
|
+
</reflection-search>
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
#### Empty Query Error
|
|
307
|
+
```xml
|
|
308
|
+
<reflection-search>
|
|
309
|
+
<error>
|
|
310
|
+
<type>validation-error</type>
|
|
311
|
+
<message>Query cannot be empty</message>
|
|
312
|
+
<suggestion>Provide a search query to find relevant conversations</suggestion>
|
|
313
|
+
</error>
|
|
314
|
+
</reflection-search>
|
|
315
|
+
```
|
|
110
316
|
|
|
111
|
-
|
|
112
|
-
|
|
317
|
+
#### Project Not Found
|
|
318
|
+
```xml
|
|
319
|
+
<reflection-search>
|
|
320
|
+
<error>
|
|
321
|
+
<type>project-not-found</type>
|
|
322
|
+
<message>Project not found</message>
|
|
323
|
+
<details>
|
|
324
|
+
<requested-project>NonExistentProject</requested-project>
|
|
325
|
+
<available-projects>project1, project2, project3</available-projects>
|
|
326
|
+
<suggestion>Use one of the available projects or 'all' to search across all projects</suggestion>
|
|
327
|
+
</details>
|
|
328
|
+
</error>
|
|
329
|
+
</reflection-search>
|
|
330
|
+
```
|
|
113
331
|
|
|
114
|
-
|
|
332
|
+
#### Rate Limit Error
|
|
333
|
+
```xml
|
|
334
|
+
<reflection-search>
|
|
335
|
+
<error>
|
|
336
|
+
<type>rate-limit</type>
|
|
337
|
+
<message>API rate limit exceeded</message>
|
|
338
|
+
<details>
|
|
339
|
+
<retry-after>60</retry-after>
|
|
340
|
+
<suggestion>Wait 60 seconds before retrying</suggestion>
|
|
341
|
+
</details>
|
|
342
|
+
</error>
|
|
343
|
+
</reflection-search>
|
|
115
344
|
```
|
|
116
345
|
|
|
117
346
|
## Memory Decay Insights
|
package/README.md
CHANGED
|
@@ -123,6 +123,51 @@ Once installed, just talk naturally:
|
|
|
123
123
|
|
|
124
124
|
The reflection specialist automatically activates. No special commands needed.
|
|
125
125
|
|
|
126
|
+
## Project-Scoped Search (New in v2.4.3)
|
|
127
|
+
|
|
128
|
+
**⚠️ Breaking Change**: Searches now default to current project only. Previously searched all projects.
|
|
129
|
+
|
|
130
|
+
Conversations are now **project-aware by default**. When you ask about past conversations, Claude automatically searches within your current project directory, keeping results focused and relevant.
|
|
131
|
+
|
|
132
|
+
### How It Works
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
# Example: Working in ~/projects/ShopifyMCPMockShop
|
|
136
|
+
You: "What authentication method did we implement?"
|
|
137
|
+
Claude: [Searches ONLY ShopifyMCPMockShop conversations]
|
|
138
|
+
"Found 3 conversations about JWT authentication..."
|
|
139
|
+
|
|
140
|
+
# To search everywhere (like pre-v2.4.3 behavior)
|
|
141
|
+
You: "Search all projects for WebSocket implementations"
|
|
142
|
+
Claude: [Searches across ALL your projects]
|
|
143
|
+
"Found implementations in 5 projects: ..."
|
|
144
|
+
|
|
145
|
+
# To search a specific project
|
|
146
|
+
You: "Find Docker setup in claude-self-reflect project"
|
|
147
|
+
Claude: [Searches only claude-self-reflect conversations]
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Key Behaviors
|
|
151
|
+
|
|
152
|
+
| Search Type | How to Trigger | Example |
|
|
153
|
+
|------------|----------------|---------|
|
|
154
|
+
| **Current Project** (default) | Just ask normally | "What did we discuss about caching?" |
|
|
155
|
+
| **All Projects** | Say "all projects" or "across projects" | "Search all projects for error handling" |
|
|
156
|
+
| **Specific Project** | Mention the project name | "Find auth code in MyApp project" |
|
|
157
|
+
|
|
158
|
+
### Why This Change?
|
|
159
|
+
|
|
160
|
+
- **Focused Results**: No more sifting through unrelated conversations
|
|
161
|
+
- **Better Performance**: Single-project search is ~100ms faster
|
|
162
|
+
- **Natural Workflow**: Results match your current working context
|
|
163
|
+
- **Privacy**: Work and personal projects stay isolated
|
|
164
|
+
|
|
165
|
+
### Upgrading from Earlier Versions?
|
|
166
|
+
|
|
167
|
+
Your existing conversations remain searchable. The only change is that searches now default to your current project. To get the old behavior, simply ask to "search all projects".
|
|
168
|
+
|
|
169
|
+
See [Project-Scoped Search Guide](docs/project-scoped-search.md) for detailed examples and advanced usage.
|
|
170
|
+
|
|
126
171
|
## Memory Decay
|
|
127
172
|
|
|
128
173
|
Recent conversations matter more. Old ones fade. Like your brain, but reliable.
|
|
@@ -192,6 +237,11 @@ Both embedding options work well. Local mode uses FastEmbed for privacy and offl
|
|
|
192
237
|
- [GitHub Issues](https://github.com/ramakay/claude-self-reflect/issues)
|
|
193
238
|
- [Discussions](https://github.com/ramakay/claude-self-reflect/discussions)
|
|
194
239
|
|
|
240
|
+
## Latest Updates
|
|
241
|
+
|
|
242
|
+
- 📢 [v2.4.x Announcement](https://github.com/ramakay/claude-self-reflect/discussions/19) - Major improvements including Docker setup and project-scoped search
|
|
243
|
+
- 💬 [Project-Scoped Search Feedback](https://github.com/ramakay/claude-self-reflect/discussions/17) - Share your experience with the breaking change
|
|
244
|
+
|
|
195
245
|
## Contributing
|
|
196
246
|
|
|
197
247
|
See our [Contributing Guide](CONTRIBUTING.md) for development setup and guidelines.
|
package/mcp-server/src/server.py
CHANGED
|
@@ -7,6 +7,7 @@ from typing import Any, Optional, List, Dict, Union
|
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
import json
|
|
9
9
|
import numpy as np
|
|
10
|
+
import hashlib
|
|
10
11
|
|
|
11
12
|
from fastmcp import FastMCP, Context
|
|
12
13
|
from pydantic import BaseModel, Field
|
|
@@ -149,7 +150,8 @@ async def reflect_on_past(
|
|
|
149
150
|
query: str = Field(description="The search query to find semantically similar conversations"),
|
|
150
151
|
limit: int = Field(default=5, description="Maximum number of results to return"),
|
|
151
152
|
min_score: float = Field(default=0.7, description="Minimum similarity score (0-1)"),
|
|
152
|
-
use_decay: Union[int, str] = Field(default=-1, description="Apply time-based decay: 1=enable, 0=disable, -1=use environment default (accepts int or str)")
|
|
153
|
+
use_decay: Union[int, str] = Field(default=-1, description="Apply time-based decay: 1=enable, 0=disable, -1=use environment default (accepts int or str)"),
|
|
154
|
+
project: Optional[str] = Field(default=None, description="Search specific project only. If not provided, searches current project based on working directory. Use 'all' to search across all projects.")
|
|
153
155
|
) -> str:
|
|
154
156
|
"""Search for relevant past conversations using semantic search with optional time decay."""
|
|
155
157
|
|
|
@@ -167,7 +169,37 @@ async def reflect_on_past(
|
|
|
167
169
|
else ENABLE_MEMORY_DECAY # -1 or any other value
|
|
168
170
|
)
|
|
169
171
|
|
|
172
|
+
# Determine project scope
|
|
173
|
+
target_project = project
|
|
174
|
+
if project is None:
|
|
175
|
+
# Try to detect current project from working directory
|
|
176
|
+
cwd = os.getcwd()
|
|
177
|
+
# Extract project name from path (e.g., /Users/.../projects/project-name)
|
|
178
|
+
path_parts = Path(cwd).parts
|
|
179
|
+
if 'projects' in path_parts:
|
|
180
|
+
idx = path_parts.index('projects')
|
|
181
|
+
if idx + 1 < len(path_parts):
|
|
182
|
+
target_project = path_parts[idx + 1]
|
|
183
|
+
elif '.claude' in path_parts:
|
|
184
|
+
# If we're in a .claude directory, go up to find project
|
|
185
|
+
for i, part in enumerate(path_parts):
|
|
186
|
+
if part == '.claude' and i > 0:
|
|
187
|
+
target_project = path_parts[i - 1]
|
|
188
|
+
break
|
|
189
|
+
|
|
190
|
+
# If still no project detected, use the last directory name
|
|
191
|
+
if target_project is None:
|
|
192
|
+
target_project = Path(cwd).name
|
|
193
|
+
|
|
194
|
+
# For project matching, we need to handle the dash-encoded format
|
|
195
|
+
# Convert folder name to the format used in stored data
|
|
196
|
+
if target_project != 'all':
|
|
197
|
+
# The stored format uses full path with dashes, so we need to construct it
|
|
198
|
+
# For now, let's try to match based on the end of the project name
|
|
199
|
+
pass # We'll handle this differently in the filtering logic
|
|
200
|
+
|
|
170
201
|
await ctx.debug(f"Searching for: {query}")
|
|
202
|
+
await ctx.debug(f"Project scope: {target_project if target_project != 'all' else 'all projects'}")
|
|
171
203
|
await ctx.debug(f"Decay enabled: {should_use_decay}")
|
|
172
204
|
await ctx.debug(f"Native decay mode: {USE_NATIVE_DECAY}")
|
|
173
205
|
await ctx.debug(f"ENABLE_MEMORY_DECAY env: {ENABLE_MEMORY_DECAY}")
|
|
@@ -182,13 +214,34 @@ async def reflect_on_past(
|
|
|
182
214
|
if not all_collections:
|
|
183
215
|
return "No conversation collections found. Please import conversations first."
|
|
184
216
|
|
|
185
|
-
|
|
217
|
+
# Filter collections by project if not searching all
|
|
218
|
+
project_collections = [] # Define at this scope for later use
|
|
219
|
+
if target_project != 'all':
|
|
220
|
+
# Generate the collection name pattern for this project
|
|
221
|
+
project_hash = hashlib.md5(target_project.encode()).hexdigest()[:8]
|
|
222
|
+
project_collections = [
|
|
223
|
+
c for c in all_collections
|
|
224
|
+
if c.startswith(f"conv_{project_hash}_")
|
|
225
|
+
]
|
|
226
|
+
|
|
227
|
+
if not project_collections:
|
|
228
|
+
# Try to find collections with project metadata
|
|
229
|
+
# Fall back to searching all collections but filtering by project metadata
|
|
230
|
+
await ctx.debug(f"No collections found for project hash {project_hash}, will filter by metadata")
|
|
231
|
+
collections_to_search = all_collections
|
|
232
|
+
else:
|
|
233
|
+
await ctx.debug(f"Found {len(project_collections)} collections for project {target_project}")
|
|
234
|
+
collections_to_search = project_collections
|
|
235
|
+
else:
|
|
236
|
+
collections_to_search = all_collections
|
|
237
|
+
|
|
238
|
+
await ctx.debug(f"Searching across {len(collections_to_search)} collections")
|
|
186
239
|
await ctx.debug(f"Using {'local' if PREFER_LOCAL_EMBEDDINGS or not voyage_client else 'Voyage AI'} embeddings")
|
|
187
240
|
|
|
188
241
|
all_results = []
|
|
189
242
|
|
|
190
243
|
# Search each collection
|
|
191
|
-
for collection_name in
|
|
244
|
+
for collection_name in collections_to_search:
|
|
192
245
|
try:
|
|
193
246
|
if should_use_decay and USE_NATIVE_DECAY and NATIVE_DECAY_AVAILABLE:
|
|
194
247
|
# Use native Qdrant decay with newer API
|
|
@@ -285,13 +338,23 @@ async def reflect_on_past(
|
|
|
285
338
|
raw_timestamp = point.payload.get('timestamp', datetime.now().isoformat())
|
|
286
339
|
clean_timestamp = raw_timestamp.replace('Z', '+00:00') if raw_timestamp.endswith('Z') else raw_timestamp
|
|
287
340
|
|
|
341
|
+
# Check project filter if we're searching all collections but want specific project
|
|
342
|
+
point_project = point.payload.get('project', collection_name.replace('conv_', '').replace('_voyage', '').replace('_local', ''))
|
|
343
|
+
|
|
344
|
+
# Handle project matching - check if the target project name appears at the end of the stored project path
|
|
345
|
+
if target_project != 'all' and not project_collections:
|
|
346
|
+
# The stored project name is like "-Users-ramakrishnanannaswamy-projects-ShopifyMCPMockShop"
|
|
347
|
+
# We want to match just "ShopifyMCPMockShop"
|
|
348
|
+
if not point_project.endswith(f"-{target_project}") and point_project != target_project:
|
|
349
|
+
continue # Skip results from other projects
|
|
350
|
+
|
|
288
351
|
all_results.append(SearchResult(
|
|
289
352
|
id=str(point.id),
|
|
290
353
|
score=point.score, # Score already includes decay
|
|
291
354
|
timestamp=clean_timestamp,
|
|
292
355
|
role=point.payload.get('start_role', point.payload.get('role', 'unknown')),
|
|
293
356
|
excerpt=(point.payload.get('text', '')[:500] + '...'),
|
|
294
|
-
project_name=
|
|
357
|
+
project_name=point_project,
|
|
295
358
|
conversation_id=point.payload.get('conversation_id'),
|
|
296
359
|
collection_name=collection_name
|
|
297
360
|
))
|
|
@@ -350,13 +413,23 @@ async def reflect_on_past(
|
|
|
350
413
|
raw_timestamp = point.payload.get('timestamp', datetime.now().isoformat())
|
|
351
414
|
clean_timestamp = raw_timestamp.replace('Z', '+00:00') if raw_timestamp.endswith('Z') else raw_timestamp
|
|
352
415
|
|
|
416
|
+
# Check project filter if we're searching all collections but want specific project
|
|
417
|
+
point_project = point.payload.get('project', collection_name.replace('conv_', '').replace('_voyage', '').replace('_local', ''))
|
|
418
|
+
|
|
419
|
+
# Handle project matching - check if the target project name appears at the end of the stored project path
|
|
420
|
+
if target_project != 'all' and not project_collections:
|
|
421
|
+
# The stored project name is like "-Users-ramakrishnanannaswamy-projects-ShopifyMCPMockShop"
|
|
422
|
+
# We want to match just "ShopifyMCPMockShop"
|
|
423
|
+
if not point_project.endswith(f"-{target_project}") and point_project != target_project:
|
|
424
|
+
continue # Skip results from other projects
|
|
425
|
+
|
|
353
426
|
all_results.append(SearchResult(
|
|
354
427
|
id=str(point.id),
|
|
355
428
|
score=adjusted_score, # Use adjusted score
|
|
356
429
|
timestamp=clean_timestamp,
|
|
357
430
|
role=point.payload.get('start_role', point.payload.get('role', 'unknown')),
|
|
358
431
|
excerpt=(point.payload.get('text', '')[:500] + '...'),
|
|
359
|
-
project_name=
|
|
432
|
+
project_name=point_project,
|
|
360
433
|
conversation_id=point.payload.get('conversation_id'),
|
|
361
434
|
collection_name=collection_name
|
|
362
435
|
))
|
|
@@ -375,13 +448,23 @@ async def reflect_on_past(
|
|
|
375
448
|
raw_timestamp = point.payload.get('timestamp', datetime.now().isoformat())
|
|
376
449
|
clean_timestamp = raw_timestamp.replace('Z', '+00:00') if raw_timestamp.endswith('Z') else raw_timestamp
|
|
377
450
|
|
|
451
|
+
# Check project filter if we're searching all collections but want specific project
|
|
452
|
+
point_project = point.payload.get('project', collection_name.replace('conv_', '').replace('_voyage', '').replace('_local', ''))
|
|
453
|
+
|
|
454
|
+
# Handle project matching - check if the target project name appears at the end of the stored project path
|
|
455
|
+
if target_project != 'all' and not project_collections:
|
|
456
|
+
# The stored project name is like "-Users-ramakrishnanannaswamy-projects-ShopifyMCPMockShop"
|
|
457
|
+
# We want to match just "ShopifyMCPMockShop"
|
|
458
|
+
if not point_project.endswith(f"-{target_project}") and point_project != target_project:
|
|
459
|
+
continue # Skip results from other projects
|
|
460
|
+
|
|
378
461
|
all_results.append(SearchResult(
|
|
379
462
|
id=str(point.id),
|
|
380
463
|
score=point.score,
|
|
381
464
|
timestamp=clean_timestamp,
|
|
382
465
|
role=point.payload.get('start_role', point.payload.get('role', 'unknown')),
|
|
383
466
|
excerpt=(point.payload.get('text', '')[:500] + '...'),
|
|
384
|
-
project_name=
|
|
467
|
+
project_name=point_project,
|
|
385
468
|
conversation_id=point.payload.get('conversation_id'),
|
|
386
469
|
collection_name=collection_name
|
|
387
470
|
))
|