惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
小众软件
小众软件
Vercel News
Vercel News
Last Week in AI
Last Week in AI
H
Help Net Security
The Cloudflare Blog
L
LangChain Blog
Microsoft Security Blog
Microsoft Security Blog
B
Blog RSS Feed
云风的 BLOG
云风的 BLOG
I
InfoQ
U
Unit 42
美团技术团队
人人都是产品经理
人人都是产品经理
雷峰网
雷峰网
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 叶小钗
Y
Y Combinator Blog
Hugging Face - Blog
Hugging Face - Blog
A
About on SuperTechFans
宝玉的分享
宝玉的分享
量子位
博客园_首页

Hacker News: Show HN

PurrrrrFocus: Pomodoro Timer App - App Store Workflow Engine — Multi-Step Orchestration for Bun RapidPhoto: Pro Photo Editor App - App Store GitHub - DheerG/swarms: Achieve extraordinary results with claude code across a variety of tasks SPICE simulation → oscilloscope → verification with Claude Code — Lucas Gerads Show HN: VCoding – A 5 MB native Windows IDE with no dynamic dependencies Show HN: LLMs don't hallucinate because they're bad at math, it's the format GitHub - Agent-FM/agentfm-core: AgentFM is a peer-to-peer network that turns everyday computers into a decentralized AI supercomputer. AgentFM lets you run massive AI workloads directly across a global mesh of idle CPUs and GPUs. Show HN: Tracking Top US Science Olympiad Alumni over Last 25 Years GitHub - Potarix/agent-hub: One place to talk to all your agents Show HN: Runtime security for AI agents(injection,tool abuse, data exfiltration) GitHub - dubeyKartikay/lazyspotify: Terminal Spotify client for macOS and Linux GitHub - the-banana-tool/king-louie: Easy to use GUI Personal AI Assistant. Win/Linux/Mac. Show HN I made my vacation rental bookable by AI agents–no Airbnb, 0% commission GitHub - basteez/jsf-autoreload: maven plugin to enable hot reload on jsf projects uvm32/hosts/host-gdbstub at main · ringtailsoftware/uvm32 GitHub - labsai/EDDI: Config-driven engine that turns JSON into production-grade AI agents. Multi-agent orchestration, 12+ LLM providers, MCP/A2A protocols, RAG, persistent memory, and enterprise compliance (EU AI Act, GDPR, HIPAA). Built on Quarkus. GitHub - glitchnsec/fortyone-oss: AI Executive Assistant Platform Quickstart | Alien GitHub - muxshed/shed: One stream in, or many. Every destination, simultaneously. No cloud middleman, no per-channel fees, no limits. GitHub - ocrbase-hq/ocrbase: 📄 PDF/IMG ->.MD/JSON Document OCR API for PaddleOCR and GLMOCR. Self-hostable. GitHub - impactjo/home-memory: MCP server that lets your AI assistant remember everything about your home. GitHub - Sets88/dbcls: DbCls is a powerful terminal database client that supports various databases GitHub - neptun2000/heor-agent-mcp GitHub - SeanFDZ/macmind: Single-layer transformer in HyperTalk for the classic Macintosh RollQuation: Math Puzzles - Apps on Google Play GitHub - dropbox/witchcraft Show HN: Agent-cache – Multi-tier LLM/tool/session caching for Valkey and Redis GitHub - opentalon/opentalon: OpenTalon is an open-source platform built from the ground up in Go as a robust alternative to OpenClaw LinkedIn™ 职位抓取工具 - Chrome 应用商店
GitHub - Tem-Degu/streetai-memory: Your AI's memory grows...
degutemesgen · 2026-05-24 · via Hacker News: Show HN

Street AI

Continuously learning memory layer for LLM applications. Your AI's memory grows forever. Your token bill doesn't.

Street AI sits between your application and the LLM API. It stores conversation as signals organized into stacks, decays old data automatically, and retrieves only what's relevant on each turn — so you send a tiny prompt instead of the full conversation history.

