soothe-client-python 1.0.3__tar.gz → 1.0.4__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 (33) hide show
  1. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/PKG-INFO +2 -2
  2. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/pyproject.toml +1 -1
  3. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/daemon_session.py +20 -0
  4. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/.gitignore +0 -0
  5. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/LICENSE +0 -0
  6. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/README.md +0 -0
  7. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/__init__.py +0 -0
  8. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/__init__.py +0 -0
  9. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/attachments.py +0 -0
  10. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/broadcaster.py +0 -0
  11. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/chunk_filter.py +0 -0
  12. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/classifier.py +0 -0
  13. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/events.py +0 -0
  14. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/managed_client.py +0 -0
  15. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/observability.py +0 -0
  16. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/pool.py +0 -0
  17. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/query_gate.py +0 -0
  18. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/session_store.py +0 -0
  19. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/thinking_step.py +0 -0
  20. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/turn.py +0 -0
  21. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/turn_boundary.py +0 -0
  22. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/appkit/turn_runner.py +0 -0
  23. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/command_client.py +0 -0
  24. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/errors.py +0 -0
  25. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/helpers.py +0 -0
  26. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/intent_hints.py +0 -0
  27. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/protocol_params.py +0 -0
  28. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/py.typed +0 -0
  29. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/schemas.py +0 -0
  30. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/session.py +0 -0
  31. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/stream_terminal.py +0 -0
  32. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/turn_boundary.py +0 -0
  33. {soothe_client_python-1.0.3 → soothe_client_python-1.0.4}/src/soothe_client/websocket.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soothe-client-python
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: WebSocket client + appkit for soothe-daemon (Python)
5
5
  Project-URL: Homepage, https://github.com/mirasoth/soothe-client-python
6
6
  Project-URL: Documentation, https://soothe.readthedocs.io
@@ -21,7 +21,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
21
  Requires-Python: <3.15,>=3.11
22
22
  Requires-Dist: pillow<12.0.0,>=10.0.0
23
23
  Requires-Dist: pydantic<3.0.0,>=2.0.0
24
- Requires-Dist: soothe-sdk<2.0.0,>=1.0.0
24
+ Requires-Dist: soothe-sdk<2.0.0,>=1.0.2
25
25
  Requires-Dist: websockets>=12.0
26
26
  Provides-Extra: dev
27
27
  Requires-Dist: mypy>=1.0.0; extra == 'dev'
@@ -23,7 +23,7 @@ classifiers = [
23
23
  "Topic :: Software Development :: Libraries :: Python Modules",
24
24
  ]
25
25
  dependencies = [
26
- "soothe-sdk>=1.0.0,<2.0.0",
26
+ "soothe-sdk>=1.0.2,<2.0.0",
27
27
  "pydantic>=2.0.0,<3.0.0",
28
28
  "websockets>=12.0",
29
29
  "pillow>=10.0.0,<12.0.0",
@@ -82,9 +82,21 @@ class DaemonSession:
82
82
  self.last_turn_cancellation_seen: bool = False
83
83
  self.last_turn_error_message: str | None = None
84
84
  # Last completed turn's seq floor (drop stale prior-turn frames).
85
+ # Scoped to the current peer seq namespace: reset on reconnect / loop
86
+ # change — daemon seq is per-process and restarts after daemon restart.
85
87
  self._last_turn_end_seq: int = 0
86
88
  self._expected_turn_id: str | None = None
87
89
 
90
+ def _reset_turn_seq_floor(self) -> None:
91
+ """Clear seq/turn filters when the peer seq namespace may have restarted.
92
+
93
+ Keep-TUI reconnect after a daemon restart (or subscribe to a different
94
+ loop) would otherwise drop all low-seq frames — including
95
+ ``status=running`` — leaving ``query_started=False`` and a silent TUI.
96
+ """
97
+ self._last_turn_end_seq = 0
98
+ self._expected_turn_id = None
99
+
88
100
  @property
89
101
  def client(self) -> WebSocketClient:
90
102
  """Subscribed stream WebSocket (loop events)."""
@@ -131,6 +143,7 @@ class DaemonSession:
131
143
  return await self._bootstrap_loop(resume_loop_id=resume_loop_id)
132
144
 
133
145
  async def _bootstrap_loop(self, *, resume_loop_id: str | None = None) -> dict[str, Any]:
146
+ prev_loop_id = self._loop_id
134
147
  status_event = await bootstrap_loop_session(
135
148
  self._client,
136
149
  resume_loop_id=resume_loop_id,
@@ -140,6 +153,9 @@ class DaemonSession:
140
153
  if status_event.get("type") == "error":
141
154
  raise RuntimeError(str(status_event.get("message", "daemon bootstrap failed")))
142
155
  self._loop_id = status_event.get("loop_id")
156
+ # New/changed loop has an independent seq counter on the daemon.
157
+ if prev_loop_id != self._loop_id:
158
+ self._reset_turn_seq_floor()
143
159
  return status_event
144
160
 
145
161
  async def new_loop(self) -> dict[str, Any]:
@@ -179,6 +195,10 @@ class DaemonSession:
179
195
  await self._client.close()
180
196
  await connect_websocket_with_retries(self._client)
181
197
 
198
+ # Peer seq is process-local; daemon restart restarts counters at 1 while
199
+ # this session may still hold a high floor from before the disconnect.
200
+ self._reset_turn_seq_floor()
201
+
182
202
  if resume_loop_id:
183
203
  reattach = getattr(self._client, "reattach_and_probe", None)
184
204
  if callable(reattach):