voice-vibecoder 2.5.2__tar.gz → 2.5.3__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.
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/CHANGELOG.md +8 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/PKG-INFO +1 -1
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/pyproject.toml +1 -1
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/__init__.py +1 -1
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/config.py +26 -4
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/session.py +4 -2
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/tools/agent_task.py +15 -2
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/tools/handlers.py +20 -9
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/.github/workflows/ci.yml +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/.github/workflows/release.yml +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/.gitignore +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/LICENSE +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/README.md +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/app.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/index.html +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/app_config.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/audio.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/cli_serve.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/code_providers/__init__.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/code_providers/claude.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/code_providers/cursor.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/code_providers/registry.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/instances.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/server.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/tools/__init__.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/tools/definitions.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/tools/dispatch.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/tools/file_tree.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/ui/__init__.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/ui/callbacks.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/ui/diff_view.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/ui/help_modal.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/ui/panels.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/ui/screen.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/ui/setup.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/ui/state.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/ui/styles.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/ui/update_modal.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/ui/wizard.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/voice_providers/__init__.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/voice_providers/openai.py +0 -0
- {voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/worktrees.py +0 -0
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- version list -->
|
|
4
4
|
|
|
5
|
+
## v2.5.3 (2026-02-20)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Prevent duplicate sessions by embedding active instances in instructions
|
|
10
|
+
([`7f493dc`](https://github.com/snokam/voice-vibecoder/commit/7f493dc275d7913edc760afc8ac3b2c066062954))
|
|
11
|
+
|
|
12
|
+
|
|
5
13
|
## v2.5.2 (2026-02-20)
|
|
6
14
|
|
|
7
15
|
### Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voice-vibecoder
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.3
|
|
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.5.
|
|
7
|
+
version = "2.5.3"
|
|
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"
|
|
@@ -47,9 +47,12 @@ Branch-navn fuzzy-matches — f.eks. "branding" matcher "feat/branding-refresh".
|
|
|
47
47
|
send_to_session med beskrivende navn. Gjenbruk eksisterende sesjoner for samme tema.
|
|
48
48
|
|
|
49
49
|
Sesjoner:
|
|
50
|
+
- SJEKK ALLTID listen over aktive sesjoner nedenfor før du oppretter en ny.
|
|
51
|
+
- Hvis en sesjon dekker samme tema, GJENBRUK den ved å bruke det eksakte navnet.
|
|
52
|
+
- Opprett kun en ny sesjon for et genuint annet tema.
|
|
50
53
|
- Bruk beskrivende navn: "jira-research", "ci-status", "arkitektur-gjennomgang".
|
|
51
|
-
- Gjenbruk en sesjon hvis temaet er det samme. Opprett ny for nytt tema.
|
|
52
54
|
- remove_session for å fjerne en sesjon.
|
|
55
|
+
{active_instances}
|
|
53
56
|
|
|
54
57
|
Agenter:
|
|
55
58
|
- Tilgjengelige agenter: {agent_names}.
|
|
@@ -100,9 +103,12 @@ Branch names are fuzzy-matched — e.g. "branding" matches "feat/branding-refres
|
|
|
100
103
|
send_to_session with a descriptive name. Reuse existing sessions for the same topic.
|
|
101
104
|
|
|
102
105
|
Sessions:
|
|
106
|
+
- ALWAYS check the active sessions list below before creating a new one.
|
|
107
|
+
- If a session covers the same topic, REUSE it by using its exact name.
|
|
108
|
+
- Only create a new session for a genuinely different topic.
|
|
103
109
|
- Use descriptive names: "jira-research", "ci-status", "architecture-review".
|
|
104
|
-
- Reuse a session if the topic is the same. Create new for a different topic.
|
|
105
110
|
- remove_session to remove a session.
|
|
111
|
+
{active_instances}
|
|
106
112
|
|
|
107
113
|
Agents:
|
|
108
114
|
- Available agents: {agent_names}.
|
|
@@ -153,9 +159,12 @@ Branch-namn fuzzy-matchas — t.ex. "branding" matchar "feat/branding-refresh".
|
|
|
153
159
|
send_to_session med beskrivande namn. Återanvänd befintliga sessioner för samma ämne.
|
|
154
160
|
|
|
155
161
|
Sessioner:
|
|
162
|
+
- KONTROLLERA ALLTID listan över aktiva sessioner nedan innan du skapar en ny.
|
|
163
|
+
- Om en session täcker samma ämne, ÅTERANVÄND den genom att använda det exakta namnet.
|
|
164
|
+
- Skapa bara en ny session för ett genuint annorlunda ämne.
|
|
156
165
|
- Använd beskrivande namn: "jira-research", "ci-status", "arkitektur-granskning".
|
|
157
|
-
- Återanvänd en session om ämnet är detsamma. Skapa ny för nytt ämne.
|
|
158
166
|
- remove_session för att ta bort en session.
|
|
167
|
+
{active_instances}
|
|
159
168
|
|
|
160
169
|
Agenter:
|
|
161
170
|
- Tillgängliga agenter: {agent_names}.
|
|
@@ -195,12 +204,25 @@ def get_system_instructions(
|
|
|
195
204
|
context: str = "",
|
|
196
205
|
overrides: dict[str, str] | None = None,
|
|
197
206
|
enabled_agents: list[str] | None = None,
|
|
207
|
+
active_instances: str = "",
|
|
198
208
|
) -> str:
|
|
199
209
|
if overrides and language in overrides:
|
|
200
210
|
base = overrides[language]
|
|
201
211
|
else:
|
|
202
212
|
base = _SYSTEM_INSTRUCTIONS.get(language, _SYSTEM_INSTRUCTIONS["en"])
|
|
203
|
-
|
|
213
|
+
instances_text = active_instances or "(No active sessions or agents.)"
|
|
214
|
+
has_instances_placeholder = "{active_instances}" in base
|
|
215
|
+
try:
|
|
216
|
+
base = base.format(
|
|
217
|
+
agent_names=_agent_names(enabled_agents),
|
|
218
|
+
active_instances=instances_text,
|
|
219
|
+
)
|
|
220
|
+
except KeyError:
|
|
221
|
+
# Override instructions may not have all placeholders
|
|
222
|
+
base = base.format(agent_names=_agent_names(enabled_agents))
|
|
223
|
+
# If the template didn't have {active_instances}, append inline
|
|
224
|
+
if not has_instances_placeholder and active_instances:
|
|
225
|
+
base += f"\n\n{instances_text}"
|
|
204
226
|
if context:
|
|
205
227
|
return f"{base}\n\n{context}"
|
|
206
228
|
return base
|
|
@@ -128,13 +128,14 @@ class RealtimeSession:
|
|
|
128
128
|
self._on_status("connected")
|
|
129
129
|
|
|
130
130
|
async def configure_session(self) -> None:
|
|
131
|
-
from voice_vibecoder.tools.handlers import get_startup_context
|
|
131
|
+
from voice_vibecoder.tools.handlers import get_active_instances_text, get_startup_context
|
|
132
132
|
|
|
133
133
|
s = self._settings
|
|
134
134
|
overrides = self._voice_config.system_instructions if self._voice_config else None
|
|
135
135
|
instructions = get_system_instructions(
|
|
136
136
|
s.language, context=get_startup_context(),
|
|
137
137
|
overrides=overrides, enabled_agents=s.enabled_agents,
|
|
138
|
+
active_instances=get_active_instances_text(),
|
|
138
139
|
)
|
|
139
140
|
|
|
140
141
|
vad: VADSettings | None = None
|
|
@@ -304,12 +305,13 @@ class RealtimeSession:
|
|
|
304
305
|
asyncio.run_coroutine_threadsafe(self._refresh_instructions(), self._loop)
|
|
305
306
|
|
|
306
307
|
async def _refresh_instructions(self) -> None:
|
|
307
|
-
from voice_vibecoder.tools.handlers import get_startup_context
|
|
308
|
+
from voice_vibecoder.tools.handlers import get_active_instances_text, get_startup_context
|
|
308
309
|
|
|
309
310
|
overrides = self._voice_config.system_instructions if self._voice_config else None
|
|
310
311
|
instructions = get_system_instructions(
|
|
311
312
|
self._settings.language, context=get_startup_context(),
|
|
312
313
|
overrides=overrides, enabled_agents=self._settings.enabled_agents,
|
|
314
|
+
active_instances=get_active_instances_text(),
|
|
313
315
|
)
|
|
314
316
|
try:
|
|
315
317
|
await self._provider.update_session(instructions=instructions)
|
|
@@ -198,6 +198,7 @@ def _handle_send_to_session(message: str, session_name: str | None = None, agent
|
|
|
198
198
|
session_name = "session"
|
|
199
199
|
|
|
200
200
|
instance = _registry.get_session_by_name(session_name)
|
|
201
|
+
is_new_session = instance is None
|
|
201
202
|
if not instance:
|
|
202
203
|
instance = _registry.create_session(session_name, agent_type=target_agent)
|
|
203
204
|
# Update display_name if a better one was provided by the LLM
|
|
@@ -239,7 +240,13 @@ def _handle_send_to_session(message: str, session_name: str | None = None, agent
|
|
|
239
240
|
daemon=True,
|
|
240
241
|
)
|
|
241
242
|
thread.start()
|
|
242
|
-
|
|
243
|
+
result = f"Sent to session '{instance.display_name}'."
|
|
244
|
+
if is_new_session:
|
|
245
|
+
all_sessions = registry.get_all_sessions()
|
|
246
|
+
if len(all_sessions) > 1:
|
|
247
|
+
names = [s.display_name for s in all_sessions]
|
|
248
|
+
result += f" (Active sessions: {', '.join(names)})"
|
|
249
|
+
return result
|
|
243
250
|
|
|
244
251
|
thread = threading.Thread(
|
|
245
252
|
target=_run_agent_background,
|
|
@@ -248,7 +255,13 @@ def _handle_send_to_session(message: str, session_name: str | None = None, agent
|
|
|
248
255
|
)
|
|
249
256
|
thread.start()
|
|
250
257
|
|
|
251
|
-
|
|
258
|
+
result = f"Sent to session '{instance.display_name}'."
|
|
259
|
+
if is_new_session:
|
|
260
|
+
all_sessions = registry.get_all_sessions()
|
|
261
|
+
if len(all_sessions) > 1:
|
|
262
|
+
names = [s.display_name for s in all_sessions]
|
|
263
|
+
result += f" (Active sessions: {', '.join(names)})"
|
|
264
|
+
return result
|
|
252
265
|
|
|
253
266
|
|
|
254
267
|
def _run_agent_background(instance: AgentInstance, message: str, registry: "InstanceRegistry") -> None:
|
|
@@ -15,19 +15,12 @@ from voice_vibecoder.tools.dispatch import (
|
|
|
15
15
|
from voice_vibecoder.worktrees import remove_worktree, resolve_worktree_path
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def
|
|
19
|
-
"""
|
|
18
|
+
def get_active_instances_text() -> str:
|
|
19
|
+
"""Return a text summary of active sessions and code instances for inline insertion."""
|
|
20
20
|
from voice_vibecoder.code_providers.registry import get_agent
|
|
21
21
|
|
|
22
22
|
parts = []
|
|
23
23
|
|
|
24
|
-
enabled = _dispatch._enabled_agents
|
|
25
|
-
if len(enabled) > 1:
|
|
26
|
-
labels = [get_agent(a).label for a in enabled]
|
|
27
|
-
parts.append(f"Enabled agents: {', '.join(labels)}")
|
|
28
|
-
parts.append(f"Default agent: {get_agent(enabled[0]).label}")
|
|
29
|
-
parts.append("Use the 'agent' parameter in send_to_agent/send_to_session to pick a specific agent.")
|
|
30
|
-
|
|
31
24
|
if _dispatch._registry:
|
|
32
25
|
code_instances = _dispatch._registry.get_all_code_instances()
|
|
33
26
|
sessions = _dispatch._registry.get_all_sessions()
|
|
@@ -44,6 +37,24 @@ def get_startup_context() -> str:
|
|
|
44
37
|
agent_label = get_agent(inst.agent_type).label
|
|
45
38
|
parts.append(f" - {inst.display_name} ({inst.status.value}) [{agent_label}]")
|
|
46
39
|
|
|
40
|
+
if not parts:
|
|
41
|
+
return ""
|
|
42
|
+
return "\n".join(parts)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_startup_context() -> str:
|
|
46
|
+
"""Build a context string with agent config and worktrees for the system prompt."""
|
|
47
|
+
from voice_vibecoder.code_providers.registry import get_agent
|
|
48
|
+
|
|
49
|
+
parts = []
|
|
50
|
+
|
|
51
|
+
enabled = _dispatch._enabled_agents
|
|
52
|
+
if len(enabled) > 1:
|
|
53
|
+
labels = [get_agent(a).label for a in enabled]
|
|
54
|
+
parts.append(f"Enabled agents: {', '.join(labels)}")
|
|
55
|
+
parts.append(f"Default agent: {get_agent(enabled[0]).label}")
|
|
56
|
+
parts.append("Use the 'agent' parameter in send_to_agent/send_to_session to pick a specific agent.")
|
|
57
|
+
|
|
47
58
|
if _dispatch._repo_root:
|
|
48
59
|
from voice_vibecoder.worktrees import list_worktrees
|
|
49
60
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/code_providers/__init__.py
RENAMED
|
File without changes
|
{voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/code_providers/claude.py
RENAMED
|
File without changes
|
{voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/code_providers/cursor.py
RENAMED
|
File without changes
|
{voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/code_providers/registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/voice_providers/__init__.py
RENAMED
|
File without changes
|
{voice_vibecoder-2.5.2 → voice_vibecoder-2.5.3}/src/voice_vibecoder/voice_providers/openai.py
RENAMED
|
File without changes
|
|
File without changes
|