In our 16-turn benchmark, input tokens dropped by 55–80% per turn (average 68%), with the savings growing as the conversation lengthens.

Status

Alpha (0.2.0). API will change. Pin a version if you depend on it.

Install

pip install streetai-memory

The PyPI name is streetai-memory; the import path is streetai:

from streetai import Memory, MemoryRegistry, Config

First use downloads a ~90MB embedding model (all-MiniLM-L6-v2) into a local cache.

To install with provider adapters:

pip install "streetai-memory[anthropic]"  # Anthropic
pip install "streetai-memory[openai]"     # OpenAI (also DeepSeek, Together, Groq)
pip install "streetai-memory[gemini]"     # Google Gemini
pip install "streetai-memory[all]"        # all of the above

Quickstart

from streetai import MemoryRegistry

registry = MemoryRegistry("./memory.db")
mem = registry.get("user_123")

mem.add_message("Hi, I'm planning a trip to Japan.", role="user")
mem.add_message("Great! Which cities?", role="assistant")

prompt = mem.build_prompt("What did I say about Japan?")

# prompt.messages   -> list of {role, content} ready for any LLM API
# prompt.retrieved  -> signals that were pulled in (pass to post_process)
# prompt.inspector  -> debug info (stacks activated, scores, etc.)

# After your LLM responds:
# response_text = your_llm(messages=prompt.messages)
# mem.post_process(prompt.retrieved, response_text)
# mem.add_message("What did I say about Japan?", role="user")
# mem.add_message(response_text, role="assistant")

For a fully runnable version, see examples/quickstart.py.

Memory IDs and persistence. Each memory_id is a separate, persistent memory. Use one per user or session (they never leak into each other). Memory is saved to the SQLite file you pass (./memory.db above) and reloads automatically on the next run, so it survives restarts and across processes.

To wipe one memory (for example on a "clear chat" action or account deletion):

registry.reset("user_123")

Editing or deleting a specific past message. Each call to mem.add_message returns the created signals; each signal carries a parent_turn_id that identifies the whole message. Store that id alongside the message in your display DB, then use it when a user edits or deletes:

created = mem.add_message("I am vegetarian", role="user")
pid = created[0].parent_turn_id

mem.update_message(pid, "I am vegan")   # in-place edit; keeps the same turn
mem.delete_message(pid)                  # remove the message entirely

Drop-in adapters

The adapters wrap a real provider client. You use the same SDK API you already know; memory is read and written transparently on every call.

Anthropic

from anthropic import Anthropic
from streetai.adapters.anthropic import with_memory

client = with_memory(Anthropic(), memory_id="user_123")

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system="You are helpful.",
    messages=[{"role": "user", "content": "What did I mention earlier?"}],
)
print(response.content[0].text)

Full example: examples/anthropic_chat.py.

OpenAI

from openai import OpenAI
from streetai.adapters.openai import with_memory

client = with_memory(OpenAI(), memory_id="user_123")

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "What did I mention earlier?"}],
)
print(response.choices[0].message.content)

Full example: examples/openai_chat.py.

DeepSeek (uses the OpenAI adapter)

DeepSeek is OpenAI-API-compatible. Use the OpenAI adapter with base_url:

import os
from openai import OpenAI
from streetai.adapters.openai import with_memory

deepseek = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com/v1",
)
client = with_memory(deepseek, memory_id="user_123")

response = client.chat.completions.create(
    model="deepseek-chat",
    messages=[{"role": "user", "content": "What did I mention earlier?"}],
)

The same pattern works for Together, Anyscale, Groq, and any other OpenAI-compatible endpoint. Full example: examples/deepseek_chat.py.

Google Gemini

from google import genai
from streetai.adapters.gemini import with_memory

client = with_memory(genai.Client(api_key="..."), memory_id="user_123")

response = client.models.generate_content(
    model="gemini-2.0-flash",
    contents="What did I mention earlier?",
)
print(response.text)

