Skip to content

Message Handling

Makaio adapters do not expose a direct adapter.sendMessage() API. Message traffic moves through bus subjects owned by the adapter and agent layers:

  • AdapterSubjects.startAgent creates an agent and optionally sends the first message.
  • AgentSubjects.sendMessage sends a follow-up message to an existing agent.
  • AdapterSubjects.infer runs one-shot inference without registering a long-lived agent.

Use AdapterSubjects.startAgent when the caller needs an agent lifecycle, session identity, tool orchestration, streaming events, or future follow-up turns.

import { AdapterSubjects } from '@makaio/contracts';
import { MakaioBus } from '@makaio/bus-core';
const started = await MakaioBus.request(AdapterSubjects.startAgent, {
adapterId,
role: 'lead',
initialMessage: 'Summarize the current project state.',
model: 'provider-model-id',
cwd: '/workspace/project',
systemPrompt: {
mode: 'append',
content: 'Keep the response concise.',
},
});
if (!started.success) {
throw new Error(started.message);
}
const { agentId, sessionId, messageId } = started;

startAgent returns identifiers, not final assistant text. Consumers observe normalized agent.* events such as agent.message_delta, agent.message, agent.complete, agent.tool.use, and agent.usage.

Use AgentSubjects.sendMessage for follow-up turns. Include the sessionId returned by startAgent so hooks, storage, and session-aware services can resolve context.

import { AgentSubjects } from '@makaio/contracts';
import { MakaioBus } from '@makaio/bus-core';
const response = await MakaioBus.request(AgentSubjects.sendMessage, {
adapterId,
agentId,
sessionId,
message: 'Now list the risky areas.',
messageId: crypto.randomUUID(),
turnId: crypto.randomUUID(),
deliveryMode: 'enqueue',
});
console.log(response.messageId);

The request acknowledges that the message entered the agent pipeline. Final content and errors arrive on lifecycle events emitted by the agent.

Use AdapterSubjects.infer for short, stateless calls that should not create an agent record or participate in multi-turn orchestration.

import { AdapterSubjects } from '@makaio/contracts';
import { MakaioBus } from '@makaio/bus-core';
const result = await MakaioBus.request(AdapterSubjects.infer, {
adapterId,
prompt: 'Return a JSON title for this note.',
model: 'provider-model-id',
systemPrompt: 'Return only JSON.',
});
console.log(result.text);

initialMessage and AgentSubjects.sendMessage.message accept either a plain string or a structured message:

{
role: 'user',
blocks: [
{ type: 'text', content: 'Review this screenshot.' },
{
type: 'image',
source: {
type: 'base64',
data: encodedImage,
mimeType: 'image/png',
},
},
],
}

Adapters normalize this input before it reaches the connector.

Common runtime options are carried on startAgent, AgentSubjects.sendMessage, or AdapterSubjects.infer depending on the subject schema:

OptionApplies toPurpose
modelstartAgent, inferProvider model identifier
reasoningEffortstartAgentReasoning level for providers that support it
cwdstartAgentWorking directory for tool-aware adapters
allowedTools / disallowedToolsstartAgentAdapter-specific tool policy
systemPromptstartAgent, inferStart accepts replace/append; infer accepts string instructions
responseSchemaAgentSubjects.sendMessageJSON schema for structured output
sessionContextstartAgent, AgentSubjects.sendMessageCurated history and resume/fork signals
mcpSessionContextstartAgentResolved MCP tools and servers
providerContextstartAgent, inferCredential refs and provider definition identity

startAgent.role is a session role, not a chat-message role. Valid values are lead and member; user/assistant roles belong inside structured message blocks.

Check capabilities before setting optional features. For example, require structuredOutput before sending responseSchema, tools before enabling tool use, streaming before relying on incremental response events, and modelSwitchInSession before changing models on an active agent.

Bus requests throw if the subject has no handler or the handler rejects. Subject responses also carry domain-level failures:

const started = await MakaioBus.request(AdapterSubjects.startAgent, {
adapterId,
role: 'lead',
initialMessage: 'Hello',
});
if (!started.success) {
throw new Error(started.message);
}

For active turns, listen to agent.complete. A completed turn has outcome: 'completed'; other outcomes include error, cancelled, superseded, merged, and rejected.

  • Creating Adapters - Current adapter implementation guide
  • Capabilities - Capability declaration and querying