Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Autotests/mock/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
except ImportError:
from rpc import Rpc, IPCClient, IPCServer
from contextlib import contextmanager
import re
import threading
from providers import *

LLM_MOCK_PORT = 9765

# The loop sends every user message as "Step <time>: <text>"; answers are keyed by <text>.
_STEP_PREFIX = re.compile(r"^Step \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}: ")

class LlmMockAgent:

def __init__(self, address):
Expand Down Expand Up @@ -41,15 +45,16 @@ def normalize(text):
.replace("_quote_", '"')
.replace("_newline_", "\n"))

text = _STEP_PREFIX.sub("", body, count=1)
with self._lock:
answer = self._answers.get(body) or self._answers.get(normalize(body))
answer = self._answers.get(text) or self._answers.get(normalize(text))

if not answer:
# IRC may deliver multiple PRIVMSGs in one agent iteration; the
# agent concatenates them with " | " between speakers. Split
# and look up each fragment individually so a registered answer
# is not missed when several messages arrive together.
fragments = body.split(" | ")
fragments = text.split(" | ")
for fragment in fragments:
if ": " not in fragment:
continue
Expand Down
10 changes: 10 additions & 0 deletions Autotests/mock/test_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ def test_no_message(self, agent, controller):
assert controller.set_answer("hello", _llm_response_json("world"))
assert agent.chat(_llm_request("DO NOT RE-SEND OR SPAM!")) == LLMResponse()

def test_step_prefix_before_sender(self, agent, controller):
assert controller.set_answer("hello", _llm_response_json("world"))
msg = "Step 2026-09-24 15:12:23: <@U0B6ML16Q84> (OmegaClaw Driver): hello"
assert agent.chat(_llm_request(msg)) == _llm_response("world")

def test_step_prefix_without_sender(self, agent, controller):
assert controller.set_answer("hello", _llm_response_json("world"))
msg = "Step 2026-09-24 15:12:23: hello"
assert agent.chat(_llm_request(msg)) == _llm_response("world")

def test_context_manager(self, agent):
with llm_mock_controller(address=TEST_ADDRESS) as controller:
assert controller.set_answer("hello", _llm_response_json("world"))
Expand Down
11 changes: 6 additions & 5 deletions Autotests/mock_slack/test_complex_weather_flow_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,12 @@ def test_complex_weather_flow_slack_mock(llm, sl):
# Single LLM response containing the full pipeline.
llm.set_answer(
prompt,
f'(write-file "{WEATHER_TXT}" "{FORECAST_TEXT}") '
f'(write-file "{SCRIPT_SH}" '
f'"#!/bin/bash\\ngrep -oE \'[0-9]+\' {WEATHER_TXT} | head -1 > {TEMP_ONLY}\\n") '
f'(shell "chmod +x {SCRIPT_SH}") '
f'(shell "sh {SCRIPT_SH}")',
[
("write-file", { "filename": f"{WEATHER_TXT}", "content": f"{FORECAST_TEXT}" }),
("write-file", { "filename": f"{SCRIPT_SH}", "content": f"#!/bin/bash\\ngrep -oE '[0-9]+' {WEATHER_TXT} | head -1 > {TEMP_ONLY}\\n" }),
("shell", { "cmd": f"chmod +x {SCRIPT_SH}" }),
("shell", { "cmd": f"sh {SCRIPT_SH}" }),
],
)
sl_send_prompt(sl, prompt)
c.ok("slack", f"run-id={c.run_id}")
Expand Down
2 changes: 1 addition & 1 deletion Autotests/mock_slack/test_convert_format_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def test_convert_md_to_txt_slack_mock(llm, sl):
)
llm.set_answer(
prompt,
f'(shell "cp {SOURCE_FILE} {DEST_FILE}")',
[("shell", { "cmd": f"cp {SOURCE_FILE} {DEST_FILE}" })],
)
sl_send_prompt(sl, prompt)
c.ok("slack", f"run-id={c.run_id}")
Expand Down
6 changes: 4 additions & 2 deletions Autotests/mock_slack/test_create_empty_file_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ def test_create_empty_file_slack_mock(llm, sl):
)
llm.set_answer(
prompt,
f'(shell "mkdir -p {TARGET_DIR}") '
f'(write-file "{TARGET_FILE}" "")',
[
("shell", { "cmd": f"mkdir -p {TARGET_DIR}" }),
("write-file", { "filename": f"{TARGET_FILE}", "content": "" }),
],
)
sl_send_prompt(sl, prompt)
c.ok("slack", f"run-id={c.run_id}")
Expand Down
5 changes: 4 additions & 1 deletion Autotests/mock_slack/test_create_file_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ def test_hello_file_slack_mock(llm, sl):
f"Please overwrite {TARGET_FILE} so it contains exactly the single "
"word Hello (no quotes, no extra newlines, create the directory if needed).",
)
llm.set_answer(prompt, f'(shell "mkdir -p /tmp/testcat") (write-file "/tmp/testcat/hello.txt" "Hello")')
llm.set_answer(prompt, [
("shell", { "cmd": "mkdir -p /tmp/testcat" }),
("write-file", { "filename": "/tmp/testcat/hello.txt", "content": "Hello" }),
])

