Krzysztof Woś 276d4f6e84 fix(code-interpreter): three correctness fixes for the TwentyMCP helper + tool output shape (#20103)
## Summary

Three independently-useful correctness fixes for the `code_interpreter`
tool, all surfaced while standing up a self-hosted code interpreter
against MCP. Each is isolated to one bug and applies regardless of
`CODE_INTERPRETER_TYPE`.

### 1. UI: unwrap `execute_tool` envelope when rendering
`code_interpreter` output

When `code_interpreter` is invoked through MCP's `execute_tool`
meta-tool, the result arrives wrapped: `{success, result: {stdout,
exitCode, files, ...}, ...}`. `ToolStepRenderer` reads `exitCode` at the
top level, which is `undefined` → the step renders as "Failed" even on a
clean `exitCode === 0`. Symmetric to the input-side unwrap that already
exists; the fix lifts `outputObj.result` when `rawToolName ===
'execute_tool'`.

### 2. Helper: route `TwentyMCP.call_tool` through `execute_tool` for
catalog tools

The `TwentyMCP` helper injected into every code-interpreter sandbox
exposes a `call_tool(name, arguments)` method. Direct MCP calls only
work for the 5 meta-tools (`get_tool_catalog`, `learn_tools`,
`execute_tool`, `load_skills`, `search_help_center`); the 250+ catalog
tools are accessed through `execute_tool`. Today
`twenty.call_tool('find_companies', {...})` raises "Unknown tool". This
commit detects catalog tools and auto-routes them through
`execute_tool`. It also flattens the nested `{catalog: {category:
[...]}}` shape returned by `list_tools()` and propagates `{success:
false}` envelopes as explicit exceptions (they were being silently
returned as dicts).

### 3. Prompt: stop the agent from hallucinating \`import twenty\`

Despite the helper being pre-injected, models frequently emitted
\`import twenty\` and crashed with \`ModuleNotFoundError\`. Two
contributing sources: the helper docstring did not explicitly say "do
not import," and the code-interpreter skill template's example block
referenced placeholder tool names. Fix: explicit "DO NOT import twenty"
block in the helper + rewritten skill examples using real tool names and
real response shapes.

## Test plan

- [ ] Existing \`code_interpreter\` tests still pass.
- [ ] Run a chat turn that invokes \`code_interpreter\` indirectly via
MCP \`execute_tool\` and confirm the UI no longer flips to "Failed" on
\`exitCode === 0\`.
- [ ] From inside the sandbox, run \`twenty.call_tool('find_companies',
{limit: 5})\` and confirm records return (was raising "Unknown tool").
- [ ] Confirm \`twenty.list_tools()\` returns a flat list, not the
nested \`{catalog: {...}}\` envelope.
- [ ] Trigger a tool error from inside the sandbox and confirm it raises
rather than returning a \`{success: false}\` dict.
- [ ] Ask an LLM to use \`code_interpreter\`; confirm it does not emit
\`import twenty\`.

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2026-05-03 11:16:53 +02:00
2025-08-07 17:02:12 +02:00

Twenty logo

The #1 Open-Source CRM

Website · Documentation · Roadmap · Discord · Figma

Twenty banner


Why Twenty

Twenty gives technical teams the building blocks for a custom CRM that meets complex business needs and quickly adapts as the business evolves. Twenty is the CRM you build, ship, and version like the rest of your stack.

Learn more about why we built Twenty


Installation

Cloud

The fastest way to get started. Sign up at twenty.com and spin up a workspace in under a minute, with no infrastructure to manage and always up to date.

Build an app

Scaffold a new app with the Twenty CLI:

npx create-twenty-app my-app

Define objects, fields, and views as code:

import { defineObject, FieldType } from 'twenty-sdk/define';

export default defineObject({
  nameSingular: 'deal',
  namePlural: 'deals',
  labelSingular: 'Deal',
  labelPlural: 'Deals',
  fields: [
    { name: 'name', label: 'Name', type: FieldType.TEXT },
    { name: 'amount', label: 'Amount', type: FieldType.CURRENCY },
    { name: 'closeDate', label: 'Close Date', type: FieldType.DATE_TIME },
  ],
});

Then ship it to your workspace:

npx twenty deploy

See the app development guide for objects, views, agents, and logic functions.

Self-hosting

Run Twenty on your own infrastructure with Docker Compose, or contribute locally via the local setup guide.



Everything you need

Twenty gives you the building blocks of a modern CRM (objects, views, workflows, and agents) and lets you extend them as code. Here's a tour of what's in the box.

Want to go deeper? Read the User Guide for product walkthroughs, or the Documentation for developer reference.

Create your apps

Learn more about apps in doc

Stay on top with version control

Learn more about version control in doc

All the tools you need to build anything

Learn more about primitives in doc

Customize your layouts

Learn more about layouts in doc

AI agents and chats

Learn more about AI in doc

Plus all the tools of a good CRM

Learn more about CRM features in doc


Stack

Thanks

Chromatic      Greptile      Sentry      Crowdin

Thanks to these amazing services that we use and recommend for UI testing (Chromatic), code review (Greptile), catching bugs (Sentry) and translating (Crowdin).

Join the Community

Star the repo · Discord · Feature requests · Releases · X · LinkedIn · Crowdin · Contribute

S
Description
The open alternative to Salesforce, designed for AI.
Readme AGPL-3.0 1.4 GiB
Languages
TypeScript 79.6%
MDX 17.3%
JavaScript 2.7%
Python 0.2%
SCSS 0.1%