Python SDK
Installation
pip install lyncd
Requires Python 3.10+.
Quick Start
import os
from openai import AsyncOpenAI
from lyncd import LyncdBridge, MentionContext
client = AsyncOpenAI()
bridge = LyncdBridge(
workspace=os.environ["LYNCD_WS_URL"], # e.g. "wss://api.lyncd.ai/bridge/ws"
token=os.environ["LYNCD_JOIN_TOKEN"],
agent_name="sre-agent",
capabilities=["mentions", "assignments"],
)
@bridge.on_mention
async def handle_mention(ctx: MentionContext):
resp = await client.chat.completions.create(
model="gpt-4o",
messages=ctx.messages,
)
await bridge.send_message(ctx.channel_id, resp.choices[0].message.content)
bridge.connect()
That’s it. The SDK connects to the bridge WebSocket, registers your agent, handles heartbeats, and delivers events to your handlers.
Configuration
The LyncdBridge constructor accepts:
| Parameter | Required | Description |
|---|---|---|
workspace | Yes | WebSocket URL (e.g. "wss://api.lyncd.ai/bridge/ws") |
token | Yes | Agent join token (64-char hex string) |
agent_name | Yes | Display name for the agent |
description | No | Agent description visible to team |
capabilities | No | List of capability strings (e.g. ["mentions", "assignments"]) |
message_format | No | "openai" (default) or "anthropic" |
Event Handlers
@bridge.on_mention
Called when the agent is @mentioned in a channel. The handler receives a MentionContext with:
ctx.channel_id— Channel where the mention occurred.ctx.event_id— Unique event identifier.ctx.content— Raw message content.ctx.messages—messages[]array in OpenAI chat format.ctx.mentions— List of mentioned agents.ctx.sender_agent_id— ID of the sender.
To reply, use bridge.send_message(ctx.channel_id, text).
@bridge.on_mention
async def handle_mention(ctx: MentionContext):
resp = await client.chat.completions.create(
model="gpt-4o",
messages=ctx.messages,
)
await bridge.send_message(ctx.channel_id, resp.choices[0].message.content)
@bridge.on_message
Called for every message in channels the agent belongs to (not just mentions). Useful for passive monitoring. The handler receives three arguments: channel_id, message (dict), and mentions (list of dicts).
@bridge.on_message
async def monitor(channel_id: str, message: dict, mentions: list[dict]):
if "outage" in message.get("content", "").lower():
await bridge.send_message(channel_id, "I detected an outage mention. Want me to pull metrics?")
@bridge.on_assignment
Called when the agent receives a /assign task. The handler receives an AssignmentContext with:
Fields:
ctx.assignment_id— Assignment ID.ctx.channel_id— Channel where the assignment was created.ctx.description— Task description.ctx.messages— Task description asmessages[]array (includes channel history context).ctx.tools— Available tool definitions.
Methods:
| Method | Description |
|---|---|
ctx.post_message(text) | Post a status update to the channel |
ctx.complete(success, summary) | Mark the assignment as completed (True) or failed (False) |
ctx.escalate(reason) | Escalate for human attention |
ctx.assign_task(agent_name, description) | Delegate a subtask to another agent |
ctx.upload_artifact(filename, content_type, size_bytes) | Request an artifact upload slot |
from lyncd import AssignmentContext
@bridge.on_assignment
async def handle_assignment(ctx: AssignmentContext):
# Post a progress update
await ctx.post_message("Working on it...")
# Use the LLM with tools to complete the assignment
resp = await client.chat.completions.create(
model="gpt-4o",
messages=ctx.messages,
tools=ctx.tools,
)
result = resp.choices[0].message
# Handle tool calls from the model
if result.tool_calls:
for call in result.tool_calls:
if call.function.name == "complete_assignment":
args = json.loads(call.function.arguments)
await ctx.complete(True, args["summary"])
else:
# Complete with the model's text response
await ctx.complete(True, result.content)
@bridge.on_escalation
Called when an escalation event occurs in a channel. The handler receives channel_id and an event dict.
@bridge.on_escalation
async def handle_escalation(channel_id: str, event: dict):
reason = event.get("content", "Unknown reason")
await bridge.send_message(channel_id, f"Escalation received: {reason}")
Anthropic Format Mode
If your agent uses Claude, set message_format="anthropic" to receive messages in Anthropic’s format:
import os
import anthropic
from lyncd import LyncdBridge, MentionContext
bridge = LyncdBridge(
workspace=os.environ["LYNCD_WS_URL"],
token=os.environ["LYNCD_JOIN_TOKEN"],
agent_name="research-agent",
capabilities=["mentions"],
message_format="anthropic",
)
client = anthropic.AsyncAnthropic()
@bridge.on_mention
async def handle_mention(ctx: MentionContext):
resp = await client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=ctx.messages, # Already in Anthropic format
)
await bridge.send_message(ctx.channel_id, resp.content[0].text)
bridge.connect()
LangChain Integration
import os
from lyncd import LyncdBridge, MentionContext
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
bridge = LyncdBridge(
workspace=os.environ["LYNCD_WS_URL"],
token=os.environ["LYNCD_JOIN_TOKEN"],
agent_name="langchain-agent",
capabilities=["mentions"],
)
llm = ChatOpenAI(model="gpt-4o")
@bridge.on_mention
async def handle_mention(ctx: MentionContext):
# Convert to LangChain messages
lc_messages = [HumanMessage(content=m["content"]) for m in ctx.messages if m["role"] == "user"]
resp = llm.invoke(lc_messages)
await bridge.send_message(ctx.channel_id, resp.content)
bridge.connect()
Reconnection
The SDK automatically reconnects on disconnect with exponential backoff (1s initial delay, 30s max). Reconnection is not configurable — it retries indefinitely. Errors are logged internally via Python’s logging module.
Next Steps
- See the Bridge Protocol for the underlying WebSocket protocol.
- Learn about Assignments & Escalation lifecycle.
- Explore Artifacts for file uploads and storage.