sl_send_prompt(sl, prompt)
c.ok("slack", f"prompt delivered, run-id={c.run_id}")
Expand Down
8 changes: 5 additions & 3 deletions Autotests/mock_slack/test_create_script_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ def test_create_date_script_slack_mock(llm, sl):
)
llm.set_answer(
prompt,
f'(shell "mkdir -p {TARGET_DIR}") '
f'(write-file "{TARGET_FILE}" "#!/bin/bash\\ndate\\n") '
f'(shell "chmod +x {TARGET_FILE}")',
[
("shell", { "cmd": f"mkdir -p {TARGET_DIR}" }),
("write-file", { "filename": f"{TARGET_FILE}", "content": "#!/bin/bash\\ndate\\n" }),
("shell", { "cmd": f"chmod +x {TARGET_FILE}" }),
],
)
sl_send_prompt(sl, prompt)
c.ok("slack", f"run-id={c.run_id}")
Expand Down
2 changes: 1 addition & 1 deletion Autotests/mock_slack/test_edit_add_timestamp_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def test_edit_add_timestamp_slack_mock(llm, sl):
# real test.
llm.set_answer(
prompt,
f'(shell "date -Iseconds >> {TARGET_FILE}")',
[("shell", { "cmd": f"date -Iseconds >> {TARGET_FILE}" })],
)
sl_send_prompt(sl, prompt)
c.ok("slack", f"run-id={c.run_id}")
Expand Down
2 changes: 1 addition & 1 deletion Autotests/mock_slack/test_edit_append_line_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def test_edit_append_line_slack_mock(llm, sl):
)
llm.set_answer(
prompt,
f'(shell "printf \'%s\\\\n\' {LINE4_EXPECTED} >> {TARGET_FILE}")',
[("shell", { "cmd": f"printf '%s\\\\n' {LINE4_EXPECTED} >> {TARGET_FILE}" })],
)
sl_send_prompt(sl, prompt)
c.ok("slack", f"run-id={c.run_id}")
Expand Down
2 changes: 1 addition & 1 deletion Autotests/mock_slack/test_edit_delete_line_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def test_edit_delete_line_slack_mock(llm, sl):
)
llm.set_answer(
prompt,
f'(shell "sed -i 2d {TARGET_FILE}")',
[("shell", { "cmd": f"sed -i 2d {TARGET_FILE}" })],
)
sl_send_prompt(sl, prompt)
c.ok("slack", f"run-id={c.run_id}")
Expand Down
10 changes: 6 additions & 4 deletions Autotests/mock_slack/test_git_local_commit_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@ def test_git_local_commit_slack_mock(llm, sl):
# arg itself is double-quoted, so we escape inner quotes.
llm.set_answer(
prompt,
f'(shell "git -C {TARGET_DIR} init") '
f'(write-file "{commit_path}" "{marker}") '
f'(shell "git -C {TARGET_DIR} add -A") '
f'(shell "git -C {TARGET_DIR} commit -m \\"add hello {c.run_id}\\"")',
[
("shell", { "cmd": f"git -C {TARGET_DIR} init" }),
("write-file", { "filename": f"{commit_path}", "content": f"{marker}" }),
("shell", { "cmd": f"git -C {TARGET_DIR} add -A" }),
("shell", { "cmd": f"git -C {TARGET_DIR} commit -m \"add hello {c.run_id}\"" }),
],
)
sl_send_prompt(sl, prompt)
c.ok("slack", f"run-id={c.run_id}")
Expand Down
2 changes: 1 addition & 1 deletion Autotests/mock_slack/test_memory_chromadb_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def test_memory_chromadb_slack_mock(llm, sl):
)
llm.set_answer(
prompt,
f'(remember "Unique smoke marker {marker} was emitted by CI.")',
[("remember", { "content": f"Unique smoke marker {marker} was emitted by CI." })],
)
sl_send_prompt(sl, prompt)
c.ok("slack", f"run-id={c.run_id}")
Expand Down
7 changes: 5 additions & 2 deletions Autotests/mock_slack/test_memory_episode_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def test_memory_episode_slack_mock(llm, sl):
)
llm.set_answer(
prompt1,
'(remember "Barney the dog lost his first baby tooth at the vet today.")',
[("remember", { "content": "Barney the dog lost his first baby tooth at the vet today." })],
)
sl_send_prompt(sl, prompt1)
c.ok("irc-1", f"run-id={fact_marker}")
Expand Down Expand Up @@ -88,7 +88,10 @@ def is_barney_memory(s):
)
llm.set_answer(
prompt2,
f'(query "Barney tooth") (send "{recall_reply}")',
[
("query", { "content": "Barney tooth" }),
("send", { "content": f"{recall_reply}" }),
],
)
sl_send_prompt(sl, prompt2)
c.ok("irc-2", f"run-id={recall_marker}")
Expand Down
8 changes: 5 additions & 3 deletions Autotests/mock_slack/test_run_create_dirs_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ def test_run_create_dirs_slack_mock(llm, sl):
mkdir_args = " ".join(f"{TARGET_DIR}/{d}" for d in EXPECTED_DIRS)
llm.set_answer(
prompt,
f'(write-file "{SCRIPT_PATH}" "#!/bin/bash\\nmkdir -p {mkdir_args}\\n") '
f'(shell "chmod +x {SCRIPT_PATH}") '
f'(shell "sh {SCRIPT_PATH}")',
[
("write-file", { "filename": f"{SCRIPT_PATH}", "content": f"#!/bin/bash\\nmkdir -p {mkdir_args}\\n" }),
("shell", { "cmd": f"chmod +x {SCRIPT_PATH}" }),
("shell", { "cmd": f"sh {SCRIPT_PATH}" }),
],
)
sl_send_prompt(sl, prompt)
c.ok("slack", f"run-id={c.run_id}")
Expand Down
2 changes: 1 addition & 1 deletion Autotests/mock_slack/test_run_error_script_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def test_run_error_script_slack_mock(llm, sl):
)
llm.set_answer(
prompt,
f'(shell "sh {SCRIPT_FILE} > {OUTPUT_FILE} 2>&1")',
[("shell", { "cmd": f"sh {SCRIPT_FILE} > {OUTPUT_FILE} 2>&1" })],
)
sl_send_prompt(sl, prompt)
c.ok("slack", f"run-id={c.run_id}")
Expand Down
7 changes: 5 additions & 2 deletions Autotests/mock_slack/test_skill_episodes_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def test_skill_episodes_slack_mock(llm, sl):
f"the keyword {marker} from me. No need to remember it — just "
f"reply once.",
)
llm.set_answer(seed_prompt, f'(send "Acknowledged keyword {marker}.")')
llm.set_answer(seed_prompt, [("send", { "content": f"Acknowledged keyword {marker}." })])
sl_send_prompt(sl, seed_prompt)
c.ok("irc-seed", f"run-id={seed_id}, time={seed_time:%H:%M:%S}")

