Skip to content

fix: wire Firestore client and memory store into main.go (#126)#129

Merged
ComBba merged 2 commits into
mainfrom
fix/issue-126-firestore-init
Feb 25, 2026
Merged

fix: wire Firestore client and memory store into main.go (#126)#129
ComBba merged 2 commits into
mainfrom
fix/issue-126-firestore-init

Conversation

@ComBba

@ComBba ComBba commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Create Firestore client in main.go with NewClientWithDatabase using configured project/database
  • Initialize FirestoreStore and MemoryStore, inject into WebSocket handler
  • Wire MemoryStore into ToolHandler so recall_memory tool works at runtime
  • Persist session state to Firestore on WebSocket disconnect
  • Both stores gracefully fall back to in-memory when Firestore is unavailable

Issue

Closes #126

Local CI

  • go vet passed
  • go test -race -count=1 ./... passed (all packages)

Test plan

  • Existing handler tests pass with nil store parameters (in-memory fallback)
  • Runtime verification requires GCP credentials + Firestore access

🤖 Generated with Claude Code

- Create Firestore client in main.go with configured database
- Initialize FirestoreStore and MemoryStore, pass to WebSocket handler
- Wire MemoryStore into ToolHandler so recall_memory tool works at runtime
- Persist session state to Firestore on WebSocket disconnect
- Update tests for new RegisterWebSocket/handleWebSocket signatures

Closes #126

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Feb 25, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@ComBba has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 49 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 892f8e9 and 38c8625.

📒 Files selected for processing (3)
  • cmd/server/main.go
  • internal/handler/websocket.go
  • internal/handler/websocket_test.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/issue-126-firestore-init

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @ComBba, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request integrates Google Cloud Firestore for persistent storage of session data and memory, enhancing the application's state management capabilities. It introduces a Firestore client, initializes dedicated session and memory stores, and ensures these are properly wired into the WebSocket handling and tool management logic. A key aspect of this change is the implementation of a graceful fallback mechanism, allowing the application to continue functioning with in-memory stores if Firestore is not configured or accessible, thereby improving resilience.

Highlights

  • Firestore Client Integration: A Firestore client is now initialized in main.go using configured project and database IDs, with a fallback to nil if unavailable.
  • Session and Memory Store Initialization: FirestoreStore and MemoryStore instances are created and injected into the WebSocket handler.
  • Memory Store for ToolHandler: The MemoryStore is wired into the ToolHandler to enable the recall_memory tool.
  • Session State Persistence: Session state is now persisted to Firestore upon WebSocket disconnection.
  • Graceful Fallback: Both the session and memory stores are designed to gracefully fall back to in-memory operation if Firestore is not available.
Changelog
  • cmd/server/main.go
    • Added imports for cloud.google.com/go/firestore, internal/memory, and internal/store.
    • Implemented conditional initialization of a Firestore client based on ProjectID configuration.
    • Initialized FirestoreStore and MemoryStore instances.
    • Updated the handler.RegisterWebSocket call to pass the newly created sessionStore and memStore.
  • internal/handler/websocket.go
    • Added imports for internal/memory and internal/store.
    • Modified RegisterWebSocket and handleWebSocket function signatures to accept *store.FirestoreStore and *memory.Store parameters.
    • Updated slog.Info call to include has_session_store and has_memory_store status.
    • Conditionally set the MemoryStore on the ToolHandler.
    • Added logic to persist session state to Firestore on WebSocket disconnect if a sessionStore is available.
  • internal/handler/websocket_test.go
    • Updated calls to handleWebSocket in tests to pass nil for the new sessionStore and memStore parameters, maintaining existing test behavior.
Activity
  • The author confirmed go vet passed.
  • The author confirmed go test -race -count=1 ./... passed for all packages.
  • The author noted that existing handler tests pass with nil store parameters (in-memory fallback).
  • The author mentioned that runtime verification requires GCP credentials and Firestore access.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bcfa9385a7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

toolHandler.SetGenerator(sceneGen)
toolHandler.SetGenaiClient(client)
if memStore != nil {
toolHandler.SetMemoryStore(memStore, "")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Set persona ID when wiring memory store

recall_memory will never return results from the injected store because this initialization hard-codes an empty persona ID. In handleRecallMemory (internal/live/tools.go), the handler returns an empty memory list whenever pid == "", so any memories saved under real persona keys (for example from analysis) are unreachable at runtime even though memStore is present.

Useful? React with 👍 / 👎.

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

Copy link
Copy Markdown

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 wires up Firestore for session and memory persistence, with a graceful fallback to in-memory storage. The changes correctly initialize the Firestore client and inject the new stores into the WebSocket handler. My review focuses on a few areas for improvement: a critical issue with the recall_memory tool's implementation, incomplete session state persistence, and a minor maintainability point regarding a magic number. Addressing these will ensure the new persistence features are robust and fully functional.

toolHandler.SetGenerator(sceneGen)
toolHandler.SetGenaiClient(client)
if memStore != nil {
toolHandler.SetMemoryStore(memStore, "")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

The personaID passed to toolHandler.SetMemoryStore is an empty string. This will cause the recall_memory tool to be non-functional because the check for an empty personaID in handleRecallMemory will always pass, returning no results.

The personaID should be set on the toolHandler once it's known (likely after persona selection). This may require a mechanism for the session.Manager to update the toolHandler with the correct personaID when SetPersona is called.

Comment on lines +172 to +175
sd := &store.SessionData{
PersonaName: mgr.PersonaName(),
State: string(mgr.State()),
}

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 session state being persisted to Firestore is incomplete. It's missing fields like MatchedVoice, ReunionCount, and LanguageCode which are part of the session state managed by session.Manager.

This could lead to inconsistent state if the session is restored later. Consider saving all relevant session data.

Note that languageCode is currently a private field in session.Manager and would need a getter to be accessed here.

		sd := &store.SessionData{
			PersonaName:  mgr.PersonaName(),
			State:        string(mgr.State()),
			MatchedVoice: mgr.MatchedVoice(),
			ReunionCount: mgr.ReunionCount(),
		}

Comment thread cmd/server/main.go Outdated
}

sessionStore := store.NewFirestoreStore(cfg.ProjectID, firestoreClient)
memStore := memory.NewStore(100, firestoreClient)

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 value 100 for maxPerKey in memory.NewStore is a magic number. To improve readability and maintainability, consider defining this as a constant (e.g., const maxMemoriesPerPersona = 100) at the top of the file or in a relevant package, and using that constant here.

- Extract magic number 100 to maxMemoriesPerPersona constant
- Include MatchedVoice in persisted session data
- Use mgr.SessionID() instead of r.RemoteAddr as session key

Note: personaID is intentionally empty at connection time;
it will be set by the onboarding pipeline when persona is created.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 38c86257a9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +173 to +175
PersonaName: mgr.PersonaName(),
MatchedVoice: mgr.MatchedVoice(),
State: string(mgr.State()),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Populate session data from runtime state before persisting

handleWebSocket now writes PersonaName, MatchedVoice, and State from mgr on disconnect, but this handler never updates mgr after session.NewManager(...) (no SetPersona or state transitions are invoked in this code path), so persisted records will be saved as empty persona/voice and default onboarding state even after a real reunion flow. This makes the new Firestore persistence effectively incorrect for every session.

Useful? React with 👍 / 👎.

MatchedVoice: mgr.MatchedVoice(),
State: string(mgr.State()),
}
if err := sessionStore.SaveSession(saveCtx, mgr.SessionID(), sd); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use a stable session key when saving websocket state

The session is persisted under mgr.SessionID(), and in this handler that ID is initialized from r.RemoteAddr; source address/port values change across reconnects and can be reused, so saved state is not reliably tied to one logical user session and can be overwritten in multi-client or reconnect-heavy environments.

Useful? React with 👍 / 👎.

@ComBba ComBba merged commit a466a13 into main Feb 25, 2026
8 of 9 checks passed
@ComBba ComBba deleted the fix/issue-126-firestore-init branch February 25, 2026 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🟡 MEDIUM: main.go에 Firestore 클라이언트 초기화 누락

1 participant