superlocalmemory 3.5.8 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ATTRIBUTION.md +24 -0
- package/CHANGELOG.md +35 -0
- package/README.md +142 -35
- package/package.json +1 -1
- package/pyproject.toml +2 -1
- package/src/superlocalmemory/__init__.py +1 -1
- package/src/superlocalmemory/cli/cache_cmd.py +198 -0
- package/src/superlocalmemory/cli/commands.py +80 -2
- package/src/superlocalmemory/cli/compress_cmd.py +179 -0
- package/src/superlocalmemory/cli/help_cmd.py +197 -0
- package/src/superlocalmemory/cli/main.py +122 -0
- package/src/superlocalmemory/cli/optimize_cmd.py +175 -0
- package/src/superlocalmemory/cli/optimize_constants.py +31 -0
- package/src/superlocalmemory/cli/proxy_cmd.py +95 -0
- package/src/superlocalmemory/core/config.py +5 -0
- package/src/superlocalmemory/core/engine.py +23 -0
- package/src/superlocalmemory/core/mcp_embedder_proxy.py +89 -0
- package/src/superlocalmemory/llm/backbone.py +10 -4
- package/src/superlocalmemory/mcp/server.py +34 -0
- package/src/superlocalmemory/mcp/tools_v3.py +6 -2
- package/src/superlocalmemory/optimize/NOTICE +11 -0
- package/src/superlocalmemory/optimize/__init__.py +0 -0
- package/src/superlocalmemory/optimize/adapters/__init__.py +68 -0
- package/src/superlocalmemory/optimize/adapters/_agent_registry.py +120 -0
- package/src/superlocalmemory/optimize/adapters/anthropic_adapter.py +115 -0
- package/src/superlocalmemory/optimize/adapters/openai_adapter.py +125 -0
- package/src/superlocalmemory/optimize/adapters/wrap.py +188 -0
- package/src/superlocalmemory/optimize/cache/__init__.py +31 -0
- package/src/superlocalmemory/optimize/cache/boundary_store.py +455 -0
- package/src/superlocalmemory/optimize/cache/centroid_store.py +158 -0
- package/src/superlocalmemory/optimize/cache/context_key.py +67 -0
- package/src/superlocalmemory/optimize/cache/exact.py +85 -0
- package/src/superlocalmemory/optimize/cache/invalidation.py +36 -0
- package/src/superlocalmemory/optimize/cache/key_builder.py +98 -0
- package/src/superlocalmemory/optimize/cache/manager.py +452 -0
- package/src/superlocalmemory/optimize/cache/semantic.py +568 -0
- package/src/superlocalmemory/optimize/cache/stampede.py +50 -0
- package/src/superlocalmemory/optimize/compress/__init__.py +17 -0
- package/src/superlocalmemory/optimize/compress/align.py +153 -0
- package/src/superlocalmemory/optimize/compress/ccr.py +157 -0
- package/src/superlocalmemory/optimize/compress/extractive_code.py +311 -0
- package/src/superlocalmemory/optimize/compress/extractive_json.py +72 -0
- package/src/superlocalmemory/optimize/compress/prose_llmlingua.py +77 -0
- package/src/superlocalmemory/optimize/compress/router.py +548 -0
- package/src/superlocalmemory/optimize/config/__init__.py +35 -0
- package/src/superlocalmemory/optimize/config/defaults.py +48 -0
- package/src/superlocalmemory/optimize/config/schema.py +255 -0
- package/src/superlocalmemory/optimize/config/store.py +209 -0
- package/src/superlocalmemory/optimize/metrics/__init__.py +8 -0
- package/src/superlocalmemory/optimize/metrics/counters.py +138 -0
- package/src/superlocalmemory/optimize/metrics/estimator.py +90 -0
- package/src/superlocalmemory/optimize/metrics/exporters.py +77 -0
- package/src/superlocalmemory/optimize/metrics/persistence.py +115 -0
- package/src/superlocalmemory/optimize/proxy/__init__.py +28 -0
- package/src/superlocalmemory/optimize/proxy/_helpers.py +257 -0
- package/src/superlocalmemory/optimize/proxy/anthropic_surface.py +171 -0
- package/src/superlocalmemory/optimize/proxy/gemini_surface.py +121 -0
- package/src/superlocalmemory/optimize/proxy/lifecycle.py +126 -0
- package/src/superlocalmemory/optimize/proxy/openai_surface.py +125 -0
- package/src/superlocalmemory/optimize/proxy/server.py +151 -0
- package/src/superlocalmemory/optimize/storage/__init__.py +0 -0
- package/src/superlocalmemory/optimize/storage/db.py +1016 -0
- package/src/superlocalmemory/optimize/storage/schema.py +184 -0
- package/src/superlocalmemory/server/routes/optimize.py +166 -0
- package/src/superlocalmemory/server/routes/v3_api.py +63 -1
- package/src/superlocalmemory/server/unified_daemon.py +105 -0
- package/src/superlocalmemory/ui/index.html +98 -0
- package/src/superlocalmemory/ui/js/ng-shell.js +2 -1
- package/src/superlocalmemory/ui/js/optimize.js +173 -0
- package/src/superlocalmemory.egg-info/PKG-INFO +2 -1
- package/src/superlocalmemory.egg-info/SOURCES.txt +51 -0
- package/src/superlocalmemory.egg-info/requires.txt +1 -0
|
@@ -64,6 +64,36 @@ def _cmd_escape_rotate_token(args: Namespace) -> None:
|
|
|
64
64
|
cmd_rotate_token(args)
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
# ---- SLM v3.6 Optimize dispatch functions (additive) ----
|
|
68
|
+
|
|
69
|
+
def _cmd_optimize(args: Namespace) -> None:
|
|
70
|
+
from superlocalmemory.cli.optimize_cmd import cmd_optimize
|
|
71
|
+
cmd_optimize(args)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _cmd_cache(args: Namespace) -> None:
|
|
75
|
+
from superlocalmemory.cli.cache_cmd import cmd_cache
|
|
76
|
+
cmd_cache(args)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _cmd_compress(args: Namespace) -> None:
|
|
80
|
+
from superlocalmemory.cli.compress_cmd import cmd_compress
|
|
81
|
+
cmd_compress(args)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _cmd_proxy(args: Namespace) -> None:
|
|
85
|
+
from superlocalmemory.cli.proxy_cmd import cmd_proxy
|
|
86
|
+
cmd_proxy(args)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _cmd_help_optimize(args: Namespace) -> None:
|
|
90
|
+
from superlocalmemory.cli.help_cmd import cmd_help_optimize
|
|
91
|
+
cmd_help_optimize(args)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ---- end SLM v3.6 Optimize dispatch functions ----
|
|
95
|
+
|
|
96
|
+
|
|
67
97
|
def dispatch(args: Namespace) -> None:
|
|
68
98
|
"""Route CLI command to the appropriate handler."""
|
|
69
99
|
# Auto-install/upgrade hooks on version change (single file read, ~0.1ms)
|
|
@@ -126,6 +156,14 @@ def dispatch(args: Namespace) -> None:
|
|
|
126
156
|
"reconfigure": _cmd_escape_reconfigure,
|
|
127
157
|
"benchmark": _cmd_escape_benchmark,
|
|
128
158
|
"rotate-token": _cmd_escape_rotate_token,
|
|
159
|
+
# LLD-06 — `slm wrap <agent> [args...]` activates the Optimize proxy.
|
|
160
|
+
"wrap": _cmd_wrap,
|
|
161
|
+
# V3.6 Optimize subcommands (additive)
|
|
162
|
+
"optimize": _cmd_optimize,
|
|
163
|
+
"cache": _cmd_cache,
|
|
164
|
+
"compress": _cmd_compress,
|
|
165
|
+
"proxy": _cmd_proxy,
|
|
166
|
+
"help-optimize": _cmd_help_optimize,
|
|
129
167
|
}
|
|
130
168
|
handler = handlers.get(args.command)
|
|
131
169
|
if handler:
|
|
@@ -135,6 +173,39 @@ def dispatch(args: Namespace) -> None:
|
|
|
135
173
|
sys.exit(1)
|
|
136
174
|
|
|
137
175
|
|
|
176
|
+
def _cmd_wrap(args: Namespace) -> None:
|
|
177
|
+
"""LLD-06 §6.6 — `slm wrap <agent> [args...]` activates the Optimize proxy.
|
|
178
|
+
|
|
179
|
+
Routes the Optimize layer's per-agent launch/activation. See
|
|
180
|
+
optimize.adapters._agent_registry for the full agent table.
|
|
181
|
+
"""
|
|
182
|
+
if getattr(args, "list", False):
|
|
183
|
+
from superlocalmemory.optimize.adapters.wrap import list_agents
|
|
184
|
+
from superlocalmemory.optimize.adapters._agent_registry import AGENT_REGISTRY
|
|
185
|
+
print("Registered agents for `slm wrap`:")
|
|
186
|
+
for key in list_agents():
|
|
187
|
+
spec = AGENT_REGISTRY.get(key, {})
|
|
188
|
+
mech = spec.get("mechanism", "unknown")
|
|
189
|
+
print(f" {key:20s} mechanism={mech}")
|
|
190
|
+
return
|
|
191
|
+
|
|
192
|
+
agent = getattr(args, "agent", None)
|
|
193
|
+
if not agent:
|
|
194
|
+
print("Usage: slm wrap <agent> [args...]\n"
|
|
195
|
+
" slm wrap --list\n"
|
|
196
|
+
" slm wrap --help")
|
|
197
|
+
sys.exit(2)
|
|
198
|
+
|
|
199
|
+
agent_args = list(getattr(args, "agent_args", []) or [])
|
|
200
|
+
persistent = bool(getattr(args, "persistent", False))
|
|
201
|
+
dry_run = bool(getattr(args, "dry_run", False))
|
|
202
|
+
|
|
203
|
+
from superlocalmemory.optimize.adapters.wrap import wrap_agent
|
|
204
|
+
rc = wrap_agent(agent, agent_args, persistent=persistent, dry_run=dry_run)
|
|
205
|
+
if rc:
|
|
206
|
+
sys.exit(rc)
|
|
207
|
+
|
|
208
|
+
|
|
138
209
|
# -- Daemon serve mode (V3.3.21) ------------------------------------------
|
|
139
210
|
|
|
140
211
|
def cmd_serve(args: Namespace) -> None:
|
|
@@ -2573,6 +2644,11 @@ def cmd_reap(args: Namespace) -> None:
|
|
|
2573
2644
|
"""Find and kill orphaned SLM processes."""
|
|
2574
2645
|
use_json = getattr(args, "json", False)
|
|
2575
2646
|
dry_run = not getattr(args, "force", False)
|
|
2647
|
+
# V3.5.9: --all bypasses orphan detection and kills every slm mcp process
|
|
2648
|
+
# except the current one. Use after switching IDEs to clear stale sessions.
|
|
2649
|
+
use_force_all = getattr(args, "all", False)
|
|
2650
|
+
if use_force_all:
|
|
2651
|
+
dry_run = False # --all always kills; --force is implied
|
|
2576
2652
|
|
|
2577
2653
|
try:
|
|
2578
2654
|
from superlocalmemory.infra.process_reaper import (
|
|
@@ -2581,7 +2657,7 @@ def cmd_reap(args: Namespace) -> None:
|
|
|
2581
2657
|
)
|
|
2582
2658
|
|
|
2583
2659
|
config = ReaperConfig()
|
|
2584
|
-
result = cleanup_all_orphans(config, dry_run=dry_run)
|
|
2660
|
+
result = cleanup_all_orphans(config, dry_run=dry_run, force=use_force_all)
|
|
2585
2661
|
except Exception as exc:
|
|
2586
2662
|
if use_json:
|
|
2587
2663
|
from superlocalmemory.cli.json_output import json_print
|
|
@@ -2600,7 +2676,8 @@ def cmd_reap(args: Namespace) -> None:
|
|
|
2600
2676
|
"killed": result.get("killed", 0),
|
|
2601
2677
|
"skipped": result.get("skipped", 0),
|
|
2602
2678
|
}, next_actions=[
|
|
2603
|
-
{"command": "slm reap --force --json", "description": "Kill
|
|
2679
|
+
{"command": "slm reap --force --json", "description": "Kill orphan processes"},
|
|
2680
|
+
{"command": "slm reap --all --json", "description": "Kill ALL slm mcp sessions (IDE switch)"},
|
|
2604
2681
|
{"command": "slm status --json", "description": "Check status"},
|
|
2605
2682
|
])
|
|
2606
2683
|
return
|
|
@@ -2620,3 +2697,4 @@ def cmd_reap(args: Namespace) -> None:
|
|
|
2620
2697
|
print(f" Skipped: {skipped}")
|
|
2621
2698
|
if dry_run and orphans > 0:
|
|
2622
2699
|
print("\n Use --force to kill orphaned processes.")
|
|
2700
|
+
print(" Use --all to kill ALL slm mcp sessions (after IDE switch).")
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
|
|
4
|
+
|
|
5
|
+
"""Handlers for ``slm compress status|mode|code|prose|ccr``."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import dataclasses
|
|
10
|
+
import json
|
|
11
|
+
import sys
|
|
12
|
+
from argparse import Namespace
|
|
13
|
+
|
|
14
|
+
from superlocalmemory.cli.optimize_constants import AGGRESSIVE_MODE_WARNING
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _get_store():
|
|
18
|
+
from superlocalmemory.optimize.config.store import ConfigStore
|
|
19
|
+
return ConfigStore()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _get_cache_db():
|
|
23
|
+
from superlocalmemory.optimize.storage.db import CacheDB
|
|
24
|
+
return CacheDB()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _write_config(**fields) -> None:
|
|
28
|
+
"""5-step immutable config-write."""
|
|
29
|
+
store = _get_store()
|
|
30
|
+
cfg = store.get()
|
|
31
|
+
try:
|
|
32
|
+
cfg = dataclasses.replace(cfg, **fields)
|
|
33
|
+
store.save(cfg)
|
|
34
|
+
except ValueError as e:
|
|
35
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
36
|
+
sys.exit(1)
|
|
37
|
+
except OSError as e:
|
|
38
|
+
print(f"Error writing config: {e}", file=sys.stderr)
|
|
39
|
+
sys.exit(1)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def cmd_compress(args: Namespace) -> None:
|
|
43
|
+
"""Top-level dispatcher for ``slm compress <subcommand>``."""
|
|
44
|
+
sub = getattr(args, "compress_command", None)
|
|
45
|
+
_dispatch = {
|
|
46
|
+
"status": cmd_compress_status,
|
|
47
|
+
"mode": cmd_compress_mode,
|
|
48
|
+
"code": cmd_compress_code,
|
|
49
|
+
"prose": cmd_compress_prose,
|
|
50
|
+
"ccr": cmd_compress_ccr,
|
|
51
|
+
"align": cmd_compress_align,
|
|
52
|
+
}
|
|
53
|
+
handler = _dispatch.get(sub or "")
|
|
54
|
+
if handler:
|
|
55
|
+
handler(args)
|
|
56
|
+
else:
|
|
57
|
+
print("Usage: slm compress status|mode|code|prose|ccr [options]")
|
|
58
|
+
sys.exit(0)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def cmd_compress_status(args: Namespace) -> None:
|
|
62
|
+
"""Print compression status."""
|
|
63
|
+
use_json = getattr(args, "json", False)
|
|
64
|
+
cfg = _get_store().get()
|
|
65
|
+
|
|
66
|
+
if use_json:
|
|
67
|
+
data = {
|
|
68
|
+
"status": "ok",
|
|
69
|
+
"compress_enabled": cfg.compress_enabled,
|
|
70
|
+
"compress_mode": cfg.compress_mode,
|
|
71
|
+
"compress_code": cfg.compress_code,
|
|
72
|
+
"compress_prose": cfg.compress_prose,
|
|
73
|
+
"compress_ccr": cfg.compress_ccr,
|
|
74
|
+
}
|
|
75
|
+
print(json.dumps(data, indent=2))
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
print("Compression status:")
|
|
79
|
+
print(f" Enabled: {'yes' if cfg.compress_enabled else 'no'}")
|
|
80
|
+
print(f" Mode: {cfg.compress_mode}")
|
|
81
|
+
print(f" Code: {'ON' if cfg.compress_code else 'OFF'}"
|
|
82
|
+
" (extractive JSON/code — lossless structure)")
|
|
83
|
+
print(f" Prose: {'ON' if cfg.compress_prose else 'OFF'}")
|
|
84
|
+
print(f" CCR: {'ON' if cfg.compress_ccr else 'OFF'}"
|
|
85
|
+
" (reversible context retrieval)")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def cmd_compress_mode(args: Namespace) -> None:
|
|
89
|
+
"""Set compression mode to safe or aggressive."""
|
|
90
|
+
use_json = getattr(args, "json", False)
|
|
91
|
+
mode_value = getattr(args, "mode_value", "safe")
|
|
92
|
+
|
|
93
|
+
if mode_value == "aggressive":
|
|
94
|
+
print(AGGRESSIVE_MODE_WARNING)
|
|
95
|
+
|
|
96
|
+
_write_config(compress_mode=mode_value)
|
|
97
|
+
|
|
98
|
+
if use_json:
|
|
99
|
+
print(json.dumps({"status": "ok", "compress_mode": mode_value}))
|
|
100
|
+
return
|
|
101
|
+
|
|
102
|
+
print(f"Compression mode set to: {mode_value}.")
|
|
103
|
+
print("Daemon hot-reload: active within 2s. No restart required.")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def cmd_compress_code(args: Namespace) -> None:
|
|
107
|
+
"""Enable or disable code/JSON compression."""
|
|
108
|
+
use_json = getattr(args, "json", False)
|
|
109
|
+
value = getattr(args, "code_value", "on")
|
|
110
|
+
|
|
111
|
+
_write_config(compress_code=(value == "on"))
|
|
112
|
+
|
|
113
|
+
if use_json:
|
|
114
|
+
print(json.dumps({"status": "ok", "compress_code": value == "on"}))
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
print(f"Code compression: {'ENABLED' if value == 'on' else 'DISABLED'}.")
|
|
118
|
+
print("Daemon hot-reload: active within 2s.")
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def cmd_compress_prose(args: Namespace) -> None:
|
|
122
|
+
"""Enable or disable prose compression."""
|
|
123
|
+
use_json = getattr(args, "json", False)
|
|
124
|
+
value = getattr(args, "prose_value", "off")
|
|
125
|
+
|
|
126
|
+
store = _get_store()
|
|
127
|
+
cfg = store.get()
|
|
128
|
+
|
|
129
|
+
fields: dict = {"compress_prose": (value == "on")}
|
|
130
|
+
if value == "on" and not cfg.compress_enabled:
|
|
131
|
+
fields["compress_enabled"] = True
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
cfg = dataclasses.replace(cfg, **fields)
|
|
135
|
+
store.save(cfg)
|
|
136
|
+
except (ValueError, OSError) as e:
|
|
137
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
138
|
+
sys.exit(1)
|
|
139
|
+
|
|
140
|
+
if use_json:
|
|
141
|
+
print(json.dumps({"status": "ok", "compress_prose": value == "on"}))
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
print(f"Prose compression: {'ENABLED' if value == 'on' else 'DISABLED'}.")
|
|
145
|
+
if value == "on" and "compress_enabled" in fields:
|
|
146
|
+
print(" (also enabled global compress)")
|
|
147
|
+
print("Daemon hot-reload: active within 2s.")
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def cmd_compress_align(args: Namespace) -> None:
|
|
151
|
+
"""Enable or disable alignment compression."""
|
|
152
|
+
use_json = getattr(args, "json", False)
|
|
153
|
+
value = getattr(args, "align_value", "on")
|
|
154
|
+
|
|
155
|
+
_write_config(compress_align=(value == "on"))
|
|
156
|
+
|
|
157
|
+
if use_json:
|
|
158
|
+
print(json.dumps({"status": "ok", "compress_align": value == "on"}))
|
|
159
|
+
return
|
|
160
|
+
|
|
161
|
+
print(f"Alignment compression: {'ENABLED' if value == 'on' else 'DISABLED'}.")
|
|
162
|
+
print("Daemon hot-reload: active within 2s.")
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def cmd_compress_ccr(args: Namespace) -> None:
|
|
166
|
+
"""Enable or disable CCR (Compressed Context Retrieval)."""
|
|
167
|
+
use_json = getattr(args, "json", False)
|
|
168
|
+
value = getattr(args, "ccr_value", "off")
|
|
169
|
+
|
|
170
|
+
_write_config(compress_ccr=(value == "on"))
|
|
171
|
+
|
|
172
|
+
if use_json:
|
|
173
|
+
print(json.dumps({"status": "ok", "compress_ccr": value == "on"}))
|
|
174
|
+
return
|
|
175
|
+
|
|
176
|
+
print(f"CCR (Compressed Context Retrieval): {'ENABLED' if value == 'on' else 'DISABLED'}.")
|
|
177
|
+
if value == "on":
|
|
178
|
+
print("Originals stored in llmcache.db for reversible retrieval.")
|
|
179
|
+
print("Daemon hot-reload: active within 2s.")
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
+
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
+
# Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
|
|
4
|
+
|
|
5
|
+
"""Handler for ``slm help-optimize``."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
from argparse import Namespace
|
|
11
|
+
|
|
12
|
+
_HELP_SECTIONS: dict[str, str] = {
|
|
13
|
+
"header": """\
|
|
14
|
+
SLM v3.6 Optimize — Developer Reference
|
|
15
|
+
========================================
|
|
16
|
+
Every feature is configurable via CLI. UI provides the same controls for
|
|
17
|
+
non-technical users. All CLI commands write config at runtime — daemon
|
|
18
|
+
hot-reloads within 2 seconds. No restart required.
|
|
19
|
+
""",
|
|
20
|
+
"optimize": """\
|
|
21
|
+
slm optimize — Optimize module control
|
|
22
|
+
---------------------------------------
|
|
23
|
+
slm optimize status Show all Optimize settings
|
|
24
|
+
slm optimize on Enable cache + compress
|
|
25
|
+
slm optimize off Disable cache + compress (proxy keeps running)
|
|
26
|
+
slm optimize savings [--since N] Token/cost savings report (default: 7 days)
|
|
27
|
+
--since N Days to look back (integer, default 7)
|
|
28
|
+
--provider P Filter by: anthropic|openai|gemini
|
|
29
|
+
All: --json Machine-readable JSON output
|
|
30
|
+
""",
|
|
31
|
+
"cache": """\
|
|
32
|
+
slm cache — Cache control
|
|
33
|
+
--------------------------
|
|
34
|
+
slm cache status Entry count, DB size, TTLs, hit rate
|
|
35
|
+
slm cache clear Delete all entries for this tenant
|
|
36
|
+
slm cache invalidate --tag <t> Delete entries whose tag array contains <t>
|
|
37
|
+
slm cache ttl --set <s> Set exact-cache TTL (seconds)
|
|
38
|
+
--semantic <s> Set semantic-cache TTL (seconds)
|
|
39
|
+
slm cache semantic on|off Enable/disable semantic cache
|
|
40
|
+
All: --json --tenant <id>
|
|
41
|
+
|
|
42
|
+
TTL examples:
|
|
43
|
+
slm cache ttl --set 3600 # 1 hour exact cache
|
|
44
|
+
slm cache ttl --set 86400 # 24 hour exact cache (default)
|
|
45
|
+
slm cache ttl --semantic 7200 # 2 hour semantic cache
|
|
46
|
+
""",
|
|
47
|
+
"compress": """\
|
|
48
|
+
slm compress — Compression control
|
|
49
|
+
-----------------------------------
|
|
50
|
+
slm compress status Show compression mode, per-channel state
|
|
51
|
+
slm compress mode safe|aggressive Set compression aggressiveness
|
|
52
|
+
slm compress code on|off Enable/disable code/JSON compression
|
|
53
|
+
slm compress prose on|off Enable/disable prose compression
|
|
54
|
+
slm compress ccr on|off Enable/disable Compressed Context Retrieval
|
|
55
|
+
All: --json
|
|
56
|
+
""",
|
|
57
|
+
"safety": """\
|
|
58
|
+
COMPRESSION SAFETY WARNING
|
|
59
|
+
---------------------------
|
|
60
|
+
Safe mode (default):
|
|
61
|
+
- Code/JSON compression: extractive, structure-preserving, lossless.
|
|
62
|
+
- Prose compression: DISABLED in safe mode. Enable manually.
|
|
63
|
+
- CCR: DISABLED by default. Originals stored for reversible retrieval.
|
|
64
|
+
- This mode is production-safe for all use cases.
|
|
65
|
+
|
|
66
|
+
Aggressive mode:
|
|
67
|
+
!! RISK: May reduce output fidelity. Use with caution. !!
|
|
68
|
+
- Prose compression: LLMLingua-2-style extractive summarization.
|
|
69
|
+
- May omit nuance, hedges, or low-salience context.
|
|
70
|
+
- DO NOT use for:
|
|
71
|
+
- Code generation or code review
|
|
72
|
+
- Legal, compliance, or regulatory text
|
|
73
|
+
- Math, formulas, or structured data generation
|
|
74
|
+
- Any task requiring exact reproduction of input
|
|
75
|
+
- Suitable for:
|
|
76
|
+
- Open-ended brainstorming
|
|
77
|
+
- Summarization of long documents
|
|
78
|
+
- Casual conversation and exploration
|
|
79
|
+
- To revert: slm compress mode safe
|
|
80
|
+
""",
|
|
81
|
+
"proxy": """\
|
|
82
|
+
slm proxy — Optimization proxy
|
|
83
|
+
--------------------------------
|
|
84
|
+
slm proxy [--port P] [--provider anthropic|openai|gemini]
|
|
85
|
+
[--no-compress] [--semantic] [--json]
|
|
86
|
+
|
|
87
|
+
Starts the SLM proxy (or reports existing). Proxy intercepts LLM calls,
|
|
88
|
+
applies cache lookup, and optionally compresses context before forwarding.
|
|
89
|
+
|
|
90
|
+
Default port: 8765
|
|
91
|
+
Anthropic surface: http://127.0.0.1:8765
|
|
92
|
+
OpenAI surface: http://127.0.0.1:8765/v1
|
|
93
|
+
""",
|
|
94
|
+
"agents": """\
|
|
95
|
+
PER-AGENT SETUP RECIPES
|
|
96
|
+
------------------------
|
|
97
|
+
|
|
98
|
+
--- Claude Code (ANTHROPIC_BASE_URL) ---
|
|
99
|
+
The simplest redirect. Set this env var before launching Claude Code.
|
|
100
|
+
|
|
101
|
+
Option A — environment variable (per-session):
|
|
102
|
+
export ANTHROPIC_BASE_URL=http://127.0.0.1:8765
|
|
103
|
+
claude # Claude Code picks up the env var
|
|
104
|
+
|
|
105
|
+
Option B — slm wrap (one command, recommended):
|
|
106
|
+
slm wrap claude # starts proxy + sets env + launches claude
|
|
107
|
+
|
|
108
|
+
Option C — permanent (add to ~/.zshrc or ~/.bashrc):
|
|
109
|
+
echo 'export ANTHROPIC_BASE_URL=http://127.0.0.1:8765' >> ~/.zshrc
|
|
110
|
+
source ~/.zshrc
|
|
111
|
+
|
|
112
|
+
Verify: slm optimize status -> look for "proxy: running on :8765"
|
|
113
|
+
|
|
114
|
+
--- Antigravity (config.toml base_url) ---
|
|
115
|
+
Antigravity reads base_url from its config.toml.
|
|
116
|
+
Default config location: ~/.config/antigravity/config.toml
|
|
117
|
+
|
|
118
|
+
Add or update this line under the [api] section:
|
|
119
|
+
[api]
|
|
120
|
+
base_url = "http://127.0.0.1:8765"
|
|
121
|
+
|
|
122
|
+
Or use slm wrap (if supported in your version):
|
|
123
|
+
slm wrap antigravity
|
|
124
|
+
|
|
125
|
+
Verify: antigravity --debug -> look for "base_url: http://127.0.0.1:8765"
|
|
126
|
+
|
|
127
|
+
--- Generic OpenAI-compatible clients (Cline, Cursor, Aider, OpenCode) ---
|
|
128
|
+
Any client that accepts an OpenAI base_url can use the /v1 surface:
|
|
129
|
+
base_url = http://127.0.0.1:8765/v1
|
|
130
|
+
api_key = (use your real provider key — proxy forwards it)
|
|
131
|
+
|
|
132
|
+
Aider:
|
|
133
|
+
aider --openai-api-base http://127.0.0.1:8765/v1
|
|
134
|
+
|
|
135
|
+
Cline (VS Code settings.json):
|
|
136
|
+
"cline.openAiBaseUrl": "http://127.0.0.1:8765/v1"
|
|
137
|
+
|
|
138
|
+
Cursor (Settings > Models > Base URL):
|
|
139
|
+
http://127.0.0.1:8765/v1
|
|
140
|
+
|
|
141
|
+
OpenCode / other CLI tools:
|
|
142
|
+
OPENAI_BASE_URL=http://127.0.0.1:8765/v1 opencode
|
|
143
|
+
|
|
144
|
+
Or use slm wrap:
|
|
145
|
+
slm wrap aider [-- <aider args>]
|
|
146
|
+
slm wrap cursor
|
|
147
|
+
slm wrap opencode
|
|
148
|
+
|
|
149
|
+
--- SDK adapters (Python) ---
|
|
150
|
+
from superlocalmemory.optimize.adapters.openai_adapter import withSLM
|
|
151
|
+
from openai import OpenAI
|
|
152
|
+
client = withSLM(OpenAI()) # same interface as OpenAI() — zero API change
|
|
153
|
+
|
|
154
|
+
from superlocalmemory.optimize.adapters.anthropic_adapter import withSLM
|
|
155
|
+
from anthropic import Anthropic
|
|
156
|
+
client = withSLM(Anthropic())
|
|
157
|
+
|
|
158
|
+
NOTE: withSLM() is a pass-through when optimize is OFF.
|
|
159
|
+
No behavioral change until you run: slm optimize on
|
|
160
|
+
""",
|
|
161
|
+
"footer": """\
|
|
162
|
+
More commands:
|
|
163
|
+
slm help-optimize cache Cache subcommand reference
|
|
164
|
+
slm help-optimize compress Compress reference + safety warning
|
|
165
|
+
slm help-optimize agents Per-agent setup recipes
|
|
166
|
+
slm help-optimize safety Compression safety warning only
|
|
167
|
+
|
|
168
|
+
Documentation: https://superlocalmemory.com
|
|
169
|
+
GitHub: https://github.com/qualixar/superlocalmemory
|
|
170
|
+
AI Reliability Engineering by @varunPbhardwaj — https://qualixar.com
|
|
171
|
+
""",
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def cmd_help_optimize(args: Namespace) -> None:
|
|
176
|
+
"""Print the full slm help-optimize page or a topic-specific section."""
|
|
177
|
+
topic = getattr(args, "topic", None)
|
|
178
|
+
no_pager = getattr(args, "no_pager", False)
|
|
179
|
+
|
|
180
|
+
if topic and topic not in _HELP_SECTIONS:
|
|
181
|
+
print(f"Unknown topic: {topic}."
|
|
182
|
+
f" Topics: {' '.join(k for k in _HELP_SECTIONS if k != 'footer')}")
|
|
183
|
+
sys.exit(1)
|
|
184
|
+
|
|
185
|
+
if topic:
|
|
186
|
+
text = _HELP_SECTIONS[topic]
|
|
187
|
+
else:
|
|
188
|
+
text = "\n".join(_HELP_SECTIONS.values())
|
|
189
|
+
|
|
190
|
+
if no_pager or not sys.stdout.isatty():
|
|
191
|
+
print(text)
|
|
192
|
+
else:
|
|
193
|
+
try:
|
|
194
|
+
import pydoc
|
|
195
|
+
pydoc.pager(text)
|
|
196
|
+
except Exception:
|
|
197
|
+
print(text)
|
|
@@ -240,6 +240,28 @@ def main() -> None:
|
|
|
240
240
|
help="Run only the fast checks (deps + config); skip daemon/embedding probes",
|
|
241
241
|
)
|
|
242
242
|
|
|
243
|
+
# LLD-06 §6.6 — `slm wrap <agent> [args...]` activates the Optimize
|
|
244
|
+
# proxy for a specific agent. Supported agents: claude, claude-settings,
|
|
245
|
+
# codex, aider, cline, generic, etc. See optimize.adapters._agent_registry.
|
|
246
|
+
wrap_p = sub.add_parser(
|
|
247
|
+
"wrap",
|
|
248
|
+
help="Activate Optimize proxy for a specific agent (claude, codex, aider, ...)",
|
|
249
|
+
)
|
|
250
|
+
wrap_p.add_argument(
|
|
251
|
+
"--list", action="store_true",
|
|
252
|
+
help="List all registered agents and their mechanisms",
|
|
253
|
+
)
|
|
254
|
+
wrap_p.add_argument(
|
|
255
|
+
"--persistent", action="store_true",
|
|
256
|
+
help="Persist env vars to the agent's config file (~/.claude/settings.json) instead of launching",
|
|
257
|
+
)
|
|
258
|
+
wrap_p.add_argument(
|
|
259
|
+
"--dry-run", action="store_true",
|
|
260
|
+
help="Print the action that would be taken without executing it",
|
|
261
|
+
)
|
|
262
|
+
wrap_p.add_argument("agent", nargs="?", default=None, help="Agent key (run `slm wrap --list` to see all)")
|
|
263
|
+
wrap_p.add_argument("agent_args", nargs=argparse.REMAINDER, help="Args passed to the agent binary")
|
|
264
|
+
|
|
243
265
|
# -- Services ------------------------------------------------------
|
|
244
266
|
sub.add_parser("mcp", help="Start MCP server (stdio transport for IDE integration)")
|
|
245
267
|
sub.add_parser("warmup", help="Pre-download embedding model (~500MB, one-time)")
|
|
@@ -349,6 +371,10 @@ def main() -> None:
|
|
|
349
371
|
"--force", action="store_true",
|
|
350
372
|
help="Kill orphans (default: dry run only)",
|
|
351
373
|
)
|
|
374
|
+
reap_p.add_argument(
|
|
375
|
+
"--all", action="store_true", dest="all",
|
|
376
|
+
help="Kill ALL slm mcp processes regardless of orphan status (use after IDE switch)",
|
|
377
|
+
)
|
|
352
378
|
reap_p.add_argument("--json", action="store_true", help="Output structured JSON (agent-native)")
|
|
353
379
|
|
|
354
380
|
# V3.4.3: Ingestion adapters
|
|
@@ -445,6 +471,95 @@ def main() -> None:
|
|
|
445
471
|
help="Rotate the SLM install token (run `slm restart` afterwards)",
|
|
446
472
|
)
|
|
447
473
|
|
|
474
|
+
# ---- SLM v3.6 Optimize subcommands (additive, never modify above) ----
|
|
475
|
+
|
|
476
|
+
# slm optimize status|on|off|savings
|
|
477
|
+
opt_p = sub.add_parser("optimize", help="Optimize module control (cache + compress)")
|
|
478
|
+
opt_sub = opt_p.add_subparsers(dest="opt_command", title="optimize subcommands")
|
|
479
|
+
opt_sub.add_parser("status", help="Show Optimize status")
|
|
480
|
+
opt_sub.add_parser("on", help="Enable cache + compress")
|
|
481
|
+
opt_sub.add_parser("off", help="Disable cache + compress")
|
|
482
|
+
savings_p = opt_sub.add_parser("savings", help="Token/cost savings report")
|
|
483
|
+
savings_p.add_argument("--since", type=int, default=7, help="Days to look back (default 7)")
|
|
484
|
+
savings_p.add_argument("--provider", default=None,
|
|
485
|
+
choices=["anthropic", "openai", "gemini"],
|
|
486
|
+
help="Filter by provider")
|
|
487
|
+
for _sp in opt_sub.choices.values():
|
|
488
|
+
if not any(a.option_strings == ["--json"] for a in _sp._actions):
|
|
489
|
+
_sp.add_argument("--json", action="store_true",
|
|
490
|
+
help="Output structured JSON (agent-native)")
|
|
491
|
+
|
|
492
|
+
# slm cache status|clear|invalidate|ttl|semantic
|
|
493
|
+
cache_p = sub.add_parser("cache", help="Cache control (TTL, clear, invalidate, semantic)")
|
|
494
|
+
cache_sub = cache_p.add_subparsers(dest="cache_command", title="cache subcommands")
|
|
495
|
+
cache_sub.add_parser("status", help="Show cache state")
|
|
496
|
+
cache_sub.add_parser("clear", help="Delete all entries for tenant")
|
|
497
|
+
cache_inv_p = cache_sub.add_parser("invalidate", help="Delete entries by tag")
|
|
498
|
+
cache_inv_p.add_argument("--tag", required=True, help="Tag string to match")
|
|
499
|
+
cache_ttl_p = cache_sub.add_parser("ttl", help="Set cache TTL in seconds")
|
|
500
|
+
cache_ttl_p.add_argument("--set", dest="ttl_set", type=int, default=None,
|
|
501
|
+
help="Exact-cache TTL (seconds, >0)")
|
|
502
|
+
cache_ttl_p.add_argument("--semantic", dest="ttl_semantic", type=int, default=None,
|
|
503
|
+
help="Semantic-cache TTL (seconds, >0)")
|
|
504
|
+
cache_sem_p = cache_sub.add_parser("semantic", help="Enable/disable semantic cache")
|
|
505
|
+
cache_sem_p.add_argument("semantic_value", choices=["on", "off"], help="on or off")
|
|
506
|
+
for _sp in cache_sub.choices.values():
|
|
507
|
+
if not any(a.option_strings == ["--json"] for a in _sp._actions):
|
|
508
|
+
_sp.add_argument("--json", action="store_true",
|
|
509
|
+
help="Output structured JSON (agent-native)")
|
|
510
|
+
if not any(a.option_strings == ["--tenant"] for a in _sp._actions):
|
|
511
|
+
_sp.add_argument("--tenant", default="default", help="Tenant ID (default: 'default')")
|
|
512
|
+
|
|
513
|
+
# slm compress status|mode|code|prose|ccr
|
|
514
|
+
compress_p = sub.add_parser("compress", help="Compression control (mode, code, prose, CCR)")
|
|
515
|
+
comp_sub = compress_p.add_subparsers(dest="compress_command", title="compress subcommands")
|
|
516
|
+
comp_sub.add_parser("status", help="Show compression state")
|
|
517
|
+
comp_mode_p = comp_sub.add_parser("mode", help="Set compression mode")
|
|
518
|
+
comp_mode_p.add_argument("mode_value", choices=["safe", "aggressive"],
|
|
519
|
+
help="safe (default) or aggressive")
|
|
520
|
+
comp_code_p = comp_sub.add_parser("code", help="Enable/disable code compression")
|
|
521
|
+
comp_code_p.add_argument("code_value", choices=["on", "off"], help="on or off")
|
|
522
|
+
comp_prose_p = comp_sub.add_parser("prose", help="Enable/disable prose compression")
|
|
523
|
+
comp_prose_p.add_argument("prose_value", choices=["on", "off"], help="on or off")
|
|
524
|
+
comp_ccr_p = comp_sub.add_parser("ccr", help="Enable/disable CCR")
|
|
525
|
+
comp_ccr_p.add_argument("ccr_value", choices=["on", "off"], help="on or off")
|
|
526
|
+
comp_align_p = comp_sub.add_parser("align", help="Enable/disable alignment compression")
|
|
527
|
+
comp_align_p.add_argument("align_value", choices=["on", "off"], help="on or off")
|
|
528
|
+
for _sp in comp_sub.choices.values():
|
|
529
|
+
if not any(a.option_strings == ["--json"] for a in _sp._actions):
|
|
530
|
+
_sp.add_argument("--json", action="store_true",
|
|
531
|
+
help="Output structured JSON (agent-native)")
|
|
532
|
+
|
|
533
|
+
# slm proxy
|
|
534
|
+
proxy_p = sub.add_parser("proxy", help="Start SLM optimization proxy (Anthropic + OpenAI)")
|
|
535
|
+
proxy_p.add_argument("--port", type=int, default=8765, help="Port (default: 8765)")
|
|
536
|
+
proxy_p.add_argument("--provider", default="anthropic",
|
|
537
|
+
choices=["anthropic", "openai", "gemini"],
|
|
538
|
+
help="Target provider (default: anthropic)")
|
|
539
|
+
proxy_p.add_argument("--no-compress", action="store_true", dest="no_compress",
|
|
540
|
+
help="Disable compression for this session")
|
|
541
|
+
proxy_p.add_argument("--semantic", action="store_true",
|
|
542
|
+
help="Enable semantic cache for this session")
|
|
543
|
+
proxy_p.add_argument("--json", action="store_true",
|
|
544
|
+
help="Output structured JSON (agent-native)")
|
|
545
|
+
|
|
546
|
+
# slm help-optimize
|
|
547
|
+
help_opt_p = sub.add_parser(
|
|
548
|
+
"help-optimize",
|
|
549
|
+
help="Full Optimize reference: subcommands + agent recipes + safety notes",
|
|
550
|
+
)
|
|
551
|
+
help_opt_p.add_argument(
|
|
552
|
+
"topic", nargs="?", default=None,
|
|
553
|
+
choices=["cache", "compress", "optimize", "proxy", "agents", "safety"],
|
|
554
|
+
help="Topic to display (default: all)",
|
|
555
|
+
)
|
|
556
|
+
help_opt_p.add_argument(
|
|
557
|
+
"--no-pager", action="store_true", dest="no_pager", default=False,
|
|
558
|
+
help="Print to stdout instead of piping through a pager",
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
# ---- end SLM v3.6 Optimize subcommands ----
|
|
562
|
+
|
|
448
563
|
args = parser.parse_args()
|
|
449
564
|
|
|
450
565
|
if not args.command:
|
|
@@ -464,6 +579,13 @@ def main() -> None:
|
|
|
464
579
|
# v3.4.22 escape hatches — never auto-start the daemon on these.
|
|
465
580
|
"disable", "enable", "clear-cache", "reconfigure", "benchmark",
|
|
466
581
|
"rotate-token",
|
|
582
|
+
# LLD-06 — `slm wrap` may launch the agent binary directly without
|
|
583
|
+
# needing the daemon running (the agent will start the daemon on
|
|
584
|
+
# first LLM call, or the wrap command can be --dry-run).
|
|
585
|
+
"wrap",
|
|
586
|
+
# V3.6 Optimize commands that are config read/write only (no daemon needed)
|
|
587
|
+
"optimize", "cache", "compress", "help-optimize",
|
|
588
|
+
# NOTE: "proxy" NOT here — proxy needs daemon running
|
|
467
589
|
}
|
|
468
590
|
if args.command not in _NO_DAEMON_COMMANDS:
|
|
469
591
|
try:
|