mirror of
https://github.com/lukaszraczylo/claude-mnemonic.git
synced 2026-06-05 23:03:55 +00:00
fix(hooks,db,mcp,worker): add type safety and error handling (#21)
- [x] Add type checking and error handling for JSON type assertions in user-prompt hook - [x] Add error handling for session update query in CreateSDKSession - [x] Update MCP tool description to reference sqlite-vec instead of ChromaDB - [x] Fix MinConfidence sentinel value check from 0 to -1 - [x] Pass project parameter to vector search filter in handleSearchByPrompt - [x] Return empty map instead of nil for successful responses without JSON body
This commit is contained in:
@@ -94,8 +94,18 @@ func handleUserPrompt(ctx *hooks.HookContext, input *Input) (string, error) {
|
|||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionID := int64(result["sessionDbId"].(float64))
|
// Safely extract session ID and prompt number with type checking
|
||||||
promptNumber := int(result["promptNumber"].(float64))
|
sessionDbIdRaw, ok := result["sessionDbId"].(float64)
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("invalid or missing sessionDbId in response")
|
||||||
|
}
|
||||||
|
sessionID := int64(sessionDbIdRaw)
|
||||||
|
|
||||||
|
promptNumberRaw, ok := result["promptNumber"].(float64)
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("invalid or missing promptNumber in response")
|
||||||
|
}
|
||||||
|
promptNumber := int(promptNumberRaw)
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, "[user-prompt] Session %d, prompt #%d\n", sessionID, promptNumber)
|
fmt.Fprintf(os.Stderr, "[user-prompt] Session %d, prompt #%d\n", sessionID, promptNumber)
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package gorm
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -67,10 +68,12 @@ func (s *SessionStore) CreateSDKSession(ctx context.Context, claudeSessionID, pr
|
|||||||
if userPrompt != "" {
|
if userPrompt != "" {
|
||||||
updates["user_prompt"] = userPrompt
|
updates["user_prompt"] = userPrompt
|
||||||
}
|
}
|
||||||
s.db.WithContext(ctx).
|
if err := s.db.WithContext(ctx).
|
||||||
Model(&SDKSession{}).
|
Model(&SDKSession{}).
|
||||||
Where("claude_session_id = ?", claudeSessionID).
|
Where("claude_session_id = ?", claudeSessionID).
|
||||||
Updates(updates)
|
Updates(updates).Error; err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to update session: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch existing session
|
// Fetch existing session
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ func (s *Server) handleToolsList(req *Request) *Response {
|
|||||||
tools := []Tool{
|
tools := []Tool{
|
||||||
{
|
{
|
||||||
Name: "search",
|
Name: "search",
|
||||||
Description: "Unified search across all memory types (observations, sessions, and user prompts) using vector-first semantic search (ChromaDB).",
|
Description: "Unified search across all memory types (observations, sessions, and user prompts) using vector-first semantic search (sqlite-vec).",
|
||||||
InputSchema: map[string]any{
|
InputSchema: map[string]any{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": map[string]any{
|
"properties": map[string]any{
|
||||||
@@ -599,7 +599,8 @@ func (s *Server) handleFindRelatedObservations(ctx context.Context, args json.Ra
|
|||||||
return "", fmt.Errorf("id is required")
|
return "", fmt.Errorf("id is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.MinConfidence == 0 {
|
// Use -1 as sentinel for "not provided" since 0.0 is a valid threshold
|
||||||
|
if params.MinConfidence < 0 {
|
||||||
params.MinConfidence = 0.5
|
params.MinConfidence = 0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -774,7 +774,7 @@ func (s *Service) handleSearchByPrompt(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// Try vector search first if available
|
// Try vector search first if available
|
||||||
if s.vectorClient != nil && s.vectorClient.IsConnected() {
|
if s.vectorClient != nil && s.vectorClient.IsConnected() {
|
||||||
where := sqlitevec.BuildWhereFilter(sqlitevec.DocTypeObservation, "")
|
where := sqlitevec.BuildWhereFilter(sqlitevec.DocTypeObservation, project)
|
||||||
|
|
||||||
// Search with each expanded query and merge results
|
// Search with each expanded query and merge results
|
||||||
allVectorResults := make([]sqlitevec.QueryResult, 0)
|
allVectorResults := make([]sqlitevec.QueryResult, 0)
|
||||||
|
|||||||
+2
-2
@@ -251,8 +251,8 @@ func POST(port int, path string, body interface{}) (map[string]interface{}, erro
|
|||||||
|
|
||||||
var result map[string]interface{}
|
var result map[string]interface{}
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||||
// Not all endpoints return JSON
|
// Not all endpoints return JSON body - return empty map for success with no body
|
||||||
return nil, nil
|
return map[string]interface{}{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user