@tiens.nguyen/gonext-local-worker 1.0.141 → 1.0.142
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 +86 -3
- package/package.json +1 -1
package/gonext_agent_chat.py
CHANGED
|
@@ -1805,6 +1805,85 @@ def run_agent_chat(cfg):
|
|
|
1805
1805
|
# and any step memory it accumulates. completion_kwargs["messages"] here is the
|
|
1806
1806
|
# literal messages array sent to /v1/chat/completions.
|
|
1807
1807
|
class _LoggingModel(OpenAIServerModel):
|
|
1808
|
+
def __init__(self, *a, stream_agent=False, **kw):
|
|
1809
|
+
# stream_agent: request the completion with stream=True and reassemble the
|
|
1810
|
+
# deltas into one message. Enabled for Ollama, where a long single-shot
|
|
1811
|
+
# (non-stream) generation sends nothing until the very end — a reverse proxy
|
|
1812
|
+
# in front of the box (ollama1.gomarsic.cc) then hits its idle read-timeout
|
|
1813
|
+
# and kills the request mid-generation. Streaming keeps tokens flowing so the
|
|
1814
|
+
# idle timer never fires. smolagents still receives the COMPLETE text, so its
|
|
1815
|
+
# <code>/final_answer parsing is unaffected.
|
|
1816
|
+
self._stream_agent = bool(stream_agent)
|
|
1817
|
+
super().__init__(*a, **kw)
|
|
1818
|
+
|
|
1819
|
+
def _generate_once(self, *args, **kwargs):
|
|
1820
|
+
"""One model call. Streams + reassembles when _stream_agent, else the normal
|
|
1821
|
+
non-streaming path. Streaming is a pure transport optimization: on ANY failure
|
|
1822
|
+
it falls back to the non-streaming call, and it's skipped for tool-calling
|
|
1823
|
+
mode (tools_to_call_from), whose tool_call deltas we don't reassemble."""
|
|
1824
|
+
tools_to_call_from = kwargs.get("tools_to_call_from")
|
|
1825
|
+
if not self._stream_agent or tools_to_call_from:
|
|
1826
|
+
return super().generate(*args, **kwargs)
|
|
1827
|
+
try:
|
|
1828
|
+
return self._streamed_generate(*args, **kwargs)
|
|
1829
|
+
except Exception as e: # noqa: BLE001
|
|
1830
|
+
_log(f"streamed generate failed ({e}) → falling back to non-streaming")
|
|
1831
|
+
return super().generate(*args, **kwargs)
|
|
1832
|
+
|
|
1833
|
+
def _streamed_generate(
|
|
1834
|
+
self, messages, stop_sequences=None, response_format=None,
|
|
1835
|
+
tools_to_call_from=None, **kwargs,
|
|
1836
|
+
):
|
|
1837
|
+
from smolagents.models import ChatMessage, TokenUsage # local: version-safe
|
|
1838
|
+
completion_kwargs = self._prepare_completion_kwargs(
|
|
1839
|
+
messages=messages,
|
|
1840
|
+
stop_sequences=stop_sequences,
|
|
1841
|
+
response_format=response_format,
|
|
1842
|
+
tools_to_call_from=tools_to_call_from,
|
|
1843
|
+
model=self.model_id,
|
|
1844
|
+
custom_role_conversions=self.custom_role_conversions,
|
|
1845
|
+
convert_images_to_image_urls=True,
|
|
1846
|
+
**kwargs,
|
|
1847
|
+
)
|
|
1848
|
+
completion_kwargs["stream"] = True
|
|
1849
|
+
# Ask for a usage summary in the final chunk (OpenAI streaming convention;
|
|
1850
|
+
# Ollama honors it). Harmless if the server ignores it — usage stays 0.
|
|
1851
|
+
completion_kwargs["stream_options"] = {"include_usage": True}
|
|
1852
|
+
self._apply_rate_limit()
|
|
1853
|
+
stream = self.client.chat.completions.create(**completion_kwargs)
|
|
1854
|
+
parts = []
|
|
1855
|
+
role = "assistant"
|
|
1856
|
+
in_tok = out_tok = 0
|
|
1857
|
+
for chunk in stream:
|
|
1858
|
+
usage = getattr(chunk, "usage", None)
|
|
1859
|
+
if usage is not None:
|
|
1860
|
+
in_tok = getattr(usage, "prompt_tokens", 0) or in_tok
|
|
1861
|
+
out_tok = getattr(usage, "completion_tokens", 0) or out_tok
|
|
1862
|
+
choices = getattr(chunk, "choices", None)
|
|
1863
|
+
if not choices:
|
|
1864
|
+
continue
|
|
1865
|
+
delta = getattr(choices[0], "delta", None)
|
|
1866
|
+
if delta is None:
|
|
1867
|
+
continue
|
|
1868
|
+
if getattr(delta, "role", None):
|
|
1869
|
+
role = delta.role
|
|
1870
|
+
piece = getattr(delta, "content", None)
|
|
1871
|
+
if piece:
|
|
1872
|
+
parts.append(piece)
|
|
1873
|
+
content = "".join(parts)
|
|
1874
|
+
if stop_sequences and not self.supports_stop_parameter:
|
|
1875
|
+
from smolagents.models import remove_content_after_stop_sequences
|
|
1876
|
+
content = remove_content_after_stop_sequences(content, stop_sequences)
|
|
1877
|
+
_log(f"streamed generate assembled {len(content)} chars "
|
|
1878
|
+
f"(in={in_tok} out={out_tok} tokens)")
|
|
1879
|
+
return ChatMessage(
|
|
1880
|
+
role=role,
|
|
1881
|
+
content=content,
|
|
1882
|
+
tool_calls=None,
|
|
1883
|
+
raw=None,
|
|
1884
|
+
token_usage=TokenUsage(input_tokens=in_tok, output_tokens=out_tok),
|
|
1885
|
+
)
|
|
1886
|
+
|
|
1808
1887
|
def generate(self, *args, **kwargs):
|
|
1809
1888
|
# Two safeguards on each step's reply BEFORE smolagents parses it for the
|
|
1810
1889
|
# code block / final_answer:
|
|
@@ -1843,7 +1922,7 @@ def run_agent_chat(cfg):
|
|
|
1843
1922
|
try:
|
|
1844
1923
|
for attempt in range(3):
|
|
1845
1924
|
try:
|
|
1846
|
-
msg =
|
|
1925
|
+
msg = self._generate_once(*args, **kwargs)
|
|
1847
1926
|
break
|
|
1848
1927
|
except Exception as e: # noqa: BLE001
|
|
1849
1928
|
emsg = str(e)
|
|
@@ -2014,13 +2093,17 @@ def run_agent_chat(cfg):
|
|
|
2014
2093
|
# the live test — minutes per step on a slow GPU — so disable it explicitly.
|
|
2015
2094
|
# Sniffed per-server because MLX might reject the unknown param.
|
|
2016
2095
|
extra_model_kwargs = {}
|
|
2017
|
-
|
|
2018
|
-
|
|
2096
|
+
coding_is_ollama = _is_ollama_server(coding_base_url)
|
|
2097
|
+
if coding_is_ollama:
|
|
2098
|
+
_log("coding server is Ollama → reasoning_effort='none' (disable thinking) + streaming")
|
|
2019
2099
|
extra_model_kwargs["reasoning_effort"] = "none"
|
|
2020
2100
|
model = _LoggingModel(
|
|
2021
2101
|
model_id=coding_model_id,
|
|
2022
2102
|
api_base=coding_base_url,
|
|
2023
2103
|
api_key=agent_api_key,
|
|
2104
|
+
# Stream for Ollama so a long generation keeps the connection warm and can't
|
|
2105
|
+
# trip a reverse-proxy idle read-timeout. smolagents still gets the full text.
|
|
2106
|
+
stream_agent=coding_is_ollama,
|
|
2024
2107
|
# Cap each HTTP attempt at 600s so a genuinely slow single call (a
|
|
2025
2108
|
# remote M6000/Vulkan box doing a cold ~4-5min prompt-eval) can finish
|
|
2026
2109
|
# on the first try, while a truly hung request still fails into OUR
|
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.142",
|
|
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",
|