voice-vibecoder 2.9.5__tar.gz → 2.9.6__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.9.5 → voice_vibecoder-2.9.6}/CHANGELOG.md +8 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/PKG-INFO +1 -1
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/pyproject.toml +1 -1
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/__init__.py +1 -1
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/code_providers/openclaw.py +33 -30
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/.github/workflows/ci.yml +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/.github/workflows/release.yml +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/.gitignore +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/LICENSE +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/README.md +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/app.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/index.html +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/app_config.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/audio.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/cli_serve.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/code_providers/__init__.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/code_providers/claude.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/code_providers/cursor.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/code_providers/registry.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/config.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/instances.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/server.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/session.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/tools/__init__.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/tools/agent_task.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/tools/definitions.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/tools/dispatch.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/tools/file_tree.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/tools/handlers.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/ui/__init__.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/ui/callbacks.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/ui/diff_view.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/ui/help_modal.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/ui/panels.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/ui/screen.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/ui/setup.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/ui/state.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/ui/styles.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/ui/update_modal.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/ui/wizard.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/voice_providers/__init__.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/voice_providers/openai.py +0 -0
- {voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/worktrees.py +0 -0
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- version list -->
|
|
4
4
|
|
|
5
|
+
## v2.9.6 (2026-02-21)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Handle agent/chat events correctly for streaming
|
|
10
|
+
([`2abd488`](https://github.com/snokam/voice-vibecoder/commit/2abd488a7e408a4227375bb332f9e2d76ae8df85))
|
|
11
|
+
|
|
12
|
+
|
|
5
13
|
## v2.9.5 (2026-02-21)
|
|
6
14
|
|
|
7
15
|
### Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voice-vibecoder
|
|
3
|
-
Version: 2.9.
|
|
3
|
+
Version: 2.9.6
|
|
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.9.
|
|
7
|
+
version = "2.9.6"
|
|
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"
|
{voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/code_providers/openclaw.py
RENAMED
|
@@ -132,7 +132,6 @@ class OpenClawRunner:
|
|
|
132
132
|
timeout=5.0
|
|
133
133
|
)
|
|
134
134
|
|
|
135
|
-
# Wait for challenge
|
|
136
135
|
challenge_msg = await asyncio.wait_for(ws.recv(), timeout=5.0)
|
|
137
136
|
challenge = json.loads(challenge_msg)
|
|
138
137
|
|
|
@@ -144,7 +143,6 @@ class OpenClawRunner:
|
|
|
144
143
|
nonce = challenge["payload"]["nonce"]
|
|
145
144
|
signed_at_ms = int(time.time() * 1000)
|
|
146
145
|
|
|
147
|
-
# Build auth payload and sign
|
|
148
146
|
client_id = "cli"
|
|
149
147
|
client_mode = "cli"
|
|
150
148
|
role = "operator"
|
|
@@ -162,14 +160,12 @@ class OpenClawRunner:
|
|
|
162
160
|
)
|
|
163
161
|
signature = _sign_payload(self._private_key, payload)
|
|
164
162
|
|
|
165
|
-
# Get public key in base64
|
|
166
163
|
public_key_bytes = self._private_key.public_key().public_bytes(
|
|
167
164
|
encoding=serialization.Encoding.Raw,
|
|
168
165
|
format=serialization.PublicFormat.Raw
|
|
169
166
|
)
|
|
170
167
|
pub_b64 = base64.urlsafe_b64encode(public_key_bytes).decode().rstrip("=")
|
|
171
168
|
|
|
172
|
-
# Send connect request
|
|
173
169
|
connect_req = {
|
|
174
170
|
"type": "req",
|
|
175
171
|
"id": str(uuid.uuid4()),
|
|
@@ -203,7 +199,6 @@ class OpenClawRunner:
|
|
|
203
199
|
|
|
204
200
|
await ws.send(json.dumps(connect_req))
|
|
205
201
|
|
|
206
|
-
# Wait for response
|
|
207
202
|
response_msg = await asyncio.wait_for(ws.recv(), timeout=5.0)
|
|
208
203
|
response = json.loads(response_msg)
|
|
209
204
|
|
|
@@ -233,7 +228,6 @@ class OpenClawRunner:
|
|
|
233
228
|
req_id = str(uuid.uuid4())
|
|
234
229
|
idempotency_key = f"voice-{uuid.uuid4().hex[:16]}"
|
|
235
230
|
|
|
236
|
-
# Use chat.send method
|
|
237
231
|
chat_req = {
|
|
238
232
|
"type": "req",
|
|
239
233
|
"id": req_id,
|
|
@@ -248,41 +242,50 @@ class OpenClawRunner:
|
|
|
248
242
|
await ws.send(json.dumps(chat_req))
|
|
249
243
|
|
|
250
244
|
result_text = ""
|
|
245
|
+
last_text = ""
|
|
251
246
|
|
|
252
247
|
while True:
|
|
253
248
|
msg = await asyncio.wait_for(ws.recv(), timeout=300.0)
|
|
254
249
|
data = json.loads(msg)
|
|
255
250
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
251
|
+
event = data.get("event")
|
|
252
|
+
payload = data.get("payload", {})
|
|
253
|
+
|
|
254
|
+
if event == "agent":
|
|
255
|
+
stream = payload.get("stream")
|
|
256
|
+
agent_data = payload.get("data", {})
|
|
257
|
+
|
|
258
|
+
if stream == "assistant" and "text" in agent_data:
|
|
259
|
+
text = agent_data["text"]
|
|
260
|
+
# Send delta (new text since last)
|
|
261
|
+
if text and len(text) > len(last_text):
|
|
262
|
+
delta = text[len(last_text):]
|
|
263
|
+
if on_output and delta:
|
|
264
|
+
on_output(AgentOutput(category="text", content=delta))
|
|
265
|
+
last_text = text
|
|
266
|
+
result_text = text
|
|
260
267
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if text and on_output:
|
|
264
|
-
on_output(AgentOutput(category="text", content=text))
|
|
265
|
-
result_text += text
|
|
266
|
-
elif event == "chat.tool":
|
|
267
|
-
tool = payload.get("name", payload.get("tool", ""))
|
|
268
|
+
elif stream == "tool_use" and "name" in agent_data:
|
|
269
|
+
tool = agent_data["name"]
|
|
268
270
|
if on_output:
|
|
269
|
-
on_output(AgentOutput(category="tool_call", content=f"[{tool}]"))
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
271
|
+
on_output(AgentOutput(category="tool_call", content=f"\n[{tool}] "))
|
|
272
|
+
|
|
273
|
+
elif event == "chat":
|
|
274
|
+
state = payload.get("state")
|
|
275
|
+
if state == "final":
|
|
276
|
+
# Get final message
|
|
277
|
+
msg_content = payload.get("message", {})
|
|
278
|
+
if isinstance(msg_content, dict) and "content" in msg_content:
|
|
279
|
+
result_text = msg_content["content"]
|
|
275
280
|
break
|
|
276
|
-
elif
|
|
277
|
-
error = payload.get("
|
|
281
|
+
elif state == "error":
|
|
282
|
+
error = payload.get("error", "Unknown error")
|
|
278
283
|
raise RuntimeError(f"Chat error: {error}")
|
|
279
284
|
|
|
280
|
-
# Handle response (initial ack)
|
|
281
285
|
elif data.get("type") == "res" and data.get("id") == req_id:
|
|
282
286
|
if not data.get("ok"):
|
|
283
287
|
error = data.get("error", {}).get("message", "Unknown error")
|
|
284
288
|
raise RuntimeError(f"Chat send error: {error}")
|
|
285
|
-
# Continue listening for events
|
|
286
289
|
|
|
287
290
|
return AgentResult(text=result_text.strip(), session_id=session_id)
|
|
288
291
|
|
|
@@ -345,13 +348,13 @@ class OpenClawRunner:
|
|
|
345
348
|
effective_session = session_id or self._session_id
|
|
346
349
|
|
|
347
350
|
if on_output:
|
|
348
|
-
on_output(AgentOutput(category="text", content="🦞 Connecting to OpenClaw
|
|
351
|
+
on_output(AgentOutput(category="text", content="🦞 Connecting to OpenClaw...\n"))
|
|
349
352
|
|
|
350
353
|
ws = await self._connect_websocket()
|
|
351
354
|
if ws:
|
|
352
355
|
try:
|
|
353
356
|
if on_output:
|
|
354
|
-
on_output(AgentOutput(category="text", content="🦞 Connected! Streaming
|
|
357
|
+
on_output(AgentOutput(category="text", content="🦞 Connected! Streaming...\n"))
|
|
355
358
|
result = await self._run_via_websocket(ws, message, cwd, effective_session, on_output)
|
|
356
359
|
if result:
|
|
357
360
|
return result
|
|
@@ -359,7 +362,7 @@ class OpenClawRunner:
|
|
|
359
362
|
await ws.close()
|
|
360
363
|
|
|
361
364
|
if on_output:
|
|
362
|
-
on_output(AgentOutput(category="text", content="WebSocket unavailable, using CLI
|
|
365
|
+
on_output(AgentOutput(category="text", content="WebSocket unavailable, using CLI...\n"))
|
|
363
366
|
|
|
364
367
|
return await self._run_via_cli(message, cwd, effective_session, on_output)
|
|
365
368
|
|
|
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.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/code_providers/__init__.py
RENAMED
|
File without changes
|
{voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/code_providers/claude.py
RENAMED
|
File without changes
|
{voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/code_providers/cursor.py
RENAMED
|
File without changes
|
{voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/voice_providers/__init__.py
RENAMED
|
File without changes
|
{voice_vibecoder-2.9.5 → voice_vibecoder-2.9.6}/src/voice_vibecoder/voice_providers/openai.py
RENAMED
|
File without changes
|
|
File without changes
|