diff --git a/packages/tf-sync/src/tf_sync/__pycache__/tools.cpython-313.pyc b/packages/tf-sync/src/tf_sync/__pycache__/tools.cpython-313.pyc index 3f0405583..33690be84 100644 Binary files a/packages/tf-sync/src/tf_sync/__pycache__/tools.cpython-313.pyc and b/packages/tf-sync/src/tf_sync/__pycache__/tools.cpython-313.pyc differ diff --git a/packages/tf-sync/src/tf_sync/tools.py b/packages/tf-sync/src/tf_sync/tools.py index 9bc92678d..053a5083b 100644 --- a/packages/tf-sync/src/tf_sync/tools.py +++ b/packages/tf-sync/src/tf_sync/tools.py @@ -24,8 +24,13 @@ class SyncedTool(BaseModel): 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] = [] authorisation_type: Optional[str] = None @@ -96,10 +101,34 @@ def parse_function(func: AgentFunction) -> SyncedTool: ) +def parse_agent(agent) -> SyncedTool: + """ + Parse Agent from SDK into SyncedTool. + + Args: + agent: Agent from TF SDK + + Returns: + SyncedTool instance + """ + return SyncedTool( + id=agent.id, + name=agent.label or f"agent_{agent.id[:8]}", + description=agent.description, + tool_type=ToolType.AGENT_SKILL, + is_agent_skill=True, + auth_via="tf_agent", + ) + + def sync_tools(config: TFConfig) -> ToolSyncResult: """ Sync all tools from ToothFairyAI workspace using SDK. + Includes: + - Agent Functions (API Functions) + - Coder Agents (agents with mode='coder') + Args: config: TFConfig instance @@ -108,9 +137,19 @@ def sync_tools(config: TFConfig) -> ToolSyncResult: """ try: client = config.get_client() - result = client.agent_functions.list() - tools = [parse_function(f) for f in result.items] + # Sync agent functions + func_result = client.agent_functions.list() + tools = [parse_function(f) for f in func_result.items] + + # Sync coder agents + try: + agents_result = client.agents.list() + for agent in agents_result.items: + if getattr(agent, 'mode', None) == 'coder': + tools.append(parse_agent(agent)) + except Exception as e: + pass by_type = {} for tool in tools: diff --git a/packages/tfcode/src/agent/agent.ts b/packages/tfcode/src/agent/agent.ts index 60d8d04b3..2ce3f41af 100644 --- a/packages/tfcode/src/agent/agent.ts +++ b/packages/tfcode/src/agent/agent.ts @@ -255,10 +255,50 @@ export namespace Agent { return state().then((x) => x[agent]) } + async function loadTFCoderAgents(): Promise { + const toolsPath = path.join(Global.Path.data, ".tfcode", "tools.json") + console.log("[TF Agents] Loading from:", toolsPath) + try { + const content = await Bun.file(toolsPath).text() + const data = JSON.parse(content) + console.log("[TF Agents] File loaded, success:", data.success, "tools:", data.tools?.length) + if (!data.success || !data.tools) { + console.log("[TF Agents] No tools data, returning []") + return [] + } + + const tfAgents = data.tools + .filter((t: any) => t.tool_type === "agent_skill") + + console.log("[TF Agents] Found agent_skill items:", tfAgents.length) + console.log("[TF Agents] Names:", tfAgents.map((t: any) => t.name)) + + return tfAgents.map((t: any): Info => ({ + name: t.name, + description: t.description, + mode: "subagent" as const, + permission: Permission.fromConfig({ "*": "allow" }), + native: false, + options: { + tf_agent_id: t.id, + tf_auth_via: t.auth_via, + }, + })) + } catch (e) { + console.log("[TF Agents] Error:", e) + return [] + } + } + export async function list() { const cfg = await Config.get() + const localAgents = await state() + const tfAgents = await loadTFCoderAgents() + + console.log("[TF Agents] list() - local:", Object.keys(localAgents).length, "tf:", tfAgents.length) + return pipe( - await state(), + { ...localAgents, ...Object.fromEntries(tfAgents.map(a => [a.name, a])) }, values(), sortBy( [(x) => (cfg.default_agent ? x.name === cfg.default_agent : x.name === "build"), "desc"], diff --git a/packages/tfcode/src/cli/cmd/tools.ts b/packages/tfcode/src/cli/cmd/tools.ts index 2d1e07647..a966739e3 100644 --- a/packages/tfcode/src/cli/cmd/tools.ts +++ b/packages/tfcode/src/cli/cmd/tools.ts @@ -62,6 +62,8 @@ async function runPythonSync( method: string, args: Record = {}, ): Promise { + const credentials = await loadCredentials() + const pythonCode = ` import json import sys @@ -162,6 +164,9 @@ sys.exit(0) env: { ...process.env, PYTHONPATH: getPythonSyncPath(), + TF_WORKSPACE_ID: credentials?.workspace_id || "", + TF_API_KEY: credentials?.api_key || "", + TF_REGION: credentials?.region || "au", }, }) @@ -204,6 +209,23 @@ function getToolsFilePath(): string { return path.join(getConfigPath(), TFCODE_TOOLS_FILE) } +function getCredentialsFilePath(): string { + return path.join(getConfigPath(), "credentials.json") +} + +async function loadCredentials(): Promise<{ workspace_id: string; api_key: string; region: string } | null> { + const credFile = getCredentialsFilePath() + if (!(await Filesystem.exists(credFile))) { + return null + } + try { + const content = await Bun.file(credFile).text() + return JSON.parse(content) + } catch { + return null + } +} + async function loadCachedTools(): Promise { const toolsFile = getToolsFilePath() if (!(await Filesystem.exists(toolsFile))) { diff --git a/packages/tfcode/src/cli/ui.ts b/packages/tfcode/src/cli/ui.ts index 0ea5c0c5a..545f6e329 100644 --- a/packages/tfcode/src/cli/ui.ts +++ b/packages/tfcode/src/cli/ui.ts @@ -44,7 +44,7 @@ export namespace UI { const result: string[] = [] const reset = "\x1b[0m" const left = { - fg: Bun.color("gray", "ansi") ?? "", + fg: "\x1b[38;2;29;184;198m", shadow: "\x1b[38;5;235m", bg: "\x1b[48;5;235m", }