From 1bda37f54c7584468cf68440257c0110a477dfe6 Mon Sep 17 00:00:00 2001 From: lztmdrclht <1851937751@qq.com> Date: Sun, 26 Jul 2026 16:16:31 +0800 Subject: [PATCH 1/5] fix:Rescan ready files after spec producers exit to avoid skipping verification Fixes #155 --- fm-agent.toml | 6 +++--- install.sh | 2 +- src/verification.py | 35 ++++++++++++++++++++++++++++------- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/fm-agent.toml b/fm-agent.toml index 8c3f5b21..a0b351f6 100644 --- a/fm-agent.toml +++ b/fm-agent.toml @@ -6,9 +6,9 @@ # What each setting does, with defaults: see docs/configuration.md [llm] -name = "anthropic/claude-sonnet-4.6" # LLM_MODEL -provider = "openrouter" # OPENCODE_MODEL_PROVIDER — the OpenCode provider id FM-Agent generates -base_url = "https://openrouter.ai/api/v1" # LLM_API_BASE_URL +name = "deepseek-v4-flash" # LLM_MODEL +provider = "deepseek" # OPENCODE_MODEL_PROVIDER — the OpenCode provider id FM-Agent generates +base_url = "https://api.deepseek.com/v1" # LLM_API_BASE_URL backend = "opencode" # FM_AGENT_MODEL_BACKEND — opencode | auto | codex-cli | claude-cli effort = "" # LLM_EFFORT — reasoning-effort hint ("", low, medium, high) api_style = "openai" # LLM_API_STYLE — endpoint style for the OpenCode adapter: openai | anthropic diff --git a/install.sh b/install.sh index f1e297f3..610685af 100755 --- a/install.sh +++ b/install.sh @@ -153,7 +153,7 @@ else curl -fsSL https://opencode.ai/install | bash fi - # ---------- oh-my-openagent plugin ---------- + ---------- oh-my-openagent plugin ---------- if command -v bunx &>/dev/null; then echo "[ok] bun found" else diff --git a/src/verification.py b/src/verification.py index 2ebec19e..cc25b9ee 100644 --- a/src/verification.py +++ b/src/verification.py @@ -116,6 +116,16 @@ def streaming_reasoner( validation_futures = {} submitted = set() + def _submit_file(file_path, ext): + # Submit a ready file for reasoning/verification. + submitted.add(file_path) + language = EXT_TO_LANG.get(ext, "C") + future = executor.submit( + _verify_single_file, file_path, input_dir, output_dir, language, work_dir, resume + ) + reasoning_futures[future] = file_path + logging.info(f"Submitted: {file_path}") + while True: # Scan for new ready files for root, _, files in os.walk(input_dir): @@ -134,13 +144,7 @@ def streaming_reasoner( continue # File is ready and not yet submitted or processed. - submitted.add(file_path) - language = EXT_TO_LANG.get(ext, "C") - future = executor.submit( - _verify_single_file, file_path, input_dir, output_dir, language, work_dir, resume - ) - reasoning_futures[future] = file_path - logging.info(f"Submitted: {file_path}") + _submit_file(file_path, ext) # Collect completed reasoning futures (non-blocking) done = [f for f in reasoning_futures if f.done()] @@ -221,6 +225,23 @@ def streaming_reasoner( # Detect if spec generation subprocesses exited before all files are ready _all_procs = spec_procs if spec_procs else None if _all_procs is not None and all(_spec_task_done(p) for p in _all_procs): + # Final scan: producers may have finished writing markers after the + # last regular scan, so check remaining expected files once more. + newly_ready = False + for file_path in (expected_files or set()) - processed - submitted: + ext = os.path.splitext(file_path)[1] + if ext not in EXT_TO_LANG: + continue + if not is_file_ready(file_path): + continue + _submit_file(file_path, ext) + newly_ready = True + if newly_ready: + logging.info( + "All spec producers done; rescan found newly ready files, submitting them." + ) + continue + unready = (expected_files or set()) - processed if unready and not reasoning_futures and not validation_futures: exit_codes = [_spec_task_exit_code(p) for p in _all_procs] From b9a19828e772e09463b9ec2186923e9df1756542 Mon Sep 17 00:00:00 2001 From: Long Hongtan <61901657+lztmdrclht@users.noreply.github.com> Date: Sun, 26 Jul 2026 16:26:16 +0800 Subject: [PATCH 2/5] Update fm-agent.toml --- fm-agent.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fm-agent.toml b/fm-agent.toml index 7be09d37..df0ab020 100644 --- a/fm-agent.toml +++ b/fm-agent.toml @@ -6,9 +6,9 @@ # What each setting does, with defaults: see docs/configuration.md [llm] -name = "deepseek-v4-flash" # LLM_MODEL -provider = "deepseek" # OPENCODE_MODEL_PROVIDER — the OpenCode provider id FM-Agent generates -base_url = "https://api.deepseek.com/v1" # LLM_API_BASE_URL +name = "anthropic/claude-sonnet-4.6" # LLM_MODEL +provider = "openrouter" # OPENCODE_MODEL_PROVIDER — the OpenCode provider id FM-Agent generates +base_url = "https://openrouter.ai/api/v1" # LLM_API_BASE_URL backend = "opencode" # FM_AGENT_MODEL_BACKEND — opencode | auto | codex-cli | claude-cli effort = "" # LLM_EFFORT — reasoning-effort hint ("", low, medium, high) api_style = "openai" # LLM_API_STYLE — endpoint style for the OpenCode adapter: openai | anthropic From 23d42fa3502b810f6de90f96f4fb65e3b6bbbca1 Mon Sep 17 00:00:00 2001 From: lztmdrclht <1851937751@qq.com> Date: Sun, 26 Jul 2026 21:25:31 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E6=96=B0=E5=A2=9Efailed=EF=BC=8C=E6=A0=87?= =?UTF-8?q?=E8=AE=B0=E9=AA=8C=E8=AF=81=E5=A4=B1=E8=B4=A5=E7=9A=84=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E3=80=82=E4=BF=AE=E6=94=B9resume=E7=9A=84=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E6=8D=95=E8=8E=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/verification.py | 50 ++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/verification.py b/src/verification.py index 75f66d96..62ba915b 100644 --- a/src/verification.py +++ b/src/verification.py @@ -115,6 +115,7 @@ def streaming_reasoner( reasoning_futures = {} validation_futures = {} submitted = set() + failed = set() # files that raised unhandled errors; don't retry forever def _submit_file(file_path, ext): # Submit a ready file for reasoning/verification. @@ -140,6 +141,8 @@ def _submit_file(file_path, ext): continue if file_path in submitted: continue + if file_path in failed: + continue if not is_file_ready(file_path): continue @@ -183,6 +186,7 @@ def _submit_file(file_path, ext): print(f"[{completed_count}/{num_functions}] {rel_path}: {label}") except Exception as exc: logging.error(f"Error verifying {fpath}: {exc}") + failed.add(fpath) # Collect completed validation futures (non-blocking) val_done = [f for f in validation_futures if f.done()] @@ -215,7 +219,7 @@ def _submit_file(file_path, ext): # Check if all expected files have been processed all_reasoning_done = ( expected_files is not None - and processed >= expected_files + and (processed | failed) >= expected_files and not reasoning_futures ) if all_reasoning_done and not validation_futures: @@ -228,7 +232,7 @@ def _submit_file(file_path, ext): # Final scan: producers may have finished writing markers after the # last regular scan, so check remaining expected files once more. newly_ready = False - for file_path in (expected_files or set()) - processed - submitted: + for file_path in (expected_files or set()) - processed - submitted - failed: ext = os.path.splitext(file_path)[1] if ext not in EXT_TO_LANG: continue @@ -242,24 +246,32 @@ def _submit_file(file_path, ext): ) continue - unready = (expected_files or set()) - processed - if unready and not reasoning_futures and not validation_futures: + unready = (expected_files or set()) - processed - failed + if not reasoning_futures and not validation_futures: exit_codes = [_spec_task_exit_code(p) for p in _all_procs] - if not processed: - # No function got a spec at all – this is an error - logging.warning( - f"Spec generation process(es) exited (codes {exit_codes}) " - f"but no .spec.json/.info.json sidecar pairs were created." - ) - else: - # Some functions are missing specs; leave them pending for retry. - logging.warning( - f"Spec generation process(es) exited (codes {exit_codes}), " - f"{len(unready)} files missing specs, leaving them pending for retry." + if unready: + if not processed: + # No function got a spec at all – this is an error + logging.warning( + f"Spec generation process(es) exited (codes {exit_codes}) " + f"but no .spec.json/.info.json sidecar pairs were created." + ) + else: + # Some functions are missing specs; leave them pending for retry. + logging.warning( + f"Spec generation process(es) exited (codes {exit_codes}), " + f"{len(unready)} files missing specs, leaving them pending for retry." + ) + for uf in sorted(unready): + rel_path = os.path.relpath(uf, proj_dir) if proj_dir else os.path.relpath(uf, input_dir) + print(f"[pending] {rel_path}: no spec yet; will retry") + if failed: + logging.error( + f"{len(failed)} file(s) failed verification and will not be retried." ) - for uf in sorted(unready): - rel_path = os.path.relpath(uf, proj_dir) if proj_dir else os.path.relpath(uf, input_dir) - print(f"[pending] {rel_path}: no spec yet; will retry") + for ff in sorted(failed): + rel_path = os.path.relpath(ff, proj_dir) if proj_dir else os.path.relpath(ff, input_dir) + print(f"[failed] {rel_path}: verification error") break time.sleep(poll_interval) @@ -298,7 +310,7 @@ def _verify_single_file(file_path, input_dir, output_dir, language, work_dir=Non verdict = existing.get("verdict", "ERROR") logging.info(f"Already verified, skipping: {file_path} (verdict={verdict})") return file_path, verdict - except (json.JSONDecodeError, OSError): + except (json.JSONDecodeError, OSError, UnicodeDecodeError): pass # re-verify if existing result is corrupted os.makedirs(os.path.dirname(output_path), exist_ok=True) From ef7c3505fe0a54b31c42b2549f9e1a368c6313d7 Mon Sep 17 00:00:00 2001 From: Long Hongtan <61901657+lztmdrclht@users.noreply.github.com> Date: Sun, 26 Jul 2026 21:28:59 +0800 Subject: [PATCH 4/5] Comment out oh-my-openagent plugin section Commented out the section for the oh-my-openagent plugin. --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 610685af..f1e297f3 100755 --- a/install.sh +++ b/install.sh @@ -153,7 +153,7 @@ else curl -fsSL https://opencode.ai/install | bash fi - ---------- oh-my-openagent plugin ---------- + # ---------- oh-my-openagent plugin ---------- if command -v bunx &>/dev/null; then echo "[ok] bun found" else From 53c03f88bd859fcbb13c7e0c005f22921cb25316 Mon Sep 17 00:00:00 2001 From: lztmdrclht <1851937751@qq.com> Date: Sun, 26 Jul 2026 21:45:49 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E6=8B=86=E5=88=86failed=E4=B8=8Eprocessed?= =?UTF-8?q?=E5=88=A4=E6=96=AD=EF=BC=8C=E7=8B=AC=E7=AB=8B=E6=8A=A5=E5=91=8A?= =?UTF-8?q?failed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/verification.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/verification.py b/src/verification.py index 62ba915b..909a5f29 100644 --- a/src/verification.py +++ b/src/verification.py @@ -216,16 +216,33 @@ def _submit_file(file_path, ext): except Exception as exc: logging.error(f"Validation error for {fpath}: {exc}") - # Check if all expected files have been processed + # Check if all expected files have been processed successfully all_reasoning_done = ( expected_files is not None - and (processed | failed) >= expected_files + and processed >= expected_files and not reasoning_futures ) if all_reasoning_done and not validation_futures: logging.info("All files verified and validated. Done.") break + # Terminal state: every expected file is either processed or failed. + # Report failures explicitly instead of claiming success. + all_terminal = ( + expected_files is not None + and (processed | failed) >= expected_files + and not reasoning_futures + and not validation_futures + ) + if all_terminal and failed: + logging.error( + f"All files finished, but {len(failed)} file(s) failed verification." + ) + for ff in sorted(failed): + rel_path = os.path.relpath(ff, proj_dir) if proj_dir else os.path.relpath(ff, input_dir) + print(f"[failed] {rel_path}: verification error") + break + # Detect if spec generation subprocesses exited before all files are ready _all_procs = spec_procs if spec_procs else None if _all_procs is not None and all(_spec_task_done(p) for p in _all_procs):