You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Improve LLM debugging, repair, retry feedback, and CLI output
- Add --debug support to fingerprint_style.py and apply_fingerprint.py for jq-formatted parsed LLM JSON emitted to stderr
- Forward debug and author-name options through shell wrappers, including local db-priv/stylo.sh
- Harden apply_fingerprint JSON parsing with deterministic repair for common malformed quoted strings before falling back to LLM repair
- Strengthen apply prompts to require escaped double quotes in JSON string fields
- Add forced-person pronoun mitigation with deterministic sentence repair and sentence-only LLM repair before full chunk retries
- Add --author-name handling for --3rd-person rewrites so prompts can occasionally use the author name, especially after headings
- Improve style retry feedback with prioritized failed constraints, actual/target measurements, response diagnostics, and preservation instructions
- Add regression coverage for JSON quote repair, author-name third-person prompting, pronoun repair, and actionable style retry feedback
- Redesign CLI output for apply/fingerprint flows with compact colorized box-drawing tables, streaming headers, row separators, wrapped cells, consolidated final result output, and NO_COLOR/CLICOLOR support
- Update README.md and AGENTS.md for new CLI flags, repair/retry behavior, pronoun handling, debug output, and console formatting
Copy file name to clipboardExpand all lines: AGENTS.md
+9-6Lines changed: 9 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -63,7 +63,7 @@ Avoid ambiguous terms like “clone” in public documentation.
63
63
- Normalize verbose/duplicative `controls.rewrite_policy` clauses and filter `priority_order` to short tokens before writing the fingerprint
64
64
- Normalize lexicon spelling to a US baseline (except literal hard avoids)
65
65
- CLI short flags: `-c` (config, optional; defaults to `./config.llm.json` if present, else next to script), `-a` (archive), `-o` (out), `-v` (verbose)
- Defaults: if `--profile-id` or `--author-name` are omitted, both default to the output filename without the `.json` extension
68
68
69
69
-`apply_fingerprint.py`
@@ -75,8 +75,9 @@ Avoid ambiguous terms like “clone” in public documentation.
75
75
- Preserve blockquotes, reference sections, footnotes, and inline citations verbatim (excluded from style transfer)
76
76
- Strip embedded BASE64 images before prompt and re-insert after rewrite
77
77
- Call LLM with fingerprint + measurements
78
+
- Parse LLM JSON with deterministic repair for common malformed quote escaping in `final_markdown`, `chunk_summary`, deviation `reason` fields, and `self_check.notes` before falling back to LLM repair
78
79
- Enforce preservation of meaning
79
-
- Score style compliance locally and retry with delta feedback (disable with `--no-style-retry`)
80
+
- Score style compliance locally and retry with actionable feedback (prioritized failed constraints, actual/target measurements, response diagnostics, and preservation instructions; disable with `--no-style-retry`)
80
81
- Apply `general-guidelines.md` humanizer rules when available, using an LLM parser by default then deterministically filtering out conflicts (disable with `--no-humanizer-llm-parse` or `--no-humanizer-guidelines`)
81
82
- Cache parsed humanizer rules in `humanizer_rules.cache.json` (script directory) and re-parse only when guidelines change
82
83
- Sanitize trailing parenthetical/comma qualifiers in headings when enabled (humanizer_mandatory)
@@ -87,11 +88,12 @@ Avoid ambiguous terms like “clone” in public documentation.
- Normalize verbose/duplicative `controls.rewrite_policy` clauses and filter `priority_order` when loading a fingerprint
89
90
- Normalize lexical avoidance checks to US spelling for matching, then apply local spelling to final output
91
+
- In forced-person mode, attempt deterministic sentence-level pronoun repair and sentence-only LLM repair before resending the whole chunk
90
92
- Return rewritten text and deviations
91
-
-In verbose mode, report per-chunk attempt scores and when best-attempt selection overrides the last attempt
93
+
-Console output uses compact colorized box-drawing tables for run settings, mode, artifacts, counts, and metrics (`NO_COLOR=1` or `CLICOLOR=0` disables ANSI colors); table headers use a very dark blue background with bright text; final apply output consolidates artifacts, count deltas, and metrics into one result table; compatible rows stream under one header, headers use double-line separators, logical rows use single-line separators, packed setting/value groups use double vertical separators between groups, status lines close/restart table sections, and long cells wrap onto aligned continuation lines; verbose mode also reports grouped tuning, retry budgets, chunk token summaries, concise retry lines, and best-attempt selection details
92
94
- CLI short flags: `-c` (config, optional; defaults to `./config.llm.json` if present, else next to script), `-f` (fingerprint; adds `.json` if missing), `-i` (input), `-o` (out), `-v` (verbose)
- Overrides: `--1st-person` / `--2nd-person` / `--3rd-person` force narrative voice regardless of fingerprint; with `--3rd-person`, `--author-name AUTHOR_NAME` asks the LLM to occasionally use that name instead of he/she/they, including once after headings when natural
95
97
- Runtime overrides: `--local-spelling {none|canadian|australian|british|us}` (applies to both LLM + deterministic rules), `--local-spelling-llm ...`, `--local-spelling-rules ...`, `--perplexity {default|low|medium|high|extreme}`, `--roster [N]` (optional seeded chunk-level roster shuffle), and `--seed [N]` (omitted value or `0` => random run seed)
96
98
97
99
-`fingerprint_api.py`
@@ -339,6 +341,7 @@ Always handle:
339
341
340
342
Current strategy:
341
343
- Attempt strict parse
344
+
- Apply deterministic repair for common malformed JSON string quoting in apply outputs
342
345
- If failure, call LLM repair mode
343
346
344
347
Preserve this pattern.
@@ -427,7 +430,7 @@ High‑value next steps, in priority order:
Copy file name to clipboardExpand all lines: README.md
+17-14Lines changed: 17 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -595,7 +595,7 @@ This project does not compute classic language-model perplexity directly. In pra
595
595
596
596
Quick preset option:
597
597
- Set `perplexity_level` in `config.tunables.json`, or pass `--perplexity {default|low|medium|high|extreme}` for a one-run override.
598
-
-Regular logs print the active level; verbose logs print the effective knob values.
598
+
-Normal output includes the active mode/perplexity in the compact run header; verbose output prints the effective tuning values.
599
599
600
600
Recommended workflow:
601
601
@@ -649,7 +649,7 @@ Recommended workflow:
649
649
650
650
<u>Troubleshooting: non-fiction detected as fiction (quotes getting rewritten)</u>
651
651
652
-
If you see `Detected fiction: quoted passages may be rewritten.` but your document is non-fiction and you want multi-word quotations preserved:
652
+
If the run header shows `Mode fiction (detected); quotes mutable` but your document is non-fiction and you want multi-word quotations preserved:
653
653
654
654
1. Quick fix (per run): force the mode explicitly.
655
655
-`apply_fingerprint.py`: pass `--non-fiction`
@@ -694,7 +694,7 @@ If you see `Detected fiction: quoted passages may be rewritten.` but your docume
694
694
695
695
**Style/Voice Retry Budgets (`style_retry`)**
696
696
*These budgets cap compliance retries and forced-person voice retries for each chunk.*
697
-
-`style_retry.enabled` (boolean): enable/disable the delta‑feedback retry pass after measuring style compliance.
697
+
-`style_retry.enabled` (boolean): enable/disable the actionable feedback retry pass after measuring style compliance.
698
698
-`style_retry.threshold` (0–1): retry when compliance score is below this threshold (project config currently `0.60`; internal fallback default `0.75`). Lower values trigger fewer retries (more permissive); higher values trigger more retries (stricter). `0.0` effectively disables threshold-based retries, while `1.0` retries unless the output is nearly perfect.
699
699
-`style_retry.max_retries` (integer): maximum additional retry passes for the style loop after the initial attempt.
700
700
-`style_retry.voice_max_retries` (integer): maximum retry passes for the forced-person voice loop (`--1st-person` / `--2nd-person` / `--3rd-person`). If omitted, it inherits `style_retry.max_retries`.
@@ -713,7 +713,7 @@ Under the hood, the compliance score is a weighted average of section-level simi
713
713
- Histogram sections (sentence length, paragraph length): distance is total variation, `d = 0.5 * sum_i |p_i - q_i|` (ranges 0-1), then `score = 1 - d`.
714
714
- Scalar/rate sections (punctuation rates, stance signals, rhetoric moves, epistemic profile, syntax texture, etc.): distance is a clipped relative error, `d = |out - target| / max(|target|, 1)`, then `score = 1 - clip(d, 0, 1)`. Multi-field sections average their per-field distances before scoring.
715
715
716
-
Section weights come from `fingerprint.validators.weights` when present; otherwise, sections are averaged equally. In verbose logs, the printed `compliance score: X.XXX` is this aggregate value.
716
+
Section weights come from `fingerprint.validators.weights` when present; otherwise, sections are averaged equally. In verbose logs, the per-attempt `score=X.XXX`value is this aggregate compliance score.
717
717
718
718
<u>How to pick a threshold:</u>
719
719
@@ -757,15 +757,17 @@ All thresholds are conservative defaults. Lowering a threshold increases the lik
Controls the sleep schedule for the transport retries above.
759
759
-`config.llm.json:max_retries` (second use in apply path):
760
-
The chunk-rewrite loop also uses this budget to recover invalid model payloads (for example missing/empty `final_markdown`), re-calling the model before falling back to split recovery or verbatim preserve.
760
+
The chunk-rewrite loop also uses this budget to recover invalid model payloads (for example missing/empty `final_markdown`), re-calling the model before falling back to split recovery or verbatim preserve. Before invoking LLM repair, the apply parser attempts deterministic repair for common malformed JSON string quoting in `final_markdown`, `chunk_summary`, deviation `reason` fields, and `self_check.notes`.
If local compliance score is below threshold, a style retry pass is attempted (subject to `style_retry.max_retries`).
764
+
If local compliance score is below threshold, a style retry pass is attempted (subject to `style_retry.max_retries`). Retry prompts include prioritized failed constraints, actual vs target measurements, response diagnostics such as long sentences/repetition, and explicit preservation instructions.
765
765
-`style_retry.max_retries`:
766
766
Sets retry budget for the style loop (additional passes after the base attempt).
767
767
-`style_retry.voice_max_retries`:
768
768
Sets retry budget for the voice loop when forced-person mode is enabled. If absent, uses `style_retry.max_retries`.
769
+
- Forced-person voice repair:
770
+
Before consuming a full voice retry, the apply path first attempts high-confidence deterministic sentence repairs, then an optional sentence-only LLM repair for remaining violating sentences. Full chunk retry is used only if those local/micro repairs do not satisfy the forced-person check.
769
771
-`humanization_controller.max_feedback_retries`:
770
772
Caps only how many style retries carry controller-overlay delta feedback. It does not increase retry count; it only changes feedback content.
771
773
@@ -774,12 +776,13 @@ All thresholds are conservative defaults. Lowering a threshold increases the lik
774
776
- Base attempt is always 1.
775
777
- Style-only mode: up to `1 + style_retry.max_retries` attempts.
776
778
- Forced-person mode:
779
+
- Before a full voice retry, sentence-level deterministic and micro-LLM repairs may resolve pronoun violations without resending the whole chunk.
777
780
- Voice loop can consume up to `style_retry.voice_max_retries` additional attempts (or `style_retry.max_retries` if voice cap is unset).
778
781
- Style loop can then consume up to `style_retry.max_retries` additional attempts.
779
782
- Total attempts can therefore approach `1 + voice_cap + style_retry.max_retries` (plus transport retries inside each call).
780
783
- Each attempt may itself contain up to `1 + config.llm.max_retries` transport attempts at HTTP level.
781
784
782
-
In verbose mode, per-chunk logs show attempt number, compliance score, threshold, and whether best-attempt replacement was used after retries were exhausted.
785
+
Console output is intentionally compact and table-oriented: normal runs print a short run header, mode table, and one consolidated final result table for artifacts, count deltas, and metrics. In verbose mode, grouped settings, retry budgets, token budgets, chunk token min/avg/max, metric scores, concise retry lines, and best-attempt replacement details are shown in compact colorized box-drawing tables where useful. Table headers use a very dark blue background with bright text. Compatible table rows stream under one header; double rules separate headers from data, single rules separate logical rows, and packed setting/value groups use double vertical separators between groups. Non-table status lines close the table so the next table reprints headers. Long cells wrap onto aligned continuation lines. Set `NO_COLOR=1` or `CLICOLOR=0` to disable ANSI colors.
783
786
784
787
---
785
788
@@ -832,7 +835,7 @@ Alternatively, use the wrapper script:
832
835
--author-name "Me"
833
836
```
834
837
835
-
To specify a non-default configuration path, pass `-c/--config`. If `--profile-id` or `--author-name` are not provided, they default to the output filename without the `.json` extension (for example, `my_fingerprint`). Progress logging is enabled with `-v/--verbose`.
838
+
To specify a non-default configuration path, pass `-c/--config`. If `--profile-id` or `--author-name` are not provided, they default to the output filename without the `.json` extension (for example, `my_fingerprint`). Normal output is compact; progress details are enabled with `-v/--verbose`. To inspect LLM JSON responses, pass `--debug`; each parsed response is emitted to stderr as a jq-formatted JSON object.
836
839
837
840
By default, common phrases are validated using an additional LLM pass to filter out OCR errors and citation fragments. This can be disabled via `--no-phrase-validation`.
838
841
@@ -864,23 +867,23 @@ Alternatively, use the wrapper script:
864
867
-i draft.md
865
868
```
866
869
867
-
Specify a non-default configuration path with `-c/--config`. Progress logging is enabled with `-v/--verbose`. `-f/--fingerprint` appends `.json` if no extension is given. Long inputs are chunked automatically based on `max_prompt_tokens`; override this with `--max-prompt-tokens`.
870
+
Specify a non-default configuration path with `-c/--config`. Normal output is compact; progress details are enabled with `-v/--verbose`. To inspect LLM JSON responses, pass `--debug`; each parsed response is emitted to stderr as a jq-formatted JSON object. `-f/--fingerprint` appends `.json` if no extension is given. Long inputs are chunked automatically based on `max_prompt_tokens`; override this with `--max-prompt-tokens`.
868
871
869
-
Style compliance is scored locally. If the score falls below the threshold, the system performs bounded retry passes according to `style_retry` tunables (or CLI overrides) and produces delta feedback between attempts (disable with `--no-style-retry`, adjust with `--style-retry-threshold` or `--max-style-retries`).
872
+
Style compliance is scored locally. If the score falls below the threshold, the system performs bounded retry passes according to `style_retry` tunables (or CLI overrides) and produces actionable feedback between attempts: top failed constraints, actual vs target measurements, response diagnostics, and preservation instructions (disable with `--no-style-retry`, adjust with `--style-retry-threshold` or `--max-style-retries`).
870
873
871
874
If `general-guidelines.md` is present in the repository root or next to the scripts, its humanization rules (adapted from softaworks/agent-toolkit by @leonardocouy) are parsed with an LLM by default. Deterministically conflicting guidance (based on fingerprint signals such as em-dash rate, hedging or first-person use) is dropped before prompting. This introduces one additional LLM call when enabled. Parsed rules are cached in `humanizer_rules.cache.json` next to the scripts and are only re-parsed when `general-guidelines.md` changes. LLM parsing can be disabled via `--no-humanizer-llm-parse`, or the guidelines can be disabled entirely via `--no-humanizer-guidelines`.
872
875
873
-
Pronoun override flags let you force the narrative voice regardless of the fingerprint: `--1st-person`, `--2nd-person`, or `--3rd-person`.
876
+
Pronoun override flags let you force the narrative voice regardless of the fingerprint: `--1st-person`, `--2nd-person`, or `--3rd-person`. When `--3rd-person` is combined with `--author-name AUTHOR_NAME`, the LLM is instructed to occasionally use that name instead of he/she/they where it reads naturally, including once after each Markdown heading when the following prose naturally refers to the author/narrator.
When a pronoun override is active, each chunk is checked for "wrong-person" pronouns used in subject-like roles. If violations are detected, the chunk is re-prompted with voice-specific feedback, up to the configured voice retry budget.
880
+
When a pronoun override is active, each chunk is checked for "wrong-person" pronouns used in subject-like roles. If violations are detected, the system first tries deterministic sentence-level repair and then sentence-only LLM repair before spending a full chunk voice retry.
0 commit comments