Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
93fe020
chore(ci): add Python SDK pytest workflow
Dhravya Aug 8, 2026
be267c2
feat(web): automation connection warnings and calmer automations page…
MaheshtheDev Aug 10, 2026
59b148e
feat(web): sell Company Brain on Max as well as Scale (#1440)
MaheshtheDev Aug 10, 2026
a7efd81
fix(validation): reject non-positive page/limit in pagination query s…
abhay-codes07 Aug 12, 2026
f163c93
fix(web): keep highlights card active index in range on refresh (#1334)
abhay-codes07 Aug 12, 2026
74b2201
fix(memory-graph): stop painting expired memories as expiring (#1335)
abhay-codes07 Aug 12, 2026
14bcc92
fix(memory-graph): center arrow-key navigation in the visible graph a…
abhay-codes07 Aug 12, 2026
47152af
fix(openai-sdk): cap supermemory to <3.5 so a fresh install imports (…
Cintu07 Aug 12, 2026
00e57fb
fix(web): stop formatUsageNumber rendering 1000.0K at unit boundaries…
abhay-codes07 Aug 12, 2026
b7a6ea9
fix(extension): stop fragmenting Included Memories that contain comma…
abhay-codes07 Aug 12, 2026
c70c142
fix(web): open Slack install in new window (#1460)
Dhravya Aug 12, 2026
0695ca4
feat(web): take a card before the Company Brain trial starts (#1459)
MaheshtheDev Aug 13, 2026
fcf4985
Upgrade Nova model picker to current runtime models (#1404)
ishaanxgupta Aug 13, 2026
1356aff
fix(extension): finish Included Memories leftovers on T3 (#1257) (#1421)
HaoChiBao Aug 13, 2026
9d64e0f
fix: add type checks for TypeScript workspaces (#1447)
abhinavkr26104 Aug 13, 2026
7f448d5
docs: document pinned install for supermemory-server (#1238)
dupenodi Aug 13, 2026
82dae50
fix(tools): bound memory forget requests (#1451)
abhinavkr26104 Aug 13, 2026
eac0700
feat(web): add memory button to company brain navbar (#1468)
Dhravya Aug 14, 2026
2e85722
Clarify Company Brain trial copy (#1469)
MaheshtheDev Aug 14, 2026
9cbddce
docs: historical backfill guide (#1474)
Prasanna721 Aug 14, 2026
5ecbc26
fix(mcp): surface real API error messages instead of 'restricted or b…
Dhravya Aug 14, 2026
e651045
Remove paid plugin UI (#1403)
ishaanxgupta Aug 15, 2026
d14b209
feat(web): support discount code checkout (#1523)
Dhravya Aug 16, 2026
5d2b585
feat(auth): AgentID sign-in button on the web login page (#1467)
Dhravya Aug 16, 2026
e2be9c9
Fix integrations layout and mobile promo responsiveness (#1481)
ishaanxgupta Aug 17, 2026
f68bd30
Merge origin/main into fix/openai-sdk-python-v4-api
cursoragent Aug 18, 2026
c0eb81c
refactor(brain): one isCompanyBrainOrg helper in the web app (#1535)
MaheshtheDev Aug 18, 2026
149589a
fix(brain): keep the confirmed company domain after checkout return (…
MaheshtheDev Aug 18, 2026
18a2dfb
feat(mcp): accept Supermemory API keys as Bearer auth (#1537)
Dhravya Aug 19, 2026
7d59070
fix(web): scope the ?view=mcp guest exemption to / (#1553)
rajarshidattapy Aug 19, 2026
20410a6
fix(ui): remove the unused, broken AnonymousAuth component (#1555)
rajarshidattapy Aug 19, 2026
7b1175c
fix(browser-extension): run wxt prepare before type checking (#1557)
addyCooks Aug 19, 2026
818a83a
fix(mcp): strip API extras from listMemories entries (#1539)
Dhravya Aug 19, 2026
dda56e7
Add plugin CLI command guide to integrations (#1534)
ishaanxgupta Aug 20, 2026
3487666
feat(web): add MCP connector directory (#1461)
Dhravya Aug 20, 2026
183e9fb
fix(openai-sdk-python): harden v4 migration
ved015 Aug 21, 2026
7eca7c7
Merge remote-tracking branch 'origin/main' into fix/openai-sdk-python…
ved015 Aug 21, 2026
7cf0480
fix(openai-sdk-python): harden 7-tool parity
ved015 Aug 21, 2026
006a3f5
chore(ci): harden Python SDK test workflow
ved015 Aug 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
239 changes: 239 additions & 0 deletions .github/workflows/ci-python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
name: CI - Python SDKs

on:
pull_request:
paths:
- "packages/agent-framework-python/**"
- "packages/cartesia-sdk-python/**"
- "packages/openai-sdk-python/**"
- "packages/pipecat-sdk-python/**"
- ".github/workflows/ci-python.yml"

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

env:
PIP_DISABLE_PIP_VERSION_CHECK: "1"

jobs:
agent-framework-python:
name: agent-framework-python (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.13"]
defaults:
run:
working-directory: packages/agent-framework-python
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Setup Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: packages/agent-framework-python/pyproject.toml

- name: Install build and test tools
run: python -m pip install build pytest pytest-asyncio

- name: Build wheel
run: python -m build --wheel --outdir "$RUNNER_TEMP/wheels"

- name: Install wheel and runtime dependencies
run: python -m pip install "$RUNNER_TEMP"/wheels/*.whl

- name: Check dependency compatibility
run: python -m pip check

- name: Verify installed wheel
run: >-
python -c "from pathlib import Path; import supermemory_agent_framework;
assert 'site-packages' in Path(supermemory_agent_framework.__file__).parts"

- name: Run tests
run: python -m pytest

openai-sdk-python:
name: openai-sdk-python (${{ matrix.dependency-lane }}, Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- python-version: "3.9"
dependency-lane: minimum-supermemory
supermemory-version: "3.50.0"
expected-supermemory-version: "3.50.0"
- python-version: "3.12"
dependency-lane: locked
supermemory-version: ""
expected-supermemory-version: "3.59.0"
defaults:
run:
working-directory: packages/openai-sdk-python
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Setup Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ matrix.python-version }}

- name: Setup uv
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
version: "0.12.5"
enable-cache: true
working-directory: packages/openai-sdk-python
cache-dependency-glob: uv.lock

- name: Install locked dependencies
run: uv sync --locked --python "${{ matrix.python-version }}"

- name: Build wheel
run: uv build --wheel --out-dir "$RUNNER_TEMP/wheels"

- name: Install built wheel
run: >-
uv pip install --python .venv/bin/python --reinstall --no-deps
"$RUNNER_TEMP"/wheels/*.whl

- name: Install minimum Supermemory SDK
if: matrix.supermemory-version != ''
run: >-
uv pip install --python .venv/bin/python
"supermemory==${{ matrix.supermemory-version }}"

- name: Check dependency compatibility
run: uv pip check --python .venv/bin/python

- name: Verify installed wheel and SDK version
run: >-
.venv/bin/python -c "from importlib.metadata import version;
from pathlib import Path; import supermemory_openai;
assert version('supermemory') == '${{ matrix.expected-supermemory-version }}';
assert 'site-packages' in Path(supermemory_openai.__file__).parts"

- name: Run tests without changing the verified environment
run: .venv/bin/python -m pytest

cartesia-sdk-python:
name: cartesia-sdk-python (${{ matrix.dependency-lane }}, Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- python-version: "3.10"
dependency-lane: minimum-supermemory
supermemory-spec: "supermemory==3.16.0"
supermemory-version: "3.16.0"
- python-version: "3.12"
dependency-lane: current-supermemory
supermemory-spec: "supermemory==3.59.0"
supermemory-version: "3.59.0"
defaults:
run:
working-directory: packages/cartesia-sdk-python
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Setup Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: packages/cartesia-sdk-python/pyproject.toml

- name: Install build tools and lightweight test dependencies
run: >-
python -m pip install build pytest "loguru>=0.7.3" "pydantic>=2.10.0"
"${{ matrix.supermemory-spec }}"

- name: Build wheel
run: python -m build --wheel --outdir "$RUNNER_TEMP/wheels"

- name: Install wheel without the voice framework
run: python -m pip install --no-deps "$RUNNER_TEMP"/wheels/*.whl

- name: Run tests against the installed wheel and real lightweight dependencies
run: >-
python -c "from importlib.metadata import version;
from pathlib import Path; import loguru, pydantic, supermemory, pytest;
assert version('supermemory') == '${{ matrix.supermemory-version }}';
result = pytest.main(['-W', 'ignore::pytest.PytestAssertRewriteWarning', 'tests']);
import supermemory_cartesia;
assert 'site-packages' in Path(supermemory_cartesia.__file__).parts;
raise SystemExit(result)"

pipecat-sdk-python:
name: pipecat-sdk-python (${{ matrix.dependency-lane }}, Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- python-version: "3.10"
dependency-lane: minimum-supermemory
supermemory-spec: "supermemory==3.16.0"
supermemory-version: "3.16.0"
- python-version: "3.12"
dependency-lane: current-supermemory
supermemory-spec: "supermemory==3.59.0"
supermemory-version: "3.59.0"
defaults:
run:
working-directory: packages/pipecat-sdk-python
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Setup Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: packages/pipecat-sdk-python/pyproject.toml

- name: Install build tools and lightweight test dependencies
run: >-
python -m pip install build pytest "loguru>=0.7.3" "pydantic>=2.10.0"
"${{ matrix.supermemory-spec }}"

- name: Build wheel
run: python -m build --wheel --outdir "$RUNNER_TEMP/wheels"

- name: Install wheel without the voice framework
run: python -m pip install --no-deps "$RUNNER_TEMP"/wheels/*.whl

- name: Run tests against the installed wheel and real lightweight dependencies
run: >-
python -c "from importlib.metadata import version;
from pathlib import Path; import loguru, pydantic, supermemory, pytest;
assert version('supermemory') == '${{ matrix.supermemory-version }}';
result = pytest.main(['-W', 'ignore::pytest.PytestAssertRewriteWarning', 'tests']);
import supermemory_pipecat;
assert 'site-packages' in Path(supermemory_pipecat.__file__).parts;
raise SystemExit(result)"
5 changes: 4 additions & 1 deletion apps/browser-extension/entrypoints/content/chatgpt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
acceptMemorySuggestion,
clearMemorySuggestion,
hasAcceptedSupermemoryContext,
serializeMemoriesForDataset,
setMemoryMarkerStatus,
showLoadingSuggestion,
showMarkerPopover,
Expand Down Expand Up @@ -212,7 +213,9 @@ async function getRelatedMemoriesForChatGPT(actionSource: string) {
memoryLength: memoryText.length,
})

iconElement.dataset.memoriesData = String(response.data)
iconElement.dataset.memoriesData = serializeMemoriesForDataset(
response.data,
)

if (isAutoSearch) {
setMemoryMarkerStatus(iconElement, "found")
Expand Down
5 changes: 4 additions & 1 deletion apps/browser-extension/entrypoints/content/claude.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
acceptMemorySuggestion,
clearMemorySuggestion,
hasAcceptedSupermemoryContext,
serializeMemoriesForDataset,
setMemoryMarkerStatus,
showLoadingSuggestion,
showMarkerPopover,
Expand Down Expand Up @@ -459,7 +460,9 @@ async function getRelatedMemoriesForClaude(actionSource: string) {
memoryLength: memoryText.length,
})

iconElement.dataset.memoriesData = String(response.data)
iconElement.dataset.memoriesData = serializeMemoriesForDataset(
response.data,
)

if (isAutoSearch) {
setMemoryMarkerStatus(iconElement, "found")
Expand Down
5 changes: 4 additions & 1 deletion apps/browser-extension/entrypoints/content/gemini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
acceptMemorySuggestion,
clearMemorySuggestion,
hasAcceptedSupermemoryContext,
serializeMemoriesForDataset,
setMemoryMarkerStatus,
showLoadingSuggestion,
showMarkerPopover,
Expand Down Expand Up @@ -417,7 +418,9 @@ async function getRelatedMemoriesForGemini(actionSource: string) {

if (response?.success && response?.data && input) {
const memoryText = showMemorySuggestion("gemini", input, response.data)
iconElement.dataset.memoriesData = String(response.data)
iconElement.dataset.memoriesData = serializeMemoriesForDataset(
response.data,
)
iconElement.dataset.supermemories = memoryText
if (isAutoSearch) {
setMemoryMarkerStatus(iconElement, "found")
Expand Down
45 changes: 41 additions & 4 deletions apps/browser-extension/entrypoints/content/memory-suggestion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,46 @@ export function buildSupermemoryText(memories: unknown): string {
return `\n\n${SUPERMEMORY_PREFIX} ${memoryText}`
}

function normalizeMemoryList(memories: unknown): string[] {
const list = Array.isArray(memories)
? memories
: memories == null
? []
: [memories]
return list
.map((memory) => (typeof memory === "string" ? memory : String(memory)))
.map((memory) => memory.trim())
.filter((memory) => memory.length > 0)
}

export function serializeMemoriesForDataset(memories: unknown): string {
const list = normalizeMemoryList(memories)
return list.length > 0 ? JSON.stringify(list) : ""
}

export function parseMemoriesFromDataset(
raw: string | null | undefined,
): string[] {
if (!raw) return []
try {
const parsed = JSON.parse(raw)
if (Array.isArray(parsed)) return normalizeMemoryList(parsed)
} catch {
// Not JSON — fall through to the legacy delimiter split.
}
return raw
.split(/[,\n]/)
.map((memory) => memory.trim())
.filter((memory) => memory.length > 0 && memory !== ",")
}

export function renumberIncludedMemories(memories: string[]): string[] {
return memories.map((memory, index) => {
const text = memory.replace(/^\d+\.\s*/, "").replace(/\s+$/, "")
return `${index + 1}. ${text} \n`
})
}

export function showMemorySuggestion(
platform: string,
input: SuggestionInput,
Expand Down Expand Up @@ -305,10 +345,7 @@ export function showMarkerPopover(
color: rgba(255, 255, 255, 0.76);
`

memories
.split(/[,\n]/)
.map((memory) => memory.trim())
.filter((memory) => memory.length > 0 && memory !== ",")
parseMemoriesFromDataset(memories)
.slice(0, 5)
.forEach((memory) => {
const item = document.createElement("div")
Expand Down
Loading
Loading