Files
kandev/apps/backend/cmd/mock-agent/main.go
T
2026-02-07 17:48:04 +00:00

108 lines
3.4 KiB
Go

// Package main implements a mock agent binary that speaks the claude-code
// stream-json protocol over stdin/stdout. It generates simulated responses
// for rapid feature testing and e2e web app tests.
package main
import (
"bufio"
"encoding/json"
"fmt"
"os"
"strings"
)
// sessionID is a unique identifier for this mock-agent process instance.
// Each session spawns its own process, so using PID ensures uniqueness
// across parallel sessions.
var sessionID = fmt.Sprintf("mock-session-%d", os.Getpid())
func main() {
model := parseModelFlag()
scanner := bufio.NewScanner(os.Stdin)
buf := make([]byte, 0, 64*1024)
scanner.Buffer(buf, 10*1024*1024)
enc := json.NewEncoder(os.Stdout)
for scanner.Scan() {
line := scanner.Bytes()
if len(line) == 0 {
continue
}
var msg IncomingMessage
if err := json.Unmarshal(line, &msg); err != nil {
continue
}
switch msg.Type {
case TypeControlRequest:
handleControlRequest(enc, msg)
case TypeUser:
if msg.Message != nil {
handleUserPrompt(enc, scanner, msg.Message.Content, model)
}
}
}
if err := scanner.Err(); err != nil {
fmt.Fprintf(os.Stderr, "mock-agent: scanner error: %v\n", err)
os.Exit(1)
}
}
// parseModelFlag extracts --model value from command line args.
func parseModelFlag() string {
return parseModelFromArgs(os.Args)
}
// parseModelFromArgs extracts --model value from the given args slice.
func parseModelFromArgs(args []string) string {
for i, arg := range args[1:] {
if arg == "--model" && i+1 < len(args)-1 {
return args[i+2]
}
if strings.HasPrefix(arg, "--model=") {
return strings.TrimPrefix(arg, "--model=")
}
}
return "mock-default"
}
// handleControlRequest responds to control requests from the backend.
func handleControlRequest(enc *json.Encoder, msg IncomingMessage) {
// We only handle the initialize request from the backend
if msg.RequestID != "" {
resp := ControlResponseMsg{
Type: TypeControlResponse,
Response: ControlResponseBody{
Subtype: "success",
RequestID: msg.RequestID,
Response: &InitializeResponse{
Commands: []Command{
{Name: "error", Description: "Simulate an error result"},
{Name: "slow", Description: "Random response with slow delays", ArgumentHint: "<duration e.g. 5s, 30s, 2m>"},
{Name: "thinking", Description: "Extended thinking/reasoning blocks"},
{Name: "tool:read", Description: "Single file read"},
{Name: "tool:edit", Description: "Single file edit (with permission)"},
{Name: "tool:exec", Description: "Single shell command (with permission)"},
{Name: "tool:search", Description: "Single code search"},
{Name: "subagent", Description: "Subagent Task with nested child messages"},
{Name: "todo", Description: "Todo management sequence"},
{Name: "e2e:simple-message", Description: "E2E: text only, fixed timing"},
{Name: "e2e:read-and-edit", Description: "E2E: read + edit + text"},
{Name: "e2e:permission-flow", Description: "E2E: tool requiring permission"},
{Name: "e2e:error", Description: "E2E: error result"},
{Name: "e2e:subagent", Description: "E2E: subagent with child messages"},
{Name: "e2e:all-tools", Description: "E2E: one of each tool type"},
{Name: "e2e:multi-turn", Description: "E2E: minimal multi-turn response"},
},
Agents: []string{"Bash", "Read", "Edit", "Grep", "Glob", "Task"},
},
},
}
_ = enc.Encode(resp)
}
}