@rethinkingstudio/clawpilot 2.1.21-beta.1 → 2.1.21-beta.10
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/package.json +1 -1
- package/scripts/hermes_agent_bridge.py +85 -12
package/package.json
CHANGED
|
@@ -87,30 +87,102 @@ def read_base_config_for_profile() -> Dict[str, Any]:
|
|
|
87
87
|
return read_yaml_config(parent.parent / "config.yaml")
|
|
88
88
|
|
|
89
89
|
|
|
90
|
+
def normalize_message_content(value: Any) -> Any:
|
|
91
|
+
if value is None:
|
|
92
|
+
return ""
|
|
93
|
+
if isinstance(value, str):
|
|
94
|
+
return value
|
|
95
|
+
if isinstance(value, list):
|
|
96
|
+
parts: List[Any] = []
|
|
97
|
+
for part in value:
|
|
98
|
+
if isinstance(part, str):
|
|
99
|
+
parts.append({"type": "text", "text": part})
|
|
100
|
+
continue
|
|
101
|
+
if not isinstance(part, dict):
|
|
102
|
+
continue
|
|
103
|
+
clean_part = {k: v for k, v in part.items() if v is not None}
|
|
104
|
+
if clean_part.get("type") == "text":
|
|
105
|
+
clean_part["text"] = str(clean_part.get("text") or "")
|
|
106
|
+
if clean_part:
|
|
107
|
+
parts.append(clean_part)
|
|
108
|
+
return parts if parts else ""
|
|
109
|
+
return str(value)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def normalize_tool_calls(value: Any) -> List[Dict[str, Any]]:
|
|
113
|
+
if not isinstance(value, list):
|
|
114
|
+
return []
|
|
115
|
+
clean_calls: List[Dict[str, Any]] = []
|
|
116
|
+
for index, call in enumerate(value):
|
|
117
|
+
if not isinstance(call, dict):
|
|
118
|
+
continue
|
|
119
|
+
raw_function = call.get("function")
|
|
120
|
+
function = raw_function if isinstance(raw_function, dict) else {}
|
|
121
|
+
name = str(function.get("name") or call.get("name") or "").strip()
|
|
122
|
+
if not name:
|
|
123
|
+
continue
|
|
124
|
+
raw_arguments = function.get("arguments")
|
|
125
|
+
if raw_arguments is None:
|
|
126
|
+
arguments = "{}"
|
|
127
|
+
elif isinstance(raw_arguments, str):
|
|
128
|
+
arguments = raw_arguments
|
|
129
|
+
else:
|
|
130
|
+
try:
|
|
131
|
+
arguments = json.dumps(raw_arguments, ensure_ascii=False)
|
|
132
|
+
except Exception:
|
|
133
|
+
arguments = str(raw_arguments)
|
|
134
|
+
call_id = str(call.get("id") or call.get("call_id") or f"call_{index}").strip()
|
|
135
|
+
clean_calls.append(
|
|
136
|
+
{
|
|
137
|
+
"id": call_id,
|
|
138
|
+
"type": str(call.get("type") or "function"),
|
|
139
|
+
"function": {
|
|
140
|
+
"name": name,
|
|
141
|
+
"arguments": arguments,
|
|
142
|
+
},
|
|
143
|
+
}
|
|
144
|
+
)
|
|
145
|
+
return clean_calls
|
|
146
|
+
|
|
147
|
+
|
|
90
148
|
def sanitize_messages_for_api(messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
91
149
|
valid_tool_call_ids: set[str] = set()
|
|
92
150
|
for msg in messages:
|
|
93
151
|
if not isinstance(msg, dict):
|
|
94
152
|
continue
|
|
95
153
|
if msg.get("role") == "assistant":
|
|
96
|
-
for tc in msg.get("tool_calls")
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
valid_tool_call_ids.add(str(tid))
|
|
154
|
+
for tc in normalize_tool_calls(msg.get("tool_calls")):
|
|
155
|
+
tid = tc.get("id") or ""
|
|
156
|
+
if tid:
|
|
157
|
+
valid_tool_call_ids.add(str(tid))
|
|
101
158
|
|
|
102
159
|
clean: List[Dict[str, Any]] = []
|
|
103
160
|
for msg in messages:
|
|
104
161
|
if not isinstance(msg, dict):
|
|
105
162
|
continue
|
|
106
|
-
role = msg.get("role")
|
|
163
|
+
role = str(msg.get("role") or "").strip()
|
|
164
|
+
if role not in {"system", "user", "assistant", "tool"}:
|
|
165
|
+
continue
|
|
166
|
+
sanitized: Dict[str, Any] = {"role": role}
|
|
107
167
|
if role == "tool":
|
|
108
168
|
tid = str(msg.get("tool_call_id") or "")
|
|
109
169
|
if not tid or tid not in valid_tool_call_ids:
|
|
110
170
|
continue
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
171
|
+
sanitized["tool_call_id"] = tid
|
|
172
|
+
if msg.get("name"):
|
|
173
|
+
sanitized["name"] = str(msg.get("name"))
|
|
174
|
+
|
|
175
|
+
if role == "assistant":
|
|
176
|
+
tool_calls = normalize_tool_calls(msg.get("tool_calls"))
|
|
177
|
+
if tool_calls:
|
|
178
|
+
sanitized["tool_calls"] = tool_calls
|
|
179
|
+
|
|
180
|
+
content = normalize_message_content(msg.get("content"))
|
|
181
|
+
if content or role != "assistant" or sanitized.get("tool_calls"):
|
|
182
|
+
sanitized["content"] = content
|
|
183
|
+
if msg.get("refusal") is not None:
|
|
184
|
+
sanitized["refusal"] = str(msg.get("refusal"))
|
|
185
|
+
clean.append(sanitized)
|
|
114
186
|
return clean
|
|
115
187
|
|
|
116
188
|
|
|
@@ -147,9 +219,10 @@ def read_session_history_from_json(session_id: Optional[str]) -> List[Dict[str,
|
|
|
147
219
|
|
|
148
220
|
|
|
149
221
|
def read_session_history(session_id: Optional[str], session_db: Optional[SessionDB]) -> List[Dict[str, Any]]:
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
222
|
+
if os.environ.get("CLAWPILOT_HERMES_BRIDGE_DISABLE_SESSIONDB_HISTORY") != "1":
|
|
223
|
+
from_db = read_session_history_from_db(session_id, session_db)
|
|
224
|
+
if from_db:
|
|
225
|
+
return from_db
|
|
153
226
|
return read_session_history_from_json(session_id)
|
|
154
227
|
|
|
155
228
|
|