mlx-code 0.0.3__tar.gz → 0.0.4__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mlx-code
3
- Version: 0.0.3
3
+ Version: 0.0.4
4
4
  Summary: Coding Agent for Mac
5
5
  Home-page: https://github.com/JosefAlbers/mlx-code
6
6
  Author: J Joe
@@ -35,7 +35,7 @@ It features a multi-provider local server, a terminal-based chat REPL, and a ded
35
35
  ### Features
36
36
 
37
37
  * **Local MLX Inference**: Powered by `mlx-lm` for optimized performance on Apple Silicon. Includes intelligent prompt caching.
38
- * **Multi-Provider Compatibility**: Seamlessly translates and handles requests formatted for Claude, Gemini, Codex, and standard OpenAI APIs.
38
+ * **Multi-Provider Compatibility**: Seamlessly translates and handles requests formatted for **Claude**, **Gemini**, **Codex**, **DeepSeek** and standard OpenAI APIs.
39
39
  * **Built-in REPL & Tools**: Comes with `pie`, a fully-featured chat REPL with tool execution and reasoning token support.
40
40
  * **TUI Log Viewer**: Includes a Curses-based Terminal UI for filtering, inspecting, and tracking JSON logs in real-time.
41
41
  * **Server Mode**: Easily spin up a local server compatible with standard LLM tooling.
@@ -70,8 +70,11 @@ mc --model mlx-community/Qwen3.5-4B-OptiQ-4bit
70
70
  # Use DeepSeek V4 Flash API
71
71
  me --deepseek
72
72
 
73
- # Run the server only on a custom port
74
- mc --nocc --port 8080
73
+ # Run the server only
74
+ mc --nocc
75
+
76
+ # General shell piping and chaining works too
77
+ echo "explain symgraph.py" | mc | cat - PLAN.md | mc
75
78
  ```
76
79
  *(For a full list of mc server arguments, run mc --help)*
77
80
 
@@ -9,7 +9,7 @@ It features a multi-provider local server, a terminal-based chat REPL, and a ded
9
9
  ### Features
10
10
 
11
11
  * **Local MLX Inference**: Powered by `mlx-lm` for optimized performance on Apple Silicon. Includes intelligent prompt caching.
12
- * **Multi-Provider Compatibility**: Seamlessly translates and handles requests formatted for Claude, Gemini, Codex, and standard OpenAI APIs.
12
+ * **Multi-Provider Compatibility**: Seamlessly translates and handles requests formatted for **Claude**, **Gemini**, **Codex**, **DeepSeek** and standard OpenAI APIs.
13
13
  * **Built-in REPL & Tools**: Comes with `pie`, a fully-featured chat REPL with tool execution and reasoning token support.
14
14
  * **TUI Log Viewer**: Includes a Curses-based Terminal UI for filtering, inspecting, and tracking JSON logs in real-time.
15
15
  * **Server Mode**: Easily spin up a local server compatible with standard LLM tooling.
@@ -44,8 +44,11 @@ mc --model mlx-community/Qwen3.5-4B-OptiQ-4bit
44
44
  # Use DeepSeek V4 Flash API
45
45
  me --deepseek
46
46
 
47
- # Run the server only on a custom port
48
- mc --nocc --port 8080
47
+ # Run the server only
48
+ mc --nocc
49
+
50
+ # General shell piping and chaining works too
51
+ echo "explain symgraph.py" | mc | cat - PLAN.md | mc
49
52
  ```
50
53
  *(For a full list of mc server arguments, run mc --help)*
51
54
 
@@ -335,7 +335,7 @@ def parse_default(body: dict) -> tuple[list[Tool], list[Message]]:
335
335
  for b in content:
336
336
  btype = b.get("type")
337
337
  if btype == "thinking":
338
- thinking_parts.append(b.get("thinking") or b.get("text", ""))
338
+ thinking_parts.append(b.get("thinking") or b.get("reasoning_content") or b.get("text", ""))
339
339
  elif btype == "text":
340
340
  text_parts.append(b.get("text", ""))
341
341
  return "\n".join(text_parts), "\n".join(thinking_parts)
@@ -355,7 +355,7 @@ def parse_default(body: dict) -> tuple[list[Tool], list[Message]]:
355
355
  messages.append(Message(
356
356
  role="assistant",
357
357
  content=text or None,
358
- thinking=thinking or m.get("thinking") or None,
358
+ thinking=thinking or m.get("reasoning_content") or m.get("thinking") or None,
359
359
  tool_calls=[
360
360
  ToolCall(tc["id"], tc["function"]["name"], _safe_json(tc["function"]["arguments"]))
361
361
  for tc in m["tool_calls"]
@@ -367,7 +367,7 @@ def parse_default(body: dict) -> tuple[list[Tool], list[Message]]:
367
367
  messages.append(Message(
368
368
  role=role,
369
369
  content=text or None,
370
- thinking=thinking or m.get("thinking") or None,
370
+ thinking=thinking or m.get("reasoning_content") or m.get("thinking") or None,
371
371
  ))
372
372
 
373
373
  return tools, messages
@@ -1111,7 +1111,7 @@ class DefaultAdapter(BaseAdapter):
1111
1111
  if not text:
1112
1112
  return b""
1113
1113
  if state == "thinking":
1114
- return self.chunk({"thinking": text})
1114
+ return self.chunk({"reasoning_content": text})
1115
1115
  return self.chunk({"content": text})
1116
1116
 
1117
1117
  def tool(self, tool):
@@ -516,7 +516,7 @@ class DefaultChat:
516
516
  if text_parts:
517
517
  msg["content"] = "".join(b.text for b in text_parts)
518
518
  if thinking_parts:
519
- msg["thinking"] = "".join(b.thinking for b in thinking_parts)
519
+ msg["reasoning_content"] = "".join(b.thinking for b in thinking_parts)
520
520
  if tool_calls:
521
521
  msg["tool_calls"] = [
522
522
  {"id": tc.id, "type": "function",
@@ -585,7 +585,7 @@ class DefaultChat:
585
585
  msg = AssistantMessage()
586
586
  try:
587
587
  async with httpx.AsyncClient(timeout=120.0) as client:
588
- async with client.stream("POST", f"{self.base_url}/chat/completions", json=payload, headers=headers) as resp:
588
+ async with client.stream("POST", f"{self.base_url}/v1/chat/completions", json=payload, headers=headers) as resp:
589
589
  if resp.status_code >= 400:
590
590
  body = await resp.aread()
591
591
  raise RuntimeError(f"HTTP {resp.status_code}: {body.decode()}")
@@ -610,10 +610,10 @@ class DefaultChat:
610
610
  delta = choice.get("delta", {})
611
611
  finish_reason = choice.get("finish_reason") or finish_reason
612
612
 
613
- if delta.get("thinking"):
614
- text = delta["thinking"]
615
- _thinking_buf += text
616
- es.push(Event("thinking_delta", {"delta": text, "partial": msg}))
613
+ reasoning = delta.get("reasoning_content") or delta.get("thinking")
614
+ if reasoning:
615
+ _thinking_buf += reasoning
616
+ es.push(Event("thinking_delta", {"delta": reasoning, "partial": msg}))
617
617
 
618
618
  if delta.get("content"):
619
619
  text = delta["content"]
@@ -1986,11 +1986,18 @@ async def _repl(
1986
1986
  agent = Agent(api, system=system, tools=available_tools)
1987
1987
  loop = asyncio.get_running_loop()
1988
1988
  _suppress = False
1989
+ last_ev_type = ""
1990
+ last_delta = ""
1989
1991
  async def on_event(event: AgentEvent) -> None:
1990
1992
  # logger.debug(event) # □
1991
- nonlocal _suppress, is_tty
1993
+ nonlocal _suppress, is_tty, last_ev_type, last_delta
1992
1994
  if event.type == "text_delta":
1993
1995
  delta = event.payload.get("delta", "")
1996
+
1997
+ if last_ev_type and last_ev_type[:4] != event.type[:4] and last_delta and not last_delta[-1].isspace() and delta and not delta[0].isspace():
1998
+ print()
1999
+ last_delta = delta
2000
+ last_ev_type = event.type
1994
2001
  if "<tool_call>" in delta:
1995
2002
  before, _, _ = delta.partition("<tool_call>")
1996
2003
  print(before.strip(), end="", flush=True)
@@ -2004,10 +2011,19 @@ async def _repl(
2004
2011
  elif is_tty:
2005
2012
  if event.type == "thinking_delta":
2006
2013
  delta = event.payload.get("delta", "")
2014
+ if last_ev_type and last_ev_type[:4] != event.type[:4] and last_delta and not last_delta[-1].isspace() and delta and not delta[0].isspace():
2015
+ print()
2016
+ last_delta = delta
2017
+ last_ev_type = event.type
2007
2018
  if delta.strip():
2008
2019
  print(f"\033[2m{delta}\033[0m", end="", flush=True)
2009
2020
  elif event.type == "tool_start":
2010
- print(f"\033[33m{event.payload['name']}:\033[0m {json.dumps(event.payload['args'])[:120]}\n", flush=True)
2021
+ delta = f"\033[33m{event.payload['name']}:\033[0m {json.dumps(event.payload['args'])[:120]}\n"
2022
+ if last_ev_type and last_ev_type[:4] != event.type[:4] and last_delta and not last_delta[-1].isspace() and delta and not delta[0].isspace():
2023
+ print()
2024
+ last_delta = delta
2025
+ last_ev_type = event.type
2026
+ print(delta, flush=True)
2011
2027
  elif event.type == "tool_result":
2012
2028
  msg = event.payload["message"]
2013
2029
  raw = "\n".join(b.text for b in msg.content if isinstance(b, TextContent))
@@ -2015,10 +2031,10 @@ async def _repl(
2015
2031
  # print(f"\n\n\033[36m{raw[:200]}\033[0m\n", end="", flush=True) # □
2016
2032
  elif event.type == "tool_end":
2017
2033
  if event.payload.get("is_error"):
2018
- print(" \033[31m(error)\033[0m", end="", flush=True)
2034
+ print(" \033[31m(error)\033[0m", flush=True)
2019
2035
  elif event.type == "error":
2020
2036
  err = event.payload.get("error")
2021
- print(f"\n\033[31m[error]\033[0m {getattr(err, 'error_message', str(err))}")
2037
+ print(f"\n\033[31m[error]\033[0m {getattr(err, 'error_message', str(err))}\n")
2022
2038
 
2023
2039
  agent.subscribe(on_event)
2024
2040
  if is_tty:
@@ -2037,6 +2053,8 @@ async def _repl(
2037
2053
  if not user_input:
2038
2054
  continue
2039
2055
 
2056
+ last_delta = ""
2057
+ last_ev_type = ""
2040
2058
  logger.info(user_input)
2041
2059
 
2042
2060
  if user_input.startswith("/"):
@@ -2108,7 +2126,7 @@ def run_repl(
2108
2126
  elif provider == "codex":
2109
2127
  api = CodexChat(model=model, api_key=os.environ.get("OPENAI_API_KEY") if api_key is None else api_key, base_url=f'{base_url}/v1' if base_url else "https://api.openai.com/v1")
2110
2128
  else:
2111
- api = DefaultChat(model=model, api_key="mp" if api_key is None else api_key, base_url=f'{base_url}/v1' if base_url else "https://api.openai.com/v1")
2129
+ api = DefaultChat(model=model, api_key="mp" if api_key is None else api_key, base_url=base_url if base_url else "https://api.openai.com/v1")
2112
2130
 
2113
2131
  try:
2114
2132
  asyncio.run(_repl(api, system=system, cwd=cwd, tools=tools))
@@ -2132,7 +2150,7 @@ def main():
2132
2150
  if args.simulate:
2133
2151
  asyncio.run(simulate())
2134
2152
  elif args.deepseek:
2135
- run_repl(base_url="https://api.deepseek.com/anthropic", model="deepseek-v4-flash", provider="claude", api_key=os.environ.get('DEEPSEEK_API_KEY'))
2153
+ run_repl(base_url="https://api.deepseek.com", model="deepseek-v4-flash", provider="default", api_key=os.environ.get('DEEPSEEK_API_KEY'))
2136
2154
  else:
2137
2155
  run_repl(
2138
2156
  model=args.model,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mlx-code
3
- Version: 0.0.3
3
+ Version: 0.0.4
4
4
  Summary: Coding Agent for Mac
5
5
  Home-page: https://github.com/JosefAlbers/mlx-code
6
6
  Author: J Joe
@@ -35,7 +35,7 @@ It features a multi-provider local server, a terminal-based chat REPL, and a ded
35
35
  ### Features
36
36
 
37
37
  * **Local MLX Inference**: Powered by `mlx-lm` for optimized performance on Apple Silicon. Includes intelligent prompt caching.
38
- * **Multi-Provider Compatibility**: Seamlessly translates and handles requests formatted for Claude, Gemini, Codex, and standard OpenAI APIs.
38
+ * **Multi-Provider Compatibility**: Seamlessly translates and handles requests formatted for **Claude**, **Gemini**, **Codex**, **DeepSeek** and standard OpenAI APIs.
39
39
  * **Built-in REPL & Tools**: Comes with `pie`, a fully-featured chat REPL with tool execution and reasoning token support.
40
40
  * **TUI Log Viewer**: Includes a Curses-based Terminal UI for filtering, inspecting, and tracking JSON logs in real-time.
41
41
  * **Server Mode**: Easily spin up a local server compatible with standard LLM tooling.
@@ -70,8 +70,11 @@ mc --model mlx-community/Qwen3.5-4B-OptiQ-4bit
70
70
  # Use DeepSeek V4 Flash API
71
71
  me --deepseek
72
72
 
73
- # Run the server only on a custom port
74
- mc --nocc --port 8080
73
+ # Run the server only
74
+ mc --nocc
75
+
76
+ # General shell piping and chaining works too
77
+ echo "explain symgraph.py" | mc | cat - PLAN.md | mc
75
78
  ```
76
79
  *(For a full list of mc server arguments, run mc --help)*
77
80
 
@@ -6,7 +6,7 @@ setup(
6
6
  author_email="albersj66@gmail.com",
7
7
  author="J Joe",
8
8
  license="Apache-2.0",
9
- version="0.0.3",
9
+ version="0.0.4",
10
10
  readme="README.md",
11
11
  description="Coding Agent for Mac",
12
12
  long_description=open("README.md").read(),
File without changes
File without changes
File without changes
File without changes