| package main | |
| import ( | |
| "archive/zip" | |
| "bufio" | |
| "bytes" | |
| "encoding/json" | |
| "fmt" | |
| "io" | |
| "net/http" | |
| "os" | |
| "os/exec" | |
| "path/filepath" | |
| "regexp" | |
| "strings" | |
| "time" | |
| ) | |
| type Message struct { | |
| Role string `json:"role"` | |
| Content interface{} `json:"content"` // can be string or null | |
| ToolCallID string `json:"tool_call_id,omitempty"` | |
| Name string `json:"name,omitempty"` | |
| ToolCalls []ToolCall `json:"tool_calls,omitempty"` | |
| } | |
| type ToolCall struct { | |
| ID string `json:"id"` | |
| Type string `json:"type"` | |
| Function struct { | |
| Name string `json:"name"` | |
| Arguments string `json:"arguments"` | |
| } `json:"function"` | |
| } | |
| var agentTools = []map[string]interface{}{ | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "run_command", | |
| "description": "Run a bash shell command on the user's local machine.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{"command": map[string]interface{}{"type": "string", "description": "The bash command to run."}}, | |
| "required": []string{"command"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "execute_python", | |
| "description": "Execute arbitrary Python 3 code for data processing, web scraping, or testing.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{"code": map[string]interface{}{"type": "string", "description": "The Python code to execute."}}, | |
| "required": []string{"code"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "search_web", | |
| "description": "Search the web using DuckDuckGo HTML parser to find current information.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{"query": map[string]interface{}{"type": "string", "description": "The search query."}}, | |
| "required": []string{"query"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "list_directory", | |
| "description": "List files and folders in a specific directory.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{"path": map[string]interface{}{"type": "string", "description": "Path to list, e.g., '.'"}}, | |
| "required": []string{"path"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "read_file", | |
| "description": "Read the contents of a local file.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{"path": map[string]interface{}{"type": "string", "description": "Path to the file."}}, | |
| "required": []string{"path"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "write_file", | |
| "description": "Write text to a local file (overwrites existing).", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{"path": map[string]interface{}{"type": "string"}, "content": map[string]interface{}{"type": "string"}}, | |
| "required": []string{"path", "content"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "ask_user", | |
| "description": "Pause execution and ask the user a question to get their input or permission.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{"question": map[string]interface{}{"type": "string", "description": "The question to ask the user."}}, | |
| "required": []string{"question"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "call_python_agent", | |
| "description": "Delegates a complex task to the Python LangGraph agent. Useful for advanced multi-step reasoning, LangGraph workflows, and complex tool orchestrations.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{"prompt": map[string]interface{}{"type": "string", "description": "The specific task prompt for the Python agent."}}, | |
| "required": []string{"prompt"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "deploy_tool", | |
| "description": "Deploys the tool in the current directory to the server using the CLI's deploy function.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "get_webpage_content", | |
| "description": "Downloads a webpage and extracts clean, human-readable text.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{"url": map[string]interface{}{"type": "string", "description": "The URL of the webpage."}}, | |
| "required": []string{"url"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "scaffold_tool_template", | |
| "description": "Generate standard metadata and code files (tool.json and tool.html) based on category templates.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "name": map[string]interface{}{"type": "string", "description": "Name of the tool"}, | |
| "category": map[string]interface{}{"type": "string", "description": "Template category", "enum": []string{"data-visualization", "interactive-form", "calculator", "map-location"}}, | |
| }, | |
| "required": []string{"name", "category"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "validate_tool_schema", | |
| "description": "Perform structural and type validation on tool.json structure.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "path": map[string]interface{}{"type": "string", "description": "Path to tool.json (defaults to 'tool.json')"}, | |
| }, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "lint_tool_html", | |
| "description": "Audit tool.html script tags, layout, sandbox messaging protocol, and styling warnings.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "path": map[string]interface{}{"type": "string", "description": "Path to tool.html (defaults to 'tool.html')"}, | |
| }, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "add_tool_parameter", | |
| "description": "Add a new configuration parameter dynamically to tool.json.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "path": map[string]interface{}{"type": "string", "description": "Path to tool.json"}, | |
| "name": map[string]interface{}{"type": "string", "description": "Parameter identifier name"}, | |
| "paramType": map[string]interface{}{"type": "string", "description": "Type of parameter", "enum": []string{"string", "number", "boolean", "array", "object"}}, | |
| "label": map[string]interface{}{"type": "string", "description": "User friendly input label"}, | |
| "required": map[string]interface{}{"type": "boolean", "description": "Whether the parameter is required"}, | |
| }, | |
| "required": []string{"path", "name", "paramType", "label", "required"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "inject_javascript_library", | |
| "description": "Embed a popular script/library CDN into tool.html header automatically.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "path": map[string]interface{}{"type": "string", "description": "Path to tool.html"}, | |
| "libraryName": map[string]interface{}{"type": "string", "description": "Library to inject", "enum": []string{"TailwindCSS", "ChartJS", "KaTeX", "jQuery", "Bootstrap"}}, | |
| }, | |
| "required": []string{"path", "libraryName"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "generate_mock_payload", | |
| "description": "Produce a mock postMessage payload matching parameters defined in tool.json.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "path": map[string]interface{}{"type": "string", "description": "Path to tool.json"}, | |
| }, | |
| "required": []string{"path"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "preview_tool_in_dev", | |
| "description": "Registers tool variables in the active dev server configuration for direct browser validation.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "path": map[string]interface{}{"type": "string", "description": "Path to current directory"}, | |
| }, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "export_tool_package", | |
| "description": "Package the local sandbox tool into a standard distributable ZIP package.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "dirPath": map[string]interface{}{"type": "string", "description": "Directory containing tool files"}, | |
| }, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "optimize_tool_html", | |
| "description": "Lint, format, and minify HTML and JavaScript inside tool.html.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "path": map[string]interface{}{"type": "string", "description": "Path to tool.html"}, | |
| }, | |
| "required": []string{"path"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "get_tool_templates_list", | |
| "description": "Retrieve list of all available templates supported by scaffold_tool_template.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "modify_file_content", | |
| "description": "Replaces a targeted block of text inside a file. Use this for precise edits.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "file_path": map[string]interface{}{"type": "string", "description": "Path to the file to modify"}, | |
| "target_text": map[string]interface{}{"type": "string", "description": "Exact text block to search and replace"}, | |
| "replacement_text": map[string]interface{}{"type": "string", "description": "The new text block to insert"}, | |
| }, | |
| "required": []string{"file_path", "target_text", "replacement_text"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "get_project_tree", | |
| "description": "Recursively returns a visual tree structure of directories and files, ignoring build artifacts.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "root_path": map[string]interface{}{"type": "string", "description": "Root path to list (defaults to '.')"}, | |
| }, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "search_in_files", | |
| "description": "Searches files recursively for a string query.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "query": map[string]interface{}{"type": "string", "description": "The search term"}, | |
| "path": map[string]interface{}{"type": "string", "description": "Path to search in (defaults to '.')"}, | |
| }, | |
| "required": []string{"query"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "http_request", | |
| "description": "Makes a network HTTP request (GET, POST, etc.) to query APIs or local dev servers.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "method": map[string]interface{}{"type": "string", "description": "HTTP Method, e.g., GET, POST"}, | |
| "url": map[string]interface{}{"type": "string", "description": "The full request URL"}, | |
| "headers": map[string]interface{}{"type": "object", "description": "Optional HTTP headers mapping"}, | |
| "json_body": map[string]interface{}{"type": "object", "description": "Optional JSON body payload"}, | |
| }, | |
| "required": []string{"method", "url"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "execute_go", | |
| "description": "Execute arbitrary Go code by compilation and execution.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{"code": map[string]interface{}{"type": "string", "description": "The Go code to run."}}, | |
| "required": []string{"code"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "find_files_by_name", | |
| "description": "Finds files recursively by matching their name against a pattern (case-insensitive).", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "pattern": map[string]interface{}{"type": "string", "description": "The name pattern to match, e.g., *.go"}, | |
| "path": map[string]interface{}{"type": "string", "description": "Path to search in (defaults to '.')"}, | |
| }, | |
| "required": []string{"pattern"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| "type": "function", | |
| "function": map[string]interface{}{ | |
| "name": "read_file_lines", | |
| "description": "Reads specific lines from a file (1-indexed, inclusive). Use to read parts of large files.", | |
| "parameters": map[string]interface{}{ | |
| "type": "object", | |
| "properties": map[string]interface{}{ | |
| "path": map[string]interface{}{"type": "string", "description": "Path to file"}, | |
| "start_line": map[string]interface{}{"type": "integer", "description": "1-based start line index"}, | |
| "end_line": map[string]interface{}{"type": "integer", "description": "1-based end line index"}, | |
| }, | |
| "required": []string{"path", "start_line", "end_line"}, | |
| }, | |
| }, | |
| }, | |
| } | |
| func startAgentSession() { | |
| if parsedArgs.Has("--list-tools", "") { | |
| fmt.Println(hdr("Registered Agent Tools")) | |
| for _, tool := range agentTools { | |
| fn, _ := tool["function"].(map[string]interface{}) | |
| name, _ := fn["name"].(string) | |
| desc, _ := fn["description"].(string) | |
| fmt.Printf(" • %s%-25s%s %s\n", Bold+Green, name, Reset, desc) | |
| } | |
| return | |
| } | |
| fmt.Println(hdr("MioBook Autonomous AI Agent")) | |
| // Load key from config or environment | |
| var apiKey string | |
| cfg, errCfg := loadConfig() | |
| if errCfg == nil && cfg != nil { | |
| apiKey = cfg.OpenAIKey | |
| } | |
| if envKey := os.Getenv("OPENAI_API_KEY"); envKey != "" { | |
| apiKey = envKey | |
| } | |
| if apiKey == "" { | |
| fmt.Printf("%s[OPENAI KEY]%s OpenAI API Key is not set.\n", Yellow, Reset) | |
| fmt.Printf("Please enter your OpenAI API Key: ") | |
| scanner := bufio.NewScanner(os.Stdin) | |
| if scanner.Scan() { | |
| apiKey = strings.TrimSpace(scanner.Text()) | |
| if apiKey != "" { | |
| if cfg == nil { | |
| cfg = &Config{Host: DefaultHost} | |
| } | |
| cfg.OpenAIKey = apiKey | |
| saveConfig(cfg) | |
| fmt.Printf("%s✔ API key successfully saved to configuration!%s\n\n", Green, Reset) | |
| } else { | |
| fmt.Println(err("API Key entry cancelled.")) | |
| return | |
| } | |
| } | |
| } | |
| fmt.Printf("%sWelcome! I am your autonomous AI assistant. I have advanced platform tool-making tools enabled!%s\n", Cyan, Reset) | |
| fmt.Println("Type 'exit' to leave.") | |
| systemPrompt := `You are an expert autonomous developer agent specializing in sandboxed React-like widgets and components. | |
| You possess a suite of 10 powerful tool-making tools: scaffold_tool_template, validate_tool_schema, lint_tool_html, add_tool_parameter, inject_javascript_library, generate_mock_payload, preview_tool_in_dev, export_tool_package, optimize_tool_html, and get_tool_templates_list. | |
| Use these specific tools directly when the user requests generating, validating, updating, or previewing extensions or widgets. | |
| PROMPT ENGINEERING GUIDELINES FOR HTML SANDBOX CREATION (tool.html): | |
| - Treat the single HTML file like a React/Vue application. Implement a reactive state object (e.g. const state = { data: [] };) and a render() function that updates the DOM dynamically when state changes. | |
| - Always implement the sandboxed handshake protocol: | |
| 1. Listen for the 'init' postMessage event to retrieve inputs (window.addEventListener('message', (e) => { if (e.data.type === 'init') { ... } })). | |
| 2. Send a 'ready' postMessage to the parent immediately after load (window.parent.postMessage({ type: 'ready' }, '*')). | |
| 3. Send interactive responses or final values back to the parent using window.parent.postMessage({ type: 'submit' / 'result', data: ... }, '*'). | |
| - Apply modern, premium aesthetics: | |
| - Import Tailwind CSS or define beautiful custom styles. | |
| - Use elegant typography (e.g. Outfit, Inter or Roboto from Google Fonts). | |
| - Use professional color palettes (dark modes, translucent backgrounds, glassmorphism). | |
| - Add smooth CSS transitions and micro-animations for hovered elements. | |
| - Never use raw default browser inputs/buttons; style them to look modern and premium.` | |
| customSession := parsedArgs.Get("--session", "") | |
| messages := loadSession(customSession) | |
| if len(messages) == 0 { | |
| messages = append(messages, Message{Role: "system", Content: systemPrompt}) | |
| } else { | |
| fmt.Printf("%s[Shared Session] Loaded %d messages from history.%s\n", Green, len(messages), Reset) | |
| } | |
| // Single-shot prompt mode from CLI | |
| if len(parsedArgs.Positional) > 1 { | |
| prompt := strings.Join(parsedArgs.Positional[1:], " ") | |
| fmt.Printf("%s[Single-Shot Mode] Prompt: %s%s\n", Cyan, prompt, Reset) | |
| messages = append(messages, Message{Role: "user", Content: prompt}) | |
| processAgentTurn(apiKey, &messages) | |
| saveSession(customSession, messages) | |
| exportSession(&messages) | |
| return | |
| } | |
| scanner := bufio.NewScanner(os.Stdin) | |
| for { | |
| fmt.Printf("\n%s> %s", Green, Reset) | |
| if !scanner.Scan() { | |
| break | |
| } | |
| input := strings.TrimSpace(scanner.Text()) | |
| if input == "exit" || input == "quit" { | |
| break | |
| } | |
| if input == "" { | |
| continue | |
| } | |
| messages = append(messages, Message{Role: "user", Content: input}) | |
| processAgentTurn(apiKey, &messages) | |
| saveSession(customSession, messages) | |
| } | |
| exportSession(&messages) | |
| } | |
| func processAgentTurn(apiKey string, messages *[]Message) { | |
| for { | |
| spin := startSpinner("Agent is thinking...") | |
| respBytes, errAPI := callOpenAI(apiKey, *messages) | |
| spin.Stop("") | |
| if errAPI != nil { | |
| fmt.Println(err("Error: " + errAPI.Error())) | |
| return | |
| } | |
| var openAIResp map[string]interface{} | |
| json.Unmarshal(respBytes, &openAIResp) | |
| choices, _ := openAIResp["choices"].([]interface{}) | |
| choice := choices[0].(map[string]interface{}) | |
| msg := choice["message"].(map[string]interface{}) | |
| finishReason, _ := choice["finish_reason"].(string) | |
| // Parse standard content | |
| var contentStr string | |
| if c, ok := msg["content"].(string); ok && c != "" { | |
| contentStr = c | |
| fmt.Printf("\n┌── %s🤖 AGENT RESPONSE%s ──────────────────────────────────────────────────\n", Purple+Bold, Reset) | |
| lines := strings.Split(contentStr, "\n") | |
| for _, line := range lines { | |
| fmt.Printf("│ %s\n", line) | |
| } | |
| fmt.Printf("└──────────────────────────────────────────────────────────────────────────\n") | |
| } | |
| // Append assistant message | |
| assistantMsg := Message{Role: "assistant", Content: msg["content"]} | |
| // Check for tool calls | |
| if finishReason == "tool_calls" || msg["tool_calls"] != nil { | |
| toolCallsRaw, _ := json.Marshal(msg["tool_calls"]) | |
| var tCalls []ToolCall | |
| json.Unmarshal(toolCallsRaw, &tCalls) | |
| assistantMsg.ToolCalls = tCalls | |
| *messages = append(*messages, assistantMsg) | |
| for _, tc := range tCalls { | |
| fmt.Printf("\n┌── %s⚙️ EXECUTING TOOL: %s%s ──────────────────────────────────────────────\n", Yellow+Bold, tc.Function.Name, Reset) | |
| fmt.Printf("│ Arguments: %s\n", tc.Function.Arguments) | |
| result := executeLocalTool(tc.Function.Name, tc.Function.Arguments) | |
| truncated := result | |
| if len(truncated) > 300 { | |
| truncated = truncated[:300] + "... (truncated)" | |
| } | |
| truncated = strings.ReplaceAll(truncated, "\n", "\n│ ") | |
| fmt.Printf("│ Result: %s\n", truncated) | |
| fmt.Printf("└──────────────────────────────────────────────────────────────────────────\n") | |
| *messages = append(*messages, Message{ | |
| Role: "tool", | |
| ToolCallID: tc.ID, | |
| Name: tc.Function.Name, | |
| Content: result, | |
| }) | |
| } | |
| // Loop continues to send tool results back to OpenAI | |
| } else { | |
| *messages = append(*messages, assistantMsg) | |
| break // conversation turn ended | |
| } | |
| } | |
| } | |
| func executeLocalTool(name, argsJSON string) string { | |
| if !confirmTool(name, argsJSON) { | |
| return "Error: User denied execution of this tool." | |
| } | |
| var args map[string]interface{} | |
| json.Unmarshal([]byte(argsJSON), &args) | |
| switch name { | |
| case "run_command": | |
| cmdStr, _ := args["command"].(string) | |
| cmd := exec.Command("sh", "-c", cmdStr) | |
| out, err := cmd.CombinedOutput() | |
| if err != nil { | |
| return fmt.Sprintf("Error: %v\nOutput: %s", err, string(out)) | |
| } | |
| return string(out) | |
| case "execute_python": | |
| code, _ := args["code"].(string) | |
| // Write to temp file | |
| tmpFile := "temp_agent_script.py" | |
| os.WriteFile(tmpFile, []byte(code), 0644) | |
| defer os.Remove(tmpFile) | |
| cmd := exec.Command("python3", tmpFile) | |
| out, err := cmd.CombinedOutput() | |
| if err != nil { | |
| return fmt.Sprintf("Python Error: %v\nOutput: %s", err, string(out)) | |
| } | |
| return string(out) | |
| case "search_web": | |
| query, _ := args["query"].(string) | |
| // Assuming we can call duckduckgo locally like we do in commands.go | |
| // We'll just run our own CLI command for web-search as a shortcut! | |
| cmd := exec.Command("ie-cli", "web-search", "-q", query, "--json") | |
| out, _ := cmd.CombinedOutput() | |
| return string(out) | |
| case "get_webpage_content": | |
| url, _ := args["url"].(string) | |
| return getWebpageContent(url) | |
| case "list_directory": | |
| path, _ := args["path"].(string) | |
| entries, err := os.ReadDir(path) | |
| if err != nil { | |
| return err.Error() | |
| } | |
| var list []string | |
| for _, e := range entries { | |
| list = append(list, e.Name()) | |
| } | |
| return strings.Join(list, "\n") | |
| case "ask_user": | |
| question, _ := args["question"].(string) | |
| fmt.Printf("\n%s[Agent Question]%s %s\n> ", Yellow, Reset, question) | |
| scanner := bufio.NewScanner(os.Stdin) | |
| if scanner.Scan() { | |
| return scanner.Text() | |
| } | |
| return "No response" | |
| case "read_file": | |
| path, _ := args["path"].(string) | |
| data, err := os.ReadFile(path) | |
| if err != nil { | |
| return err.Error() | |
| } | |
| return string(data) | |
| case "write_file": | |
| path, _ := args["path"].(string) | |
| content, _ := args["content"].(string) | |
| err := os.WriteFile(path, []byte(content), 0644) | |
| if err != nil { | |
| return err.Error() | |
| } | |
| return "Success" | |
| case "call_python_agent": | |
| prompt, _ := args["prompt"].(string) | |
| return callPythonAgent(prompt) | |
| case "deploy_tool": | |
| os.Args = []string{"ie-cli", "deploy"} | |
| handleDeploy() | |
| return "Deploy command triggered locally. Check user console for results." | |
| case "scaffold_tool_template": | |
| n, _ := args["name"].(string) | |
| cat, _ := args["category"].(string) | |
| return scaffoldToolTemplate(n, cat) | |
| case "validate_tool_schema": | |
| p, _ := args["path"].(string) | |
| return validateToolSchema(p) | |
| case "lint_tool_html": | |
| p, _ := args["path"].(string) | |
| return lintToolHTML(p) | |
| case "add_tool_parameter": | |
| p, _ := args["path"].(string) | |
| n, _ := args["name"].(string) | |
| t, _ := args["paramType"].(string) | |
| lbl, _ := args["label"].(string) | |
| req, _ := args["required"].(bool) | |
| return addToolParameter(p, n, t, lbl, req) | |
| case "inject_javascript_library": | |
| p, _ := args["path"].(string) | |
| lib, _ := args["libraryName"].(string) | |
| return injectJSClass(p, lib) | |
| case "generate_mock_payload": | |
| p, _ := args["path"].(string) | |
| return generateMockPayload(p) | |
| case "preview_tool_in_dev": | |
| p, _ := args["path"].(string) | |
| return previewToolDev(p) | |
| case "export_tool_package": | |
| dp, _ := args["dirPath"].(string) | |
| return exportToolPackage(dp) | |
| case "optimize_tool_html": | |
| p, _ := args["path"].(string) | |
| return optimizeToolHTML(p) | |
| case "get_tool_templates_list": | |
| return getToolTemplatesList() | |
| case "modify_file_content": | |
| path, _ := args["file_path"].(string) | |
| target, _ := args["target_text"].(string) | |
| replacement, _ := args["replacement_text"].(string) | |
| data, err := os.ReadFile(path) | |
| if err != nil { | |
| return err.Error() | |
| } | |
| content := string(data) | |
| if !strings.Contains(content, target) { | |
| return fmt.Sprintf("Error: Target text not found in %s", path) | |
| } | |
| updated := strings.Replace(content, target, replacement, 1) | |
| err = os.WriteFile(path, []byte(updated), 0644) | |
| if err != nil { | |
| return err.Error() | |
| } | |
| return "Success" | |
| case "get_project_tree": | |
| rootPath, _ := args["root_path"].(string) | |
| if rootPath == "" { | |
| rootPath = "." | |
| } | |
| var treeBuilder strings.Builder | |
| treeBuilder.WriteString(rootPath + "\n") | |
| ignored := map[string]bool{ | |
| ".git": true, "node_modules": true, "target": true, ".gradle": true, | |
| "bin": true, ".idea": true, "dist": true, "build": true, | |
| } | |
| var walk func(string, string) | |
| walk = func(path string, prefix string) { | |
| entries, err := os.ReadDir(path) | |
| if err != nil { | |
| return | |
| } | |
| var filtered []os.DirEntry | |
| for _, entry := range entries { | |
| if !ignored[entry.Name()] { | |
| filtered = append(filtered, entry) | |
| } | |
| } | |
| for i, entry := range filtered { | |
| isLast := i == len(filtered)-1 | |
| connector := "├── " | |
| if isLast { | |
| connector = "└── " | |
| } | |
| treeBuilder.WriteString(prefix + connector + entry.Name() + "\n") | |
| if entry.IsDir() { | |
| newPrefix := prefix + "│ " | |
| if isLast { | |
| newPrefix = prefix + " " | |
| } | |
| walk(filepath.Join(path, entry.Name()), newPrefix) | |
| } | |
| } | |
| } | |
| walk(rootPath, "") | |
| return treeBuilder.String() | |
| case "search_in_files": | |
| query, _ := args["query"].(string) | |
| path, _ := args["path"].(string) | |
| if path == "" { | |
| path = "." | |
| } | |
| ignored := map[string]bool{ | |
| ".git": true, "node_modules": true, "target": true, ".gradle": true, | |
| "bin": true, ".idea": true, "dist": true, "build": true, | |
| } | |
| var results []string | |
| err := filepath.Walk(path, func(filePath string, info os.FileInfo, err error) error { | |
| if err != nil { | |
| return nil | |
| } | |
| if info.IsDir() { | |
| if ignored[info.Name()] { | |
| return filepath.SkipDir | |
| } | |
| return nil | |
| } | |
| data, err := os.ReadFile(filePath) | |
| if err != nil { | |
| return nil | |
| } | |
| lines := strings.Split(string(data), "\n") | |
| for i, line := range lines { | |
| if strings.Contains(line, query) { | |
| results = append(results, fmt.Sprintf("%s:%d: %s", filePath, i+1, strings.TrimSpace(line))) | |
| if len(results) >= 50 { | |
| return io.EOF // Stop walking | |
| } | |
| } | |
| } | |
| return nil | |
| }) | |
| if err != nil && err != io.EOF { | |
| return err.Error() | |
| } | |
| if len(results) == 0 { | |
| return "No matches found." | |
| } | |
| ret := strings.Join(results, "\n") | |
| if len(results) >= 50 { | |
| ret += "\n\n(Truncated to 50 results)" | |
| } | |
| return ret | |
| case "http_request": | |
| method, _ := args["method"].(string) | |
| url, _ := args["url"].(string) | |
| headersRaw, _ := args["headers"].(map[string]interface{}) | |
| jsonBodyRaw, _ := args["json_body"].(map[string]interface{}) | |
| var body io.Reader | |
| if jsonBodyRaw != nil { | |
| bodyBytes, _ := json.Marshal(jsonBodyRaw) | |
| body = bytes.NewBuffer(bodyBytes) | |
| } | |
| req, err := http.NewRequest(method, url, body) | |
| if err != nil { | |
| return err.Error() | |
| } | |
| if jsonBodyRaw != nil { | |
| req.Header.Set("Content-Type", "application/json") | |
| } | |
| for k, v := range headersRaw { | |
| if vStr, ok := v.(string); ok { | |
| req.Header.Set(k, vStr) | |
| } | |
| } | |
| client := &http.Client{Timeout: 15 * time.Second} | |
| resp, err := client.Do(req) | |
| if err != nil { | |
| return fmt.Sprintf("Network request failed: %v", err) | |
| } | |
| defer resp.Body.Close() | |
| respBytes, _ := io.ReadAll(resp.Body) | |
| return fmt.Sprintf("Status Code: %d\nResponse:\n%s", resp.StatusCode, string(respBytes)) | |
| case "execute_go": | |
| code, _ := args["code"].(string) | |
| tmpFile := "temp_agent_script.go" | |
| if !strings.HasPrefix(strings.TrimSpace(code), "package ") { | |
| code = "package main\n\nimport \"fmt\"\n\nfunc main() {\n" + code + "\n}" | |
| } | |
| os.WriteFile(tmpFile, []byte(code), 0644) | |
| defer os.Remove(tmpFile) | |
| cmd := exec.Command("go", "run", tmpFile) | |
| out, err := cmd.CombinedOutput() | |
| if err != nil { | |
| return fmt.Sprintf("Go Run Error: %v\nOutput: %s", err, string(out)) | |
| } | |
| return string(out) | |
| case "find_files_by_name": | |
| pattern, _ := args["pattern"].(string) | |
| path, _ := args["path"].(string) | |
| if path == "" { | |
| path = "." | |
| } | |
| ignored := map[string]bool{ | |
| ".git": true, "node_modules": true, "target": true, ".gradle": true, | |
| "bin": true, ".idea": true, "dist": true, "build": true, | |
| } | |
| var results []string | |
| filepath.Walk(path, func(filePath string, info os.FileInfo, err error) error { | |
| if err != nil { | |
| return nil | |
| } | |
| if info.IsDir() && ignored[info.Name()] { | |
| return filepath.SkipDir | |
| } | |
| name := strings.ToLower(info.Name()) | |
| pat := strings.ToLower(pattern) | |
| matched := false | |
| if strings.Contains(pat, "*") { | |
| cleanPat := strings.ReplaceAll(pat, "*", "") | |
| if strings.HasPrefix(pat, "*") && strings.HasSuffix(pat, "*") { | |
| matched = strings.Contains(name, cleanPat) | |
| } else if strings.HasPrefix(pat, "*") { | |
| matched = strings.HasSuffix(name, cleanPat) | |
| } else if strings.HasSuffix(pat, "*") { | |
| matched = strings.HasPrefix(name, cleanPat) | |
| } else { | |
| matched = strings.Contains(name, cleanPat) | |
| } | |
| } else { | |
| matched = strings.Contains(name, pat) | |
| } | |
| if matched { | |
| results = append(results, filePath) | |
| if len(results) >= 100 { | |
| return io.EOF | |
| } | |
| } | |
| return nil | |
| }) | |
| if len(results) == 0 { | |
| return "No matching files found." | |
| } | |
| return strings.Join(results, "\n") | |
| case "read_file_lines": | |
| path, _ := args["path"].(string) | |
| start, _ := args["start_line"].(float64) | |
| end, _ := args["end_line"].(float64) | |
| data, err := os.ReadFile(path) | |
| if err != nil { | |
| return err.Error() | |
| } | |
| lines := strings.Split(string(data), "\n") | |
| startIdx := int(start) - 1 | |
| endIdx := int(end) | |
| if startIdx < 0 { | |
| startIdx = 0 | |
| } | |
| if endIdx > len(lines) { | |
| endIdx = len(lines) | |
| } | |
| if startIdx >= len(lines) || startIdx > endIdx { | |
| return "Error: Invalid line range." | |
| } | |
| return strings.Join(lines[startIdx:endIdx], "\n") | |
| default: | |
| return "Unknown tool" | |
| } | |
| } | |
| func scaffoldToolTemplate(name, category string) string { | |
| var toolJSON, toolHTML string | |
| switch category { | |
| case "data-visualization": | |
| toolJSON = fmt.Sprintf(`{ | |
| "name": "%s", | |
| "version": "1.0.0", | |
| "description": "Dynamic Chart Visualization", | |
| "entrypoint": "tool.html", | |
| "parameters": [ | |
| {"name": "title", "type": "string", "label": "Chart Title", "required": true}, | |
| {"name": "values", "type": "string", "label": "Values (Comma Separated)", "required": true} | |
| ] | |
| }`, name) | |
| toolHTML = `<!DOCTYPE html> | |
| <html> | |
| <head> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script> | |
| <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script> | |
| <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&display=swap'); | |
| body { font-family: 'Outfit', sans-serif; background-color: #0f172a; color: #f8fafc; } | |
| </style> | |
| </head> | |
| <body class="p-6"> | |
| <div id="root"></div> | |
| <script type="text/babel"> | |
| function App() { | |
| const [title, setTitle] = React.useState('Data Visualization'); | |
| const [values, setValues] = React.useState([10, 20, 30, 40]); | |
| const chartRef = React.useRef(null); | |
| const chartInstance = React.useRef(null); | |
| React.useEffect(() => { | |
| const handleMsg = (e) => { | |
| if (e.data && e.data.type === 'init') { | |
| const data = e.data.data || {}; | |
| if (data.title) setTitle(data.title); | |
| if (data.values) { | |
| const parsed = data.values.split(',').map(Number); | |
| setValues(parsed); | |
| } | |
| } | |
| }; | |
| window.addEventListener('message', handleMsg); | |
| window.parent.postMessage({ type: 'ready' }, '*'); | |
| return () => window.removeEventListener('message', handleMsg); | |
| }, []); | |
| React.useEffect(() => { | |
| if (!chartRef.current) return; | |
| if (chartInstance.current) chartInstance.current.destroy(); | |
| const ctx = chartRef.current.getContext('2d'); | |
| chartInstance.current = new Chart(ctx, { | |
| type: 'bar', | |
| data: { | |
| labels: values.map((_, i) => 'Item ' + (i + 1)), | |
| datasets: [{ | |
| label: 'Values', | |
| data: values, | |
| backgroundColor: 'rgba(56, 189, 248, 0.5)', | |
| borderColor: 'rgba(56, 189, 248, 1)', | |
| borderWidth: 1 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| plugins: { | |
| legend: { labels: { color: '#94a3b8' } } | |
| }, | |
| scales: { | |
| x: { grid: { color: '#334155' }, ticks: { color: '#94a3b8' } }, | |
| y: { grid: { color: '#334155' }, ticks: { color: '#94a3b8' } } | |
| } | |
| } | |
| }); | |
| }, [title, values]); | |
| return ( | |
| <div class="max-w-xl mx-auto bg-slate-800 border border-slate-700 rounded-2xl p-6 shadow-2xl"> | |
| <h2 class="text-xl font-bold mb-4 text-sky-400">{title}</h2> | |
| <canvas ref={chartRef}></canvas> | |
| <div class="mt-4 flex justify-between items-center"> | |
| <span class="text-xs text-slate-400">Powered by React & Tailwind</span> | |
| <button | |
| onClick={() => { | |
| console.log("Submitting chart result..."); | |
| window.parent.postMessage({ type: 'submit', data: { title, values } }, '*'); | |
| }} | |
| class="bg-sky-500 hover:bg-sky-600 text-slate-950 font-bold px-4 py-2 rounded-lg text-sm transition" | |
| > | |
| Submit Result | |
| </button> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| const root = ReactDOM.createRoot(document.getElementById('root')); | |
| root.render(<App />); | |
| </script> | |
| </body> | |
| </html>` | |
| case "interactive-form": | |
| toolJSON = fmt.Sprintf(`{ | |
| "name": "%s", | |
| "version": "1.0.0", | |
| "description": "Dynamic Feedback Form", | |
| "entrypoint": "tool.html", | |
| "parameters": [ | |
| {"name": "title", "type": "string", "label": "Form Title", "required": true}, | |
| {"name": "placeholder", "type": "string", "label": "Input Placeholder", "required": false} | |
| ] | |
| }`, name) | |
| toolHTML = `<!DOCTYPE html> | |
| <html> | |
| <head> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| </head> | |
| <body class="bg-slate-50 p-6"> | |
| <div class="max-w-md mx-auto bg-white p-6 rounded-2xl shadow-sm border border-slate-100"> | |
| <h2 id="form-title" class="text-lg font-semibold text-slate-800 mb-4">Feedback Form</h2> | |
| <div class="space-y-4"> | |
| <input type="text" id="userInput" class="w-full px-3 py-2 border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Type here..."> | |
| <button onclick="submitFeedback()" class="w-full bg-blue-600 text-white py-2 rounded-lg hover:bg-blue-700 transition">Submit</button> | |
| </div> | |
| </div> | |
| <script> | |
| window.addEventListener('message', function(event) { | |
| if (event.data.type === 'init') { | |
| const payload = event.data.payload || {}; | |
| document.getElementById('form-title').innerText = payload.title || 'Form'; | |
| document.getElementById('userInput').placeholder = payload.placeholder || 'Type here...'; | |
| } | |
| }); | |
| function submitFeedback() { | |
| const val = document.getElementById('userInput').value; | |
| window.parent.postMessage({ | |
| type: 'submit', | |
| data: { value: val } | |
| }, '*'); | |
| } | |
| window.parent.postMessage({ type: 'ready' }, '*'); | |
| </script> | |
| </body> | |
| </html>` | |
| default: | |
| toolJSON = fmt.Sprintf(`{ | |
| "name": "%s", | |
| "version": "1.0.0", | |
| "description": "Simple mathematical operations", | |
| "entrypoint": "tool.html", | |
| "parameters": [ | |
| {"name": "operation", "type": "string", "label": "Operation (add, sub, mul, div)", "required": true} | |
| ] | |
| }`, name) | |
| toolHTML = `<!DOCTYPE html> | |
| <html> | |
| <head> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| </head> | |
| <body class="p-6 bg-gray-100"> | |
| <div class="bg-white p-6 rounded-lg shadow-md max-w-sm mx-auto text-center"> | |
| <h2 class="text-xl font-bold mb-4">Smart Sandbox Calculator</h2> | |
| <div class="flex justify-center gap-4 mb-4"> | |
| <input type="number" id="num1" value="10" class="w-20 px-2 py-1 border rounded text-center"> | |
| <span id="op-symbol" class="text-xl font-bold">+</span> | |
| <input type="number" id="num2" value="5" class="w-20 px-2 py-1 border rounded text-center"> | |
| </div> | |
| <button onclick="calculate()" class="bg-emerald-500 text-white px-4 py-2 rounded hover:bg-emerald-600">Calculate</button> | |
| <div id="result" class="mt-4 text-2xl font-bold text-emerald-600">Result: 15</div> | |
| </div> | |
| <script> | |
| let op = 'add'; | |
| window.addEventListener('message', function(event) { | |
| if (event.data.type === 'init') { | |
| op = event.data.payload.operation || 'add'; | |
| const symbols = { 'add': '+', 'sub': '-', 'mul': '*', 'div': '/' }; | |
| document.getElementById('op-symbol').innerText = symbols[op] || '+'; | |
| } | |
| }); | |
| function calculate() { | |
| const n1 = parseFloat(document.getElementById('num1').value); | |
| const n2 = parseFloat(document.getElementById('num2').value); | |
| let res = 0; | |
| if (op === 'add') res = n1 + n2; | |
| else if (op === 'sub') res = n1 - n2; | |
| else if (op === 'mul') res = n1 * n2; | |
| else if (op === 'div') res = n1 / n2; | |
| document.getElementById('result').innerText = 'Result: ' + res; | |
| window.parent.postMessage({ type: 'result', value: res }, '*'); | |
| } | |
| window.parent.postMessage({ type: 'ready' }, '*'); | |
| </script> | |
| </body> | |
| </html>` | |
| } | |
| os.WriteFile("tool.json", []byte(toolJSON), 0644) | |
| os.WriteFile("tool.html", []byte(toolHTML), 0644) | |
| return fmt.Sprintf("Successfully scaffolded tool '%s' with category '%s' in current folder.", name, category) | |
| } | |
| func validateToolSchema(path string) string { | |
| if path == "" { | |
| path = "tool.json" | |
| } | |
| data, err := os.ReadFile(path) | |
| if err != nil { | |
| return fmt.Sprintf("Error reading tool.json: %v", err) | |
| } | |
| var m map[string]interface{} | |
| if err := json.Unmarshal(data, &m); err != nil { | |
| return fmt.Sprintf("JSON parse error: %v", err) | |
| } | |
| requiredFields := []string{"name", "version", "entrypoint", "parameters"} | |
| for _, f := range requiredFields { | |
| if _, exists := m[f]; !exists { | |
| return fmt.Sprintf("Validation failed: missing required field '%s'", f) | |
| } | |
| } | |
| return "Validation Succeeded: tool.json is well formed." | |
| } | |
| func lintToolHTML(path string) string { | |
| if path == "" { | |
| path = "tool.html" | |
| } | |
| data, err := os.ReadFile(path) | |
| if err != nil { | |
| return fmt.Sprintf("Error reading html: %v", err) | |
| } | |
| content := string(data) | |
| var warnings []string | |
| if !strings.Contains(content, "window.addEventListener('message'") { | |
| warnings = append(warnings, "Missing iframe handshake message listener: 'window.addEventListener(\"message\", ...)'") | |
| } | |
| if !strings.Contains(content, "window.parent.postMessage") { | |
| warnings = append(warnings, "Missing message post back to parent page: 'window.parent.postMessage(...)'") | |
| } | |
| if !strings.Contains(content, "cdn.tailwindcss.com") && !strings.Contains(content, "<style>") { | |
| warnings = append(warnings, "Recommendation: Use TailwindCSS or styles for a beautiful layout.") | |
| } | |
| if len(warnings) == 0 { | |
| return "Lint Succeeded: No issues found. Extension is sandbox compatible." | |
| } | |
| return "Lint Warnings:\n- " + strings.Join(warnings, "\n- ") | |
| } | |
| func addToolParameter(path, name, paramType, label string, required bool) string { | |
| data, err := os.ReadFile(path) | |
| if err != nil { | |
| return fmt.Sprintf("Error reading tool.json: %v", err) | |
| } | |
| var m map[string]interface{} | |
| json.Unmarshal(data, &m) | |
| params, _ := m["parameters"].([]interface{}) | |
| newParam := map[string]interface{}{ | |
| "name": name, | |
| "type": paramType, | |
| "label": label, | |
| "required": required, | |
| } | |
| params = append(params, newParam) | |
| m["parameters"] = params | |
| updated, _ := json.MarshalIndent(m, "", " ") | |
| os.WriteFile(path, updated, 0644) | |
| return fmt.Sprintf("Successfully added parameter '%s' to '%s'.", name, path) | |
| } | |
| func injectJSClass(path, libName string) string { | |
| data, err := os.ReadFile(path) | |
| if err != nil { | |
| return fmt.Sprintf("Error reading html: %v", err) | |
| } | |
| content := string(data) | |
| var injection string | |
| switch libName { | |
| case "TailwindCSS": | |
| injection = `<script src="https://cdn.tailwindcss.com"></script>` | |
| case "ChartJS": | |
| injection = `<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>` | |
| case "KaTeX": | |
| injection = `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css"><script src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.js"></script>` | |
| case "jQuery": | |
| injection = `<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>` | |
| case "Bootstrap": | |
| injection = `<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">` | |
| } | |
| if strings.Contains(content, "</head>") { | |
| content = strings.Replace(content, "</head>", injection+"\n</head>", 1) | |
| } else if strings.Contains(content, "<body>") { | |
| content = strings.Replace(content, "<body>", "<body>\n"+injection, 1) | |
| } else { | |
| content = injection + "\n" + content | |
| } | |
| os.WriteFile(path, []byte(content), 0644) | |
| return fmt.Sprintf("Injected %s script tags successfully.", libName) | |
| } | |
| func generateMockPayload(path string) string { | |
| data, err := os.ReadFile(path) | |
| if err != nil { | |
| return fmt.Sprintf("Error reading tool.json: %v", err) | |
| } | |
| var m map[string]interface{} | |
| json.Unmarshal(data, &m) | |
| params, _ := m["parameters"].([]interface{}) | |
| mockData := make(map[string]interface{}) | |
| for _, p := range params { | |
| paramMap, _ := p.(map[string]interface{}) | |
| name, _ := paramMap["name"].(string) | |
| pType, _ := paramMap["type"].(string) | |
| switch pType { | |
| case "string": | |
| mockData[name] = "Mock String Value" | |
| case "number": | |
| mockData[name] = 42 | |
| case "boolean": | |
| mockData[name] = true | |
| case "array": | |
| mockData[name] = []string{"item1", "item2"} | |
| case "object": | |
| mockData[name] = map[string]interface{}{"key": "value"} | |
| } | |
| } | |
| payload := map[string]interface{}{ | |
| "type": "init", | |
| "payload": mockData, | |
| } | |
| res, _ := json.MarshalIndent(payload, "", " ") | |
| return string(res) | |
| } | |
| func previewToolDev(path string) string { | |
| cmd := exec.Command("ie-cli", "dev") | |
| err := cmd.Start() | |
| if err != nil { | |
| return fmt.Sprintf("Failed to run local dev server: %v", err) | |
| } | |
| return "Preview Server started on http://localhost:3000. Access it now." | |
| } | |
| func exportToolPackage(dirPath string) string { | |
| if dirPath == "" { | |
| dirPath = "." | |
| } | |
| zipFile, err := os.Create("tool-package.zip") | |
| if err != nil { | |
| return fmt.Sprintf("Error creating zip: %v", err) | |
| } | |
| defer zipFile.Close() | |
| w := zip.NewWriter(zipFile) | |
| defer w.Close() | |
| files := []string{"tool.json", "tool.html"} | |
| for _, file := range files { | |
| fPath := filepath.Join(dirPath, file) | |
| f, err := os.Open(fPath) | |
| if err != nil { | |
| continue | |
| } | |
| zf, err := w.Create(file) | |
| if err != nil { | |
| continue | |
| } | |
| io.Copy(zf, f) | |
| f.Close() | |
| } | |
| return "Tool package exported to tool-package.zip successfully." | |
| } | |
| func optimizeToolHTML(path string) string { | |
| data, err := os.ReadFile(path) | |
| if err != nil { | |
| return fmt.Sprintf("Error reading HTML: %v", err) | |
| } | |
| content := string(data) | |
| lines := strings.Split(content, "\n") | |
| var result []string | |
| for _, l := range lines { | |
| trimmed := strings.TrimSpace(l) | |
| if trimmed != "" { | |
| result = append(result, l) | |
| } | |
| } | |
| os.WriteFile(path, []byte(strings.Join(result, "\n")), 0644) | |
| return "HTML formatting cleaned up and optimized." | |
| } | |
| func getToolTemplatesList() string { | |
| return "Templates List:\n1. data-visualization (TailwindCSS, Chart.js, init message bindings)\n2. interactive-form (Input submissions, postMessage bindings)\n3. calculator (Default basic tool framework)" | |
| } | |
| func callOpenAI(apiKey string, messages []Message) ([]byte, error) { | |
| modelName := parsedArgs.Get("--model", "-m") | |
| if modelName == "" { | |
| modelName = "gpt-4o-mini" | |
| } | |
| payload := map[string]interface{}{ | |
| "model": modelName, | |
| "messages": messages, | |
| "temperature": 0.5, | |
| "tools": agentTools, | |
| } | |
| payloadBytes, _ := json.Marshal(payload) | |
| req, _ := http.NewRequest("POST", "https://api.openai.com/v1/chat/completions", bytes.NewBuffer(payloadBytes)) | |
| req.Header.Set("Authorization", "Bearer "+apiKey) | |
| req.Header.Set("Content-Type", "application/json") | |
| client := &http.Client{Timeout: 120 * time.Second} | |
| resp, errReq := client.Do(req) | |
| if errReq != nil { | |
| return nil, errReq | |
| } | |
| defer resp.Body.Close() | |
| bodyBytes, _ := io.ReadAll(resp.Body) | |
| if resp.StatusCode != 200 { | |
| return nil, fmt.Errorf("API Error (%d): %s", resp.StatusCode, string(bodyBytes)) | |
| } | |
| return bodyBytes, nil | |
| } | |
| func runPythonAgent() { | |
| args := []string{"cli/python_agent/agent.py"} | |
| if len(os.Args) > 2 { | |
| args = append(args, os.Args[2:]...) | |
| } | |
| cmd := exec.Command("python3", args...) | |
| cmd.Stdin = os.Stdin | |
| cmd.Stdout = os.Stdout | |
| cmd.Stderr = os.Stderr | |
| err := cmd.Run() | |
| if err != nil { | |
| fmt.Printf("%sError running Python LangGraph agent: %v%s\n", Red, err, Reset) | |
| } | |
| } | |
| func confirmTool(name, argsJSON string) bool { | |
| if parsedArgs.Has("--confirm", "-c") { | |
| if name == "run_command" || name == "execute_python" || name == "execute_go" || name == "deploy_tool" || name == "write_file" || name == "modify_file_content" { | |
| fmt.Printf("\n%s[Confirm Tool]%s Agent wants to execute %s with args: %s\n", Yellow, Reset, name, argsJSON) | |
| confirm := ask("Allow execution? [y/N]: ") | |
| return strings.ToLower(confirm) == "y" | |
| } | |
| } | |
| return true | |
| } | |
| func exportSession(messages *[]Message) { | |
| exportFile := parsedArgs.Get("--export", "-e") | |
| if exportFile != "" { | |
| historyBytes, _ := json.MarshalIndent(messages, "", " ") | |
| os.WriteFile(exportFile, historyBytes, 0644) | |
| fmt.Println(ok(fmt.Sprintf("Session history exported to %s", exportFile))) | |
| } | |
| } | |
| func getSessionFilePath(customPath string) string { | |
| if customPath != "" { | |
| return customPath | |
| } | |
| home, _ := os.UserHomeDir() | |
| return filepath.Join(home, ".ie-research-agent-session.json") | |
| } | |
| func loadSession(customPath string) []Message { | |
| if parsedArgs.Has("--clear-session", "") { | |
| return nil | |
| } | |
| path := getSessionFilePath(customPath) | |
| data, err := os.ReadFile(path) | |
| if err != nil { | |
| return nil | |
| } | |
| var msgs []Message | |
| if err := json.Unmarshal(data, &msgs); err == nil { | |
| return msgs | |
| } | |
| return nil | |
| } | |
| func saveSession(customPath string, msgs []Message) { | |
| path := getSessionFilePath(customPath) | |
| data, err := json.MarshalIndent(msgs, "", " ") | |
| if err == nil { | |
| os.WriteFile(path, data, 0644) | |
| } | |
| } | |
| func getWebpageContent(url string) string { | |
| req, _ := http.NewRequest("GET", url, nil) | |
| req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)") | |
| client := &http.Client{Timeout: 15 * time.Second} | |
| resp, err := client.Do(req) | |
| if err != nil { | |
| return fmt.Sprintf("Error fetching webpage: %v", err) | |
| } | |
| defer resp.Body.Close() | |
| if resp.StatusCode != http.StatusOK { | |
| return fmt.Sprintf("Error fetching webpage: status code %d", resp.StatusCode) | |
| } | |
| body, err := io.ReadAll(resp.Body) | |
| if err != nil { | |
| return fmt.Sprintf("Error reading response: %v", err) | |
| } | |
| // Strip script, style, and HTML tags | |
| re := regexp.MustCompile("(?i)<script[^>]*>[\\s\\S]*?</script>|<style[^>]*>[\\s\\S]*?</style>|<[^>]+>") | |
| plainText := re.ReplaceAllString(string(body), " ") | |
| // Collapse multiple spaces/newlines | |
| reSpaces := regexp.MustCompile(`\s+`) | |
| plainText = reSpaces.ReplaceAllString(plainText, " ") | |
| plainText = strings.TrimSpace(plainText) | |
| if len(plainText) > 10000 { | |
| return plainText[:10000] + "\n\n(Truncated...)" | |
| } | |
| return plainText | |
| } | |
| func callPythonAgent(prompt string) string { | |
| sessionPath := parsedArgs.Get("--session", "") | |
| pythonScript := "cli/python_agent/agent.py" | |
| if _, err := os.Stat(pythonScript); os.IsNotExist(err) { | |
| pythonScript = "python_agent/agent.py" | |
| } | |
| cmdArgs := []string{pythonScript, "agent", prompt} | |
| if sessionPath != "" { | |
| cmdArgs = append(cmdArgs, "--session", sessionPath) | |
| } | |
| modelName := parsedArgs.Get("--model", "-m") | |
| if modelName != "" { | |
| cmdArgs = append(cmdArgs, "--model", modelName) | |
| } | |
| fmt.Printf("\n%s[Go Agent] Invoking Python LangGraph Agent with prompt: \"%s\"...%s\n", Yellow+Bold, prompt, Reset) | |
| cmd := exec.Command("python3", cmdArgs...) | |
| out, err := cmd.CombinedOutput() | |
| if err != nil { | |
| return fmt.Sprintf("Python agent execution failed: %v\nOutput: %s", err, string(out)) | |
| } | |
| fmt.Printf("%s[Go Agent] Python Agent execution complete.%s\n", Green+Bold, Reset) | |
| return string(out) | |
| } | |
Xet Storage Details
- Size:
- 50.2 kB
- Xet hash:
- d9cc94cd406f3c73253ed87139301eb429afc77dc7afc401cce8ad42ee0f7d18
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.