Skip to content

fix(mcp): make local-endpoint budgets configurable - #1856

Open
NullSense wants to merge 1 commit into
repowise-dev:mainfrom
NullSense:fix/local-endpoint-timeout-overrides
Open

fix(mcp): make local-endpoint budgets configurable#1856
NullSense wants to merge 1 commit into
repowise-dev:mainfrom
NullSense:fix/local-endpoint-timeout-overrides

Conversation

@NullSense

Copy link
Copy Markdown

Summary

  • tool_answer/config.py: _SYNTHESIS_MAX_TOKENS (1024, hardcoded) now reads REPOWISE_SYNTHESIS_MAX_TOKENS. A reasoning model spends its whole budget on hidden thinking before emitting an answer token, so the call comes back empty at the old cap; measured against nanbeige, 1024 tokens returned nothing, 8192 produced a correct, cited answer.
  • _answer_pipeline.py / _helpers.py: _EMBED_TIMEOUT_S (8.0, hardcoded) now reads REPOWISE_EMBED_TIMEOUT_S via a new embed_timeout_s(), mirroring the sibling vector_search_timeout_s(). A cold-loading local embedding model blows the old 8s budget; get_answer still exits 0 with the semantic leg silently dropped, visible only at WARNING.
  • One PR because it's one root cause: constants tuned for a warm remote service, with no override, that degrade silently on a local one. Both follow the existing pattern for REPOWISE_EMBEDDING_TIMEOUT / REPOWISE_VECTOR_SEARCH_TIMEOUT_S: an unparseable or non-positive override warns and keeps the default.

Related Issues

None.

Test Plan

  • uv run pytest tests/unit/ -q — 14242 passed, 12 skipped, 2 xfailed. 2 failures, both pre-existing on unmodified main and unrelated to this change: a git-rebase test that depends on local git config, and a timezone-sensitive episode-dating test.
  • uv run ruff check .
  • uv run repowise risk main..HEAD:
    Change risk for main..HEAD: touches files that have broken before · 90th percentile of this repo's fix-bearing files
      fix(mcp): make local-endpoint budgets configurable
      +269 / -12 lines · 7 files · 3 dirs · 2 subsystems · entropy 2.19 · author exp 0  (fix)
    
    File                                                                       Lines   Prior fixes
    packages/server/src/repowise/server/mcp_server/tool_answer/config.py         36           11.7
    packages/server/src/repowise/server/mcp_server/_helpers.py                   36            6.4
    tests/unit/server/mcp/test_answer_synthesis_timeout.py                       47            5.8
    packages/server/src/repowise/server/mcp_server/_answer_pipeline.py           19            4.9
    packages/server/src/repowise/server/mcp_server/tool_answer/synthesis.py       6            2.8
    
    Diff shape: Typical · 57th percentile of recent commits by size and spread
      About as risky as a typical commit in this repo.
    
    This flags real history: these are exactly the answer-pipeline files this fix targets, and they carry a documented run of prior fixes (config.py alone shows a recency-weighted 11.7). That matches the PR's own premise — this is a bug-prone area — rather than indicating a new problem in this diff; the full-suite result above is the direct check on that.
    (impacted-tests / health --file need a completed repowise init against this clone; that indexing run did not finish in time and is omitted rather than faked.)

Checklist

  • My code follows the project's code style
  • I have added tests for new functionality
  • All existing tests still pass
  • I have updated documentation if needed

Written with AI assistance; measurements and tests were run and verified locally.

@repowise-bot

repowise-bot Bot commented Aug 22, 2026

Copy link
Copy Markdown

✅ Health of changed files: 3.2 → 3.6 (+0.3)
⚠️ Change risk: moderate, riskier than 54% of this repo's commits.

📋 At a glance
5 hotspots touched · 2 co-change pairs left out · 5 files with recent fix history.

Files & modules (2)
  • packages (4 files)
    • .../mcp_server/_answer_pipeline.py
    • .../tool_answer/config.py
    • .../mcp_server/_helpers.py
    • .../tool_answer/synthesis.py
  • tests (1 file)
    • .../mcp/test_answer_synthesis_timeout.py

✅ Health gate: passed

