webbee 0.3.9__tar.gz → 0.3.10__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.
- {webbee-0.3.9 → webbee-0.3.10}/CHANGELOG.md +6 -0
- {webbee-0.3.9 → webbee-0.3.10}/PKG-INFO +1 -1
- {webbee-0.3.9 → webbee-0.3.10}/pyproject.toml +1 -1
- webbee-0.3.10/src/webbee/__init__.py +1 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/repl.py +10 -7
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/session.py +6 -1
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/steer.py +11 -6
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_repl.py +7 -4
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_session.py +21 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_steer.py +51 -7
- webbee-0.3.9/src/webbee/__init__.py +0 -1
- {webbee-0.3.9 → webbee-0.3.10}/.github/workflows/publish.yml +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/.gitignore +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/LICENSE +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/README.md +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/install.sh +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/account.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/banner_art.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/boot.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/checkpoints.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/cli.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/clipboard.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/coding_context.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/commands.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/config.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/consent.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/details.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/events.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/frames.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/intel/__init__.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/intel/chunker.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/intel/embed.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/intel/graph.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/intel/indexer.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/intel/models.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/intel/query.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/intel/service.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/intel/store.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/intel/vectors.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/intel/watch.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/output_pane.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/remote.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/render.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/repo.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/sessions.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/stream.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/thread.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/tokens.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/tools.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/tui.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/src/webbee/update.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/__init__.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_account.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_checkpoints.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_cli.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_clipboard.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_commands.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_config.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_cpc_contract_stable.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_details.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_events.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_freeze_fix.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_intel_chunker.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_intel_embed.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_intel_graph.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_intel_indexer.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_intel_no_numpy.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_intel_query.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_intel_service.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_intel_store.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_intel_vectors.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_intel_watch.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_marathon.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_packaging.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_render.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_repo.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_sessions.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_stream.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_thread.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_tokens.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_tools.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_tui.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_tui_hardening.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_update.py +0 -0
- {webbee-0.3.9 → webbee-0.3.10}/tests/test_version.py +0 -0
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.10
|
|
4
|
+
|
|
5
|
+
- Remote instructions picked up by an idle terminal now carry a dedup id, so
|
|
6
|
+
an at-least-once delivery can never run — or bill — the same instruction
|
|
7
|
+
twice.
|
|
8
|
+
|
|
3
9
|
## 0.3.9
|
|
4
10
|
|
|
5
11
|
- Internal restructure: the session engine was split into focused modules
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.3.10"
|
|
@@ -214,14 +214,16 @@ async def run_repl(cfg, mode: str = "default", *, once: bool = False, sink=None,
|
|
|
214
214
|
await _run_turn(line)
|
|
215
215
|
return "continue"
|
|
216
216
|
|
|
217
|
-
async def _run_turn(line: str, surface: str = "") -> None:
|
|
217
|
+
async def _run_turn(line: str, surface: str = "", steer_iid: str = "") -> None:
|
|
218
218
|
"""ONE agent turn -- the SAME path for a typed line and an idle-steer
|
|
219
219
|
pickup (liveness v2 §B), which threads the queued item's origin
|
|
220
|
-
`surface`
|
|
221
|
-
Only the echo differs at the call sites:
|
|
222
|
-
foreign_turn for a remote one."""
|
|
220
|
+
`surface` (provenance) and dedup `steer_iid` (kernel dedup ring) into
|
|
221
|
+
the turn start-path. Only the echo differs at the call sites:
|
|
222
|
+
user_echo for a typed line, foreign_turn for a remote one."""
|
|
223
223
|
_sink.begin_turn()
|
|
224
224
|
kw = {"surface": surface} if surface else {}
|
|
225
|
+
if steer_iid:
|
|
226
|
+
kw["steer_iid"] = steer_iid
|
|
225
227
|
try:
|
|
226
228
|
text = await agent.run(line, _sink, marathon=not once,
|
|
227
229
|
goal=(line if not once else ""), **kw)
|
|
@@ -236,11 +238,12 @@ async def run_repl(cfg, mode: str = "default", *, once: bool = False, sink=None,
|
|
|
236
238
|
return
|
|
237
239
|
_sink.end_turn(text)
|
|
238
240
|
|
|
239
|
-
async def _steer_submit(text: str, surface: str) -> None:
|
|
241
|
+
async def _steer_submit(text: str, surface: str, steer_iid: str = "") -> None:
|
|
240
242
|
"""webbee.steer hands a drained remote instruction here: render it as
|
|
241
|
-
the remote user's own line, then run it as a normal turn
|
|
243
|
+
the remote user's own line, then run it as a normal turn (carrying the
|
|
244
|
+
item's dedup iid so the kernel can drop an at-least-once twin)."""
|
|
242
245
|
_sink.foreign_turn(surface, "user", text)
|
|
243
|
-
await _run_turn(text, surface=surface)
|
|
246
|
+
await _run_turn(text, surface=surface, steer_iid=steer_iid)
|
|
244
247
|
|
|
245
248
|
def _cancel_background() -> None:
|
|
246
249
|
for _t in (watcher_task, steer_task):
|
|
@@ -45,7 +45,7 @@ class AgentSession:
|
|
|
45
45
|
return {"Authorization": f"Bearer {token}"}
|
|
46
46
|
|
|
47
47
|
async def run(self, task: str, sink, *, marathon: bool = False, goal: str = "",
|
|
48
|
-
surface: str = "") -> str:
|
|
48
|
+
surface: str = "", steer_iid: str = "") -> str:
|
|
49
49
|
import httpx
|
|
50
50
|
|
|
51
51
|
from webbee.tools import LocalToolExecutor
|
|
@@ -72,6 +72,11 @@ class AgentSession:
|
|
|
72
72
|
# [surface] tags). Additive-only -- a typed turn's body is
|
|
73
73
|
# byte-identical to before.
|
|
74
74
|
body["surface"] = surface
|
|
75
|
+
if steer_iid:
|
|
76
|
+
# steer-iid-dedup: a pickup also carries the queued item's dedup id
|
|
77
|
+
# so the kernel's ring can drop an at-least-once twin. Same
|
|
78
|
+
# additive-only contract -- a typed turn has none, key omitted.
|
|
79
|
+
body["steer_iid"] = steer_iid
|
|
75
80
|
if marathon:
|
|
76
81
|
body["marathon"] = True
|
|
77
82
|
body["goal"] = goal
|
|
@@ -58,8 +58,9 @@ async def poll_idle_steer(cfg, token_provider, *, workspace: str, is_busy,
|
|
|
58
58
|
live_session_id=lambda: "",
|
|
59
59
|
interval: float = _POLL_INTERVAL) -> None:
|
|
60
60
|
"""Run forever (until cancelled): every ~`interval`s of idle time, drain
|
|
61
|
-
the pending-steer queue and hand the FIRST item to
|
|
62
|
-
-- the repl's normal turn path. Seams
|
|
61
|
+
the pending-steer queue and hand the FIRST item to
|
|
62
|
+
`submit(text, surface, steer_iid)` -- the repl's normal turn path. Seams
|
|
63
|
+
(all injected by the repl wiring):
|
|
63
64
|
* is_busy() -- sync; True while a turn is running. Checked BEFORE
|
|
64
65
|
the destructive fetch (never drain mid-turn) and
|
|
65
66
|
AGAIN right before submit (a locally-typed line
|
|
@@ -67,9 +68,12 @@ async def poll_idle_steer(cfg, token_provider, *, workspace: str, is_busy,
|
|
|
67
68
|
backlog instead of being lost).
|
|
68
69
|
* live_session_id()-- sync; the agent's gateway-issued session id once a
|
|
69
70
|
turn has run ("" before). Wins over derivation.
|
|
70
|
-
* submit(text, surface) -- async; renders the remote line and
|
|
71
|
-
turn. Runs INSIDE this task, so polling
|
|
72
|
-
naturally paused for the turn's whole duration.
|
|
71
|
+
* submit(text, surface, steer_iid) -- async; renders the remote line and
|
|
72
|
+
runs the turn. Runs INSIDE this task, so polling
|
|
73
|
+
is naturally paused for the turn's whole duration.
|
|
74
|
+
steer_iid = the queued item's dedup id ("" on an
|
|
75
|
+
older gateway), threaded into the turn POST so the
|
|
76
|
+
kernel's dedup ring can drop an at-least-once twin."""
|
|
73
77
|
from webbee.thread import fetch_pending_steer
|
|
74
78
|
derived = ""
|
|
75
79
|
backlog: deque = deque()
|
|
@@ -97,7 +101,8 @@ async def poll_idle_steer(cfg, token_provider, *, workspace: str, is_busy,
|
|
|
97
101
|
if is_busy():
|
|
98
102
|
backlog.appendleft(item) # a local line won the race -- defer, don't drop
|
|
99
103
|
continue
|
|
100
|
-
await submit(text, str(item.get("surface") or "telegram")
|
|
104
|
+
await submit(text, str(item.get("surface") or "telegram"),
|
|
105
|
+
str(item.get("iid") or ""))
|
|
101
106
|
if _cancel_absorbed():
|
|
102
107
|
raise asyncio.CancelledError
|
|
103
108
|
except asyncio.CancelledError:
|
|
@@ -590,10 +590,11 @@ class SurfaceAgent(FakeAgent):
|
|
|
590
590
|
with a typed turn (the plain fallback read_line is sync)."""
|
|
591
591
|
session_id = "marathon-user-1-rab12cd34ef56"
|
|
592
592
|
|
|
593
|
-
async def run(self, task, sink, *, marathon=False, goal="", surface=""
|
|
593
|
+
async def run(self, task, sink, *, marathon=False, goal="", surface="",
|
|
594
|
+
steer_iid=""):
|
|
594
595
|
self.tasks.append(task)
|
|
595
596
|
self.runs.append({"task": task, "marathon": marathon, "goal": goal,
|
|
596
|
-
"surface": surface})
|
|
597
|
+
"surface": surface, "steer_iid": steer_iid})
|
|
597
598
|
await asyncio.sleep(0)
|
|
598
599
|
return f"answer:{task}"
|
|
599
600
|
|
|
@@ -606,7 +607,7 @@ def test_steer_pickup_renders_remote_line_and_runs_tagged_turn(monkeypatch):
|
|
|
606
607
|
marathon=True, live_session_id=lambda: "", **kw):
|
|
607
608
|
captured["marathon"] = marathon
|
|
608
609
|
captured["live_sid"] = live_session_id()
|
|
609
|
-
await submit("push the fix", "telegram")
|
|
610
|
+
await submit("push the fix", "telegram", "iid-42")
|
|
610
611
|
|
|
611
612
|
monkeypatch.setattr(SP, "poll_idle_steer", spy_poller)
|
|
612
613
|
|
|
@@ -617,9 +618,11 @@ def test_steer_pickup_renders_remote_line_and_runs_tagged_turn(monkeypatch):
|
|
|
617
618
|
sink, agent = _run(read_line=_lines("hello", "again", "/exit"), agent=agent)
|
|
618
619
|
# the remote user's line renders tagged with its origin surface...
|
|
619
620
|
assert ("telegram", "user", "push the fix") in getattr(sink, "foreign", [])
|
|
620
|
-
# ...and the SAME turn path ran it, threading surface
|
|
621
|
+
# ...and the SAME turn path ran it, threading surface + the item's dedup
|
|
622
|
+
# iid into the turn kwargs (steer-iid-dedup pickup path)
|
|
621
623
|
steer_runs = [r for r in agent.runs if r["task"] == "push the fix"]
|
|
622
624
|
assert steer_runs and steer_runs[0]["surface"] == "telegram"
|
|
625
|
+
assert steer_runs[0]["steer_iid"] == "iid-42"
|
|
623
626
|
assert steer_runs[0]["marathon"] is True # normal marathon turn
|
|
624
627
|
# a picked-up turn ends like any other -- end_turn fired, dock leaves busy
|
|
625
628
|
assert "answer:push the fix" in sink.turns
|
|
@@ -961,3 +961,24 @@ def test_run_omits_surface_key_for_plain_typed_turns(monkeypatch):
|
|
|
961
961
|
# to before -- no `surface` key at all.
|
|
962
962
|
body = _run_turn_capture_body(monkeypatch)
|
|
963
963
|
assert "surface" not in body
|
|
964
|
+
|
|
965
|
+
|
|
966
|
+
def test_run_threads_steer_iid_into_session_post_body(monkeypatch):
|
|
967
|
+
# steer-iid-dedup pickup path: a picked-up remote instruction carries the
|
|
968
|
+
# queue entry's dedup id so the kernel ring can drop an at-least-once twin.
|
|
969
|
+
body = _run_turn_capture_body(monkeypatch, surface="telegram", steer_iid="iid-42")
|
|
970
|
+
assert body["steer_iid"] == "iid-42"
|
|
971
|
+
assert body["surface"] == "telegram"
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
def test_run_omits_steer_iid_key_for_plain_typed_turns(monkeypatch):
|
|
975
|
+
# A typed turn has no dedup id -- key omitted, body byte-identical to today.
|
|
976
|
+
body = _run_turn_capture_body(monkeypatch)
|
|
977
|
+
assert "steer_iid" not in body
|
|
978
|
+
|
|
979
|
+
|
|
980
|
+
def test_run_omits_steer_iid_key_when_pickup_item_had_none(monkeypatch):
|
|
981
|
+
# Older gateway: /pending-steer items without `iid` -> "" -> key omitted.
|
|
982
|
+
body = _run_turn_capture_body(monkeypatch, surface="telegram", steer_iid="")
|
|
983
|
+
assert "steer_iid" not in body
|
|
984
|
+
assert body["surface"] == "telegram"
|
|
@@ -85,7 +85,7 @@ def test_poll_submits_first_item_with_surface(monkeypatch):
|
|
|
85
85
|
import webbee.thread as TH
|
|
86
86
|
monkeypatch.setattr(TH, "fetch_pending_steer", fake_fetch)
|
|
87
87
|
|
|
88
|
-
async def submit(text, surface):
|
|
88
|
+
async def submit(text, surface, steer_iid=""):
|
|
89
89
|
submitted.append((text, surface))
|
|
90
90
|
|
|
91
91
|
_drive(SP.poll_idle_steer(_Cfg(), _tp, workspace=".", is_busy=lambda: False,
|
|
@@ -97,6 +97,50 @@ def test_poll_submits_first_item_with_surface(monkeypatch):
|
|
|
97
97
|
assert polled[0] == "marathon-user-1-rlive"
|
|
98
98
|
|
|
99
99
|
|
|
100
|
+
def test_poll_passes_item_iid_to_submit(monkeypatch):
|
|
101
|
+
# steer-iid-dedup pickup path: /pending-steer items carry the queue entry's
|
|
102
|
+
# `iid`; the poller must hand it to submit so the turn POST carries
|
|
103
|
+
# steer_iid and the kernel's dedup ring can drop an at-least-once twin.
|
|
104
|
+
submitted = []
|
|
105
|
+
|
|
106
|
+
async def fake_fetch(cfg, tp, session_id):
|
|
107
|
+
return [{"text": "push the fix", "surface": "telegram", "ts": 1,
|
|
108
|
+
"iid": "iid-42"}]
|
|
109
|
+
|
|
110
|
+
import webbee.thread as TH
|
|
111
|
+
monkeypatch.setattr(TH, "fetch_pending_steer", fake_fetch)
|
|
112
|
+
|
|
113
|
+
async def submit(text, surface, steer_iid=""):
|
|
114
|
+
submitted.append((text, surface, steer_iid))
|
|
115
|
+
|
|
116
|
+
_drive(SP.poll_idle_steer(_Cfg(), _tp, workspace=".", is_busy=lambda: False,
|
|
117
|
+
submit=submit, live_session_id=lambda: "marathon-u-r1",
|
|
118
|
+
interval=0.01),
|
|
119
|
+
until=lambda: submitted)
|
|
120
|
+
assert submitted[0] == ("push the fix", "telegram", "iid-42")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def test_poll_item_without_iid_submits_empty_iid(monkeypatch):
|
|
124
|
+
# An older gateway's items carry no `iid` -- submit gets "" (the turn POST
|
|
125
|
+
# then omits steer_iid entirely), never a crash.
|
|
126
|
+
submitted = []
|
|
127
|
+
|
|
128
|
+
async def fake_fetch(cfg, tp, session_id):
|
|
129
|
+
return [{"text": "resume", "surface": "telegram", "ts": 2}]
|
|
130
|
+
|
|
131
|
+
import webbee.thread as TH
|
|
132
|
+
monkeypatch.setattr(TH, "fetch_pending_steer", fake_fetch)
|
|
133
|
+
|
|
134
|
+
async def submit(text, surface, steer_iid=""):
|
|
135
|
+
submitted.append((text, surface, steer_iid))
|
|
136
|
+
|
|
137
|
+
_drive(SP.poll_idle_steer(_Cfg(), _tp, workspace=".", is_busy=lambda: False,
|
|
138
|
+
submit=submit, live_session_id=lambda: "marathon-u-r1",
|
|
139
|
+
interval=0.01),
|
|
140
|
+
until=lambda: submitted)
|
|
141
|
+
assert submitted[0] == ("resume", "telegram", "")
|
|
142
|
+
|
|
143
|
+
|
|
100
144
|
def test_poll_no_items_never_submits(monkeypatch):
|
|
101
145
|
polled = []
|
|
102
146
|
submitted = []
|
|
@@ -108,7 +152,7 @@ def test_poll_no_items_never_submits(monkeypatch):
|
|
|
108
152
|
import webbee.thread as TH
|
|
109
153
|
monkeypatch.setattr(TH, "fetch_pending_steer", fake_fetch)
|
|
110
154
|
|
|
111
|
-
async def submit(text, surface):
|
|
155
|
+
async def submit(text, surface, steer_iid=""):
|
|
112
156
|
submitted.append((text, surface))
|
|
113
157
|
|
|
114
158
|
_drive(SP.poll_idle_steer(_Cfg(), _tp, workspace=".", is_busy=lambda: False,
|
|
@@ -132,7 +176,7 @@ def test_poll_silent_on_network_error_and_recovers(monkeypatch):
|
|
|
132
176
|
import webbee.thread as TH
|
|
133
177
|
monkeypatch.setattr(TH, "fetch_pending_steer", flaky_fetch)
|
|
134
178
|
|
|
135
|
-
async def submit(text, surface):
|
|
179
|
+
async def submit(text, surface, steer_iid=""):
|
|
136
180
|
submitted.append((text, surface))
|
|
137
181
|
|
|
138
182
|
# No exception escapes the poller; the tick after the blip succeeds.
|
|
@@ -156,7 +200,7 @@ def test_poll_never_fetches_while_busy(monkeypatch):
|
|
|
156
200
|
import webbee.thread as TH
|
|
157
201
|
monkeypatch.setattr(TH, "fetch_pending_steer", fake_fetch)
|
|
158
202
|
|
|
159
|
-
async def submit(text, surface):
|
|
203
|
+
async def submit(text, surface, steer_iid=""):
|
|
160
204
|
submitted.append((text, surface))
|
|
161
205
|
|
|
162
206
|
ticks = {"n": 0}
|
|
@@ -192,7 +236,7 @@ def test_multi_item_drain_runs_in_order_one_per_tick_nothing_lost(monkeypatch):
|
|
|
192
236
|
import webbee.thread as TH
|
|
193
237
|
monkeypatch.setattr(TH, "fetch_pending_steer", fake_fetch)
|
|
194
238
|
|
|
195
|
-
async def submit(text, surface):
|
|
239
|
+
async def submit(text, surface, steer_iid=""):
|
|
196
240
|
submitted.append((text, surface))
|
|
197
241
|
|
|
198
242
|
# The gateway drain returns each item exactly ONCE -- items 2..n of a batch
|
|
@@ -221,7 +265,7 @@ def test_item_deferred_not_lost_when_turn_starts_mid_tick(monkeypatch):
|
|
|
221
265
|
def is_busy():
|
|
222
266
|
return busy_answers.pop(0) if busy_answers else False
|
|
223
267
|
|
|
224
|
-
async def submit(text, surface):
|
|
268
|
+
async def submit(text, surface, steer_iid=""):
|
|
225
269
|
submitted.append((text, surface))
|
|
226
270
|
|
|
227
271
|
_drive(SP.poll_idle_steer(_Cfg(), _tp, workspace=".", is_busy=is_busy,
|
|
@@ -245,7 +289,7 @@ def test_poller_exits_when_submitted_turn_absorbs_the_cancel(monkeypatch):
|
|
|
245
289
|
import webbee.thread as TH
|
|
246
290
|
monkeypatch.setattr(TH, "fetch_pending_steer", fake_fetch)
|
|
247
291
|
|
|
248
|
-
async def swallowing_submit(text, surface):
|
|
292
|
+
async def swallowing_submit(text, surface, steer_iid=""):
|
|
249
293
|
in_submit.set()
|
|
250
294
|
try:
|
|
251
295
|
await asyncio.sleep(3600)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.3.9"
|
|
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
|
|
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
|