@asm-agent/coding-agent 0.8.7 → 0.9.0
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.
- package/CHANGELOG.md +19 -0
- package/README.md +2 -7
- package/dist/asm-agent-runtime/src/__pycache__/asm_cm_driver.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/__pycache__/phase76_address_head.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__init__.py +1 -1
- package/dist/asm-agent-runtime/src/rlm/__pycache__/__init__.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/_winjob.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/bash.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/bash.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/harness.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/mcp.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/mcp.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/mcp_base.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/mcp_base.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/repl.cpython-312.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/repl.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/__pycache__/skill.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/src/rlm/bash.py +94 -31
- package/dist/asm-agent-runtime/src/rlm/repl.md +3 -3
- package/dist/asm-agent-runtime/src/rlm/repl.py +46 -45
- package/dist/asm-agent-runtime/test/__pycache__/test_agent_message_skill.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_bash.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_harness.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_mcp.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_mcp_base.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_repl.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_subagent_registry.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/__pycache__/test_winjob.cpython-313.pyc +0 -0
- package/dist/asm-agent-runtime/test/test_bash.py +74 -19
- package/dist/asm-agent-runtime/test/test_repl.py +67 -3
- package/dist/asm-agent-runtime/uv.lock +446 -155
- package/dist/bundle/{anthropic-XSMQHGYB.js → anthropic-ZOZNPFXS.js} +2 -2
- package/dist/bundle/{azure-openai-responses-XLQAIKKH.js → azure-openai-responses-TDHCU647.js} +2 -2
- package/dist/bundle/{bundled-modules-5OCN73BM.js → bundled-modules-Q2YODC4B.js} +3 -3
- package/dist/bundle/{chunk-IAQLPSMN.js → chunk-AMKLNEAK.js} +47 -47
- package/dist/bundle/{chunk-2LPSALBF.js → chunk-FPY7FFJS.js} +978 -1821
- package/dist/bundle/{chunk-E3YE2Q7A.js → chunk-G6SC4YYW.js} +4973 -1926
- package/dist/bundle/{chunk-YPNK4MRU.js → chunk-QLHAP3FT.js} +1 -1
- package/dist/bundle/{cli-main-QYX5R3LF.js → cli-main-277AG2BR.js} +3 -3
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/{google-ZXJEPWJA.js → google-Q3AJWUOY.js} +1 -1
- package/dist/bundle/{google-vertex-WAF3RIJ6.js → google-vertex-2CSNOUBS.js} +1 -1
- package/dist/bundle/{main-EOUAQCJH.js → main-TNXWJXIU.js} +3 -3
- package/dist/bundle/{mistral-GDZXSXRS.js → mistral-XRYJGLLG.js} +1 -1
- package/dist/bundle/{openai-codex-responses-7XMPW4LG.js → openai-codex-responses-C6BRO2BN.js} +2 -2
- package/dist/bundle/{openai-completions-LNSVGDMF.js → openai-completions-DNXCK2JW.js} +4 -4
- package/dist/bundle/{openai-responses-MFZOBMIT.js → openai-responses-BEMWVIXE.js} +2 -2
- package/dist/config.d.ts +0 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-config.d.ts +1 -2
- package/dist/core/agent-session-config.d.ts.map +1 -1
- package/dist/core/agent-session-config.js +0 -3
- package/dist/core/agent-session-config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +0 -8
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +0 -2
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +0 -22
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +8 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +100 -22
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/kernel/bootstrap.d.ts.map +1 -1
- package/dist/core/kernel/bootstrap.js +1 -1
- package/dist/core/kernel/bootstrap.js.map +1 -1
- package/dist/core/kernel/repl-manager.d.ts +32 -8
- package/dist/core/kernel/repl-manager.d.ts.map +1 -1
- package/dist/core/kernel/repl-manager.js +401 -102
- package/dist/core/kernel/repl-manager.js.map +1 -1
- package/dist/core/kernel/shared.d.ts +11 -7
- package/dist/core/kernel/shared.d.ts.map +1 -1
- package/dist/core/kernel/shared.js +2 -5
- package/dist/core/kernel/shared.js.map +1 -1
- package/dist/core/mcp/mcp-manager.d.ts +4 -2
- package/dist/core/mcp/mcp-manager.d.ts.map +1 -1
- package/dist/core/mcp/mcp-manager.js +9 -7
- package/dist/core/mcp/mcp-manager.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +1 -1
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/ollama-models.d.ts +3 -1
- package/dist/core/ollama-models.d.ts.map +1 -1
- package/dist/core/ollama-models.js +31 -10
- package/dist/core/ollama-models.js.map +1 -1
- package/dist/core/prime-inference-auth.d.ts +0 -9
- package/dist/core/prime-inference-auth.d.ts.map +1 -1
- package/dist/core/prime-inference-auth.js +0 -50
- package/dist/core/prime-inference-auth.js.map +1 -1
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +0 -1
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/session-manager.d.ts +0 -4
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +0 -22
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +4 -16
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +13 -43
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +0 -5
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tools/acp-mcp.d.ts +6 -0
- package/dist/core/tools/acp-mcp.d.ts.map +1 -0
- package/dist/core/tools/acp-mcp.js +86 -0
- package/dist/core/tools/acp-mcp.js.map +1 -0
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ipython.d.ts.map +1 -1
- package/dist/core/tools/ipython.js +9 -4
- package/dist/core/tools/ipython.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -11
- package/dist/main.js.map +1 -1
- package/dist/modes/acp/acp-mode.d.ts.map +1 -1
- package/dist/modes/acp/acp-mode.js +1 -1
- package/dist/modes/acp/acp-mode.js.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.d.ts +0 -2
- package/dist/modes/agent-connection/daemon-agent-connection.d.ts.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.js +0 -2
- package/dist/modes/agent-connection/daemon-agent-connection.js.map +1 -1
- package/dist/modes/agents-view/agents-view-mode.d.ts.map +1 -1
- package/dist/modes/agents-view/agents-view-mode.js +0 -19
- package/dist/modes/agents-view/agents-view-mode.js.map +1 -1
- package/dist/modes/daemon/daemon-mode.d.ts +1 -10
- package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-mode.js +134 -274
- package/dist/modes/daemon/daemon-mode.js.map +1 -1
- package/dist/modes/daemon/daemon-protocol.d.ts +11 -5
- package/dist/modes/daemon/daemon-protocol.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-protocol.js +6 -8
- package/dist/modes/daemon/daemon-protocol.js.map +1 -1
- package/dist/modes/daemon/daemon-supervisor.d.ts +0 -3
- package/dist/modes/daemon/daemon-supervisor.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-supervisor.js +18 -52
- package/dist/modes/daemon/daemon-supervisor.js.map +1 -1
- package/dist/modes/daemon/daemon-worker-protocol.d.ts +1 -6
- package/dist/modes/daemon/daemon-worker-protocol.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-worker-protocol.js +0 -2
- package/dist/modes/daemon/daemon-worker-protocol.js.map +1 -1
- package/dist/modes/interactive/auth-flows.d.ts +0 -2
- package/dist/modes/interactive/auth-flows.d.ts.map +1 -1
- package/dist/modes/interactive/auth-flows.js +1 -101
- package/dist/modes/interactive/auth-flows.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +6 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +13 -3
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +2 -2
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/mermaid.d.ts +12 -0
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
- package/dist/modes/interactive/components/mermaid.js +63 -0
- package/dist/modes/interactive/components/mermaid.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/feature-hints.d.ts.map +1 -1
- package/dist/modes/interactive/feature-hints.js +0 -4
- package/dist/modes/interactive/feature-hints.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -7
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +23 -279
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +1 -1
- package/dist/utils/version-check.js.map +1 -1
- package/docs/settings.md +1 -31
- package/docs/usage.md +1 -4
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +6 -5
- package/dist/core/agent-traces.d.ts +0 -130
- package/dist/core/agent-traces.d.ts.map +0 -1
- package/dist/core/agent-traces.js +0 -746
- package/dist/core/agent-traces.js.map +0 -1
- package/dist/core/telemetry.d.ts +0 -92
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/core/telemetry.js +0 -633
- package/dist/core/telemetry.js.map +0 -1
|
@@ -176,20 +176,20 @@ class BashTest(unittest.IsolatedAsyncioTestCase):
|
|
|
176
176
|
self.assertFalse(records[-1]["active"])
|
|
177
177
|
await _poll_group_dead(handle.pid)
|
|
178
178
|
|
|
179
|
-
async def
|
|
179
|
+
async def test_delivered_status_wins_when_shell_dies_during_completion(self):
|
|
180
180
|
entered = threading.Event()
|
|
181
181
|
release = threading.Event()
|
|
182
|
-
original = bash_module.BashHandle.
|
|
182
|
+
original = bash_module.BashHandle._wait_for_completion
|
|
183
183
|
|
|
184
|
-
def
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
release.wait(10)
|
|
190
|
-
original(handle_self)
|
|
184
|
+
def held_completion(handle_self):
|
|
185
|
+
output = original(handle_self)
|
|
186
|
+
entered.set()
|
|
187
|
+
release.wait(10)
|
|
188
|
+
return output
|
|
191
189
|
|
|
192
|
-
with mock.patch.object(
|
|
190
|
+
with mock.patch.object(
|
|
191
|
+
bash_module.BashHandle, "_wait_for_completion", held_completion
|
|
192
|
+
):
|
|
193
193
|
# Background job keeps the shell alive in `wait` after status 0 is delivered.
|
|
194
194
|
handle = bash("sleep 30 & true")
|
|
195
195
|
try:
|
|
@@ -337,7 +337,7 @@ class BashTest(unittest.IsolatedAsyncioTestCase):
|
|
|
337
337
|
self.skipTest("POSIX-only gate")
|
|
338
338
|
with tempfile.TemporaryDirectory() as tmp:
|
|
339
339
|
marker = os.path.join(tmp, "ran")
|
|
340
|
-
script = bash_module._status_script(f"touch {marker}")
|
|
340
|
+
script = bash_module._status_script(f"touch {marker}", "a" * 32, "b" * 32)
|
|
341
341
|
parent, child = socket.socketpair()
|
|
342
342
|
proc = subprocess.Popen(
|
|
343
343
|
[bash_module._shell(), "-c", script],
|
|
@@ -539,26 +539,29 @@ class BashTest(unittest.IsolatedAsyncioTestCase):
|
|
|
539
539
|
bash_module._shell()
|
|
540
540
|
which.assert_not_called()
|
|
541
541
|
|
|
542
|
-
async def
|
|
543
|
-
#
|
|
544
|
-
# in the buffer; the drain fence must wait for the commit.
|
|
542
|
+
async def test_pump_delayed_past_old_quiescence_bound_captures_all_output(self):
|
|
543
|
+
# The ordered sentinel must wait through a pump delay beyond the old 500 ms bound.
|
|
545
544
|
original_write = bash_module._BoundedBuffer.write
|
|
546
545
|
delayed_once = threading.Event()
|
|
547
546
|
|
|
548
547
|
def delayed_write(buffer_self, chunk):
|
|
549
548
|
if not delayed_once.is_set():
|
|
550
549
|
delayed_once.set()
|
|
551
|
-
time.sleep(0.
|
|
550
|
+
time.sleep(0.7)
|
|
552
551
|
original_write(buffer_self, chunk)
|
|
553
552
|
|
|
554
553
|
with mock.patch.object(bash_module._BoundedBuffer, "write", delayed_write):
|
|
555
|
-
result = await asyncio.wait_for(bash("printf
|
|
554
|
+
result = await asyncio.wait_for(bash("printf delayed-output-complete"), timeout=5)
|
|
556
555
|
self.assertEqual(result.exit_code, 0)
|
|
557
|
-
self.
|
|
556
|
+
self.assertEqual(result.output, "delayed-output-complete")
|
|
557
|
+
|
|
558
|
+
async def test_completion_marker_split_across_reads_is_removed(self):
|
|
559
|
+
with mock.patch.object(bash_module, "_READ_CHUNK", 7):
|
|
560
|
+
result = await asyncio.wait_for(bash("printf exact-pre-fence-output"), timeout=5)
|
|
561
|
+
self.assertEqual(result.output, "exact-pre-fence-output")
|
|
558
562
|
|
|
559
563
|
async def test_slow_pump_does_not_lose_foreground_output(self):
|
|
560
|
-
#
|
|
561
|
-
# while the shell's output still sits unread in the pipe.
|
|
564
|
+
# Finalization waits for the pump to parse the ordered sentinel.
|
|
562
565
|
original_pump = bash_module.BashHandle._pump
|
|
563
566
|
|
|
564
567
|
def slow_pump(handle_self):
|
|
@@ -570,6 +573,58 @@ class BashTest(unittest.IsolatedAsyncioTestCase):
|
|
|
570
573
|
self.assertEqual(result.exit_code, 0)
|
|
571
574
|
self.assertIn("slow-pump-x", result.output)
|
|
572
575
|
|
|
576
|
+
async def test_sentinel_like_output_and_echoed_wrapper_do_not_truncate(self):
|
|
577
|
+
token = "0123456789abcdef" * 4
|
|
578
|
+
raw_lookalike = "\x1easm-agent-complete:not-this-invocation\x1f"
|
|
579
|
+
command = (
|
|
580
|
+
"set -x\n"
|
|
581
|
+
"printf '\\036asm-agent-complete:not-this-invocation\\037'\n"
|
|
582
|
+
"if [ -r /proc/$$/cmdline ]; then cat /proc/$$/cmdline; fi\n"
|
|
583
|
+
"printf '\\nafter-sentinel-lookalike\\n'"
|
|
584
|
+
)
|
|
585
|
+
with mock.patch.object(bash_module.secrets, "token_hex", return_value=token):
|
|
586
|
+
result = await asyncio.wait_for(bash(command), timeout=5)
|
|
587
|
+
actual_marker = (
|
|
588
|
+
bash_module._COMPLETION_PREFIX + token.encode() + bash_module._COMPLETION_SUFFIX
|
|
589
|
+
)
|
|
590
|
+
self.assertIn(raw_lookalike, result.output)
|
|
591
|
+
self.assertIn("after-sentinel-lookalike", result.output)
|
|
592
|
+
self.assertNotIn(actual_marker.decode(), result.output)
|
|
593
|
+
|
|
594
|
+
async def test_user_alias_cannot_replace_completion_emitter(self):
|
|
595
|
+
if os.path.basename(bash_module._shell()) != "bash":
|
|
596
|
+
self.skipTest("bash alias expansion semantics")
|
|
597
|
+
handle = bash(
|
|
598
|
+
"shopt -s expand_aliases; alias command='printf alias-expanded'; sleep 30 &"
|
|
599
|
+
)
|
|
600
|
+
try:
|
|
601
|
+
result = await asyncio.wait_for(handle, timeout=5)
|
|
602
|
+
self.assertEqual(result.exit_code, 0)
|
|
603
|
+
self.assertNotIn("alias-expanded", result.output)
|
|
604
|
+
finally:
|
|
605
|
+
handle.kill(signal.SIGKILL)
|
|
606
|
+
await _poll_group_dead(handle.pid)
|
|
607
|
+
|
|
608
|
+
async def test_user_function_cannot_replace_completion_emitter(self):
|
|
609
|
+
# The backslash in `\command` defeats alias expansion only: a shell
|
|
610
|
+
# function named `command` would otherwise swallow both fence frames
|
|
611
|
+
# and wedge the await behind the background job until shell death.
|
|
612
|
+
handle = bash("command() { printf function-expanded; }; sleep 30 &")
|
|
613
|
+
try:
|
|
614
|
+
result = await asyncio.wait_for(handle, timeout=5)
|
|
615
|
+
self.assertEqual(result.exit_code, 0)
|
|
616
|
+
self.assertNotIn("function-expanded", result.output)
|
|
617
|
+
finally:
|
|
618
|
+
handle.kill(signal.SIGKILL)
|
|
619
|
+
await _poll_group_dead(handle.pid)
|
|
620
|
+
|
|
621
|
+
async def test_shell_killed_before_sentinel_finalizes_from_exit(self):
|
|
622
|
+
result = await asyncio.wait_for(
|
|
623
|
+
bash("printf output-before-shell-kill; kill -KILL $$"), timeout=5
|
|
624
|
+
)
|
|
625
|
+
self.assertEqual(result.exit_code, -signal.SIGKILL)
|
|
626
|
+
self.assertIn("output-before-shell-kill", result.output)
|
|
627
|
+
|
|
573
628
|
async def test_relative_bash_shell_override_rejected(self):
|
|
574
629
|
with mock.patch.dict(os.environ, {"ASM_AGENT_BASH_SHELL": "bash"}):
|
|
575
630
|
with self.assertRaises(ValueError):
|
|
@@ -117,7 +117,7 @@ class ReplTest(unittest.TestCase):
|
|
|
117
117
|
|
|
118
118
|
def test_ready_handshake_and_startup_time(self):
|
|
119
119
|
self.assertEqual(self.ready_event["event"], "ready")
|
|
120
|
-
self.assertEqual(self.ready_event["protocol"],
|
|
120
|
+
self.assertEqual(self.ready_event["protocol"], 3)
|
|
121
121
|
major, minor = sys.version_info[:2]
|
|
122
122
|
self.assertTrue(self.ready_event["python"].startswith(f"{major}.{minor}."))
|
|
123
123
|
# Loose bound for loaded CI machines; still catches an order-of-magnitude regression.
|
|
@@ -779,11 +779,75 @@ class ReplTest(unittest.TestCase):
|
|
|
779
779
|
while request.get("event") != "host_request":
|
|
780
780
|
request = self.repl.read_event()
|
|
781
781
|
self.assertEqual(request["data"], {"type": "demo", "value": 7})
|
|
782
|
-
|
|
782
|
+
envelope = {"status": "ok", "result": {"status": "weird", "answer": 42}}
|
|
783
|
+
self.repl.send({"type": "host_reply", "id": request["id"], "data": envelope})
|
|
783
784
|
events = self.repl.until_done("hr")
|
|
784
|
-
self.assertEqual(one(events, "result")["text"],
|
|
785
|
+
self.assertEqual(one(events, "result")["text"], repr(envelope))
|
|
785
786
|
self.assertEqual(one(events, "done")["status"], "ok")
|
|
786
787
|
|
|
788
|
+
def test_typed_host_request_unwraps_exact_handler_result(self):
|
|
789
|
+
code = "\n".join(
|
|
790
|
+
[
|
|
791
|
+
"from rlm import host_request",
|
|
792
|
+
"reply = await host_request('demo')",
|
|
793
|
+
"reply",
|
|
794
|
+
]
|
|
795
|
+
)
|
|
796
|
+
self.repl.send({"type": "execute", "id": "typed-hr", "code": code})
|
|
797
|
+
request = self.repl.read_event()
|
|
798
|
+
while request.get("event") != "host_request":
|
|
799
|
+
request = self.repl.read_event()
|
|
800
|
+
handler_result = {"status": "weird", "answer": 42}
|
|
801
|
+
self.repl.send(
|
|
802
|
+
{
|
|
803
|
+
"type": "host_reply",
|
|
804
|
+
"id": request["id"],
|
|
805
|
+
"data": {"status": "ok", "result": handler_result},
|
|
806
|
+
}
|
|
807
|
+
)
|
|
808
|
+
events = self.repl.until_done("typed-hr")
|
|
809
|
+
self.assertEqual(one(events, "result")["text"], repr(handler_result))
|
|
810
|
+
self.assertEqual(one(events, "done")["status"], "ok")
|
|
811
|
+
|
|
812
|
+
def test_typed_host_request_raises_host_error(self):
|
|
813
|
+
code = "from rlm import host_request\nawait host_request('demo')"
|
|
814
|
+
self.repl.send({"type": "execute", "id": "typed-error", "code": code})
|
|
815
|
+
request = self.repl.read_event()
|
|
816
|
+
while request.get("event") != "host_request":
|
|
817
|
+
request = self.repl.read_event()
|
|
818
|
+
self.repl.send(
|
|
819
|
+
{
|
|
820
|
+
"type": "host_reply",
|
|
821
|
+
"id": request["id"],
|
|
822
|
+
"data": {"status": "error", "error": "handler exploded"},
|
|
823
|
+
}
|
|
824
|
+
)
|
|
825
|
+
events = self.repl.until_done("typed-error")
|
|
826
|
+
self.assertEqual(one(events, "error")["ename"], "RuntimeError")
|
|
827
|
+
self.assertEqual(one(events, "error")["evalue"], "handler exploded")
|
|
828
|
+
self.assertEqual(one(events, "done")["status"], "error")
|
|
829
|
+
|
|
830
|
+
def test_typed_host_request_rejects_unexpected_envelope_status(self):
|
|
831
|
+
code = "from rlm import host_request\nawait host_request('demo')"
|
|
832
|
+
self.repl.send({"type": "execute", "id": "typed-unexpected", "code": code})
|
|
833
|
+
request = self.repl.read_event()
|
|
834
|
+
while request.get("event") != "host_request":
|
|
835
|
+
request = self.repl.read_event()
|
|
836
|
+
self.repl.send(
|
|
837
|
+
{
|
|
838
|
+
"type": "host_reply",
|
|
839
|
+
"id": request["id"],
|
|
840
|
+
"data": {"status": "partial", "result": {}},
|
|
841
|
+
}
|
|
842
|
+
)
|
|
843
|
+
events = self.repl.until_done("typed-unexpected")
|
|
844
|
+
self.assertEqual(one(events, "error")["ename"], "RuntimeError")
|
|
845
|
+
self.assertEqual(
|
|
846
|
+
one(events, "error")["evalue"],
|
|
847
|
+
"host request demo returned unexpected status: 'partial'",
|
|
848
|
+
)
|
|
849
|
+
self.assertEqual(one(events, "done")["status"], "error")
|
|
850
|
+
|
|
787
851
|
def test_host_reply_for_unknown_id_dropped(self):
|
|
788
852
|
self.repl.send({"type": "host_reply", "id": "no-such-request", "data": {"status": "ok"}})
|
|
789
853
|
events = self.repl.execute("ok", "'alive'")
|