voice-vibecoder 2.26.1__tar.gz → 2.27.0__tar.gz

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.
Files changed (51) hide show
  1. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/CHANGELOG.md +35 -0
  2. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/PKG-INFO +1 -1
  3. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/pyproject.toml +1 -1
  4. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/__init__.py +1 -1
  5. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/server.py +3 -0
  6. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/session.py +13 -2
  7. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/tools/agent_task.py +13 -4
  8. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/.github/workflows/ci.yml +0 -0
  9. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/.github/workflows/release.yml +0 -0
  10. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/.gitignore +0 -0
  11. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/CLAUDE.md +0 -0
  12. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/LICENSE +0 -0
  13. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/README.md +0 -0
  14. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/app.py +0 -0
  15. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/app_config.py +0 -0
  16. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/audio.py +0 -0
  17. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/audio_macos.py +0 -0
  18. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/cli_serve.py +0 -0
  19. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/code_providers/__init__.py +0 -0
  20. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/code_providers/claude.py +0 -0
  21. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/code_providers/cursor.py +0 -0
  22. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/code_providers/openclaw.py +0 -0
  23. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/code_providers/registry.py +0 -0
  24. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/config.py +0 -0
  25. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/instances.py +0 -0
  26. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/tools/__init__.py +0 -0
  27. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/tools/definitions.py +0 -0
  28. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/tools/dispatch.py +0 -0
  29. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/tools/file_tree.py +0 -0
  30. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/tools/handlers.py +0 -0
  31. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/ui/__init__.py +0 -0
  32. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/ui/callbacks.py +0 -0
  33. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/ui/diff_view.py +0 -0
  34. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/ui/help_modal.py +0 -0
  35. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/ui/panels.py +0 -0
  36. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/ui/screen.py +0 -0
  37. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/ui/setup.py +0 -0
  38. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/ui/state.py +0 -0
  39. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/ui/styles.py +0 -0
  40. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/ui/update_modal.py +0 -0
  41. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/ui/wizard.py +0 -0
  42. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/voice_providers/__init__.py +0 -0
  43. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/voice_providers/gemini.py +0 -0
  44. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/voice_providers/openai.py +0 -0
  45. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/src/voice_vibecoder/worktrees.py +0 -0
  46. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/tests/test_audio_gating.py +0 -0
  47. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/tests/test_file_tree.py +0 -0
  48. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/tests/test_merge_branch.py +0 -0
  49. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/tests/test_openai_events.py +0 -0
  50. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/tests/test_session_interrupts.py +0 -0
  51. {voice_vibecoder-2.26.1 → voice_vibecoder-2.27.0}/tests/test_startup_context.py +0 -0
@@ -2,6 +2,41 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v2.27.0 (2026-07-22)
6
+
7
+ ### Bug Fixes
8
+
9
+ - Never run a disabled agent for a persisted instance
10
+ ([#9](https://github.com/snokam/voice-vibecoder/pull/9),
11
+ [`01cd4c0`](https://github.com/snokam/voice-vibecoder/commit/01cd4c0095ef871a022f42929f653e3fe76f5cc9))
12
+
13
+ - Per-connection dispatch state via ContextVars
14
+ ([#9](https://github.com/snokam/voice-vibecoder/pull/9),
15
+ [`01cd4c0`](https://github.com/snokam/voice-vibecoder/commit/01cd4c0095ef871a022f42929f653e3fe76f5cc9))
16
+
17
+ ### Features
18
+
19
+ - Page context via session instructions ([#9](https://github.com/snokam/voice-vibecoder/pull/9),
20
+ [`01cd4c0`](https://github.com/snokam/voice-vibecoder/commit/01cd4c0095ef871a022f42929f653e3fe76f5cc9))
21
+
22
+ - Page context via session instructions, not baked into messages
23
+ ([#9](https://github.com/snokam/voice-vibecoder/pull/9),
24
+ [`01cd4c0`](https://github.com/snokam/voice-vibecoder/commit/01cd4c0095ef871a022f42929f653e3fe76f5cc9))
25
+
26
+
27
+ ## v2.26.2 (2026-07-22)
28
+
29
+ ### Bug Fixes
30
+
31
+ - Never run a disabled agent for a persisted instance
32
+ ([#8](https://github.com/snokam/voice-vibecoder/pull/8),
33
+ [`99b67aa`](https://github.com/snokam/voice-vibecoder/commit/99b67aa74cf4932535d7a16cf5076f6086bb4431))
34
+
35
+ - Per-connection dispatch state via ContextVars
36
+ ([#8](https://github.com/snokam/voice-vibecoder/pull/8),
37
+ [`99b67aa`](https://github.com/snokam/voice-vibecoder/commit/99b67aa74cf4932535d7a16cf5076f6086bb4431))
38
+
39
+
5
40
  ## v2.26.1 (2026-07-22)
6
41
 
7
42
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: voice-vibecoder
3
- Version: 2.26.1
3
+ Version: 2.27.0
4
4
  Summary: Olaf The Vibecoder — a voice-controlled coding assistant using OpenAI Realtime API + Claude Code
5
5
  Project-URL: Homepage, https://github.com/snokam/voice-vibecoder
6
6
  Project-URL: Repository, https://github.com/snokam/voice-vibecoder
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "voice-vibecoder"
7
- version = "2.26.1"
7
+ version = "2.27.0"
8
8
  description = "Olaf The Vibecoder — a voice-controlled coding assistant using OpenAI Realtime API + Claude Code"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -3,7 +3,7 @@
3
3
  A voice-controlled coding assistant using OpenAI Realtime API + Claude Code.
4
4
  """
5
5
 
6
- __version__ = "2.26.1"
6
+ __version__ = "2.27.0"
7
7
 
8
8
  from voice_vibecoder.app_config import VoiceConfig
9
9
  from voice_vibecoder.ui.screen import VoiceCodingScreen
@@ -188,6 +188,9 @@ class WebSocketBridge:
188
188
  else:
189
189
  # Text-only mode: route directly to agent
190
190
  await self._handle_text_only(text)
191
+ elif msg_type == "context":
192
+ if self._session:
193
+ await self._session.set_page_context(msg.get("text", "") or "")
191
194
  elif msg_type == "update_settings":
192
195
  await self._handle_settings_update(msg.get("settings", {}))
193
196
  elif msg_type == "sync_state":
@@ -153,6 +153,7 @@ class RealtimeSession:
153
153
  self._on_response_active = on_response_active
154
154
  self._running = False
155
155
  self._assistant_transcript = ""
156
+ self._page_context = ""
156
157
  self.text_only = False
157
158
  self._response_pending = False
158
159
  self._fallback_task: asyncio.Task | None = None
@@ -227,7 +228,7 @@ class RealtimeSession:
227
228
  s = self._settings
228
229
  overrides = self._voice_config.system_instructions if self._voice_config else None
229
230
  instructions = get_system_instructions(
230
- s.language, context=get_startup_context(),
231
+ s.language, context=self._instructions_context(get_startup_context()),
231
232
  overrides=overrides, enabled_agents=s.enabled_agents,
232
233
  active_instances=get_active_instances_text(),
233
234
  )
@@ -488,12 +489,22 @@ class RealtimeSession:
488
489
  if self._loop and self._running:
489
490
  asyncio.run_coroutine_threadsafe(self._refresh_instructions(), self._loop)
490
491
 
492
+ def _instructions_context(self, base: str) -> str:
493
+ if self._page_context:
494
+ return f"{base}\n\n{self._page_context}" if base else self._page_context
495
+ return base
496
+
497
+ async def set_page_context(self, text: str) -> None:
498
+ self._page_context = (text or "").strip()
499
+ if self._running:
500
+ await self._refresh_instructions()
501
+
491
502
  async def _refresh_instructions(self) -> None:
492
503
  from voice_vibecoder.tools.handlers import get_active_instances_text, get_startup_context
493
504
 
494
505
  overrides = self._voice_config.system_instructions if self._voice_config else None
495
506
  instructions = get_system_instructions(
496
- self._settings.language, context=get_startup_context(),
507
+ self._settings.language, context=self._instructions_context(get_startup_context()),
497
508
  overrides=overrides, enabled_agents=self._settings.enabled_agents,
498
509
  active_instances=get_active_instances_text(),
499
510
  )
@@ -117,7 +117,7 @@ def _create_runner(agent_type: str, permission_mode: str, mcp_servers: dict | No
117
117
 
118
118
  def _handle_send_to_agent(message: str, branch: str | None = None, agent: str | None = None) -> str:
119
119
  from voice_vibecoder.tools.dispatch import (
120
- _default_agent_type, _fuzzy_match_branch, _helper_override,
120
+ _default_agent_type, _enabled_agents, _fuzzy_match_branch, _helper_override,
121
121
  _registry, _repo_root, _resolve_instance,
122
122
  )
123
123
 
@@ -146,8 +146,13 @@ def _handle_send_to_agent(message: str, branch: str | None = None, agent: str |
146
146
  return f"No instance for branch '{branch}'."
147
147
  return "No agent instance available."
148
148
 
149
- # Update agent type if switching on an existing instance
149
+ # Update agent type if switching on an existing instance. A persisted
150
+ # instance may carry an agent that is no longer enabled (e.g. "claude"
151
+ # after the default moved to openclaw); never run a disabled agent —
152
+ # fall back to the default instead of honouring the stale type.
150
153
  resolved_agent = agent or instance.agent_type or target_agent
154
+ if resolved_agent not in _enabled_agents:
155
+ resolved_agent = target_agent
151
156
  if resolved_agent != instance.agent_type:
152
157
  instance.agent_type = resolved_agent
153
158
  instance.session_id = "" # Clear session when switching agents
@@ -191,7 +196,7 @@ def _handle_send_to_agent(message: str, branch: str | None = None, agent: str |
191
196
 
192
197
  def _handle_send_to_session(message: str, session_name: str | None = None, agent: str | None = None, display_name: str | None = None) -> str:
193
198
  from voice_vibecoder.tools.dispatch import (
194
- _default_agent_type, _helper_override,
199
+ _default_agent_type, _enabled_agents, _helper_override,
195
200
  _registry, _repo_root,
196
201
  )
197
202
 
@@ -223,8 +228,12 @@ def _handle_send_to_session(message: str, session_name: str | None = None, agent
223
228
  instance.display_name = display_name
224
229
  _registry._save_state()
225
230
 
226
- # Update agent type if switching
231
+ # Update agent type if switching. Never run a disabled agent — a persisted
232
+ # session may carry a stale type (e.g. "claude" after the default moved to
233
+ # openclaw); fall back to the default in that case.
227
234
  resolved_agent = agent or instance.agent_type or target_agent
235
+ if resolved_agent not in _enabled_agents:
236
+ resolved_agent = target_agent
228
237
  if resolved_agent != instance.agent_type:
229
238
  instance.agent_type = resolved_agent
230
239
  instance.session_id = ""