Skip to content

Conversation

@bjoaquinc
Copy link
Contributor

@bjoaquinc bjoaquinc commented Sep 30, 2025

📝 Summary

Create frontend tools framework to manage and send tools to backend via ai body. Update openapi to include ToolDefinition in body. Remove any frontend tool handing from ToolManager.

Screenshot 2025-09-29 at 9 12 24 PM

🔍 Description of Changes

  • Create frontend tool registry to handle registering and invoking tools from the frontend in registry.ts
  • Add BaseTool to handle frontend tool shape validation and centralize logic in base.ts
  • Handle zod v4 collision in tsconfig.json
  • Add sample tools as example of how to create a frontend tool (maybe remove before merge?)
  • Send back frontend tools via body in chat-panel.tsx
  • Update invokeAiTool to handle frontend tools if in list in chat-utils.ts
  • Add ToolDefinition to ChatRequest body and OpenAPI schemas
  • Inject tools through stream_completion if tools is avaliable in ai.py and providers.py
  • Remove all left over frontend tool logic and handling in tool_manager.py

📋 Checklist

  • I have read the contributor guidelines.
  • For large changes, or changes that affect the public API: this change was discussed or approved through an issue, on Discord, or the community discussions (Please provide a link if applicable).
  • I have added tests for the changes made.
  • I have run the code and verified that it works as expected.

Note

Introduce a frontend tools framework and pass tool schemas through chat requests to providers, while removing frontend-tool handling from the backend and updating OpenAPI/types.

  • Frontend:
    • Tools Framework: Add AiTool interface (base.ts), FrontendToolRegistry with zod validation and memoized schemas (registry.ts), and a sample tool (sample-tool.ts); add tests for registry behavior.
    • Chat Integration: Send FRONTEND_TOOL_REGISTRY.getToolSchemas() in chat request body and handle frontend tool calls client-side before falling back to backend (chat-panel.tsx, chat-utils.ts).
    • Config: Pin zod path in tsconfig.json.
  • Backend:
    • Providers: Extend stream_completion to accept additional_tools and merge with configured tools for OpenAI, Anthropic, Google, and Bedrock (providers.py).
    • Endpoints: Pass body.tools to providers in POST /api/ai/chat; no tools for completion/inline completion (ai.py).
    • ToolManager: Drop frontend tool registration/lookup; warn on frontend source requests; simplify init log; tighten error messages (tool_manager.py).
  • API/OpenAPI:
    • Add ToolDefinition schema and include optional tools in ChatRequest; regenerate TS types (api.yaml, src/api.ts).
    • Include ToolDefinition in dev OpenAPI generation (commands.py).
  • Tests:
    • Update provider tests to new stream_completion signature (test_providers.py).

Written by Cursor Bugbot for commit d7836e8. This will update automatically on new commits. Configure here.

@vercel
Copy link

vercel bot commented Sep 30, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
marimo-docs Ready Ready Preview Comment Oct 1, 2025 0:44am

@github-actions github-actions bot added the bash-focus Area to focus on during release bug bash label Sep 30, 2025
export const FRONTEND_TOOL_REGISTRY = new FrontendToolRegistry();

/* Register all the frontend tools */
FRONTEND_TOOL_REGISTRY.registerAll([
Copy link
Contributor

Choose a reason for hiding this comment

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

could we put this in the constructor (instead of register), then we can confidently do @Memoize on the.getToolSchemas function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

return this.tools.has(toolName);
}

private getTool(toolName: string): StoredTool {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: getToolOrThrow if it may throw

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

TIn extends AnyZodObject,
TOut extends AnyZodObject,
> {
public readonly name: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

this does not do much being abstract, and instead could just be an interface that others implement

export class MyTool implement AiTool {
   public readonly name = "run"
   public readonly schema = z.object()
....
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done!

});
if (FRONTEND_TOOL_REGISTRY.has(toolCall.toolName)) {
// Invoke the frontend tool
const response = await FRONTEND_TOOL_REGISTRY.invoke(
Copy link
Contributor

Choose a reason for hiding this comment

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

should we validate the mode here? or not needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think its needed since it's already hard typed. I'm more worried about the CopilotMode type in the frontend going out of sync with the backend.

/** should be the same as marimo/_config/config.py > CopilotMode */
export type CopilotMode = "manual" | "ask";

export interface FrontendToolDefinition {
Copy link
Contributor

Choose a reason for hiding this comment

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

you could grab this from import type { components } from "@marimo-team/marimo-api"; or at least extend it:

export interface FrontendToolDefinition extends ToolDefinition {
  source: "frontend";
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done! I was looking for something like this thanks

Copy link
Contributor Author

@bjoaquinc bjoaquinc Sep 30, 2025

Choose a reason for hiding this comment

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

@mscolnick can we also do this with CopilotMode?

Copy link
Contributor

Choose a reason for hiding this comment

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

yep we can as well (but less worried it will get out of sync)

/** All registered tools */
private tools = new Map<string, StoredTool>();

registerAll<TIn extends AnyZodObject, TOut extends AnyZodObject>(
Copy link
Contributor

Choose a reason for hiding this comment

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

you could simplify this to:

constructor() {
  this.tools = new Map(tools.map(tool => [tool.id, tool])
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done! Nice we were able to get rid of registerAll() and register()

mscolnick
mscolnick previously approved these changes Sep 30, 2025
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

if tools:
create_params["tools"] = convert_to_openai_tools(tools)
all_tools = tools + additional_tools
create_params["tools"] = convert_to_openai_tools(all_tools)
Copy link

Choose a reason for hiding this comment

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

Bug: Frontend Tools Ignored When Backend Tools Unconfigured

Frontend tools (additional_tools) are not sent to the AI provider when backend tools (self.config.tools) are not configured. The if tools: condition prevents additional_tools from being included, which means frontend tools are ignored. This impacts OpenAIProvider, AnthropicProvider, GoogleProvider, and BedrockProvider.

Additional Locations (3)

Fix in Cursor Fix in Web

@mscolnick mscolnick merged commit 47bf570 into marimo-team:main Oct 1, 2025
27 of 39 checks passed
@bjoaquinc bjoaquinc deleted the frontend-framework branch October 5, 2025 14:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bash-focus Area to focus on during release bug bash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants