Skip to content

Conversation

@ryoppippi
Copy link
Member

@ryoppippi ryoppippi commented Aug 6, 2025

Summary

This PR introduces meta tools functionality to enable dynamic tool discovery and execution in the StackOne AI SDK. Meta tools allow AI agents to search for relevant tools using natural language queries and execute them without hardcoding tool names.

Note: This implementation is based on the learnings from #77 and addresses the issues encountered in that PR.

Features Added

🔍 Meta Tools (Beta)

  • meta_filter_relevant_tools: Discovers relevant tools using natural language queries with BM25 relevance ranking
  • meta_execute_tool: Executes discovered tools dynamically with provided parameters

Key Improvements

  • Uses Orama's BM25 algorithm for high-quality relevance ranking
  • Supports filtering by minimum relevance score
  • Provides both OpenAI and AI SDK format compatibility
  • Includes comprehensive test coverage

Implementation Details

Tool Discovery

  • Indexes all available tools using Orama search engine
  • Extracts categories and action types from tool names for better search
  • Returns tools with relevance scores for transparency

Developer Experience

  • Simple API: await tools.metaTools() to get meta tools
  • Works seamlessly with existing OpenAI and AI SDK integrations
  • No authentication complexity - uses existing toolset authentication

Testing

  • ✅ Unit tests for both meta tools
  • ✅ Integration tests for the complete workflow
  • ✅ Format conversion tests (OpenAI and AI SDK)
  • ✅ Example implementations provided

Documentation

  • Added comprehensive documentation to README with beta warning
  • Created detailed examples in examples/meta-tools.ts
  • Included usage patterns for both AI-assisted and direct usage

Beta Status

These features are marked as beta as the API may evolve based on user feedback. The core functionality is stable and well-tested.

Example Usage

// Get meta tools
const metaTools = await tools.metaTools();

// Use with AI SDK
const aiSdkTools = metaTools.toAISDK();
const { text } = await generateText({
  model: openai("gpt-4o-mini"),
  tools: aiSdkTools,
  prompt: "Find tools for managing employees",
});

Test Plan

  • Run all unit tests: bun run test:unit
  • Test examples work correctly
  • Verify OpenAI format compatibility
  • Verify AI SDK format compatibility
  • Check relevance scoring accuracy

Summary by cubic

Added meta tools for dynamic tool discovery and execution, allowing agents to search for relevant tools using natural language and run them without hardcoding tool names.

  • New Features
    • Added meta_filter_relevant_tools for searching tools with BM25 relevance ranking.
    • Added meta_execute_tool for running discovered tools dynamically.
    • Included full parameter schemas in search results for compatibility with OpenAI and SDK formats.
    • Added documentation, examples, and comprehensive tests for meta tools.

… execution

- Add metaTools() method to Tools class for getting meta tools

- Implement meta_filter_relevant_tools using Orama BM25 search algorithm

- Implement meta_execute_tool for dynamic tool execution

- Fix async initialization of Orama database

- Add MetaToolSearchResult interface for type safety

- Include tool configurations in search results for LLM usage

- Add comprehensive documentation comments and JSDoc

BREAKING CHANGE: metaRelevantTools() renamed to metaTools() and now returns Promise<Tools>
- Add meta_filter_relevant_tools for searching tools using Orama BM25

- Add meta_execute_tool for executing discovered tools dynamically

- Filter tool returns full parameter schemas for LLM usage

- Use synchronous Orama initialization (not async)
- AI SDK integration example with dynamic tool discovery

- OpenAI integration example for agent workflows

- Direct usage example without AI frameworks

- Dynamic tool router pattern for flexible workflows
- Add beta warning for meta tools feature

- Explain how meta tools enable dynamic tool discovery

- Provide usage examples with AI SDK and OpenAI

- Document the workflow and benefits
Copilot AI review requested due to automatic review settings August 6, 2025 18:54
@pkg-pr-new
Copy link

pkg-pr-new bot commented Aug 6, 2025

Open in StackBlitz

npm i https://pkg.pr.new/StackOneHQ/stackone-ai-node/@stackone/ai@84

commit: 66503e2

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces meta tools functionality to enable dynamic tool discovery and execution in the StackOne AI SDK. Meta tools allow AI agents to search for relevant tools using natural language queries and execute them without hardcoding tool names. This feature uses Orama's BM25 algorithm for high-quality tool relevance ranking.

  • Adds meta_filter_relevant_tools for discovering relevant tools using natural language queries
  • Adds meta_execute_tool for executing discovered tools dynamically with provided parameters
  • Implements comprehensive test coverage and example usage patterns

Reviewed Changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/tool.ts Implements meta tools functionality with Orama BM25 search for tool discovery and dynamic execution
src/tests/meta-tools.spec.ts Comprehensive test suite covering meta tools functionality, format conversion, and integration workflows
package.json Adds Orama dependency for BM25 search functionality
mocks/handlers.ts Adds mock HTTP handlers for meta tools testing
examples/meta-tools.ts Detailed examples demonstrating meta tools usage with AI SDK, OpenAI, and direct usage patterns
README.md Documents meta tools functionality with beta warning and usage examples
.mcp.json Adds Orama documentation reference for development

const results = await orama.search(oramaDb, {
term: params.query || '',
limit: params.limit || 5,
} as Parameters<typeof orama.search>[1]);
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type assertion as Parameters<typeof orama.search>[1] should be avoided. Consider creating a proper interface for the search parameters or using a more explicit type definition.

Suggested change
} as Parameters<typeof orama.search>[1]);
} as OramaSearchParams);

Copilot uses AI. Check for mistakes.
};
return result;
})
.filter(Boolean);
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using .filter(Boolean) can be unclear. Consider using an explicit filter function like .filter((result): result is MetaToolSearchResult => result !== null) for better type safety and readability.

Suggested change
.filter(Boolean);
.filter((result): result is MetaToolSearchResult => result !== null);

Copilot uses AI. Check for mistakes.
const atsTools = toolset.getStackOneTools('ats_*', accountId);

// Combine tools
const combinedTools = new (await import('../src')).Tools([
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dynamic import inside a function creates unclear dependencies. Consider importing Tools at the top of the file for better readability and static analysis.

Suggested change
const combinedTools = new (await import('../src')).Tools([
const combinedTools = new Tools([

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cubic analysis

3 issues found across 8 files • Review in cubic

React with 👍 or 👎 to teach cubic. You can also tag @cubic-dev-ai to give feedback, ask questions, or re-run the review.

async function initializeOramaDb(tools: BaseTool[]): Promise<OramaDb> {
// Create Orama database schema with BM25 scoring algorithm
// BM25 provides better relevance ranking for natural language queries
const oramaDb = orama.create({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The result of orama.create is never awaited, so a promise is treated as the database instance and later passed to orama.search, which will throw at runtime.

Prompt for AI agents
Address the following comment on src/tool.ts at line 346:

<comment>The result of `orama.create` is never awaited, so a promise is treated as the database instance and later passed to `orama.search`, which will throw at runtime.</comment>

<file context>
@@ -309,3 +321,223 @@ export class Tools implements Iterable&lt;BaseTool&gt; {
     this.tools.forEach(callback);
   }
 }
+
+/**
+ * Result from meta_filter_relevant_tools
+ */
+export interface MetaToolSearchResult {
+  name: string;
</file context>
Suggested change
const oramaDb = orama.create({
const oramaDb = await orama.create({

http.get('https://api.example.com/hris/employees', ({ request }) => {
const url = new URL(request.url);
const limit = url.searchParams.get('limit');
return HttpResponse.json({ limit: limit ? Number(limit) : undefined });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the query parameter "limit" is "0" the truthiness check treats it as falsy, so the handler incorrectly returns undefined instead of 0; use an explicit null-check instead.

Prompt for AI agents
Address the following comment on mocks/handlers.ts at line 51:

<comment>If the query parameter &quot;limit&quot; is &quot;0&quot; the truthiness check treats it as falsy, so the handler incorrectly returns undefined instead of 0; use an explicit null-check instead.</comment>

<file context>
@@ -39,6 +39,39 @@ export const handlers = [
     });
   }),
 
+  // Meta tools test endpoints
+  http.post(&#39;https://api.example.com/hris/employees&#39;, async ({ request }) =&gt; {
+    const body = await request.json();
+    return HttpResponse.json(body);
+  }),
+  
</file context>
Suggested change
return HttpResponse.json({ limit: limit ? Number(limit) : undefined });
return HttpResponse.json({ limit: limit !== null ? Number(limit) : undefined });

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Copy link
Contributor

@mattzcarey mattzcarey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ryoppippi ryoppippi merged commit e1da427 into main Aug 8, 2025
7 checks passed
@ryoppippi ryoppippi deleted the meta-tools-2 branch August 8, 2025 10:55
@ryoppippi
Copy link
Member Author

merged!!!

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.

3 participants