nexo-brain 7.17.0 → 7.17.1
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/.claude-plugin/plugin.json +1 -1
- package/README.md +3 -1
- package/package.json +1 -1
- package/src/agent_runner.py +21 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.17.
|
|
3
|
+
"version": "7.17.1",
|
|
4
4
|
"description": "Local cognitive runtime for Claude Code \u2014 persistent memory, overnight learning, doctor diagnostics, personal scripts, recovery-aware jobs, startup preflight, and optional dashboard/power helper.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "NEXO Brain",
|
package/README.md
CHANGED
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
|
|
19
19
|
[Watch the overview video](https://nexo-brain.com/watch/) · [Watch on YouTube](https://www.youtube.com/watch?v=i2lkGhKyVqI) · [Open the infographic](https://nexo-brain.com/assets/nexo-brain-infographic-v5.png)
|
|
20
20
|
|
|
21
|
-
Version `7.17.
|
|
21
|
+
Version `7.17.1` is the current packaged-runtime line. Patch release over v7.17.0 - the headless Claude CLI 2.1+ direct-JSON response shape is now handled: when the wrapper `{"result": ...}` is absent and the agent's answer is returned directly, `_extract_claude_telemetry` surfaces the full payload to the caller instead of an empty string. Fixes the daily morning-agent failure with "Morning agent returned invalid JSON output".
|
|
22
|
+
|
|
23
|
+
Previously in `7.17.0`: minor release over v7.16.3 - the headless runner pre-emptive guard becomes advisory: it surfaces learnings/schemas to the agent and logs to `guard_checks`, but never returns `blocked=True`. The PreToolUse hook is the authoritative gate at write time.
|
|
22
24
|
|
|
23
25
|
Previously in `7.16.3`: patch release over v7.16.2 - the headless runner guard opts out of the runtime-core blocking rule because actual writes on those paths are already blocked at the PreToolUse layer.
|
|
24
26
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexo-brain",
|
|
3
|
-
"version": "7.17.
|
|
3
|
+
"version": "7.17.1",
|
|
4
4
|
"mcpName": "io.github.wazionapps/nexo",
|
|
5
5
|
"description": "NEXO Brain — Shared brain for AI agents. Persistent memory, semantic RAG, natural forgetting, metacognitive guard, trust scoring, 150+ MCP tools. Works with Claude Code, Codex, Claude Desktop & any MCP client. 100% local, free.",
|
|
6
6
|
"homepage": "https://nexo-brain.com",
|
package/src/agent_runner.py
CHANGED
|
@@ -94,15 +94,32 @@ def _extract_claude_telemetry(raw_stdout: str, *, requested_output_format: str)
|
|
|
94
94
|
"warnings": ["backend did not return parseable JSON telemetry"],
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
# Two shapes can arrive in raw_stdout:
|
|
98
|
+
# (a) Classic Claude CLI wrapper:
|
|
99
|
+
# {"result": "<agent text or stringified JSON>", "usage": {...}, "total_cost_usd": N}
|
|
100
|
+
# (b) Direct agent JSON (Claude CLI 2.1+ with bare_mode + output_format=json
|
|
101
|
+
# + a prompt that requests raw JSON only). The wrapper is dropped and
|
|
102
|
+
# the entire payload IS the agent's answer, e.g. {"subject":..., "body":...}.
|
|
103
|
+
# Pre-7.17.1 only handled (a): payload.get("result", "") returned "" in case (b),
|
|
104
|
+
# which left result.stdout empty for the caller. morning-agent then raised
|
|
105
|
+
# "Morning agent returned invalid JSON output" on every cron tick even though
|
|
106
|
+
# the agent had answered correctly and the answer was already persisted in
|
|
107
|
+
# automation_runs.metadata.raw. The branch below normalises both shapes.
|
|
108
|
+
if "result" in payload:
|
|
109
|
+
result_payload = payload["result"]
|
|
110
|
+
telemetry_payload = payload
|
|
111
|
+
else:
|
|
112
|
+
result_payload = payload
|
|
113
|
+
telemetry_payload = {}
|
|
114
|
+
|
|
98
115
|
if requested_output_format and requested_output_format.lower() == "json" and not isinstance(result_payload, str):
|
|
99
116
|
final_stdout = json.dumps(result_payload, ensure_ascii=False)
|
|
100
117
|
else:
|
|
101
118
|
final_stdout = result_payload if isinstance(result_payload, str) else json.dumps(result_payload, ensure_ascii=False)
|
|
102
119
|
|
|
103
|
-
usage =
|
|
104
|
-
model_usage =
|
|
105
|
-
explicit_cost =
|
|
120
|
+
usage = telemetry_payload.get("usage") or {}
|
|
121
|
+
model_usage = telemetry_payload.get("modelUsage") or {}
|
|
122
|
+
explicit_cost = telemetry_payload.get("total_cost_usd")
|
|
106
123
|
if explicit_cost is None and isinstance(model_usage, dict):
|
|
107
124
|
explicit_cost = sum(
|
|
108
125
|
float((item or {}).get("costUSD") or 0.0)
|