Fixes onnx version mismatch, vectordb not liking it and dashboard

Fixes summaries not being generated and timeline showing all observations
despite of project filter being applied.
This commit is contained in:
2025-12-16 18:27:55 +00:00
parent 2730727e8b
commit 4440fd0afb
11 changed files with 137 additions and 18 deletions
+19 -2
View File
@@ -75,13 +75,16 @@ func parseTranscript(path string) (lastUser, lastAssistant string) {
continue continue
} }
if msg.Type == "message" { // Transcript entries have type: "user" or "assistant" (not "message")
// Check if this is a user/assistant message with content
if msg.Type == "user" || msg.Type == "assistant" {
text := extractTextContent(msg.Message.Content) text := extractTextContent(msg.Message.Content)
if text == "" { if text == "" {
continue continue
} }
switch msg.Message.Role { // Use the outer type field for role (message.role may differ)
switch msg.Type {
case "user": case "user":
lastUser = text lastUser = text
case "assistant": case "assistant":
@@ -98,6 +101,9 @@ func main() {
} }
func handleStop(ctx *hooks.HookContext, input *Input) (string, error) { func handleStop(ctx *hooks.HookContext, input *Input) (string, error) {
// Debug: dump raw input
fmt.Fprintf(os.Stderr, "[stop] Raw input: %s\n", string(ctx.RawInput))
// Find session // Find session
result, err := hooks.GET(ctx.Port, fmt.Sprintf("/api/sessions?claudeSessionId=%s", ctx.SessionID)) result, err := hooks.GET(ctx.Port, fmt.Sprintf("/api/sessions?claudeSessionId=%s", ctx.SessionID))
if err != nil || result == nil { if err != nil || result == nil {
@@ -116,6 +122,17 @@ func handleStop(ctx *hooks.HookContext, input *Input) (string, error) {
lastUser, lastAssistant = parseTranscript(input.TranscriptPath) lastUser, lastAssistant = parseTranscript(input.TranscriptPath)
} }
// Debug: log what we extracted
fmt.Fprintf(os.Stderr, "[stop] Transcript path: %s\n", input.TranscriptPath)
fmt.Fprintf(os.Stderr, "[stop] Last user message length: %d\n", len(lastUser))
fmt.Fprintf(os.Stderr, "[stop] Last assistant message length: %d\n", len(lastAssistant))
if len(lastAssistant) > 0 {
preview := lastAssistant
if len(preview) > 300 {
preview = preview[:300] + "..."
}
fmt.Fprintf(os.Stderr, "[stop] Last assistant preview: %s\n", preview)
}
fmt.Fprintf(os.Stderr, "[stop] Requesting summary for session %d (transcript: %v)\n", int64(sessionID), input.TranscriptPath != "") fmt.Fprintf(os.Stderr, "[stop] Requesting summary for session %d (transcript: %v)\n", int64(sessionID), input.TranscriptPath != "")
// Request summary with message context from transcript // Request summary with message context from transcript
+23
View File
@@ -175,6 +175,29 @@ func (s *ObservationStore) GetRecentObservations(ctx context.Context, project st
return scanObservationRows(rows) return scanObservationRows(rows)
} }
// GetObservationsByProjectStrict retrieves observations strictly for a specific project.
// Unlike GetRecentObservations, this does NOT include global observations from other projects.
// Use this for dashboard filtering where the user expects to see only that project's data.
func (s *ObservationStore) GetObservationsByProjectStrict(ctx context.Context, project string, limit int) ([]*models.Observation, error) {
const query = `
SELECT id, sdk_session_id, project, COALESCE(scope, 'project') as scope, type, title, subtitle, facts, narrative,
concepts, files_read, files_modified, file_mtimes, prompt_number, discovery_tokens,
created_at, created_at_epoch
FROM observations
WHERE project = ?
ORDER BY created_at_epoch DESC
LIMIT ?
`
rows, err := s.store.QueryContext(ctx, query, project, limit)
if err != nil {
return nil, err
}
defer rows.Close()
return scanObservationRows(rows)
}
// GetObservationCount returns the count of observations for a project (including global). // GetObservationCount returns the count of observations for a project (including global).
func (s *ObservationStore) GetObservationCount(ctx context.Context, project string) (int, error) { func (s *ObservationStore) GetObservationCount(ctx context.Context, project string) (int, error) {
const query = ` const query = `
@@ -0,0 +1 @@
1.23.2
@@ -0,0 +1 @@
1.23.2
@@ -0,0 +1 @@
1.23.2
@@ -0,0 +1 @@
1.23.2
+2 -2
View File
@@ -478,8 +478,8 @@ func (s *Service) handleGetObservations(w http.ResponseWriter, r *http.Request)
// Fall back to SQLite if vector search not used // Fall back to SQLite if vector search not used
if !usedVector { if !usedVector {
if project != "" { if project != "" {
// Filter by project - includes project-scoped and global observations // Strict project filtering for dashboard - only observations from this project
observations, err = s.observationStore.GetRecentObservations(r.Context(), project, limit) observations, err = s.observationStore.GetObservationsByProjectStrict(r.Context(), project, limit)
} else { } else {
// All projects // All projects
observations, err = s.observationStore.GetAllRecentObservations(r.Context(), limit) observations, err = s.observationStore.GetAllRecentObservations(r.Context(), limit)
+16
View File
@@ -234,11 +234,19 @@ func (p *Processor) ProcessObservation(ctx context.Context, sdkSessionID, projec
// ProcessSummary processes a session summary request. // ProcessSummary processes a session summary request.
func (p *Processor) ProcessSummary(ctx context.Context, sessionDBID int64, sdkSessionID, project, userPrompt, lastUserMsg, lastAssistantMsg string) error { func (p *Processor) ProcessSummary(ctx context.Context, sessionDBID int64, sdkSessionID, project, userPrompt, lastUserMsg, lastAssistantMsg string) error {
// Debug: log what we received
log.Debug().
Int64("sessionId", sessionDBID).
Int("lastAssistantMsgLen", len(lastAssistantMsg)).
Str("lastAssistantMsgPreview", truncateForLog(lastAssistantMsg, 200)).
Msg("ProcessSummary called")
// Skip summary generation if there's no meaningful assistant response // Skip summary generation if there's no meaningful assistant response
// This prevents generic "initial session setup" summaries // This prevents generic "initial session setup" summaries
if !hasMeaningfulContent(lastAssistantMsg) { if !hasMeaningfulContent(lastAssistantMsg) {
log.Info(). log.Info().
Int64("sessionId", sessionDBID). Int64("sessionId", sessionDBID).
Int("msgLen", len(lastAssistantMsg)).
Msg("Skipping summary - no meaningful assistant response") Msg("Skipping summary - no meaningful assistant response")
return nil return nil
} }
@@ -727,6 +735,14 @@ func hasMeaningfulContent(assistantMsg string) bool {
return matchCount >= 2 return matchCount >= 2
} }
// truncateForLog truncates a string for logging purposes.
func truncateForLog(s string, maxLen int) string {
if len(s) <= maxLen {
return s
}
return s[:maxLen] + "..."
}
const systemPrompt = `You are a memory extraction agent for Claude Code sessions. Your job is to analyze tool executions and extract meaningful observations that would be useful for future sessions. const systemPrompt = `You are a memory extraction agent for Claude Code sessions. Your job is to analyze tool executions and extract meaningful observations that would be useful for future sessions.
GUIDELINES: GUIDELINES:
+70 -11
View File
@@ -1,13 +1,22 @@
#!/bin/bash #!/bin/bash
# Download ONNX Runtime libraries for embedding # Download ONNX Runtime libraries for embedding
# Usage: ./download-onnx-libs.sh [platform] # Usage: ./download-onnx-libs.sh [platform] [--force]
# Platform: darwin-arm64, linux-amd64, windows-amd64, or "all" (default) # Platform: darwin-arm64, linux-amd64, windows-amd64, or "all" (default)
# Use --force to re-download even if libraries exist
set -e set -e
ONNX_VERSION="1.23.2" ONNX_VERSION="1.23.2"
ASSETS_DIR="internal/embedding/assets/lib" ASSETS_DIR="internal/embedding/assets/lib"
PLATFORM="${1:-all}" PLATFORM="${1:-all}"
FORCE_DOWNLOAD=false
# Check for --force flag
for arg in "$@"; do
if [ "$arg" = "--force" ]; then
FORCE_DOWNLOAD=true
fi
done
# Auto-detect platform if not specified # Auto-detect platform if not specified
if [ "$PLATFORM" = "auto" ]; then if [ "$PLATFORM" = "auto" ]; then
@@ -31,12 +40,38 @@ fi
TEMP_DIR=$(mktemp -d) TEMP_DIR=$(mktemp -d)
trap "rm -rf ${TEMP_DIR}" EXIT trap "rm -rf ${TEMP_DIR}" EXIT
# Get the installed version for a platform
get_installed_version() {
local plat="$1"
local version_file="${ASSETS_DIR}/${plat}/.version"
if [ -f "$version_file" ]; then
cat "$version_file"
else
echo ""
fi
}
# Write version file after successful download
write_version_file() {
local plat="$1"
echo "${ONNX_VERSION}" > "${ASSETS_DIR}/${plat}/.version"
}
# Check if version matches
version_matches() {
local plat="$1"
local installed_version
installed_version=$(get_installed_version "$plat")
[ "$installed_version" = "$ONNX_VERSION" ]
}
download_darwin_arm64() { download_darwin_arm64() {
echo "Downloading darwin-arm64..." echo "Downloading darwin-arm64..."
mkdir -p "${ASSETS_DIR}/darwin-arm64" mkdir -p "${ASSETS_DIR}/darwin-arm64"
curl -fsSL "https://github.com/microsoft/onnxruntime/releases/download/v${ONNX_VERSION}/onnxruntime-osx-arm64-${ONNX_VERSION}.tgz" -o "${TEMP_DIR}/darwin-arm64.tgz" curl -fsSL "https://github.com/microsoft/onnxruntime/releases/download/v${ONNX_VERSION}/onnxruntime-osx-arm64-${ONNX_VERSION}.tgz" -o "${TEMP_DIR}/darwin-arm64.tgz"
tar -xzf "${TEMP_DIR}/darwin-arm64.tgz" -C "${TEMP_DIR}" tar -xzf "${TEMP_DIR}/darwin-arm64.tgz" -C "${TEMP_DIR}"
cp "${TEMP_DIR}/onnxruntime-osx-arm64-${ONNX_VERSION}/lib/libonnxruntime.${ONNX_VERSION}.dylib" "${ASSETS_DIR}/darwin-arm64/libonnxruntime.dylib" cp "${TEMP_DIR}/onnxruntime-osx-arm64-${ONNX_VERSION}/lib/libonnxruntime.${ONNX_VERSION}.dylib" "${ASSETS_DIR}/darwin-arm64/libonnxruntime.dylib"
write_version_file "darwin-arm64"
} }
download_linux_amd64() { download_linux_amd64() {
@@ -46,6 +81,7 @@ download_linux_amd64() {
tar -xzf "${TEMP_DIR}/linux-amd64.tgz" -C "${TEMP_DIR}" tar -xzf "${TEMP_DIR}/linux-amd64.tgz" -C "${TEMP_DIR}"
cp "${TEMP_DIR}/onnxruntime-linux-x64-${ONNX_VERSION}/lib/libonnxruntime.so.${ONNX_VERSION}" "${ASSETS_DIR}/linux-amd64/libonnxruntime.so" cp "${TEMP_DIR}/onnxruntime-linux-x64-${ONNX_VERSION}/lib/libonnxruntime.so.${ONNX_VERSION}" "${ASSETS_DIR}/linux-amd64/libonnxruntime.so"
cp "${TEMP_DIR}/onnxruntime-linux-x64-${ONNX_VERSION}/lib/libonnxruntime_providers_shared.so" "${ASSETS_DIR}/linux-amd64/libonnxruntime_providers_shared.so" 2>/dev/null || true cp "${TEMP_DIR}/onnxruntime-linux-x64-${ONNX_VERSION}/lib/libonnxruntime_providers_shared.so" "${ASSETS_DIR}/linux-amd64/libonnxruntime_providers_shared.so" 2>/dev/null || true
write_version_file "linux-amd64"
} }
download_linux_arm64() { download_linux_arm64() {
@@ -55,6 +91,7 @@ download_linux_arm64() {
tar -xzf "${TEMP_DIR}/linux-arm64.tgz" -C "${TEMP_DIR}" tar -xzf "${TEMP_DIR}/linux-arm64.tgz" -C "${TEMP_DIR}"
cp "${TEMP_DIR}/onnxruntime-linux-aarch64-${ONNX_VERSION}/lib/libonnxruntime.so.${ONNX_VERSION}" "${ASSETS_DIR}/linux-arm64/libonnxruntime.so" cp "${TEMP_DIR}/onnxruntime-linux-aarch64-${ONNX_VERSION}/lib/libonnxruntime.so.${ONNX_VERSION}" "${ASSETS_DIR}/linux-arm64/libonnxruntime.so"
cp "${TEMP_DIR}/onnxruntime-linux-aarch64-${ONNX_VERSION}/lib/libonnxruntime_providers_shared.so" "${ASSETS_DIR}/linux-arm64/libonnxruntime_providers_shared.so" 2>/dev/null || true cp "${TEMP_DIR}/onnxruntime-linux-aarch64-${ONNX_VERSION}/lib/libonnxruntime_providers_shared.so" "${ASSETS_DIR}/linux-arm64/libonnxruntime_providers_shared.so" 2>/dev/null || true
write_version_file "linux-arm64"
} }
download_windows_amd64() { download_windows_amd64() {
@@ -66,6 +103,7 @@ download_windows_amd64() {
echo "Downloaded file size: $(wc -c < "${TEMP_DIR}/windows-amd64.zip") bytes" echo "Downloaded file size: $(wc -c < "${TEMP_DIR}/windows-amd64.zip") bytes"
unzip -q "${TEMP_DIR}/windows-amd64.zip" -d "${TEMP_DIR}" unzip -q "${TEMP_DIR}/windows-amd64.zip" -d "${TEMP_DIR}"
cp "${TEMP_DIR}/onnxruntime-win-x64-${ONNX_VERSION}/lib/onnxruntime.dll" "${ASSETS_DIR}/windows-amd64/onnxruntime.dll" cp "${TEMP_DIR}/onnxruntime-win-x64-${ONNX_VERSION}/lib/onnxruntime.dll" "${ASSETS_DIR}/windows-amd64/onnxruntime.dll"
write_version_file "windows-amd64"
} }
# Check if library already exists for a platform # Check if library already exists for a platform
@@ -79,19 +117,40 @@ lib_exists() {
esac esac
} }
# Download only if not present # Download only if not present or version mismatch
download_if_needed() { download_if_needed() {
local plat="$1" local plat="$1"
if lib_exists "$plat"; then local need_download=false
echo "Library for ${plat} already exists, skipping download" local reason=""
return 0
if [ "$FORCE_DOWNLOAD" = true ]; then
need_download=true
reason="forced"
elif ! lib_exists "$plat"; then
need_download=true
reason="not found"
elif ! version_matches "$plat"; then
local installed_version
installed_version=$(get_installed_version "$plat")
need_download=true
reason="version mismatch (installed: ${installed_version:-unknown}, required: ${ONNX_VERSION})"
fi
if [ "$need_download" = true ]; then
if [ -n "$reason" ] && [ "$reason" != "not found" ]; then
echo "Re-downloading ${plat}: ${reason}"
fi
# Remove old library before downloading
rm -rf "${ASSETS_DIR}/${plat}"
case "$plat" in
darwin-arm64) download_darwin_arm64 ;;
linux-amd64) download_linux_amd64 ;;
linux-arm64) download_linux_arm64 ;;
windows-amd64) download_windows_amd64 ;;
esac
else
echo "Library for ${plat} already exists (v${ONNX_VERSION}), skipping download"
fi fi
case "$plat" in
darwin-arm64) download_darwin_arm64 ;;
linux-amd64) download_linux_amd64 ;;
linux-arm64) download_linux_arm64 ;;
windows-amd64) download_windows_amd64 ;;
esac
} }
echo "ONNX Runtime v${ONNX_VERSION} - Platform: ${PLATFORM}" echo "ONNX Runtime v${ONNX_VERSION} - Platform: ${PLATFORM}"
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "claude-mnemonic-dashboard", "name": "claude-mnemonic-dashboard",
"version": "v0.6.5-23-g21bcbfa", "version": "v0.6.5-25-g372942e-dirty",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "claude-mnemonic-dashboard", "name": "claude-mnemonic-dashboard",
"version": "v0.6.5-23-g21bcbfa", "version": "v0.6.5-25-g372942e-dirty",
"dependencies": { "dependencies": {
"vue": "^3.5.13" "vue": "^3.5.13"
}, },
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "claude-mnemonic-dashboard", "name": "claude-mnemonic-dashboard",
"version": "v0.6.5-23-g21bcbfa", "version": "v0.6.5-25-g372942e-dirty",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {