mlx-code 0.0.3__tar.gz → 0.0.5__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.
- mlx_code-0.0.5/PKG-INFO +274 -0
- mlx_code-0.0.5/README.md +248 -0
- {mlx_code-0.0.3 → mlx_code-0.0.5}/mlx_code/log.py +109 -34
- {mlx_code-0.0.3 → mlx_code-0.0.5}/mlx_code/main.py +10 -10
- {mlx_code-0.0.3 → mlx_code-0.0.5}/mlx_code/pie.py +148 -61
- mlx_code-0.0.5/mlx_code/symgraph.py +419 -0
- mlx_code-0.0.5/mlx_code.egg-info/PKG-INFO +274 -0
- {mlx_code-0.0.3 → mlx_code-0.0.5}/mlx_code.egg-info/SOURCES.txt +1 -0
- {mlx_code-0.0.3 → mlx_code-0.0.5}/mlx_code.egg-info/entry_points.txt +1 -0
- {mlx_code-0.0.3 → mlx_code-0.0.5}/setup.py +2 -2
- mlx_code-0.0.3/PKG-INFO +0 -85
- mlx_code-0.0.3/README.md +0 -59
- mlx_code-0.0.3/mlx_code.egg-info/PKG-INFO +0 -85
- {mlx_code-0.0.3 → mlx_code-0.0.5}/LICENSE +0 -0
- {mlx_code-0.0.3 → mlx_code-0.0.5}/mlx_code/__init__.py +0 -0
- {mlx_code-0.0.3 → mlx_code-0.0.5}/mlx_code.egg-info/dependency_links.txt +0 -0
- {mlx_code-0.0.3 → mlx_code-0.0.5}/mlx_code.egg-info/requires.txt +0 -0
- {mlx_code-0.0.3 → mlx_code-0.0.5}/mlx_code.egg-info/top_level.txt +0 -0
- {mlx_code-0.0.3 → mlx_code-0.0.5}/setup.cfg +0 -0
mlx_code-0.0.5/PKG-INFO
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mlx-code
|
|
3
|
+
Version: 0.0.5
|
|
4
|
+
Summary: Coding Agent for Mac
|
|
5
|
+
Home-page: https://github.com/JosefAlbers/mlx-code
|
|
6
|
+
Author: J Joe
|
|
7
|
+
Author-email: albersj66@gmail.com
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Requires-Python: >=3.12.8
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: mlx-lm>=0.31.3
|
|
13
|
+
Requires-Dist: numpy
|
|
14
|
+
Requires-Dist: httpx
|
|
15
|
+
Requires-Dist: pydantic
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: author-email
|
|
18
|
+
Dynamic: description
|
|
19
|
+
Dynamic: description-content-type
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: license
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
Dynamic: requires-dist
|
|
24
|
+
Dynamic: requires-python
|
|
25
|
+
Dynamic: summary
|
|
26
|
+
|
|
27
|
+
# mlx-code
|
|
28
|
+
|
|
29
|
+
[](https://youtu.be/bizPhrHL1_w)
|
|
30
|
+
|
|
31
|
+
A lightweight, powerful Coding Agent for Mac. Built on top of Apple's MLX framework, `mlx-code` provides fast, local inference with built-in prompt caching and robust tool-calling capabilities.
|
|
32
|
+
|
|
33
|
+
### Features
|
|
34
|
+
|
|
35
|
+
* **Multi-Provider Compatibility**: Seamlessly translates and handles requests formatted for **Claude**, **Gemini**, **Codex**, and **DeepSeek**.
|
|
36
|
+
* **Built-in REPL & Tools**: Comes with `pie`, a fully-featured REPL with tool execution and reasoning token support.
|
|
37
|
+
* **Server Mode**: Easily spin up a local LLM server.
|
|
38
|
+
|
|
39
|
+
### Quick Start
|
|
40
|
+
|
|
41
|
+
Install via pip and launch the agent immediately:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install mlx-code
|
|
45
|
+
mc
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Command Line Interfaces
|
|
49
|
+
|
|
50
|
+
The package installs three primary command-line tools:
|
|
51
|
+
- mc (Main/Server): Launches the local LLM API server (defaults to 127.0.0.1:8000).
|
|
52
|
+
- me (TUI/Harness): Runs the interactive pie chat REPL.
|
|
53
|
+
|
|
54
|
+
### Options
|
|
55
|
+
|
|
56
|
+
You can customize the model, server, and behavior using command-line flags.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Use Gemini CLI as the harness
|
|
60
|
+
mc --harness gemini
|
|
61
|
+
|
|
62
|
+
# Use a custom local LLM backend
|
|
63
|
+
mc --model mlx-community/Qwen3.5-4B-OptiQ-4bit
|
|
64
|
+
|
|
65
|
+
# Use DeepSeek V4 Flash API
|
|
66
|
+
me --deepseek
|
|
67
|
+
|
|
68
|
+
# Run the server only
|
|
69
|
+
mc --nocc
|
|
70
|
+
|
|
71
|
+
# General shell piping and chaining works too
|
|
72
|
+
echo "explain symgraph.py" | mc -d | cat - PLAN.md | mc
|
|
73
|
+
```
|
|
74
|
+
*(For a full list of mc server arguments, run mc --help)*
|
|
75
|
+
|
|
76
|
+
### Credits
|
|
77
|
+
|
|
78
|
+
- `main.py`: Built on [MLX](https://github.com/ml-explore/mlx) and [MLX LM](https://github.com/ml-explore/mlx-lm) by Apple.
|
|
79
|
+
- `pie.py`: Adapted from [pi](https://github.com/badlogic/pi-mono) by Mario Zechner (MIT License).
|
|
80
|
+
|
|
81
|
+
### Licence
|
|
82
|
+
|
|
83
|
+
Apache License 2.0 — see LICENSE for details.
|
|
84
|
+
|
|
85
|
+
<details><summary>...</summary><pre>
|
|
86
|
+
|
|
87
|
+
~/D/tmp> mc
|
|
88
|
+
pie REPL • type /help for commands, Ctrl-D or 'exit' to quit.
|
|
89
|
+
|
|
90
|
+
≫ explain symgraph.py
|
|
91
|
+
π The user wants me to explain symgraph.py. I should first look at the file to understand its contents. Let me use the ReadAST function to inspect this file.
|
|
92
|
+
|
|
93
|
+
ReadAST {"path": "symgraph.py"} This looks like a Python file that defines a graph-based system for analyzing code. Let me get more details about the main components by looking up the key symbols.
|
|
94
|
+
|
|
95
|
+
ReadAST {"path": "symgraph.py", "symbols": "[\"Edge\", \"Graph\", \"DefCollector\", \"TypeInfo\", \"TypeInferrer\", \"EdgeEmitte This is a comprehensive Python file that builds a symbolic graph representation of Python code. Let me provide a clear explanation of what this file does.
|
|
96
|
+
|
|
97
|
+
## Overview
|
|
98
|
+
|
|
99
|
+
`symgraph.py` is a **symbolic graph builder** for Python code that constructs a directed graph representation of Python modules, classes, functions, and their relationships. It uses Python's `ast` (Abstract Syntax Tree) module to analyze code and build a graph where nodes are symbols and edges represent relationships like calls and references.
|
|
100
|
+
|
|
101
|
+
## Key Components
|
|
102
|
+
|
|
103
|
+
### 1. **Edge** (47-60)
|
|
104
|
+
Represents relationships between symbols:
|
|
105
|
+
- `src`, `dst`: source and destination symbols
|
|
106
|
+
- `kind`: "call" or "ref" (call or reference)
|
|
107
|
+
- `via`: optional alias/variable name for indirect references
|
|
108
|
+
|
|
109
|
+
### 2. **Graph** (67-167)
|
|
110
|
+
The main graph structure that stores:
|
|
111
|
+
- `symbols`: list of all discovered symbols
|
|
112
|
+
- `edges`: list of all relationships
|
|
113
|
+
- Internal indexes for efficient lookup (`_sym_by_qname`, `_uses`, `_used_by`)
|
|
114
|
+
|
|
115
|
+
### 3. **DefCollector** (186-238)
|
|
116
|
+
First pass visitor that collects all definitions:
|
|
117
|
+
- Classes, functions, methods, module-level variables
|
|
118
|
+
- Tracks scope (class/function nesting)
|
|
119
|
+
- No type inference, just definition collection
|
|
120
|
+
|
|
121
|
+
### 4. **TypeInferrer** (253-464)
|
|
122
|
+
Second pass that infers types using **fixpoint iteration**:
|
|
123
|
+
- Tracks local variable types per scope
|
|
124
|
+
- Resolves return types from annotations
|
|
125
|
+
- Handles class instances and method calls
|
|
126
|
+
- Uses `ast.NodeVisitor` with proper scope tracking
|
|
127
|
+
|
|
128
|
+
### 5. **EdgeEmitter** (471-700)
|
|
129
|
+
Third pass that emits edges based on type information:
|
|
130
|
+
- Emits "call" edges for function/method calls
|
|
131
|
+
- Emits "ref" edges for variable references
|
|
132
|
+
- Handles `__call__` for class instances
|
|
133
|
+
- Tracks live local variable environments
|
|
134
|
+
|
|
135
|
+
### 6. **build()** (730-755)
|
|
136
|
+
Main entry point that orchestrates the three passes:
|
|
137
|
+
1. Collect definitions
|
|
138
|
+
2. Infer types (fixpoint)
|
|
139
|
+
3. Emit edges
|
|
140
|
+
|
|
141
|
+
### 7. **main()** (762-776)
|
|
142
|
+
CLI interface:
|
|
143
|
+
- `symgraph.py <path>` → outputs all edges as JSON
|
|
144
|
+
- `symgraph.py <path> <query>` → queries for symbols matching a name
|
|
145
|
+
|
|
146
|
+
## How It Works
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
150
|
+
│ Pass 1: DefCollector │
|
|
151
|
+
│ └─ Collects all symbols (classes, functions, variables) │
|
|
152
|
+
└─────────────────────────────────────────────────────────────┘
|
|
153
|
+
↓
|
|
154
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
155
|
+
│ Pass 2: TypeInferrer (fixpoint) │
|
|
156
|
+
│ └─ Infers types, return types, class instances │
|
|
157
|
+
└─────────────────────────────────────────────────────────────┘
|
|
158
|
+
↓
|
|
159
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
160
|
+
│ Pass 3: EdgeEmitter │
|
|
161
|
+
│ └─ Emits call/ref edges based on type info │
|
|
162
|
+
└─────────────────────────────────────────────────────────────┘
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Use Cases
|
|
166
|
+
|
|
167
|
+
This tool is useful for:
|
|
168
|
+
- **Dependency analysis** - understand call graphs and dependencies
|
|
169
|
+
- **Code navigation** - find where symbols are used
|
|
170
|
+
- **Refactoring** - understand impact of changes
|
|
171
|
+
- **Static analysis** - detect unused code, circular dependencies
|
|
172
|
+
|
|
173
|
+
The graph can be queried to find all uses of a symbol, all callers, or all references within a module.
|
|
174
|
+
≫ Add a method to Graph called clear_edges() that resets edges, _edge_keys, _uses, and _used_by to empty.
|
|
175
|
+
π The user wants me to add a `clear_edges()` method to the `Graph` class that resets the edges and related internal structures. I need to:1. Add the method to the Graph class2. Reset `self.edges`, `self._edge_keys`, `self._uses`, and `self._used_by` to emptyLet me first read the Graph class to see its current structure, then add the method.
|
|
176
|
+
|
|
177
|
+
Edit {"path": "symgraph.py", "old_text": "# \u2500\u2500 query \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u The edit was successful. Let me verify the change by reading the updated section of the file to confirm the method was added correctly.
|
|
178
|
+
|
|
179
|
+
ReadAST {"path": "symgraph.py", "symbols": "[\"Graph\"]"} The edit was successful. The `clear_edges()` method has been added to the `Graph` class. It resets:- `self.edges` - the list of edges- `self._edge_keys` - the set of edge keys (to prevent duplicate edges)- `self._uses` - the dictionary tracking which symbols use which edges- `self._used_by` - the dictionary tracking which symbols are used by which edgesThe symbols list is NOT cleared, which makes sense since we want to keep the symbol definitions but just clear the edges.Let me provide a summary of what was added.
|
|
180
|
+
|
|
181
|
+
Done! I've added the `clear_edges()` method to the `Graph` class. Here's what it does:
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
def clear_edges(self) -> None:
|
|
185
|
+
"""Reset all edges and related internal structures."""
|
|
186
|
+
self.edges.clear()
|
|
187
|
+
self._edge_keys.clear()
|
|
188
|
+
self._uses.clear()
|
|
189
|
+
self._used_by.clear()
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
This method:
|
|
193
|
+
- Clears all edges from the graph
|
|
194
|
+
- Resets the edge key set (prevents duplicate edges)
|
|
195
|
+
- Clears the `_uses` mapping (which symbols use which edges)
|
|
196
|
+
- Clears the `_used_by` mapping (which symbols are used by which edges)
|
|
197
|
+
|
|
198
|
+
**Note:** It does NOT clear `self.symbols` or `self._sym_by_qname`, so symbol definitions are preserved while only the edge relationships are reset. This is useful for:
|
|
199
|
+
- Re-running edge emission on the same symbols
|
|
200
|
+
- Building multiple graphs from the same codebase
|
|
201
|
+
- Resetting the graph state without losing collected definitions
|
|
202
|
+
≫ exit
|
|
203
|
+
Bye!
|
|
204
|
+
~/D/tmp> gg *.py
|
|
205
|
+
staging: log.py
|
|
206
|
+
exists
|
|
207
|
+
staging: main.py
|
|
208
|
+
exists
|
|
209
|
+
staging: pie.py
|
|
210
|
+
exists
|
|
211
|
+
staging: symgraph.py
|
|
212
|
+
exists
|
|
213
|
+
|
|
214
|
+
Diff preview:
|
|
215
|
+
Users/jjms/Downloads/tmp/symgraph.py | 7 +++++++
|
|
216
|
+
1 file changed, 7 insertions(+)
|
|
217
|
+
|
|
218
|
+
Show per-file diffs? [s=skip]: s
|
|
219
|
+
|
|
220
|
+
read> symgraph edit by mlx-code
|
|
221
|
+
Saved snapshot 09529bc9bcbc6d1ff761618c982ece9a290f50fb
|
|
222
|
+
|
|
223
|
+
~/D/tmp> md
|
|
224
|
+
|
|
225
|
+
┌─ logs ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐┌─ detail ──────────────────────────────────────────────────────────────────────────┐
|
|
226
|
+
│ TIME LVL FILE FUNC MESSAGE …││ time : 2026-05-05T20:55:26.707364+00:00 │
|
|
227
|
+
│ 20:55:21 INFO main.py main args=Namespace(model='mlx-community/Qwen3.5-4B-OptiQ-4bit', api='de…││ level : INFO │
|
|
228
|
+
│ 20:55:26 INFO pie.py _repl explain symgraph.py ││ logger : root │
|
|
229
|
+
│ 20:55:26 INFO main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ file : tmp/main.py │
|
|
230
|
+
│ 20:55:26 DEBUG main.py translate messages=[Message(role='system', content='You are a helpful assista…││ function : do_POST │
|
|
231
|
+
│ 20:55:26 INFO main.py encode ckpts=[742] <|im_start|>system # Tools You have access to the follo…││ line : 1432 │
|
|
232
|
+
│ 20:55:26 INFO main.py __call__ ckpts=[742] len(prompt)=753 len(self.hx)=0 cl=0 ││ id : bdedc2c5-00a5-49od-9bj9-890a6e2a89b1 │
|
|
233
|
+
│ 20:55:26 DEBUG main.py load cache/mlxcommunityQwen354BOptiQ4bit_742_3bb19df63c78dde8.safetensor…││ │
|
|
234
|
+
│ 20:55:27 DEBUG main.py generate pmt Processed 753 input tokens in 0 seconds (4684 tokens per second…││ ── message ── │
|
|
235
|
+
│ 20:55:27 INFO main.py generate gen The user wants me to explain symgraph.py. I should first look a…││ self.path='/v1/chat/completions' │
|
|
236
|
+
│ 20:55:27 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='The user wants …││ { │
|
|
237
|
+
│ 20:55:27 DEBUG pie.py on_event symgraph.py ─────────────── [C] Symbol (32-43) [C] Edge (47-60) [C…││ "model": "jj", │
|
|
238
|
+
│ 20:55:28 INFO main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ "max_tokens": 8192, │
|
|
239
|
+
│ 20:55:28 DEBUG main.py translate messages=[Message(role='system', content='You are a helpful assista…││ "messages": [ │
|
|
240
|
+
│ 20:55:28 INFO main.py encode ckpts=[742] <|im_start|>system # Tools You have access to the follo…││ { │
|
|
241
|
+
│ 20:55:28 INFO main.py __call__ ckpts=[742] len(prompt)=1015 len(self.hx)=818 cl=818 ││ "role": "system", │
|
|
242
|
+
│ 20:55:28 DEBUG main.py __call__ cont ││ "content": "You are a helpful assistant." │
|
|
243
|
+
│ 20:55:28 DEBUG main.py generate pmt Processed 1015 input tokens in 1 seconds (1761 tokens per secon…││ }, │
|
|
244
|
+
│ 20:55:30 INFO main.py generate gen This looks like a Python file that defines a graph-based system…││ { │
|
|
245
|
+
│ 20:55:30 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='This looks like…││ "role": "user", │
|
|
246
|
+
│ 20:55:30 DEBUG pie.py on_event # DEF class symgraph.Edge /private/var/folders/_5/vz_p3mls23l5rtlhj…││ "content": "explain symgraph.py" │
|
|
247
|
+
│ 20:55:30 INFO main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ } │
|
|
248
|
+
│ 20:55:30 DEBUG main.py translate messages=[Message(role='system', content='You are a helpful assista…││ ], │
|
|
249
|
+
│ 20:55:30 INFO main.py encode ckpts=[742] <|im_start|>system # Tools You have access to the follo…││ "stream": true, │
|
|
250
|
+
│ 20:55:30 INFO main.py __call__ ckpts=[742] len(prompt)=12781 len(self.hx)=1117 cl=1117 ││ "tools": [ │
|
|
251
|
+
│ 20:55:30 DEBUG main.py __call__ cont ││ { │
|
|
252
|
+
│ 20:55:58 DEBUG main.py generate pmt Processed 12781 input tokens in 28 seconds (454 tokens per seco…││ "type": "function", │
|
|
253
|
+
│ 20:56:11 INFO main.py generate gen This is a comprehensive Python file that builds a symbolic grap…││ "function": { │
|
|
254
|
+
│ 20:56:11 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='This is a compr…││ "name": "Read", │
|
|
255
|
+
│ 20:56:25 INFO pie.py _repl Add a method to Graph called clear_edges() that resets edges, _edge…││ "description": "Read a file. Use offset/limit for large files instead of │
|
|
256
|
+
│ 20:56:25 INFO main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ reading the whole thing.", │
|
|
257
|
+
│ 20:56:25 DEBUG main.py translate messages=[Message(role='system', content='You are a helpful assista…││ "parameters": { │
|
|
258
|
+
│ 20:56:25 INFO main.py encode ckpts=[742, 13481] <|im_start|>system # Tools You have access to th…││ "type": "object", │
|
|
259
|
+
│ 20:56:25 INFO main.py __call__ ckpts=[13481, 742] len(prompt)=13515 len(self.hx)=13586 cl=751 ││ "properties": { │
|
|
260
|
+
│ 20:56:25 DEBUG main.py load cache/mlxcommunityQwen354BOptiQ4bit_742_3bb19df63c78dde8.safetensor…││ "path": { │
|
|
261
|
+
│ 20:56:25 DEBUG main.py generate save_fn 13481 ││ "description": "File path to read (relative to cwd)", │
|
|
262
|
+
│ 20:56:56 DEBUG main.py generate pmt Processed 13515 input tokens in 31 seconds (438 tokens per seco…││ "title": "Path", │
|
|
263
|
+
│ 20:57:00 INFO main.py generate gen The user wants me to add a `clear_edges()` method to the `Graph…││ "type": "string" │
|
|
264
|
+
│ 20:57:00 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='The user wants …││ }, │
|
|
265
|
+
│ 20:57:00 DEBUG pie.py on_event edited symgraph.py: replaced 3 line(s) with 10 line(s) ││ "offset": { │
|
|
266
|
+
│ 20:57:00 INFO main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ "anyOf": [ │
|
|
267
|
+
│ 20:57:00 DEBUG main.py translate messages=[Message(role='system', content='You are a helpful assista…││ { │
|
|
268
|
+
│ 20:57:00 INFO main.py encode ckpts=[742, 13481] <|im_start|>system # Tools You have access to th…││ "type": "integer" │
|
|
269
|
+
│ 20:57:00 INFO main.py __call__ ckpts=[13481, 742] len(prompt)=13801 len(self.hx)=13768 cl=13768 ││ }, │
|
|
270
|
+
│ 20:57:00 DEBUG main.py __call__ cont ││ { │
|
|
271
|
+
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘└───────────────────────────────────────────────────────────────────────────────────┘
|
|
272
|
+
All bdedc2c5-0 8j7j3o1e-6
|
|
273
|
+
log.json │ 3/58 (of 172) filter: lvl:10;file:main,pie │ ↑/k ↓/j · PgUp/PgDn · g/G · n/N · * highlight · o open · ; filter · h/l tabs · q quit
|
|
274
|
+
</pre></details><br>
|
mlx_code-0.0.5/README.md
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# mlx-code
|
|
2
|
+
|
|
3
|
+
[](https://youtu.be/bizPhrHL1_w)
|
|
4
|
+
|
|
5
|
+
A lightweight, powerful Coding Agent for Mac. Built on top of Apple's MLX framework, `mlx-code` provides fast, local inference with built-in prompt caching and robust tool-calling capabilities.
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* **Multi-Provider Compatibility**: Seamlessly translates and handles requests formatted for **Claude**, **Gemini**, **Codex**, and **DeepSeek**.
|
|
10
|
+
* **Built-in REPL & Tools**: Comes with `pie`, a fully-featured REPL with tool execution and reasoning token support.
|
|
11
|
+
* **Server Mode**: Easily spin up a local LLM server.
|
|
12
|
+
|
|
13
|
+
### Quick Start
|
|
14
|
+
|
|
15
|
+
Install via pip and launch the agent immediately:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install mlx-code
|
|
19
|
+
mc
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Command Line Interfaces
|
|
23
|
+
|
|
24
|
+
The package installs three primary command-line tools:
|
|
25
|
+
- mc (Main/Server): Launches the local LLM API server (defaults to 127.0.0.1:8000).
|
|
26
|
+
- me (TUI/Harness): Runs the interactive pie chat REPL.
|
|
27
|
+
|
|
28
|
+
### Options
|
|
29
|
+
|
|
30
|
+
You can customize the model, server, and behavior using command-line flags.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Use Gemini CLI as the harness
|
|
34
|
+
mc --harness gemini
|
|
35
|
+
|
|
36
|
+
# Use a custom local LLM backend
|
|
37
|
+
mc --model mlx-community/Qwen3.5-4B-OptiQ-4bit
|
|
38
|
+
|
|
39
|
+
# Use DeepSeek V4 Flash API
|
|
40
|
+
me --deepseek
|
|
41
|
+
|
|
42
|
+
# Run the server only
|
|
43
|
+
mc --nocc
|
|
44
|
+
|
|
45
|
+
# General shell piping and chaining works too
|
|
46
|
+
echo "explain symgraph.py" | mc -d | cat - PLAN.md | mc
|
|
47
|
+
```
|
|
48
|
+
*(For a full list of mc server arguments, run mc --help)*
|
|
49
|
+
|
|
50
|
+
### Credits
|
|
51
|
+
|
|
52
|
+
- `main.py`: Built on [MLX](https://github.com/ml-explore/mlx) and [MLX LM](https://github.com/ml-explore/mlx-lm) by Apple.
|
|
53
|
+
- `pie.py`: Adapted from [pi](https://github.com/badlogic/pi-mono) by Mario Zechner (MIT License).
|
|
54
|
+
|
|
55
|
+
### Licence
|
|
56
|
+
|
|
57
|
+
Apache License 2.0 — see LICENSE for details.
|
|
58
|
+
|
|
59
|
+
<details><summary>...</summary><pre>
|
|
60
|
+
|
|
61
|
+
~/D/tmp> mc
|
|
62
|
+
pie REPL • type /help for commands, Ctrl-D or 'exit' to quit.
|
|
63
|
+
|
|
64
|
+
≫ explain symgraph.py
|
|
65
|
+
π The user wants me to explain symgraph.py. I should first look at the file to understand its contents. Let me use the ReadAST function to inspect this file.
|
|
66
|
+
|
|
67
|
+
ReadAST {"path": "symgraph.py"} This looks like a Python file that defines a graph-based system for analyzing code. Let me get more details about the main components by looking up the key symbols.
|
|
68
|
+
|
|
69
|
+
ReadAST {"path": "symgraph.py", "symbols": "[\"Edge\", \"Graph\", \"DefCollector\", \"TypeInfo\", \"TypeInferrer\", \"EdgeEmitte This is a comprehensive Python file that builds a symbolic graph representation of Python code. Let me provide a clear explanation of what this file does.
|
|
70
|
+
|
|
71
|
+
## Overview
|
|
72
|
+
|
|
73
|
+
`symgraph.py` is a **symbolic graph builder** for Python code that constructs a directed graph representation of Python modules, classes, functions, and their relationships. It uses Python's `ast` (Abstract Syntax Tree) module to analyze code and build a graph where nodes are symbols and edges represent relationships like calls and references.
|
|
74
|
+
|
|
75
|
+
## Key Components
|
|
76
|
+
|
|
77
|
+
### 1. **Edge** (47-60)
|
|
78
|
+
Represents relationships between symbols:
|
|
79
|
+
- `src`, `dst`: source and destination symbols
|
|
80
|
+
- `kind`: "call" or "ref" (call or reference)
|
|
81
|
+
- `via`: optional alias/variable name for indirect references
|
|
82
|
+
|
|
83
|
+
### 2. **Graph** (67-167)
|
|
84
|
+
The main graph structure that stores:
|
|
85
|
+
- `symbols`: list of all discovered symbols
|
|
86
|
+
- `edges`: list of all relationships
|
|
87
|
+
- Internal indexes for efficient lookup (`_sym_by_qname`, `_uses`, `_used_by`)
|
|
88
|
+
|
|
89
|
+
### 3. **DefCollector** (186-238)
|
|
90
|
+
First pass visitor that collects all definitions:
|
|
91
|
+
- Classes, functions, methods, module-level variables
|
|
92
|
+
- Tracks scope (class/function nesting)
|
|
93
|
+
- No type inference, just definition collection
|
|
94
|
+
|
|
95
|
+
### 4. **TypeInferrer** (253-464)
|
|
96
|
+
Second pass that infers types using **fixpoint iteration**:
|
|
97
|
+
- Tracks local variable types per scope
|
|
98
|
+
- Resolves return types from annotations
|
|
99
|
+
- Handles class instances and method calls
|
|
100
|
+
- Uses `ast.NodeVisitor` with proper scope tracking
|
|
101
|
+
|
|
102
|
+
### 5. **EdgeEmitter** (471-700)
|
|
103
|
+
Third pass that emits edges based on type information:
|
|
104
|
+
- Emits "call" edges for function/method calls
|
|
105
|
+
- Emits "ref" edges for variable references
|
|
106
|
+
- Handles `__call__` for class instances
|
|
107
|
+
- Tracks live local variable environments
|
|
108
|
+
|
|
109
|
+
### 6. **build()** (730-755)
|
|
110
|
+
Main entry point that orchestrates the three passes:
|
|
111
|
+
1. Collect definitions
|
|
112
|
+
2. Infer types (fixpoint)
|
|
113
|
+
3. Emit edges
|
|
114
|
+
|
|
115
|
+
### 7. **main()** (762-776)
|
|
116
|
+
CLI interface:
|
|
117
|
+
- `symgraph.py <path>` → outputs all edges as JSON
|
|
118
|
+
- `symgraph.py <path> <query>` → queries for symbols matching a name
|
|
119
|
+
|
|
120
|
+
## How It Works
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
124
|
+
│ Pass 1: DefCollector │
|
|
125
|
+
│ └─ Collects all symbols (classes, functions, variables) │
|
|
126
|
+
└─────────────────────────────────────────────────────────────┘
|
|
127
|
+
↓
|
|
128
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
129
|
+
│ Pass 2: TypeInferrer (fixpoint) │
|
|
130
|
+
│ └─ Infers types, return types, class instances │
|
|
131
|
+
└─────────────────────────────────────────────────────────────┘
|
|
132
|
+
↓
|
|
133
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
134
|
+
│ Pass 3: EdgeEmitter │
|
|
135
|
+
│ └─ Emits call/ref edges based on type info │
|
|
136
|
+
└─────────────────────────────────────────────────────────────┘
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Use Cases
|
|
140
|
+
|
|
141
|
+
This tool is useful for:
|
|
142
|
+
- **Dependency analysis** - understand call graphs and dependencies
|
|
143
|
+
- **Code navigation** - find where symbols are used
|
|
144
|
+
- **Refactoring** - understand impact of changes
|
|
145
|
+
- **Static analysis** - detect unused code, circular dependencies
|
|
146
|
+
|
|
147
|
+
The graph can be queried to find all uses of a symbol, all callers, or all references within a module.
|
|
148
|
+
≫ Add a method to Graph called clear_edges() that resets edges, _edge_keys, _uses, and _used_by to empty.
|
|
149
|
+
π The user wants me to add a `clear_edges()` method to the `Graph` class that resets the edges and related internal structures. I need to:1. Add the method to the Graph class2. Reset `self.edges`, `self._edge_keys`, `self._uses`, and `self._used_by` to emptyLet me first read the Graph class to see its current structure, then add the method.
|
|
150
|
+
|
|
151
|
+
Edit {"path": "symgraph.py", "old_text": "# \u2500\u2500 query \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u The edit was successful. Let me verify the change by reading the updated section of the file to confirm the method was added correctly.
|
|
152
|
+
|
|
153
|
+
ReadAST {"path": "symgraph.py", "symbols": "[\"Graph\"]"} The edit was successful. The `clear_edges()` method has been added to the `Graph` class. It resets:- `self.edges` - the list of edges- `self._edge_keys` - the set of edge keys (to prevent duplicate edges)- `self._uses` - the dictionary tracking which symbols use which edges- `self._used_by` - the dictionary tracking which symbols are used by which edgesThe symbols list is NOT cleared, which makes sense since we want to keep the symbol definitions but just clear the edges.Let me provide a summary of what was added.
|
|
154
|
+
|
|
155
|
+
Done! I've added the `clear_edges()` method to the `Graph` class. Here's what it does:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
def clear_edges(self) -> None:
|
|
159
|
+
"""Reset all edges and related internal structures."""
|
|
160
|
+
self.edges.clear()
|
|
161
|
+
self._edge_keys.clear()
|
|
162
|
+
self._uses.clear()
|
|
163
|
+
self._used_by.clear()
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
This method:
|
|
167
|
+
- Clears all edges from the graph
|
|
168
|
+
- Resets the edge key set (prevents duplicate edges)
|
|
169
|
+
- Clears the `_uses` mapping (which symbols use which edges)
|
|
170
|
+
- Clears the `_used_by` mapping (which symbols are used by which edges)
|
|
171
|
+
|
|
172
|
+
**Note:** It does NOT clear `self.symbols` or `self._sym_by_qname`, so symbol definitions are preserved while only the edge relationships are reset. This is useful for:
|
|
173
|
+
- Re-running edge emission on the same symbols
|
|
174
|
+
- Building multiple graphs from the same codebase
|
|
175
|
+
- Resetting the graph state without losing collected definitions
|
|
176
|
+
≫ exit
|
|
177
|
+
Bye!
|
|
178
|
+
~/D/tmp> gg *.py
|
|
179
|
+
staging: log.py
|
|
180
|
+
exists
|
|
181
|
+
staging: main.py
|
|
182
|
+
exists
|
|
183
|
+
staging: pie.py
|
|
184
|
+
exists
|
|
185
|
+
staging: symgraph.py
|
|
186
|
+
exists
|
|
187
|
+
|
|
188
|
+
Diff preview:
|
|
189
|
+
Users/jjms/Downloads/tmp/symgraph.py | 7 +++++++
|
|
190
|
+
1 file changed, 7 insertions(+)
|
|
191
|
+
|
|
192
|
+
Show per-file diffs? [s=skip]: s
|
|
193
|
+
|
|
194
|
+
read> symgraph edit by mlx-code
|
|
195
|
+
Saved snapshot 09529bc9bcbc6d1ff761618c982ece9a290f50fb
|
|
196
|
+
|
|
197
|
+
~/D/tmp> md
|
|
198
|
+
|
|
199
|
+
┌─ logs ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐┌─ detail ──────────────────────────────────────────────────────────────────────────┐
|
|
200
|
+
│ TIME LVL FILE FUNC MESSAGE …││ time : 2026-05-05T20:55:26.707364+00:00 │
|
|
201
|
+
│ 20:55:21 INFO main.py main args=Namespace(model='mlx-community/Qwen3.5-4B-OptiQ-4bit', api='de…││ level : INFO │
|
|
202
|
+
│ 20:55:26 INFO pie.py _repl explain symgraph.py ││ logger : root │
|
|
203
|
+
│ 20:55:26 INFO main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ file : tmp/main.py │
|
|
204
|
+
│ 20:55:26 DEBUG main.py translate messages=[Message(role='system', content='You are a helpful assista…││ function : do_POST │
|
|
205
|
+
│ 20:55:26 INFO main.py encode ckpts=[742] <|im_start|>system # Tools You have access to the follo…││ line : 1432 │
|
|
206
|
+
│ 20:55:26 INFO main.py __call__ ckpts=[742] len(prompt)=753 len(self.hx)=0 cl=0 ││ id : bdedc2c5-00a5-49od-9bj9-890a6e2a89b1 │
|
|
207
|
+
│ 20:55:26 DEBUG main.py load cache/mlxcommunityQwen354BOptiQ4bit_742_3bb19df63c78dde8.safetensor…││ │
|
|
208
|
+
│ 20:55:27 DEBUG main.py generate pmt Processed 753 input tokens in 0 seconds (4684 tokens per second…││ ── message ── │
|
|
209
|
+
│ 20:55:27 INFO main.py generate gen The user wants me to explain symgraph.py. I should first look a…││ self.path='/v1/chat/completions' │
|
|
210
|
+
│ 20:55:27 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='The user wants …││ { │
|
|
211
|
+
│ 20:55:27 DEBUG pie.py on_event symgraph.py ─────────────── [C] Symbol (32-43) [C] Edge (47-60) [C…││ "model": "jj", │
|
|
212
|
+
│ 20:55:28 INFO main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ "max_tokens": 8192, │
|
|
213
|
+
│ 20:55:28 DEBUG main.py translate messages=[Message(role='system', content='You are a helpful assista…││ "messages": [ │
|
|
214
|
+
│ 20:55:28 INFO main.py encode ckpts=[742] <|im_start|>system # Tools You have access to the follo…││ { │
|
|
215
|
+
│ 20:55:28 INFO main.py __call__ ckpts=[742] len(prompt)=1015 len(self.hx)=818 cl=818 ││ "role": "system", │
|
|
216
|
+
│ 20:55:28 DEBUG main.py __call__ cont ││ "content": "You are a helpful assistant." │
|
|
217
|
+
│ 20:55:28 DEBUG main.py generate pmt Processed 1015 input tokens in 1 seconds (1761 tokens per secon…││ }, │
|
|
218
|
+
│ 20:55:30 INFO main.py generate gen This looks like a Python file that defines a graph-based system…││ { │
|
|
219
|
+
│ 20:55:30 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='This looks like…││ "role": "user", │
|
|
220
|
+
│ 20:55:30 DEBUG pie.py on_event # DEF class symgraph.Edge /private/var/folders/_5/vz_p3mls23l5rtlhj…││ "content": "explain symgraph.py" │
|
|
221
|
+
│ 20:55:30 INFO main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ } │
|
|
222
|
+
│ 20:55:30 DEBUG main.py translate messages=[Message(role='system', content='You are a helpful assista…││ ], │
|
|
223
|
+
│ 20:55:30 INFO main.py encode ckpts=[742] <|im_start|>system # Tools You have access to the follo…││ "stream": true, │
|
|
224
|
+
│ 20:55:30 INFO main.py __call__ ckpts=[742] len(prompt)=12781 len(self.hx)=1117 cl=1117 ││ "tools": [ │
|
|
225
|
+
│ 20:55:30 DEBUG main.py __call__ cont ││ { │
|
|
226
|
+
│ 20:55:58 DEBUG main.py generate pmt Processed 12781 input tokens in 28 seconds (454 tokens per seco…││ "type": "function", │
|
|
227
|
+
│ 20:56:11 INFO main.py generate gen This is a comprehensive Python file that builds a symbolic grap…││ "function": { │
|
|
228
|
+
│ 20:56:11 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='This is a compr…││ "name": "Read", │
|
|
229
|
+
│ 20:56:25 INFO pie.py _repl Add a method to Graph called clear_edges() that resets edges, _edge…││ "description": "Read a file. Use offset/limit for large files instead of │
|
|
230
|
+
│ 20:56:25 INFO main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ reading the whole thing.", │
|
|
231
|
+
│ 20:56:25 DEBUG main.py translate messages=[Message(role='system', content='You are a helpful assista…││ "parameters": { │
|
|
232
|
+
│ 20:56:25 INFO main.py encode ckpts=[742, 13481] <|im_start|>system # Tools You have access to th…││ "type": "object", │
|
|
233
|
+
│ 20:56:25 INFO main.py __call__ ckpts=[13481, 742] len(prompt)=13515 len(self.hx)=13586 cl=751 ││ "properties": { │
|
|
234
|
+
│ 20:56:25 DEBUG main.py load cache/mlxcommunityQwen354BOptiQ4bit_742_3bb19df63c78dde8.safetensor…││ "path": { │
|
|
235
|
+
│ 20:56:25 DEBUG main.py generate save_fn 13481 ││ "description": "File path to read (relative to cwd)", │
|
|
236
|
+
│ 20:56:56 DEBUG main.py generate pmt Processed 13515 input tokens in 31 seconds (438 tokens per seco…││ "title": "Path", │
|
|
237
|
+
│ 20:57:00 INFO main.py generate gen The user wants me to add a `clear_edges()` method to the `Graph…││ "type": "string" │
|
|
238
|
+
│ 20:57:00 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='The user wants …││ }, │
|
|
239
|
+
│ 20:57:00 DEBUG pie.py on_event edited symgraph.py: replaced 3 line(s) with 10 line(s) ││ "offset": { │
|
|
240
|
+
│ 20:57:00 INFO main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ "anyOf": [ │
|
|
241
|
+
│ 20:57:00 DEBUG main.py translate messages=[Message(role='system', content='You are a helpful assista…││ { │
|
|
242
|
+
│ 20:57:00 INFO main.py encode ckpts=[742, 13481] <|im_start|>system # Tools You have access to th…││ "type": "integer" │
|
|
243
|
+
│ 20:57:00 INFO main.py __call__ ckpts=[13481, 742] len(prompt)=13801 len(self.hx)=13768 cl=13768 ││ }, │
|
|
244
|
+
│ 20:57:00 DEBUG main.py __call__ cont ││ { │
|
|
245
|
+
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘└───────────────────────────────────────────────────────────────────────────────────┘
|
|
246
|
+
All bdedc2c5-0 8j7j3o1e-6
|
|
247
|
+
log.json │ 3/58 (of 172) filter: lvl:10;file:main,pie │ ↑/k ↓/j · PgUp/PgDn · g/G · n/N · * highlight · o open · ; filter · h/l tabs · q quit
|
|
248
|
+
</pre></details><br>
|