Anthropic tool use

Operations

Tool definitions for the Claude Messages API.

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();
const KEY    = process.env.MYAGENTMAIL_KEY!;
const API    = "https://myagentmail.com/v1";

async function mam(method: string, path: string, body?: unknown) {
  const r = await fetch(`${API}${path}`, {
    method,
    headers: { "X-API-Key": KEY, "Content-Type": "application/json" },
    body: body ? JSON.stringify(body) : undefined,
  });
  if (!r.ok) throw new Error(`${method} ${path} → ${r.status}`);
  return r.json();
}

const tools: Anthropic.Tool[] = [
  {
    name: "create_inbox",
    description: "Provision a new myagentmail inbox.",
    input_schema: {
      type: "object",
      properties: {
        username:    { type: "string" },
        displayName: { type: "string" },
      },
    },
  },
  {
    name: "send_email",
    description: "Send an email from an inbox. Set verified=true if you've validated the address.",
    input_schema: {
      type: "object",
      required: ["inboxId", "to", "subject", "plainBody"],
      properties: {
        inboxId:   { type: "string" },
        to:        { type: "string" },
        subject:   { type: "string" },
        plainBody: { type: "string" },
        verified:  { type: "boolean", default: true },
      },
    },
  },
];

async function runTool(name: string, input: any) {
  if (name === "create_inbox") return mam("POST", "/inboxes", input);
  if (name === "send_email") {
    return mam("POST", `/inboxes/${input.inboxId}/send`, {
      to: input.to,
      subject: input.subject,
      plainBody: input.plainBody,
      verified: input.verified ?? true,
    });
  }
  throw new Error(`unknown tool: ${name}`);
}

// Standard tool-use loop
let messages: Anthropic.MessageParam[] = [
  { role: "user", content: "Create an inbox 'sales-bot' and send a hello to [email protected]." },
];
while (true) {
  const res = await client.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 4096,
    tools,
    messages,
  });
  messages.push({ role: "assistant", content: res.content });
  if (res.stop_reason !== "tool_use") break;

  const toolResults: Anthropic.ToolResultBlockParam[] = [];
  for (const block of res.content) {
    if (block.type !== "tool_use") continue;
    const result = await runTool(block.name, block.input);
    toolResults.push({
      type: "tool_result",
      tool_use_id: block.id,
      content: JSON.stringify(result),
    });
  }
  messages.push({ role: "user", content: toolResults });
}