Skip to content

Feature/local setup#201

Merged
Ankit-Kotnala merged 2 commits into
mainfrom
feature/Local-Setup
May 23, 2026
Merged

Feature/local setup#201
Ankit-Kotnala merged 2 commits into
mainfrom
feature/Local-Setup

Conversation

@Ankit-Kotnala
Copy link
Copy Markdown
Collaborator

Repaired virtual env setup while setting up local

@Ankit-Kotnala Ankit-Kotnala self-assigned this May 23, 2026
@Ankit-Kotnala Ankit-Kotnala merged commit 3912666 into main May 23, 2026
8 checks passed
@github-actions
Copy link
Copy Markdown

Fails
🚫

📋 PR description is too short. Please describe:

  • What changed and Why
  • Any relevant issue links (Closes #NNN)
  • Steps to test manually
Warnings
⚠️

📦 This PR changes 3915 lines (additions + deletions). Large PRs are harder to review thoroughly — consider splitting it.

⚠️

🧪 Source files in src/ were modified but no test files changed. Please add or update tests to cover your changes.

Messages
📖

📝 No CHANGELOG.md update detected. If this PR introduces a user-visible change, please add an entry.

📖

✅ Targeting main. Please squash commits before merging to keep the git history clean.

Generated by 🚫 dangerJS against d52642d

@github-actions
Copy link
Copy Markdown

✅ Staging Deployment Report

Item Value
Branch feature/Local-Setup
Commit f2f089f
Environment Staging
Health http://13.232.74.176:8001/health
API Docs http://13.232.74.176:8001/docs
Smoke Tests success

🟢 Staging is live and healthy! Test your changes at the staging URL above.

Ready to ship? Comment /promote on this PR to merge to main and deploy to production.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the benchmarking system and ports several core agents (Classifier, Code, Image, Judge, etc.) from Python to Go to ensure feature parity. It introduces a robust tracing and metrics collector for LLM calls, adds multimodal vision support across multiple providers, and enhances the Neo4j storage layer with relationship-based event tracking and vector search. Feedback identifies several critical issues, including a missing method in the Go implementation that will cause compilation errors, logic flaws in Neo4j event updates and creation that could lead to data duplication or loss, and incorrect handling of image data for Gemini and Claude vision APIs. Additionally, improvements are needed for database performance via indexing and optimizing API call placement within retry logic.

incoming := temporalFieldsFromContent(itemStr)
existing := temporalFieldsFromMatch(match)
if sameTemporalEvent(incoming, existing) {
ops = append(ops, weaver.Operation{Type: weaver.OperationNoop, Content: itemStr, EmbeddingID: match.EmbeddingID(), Reason: "Existing temporal event is unchanged."})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The EmbeddingID() method appears to be missing from the graph.Event struct definition in internal/graph/types.go. This will cause a compilation error. Please ensure the method is implemented (e.g., returning a combination of date and event name) or access the identifying fields directly.

func (s *Neo4jTemporalStore) initSchema(ctx context.Context) {
constraints := []string{
"CREATE CONSTRAINT user_id_unique IF NOT EXISTS FOR (u:User) REQUIRE u.user_id IS UNIQUE",
"CREATE CONSTRAINT date_val_unique IF NOT EXISTS FOR (d:Date) REQUIRE d.date IS UNIQUE",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The SearchEventsByEmbedding method relies on vector.similarity.cosine, which requires a vector index for efficient execution. Without an index, Neo4j will perform a full scan of all relationships, leading to significant performance degradation as the database grows. Consider adding vector index creation to initSchema.

Comment on lines +85 to +87
MATCH (u:User {user_id: $user_id})
-[r:HAS_EVENT]->
(d:Date {date: $date_str})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The MATCH clause in updateEventOnce is missing a filter for the specific event name. As currently implemented, it will match and update all HAS_EVENT relationships between the user and the specified date, which will overwrite unrelated events if multiple events exist on the same day.

if imageURL != "" {
parts = append(parts, map[string]any{
"inline_data": map[string]string{"mime_type": "image/jpeg", "data": imageURL},
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The Gemini API's inline_data field expects base64-encoded image data in the data field, not a URL. If imageURL is a web URL, this request will fail. You should either fetch and encode the image or use a supported method for providing URLs if available.

contentBlocks = append(contentBlocks, map[string]any{
"type": "image", "source": map[string]string{"type": "url", "url": imageURL},
})
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The Anthropic (Claude) Messages API does not support type: "url" for image sources. It requires type: "base64" with the image data. This implementation will fail when provided with a web URL.


func (s *Neo4jTemporalStore) CreateEvent(ctx context.Context, userID string, date string, event Event) error {
return s.upsertEvent(ctx, userID, date, event)
return s.withRetry(ctx, func() error {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The embedding API call (s.embedder.Embed) is performed inside the withRetry loop (via createEventOnce). If the database operation fails and triggers a retry, it will result in redundant and potentially costly embedding requests. The embedding should be generated once before entering the retry logic.

_, err := neo4j.ExecuteQuery(ctx, s.driver, `
MERGE (u:User {user_id: $user_id})
MERGE (d:Date {date: $date_str})
CREATE (u)-[r:HAS_EVENT]->(d)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using CREATE for the relationship will result in duplicate HAS_EVENT relationships if CreateEvent is called multiple times for the same event. Consider using MERGE with the event_name property to ensure idempotency and data integrity.

MATCH (u:User {user_id: $user_id})
-[r:HAS_EVENT]->
(d:Date)
WHERE toLower(r.event_name) = toLower($event_name)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Changing from CONTAINS to an exact equality check (=) is a regression in search flexibility. Users searching for a partial event name will no longer find relevant results. Reverting to CONTAINS is recommended for better usability.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 23, 2026

Greptile Summary

This PR repairs the local Python virtual-environment setup (the headline fix in scripts/xmem.js) and bundles a broad set of related improvements across both the Go and Python sides of the codebase.

  • scripts/xmem.js: New ensureVirtualenv() verifies pip availability after venv creation and attempts ensurepip --upgrade repair before failing with a clear message.
  • Go refactor: Monolithic agents.go split into per-agent files; models.NewRegistry now returns an error; JudgeAgent gains a TemporalStore for deterministic temporal deduplication; Neo4j receives embedder-backed cosine-similarity search with keyword fallback; bootstrap.go adds strict production guards for missing cloud credentials.
  • benchmark.py / smoke_test: In-memory fakes removed in favour of real pipeline runs; TimedModel extended with per-agent token metrics, cost estimates, and coloured LLM-call traces; Go benchmark renamed to smoke_test with an optional trace.go cloud-connected variant.

Confidence Score: 3/5

The venv-repair fix and Go refactoring are solid, but the JWT handler accepts expired tokens, which is an authentication gap that should be closed before this reaches a production deployment.

The auth handler's missing exp check means any leaked or old token authenticates users without a time bound. The temporal date validator always permits Feb 29 regardless of the stored year. The trace tool has an unguarded read of shared state.

xmem-go/internal/api/auth.go needs the exp claim validated; xmem-go/internal/agents/temporal.go should cross-check Feb 29 against the Year field; xmem-go/cmd/smoke_test/trace.go PrintSummary needs a mutex guard.

Security Review

  • xmem-go/internal/api/auth.go — JWT expiry not enforced: validateJWT verifies the HMAC signature and decodes the payload but never reads the exp claim. Any previously valid token remains accepted after its expiry window, giving an attacker with a captured token permanent access.

Important Files Changed

Filename Overview
scripts/xmem.js Adds ensureVirtualenv() to verify pip availability after venv creation and repair it via ensurepip; cleanly replaces the old inline venv check in runSetup.
xmem-go/internal/api/auth.go Only change is swapping encoding/json for goccy/go-json; pre-existing validateJWT never checks the exp claim, so expired tokens authenticate indefinitely.
xmem-go/internal/models/models.go NewRegistry now returns (ChatModel, error) instead of panicking silently when no provider is configured; HTTP/2 transport and multi-provider support look correct.
xmem-go/internal/agents/temporal.go New isValidDate uses daysInMonth map for tighter validation but sets February to 29, accepting 02-29 in non-leap years when paired with any Year value.
xmem-go/internal/agents/judge.go Adds JudgeTemporal method using the new TemporalStore field; deduplication, fallback paths, and LLM parse fallback all look correct.
xmem-go/internal/graph/neo4j.go Adds embedder-backed cosine-similarity search for temporal events with keyword fallback; retry wrapper, schema init, and CRUD operations all look sound.
xmem-go/cmd/xmem/bootstrap.go Refactors embedder/temporal store initialisation with proper production vs. dev guards; NewRegistry error is now propagated correctly.
xmem-go/cmd/smoke_test/trace.go New cloud-connected tracing binary (build-ignored); PrintSummary reads mc.entries and mc.pipelineTimings without holding the mutex, creating a data race when called concurrently with ongoing agent calls.
benchmark.py Major overhaul: removes in-memory fakes and per-agent micro-benchmarks in favour of full-pipeline tracing with per-agent token metrics and cost estimates.
xmem-go/internal/agents/base.go Extracts shared callModel helper with a 45s per-call timeout; clean separation from the deleted monolithic agents.go.
src/prompts/temporal.py Adds today -> use CONTEXT_DATE resolution rule to the temporal system prompt; change is minimal and consistent with the new few-shot example.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[npm run setup] --> B{venv Python exists?}
    B -- No --> C[Create .venv via python -m venv]
    C --> D{pip available?}
    B -- Yes --> D
    D -- No --> E[Run ensurepip --upgrade]
    E --> F{pip now available?}
    F -- No --> G[FAIL: reinstall Python]
    F -- Yes --> H[pip install dependencies]
    D -- Yes --> H
    H --> I[Setup complete]
Loading

Comments Outside Diff (3)

  1. xmem-go/internal/api/auth.go, line 41-72 (link)

    P1 security JWT expiry (exp) never validated

    validateJWT verifies the HMAC signature and decodes the payload, but never inspects the exp claim. Any token that was legitimately issued in the past will continue to authenticate users indefinitely after it expires. An attacker who captures an old token (e.g., from logs or a leaked header) can reuse it forever.

    Fix in Cursor Fix in Codex Fix in Claude Code

  2. xmem-go/cmd/smoke_test/trace.go, line 1150-1227 (link)

    P2 PrintSummary reads shared state without holding the mutex

    mc.entries and mc.pipelineTimings are iterated without mc.mu.Lock(), while Record and RecordPipeline mutate those same fields under the lock on other goroutines. This is a data race even though the file carries //go:build ignore — running the trace tool alongside concurrent agent calls will produce non-deterministic output or a panic.

    Fix in Cursor Fix in Codex Fix in Claude Code

  3. xmem-go/internal/agents/temporal.go, line 13-16 (link)

    P2 daysInMonth treats February as always 29 days

    The map hard-codes February as 29, so isValidDate accepts 02-29 for any input, including years that are not leap years. Because the Event struct tracks Year separately, a non-leap-year event could be stored with an invalid date (e.g., Year: "2025", Date: "02-29") and later fail to parse or mismatch when correlated with calendar lookups.

    Fix in Cursor Fix in Codex Fix in Claude Code

Fix All in Cursor Fix All in Codex Fix All in Claude Code

Reviews (1): Last reviewed commit: "Repaired incomplete local virtualenv set..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant