MCPcopy
hub / github.com/ComposioHQ/composio / _infer_tool_from_function

Function _infer_tool_from_function

python/composio/core/models/custom_tool.py:264–357  ·  view source on GitHub ↗

Create a CustomTool by inferring metadata from a decorated function. - slug: from ``fn.__name__.upper()`` - name: from ``fn.__name__`` humanized - description: from ``fn.__doc__`` - input_params: from the first parameter with a BaseModel type annotation

(
    fn: t.Callable[..., t.Any],
    *,
    slug: t.Optional[str] = None,
    name: t.Optional[str] = None,
    description: t.Optional[str] = None,
    extends_toolkit: t.Optional[str] = None,
    output_params: t.Optional[t.Type[BaseModel]] = None,
    preload: t.Optional[bool] = None,
    annotation_locals: t.Optional[t.Mapping[str, t.Any]] = None,
)

Source from the content-addressed store, hash-verified

262
263
264def _infer_tool_from_function(
265 fn: t.Callable[..., t.Any],
266 *,
267 slug: t.Optional[str] = None,
268 name: t.Optional[str] = None,
269 description: t.Optional[str] = None,
270 extends_toolkit: t.Optional[str] = None,
271 output_params: t.Optional[t.Type[BaseModel]] = None,
272 preload: t.Optional[bool] = None,
273 annotation_locals: t.Optional[t.Mapping[str, t.Any]] = None,
274) -> CustomTool:
275 """Create a CustomTool by inferring metadata from a decorated function.
276
277 - slug: from ``fn.__name__.upper()``
278 - name: from ``fn.__name__`` humanized
279 - description: from ``fn.__doc__``
280 - input_params: from the first parameter with a BaseModel type annotation
281 """
282 # Infer slug
283 actual_slug = slug or fn.__name__.upper()
284 actual_name = name or fn.__name__.replace("_", " ").title()
285 actual_description = description or inspect.cleandoc(fn.__doc__ or "")
286
287 if not actual_description:
288 raise ValidationError(
289 f"experimental.tool: description is required. "
290 f'Add a docstring to "{fn.__name__}" or pass description=...'
291 )
292
293 # Validate and infer function signature.
294 # Accepted shapes (consistent with TS CustomToolExecuteFn):
295 # (input: BaseModel) — no session context needed
296 # (input: BaseModel, ctx) — with session context
297 # The first param MUST be annotated with a BaseModel subclass.
298 # Reject async before wrapping (wrapper would hide it from _create_tool)
299 if asyncio.iscoroutinefunction(fn):
300 raise ValidationError(
301 f'experimental.tool: "{fn.__name__}" is async. '
302 f"The Composio Python SDK is synchronous — use a regular "
303 f"'def {fn.__name__}(input, ctx)' instead of 'async def'."
304 )
305
306 sig = inspect.signature(fn)
307 params = list(sig.parameters.values())
308 resolved_annotations = _resolve_function_annotations(
309 fn,
310 localns=annotation_locals,
311 )
312
313 if not params:
314 raise ValidationError(
315 f'experimental.tool: "{fn.__name__}" must accept at least one parameter '
316 f"annotated with a Pydantic BaseModel subclass, e.g. "
317 f"def {fn.__name__}(input: MyInput, ctx): ..."
318 )
319
320 if len(params) > 2:
321 raise ValidationError(

Callers 4

decoratorMethod · 0.85
toolMethod · 0.85
decoratorMethod · 0.85
toolMethod · 0.85

Calls 6

ValidationErrorClass · 0.90
_create_toolFunction · 0.85
valuesMethod · 0.80
replaceMethod · 0.65
getMethod · 0.65

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…