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.
Files changed (42) hide show
  1. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/PKG-INFO +1 -1
  2. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/pyproject.toml +1 -1
  3. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/voice.py +6 -1
  4. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_voice.py +36 -5
  5. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/.gitignore +0 -0
  6. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/README.md +0 -0
  7. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/examples/__init__.py +0 -0
  8. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/examples/runs_app.py +0 -0
  9. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/__init__.py +0 -0
  10. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/checkpoints.py +0 -0
  11. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/deepagents.py +0 -0
  12. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/fenced_postgres.py +0 -0
  13. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/linear_thread.py +0 -0
  14. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/src/harness_sdk/run_manager.py +0 -0
  15. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/run_helpers.py +0 -0
  16. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_admit_steer.py +0 -0
  17. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_applied_visibility.py +0 -0
  18. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_batches.py +0 -0
  19. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_branch_anchor.py +0 -0
  20. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_checkpoints.py +0 -0
  21. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_deepagents_messages.py +0 -0
  22. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_dispatching.py +0 -0
  23. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_durability.py +0 -0
  24. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_edit_dispatched.py +0 -0
  25. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_edit_reload.py +0 -0
  26. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_enqueue.py +0 -0
  27. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_fenced_postgres.py +0 -0
  28. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_input_required.py +0 -0
  29. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_linear_thread.py +0 -0
  30. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_meta.py +0 -0
  31. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_mint_concurrency.py +0 -0
  32. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_outcomes.py +0 -0
  33. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_placement.py +0 -0
  34. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_prepare_hooks.py +0 -0
  35. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_restore.py +0 -0
  36. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_rewind_during_run.py +0 -0
  37. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_run_crash_sweep.py +0 -0
  38. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_settle.py +0 -0
  39. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_steer.py +0 -0
  40. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_stop_continue.py +0 -0
  41. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/test_stopping_window.py +0 -0
  42. {harness_sdk_python-0.29.1 → harness_sdk_python-0.29.2}/tests/voice_helpers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: harness-sdk-python
3
- Version: 0.29.1
3
+ Version: 0.29.2
4
4
  Summary: RunManager: the harness-sdk runs subsystem for Python Statewire hosts
5
5
  Project-URL: Repository, https://github.com/assistant-ui/harness-sdk
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "harness-sdk-python"
3
- version = "0.29.1"
3
+ version = "0.29.2"
4
4
  description = "RunManager: the harness-sdk runs subsystem for Python Statewire hosts"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -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 and drops in-progress 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 test_end_drops_in_progress_turns():
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 == [[{"id": "t1", "role": "user", "text": "question"}]]
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
- == [{"id": "t1", "type": "human", "content": "question"}]
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 test_end_with_no_done_turns_commits_nothing():
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 == [[{"id": "t1", "role": "assistant", "text": "goodbye"}]]
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