Skip to content

Conversation

@fav-devs
Copy link
Contributor

@fav-devs fav-devs commented Sep 30, 2025

Overview

Adds a simplified approach for exposing agent tools as HTTP endpoints. Instead of requiring separate functions or decorators, tools can now be exposed as endpoints by simply adding an optional endpoint parameter to the existing createTool() function.

Key Features

  • Simple Toggle Pattern: Just add endpoint: { enabled: true } to any tool
  • OFF by Default: Endpoints are disabled unless explicitly enabled for security
  • Backward Compatible: Existing tools without endpoint config work unchanged
  • Flexible Control: Support for environment variables, feature flags, conditional logic
  • Advanced Options: Custom paths, methods, auth, rate limiting, response transformers
  • Consistent API: Aligned with agent endpoint pattern (/tools/{id} matching /agents/{id}/...)

Changes

Core Implementation

  • Added ToolEndpointConfig interface for endpoint configuration
  • Added optional endpoint parameter to ToolOptions<T>
  • Added endpoint property to Tool class
  • Added methods: canBeEndpoint(), toEndpoint(), getEndpointInfo()
  • Added utility functions: generateEndpointsFromTools(), createBatchEndpoint(), createListingEndpoint()
  • Fixed tool wrapping in agent to preserve instance methods
  • Fixed tool spreading in reasoning tools

API Endpoints

  • POST /tools/{toolName} - Execute tool with JSON body
  • GET /tools/{toolName} - Execute via query params (if supportsGet: true)
  • POST /tools/batch - Execute multiple tools in a single request
  • GET /tools - List all available tools and their schemas

Documentation

  • Added comprehensive documentation in docs/tool-endpoints.md
  • Created working example in examples/simple-tool-endpoints/
  • Demonstrates 6 different use cases and control mechanisms

Example Usage

import { createTool, generateEndpointsFromTools } from "@voltagent/core";
import { z } from "zod";

// Regular tool (no endpoint)
const internalTool = createTool({
  name: "internalCalculation",
  description: "Internal calculation tool",
  parameters: z.object({ value: z.number() }),
  execute: async ({ value }) => ({ result: value * 2 }),
  // No endpoint config = no HTTP endpoint
});

// Tool with endpoint enabled
const publicTool = createTool({
  name: "calculator",
  description: "Perform mathematical calculations",
  parameters: z.object({
    operation: z.enum(["add", "subtract", "multiply", "divide"]),
    a: z.number(),
    b: z.number(),
  }),
  execute: async ({ operation, a, b }) => {
    const operations = {
      add: a + b,
      subtract: a - b,
      multiply: a * b,
      divide: a / b,
    };
    return { result: operations[operation] };
  },
  endpoint: {
    enabled: true, // Just toggle it on!
  },
});

// Generate endpoints
const endpoints = generateEndpointsFromTools([internalTool, publicTool], {
  basePath: "/tools",
  includeBatch: true,
  includeListing: true,
});

// Start VoltAgent with custom endpoints
new VoltAgent({
  agents: { agent },
  customEndpoints: endpoints,
});

Testing

  • TypeScript build: ✅ PASSING
  • Runtime tests: ✅ PASSING
  • Example server: ✅ WORKING
  • Endpoint functionality verified with Node.js fetch

Migration

Existing tools continue to work unchanged. To add endpoints:

// Before: Regular tool
const tool = createTool({
  name: "myTool",
  // ... config
});

// After: Same tool with endpoint
const tool = createTool({
  name: "myTool",
  // ... config
  endpoint: { enabled: true }, // Just add this!
});

No breaking changes. No refactoring required.

Commits

  • d31687bd - feat(tools): add simple endpoint toggle to createTool
  • 5343f8d5 - refactor(tools): update endpoint paths from /api/tools to /tools
  • 3a8028d9 - fix(agent): preserve tool instance methods when wrapping execute

@changeset-bot
Copy link

changeset-bot bot commented Sep 30, 2025

⚠️ No Changeset found

Latest commit: ce87b1c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@fav-devs fav-devs closed this Sep 30, 2025
@omeraplak omeraplak added good first issue Good for newcomers and removed good first issue Good for newcomers labels Sep 30, 2025
@omeraplak
Copy link
Member

Hey @fav-devs , thanks a lot for the PR! I think we could directly expose the tools of the agents registered in AgentRegistry.getInstance(). That way, users wouldn’t need to write bootstrap code. If you need any help, please feel free to reach out. I’d be happy to provide more details.

@fav-devs fav-devs reopened this Sep 30, 2025
@fav-devs
Copy link
Contributor Author

fav-devs commented Sep 30, 2025

✅ Branch History Cleaned!

The branch has been rebased on the latest main and now contains only the 3 relevant commits for the tool endpoints feature:

Tool Endpoint Feature Commits:

  1. 9369a282 - feat(tools): add simple endpoint toggle to createTool
  2. bceb0ae6 - refactor(tools): update endpoint paths from /api/tools to /tools
  3. a346d60d - fix(agent): preserve tool instance methods when wrapping execute

The old unrelated commits from the gemini_TTS branch have been removed. The PR is now ready for review with a clean history!


About Auto-Discovery

Regarding your suggestion about auto-discovery from AgentRegistry - I noticed that the architecture has changed significantly in v1.0. The old customEndpoints pattern has been replaced with the configureApp callback in server providers.

I'd like to discuss the best approach for auto-discovery in the new architecture:

Option 1: Server Provider Integration

import { honoServer } from "@voltagent/server-hono";
import { generateToolEndpoints } from "@voltagent/core";

new VoltAgent({
  agents: { agent },
  server: honoServer({
    port: 3141,
    configureApp: (app) => {
      // Auto-generate tool endpoints
      const endpoints = generateToolEndpoints(agentRegistry);
      endpoints.forEach(endpoint => {
        app[endpoint.method](endpoint.path, endpoint.handler);
      });
    },
  }),
});

Option 2: Built-in Server Provider Option

new VoltAgent({
  agents: { agent },
  server: honoServer({
    port: 3141,
    enableToolEndpoints: true, // Auto-discover and register
  }),
});

Which approach would you prefer? Or do you have a different pattern in mind for the new architecture?

@fav-devs fav-devs force-pushed the simplified-tool-endpoints branch from 837573a to a346d60 Compare September 30, 2025 15:27
- add optional endpoint configuration to Tool class
- endpoints are OFF by default for security
- simple toggle pattern: endpoint: { enabled: true }
- support for custom paths, methods, auth, rate limiting
- add generateEndpointsFromTools utility function
- add batch and listing endpoint generators
- fix tool spreading in reasoning tools
- add complete documentation and working example
- backward compatible with existing tools
- change default basePath from /api/tools to /tools
- update all documentation and examples
- align with agent endpoint pattern (/agents/{id}/...)
- maintain consistency across API surface
- use Object.assign with prototype to maintain tool class methods
- fixes TypeScript build errors for canBeEndpoint, toEndpoint, getEndpointInfo
- wrapped tools now retain all Tool class functionality
- resolves DTS generation failures
@fav-devs fav-devs force-pushed the simplified-tool-endpoints branch from 2985b6b to ce87b1c Compare September 30, 2025 22:44
@fav-devs
Copy link
Contributor Author

Please check it now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants