1bcoder 0.1.14__tar.gz → 0.1.16__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.
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/1bcoder.egg-info/PKG-INFO +1 -1
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/1bcoder.egg-info/SOURCES.txt +3 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/PKG-INFO +1 -1
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/agents/websearch.txt +7 -1
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/doc/PARAM.md +4 -0
- 1bcoder-0.1.16/_bcoder_data/flows/compress.py +310 -0
- 1bcoder-0.1.16/_bcoder_data/flows/deepagent_md.py +875 -0
- 1bcoder-0.1.16/_bcoder_data/proc/ctx_expand.py +37 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/chat.py +303 -27
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/pyproject.toml +1 -1
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/1bcoder.egg-info/dependency_links.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/1bcoder.egg-info/entry_points.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/1bcoder.egg-info/requires.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/1bcoder.egg-info/top_level.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/LICENSE +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/README.md +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/__init__.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/agents/advance.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/agents/ask.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/agents/compact.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/agents/concepts.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/agents/fill.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/agents/planning.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/agents/scan.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/agents/sqlite.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/aliases.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/doc/FLOWS.md +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/doc/MCP.md +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/doc/OLLAMA_SERVER_PARAM.md +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/doc/PROC.md +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/doc/TRANSLATE.md +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/__pycache__/commit_message.cpython-311.pyc +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/__pycache__/webcrawl.cpython-311.pyc +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/commit_message.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/deepagent.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/deobfuscate.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/external_help.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/grounding.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/obfuscate.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/py_error_trace.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/simargl_files.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/visual_search.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/webask.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/flows/webcrawl.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/map.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/action-required.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/add-save.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/assist.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/collect-files.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/ctx_cut.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/extract-code.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/extract-files.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/extract-list.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/grounding-check.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/md.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/mdx.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/pattern-gate.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/regexp-extract.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/rude_words.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/scan-save.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/secret_check.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/sql_readonly_guard.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/proc/tempctx-cut.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/profiles.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/prompts/analysis.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/prompts/sumarise.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/prompts.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/AddFunction.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/AskProject.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/CheckRequirements.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/DockerMySQL.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/DockerNginx.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/DockerPython.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/DockerStack.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/DuckDuckGoInstant.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/EnvTemplate.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/Explain.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/ExploreProjectStructure.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/GitIgnorePython.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/MySQLDump.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/NewScript.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/PipFreeze.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/PyPI.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/Refactor.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/RunAndFix.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/SQLiteSchema.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/Translate.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/WikiPage.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/WikiSearch.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/auto-bkup.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/edit-control.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/parallel_call.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/personal/content/create-regular-content.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/personal/content/plan.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/personal/test/collect-data-from-test-environment.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/plan.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/remote/create-content-on-remote-server.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/set_ctx.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/simargl-cli_index_files.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/simargl-cli_index_units.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/simargl-cli_search.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/team-map-worker.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/team-search-worker.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/team-summarize.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/team-tree-worker.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/scripts/test.txt +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/_bcoder_data/teams/code-analysis.yaml +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/map_index.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/map_query.py +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/setup.cfg +0 -0
- {1bcoder-0.1.14 → 1bcoder-0.1.16}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: 1bcoder
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.16
|
|
4
4
|
Summary: AI coding assistant agent for 1B–7B local models (Ollama, LMStudio, llama.cpp). Terminal REPL with file editing, project map, agents, scripts, and parallel multi-model queries.
|
|
5
5
|
Project-URL: Homepage, https://github.com/szholobetsky/1bcoder
|
|
6
6
|
Project-URL: Repository, https://github.com/szholobetsky/1bcoder
|
|
@@ -31,7 +31,9 @@ _bcoder_data/doc/PARAM.md
|
|
|
31
31
|
_bcoder_data/doc/PROC.md
|
|
32
32
|
_bcoder_data/doc/TRANSLATE.md
|
|
33
33
|
_bcoder_data/flows/commit_message.py
|
|
34
|
+
_bcoder_data/flows/compress.py
|
|
34
35
|
_bcoder_data/flows/deepagent.py
|
|
36
|
+
_bcoder_data/flows/deepagent_md.py
|
|
35
37
|
_bcoder_data/flows/deobfuscate.py
|
|
36
38
|
_bcoder_data/flows/external_help.py
|
|
37
39
|
_bcoder_data/flows/grounding.py
|
|
@@ -48,6 +50,7 @@ _bcoder_data/proc/add-save.py
|
|
|
48
50
|
_bcoder_data/proc/assist.py
|
|
49
51
|
_bcoder_data/proc/collect-files.py
|
|
50
52
|
_bcoder_data/proc/ctx_cut.py
|
|
53
|
+
_bcoder_data/proc/ctx_expand.py
|
|
51
54
|
_bcoder_data/proc/extract-code.py
|
|
52
55
|
_bcoder_data/proc/extract-files.py
|
|
53
56
|
_bcoder_data/proc/extract-list.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: 1bcoder
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.16
|
|
4
4
|
Summary: AI coding assistant agent for 1B–7B local models (Ollama, LMStudio, llama.cpp). Terminal REPL with file editing, project map, agents, scripts, and parallel multi-model queries.
|
|
5
5
|
Project-URL: Homepage, https://github.com/szholobetsky/1bcoder
|
|
6
6
|
Project-URL: Repository, https://github.com/szholobetsky/1bcoder
|
|
@@ -13,8 +13,14 @@ system =
|
|
|
13
13
|
One ACTION per turn.
|
|
14
14
|
When done, write a clear summary answer. Do not write any ACTION when done.
|
|
15
15
|
|
|
16
|
+
IMPORTANT: never wrap the /web search query in quotes. Write keywords as plain words.
|
|
17
|
+
Wrong: ACTION: /web search "lenovo m75q gen 2 price ukraine"
|
|
18
|
+
Right: ACTION: /web search lenovo m75q gen 2 price ukraine
|
|
19
|
+
|
|
16
20
|
Strategy:
|
|
17
|
-
1. Start with ACTION: /web search
|
|
21
|
+
1. Start with ACTION: /web search keyword1 keyword2 keyword*
|
|
22
|
+
DuckDuckGo operators: "exact phrase", -exclude, OR, AND, site:, filetype:, intitle:, inurl:, region:
|
|
23
|
+
Use quotes only around specific phrases, not around the whole query.
|
|
18
24
|
2. Review the search results (titles, URLs, snippets)
|
|
19
25
|
3. Pick the most relevant URLs and fetch them with ACTION: /web fetch <url>
|
|
20
26
|
4. Fetch up to 3 pages total — stop earlier if you already have enough to answer
|
|
@@ -19,6 +19,7 @@ These are handled by 1bcoder directly and are not forwarded to the model API.
|
|
|
19
19
|
| `ask_show` | 500 | Characters shown in terminal when output is truncated. |
|
|
20
20
|
| `run_timeout` | 30 | Timeout in seconds for `/run` shell commands. Set to `0` to disable (no timeout). Useful for long-running CLI tools like `simargl search`. |
|
|
21
21
|
| `log` | `false` | Print full request details before each LLM call: URL, model, message count, options. Also prints HTTP response headers on error. Useful for debugging 500 errors or unexpected model behaviour. |
|
|
22
|
+
| `keep_alive` | *(not set)* | **Ollama only.** How long to keep the model loaded after a response. `-1` = never unload. `"5m"` = 5 minutes (Ollama default). `"0"` = unload immediately. Set `-1` to prevent KV-cache eviction during long sessions. |
|
|
22
23
|
|
|
23
24
|
---
|
|
24
25
|
|
|
@@ -134,6 +135,9 @@ An alternative to top_p/top_k that targets a specific perplexity level.
|
|
|
134
135
|
# Keep reasoning in context for chained agents
|
|
135
136
|
/param think_exclude false
|
|
136
137
|
|
|
138
|
+
# Prevent Ollama from evicting KV-cache between requests (fixes slowdown after 10k+ tokens)
|
|
139
|
+
/param keep_alive -1
|
|
140
|
+
|
|
137
141
|
# Reset everything
|
|
138
142
|
/param clear
|
|
139
143
|
```
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"""compress — annotate and remove redundant words/phrases.
|
|
2
|
+
|
|
3
|
+
Four modes:
|
|
4
|
+
--mode rules pure rule-based (fast, deterministic, covers common patterns)
|
|
5
|
+
--mode list LLM outputs a PHRASE → reason list, then annotate (default for hybrid step)
|
|
6
|
+
--mode inline LLM rewrites text with <phrase|reason> tags inline
|
|
7
|
+
--mode hybrid rules first, then list-model for remaining text (default)
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
/flow compress <text>
|
|
11
|
+
/flow compress $ (compress last LLM reply)
|
|
12
|
+
/flow compress file: notes.txt
|
|
13
|
+
/flow compress --strip <text> (output compressed only, no annotations)
|
|
14
|
+
/flow compress --mode rules <text>
|
|
15
|
+
/flow compress --mode list <text>
|
|
16
|
+
/flow compress --mode inline <text>
|
|
17
|
+
"""
|
|
18
|
+
import re as _re
|
|
19
|
+
import os as _os
|
|
20
|
+
|
|
21
|
+
# ── rule-based patterns ───────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
_RULES = [
|
|
24
|
+
# hedges
|
|
25
|
+
(r"\bI think,?\s*", "hedge"),
|
|
26
|
+
(r"\bI believe,?\s*", "hedge"),
|
|
27
|
+
(r"\bI feel,?\s*", "hedge"),
|
|
28
|
+
(r"\bin my opinion,?\s*", "hedge"),
|
|
29
|
+
(r"\bit seems(?: that)?,?\s*","hedge"),
|
|
30
|
+
(r"\bperhaps\s+", "hedge"),
|
|
31
|
+
(r"\bmaybe\s+", "hedge"),
|
|
32
|
+
(r"\bprobably\s+", "hedge"),
|
|
33
|
+
(r"\bgenerally\s+", "hedge"),
|
|
34
|
+
(r"\busually\s+", "hedge"),
|
|
35
|
+
(r"\btypically\s+", "hedge"),
|
|
36
|
+
# filler intensifiers
|
|
37
|
+
(r"\bvery\s+", "filler"),
|
|
38
|
+
(r"\bquite\s+", "filler"),
|
|
39
|
+
(r"\brather\s+", "filler"),
|
|
40
|
+
(r"\breally\s+", "filler"),
|
|
41
|
+
(r"\bextremely\s+", "filler"),
|
|
42
|
+
(r"\babsolutely\s+", "filler"),
|
|
43
|
+
(r"\bcompletely\s+", "filler"),
|
|
44
|
+
(r"\btotally\s+", "filler"),
|
|
45
|
+
(r"\bsomewhat\s+", "filler"),
|
|
46
|
+
# empty phrases
|
|
47
|
+
(r"\bthe fact that\s+", "filler"),
|
|
48
|
+
(r"\bit is worth noting that\s+", "filler"),
|
|
49
|
+
(r"\bit should be noted that\s+", "filler"),
|
|
50
|
+
(r"\bit is important to note that\s+", "filler"),
|
|
51
|
+
(r"\bit is worth mentioning that\s+", "filler"),
|
|
52
|
+
(r"\bit is necessary to note that\s+", "filler"),
|
|
53
|
+
(r"\bnote that\s+", "filler"),
|
|
54
|
+
(r"\bin order to\s+", "filler"),
|
|
55
|
+
(r"\bI would like to take this opportunity to mention\s+that\s+", "hedge"),
|
|
56
|
+
(r"\bI would like to take this opportunity to\s+", "hedge"),
|
|
57
|
+
(r"\btake this opportunity to\s+", "hedge"),
|
|
58
|
+
(r"\bdue to the fact that\s+","filler"),
|
|
59
|
+
(r"\bas a matter of fact,?\s*","filler"),
|
|
60
|
+
(r"\bbasically\s+", "filler"),
|
|
61
|
+
(r"\bessentially\s+", "filler"),
|
|
62
|
+
(r"\bfundamentally\s+", "filler"),
|
|
63
|
+
# weak verb clusters
|
|
64
|
+
(r"\btends? to\s+", "weaken"),
|
|
65
|
+
(r"\bseems? to\s+", "weaken"),
|
|
66
|
+
(r"\bappears? to\s+", "weaken"),
|
|
67
|
+
# redundant quantifiers
|
|
68
|
+
(r"\beach and every\b", "redundant"),
|
|
69
|
+
(r"\bfirst and foremost\b", "redundant"),
|
|
70
|
+
(r"\bat this point in time\b","redundant"),
|
|
71
|
+
(r"\bin the event that\b", "redundant"),
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
_STRIP_RE = _re.compile(r'<([^|>]+)\|[^>]+>')
|
|
75
|
+
_INLINE_RE = _re.compile(r'<([^|>]+)\|([a-z]+)>')
|
|
76
|
+
|
|
77
|
+
_PROMPT_LIST = """\
|
|
78
|
+
Find redundant words and phrases in the text below.
|
|
79
|
+
Output ONLY a list, one per line: PHRASE → reason
|
|
80
|
+
Reasons: hedge, filler, redundant, weaken
|
|
81
|
+
|
|
82
|
+
Rules:
|
|
83
|
+
- PHRASE must be copied exactly from the text
|
|
84
|
+
- Never mark: technical terms, subjects, main verbs, key nouns
|
|
85
|
+
- Only mark words that can be removed without changing the core meaning
|
|
86
|
+
|
|
87
|
+
Example:
|
|
88
|
+
Text: I think cats are very nice animals that people generally tend to like a lot
|
|
89
|
+
I think → hedge
|
|
90
|
+
very → filler
|
|
91
|
+
that people generally tend to like a lot → redundant
|
|
92
|
+
|
|
93
|
+
Text: {text}
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
_PROMPT_INLINE = """\
|
|
97
|
+
Rewrite the text below with redundant words and phrases wrapped in <word|reason> tags.
|
|
98
|
+
Reasons: hedge, filler, redundant, weaken
|
|
99
|
+
Keep ALL other words exactly as they are. Do not add, remove, or reorder any words outside the tags.
|
|
100
|
+
|
|
101
|
+
Rules:
|
|
102
|
+
- Never mark: technical terms, subjects, main verbs, key nouns
|
|
103
|
+
- Only mark what can be removed without changing the core meaning
|
|
104
|
+
|
|
105
|
+
Example:
|
|
106
|
+
Input: I think cats are very nice animals that people generally tend to like a lot
|
|
107
|
+
Output: <I think|hedge> cats are <very|filler> nice animals <that people generally tend to like a lot|redundant>
|
|
108
|
+
|
|
109
|
+
Input: {text}
|
|
110
|
+
Output:"""
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# ── core functions ────────────────────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
def _apply_rules(text: str) -> tuple:
|
|
116
|
+
"""Returns (annotated_text, [(phrase, reason), ...]).
|
|
117
|
+
Searches all patterns in the ORIGINAL text, deduplicates, then annotates once."""
|
|
118
|
+
candidates = []
|
|
119
|
+
for pattern, reason in _RULES:
|
|
120
|
+
m = _re.search(pattern, text, _re.IGNORECASE)
|
|
121
|
+
if m:
|
|
122
|
+
candidates.append((m.group(0).rstrip(), reason))
|
|
123
|
+
|
|
124
|
+
# deduplicate: keep longest, remove any phrase that is a substring of a longer one
|
|
125
|
+
found = []
|
|
126
|
+
for phrase, reason in sorted(candidates, key=lambda x: -len(x[0])):
|
|
127
|
+
if not any(phrase.lower() in p.lower() for p, _ in found):
|
|
128
|
+
found.append((phrase, reason))
|
|
129
|
+
|
|
130
|
+
result = _annotate(text, found)
|
|
131
|
+
return _re.sub(r' +', ' ', result).strip(), found
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
_VALID_REASONS = {'hedge', 'filler', 'redundant', 'weaken'}
|
|
135
|
+
|
|
136
|
+
def _parse_model_list(raw: str) -> list:
|
|
137
|
+
pairs = []
|
|
138
|
+
for line in raw.splitlines():
|
|
139
|
+
line = line.strip()
|
|
140
|
+
# skip lines without a separator — they're prose/thinking output
|
|
141
|
+
sep_found = None
|
|
142
|
+
for sep in (' → ', ' -> ', ' — ', ': '):
|
|
143
|
+
if sep in line:
|
|
144
|
+
sep_found = sep
|
|
145
|
+
break
|
|
146
|
+
if not sep_found:
|
|
147
|
+
continue
|
|
148
|
+
phrase, _, reason = line.partition(sep_found)
|
|
149
|
+
# clean up list markers and stray quotes from phrase
|
|
150
|
+
phrase = phrase.strip()
|
|
151
|
+
phrase = _re.sub(r'^[-*•]\s*', '', phrase) # leading - * •
|
|
152
|
+
phrase = phrase.strip('"\'`') # surrounding quotes/backticks
|
|
153
|
+
phrase = phrase.strip()
|
|
154
|
+
reason = reason.strip().split()[0].lower().rstrip('.,;')
|
|
155
|
+
# only accept known reasons, skip malformed/thinking lines
|
|
156
|
+
if phrase and reason in _VALID_REASONS:
|
|
157
|
+
pairs.append((phrase, reason))
|
|
158
|
+
# deduplicate — keep first occurrence of each phrase
|
|
159
|
+
seen = set()
|
|
160
|
+
return [(p, r) for p, r in pairs if not (p in seen or seen.add(p))]
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _annotate(text: str, pairs: list) -> str:
|
|
164
|
+
result = text
|
|
165
|
+
for phrase, reason in sorted(pairs, key=lambda x: -len(x[0])):
|
|
166
|
+
result = _re.sub(_re.escape(phrase), f"<{phrase}|{reason}>", result, count=1)
|
|
167
|
+
return result
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _compress(annotated: str) -> str:
|
|
171
|
+
# strip annotations, handle nested cases by repeating until stable
|
|
172
|
+
text = annotated
|
|
173
|
+
for _ in range(5):
|
|
174
|
+
prev = text
|
|
175
|
+
text = _STRIP_RE.sub('', text)
|
|
176
|
+
# also clean up any leftover |reason> fragments from nesting
|
|
177
|
+
text = _re.sub(r'\|[a-z]+>', '', text)
|
|
178
|
+
text = _re.sub(r'<[^>]*>', '', text) # catch any remaining < > fragments
|
|
179
|
+
if text == prev:
|
|
180
|
+
break
|
|
181
|
+
text = _re.sub(r' +', ' ', text).strip()
|
|
182
|
+
# clean up orphan punctuation at start: ". text" → "text"
|
|
183
|
+
text = _re.sub(r'^[.,;:\-–—]+\s*', '', text)
|
|
184
|
+
return text
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _model_annotate_list(chat, text: str) -> tuple:
|
|
188
|
+
prompt = _PROMPT_LIST.format(text=text)
|
|
189
|
+
msgs = [
|
|
190
|
+
{"role": "system", "content": "You are a text editor. Output only the redundancy list."},
|
|
191
|
+
{"role": "user", "content": prompt},
|
|
192
|
+
]
|
|
193
|
+
raw = chat._stream_chat(msgs) or ""
|
|
194
|
+
print()
|
|
195
|
+
pairs = _parse_model_list(raw)
|
|
196
|
+
return _annotate(text, pairs), pairs
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _model_annotate_inline(chat, text: str) -> tuple:
|
|
200
|
+
prompt = _PROMPT_INLINE.format(text=text)
|
|
201
|
+
msgs = [
|
|
202
|
+
{"role": "system", "content": "You are a text editor. Output only the rewritten line with tags."},
|
|
203
|
+
{"role": "user", "content": prompt},
|
|
204
|
+
]
|
|
205
|
+
raw = chat._stream_chat(msgs) or ""
|
|
206
|
+
print()
|
|
207
|
+
pairs = [(p, r) for p, r in _INLINE_RE.findall(raw) if r in _VALID_REASONS]
|
|
208
|
+
seen: set = set()
|
|
209
|
+
pairs = [(p, r) for p, r in pairs if not (p in seen or seen.add(p))]
|
|
210
|
+
# raw is already annotated; clean up any stray leading/trailing prose
|
|
211
|
+
annotated = raw.strip().splitlines()[-1] if raw.strip() else text
|
|
212
|
+
return annotated, pairs
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# ── main ──────────────────────────────────────────────────────────────────────
|
|
216
|
+
|
|
217
|
+
def run(chat, args: str):
|
|
218
|
+
args = args.strip()
|
|
219
|
+
|
|
220
|
+
strip_only = "--strip" in args
|
|
221
|
+
if strip_only:
|
|
222
|
+
args = args.replace("--strip", "").strip()
|
|
223
|
+
|
|
224
|
+
mode = "hybrid"
|
|
225
|
+
m = _re.search(r'--mode\s+(\S+)', args)
|
|
226
|
+
if m:
|
|
227
|
+
mode = m.group(1)
|
|
228
|
+
args = (args[:m.start()] + args[m.end():]).strip()
|
|
229
|
+
|
|
230
|
+
if mode not in ("rules", "list", "inline", "hybrid"):
|
|
231
|
+
print(f"[compress] unknown mode '{mode}'. Use: rules, list, inline, hybrid"); return
|
|
232
|
+
|
|
233
|
+
if args.startswith("file:"):
|
|
234
|
+
fpath = args[5:].strip()
|
|
235
|
+
if not _os.path.isabs(fpath):
|
|
236
|
+
fpath = _os.path.join(_os.getcwd(), fpath)
|
|
237
|
+
try:
|
|
238
|
+
text = open(fpath, encoding="utf-8").read().strip()
|
|
239
|
+
except OSError as e:
|
|
240
|
+
print(f"[compress] {e}"); return
|
|
241
|
+
elif args == "$":
|
|
242
|
+
text = getattr(chat, "_last_output", "").strip()
|
|
243
|
+
if not text:
|
|
244
|
+
print("[compress] no last output"); return
|
|
245
|
+
else:
|
|
246
|
+
text = args
|
|
247
|
+
|
|
248
|
+
if not text:
|
|
249
|
+
print("usage: /flow compress [--mode rules|model|hybrid] [--strip] <text | $ | file: path>")
|
|
250
|
+
return
|
|
251
|
+
|
|
252
|
+
print(f"[compress] input : {text}")
|
|
253
|
+
print(f"[compress] mode : {mode}\n")
|
|
254
|
+
|
|
255
|
+
all_pairs = []
|
|
256
|
+
annotated = text
|
|
257
|
+
final_compressed = None
|
|
258
|
+
|
|
259
|
+
if mode == "rules":
|
|
260
|
+
annotated, all_pairs = _apply_rules(text)
|
|
261
|
+
|
|
262
|
+
elif mode == "list":
|
|
263
|
+
annotated, all_pairs = _model_annotate_list(chat, text)
|
|
264
|
+
|
|
265
|
+
elif mode == "inline":
|
|
266
|
+
annotated, all_pairs = _model_annotate_inline(chat, text)
|
|
267
|
+
|
|
268
|
+
elif mode == "hybrid":
|
|
269
|
+
# step 1: rules on original text
|
|
270
|
+
annotated, rule_pairs = _apply_rules(text)
|
|
271
|
+
all_pairs.extend(rule_pairs)
|
|
272
|
+
if rule_pairs:
|
|
273
|
+
print(f"[compress] rules : {len(rule_pairs)} match(es)")
|
|
274
|
+
# step 2: list-model on the clean (compressed) version of what rules left
|
|
275
|
+
clean_after_rules = _compress(annotated)
|
|
276
|
+
if clean_after_rules != _compress(text): # rules found something
|
|
277
|
+
model_input = clean_after_rules
|
|
278
|
+
else:
|
|
279
|
+
model_input = text
|
|
280
|
+
model_annotated, model_pairs = _model_annotate_list(chat, model_input)
|
|
281
|
+
model_pairs = [(p, r) for p, r in model_pairs if p not in {x[0] for x in rule_pairs}]
|
|
282
|
+
all_pairs = rule_pairs + model_pairs
|
|
283
|
+
# display: rules annotation on original text
|
|
284
|
+
annotated, _ = _apply_rules(text)
|
|
285
|
+
# compressed: sequential — rules clean first, then model strips on top
|
|
286
|
+
seq = clean_after_rules
|
|
287
|
+
for phrase, _ in model_pairs:
|
|
288
|
+
seq = _re.sub(_re.escape(phrase), '', seq, count=1, flags=_re.IGNORECASE)
|
|
289
|
+
seq = _re.sub(r'^[.,;:\-–—\s]+', '', _re.sub(r' +', ' ', seq)).strip()
|
|
290
|
+
final_compressed = seq
|
|
291
|
+
|
|
292
|
+
if not all_pairs:
|
|
293
|
+
print("[compress] no redundancies found")
|
|
294
|
+
compressed = text
|
|
295
|
+
else:
|
|
296
|
+
print(f"[compress] found : {len(all_pairs)} redundanc{'y' if len(all_pairs)==1 else 'ies'}")
|
|
297
|
+
for phrase, reason in all_pairs:
|
|
298
|
+
print(f" '{phrase}' → {reason}")
|
|
299
|
+
|
|
300
|
+
compressed = final_compressed if final_compressed is not None else _compress(annotated)
|
|
301
|
+
ratio = round((1 - len(compressed) / max(len(text), 1)) * 100)
|
|
302
|
+
|
|
303
|
+
if not strip_only:
|
|
304
|
+
print(f"\n[compress] annotated:")
|
|
305
|
+
print(f" {annotated}")
|
|
306
|
+
|
|
307
|
+
print(f"\n[compress] compressed (-{ratio}%):")
|
|
308
|
+
print(f" {compressed}")
|
|
309
|
+
|
|
310
|
+
chat._last_output = compressed
|