Skip to content

Commit 30462eb

Browse files
committed
update codex
1 parent 8a27942 commit 30462eb

3 files changed

Lines changed: 351 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6565
- Correctly distinguishes between orchestrator messages (AgentID="system") and agent announcements
6666
- Agent announcements are system messages from specific agents, not the conversation topic
6767
- All agents now receive the orchestrator's initial prompt in the "YOUR TASK" section
68+
- **Codex Non-Interactive Mode**: Fixed terminal compatibility errors with Codex agent
69+
- Uses `codex exec` subcommand for non-interactive execution
70+
- Parses JSON output to extract agent messages cleanly
71+
- Automatically bypasses approval prompts with safety flags
72+
- No more "stdout is not a terminal" errors in multi-agent conversations
73+
- **Standardized All Adapters**: Applied consistent interaction pattern across all 7 adapters
74+
- All adapters (Amp, Claude, Codex, Copilot, Cursor, Gemini, Qwen) now use identical:
75+
- Three-part structured prompts (Setup → Task → History)
76+
- Message filtering to exclude agent's own messages
77+
- Comprehensive structured logging with timing and metrics
78+
- Proper error handling with specific error detection
79+
- Ensures reliable, consistent behavior across all agent types
6880

6981
## [v0.0.16] - 2025-10-15
7082

README.md

Lines changed: 285 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

140145
Check 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+
511529
type 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
515716
func 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
560767
See `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

564833
AgentPipe 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
7311009
The Qwen Code CLI uses a different interface than other agents:
7321010
- Use `qwen --prompt "your prompt"` for non-interactive mode

0 commit comments

Comments
 (0)