Messages

Send and receive chat messages, stream AI responses, and search conversation history.

Messages API

Messages are the communication layer between you (the Captain) and your agent team. Every message is persisted in Convex, supports real-time streaming, and is searchable. Messages are scoped to a lab.

Message Roles

RoleDescription
userMessage from the Captain or a collaborator
assistantResponse from an AI agent
systemSystem-generated message (experiment alerts, status changes, etc.)

Send a Message

Send a message to the orchestrator or a specific agent. The response streams back in real time.

Lab ID for the conversation.

Message text. Supports markdown.

Target a specific agent. If omitted, the message goes to the orchestrator.

Contextual metadata (e.g., which experiment, paper, or view is currently open).

Active experiment ID.
Active paper ID.
Current UI view (e.g., `captain`, `experiments`, `papers`).
curl -X POST https://api.hubify.com/v1/messages \
  -H "Authorization: Bearer $HUBIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "labId": "j57a8k9m2n3p4q5r",
    "content": "What is the current status of the Planck+BAO MCMC chains?",
    "context": {"view": "experiments"}
  }'
const message = await hubify.messages.send({
  labId: "j57a8k9m2n3p4q5r",
  content: "What is the current status of the Planck+BAO MCMC chains?",
  context: { view: "experiments" },
});
Convex document ID.
Lab ID.
Sender user ID (for `user` role).
Sender agent ID (for `assistant` role).
Message role: `user`, `assistant`, or `system`.
Message content (markdown).
JSON-encoded context metadata.
True while the assistant is still generating.
Model that generated the response (e.g., `claude-opus-4-6`).
Total tokens used.
Estimated cost in USD.
Timestamp (ms).

Streaming Responses

When an agent responds, the message is created immediately with streaming: true. The content field updates in real time as tokens are generated. When the response is complete, streaming flips to false.

Subscribe to Streaming (Real-Time)




function ChatPanel({ labId }: { labId: string }) {
  // This query re-renders on every content update (token-level streaming)
  const messages = useQuery(api.messages.list, { labId });

  return (
    <div>
      {messages?.map((msg) => (
        <div key={msg._id} className={msg.role}>
          {msg.content}
          {msg.streaming && <span className="cursor-blink" />}
        </div>
      ))}
    </div>
  );
}

HTTP Streaming (Server-Sent Events)

For non-Convex clients, the API supports SSE streaming:

curl -N https://api.hubify.com/v1/messages/stream \
  -H "Authorization: Bearer $HUBIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "labId": "j57a8k9m2n3p4q5r",
    "content": "Summarize the latest experiment results"
  }'

Response stream:

data: {"type": "token", "content": "The"}
data: {"type": "token", "content": " latest"}
data: {"type": "token", "content": " MCMC"}
...
data: {"type": "done", "messageId": "p12e3f4g5h6i7j8k", "tokenCount": 847}

List Messages

Retrieve conversation history for a lab.

Lab ID.

Number of messages to return (most recent first).

Pagination cursor for older messages.

Filter by role: user, assistant, system.

Filter to messages from a specific agent.

curl "https://api.hubify.com/v1/messages?labId=j57a8k9m2n3p4q5r&limit=20" \
  -H "Authorization: Bearer $HUBIFY_TOKEN"
const messages = await hubify.messages.list({
  labId: "j57a8k9m2n3p4q5r",
  limit: 20,
});

Search Messages

Full-text search across conversation history.

Lab ID to search within.

Search query. Matches against message content.

Maximum results.

curl "https://api.hubify.com/v1/messages/search?labId=j57a8k9m2n3p4q5r&query=convergence+diagnostics" \
  -H "Authorization: Bearer $HUBIFY_TOKEN"
const results = await hubify.messages.search({
  labId: "j57a8k9m2n3p4q5r",
  query: "convergence diagnostics",
});

Delete a Message

Delete a single message. Only the Captain can delete messages.

curl -X DELETE https://api.hubify.com/v1/messages/p12e3f4g5h6i7j8k \
  -H "Authorization: Bearer $HUBIFY_TOKEN"
await hubify.messages.delete({ messageId: "p12e3f4g5h6i7j8k" });

Agent-to-Agent Messages

Internal communication between agents is logged in the agent_messages table and visible in the Activity Feed. These are separate from Captain-facing chat messages.

List Agent Messages

Lab ID.

Filter by channel: delegation, status, escalation, broadcast.

curl "https://api.hubify.com/v1/agent-messages?labId=j57a8k9m2n3p4q5r&channel=escalation" \
  -H "Authorization: Bearer $HUBIFY_TOKEN"
const agentMessages = await hubify.agentMessages.list({
  labId: "j57a8k9m2n3p4q5r",
  channel: "escalation",
});
Convex document ID.
Lab ID.
Sending agent ID.
Receiving agent ID. Null for broadcasts.
Communication channel.
Message content.
JSON-encoded context.
Timestamp (ms).
← Back to docs index