Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
d4848f9
fix(memory): harden capture and source ingestion
hijzy Aug 19, 2026
1d7b8cd
feat(memory): add project-scoped L3 world model
Wang-Daoji Aug 19, 2026
1bf1b92
Merge remote-tracking branch 'upstream/v1.0.9' into feature/world-mod…
Wang-Daoji Aug 20, 2026
cec1972
feat: add model-specific token defaults for BYOK presets
ZongYue99 Aug 20, 2026
88fa2a9
fix(memory): ground recall and handle live corrections
hijzy Aug 20, 2026
2bb00e6
Merge remote-tracking branch 'upstream/release/v1.0.9' into feature/w…
Wang-Daoji Aug 20, 2026
5a59dc0
fix(memory): enable workspace bridge by default
Wang-Daoji Aug 20, 2026
26a4bae
feat(memory): refine project world model profiles
Wang-Daoji Aug 20, 2026
cc95981
add pkg lock
wustzdy Aug 21, 2026
5c1d6a1
Merge pull request #274 from wustzdy/v1.1.0_zdy_0821_lock
wustzdy Aug 21, 2026
2838545
Merge remote-tracking branch 'upstream/main' into feature/world-model-wy
Wang-Daoji Aug 21, 2026
7227716
Merge remote-tracking branch 'upstream/v1.1.0' into feature/world-mod…
Wang-Daoji Aug 21, 2026
d57b830
Merge pull request #275 from hijzy/main
hijzy Aug 21, 2026
fa82faf
feat(memory): localize project environment scanning
Wang-Daoji Aug 21, 2026
04125f6
fix(agent): make goal context provider-neutral
Wang-Daoji Aug 21, 2026
89b777a
fix: align user memory capture and diagnostics
hijzy Aug 21, 2026
e9c45b2
Merge pull request #276 from hijzy/main
hijzy Aug 21, 2026
1b9d7c8
fix(updater): harden Windows upgrade recovery
Aug 21, 2026
9a9f230
fix: support Windows memory sync from WSL agents
hijzy Aug 21, 2026
15f5620
fix(memory): clarify persistent project contract rules
Wang-Daoji Aug 21, 2026
2148fb8
fix(agent): raise webui transcript size limit
Wang-Daoji Aug 21, 2026
3a0e88f
fix(memory): keep environment profiles concise
Wang-Daoji Aug 21, 2026
76067bd
Merge pull request #280 from hijzy/agent/fix-windows-wsl-agent-memory
hijzy Aug 21, 2026
1deebe8
fix: refine user memory retrieval and UI
hijzy Aug 21, 2026
56ada01
Merge pull request #281 from hijzy/agent/fix-windows-wsl-agent-memory
hijzy Aug 21, 2026
affab31
fix(memory): omit reasoning from L3 evidence
Wang-Daoji Aug 21, 2026
068a60a
feat(agent): adopt patch envelope for apply_patch
Wang-Daoji Aug 23, 2026
704f60f
feat(agent): compact context mid-turn
Wang-Daoji Aug 23, 2026
58bc4b7
Merge remote-tracking branch 'upstream/v1.1.0' into feature/world-mod…
Wang-Daoji Aug 23, 2026
937cbe9
Merge pull request #283 from Wang-Daoji/feature/world-model-wy
Wang-Daoji Aug 23, 2026
28e4706
fix(desktop): validate update package integrity before install
wustzdy Aug 24, 2026
9de971a
Merge pull request #284 from wustzdy/v1.1.0_zdy_0824
wustzdy Aug 24, 2026
813478b
fix(memory): harden L3 profile generation
Wang-Daoji Aug 24, 2026
e49098a
fix(memory): relax project contract extraction
Wang-Daoji Aug 24, 2026
c4e9d51
fix(desktop): restore chat composer layout
EF1874 Aug 24, 2026
dd4e055
fix(memory): retain project presentation conventions
Wang-Daoji Aug 24, 2026
e304e1a
Merge pull request #287 from Wang-Daoji/feature/agent-wy
Wang-Daoji Aug 24, 2026
f3c709a
fix(desktop): align workspace branch menu
EF1874 Aug 24, 2026
ef6b47b
fix(memory): strengthen project contract decisions
Wang-Daoji Aug 24, 2026
c3dc6fd
Merge pull request #288 from Wang-Daoji/feature/agent-wy
Wang-Daoji Aug 24, 2026
d39f468
Merge pull request #277 from EF1874/codex/audit-v1.1.0-windows-upgrad…
ZongYue99 Aug 24, 2026
5f1bd3e
Merge pull request #285 from EF1874/codex/fix-chat-layout-v1.1.0
ZongYue99 Aug 24, 2026
decb13d
Merge branch 'MemTensor:main' into zy_v1.0.10
ZongYue99 Aug 24, 2026
249a1c8
Merge pull request #289 from ZongYue99/zy_v1.0.10
ZongYue99 Aug 24, 2026
0fd626b
fix(desktop): wait for memory service readiness
hijzy Aug 24, 2026
80bf4d6
fix(desktop): keep UI responsive during memory startup
hijzy Aug 24, 2026
9e9cff4
Merge pull request #290 from hijzy/main
hijzy Aug 24, 2026
393b490
feat: support DeepSeek experimental vision model
Wang-Daoji Aug 24, 2026
d7743b6
Merge pull request #291 from Wang-Daoji/feature/agent-wy
Wang-Daoji Aug 24, 2026
95f7acc
fix: hot reload Composio MCP after backend startup
ZongYue99 Aug 24, 2026
9391378
Merge branch 'v1.1.0' into zy_v1.0.10
ZongYue99 Aug 24, 2026
435d8bb
fix(updater): preserve authoritative Windows data
Aug 24, 2026
418cae7
Merge pull request #293 from EF1874/codex/fix-v1.1.0-windows-data-mig…
ZongYue99 Aug 24, 2026
fd702da
fix: hot reload Composio MCP after backend startup
ZongYue99 Aug 24, 2026
0d4b0a7
chore(release): prepare Memmy v1.1.0
Aug 24, 2026
e61049c
fix(release): close v1.1.0 quality gaps
Aug 24, 2026
60cb720
Merge remote-tracking branch 'upstream/main' into release/v1.1.0
Aug 24, 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
29 changes: 29 additions & 0 deletions .github/release-notes/v1.1.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Memmy v1.1.0

## Highlights

- Added project-scoped World Models that learn a workspace's environment, durable working contract, and domain knowledge, then make that context available to Memmy Agent and supported connected Agents.
- Made long Agent work more resilient with mid-turn context compaction and validated, transactional multi-file patch editing.
- Reworked Windows upgrade data handling to preserve authoritative account, model, and runtime state across direct, silent, cross-volume, and interrupted upgrades.

## Memory improvements

- Memory now maintains general rules and safety constraints separately from workspace-scoped environment profiles, project contracts, and domain knowledge. The Desktop World Model view labels project entries with their workspace and displays these fields directly.
- Project profiles are built from bounded scans of workspace structure, manifests, toolchains, runtime versions, and build, test, and check commands. Sensitive paths, symlinks, binary artifacts, and ignored dependency or build directories are excluded.
- Updated the Codex, Claude Code, Cursor, OpenCode, OpenClaw, DeepSeek Harness, and Hermes integrations so scoped project context can be loaded at session boundaries and refreshed after compaction.
- User Memory now confirms repeated durable facts or preferences, applies explicit corrections to existing records, avoids echoing freshly captured turns, and can show recall evidence beside earlier completed responses.
- Windows Desktop can now sync supported Agent histories stored inside WSL distributions.

## Agent improvements

- Long, tool-heavy turns can compact older provider context after completed tool iterations while preserving current-turn tool results and the full saved transcript. The conversation transcript loading limit was also raised from 8 MB to 128 MB.
- File edits now use a validated workspace-relative patch format with add, update, delete, and move support. Conflicting or failed multi-file changes are rolled back, and Desktop edit traces identify the affected file or file count.
- Recognized BYOK model presets now receive model-specific context-window and output-token defaults unless explicitly overridden. Added image input support for the experimental DeepSeek V4 Flash vision route.
- Composio MCP tools are reloaded after the Desktop backend writes startup configuration, allowing them to become available without restarting Memmy. MCP discovery and calls also use bounded timeouts.

## Desktop and update reliability

- Managed Memory startup and database migrations now continue in the background so the Desktop remains responsive; runtime configuration is refreshed once Memory is ready.
- Windows upgrades now migrate install-local account and runtime data transactionally, validate account and model consistency, retain a boot-verified rollback window, and recover stale relay or installer state without merging unrelated data generations.
- Update downloads must be non-empty and complete before being marked ready. macOS DMGs that fail staging are discarded instead of being reused for installation.
- Polished the chat composer, queued-message steer action, and workspace branch menu, including clearer branch-creation context, a five-row scrollable list, and restored keyboard focus.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ sessions/
.env
.env.*
!.env.example
App/backend/src/adapters/outbound/skill-writer/workspace-bridge/memmy-workspace-bridge.mjs
6 changes: 6 additions & 0 deletions App/backend/local-api-contracts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { z } from "zod";
export * from "./model-catalog-resolver.js";

export * from "./memory-runtime.js";
export * from "./memory-canonical-json.js";
export * from "./memory-workspace-identity.js";
export * from "./memory-l3-world-model.js";
export * from "./endpoints.js";
export * from "./cloud-service.js";
export * from "./desktop-runtime-manifest.js";
Expand Down Expand Up @@ -334,6 +337,9 @@ const ManagedAgentSyncFieldMapSchema = z.object({
const ManagedAgentSyncRecipeBaseSchema = z.object({
version: z.literal(1),
path: z.string().trim().min(1),
wslDistro: z.string().trim().min(1).refine((value) => !/[\\/\0]/u.test(value), {
message: "WSL distribution name must not contain path separators"
}).optional(),
fields: ManagedAgentSyncFieldMapSchema,
roleMap: z.record(z.string(), z.enum(["user", "assistant", "tool", "system"])).optional(),
timestampFormat: z.enum(["auto", "iso", "unix_seconds", "unix_milliseconds"]).default("auto")
Expand Down
160 changes: 160 additions & 0 deletions App/backend/local-api-contracts/src/memory-canonical-json.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/** Canonical JSON helpers shared by Memory and every Agent Adapter. */

export type JsonPrimitive = string | number | boolean | null;
export type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue };

const SHA256_INITIAL = [
0x6a09e667,
0xbb67ae85,
0x3c6ef372,
0xa54ff53a,
0x510e527f,
0x9b05688c,
0x1f83d9ab,
0x5be0cd19
] as const;

const SHA256_ROUND_CONSTANTS = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
] as const;

/** Serializes a JSON value with recursively sorted object keys and no truncation. */
export function canonicalJson(value: JsonValue): string {
return serializeJsonValue(assertJsonValue(value));
}

/** Validates that a runtime value is representable as JSON without implicit coercion. */
export function assertJsonValue(value: unknown): JsonValue {
assertJsonNode(value, new Set<object>(), "$input");
return value as JsonValue;
}

/** Compares strings by Unicode code point rather than locale or UTF-16 collation. */
export function compareUnicodeCodePoints(left: string, right: string): number {
const leftPoints = Array.from(left, (character) => character.codePointAt(0) ?? 0);
const rightPoints = Array.from(right, (character) => character.codePointAt(0) ?? 0);
const length = Math.min(leftPoints.length, rightPoints.length);
for (let index = 0; index < length; index += 1) {
const delta = leftPoints[index]! - rightPoints[index]!;
if (delta !== 0) return delta;
}
return leftPoints.length - rightPoints.length;
}

/** Portable SHA-256 used by cross-runtime contract identities and fixtures. */
export function sha256Hex(input: string): string {
const bytes = new TextEncoder().encode(input);
const bitLength = bytes.length * 8;
const paddedLength = Math.ceil((bytes.length + 9) / 64) * 64;
const padded = new Uint8Array(paddedLength);
padded.set(bytes);
padded[bytes.length] = 0x80;
const view = new DataView(padded.buffer);
const high = Math.floor(bitLength / 0x1_0000_0000);
const low = bitLength >>> 0;
view.setUint32(paddedLength - 8, high, false);
view.setUint32(paddedLength - 4, low, false);

const state: number[] = [...SHA256_INITIAL];
const words = new Uint32Array(64);
for (let offset = 0; offset < padded.length; offset += 64) {
for (let index = 0; index < 16; index += 1) {
words[index] = view.getUint32(offset + index * 4, false);
}
for (let index = 16; index < 64; index += 1) {
const word15 = words[index - 15]!;
const word2 = words[index - 2]!;
const sigma0 = rotateRight(word15, 7) ^ rotateRight(word15, 18) ^ (word15 >>> 3);
const sigma1 = rotateRight(word2, 17) ^ rotateRight(word2, 19) ^ (word2 >>> 10);
words[index] = (words[index - 16]! + sigma0 + words[index - 7]! + sigma1) >>> 0;
}

let [a, b, c, d, e, f, g, h] = state;
for (let index = 0; index < 64; index += 1) {
const sum1 = rotateRight(e!, 6) ^ rotateRight(e!, 11) ^ rotateRight(e!, 25);
const choose = (e! & f!) ^ (~e! & g!);
const temporary1 = (h! + sum1 + choose + SHA256_ROUND_CONSTANTS[index]! + words[index]!) >>> 0;
const sum0 = rotateRight(a!, 2) ^ rotateRight(a!, 13) ^ rotateRight(a!, 22);
const majority = (a! & b!) ^ (a! & c!) ^ (b! & c!);
const temporary2 = (sum0 + majority) >>> 0;
h = g;
g = f;
f = e;
e = (d! + temporary1) >>> 0;
d = c;
c = b;
b = a;
a = (temporary1 + temporary2) >>> 0;
}

state[0] = (state[0]! + a!) >>> 0;
state[1] = (state[1]! + b!) >>> 0;
state[2] = (state[2]! + c!) >>> 0;
state[3] = (state[3]! + d!) >>> 0;
state[4] = (state[4]! + e!) >>> 0;
state[5] = (state[5]! + f!) >>> 0;
state[6] = (state[6]! + g!) >>> 0;
state[7] = (state[7]! + h!) >>> 0;
}

return state.map((word) => word.toString(16).padStart(8, "0")).join("");
}

export const MEMORY_CANONICAL_JSON_FIXTURES = [
{
input: { z: 1, a: [true, null, "值"] } satisfies JsonValue,
canonical: "{\"a\":[true,null,\"值\"],\"z\":1}"
},
{
input: { "😀": 1, "界": 2 } satisfies JsonValue,
canonical: "{\"界\":2,\"😀\":1}"
}
] as const;

function assertJsonNode(value: unknown, ancestors: Set<object>, path: string): void {
if (value === null || typeof value === "string" || typeof value === "boolean") return;
if (typeof value === "number") {
if (!Number.isFinite(value)) throw new TypeError(`${path} contains a non-finite number`);
return;
}
if (typeof value !== "object") {
throw new TypeError(`${path} contains a non-JSON ${typeof value} value`);
}
if (ancestors.has(value)) throw new TypeError(`${path} contains a circular reference`);
ancestors.add(value);
try {
if (Array.isArray(value)) {
value.forEach((item, index) => assertJsonNode(item, ancestors, `${path}[${index}]`));
return;
}
const prototype = Object.getPrototypeOf(value);
if (prototype !== Object.prototype && prototype !== null) {
throw new TypeError(`${path} contains a non-plain object`);
}
for (const [key, item] of Object.entries(value)) {
assertJsonNode(item, ancestors, `${path}.${key}`);
}
} finally {
ancestors.delete(value);
}
}

function serializeJsonValue(value: JsonValue): string {
if (value === null || typeof value !== "object") return JSON.stringify(value);
if (Array.isArray(value)) return `[${value.map(serializeJsonValue).join(",")}]`;
return `{${Object.keys(value)
.sort(compareUnicodeCodePoints)
.map((key) => `${JSON.stringify(key)}:${serializeJsonValue(value[key]!)}`)
.join(",")}}`;
}

function rotateRight(value: number, count: number): number {
return (value >>> count) | (value << (32 - count));
}
Loading
Loading