Tool Architecture & Execution
1. Overview and Core Principles
Section titled “1. Overview and Core Principles”The tool architecture is a cornerstone of the Viber framework, designed to safely provide agents with the capabilities they need to perform meaningful work. It directly supports the Vibe-X philosophy by enabling a secure, observable, and extensible system where a human expert can confidently delegate tasks to an AI partner.
The core principles are:
- Security First: Untrusted, LLM-generated code or commands must never execute directly on a host machine. All tool execution is centralized, validated, and sandboxed.
- Robust Self-Correction: LLM-generated tool calls can be malformed. The system is designed to detect this, provide clear, corrective feedback to the agent, and enable the agent to fix its own mistakes.
- Extensible by Design: The framework is built to be easily extended. Adding new tools follows a consistent pattern, and the architecture supports advanced integrations like the Model Context Protocol (MCP).
2. Tool Definition and Registration
Section titled “2. Tool Definition and Registration”A “tool” is a capability that an agent can call. Tools are defined using the AI SDK pattern with Zod schemas.
2.1. Tool Definition
Section titled “2.1. Tool Definition”Tools are defined with a name, description, parameter schema, and execute function:
import { z } from "zod";import type { CoreTool } from "@viber/core";
const writeFileTool: CoreTool = { name: "write_file", description: "Writes content to a file at the specified path.", parameters: z.object({ path: z.string().describe("The file path to write to"), content: z.string().describe("The content to write"), }), execute: async ({ path, content }) => { // Implementation return { success: true, message: `File '${path}' written successfully.` }; },};2.2. Tool Registration
Section titled “2.2. Tool Registration”Tools are registered with agents through configuration:
import { Agent } from "viber";
const agent = new Agent({ name: "Developer", llm: { provider: "openai", model: "gpt-4o" }, tools: ["write_file", "read_file", "execute_code"], requireApproval: ["write_file", "execute_code"], // Human-in-the-loop});3. The Tool Call Lifecycle
Section titled “3. The Tool Call Lifecycle”The following diagram and steps describe the end-to-end flow of a tool call, from the XAgent’s task assignment to the final result.
graph TD XAgent -- "1. Assign Task" --> Agent
subgraph "Agent" AgentLLM["LLM"] AgentCore["Core Logic"] end
subgraph "Framework" ToolManager["Tool Manager"] end
subgraph "Execution Environment" Tool["Tool (e.g., write_file)"] end
AgentLLM -- "2. Generate Tool Call" --> AgentCore AgentCore -- "3. Request Execution" --> ToolManager
alt 4a. Validation Fails ToolManager -- "Validation Error" --> AgentCore AgentCore -- "Error Context" --> AgentLLM AgentLLM -- "Corrected Tool Call" --> AgentCore AgentCore -- "Retry Request" --> ToolManager end
ToolManager -- "4b. Validation Succeeds" --> Tool Tool -- "5. Return Result" --> ToolManager ToolManager -- "6. Return Structured Result" --> AgentCore AgentCore -- "7. Report Task Completion" --> XAgentStep-by-Step Flow:
-
Task Assignment (
XAgent): The process begins when theXAgent, following the project’s plan, assigns a specific task to a specialistAgent(e.g., “Write ‘hello world’ tohello.txt”). -
Tool Call Generation (
Agent’s LLM): The Agent’s LLM receives the instruction. It determines that the task can be accomplished with a tool and generates the corresponding structured tool call. -
Execution Request: The Agent’s core logic receives the generated tool call and passes it to the Tool Manager for secure execution.
-
Validation: The Tool Manager validates the call against the tool’s registered schema.
- If Validation Fails: The Tool Manager returns a structured error to the Agent. The Agent’s LLM receives the error context and generates a corrected call. This self-correction loop is a key feature of the framework’s robustness.
- If Validation Succeeds: The Tool Manager proceeds to execution.
-
Secure Execution: The Tool Manager securely runs the tool with validated parameters.
-
Result Capturing: The Tool Manager captures the tool’s output and packages it into a structured result object, which is returned to the Agent.
-
Task Completion: The Agent has now completed its assigned task. It reports the result back to the XAgent, which updates the project plan and proceeds to the next step in the workflow.
4. Human-in-the-Loop Tool Approval
Section titled “4. Human-in-the-Loop Tool Approval”Viber supports native tool approval through AI SDK v6’s approval mechanism:
// Agent configuration with approval requirementsconst agent = new Agent({ name: "Developer", tools: ["write_file", "execute_code", "read_file"], requireApproval: ["write_file", "execute_code"],});
// Frontend handles approvalconst { messages, approveToolCall, status } = useXChat({ spaceId: "my-space",});
// When status is "awaiting-approval"if (status === "awaiting-approval") { const pendingApprovals = getPendingApprovals(messages[messages.length - 1]); // Show UI for approval await approveToolCall(pendingApprovals[0].toolCallId, true);}5. Security Architecture
Section titled “5. Security Architecture”Executing arbitrary, LLM-generated commands is a major security risk. Viber mitigates this through multiple layers:
Space-Scoped Execution
Section titled “Space-Scoped Execution”All tool executions are scoped to the Space’s workspace directory:
- Tools can only read from and write to the Space’s artifact directory
- Path traversal attacks are mitigated by resolving all paths relative to the Space root
- Each Space has complete data isolation from other Spaces
Tool Permissions
Section titled “Tool Permissions”// Tools can specify their permission requirementsconst webBrowseTool: CoreTool = { name: "browse_web", description: "Browse a webpage and extract content", parameters: z.object({ url: z.string().url(), }), permissions: ["network"], // Requires network access execute: async ({ url }) => { // Implementation with Playwright },};6. Built-in Tools
Section titled “6. Built-in Tools”Viber provides a core set of tools in @viber/tools:
| Tool | Description | Category |
|---|---|---|
read_file | Read file contents | File |
write_file | Write content to file | File |
list_files | List directory contents | File |
web_search | Search the web | Search |
browse_web | Browse and extract web pages | Web |
execute_sql | Execute database queries | Database |
7. Custom Tools
Section titled “7. Custom Tools”Users can define custom tools following the same pattern:
import { z } from "zod";import type { CoreTool } from "@viber/core";
export const customTool: CoreTool = { name: "my_custom_tool", description: "Does something custom", parameters: z.object({ input: z.string(), }), execute: async ({ input }) => { // Custom implementation return { result: `Processed: ${input}` }; },};
// Register with agentconst agent = new Agent({ name: "CustomAgent", tools: [customTool], // Pass tool object directly});8. MCP Integration
Section titled “8. MCP Integration”Viber supports the Model Context Protocol (MCP) for integrating external tool servers:
import { createMCPToolProvider } from "@viber/tools";
// Connect to an MCP serverconst mcpTools = await createMCPToolProvider({ server: "mcp://localhost:3000",});
// Use MCP tools with agentsconst agent = new Agent({ name: "MCPAgent", tools: [...mcpTools.getTools()],});This enables agents to access a vast ecosystem of third-party capabilities without requiring custom code for each integration.