Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion extensions/reddog/INTERFACE.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ Model and context routing:
- Principal/synthesis default: `z-ai/glm-5.2`.
- Adversarial critic default: `deepseek/deepseek-v4-pro`.
- Implementation critic default: `moonshotai/kimi-k2.7-code`.
- Long-horizon reasoning critic default: `moonshotai/kimi-k3` with mandatory `max` reasoning, no temperature parameter, and a receipt-recorded 4096-token critic budget.
- Long-horizon reasoning critic default: `moonshotai/kimi-k3` with mandatory `max` reasoning, no temperature parameter, and a receipt-recorded 4096-token floor for every direct completion call. An explicit direct selection or receipt-backed signed promotion may place K3 in single, principal, or synthesis roles; this bridge does not itself promote a champion, change defaults, open an OpenClaw execution valve, or dispatch Hermes.
- REGULAR smoke/simple prompts auto-route to `openrouter_single` with the GLM principal and `wsp_holo` HoloIndex grounding (no Fusion panel, Skillz, or git).
- Context is not a 012-facing selector; it is resolved from WSP_15 tier.
- Skillz/Wardrobe/Rolodex/OpenClaw/Hermes discovery is context only. RedDog may recommend a governed handoff, but this extension cannot execute it.
Expand All @@ -322,6 +322,7 @@ Review packet additions:
- `resolved_context`
- `principal_model`
- `panel_models`
- direct `requested_max_tokens` and provider-effective `effective_max_tokens`; manual Fusion `requested_max_tokens`, `role_max_tokens`, and `panel_max_tokens`
- `mode_selection_reasoning`
- `work_focus_digest` (`hash`, `excerpt`, `length` - redacted)
- `wsp_prompt_digest` (`hash`, `excerpt`, `length` - redacted)
Expand Down
8 changes: 8 additions & 0 deletions extensions/reddog/ModLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

# ModLog - RedDog Extension

## 2026-07-18 - REDDOG_KIMI_K3_ALL_ROLE_RUNTIME_BUDGET_HARDENING_PHASE1 (0.4.2 unchanged)

- Preserved Kimi K3 as the default long-horizon critic while applying its 4096-token floor, mandatory `max` reasoning, and no-temperature contract to every exact `moonshotai/kimi-k3` direct completion call, including explicit single use and receipt-backed principal/synthesis selection.
- Added truthful direct `requested_max_tokens` / `effective_max_tokens` receipts and retained manual Fusion requested, per-role, and per-panel effective budget receipts; non-K3 budgets remain unchanged.
- This compatibility hardening does not promote K3 to champion, change RedDog defaults, open an OpenClaw execution valve, or dispatch Hermes. Signed promotion and live runtime binding remain separate evidence-gated responsibilities.
- Preserved extension version `0.4.2`; this is a bridge correctness amendment, not a product-surface release.
- WSP_15: Complexity 2 + Importance 4 + Deferability 4 + Impact 3 = 13 (P1).

## 2026-07-18 - REDDOG_HOLO_SEMANTIC_FIRST_PHASE1 (semantic retrieval recovery, 0.4.2)

