@@ -16,14 +16,16 @@ AgentPipe is a powerful CLI and TUI application that orchestrates conversations
1616
1717## Supported AI Agents
1818
19- - ✅ ** Amp** (Sourcegraph) - Advanced coding agent with autonomous reasoning
19+ All agents now use a ** standardized interaction pattern** with structured three-part prompts, message filtering, and comprehensive logging for reliable multi-agent conversations.
20+
21+ - ✅ ** Amp** (Sourcegraph) - Advanced coding agent with autonomous reasoning ⚡ ** Thread-optimized**
2022- ✅ ** Claude** (Anthropic) - Advanced reasoning and coding
23+ - ✅ ** Codex** (OpenAI) - Code generation specialist (non-interactive exec mode)
2124- ✅ ** Copilot** (GitHub) - Terminal-based coding agent with multiple model support
2225- ✅ ** Cursor** (Cursor AI) - IDE-integrated AI assistance
2326- ✅ ** Gemini** (Google) - Multimodal understanding
2427- ✅ ** Qwen** (Alibaba) - Multilingual capabilities
25- - ✅ ** Codex** (OpenAI) - Code generation specialist
26- - ✅ ** Ollama** - Local LLM support
28+ - ✅ ** Ollama** - Local LLM support (planned)
2729
2830## Features
2931
@@ -135,7 +137,10 @@ AgentPipe requires at least one AI CLI tool to be installed:
135137- [ Gemini CLI] ( https://github.com/google/generative-ai-cli ) - ` gemini `
136138- [ Qwen CLI] ( https://github.com/QwenLM/qwen-code ) - ` qwen `
137139- [ Codex CLI] ( https://github.com/openai/codex-cli ) - ` codex `
138- - [ Ollama] ( https://github.com/ollama/ollama ) - ` ollama `
140+ - Uses ` codex exec ` subcommand for non-interactive mode
141+ - Automatically bypasses approval prompts for multi-agent conversations
142+ - ⚠️ For development/testing only - not recommended for production use
143+ - [ Ollama] ( https://github.com/ollama/ollama ) - ` ollama ` (planned)
139144
140145Check which agents are available on your system:
141146
@@ -503,20 +508,222 @@ agentpipe/
503508
504509### Adding New Agent Types
505510
506- 1. Create a new adapter in `pkg/adapters/`
507- 2. Implement the `Agent` interface
508- 3. Register the factory in `init()`
511+ When creating a new agent adapter, follow the standardized pattern for consistency:
512+
513+ 1. **Create adapter structure** in `pkg/adapters/`:
509514
510515```go
516+ package adapters
517+
518+ import (
519+ "context"
520+ "fmt"
521+ "os/exec"
522+ "strings"
523+ "time"
524+
525+ "github.com/kevinelliott/agentpipe/pkg/agent"
526+ "github.com/kevinelliott/agentpipe/pkg/log"
527+ )
528+
511529type MyAgent struct {
512530 agent.BaseAgent
531+ execPath string
532+ }
533+
534+ func NewMyAgent() agent.Agent {
535+ return &MyAgent{}
536+ }
537+ ```
538+
539+ 2 . ** Implement required methods** with structured logging:
540+
541+ ``` go
542+ func (m *MyAgent ) Initialize (config agent .AgentConfig ) error {
543+ if err := m.BaseAgent .Initialize (config); err != nil {
544+ log.WithFields (map [string ]interface {}{
545+ " agent_id" : config.ID ,
546+ " agent_name" : config.Name ,
547+ }).WithError (err).Error (" myagent base initialization failed" )
548+ return err
549+ }
550+
551+ path , err := exec.LookPath (" myagent" )
552+ if err != nil {
553+ log.WithFields (map [string ]interface {}{
554+ " agent_id" : m.ID ,
555+ " agent_name" : m.Name ,
556+ }).WithError (err).Error (" myagent CLI not found in PATH" )
557+ return fmt.Errorf (" myagent CLI not found: % w" , err)
558+ }
559+ m.execPath = path
560+
561+ log.WithFields (map [string ]interface {}{
562+ " agent_id" : m.ID ,
563+ " agent_name" : m.Name ,
564+ " exec_path" : path,
565+ " model" : m.Config .Model ,
566+ }).Info (" myagent initialized successfully" )
567+
568+ return nil
569+ }
570+
571+ func (m *MyAgent ) IsAvailable () bool {
572+ _ , err := exec.LookPath (" myagent" )
573+ return err == nil
574+ }
575+
576+ func (m *MyAgent ) HealthCheck (ctx context .Context ) error {
577+ // Check if CLI is responsive
578+ cmd := exec.CommandContext (ctx, m.execPath , " --version" )
579+ output , err := cmd.CombinedOutput ()
580+ // ... error handling with logging
581+ return nil
513582}
583+ ```
514584
585+ 3 . ** Implement message filtering** :
586+
587+ ``` go
588+ func (m *MyAgent ) filterRelevantMessages (messages []agent .Message ) []agent .Message {
589+ relevant := make ([]agent.Message , 0 , len (messages))
590+ for _ , msg := range messages {
591+ // Exclude this agent's own messages
592+ if msg.AgentName == m.Name || msg.AgentID == m.ID {
593+ continue
594+ }
595+ relevant = append (relevant, msg)
596+ }
597+ return relevant
598+ }
599+ ```
600+
601+ 4 . ** Implement structured prompt building** :
602+
603+ ``` go
604+ func (m *MyAgent ) buildPrompt (messages []agent .Message , isInitialSession bool ) string {
605+ var prompt strings.Builder
606+
607+ // PART 1: IDENTITY AND ROLE
608+ prompt.WriteString (" AGENT SETUP:\n " )
609+ prompt.WriteString (strings.Repeat (" =" , 60 ))
610+ prompt.WriteString (" \n " )
611+ prompt.WriteString (fmt.Sprintf (" You are '%s ' participating in a multi-agent conversation.\n\n " , m.Name ))
612+
613+ if m.Config .Prompt != " " {
614+ prompt.WriteString (" YOUR ROLE AND INSTRUCTIONS:\n " )
615+ prompt.WriteString (m.Config .Prompt )
616+ prompt.WriteString (" \n\n " )
617+ }
618+
619+ // PART 2: CONVERSATION CONTEXT
620+ if len (messages) > 0 {
621+ var initialPrompt string
622+ var otherMessages []agent.Message
623+
624+ // Find orchestrator's initial prompt vs agent announcements
625+ for _ , msg := range messages {
626+ if msg.Role == " system" && (msg.AgentID == " system" || msg.AgentName == " System" ) && initialPrompt == " " {
627+ initialPrompt = msg.Content
628+ } else {
629+ otherMessages = append (otherMessages, msg)
630+ }
631+ }
632+
633+ // Show initial task prominently
634+ if initialPrompt != " " {
635+ prompt.WriteString (" YOUR TASK - PLEASE RESPOND TO THIS:\n " )
636+ prompt.WriteString (strings.Repeat (" =" , 60 ))
637+ prompt.WriteString (" \n " )
638+ prompt.WriteString (initialPrompt)
639+ prompt.WriteString (" \n " )
640+ prompt.WriteString (strings.Repeat (" =" , 60 ))
641+ prompt.WriteString (" \n\n " )
642+ }
643+
644+ // Show conversation history
645+ if len (otherMessages) > 0 {
646+ prompt.WriteString (" CONVERSATION SO FAR:\n " )
647+ prompt.WriteString (strings.Repeat (" -" , 60 ))
648+ prompt.WriteString (" \n " )
649+ for _ , msg := range otherMessages {
650+ timestamp := time.Unix (msg.Timestamp , 0 ).Format (" 15:04:05" )
651+ if msg.Role == " system" {
652+ prompt.WriteString (fmt.Sprintf (" [%s ] SYSTEM: %s \n " , timestamp, msg.Content ))
653+ } else {
654+ prompt.WriteString (fmt.Sprintf (" [%s ] %s : %s \n " , timestamp, msg.AgentName , msg.Content ))
655+ }
656+ }
657+ prompt.WriteString (strings.Repeat (" -" , 60 ))
658+ prompt.WriteString (" \n\n " )
659+ }
660+
661+ if initialPrompt != " " {
662+ prompt.WriteString (fmt.Sprintf (" Now respond to the task above as %s . Provide a direct, thoughtful answer.\n " , m.Name ))
663+ }
664+ }
665+
666+ return prompt.String ()
667+ }
668+ ```
669+
670+ 5 . ** Implement SendMessage with timing and logging** :
671+
672+ ``` go
673+ func (m *MyAgent ) SendMessage (ctx context .Context , messages []agent .Message ) (string , error ) {
674+ if len (messages) == 0 {
675+ return " " , nil
676+ }
677+
678+ log.WithFields (map [string ]interface {}{
679+ " agent_name" : m.Name ,
680+ " message_count" : len (messages),
681+ }).Debug (" sending message to myagent CLI" )
682+
683+ // Filter and build prompt
684+ relevantMessages := m.filterRelevantMessages (messages)
685+ prompt := m.buildPrompt (relevantMessages, true )
686+
687+ // Execute CLI command (use stdin when possible)
688+ cmd := exec.CommandContext (ctx, m.execPath )
689+ cmd.Stdin = strings.NewReader (prompt)
690+
691+ startTime := time.Now ()
692+ output , err := cmd.CombinedOutput ()
693+ duration := time.Since (startTime)
694+
695+ if err != nil {
696+ log.WithFields (map [string ]interface {}{
697+ " agent_name" : m.Name ,
698+ " duration" : duration.String (),
699+ }).WithError (err).Error (" myagent execution failed" )
700+ return " " , fmt.Errorf (" myagent execution failed: % w" , err)
701+ }
702+
703+ log.WithFields (map [string ]interface {}{
704+ " agent_name" : m.Name ,
705+ " duration" : duration.String (),
706+ " response_size" : len (output),
707+ }).Info (" myagent message sent successfully" )
708+
709+ return strings.TrimSpace (string (output)), nil
710+ }
711+ ```
712+
713+ 6 . ** Register the factory** :
714+
715+ ``` go
515716func init () {
516717 agent.RegisterFactory (" myagent" , NewMyAgent)
517718}
518719```
519720
721+ ** See existing adapters** in ` pkg/adapters/ ` for complete reference implementations:
722+ - ` claude.go ` - Simple stdin-based pattern
723+ - ` codex.go ` - Non-interactive exec mode with flags
724+ - ` amp.go ` - Advanced thread management pattern
725+ - ` cursor.go ` - JSON stream parsing pattern
726+
520727## Advanced Features
521728
522729### Amp CLI Thread Management ⚡
@@ -559,6 +766,68 @@ agents:
559766
560767See ` examples/amp-coding.yaml` for a complete example.
561768
769+ # ## Standardized Agent Interaction Pattern
770+
771+ All AgentPipe adapters now implement a **consistent, reliable interaction pattern** that ensures agents properly understand and respond to conversation context :
772+
773+ **Three-Part Structured Prompts:**
774+
775+ Every agent receives prompts in the same clear, structured format :
776+
777+ ` ` `
778+ PART 1: AGENT SETUP
779+ ============================================================
780+ You are 'AgentName' participating in a multi-agent conversation.
781+
782+ YOUR ROLE AND INSTRUCTIONS:
783+ <your custom prompt from config>
784+ ============================================================
785+
786+ PART 2: YOUR TASK - PLEASE RESPOND TO THIS
787+ ============================================================
788+ <orchestrator's initial prompt - the conversation topic>
789+ ============================================================
790+
791+ PART 3: CONVERSATION SO FAR
792+ ------------------------------------------------------------
793+ [timestamp] AgentName: message content
794+ [timestamp] SYSTEM: system announcement
795+ ...
796+ ------------------------------------------------------------
797+
798+ Now respond to the task above as AgentName. Provide a direct, thoughtful answer.
799+ ` ` `
800+
801+ **Key Features:**
802+
803+ 1. **Message Filtering** : Each agent automatically filters out its own previous messages to avoid redundancy
804+ 2. **Directive Instructions** : Clear "YOUR TASK - PLEASE RESPOND TO THIS" header ensures agents understand what to do
805+ 3. **Context Separation** : System messages are clearly labeled and separated from agent messages
806+ 4. **Consistent Structure** : All 7 adapters (Amp, Claude, Codex, Copilot, Cursor, Gemini, Qwen) use identical patterns
807+ 5. **Structured Logging** : Comprehensive debug logging with timing, message counts, and prompt previews
808+
809+ **Benefits:**
810+
811+ - ✅ **Immediate Engagement** : Agents respond directly to prompts instead of asking "what would you like help with?"
812+ - ✅ **Reduced Confusion** : Clear separation between setup, task, and conversation history
813+ - ✅ **Better Debugging** : Detailed logs show exactly what each agent receives
814+ - ✅ **Reliable Responses** : Standardized approach works consistently across all agent types
815+ - ✅ **Cost Efficiency** : Message filtering eliminates redundant data transfer
816+
817+ **Implementation Details:**
818+
819+ Each adapter implements :
820+ - ` filterRelevantMessages()` - Excludes agent's own messages
821+ - ` buildPrompt()` - Creates structured three-part prompts
822+ - Comprehensive error handling with specific error detection
823+ - Timing and metrics for all operations
824+
825+ This pattern evolved from extensive testing with multi-agent conversations and addresses common issues like :
826+ - Agents not receiving the initial conversation topic
827+ - Agents treating prompts as passive context rather than direct instructions
828+ - Redundant message delivery increasing API costs
829+ - Inconsistent behavior across different agent types
830+
562831# ## Prometheus Metrics & Monitoring
563832
564833AgentPipe includes comprehensive Prometheus metrics for production monitoring :
@@ -727,6 +996,15 @@ The Cursor CLI (`cursor-agent`) has some unique characteristics:
727996- **Check Status**: Run `cursor-agent status` to verify authentication
728997- **Timeout Errors**: If you see timeout errors, ensure you're authenticated and have a stable internet connection
729998
999+ # ## Codex CLI Specific Issues
1000+ The Codex CLI requires non-interactive exec mode for multi-agent conversations :
1001+ - **Non-Interactive Mode**: AgentPipe uses `codex exec` subcommand automatically
1002+ - **JSON Output**: Responses are parsed from JSON format to extract agent messages
1003+ - **Approval Bypass**: Uses `--dangerously-bypass-approvals-and-sandbox` flag for automated execution
1004+ - **Important**: This is designed for development/testing environments only
1005+ - **Security Note**: Never use with untrusted prompts or in production without proper sandboxing
1006+ - Check status : ` codex --help` to verify installation and available commands
1007+
7301008# ## Qwen Code CLI Issues
7311009The Qwen Code CLI uses a different interface than other agents :
7321010- Use `qwen --prompt "your prompt"` for non-interactive mode
0 commit comments