MemoSift

PYTHON SDK

Python SDK Reference.

The memosift package on PyPI. Tool-result interception, persistent memory, and 7 framework adapters in one install.

terminal
pip install memosift

Pick your mode

Compare in detail

By mode — code patterns

The same SDK serves all three integration modes. Pick the one your agent needs and use the matching pattern.

Mode A

Inspector

Local-only primitives — no cloud, no API key. Free under MIT.

# Pure local — no MemoSift instance needed
from memosift.classifier import classify
from memosift.metadata import extract_metadata
from memosift.security import scan
from memosift.types import SecurityMode

content_type = classify(my_tool_output)
metadata = extract_metadata(my_tool_output, content_type)

result = scan(my_tool_output, mode=SecurityMode.REDACT)
print(result.content)        # secrets masked
print(result.findings)       # list of SecurityFinding
Mode B

Sidecar

Push turns to the cloud, recall across sessions. No tool-result mutation.

# Track + recall against the MemoSift cloud
import os
from memosift import MemoSift

ms = MemoSift(
    api_key=os.environ["MEMOSIFT_API_KEY"],
    base_url="https://dev.memosift.com",
)

# After each turn:
await ms.track(messages, session_id="my-session")

# When you need recall:
result = await ms.recall(query="user's question", session_id="my-session")
for item in result.items:
    print(item.content[:120])
Mode C

Co-pilot

Adapter wraps the LLM client; large tool results auto-stub in the model's view.

# Tool results above ~2 KB are silently replaced with artifact stubs
from anthropic import AsyncAnthropic
from memosift import MemoSift

ms = MemoSift(
    api_key=os.environ["MEMOSIFT_API_KEY"],
    base_url="https://dev.memosift.com",
)
client = ms.wrap_anthropic(AsyncAnthropic(), session_id="my-session")

# Use `client` exactly like the original Anthropic SDK.
response = await client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    messages=[...],
)

MemoSift()

#
MemoSift(api_key: str, base_url: str = "https://dev.memosift.com", timeout: float = 30.0)

Create a MemoSift client. The API key is required and can be generated from the dashboard or CLI. All subsequent calls use this client instance.

NameTypeDescription
api_keystrYour MemoSift API key. Starts with "msk_".
base_urlstrAPI base URL. Override for self-hosted deployments.
timeoutfloatHTTP request timeout in seconds. Default 30.
setup.py
from memosift import MemoSift

ms = MemoSift(api_key="msk_live_abc123")

# Self-hosted
ms = MemoSift(
    api_key="msk_live_abc123",
    base_url="https://memosift.internal.corp",
    timeout=60.0,
)

Returns

MemoSift

  • session()Create session-bound client
  • intercept()Intercept tool results
  • recall()Hybrid memory recall

session()

#
session(session_id: str) → MemoSiftSession

Returns a session-bound client that pre-fills session_id on all subsequent calls. Recommended for most workflows.

NameTypeDescription
session_idstrUnique identifier for this conversation session.
example.py
session = ms.session("conv_2024_04_18_a")

# All calls now use session_id automatically
result = await session.intercept(content, tool_name="bash")
await session.track(messages)
memories = await session.recall("auth decisions")

Returns

MemoSiftSession

  • session_idThe bound session identifier

intercept()

#
intercept(content: str | bytes, *, tool_name: str, session_id: str, security_mode: SecurityMode = REDACT, security_config: SecurityConfig | None = None) → InterceptResult

Runs the 5-stage local pipeline on tool output: strip reasoning, security scan, size gate, classify, and metadata extraction. Content under 500 chars passes through unchanged. Content 500+ chars creates an artifact. Content 2000+ chars is replaced with a summary.

NameTypeDescription
contentstr | bytesRaw tool output to intercept.
tool_namestrName of the tool that produced this output (e.g. "read_file").
session_idstrSession identifier.
security_modeSecurityModeREDACT (default), BLOCK, or PASSTHROUGH. Controls how security findings are handled.
security_configSecurityConfig | NoneFine-grained security rules: allow-lists, redaction patterns, and confidence thresholds.
intercept.py
result = await ms.intercept(
    tool_output,
    tool_name="read_file",
    session_id="my-session",
    security_mode=SecurityMode.REDACT,
)

