harness-sdk-python 0.29.1__tar.gz → 0.29.2__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.
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/PKG-INFO +1 -1
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/pyproject.toml +1 -1
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/voice.py +6 -1
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_voice.py +36 -5
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/.gitignore +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/README.md +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/examples/__init__.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/examples/runs_app.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/__init__.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/checkpoints.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/deepagents.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/fenced_postgres.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/linear_thread.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/run_manager.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/run_helpers.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_admit_steer.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_applied_visibility.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_batches.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_branch_anchor.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_checkpoints.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_deepagents_messages.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_dispatching.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_durability.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_edit_dispatched.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_edit_reload.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_enqueue.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_fenced_postgres.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_input_required.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_linear_thread.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_meta.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_mint_concurrency.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_outcomes.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_placement.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_prepare_hooks.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_restore.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_rewind_during_run.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_run_crash_sweep.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_settle.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_steer.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_stop_continue.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_stopping_window.py +0 -0
- {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/voice_helpers.py +0 -0
|
@@ -18,7 +18,8 @@ events render live in ``state["messages"]`` through
|
|
|
18
18
|
turn commits through ``Host.commit_voice_turns`` (serialized, in
|
|
19
19
|
done-order) and the durable entry replaces the ephemeral one under the
|
|
20
20
|
same id, a failed commit keeps its turns for the next flush; session end
|
|
21
|
-
flushes the remaining done turns
|
|
21
|
+
flushes the remaining done turns, then commits in-progress turns with
|
|
22
|
+
their partial text; in-progress turns with no text yet are dropped.
|
|
22
23
|
|
|
23
24
|
Rejections: ``voice-active`` (a session is already live), ``no-voice``
|
|
24
25
|
(no voice manager declared, or ``voice/end`` with no session),
|
|
@@ -189,6 +190,10 @@ class VoiceManager(Tray):
|
|
|
189
190
|
await provider.close()
|
|
190
191
|
except Exception:
|
|
191
192
|
logger.exception("voice provider close failed for session %r", self.id)
|
|
193
|
+
self._turns.sort(key=lambda turn: not turn["done"])
|
|
194
|
+
for turn in self._turns:
|
|
195
|
+
if turn["text"]:
|
|
196
|
+
turn["done"] = True
|
|
192
197
|
await self._flush()
|
|
193
198
|
turns, self._turns = self._turns, []
|
|
194
199
|
for turn in turns:
|
|
@@ -186,7 +186,7 @@ async def test_commit_failure_retries_in_order_with_the_next_turn():
|
|
|
186
186
|
]
|
|
187
187
|
|
|
188
188
|
|
|
189
|
-
async def
|
|
189
|
+
async def test_end_commits_in_progress_turns_with_partial_text():
|
|
190
190
|
bench = Bench()
|
|
191
191
|
async with voice_host(bench) as (drv, _app):
|
|
192
192
|
await drv.command("voice/start", {"offer": OFFER})
|
|
@@ -199,15 +199,41 @@ async def test_end_drops_in_progress_turns():
|
|
|
199
199
|
rsp = await drv.command("voice/end")
|
|
200
200
|
assert rsp["type"] == "accepted", rsp
|
|
201
201
|
assert bench.provider.closed
|
|
202
|
-
assert bench.commits == [
|
|
202
|
+
assert bench.commits == [
|
|
203
|
+
[{"id": "t1", "role": "user", "text": "question"}],
|
|
204
|
+
[{"id": "t2", "role": "assistant", "text": "half an ans"}],
|
|
205
|
+
]
|
|
206
|
+
# the durable entries replaced the ephemeral ones under the same ids
|
|
203
207
|
await drv.wait(
|
|
204
208
|
lambda s: voice_of(s) is None
|
|
205
209
|
and messages_of(s)
|
|
206
|
-
== [
|
|
210
|
+
== [
|
|
211
|
+
{"id": "t1", "type": "human", "content": "question"},
|
|
212
|
+
{"id": "t2", "type": "ai", "content": "half an ans"},
|
|
213
|
+
]
|
|
207
214
|
)
|
|
208
215
|
|
|
209
216
|
|
|
210
|
-
async def
|
|
217
|
+
async def test_end_commits_partial_turns_after_kept_done_turns():
|
|
218
|
+
bench = Bench(commit_failures=[RuntimeError("checkpointer down")])
|
|
219
|
+
async with voice_host(bench) as (drv, _app):
|
|
220
|
+
await drv.command("voice/start", {"offer": OFFER})
|
|
221
|
+
events = bench.events()
|
|
222
|
+
events.turn_started("t1", "user")
|
|
223
|
+
events.turn_done("t1", "question")
|
|
224
|
+
await until(lambda: bench.commit_failures == [])
|
|
225
|
+
events.turn_started("t2", "assistant")
|
|
226
|
+
events.turn_delta("t2", "half an ans")
|
|
227
|
+
await drv.command("voice/end")
|
|
228
|
+
assert bench.commits == [
|
|
229
|
+
[
|
|
230
|
+
{"id": "t1", "role": "user", "text": "question"},
|
|
231
|
+
{"id": "t2", "role": "assistant", "text": "half an ans"},
|
|
232
|
+
]
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
async def test_end_drops_started_turns_with_no_text():
|
|
211
237
|
bench = Bench()
|
|
212
238
|
async with voice_host(bench) as (drv, _app):
|
|
213
239
|
await drv.command("voice/start", {"offer": OFFER})
|
|
@@ -234,9 +260,14 @@ async def test_provider_closed_event_ends_and_commits():
|
|
|
234
260
|
events = bench.events()
|
|
235
261
|
events.turn_started("t1", "assistant")
|
|
236
262
|
events.turn_done("t1", "goodbye")
|
|
263
|
+
events.turn_started("t2", "user")
|
|
264
|
+
events.turn_delta("t2", "wai")
|
|
237
265
|
events.closed("server")
|
|
238
266
|
await drv.wait(lambda s: voice_of(s) is None)
|
|
239
|
-
assert bench.commits == [
|
|
267
|
+
assert bench.commits == [
|
|
268
|
+
[{"id": "t1", "role": "assistant", "text": "goodbye"}],
|
|
269
|
+
[{"id": "t2", "role": "user", "text": "wai"}],
|
|
270
|
+
]
|
|
240
271
|
assert_rejected(await drv.command("voice/end"), "no-voice")
|
|
241
272
|
|
|
242
273
|
|
|
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
|
|
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
|