fix: improve JSON parsing error handling with bad_json mechanism
This commit is contained in:
Binary file not shown.
BIN
.vs/GenericAgent/v17/.wsuo
Normal file
BIN
.vs/GenericAgent/v17/.wsuo
Normal file
Binary file not shown.
12
.vs/GenericAgent/v17/DocumentLayout.json
Normal file
12
.vs/GenericAgent/v17/DocumentLayout.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"WorkspaceRootPath": "C:\\Users\\Ljq\\Documents\\mywork\\MyTools\\AutoOperation\\webagent\\GenericAgent\\",
|
||||||
|
"Documents": [],
|
||||||
|
"DocumentGroupContainers": [
|
||||||
|
{
|
||||||
|
"Orientation": 0,
|
||||||
|
"VerticalTabListWidth": 256,
|
||||||
|
"DocumentGroups": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
3
.vs/ProjectSettings.json
Normal file
3
.vs/ProjectSettings.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"CurrentProjectSetting": null
|
||||||
|
}
|
||||||
6
.vs/VSWorkspaceState.json
Normal file
6
.vs/VSWorkspaceState.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"ExpandedNodes": [
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"PreviewInSolutionExplorer": false
|
||||||
|
}
|
||||||
BIN
.vs/slnx.sqlite
Normal file
BIN
.vs/slnx.sqlite
Normal file
Binary file not shown.
@@ -24,6 +24,8 @@ class BaseHandler:
|
|||||||
ret = yield from try_call_generator(getattr(self, method_name), args, response)
|
ret = yield from try_call_generator(getattr(self, method_name), args, response)
|
||||||
_ = yield from try_call_generator(self.tool_after_callback, tool_name, args, response, ret)
|
_ = yield from try_call_generator(self.tool_after_callback, tool_name, args, response, ret)
|
||||||
return ret
|
return ret
|
||||||
|
elif tool_name == 'bad_json':
|
||||||
|
return StepOutcome(None, next_prompt=args.get('msg', 'bad_json'), should_exit=False)
|
||||||
else:
|
else:
|
||||||
yield f"❌ 未知工具: {tool_name}\n"
|
yield f"❌ 未知工具: {tool_name}\n"
|
||||||
return StepOutcome(None, next_prompt=f"未知工具 {tool_name}", should_exit=False)
|
return StepOutcome(None, next_prompt=f"未知工具 {tool_name}", should_exit=False)
|
||||||
|
|||||||
@@ -30,15 +30,14 @@ class GeneraticAgent:
|
|||||||
if not os.path.exists('temp'): os.makedirs('temp')
|
if not os.path.exists('temp'): os.makedirs('temp')
|
||||||
from sidercall import sider_cookie, oai_configs, claude_configs
|
from sidercall import sider_cookie, oai_configs, claude_configs
|
||||||
llm_sessions = []
|
llm_sessions = []
|
||||||
|
for cfg in claude_configs.values():
|
||||||
|
llm_sessions += [ClaudeSession(api_key=cfg['apikey'], api_base=cfg['apibase'], model=cfg['model'])]
|
||||||
if sider_cookie: llm_sessions += [SiderLLMSession(default_model=x) for x in \
|
if sider_cookie: llm_sessions += [SiderLLMSession(default_model=x) for x in \
|
||||||
["gemini-3.0-flash", "claude-haiku-4.5", "kimi-k2"]]
|
["gemini-3.0-flash", "claude-haiku-4.5", "kimi-k2"]]
|
||||||
for cfg in oai_configs.values():
|
for cfg in oai_configs.values():
|
||||||
llm_sessions += [LLMSession(api_key=cfg['apikey'], api_base=cfg['apibase'], model=cfg['model'])]
|
llm_sessions += [LLMSession(api_key=cfg['apikey'], api_base=cfg['apibase'], model=cfg['model'])]
|
||||||
for cfg in claude_configs.values():
|
|
||||||
llm_sessions += [ClaudeSession(api_key=cfg['apikey'], api_base=cfg['apibase'], model=cfg['model'])]
|
|
||||||
if len(llm_sessions) > 0:
|
if len(llm_sessions) > 0:
|
||||||
llmclient = ToolClient(llm_sessions, auto_save_tokens=True)
|
self.llmclient = ToolClient(llm_sessions, auto_save_tokens=True)
|
||||||
self.llmclient = llmclient
|
|
||||||
else:
|
else:
|
||||||
self.llmclient = None
|
self.llmclient = None
|
||||||
self.lock = threading.Lock()
|
self.lock = threading.Lock()
|
||||||
|
|||||||
16
ga.py
16
ga.py
@@ -84,20 +84,10 @@ def code_run(code, code_type="python", timeout=60, cwd=None, code_cwd=None, stop
|
|||||||
|
|
||||||
|
|
||||||
def ask_user(question: str, candidates: list = None):
|
def ask_user(question: str, candidates: list = None):
|
||||||
|
"""question: 向用户提出的问题。candidates: 可选的候选项列表。需要保证should_exit为True
|
||||||
"""
|
"""
|
||||||
构造一个中断请求。
|
return {"status": "INTERRUPT", "intent": "HUMAN_INTERVENTION",
|
||||||
question: 向用户提出的问题。
|
"data": {"question": question, "candidates": candidates or []}}
|
||||||
candidates: 可选的候选项列表。
|
|
||||||
需要保证should_exit为True
|
|
||||||
"""
|
|
||||||
return {
|
|
||||||
"status": "INTERRUPT",
|
|
||||||
"intent": "HUMAN_INTERVENTION",
|
|
||||||
"data": {
|
|
||||||
"question": question,
|
|
||||||
"candidates": candidates or []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
from simphtml import execute_js_rich, get_html
|
from simphtml import execute_js_rich, get_html
|
||||||
|
|
||||||
|
|||||||
2964
restore_commit.txt
Normal file
2964
restore_commit.txt
Normal file
File diff suppressed because it is too large
Load Diff
14
sidercall.py
14
sidercall.py
@@ -56,18 +56,18 @@ class GeminiSession:
|
|||||||
return iter([full_text]) if stream else full_text
|
return iter([full_text]) if stream else full_text
|
||||||
|
|
||||||
class ClaudeSession:
|
class ClaudeSession:
|
||||||
def __init__(self, api_key, api_base, model="claude-opus", context_win=32000):
|
def __init__(self, api_key, api_base, model="claude-opus", context_win=24000):
|
||||||
self.api_key, self.api_base, self.default_model, self.context_win = api_key, api_base.rstrip('/'), model, context_win
|
self.api_key, self.api_base, self.default_model, self.context_win = api_key, api_base.rstrip('/'), model, context_win
|
||||||
self.raw_msgs, self.lock = [], threading.Lock()
|
self.raw_msgs, self.lock = [], threading.Lock()
|
||||||
def _trim_messages(self, messages):
|
def _trim_messages(self, messages):
|
||||||
total = sum(len(m['prompt'])//4 for m in messages)
|
total = sum(len(m['prompt'])//4 for m in messages)
|
||||||
if total <= self.context_win: return messages
|
if total <= self.context_win: return messages
|
||||||
trimmed = []
|
target, current, result = self.context_win * 0.9, 0, []
|
||||||
for msg in reversed(messages):
|
for msg in reversed(messages):
|
||||||
if sum(len(m['prompt'])//4 for m in trimmed) + len(msg['prompt'])//4 <= self.context_win * 0.9:
|
if (msg_len := len(msg['prompt'])//4) + current <= target:
|
||||||
trimmed.insert(0, msg)
|
result.append(msg); current += msg_len
|
||||||
else: break
|
else: break
|
||||||
return trimmed if trimmed else messages[-2:]
|
return result[::-1] or messages[-2:]
|
||||||
def raw_ask(self, messages, model=None, temperature=0.5, max_tokens=4096):
|
def raw_ask(self, messages, model=None, temperature=0.5, max_tokens=4096):
|
||||||
model = model or self.default_model
|
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"}
|
||||||
@@ -315,9 +315,9 @@ class ToolClient:
|
|||||||
args = data.get('arguments') or data.get('args') or data.get('params') or data.get('parameters')
|
args = data.get('arguments') or data.get('args') or data.get('params') or data.get('parameters')
|
||||||
if args is None: args = data
|
if args is None: args = data
|
||||||
if func_name: tool_calls = [MockToolCall(func_name, args)]
|
if func_name: tool_calls = [MockToolCall(func_name, args)]
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError as e:
|
||||||
print("[Warn] Failed to parse tool_use JSON:", json_str)
|
print("[Warn] Failed to parse tool_use JSON:", json_str)
|
||||||
remaining_text += f"[Warning] JSON 解析失败,模型输出了无效的 JSON."
|
tool_calls = [MockToolCall('bad_json', {'msg': f'Failed to parse tool_use JSON: {str(e)}'})]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("[Error] Exception during tool_use parsing:", str(e), data)
|
print("[Error] Exception during tool_use parsing:", str(e), data)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user