- Proved the local HoloIndex embedding stack healthy (`sentence_transformers`, cached `all-MiniLM-L6-v2`) and measured a real semantic bundle at 15.6 seconds with five code and five WSP hits.
Expand Down
2 changes: 1 addition & 1 deletion extensions/reddog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ The lead is configurable. Use Cursor settings or workspace/user settings:
}
```

The extension uses up to four panel models. RedDog defaults to GLM-5.2 as principal, DeepSeek V4 Pro as adversarial critic, Kimi K2.7 Code as implementation critic, and Kimi K3 as a long-horizon reasoning critic. Kimi K3 uses OpenRouter's explicit `moonshotai/kimi-k3` slug; its request omits unsupported temperature, records mandatory `max` reasoning, and uses a 4096-token critic budget because lower budgets did not produce quorum-usable final output in the live compatibility smoke. The review packet records the actual per-panel token budgets.
The extension uses up to four panel models. RedDog defaults to GLM-5.2 as principal, DeepSeek V4 Pro as adversarial critic, Kimi K2.7 Code as implementation critic, and Kimi K3 as a long-horizon reasoning critic. Kimi K3 uses OpenRouter's explicit `moonshotai/kimi-k3` slug; every direct completion call omits unsupported temperature, records mandatory `max` reasoning, and applies a 4096-token floor because lower budgets did not produce quorum-usable final output in the live compatibility smoke. This covers its default critic call and, only when an explicit direct selection or receipt-backed signed promotion selects K3, the single, principal, and synthesis roles. Review packets distinguish the requested budget from effective direct and per-role budgets. The bridge does not automatically promote K3 to champion, change RedDog defaults, open an OpenClaw execution valve, or dispatch Hermes.

## Bounded Repo Context

Expand Down
7 changes: 7 additions & 0 deletions extensions/reddog/tests/TestModLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Foundups(R)Agent TestModLog

## 2026-07-18 - REDDOG_KIMI_K3_ALL_ROLE_RUNTIME_BUDGET_HARDENING_PHASE1

- Added exact Kimi K3 and non-K3 `openrouter_single` receipt coverage for requested and provider-effective token budgets.
- Moved the new K3 all-role budget proofs into the focused `KimiK3RuntimeBudgetTests` class so the oversized legacy hardening class does not grow.
- Covered K3's 4096-token floor in direct, Fusion principal, and synthesis calls while retaining the existing panel-budget proof and non-K3 behavior.
- Verification: `python -B -m pytest -q -p no:cacheprovider --tb=short scripts/tests/test_advisory_model_once_hardening.py` and `node extensions/reddog/tests/verify_extension_contract.js`.

## 2026-07-18 - REDDOG_HOLO_SEMANTIC_FIRST_PHASE1

- Asserted semantic is the production default and lexical retrieval requires explicit `REDDOG_HOLO_RETRIEVAL_MODE=lexical` opt-down.
Expand Down
87 changes: 68 additions & 19 deletions scripts/advisory_model_once.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
DEEPSEEK_CRITIC_MODEL = "deepseek/deepseek-v4-pro"
KIMI_CODE_PANEL_MODEL = "moonshotai/kimi-k2.7-code"
KIMI_PANEL_MODEL = "moonshotai/kimi-k3"
# Historical constant name retained because the extension contract inspects the
# bridge as text. The K3 budget applies to every direct completion role.
KIMI_K3_PANEL_MAX_TOKENS = 4096
DEFAULT_LEAD_MODEL = GLM_PRINCIPAL_MODEL
DEFAULT_PANEL_MODELS = (DEEPSEEK_CRITIC_MODEL, KIMI_CODE_PANEL_MODEL, KIMI_PANEL_MODEL)
Expand Down Expand Up @@ -138,7 +140,7 @@ def _chat_completion(
body: dict[str, Any] = {
"model": model,
"messages": messages,
"max_tokens": max_tokens,
"max_tokens": _effective_max_tokens(model, max_tokens),
"stream": False,
}
if model == KIMI_PANEL_MODEL:
Expand All @@ -153,6 +155,33 @@ def _chat_completion(
return str(content), retry_meta


def _effective_max_tokens(model: str, requested_max_tokens: int) -> int:
"""Return the provider-compatible output budget for one model call."""

if model == KIMI_PANEL_MODEL:
return max(requested_max_tokens, KIMI_K3_PANEL_MAX_TOKENS)
return requested_max_tokens


def _fusion_token_budgets(
lead_model: str,
panel_models: list[str],
requested_max_tokens: int,
) -> tuple[dict[str, Any], dict[str, int]]:
"""Build truthful effective token budgets for every Fusion role."""

panel = {
model: _effective_max_tokens(model, requested_max_tokens)
for model in panel_models
}
roles: dict[str, Any] = {
"lead": _effective_max_tokens(lead_model, requested_max_tokens),
"panel": panel,
"synthesis": _effective_max_tokens(lead_model, requested_max_tokens),
}
return roles, panel


def _clean_history(value: object) -> list[dict[str, str]]:
if not isinstance(value, list):
return []
Expand Down Expand Up @@ -220,6 +249,27 @@ def _format_panel(lead_model: str, lead_text: str, panel_results: dict[str, str]
return "\n\n".join(parts)


def _synthesis_user_prompt(
redacted_prompt: str,
lead_text: str,
panel_results: dict[str, str],
) -> str:
"""Assemble the bounded lead and panel evidence for synthesis."""

panel_text = "\n\n".join(
_model_label(model) + " critique:\n" + text[:8000]
for model, text in panel_results.items()
)
return (
"Original task:\n"
+ redacted_prompt
+ "\n\nLead answer:\n"
+ lead_text[:12000]
+ "\n\nPanel critiques:\n"
+ panel_text
)


def _none_like_model_text(value: object) -> bool:
text = str(value or "").strip()
lowered = text.lower()
Expand Down Expand Up @@ -283,6 +333,7 @@ def _fusion_quorum_packet(
lead_model: str,
panel_models: list[str],
panel_models_truncated: bool,
role_max_tokens: dict[str, Any] | None = None,
panel_max_tokens: dict[str, int] | None = None,
missing_required_evidence: list[str] | None = None,
challenging_critics: list[str] | None = None,
Expand All @@ -307,6 +358,7 @@ def _fusion_quorum_packet(
"lead_model": lead_model,
"panel_models": panel_models,
"panel_models_truncated": panel_models_truncated,
"role_max_tokens": dict(role_max_tokens or {}),
"panel_max_tokens": dict(panel_max_tokens or {}),
"fusion_panel_quorum": quorum,
},
Expand Down Expand Up @@ -383,10 +435,9 @@ def _run_foundups_fusion(
temperature = _bounded_temperature(payload.get("temperature"), 0.2)
lead_model = _model_slug(payload.get("lead_model"), DEFAULT_LEAD_MODEL)
panel_models, panel_models_truncated = _panel_models_with_meta(payload.get("panel_models"))
panel_max_tokens = {
model: (max(max_tokens, KIMI_K3_PANEL_MAX_TOKENS) if model == KIMI_PANEL_MODEL else max_tokens)
for model in panel_models
}
role_max_tokens, panel_max_tokens = _fusion_token_budgets(
lead_model, panel_models, max_tokens
)
base_system = _system_prompt(payload)
response_contract = str(payload.get("response_contract") or "")
strict_json_contract = response_contract.startswith("strict_json")
Expand All @@ -401,6 +452,7 @@ def _run_foundups_fusion(
lead_model=lead_model,
panel_models=panel_models,
panel_models_truncated=panel_models_truncated,
role_max_tokens=role_max_tokens,
panel_max_tokens=panel_max_tokens,
missing_required_evidence=missing_evidence,
)
Expand All @@ -422,7 +474,7 @@ def _run_foundups_fusion(
api_key,
lead_model,
lead_messages,
max_tokens=max_tokens,
max_tokens=role_max_tokens["lead"],
temperature=temperature,
timeout=timeout,
)
Expand All @@ -439,6 +491,7 @@ def _run_foundups_fusion(
lead_model=lead_model,
panel_models=panel_models,
panel_models_truncated=panel_models_truncated,
role_max_tokens=role_max_tokens,
panel_max_tokens=panel_max_tokens,
)

Expand Down Expand Up @@ -492,6 +545,7 @@ def _run_foundups_fusion(
lead_model=lead_model,
panel_models=panel_models,
panel_models_truncated=panel_models_truncated,
role_max_tokens=role_max_tokens,
panel_max_tokens=panel_max_tokens,
challenging_critics=[],
)
Expand All @@ -506,18 +560,7 @@ def _run_foundups_fusion(
base_system
+ "\n\nSynthesis pass: resolve panel disagreement, preserve useful dissent, and return the best actionable WSP-compliant recommendation. The final section must be WSP_15 Priority followed by Next safest step."
)
panel_text = "\n\n".join(
_model_label(model) + " critique:\n" + text[:8000]
for model, text in panel_results.items()
)
synthesis_user = (
"Original task:\n"
+ redacted_prompt
+ "\n\nLead answer:\n"
+ lead_text[:12000]
+ "\n\nPanel critiques:\n"
+ panel_text
)
synthesis_user = _synthesis_user_prompt(redacted_prompt, lead_text, panel_results)
_progress("synthesis_start", "Synthesis request started: " + lead_model)
try:
synthesis, _syn_retry = _chat_completion(
Expand All @@ -527,7 +570,7 @@ def _run_foundups_fusion(
{"role": "system", "content": synthesis_system},
{"role": "user", "content": synthesis_user},
],
max_tokens=max_tokens,
max_tokens=role_max_tokens["synthesis"],
temperature=temperature,
timeout=timeout,
)
Expand All @@ -538,6 +581,7 @@ def _run_foundups_fusion(
lead_model=lead_model,
panel_models=panel_models,
panel_models_truncated=panel_models_truncated,
role_max_tokens=role_max_tokens,
panel_max_tokens=panel_max_tokens,
challenging_critics=challenging_critics,
)
Expand All @@ -561,6 +605,8 @@ def _run_foundups_fusion(
"lead_model": lead_model,
"panel_models": panel_models,
"panel_models_truncated": panel_models_truncated,
"requested_max_tokens": max_tokens,
"role_max_tokens": role_max_tokens,
"panel_max_tokens": panel_max_tokens,
"redacted_prompt": redacted_prompt,
"lead_excerpt": lead_text[:4000],
Expand Down Expand Up @@ -721,6 +767,7 @@ def main() -> int:
return _json_result(ok=False, reason="missing_model")

max_tokens = _bounded_int(payload.get("max_tokens"), 2048, 1, 4096)
effective_max_tokens = _effective_max_tokens(model, max_tokens)
temperature = _bounded_temperature(payload.get("temperature"), 0.2)
timeout = _bounded_int(payload.get("timeout"), 60, 1, 120)

Expand Down Expand Up @@ -759,6 +806,8 @@ def main() -> int:
review_packet={
"mode": "openrouter_single",
"lead_model": model,
"requested_max_tokens": max_tokens,
"effective_max_tokens": effective_max_tokens,
"redacted_prompt_excerpt": redacted_user_message[:4000],
"retry_count": retry_meta.get("retry_count", 0),
"final_retry_reason": retry_meta.get("final_retry_reason"),
Expand Down
115 changes: 115 additions & 0 deletions scripts/tests/test_advisory_model_once_hardening.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,5 +718,120 @@ def fake_urlopen(request, timeout=0): # noqa: ARG001
self.assertEqual(kwargs["required_target_paths"], ("real/a.py", "real/b.py"))


class KimiK3RuntimeBudgetTests(unittest.TestCase):
"""Focused coverage for K3 provider budgets and truthful role receipts."""

def _invoke_main(self, payload: dict) -> tuple[int, dict]:
stdin_bytes = json.dumps(payload, ensure_ascii=False).encode("utf-8")
fake_stdin = mock.Mock()
fake_stdin.buffer = io.BytesIO(stdin_bytes)
stdout = io.StringIO()
with mock.patch("sys.stdin", fake_stdin), mock.patch("sys.stdout", stdout), mock.patch.dict(
os.environ, {bridge.ENV_API_KEY: "test-key"}, clear=False
):
rc = bridge.main()
return rc, json.loads(stdout.getvalue())

def test_kimi_k3_completion_applies_4096_floor(self) -> None:
post = mock.Mock(
return_value=(
{"choices": [{"message": {"content": "ok"}}]},
{"retry_count": 0, "final_retry_reason": None},
)
)
with mock.patch.object(bridge, "_post_openrouter", post):
bridge._chat_completion(
"key",
"moonshotai/kimi-k3",
[{"role": "user", "content": "test"}],
max_tokens=256,
temperature=0.2,
timeout=30,
)

body = post.call_args.args[1]
self.assertEqual(body["max_tokens"], 4096)
self.assertEqual(body["reasoning"], {"effort": "max"})
self.assertNotIn("temperature", body)

def test_fusion_kimi_k3_principal_uses_and_records_4096_for_both_passes(self) -> None:
calls: list[tuple[str, int]] = []

def fake_chat(api_key, model, messages, **kwargs): # noqa: ANN001, ARG001
calls.append((model, kwargs["max_tokens"]))
system = str(messages[0]["content"])
if "Panel critic pass" in system:
return (
"Challenge: the evidence framing is unsupported and the WSP_15 "
"priority needs verification.",
{"retry_count": 0},
)
return "Evidence-backed result with WSP_15 priority.", {"retry_count": 0}

with mock.patch.object(bridge, "_chat_completion", side_effect=fake_chat):
result = bridge._run_foundups_fusion(
"key",
"prompt",
[],
{
"lead_model": "moonshotai/kimi-k3",
"panel_models": ["critic-a"],
"max_tokens": 1200,
},
)

self.assertTrue(result["ok"])
self.assertEqual(calls.count(("moonshotai/kimi-k3", 4096)), 2)
self.assertIn(("critic-a", 1200), calls)
packet = result["review_packet"]
self.assertEqual(packet["requested_max_tokens"], 1200)
self.assertEqual(
packet["role_max_tokens"],
{"lead": 4096, "panel": {"critic-a": 1200}, "synthesis": 4096},
)

def test_single_kimi_k3_receipt_records_requested_and_effective_budget(self) -> None:
chat = mock.Mock(return_value=("ok", {"retry_count": 0, "final_retry_reason": None}))
with mock.patch.object(bridge, "evaluate_redaction_gate", return_value=_passed_gate()), mock.patch.object(
bridge, "_chat_completion", chat
):
rc, result = self._invoke_main(
{
"mode": "openrouter_single",
"prompt": "test",
"lead_model": "moonshotai/kimi-k3",
"max_tokens": 256,
}
)

self.assertEqual(rc, 0)
self.assertTrue(result["ok"])
self.assertEqual(chat.call_args.kwargs["max_tokens"], 256)
packet = result["review_packet"]
self.assertEqual(packet["requested_max_tokens"], 256)
self.assertEqual(packet["effective_max_tokens"], 4096)

def test_single_non_kimi_receipt_preserves_requested_budget(self) -> None:
chat = mock.Mock(return_value=("ok", {"retry_count": 0, "final_retry_reason": None}))
with mock.patch.object(bridge, "evaluate_redaction_gate", return_value=_passed_gate()), mock.patch.object(
bridge, "_chat_completion", chat
):
rc, result = self._invoke_main(
{
"mode": "openrouter_single",
"prompt": "test",
"lead_model": "z-ai/glm-5.2",
"max_tokens": 777,
}
)

self.assertEqual(rc, 0)
self.assertTrue(result["ok"])
self.assertEqual(chat.call_args.kwargs["max_tokens"], 777)
packet = result["review_packet"]
self.assertEqual(packet["requested_max_tokens"], 777)
self.assertEqual(packet["effective_max_tokens"], 777)


if __name__ == "__main__":
unittest.main()
Loading