# result.agent_facing_content  → summary or raw
# result.replaced              → True if content was replaced
# result.artifact               → ArtifactRecord if stored
# result.content_type          → ContentType enum
# result.security_findings     → tuple of SecurityFinding

Returns

InterceptResult

  • agent_facing_contentThe processed content to return to the agent
  • replacedTrue if content was replaced with a summary
  • artifactArtifactRecord if content was stored
  • content_typeClassified ContentType enum
  • security_findingsTuple of SecurityFinding objects
  • metadataExtracted metadata dict

track()

#
track(messages: list[dict], *, session_id: str, intercept_results: Sequence[InterceptResult] | None = None) → None

Ships a conversation turn to the MemoSift cloud. If the cloud is unreachable, the turn is queued locally (up to 1000 items) and retried automatically. Attach intercept results to link artifacts with the turn.

NameTypeDescription
messageslist[dict]OpenAI-format message dicts with role and content.
session_idstrSession identifier.
intercept_resultsSequence[InterceptResult] | NoneIntercept results from this turn, to link artifacts.
track.py
await ms.track(
    [
        {"role": "user", "content": "Read the auth module"},
        {"role": "assistant", "content": "Here's the code..."},
    ],
    session_id="my-session",
    intercept_results=[result],
)

Returns

None


recall()

#
recall(query: str | None = None, *, session_id: str, limit: int = 10, scope: str = "session", mode: str = "fast", filters: RecallFilters | None = None, intent_weights: dict[int, float] | None = None, query_embedding: list[float] | None = None, intent_version: int | None = None, turn: int | None = None) → RecallResult

Retrieves memories from the session or project. Supports three mutually exclusive modes: query (text search), intent_version (goal epoch retrieval), and turn (temporal snapshot). Exactly one mode parameter must be provided.

NameTypeDescription
querystr | NoneNatural language search query. Triggers query mode.
session_idstrSession identifier.
limitintMax number of results to return. Default 10.
scopestr"session" (default) or "project". Project scope searches across all sessions.
modestr"fast" (default) or "deep". Deep mode uses re-ranking for higher quality.
filtersRecallFilters | NoneFilter by content types, entities, topics, tags, turn range, or intent version.
intent_weightsdict[int, float] | NoneCustom weights for intent version scoring.
query_embeddinglist[float] | NonePre-computed embedding vector. Skips server-side embedding.
intent_versionint | NoneRetrieve memories for a specific intent epoch. Triggers intent mode.
turnint | NoneRetrieve memories active at a specific turn number. Triggers temporal mode.
recall_query.py
# Query mode
result = await ms.recall(
    "auth middleware decisions",
    session_id="s1",
    scope="project",
    mode="deep",
)
recall_intent.py
# Intent mode
result = await ms.recall(intent_version=2, session_id="s1")
recall_temporal.py
# Temporal mode
result = await ms.recall(turn=15, session_id="s1")

Returns

RecallResult

  • itemsList of RecallItem matches
  • total_availableTotal matching items (before limit)
  • session_intentCurrent session intent summary
  • diagnosticsTiming and scoring diagnostics

explore()

#
explore(item_id: str, *, kind: Literal["memory", "artifact", "proposition"], session_id: str, limit: int = 10) → ExploreResult

Multi-axis graph exploration from a given anchor item. Returns connected entities, related artifacts, temporal neighbors, and intent connections.

NameTypeDescription
item_idstrID of the anchor item to explore from.
kind"memory" | "artifact" | "proposition"Type of the anchor item.
session_idstrSession identifier.
limitintMax connections per axis. Default 10.
explore.py
related = await ms.explore(
    item_id="mem_4f8a2c",
    kind="memory",
    session_id="s1",
    limit=5,
)

for item in related.items:
    print(f"{item.via}: {item.content[:80]}")

Returns

