Skip to content

Instantly share code, notes, and snippets.

@theblazehen
Created January 17, 2026 07:30
Show Gist options
  • Select an option

  • Save theblazehen/1c1954d09d1a98b0a4e827bf4fb14f44 to your computer and use it in GitHub Desktop.

Select an option

Save theblazehen/1c1954d09d1a98b0a4e827bf4fb14f44 to your computer and use it in GitHub Desktop.
package main
import (
"bufio"
"bytes"
"crypto/tls"
"encoding/json"
"flag"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"strings"
)
const apiURL = "https://your.llm.api/v1/chat/completions"
const apiKey = "sk-yourkey"
const model = "model here"
type Message struct {
Role string `json:"role"`
Content string `json:"content,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
}
type ToolCall struct {
ID string `json:"id"`
Type string `json:"type"`
Function FunctionCall `json:"function"`
}
type FunctionCall struct {
Name string `json:"name"`
Arguments string `json:"arguments"`
}
type Tool struct {
Type string `json:"type"`
Function ToolFunction `json:"function"`
}
type ToolFunction struct {
Name string `json:"name"`
Description string `json:"description"`
Parameters map[string]interface{} `json:"parameters"`
}
type Request struct {
Model string `json:"model"`
Messages []Message `json:"messages"`
Tools []Tool `json:"tools,omitempty"`
}
type Choice struct {
Message Message `json:"message"`
FinishReason string `json:"finish_reason"`
}
type Response struct {
Choices []Choice `json:"choices"`
}
var tools = []Tool{
{
Type: "function",
Function: ToolFunction{
Name: "run_command",
Description: "Execute an rc shell command on Plan 9 and return its output",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"command": map[string]interface{}{
"type": "string",
"description": "The rc shell command to execute",
},
},
"required": []string{"command"},
},
},
},
{
Type: "function",
Function: ToolFunction{
Name: "read_file",
Description: "Read the contents of a file",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"path": map[string]interface{}{
"type": "string",
"description": "The file path to read",
},
},
"required": []string{"path"},
},
},
},
{
Type: "function",
Function: ToolFunction{
Name: "write_file",
Description: "Write content to a file",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"path": map[string]interface{}{
"type": "string",
"description": "The file path to write to",
},
"content": map[string]interface{}{
"type": "string",
"description": "The content to write",
},
},
"required": []string{"path", "content"},
},
},
},
{
Type: "function",
Function: ToolFunction{
Name: "list_directory",
Description: "List files in a directory",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"path": map[string]interface{}{
"type": "string",
"description": "The directory path to list",
},
},
"required": []string{"path"},
},
},
},
}
var client = &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
func callLLM(messages []Message) (*Response, error) {
req := Request{
Model: model,
Messages: messages,
Tools: tools,
}
body, _ := json.Marshal(req)
httpReq, _ := http.NewRequest("POST", apiURL, bytes.NewReader(body))
httpReq.Header.Set("Authorization", "Bearer "+apiKey)
httpReq.Header.Set("Content-Type", "application/json")
resp, err := client.Do(httpReq)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
var result Response
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("parse error: %v\nBody: %s", err, respBody)
}
return &result, nil
}
func executeTool(name string, args string) string {
var params map[string]string
json.Unmarshal([]byte(args), &params)
switch name {
case "run_command":
cmd := exec.Command("rc", "-c", params["command"])
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Sprintf("Error: %v\nOutput: %s", err, out)
}
return string(out)
case "read_file":
data, err := os.ReadFile(params["path"])
if err != nil {
return fmt.Sprintf("Error: %v", err)
}
return string(data)
case "write_file":
err := os.WriteFile(params["path"], []byte(params["content"]), 0644)
if err != nil {
return fmt.Sprintf("Error: %v", err)
}
return "File written successfully"
case "list_directory":
entries, err := os.ReadDir(params["path"])
if err != nil {
return fmt.Sprintf("Error: %v", err)
}
var names []string
for _, e := range entries {
if e.IsDir() {
names = append(names, e.Name()+"/")
} else {
names = append(names, e.Name())
}
}
return strings.Join(names, "\n")
default:
return fmt.Sprintf("Unknown tool: %s", name)
}
}
// runAgentLoop runs the agent loop with the given system and user prompts
// Returns the final text response
func runAgentLoop(systemPrompt, userPrompt string, quiet bool) string {
messages := []Message{
{Role: "system", Content: systemPrompt},
{Role: "user", Content: userPrompt},
}
maxIterations := 10
for i := 0; i < maxIterations; i++ {
resp, err := callLLM(messages)
if err != nil {
return fmt.Sprintf("Error: %v", err)
}
if len(resp.Choices) == 0 {
return "Error: No response from LLM"
}
choice := resp.Choices[0]
messages = append(messages, choice.Message)
// If there are tool calls, execute them
if len(choice.Message.ToolCalls) > 0 {
for _, tc := range choice.Message.ToolCalls {
if !quiet {
fmt.Fprintf(os.Stderr, "[Tool: %s] %s\n", tc.Function.Name, tc.Function.Arguments)
}
result := executeTool(tc.Function.Name, tc.Function.Arguments)
// Truncate long results
if len(result) > 2000 {
result = result[:2000] + "\n... (truncated)"
}
messages = append(messages, Message{
Role: "tool",
Content: result,
ToolCallID: tc.ID,
})
}
continue // Loop to get next response
}
// No tool calls, return final response
return choice.Message.Content
}
return "Error: Max iterations reached"
}
// runAcmeMode handles the Acme editor integration
// Reads selection from stdin, processes AI: prompt, outputs replacement text
func runAcmeMode() {
// Read all of stdin (the selection from Acme)
var selection strings.Builder
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
selection.WriteString(scanner.Text())
selection.WriteString("\n")
}
selectionText := selection.String()
if strings.TrimSpace(selectionText) == "" {
fmt.Println("Error: No selection provided")
return
}
systemPrompt := `You are an AI assistant integrated into the Acme editor on Plan 9 (9front).
The user has selected some text that contains a line with "AI:" (case-insensitive) followed by their request.
Your response will REPLACE their entire selection in the editor.
Rules:
- Find the line containing "AI:" and understand it as the user's request
- Do NOT include the "AI: ..." line in your response - it should be removed
- Match the indentation and coding style of the surrounding code/text
- Be concise - return ONLY what should replace the selection
- Do NOT wrap your response in markdown code fences or any other formatting
- Output raw code/text only, exactly as it should appear in the file
- If asked to read a file, use the read_file tool then include relevant contents
- If asked to write a file, use write_file tool AND return appropriate confirmation/preview text
- If asked to run a command, use run_command tool and format the output nicely
You have access to tools:
- run_command: Execute rc shell commands
- read_file: Read file contents
- write_file: Write to files
- list_directory: List directory contents
The user's selected text is provided below. Find the "AI:" request, understand what they want, and respond with the replacement text only. No markdown, no code fences, just the raw replacement text.`
userPrompt := selectionText
// Run agent loop quietly (don't print tool names to stdout - they'd end up in the file)
response := runAgentLoop(systemPrompt, userPrompt, true)
// Output the response (this replaces the selection in Acme)
fmt.Print(response)
}
// runDirectMode handles direct command-line invocation
func runDirectMode(prompt string) {
systemPrompt := `You are a helpful AI assistant running natively on Plan 9 from Bell Labs (9front).
You have access to tools to interact with the system. Use them to help the user.
The shell is rc, not bash. Common differences:
- Use 'cat /dev/sysname' to get hostname
- Use 'ls' for listing, 'du' for disk usage
- Paths: /bin, /sys, /usr, /tmp, /mnt, /n
- No head command, use 'sed 5q' instead of 'head -5'
Be concise and helpful.`
response := runAgentLoop(systemPrompt, prompt, false)
fmt.Println(response)
}
// runReplMode runs an interactive REPL with conversation history
func runReplMode() {
systemPrompt := `You are a helpful AI assistant running natively on Plan 9 from Bell Labs (9front).
You have access to tools to interact with the system. Use them to help the user.
The shell is rc, not bash. Common differences:
- Use 'cat /dev/sysname' to get hostname
- Use 'ls' for listing, 'du' for disk usage
- Paths: /bin, /sys, /usr, /tmp, /mnt, /n
- No head command, use 'sed 5q' instead of 'head -5'
Be concise and helpful.`
messages := []Message{
{Role: "system", Content: systemPrompt},
}
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("Plan 9 AI Agent REPL")
fmt.Println("Type 'quit' or 'exit' to exit, 'clear' to reset conversation")
fmt.Println()
for {
fmt.Print("> ")
if !scanner.Scan() {
break
}
input := strings.TrimSpace(scanner.Text())
if input == "" {
continue
}
// Handle special commands
switch strings.ToLower(input) {
case "quit", "exit":
fmt.Println("Goodbye!")
return
case "clear":
messages = []Message{
{Role: "system", Content: systemPrompt},
}
fmt.Println("Conversation cleared.")
continue
}
// Add user message
messages = append(messages, Message{Role: "user", Content: input})
// Run agent loop with conversation history
maxIterations := 10
for i := 0; i < maxIterations; i++ {
resp, err := callLLM(messages)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
break
}
if len(resp.Choices) == 0 {
fmt.Println("Error: No response from LLM")
break
}
choice := resp.Choices[0]
messages = append(messages, choice.Message)
// If there are tool calls, execute them
if len(choice.Message.ToolCalls) > 0 {
for _, tc := range choice.Message.ToolCalls {
fmt.Fprintf(os.Stderr, "[Tool: %s] %s\n", tc.Function.Name, tc.Function.Arguments)
result := executeTool(tc.Function.Name, tc.Function.Arguments)
// Truncate long results
if len(result) > 2000 {
result = result[:2000] + "\n... (truncated)"
}
messages = append(messages, Message{
Role: "tool",
Content: result,
ToolCallID: tc.ID,
})
}
continue // Loop to get next response
}
// No tool calls, print response and break
if choice.Message.Content != "" {
fmt.Println()
fmt.Println(choice.Message.Content)
fmt.Println()
}
break
}
}
}
func main() {
acmeMode := flag.Bool("acme", false, "Acme editor integration mode (reads selection from stdin)")
replMode := flag.Bool("repl", false, "Interactive REPL mode with conversation history")
flag.Parse()
if *acmeMode {
runAcmeMode()
return
}
if *replMode {
runReplMode()
return
}
// Direct invocation mode
args := flag.Args()
if len(args) < 1 {
fmt.Println("Usage: agent [-acme] [-repl] <prompt>")
fmt.Println(" -acme Acme editor mode (reads selection from stdin)")
fmt.Println(" -repl Interactive REPL mode with conversation history")
os.Exit(1)
}
prompt := strings.Join(args, " ")
runDirectMode(prompt)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment