pythonclaw 0.6.3__py3-none-any.whl → 0.6.4__py3-none-any.whl

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.
@@ -244,8 +244,7 @@ class TelegramBot:
244
244
  except Exception:
245
245
  pass
246
246
 
247
- # Max wall-clock time for a single agent invocation (seconds).
248
- _AGENT_TIMEOUT = 180
247
+ _AGENT_TIMEOUT = 600
249
248
 
250
249
  async def _flush_stream(
251
250
  self,
@@ -253,98 +252,47 @@ class TelegramBot:
253
252
  token_queue: "_queue.Queue[str]",
254
253
  future: "asyncio.Future[str]",
255
254
  ) -> None:
256
- """Progressively stream tokens to Telegram via edit-in-place.
255
+ """Collect streamed tokens and deliver as 2-3 large messages.
257
256
 
258
- Uses send-then-edit (like OpenClaw): one live message that gets
259
- updated as tokens arrive (~1.5 s throttle). Tool-call markers
260
- produce a short status line and start a fresh message.
257
+ Strategy: accumulate all tokens silently. Tool-call markers are
258
+ stripped but do NOT trigger new messages. Content is edit-in-place
259
+ updated into a single live message; only when a message hits the
260
+ Telegram 4096 char limit is a new message started.
261
261
 
262
- Safeguards against hangs:
263
- - **Heartbeat**: if no tokens arrive for 15 s, sends a "still
264
- working" notification so the user knows the bot is alive.
265
- - **Overall timeout**: after ``_AGENT_TIMEOUT`` seconds the
266
- future is abandoned and a timeout message is sent.
262
+ No heartbeat / "still working" messages are sent.
267
263
  """
268
264
  buf: list[str] = []
269
265
  live_msg = None
270
266
  live_text = ""
271
267
  sent_any = False
272
- THROTTLE = 1.5
273
- HEARTBEAT_INTERVAL = 15.0
268
+ THROTTLE = 2.0
274
269
  last_edit = time.monotonic()
275
- last_token_time = time.monotonic()
276
270
  start_time = time.monotonic()
277
- heartbeat_sent = False
278
271
  _MARKER = re.compile(r'`\[calling:\s*([^\]]+)\]`')
279
272
 
280
273
  while not future.done():
281
- # ── Overall timeout guard ─────────────────────────────────
282
274
  if (time.monotonic() - start_time) > self._AGENT_TIMEOUT:
283
275
  logger.warning(
284
276
  "[Telegram] Agent timeout after %ds", self._AGENT_TIMEOUT,
285
277
  )
286
- try:
287
- await update.message.reply_text(
288
- "\u23f0 The operation timed out. "
289
- "Please try a simpler request."
290
- )
291
- except Exception:
292
- pass
293
- return
278
+ break
294
279
 
295
- # ── Drain token queue ─────────────────────────────────────
296
280
  drained = False
297
281
  while True:
298
282
  try:
299
283
  buf.append(token_queue.get_nowait())
300
284
  drained = True
301
- last_token_time = time.monotonic()
302
- heartbeat_sent = False
303
285
  except _queue.Empty:
304
286
  break
305
287
 
306
- # ── Heartbeat: notify user during long silences ───────────
307
- if (
308
- not drained
309
- and not heartbeat_sent
310
- and (time.monotonic() - last_token_time) > HEARTBEAT_INTERVAL
311
- ):
312
- try:
313
- await update.message.reply_text(
314
- "\u23f3 Still working\u2026"
315
- )
316
- except Exception:
317
- pass
318
- heartbeat_sent = True
319
-
320
288
  if not drained:
321
- await asyncio.sleep(0.3)
289
+ await asyncio.sleep(0.4)
322
290
  continue
323
291
 
324
- raw = "".join(buf)
292
+ raw = _MARKER.sub("", "".join(buf))
293
+ text = _clean_response(raw)
325
294
  now = time.monotonic()
326
295
 
327
- # ── Tool-call marker → status line + new message ──────────
328
- marker = _MARKER.search(raw)
329
- if marker:
330
- before = _clean_response(raw[:marker.start()])
331
- if before and before != live_text:
332
- try:
333
- if live_msg:
334
- await live_msg.edit_text(before[:4096])
335
- else:
336
- await update.message.reply_text(before[:4096])
337
- sent_any = True
338
- except Exception:
339
- pass
340
- live_msg = None
341
- live_text = ""
342
- buf = [raw[marker.end():].lstrip()]
343
- last_edit = now
344
- continue
345
-
346
- # ── Regular text → edit-in-place ──────────────────────────
347
- text = _clean_response(raw)
348
296
  if text and text != live_text and (now - last_edit) >= THROTTLE:
349
297
  try:
350
298
  if live_msg is None:
@@ -356,26 +304,27 @@ class TelegramBot:
356
304
  await live_msg.edit_text(text)
357
305
  live_text = text
358
306
  else:
359
- await live_msg.edit_text(text[:4096])
307
+ await live_msg.edit_text(live_text)
360
308
  live_msg = None
361
309
  live_text = ""
362
- buf = [text[4096:]]
310
+ buf = [text[len(live_text):] if live_text else text]
363
311
  sent_any = True
364
312
  except Exception:
365
313
  pass
366
314
  last_edit = now
367
315
 
368
- await asyncio.sleep(0.3)
316
+ await asyncio.sleep(0.4)
369
317
 
370
318
  # ── Final drain ───────────────────────────────────────────────
371
- response = future.result()
319
+ response = future.result() if future.done() else "(timed out)"
372
320
  while True:
373
321
  try:
374
322
  buf.append(token_queue.get_nowait())
375
323
  except _queue.Empty:
376
324
  break
377
325
 
378
- remaining = _clean_response("".join(buf).strip())
326
+ raw = _MARKER.sub("", "".join(buf))
327
+ remaining = _clean_response(raw.strip())
379
328
  if remaining and remaining != live_text:
380
329
  try:
381
330
  if live_msg and len(remaining) <= 4096:
pythonclaw/core/agent.py CHANGED
@@ -120,9 +120,9 @@ class Agent:
120
120
  cron_manager : CronScheduler instance (enables cron_add/remove/list tools)
121
121
  """
122
122
 
123
- MAX_TOOL_ROUNDS = 8
123
+ MAX_TOOL_ROUNDS = 12
124
124
  MAX_PARALLEL_SKILLS = 5
125
- TOOL_TIMEOUT = 90
125
+ TOOL_TIMEOUT = 300
126
126
 
127
127
  def __init__(
128
128
  self,
@@ -29,7 +29,7 @@ class AnthropicProvider(LLMProvider):
29
29
  def __init__(self, api_key: str, model_name: str = "claude-sonnet-4-20250514"):
30
30
  self.client = anthropic.Anthropic(
31
31
  api_key=api_key,
32
- timeout=120.0,
32
+ timeout=300.0,
33
33
  )
34
34
  self.model_name = model_name
35
35
  self._auth_type = (
@@ -104,7 +104,7 @@ class GeminiProvider(LLMProvider):
104
104
  response = self.model.generate_content(
105
105
  contents=gemini_history,
106
106
  tools=gemini_tools,
107
- request_options={"timeout": 120},
107
+ request_options={"timeout": 300},
108
108
  )
109
109
 
110
110
  # Convert to OpenAI-compatible format
@@ -22,7 +22,7 @@ class OpenAICompatibleProvider(LLMProvider):
22
22
  self.client = OpenAI(
23
23
  api_key=api_key,
24
24
  base_url=base_url,
25
- timeout=120.0,
25
+ timeout=300.0,
26
26
  )
27
27
  self.model_name = model_name
28
28
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonclaw
3
- Version: 0.6.3
3
+ Version: 0.6.4
4
4
  Summary: OpenClaw reimagined in pure Python — autonomous AI agent with memory, RAG, skills, web dashboard, and multi-channel support.
5
5
  Author-email: Eric Wang <wangchen2007915@gmail.com>
6
6
  License: MIT
@@ -8,10 +8,10 @@ pythonclaw/onboard.py,sha256=X6ViAduToi9P9J_WdWm9mKQtTb48IwGj5DiqS4jjt0Y,13921
8
8
  pythonclaw/server.py,sha256=zUV09uNTmzK597swGwt45gdmVxuHPsF7ogVV0DHBIhA,4521
9
9
  pythonclaw/session_manager.py,sha256=LKRolNa2i3evb6Ps1zRbajlk4AfvujbR1iPlhfAMBj8,5981
10
10
  pythonclaw/channels/discord_bot.py,sha256=95IJcBJlcnOSbsg0LILq6uBYfhdpb-iLLlRw_41Xz7U,11744
11
- pythonclaw/channels/telegram_bot.py,sha256=WGZFgDcHIOLKNSphMT79ZrpC_6XbsZ-WU8t9Yto8LsQ,21944
11
+ pythonclaw/channels/telegram_bot.py,sha256=QCwGZlTm6bZIr-E557EEwQktFXvmwvJ4DJJviXgfG00,19610
12
12
  pythonclaw/channels/whatsapp_bot.py,sha256=60n6W3ONEIKAdpmI6gCS9RWf5KkLtMUU4J5NJH8vQEY,10650
13
13
  pythonclaw/core/__init__.py,sha256=G5LCqUcCIcYYbMv6SreqS-kj8T9n-IvBAhHEG7wDF5w,661
14
- pythonclaw/core/agent.py,sha256=75cLwIF2HH9-IH9YpHoujyPGg9Sapg6vCTMMfHRY1vk,50158
14
+ pythonclaw/core/agent.py,sha256=kNXHAZRy0NcL3lktI4E3P7dz_d2ubTrp3bE7HaUYFGk,50160
15
15
  pythonclaw/core/compaction.py,sha256=b3zrqwBhPmsmQdfRjrvKK6j0hcfNLpiRrZ8qFxY1h1U,8966
16
16
  pythonclaw/core/persistent_agent.py,sha256=nnY1vaZFsn0Wd_MQ27wbG7sRjO1v2ZxbwXjnJGKsBZc,4932
17
17
  pythonclaw/core/session_store.py,sha256=V44wMBbMpbDCh1aiCa5lb0_iXrKA_7VrR1rOHGGZYhs,9458
@@ -20,10 +20,10 @@ pythonclaw/core/skillhub.py,sha256=3MGJ81DFcgcVDCD_Wvf5vHJhcDLZf6IKOhzGzaHkPPQ,1
20
20
  pythonclaw/core/tools.py,sha256=e3ZZnZ5uZt1bj30IBMJP9ZAwhXUEs-3F_q1tmE2Uk90,23205
21
21
  pythonclaw/core/utils.py,sha256=Ih_ZYnulGlxctdyVy4oKknjvkwFS6ZHcdrznIFIAwxo,1919
22
22
  pythonclaw/core/knowledge/rag.py,sha256=_6GKs8ZFirMQhOeT-CAJBkwLcPkEz7Og-gWKMfUezDw,2895
23
- pythonclaw/core/llm/anthropic_client.py,sha256=w6mXlpxvdmulZMD8_ocC8cufDON-RjLIvslWiPb-GnM,11797
23
+ pythonclaw/core/llm/anthropic_client.py,sha256=MrzXK79V5brWnfUdl8HPD3sEZ__8iRgILATb4tSRWes,11797
24
24
  pythonclaw/core/llm/base.py,sha256=y1muHBuK14rvzWlXmoSf6ahz6Xi0BojpnDUTRhaD3pI,1683
25
- pythonclaw/core/llm/gemini_client.py,sha256=Oarzq12YnuMdivAYLLsVmMUTvNCmXXxHfitbUAebYu8,7218
26
- pythonclaw/core/llm/openai_compatible.py,sha256=4FK1OB93tB_ARs_0vdvBADtP3cuNReixNWf6PUkfCys,3567
25
+ pythonclaw/core/llm/gemini_client.py,sha256=pCFcxBov7Kp9uVZ_TEgo7MRFsqxyd71lX2A9NqAwGSs,7218
26
+ pythonclaw/core/llm/openai_compatible.py,sha256=PeqIaZNyCKEyqTnHpmzmIn7djoGN2HJUU4E4uRP47Ts,3567
27
27
  pythonclaw/core/llm/response.py,sha256=hNCsi0aV1ffXsFuDNnBpRp96cFtVDfX_XEC34QZoykc,1223
28
28
  pythonclaw/core/memory/manager.py,sha256=JzNT6CGVRmmIqbOflRzF7HxSfPfI5jLu8tmF6-91ZVA,8945
29
29
  pythonclaw/core/memory/storage.py,sha256=mHDN8yCVUZ5srOwYWDNjUhbELXka-X8zSexFWEBUB1M,9119
@@ -112,9 +112,9 @@ pythonclaw/web/app.py,sha256=uudrxieo5oGwhQUBLzkmn6GU6SnR4VKlRYOg1bFAYQg,32208
112
112
  pythonclaw/web/static/favicon.png,sha256=zJA13uE8mSe6lOlR5NyAhiOmnZkfv7ZlBbSBNCH7iTM,2557
113
113
  pythonclaw/web/static/index.html,sha256=wU4Lw0NcenS0i0HsJS6a6ceFefDxpRsUQnCXVUXYWVU,93734
114
114
  pythonclaw/web/static/logo.png,sha256=h7v0HHllD23FtmCL2UvjjTDt0UgqKjGy5jOhI3rb7lM,28359
115
- pythonclaw-0.6.3.dist-info/licenses/LICENSE,sha256=wbYsm5Ofe8cnxHgWSnSG1vUJDNiY1DIeTyxHSbo1HqM,1066
116
- pythonclaw-0.6.3.dist-info/METADATA,sha256=7uJE3m-kzB0X-DKqlHM5D2GLGfSY7yFrmx-6Xb3NiJc,14919
117
- pythonclaw-0.6.3.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
118
- pythonclaw-0.6.3.dist-info/entry_points.txt,sha256=4uGCuBw-id_22IRdkoxPVOOcwgiPX5lNEpD1XKQWE4I,52
119
- pythonclaw-0.6.3.dist-info/top_level.txt,sha256=S_lM2VH3gP3UeZbSWHXIrBOCNtoqn5pk491IAzgsV7M,11
120
- pythonclaw-0.6.3.dist-info/RECORD,,
115
+ pythonclaw-0.6.4.dist-info/licenses/LICENSE,sha256=wbYsm5Ofe8cnxHgWSnSG1vUJDNiY1DIeTyxHSbo1HqM,1066
116
+ pythonclaw-0.6.4.dist-info/METADATA,sha256=cQ3xhWP9WNNTkyUJehSl2sxJuuZUwVdCiwifLnRYhmM,14919
117
+ pythonclaw-0.6.4.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
118
+ pythonclaw-0.6.4.dist-info/entry_points.txt,sha256=4uGCuBw-id_22IRdkoxPVOOcwgiPX5lNEpD1XKQWE4I,52
119
+ pythonclaw-0.6.4.dist-info/top_level.txt,sha256=S_lM2VH3gP3UeZbSWHXIrBOCNtoqn5pk491IAzgsV7M,11
120
+ pythonclaw-0.6.4.dist-info/RECORD,,