Back to Rivet

Agent-to-Agent Communication

website/src/content/docs/agent-os/agent-to-agent.mdx

2.2.14.0 KB
Original Source

Agents communicate through host tools. You define a toolkit that lets one agent send work to another, and the agent calls it like any other CLI command.

Example: code writer + reviewer

This example creates a writer agent with a review tool. When the writer calls the tool, it reads the file from the writer's VM, writes it to a separate reviewer VM, and sends a review prompt.

<CodeGroup stacked> ```ts @nocheck server.ts import { agentOs } from "rivetkit/agent-os"; import { setup } from "rivetkit"; import common from "@rivet-dev/agent-os-common"; import pi from "@rivet-dev/agent-os-pi"; import { toolKit, hostTool } from "@rivet-dev/agent-os-core"; import { createClient } from "rivetkit/client"; import { z } from "zod";

// Tool that bridges the writer to the reviewer const reviewToolkit = toolKit({ name: "review", description: "Send code to the reviewer agent", tools: { submit: hostTool({ description: "Submit a file for code review", inputSchema: z.object({ path: z.string().describe("Path to the file to review"), }), execute: async (input) => { const client = createClient<typeof registry>("http://localhost:6420"); const writerHandle = client.writer.getOrCreate(["my-project"]); const reviewerHandle = client.reviewer.getOrCreate(["my-project"]);

    // Read file from writer, write to reviewer
    const content = await writerHandle.readFile(input.path);
    await reviewerHandle.writeFile(input.path, content);

    // Ask the reviewer to review
    const session = await reviewerHandle.createSession("pi", {
      env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
    });
    const response = await reviewerHandle.sendPrompt(
      session.sessionId,
      `Review the code at ${input.path} and list any issues.`,
    );
    await reviewerHandle.closeSession(session.sessionId);

    return { review: response };
  },
}),

}, });

// Writer has the review toolkit, reviewer is plain const writer = agentOs({ options: { software: [common, pi], toolKits: [reviewToolkit] }, }); const reviewer = agentOs({ options: { software: [common, pi] }, });

export const registry = setup({ use: { writer, reviewer } }); registry.start();


```ts @nocheck client.ts
import { createClient } from "rivetkit/client";
import type { registry } from "./server";

const client = createClient<typeof registry>("http://localhost:6420");
const writerAgent = client.writer.getOrCreate(["my-project"]);

const session = await writerAgent.createSession("pi", {
  env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});

// The writer will call `agentos-review submit --path /home/user/api.ts`
// when it's ready for a review
await writerAgent.sendPrompt(
  session.sessionId,
  "Write a REST API at /home/user/api.ts, then submit it for review.",
);
</CodeGroup>

The writer agent sees the review tool as a CLI command:

bash
agentos-review submit --path /home/user/api.ts

When the writer calls this, the host tool reads the file from the writer's VM, writes it to the reviewer's VM, and sends a prompt to the reviewer. The review result is returned to the writer as JSON.

Why host tools?

Host tools are the natural communication layer between agents because:

  • The agent doesn't need to know about other agents. It just calls a tool. You can swap the implementation without changing the agent's behavior.
  • No credentials in the VM. The host tool executes on the server, so it can access other agents directly without exposing connection details.
  • Composable. Chain any number of agents by adding more tools. Each tool is a self-contained bridge to another agent.

Recommendations

  • Each agent has its own isolated VM and filesystem. Use readFile/writeFile in host tools to pass files between them.
  • Use Queues when agents need to process work asynchronously.
  • Use Workflows to make multi-agent pipelines durable across restarts.