@tiens.nguyen/gonext-local-worker 1.0.312 → 1.0.313
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.
- package/gonext_agent_chat.py +35 -0
- package/package.json +1 -1
package/gonext_agent_chat.py
CHANGED
|
@@ -4960,6 +4960,7 @@ def run_agent_chat(cfg):
|
|
|
4960
4960
|
_log("streamed generate: request issued (stream=True), awaiting first token…")
|
|
4961
4961
|
stream = self.client.chat.completions.create(**completion_kwargs)
|
|
4962
4962
|
parts = []
|
|
4963
|
+
rparts = [] # reasoning-channel text (task #111: may hold the <code> block)
|
|
4963
4964
|
role = "assistant"
|
|
4964
4965
|
in_tok = out_tok = reasoning_len = 0
|
|
4965
4966
|
first_token_at = None
|
|
@@ -5028,6 +5029,7 @@ def run_agent_chat(cfg):
|
|
|
5028
5029
|
if rpiece:
|
|
5029
5030
|
_mark_first()
|
|
5030
5031
|
reasoning_len += len(rpiece)
|
|
5032
|
+
rparts.append(rpiece)
|
|
5031
5033
|
_stream_buf.append(rpiece)
|
|
5032
5034
|
_stream_chars += len(rpiece)
|
|
5033
5035
|
_emit({"type": "stream", "text": rpiece})
|
|
@@ -5055,10 +5057,43 @@ def run_agent_chat(cfg):
|
|
|
5055
5057
|
_emit({"type": "step", "text": "Model output ran away — restarting this step…"})
|
|
5056
5058
|
_log(f"streamed generate: discarded {len(content)} runaway chars → empty content")
|
|
5057
5059
|
return "", role, in_tok, out_tok, reasoning_len
|
|
5060
|
+
# Task #111: reasoning models on an OpenAI-compatible API (e.g. Kimi K3 @ Moonshot)
|
|
5061
|
+
# can emit the actionable <code>…</code> into the REASONING channel, leaving only
|
|
5062
|
+
# prose + a stray tag in `content` → smolagents' parser can't find the pair. When
|
|
5063
|
+
# content has no usable code block but the reasoning stream does, rebuild content
|
|
5064
|
+
# from it. Inert when reasoning is empty (Ollama with thinking off) → path untouched.
|
|
5065
|
+
content = self._recover_code_from_channels(content, "".join(rparts))
|
|
5058
5066
|
_log(f"streamed generate assembled {len(content)} chars "
|
|
5059
5067
|
f"(in={in_tok} out={out_tok} tokens, reasoning={reasoning_len} chars)")
|
|
5060
5068
|
return content, role, in_tok, out_tok, reasoning_len
|
|
5061
5069
|
|
|
5070
|
+
def _recover_code_from_channels(self, content, reasoning):
|
|
5071
|
+
"""Recover a <code>…</code> tool call that a reasoning model placed in the
|
|
5072
|
+
REASONING channel instead of the visible message (task #111). No-op when the
|
|
5073
|
+
visible content already has a usable code block, or when there is no reasoning
|
|
5074
|
+
text (e.g. Ollama with reasoning_effort='none') — so the Ollama path is unchanged."""
|
|
5075
|
+
_pair = r"<code[^>]*>[\s\S]*?</code>"
|
|
5076
|
+
if re.search(_pair, content or "", re.I):
|
|
5077
|
+
return content # already parseable
|
|
5078
|
+
if not (reasoning or "").strip():
|
|
5079
|
+
return content # nothing to recover from (Ollama / non-reasoning model)
|
|
5080
|
+
# Take the LAST code block in the combined stream (reasoning usually holds it).
|
|
5081
|
+
combined = (reasoning or "") + "\n" + (content or "")
|
|
5082
|
+
last = None
|
|
5083
|
+
for last in re.finditer(r"<code[^>]*>([\s\S]*?)</code>", combined, re.I):
|
|
5084
|
+
pass
|
|
5085
|
+
if not last:
|
|
5086
|
+
return content
|
|
5087
|
+
code = (last.group(1) or "").strip()
|
|
5088
|
+
if not code:
|
|
5089
|
+
return content
|
|
5090
|
+
# Keep the visible Thought prose (strip any stray/unbalanced code tags), then
|
|
5091
|
+
# append the recovered block so smolagents parses a clean Thought → <code> pair.
|
|
5092
|
+
prose = re.sub(r"</?code[^>]*>", "", content or "", flags=re.I).strip()
|
|
5093
|
+
rebuilt = (prose + "\n" if prose else "") + "<code>\n" + code + "\n</code>"
|
|
5094
|
+
_log(f"#111 recovered <code> block from reasoning channel ({len(code)} chars)")
|
|
5095
|
+
return rebuilt
|
|
5096
|
+
|
|
5062
5097
|
# Injected when a turn produced ONLY reasoning and no message content — a hard,
|
|
5063
5098
|
# model-agnostic steer to emit the actionable code block instead of more analysis.
|
|
5064
5099
|
_CODE_NOW_DIRECTIVE = (
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tiens.nguyen/gonext-local-worker",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.313",
|
|
4
4
|
"description": "Polls GoNext cloud API for async local LLM jobs and runs them against Ollama/OpenAI-compatible servers on this Mac",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|