agentram 0.1.7 → 0.1.8
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/agentram/cli.py +2 -0
- package/agentram/orchestration.py +32 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
package/agentram/cli.py
CHANGED
|
@@ -825,6 +825,8 @@ def model_error_hint(message: str) -> str:
|
|
|
825
825
|
return message + " | Fix: start your OpenAI-compatible server at base_url, or change --base-url."
|
|
826
826
|
if "http 404" in lower or "404: not found" in lower:
|
|
827
827
|
return message + " | Fix: verify base_url includes /v1, provider supports /chat/completions, and model name exists."
|
|
828
|
+
if "http 400" in lower and "not supported" in lower:
|
|
829
|
+
return message + " | Fix: this account/provider rejects that model. Bind a supported model name from your local endpoint."
|
|
828
830
|
if "returned non-json" in lower or "expecting value" in lower:
|
|
829
831
|
return message + " | Fix: endpoint returned empty/HTML/non-JSON. Check base_url, auth key, proxy, and server logs."
|
|
830
832
|
if "missing api key env" in lower:
|
|
@@ -139,6 +139,9 @@ class MultiModelCodingOrchestrator:
|
|
|
139
139
|
try:
|
|
140
140
|
data = json.loads(raw)
|
|
141
141
|
except json.JSONDecodeError as error:
|
|
142
|
+
streamed = parse_openai_sse(raw)
|
|
143
|
+
if streamed:
|
|
144
|
+
return streamed
|
|
142
145
|
raise RuntimeError(f"OpenAI-compatible returned non-JSON at {url} | response={raw[:500]}") from error
|
|
143
146
|
return str(data.get("choices", [{}])[0].get("message", {}).get("content", ""))
|
|
144
147
|
|
|
@@ -188,3 +191,32 @@ class MultiModelCodingOrchestrator:
|
|
|
188
191
|
if process.returncode != 0:
|
|
189
192
|
raise RuntimeError(error or f"claude command failed with exit code {process.returncode}")
|
|
190
193
|
return output or error
|
|
194
|
+
|
|
195
|
+
def parse_openai_sse(raw: str) -> str:
|
|
196
|
+
parts: list[str] = []
|
|
197
|
+
for line in raw.splitlines():
|
|
198
|
+
stripped = line.strip()
|
|
199
|
+
if not stripped.startswith("data:"):
|
|
200
|
+
continue
|
|
201
|
+
payload = stripped[5:].strip()
|
|
202
|
+
if not payload or payload == "[DONE]":
|
|
203
|
+
continue
|
|
204
|
+
try:
|
|
205
|
+
item = json.loads(payload)
|
|
206
|
+
except json.JSONDecodeError:
|
|
207
|
+
continue
|
|
208
|
+
choices = item.get("choices", [])
|
|
209
|
+
if not choices or not isinstance(choices, list):
|
|
210
|
+
continue
|
|
211
|
+
choice = choices[0]
|
|
212
|
+
if not isinstance(choice, dict):
|
|
213
|
+
continue
|
|
214
|
+
delta = choice.get("delta", {})
|
|
215
|
+
if isinstance(delta, dict):
|
|
216
|
+
content = delta.get("content")
|
|
217
|
+
if content:
|
|
218
|
+
parts.append(str(content))
|
|
219
|
+
message = choice.get("message", {})
|
|
220
|
+
if isinstance(message, dict) and message.get("content"):
|
|
221
|
+
parts.append(str(message.get("content")))
|
|
222
|
+
return "".join(parts).strip()
|
package/package.json
CHANGED