📌 Before you merge

  • Run .../mcp/test_answer_agreement.py, .../mcp/test_answer_confidence_reasons.py, .../mcp/test_answer_decision_rows.py, .../mcp/test_decision_hygiene.py (+8 more): they import the changed files
  • .../tool_answer/answer.py changed together with .../tool_answer/config.py in 23 past commits and isn't in this PR
  • .../tool_answer/symbols.py changed together with .../tool_answer/config.py in 10 past commits and isn't in this PR
🔎 More signals (3)

🗺️ Change map

flowchart LR
  subgraph PR ["Changed in this PR (4 with dependents)"]
    f_packages_server_src_repowise_server_mcp_server__answer_pipeline_py[".../mcp_server/_answer_pipeline.py 🔥"]:::changed
    f_packages_server_src_repowise_server_mcp_server__helpers_py[".../mcp_server/_helpers.py 🔥"]:::changed
    f_packages_server_src_repowise_server_mcp_server_tool_answer_config_py[".../tool_answer/config.py 🔥"]:::changed
    f_packages_server_src_repowise_server_mcp_server_tool_answer_synthesis_py[".../tool_answer/synthesis.py 🔥"]:::changed
  end
  f_packages_server_src_repowise_server_mcp_server__neighbor_rerank_py[".../mcp_server/_neighbor_rerank.py"]
  f_packages_server_src_repowise_server_mcp_server__answer_pipeline_py --> f_packages_server_src_repowise_server_mcp_server__neighbor_rerank_py
  f_packages_server_src_repowise_server_mcp_server_tool_answer_answer_py[".../tool_answer/answer.py"]
  f_packages_server_src_repowise_server_mcp_server__answer_pipeline_py --> f_packages_server_src_repowise_server_mcp_server_tool_answer_answer_py
  f_packages_server_src_repowise_server_mcp_server_tool_search_py[".../mcp_server/tool_search.py"]
  f_packages_server_src_repowise_server_mcp_server__answer_pipeline_py --> f_packages_server_src_repowise_server_mcp_server_tool_search_py
  f_packages_server_src_repowise_server_mcp_server__prose_symbols_py[".../mcp_server/_prose_symbols.py"]
  f_packages_server_src_repowise_server_mcp_server__helpers_py --> f_packages_server_src_repowise_server_mcp_server__prose_symbols_py
  f_packages_server_src_repowise_server_mcp_server__helpers_py --> f_packages_server_src_repowise_server_mcp_server_tool_answer_answer_py
  f_packages_server_src_repowise_server_mcp_server_tool_answer_cache_py[".../tool_answer/cache.py"]
  f_packages_server_src_repowise_server_mcp_server__helpers_py --> f_packages_server_src_repowise_server_mcp_server_tool_answer_cache_py
  f_packages_server_src_repowise_server_mcp_server_tool_answer_evidence_py[".../tool_answer/evidence.py"]
  f_packages_server_src_repowise_server_mcp_server__helpers_py --> f_packages_server_src_repowise_server_mcp_server_tool_answer_evidence_py
  f_packages_server_src_repowise_server_mcp_server_tool_answer_config_py --> f_packages_server_src_repowise_server_mcp_server_tool_answer_answer_py
  f_packages_server_src_repowise_server_mcp_server_tool_answer_bodies_py[".../tool_answer/bodies.py"]
  f_packages_server_src_repowise_server_mcp_server_tool_answer_config_py --> f_packages_server_src_repowise_server_mcp_server_tool_answer_bodies_py
  f_packages_server_src_repowise_server_mcp_server_tool_answer_config_py --> f_packages_server_src_repowise_server_mcp_server_tool_answer_cache_py
  f_packages_server_src_repowise_server_mcp_server_tool_answer_confidence_py[".../tool_answer/confidence.py"]
  f_packages_server_src_repowise_server_mcp_server_tool_answer_config_py --> f_packages_server_src_repowise_server_mcp_server_tool_answer_confidence_py
  f_packages_server_src_repowise_server_mcp_server__server_py[".../mcp_server/_server.py"]
  f_packages_server_src_repowise_server_mcp_server_tool_answer_synthesis_py --> f_packages_server_src_repowise_server_mcp_server__server_py
  f_packages_server_src_repowise_server_mcp_server_tool_answer_synthesis_py --> f_packages_server_src_repowise_server_mcp_server_tool_answer_answer_py
  more(["+24 more dependents"])
  PR --> more
  w_packages_server_src_repowise_server_mcp_server_tool_answer_answer_py(["⚠️ .../tool_answer/answer.py changed together 23×, not in PR"]):::warn
  f_packages_server_src_repowise_server_mcp_server_tool_answer_config_py -.- w_packages_server_src_repowise_server_mcp_server_tool_answer_answer_py
  w_packages_server_src_repowise_server_mcp_server_tool_answer_symbols_py(["⚠️ .../tool_answer/symbols.py changed together 10×, not in PR"]):::warn
  f_packages_server_src_repowise_server_mcp_server_tool_answer_config_py -.- w_packages_server_src_repowise_server_mcp_server_tool_answer_symbols_py
  t_tests_unit_server_mcp_test_answer_agreement_py(["✅ .../mcp/test_answer_agreement.py"]):::guard
  t_tests_unit_server_mcp_test_answer_agreement_py -.-> f_packages_server_src_repowise_server_mcp_server__answer_pipeline_py
  t_tests_unit_server_mcp_test_decision_hygiene_py(["✅ .../mcp/test_decision_hygiene.py"]):::guard
  t_tests_unit_server_mcp_test_decision_hygiene_py -.-> f_packages_server_src_repowise_server_mcp_server__helpers_py
  t_tests_unit_server_mcp_test_answer_cache_py(["✅ .../mcp/test_answer_cache.py"]):::guard
  t_tests_unit_server_mcp_test_answer_cache_py -.-> f_packages_server_src_repowise_server_mcp_server_tool_answer_config_py
  classDef changed fill:#dbeafe,stroke:#1d4ed8,color:#1e3a5f
  classDef warn fill:#fef3c7,stroke:#b45309,color:#78350f
  classDef guard fill:#dcfce7,stroke:#15803d,color:#14532d