ExploreResult

  • anchor_idID of the anchor item
  • anchor_kindType of the anchor item
  • itemsConnected items, each with a via field indicating the connection axis

fetch()

#
fetch(artifact_id: str) → FetchResult

Retrieves artifact metadata and content. For artifacts under 500KB, the content is returned inline as base64. For larger artifacts, a signed download URL is provided.

NameTypeDescription
artifact_idstrArtifact identifier (e.g. "art_7f2a3b").
fetch.py
content = await ms.fetch("art_7f2a3b")

if content.bytes_b64:
    raw = base64.b64decode(content.bytes_b64)
elif content.download_url:
    # Stream large artifacts
    async with httpx.AsyncClient() as client:
        resp = await client.get(content.download_url)

Returns

FetchResult

  • artifact_idThe artifact identifier
  • artifact_typeMIME type or content classification
  • byte_sizeSize in bytes
  • download_urlSigned URL for large artifacts (>500KB)
  • bytes_b64Base64-encoded content for small artifacts
  • summaryGenerated summary of the artifact

compress()

#
compress(*, session_id: str) → CompressResult

Assembles a compressed context window for the session. Uses pure SQL and template rendering with no LLM calls. Completes in under 50ms.

NameTypeDescription
session_idstrSession to assemble context for.
compress.py
compressed = await ms.compress(session_id="s1")

# Use as system prompt or prepend to messages
system_msg = {"role": "system", "content": compressed.rendered_text}

# Or use the structured representation
for section in compressed.structured:
    print(f"{section.label}: {len(section.content)} chars")

Returns

CompressResult

  • rendered_textReady-to-use compressed context string
  • structuredStructured sections with labels and content
  • diagnosticsAssembly timing and stats

get_at_turn()

#
get_at_turn(session_id: str, turn: int) → SessionSnapshot

Bi-temporal snapshot of the session at a specific turn. Returns the intent that was active, memories that existed, and artifacts that had been seen up to that point.

NameTypeDescription
session_idstrSession identifier.
turnintTurn number to snapshot.
get_at_turn.py
snapshot = await ms.get_at_turn("s1", turn=15)

print(snapshot.intent_at_turn)
print(f"Memories active: {len(snapshot.memories_active_at_turn)}")
print(f"Artifacts seen: {len(snapshot.artifacts_seen_by_turn)}")

Returns

SessionSnapshot

  • intent_at_turnThe intent version active at this turn
  • memories_active_at_turnMemories that existed at this turn
  • artifacts_seen_by_turnArtifacts created or referenced by this turn

get_intent()

#
get_intent(*, session_id: str) → SessionIntent

Retrieves the full intent history for a session, including all versions and the turn each was derived at. Useful for understanding how the conversation goal evolved.

NameTypeDescription
session_idstrSession identifier.
get_intent.py
intent = await ms.get_intent(session_id="s1")

for version in intent.versions:
    print(f"v{version.version} (turn {version.derived_at_turn}): {version.summary}")

Returns

SessionIntent

  • versionsList of intent versions with summary and derived_at_turn

Framework adapters

Each adapter wires MemoSift into the framework's native extension point \u2014 proxies for OpenAI / Anthropic, callback handlers for LangChain, hook wrappers for Claude Agent SDK, and so on. Tool results flow through interception transparently.

Anthropic

ms.wrap_anthropic(...)

pip install "memosift[anthropic]"

Proxy on messages.create / messages.stream. Walks tool_result content blocks pre-flight; mutates oversized blocks in place with artifact stubs.

from anthropic import AsyncAnthropic
from memosift import MemoSift

ms = MemoSift(api_key="msk_...", base_url="https://dev.memosift.com")
client = ms.wrap_anthropic(AsyncAnthropic(), session_id="my-session")

response = await client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    messages=[...],
)

OpenAI

ms.wrap_openai(...)

pip install "memosift[openai]"

Proxies both chat.completions.create (intercepts role=tool messages) AND responses.create (intercepts function_call_output entries).

from openai import AsyncOpenAI

