From e35165d2917830d168bdb1be284c67e1dbcfb5e1 Mon Sep 17 00:00:00 2001 From: OpenCode Date: Sun, 19 Apr 2026 15:50:42 +0700 Subject: [PATCH 1/5] Ignore agent tool-generated files (.agents/, AGENTS.md, .opencode/, .sisyphus/, docs/, skills-lock.json) --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index c78f031..f9f144b 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,9 @@ benchmark/data/*/openclaw_state/agents/*/agent/ # ── Claude Code local settings ──────────────────────────────────────────────── .claude/settings.local.json +.agents/ +*AGENTS.md +.opencode/ +.sisyphus/ +docs/ +skills-lock.json From 13292d8923188a66b8fd9fc9300d8ac47dec0f39 Mon Sep 17 00:00:00 2001 From: OpenCode Date: Sun, 19 Apr 2026 15:50:53 +0700 Subject: [PATCH 2/5] Add OpenClaw v2026.4.10+ compatibility layer with context-engine dispatch - Add openclaw_compat config section (context_engine_enabled, active_memory_compat, prefer_proxy_synergy, min_version) to MetaClawConfig, ConfigStore defaults, and describe() output - Extend setup wizard with advanced OpenClaw compatibility prompts - Refactor API server message augmentation to dispatch on x-metaclaw-contextengine header: context-engine path skips proxy-side memory injection (skills only), with optional prefer_proxy_synergy escape hatch for full synergy - Suppress OpenClaw built-in Active Memory via plugin slot override in claw_adapter when openclaw_active_memory_compat is enabled - Detect registerContextEngine API in OpenClaw extension and signal proxy with x-metaclaw-contextengine header --- extensions/metaclaw-openclaw/index.ts | 12 +++++++- metaclaw/api_server.py | 17 ++++++++++- metaclaw/claw_adapter.py | 7 ++++- metaclaw/config.py | 8 +++++ metaclaw/config_store.py | 21 ++++++++++++- metaclaw/setup_wizard.py | 44 +++++++++++++++++++++++++++ 6 files changed, 105 insertions(+), 4 deletions(-) diff --git a/extensions/metaclaw-openclaw/index.ts b/extensions/metaclaw-openclaw/index.ts index f4cdfff..e2e0b02 100644 --- a/extensions/metaclaw-openclaw/index.ts +++ b/extensions/metaclaw-openclaw/index.ts @@ -132,6 +132,11 @@ function patchFetchForTrainingHeaders( let pendingHeaders: Record | null = null; const originalFetch = globalThis.fetch; + // Detect if OpenClaw supports context-engine API (v2026.4.10+) + // When available, the metaclaw-memory plugin registers as context-engine, + // and memories are injected at gateway level via assemble(). + const contextEngineAvailable = typeof api.registerContextEngine === "function"; + globalThis.fetch = function metaclawPatchedFetch( input: RequestInfo | URL, init?: RequestInit, @@ -152,10 +157,15 @@ function patchFetchForTrainingHeaders( api.on("before_prompt_build", (_event, ctx) => { const sessionId = ctx.sessionId ?? ""; const turnType = SIDE_TRIGGERS.has(ctx.trigger ?? "") ? "side" : "main"; - pendingHeaders = { + const headers: Record = { [config.sessionIdHeader]: sessionId, [config.turnTypeHeader]: turnType, }; + // Signal proxy that context-engine may have injected memories at gateway level + if (contextEngineAvailable) { + headers["x-metaclaw-contextengine"] = "1"; + } + pendingHeaders = headers; return {}; }); diff --git a/metaclaw/api_server.py b/metaclaw/api_server.py index 0d3da24..48469f8 100644 --- a/metaclaw/api_server.py +++ b/metaclaw/api_server.py @@ -622,6 +622,7 @@ async def chat_completions( x_memory_scope: Optional[str] = Header(default=None), x_user_id: Optional[str] = Header(default=None), x_workspace_id: Optional[str] = Header(default=None), + x_metaclaw_contextengine: Optional[str] = Header(default=None), ): owner: MetaClawAPIServer = request.app.state.owner # Update idle tracker so the scheduler knows the user is active @@ -687,6 +688,7 @@ async def chat_completions( turn_type=turn_type, session_done=session_done, memory_scope=memory_scope, + context_engine_active=x_metaclaw_contextengine == "1", ) if stream: return StreamingResponse( @@ -1194,6 +1196,7 @@ async def _handle_request( turn_type: str, session_done: bool, memory_scope: str = "", + context_engine_active: bool = False, ) -> dict[str, Any]: messages = body.get("messages") if not isinstance(messages, list) or not messages: @@ -1252,7 +1255,19 @@ def _prompt_len(msgs): # Inject memory and skills into system message for main turns if turn_type == "main": - if ( + if context_engine_active and self.config.openclaw_context_engine_enabled: + if ( + self.config.openclaw_prefer_proxy_synergy + and self.memory_manager + and self.skill_manager + and self.config.synergy_enabled + ): + # User opted into proxy-side synergy even with context-engine active + messages = await self._inject_augmentation(messages, scope_id=effective_memory_scope) + elif self.skill_manager: + # Context-engine injected memories at gateway — skills only + messages = self._inject_skills(messages) + elif ( self.memory_manager and self.skill_manager and self.config.synergy_enabled diff --git a/metaclaw/claw_adapter.py b/metaclaw/claw_adapter.py index c4a1aed..13570e5 100644 --- a/metaclaw/claw_adapter.py +++ b/metaclaw/claw_adapter.py @@ -77,8 +77,13 @@ def _configure_openclaw(cfg: "MetaClawConfig") -> None: ["openclaw", "config", "set", "agents.defaults.model.primary", f"metaclaw/{model_id}"], ["openclaw", "config", "set", "agents.defaults.sandbox.mode", "off"], - ["openclaw", "gateway", "restart"], ] + # Suppress built-in Active Memory — MetaClaw handles memory via context-engine + if cfg.openclaw_active_memory_compat: + commands.append( + ["openclaw", "config", "set", "plugins.slots.memory", "metaclaw-memory"], + ) + commands.append(["openclaw", "gateway", "restart"]) _run_commands("openclaw", commands) diff --git a/metaclaw/config.py b/metaclaw/config.py index 41925dc..387cbea 100644 --- a/metaclaw/config.py +++ b/metaclaw/config.py @@ -176,3 +176,11 @@ class MetaClawConfig: # WeChat (official openclaw-weixin plugin, auto-installed) # # ------------------------------------------------------------------ # wechat_enabled: bool = False + + # ------------------------------------------------------------------ # + # OpenClaw Compatibility # + # ------------------------------------------------------------------ # + openclaw_context_engine_enabled: bool = True # Use context-engine lifecycle (v2026.4.10+) + openclaw_active_memory_compat: bool = True # Suppress OpenClaw built-in Active Memory + openclaw_prefer_proxy_synergy: bool = False # Force proxy-side synergy when context-engine active + openclaw_min_version: str = "2026.4.10" # Minimum OpenClaw version for full integration diff --git a/metaclaw/config_store.py b/metaclaw/config_store.py index 99c8e55..5a0e368 100644 --- a/metaclaw/config_store.py +++ b/metaclaw/config_store.py @@ -79,6 +79,12 @@ "wechat": { "enabled": False, }, + "openclaw_compat": { + "context_engine_enabled": True, + "active_memory_compat": True, + "prefer_proxy_synergy": False, + "min_version": "2026.4.10", + }, } @@ -185,6 +191,7 @@ def to_metaclaw_config(self) -> MetaClawConfig: sched = data.get("scheduler", {}) sched_cal = sched.get("calendar", {}) wx = data.get("wechat", {}) + oc = data.get("openclaw_compat", {}) mode = data.get("mode", "auto") rl_enabled = mode in ("rl", "auto") or bool(rl.get("enabled", False)) @@ -315,8 +322,12 @@ def to_metaclaw_config(self) -> MetaClawConfig: sched_cal.get("token_path", "") or str(Path.home() / ".metaclaw" / "calendar_token.json") ), - # WeChat (official openclaw-weixin plugin) wechat_enabled=_yaml_bool(wx.get("enabled"), False), + # OpenClaw Compatibility (v2026.4.10+) + openclaw_context_engine_enabled=_yaml_bool(oc.get("context_engine_enabled"), True), + openclaw_active_memory_compat=_yaml_bool(oc.get("active_memory_compat"), True), + openclaw_prefer_proxy_synergy=_yaml_bool(oc.get("prefer_proxy_synergy"), False), + openclaw_min_version=str(oc.get("min_version", "2026.4.10")), ) def describe(self) -> str: @@ -358,4 +369,12 @@ def describe(self) -> str: f"memory.stale_h: {memory.get('review_stale_after_hours', 72)}", f"wechat.enabled: {wx.get('enabled', False)}", ] + oc = data.get("openclaw_compat", {}) + if oc: + lines += [ + f"openclaw.context_engine: {oc.get('context_engine_enabled', True)}", + f"openclaw.active_memory: {oc.get('active_memory_compat', True)}", + f"openclaw.proxy_synergy: {oc.get('prefer_proxy_synergy', False)}", + f"openclaw.min_version: {oc.get('min_version', '2026.4.10')}", + ] return "\n".join(lines) diff --git a/metaclaw/setup_wizard.py b/metaclaw/setup_wizard.py index 995ab6a..abe54d2 100644 --- a/metaclaw/setup_wizard.py +++ b/metaclaw/setup_wizard.py @@ -412,6 +412,49 @@ def run(self): else: scheduler_config = {"enabled": False, "calendar": {"enabled": False}} + + # ---- OpenClaw Compatibility (advanced) ---- + current_oc = existing.get("openclaw_compat", {}) + show_oc = _prompt_bool( + "Configure OpenClaw compatibility settings (advanced)", + default=False, + ) + if show_oc: + print("\n--- OpenClaw Compatibility ---") + print( + "MetaClaw integrates with OpenClaw v2026.4.10+ via context-engine lifecycle\n" + "and can suppress built-in Active Memory to avoid duplicate injections." + ) + oc_context_engine = _prompt_bool( + "Enable context-engine integration (memory via assemble/compact lifecycle)", + default=current_oc.get("context_engine_enabled", True), + ) + oc_active_memory = _prompt_bool( + "Suppress OpenClaw built-in Active Memory", + default=current_oc.get("active_memory_compat", True), + ) + oc_proxy_synergy = _prompt_bool( + "Force proxy-side synergy (memory+skills) even with context-engine active", + default=current_oc.get("prefer_proxy_synergy", False), + ) + oc_min_version = _prompt( + "Minimum OpenClaw version", + default=current_oc.get("min_version", "2026.4.10"), + ) + openclaw_compat_config = { + "context_engine_enabled": oc_context_engine, + "active_memory_compat": oc_active_memory, + "prefer_proxy_synergy": oc_proxy_synergy, + "min_version": oc_min_version, + } + else: + openclaw_compat_config = current_oc or { + "context_engine_enabled": True, + "active_memory_compat": True, + "prefer_proxy_synergy": False, + "min_version": "2026.4.10", + } + # ---- Write config ---- data = { "mode": mode, @@ -434,6 +477,7 @@ def run(self): }, "rl": rl_config, "scheduler": scheduler_config, + "openclaw_compat": openclaw_compat_config, } cs.save(data) From 071efcac81f584d9c88bca253375e0f69672d138 Mon Sep 17 00:00:00 2001 From: OpenCode Date: Sun, 19 Apr 2026 15:51:24 +0700 Subject: [PATCH 3/5] Upgrade memory plugin to context-engine lifecycle with incremental capture - Add context-engine.ts implementing assemble/compact lifecycle: retrieve relevant memories on assemble, consolidate on compact, no-op ingest/afterTurn (sidecar scheduler handles batching) - Register as both 'memory' and 'context-engine' plugin kind; skip auto-recall when context-engine is active to prevent double-injection at gateway level - Refactor auto-capture from bulk ingest to per-turn bufferTurn with session_end final flush, tracking per-session turn counts to only enqueue new turns on each agent_end event - Add bufferTurn/flushSession methods to SidecarClient with BufferTurnResponse and FlushSessionResponse types - Add vitest dev dependency and config, with unit tests for context-engine assembly logic and plugin registration - Rebuild dist/ to reflect all source changes --- openclaw-metaclaw-memory/dist/client.d.ts | 7 +- openclaw-metaclaw-memory/dist/client.js | 14 + openclaw-metaclaw-memory/dist/client.js.map | 2 +- .../dist/context-engine.d.ts | 34 + .../dist/context-engine.js | 94 ++ .../dist/context-engine.js.map | 1 + .../dist/hooks/auto-capture.js | 46 +- .../dist/hooks/auto-capture.js.map | 2 +- openclaw-metaclaw-memory/dist/index.d.ts | 2 +- openclaw-metaclaw-memory/dist/index.js | 23 +- openclaw-metaclaw-memory/dist/index.js.map | 2 +- openclaw-metaclaw-memory/dist/types.d.ts | 7 + openclaw-metaclaw-memory/openclaw.plugin.json | 2 +- openclaw-metaclaw-memory/package-lock.json | 1279 ++++++++++++++++- openclaw-metaclaw-memory/package.json | 26 +- .../src/__tests__/context-engine.test.ts | 183 +++ .../src/__tests__/index.test.ts | 106 ++ .../src/context-engine.ts | 138 ++ openclaw-metaclaw-memory/src/index.ts | 25 +- openclaw-metaclaw-memory/vitest.config.ts | 7 + 20 files changed, 1974 insertions(+), 26 deletions(-) create mode 100644 openclaw-metaclaw-memory/dist/context-engine.d.ts create mode 100644 openclaw-metaclaw-memory/dist/context-engine.js create mode 100644 openclaw-metaclaw-memory/dist/context-engine.js.map create mode 100644 openclaw-metaclaw-memory/src/__tests__/context-engine.test.ts create mode 100644 openclaw-metaclaw-memory/src/__tests__/index.test.ts create mode 100644 openclaw-metaclaw-memory/src/context-engine.ts create mode 100644 openclaw-metaclaw-memory/vitest.config.ts diff --git a/openclaw-metaclaw-memory/dist/client.d.ts b/openclaw-metaclaw-memory/dist/client.d.ts index 0dfe088..9f2334f 100644 --- a/openclaw-metaclaw-memory/dist/client.d.ts +++ b/openclaw-metaclaw-memory/dist/client.d.ts @@ -1,4 +1,4 @@ -import type { HealthResponse, RetrieveResponse, IngestResponse, SearchResult, StoreResponse, StatsResponse, ConsolidateResponse, UpgradeStatusResponse } from "./types.js"; +import type { HealthResponse, RetrieveResponse, IngestResponse, BufferTurnResponse, FlushSessionResponse, SearchResult, StoreResponse, StatsResponse, ConsolidateResponse, UpgradeStatusResponse } from "./types.js"; export declare class SidecarClient { private baseUrl; constructor(baseUrl: string); @@ -9,6 +9,11 @@ export declare class SidecarClient { prompt_text: string; response_text: string; }>, scopeId?: string): Promise; + bufferTurn(sessionId: string, turn: { + prompt_text: string; + response_text: string; + }, scopeId?: string): Promise; + flushSession(sessionId: string, scopeId?: string, final?: boolean): Promise; search(query: string, scopeId?: string, limit?: number): Promise; store(content: string, memoryType: string, scopeId?: string, tags?: string[], importance?: number): Promise; forget(memoryId: string): Promise<{ diff --git a/openclaw-metaclaw-memory/dist/client.js b/openclaw-metaclaw-memory/dist/client.js index 91b5492..ed2815d 100644 --- a/openclaw-metaclaw-memory/dist/client.js +++ b/openclaw-metaclaw-memory/dist/client.js @@ -35,6 +35,20 @@ export class SidecarClient { ...(scopeId && { scope_id: scopeId }), }); } + async bufferTurn(sessionId, turn, scopeId) { + return this.request("/buffer_turn", { + session_id: sessionId, + turn, + ...(scopeId && { scope_id: scopeId }), + }); + } + async flushSession(sessionId, scopeId, final = true) { + return this.request("/flush_session", { + session_id: sessionId, + final, + ...(scopeId && { scope_id: scopeId }), + }); + } async search(query, scopeId, limit) { const resp = await this.request("/search", { query, diff --git a/openclaw-metaclaw-memory/dist/client.js.map b/openclaw-metaclaw-memory/dist/client.js.map index 6c996ce..58b9ea5 100644 --- a/openclaw-metaclaw-memory/dist/client.js.map +++ b/openclaw-metaclaw-memory/dist/client.js.map @@ -1 +1 @@ -{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/openclaw-metaclaw-memory/dist/context-engine.d.ts b/openclaw-metaclaw-memory/dist/context-engine.d.ts new file mode 100644 index 0000000..8e7e9b5 --- /dev/null +++ b/openclaw-metaclaw-memory/dist/context-engine.d.ts @@ -0,0 +1,34 @@ +import type { SidecarClient } from "./client.js"; +import type { PluginConfig } from "./types.js"; +interface AssembleQuery { + sessionId: string; + messages: Array>; + systemPrompt?: string; +} +interface AssembleResult { + messages: Array>; + estimatedTokens: number; + systemPromptAddition?: string; +} +interface CompactResult { + ok: boolean; + compacted: boolean; + reason?: string; +} +interface ContextEngine { + bootstrap(): Promise; + ingest?(messages: Array>): Promise; + ingestBatch?(messages: Array>>): Promise; + afterTurn?(result: Record): Promise; + assemble(query: AssembleQuery): Promise; + compact?(sessionId: string): Promise; + dispose(): Promise; +} +interface Logger { + info(message: string, ...args: unknown[]): void; + warn(message: string, ...args: unknown[]): void; + error(message: string, ...args: unknown[]): void; + debug?(message: string, ...args: unknown[]): void; +} +export declare function createMetaClawContextEngine(getClient: () => SidecarClient, cfg: PluginConfig, logger: Logger): ContextEngine; +export {}; diff --git a/openclaw-metaclaw-memory/dist/context-engine.js b/openclaw-metaclaw-memory/dist/context-engine.js new file mode 100644 index 0000000..2ed7ba6 --- /dev/null +++ b/openclaw-metaclaw-memory/dist/context-engine.js @@ -0,0 +1,94 @@ +function extractUserPrompt(messages) { + for (let i = messages.length - 1; i >= 0; i--) { + const msg = messages[i]; + if (!msg || msg.role !== "user") + continue; + const content = msg.content; + if (typeof content === "string") { + const trimmed = content.trim(); + return trimmed.length > 0 ? trimmed : null; + } + if (Array.isArray(content)) { + const parts = []; + for (const block of content) { + if (block && typeof block === "object") { + const b = block; + if (typeof b.text === "string") { + parts.push(b.text); + } + else if (b.type === "text" && typeof b.content === "string") { + parts.push(b.content); + } + } + else if (typeof block === "string") { + parts.push(block); + } + } + const joined = parts.join("\n").trim(); + return joined.length > 0 ? joined : null; + } + } + return null; +} +export function createMetaClawContextEngine(getClient, cfg, logger) { + return { + async bootstrap() { + const client = getClient(); + try { + await client.health(); + logger.info("metaclaw-memory: context-engine bootstrap ok (sidecar healthy)"); + } + catch (err) { + const msg = err instanceof Error ? err.message : String(err); + logger.error(`metaclaw-memory: context-engine bootstrap failed: ${msg}`); + throw new Error(`metaclaw-memory context-engine bootstrap failed: ${msg}`); + } + }, + async ingest(_messages) { + // No-op: turn ingestion is handled by auto-capture hook + sidecar scheduler. + }, + async ingestBatch(_messages) { + // No-op: same as ingest — sidecar scheduler handles batching. + }, + async afterTurn(_result) { + // No-op: consolidation handled by sidecar scheduler. + }, + async assemble(query) { + const prompt = extractUserPrompt(query.messages); + if (!prompt) { + return { messages: query.messages, estimatedTokens: 0 }; + } + try { + const result = await getClient().retrieve(prompt, cfg.scope); + if (result.unit_count > 0 && result.rendered_prompt) { + return { + messages: query.messages, + estimatedTokens: Math.ceil(result.rendered_prompt.length / 4), + systemPromptAddition: result.rendered_prompt, + }; + } + return { messages: query.messages, estimatedTokens: 0 }; + } + catch (err) { + const msg = err instanceof Error ? err.message : String(err); + logger.warn(`metaclaw-memory: assemble retrieve failed: ${msg}`); + return { messages: query.messages, estimatedTokens: 0 }; + } + }, + async compact(_sessionId) { + try { + await getClient().consolidate(cfg.scope); + return { ok: true, compacted: true }; + } + catch (err) { + const msg = err instanceof Error ? err.message : String(err); + logger.warn(`metaclaw-memory: compact consolidate failed: ${msg}`); + return { ok: false, compacted: false, reason: msg }; + } + }, + async dispose() { + // No-op: sidecar lifecycle managed by SidecarManager via registerService. + }, + }; +} +//# sourceMappingURL=context-engine.js.map \ No newline at end of file diff --git a/openclaw-metaclaw-memory/dist/context-engine.js.map b/openclaw-metaclaw-memory/dist/context-engine.js.map new file mode 100644 index 0000000..c83a768 --- /dev/null +++ b/openclaw-metaclaw-memory/dist/context-engine.js.map @@ -0,0 +1 @@ +{"version":3,"file":"context-engine.js","sourceRoot":"","sources":["../src/context-engine.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/openclaw-metaclaw-memory/dist/hooks/auto-capture.js b/openclaw-metaclaw-memory/dist/hooks/auto-capture.js index c602dc0..3b55e88 100644 --- a/openclaw-metaclaw-memory/dist/hooks/auto-capture.js +++ b/openclaw-metaclaw-memory/dist/hooks/auto-capture.js @@ -1,26 +1,56 @@ import { randomUUID } from "node:crypto"; +// Per-session state: how many turns have already been forwarded to the sidecar. +// Lets agent_end fire per-turn with a full history snapshot while we only +// enqueue the *new* turn(s) since the previous attempt. +const sessionTurnCounts = new Map(); export function registerAutoCapture(api, getClient, config) { if (!config.autoCapture) return; - api.on("agent_end", async (event, _ctx) => { + api.on("agent_end", async (event, ctx) => { try { if (!event.success) return; const messages = event.messages; if (!Array.isArray(messages) || messages.length === 0) return; - const turns = extractTurns(messages); - if (turns.length === 0) + const sessionId = ctx?.sessionId || + event.sessionId || + randomUUID(); + const allTurns = extractTurns(messages); + const alreadySent = sessionTurnCounts.get(sessionId) ?? 0; + const newTurns = allTurns.slice(alreadySent); + if (newTurns.length === 0) return; - const sessionId = event.sessionId || randomUUID(); const client = getClient(); - const result = await client.ingest(sessionId, turns, config.scope); - if (result.added > 0) { - api.logger.info(`metaclaw-memory: captured ${result.added} memories from session ${sessionId}`); + for (const turn of newTurns) { + const res = await client.bufferTurn(sessionId, turn, config.scope); + if (res.flushed && res.added && res.added > 0) { + api.logger.info(`metaclaw-memory: incremental flush added ${res.added} memories (session=${sessionId})`); + } } + sessionTurnCounts.set(sessionId, allTurns.length); } catch (err) { - api.logger.error("metaclaw-memory: auto-capture failed", err); + api.logger.error("metaclaw-memory: auto-capture buffer_turn failed", err); + } + }); + api.on("session_end", async (event, ctx) => { + try { + const sessionId = event?.sessionId ?? + ctx?.sessionId; + if (!sessionId) + return; + if (!sessionTurnCounts.has(sessionId)) + return; + const client = getClient(); + const res = await client.flushSession(sessionId, config.scope, true); + if (res.added > 0) { + api.logger.info(`metaclaw-memory: final flush added ${res.added} memories (session=${sessionId})`); + } + sessionTurnCounts.delete(sessionId); + } + catch (err) { + api.logger.error("metaclaw-memory: auto-capture flush_session failed", err); } }); } diff --git a/openclaw-metaclaw-memory/dist/hooks/auto-capture.js.map b/openclaw-metaclaw-memory/dist/hooks/auto-capture.js.map index d740308..e0913de 100644 --- a/openclaw-metaclaw-memory/dist/hooks/auto-capture.js.map +++ b/openclaw-metaclaw-memory/dist/hooks/auto-capture.js.map @@ -1 +1 @@ -{"version":3,"file":"auto-capture.js","sourceRoot":"","sources":["../../src/hooks/auto-capture.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"auto-capture.js","sourceRoot":"","sources":["../../src/hooks/auto-capture.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/openclaw-metaclaw-memory/dist/index.d.ts b/openclaw-metaclaw-memory/dist/index.d.ts index 04aff1d..70dc182 100644 --- a/openclaw-metaclaw-memory/dist/index.d.ts +++ b/openclaw-metaclaw-memory/dist/index.d.ts @@ -2,7 +2,7 @@ declare const _default: { id: string; name: string; description: string; - kind: "memory"; + kind: readonly ["memory", "context-engine"]; configSchema: import("@sinclair/typebox").TObject<{ autoRecall: import("@sinclair/typebox").TOptional; autoCapture: import("@sinclair/typebox").TOptional; diff --git a/openclaw-metaclaw-memory/dist/index.js b/openclaw-metaclaw-memory/dist/index.js index 60f5e6a..22cc2aa 100644 --- a/openclaw-metaclaw-memory/dist/index.js +++ b/openclaw-metaclaw-memory/dist/index.js @@ -9,12 +9,13 @@ import { registerMemoryForgetTool } from "./tools/memory-forget.js"; import { registerMemoryStatusTool } from "./tools/memory-status.js"; import { registerCli } from "./commands/cli.js"; import { registerSlashCommands } from "./commands/slash.js"; +import { createMetaClawContextEngine } from "./context-engine.js"; import { configSchema } from "./config-schema.js"; export default { id: "metaclaw-memory", name: "MetaClaw Memory", description: "Self-evolving local-first memory with hybrid retrieval, 6 structured types, and adaptive policy — no cloud required.", - kind: "memory", + kind: ["memory", "context-engine"], configSchema, register(api) { const cfg = parseConfig(api.pluginConfig ?? {}); @@ -44,8 +45,24 @@ export default { } return client; }; - // Hooks - registerAutoRecall(api, getClient, cfg); + // ContextEngine registration (OpenClaw v2026.4.10+) + // If context-engine API is available, register and skip auto-recall + // to prevent double-injection (assemble + prependContext both injecting memories). + let contextEngineActive = false; + try { + if (typeof api.registerContextEngine === "function") { + api.registerContextEngine("metaclaw-memory", () => createMetaClawContextEngine(getClient, cfg, api.logger)); + contextEngineActive = true; + api.logger.info("metaclaw-memory: context-engine registered (assemble/compact lifecycle)"); + } + } + catch { + api.logger.info("metaclaw-memory: context-engine registration skipped (API not available)"); + } + // Hooks — skip auto-recall if context-engine handles memory injection + if (!contextEngineActive) { + registerAutoRecall(api, getClient, cfg); + } registerAutoCapture(api, getClient, cfg); // AI tools registerMemorySearchTool(api, getClient, cfg); diff --git a/openclaw-metaclaw-memory/dist/index.js.map b/openclaw-metaclaw-memory/dist/index.js.map index 15f3da6..96debc3 100644 --- a/openclaw-metaclaw-memory/dist/index.js.map +++ b/openclaw-metaclaw-memory/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAC7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAA;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAA;AACnE,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAA;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,eAAe;IACb,EAAE,EAAE,iBAAiB;IACrB,IAAI,EAAE,iBAAiB;IACvB,WAAW,EACT,sHAAsH;IACxH,IAAI,EAAE,QAAiB;IACvB,YAAY;IAEZ,QAAQ,CAAC,GAAQ;QACf,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAA;QAE/C,IAAI,OAAO,GAA0B,IAAI,CAAA;QACzC,IAAI,MAAM,GAAyB,IAAI,CAAA;QAEvC,wCAAwC;QACxC,GAAG,CAAC,eAAe,CAAC;YAClB,EAAE,EAAE,iBAAiB;YACrB,KAAK,EAAE,KAAK,IAAI,EAAE;gBAChB,OAAO,GAAG,IAAI,cAAc,CAAC,GAAG,CAAC,CAAA;gBACjC,MAAM,GAAG,IAAI,aAAa,CAAC,oBAAoB,GAAG,CAAC,WAAW,EAAE,CAAC,CAAA;gBACjE,MAAM,OAAO,CAAC,KAAK,EAAE,CAAA;gBACrB,MAAM,OAAO,CAAC,YAAY,EAAE,CAAA;gBAC5B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAA;YACrD,CAAC;YACD,IAAI,EAAE,GAAG,EAAE;gBACT,IAAI,OAAO,EAAE,CAAC;oBACZ,OAAO,CAAC,IAAI,EAAE,CAAA;oBACd,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAA;gBACrD,CAAC;YACH,CAAC;SACF,CAAC,CAAA;QAEF,mEAAmE;QACnE,MAAM,SAAS,GAAG,GAAkB,EAAE;YACpC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,GAAG,IAAI,aAAa,CAAC,oBAAoB,GAAG,CAAC,WAAW,EAAE,CAAC,CAAA;YACnE,CAAC;YACD,OAAO,MAAM,CAAA;QACf,CAAC,CAAA;QAED,QAAQ;QACR,kBAAkB,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,CAAA;QACvC,mBAAmB,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,CAAA;QAExC,WAAW;QACX,wBAAwB,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,CAAA;QAC7C,uBAAuB,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,CAAA;QAC5C,wBAAwB,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,CAAA;QAC7C,wBAAwB,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,CAAA;QAE7C,sDAAsD;QACtD,qBAAqB,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,CAAA;QAE1C,oEAAoE;QACpE,WAAW,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,CAAA;IAClC,CAAC;CACF,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/openclaw-metaclaw-memory/dist/types.d.ts b/openclaw-metaclaw-memory/dist/types.d.ts index 22d9344..7a1868b 100644 --- a/openclaw-metaclaw-memory/dist/types.d.ts +++ b/openclaw-metaclaw-memory/dist/types.d.ts @@ -43,6 +43,13 @@ export interface RetrieveResponse { export interface IngestResponse { added: number; } +export interface BufferTurnResponse { + flushed: boolean; + added: number | null; +} +export interface FlushSessionResponse { + added: number; +} export interface StoreResponse { memory_id: string; } diff --git a/openclaw-metaclaw-memory/openclaw.plugin.json b/openclaw-metaclaw-memory/openclaw.plugin.json index a39c6f5..4cf7b37 100644 --- a/openclaw-metaclaw-memory/openclaw.plugin.json +++ b/openclaw-metaclaw-memory/openclaw.plugin.json @@ -1,6 +1,6 @@ { "id": "metaclaw-memory", - "kind": "memory", + "kind": ["memory", "context-engine"], "configSchema": { "type": "object", "additionalProperties": false, diff --git a/openclaw-metaclaw-memory/package-lock.json b/openclaw-metaclaw-memory/package-lock.json index 0b85ab7..dd67c6b 100644 --- a/openclaw-metaclaw-memory/package-lock.json +++ b/openclaw-metaclaw-memory/package-lock.json @@ -13,7 +13,8 @@ }, "devDependencies": { "@types/node": "^20.0.0", - "typescript": "^5.4.0" + "typescript": "^5.4.0", + "vitest": "^4.1.4" }, "engines": { "node": ">=18" @@ -27,12 +28,407 @@ } } }, + "node_modules/@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.124.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", + "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", + "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", + "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", + "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", + "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", + "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", + "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.9.2", + "@emnapi/runtime": "1.9.2", + "@napi-rs/wasm-runtime": "^1.1.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", + "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", + "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", + "dev": true, + "license": "MIT" + }, "node_modules/@sinclair/typebox": { "version": "0.32.35", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.32.35.tgz", "integrity": "sha512-Ul3YyOTU++to8cgNkttakC0dWvpERr6RYoHO2W47DLbFvrwBDJUY31B1sImH6JZSYc4Kt4PyHtoPNu+vL2r2dA==", "license": "MIT" }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "20.19.37", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz", @@ -43,6 +439,702 @@ "undici-types": "~6.21.0" } }, + "node_modules/@vitest/expect": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz", + "integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.4", + "@vitest/utils": "4.1.4", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz", + "integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz", + "integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.4.tgz", + "integrity": "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.4", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.4.tgz", + "integrity": "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.4", + "@vitest/utils": "4.1.4", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.4.tgz", + "integrity": "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.4.tgz", + "integrity": "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.4", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.15", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", + "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.124.0", + "@rolldown/pluginutils": "1.0.0-rc.15" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", + "@rolldown/binding-darwin-x64": "1.0.0-rc.15", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", + "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -63,6 +1155,191 @@ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" + }, + "node_modules/vite": { + "version": "8.0.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", + "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.15", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.4.tgz", + "integrity": "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.4", + "@vitest/mocker": "4.1.4", + "@vitest/pretty-format": "4.1.4", + "@vitest/runner": "4.1.4", + "@vitest/snapshot": "4.1.4", + "@vitest/spy": "4.1.4", + "@vitest/utils": "4.1.4", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.4", + "@vitest/browser-preview": "4.1.4", + "@vitest/browser-webdriverio": "4.1.4", + "@vitest/coverage-istanbul": "4.1.4", + "@vitest/coverage-v8": "4.1.4", + "@vitest/ui": "4.1.4", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } } } } diff --git a/openclaw-metaclaw-memory/package.json b/openclaw-metaclaw-memory/package.json index 0942bc3..4c864b6 100644 --- a/openclaw-metaclaw-memory/package.json +++ b/openclaw-metaclaw-memory/package.json @@ -6,30 +6,46 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "openclaw": { - "extensions": ["./dist/index.js"] + "extensions": [ + "./dist/index.js" + ] }, "scripts": { "build": "tsc", "dev": "tsc --watch", + "test": "vitest run", "prepublishOnly": "npm run build" }, - "keywords": ["openclaw", "plugin", "memory", "local", "metaclaw"], + "keywords": [ + "openclaw", + "plugin", + "memory", + "local", + "metaclaw" + ], "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.32.0" }, "devDependencies": { + "@types/node": "^20.0.0", "typescript": "^5.4.0", - "@types/node": "^20.0.0" + "vitest": "^4.1.4" }, "peerDependencies": { "openclaw": "*" }, "peerDependenciesMeta": { - "openclaw": { "optional": true } + "openclaw": { + "optional": true + } }, "engines": { "node": ">=18" }, - "files": ["dist/", "openclaw.plugin.json", "sidecar/"] + "files": [ + "dist/", + "openclaw.plugin.json", + "sidecar/" + ] } diff --git a/openclaw-metaclaw-memory/src/__tests__/context-engine.test.ts b/openclaw-metaclaw-memory/src/__tests__/context-engine.test.ts new file mode 100644 index 0000000..0fb3860 --- /dev/null +++ b/openclaw-metaclaw-memory/src/__tests__/context-engine.test.ts @@ -0,0 +1,183 @@ +import { describe, it, expect, vi } from "vitest"; +import { createMetaClawContextEngine } from "../context-engine.js"; + +function makeLogger() { + return { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }; +} + +const cfg = { scope: "default" } as any; + +describe("createMetaClawContextEngine", () => { + describe("assemble", () => { + it("returns systemPromptAddition when sidecar has memories", async () => { + const mockClient = { + retrieve: vi.fn().mockResolvedValue({ + unit_count: 2, + rendered_prompt: "Memory 1: ...\nMemory 2: ...", + }), + }; + const logger = makeLogger(); + const engine = createMetaClawContextEngine(() => mockClient as any, cfg, logger); + const result = await engine.assemble({ + sessionId: "test-session", + messages: [{ role: "user", content: "What is MetaClaw?" }], + }); + + expect(result.systemPromptAddition).toBe("Memory 1: ...\nMemory 2: ..."); + expect(result.estimatedTokens).toBeGreaterThan(0); + expect(result.messages).toHaveLength(1); + expect(mockClient.retrieve).toHaveBeenCalledWith("What is MetaClaw?", "default"); + }); + + it("returns empty when no user message found", async () => { + const mockClient = { retrieve: vi.fn() }; + const logger = makeLogger(); + const engine = createMetaClawContextEngine(() => mockClient as any, cfg, logger); + const result = await engine.assemble({ + sessionId: "test-session", + messages: [{ role: "system", content: "You are helpful" }], + }); + + expect(result.systemPromptAddition).toBeUndefined(); + expect(result.estimatedTokens).toBe(0); + expect(mockClient.retrieve).not.toHaveBeenCalled(); + }); + + it("returns empty when sidecar has no memories", async () => { + const mockClient = { + retrieve: vi.fn().mockResolvedValue({ unit_count: 0, rendered_prompt: null }), + }; + const logger = makeLogger(); + const engine = createMetaClawContextEngine(() => mockClient as any, cfg, logger); + const result = await engine.assemble({ + sessionId: "test", + messages: [{ role: "user", content: "hello" }], + }); + + expect(result.systemPromptAddition).toBeUndefined(); + expect(result.estimatedTokens).toBe(0); + }); + + it("gracefully handles retrieve errors", async () => { + const mockClient = { + retrieve: vi.fn().mockRejectedValue(new Error("sidecar down")), + }; + const logger = makeLogger(); + const engine = createMetaClawContextEngine(() => mockClient as any, cfg, logger); + const result = await engine.assemble({ + sessionId: "test", + messages: [{ role: "user", content: "hello" }], + }); + + expect(result.systemPromptAddition).toBeUndefined(); + expect(result.estimatedTokens).toBe(0); + expect(result.messages).toHaveLength(1); + expect(logger.warn).toHaveBeenCalled(); + }); + + it("extracts prompt from array content blocks", async () => { + const mockClient = { + retrieve: vi.fn().mockResolvedValue({ unit_count: 1, rendered_prompt: "mem" }), + }; + const logger = makeLogger(); + const engine = createMetaClawContextEngine(() => mockClient as any, cfg, logger); + await engine.assemble({ + sessionId: "test", + messages: [ + { + role: "user", + content: [ + { type: "text", text: "Hello " }, + { type: "text", text: "World" }, + ], + }, + ], + }); + + expect(mockClient.retrieve).toHaveBeenCalledWith("Hello \nWorld", "default"); + }); + + it("returns empty when user content is empty/whitespace string", async () => { + const mockClient = { retrieve: vi.fn() }; + const logger = makeLogger(); + const engine = createMetaClawContextEngine(() => mockClient as any, cfg, logger); + const result = await engine.assemble({ + sessionId: "t", + messages: [{ role: "user", content: " " }], + }); + + expect(result.systemPromptAddition).toBeUndefined(); + expect(mockClient.retrieve).not.toHaveBeenCalled(); + }); + }); + + describe("bootstrap", () => { + it("succeeds when sidecar is healthy", async () => { + const mockClient = { health: vi.fn().mockResolvedValue({ ok: true }) }; + const logger = makeLogger(); + const engine = createMetaClawContextEngine(() => mockClient as any, cfg, logger); + + await expect(engine.bootstrap()).resolves.toBeUndefined(); + expect(logger.info).toHaveBeenCalledWith(expect.stringContaining("bootstrap ok")); + }); + + it("throws when sidecar is unhealthy", async () => { + const mockClient = { + health: vi.fn().mockRejectedValue(new Error("connection refused")), + }; + const logger = makeLogger(); + const engine = createMetaClawContextEngine(() => mockClient as any, cfg, logger); + + await expect(engine.bootstrap()).rejects.toThrow("bootstrap failed"); + expect(logger.error).toHaveBeenCalled(); + }); + }); + + describe("compact", () => { + it("consolidates memory and returns ok", async () => { + const mockClient = { consolidate: vi.fn().mockResolvedValue({ ok: true }) }; + const logger = makeLogger(); + const engine = createMetaClawContextEngine(() => mockClient as any, cfg, logger); + + const result = await engine.compact!("session-123"); + expect(result.ok).toBe(true); + expect(result.compacted).toBe(true); + expect(mockClient.consolidate).toHaveBeenCalledWith("default"); + }); + + it("returns failure on consolidate error", async () => { + const mockClient = { + consolidate: vi.fn().mockRejectedValue(new Error("timeout")), + }; + const logger = makeLogger(); + const engine = createMetaClawContextEngine(() => mockClient as any, cfg, logger); + + const result = await engine.compact!("session-123"); + expect(result.ok).toBe(false); + expect(result.compacted).toBe(false); + expect(result.reason).toContain("timeout"); + }); + }); + + describe("no-op lifecycle methods", () => { + const mockClient = {} as any; + const logger = makeLogger(); + const engine = createMetaClawContextEngine(() => mockClient, cfg, logger); + + it("ingest is a no-op", async () => { + await expect(engine.ingest!([{ role: "user", content: "hi" }])).resolves.toBeUndefined(); + }); + + it("ingestBatch is a no-op", async () => { + await expect(engine.ingestBatch!([[{ role: "user", content: "hi" }]])).resolves.toBeUndefined(); + }); + + it("afterTurn is a no-op", async () => { + await expect(engine.afterTurn!({ ok: true })).resolves.toBeUndefined(); + }); + + it("dispose is a no-op", async () => { + await expect(engine.dispose()).resolves.toBeUndefined(); + }); + }); +}); diff --git a/openclaw-metaclaw-memory/src/__tests__/index.test.ts b/openclaw-metaclaw-memory/src/__tests__/index.test.ts new file mode 100644 index 0000000..11eb22f --- /dev/null +++ b/openclaw-metaclaw-memory/src/__tests__/index.test.ts @@ -0,0 +1,106 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; + +vi.mock("../hooks/auto-recall.js", () => ({ + registerAutoRecall: vi.fn(), +})); +vi.mock("../hooks/auto-capture.js", () => ({ + registerAutoCapture: vi.fn(), +})); +vi.mock("../tools/memory-search.js", () => ({ + registerMemorySearchTool: vi.fn(), +})); +vi.mock("../tools/memory-store.js", () => ({ + registerMemoryStoreTool: vi.fn(), +})); +vi.mock("../tools/memory-forget.js", () => ({ + registerMemoryForgetTool: vi.fn(), +})); +vi.mock("../tools/memory-status.js", () => ({ + registerMemoryStatusTool: vi.fn(), +})); +vi.mock("../commands/cli.js", () => ({ + registerCli: vi.fn(), +})); +vi.mock("../commands/slash.js", () => ({ + registerSlashCommands: vi.fn(), +})); +vi.mock("../sidecar.js", () => ({ + SidecarManager: vi.fn().mockImplementation(() => ({ + start: vi.fn(), + waitForReady: vi.fn(), + stop: vi.fn(), + })), +})); +vi.mock("../client.js", () => ({ + SidecarClient: vi.fn().mockImplementation(() => ({})), +})); +vi.mock("../config-schema.js", () => ({ + configSchema: {}, +})); +vi.mock("../types.js", () => ({ + parseConfig: (cfg: any) => ({ sidecarPort: 19823, scope: "default", ...cfg }), +})); + +import plugin from "../index.js"; +import { registerAutoRecall } from "../hooks/auto-recall.js"; +import { registerAutoCapture } from "../hooks/auto-capture.js"; + +function makeApi(overrides: Record = {}) { + return { + pluginConfig: {}, + registerService: vi.fn(), + logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() }, + on: vi.fn(), + ...overrides, + }; +} + +describe("plugin index.ts", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("exports dual kind", () => { + expect(plugin.kind).toEqual(["memory", "context-engine"]); + }); + + it("has correct id and name", () => { + expect(plugin.id).toBe("metaclaw-memory"); + expect(plugin.name).toBe("MetaClaw Memory"); + }); + + it("registers context-engine when API available", () => { + const mockRegisterCE = vi.fn(); + const api = makeApi({ registerContextEngine: mockRegisterCE }); + + plugin.register(api); + + expect(mockRegisterCE).toHaveBeenCalledWith("metaclaw-memory", expect.any(Function)); + }); + + it("skips auto-recall when context-engine is registered (intra-plugin guard)", () => { + const api = makeApi({ registerContextEngine: vi.fn() }); + + plugin.register(api); + + expect(registerAutoRecall).not.toHaveBeenCalled(); + expect(registerAutoCapture).toHaveBeenCalled(); + }); + + it("falls back to auto-recall when context-engine API not available", () => { + const api = makeApi(); + + plugin.register(api); + + expect(registerAutoRecall).toHaveBeenCalled(); + expect(registerAutoCapture).toHaveBeenCalled(); + }); + + it("registers a service for sidecar lifecycle", () => { + const api = makeApi(); + plugin.register(api); + expect(api.registerService).toHaveBeenCalledWith( + expect.objectContaining({ id: "metaclaw-memory" }), + ); + }); +}); diff --git a/openclaw-metaclaw-memory/src/context-engine.ts b/openclaw-metaclaw-memory/src/context-engine.ts new file mode 100644 index 0000000..9c14359 --- /dev/null +++ b/openclaw-metaclaw-memory/src/context-engine.ts @@ -0,0 +1,138 @@ +import type { SidecarClient } from "./client.js" +import type { PluginConfig } from "./types.js" + +// Minimal type definitions for ContextEngine API (OpenClaw v2026.4.10+) +// Defined locally to avoid importing from "openclaw/*" +interface AssembleQuery { + sessionId: string + messages: Array> + systemPrompt?: string +} + +interface AssembleResult { + messages: Array> + estimatedTokens: number + systemPromptAddition?: string +} + +interface CompactResult { + ok: boolean + compacted: boolean + reason?: string +} + +interface ContextEngine { + bootstrap(): Promise + ingest?(messages: Array>): Promise + ingestBatch?(messages: Array>>): Promise + afterTurn?(result: Record): Promise + assemble(query: AssembleQuery): Promise + compact?(sessionId: string): Promise + dispose(): Promise +} + +interface Logger { + info(message: string, ...args: unknown[]): void + warn(message: string, ...args: unknown[]): void + error(message: string, ...args: unknown[]): void + debug?(message: string, ...args: unknown[]): void +} + +function extractUserPrompt(messages: Array>): string | null { + for (let i = messages.length - 1; i >= 0; i--) { + const msg = messages[i] + if (!msg || msg.role !== "user") continue + const content = msg.content + if (typeof content === "string") { + const trimmed = content.trim() + return trimmed.length > 0 ? trimmed : null + } + if (Array.isArray(content)) { + const parts: string[] = [] + for (const block of content) { + if (block && typeof block === "object") { + const b = block as Record + if (typeof b.text === "string") { + parts.push(b.text) + } else if (b.type === "text" && typeof b.content === "string") { + parts.push(b.content) + } + } else if (typeof block === "string") { + parts.push(block) + } + } + const joined = parts.join("\n").trim() + return joined.length > 0 ? joined : null + } + } + return null +} + +export function createMetaClawContextEngine( + getClient: () => SidecarClient, + cfg: PluginConfig, + logger: Logger, +): ContextEngine { + return { + async bootstrap(): Promise { + const client = getClient() + try { + await client.health() + logger.info("metaclaw-memory: context-engine bootstrap ok (sidecar healthy)") + } catch (err) { + const msg = err instanceof Error ? err.message : String(err) + logger.error(`metaclaw-memory: context-engine bootstrap failed: ${msg}`) + throw new Error(`metaclaw-memory context-engine bootstrap failed: ${msg}`) + } + }, + + async ingest(_messages: Array>): Promise { + // No-op: turn ingestion is handled by auto-capture hook + sidecar scheduler. + }, + + async ingestBatch(_messages: Array>>): Promise { + // No-op: same as ingest — sidecar scheduler handles batching. + }, + + async afterTurn(_result: Record): Promise { + // No-op: consolidation handled by sidecar scheduler. + }, + + async assemble(query: AssembleQuery): Promise { + const prompt = extractUserPrompt(query.messages) + if (!prompt) { + return { messages: query.messages, estimatedTokens: 0 } + } + try { + const result = await getClient().retrieve(prompt, cfg.scope) + if (result.unit_count > 0 && result.rendered_prompt) { + return { + messages: query.messages, + estimatedTokens: Math.ceil(result.rendered_prompt.length / 4), + systemPromptAddition: result.rendered_prompt, + } + } + return { messages: query.messages, estimatedTokens: 0 } + } catch (err) { + const msg = err instanceof Error ? err.message : String(err) + logger.warn(`metaclaw-memory: assemble retrieve failed: ${msg}`) + return { messages: query.messages, estimatedTokens: 0 } + } + }, + + async compact(_sessionId: string): Promise { + try { + await getClient().consolidate(cfg.scope) + return { ok: true, compacted: true } + } catch (err) { + const msg = err instanceof Error ? err.message : String(err) + logger.warn(`metaclaw-memory: compact consolidate failed: ${msg}`) + return { ok: false, compacted: false, reason: msg } + } + }, + + async dispose(): Promise { + // No-op: sidecar lifecycle managed by SidecarManager via registerService. + }, + } +} diff --git a/openclaw-metaclaw-memory/src/index.ts b/openclaw-metaclaw-memory/src/index.ts index df01510..8743cf3 100644 --- a/openclaw-metaclaw-memory/src/index.ts +++ b/openclaw-metaclaw-memory/src/index.ts @@ -9,6 +9,7 @@ import { registerMemoryForgetTool } from "./tools/memory-forget.js" import { registerMemoryStatusTool } from "./tools/memory-status.js" import { registerCli } from "./commands/cli.js" import { registerSlashCommands } from "./commands/slash.js" +import { createMetaClawContextEngine } from "./context-engine.js" import { configSchema } from "./config-schema.js" @@ -17,7 +18,7 @@ export default { name: "MetaClaw Memory", description: "Self-evolving local-first memory with hybrid retrieval, 6 structured types, and adaptive policy — no cloud required.", - kind: "memory" as const, + kind: ["memory", "context-engine"] as const, configSchema, register(api: any) { @@ -52,8 +53,26 @@ export default { return client } - // Hooks - registerAutoRecall(api, getClient, cfg) + // ContextEngine registration (OpenClaw v2026.4.10+) + // If context-engine API is available, register and skip auto-recall + // to prevent double-injection (assemble + prependContext both injecting memories). + let contextEngineActive = false + try { + if (typeof api.registerContextEngine === "function") { + api.registerContextEngine("metaclaw-memory", () => + createMetaClawContextEngine(getClient, cfg, api.logger), + ) + contextEngineActive = true + api.logger.info("metaclaw-memory: context-engine registered (assemble/compact lifecycle)") + } + } catch { + api.logger.info("metaclaw-memory: context-engine registration skipped (API not available)") + } + + // Hooks — skip auto-recall if context-engine handles memory injection + if (!contextEngineActive) { + registerAutoRecall(api, getClient, cfg) + } registerAutoCapture(api, getClient, cfg) // AI tools diff --git a/openclaw-metaclaw-memory/vitest.config.ts b/openclaw-metaclaw-memory/vitest.config.ts new file mode 100644 index 0000000..8696084 --- /dev/null +++ b/openclaw-metaclaw-memory/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["src/__tests__/**/*.test.ts"], + }, +}); From f4d5a6c981abda184ff23a750611d2a637eb345f Mon Sep 17 00:00:00 2001 From: OpenCode Date: Sun, 19 Apr 2026 15:52:13 +0700 Subject: [PATCH 4/5] Add OpenClaw compatibility test suite Cover config defaults, ConfigStore mapping (explicit/defaults/string 'false'), describe() output, claw adapter active memory suppression toggle, API server dispatcher boolean conditions, and setup wizard advanced section with override propagation. --- tests/test_openclaw_compat.py | 333 ++++++++++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 tests/test_openclaw_compat.py diff --git a/tests/test_openclaw_compat.py b/tests/test_openclaw_compat.py new file mode 100644 index 0000000..0d1fdae --- /dev/null +++ b/tests/test_openclaw_compat.py @@ -0,0 +1,333 @@ +from __future__ import annotations + +from pathlib import Path +from types import SimpleNamespace + +from metaclaw.config import MetaClawConfig +from metaclaw.config_store import ConfigStore, _DEFAULTS +from metaclaw.setup_wizard import SetupWizard + + +# ---------------------------------------------------------------- # +# 1. Config dataclass defaults # +# ---------------------------------------------------------------- # + +def test_config_openclaw_defaults(): + cfg = MetaClawConfig() + assert cfg.openclaw_context_engine_enabled is True + assert cfg.openclaw_active_memory_compat is True + assert cfg.openclaw_prefer_proxy_synergy is False + assert cfg.openclaw_min_version == "2026.4.10" + + +# ---------------------------------------------------------------- # +# 2. ConfigStore _DEFAULTS # +# ---------------------------------------------------------------- # + +def test_config_store_openclaw_defaults(tmp_path: Path): + store = ConfigStore(config_file=tmp_path / "config.yaml") + assert "openclaw_compat" in _DEFAULTS + oc = _DEFAULTS["openclaw_compat"] + assert oc["context_engine_enabled"] is True + assert oc["active_memory_compat"] is True + assert oc["prefer_proxy_synergy"] is False + assert oc["min_version"] == "2026.4.10" + + # And that load() merges these defaults into a fresh store + loaded = store.load() + assert loaded["openclaw_compat"]["context_engine_enabled"] is True + assert loaded["openclaw_compat"]["active_memory_compat"] is True + assert loaded["openclaw_compat"]["prefer_proxy_synergy"] is False + assert loaded["openclaw_compat"]["min_version"] == "2026.4.10" + + +# ---------------------------------------------------------------- # +# 3. ConfigStore mapping → MetaClawConfig # +# ---------------------------------------------------------------- # + +def test_config_store_openclaw_mapping_explicit(tmp_path: Path): + store = ConfigStore(config_file=tmp_path / "config.yaml") + store.save({ + "mode": "skills_only", + "openclaw_compat": { + "context_engine_enabled": False, + "active_memory_compat": False, + "prefer_proxy_synergy": True, + "min_version": "2026.5.1", + }, + }) + + cfg = store.to_metaclaw_config() + assert cfg.openclaw_context_engine_enabled is False + assert cfg.openclaw_active_memory_compat is False + assert cfg.openclaw_prefer_proxy_synergy is True + assert cfg.openclaw_min_version == "2026.5.1" + + +def test_config_store_openclaw_mapping_defaults_when_missing(tmp_path: Path): + store = ConfigStore(config_file=tmp_path / "config.yaml") + # Save without an openclaw_compat section + store.save({"mode": "skills_only"}) + + cfg = store.to_metaclaw_config() + # Defaults from _DEFAULTS get merged + assert cfg.openclaw_context_engine_enabled is True + assert cfg.openclaw_active_memory_compat is True + assert cfg.openclaw_prefer_proxy_synergy is False + assert cfg.openclaw_min_version == "2026.4.10" + + +def test_config_store_openclaw_mapping_string_false(tmp_path: Path): + """Verify string 'false' is parsed correctly (avoid bool('false') == True trap).""" + store = ConfigStore(config_file=tmp_path / "config.yaml") + store.save({ + "mode": "skills_only", + "openclaw_compat": { + "context_engine_enabled": "false", + "active_memory_compat": "false", + "prefer_proxy_synergy": "true", + "min_version": "2026.4.20", + }, + }) + + cfg = store.to_metaclaw_config() + assert cfg.openclaw_context_engine_enabled is False + assert cfg.openclaw_active_memory_compat is False + assert cfg.openclaw_prefer_proxy_synergy is True + assert cfg.openclaw_min_version == "2026.4.20" + + +# ---------------------------------------------------------------- # +# 4. ConfigStore describe() # +# ---------------------------------------------------------------- # + +def test_config_store_describe_openclaw(tmp_path: Path): + store = ConfigStore(config_file=tmp_path / "config.yaml") + store.save({ + "mode": "skills_only", + "openclaw_compat": { + "context_engine_enabled": True, + "active_memory_compat": False, + "prefer_proxy_synergy": True, + "min_version": "2026.4.10", + }, + }) + + out = store.describe() + assert "openclaw.context_engine" in out + assert "openclaw.active_memory" in out + assert "openclaw.proxy_synergy" in out + assert "openclaw.min_version" in out + + +def test_config_store_describe_includes_openclaw_via_defaults(tmp_path: Path): + """Describe() includes openclaw block when defaults present (load() merges defaults).""" + store = ConfigStore(config_file=tmp_path / "config.yaml") + store.save({"mode": "skills_only"}) + out = store.describe() + # Defaults are merged on load(), so the openclaw block IS present + assert "openclaw.context_engine" in out + assert "openclaw.min_version" in out + + +# ---------------------------------------------------------------- # +# 5 & 6. Claw adapter — Active Memory suppression toggle # +# ---------------------------------------------------------------- # + +def test_configure_openclaw_active_memory_suppression(monkeypatch): + calls = [] + + def fake_run(cmd, **kwargs): + calls.append(cmd) + return SimpleNamespace(returncode=0, stdout="", stderr="") + + monkeypatch.setattr("metaclaw.claw_adapter.subprocess.run", fake_run) + + from metaclaw.claw_adapter import _configure_openclaw + cfg = MetaClawConfig( + api_key="proxy-key", + llm_model_id="test-model", + proxy_port=30000, + openclaw_active_memory_compat=True, + ) + cfg.proxy_api_key = "proxy-key" # claw_adapter accesses this attribute directly + _configure_openclaw(cfg) + + slot_cmds = [c for c in calls if "plugins.slots.memory" in c] + assert len(slot_cmds) == 1 + assert slot_cmds[0][-1] == "metaclaw-memory" + + # Gateway restart must be the LAST command + assert calls[-1] == ["openclaw", "gateway", "restart"] + + +def test_configure_openclaw_skips_active_memory_suppression(monkeypatch): + calls = [] + + def fake_run(cmd, **kwargs): + calls.append(cmd) + return SimpleNamespace(returncode=0, stdout="", stderr="") + + monkeypatch.setattr("metaclaw.claw_adapter.subprocess.run", fake_run) + + from metaclaw.claw_adapter import _configure_openclaw + cfg = MetaClawConfig( + api_key="proxy-key", + llm_model_id="test-model", + proxy_port=30000, + openclaw_active_memory_compat=False, + ) + cfg.proxy_api_key = "proxy-key" # claw_adapter accesses this attribute directly + _configure_openclaw(cfg) + + slot_cmds = [c for c in calls if "plugins.slots.memory" in c] + assert len(slot_cmds) == 0 + # Gateway restart still runs last + assert calls[-1] == ["openclaw", "gateway", "restart"] + + +# ---------------------------------------------------------------- # +# 7. API server dispatcher boolean conditions # +# ---------------------------------------------------------------- # + +def test_api_server_dispatcher_conditions(): + """Verify the boolean conditions driving the context-engine dispatcher + in api_server.py:1258-1269.""" + # Case 1: context-engine active, default config → skills-only path + cfg = MetaClawConfig( + openclaw_context_engine_enabled=True, + openclaw_prefer_proxy_synergy=False, + ) + context_engine_active = True + has_skill_manager = True + has_memory_manager = True + + # Outer guard true → enter context-engine block + assert context_engine_active and cfg.openclaw_context_engine_enabled + # Synergy escape hatch NOT taken (prefer_proxy_synergy is False) + assert not (cfg.openclaw_prefer_proxy_synergy and has_memory_manager and has_skill_manager) + # Falls through to skills-only path + assert has_skill_manager + + # Case 2: prefer_proxy_synergy=True with memory + skills + synergy_enabled + cfg2 = MetaClawConfig( + openclaw_context_engine_enabled=True, + openclaw_prefer_proxy_synergy=True, + ) + assert cfg2.openclaw_prefer_proxy_synergy and has_memory_manager and has_skill_manager + + # Case 3: context-engine disabled in config → fall through to original logic + cfg3 = MetaClawConfig(openclaw_context_engine_enabled=False) + assert not (context_engine_active and cfg3.openclaw_context_engine_enabled) + + # Case 4: header not set → context_engine_active False → fall through + assert not (False and cfg.openclaw_context_engine_enabled) + + +# ---------------------------------------------------------------- # +# 8. Setup wizard — OpenClaw advanced section # +# ---------------------------------------------------------------- # + +def _wizard_skills_only_prompts(skills_dir: Path, oc_advanced: bool, oc_overrides: dict | None = None): + """Build prompt fakers for a skills_only wizard run, with optional oc overrides.""" + overrides = oc_overrides or {} + + def fake_prompt_choice(msg, choices, default=""): + if msg == "Operating mode": + return "skills_only" + if msg == "Auth method": + return "api_key" + if msg == "Provider": + return "custom" + if msg == "LLM provider": + return "custom" + raise AssertionError(f"Unexpected choice prompt: {msg}") + + def fake_prompt(msg, default="", hide=False): + if msg == "API base URL": + return "https://api.example/v1" + if msg == "Model ID": + return "test-model" + if msg == "API key": + return "test-key" + if msg == "Skills directory": + return str(skills_dir) + if msg == "Minimum OpenClaw version": + return overrides.get("min_version", "2026.4.15") + raise AssertionError(f"Unexpected text prompt: {msg}") + + def fake_prompt_bool(msg, default=False): + if msg == "Enable skill injection": + return True + if msg == "Auto-summarize skills after each conversation": + return True + if msg == "Configure OpenClaw compatibility settings (advanced)": + return oc_advanced + if msg == "Enable context-engine integration (memory via assemble/compact lifecycle)": + return overrides.get("context_engine_enabled", True) + if msg == "Suppress OpenClaw built-in Active Memory": + return overrides.get("active_memory_compat", False) + if msg == "Force proxy-side synergy (memory+skills) even with context-engine active": + return overrides.get("prefer_proxy_synergy", True) + raise AssertionError(f"Unexpected bool prompt: {msg}") + + def fake_prompt_int(msg, default=0): + if msg == "Proxy port": + return 30000 + raise AssertionError(f"Unexpected int prompt: {msg}") + + return fake_prompt_choice, fake_prompt, fake_prompt_bool, fake_prompt_int + + +def test_setup_wizard_openclaw_advanced_section(monkeypatch, tmp_path: Path): + config_path = tmp_path / "config.yaml" + skills_dir = tmp_path / "skills" + store = ConfigStore(config_file=config_path) + + pc, p, pb, pi = _wizard_skills_only_prompts( + skills_dir, + oc_advanced=True, + oc_overrides={ + "context_engine_enabled": True, + "active_memory_compat": False, + "prefer_proxy_synergy": True, + "min_version": "2026.4.15", + }, + ) + + monkeypatch.setattr("metaclaw.setup_wizard.ConfigStore", lambda: store) + monkeypatch.setattr("metaclaw.setup_wizard._prompt_choice", pc) + monkeypatch.setattr("metaclaw.setup_wizard._prompt", p) + monkeypatch.setattr("metaclaw.setup_wizard._prompt_bool", pb) + monkeypatch.setattr("metaclaw.setup_wizard._prompt_int", pi) + + SetupWizard().run() + + saved = store.load() + assert saved["openclaw_compat"]["context_engine_enabled"] is True + assert saved["openclaw_compat"]["active_memory_compat"] is False + assert saved["openclaw_compat"]["prefer_proxy_synergy"] is True + assert saved["openclaw_compat"]["min_version"] == "2026.4.15" + + +def test_setup_wizard_openclaw_skipped_uses_defaults(monkeypatch, tmp_path: Path): + config_path = tmp_path / "config.yaml" + skills_dir = tmp_path / "skills" + store = ConfigStore(config_file=config_path) + + pc, p, pb, pi = _wizard_skills_only_prompts(skills_dir, oc_advanced=False) + + monkeypatch.setattr("metaclaw.setup_wizard.ConfigStore", lambda: store) + monkeypatch.setattr("metaclaw.setup_wizard._prompt_choice", pc) + monkeypatch.setattr("metaclaw.setup_wizard._prompt", p) + monkeypatch.setattr("metaclaw.setup_wizard._prompt_bool", pb) + monkeypatch.setattr("metaclaw.setup_wizard._prompt_int", pi) + + SetupWizard().run() + + saved = store.load() + # When user declines advanced section, defaults must be persisted + assert saved["openclaw_compat"]["context_engine_enabled"] is True + assert saved["openclaw_compat"]["active_memory_compat"] is True + assert saved["openclaw_compat"]["prefer_proxy_synergy"] is False + assert saved["openclaw_compat"]["min_version"] == "2026.4.10" From 87781af63cf9083ac89b63d1106fa65cdb5a47d7 Mon Sep 17 00:00:00 2001 From: OpenCode Date: Sun, 19 Apr 2026 15:56:57 +0700 Subject: [PATCH 5/5] Bump version to v0.4.2: OpenClaw context-engine integration --- README.md | 1 + assets/README_AR.md | 1 + assets/README_DE.md | 1 + assets/README_ES.md | 1 + assets/README_FR.md | 1 + assets/README_HI.md | 1 + assets/README_IT.md | 1 + assets/README_JA.md | 1 + assets/README_KO.md | 1 + assets/README_PT.md | 1 + assets/README_RU.md | 1 + assets/README_VI.md | 1 + assets/README_ZH.md | 1 + pyproject.toml | 2 +- 14 files changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 91e3f25..cbf9496 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ metaclaw start --mode skills_only # skills only, no RL (no Tinker needed) ## 🔥 News +- **[04/19/2026]** **v0.4.2** — OpenClaw context-engine integration: memory plugin registers as a context-engine (assemble/compact lifecycle) on OpenClaw v2026.4.10+, eliminating double-injection of memories. Adds incremental per-turn capture with session-end final flush, OpenClaw compatibility config section, and active memory suppression for seamless proxy-side skill injection. - **[04/11/2026]** **v0.4.1** — Incremental memory ingestion: the memory layer now extracts and persists turns every N turns (default 5) instead of only at session end, shrinking the mid-session memory blackout window. - **[03/25/2026]** **v0.4.0** — Contexture layer: MetaClaw now persists cross-session memory for users and projects. Relevant facts, preferences, and project history are automatically retrieved and injected into prompts. Includes adaptive memory policy, background consolidation, and an optional memory sidecar service. - **[03/24/2026]** **v0.3.3** — One-click OpenClaw plugin: MetaClaw now ships as a native OpenClaw extension — drop the folder into OpenClaw's extensions, run one command, and everything is set up automatically. diff --git a/assets/README_AR.md b/assets/README_AR.md index 380a8b7..36e98fa 100644 --- a/assets/README_AR.md +++ b/assets/README_AR.md @@ -51,6 +51,7 @@ metaclaw start --mode skills_only # مهارات فقط، بدون RL (لا ح ## 🔥 آخر الأخبار +- **[2026/04/19]** **v0.4.2** — تكامل محرك سياق OpenClaw: تسجيل البرنامج المساعد للذاكرة كمحرك سياق (دورة assemble/compact) على OpenClaw v2026.4.10+، مما يزيل حقن الذاكرة المزدوج. إضافة التقاط تزايدي لكل دور مع تدفق نهائي، قسم إعدادات توافق OpenClaw، وقمع الذاكرة النشطة لحقن المهارات من جانب البروكسي. - **[2026/04/11]** **v0.4.1** — استيعاب الذاكرة التدريجي: طبقة الذاكرة تستخرج الآن وتحتفظ بالأدوار كل N أدوار (5 افتراضيًا) بدلًا من نهاية الجلسة فقط، مما يقلل فجوة الذاكرة في منتصف الجلسة. يضيف نقطتي نهاية sidecar جديدتين `/buffer_turn` و`/flush_session`، وأداة قياس أداء مع علامة `--buffer-turns`، وتقارير مقارنة التجارب. - **[2026/03/25]** **v0.4.0** — طبقة السياق (Contexture layer): يحتفظ MetaClaw الآن بالذاكرة عبر الجلسات للمستخدمين والمشاريع. يتم استرجاع الحقائق والتفضيلات وتاريخ المشروع ذات الصلة تلقائيًا وحقنها في المطالبات. يشمل سياسة ذاكرة تكيفية وتوحيدًا في الخلفية وخدمة sidecar اختيارية للذاكرة. - **[2026/03/16]** **v0.3.2** دعم متعدد الـ Claw: أصبح IronClaw وPicoClaw وZeroClaw وCoPaw وNanoClaw وNemoClaw مدعومين إلى جانب OpenClaw. NanoClaw عبر نقطة النهاية الجديدة المتوافقة مع Anthropic `/v1/messages`؛ NemoClaw عبر توجيه الاستدلال OpenShell. إضافة OpenRouter كمنصة LLM مدعومة. diff --git a/assets/README_DE.md b/assets/README_DE.md index 64d65f1..ce4c8ff 100644 --- a/assets/README_DE.md +++ b/assets/README_DE.md @@ -51,6 +51,7 @@ metaclaw start --mode skills_only # Nur Skills, kein RL (kein Tinker nötig) ## 🔥 Neuigkeiten +- **[19.04.2026]** **v0.4.2** — OpenClaw Context-Engine-Integration: Das Memory-Plugin registriert sich als Context-Engine (Assemble/Compact-Lebenszyklus) auf OpenClaw v2026.4.10+ und eliminiert doppelte Memory-Injektion. Ergänzt inkrementelle pro-Turn-Erfassung mit Final-Flush, OpenClaw-Kompatibilitäts-Konfiguration und Active-Memory-Unterdrückung für nahtlose proxyseitige Skill-Injektion. - **[11.04.2026]** **v0.4.1** — Inkrementelle Speichererfassung: die Speicherschicht extrahiert und speichert jetzt alle N Turns (Standard 5) statt nur am Sitzungsende, wodurch der Speicher-Blackout mitten in einer Sitzung verkürzt wird. Fügt neue `/buffer_turn`- und `/flush_session`-Sidecar-Endpunkte, ein Benchmark-Harness mit `--buffer-turns`-Flag und Experiment-Vergleichsberichte hinzu. - **[25.03.2026]** **v0.4.0** — Contexture layer: MetaClaw speichert nun sitzungsübergreifend Erinnerungen für Nutzer und Projekte. Relevante Fakten, Präferenzen und Projektverlauf werden automatisch abgerufen und in Prompts injiziert. Enthält adaptive Speicherrichtlinie, Hintergrundkonsolidierung und einen optionalen Memory-Sidecar-Dienst. - **[16.03.2026]** **v0.3.2** Multi-Claw-Unterstützung: IronClaw, PicoClaw, ZeroClaw, CoPaw, NanoClaw und NemoClaw werden neben OpenClaw unterstützt. NanoClaw über den neuen `/v1/messages` Anthropic-kompatiblen Endpunkt; NemoClaw über OpenShell-Inferenz-Routing. OpenRouter als LLM-Plattform hinzugefügt. diff --git a/assets/README_ES.md b/assets/README_ES.md index 579b343..cd9b24e 100644 --- a/assets/README_ES.md +++ b/assets/README_ES.md @@ -51,6 +51,7 @@ metaclaw start --mode skills_only # solo skills, sin RL (no requiere Tinker) ## 🔥 Noticias +- **[19/04/2026]** **v0.4.2** — Integración context-engine OpenClaw: el plugin de memoria se registra como context-engine (ciclo assemble/compact) en OpenClaw v2026.4.10+, eliminando la doble inyección de memorias. Añade captura incremental por turno con volcado final, sección de configuración de compatibilidad OpenClaw y supresión de memoria activa para inyección de skills del lado del proxy. - **[11/04/2026]** **v0.4.1** — Ingesta incremental de memoria: la capa de memoria ahora extrae y persiste turnos cada N turnos (5 por defecto) en lugar de solo al final de la sesión, reduciendo el hueco de memoria a mitad de sesión. Añade los nuevos endpoints sidecar `/buffer_turn` y `/flush_session`, un harness de benchmark con la opción `--buffer-turns` e informes comparativos de experimentos. - **[25/03/2026]** **v0.4.0** — Contexture layer: MetaClaw ahora persiste la memoria entre sesiones para usuarios y proyectos. Los hechos relevantes, preferencias e historial del proyecto se recuperan automáticamente y se inyectan en los prompts. Incluye política de memoria adaptativa, consolidación en segundo plano y un servicio sidecar de memoria opcional. - **[16/03/2026]** **v0.3.2** Soporte multi-Claw: IronClaw, PicoClaw, ZeroClaw, CoPaw, NanoClaw y NemoClaw ahora son compatibles junto con OpenClaw. NanoClaw a través del nuevo endpoint compatible con Anthropic `/v1/messages`; NemoClaw a través del enrutamiento de inferencia OpenShell. OpenRouter agregado como plataforma LLM. diff --git a/assets/README_FR.md b/assets/README_FR.md index 7a678d5..56057de 100644 --- a/assets/README_FR.md +++ b/assets/README_FR.md @@ -51,6 +51,7 @@ metaclaw start --mode skills_only # skills uniquement, pas de RL (Tinker non re ## 🔥 Actualites +- **[19/04/2026]** **v0.4.2** — Integration context-engine OpenClaw : le plugin memoire s'enregistre comme context-engine (cycle assemble/compact) sur OpenClaw v2026.4.10+, eliminant la double injection de memoires. Ajout capture incrementale par tour avec vidage final, section config compatibilite OpenClaw et suppression memoire active pour injection de skills transparente cote proxy. - **[11/04/2026]** **v0.4.1** — Ingestion memoire incrementale : la couche memoire extrait et persiste desormais les tours tous les N tours (5 par defaut) au lieu d'attendre la fin de la session, reduisant le blackout memoire en cours de session. Ajoute les nouveaux endpoints sidecar `/buffer_turn` et `/flush_session`, un harnais de benchmark avec l'option `--buffer-turns` et des rapports de comparaison d'experiences. - **[25/03/2026]** **v0.4.0** — Contexture layer : MetaClaw persiste desormais la memoire inter-sessions pour les utilisateurs et les projets. Les faits pertinents, preferences et historiques de projet sont automatiquement recuperes et injectes dans les prompts. Inclut une politique de memoire adaptative, une consolidation en arriere-plan et un service sidecar memoire optionnel. - **[16/03/2026]** **v0.3.2** Support multi-Claw : IronClaw, PicoClaw, ZeroClaw, CoPaw, NanoClaw et NemoClaw sont desormais supportes aux cotes d'OpenClaw. NanoClaw via le nouvel endpoint compatible Anthropic `/v1/messages` ; NemoClaw via le routage d'inference OpenShell. OpenRouter ajoute comme plateforme LLM. diff --git a/assets/README_HI.md b/assets/README_HI.md index 55d2c47..adeffa0 100644 --- a/assets/README_HI.md +++ b/assets/README_HI.md @@ -51,6 +51,7 @@ metaclaw start --mode skills_only # केवल Skills, कोई RL नही ## 🔥 ताज़ा अपडेट +- **[2026/04/19]** **v0.4.2** — OpenClaw context-engine एकीकरण: मेमोरी प्लगइन OpenClaw v2026.4.10+ पर context-engine (assemble/compact लाइफसाइकल) के रूप में पंजीकृत होता है, जिससे मेमोरी का डबल इंजेक्शन समाप्त होता है। प्रति-टर्न इंक्रीमेंटल कैप्चर, सेशन-एंड फाइनल फ्लश, OpenClaw कम्पैटिबिलिटी कॉन्फिग सेक्शन और सीमलेस प्रॉक्सी-साइड स्किल इंजेक्शन के लिए एक्टिव मेमोरी सप्रेशन जोड़ा गया। - **[2026/04/11]** **v0.4.1** — इंक्रीमेंटल मेमोरी इन्जेशन: मेमोरी लेयर अब केवल सत्र के अंत में नहीं बल्कि हर N टर्न (डिफ़ॉल्ट 5) पर एक्सट्रैक्ट और पर्सिस्ट करती है, जिससे सत्र के बीच मेमोरी ब्लैकआउट कम होता है। नए `/buffer_turn` और `/flush_session` sidecar एंडपॉइंट्स, `--buffer-turns` फ़्लैग के साथ बेंचमार्क हार्नेस और प्रयोग तुलना रिपोर्ट जोड़े गए। - **[2026/03/25]** **v0.4.0** — Contexture layer(संदर्भ परत): MetaClaw अब उपयोगकर्ताओं और प्रोजेक्ट्स के लिए सत्रों के पार मेमोरी को बनाए रखता है। प्रासंगिक तथ्य, प्राथमिकताएं और प्रोजेक्ट इतिहास स्वचालित रूप से पुनर्प्राप्त होकर प्रॉम्प्ट में इंजेक्ट किए जाते हैं। इसमें अनुकूली मेमोरी नीति, बैकग्राउंड एकत्रीकरण और वैकल्पिक मेमोरी साइडकार सेवा शामिल है। - **[2026/03/16]** **v0.3.2** मल्टी-Claw सपोर्ट: IronClaw, PicoClaw, ZeroClaw, CoPaw, NanoClaw और NemoClaw अब OpenClaw के साथ सपोर्टेड हैं। NanoClaw नए `/v1/messages` Anthropic-संगत एंडपॉइंट के माध्यम से; NemoClaw OpenShell इनफरेंस रूटिंग के माध्यम से। OpenRouter को LLM प्लेटफ़ॉर्म के रूप में जोड़ा गया। diff --git a/assets/README_IT.md b/assets/README_IT.md index 05a09fb..d67747f 100644 --- a/assets/README_IT.md +++ b/assets/README_IT.md @@ -51,6 +51,7 @@ metaclaw start --mode skills_only # solo Skill, nessun RL (Tinker non necessari ## 🔥 Novita +- **[19/04/2026]** **v0.4.2** — Integrazione context-engine OpenClaw: il plugin di memoria si registra come context-engine (ciclo assemble/compact) su OpenClaw v2026.4.10+, eliminando la doppia iniezione di memorie. Aggiunge cattura incrementale per turno con flush finale, sezione configurazione compatibilità OpenClaw e soppressione memoria attiva per iniezione di skill lato proxy. - **[11/04/2026]** **v0.4.1** — Ingestione memoria incrementale: il livello di memoria ora estrae e persiste i turni ogni N turni (default 5) invece di attendere la fine della sessione, riducendo il blackout di memoria a metà sessione. Aggiunge i nuovi endpoint sidecar `/buffer_turn` e `/flush_session`, un harness di benchmark con il flag `--buffer-turns` e report di confronto esperimenti. - **[25/03/2026]** **v0.4.0** — Contexture layer: MetaClaw ora persiste la memoria tra le sessioni per utenti e progetti. Fatti rilevanti, preferenze e cronologia del progetto vengono recuperati automaticamente e iniettati nei prompt. Include una politica di memoria adattiva, consolidamento in background e un servizio sidecar per la memoria opzionale. - **[16/03/2026]** **v0.3.2** Supporto multi-Claw: IronClaw, PicoClaw, ZeroClaw, CoPaw, NanoClaw e NemoClaw ora supportati insieme a OpenClaw. NanoClaw tramite il nuovo endpoint compatibile Anthropic `/v1/messages`; NemoClaw tramite routing di inferenza OpenShell. OpenRouter aggiunto come piattaforma LLM. diff --git a/assets/README_JA.md b/assets/README_JA.md index f82d03b..a6ce071 100644 --- a/assets/README_JA.md +++ b/assets/README_JA.md @@ -51,6 +51,7 @@ metaclaw start --mode skills_only # スキルのみ、RL なし(Tinker 不要 ## 🔥 ニュース +- **[2026/04/19]** **v0.4.2** — OpenClaw コンテキストエンジン統合:メモリプラグインが OpenClaw v2026.4.10+ のコンテキストエンジン(assemble/compact ライフサイクル)として登録され、メモリの二重注入を排除。ターンごとの増分キャプチャとセッション終了時のフラッシュ、OpenClaw 互換性設定セクション、シームレスなプロキシ側スキル注入のためのアクティブメモリ抑制を追加。 - **[2026/04/11]** **v0.4.1** — インクリメンタル・メモリ取り込み:メモリ層がセッション終了時だけでなく N ターン(デフォルト 5)ごとに抽出・永続化するようになり、セッション途中のメモリ空白期間が短縮。新しい `/buffer_turn`・`/flush_session` サイドカーエンドポイント、`--buffer-turns` フラグ付きベンチマーク、実験比較レポートを追加。 - **[2026/03/25]** **v0.4.0** — Contexture layer(コンテキスチュア レイヤー):MetaClaw がユーザーとプロジェクトのメモリをセッションをまたいで永続化。関連する事実・好み・プロジェクト履歴を自動取得してプロンプトに注入。適応型メモリポリシー、バックグラウンド統合、オプションのメモリサイドカーサービスを含む。 - **[2026/03/16]** **v0.3.2** マルチ Claw サポート:IronClaw・PicoClaw・ZeroClaw・CoPaw・NanoClaw・NemoClaw が OpenClaw に加えて利用可能に。NanoClaw は新規 `/v1/messages` Anthropic 互換エンドポイント経由で、NemoClaw は OpenShell 推論ルーティング経由で接続。OpenRouter を LLM プラットフォームとして追加。 diff --git a/assets/README_KO.md b/assets/README_KO.md index f74cc4e..8e908ea 100644 --- a/assets/README_KO.md +++ b/assets/README_KO.md @@ -51,6 +51,7 @@ metaclaw start --mode skills_only # 스킬만, RL 없음 (Tinker 불필요) ## 🔥 새소식 +- **[2026/04/19]** **v0.4.2** — OpenClaw 컨텍스트 엔진 통합: 메모리 플러그인이 OpenClaw v2026.4.10+의 컨텍스트 엔진(assemble/compact 라이프사이클)으로 등록되어 메모리 이중 주입을 제거. 턴별 증분 캡처와 세션 종료 플러시, OpenClaw 호환성 설정 섹션, 프록시 측 스킬 주입을 위한 활성 메모리 억제 추가. - **[2026/04/11]** **v0.4.1** — 증분 메모리 수집: 메모리 레이어가 세션 종료 시점뿐 아니라 N 턴(기본 5)마다 추출하고 저장하도록 변경되어 세션 중간의 메모리 공백 구간이 줄어듦. 새로운 `/buffer_turn`·`/flush_session` 사이드카 엔드포인트, `--buffer-turns` 플래그를 지원하는 벤치마크, 실험 비교 리포트 추가. - **[2026/03/25]** **v0.4.0** — Contexture layer(컨텍스처 레이어):MetaClaw가 사용자와 프로젝트의 메모리를 세션을 넘어 지속적으로 저장. 관련 사실, 선호도, 프로젝트 히스토리를 자동으로 검색해 프롬프트에 주입. 적응형 메모리 정책, 백그라운드 통합, 선택적 메모리 사이드카 서비스 포함. - **[2026/03/16]** **v0.3.2** 멀티 Claw 지원: IronClaw, PicoClaw, ZeroClaw, CoPaw, NanoClaw, NemoClaw가 OpenClaw와 함께 지원됨. NanoClaw는 새로운 `/v1/messages` Anthropic 호환 엔드포인트를 통해, NemoClaw는 OpenShell 추론 라우팅을 통해 연결. OpenRouter를 LLM 플랫폼으로 추가. diff --git a/assets/README_PT.md b/assets/README_PT.md index a3cb1f1..49b755e 100644 --- a/assets/README_PT.md +++ b/assets/README_PT.md @@ -51,6 +51,7 @@ metaclaw start --mode skills_only # apenas Skills, sem RL (sem necessidade de T ## 🔥 Novidades +- **[19/04/2026]** **v0.4.2** — Integracao context-engine OpenClaw: o plugin de memoria registra-se como context-engine (ciclo assemble/compact) no OpenClaw v2026.4.10+, eliminando a dupla injeção de memorias. Adiciona captura incremental por turno com flush final, secao de configuracao de compatibilidade OpenClaw e supressao de memoria ativa para injeção de skills no lado do proxy. - **[11/04/2026]** **v0.4.1** — Ingestao incremental de memoria: a camada de memoria agora extrai e persiste turnos a cada N turnos (padrao 5) em vez de apenas no final da sessao, reduzindo o blackout de memoria no meio da sessao. Adiciona os novos endpoints sidecar `/buffer_turn` e `/flush_session`, um harness de benchmark com a flag `--buffer-turns` e relatorios comparativos de experimentos. - **[25/03/2026]** **v0.4.0** — Contexture layer: MetaClaw agora persiste a memoria entre sessoes para usuarios e projetos. Fatos relevantes, preferencias e historico do projeto sao recuperados automaticamente e injetados nos prompts. Inclui politica de memoria adaptativa, consolidacao em segundo plano e servico sidecar de memoria opcional. - **[16/03/2026]** **v0.3.2** Suporte multi-Claw: IronClaw, PicoClaw, ZeroClaw, CoPaw, NanoClaw e NemoClaw agora sao suportados junto ao OpenClaw. NanoClaw via novo endpoint compativel com Anthropic `/v1/messages`; NemoClaw via roteamento de inferencia OpenShell. OpenRouter adicionado como plataforma LLM. diff --git a/assets/README_RU.md b/assets/README_RU.md index f6ab3e3..e08cea8 100644 --- a/assets/README_RU.md +++ b/assets/README_RU.md @@ -51,6 +51,7 @@ metaclaw start --mode skills_only # только навыки, без RL (Tinke ## 🔥 Новости +- **[19.04.2026]** **v0.4.2** — Интеграция context-engine OpenClaw: плагин памяти регистрируется как context-engine (цикл assemble/compact) в OpenClaw v2026.4.10+, устраняя двойную инъекцию памяти. Добавлена инкрементальная обработка каждого хода с финальным сбросом, секция конфигурации совместимости OpenClaw и подавление активной памяти для прозрачной инъекции навыков на стороне прокси. - **[11.04.2026]** **v0.4.1** — Инкрементальная загрузка памяти: слой памяти теперь извлекает и сохраняет ходы каждые N ходов (по умолчанию 5), а не только в конце сессии, сокращая «слепую зону» памяти в середине сессии. Добавляет новые sidecar-эндпоинты `/buffer_turn` и `/flush_session`, бенчмарк с флагом `--buffer-turns` и отчёты сравнения экспериментов. - **[25.03.2026]** **v0.4.0** — Contexture layer: MetaClaw теперь сохраняет память между сессиями для пользователей и проектов. Релевантные факты, предпочтения и история проекта автоматически извлекаются и вставляются в промпты. Включает адаптивную политику памяти, фоновую консолидацию и опциональный сервис sidecar для памяти. - **[16.03.2026]** **v0.3.2** Поддержка нескольких Claw: IronClaw, PicoClaw, ZeroClaw, CoPaw, NanoClaw и NemoClaw теперь поддерживаются наряду с OpenClaw. NanoClaw через новый эндпоинт `/v1/messages`, совместимый с Anthropic; NemoClaw через маршрутизацию инференса OpenShell. Добавлен OpenRouter как поддерживаемая платформа LLM. diff --git a/assets/README_VI.md b/assets/README_VI.md index bdfbb7f..0a212df 100644 --- a/assets/README_VI.md +++ b/assets/README_VI.md @@ -51,6 +51,7 @@ metaclaw start --mode skills_only # chi Skills, khong RL (khong can Tinker) ## 🔥 Tin moi +- **[19/04/2026]** **v0.4.2** — Tich hop context-engine OpenClaw: plugin bo nho dang ky la context-engine (vong doi assemble/compact) tren OpenClaw v2026.4.10+, loai bo su trung lap bo nho. Them capture tang dan moi luot voi flush cuoi phien, phan cau hinh tuong thich OpenClaw va che active memory cho injection skill tai proxy. - **[11/04/2026]** **v0.4.1** — Nap bo nho tang dan: lop bo nho gio trich xuat va luu moi N luot (mac dinh 5) thay vi chi cuoi phien, giam thoi gian bo nho bi trong giua phien. Them cac endpoint sidecar moi `/buffer_turn` va `/flush_session`, benchmark voi co `--buffer-turns` va bao cao so sanh thuc nghiem. - **[25/03/2026]** **v0.4.0** — Contexture layer: MetaClaw gio day luu tru bo nho xuyen phien lam viec cho nguoi dung va du an. Cac su kien, so thich va lich su du an lien quan duoc tu dong truy xuat va them vao prompt. Bao gom chinh sach bo nho thich ung, hop nhat nen va dich vu sidecar bo nho tuy chon. - **[16/03/2026]** **v0.3.2** Ho tro da Claw: IronClaw, PicoClaw, ZeroClaw, CoPaw, NanoClaw va NemoClaw nay duoc ho tro cung voi OpenClaw. NanoClaw qua endpoint tuong thich Anthropic `/v1/messages` moi; NemoClaw qua dinh tuyen suy luan OpenShell. Them OpenRouter lam nen tang LLM. diff --git a/assets/README_ZH.md b/assets/README_ZH.md index abf208c..4913b21 100644 --- a/assets/README_ZH.md +++ b/assets/README_ZH.md @@ -51,6 +51,7 @@ metaclaw start --mode skills_only # 仅 Skills,无 RL(无需 Tinker) ## 🔥 最新动态 +- **[2026/04/19]** **v0.4.2** — OpenClaw 上下文引擎集成:内存插件在 OpenClaw v2026.4.10+ 上注册为上下文引擎(assemble/compact 生命周期),消除内存重复注入。新增逐轮增量捕获与会话结束刷新、OpenClaw 兼容性配置节,以及用于无缝代理端技能注入的活跃内存抑制。 - **[2026/04/11]** **v0.4.1** — 增量记忆摄取:记忆层现在每 N 轮(默认 5)抽取并持久化一次对话,而非只在会话结束时处理,缩小了会话中途的记忆空白期。新增 `/buffer_turn` 与 `/flush_session` sidecar 端点、带 `--buffer-turns` 参数的 benchmark 工具,以及实验对比报告。 - **[2026/03/25]** **v0.4.0** — Contexture layer(上下文层):MetaClaw 现可跨会话持久化用户和项目记忆。相关事实、偏好和项目历史自动检索并注入提示中。包含自适应记忆策略、后台整合及可选的记忆边车服务。 - **[2026/03/16]** **v0.3.2** 多 Claw 支持:现已支持 IronClaw、PicoClaw、ZeroClaw、CoPaw、NanoClaw 和 NemoClaw,与 OpenClaw 并列。NanoClaw 通过新增的 `/v1/messages` Anthropic 兼容端点接入;NemoClaw 通过 OpenShell 推理路由接入。新增 OpenRouter 作为受支持的 LLM 平台。 diff --git a/pyproject.toml b/pyproject.toml index 463c9bf..01d6f2b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "aiming-metaclaw" -version = "0.4.1" +version = "0.4.2" description = "OpenClaw skill injection and RL training — one-click deployment" requires-python = ">=3.10" dependencies = [