Loading

Solid arrows: code that imports the changed files (33 direct dependents, from the last indexed snapshot). Dashed: history/tests.

🔥 Hotspots touched (5)

  • .../mcp_server/_answer_pipeline.py: 15 commits/90d, 13 dependents · primary owner: Raghav Chamadiya (82%)
  • .../mcp/test_answer_synthesis_timeout.py: 7 commits/90d, 0 dependents · primary owner: Raghav Chamadiya (99%)
  • .../tool_answer/config.py: 27 commits/90d, 21 dependents · primary owner: Swati Ahuja (59%)
2 more
  • .../mcp_server/_helpers.py: 11 commits/90d, 33 dependents · primary owner: Raghav Chamadiya (91%)
  • .../tool_answer/synthesis.py: 6 commits/90d, 6 dependents · primary owner: Swati Ahuja (51%)

🔗 Hidden coupling (1 file)

  • .../tool_answer/config.py co-changes with these files (not in this PR):
    • .../tool_answer/answer.py (23×, 🔴 strong)
    • .../tool_answer/symbols.py (10×, 🟡 notable)

👀 Suggested reviewers @RaghavChamadiya


📊 See the full report for this PR
Your repo map with this PR's blast radius lit up, every caller of the contracts it changes, and health before and after. No sign-in. · ⭐ Star Repowise · 📥 Install bot · Silence on a single PR with [skip repowise] in the title · Per-repo toggle on repowise.dev/settings?tab=bot · Updated 2026-08-22 15:46 UTC

@Ayush7614 Ayush7614 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified: pytest tests/unit/server/mcp/test_answer_synthesis_timeout.py tests/unit/server/mcp/test_embed_timeout.py -q 76 passed. Makes two hardcoded budgets configurable (REPOWISE_SYNTHESIS_MAX_TOKENS for reasoning models spending budget on hidden thinking, REPOWISE_EMBED_TIMEOUT_S via embed_timeout_s() mirroring vector_search_timeout_s()) with validate-and-warn fallback, correct 120s cap, and updated degraded message advertising the env var. Hotspot history (config.py 11.7 fixes) matches the bug-prone area being fixed — not a new risk. LGTM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants