Skip to content

feat(memory): validate official clients on current stack - #87

Merged
drewstone merged 4 commits into
mainfrom
chore/current-stack-cohort
Jul 27, 2026
Merged

feat(memory): validate official clients on current stack#87
drewstone merged 4 commits into
mainfrom
chore/current-stack-cohort

Conversation

@drewstone

@drewstone drewstone commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

  • release @tangle-network/agent-knowledge@6.1.0 on Eval 0.130.1 and Interface 0.35.0
  • compile mode-specific contracts against official Mem0 hosted, Mem0 OSS, and Neo4j client types
  • exercise Mem0 OSS through a local SQLite write, search, history, and clear lifecycle
  • update Mem0 to 3.1.2, TypeScript to 7.0.2, GitHub Actions, and replace tsup with tsdown
  • validate packed exports and official GEPA and SkillOpt integrations

Proof

  • frozen install passed
  • source and official-client type checks passed
  • Biome checked 188 files
  • 468 tests passed; 12 intentionally skipped
  • build emitted 35 files totaling 2.29 MB
  • all 6 ESM entrypoints and a clean packed consumer passed
  • official GEPA and SkillOpt verification passed against Eval 0.130.1
  • production dependency audit found 0 known vulnerabilities

Upstream limits

  • Mem0 still contains two deprecated transitive packages with no supported replacement path.
  • tsdown reports that TypeScript 7 uses its experimental compiler API. Source, declaration, and packed consumer checks pass.

tangletools
tangletools previously approved these changes Jul 27, 2026

@tangletools tangletools left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Auto-approved drewstone PR — 528816e7

This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.

tangletools · auto-approval · reason: drewstone_author · 2026-07-27T05:24:37Z

@tangletools tangletools left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Value Audit — sound-with-nits

Verdict sound-with-nits
Concerns 1 (1 weak-concern)
Heuristic 0.0s
Duplication 0.0s
Interrogation 126.9s (2 bridge agents)
Total 126.9s

💰 Value — sound-with-nits

Splits the loose Mem0 client type into mode-specific structural interfaces backed by a CI-compiled contract check and a real SQLite lifecycle test — a genuine, in-grain upgrade to type safety and validation, with one minor test-fixture duplication.

  • What it does: Replaces the single loose Mem0ClientLike (Record<string,unknown> options) with two hand-mirrored structural interfaces — Mem0HostedClient and Mem0OssClient (src/memory/mem0.ts:36-72) — and turns Mem0MemoryAdapterOptions into a discriminated union on mode (mem0.ts:86-100), so appId/latestOnly are compile-time forbidden in OSS mode (appId?: never) and the OSS-only filters on add is reflected in
  • Goals it achieves: (1) Guarantee the adapter's structural client types cannot silently drift from the official Mem0/Neo4j clients on dependency bumps — the prior 'is type-compatible' test (tests/memory/mem0.test.ts, removed) was a null as unknown as MemoryClient cast inside tests/ (excluded from tsc.json), so it verified nothing under pnpm typecheck and vitest's esbuild doesn't type-check; the new contract file
  • Assessment: Good change, firmly in the grain of the codebase. The runtime has always branched on mode; the discriminated union lifts those branches to the type system. The structural-mirror approach (not importing mem0ai types into public src) is correct because mem0ai is a devDependency/optional peer — importing MemoryClient into the public types would either force mem0ai into dependencies or yield unresolva
  • Better / existing approach: Considered importing MemoryClient/Memory directly from mem0ai instead of hand-mirroring — rejected: mem0ai is a devDep/optional peer, so importing its types into the published src would force a hard runtime dependency or unresolvable consumer types; structural interface + separate contract compile is the standard optional-peer pattern and the right call. Checked for an existing equivalent: the Neo
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 2
  • Bridge warning: opencode/kimi-for-coding/k2p7: bridge stream ended without value-audit content

🎯 Usefulness — sound

Tightens the Mem0 adapter's type contract into a mode-discriminated union that matches the adapter's existing runtime branching, guards it against upstream type drift via compile-only contract checks, and proves the OSS path with a real local-SQLite lifecycle test.

  • Integration: The adapter is the public memory surface (src/memory/index.ts:17) and is consumed through the AgentMemoryAdapter interface by the eval improvement loops. The new contract file is reachable via the typecheck:contracts script (package.json); it is a compile-only type guard by design (no vitest .test.ts name, no runtime caller) — exercised by tsc, not dead. The integration test is a normal vitest
  • Fit with existing patterns: Strong fit. The adapter already branched on options.mode everywhere (mem0.ts:117-124, 139, 189, 194); the discriminated union (Mem0HostedMemoryAdapterOptions | Mem0OssMemoryAdapterOptions, mem0.ts:86-100) makes the type system match that existing runtime logic, and appId?: never / latestOnly?: never on OSS forbid mode-inappropriate options at the type level. The compile-only contract-test
  • Real-world viability: The new integration test stands up a real mem0ai/oss Memory instance backed by local SQLite for vectors+history and a stub OpenAI-compatible embedding server, exercising write→search→history→clear and asserting files are created then cleared — so the OSS path is proven end-to-end without external API calls. The hosted path keeps its existing mock-based tests plus the type contract. The union n
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 1

💰 Value Audit

🟡 Local HTTP-server bind/close fixture duplicated across two integration tests [duplication] ``

tests/memory/mem0-oss.integration.test.ts:88-135 (startEmbeddingServer) and tests/official-optimization.integration.test.ts:283-319 (startModelServer) share the same skeleton: createServer(handler) → listen(0,'127.0.0.1') → guard server.address() → return http://127.0.0.1:${port}/v1 (+ close path). Only the response payload differs (embeddings vs chat-completions). A small shared helper like bindLocalOpenAiServer(handler) in tests/support/ would factor out ~25 duplicated lines and keep the bin


What this audit checks

It judges the change on its merits — not whether it was tasked out in an issue. Unticketed, fast-moving work is fine; the question is whether the change is good and whether a better or existing approach should be used instead.

Pass What it asks
Heuristic Vague title? Whitespace-only or cruft-bearing diff? (content signals only)
Duplication Do added function/class names already exist elsewhere in the repo?
Value Audit What does it do? What goal does it achieve? Is it good? Better architecture or already-exists?
Usefulness Audit Does it integrate and fit? Will it hold up in real use and actually get used?

Findings are concerns, not blocks — the human reviewer decides what to do with them.

value-audit · 20260727T052854Z

tangletools
tangletools previously approved these changes Jul 27, 2026

@tangletools tangletools left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Auto-approved drewstone PR — 9f821e0e

This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.

tangletools · auto-approval · reason: drewstone_author · 2026-07-27T05:48:03Z

@tangletools tangletools left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Value Audit — sound

Verdict sound
Concerns 0 (none)
Heuristic 0.0s
Duplication 0.0s
Interrogation 112.1s (2 bridge agents)
Total 112.1s

💰 Value — sound

