chad-code 1.0.5__tar.gz → 1.0.6__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.5 → chad_code-1.0.6}/PKG-INFO +21 -6
- {chad_code-1.0.5 → chad_code-1.0.6}/README.md +17 -4
- {chad_code-1.0.5 → chad_code-1.0.6}/pyproject.toml +31 -2
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/__init__.py +1 -1
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/agent.py +43 -20
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/cli.py +6 -6
- chad_code-1.0.6/src/chad/parakeet/LICENSE +201 -0
- chad_code-1.0.6/src/chad/parakeet/__init__.py +27 -0
- chad_code-1.0.6/src/chad/parakeet/alignment.py +287 -0
- chad_code-1.0.6/src/chad/parakeet/attention.py +640 -0
- chad_code-1.0.6/src/chad/parakeet/audio.py +183 -0
- chad_code-1.0.6/src/chad/parakeet/cache.py +156 -0
- chad_code-1.0.6/src/chad/parakeet/conformer.py +423 -0
- chad_code-1.0.6/src/chad/parakeet/ctc.py +34 -0
- chad_code-1.0.6/src/chad/parakeet/parakeet.py +1055 -0
- chad_code-1.0.6/src/chad/parakeet/rnnt.py +155 -0
- chad_code-1.0.6/src/chad/parakeet/tokenizer.py +3 -0
- chad_code-1.0.6/src/chad/parakeet/utils.py +112 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/prove.py +1 -1
- chad_code-1.0.6/src/chad/speech.py +565 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/tools.py +1 -1
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/tui.py +296 -13
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad_code.egg-info/PKG-INFO +21 -6
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad_code.egg-info/SOURCES.txt +15 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad_code.egg-info/requires.txt +4 -1
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_agent_e2e.py +14 -14
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_engine.py +1 -1
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_garble_invariant.py +1 -1
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_gate.py +67 -11
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_lever_bite.py +4 -4
- chad_code-1.0.6/tests/test_speech.py +284 -0
- chad_code-1.0.6/tests/test_speech_tui.py +508 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_subagent.py +7 -5
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_tui.py +50 -1
- {chad_code-1.0.5 → chad_code-1.0.6}/LICENSE +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/setup.cfg +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/atif.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/base_engine.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/bench.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/compaction.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/completion_engine.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/config.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/diag.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/engine.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/guardrails.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/ignore.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/levers.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/lsp.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/mcp.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/mcp_oauth.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/mlx_fastpath.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/mlx_qsdpa.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/profiles.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/prompt.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/render.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/repomap.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/serve.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/session.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/skills.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/symbols.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/syntaxgate.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/toolcall_parse.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad/validate.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad_code.egg-info/dependency_links.txt +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad_code.egg-info/entry_points.txt +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/src/chad_code.egg-info/top_level.txt +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_agent.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_agent_guards.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_atif.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_bench.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_cli.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_compact_notice.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_compaction.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_completion_engine.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_config.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_confirm_preview.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_done_audit.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_drift_warn.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_edit.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_edit_corruption.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_engine_kvquant.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_engine_pld_hybrid.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_feel_pack.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_ignore.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_intent.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_levers.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_log_redaction.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_lsp.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_mcp.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_mcp_oauth.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_mlx_fastpath.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_mlx_qsdpa.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_plan_review.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_prove.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_render.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_replace_lines.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_repomap.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_serve.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_session.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_skills.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_symbols.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_syntaxgate.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_toolcall_parse.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_tools.py +0 -0
- {chad_code-1.0.5 → chad_code-1.0.6}/tests/test_validate.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chad-code
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.6
|
|
4
4
|
Summary: Local MLX-backed, Claude-Code-style coding agent (Apple Silicon, Ornith 35B/9B)
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Repository, https://github.com/nathansutton/chad
|
|
@@ -21,7 +21,7 @@ Requires-Dist: mlx<0.33,>=0.32.0; sys_platform == "darwin"
|
|
|
21
21
|
Requires-Dist: mlx-lm<0.32,>=0.31.3; sys_platform == "darwin"
|
|
22
22
|
Requires-Dist: transformers<5.13,>=5.0
|
|
23
23
|
Requires-Dist: jinja2>=3.1
|
|
24
|
-
Requires-Dist: numpy<
|
|
24
|
+
Requires-Dist: numpy<3,>=1.26
|
|
25
25
|
Requires-Dist: huggingface-hub>=1.22.0
|
|
26
26
|
Requires-Dist: jedi>=0.19.2
|
|
27
27
|
Requires-Dist: prompt_toolkit>=3.0.43
|
|
@@ -33,6 +33,8 @@ Provides-Extra: highlight
|
|
|
33
33
|
Requires-Dist: pygments>=2.17; extra == "highlight"
|
|
34
34
|
Provides-Extra: lsp
|
|
35
35
|
Requires-Dist: serena-agent>=1.5; extra == "lsp"
|
|
36
|
+
Provides-Extra: speech
|
|
37
|
+
Requires-Dist: sounddevice>=0.5; extra == "speech"
|
|
36
38
|
Dynamic: license-file
|
|
37
39
|
|
|
38
40
|
# chad — a local, MLX-backed coding agent
|
|
@@ -81,10 +83,12 @@ instrument:
|
|
|
81
83
|
| **Harness** | open-ended, anything you can imagine | plan. execute. nothing else. |
|
|
82
84
|
| **When wrong** | reasons a way out | already shipped |
|
|
83
85
|
|
|
84
|
-

