<@ULVA73B9P> can you give me an example of best pr...
# ask-marvin
d
@Marvin can you give me an example of best practice to recalling marvin.Memory from within a tool. Example, I have a tool that generates sql, I will collect the user’s id from context and use that to retrieve sql preferences from the user.
m
thought for 332.0 seconds
Great question. The short version: inside a tool, create a Memory with a stable, namespaced key derived from the user id, then call
mem.get_prompt()
to retrieve the user’s stored preferences and condition your SQL generation. Use
mem.add()
to update preferences and
mem.delete()
to remove a specific entry. Here’s a concrete pattern you can copy: - Namespacing:
user:{user_id}:sql-prefs
- Provider: use a persistent provider (e.g., Postgres) for cross-process persistence, or stick with the default if you don’t need persistence - Keep
auto_use=False
and explicitly fetch memory within the tool so it only impacts this tool’s behavior Example: SQL generation tool that recalls user preferences
Copy code
from marvin import fn, generate, Memory
from marvin.memory.providers.postgres import PostgresMemory

# Helper: build a memory for this user's SQL preferences
def user_sql_memory(user_id: str) -> Memory:
    return Memory(
        key=f"user:{user_id}:sql-prefs",
        instructions="User-specific SQL style and access preferences.",
        # Use a persistent provider for multi-instance deployment.
        # You can omit 'provider=' to use the default from settings (chroma-ephemeral).
        provider=PostgresMemory(),
        auto_use=False,  # keep it opt-in for this tool only
    )

# Optional helpers to write/update preferences
def add_sql_preference(user_id: str, preference_text: str) -> str:
    """
    Store a new preference (returns a memory_id for later deletion).
    Example content: 
      - "Prefer snake_case identifiers"
      - "Only use tables in the 'analytics' schema"
      - "Target dialect: postgres"
    """
    mem = user_sql_memory(user_id)
    return mem.add(preference_text)

def delete_sql_preference(user_id: str, memory_id: str) -> None:
    mem = user_sql_memory(user_id)
    mem.delete(memory_id)

# The tool: it fetches the user's preferences and applies them to SQL generation
@fn(instructions="Generate SQL queries; respect any user-specific preferences when present.")
def generate_sql(user_id: str, task: str) -> str:
    mem = user_sql_memory(user_id)
    prefs_snippet = mem.get_prompt().strip()  # textual summary of stored prefs

    base_guidance = (
        "Return only valid SQL. If preferences are present, conform to them "
        "(dialect, naming, schemas, CTE style, etc.)."
    )
    conditioning = f"{base_guidance}\n\n{prefs_snippet}" if prefs_snippet else base_guidance

    # Drive the LLM with Marvin's generate and the recalled memory
    return generate(
        f"{conditioning}\n\nTask: {task}\n\nOutput: SQL only."
    )
Notes and best practices - Stable keys: Use a deterministic, namespaced key (e.g.,
user:{user_id}:sql-prefs
). This makes it trivial to recall the right memory in any tool or agent. - Keep preferences concise: Store small, focused facts or a short policy. It makes
get_prompt()
cleaner and easier for the LLM to apply. - Structured preferences: If you want programmatic handling, store a single JSON blob as the canonical preference and update it in-place (delete older entries). Then parse that JSON in your tool after
get_prompt()
extraction. Otherwise, let the LLM consume the plain-text summary. - Provider choice: - Default (chroma-ephemeral): great for quick experiments, not persistent across processes. - PostgresMemory: recommended for persistence and multi-instance use. - You can also set the default via env (e.g.,
MARVIN_MEMORY_PROVIDER=postgres
) if you don’t want to pass
provider=
everywhere. - Auto-use vs. explicit: Use
auto_use=False
and fetch explicitly in tools if you only want these preferences to affect SQL generation, not all agent turns. Getting the user id in context - Easiest and most reliable is to pass
user_id
as a parameter to the tool (as shown). - If you already have it in your app/session, you can centralize the memory-construction helper.
- If you’re relying on agent/thread context, you can look into
marvin.agents.actor.get_current_actor()
or
marvin.thread.get_current_thread()
and derive a key from available metadata. Passing it explicitly is clearer and test-friendly. API references and docs - Memory class: API: marvin.memory - Concepts: Concepts: Memory - Patterns: Patterns: Memory usage - Providers (Postgres, Chroma, etc.): - PostgresMemory - ChromaMemory Would you like an example that maintains a single JSON preference blob per user (and how to update/parse it safely), or is the plain-text preference style sufficient for your use case?