Overview

This example demonstrates how to use Anthropic’s Function Calling with Gbox to create an AI assistant that can execute Python code based on user queries.

How It Works

  1. User Input - User asks a natural language question
  2. AI Analysis - Claude determines if code execution is needed
  3. Code Generation - AI generates Python code using the execute_python function
  4. Code Execution - Gbox executes the code and returns results
  5. Result Integration - AI incorporates results into the final response

Use Cases

  • Data Analysis & Visualization - Process and display data
  • Mathematical Problem Solving - Solve complex computational problems
  • Interactive Code Generation - Real-time code generation and execution

Implementation Example

Step 1: Create the File

Copy the following code locally and create a new file named index.ts:

import Anthropic from "@anthropic-ai/sdk";
import GboxSDK from "gbox-sdk";
import * as dotenv from "dotenv";

dotenv.config();

// ==================== Initialize Clients ====================
const gboxSDK = new GboxSDK({
  apiKey: process.env["GBOX_API_KEY"],
});

const anthropicClient = new Anthropic({
  apiKey: process.env["ANTHROPIC_API_KEY"],
});

// ==================== Type Definitions ====================
interface ToolExecutionResult {
  success: boolean;
  result: string;
}

// ==================== Configuration Constants ====================
const DEFAULT_QUESTION =
  "Please calculate the first 20 terms of the Fibonacci sequence and create a simple chart to visualize the growth trend";

// ==================== Utility Functions ====================

/**
 * Get user question from command line arguments or use default
 */
function getUserQuestion(): string {
  const args = process.argv.slice(2);

  if (args.length > 0) {
    const userQuestion = args.join(" ").trim();
    if (userQuestion) {
      console.info(`📝 Using user question: "${userQuestion}"`);
      return userQuestion;
    }
  }

  console.info(`📝 Using default question: "${DEFAULT_QUESTION}"`);
  return DEFAULT_QUESTION;
}

/**
 * Create initial conversation messages
 */
const createInitialMessages = (question: string): Anthropic.MessageParam[] => [
  {
    role: "user",
    content: question,
  },
];

/**
 * Define available functions for function calling
 */
const createTools = (): Anthropic.Tool[] => [
  {
    name: "execute_python",
    description:
      "Execute Python code in a Linux environment and return results from stdout/stderr streams",
    input_schema: {
      type: "object",
      properties: {
        code: {
          type: "string",
          description:
            "The Python code to execute. Results will be captured from standard output and standard error streams.",
        },
      },
      required: ["code"],
    },
  },
];

// ==================== Core Execution Functions ====================

/**
 * Execute Python code using Gbox
 */
async function executePythonCode(code: string): Promise<ToolExecutionResult> {
  const box = await gboxSDK.create({ type: "linux" });

  try {
    console.info("📝 Executing Python code:");
    console.log(code);
    console.info("─".repeat(50));

    const execution = await box.runCode(code);
    const result = execution.stdout || execution.stderr || "No output";

    console.info("✅ Execution result:");
    console.log(result);
    console.info("─".repeat(50));

    return {
      success: true,
      result,
    };
  } catch (error) {
    const errorMessage = `Error: ${error}`;
    console.error("❌ Execution failed:", errorMessage);

    return {
      success: false,
      result: errorMessage,
    };
  } finally {
    await box.terminate();
  }
}

/**
 * Process function calls from Anthropic response
 */
async function processToolUse(
  toolUseBlocks: Anthropic.ToolUseBlock[],
  messages: Anthropic.MessageParam[]
): Promise<void> {
  for (const toolUse of toolUseBlocks) {
    if (toolUse.name === "execute_python") {
      try {
        const { code } = toolUse.input as { code: string };
        const executionResult = await executePythonCode(code);

        // Add function result to conversation
        messages.push({
          role: "user",
          content: [
            {
              type: "tool_result",
              tool_use_id: toolUse.id,
              content: executionResult.result,
            },
          ],
        });
      } catch (parseError) {
        console.error("❌ Failed to parse function arguments:", parseError);

        messages.push({
          role: "user",
          content: [
            {
              type: "tool_result",
              tool_use_id: toolUse.id,
              content: `Error parsing arguments: ${parseError}`,
            },
          ],
        });
      }
    }
  }
}

/**
 * Generate Anthropic message
 */
async function generateMessage(
  messages: Anthropic.MessageParam[],
  tools?: Anthropic.Tool[]
): Promise<Anthropic.Message> {
  const response = await anthropicClient.messages.create({
    model: "claude-3-5-sonnet-20241022",
    max_tokens: 4000,
    messages,
    ...(tools && { tools }),
  });

  return response;
}

// ==================== Main Execution Flow ====================

/**
 * Main function - orchestrates the entire execution flow
 */
async function main(): Promise<void> {
  try {
    console.info("🚀 Starting Anthropic + Gbox integration");
    console.info("═".repeat(50));

    const userQuestion = getUserQuestion();
    const messages = createInitialMessages(userQuestion);
    const tools = createTools();

    // Get initial response from Anthropic
    console.info("💬 Getting initial response from Anthropic...");
    const initialResponse = await generateMessage(messages, tools);

    // Add assistant message to conversation
    messages.push({
      role: "assistant",
      content: initialResponse.content,
    });

    // Check if there are function call blocks
    const toolUseBlocks = initialResponse.content.filter(
      (block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
    );

    if (toolUseBlocks.length > 0) {
      console.info(`🔧 Processing ${toolUseBlocks.length} function call(s)...`);
      await processToolUse(toolUseBlocks, messages);

      // Generate final response after function execution
      console.info("💬 Getting final response from Anthropic...");
      const finalResponse = await generateMessage(messages);

      console.info("🎉 Final response:");
      console.info("═".repeat(50));

      for (const content of finalResponse.content) {
        if (content.type === "text") {
          console.log(content.text);
        }
      }
    } else {
      console.info("🎉 Response (no functions called):");
      console.info("═".repeat(50));

      for (const content of initialResponse.content) {
        if (content.type === "text") {
          console.log(content.text);
        }
      }
    }
  } catch (error) {
    console.error("💥 Application error:", error);
    process.exit(1);
  }
}

// ==================== Help Information ====================

/**
 * Display usage instructions
 */
if (process.argv.includes("--help") || process.argv.includes("-h")) {
  console.log(`
🤖 Anthropic Claude + Gbox Cloud Integration Tool

Usage:
  npx tsx index.ts [question]

Examples:
  npx tsx index.ts
  # Uses default question: "${DEFAULT_QUESTION}"

  npx tsx index.ts "Write a Python function to sort a list"
  # Uses custom question

  npx tsx index.ts "Calculate prime numbers"
  # Works with any natural language question

Options:
  --help, -h    Show this help message
    `);
  process.exit(0);
}

// Launch the application
main();

Step 2: Run the Code

Execute the following commands to run the code:

# Use default question
npx tsx index.ts

# Use custom question
npx tsx index.ts "your question here"