fix: greedy match for file_content extraction; tgapp: add running indicator, HTML formatting, single instance lock; misc improvements
This commit is contained in:
@@ -7,7 +7,6 @@ class StepOutcome:
|
||||
next_prompt: Optional[str] = None
|
||||
should_exit: bool = False
|
||||
|
||||
|
||||
def try_call_generator(func, *args, **kwargs):
|
||||
ret = func(*args, **kwargs)
|
||||
if hasattr(ret, '__iter__') and not isinstance(ret, (str, bytes, dict, list)):
|
||||
@@ -66,9 +65,9 @@ def agent_runner_loop(client, system_prompt, user_input, handler, tools_schema,
|
||||
|
||||
if tool_name == 'no_tool': pass
|
||||
else:
|
||||
yield f"🛠️ **正在调用工具:** `{tool_name}`"
|
||||
if verbose: yield f"📥**参数:**\n````text\n{get_pretty_json(args)}\n````\n"
|
||||
else: yield '\n\n\n'
|
||||
showarg = get_pretty_json(args)
|
||||
if not verbose and len(showarg) > 200: showarg = showarg[:200] + ' ...'
|
||||
yield f"🛠️ **正在调用工具:** `{tool_name}` 📥**参数:**\n````text\n{showarg}\n````\n"
|
||||
gen = handler.dispatch(tool_name, args, response)
|
||||
if verbose:
|
||||
yield '`````\n'
|
||||
|
||||
8
ga.py
8
ga.py
@@ -226,8 +226,7 @@ def smart_format(data, max_depth=2, max_str_len=100, omit_str=' ... '):
|
||||
return json.dumps(truncate(data, 0), indent=2, ensure_ascii=False, default=str)
|
||||
|
||||
class GenericAgentHandler(BaseHandler):
|
||||
'''
|
||||
Generic Agent 工具库,包含多种工具的实现。工具函数自动加上了 do_ 前缀。实际工具名没有前缀。
|
||||
'''Generic Agent 工具库,包含多种工具的实现。工具函数自动加上了 do_ 前缀。实际工具名没有前缀。
|
||||
'''
|
||||
def __init__(self, parent, last_history=None, cwd='./'):
|
||||
self.parent = parent
|
||||
@@ -331,7 +330,7 @@ class GenericAgentHandler(BaseHandler):
|
||||
yield f"[Action] {action_str} file: {os.path.basename(path)}\n"
|
||||
|
||||
def extract_robust_content(text):
|
||||
tag = re.search(r"<file_content>(.*?)</file_content>", text, re.DOTALL)
|
||||
tag = re.search(r"<file_content>(.*)</file_content>", text, re.DOTALL)
|
||||
if tag: return tag.group(1).strip()
|
||||
s, e = text.find("```"), text.rfind("```")
|
||||
if -1 < s < e: return text[text.find("\n", s)+1 : e].strip()
|
||||
@@ -450,7 +449,8 @@ class GenericAgentHandler(BaseHandler):
|
||||
prompt = f"\n### [WORKING MEMORY]\n<history>\n{h_str}\n</history>"
|
||||
if self.key_info: prompt += f"\n<key_info>{self.key_info}</key_info>"
|
||||
if self.related_sop: prompt += f"\n有不清晰的地方请再次读取{self.related_sop}"
|
||||
print(prompt)
|
||||
try: print(prompt)
|
||||
except: pass
|
||||
return prompt
|
||||
|
||||
def get_global_memory():
|
||||
|
||||
@@ -17,7 +17,7 @@ def get_screen_width():
|
||||
except: return 1920
|
||||
|
||||
def start_streamlit(port):
|
||||
global proc
|
||||
global proc, tgproc
|
||||
cmd = [
|
||||
sys.executable, "-m", "streamlit", "run", "stapp.py",
|
||||
"--server.port", str(port),
|
||||
@@ -26,6 +26,8 @@ def start_streamlit(port):
|
||||
]
|
||||
proc = subprocess.Popen(cmd)
|
||||
atexit.register(proc.kill)
|
||||
tgproc = subprocess.Popen([sys.executable, "tgapp.py"], creationflags=subprocess.CREATE_NO_WINDOW if os.name=='nt' else 0)
|
||||
atexit.register(tgproc.kill)
|
||||
|
||||
def inject(text):
|
||||
window.evaluate_js(f"""
|
||||
|
||||
11
sidercall.py
11
sidercall.py
@@ -53,10 +53,10 @@ class ClaudeSession:
|
||||
return result[::-1] or messages[-2:]
|
||||
def raw_ask(self, messages, model=None, temperature=0.5, max_tokens=4096):
|
||||
model = model or self.default_model
|
||||
headers = {"x-api-key": self.api_key, "Content-Type": "application/json"}
|
||||
headers = {"x-api-key": self.api_key, "Content-Type": "application/json", "anthropic-version": "2023-06-01"}
|
||||
payload = {"model": model, "messages": messages, "temperature": temperature, "max_tokens": max_tokens, "stream": True}
|
||||
try:
|
||||
with requests.post(f"{self.api_base}/v1/messages", headers=headers, json=payload, stream=True, timeout=(5,60), verify=False) as r:
|
||||
with requests.post(f"{self.api_base}/v1/messages", headers=headers, json=payload, stream=True, timeout=(5,60)) as r:
|
||||
r.raise_for_status()
|
||||
for line in r.iter_lines():
|
||||
if not line: continue
|
||||
@@ -208,9 +208,8 @@ class GeminiSession:
|
||||
return iter([full_text]) if stream else full_text
|
||||
|
||||
class MockFunction:
|
||||
def __init__(self, name, arguments):
|
||||
self.name = name
|
||||
self.arguments = arguments
|
||||
def __init__(self, name, arguments): self.name, self.arguments = name, arguments
|
||||
|
||||
|
||||
class MockToolCall:
|
||||
def __init__(self, name, args):
|
||||
@@ -265,7 +264,7 @@ class ToolClient:
|
||||
请按照以下步骤思考并行动,标签之间需要回车换行:
|
||||
1. **思考**: 在 `<thinking>` 标签中先进行思考,分析现状和策略。
|
||||
2. **总结**: 在 `<summary>` 中输出*极为简短*的高度概括的单行(<30字)物理快照,包括上次工具调用结果获取的新信息+本次工具调用意图和预期。此内容将进入长期工作记忆,记录关键信息,严禁输出无实际信息增量的描述。
|
||||
3. **行动**: 如果需要调用工具,请在回复正文之后输出一个 **<tool_use>块**,然后结束,我会稍后给你返回<tool_result>块。
|
||||
3. **行动**: 如需调用工具,请在回复正文之后输出一个 **<tool_use>块**,然后结束,我会稍后给你返回<tool_result>块。
|
||||
格式: ```<tool_use>\n{{"name": "工具名", "arguments": {{参数}}}}\n</tool_use>\n```
|
||||
|
||||
### 可用工具库(已挂载,持续有效)
|
||||
|
||||
32
tgapp.py
32
tgapp.py
@@ -1,4 +1,4 @@
|
||||
import os, sys, re, threading, asyncio, queue as Q
|
||||
import os, sys, re, threading, asyncio, queue as Q, socket
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from agentmain import GeneraticAgent
|
||||
from telegram import Update
|
||||
@@ -17,6 +17,21 @@ def _clean(t):
|
||||
t = re.sub(p, '', t, flags=re.DOTALL)
|
||||
return re.sub(r'\n{3,}', '\n\n', t).strip() or '...'
|
||||
|
||||
import html as _html
|
||||
def _inline_md(s):
|
||||
s = re.sub(r'\*\*(.+?)\*\*', r'<b>\1</b>', s)
|
||||
s = re.sub(r'(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)', r'<i>\1</i>', s)
|
||||
s = re.sub(r'`([^`]+)`', r'<code>\1</code>', s)
|
||||
return s
|
||||
def _to_html(t):
|
||||
parts, pos = [], 0
|
||||
for m in re.finditer(r'(`{3,})(?:\w*\n)?([\s\S]*?)\1', t):
|
||||
parts.append(_inline_md(_html.escape(t[pos:m.start()])))
|
||||
parts.append('<pre><code>' + _html.escape(m.group(2)) + '</code></pre>')
|
||||
pos = m.end()
|
||||
parts.append(_inline_md(_html.escape(t[pos:])))
|
||||
return ''.join(parts)
|
||||
|
||||
async def _stream(dq, msg):
|
||||
last_text = ""
|
||||
while True:
|
||||
@@ -35,10 +50,13 @@ async def _stream(dq, msg):
|
||||
except Exception: pass
|
||||
last_text = ""
|
||||
show = show[-3900:]
|
||||
if show != last_text:
|
||||
try: await msg.edit_text(show)
|
||||
display = show if done else show + " ⏳"
|
||||
if display != last_text:
|
||||
try: await msg.edit_text(_to_html(display), parse_mode='HTML')
|
||||
except Exception:
|
||||
try: await msg.edit_text(display)
|
||||
except Exception: pass
|
||||
last_text = show
|
||||
last_text = display
|
||||
if done: break
|
||||
|
||||
async def handle_msg(update, ctx):
|
||||
@@ -67,10 +85,14 @@ async def cmd_llm(update, ctx):
|
||||
await update.message.reply_text("LLMs:\n" + "\n".join(lines))
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Single instance lock using socket
|
||||
try:
|
||||
_lock_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM); _lock_sock.bind(('127.0.0.1', 19527))
|
||||
except OSError: sys.exit('Another instance is already running.')
|
||||
if not ALLOWED:
|
||||
sys.exit('ERROR: tg_allowed_users in mykey.py is empty or missing. Set it to avoid unauthorized access.')
|
||||
threading.Thread(target=agent.run, daemon=True).start()
|
||||
proxy = os.environ.get('HTTPS_PROXY') or 'http://127.0.0.1:2082'
|
||||
proxy = vars(mykey).get('proxy', '127.0.0.1:2082')
|
||||
app = ApplicationBuilder().token(mykey.tg_bot_token).proxy(proxy).get_updates_proxy(proxy).build()
|
||||
app.add_handler(CommandHandler("stop", cmd_abort))
|
||||
app.add_handler(CommandHandler("llm", cmd_llm))
|
||||
|
||||
Reference in New Issue
Block a user