chad-code 1.0.8__tar.gz → 1.0.9__tar.gz
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.
- {chad_code-1.0.8 → chad_code-1.0.9}/PKG-INFO +1 -1
- {chad_code-1.0.8 → chad_code-1.0.9}/pyproject.toml +5 -5
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/__init__.py +1 -1
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/mlx_fastpath.py +55 -4
- chad_code-1.0.9/src/chad/mlx_moe_fused.py +657 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad_code.egg-info/PKG-INFO +1 -1
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad_code.egg-info/SOURCES.txt +2 -0
- chad_code-1.0.9/tests/test_mlx_moe_fused.py +354 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/LICENSE +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/README.md +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/setup.cfg +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/agent.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/atif.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/base_engine.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/bench.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/cli.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/compaction.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/completion_engine.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/config.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/diag.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/engine.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/guardrails.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/ignore.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/levers.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/lsp.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/lspclient.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/lspservers.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/mcp.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/mcp_oauth.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/mlx_qsdpa.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/parakeet/LICENSE +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/parakeet/__init__.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/parakeet/alignment.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/parakeet/attention.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/parakeet/audio.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/parakeet/cache.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/parakeet/conformer.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/parakeet/ctc.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/parakeet/parakeet.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/parakeet/rnnt.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/parakeet/tokenizer.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/parakeet/utils.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/profiles.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/prompt.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/prove.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/render.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/repomap.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/serve.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/session.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/skills.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/speech.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/symbols.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/syntaxgate.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/toolcall_parse.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/tools.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/tui.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad/validate.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad_code.egg-info/dependency_links.txt +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad_code.egg-info/entry_points.txt +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad_code.egg-info/requires.txt +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/src/chad_code.egg-info/top_level.txt +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_agent.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_agent_e2e.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_agent_guards.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_atif.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_bench.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_cli.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_compact_notice.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_compaction.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_completion_engine.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_config.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_confirm_preview.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_done_audit.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_drift_warn.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_edit.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_edit_corruption.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_engine.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_engine_kvquant.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_engine_pld_hybrid.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_feel_pack.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_garble_invariant.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_gate.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_ignore.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_intent.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_lever_bite.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_levers.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_log_redaction.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_lsp.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_lsp_live.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_lspclient.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_mcp.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_mcp_oauth.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_mlx_fastpath.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_mlx_qsdpa.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_plan_review.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_prove.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_render.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_replace_lines.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_repomap.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_repomap_polyglot.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_serve.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_session.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_skills.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_speech.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_speech_tui.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_subagent.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_symbols.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_syntaxgate.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_toolcall_parse.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_tools.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_tui.py +0 -0
- {chad_code-1.0.8 → chad_code-1.0.9}/tests/test_validate.py +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# import name, and command name are independent. `uvx chad-code` runs the alias
|
|
5
5
|
# script added under [project.scripts].
|
|
6
6
|
name = "chad-code"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.9"
|
|
8
8
|
description = "Local MLX-backed, Claude-Code-style coding agent (Apple Silicon, Ornith 35B/9B)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -174,10 +174,10 @@ module = "chad.parakeet.*"
|
|
|
174
174
|
ignore_errors = true
|
|
175
175
|
|
|
176
176
|
[[tool.mypy.overrides]]
|
|
177
|
-
#
|
|
178
|
-
# (dev Macs, the macos CI jobs)
|
|
177
|
+
# These modules patch mlx_lm classes that only exist on macOS: with mlx installed
|
|
178
|
+
# (dev Macs, the macos CI jobs) their `type: ignore[method-assign]` comments are load-
|
|
179
179
|
# bearing; on the Linux lint runner mlx_lm is absent, the patched classes type as Any,
|
|
180
180
|
# and warn_unused_ignores flags those same comments — unfixable in the code for both
|
|
181
|
-
# platforms at once, so the unused-ignore warning alone is relaxed for
|
|
182
|
-
module = "chad.mlx_fastpath"
|
|
181
|
+
# platforms at once, so the unused-ignore warning alone is relaxed for them.
|
|
182
|
+
module = ["chad.mlx_fastpath", "chad.mlx_moe_fused"]
|
|
183
183
|
warn_unused_ignores = false
|
|
@@ -4,7 +4,7 @@ A flat collection of cooperating modules behind one console script (``chad``):
|
|
|
4
4
|
the inference engine, the tool layer, the agent loop, and the terminal UI.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
__version__ = "1.0.
|
|
7
|
+
__version__ = "1.0.9"
|
|
8
8
|
|
|
9
9
|
# chad sets no MLX_* runtime vars. MLX_METAL_FAST_SYNCH, MLX_MAX_OPS_PER_BUFFER
|
|
10
10
|
# and MLX_MAX_MB_PER_BUFFER were each measured end-to-end on the 35B and every
|
|
@@ -61,6 +61,10 @@ def install(model: Any) -> bool:
|
|
|
61
61
|
return False
|
|
62
62
|
_concat_expert_gate_up(model)
|
|
63
63
|
_concat_gdn_in_projs(model)
|
|
64
|
+
# Fused MoE decode kernels + router|seg / shared gate|up concats;
|
|
65
|
+
# engages only on the exact 35B geometry, silent no-op elsewhere.
|
|
66
|
+
from . import mlx_moe_fused
|
|
67
|
+
mlx_moe_fused.install(model)
|
|
64
68
|
_install_layer_fastpath(model)
|
|
65
69
|
log.info("FASTPATH installed: fused expert/GDN projections + compiled "
|
|
66
70
|
"S=1 layer step")
|
|
@@ -129,6 +133,8 @@ def _patch_switch_glu() -> None:
|
|
|
129
133
|
import mlx.core as mx
|
|
130
134
|
from mlx_lm.models import switch_layers as sl
|
|
131
135
|
|
|
136
|
+
if getattr(sl.SwitchGLU.__call__, "_chad_fastpath", False):
|
|
137
|
+
return # already patched; re-wrapping would stack guards
|
|
132
138
|
stock_call = sl.SwitchGLU.__call__
|
|
133
139
|
|
|
134
140
|
def fused_call(self, x, indices):
|
|
@@ -151,6 +157,7 @@ def _patch_switch_glu() -> None:
|
|
|
151
157
|
y = sl._scatter_unsort(y, inv_order, indices.shape)
|
|
152
158
|
return y.squeeze(-2)
|
|
153
159
|
|
|
160
|
+
fused_call._chad_fastpath = True # type: ignore[attr-defined]
|
|
154
161
|
sl.SwitchGLU.__call__ = fused_call # type: ignore[method-assign]
|
|
155
162
|
|
|
156
163
|
|
|
@@ -187,6 +194,8 @@ def _patch_gdn_call() -> None:
|
|
|
187
194
|
import mlx.nn as nn
|
|
188
195
|
from mlx_lm.models import qwen3_5 as q35
|
|
189
196
|
|
|
197
|
+
if getattr(q35.GatedDeltaNet.__call__, "_chad_fastpath", False):
|
|
198
|
+
return
|
|
190
199
|
stock_call = q35.GatedDeltaNet.__call__
|
|
191
200
|
|
|
192
201
|
def call(self, inputs, mask=None, cache=None):
|
|
@@ -236,6 +245,7 @@ def _patch_gdn_call() -> None:
|
|
|
236
245
|
out = self.norm(out, z)
|
|
237
246
|
return self.out_proj(out.reshape(B, S, -1))
|
|
238
247
|
|
|
248
|
+
call._chad_fastpath = True # type: ignore[attr-defined]
|
|
239
249
|
q35.GatedDeltaNet.__call__ = call # type: ignore[method-assign]
|
|
240
250
|
|
|
241
251
|
|
|
@@ -246,13 +256,32 @@ def _install_layer_fastpath(model) -> None:
|
|
|
246
256
|
from mlx_lm.models import qwen3_5 as q35
|
|
247
257
|
|
|
248
258
|
for layer in model.language_model.model.layers:
|
|
249
|
-
|
|
259
|
+
body = _compile_moe_step(layer)
|
|
260
|
+
fused = getattr(layer.mlp, "_fused_step", None)
|
|
261
|
+
if fused is not None:
|
|
262
|
+
# mlx_moe_fused kernels handle the single-token (1,1,2048) decode
|
|
263
|
+
# step; anything else (batched decode, foreign width) takes the
|
|
264
|
+
# compiled stock-graph body. Pinning the exact element count keeps
|
|
265
|
+
# a future geometry change from reaching kernels that hardcode it.
|
|
266
|
+
from .mlx_moe_fused import HID as moe_hid
|
|
267
|
+
layer._moe_body_fast = body
|
|
268
|
+
layer._moe_fast = (lambda h, f=fused, b=body, n=moe_hid:
|
|
269
|
+
f(h) if h.size == n else b(h))
|
|
270
|
+
else:
|
|
271
|
+
layer._moe_fast = body
|
|
250
272
|
if layer.is_linear and hasattr(layer.linear_attn, "_fused_w"):
|
|
251
273
|
layer._gdn_fast = _compile_gdn_step(layer)
|
|
252
274
|
|
|
275
|
+
if getattr(q35.DecoderLayer.__call__, "_chad_fastpath", False):
|
|
276
|
+
return
|
|
253
277
|
stock_layer_call = q35.DecoderLayer.__call__
|
|
254
278
|
|
|
255
279
|
def layer_call(self, x, mask=None, cache=None):
|
|
280
|
+
# S==1 cannot distinguish decode from a stray 1-token prefill chunk
|
|
281
|
+
# (mask is None for both); such a chunk takes this path and pays one
|
|
282
|
+
# token's worth of the same rounding class decode itself injects into
|
|
283
|
+
# the cache every step — bounded, unlike S>1 compile-fusion drift,
|
|
284
|
+
# which is why prefill proper stays on the stock graph.
|
|
256
285
|
if mask is None and x.shape[1] == 1 and cache is not None \
|
|
257
286
|
and getattr(self, "_moe_fast", None) is not None:
|
|
258
287
|
if self.is_linear:
|
|
@@ -270,6 +299,7 @@ def _install_layer_fastpath(model) -> None:
|
|
|
270
299
|
return self._moe_fast(x + r)
|
|
271
300
|
return stock_layer_call(self, x, mask=mask, cache=cache)
|
|
272
301
|
|
|
302
|
+
layer_call._chad_fastpath = True # type: ignore[attr-defined]
|
|
273
303
|
q35.DecoderLayer.__call__ = layer_call # type: ignore[method-assign]
|
|
274
304
|
|
|
275
305
|
|
|
@@ -300,14 +330,22 @@ def _moe_body(layer):
|
|
|
300
330
|
sw = mlp.switch_mlp
|
|
301
331
|
ln_w = layer.post_attention_layernorm.weight
|
|
302
332
|
ln_eps = layer.post_attention_layernorm.eps
|
|
303
|
-
gate = mlp.gate
|
|
304
333
|
fw, fs, fb = sw._fused_w, sw._fused_s, sw._fused_b
|
|
305
334
|
sgs, sbits = sw._fused_gs, sw._fused_bits
|
|
306
335
|
dp = sw.down_proj
|
|
307
336
|
se = mlp.shared_expert
|
|
308
|
-
seg = mlp.shared_expert_gate
|
|
309
337
|
k = mlp.top_k
|
|
310
338
|
norm_topk = mlp.norm_topk_prob
|
|
339
|
+
E = mlp.num_experts
|
|
340
|
+
# mlx_moe_fused may have concatenated router|seg and shared gate|up; this
|
|
341
|
+
# body must then read the fused copies (originals are placeholders). Both
|
|
342
|
+
# variants are the same math per row.
|
|
343
|
+
moek = hasattr(mlp, "_rt_w")
|
|
344
|
+
if moek:
|
|
345
|
+
rt = (mlp._rt_w, mlp._rt_s, mlp._rt_b)
|
|
346
|
+
shg = (mlp._sh_w, mlp._sh_s, mlp._sh_b)
|
|
347
|
+
else:
|
|
348
|
+
gate, seg = mlp.gate, mlp.shared_expert_gate
|
|
311
349
|
|
|
312
350
|
def qmm(x, m):
|
|
313
351
|
return mx.quantized_matmul(x, m.weight, scales=m.scales, biases=m.biases,
|
|
@@ -316,7 +354,13 @@ def _moe_body(layer):
|
|
|
316
354
|
|
|
317
355
|
def fwd(h):
|
|
318
356
|
x = mx.fast.rms_norm(h, ln_w, ln_eps)
|
|
319
|
-
|
|
357
|
+
if moek:
|
|
358
|
+
rg = mx.quantized_matmul(x, rt[0], scales=rt[1], biases=rt[2],
|
|
359
|
+
transpose=True, group_size=mlp._rt_gs,
|
|
360
|
+
bits=mlp._rt_bits)
|
|
361
|
+
gates = mx.softmax(rg[..., :E], axis=-1, precise=True)
|
|
362
|
+
else:
|
|
363
|
+
gates = mx.softmax(qmm(x, gate), axis=-1, precise=True)
|
|
320
364
|
inds = mx.argpartition(gates, kth=-k, axis=-1)[..., -k:]
|
|
321
365
|
scores = mx.take_along_axis(gates, inds, axis=-1)
|
|
322
366
|
if norm_topk:
|
|
@@ -329,6 +373,13 @@ def _moe_body(layer):
|
|
|
329
373
|
y = mx.gather_qmm(hh, dp.weight, dp.scales, dp.biases, rhs_indices=inds,
|
|
330
374
|
transpose=True, group_size=dp.group_size, bits=dp.bits)
|
|
331
375
|
y = (y.squeeze(-2) * scores[..., None]).sum(axis=-2)
|
|
376
|
+
if moek:
|
|
377
|
+
sgu = mx.quantized_matmul(x, shg[0], scales=shg[1], biases=shg[2],
|
|
378
|
+
transpose=True, group_size=mlp._sh_gs,
|
|
379
|
+
bits=mlp._sh_bits)
|
|
380
|
+
g, u = mx.split(sgu, 2, axis=-1)
|
|
381
|
+
sh = qmm(nn.silu(g) * u, se.down_proj)
|
|
382
|
+
return h + y + mx.sigmoid(rg[..., E:E + 1]) * sh
|
|
332
383
|
sh = qmm(nn.silu(qmm(x, se.gate_proj)) * qmm(x, se.up_proj), se.down_proj)
|
|
333
384
|
return h + y + mx.sigmoid(qmm(x, seg)) * sh
|
|
334
385
|
|