Splits the loose Mem0 client type into strict hosted/OSS contracts and adds a compile-time compatibility check plus a real SQLite lifecycle test against the official Mem0 OSS package — a coherent hardening release that extends the repo's existing release-gate pattern.

  • What it does: Replaces the single permissive Mem0ClientLike (Record<string,unknown>-options blob) with two mode-specific interfaces — Mem0HostedClient and Mem0OssClient — and turns the adapter options into a discriminated union on mode, so hosted-only fields (appId, latestOnly, page/pageSize) are structurally excluded from OSS (src/memory/mem0.ts:36-100). Adds tests/contracts/official-memory-clients.ts:1-24,
  • Goals it achieves: (1) Prove the adapter's hand-rolled client interfaces actually match the real upstream Mem0/Neo4j types — the old Record<string,unknown> options would silently accept any upstream shape change. (2) Exercise the real Mem0 OSS package end-to-end through the adapter boundary so regressions in add/search/history/clear surface in CI instead of in user code. (3) Move to the current toolchain (TypeScript
  • Assessment: Good change on its merits. The hosted/OSS split is correct, not cosmetic: the two Mem0 clients genuinely differ (hosted has appId/latestOnly/page/pageSize; OSS passes filters on add and topK on getAll), and the adapter already branches on options.mode in search/write/clear (mem0.ts:139-141, 189, 263-275) — the discriminated union lifts those runtime branches into the type system. The contract file
  • Better / existing approach: none — this is the right approach. Checked: no prior contract-test or publint/attw pattern exists in the repo to extend (grep'd tests/ and scripts/); this is the first and is well-formed. No existing strict Mem0 interface to reuse — the old Mem0ClientLike was strictly looser, so this is a refinement. The tests/contracts/ pattern (separate tsconfig, compile-only, not run by vitest) is the correct i
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 2
  • Bridge warning: opencode/kimi-for-coding/k2p7: bridge stream ended without value-audit content

🎯 Usefulness — sound

Tightens the Mem0 adapter to mode-specific typed client contracts validated against the real SDK shapes, plus a real SQLite OSS lifecycle test and build-tooling modernization — all reachable and in the grain of the existing adapter pattern.

  • Integration: The new typed interfaces (Mem0HostedClient/Mem0OssClient) are exported from src/memory/index.ts:17 and re-exported through the package's ./memory subpath (package.json:32-36). The contract test at tests/contracts/official-memory-clients.ts:11-23 is reached via typecheck:contracts (package.json:70), which pnpm typecheck runs — so any drift in the official mem0ai/mem0ai/oss/`@neo4j-lab
  • Fit with existing patterns: Matches the established provider-adapter pattern exactly: a peer to createNeo4jAgentMemoryAdapter (src/memory/neo4j.ts:27) and the Graphiti adapter, all returning the shared AgentMemoryAdapter shape. The discriminated union (Mem0HostedMemoryAdapterOptions | Mem0OssMemoryAdapterOptions, src/memory/mem0.ts:100) with appId?: never / latestOnly?: never on OSS is the grain of the codebase — f
  • Real-world viability: The integration test covers the write→search→history→clear lifecycle on real SQLite files and asserts the embedding server only received /v1/embeddings (no hidden network fan-out). The adapter's runtime already handles the hard paths the typed contract exposes: delayed-delete visibility polling (src/memory/mem0.ts:258-377), hosted add response-shape validation (src/memory/mem0.ts:194-198), uns
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 1

No concerns — sound change, no better or existing approach found. ✅


What this audit checks

It judges the change on its merits — not whether it was tasked out in an issue. Unticketed, fast-moving work is fine; the question is whether the change is good and whether a better or existing approach should be used instead.

Pass What it asks
Heuristic Vague title? Whitespace-only or cruft-bearing diff? (content signals only)
Duplication Do added function/class names already exist elsewhere in the repo?
Value Audit What does it do? What goal does it achieve? Is it good? Better architecture or already-exists?
Usefulness Audit Does it integrate and fit? Will it hold up in real use and actually get used?

Findings are concerns, not blocks — the human reviewer decides what to do with them.

value-audit · 20260727T055009Z

tangletools
tangletools previously approved these changes Jul 27, 2026

@tangletools tangletools left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Auto-approved drewstone PR — ad98b906

This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.

tangletools · auto-approval · reason: drewstone_author · 2026-07-27T06:07:50Z

@tangletools tangletools left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Value Audit — sound

Verdict sound
Concerns 0 (none)
Heuristic 0.0s
Duplication 0.0s
Interrogation 109.3s (2 bridge agents)
Total 109.3s

💰 Value — sound

Tightens the Mem0 adapter to mode-specific typed contracts (hosted vs OSS) and proves them against the official SDK packages with a compile-time contract file plus a real local-SQLite integration test; also refreshes the build toolchain to currently-maintained versions.

  • What it does: Replaces the single loose Mem0ClientLike (options typed as Record<string, unknown>) with two sharply-typed interfaces, Mem0HostedClient and Mem0OssClient, that mirror the actual shapes of mem0ai's MemoryClient and mem0ai/oss's Memory. Turns Mem0MemoryAdapterOptions into a discriminated union over mode, so appId/latestOnly are accepted only for hosted and forbidden (via : never) for OSS. Adds tes
  • Goals it achieves: (1) Make silent contract drift between this adapter and upstream Mem0/Neo4j SDKs impossible to ship: the contract file forces the adapter's expected client types to compile against the real shipped package types, and the integration test exercises the real Memory class end-to-end. (2) Push mode-specific options (appId, latestOnly) from runtime convention into compile-time enforcement via the discr
  • Assessment: Good change, built in the grain of the codebase. The prior mem0.ts used a deliberately loose Mem0ClientLike with options?: Record<string, unknown> everywhere; the new code sharpens exactly those boundaries while leaving the adapter's actual runtime behavior (search/write/clear, pending-write probes, scoped-delete verification) untouched. It is strictly more type-safe than the Neo4j adapter in sr
  • Better / existing approach: none — this is the right approach. Searched for an existing contract-proof or type-compat pattern (grep for Mem0ClientLike, Mem0HostedClient, Mem0OssClient across src/ and tests/; checked tests/contracts/ for prior art; reviewed src/memory/neo4j.ts for the adjacent adapter's typing style). The contract file is the first of its kind here, the loose Mem0ClientLike is fully removed with no duplicatio
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 2
  • Bridge warning: opencode/kimi-for-coding/k2p7: bridge stream ended without value-audit content

🎯 Usefulness — sound

Tightens the Mem0 adapter's client contract to match official mem0ai hosted/OSS types and adds a real SQLite-backed integration test plus a CI-gated type-level contract check; fully reachable through the existing AgentMemoryAdapter pipeline.

  • Integration: The adapter returns AgentMemoryAdapter (src/memory/mem0.ts:110), which is the type consumed throughout the memory pipeline: branch composition (src/memory/branch.ts:37,45), experiment cells (src/memory/experiment/cell.ts:106), recovery (src/memory/experiment/recovery.ts:206), benchmarks (src/benchmarks/memory-runner.ts:215), and the improvement loop (src/memory/improvement/run.ts:47). The new cont
  • Fit with existing patterns: Fits the established adapter pattern cleanly. The Neo4j adapter already exposes a structural client shape (src/memory/neo4j.ts:16 client: object); this PR moves Mem0 from a single loose Mem0ClientLike to mode-specific structural types that mirror the two official clients, and a discriminated union on mode that matches every place the adapter already branches on mode (src/memory/mem0.ts:139,1
  • Real-world viability: Beyond the happy path: the new integration test (tests/memory/mem0-oss.integration.test.ts) stands up a local embedding HTTP server, writes to real SQLite vector + history DBs, asserts file sizes, exercises search/history/clear, and pins that only /v1/embeddings is hit (no external calls) — so it guards the actual OSS lifecycle, not a mock. The adapter's pre-existing error paths (unscoped clear
  • Model: opencode/zai-coding-plan/glm-5.2
  • Bridge attempts: 1

No concerns — sound change, no better or existing approach found. ✅


What this audit checks

It judges the change on its merits — not whether it was tasked out in an issue. Unticketed, fast-moving work is fine; the question is whether the change is good and whether a better or existing approach should be used instead.

Pass What it asks
Heuristic Vague title? Whitespace-only or cruft-bearing diff? (content signals only)
Duplication Do added function/class names already exist elsewhere in the repo?
Value Audit What does it do? What goal does it achieve? Is it good? Better architecture or already-exists?
Usefulness Audit Does it integrate and fit? Will it hold up in real use and actually get used?

Findings are concerns, not blocks — the human reviewer decides what to do with them.

value-audit · 20260727T060955Z

@drewstone
drewstone merged commit 6937339 into main Jul 27, 2026
2 checks passed
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.

2 participants