client = ms.wrap_openai(AsyncOpenAI(), session_id="my-session")

response = await client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "user", "content": "fetch data"},
        {"role": "tool", "name": "csv_fetch", "tool_call_id": "c1", "content": csv_data},
    ],
)

OpenAI Agents SDK

ms.openai_agents_tool_wrapper(...)

Decorator that wraps async tool functions to intercept their outputs.

intercept = ms.openai_agents_tool_wrapper(session_id="my-session")

@intercept
async def fetch_data(query: str) -> str:
    return long_csv_content

Claude Agent SDK

ms.claude_agent_hooks(...)

Returns a PostToolUse hooks dict \u2014 the Claude Agent SDK's native hook system.

from claude_agent_sdk import ClaudeAgentOptions

options = ClaudeAgentOptions(hooks=ms.claude_agent_hooks())

LangChain

ms.langchain_callback(...)

pip install "memosift[langchain]"

Returns an AsyncCallbackHandler \u2014 LangChain's native callback protocol. Pass via callbacks=[...] to any chain, agent, or tool.

from langchain_openai import ChatOpenAI

handler = ms.langchain_callback(session_id="my-session")
llm = ChatOpenAI(callbacks=[handler])

LangGraph

ms.langgraph_wrapper(...)

Returns an awrap_tool_call function for LangGraph's ToolNode.

from langgraph.prebuilt import ToolNode

tool_node = ToolNode(tools=my_tools, awrap_tool_call=ms.langgraph_wrapper())

Generic

ms.wrap_generic(...)

Configurable Proxy-based wrapper for any client. Declare which methods to intercept and supply an extract function.

from memosift.adapters import ExtractedToolResult

def extract(result, ctx):
    return [ExtractedToolResult(tool_name="my_tool", content=str(result))]

wrapped = ms.wrap_generic(
    my_client,
    session_id="my-session",
    methods=["chat.completions.create"],
    extract=extract,
)

TYPES

Key Types

Data classes returned by SDK methods. All fields are typed and accessible as attributes.

InterceptResult

agent_facing_contentstrProcessed content for the agent
replacedboolTrue if original content was replaced with summary
artifactArtifactRecord | NoneStored artifact record, if created
content_typeContentTypeClassified content type enum
security_findingstuple[SecurityFinding, ...]Security scan results
metadatadictExtracted metadata (entities, topics, etc.)

RecallResult

itemslist[RecallItem]Matching memory items
total_availableintTotal matches before limit
session_intentstr | NoneCurrent session intent summary
diagnosticsdictTiming and scoring details

RecallItem

idstrUnique item identifier
kindstr"memory", "artifact", or "proposition"
contentstrItem content or summary
scorefloatRelevance score (0-1)
intent_alignmentfloat | NoneAlignment with current intent
turn_numberintTurn when this item was created
artifact_metadict | NoneArtifact metadata if kind is artifact
related_entitieslist[str]Entity names linked to this item

ExploreResult

anchor_idstrID of the anchor item
anchor_kindstrType of the anchor item
itemslist[ExploreItem]Connected items with via field

FetchResult

artifact_idstrArtifact identifier
artifact_typestrMIME type or content classification
byte_sizeintSize in bytes
download_urlstr | NoneSigned URL for large artifacts
bytes_b64str | NoneBase64 content for small artifacts
summarystrGenerated summary

CompressResult

rendered_textstrCompressed context string
structuredlist[Section]Structured sections
diagnosticsdictAssembly timing and stats

SecurityConfig

allowlist[str]Patterns to allow through without scanning
redactlist[str]Patterns to always redact
min_confidencefloatMinimum confidence threshold for findings (0-1)

RecallFilters

content_typeslist[str] | NoneFilter by content type
entitieslist[str] | NoneFilter by entity name
topicslist[str] | NoneFilter by topic
tagslist[str] | NoneFilter by tag
turn_range_fromint | NoneStart of turn range (inclusive)
turn_range_toint | NoneEnd of turn range (inclusive)
intent_versionint | NoneFilter to specific intent epoch