Full example: examples/gemini_chat.py.

Async

Every adapter has an async equivalent. Pass an async client; use await. Memory operations are wrapped in asyncio.to_thread.

# Anthropic
from anthropic import AsyncAnthropic
from streetai.adapters.anthropic import with_memory_async
client = with_memory_async(AsyncAnthropic(), memory_id="user_123")
response = await client.messages.create(model="claude-sonnet-4-6",
    max_tokens=1024, messages=[{"role": "user", "content": "..."}])

# OpenAI (and DeepSeek via base_url)
from openai import AsyncOpenAI
from streetai.adapters.openai import with_memory_async
client = with_memory_async(AsyncOpenAI(), memory_id="user_123")
response = await client.chat.completions.create(model="gpt-4o-mini",
    messages=[{"role": "user", "content": "..."}])

# Gemini (uses the existing client's .aio namespace internally)
from google import genai
from streetai.adapters.gemini import with_memory_async
client = with_memory_async(genai.Client(api_key="..."), memory_id="user_123")
response = await client.models.generate_content(model="gemini-2.0-flash",
    contents="...")

Editing or deleting from an adapter

The wrapper exposes a .memory property, so any Memory method works on the client. Each adapter call stores two signals (user, then assistant), so read the parent_turn_id from client.memory.signals after the call:

resp = client.messages.create(model="claude-sonnet-4-6",
    max_tokens=512, messages=[{"role": "user", "content": "I am vegetarian"}])

user_pid = client.memory.signals[-2].parent_turn_id
client.memory.update_message(user_pid, "I am vegan")
client.memory.delete_message(user_pid)

How it works

your message
     |
     v
[1] split into chunks (sentence-sized signals)
     |
     v
[2] embed each chunk to a 384-dim vector
     |
     v
[3] assign to a stack (cluster of related signals) by cosine similarity
     |
     v
[4] when a new query arrives:
       - find top-K most relevant stacks (FAISS)
       - within those stacks, surface signals that pass the activation threshold
       - faded signals stay out — unless they're a strong match, which revives them
     |
     v
[5] build a small prompt:
       [retrieved context] + [last N messages verbatim] + [new query]
     |
     v
[6] after the LLM responds:
       - boost signals that matched the response (they helped)
       - demote signals that didn't (they were noise)
       - decay continues until the signal is used again

Decay is measured in interactions, not wall-clock time, so memory survives long idle periods. Signals refresh their clock when retrieved; frequently useful data stays sharp, unused data fades.

Compared to plain chat history

Plain chat history Street AI
Prompt grows with conversation Yes (linear) No (near flat)
Recent context kept verbatim Yes Yes (recency window)
Activity-aware (decay) No Yes (per interaction)
Learns from outcomes No Yes (boost/demote)
Self-organizing No Yes (auto-stacks)
Cross-provider Yes Yes

Configuration

Override defaults with Config:

import math
from streetai import MemoryRegistry, Config

cfg = Config(
    recency_turns=5,             # last 5 messages verbatim (default 3)
    decay_rate=math.log(2)/100,  # 100-interaction half-life (default 50; decay is per-turn)
    stack_threshold=0.65,        # tighter stack assignment (default 0.55)
    activation_threshold=0.1,    # min score for a signal to surface (default 0.15)
    revival_similarity=0.45,     # a faded signal revives on a match this strong (0 disables)
)

registry = MemoryRegistry("./memory.db", config=cfg)

All tunables: see streetai/config.py.

Limitations (v0.2)

  • Non-streaming only. stream=True raises NotImplementedError.
  • English-tuned defaults. Chunking and thresholds may need tuning for other languages.
  • fastembed is required. Pluggable encoders come in a future version.

Development

git clone https://github.com/Tem-Degu/streetai-memory.git
cd streetai-memory
pip install -e ".[dev]"
pytest

Documentation

Full documentation at StreetAI Memory.

License

Apache 2.0