@agentikos/omega-os 0.19.34 → 0.19.35

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.
@@ -188,7 +188,7 @@ from omega_engine.genesis import (
188
188
  )
189
189
  from omega_engine import plan as plan_v7
190
190
 
191
- __version__ = "0.19.34"
191
+ __version__ = "0.19.35"
192
192
 
193
193
  __all__ = [
194
194
  "__version__",
@@ -3147,28 +3147,14 @@ def cmd_menu_whiptail(_args: argparse.Namespace) -> int:
3147
3147
  return run_menu()
3148
3148
 
3149
3149
 
3150
- # Default LLM provider for chat sessions — recorded in a tiny state file
3151
- # so spawn_*_chat picks the right one. Hot-swap via `omega switch <id>`.
3152
- _PROVIDER_MARKER = "active-llm-provider"
3153
-
3154
-
3155
- def _provider_state_path() -> "Path":
3156
- from pathlib import Path
3157
- home = _omega_home()
3158
- return home / "Agentik_Extra" / "var" / _PROVIDER_MARKER
3159
-
3160
-
3161
- def _active_provider() -> str:
3162
- p = _provider_state_path()
3163
- if p.exists():
3164
- return p.read_text().strip() or "claude_code"
3165
- return "claude_code"
3166
-
3167
-
3168
- def _set_active_provider(provider_id: str) -> None:
3169
- p = _provider_state_path()
3170
- p.parent.mkdir(parents=True, exist_ok=True)
3171
- p.write_text(provider_id.strip() + "\n")
3150
+ # Active LLM provider now lives in omega_engine.provider_state so the
3151
+ # Textual TUI can read it without a circular cli↔tui import (v0.19.35 fix).
3152
+ from omega_engine.provider_state import (
3153
+ active_provider as _active_provider,
3154
+ set_active_provider as _set_active_provider,
3155
+ provider_state_path as _provider_state_path,
3156
+ PROVIDER_MARKER as _PROVIDER_MARKER,
3157
+ )
3172
3158
 
3173
3159
 
3174
3160
  def cmd_paperclip(args: argparse.Namespace) -> int:
@@ -0,0 +1,42 @@
1
+ """Active-LLM-provider marker — shared between cli.py and tui.py.
2
+
3
+ The provider state lives in a tiny file at
4
+ ``$OMEGA_HOME/Agentik_Extra/var/active-llm-provider``. `omega switch
5
+ <id>` writes here; the TUI and chat-spawn helpers read here.
6
+
7
+ Previously these helpers lived only in cli.py — but tui.py also needs
8
+ to read the active provider (to render `Switch LLM [current: claude_code]`
9
+ in the menu). Importing from cli would be circular (cli already imports
10
+ tui), so the helpers live here in their own neutral module.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import os
15
+ from pathlib import Path
16
+
17
+
18
+ PROVIDER_MARKER = "active-llm-provider"
19
+ DEFAULT_PROVIDER = "claude_code"
20
+
21
+
22
+ def _omega_home() -> Path:
23
+ return Path(os.environ.get("OMEGA_HOME", str(Path.home() / "Omega")))
24
+
25
+
26
+ def provider_state_path() -> Path:
27
+ return _omega_home() / "Agentik_Extra" / "var" / PROVIDER_MARKER
28
+
29
+
30
+ def active_provider() -> str:
31
+ """Read the active provider id, falling back to claude_code."""
32
+ p = provider_state_path()
33
+ if p.exists():
34
+ return p.read_text().strip() or DEFAULT_PROVIDER
35
+ return DEFAULT_PROVIDER
36
+
37
+
38
+ def set_active_provider(provider_id: str) -> None:
39
+ """Persist the active provider id atomically."""
40
+ p = provider_state_path()
41
+ p.parent.mkdir(parents=True, exist_ok=True)
42
+ p.write_text(provider_id.strip() + "\n")
@@ -456,6 +456,12 @@ def _arrow_menu() -> int:
456
456
  def _section(name: str) -> str:
457
457
  return f"{ORANGE}{BOLD}── {name} ──{RST}"
458
458
 
459
+ # `_active_provider` lived in cli.py until v0.19.34 — calling it from
460
+ # here NameError'd at runtime because cli isn't imported here (would
461
+ # be circular: cli already imports tui). Now lives in a neutral
462
+ # `omega_engine.provider_state` module both can read.
463
+ from omega_engine.provider_state import active_provider as _active_provider
464
+
459
465
  def _build_items() -> list[tuple[str, str]]:
460
466
  """Return (display, action_key) — section headers have key '__sep__'."""
461
467
  provider = _active_provider()
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "omega-engine"
3
- version = "0.19.34"
3
+ version = "0.19.35"
4
4
  description = "The Omega OS orchestration engine — event-sourced, verified-completion agent graphs."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -0,0 +1,104 @@
1
+ """Regression tests for omega_engine.tui — specifically the NameError
2
+ that escaped pure-import tests in v0.19.34.
3
+
4
+ v0.19.34's `_arrow_menu` referenced `_active_provider` (defined only in
5
+ cli.py) which failed with NameError when actually invoked, even though
6
+ `import omega_engine.tui` succeeded. Lesson: import-only smoke tests
7
+ don't catch undefined-name errors inside function bodies. These tests
8
+ exercise the function bodies enough to catch the same class of bug.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import inspect
13
+ import os
14
+ import tempfile
15
+ import unittest
16
+ from pathlib import Path
17
+
18
+
19
+ class TestTuiBodyResolves(unittest.TestCase):
20
+ """Compile + exec the bodies of TUI functions to surface undefined
21
+ names. Pytest's normal collection only imports modules — it never
22
+ runs `_arrow_menu` itself."""
23
+
24
+ def test_arrow_menu_body_compiles(self):
25
+ from omega_engine.tui import _arrow_menu
26
+ src = inspect.getsource(_arrow_menu)
27
+ # If a referenced helper isn't importable from inside the
28
+ # function, this raises (catches v0.19.34's NameError class).
29
+ compile(src, "<test>", "exec")
30
+
31
+ def test_plain_repl_body_compiles(self):
32
+ from omega_engine.tui import _plain_repl
33
+ src = inspect.getsource(_plain_repl)
34
+ compile(src, "<test>", "exec")
35
+
36
+ def test_dispatch_slash_for_parse_only_commands(self):
37
+ """Every documented slash command that doesn't shell out to the
38
+ omega binary must produce a CommandResult (no NameError, no
39
+ AttributeError). Commands that shell out (`/audit`, `/switch`,
40
+ `/doctor`, etc.) need the omega binary on disk — those are
41
+ smoke-tested separately on real installs."""
42
+ from omega_engine.tui import dispatch_slash
43
+ # These never shell out — pure dispatch.
44
+ cmds = [
45
+ "/help", "/quit", "/detach", "/unknown_xyz_command",
46
+ "/audit", # no args → static text only, no shell-out
47
+ ]
48
+ for c in cmds:
49
+ r = dispatch_slash(c)
50
+ self.assertIsNotNone(r, f"dispatch_slash({c!r}) returned None")
51
+ self.assertTrue(
52
+ r.text or r.exit_tui or r.detach,
53
+ f"dispatch_slash({c!r}) returned empty result",
54
+ )
55
+
56
+
57
+ class TestProviderStateSharedModule(unittest.TestCase):
58
+ """The fix for v0.19.34's NameError was to extract the provider
59
+ state helpers into omega_engine.provider_state. Lock that in."""
60
+
61
+ def test_provider_state_module_exposes_helpers(self):
62
+ from omega_engine import provider_state as PS
63
+ for name in (
64
+ "active_provider", "set_active_provider",
65
+ "provider_state_path", "PROVIDER_MARKER", "DEFAULT_PROVIDER",
66
+ ):
67
+ self.assertTrue(hasattr(PS, name),
68
+ f"provider_state.{name} missing — TUI + CLI rely on it")
69
+
70
+ def test_get_set_roundtrip(self):
71
+ from omega_engine.provider_state import (
72
+ active_provider, set_active_provider,
73
+ )
74
+ with tempfile.TemporaryDirectory() as tmp:
75
+ old_home = os.environ.get("OMEGA_HOME")
76
+ os.environ["OMEGA_HOME"] = tmp
77
+ try:
78
+ # Default before any set
79
+ self.assertEqual(active_provider(), "claude_code")
80
+ # Set + read
81
+ set_active_provider("gemini_cli")
82
+ self.assertEqual(active_provider(), "gemini_cli")
83
+ # Whitespace stripped
84
+ set_active_provider(" codex ")
85
+ self.assertEqual(active_provider(), "codex")
86
+ finally:
87
+ if old_home is None:
88
+ os.environ.pop("OMEGA_HOME", None)
89
+ else:
90
+ os.environ["OMEGA_HOME"] = old_home
91
+
92
+ def test_cli_imports_from_provider_state(self):
93
+ """The cli.py local `_active_provider` must be re-exported from
94
+ provider_state — not a divergent definition (the bug was that
95
+ cli.py owned the definition and tui.py couldn't see it)."""
96
+ from omega_engine import cli, provider_state
97
+ self.assertIs(cli._active_provider, provider_state.active_provider,
98
+ "cli._active_provider must alias provider_state.active_provider")
99
+ self.assertIs(cli._set_active_provider,
100
+ provider_state.set_active_provider)
101
+
102
+
103
+ if __name__ == "__main__":
104
+ unittest.main()
@@ -1 +1 @@
1
- 0.19.34
1
+ 0.19.35
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentikos/omega-os",
3
- "version": "0.19.34",
3
+ "version": "0.19.35",
4
4
  "description": "Omega OS — installable agentic operating system with verified-completion orchestration. Event-sourced engine, 8-block rack, autonomous agents, MCP.",
5
5
  "bin": {
6
6
  "omega-os": "bin/omega-os.js"