scripts._irc_send
Reference › scripts › _irc_send
Sends one message to the #agents IRC channel and, on a best-effort basis, captures it as a SPEC-021 conversation message through _irc_conversation. It is the sending counterpart of _irc_listen. No test imports it, and it has no command-line parser.
send_message takes the text, and optionally the host, port, nick, channel and environment. The nick defaults to the IRC_NICK variable (else claude) with an -out suffix, because the persistent listener already holds the bare nick and the server would reject a colliding registration, which would swallow the message. It opens a connection (connect), registers, joins the channel, sends the message and quits (send, read). Only after the send does it look up the current listener session in Redis and enqueue the text as a user message from the irc platform; if no listener session is active it skips capture and says so on standard error, so capture never delays or blocks the send.
At a glance
| Source | scripts/_irc_send.py |
| Lines of code | 109 |
| Classes | 0 |
| Functions | 4 |
| Imports (internal) | none |
| Imported by | none |
| Tests that import it | none |
Class diagram
No classes; see Functions.
Dependency diagram
No internal imports and no importers.
API
Functions
| Function | Signature | Summary |
|---|---|---|
connect |
connect(host: str = HOST, port: int = PORT) -> socket.socket |
|
send |
send(sock: socket.socket, msg: str) -> None |
|
read |
read(sock: socket.socket) -> None |
|
send_message |
send_message(text: str, *, host: str = HOST, port: int = PORT, nick: str | None = None, chan: str = '#agents', env: dict[str, str] | None = None, queue_key: str = 'orchestrata:conversation:queue') -> None |
Send text as a PRIVMSG to chan, then (best-effort) capture it. |
Source
Permalink: https://gitlab.com/MSamy/orchestrata-ultimate-architecture/-/blob/a4cbc2bdf/scripts/_irc_send.py
"""Send one message to #agents and (best-effort) capture it as a SPEC-021
conversation turn.
Per plans/spec-021-multiplatform-producers.md § "kimi/IRC producer": this
sender reads the CURRENT session (allocated by ``_irc_listen.py`` at
connect+join) via ``_irc_conversation.read_current_session_seq`` so an
outbound line lands in the SAME conversation the fleet's replies are being
captured under. If no listener session is active (key absent, or Redis is
unreachable), the IRC line is still SENT — delegation traffic must never be
blocked by conversation capture — and capture is skipped with a message to
stderr.
"""
import os
import socket
import sys
import time
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import _irc_conversation as convo # noqa: E402
HOST, PORT = "127.0.0.1", 6667
def connect(host: str = HOST, port: int = PORT) -> socket.socket:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.settimeout(2.0)
return s
def send(sock: socket.socket, msg: str) -> None:
sock.sendall((msg + "\r\n").encode())
def read(sock: socket.socket) -> None:
try:
data = sock.recv(4096)
for line in data.decode("utf-8", errors="replace").split("\r\n"):
if line:
print(line)
except OSError:
# fire-and-forget console reader: a recv timeout/reset is expected and
# irrelevant to this one-shot sender — nothing to recover.
pass
def send_message(
text: str,
*,
host: str = HOST,
port: int = PORT,
nick: str | None = None,
chan: str = "#agents",
env: dict[str, str] | None = None,
queue_key: str = "orchestrata:conversation:queue",
) -> None:
"""Send ``text`` as a PRIVMSG to ``chan``, then (best-effort) capture it.
The IRC send always happens first and unconditionally; capture (which
depends on a live listener session in Redis) is attempted only after,
and never delays or blocks the send.
``nick`` defaults to ``IRC_NICK`` from the environment (fleet identity)
with an ``-out`` suffix — the persistent listener already holds the bare
nick, and miniircd rejects a colliding registration (433), which silently
swallows the PRIVMSG. A distinct one-shot nick keeps the send deliverable
while still attributable to the owning agent.
"""
if nick is None:
base = (env if env is not None else os.environ).get("IRC_NICK", "claude")
nick = f"{base}-out"
s = connect(host, port)
send(s, f"NICK {nick}")
send(s, f"USER {nick} 0 * :Done")
time.sleep(0.3)
read(s)
send(s, f"JOIN {chan}")
time.sleep(0.3)
read(s)
send(s, f"PRIVMSG {chan} :{text}")
time.sleep(0.5)
read(s)
send(s, "QUIT :done")
s.close()
session_seq = convo.read_current_session_seq(env=env)
if session_seq is None:
print(
"[irc-send] capture skipped: no active kimi listener session",
file=sys.stderr,
)
return
convo.enqueue_message(
role="user",
platform="irc",
content=text,
session_seq=session_seq,
conversation_id=convo.conversation_id_for(session_seq),
env=env,
queue_key=queue_key,
)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("usage: _irc_send.py <message ...>", file=sys.stderr)
raise SystemExit(2)
send_message(" ".join(sys.argv[1:]))