Skip to content

Action (Behavior Tool)

Actions are tools that give your AI companion a physical presence. They enable communication and interaction with the external environment by sending messages or actions to P2P networks and clients.

  • Notification to Clients: Has the ability to influence external systems, such as sending messages to P2P networks or notifying clients.
  • Declarative Execution: Defines tool execution through CEL expressions using declarative syntax.

Use the createCompanionAction function to create an Action tool.

export function createCompanionAction<T extends ZodTypeAny>({
id,
description,
inputSchema,
topic,
publish,
}: CompanionActionConfig<T>)
export interface CompanionActionConfig<T extends z.ZodSchema> {
id: string;
description: string;
inputSchema: T;
topic: "actions" | "messages";
publish: (props: {
input: z.infer<T>;
id: string;
companions: Map<string, string>;
sendQuery: (query: Query) => Promise<QueryResult>;
companionAgent: CompanionAgent;
}) => Promise<Output> | Output;
}
FieldTypeDescription
idstringTool unique identifier
descriptionstringTool description for LLM
inputSchemaZodTypeAnyInput schema (Zod)
topic"actions" | "messages"Publication topic
publishfunctionMessage generator
PropertyTypeDescription
inputz.infer<T>Input from schema
idstringCompanion’s ID
companionsMap<string, string>Connected companions
sendQueryfunctionQuery sender
companionAgentCompanionAgentAgent instance
type Output = Action | Message;
  • Message: Conversational messages between companions
  • Action: Notification actions for clients

speakTool (Conversational Message Transmission)

Section titled “speakTool (Conversational Message Transmission)”

The most basic Action tool that transmits conversational messages between companions.

import { randomUUID } from "node:crypto";
export const speakTool = createCompanionAction({
id: "speak",
description: "Speak.",
inputSchema: z.object({
message: z.string(),
to: z
.array(z.string())
.describe(
"Recipient of this message. Always specify the companion's ID. " +
"Include all companions who participated unless addressing " +
"specific ones. Actively involve users in conversations."
),
emotion: z.enum(["happy", "sad", "angry", "neutral"]),
}),
topic: "messages",
publish: async ({ input, id, sendQuery }) => {
const queryId = randomUUID();
const query: Query = {
jsonrpc: "2.0",
id: queryId,
method: "query.send",
params: {
from: id,
type: "speak",
body: { message: input.message, emotion: input.emotion },
},
};
await sendQuery(query);
return {
jsonrpc: "2.0",
method: "message.send",
params: {
id: randomUUID(),
from: id,
to: input.to,
message: input.message,
metadata: { emotion: input.emotion },
},
};
},
});

Operation:

  1. Obtains message, to, and emotion from the input
  2. Generates and sends a Query with type: "speak" to the client (used for voice synthesis, etc.)
  3. Generates data in the Message type format
  4. Publishes to the messages topic

The created Action tool should be registered under the actions field of the CompanionCard.

export const companionCard: CompanionCard = {
metadata: { /* ... */ },
role: "...",
actions: {
speakTool,
lightControlAction
},
knowledge: { /* ... */ },
events: { /* ... */ }
};