nexo-brain 7.9.30 → 7.9.31

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "7.9.30",
3
+ "version": "7.9.31",
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.9.30` is the current packaged-runtime line. Patch release over `7.9.29`: hotfix for a missing ``import sys`` in ``src/agent_runner.py`` that ruff F821 caught in CI and blocked the 7.9.29 publish workflow before any npm artifact shipped. ``nexo-brain@7.9.30`` is the first npm release that carries the 7.9.29 override-path hardening.
21
+ Version `7.9.31` is the current packaged-runtime line. Patch release over `7.9.30`: fixes a wire-level bug where ``call_model_raw`` was sending ``stop_sequences=["\n", ".", " "]`` by default, which the current Anthropic Messages API rejects with HTTP 400 ``each stop sequence must contain non-whitespace``. The default is now ``None`` (no ``stop_sequences`` field sent) since ``max_tokens=3`` already caps the yes/no classifier output. A local guard rejects whitespace-only caller values up front so the error shows where the caller is, not as a remote 400. Also removes an internal design document that did not belong in the open-source distribution.
22
+
23
+ Previously in `7.9.30`: hotfix for a missing ``import sys`` in ``src/agent_runner.py`` that ruff F821 caught in CI and blocked the 7.9.29 publish workflow before any npm artifact shipped. ``nexo-brain@7.9.30`` is the first npm release that carries the 7.9.29 override-path hardening.
22
24
 
23
25
  Previously in `7.9.29`: hardening pass on the optional LLM endpoint and auth provider override path. The bearer is now passed to the Anthropic SDK via `auth_token` so it lands in the standard `Authorization: Bearer` header (7.9.28 sent it as `X-Api-Key` and any compatible proxy rejected every request with 401). The Brain config directory is resolved on each call instead of cached at import, so LaunchAgent crons that export `NEXO_HOME` via a wrapper now reach the right `~/.nexo/config/`. The `Idempotency-Key` header accepts a caller-provided value so application-level retries reuse the same dedup key. Override mode is strict about its bearer source: if `auth_provider.json` is missing or the helper fails, the call raises `ClassifierUnavailableError` instead of falling back to the operator's real `ANTHROPIC_API_KEY`, which would otherwise leak to the custom proxy as a second header. A new end-to-end test suite drives the real SDK against a local `http.server` and asserts on captured wire headers and body, complementing the SDK-mock unit tests.
24
26
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "7.9.30",
3
+ "version": "7.9.31",
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",
@@ -469,9 +469,16 @@ def _call_anthropic_raw(
469
469
  "model": wire_model,
470
470
  "max_tokens": max_tokens,
471
471
  "temperature": temperature,
472
- "stop_sequences": stop_sequences,
473
472
  "messages": [{"role": "user", "content": prompt}],
474
473
  }
474
+ if stop_sequences:
475
+ # Anthropic API rejects whitespace-only stop sequences with
476
+ # 400 ``each stop sequence must contain non-whitespace``. The
477
+ # caller-validation in call_model_raw filters these out before
478
+ # we reach this point; the empty/None case is also covered by
479
+ # the truthy check above so we omit the field entirely instead
480
+ # of sending ``stop_sequences: null`` to the wire.
481
+ kwargs["stop_sequences"] = stop_sequences
475
482
  if system:
476
483
  kwargs["system"] = system
477
484
 
@@ -582,7 +589,20 @@ def call_model_raw(
582
589
  "enforcer_classifier".
583
590
  max_tokens — hard cap on output tokens. Default 3 (yes/no only).
584
591
  temperature — sampling temperature. Default 0.0 (deterministic).
585
- stop_sequences — early-stop strings. Default ["\\n", ".", " "].
592
+ stop_sequences — early-stop strings. Default ``None`` (no stop
593
+ sequence sent on the wire). Anthropic's API
594
+ rejects whitespace-only entries with
595
+ ``each stop sequence must contain
596
+ non-whitespace`` (HTTP 400), so the previous
597
+ default of ``["\\n", ".", " "]`` made every
598
+ ``enforcer_classifier`` request fail in
599
+ production. ``max_tokens=3`` already serves as
600
+ the hard cap for yes/no classification, so a
601
+ stop sequence is unnecessary by default.
602
+ Callers that want a deterministic stop can
603
+ pass e.g. ``["."]``; whitespace-only entries
604
+ are rejected locally with
605
+ ``ClassifierUnavailableError``.
586
606
  timeout — per-request timeout in seconds. Default 10.0.
587
607
  system — optional system prompt. Default None (provider default).
588
608
  idempotency_key — optional opaque token attached as
@@ -612,8 +632,22 @@ def call_model_raw(
612
632
  Callers MUST catch this and fall back to a safer default. Fase 2 spec
613
633
  0.20 is explicit: silence is not obedience. Never fail-open.
614
634
  """
615
- if stop_sequences is None:
616
- stop_sequences = ["\n", ".", " "]
635
+ if stop_sequences is not None:
636
+ # Anthropic API: ``each stop sequence must contain
637
+ # non-whitespace`` (HTTP 400). Surface the configuration error
638
+ # locally instead of letting Anthropic 400 the request — and,
639
+ # in override mode, instead of letting the proxy translate that
640
+ # 400 into a misleading ``503 all_providers_down``.
641
+ invalid = [
642
+ repr(s) for s in stop_sequences
643
+ if not isinstance(s, str) or not s.strip()
644
+ ]
645
+ if invalid:
646
+ raise ClassifierUnavailableError(
647
+ "stop_sequences contains whitespace-only or non-string "
648
+ f"entries: {', '.join(invalid)}; Anthropic API requires "
649
+ "every stop sequence to contain non-whitespace"
650
+ )
617
651
 
618
652
  # Local imports to avoid circulars and keep agent_runner.py decoupled.
619
653
  from client_preferences import ( # type: ignore