mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-19 15:14:49 +00:00
feat: initialize tfcode project structure
- Add README.md as living documentation - Add tfcode.json schema and config template - Add FORK_MANAGEMENT.md with mirror-based fork strategy - Add scripts/rebrand.sh for reapplying branding after upstream merges - Add packages/tf-sync Python module using official ToothFairyAI SDK - Add packages/tf-mcp-bridge TypeScript module (stub) - Multi-region support (AU, EU, US) - Tool sync: MCP servers, Agent Skills, Database Scripts, API Functions
This commit is contained in:
185
packages/tf-sync/src/tf_sync/tools.py
Normal file
185
packages/tf-sync/src/tf_sync/tools.py
Normal file
@@ -0,0 +1,185 @@
|
||||
"""
|
||||
Tool sync module for tfcode.
|
||||
Syncs MCP servers, Agent Skills, Database Scripts, and API Functions from ToothFairyAI workspace.
|
||||
Uses the official ToothFairyAI Python SDK.
|
||||
"""
|
||||
|
||||
from typing import Any, Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
from toothfairyai.types import AgentFunction
|
||||
|
||||
from tf_sync.config import TFConfig, ToolType, FunctionRequestType
|
||||
|
||||
|
||||
class SyncedTool(BaseModel):
|
||||
"""A tool synced from ToothFairyAI workspace."""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
description: Optional[str] = None
|
||||
tool_type: ToolType
|
||||
|
||||
is_mcp_server: bool = False
|
||||
is_agent_skill: bool = False
|
||||
is_database_script: bool = False
|
||||
|
||||
request_type: Optional[FunctionRequestType] = None
|
||||
url: Optional[str] = None
|
||||
tools: list[str] = []
|
||||
|
||||
auth_via: str = "tf_proxy"
|
||||
|
||||
|
||||
class ToolSyncResult(BaseModel):
|
||||
"""Result of tool sync operation."""
|
||||
|
||||
success: bool
|
||||
tools: list[SyncedTool] = []
|
||||
by_type: dict[str, int] = {}
|
||||
error: Optional[str] = None
|
||||
|
||||
|
||||
def classify_tool(tool: AgentFunction) -> ToolType:
|
||||
"""
|
||||
Classify a tool based on its flags and fields.
|
||||
|
||||
Args:
|
||||
tool: AgentFunction from TF SDK
|
||||
|
||||
Returns:
|
||||
ToolType enum value
|
||||
"""
|
||||
if tool.is_mcp_server:
|
||||
return ToolType.MCP_SERVER
|
||||
if tool.is_agent_skill:
|
||||
return ToolType.AGENT_SKILL
|
||||
if tool.is_database_script:
|
||||
return ToolType.DATABASE_SCRIPT
|
||||
if tool.request_type:
|
||||
return ToolType.API_FUNCTION
|
||||
|
||||
return ToolType.API_FUNCTION
|
||||
|
||||
|
||||
def parse_tool(tool: AgentFunction) -> SyncedTool:
|
||||
"""
|
||||
Parse AgentFunction from SDK into SyncedTool.
|
||||
|
||||
Args:
|
||||
tool: AgentFunction from TF SDK
|
||||
|
||||
Returns:
|
||||
SyncedTool instance
|
||||
"""
|
||||
tool_type = classify_tool(tool)
|
||||
|
||||
request_type_enum = None
|
||||
if tool.request_type:
|
||||
try:
|
||||
request_type_enum = FunctionRequestType(tool.request_type)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
auth_via = "user_provided" if tool_type == ToolType.API_FUNCTION else "tf_proxy"
|
||||
|
||||
return SyncedTool(
|
||||
id=tool.id,
|
||||
name=tool.name,
|
||||
description=tool.description,
|
||||
tool_type=tool_type,
|
||||
is_mcp_server=tool.is_mcp_server or False,
|
||||
is_agent_skill=tool.is_agent_skill or False,
|
||||
is_database_script=tool.is_database_script or False,
|
||||
request_type=request_type_enum,
|
||||
url=tool.url,
|
||||
tools=[],
|
||||
auth_via=auth_via,
|
||||
)
|
||||
|
||||
|
||||
def sync_tools(config: TFConfig) -> ToolSyncResult:
|
||||
"""
|
||||
Sync all tools from ToothFairyAI workspace using SDK.
|
||||
|
||||
Args:
|
||||
config: TFConfig instance
|
||||
|
||||
Returns:
|
||||
ToolSyncResult with synced tools
|
||||
"""
|
||||
try:
|
||||
client = config.get_client()
|
||||
result = client.agent_functions.list()
|
||||
|
||||
tools = [parse_tool(f) for f in result.items]
|
||||
|
||||
by_type = {}
|
||||
for tool in tools:
|
||||
type_name = tool.tool_type.value
|
||||
by_type[type_name] = by_type.get(type_name, 0) + 1
|
||||
|
||||
return ToolSyncResult(
|
||||
success=True,
|
||||
tools=tools,
|
||||
by_type=by_type,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return ToolSyncResult(
|
||||
success=False,
|
||||
error=f"Sync failed: {str(e)}",
|
||||
)
|
||||
|
||||
|
||||
def sync_tools_by_type(
|
||||
config: TFConfig,
|
||||
tool_types: Optional[list[ToolType]] = None,
|
||||
) -> ToolSyncResult:
|
||||
"""
|
||||
Sync tools of specific types from ToothFairyAI workspace.
|
||||
|
||||
Args:
|
||||
config: TFConfig instance
|
||||
tool_types: List of ToolType to sync (None = all)
|
||||
|
||||
Returns:
|
||||
ToolSyncResult with filtered tools
|
||||
"""
|
||||
result = sync_tools(config)
|
||||
|
||||
if not result.success or not tool_types:
|
||||
return result
|
||||
|
||||
filtered = [t for t in result.tools if t.tool_type in tool_types]
|
||||
|
||||
by_type = {}
|
||||
for tool in filtered:
|
||||
type_name = tool.tool_type.value
|
||||
by_type[type_name] = by_type.get(type_name, 0) + 1
|
||||
|
||||
return ToolSyncResult(
|
||||
success=True,
|
||||
tools=filtered,
|
||||
by_type=by_type,
|
||||
)
|
||||
|
||||
|
||||
def sync_mcp_servers_only(config: TFConfig) -> ToolSyncResult:
|
||||
"""Sync only MCP servers (isMCPServer=true)."""
|
||||
return sync_tools_by_type(config, [ToolType.MCP_SERVER])
|
||||
|
||||
|
||||
def sync_agent_skills_only(config: TFConfig) -> ToolSyncResult:
|
||||
"""Sync only Agent Skills (isAgentSkill=true)."""
|
||||
return sync_tools_by_type(config, [ToolType.AGENT_SKILL])
|
||||
|
||||
|
||||
def sync_database_scripts_only(config: TFConfig) -> ToolSyncResult:
|
||||
"""Sync only Database Scripts (isDatabaseScript=true)."""
|
||||
return sync_tools_by_type(config, [ToolType.DATABASE_SCRIPT])
|
||||
|
||||
|
||||
def sync_api_functions_only(config: TFConfig) -> ToolSyncResult:
|
||||
"""Sync only API Functions (has requestType)."""
|
||||
return sync_tools_by_type(config, [ToolType.API_FUNCTION])
|
||||
Reference in New Issue
Block a user