|
|
85
87
|
|
|
86
|
-
> Real session, unedited (
|
|
87
|
-
>
|
|
88
|
+
> Real session, unedited (the silent prefill is cut): a local 35B finds the cent that
|
|
89
|
+
> floor division loses, fixes it, and verifies itself — then your own `pytest`, in your
|
|
90
|
+
> own shell. Recorded with `--yolo` so nothing pauses for a keypress; the default mode
|
|
91
|
+
> stops and asks before every edit and every command.
|
|
88
92
|
|
|
89
93
|
## Frontier scores, laptop cost
|
|
90
94
|
|
|
@@ -171,7 +175,10 @@ it chad uses the tree-sitter fallback automatically.
|
|
|
171
175
|
`uv run chad` launches a full-screen terminal UI (built on prompt_toolkit):
|
|
172
176
|
|
|
173
177
|
- **shift-tab cycles permission modes** — `normal` (confirm each bash/write/edit) →
|
|
174
|
-
`auto-accept edits`
|
|
178
|
+
`auto-accept edits` (edits land silently; **terminal commands still ask**) → `yolo`
|
|
179
|
+
(nothing asks) → `plan mode` (read-only: investigate + propose a numbered plan) → back.
|
|
180
|
+
- **the approval prompt shows what you're approving** — the full command on its own lines
|
|
181
|
+
above the input, not a clipped single line. Approving blind isn't approving.
|
|
175
182
|
- **type-ahead message queue** — keep typing while the agent works; messages run in order.
|
|
176
183
|
- **ctrl-c interrupts the running turn** without killing the session.
|
|
177
184
|
- **live status line** — model, mode, context %, a state glyph + verb, elapsed seconds, and
|
|
@@ -181,6 +188,14 @@ it chad uses the tree-sitter fallback automatically.
|
|
|
181
188
|
`/model`, `/mode`, `/help`, `/exit`. Same set in the `--repl` line interface.
|
|
182
189
|
- **`@file` / `@dir` mentions** and **`!command` shell passthrough** — pull a file into
|
|
183
190
|
context inline, or run a shell command without invoking the model.
|
|
191
|
+
- **voice mode, all local** — `/speech`, then ctrl-t to talk: Parakeet-on-MLX transcribes
|
|
192
|
+
into the input box for you to review before Enter sends it (esc discards a take);
|
|
193
|
+
replies are read aloud via macOS `say`. A pre-roll buffer means your first syllable
|
|
194
|
+
isn't clipped, and a personal word table (`~/.chad/speech_words.json`) teaches it your
|
|
195
|
+
identifiers — `{"pie test": "pytest"}`. Dictation cost is linear in take length, so a
|
|
196
|
+
long thought is fine; `/speech` off releases both the mic and the weights. Nothing
|
|
197
|
+
leaves the machine. Needs the `speech` extra (`uv sync --extra speech` — just a mic
|
|
198
|
+
library; no torch, no numba).
|
|
184
199
|
|
|
185
200
|
**Usage.** `uv run chad --help` is the source of truth:
|
|
186
201
|
|
|
@@ -44,10 +44,12 @@ instrument:
|
|
|
44
44
|
| **Harness** | open-ended, anything you can imagine | plan. execute. nothing else. |
|
|
45
45
|
| **When wrong** | reasons a way out | already shipped |
|
|
46
46
|
|
|
47
|
-

|
|
48
48
|
|
|
49
|
-
> Real session, unedited (
|
|
50
|
-
>
|
|
49
|
+
> Real session, unedited (the silent prefill is cut): a local 35B finds the cent that
|
|
50
|
+
> floor division loses, fixes it, and verifies itself — then your own `pytest`, in your
|
|
51
|
+
> own shell. Recorded with `--yolo` so nothing pauses for a keypress; the default mode
|
|
52
|
+
> stops and asks before every edit and every command.
|
|
51
53
|
|
|
52
54
|
## Frontier scores, laptop cost
|
|
53
55
|
|
|
@@ -134,7 +136,10 @@ it chad uses the tree-sitter fallback automatically.
|
|
|
134
136
|
`uv run chad` launches a full-screen terminal UI (built on prompt_toolkit):
|
|
135
137
|
|
|
136
138
|
- **shift-tab cycles permission modes** — `normal` (confirm each bash/write/edit) →
|
|
137
|
-
`auto-accept edits`
|
|
139
|
+
`auto-accept edits` (edits land silently; **terminal commands still ask**) → `yolo`
|
|
140
|
+
(nothing asks) → `plan mode` (read-only: investigate + propose a numbered plan) → back.
|
|
141
|
+
- **the approval prompt shows what you're approving** — the full command on its own lines
|
|
142
|
+
above the input, not a clipped single line. Approving blind isn't approving.
|
|
138
143
|
- **type-ahead message queue** — keep typing while the agent works; messages run in order.
|
|
139
144
|
- **ctrl-c interrupts the running turn** without killing the session.
|
|
140
145
|
- **live status line** — model, mode, context %, a state glyph + verb, elapsed seconds, and
|
|
@@ -144,6 +149,14 @@ it chad uses the tree-sitter fallback automatically.
|
|
|
144
149
|
`/model`, `/mode`, `/help`, `/exit`. Same set in the `--repl` line interface.
|
|
145
150
|
- **`@file` / `@dir` mentions** and **`!command` shell passthrough** — pull a file into
|
|
146
151
|
context inline, or run a shell command without invoking the model.
|
|
152
|
+
- **voice mode, all local** — `/speech`, then ctrl-t to talk: Parakeet-on-MLX transcribes
|
|
153
|
+
into the input box for you to review before Enter sends it (esc discards a take);
|
|
154
|
+
replies are read aloud via macOS `say`. A pre-roll buffer means your first syllable
|
|
155
|
+
isn't clipped, and a personal word table (`~/.chad/speech_words.json`) teaches it your
|
|
156
|
+
identifiers — `{"pie test": "pytest"}`. Dictation cost is linear in take length, so a
|
|
157
|
+
long thought is fine; `/speech` off releases both the mic and the weights. Nothing
|
|
158
|
+
leaves the machine. Needs the `speech` extra (`uv sync --extra speech` — just a mic
|
|
159
|
+
library; no torch, no numba).
|
|
147
160
|
|
|
148
161
|
**Usage.** `uv run chad --help` is the source of truth:
|
|
149
162
|
|
|
@@ -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.6"
|
|
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"
|
|
@@ -49,7 +49,10 @@ dependencies = [
|
|
|
49
49
|
# absent in a clean install (e.g. chad inside a Linux benchmark container), where its
|
|
50
50
|
# absence crashes the first turn. Declare it directly.
|
|
51
51
|
"jinja2>=3.1",
|
|
52
|
-
|
|
52
|
+
# <3: the old <2 cap was 1.0.0-era caution, not a known break. numpy 2.4.6
|
|
53
|
+
# verified end-to-end (full gate + live Parakeet-on-MLX transcription +
|
|
54
|
+
# `chad prove` 4/4); staying open keeps 2.x-floored ASR deps adoptable.
|
|
55
|
+
"numpy>=1.26,<3",
|
|
53
56
|
"huggingface-hub>=1.22.0", # first-run model download (cli.py/engine.py); imported directly, not just transitively
|
|
54
57
|
"jedi>=0.19.2", # in-process symbolic code intelligence (read/search/edit)
|
|
55
58
|
"prompt_toolkit>=3.0.43",
|
|
@@ -78,6 +81,16 @@ highlight = ["pygments>=2.17"]
|
|
|
78
81
|
# heavyweight tree; absent, every caller falls back to the tree-sitter backend.
|
|
79
82
|
# Install with `uv sync --extra lsp`.
|
|
80
83
|
lsp = ["serena-agent>=1.5"]
|
|
84
|
+
# Voice mode (/speech in the TUI): push-to-talk dictation via chad's vendored
|
|
85
|
+
# Parakeet-on-MLX (src/chad/parakeet — the PyPI parakeet-mlx drags librosa's
|
|
86
|
+
# numba/scipy tree for one mel-filterbank call) + spoken replies via macOS
|
|
87
|
+
# `say`. All on-device, nothing leaves the machine. mlx/numpy/huggingface-hub
|
|
88
|
+
# are already core deps, so the extra adds only the mic (sounddevice/PortAudio).
|
|
89
|
+
# Optional and import-guarded in speech.py: absent, /speech prints the install
|
|
90
|
+
# hint and everything else is untouched. Install with `uv sync --extra speech`.
|
|
91
|
+
speech = [
|
|
92
|
+
"sounddevice>=0.5",
|
|
93
|
+
]
|
|
81
94
|
|
|
82
95
|
# The one entrypoint: `uv run chad`. (`chad-bench` reproduces docs/benchmarks.md.)
|
|
83
96
|
# `chad-code` is an alias so `uvx chad-code` (which runs the console script matching
|
|
@@ -107,6 +120,10 @@ build-backend = "setuptools.build_meta"
|
|
|
107
120
|
[tool.setuptools.packages.find]
|
|
108
121
|
where = ["src"]
|
|
109
122
|
|
|
123
|
+
# The vendored Parakeet code is Apache-2.0; its license text must travel with
|
|
124
|
+
# the code, wheel included.
|
|
125
|
+
[tool.setuptools.package-data]
|
|
126
|
+
"chad.parakeet" = ["LICENSE"]
|
|
110
127
|
[tool.pytest.ini_options]
|
|
111
128
|
testpaths = ["tests"]
|
|
112
129
|
# No "-q" here: CI/docs/agents all invoke `pytest -q` explicitly, and stacking the two
|
|
@@ -127,6 +144,12 @@ src = ["src", "tests"]
|
|
|
127
144
|
select = ["F", "E9", "I"]
|
|
128
145
|
ignore = ["E741"] # ambiguous var names (l/I) appear in existing math code
|
|
129
146
|
|
|
147
|
+
[tool.ruff.lint.per-file-ignores]
|
|
148
|
+
# Vendored upstream (see chad/parakeet/__init__.py), kept byte-close for
|
|
149
|
+
# future re-syncs — not held to chad's own lint standard. (F401: imports left
|
|
150
|
+
# in place for upstream fidelity after the transcribe(path) cut.)
|
|
151
|
+
"src/chad/parakeet/*" = ["F401", "F821", "F841", "E741"]
|
|
152
|
+
|
|
130
153
|
[tool.mypy]
|
|
131
154
|
python_version = "3.11"
|
|
132
155
|
files = ["src/chad"]
|
|
@@ -142,6 +165,12 @@ disable_error_code = ["var-annotated"]
|
|
|
142
165
|
# Tighten (disallow_untyped_defs, re-enable var-annotated, add B/UP/SIM in ruff) in a
|
|
143
166
|
# follow-up once this baseline holds.
|
|
144
167
|
|
|
168
|
+
[[tool.mypy.overrides]]
|
|
169
|
+
# Vendored upstream inference code (see chad/parakeet/__init__.py) is not held
|
|
170
|
+
# to chad's gate so re-syncs stay a plain re-copy.
|
|
171
|
+
module = "chad.parakeet.*"
|
|
172
|
+
ignore_errors = true
|
|
173
|
+
|
|
145
174
|
[[tool.mypy.overrides]]
|
|
146
175
|
# mlx_fastpath patches mlx_lm classes that only exist on macOS: with mlx installed
|
|
147
176
|
# (dev Macs, the macos CI jobs) its `type: ignore[method-assign]` comments are load-
|
|
@@ -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.6"
|
|
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
|
|
@@ -57,11 +57,12 @@ SUBAGENT_READ_ONLY = {
|
|
|
57
57
|
|
|
58
58
|
def subagent_tools_for(parent_mode: str, requested: str) -> str:
|
|
59
59
|
"""The toolset a sub-agent may run with. A sub-agent auto-approves its own tool
|
|
60
|
-
calls (mode='
|
|
61
|
-
than its parent: only
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
calls (mode='yolo', no confirm callback), so it must never hold more autonomy
|
|
61
|
+
than its parent: only a 'yolo' parent (--yolo / headless) may delegate 'all'.
|
|
62
|
+
A 'normal' parent's human-approval promise, an 'auto' parent's narrower promise
|
|
63
|
+
(edits yes, shell no — and 'all' includes bash), and plan mode's read-only
|
|
64
|
+
promise all clamp the sub-agent to read-only."""
|
|
65
|
+
if parent_mode == "yolo" and requested == "all":
|
|
65
66
|
return "all"
|
|
66
67
|
return "read-only"
|
|
67
68
|
|
|
@@ -209,10 +210,30 @@ def close_unclosed_think(text: str, thinking: bool) -> str:
|
|
|
209
210
|
|
|
210
211
|
# Permission modes (Claude Code parity, cycled with shift-tab in the TUI):
|
|
211
212
|
# normal — confirm each mutating tool (bash/write/edit)
|
|
212
|
-
# auto — auto-approve
|
|
213
|
+
# auto — auto-approve FILE EDITS only; bash and MCP tools still ask
|
|
214
|
+
# yolo — auto-approve every mutating tool (--yolo starts here)
|
|
213
215
|
# plan — read-only: changes are blocked; the model researches and proposes a plan
|
|
214
|
-
MODES = ("normal", "auto", "plan")
|
|
215
|
-
MODE_LABEL = {"normal": "normal", "auto": "auto-accept edits", "
|
|
216
|
+
MODES = ("normal", "auto", "yolo", "plan")
|
|
217
|
+
MODE_LABEL = {"normal": "normal", "auto": "auto-accept edits", "yolo": "yolo",
|
|
218
|
+
"plan": "plan mode"}
|
|
219
|
+
|
|
220
|
+
# What `auto` waves through: edits to files in the workspace, whose blast radius is a
|
|
221
|
+
# diff you can read and revert. `bash` is excluded on purpose — a shell command can
|
|
222
|
+
# touch anything on the machine, is the one tool whose preview is genuinely hard to
|
|
223
|
+
# eyeball, and is exactly what a human is still in the loop for. MCP tools are excluded
|
|
224
|
+
# for the same reason (a server-side tool can send mail or hit an API). The list is
|
|
225
|
+
# explicit rather than `MUTATING - {"bash"}` so it fails CLOSED: a mutating tool added
|
|
226
|
+
# later asks for approval until someone deliberately adds it here.
|
|
227
|
+
AUTO_EDIT_TOOLS = {"write", "edit", "replace_lines", "insert_lines",
|
|
228
|
+
"replace_symbol", "insert_symbol", "rename_symbol"}
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def auto_approves(mode: str, name: str) -> bool:
|
|
232
|
+
"""Does `mode` clear tool `name` without asking a human? Read-only tools never
|
|
233
|
+
reach here (the caller checks is_mutating first)."""
|
|
234
|
+
if mode == "yolo":
|
|
235
|
+
return True
|
|
236
|
+
return mode == "auto" and name in AUTO_EDIT_TOOLS
|
|
216
237
|
_PLAN_PREFIX = (
|
|
217
238
|
"[PLAN MODE. Research first (read/grep/glob/repo_map/overview) — do NOT edit "
|
|
218
239
|
"project files or run commands. Then write ONE self-contained plan to "
|
|
@@ -325,7 +346,7 @@ class Agent:
|
|
|
325
346
|
skills.reset_session()
|
|
326
347
|
from . import mcp
|
|
327
348
|
mcp.reset_session()
|
|
328
|
-
self.mode = mode or ("
|
|
349
|
+
self.mode = mode or ("yolo" if yolo else "normal")
|
|
329
350
|
self.thinking = thinking # Ornith is a reasoning model; toggles <think> blocks
|
|
330
351
|
# Steps per WINDOW, not a hard kill: a window that landed+verified a change
|
|
331
352
|
# earns an extension (see guardrails.extend_step_cap; absolute ceiling 4x).
|
|
@@ -460,7 +481,7 @@ class Agent:
|
|
|
460
481
|
|
|
461
482
|
@property
|
|
462
483
|
def yolo(self) -> bool:
|
|
463
|
-
return self.mode == "
|
|
484
|
+
return self.mode == "yolo"
|
|
464
485
|
|
|
465
486
|
@property
|
|
466
487
|
def tok_per_s(self) -> float:
|
|
@@ -586,18 +607,18 @@ class Agent:
|
|
|
586
607
|
|
|
587
608
|
def _confirm(self, name, args) -> bool:
|
|
588
609
|
# Destructive-bash seatbelt: a catastrophic shell command (rm -rf ~, mkfs,
|
|
589
|
-
# curl|sh, …) is screened even in --yolo
|
|
590
|
-
# untrusted repo contents and
|
|
610
|
+
# curl|sh, …) is screened even in --yolo mode, because the model acts on
|
|
611
|
+
# untrusted repo contents and yolo mode has no human in the loop. If a confirm
|
|
591
612
|
# channel exists (TTY or callback) we force the prompt; headless with no channel
|
|
592
613
|
# we BLOCK rather than execute on injection. CHAD_NO_DESTRUCTIVE_GUARD=1 opts out.
|
|
593
614
|
dangerous = (name == "bash" and isinstance(args, dict)
|
|
594
615
|
and not config.flag("CHAD_NO_DESTRUCTIVE_GUARD")
|
|
595
616
|
and guardrails.is_destructive_bash(str(args.get("command", ""))))
|
|
596
|
-
if
|
|
617
|
+
if not is_mutating(name) or auto_approves(self.mode, name):
|
|
597
618
|
if not dangerous:
|
|
598
619
|
return True
|
|
599
620
|
if self._confirm_cb is None and not sys.stdin.isatty():
|
|
600
|
-
self._emit("info", f" [blocked destructive command
|
|
621
|
+
self._emit("info", f" [blocked destructive command — nobody to approve it: "
|
|
601
622
|
f"{args.get('command', '')!r}; set CHAD_NO_DESTRUCTIVE_GUARD=1 to allow]")
|
|
602
623
|
# Tell the MODEL the truth about who blocked it and why: "[denied by
|
|
603
624
|
# user]" reads as a human refusal and teaches the wrong lesson (the
|
|
@@ -642,12 +663,13 @@ class Agent:
|
|
|
642
663
|
parent. Its grep/read churn never enters the main transcript; only this return
|
|
643
664
|
does. Depth 1 only: a sub-agent can't itself call `task` (its schema omits it)."""
|
|
644
665
|
# Never grant a sub-agent more autonomy than its parent: the sub-agent runs
|
|
645
|
-
# mode='
|
|
646
|
-
# the parent itself is auto-approved (--yolo/headless); 'normal' (human
|
|
647
|
-
# every mutation)
|
|
666
|
+
# mode='yolo' with no confirm callback, so an 'all' toolset is honored only when
|
|
667
|
+
# the parent itself is fully auto-approved (--yolo/headless); 'normal' (human
|
|
668
|
+
# confirms every mutation), 'auto' (human still confirms shell) and 'plan'
|
|
669
|
+
# (read-only) parents clamp it to read-only.
|
|
648
670
|
requested, tools = tools, subagent_tools_for(self.mode, tools)
|
|
649
671
|
if requested == "all" and tools == "read-only":
|
|
650
|
-
self._emit("muted", " ⌊ sub-agent clamped to read-only (parent mode is not
|
|
672
|
+
self._emit("muted", " ⌊ sub-agent clamped to read-only (parent mode is not yolo)")
|
|
651
673
|
self._emit("muted", f" ⌊ delegating to sub-agent: {description}")
|
|
652
674
|
log.info("TASK start | desc=%r | tools=%s | prompt=%r",
|
|
653
675
|
description, tools, redact(prompt[:300]))
|
|
@@ -657,7 +679,7 @@ class Agent:
|
|
|
657
679
|
try:
|
|
658
680
|
sub = Agent(
|
|
659
681
|
self.engine,
|
|
660
|
-
mode="
|
|
682
|
+
mode="yolo", # auto-approve within its restricted toolset
|
|
661
683
|
max_steps=SUBAGENT_MAX_STEPS,
|
|
662
684
|
ctx_limit=min(self.ctx_limit, SUBAGENT_CTX_LIMIT),
|
|
663
685
|
thinking=self.thinking,
|
|
@@ -1509,7 +1531,8 @@ class Agent:
|
|
|
1509
1531
|
# fire, which is how a turn once shipped a 28-token garble as its final
|
|
1510
1532
|
# answer. read_only/explain asks are exempt. Banks a note so
|
|
1511
1533
|
# auto-continue relaunches fresh instead of shipping nothing.
|
|
1512
|
-
did_nothing = self.mode
|
|
1534
|
+
did_nothing = (self.mode in ("auto", "yolo")
|
|
1535
|
+
and not read_only_intent and not did_work)
|
|
1513
1536
|
if (action_task and not read_only_intent
|
|
1514
1537
|
and (not made_edit or unverified_edit)) or did_nothing:
|
|
1515
1538
|
# Churn→audit handoff: this hard stop used to fire with the
|
|
@@ -712,7 +712,7 @@ def _main(argv=None):
|
|
|
712
712
|
sys.stderr.write(f"ready in {load_s:.1f}s | context {eng.effective_ctx} tokens "
|
|
713
713
|
f"(compact at {ctx_limit})\n")
|
|
714
714
|
|
|
715
|
-
start_mode = "plan" if args.plan else ("
|
|
715
|
+
start_mode = "plan" if args.plan else ("yolo" if args.yolo else "normal")
|
|
716
716
|
thinking = not args.no_think
|
|
717
717
|
|
|
718
718
|
# Live per-turn ctx-limit recheck: the startup number was
|
|
@@ -758,9 +758,9 @@ def _main(argv=None):
|
|
|
758
758
|
# auto-approve mutating tools unless the user asked for read-only --plan.
|
|
759
759
|
run_mode = start_mode
|
|
760
760
|
if run_mode == "normal" and not sys.stdin.isatty():
|
|
761
|
-
run_mode = "
|
|
761
|
+
run_mode = "yolo"
|
|
762
762
|
sys.stderr.write("[headless: auto-approving tools (use --plan for read-only)]\n")
|
|
763
|
-
agent = Agent(eng, yolo=(run_mode == "
|
|
763
|
+
agent = Agent(eng, yolo=(run_mode == "yolo"), ctx_limit=ctx_limit,
|
|
764
764
|
mode=run_mode, thinking=thinking, resume=resume, persist=True,
|
|
765
765
|
think_budget=args.think_budget,
|
|
766
766
|
turn_budget_s=turn_budget_s, ctx_limit_fn=ctx_limit_fn)
|
|
@@ -777,7 +777,7 @@ def _main(argv=None):
|
|
|
777
777
|
# ships as an empty diff — the measured bail signature.
|
|
778
778
|
auto_continue = config.env_int("CHAD_AUTO_CONTINUE")
|
|
779
779
|
continues = auto_continue if auto_continue is not None \
|
|
780
|
-
else (2 if run_mode == "
|
|
780
|
+
else (2 if run_mode == "yolo" else 0)
|
|
781
781
|
used_continues = 0
|
|
782
782
|
while agent.budget_note:
|
|
783
783
|
# Base allowance first; past it, keep granting fresh attempts while most
|
|
@@ -819,7 +819,7 @@ def _main(argv=None):
|
|
|
819
819
|
if getattr(eng, "temp", None) is not None:
|
|
820
820
|
eng.temp = max(eng.temp, 0.6)
|
|
821
821
|
eng.reset()
|
|
822
|
-
agent = Agent(eng, yolo=(run_mode == "
|
|
822
|
+
agent = Agent(eng, yolo=(run_mode == "yolo"), ctx_limit=ctx_limit,
|
|
823
823
|
mode=run_mode, thinking=thinking, persist=True,
|
|
824
824
|
think_budget=args.think_budget,
|
|
825
825
|
turn_budget_s=relaunch_s, ctx_limit_fn=ctx_limit_fn)
|
|
@@ -841,7 +841,7 @@ def _main(argv=None):
|
|
|
841
841
|
sys.stderr.write(f"[review] task finished with {turn_budget_s - elapsed:.0f}s "
|
|
842
842
|
"of budget left; running one fresh-context verification pass\n")
|
|
843
843
|
eng.reset()
|
|
844
|
-
agent = Agent(eng, yolo=(run_mode == "
|
|
844
|
+
agent = Agent(eng, yolo=(run_mode == "yolo"), ctx_limit=ctx_limit,
|
|
845
845
|
mode=run_mode, thinking=thinking, persist=True,
|
|
846
846
|
think_budget=args.think_budget,
|
|
847
847
|
turn_budget_s=review_budget, ctx_limit_fn=ctx_limit_fn)
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Vendored Parakeet-on-MLX inference — chad's STT engine, MLX-only by design.
|
|
2
|
+
|
|
3
|
+
Copied from parakeet-mlx 0.5.2 (Apache-2.0, Copyright Senstella,
|
|
4
|
+
https://github.com/senstella/parakeet-mlx — license text in this directory's
|
|
5
|
+
LICENSE file). Parakeet TDT v3 (0.6B) replaces the earlier vendored Whisper:
|
|
6
|
+
same speed class as the coding model's own stack, better dictation accuracy,
|
|
7
|
+
and its TDT decoder doesn't have Whisper's repetition-loop hallucination mode.
|
|
8
|
+
Crucially, its tokenizer vocabulary ships inside the model repo's config.json —
|
|
9
|
+
no vocab data files in this repo or the wheel.
|
|
10
|
+
|
|
11
|
+
Vendored rather than depended on because the PyPI package drags librosa
|
|
12
|
+
(→ numba/scipy/scikit-learn) for a single mel-filterbank call, plus typer for
|
|
13
|
+
a CLI chad doesn't use. What changed, relative to upstream:
|
|
14
|
+
- audio.py: librosa.filters.mel replaced by a local numpy implementation,
|
|
15
|
+
validated against librosa to <1e-8 (goldens in tests/test_speech.py);
|
|
16
|
+
load_audio (ffmpeg file decode) removed — chad feeds mic arrays.
|
|
17
|
+
- utils.py: dacite.from_dict replaced by a local recursive dataclass builder.
|
|
18
|
+
- parakeet.py: transcribe(path) raises (it needed the ffmpeg loader); the
|
|
19
|
+
array-level pipeline chad uses — get_logmel() + generate() — is untouched.
|
|
20
|
+
- cli.py dropped.
|
|
21
|
+
Every change is marked "VENDORED CHANGE"; the rest is byte-identical to
|
|
22
|
+
upstream, so a version bump is a re-copy plus re-applying those edits.
|
|
23
|
+
|
|
24
|
+
Runtime deps beyond chad's core tree (mlx, numpy, huggingface-hub): none.
|
|
25
|
+
"""
|
|
26
|
+
from .audio import get_logmel, mel_filters # noqa: F401
|
|
27
|
+
from .utils import from_config, from_pretrained # noqa: F401
|