feat: extract and publish tool metadata to AMP#4298
feat: extract and publish tool metadata to AMP#4298thiagomoretto wants to merge 11 commits intomainfrom
Conversation
|
This PR is stale because it has been open for 45 days with no activity. |
- Use sha256 instead of md5 for module name hashing (lint S324) - Filter required list to match filtered properties in JSON schema
- Add missing mocks to metadata extraction failure test
bc6de7b to
3002211
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
- Use `is not None` instead of truthiness check so empty tools list is sent to the API rather than being silently dropped as None - Strip __init__ suffix from module path for tools in __init__.py files - Extend _unwrap_schema to handle function-before, function-wrap, and definitions wrapper types
When env_vars uses default_factory, pydantic stores a callable in the schema instead of a static default value. Fall back to calling the factory when no static default is present.
iris-clawd
left a comment
There was a problem hiding this comment.
PR Review: feat: extract and publish tool metadata to AMP
Overall: Solid feature — clean implementation, good test coverage, and the non-blocking error handling is the right call. A few things worth addressing before merge:
Issues
1. Empty metadata still sends payload to API
In plus_api.py, the condition is if tools_metadata is not None, so when metadata extraction fails and tools_metadata = [], the API receives {"package": "handle", "tools": []}. Consider using if tools_metadata instead (falsy check) to avoid sending an empty wrapper object — or confirm the backend handles this gracefully.
2. _extract_field_default return type looseness
The function returns str | list[Any] | int, and humanized_name passes the result through without str() wrapping (unlike description which does str(...).strip()). If a field default is unexpectedly an int or list, humanized_name in the payload would have the wrong type. Consider normalizing:
"humanized_name": str(_extract_field_default(fields.get("name"), fallback=tool_class.__name__)),3. _unwrap_schema has no loop guard
The while loop could theoretically spin if a malformed schema has circular type references. A simple max_depth counter (e.g., 20 iterations) would make it defensive:
for _ in range(20):
if result.get("type") not in {...}:
break
...Minor / Nits
SystemExit(1)change on L134 (was bareSystemExit) — good improvement, but it is a behavior change for anyone catchingSystemExitby code. Intentional?- Test lines are long in
test_main.py— thereturn_valuedicts in@patchdecorators are 150+ chars. Consider moving them to module-level constants for readability. - The
_IGNORED_INIT_PARAMSfrozenset is a nice touch for maintainability.
What looks good ✅
- Context manager pattern for module loading with hash-based names (no more
temp_modulecollisions) - Non-blocking metadata extraction — warnings only, publish continues
- Preview output before publishing
- Comprehensive test suite covering edge cases (empty project, import errors, syntax errors, multiple files, non-tool exports)
lru_cacheon_get_schema_generator
Verdict: Approve with minor fixes (items 1-3 above). None are blockers but would improve robustness.

Summary
crewai tool publishWhat's Included
Tool Metadata Extraction
Automatically extracts from BaseTool classes:
Publish Preview
Shows detected tools during publish with:
Non-blocking Errors
Metadata extraction failures show warnings but don't block publishing.
Payload Structure
{ "tools_metadata": { "tools": [ { "name": "ToolClassName", "humanized_name": "tool_name", "description": "Tool description", "run_params_schema": { }, "init_params_schema": { }, "env_vars": [ {"name": "API_KEY", "description": "...", "required": true, "default": null} ] } ] } }Note
Medium Risk
Adds dynamic module importing and Pydantic schema introspection during
crewai tool publish, which could surface edge-case import side effects or schema-generation failures (though publish continues without metadata). Backend payload shape also changes by addingtools_metadata, requiring server compatibility.Overview
crewai tool publishnow extracts rich metadata for exportedBaseToolclasses (name/description, module, JSON schemas for run/init params, and env var definitions), prints a pre-publish preview, and sends this metadata to the Enterprise/AMP API as a newtools_metadatapayload.Internally, tool discovery utilities were extended with safer temporary module loading/cleanup and schema generation that omits non-JSON-serializable defaults; publish now treats metadata extraction errors as warnings and continues. Tests were updated/added to cover the new API parameter, preview/continue behavior, and metadata extraction edge cases.
Written by Cursor Bugbot for commit 6f3cfb8. This will update automatically on new commits. Configure here.