Expand Down Expand Up @@ -69,7 +69,10 @@ def test_skill_episodes_slack_mock(llm, sl):
)
llm.set_answer(
recall_prompt,
f'(episodes "{time_str}") (send "The unique keyword was {marker}.")',
[
("episodes", { "timestamp": f"{time_str}" }),
("send", { "content": f"The unique keyword was {marker}." }),
],
)
sl_send_prompt(sl, recall_prompt)
c.ok("irc-recall", f"run-id={recall_id}")
Expand Down
5 changes: 4 additions & 1 deletion Autotests/mock_slack/test_skill_metta_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ def test_skill_metta_slack_mock(llm, sl):
# concrete number is communicated back.
llm.set_answer(
prompt,
'(metta "(+ 2 2)") (send "The metta skill evaluated (+ 2 2) and returned 4.")',
[
("metta", { "sexpression": "(+ 2 2)" }),
("send", { "content": "The metta skill evaluated (+ 2 2) and returned 4." }),
],
)
sl_send_prompt(sl, prompt)
c.ok("slack", f"run-id={c.run_id}")
Expand Down
8 changes: 5 additions & 3 deletions Autotests/mock_slack/test_skill_query_slack_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def test_skill_query_slack_mock(llm, sl):
seed_prompt,
[
("remember", { "content": f"My favorite color is {secret_color}." }),
("send", { "content": f"Stored: favorite colour is {secret_color}."),
("send", { "content": f"Stored: favorite colour is {secret_color}." }),
]
)
sl_send_prompt(sl, seed_prompt)
Expand Down Expand Up @@ -79,8 +79,10 @@ def has_color(arg):
)
llm.set_answer(
recall_prompt,
f'(query "favorite color") '
f'(send "Your favorite color is {secret_color}.")',
[
("query", { "content": "favorite color" }),
("send", { "content": f"Your favorite color is {secret_color}." }),
],
)
sl_send_prompt(sl, recall_prompt)
c.ok("irc-recall", f"run-id={recall_id}")
Expand Down
12 changes: 11 additions & 1 deletion Autotests/mock_slack/test_slack_unwrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
Run:
pytest test_slack_unwrap.py -s
"""
import importlib.util
import os
import sys

Expand All @@ -17,7 +18,16 @@
if _PARENT not in sys.path:
sys.path.insert(0, _PARENT)

from channels.slack import _slack_unwrap # noqa: E402
# src/channels.py shadows the channels/ package on pythonpath, so load slack.py by path
# and let it import its siblings (auth, delivery_queue) the way the container does.
_CHANNELS = os.path.join(_PARENT, "channels")
if _CHANNELS not in sys.path:
sys.path.append(_CHANNELS)
_spec = importlib.util.spec_from_file_location(
"slack_channel_under_test", os.path.join(_PARENT, "channels", "slack.py"))
_slack = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_slack)
_slack_unwrap = _slack._slack_unwrap


@pytest.fixture(scope="session")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,12 @@ def test_complex_weather_flow_telegram_mock(llm, tg):
# Single LLM response containing the full pipeline.
llm.set_answer(
prompt,
f'(write-file "{WEATHER_TXT}" "{FORECAST_TEXT}") '
f'(write-file "{SCRIPT_SH}" '
f'"#!/bin/bash\\ngrep -oE \'[0-9]+\' {WEATHER_TXT} | head -1 > {TEMP_ONLY}\\n") '
f'(shell "chmod +x {SCRIPT_SH}") '
f'(shell "sh {SCRIPT_SH}")',
[
("write-file", { "filename": f"{WEATHER_TXT}", "content": f"{FORECAST_TEXT}" }),
("write-file", { "filename": f"{SCRIPT_SH}", "content": f"#!/bin/bash\\ngrep -oE '[0-9]+' {WEATHER_TXT} | head -1 > {TEMP_ONLY}\\n" }),
("shell", { "cmd": f"chmod +x {SCRIPT_SH}" }),
("shell", { "cmd": f"sh {SCRIPT_SH}" }),
],
)
tg_send_prompt(tg, prompt)
c.ok("telegram", f"run-id={c.run_id}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def test_convert_md_to_txt_telegram_mock(llm, tg):
)
llm.set_answer(
prompt,
f'(shell "cp {SOURCE_FILE} {DEST_FILE}")',
[("shell", { "cmd": f"cp {SOURCE_FILE} {DEST_FILE}" })],
)
tg_send_prompt(tg, prompt)
c.ok("telegram", f"run-id={c.run_id}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ def test_create_empty_file_telegram_mock(llm, tg):
)
llm.set_answer(
prompt,
f'(shell "mkdir -p {TARGET_DIR}") '
f'(write-file "{TARGET_FILE}" "")',
[
("shell", { "cmd": f"mkdir -p {TARGET_DIR}" }),
("write-file", { "filename": f"{TARGET_FILE}", "content": "" }),
],
)
tg_send_prompt(tg, prompt)
c.ok("telegram", f"run-id={c.run_id}")
Expand Down
5 changes: 4 additions & 1 deletion Autotests/mock_telegram/test_create_file_telegram_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ def test_hello_file_telegram_mock(llm, tg):
f"Please overwrite {TARGET_FILE} so it contains exactly the single "
"word Hello (no quotes, no extra newlines, create the directory if needed).",
)
llm.set_answer(prompt, f'(shell "mkdir -p /tmp/testcat") (write-file "/tmp/testcat/hello.txt" "Hello")')
llm.set_answer(prompt, [
("shell", { "cmd": "mkdir -p /tmp/testcat" }),
("write-file", { "filename": "/tmp/testcat/hello.txt", "content": "Hello" }),
])

tg_send_prompt(tg, prompt)
c.ok("telegram", f"prompt delivered, run-id={c.run_id}")
Expand Down
8 changes: 5 additions & 3 deletions Autotests/mock_telegram/test_create_script_telegram_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ def test_create_date_script_telegram_mock(llm, tg):
)
llm.set_answer(
prompt,
f'(shell "mkdir -p {TARGET_DIR}") '
f'(write-file "{TARGET_FILE}" "#!/bin/bash\\ndate\\n") '
f'(shell "chmod +x {TARGET_FILE}")',
[
("shell", { "cmd": f"mkdir -p {TARGET_DIR}" }),
("write-file", { "filename": f"{TARGET_FILE}", "content": "#!/bin/bash\\ndate\\n" }),
("shell", { "cmd": f"chmod +x {TARGET_FILE}" }),
],
)
tg_send_prompt(tg, prompt)
c.ok("telegram", f"run-id={c.run_id}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def test_edit_add_timestamp_telegram_mock(llm, tg):
# real test.
llm.set_answer(
prompt,
f'(shell "date -Iseconds >> {TARGET_FILE}")',
[("shell", { "cmd": f"date -Iseconds >> {TARGET_FILE}" })],
)
tg_send_prompt(tg, prompt)
c.ok("telegram", f"run-id={c.run_id}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def test_edit_append_line_telegram_mock(llm, tg):
)
llm.set_answer(
prompt,
f'(shell "printf \'%s\\\\n\' {LINE4_EXPECTED} >> {TARGET_FILE}")',
[("shell", { "cmd": f"printf '%s\\\\n' {LINE4_EXPECTED} >> {TARGET_FILE}" })],
)
tg_send_prompt(tg, prompt)
c.ok("telegram", f"run-id={c.run_id}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def test_edit_delete_line_telegram_mock(llm, tg):
)
llm.set_answer(
prompt,
f'(shell "sed -i 2d {TARGET_FILE}")',
[("shell", { "cmd": f"sed -i 2d {TARGET_FILE}" })],
)
tg_send_prompt(tg, prompt)
c.ok("telegram", f"run-id={c.run_id}")
Expand Down
Loading