← Selected work
AI Agent · Project 1

Calendar Scheduling Agent

Agentic loop that schedules meetings from natural language. The first project — understanding how the LLM decides, tools execute, and the loop continues until the goal is reached.

Node.js · React · Anthropic Claude GitHub ↗
New Concept This Project
while(stop_reason === "tool_use") — the agentic loop. LLM decides which tool to call. Your code executes it. Results feed back. Loop repeats until goal is reached.

System Prompt

Sent to Claude on every turn. Defines the agent's personality and rules.

system
You are a calendar scheduling assistant.
Today's date is [today's date].

When the user asks to schedule a meeting:
1. ALWAYS call check_availability first
2. If slot is available → call schedule_event
3. If not available → suggest alternatives
4. Confirm once booked

Be concise and helpful.

Tool Definitions

Sent to Claude on every turn. The LLM reads these and decides when to call each one.

tools
[
  {
    "name": "check_availability",
    "description": "Check if a time slot is available on the calendar",
    "input_schema": {
      "type": "object",
      "properties": {
        "date":       { "type": "string", "description": "Date YYYY-MM-DD" },
        "start_time": { "type": "string", "description": "Start time HH:MM" },
        "end_time":   { "type": "string", "description": "End time HH:MM" }
      },
      "required": ["date", "start_time", "end_time"]
    }
  },
  {
    "name": "schedule_event",
    "description": "Book a meeting on the calendar once availability confirmed",
    "input_schema": {
      "type": "object",
      "properties": {
        "title":      { "type": "string" },
        "date":       { "type": "string" },
        "start_time": { "type": "string" },
        "end_time":   { "type": "string" },
        "attendees":  { "type": "array", "items": { "type": "string" } }
      },
      "required": ["title", "date", "start_time", "end_time"]
    }
  }
]

End-to-End Flow

User types a natural language request. The agent runs through multiple turns until the goal is achieved.

👤 User Input
"Schedule a standup tomorrow at 10am"
🤖 LLM Request — Turn 1
POST anthropic/v1/messages
{
  "model":   "claude-sonnet-4-6",
  "system":  "...system prompt above...",
  "tools":   [...2 tool definitions...],
  "messages": [
    {
      "role":    "user",
      "content": "Schedule a standup tomorrow at 10am"
    }
  ]
}
🧠 LLM Response — Turn 1
{
  "stop_reason": "tool_use",
  "content": [
    {
      "type": "text",
      "text": "Let me check if that time is available."
    },
    {
      "type":  "tool_use",
      "id":    "tool_001",
      "name":  "check_availability",
      "input": {
        "date":       "2026-07-27",
        "start_time": "10:00",
        "end_time":   "10:30"
      }
    }
  ],
  "usage": { "input_tokens": 320, "output_tokens": 75 }
}
stop_reason: "tool_use" → loop continues. LLM decided to call check_availability — your code executes it.
🔧 Tool Execution (your code)
executeTool("check_availability", input)
// Your code checks the calendar
result = { available: true, slot: "10:00–10:30" }
🤖 LLM Request — Turn 2
messages[] grows — full history sent every turn
{
  "messages": [
    { "role": "user",      "content": "Schedule a standup tomorrow at 10am" },
    { "role": "assistant", "content": [ ...tool_use block... ] },
    {
      "role": "user",
      "content": [{
        "type":        "tool_result",
        "tool_use_id": "tool_001",
        "content":     "{ \"available\": true }"
      }]
    }
  ]
}
🧠 LLM Response — Turn 2
{
  "stop_reason": "tool_use",
  "content": [{
    "type":  "tool_use",
    "id":    "tool_002",
    "name":  "schedule_event",
    "input": {
      "title":      "Standup",
      "date":       "2026-07-27",
      "start_time": "10:00",
      "end_time":   "10:30"
    }
  }],
  "usage": { "input_tokens": 480, "output_tokens": 90 }
}
🧠 LLM Response — Turn 3 (Final)
{
  "stop_reason": "end_turn",
  "content": [{
    "type": "text",
    "text": "Your standup is booked for tomorrow at 10:00–10:30 AM. ✅"
  }],
  "usage": { "input_tokens": 620, "output_tokens": 28 }
}
stop_reason: "end_turn" → loop exits. 3 turns. 2 tools. Goal achieved.
Key Insight — messages[] is memory

The LLM has no memory between API calls. Every turn you send the entire conversation history. The messages[] array IS the agent's memory. Remove it → Claude forgets everything.

Token Cost

Turn
Input
Output
Cost
Turn 1
320
75
$0.0000022
Turn 2
480
90
$0.0000029
Turn 3
620
28
$0.0000025
Total
1,420
193
~$0.000008