@tiens.nguyen/gonext-local-worker 1.0.61 → 1.0.63
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 +68 -20
- package/package.json +1 -1
package/gonext_agent_chat.py
CHANGED
|
@@ -117,6 +117,55 @@ def _summarise_step(step_log):
|
|
|
117
117
|
return label + (" | ".join(parts) if parts else "thinking…")
|
|
118
118
|
|
|
119
119
|
|
|
120
|
+
def _route(task_text: str, base_url: str, api_key: str, model_id: str) -> bool:
|
|
121
|
+
"""Ask the local model if this task needs an HTTP request.
|
|
122
|
+
Returns True → run full agent; False → plain chat reply."""
|
|
123
|
+
try:
|
|
124
|
+
from openai import OpenAI
|
|
125
|
+
client = OpenAI(base_url=base_url, api_key=api_key or "local",
|
|
126
|
+
max_retries=0, timeout=20)
|
|
127
|
+
resp = client.chat.completions.create(
|
|
128
|
+
model=model_id,
|
|
129
|
+
messages=[
|
|
130
|
+
{"role": "system", "content": (
|
|
131
|
+
"You are a task classifier. Reply with YES or NO only, no punctuation."
|
|
132
|
+
)},
|
|
133
|
+
{"role": "user", "content": (
|
|
134
|
+
f"Does this task require making an HTTP request to a URL or API?\n\n"
|
|
135
|
+
f"Task: {task_text}\n\nYES or NO:"
|
|
136
|
+
)},
|
|
137
|
+
],
|
|
138
|
+
max_tokens=3,
|
|
139
|
+
temperature=0,
|
|
140
|
+
)
|
|
141
|
+
answer = (resp.choices[0].message.content or "").strip().upper()
|
|
142
|
+
_log(f"router → {answer!r}")
|
|
143
|
+
return answer.startswith("Y")
|
|
144
|
+
except Exception as e: # noqa: BLE001
|
|
145
|
+
_log(f"router error: {e} — defaulting to agent")
|
|
146
|
+
return True
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _plain_reply(task_text: str, base_url: str, api_key: str, model_id: str) -> str:
|
|
150
|
+
"""Plain chat completion without any tools."""
|
|
151
|
+
try:
|
|
152
|
+
from openai import OpenAI
|
|
153
|
+
client = OpenAI(base_url=base_url, api_key=api_key or "local",
|
|
154
|
+
max_retries=0, timeout=60)
|
|
155
|
+
resp = client.chat.completions.create(
|
|
156
|
+
model=model_id,
|
|
157
|
+
messages=[
|
|
158
|
+
{"role": "system", "content": "You are a helpful assistant."},
|
|
159
|
+
{"role": "user", "content": task_text},
|
|
160
|
+
],
|
|
161
|
+
temperature=0.7,
|
|
162
|
+
max_tokens=512,
|
|
163
|
+
)
|
|
164
|
+
return (resp.choices[0].message.content or "").strip()
|
|
165
|
+
except Exception as e: # noqa: BLE001
|
|
166
|
+
return f"[Error: {e}]"
|
|
167
|
+
|
|
168
|
+
|
|
120
169
|
def run_agent_chat(cfg):
|
|
121
170
|
try:
|
|
122
171
|
from smolagents import CodeAgent, OpenAIServerModel, tool
|
|
@@ -132,29 +181,31 @@ def run_agent_chat(cfg):
|
|
|
132
181
|
|
|
133
182
|
_log(f"start model={agent_model_id!r} base={agent_base_url!r} maxSteps={max_steps}")
|
|
134
183
|
|
|
135
|
-
#
|
|
136
|
-
# Strip <think>...</think> blocks from assistant messages — those are internal
|
|
137
|
-
# reasoning steps and must not be fed back to the agent as conversation context.
|
|
138
|
-
_THINK_RE = re.compile(r"<think>.*?</think>", re.DOTALL | re.IGNORECASE)
|
|
139
|
-
|
|
184
|
+
# Use only the latest user message as the agent task.
|
|
140
185
|
task_text = ""
|
|
141
|
-
context_lines = []
|
|
142
186
|
for m in messages:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if role == "user":
|
|
146
|
-
task_text = content
|
|
147
|
-
elif role == "assistant":
|
|
148
|
-
clean = _THINK_RE.sub("", content).strip()
|
|
149
|
-
if clean:
|
|
150
|
-
context_lines.append(f"Assistant previously said: {clean[:500]}")
|
|
187
|
+
if m.get("role") == "user":
|
|
188
|
+
task_text = m.get("content", "")
|
|
151
189
|
|
|
152
190
|
if not task_text:
|
|
153
191
|
_emit({"type": "final", "text": "[No user message found in history]"})
|
|
154
192
|
return
|
|
155
193
|
|
|
156
|
-
|
|
157
|
-
|
|
194
|
+
_log(f"task={task_text[:120]!r}")
|
|
195
|
+
|
|
196
|
+
# Route: ask the model if this task needs HTTP tool use.
|
|
197
|
+
_emit({"type": "step", "text": "Routing…"})
|
|
198
|
+
needs_agent = _route(task_text, agent_base_url, agent_api_key, agent_model_id)
|
|
199
|
+
|
|
200
|
+
if not needs_agent:
|
|
201
|
+
_log("router: plain chat (no HTTP needed)")
|
|
202
|
+
_emit({"type": "step", "text": "No HTTP request needed — answering directly…"})
|
|
203
|
+
answer = _plain_reply(task_text, agent_base_url, agent_api_key, agent_model_id)
|
|
204
|
+
_log(f"plain reply: {len(answer)} chars")
|
|
205
|
+
_emit({"type": "final", "text": answer})
|
|
206
|
+
return
|
|
207
|
+
|
|
208
|
+
_log("router: agent (HTTP tool use needed)")
|
|
158
209
|
|
|
159
210
|
# Prepend explicit tool instructions so small models use http_request correctly
|
|
160
211
|
# and always terminate with final_answer() rather than looping forever.
|
|
@@ -162,12 +213,9 @@ def run_agent_chat(cfg):
|
|
|
162
213
|
"You have ONE built-in function: `http_request(method, url, headers='', body='')`. "
|
|
163
214
|
"Do NOT import requests, urllib, or any library — call http_request() directly.\n"
|
|
164
215
|
"When you have the answer, ALWAYS end with `final_answer(your_answer)` — this stops the agent.\n"
|
|
165
|
-
"
|
|
166
|
-
"result = http_request(method='GET', url='https://example.com')\n"
|
|
167
|
-
"final_answer(result)\n\n"
|
|
216
|
+
"Call http_request with the URL from the task, then call final_answer with the result.\n\n"
|
|
168
217
|
)
|
|
169
218
|
task_with_hint = tool_hint + "Task: " + task_text
|
|
170
|
-
_log(f"task={task_text[:120]!r}")
|
|
171
219
|
|
|
172
220
|
@tool
|
|
173
221
|
def http_request(method: str, url: str, headers: str = "", body: str = "") -> str:
|
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.63",
|
|
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",
|